You are browsing as a guest. Sign up (or log in) to start making projects!

4h 19m 49s logged

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.

0
79

Comments 0

No comments yet. Be the first!