Android NEON type could not be resolved at Eclipse

프로그래밍/NEON(ARM) 2014. 9. 23. 15:57
  • Make a new C++ project
  • Default options for everything
  • Once created, right-click the project and go to "Properties"
  • C/C++ Build -> Settings -> Tool Settings -> GCC C++ Compiler -> Miscellaneous -> Other Flags. Put-std=c++0x at the end . ... instead of GCC C++ Compiler I have also Cygwin compiler
  • C/C++ General -> Paths and Symbols -> Symbols -> GNU C++. Click "Add..." and paste__GXX_EXPERIMENTAL_CXX0X__ (ensure to append and prepend two underscores) into "Name" and leave "Value" blank.
  • Hit Apply, do whatever it asks you to do, then hit OK.
  • I had the same problem. It could be resolved by flushing the Eclipse indexer.
    I used the projects context menu and selected Index->Rebuild and Index->Freshen All Files. The last removed the error messages.


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

NEON 수학, 이항, 스칼라 연산  (0) 2014.09.03
NEON 변환 연산  (0) 2014.09.03
NEON 비교 연산과 절대값  (0) 2014.09.03
NEON 비트와 시프트 연산  (0) 2014.09.03
NEON 레인 설정과 조회  (0) 2014.08.31

NEON 수학, 이항, 스칼라 연산

프로그래밍/NEON(ARM) 2014. 9. 3. 20:47

1. 수학연산

NEON에서는 수학 함수로 역수와 역수 제곱근에 관련된 함수를 제공한다. (제곱근 함수는 지원하지 않는다.)

 

1.1 역수 함수

벡터의 각 레인에 대해서 역수를 계산한다.

 

float32x4_t r = vrecpeq_f32(float32x4_t a)

 

 

1을 레인의 값으로 나누고 그 결과를 저장한다.

 

1.2 역수 제곱근 함수

벡터의 각 레인에 대해서 제곱근의 역수 값을 계산한다.

float32x4_t r = vrsqrteq_f32(float32x4_t a)

 

  

레인의 제곱근 값으로 나누고 그 결과를 저장한다. 수식으로 풀면 r = 1/sqrt(a)

1.3 역수 확장 함수

2에서 두 벡터의 레인 사이의 곱하기 연산 결과를 뺀다. 이를 식으로 나타내면 r = 2 - (a * b)와 같다.

 float32x2_t vrecps_f32(float32x2_t a, float32x2_t b) - 실수 32bit 2개

 float32x4_t vrecps_f32(float32x4_t a, float32x4_t b) - 실수 32bit 4개

 

1.4 역수 제곱근 확장 함수

3에서 두 벡터의 레인 사이의 곱하기 연산 결과를 빼고, 그 결과를 2로 나누어 저장한다.

이를 식으로 나타내면 r = (3 - (a*b)))/2

 float32x2_t vrsqrts_f32(float32x2_t a, float32x2_t b) - 실수 32bit 2개

 float32x4_t vrsqrts_f32(float32x4_t a, float32x4_t b) - 실수 32bit 4개

 

NEON의 역수 확장 함수를 이용하면 Newton-Raphson 알고리즘을 구현 할수 있다.


1.5 역수를 이용한 나누기 연산

역수를 이용하면 나누기를 구현할수 있다.


X / N = X (1 / N)


X / N의 결과는 X * (1 / N) 과 같으므로 X / N = X * (1 / N)이 성립한다.

이 공식을 이용하면 곱하기와 역수로 나누기를 구할수 있다.

10나누기 2를 이 공식으로 나타내면 다음과 같다.



2. NEON 이항 연산

2.1 벡터 교환 함수

단일 벡터 사이에 레인 값을 교환하고 복수 벡터에 결과를 저장한다.


int8x8_t r = vtrn_s8(int8x8_t a, int8x8_t b)



2.2 인터리브와 디인터리브

인터리브와 디인터리브를 이해하면 앞에서 다룬 복수 벡터의 로드와 저장 연산 방식을 이해 할수 있게 된다.

복수 벡터로 메모리 데이터를 로드할 때는 인터리브(Interleave)가 적용되고, 메모리 데이터에 복수 벡터를 

