llgo/ssa: Do Call/Go/Defer

This commit is contained in:
xushiwei
2024-05-31 12:01:11 +08:00
parent 2196f2259f
commit 8f82d86a5d
6 changed files with 234 additions and 62 deletions

View File

@@ -0,0 +1,12 @@
package main
func main() {
done := false
go func() {
println("Hello, World!")
done = true
}()
for !done {
print(".")
}
}

View File

@@ -0,0 +1,89 @@
; ModuleID = 'main'
source_filename = "main"
%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 }
@"main.init$guard" = global ptr null
@__llgo_argc = global ptr null
@__llgo_argv = global ptr null
@0 = private unnamed_addr constant [2 x i8] c".\00", align 1
@1 = private unnamed_addr constant [14 x i8] c"Hello, World!\00", align 1
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
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 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 1)
store i1 false, ptr %2, align 1
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
%4 = getelementptr inbounds { ptr }, ptr %3, i32 0, i32 0
store ptr %2, ptr %4, align 8
%5 = alloca { ptr, ptr }, align 8
%6 = getelementptr inbounds { ptr, ptr }, ptr %5, i32 0, i32 0
store ptr @"main.main$1", ptr %6, align 8
%7 = getelementptr inbounds { ptr, ptr }, ptr %5, i32 0, i32 1
store ptr %3, ptr %7, align 8
%8 = load { ptr, ptr }, ptr %5, align 8
%9 = extractvalue { ptr, ptr } %8, 1
%10 = extractvalue { ptr, ptr } %8, 0
call void %10(ptr %9)
br label %_llgo_3
_llgo_1: ; preds = %_llgo_3
%11 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %11, i32 0, i32 0
store ptr @0, ptr %12, align 8
%13 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %11, i32 0, i32 1
store i64 1, ptr %13, align 4
%14 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %11, align 8
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %14)
br label %_llgo_3
_llgo_2: ; preds = %_llgo_3
ret i32 0
_llgo_3: ; preds = %_llgo_1, %_llgo_0
%15 = load i1, ptr %2, align 1
br i1 %15, label %_llgo_2, label %_llgo_1
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
define void @"main.main$1"(ptr %0) {
_llgo_0:
%1 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %1, i32 0, i32 0
store ptr @1, ptr %2, align 8
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %1, i32 0, i32 1
store i64 13, ptr %3, align 4
%4 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %1, align 8
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %4)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
%5 = load { ptr }, ptr %0, align 8
%6 = extractvalue { ptr } %5, 0
store i1 true, ptr %6, align 1
ret void
}
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64)
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)

5
cl/_testgo/print/in.go Normal file
View File

@@ -0,0 +1,5 @@
package main
func main() {
println('.', byte('.'))
}

40
cl/_testgo/print/out.ll Normal file
View File

@@ -0,0 +1,40 @@
; ModuleID = 'main'
source_filename = "main"
@"main.init$guard" = global ptr null
@__llgo_argc = global ptr null
@__llgo_argv = global ptr null
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
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()
call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 46)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 32)
call void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64 46)
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
ret i32 0
}
declare void @"github.com/goplus/llgo/internal/runtime.init"()
declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64)
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
declare void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64)

View File

