cl: compilePhis; llgo/ssa: phi.AddIncoming

This commit is contained in:
xushiwei
2024-05-02 11:27:02 +08:00
parent fbb1f89ab3
commit 40855c2d2a
5 changed files with 91 additions and 36 deletions

View File

@@ -13,5 +13,5 @@ func concat(args ...string) (ret string) {
func main() { func main() {
result := concat("Hello", " ", "World") result := concat("Hello", " ", "World")
c.Fprintf(c.Stderr, c.Str("Hello %s\n"), c.AllocaCStr(result)) c.Fprintf(c.Stderr, c.Str("Hi, %s\n"), c.AllocaCStr(result))
} }

View File

@@ -10,30 +10,38 @@ source_filename = "main"
@2 = private unnamed_addr constant [2 x i8] c" \00", align 1 @2 = private unnamed_addr constant [2 x i8] c" \00", align 1
@3 = private unnamed_addr constant [6 x i8] c"World\00", align 1 @3 = private unnamed_addr constant [6 x i8] c"World\00", align 1
@__stderrp = external global ptr @__stderrp = external global ptr
@4 = private unnamed_addr constant [10 x i8] c"Hello %s\0A\00", align 1 @4 = private unnamed_addr constant [8 x i8] c"Hi, %s\0A\00", align 1
define %"github.com/goplus/llgo/internal/runtime.String" @main.concat(%"github.com/goplus/llgo/internal/runtime.Slice" %0) { define %"github.com/goplus/llgo/internal/runtime.String" @main.concat(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
_llgo_0: _llgo_0:
%1 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %1 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0)
%2 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 0)
%3 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %2, 0
%4 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %2, 1
br label %_llgo_1 br label %_llgo_1
_llgo_1: ; preds = %_llgo_2, %_llgo_0 _llgo_1: ; preds = %_llgo_2, %_llgo_0
%2 = phi %"github.com/goplus/llgo/internal/runtime.String" [ %10, %_llgo_0 ], [ %9, %_llgo_2 ] %5 = phi ptr [ %3, %_llgo_0 ], [ %14, %_llgo_2 ]
%3 = phi i64 [ -1, %_llgo_0 ], [ %4, %_llgo_2 ] %6 = phi i64 [ %4, %_llgo_0 ], [ %15, %_llgo_2 ]
%4 = add i64 %3, 1 %7 = phi i64 [ -1, %_llgo_0 ], [ %8, %_llgo_2 ]
%5 = icmp slt i64 %4, %1 %mrv = insertvalue %"github.com/goplus/llgo/internal/runtime.String" poison, ptr %5, 0
br i1 %5, label %_llgo_2, label %_llgo_3 %mrv1 = insertvalue %"github.com/goplus/llgo/internal/runtime.String" %mrv, i64 %6, 1
ret %"github.com/goplus/llgo/internal/runtime.String" %mrv1
%8 = add i64 %7, 1
%9 = icmp slt i64 %8, %1
br i1 %9, label %_llgo_2, label %_llgo_3
_llgo_2: ; preds = %_llgo_1 _llgo_2: ; preds = %_llgo_1
%6 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) %10 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0)
%7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %6, i64 %4 %11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %10, i64 %8
%8 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %7, align 8 %12 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %11, align 8
%9 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringCat"(%"github.com/goplus/llgo/internal/runtime.String" %2, %"github.com/goplus/llgo/internal/runtime.String" %8) %13 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.StringCat"(void <badref>, %"github.com/goplus/llgo/internal/runtime.String" %12)
%14 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %13, 0
%15 = extractvalue %"github.com/goplus/llgo/internal/runtime.String" %13, 1
br label %_llgo_1 br label %_llgo_1
_llgo_3: ; preds = %_llgo_1 _llgo_3: ; preds = %_llgo_1
ret %"github.com/goplus/llgo/internal/runtime.String" %2 ret void <badref>
%10 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 0)
} }
define void @main.init() { define void @main.init() {

View File

@@ -237,7 +237,8 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bo
callRuntimeInit(b, pkg) callRuntimeInit(b, pkg)
b.Call(pkg.FuncOf("main.init").Expr) b.Call(pkg.FuncOf("main.init").Expr)
} }
for _, instr := range block.Instrs { instrs := p.compilePhis(b, block.Instrs)
for _, instr := range instrs {
p.compileInstr(b, instr) p.compileInstr(b, instr)
} }
return ret return ret
@@ -327,6 +328,50 @@ func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr)
panic("allocaCStr(s string): invalid arguments") panic("allocaCStr(s string): invalid arguments")
} }
func isPhi(i ssa.Instruction) bool {
_, ok := i.(*ssa.Phi)
return ok
}
func (p *context) compilePhis(b llssa.Builder, instrs []ssa.Instruction) []ssa.Instruction {
if ninstr := len(instrs); ninstr > 0 {
if isPhi(instrs[0]) {
n := 1
for n < ninstr && isPhi(instrs[n]) {
n++
}
rets := make([]llssa.Expr, n)
for i := 0; i < n; i++ {
iv := instrs[i].(*ssa.Phi)
rets[i] = p.compilePhi(b, iv)
}
for i := 0; i < n; i++ {
iv := instrs[i].(*ssa.Phi)
p.bvals[iv] = rets[i].Do(b)
}
return instrs[n:]
}
}
return instrs
}
func (p *context) compilePhi(b llssa.Builder, v *ssa.Phi) (ret llssa.Expr) {
phi := b.Phi(p.prog.Type(v.Type()))
ret = phi.Expr
p.phis = append(p.phis, func() {
preds := v.Block().Preds
bblks := make([]llssa.BasicBlock, len(preds))
for i, pred := range preds {
bblks[i] = p.fn.Block(pred.Index)
}
edges := v.Edges
phi.AddIncoming(b, bblks, func(i int) llssa.Expr {
return p.compileValue(b, edges[i])
})
})
return
}
func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue bool) (ret llssa.Expr) { func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue bool) (ret llssa.Expr) {
if asValue { if asValue {
if v, ok := p.bvals[iv]; ok { if v, ok := p.bvals[iv]; ok {
@@ -390,18 +435,6 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
case *ssa.UnOp: case *ssa.UnOp:
x := p.compileValue(b, v.X) x := p.compileValue(b, v.X)
ret = b.UnOp(v.Op, 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(b, vals, bblks)
})
case *ssa.ChangeType: case *ssa.ChangeType:
t := v.Type() t := v.Type()
x := p.compileValue(b, v.X) x := p.compileValue(b, v.X)

View File

@@ -29,7 +29,7 @@ func testCompile(t *testing.T, src, expected string) {
} }
func TestFromTestrt(t *testing.T) { func TestFromTestrt(t *testing.T) {
cltest.FromDir(t, "concat", "./_testrt", true) cltest.FromDir(t, "", "./_testrt", true)
} }
func TestFromTestdata(t *testing.T) { func TestFromTestdata(t *testing.T) {

View File

@@ -55,6 +55,7 @@ func (v Expr) Do(b Builder) Expr {
return vt.t.(delayExprTy)() return vt.t.(delayExprTy)()
case vkPhisExpr: case vkPhisExpr:
e := vt.t.(*phisExprTy) e := vt.t.(*phisExprTy)
// TODO(xsw): to check CreateAggregateRet is correct or not
return Expr{b.impl.CreateAggregateRet(e.phis), e.Type} return Expr{b.impl.CreateAggregateRet(e.phis), e.Type}
} }
return v return v
@@ -362,10 +363,10 @@ func llvmValues(vals []Expr) []llvm.Value {
return ret return ret
} }
func fieldValues(b llvm.Builder, vals []Expr, fldIdx int) []llvm.Value { func llvmDelayValues(f func(i int) Expr, n int) []llvm.Value {
ret := make([]llvm.Value, len(vals)) ret := make([]llvm.Value, n)
for i, v := range vals { for i := 0; i < n; i++ {
ret[i] = llvm.CreateExtractValue(b, v.impl, fldIdx) ret[i] = f(i).impl
} }
return ret return ret
} }
@@ -384,17 +385,30 @@ type Phi struct {
} }
// AddIncoming adds incoming values to a phi node. // AddIncoming adds incoming values to a phi node.
func (p Phi) AddIncoming(b Builder, vals []Expr, bblks []BasicBlock) { func (p Phi) AddIncoming(b Builder, bblks []BasicBlock, f func(i int) Expr) {
bs := llvmBlocks(bblks) bs := llvmBlocks(bblks)
if p.kind != vkPhisExpr { // normal phi node if p.kind != vkPhisExpr { // normal phi node
vs := llvmValues(vals) vs := llvmDelayValues(f, len(bblks))
p.impl.AddIncoming(vs, bs) p.impl.AddIncoming(vs, bs)
return return
} }
e := p.t.(*phisExprTy) e := p.t.(*phisExprTy)
for i, phi := range e.phis { phis := e.phis
flds := fieldValues(b.impl, vals, i) vals := make([][]llvm.Value, len(phis))
phi.AddIncoming(flds, bs) for iblk, blk := range bblks {
last := blk.impl.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(bblks))
}
vals[i][iblk] = llvm.CreateExtractValue(impl, val, i)
}
}
for i, phi := range phis {
phi.AddIncoming(vals[i], bs)
} }
} }