Diagnose in an asm template instead of aborting with SIGILL

This commit is contained in:
kalsprite
2026-08-23 22:36:57 -07:00
parent 965970af71
commit b6c64c28b5
4 changed files with 32 additions and 1 deletions

View File

@@ -825,6 +825,11 @@ gb_internal bool check_register(AsmCtx *asm_ctx, Operand *operand, AstAsmRegiste
u16 width_in_bits = asm_ctx->reg_size(r);
switch (width_in_bits) {
case 0:
// a register whose class the width table cannot describe, `%rip` being the only one.
// anchored on the name rather than the operand, which clobbers and pins do not have
error(asm_reg->name, "Asm registers with no operand width are not supported: %%%.*s", LIT(name));
return false;
case 8:
operand->type = t_u8;
break;
@@ -838,7 +843,7 @@ gb_internal bool check_register(AsmCtx *asm_ctx, Operand *operand, AstAsmRegiste
operand->type = t_u64;
break;
case 80:
error(operand->expr, "80-bit width asm registers are not supported");
error(asm_reg->name, "80-bit width asm registers are not supported");
return false;
case 128:
operand->type = alloc_type_simd_vector(4, t_f32);

View File

@@ -46,6 +46,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused
..\..\..\odin check ..\test_issue_ellipsis_type_call.odin -no-entry-point %COMMON% 2>&1 | find /c "Error:" | findstr /x "10" || exit /b
..\..\..\odin check ..\test_issue_foreign_redeclaration.odin -no-entry-point %COMMON% || exit /b
..\..\..\odin check ..\test_issue_foreign_redeclaration_mismatch.odin -no-entry-point %COMMON% 2>&1 | find /c "Error:" | findstr /x "1" || exit /b
..\..\..\odin check ..\test_issue_asm_rip_register.odin -no-entry-point %COMMON% 2>&1 | find /c "Error:" | findstr /x "6" || exit /b
..\..\..\odin build ..\test_issue_7037.odin %COMMON% -o:none || exit /b
..\..\..\odin build ..\test_issue_7188.odin %COMMON% || exit /b
clang -c ..\test_issue_sysv_abi.c -o test_issue_sysv_abi_c.o || exit /b

View File

@@ -110,6 +110,16 @@ else
exit 1
fi
# `asm` templates are amd64-only, so this file is empty on every other architecture
if [[ "$(uname -m)" == "x86_64" || "$(uname -m)" == "amd64" ]]; then
if [[ $($ODIN check ../test_issue_asm_rip_register.odin -no-entry-point $COMMON_CHECK 2>&1 >/dev/null | grep -c "Error:") -eq 6 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"
exit 1
fi
fi
if [[ $($ODIN build ../test_issue_7108.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]]; then
echo "SUCCESSFUL 1/1"
else

View File

@@ -0,0 +1,15 @@
#+build amd64
// `%rip` is in the amd64 register table, but its class carries no width, so the checker's width
// switch reached its `GB_PANIC` default arm and aborted with SIGILL instead of diagnosing. Every
// position that can name a register reached it, including `[%rip + disp]`.
package test_issues
rip_src :: asm() -> (v: u64) { mov v, %rip; }
rip_dst :: asm(x: u64) { mov %rip, x; }
rip_mem :: asm() { mov %rax, [%rip + 8]; }
rip_clob :: asm() [#clobber %rip] { nop; }
rip_in :: asm(x: u64) [x = %rip] { nop; }
rip_out :: asm() -> (r: u64) [r = %rip] { nop; }
// the nearest special-purpose register that does carry a class has to keep checking cleanly
rsp_ok :: asm() -> (v: u64) { mov v, %rsp; }