func (fr *frame) memsetZero(ptr llvm.Value, size llvm.Value) { memset := fr.runtime.memset ptr = fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "") fill := llvm.ConstNull(llvm.Int8Type()) size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "") align := llvm.ConstInt(llvm.Int32Type(), 1, false) isvolatile := llvm.ConstNull(llvm.Int1Type()) fr.builder.CreateCall(memset, []llvm.Value{ptr, fill, size, align, isvolatile}, "") }
func (fr *frame) memcpy(dest llvm.Value, src llvm.Value, size llvm.Value) { memcpy := fr.runtime.memcpy dest = fr.builder.CreateBitCast(dest, llvm.PointerType(llvm.Int8Type(), 0), "") src = fr.builder.CreateBitCast(src, llvm.PointerType(llvm.Int8Type(), 0), "") size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "") align := llvm.ConstInt(llvm.Int32Type(), 1, false) isvolatile := llvm.ConstNull(llvm.Int1Type()) fr.builder.CreateCall(memcpy, []llvm.Value{dest, src, size, align, isvolatile}, "") }
// interfaceMethod returns a function and receiver pointer for the specified // interface and method pair. func (fr *frame) interfaceMethod(lliface llvm.Value, ifacety types.Type, method *types.Func) (fn, recv *govalue) { llitab := fr.builder.CreateExtractValue(lliface, 0, "") recv = newValue(fr.builder.CreateExtractValue(lliface, 1, ""), types.Typ[types.UnsafePointer]) methodset := fr.types.MethodSet(ifacety) // TODO(axw) cache ordered method index index := -1 for i, m := range orderedMethodSet(methodset) { if m.Obj() == method { index = i break } } if index == -1 { panic("could not find method index") } llitab = fr.builder.CreateBitCast(llitab, llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0), "") // Skip runtime type pointer. llifnptr := fr.builder.CreateGEP(llitab, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), uint64(index+1), false), }, "") llifn := fr.builder.CreateLoad(llifnptr, "") // Replace receiver type with unsafe.Pointer. recvparam := types.NewParam(0, nil, "", types.Typ[types.UnsafePointer]) sig := method.Type().(*types.Signature) sig = types.NewSignature(nil, recvparam, sig.Params(), sig.Results(), sig.Variadic()) fn = newValue(llifn, sig) return }
func (fr *frame) compareStrings(lhs, rhs *govalue, op token.Token) *govalue { if op == token.EQL { if lhs.value.IsNull() { return fr.compareStringEmpty(rhs.value) } if rhs.value.IsNull() { return fr.compareStringEmpty(lhs.value) } } result := fr.runtime.strcmp.call(fr, lhs.value, rhs.value)[0] zero := llvm.ConstNull(fr.types.inttype) var pred llvm.IntPredicate switch op { case token.EQL: pred = llvm.IntEQ case token.LSS: pred = llvm.IntSLT case token.GTR: pred = llvm.IntSGT case token.LEQ: pred = llvm.IntSLE case token.GEQ: pred = llvm.IntSGE case token.NEQ: panic("NEQ is handled in govalue.BinaryOp") default: panic("unreachable") } result = fr.builder.CreateICmp(pred, result, zero, "") result = fr.builder.CreateZExt(result, llvm.Int8Type(), "") return newValue(result, types.Typ[types.Bool]) }
func (fr *frame) chanSelect(sel *ssa.Select) (index, recvOk *govalue, recvElems []*govalue) { n := uint64(len(sel.States)) if !sel.Blocking { // non-blocking means there's a default case n++ } size := llvm.ConstInt(llvm.Int32Type(), n, false) selectp := fr.runtime.newSelect.call(fr, size)[0] // Allocate stack for the values to send and receive. ptrs := make([]llvm.Value, len(sel.States)) for i, state := range sel.States { chantyp := state.Chan.Type().Underlying().(*types.Chan) elemtyp := fr.types.ToLLVM(chantyp.Elem()) if state.Dir == types.SendOnly { ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "") fr.builder.CreateStore(fr.llvmvalue(state.Send), ptrs[i]) } else { // Only allocate stack space if the received value is used. used := chanSelectStateUsed(sel, len(recvElems)) if used { ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "") } else { ptrs[i] = llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0)) } recvElems = append(recvElems, newValue(ptrs[i], chantyp.Elem())) } } // Create select{send,recv2} calls. var receivedp llvm.Value if len(recvElems) > 0 { receivedp = fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(types.Typ[types.Bool]), "") } if !sel.Blocking { // If the default case is chosen, the index must be -1. fr.runtime.selectdefault.call(fr, selectp, llvm.ConstAllOnes(llvm.Int32Type())) } for i, state := range sel.States { ch := fr.llvmvalue(state.Chan) index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false) if state.Dir == types.SendOnly { fr.runtime.selectsend.call(fr, selectp, ch, ptrs[i], index) } else { fr.runtime.selectrecv2.call(fr, selectp, ch, ptrs[i], receivedp, index) } } // Fire off the select. index = newValue(fr.runtime.selectgo.call(fr, selectp)[0], types.Typ[types.Int]) if len(recvElems) > 0 { recvOk = newValue(fr.builder.CreateLoad(receivedp, ""), types.Typ[types.Bool]) for _, recvElem := range recvElems { recvElem.value = fr.builder.CreateLoad(recvElem.value, "") } } return index, recvOk, recvElems }
// chanSend implements ch<- x func (fr *frame) chanSend(ch *govalue, elem *govalue) { elemtyp := ch.Type().Underlying().(*types.Chan).Elem() elem = fr.convert(elem, elemtyp) elemptr := fr.allocaBuilder.CreateAlloca(elem.value.Type(), "") fr.builder.CreateStore(elem.value, elemptr) elemptr = fr.builder.CreateBitCast(elemptr, llvm.PointerType(llvm.Int8Type(), 0), "") chantyp := fr.types.ToRuntime(ch.Type()) fr.runtime.sendBig.call(fr, chantyp, ch.value, elemptr) }
func (fr *frame) makeInterfaceFromPointer(vptr llvm.Value, vty types.Type, iface types.Type) *govalue { i8ptr := llvm.PointerType(llvm.Int8Type(), 0) llv := fr.builder.CreateBitCast(vptr, i8ptr, "") value := llvm.Undef(fr.types.ToLLVM(iface)) itab := fr.types.getItabPointer(vty, iface.Underlying().(*types.Interface)) value = fr.builder.CreateInsertValue(value, itab, 0, "") value = fr.builder.CreateInsertValue(value, llv, 1, "") return newValue(value, iface) }
func (fr *frame) createLandingPad(cleanup bool) llvm.Value { lp := fr.builder.CreateLandingPad(fr.runtime.gccgoExceptionType, fr.runtime.gccgoPersonality, 0, "") if cleanup { lp.SetCleanup(true) } else { lp.AddClause(llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0))) } return lp }
// resolveFunctionDescriptorGlobal returns a reference to the LLVM global // storing the function's descriptor. func (u *unit) resolveFunctionDescriptorGlobal(f *ssa.Function) llvm.Value { llfd, ok := u.funcDescriptors[f] if !ok { name := u.types.mc.mangleFunctionName(f) + "$descriptor" llfd = llvm.AddGlobal(u.module.Module, llvm.PointerType(llvm.Int8Type(), 0), name) llfd.SetGlobalConstant(true) u.funcDescriptors[f] = llfd } return llfd }
func (u *unit) addGlobal(global llvm.Value, ty types.Type) { u.globalInits[global] = new(globalInit) if hasPointers(ty) { global = llvm.ConstBitCast(global, llvm.PointerType(llvm.Int8Type(), 0)) size := llvm.ConstInt(u.types.inttype, uint64(u.types.Sizeof(ty)), false) root := llvm.ConstStruct([]llvm.Value{global, size}, false) u.gcRoots = append(u.gcRoots, root) } }
// stringIterNext advances the iterator, and returns the tuple (ok, k, v). func (fr *frame) stringIterNext(iter []*govalue) []*govalue { str, indexptr := iter[0], iter[1] k := fr.builder.CreateLoad(indexptr.value, "") result := fr.runtime.stringiter2.call(fr, str.value, k) fr.builder.CreateStore(result[0], indexptr.value) ok := fr.builder.CreateIsNotNull(result[0], "") ok = fr.builder.CreateZExt(ok, llvm.Int8Type(), "") v := result[1] return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, types.Typ[types.Int]), newValue(v, types.Typ[types.Rune])} }
// makeMap implements make(maptype[, initial space]) func (fr *frame) makeMap(typ types.Type, cap_ *govalue) *govalue { // TODO(pcc): call __go_new_map_big here if needed dyntyp := fr.types.getMapDescriptorPointer(typ) dyntyp = fr.builder.CreateBitCast(dyntyp, llvm.PointerType(llvm.Int8Type(), 0), "") var cap llvm.Value if cap_ != nil { cap = fr.convert(cap_, types.Typ[types.Uintptr]).value } else { cap = llvm.ConstNull(fr.types.inttype) } m := fr.runtime.newMap.call(fr, dyntyp, cap) return newValue(m[0], typ) }
func (fr *frame) registerGcRoots() { if len(fr.gcRoots) != 0 { rootty := fr.gcRoots[0].Type() roots := append(fr.gcRoots, llvm.ConstNull(rootty)) rootsarr := llvm.ConstArray(rootty, roots) rootsstruct := llvm.ConstStruct([]llvm.Value{llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0)), rootsarr}, false) rootsglobal := llvm.AddGlobal(fr.module.Module, rootsstruct.Type(), "") rootsglobal.SetInitializer(rootsstruct) rootsglobal.SetLinkage(llvm.InternalLinkage) fr.runtime.registerGcRoots.callOnly(fr, llvm.ConstBitCast(rootsglobal, llvm.PointerType(llvm.Int8Type(), 0))) } }
// mapLookup implements v[, ok] = m[k] func (fr *frame) mapLookup(m, k *govalue) (v *govalue, ok *govalue) { llk := k.value pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "") fr.builder.CreateStore(llk, pk) valptr := fr.runtime.mapIndex.call(fr, m.value, pk, boolLLVMValue(false))[0] valptr.AddInstrAttribute(2, llvm.NoCaptureAttribute) valptr.AddInstrAttribute(2, llvm.ReadOnlyAttribute) okbit := fr.builder.CreateIsNotNull(valptr, "") elemtyp := m.Type().Underlying().(*types.Map).Elem() ok = newValue(fr.builder.CreateZExt(okbit, llvm.Int8Type(), ""), types.Typ[types.Bool]) v = fr.loadOrNull(okbit, valptr, elemtyp) return }
// chanRecv implements x[, ok] = <-ch func (fr *frame) chanRecv(ch *govalue, commaOk bool) (x, ok *govalue) { elemtyp := ch.Type().Underlying().(*types.Chan).Elem() ptr := fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(elemtyp), "") ptri8 := fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "") chantyp := fr.types.ToRuntime(ch.Type()) if commaOk { okval := fr.runtime.chanrecv2.call(fr, chantyp, ch.value, ptri8)[0] ok = newValue(okval, types.Typ[types.Bool]) } else { fr.runtime.receive.call(fr, chantyp, ch.value, ptri8) } x = newValue(fr.builder.CreateLoad(ptr, ""), elemtyp) return }
// callInstruction translates function call instructions. func (fr *frame) callInstruction(instr ssa.CallInstruction) []*govalue { call := instr.Common() if builtin, ok := call.Value.(*ssa.Builtin); ok { var typ types.Type if v := instr.Value(); v != nil { typ = v.Type() } return fr.callBuiltin(typ, builtin, call.Args) } args := make([]*govalue, len(call.Args)) for i, arg := range call.Args { args[i] = fr.value(arg) } var fn *govalue var chain llvm.Value if call.IsInvoke() { var recv *govalue fn, recv = fr.interfaceMethod(fr.llvmvalue(call.Value), call.Value.Type(), call.Method) args = append([]*govalue{recv}, args...) } else { if ssafn, ok := call.Value.(*ssa.Function); ok { llfn := fr.resolveFunctionGlobal(ssafn) llfn = llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0)) fn = newValue(llfn, ssafn.Type()) } else { // First-class function values are stored as *{*fnptr}, so // we must extract the function pointer. We must also // set the chain, in case the function is a closure. fn = fr.value(call.Value) chain = fn.value fnptr := fr.builder.CreateBitCast(fn.value, llvm.PointerType(fn.value.Type(), 0), "") fnptr = fr.builder.CreateLoad(fnptr, "") fn = newValue(fnptr, fn.Type()) } if recv := call.Signature().Recv(); recv != nil { if _, ok := recv.Type().Underlying().(*types.Pointer); !ok { recvalloca := fr.allocaBuilder.CreateAlloca(args[0].value.Type(), "") fr.builder.CreateStore(args[0].value, recvalloca) args[0] = newValue(recvalloca, types.NewPointer(args[0].Type())) } } } return fr.createCall(fn, chain, args) }
// compareInterfaces emits code to compare two interfaces for // equality. func (fr *frame) compareInterfaces(a, b *govalue) *govalue { aNull := a.value.IsNull() bNull := b.value.IsNull() if aNull && bNull { return newValue(boolLLVMValue(true), types.Typ[types.Bool]) } compare := fr.runtime.emptyInterfaceCompare aI := a.Type().Underlying().(*types.Interface).NumMethods() > 0 bI := b.Type().Underlying().(*types.Interface).NumMethods() > 0 switch { case aI && bI: compare = fr.runtime.interfaceCompare case aI: a = fr.convertI2E(a) case bI: b = fr.convertI2E(b) } result := compare.call(fr, a.value, b.value)[0] result = fr.builder.CreateIsNull(result, "") result = fr.builder.CreateZExt(result, llvm.Int8Type(), "") return newValue(result, types.Typ[types.Bool]) }
// createThunk creates a thunk from a // given function and arguments, suitable for use with // "defer" and "go". func (fr *frame) createThunk(call ssa.CallInstruction) (thunk llvm.Value, arg llvm.Value) { seenarg := make(map[ssa.Value]bool) var args []ssa.Value var argtypes []*types.Var packArg := func(arg ssa.Value) { switch arg.(type) { case *ssa.Builtin, *ssa.Function, *ssa.Const, *ssa.Global: // Do nothing: we can generate these in the thunk default: if !seenarg[arg] { seenarg[arg] = true args = append(args, arg) field := types.NewField(0, nil, "_", arg.Type(), true) argtypes = append(argtypes, field) } } } packArg(call.Common().Value) for _, arg := range call.Common().Args { packArg(arg) } var isRecoverCall bool i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var structllptr llvm.Type if len(args) == 0 { if builtin, ok := call.Common().Value.(*ssa.Builtin); ok { isRecoverCall = builtin.Name() == "recover" } if isRecoverCall { // When creating a thunk for recover(), we must pass fr.canRecover. arg = fr.builder.CreateZExt(fr.canRecover, fr.target.IntPtrType(), "") arg = fr.builder.CreateIntToPtr(arg, i8ptr, "") } else { arg = llvm.ConstPointerNull(i8ptr) } } else { structtype := types.NewStruct(argtypes, nil) arg = fr.createTypeMalloc(structtype) structllptr = arg.Type() for i, ssaarg := range args { argptr := fr.builder.CreateStructGEP(arg, i, "") fr.builder.CreateStore(fr.llvmvalue(ssaarg), argptr) } arg = fr.builder.CreateBitCast(arg, i8ptr, "") } thunkfntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{i8ptr}, false) thunkfn := llvm.AddFunction(fr.module.Module, "", thunkfntype) thunkfn.SetLinkage(llvm.InternalLinkage) fr.addCommonFunctionAttrs(thunkfn) thunkfr := newFrame(fr.unit, thunkfn) defer thunkfr.dispose() prologuebb := llvm.AddBasicBlock(thunkfn, "prologue") thunkfr.builder.SetInsertPointAtEnd(prologuebb) if isRecoverCall { thunkarg := thunkfn.Param(0) thunkarg = thunkfr.builder.CreatePtrToInt(thunkarg, fr.target.IntPtrType(), "") thunkfr.canRecover = thunkfr.builder.CreateTrunc(thunkarg, llvm.Int1Type(), "") } else if len(args) > 0 { thunkarg := thunkfn.Param(0) thunkarg = thunkfr.builder.CreateBitCast(thunkarg, structllptr, "") for i, ssaarg := range args { thunkargptr := thunkfr.builder.CreateStructGEP(thunkarg, i, "") thunkarg := thunkfr.builder.CreateLoad(thunkargptr, "") thunkfr.env[ssaarg] = newValue(thunkarg, ssaarg.Type()) } } _, isDefer := call.(*ssa.Defer) entrybb := llvm.AddBasicBlock(thunkfn, "entry") br := thunkfr.builder.CreateBr(entrybb) thunkfr.allocaBuilder.SetInsertPointBefore(br) thunkfr.builder.SetInsertPointAtEnd(entrybb) var exitbb llvm.BasicBlock if isDefer { exitbb = llvm.AddBasicBlock(thunkfn, "exit") thunkfr.runtime.setDeferRetaddr.call(thunkfr, llvm.BlockAddress(thunkfn, exitbb)) } if isDefer && isRecoverCall { thunkfr.callRecover(true) } else { thunkfr.callInstruction(call) } if isDefer { thunkfr.builder.CreateBr(exitbb) thunkfr.builder.SetInsertPointAtEnd(exitbb) } thunkfr.builder.CreateRetVoid() thunk = fr.builder.CreateBitCast(thunkfn, i8ptr, "") return }
func (fr *frame) slice(x llvm.Value, xtyp types.Type, low, high, max llvm.Value) llvm.Value { if !low.IsNil() { low = fr.createZExtOrTrunc(low, fr.types.inttype, "") } else { low = llvm.ConstNull(fr.types.inttype) } if !high.IsNil() { high = fr.createZExtOrTrunc(high, fr.types.inttype, "") } if !max.IsNil() { max = fr.createZExtOrTrunc(max, fr.types.inttype, "") } var arrayptr, arraylen, arraycap llvm.Value var elemtyp types.Type var errcode uint64 switch typ := xtyp.Underlying().(type) { case *types.Pointer: // *array errcode = gccgoRuntimeErrorARRAY_SLICE_OUT_OF_BOUNDS arraytyp := typ.Elem().Underlying().(*types.Array) elemtyp = arraytyp.Elem() arrayptr = x arrayptr = fr.builder.CreateBitCast(arrayptr, llvm.PointerType(llvm.Int8Type(), 0), "") arraylen = llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false) arraycap = arraylen case *types.Slice: errcode = gccgoRuntimeErrorSLICE_SLICE_OUT_OF_BOUNDS elemtyp = typ.Elem() arrayptr = fr.builder.CreateExtractValue(x, 0, "") arraylen = fr.builder.CreateExtractValue(x, 1, "") arraycap = fr.builder.CreateExtractValue(x, 2, "") case *types.Basic: if high.IsNil() { high = llvm.ConstAllOnes(fr.types.inttype) // -1 } result := fr.runtime.stringSlice.call(fr, x, low, high) return result[0] default: panic("unimplemented") } if high.IsNil() { high = arraylen } if max.IsNil() { max = arraycap } // Bounds checking: 0 <= low <= high <= max <= cap zero := llvm.ConstNull(fr.types.inttype) l0 := fr.builder.CreateICmp(llvm.IntSLT, low, zero, "") hl := fr.builder.CreateICmp(llvm.IntSLT, high, low, "") mh := fr.builder.CreateICmp(llvm.IntSLT, max, high, "") cm := fr.builder.CreateICmp(llvm.IntSLT, arraycap, max, "") cond := fr.builder.CreateOr(l0, hl, "") cond = fr.builder.CreateOr(cond, mh, "") cond = fr.builder.CreateOr(cond, cm, "") fr.condBrRuntimeError(cond, errcode) slicelen := fr.builder.CreateSub(high, low, "") slicecap := fr.builder.CreateSub(max, low, "") elemsize := llvm.ConstInt(fr.llvmtypes.inttype, uint64(fr.llvmtypes.Sizeof(elemtyp)), false) offset := fr.builder.CreateMul(low, elemsize, "") sliceptr := fr.builder.CreateInBoundsGEP(arrayptr, []llvm.Value{offset}, "") llslicetyp := fr.llvmtypes.sliceBackendType().ToLLVM(fr.llvmtypes.ctx) sliceValue := llvm.Undef(llslicetyp) sliceValue = fr.builder.CreateInsertValue(sliceValue, sliceptr, 0, "") sliceValue = fr.builder.CreateInsertValue(sliceValue, slicelen, 1, "") sliceValue = fr.builder.CreateInsertValue(sliceValue, slicecap, 2, "") return sliceValue }
func (fr *frame) instruction(instr ssa.Instruction) { fr.logf("[%T] %v @ %s\n", instr, instr, fr.pkg.Prog.Fset.Position(instr.Pos())) if fr.GenerateDebug { fr.debug.SetLocation(fr.builder, instr.Pos()) } switch instr := instr.(type) { case *ssa.Alloc: typ := deref(instr.Type()) llvmtyp := fr.llvmtypes.ToLLVM(typ) var value llvm.Value if !instr.Heap { value = fr.env[instr].value fr.memsetZero(value, llvm.SizeOf(llvmtyp)) } else if fr.isInit && fr.shouldStaticallyAllocate(instr) { // If this is the init function and we think it may be beneficial, // allocate memory statically in the object file rather than on the // heap. This allows us to optimize constant stores into such // variables as static initializations. global := llvm.AddGlobal(fr.module.Module, llvmtyp, "") global.SetLinkage(llvm.InternalLinkage) fr.addGlobal(global, typ) ptr := llvm.ConstBitCast(global, llvm.PointerType(llvm.Int8Type(), 0)) fr.env[instr] = newValue(ptr, instr.Type()) } else { value = fr.createTypeMalloc(typ) value.SetName(instr.Comment) value = fr.builder.CreateBitCast(value, llvm.PointerType(llvm.Int8Type(), 0), "") fr.env[instr] = newValue(value, instr.Type()) } case *ssa.BinOp: lhs, rhs := fr.value(instr.X), fr.value(instr.Y) fr.env[instr] = fr.binaryOp(lhs, instr.Op, rhs) case *ssa.Call: tuple := fr.callInstruction(instr) if len(tuple) == 1 { fr.env[instr] = tuple[0] } else { fr.tuples[instr] = tuple } case *ssa.ChangeInterface: x := fr.value(instr.X) // The source type must be a non-empty interface, // as ChangeInterface cannot fail (E2I may fail). if instr.Type().Underlying().(*types.Interface).NumMethods() > 0 { x = fr.changeInterface(x, instr.Type(), false) } else { x = fr.convertI2E(x) } fr.env[instr] = x case *ssa.ChangeType: value := fr.llvmvalue(instr.X) if _, ok := instr.Type().Underlying().(*types.Pointer); ok { value = fr.builder.CreateBitCast(value, fr.llvmtypes.ToLLVM(instr.Type()), "") } fr.env[instr] = newValue(value, instr.Type()) case *ssa.Convert: v := fr.value(instr.X) fr.env[instr] = fr.convert(v, instr.Type()) case *ssa.Defer: fn, arg := fr.createThunk(instr) fr.runtime.Defer.call(fr, fr.frameptr, fn, arg) case *ssa.Extract: var elem llvm.Value if t, ok := fr.tuples[instr.Tuple]; ok { elem = t[instr.Index].value } else { tuple := fr.llvmvalue(instr.Tuple) elem = fr.builder.CreateExtractValue(tuple, instr.Index, instr.Name()) } elemtyp := instr.Type() fr.env[instr] = newValue(elem, elemtyp) case *ssa.Field: fieldtyp := instr.Type() if p, ok := fr.ptr[instr.X]; ok { field := fr.builder.CreateStructGEP(p, instr.Field, instr.Name()) if fr.canAvoidElementLoad(*instr.Referrers()) { fr.ptr[instr] = field } else { fr.env[instr] = newValue(fr.builder.CreateLoad(field, ""), fieldtyp) } } else { value := fr.llvmvalue(instr.X) field := fr.builder.CreateExtractValue(value, instr.Field, instr.Name()) fr.env[instr] = newValue(field, fieldtyp) } case *ssa.FieldAddr: ptr := fr.llvmvalue(instr.X) fr.nilCheck(instr.X, ptr) xtyp := instr.X.Type().Underlying().(*types.Pointer).Elem() ptrtyp := llvm.PointerType(fr.llvmtypes.ToLLVM(xtyp), 0) ptr = fr.builder.CreateBitCast(ptr, ptrtyp, "") fieldptr := fr.builder.CreateStructGEP(ptr, instr.Field, instr.Name()) fieldptr = fr.builder.CreateBitCast(fieldptr, llvm.PointerType(llvm.Int8Type(), 0), "") fieldptrtyp := instr.Type() fr.env[instr] = newValue(fieldptr, fieldptrtyp) case *ssa.Go: fn, arg := fr.createThunk(instr) fr.runtime.Go.call(fr, fn, arg) case *ssa.If: cond := fr.llvmvalue(instr.Cond) block := instr.Block() trueBlock := fr.block(block.Succs[0]) falseBlock := fr.block(block.Succs[1]) cond = fr.builder.CreateTrunc(cond, llvm.Int1Type(), "") fr.builder.CreateCondBr(cond, trueBlock, falseBlock) case *ssa.Index: var arrayptr llvm.Value if ptr, ok := fr.ptr[instr.X]; ok { arrayptr = ptr } else { array := fr.llvmvalue(instr.X) arrayptr = fr.allocaBuilder.CreateAlloca(array.Type(), "") fr.builder.CreateStore(array, arrayptr) } index := fr.llvmvalue(instr.Index) arraytyp := instr.X.Type().Underlying().(*types.Array) arraylen := llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false) // The index may not have been promoted to int (for example, if it // came from a composite literal). index = fr.createZExtOrTrunc(index, fr.types.inttype, "") // Bounds checking: 0 <= index < len zero := llvm.ConstNull(fr.types.inttype) i0 := fr.builder.CreateICmp(llvm.IntSLT, index, zero, "") li := fr.builder.CreateICmp(llvm.IntSLE, arraylen, index, "") cond := fr.builder.CreateOr(i0, li, "") fr.condBrRuntimeError(cond, gccgoRuntimeErrorARRAY_INDEX_OUT_OF_BOUNDS) addr := fr.builder.CreateGEP(arrayptr, []llvm.Value{zero, index}, "") if fr.canAvoidElementLoad(*instr.Referrers()) { fr.ptr[instr] = addr } else { fr.env[instr] = newValue(fr.builder.CreateLoad(addr, ""), instr.Type()) } case *ssa.IndexAddr: x := fr.llvmvalue(instr.X) index := fr.llvmvalue(instr.Index) var arrayptr, arraylen llvm.Value var elemtyp types.Type var errcode uint64 switch typ := instr.X.Type().Underlying().(type) { case *types.Slice: elemtyp = typ.Elem() arrayptr = fr.builder.CreateExtractValue(x, 0, "") arraylen = fr.builder.CreateExtractValue(x, 1, "") errcode = gccgoRuntimeErrorSLICE_INDEX_OUT_OF_BOUNDS case *types.Pointer: // *array arraytyp := typ.Elem().Underlying().(*types.Array) elemtyp = arraytyp.Elem() fr.nilCheck(instr.X, x) arrayptr = x arraylen = llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false) errcode = gccgoRuntimeErrorARRAY_INDEX_OUT_OF_BOUNDS } // The index may not have been promoted to int (for example, if it // came from a composite literal). index = fr.createZExtOrTrunc(index, fr.types.inttype, "") // Bounds checking: 0 <= index < len zero := llvm.ConstNull(fr.types.inttype) i0 := fr.builder.CreateICmp(llvm.IntSLT, index, zero, "") li := fr.builder.CreateICmp(llvm.IntSLE, arraylen, index, "") cond := fr.builder.CreateOr(i0, li, "") fr.condBrRuntimeError(cond, errcode) ptrtyp := llvm.PointerType(fr.llvmtypes.ToLLVM(elemtyp), 0) arrayptr = fr.builder.CreateBitCast(arrayptr, ptrtyp, "") addr := fr.builder.CreateGEP(arrayptr, []llvm.Value{index}, "") addr = fr.builder.CreateBitCast(addr, llvm.PointerType(llvm.Int8Type(), 0), "") fr.env[instr] = newValue(addr, types.NewPointer(elemtyp)) case *ssa.Jump: succ := instr.Block().Succs[0] fr.builder.CreateBr(fr.block(succ)) case *ssa.Lookup: x := fr.value(instr.X) index := fr.value(instr.Index) if isString(x.Type().Underlying()) { fr.env[instr] = fr.stringIndex(x, index) } else { v, ok := fr.mapLookup(x, index) if instr.CommaOk { fr.tuples[instr] = []*govalue{v, ok} } else { fr.env[instr] = v } } case *ssa.MakeChan: fr.env[instr] = fr.makeChan(instr.Type(), fr.value(instr.Size)) case *ssa.MakeClosure: llfn := fr.resolveFunctionGlobal(instr.Fn.(*ssa.Function)) llfn = llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0)) fn := newValue(llfn, instr.Fn.(*ssa.Function).Signature) bindings := make([]*govalue, len(instr.Bindings)) for i, binding := range instr.Bindings { bindings[i] = fr.value(binding) } fr.env[instr] = fr.makeClosure(fn, bindings) case *ssa.MakeInterface: // fr.ptr[instr.X] will be set if a pointer load was elided by canAvoidLoad if ptr, ok := fr.ptr[instr.X]; ok { fr.env[instr] = fr.makeInterfaceFromPointer(ptr, instr.X.Type(), instr.Type()) } else { receiver := fr.llvmvalue(instr.X) fr.env[instr] = fr.makeInterface(receiver, instr.X.Type(), instr.Type()) } case *ssa.MakeMap: fr.env[instr] = fr.makeMap(instr.Type(), fr.value(instr.Reserve)) case *ssa.MakeSlice: length := fr.value(instr.Len) capacity := fr.value(instr.Cap) fr.env[instr] = fr.makeSlice(instr.Type(), length, capacity) case *ssa.MapUpdate: m := fr.value(instr.Map) k := fr.value(instr.Key) v := fr.value(instr.Value) fr.mapUpdate(m, k, v) case *ssa.Next: iter := fr.tuples[instr.Iter] if instr.IsString { fr.tuples[instr] = fr.stringIterNext(iter) } else { fr.tuples[instr] = fr.mapIterNext(iter) } case *ssa.Panic: arg := fr.value(instr.X) fr.callPanic(arg) case *ssa.Phi: typ := instr.Type() phi := fr.builder.CreatePHI(fr.llvmtypes.ToLLVM(typ), instr.Comment) fr.env[instr] = newValue(phi, typ) fr.phis = append(fr.phis, pendingPhi{instr, phi}) case *ssa.Range: x := fr.value(instr.X) switch x.Type().Underlying().(type) { case *types.Map: fr.tuples[instr] = fr.mapIterInit(x) case *types.Basic: // string fr.tuples[instr] = fr.stringIterInit(x) default: panic(fmt.Sprintf("unhandled range for type %T", x.Type())) } case *ssa.Return: vals := make([]llvm.Value, len(instr.Results)) for i, res := range instr.Results { vals[i] = fr.llvmvalue(res) } fr.retInf.encode(llvm.GlobalContext(), fr.allocaBuilder, fr.builder, vals) case *ssa.RunDefers: fr.runDefers() case *ssa.Select: states := make([]selectState, len(instr.States)) for i, state := range instr.States { states[i] = selectState{ Dir: state.Dir, Chan: fr.value(state.Chan), Send: fr.value(state.Send), } } index, recvOk, recvElems := fr.chanSelect(states, instr.Blocking) tuple := append([]*govalue{index, recvOk}, recvElems...) fr.tuples[instr] = tuple case *ssa.Send: fr.chanSend(fr.value(instr.Chan), fr.value(instr.X)) case *ssa.Slice: x := fr.llvmvalue(instr.X) low := fr.llvmvalue(instr.Low) high := fr.llvmvalue(instr.High) max := fr.llvmvalue(instr.Max) slice := fr.slice(x, instr.X.Type(), low, high, max) fr.env[instr] = newValue(slice, instr.Type()) case *ssa.Store: addr := fr.llvmvalue(instr.Addr) value := fr.llvmvalue(instr.Val) addr = fr.builder.CreateBitCast(addr, llvm.PointerType(value.Type(), 0), "") // If this is the init function, see if we can simulate the effect // of the store in a global's initializer, in which case we can avoid // generating code for it. if !fr.isInit || !fr.maybeStoreInInitializer(value, addr) { fr.nilCheck(instr.Addr, addr) fr.builder.CreateStore(value, addr) } case *ssa.TypeAssert: x := fr.value(instr.X) if instr.CommaOk { v, ok := fr.interfaceTypeCheck(x, instr.AssertedType) fr.tuples[instr] = []*govalue{v, ok} } else { fr.env[instr] = fr.interfaceTypeAssert(x, instr.AssertedType) } case *ssa.UnOp: operand := fr.value(instr.X) switch instr.Op { case token.ARROW: x, ok := fr.chanRecv(operand, instr.CommaOk) if instr.CommaOk { fr.tuples[instr] = []*govalue{x, ok} } else { fr.env[instr] = x } case token.MUL: fr.nilCheck(instr.X, operand.value) if !fr.canAvoidLoad(instr, operand.value) { // The bitcast is necessary to handle recursive pointer loads. llptr := fr.builder.CreateBitCast(operand.value, llvm.PointerType(fr.llvmtypes.ToLLVM(instr.Type()), 0), "") fr.env[instr] = newValue(fr.builder.CreateLoad(llptr, ""), instr.Type()) } default: fr.env[instr] = fr.unaryOp(operand, instr.Op) } default: panic(fmt.Sprintf("unhandled: %v", instr)) } }
func (u *unit) defineFunction(f *ssa.Function) { // Only define functions from this package, or synthetic // wrappers (which do not have a package). if f.Pkg != nil && f.Pkg != u.pkg { return } llfn := u.resolveFunctionGlobal(f) linkage := u.getFunctionLinkage(f) isMethod := f.Signature.Recv() != nil // Methods cannot be referred to via a descriptor. if !isMethod { llfd := u.resolveFunctionDescriptorGlobal(f) llfd.SetInitializer(llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0))) llfd.SetLinkage(linkage) } // We only need to emit a descriptor for functions without bodies. if len(f.Blocks) == 0 { return } ssaopt.LowerAllocsToStack(f) if u.DumpSSA { f.WriteTo(os.Stderr) } fr := newFrame(u, llfn) defer fr.dispose() fr.addCommonFunctionAttrs(fr.function) fr.function.SetLinkage(linkage) fr.logf("Define function: %s", f.String()) fti := u.llvmtypes.getSignatureInfo(f.Signature) delete(u.undefinedFuncs, f) fr.retInf = fti.retInf // Push the compile unit and function onto the debug context. if u.GenerateDebug { u.debug.PushFunction(fr.function, f.Signature, f.Pos()) defer u.debug.PopFunction() u.debug.SetLocation(fr.builder, f.Pos()) } // If a function calls recover, we create a separate function to // hold the real function, and this function calls __go_can_recover // and bridges to it. if callsRecover(f) { fr = fr.bridgeRecoverFunc(fr.function, fti) } fr.blocks = make([]llvm.BasicBlock, len(f.Blocks)) fr.lastBlocks = make([]llvm.BasicBlock, len(f.Blocks)) for i, block := range f.Blocks { fr.blocks[i] = llvm.AddBasicBlock(fr.function, fmt.Sprintf(".%d.%s", i, block.Comment)) } fr.builder.SetInsertPointAtEnd(fr.blocks[0]) prologueBlock := llvm.InsertBasicBlock(fr.blocks[0], "prologue") fr.builder.SetInsertPointAtEnd(prologueBlock) // Map parameter positions to indices. We use this // when processing locals to map back to parameters // when generating debug metadata. paramPos := make(map[token.Pos]int) for i, param := range f.Params { paramPos[param.Pos()] = i llparam := fti.argInfos[i].decode(llvm.GlobalContext(), fr.builder, fr.builder) if isMethod && i == 0 { if _, ok := param.Type().Underlying().(*types.Pointer); !ok { llparam = fr.builder.CreateBitCast(llparam, llvm.PointerType(fr.types.ToLLVM(param.Type()), 0), "") llparam = fr.builder.CreateLoad(llparam, "") } } fr.env[param] = newValue(llparam, param.Type()) } // Load closure, extract free vars. if len(f.FreeVars) > 0 { for _, fv := range f.FreeVars { fr.env[fv] = newValue(llvm.ConstNull(u.llvmtypes.ToLLVM(fv.Type())), fv.Type()) } elemTypes := make([]llvm.Type, len(f.FreeVars)+1) elemTypes[0] = llvm.PointerType(llvm.Int8Type(), 0) // function pointer for i, fv := range f.FreeVars { elemTypes[i+1] = u.llvmtypes.ToLLVM(fv.Type()) } structType := llvm.StructType(elemTypes, false) closure := fr.runtime.getClosure.call(fr)[0] closure = fr.builder.CreateBitCast(closure, llvm.PointerType(structType, 0), "") for i, fv := range f.FreeVars { ptr := fr.builder.CreateStructGEP(closure, i+1, "") ptr = fr.builder.CreateLoad(ptr, "") fr.env[fv] = newValue(ptr, fv.Type()) } } // Allocate stack space for locals in the prologue block. for _, local := range f.Locals { typ := fr.llvmtypes.ToLLVM(deref(local.Type())) alloca := fr.builder.CreateAlloca(typ, local.Comment) fr.memsetZero(alloca, llvm.SizeOf(typ)) bcalloca := fr.builder.CreateBitCast(alloca, llvm.PointerType(llvm.Int8Type(), 0), "") value := newValue(bcalloca, local.Type()) fr.env[local] = value if fr.GenerateDebug { paramIndex, ok := paramPos[local.Pos()] if !ok { paramIndex = -1 } fr.debug.Declare(fr.builder, local, alloca, paramIndex) } } // If this is the "init" function, enable init-specific optimizations. if !isMethod && f.Name() == "init" { fr.isInit = true } // If the function contains any defers, we must first create // an unwind block. We can short-circuit the check for defers with // f.Recover != nil. if f.Recover != nil || hasDefer(f) { fr.unwindBlock = llvm.AddBasicBlock(fr.function, "") fr.frameptr = fr.builder.CreateAlloca(llvm.Int8Type(), "") } term := fr.builder.CreateBr(fr.blocks[0]) fr.allocaBuilder.SetInsertPointBefore(term) for _, block := range f.DomPreorder() { fr.translateBlock(block, fr.blocks[block.Index]) } fr.fixupPhis() if !fr.unwindBlock.IsNil() { fr.setupUnwindBlock(f.Recover, f.Signature.Results()) } // The init function needs to register the GC roots first. We do this // after generating code for it because allocations may have caused // additional GC roots to be created. if fr.isInit { fr.builder.SetInsertPointBefore(prologueBlock.FirstInstruction()) fr.registerGcRoots() } }
func (c *Codegen) defineConstants() { nullVal := llvm.ConstPointerNull(llvm.PointerType(llvm.Int8Type(), 0)) c.scope.AddVariable("null", nullVal) }
// mapIterNext advances the iterator, and returns the tuple (ok, k, v). func (fr *frame) mapIterNext(iter []*govalue) []*govalue { maptyp := iter[0].Type().Underlying().(*types.Map) ktyp := maptyp.Key() klltyp := fr.types.ToLLVM(ktyp) vtyp := maptyp.Elem() vlltyp := fr.types.ToLLVM(vtyp) m, isinitptr := iter[0], iter[1] i8ptr := llvm.PointerType(llvm.Int8Type(), 0) mapiterbufty := llvm.ArrayType(i8ptr, 4) mapiterbuf := fr.allocaBuilder.CreateAlloca(mapiterbufty, "") mapiterbufelem0ptr := fr.builder.CreateStructGEP(mapiterbuf, 0, "") keybuf := fr.allocaBuilder.CreateAlloca(klltyp, "") keyptr := fr.builder.CreateBitCast(keybuf, i8ptr, "") valbuf := fr.allocaBuilder.CreateAlloca(vlltyp, "") valptr := fr.builder.CreateBitCast(valbuf, i8ptr, "") isinit := fr.builder.CreateLoad(isinitptr.value, "") initbb := llvm.AddBasicBlock(fr.function, "") nextbb := llvm.AddBasicBlock(fr.function, "") contbb := llvm.AddBasicBlock(fr.function, "") fr.builder.CreateCondBr(isinit, nextbb, initbb) fr.builder.SetInsertPointAtEnd(initbb) fr.builder.CreateStore(llvm.ConstAllOnes(llvm.Int1Type()), isinitptr.value) fr.runtime.mapiterinit.call(fr, m.value, mapiterbufelem0ptr) fr.builder.CreateBr(contbb) fr.builder.SetInsertPointAtEnd(nextbb) fr.runtime.mapiternext.call(fr, mapiterbufelem0ptr) fr.builder.CreateBr(contbb) fr.builder.SetInsertPointAtEnd(contbb) mapiterbufelem0 := fr.builder.CreateLoad(mapiterbufelem0ptr, "") okbit := fr.builder.CreateIsNotNull(mapiterbufelem0, "") ok := fr.builder.CreateZExt(okbit, llvm.Int8Type(), "") loadbb := llvm.AddBasicBlock(fr.function, "") cont2bb := llvm.AddBasicBlock(fr.function, "") fr.builder.CreateCondBr(okbit, loadbb, cont2bb) fr.builder.SetInsertPointAtEnd(loadbb) fr.runtime.mapiter2.call(fr, mapiterbufelem0ptr, keyptr, valptr) loadbb = fr.builder.GetInsertBlock() loadedkey := fr.builder.CreateLoad(keybuf, "") loadedval := fr.builder.CreateLoad(valbuf, "") fr.builder.CreateBr(cont2bb) fr.builder.SetInsertPointAtEnd(cont2bb) k := fr.builder.CreatePHI(klltyp, "") k.AddIncoming( []llvm.Value{llvm.ConstNull(klltyp), loadedkey}, []llvm.BasicBlock{contbb, loadbb}, ) v := fr.builder.CreatePHI(vlltyp, "") v.AddIncoming( []llvm.Value{llvm.ConstNull(vlltyp), loadedval}, []llvm.BasicBlock{contbb, loadbb}, ) return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, ktyp), newValue(v, vtyp)} }
func boolLLVMValue(v bool) (lv llvm.Value) { if v { return llvm.ConstInt(llvm.Int8Type(), 1, false) } return llvm.ConstNull(llvm.Int8Type()) }
func (fr *frame) compareStringEmpty(v llvm.Value) *govalue { len := fr.builder.CreateExtractValue(v, 1, "") result := fr.builder.CreateIsNull(len, "") result = fr.builder.CreateZExt(result, llvm.Int8Type(), "") return newValue(result, types.Typ[types.Bool]) }
func newRuntimeInterface(module llvm.Module, tm *llvmTypeMap) (*runtimeInterface, error) { var ri runtimeInterface Bool := types.Typ[types.Bool] Complex128 := types.Typ[types.Complex128] Float64 := types.Typ[types.Float64] Int32 := types.Typ[types.Int32] Int64 := types.Typ[types.Int64] Int := types.Typ[types.Int] Rune := types.Typ[types.Rune] String := types.Typ[types.String] Uintptr := types.Typ[types.Uintptr] UnsafePointer := types.Typ[types.UnsafePointer] EmptyInterface := types.NewInterface(nil, nil) IntSlice := types.NewSlice(types.Typ[types.Int]) for _, rt := range [...]struct { name string rfi *runtimeFnInfo args, res []types.Type attrs []llvm.Attribute }{ { name: "__go_append", rfi: &ri.append, args: []types.Type{IntSlice, UnsafePointer, Uintptr, Uintptr}, res: []types.Type{IntSlice}, }, { name: "__go_assert_interface", rfi: &ri.assertInterface, args: []types.Type{UnsafePointer, UnsafePointer}, res: []types.Type{UnsafePointer}, }, { name: "__go_can_recover", rfi: &ri.canRecover, args: []types.Type{UnsafePointer}, res: []types.Type{Bool}, }, { name: "__go_chan_cap", rfi: &ri.chanCap, args: []types.Type{UnsafePointer}, res: []types.Type{Int}, }, { name: "__go_chan_len", rfi: &ri.chanLen, args: []types.Type{UnsafePointer}, res: []types.Type{Int}, }, { name: "runtime.chanrecv2", rfi: &ri.chanrecv2, args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, res: []types.Type{Bool}, }, { name: "__go_check_defer", rfi: &ri.checkDefer, args: []types.Type{UnsafePointer}, }, { name: "__go_check_interface_type", rfi: &ri.checkInterfaceType, args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, }, { name: "__go_builtin_close", rfi: &ri.builtinClose, args: []types.Type{UnsafePointer}, }, { name: "__go_convert_interface", rfi: &ri.convertInterface, args: []types.Type{UnsafePointer, UnsafePointer}, res: []types.Type{UnsafePointer}, }, { name: "__go_copy", rfi: &ri.copy, args: []types.Type{UnsafePointer, UnsafePointer, Uintptr}, }, { name: "__go_defer", rfi: &ri.Defer, args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, }, { name: "__go_deferred_recover", rfi: &ri.deferredRecover, res: []types.Type{EmptyInterface}, }, { name: "__go_empty_interface_compare", rfi: &ri.emptyInterfaceCompare, args: []types.Type{EmptyInterface, EmptyInterface}, res: []types.Type{Int}, }, { name: "__go_go", rfi: &ri.Go, args: []types.Type{UnsafePointer, UnsafePointer}, }, { name: "runtime.ifaceE2I2", rfi: &ri.ifaceE2I2, args: []types.Type{UnsafePointer, EmptyInterface}, res: []types.Type{EmptyInterface, Bool}, }, { name: "runtime.ifaceI2I2", rfi: &ri.ifaceI2I2, args: []types.Type{UnsafePointer, EmptyInterface}, res: []types.Type{EmptyInterface, Bool}, }, { name: "__go_int_array_to_string", rfi: &ri.intArrayToString, args: []types.Type{UnsafePointer, Int}, res: []types.Type{String}, }, { name: "__go_int_to_string", rfi: &ri.intToString, args: []types.Type{Int}, res: []types.Type{String}, }, { name: "__go_interface_compare", rfi: &ri.interfaceCompare, args: []types.Type{EmptyInterface, EmptyInterface}, res: []types.Type{Int}, }, { name: "__go_make_slice2", rfi: &ri.makeSlice, args: []types.Type{UnsafePointer, Uintptr, Uintptr}, res: []types.Type{IntSlice}, }, { name: "runtime.mapdelete", rfi: &ri.mapdelete, args: []types.Type{UnsafePointer, UnsafePointer}, }, { name: "runtime.mapiter2", rfi: &ri.mapiter2, args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, }, { name: "runtime.mapiterinit", rfi: &ri.mapiterinit, args: []types.Type{UnsafePointer, UnsafePointer}, }, { name: "runtime.mapiternext", rfi: &ri.mapiternext, args: []types.Type{UnsafePointer}, }, { name: "__go_map_index", rfi: &ri.mapIndex, args: []types.Type{UnsafePointer, UnsafePointer, Bool}, res: []types.Type{UnsafePointer}, }, { name: "__go_map_len", rfi: &ri.mapLen, args: []types.Type{UnsafePointer}, res: []types.Type{Int}, }, { name: "__go_new", rfi: &ri.New, args: []types.Type{UnsafePointer, Uintptr}, res: []types.Type{UnsafePointer}, }, { name: "__go_new_channel", rfi: &ri.newChannel, args: []types.Type{UnsafePointer, Uintptr}, res: []types.Type{UnsafePointer}, }, { name: "__go_new_map", rfi: &ri.newMap, args: []types.Type{UnsafePointer, Uintptr}, res: []types.Type{UnsafePointer}, }, { name: "__go_new_nopointers", rfi: &ri.NewNopointers, args: []types.Type{UnsafePointer, Uintptr}, res: []types.Type{UnsafePointer}, }, { name: "runtime.newselect", rfi: &ri.newSelect, args: []types.Type{Int32}, res: []types.Type{UnsafePointer}, }, { name: "__go_panic", rfi: &ri.panic, args: []types.Type{EmptyInterface}, attrs: []llvm.Attribute{llvm.NoReturnAttribute}, }, { name: "__go_print_bool", rfi: &ri.printBool, args: []types.Type{Bool}, }, { name: "__go_print_complex", rfi: &ri.printComplex, args: []types.Type{Complex128}, }, { name: "__go_print_double", rfi: &ri.printDouble, args: []types.Type{Float64}, }, { name: "__go_print_empty_interface", rfi: &ri.printEmptyInterface, args: []types.Type{EmptyInterface}, }, { name: "__go_print_interface", rfi: &ri.printInterface, args: []types.Type{EmptyInterface}, }, { name: "__go_print_int64", rfi: &ri.printInt64, args: []types.Type{Int64}, }, { name: "__go_print_nl", rfi: &ri.printNl, }, { name: "__go_print_pointer", rfi: &ri.printPointer, args: []types.Type{UnsafePointer}, }, { name: "__go_print_slice", rfi: &ri.printSlice, args: []types.Type{IntSlice}, }, { name: "__go_print_space", rfi: &ri.printSpace, }, { name: "__go_print_string", rfi: &ri.printString, args: []types.Type{String}, }, { name: "__go_print_uint64", rfi: &ri.printUint64, args: []types.Type{Int64}, }, { name: "__go_receive", rfi: &ri.receive, args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, }, { name: "__go_recover", rfi: &ri.recover, res: []types.Type{EmptyInterface}, }, { name: "__go_register_gc_roots", rfi: &ri.registerGcRoots, args: []types.Type{UnsafePointer}, }, { name: "__go_runtime_error", rfi: &ri.runtimeError, args: []types.Type{Int32}, attrs: []llvm.Attribute{llvm.NoReturnAttribute}, }, { name: "runtime.selectdefault", rfi: &ri.selectdefault, args: []types.Type{UnsafePointer, Int32}, }, { name: "runtime.selectgo", rfi: &ri.selectgo, args: []types.Type{UnsafePointer}, res: []types.Type{Int}, }, { name: "runtime.selectrecv2", rfi: &ri.selectrecv2, args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, UnsafePointer, Int32}, }, { name: "runtime.selectsend", rfi: &ri.selectsend, args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, Int32}, }, { name: "__go_send_big", rfi: &ri.sendBig, args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, }, { name: "__go_set_defer_retaddr", rfi: &ri.setDeferRetaddr, args: []types.Type{UnsafePointer}, res: []types.Type{Bool}, }, { name: "__go_strcmp", rfi: &ri.strcmp, args: []types.Type{String, String}, res: []types.Type{Int}, }, { name: "__go_string_plus", rfi: &ri.stringPlus, args: []types.Type{String, String}, res: []types.Type{String}, }, { name: "__go_string_slice", rfi: &ri.stringSlice, args: []types.Type{String, Int, Int}, res: []types.Type{String}, }, { name: "__go_string_to_int_array", rfi: &ri.stringToIntArray, args: []types.Type{String}, res: []types.Type{IntSlice}, }, { name: "runtime.stringiter2", rfi: &ri.stringiter2, args: []types.Type{String, Int}, res: []types.Type{Int, Rune}, }, { name: "__go_type_descriptors_equal", rfi: &ri.typeDescriptorsEqual, args: []types.Type{UnsafePointer, UnsafePointer}, res: []types.Type{Bool}, }, { name: "__go_undefer", rfi: &ri.undefer, args: []types.Type{UnsafePointer}, }, } { rt.rfi.init(tm, module, rt.name, rt.args, rt.res) for _, attr := range rt.attrs { rt.rfi.fn.AddFunctionAttr(attr) } } memsetName := "llvm.memset.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth()) memsetType := llvm.FunctionType( llvm.VoidType(), []llvm.Type{ llvm.PointerType(llvm.Int8Type(), 0), llvm.Int8Type(), tm.target.IntPtrType(), llvm.Int32Type(), llvm.Int1Type(), }, false, ) ri.memset = llvm.AddFunction(module, memsetName, memsetType) memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth()) memcpyType := llvm.FunctionType( llvm.VoidType(), []llvm.Type{ llvm.PointerType(llvm.Int8Type(), 0), llvm.PointerType(llvm.Int8Type(), 0), tm.target.IntPtrType(), llvm.Int32Type(), llvm.Int1Type(), }, false, ) ri.memcpy = llvm.AddFunction(module, memcpyName, memcpyType) returnaddressType := llvm.FunctionType( llvm.PointerType(llvm.Int8Type(), 0), []llvm.Type{llvm.Int32Type()}, false, ) ri.returnaddress = llvm.AddFunction(module, "llvm.returnaddress", returnaddressType) gccgoPersonalityType := llvm.FunctionType( llvm.Int32Type(), []llvm.Type{ llvm.Int32Type(), llvm.Int64Type(), llvm.PointerType(llvm.Int8Type(), 0), llvm.PointerType(llvm.Int8Type(), 0), }, false, ) ri.gccgoPersonality = llvm.AddFunction(module, "__gccgo_personality_v0", gccgoPersonalityType) ri.gccgoExceptionType = llvm.StructType( []llvm.Type{ llvm.PointerType(llvm.Int8Type(), 0), llvm.Int32Type(), }, false, ) return &ri, nil }
func (fr *frame) createMalloc(size llvm.Value) llvm.Value { return fr.runtime.NewNopointers.callOnly(fr, llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0)), fr.createZExtOrTrunc(size, fr.target.IntPtrType(), ""))[0] }
// resolveFunctionDescriptor returns a function's // first-class value representation. func (u *unit) resolveFunctionDescriptor(f *ssa.Function) *govalue { llfd := u.resolveFunctionDescriptorGlobal(f) llfd = llvm.ConstBitCast(llfd, llvm.PointerType(llvm.Int8Type(), 0)) return newValue(llfd, f.Signature) }
// newValueFromConst converts a constant value to an LLVM value. func (fr *frame) newValueFromConst(v exact.Value, typ types.Type) *govalue { switch { case v == nil: llvmtyp := fr.types.ToLLVM(typ) return newValue(llvm.ConstNull(llvmtyp), typ) case isString(typ): if isUntyped(typ) { typ = types.Typ[types.String] } llvmtyp := fr.types.ToLLVM(typ) strval := exact.StringVal(v) strlen := len(strval) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var ptr llvm.Value if strlen > 0 { init := llvm.ConstString(strval, false) ptr = llvm.AddGlobal(fr.module.Module, init.Type(), "") ptr.SetInitializer(init) ptr.SetLinkage(llvm.InternalLinkage) ptr = llvm.ConstBitCast(ptr, i8ptr) } else { ptr = llvm.ConstNull(i8ptr) } len_ := llvm.ConstInt(fr.types.inttype, uint64(strlen), false) llvmvalue := llvm.Undef(llvmtyp) llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0}) llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1}) return newValue(llvmvalue, typ) case isInteger(typ): if isUntyped(typ) { typ = types.Typ[types.Int] } llvmtyp := fr.types.ToLLVM(typ) var llvmvalue llvm.Value if isUnsigned(typ) { v, _ := exact.Uint64Val(v) llvmvalue = llvm.ConstInt(llvmtyp, v, false) } else { v, _ := exact.Int64Val(v) llvmvalue = llvm.ConstInt(llvmtyp, uint64(v), true) } return newValue(llvmvalue, typ) case isBoolean(typ): if isUntyped(typ) { typ = types.Typ[types.Bool] } return newValue(boolLLVMValue(exact.BoolVal(v)), typ) case isFloat(typ): if isUntyped(typ) { typ = types.Typ[types.Float64] } llvmtyp := fr.types.ToLLVM(typ) floatval, _ := exact.Float64Val(v) llvmvalue := llvm.ConstFloat(llvmtyp, floatval) return newValue(llvmvalue, typ) case typ == types.Typ[types.UnsafePointer]: llvmtyp := fr.types.ToLLVM(typ) v, _ := exact.Uint64Val(v) llvmvalue := llvm.ConstInt(fr.types.inttype, v, false) llvmvalue = llvm.ConstIntToPtr(llvmvalue, llvmtyp) return newValue(llvmvalue, typ) case isComplex(typ): if isUntyped(typ) { typ = types.Typ[types.Complex128] } llvmtyp := fr.types.ToLLVM(typ) floattyp := llvmtyp.StructElementTypes()[0] llvmvalue := llvm.ConstNull(llvmtyp) realv := exact.Real(v) imagv := exact.Imag(v) realfloatval, _ := exact.Float64Val(realv) imagfloatval, _ := exact.Float64Val(imagv) llvmre := llvm.ConstFloat(floattyp, realfloatval) llvmim := llvm.ConstFloat(floattyp, imagfloatval) llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmre, []uint32{0}) llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmim, []uint32{1}) return newValue(llvmvalue, typ) } // Special case for string -> [](byte|rune) if u, ok := typ.Underlying().(*types.Slice); ok && isInteger(u.Elem()) { if v.Kind() == exact.String { strval := fr.newValueFromConst(v, types.Typ[types.String]) return fr.convert(strval, typ) } } panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", typ, typ, v, v)) }
// ResolveMethod implements MethodResolver.ResolveMethod. func (u *unit) ResolveMethod(s *types.Selection) *govalue { m := u.pkg.Prog.Method(s) llfn := u.resolveFunctionGlobal(m) llfn = llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0)) return newValue(llfn, m.Signature) }