llgo/ssa: phi refactor

This commit is contained in:
xushiwei
2024-05-26 14:58:26 +08:00
parent 91c9b4e168
commit 5cf6a30027
9 changed files with 197 additions and 74 deletions

16
cl/_testgo/abiname/in.go Normal file
View File

@@ -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())
}

99
cl/_testgo/abiname/out.ll Normal file
View File

@@ -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)

View File

@@ -522,7 +522,7 @@ func (p *context) compilePhis(b llssa.Builder, block *ssa.BasicBlock) int {
} }
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
iv := block.Instrs[i].(*ssa.Phi) iv := block.Instrs[i].(*ssa.Phi)
p.bvals[iv] = rets[i].Do(b) p.bvals[iv] = rets[i]
} }
return n return n
} }
@@ -784,7 +784,7 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
val := p.compileValue(b, v.Value) val := p.compileValue(b, v.Value)
b.MapUpdate(m, key, val) b.MapUpdate(m, key, val)
case *ssa.Panic: case *ssa.Panic:
arg := p.compileValue(b, v.X).Do(b) arg := p.compileValue(b, v.X)
b.Panic(arg) b.Panic(arg)
default: default:
panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr)) 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 n := len(vals) - hasVArg
ret := make([]llssa.Expr, n) ret := make([]llssa.Expr, n)
for i := 0; i < n; i++ { 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 { if hasVArg > 0 {
ret = p.compileVArg(ret, b, vals[n]) ret = p.compileVArg(ret, b, vals[n])

Binary file not shown.

Binary file not shown.

View File

@@ -26,7 +26,7 @@ import (
) )
func TestFromTestgo(t *testing.T) { func TestFromTestgo(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testgo", false) cltest.FromDir(t, "abiname", "../cl/_testgo", false)
} }
func TestFromTestpy(t *testing.T) { func TestFromTestpy(t *testing.T) {

View File

@@ -41,16 +41,6 @@ func (v Expr) IsNil() bool {
return v.Type == nil 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 { 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 { func (p Program) Zero(t Type) Expr {
var ret llvm.Value var ret llvm.Value
switch u := t.raw.Type.Underlying().(type) { switch u := t.raw.Type.Underlying().(type) {
@@ -533,14 +503,6 @@ func llvmFields(vals []Expr, t *types.Struct, b Builder) (ret []llvm.Value) {
return 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 { func llvmPredBlocks(preds []BasicBlock) []llvm.BasicBlock {
ret := make([]llvm.BasicBlock, len(preds)) ret := make([]llvm.BasicBlock, len(preds))
for i, v := range preds { for i, v := range preds {
@@ -549,21 +511,24 @@ func llvmPredBlocks(preds []BasicBlock) []llvm.BasicBlock {
return ret return ret
} }
// Phi represents a phi node. type aPhi struct {
type Phi struct {
Expr 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. // AddIncoming adds incoming values to a phi node.
func (p Phi) AddIncoming(b Builder, preds []BasicBlock, f func(i int) Expr) { func (p Phi) AddIncoming(b Builder, preds []BasicBlock, f func(i int) Expr) {
bs := llvmPredBlocks(preds) bs := llvmPredBlocks(preds)
if p.kind != vkPhisExpr { // normal phi node phis := p.phis
vs := llvmDelayValues(f, len(preds)) if phis != nil {
p.impl.AddIncoming(vs, bs)
return
}
e := p.raw.Type.(*phisExprTy)
phis := e.phis
vals := make([][]llvm.Value, len(phis)) vals := make([][]llvm.Value, len(phis))
for iblk, blk := range preds { for iblk, blk := range preds {
last := blk.last.LastInstruction() last := blk.last.LastInstruction()
@@ -580,6 +545,15 @@ func (p Phi) AddIncoming(b Builder, preds []BasicBlock, f func(i int) Expr) {
for i, phi := range phis { for i, phi := range phis {
phi.AddIncoming(vals[i], bs) 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)
}
} }
// Phi returns a phi node. // Phi returns a phi node.
@@ -590,17 +564,55 @@ func (b Builder) Phi(t Type) Phi {
kind := tund.Kind() kind := tund.Kind()
switch kind { switch kind {
case types.String: case types.String:
prog := b.Prog phis := createStringPhis(impl, make([]llvm.Value, 0, 2), b.Prog)
phis := make([]llvm.Value, 2) return b.newPhi(t, phis)
phis[0] = llvm.CreatePHI(impl, prog.tyVoidPtr())
phis[1] = llvm.CreatePHI(impl, prog.tyInt())
return Phi{phisExpr(t, phis)}
} }
case *types.Struct: case *types.Struct:
phis := createStrucPhis(impl, nil, tund, b.Prog)
return b.newPhi(t, phis)
default:
panic("todo") panic("todo")
} }
phi := llvm.CreatePHI(impl, t.ll) 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)
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -109,9 +109,7 @@ func TestCvtType(t *testing.T) {
} }
func TestUserdefExpr(t *testing.T) { func TestUserdefExpr(t *testing.T) {
b := &phisExprTy{}
c := &pyVarTy{} c := &pyVarTy{}
_ = b.String()
_ = c.String() _ = c.String()
test := func(a types.Type) { test := func(a types.Type) {
defer func() { defer func() {
@@ -121,7 +119,6 @@ func TestUserdefExpr(t *testing.T) {
}() }()
a.Underlying() a.Underlying()
} }
test(b)
test(c) test(c)
} }

View File

@@ -53,7 +53,6 @@ const (
vkEface vkEface
vkIface vkIface
vkStruct vkStruct
vkPhisExpr = -1
) )
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------