NEON 레인 설정과 조회

프로그래밍/NEON(ARM) 2014. 8. 31. 20:10

NEON 에서는 벡터 안의 레인에 다양한 값을 저장하거나, 레인의 값을 확인할 수 있다. 또한, 하나의 벡터 안에서 레인 사이의 교환(swap)도 가능하다. 레인 설정함수 중 몇 개는 벡터 저장 함수 중에서 브로드캐스트 함수나 레인 저장함수와 결과가 같은데, 이는 어셈블러 명령어 차이에 따른 것으로 성능의 차이는 없다.


1. NEON 레인 설정

NEON 에서는 벡터의 특정 레인의 값을 불러오거나 변경 할수 있다. 

단 레인 설정에 관련된 모든 함수는 복수 벡터에 지원하지 않는다.


1.1 레인 추출 함수


지정된 레인의 값 하나를 일반 변수에 저장한다.

uint16_t r = vgetq_lane_u16(uint16x8_t a, __constrange(0, 7) int lane)

예) lane이 2일때 변수 r에 벡터 a의 2번째 레인 값이 대입된다.


1.2 레인 설정 함수


일반 변수의 값을 지정된 레인에 저장한다.

uint16x8_t r = vsetq_lane_u16(uint16_t value, uint16x8_t vec, __constrange(0, 7) int lane)

예) lane이 2, value = 5일때 벡터 r에서 일반변수 lane 값으로 설정된 레인에 일반 변수 value(5) 값을 대입하고, 

     그외 부분은 벡터 vec의 레인 값을 대입한다.


1.3 비트 패턴을 이용한 레인 초기화 함수

비트 패턴은 비트가 존재하는 형태를 말하며, 예를 들어 uint64_t형 정수 10,421을 2진수로 표현하면 

0x0001000100010001이 된다. 이렇게 2진수로 표현하면 비트가 0과 1로 구성되어 있는데, 이를 비트 패턴이라고 한다.

이러한 비트 패턴을 이용하여 벡터의 레인을 초기화할 수 있다.


uint16x4_t r = vcreate_u16(uint64_t a)

예) uint64_t형 변수의 비트 패턴을 이용하여 벡터를 초기화한다. 변수 a에 10,421을 대입하고 a의 비트 패턴을 이용해서 벡터 r의 레인을 설정한다. 이때 일반 변수 a는 배열이 아니고 일반 변수(uint64_t 형)인 것에 주의해야 한다.



1.4 특정 레인으로 벡터 초기화 함수

벡터 안의 특정 레인 값을 벡터의 모든 레인에 할당한다.


uint16x8_t r = vdupq_lane_u16(uint16x4_t a, __constrange(0, 3), int lane);

예) 벡터 a의 lane번째 값을 벡터 r에 모두 대입한다.



1.5 레인 브로드캐스트 함수

벡터의 모든 레인을 일반 변숫값으로 설정한다. 같은 기능을 하는 함수가 2개 있다.


  • 브로드캐스트 함수

 uint16x8_t r = vdupq_n_u16(uint16_t value)




  • vmov 함수

 uint16x8_t r = vmovq_n_u16(uint16_t value)


두 함수는 명칭만 다를뿐 수행 기능은 같다.

예) value 값을 벡터 r의 모든 레인에 대입한다.


2. NEON 레인 조회

레인 조회에 관련된 함수는 레인의 값만 확인하는 것이 아니라, 두 벡터의 레인으로 하나의 새로운 벡터를 

생성하거나 레인을 조합하여 새로운 벡터를 생성할 수 있다. 


2.1 레인 조회 함수

레인 번호가 저장된 벡터를 이용하여 대상 벡터의 레인 값을 조회하고, 조회된 값으로 새로운 벡터를 생성한다. 

레인 조회 함수는 단일 벡터와 복수 벡터를 모두 조회할 수 있다.

벡터 변수 조회는 8bit 레인 더블 워드 벡터에서만 동작하고, 조회의 범위를 벗어나면 0을 저장한다.


2.1.1 단일 벡터 레인 조회


int8x8_t r = vtbl1_s8(int8x8_t a, int8x8_t b)


                   


