SIMD 알아보기 (feat C++, Assembly 연산)
범용 어셈블리 언어
-범용 레지스터 종류
사용할 수 있는 32bit 범용 레지스터는 8개가 있지만 실제 프로그램 구현 시에 사용하 수 있는 레지스터 개수는 6개 정도로 생각하면 된다.
(주로 ECX, EDX, ESI, EDI, EBP, ESP를 사용하여 프로그램을 구현하면 된다.)
EAX : Accumulator
EDX : Data
ECX : Count
EBX : Base
ESI : Source Index Pointer
EDI : Destination Index Pointer
---------------------------------
EBP : Base Pointer
ESP : Stack Pointer
int A, B, C, D
int* SI, DI
------------------------
앞뒤로 E, X 라 생각하자
-연산
대입 연산
mov 명령어 사용 문법
----------------------------------
mov 범용 레지스터, 범용 레지스터
mov 범용 레지스터, 메모리(변수)
mov 메모리(변수), 범용 레지스터
mov 범용 레지스터, 상수
mov 메모리(변수), 상수
----------------------------------
mov reg, reg (레지스터)
(32bit 레지스터와 16bit, 8bit 레지스터를 구분하기 위해 r32로 적기도 한다.)
mov reg, mem
mov mem, reg
mov reg, imm
mov mem, imm
------------------------------------------
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int a = 1;
int nValue = 0; //메모리 변수
__asm
{
mov eax, 1 //레지스터 변수
mov nValue, 2 //nValue = 2;
}
cout << "nValue : " << nValue << endl;
return 0;
}
산술연산
덧셈(add)
레지스터를 이용하여 덧셈을 구현해 보자.
------------------------------------------
add reg, reg (레지스터, 레지스터)
add reg, mem (레지스터, 메모리 변수)
add mem, reg (메모리 변수, 레지스터)
add reg, imm (레지스터, 상수)
add mem, imm (메모리 변수, 상수)
------------------------------------------
int main(int argc, char* argv[])
{
int a = 5;
int b = 7;
int c = 0;
__asm
{
pushad
mov eax, a //eax = a 값 대입
mov ebx, b //ebx = b 값 대입
add eax, ebx //eax = eax + ebx;
mov c, eax //c = eax 대입
popad
}
cout << "5 + 7 = " << c << endl;
return 0;
}
큰 특징이 없던 코드에 pushad와 popad가 추가되었다. 우리가 작성한 코드가 실행되기 전에 CPU는 다른 여러 가지 연산을 수행 중에 있을 것이다. 그때 사용하던 레지스터에 값 역시 사용 중에 있을 것이다. 레지스터를 사용하기 전에 그 값들을 시스템 스택에 push로 저장을 하고, 우리가 레지스터를 다 사용하였으면 pop으로 되돌려 주느 것을 의미한다.
뺄셈 (sub)
------------------------------------------
sub reg, reg(레지스터, 레지스터)
sub reg, mem(레지스터, 메모리 변수)
sub mem, reg(메모리 변수, 레지스터)
sub reg, imm(레지스터, 상수)
sub mem, imm(메모리 변수, 상수)
------------------------------------------
곱셈(mul)
------------------------------------------
mul reg/mem
------------------------------------------
곱셈 구현코드
------------------------------------------
mov eax, 5
mov Value, 8
mul Value //eax = eax*Value;
------------------------------------------
int main(int argc, char* argv[])
{
int a = 5;
int c = 0;
__asm
{
pushad
mov ebx, 15 //ebx = 15 값 대입
mov eax, a //eax = a 값 대입
mul ebx //eax = ebx + eax;
mov c, eax //c = eax 대입
popad
}
cout << "15 * 5 = " << c << endl;
return 0;
}
나눗셈(div)
------------------------------------------
div reg/mem
------------------------------------------
나눗셈구현코드
------------------------------------------
mov eax, 15
mov Value, 3
div Value //eax = eax / Value;
------------------------------------------
각각 eax = eax/Value;, edx = eax%Value;
int main(int argc, char* argv[])
{
int a = 5;
int b = 0;
int c = 0;
__asm
{
pushad
mov eax, 17 //eax = 17 값 대입
cdq //32bit를 64bit로 확장
//convert double word to quad word
mov ebx, a //ebx = a 값 대입
div ebx //eax = eax / ebx;
mov b, eax //b = eax;
//edx = eax % eax;
mov c, edx //c = edx 대입
popad
}
cout << "17 / 5 = " << b<<"," << c << endl;
return 0;
}
증가 명령어++(inc)
------------------------------------------
inc reg/mem
------------------------------------------
증가 명령어 구현코드
------------------------------------------
__asm
{
inc eax // eax++;
}
------------------------------------------
감소 명령어--(dec)
------------------------------------------
dec reg/mem
------------------------------------------
감소 명령어 구현코드
------------------------------------------
int nValue = 100;
__asm
{
Dec nValue // nValue--;
}
------------------------------------------
shift 연산
왼쪽 방향 shift(shl)
------------------------------------------
shl reg, imm8
shl m32, imm8
------------------------------------------
오른쪽 방향 shift(shr)
------------------------------------------
shr reg, imm8
shr m32, imm8
------------------------------------------
imm8의 의미는 int형 상수만 올 수 있다는 것으로 이것 떄문에 코드 구현에 상당한 제약이 따른다.
int main(int argc, char* argv[])
{
int nValue = 8;
__asm
{
pushad
mov eax, nValue //eax = nValue(8);
shl eax, 1 //eax << 1; 8*2 = 16;
mov nValue, eax //nValue = eax;
popad
}
cout << "SHL Result : " << nValue << endl;
__asm
{
pushad
mov eax, nValue //eax = nValue(8);
shr eax, 2 //eax >> 2; 16/4 = 4;
mov nValue, eax //nValue = eax;
popad
}
cout << "SHR Result : " << nValue << endl;
return 0;
}