Improve error messages for register class printing

This commit is contained in:
gingerBill
2026-08-17 21:10:24 +01:00
parent ad1ef6328d
commit a2bcf3177a
5 changed files with 125 additions and 5 deletions

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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:

View File

@@ -818,6 +818,9 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm
auto possible_kinds = slice_make<AsmOperandKind>(heap_allocator(), max_count);
defer (slice_free(&possible_kinds, heap_allocator()));
auto possible_class_kinds = slice_make<AsmRegClass>(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]));

View File

@@ -735,7 +735,14 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate {
gb_internal lbValue lb_emit_asm_template_call(lbProcedure *p, Entity *entity, Array<lbValue> 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);
}