티스토리 뷰

얼마 전에 페이스북에 올라온 질문인데, “MIPS 어셈블리 코드 중 beq 를 안쓰고 bne 를 쓰는 이유는 무엇인가요?” 라는 질문이다.

아래와 같은 C 언어 코드가 있고,

if (i == j) f = g + h; else f = g - h;

이를 순서도로 나타내면 다음과 같다.

컴파일러와 최적화 옵션에 따라 생성되는 어셈블리 인스트럭션이 아래와 똑같다고 말할 수 없다.

일반적으로 컴파일러는 인스트럭션을 생성할 때 조건문의 경우 반대 조건으로 해석해서 인스트럭션을 작성한다. 이런 경우 대부분 인스트럭션의 크기가 짧아지기 때문에 더 적은 클럭에서 명령을 수행할 수 있기 때문이다. 따라서 아래와 같은 어셈블리 코드가 생성된다.

# bne 를 사용하는 코드  
bne $s3, $s4, Else  
add $s0, $s1, $s2  
j Exit  
Else:  
sub $s0, $s1, $s2  
Exit:

다음은 beq 를 사용하는 코드이다.

# beq 를 사용하는 코드  
beq $s3, $s4, Then  
sub $s0, $s1, $s2  
j Exit  
Then:  
add $s0, $s1, $s2  
Exit:

어?? 이상하다. 책의 내용을 보면 분명 ‘더 효율적이다.’ 라고 언급하는데, 무엇이 더 효율적인지 우열을 가리기 힘들다. 맞다. 단항 비교 연산인 경우 비교적으로 bnebeq 의 코드 길이에 대한 효율성 차이는 그리 크지 않다.

그렇다면, bne 가 더 효율적이려면 다음의 코드로 생각을 해보자.

if (i==j && i==k) f = g + h; else f = g - h;

바로 각각 beq 코드와 bne 코드로 구현해 보자.

# beq 를 사용하는 코드  
beq $s3, $s4, And  
j Else  
And:  
beq $s3, $s5, Then:  
j Else  
Then:  
add $s0, $s1, $s2  
j Exit  
Else:  
sub $s0, $s1, $s2  
Exit:

다음 코드는 bne 를 사용하는 코드이다.

bne $s3, $s4, Else  
bne $s3, $s5, Else  
add $s0, $s1, $s2  
j Exit  
Else:  
sub $s0, $s1, $s2  
Exit:

위 두 코드의 결과를 보면 확실하게 bne 코드의 결과가 적은 인스트럭션을 생성하는 것을 볼 수 있다. AT&T, x86, ARM 코어 등을 막론하고 대부분 조건 비교는 (!contidion) 형태를 띄고 있다.

참고로 더 자세한 내용을 알고 싶다면 필자가 추천하는 뇌를 자극하는 프로그래밍 원리 : CPU부터 OS까지 책을 참고하길 바란다. 참 좋은 책이다 ^^

댓글