From b2724caedaa9942bccae7d99e8bb5b37331dea90 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 23 Nov 2024 17:10:37 +0100 Subject: [PATCH] Begin work on asm label support. --- src/compiler/codegen_asm.c | 10 ++++++++++ src/compiler/compiler_internal.h | 4 +++- src/compiler/copying.c | 1 + src/compiler/enums.h | 1 + src/compiler/llvm_codegen_stmt.c | 1 + src/compiler/parse_stmt.c | 8 ++++++++ src/compiler/sema_asm.c | 21 ++++++--------------- src/compiler/sema_decls.c | 1 + src/compiler/sema_liveness.c | 1 + src/compiler/sema_stmts.c | 22 ++++++++++++++++++++++ 10 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/compiler/codegen_asm.c b/src/compiler/codegen_asm.c index 20b2149ff..105848871 100644 --- a/src/compiler/codegen_asm.c +++ b/src/compiler/codegen_asm.c @@ -7,6 +7,13 @@ #define CAST_AND_EXTEND(x, n) \ (((int64_t)((x) << (64 - (n)))) >> (64 - (n))) +INLINE bool codegen_asm_label(Ast *ast) +{ + if (ast->ast_kind != AST_ASM_LABEL) return false; + scratch_buffer_printf("${:private}%s.${:uid}:\n", ast->asm_label); + return true; +} + static inline void codegen_create_x86att_arg(AsmInlineBlock *block, unsigned input_offset, Expr *expr) { ExprAsmArg *arg = &expr->expr_asm_arg; @@ -177,6 +184,7 @@ static inline char *codegen_create_x86_att_asm(AsmInlineBlock *block) { Ast *ast = astptr(next); next = ast->next; + if (codegen_asm_label(ast)) continue; scratch_buffer_append(ast->asm_stmt.instruction); Expr** args = ast->asm_stmt.args; unsigned arg_count = vec_size(args); @@ -201,6 +209,7 @@ static inline char *codegen_create_aarch64_asm(AsmInlineBlock *block) { Ast *ast = astptr(next); next = ast->next; + if (codegen_asm_label(ast)) continue; scratch_buffer_append(ast->asm_stmt.instruction); Expr** args = ast->asm_stmt.args; unsigned arg_count = vec_size(args); @@ -225,6 +234,7 @@ static inline char *codegen_create_riscv_asm(AsmInlineBlock *block) { Ast *ast = astptr(next); next = ast->next; + if (codegen_asm_label(ast)) continue; scratch_buffer_append(ast->asm_stmt.instruction); Expr** args = ast->asm_stmt.args; unsigned arg_count = vec_size(args); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 4f90aa63e..000f9d8b3 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1376,8 +1376,8 @@ typedef struct typedef struct { Clobbers clobbers; - const char *asm_block; AstId asm_stmt; + Ast **labels; ExprAsmArg **output_vars; ExprAsmArg **input; } AsmInlineBlock; @@ -1454,8 +1454,10 @@ typedef struct Ast_ union { FlowCommon flow; // Shared struct + AstAsmBlock asm_block_stmt; AstAsmStmt asm_stmt; + const char *asm_label; AstAssertStmt assert_stmt; // 16 AstCaseStmt case_stmt; // 32 AstCompoundStmt compound_stmt; // 12 diff --git a/src/compiler/copying.c b/src/compiler/copying.c index e89389119..4d572885f 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -727,6 +727,7 @@ Ast *ast_copy_deep(CopyStruct *c, Ast *source) MACRO_COPY_EXPRID(ast->nextcase_stmt.expr); break; case AST_NOP_STMT: + case AST_ASM_LABEL: break; case AST_BLOCK_EXIT_STMT: case AST_RETURN_STMT: diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 7f2ddd06d..1524c1bab 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -188,6 +188,7 @@ typedef enum AST_POISONED, AST_ASM_STMT, AST_ASM_BLOCK_STMT, + AST_ASM_LABEL, AST_ASSERT_STMT, AST_BREAK_STMT, AST_CASE_STMT, diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index aecc355e4..c4ea4a5f6 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -1612,6 +1612,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) case AST_FOREACH_STMT: case AST_CONTRACT: case AST_ASM_STMT: + case AST_ASM_LABEL: case AST_CONTRACT_FAULT: case AST_CASE_STMT: case AST_DEFAULT_STMT: diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 2e98fac2d..48e8c115c 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -380,6 +380,14 @@ static inline Expr *parse_asm_expr(ParseContext *c) static inline Ast *parse_asm_stmt(ParseContext *c) { Ast *asm_stmt = ast_new_curr(c, AST_ASM_STMT); + if (tok_is(c, TOKEN_CONST_IDENT)) + { + asm_stmt->asm_label = symstr(c); + advance_and_verify(c, TOKEN_CONST_IDENT); + asm_stmt->ast_kind = AST_ASM_LABEL; + TRY_CONSUME_OR_RET(TOKEN_COLON, "Expected a ':' to terminate the label.", poisoned_ast); + return asm_stmt; + } if (!tok_is(c, TOKEN_IDENT) && !tok_is(c, TOKEN_INT)) { PRINT_ERROR_HERE("Expected an asm instruction here."); diff --git a/src/compiler/sema_asm.c b/src/compiler/sema_asm.c index 07de529d3..3aa37a845 100644 --- a/src/compiler/sema_asm.c +++ b/src/compiler/sema_asm.c @@ -184,8 +184,7 @@ static inline bool sema_check_asm_arg_addr(SemaContext *context, AsmInlineBlock { if (!arg_type.is_address) { - SEMA_ERROR(expr, "An address cannot appear in this slot."); - return false; + RETURN_SEMA_ERROR(expr, "An address cannot appear in this slot."); } ExprAsmArg *asm_arg = &expr->expr_asm_arg; Expr *base = exprptr(asm_arg->base); @@ -207,8 +206,7 @@ static inline bool sema_check_asm_arg_addr(SemaContext *context, AsmInlineBlock TODO break; default: - SEMA_ERROR(expr, "Expected a register here."); - return false; + RETURN_SEMA_ERROR(expr, "Expected a register here."); } Expr *index = exprptrzero(asm_arg->idx); @@ -232,8 +230,7 @@ static inline bool sema_check_asm_arg_addr(SemaContext *context, AsmInlineBlock } if (bit_size != index_size) { - SEMA_ERROR(index, "Expected the same register size as for the base value."); - return false; + RETURN_SEMA_ERROR(index, "Expected the same register size as for the base value."); } } if ((compiler.platform.arch == ARCH_TYPE_RISCV32 || @@ -243,8 +240,7 @@ static inline bool sema_check_asm_arg_addr(SemaContext *context, AsmInlineBlock if ((asm_arg->neg_offset && asm_arg->offset > abs(INT12_MIN)) || (!asm_arg->neg_offset && asm_arg->offset > INT12_MAX)) { - SEMA_ERROR(expr, "RISC-V offset limited to 12-bits signed."); - return false; + RETURN_SEMA_ERROR(expr, "RISC-V offset limited to 12-bits signed."); } } @@ -256,15 +252,10 @@ static inline bool sema_check_asm_arg_reg(SemaContext *context, AsmInlineBlock * { const char *name = expr->expr_asm_arg.reg.name; AsmRegister *reg = expr->expr_asm_arg.reg.ref = asm_reg_by_name(&compiler.platform, name); - if (!reg) - { - SEMA_ERROR(expr, "Expected a valid register name."); - return false; - } + if (!reg) RETURN_SEMA_ERROR(expr, "Expected a valid register name."); if (!sema_reg_is_valid_in_slot(reg, arg_type)) { - SEMA_ERROR(expr, "'%s' is not valid in this slot.", reg->name); - return false; + RETURN_SEMA_ERROR(expr, "'%s' is not valid in this slot.", reg->name); } if (arg_type.is_write) { diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 494808e8d..fe28a0738 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -3700,6 +3700,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *er continue; case AST_POISONED: case AST_ASM_STMT: + case AST_ASM_LABEL: case AST_ASM_BLOCK_STMT: case AST_ASSERT_STMT: case AST_BREAK_STMT: diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index 6bf9fb99c..8fb43140f 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -111,6 +111,7 @@ static void sema_trace_stmt_liveness(Ast *ast) sema_trace_stmt_liveness(astptr(ast->defer_stmt.body)); return; case AST_NOP_STMT: + case AST_ASM_LABEL: return; case AST_COMPOUND_STMT: sema_trace_stmt_chain_liveness(ast->compound_stmt.first_stmt); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index c191c96ef..27264faf0 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -51,6 +51,22 @@ static bool sema_analyse_require(SemaContext *context, Ast *directive, AstId **a static bool sema_analyse_ensure(SemaContext *context, Ast *directive); static bool sema_analyse_optional_returns(SemaContext *context, Ast *directive); +static inline bool sema_analyse_asm_label(SemaContext *context, AsmInlineBlock *block, Ast *label) +{ + const char *name = label->asm_label; + FOREACH(Ast *, other, block->labels) + { + if (name == other->asm_label) + { + SEMA_ERROR(label, "Duplicate ASM label '%s'.", name); + SEMA_NOTE(other, "The previous definition was here."); + return false; + } + } + vec_add(block->labels, label); + return true; +} + static inline bool sema_analyse_asm_stmt(SemaContext *context, Ast *stmt) { if (stmt->asm_block_stmt.is_string) return sema_analyse_asm_string_stmt(context, stmt); @@ -68,6 +84,11 @@ static inline bool sema_analyse_asm_stmt(SemaContext *context, Ast *stmt) { Ast *ast = astptr(ast_id); ast_id = ast->next; + if (ast->ast_kind == AST_ASM_LABEL) + { + sema_analyse_asm_label(context, block, ast); + continue; + } if (!sema_analyse_asm(context, block, ast)) return false; } return true; @@ -2910,6 +2931,7 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state case AST_IF_CATCH_SWITCH_STMT: case AST_CONTRACT: case AST_ASM_STMT: + case AST_ASM_LABEL: case AST_CONTRACT_FAULT: UNREACHABLE case AST_DECLS_STMT: