Merge pull request #81 from xushiwei/q

llgo/ssa,runtime: Slice; llgo/ssa: phi node
This commit is contained in:
xushiwei
2024-04-30 11:36:11 +08:00
committed by GitHub
14 changed files with 268 additions and 29 deletions

View File

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

View File

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

View File

@@ -10,5 +10,5 @@ func foo() {
func main() {
foo()
c.Printf(c.String("Hello\n"))
c.Printf(c.Str("Hello\n"))
}

View File

@@ -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
View File

@@ -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
View File

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

View File

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

View File

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

View File

@@ -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
}
// -----------------------------------------------------------------------------

View File

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

View File

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

View File

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