Merge pull request #94 from xushiwei/q
cl: compilePhis; llgo/ssa: phi.AddIncoming
This commit is contained in:
@@ -13,5 +13,5 @@ func concat(args ...string) (ret string) {
|
||||
|
||||
func main() {
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -10,30 +10,38 @@ source_filename = "main"
|
||||
@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
|
||||
@__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) {
|
||||
_llgo_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
|
||||
|
||||
_llgo_1: ; preds = %_llgo_2, %_llgo_0
|
||||
%2 = phi %"github.com/goplus/llgo/internal/runtime.String" [ %10, %_llgo_0 ], [ %9, %_llgo_2 ]
|
||||
%3 = phi i64 [ -1, %_llgo_0 ], [ %4, %_llgo_2 ]
|
||||
%4 = add i64 %3, 1
|
||||
%5 = icmp slt i64 %4, %1
|
||||
br i1 %5, label %_llgo_2, label %_llgo_3
|
||||
%5 = phi ptr [ %3, %_llgo_0 ], [ %14, %_llgo_2 ]
|
||||
%6 = phi i64 [ %4, %_llgo_0 ], [ %15, %_llgo_2 ]
|
||||
%7 = phi i64 [ -1, %_llgo_0 ], [ %8, %_llgo_2 ]
|
||||
%mrv = insertvalue %"github.com/goplus/llgo/internal/runtime.String" poison, ptr %5, 0
|
||||
%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
|
||||
%6 = 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
|
||||
%8 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %7, 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)
|
||||
%10 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0)
|
||||
%11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %10, i64 %8
|
||||
%12 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %11, align 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
|
||||
|
||||
_llgo_3: ; preds = %_llgo_1
|
||||
ret %"github.com/goplus/llgo/internal/runtime.String" %2
|
||||
%10 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 0)
|
||||
ret void <badref>
|
||||
}
|
||||
|
||||
define void @main.init() {
|
||||
|
||||
@@ -237,7 +237,8 @@ func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, doInit bo
|
||||
callRuntimeInit(b, pkg)
|
||||
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)
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
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) {
|
||||
if asValue {
|
||||
if v, ok := p.bvals[iv]; ok {
|
||||
@@ -390,18 +435,6 @@ 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)
|
||||
@@ -528,7 +561,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()
|
||||
arg := p.compileValue(b, v.X).Do(b)
|
||||
b.Panic(arg)
|
||||
default:
|
||||
panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr))
|
||||
@@ -585,7 +618,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()
|
||||
ret[i] = p.compileValue(b, vals[i]).Do(b)
|
||||
}
|
||||
if hasVArg > 0 {
|
||||
ret = p.compileVArg(ret, b, vals[n])
|
||||
|
||||
2
go.mod
2
go.mod
@@ -5,7 +5,7 @@ go 1.18
|
||||
require (
|
||||
github.com/aykevl/go-wasm v0.0.1
|
||||
github.com/goplus/gogen v1.15.2
|
||||
github.com/goplus/llvm v0.7.3
|
||||
github.com/goplus/llvm v0.7.4-0.20240502033044-f17514e2af8a
|
||||
github.com/goplus/mod v0.13.10
|
||||
github.com/qiniu/x v1.13.10
|
||||
golang.org/x/tools v0.20.0
|
||||
|
||||
2
go.sum
2
go.sum
@@ -4,6 +4,8 @@ github.com/goplus/gogen v1.15.2 h1:Q6XaSx/Zi5tWnjfAziYsQI6Jv6MgODRpFtOYqNkiiqM=
|
||||
github.com/goplus/gogen v1.15.2/go.mod h1:92qEzVgv7y8JEFICWG9GvYI5IzfEkxYdsA1DbmnTkqk=
|
||||
github.com/goplus/llvm v0.7.3 h1:I7UkAO4kzn0Es2iHKRpGU1LjYQ452XwYfsSs1OAAXk8=
|
||||
github.com/goplus/llvm v0.7.3/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
|
||||
github.com/goplus/llvm v0.7.4-0.20240502033044-f17514e2af8a h1:FLRrz/S4mCuVTB+M1lSOiCU7bTbcbl5A5XhI3ntKfmI=
|
||||
github.com/goplus/llvm v0.7.4-0.20240502033044-f17514e2af8a/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
|
||||
github.com/goplus/mod v0.13.10 h1:5Om6KOvo31daN7N30kWU1vC5zhsJPM+uPbcEN/FnlzE=
|
||||
github.com/goplus/mod v0.13.10/go.mod h1:HDuPZgpWiaTp3PUolFgsiX+Q77cbUWB/mikVHfYND3c=
|
||||
github.com/qiniu/x v1.13.10 h1:J4Z3XugYzAq85SlyAfqlKVrbf05glMbAOh+QncsDQpE=
|
||||
|
||||
83
ssa/expr.go
83
ssa/expr.go
@@ -49,13 +49,20 @@ func (v Expr) TypeOf() types.Type {
|
||||
*/
|
||||
|
||||
// Do evaluates the delay expression and returns the result.
|
||||
func (v Expr) Do() Expr {
|
||||
if vt := v.Type; vt.kind == vkDelayExpr {
|
||||
func (v Expr) Do(b Builder) Expr {
|
||||
switch vt := v.Type; vt.kind {
|
||||
case vkDelayExpr:
|
||||
return vt.t.(delayExprTy)()
|
||||
case vkPhisExpr:
|
||||
e := vt.t.(*phisExprTy)
|
||||
// TODO(xsw): to check CreateAggregateRet is correct or not
|
||||
return Expr{b.impl.CreateAggregateRet(e.phis), e.Type}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// DelayExpr returns a delay expression.
|
||||
func DelayExpr(f func() Expr) Expr {
|
||||
return Expr{Type: &aType{t: delayExprTy(f), kind: vkDelayExpr}}
|
||||
@@ -73,6 +80,25 @@ func (p delayExprTy) String() string {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
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 {
|
||||
return Expr{Type: &aType{t: &phisExprTy{phis, t}, kind: vkPhisExpr}}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Null returns a null constant expression.
|
||||
func (p Program) Null(t Type) Expr {
|
||||
return Expr{llvm.ConstNull(t.ll), t}
|
||||
@@ -337,6 +363,14 @@ func llvmValues(vals []Expr) []llvm.Value {
|
||||
return ret
|
||||
}
|
||||
|
||||
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 llvmBlocks(bblks []BasicBlock) []llvm.BasicBlock {
|
||||
ret := make([]llvm.BasicBlock, len(bblks))
|
||||
for i, v := range bblks {
|
||||
@@ -351,15 +385,50 @@ type Phi struct {
|
||||
}
|
||||
|
||||
// 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)
|
||||
func (p Phi) AddIncoming(b Builder, bblks []BasicBlock, f func(i int) Expr) {
|
||||
bs := llvmBlocks(bblks)
|
||||
if p.kind != vkPhisExpr { // normal phi node
|
||||
vs := llvmDelayValues(f, len(bblks))
|
||||
p.impl.AddIncoming(vs, bs)
|
||||
return
|
||||
}
|
||||
e := p.t.(*phisExprTy)
|
||||
phis := e.phis
|
||||
vals := make([][]llvm.Value, len(phis))
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// Phi returns a phi node.
|
||||
func (b Builder) Phi(t Type) Phi {
|
||||
return Phi{Expr{llvm.CreatePHI(b.impl, t.ll), t}}
|
||||
impl := b.impl
|
||||
switch tund := t.t.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
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)}
|
||||
}
|
||||
}
|
||||
phi := llvm.CreatePHI(impl, t.ll)
|
||||
return Phi{Expr{phi, t}}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -30,15 +30,21 @@ func TestMakeInterface(t *testing.T) {
|
||||
}
|
||||
*/
|
||||
|
||||
func TestDelayExpr(t *testing.T) {
|
||||
func TestUserdefExpr(t *testing.T) {
|
||||
a := delayExprTy(nil)
|
||||
b := &phisExprTy{}
|
||||
_ = a.String()
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Log("TestDelayExpr: no error?")
|
||||
}
|
||||
}()
|
||||
a.Underlying()
|
||||
_ = b.String()
|
||||
test := func(a types.Type) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Log("TestUserdefExpr: no error?")
|
||||
}
|
||||
}()
|
||||
a.Underlying()
|
||||
}
|
||||
test(a)
|
||||
test(b)
|
||||
}
|
||||
|
||||
func TestAny(t *testing.T) {
|
||||
|
||||
@@ -43,6 +43,7 @@ const (
|
||||
vkFunc
|
||||
vkTuple
|
||||
vkDelayExpr = -1
|
||||
vkPhisExpr = -2
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user