q/src/core/CallExtern.go
2025-02-25 17:16:09 +01:00

55 lines
1.3 KiB
Go

package core
import (
"fmt"
"slices"
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/cpu"
"git.urbach.dev/cli/q/src/expression"
"git.urbach.dev/cli/q/src/types"
"git.urbach.dev/cli/q/src/x86"
)
// CallExtern calls an external function.
func (f *Function) CallExtern(fn *Function, parameters []*expression.Expression) ([]types.Type, error) {
f.DLLs = f.DLLs.Append(fn.Package, fn.Name)
var pushedRegisters []cpu.Register
for _, register := range x86.WindowsVolatileRegisters {
if f.RegisterIsUsed(register) {
f.Register(asm.PUSH, register)
f.FreeRegister(register)
pushedRegisters = append(pushedRegisters, register)
}
}
registers := x86.WindowsInputRegisters[:len(parameters)]
err := f.ExpressionsToRegisters(parameters, registers, fn.Input, true)
if err != nil {
return nil, err
}
f.Register(asm.PUSH, x86.RBP)
f.RegisterRegister(asm.MOVE, x86.RBP, x86.RSP)
f.RegisterNumber(asm.AND, x86.RSP, -16)
f.Number(asm.PUSH, 0)
f.Number(asm.PUSH, 0)
f.RegisterNumber(asm.SUB, x86.RSP, 32)
f.DLLCall(fmt.Sprintf("%s.%s", fn.Package, fn.Name))
f.RegisterRegister(asm.MOVE, x86.RSP, x86.RBP)
f.Register(asm.POP, x86.RBP)
for _, register := range registers {
f.FreeRegister(register)
}
for _, register := range slices.Backward(pushedRegisters) {
f.Register(asm.POP, register)
}
return fn.OutputTypes, nil
}