https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120433
Bug ID: 120433 Summary: RISC-V:Unexpected Sign-Extension Behavior for uint32_t Return Values in RV64 Product: gcc Version: 14.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: bigmagicreadsun at gmail dot com Target Milestone: --- I encountered an inconsistency with sign-extension of uint32_t return values in RV64 when comparing values in C code versus inline assembly. Below is a minimal reproducer: -march=rv64gc -mabi=lp64d -O2 https://godbolt.org/z/qPbj1dWfz #include <stdint.h> #include <stdio.h> #define TEST_NUM 0xFFFF0231 __attribute__((noinline)) uint32_t a0_in_asm() { asm volatile ( "lui a0, 0xFFFF\n" "slli a0, a0, 0x4\n" "addi a0, a0, 0x231\n" "ecall\n" ); } int main(void) { uint32_t res = a0_in_asm(); uint32_t val = (res != TEST_NUM) ? 20 : 30; // Fails unexpectedly printf("val is %d\n", val); // Outputs 20 (unexpected) return 0; Assembly Output: a0_in_asm: lui a0, 0xFFFF slli a0, a0, 0x4 addi a0, a0, 0x231 ecall ret .LC0: .string "val is %d\n" main: addi sp,sp,-16 sd ra,8(sp) call a0_in_asm li a5,-65536 addi a5,a5,561 li a1,20 bne a0,a5,.L4 li a1,30 .L4: lui a0,%hi(.LC0) addi a0,a0,%lo(.LC0) call printf ld ra,8(sp) li a0,0 addi sp,sp,16 jr ra The function a0_in_asm loads 0xFFFF0231 into a0 (as expected): However, the comparison res != TEST_NUM evaluates to true because: res (from a0_in_asm) is not sign-extended: 0x00000000FFFF0231 (RV64 a0 post-call). TEST_NUM is sign-extended to 0xFFFFFFFFFFFF0231 due to RISC-V calling conventions (treating uint32_t as sign-extended). The comparison in main shows: li a5, -65536 # a5 = 0xFFFFFFFFFFFF0000 addi a5, a5, 561 # a5 = 0xFFFFFFFFFFFF0231 (sign-extended TEST_NUM) bne a0, a5, .L4 # Mismatch due to lack of sign-extension in `a0` Why does the toolchain not automatically sign-extend the uint32_t return value from a0_in_asm, even though the calling convention mandates it? Is this a compiler bug or intended behavior?