Handle multiple ret values.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@48254 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Devang Patel 2008-03-11 22:24:29 +00:00
parent a0238778db
commit 7db30ba701
2 changed files with 79 additions and 21 deletions

View File

@ -24,6 +24,7 @@
#include "llvm/Support/CallSite.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SmallVector.h"
using namespace llvm;
STATISTIC(NumArgumentsProped, "Number of args turned into constants");
@ -142,22 +143,44 @@ bool IPCP::PropagateConstantReturn(Function &F) {
return false; // No return value.
// Check to see if this function returns a constant.
Value *RetVal = 0;
SmallVector<Value *,4> RetVals;
unsigned N = 0;
const StructType *STy = dyn_cast<StructType>(F.getReturnType());
if (STy)
N = STy->getNumElements();
else
N = 1;
for (unsigned i = 0; i < N; ++i)
RetVals.push_back(0);
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
if (ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator())) {
if (isa<UndefValue>(RI->getOperand(0))) {
// Ignore.
} else if (Constant *C = dyn_cast<Constant>(RI->getOperand(0))) {
if (RetVal == 0)
RetVal = C;
else if (RetVal != C)
return false; // Does not return the same constant.
} else {
return false; // Does not return a constant.
assert (N == RI->getNumOperands() && "Invalid ReturnInst operands!");
for (unsigned i = 0; i < N; ++i) {
if (isa<UndefValue>(RI->getOperand(i))) {
// Ignore
} else if (Constant *C = dyn_cast<Constant>(RI->getOperand(i))) {
Value *RV = RetVals[i];
if (RV == 0)
RetVals[i] = C;
else if (RV != C)
return false; // Does not return the same constant.
} else {
return false; // Does not return a constant.
}
}
}
if (RetVal == 0) RetVal = UndefValue::get(F.getReturnType());
if (N == 1) {
if (RetVals[0] == 0)
RetVals[0] = UndefValue::get(F.getReturnType());
} else {
for (unsigned i = 0; i < N; ++i) {
Value *RetVal = RetVals[i];
if (RetVal == 0)
RetVals[i] = UndefValue::get(STy->getElementType(i));
}
}
// If we got here, the function returns a constant value. Loop over all
// users, replacing any uses of the return value with the returned constant.
@ -172,8 +195,18 @@ bool IPCP::PropagateConstantReturn(Function &F) {
CS.getCalledFunction() != &F) {
ReplacedAllUsers = false;
} else {
if (!CS.getInstruction()->use_empty()) {
CS.getInstruction()->replaceAllUsesWith(RetVal);
Instruction *Call = CS.getInstruction();
if (!Call->use_empty()) {
if (N == 1)
Call->replaceAllUsesWith(RetVals[0]);
else {
for(Value::use_iterator CUI = Call->use_begin(), CUE = Call->use_end();
CUI != CUE; ++CUI) {
GetResultInst *GR = cast<GetResultInst>(CUI);
GR->replaceAllUsesWith(RetVals[GR->getIndex()]);
GR->eraseFromParent();
}
}
MadeChange = true;
}
}
@ -182,15 +215,20 @@ bool IPCP::PropagateConstantReturn(Function &F) {
// If we replace all users with the returned constant, and there can be no
// other callers of the function, replace the constant being returned in the
// function with an undef value.
if (ReplacedAllUsers && F.hasInternalLinkage() && !isa<UndefValue>(RetVal)) {
Value *RV = UndefValue::get(RetVal->getType());
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
if (ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator())) {
if (RI->getOperand(0) != RV) {
RI->setOperand(0, RV);
MadeChange = true;
if (ReplacedAllUsers && F.hasInternalLinkage()) {
for (unsigned i = 0; i < N; ++i) {
Value *RetVal = RetVals[i];
if (isa<UndefValue>(RetVal))
continue;
Value *RV = UndefValue::get(RetVal->getType());
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
if (ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator())) {
if (RI->getOperand(i) != RV) {
RI->setOperand(i, RV);
MadeChange = true;
}
}
}
}
}
if (MadeChange) ++NumReturnValProped;

View File

@ -0,0 +1,20 @@
; RUN: llvm-as < %s | opt -ipconstprop | llvm-dis | grep {add i32 21, 21}
define internal {i32, i32} @foo(i1 %C) {
br i1 %C, label %T, label %F
T: ; preds = %0
ret i32 21, i32 21
F: ; preds = %0
ret i32 21, i32 21
}
define i32 @caller(i1 %C) {
%X = call {i32, i32} @foo( i1 %C )
%A = getresult {i32, i32} %X, 0
%B = getresult {i32, i32} %X, 1
%Y = add i32 %A, %B
ret i32 %Y
}