diff --git a/cl/compile.go b/cl/compile.go index 7bbca572..b0a954be 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -142,6 +142,7 @@ type context struct { bvals map[ssa.Value]llssa.Expr // block values vargs map[*ssa.Alloc][]llssa.Expr // varargs inits []func() + phis []func() } func (p *context) compileType(pkg llssa.Package, t *ssa.Type) { @@ -203,6 +204,7 @@ func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa defer func() { p.fn = nil }() + p.phis = nil nblk := len(f.Blocks) if nblk == 0 { // external function return @@ -219,6 +221,9 @@ func (p *context) compileFunc(pkg llssa.Package, pkgTypes *types.Package, f *ssa for i, block := range f.Blocks { p.compileBlock(b, block, i == 0 && name == "main") } + for _, phi := range p.phis { + phi() + } }) } @@ -349,6 +354,18 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue case *ssa.UnOp: x := p.compileValue(b, v.X) ret = b.UnOp(v.Op, x) + case *ssa.Phi: + phi := b.Phi(p.prog.Type(v.Type())) + ret = phi.Expr + p.phis = append(p.phis, func() { + vals := p.compileValues(b, v.Edges, 0) + preds := v.Block().Preds + bblks := make([]llssa.BasicBlock, len(preds)) + for i, pred := range preds { + bblks[i] = p.fn.Block(pred.Index) + } + phi.AddIncoming(vals, bblks) + }) case *ssa.ChangeType: t := v.Type() x := p.compileValue(b, v.X) diff --git a/ssa/expr.go b/ssa/expr.go index c6010e1e..9ad4ee15 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -72,16 +72,6 @@ func (p delayExprTy) String() string { // ----------------------------------------------------------------------------- -func llvmValues(vals []Expr) []llvm.Value { - ret := make([]llvm.Value, len(vals)) - for i, v := range vals { - ret[i] = v.impl - } - return ret -} - -// ----------------------------------------------------------------------------- - // Null returns a null constant expression. func (p Program) Null(t Type) Expr { return Expr{llvm.ConstNull(t.ll), t} @@ -326,6 +316,43 @@ func (b Builder) UnOp(op token.Token, x Expr) Expr { panic("todo") } +// ----------------------------------------------------------------------------- + +func llvmValues(vals []Expr) []llvm.Value { + ret := make([]llvm.Value, len(vals)) + for i, v := range vals { + ret[i] = v.impl + } + return ret +} + +func llvmBlocks(bblks []BasicBlock) []llvm.BasicBlock { + ret := make([]llvm.BasicBlock, len(bblks)) + for i, v := range bblks { + ret[i] = v.impl + } + return ret +} + +// Phi represents a phi node. +type Phi struct { + Expr +} + +// AddIncoming adds incoming values to a phi node. +func (p Phi) AddIncoming(vals []Expr, bblks []BasicBlock) { + v := llvmValues(vals) + b := llvmBlocks(bblks) + p.impl.AddIncoming(v, b) +} + +// Phi returns a phi node. +func (b Builder) Phi(t Type) Phi { + return Phi{Expr{llvm.CreatePHI(b.impl, t.ll), t}} +} + +// ----------------------------------------------------------------------------- + // Load returns the value at the pointer ptr. func (b Builder) Load(ptr Expr) Expr { if debugInstr { @@ -434,6 +461,8 @@ func (b Builder) Slice(x, low, high, max Expr) (ret Expr) { panic("todo") } +// ----------------------------------------------------------------------------- + // The Alloc instruction reserves space for a variable of the given type, // zero-initializes it, and yields its address. // @@ -495,6 +524,8 @@ func (b Builder) ArrayAlloca(telem Type, n Expr) (ret Expr) { } */ +// ----------------------------------------------------------------------------- + // The ChangeType instruction applies to X a value-preserving type // change to Type(). //