From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp0.migadu.com ([2001:41d0:303:e224::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id GHZbJUZq92ZxkwAAqHPOHw:P1 (envelope-from ) for ; Sat, 28 Sep 2024 04:30:30 +0200 Received: from aspmx1.migadu.com ([2001:41d0:303:e224::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp0.migadu.com with LMTPS id GHZbJUZq92ZxkwAAqHPOHw (envelope-from ) for ; Sat, 28 Sep 2024 04:30:30 +0200 X-Envelope-To: patches@johnnyrichard.com Authentication-Results: aspmx1.migadu.com; none Received: from mail-a.sr.ht (mail-a.sr.ht [46.23.81.152]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 79B951971D for ; Sat, 28 Sep 2024 04:30:30 +0200 (CEST) DKIM-Signature: a=rsa-sha256; bh=inpHloeGcuNyHU/dMvhXUhjdJwETwyqNeKoMKnDUnFQ=; c=simple/simple; d=lists.sr.ht; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Unsubscribe:List-Subscribe:List-Archive:List-Post:List-ID; q=dns/txt; s=20240113; t=1727490629; v=1; b=EoF54NH/GEgwpQrtg6p3LgK5z4RJjkbtTwobGFA66f6kSxJ5o49+6zX3cYFs0CtkgCxNbwj3 j4YVPvj/xv1M/+qAb5+EKCRqN4SPnkPKJVBBUsVUly0j1FTpUnxcC/UwWkxWpO4bjDWOaAZfvLK 3S4kX22uzh64a97CNjtHhZLUjDy7INum8h9wwgyvQR05r4m26aBpGPbiievwa/0jDULof1FvJK5 3+3Vq/14k+aMLo1cl6hMDNqw9SQdELuRp/9XzB4QIkBBaWrKSEaMDqVo+5Eu2eBGTYS5h0eadCg dIJa9PKAd/z2dQ1IKQW+oJET66FHPrXs+Nm+lZRX7Hx7Q== Received: from lists.sr.ht (unknown [46.23.81.154]) by mail-a.sr.ht (Postfix) with ESMTPSA id 76DE02032E for ; Sat, 28 Sep 2024 02:30:29 +0000 (UTC) Received: from out-185.mta0.migadu.com (out-185.mta0.migadu.com [91.218.175.185]) by mail-a.sr.ht (Postfix) with ESMTPS id 9ABD4202E3 for <~johnnyrichard/olang-devel@lists.sr.ht>; Sat, 28 Sep 2024 02:30:28 +0000 (UTC) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=johnnyrichard.com; s=key1; t=1727490628; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zleXIrjpPx/jLvtaXMF3k7h8eJw3PIGy/s7HqmC2/VY=; b=eruHb91V2cB4PVakP20LCv4/r5AAtu8SNdvxOebv/1y8p/iBmg/Dm2I36LZA6MVYITXixr plVqXGx0ZodCUjg4Bae//vc3KcUqbSZ4ucrazZakO0QTrF6R+kzKYa76u9ygG0EDIxM6yR JUMs1FuTmX2QELh5adP62xm0SYStkPFwae8wwmiSOo2d03r84h7krWqp3bcx68sKP5B2BR 5j2B+PVqMpmnbP9m0+OP3ocpvXd10300SWN/8NMQC2mQZeEakN02SoNAUbE63WJnjmNYWd oylClGultdAxOv0kFLuGOV8z8mF4Ek4PXwNbVqOx7npitSuU9nAxr1KWT+A8pg== From: Johnny Richard To: ~johnnyrichard/olang-devel@lists.sr.ht Cc: Johnny Richard Subject: [PATCH olang v1 2/2] codegen: x64: implement function call Date: Sat, 28 Sep 2024 06:29:28 +0200 Message-ID: <20240928043016.104228-3-johnny@johnnyrichard.com> In-Reply-To: <20240928043016.104228-1-johnny@johnnyrichard.com> References: <20240928043016.104228-1-johnny@johnnyrichard.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Sourcehut-Patchset-Status: UNKNOWN List-Unsubscribe: List-Subscribe: List-Archive: Archived-At: List-Post: List-ID: ~johnnyrichard/olang-devel <~johnnyrichard/olang-devel.lists.sr.ht> Sender: ~johnnyrichard/olang-devel <~johnnyrichard/olang-devel@lists.sr.ht> X-Migadu-Flow: FLOW_IN X-Migadu-Country: NL X-Migadu-Scanner: mx12.migadu.com X-Migadu-Spam-Score: -4.00 X-Spam-Score: -4.00 X-Migadu-Queue-Id: 79B951971D X-TUID: 1U6sV4KWb5Nh The current function call is limited to parameters with 64bits only and 6 arguments max (we have to allow pass arguments through stack after 6th argument). The previous function-definition implementation was using the global scope to register parameters symbols, after this change function parameters must have their own scope. Signed-off-by: Johnny Richard --- src/checker.c | 6 +- src/codegen_linux_x86_64.c | 268 ++++++++++++++++++++++++++++++-- tests/olc/0028_function_call.ol | 10 +- 3 files changed, 263 insertions(+), 21 deletions(-) diff --git a/src/checker.c b/src/checker.c index 7c3767f..b7cbe20 100644 --- a/src/checker.c +++ b/src/checker.c @@ -65,7 +65,7 @@ populate_scope(checker_t *checker, scope_t *scope, ast_node_t *ast) case AST_NODE_FN_DEF: { ast_fn_definition_t *fn_def = &ast->as_fn_def; - fn_def->scope = scope; + fn_def->scope = scope_push(scope); list_item_t *item = list_head(fn_def->params); @@ -73,12 +73,12 @@ populate_scope(checker_t *checker, scope_t *scope, ast_node_t *ast) ast_fn_param_t *param = (ast_fn_param_t *)item->value; symbol_t *symbol = symbol_new(checker->arena, param->id, type_from_id(param->type_id)); - scope_insert(scope, symbol); + scope_insert(fn_def->scope, symbol); item = list_next(item); } - populate_scope(checker, scope, ast->as_fn_def.block); + populate_scope(checker, fn_def->scope, ast->as_fn_def.block); return; } diff --git a/src/codegen_linux_x86_64.c b/src/codegen_linux_x86_64.c index 0173443..e04de0e 100644 --- a/src/codegen_linux_x86_64.c +++ b/src/codegen_linux_x86_64.c @@ -29,6 +29,34 @@ // The call instruction pushes EIP into stack so the first 8 bytes from stack // must be preserved else the ret instruction will jump to nowere. #define X86_CALL_EIP_STACK_OFFSET (8) +#define X86_CALL_ARG_SIZE 6 + +typedef enum x86_64_register_type +{ + REG_ACCUMULATOR, + REG_BASE, + REG_COUNTER, + REG_DATA, + REG_SRC_IDX, + REG_DEST_IDX, + REG_STACK_PTR, + REG_BASE_PTR, + REG_R8, + REG_R9, + REG_R10, + REG_R11, + REG_R12, + REG_R13, + REG_R14, + REG_R15 +} x86_64_register_type_t; + +/** + * Arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7 Notes + * ────────────────────────────────────────────────────────────── + * x86-64 rdi rsi rdx r10 r8 r9 - + */ +static int x86_call_args[X86_CALL_ARG_SIZE] = { REG_DEST_IDX, REG_SRC_IDX, REG_DATA, REG_R10, REG_R8, REG_R9 }; static void codegen_linux_x86_64_emit_start_entrypoint(codegen_x86_64_t *codegen); @@ -40,7 +68,7 @@ static size_t type_to_bytes(type_t *type); static char * -get_accumulator_reg_for(size_t bytes); +get_reg_for(x86_64_register_type_t type, size_t bytes); void codegen_linux_x86_64_init(codegen_x86_64_t *codegen, arena_t *arena, FILE *out) @@ -131,7 +159,31 @@ codegen_linux_x86_64_emit_expression(codegen_x86_64_t *codegen, ast_node_t *expr fprintf(codegen->out, " mov -%ld(%%rbp), %s\n", *offset, - get_accumulator_reg_for(type_to_bytes(&symbol->type))); + get_reg_for(REG_ACCUMULATOR, type_to_bytes(&symbol->type))); + return; + } + case AST_NODE_FN_CALL: { + ast_fn_call_t fn_call = expr_node->as_fn_call; + + size_t i = 0; + for (list_item_t *item = list_head(fn_call.args); item != NULL; item = list_next(item)) { + // FIXME: add support for more args than X86_CALL_ARG_SIZE + assert(i < X86_CALL_ARG_SIZE); + + ast_node_t *arg_node = (ast_node_t *)item->value; + + codegen_linux_x86_64_emit_expression(codegen, arg_node); + + // FIXME: should get the correct size according to the ast node + fprintf(codegen->out, " push %s\n", get_reg_for(REG_ACCUMULATOR, 8)); + ++i; + } + + for (; i > 0; --i) { + fprintf(codegen->out, " pop %s\n", get_reg_for(x86_call_args[i - 1], 8)); + } + + fprintf(codegen->out, " call " SV_FMT "\n", SV_ARG(fn_call.id)); return; } case AST_NODE_BINARY_OP: { @@ -373,6 +425,7 @@ codegen_linux_x86_64_emit_block(codegen_x86_64_t *codegen, ast_block_t *block) codegen_linux_x86_64_emit_expression(codegen, expr); fprintf(codegen->out, " mov %%rbp, %%rsp\n"); + fprintf(codegen->out, " pop %%rbp\n"); fprintf(codegen->out, " ret\n"); break; @@ -401,7 +454,7 @@ codegen_linux_x86_64_emit_block(codegen_x86_64_t *codegen, ast_block_t *block) fprintf(codegen->out, " mov %s, -%ld(%%rbp)\n", - get_accumulator_reg_for(type_size), + get_reg_for(REG_ACCUMULATOR, type_size), codegen->base_offset); codegen->base_offset += type_size; @@ -497,16 +550,45 @@ calculate_fn_local_size(scope_t *scope) } static void -codegen_linux_x86_64_emit_function(codegen_x86_64_t *codegen, ast_fn_definition_t *fn) +codegen_linux_x86_64_emit_function(codegen_x86_64_t *codegen, ast_fn_definition_t *fn_def) { codegen->base_offset = X86_CALL_EIP_STACK_OFFSET; - ast_node_t *block_node = fn->block; - fprintf(codegen->out, "" SV_FMT ":\n", SV_ARG(fn->id)); + ast_node_t *block_node = fn_def->block; + fprintf(codegen->out, "" SV_FMT ":\n", SV_ARG(fn_def->id)); + fprintf(codegen->out, " push %%rbp\n"); fprintf(codegen->out, " mov %%rsp, %%rbp\n"); - size_t local_size = calculate_fn_local_size(fn->scope); + size_t i = 0; + for (list_item_t *item = list_head(fn_def->params); item != NULL; item = list_next(item)) { + assert(i < X86_CALL_ARG_SIZE); + + ast_fn_param_t *param = item->value; + + size_t *offset = arena_alloc(codegen->arena, sizeof(size_t)); + *offset = codegen->base_offset; + + symbol_t *symbol = scope_lookup(fn_def->scope, param->id); + assert(symbol); + + char symbol_ptr[PTR_HEX_CSTR_SIZE]; + sprintf(symbol_ptr, "%p", (void *)symbol); + + map_put(codegen->symbols_stack_offset, symbol_ptr, offset); + + fprintf(codegen->out, + " mov %s, -%ld(%s)\n", + get_reg_for(x86_call_args[i], 8), + *offset, + get_reg_for(REG_BASE_PTR, 8)); + + // FIXME: add offset according to the param size + codegen->base_offset += 8; + ++i; + } + + size_t local_size = calculate_fn_local_size(fn_def->scope); if (local_size != 0) { fprintf(codegen->out, " sub $%ld, %%rsp\n", local_size); @@ -519,14 +601,170 @@ codegen_linux_x86_64_emit_function(codegen_x86_64_t *codegen, ast_fn_definition_ } static char * -get_accumulator_reg_for(size_t bytes) +get_reg_for(x86_64_register_type_t type, size_t bytes) { - if (bytes <= 1) { - return "%ah"; - } else if (bytes <= 2) { - return "%ax"; - } else if (bytes <= 4) { - return "%eax"; + switch (type) { + case REG_ACCUMULATOR: { + if (bytes <= 1) { + return "%ah"; + } else if (bytes <= 2) { + return "%ax"; + } else if (bytes <= 4) { + return "%eax"; + } + return "%rax"; + } + case REG_BASE: { + if (bytes <= 1) { + return "%bh"; + } else if (bytes <= 2) { + return "%bx"; + } else if (bytes <= 4) { + return "%ebx"; + } + return "%rbx"; + } + case REG_COUNTER: { + if (bytes <= 1) { + return "%ch"; + } else if (bytes <= 2) { + return "%cx"; + } else if (bytes <= 4) { + return "%ecx"; + } + return "%rcx"; + } + case REG_DATA: { + if (bytes <= 1) { + return "%dh"; + } else if (bytes <= 2) { + return "%dx"; + } else if (bytes <= 4) { + return "%edx"; + } + return "%rdx"; + } + case REG_SRC_IDX: { + if (bytes <= 1) { + return "%sil"; + } else if (bytes <= 2) { + return "%si"; + } else if (bytes <= 4) { + return "%esi"; + } + return "%rsi"; + } + case REG_DEST_IDX: { + if (bytes <= 1) { + return "%sil"; + } else if (bytes <= 2) { + return "%di"; + } else if (bytes <= 4) { + return "%edi"; + } + return "%rdi"; + } + case REG_STACK_PTR: { + if (bytes <= 1) { + return "%spl"; + } else if (bytes <= 2) { + return "%sp"; + } else if (bytes <= 4) { + return "%esp"; + } + return "%rsp"; + } + case REG_BASE_PTR: { + if (bytes <= 1) { + return "%bpl"; + } else if (bytes <= 2) { + return "%bp"; + } else if (bytes <= 4) { + return "%ebp"; + } + return "%rbp"; + } + case REG_R8: { + if (bytes <= 1) { + return "%r8b"; + } else if (bytes <= 2) { + return "%r8w"; + } else if (bytes <= 4) { + return "%r8d"; + } + return "%r8"; + } + case REG_R9: { + if (bytes <= 1) { + return "%r9b"; + } else if (bytes <= 2) { + return "%r9w"; + } else if (bytes <= 4) { + return "%r9d"; + } + return "%r9"; + } + case REG_R10: { + if (bytes <= 1) { + return "%r10b"; + } else if (bytes <= 2) { + return "%r10w"; + } else if (bytes <= 4) { + return "%r10d"; + } + return "%r10"; + } + case REG_R11: { + if (bytes <= 1) { + return "%r11b"; + } else if (bytes <= 2) { + return "%r11w"; + } else if (bytes <= 4) { + return "%r11d"; + } + return "%r11"; + } + case REG_R12: { + if (bytes <= 1) { + return "%r12b"; + } else if (bytes <= 2) { + return "%r12w"; + } else if (bytes <= 4) { + return "%r12d"; + } + return "%r12"; + } + case REG_R13: { + if (bytes <= 1) { + return "%r13b"; + } else if (bytes <= 2) { + return "%r13w"; + } else if (bytes <= 4) { + return "%r13d"; + } + return "%r13"; + } + case REG_R14: { + if (bytes <= 1) { + return "%r14b"; + } else if (bytes <= 2) { + return "%r14w"; + } else if (bytes <= 4) { + return "%r14d"; + } + return "%r14"; + } + case REG_R15: { + if (bytes <= 1) { + return "%r15b"; + } else if (bytes <= 2) { + return "%r15w"; + } else if (bytes <= 4) { + return "%r15d"; + } + return "%r15"; + } } - return "%rax"; + assert(0 && "invalid register"); + return NULL; } diff --git a/tests/olc/0028_function_call.ol b/tests/olc/0028_function_call.ol index cfaa969..cfd06de 100644 --- a/tests/olc/0028_function_call.ol +++ b/tests/olc/0028_function_call.ol @@ -17,10 +17,14 @@ fn main(): u8 { return add(40, 2) } -fn add(a: u32, b: u32): u8 { +fn add(a: u64, b: u64): u8 { return a + b } +# TEST test_compile(exit_code=0) + +# TEST test_run_binary(exit_code=42) + # TEST test_ast WITH # Translation_Unit # |-Function_Definition @@ -30,8 +34,8 @@ fn add(a: u32, b: u32): u8 { # | |-Literal # | `-Literal # `-Function_Definition -# |-Param_Definition -# |-Param_Definition +# |-Param_Definition +# |-Param_Definition # `-Block # `-Return_Statement # `-Binary_Operation (+) -- 2.46.0