public inbox for ~johnnyrichard/olang-devel@lists.sr.ht
 help / color / mirror / code / Atom feed
From: Johnny Richard <johnny@johnnyrichard.com>
To: ~johnnyrichard/olang-devel@lists.sr.ht
Cc: Johnny Richard <johnny@johnnyrichard.com>
Subject: [PATCH olang v1 2/2] codegen: x86_64: implement binary operations
Date: Sat, 27 Apr 2024 14:14:12 +0200	[thread overview]
Message-ID: <20240427121832.203068-3-johnny@johnnyrichard.com> (raw)
In-Reply-To: <20240427121832.203068-1-johnny@johnnyrichard.com>

In order to simplify most of the binary operation expressions we are
using stack to store previous execution.  It makes the implementation
easy but inefficient.

We can optimize this codegen in a near future as soon as re get IR in
place.

This change also include a small fix on binary operation precedence for
TOKEN_CMP_EQ.

Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
---
 examples/sum.ol            |   3 +
 src/codegen_linux_x86_64.c | 232 ++++++++++++++++++++++++++++++++++++-
 src/parser.c               |   2 +-
 3 files changed, 232 insertions(+), 5 deletions(-)
 create mode 100644 examples/sum.ol

diff --git a/examples/sum.ol b/examples/sum.ol
new file mode 100644
index 0000000..b724088
--- /dev/null
+++ b/examples/sum.ol
@@ -0,0 +1,3 @@
+fn main(): u32 {
+  return 1 + 4 + 60 + 4
+}
diff --git a/src/codegen_linux_x86_64.c b/src/codegen_linux_x86_64.c
index 72db1c6..0accef4 100644
--- a/src/codegen_linux_x86_64.c
+++ b/src/codegen_linux_x86_64.c
@@ -23,6 +23,8 @@
 
 #define SYS_exit (60)
 
+size_t label_index;
+
 static void
 codegen_linux_x86_64_emit_start_entrypoint(FILE *out);
 
@@ -32,6 +34,7 @@ codegen_linux_x86_64_emit_function(FILE *out, ast_fn_definition_t *fn);
 void
 codegen_linux_x86_64_emit_program(FILE *out, ast_node_t *node)
 {
+    label_index = 0;
     codegen_linux_x86_64_emit_start_entrypoint(out);
 
     assert(node->kind == AST_NODE_PROGRAM);
@@ -56,6 +59,12 @@ codegen_linux_x86_64_emit_start_entrypoint(FILE *out)
     fprintf(out, "    syscall\n");
 }
 
