Exemplo n.º 1
0
Arquivo: stmt.go Projeto: qioixiy/llgo
func (c *compiler) VisitIfStmt(stmt *ast.IfStmt) {
	currBlock := c.builder.GetInsertBlock()
	resumeBlock := llvm.AddBasicBlock(currBlock.Parent(), "endif")
	resumeBlock.MoveAfter(currBlock)
	defer c.builder.SetInsertPointAtEnd(resumeBlock)

	var ifBlock, elseBlock llvm.BasicBlock
	if stmt.Else != nil {
		elseBlock = llvm.InsertBasicBlock(resumeBlock, "else")
		ifBlock = llvm.InsertBasicBlock(elseBlock, "if")
	} else {
		ifBlock = llvm.InsertBasicBlock(resumeBlock, "if")
	}
	if stmt.Else == nil {
		elseBlock = resumeBlock
	}

	if stmt.Init != nil {
		c.VisitStmt(stmt.Init)
	}

	cond_val := c.VisitExpr(stmt.Cond)
	c.builder.CreateCondBr(cond_val.LLVMValue(), ifBlock, elseBlock)
	c.builder.SetInsertPointAtEnd(ifBlock)
	c.VisitBlockStmt(stmt.Body, false)
	c.maybeImplicitBranch(resumeBlock)

	if stmt.Else != nil {
		c.builder.SetInsertPointAtEnd(elseBlock)
		c.VisitStmt(stmt.Else)
		c.maybeImplicitBranch(resumeBlock)
	}
}
Exemplo n.º 2
0
Arquivo: expr.go Projeto: kisielk/llgo
// Binary logical operators are handled specially, outside of the Value
// type, because of the need to perform lazy evaluation.
//
// Binary logical operators are implemented using a Phi node, which takes
// on the appropriate value depending on which basic blocks branch to it.
func (c *compiler) compileLogicalOp(op token.Token, lhs Value, rhsFunc func() Value) Value {
	lhsBlock := c.builder.GetInsertBlock()
	resultBlock := llvm.AddBasicBlock(lhsBlock.Parent(), "")
	resultBlock.MoveAfter(lhsBlock)
	rhsBlock := llvm.InsertBasicBlock(resultBlock, "")
	falseBlock := llvm.InsertBasicBlock(resultBlock, "")

	if op == token.LOR {
		c.builder.CreateCondBr(lhs.LLVMValue(), resultBlock, rhsBlock)
	} else {
		c.builder.CreateCondBr(lhs.LLVMValue(), rhsBlock, falseBlock)
	}
	c.builder.SetInsertPointAtEnd(rhsBlock)
	rhs := rhsFunc()
	rhsBlock = c.builder.GetInsertBlock() // rhsFunc may create blocks
	c.builder.CreateCondBr(rhs.LLVMValue(), resultBlock, falseBlock)
	c.builder.SetInsertPointAtEnd(falseBlock)
	c.builder.CreateBr(resultBlock)
	c.builder.SetInsertPointAtEnd(resultBlock)

	result := c.builder.CreatePHI(llvm.Int1Type(), "")
	trueValue := llvm.ConstAllOnes(llvm.Int1Type())
	falseValue := llvm.ConstNull(llvm.Int1Type())
	var values []llvm.Value
	var blocks []llvm.BasicBlock
	if op == token.LOR {
		values = []llvm.Value{trueValue, trueValue, falseValue}
		blocks = []llvm.BasicBlock{lhsBlock, rhsBlock, falseBlock}
	} else {
		values = []llvm.Value{trueValue, falseValue}
		blocks = []llvm.BasicBlock{rhsBlock, falseBlock}
	}
	result.AddIncoming(values, blocks)
	return c.NewLLVMValue(result, types.Bool)
}
Exemplo n.º 3
0
Arquivo: ssa.go Projeto: pcc/llgo
// contextFunction creates a wrapper function that
// has the same signature as the specified function,
// but has an additional first parameter that accepts
// and ignores the function context value.
//
// contextFunction must be called with a global function
// pointer.
func contextFunction(c *compiler, f *LLVMValue) *LLVMValue {
	defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock())
	resultType := c.llvmtypes.ToLLVM(f.Type())
	fnptr := f.LLVMValue()
	contextType := resultType.StructElementTypes()[1]
	llfntyp := fnptr.Type().ElementType()
	llfntyp = llvm.FunctionType(
		llfntyp.ReturnType(),
		append([]llvm.Type{contextType}, llfntyp.ParamTypes()...),
		llfntyp.IsFunctionVarArg(),
	)
	wrapper := llvm.AddFunction(c.module.Module, fnptr.Name()+".ctx", llfntyp)
	wrapper.SetLinkage(llvm.PrivateLinkage)
	entry := llvm.AddBasicBlock(wrapper, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	args := make([]llvm.Value, len(llfntyp.ParamTypes())-1)
	for i := range args {
		args[i] = wrapper.Param(i + 1)
	}
	result := c.builder.CreateCall(fnptr, args, "")
	switch nresults := f.Type().(*types.Signature).Results().Len(); nresults {
	case 0:
		c.builder.CreateRetVoid()
	case 1:
		c.builder.CreateRet(result)
	default:
		results := make([]llvm.Value, nresults)
		for i := range results {
			results[i] = c.builder.CreateExtractValue(result, i, "")
		}
		c.builder.CreateAggregateRet(results)
	}
	return c.NewValue(wrapper, f.Type())
}
Exemplo n.º 4
0
func (c *compiler) defineMemcpyFunction(fn llvm.Value) {
	entry := llvm.AddBasicBlock(fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	dst, src, size := fn.Param(0), fn.Param(1), fn.Param(2)

	pint8 := llvm.PointerType(llvm.Int8Type(), 0)
	dst = c.builder.CreateIntToPtr(dst, pint8, "")
	src = c.builder.CreateIntToPtr(src, pint8, "")

	sizeType := size.Type()
	sizeBits := sizeType.IntTypeWidth()
	memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(sizeBits)
	memcpy := c.module.NamedFunction(memcpyName)
	if memcpy.IsNil() {
		paramtypes := []llvm.Type{
			pint8, pint8, size.Type(), llvm.Int32Type(), llvm.Int1Type()}
		memcpyType := llvm.FunctionType(llvm.VoidType(), paramtypes, false)
		memcpy = llvm.AddFunction(c.module.Module, memcpyName, memcpyType)
	}

	args := []llvm.Value{
		dst, src, size,
		llvm.ConstInt(llvm.Int32Type(), 1, false), // single byte alignment
		llvm.ConstInt(llvm.Int1Type(), 0, false),  // not volatile
	}
	c.builder.CreateCall(memcpy, args, "")
	c.builder.CreateRetVoid()
}
Exemplo n.º 5
0
func (c *compiler) defineFreeFunction(fn llvm.Value) {
	entry := llvm.AddBasicBlock(fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	ptr := fn.FirstParam()
	ptrtyp := llvm.PointerType(llvm.Int8Type(), 0)
	c.builder.CreateFree(c.builder.CreateIntToPtr(ptr, ptrtyp, ""))
	c.builder.CreateRetVoid()
}
Exemplo n.º 6
0
// promoteMethod promotes a named type's method to another type
// which has embedded the named type.
func (c *compiler) promoteMethod(m *types.Func, recv types.Type, indices []int) types.Object {
	var pkg *types.Package
	if recv, ok := recv.(*types.Named); ok {
		pkg = c.objectdata[recv.Obj()].Package
	}
	recvvar := types.NewVar(pkg, "", recv)
	sig := m.Type().(*types.Signature)
	sig = types.NewSignature(recvvar, sig.Params(), sig.Results(), sig.IsVariadic())
	f := &synthFunc{pkg: pkg, name: m.Name(), typ: sig}
	ident := ast.NewIdent(f.Name())

	var isptr bool
	if ptr, ok := recv.(*types.Pointer); ok {
		isptr = true
		recv = ptr.Elem()
	}

	c.objects[ident] = f
	c.objectdata[f] = &ObjectData{Ident: ident, Package: pkg}

	if pkg == nil || pkg == c.pkg {
		if currblock := c.builder.GetInsertBlock(); !currblock.IsNil() {
			defer c.builder.SetInsertPointAtEnd(currblock)
		}
		llvmfn := c.Resolve(ident).LLVMValue()
		llvmfn = c.builder.CreateExtractValue(llvmfn, 0, "")
		llvmfn.SetLinkage(llvm.LinkOnceODRLinkage)
		entry := llvm.AddBasicBlock(llvmfn, "entry")
		c.builder.SetInsertPointAtEnd(entry)

		realfn := c.Resolve(c.objectdata[m].Ident).LLVMValue()
		realfn = c.builder.CreateExtractValue(realfn, 0, "")

		args := llvmfn.Params()
		recvarg := args[0]
		if !isptr {
			ptr := c.builder.CreateAlloca(recvarg.Type(), "")
			c.builder.CreateStore(recvarg, ptr)
			recvarg = ptr
		}
		for _, i := range indices {
			if i == -1 {
				recvarg = c.builder.CreateLoad(recvarg, "")
			} else {
				recvarg = c.builder.CreateStructGEP(recvarg, i, "")
			}
		}

		args[0] = recvarg
		result := c.builder.CreateCall(realfn, args, "")
		if sig.Results().Len() == 0 {
			c.builder.CreateRetVoid()
		} else {
			c.builder.CreateRet(result)
		}
	}
	return f
}
Exemplo n.º 7
0
func (c *compiler) VisitForStmt(stmt *ast.ForStmt) {
	currBlock := c.builder.GetInsertBlock()
	doneBlock := llvm.AddBasicBlock(currBlock.Parent(), "done")
	doneBlock.MoveAfter(currBlock)
	loopBlock := llvm.InsertBasicBlock(doneBlock, "loop")
	defer c.builder.SetInsertPointAtEnd(doneBlock)

	condBlock := loopBlock
	if stmt.Cond != nil {
		condBlock = llvm.InsertBasicBlock(loopBlock, "cond")
	}

	postBlock := condBlock
	if stmt.Post != nil {
		postBlock = llvm.InsertBasicBlock(doneBlock, "post")
	}

	if c.lastlabel != nil {
		labelData := c.labelData(c.lastlabel)
		labelData.Break = doneBlock
		labelData.Continue = postBlock
		c.lastlabel = nil
	}

	c.breakblocks = append(c.breakblocks, doneBlock)
	c.continueblocks = append(c.continueblocks, postBlock)
	defer func() {
		c.breakblocks = c.breakblocks[:len(c.breakblocks)-1]
		c.continueblocks = c.continueblocks[:len(c.continueblocks)-1]
	}()

	// Is there an initializer? Create a new scope and visit the statement.
	if stmt.Init != nil {
		c.VisitStmt(stmt.Init)
	}

	// Start the loop.
	if stmt.Cond != nil {
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		condVal := c.VisitExpr(stmt.Cond)
		c.builder.CreateCondBr(condVal.LLVMValue(), loopBlock, doneBlock)
	} else {
		c.builder.CreateBr(loopBlock)
	}

	// Post.
	if stmt.Post != nil {
		c.builder.SetInsertPointAtEnd(postBlock)
		c.VisitStmt(stmt.Post)
		c.builder.CreateBr(condBlock)
	}

	// Loop body.
	c.builder.SetInsertPointAtEnd(loopBlock)
	c.VisitBlockStmt(stmt.Body, false)
	c.maybeImplicitBranch(postBlock)
}
Exemplo n.º 8
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.NamedFunction("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.NamedFunction("runtime.main", "func(int32, **byte, **byte, *int8) int32")
	main := c.NamedFunction("main", "func(int32, **byte, **byte) int32")
	c.builder.SetCurrentDebugLocation(c.debug_info.MDNode(nil))
	entry := llvm.AddBasicBlock(main, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	mainMain = c.builder.CreateBitCast(mainMain, runtimeMain.Type().ElementType().ParamTypes()[3], "")
	args := []llvm.Value{main.Param(0), main.Param(1), main.Param(2), mainMain}
	result := c.builder.CreateCall(runtimeMain, args, "")
	c.builder.CreateRet(result)
	return nil
}
Exemplo n.º 9
0
func (c *compiler) defineMallocFunction(fn llvm.Value) {
	entry := llvm.AddBasicBlock(fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	size := fn.FirstParam()
	ptr := c.builder.CreateArrayMalloc(llvm.Int8Type(), size, "")
	// XXX memset to zero, or leave that to Go runtime code?
	fn_type := fn.Type().ElementType()
	result := c.builder.CreatePtrToInt(ptr, fn_type.ReturnType(), "")
	c.builder.CreateRet(result)
}
Exemplo n.º 10
0
Arquivo: labels.go Projeto: payco/llgo
func (c *compiler) labelData(label *ast.Ident) *LabelData {
	data, ok := label.Obj.Data.(*LabelData)
	if !ok {
		bb := c.builder.GetInsertBlock()
		data = &LabelData{}
		data.Goto = llvm.AddBasicBlock(bb.Parent(), label.Name)
		label.Obj.Data = data
	}
	return data
}
Exemplo n.º 11
0
Arquivo: stmt.go Projeto: spate/llgo
func (c *compiler) VisitLabeledStmt(stmt *ast.LabeledStmt) {
	currBlock := c.builder.GetInsertBlock()
	labeledBlock, _ := stmt.Label.Obj.Data.(llvm.BasicBlock)
	if labeledBlock.IsNil() {
		labeledBlock = llvm.AddBasicBlock(currBlock.Parent(), stmt.Label.Name)
		stmt.Label.Obj.Data = labeledBlock
	}
	labeledBlock.MoveAfter(currBlock)
	c.builder.CreateBr(labeledBlock)
	c.builder.SetInsertPointAtEnd(labeledBlock)
	c.VisitStmt(stmt.Stmt)
}
Exemplo n.º 12
0
func (c *compiler) VisitForStmt(stmt *ast.ForStmt) {
	curr_block := c.builder.GetInsertBlock()
	var cond_block, loop_block, done_block llvm.BasicBlock
	if stmt.Cond != nil {
		cond_block = llvm.AddBasicBlock(curr_block.Parent(), "cond")
	}
	loop_block = llvm.AddBasicBlock(curr_block.Parent(), "loop")
	done_block = llvm.AddBasicBlock(curr_block.Parent(), "done")

	// Is there an initializer? Create a new scope and visit the statement.
	if stmt.Init != nil {
		c.PushScope()
		c.VisitStmt(stmt.Init)
		defer c.PopScope()
	}

	// Start the loop.
	if stmt.Cond != nil {
		c.builder.CreateBr(cond_block)
		c.builder.SetInsertPointAtEnd(cond_block)
		cond_val := c.VisitExpr(stmt.Cond)
		c.builder.CreateCondBr(
			cond_val.LLVMValue(), loop_block, done_block)
	} else {
		c.builder.CreateBr(loop_block)
	}

	// Loop body.
	c.builder.SetInsertPointAtEnd(loop_block)
	c.VisitBlockStmt(stmt.Body)
	if stmt.Post != nil {
		c.VisitStmt(stmt.Post)
	}
	if stmt.Cond != nil {
		c.builder.CreateBr(cond_block)
	} else {
		c.builder.CreateBr(loop_block)
	}
	c.builder.SetInsertPointAtEnd(done_block)
}
Exemplo n.º 13
0
func (c *compiler) VisitForStmt(stmt *ast.ForStmt) {
	currBlock := c.builder.GetInsertBlock()
	doneBlock := llvm.AddBasicBlock(currBlock.Parent(), "done")
	doneBlock.MoveAfter(currBlock)
	loopBlock := llvm.InsertBasicBlock(doneBlock, "loop")
	defer c.builder.SetInsertPointAtEnd(doneBlock)

	condBlock := loopBlock
	if stmt.Cond != nil {
		condBlock = llvm.InsertBasicBlock(loopBlock, "cond")
	}

	postBlock := condBlock
	if stmt.Post != nil {
		postBlock = llvm.InsertBasicBlock(doneBlock, "post")
	}

	// Is there an initializer? Create a new scope and visit the statement.
	if stmt.Init != nil {
		c.PushScope()
		c.VisitStmt(stmt.Init)
		defer c.PopScope()
	}

	// Start the loop.
	if stmt.Cond != nil {
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		condVal := c.VisitExpr(stmt.Cond)
		c.builder.CreateCondBr(condVal.LLVMValue(), loopBlock, doneBlock)
	} else {
		c.builder.CreateBr(loopBlock)
	}

	// Post.
	if stmt.Post != nil {
		c.builder.SetInsertPointAtEnd(postBlock)
		c.VisitStmt(stmt.Post)
		c.builder.CreateBr(condBlock)
	}

	// Loop body.
	c.builder.SetInsertPointAtEnd(loopBlock)
	c.VisitBlockStmt(stmt.Body)
	c.maybeImplicitBranch(postBlock)
}
Exemplo n.º 14
0
func (c *compiler) buildPtrRecvFunction(fn llvm.Value) llvm.Value {
	defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock())
	ifname := "*" + fn.Name()
	ifn := c.module.Module.NamedFunction(ifname)
	fntyp := fn.Type().ElementType()
	entry := llvm.AddBasicBlock(ifn, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	args := ifn.Params()
	args[0] = c.builder.CreateLoad(args[0], "recv")
	result := c.builder.CreateCall(fn, args, "")
	if fntyp.ReturnType().TypeKind() == llvm.VoidTypeKind {
		c.builder.CreateRetVoid()
	} else {
		c.builder.CreateRet(result)
	}
	return ifn
}
Exemplo n.º 15
0
func (c *compiler) VisitIfStmt(stmt *ast.IfStmt) {
	curr_block := c.builder.GetInsertBlock()
	resume_block := llvm.AddBasicBlock(curr_block.Parent(), "endif")
	resume_block.MoveAfter(curr_block)

	var if_block, else_block llvm.BasicBlock
	if stmt.Else != nil {
		else_block = llvm.InsertBasicBlock(resume_block, "else")
		if_block = llvm.InsertBasicBlock(else_block, "if")
	} else {
		if_block = llvm.InsertBasicBlock(resume_block, "if")
	}
	if stmt.Else == nil {
		else_block = resume_block
	}

	if stmt.Init != nil {
		c.PushScope()
		c.VisitStmt(stmt.Init)
		defer c.PopScope()
	}

	cond_val := c.VisitExpr(stmt.Cond)
	c.builder.CreateCondBr(cond_val.LLVMValue(), if_block, else_block)
	c.builder.SetInsertPointAtEnd(if_block)
	c.VisitBlockStmt(stmt.Body)
	if in := if_block.LastInstruction(); in.IsNil() || in.IsATerminatorInst().IsNil() {
		c.builder.CreateBr(resume_block)
	}

	if stmt.Else != nil {
		c.builder.SetInsertPointAtEnd(else_block)
		c.VisitStmt(stmt.Else)
		if in := else_block.LastInstruction(); in.IsNil() || in.IsATerminatorInst().IsNil() {
			c.builder.CreateBr(resume_block)
		}
	}

	// If there's a block after the "resume" block (i.e. a nested control
	// statement), then create a branch to it as the last instruction.
	c.builder.SetInsertPointAtEnd(resume_block)
	if last := resume_block.Parent().LastBasicBlock(); last != resume_block {
		c.builder.CreateBr(last)
		c.builder.SetInsertPointBefore(resume_block.FirstInstruction())
	}
}
Exemplo n.º 16
0
// buildFunction takes a function Value, a list of parameters, and a body,
// and generates code for the function.
func (c *compiler) buildFunction(f *LLVMValue, params []*ast.Object, body *ast.BlockStmt) {
	ftyp := f.Type().(*types.Func)
	llvm_fn := f.LLVMValue()
	entry := llvm.AddBasicBlock(llvm_fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)

	// Bind receiver, arguments and return values to their identifiers/objects.
	// We'll store each parameter on the stack so they're addressable.
	for i, obj := range params {
		if obj.Name != "" {
			value := llvm_fn.Param(i)
			typ := obj.Type.(types.Type)
			stackvalue := c.builder.CreateAlloca(c.types.ToLLVM(typ), obj.Name)
			c.builder.CreateStore(value, stackvalue)
			ptrvalue := c.NewLLVMValue(stackvalue, &types.Pointer{Base: typ})
			stackvar := ptrvalue.makePointee()
			stackvar.stack = f
			obj.Data = stackvar
		}
	}

	// Allocate space on the stack for named results.
	for _, obj := range ftyp.Results {
		if obj.Name != "" {
			typ := obj.Type.(types.Type)
			llvmtyp := c.types.ToLLVM(typ)
			stackptr := c.builder.CreateAlloca(llvmtyp, obj.Name)
			c.builder.CreateStore(llvm.ConstNull(llvmtyp), stackptr)
			ptrvalue := c.NewLLVMValue(stackptr, &types.Pointer{Base: typ})
			stackvar := ptrvalue.makePointee()
			stackvar.stack = f
			obj.Data = stackvar
		}
	}

	c.functions = append(c.functions, f)
	c.VisitBlockStmt(body, false)
	c.functions = c.functions[0 : len(c.functions)-1]
	last := llvm_fn.LastBasicBlock()
	if in := last.LastInstruction(); in.IsNil() || in.IsATerminatorInst().IsNil() {
		// Assume nil return type, AST should be checked first.
		c.builder.SetInsertPointAtEnd(last)
		c.builder.CreateRetVoid()
	}
}
Exemplo n.º 17
0
func (c *compiler) defineMemsetFunction(fn llvm.Value) {
	entry := llvm.AddBasicBlock(fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)
	dst, fill, size := fn.Param(0), fn.Param(1), fn.Param(2)
	sizeType := size.Type()
	sizeBits := sizeType.IntTypeWidth()
	memsetName := "llvm.memset.p0i8.i" + strconv.Itoa(sizeBits)
	memset := c.NamedFunction(memsetName, "func f(dst *int8, fill byte, size uintptr, align int32, volatile bool)")
	pint8 := memset.Type().ElementType().ParamTypes()[0]
	dst = c.builder.CreateIntToPtr(dst, pint8, "")
	args := []llvm.Value{
		dst, fill, size,
		llvm.ConstInt(llvm.Int32Type(), 1, false), // single byte alignment
		llvm.ConstInt(llvm.Int1Type(), 0, false),  // not volatile
	}
	c.builder.CreateCall(memset, args, "")
	c.builder.CreateRetVoid()
}
Exemplo n.º 18
0
func (tm *TypeMap) interfaceFuncWrapper(f llvm.Value) llvm.Value {
	ftyp := f.Type().ElementType()
	paramTypes := ftyp.ParamTypes()
	recvType := paramTypes[0]
	paramTypes[0] = llvm.PointerType(llvm.Int8Type(), 0)
	newf := llvm.AddFunction(f.GlobalParent(), f.Name()+".ifn", llvm.FunctionType(
		ftyp.ReturnType(),
		paramTypes,
		ftyp.IsFunctionVarArg(),
	))

	b := llvm.GlobalContext().NewBuilder()
	defer b.Dispose()
	entry := llvm.AddBasicBlock(newf, "entry")
	b.SetInsertPointAtEnd(entry)
	args := make([]llvm.Value, len(paramTypes))
	for i := range paramTypes {
		args[i] = newf.Param(i)
	}

	recvBits := int(tm.target.TypeSizeInBits(recvType))
	if recvBits > 0 {
		args[0] = b.CreatePtrToInt(args[0], tm.target.IntPtrType(), "")
		if args[0].Type().IntTypeWidth() > recvBits {
			args[0] = b.CreateTrunc(args[0], llvm.IntType(recvBits), "")
		}
		args[0] = coerce(b, args[0], recvType)
	} else {
		args[0] = llvm.ConstNull(recvType)
	}

	result := b.CreateCall(f, args, "")
	if result.Type().TypeKind() == llvm.VoidTypeKind {
		b.CreateRetVoid()
	} else {
		b.CreateRet(result)
	}
	return newf
}
Exemplo n.º 19
0
Arquivo: stmt.go Projeto: kisielk/llgo
func (c *compiler) VisitBranchStmt(stmt *ast.BranchStmt) {
	// TODO handle labeled continue, break.
	switch stmt.Tok {
	case token.BREAK:
		block := c.breakblocks[len(c.breakblocks)-1]
		c.builder.CreateBr(block)
	case token.CONTINUE:
		block := c.continueblocks[len(c.continueblocks)-1]
		c.builder.CreateBr(block)
	case token.GOTO:
		block, _ := stmt.Label.Obj.Data.(llvm.BasicBlock)
		if block.IsNil() {
			f := c.builder.GetInsertBlock().Parent()
			block = llvm.AddBasicBlock(f, stmt.Label.Name)
			stmt.Label.Obj.Data = block
		}
		c.builder.CreateBr(block)
	default:
		// TODO implement goto, fallthrough
		panic("unimplemented: " + stmt.Tok.String())
	}
}
Exemplo n.º 20
0
func (c *compiler) VisitFuncLit(lit *ast.FuncLit) Value {
	fn_type := c.VisitFuncType(lit.Type)
	fn := llvm.AddFunction(c.module.Module, "", c.types.ToLLVM(fn_type))
	fn.SetFunctionCallConv(llvm.FastCallConv)

	defer c.builder.SetInsertPointAtEnd(c.builder.GetInsertBlock())
	entry := llvm.AddBasicBlock(fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)

	fn_value := c.NewLLVMValue(fn, fn_type)
	c.functions = append(c.functions, fn_value)
	c.VisitBlockStmt(lit.Body)
	if fn_type.Results == nil {
		lasti := entry.LastInstruction()
		if lasti.IsNil() || lasti.Opcode() != llvm.Ret {
			// Assume nil return type, AST should be checked first.
			c.builder.CreateRetVoid()
		}
	}
	c.functions = c.functions[0 : len(c.functions)-1]
	return fn_value
}
Exemplo n.º 21
0
// indirectFunction creates an indirect function from a
// given function, suitable for use with "defer" and "go".
func (c *compiler) indirectFunction(fn *LLVMValue, args []Value, dotdotdot bool) *LLVMValue {
	nilarytyp := &types.Signature{}
	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, "")
		fn = c.NewValue(fnval, nilarytyp)
		return fn
	}

	// TODO check if function pointer is global. I suppose
	// the same can be done with the context ptr...
	fnval := fn.LLVMValue()
	fnptr := c.builder.CreateExtractValue(fnval, 0, "")
	ctx := c.builder.CreateExtractValue(fnval, 1, "")
	nctx := 1 // fnptr
	if !ctx.IsNull() {
		nctx++ // fnctx
	}

	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()
	}
	llvmargtypes[0] = fnptr.Type()
	llvmargs[0] = fnptr
	if nctx > 1 {
		llvmargtypes[1] = ctx.Type()
		llvmargs[1] = ctx
	}

	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)
	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)}, "")
		ptrtyp := types.NewPointer(args[i].Type())
		args[i] = c.NewValue(argptr, ptrtyp).makePointee()
	}

	// Extract the function pointer.
	// TODO if function is a global, elide.
	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 nctx > 1 {
		ctxptr := c.builder.CreateGEP(argstruct, []llvm.Value{
			llvm.ConstInt(llvm.Int32Type(), 0, false),
			llvm.ConstInt(llvm.Int32Type(), 1, false)}, "")
		ctx = c.builder.CreateLoad(ctxptr, "")
		fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "")
		fn = c.NewValue(fnval, fn.Type())
	}
	c.createCall(fn, args, dotdotdot, false)

	// 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
}
Exemplo n.º 22
0
Arquivo: ssa.go Projeto: pcc/llgo
func (fr *frame) value(v ssa.Value) (result *LLVMValue) {
	switch v := v.(type) {
	case nil:
		return nil
	case *ssa.Function:
		result, ok := fr.funcvals[v]
		if ok {
			return result
		}
		// fr.globals[v] has the function in raw pointer form;
		// we must convert it to <f,ctx> form. If the function
		// does not have a receiver, then create a wrapper
		// function that has an additional "context" parameter.
		f := fr.resolveFunction(v)
		if v.Signature.Recv() == nil && len(v.FreeVars) == 0 {
			f = contextFunction(fr.compiler, f)
		}
		pair := llvm.ConstNull(fr.llvmtypes.ToLLVM(f.Type()))
		fnptr := llvm.ConstBitCast(f.LLVMValue(), pair.Type().StructElementTypes()[0])
		pair = llvm.ConstInsertValue(pair, fnptr, []uint32{0})
		result = fr.NewValue(pair, f.Type())
		fr.funcvals[v] = result
		return result
	case *ssa.Const:
		return fr.NewConstValue(v.Value, v.Type())
	case *ssa.Global:
		if g, ok := fr.globals[v]; ok {
			return g
		}
		// Create an external global. Globals for this package are defined
		// on entry to translatePackage, and have initialisers.
		llelemtyp := fr.llvmtypes.ToLLVM(deref(v.Type()))
		llglobal := llvm.AddGlobal(fr.module.Module, llelemtyp, v.String())
		global := fr.NewValue(llglobal, v.Type())
		fr.globals[v] = global
		return global
	}
	if value, ok := fr.env[v]; ok {
		return value
	}

	// Instructions are not necessarily visited before they are used (e.g. Phi
	// edges) so we must "backpatch": create a value with the resultant type,
	// and then replace it when we visit the instruction.
	if b, ok := fr.backpatch[v]; ok {
		return b
	}
	if fr.backpatch == nil {
		fr.backpatch = make(map[ssa.Value]*LLVMValue)
	}
	// Note: we must not create a constant here (e.g. Undef/ConstNull), as
	// it is not permissible to replace a constant with a non-constant.
	// We must create the value in its own standalone basic block, so we can
	// dispose of it after replacing.
	currBlock := fr.builder.GetInsertBlock()
	fr.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(currBlock.Parent(), ""))
	placeholder := fr.compiler.builder.CreatePHI(fr.llvmtypes.ToLLVM(v.Type()), "")
	fr.builder.SetInsertPointAtEnd(currBlock)
	value := fr.NewValue(placeholder, v.Type())
	fr.backpatch[v] = value
	return value
}
Exemplo n.º 23
0
Arquivo: ssa.go Projeto: pcc/llgo
func (u *unit) defineFunction(f *ssa.Function) {
	// Nothing to do for functions without bodies.
	if len(f.Blocks) == 0 {
		return
	}

	// Only define functions from this package.
	if f.Pkg == nil {
		if r := f.Signature.Recv(); r != nil && r.Pkg() != nil && r.Pkg() != u.pkg.Object {
			return
		}
	} else if f.Pkg != u.pkg {
		return
	}

	fr := frame{
		unit:   u,
		blocks: make([]llvm.BasicBlock, len(f.Blocks)),
		env:    make(map[ssa.Value]*LLVMValue),
	}

	fr.logf("Define function: %s", f.String())
	llvmFunction := fr.resolveFunction(f).LLVMValue()
	delete(u.undefinedFuncs, f)

	// Functions that call recover must not be inlined, or we
	// can't tell whether the recover call is valid at runtime.
	if f.Recover != nil {
		llvmFunction.AddFunctionAttr(llvm.NoInlineAttribute)
	}

	for i, block := range f.Blocks {
		fr.blocks[i] = llvm.AddBasicBlock(llvmFunction, fmt.Sprintf(".%d.%s", i, block.Comment))
	}
	fr.builder.SetInsertPointAtEnd(fr.blocks[0])

	var paramOffset int
	if len(f.FreeVars) > 0 {
		// Extract captures from the first implicit parameter.
		arg0 := llvmFunction.Param(0)
		for i, fv := range f.FreeVars {
			addressPtr := fr.builder.CreateStructGEP(arg0, i, "")
			address := fr.builder.CreateLoad(addressPtr, "")
			fr.env[fv] = fr.NewValue(address, fv.Type())
		}
		paramOffset++
	}
	for i, param := range f.Params {
		fr.env[param] = fr.NewValue(llvmFunction.Param(i+paramOffset), param.Type())
	}

	// Allocate stack space for locals in the prologue block.
	prologueBlock := llvm.InsertBasicBlock(fr.blocks[0], "prologue")
	fr.builder.SetInsertPointAtEnd(prologueBlock)
	for _, local := range f.Locals {
		typ := fr.llvmtypes.ToLLVM(deref(local.Type()))
		alloca := fr.builder.CreateAlloca(typ, local.Comment)
		u.memsetZero(alloca, llvm.SizeOf(typ))
		value := fr.NewValue(alloca, local.Type())
		fr.env[local] = value
	}

	// Move any allocs relating to named results from the entry block
	// to the prologue block, so they dominate the rundefers and recover
	// blocks.
	//
	// TODO(axw) ask adonovan for a cleaner way of doing this, e.g.
	// have ssa generate an entry block that defines Allocs and related
	// stores, and then a separate block for function body instructions.
	if f.Synthetic == "" {
		if results := f.Signature.Results(); results != nil {
			for i := 0; i < results.Len(); i++ {
				result := results.At(i)
				if result.Name() == "" {
					break
				}
				for i, instr := range f.Blocks[0].Instrs {
					if instr, ok := instr.(*ssa.Alloc); ok && instr.Heap && instr.Pos() == result.Pos() {
						fr.instruction(instr)
						instrs := f.Blocks[0].Instrs
						instrs = append(instrs[:i], instrs[i+1:]...)
						f.Blocks[0].Instrs = instrs
						break
					}
				}
			}
		}
	}

	// If the function contains any defers, we must first call
	// setjmp so we can call rundefers in response to a panic.
	// We can short-circuit the check for defers with
	// f.Recover != nil.
	if f.Recover != nil || hasDefer(f) {
		rdblock := llvm.AddBasicBlock(llvmFunction, "rundefers")
		defers := fr.builder.CreateAlloca(fr.runtime.defers.llvm, "")
		fr.builder.CreateCall(fr.runtime.initdefers.LLVMValue(), []llvm.Value{defers}, "")
		jb := fr.builder.CreateStructGEP(defers, 0, "")
		jb = fr.builder.CreateBitCast(jb, llvm.PointerType(llvm.Int8Type(), 0), "")
		result := fr.builder.CreateCall(fr.runtime.setjmp.LLVMValue(), []llvm.Value{jb}, "")
		result = fr.builder.CreateIsNotNull(result, "")
		fr.builder.CreateCondBr(result, rdblock, fr.blocks[0])
		// We'll only get here via a panic, which must either be
		// recovered or continue panicking up the stack without
		// returning from "rundefers". The recover block may be
		// nil even if we can recover, in which case we just need
		// to return the zero value for each result (if any).
		var recoverBlock llvm.BasicBlock
		if f.Recover != nil {
			recoverBlock = fr.block(f.Recover)
		} else {
			recoverBlock = llvm.AddBasicBlock(llvmFunction, "recover")
			fr.builder.SetInsertPointAtEnd(recoverBlock)
			var nresults int
			results := f.Signature.Results()
			if results != nil {
				nresults = results.Len()
			}
			switch nresults {
			case 0:
				fr.builder.CreateRetVoid()
			case 1:
				fr.builder.CreateRet(llvm.ConstNull(fr.llvmtypes.ToLLVM(results.At(0).Type())))
			default:
				values := make([]llvm.Value, nresults)
				for i := range values {
					values[i] = llvm.ConstNull(fr.llvmtypes.ToLLVM(results.At(i).Type()))
				}
				fr.builder.CreateAggregateRet(values)
			}
		}
		fr.builder.SetInsertPointAtEnd(rdblock)
		fr.builder.CreateCall(fr.runtime.rundefers.LLVMValue(), nil, "")
		fr.builder.CreateBr(recoverBlock)
	} else {
		fr.builder.CreateBr(fr.blocks[0])
	}

	for i, block := range f.Blocks {
		fr.translateBlock(block, fr.blocks[i])
	}
}
Exemplo n.º 24
0
Arquivo: stmt.go Projeto: qioixiy/llgo
func (c *compiler) VisitTypeSwitchStmt(stmt *ast.TypeSwitchStmt) {
	if stmt.Init != nil {
		c.VisitStmt(stmt.Init)
	}

	var assignIdent *ast.Ident
	var typeAssertExpr *ast.TypeAssertExpr
	switch stmt := stmt.Assign.(type) {
	case *ast.AssignStmt:
		assignIdent = stmt.Lhs[0].(*ast.Ident)
		typeAssertExpr = stmt.Rhs[0].(*ast.TypeAssertExpr)
	case *ast.ExprStmt:
		typeAssertExpr = stmt.X.(*ast.TypeAssertExpr)
	}
	if len(stmt.Body.List) == 0 {
		// No case clauses, so just evaluate the expression.
		c.VisitExpr(typeAssertExpr.X)
		return
	}

	currBlock := c.builder.GetInsertBlock()
	endBlock := llvm.AddBasicBlock(currBlock.Parent(), "")
	endBlock.MoveAfter(currBlock)
	defer c.builder.SetInsertPointAtEnd(endBlock)

	// Add a "break" block to the stack.
	c.breakblocks = append(c.breakblocks, endBlock)
	defer func() { c.breakblocks = c.breakblocks[:len(c.breakblocks)-1] }()

	// TODO: investigate the use of a switch instruction
	//       on the type's hash (when we compute type hashes).

	// Create blocks for each statement.
	defaultBlock := endBlock
	var condBlocks []llvm.BasicBlock
	var stmtBlocks []llvm.BasicBlock
	for _, stmt := range stmt.Body.List {
		caseClause := stmt.(*ast.CaseClause)
		if caseClause.List == nil {
			defaultBlock = llvm.InsertBasicBlock(endBlock, "")
		} else {
			condBlock := llvm.InsertBasicBlock(endBlock, "")
			stmtBlock := llvm.InsertBasicBlock(endBlock, "")
			condBlocks = append(condBlocks, condBlock)
			stmtBlocks = append(stmtBlocks, stmtBlock)
		}
	}
	stmtBlocks = append(stmtBlocks, defaultBlock)

	// Evaluate the expression, then jump to the first condition block.
	iface := c.VisitExpr(typeAssertExpr.X).(*LLVMValue)
	if len(stmt.Body.List) == 1 && defaultBlock != endBlock {
		c.builder.CreateBr(defaultBlock)
	} else {
		c.builder.CreateBr(condBlocks[0])
	}

	i := 0
	for _, stmt := range stmt.Body.List {
		caseClause := stmt.(*ast.CaseClause)
		if caseClause.List != nil {
			c.builder.SetInsertPointAtEnd(condBlocks[i])
			stmtBlock := stmtBlocks[i]
			nextCondBlock := defaultBlock
			if i+1 < len(condBlocks) {
				nextCondBlock = condBlocks[i+1]
			}
			caseCond := func(j int) Value {
				if c.isNilIdent(caseClause.List[j]) {
					iface := iface.LLVMValue()
					ifacetyp := c.builder.CreateExtractValue(iface, 0, "")
					isnil := c.builder.CreateIsNull(ifacetyp, "")
					return c.NewValue(isnil, types.Typ[types.Bool])
				}
				typ := c.typeinfo.Types[caseClause.List[j]]
				switch typ := typ.Underlying().(type) {
				case *types.Interface:
					_, ok := iface.convertI2I(typ)
					return ok
				}
				return iface.interfaceTypeEquals(typ)
			}
			cond := caseCond(0)
			for j := 1; j < len(caseClause.List); j++ {
				f := func() Value {
					return caseCond(j)
				}
				cond = c.compileLogicalOp(token.LOR, cond, f).(*LLVMValue)
			}
			c.builder.CreateCondBr(cond.LLVMValue(), stmtBlock, nextCondBlock)
			i++
		}
	}

	i = 0
	for _, stmt := range stmt.Body.List {
		caseClause := stmt.(*ast.CaseClause)
		var block llvm.BasicBlock
		var typ types.Type
		if caseClause.List != nil {
			block = stmtBlocks[i]
			if len(caseClause.List) == 1 {
				typ = c.typeinfo.Types[caseClause.List[0]]
			}
			i++
		} else {
			block = defaultBlock
		}
		c.builder.SetInsertPointAtEnd(block)
		if assignIdent != nil {
			obj := c.typeinfo.Implicits[caseClause]
			if len(caseClause.List) == 1 && !c.isNilIdent(caseClause.List[0]) {
				switch utyp := typ.Underlying().(type) {
				case *types.Interface:
					// FIXME Use value from convertI2I in the case
					// clause condition test.
					c.objectdata[obj].Value, _ = iface.convertI2I(utyp)
				default:
					c.objectdata[obj].Value = iface.loadI2V(typ)
				}
			} else {
				c.objectdata[obj].Value = iface
			}
		}
		for _, stmt := range caseClause.Body {
			c.VisitStmt(stmt)
		}
		c.maybeImplicitBranch(endBlock)
	}
}
Exemplo n.º 25
0
func (c *compiler) VisitSelectStmt(stmt *ast.SelectStmt) {
	// TODO optimisations:
	//     1. No clauses: runtime.block.
	//     2. Single recv, and default clause: runtime.selectnbrecv
	//     2. Single send, and default clause: runtime.selectnbsend

	startBlock := c.builder.GetInsertBlock()
	function := startBlock.Parent()
	endBlock := llvm.AddBasicBlock(function, "end")
	endBlock.MoveAfter(startBlock)
	defer c.builder.SetInsertPointAtEnd(endBlock)

	// Cache runtime functions
	var selectrecv, selectsend llvm.Value
	getselectsend := func() llvm.Value {
		if selectsend.IsNil() {
			selectsend = c.NamedFunction("runtime.selectsend", "func(selectp, blockaddr, ch, elem unsafe.Pointer)")
		}
		return selectsend
	}
	getselectrecv := func() llvm.Value {
		if selectrecv.IsNil() {
			selectrecv = c.NamedFunction("runtime.selectrecv", "func(selectp, blockaddr, ch, elem unsafe.Pointer, received *bool)")
		}
		return selectrecv
	}

	// We create a pointer-pointer for each newly defined var on the
	// lhs of receive expressions, which will be assigned to when the
	// expressions are (conditionally) evaluated.
	lhsptrs := make([][]llvm.Value, len(stmt.Body.List))
	for i, stmt := range stmt.Body.List {
		clause := stmt.(*ast.CommClause)
		if stmt, ok := clause.Comm.(*ast.AssignStmt); ok && stmt.Tok == token.DEFINE {
			lhs := make([]llvm.Value, len(stmt.Lhs))
			for i, expr := range stmt.Lhs {
				ident := expr.(*ast.Ident)
				if !isBlank(ident.Name) {
					typ := c.target.IntPtrType()
					lhs[i] = c.builder.CreateAlloca(typ, "")
					c.builder.CreateStore(llvm.ConstNull(typ), lhs[i])
				}
			}
			lhsptrs[i] = lhs
		}
	}

	// Create clause basic blocks.
	blocks := make([]llvm.BasicBlock, len(stmt.Body.List))
	var basesize uint64
	for i, stmt := range stmt.Body.List {
		clause := stmt.(*ast.CommClause)
		if clause.Comm == nil {
			basesize++
		}
		currBlock := c.builder.GetInsertBlock()
		block := llvm.InsertBasicBlock(endBlock, "")
		c.builder.SetInsertPointAtEnd(block)
		blocks[i] = block
		lhs := lhsptrs[i]
		if stmt, ok := clause.Comm.(*ast.AssignStmt); ok {
			for i, expr := range stmt.Lhs {
				ident := expr.(*ast.Ident)
				if !isBlank(ident.Name) {
					ptr := c.builder.CreateLoad(lhs[i], "")
					obj := c.typeinfo.Objects[ident]
					ptrtyp := types.NewPointer(obj.Type())
					ptr = c.builder.CreateIntToPtr(ptr, c.types.ToLLVM(ptrtyp), "")
					value := c.NewValue(ptr, ptrtyp).makePointee()
					c.objectdata[obj].Value = value
				}
			}
		}
		for _, stmt := range clause.Body {
			c.VisitStmt(stmt)
		}
		c.maybeImplicitBranch(endBlock)
		c.builder.SetInsertPointAtEnd(currBlock)
	}

	// We need to make an initial pass through the cases,
	// discarding those where the channel is nil.
	size := llvm.ConstInt(llvm.Int32Type(), basesize, false)
	channels := make([]Value, len(stmt.Body.List))
	rhs := make([]*LLVMValue, len(stmt.Body.List))
	for i, stmt := range stmt.Body.List {
		clause := stmt.(*ast.CommClause)
		switch comm := clause.Comm.(type) {
		case nil:
		case *ast.SendStmt:
			channels[i] = c.VisitExpr(comm.Chan)
			rhs[i] = c.VisitExpr(comm.Value).(*LLVMValue)
		case *ast.ExprStmt:
			channels[i] = c.VisitExpr(comm.X.(*ast.UnaryExpr).X)
		case *ast.AssignStmt:
			channels[i] = c.VisitExpr(comm.Rhs[0].(*ast.UnaryExpr).X)
		default:
			panic(fmt.Errorf("unhandled: %T", comm))
		}
		if channels[i] != nil {
			nonnil := c.builder.CreateIsNotNull(channels[i].LLVMValue(), "")
			zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
			one := llvm.ConstInt(llvm.Int32Type(), 1, false)
			addend := c.builder.CreateSelect(nonnil, one, zero, "")
			size = c.builder.CreateAdd(size, addend, "")
		}
	}

	f := c.NamedFunction("runtime.selectsize", "func(size int32) uintptr")
	selectsize := c.builder.CreateCall(f, []llvm.Value{size}, "")
	selectp := c.builder.CreateArrayAlloca(llvm.Int8Type(), selectsize, "selectp")
	c.memsetZero(selectp, selectsize)
	selectp = c.builder.CreatePtrToInt(selectp, c.target.IntPtrType(), "")
	f = c.NamedFunction("runtime.initselect", "func(size int32, ptr unsafe.Pointer)")
	c.builder.CreateCall(f, []llvm.Value{size, selectp}, "")

	for i, stmt := range stmt.Body.List {
		clause := stmt.(*ast.CommClause)
		blockaddr := llvm.BlockAddress(function, blocks[i])
		blockaddr = c.builder.CreatePtrToInt(blockaddr, c.target.IntPtrType(), "")
		if clause.Comm == nil {
			// default clause
			f := c.NamedFunction("runtime.selectdefault", "func(selectp, blockaddr unsafe.Pointer)")
			c.builder.CreateCall(f, []llvm.Value{selectp, blockaddr}, "")
			continue
		}

		currBlock := c.builder.GetInsertBlock()
		nextBlock := llvm.InsertBasicBlock(currBlock, "")
		nextBlock.MoveAfter(currBlock)
		block := llvm.InsertBasicBlock(endBlock, "")
		chanval := channels[i].LLVMValue()
		nonnilchan := c.builder.CreateIsNotNull(chanval, "")
		c.builder.CreateCondBr(nonnilchan, block, nextBlock)
		c.builder.SetInsertPointAtEnd(block)

		switch comm := clause.Comm.(type) {
		case *ast.SendStmt:
			// c <- val
			elem := rhs[i]
			var elemptr llvm.Value
			if elem.pointer == nil {
				value := elem.LLVMValue()
				elemptr = c.builder.CreateAlloca(value.Type(), "")
				c.builder.CreateStore(value, elemptr)
			} else {
				elemptr = elem.pointer.LLVMValue()
			}
			elemptr = c.builder.CreatePtrToInt(elemptr, c.target.IntPtrType(), "")
			f := getselectsend()
			c.builder.CreateCall(f, []llvm.Value{selectp, blockaddr, chanval, elemptr}, "")

		case *ast.ExprStmt:
			// <-c
			f := getselectrecv()
			paramtypes := f.Type().ElementType().ParamTypes()
			elem := llvm.ConstNull(paramtypes[3])
			received := llvm.ConstNull(paramtypes[4])
			c.builder.CreateCall(f, []llvm.Value{selectp, blockaddr, chanval, elem, received}, "")

		case *ast.AssignStmt:
			// val := <-c
			// val, ok = <-c
			f := getselectrecv()
			lhs := c.assignees(comm)
			paramtypes := f.Type().ElementType().ParamTypes()
			var elem llvm.Value
			if lhs[0] != nil {
				elem = lhs[0].pointer.LLVMValue()
				elem = c.builder.CreatePtrToInt(elem, paramtypes[3], "")
				if !lhsptrs[i][0].IsNil() {
					c.builder.CreateStore(elem, lhsptrs[i][0])
				}
			} else {
				elem = llvm.ConstNull(paramtypes[3])
			}
			var received llvm.Value
			if len(lhs) == 2 && lhs[1] != nil {
				received = lhs[1].pointer.LLVMValue()
				received = c.builder.CreatePtrToInt(received, paramtypes[4], "")
				if !lhsptrs[i][1].IsNil() {
					c.builder.CreateStore(received, lhsptrs[i][1])
				}
			} else {
				received = llvm.ConstNull(paramtypes[4])
			}
			c.builder.CreateCall(f, []llvm.Value{selectp, blockaddr, chanval, elem, received}, "")
		}

		c.builder.CreateBr(nextBlock)
		c.builder.SetInsertPointAtEnd(nextBlock)
	}

	f = c.NamedFunction("runtime.selectgo", "func(selectp unsafe.Pointer) unsafe.Pointer")
	blockaddr := c.builder.CreateCall(f, []llvm.Value{selectp}, "")
	blockaddr = c.builder.CreateIntToPtr(blockaddr, llvm.PointerType(llvm.Int8Type(), 0), "")
	ibr := c.builder.CreateIndirectBr(blockaddr, len(stmt.Body.List))
	for _, block := range blocks {
		ibr.AddDest(block)
	}
}
Exemplo n.º 26
0
Arquivo: stmt.go Projeto: qioixiy/llgo
func (c *compiler) VisitRangeStmt(stmt *ast.RangeStmt) {
	currBlock := c.builder.GetInsertBlock()
	doneBlock := llvm.AddBasicBlock(currBlock.Parent(), "done")
	doneBlock.MoveAfter(currBlock)
	postBlock := llvm.InsertBasicBlock(doneBlock, "post")
	loopBlock := llvm.InsertBasicBlock(postBlock, "loop")
	condBlock := llvm.InsertBasicBlock(loopBlock, "cond")
	defer c.builder.SetInsertPointAtEnd(doneBlock)

	// Evaluate range expression first.
	x := c.VisitExpr(stmt.X)

	// If it's a pointer type, we'll first check that it's non-nil.
	typ := x.Type().Underlying()
	if _, ok := typ.(*types.Pointer); ok {
		ifBlock := llvm.InsertBasicBlock(doneBlock, "if")
		isnotnull := c.builder.CreateIsNotNull(x.LLVMValue(), "")
		c.builder.CreateCondBr(isnotnull, ifBlock, doneBlock)
		c.builder.SetInsertPointAtEnd(ifBlock)
	}

	// Is it a new var definition? Then allocate some memory on the stack.
	var keyPtr, valuePtr llvm.Value
	if stmt.Tok == token.DEFINE {
		if key := stmt.Key.(*ast.Ident); !isBlank(key.Name) {
			keyobj := c.typeinfo.Objects[key]
			keyPtr, _ = c.newStackVar(c.functions.top().LLVMValue, keyobj, llvm.Value{}, key.Name)
		}
		if stmt.Value != nil {
			if value := stmt.Value.(*ast.Ident); !isBlank(value.Name) {
				valueobj := c.typeinfo.Objects[value]
				valuePtr, _ = c.newStackVar(c.functions.top().LLVMValue, valueobj, llvm.Value{}, value.Name)
			}
		}
	} else {
		// Simple assignment, resolve the key/value pointers.
		if key := stmt.Key.(*ast.Ident); !isBlank(key.Name) {
			keyPtr = c.Resolve(key).(*LLVMValue).pointer.LLVMValue()
		}
		if stmt.Value != nil {
			if value := stmt.Value.(*ast.Ident); !isBlank(value.Name) {
				valuePtr = c.Resolve(value).(*LLVMValue).pointer.LLVMValue()
			}
		}
	}

	if c.lastlabel != nil {
		labelData := c.labelData(c.lastlabel)
		labelData.Break = doneBlock
		labelData.Continue = postBlock
		c.lastlabel = nil
	}

	c.breakblocks = append(c.breakblocks, doneBlock)
	c.continueblocks = append(c.continueblocks, postBlock)
	defer func() {
		c.breakblocks = c.breakblocks[:len(c.breakblocks)-1]
		c.continueblocks = c.continueblocks[:len(c.continueblocks)-1]
	}()

	isarray := false
	var base, length llvm.Value
	_, isptr := typ.(*types.Pointer)
	if isptr {
		typ = typ.(*types.Pointer).Elem()
	}
	switch typ := typ.Underlying().(type) {
	case *types.Map:
		goto maprange
	case *types.Chan:
		goto chanrange
	case *types.Basic:
		stringvalue := x.LLVMValue()
		length = c.builder.CreateExtractValue(stringvalue, 1, "")
		goto stringrange
	case *types.Array:
		isarray = true
		x := x
		if !isptr {
			if x_, ok := x.(*LLVMValue); ok && x_.pointer != nil {
				x = x_.pointer
			} else {
				ptr := c.builder.CreateAlloca(c.types.ToLLVM(x.Type()), "")
				c.builder.CreateStore(x.LLVMValue(), ptr)
				x = c.NewValue(ptr, types.NewPointer(x.Type()))
			}
		}
		base = x.LLVMValue()
		length = llvm.ConstInt(c.llvmtypes.inttype, uint64(typ.Len()), false)
		goto arrayrange
	case *types.Slice:
		slicevalue := x.LLVMValue()
		base = c.builder.CreateExtractValue(slicevalue, 0, "")
		length = c.builder.CreateExtractValue(slicevalue, 1, "")
		goto arrayrange
	}
	panic("unreachable")

maprange:
	{
		currBlock = c.builder.GetInsertBlock()
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		nextptrphi := c.builder.CreatePHI(c.target.IntPtrType(), "next")
		nextptr, pk, pv := c.mapNext(x.(*LLVMValue), nextptrphi)
		notnull := c.builder.CreateIsNotNull(nextptr, "")
		c.builder.CreateCondBr(notnull, loopBlock, doneBlock)
		c.builder.SetInsertPointAtEnd(loopBlock)
		if !keyPtr.IsNil() {
			keyval := c.builder.CreateLoad(pk, "")
			c.builder.CreateStore(keyval, keyPtr)
		}
		if !valuePtr.IsNil() {
			valval := c.builder.CreateLoad(pv, "")
			c.builder.CreateStore(valval, valuePtr)
		}
		c.VisitBlockStmt(stmt.Body, false)
		c.maybeImplicitBranch(postBlock)
		c.builder.SetInsertPointAtEnd(postBlock)
		c.builder.CreateBr(condBlock)
		nextptrphi.AddIncoming([]llvm.Value{llvm.ConstNull(c.target.IntPtrType()), nextptr}, []llvm.BasicBlock{currBlock, postBlock})
		return
	}

stringrange:
	{
		zero := llvm.ConstNull(c.types.inttype)
		currBlock = c.builder.GetInsertBlock()
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		index := c.builder.CreatePHI(c.types.inttype, "index")
		lessthan := c.builder.CreateICmp(llvm.IntULT, index, length, "")
		c.builder.CreateCondBr(lessthan, loopBlock, doneBlock)
		c.builder.SetInsertPointAtEnd(loopBlock)
		consumed, value := c.stringNext(x.LLVMValue(), index)
		if !keyPtr.IsNil() {
			c.builder.CreateStore(index, keyPtr)
		}
		if !valuePtr.IsNil() {
			c.builder.CreateStore(value, valuePtr)
		}
		c.VisitBlockStmt(stmt.Body, false)
		c.maybeImplicitBranch(postBlock)
		c.builder.SetInsertPointAtEnd(postBlock)
		newindex := c.builder.CreateAdd(index, consumed, "")
		c.builder.CreateBr(condBlock)
		index.AddIncoming([]llvm.Value{zero, newindex}, []llvm.BasicBlock{currBlock, postBlock})
		return
	}

arrayrange:
	{
		zero := llvm.ConstNull(c.types.inttype)
		currBlock = c.builder.GetInsertBlock()
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		index := c.builder.CreatePHI(c.types.inttype, "index")
		lessthan := c.builder.CreateICmp(llvm.IntULT, index, length, "")
		c.builder.CreateCondBr(lessthan, loopBlock, doneBlock)
		c.builder.SetInsertPointAtEnd(loopBlock)
		if !keyPtr.IsNil() {
			c.builder.CreateStore(index, keyPtr)
		}
		if !valuePtr.IsNil() {
			var indices []llvm.Value
			if isarray {
				indices = []llvm.Value{zero, index}
			} else {
				indices = []llvm.Value{index}
			}
			elementptr := c.builder.CreateGEP(base, indices, "")
			element := c.builder.CreateLoad(elementptr, "")
			c.builder.CreateStore(element, valuePtr)
		}
		c.VisitBlockStmt(stmt.Body, false)
		c.maybeImplicitBranch(postBlock)
		c.builder.SetInsertPointAtEnd(postBlock)
		newindex := c.builder.CreateAdd(index, llvm.ConstInt(c.types.inttype, 1, false), "")
		c.builder.CreateBr(condBlock)
		index.AddIncoming([]llvm.Value{zero, newindex}, []llvm.BasicBlock{currBlock, postBlock})
		return
	}

chanrange:
	{
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		value, received := x.(*LLVMValue).chanRecv(true)
		c.builder.CreateCondBr(received.LLVMValue(), loopBlock, doneBlock)
		c.builder.SetInsertPointAtEnd(loopBlock)
		if !keyPtr.IsNil() {
			c.builder.CreateStore(value.LLVMValue(), keyPtr)
		}
		c.VisitBlockStmt(stmt.Body, false)
		c.maybeImplicitBranch(postBlock)
		c.builder.SetInsertPointAtEnd(postBlock)
		c.builder.CreateBr(condBlock)
		return
	}
}
Exemplo n.º 27
0
Arquivo: stmt.go Projeto: qioixiy/llgo
func (c *compiler) VisitSwitchStmt(stmt *ast.SwitchStmt) {
	if stmt.Init != nil {
		c.VisitStmt(stmt.Init)
	}

	var tag Value
	if stmt.Tag != nil {
		tag = c.VisitExpr(stmt.Tag)
	} else {
		tag = c.NewConstValue(exact.MakeBool(true), types.Typ[types.Bool])
	}
	if len(stmt.Body.List) == 0 {
		return
	}

	// Convert untyped constant clauses.
	for _, clause := range stmt.Body.List {
		for _, expr := range clause.(*ast.CaseClause).List {
			if typ := c.typeinfo.Types[expr]; isUntyped(typ) {
				c.typeinfo.Types[expr] = tag.Type()
			}
		}
	}

	// makeValueFunc takes an expression, evaluates it, and returns
	// a Value representing its equality comparison with the tag.
	makeValueFunc := func(expr ast.Expr) func() Value {
		return func() Value {
			return c.VisitExpr(expr).BinaryOp(token.EQL, tag)
		}
	}

	// Create a BasicBlock for each case clause and each associated
	// statement body. Each case clause will branch to either its
	// statement body (success) or to the next case (failure), or the
	// end block if there are no remaining cases.
	startBlock := c.builder.GetInsertBlock()
	endBlock := llvm.AddBasicBlock(startBlock.Parent(), "end")
	endBlock.MoveAfter(startBlock)
	defer c.builder.SetInsertPointAtEnd(endBlock)

	if c.lastlabel != nil {
		labelData := c.labelData(c.lastlabel)
		labelData.Break = endBlock
		c.lastlabel = nil
	}

	// Add a "break" block to the stack.
	c.breakblocks = append(c.breakblocks, endBlock)
	defer func() { c.breakblocks = c.breakblocks[:len(c.breakblocks)-1] }()

	caseBlocks := make([]llvm.BasicBlock, 0, len(stmt.Body.List))
	stmtBlocks := make([]llvm.BasicBlock, 0, len(stmt.Body.List))
	for _ = range stmt.Body.List {
		caseBlocks = append(caseBlocks, llvm.InsertBasicBlock(endBlock, ""))
	}
	for _ = range stmt.Body.List {
		stmtBlocks = append(stmtBlocks, llvm.InsertBasicBlock(endBlock, ""))
	}

	// Move the "default" block to the end, if there is one.
	caseclauses := make([]*ast.CaseClause, 0, len(stmt.Body.List))
	var defaultclause *ast.CaseClause
	for _, stmt := range stmt.Body.List {
		clause := stmt.(*ast.CaseClause)
		if clause.List == nil {
			defaultclause = clause
		} else {
			caseclauses = append(caseclauses, clause)
		}
	}
	if defaultclause != nil {
		caseclauses = append(caseclauses, defaultclause)
	}

	c.builder.CreateBr(caseBlocks[0])
	for i, clause := range caseclauses {
		c.builder.SetInsertPointAtEnd(caseBlocks[i])
		stmtBlock := stmtBlocks[i]
		nextBlock := endBlock
		if i+1 < len(caseBlocks) {
			nextBlock = caseBlocks[i+1]
		}

		if clause.List != nil {
			value := c.VisitExpr(clause.List[0])
			result := value.BinaryOp(token.EQL, tag)
			for _, expr := range clause.List[1:] {
				rhsResultFunc := makeValueFunc(expr)
				result = c.compileLogicalOp(token.LOR, result, rhsResultFunc)
			}
			c.builder.CreateCondBr(result.LLVMValue(), stmtBlock, nextBlock)
		} else {
			// default case
			c.builder.CreateBr(stmtBlock)
		}

		c.builder.SetInsertPointAtEnd(stmtBlock)
		branchBlock := endBlock
		for _, stmt := range clause.Body {
			if br, isbr := stmt.(*ast.BranchStmt); isbr {
				if br.Tok == token.FALLTHROUGH {
					if i+1 < len(stmtBlocks) {
						branchBlock = stmtBlocks[i+1]
					}
				} else {
					c.VisitStmt(stmt)
				}
				// Ignore anything after a branch statement.
				break
			} else {
				c.VisitStmt(stmt)
			}
		}
		c.maybeImplicitBranch(branchBlock)
	}
}
Exemplo n.º 28
0
Arquivo: ssa.go Projeto: pcc/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())
	}
}
Exemplo n.º 29
0
func (c *compiler) VisitFuncDecl(f *ast.FuncDecl) Value {
	var fn Value
	if f.Name.Obj != nil {
		fn = c.Resolve(f.Name.Obj)
	} else {
		fn = c.VisitFuncProtoDecl(f)
	}
	if f.Body == nil {
		return fn
	}

	fn_type := fn.Type().(*types.Func)
	llvm_fn := fn.LLVMValue()

	entry := llvm.AddBasicBlock(llvm_fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)

	// Bind receiver, arguments and return values to their identifiers/objects.
	// We'll store each parameter on the stack so they're addressable.
	paramObjects := fn_type.Params
	if f.Recv != nil {
		paramObjects = append([]*ast.Object{fn_type.Recv}, paramObjects...)
	}
	for i, obj := range paramObjects {
		if obj.Name != "" {
			value := llvm_fn.Param(i)
			typ := obj.Type.(types.Type)
			stackvalue := c.builder.CreateAlloca(c.types.ToLLVM(typ), obj.Name)
			c.builder.CreateStore(value, stackvalue)
			ptrvalue := c.NewLLVMValue(stackvalue, &types.Pointer{Base: typ})
			obj.Data = ptrvalue.makePointee()
		}
	}

	// Allocate space on the stack for named results.
	for _, obj := range fn_type.Results {
		if obj.Name != "" {
			typ := obj.Type.(types.Type)
			llvmtyp := c.types.ToLLVM(typ)
			stackptr := c.builder.CreateAlloca(llvmtyp, obj.Name)
			c.builder.CreateStore(llvm.ConstNull(llvmtyp), stackptr)
			ptrvalue := c.NewLLVMValue(stackptr, &types.Pointer{Base: typ})
			obj.Data = ptrvalue.makePointee()
		}
	}

	c.functions = append(c.functions, fn)
	if f.Body != nil {
		c.VisitBlockStmt(f.Body)
	}
	c.functions = c.functions[0 : len(c.functions)-1]

	last := llvm_fn.LastBasicBlock()
	if in := last.LastInstruction(); in.IsNil() || in.IsATerminatorInst().IsNil() {
		// Assume nil return type, AST should be checked first.
		c.builder.SetInsertPointAtEnd(last)
		c.builder.CreateRetVoid()
	}

	// Is it an 'init' function? Then record it.
	if f.Name.String() == "init" {
		c.initfuncs = append(c.initfuncs, fn)
	} else {
		//if obj != nil {
		//    obj.Data = fn
		//}
	}
	return fn
}
Exemplo n.º 30
0
// Create a constructor function which initialises a global.
// TODO collapse all global inits into one init function?
func (c *compiler) createGlobal(e ast.Expr, t types.Type, name string, export bool) (g *LLVMValue) {
	if e == nil {
		gv := llvm.AddGlobal(c.module.Module, c.types.ToLLVM(t), name)
		if !export {
			gv.SetLinkage(llvm.InternalLinkage)
		}
		g = c.NewLLVMValue(gv, &types.Pointer{Base: t})
		if !isArray(t) {
			return g.makePointee()
		}
		return g
	}

	if block := c.builder.GetInsertBlock(); !block.IsNil() {
		defer c.builder.SetInsertPointAtEnd(block)
	}
	fn_type := new(types.Func)
	llvm_fn_type := c.types.ToLLVM(fn_type).ElementType()
	fn := llvm.AddFunction(c.module.Module, "", llvm_fn_type)
	fn.SetLinkage(llvm.InternalLinkage)
	entry := llvm.AddBasicBlock(fn, "entry")
	c.builder.SetInsertPointAtEnd(entry)

	// Visit the expression. Dereference if necessary, and generalise
	// the type if one hasn't been specified.
	init_ := c.VisitExpr(e)
	_, isconst := init_.(ConstValue)
	if t == nil {
		t = init_.Type()
	} else {
		init_ = init_.Convert(t)
	}

	// If the result is a constant, discard the function before
	// creating any llvm.Value's.
	if isconst {
		fn.EraseFromParentAsFunction()
		fn = llvm.Value{nil}
	}

	// Set the initialiser. If it's a non-const value, then
	// we'll have to do the assignment in a global constructor
	// function.
	gv := llvm.AddGlobal(c.module.Module, c.types.ToLLVM(t), name)
	if !export {
		gv.SetLinkage(llvm.InternalLinkage)
	}
	g = c.NewLLVMValue(gv, &types.Pointer{Base: t})
	if !isArray(t) {
		g = g.makePointee()
	}
	if isconst {
		// Initialiser is constant; discard function and return global now.
		gv.SetInitializer(init_.LLVMValue())
	} else {
		gv.SetInitializer(llvm.ConstNull(c.types.ToLLVM(t)))
		c.builder.CreateStore(init_.LLVMValue(), gv)
	}

	if !fn.IsNil() {
		c.builder.CreateRetVoid()
		// FIXME order global ctors
		fn_value := c.NewLLVMValue(fn, fn_type)
		c.initfuncs = append(c.initfuncs, fn_value)
	}
	return g
}