Skip to content

Conversation

@itsfuad
Copy link

@itsfuad itsfuad commented Dec 25, 2025

  • Introduced a new target structure for Windows x64 calling convention in amd64/targ.c.
  • Updated main.c to include the new Windows x64 target in the target mapping.
  • Implemented the Windows x64 ABI logic in amd64/win64.c, including argument classification, return value handling, and stack management.
  • Created a dedicated emitter for Windows x64 in amd64/win64_emit.c, mirroring existing functionality while adhering to the Windows calling conventions.
  • Added necessary utility functions for argument handling and register management specific to the Windows ABI.

Closes #4

- Introduced a new target structure for Windows x64 calling convention in `amd64/targ.c`.
- Updated `main.c` to include the new Windows x64 target in the target mapping.
- Implemented the Windows x64 ABI logic in `amd64/win64.c`, including argument classification, return value handling, and stack management.
- Created a dedicated emitter for Windows x64 in `amd64/win64_emit.c`, mirroring existing functionality while adhering to the Windows calling conventions.
- Added necessary utility functions for argument handling and register management specific to the Windows ABI.
@itsfuad
Copy link
Author

itsfuad commented Dec 27, 2025

The block-entry remap step in rega.c can assign a live temp to a register already used by another live temp in the same block.

  • On amd64, this can break div/rem loops where two phi values are live at the loop header, causing the dividend and divisor to share a register (wrong results or infinite loops).

Repro (QBE IL):

export function w $gcd(w %a, w %b) {
@b1
	%x =w copy %a
	%y =w copy %b
	jmp @b2
@b2
	%y2 =w phi @b1 %y, @b3 %y3
	%x2 =w phi @b1 %x, @b3 %x3
	%c =w cnew %y2, 0
	jnz %c, @b3, @b4
@b3
	%tmp =w copy %y2
	%rem =w rem %x2, %y2
	%y3 =w copy %rem
	%x3 =w copy %tmp
	jmp @b2
@b4
	ret %x2
}

Before patch, qbe -dR shows %x2 and %y2 mapped to the same register at @b2, which makes idiv use the same reg for dividend/divisor. After patch, they stay in distinct registers.

Fix:

  • In rega.c step “emit copies shared by multiple edges,” skip remapping a temp to a register that is already assigned to another live temp in the block.
  • Only update m->r and the bitset when the target register is free.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows Support

1 participant