Implement minimal bump pointer allocator
Useful for MCUs, until a real garbage collector has been implemented.
Этот коммит содержится в:
родитель
b45ea2deb9
коммит
e171f32493
4 изменённых файлов: 163 добавлений и 62 удалений
5
arm.ld
5
arm.ld
|
@ -75,3 +75,8 @@ SECTIONS
|
||||||
__etext = _etext;
|
__etext = _etext;
|
||||||
__data_start__ = _sdata;
|
__data_start__ = _sdata;
|
||||||
__bss_start__ = _sbss;
|
__bss_start__ = _sbss;
|
||||||
|
|
||||||
|
/* For the memory allocator. */
|
||||||
|
_heap_start = _ebss;
|
||||||
|
_heap_end = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
runtime.heapptr = _heap_start; /* necessary? */
|
||||||
|
|
31
src/runtime/gc.go
Обычный файл
31
src/runtime/gc.go
Обычный файл
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_extern__heap_start unsafe.Pointer // defined by the linker
|
||||||
|
heapptr = uintptr(unsafe.Pointer(&_extern__heap_start))
|
||||||
|
)
|
||||||
|
|
||||||
|
func alloc(size uintptr) unsafe.Pointer {
|
||||||
|
// TODO: this can be optimized by not casting between pointers and ints so
|
||||||
|
// much. And by using platform-native data types (e.g. *uint8 for 8-bit
|
||||||
|
// systems).
|
||||||
|
size = align(size)
|
||||||
|
addr := heapptr
|
||||||
|
heapptr += size
|
||||||
|
for i := uintptr(0); i < uintptr(size); i += 4 {
|
||||||
|
ptr := (*uint32)(unsafe.Pointer(addr + i))
|
||||||
|
*ptr = 0
|
||||||
|
}
|
||||||
|
return unsafe.Pointer(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func free(ptr unsafe.Pointer) {
|
||||||
|
// TODO: use a GC
|
||||||
|
}
|
|
@ -3,6 +3,10 @@
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// #include <stdio.h>
|
// #include <stdio.h>
|
||||||
// #include <stdlib.h>
|
// #include <stdlib.h>
|
||||||
// #include <unistd.h>
|
// #include <unistd.h>
|
||||||
|
@ -21,3 +25,15 @@ func Sleep(d Duration) {
|
||||||
func abort() {
|
func abort() {
|
||||||
C.abort()
|
C.abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func alloc(size uintptr) unsafe.Pointer {
|
||||||
|
buf := C.calloc(1, C.size_t(size))
|
||||||
|
if buf == nil {
|
||||||
|
panic("cannot allocate memory")
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func free(ptr unsafe.Pointer) {
|
||||||
|
C.free(ptr)
|
||||||
|
}
|
||||||
|
|
173
tgo.go
173
tgo.go
|
@ -35,11 +35,14 @@ type Compiler struct {
|
||||||
machine llvm.TargetMachine
|
machine llvm.TargetMachine
|
||||||
targetData llvm.TargetData
|
targetData llvm.TargetData
|
||||||
intType llvm.Type
|
intType llvm.Type
|
||||||
|
i8ptrType llvm.Type // for convenience
|
||||||
uintptrType llvm.Type
|
uintptrType llvm.Type
|
||||||
stringLenType llvm.Type
|
stringLenType llvm.Type
|
||||||
stringType llvm.Type
|
stringType llvm.Type
|
||||||
interfaceType llvm.Type
|
interfaceType llvm.Type
|
||||||
typeassertType llvm.Type
|
typeassertType llvm.Type
|
||||||
|
allocFunc llvm.Value
|
||||||
|
freeFunc llvm.Value
|
||||||
itfTypeNumbers map[types.Type]uint64
|
itfTypeNumbers map[types.Type]uint64
|
||||||
itfTypes []types.Type
|
itfTypes []types.Type
|
||||||
initFuncs []llvm.Value
|
initFuncs []llvm.Value
|
||||||
|
@ -86,15 +89,22 @@ func NewCompiler(pkgName, triple string) (*Compiler, error) {
|
||||||
c.intType = llvm.Int32Type()
|
c.intType = llvm.Int32Type()
|
||||||
c.stringLenType = llvm.Int32Type()
|
c.stringLenType = llvm.Int32Type()
|
||||||
c.uintptrType = c.targetData.IntPtrType()
|
c.uintptrType = c.targetData.IntPtrType()
|
||||||
|
c.i8ptrType = llvm.PointerType(llvm.Int8Type(), 0)
|
||||||
|
|
||||||
// Go string: tuple of (len, ptr)
|
// Go string: tuple of (len, ptr)
|
||||||
c.stringType = llvm.StructType([]llvm.Type{c.stringLenType, llvm.PointerType(llvm.Int8Type(), 0)}, false)
|
c.stringType = llvm.StructType([]llvm.Type{c.stringLenType, c.i8ptrType}, false)
|
||||||
|
|
||||||
// Go interface: tuple of (type, ptr)
|
// Go interface: tuple of (type, ptr)
|
||||||
c.interfaceType = llvm.StructType([]llvm.Type{llvm.Int32Type(), llvm.PointerType(llvm.Int8Type(), 0)}, false)
|
c.interfaceType = llvm.StructType([]llvm.Type{llvm.Int32Type(), c.i8ptrType}, false)
|
||||||
|
|
||||||
// Go typeassert result: tuple of (ptr, bool)
|
// Go typeassert result: tuple of (ptr, bool)
|
||||||
c.typeassertType = llvm.StructType([]llvm.Type{llvm.PointerType(llvm.Int8Type(), 0), llvm.Int1Type()}, false)
|
c.typeassertType = llvm.StructType([]llvm.Type{c.i8ptrType, llvm.Int1Type()}, false)
|
||||||
|
|
||||||
|
allocType := llvm.FunctionType(c.i8ptrType, []llvm.Type{c.uintptrType}, false)
|
||||||
|
c.allocFunc = llvm.AddFunction(c.mod, "runtime.alloc", allocType)
|
||||||
|
|
||||||
|
freeType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{c.i8ptrType}, false)
|
||||||
|
c.freeFunc = llvm.AddFunction(c.mod, "runtime.free", freeType)
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
@ -224,7 +234,7 @@ func (c *Compiler) getLLVMType(goType types.Type) (llvm.Type, error) {
|
||||||
case types.Uintptr:
|
case types.Uintptr:
|
||||||
return c.uintptrType, nil
|
return c.uintptrType, nil
|
||||||
case types.UnsafePointer:
|
case types.UnsafePointer:
|
||||||
return llvm.PointerType(llvm.Int8Type(), 0), nil
|
return c.i8ptrType, nil
|
||||||
default:
|
default:
|
||||||
return llvm.Type{}, errors.New("todo: unknown basic type: " + fmt.Sprintf("%#v", typ))
|
return llvm.Type{}, errors.New("todo: unknown basic type: " + fmt.Sprintf("%#v", typ))
|
||||||
}
|
}
|
||||||
|
@ -295,6 +305,16 @@ func (c *Compiler) getInterfaceType(typ types.Type) llvm.Value {
|
||||||
return llvm.ConstInt(llvm.Int32Type(), c.itfTypeNumbers[typ], false)
|
return llvm.ConstInt(llvm.Int32Type(), c.itfTypeNumbers[typ], false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Compiler) isPointer(typ types.Type) bool {
|
||||||
|
if _, ok := typ.(*types.Pointer); ok {
|
||||||
|
return true
|
||||||
|
} else if typ, ok := typ.(*types.Basic); ok && typ.Kind() == types.UnsafePointer {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Compiler) getFunctionName(fn *ssa.Function) string {
|
func (c *Compiler) getFunctionName(fn *ssa.Function) string {
|
||||||
if fn.Signature.Recv() != nil {
|
if fn.Signature.Recv() != nil {
|
||||||
// Method on a defined type.
|
// Method on a defined type.
|
||||||
|
@ -311,6 +331,14 @@ func (c *Compiler) getFunctionName(fn *ssa.Function) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Compiler) getGlobalName(global *ssa.Global) string {
|
||||||
|
if strings.HasPrefix(global.Name(), "_extern_") {
|
||||||
|
return global.Name()[len("_extern_"):]
|
||||||
|
} else {
|
||||||
|
return pkgPrefix(global.Pkg) + "." + global.Name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Compiler) parsePackage(program *ssa.Program, pkg *ssa.Package) error {
|
func (c *Compiler) parsePackage(program *ssa.Program, pkg *ssa.Package) error {
|
||||||
fmt.Println("\npackage:", pkg.Pkg.Path())
|
fmt.Println("\npackage:", pkg.Pkg.Path())
|
||||||
|
|
||||||
|
@ -359,13 +387,15 @@ func (c *Compiler) parsePackage(program *ssa.Program, pkg *ssa.Package) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
global := llvm.AddGlobal(c.mod, llvmType, pkgPrefix(member.Pkg) + "." + member.Name())
|
global := llvm.AddGlobal(c.mod, llvmType, c.getGlobalName(member))
|
||||||
global.SetLinkage(llvm.PrivateLinkage)
|
if !strings.HasPrefix(member.Name(), "_extern_") {
|
||||||
initializer, err := c.getZeroValue(llvmType)
|
global.SetLinkage(llvm.PrivateLinkage)
|
||||||
if err != nil {
|
initializer, err := c.getZeroValue(llvmType)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
global.SetInitializer(initializer)
|
||||||
}
|
}
|
||||||
global.SetInitializer(initializer)
|
|
||||||
case *ssa.Type:
|
case *ssa.Type:
|
||||||
ms := program.MethodSets.MethodSet(member.Type())
|
ms := program.MethodSets.MethodSet(member.Type())
|
||||||
for i := 0; i < ms.Len(); i++ {
|
for i := 0; i < ms.Len(); i++ {
|
||||||
|
@ -489,8 +519,7 @@ func (c *Compiler) parseInitFunc(frame *Frame, f *ssa.Function) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fullName := pkgPrefix(addr.Pkg) + "." + addr.Name()
|
llvmAddr := c.mod.NamedGlobal(c.getGlobalName(addr))
|
||||||
llvmAddr := c.mod.NamedGlobal(fullName)
|
|
||||||
llvmAddr.SetInitializer(val)
|
llvmAddr.SetInitializer(val)
|
||||||
case *ssa.FieldAddr:
|
case *ssa.FieldAddr:
|
||||||
// Initialize field of a global struct.
|
// Initialize field of a global struct.
|
||||||
|
@ -503,8 +532,14 @@ func (c *Compiler) parseInitFunc(frame *Frame, f *ssa.Function) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
global := addr.X.(*ssa.Global)
|
global := addr.X.(*ssa.Global)
|
||||||
llvmAddr := c.mod.NamedGlobal(pkgPrefix(global.Pkg) + "." + global.Name())
|
llvmAddr := c.mod.NamedGlobal(c.getGlobalName(global))
|
||||||
llvmValue := llvmAddr.Initializer()
|
llvmValue := llvmAddr.Initializer()
|
||||||
|
if llvmValue.IsNil() {
|
||||||
|
llvmValue, err = c.getZeroValue(llvmAddr.Type().ElementType())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
llvmValue = c.builder.CreateInsertValue(llvmValue, val, addr.Field, "")
|
llvmValue = c.builder.CreateInsertValue(llvmValue, val, addr.Field, "")
|
||||||
llvmAddr.SetInitializer(llvmValue)
|
llvmAddr.SetInitializer(llvmValue)
|
||||||
case *ssa.IndexAddr:
|
case *ssa.IndexAddr:
|
||||||
|
@ -519,8 +554,14 @@ func (c *Compiler) parseInitFunc(frame *Frame, f *ssa.Function) error {
|
||||||
}
|
}
|
||||||
fieldAddr := addr.X.(*ssa.FieldAddr)
|
fieldAddr := addr.X.(*ssa.FieldAddr)
|
||||||
global := fieldAddr.X.(*ssa.Global)
|
global := fieldAddr.X.(*ssa.Global)
|
||||||
llvmAddr := c.mod.NamedGlobal(pkgPrefix(global.Pkg) + "." + global.Name())
|
llvmAddr := c.mod.NamedGlobal(c.getGlobalName(global))
|
||||||
llvmValue := c.mod.NamedGlobal(pkgPrefix(global.Pkg) + "." + global.Name()).Initializer()
|
llvmValue := llvmAddr.Initializer()
|
||||||
|
if llvmValue.IsNil() {
|
||||||
|
llvmValue, err = c.getZeroValue(llvmAddr.Type().ElementType())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
llvmFieldValue := c.builder.CreateExtractValue(llvmValue, fieldAddr.Field, "")
|
llvmFieldValue := c.builder.CreateExtractValue(llvmValue, fieldAddr.Field, "")
|
||||||
llvmFieldValue = c.builder.CreateInsertValue(llvmFieldValue, val, int(index), "")
|
llvmFieldValue = c.builder.CreateInsertValue(llvmFieldValue, val, int(index), "")
|
||||||
llvmValue = c.builder.CreateInsertValue(llvmValue, llvmFieldValue, fieldAddr.Field, "")
|
llvmValue = c.builder.CreateInsertValue(llvmValue, llvmFieldValue, fieldAddr.Field, "")
|
||||||
|
@ -774,18 +815,17 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
var buf llvm.Value
|
var buf llvm.Value
|
||||||
if expr.Heap {
|
if expr.Heap {
|
||||||
// TODO: escape analysis
|
// TODO: escape analysis
|
||||||
buf = c.builder.CreateMalloc(typ, expr.Comment)
|
size := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(typ), false)
|
||||||
|
buf = c.builder.CreateCall(c.allocFunc, []llvm.Value{size}, expr.Comment)
|
||||||
|
buf = c.builder.CreateBitCast(buf, llvm.PointerType(typ, 0), "")
|
||||||
} else {
|
} else {
|
||||||
buf = c.builder.CreateAlloca(typ, expr.Comment)
|
buf = c.builder.CreateAlloca(typ, expr.Comment)
|
||||||
|
zero, err := c.getZeroValue(typ)
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
c.builder.CreateStore(zero, buf) // zero-initialize var
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
zero, err := c.getZeroValue(typ)
|
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
c.builder.CreateStore(zero, buf) // zero-initialize var
|
|
||||||
return buf, nil
|
return buf, nil
|
||||||
case *ssa.BinOp:
|
case *ssa.BinOp:
|
||||||
return c.parseBinOp(frame, expr)
|
return c.parseBinOp(frame, expr)
|
||||||
|
@ -815,7 +855,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
}
|
}
|
||||||
return c.builder.CreateGEP(val, indices, ""), nil
|
return c.builder.CreateGEP(val, indices, ""), nil
|
||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
fullName := pkgPrefix(expr.Pkg) + "." + expr.Name()
|
fullName := c.getGlobalName(expr)
|
||||||
value := c.mod.NamedGlobal(fullName)
|
value := c.mod.NamedGlobal(fullName)
|
||||||
if value.IsNil() {
|
if value.IsNil() {
|
||||||
return llvm.Value{}, errors.New("global not found: " + fullName)
|
return llvm.Value{}, errors.New("global not found: " + fullName)
|
||||||
|
@ -905,14 +945,15 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
var itfValue llvm.Value
|
var itfValue llvm.Value
|
||||||
switch typ := expr.X.Type().(type) {
|
switch typ := expr.X.Type().(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
itfValueType := llvm.PointerType(llvm.Int8Type(), 0)
|
|
||||||
if typ.Info() & types.IsInteger != 0 { // TODO: 64-bit int on 32-bit platform
|
if typ.Info() & types.IsInteger != 0 { // TODO: 64-bit int on 32-bit platform
|
||||||
itfValue = c.builder.CreateIntToPtr(val, itfValueType, "")
|
itfValue = c.builder.CreateIntToPtr(val, c.i8ptrType, "")
|
||||||
} else if typ.Kind() == types.String {
|
} else if typ.Kind() == types.String {
|
||||||
// TODO: escape analysis
|
// TODO: escape analysis
|
||||||
itfValue = c.builder.CreateMalloc(c.stringType, "")
|
size := c.targetData.TypeAllocSize(c.stringType)
|
||||||
c.builder.CreateStore(val, itfValue)
|
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
||||||
itfValue = c.builder.CreateBitCast(itfValue, itfValueType, "")
|
itfValue = c.builder.CreateCall(c.allocFunc, []llvm.Value{sizeValue}, "")
|
||||||
|
itfValueCast := c.builder.CreateBitCast(itfValue, llvm.PointerType(c.stringType, 0), "")
|
||||||
|
c.builder.CreateStore(val, itfValueCast)
|
||||||
} else {
|
} else {
|
||||||
return llvm.Value{}, errors.New("todo: make interface: unknown basic type")
|
return llvm.Value{}, errors.New("todo: make interface: unknown basic type")
|
||||||
}
|
}
|
||||||
|
@ -920,7 +961,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
return llvm.Value{}, errors.New("todo: make interface: unknown type")
|
return llvm.Value{}, errors.New("todo: make interface: unknown type")
|
||||||
}
|
}
|
||||||
itfType := c.getInterfaceType(expr.X.Type())
|
itfType := c.getInterfaceType(expr.X.Type())
|
||||||
itf := c.ctx.ConstStruct([]llvm.Value{itfType, llvm.Undef(llvm.PointerType(llvm.Int8Type(), 0))}, false)
|
itf := c.ctx.ConstStruct([]llvm.Value{itfType, llvm.Undef(c.i8ptrType)}, false)
|
||||||
itf = c.builder.CreateInsertValue(itf, itfValue, 1, "")
|
itf = c.builder.CreateInsertValue(itf, itfValue, 1, "")
|
||||||
return itf, nil
|
return itf, nil
|
||||||
case *ssa.Phi:
|
case *ssa.Phi:
|
||||||
|
@ -1057,34 +1098,34 @@ func (c *Compiler) parseBinOp(frame *Frame, binop *ssa.BinOp) (llvm.Value, error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) parseConst(expr *ssa.Const) (llvm.Value, error) {
|
func (c *Compiler) parseConst(expr *ssa.Const) (llvm.Value, error) {
|
||||||
switch expr.Value.Kind() {
|
typ := expr.Type()
|
||||||
case constant.Bool, constant.Int:
|
if named, ok := typ.(*types.Named); ok {
|
||||||
return c.parseConstInt(expr, expr.Type())
|
typ = named.Underlying()
|
||||||
case constant.String:
|
|
||||||
str := constant.StringVal(expr.Value)
|
|
||||||
strLen := llvm.ConstInt(c.stringLenType, uint64(len(str)), false)
|
|
||||||
strPtr := c.builder.CreateGlobalStringPtr(str, ".str") // TODO: remove \0 at end
|
|
||||||
strObj := llvm.ConstStruct([]llvm.Value{strLen, strPtr}, false)
|
|
||||||
return strObj, nil
|
|
||||||
default:
|
|
||||||
return llvm.Value{}, errors.New("todo: unknown constant: " + fmt.Sprintf("%#v", expr.Value.Kind()))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Compiler) parseConstInt(expr *ssa.Const, typ types.Type) (llvm.Value, error) {
|
|
||||||
switch typ := typ.(type) {
|
switch typ := typ.(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
llvmType, err := c.getLLVMType(typ)
|
llvmType, err := c.getLLVMType(typ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
if typ.Info() & types.IsBoolean != 0 {
|
if typ.Kind() == types.Bool {
|
||||||
b := constant.BoolVal(expr.Value)
|
b := constant.BoolVal(expr.Value)
|
||||||
n := uint64(0)
|
n := uint64(0)
|
||||||
if b {
|
if b {
|
||||||
n = 1
|
n = 1
|
||||||
}
|
}
|
||||||
return llvm.ConstInt(llvmType, n, false), nil
|
return llvm.ConstInt(llvmType, n, false), nil
|
||||||
|
} else if typ.Kind() == types.String {
|
||||||
|
str := constant.StringVal(expr.Value)
|
||||||
|
strLen := llvm.ConstInt(c.stringLenType, uint64(len(str)), false)
|
||||||
|
strPtr := c.builder.CreateGlobalStringPtr(str, ".str") // TODO: remove \0 at end
|
||||||
|
strObj := llvm.ConstStruct([]llvm.Value{strLen, strPtr}, false)
|
||||||
|
return strObj, nil
|
||||||
|
} else if typ.Kind() == types.UnsafePointer {
|
||||||
|
if !expr.IsNil() {
|
||||||
|
return llvm.Value{}, errors.New("todo: non-null constant pointer")
|
||||||
|
}
|
||||||
|
return llvm.ConstNull(c.i8ptrType), nil
|
||||||
} else if typ.Info() & types.IsUnsigned != 0 {
|
} else if typ.Info() & types.IsUnsigned != 0 {
|
||||||
n, _ := constant.Uint64Val(expr.Value)
|
n, _ := constant.Uint64Val(expr.Value)
|
||||||
return llvm.ConstInt(llvmType, n, false), nil
|
return llvm.ConstInt(llvmType, n, false), nil
|
||||||
|
@ -1092,34 +1133,40 @@ func (c *Compiler) parseConstInt(expr *ssa.Const, typ types.Type) (llvm.Value, e
|
||||||
n, _ := constant.Int64Val(expr.Value)
|
n, _ := constant.Int64Val(expr.Value)
|
||||||
return llvm.ConstInt(llvmType, uint64(n), true), nil
|
return llvm.ConstInt(llvmType, uint64(n), true), nil
|
||||||
} else {
|
} else {
|
||||||
return llvm.Value{}, errors.New("unknown integer constant")
|
return llvm.Value{}, errors.New("todo: unknown constant: " + fmt.Sprintf("%v", typ))
|
||||||
}
|
}
|
||||||
case *types.Named:
|
|
||||||
return c.parseConstInt(expr, typ.Underlying())
|
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, errors.New("todo: unknown constant: " + fmt.Sprintf("%#v", typ))
|
return llvm.Value{}, errors.New("todo: unknown constant: " + fmt.Sprintf("%#v", typ))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) parseConvert(frame *Frame, typeTo types.Type, x ssa.Value) (llvm.Value, error) {
|
func (c *Compiler) parseConvert(frame *Frame, typeTo types.Type, x ssa.Value) (llvm.Value, error) {
|
||||||
|
value, err := c.parseExpr(frame, x)
|
||||||
|
if err != nil {
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
llvmTypeFrom, err := c.getLLVMType(x.Type())
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
llvmTypeTo, err := c.getLLVMType(typeTo)
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
switch typeTo := typeTo.(type) {
|
switch typeTo := typeTo.(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
value, err := c.parseExpr(frame, x)
|
isPtrFrom := c.isPointer(x.Type())
|
||||||
if err != nil {
|
isPtrTo := c.isPointer(typeTo)
|
||||||
return value, nil
|
if isPtrFrom && !isPtrTo {
|
||||||
|
return c.builder.CreatePtrToInt(value, llvmTypeTo, ""), nil
|
||||||
|
} else if !isPtrFrom && isPtrTo {
|
||||||
|
return c.builder.CreateIntToPtr(value, llvmTypeTo, ""), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
llvmTypeFrom, err := c.getLLVMType(x.Type())
|
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
sizeFrom := c.targetData.TypeAllocSize(llvmTypeFrom)
|
sizeFrom := c.targetData.TypeAllocSize(llvmTypeFrom)
|
||||||
llvmTypeTo, err := c.getLLVMType(typeTo)
|
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
sizeTo := c.targetData.TypeAllocSize(llvmTypeTo)
|
sizeTo := c.targetData.TypeAllocSize(llvmTypeTo)
|
||||||
|
|
||||||
if sizeFrom == sizeTo {
|
if sizeFrom == sizeTo {
|
||||||
return c.builder.CreateBitCast(value, llvmTypeTo, ""), nil
|
return c.builder.CreateBitCast(value, llvmTypeTo, ""), nil
|
||||||
}
|
}
|
||||||
|
@ -1137,6 +1184,8 @@ func (c *Compiler) parseConvert(frame *Frame, typeTo types.Type, x ssa.Value) (l
|
||||||
}
|
}
|
||||||
case *types.Named:
|
case *types.Named:
|
||||||
return c.parseConvert(frame, typeTo.Underlying(), x)
|
return c.parseConvert(frame, typeTo.Underlying(), x)
|
||||||
|
case *types.Pointer:
|
||||||
|
return c.builder.CreateBitCast(value, llvmTypeTo, ""), nil
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, errors.New("todo: convert: extend non-basic type: " + fmt.Sprintf("%#v", typeTo))
|
return llvm.Value{}, errors.New("todo: convert: extend non-basic type: " + fmt.Sprintf("%#v", typeTo))
|
||||||
}
|
}
|
||||||
|
@ -1158,7 +1207,7 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
|
||||||
// Magic type name: treat the value as a register pointer.
|
// Magic type name: treat the value as a register pointer.
|
||||||
register := unop.X.(*ssa.FieldAddr)
|
register := unop.X.(*ssa.FieldAddr)
|
||||||
global := register.X.(*ssa.Global)
|
global := register.X.(*ssa.Global)
|
||||||
llvmGlobal := c.mod.NamedGlobal(pkgPrefix(global.Pkg) + "." + global.Name())
|
llvmGlobal := c.mod.NamedGlobal(c.getGlobalName(global))
|
||||||
llvmAddr := c.builder.CreateExtractValue(llvmGlobal.Initializer(), register.Field, "")
|
llvmAddr := c.builder.CreateExtractValue(llvmGlobal.Initializer(), register.Field, "")
|
||||||
ptr := llvm.ConstIntToPtr(llvmAddr, x.Type())
|
ptr := llvm.ConstIntToPtr(llvmAddr, x.Type())
|
||||||
load := c.builder.CreateLoad(ptr, "")
|
load := c.builder.CreateLoad(ptr, "")
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче