자기개발/SIMD

SIMD 알아보기 (feat C++, Assembly 연산)

pi92 2021. 10. 7. 14:38

범용 어셈블리 언어

 

-범용 레지스터 종류


 사용할 수 있는 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;
}