Merge pull request #66 from xushiwei/q

runtime
This commit is contained in:
xushiwei
2024-04-28 12:24:59 +08:00
committed by GitHub
20 changed files with 715 additions and 78 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
}
}
}
@@ -300,6 +298,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)
@@ -318,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
@@ -383,6 +385,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))
}

View File

@@ -35,6 +35,10 @@ 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

View File

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

View File

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

View File

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

View File

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

31
internal/runtime/z_gc.go Normal file
View File

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

View File

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

View File

@@ -16,8 +16,18 @@
package runtime
type Slice = slice
import (
"unsafe"
)
func MakeEmptySlice() Slice {
// Slice is the runtime representation of a slice.
type Slice struct {
array unsafe.Pointer
len int
cap int
}
// NilSlice returns a nil slice.
func NilSlice() Slice {
return Slice{nil, 0, 0}
}

View File

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

View File

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

View File

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

View File

@@ -23,6 +23,7 @@ import (
"go/token"
"go/types"
"log"
"unsafe"
"github.com/goplus/llvm"
)
@@ -76,10 +77,26 @@ 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}
}
// 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()
var bv uint64
@@ -90,15 +107,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,17 +130,24 @@ func (p Program) Val(v interface{}) Expr {
panic("todo")
}
// Const returns a constant expression.
func (b Builder) Const(v constant.Value, typ Type) Expr {
prog := b.prog
if v == nil {
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")
@@ -255,7 +283,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:
@@ -375,18 +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)
pkg := b.fn.pkg
size := unsafe.Sizeof(telem)
ret = b.Call(pkg.rtFunc("Alloc"), prog.Val(size))
} else {
panic("todo")
ret.impl = llvm.CreateAlloca(b.impl, prog.Type(telem).ll)
}
// TODO: zero-initialize
ret.Type = t
// TODO(xsw): zero-initialize
ret.Type = prog.Type(t)
return
}
@@ -410,9 +441,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 +450,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")
@@ -459,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")
}
@@ -534,6 +614,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...)
}

View File

@@ -110,14 +110,18 @@ 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
intTy Type
f64Ty Type
anyTy Type
voidTy Type
boolTy Type
cstrTy Type
stringTy Type
uintptrTy Type
intTy Type
f64Ty Type
}
// A Program presents a program.
@@ -169,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)
@@ -195,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 {
@@ -211,6 +236,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 {
@@ -259,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)
@@ -271,14 +307,14 @@ func (p Package) FuncOf(name string) Function {
return p.fns[name]
}
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
}
// -----------------------------------------------------------------------------

View File

@@ -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()) // TODO(xsw): pass v
}
// Return emits a return instruction.
func (b Builder) Return(results ...Expr) {
if debugInstr {

View File

@@ -39,6 +39,7 @@ const (
vkComplex
vkString
vkBool
vkPtr
vkFunc
vkTuple
vkDelayExpr = -1
@@ -122,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)
}
@@ -236,12 +240,13 @@ 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, 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:
@@ -251,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}