저장할 때는 디인터리브(De-Interleave)가 자동으로 적용된다. 여기에서 메모리 데이터는 배열을 의미한다.


        

 예를 들어 RGB 이미지 메모리를 uint8x8x3_t 형식의 복수 벡터에 로드하면 R, G, B 데이터가 val[0], val[1], 

val[2]에 각각 로드된다. 이렇게 메모리가 벡터에 분할되어 로드되는 것을 인터리브라고 한다.


반대로 uint8x8x3_t 형식의 벡터를 메모리로 저장하는 경우 val[0], val[1], val[2]에 포함된 

R, G, B데이터가 메모리에 각각 저장되는 것을 인터리브라고 한다. 디인터리브는 인터리브의 반대이다.


RGB 데이터는 이미지 데이터 포맷으로 멀티미디어에 사용되는데, NEON은 이와 같은 연산을 지원하여

멀티미디어를 처리하는 데 최적화되어 있으므로, 개발자가 이미지 데이터를 처리하는 애플리케이션을 

제작하기 수월하다.


벡터 인터리브

두개의 벡터를 하나의 복수 벡터에 저장한다.


int8x8x2_t r = vzip_s8(int8x8_t a, int8x8_t b)

두 개의 메모리 데이터가 복수 벡터에 대입될 때 1개 레인을 건너가며 저장된다.


   



벡터 디 인터리브

디인터리브는 인터리브와 마찬가지로 두 개의 단일 벡터를 하나의 복수 벡터에 저장하지만, 

저장하는 방식이 다르다.


int8x8x2_t r = vuzp_s8(int8x8_t a, int8x8_t b)

   

두 개의 벡터가 복수 벡터에 대입될 때 val[0]과 val[1]에 교대로 저장된다. 

현재까지 NEON의 벡터 인터리브와 벡터 디 인터리브는 2개의 단일 벡터만 연산이 가능하다.


3. NEON 스칼라 연산

NEON에서 스칼라(Scalar)는 벡터에 포함된 여러 레인 중에서 하나의 레인만을 참조하거나 

하나의 일반 변수를 이용하여 벡터의 여러 레인을 참조하는 것을 말한다. 스칼라에 사용되는

값은 16비트 또는 32비트, 64비트 값이 될 수 있다. NEON에는 여러 가지 스칼라 연산이 있지만

대부분 곱하기 연산에 특화되어 있다.


3.1 스칼라 곱하기

벡터의 모든 레인을 하나의 값으로 곱한다


int16x4_t r = vmul_n_s16(int16x4_t a, int16_t b)


 


3.2 스칼라 벡터 Long 곱하기

두 개의 벡터에서 특정 레인을 이용한 곱하기 연산이다.


int32x4_t r = vmull_lane_s16(int16x4_t a, int16x4_t b, __constrange(0, 3) int c)


     



일반 변수 c로 벡터 b의 레인 중에서 하나의 레인을 선택한다. 

선택된 레인으로 벡터 a의 각레인을 곱하여 결과를 쿼드 워드 벡터 r에 저장한다.


3.3 스칼라 곱하기 누계

스칼라 곱하기 연산 결과에 벡터 더하기 연산을 실행


int16x4_t r = vmla_n_s16(int16x4_t a, int16x4_t b, int16_t c)


b 벡터의 각 레인에 c를 곱한뒤 벡터 a와 각 레인을 더해 벡터 r에 저장한다.(r = (b * c) + a)


3.4 스칼라 벡터 곱하기 누계

스칼라 벡터 곱하기 연산 결과에 벡터 더하기 연산을 실행한다.


int16x4_t r = vmla_lane_s16(int16x4_t a, int16x4_t b, int16x4_t v, __constrange(0, 3) int l)


벡터 b와 v에 스칼라 벡터 곱하기 연산을 실행한다.

벡터 b의 각 레인에 벡터 v의 l번째 값과 곱한뒤 벡터 a의 각 레인값과 더한뒤 벡터 r에 저장





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