벡터 b의 레인에는 벡터 a에서 가져올 레인의 번호가 저장된다. 예를 들어 벡터 b의 0번 레인에 4가 대입되어 있다면,

벡터a의 4번 레인의 값 5를 벡터 r의 0번 레인에 저장한다. 벡터 a, b, r의 크기는 모두 같아야 하며, 벡터 b는

8bit 더블레인 워드벡터여야만 한다. 

벡터 b와 같이 조회하는 레인 번호를 가진 벡터를 테이블 벡터 또는 테이블이라고 한다.


2.1.2 복수 벡터 레인 조회


int8x8_t r = vtbl2_s8(int8x8x2_t a, int8x8_t b)


단일 벡터 레인 조회방법과 동일하게 벡터 a 레인값을 벡터 b에 있는 레인 번호를 이용하여 조회하고, 

결과를 벡터 r에 저장한다. 조회범위가 벗어나면 0을 저장한다. 

복수 벡터 a의 레인은 val[0]과 val[1]이 각각 0번 레인부터 시작하지 않고, val[0]의 0번 레인부터 차례로

증가해서 val[1]의 마지막 레인이 15번 레인이 된다.


2.2 레인 조회 확장 함수

레인 조회 확장 함수도 레인 번호가 저장된 벡터를 이용하여 대상 벡터의 레인 값을 조회하고,

조회된 값을 새로운 벡터에 저장한다. 레인 조회 확장 함수는 레인 조회 함수와 다르게 조회된 범위를

벗어나면 0을 저장하지 않고, 또 다른 벡터의 레인 값으로 저장한다.


int8x8_t r = vtbx1_s8(int8x8_t a, int8x8_t b, int8x8_t c)


벡터 c에 있는 레인 번호를 이용해서 벡터 b의 레인 값을 조회하고, 결과를 벡터 r에 저장한다. 

만약 조회의 범위가 벗어나면 벡터 a의 레인 값으로 대체한다. 

(확장함수와 기본 조회함수와의 차이를 주의해야 한다. 벡터 조회에서는 벡터 b가 테이블 벡터이지만,

벡터 조회 확장에서는 벡터 c가 테이블 벡터가 된다.)


2.3 레인 조합 함수

두 벡터의 레인을 조합하여 하나의 벡터로 생성한다.


int8x8_t r = vext_s8(int8x8_t a, int8x8_t b, __constrange(0, 7) int c)



변수 c의 값을 이용해서 벡터 a와 b의 레인을 조합하여, 그 결과를 벡터 r에 대입한다. 

레인 조합은 피연산자 벡터 a의 7번 레인에서부터, 두 번째 피연산자 벡터 b의 0번 레인에서부터 레인을 추출한다.

예를 들면 c가 3일때 b벡터 3개 a벡터 5개를 추출해 저장한다.


2.4 레인 교환 함수

하나의 벡터 변수 안에서 레인의 값을 교환(Swap)할 수 있다. 레인 교환 함수는 여러가지 종류가 있는데,

함수의 이름으로 교환되는 벡터의 범위와 레인의 크기를 예측할 수 있다.


           


n비트의 크기에 따라 총 3가지 유형의 레인 교환 함수가 있다.

  • 더블 워드 내 레인 교환

  • 싱글 워드 내 레인 교환

  • 하프 워드 내 레인 교환


2.4.1 더블 워드 내 레인 교환

int8x8_t r = vrev64_s8(int8x8_t vec)

벡터 내에서 더블 워드 크기로 레인의 순서를 교환하고 결과를 벡터 변수에 저장한다.

0번 레인은 7번 레인, 1번 레인은 6번 레인, 2번 레인은 5번 레인, 3번 레인은 4번 레인 순으로 교환해 저장한다.


2.4.2 싱글 워드 내 레인 교환

int8x8_t r = vrev32_s8(int8x8_t vec)

벡터 내에서 싱글 워드 크기로 레인의 순서를 교환하고 결과를 벡터 변수에 저장한다.

0번 레인은 3번 레인, 3번 레인은 0번 레인과 같이 하나의 벡터 변수를 두 개(절반)로 나눠서 레인 교환한다.

4번 레인은 7번 레인, 7번 레인은 4번 레인


