So it’s been a day or 2 since the last devlog, but I’ve been on vacation and just been a little busy with life, anyhow enough of a rant.
This devlog goes over what I’ve added; that being: while loops, char and unsigned integer types, signed and unsigned aware comparison codegen, and a bit of better cross-platform toolchain support.
while loops were implemented E2E. The lexer recongizes the while keyword, a new WhileStatement AST node holds the info, and the parser backing it. Now the codegen emits the loop as a loopTop label, a conditional branch via the existing infra, the body statements, and a jmp loopTop.
Now keep in mind this is basically a debug build, but now let’s say you have this C code:
int main()
{
char x = 0;
while (x < 15)
{
x = x + 1;
}
return x;
}
To keep it bluntly this is the ASM:
_TEXT SEGMENT
main PROC
push rbp
mov rbp, rsp
sub rsp, 16
mov eax, 0
mov byte ptr [rbp-8], al
@while_top0:
cmp byte ptr [rbp-8], 15
jge @while_end2
@while_body1:
movsx eax, byte ptr [rbp-8]
add eax, 1
mov byte ptr [rbp-8], al
jmp @while_top0
@while_end2:
movsx eax, byte ptr [rbp-8]
mov rsp, rbp
pop rbp
ret
main ENDP
_TEXT ENDS
END
But if you want an explanation:
Now I’m going to skip the setting up the stack frame, but baically the first few instrctions setup the stack frame and reserve 16 bytes.
Now you see we have a variable x which is a char. Now a char on x64 is 1 byte. So that’s what this does:
mov eax, 0
mov byte ptr [rbp-8], al
We zero it out and then store the low byte (al) into x‘s stack slot. Now that’s cool and all, but what about the while loop!!
Well before we can do anything we have a condition: x < 15 or while (x < 15) and that is the part of the @while_top0.
@while_top0:
cmp byte ptr [rbp-8], 15
jge @while_end2
We take x and compare it directly against 15 as a byte and jumps out of the loop if x >= 15.
Now what about the body? Well the body (x = x + 1;) gets evaluated in this body:
@while_body1:
movsx eax, byte ptr [rbp-8]
add eax, 1
mov byte ptr [rbp-8], al
jmp @while_top0
This code loads x, sign-extending it into a full 32-bit eax which is needed because arithmetic promotes char to int in C. It adds 1, then truncates back down to a byte when storing into x. Then it jumps back to re-check the condition.
What about the end? Well this:
@while_end2:
movsx eax, byte ptr [rbp-8]
mov rsp, rbp
pop rbp
ret
Now this sign-extends x into eax one more time as the return value, tears down the frame, and returns.
Now unsigned works, but uhh that’s a lot of instructions, but yeah this is DotC with a while. Now the cross-platform system it mainly reliant on Wine as this compiler only really emits MASM for right now and it requires kernel32.lib… so maybe in the future.
And to my Linux people: yes, that is PowerShell, not Bash, and also it’s Kitty.
And to my .NET people: yeah I’m using VSCode over Rider on Linux. it’s just lighter weight and I really don’t need a full IDE at the moment.
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.