Android NEON type could not be resolved at Eclipse  (0) 2014.09.23
NEON 변환 연산  (0) 2014.09.03
NEON 비교 연산과 절대값  (0) 2014.09.03
NEON 비트와 시프트 연산  (0) 2014.09.03
NEON 레인 설정과 조회  (0) 2014.08.31

NEON 변환 연산

프로그래밍/NEON(ARM) 2014. 9. 3. 17:33

1. NEON 변환 연산

벡터의 변환은 NEON의 모든 연산에서 유용하게 사용되며, 필요에 따라서 여러 방법으로 사용할 수 있다.

벡터의 변환은 더블 워드 벡터를 연산하여 쿼드 워드 벡터에 저장하거나, 그 반대의 경우 포화 연산을

지원하지 않는 연산에서 오버플로를 방지하기 위해서 사용된다.

 

1.1 벡터 결합 함수

벡터를 두 배 크기로 확장할 때 벡터 결합을 사용한다.

벡터 결합 함수는 레인의 수는 변경되고, 레인의 크기는 변경되지 않는다.

 

int16x8_t r = vcombine_s16(int16x4_t a, int16x4_t b)

16bit 레인 더블 워드 벡터 2개를 결합하여 16bit 레인 쿼드 워드 벡터를 생성한다.

 

    

 

 

1.2 벡터 분할 함수

벡터 변수의 분할은 high분할과 low 분할로 나뉜다.

결합과 마찬가지로 레인의 수는 변경되고, 레인의 크기는 변경되지 않는다.

 

High 분할

int16x4_t r = vget_high_s16(int16x8_t a)

 

  

 

 

Low 분할

int16x4_t r = vget_low_s16(int16x8_t a)

 

  

 

1.3 벡터 레인 축소 함수

벡터 레인 축소(Narrow) 함수는 쿼드 워드 벡터를 더블 워드 벡터로 변경한다.

레인의 크기는 절반으로 축소되고, 레인의 수는 변경되지 않는다.

 

int8x8_t r = vmovn_s16(int16x8_t a)

16bit 레인 쿼드 워드 벡터 a가 8bit 레인 더블 워드 벡터 r로 변경된다.

( C언어에서 signed short 형을 강제로 unsigned char 형으로 강제 형변환(casting)한 것과 같다.)

 

1.4 벡터 레인 확대 함수

벡터 레인 확대(Long) 함수는 더블 워드 벡터를 쿼드 워드 벡터로 변경한다.

레인의 크기는 2배 확대 되고, 레인의 수는 변경되지 않는다.

 

int8x8_t r = vmovl_s8(int8x8_t a)

8bit 레인 더블 워드 벡터 a가 16bit 쿼드 워드 벡터 r로 변경된다. char형이 short 형으로 강제 형변환된다.

 

1.5 실수 형변환 함수

 실수 벡터를 정수 벡터로 변환하거나 정수 벡터를 실수 벡터로 형변환 할 수 있다.

 

실수형 레인 ▶  (부호 있는, 부호 없는) 정수형 레인

int32x4_t r = vcvtq_s32_f32(float32x4_t a)

   

 

(부호 있는, 부호 없는) 정수형 레인 ▶  실수형 레인

float32x4_t r = vcvtq_f32_s32(int32x4_t a)

 

NEON 변환과 재해석 연산은 NEON으로 어플리케이션을 개발할 때 매우 자주 사용된다.

NEON에서는 형변환시 분할 함수와 결합 함수를 사용해야하만 한다. 또한 NEON에서는

정수와 실수 사이에 연산할 때에도 같은 형으로(정수를 실수 또는 실수를 정수로) 변환하고 연산해야 한다.

 

2. NEON 재해석 함수

어플리케이션을 개발하다 보면, 실수 변수의 형변환 이외에 다른 종류의 벡터 사이에 형변환이 필요할 때가 있다.

이런 경우를 대비해 NEON은 재해석 함수(형변환)를 제공한다.

NEON에서의 형변환 결과는 C/C++ 과는 조금 다르다. NEON 재해석 함수는 함수 이름의 조합으로 다양한

형변환을 할 수 있다.

 

재해석 함수 문법

 

 

int16x8_t r = vreinterpertq_s16_f32(float32x4_t a)

