From 55377f71ef55980b95ec2ce836ac6db82e9d7c4b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Aug 2026 13:21:40 +0100 Subject: [PATCH] Support `#byte` directive for `asm` templates --- src/check_asm.cpp | 32 ++++++++++++++++++++++++++++++++ src/llvm_backend_asm.cpp | 19 +++++++++++++++++++ src/parser.cpp | 14 ++++++++++++++ src/parser.hpp | 5 +++++ src/parser_pos.cpp | 7 +++++++ 5 files changed, 77 insertions(+) diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 6c077d1de..ea50aa45e 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -1486,6 +1486,38 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity } case_end; + case_ast_node(dir, AsmDirective, instruction_); + String name = dir->name.string; + if (name == "byte") { + if (dir->operands.count == 0) { + error(dir->name, "Expected 1 or more integers for the asm directive #%.*s", LIT(name)); + break; + } + array_clear(&operands); + for (Ast *expr : dir->operands) { + Operand operand = {}; + check_asm_instruction_operand(asm_ctx, ctx, entity, &operand, expr, /*allow_memory_operands*/true); + array_add(&operands, operand); + } + for (auto const &op : operands) { + if (op.mode != Addressing_Constant) { + error(op.expr, "Expected an integer for the asm directive #%.*s", LIT(name)); + continue; + } + ExactValue ev = exact_value_to_integer(op.value); + if (ev.kind != ExactValue_Integer) { + error(op.expr, "Expected an integer for the asm directive #%.*s", LIT(name)); + continue; + } + i64 i = exact_value_to_i64(ev); + if (i < 0 || i > 255) { + error(op.expr, "Expected an integer within 0..<256 for the asm directive #%.*s, got %lld", LIT(name), cast(long long)i); + continue; + } + } + } + case_end; + default: error(instruction_, "Unexpected instruction in asm template"); break; diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index d107b5032..19a902c99 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -480,6 +480,25 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { asm_string = this->write_label(asm_string, &label->name->Ident); asm_string = gb_string_appendc(asm_string, ":"); case_end; + case_ast_node(dir, AsmDirective, instr_); + String name = dir->name.string; + if (name == "byte") { + asm_string = gb_string_appendc(asm_string, ".byte "); + isize op_index = 0; + for (auto const &op : dir->operands) { + if (op_index > 0) { + asm_string = gb_string_appendc(asm_string, ", "); + } + ExactValue ev = exact_value_to_integer(op->tav.value); + GB_ASSERT(ev.kind == ExactValue_Integer); + i64 i = exact_value_to_i64(ev); + asm_string = gb_string_append_fmt(asm_string, "%d", cast(int)i); + op_index += 1; + } + } else { + GB_PANIC("Invalid asm directive: %.*s", LIT(name)); + } + case_end; default: GB_PANIC("Invalid asm instruction"); break; diff --git a/src/parser.cpp b/src/parser.cpp index 2d78991c2..02c35687e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -551,6 +551,9 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) { n->AsmMemoryOperand.disp = clone_ast(n->AsmMemoryOperand.disp, f); n->AsmMemoryOperand.type = clone_ast(n->AsmMemoryOperand.type, f); break; + case Ast_AsmDirective: + n->AsmDirective.operands = clone_ast_array(n->AsmDirective.operands, f); + break; } return n; } @@ -2573,6 +2576,17 @@ gb_internal Ast *parse_asm_instruction(AstFile *f) { label_decl->AsmLabelDecl.name = name; return label_decl; } + case Token_Hash: + { + Token token = expect_token(f, Token_Hash); + Token name = expect_token(f, Token_Ident); + auto operands = parse_asm_operands(f); + Ast *dir = alloc_ast_node(f, Ast_AsmDirective); + dir->AsmDirective.token = token; + dir->AsmDirective.name = name; + dir->AsmDirective.operands = operands; + return dir; + } } syntax_error(f->curr_token, "Expected an asm instruction, got '%.*s'", LIT(f->curr_token.string)); advance_token(f); diff --git a/src/parser.hpp b/src/parser.hpp index fb3445825..d39b28589 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -512,6 +512,11 @@ struct AstSplitArgs { Ast * type; \ Token close; \ }) \ + AST_KIND(AsmDirective, "asm directive", struct { \ + Token token; \ + Token name; \ + Slice operands; \ + }) \ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \ AST_KIND(TagExpr, "tag expression", struct { Token token, name; Ast *expr; }) \ diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index 96611b7a8..99f1ce65d 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -27,6 +27,8 @@ gb_internal Token ast_token(Ast *node) { return ast_token(node->AsmInstruction.name); case Ast_AsmMemoryOperand: return node->AsmMemoryOperand.open; + case Ast_AsmDirective: + return node->AsmDirective.token; case Ast_TagExpr: return node->TagExpr.token; case Ast_BadExpr: return node->BadExpr.begin; @@ -197,6 +199,11 @@ Token ast_end_token(Ast *node) { return ast_end_token(node->AsmInstruction.operands[node->AsmInstruction.operands.count-1]); } return ast_end_token(node->AsmInstruction.name); + case Ast_AsmDirective: + if (node->AsmDirective.operands.count > 0) { + return ast_end_token(node->AsmDirective.operands[node->AsmDirective.operands.count-1]); + } + return node->AsmDirective.name; case Ast_AsmMemoryOperand: if (node->AsmMemoryOperand.type) { return ast_end_token(node->AsmMemoryOperand.type);