2.4.3 하프 워드 내 레인 교환

int8x8_t r = vrev16_s8(int8x8_t vec)

벡터 내에서 하프 워드 크기로 레인의 순서를 교환하고 결과를 벡터 변수에 저장한다.

0번 레인은 1번 레인, 1번 레인은 0번 레인과 같이 하나의 벡터 변수를 네개로 나눠서 레인 교환한다.

(서로 인접해 있는 것끼리 교환)

'프로그래밍 > NEON(ARM)' 카테고리의 다른 글

NEON 비교 연산과 절대값  (0) 2014.09.03
NEON 비트와 시프트 연산  (0) 2014.09.03
NEON 산술 연산과 확장  (0) 2014.08.27
NEON 함수 정리(로드 함수, 저장함수)  (0) 2014.08.27
NEON 벡터 자료형  (0) 2014.08.27

NEON 산술 연산과 확장

프로그래밍/NEON(ARM) 2014. 8. 27. 15:58

NEON 에서는 벡터 변수 사이의 기본 산술 연산을 지원하고, 포화 더하기와 인접 레인 더하기 등 NEON만의 독특한 산술 연산도 지원한다. 또한 최댓값 및 최솟값 연산과 Long, Wide, Narrow, 포화와 관련된 산술 연산을 지원한다.


NEON에서는 나누기와 제곱근 연산은 지원하지 않아서 Shift 연산이나 역수를 이용해야 한다.



1. NEON 기본 산술 연산 (더하기, 빼기, 곱하기, 레인 최댓값, 최솟값, 인접 레인 더하기 함수)


(1) 더하기 함수

uint16x8_t r = vaddq_u16(uint16x8_t a, uint16x8_t b)   a + b 를 r벡터에 저장


(2) 빼기 함수

uint16x8_t r = vsubq_u16(uint16x8_t a, uint16x8_t b)   a - b 를 r벡터에 저장


(3) 곱하기 함수

uint16x8_t r = vmulq_u16(uint16x8_t a, uint16x8_t b)   a * b 를 r벡터에 저장

 ※ 곱하기 연산의 오버플로를 방지하려면 레인의 크기를 확장하거나 포화연산을 사용하는 것이 좋다.


(4) 나눗셈

NEON에서는 나눗셈 연산을 지원하지 않는다. 그래서 Shift 연산으로 나눗셈을 대체하는 방법을 이용하거나 역수를 이용한 나눗셈을 구현해야 한다. 단 역수를 이용한 나눗셈은 부호 있는 정수와 부호 있는 실수만 가능하므로 변수형을 부호 있는 정수나 실수로 벡터 형변환하여 나눗셈을 구현해야 한다.


(5) 인접 레인 더하기 함수

uint16x4_t r = vpadd_u16(uint16x4_t a, uint16x4_t b) 

 a[3] + a[2] = r[3]  , a[1] + a[0] = r[2] 

 b[3] + b[2] = r[1]  , b[1] + b[0] = r[0]

인접 레인 사이의 더하기 연산

(6) 최댓값 함수

uint16x8_t r = vmaxq_u16(uint16x8_t a, uint16x8_t b)

a레인과 b레인을 각각 순서대로 비교해 큰 값을 r 레인에 저장

예) a[0] 과 b[0]을 비교해 큰 값을 r[0]에 저장 ...


(7) 최솟값 함수

uint16x8_t r = vminq_u16(uint16x8_t a, uint16x8_t b)

최댓값 함수와 마찬가지로 a레인과 b레인을 각각 순서대로 비교해 작은 값을 r레인에 저장



2. 산술 연산의 확장

(1) Long 더하기 함수 : 같은 레인을 연산해 2배 크기의 벡터에 저장

uint16x8_t r = vaddl_u8(uint8x8_t a, uint8x8_t b)


(2) Wide 더하기 함수 : 다른 크기의 벡터 사이에 더하기 연산을 하고 그 결과를 쿼드 워드 벡터에 저장

uint16x8_t r = vaddw_u8(uint16x8_t a, uint8x8_t b)


(3) 포화 더하기 함수 : 같은 크기의 벡터 사이에 더하기 연산을 한다. 단 오버플로가 발생하면 bit의 최댓값 또는 최솟값으로 저장