+static size_t
+codegen_linux_x86_64_get_next_label(void)
+{
+    return ++label_index;
+}
+
 static void
 codegen_linux_x86_64_emit_expression(FILE *out, ast_node_t *expr_node)
 {
@@ -63,14 +72,229 @@ codegen_linux_x86_64_emit_expression(FILE *out, ast_node_t *expr_node)
         case AST_NODE_LITERAL: {
             ast_literal_t literal_u32 = expr_node->data.as_literal;
             assert(literal_u32.kind == AST_LITERAL_U32);
-            uint32_t exit_code = literal_u32.value.as_u32;
+            uint32_t n = literal_u32.value.as_u32;
 
-            fprintf(out, "    mov $%d, %%eax\n", exit_code);
+            fprintf(out, "    mov $%d, %%rax\n", n);
             return;
         }
-        case AST_NODE_BINARY_OP:
+        case AST_NODE_BINARY_OP: {
+            ast_binary_op_t bin_op = expr_node->data.as_bin_op;
+            switch (bin_op.kind) {
+                case AST_BINOP_ADDITION: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    add %%rcx, %%rax\n");
+
+                    return;
+                }
+                case AST_BINOP_MULTIPLICATION: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    mul %%rcx\n");
+
+                    return;
+                }
+                case AST_BINOP_DIVISION: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    div %%rcx\n");
+
+                    return;
+                }
+                case AST_BINOP_REMINDER: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+                    fprintf(out, "    xor %%edx, %%edx\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    div %%rcx\n");
+                    fprintf(out, "    mov %%edx, %%eax\n");
+
+                    return;
+                }
+                case AST_BINOP_SUBTRACTION: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    sub %%rcx, %%rax\n");
+
+                    return;
+                }
+                case AST_BINOP_CMP_EQ: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    cmp %%rcx, %%rax\n");
+                    fprintf(out, "    sete %%al\n");
+                    fprintf(out, "    movzb %%al, %%rax\n");
+
+                    return;
+                }
+                case AST_BINOP_CMP_LT: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    cmp %%rcx, %%rax\n");
+                    fprintf(out, "    setl %%al\n");
+                    fprintf(out, "    movzb %%al, %%rax\n");
+
+                    return;
+                }
+                case AST_BINOP_CMP_GT: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    cmp %%rcx, %%rax\n");
+                    fprintf(out, "    setg %%al\n");
+                    fprintf(out, "    movzb %%al, %%rax\n");
+
+                    return;
+                }
+                case AST_BINOP_CMP_NEQ: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    cmp %%rcx, %%rax\n");
+                    fprintf(out, "    setne %%al\n");
+                    fprintf(out, "    movzb %%al, %%rax\n");
+
+                    return;
+                }
+                case AST_BINOP_CMP_LEQ: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    cmp %%rcx, %%rax\n");
+                    fprintf(out, "    setle %%al\n");
+                    fprintf(out, "    movzb %%al, %%rax\n");
+
+                    return;
+                }
+                case AST_BINOP_CMP_GEQ: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    cmp %%rcx, %%rax\n");
+                    fprintf(out, "    setge %%al\n");
+                    fprintf(out, "    movzb %%al, %%rax\n");
+
+                    return;
+                }
+                case AST_BINOP_BITWISE_LSHIFT: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    shl %%cl, %%rax\n");
+
+                    return;
+                }
+                case AST_BINOP_BITWISE_RSHIFT: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    shr %%cl, %%rax\n");
+
+                    return;
+                }
+                case AST_BINOP_BITWISE_XOR: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    xor %%ecx, %%eax\n");
+
+                    return;
+                }
+                case AST_BINOP_BITWISE_AND: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    and %%ecx, %%eax\n");
+
+                    return;
+                }
+                case AST_BINOP_BITWISE_OR: {
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    push %%rax\n");
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    pop %%rcx\n");
+                    fprintf(out, "    or %%ecx, %%eax\n");
+
+                    return;
+                }
+                case AST_BINOP_LOGICAL_AND: {
+                    size_t label_exit = codegen_linux_x86_64_get_next_label();
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    cmp $0, %%rax\n");
+                    fprintf(out, "    je .L%ld\n", label_exit);
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    cmp $0, %%rax\n");
+                    fprintf(out, "    je .L%ld\n", label_exit);
+                    fprintf(out, "    mov $1, %%rax\n");
+                    fprintf(out, ".L%ld:\n", label_exit);
+
+                    return;
+                }
+                case AST_BINOP_LOGICAL_OR: {
+                    size_t label_t = codegen_linux_x86_64_get_next_label();
+                    size_t label_f = codegen_linux_x86_64_get_next_label();
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
+                    fprintf(out, "    cmp $0, %%rax\n");
+                    fprintf(out, "    jne .L%ld\n", label_t);
+
+                    codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
+                    fprintf(out, "    cmp $0, %%rax\n");
+                    fprintf(out, "    je .L%ld\n", label_f);
+
+                    fprintf(out, ".L%ld:\n", label_t);
+                    fprintf(out, "    mov $1, %%rax\n");
+                    fprintf(out, ".L%ld:\n", label_f);
+
+                    return;
+                }
+                default: {
+                    assert(0 && "unsupported binary operation");
+                    return;
+                }
+            }
+        }
         default:
-            assert(0 && "NOT IMPLEMENTED");
+            assert(0 && "unsupported expression");
     }
 }
 
diff --git a/src/parser.c b/src/parser.c
index 5ba5a3f..5dd4ef1 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -152,7 +152,7 @@ get_binary_op_precedence(token_kind_t kind)
         case TOKEN_CMP_LEQ:
         case TOKEN_CMP_GEQ:
             return BINOP_CMP_RELATIONAL_PREC;
-        case TOKEN_EQ:
+        case TOKEN_CMP_EQ:
         case TOKEN_CMP_NEQ:
             return BINOP_CMP_EQUALITY_PREC;
         case TOKEN_AND:
-- 
2.44.0


  parent reply	other threads:[~2024-04-27 11:20 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-27 12:14 [PATCH olang v1 0/2] " Johnny Richard
2024-04-27 12:14 ` [PATCH olang v1 1/2] codegen: x86_64: extract function to emit expression Johnny Richard
2024-04-27 12:14 ` Johnny Richard [this message]
2024-04-27 11:21   ` [olang/patches/.build.yml] build success builds.sr.ht
2024-05-03  2:04   ` [PATCH olang v1 2/2] codegen: x86_64: implement binary operations Carlos Maniero
2024-08-25 13:52 ` [PATCH olang v1 0/2] " Johnny Richard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240427121832.203068-3-johnny@johnnyrichard.com \
    --to=johnny@johnnyrichard.com \
    --cc=~johnnyrichard/olang-devel@lists.sr.ht \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.johnnyrichard.com/olang.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox