ARM 아키텍처에는 16개의 레지스터와 함께 cpsr(current program status register)이라고 하는 레지스터가 존재한다.

cpsr은 다음과 같은 구조인데, 이번 포스팅에서는 이 cpsr에서의 flags 부분에서 overflow, carry flag를 비교해볼 것이다.




보통 overflow 를 흘러넘치다라는 표현으로 받아들이고, overflow랑 carry를 혼동하는 경우가 많다.

나같은 경우, 정확하기 이해하기 전에는 이 두 개념을 완전히 서로 반대로 이해하고 있었는데,


예를 들어 4-bit 연산을 한다고 했을 때,


1) 1000 + 1000 = 10000 (여기서 맨 앞에 있는 1은 사라지게 됨)

이런 경우 overflow가 되는 것이라고 생각했다. (왜냐하면 4개의 비트에서 흘러넘쳤으니깐)

하지만 이 경우에는 carry flag가 set되는 것이다.

즉, carry flag는 최상단 비트에서 캐리가 생겼을 때 set 된다!


반면,

2) 0111 + 0001 = 1000 

그리고 이 경우에는 overflow flag가 set되는 것이다.

왜냐하면, 이들이 signed expression이라고 가정했을 때, 7+1 = 8이 나와야 하지만, -8이 나왔기 때문이다. (overflow로 인한 잘못된 결과)

즉, 부호가 있는 연산에서 최대 표현 숫자를 넘어서서 오버플로우가 난 경우 overflow flag가 set된다!

(같은 부호를 더했을 때 다른 부호가 나오는 것으로도 오버플로우를 인지할 수 있다.)


따라서, signed 에서만 overflow flag가 의미 있고,

unsigned 에서만 carry flag가 의미가 있는 것이다.


하지만 주의해야 할 점은 CPU는 signed/unsigned와 같은 의미를 모른다.

따라서, 내가 지금 무슨 연산을 하고 있던 간에 overflow flag가 set되야 할 때, carry flag가 set되야 할 때는 독립적인 사건이다.

즉, 1000 + 1000 = 10000과 같은 상황에서는 두 플래그가 모두 셋이 될 것이다.

왜냐하면, 부호가 있다고 생각하든 없다고 생각하든, 최상단 비트에서 carry가 생겼으며,

두개의 입력값 모두 최상단 비트는 1인데 결과는 최상단 비트가 0이 되었으므로 오버플로우 플래그도 세팅이 되는 것이다.


즉, 내가 지금 signed 연산을 하고 있더라도, carry flag는 의미는 없지만, set될 수도 있고 아닐 수도 있는 것이다.

왜 의미가 없냐 하면, 어차피 signed연산을 하는 시점에서는 최상단 비트는 오로지 부호의 역할만 하므로 그 이후 캐리가 생기고 말고는 의미가 없는 것이다.



"switch문과 if문의 차이는 무엇일까? 성능의 차이가 있을까?"


switch문과 if문의 성능에 대해서 이야기를 하는 시간을 가져보고자 합니다.

프로그래밍을 배우다 보면 선택문을 사용해야 할 때 if문을 사용하거나 switch문을 사용합니다.

물론 switch문을 쓸 수 있는 경우는 전부 if문으로 대체 가능합니다만,

if문으로 가능한 것들 중 switch문으로 구현 불가능한 경우도 있죠.


이번 포스팅에서는 switch문과 if문 모두 가능한 경우에 대해서 따져보고자 합니다.

(당연한 이야기겠죠... 두 개 동시 사용 가능한 경우에 대해서 이런 논의가 의미가 있는 것이죠)


그리고, 단순히 고수준 언어의 측면에서 보기보단 ISA의 관점에서 풀어서 포스팅을 해보고자 합니다.

따라서, 특정 고수준 언어에 대해서는 이 포스팅의 내용이 옳지 않을수도 있습니다.

왜냐하면 고수준 언어들은 더욱 복잡한 컴파일러에 귀속되어 있는데, 

그 언어의 컴파일러가 어떠한 방식으로 instruction set (혹은 기계어나 어셈블리어)를 만들어가는지는 언어마다 다르기 때문입니다.


제가 공부한 ISA인 MIPS에는 branch statement와 jump statement가 있습니다.

branch statement는 레지스터 2개를 비교해서(혹은 레지스터와 상수를 비교해서) 특정 메모리 번지로 이동할 것이냐 말것이냐?를 결정합니다. 

jump statement는 즉시 특정 메모리 번지로 이동하는 기능을 합니다.


그리고 if문은 branch statement에 기반을 두고 있고,

switch문은 jump statement에 기반을 두고 있습니다.


왜냐하면, if문은 조건이 만족하면 실행/만족하지 않으면 무시 (실행을 할 것이냐 말것이냐?)

switch문은 입력된 값을 보고 특정 위치로 점프 (어떤 코드를 실행할 것이냐?)


switch문은 "점프테이블"을 만들고 switch문의 입력값으로 받은 변수 값만큼 점프 테이블 내에서 이동하면 됩니다.

if문보다 훨씬 쉽네요? 점프 테이블만 만들수 있다면 말이죠.


대충 이 정도 이야기를 하면 어느 정도 눈치를 채셨을 수도 있는데,

if-else문은 각 조건마다 그 조건 처리할수 있게 레지스터를 변경해주는 그런 인스트럭션들이 먼저 선행되야 합니다. 각 조건마다.

그런데, switch문은 점프 테이블을 만들기만 하면 조건이 몇개든 훨씬 빠르고 쉽게 넘어갈 수 있어요.

다만 점프 테이블을 만드는 오버헤드가 있는거죠.


<정리하자면>

if문

장점: 점프 테이블을 만드는 오버헤드가 없다.

단점: if 혹은 else if를 만날 때마다 조건을 만족하는지 안하는지를 확인하기 위한 인스트럭션이 계속해서 필요됨.

즉, 따져야 할 조건의 수가 적을 경우 if-else를 쓰는 것이 유리함.


switch문

장점: switch문 시작시에 입력받은 값을 확인하는 인스트럭션만 필요. 조건을 확인하는 인스트럭션이 필요 없음.

단점: 점프 테이블을 만드는 오버헤드가 있음.

즉, 따져야 할 조건의 수가 많아져도 인스트럭션이 추가로 요구되는 것이 아니기 때문에,

따져야 할 조건이 많은 경우 switch문을 쓰는 것이 유리합니다.


+ Recent posts