From 475f0fa2ff9365884d510f005b88abe4109d6bc9 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 28 Apr 2024 06:23:21 +0800 Subject: [PATCH 1/8] llgo/ssa: ChangeType, Convert --- cl/compile.go | 4 ++++ ssa/expr.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/cl/compile.go b/cl/compile.go index 9f2e9ceb..3a4fd9fa 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -300,6 +300,10 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l t := v.Type() x := p.compileValue(b, v.X) ret = b.ChangeType(p.prog.Type(t), x) + case *ssa.Convert: + t := v.Type() + x := p.compileValue(b, v.X) + ret = b.Convert(p.prog.Type(t), x) case *ssa.FieldAddr: x := p.compileValue(b, v.X) ret = b.FieldAddr(x, v.Field) diff --git a/ssa/expr.go b/ssa/expr.go index 811d6d06..bbc76f57 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -110,6 +110,9 @@ func (p Program) Val(v interface{}) Expr { } func (b Builder) Const(v constant.Value, typ Type) Expr { + if v == nil { + return b.prog.Null(typ) + } switch t := typ.t.(type) { case *types.Basic: kind := t.Kind() @@ -410,9 +413,6 @@ func (b Builder) Alloc(t Type, heap bool) (ret Expr) { // types in the type set of X.Type() have a value-preserving type // change to all types in the type set of Type(). // -// Pos() returns the ast.CallExpr.Lparen, if the instruction arose -// from an explicit conversion in the source. -// // Example printed form: // // t1 = changetype *int <- IntPtr (t0) @@ -422,9 +422,58 @@ func (b Builder) ChangeType(t Type, x Expr) (ret Expr) { } typ := t.t switch typ.(type) { + default: + ret.impl = b.impl.CreateBitCast(x.impl, t.ll, "bitCast") + ret.Type = b.prog.Type(typ) + return + } +} + +// The Convert instruction yields the conversion of value X to type +// Type(). One or both of those types is basic (but possibly named). +// +// A conversion may change the value and representation of its operand. +// Conversions are permitted: +// - between real numeric types. +// - between complex numeric types. +// - between string and []byte or []rune. +// - between pointers and unsafe.Pointer. +// - between unsafe.Pointer and uintptr. +// - from (Unicode) integer to (UTF-8) string. +// +// A conversion may imply a type name change also. +// +// Conversions may to be to or from a type parameter. All types in +// the type set of X.Type() can be converted to all types in the type +// set of Type(). +// +// This operation cannot fail dynamically. +// +// Conversions of untyped string/number/bool constants to a specific +// representation are eliminated during SSA construction. +// +// Pos() returns the ast.CallExpr.Lparen, if the instruction arose +// from an explicit conversion in the source. +// +// Example printed form: +// +// t1 = convert []byte <- string (t0) +func (b Builder) Convert(t Type, x Expr) (ret Expr) { + typ := t.t + ret.Type = b.prog.Type(typ) + switch und := typ.Underlying().(type) { + case *types.Basic: + kind := und.Kind() + switch { + case kind >= types.Int && kind <= types.Uintptr: + ret.impl = b.impl.CreateIntCast(x.impl, t.ll, "castInt") + return + case kind == types.UnsafePointer: + ret.impl = b.impl.CreatePointerCast(x.impl, t.ll, "castPtr") + return + } case *types.Pointer: ret.impl = b.impl.CreatePointerCast(x.impl, t.ll, "castPtr") - ret.Type = b.prog.Type(typ) return } panic("todo") @@ -534,6 +583,7 @@ func (b Builder) TypeAssert(x Expr, assertedTyp Type, commaOk bool) (ret Expr) { // ----------------------------------------------------------------------------- +// TODO(xsw): make inline call func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) { return b.Call(fn, args...) } From 5415f68c1bc2f564a21214b55137c213784a0cb5 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 28 Apr 2024 07:08:01 +0800 Subject: [PATCH 2/8] llgo/ssa: Alloc, BinOp(vkPtr) --- internal/runtime/z_type.go | 4 ++-- ssa/expr.go | 16 +++++++++++++--- ssa/package.go | 19 ++++++++++++++----- ssa/type.go | 5 +++-- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/internal/runtime/z_type.go b/internal/runtime/z_type.go index f0ad7723..02b31b2d 100644 --- a/internal/runtime/z_type.go +++ b/internal/runtime/z_type.go @@ -17,15 +17,15 @@ package runtime import ( - "go/types" "unsafe" "github.com/goplus/llgo/internal/abi" ) +type Kind = abi.Kind type Type = abi.Type -func Basic(kind types.BasicKind) *Type { +func Basic(kind Kind) *Type { return basicTypes[kind] } diff --git a/ssa/expr.go b/ssa/expr.go index bbc76f57..eda2c4dc 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -23,6 +23,7 @@ import ( "go/token" "go/types" "log" + "unsafe" "github.com/goplus/llvm" ) @@ -76,10 +77,12 @@ func llvmValues(vals []Expr) []llvm.Value { // ----------------------------------------------------------------------------- +// Null returns a null constant expression. func (p Program) Null(t Type) Expr { return Expr{llvm.ConstNull(t.ll), t} } +// BoolVal returns a boolean constant expression. func (p Program) BoolVal(v bool) Expr { t := p.Bool() var bv uint64 @@ -90,15 +93,19 @@ func (p Program) BoolVal(v bool) Expr { return Expr{ret, t} } +// IntVal returns an integer constant expression. func (p Program) IntVal(v uint64, t Type) Expr { ret := llvm.ConstInt(t.ll, v, false) return Expr{ret, t} } +// Val returns a constant expression. func (p Program) Val(v interface{}) Expr { switch v := v.(type) { case int: return p.IntVal(uint64(v), p.Int()) + case uintptr: + return p.IntVal(uint64(v), p.Uintptr()) case bool: return p.BoolVal(v) case float64: @@ -109,6 +116,7 @@ func (p Program) Val(v interface{}) Expr { panic("todo") } +// Const returns a constant expression. func (b Builder) Const(v constant.Value, typ Type) Expr { if v == nil { return b.prog.Null(typ) @@ -258,7 +266,7 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr { case vkSigned: pred := intPredOpToLLVM[op-predOpBase] return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret} - case vkUnsigned: + case vkUnsigned, vkPtr: pred := uintPredOpToLLVM[op-predOpBase] return Expr{llvm.CreateICmp(b.impl, pred, x.impl, y.impl), tret} case vkFloat: @@ -386,9 +394,11 @@ func (b Builder) Alloc(t Type, heap bool) (ret Expr) { if heap { ret.impl = llvm.CreateAlloca(b.impl, telem.ll) } else { - panic("todo") + pkg := b.fn.pkg + size := unsafe.Sizeof(t.t) + ret = b.Call(pkg.rtFunc("Alloc"), b.prog.Val(size)) } - // TODO: zero-initialize + // TODO(xsw): zero-initialize ret.Type = t return } diff --git a/ssa/package.go b/ssa/package.go index 23af1d23..cd63b986 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -113,11 +113,12 @@ type aProgram struct { rtIfaceTy llvm.Type rtSliceTy llvm.Type - anyTy Type - voidTy Type - boolTy Type - intTy Type - f64Ty Type + anyTy Type + voidTy Type + boolTy Type + uintptrTy Type + intTy Type + f64Ty Type } // A Program presents a program. @@ -211,6 +212,14 @@ func (p Program) Int() Type { return p.intTy } +// Uintptr returns uintptr type. +func (p Program) Uintptr() Type { + if p.uintptrTy == nil { + p.uintptrTy = p.Type(types.Typ[types.Uintptr]) + } + return p.uintptrTy +} + // Float64 returns float64 type. func (p Program) Float64() Type { if p.f64Ty == nil { diff --git a/ssa/type.go b/ssa/type.go index ffec59b9..dc5d20aa 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -39,6 +39,7 @@ const ( vkComplex vkString vkBool + vkPtr vkFunc vkTuple vkDelayExpr = -1 @@ -237,11 +238,11 @@ func (p Program) toLLVMType(typ types.Type) Type { case types.Complex128: case types.String: case types.UnsafePointer: - return &aType{p.tyVoidPtr(), typ, vkInvalid} + return &aType{p.tyVoidPtr(), typ, vkPtr} } case *types.Pointer: elem := p.Type(t.Elem()) - return &aType{llvm.PointerType(elem.ll, 0), typ, vkInvalid} + return &aType{llvm.PointerType(elem.ll, 0), typ, vkPtr} case *types.Interface: return &aType{p.rtIface(), typ, vkInvalid} case *types.Slice: From 510f2f4769d39ea09a26059fa0467dd898764442 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 28 Apr 2024 07:08:33 +0800 Subject: [PATCH 3/8] runtime: Alloc --- internal/runtime/z_gc.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 internal/runtime/z_gc.go diff --git a/internal/runtime/z_gc.go b/internal/runtime/z_gc.go new file mode 100644 index 00000000..1aae6025 --- /dev/null +++ b/internal/runtime/z_gc.go @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package runtime + +import "unsafe" + +const ( + LLGoPackage = true +) + +//go:linkname Malloc C.malloc +func Malloc(size uintptr) unsafe.Pointer + +// Alloc allocates memory. +func Alloc(size uintptr) unsafe.Pointer { + return Malloc(size) +} From 7039cb3bc2ff9a0908241a0c451e85e4b85bfe35 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 28 Apr 2024 09:55:54 +0800 Subject: [PATCH 4/8] llgo/ssa: support string/cstring; panic --- cl/compile.go | 3 +++ internal/runtime/z_slice.go | 4 +++- internal/runtime/z_string.go | 37 ++++++++++++++++++++++++++++++++++ ssa/expr.go | 23 ++++++++++++++++++--- ssa/package.go | 39 +++++++++++++++++++++++++++++++++--- ssa/stmt_builder.go | 9 +++++++++ ssa/type.go | 1 + 7 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 internal/runtime/z_string.go diff --git a/cl/compile.go b/cl/compile.go index 3a4fd9fa..e6a5ed3d 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -387,6 +387,9 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) { thenb := fn.Block(succs[0].Index) elseb := fn.Block(succs[1].Index) b.If(cond, thenb, elseb) + case *ssa.Panic: + arg := p.compileValue(b, v.X).Do() + b.Panic(arg) default: panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr)) } diff --git a/internal/runtime/z_slice.go b/internal/runtime/z_slice.go index b6d5cbf5..a3f59f6d 100644 --- a/internal/runtime/z_slice.go +++ b/internal/runtime/z_slice.go @@ -16,8 +16,10 @@ package runtime +// Slice is the runtime representation of a slice. type Slice = slice -func MakeEmptySlice() Slice { +// NilSlice returns a nil slice. +func NilSlice() Slice { return Slice{nil, 0, 0} } diff --git a/internal/runtime/z_string.go b/internal/runtime/z_string.go new file mode 100644 index 00000000..ed8ca0c1 --- /dev/null +++ b/internal/runtime/z_string.go @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package runtime + +import ( + "unsafe" +) + +// String is the runtime representation of a string. +// It cannot be used safely or portably and its representation may +// change in a later release. +// +// Unlike reflect.StringHeader, its Data field is sufficient to guarantee the +// data it references will not be garbage collected. +type String struct { + data unsafe.Pointer + len int +} + +// EmptyString returns an empty string. +func EmptyString() String { + return String{nil, 0} +} diff --git a/ssa/expr.go b/ssa/expr.go index eda2c4dc..b1a2fe54 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -82,6 +82,20 @@ func (p Program) Null(t Type) Expr { return Expr{llvm.ConstNull(t.ll), t} } +// CStringVal returns a c-style string constant expression. +func (p Program) CStringVal(v string) Expr { + t := p.CString() + return Expr{llvm.ConstString(v, true), t} +} + +// StringVal returns string constant expression. +func (p Program) StringVal(v string) Expr { + t := p.String() + cstr := llvm.ConstString(v, true) + // TODO(xsw): cstr => gostring + return Expr{cstr, t} +} + // BoolVal returns a boolean constant expression. func (p Program) BoolVal(v bool) Expr { t := p.Bool() @@ -118,19 +132,22 @@ func (p Program) Val(v interface{}) Expr { // Const returns a constant expression. func (b Builder) Const(v constant.Value, typ Type) Expr { + prog := b.prog if v == nil { - return b.prog.Null(typ) + return prog.Null(typ) } switch t := typ.t.(type) { case *types.Basic: kind := t.Kind() switch { case kind == types.Bool: - return b.prog.BoolVal(constant.BoolVal(v)) + return prog.BoolVal(constant.BoolVal(v)) case kind >= types.Int && kind <= types.Uintptr: if v, exact := constant.Uint64Val(v); exact { - return b.prog.IntVal(v, typ) + return prog.IntVal(v, typ) } + case kind == types.String: + return prog.StringVal(constant.StringVal(v)) } } panic("todo") diff --git a/ssa/package.go b/ssa/package.go index cd63b986..edddc5c6 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -110,12 +110,15 @@ type aProgram struct { voidType llvm.Type voidPtrTy llvm.Type - rtIfaceTy llvm.Type - rtSliceTy llvm.Type + rtStringTy llvm.Type + rtIfaceTy llvm.Type + rtSliceTy llvm.Type anyTy Type voidTy Type boolTy Type + cstrTy Type + stringTy Type uintptrTy Type intTy Type f64Ty Type @@ -170,6 +173,13 @@ func (p Program) rtSlice() llvm.Type { return p.rtSliceTy } +func (p Program) rtString() llvm.Type { + if p.rtStringTy.IsNil() { + p.rtStringTy = p.rtType("String").ll + } + return p.rtStringTy +} + // NewPackage creates a new package. func (p Program) NewPackage(name, pkgPath string) Package { mod := p.ctx.NewModule(pkgPath) @@ -177,7 +187,7 @@ func (p Program) NewPackage(name, pkgPath string) Package { // mod.Finalize() fns := make(map[string]Function) gbls := make(map[string]Global) - return &aPackage{mod, fns, gbls, p} + return &aPackage{mod, fns, gbls, p, nil} } // Void returns void type. @@ -196,6 +206,20 @@ func (p Program) Bool() Type { return p.boolTy } +func (p Program) CString() Type { + if p.cstrTy == nil { // *int8 + p.cstrTy = p.Type(types.NewPointer(types.Typ[types.Int8])) + } + return p.cstrTy +} + +func (p Program) String() Type { + if p.stringTy == nil { + p.stringTy = p.Type(types.Typ[types.String]) + } + return p.stringTy +} + // Any returns any type. func (p Program) Any() Type { if p.anyTy == nil { @@ -243,6 +267,8 @@ type aPackage struct { fns map[string]Function vars map[string]Global prog Program + + abort Function } type Package = *aPackage @@ -280,6 +306,13 @@ func (p Package) FuncOf(name string) Function { return p.fns[name] } +func (p Package) rtAbort() Function { + if p.abort == nil { + p.abort = p.NewFunc("abort", types.NewSignatureType(nil, nil, nil, nil, nil, false)) + } + return p.abort +} + func (p Package) rtFunc(fnName string) Expr { fn := p.prog.runtime().Lookup(fnName).(*types.Func) name := FullName(fn.Pkg(), fnName) diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index a5e2f1f2..9b165cfb 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -68,6 +68,15 @@ func (b Builder) SetBlock(blk BasicBlock) Builder { return b } +// Panic emits a panic instruction. +func (b Builder) Panic(v Expr) { + if debugInstr { + log.Printf("Panic %v\n", v.impl) + } + pkg := b.fn.pkg + b.Call(pkg.rtAbort().Expr) +} + // Return emits a return instruction. func (b Builder) Return(results ...Expr) { if debugInstr { diff --git a/ssa/type.go b/ssa/type.go index dc5d20aa..fed294c7 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -237,6 +237,7 @@ func (p Program) toLLVMType(typ types.Type) Type { case types.Complex64: case types.Complex128: case types.String: + return &aType{p.rtString(), typ, vkString} case types.UnsafePointer: return &aType{p.tyVoidPtr(), typ, vkPtr} } From 0d68066086ce79444efcf19b9f44b2bcbc38f240 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 28 Apr 2024 10:29:06 +0800 Subject: [PATCH 5/8] runtime: MakeAnyString --- cl/compile.go | 16 +++++++--------- internal/runtime/z_iface.go | 7 +++++++ internal/runtime/z_type.go | 2 ++ ssa/expr.go | 18 +++++++++++------- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/cl/compile.go b/cl/compile.go index e6a5ed3d..086408cb 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -245,14 +245,12 @@ func (p *context) isVArgs(vx ssa.Value) (ret []llssa.Expr, ok bool) { return } -func (p *context) checkVArgs(v *ssa.Alloc, t types.Type) bool { +func (p *context) checkVArgs(v *ssa.Alloc, t *types.Pointer) bool { if v.Comment == "varargs" { // this is a varargs allocation - if t, ok := t.(*types.Pointer); ok { - if arr, ok := t.Elem().(*types.Array); ok { - if isAny(arr.Elem()) { - p.vargs[v] = make([]llssa.Expr, arr.Len()) - return true - } + if arr, ok := t.Elem().(*types.Array); ok { + if isAny(arr.Elem()) { + p.vargs[v] = make([]llssa.Expr, arr.Len()) + return true } } } @@ -322,11 +320,11 @@ func (p *context) compileInstrAndValue(b llssa.Builder, iv instrAndValue) (ret l } panic("todo") case *ssa.Alloc: - t := v.Type() + t := v.Type().(*types.Pointer) if p.checkVArgs(v, t) { // varargs: this is a varargs allocation return } - ret = b.Alloc(p.prog.Type(t), v.Heap) + ret = b.Alloc(t, v.Heap) case *ssa.MakeInterface: const ( delayExpr = true // varargs: don't need to convert an expr to any diff --git a/internal/runtime/z_iface.go b/internal/runtime/z_iface.go index e2a07fea..a8ed5590 100644 --- a/internal/runtime/z_iface.go +++ b/internal/runtime/z_iface.go @@ -37,6 +37,13 @@ func MakeAnyInt(typ *Type, data uintptr) Interface { } } +func MakeAnyString(data string) Interface { + return Interface{ + tab: &itab{inter: TyAny, _type: Basic(abi.String), hash: 0, fun: [1]uintptr{0}}, + data: unsafe.Pointer(&data), + } +} + func MakeAny(typ *Type, data unsafe.Pointer) Interface { return Interface{ tab: &itab{inter: TyAny, _type: typ, hash: 0, fun: [1]uintptr{0}}, diff --git a/internal/runtime/z_type.go b/internal/runtime/z_type.go index 02b31b2d..3e8adb26 100644 --- a/internal/runtime/z_type.go +++ b/internal/runtime/z_type.go @@ -47,6 +47,7 @@ var ( abi.Float64: basicType(abi.Float64), abi.Complex64: basicType(abi.Complex64), abi.Complex128: basicType(abi.Complex128), + abi.String: basicType(abi.String), } ) @@ -68,6 +69,7 @@ var ( abi.Float64: 8, abi.Complex64: 8, abi.Complex128: 16, + abi.String: unsafe.Sizeof(String{}), } ) diff --git a/ssa/expr.go b/ssa/expr.go index b1a2fe54..165f1a21 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -403,20 +403,21 @@ func (b Builder) IndexAddr(x, idx Expr) Expr { // // t0 = local int // t1 = new int -func (b Builder) Alloc(t Type, heap bool) (ret Expr) { +func (b Builder) Alloc(t *types.Pointer, heap bool) (ret Expr) { if debugInstr { - log.Printf("Alloc %v, %v\n", t.t, heap) + log.Printf("Alloc %v, %v\n", t, heap) } - telem := b.prog.Elem(t) + prog := b.prog + telem := t.Elem() if heap { - ret.impl = llvm.CreateAlloca(b.impl, telem.ll) + ret.impl = llvm.CreateAlloca(b.impl, prog.Type(telem).ll) } else { pkg := b.fn.pkg - size := unsafe.Sizeof(t.t) - ret = b.Call(pkg.rtFunc("Alloc"), b.prog.Val(size)) + size := unsafe.Sizeof(telem) + ret = b.Call(pkg.rtFunc("Alloc"), prog.Val(size)) } // TODO(xsw): zero-initialize - ret.Type = t + ret.Type = prog.Type(t) return } @@ -535,6 +536,9 @@ func (b Builder) MakeInterface(inter types.Type, x Expr, mayDelay bool) (ret Exp case vkSigned, vkUnsigned, vkFloat: fn := pkg.rtFunc("MakeAnyInt") return b.InlineCall(fn, x) + case vkString: + fn := pkg.rtFunc("MakeAnyString") + return b.InlineCall(fn, x) } panic("todo") } From eb4146d80deda77b95b2b3655d831df52862b24c Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 28 Apr 2024 10:39:11 +0800 Subject: [PATCH 6/8] llgo/ssa: Alloc bugfix (heap) --- ssa/expr.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssa/expr.go b/ssa/expr.go index 165f1a21..108c2d3e 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -410,11 +410,11 @@ func (b Builder) Alloc(t *types.Pointer, heap bool) (ret Expr) { prog := b.prog telem := t.Elem() if heap { - ret.impl = llvm.CreateAlloca(b.impl, prog.Type(telem).ll) - } else { pkg := b.fn.pkg size := unsafe.Sizeof(telem) ret = b.Call(pkg.rtFunc("Alloc"), prog.Val(size)) + } else { + ret.impl = llvm.CreateAlloca(b.impl, prog.Type(telem).ll) } // TODO(xsw): zero-initialize ret.Type = prog.Type(t) From 2cc1bdee19a562b307b04ab1de71d30b0a9e478b Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 28 Apr 2024 12:09:47 +0800 Subject: [PATCH 7/8] llgo/ssa: pkg.NewFunc bugfix --- cl/_testcgo/struct/in.go | 2 +- cl/_testcgo/struct/out.ll | 27 +++++++++++++++++++-------- cl/_testcgo/typalias/out.ll | 4 +++- cl/cltest/cltest.go | 13 ++++++++++++- cl/compile_test.go | 6 ++++++ internal/llgen/llgenf.go | 8 ++++---- internal/runtime/iface.go | 5 ----- internal/runtime/slice.go | 15 --------------- internal/runtime/z_slice.go | 10 +++++++++- ssa/package.go | 20 +++++++------------- ssa/stmt_builder.go | 2 +- ssa/type.go | 5 +++-- 12 files changed, 65 insertions(+), 52 deletions(-) delete mode 100644 internal/runtime/iface.go delete mode 100644 internal/runtime/slice.go diff --git a/cl/_testcgo/struct/in.go b/cl/_testcgo/struct/in.go index 74aad81a..71cdeb09 100644 --- a/cl/_testcgo/struct/in.go +++ b/cl/_testcgo/struct/in.go @@ -13,7 +13,7 @@ type Foo struct { var format = [...]int8{'H', 'e', 'l', 'l', 'o', ' ', '%', 'd', '\n', 0} -func (p *Foo) Print() { +func (p Foo) Print() { if p.ok { printf(&format[0], p.A) } diff --git a/cl/_testcgo/struct/out.ll b/cl/_testcgo/struct/out.ll index 5142a659..002f5000 100644 --- a/cl/_testcgo/struct/out.ll +++ b/cl/_testcgo/struct/out.ll @@ -6,22 +6,32 @@ source_filename = "main" @main.format = global ptr null @"main.init$guard" = global ptr null -define void @"(*main.Foo).Print"(ptr %0) { +define void @"(main.Foo).Print"(%main.Foo %0) { _llgo_0: - %1 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 1 - %2 = load i1, ptr %1, align 1 - br i1 %2, label %_llgo_1, label %_llgo_2 + %1 = alloca %main.Foo, align 8 + store %main.Foo %0, ptr %1, align 4 + %2 = getelementptr inbounds %main.Foo, ptr %1, i32 0, i32 1 + %3 = load i1, ptr %2, align 1 + br i1 %3, label %_llgo_1, label %_llgo_2 _llgo_1: ; preds = %_llgo_0 - %3 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 0 - %4 = load i32, ptr %3, align 4 - call void (ptr, ...) @printf(ptr @main.format, i32 %4) + %4 = alloca %main.Foo, align 8 + %5 = getelementptr inbounds %main.Foo, ptr %4, i32 0, i32 0 + %6 = load i32, ptr %5, align 4 + call void (ptr, ...) @printf(ptr @main.format, i32 %6) br label %_llgo_2 _llgo_2: ; preds = %_llgo_1, %_llgo_0 ret void } +define void @"(*main.Foo).Print"(ptr %0) { +_llgo_0: + %1 = load %main.Foo, ptr %0, align 4 + call void @"(main.Foo).Print"(%main.Foo %1) + ret void +} + define void @main.init() { _llgo_0: %0 = load i1, ptr @"main.init$guard", align 1 @@ -53,7 +63,8 @@ _llgo_0: %2 = getelementptr inbounds %main.Foo, ptr %0, i32 0, i32 1 store i32 100, ptr %1, align 4 store i1 true, ptr %2, align 1 - call void @"(*main.Foo).Print"(ptr %0) + %3 = load %main.Foo, ptr %0, align 4 + call void @"(main.Foo).Print"(%main.Foo %3) ret void } diff --git a/cl/_testcgo/typalias/out.ll b/cl/_testcgo/typalias/out.ll index dac39a22..3e2d16f8 100644 --- a/cl/_testcgo/typalias/out.ll +++ b/cl/_testcgo/typalias/out.ll @@ -46,7 +46,7 @@ _llgo_2: ; preds = %_llgo_1, %_llgo_0 define void @main() { _llgo_0: call void @main.init() - %0 = alloca { i32, i1 }, align 8 + %0 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) %1 = getelementptr inbounds { i32, i1 }, ptr %0, i32 0, i32 0 %2 = getelementptr inbounds { i32, i1 }, ptr %0, i32 0, i32 1 store i32 100, ptr %1, align 4 @@ -56,3 +56,5 @@ _llgo_0: } declare void @printf(ptr, ...) + +declare ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64) diff --git a/cl/cltest/cltest.go b/cl/cltest/cltest.go index bc6900e8..8ef858f1 100644 --- a/cl/cltest/cltest.go +++ b/cl/cltest/cltest.go @@ -63,6 +63,17 @@ func FromDir(t *testing.T, sel, relDir string, byLLGen bool) { } } +func Pkg(t *testing.T, pkgPath, outFile string) { + b, err := os.ReadFile(outFile) + if err != nil { + t.Fatal("ReadFile failed:", err) + } + expected := string(b) + if v := llgen.GenFrom(pkgPath); v != expected { + t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected) + } +} + func testFrom(t *testing.T, pkgDir, sel string, byLLGen bool) { if sel != "" && !strings.Contains(pkgDir, sel) { return @@ -76,7 +87,7 @@ func testFrom(t *testing.T, pkgDir, sel string, byLLGen bool) { } expected := string(b) if byLLGen { - if v := llgen.GenFromFile(in); v != expected { + if v := llgen.GenFrom(in); v != expected { t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected) } } else { diff --git a/cl/compile_test.go b/cl/compile_test.go index 671f8cba..1acd3786 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -35,6 +35,12 @@ func TestFromTestdata(t *testing.T) { cltest.FromDir(t, "", "./_testdata", false) } +/* +func TestRuntime(t *testing.T) { + cltest.Pkg(t, "github.com/goplus/llgo/internal/runtime", "../internal/runtime/llgo_autogen.ll") +} +*/ + func TestVar(t *testing.T) { testCompile(t, `package foo diff --git a/internal/llgen/llgenf.go b/internal/llgen/llgenf.go index 203ed23e..b8bc71cb 100644 --- a/internal/llgen/llgenf.go +++ b/internal/llgen/llgenf.go @@ -35,11 +35,11 @@ const ( loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo ) -func GenFromFile(inFile string) string { +func GenFrom(fileOrPkg string) string { cfg := &packages.Config{ Mode: loadSyntax, } - initial, err := packages.Load(cfg, inFile) + initial, err := packages.Load(cfg, fileOrPkg) check(err) _, pkgs := ssautil.AllPackages(initial, ssa.SanityCheckFunctions) @@ -61,8 +61,8 @@ func GenFromFile(inFile string) string { return ret.String() } -func DoFile(inFile, outFile string) { - ret := GenFromFile(inFile) +func DoFile(fileOrPkg, outFile string) { + ret := GenFrom(fileOrPkg) err := os.WriteFile(outFile, []byte(ret), 0644) check(err) } diff --git a/internal/runtime/iface.go b/internal/runtime/iface.go deleted file mode 100644 index 47bf8fc2..00000000 --- a/internal/runtime/iface.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime diff --git a/internal/runtime/slice.go b/internal/runtime/slice.go deleted file mode 100644 index 21caa126..00000000 --- a/internal/runtime/slice.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "unsafe" -) - -type slice struct { - array unsafe.Pointer - len int - cap int -} diff --git a/internal/runtime/z_slice.go b/internal/runtime/z_slice.go index a3f59f6d..4a8e0e40 100644 --- a/internal/runtime/z_slice.go +++ b/internal/runtime/z_slice.go @@ -16,8 +16,16 @@ package runtime +import ( + "unsafe" +) + // Slice is the runtime representation of a slice. -type Slice = slice +type Slice struct { + array unsafe.Pointer + len int + cap int +} // NilSlice returns a nil slice. func NilSlice() Slice { diff --git a/ssa/package.go b/ssa/package.go index edddc5c6..55c09666 100644 --- a/ssa/package.go +++ b/ssa/package.go @@ -187,7 +187,7 @@ func (p Program) NewPackage(name, pkgPath string) Package { // mod.Finalize() fns := make(map[string]Function) gbls := make(map[string]Global) - return &aPackage{mod, fns, gbls, p, nil} + return &aPackage{mod, fns, gbls, p} } // Void returns void type. @@ -267,8 +267,6 @@ type aPackage struct { fns map[string]Function vars map[string]Global prog Program - - abort Function } type Package = *aPackage @@ -294,6 +292,9 @@ func (p Package) VarOf(name string) Global { // NewFunc creates a new function. func (p Package) NewFunc(name string, sig *types.Signature) Function { + if v, ok := p.fns[name]; ok { + return v + } t := p.prog.llvmSignature(sig) fn := llvm.AddFunction(p.mod, name, t.ll) ret := newFunction(fn, t, p, p.prog) @@ -306,21 +307,14 @@ func (p Package) FuncOf(name string) Function { return p.fns[name] } -func (p Package) rtAbort() Function { - if p.abort == nil { - p.abort = p.NewFunc("abort", types.NewSignatureType(nil, nil, nil, nil, nil, false)) - } - return p.abort +func (p Package) rtAbort() Expr { + return p.NewFunc("abort", types.NewSignatureType(nil, nil, nil, nil, nil, false)).Expr } func (p Package) rtFunc(fnName string) Expr { fn := p.prog.runtime().Lookup(fnName).(*types.Func) name := FullName(fn.Pkg(), fnName) - v, ok := p.fns[name] - if !ok { - v = p.NewFunc(name, fn.Type().(*types.Signature)) - } - return v.Expr + return p.NewFunc(name, fn.Type().(*types.Signature)).Expr } // ----------------------------------------------------------------------------- diff --git a/ssa/stmt_builder.go b/ssa/stmt_builder.go index 9b165cfb..d3a922d5 100644 --- a/ssa/stmt_builder.go +++ b/ssa/stmt_builder.go @@ -74,7 +74,7 @@ func (b Builder) Panic(v Expr) { log.Printf("Panic %v\n", v.impl) } pkg := b.fn.pkg - b.Call(pkg.rtAbort().Expr) + b.Call(pkg.rtAbort()) // TODO(xsw): pass v } // Return emits a return instruction. diff --git a/ssa/type.go b/ssa/type.go index fed294c7..f265d215 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -123,6 +123,9 @@ func (p Program) Field(typ Type, i int) Type { } func (p Program) Type(typ types.Type) Type { + if sig, ok := typ.(*types.Signature); ok { // should methodToFunc + return p.llvmSignature(sig) + } if v := p.typs.At(typ); v != nil { return v.(Type) } @@ -253,8 +256,6 @@ func (p Program) toLLVMType(typ types.Type) Type { return p.toLLVMStruct(t) case *types.Named: return p.toLLVMNamed(t) - case *types.Signature: - return p.toLLVMFunc(t) case *types.Array: elem := p.Type(t.Elem()) return &aType{llvm.ArrayType(elem.ll, int(t.Len())), typ, vkInvalid} From 41dfafe957b4a6a48bb71c2eedcfaf4983dd19ad Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 28 Apr 2024 12:22:56 +0800 Subject: [PATCH 8/8] TestRuntime --- cl/compile_test.go | 2 - internal/runtime/llgo_autogen.ll | 404 +++++++++++++++++++++++++++++++ ssa/cl_test.go | 4 + 3 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 internal/runtime/llgo_autogen.ll diff --git a/cl/compile_test.go b/cl/compile_test.go index 1acd3786..1ac09e2c 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -35,11 +35,9 @@ func TestFromTestdata(t *testing.T) { cltest.FromDir(t, "", "./_testdata", false) } -/* func TestRuntime(t *testing.T) { cltest.Pkg(t, "github.com/goplus/llgo/internal/runtime", "../internal/runtime/llgo_autogen.ll") } -*/ func TestVar(t *testing.T) { testCompile(t, `package foo diff --git a/internal/runtime/llgo_autogen.ll b/internal/runtime/llgo_autogen.ll new file mode 100644 index 00000000..8ba70e36 --- /dev/null +++ b/internal/runtime/llgo_autogen.ll @@ -0,0 +1,404 @@ +; ModuleID = 'github.com/goplus/llgo/internal/runtime' +source_filename = "github.com/goplus/llgo/internal/runtime" + +%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr } +%"github.com/goplus/llgo/internal/runtime.itab" = type { ptr, ptr, i32, [4 x i8], [1 x i64] } +%"github.com/goplus/llgo/internal/runtime.String" = type { ptr, i64 } +%"github.com/goplus/llgo/internal/abi.InterfaceType" = type { %"github.com/goplus/llgo/internal/abi.Type", %"github.com/goplus/llgo/internal/abi.Name", %"github.com/goplus/llgo/internal/runtime.Slice" } +%"github.com/goplus/llgo/internal/abi.Type" = type { i64, i64, i32, i8, i8, i8, i8, i1 (ptr, ptr), ptr, i32, i32 } +%"github.com/goplus/llgo/internal/abi.Name" = type { ptr } +%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 } +%"github.com/goplus/llgo/internal/runtime.String.0" = type { ptr, i64 } +%"github.com/goplus/llgo/internal/runtime.Slice.1" = type { ptr, i64, i64 } + +@"github.com/goplus/llgo/internal/runtime.TyAny" = global ptr null +@"github.com/goplus/llgo/internal/runtime.basicTypes" = global ptr null +@"github.com/goplus/llgo/internal/runtime.init$guard" = global ptr null +@"github.com/goplus/llgo/internal/runtime.sizeBasicTypes" = global ptr null + +define ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 %0) { +_llgo_0: + %1 = call ptr @malloc(i64 %0) + ret ptr %1 +} + +define ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 %0) { +_llgo_0: + %1 = getelementptr inbounds ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 %0 + %2 = load ptr, ptr %1, align 8 + ret ptr %2 +} + +define { i64, i1 } @"github.com/goplus/llgo/internal/runtime.CheckI2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %1) { +_llgo_0: + %2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 + store %"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %2, align 8 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0 + %4 = load ptr, ptr %3, align 8 + %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1 + %6 = load ptr, ptr %5, align 8 + %7 = icmp eq ptr %6, %1 + br i1 %7, label %_llgo_1, label %_llgo_2 + +_llgo_1: ; preds = %_llgo_0 + %8 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 + %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %8, i32 0, i32 1 + %10 = load ptr, ptr %9, align 8 + %castInt = sext ptr %10 to i64 + %mrv = insertvalue { i64, i1 } poison, i64 %castInt, 0 + %mrv1 = insertvalue { i64, i1 } %mrv, i1 true, 1 + ret { i64, i1 } %mrv1 + +_llgo_2: ; preds = %_llgo_0 + ret { i64, i1 } zeroinitializer +} + +define %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.EmptyString"() { +_llgo_0: + %0 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8 + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 0 + %2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %0, i32 0, i32 1 + store ptr null, ptr %1, align 8 + store i64 0, ptr %2, align 4 + %3 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %0, align 8 + ret %"github.com/goplus/llgo/internal/runtime.String" %3 +} + +define i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %1) { +_llgo_0: + %2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 + store %"github.com/goplus/llgo/internal/runtime.iface" %0, ptr %2, align 8 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0 + %4 = load ptr, ptr %3, align 8 + %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1 + %6 = load ptr, ptr %5, align 8 + %7 = icmp eq ptr %6, %1 + br i1 %7, label %_llgo_1, label %_llgo_2 + +_llgo_1: ; preds = %_llgo_0 + %8 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 + %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %8, i32 0, i32 1 + %10 = load ptr, ptr %9, align 8 + %castInt = sext ptr %10 to i64 + ret i64 %castInt + +_llgo_2: ; preds = %_llgo_0 + %11 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyString"([21 x i8] c"I2Int: type mismatch\00") + call void @abort() +} + +define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).ArrayType"(ptr %0) { +_llgo_0: + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %1) + ret ptr %2 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %4 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr %3) + ret ptr %4 + +_llgo_01: ; No predecessors! +} + +define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).Common"(ptr %0) { +_llgo_0: + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %1) + ret ptr %2 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %4 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr %3) + ret ptr %4 + +_llgo_01: ; No predecessors! +} + +define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).Elem"(ptr %0) { +_llgo_0: + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Elem"(ptr %1) + ret ptr %2 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %4 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).Elem"(ptr %3) + ret ptr %4 + +_llgo_01: ; No predecessors! +} + +define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).FuncType"(ptr %0) { +_llgo_0: + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %1) + ret ptr %2 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %4 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr %3) + ret ptr %4 + +_llgo_01: ; No predecessors! +} + +define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).InterfaceType"(ptr %0) { +_llgo_0: + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %1) + ret ptr %2 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %4 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr %3) + ret ptr %4 + +_llgo_01: ; No predecessors! +} + +define i64 @"(*github.com/goplus/llgo/internal/abi.InterfaceType).Kind"(ptr %0) { +_llgo_0: + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %1) + ret i64 %2 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %4 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr %3) + ret i64 %4 + +_llgo_01: ; No predecessors! +} + +define i64 @"(*github.com/goplus/llgo/internal/abi.InterfaceType).Len"(ptr %0) { +_llgo_0: + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %2 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr %1) + ret i64 %2 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %4 = call i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr %3) + ret i64 %4 + +_llgo_01: ; No predecessors! +} + +define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).MapType"(ptr %0) { +_llgo_0: + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %1) + ret ptr %2 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %4 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr %3) + ret ptr %4 + +_llgo_01: ; No predecessors! +} + +define ptr @"(*github.com/goplus/llgo/internal/abi.InterfaceType).StructType"(ptr %0) { +_llgo_0: + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %2 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %1) + ret ptr %2 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.InterfaceType", ptr %0, i32 0, i32 0 + %4 = call ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr %3) + ret ptr %4 + +_llgo_01: ; No predecessors! +} + +define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAny"(ptr %0, ptr %1) { +_llgo_0: + %2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0 + %4 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) + %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 0 + %6 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8 + %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1 + %8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 2 + %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 4 + %10 = getelementptr inbounds i64, ptr %9, i64 0 + store ptr %6, ptr %5, align 8 + store ptr %0, ptr %7, align 8 + store i32 0, ptr %8, align 4 + store i64 0, ptr %10, align 4 + %11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 1 + store ptr %4, ptr %3, align 8 + store ptr %1, ptr %11, align 8 + %12 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, align 8 + ret %"github.com/goplus/llgo/internal/runtime.iface" %12 +} + +define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %0, i64 %1) { +_llgo_0: + %2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0 + %4 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) + %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 0 + %6 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8 + %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1 + %8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 2 + %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 4 + %10 = getelementptr inbounds i64, ptr %9, i64 0 + store ptr %6, ptr %5, align 8 + store ptr %0, ptr %7, align 8 + store i32 0, ptr %8, align 4 + store i64 0, ptr %10, align 4 + %11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 1 + %castPtr = addrspacecast i64 %1 to ptr + store ptr %4, ptr %3, align 8 + store ptr %castPtr, ptr %11, align 8 + %12 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, align 8 + ret %"github.com/goplus/llgo/internal/runtime.iface" %12 +} + +define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyString"(%"github.com/goplus/llgo/internal/runtime.String.0" %0) { +_llgo_0: + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) + store %"github.com/goplus/llgo/internal/runtime.String.0" %0, ptr %1, align 8 + %2 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 0 + %4 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) + %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 0 + %6 = load ptr, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8 + %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 1 + %8 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 24) + %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 2 + %10 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %4, i32 0, i32 4 + %11 = getelementptr inbounds i64, ptr %10, i64 0 + store ptr %6, ptr %5, align 8 + store ptr %8, ptr %7, align 8 + store i32 0, ptr %9, align 4 + store i64 0, ptr %11, align 4 + %12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i32 0, i32 1 + store ptr %4, ptr %3, align 8 + store ptr %1, ptr %12, align 8 + %13 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, align 8 + ret %"github.com/goplus/llgo/internal/runtime.iface" %13 +} + +define %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeInterface"(ptr %0, ptr %1, ptr %2) { +_llgo_0: + %3 = alloca %"github.com/goplus/llgo/internal/runtime.iface", align 8 + %4 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %3, i32 0, i32 0 + %5 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) + %6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 0 + %7 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 1 + %8 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 2 + %9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.itab", ptr %5, i32 0, i32 4 + %10 = getelementptr inbounds i64, ptr %9, i64 0 + store ptr %0, ptr %6, align 8 + store ptr %1, ptr %7, align 8 + store i32 0, ptr %8, align 4 + store i64 0, ptr %10, align 4 + %11 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %3, i32 0, i32 1 + store ptr %5, ptr %4, align 8 + store ptr %2, ptr %11, align 8 + %12 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %3, align 8 + ret %"github.com/goplus/llgo/internal/runtime.iface" %12 +} + +declare ptr @malloc(i64) + +define %"github.com/goplus/llgo/internal/runtime.Slice.1" @"github.com/goplus/llgo/internal/runtime.NilSlice"() { +_llgo_0: + %0 = alloca %"github.com/goplus/llgo/internal/runtime.Slice.1", align 8 + %1 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice.1", ptr %0, i32 0, i32 0 + %2 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice.1", ptr %0, i32 0, i32 1 + %3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice.1", ptr %0, i32 0, i32 2 + store ptr null, ptr %1, align 8 + store i64 0, ptr %2, align 4 + store i64 0, ptr %3, align 4 + %4 = load %"github.com/goplus/llgo/internal/runtime.Slice.1", ptr %0, align 8 + ret %"github.com/goplus/llgo/internal/runtime.Slice.1" %4 +} + +declare ptr @"(*github.com/goplus/llgo/internal/abi.Type).ArrayType"(ptr) + +declare ptr @"(*github.com/goplus/llgo/internal/abi.Type).Common"(ptr) + +declare ptr @"(*github.com/goplus/llgo/internal/abi.Type).Elem"(ptr) + +declare ptr @"(*github.com/goplus/llgo/internal/abi.Type).FuncType"(ptr) + +declare ptr @"(*github.com/goplus/llgo/internal/abi.Type).InterfaceType"(ptr) + +declare i64 @"(*github.com/goplus/llgo/internal/abi.Type).Kind"(ptr) + +declare i64 @"(*github.com/goplus/llgo/internal/abi.Type).Len"(ptr) + +declare ptr @"(*github.com/goplus/llgo/internal/abi.Type).MapType"(ptr) + +declare ptr @"(*github.com/goplus/llgo/internal/abi.Type).StructType"(ptr) + +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) + %2 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %1, i32 0, i32 0 + %3 = getelementptr inbounds i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 %0 + %4 = load i64, ptr %3, align 4 + %5 = getelementptr inbounds %"github.com/goplus/llgo/internal/abi.Type", ptr %1, i32 0, i32 6 + %castInt = trunc i64 %0 to i8 + store i64 %4, ptr %2, align 4 + store i8 %castInt, ptr %5, align 1 + ret ptr %1 +} + +define void @"github.com/goplus/llgo/internal/runtime.init"() { +_llgo_0: + %0 = load i1, ptr @"github.com/goplus/llgo/internal/runtime.init$guard", align 1 + br i1 %0, label %_llgo_2, label %_llgo_1 + +_llgo_1: ; preds = %_llgo_0 + store i1 true, ptr @"github.com/goplus/llgo/internal/runtime.init$guard", align 1 + call void @"github.com/goplus/llgo/internal/abi.init"() + %1 = call ptr @"github.com/goplus/llgo/internal/runtime.Alloc"(i64 16) + store ptr %1, ptr @"github.com/goplus/llgo/internal/runtime.TyAny", align 8 + store i64 1, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 1), align 4 + store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 2), align 4 + store i64 1, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 3), align 4 + store i64 2, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 4), align 4 + store i64 4, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 5), align 4 + store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 6), align 4 + store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 7), align 4 + store i64 1, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 8), align 4 + store i64 2, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 9), align 4 + store i64 4, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 10), align 4 + store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 11), align 4 + store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 12), align 4 + store i64 4, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 13), align 4 + store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 14), align 4 + store i64 8, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 15), align 4 + store i64 16, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 16), align 4 + store i64 16, ptr getelementptr inbounds (i64, ptr @"github.com/goplus/llgo/internal/runtime.sizeBasicTypes", i64 24), align 4 + %2 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 1) + %3 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 2) + %4 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 3) + %5 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 4) + %6 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 5) + %7 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 6) + %8 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 7) + %9 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 8) + %10 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 9) + %11 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 10) + %12 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 11) + %13 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 12) + %14 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 13) + %15 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 14) + %16 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 15) + %17 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 16) + %18 = call ptr @"github.com/goplus/llgo/internal/runtime.basicType"(i64 24) + store ptr %2, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 1), align 8 + store ptr %3, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 2), align 8 + store ptr %4, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 3), align 8 + store ptr %5, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 4), align 8 + store ptr %6, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 5), align 8 + store ptr %7, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 6), align 8 + store ptr %8, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 7), align 8 + store ptr %9, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 8), align 8 + store ptr %10, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 9), align 8 + store ptr %11, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 10), align 8 + store ptr %12, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 11), align 8 + store ptr %13, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 12), align 8 + store ptr %14, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 13), align 8 + store ptr %15, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 14), align 8 + store ptr %16, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 15), align 8 + store ptr %17, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 16), align 8 + store ptr %18, ptr getelementptr inbounds (ptr, ptr @"github.com/goplus/llgo/internal/runtime.basicTypes", i64 24), align 8 + br label %_llgo_2 + +_llgo_2: ; preds = %_llgo_1, %_llgo_0 + ret void +} + +declare void @abort() + +declare void @"github.com/goplus/llgo/internal/abi.init"() diff --git a/ssa/cl_test.go b/ssa/cl_test.go index db26f209..bc215f6e 100644 --- a/ssa/cl_test.go +++ b/ssa/cl_test.go @@ -29,3 +29,7 @@ func TestFromTestcgo(t *testing.T) { func TestFromTestdata(t *testing.T) { cltest.FromDir(t, "", "../cl/_testdata", false) } + +func TestRuntime(t *testing.T) { + cltest.Pkg(t, "github.com/goplus/llgo/internal/runtime", "../internal/runtime/llgo_autogen.ll") +}