Exemplo n.º 1
0
Arquivo: irgen.go Projeto: mewmew/uc
// endBody finalizes the generation of the function body.
func (f *Function) endBody() error {
	if block := f.curBlock; block != nil && block.Term() == nil {
		switch {
		case f.Function.Name() == "main":
			// From C11 spec $5.1.2.2.3.
			//
			// "If the return type of the main function is a type compatible with
			// int, a return from the initial call to the main function is
			// equivalent to calling the exit function with the value returned by
			// the main function as its argument; reaching the } that terminates
			// the main function returns a value of 0."
			result := f.Sig().Result()
			zero := constZero(result)
			term, err := instruction.NewRet(zero)
			if err != nil {
				panic(fmt.Sprintf("unable to create ret terminator; %v", err))
			}
			block.SetTerm(term)
		default:
			// Add void return terminator to the current basic block, if a
			// terminator is missing.
			switch result := f.Sig().Result(); {
			case irtypes.IsVoid(result):
				term, err := instruction.NewRet(nil)
				if err != nil {
					panic(fmt.Sprintf("unable to create ret instruction; %v", err))
				}
				block.SetTerm(term)
			default:
				// The semantic analysis checker guarantees that all branches of
				// non-void functions end with return statements. Therefore, if we
				// reach the current basic block doesn't have a terminator at the
				// end of the function body, it must be unreachable.
				term, err := instruction.NewUnreachable()
				if err != nil {
					panic(fmt.Sprintf("unable to create unreachable instruction; %v", err))
				}
				block.SetTerm(term)
			}
		}
	}
	f.curBlock = nil
	if err := f.AssignIDs(); err != nil {
		return errutil.Err(err)
	}
	return nil
}
Exemplo n.º 2
0
// assignIDs assigns unique IDs to unnamed basic blocks and local variable
// definitions.
func (block *BasicBlock) assignIDs() error {
	f := block.Parent()

	// Named represents a named basic block or local variable definition.
	type Named interface {
		Name() string
		SetName(name string)
	}

	// setName assigns unique local IDs to unnamed basic blocks and local
	// variable definitions.
	setName := func(n Named) error {
		// TODO: Ensure that global variables cannot be mixed up with local
		// variables. This should be easy, as global variables may not be unnamed.
		// Check that global variables are always given a name during creation.
		if name := n.Name(); len(name) == 0 {
			n.SetName(f.nextID())
		} else if isLocalID(name) {
			// Validate that explicitly named local IDs conform to the localID
			// counter and update the localID counter to keep explicitly and
			// implicitly named local IDs in sync.
			if want := f.nextID(); name != want {
				return errutil.Newf("invalid local ID; expected %s, got %s", enc.Local(want), enc.Local(name))
			}
		}
		return nil
	}

	// Assign unique local IDs to unnamed basic blocks.
	if err := setName(block); err != nil {
		return errutil.Err(err)
	}

	// Assign unique local IDs to unnamed local variable definitions.
	for _, inst := range block.Insts() {
		if def, ok := inst.(*instruction.LocalVarDef); ok {
			if !types.IsVoid(def.ValInst().RetType()) {
				if err := setName(def); err != nil {
					return errutil.Err(err)
				}
			}
		}
	}

	return nil
}
Exemplo n.º 3
0
// NewRet returns a new ret instruction based on the given return value. A nil
// return value indicates a "void" return instruction.
func NewRet(val value.Value) (*Ret, error) {
	if val != nil && types.IsVoid(val.Type()) {
		return nil, errutil.Newf(`expected no return value for return type "void"; got %q`, val)
	}
	return &Ret{val: val}, nil
}
Exemplo n.º 4
0
Arquivo: local.go Projeto: llir/llvm
// String returns the string representation of the local variable definition;
// e.g.
//
//    %foo = add i32 13, 42
func (def *LocalVarDef) String() string {
	if types.IsVoid(def.Type()) || len(def.Name()) == 0 {
		return def.valInst.String()
	}
	return fmt.Sprintf("%s = %s", def.ValueString(), def.valInst)
}