I'm writing a compiler for a uni assignment, I'm currently emitting asm from an internal representation. I have the following representation for for (a = 1; a < 10; a++) do print a
:
COPY a, 1 // Copy 1 to a
LABEL label0 //
LT tmp0, a, 10 // Store in tmp0 the result of the expression a < 10
JUMP_FALSE label1, tmp0 // Jump to label1 if tmp0 is false
PRINT a //
ADD a, a, 1 // Store in a the result of the expression a + 1
JUMP label0 //
LABEL label1 //
I am emitting the following asm for this, where both constants and variables are emitted as globals variables for orthogonality:
#a := 1
movl var_1(%rip), %eax
movl %eax, var_a(%rip)
.label0:
#EXPR_START tmp0 = a < 10
movl var_a(%rip), %eax
movl var_10(%rip), %edx
cmpl %eax, %edx
setl %al
movzbl %al, %eax
movl %eax, var_tmp0(%rip)
#EXPR_END
#jmpf label1, tmp0
movl var_tmp0(%rip), %eax
testl %eax, %eax
jne .label1
#Print a
movl var_a(%rip), %eax
movl %eax, %esi
leaq printf_int(%rip), %rdi
movl $0, %eax
call printf@PLT
movl $0, %eax
#EXPR_START a = a + 1
movl var_a(%rip), %eax
movl var_1(%rip), %edx
addl %edx, %eax
movl %eax, var_a(%rip)
#EXPR_END
#jmp label0
jmp .label0
.label1:
This seems to be comparing a <= 10
, but I don't understand why. Isn't the cmpl
and setl
combo setting the value of %al
as 1 if the result of the comparison was "less then"? Then shouldn't testl %eax, %eax
be 1
while a < 10
and jne
occur when a == 10
? If my understanding is wrong, how can I store the result of a comparison in a register (1 if the comparison holds, 0 otherwise)?
Below is the full asm which can be compiled with gcc asm.s
. The expected output is 1 2 3 4 5 6 7 8 9
the actual output is 1 2 3 4 5 6 7 8 9 10
.
main:
pushq %rbp
movq %rsp, %rbp
#a := 1
movl var_1(%rip), %eax
movl %eax, var_a(%rip)
.label0:
#EXPR_START
movl var_a(%rip), %eax
movl var_10(%rip), %edx
cmpl %eax, %edx
setl %al
movzbl %al, %eax
movl %eax, var_tmp0(%rip)
#EXPR_END
#jmpf label1, tmp0
movl var_tmp0(%rip), %eax
movl $1, %edx
cmpl %eax, %edx
je .label1
#Print a
movl var_a(%rip), %eax
movl %eax, %esi
leaq _printf_int(%rip), %rdi
movl $0, %eax
call printf@PLT
movl $0, %eax
#EXPR_START
movl var_a(%rip), %eax
movl var_1(%rip), %edx
addl %edx, %eax
movl %eax, var_a(%rip)
#EXPR_END
#jmp label0
jmp .label0
.label1:
popq %rbp
ret
.text
.globl var_tmp1
.data
.size var_tmp1, 4
var_tmp1:
.long 0
.text
.globl main
.text
.globl var_1
.data
.size var_1, 4
var_1:
.long 1
.text
.globl var_a
.data
.size var_a, 4
var_a:
.long 0
.text
.globl var_10
.data
.size var_10, 4
var_10:
.long 10
.text
.globl var_tmp0
.data
.size var_tmp0, 4
var_tmp0:
.long 0
_printf_int:
.string "%d "