실수 32bit 쿼드 워드 벡터를 정수 16bit 레인 쿼드 워드(부호있는) 벡터로 재해석 한다.

 

uint16x4_t r = vreinterpret_u16_s16(int16x4_t a)

부호 있는 정수 16bit 레인 더블 워드 벡터를 부호 없는 정수 16bit 레인 더블 워드 벡터로 재해석 한다.

   

 

 

재해석할 때 bit의 이동

재해석 연산이 실행되면 레인의 bit는 그대로 복사된다. 재해석 연산에서는 bit의 패턴이 변경되지 않으므로

예상치 못한 결과가 나타날 수 있다. 예를 들어 16bit 레인이 8bit레인 2개로 변경되면 16bit의 상위 8bit는 상위

레인에 복사되고, 하위 8bit는 하위레인에 그대로 복사된다.

 

  

 

 

 

NEON 비교 연산과 절대값

프로그래밍/NEON(ARM) 2014. 9. 3. 16:44

1. 비교 연산

1.1 같음(==) 비교 함수

벡터 사이에 레인 값이 같은지 비교한다.

 

uint16x8_t r = vceqq_s16(int16x8_t a, int16x8_t b)

벡터 a와 b의 레인이 같은 값인지 비교하여 벡터 r의 각 레인에 결과가 참이면 16진수로

0xffff, 거짓이면 16진수로 0x0000을 저장한다.

 

1.2 크거나 같음(>=) 비교 함수

벡터 사이에 레인 값이 크거나 같은지 비교한다.

 

uint16x8_t r = vcgqe_s16(int16x8_t a, int16x8_t b)

벡터 a가 b보다 크거나 같은지 비교하여 벡터 r의 각 레인에 그 결과가 참이면

0xffff, 거짓이면 0x0000을 저장한다.

 

1.3 작거나 같음(<=) 비교 함수

벡터 사이에 레인 값이 작거나 같은지 비교한다.

 

uint16x8_t r = vcleq_s16(int16x8_t a, int16x8_t b)

벡터 a가 b보다 작거나 같은지 비교하여 벡터 r의 각 레인의 위치에 그 결과가 참이면 0xffff,

거짓이면 0x0000을 저장한다.

 

1.4 큼(>) 비교 함수

벡터 사이에 레인 값이 큰지를 비교한다.

 

uint16x8_t r = vcgtq_s16(int16x8_t a, int16x8_t b)

벡터 a가 b보다 큰지를 비교하여 벡터 r의 각 레인의 위치에 그 결과가 참이면 0xffff, 거짓이면 0x0000을 저장한다.

 

1.5 작음(<) 비교 함수

벡터  사이에 레인값이 작은지 비교한다.

 

uint16x8_t r = vcltq_s16(int16x8_t a, int16x8_t b)

벡터 a가 b보다 작은지를 비교하여 벡터 r의 각 레인의 위치에 그 결과가 참이면 0xffff, 거짓이면 0x0000을 저장한다.

 

2. 절댓값

2.1 절댓값 함수

벡터의 절댓값(ABS)를 구한다.

 

int8x8_t r = vabs_s8(int8x8_t a)

벡터 a의 절댓값을 계산한다.

 

2.2 절대 차이 함수

벡터 변수 사이에 빼기 연산을 하고 절댓값을 구한다.

 

int8x8_t r = vabd_s8(int8x8_t a, int8x8_t b)

벡터 a에서 b를 뺀 결과의 절댓값을 구한다. (r = |a-b|)

 

2.3 절대 차이 누계 함수

절대 차이 함수의 실행 결과에 또 다른 벡터를 더하여 저장한다.

 

int8x8_t r = vaba_s8(int8x8_t a, int 8x8_t b, int8x8_t c)

벡터 b에서 c를 뺀 절댓값에 벡터 a를 더한다. (r = a + |b-c|)

 

2.4 절댓값 비교

NEON은 절댓값 사이의 비교 연산을 지원한다. 절댓값 비교의 종류는 총 4가지로

절댓값이 크거나 같음, 절댓값이 작거나 같음, 절댓값 큼, 절댓값 작음이 있다.

단, 절댓값 비교는 실수형 벡터만 지원한다.

 

