diff --git a/src/check_asm.cpp b/src/check_asm.cpp index ffedd2eaa..cb0c5ce5b 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -2389,6 +2389,17 @@ gb_internal void check_asm_instruction_operand(AsmCtx *asm_ctx, CheckerContext * mem_op->classify.has_disp_const = has_disp_const; mem_op->classify.ok = class_ok; + // Defensive: a well-formed memory operand always classifies to at least one + // of base / index / label / displacement. If none is set, the term list + // reached the checker empty or malformed — e.g. a bare `[reg]` whose sole + // term the parser dropped (it pushes terms only inside the +/- loop). Catch + // that here rather than silently emitting a memory operand with no address. + GB_ASSERT_MSG(!(base.expr == nullptr && index.expr == nullptr && + label_node == nullptr && !has_disp_const && disp.expr == nullptr), + "asm: memory operand produced no base/index/displacement " + "(terms.count = %td); the parser likely dropped a single-term '[operand]'", + cast(isize)mem_op->terms.count); + i32 base_w = 0; i32 index_w = 0; bool have_base = false; diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index 8a1557a71..a4131e132 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -1,4 +1,4 @@ -#define LLVM_ASM_DEBUG_PRINT false +#define LLVM_ASM_DEBUG_PRINT true struct lbAsmGenerate { Entity * tmpl_entity; @@ -891,6 +891,21 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } GB_ASSERT(instr->valid_form_index >= 0); + // NOTE(bill): The descriptor-table ops (lgdt/lidt/sgdt/sidt) take an m16:32 / m16:64 pseudo-descriptor. + // Its size can't be carried by the memory operand and it isn't a 1/2/4/8-byte scalar, + // so LLVM's AT&T assembler requires an explicit mnemonic suffix to pick the form: 'q' in 64-bit mode ('l' in 32-bit). + switch (instr->mnemonic) { + case Asm_amd64::M_LGDT: + case Asm_amd64::M_LIDT: + case Asm_amd64::M_SGDT: + case Asm_amd64::M_SIDT: + if (build_context.metrics.arch == TargetArch_i386) { + return 'l'; + } + return 'q'; + } + + auto forms = g_asm_amd64.encoding_forms(instr->mnemonic); if (forms.count <= 1) { return 0; diff --git a/src/parser.cpp b/src/parser.cpp index 18ecaddd6..d813ffa9b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2618,9 +2618,10 @@ gb_internal Ast *parse_asm_operand(AstFile *f, bool allow_memory_operand) { Token op = {}; op.kind = Token_Add; - while (f->curr_token.kind != Token_EOF && - f->curr_token.kind != Token_Semicolon && - f->curr_token.kind != Token_CloseBracket) { + while (base != nullptr || + (f->curr_token.kind != Token_EOF && + f->curr_token.kind != Token_Semicolon && + f->curr_token.kind != Token_CloseBracket)) { Ast *operand = nullptr; Ast *scale = nullptr; Token scale_op = {};