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
next prev 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