절댓값 크거나 같음 (>=)

uint32x4_t r = vcageq_f32(float 32x4_t a, float32x4_t b)

실수 32bit 레인 벡터 a의 절댓값이 같은 크기의 벡터 b의 절댓값보다 크거나 같은지 비교하여

결과를 부호 없는 정수형 벡터 r에 대입한다. 정수 비교와 마찬가지로 참이면 대상 레인은

0xffff로 설정되고, 그렇지 않으면 모두 0x0000으로 설정된다.

 

절댓값 큼 (<)

uint32x4_t r = vcagtq_f32(float32x4_t a, float32x4_t b)

실수 32bit 레인 벡터 a의 절댓값이 같은 크기의 벡터 b의 절댓값보다 큰지 비교하여 결과를

부호 없는 정수형 벡터 r에 대입한다.

 

절댓값 작거나 같음 (<=)

uint32x4_t r = vcaleq_f32(float32x4_t a, float32x4_t b)

실수 32bit 레인 벡터 a의 절댓값이 같은 크기의 벡터 b의 절댓값보다 작거나 같은지 비교하여 결과를

부호 없는 정수형 벡터 r에 대입한다.

 

절댓값 작음 (<)

uint32x4_t r = vcaltq_f32(float32x4_t a, float32x4_t b)

실수 32bit 레인 벡터 a의 절댓값이 같은 크기의 벡터 b의 절댓값보다 작은지 비교하여 결과를

부호없는 정수형 벡터 r에 대입한다.

 

 

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

NEON 수학, 이항, 스칼라 연산  (0) 2014.09.03
NEON 변환 연산  (0) 2014.09.03
NEON 비트와 시프트 연산  (0) 2014.09.03
NEON 레인 설정과 조회  (0) 2014.08.31
NEON 산술 연산과 확장  (0) 2014.08.27

NEON 비트와 시프트 연산

프로그래밍/NEON(ARM) 2014. 9. 3. 16:04

1. 비트 연산

1.1 NOT(~)연산

uint8x8_t r = vmvn_u8(uint8x8_t a)

벡터의 모든 레인에 NOT 연산을 실행

 

1.2 AND(&) 연산

uint8x8_t r = vand_u8(uint8x8_t a, uint8x8_t b)

두 벡터의 레인 사이에 AND(&)연산을 실행

 

1.3 OR(|) 연산

uint8x8_t r = vorr_u8(uint8x8_t a, uint8x8_t b)

두 벡터의 레인 사이에 OR(|) 연산을 실행

 

1.4 XOR(^) 연산

uint8x8_t r = veor_u8(uint8x8_t a, uint8x8_t b)

두 벡터의 레인 사이에 XOR(^) 연산을 실행

 

1.5 AND NOT(&~) 연산

uint8x8_t ar = vbic_u8(uint8x8_t a, uint8x8_t b)

벡터에 NOT 연산한 결과를 또 다른 벡터와 AND연산 (b 벡터에 NOT 연산후 AND연산)

 

1.6 OR NOT(|~) 연산

uint8x8_t r = vorn_u8(uint8x8_t a, uint8x8_t b)

벡터에 NOT(~) 연산한 결과를 또 다른 벡터와 OR(|) 연산 (b 벡터에 NOT 연산후 OR 연산)

 

1.7 비트 단위 선택 함수

int8x8_t r = vbsl_s8(uint8x8_t a, int8x8_t b, int8x8_t c)

두 벡터의 레인 bit를 조합하여 하나의 레인에 저장

벡터 a의 레인의 값이 1이면 b벡터의 비트 선택, 레인값이 0이면 c벡터의 비트 선택

 

1.8 부호 비트 변환 함수

int8x8_t r = vneg_s8(int8x8_t a)

벡터의 부호 변경(각 레인 마다 변경)

 

2. NEON 시프트 연산

2.1 NEON Shift 함수

int8x8_t r = vshl_s8(int8x8_t a, int8x8_t b)

벡터 a의 레인 값을 벡터 b의 레인 값 만큼 Shift 연산을 한다.(양수는 왼쪽으로 shift, 음수는 오른쪽으로 shift)

 

