Example #1
0
// interfaceMethod returns a function pointer for the specified
// interface and method pair.
func (c *compiler) interfaceMethod(iface *LLVMValue, method *types.Func) *LLVMValue {
	lliface := iface.LLVMValue()
	llitab := c.builder.CreateExtractValue(lliface, 0, "")
	llvalue := c.builder.CreateExtractValue(lliface, 1, "")
	sig := method.Type().(*types.Signature)
	methodset := c.types.MethodSet(sig.Recv().Type())
	// TODO(axw) cache ordered method index
	var index int
	for i := 0; i < methodset.Len(); i++ {
		if methodset.At(i).Obj() == method {
			index = i
			break
		}
	}
	llitab = c.builder.CreateBitCast(llitab, llvm.PointerType(c.runtime.itab.llvm, 0), "")
	llifn := c.builder.CreateGEP(llitab, []llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), 0, false),
		llvm.ConstInt(llvm.Int32Type(), 5, false), // index of itab.fun
	}, "")
	_ = index
	llifn = c.builder.CreateGEP(llifn, []llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(index), false),
	}, "")
	llifn = c.builder.CreateLoad(llifn, "")
	// Strip receiver.
	sig = types.NewSignature(nil, nil, sig.Params(), sig.Results(), sig.Variadic())
	llfn := llvm.Undef(c.types.ToLLVM(sig))
	llifn = c.builder.CreateIntToPtr(llifn, llfn.Type().StructElementTypes()[0], "")
	llfn = c.builder.CreateInsertValue(llfn, llifn, 0, "")
	llfn = c.builder.CreateInsertValue(llfn, llvalue, 1, "")
	return c.NewValue(llfn, sig)
}
Example #2
0
File: debug.go Project: rvedam/llgo
func (d *debugInfo) setLocation(b llvm.Builder, pos token.Pos) {
	position := d.Fset.Position(pos)
	b.SetCurrentDebugLocation(llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(position.Line), true),
		llvm.ConstInt(llvm.Int32Type(), uint64(position.Column), true),
		d.MDNode(d.context()),
		llvm.Value{},
	}))
}
Example #3
0
func (d *BlockDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false),
		info.mdFileNode(d.File),
		info.MDNode(d.Context),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Column), false),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Id), false),
	})
}
Example #4
0
func (c *compiler) createMainFunction() error {
	// In a PNaCl program (plugin), there should not be a "main.main";
	// instead, we expect a "main.CreateModule" function.
	// See pkg/nacl/ppapi/ppapi.go for more details.
	mainMain := c.module.NamedFunction("main.main")
	/*
		if c.pnacl {
			// PNaCl's libppapi_stub.a implements "main", which simply
			// calls through to PpapiPluginMain. We define our own "main"
			// so that we can capture argc/argv.
			if !mainMain.IsNil() {
				return fmt.Errorf("Found main.main")
			}
			pluginMain := c.RuntimeFunction("PpapiPluginMain", "func() int32")

			// Synthesise a main which has no return value. We could cast
			// PpapiPluginMain, but this is potentially unsafe as its
			// calling convention is unspecified.
			ftyp := llvm.FunctionType(llvm.VoidType(), nil, false)
			mainMain = llvm.AddFunction(c.module.Module, "main.main", ftyp)
			entry := llvm.AddBasicBlock(mainMain, "entry")
			c.builder.SetInsertPointAtEnd(entry)
			c.builder.CreateCall(pluginMain, nil, "")
			c.builder.CreateRetVoid()
		} else */{
		mainMain = c.module.NamedFunction("main.main")
	}

	if mainMain.IsNil() {
		return fmt.Errorf("Could not find main.main")
	}

	// runtime.main is called by main, with argc, argv, argp,
	// and a pointer to main.main, which must be a niladic
	// function with no result.
	runtimeMain := c.runtime.main.LLVMValue()

	ptrptr := llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0)
	ftyp := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{llvm.Int32Type(), ptrptr, ptrptr}, true)
	main := llvm.AddFunction(c.module.Module, "main", ftyp)

	c.builder.SetCurrentDebugLocation(c.debug.MDNode(nil))
	entry := llvm.AddBasicBlock(main, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	runtimeMainParamTypes := runtimeMain.Type().ElementType().ParamTypes()
	args := []llvm.Value{
		main.Param(0), // argc
		main.Param(1), // argv
		main.Param(2), // argp
		c.builder.CreateBitCast(mainMain, runtimeMainParamTypes[3], ""),
	}
	result := c.builder.CreateCall(runtimeMain, args, "")
	c.builder.CreateRet(result)
	return nil
}
Example #5
0
func (d *LocalVariableDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false),
		info.MDNode(d.Context),
		llvm.MDString(d.Name),
		info.mdFileNode(d.File),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line)|(uint64(d.Argument)<<24), false),
		info.MDNode(d.Type),
		llvm.ConstNull(llvm.Int32Type()), // flags
		llvm.ConstNull(llvm.Int32Type()), // optional reference to inline location
	})
}
Example #6
0
func (d *DerivedTypeDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false),
		FileDescriptor(d.File).path(),
		info.MDNode(d.Context),
		llvm.MDString(d.Name),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false),
		llvm.ConstInt(llvm.Int64Type(), d.Size, false),
		llvm.ConstInt(llvm.Int64Type(), d.Alignment, false),
		llvm.ConstInt(llvm.Int64Type(), d.Offset, false),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Flags), false),
		info.MDNode(d.Base)})
}
Example #7
0
func (d *GlobalVariableDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false),
		llvm.ConstNull(llvm.Int32Type()),
		info.MDNode(d.Context),
		llvm.MDString(d.Name),
		llvm.MDString(d.DisplayName),
		llvm.MDNode(nil),
		info.mdFileNode(d.File),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false),
		info.MDNode(d.Type),
		constInt1(d.Local),
		constInt1(!d.External),
		d.Value})
}
Example #8
0
func (d subrangeDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false),
		llvm.ConstInt(llvm.Int64Type(), uint64(d.low), true),
		llvm.ConstInt(llvm.Int64Type(), uint64(d.high), true),
	})
}
Example #9
0
func (tm *llvmTypeMap) basicLLVMType(b *types.Basic) llvm.Type {
	switch b.Kind() {
	case types.Bool:
		return llvm.Int1Type()
	case types.Int8, types.Uint8:
		return llvm.Int8Type()
	case types.Int16, types.Uint16:
		return llvm.Int16Type()
	case types.Int32, types.Uint32:
		return llvm.Int32Type()
	case types.Uint, types.Int:
		return tm.inttype
	case types.Int64, types.Uint64:
		return llvm.Int64Type()
	case types.Float32:
		return llvm.FloatType()
	case types.Float64:
		return llvm.DoubleType()
	case types.UnsafePointer, types.Uintptr:
		return tm.target.IntPtrType()
	case types.Complex64:
		f32 := llvm.FloatType()
		elements := []llvm.Type{f32, f32}
		return llvm.StructType(elements, false)
	case types.Complex128:
		f64 := llvm.DoubleType()
		elements := []llvm.Type{f64, f64}
		return llvm.StructType(elements, false)
	case types.String:
		i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
		elements := []llvm.Type{i8ptr, tm.inttype}
		return llvm.StructType(elements, false)
	}
	panic(fmt.Sprint("unhandled kind: ", b.Kind))
}
Example #10
0
func (c *compiler) compareStrings(lhs, rhs *LLVMValue, op token.Token) *LLVMValue {
	strcmp := c.runtime.strcmp.LLVMValue()
	_string := strcmp.Type().ElementType().ParamTypes()[0]
	lhsstr := c.coerceString(lhs.LLVMValue(), _string)
	rhsstr := c.coerceString(rhs.LLVMValue(), _string)
	args := []llvm.Value{lhsstr, rhsstr}
	result := c.builder.CreateCall(strcmp, args, "")
	zero := llvm.ConstNull(llvm.Int32Type())
	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 LLVMValue.BinaryOp")
	default:
		panic("unreachable")
	}
	result = c.builder.CreateICmp(pred, result, zero, "")
	return c.NewValue(result, types.Typ[types.Bool])
}
Example #11
0
func (d *CompileUnitDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Tag())+llvm.LLVMDebugVersion, false),
		d.Path.path(),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Language), false),
		llvm.MDString(d.Producer),
		constInt1(d.Optimized),
		llvm.MDString(d.CompilerFlags),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Runtime), false),
		d.mdNodeList(info, d.EnumTypes),
		d.mdNodeList(info, d.RetainedTypes),
		d.mdNodeList(info, d.Subprograms),
		d.mdNodeList(info, d.GlobalVariables),
		d.mdNodeList(info, nil), // List of imported entities
		llvm.MDString(""),       // Split debug filename
	})
}
Example #12
0
func (d *CompositeTypeDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false),
		FileDescriptor(d.File).path(),
		info.MDNode(d.Context),
		llvm.MDString(d.Name),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false),
		llvm.ConstInt(llvm.Int64Type(), d.Size, false),
		llvm.ConstInt(llvm.Int64Type(), d.Alignment, false),
		llvm.ConstInt(llvm.Int64Type(), d.Offset, false),
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Flags), false),
		info.MDNode(d.Base), // reference type derived from
		llvm.MDNode(info.MDNodes(d.Members)),
		llvm.ConstInt(llvm.Int32Type(), uint64(0), false), // Runtime language
		llvm.ConstInt(llvm.Int32Type(), uint64(0), false), // Base type containing the vtable pointer for this type
	})
}
Example #13
0
func (d FileDescriptor) mdNode(info *DebugInfo) llvm.Value {
	if d == "" {
		return llvm.Value{}
	}
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false),
		d.path(),
	})
}
Example #14
0
func getFflush(module llvm.Module) llvm.Value {
	fflush := module.NamedFunction("fflush")
	if fflush.IsNil() {
		voidPtr := llvm.PointerType(llvm.Int8Type(), 0)
		ftyp := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{voidPtr}, false)
		fflush = llvm.AddFunction(module, "fflush", ftyp)
		fflush.SetFunctionCallConv(llvm.CCallConv)
	}
	return fflush
}
Example #15
0
func getPrintf(module llvm.Module) llvm.Value {
	printf := module.NamedFunction("printf")
	if printf.IsNil() {
		charPtr := llvm.PointerType(llvm.Int8Type(), 0)
		ftyp := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{charPtr}, true)
		printf = llvm.AddFunction(module, "printf", ftyp)
		printf.SetFunctionCallConv(llvm.CCallConv)
	}
	return printf
}
Example #16
0
File: slice.go Project: rvedam/llgo
// makeLiteralSlice allocates a new slice, storing in it the provided elements.
func (c *compiler) makeLiteralSlice(v []llvm.Value, elttyp types.Type) llvm.Value {
	n := llvm.ConstInt(c.types.inttype, uint64(len(v)), false)
	eltType := c.types.ToLLVM(elttyp)
	arrayType := llvm.ArrayType(eltType, len(v))
	mem := c.createMalloc(llvm.SizeOf(arrayType))
	mem = c.builder.CreateIntToPtr(mem, llvm.PointerType(eltType, 0), "")
	for i, value := range v {
		indices := []llvm.Value{llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}
		ep := c.builder.CreateGEP(mem, indices, "")
		c.builder.CreateStore(value, ep)
	}
	slicetyp := types.NewSlice(elttyp)
	struct_ := llvm.Undef(c.types.ToLLVM(slicetyp))
	struct_ = c.builder.CreateInsertValue(struct_, mem, 0, "")
	struct_ = c.builder.CreateInsertValue(struct_, n, 1, "")
	struct_ = c.builder.CreateInsertValue(struct_, n, 2, "")
	return struct_
}
Example #17
0
func NewLLVMTypeMap(target llvm.TargetData) *llvmTypeMap {
	// spec says int is either 32-bit or 64-bit.
	var inttype llvm.Type
	if target.PointerSize() >= 8 {
		inttype = llvm.Int64Type()
	} else {
		inttype = llvm.Int32Type()
	}
	return &llvmTypeMap{
		StdSizes: &types.StdSizes{
			WordSize: int64(target.PointerSize()),
			MaxAlign: 8,
		},
		target:     target,
		inttype:    inttype,
		ptrstandin: llvm.GlobalContext().StructCreateNamed(""),
	}
}
Example #18
0
func (d *SubprogramDescriptor) mdNode(info *DebugInfo) llvm.Value {
	return llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), llvm.LLVMDebugVersion+uint64(d.Tag()), false),
		FileDescriptor(d.File).path(),
		info.MDNode(d.Context),
		llvm.MDString(d.Name),
		llvm.MDString(d.DisplayName),
		llvm.MDString(""), // mips linkage name
		llvm.ConstInt(llvm.Int32Type(), uint64(d.Line), false),
		info.MDNode(d.Type),
		llvm.ConstNull(llvm.Int1Type()),           // not static
		llvm.ConstAllOnes(llvm.Int1Type()),        // locally defined (not extern)
		llvm.ConstNull(llvm.Int32Type()),          // virtuality
		llvm.ConstNull(llvm.Int32Type()),          // index into a virtual function
		info.MDNode(nil),                          // basetype containing the vtable pointer
		llvm.ConstInt(llvm.Int32Type(), 0, false), // flags
		llvm.ConstNull(llvm.Int1Type()),           // not optimised
		d.Function,
		info.MDNode(nil),                                            // Template parameters
		info.MDNode(nil),                                            // function declaration descriptor
		llvm.MDNode(nil),                                            // function variables
		llvm.ConstInt(llvm.Int32Type(), uint64(d.ScopeLine), false), // Line number where the scope of the subprogram begins
	})
}
Example #19
0
File: ssa.go Project: rvedam/llgo
// prepareCall returns the evaluated function and arguments.
//
// For builtins that may not be used in go/defer, prepareCall
// will emits inline code. In this case, prepareCall returns
// nil for fn and args, and returns a non-nil value for result.
func (fr *frame) prepareCall(instr ssa.CallInstruction) (fn *LLVMValue, args []*LLVMValue, result *LLVMValue) {
	call := instr.Common()
	args = make([]*LLVMValue, len(call.Args))
	for i, arg := range call.Args {
		args[i] = fr.value(arg)
	}

	if call.IsInvoke() {
		fn := fr.interfaceMethod(fr.value(call.Value), call.Method)
		return fn, args, nil
	}

	switch v := call.Value.(type) {
	case *ssa.Builtin:
		// handled below
	case *ssa.Function:
		// Function handled specially; value() will convert
		// a function to one with a context argument.
		fn = fr.resolveFunction(v)
		pair := llvm.ConstNull(fr.llvmtypes.ToLLVM(fn.Type()))
		pair = llvm.ConstInsertValue(pair, fn.LLVMValue(), []uint32{0})
		fn = fr.NewValue(pair, fn.Type())
		return fn, args, nil
	default:
		fn = fr.value(call.Value)
		return fn, args, nil
	}

	// Builtins may only be used in calls (i.e. can't be assigned),
	// and only print[ln], panic and recover may be used in go/defer.
	builtin := call.Value.(*ssa.Builtin)
	switch builtin.Name() {
	case "print", "println":
		// print/println generates a call-site specific anonymous
		// function to print the values. It's not inline because
		// print/println may be deferred.
		params := make([]*types.Var, len(call.Args))
		for i, arg := range call.Args {
			// make sure to use args[i].Type(), not call.Args[i].Type(),
			// as the evaluated expression converts untyped.
			params[i] = types.NewParam(arg.Pos(), nil, arg.Name(), args[i].Type())
		}
		sig := types.NewSignature(nil, nil, types.NewTuple(params...), nil, false)
		llfntyp := fr.llvmtypes.ToLLVM(sig)
		llfnptr := llvm.AddFunction(fr.module.Module, "", llfntyp.StructElementTypes()[0].ElementType())
		currBlock := fr.builder.GetInsertBlock()
		entry := llvm.AddBasicBlock(llfnptr, "entry")
		fr.builder.SetInsertPointAtEnd(entry)
		internalArgs := make([]Value, len(args))
		for i, arg := range args {
			internalArgs[i] = fr.NewValue(llfnptr.Param(i), arg.Type())
		}
		fr.printValues(builtin.Name() == "println", internalArgs...)
		fr.builder.CreateRetVoid()
		fr.builder.SetInsertPointAtEnd(currBlock)
		return fr.NewValue(llfnptr, sig), args, nil

	case "panic":
		panic("TODO: panic")

	case "recover":
		// TODO(axw) determine number of frames to skip in pc check
		indirect := fr.NewValue(llvm.ConstNull(llvm.Int32Type()), types.Typ[types.Int32])
		return fr.runtime.recover_, []*LLVMValue{indirect}, nil

	case "append":
		return nil, nil, fr.callAppend(args[0], args[1])

	case "close":
		return fr.runtime.chanclose, args, nil

	case "cap":
		return nil, nil, fr.callCap(args[0])

	case "len":
		return nil, nil, fr.callLen(args[0])

	case "copy":
		return nil, nil, fr.callCopy(args[0], args[1])

	case "delete":
		fr.callDelete(args[0], args[1])
		return nil, nil, nil

	case "real":
		return nil, nil, args[0].extractComplexComponent(0)

	case "imag":
		return nil, nil, args[0].extractComplexComponent(1)

	case "complex":
		r := args[0].LLVMValue()
		i := args[1].LLVMValue()
		typ := instr.Value().Type()
		cmplx := llvm.Undef(fr.llvmtypes.ToLLVM(typ))
		cmplx = fr.builder.CreateInsertValue(cmplx, r, 0, "")
		cmplx = fr.builder.CreateInsertValue(cmplx, i, 1, "")
		return nil, nil, fr.NewValue(cmplx, typ)

	default:
		panic("unimplemented: " + builtin.Name())
	}
}
Example #20
0
func test() {
	llvm.LinkInMCJIT()
	llvm.InitializeNativeTarget()
	llvm.InitializeNativeAsmPrinter()

	mod := llvm.NewModule("fac_module")

	// don't do that, because ExecutionEngine takes ownership over module
	//defer mod.Dispose()

	fac_args := []llvm.Type{llvm.Int32Type()}
	fac_type := llvm.FunctionType(llvm.Int32Type(), fac_args, false)
	fac := llvm.AddFunction(mod, "fac", fac_type)
	fac.SetFunctionCallConv(llvm.CCallConv)
	n := fac.Param(0)

	entry := llvm.AddBasicBlock(fac, "entry")
	iftrue := llvm.AddBasicBlock(fac, "iftrue")
	iffalse := llvm.AddBasicBlock(fac, "iffalse")
	end := llvm.AddBasicBlock(fac, "end")

	builder := llvm.NewBuilder()
	defer builder.Dispose()

	builder.SetInsertPointAtEnd(entry)
	If := builder.CreateICmp(llvm.IntEQ, n, llvm.ConstInt(llvm.Int32Type(), 0, false), "cmptmp")
	builder.CreateCondBr(If, iftrue, iffalse)

	builder.SetInsertPointAtEnd(iftrue)
	res_iftrue := llvm.ConstInt(llvm.Int32Type(), 1, false)
	builder.CreateBr(end)

	builder.SetInsertPointAtEnd(iffalse)
	n_minus := builder.CreateSub(n, llvm.ConstInt(llvm.Int32Type(), 1, false), "subtmp")
	call_fac_args := []llvm.Value{n_minus}
	call_fac := builder.CreateCall(fac, call_fac_args, "calltmp")
	res_iffalse := builder.CreateMul(n, call_fac, "multmp")
	builder.CreateBr(end)

	builder.SetInsertPointAtEnd(end)
	res := builder.CreatePHI(llvm.Int32Type(), "result")
	phi_vals := []llvm.Value{res_iftrue, res_iffalse}
	phi_blocks := []llvm.BasicBlock{iftrue, iffalse}
	res.AddIncoming(phi_vals, phi_blocks)
	builder.CreateRet(res)

	err := llvm.VerifyModule(mod, llvm.ReturnStatusAction)
	if err != nil {
		fmt.Println(err)
		return
	}

	engine, err := llvm.NewMCJITCompiler(mod, llvm.MCJITCompilerOptions{OptLevel: 2})
	if err != nil {
		fmt.Println(err)
		return
	}
	defer engine.Dispose()

	pass := llvm.NewPassManager()
	defer pass.Dispose()

	pass.Add(engine.TargetData())
	pass.AddConstantPropagationPass()
	pass.AddInstructionCombiningPass()
	pass.AddPromoteMemoryToRegisterPass()
	pass.AddGVNPass()
	pass.AddCFGSimplificationPass()
	pass.Run(mod)

	mod.Dump()

	exec_args := []llvm.GenericValue{llvm.NewGenericValueFromInt(llvm.Int32Type(), 10, false)}
	exec_res := engine.RunFunction(fac, exec_args)
	fmt.Println("-----------------------------------------")
	fmt.Println("Running fac(10) with JIT...")
	fmt.Printf("Result: %d\n", exec_res.Int(false))
}
Example #21
0
func (c *compiler) chanSelect(states []selectState, blocking bool) *LLVMValue {
	stackptr := c.stacksave()
	defer c.stackrestore(stackptr)

	n := uint64(len(states))
	if !blocking {
		// blocking means there's no default case
		n++
	}
	lln := llvm.ConstInt(llvm.Int32Type(), n, false)
	allocsize := c.builder.CreateCall(c.runtime.selectsize.LLVMValue(), []llvm.Value{lln}, "")
	selectp := c.builder.CreateArrayAlloca(llvm.Int8Type(), allocsize, "selectp")
	c.memsetZero(selectp, allocsize)
	selectp = c.builder.CreatePtrToInt(selectp, c.target.IntPtrType(), "")
	c.builder.CreateCall(c.runtime.selectinit.LLVMValue(), []llvm.Value{lln, selectp}, "")

	// Allocate stack for the values to send/receive.
	//
	// TODO(axw) request optimisation in ssa to special-
	// case receive cases with no assignment, so we know
	// not to allocate stack space or do a copy.
	resTypes := []types.Type{types.Typ[types.Int], types.Typ[types.Bool]}
	for _, state := range states {
		if state.Dir == types.RecvOnly {
			chantyp := state.Chan.Type().Underlying().(*types.Chan)
			resTypes = append(resTypes, chantyp.Elem())
		}
	}
	resType := tupleType(resTypes...)
	llResType := c.types.ToLLVM(resType)
	tupleptr := c.builder.CreateAlloca(llResType, "")
	c.memsetZero(tupleptr, llvm.SizeOf(llResType))

	var recvindex int
	ptrs := make([]llvm.Value, len(states))
	for i, state := range states {
		chantyp := state.Chan.Type().Underlying().(*types.Chan)
		elemtyp := c.types.ToLLVM(chantyp.Elem())
		if state.Dir == types.SendOnly {
			ptrs[i] = c.builder.CreateAlloca(elemtyp, "")
			c.builder.CreateStore(state.Send.LLVMValue(), ptrs[i])
		} else {
			ptrs[i] = c.builder.CreateStructGEP(tupleptr, recvindex+2, "")
			recvindex++
		}
		ptrs[i] = c.builder.CreatePtrToInt(ptrs[i], c.target.IntPtrType(), "")
	}

	// Create select{send,recv} calls.
	selectsend := c.runtime.selectsend.LLVMValue()
	selectrecv := c.runtime.selectrecv.LLVMValue()
	var received llvm.Value
	if recvindex > 0 {
		received = c.builder.CreateStructGEP(tupleptr, 1, "")
	}
	if !blocking {
		c.builder.CreateCall(c.runtime.selectdefault.LLVMValue(), []llvm.Value{selectp}, "")
	}
	for i, state := range states {
		ch := state.Chan.LLVMValue()
		if state.Dir == types.SendOnly {
			c.builder.CreateCall(selectsend, []llvm.Value{selectp, ch, ptrs[i]}, "")
		} else {
			c.builder.CreateCall(selectrecv, []llvm.Value{selectp, ch, ptrs[i], received}, "")
		}
	}

	// Fire off the select.
	index := c.builder.CreateCall(c.runtime.selectgo.LLVMValue(), []llvm.Value{selectp}, "")
	tuple := c.builder.CreateLoad(tupleptr, "")
	tuple = c.builder.CreateInsertValue(tuple, index, 0, "")
	return c.NewValue(tuple, resType)
}
Example #22
0
// indirectFunction creates an indirect function from a
// given function and arguments, suitable for use with
// "defer" and "go".
func (c *compiler) indirectFunction(fn *LLVMValue, args []*LLVMValue) *LLVMValue {
	nilarytyp := types.NewSignature(nil, nil, nil, nil, false)
	if len(args) == 0 {
		val := fn.LLVMValue()
		ptr := c.builder.CreateExtractValue(val, 0, "")
		ctx := c.builder.CreateExtractValue(val, 1, "")
		fnval := llvm.Undef(c.types.ToLLVM(nilarytyp))
		ptr = c.builder.CreateBitCast(ptr, fnval.Type().StructElementTypes()[0], "")
		ctx = c.builder.CreateBitCast(ctx, fnval.Type().StructElementTypes()[1], "")
		fnval = c.builder.CreateInsertValue(fnval, ptr, 0, "")
		fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "")
		return c.NewValue(fnval, nilarytyp)
	}

	// Check if function pointer or context pointer is global/null.
	fnval := fn.LLVMValue()
	fnptr := fnval
	var nctx int
	var fnctx llvm.Value
	var fnctxindex uint64
	var globalfn bool
	if fnptr.Type().TypeKind() == llvm.StructTypeKind {
		fnptr = c.builder.CreateExtractValue(fnval, 0, "")
		fnctx = c.builder.CreateExtractValue(fnval, 1, "")
		globalfn = !fnptr.IsAFunction().IsNil()
		if !globalfn {
			nctx++
		}
		if !fnctx.IsNull() {
			fnctxindex = uint64(nctx)
			nctx++
		}
	} else {
		// We've got a raw global function pointer. Convert to <ptr,ctx>.
		fnval = llvm.ConstNull(c.types.ToLLVM(fn.Type()))
		fnval = llvm.ConstInsertValue(fnval, fnptr, []uint32{0})
		fn = c.NewValue(fnval, fn.Type())
		fnctx = llvm.ConstExtractValue(fnval, []uint32{1})
		globalfn = true
	}

	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	llvmargs := make([]llvm.Value, len(args)+nctx)
	llvmargtypes := make([]llvm.Type, len(args)+nctx)
	for i, arg := range args {
		llvmargs[i+nctx] = arg.LLVMValue()
		llvmargtypes[i+nctx] = llvmargs[i+nctx].Type()
	}
	if !globalfn {
		llvmargtypes[0] = fnptr.Type()
		llvmargs[0] = fnptr
	}
	if !fnctx.IsNull() {
		llvmargtypes[fnctxindex] = fnctx.Type()
		llvmargs[fnctxindex] = fnctx
	}

	// TODO(axw) investigate an option for go statements
	// to allocate argument structure on the stack in the
	// initiator, and block until the spawned goroutine
	// has loaded the arguments from it.
	structtyp := llvm.StructType(llvmargtypes, false)
	argstruct := c.createTypeMalloc(structtyp)
	for i, llvmarg := range llvmargs {
		argptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "")
		c.builder.CreateStore(llvmarg, argptr)
	}

	// Create a function that will take a pointer to a structure of the type
	// defined above, or no parameters if there are none to pass.
	fntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{argstruct.Type()}, false)
	indirectfn := llvm.AddFunction(c.module.Module, "", fntype)
	i8argstruct := c.builder.CreateBitCast(argstruct, i8ptr, "")
	currblock := c.builder.GetInsertBlock()
	c.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(indirectfn, "entry"))
	argstruct = indirectfn.Param(0)
	newargs := make([]*LLVMValue, len(args))
	for i := range llvmargs[nctx:] {
		argptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), uint64(i+nctx), false)}, "")
		newargs[i] = c.NewValue(c.builder.CreateLoad(argptr, ""), args[i].Type())
	}

	// Unless we've got a global function, extract the
	// function pointer from the context.
	if !globalfn {
		fnval = llvm.Undef(fnval.Type())
		fnptrptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), 0, false)}, "")
		fnptr = c.builder.CreateLoad(fnptrptr, "")
		fnval = c.builder.CreateInsertValue(fnval, fnptr, 0, "")
	}
	if !fnctx.IsNull() {
		fnctxptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), fnctxindex, false)}, "")
		fnctx = c.builder.CreateLoad(fnctxptr, "")
		fnval = c.builder.CreateInsertValue(fnval, fnctx, 1, "")
		fn = c.NewValue(fnval, fn.Type())
	}
	c.createCall(fn, newargs)

	// Indirect function calls' return values are always ignored.
	c.builder.CreateRetVoid()
	c.builder.SetInsertPointAtEnd(currblock)

	fnval = llvm.Undef(c.types.ToLLVM(nilarytyp))
	indirectfn = c.builder.CreateBitCast(indirectfn, fnval.Type().StructElementTypes()[0], "")
	fnval = c.builder.CreateInsertValue(fnval, indirectfn, 0, "")
	fnval = c.builder.CreateInsertValue(fnval, i8argstruct, 1, "")
	fn = c.NewValue(fnval, nilarytyp)
	return fn
}
Example #23
0
func (d *CompileUnitDescriptor) mdNodeList(info *DebugInfo, list []DebugDescriptor) llvm.Value {
	if len(list) > 0 {
		return llvm.MDNode(info.MDNodes(list))
	}
	return llvm.MDNode([]llvm.Value{llvm.ConstNull(llvm.Int32Type())})
}