public inbox for ~johnnyrichard/olang-devel@lists.sr.ht
 help / color / mirror / code / Atom feed
* [olang/patches/.build.yml] build success
  2024-04-27 12:14 ` [PATCH olang v1 2/2] codegen: x86_64: implement binary operations Johnny Richard
@ 2024-04-27 11:21   ` builds.sr.ht
  2024-05-03  2:04   ` [PATCH olang v1 2/2] codegen: x86_64: implement binary operations Carlos Maniero
  1 sibling, 0 replies; 6+ messages in thread
From: builds.sr.ht @ 2024-04-27 11:21 UTC (permalink / raw)
  To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel

olang/patches/.build.yml: SUCCESS in 43s

[codegen: x86_64: implement binary operations][0] from [Johnny Richard][1]

[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/51409
[1]: mailto:johnny@johnnyrichard.com

✓ #1206119 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1206119

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH olang v1 0/2] codegen: x86_64: implement binary operations
@ 2024-04-27 12:14 Johnny Richard
  2024-04-27 12:14 ` [PATCH olang v1 1/2] codegen: x86_64: extract function to emit expression Johnny Richard
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Johnny Richard @ 2024-04-27 12:14 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Johnny Richard

Johnny Richard (2):
  codegen: x86_64: extract function to emit expression
  codegen: x86_64: implement binary operations

 examples/sum.ol            |   3 +
 src/codegen_linux_x86_64.c | 253 ++++++++++++++++++++++++++++++++++++-
 src/parser.c               |   2 +-
 3 files changed, 250 insertions(+), 8 deletions(-)
 create mode 100644 examples/sum.ol


base-commit: 36b028f712ff2402761ea307467860c346d3c0a0
-- 
2.44.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH olang v1 1/2] codegen: x86_64: extract function to emit expression
  2024-04-27 12:14 [PATCH olang v1 0/2] codegen: x86_64: implement binary operations Johnny Richard
@ 2024-04-27 12:14 ` Johnny Richard
  2024-04-27 12:14 ` [PATCH olang v1 2/2] codegen: x86_64: implement binary operations Johnny Richard
  2024-08-25 13:52 ` [PATCH olang v1 0/2] " Johnny Richard
  2 siblings, 0 replies; 6+ messages in thread
From: Johnny Richard @ 2024-04-27 12:14 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Johnny Richard

We want to generalize how we emit expressions since we could have
different ast_node types.  Today we are expecting integer literal but we
want to make room for emitting binary operations as well.

Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
---
 src/codegen_linux_x86_64.c | 29 ++++++++++++++++++++++-------
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/src/codegen_linux_x86_64.c b/src/codegen_linux_x86_64.c
index d4f8222..72db1c6 100644
--- a/src/codegen_linux_x86_64.c
+++ b/src/codegen_linux_x86_64.c
@@ -56,6 +56,24 @@ codegen_linux_x86_64_emit_start_entrypoint(FILE *out)
     fprintf(out, "    syscall\n");
 }
 
+static void
+codegen_linux_x86_64_emit_expression(FILE *out, ast_node_t *expr_node)
+{
+    switch (expr_node->kind) {
+        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;
+
+            fprintf(out, "    mov $%d, %%eax\n", exit_code);
+            return;
+        }
+        case AST_NODE_BINARY_OP:
+        default:
+            assert(0 && "NOT IMPLEMENTED");
+    }
+}
+
 static void
 codegen_linux_x86_64_emit_function(FILE *out, ast_fn_definition_t *fn)
 {
@@ -70,14 +88,11 @@ codegen_linux_x86_64_emit_function(FILE *out, ast_fn_definition_t *fn)
     assert(return_node->kind == AST_NODE_RETURN_STMT);
     ast_return_stmt_t return_stmt = return_node->data.as_return_stmt;
 
-    ast_node_t *literal_node = return_stmt.data;
-    assert(literal_node->kind == AST_NODE_LITERAL);
-    ast_literal_t literal_u32 = literal_node->data.as_literal;
-
-    assert(literal_u32.kind == AST_LITERAL_U32);
-    uint32_t exit_code = literal_u32.value.as_u32;
+    ast_node_t *expr = return_stmt.data;
 
     fprintf(out, "" SV_FMT ":\n", SV_ARG(fn->identifier));
-    fprintf(out, "    mov $%d, %%eax\n", exit_code);
+
+    codegen_linux_x86_64_emit_expression(out, expr);
+
     fprintf(out, "    ret\n");
 }
-- 
2.44.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH olang v1 2/2] codegen: x86_64: implement binary operations
  2024-04-27 12:14 [PATCH olang v1 0/2] codegen: x86_64: implement binary operations 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
  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
  2 siblings, 2 replies; 6+ messages in thread
From: Johnny Richard @ 2024-04-27 12:14 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel; +Cc: Johnny Richard

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


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH olang v1 2/2] codegen: x86_64: implement binary operations
  2024-04-27 12:14 ` [PATCH olang v1 2/2] codegen: x86_64: implement binary operations Johnny Richard
  2024-04-27 11:21   ` [olang/patches/.build.yml] build success builds.sr.ht
@ 2024-05-03  2:04   ` Carlos Maniero
  1 sibling, 0 replies; 6+ messages in thread
From: Carlos Maniero @ 2024-05-03  2:04 UTC (permalink / raw)
  To: Johnny Richard, ~johnnyrichard/olang-devel

That's a brilliant work man. I'm inspired in how simple the code is. I
even took a look at our previous work on pipa, and this patch is art
compared with pipa's implementation. Kudos!

There is just one issue with the current implementation:

>                 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;
>                 }

You should always ensure *rdx* is zero right before calling the *div*
instruction otherwise the code bellow will return an unexpected value.

  fn main(): u32 {
    return 7 / 3 / 3
  }

The same is valid for the reminder operation.

I also missed integration tests, the issue I described before could only
be catch over an integration test. I know we don't have the best ever
developer experience for integration tests, but following the
*test_cli_compile_minimal_program* test structure could save us a lot of
time in the future during refactors.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH olang v1 0/2] codegen: x86_64: implement binary operations
  2024-04-27 12:14 [PATCH olang v1 0/2] codegen: x86_64: implement binary operations 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 ` [PATCH olang v1 2/2] codegen: x86_64: implement binary operations Johnny Richard
@ 2024-08-25 13:52 ` Johnny Richard
  2 siblings, 0 replies; 6+ messages in thread
From: Johnny Richard @ 2024-08-25 13:52 UTC (permalink / raw)
  To: ~johnnyrichard/olang-devel

Patchset SUPERSEDED by v2[1]

[1]:  Message-ID: <20240825132523.253490-1-johnny@johnnyrichard.com>


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-08-25 13:52 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-27 12:14 [PATCH olang v1 0/2] codegen: x86_64: implement binary operations 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 ` [PATCH olang v1 2/2] codegen: x86_64: implement binary operations Johnny Richard
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

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