int8x8_t r = vqshl_s8(int8x8_t a, int8x8_t b) - 포화 shift 함수(오버플로우 방지)

 

※ 일반적으로 Shift 연산은 산술적 Shift 연산과 논리적 Shift 연산이 있다.

    NEON 에서는 논리적 Shift 연산을 지원하지 않는다. 그 이유는 예를들어 논리적 Shift 연산은 2의 n승으로

    나눈 효과가 있지만, 음수에서는 문제가 나타난다. 일반적으로 음의 정수는 2의 보수로 구현되는데,

    2의 보수의 최상위 부호는 1이 된다. 그래서 논리적 Shift 연산을 음수에 사용하면 2로 나눈 결과가 아닌

    양수로 바뀌게 된다.(논리적 Shift 연산은 최상위 비트가 부호에 상관없이 무조건 0이 채워지기 때문)

    따라서 NEON 에서는 논리적 Shift 연산을 지원하지 않는다.

 

2.2 오른쪽 Shift 함수

int8x8_t r = vshr_n_s8(int8x8_t a, __constrange(1, 8) int b)

벡터 a 를 b만큼 오른쪽으로 Shift 연산한다. 각 레인에 대해서 최상위 비트 값은 유지하고,

이후 1bit씩 Shift하므로 2의 n승으로 나눈 결과가 된다.

 

2.3 왼쪽 Shift 함수

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

벡터 a를 b만큼 왼쪽으로 Shift 연산한다. 논리적 왼쪽 Shift 연산은 2의 n승으로 곱한 효과가 있다.

 

2.4 Shift 후 삽입 함수

오른쪽 Shift 후 삽입

uint8x8_t r = vsri_n_u8(uint8x8_t a, uint8x8_t b, __constrange(1, 8) int c)

벡터 레인을 Shift 하고, Shift 한 크기만큼 다른 벡터 레인의 bit로 채워 넣는다.

벡터 b를 c 만큼 오른쪽 shift 연산 한후, 빈 공간은 벡터 b의 bit로 채운다.

 

왼쪽 Shift 후 삽입

uint8x8_t r =vsli_n_u8(uint8x8_t a, uint8x8_t b, __constrange(0, 7) int c)

벡터 a를 2만큼 왼쪽 shift 연산 한 후, 빈 공간은 b의 bit로 채운다.

 

2.5 나눗셈 구현

NEON 에서는 나눗셈을 지원하지 않으므로 Shift 연산으로 대체해야 한다.

순수하게 Shift만을 사용하게 되면 2, 4, 6, 8, 16, 32, 64와 같이 2의 n승 단위의 나눗셈만 구현할 수 있다.

 

149/23과 같은 나눗셈을 구현하려면 일정한 값을 곱하고 나서 Shift 연산을 수행해야 한다.

먼저 레인이 오버플로가 발생하는지를 고려하여 Shift 연산을 수행할 크기를 정한다.

오버플로에 대한 우려가 없다면 Shift 단위가 클수록 오차가 줄고 정확하다. 나눗셈을 구현하는 과정은 다음과 같다.

 

  ① 오버플로가 발생하지 않는 범위의 Shift 단위를 정한다.

  ② Shift 단위를 제수로 나눈다. (6÷3=2에서 6을 말함 )

  ③ 구한 값을 피제수로 곱한다.

  ④ 피제수를 오른쪽 Shift 연산한다.

 

예) 256 Shift 단위로 다음 나눗셈을 구현하기

   149 / 9 = 16

 

직접 나눗셈을 할수 없으므로 Shift 연산을 수행할 단위 256을 9로 나눈다.

   256 / 9 = 16

 

28을 149에 곱하고 나서 256으로 나눈다.

   149 * 28 = 4172

 

4172를 8번 오른쪽 Shift 연산하면

   4172 / 256 = 16

 

결과값 16이 나온다.

 

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

NEON 변환 연산  (0) 2014.09.03
NEON 비교 연산과 절대값  (0) 2014.09.03
NEON 레인 설정과 조회  (0) 2014.08.31
NEON 산술 연산과 확장  (0) 2014.08.27
NEON 함수 정리(로드 함수, 저장함수)  (0) 2014.08.27

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