diff --git a/ssa/decl.go b/ssa/decl.go index 1f098e09..c04ec0f2 100644 --- a/ssa/decl.go +++ b/ssa/decl.go @@ -105,19 +105,24 @@ type aFunction struct { Expr prog Program - params []Type + params []Type + hasVArg bool } type Function = *aFunction func newFunction(fn llvm.Value, t Type, prog Program) Function { - return &aFunction{Expr{fn, t}, prog, newParams(t, prog)} + params, hasVArg := newParams(t, prog) + return &aFunction{Expr{fn, t}, prog, params, hasVArg} } -func newParams(fn Type, prog Program) (params []Type) { +func newParams(fn Type, prog Program) (params []Type, hasVArg bool) { sig := fn.t.(*types.Signature) in := sig.Params() if n := in.Len(); n > 0 { + if hasVArg = HasVArg(in, n); hasVArg { + n-- + } params = make([]Type, n) for i := 0; i < n; i++ { params[i] = prog.llvmType(in.At(i).Type()) diff --git a/ssa/ssa_test.go b/ssa/ssa_test.go index 0e5612e9..aef73ace 100644 --- a/ssa/ssa_test.go +++ b/ssa/ssa_test.go @@ -192,6 +192,21 @@ define { i64, double } @fn(double %0) { `) } +func TestPrintf(t *testing.T) { + prog := NewProgram(nil) + pkg := prog.NewPackage("bar", "foo/bar") + pchar := types.NewPointer(types.Typ[types.Int8]) + params := types.NewTuple(types.NewVar(0, nil, "format", pchar), VArg()) + rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int32])) + sig := types.NewSignatureType(nil, nil, nil, params, rets, false) + pkg.NewFunc("printf", sig) + assertPkg(t, pkg, `; ModuleID = 'foo/bar' +source_filename = "foo/bar" + +declare i32 @printf(ptr, ...) +`) +} + func TestBinOp(t *testing.T) { prog := NewProgram(nil) pkg := prog.NewPackage("bar", "foo/bar") diff --git a/ssa/type.go b/ssa/type.go index ad089ae9..ddf955b6 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -18,6 +18,7 @@ package ssa import ( "go/types" + "log" "github.com/goplus/llvm" ) @@ -40,6 +41,24 @@ const ( // ----------------------------------------------------------------------------- +const ( + nameValist = "__llgo_va_list" +) + +func VArg() *types.Var { + return types.NewParam(0, nil, nameValist, types.Typ[types.Invalid]) +} + +func IsVArg(arg *types.Var) bool { + return arg.Name() == nameValist +} + +func HasVArg(t *types.Tuple, n int) bool { + return n > 0 && IsVArg(t.At(n-1)) +} + +// ----------------------------------------------------------------------------- + type aType struct { ll llvm.Type t types.Type @@ -181,6 +200,7 @@ func (p Program) toLLVMType(typ types.Type) Type { return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid} case *types.Chan: } + log.Println("toLLVMType: todo -", typ) panic("todo") } @@ -196,30 +216,39 @@ func (p Program) toLLVMStruct(typ *types.Struct) Type { return &aType{p.ctx.StructType(fields, false), typ, vkInvalid} } -func (p Program) toLLVMFields(typ *types.Struct) []llvm.Type { +func (p Program) toLLVMFields(typ *types.Struct) (fields []llvm.Type) { n := typ.NumFields() - fields := make([]llvm.Type, n) - for i := 0; i < n; i++ { - fields[i] = p.llvmType(typ.Field(i).Type()).ll + if n > 0 { + fields = make([]llvm.Type, n) + for i := 0; i < n; i++ { + fields[i] = p.llvmType(typ.Field(i).Type()).ll + } } - return fields + return } func (p Program) toLLVMTuple(t *types.Tuple) llvm.Type { - return p.ctx.StructType(p.toLLVMTypes(t), false) + return p.ctx.StructType(p.toLLVMTypes(t, t.Len()), false) } -func (p Program) toLLVMTypes(t *types.Tuple) []llvm.Type { - n := t.Len() - ret := make([]llvm.Type, n) - for i := 0; i < n; i++ { - ret[i] = p.llvmType(t.At(i).Type()).ll +func (p Program) toLLVMTypes(t *types.Tuple, n int) (ret []llvm.Type) { + if n > 0 { + ret = make([]llvm.Type, n) + for i := 0; i < n; i++ { + ret[i] = p.llvmType(t.At(i).Type()).ll + } } - return ret + return } func (p Program) toLLVMFunc(sig *types.Signature) Type { - params := p.toLLVMTypes(sig.Params()) + tParams := sig.Params() + n := tParams.Len() + hasVArg := HasVArg(tParams, n) + if hasVArg { + n-- + } + params := p.toLLVMTypes(tParams, n) out := sig.Results() var ret llvm.Type switch nret := out.Len(); nret { @@ -230,7 +259,7 @@ func (p Program) toLLVMFunc(sig *types.Signature) Type { default: ret = p.toLLVMTuple(out) } - ft := llvm.FunctionType(ret, params, sig.Variadic()) + ft := llvm.FunctionType(ret, params, hasVArg) return &aType{ft, sig, vkFunc} }