Merge pull request #81 from xushiwei/q
llgo/ssa,runtime: Slice; llgo/ssa: phi node
This commit is contained in:
@@ -7,8 +7,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := c.String("Hi\n")
|
||||
s := c.Str("Hi\n")
|
||||
s2 := c.Alloca(4)
|
||||
c.Memcpy(s2, unsafe.Pointer(s), 4)
|
||||
c.Printf(c.String("%s"), s2)
|
||||
c.Printf(c.Str("%s"), s2)
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ func incVal(a any) int {
|
||||
}
|
||||
|
||||
func main() {
|
||||
c.Printf(c.String("Hello %d\n"), incVal(100))
|
||||
c.Printf(c.Str("Hello %d\n"), incVal(100))
|
||||
}
|
||||
|
||||
16
cl/_testcgo/sum/in.go
Normal file
16
cl/_testcgo/sum/in.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/internal/runtime/c"
|
||||
)
|
||||
|
||||
func sum(args ...int) (ret int) {
|
||||
for _, v := range args {
|
||||
ret += v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
c.Printf(c.Str("Hello %d\n"), sum(1, 2, 3, 4))
|
||||
}
|
||||
68
cl/_testcgo/sum/out.ll
Normal file
68
cl/_testcgo/sum/out.ll
Normal file
@@ -0,0 +1,68 @@
|
||||
; ModuleID = 'main'
|
||||
source_filename = "main"
|
||||
|
||||
%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 }
|
||||
|
||||
@"main.init$guard" = global ptr null
|
||||
@0 = private unnamed_addr constant [10 x i8] c"Hello %d\0A\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 void @main() {
|
||||
_llgo_0:
|
||||
call void @main.init()
|
||||
%0 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||
%1 = getelementptr inbounds i64, ptr %0, i64 0
|
||||
store i64 1, ptr %1, align 4
|
||||
%2 = getelementptr inbounds i64, ptr %0, i64 1
|
||||
store i64 2, ptr %2, align 4
|
||||
%3 = getelementptr inbounds i64, ptr %0, i64 2
|
||||
store i64 3, ptr %3, align 4
|
||||
%4 = getelementptr inbounds i64, ptr %0, i64 3
|
||||
store i64 4, ptr %4, align 4
|
||||
%5 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(i64 4, i64 4)
|
||||
%6 = call i64 @main.sum(%"github.com/goplus/llgo/internal/runtime.Slice" %5)
|
||||
%7 = call i32 (ptr, ...) @printf(ptr @0, i64 %6)
|
||||
ret void
|
||||
}
|
||||
|
||||
define i64 @main.sum(%"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)
|
||||
br label %_llgo_1
|
||||
|
||||
_llgo_1: ; preds = %_llgo_2, %_llgo_0
|
||||
%2 = phi i64 [ 0, %_llgo_0 ], [ %8, %_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
|
||||
|
||||
_llgo_2: ; preds = %_llgo_1
|
||||
%6 = getelementptr inbounds i64, %"github.com/goplus/llgo/internal/runtime.Slice" %0, i64 %4
|
||||
%7 = load i64, %"github.com/goplus/llgo/internal/runtime.Slice" %6, align 4
|
||||
%8 = add i64 %2, %7
|
||||
br label %_llgo_1
|
||||
|
||||
_llgo_3: ; preds = %_llgo_1
|
||||
ret i64 %2
|
||||
}
|
||||
|
||||
declare ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64)
|
||||
|
||||
declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr, i64, i64)
|
||||
|
||||
declare i32 @printf(ptr, ...)
|
||||
|
||||
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice")
|
||||
@@ -10,5 +10,5 @@ func foo() {
|
||||
|
||||
func main() {
|
||||
foo()
|
||||
c.Printf(c.String("Hello\n"))
|
||||
c.Printf(c.Str("Hello\n"))
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -275,7 +280,7 @@ func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||
if c, ok := args[0].(*ssa.Const); ok {
|
||||
if v := c.Value; v.Kind() == constant.String {
|
||||
sv := constant.StringVal(v)
|
||||
return b.CString(sv)
|
||||
return b.CStr(sv)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -373,7 +390,18 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
||||
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs slice
|
||||
return
|
||||
}
|
||||
panic("todo")
|
||||
var low, high, max llssa.Expr
|
||||
x := p.compileValue(b, vx)
|
||||
if v.Low != nil {
|
||||
low = p.compileValue(b, v.Low)
|
||||
}
|
||||
if v.High != nil {
|
||||
high = p.compileValue(b, v.High)
|
||||
}
|
||||
if v.Max != nil {
|
||||
max = p.compileValue(b, v.Max)
|
||||
}
|
||||
ret = b.Slice(x, low, high, max)
|
||||
case *ssa.Alloc:
|
||||
t := v.Type().(*types.Pointer)
|
||||
if p.checkVArgs(v, t) { // varargs: this is a varargs allocation
|
||||
|
||||
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-0.20240429101120-83f0ad1fd7b3
|
||||
github.com/goplus/llvm v0.7.3-0.20240430032503-06c2c6248df7
|
||||
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
@@ -10,6 +10,8 @@ github.com/goplus/llvm v0.7.3-0.20240429063826-4d6268bd1670 h1:M5fGMLl9vj1W4lSKr
|
||||
github.com/goplus/llvm v0.7.3-0.20240429063826-4d6268bd1670/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
|
||||
github.com/goplus/llvm v0.7.3-0.20240429101120-83f0ad1fd7b3 h1:FWne6LdbQ0p+lGBpkdmCYzcJDDTH85ygkkWKy2Pd3EQ=
|
||||
github.com/goplus/llvm v0.7.3-0.20240429101120-83f0ad1fd7b3/go.mod h1:PeVK8GgzxwAYCiMiUAJb5wJR6xbhj989tu9oulKLLT4=
|
||||
github.com/goplus/llvm v0.7.3-0.20240430032503-06c2c6248df7 h1:mRJ4mVkklwfhFRI5lmC9ZrEptTkW2FLSEWiZg/rqM7k=
|
||||
github.com/goplus/llvm v0.7.3-0.20240430032503-06c2c6248df7/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=
|
||||
|
||||
@@ -23,8 +23,8 @@ const (
|
||||
LLGoPackage = "decl"
|
||||
)
|
||||
|
||||
//go:linkname String llgo.cstr
|
||||
func String(string) *int8
|
||||
//go:linkname Str llgo.cstr
|
||||
func Str(string) *int8
|
||||
|
||||
//go:linkname Alloca llgo.alloca
|
||||
func Alloca(size uintptr) unsafe.Pointer
|
||||
|
||||
@@ -172,6 +172,19 @@ _llgo_0:
|
||||
ret %"github.com/goplus/llgo/internal/runtime.iface" %12
|
||||
}
|
||||
|
||||
define %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice"(ptr %0, i64 %1, i64 %2) {
|
||||
_llgo_0:
|
||||
%3 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
|
||||
%4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %3, i32 0, i32 0
|
||||
%5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %3, i32 0, i32 1
|
||||
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %3, i32 0, i32 2
|
||||
store ptr %0, ptr %4, align 8
|
||||
store i64 %1, ptr %5, align 4
|
||||
store i64 %2, ptr %6, align 4
|
||||
%7 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr %3, align 8
|
||||
ret %"github.com/goplus/llgo/internal/runtime.Slice" %7
|
||||
}
|
||||
|
||||
define %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NilSlice"() {
|
||||
_llgo_0:
|
||||
%0 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
|
||||
@@ -185,6 +198,15 @@ _llgo_0:
|
||||
ret %"github.com/goplus/llgo/internal/runtime.Slice" %4
|
||||
}
|
||||
|
||||
define i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
|
||||
_llgo_0:
|
||||
%1 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8
|
||||
store %"github.com/goplus/llgo/internal/runtime.Slice" %0, ptr %1, align 8
|
||||
%2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %1, i32 0, i32 1
|
||||
%3 = load i64, ptr %2, align 4
|
||||
ret i64 %3
|
||||
}
|
||||
|
||||
define ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 %0) {
|
||||
_llgo_0:
|
||||
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16)
|
||||
|
||||
@@ -24,9 +24,9 @@ import (
|
||||
|
||||
// Slice is the runtime representation of a slice.
|
||||
type Slice struct {
|
||||
array unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
data unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
}
|
||||
|
||||
// NilSlice returns a nil slice.
|
||||
@@ -34,4 +34,14 @@ func NilSlice() Slice {
|
||||
return Slice{nil, 0, 0}
|
||||
}
|
||||
|
||||
// NewSlice creates a new slice.
|
||||
func NewSlice(data unsafe.Pointer, len, cap int) Slice {
|
||||
return Slice{data, len, cap}
|
||||
}
|
||||
|
||||
// SliceLen returns the length of a slice.
|
||||
func SliceLen(s Slice) int {
|
||||
return s.len
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
121
ssa/expr.go
121
ssa/expr.go
@@ -35,6 +35,11 @@ type Expr struct {
|
||||
Type
|
||||
}
|
||||
|
||||
// IsNil checks if the expression is nil or not.
|
||||
func (v Expr) IsNil() bool {
|
||||
return v.Type == nil
|
||||
}
|
||||
|
||||
/*
|
||||
// TypeOf returns the type of the expression.
|
||||
func (v Expr) TypeOf() types.Type {
|
||||
@@ -67,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}
|
||||
@@ -142,9 +137,15 @@ func (b Builder) Const(v constant.Value, typ Type) Expr {
|
||||
case kind == types.Bool:
|
||||
return prog.BoolVal(constant.BoolVal(v))
|
||||
case kind >= types.Int && kind <= types.Uintptr:
|
||||
if v, exact := constant.Uint64Val(v); exact {
|
||||
return prog.IntVal(v, typ)
|
||||
if v, exact := constant.Int64Val(v); exact {
|
||||
return prog.IntVal(uint64(v), typ)
|
||||
}
|
||||
panic("todo")
|
||||
/*
|
||||
if v, exact := constant.Uint64Val(v); exact {
|
||||
return prog.IntVal(v, typ)
|
||||
}
|
||||
*/
|
||||
case kind == types.Float32 || kind == types.Float64:
|
||||
if v, exact := constant.Float64Val(v); exact {
|
||||
return prog.FloatVal(v, typ)
|
||||
@@ -153,12 +154,12 @@ func (b Builder) Const(v constant.Value, typ Type) Expr {
|
||||
return prog.StringVal(constant.StringVal(v))
|
||||
}
|
||||
}
|
||||
panic("todo")
|
||||
panic(fmt.Sprintf("unsupported Const: %v, %v", v, typ.t))
|
||||
}
|
||||
|
||||
// CString returns a c-style string constant expression.
|
||||
func (b Builder) CString(v string) Expr {
|
||||
return Expr{llvm.CreateGlobalStringPtr(b.impl, v), b.Prog.CString()}
|
||||
// CStr returns a c-style string constant expression.
|
||||
func (b Builder) CStr(v string) Expr {
|
||||
return Expr{llvm.CreateGlobalStringPtr(b.impl, v), b.Prog.CStr()}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -321,6 +322,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 {
|
||||
@@ -392,6 +430,45 @@ func (b Builder) IndexAddr(x, idx Expr) Expr {
|
||||
return Expr{llvm.CreateInBoundsGEP(b.impl, telem.ll, x.impl, indices), pt}
|
||||
}
|
||||
|
||||
// The Slice instruction yields a slice of an existing string, slice
|
||||
// or *array X between optional integer bounds Low and High.
|
||||
//
|
||||
// Dynamically, this instruction panics if X evaluates to a nil *array
|
||||
// pointer.
|
||||
//
|
||||
// Type() returns string if the type of X was string, otherwise a
|
||||
// *types.Slice with the same element type as X.
|
||||
//
|
||||
// Pos() returns the ast.SliceExpr.Lbrack if created by a x[:] slice
|
||||
// operation, the ast.CompositeLit.Lbrace if created by a literal, or
|
||||
// NoPos if not explicit in the source (e.g. a variadic argument slice).
|
||||
//
|
||||
// Example printed form:
|
||||
//
|
||||
// t1 = slice t0[1:]
|
||||
func (b Builder) Slice(x, low, high, max Expr) (ret Expr) {
|
||||
if debugInstr {
|
||||
log.Printf("Slice %v, %v, %v\n", x.impl, low.impl, high.impl)
|
||||
}
|
||||
prog := b.Prog
|
||||
pkg := b.fn.pkg
|
||||
switch t := x.t.Underlying().(type) {
|
||||
case *types.Pointer:
|
||||
telem := t.Elem()
|
||||
switch te := telem.Underlying().(type) {
|
||||
case *types.Array:
|
||||
ret.Type = prog.Type(types.NewSlice(te.Elem()))
|
||||
if low.IsNil() && high.IsNil() && max.IsNil() {
|
||||
n := prog.Val(int(te.Len()))
|
||||
return b.InlineCall(pkg.rtFunc("NewSlice"), n, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// The Alloc instruction reserves space for a variable of the given type,
|
||||
// zero-initializes it, and yields its address.
|
||||
//
|
||||
@@ -453,6 +530,8 @@ func (b Builder) ArrayAlloca(telem Type, n Expr) (ret Expr) {
|
||||
}
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// The ChangeType instruction applies to X a value-preserving type
|
||||
// change to Type().
|
||||
//
|
||||
@@ -713,6 +792,16 @@ func (b Builder) Call(fn Expr, args ...Expr) (ret Expr) {
|
||||
// `fn` indicates the function: one of the built-in functions from the
|
||||
// Go spec (excluding "make" and "new").
|
||||
func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
||||
switch fn {
|
||||
case "len":
|
||||
if len(args) == 1 {
|
||||
arg := args[0]
|
||||
switch arg.t.Underlying().(type) {
|
||||
case *types.Slice:
|
||||
return b.InlineCall(b.fn.pkg.rtFunc("SliceLen"), arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
panic("todo")
|
||||
}
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ func (p Program) Bool() Type {
|
||||
return p.boolTy
|
||||
}
|
||||
|
||||
func (p Program) CString() Type {
|
||||
func (p Program) CStr() Type {
|
||||
if p.cstrTy == nil { // *int8
|
||||
p.cstrTy = p.Type(types.NewPointer(types.Typ[types.Int8]))
|
||||
}
|
||||
|
||||
@@ -104,6 +104,10 @@ type aType struct {
|
||||
|
||||
type Type = *aType
|
||||
|
||||
func (p Program) Slice(typ Type) Type {
|
||||
return p.Type(types.NewSlice(typ.t))
|
||||
}
|
||||
|
||||
func (p Program) Pointer(typ Type) Type {
|
||||
return p.Type(types.NewPointer(typ.t))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user