@@ -548,6 +548,72 @@ func (p *context) compilePhi(b llssa.Builder, v *ssa.Phi) (ret llssa.Expr) {
return return
} }
func (p *context) call(b llssa.Builder, act llssa.DoAction, call *ssa.CallCommon) (ret llssa.Expr) {
cv := call.Value
if mthd := call.Method; mthd != nil {
o := p.compileValue(b, cv)
fn := b.Imethod(o, mthd)
args := p.compileValues(b, call.Args, fnNormal)
ret = b.Do(act, fn, args...)
return
}
kind := p.funcKind(cv)
if kind == fnIgnore {
return
}
args := call.Args
if debugGoSSA {
log.Println(">>> Do", act, cv, args)
}
switch cv := cv.(type) {
case *ssa.Builtin:
fn := cv.Name()
if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr
arg := args[0]
ret = p.compileValue(b, arg)
// log.Println("wrapnilchk:", ret.TypeOf())
} else {
args := p.compileValues(b, args, kind)
ret = b.BuiltinDo(act, fn, args...)
}
case *ssa.Function:
aFn, pyFn, ftype := p.compileFunction(cv)
// TODO(xsw): check ca != llssa.Call
switch ftype {
case goFunc, cFunc:
args := p.compileValues(b, args, kind)
ret = b.Do(act, aFn.Expr, args...)
case pyFunc:
args := p.compileValues(b, args, kind)
ret = b.Do(act, pyFn.Expr, args...)
case llgoPyList:
args := p.compileValues(b, args, fnHasVArg)
ret = b.PyList(args...)
case llgoCstr:
ret = cstr(b, args)
case llgoAdvance:
ret = p.advance(b, args)
case llgoIndex:
ret = p.index(b, args)
case llgoAlloca:
ret = p.alloca(b, args)
case llgoAllocaCStr:
ret = p.allocaCStr(b, args)
case llgoStringData:
ret = p.stringData(b, args)
case llgoUnreachable: // func unreachable()
b.Unreachable()
default:
log.Panicln("unknown ftype:", ftype)
}
default:
fn := p.compileValue(b, cv)
args := p.compileValues(b, args, kind)
ret = b.Do(act, fn, args...)
}
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 {
@@ -557,67 +623,7 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
} }
switch v := iv.(type) { switch v := iv.(type) {
case *ssa.Call: case *ssa.Call:
cv := v.Call.Value ret = p.call(b, llssa.Call, &v.Call)
if mthd := v.Call.Method; mthd != nil {
o := p.compileValue(b, cv)
fn := b.Imethod(o, v.Call.Method)
args := p.compileValues(b, v.Call.Args, fnNormal)
ret = b.Call(fn, args...)
break
}
kind := p.funcKind(cv)
if kind == fnIgnore {
return
}
args := v.Call.Args
if debugGoSSA {
log.Println(">>> Call", cv, args)
}
switch cv := cv.(type) {
case *ssa.Builtin:
fn := cv.Name()
if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr
arg := args[0]
ret = p.compileValue(b, arg)
// log.Println("wrapnilchk:", ret.TypeOf())
} else {
args := p.compileValues(b, args, kind)
ret = b.BuiltinCall(fn, args...)
}
case *ssa.Function:
aFn, pyFn, ftype := p.compileFunction(cv)
switch ftype {
case goFunc, cFunc:
args := p.compileValues(b, args, kind)
ret = b.Call(aFn.Expr, args...)
case pyFunc:
args := p.compileValues(b, args, kind)
ret = b.Call(pyFn.Expr, args...)
case llgoPyList:
args := p.compileValues(b, args, fnHasVArg)
ret = b.PyList(args...)
case llgoCstr:
ret = cstr(b, args)
case llgoAdvance:
ret = p.advance(b, args)
case llgoIndex:
ret = p.index(b, args)
case llgoAlloca:
ret = p.alloca(b, args)
case llgoAllocaCStr:
ret = p.allocaCStr(b, args)
case llgoStringData:
ret = p.stringData(b, args)
case llgoUnreachable: // func unreachable()
b.Unreachable()
default:
log.Panicln("unknown ftype:", ftype)
}
default:
fn := p.compileValue(b, cv)
args := p.compileValues(b, args, kind)
ret = b.Call(fn, args...)
}
case *ssa.BinOp: case *ssa.BinOp:
x := p.compileValue(b, v.X) x := p.compileValue(b, v.X)
y := p.compileValue(b, v.Y) y := p.compileValue(b, v.Y)
@@ -791,6 +797,8 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
key := p.compileValue(b, v.Key) key := p.compileValue(b, v.Key)
val := p.compileValue(b, v.Value) val := p.compileValue(b, v.Value)
b.MapUpdate(m, key, val) b.MapUpdate(m, key, val)
case *ssa.Go:
p.call(b, llssa.Go, &v.Call)
case *ssa.Panic: case *ssa.Panic:
arg := p.compileValue(b, v.X) arg := p.compileValue(b, v.X)
b.Panic(arg) b.Panic(arg)

View File

@@ -892,13 +892,26 @@ func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) {
// t2 = println(t0, t1) // t2 = println(t0, t1)
// t4 = t3() // t4 = t3()
func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) { func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
return b.Do(Call, fn, args...)
}
type DoAction int
const (
Call DoAction = iota
Go
Defer
)
// Do call a function with an action.
func (b Builder) Do(da DoAction, fn Expr, args ...Expr) (ret Expr) {
if debugInstr { if debugInstr {
var b bytes.Buffer var b bytes.Buffer
name := fn.impl.Name() name := fn.impl.Name()
if name == "" { if name == "" {
name = "closure" name = "closure"
} }
fmt.Fprint(&b, "Call ", fn.kind, " ", fn.raw.Type, " ", name) fmt.Fprint(&b, "Do ", da, " ", fn.kind, " ", fn.raw.Type, " ", name)
sep := ": " sep := ": "
for _, arg := range args { for _, arg := range args {
fmt.Fprint(&b, sep, arg.impl) fmt.Fprint(&b, sep, arg.impl)
@@ -987,6 +1000,11 @@ func (b Builder) Next(iter Expr, isString bool) (ret Expr) {
// `fn` indicates the function: one of the built-in functions from the // `fn` indicates the function: one of the built-in functions from the
// Go spec (excluding "make" and "new"). // Go spec (excluding "make" and "new").
func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) { func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
return b.BuiltinDo(Call, fn, args...)
}
// BuiltinDo call a builtin function with an action.
func (b Builder) BuiltinDo(da DoAction, fn string, args ...Expr) (ret Expr) {
switch fn { switch fn {
case "len": case "len":
if len(args) == 1 { if len(args) == 1 {