uint8x8_t r = vqadd_s8(int8x8_t a, int8x8_t b)


(4) Narrow 더하기 함수 : 같은 크기의 벡터 사이에 더하기 연산을 하고 절반 크기의 벡터에 그 결과를 저장한다.

                                    이때 결과는 상위비트만 저장된다.(레인의 크기가 반으로 줄어듬)

uint8x8_t vaddhn_u16(uint16x8_t a, uint16x8_t b)


(5) 벡터 2개의 평균 구하기 함수

uint16x8_t vrhaddq_u16(uint16x8_t a, uint16x8_t b) (a+b)>>1의 연산 수

NEON 에는 나누기 연산이 없으므로 >>1 연산(비트 연산자)를 사용하여 나누기 2를 대신한다.


(6) Long 빼기 함수

uint16x8_t r = vsubl_u8(uint8x8_t a, uint8x8_t b)

같은 크기 2개의 벡터를 빼기 연산하고 그 결과를 2배 크기의 벡터에 저장한다. (더블워드 -> 쿼드워드)


(7) Wide 빼기 함수

uint16x8_t r = vsubw_u8(uint16x8_t a, uint8x8_t b)

다른 크기의 벡터 변수 사이에 빼기 연산을 하고, 그 결과를 쿼드 워드 벡터 변수에 저장(쿼드워드-더블워드 = 쿼드워드)


(8) 포화 빼기 함수

int8x8_t r = vqsub_s8(int8x8_t a, int8x8_t b)

같은 크기의 벡터 사이에 빼기 연산을 하고 그 결과를 벡터 변수에 저장한다. 만약 오버플로가 발생하면 bit의 최댓값 또는 최솟값으로 저장한다.


(9) Narrow 빼기 함수

int8x8_t r = vsubhn_u16(uint16x8_t a, uint16x8_t b) 

같은 크기의 벡터 사이에 빼기 연산을 하고 절반 크기의 벡터에 결과를 저장한다. Narrow 더하기 함수와 마찬가지로 이때 결과는 상위비트만 저장된다.


(10) 빼기 후 평균 함수

uint16x8_t r = vhsub_u16(uint16x8_t a, uint16x8_t b) (a-b)>>1

벡터 2개를 뺀 값의 평균을 구한다.


(11) Long 곱하기 함수

uint16x8_t r = vmull_u8(uint8x8_t a, uint8x8_t b)

같은 크기의 벡터 사이에 곱하기 연산 후 그 결과를 2배 크기의 벡터에 저장한다.


(12) 곱한 후 가감 함수

uint16x8_t r = vmlaq_u16(uint16x8_t a, uint16x8_t b, uint16x8_t c)  ra+(b*c)

3개의 벡터를 이용하여 벡터 사이에 곱하기 연산과 더하기 연산을 실행한다.

벡터 b와 c를 곱한 결과에 벡터 a의 값을 더하고 그 결과를 r에 저장한다.


uint16x8_t r = vmlsq_u16(uint16x8_t a, uint16x8_t b, uint16x8_t c)  r = a-(b*c)

벡터 b와 c를 곱한 결과에 벡터 a를 빼 그 결과를 r에 저장한다.


(13) Long 인접 레인 더하기 함수

uint16x4_t r = vpaddl_u8(uint8x8_t a)

인접한 레인 사이의 더하기 연산을 하고 확장하여 저장한다. 결과 벡터는 피 연산자 레인 수의 절반이 되고, 레인의 크기는 2배로 커지지만, 결과 벡터와 피연산자 벡터의 크기는 동일하다.

r[0] = a[0]+a[1], r[1] = a[2]+a[3], r[2] = a[4]+a[5], r[3] = a[6]+a[7]


(14) Long 인접 레인 더하기 누계 함수

uint16x4_t r = vpadal_u8(uint16x4_t a, uint16x4_t b)

2개의 벡터를 이용하여 Long 인접 레인 더하기 연산을 하고, 다시 더하기 연산을 실행한다.

벡터 b에서 인접 레인과 더하기 연산을 수행한수, 그 결과를 벡터 a와 더한다. 벡터 a의 레인 크기는 변수 b의 레인 크기의 2배여야 하며, 벡터 b의 인접한 레인 더하기 연산이 먼저 실행되는 것에 주의해야 한다.


(15) 인접 레인 최댓값과 최솟값 함수

uint16x4_t r = vpmax_u16(uint16x4_t a, uint16x4_t b)

인접 레인 사이의 최댓값을 저장할수 있다.

  a[0] 와 a[1] 의 레인 최댓값을 r[0]에 저장 

  a[2] 와 a[3] 의 레인 최댓값을 r[1]에 저장

  b[0] 와 b[1] 의 레인 최댓값을 r[2]에 저장 

  b[2] 와 b[3] 의 레인 최댓값을 r[3]에 저장


'프로그래밍 > NEON(ARM)' 카테고리의 다른 글

NEON 비트와 시프트 연산  (0) 2014.09.03
NEON 레인 설정과 조회  (0) 2014.08.31
NEON 함수 정리(로드 함수, 저장함수)  (0) 2014.08.27
NEON 벡터 자료형  (0) 2014.08.27
NEON 기본개념  (0) 2014.08.27

NEON 함수 정리(로드 함수, 저장함수)

프로그래밍/NEON(ARM) 2014. 8. 27. 15:32

단일 로드 함수

일반 로드 함수

uint16x8_t = r = vld1q_u16(__transfersize(8) uint16_t const *ptr)

메모리 배열에서 벡터로 데이터를 가져온다. (메모리 배열 요소와 벡터의 레인 크기가 같아야 한다)


레인 로드 함수

uint16x8_t r = 

    vld1q_lane_u16(__transfersize(1) uint16_t const *ptr, uint16x8_t a, __constrange(0, 7) int nlane)

메모리의 값을 벡터의 특정 레인으로 가져온다.(ptr 메모리 변수에서 nlane번쨰 값을 a로 변환)


브로드캐스트 로드 함수

uint16x8_t q = vld1q_dup_u16(__transfersize(1) uint16_t const *ptr)

벡터의 모든 레인을 하나의 메모리 값으로 설정한다.(q레인에 ptr값을 대입)

브로드캐스트 로드 함수는 벡터의 레인을 0으로 초기화 하거나, 특정 값으로 초기화 할때 많이 사용하는 유용한 함수이다.


복수 로드 함수

일반 로드 함수

uint16x8x2_t r = vld2q_u16(__transfersize(16) uint16_t const *ptr)

복수 벡터의 일반 로드 함수는 단일 벡터의 일반 로드 함수와는 조금 다르게 동작한다.

배열을 기준으로 0, 2, 4, 6, 8, 10, 12, 14 요소의 값은 val[0] 레인에 저장되고, 1, 3, 5, 7, 9, 11, 13, 15 요소의 값은 val[1] 레인에 저장된다.

이처럼 저장되는 것을 인터리브(Interleave)라고하며, 인터리브는 이미지 데이터를 로드할 때 매우 유용하다.


레인 로드 함수

uint 16x8x2_t r = 

    vld2q_lane_u16(__transfersize(2) uint16_t const *ptr, uint16x8x2_t src, __constrange(0, 7) int lane)

복수 벡터의 특정 레인에 메모리 변수의 값을 대입한다.


브로드캐스트 로드 함수

uint16x4x2_t r = int16x4x2_t vld2_dup_u16(__transfersize(2) uint16_t const *ptr)

복수 벡터의 모든 레인에 하나의 메모리 변수값을 대입한다.



단일 저장 함수

일반 저장 함수

void vst1q_u16(__transfersize(8) uint16_t const *ptr, uint16x8_t r)

벡터 변수를 메모리 배열에 저장(메모리 배열과 벡터 변수의 크기는 같아야 한다)


레인 저장 함수

void vstl1q_lane_u16(__transfersize(1) uint8_t *ptr, uint8x16_t r, __constrange(0, 15) int nlane)

특정 레인의 값을 메모리 변수에 저장(r 벡터의 nlane 번째 레인 값을 ptr에 저장)


복수 저장 함수

일반 저장 함수

