compiler: do not return an error from getLLVMType
This commit replaces "unknown type" errors in getLLVMType with panics. The main reason this is done is that it simplifies the code *a lot*. Many `if err != nil` lines were there just because of type information. Additionally, simply panicking is probably a better approach as the only way this error can be produced is either with big new language features or a serious compiler bug. Panicking is probably a better way to handle this error anyway.
Этот коммит содержится в:
родитель
6d23809218
коммит
c25fe609a9
6 изменённых файлов: 101 добавлений и 293 удалений
|
@ -12,10 +12,7 @@ import (
|
|||
|
||||
// emitMakeChan returns a new channel value for the given channel type.
|
||||
func (c *Compiler) emitMakeChan(expr *ssa.MakeChan) (llvm.Value, error) {
|
||||
valueType, err := c.getLLVMType(expr.Type().(*types.Chan).Elem())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
valueType := c.getLLVMType(expr.Type().(*types.Chan).Elem())
|
||||
if c.targetData.TypeAllocSize(valueType) > c.targetData.TypeAllocSize(c.intType) {
|
||||
// Values bigger than int overflow the data part of the coroutine.
|
||||
// TODO: make the coroutine data part big enough to hold these bigger
|
||||
|
@ -33,10 +30,7 @@ func (c *Compiler) emitMakeChan(expr *ssa.MakeChan) (llvm.Value, error) {
|
|||
// emitChanSend emits a pseudo chan send operation. It is lowered to the actual
|
||||
// channel send operation during goroutine lowering.
|
||||
func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) error {
|
||||
valueType, err := c.getLLVMType(instr.Chan.Type().(*types.Chan).Elem())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
valueType := c.getLLVMType(instr.Chan.Type().(*types.Chan).Elem())
|
||||
ch, err := c.parseExpr(frame, instr.Chan)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -56,10 +50,7 @@ func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) error {
|
|||
// emitChanRecv emits a pseudo chan receive operation. It is lowered to the
|
||||
// actual channel receive operation during goroutine lowering.
|
||||
func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
|
||||
valueType, err := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
valueType := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
|
||||
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
|
||||
ch, err := c.parseExpr(frame, unop.X)
|
||||
if err != nil {
|
||||
|
@ -83,11 +74,8 @@ func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) (llvm.Value, error
|
|||
|
||||
// emitChanClose closes the given channel.
|
||||
func (c *Compiler) emitChanClose(frame *Frame, param ssa.Value) error {
|
||||
valueType, err := c.getLLVMType(param.Type().(*types.Chan).Elem())
|
||||
valueType := c.getLLVMType(param.Type().(*types.Chan).Elem())
|
||||
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ch, err := c.parseExpr(frame, param)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -274,10 +274,7 @@ func (c *Compiler) Compile(mainPath string) error {
|
|||
for _, t := range c.ir.NamedTypes {
|
||||
if named, ok := t.Type.Type().(*types.Named); ok {
|
||||
if st, ok := named.Underlying().(*types.Struct); ok {
|
||||
llvmType, err := c.getLLVMType(st)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
llvmType := c.getLLVMType(st)
|
||||
t.LLVMType.StructSetBody(llvmType.StructElementTypes(), false)
|
||||
}
|
||||
}
|
||||
|
@ -286,10 +283,7 @@ func (c *Compiler) Compile(mainPath string) error {
|
|||
// Declare all globals.
|
||||
for _, g := range c.ir.Globals {
|
||||
typ := g.Type().(*types.Pointer).Elem()
|
||||
llvmType, err := c.getLLVMType(typ)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
llvmType := c.getLLVMType(typ)
|
||||
global := c.mod.NamedGlobal(g.LinkName())
|
||||
if global.IsNil() {
|
||||
global = llvm.AddGlobal(c.mod, llvmType, g.LinkName())
|
||||
|
@ -303,11 +297,7 @@ func (c *Compiler) Compile(mainPath string) error {
|
|||
|
||||
// Declare all functions.
|
||||
for _, f := range c.ir.Functions {
|
||||
frame, err := c.parseFuncDecl(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frames = append(frames, frame)
|
||||
frames = append(frames, c.parseFuncDecl(f))
|
||||
}
|
||||
|
||||
// Add definitions to declarations.
|
||||
|
@ -330,10 +320,7 @@ func (c *Compiler) Compile(mainPath string) error {
|
|||
// Define the already declared functions that wrap methods for use in
|
||||
// interfaces.
|
||||
for _, state := range c.interfaceInvokeWrappers {
|
||||
err = c.createInterfaceInvokeWrapper(state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.createInterfaceInvokeWrapper(state)
|
||||
}
|
||||
|
||||
// After all packages are imported, add a synthetic initializer function
|
||||
|
@ -342,10 +329,7 @@ func (c *Compiler) Compile(mainPath string) error {
|
|||
initFn.LLVMFn.SetLinkage(llvm.InternalLinkage)
|
||||
initFn.LLVMFn.SetUnnamedAddr(true)
|
||||
if c.Debug {
|
||||
difunc, err := c.attachDebugInfo(initFn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
difunc := c.attachDebugInfo(initFn)
|
||||
pos := c.ir.Program.Fset.Position(initFn.Pos())
|
||||
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
|
||||
}
|
||||
|
@ -411,87 +395,74 @@ func (c *Compiler) Compile(mainPath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Compiler) getLLVMType(goType types.Type) (llvm.Type, error) {
|
||||
func (c *Compiler) getLLVMType(goType types.Type) llvm.Type {
|
||||
switch typ := goType.(type) {
|
||||
case *types.Array:
|
||||
elemType, err := c.getLLVMType(typ.Elem())
|
||||
if err != nil {
|
||||
return llvm.Type{}, err
|
||||
}
|
||||
return llvm.ArrayType(elemType, int(typ.Len())), nil
|
||||
elemType := c.getLLVMType(typ.Elem())
|
||||
return llvm.ArrayType(elemType, int(typ.Len()))
|
||||
case *types.Basic:
|
||||
switch typ.Kind() {
|
||||
case types.Bool, types.UntypedBool:
|
||||
return c.ctx.Int1Type(), nil
|
||||
return c.ctx.Int1Type()
|
||||
case types.Int8, types.Uint8:
|
||||
return c.ctx.Int8Type(), nil
|
||||
return c.ctx.Int8Type()
|
||||
case types.Int16, types.Uint16:
|
||||
return c.ctx.Int16Type(), nil
|
||||
return c.ctx.Int16Type()
|
||||
case types.Int32, types.Uint32:
|
||||
return c.ctx.Int32Type(), nil
|
||||
return c.ctx.Int32Type()
|
||||
case types.Int, types.Uint:
|
||||
return c.intType, nil
|
||||
return c.intType
|
||||
case types.Int64, types.Uint64:
|
||||
return c.ctx.Int64Type(), nil
|
||||
return c.ctx.Int64Type()
|
||||
case types.Float32:
|
||||
return c.ctx.FloatType(), nil
|
||||
return c.ctx.FloatType()
|
||||
case types.Float64:
|
||||
return c.ctx.DoubleType(), nil
|
||||
return c.ctx.DoubleType()
|
||||
case types.Complex64:
|
||||
return c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false), nil
|
||||
return c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false)
|
||||
case types.Complex128:
|
||||
return c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false), nil
|
||||
return c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false)
|
||||
case types.String, types.UntypedString:
|
||||
return c.mod.GetTypeByName("runtime._string"), nil
|
||||
return c.mod.GetTypeByName("runtime._string")
|
||||
case types.Uintptr:
|
||||
return c.uintptrType, nil
|
||||
return c.uintptrType
|
||||
case types.UnsafePointer:
|
||||
return c.i8ptrType, nil
|
||||
return c.i8ptrType
|
||||
default:
|
||||
return llvm.Type{}, errors.New("todo: unknown basic type: " + typ.String())
|
||||
panic("unknown basic type: " + typ.String())
|
||||
}
|
||||
case *types.Chan:
|
||||
return llvm.PointerType(c.mod.GetTypeByName("runtime.channel"), 0), nil
|
||||
return llvm.PointerType(c.mod.GetTypeByName("runtime.channel"), 0)
|
||||
case *types.Interface:
|
||||
return c.mod.GetTypeByName("runtime._interface"), nil
|
||||
return c.mod.GetTypeByName("runtime._interface")
|
||||
case *types.Map:
|
||||
return llvm.PointerType(c.mod.GetTypeByName("runtime.hashmap"), 0), nil
|
||||
return llvm.PointerType(c.mod.GetTypeByName("runtime.hashmap"), 0)
|
||||
case *types.Named:
|
||||
if _, ok := typ.Underlying().(*types.Struct); ok {
|
||||
llvmType := c.mod.GetTypeByName(typ.Obj().Pkg().Path() + "." + typ.Obj().Name())
|
||||
if llvmType.IsNil() {
|
||||
return llvm.Type{}, errors.New("type not found: " + typ.Obj().Pkg().Path() + "." + typ.Obj().Name())
|
||||
panic("underlying type not found: " + typ.Obj().Pkg().Path() + "." + typ.Obj().Name())
|
||||
}
|
||||
return llvmType, nil
|
||||
return llvmType
|
||||
}
|
||||
return c.getLLVMType(typ.Underlying())
|
||||
case *types.Pointer:
|
||||
ptrTo, err := c.getLLVMType(typ.Elem())
|
||||
if err != nil {
|
||||
return llvm.Type{}, err
|
||||
}
|
||||
return llvm.PointerType(ptrTo, 0), nil
|
||||
ptrTo := c.getLLVMType(typ.Elem())
|
||||
return llvm.PointerType(ptrTo, 0)
|
||||
case *types.Signature: // function value
|
||||
return c.getFuncType(typ)
|
||||
case *types.Slice:
|
||||
elemType, err := c.getLLVMType(typ.Elem())
|
||||
if err != nil {
|
||||
return llvm.Type{}, err
|
||||
}
|
||||
elemType := c.getLLVMType(typ.Elem())
|
||||
members := []llvm.Type{
|
||||
llvm.PointerType(elemType, 0),
|
||||
c.uintptrType, // len
|
||||
c.uintptrType, // cap
|
||||
}
|
||||
return c.ctx.StructType(members, false), nil
|
||||
return c.ctx.StructType(members, false)
|
||||
case *types.Struct:
|
||||
members := make([]llvm.Type, typ.NumFields())
|
||||
for i := 0; i < typ.NumFields(); i++ {
|
||||
member, err := c.getLLVMType(typ.Field(i).Type())
|
||||
if err != nil {
|
||||
return llvm.Type{}, err
|
||||
}
|
||||
members[i] = member
|
||||
members[i] = c.getLLVMType(typ.Field(i).Type())
|
||||
}
|
||||
if len(members) > 2 && typ.Field(0).Name() == "C union" {
|
||||
// Not a normal struct but a C union emitted by cgo.
|
||||
|
@ -520,19 +491,15 @@ func (c *Compiler) getLLVMType(goType types.Type) (llvm.Type, error) {
|
|||
members = append(members, llvm.ArrayType(c.ctx.Int8Type(), int(maxSize-mainTypeSize)))
|
||||
}
|
||||
}
|
||||
return c.ctx.StructType(members, false), nil
|
||||
return c.ctx.StructType(members, false)
|
||||
case *types.Tuple:
|
||||
members := make([]llvm.Type, typ.Len())
|
||||
for i := 0; i < typ.Len(); i++ {
|
||||
member, err := c.getLLVMType(typ.At(i).Type())
|
||||
if err != nil {
|
||||
return llvm.Type{}, err
|
||||
}
|
||||
members[i] = member
|
||||
members[i] = c.getLLVMType(typ.At(i).Type())
|
||||
}
|
||||
return c.ctx.StructType(members, false), nil
|
||||
return c.ctx.StructType(members, false)
|
||||
default:
|
||||
return llvm.Type{}, errors.New("todo: unknown type: " + goType.String())
|
||||
panic("unknown type: " + goType.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -584,15 +551,12 @@ func isPointer(typ types.Type) bool {
|
|||
}
|
||||
|
||||
// Get the DWARF type for this Go type.
|
||||
func (c *Compiler) getDIType(typ types.Type) (llvm.Metadata, error) {
|
||||
func (c *Compiler) getDIType(typ types.Type) llvm.Metadata {
|
||||
name := typ.String()
|
||||
if dityp, ok := c.ditypes[name]; ok {
|
||||
return dityp, nil
|
||||
return dityp
|
||||
} else {
|
||||
llvmType, err := c.getLLVMType(typ)
|
||||
if err != nil {
|
||||
return llvm.Metadata{}, err
|
||||
}
|
||||
llvmType := c.getLLVMType(typ)
|
||||
sizeInBytes := c.targetData.TypeAllocSize(llvmType)
|
||||
var encoding llvm.DwarfTypeEncoding
|
||||
switch typ := typ.(type) {
|
||||
|
@ -620,11 +584,11 @@ func (c *Compiler) getDIType(typ types.Type) (llvm.Metadata, error) {
|
|||
Encoding: encoding,
|
||||
})
|
||||
c.ditypes[name] = dityp
|
||||
return dityp, nil
|
||||
return dityp
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Compiler) parseFuncDecl(f *ir.Function) (*Frame, error) {
|
||||
func (c *Compiler) parseFuncDecl(f *ir.Function) *Frame {
|
||||
frame := &Frame{
|
||||
fn: f,
|
||||
locals: make(map[ssa.Value]llvm.Value),
|
||||
|
@ -636,29 +600,18 @@ func (c *Compiler) parseFuncDecl(f *ir.Function) (*Frame, error) {
|
|||
if f.Signature.Results() == nil {
|
||||
retType = c.ctx.VoidType()
|
||||
} else if f.Signature.Results().Len() == 1 {
|
||||
var err error
|
||||
retType, err = c.getLLVMType(f.Signature.Results().At(0).Type())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retType = c.getLLVMType(f.Signature.Results().At(0).Type())
|
||||
} else {
|
||||
results := make([]llvm.Type, 0, f.Signature.Results().Len())
|
||||
for i := 0; i < f.Signature.Results().Len(); i++ {
|
||||
typ, err := c.getLLVMType(f.Signature.Results().At(i).Type())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, typ)
|
||||
results = append(results, c.getLLVMType(f.Signature.Results().At(i).Type()))
|
||||
}
|
||||
retType = c.ctx.StructType(results, false)
|
||||
}
|
||||
|
||||
var paramTypes []llvm.Type
|
||||
for _, param := range f.Params {
|
||||
paramType, err := c.getLLVMType(param.Type())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paramType := c.getLLVMType(param.Type())
|
||||
paramTypeFragments := c.expandFormalParamType(paramType)
|
||||
paramTypes = append(paramTypes, paramTypeFragments...)
|
||||
}
|
||||
|
@ -678,15 +631,15 @@ func (c *Compiler) parseFuncDecl(f *ir.Function) (*Frame, error) {
|
|||
frame.fn.LLVMFn = llvm.AddFunction(c.mod, name, fnType)
|
||||
}
|
||||
|
||||
return frame, nil
|
||||
return frame
|
||||
}
|
||||
|
||||
func (c *Compiler) attachDebugInfo(f *ir.Function) (llvm.Metadata, error) {
|
||||
func (c *Compiler) attachDebugInfo(f *ir.Function) llvm.Metadata {
|
||||
pos := c.ir.Program.Fset.Position(f.Syntax().Pos())
|
||||
return c.attachDebugInfoRaw(f, f.LLVMFn, "", pos.Filename, pos.Line)
|
||||
}
|
||||
|
||||
func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix, filename string, line int) (llvm.Metadata, error) {
|
||||
func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix, filename string, line int) llvm.Metadata {
|
||||
if _, ok := c.difiles[filename]; !ok {
|
||||
dir, file := filepath.Split(filename)
|
||||
if dir != "" {
|
||||
|
@ -698,11 +651,7 @@ func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix,
|
|||
// Debug info for this function.
|
||||
diparams := make([]llvm.Metadata, 0, len(f.Params))
|
||||
for _, param := range f.Params {
|
||||
ditype, err := c.getDIType(param.Type())
|
||||
if err != nil {
|
||||
return llvm.Metadata{}, err
|
||||
}
|
||||
diparams = append(diparams, ditype)
|
||||
diparams = append(diparams, c.getDIType(param.Type()))
|
||||
}
|
||||
diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
|
||||
File: c.difiles[filename],
|
||||
|
@ -722,7 +671,7 @@ func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix,
|
|||
Optimized: true,
|
||||
})
|
||||
llvmFn.SetSubprogram(difunc)
|
||||
return difunc, nil
|
||||
return difunc
|
||||
}
|
||||
|
||||
func (c *Compiler) parseFunc(frame *Frame) error {
|
||||
|
@ -742,18 +691,10 @@ func (c *Compiler) parseFunc(frame *Frame) error {
|
|||
if frame.fn.Synthetic == "package initializer" {
|
||||
// Package initializers have no debug info. Create some fake debug
|
||||
// info to at least have *something*.
|
||||
difunc, err := c.attachDebugInfoRaw(frame.fn, frame.fn.LLVMFn, "", "", 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frame.difunc = difunc
|
||||
frame.difunc = c.attachDebugInfoRaw(frame.fn, frame.fn.LLVMFn, "", "", 0)
|
||||
} else if frame.fn.Syntax() != nil {
|
||||
// Create debug info file if needed.
|
||||
difunc, err := c.attachDebugInfo(frame.fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frame.difunc = difunc
|
||||
frame.difunc = c.attachDebugInfo(frame.fn)
|
||||
}
|
||||
pos := c.ir.Program.Fset.Position(frame.fn.Pos())
|
||||
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), frame.difunc, llvm.Metadata{})
|
||||
|
@ -771,10 +712,7 @@ func (c *Compiler) parseFunc(frame *Frame) error {
|
|||
// Load function parameters
|
||||
llvmParamIndex := 0
|
||||
for i, param := range frame.fn.Params {
|
||||
llvmType, err := c.getLLVMType(param.Type())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
llvmType := c.getLLVMType(param.Type())
|
||||
fields := make([]llvm.Value, 0, 1)
|
||||
for range c.expandFormalParamType(llvmType) {
|
||||
fields = append(fields, frame.fn.LLVMFn.Param(llvmParamIndex))
|
||||
|
@ -785,15 +723,11 @@ func (c *Compiler) parseFunc(frame *Frame) error {
|
|||
// Add debug information to this parameter (if available)
|
||||
if c.Debug && frame.fn.Syntax() != nil {
|
||||
pos := c.ir.Program.Fset.Position(frame.fn.Syntax().Pos())
|
||||
dityp, err := c.getDIType(param.Type())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.dibuilder.CreateParameterVariable(frame.difunc, llvm.DIParameterVariable{
|
||||
Name: param.Name(),
|
||||
File: c.difiles[pos.Filename],
|
||||
Line: pos.Line,
|
||||
Type: dityp,
|
||||
Type: c.getDIType(param.Type()),
|
||||
AlwaysPreserve: true,
|
||||
ArgNo: i + 1,
|
||||
})
|
||||
|
@ -814,11 +748,7 @@ func (c *Compiler) parseFunc(frame *Frame) error {
|
|||
// Determine the context type. It's a struct containing all variables.
|
||||
freeVarTypes := make([]llvm.Type, 0, len(frame.fn.FreeVars))
|
||||
for _, freeVar := range frame.fn.FreeVars {
|
||||
typ, err := c.getLLVMType(freeVar.Type())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
freeVarTypes = append(freeVarTypes, typ)
|
||||
freeVarTypes = append(freeVarTypes, c.getLLVMType(freeVar.Type()))
|
||||
}
|
||||
contextType := c.ctx.StructType(freeVarTypes, false)
|
||||
|
||||
|
@ -1346,10 +1276,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
|
||||
switch expr := expr.(type) {
|
||||
case *ssa.Alloc:
|
||||
typ, err := c.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
typ := c.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
||||
var buf llvm.Value
|
||||
if expr.Heap {
|
||||
size := c.targetData.TypeAllocSize(typ)
|
||||
|
@ -1400,10 +1327,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmType, err := c.getLLVMType(expr.Type())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmType := c.getLLVMType(expr.Type())
|
||||
if x.Type() == llvmType {
|
||||
// Different Go type but same LLVM type (for example, named int).
|
||||
// This is the common case.
|
||||
|
@ -1452,10 +1376,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
// Extract a field from a CGo union.
|
||||
// This could be done directly, but as this is a very infrequent
|
||||
// operation it's much easier to bitcast it through an alloca.
|
||||
resultType, err := c.getLLVMType(expr.Type())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
resultType := c.getLLVMType(expr.Type())
|
||||
alloca := c.builder.CreateAlloca(value.Type(), "")
|
||||
c.builder.CreateStore(value, alloca)
|
||||
bitcast := c.builder.CreateBitCast(alloca, llvm.PointerType(resultType, 0), "")
|
||||
|
@ -1477,10 +1398,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
// This is not a regular struct but actually an union.
|
||||
// That simplifies things, as we can just bitcast the pointer to the
|
||||
// right type.
|
||||
ptrType, err := c.getLLVMType(expr.Type())
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil
|
||||
}
|
||||
ptrType := c.getLLVMType(expr.Type())
|
||||
return c.builder.CreateBitCast(val, ptrType, ""), nil
|
||||
} else {
|
||||
// Do a GEP on the pointer to get the field address.
|
||||
|
@ -1495,7 +1413,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
if fn.IsExported() {
|
||||
return llvm.Value{}, c.makeError(expr.Pos(), "cannot use an exported function as value")
|
||||
}
|
||||
return c.createFuncValue(fn.LLVMFn, llvm.Undef(c.i8ptrType), fn.Signature)
|
||||
return c.createFuncValue(fn.LLVMFn, llvm.Undef(c.i8ptrType), fn.Signature), nil
|
||||
case *ssa.Global:
|
||||
value := c.ir.GetGlobal(expr).LLVMGlobal
|
||||
if value.IsNil() {
|
||||
|
@ -1620,14 +1538,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
return c.parseMakeInterface(val, expr.X.Type(), expr.Pos())
|
||||
case *ssa.MakeMap:
|
||||
mapType := expr.Type().Underlying().(*types.Map)
|
||||
llvmKeyType, err := c.getLLVMType(mapType.Key().Underlying())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmValueType, err := c.getLLVMType(mapType.Elem().Underlying())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmKeyType := c.getLLVMType(mapType.Key().Underlying())
|
||||
llvmValueType := c.getLLVMType(mapType.Elem().Underlying())
|
||||
keySize := c.targetData.TypeAllocSize(llvmKeyType)
|
||||
valueSize := c.targetData.TypeAllocSize(llvmValueType)
|
||||
llvmKeySize := llvm.ConstInt(c.ctx.Int8Type(), keySize, false)
|
||||
|
@ -1644,10 +1556,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
return llvm.Value{}, nil
|
||||
}
|
||||
sliceType := expr.Type().Underlying().(*types.Slice)
|
||||
llvmElemType, err := c.getLLVMType(sliceType.Elem())
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil
|
||||
}
|
||||
llvmElemType := c.getLLVMType(sliceType.Elem())
|
||||
elemSize := c.targetData.TypeAllocSize(llvmElemType)
|
||||
elemSizeValue := llvm.ConstInt(c.uintptrType, elemSize, false)
|
||||
|
||||
|
@ -1707,14 +1616,8 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
if expr.IsString {
|
||||
return c.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil
|
||||
} else { // map
|
||||
llvmKeyType, err := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmValueType, err := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmKeyType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
|
||||
llvmValueType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
|
||||
|
||||
mapKeyAlloca := c.builder.CreateAlloca(llvmKeyType, "range.key")
|
||||
mapKeyPtr := c.builder.CreateBitCast(mapKeyAlloca, c.i8ptrType, "range.keyptr")
|
||||
|
@ -1729,11 +1632,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
return tuple, nil
|
||||
}
|
||||
case *ssa.Phi:
|
||||
t, err := c.getLLVMType(expr.Type())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
phi := c.builder.CreatePHI(t, "")
|
||||
phi := c.builder.CreatePHI(c.getLLVMType(expr.Type()), "")
|
||||
frame.phis = append(frame.phis, Phi{expr, phi})
|
||||
return phi, nil
|
||||
case *ssa.Range:
|
||||
|
@ -1752,10 +1651,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
case *ssa.Select:
|
||||
if len(expr.States) == 0 {
|
||||
// Shortcuts for some simple selects.
|
||||
llvmType, err := c.getLLVMType(expr.Type())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmType := c.getLLVMType(expr.Type())
|
||||
if expr.Blocking {
|
||||
// Blocks forever:
|
||||
// select {}
|
||||
|
@ -2225,10 +2121,7 @@ func (c *Compiler) parseBinOp(op token.Token, typ types.Type, x, y llvm.Value, p
|
|||
func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error) {
|
||||
switch typ := expr.Type().Underlying().(type) {
|
||||
case *types.Basic:
|
||||
llvmType, err := c.getLLVMType(typ)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmType := c.getLLVMType(typ)
|
||||
if typ.Info()&types.IsBoolean != 0 {
|
||||
b := constant.BoolVal(expr.Value)
|
||||
n := uint64(0)
|
||||
|
@ -2294,20 +2187,12 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
|||
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
|
||||
}
|
||||
case *types.Chan:
|
||||
sig, err := c.getLLVMType(expr.Type())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
return c.getZeroValue(sig), nil
|
||||
return c.getZeroValue(c.getLLVMType(expr.Type())), nil
|
||||
case *types.Signature:
|
||||
if expr.Value != nil {
|
||||
return llvm.Value{}, errors.New("non-nil signature constant")
|
||||
}
|
||||
sig, err := c.getLLVMType(expr.Type())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
return c.getZeroValue(sig), nil
|
||||
return c.getZeroValue(c.getLLVMType(expr.Type())), nil
|
||||
case *types.Interface:
|
||||
if expr.Value != nil {
|
||||
return llvm.Value{}, errors.New("non-nil interface constant")
|
||||
|
@ -2323,19 +2208,12 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
|||
if expr.Value != nil {
|
||||
return llvm.Value{}, errors.New("non-nil pointer constant")
|
||||
}
|
||||
llvmType, err := c.getLLVMType(typ)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
return llvm.ConstPointerNull(llvmType), nil
|
||||
return llvm.ConstPointerNull(c.getLLVMType(typ)), nil
|
||||
case *types.Slice:
|
||||
if expr.Value != nil {
|
||||
return llvm.Value{}, errors.New("non-nil slice constant")
|
||||
}
|
||||
elemType, err := c.getLLVMType(typ.Elem())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
elemType := c.getLLVMType(typ.Elem())
|
||||
llvmPtr := llvm.ConstPointerNull(llvm.PointerType(elemType, 0))
|
||||
llvmLen := llvm.ConstInt(c.uintptrType, 0, false)
|
||||
slice := c.ctx.ConstStruct([]llvm.Value{
|
||||
|
@ -2349,10 +2227,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
|||
// I believe this is not allowed by the Go spec.
|
||||
panic("non-nil map constant")
|
||||
}
|
||||
llvmType, err := c.getLLVMType(typ)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmType := c.getLLVMType(typ)
|
||||
return c.getZeroValue(llvmType), nil
|
||||
default:
|
||||
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
|
||||
|
@ -2361,10 +2236,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
|||
|
||||
func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, pos token.Pos) (llvm.Value, error) {
|
||||
llvmTypeFrom := value.Type()
|
||||
llvmTypeTo, err := c.getLLVMType(typeTo)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmTypeTo := c.getLLVMType(typeTo)
|
||||
|
||||
// Conversion between unsafe.Pointer and uintptr.
|
||||
isPtrFrom := isPointer(typeFrom.Underlying())
|
||||
|
|
|
@ -217,11 +217,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) error {
|
|||
// Get the real defer struct type and cast to it.
|
||||
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0), c.i8ptrType}
|
||||
for _, arg := range callback.Args {
|
||||
llvmType, err := c.getLLVMType(arg.Type())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
valueTypes = append(valueTypes, llvmType)
|
||||
valueTypes = append(valueTypes, c.getLLVMType(arg.Type()))
|
||||
}
|
||||
deferFrameType := c.ctx.StructType(valueTypes, false)
|
||||
deferFramePtr := c.builder.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||
|
@ -255,11 +251,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) error {
|
|||
// Get the real defer struct type and cast to it.
|
||||
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0)}
|
||||
for _, param := range callback.Params {
|
||||
llvmType, err := c.getLLVMType(param.Type())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
valueTypes = append(valueTypes, llvmType)
|
||||
valueTypes = append(valueTypes, c.getLLVMType(param.Type()))
|
||||
}
|
||||
deferFrameType := c.ctx.StructType(valueTypes, false)
|
||||
deferFramePtr := c.builder.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||
|
@ -289,11 +281,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) error {
|
|||
valueTypes := []llvm.Type{c.uintptrType, llvm.PointerType(c.mod.GetTypeByName("runtime._defer"), 0)}
|
||||
params := fn.Signature.Params()
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
llvmType, err := c.getLLVMType(params.At(i).Type())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
valueTypes = append(valueTypes, llvmType)
|
||||
valueTypes = append(valueTypes, c.getLLVMType(params.At(i).Type()))
|
||||
}
|
||||
valueTypes = append(valueTypes, c.i8ptrType) // closure
|
||||
deferFrameType := c.ctx.StructType(valueTypes, false)
|
||||
|
|
|
@ -41,7 +41,7 @@ func (c *Compiler) funcImplementation() funcValueImplementation {
|
|||
|
||||
// createFuncValue creates a function value from a raw function pointer with no
|
||||
// context.
|
||||
func (c *Compiler) createFuncValue(funcPtr, context llvm.Value, sig *types.Signature) (llvm.Value, error) {
|
||||
func (c *Compiler) createFuncValue(funcPtr, context llvm.Value, sig *types.Signature) llvm.Value {
|
||||
var funcValueScalar llvm.Value
|
||||
switch c.funcImplementation() {
|
||||
case funcValueDoubleword:
|
||||
|
@ -66,14 +66,11 @@ func (c *Compiler) createFuncValue(funcPtr, context llvm.Value, sig *types.Signa
|
|||
default:
|
||||
panic("unimplemented func value variant")
|
||||
}
|
||||
funcValueType, err := c.getFuncType(sig)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
funcValueType := c.getFuncType(sig)
|
||||
funcValue := llvm.Undef(funcValueType)
|
||||
funcValue = c.builder.CreateInsertValue(funcValue, context, 0, "")
|
||||
funcValue = c.builder.CreateInsertValue(funcValue, funcValueScalar, 1, "")
|
||||
return funcValue, nil
|
||||
return funcValue
|
||||
}
|
||||
|
||||
// getFuncSignature returns a global for identification of a particular function
|
||||
|
@ -112,10 +109,7 @@ func (c *Compiler) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (
|
|||
case funcValueDoubleword:
|
||||
funcPtr = c.builder.CreateExtractValue(funcValue, 1, "")
|
||||
case funcValueSwitch:
|
||||
llvmSig, err := c.getRawFuncType(sig)
|
||||
if err != nil {
|
||||
return llvm.Value{}, llvm.Value{}, err
|
||||
}
|
||||
llvmSig := c.getRawFuncType(sig)
|
||||
sigGlobal := c.getFuncSignature(sig)
|
||||
funcPtr = c.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "")
|
||||
funcPtr = c.builder.CreateIntToPtr(funcPtr, llvmSig, "")
|
||||
|
@ -126,25 +120,21 @@ func (c *Compiler) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (
|
|||
}
|
||||
|
||||
// getFuncType returns the type of a func value given a signature.
|
||||
func (c *Compiler) getFuncType(typ *types.Signature) (llvm.Type, error) {
|
||||
func (c *Compiler) getFuncType(typ *types.Signature) llvm.Type {
|
||||
switch c.funcImplementation() {
|
||||
case funcValueDoubleword:
|
||||
rawPtr, err := c.getRawFuncType(typ)
|
||||
if err != nil {
|
||||
return llvm.Type{}, err
|
||||
}
|
||||
return c.ctx.StructType([]llvm.Type{c.i8ptrType, rawPtr}, false), nil
|
||||
rawPtr := c.getRawFuncType(typ)
|
||||
return c.ctx.StructType([]llvm.Type{c.i8ptrType, rawPtr}, false)
|
||||
case funcValueSwitch:
|
||||
return c.mod.GetTypeByName("runtime.funcValue"), nil
|
||||
return c.mod.GetTypeByName("runtime.funcValue")
|
||||
default:
|
||||
panic("unimplemented func value variant")
|
||||
}
|
||||
}
|
||||
|
||||
// getRawFuncType returns a LLVM function pointer type for a given signature.
|
||||
func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
|
||||
func (c *Compiler) getRawFuncType(typ *types.Signature) llvm.Type {
|
||||
// Get the return type.
|
||||
var err error
|
||||
var returnType llvm.Type
|
||||
switch typ.Results().Len() {
|
||||
case 0:
|
||||
|
@ -152,21 +142,14 @@ func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
|
|||
returnType = c.ctx.VoidType()
|
||||
case 1:
|
||||
// Just one return value.
|
||||
returnType, err = c.getLLVMType(typ.Results().At(0).Type())
|
||||
if err != nil {
|
||||
return llvm.Type{}, err
|
||||
}
|
||||
returnType = c.getLLVMType(typ.Results().At(0).Type())
|
||||
default:
|
||||
// Multiple return values. Put them together in a struct.
|
||||
// This appears to be the common way to handle multiple return values in
|
||||
// LLVM.
|
||||
members := make([]llvm.Type, typ.Results().Len())
|
||||
for i := 0; i < typ.Results().Len(); i++ {
|
||||
returnType, err := c.getLLVMType(typ.Results().At(i).Type())
|
||||
if err != nil {
|
||||
return llvm.Type{}, err
|
||||
}
|
||||
members[i] = returnType
|
||||
members[i] = c.getLLVMType(typ.Results().At(i).Type())
|
||||
}
|
||||
returnType = c.ctx.StructType(members, false)
|
||||
}
|
||||
|
@ -174,10 +157,7 @@ func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
|
|||
// Get the parameter types.
|
||||
var paramTypes []llvm.Type
|
||||
if typ.Recv() != nil {
|
||||
recv, err := c.getLLVMType(typ.Recv().Type())
|
||||
if err != nil {
|
||||
return llvm.Type{}, err
|
||||
}
|
||||
recv := c.getLLVMType(typ.Recv().Type())
|
||||
if recv.StructName() == "runtime._interface" {
|
||||
// This is a call on an interface, not a concrete type.
|
||||
// The receiver is not an interface, but a i8* type.
|
||||
|
@ -186,10 +166,7 @@ func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
|
|||
paramTypes = append(paramTypes, c.expandFormalParamType(recv)...)
|
||||
}
|
||||
for i := 0; i < typ.Params().Len(); i++ {
|
||||
subType, err := c.getLLVMType(typ.Params().At(i).Type())
|
||||
if err != nil {
|
||||
return llvm.Type{}, err
|
||||
}
|
||||
subType := c.getLLVMType(typ.Params().At(i).Type())
|
||||
paramTypes = append(paramTypes, c.expandFormalParamType(subType)...)
|
||||
}
|
||||
// All functions take these parameters at the end.
|
||||
|
@ -197,7 +174,7 @@ func (c *Compiler) getRawFuncType(typ *types.Signature) (llvm.Type, error) {
|
|||
paramTypes = append(paramTypes, c.i8ptrType) // parent coroutine
|
||||
|
||||
// Make a func type out of the signature.
|
||||
return llvm.PointerType(llvm.FunctionType(returnType, paramTypes, false), c.funcPtrAddrSpace), nil
|
||||
return llvm.PointerType(llvm.FunctionType(returnType, paramTypes, false), c.funcPtrAddrSpace)
|
||||
}
|
||||
|
||||
// parseMakeClosure makes a function value (with context) from the given
|
||||
|
@ -261,5 +238,5 @@ func (c *Compiler) parseMakeClosure(frame *Frame, expr *ssa.MakeClosure) (llvm.V
|
|||
}
|
||||
|
||||
// Create the closure.
|
||||
return c.createFuncValue(f.LLVMFn, context, f.Signature)
|
||||
return c.createFuncValue(f.LLVMFn, context, f.Signature), nil
|
||||
}
|
||||
|
|
|
@ -279,10 +279,7 @@ func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Val
|
|||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
assertedType, err := c.getLLVMType(expr.AssertedType)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
assertedType := c.getLLVMType(expr.AssertedType)
|
||||
|
||||
actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type")
|
||||
commaOk := llvm.Value{}
|
||||
|
@ -389,10 +386,7 @@ func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Valu
|
|||
return llvm.Value{}, nil, err
|
||||
}
|
||||
|
||||
llvmFnType, err := c.getRawFuncType(instr.Method.Type().(*types.Signature))
|
||||
if err != nil {
|
||||
return llvm.Value{}, nil, err
|
||||
}
|
||||
llvmFnType := c.getRawFuncType(instr.Method.Type().(*types.Signature))
|
||||
|
||||
typecode := c.builder.CreateExtractValue(itf, 0, "invoke.typecode")
|
||||
values := []llvm.Value{
|
||||
|
@ -443,10 +437,7 @@ func (c *Compiler) getInterfaceInvokeWrapper(f *ir.Function) (llvm.Value, error)
|
|||
}
|
||||
|
||||
// Get the expanded receiver type.
|
||||
receiverType, err := c.getLLVMType(f.Params[0].Type())
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
receiverType := c.getLLVMType(f.Params[0].Type())
|
||||
expandedReceiverType := c.expandFormalParamType(receiverType)
|
||||
|
||||
// Does this method even need any wrapping?
|
||||
|
@ -473,7 +464,7 @@ func (c *Compiler) getInterfaceInvokeWrapper(f *ir.Function) (llvm.Value, error)
|
|||
|
||||
// createInterfaceInvokeWrapper finishes the work of getInterfaceInvokeWrapper,
|
||||
// see that function for details.
|
||||
func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) error {
|
||||
func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) {
|
||||
wrapper := state.wrapper
|
||||
fn := state.fn
|
||||
receiverType := state.receiverType
|
||||
|
@ -483,10 +474,7 @@ func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) er
|
|||
// add debug info if needed
|
||||
if c.Debug {
|
||||
pos := c.ir.Program.Fset.Position(fn.Pos())
|
||||
difunc, err := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
difunc := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line)
|
||||
c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
|
||||
}
|
||||
|
||||
|
@ -524,6 +512,4 @@ func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) er
|
|||
ret := c.builder.CreateCall(fn.LLVMFn, params, "ret")
|
||||
c.builder.CreateRet(ret)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -10,10 +10,7 @@ import (
|
|||
)
|
||||
|
||||
func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Value, commaOk bool, pos token.Pos) (llvm.Value, error) {
|
||||
llvmValueType, err := c.getLLVMType(valueType)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
llvmValueType := c.getLLVMType(valueType)
|
||||
mapValueAlloca := c.builder.CreateAlloca(llvmValueType, "hashmap.value")
|
||||
mapValuePtr := c.builder.CreateBitCast(mapValueAlloca, c.i8ptrType, "hashmap.valueptr")
|
||||
var commaOkValue llvm.Value
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче