Esempio n. 1
0
File: codegen.go Progetto: 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)
	}
}
Esempio n. 2
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
}
Esempio n. 3
0
// parseBasicBlock converts the provided LLVM IR basic block into a basic block
// in which the instructions have been translated to Go AST statement nodes but
// the terminator instruction is an unmodified LLVM IR value.
func parseBasicBlock(llBB llvm.BasicBlock) (bb *basicBlock, err error) {
	name, err := getBBName(llBB.AsValue())
	if err != nil {
		return nil, err
	}
	bb = &basicBlock{name: name, phis: make(map[string][]*definition)}
	for inst := llBB.FirstInstruction(); !inst.IsNil(); inst = llvm.NextInstruction(inst) {
		// Handle terminator instruction.
		if inst == llBB.LastInstruction() {
			err = bb.addTerm(inst)
			if err != nil {
				return nil, errutil.Err(err)
			}
			return bb, nil
		}

		// Handle PHI instructions.
		if inst.InstructionOpcode() == llvm.PHI {
			ident, def, err := parsePHIInst(inst)
			if err != nil {
				return nil, errutil.Err(err)
			}
			bb.phis[ident] = def
			continue
		}

		// Handle non-terminator instructions.
		stmt, err := parseInst(inst)
		if err != nil {
			return nil, err
		}
		bb.stmts = append(bb.stmts, stmt)
	}
	return nil, errutil.Newf("invalid basic block %q; contains no instructions", name)
}
Esempio n. 4
0
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])
	fr.transformSwitches(f)

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

	for i, param := range f.Params {
		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.function.Param(fti.chainIndex)
		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 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(), "")
	}

	// Keep track of the block into which we need to insert the call
	// to __go_register_gc_roots. This needs to be inserted after the
	// init guard check under the llgo ABI.
	var registerGcBlock llvm.BasicBlock

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

	fr.builder.CreateBr(fr.blocks[0])
	fr.allocaBuilder.SetInsertPointBefore(prologueBlock.FirstInstruction())

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

	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(registerGcBlock.FirstInstruction())
		fr.registerGcRoots()
	}
}