mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-15 04:30:12 +00:00
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:
parent
313d4b8093
commit
57ef4f46c1
@ -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; }
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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 {
|
||||||
|
@ -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()) {
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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...
|
||||||
|
Loading…
Reference in New Issue
Block a user