goroutine support; llgo/ssa: memory (malloc/free)
This commit is contained in:
12
c/c.go
12
c/c.go
@@ -63,6 +63,9 @@ func Unreachable()
|
|||||||
//go:linkname Malloc C.malloc
|
//go:linkname Malloc C.malloc
|
||||||
func Malloc(size uintptr) Pointer
|
func Malloc(size uintptr) Pointer
|
||||||
|
|
||||||
|
//go:linkname Free C.free
|
||||||
|
func Free(ptr Pointer)
|
||||||
|
|
||||||
//go:linkname Memcpy C.memcpy
|
//go:linkname Memcpy C.memcpy
|
||||||
func Memcpy(dst, src Pointer, n uintptr) Pointer
|
func Memcpy(dst, src Pointer, n uintptr) Pointer
|
||||||
|
|
||||||
@@ -115,11 +118,20 @@ func Fwrite(data Pointer, size, count uintptr, fp FilePtr) uintptr
|
|||||||
//go:linkname Fputc C.fputc
|
//go:linkname Fputc C.fputc
|
||||||
func Fputc(c Int, fp FilePtr) Int
|
func Fputc(c Int, fp FilePtr) Int
|
||||||
|
|
||||||
|
//go:linkname Fputs C.fputs
|
||||||
|
func Fputs(s *Char, fp FilePtr) Int
|
||||||
|
|
||||||
|
//go:linkname Fflush C.fflush
|
||||||
|
func Fflush(fp FilePtr) Int
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
//go:linkname Time C.time
|
//go:linkname Time C.time
|
||||||
func Time(*int32) int32
|
func Time(*int32) int32
|
||||||
|
|
||||||
|
//go:linkname Usleep C.usleep
|
||||||
|
func Usleep(useconds Uint) Int
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
type Option struct {
|
type Option struct {
|
||||||
|
|||||||
@@ -39,27 +39,29 @@ _llgo_0:
|
|||||||
%7 = getelementptr inbounds { ptr, ptr }, ptr %5, i32 0, i32 1
|
%7 = getelementptr inbounds { ptr, ptr }, ptr %5, i32 0, i32 1
|
||||||
store ptr %3, ptr %7, align 8
|
store ptr %3, ptr %7, align 8
|
||||||
%8 = load { ptr, ptr }, ptr %5, align 8
|
%8 = load { ptr, ptr }, ptr %5, align 8
|
||||||
%9 = extractvalue { ptr, ptr } %8, 1
|
%9 = call ptr @malloc(i64 16)
|
||||||
%10 = extractvalue { ptr, ptr } %8, 0
|
%10 = getelementptr inbounds { { ptr, ptr } }, ptr %9, i32 0, i32 0
|
||||||
call void %10(ptr %9)
|
store { ptr, ptr } %8, ptr %10, align 8
|
||||||
|
%11 = alloca i8, i64 8, align 1
|
||||||
|
%12 = call i32 @pthread_create(ptr %11, ptr null, ptr @"main._llgo_routine$1", ptr %9)
|
||||||
br label %_llgo_3
|
br label %_llgo_3
|
||||||
|
|
||||||
_llgo_1: ; preds = %_llgo_3
|
_llgo_1: ; preds = %_llgo_3
|
||||||
%11 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
%13 = alloca %"github.com/goplus/llgo/internal/runtime.String", align 8
|
||||||
%12 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %11, i32 0, i32 0
|
%14 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %13, i32 0, i32 0
|
||||||
store ptr @0, ptr %12, align 8
|
store ptr @0, ptr %14, align 8
|
||||||
%13 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %11, i32 0, i32 1
|
%15 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.String", ptr %13, i32 0, i32 1
|
||||||
store i64 1, ptr %13, align 4
|
store i64 1, ptr %15, align 4
|
||||||
%14 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %11, align 8
|
%16 = load %"github.com/goplus/llgo/internal/runtime.String", ptr %13, align 8
|
||||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %14)
|
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %16)
|
||||||
br label %_llgo_3
|
br label %_llgo_3
|
||||||
|
|
||||||
_llgo_2: ; preds = %_llgo_3
|
_llgo_2: ; preds = %_llgo_3
|
||||||
ret i32 0
|
ret i32 0
|
||||||
|
|
||||||
_llgo_3: ; preds = %_llgo_1, %_llgo_0
|
_llgo_3: ; preds = %_llgo_1, %_llgo_0
|
||||||
%15 = load i1, ptr %2, align 1
|
%17 = load i1, ptr %2, align 1
|
||||||
br i1 %15, label %_llgo_2, label %_llgo_1
|
br i1 %17, label %_llgo_2, label %_llgo_1
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
@@ -84,6 +86,23 @@ _llgo_0:
|
|||||||
|
|
||||||
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64)
|
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64)
|
||||||
|
|
||||||
|
declare ptr @malloc(i64)
|
||||||
|
|
||||||
|
define ptr @"main._llgo_routine$1"(ptr %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = load { { ptr, ptr } }, ptr %0, align 8
|
||||||
|
%2 = extractvalue { { ptr, ptr } } %1, 0
|
||||||
|
%3 = extractvalue { ptr, ptr } %2, 1
|
||||||
|
%4 = extractvalue { ptr, ptr } %2, 0
|
||||||
|
call void %4(ptr %3)
|
||||||
|
call void @free({ { ptr, ptr } } %1)
|
||||||
|
ret ptr null
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @free(ptr)
|
||||||
|
|
||||||
|
declare i32 @pthread_create(ptr, ptr, ptr, ptr)
|
||||||
|
|
||||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
|
||||||
|
|
||||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
|
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
|
||||||
|
|||||||
420
ssa/expr.go
420
ssa/expr.go
@@ -443,251 +443,6 @@ func (b Builder) UnOp(op token.Token, x Expr) (ret Expr) {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
func checkExpr(v Expr, t types.Type, b Builder) Expr {
|
|
||||||
if t, ok := t.(*types.Struct); ok && isClosure(t) {
|
|
||||||
if v.kind != vkClosure {
|
|
||||||
return b.Pkg.closureStub(b, t, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func needsNegativeCheck(x Expr) bool {
|
|
||||||
if x.kind == vkSigned {
|
|
||||||
if rv := x.impl.IsAConstantInt(); !rv.IsNil() && rv.SExtValue() >= 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func llvmParamsEx(data Expr, vals []Expr, params *types.Tuple, b Builder) (ret []llvm.Value) {
|
|
||||||
if data.IsNil() {
|
|
||||||
return llvmParams(0, vals, params, b)
|
|
||||||
}
|
|
||||||
ret = llvmParams(1, vals, params, b)
|
|
||||||
ret[0] = data.impl
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func llvmParams(base int, vals []Expr, params *types.Tuple, b Builder) (ret []llvm.Value) {
|
|
||||||
n := params.Len()
|
|
||||||
if n > 0 {
|
|
||||||
ret = make([]llvm.Value, len(vals)+base)
|
|
||||||
for idx, v := range vals {
|
|
||||||
i := base + idx
|
|
||||||
if i < n {
|
|
||||||
v = checkExpr(v, params.At(i).Type(), b)
|
|
||||||
}
|
|
||||||
ret[i] = v.impl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func llvmFields(vals []Expr, t *types.Struct, b Builder) (ret []llvm.Value) {
|
|
||||||
n := t.NumFields()
|
|
||||||
if n > 0 {
|
|
||||||
ret = make([]llvm.Value, len(vals))
|
|
||||||
for i, v := range vals {
|
|
||||||
if i < n {
|
|
||||||
v = checkExpr(v, t.Field(i).Type(), b)
|
|
||||||
}
|
|
||||||
ret[i] = v.impl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Advance returns the pointer ptr advanced by offset.
|
|
||||||
func (b Builder) Advance(ptr Expr, offset Expr) Expr {
|
|
||||||
if debugInstr {
|
|
||||||
log.Printf("Advance %v, %v\n", ptr.impl, offset.impl)
|
|
||||||
}
|
|
||||||
var elem llvm.Type
|
|
||||||
var prog = b.Prog
|
|
||||||
switch t := ptr.raw.Type.(type) {
|
|
||||||
case *types.Basic: // void
|
|
||||||
elem = prog.tyInt8()
|
|
||||||
default:
|
|
||||||
elem = prog.rawType(t.(*types.Pointer).Elem()).ll
|
|
||||||
}
|
|
||||||
ret := llvm.CreateGEP(b.impl, elem, ptr.impl, []llvm.Value{offset.impl})
|
|
||||||
return Expr{ret, ptr.Type}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load returns the value at the pointer ptr.
|
|
||||||
func (b Builder) Load(ptr Expr) Expr {
|
|
||||||
if debugInstr {
|
|
||||||
log.Printf("Load %v\n", ptr.impl)
|
|
||||||
}
|
|
||||||
if ptr.kind == vkPyVarRef {
|
|
||||||
return b.pyLoad(ptr)
|
|
||||||
}
|
|
||||||
telem := b.Prog.Elem(ptr.Type)
|
|
||||||
return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store stores val at the pointer ptr.
|
|
||||||
func (b Builder) Store(ptr, val Expr) Builder {
|
|
||||||
raw := ptr.raw.Type
|
|
||||||
if debugInstr {
|
|
||||||
log.Printf("Store %v, %v, %v\n", raw, ptr.impl, val.impl)
|
|
||||||
}
|
|
||||||
val = checkExpr(val, raw.(*types.Pointer).Elem(), b)
|
|
||||||
b.impl.CreateStore(val.impl, ptr.impl)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b Builder) aggregateAlloc(t Type, flds ...llvm.Value) llvm.Value {
|
|
||||||
prog := b.Prog
|
|
||||||
size := prog.SizeOf(t)
|
|
||||||
ptr := b.InlineCall(b.Pkg.rtFunc("AllocU"), prog.IntVal(size, prog.Uintptr())).impl
|
|
||||||
tll := t.ll
|
|
||||||
impl := b.impl
|
|
||||||
for i, fld := range flds {
|
|
||||||
impl.CreateStore(fld, llvm.CreateStructGEP(impl, tll, ptr, i))
|
|
||||||
}
|
|
||||||
return ptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// aggregateValue yields the value of the aggregate X with the fields
|
|
||||||
func (b Builder) aggregateValue(t Type, flds ...llvm.Value) Expr {
|
|
||||||
return Expr{aggregateValue(b.impl, t.ll, flds...), t}
|
|
||||||
}
|
|
||||||
|
|
||||||
func aggregateValue(b llvm.Builder, tll llvm.Type, flds ...llvm.Value) llvm.Value {
|
|
||||||
ptr := llvm.CreateAlloca(b, tll)
|
|
||||||
for i, fld := range flds {
|
|
||||||
b.CreateStore(fld, llvm.CreateStructGEP(b, tll, ptr, i))
|
|
||||||
}
|
|
||||||
return llvm.CreateLoad(b, tll, ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The MakeClosure instruction yields a closure value whose code is
|
|
||||||
// Fn and whose free variables' values are supplied by Bindings.
|
|
||||||
//
|
|
||||||
// Type() returns a (possibly named) *types.Signature.
|
|
||||||
//
|
|
||||||
// Example printed form:
|
|
||||||
//
|
|
||||||
// t0 = make closure anon@1.2 [x y z]
|
|
||||||
// t1 = make closure bound$(main.I).add [i]
|
|
||||||
func (b Builder) MakeClosure(fn Expr, bindings []Expr) Expr {
|
|
||||||
if debugInstr {
|
|
||||||
log.Printf("MakeClosure %v, %v\n", fn, bindings)
|
|
||||||
}
|
|
||||||
prog := b.Prog
|
|
||||||
tfn := fn.Type
|
|
||||||
sig := tfn.raw.Type.(*types.Signature)
|
|
||||||
tctx := sig.Params().At(0).Type().Underlying().(*types.Pointer).Elem().(*types.Struct)
|
|
||||||
flds := llvmFields(bindings, tctx, b)
|
|
||||||
data := b.aggregateAlloc(prog.rawType(tctx), flds...)
|
|
||||||
return b.aggregateValue(prog.Closure(tfn), fn.impl, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// The Alloc instruction reserves space for a variable of the given type,
|
|
||||||
// zero-initializes it, and yields its address.
|
|
||||||
//
|
|
||||||
// If heap is false, Alloc zero-initializes the same local variable in
|
|
||||||
// the call frame and returns its address; in this case the Alloc must
|
|
||||||
// be present in Function.Locals. We call this a "local" alloc.
|
|
||||||
//
|
|
||||||
// If heap is true, Alloc allocates a new zero-initialized variable
|
|
||||||
// each time the instruction is executed. We call this a "new" alloc.
|
|
||||||
//
|
|
||||||
// When Alloc is applied to a channel, map or slice type, it returns
|
|
||||||
// the address of an uninitialized (nil) reference of that kind; store
|
|
||||||
// the result of MakeSlice, MakeMap or MakeChan in that location to
|
|
||||||
// instantiate these types.
|
|
||||||
//
|
|
||||||
// Example printed form:
|
|
||||||
//
|
|
||||||
// t0 = local int
|
|
||||||
// t1 = new int
|
|
||||||
func (b Builder) Alloc(elem Type, heap bool) (ret Expr) {
|
|
||||||
if debugInstr {
|
|
||||||
log.Printf("Alloc %v, %v\n", elem.RawType(), heap)
|
|
||||||
}
|
|
||||||
prog := b.Prog
|
|
||||||
pkg := b.Pkg
|
|
||||||
size := SizeOf(prog, elem)
|
|
||||||
if heap {
|
|
||||||
ret = b.InlineCall(pkg.rtFunc("AllocZ"), size)
|
|
||||||
} else {
|
|
||||||
ret = Expr{llvm.CreateAlloca(b.impl, elem.ll), prog.VoidPtr()}
|
|
||||||
ret.impl = b.InlineCall(pkg.rtFunc("Zeroinit"), ret, size).impl
|
|
||||||
}
|
|
||||||
ret.Type = prog.Pointer(elem)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllocU allocates uninitialized space for n*sizeof(elem) bytes.
|
|
||||||
func (b Builder) AllocU(elem Type, n ...int64) (ret Expr) {
|
|
||||||
prog := b.Prog
|
|
||||||
size := SizeOf(prog, elem, n...)
|
|
||||||
ret = b.InlineCall(b.Pkg.rtFunc("AllocU"), size)
|
|
||||||
ret.Type = prog.Pointer(elem)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllocZ allocates zero initialized space for n bytes.
|
|
||||||
func (b Builder) AllocZ(n Expr) (ret Expr) {
|
|
||||||
return b.InlineCall(b.Pkg.rtFunc("AllocZ"), n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alloca allocates uninitialized space for n bytes.
|
|
||||||
func (b Builder) Alloca(n Expr) (ret Expr) {
|
|
||||||
if debugInstr {
|
|
||||||
log.Printf("Alloca %v\n", n.impl)
|
|
||||||
}
|
|
||||||
prog := b.Prog
|
|
||||||
telem := prog.tyInt8()
|
|
||||||
ret.impl = llvm.CreateArrayAlloca(b.impl, telem, n.impl)
|
|
||||||
ret.Type = prog.VoidPtr()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllocaCStr allocates space for copy it from a Go string.
|
|
||||||
func (b Builder) AllocaCStr(gostr Expr) (ret Expr) {
|
|
||||||
if debugInstr {
|
|
||||||
log.Printf("AllocaCStr %v\n", gostr.impl)
|
|
||||||
}
|
|
||||||
n := b.StringLen(gostr)
|
|
||||||
n1 := b.BinOp(token.ADD, n, b.Prog.Val(1))
|
|
||||||
cstr := b.Alloca(n1)
|
|
||||||
return b.InlineCall(b.Pkg.rtFunc("CStrCopy"), cstr, gostr)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// ArrayAlloca reserves space for an array of n elements of type telem.
|
|
||||||
func (b Builder) ArrayAlloca(telem Type, n Expr) (ret Expr) {
|
|
||||||
if debugInstr {
|
|
||||||
log.Printf("ArrayAlloca %v, %v\n", telem.t, n.impl)
|
|
||||||
}
|
|
||||||
ret.impl = llvm.CreateArrayAlloca(b.impl, telem.ll, n.impl)
|
|
||||||
ret.Type = b.Prog.Pointer(telem)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ArrayAlloc allocates zero initialized space for an array of n elements of type telem.
|
|
||||||
func (b Builder) ArrayAlloc(telem Type, n Expr) (ret Expr) {
|
|
||||||
prog := b.Prog
|
|
||||||
elemSize := SizeOf(prog, telem)
|
|
||||||
size := b.BinOp(token.MUL, n, elemSize)
|
|
||||||
ret.impl = b.AllocZ(size).impl
|
|
||||||
ret.Type = prog.Pointer(telem)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// The ChangeType instruction applies to X a value-preserving type
|
// The ChangeType instruction applies to X a value-preserving type
|
||||||
// change to Type().
|
// change to Type().
|
||||||
//
|
//
|
||||||
@@ -876,6 +631,77 @@ func castPtr(b llvm.Builder, x llvm.Value, t llvm.Type) llvm.Value {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// The Range instruction yields an iterator over the domain and range
|
||||||
|
// of X, which must be a string or map.
|
||||||
|
//
|
||||||
|
// Elements are accessed via Next.
|
||||||
|
//
|
||||||
|
// Type() returns an opaque and degenerate "rangeIter" type.
|
||||||
|
//
|
||||||
|
// Pos() returns the ast.RangeStmt.For.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t0 = range "hello":string
|
||||||
|
func (b Builder) Range(x Expr) Expr {
|
||||||
|
switch x.kind {
|
||||||
|
case vkString:
|
||||||
|
return b.InlineCall(b.Pkg.rtFunc("NewStringIter"), x)
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Next instruction reads and advances the (map or string)
|
||||||
|
// iterator Iter and returns a 3-tuple value (ok, k, v). If the
|
||||||
|
// iterator is not exhausted, ok is true and k and v are the next
|
||||||
|
// elements of the domain and range, respectively. Otherwise ok is
|
||||||
|
// false and k and v are undefined.
|
||||||
|
//
|
||||||
|
// Components of the tuple are accessed using Extract.
|
||||||
|
//
|
||||||
|
// The IsString field distinguishes iterators over strings from those
|
||||||
|
// over maps, as the Type() alone is insufficient: consider
|
||||||
|
// map[int]rune.
|
||||||
|
//
|
||||||
|
// Type() returns a *types.Tuple for the triple (ok, k, v).
|
||||||
|
// The types of k and/or v may be types.Invalid.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t1 = next t0
|
||||||
|
func (b Builder) Next(iter Expr, isString bool) (ret Expr) {
|
||||||
|
if isString {
|
||||||
|
return b.InlineCall(b.Pkg.rtFunc("StringIterNext"), iter)
|
||||||
|
}
|
||||||
|
panic("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// The MakeClosure instruction yields a closure value whose code is
|
||||||
|
// Fn and whose free variables' values are supplied by Bindings.
|
||||||
|
//
|
||||||
|
// Type() returns a (possibly named) *types.Signature.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t0 = make closure anon@1.2 [x y z]
|
||||||
|
// t1 = make closure bound$(main.I).add [i]
|
||||||
|
func (b Builder) MakeClosure(fn Expr, bindings []Expr) Expr {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("MakeClosure %v, %v\n", fn, bindings)
|
||||||
|
}
|
||||||
|
prog := b.Prog
|
||||||
|
tfn := fn.Type
|
||||||
|
sig := tfn.raw.Type.(*types.Signature)
|
||||||
|
tctx := sig.Params().At(0).Type().Underlying().(*types.Pointer).Elem().(*types.Struct)
|
||||||
|
flds := llvmFields(bindings, tctx, b)
|
||||||
|
data := b.aggregateAllocU(prog.rawType(tctx), flds...)
|
||||||
|
return b.aggregateValue(prog.Closure(tfn), fn.impl, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// TODO(xsw): make inline call
|
// TODO(xsw): make inline call
|
||||||
func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) {
|
func (b Builder) InlineCall(fn Expr, args ...Expr) (ret Expr) {
|
||||||
return b.Call(fn, args...)
|
return b.Call(fn, args...)
|
||||||
@@ -958,51 +784,6 @@ func (b Builder) Do(da DoAction, fn Expr, args ...Expr) (ret Expr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Range instruction yields an iterator over the domain and range
|
|
||||||
// of X, which must be a string or map.
|
|
||||||
//
|
|
||||||
// Elements are accessed via Next.
|
|
||||||
//
|
|
||||||
// Type() returns an opaque and degenerate "rangeIter" type.
|
|
||||||
//
|
|
||||||
// Pos() returns the ast.RangeStmt.For.
|
|
||||||
//
|
|
||||||
// Example printed form:
|
|
||||||
//
|
|
||||||
// t0 = range "hello":string
|
|
||||||
func (b Builder) Range(x Expr) Expr {
|
|
||||||
switch x.kind {
|
|
||||||
case vkString:
|
|
||||||
return b.InlineCall(b.Pkg.rtFunc("NewStringIter"), x)
|
|
||||||
}
|
|
||||||
panic("todo")
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Next instruction reads and advances the (map or string)
|
|
||||||
// iterator Iter and returns a 3-tuple value (ok, k, v). If the
|
|
||||||
// iterator is not exhausted, ok is true and k and v are the next
|
|
||||||
// elements of the domain and range, respectively. Otherwise ok is
|
|
||||||
// false and k and v are undefined.
|
|
||||||
//
|
|
||||||
// Components of the tuple are accessed using Extract.
|
|
||||||
//
|
|
||||||
// The IsString field distinguishes iterators over strings from those
|
|
||||||
// over maps, as the Type() alone is insufficient: consider
|
|
||||||
// map[int]rune.
|
|
||||||
//
|
|
||||||
// Type() returns a *types.Tuple for the triple (ok, k, v).
|
|
||||||
// The types of k and/or v may be types.Invalid.
|
|
||||||
//
|
|
||||||
// Example printed form:
|
|
||||||
//
|
|
||||||
// t1 = next t0
|
|
||||||
func (b Builder) Next(iter Expr, isString bool) (ret Expr) {
|
|
||||||
if isString {
|
|
||||||
return b.InlineCall(b.Pkg.rtFunc("StringIterNext"), iter)
|
|
||||||
}
|
|
||||||
panic("todo")
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Builtin represents a specific use of a built-in function, e.g. len.
|
// A Builtin represents a specific use of a built-in function, e.g. len.
|
||||||
//
|
//
|
||||||
// Builtins are immutable values. Builtins do not have addresses.
|
// Builtins are immutable values. Builtins do not have addresses.
|
||||||
@@ -1139,3 +920,62 @@ func (b Builder) PrintEx(ln bool, args ...Expr) (ret Expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func checkExpr(v Expr, t types.Type, b Builder) Expr {
|
||||||
|
if t, ok := t.(*types.Struct); ok && isClosure(t) {
|
||||||
|
if v.kind != vkClosure {
|
||||||
|
return b.Pkg.closureStub(b, t, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func needsNegativeCheck(x Expr) bool {
|
||||||
|
if x.kind == vkSigned {
|
||||||
|
if rv := x.impl.IsAConstantInt(); !rv.IsNil() && rv.SExtValue() >= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func llvmParamsEx(data Expr, vals []Expr, params *types.Tuple, b Builder) (ret []llvm.Value) {
|
||||||
|
if data.IsNil() {
|
||||||
|
return llvmParams(0, vals, params, b)
|
||||||
|
}
|
||||||
|
ret = llvmParams(1, vals, params, b)
|
||||||
|
ret[0] = data.impl
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func llvmParams(base int, vals []Expr, params *types.Tuple, b Builder) (ret []llvm.Value) {
|
||||||
|
n := params.Len()
|
||||||
|
if n > 0 {
|
||||||
|
ret = make([]llvm.Value, len(vals)+base)
|
||||||
|
for idx, v := range vals {
|
||||||
|
i := base + idx
|
||||||
|
if i < n {
|
||||||
|
v = checkExpr(v, params.At(i).Type(), b)
|
||||||
|
}
|
||||||
|
ret[i] = v.impl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func llvmFields(vals []Expr, t *types.Struct, b Builder) (ret []llvm.Value) {
|
||||||
|
n := t.NumFields()
|
||||||
|
if n > 0 {
|
||||||
|
ret = make([]llvm.Value, len(vals))
|
||||||
|
for i, v := range vals {
|
||||||
|
if i < n {
|
||||||
|
v = checkExpr(v, t.Field(i).Type(), b)
|
||||||
|
}
|
||||||
|
ret[i] = v.impl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
114
ssa/goroutine.go
Normal file
114
ssa/goroutine.go
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* 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 ssa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/goplus/llvm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// func(c.Pointer) c.Pointer
|
||||||
|
func (p Program) tyRoutine() *types.Signature {
|
||||||
|
if p.routineTy == nil {
|
||||||
|
paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
|
||||||
|
params := types.NewTuple(paramPtr)
|
||||||
|
p.routineTy = types.NewSignatureType(nil, nil, nil, params, params, false)
|
||||||
|
}
|
||||||
|
return p.routineTy
|
||||||
|
}
|
||||||
|
|
||||||
|
// func(pthread *Thread, attr *Attr, routine func(c.Pointer) c.Pointer, arg c.Pointer) c.Int
|
||||||
|
func (p Program) tyPthreadCreate() *types.Signature {
|
||||||
|
if p.createThdTy == nil {
|
||||||
|
paramPPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtrPtr().raw.Type)
|
||||||
|
paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
|
||||||
|
paramRoutine := types.NewParam(token.NoPos, nil, "", p.tyRoutine())
|
||||||
|
paramCInt := types.NewParam(token.NoPos, nil, "", p.CInt().raw.Type)
|
||||||
|
params := types.NewTuple(paramPPtr, paramPtr, paramRoutine, paramPtr)
|
||||||
|
results := types.NewTuple(paramCInt)
|
||||||
|
p.createThdTy = types.NewSignatureType(nil, nil, nil, params, results, false)
|
||||||
|
}
|
||||||
|
return p.createThdTy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) createThread(pp, attr, routine, arg Expr) Expr {
|
||||||
|
fn := b.Pkg.cFunc("pthread_create", b.Prog.tyPthreadCreate())
|
||||||
|
return b.Call(fn, pp, attr, routine, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// The Go instruction creates a new goroutine and calls the specified
|
||||||
|
// function within it.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// go println(t0, t1)
|
||||||
|
// go t3()
|
||||||
|
// go invoke t5.Println(...t6)
|
||||||
|
func (b Builder) Go(fn Expr, args ...Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
logCall("Go", fn, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
prog := b.Prog
|
||||||
|
pkg := b.Pkg
|
||||||
|
|
||||||
|
typs := make([]Type, len(args)+1)
|
||||||
|
flds := make([]llvm.Value, len(args)+1)
|
||||||
|
typs[0] = fn.Type
|
||||||
|
flds[0] = fn.impl
|
||||||
|
for i, arg := range args {
|
||||||
|
typs[i+1] = arg.Type
|
||||||
|
flds[i+1] = arg.impl
|
||||||
|
}
|
||||||
|
t := prog.Struct(typs...)
|
||||||
|
voidPtr := prog.VoidPtr()
|
||||||
|
data := Expr{b.aggregateMalloc(t, flds...), voidPtr}
|
||||||
|
size := prog.SizeOf(voidPtr)
|
||||||
|
pthd := b.Alloca(prog.IntVal(uint64(size), prog.Uintptr()))
|
||||||
|
b.createThread(pthd, prog.Null(voidPtr), pkg.routine(t, len(args)), data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Package) routineName() string {
|
||||||
|
p.iRoutine++
|
||||||
|
return p.Path() + "._llgo_routine$" + strconv.Itoa(p.iRoutine)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Package) routine(t Type, n int) Expr {
|
||||||
|
prog := p.Prog
|
||||||
|
routine := p.NewFunc(p.routineName(), prog.tyRoutine(), InC)
|
||||||
|
b := routine.MakeBody(1)
|
||||||
|
param := routine.Param(0)
|
||||||
|
data := Expr{llvm.CreateLoad(b.impl, t.ll, param.impl), t}
|
||||||
|
args := make([]Expr, n)
|
||||||
|
fn := b.getField(data, 0)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
args[i] = b.getField(data, i+1)
|
||||||
|
}
|
||||||
|
b.Call(fn, args...)
|
||||||
|
b.free(data)
|
||||||
|
b.Return(prog.Null(prog.VoidPtr()))
|
||||||
|
return routine.Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
235
ssa/memory.go
Normal file
235
ssa/memory.go
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
* 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 ssa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/goplus/llvm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Advance returns the pointer ptr advanced by offset.
|
||||||
|
func (b Builder) Advance(ptr Expr, offset Expr) Expr {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("Advance %v, %v\n", ptr.impl, offset.impl)
|
||||||
|
}
|
||||||
|
var elem llvm.Type
|
||||||
|
var prog = b.Prog
|
||||||
|
switch t := ptr.raw.Type.(type) {
|
||||||
|
case *types.Basic: // void
|
||||||
|
elem = prog.tyInt8()
|
||||||
|
default:
|
||||||
|
elem = prog.rawType(t.(*types.Pointer).Elem()).ll
|
||||||
|
}
|
||||||
|
ret := llvm.CreateGEP(b.impl, elem, ptr.impl, []llvm.Value{offset.impl})
|
||||||
|
return Expr{ret, ptr.Type}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load returns the value at the pointer ptr.
|
||||||
|
func (b Builder) Load(ptr Expr) Expr {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("Load %v\n", ptr.impl)
|
||||||
|
}
|
||||||
|
if ptr.kind == vkPyVarRef {
|
||||||
|
return b.pyLoad(ptr)
|
||||||
|
}
|
||||||
|
telem := b.Prog.Elem(ptr.Type)
|
||||||
|
return Expr{llvm.CreateLoad(b.impl, telem.ll, ptr.impl), telem}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store stores val at the pointer ptr.
|
||||||
|
func (b Builder) Store(ptr, val Expr) Builder {
|
||||||
|
raw := ptr.raw.Type
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("Store %v, %v, %v\n", raw, ptr.impl, val.impl)
|
||||||
|
}
|
||||||
|
val = checkExpr(val, raw.(*types.Pointer).Elem(), b)
|
||||||
|
b.impl.CreateStore(val.impl, ptr.impl)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) aggregateAllocU(t Type, flds ...llvm.Value) llvm.Value {
|
||||||
|
prog := b.Prog
|
||||||
|
size := prog.SizeOf(t)
|
||||||
|
ptr := b.allocUninited(prog.IntVal(size, prog.Uintptr())).impl
|
||||||
|
aggregateInit(b.impl, ptr, t.ll, flds...)
|
||||||
|
return ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) aggregateMalloc(t Type, flds ...llvm.Value) llvm.Value {
|
||||||
|
prog := b.Prog
|
||||||
|
size := prog.SizeOf(t)
|
||||||
|
ptr := b.malloc(prog.IntVal(size, prog.Uintptr())).impl
|
||||||
|
aggregateInit(b.impl, ptr, t.ll, flds...)
|
||||||
|
return ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// aggregateValue yields the value of the aggregate X with the fields
|
||||||
|
func (b Builder) aggregateValue(t Type, flds ...llvm.Value) Expr {
|
||||||
|
return Expr{aggregateValue(b.impl, t.ll, flds...), t}
|
||||||
|
}
|
||||||
|
|
||||||
|
func aggregateValue(b llvm.Builder, tll llvm.Type, flds ...llvm.Value) llvm.Value {
|
||||||
|
ptr := llvm.CreateAlloca(b, tll)
|
||||||
|
aggregateInit(b, ptr, tll, flds...)
|
||||||
|
return llvm.CreateLoad(b, tll, ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func aggregateInit(b llvm.Builder, ptr llvm.Value, tll llvm.Type, flds ...llvm.Value) {
|
||||||
|
for i, fld := range flds {
|
||||||
|
b.CreateStore(fld, llvm.CreateStructGEP(b, tll, ptr, i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// The Alloc instruction reserves space for a variable of the given type,
|
||||||
|
// zero-initializes it, and yields its address.
|
||||||
|
//
|
||||||
|
// If heap is false, Alloc zero-initializes the same local variable in
|
||||||
|
// the call frame and returns its address; in this case the Alloc must
|
||||||
|
// be present in Function.Locals. We call this a "local" alloc.
|
||||||
|
//
|
||||||
|
// If heap is true, Alloc allocates a new zero-initialized variable
|
||||||
|
// each time the instruction is executed. We call this a "new" alloc.
|
||||||
|
//
|
||||||
|
// When Alloc is applied to a channel, map or slice type, it returns
|
||||||
|
// the address of an uninitialized (nil) reference of that kind; store
|
||||||
|
// the result of MakeSlice, MakeMap or MakeChan in that location to
|
||||||
|
// instantiate these types.
|
||||||
|
//
|
||||||
|
// Example printed form:
|
||||||
|
//
|
||||||
|
// t0 = local int
|
||||||
|
// t1 = new int
|
||||||
|
func (b Builder) Alloc(elem Type, heap bool) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("Alloc %v, %v\n", elem.RawType(), heap)
|
||||||
|
}
|
||||||
|
prog := b.Prog
|
||||||
|
pkg := b.Pkg
|
||||||
|
size := SizeOf(prog, elem)
|
||||||
|
if heap {
|
||||||
|
ret = b.InlineCall(pkg.rtFunc("AllocZ"), size)
|
||||||
|
} else {
|
||||||
|
ret = Expr{llvm.CreateAlloca(b.impl, elem.ll), prog.VoidPtr()}
|
||||||
|
ret.impl = b.InlineCall(pkg.rtFunc("Zeroinit"), ret, size).impl
|
||||||
|
}
|
||||||
|
ret.Type = prog.Pointer(elem)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllocU allocates uninitialized space for n*sizeof(elem) bytes.
|
||||||
|
func (b Builder) AllocU(elem Type, n ...int64) (ret Expr) {
|
||||||
|
prog := b.Prog
|
||||||
|
size := SizeOf(prog, elem, n...)
|
||||||
|
return Expr{b.allocUninited(size).impl, prog.Pointer(elem)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) allocUninited(size Expr) (ret Expr) {
|
||||||
|
return b.InlineCall(b.Pkg.rtFunc("AllocU"), size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllocZ allocates zero initialized space for n bytes.
|
||||||
|
func (b Builder) AllocZ(n Expr) (ret Expr) {
|
||||||
|
return b.InlineCall(b.Pkg.rtFunc("AllocZ"), n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alloca allocates uninitialized space for n bytes.
|
||||||
|
func (b Builder) Alloca(n Expr) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("Alloca %v\n", n.impl)
|
||||||
|
}
|
||||||
|
prog := b.Prog
|
||||||
|
telem := prog.tyInt8()
|
||||||
|
ret.impl = llvm.CreateArrayAlloca(b.impl, telem, n.impl)
|
||||||
|
ret.Type = prog.VoidPtr()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllocaCStr allocates space for copy it from a Go string.
|
||||||
|
func (b Builder) AllocaCStr(gostr Expr) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("AllocaCStr %v\n", gostr.impl)
|
||||||
|
}
|
||||||
|
n := b.StringLen(gostr)
|
||||||
|
n1 := b.BinOp(token.ADD, n, b.Prog.Val(1))
|
||||||
|
cstr := b.Alloca(n1)
|
||||||
|
return b.InlineCall(b.Pkg.rtFunc("CStrCopy"), cstr, gostr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (p Program) tyMalloc() *types.Signature {
|
||||||
|
if p.mallocTy == nil {
|
||||||
|
paramSize := types.NewParam(token.NoPos, nil, "", p.Uintptr().raw.Type)
|
||||||
|
paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
|
||||||
|
params := types.NewTuple(paramSize)
|
||||||
|
results := types.NewTuple(paramPtr)
|
||||||
|
p.mallocTy = types.NewSignatureType(nil, nil, nil, params, results, false)
|
||||||
|
}
|
||||||
|
return p.mallocTy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Program) tyFree() *types.Signature {
|
||||||
|
if p.freeTy == nil {
|
||||||
|
paramPtr := types.NewParam(token.NoPos, nil, "", p.VoidPtr().raw.Type)
|
||||||
|
params := types.NewTuple(paramPtr)
|
||||||
|
p.freeTy = types.NewSignatureType(nil, nil, nil, params, nil, false)
|
||||||
|
}
|
||||||
|
return p.freeTy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) malloc(size Expr) Expr {
|
||||||
|
fn := b.Pkg.cFunc("malloc", b.Prog.tyMalloc())
|
||||||
|
return b.Call(fn, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Builder) free(ptr Expr) Expr {
|
||||||
|
fn := b.Pkg.cFunc("free", b.Prog.tyFree())
|
||||||
|
return b.Call(fn, ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
// ArrayAlloca reserves space for an array of n elements of type telem.
|
||||||
|
func (b Builder) ArrayAlloca(telem Type, n Expr) (ret Expr) {
|
||||||
|
if debugInstr {
|
||||||
|
log.Printf("ArrayAlloca %v, %v\n", telem.t, n.impl)
|
||||||
|
}
|
||||||
|
ret.impl = llvm.CreateArrayAlloca(b.impl, telem.ll, n.impl)
|
||||||
|
ret.Type = b.Prog.Pointer(telem)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ArrayAlloc allocates zero initialized space for an array of n elements of type telem.
|
||||||
|
func (b Builder) ArrayAlloc(telem Type, n Expr) (ret Expr) {
|
||||||
|
prog := b.Prog
|
||||||
|
elemSize := SizeOf(prog, telem)
|
||||||
|
size := b.BinOp(token.MUL, n, elemSize)
|
||||||
|
ret.impl = b.AllocZ(size).impl
|
||||||
|
ret.Type = prog.Pointer(telem)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
@@ -163,6 +163,12 @@ type aProgram struct {
|
|||||||
loadPyModS *types.Signature
|
loadPyModS *types.Signature
|
||||||
getAttrStr *types.Signature
|
getAttrStr *types.Signature
|
||||||
|
|
||||||
|
mallocTy *types.Signature
|
||||||
|
freeTy *types.Signature
|
||||||
|
|
||||||
|
createThdTy *types.Signature
|
||||||
|
routineTy *types.Signature
|
||||||
|
|
||||||
paramObjPtr_ *types.Var
|
paramObjPtr_ *types.Var
|
||||||
|
|
||||||
ptrSize int
|
ptrSize int
|
||||||
@@ -511,6 +517,8 @@ func (p Program) Uint64() Type {
|
|||||||
// and unspecified other things too.
|
// and unspecified other things too.
|
||||||
type aPackage struct {
|
type aPackage struct {
|
||||||
mod llvm.Module
|
mod llvm.Module
|
||||||
|
abi abi.Builder
|
||||||
|
abiTypes
|
||||||
|
|
||||||
vars map[string]Global
|
vars map[string]Global
|
||||||
fns map[string]Function
|
fns map[string]Function
|
||||||
@@ -519,8 +527,7 @@ type aPackage struct {
|
|||||||
pymods map[string]Global
|
pymods map[string]Global
|
||||||
Prog Program
|
Prog Program
|
||||||
|
|
||||||
abi abi.Builder
|
iRoutine int
|
||||||
abiTypes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Package = *aPackage
|
type Package = *aPackage
|
||||||
@@ -532,6 +539,10 @@ func (p Package) rtFunc(fnName string) Expr {
|
|||||||
return p.NewFunc(name, sig, InGo).Expr
|
return p.NewFunc(name, sig, InGo).Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Package) cFunc(fullName string, sig *types.Signature) Expr {
|
||||||
|
return p.NewFunc(fullName, sig, InC).Expr
|
||||||
|
}
|
||||||
|
|
||||||
func (p Package) pyFunc(fullName string, sig *types.Signature) Expr {
|
func (p Package) pyFunc(fullName string, sig *types.Signature) Expr {
|
||||||
p.Prog.NeedPyInit = true
|
p.Prog.NeedPyInit = true
|
||||||
return p.NewFunc(fullName, sig, InC).Expr
|
return p.NewFunc(fullName, sig, InC).Expr
|
||||||
|
|||||||
@@ -142,21 +142,6 @@ func (b Builder) Unreachable() {
|
|||||||
b.impl.CreateUnreachable()
|
b.impl.CreateUnreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Go instruction creates a new goroutine and calls the specified
|
|
||||||
// function within it.
|
|
||||||
//
|
|
||||||
// Example printed form:
|
|
||||||
//
|
|
||||||
// go println(t0, t1)
|
|
||||||
// go t3()
|
|
||||||
// go invoke t5.Println(...t6)
|
|
||||||
func (b Builder) Go(fn Expr, args ...Expr) {
|
|
||||||
if debugInstr {
|
|
||||||
logCall("Go", fn, args)
|
|
||||||
}
|
|
||||||
b.Call(fn, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return emits a return instruction.
|
// Return emits a return instruction.
|
||||||
func (b Builder) Return(results ...Expr) {
|
func (b Builder) Return(results ...Expr) {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
|
|||||||
Reference in New Issue
Block a user