Example #1
0
func (c *Codegen) generateLoop(node *parser.LoopStmtNode) (ret bool) {
	currFunc := c.module.NamedFunction(c.currFunc)
	if node.Init != nil {
		c.generateVarDecl(node.Init, false)
	}
	entry := llvm.AddBasicBlock(currFunc, "")
	body := llvm.AddBasicBlock(currFunc, "")
	exit := llvm.AddBasicBlock(currFunc, "")
	c.builder.CreateBr(entry)

	c.builder.SetInsertPoint(entry, entry.LastInstruction())
	cond := c.generateExpression(node.Cond)
	c.builder.CreateCondBr(cond, body, exit)

	c.builder.SetInsertPoint(body, body.LastInstruction())
	if ret = c.generateBlock(node.Body); !ret {
		if node.Post != nil {
			switch t := node.Post.(type) {
			case *parser.AssignStmtNode:
				c.generateAssign(t)
			case *parser.CallStmtNode:
				c.generateCall(t.Call, null)
			}
		}

		c.builder.CreateBr(entry)
	}
	c.builder.SetInsertPoint(exit, exit.LastInstruction())

	return
}
Example #2
0
func (v *Codegen) genLoopStat(n *parser.LoopStat) {
	switch n.LoopType {
	case parser.LOOP_TYPE_INFINITE:
		loopBlock := llvm.AddBasicBlock(v.currentFunction, "")
		v.builder.CreateBr(loopBlock)
		v.builder.SetInsertPointAtEnd(loopBlock)

		v.genBlock(n.Body)

		v.builder.CreateBr(loopBlock)
		afterBlock := llvm.AddBasicBlock(v.currentFunction, "")
		v.builder.SetInsertPointAtEnd(afterBlock)
	case parser.LOOP_TYPE_CONDITIONAL:
		evalBlock := llvm.AddBasicBlock(v.currentFunction, "")
		v.builder.CreateBr(evalBlock)

		loopBlock := llvm.AddBasicBlock(v.currentFunction, "")
		afterBlock := llvm.AddBasicBlock(v.currentFunction, "")

		v.builder.SetInsertPointAtEnd(evalBlock)
		cond := v.genExpr(n.Condition)
		v.builder.CreateCondBr(cond, loopBlock, afterBlock)

		v.builder.SetInsertPointAtEnd(loopBlock)
		v.genBlock(n.Body)
		v.builder.CreateBr(evalBlock)

		v.builder.SetInsertPointAtEnd(afterBlock)
	default:
		panic("invalid loop type")
	}
}
Example #3
0
File: codegen.go Project: vnev/ark
func (v *Codegen) genLogicalBinop(n *parser.BinaryExpr) llvm.Value {
	and := n.Op == parser.BINOP_LOG_AND

	next := llvm.AddBasicBlock(v.currentLLVMFunction(), "and_next")
	exit := llvm.AddBasicBlock(v.currentLLVMFunction(), "and_exit")

	b1 := v.genExpr(n.Lhand)
	first := v.builder().GetInsertBlock()
	if and {
		v.builder().CreateCondBr(b1, next, exit)
	} else {
		v.builder().CreateCondBr(b1, exit, next)
	}

	v.builder().SetInsertPointAtEnd(next)
	b2 := v.genExpr(n.Rhand)
	next = v.builder().GetInsertBlock()
	v.builder().CreateBr(exit)

	v.builder().SetInsertPointAtEnd(exit)
	phi := v.builder().CreatePHI(b2.Type(), "and_phi")

	var testIncVal uint64
	if and {
		testIncVal = 0
	} else {
		testIncVal = 1
	}

	phi.AddIncoming([]llvm.Value{llvm.ConstInt(llvm.IntType(1), testIncVal, false), b2}, []llvm.BasicBlock{first, next})

	return phi
}
Example #4
0
func (fr *frame) condBrRuntimeError(cond llvm.Value, errcode uint64) {
	if cond.IsNull() {
		return
	}

	errorbb := fr.runtimeErrorBlocks[errcode]
	newbb := errorbb.C == nil
	if newbb {
		errorbb = llvm.AddBasicBlock(fr.function, "")
		fr.runtimeErrorBlocks[errcode] = errorbb
	}

	contbb := llvm.AddBasicBlock(fr.function, "")

	br := fr.builder.CreateCondBr(cond, errorbb, contbb)
	fr.setBranchWeightMetadata(br, 1, 1000)

	if newbb {
		fr.builder.SetInsertPointAtEnd(errorbb)
		fr.runtime.runtimeError.call(fr, llvm.ConstInt(llvm.Int32Type(), errcode, false))
		fr.builder.CreateUnreachable()
	}

	fr.builder.SetInsertPointAtEnd(contbb)
}
Example #5
0
File: codegen.go Project: vnev/ark
func (v *Codegen) genBoundsCheck(limit llvm.Value, index llvm.Value, indexType parser.Type) {
	segvBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_segv")
	endBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_end")
	upperCheckBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_upper_block")

	tooLow := v.builder().CreateICmp(llvm.IntSGT, llvm.ConstInt(index.Type(), 0, false), index, "boundscheck_lower")
	v.builder().CreateCondBr(tooLow, segvBlock, upperCheckBlock)

	v.builder().SetInsertPointAtEnd(upperCheckBlock)

	// make sure limit and index have same width
	castedLimit := limit
	castedIndex := index
	if index.Type().IntTypeWidth() < limit.Type().IntTypeWidth() {
		if indexType.IsSigned() {
			castedIndex = v.builder().CreateSExt(index, limit.Type(), "")
		} else {
			castedIndex = v.builder().CreateZExt(index, limit.Type(), "")
		}
	} else if index.Type().IntTypeWidth() > limit.Type().IntTypeWidth() {
		castedLimit = v.builder().CreateZExt(limit, index.Type(), "")
	}

	tooHigh := v.builder().CreateICmp(llvm.IntSLE, castedLimit, castedIndex, "boundscheck_upper")
	v.builder().CreateCondBr(tooHigh, segvBlock, endBlock)

	v.builder().SetInsertPointAtEnd(segvBlock)
	v.genRaiseSegfault()
	v.builder().CreateUnreachable()

	v.builder().SetInsertPointAtEnd(endBlock)
}
Example #6
0
// emitInitPrologue emits the init-specific function prologue (guard check and
// initialization of dependent packages under the llgo native ABI), and returns
// the basic block into which the GC registration call should be emitted.
func (fr *frame) emitInitPrologue() llvm.BasicBlock {
	if fr.GccgoABI {
		return fr.builder.GetInsertBlock()
	}

	initGuard := llvm.AddGlobal(fr.module.Module, llvm.Int1Type(), "init$guard")
	initGuard.SetLinkage(llvm.InternalLinkage)
	initGuard.SetInitializer(llvm.ConstNull(llvm.Int1Type()))

	returnBlock := llvm.AddBasicBlock(fr.function, "")
	initBlock := llvm.AddBasicBlock(fr.function, "")

	initGuardVal := fr.builder.CreateLoad(initGuard, "")
	fr.builder.CreateCondBr(initGuardVal, returnBlock, initBlock)

	fr.builder.SetInsertPointAtEnd(returnBlock)
	fr.builder.CreateRetVoid()

	fr.builder.SetInsertPointAtEnd(initBlock)
	fr.builder.CreateStore(llvm.ConstInt(llvm.Int1Type(), 1, false), initGuard)
	int8ptr := llvm.PointerType(fr.types.ctx.Int8Type(), 0)
	ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false)
	for _, pkg := range fr.pkg.Object.Imports() {
		initname := ManglePackagePath(pkg.Path()) + "..import"
		initfn := fr.module.Module.NamedFunction(initname)
		if initfn.IsNil() {
			initfn = llvm.AddFunction(fr.module.Module, initname, ftyp)
		}
		args := []llvm.Value{llvm.Undef(int8ptr)}
		fr.builder.CreateCall(initfn, args, "")
	}

	return initBlock
}
Example #7
0
func (fr *frame) callRecover(isDeferredRecover bool) *govalue {
	startbb := fr.builder.GetInsertBlock()
	recoverbb := llvm.AddBasicBlock(fr.function, "")
	contbb := llvm.AddBasicBlock(fr.function, "")
	canRecover := fr.builder.CreateTrunc(fr.canRecover, llvm.Int1Type(), "")
	fr.builder.CreateCondBr(canRecover, recoverbb, contbb)

	fr.builder.SetInsertPointAtEnd(recoverbb)
	var recovered llvm.Value
	if isDeferredRecover {
		recovered = fr.runtime.deferredRecover.call(fr)[0]
	} else {
		recovered = fr.runtime.recover.call(fr)[0]
	}
	recoverbb = fr.builder.GetInsertBlock()
	fr.builder.CreateBr(contbb)

	fr.builder.SetInsertPointAtEnd(contbb)
	eface := types.NewInterface(nil, nil)
	llv := fr.builder.CreatePHI(fr.types.ToLLVM(eface), "")
	llv.AddIncoming(
		[]llvm.Value{llvm.ConstNull(llv.Type()), recovered},
		[]llvm.BasicBlock{startbb, recoverbb},
	)
	return newValue(llv, eface)
}
Example #8
0
File: ssa.go Project: hinike/llgo
// Runs defers. If a defer panics, check for recovers in later defers.
func (fr *frame) runDefers() {
	loopbb := llvm.AddBasicBlock(fr.function, "")
	fr.builder.CreateBr(loopbb)

	retrylpad := llvm.AddBasicBlock(fr.function, "")
	fr.builder.SetInsertPointAtEnd(retrylpad)
	fr.createLandingPad(false)
	fr.runtime.checkDefer.callOnly(fr, fr.frameptr)
	fr.builder.CreateBr(loopbb)

	fr.builder.SetInsertPointAtEnd(loopbb)
	fr.runtime.undefer.invoke(fr, retrylpad, fr.frameptr)
}
Example #9
0
File: codegen.go Project: vnev/ark
func (v *Codegen) genIfStat(n *parser.IfStat) {
	// Warning to all who tread here:
	// This function is complicated, but theoretically it should never need to
	// be changed again. God help the soul who has to edit this.

	if !v.inFunction() {
		panic("tried to gen if stat not in function")
	}

	statTerm := semantic.IsNodeTerminating(n)

	var end llvm.BasicBlock
	if !statTerm {
		end = llvm.AddBasicBlock(v.currentLLVMFunction(), "end")
	}

	for i, expr := range n.Exprs {
		cond := v.genExpr(expr)

		ifTrue := llvm.AddBasicBlock(v.currentLLVMFunction(), "if_true")
		ifFalse := llvm.AddBasicBlock(v.currentLLVMFunction(), "if_false")

		v.builder().CreateCondBr(cond, ifTrue, ifFalse)

		v.builder().SetInsertPointAtEnd(ifTrue)
		v.genBlock(n.Bodies[i])

		if !statTerm && !n.Bodies[i].IsTerminating && !isBreakOrNext(n.Bodies[i].LastNode()) {
			v.builder().CreateBr(end)
		}

		v.builder().SetInsertPointAtEnd(ifFalse)

		if !statTerm {
			end.MoveAfter(ifFalse)
		}
	}

	if n.Else != nil {
		v.genBlock(n.Else)
	}

	if !statTerm && (n.Else == nil || (!n.Else.IsTerminating && !isBreakOrNext(n.Else.LastNode()))) {
		v.builder().CreateBr(end)
	}

	if !statTerm {
		v.builder().SetInsertPointAtEnd(end)
	}
}
Example #10
0
func (c *compiler) createInitMainFunction(mainPkg *ssa.Package) {
	int8ptr := llvm.PointerType(c.types.ctx.Int8Type(), 0)
	ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false)
	initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp)
	c.addCommonFunctionAttrs(initMain)
	entry := llvm.AddBasicBlock(initMain, "entry")

	builder := llvm.GlobalContext().NewBuilder()
	defer builder.Dispose()
	builder.SetInsertPointAtEnd(entry)

	args := []llvm.Value{llvm.Undef(int8ptr)}

	if !c.GccgoABI {
		initfn := c.module.Module.NamedFunction("main..import")
		if !initfn.IsNil() {
			builder.CreateCall(initfn, args, "")
		}
		builder.CreateRetVoid()
		return
	}

	initdata := c.buildPackageInitData(mainPkg)

	for _, init := range initdata.Inits {
		initfn := c.module.Module.NamedFunction(init.InitFunc)
		if initfn.IsNil() {
			initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp)
		}
		builder.CreateCall(initfn, args, "")
	}

	builder.CreateRetVoid()
}
Example #11
0
func (c *Codegen) stdString() {
	tmpl := &Template{
		Type:      llvm.GlobalContext().StructCreateNamed("string"),
		Variables: map[string]int{},
	}
	c.templates["string"] = tmpl

	vars := []llvm.Type{
		llvm.PointerType(PRIMITIVE_TYPES["char"], 0),
		PRIMITIVE_TYPES["int"],
		PRIMITIVE_TYPES["int"],
	}
	tmpl.Type.StructSetBody(vars, false)

	lenFuncType := llvm.FunctionType(PRIMITIVE_TYPES["int"], []llvm.Type{llvm.PointerType(tmpl.Type, 0)}, false)
	lenFunc := llvm.AddFunction(c.module, "-string-len", lenFuncType)
	lenFunc.Param(0).SetName("this")
	block := llvm.AddBasicBlock(c.module.NamedFunction("-string-len"), "entry")
	c.functions["-string-len"] = block
	c.currFunc = "-string-len"
	c.builder.SetInsertPoint(block, block.LastInstruction())
	ret := c.builder.CreateStructGEP(c.getCurrParam("this"), 1, "")
	ret = c.builder.CreateLoad(ret, "")
	ret = c.builder.CreateSub(ret, llvm.ConstInt(PRIMITIVE_TYPES["int"], 1, false), "")
	c.builder.CreateRet(ret)

	printFuncType := llvm.FunctionType(PRIMITIVE_TYPES["int"], []llvm.Type{
		llvm.PointerType(PRIMITIVE_TYPES["char"], 0),
	}, true)
	llvm.AddFunction(c.module, "printf", printFuncType)
}
Example #12
0
func (v *Codegen) genFunctionDecl(n *parser.FunctionDecl) llvm.Value {
	var res llvm.Value

	mangledName := n.Function.MangledName(parser.MANGLE_ARK_UNSTABLE)
	function := v.curFile.Module.NamedFunction(mangledName)
	if function.IsNil() {
		//v.err("genning function `%s` doesn't exist in module", n.Function.Name)
		// hmmmm seems we just ignore this here
	} else {

		if !n.Prototype {
			block := llvm.AddBasicBlock(function, "entry")
			v.builder.SetInsertPointAtEnd(block)

			for i, par := range n.Function.Parameters {
				alloc := v.builder.CreateAlloca(v.typeToLLVMType(par.Variable.Type), par.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE))
				v.variableLookup[par.Variable] = alloc

				v.builder.CreateStore(function.Params()[i], alloc)
			}

			v.inFunction = true
			v.currentFunction = function
			v.genBlock(n.Function.Body)
			v.inFunction = false
		}
	}

	return res
}
Example #13
0
File: codegen.go Project: vnev/ark
func (v *Codegen) genFunctionBody(fn *parser.Function, llvmFn llvm.Value) {
	block := llvm.AddBasicBlock(llvmFn, "entry")

	v.pushFunction(fn)
	v.builders[v.currentFunction()] = llvm.NewBuilder()
	v.builder().SetInsertPointAtEnd(block)

	pars := fn.Parameters

	if fn.Type.Receiver != nil {
		newPars := make([]*parser.VariableDecl, len(pars)+1)
		newPars[0] = fn.Receiver
		copy(newPars[1:], pars)
		pars = newPars
	}

	for i, par := range pars {
		alloc := v.builder().CreateAlloca(v.typeToLLVMType(par.Variable.Type), par.Variable.Name)
		v.variableLookup[par.Variable] = alloc

		v.builder().CreateStore(llvmFn.Params()[i], alloc)
	}

	v.genBlock(fn.Body)
	v.builder().Dispose()
	delete(v.builders, v.currentFunction())
	delete(v.curLoopExits, v.currentFunction())
	delete(v.curLoopNexts, v.currentFunction())
	v.popFunction()
}
Example #14
0
File: codegen.go Project: vnev/ark
func (v *Codegen) genLoopStat(n *parser.LoopStat) {
	curfn := v.currentFunction()
	afterBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "loop_exit")
	v.curLoopExits[curfn] = append(v.curLoopExits[curfn], afterBlock)

	switch n.LoopType {
	case parser.LOOP_TYPE_INFINITE:
		loopBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "loop_body")
		v.curLoopNexts[curfn] = append(v.curLoopNexts[curfn], loopBlock)
		v.builder().CreateBr(loopBlock)
		v.builder().SetInsertPointAtEnd(loopBlock)

		v.genBlock(n.Body)

		if !isBreakOrNext(n.Body.LastNode()) {
			v.builder().CreateBr(loopBlock)
		}

		v.builder().SetInsertPointAtEnd(afterBlock)
	case parser.LOOP_TYPE_CONDITIONAL:
		evalBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "loop_condeval")
		v.builder().CreateBr(evalBlock)
		v.curLoopNexts[curfn] = append(v.curLoopNexts[curfn], evalBlock)

		loopBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "loop_body")

		v.builder().SetInsertPointAtEnd(evalBlock)
		cond := v.genExpr(n.Condition)
		v.builder().CreateCondBr(cond, loopBlock, afterBlock)

		v.builder().SetInsertPointAtEnd(loopBlock)
		v.genBlock(n.Body)

		if !isBreakOrNext(n.Body.LastNode()) {
			v.builder().CreateBr(evalBlock)
		}

		v.builder().SetInsertPointAtEnd(afterBlock)
	default:
		panic("invalid loop type")
	}

	v.curLoopExits[curfn] = v.curLoopExits[curfn][:len(v.curLoopExits[curfn])-1]
	v.curLoopNexts[curfn] = v.curLoopNexts[curfn][:len(v.curLoopNexts[curfn])-1]
}
Example #15
0
func (v *Codegen) genIfStat(n *parser.IfStat) {
	if !v.inFunction {
		panic("tried to gen if stat not in function")
	}

	end := llvm.AddBasicBlock(v.currentFunction, "")

	for i, expr := range n.Exprs {
		cond := v.genExpr(expr)

		ifTrue := llvm.AddBasicBlock(v.currentFunction, "")
		ifFalse := llvm.AddBasicBlock(v.currentFunction, "")

		v.builder.CreateCondBr(cond, ifTrue, ifFalse)

		v.builder.SetInsertPointAtEnd(ifTrue)
		for _, node := range n.Bodies[i].Nodes {
			v.genNode(node)
		}

		if len(n.Bodies[i].Nodes) == 0 {
			v.builder.CreateBr(end)
		} else {
			switch n.Bodies[i].Nodes[len(n.Bodies[i].Nodes)-1].(type) {
			case *parser.ReturnStat: // do nothing
			default:
				v.builder.CreateBr(end)
			}
		}

		v.builder.SetInsertPointAtEnd(ifFalse)
		end.MoveAfter(ifFalse)
	}

	if n.Else != nil {
		for _, node := range n.Else.Nodes {
			v.genNode(node)
		}
	}

	v.builder.CreateBr(end)

	v.builder.SetInsertPointAtEnd(end)
}
Example #16
0
func (c *Codegen) generateControl(node *parser.IfStmtNode) (ret bool) {
	currFunc := c.module.NamedFunction(c.currFunc)

	tru := llvm.AddBasicBlock(currFunc, "")
	var els llvm.BasicBlock
	if node.Else != nil {
		els = llvm.AddBasicBlock(currFunc, "")
	}
	exit := llvm.AddBasicBlock(currFunc, "")

	cond := c.generateExpression(node.Condition)
	if node.Else != nil {
		c.builder.CreateCondBr(cond, tru, els)
	} else {
		c.builder.CreateCondBr(cond, tru, exit)
	}

	c.builder.SetInsertPoint(tru, tru.LastInstruction())
	if c.generateBlock(node.Body) {
		ret = true
	} else {
		c.builder.CreateBr(exit)
	}

	if node.Else != nil {
		c.builder.SetInsertPoint(els, els.LastInstruction())
		var ok bool
		switch t := node.Else.(type) {
		case *parser.BlockNode:
			ok = c.generateBlock(t)
			ret = ok && ret
		case *parser.IfStmtNode:
			ok = c.generateControl(t)
			ret = ok && ret
		}

		if !ok {
			c.builder.CreateBr(exit)
		}
	}

	c.builder.SetInsertPoint(exit, exit.LastInstruction())
	return
}
Example #17
0
func (n *ForExpr) Gen(cg *CG) llvm.Value {
	startVal := n.Start.Gen(cg)
	if startVal.IsNil() {
		return errv("Code generation failed for start expression")
	}

	fun := cg.GetInsertBlock().Parent()
	alloca := createEntryBlockAlloca(fun, n.Var)
	cg.CreateStore(startVal, alloca)

	loopBB := llvm.AddBasicBlock(fun, "loop")
	cg.CreateBr(loopBB)
	cg.SetInsertPointAtEnd(loopBB)

	oldVal := cg.NamedValues[n.Var]
	cg.NamedValues[n.Var] = alloca

	if n.Body.Gen(cg).IsNil() {
		return llvm.Value{}
	}

	var stepVal llvm.Value
	if n.Step != nil {
		stepVal = n.Step.Gen(cg)
		if stepVal.IsNil() {
			return llvm.ConstNull(llvm.DoubleType())
		}
	} else {
		stepVal = llvm.ConstFloat(llvm.DoubleType(), 1)
	}

	endVal := n.End.Gen(cg)
	if endVal.IsNil() {
		return llvm.Value{}
	}

	curVar := cg.CreateLoad(alloca, n.Var)
	nextVar := cg.CreateFAdd(curVar, stepVal, "nextvar")
	cg.CreateStore(nextVar, alloca)

	endVal = cg.CreateFCmp(llvm.FloatONE, endVal, llvm.ConstFloat(llvm.DoubleType(), 0), "loopcond")
	afterBB := cg.AddBasicBlock(fun, "afterloop")

	cg.CreateCondBr(endVal, loopBB, afterBB)

	cg.SetInsertPointAtEnd(afterBB)

	if !oldVal.IsNil() {
		cg.NamedValues[n.Var] = oldVal
	} else {
		delete(cg.NamedValues, n.Var)
	}

	return llvm.ConstFloat(llvm.DoubleType(), 0)
}
Example #18
0
File: utils.go Project: hinike/llgo
func (fr *frame) loadOrNull(cond, ptr llvm.Value, ty types.Type) *govalue {
	startbb := fr.builder.GetInsertBlock()
	loadbb := llvm.AddBasicBlock(fr.function, "")
	contbb := llvm.AddBasicBlock(fr.function, "")
	fr.builder.CreateCondBr(cond, loadbb, contbb)

	fr.builder.SetInsertPointAtEnd(loadbb)
	llty := fr.types.ToLLVM(ty)
	typedptr := fr.builder.CreateBitCast(ptr, llvm.PointerType(llty, 0), "")
	loadedval := fr.builder.CreateLoad(typedptr, "")
	fr.builder.CreateBr(contbb)

	fr.builder.SetInsertPointAtEnd(contbb)
	llv := fr.builder.CreatePHI(llty, "")
	llv.AddIncoming(
		[]llvm.Value{llvm.ConstNull(llty), loadedval},
		[]llvm.BasicBlock{startbb, loadbb},
	)
	return newValue(llv, ty)
}
Example #19
0
func (c *Codegen) declareFunc(n *parser.FuncNode, obj llvm.Type) {
	sig := n.Signature
	name := c.mangle(sig.Name.Value)
	f := c.getLLVMFuncType(sig.Return, sig.Parameters, obj)
	llvmf := llvm.AddFunction(c.module, name, f)

	if obj != llvm.VoidType() {
		llvmf.Param(0).SetName("this")
	}

	block := llvm.AddBasicBlock(c.module.NamedFunction(name), "entry")

	c.functions[name] = block
}
Example #20
0
File: ssa.go Project: hinike/llgo
func (fr *frame) setupUnwindBlock(rec *ssa.BasicBlock, results *types.Tuple) {
	recoverbb := llvm.AddBasicBlock(fr.function, "")
	if rec != nil {
		fr.translateBlock(rec, recoverbb)
	} else if results.Len() == 0 || results.At(0).Anonymous() {
		// TODO(pcc): Remove this code after https://codereview.appspot.com/87210044/ lands
		fr.builder.SetInsertPointAtEnd(recoverbb)
		values := make([]llvm.Value, results.Len())
		for i := range values {
			values[i] = llvm.ConstNull(fr.llvmtypes.ToLLVM(results.At(i).Type()))
		}
		fr.retInf.encode(llvm.GlobalContext(), fr.allocaBuilder, fr.builder, values)
	} else {
		fr.builder.SetInsertPointAtEnd(recoverbb)
		fr.builder.CreateUnreachable()
	}

	checkunwindbb := llvm.AddBasicBlock(fr.function, "")
	fr.builder.SetInsertPointAtEnd(checkunwindbb)
	exc := fr.createLandingPad(true)
	fr.runDefers()

	frame := fr.builder.CreateLoad(fr.frameptr, "")
	shouldresume := fr.builder.CreateIsNull(frame, "")

	resumebb := llvm.AddBasicBlock(fr.function, "")
	fr.builder.CreateCondBr(shouldresume, resumebb, recoverbb)

	fr.builder.SetInsertPointAtEnd(resumebb)
	fr.builder.CreateResume(exc)

	fr.builder.SetInsertPointAtEnd(fr.unwindBlock)
	fr.createLandingPad(false)
	fr.runtime.checkDefer.invoke(fr, checkunwindbb, fr.frameptr)
	fr.runDefers()
	fr.builder.CreateBr(recoverbb)
}
Example #21
0
func (v *Codegen) genFunctionDecl(n *parser.FunctionDecl) llvm.Value {
	var res llvm.Value

	mangledName := n.Function.MangledName(parser.MANGLE_ARK_UNSTABLE)
	function := v.curFile.Module.NamedFunction(mangledName)
	if function.IsNil() {
		//v.err("genning function `%s` doesn't exist in module", n.Function.Name)
		// hmmmm seems we just ignore this here
	} else {

		if !n.Prototype {
			block := llvm.AddBasicBlock(function, "entry")
			v.builder.SetInsertPointAtEnd(block)

			for i, par := range n.Function.Parameters {
				alloc := v.builder.CreateAlloca(v.typeToLLVMType(par.Variable.Type), par.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE))
				v.variableLookup[par.Variable] = alloc

				v.builder.CreateStore(function.Params()[i], alloc)
			}

			v.inFunction = true
			v.currentFunction = function
			for _, stat := range n.Function.Body.Nodes {
				v.genNode(stat)
			}
			v.inFunction = false

			retType := llvm.VoidType()
			if n.Function.ReturnType != nil {
				retType = v.typeToLLVMType(n.Function.ReturnType)
			}

			// function returns void, lets return void
			// unless its a prototype obviously...
			if retType == llvm.VoidType() && !n.Prototype {
				v.builder.CreateRetVoid()
			}
		}
	}

	return res
}
Example #22
0
File: call.go Project: hinike/llgo
// createCall emits the code for a function call,
// taking into account receivers, and panic/defer.
func (fr *frame) createCall(fn *govalue, argValues []*govalue) []*govalue {
	fntyp := fn.Type().Underlying().(*types.Signature)
	typinfo := fr.types.getSignatureInfo(fntyp)

	args := make([]llvm.Value, len(argValues))
	for i, arg := range argValues {
		args[i] = arg.value
	}
	var results []llvm.Value
	if fr.unwindBlock.IsNil() {
		results = typinfo.call(fr.types.ctx, fr.allocaBuilder, fr.builder, fn.value, args)
	} else {
		contbb := llvm.AddBasicBlock(fr.function, "")
		results = typinfo.invoke(fr.types.ctx, fr.allocaBuilder, fr.builder, fn.value, args, contbb, fr.unwindBlock)
	}

	resultValues := make([]*govalue, len(results))
	for i, res := range results {
		resultValues[i] = newValue(res, fntyp.Results().At(i).Type())
	}
	return resultValues
}
Example #23
0
File: ssa.go Project: hinike/llgo
// bridgeRecoverFunc creates a function that may call recover(), and creates
// a call to it from the current frame. The created function will be called
// with a boolean parameter that indicates whether it may call recover().
//
// The created function will have the same name as the current frame's function
// with "$recover" appended, having the same return types and parameters with
// an additional boolean parameter appended.
//
// A new frame will be returned for the newly created function.
func (fr *frame) bridgeRecoverFunc(llfn llvm.Value, fti functionTypeInfo) *frame {
	// The bridging function must not be inlined, or the return address
	// may not correspond to the source function.
	llfn.AddFunctionAttr(llvm.NoInlineAttribute)

	// Call __go_can_recover, passing in the function's return address.
	entry := llvm.AddBasicBlock(llfn, "entry")
	fr.builder.SetInsertPointAtEnd(entry)
	canRecover := fr.runtime.canRecover.call(fr, fr.returnAddress(0))[0]
	returnType := fti.functionType.ReturnType()
	argTypes := fti.functionType.ParamTypes()
	argTypes = append(argTypes, canRecover.Type())

	// Create and call the $recover function.
	ftiRecover := fti
	ftiRecover.functionType = llvm.FunctionType(returnType, argTypes, false)
	llfnRecover := ftiRecover.declare(fr.module.Module, llfn.Name()+"$recover")
	fr.addCommonFunctionAttrs(llfnRecover)
	llfnRecover.SetLinkage(llvm.InternalLinkage)
	args := make([]llvm.Value, len(argTypes)-1, len(argTypes))
	for i := range args {
		args[i] = llfn.Param(i)
	}
	args = append(args, canRecover)
	result := fr.builder.CreateCall(llfnRecover, args, "")
	if returnType.TypeKind() == llvm.VoidTypeKind {
		fr.builder.CreateRetVoid()
	} else {
		fr.builder.CreateRet(result)
	}

	// The $recover function must condition calls to __go_recover on
	// the result of __go_can_recover passed in as an argument.
	fr = newFrame(fr.unit, llfnRecover)
	fr.retInf = ftiRecover.retInf
	fr.canRecover = fr.function.Param(len(argTypes) - 1)
	return fr
}
Example #24
0
func (n *FuncDecl) Gen(p *Parser, cg *CG) llvm.Value {
	cg.Protos[n.Proto.Name] = n.Proto
	fun := cg.GetFunction(n.Proto.Name)
	if fun.IsNil() {
		return errv("Prototype is missing")
	}

	if n.Proto.IsBinaryOp() {
		p.Prec[n.Proto.OperatorName()] = p.precedence()
	}

	bb := llvm.AddBasicBlock(fun, "entry")
	cg.SetInsertPointAtEnd(bb)

	cg.NamedValues = make(map[string]llvm.Value)

	args := fun.Params()
	for i := range args {
		alloca := createEntryBlockAlloca(fun, n.Proto.Args[i])
		cg.CreateStore(args[i], alloca)
		cg.NamedValues[n.Proto.Args[i]] = alloca
	}

	retVal := n.Body.Gen(cg)
	if !retVal.IsNil() {
		cg.CreateRet(retVal)
		llvm.VerifyFunction(fun, llvm.PrintMessageAction)
		cg.Fpm.RunFunc(fun)
		return fun
	}

	fun.EraseFromParentAsFunction()
	if n.Proto.IsBinaryOp() {
		delete(p.Prec, n.Proto.OperatorName())
	}

	return llvm.Value{}
}
Example #25
0
func (c *compiler) createInitMainFunction(mainPkg *ssa.Package, initmap map[*types.Package]gccgoimporter.InitData) error {
	initdata := c.buildPackageInitData(mainPkg, initmap)

	ftyp := llvm.FunctionType(llvm.VoidType(), nil, false)
	initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp)
	c.addCommonFunctionAttrs(initMain)
	entry := llvm.AddBasicBlock(initMain, "entry")

	builder := llvm.GlobalContext().NewBuilder()
	defer builder.Dispose()
	builder.SetInsertPointAtEnd(entry)

	for _, init := range initdata.Inits {
		initfn := c.module.Module.NamedFunction(init.InitFunc)
		if initfn.IsNil() {
			initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp)
		}
		builder.CreateCall(initfn, nil, "")
	}

	builder.CreateRetVoid()
	return nil
}
Example #26
0
File: ssa.go Project: hinike/llgo
func (u *unit) defineFunction(f *ssa.Function) {
	// Only define functions from this package, or synthetic
	// wrappers (which do not have a package).
	if f.Pkg != nil && f.Pkg != u.pkg {
		return
	}

	llfn := u.resolveFunctionGlobal(f)
	linkage := u.getFunctionLinkage(f)

	isMethod := f.Signature.Recv() != nil

	// Methods cannot be referred to via a descriptor.
	if !isMethod {
		llfd := u.resolveFunctionDescriptorGlobal(f)
		llfd.SetInitializer(llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0)))
		llfd.SetLinkage(linkage)
	}

	// We only need to emit a descriptor for functions without bodies.
	if len(f.Blocks) == 0 {
		return
	}

	ssaopt.LowerAllocsToStack(f)

	if u.DumpSSA {
		f.WriteTo(os.Stderr)
	}

	fr := newFrame(u, llfn)
	defer fr.dispose()
	fr.addCommonFunctionAttrs(fr.function)
	fr.function.SetLinkage(linkage)

	fr.logf("Define function: %s", f.String())
	fti := u.llvmtypes.getSignatureInfo(f.Signature)
	delete(u.undefinedFuncs, f)
	fr.retInf = fti.retInf

	// Push the compile unit and function onto the debug context.
	if u.GenerateDebug {
		u.debug.PushFunction(fr.function, f.Signature, f.Pos())
		defer u.debug.PopFunction()
		u.debug.SetLocation(fr.builder, f.Pos())
	}

	// If a function calls recover, we create a separate function to
	// hold the real function, and this function calls __go_can_recover
	// and bridges to it.
	if callsRecover(f) {
		fr = fr.bridgeRecoverFunc(fr.function, fti)
	}

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

	prologueBlock := llvm.InsertBasicBlock(fr.blocks[0], "prologue")
	fr.builder.SetInsertPointAtEnd(prologueBlock)

	// Map parameter positions to indices. We use this
	// when processing locals to map back to parameters
	// when generating debug metadata.
	paramPos := make(map[token.Pos]int)
	for i, param := range f.Params {
		paramPos[param.Pos()] = i
		llparam := fti.argInfos[i].decode(llvm.GlobalContext(), fr.builder, fr.builder)
		if isMethod && i == 0 {
			if _, ok := param.Type().Underlying().(*types.Pointer); !ok {
				llparam = fr.builder.CreateBitCast(llparam, llvm.PointerType(fr.types.ToLLVM(param.Type()), 0), "")
				llparam = fr.builder.CreateLoad(llparam, "")
			}
		}
		fr.env[param] = newValue(llparam, param.Type())
	}

	// Load closure, extract free vars.
	if len(f.FreeVars) > 0 {
		for _, fv := range f.FreeVars {
			fr.env[fv] = newValue(llvm.ConstNull(u.llvmtypes.ToLLVM(fv.Type())), fv.Type())
		}
		elemTypes := make([]llvm.Type, len(f.FreeVars)+1)
		elemTypes[0] = llvm.PointerType(llvm.Int8Type(), 0) // function pointer
		for i, fv := range f.FreeVars {
			elemTypes[i+1] = u.llvmtypes.ToLLVM(fv.Type())
		}
		structType := llvm.StructType(elemTypes, false)
		closure := fr.runtime.getClosure.call(fr)[0]
		closure = fr.builder.CreateBitCast(closure, llvm.PointerType(structType, 0), "")
		for i, fv := range f.FreeVars {
			ptr := fr.builder.CreateStructGEP(closure, i+1, "")
			ptr = fr.builder.CreateLoad(ptr, "")
			fr.env[fv] = newValue(ptr, fv.Type())
		}
	}

	// Allocate stack space for locals in the prologue block.
	for _, local := range f.Locals {
		typ := fr.llvmtypes.ToLLVM(deref(local.Type()))
		alloca := fr.builder.CreateAlloca(typ, local.Comment)
		fr.memsetZero(alloca, llvm.SizeOf(typ))
		bcalloca := fr.builder.CreateBitCast(alloca, llvm.PointerType(llvm.Int8Type(), 0), "")
		value := newValue(bcalloca, local.Type())
		fr.env[local] = value
		if fr.GenerateDebug {
			paramIndex, ok := paramPos[local.Pos()]
			if !ok {
				paramIndex = -1
			}
			fr.debug.Declare(fr.builder, local, alloca, paramIndex)
		}
	}

	// If this is the "init" function, enable init-specific optimizations.
	if !isMethod && f.Name() == "init" {
		fr.isInit = true
	}

	// If the function contains any defers, we must first create
	// an unwind block. We can short-circuit the check for defers with
	// f.Recover != nil.
	if f.Recover != nil || hasDefer(f) {
		fr.unwindBlock = llvm.AddBasicBlock(fr.function, "")
		fr.frameptr = fr.builder.CreateAlloca(llvm.Int8Type(), "")
	}

	term := fr.builder.CreateBr(fr.blocks[0])
	fr.allocaBuilder.SetInsertPointBefore(term)

	for _, block := range f.DomPreorder() {
		fr.translateBlock(block, fr.blocks[block.Index])
	}

	fr.fixupPhis()

	if !fr.unwindBlock.IsNil() {
		fr.setupUnwindBlock(f.Recover, f.Signature.Results())
	}

	// The init function needs to register the GC roots first. We do this
	// after generating code for it because allocations may have caused
	// additional GC roots to be created.
	if fr.isInit {
		fr.builder.SetInsertPointBefore(prologueBlock.FirstInstruction())
		fr.registerGcRoots()
	}
}
Example #27
0
// createThunk creates a thunk from a
// given function and arguments, suitable for use with
// "defer" and "go".
func (fr *frame) createThunk(call ssa.CallInstruction) (thunk llvm.Value, arg llvm.Value) {
	seenarg := make(map[ssa.Value]bool)
	var args []ssa.Value
	var argtypes []*types.Var

	packArg := func(arg ssa.Value) {
		switch arg.(type) {
		case *ssa.Builtin, *ssa.Function, *ssa.Const, *ssa.Global:
			// Do nothing: we can generate these in the thunk
		default:
			if !seenarg[arg] {
				seenarg[arg] = true
				args = append(args, arg)
				field := types.NewField(0, nil, "_", arg.Type(), true)
				argtypes = append(argtypes, field)
			}
		}
	}

	packArg(call.Common().Value)
	for _, arg := range call.Common().Args {
		packArg(arg)
	}

	var isRecoverCall bool
	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	var structllptr llvm.Type
	if len(args) == 0 {
		if builtin, ok := call.Common().Value.(*ssa.Builtin); ok {
			isRecoverCall = builtin.Name() == "recover"
		}
		if isRecoverCall {
			// When creating a thunk for recover(), we must pass fr.canRecover.
			arg = fr.builder.CreateZExt(fr.canRecover, fr.target.IntPtrType(), "")
			arg = fr.builder.CreateIntToPtr(arg, i8ptr, "")
		} else {
			arg = llvm.ConstPointerNull(i8ptr)
		}
	} else {
		structtype := types.NewStruct(argtypes, nil)
		arg = fr.createTypeMalloc(structtype)
		structllptr = arg.Type()
		for i, ssaarg := range args {
			argptr := fr.builder.CreateStructGEP(arg, i, "")
			fr.builder.CreateStore(fr.llvmvalue(ssaarg), argptr)
		}
		arg = fr.builder.CreateBitCast(arg, i8ptr, "")
	}

	thunkfntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{i8ptr}, false)
	thunkfn := llvm.AddFunction(fr.module.Module, "", thunkfntype)
	thunkfn.SetLinkage(llvm.InternalLinkage)
	fr.addCommonFunctionAttrs(thunkfn)

	thunkfr := newFrame(fr.unit, thunkfn)
	defer thunkfr.dispose()

	prologuebb := llvm.AddBasicBlock(thunkfn, "prologue")
	thunkfr.builder.SetInsertPointAtEnd(prologuebb)

	if isRecoverCall {
		thunkarg := thunkfn.Param(0)
		thunkarg = thunkfr.builder.CreatePtrToInt(thunkarg, fr.target.IntPtrType(), "")
		thunkfr.canRecover = thunkfr.builder.CreateTrunc(thunkarg, llvm.Int1Type(), "")
	} else if len(args) > 0 {
		thunkarg := thunkfn.Param(0)
		thunkarg = thunkfr.builder.CreateBitCast(thunkarg, structllptr, "")
		for i, ssaarg := range args {
			thunkargptr := thunkfr.builder.CreateStructGEP(thunkarg, i, "")
			thunkarg := thunkfr.builder.CreateLoad(thunkargptr, "")
			thunkfr.env[ssaarg] = newValue(thunkarg, ssaarg.Type())
		}
	}

	_, isDefer := call.(*ssa.Defer)

	entrybb := llvm.AddBasicBlock(thunkfn, "entry")
	br := thunkfr.builder.CreateBr(entrybb)
	thunkfr.allocaBuilder.SetInsertPointBefore(br)

	thunkfr.builder.SetInsertPointAtEnd(entrybb)
	var exitbb llvm.BasicBlock
	if isDefer {
		exitbb = llvm.AddBasicBlock(thunkfn, "exit")
		thunkfr.runtime.setDeferRetaddr.call(thunkfr, llvm.BlockAddress(thunkfn, exitbb))
	}
	if isDefer && isRecoverCall {
		thunkfr.callRecover(true)
	} else {
		thunkfr.callInstruction(call)
	}
	if isDefer {
		thunkfr.builder.CreateBr(exitbb)
		thunkfr.builder.SetInsertPointAtEnd(exitbb)
	}
	thunkfr.builder.CreateRetVoid()

	thunk = fr.builder.CreateBitCast(thunkfn, i8ptr, "")
	return
}
Example #28
0
func (rfi *runtimeFnInfo) invoke(f *frame, lpad llvm.BasicBlock, args ...llvm.Value) []llvm.Value {
	contbb := llvm.AddBasicBlock(f.function, "")
	return rfi.fi.invoke(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, llvm.Value{nil}, args, contbb, lpad)
}
Example #29
0
// mapIterNext advances the iterator, and returns the tuple (ok, k, v).
func (fr *frame) mapIterNext(iter []*govalue) []*govalue {
	maptyp := iter[0].Type().Underlying().(*types.Map)
	ktyp := maptyp.Key()
	klltyp := fr.types.ToLLVM(ktyp)
	vtyp := maptyp.Elem()
	vlltyp := fr.types.ToLLVM(vtyp)

	m, isinitptr := iter[0], iter[1]

	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	mapiterbufty := llvm.ArrayType(i8ptr, 4)
	mapiterbuf := fr.allocaBuilder.CreateAlloca(mapiterbufty, "")
	mapiterbufelem0ptr := fr.builder.CreateStructGEP(mapiterbuf, 0, "")

	keybuf := fr.allocaBuilder.CreateAlloca(klltyp, "")
	keyptr := fr.builder.CreateBitCast(keybuf, i8ptr, "")
	valbuf := fr.allocaBuilder.CreateAlloca(vlltyp, "")
	valptr := fr.builder.CreateBitCast(valbuf, i8ptr, "")

	isinit := fr.builder.CreateLoad(isinitptr.value, "")

	initbb := llvm.AddBasicBlock(fr.function, "")
	nextbb := llvm.AddBasicBlock(fr.function, "")
	contbb := llvm.AddBasicBlock(fr.function, "")

	fr.builder.CreateCondBr(isinit, nextbb, initbb)

	fr.builder.SetInsertPointAtEnd(initbb)
	fr.builder.CreateStore(llvm.ConstAllOnes(llvm.Int1Type()), isinitptr.value)
	fr.runtime.mapiterinit.call(fr, m.value, mapiterbufelem0ptr)
	fr.builder.CreateBr(contbb)

	fr.builder.SetInsertPointAtEnd(nextbb)
	fr.runtime.mapiternext.call(fr, mapiterbufelem0ptr)
	fr.builder.CreateBr(contbb)

	fr.builder.SetInsertPointAtEnd(contbb)
	mapiterbufelem0 := fr.builder.CreateLoad(mapiterbufelem0ptr, "")
	okbit := fr.builder.CreateIsNotNull(mapiterbufelem0, "")
	ok := fr.builder.CreateZExt(okbit, llvm.Int8Type(), "")

	loadbb := llvm.AddBasicBlock(fr.function, "")
	cont2bb := llvm.AddBasicBlock(fr.function, "")
	fr.builder.CreateCondBr(okbit, loadbb, cont2bb)

	fr.builder.SetInsertPointAtEnd(loadbb)
	fr.runtime.mapiter2.call(fr, mapiterbufelem0ptr, keyptr, valptr)
	loadbb = fr.builder.GetInsertBlock()
	loadedkey := fr.builder.CreateLoad(keybuf, "")
	loadedval := fr.builder.CreateLoad(valbuf, "")
	fr.builder.CreateBr(cont2bb)

	fr.builder.SetInsertPointAtEnd(cont2bb)
	k := fr.builder.CreatePHI(klltyp, "")
	k.AddIncoming(
		[]llvm.Value{llvm.ConstNull(klltyp), loadedkey},
		[]llvm.BasicBlock{contbb, loadbb},
	)
	v := fr.builder.CreatePHI(vlltyp, "")
	v.AddIncoming(
		[]llvm.Value{llvm.ConstNull(vlltyp), loadedval},
		[]llvm.BasicBlock{contbb, loadbb},
	)

	return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, ktyp), newValue(v, vtyp)}
}