55 lines
1.3 KiB
Go
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
|
|
}
|