diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 19d35bf58..3f7bfd9c9 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -843,6 +843,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; @@ -856,7 +861,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); diff --git a/tests/issues/run.bat b/tests/issues/run.bat index 9d83a6c05..d31751a87 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -47,6 +47,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 check ..\test_issue_asm_template_as_value.odin -no-entry-point %COMMON% 2>&1 | find /c "Error:" | findstr /x "10" || exit /b ..\..\..\odin build ..\test_issue_7037.odin %COMMON% -o:none || exit /b ..\..\..\odin build ..\test_issue_7188.odin %COMMON% || exit /b diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 8794c95df..3e7d4428d 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -122,6 +122,12 @@ 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 if [[ $($ODIN check ../test_issue_asm_template_as_value.odin -no-entry-point $COMMON_CHECK 2>&1 >/dev/null | grep -c "Error:") -eq 10 ]]; then echo "SUCCESSFUL 1/1" else diff --git a/tests/issues/test_issue_asm_rip_register.odin b/tests/issues/test_issue_asm_rip_register.odin new file mode 100644 index 000000000..8b9784790 --- /dev/null +++ b/tests/issues/test_issue_asm_rip_register.odin @@ -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; }