From 8d13f1ece861b24db1b43ee633b2232524109043 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Sat, 5 Jul 2025 22:27:01 +0200 Subject: [PATCH] Improved Windows x86-64 ABI support --- lib/io/write_windows.q | 4 ++-- src/asm/Instruction.go | 7 +++++++ src/asm/compilerARM.go | 8 ++++++++ src/asm/compilerX86.go | 12 ++++++++---- src/ssa2asm/CreateSteps.go | 6 ++++++ src/ssa2asm/Exec.go | 8 +++++++- 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/lib/io/write_windows.q b/lib/io/write_windows.q index c9a4f3d..ac21bb9 100644 --- a/lib/io/write_windows.q +++ b/lib/io/write_windows.q @@ -1,12 +1,12 @@ write(buffer string) -> (written int) { stdout := kernel32.GetStdHandle(-11) - kernel32.WriteConsoleA(stdout, buffer.ptr, buffer.len, 0) + kernel32.WriteFile(stdout, buffer.ptr, buffer.len, 0, 0) return buffer.len } extern { kernel32 { GetStdHandle(device int64) -> (handle int64) - WriteConsoleA(fd int64, buffer *byte, length uint32, written *uint32) -> (success bool) + WriteFile(fd int64, buffer *byte, length uint32, written *uint32, overlapped *any) -> (success bool) } } \ No newline at end of file diff --git a/src/asm/Instruction.go b/src/asm/Instruction.go index d8f9889..5e937fe 100644 --- a/src/asm/Instruction.go +++ b/src/asm/Instruction.go @@ -25,6 +25,9 @@ type CallExtern struct { Function string } +type CallExternStart struct{} +type CallExternEnd struct{} + type FunctionStart struct{} type FunctionEnd struct{} @@ -51,6 +54,10 @@ type MoveRegisterRegister struct { Source cpu.Register } +type PushRegister struct { + Register cpu.Register +} + type Return struct{} type SubRegisterNumber struct { diff --git a/src/asm/compilerARM.go b/src/asm/compilerARM.go index c6604c8..297c06c 100644 --- a/src/asm/compilerARM.go +++ b/src/asm/compilerARM.go @@ -32,6 +32,12 @@ func (c *compilerARM) Compile(instr Instruction) { offset := (address - start) / 4 binary.LittleEndian.PutUint32(c.code[start:start+4], arm.Call(offset)) }) + case *CallExtern: + panic("not implemented") + case *CallExternStart: + panic("not implemented") + case *CallExternEnd: + panic("not implemented") case *Jump: start := len(c.code) c.append(arm.Jump(0)) @@ -76,6 +82,8 @@ func (c *compilerARM) Compile(instr Instruction) { c.code = arm.MoveRegisterNumber(c.code, instr.Destination, instr.Number) case *MoveRegisterRegister: c.append(arm.MoveRegisterRegister(instr.Destination, instr.Source)) + case *PushRegister: + panic("not implemented") case *Return: c.append(arm.Return()) case *Syscall: diff --git a/src/asm/compilerX86.go b/src/asm/compilerX86.go index 61977f4..20d1a13 100644 --- a/src/asm/compilerX86.go +++ b/src/asm/compilerX86.go @@ -41,12 +41,8 @@ func (c *compilerX86) Compile(instr Instruction) { binary.LittleEndian.PutUint32(c.code[end-4:end], uint32(offset)) }) case *CallExtern: - c.code = x86.MoveRegisterRegister(c.code, x86.R5, x86.SP) - c.code = x86.AndRegisterNumber(c.code, x86.SP, -16) - c.code = x86.SubRegisterNumber(c.code, x86.SP, 32) c.code = x86.CallAt(c.code, 0) end := len(c.code) - c.code = x86.MoveRegisterRegister(c.code, x86.SP, x86.R5) c.Defer(func() { index := c.libraries.Index(instr.Library, instr.Function) @@ -59,6 +55,12 @@ func (c *compilerX86) Compile(instr Instruction) { offset := address - end binary.LittleEndian.PutUint32(c.code[end-4:end], uint32(offset)) }) + case *CallExternStart: + c.code = x86.MoveRegisterRegister(c.code, x86.R5, x86.SP) + c.code = x86.AndRegisterNumber(c.code, x86.SP, -16) + c.code = x86.SubRegisterNumber(c.code, x86.SP, 32) + case *CallExternEnd: + c.code = x86.MoveRegisterRegister(c.code, x86.SP, x86.R5) case *FunctionStart: case *FunctionEnd: case *Jump: @@ -100,6 +102,8 @@ func (c *compilerX86) Compile(instr Instruction) { c.code = x86.MoveRegisterNumber(c.code, instr.Destination, instr.Number) case *MoveRegisterRegister: c.code = x86.MoveRegisterRegister(c.code, instr.Destination, instr.Source) + case *PushRegister: + c.code = x86.PushRegister(c.code, instr.Register) case *Return: c.code = x86.Return(c.code) case *SubRegisterNumber: diff --git a/src/ssa2asm/CreateSteps.go b/src/ssa2asm/CreateSteps.go index 13fcd2b..4ee4279 100644 --- a/src/ssa2asm/CreateSteps.go +++ b/src/ssa2asm/CreateSteps.go @@ -41,6 +41,12 @@ func (f *Compiler) CreateSteps(ir ssa.IR) []Step { case *ssa.CallExtern: for r, param := range instr.Arguments[1:] { + if r >= len(f.CPU.ExternCall.In) { + // Temporary hack to allow arguments 5 and 6 to be hinted as r10 and r11, then pushed later. + f.ValueToStep[param].Hint(f.CPU.ExternCall.Volatile[1+r]) + continue + } + f.ValueToStep[param].Hint(f.CPU.ExternCall.In[r]) } diff --git a/src/ssa2asm/Exec.go b/src/ssa2asm/Exec.go index e65aeac..cf9ad43 100644 --- a/src/ssa2asm/Exec.go +++ b/src/ssa2asm/Exec.go @@ -69,10 +69,15 @@ func (f *Compiler) Exec(step *Step) { }) case *ssa.CallExtern: + f.Assembler.Append(&asm.CallExternStart{}) args := instr.Arguments[1:] for i, arg := range args { - if f.ValueToStep[arg].Register != f.CPU.ExternCall.In[i] { + if i >= len(f.CPU.ExternCall.In) { + f.Assembler.Append(&asm.PushRegister{ + Register: f.ValueToStep[arg].Register, + }) + } else if f.ValueToStep[arg].Register != f.CPU.ExternCall.In[i] { f.Assembler.Append(&asm.MoveRegisterRegister{ Destination: f.CPU.ExternCall.In[i], Source: f.ValueToStep[arg].Register, @@ -85,6 +90,7 @@ func (f *Compiler) Exec(step *Step) { library := fn.UniqueName[:dot] function := fn.UniqueName[dot+1:] f.Assembler.Append(&asm.CallExtern{Library: library, Function: function}) + f.Assembler.Append(&asm.CallExternEnd{}) if step.Register == -1 || step.Register == f.CPU.ExternCall.Out[0] { return