void vst2q_u16(__transfersize(16) uint16_t const *ptr, uint16x8x2_t q)

복수 벡터를 로드 했던 것을 거꾸 로 배열에 저장하므로 복수 벡터 변수를 저장한 배열의 순서가 엉키지 않고 출력된다.


레인 저장 함수

void vstl1q_lane_u16(__transfersize(1) uint8_t *ptr, uint8x16_t r, __constrange(0, 15) int nlane);

복수 벡터의 특정 레인 값을 메모리 변수에 저장

(r벡터의 nlane 번째 레인값을 ptr에 저장 - 복수 레인이므로 r[0],[1]의 레인값을 각각 ptr[0], ptr[1]에 저장)





'프로그래밍 > NEON(ARM)' 카테고리의 다른 글

NEON 비트와 시프트 연산  (0) 2014.09.03
NEON 레인 설정과 조회  (0) 2014.08.31
NEON 산술 연산과 확장  (0) 2014.08.27
NEON 벡터 자료형  (0) 2014.08.27
NEON 기본개념  (0) 2014.08.27

NEON 벡터 자료형

프로그래밍/NEON(ARM) 2014. 8. 27. 15:19

NEON 벡터 변수 자료형 표현 방식

<type><size>x<number of lanes>_t  변수명

  타입  사이즈 x          길이         _t  변수명


<NEON 벡터>                   <C 변수>

  int16x4_t a           ▷      int16_t a[4]


<type><size>x<number of lanes>x<length of array>_t

 타입   사이즈 x 길이(레인개수)  x 개수 _t 



'프로그래밍 > NEON(ARM)' 카테고리의 다른 글

NEON 비트와 시프트 연산  (0) 2014.09.03
NEON 레인 설정과 조회  (0) 2014.08.31
NEON 산술 연산과 확장  (0) 2014.08.27
NEON 함수 정리(로드 함수, 저장함수)  (0) 2014.08.27
NEON 기본개념  (0) 2014.08.27

NEON 기본개념

프로그래밍/NEON(ARM) 2014. 8. 27. 14:21

NEON의 자료형


{0,1}을 통한 다항식 산술이란 숫자 0과 1을 이용하여 bool 산술 규칙을 이용하는 것을 말한다.


  0 + 0 = 1 + 1 = 0,    0 + 1 = 1 + 0 = 1,   0 * 0 = 0 * 1 = 1 * 0 = 0,    1 * 1 = 1



NEON 벡터의 크기

NEON 벡터(변수) 는 레지스터와 연결되어 있고, NEON 함수는 레지스터를 제어하기 위해서 사용된다.


더블워드(64bit) NEON벡터(D 레지스터)

- 8개의 8비트 요소

- 4개의 16비트 요소

- 2개의 64비트 요소

- 1개의 64 비트 요소


쿼드워드(128bit) NEON벡터(Q 레지스터)

- 16개의 8비트 요소

- 8개의 16비트 요소

- 4개의 32비트 요소

- 2개의 64비트 요소


더블워드 NEON 벡터는 64bit 크기의 연산을 지원하고, 쿼드워드 NEON 벡터는 128bit 크기의 연산을 지원한다.



NEON 레지스터

NEON에서는 Q레지스터와 16개의 D레지스터 32개를 포함하여 총 256byte의 레지스터를 사용하여 연산한다.

256byte 중에서 D레지스터는 VFP(부동 소수점) 레지스터와 공유한다. VFPv2는 D0~D15 레지스터를 사용하고, 

VFPv3은 D0~D31 까지 사용한다.

NEON은 D레지스터를 VFP 레지스터와 공유하므로 NEON 연산과 VFP연산을 동시에 사용하면 레지스터가 충돌하여 예상치 못한 결과가 발생할수 있다.


출처 : http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0002a/ch01s03s02.html



'프로그래밍 > NEON(ARM)' 카테고리의 다른 글

NEON 비트와 시프트 연산  (0) 2014.09.03
NEON 레인 설정과 조회  (0) 2014.08.31
NEON 산술 연산과 확장  (0) 2014.08.27
NEON 함수 정리(로드 함수, 저장함수)  (0) 2014.08.27
NEON 벡터 자료형  (0) 2014.08.27