Ejemplo n.º 1
0
Archivo: lower.go Proyecto: mewmew/uc
// returnStmt lowers the given return statement to LLVM IR, emitting code to f.
func (m *Module) returnStmt(f *Function, stmt *ast.ReturnStmt) {
	// Input:
	//    int f() {
	//       return 42;       // <-- relevant line
	//    }
	// Output:
	//    ret i32 42
	if stmt.Result == nil {
		term, err := instruction.NewRet(nil)
		if err != nil {
			panic(fmt.Sprintf("unable to create ret terminator; %v", err))
		}
		f.curBlock.SetTerm(term)
		f.curBlock = nil
		return
	}
	result := m.expr(f, stmt.Result)
	// Implicit conversion.
	resultType := f.Sig().Result()
	result = m.convert(f, result, resultType)
	term, err := instruction.NewRet(result)
	if err != nil {
		panic(fmt.Sprintf("unable to create ret terminator; %v", err))
	}
	f.curBlock.SetTerm(term)
	f.curBlock = nil
}
Ejemplo n.º 2
0
Archivo: irgen.go Proyecto: 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
}
Ejemplo n.º 3
0
Archivo: irx.go Proyecto: llir/llvm
// NewRetInst returns a new return instruction based on the given result type
// and value.
func NewRetInst(typ, val interface{}) (*instruction.Ret, error) {
	if typ, ok := typ.(types.Type); ok {
		val, err := NewValue(typ, val)
		if err != nil {
			return nil, errutil.Err(err)
		}
		return instruction.NewRet(val)
	}
	return nil, errutil.Newf("invalid result type; expected types.Type, got %T", typ)
}
Ejemplo n.º 4
0
Archivo: fix.go Proyecto: llir/llvm
// fixTerm replaces dummy values within the given terminator with their
// corresponding local variables.
func (m dummyMap) fixTerm(oldTerm instruction.Terminator) instruction.Terminator {
	switch oldTerm := oldTerm.(type) {
	case *instruction.Ret:
		oldVal := oldTerm.Value()
		var val value.Value
		if oldVal != nil {
			val = m.fixValue(oldVal)
		}
		term, err := instruction.NewRet(val)
		if err != nil {
			panic(errutil.Err(err))
		}
		return term
	case *instruction.Jmp:
		target := m.fixNamedValue(oldTerm.Target())
		term, err := instruction.NewJmp(target)
		if err != nil {
			panic(errutil.Err(err))
		}
		return term
	case *instruction.Br:
		cond := m.fixValue(oldTerm.Cond())
		trueBranch := m.fixNamedValue(oldTerm.TrueBranch())
		falseBranch := m.fixNamedValue(oldTerm.FalseBranch())
		term, err := instruction.NewBr(cond, trueBranch, falseBranch)
		if err != nil {
			panic(errutil.Err(err))
		}
		return term
	case *instruction.Switch:
		panic("irx.dummyMap.fixTerm: Switch not yet implemented")
	case *instruction.IndirectBr:
		panic("irx.dummyMap.fixTerm: IndirectBr not yet implemented")
	case *instruction.Invoke:
		panic("irx.dummyMap.fixTerm: Invoke not yet implemented")
	case *instruction.Resume:
		panic("irx.dummyMap.fixTerm: Resume not yet implemented")
	case *instruction.CatchSwitch:
		panic("irx.dummyMap.fixTerm: CatchSwitch not yet implemented")
	case *instruction.CatchRet:
		panic("irx.dummyMap.fixTerm: CatchRet not yet implemented")
	case *instruction.CleanupRet:
		panic("irx.dummyMap.fixTerm: CleanupRet not yet implemented")
	case *instruction.Unreachable:
		panic("irx.dummyMap.fixTerm: Unreachable not yet implemented")
	default:
		panic(fmt.Sprintf("support for terminator type %T not yet implemented", oldTerm))
	}
}