논리 연산은 다음과 같다.
맨 마지막 (i = 상수)만큼 곱하거나 나누는 연산이다. 이진수로 나타냈을 때, 한 칸씩 앞으로 shift(옮긴다)한다 생각하면 된다.
sll $t2, $s0, 4 # $t2 = $s0 << 4
srl $t2, $s0, 4 # $t2 = $s0 >> 4
and $t0, $t1, $t2
t1과 t2 and 연산 이후 t0에 저장
or $t0, $t1, $t2
nor $t0, $t1, $zero
0과의 nor 연산을 통해 not을 수행한다.
- beq rs, rt, L1
if (rs == rt)면, L1으로 점프한다. L1은 주소이다.- bne rs, rt, L1
if (rs != rt)면, L1으로 점프한다.- j L1
조건없이 L1으로 점프한다.- slt rd, rs, rt
if (rs < rt) rd = 1, else rd = 0- slti rt, rs, constant
if (rs < constant) rt = 1, else rt = 0
왜 와 같은 비교연산은 없을까? 저런 비교연산은 CPU clock period를 늘리기 때문에, period가 작은 연산엔 시간 낭비가 일나고 frequency도 줄기 때문이다.
if (i==j) f = g+h;
else f = g-h;
f,g는 $s0, $s1이다.
bne $s3, $s4, Else
add $s0, $s1, $s2
j Exit
Else: sub $s0, $s1, $s2
Exit: …
while (save[i] == k) i += 1;
Loop: sll $t1, $s3, 2
add $t1, $t1, $s6
lw $t0, 0($t1)
bne $t0, $s5, Exit
addi $s3, $s3, 1
j Loop
Exit: …
Basic Blocks란 점프가 일어나거나 점프되는 block이 아니다.(이곳에서 명령어 최적화를 한다.)
s1 = 0000 0000 0000 0000 0000 0000 0000 0001
slt $t0, $s0, $s1 # signed
–1 < +1 $t0 = 1
sltu $t0, $s0, $s1 # unsigned
+4,294,967,295 > +1 $t0 = 0
함수 호출을 위한 과정을 알아보자.
- 함수 호출 인자들을 레지스터에 저장한다.
- 함수 코드로 점프한다.
- 지역변수 등 함수에 필요한 값들을 레지스터에 배치한다.
- 함수를 수행한다.
- 반환값을 레지스터에 저장한다.
- 호출 시점 다음 instruction으로 점프한다.
이전에 $t, $s 레지스터를 확인했다. 남은 레지스터를 알아보자.
- $a0 – $a3: 함수 인자를 저장 (reg’s 4 – 7)
- $v0, $v1: 리턴값을 저장 (reg’s 2 and 3)
- $gp: 전역, 정적 변수를 저장하는 메모리 영역의 주소를 저장 (reg 28)
- $sp: 스택 메모리의 주소(top 마지막 부분) 저장(reg 29)
- $fp: 스택 메모리의 주소(시작 부분) 저장 (reg 30)
- $ra: 리턴할 주소 저장 (reg 31)
- jal ProcedureLabel
다음 명령어(반환 위치)를 $ra에 저장 후 함수로 점프- jr $ra
$ra의 값을 program counter 레지스터에 저장: 다음 명령어는 반환 위치가 된다.(리턴)
case/switch statment 사용가능.
int leaf_example (int g, h, i, j)
{
int f;
f = (g + h) - (i + j);
return f;
}
• Arguments g, …, j in $a0, …, $a3
• f in $s0 (hence, need to save $s0 on stack)
• Result in $v0
이 경우, 함수를 호출하는 함수의 리턴 주소와 매개변수를 스택에 저장해야함.
함수 수행이 끝난 후 복원
int leaf_example (int g, h, i, j)
{
int f;
f = (g + h) - (i + j);
return f;
}
• Argument n in $a0
• Result in $v0
유심히 봐야할 곳은 리턴할 때 n이 1일 때, 스택에 8만 더하고(리턴 값(4바이트)와 매개변수(4바이트) 를 무시) 1리턴, 만약 n이 1이 아니면 값을 꺼내고 반환값을 계산해주고 리턴한다.
$fp 레지스터는 하나의 함수가 시작될 때, $sp의 자리로 set된다. 이러한 이유는 특정함수가 시작되고 나서 함수에 관한 데이터들이 스택에 저장되는데, 함수의 시작점이란 것을 알려주는 것이다. 시작 후 매개변수와 리턴 주소 등이 저장되고 이후에 너무 많은 데이터가 있다면 $sp로 찾기 힘들 수 있다. $fp에 대한 상대주소로 쉽게 찾을 수 있을 것이다