Add extra checks for asm memory operand scale in frontend and backend

This commit is contained in:
gingerBill
2026-08-11 16:00:03 +01:00
parent a76664ed2a
commit 6a20d21358
2 changed files with 58 additions and 34 deletions

View File

@@ -740,10 +740,10 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, AstAsmInst
}
{
if (best_score == operands.count*2 - 1) {
error(instr->name, "Asm operands to '%.*s' nearly matched the expected encoding forms", LIT(name));
if (best_score >= gb_max(operands.count*2 - 2, 0)) {
error(instr->name, "'%.*s' operands nearly matched the expected encoding forms", LIT(name));
} else {
error(instr->name, "Asm operands to '%.*s' matched none of the expected encoding forms", LIT(name));
error(instr->name, "'%.*s' operands matched none of the expected encoding forms", LIT(name));
}
for_array(i, valid_spots) {
if (valid_spots[i] || i >= operands.count) {
@@ -760,33 +760,27 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, AstAsmInst
i32 bits_required = 0;
check_asm_immediate_value_fits(ev, want_bits[i], &bits_required, nullptr);
if (bits_required > 0) {
error(operands[i].expr,
"Operand %td of '%.*s' is a %d-bit immediate value, but the value %s does not fit in the %d-bit immediate this form encodes",
i, LIT(name), bits_required, vs, cast(int)want_bits[i]);
error(operands[i].expr, "'%.*s' operand-%td is a %d-bit immediate value, but the value %s does not fit in the %d-bit immediate this form encodes",
LIT(name), i, bits_required, vs, cast(int)want_bits[i]);
} else {
error(operands[i].expr,
"Operand %td of '%.*s' is an immediate value, but the value %s does not fit in the %d-bit immediate this form encodes",
i, LIT(name), vs, cast(int)want_bits[i]);
error(operands[i].expr, "'%.*s' operand-%td is an immediate value, but the value %s does not fit in the %d-bit immediate this form encodes",
LIT(name), i, vs, cast(int)want_bits[i]);
}
gb_string_free(vs);
} else if (m == AsmMismatch_ImmType) {
error(operands[i].expr,
"Operand %td of '%.*s': a floating-point constant cannot be used as an immediate",
i, LIT(name));
error(operands[i].expr, "'%.*s'' operand-%td a floating-point constant cannot be used as an immediate",
LIT(name), i);
} else if (m == AsmMismatch_Size && want_bits[i] && got_bits[i]) {
error(operands[i].expr,
"Operand %td of '%.*s' has the wrong size: expected a %u-bit operand, got %u-bit",
i, LIT(name), cast(unsigned)want_bits[i], cast(unsigned)got_bits[i]);
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,
"Operand %td of '%.*s' is in the wrong register class, expected %.*s operand, got %.*s",
i, LIT(name), 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 %.*s operand, got %.*s",
LIT(name), i, LIT(asm_operand_kind_expected_strings[dst]), LIT(asm_operand_kind_expected_strings[src]));
} else if (dst) {
error(operands[i].expr,
"Operand %td of '%.*s' has an invalid kind, expected %.*s operand",
i, LIT(name), LIT(asm_operand_kind_expected_strings[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]));
} else {
error(operands[i].expr, "Operand %td of '%.*s' has an invalid kind", i, LIT(name));
error(operands[i].expr, "'%.*s' operand-%td has an invalid kind", LIT(name), i);
}
}
}
@@ -905,11 +899,21 @@ gb_internal void check_asm_instruction_operand(AsmCtx *asm_ctx, CheckerContext *
break;
}
if (scale.mode == Addressing_Constant) {
gbString s = exact_value_to_string(scale.value);
defer (gb_string_free(s));
if (scale.value.kind != ExactValue_Integer) {
gbString s = exact_value_to_string(scale.value);
error(scale.expr, "A scale must be a constant integer or an immediate, got %s", s);
gb_string_free(s);
break;
} else {
i64 v = exact_value_to_i64(scale.value);
switch (v) {
case 1: case 2: case 4: case 8:
// okay
break;
default:
error(scale.expr, "A scale must be a constant integer or an immediate with the value 1, 2, 4, or 8, got %s", s);
break;
}
}
} else {
Entity *param_entity = entity_of_node(scale.expr);