diff --git a/src/core/Evaluate.go b/src/core/Evaluate.go index f7eef07..216e480 100644 --- a/src/core/Evaluate.go +++ b/src/core/Evaluate.go @@ -145,12 +145,11 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) { } } - call := &ssa.Call{ - Arguments: args, - Source: ssa.Source(expr.Source), + if fn.IsExtern() { + return f.Append(&ssa.CallExtern{Arguments: args, Source: ssa.Source(expr.Source)}), nil } - return f.Append(call), nil + return f.Append(&ssa.Call{Arguments: args, Source: ssa.Source(expr.Source)}), nil } case token.Dot: diff --git a/src/ssa/CallExtern.go b/src/ssa/CallExtern.go new file mode 100644 index 0000000..a6b4b68 --- /dev/null +++ b/src/ssa/CallExtern.go @@ -0,0 +1,73 @@ +package ssa + +import ( + "strconv" + "strings" + + "git.urbach.dev/cli/q/src/types" +) + +type CallExtern struct { + Id + Arguments + Liveness + Source +} + +func (a *CallExtern) Equals(v Value) bool { + b, sameType := v.(*CallExtern) + + if !sameType { + return false + } + + return a.Arguments.Equals(b.Arguments) +} + +func (v *CallExtern) IsConst() bool { + return false +} + +func (v *CallExtern) Debug(expand bool) string { + tmp := strings.Builder{} + + if expand { + tmp.WriteString(v.Arguments[0].String()) + } else { + tmp.WriteString("%") + tmp.WriteString(strconv.Itoa(v.Arguments[0].ID())) + } + + tmp.WriteString("(") + args := v.Arguments[1:] + + for i, arg := range args { + if expand { + tmp.WriteString(arg.String()) + } else { + tmp.WriteString("%") + tmp.WriteString(strconv.Itoa(arg.ID())) + } + + if i != len(args)-1 { + tmp.WriteString(", ") + } + } + + tmp.WriteString(")") + return tmp.String() +} + +func (v *CallExtern) String() string { + return v.Debug(true) +} + +func (v *CallExtern) Type() types.Type { + typ := v.Arguments[0].(*Function).Typ + + if len(typ.Output) == 0 { + return types.Void + } + + return typ.Output[0] +} \ No newline at end of file diff --git a/src/ssa2asm/GenerateAssembly.go b/src/ssa2asm/GenerateAssembly.go index e36f902..1781ccf 100644 --- a/src/ssa2asm/GenerateAssembly.go +++ b/src/ssa2asm/GenerateAssembly.go @@ -21,7 +21,7 @@ func (f *Compiler) GenerateAssembly(ir ssa.IR, isLeaf bool) { } switch instr := instr.(type) { - case *ssa.Call, *ssa.Syscall: + case *ssa.Call, *ssa.CallExtern, *ssa.Syscall: f.ValueToRegister(instr, f.CPU.Return[0]) case *ssa.Return: diff --git a/src/ssa2asm/ValueToRegister.go b/src/ssa2asm/ValueToRegister.go index 10b1bfb..81e2d05 100644 --- a/src/ssa2asm/ValueToRegister.go +++ b/src/ssa2asm/ValueToRegister.go @@ -25,35 +25,45 @@ func (f *Compiler) ValueToRegister(instr ssa.Value, destination cpu.Register) { case *ssa.Call: fn := instr.Arguments[0].(*ssa.Function) args := instr.Arguments[1:] + offset := 0 - if fn.IsExtern { - for i := range slices.Backward(args) { - f.ValueToRegister(args[i], f.CPU.ExternCall[i]) - } + for i := range slices.Backward(args) { + structure, isStruct := args[i].(*ssa.Struct) - dot := strings.IndexByte(fn.UniqueName, '.') - library := fn.UniqueName[:dot] - function := fn.UniqueName[dot+1:] - f.Assembler.Append(&asm.CallExtern{Library: library, Function: function}) - } else { - offset := 0 - - for i := range slices.Backward(args) { - structure, isStruct := args[i].(*ssa.Struct) - - if isStruct { - for _, field := range structure.Arguments { - f.ValueToRegister(field, f.CPU.Call[offset+i]) - i++ - } - } else { - f.ValueToRegister(args[i], f.CPU.Call[offset+i]) + if isStruct { + for _, field := range structure.Arguments { + f.ValueToRegister(field, f.CPU.Call[offset+i]) + i++ } + } else { + f.ValueToRegister(args[i], f.CPU.Call[offset+i]) } - - f.Assembler.Append(&asm.Call{Label: fn.UniqueName}) } + f.Assembler.Append(&asm.Call{Label: fn.UniqueName}) + + if destination == f.CPU.Return[0] { + return + } + + f.Assembler.Append(&asm.MoveRegisterRegister{ + Destination: destination, + Source: f.CPU.Return[0], + }) + + case *ssa.CallExtern: + fn := instr.Arguments[0].(*ssa.Function) + args := instr.Arguments[1:] + + for i := range slices.Backward(args) { + f.ValueToRegister(args[i], f.CPU.ExternCall[i]) + } + + dot := strings.IndexByte(fn.UniqueName, '.') + library := fn.UniqueName[:dot] + function := fn.UniqueName[dot+1:] + f.Assembler.Append(&asm.CallExtern{Library: library, Function: function}) + if destination == f.CPU.Return[0] { return }