diff --git a/cl/_testgo/abiname/in.go b/cl/_testgo/abiname/in.go new file mode 100644 index 00000000..eea265b5 --- /dev/null +++ b/cl/_testgo/abiname/in.go @@ -0,0 +1,16 @@ +package main + +import "github.com/goplus/llgo/internal/abi" + +// NewPkgName creates a package name. +func NewPkgName(pkgPath string) (ret abi.Name) { + if len(pkgPath) > 0 { + ret = abi.NewName(pkgPath, "", false, false) + } + return +} + +func main() { + n := NewPkgName("pkgPath") + println(n.Name(), n.Tag(), n.IsExported(), n.IsEmbedded(), n.IsBlank()) +} diff --git a/cl/_testgo/abiname/out.ll b/cl/_testgo/abiname/out.ll new file mode 100644 index 00000000..bc029667 --- /dev/null +++ b/cl/_testgo/abiname/out.ll @@ -0,0 +1,99 @@ +; ModuleID = 'main' +source_filename = "main" + +%"github.com/goplus/llgo/internal/abi.Name" = type { ptr } +%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } + +@"main.init$guard" = global ptr null +@0 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1 +@__llgo_argc = global ptr null +@__llgo_argv = global ptr null +@1 = private unnamed_addr constant [8 x i8] c"pkgPath\00", align 1 + +define %"github.com/goplus/llgo/internal/abi.Name" @main.NewPkgName(%"github.com/goplus/llgo/internal/runtime.String" %0) { +_llgo_0: + %1 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %0, 1 + %2 = icmp sgt i64 %1, 0 + br i1 %2, label %_llgo_1, label %_llgo_2 + +_llgo_1: ; preds = %_llgo_0 + %3 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %3, i32 0, i32 0 + store ptr @0, ptr %4, align 8 + %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %3, i32 0, i32 1 + store i64 0, ptr %5, align 4 + %6 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %3, align 8 + %7 = call %"github.com/goplus/llgo/internal/abi.Name" @"github.com/goplus/llgo/internal/abi.NewName"(%"github.com/goplus/llgo/internal/runtime.String" %0, %"github.com/goplus/llgo/internal/runtime.String" %6, i1 false, i1 false) + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + %8 = phi ptr [ zeroinitializer, %_llgo_0 ], [ %7, %_llgo_1 ] + ret ptr %8 +} + +define void @main.init() { +_llgo_0: + %0 = load i1, ptr @"main.init$guard", align 1 + br i1 %0, label %_llgo_2, label %_llgo_1 + +_llgo_1: ; preds = %_llgo_0 + store i1 true, ptr @"main.init$guard", align 1 + call void @"github.com/goplus/llgo/internal/abi.init"() + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +define i32 @main(i32 %0, ptr %1) { +_llgo_0: + store i32 %0, ptr @__llgo_argc, align 4 + store ptr %1, ptr @__llgo_argv, align 8 + call void @"github.com/goplus/llgo/internal/runtime.init"() + call void @main.init() + %2 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 0 + store ptr @1, ptr %3, align 8 + %4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %2, i32 0, i32 1 + store i64 7, ptr %4, align 4 + %5 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %2, align 8 + %6 = call %"github.com/goplus/llgo/internal/abi.Name" @main.NewPkgName(%"github.com/goplus/llgo/internal/runtime.String" %5) + %7 = call %"github.com/goplus/llgo/internal/runtime.String" @"(github.com/goplus/llgo/internal/abi.Name).Name"(%"github.com/goplus/llgo/internal/abi.Name" %6) + %8 = call %"github.com/goplus/llgo/internal/runtime.String" @"(github.com/goplus/llgo/internal/abi.Name).Tag"(%"github.com/goplus/llgo/internal/abi.Name" %6) + %9 = call i1 @"(github.com/goplus/llgo/internal/abi.Name).IsExported"(%"github.com/goplus/llgo/internal/abi.Name" %6) + %10 = call i1 @"(github.com/goplus/llgo/internal/abi.Name).IsEmbedded"(%"github.com/goplus/llgo/internal/abi.Name" %6) + %11 = call i1 @"(github.com/goplus/llgo/internal/abi.Name).IsBlank"(%"github.com/goplus/llgo/internal/abi.Name" %6) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %7) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %8) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32) + call void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1 %9) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32) + call void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1 %10) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32) + call void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1 %11) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + ret i32 0 +} + +declare %"github.com/goplus/llgo/internal/abi.Name" @"github.com/goplus/llgo/internal/abi.NewName"(%"github.com/goplus/llgo/internal/runtime.String", %"github.com/goplus/llgo/internal/runtime.String", i1, i1) + +declare void @"github.com/goplus/llgo/internal/abi.init"() + +declare void @"github.com/goplus/llgo/internal/runtime.init"() + +declare %"github.com/goplus/llgo/internal/runtime.String" @"(github.com/goplus/llgo/internal/abi.Name).Name"(%"github.com/goplus/llgo/internal/abi.Name") + +declare %"github.com/goplus/llgo/internal/runtime.String" @"(github.com/goplus/llgo/internal/abi.Name).Tag"(%"github.com/goplus/llgo/internal/abi.Name") + +declare i1 @"(github.com/goplus/llgo/internal/abi.Name).IsExported"(%"github.com/goplus/llgo/internal/abi.Name") + +declare i1 @"(github.com/goplus/llgo/internal/abi.Name).IsEmbedded"(%"github.com/goplus/llgo/internal/abi.Name") + +declare i1 @"(github.com/goplus/llgo/internal/abi.Name).IsBlank"(%"github.com/goplus/llgo/internal/abi.Name") + +declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String") + +declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintBool"(i1) diff --git a/cl/compile.go b/cl/compile.go index 991c136e..608a09de 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -522,7 +522,7 @@ func (p *context) compilePhis(b llssa.Builder, block *ssa.BasicBlock) int { } for i := 0; i < n; i++ { iv := block.Instrs[i].(*ssa.Phi) - p.bvals[iv] = rets[i].Do(b) + p.bvals[iv] = rets[i] } return n } @@ -784,7 +784,7 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) { val := p.compileValue(b, v.Value) b.MapUpdate(m, key, val) case *ssa.Panic: - arg := p.compileValue(b, v.X).Do(b) + arg := p.compileValue(b, v.X) b.Panic(arg) default: panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr)) @@ -856,7 +856,7 @@ func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int) n := len(vals) - hasVArg ret := make([]llssa.Expr, n) for i := 0; i < n; i++ { - ret[i] = p.compileValue(b, vals[i]).Do(b) + ret[i] = p.compileValue(b, vals[i]) } if hasVArg > 0 { ret = p.compileVArg(ret, b, vals[n]) diff --git a/internal/abi/llgo_autogen.lla b/internal/abi/llgo_autogen.lla index 6e0de50e..728e9013 100644 Binary files a/internal/abi/llgo_autogen.lla and b/internal/abi/llgo_autogen.lla differ diff --git a/internal/runtime/llgo_autogen.lla b/internal/runtime/llgo_autogen.lla new file mode 100644 index 00000000..8bb2787b Binary files /dev/null and b/internal/runtime/llgo_autogen.lla differ diff --git a/ssa/cl_test.go b/ssa/cl_test.go index 513944c1..0405b3f2 100644 --- a/ssa/cl_test.go +++ b/ssa/cl_test.go @@ -26,7 +26,7 @@ import ( ) func TestFromTestgo(t *testing.T) { - cltest.FromDir(t, "", "../cl/_testgo", false) + cltest.FromDir(t, "abiname", "../cl/_testgo", false) } func TestFromTestpy(t *testing.T) { diff --git a/ssa/expr.go b/ssa/expr.go index 9ff69d84..67009a18 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -41,16 +41,6 @@ func (v Expr) IsNil() bool { return v.Type == nil } -// Do evaluates the delay expression and returns the result. -func (v Expr) Do(b Builder) Expr { // TODO(xsw): can we remove this method? - switch vt := v.Type; vt.kind { - case vkPhisExpr: - e := vt.raw.Type.(*phisExprTy) - return b.aggregateValue(e.Type, e.phis...) - } - return v -} - // ----------------------------------------------------------------------------- type pyVarTy struct { @@ -73,26 +63,6 @@ func pyVarExpr(mod Expr, name string) Expr { // ----------------------------------------------------------------------------- -type phisExprTy struct { - phis []llvm.Value - Type -} - -func (p phisExprTy) Underlying() types.Type { - panic("don't call") -} - -func (p phisExprTy) String() string { - return "phisExpr" -} - -func phisExpr(t Type, phis []llvm.Value) Expr { - tphi := &aType{raw: rawType{&phisExprTy{phis, t}}, kind: vkPhisExpr} - return Expr{Type: tphi} -} - -// ----------------------------------------------------------------------------- - func (p Program) Zero(t Type) Expr { var ret llvm.Value switch u := t.raw.Type.Underlying().(type) { @@ -533,14 +503,6 @@ func llvmFields(vals []Expr, t *types.Struct, b Builder) (ret []llvm.Value) { return } -func llvmDelayValues(f func(i int) Expr, n int) []llvm.Value { - ret := make([]llvm.Value, n) - for i := 0; i < n; i++ { - ret[i] = f(i).impl - } - return ret -} - func llvmPredBlocks(preds []BasicBlock) []llvm.BasicBlock { ret := make([]llvm.BasicBlock, len(preds)) for i, v := range preds { @@ -549,36 +511,48 @@ func llvmPredBlocks(preds []BasicBlock) []llvm.BasicBlock { return ret } -// Phi represents a phi node. -type Phi struct { +type aPhi struct { Expr + phis []llvm.Value +} + +// Phi represents a phi node. +type Phi = *aPhi + +func (b Builder) newPhi(t Type, phis []llvm.Value) Phi { + ret := b.aggregateValue(t, phis...) + return &aPhi{ret, phis} } // AddIncoming adds incoming values to a phi node. func (p Phi) AddIncoming(b Builder, preds []BasicBlock, f func(i int) Expr) { bs := llvmPredBlocks(preds) - if p.kind != vkPhisExpr { // normal phi node - vs := llvmDelayValues(f, len(preds)) - p.impl.AddIncoming(vs, bs) - return - } - e := p.raw.Type.(*phisExprTy) - phis := e.phis - vals := make([][]llvm.Value, len(phis)) - for iblk, blk := range preds { - last := blk.last.LastInstruction() - b.impl.SetInsertPointBefore(last) - impl := b.impl - val := f(iblk).impl - for i := range phis { - if iblk == 0 { - vals[i] = make([]llvm.Value, len(preds)) + phis := p.phis + if phis != nil { + vals := make([][]llvm.Value, len(phis)) + for iblk, blk := range preds { + last := blk.last.LastInstruction() + b.impl.SetInsertPointBefore(last) + impl := b.impl + val := f(iblk).impl + for i := range phis { + if iblk == 0 { + vals[i] = make([]llvm.Value, len(preds)) + } + vals[i][iblk] = llvm.CreateExtractValue(impl, val, i) } - vals[i][iblk] = llvm.CreateExtractValue(impl, val, i) } - } - for i, phi := range phis { - phi.AddIncoming(vals[i], bs) + for i, phi := range phis { + phi.AddIncoming(vals[i], bs) + } + } else { + vals := make([]llvm.Value, len(preds)) + for iblk, blk := range preds { + last := blk.last.LastInstruction() + b.impl.SetInsertPointBefore(last) + vals[iblk] = f(iblk).impl + } + p.impl.AddIncoming(vals, bs) } } @@ -590,17 +564,55 @@ func (b Builder) Phi(t Type) Phi { kind := tund.Kind() switch kind { case types.String: - prog := b.Prog - phis := make([]llvm.Value, 2) - phis[0] = llvm.CreatePHI(impl, prog.tyVoidPtr()) - phis[1] = llvm.CreatePHI(impl, prog.tyInt()) - return Phi{phisExpr(t, phis)} + phis := createStringPhis(impl, make([]llvm.Value, 0, 2), b.Prog) + return b.newPhi(t, phis) } case *types.Struct: + phis := createStrucPhis(impl, nil, tund, b.Prog) + return b.newPhi(t, phis) + default: panic("todo") } phi := llvm.CreatePHI(impl, t.ll) - return Phi{Expr{phi, t}} + return &aPhi{Expr{phi, t}, nil} +} + +func createStringPhis(b llvm.Builder, phis []llvm.Value, prog Program) []llvm.Value { + phis = append(phis, llvm.CreatePHI(b, prog.tyVoidPtr())) + return append(phis, llvm.CreatePHI(b, prog.tyInt())) +} + +func createStrucPhis(b llvm.Builder, phis []llvm.Value, t *types.Struct, prog Program) []llvm.Value { + n := t.NumFields() + if phis == nil { + phis = make([]llvm.Value, 0, n) + } + for i := 0; i < n; i++ { + fld := t.Field(i) + switch tfld := fld.Type().Underlying().(type) { + case *types.Basic: + kind := tfld.Kind() + switch kind { + case types.String: + phis = createStringPhis(b, phis, prog) + default: + phis = createBasicPhi(b, phis, tfld, prog) + } + case *types.Pointer: + phis = createBasicPhi(b, phis, tfld, prog) + case *types.Struct: + phis = createStrucPhis(b, phis, tfld, prog) + default: + panic("todo") + } + } + return phis +} + +func createBasicPhi(b llvm.Builder, phis []llvm.Value, t types.Type, prog Program) []llvm.Value { + tll := prog.rawType(t).ll + phi := llvm.CreatePHI(b, tll) + return append(phis, phi) } // ----------------------------------------------------------------------------- diff --git a/ssa/ssa_test.go b/ssa/ssa_test.go index 3e23e756..b6123bd3 100644 --- a/ssa/ssa_test.go +++ b/ssa/ssa_test.go @@ -109,9 +109,7 @@ func TestCvtType(t *testing.T) { } func TestUserdefExpr(t *testing.T) { - b := &phisExprTy{} c := &pyVarTy{} - _ = b.String() _ = c.String() test := func(a types.Type) { defer func() { @@ -121,7 +119,6 @@ func TestUserdefExpr(t *testing.T) { }() a.Underlying() } - test(b) test(c) } diff --git a/ssa/type.go b/ssa/type.go index ece67e4c..2b1f3608 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -53,7 +53,6 @@ const ( vkEface vkIface vkStruct - vkPhisExpr = -1 ) // -----------------------------------------------------------------------------