diff --git a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin index bd60c3f18..db7064914 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -320,7 +320,7 @@ main :: proc() { strings.write_string(&sb, "\n\n\n") - fmt.sbprintf(&sb, "gb_internal Asm_{0:s} g_asm_{0:s};\n", ISA_NAME) + fmt.sbprintf(&sb, "gb_global Asm_{0:s} g_asm_{0:s};\n", ISA_NAME) strings.write_string(&sb, "\n\n\n") diff --git a/src/asm_tables.cpp b/src/asm_tables.cpp index 335efe4d9..df68ce1b8 100644 --- a/src/asm_tables.cpp +++ b/src/asm_tables.cpp @@ -5,6 +5,26 @@ enum AsmOperandKind : u8 { AsmOperand_Register_Or_Memory, AsmOperand_Immediate, AsmOperand_Label, + + AsmOperand_COUNT +}; + +gb_global String const asm_operand_kind_strings[AsmOperand_COUNT] = { + str_lit(""), + str_lit("register"), + str_lit("memory"), + str_lit("register or memory"), + str_lit("immediate"), + str_lit("label"), +}; + +gb_global String const asm_operand_kind_expected_strings[AsmOperand_COUNT] = { + str_lit(""), + str_lit("a register"), + str_lit("a memory"), + str_lit("a register or memory"), + str_lit("an immediate"), + str_lit("a label"), }; #include "asm_tables_amd64.cpp" \ No newline at end of file diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index 5d236e91f..e7853bd31 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -341,7 +341,7 @@ struct Asm_amd64 { -gb_internal Asm_amd64 g_asm_amd64; +gb_global Asm_amd64 g_asm_amd64; diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 6e0891793..bbdeb34c3 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -379,6 +379,9 @@ gb_internal void check_mnemonic(CheckerContext *ctx, AstAsmInstruction *instr, u auto valid_spots = slice_make(heap_allocator(), max_count); defer (slice_free(&valid_spots, heap_allocator())); + auto possible_kinds = slice_make(heap_allocator(), max_count); + defer (slice_free(&possible_kinds, heap_allocator())); + bool ok = true; for (auto form : forms) { int explicit_count = cast(int)form.explicit_count(); @@ -394,6 +397,11 @@ gb_internal void check_mnemonic(CheckerContext *ctx, AstAsmInstruction *instr, u Operand const *operand = &operands[i]; AsmOperandKind dst_kind = g_asm_amd64.kind_from_operand_type(type); AsmOperandKind src_kind = determine_asm_operand_kind(operand); + + // TODO(bill): Is this even correct logic for determine the best error message for the possible operand kinds? + // for partially correct forms of the instruction? + possible_kinds[i] = dst_kind; + if (dst_kind == src_kind) { valid_spots[i] = true; continue; @@ -404,7 +412,6 @@ gb_internal void check_mnemonic(CheckerContext *ctx, AstAsmInstruction *instr, u continue; } ok = false; - break; } if (ok) { // the result has been found to be correct @@ -432,7 +439,12 @@ gb_internal void check_mnemonic(CheckerContext *ctx, AstAsmInstruction *instr, u error(instr->name, "The operands to '%.*s' matched non of the expected encoding forms", LIT(name)); for_array(i, valid_spots) { if (!valid_spots[i] && i < operands.count) { - error(operands[i].expr, "Invalid operand kind for the asm instruction '%.*s'", LIT(name)); + auto kind = possible_kinds[i]; + if (kind) { + error(operands[i].expr, "Invalid operand kind for the asm instruction '%.*s', expected %.*s operand", LIT(name), LIT(asm_operand_kind_expected_strings[kind])); + } else { + error(operands[i].expr, "Invalid operand kind for the asm instruction '%.*s'", LIT(name)); + } } } }