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 }