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