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 a6f05f973..489f5cae7 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -493,6 +493,51 @@ main :: proc() { """) strings.write_string(&sb, "\n\n") + strings.write_string(&sb, """ + AsmRegClass reg_class_from_operand_type(OperandType type) { + switch (type) { + case OP_R8: case OP_R16: case OP_R32: case OP_R64: + case OP_RM8: case OP_RM16: case OP_RM32: case OP_RM64: + case OP_AL_IMPL: case OP_AX_IMPL: case OP_EAX_IMPL: case OP_RAX_IMPL: + case OP_CL_IMPL: case OP_DX_IMPL: + return AsmRegClass_Integer; + + case OP_XMM: case OP_YMM: case OP_ZMM: + case OP_XMM_M32: case OP_XMM_M64: case OP_XMM_M128: + case OP_YMM_M256: case OP_ZMM_M512: + case OP_XMM0_IMPL: + return AsmRegClass_Vector; + + case OP_K: + case OP_K_M8: case OP_K_M16: case OP_K_M32: case OP_K_M64: + return AsmRegClass_Mask; + + case OP_STI: + case OP_ST0_IMPL: + return AsmRegClass_Float; + + case OP_MM: + case OP_MM_M64: + return AsmRegClass_Vector; + + case OP_SREG: case OP_CR: case OP_DR: + case OP_M: case OP_M8: case OP_M16: case OP_M32: case OP_M64: + case OP_M80: case OP_M128: case OP_M256: case OP_M512: + case OP_MOFFS8: case OP_MOFFS16: case OP_MOFFS32: case OP_MOFFS64: + case OP_M16_16: case OP_M16_32: case OP_M16_64: + case OP_IMM8: case OP_IMM16: case OP_IMM32: case OP_IMM64: + case OP_IMM8SX: + case OP_ONE_IMPL: + case OP_PTR16_16: case OP_PTR16_32: case OP_PTR16_64: + case OP_REL8: case OP_REL32: + case OP_NONE: + default: + return AsmRegClass_Unknown; + } + } + """) + strings.write_string(&sb, "\n\n") + strings.write_string(&sb, """ bool operand_type_is_implicit(OperandType t) { switch (t) { diff --git a/src/asm_tables.cpp b/src/asm_tables.cpp index e599ff1b5..eb7e3c109 100644 --- a/src/asm_tables.cpp +++ b/src/asm_tables.cpp @@ -4,8 +4,25 @@ enum AsmRegClass : u8 { AsmRegClass_Float, AsmRegClass_Vector, AsmRegClass_Mask, + + AsmRegClass_COUNT }; +gb_global String const asm_reg_class_strings[AsmRegClass_COUNT] = { + str_lit("unknown"), + str_lit("integer"), + str_lit("float"), + str_lit("vector"), + str_lit("mask"), +}; + +gb_global String const asm_reg_class_strings_with_article[AsmRegClass_COUNT] = { + str_lit("an unknown"), + str_lit("an integer"), + str_lit("a float"), + str_lit("a vector"), + str_lit("a mask"), +}; enum AsmOperandKind : u8 { AsmOperand_Invalid, diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index d6b5b2d58..1c229c97d 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -510,6 +510,48 @@ struct Asm_amd64 { } } + AsmRegClass reg_class_from_operand_type(OperandType type) { + switch (type) { + case OP_R8: case OP_R16: case OP_R32: case OP_R64: + case OP_RM8: case OP_RM16: case OP_RM32: case OP_RM64: + case OP_AL_IMPL: case OP_AX_IMPL: case OP_EAX_IMPL: case OP_RAX_IMPL: + case OP_CL_IMPL: case OP_DX_IMPL: + return AsmRegClass_Integer; + + case OP_XMM: case OP_YMM: case OP_ZMM: + case OP_XMM_M32: case OP_XMM_M64: case OP_XMM_M128: + case OP_YMM_M256: case OP_ZMM_M512: + case OP_XMM0_IMPL: + return AsmRegClass_Vector; + + case OP_K: + case OP_K_M8: case OP_K_M16: case OP_K_M32: case OP_K_M64: + return AsmRegClass_Mask; + + case OP_STI: + case OP_ST0_IMPL: + return AsmRegClass_Float; + + case OP_MM: + case OP_MM_M64: + return AsmRegClass_Vector; + + case OP_SREG: case OP_CR: case OP_DR: + case OP_M: case OP_M8: case OP_M16: case OP_M32: case OP_M64: + case OP_M80: case OP_M128: case OP_M256: case OP_M512: + case OP_MOFFS8: case OP_MOFFS16: case OP_MOFFS32: case OP_MOFFS64: + case OP_M16_16: case OP_M16_32: case OP_M16_64: + case OP_IMM8: case OP_IMM16: case OP_IMM32: case OP_IMM64: + case OP_IMM8SX: + case OP_ONE_IMPL: + case OP_PTR16_16: case OP_PTR16_32: case OP_PTR16_64: + case OP_REL8: case OP_REL32: + case OP_NONE: + default: + return AsmRegClass_Unknown; + } + } + bool operand_type_is_implicit(OperandType t) { switch (t) { case OP_AL_IMPL: case OP_AX_IMPL: diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 86769af6a..50515a490 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -818,6 +818,9 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm auto possible_kinds = slice_make(heap_allocator(), max_count); defer (slice_free(&possible_kinds, heap_allocator())); + auto possible_class_kinds = slice_make(heap_allocator(), max_count); + defer (slice_free(&possible_class_kinds, heap_allocator())); + bool matched = false; isize valid_form_index = -1; @@ -950,6 +953,7 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm AsmOperandKind dst = asm_ctx->kind_from_operand_type(type); AsmOperandKind src = determine_asm_operand_kind(&operands[i]); possible_kinds[i] = dst; + possible_class_kinds[i] = asm_ctx->reg_class_from_operand_type(type); bool kind_ok = (dst == src) || (dst == AsmOperand_Register_Or_Memory && (src == AsmOperand_Register || src == AsmOperand_Memory)); @@ -983,6 +987,9 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm auto dst = possible_kinds[i]; AsmOperandKind src = determine_asm_operand_kind(&operands[i]); + AsmRegClass dst_reg_class = possible_class_kinds[i]; + AsmRegClass src_reg_class = check_asm_reg_class_from_type(operands[i].type); + AsmMismatch m = (i < MAX_VARIANT_COUNT) ? mismatch[i] : AsmMismatch_None; if (m == AsmMismatch_ImmRange) { @@ -1005,8 +1012,10 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm error(operands[i].expr, "'%.*s' operand-%td has the wrong size: expected a %u-bit operand, got %u-bit", LIT(name), i, cast(unsigned)want_bits[i], cast(unsigned)got_bits[i]); } else if (m == AsmMismatch_Class) { - error(operands[i].expr, "'%.*s' operand-%td is in the wrong register class, expected %.*s operand, got %.*s", - LIT(name), i, LIT(asm_operand_kind_expected_strings[dst]), LIT(asm_operand_kind_expected_strings[src])); + error(operands[i].expr, "'%.*s' operand-%td is in the wrong register class, expected %d-bit %.*s %.*s, got %d-bit %.*s %.*s", + LIT(name), i, + want_bits[i], LIT(asm_reg_class_strings[dst_reg_class]), LIT(asm_operand_kind_strings[dst]), + got_bits[i], LIT(asm_reg_class_strings[src_reg_class]), LIT(asm_operand_kind_strings[src])); } else if (dst) { error(operands[i].expr, "'%.*s' operand-%td has an invalid kind, expected %.*s operand", LIT(name), i, LIT(asm_operand_kind_expected_strings[dst])); diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index 7dbf84e15..215d0e7d5 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -735,7 +735,14 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { gb_internal lbValue lb_emit_asm_template_call(lbProcedure *p, Entity *entity, Array const &args) { - lbAsmGenerate_amd64 generator = {}; - generator.init(entity); - return generator.emit_call(p, args); + lbAsmGenerate *generator = nullptr; + if (build_context.metrics.arch == TargetArch_amd64) { + lbAsmGenerate_amd64 generator_amd64 = {}; + generator = &generator_amd64; + } else { + compiler_error("Architecture does not support asm templates"); + return {}; + } + generator->init(entity); + return generator->emit_call(p, args); } \ No newline at end of file