To support multiple return values, now ret instruction supports multiple operands instead of one aggregate operand.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@47508 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Devang Patel 2008-02-23 00:35:18 +00:00
parent 313d4b8093
commit 57ef4f46c1
6 changed files with 77 additions and 65 deletions

View File

@ -1379,9 +1379,9 @@ public:
/// does not continue in this function any longer. /// does not continue in this function any longer.
/// ///
class ReturnInst : public TerminatorInst { class ReturnInst : public TerminatorInst {
Use RetVal; // Return Value: null if 'void'.
ReturnInst(const ReturnInst &RI); ReturnInst(const ReturnInst &RI);
void init(Value *RetVal); void init(Value *RetVal);
void init(std::vector<Value *> &RetVals);
public: public:
// ReturnInst constructors: // ReturnInst constructors:
@ -1397,21 +1397,15 @@ public:
// if it was passed NULL. // if it was passed NULL.
explicit ReturnInst(Value *retVal = 0, Instruction *InsertBefore = 0); explicit ReturnInst(Value *retVal = 0, Instruction *InsertBefore = 0);
ReturnInst(Value *retVal, BasicBlock *InsertAtEnd); ReturnInst(Value *retVal, BasicBlock *InsertAtEnd);
ReturnInst(std::vector<Value *> &retVals);
ReturnInst(std::vector<Value *> &retVals, Instruction *InsertBefore);
ReturnInst(std::vector<Value *> &retVals, BasicBlock *InsertAtEnd);
explicit ReturnInst(BasicBlock *InsertAtEnd); explicit ReturnInst(BasicBlock *InsertAtEnd);
virtual ~ReturnInst();
virtual ReturnInst *clone() const; virtual ReturnInst *clone() const;
// Transparently provide more efficient getOperand methods. Value *getReturnValue(unsigned n = 0) const;
Value *getOperand(unsigned i) const {
assert(i < getNumOperands() && "getOperand() out of range!");
return RetVal;
}
void setOperand(unsigned i, Value *Val) {
assert(i < getNumOperands() && "setOperand() out of range!");
RetVal = Val;
}
Value *getReturnValue() const { return RetVal; }
unsigned getNumSuccessors() const { return 0; } unsigned getNumSuccessors() const { return 0; }

View File

@ -29,8 +29,9 @@ protected:
/// OperandList - This is a pointer to the array of Users for this operand. /// OperandList - This is a pointer to the array of Users for this operand.
/// For nodes of fixed arity (e.g. a binary operator) this array will live /// For nodes of fixed arity (e.g. a binary operator) this array will live
/// embedded into the derived class. For nodes of variable arity /// embedded into the derived class. For nodes of variable arity
/// (e.g. ConstantArrays, CallInst, PHINodes, etc), this memory will be /// (e.g. ConstantArrays, CallInst, PHINodes, ReturnInst etc), this memory
/// dynamically allocated and should be destroyed by the classes virtual dtor. /// will be dynamically allocated and should be destroyed by the classes
/// virtual dtor.
Use *OperandList; Use *OperandList;
/// NumOperands - The number of values used by this User. /// NumOperands - The number of values used by this User.

View File

@ -2531,7 +2531,7 @@ ReturnedVal : ResolvedVal {
$$->push_back($1); $$->push_back($1);
CHECK_FOR_ERROR CHECK_FOR_ERROR
} }
| ReturnedVal ',' ConstVal { | ReturnedVal ',' ResolvedVal {
($$=$1)->push_back($3); ($$=$1)->push_back($3);
CHECK_FOR_ERROR CHECK_FOR_ERROR
}; };
@ -2580,28 +2580,7 @@ InstructionList : InstructionList Inst {
BBTerminatorInst : BBTerminatorInst :
RET ReturnedVal { // Return with a result... RET ReturnedVal { // Return with a result...
if($2->size() == 1) $$ = new ReturnInst(*$2);
$$ = new ReturnInst($2->back());
else {
std::vector<const Type*> Elements;
std::vector<Constant*> Vals;
for (std::vector<Value *>::iterator I = $2->begin(),
E = $2->end(); I != E; ++I) {
Value *V = *I;
Constant *C = cast<Constant>(V);
Elements.push_back(V->getType());
Vals.push_back(C);
}
const StructType *STy = StructType::get(Elements);
PATypeHolder *PTy =
new PATypeHolder(HandleUpRefs(StructType::get(Elements)));
Constant *CS = ConstantStruct::get(STy, Vals); // *$2);
$$ = new ReturnInst(CS);
delete PTy;
}
delete $2; delete $2;
CHECK_FOR_ERROR CHECK_FOR_ERROR
} }
@ -3174,6 +3153,7 @@ MemoryInst : MALLOC Types OptCAlign {
if (!GetResultInst::isValidOperands(TmpVal, $5)) if (!GetResultInst::isValidOperands(TmpVal, $5))
GEN_ERROR("Invalid getresult operands"); GEN_ERROR("Invalid getresult operands");
$$ = new GetResultInst(TmpVal, $5); $$ = new GetResultInst(TmpVal, $5);
delete $2;
CHECK_FOR_ERROR CHECK_FOR_ERROR
} }
| GETELEMENTPTR Types ValueRef IndexList { | GETELEMENTPTR Types ValueRef IndexList {

View File

@ -1304,23 +1304,8 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
Out << " }"; Out << " }";
writeOperand(I.getOperand(0), false); writeOperand(I.getOperand(0), false);
Out << ", " << cast<GetResultInst>(I).getIndex(); Out << ", " << cast<GetResultInst>(I).getIndex();
} else if (isa<ReturnInst>(I)) { } else if (isa<ReturnInst>(I) && !Operand) {
if (!Operand) Out << " void";
Out << " void";
else {
if (I.getOperand(0)->getType()->isFirstClassType())
writeOperand(I.getOperand(0), true);
else {
Constant *ROp = cast<Constant>(I.getOperand(0));
const StructType *STy = cast<StructType>(ROp->getType());
unsigned NumElems = STy->getNumElements();
for (unsigned i = 0; i < NumElems; ++i) {
if (i)
Out << ",";
writeOperand(ROp->getOperand(i), true);
}
}
}
} else if (const CallInst *CI = dyn_cast<CallInst>(&I)) { } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
// Print the calling convention being used. // Print the calling convention being used.
switch (CI->getCallingConv()) { switch (CI->getCallingConv()) {

View File

@ -573,34 +573,75 @@ bool InvokeInst::isStructReturn() const {
ReturnInst::ReturnInst(const ReturnInst &RI) ReturnInst::ReturnInst(const ReturnInst &RI)
: TerminatorInst(Type::VoidTy, Instruction::Ret, : TerminatorInst(Type::VoidTy, Instruction::Ret,
&RetVal, RI.getNumOperands()) { OperandList, RI.getNumOperands()) {
if (RI.getNumOperands()) unsigned N = RI.getNumOperands();
RetVal.init(RI.RetVal, this); Use *OL = OperandList = new Use[N];
for (unsigned i = 0; i < N; ++i)
OL[i].init(RI.getOperand(i), this);
} }
ReturnInst::ReturnInst(Value *retVal, Instruction *InsertBefore) ReturnInst::ReturnInst(Value *retVal, Instruction *InsertBefore)
: TerminatorInst(Type::VoidTy, Instruction::Ret, &RetVal, 0, InsertBefore) { : TerminatorInst(Type::VoidTy, Instruction::Ret, OperandList, 0, InsertBefore) {
init(retVal); init(retVal);
} }
ReturnInst::ReturnInst(Value *retVal, BasicBlock *InsertAtEnd) ReturnInst::ReturnInst(Value *retVal, BasicBlock *InsertAtEnd)
: TerminatorInst(Type::VoidTy, Instruction::Ret, &RetVal, 0, InsertAtEnd) { : TerminatorInst(Type::VoidTy, Instruction::Ret, OperandList, 0, InsertAtEnd) {
init(retVal); init(retVal);
} }
ReturnInst::ReturnInst(BasicBlock *InsertAtEnd) ReturnInst::ReturnInst(BasicBlock *InsertAtEnd)
: TerminatorInst(Type::VoidTy, Instruction::Ret, &RetVal, 0, InsertAtEnd) { : TerminatorInst(Type::VoidTy, Instruction::Ret, OperandList, 0, InsertAtEnd) {
} }
ReturnInst::ReturnInst(std::vector<Value *> &retVals, Instruction *InsertBefore)
: TerminatorInst(Type::VoidTy, Instruction::Ret, OperandList, retVals.size(), InsertBefore) {
init(retVals);
}
ReturnInst::ReturnInst(std::vector<Value *> &retVals, BasicBlock *InsertAtEnd)
: TerminatorInst(Type::VoidTy, Instruction::Ret, OperandList, retVals.size(), InsertAtEnd) {
init(retVals);
}
ReturnInst::ReturnInst(std::vector<Value *> &retVals)
: TerminatorInst(Type::VoidTy, Instruction::Ret, OperandList, retVals.size()) {
init(retVals);
}
void ReturnInst::init(Value *retVal) { void ReturnInst::init(Value *retVal) {
if (retVal && retVal->getType() != Type::VoidTy) { if (retVal && retVal->getType() != Type::VoidTy) {
assert(!isa<BasicBlock>(retVal) && assert(!isa<BasicBlock>(retVal) &&
"Cannot return basic block. Probably using the incorrect ctor"); "Cannot return basic block. Probably using the incorrect ctor");
NumOperands = 1; NumOperands = 1;
RetVal.init(retVal, this); Use *OL = OperandList = new Use[1];
OL[0].init(retVal, this);
} }
} }
void ReturnInst::init(std::vector<Value *> &retVals) {
if (retVals.empty())
return;
NumOperands = retVals.size();
if (NumOperands == 1) {
Value *V = retVals[0];
if (V->getType() == Type::VoidTy)
return;
}
Use *OL = OperandList = new Use[NumOperands];
for (unsigned i = 0; i < NumOperands; ++i) {
Value *V = retVals[i];
assert(!isa<BasicBlock>(V) &&
"Cannot return basic block. Probably using the incorrect ctor");
OL[i].init(V, this);
}
}
Value *ReturnInst::getReturnValue(unsigned n) const {
if (NumOperands)
return OperandList[n];
else
return 0;
}
unsigned ReturnInst::getNumSuccessorsV() const { unsigned ReturnInst::getNumSuccessorsV() const {
return getNumSuccessors(); return getNumSuccessors();
} }
@ -617,6 +658,10 @@ BasicBlock *ReturnInst::getSuccessorV(unsigned idx) const {
return 0; return 0;
} }
ReturnInst::~ReturnInst() {
if (NumOperands)
delete [] OperandList;
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// UnwindInst Implementation // UnwindInst Implementation
@ -2759,7 +2804,6 @@ bool GetResultInst::isValidOperands(const Value *Aggregate, unsigned Index) {
return false; return false;
} }
// Define these methods here so vtables don't get emitted into every translation // Define these methods here so vtables don't get emitted into every translation
// unit that uses these classes. // unit that uses these classes.

View File

@ -576,14 +576,22 @@ void Verifier::visitTerminatorInst(TerminatorInst &I) {
void Verifier::visitReturnInst(ReturnInst &RI) { void Verifier::visitReturnInst(ReturnInst &RI) {
Function *F = RI.getParent()->getParent(); Function *F = RI.getParent()->getParent();
if (RI.getNumOperands() == 0) unsigned N = RI.getNumOperands();
if (N == 0)
Assert2(F->getReturnType() == Type::VoidTy, Assert2(F->getReturnType() == Type::VoidTy,
"Found return instr that returns void in Function of non-void " "Found return instr that returns void in Function of non-void "
"return type!", &RI, F->getReturnType()); "return type!", &RI, F->getReturnType());
else else if (N == 1)
Assert2(F->getReturnType() == RI.getOperand(0)->getType(), Assert2(F->getReturnType() == RI.getOperand(0)->getType(),
"Function return type does not match operand " "Function return type does not match operand "
"type of return inst!", &RI, F->getReturnType()); "type of return inst!", &RI, F->getReturnType());
else {
const StructType *STy = cast<StructType>(F->getReturnType());
for (unsigned i = 0; i < N; i++)
Assert2(STy->getElementType(i) == RI.getOperand(i)->getType(),
"Function return type does not match operand "
"type of return inst!", &RI, F->getReturnType());
}
// Check to make sure that the return value has necessary properties for // Check to make sure that the return value has necessary properties for
// terminators... // terminators...