예제 #1
0
파일: stmt.go 프로젝트: 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)
	}
}
예제 #2
0
파일: interfaces.go 프로젝트: hzmangel/llgo
// convertI2V converts an interface to a value.
func (v *LLVMValue) convertI2V(typ types.Type) (result, success Value) {
	builder := v.compiler.builder
	predicate := v.interfaceTypeEquals(typ).LLVMValue()

	// If result is zero, then we've got a match.
	end := llvm.InsertBasicBlock(builder.GetInsertBlock(), "end")
	end.MoveAfter(builder.GetInsertBlock())
	nonmatch := llvm.InsertBasicBlock(end, "nonmatch")
	match := llvm.InsertBasicBlock(nonmatch, "match")
	builder.CreateCondBr(predicate, match, nonmatch)

	builder.SetInsertPointAtEnd(match)
	matchResultValue := v.loadI2V(typ).LLVMValue()
	builder.CreateBr(end)

	builder.SetInsertPointAtEnd(nonmatch)
	nonmatchResultValue := llvm.ConstNull(matchResultValue.Type())
	builder.CreateBr(end)

	builder.SetInsertPointAtEnd(end)
	successValue := builder.CreatePHI(llvm.Int1Type(), "")
	resultValue := builder.CreatePHI(matchResultValue.Type(), "")

	successValues := []llvm.Value{llvm.ConstAllOnes(llvm.Int1Type()), llvm.ConstNull(llvm.Int1Type())}
	successBlocks := []llvm.BasicBlock{match, nonmatch}
	successValue.AddIncoming(successValues, successBlocks)
	success = v.compiler.NewValue(successValue, types.Typ[types.Bool])

	resultValues := []llvm.Value{matchResultValue, nonmatchResultValue}
	resultBlocks := []llvm.BasicBlock{match, nonmatch}
	resultValue.AddIncoming(resultValues, resultBlocks)
	result = v.compiler.NewValue(resultValue, typ)
	return result, success
}
예제 #3
0
파일: interfaces.go 프로젝트: hzmangel/llgo
func (lhs *LLVMValue) compareI2V(rhs *LLVMValue) Value {
	c := lhs.compiler
	predicate := lhs.interfaceTypeEquals(rhs.typ).LLVMValue()

	end := llvm.InsertBasicBlock(c.builder.GetInsertBlock(), "end")
	end.MoveAfter(c.builder.GetInsertBlock())
	nonmatch := llvm.InsertBasicBlock(end, "nonmatch")
	match := llvm.InsertBasicBlock(nonmatch, "match")
	c.builder.CreateCondBr(predicate, match, nonmatch)

	c.builder.SetInsertPointAtEnd(match)
	lhsValue := lhs.loadI2V(rhs.typ)
	matchResultValue := lhsValue.BinaryOp(token.EQL, rhs).LLVMValue()
	c.builder.CreateBr(end)

	c.builder.SetInsertPointAtEnd(nonmatch)
	nonmatchResultValue := llvm.ConstNull(llvm.Int1Type())
	c.builder.CreateBr(end)

	c.builder.SetInsertPointAtEnd(end)
	resultValue := c.builder.CreatePHI(matchResultValue.Type(), "")
	resultValues := []llvm.Value{matchResultValue, nonmatchResultValue}
	resultBlocks := []llvm.BasicBlock{match, nonmatch}
	resultValue.AddIncoming(resultValues, resultBlocks)
	return c.NewValue(resultValue, types.Typ[types.Bool])
}
예제 #4
0
파일: stmt.go 프로젝트: spate/llgo
func (c *compiler) VisitBlockStmt(stmt *ast.BlockStmt, createNewBlock bool) {
	// This is a little awkward, but it makes dealing with branching easier.
	// A free-standing block statement (i.e. one not attached to a control
	// statement) will splice in a new block.
	var doneBlock llvm.BasicBlock
	if createNewBlock {
		currBlock := c.builder.GetInsertBlock()
		doneBlock = llvm.InsertBasicBlock(currBlock, "")
		doneBlock.MoveAfter(currBlock)
		newBlock := llvm.InsertBasicBlock(doneBlock, "")
		c.builder.CreateBr(newBlock)
		c.builder.SetInsertPointAtEnd(newBlock)
	}

	for _, stmt := range stmt.List {
		c.VisitStmt(stmt)
		if _, ok := stmt.(*ast.BranchStmt); ok {
			// Ignore anything after a branch statement.
			break
		}
	}

	if createNewBlock {
		c.maybeImplicitBranch(doneBlock)
		c.builder.SetInsertPointAtEnd(doneBlock)
	}
}
예제 #5
0
파일: stmt.go 프로젝트: hzmangel/llgo
func (c *compiler) VisitBlockStmt(stmt *ast.BlockStmt, createNewBlock bool) {
	// This is a little awkward, but it makes dealing with branching easier.
	// A free-standing block statement (i.e. one not attached to a control
	// statement) will splice in a new block.
	var doneBlock llvm.BasicBlock
	if createNewBlock {
		currBlock := c.builder.GetInsertBlock()
		doneBlock = llvm.InsertBasicBlock(currBlock, "")
		doneBlock.MoveAfter(currBlock)
		newBlock := llvm.InsertBasicBlock(doneBlock, "")
		c.builder.CreateBr(newBlock)
		c.builder.SetInsertPointAtEnd(newBlock)
	}

	// Visit each statement in the block. When we have a terminator,
	// ignore everything until we get to a labeled statement.
	for _, stmt := range stmt.List {
		currBlock := c.builder.GetInsertBlock()
		in := currBlock.LastInstruction()
		if in.IsNil() || in.IsATerminatorInst().IsNil() {
			c.VisitStmt(stmt)
		} else if _, ok := stmt.(*ast.LabeledStmt); ok {
			// FIXME we might end up with a labeled statement
			// with no predecessors, due to dead code elimination.
			c.VisitStmt(stmt)
		}
	}

	if createNewBlock {
		c.maybeImplicitBranch(doneBlock)
		c.builder.SetInsertPointAtEnd(doneBlock)
	}
}
예제 #6
0
파일: expr.go 프로젝트: 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)
}
예제 #7
0
파일: stmt.go 프로젝트: dtcaciuc/llgo
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)
}
예제 #8
0
파일: interfaces.go 프로젝트: hzmangel/llgo
func (v *LLVMValue) mustConvertI2V(typ types.Type) Value {
	result, ok := v.convertI2V(typ)

	c, builder := v.compiler, v.compiler.builder
	end := llvm.InsertBasicBlock(builder.GetInsertBlock(), "end")
	end.MoveAfter(builder.GetInsertBlock())
	failed := llvm.InsertBasicBlock(end, "failed")
	builder.CreateCondBr(ok.LLVMValue(), end, failed)
	builder.SetInsertPointAtEnd(failed)

	s := fmt.Sprintf("convertI2V(%s, %s) failed", v.typ, typ)
	c.visitPanic(c.NewConstValue(exact.MakeString(s), types.Typ[types.String]))
	builder.SetInsertPointAtEnd(end)
	return result
}
예제 #9
0
func (v *LLVMValue) mustConvertI2I(iface *types.Interface) Value {
	result, ok := v.convertI2I(iface)

	c, builder := v.compiler, v.compiler.builder
	end := llvm.InsertBasicBlock(builder.GetInsertBlock(), "end")
	end.MoveAfter(builder.GetInsertBlock())
	failed := llvm.InsertBasicBlock(end, "failed")
	builder.CreateCondBr(ok.LLVMValue(), end, failed)
	builder.SetInsertPointAtEnd(failed)

	s := fmt.Sprintf("convertI2I(%s, %s) failed", v.typ, iface)
	c.visitPanic(c.NewConstValue(token.STRING, strconv.Quote(s)))
	builder.SetInsertPointAtEnd(end)
	return result
}
예제 #10
0
파일: stmt.go 프로젝트: prattmic/llgo
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())
	}
}
예제 #11
0
파일: stmt.go 프로젝트: c0der007/llgo
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)
}
예제 #12
0
파일: interfaces.go 프로젝트: kisielk/llgo
// convertI2V converts an interface to a value.
func (v *LLVMValue) convertI2V(typ types.Type) (result, success Value) {
	typptrType := llvm.PointerType(llvm.Int8Type(), 0)
	runtimeType := v.compiler.types.ToRuntime(typ)
	runtimeType = llvm.ConstBitCast(runtimeType, typptrType)
	vval := v.LLVMValue()

	builder := v.compiler.builder
	ifaceType := builder.CreateExtractValue(vval, 0, "")
	diff := builder.CreatePtrDiff(runtimeType, ifaceType, "")
	zero := llvm.ConstNull(diff.Type())
	predicate := builder.CreateICmp(llvm.IntEQ, diff, zero, "")

	// If result is zero, then we've got a match.
	end := llvm.InsertBasicBlock(builder.GetInsertBlock(), "end")
	end.MoveAfter(builder.GetInsertBlock())
	nonmatch := llvm.InsertBasicBlock(end, "nonmatch")
	match := llvm.InsertBasicBlock(nonmatch, "match")
	builder.CreateCondBr(predicate, match, nonmatch)

	builder.SetInsertPointAtEnd(match)
	matchResultValue := v.loadI2V(typ).LLVMValue()
	builder.CreateBr(end)

	builder.SetInsertPointAtEnd(nonmatch)
	nonmatchResultValue := llvm.ConstNull(matchResultValue.Type())
	builder.CreateBr(end)

	builder.SetInsertPointAtEnd(end)
	successValue := builder.CreatePHI(llvm.Int1Type(), "")
	resultValue := builder.CreatePHI(matchResultValue.Type(), "")

	successValues := []llvm.Value{llvm.ConstAllOnes(llvm.Int1Type()), llvm.ConstNull(llvm.Int1Type())}
	successBlocks := []llvm.BasicBlock{match, nonmatch}
	successValue.AddIncoming(successValues, successBlocks)
	success = v.compiler.NewLLVMValue(successValue, types.Bool)

	resultValues := []llvm.Value{matchResultValue, nonmatchResultValue}
	resultBlocks := []llvm.BasicBlock{match, nonmatch}
	resultValue.AddIncoming(resultValues, resultBlocks)
	result = v.compiler.NewLLVMValue(resultValue, typ)
	return result, success
}
예제 #13
0
파일: println.go 프로젝트: hzmangel/llgo
func (c *compiler) getBoolString(v llvm.Value) llvm.Value {
	startBlock := c.builder.GetInsertBlock()
	resultBlock := llvm.InsertBasicBlock(startBlock, "")
	resultBlock.MoveAfter(startBlock)
	falseBlock := llvm.InsertBasicBlock(resultBlock, "")

	CharPtr := llvm.PointerType(llvm.Int8Type(), 0)
	falseString := c.builder.CreateGlobalStringPtr("false", "")
	falseString = c.builder.CreateBitCast(falseString, CharPtr, "")
	trueString := c.builder.CreateGlobalStringPtr("true", "")
	trueString = c.builder.CreateBitCast(trueString, CharPtr, "")

	c.builder.CreateCondBr(v, resultBlock, falseBlock)
	c.builder.SetInsertPointAtEnd(falseBlock)
	c.builder.CreateBr(resultBlock)
	c.builder.SetInsertPointAtEnd(resultBlock)
	result := c.builder.CreatePHI(CharPtr, "")
	result.AddIncoming([]llvm.Value{trueString, falseString},
		[]llvm.BasicBlock{startBlock, falseBlock})
	return result
}
예제 #14
0
파일: interfaces.go 프로젝트: prattmic/llgo
// convertI2V converts an interface to a value.
func (v *LLVMValue) convertI2V(typ types.Type) Value {
	typptrType := llvm.PointerType(llvm.Int8Type(), 0)
	runtimeType := v.compiler.types.ToRuntime(typ)
	runtimeType = llvm.ConstBitCast(runtimeType, typptrType)
	vptr := v.pointer.LLVMValue()

	builder := v.compiler.builder
	ifaceType := builder.CreateLoad(builder.CreateStructGEP(vptr, 1, ""), "")
	diff := builder.CreatePtrDiff(runtimeType, ifaceType, "")
	zero := llvm.ConstNull(diff.Type())
	predicate := builder.CreateICmp(llvm.IntEQ, diff, zero, "")
	llvmtype := v.compiler.types.ToLLVM(typ)
	result := builder.CreateAlloca(llvmtype, "")

	// If result is zero, then we've got a match.
	end := llvm.InsertBasicBlock(builder.GetInsertBlock(), "end")
	end.MoveAfter(builder.GetInsertBlock())
	nonmatch := llvm.InsertBasicBlock(end, "nonmatch")
	match := llvm.InsertBasicBlock(nonmatch, "match")
	builder.CreateCondBr(predicate, match, nonmatch)

	builder.SetInsertPointAtEnd(match)
	value := builder.CreateLoad(builder.CreateStructGEP(vptr, 0, ""), "")
	value = builder.CreateBitCast(value, result.Type(), "")
	value = builder.CreateLoad(value, "")
	builder.CreateStore(value, result)
	builder.CreateBr(end)

	// TODO should return {value, ok}
	builder.SetInsertPointAtEnd(nonmatch)
	builder.CreateStore(llvm.ConstNull(llvmtype), result)
	builder.CreateBr(end)

	//builder.SetInsertPointAtEnd(end)
	result = builder.CreateLoad(result, "")
	return v.compiler.NewLLVMValue(result, typ)
}
예제 #15
0
파일: stmt.go 프로젝트: kisielk/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 := types.Underlying(x.Type())
	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 keyType, valueType types.Type
	var keyPtr, valuePtr llvm.Value
	if stmt.Tok == token.DEFINE {
		if key := stmt.Key.(*ast.Ident); key.Name != "_" {
			keyType = key.Obj.Type.(types.Type)
			keyPtr = c.builder.CreateAlloca(c.types.ToLLVM(keyType), "")
			key.Obj.Data = c.NewLLVMValue(keyPtr, &types.Pointer{Base: keyType}).makePointee()
		}
		if stmt.Value != nil {
			if value := stmt.Value.(*ast.Ident); value.Name != "_" {
				valueType = value.Obj.Type.(types.Type)
				valuePtr = c.builder.CreateAlloca(c.types.ToLLVM(valueType), "")
				value.Obj.Data = c.NewLLVMValue(valuePtr, &types.Pointer{Base: valueType}).makePointee()
			}
		}
	}

	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).Base
	}
	switch typ := types.Underlying(typ).(type) {
	case *types.Map:
		goto maprange
	case *types.Name:
		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 {
				// TODO load value onto stack for indexing?
			}
		}
		base = x.LLVMValue()
		length = llvm.ConstInt(llvm.Int32Type(), 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
	}

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(llvm.Int32Type())
		currBlock = c.builder.GetInsertBlock()
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		index := c.builder.CreatePHI(llvm.Int32Type(), "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(llvm.Int32Type())
		currBlock = c.builder.GetInsertBlock()
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		index := c.builder.CreatePHI(llvm.Int32Type(), "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(llvm.Int32Type(), 1, false), "")
		c.builder.CreateBr(condBlock)
		index.AddIncoming([]llvm.Value{zero, newindex}, []llvm.BasicBlock{currBlock, postBlock})
		return
	}
}
예제 #16
0
파일: expr.go 프로젝트: quarnster/llgo
// createCall emits the code for a function call, taking into account
// variadic functions, receivers, and panic/defer.
//
// dotdotdot is true if the last argument is followed with "...".
func (c *compiler) createCall(fn *LLVMValue, argValues []Value, dotdotdot, invoke bool) *LLVMValue {
	fn_type := fn.Type().Underlying().(*types.Signature)
	var args []llvm.Value

	// TODO Move all of this to evalCallArgs?
	params := fn_type.Params()
	if nparams := int(params.Len()); nparams > 0 {
		if fn_type.IsVariadic() {
			nparams--
		}
		for i := 0; i < nparams; i++ {
			value := argValues[i]
			args = append(args, value.LLVMValue())
		}
		if fn_type.IsVariadic() {
			if dotdotdot {
				// Calling f(x...). Just pass the slice directly.
				slice_value := argValues[nparams].LLVMValue()
				args = append(args, slice_value)
			} else {
				varargs := make([]llvm.Value, len(argValues)-nparams)
				for i, value := range argValues[nparams:] {
					varargs[i] = value.LLVMValue()
				}
				param_type := params.At(nparams).Type().(*types.Slice).Elem()
				slice_value := c.makeLiteralSlice(varargs, param_type)
				args = append(args, slice_value)
			}
		}
	}

	var result_type types.Type
	switch results := fn_type.Results(); results.Len() {
	case 0: // no-op
	case 1:
		result_type = results.At(0).Type()
	default:
		result_type = results
	}

	// Depending on whether the function contains defer statements or not,
	// we'll generate either a "call" or an "invoke" instruction.
	var createCall = c.builder.CreateCall
	if invoke {
		f := c.functions.top()
		// TODO Create a method on compiler (avoid creating closures).
		createCall = func(fn llvm.Value, args []llvm.Value, name string) llvm.Value {
			currblock := c.builder.GetInsertBlock()
			returnblock := llvm.AddBasicBlock(currblock.Parent(), "")
			returnblock.MoveAfter(currblock)
			value := c.builder.CreateInvoke(fn, args, returnblock, f.unwindblock, "")
			c.builder.SetInsertPointAtEnd(returnblock)
			return value
		}
	}

	var fnptr llvm.Value
	fnval := fn.LLVMValue()
	if fnval.Type().TypeKind() == llvm.PointerTypeKind {
		fnptr = fnval
	} else {
		fnptr = c.builder.CreateExtractValue(fnval, 0, "")
		context := c.builder.CreateExtractValue(fnval, 1, "")
		fntyp := fnptr.Type().ElementType()
		paramTypes := fntyp.ParamTypes()

		// If the context is not a constant null, and we're not
		// dealing with a method (where we don't care about the value
		// of the receiver), then we must conditionally call the
		// function with the additional receiver/closure.
		if !context.IsNull() || fn_type.Recv() != nil {
			// Store the blocks for referencing in the Phi below;
			// note that we update the block after each createCall,
			// since createCall may create new blocks and we want
			// the predecessors to the Phi.
			var nullctxblock llvm.BasicBlock
			var nonnullctxblock llvm.BasicBlock
			var endblock llvm.BasicBlock
			var nullctxresult llvm.Value

			// len(paramTypes) == len(args) iff function is not a method.
			if !context.IsConstant() && len(paramTypes) == len(args) {
				currblock := c.builder.GetInsertBlock()
				endblock = llvm.AddBasicBlock(currblock.Parent(), "")
				endblock.MoveAfter(currblock)
				nonnullctxblock = llvm.InsertBasicBlock(endblock, "")
				nullctxblock = llvm.InsertBasicBlock(nonnullctxblock, "")
				nullctx := c.builder.CreateIsNull(context, "")
				c.builder.CreateCondBr(nullctx, nullctxblock, nonnullctxblock)

				// null context case.
				c.builder.SetInsertPointAtEnd(nullctxblock)
				nullctxresult = createCall(fnptr, args, "")
				nullctxblock = c.builder.GetInsertBlock()
				c.builder.CreateBr(endblock)
				c.builder.SetInsertPointAtEnd(nonnullctxblock)
			}

			// non-null context case.
			var result llvm.Value
			args := append([]llvm.Value{context}, args...)
			if len(paramTypes) < len(args) {
				returnType := fntyp.ReturnType()
				ctxType := context.Type()
				paramTypes := append([]llvm.Type{ctxType}, paramTypes...)
				vararg := fntyp.IsFunctionVarArg()
				fntyp := llvm.FunctionType(returnType, paramTypes, vararg)
				fnptrtyp := llvm.PointerType(fntyp, 0)
				fnptr = c.builder.CreateBitCast(fnptr, fnptrtyp, "")
			}
			result = createCall(fnptr, args, "")

			// If the return type is not void, create a
			// PHI node to select which value to return.
			if !nullctxresult.IsNil() {
				nonnullctxblock = c.builder.GetInsertBlock()
				c.builder.CreateBr(endblock)
				c.builder.SetInsertPointAtEnd(endblock)
				if result.Type().TypeKind() != llvm.VoidTypeKind {
					phiresult := c.builder.CreatePHI(result.Type(), "")
					values := []llvm.Value{nullctxresult, result}
					blocks := []llvm.BasicBlock{nullctxblock, nonnullctxblock}
					phiresult.AddIncoming(values, blocks)
					result = phiresult
				}
			}
			return c.NewValue(result, result_type)
		}
	}
	result := createCall(fnptr, args, "")
	return c.NewValue(result, result_type)
}
예제 #17
0
파일: stmt.go 프로젝트: kisielk/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)
	typptr := c.builder.CreateExtractValue(iface.LLVMValue(), 0, "")
	typptr = c.builder.CreatePtrToInt(typptr, c.target.IntPtrType(), "")
	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]
			}
			// TODO handle multiple types
			// TODO use runtime type equality function
			if len(caseClause.List) > 1 {
				panic("unimplemented")
			}
			var cond llvm.Value
			if isNilIdent(caseClause.List[0]) {
				cond = c.builder.CreateIsNull(typptr, "")
			} else {
				typ := c.types.expr[caseClause.List[0]]
				check := c.types.ToRuntime(typ)
				check = c.builder.CreatePtrToInt(check, c.target.IntPtrType(), "")
				cond = c.builder.CreateICmp(llvm.IntEQ, typptr, check, "")
			}
			c.builder.CreateCondBr(cond, 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.types.expr[caseClause.List[0]]
			}
			i++
		} else {
			block = defaultBlock
		}
		c.builder.SetInsertPointAtEnd(block)
		if assignIdent != nil {
			if len(caseClause.List) == 1 && !isNilIdent(caseClause.List[0]) {
				assignIdent.Obj.Data = iface.loadI2V(typ)
			} else {
				assignIdent.Obj.Data = iface
			}
		}
		for _, stmt := range caseClause.Body {
			c.VisitStmt(stmt)
		}
		c.maybeImplicitBranch(endBlock)
	}
}
예제 #18
0
파일: channels.go 프로젝트: quarnster/llgo
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)
	}
}
예제 #19
0
파일: stmt.go 프로젝트: kisielk/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 {
		True := types.Universe.Lookup("true")
		tag = c.Resolve(True)
	}
	if len(stmt.Body.List) == 0 {
		return
	}

	// 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)

	// 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, ""))
	}

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

		clause := stmt.(*ast.CaseClause)
		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)
	}
}
예제 #20
0
파일: stmt.go 프로젝트: 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)
	}
}
예제 #21
0
파일: stmt.go 프로젝트: 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
	}
}
예제 #22
0
파일: stmt.go 프로젝트: 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)
	}
}
예제 #23
0
파일: stmt.go 프로젝트: c0der007/llgo
func (c *compiler) VisitSwitchStmt(stmt *ast.SwitchStmt) {
	if stmt.Init != nil {
		c.PushScope()
		defer c.PopScope()
		c.VisitStmt(stmt.Init)
	}

	var tag Value
	if stmt.Tag != nil {
		tag = c.VisitExpr(stmt.Tag)
	} else {
		True := types.Universe.Lookup("true")
		tag = c.Resolve(True)
	}
	if len(stmt.Body.List) == 0 {
		return
	}

	// 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)

	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, ""))
	}

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

		clause := stmt.(*ast.CaseClause)
		if clause.List != nil {
			value := c.VisitExpr(clause.List[0])
			result := value.BinaryOp(token.EQL, tag)
			for _, expr := range clause.List[1:] {
				value = c.compileLogicalOp(token.LOR, result, expr)
			}
			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 && br.Tok == token.FALLTHROUGH {
				if i+1 < len(stmtBlocks) {
					branchBlock = stmtBlocks[i+1]
				}
			} else {
				c.VisitStmt(stmt)
			}
		}
		c.maybeImplicitBranch(branchBlock)
	}
}
예제 #24
0
파일: ssa.go 프로젝트: 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])
	}
}