[llvm-commits] [llvm] r85973 - in /llvm/trunk: lib/Transforms/Scalar/SCCP.cpp test/Transforms/SCCP/ipsccp-basic.ll
Chris Lattner
sabre at nondot.org
Tue Nov 3 15:40:48 PST 2009
Author: lattner
Date: Tue Nov 3 17:40:48 2009
New Revision: 85973
URL: http://llvm.org/viewvc/llvm-project?rev=85973&view=rev
Log:
reimplement multiple return value handling in IPSCCP, making it
more aggressive an correct. This survives building llvm in 64-bit
mode with optimizations and the built llvm passes make check.
Modified:
llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll
Modified: llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SCCP.cpp?rev=85973&r1=85972&r2=85973&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/SCCP.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/SCCP.cpp Tue Nov 3 17:40:48 2009
@@ -159,6 +159,11 @@
SmallPtrSet<BasicBlock*, 8> BBExecutable;// The BBs that are executable.
DenseMap<Value*, LatticeVal> ValueState; // The state each value is in.
+ /// StructValueState - This maintains ValueState for values that have
+ /// StructType, for example for formal arguments, calls, insertelement, etc.
+ ///
+ DenseMap<std::pair<Value*, unsigned>, LatticeVal> StructValueState;
+
/// GlobalValue - If we are tracking any values for the contents of a global
/// variable, we keep a mapping from the constant accessor to the element of
/// the global, to the currently known value. If the value becomes
@@ -173,6 +178,10 @@
/// TrackedMultipleRetVals - Same as TrackedRetVals, but used for functions
/// that return multiple values.
DenseMap<std::pair<Function*, unsigned>, LatticeVal> TrackedMultipleRetVals;
+
+ /// MRVFunctionsTracked - Each function in TrackedMultipleRetVals is
+ /// represented here for efficient lookup.
+ SmallPtrSet<Function*, 16> MRVFunctionsTracked;
/// TrackingIncomingArguments - This is the set of functions for whose
/// arguments we make optimistic assumptions about and try to prove as
@@ -219,8 +228,8 @@
/// specified global variable if it can. This is only legal to call if
/// performing Interprocedural SCCP.
void TrackValueOfGlobalVariable(GlobalVariable *GV) {
- const Type *ElTy = GV->getType()->getElementType();
- if (ElTy->isFirstClassType()) {
+ // We only track the contents of scalar globals.
+ if (GV->getType()->getElementType()->isSingleValueType()) {
LatticeVal &IV = TrackedGlobals[GV];
if (!isa<UndefValue>(GV->getInitializer()))
IV.markConstant(GV->getInitializer());
@@ -233,6 +242,7 @@
void AddTrackedFunction(Function *F) {
// Add an entry, F -> undef.
if (const StructType *STy = dyn_cast<StructType>(F->getReturnType())) {
+ MRVFunctionsTracked.insert(F);
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
TrackedMultipleRetVals.insert(std::make_pair(std::make_pair(F, i),
LatticeVal()));
@@ -264,6 +274,13 @@
assert(I != ValueState.end() && "V is not in valuemap!");
return I->second;
}
+
+ LatticeVal getStructLatticeValueFor(Value *V, unsigned i) const {
+ DenseMap<std::pair<Value*, unsigned>, LatticeVal>::const_iterator I =
+ StructValueState.find(std::make_pair(V, i));
+ assert(I != StructValueState.end() && "V is not in valuemap!");
+ return I->second;
+ }
/// getTrackedRetVals - Get the inferred return value map.
///
@@ -278,9 +295,20 @@
}
void markOverdefined(Value *V) {
+ assert(!isa<StructType>(V->getType()) && "Should use other method");
markOverdefined(ValueState[V], V);
}
+ /// markAnythingOverdefined - Mark the specified value overdefined. This
+ /// works with both scalars and structs.
+ void markAnythingOverdefined(Value *V) {
+ if (const StructType *STy = dyn_cast<StructType>(V->getType()))
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
+ markOverdefined(getStructValueState(V, i), V);
+ else
+ markOverdefined(V);
+ }
+
private:
// markConstant - Make a value be marked as "constant". If the value
// is not already a constant, add it to the instruction work list so that
@@ -293,10 +321,12 @@
}
void markConstant(Value *V, Constant *C) {
+ assert(!isa<StructType>(V->getType()) && "Should use other method");
markConstant(ValueState[V], V, C);
}
void markForcedConstant(Value *V, Constant *C) {
+ assert(!isa<StructType>(V->getType()) && "Should use other method");
ValueState[V].markForcedConstant(C);
DEBUG(errs() << "markForcedConstant: " << *C << ": " << *V << '\n');
InstWorkList.push_back(V);
@@ -330,6 +360,7 @@
}
void mergeInValue(Value *V, LatticeVal MergeWithV) {
+ assert(!isa<StructType>(V->getType()) && "Should use other method");
mergeInValue(ValueState[V], V, MergeWithV);
}
@@ -338,8 +369,12 @@
/// value. This function handles the case when the value hasn't been seen yet
/// by properly seeding constants etc.
LatticeVal &getValueState(Value *V) {
+ assert(!isa<StructType>(V->getType()) && "Should use getStructValueState");
+
+ // TODO: Change to do insert+find in one operation.
DenseMap<Value*, LatticeVal>::iterator I = ValueState.find(V);
- if (I != ValueState.end()) return I->second; // Common case, in the map
+ if (I != ValueState.end())
+ return I->second; // Common case, already in the map.
LatticeVal &LV = ValueState[V];
@@ -353,6 +388,39 @@
return LV;
}
+ /// getStructValueState - Return the LatticeVal object that corresponds to the
+ /// value/field pair. This function handles the case when the value hasn't
+ /// been seen yet by properly seeding constants etc.
+ LatticeVal &getStructValueState(Value *V, unsigned i) {
+ assert(isa<StructType>(V->getType()) && "Should use getValueState");
+ assert(i < cast<StructType>(V->getType())->getNumElements() &&
+ "Invalid element #");
+
+ // TODO: Change to do insert+find in one operation.
+ DenseMap<std::pair<Value*, unsigned>, LatticeVal>::iterator
+ I = StructValueState.find(std::make_pair(V, i));
+ if (I != StructValueState.end())
+ return I->second; // Common case, already in the map.
+
+ LatticeVal &LV = StructValueState[std::make_pair(V, i)];
+
+ if (Constant *C = dyn_cast<Constant>(V)) {
+ if (isa<UndefValue>(C))
+ ; // Undef values remain undefined.
+ else if (ConstantStruct *CS = dyn_cast<ConstantStruct>(C))
+ LV.markConstant(CS->getOperand(i)); // Constants are constant.
+ else if (isa<ConstantAggregateZero>(C)) {
+ const Type *FieldTy = cast<StructType>(V->getType())->getElementType(i);
+ LV.markConstant(Constant::getNullValue(FieldTy));
+ } else
+ LV.markOverdefined(); // Unknown sort of constant.
+ }
+
+ // All others are underdefined by default.
+ return LV;
+ }
+
+
/// markEdgeExecutable - Mark a basic block as executable, adding it to the BB
/// work list if it is not already executable.
void markEdgeExecutable(BasicBlock *Source, BasicBlock *Dest) {
@@ -444,12 +512,12 @@
void visitUnreachableInst(TerminatorInst &I) { /*returns void*/ }
void visitAllocaInst (Instruction &I) { markOverdefined(&I); }
void visitVANextInst (Instruction &I) { markOverdefined(&I); }
- void visitVAArgInst (Instruction &I) { markOverdefined(&I); }
+ void visitVAArgInst (Instruction &I) { markAnythingOverdefined(&I); }
void visitInstruction(Instruction &I) {
// If a new instruction is added to LLVM that we don't handle.
errs() << "SCCP: Don't know how to handle: " << I;
- markOverdefined(&I); // Just in case
+ markAnythingOverdefined(&I); // Just in case
}
};
@@ -596,6 +664,11 @@
// successors executable.
//
void SCCPSolver::visitPHINode(PHINode &PN) {
+ // If this PN returns a struct, just mark the result overdefined.
+ // TODO: We could do a lot better than this if code actually uses this.
+ if (isa<StructType>(PN.getType()))
+ return markAnythingOverdefined(&PN);
+
if (getValueState(&PN).isOverdefined()) {
// There may be instructions using this PHI node that are not overdefined
// themselves. If so, make sure that they know that the PHI node operand
@@ -617,7 +690,7 @@
// and slow us down a lot. Just mark them overdefined.
if (PN.getNumIncomingValues() > 64)
return markOverdefined(&PN);
-
+
// Look at all of the executable operands of the PHI node. If any of them
// are overdefined, the PHI becomes overdefined as well. If they are all
// constant, and they agree with each other, the PHI becomes the identical
@@ -666,28 +739,26 @@
if (I.getNumOperands() == 0) return; // ret void
Function *F = I.getParent()->getParent();
+ Value *ResultOp = I.getOperand(0);
// If we are tracking the return value of this function, merge it in.
- if (!TrackedRetVals.empty()) {
+ if (!TrackedRetVals.empty() && !isa<StructType>(ResultOp->getType())) {
DenseMap<Function*, LatticeVal>::iterator TFRVI =
TrackedRetVals.find(F);
if (TFRVI != TrackedRetVals.end()) {
- mergeInValue(TFRVI->second, F, getValueState(I.getOperand(0)));
+ mergeInValue(TFRVI->second, F, getValueState(ResultOp));
return;
}
}
// Handle functions that return multiple values.
- if (!TrackedMultipleRetVals.empty() &&
- isa<StructType>(I.getOperand(0)->getType())) {
- for (unsigned i = 0, e = I.getOperand(0)->getType()->getNumContainedTypes();
- i != e; ++i) {
- DenseMap<std::pair<Function*, unsigned>, LatticeVal>::iterator
- It = TrackedMultipleRetVals.find(std::make_pair(F, i));
- if (It == TrackedMultipleRetVals.end()) break;
- if (Value *Val = FindInsertedValue(I.getOperand(0), i, I.getContext()))
- mergeInValue(It->second, F, getValueState(Val));
- }
+ if (!TrackedMultipleRetVals.empty()) {
+ if (const StructType *STy = dyn_cast<StructType>(ResultOp->getType()))
+ if (MRVFunctionsTracked.count(F))
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
+ mergeInValue(TrackedMultipleRetVals[std::make_pair(F, i)], F,
+ getStructValueState(ResultOp, i));
+
}
}
@@ -712,78 +783,62 @@
OpSt.getConstant(), I.getType()));
}
-void SCCPSolver::visitExtractValueInst(ExtractValueInst &EVI) {
- Value *Aggr = EVI.getAggregateOperand();
-
- // If the operand to the extractvalue is an undef, the result is undef.
- if (isa<UndefValue>(Aggr))
- return;
- // Currently only handle single-index extractvalues.
+void SCCPSolver::visitExtractValueInst(ExtractValueInst &EVI) {
+ // If this returns a struct, mark all elements over defined, we don't track
+ // structs in structs.
+ if (isa<StructType>(EVI.getType()))
+ return markAnythingOverdefined(&EVI);
+
+ // If this is extracting from more than one level of struct, we don't know.
if (EVI.getNumIndices() != 1)
return markOverdefined(&EVI);
-
- Function *F = 0;
- if (CallInst *CI = dyn_cast<CallInst>(Aggr))
- F = CI->getCalledFunction();
- else if (InvokeInst *II = dyn_cast<InvokeInst>(Aggr))
- F = II->getCalledFunction();
-
- // TODO: If IPSCCP resolves the callee of this function, we could propagate a
- // result back!
- if (F == 0 || TrackedMultipleRetVals.empty())
- return markOverdefined(&EVI);
-
- // See if we are tracking the result of the callee. If not tracking this
- // function (for example, it is a declaration) just move to overdefined.
- if (!TrackedMultipleRetVals.count(std::make_pair(F, *EVI.idx_begin())))
- return markOverdefined(&EVI);
-
- // Otherwise, the value will be merged in here as a result of CallSite
- // handling.
+
+ Value *AggVal = EVI.getAggregateOperand();
+ unsigned i = *EVI.idx_begin();
+ LatticeVal EltVal = getStructValueState(AggVal, i);
+ mergeInValue(getValueState(&EVI), &EVI, EltVal);
}
void SCCPSolver::visitInsertValueInst(InsertValueInst &IVI) {
- Value *Aggr = IVI.getAggregateOperand();
- Value *Val = IVI.getInsertedValueOperand();
-
- // If the operands to the insertvalue are undef, the result is undef.
- if (isa<UndefValue>(Aggr) && isa<UndefValue>(Val))
- return;
-
- // Currently only handle single-index insertvalues.
- if (IVI.getNumIndices() != 1)
+ const StructType *STy = dyn_cast<StructType>(IVI.getType());
+ if (STy == 0)
return markOverdefined(&IVI);
-
- // Currently only handle insertvalue instructions that are in a single-use
- // chain that builds up a return value.
- for (const InsertValueInst *TmpIVI = &IVI; ; ) {
- if (!TmpIVI->hasOneUse())
- return markOverdefined(&IVI);
-
- const Value *V = *TmpIVI->use_begin();
- if (isa<ReturnInst>(V))
- break;
- TmpIVI = dyn_cast<InsertValueInst>(V);
- if (!TmpIVI)
- return markOverdefined(&IVI);
- }
-
- // See if we are tracking the result of the callee.
- Function *F = IVI.getParent()->getParent();
- DenseMap<std::pair<Function*, unsigned>, LatticeVal>::iterator
- It = TrackedMultipleRetVals.find(std::make_pair(F, *IVI.idx_begin()));
-
- // Merge in the inserted member value.
- if (It != TrackedMultipleRetVals.end())
- mergeInValue(It->second, F, getValueState(Val));
-
- // Mark the aggregate result of the IVI overdefined; any tracking that we do
- // will be done on the individual member values.
- markOverdefined(&IVI);
+
+ // If this has more than one index, we can't handle it, drive all results to
+ // undef.
+ if (IVI.getNumIndices() != 1)
+ return markAnythingOverdefined(&IVI);
+
+ Value *Aggr = IVI.getAggregateOperand();
+ unsigned Idx = *IVI.idx_begin();
+
+ // Compute the result based on what we're inserting.
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+ // This passes through all values that aren't the inserted element.
+ if (i != Idx) {
+ LatticeVal EltVal = getStructValueState(Aggr, i);
+ mergeInValue(getStructValueState(&IVI, i), &IVI, EltVal);
+ continue;
+ }
+
+ Value *Val = IVI.getInsertedValueOperand();
+ if (isa<StructType>(Val->getType()))
+ // We don't track structs in structs.
+ markOverdefined(getStructValueState(&IVI, i), &IVI);
+ else {
+ LatticeVal InVal = getValueState(Val);
+ mergeInValue(getStructValueState(&IVI, i), &IVI, InVal);
+ }
+ }
}
void SCCPSolver::visitSelectInst(SelectInst &I) {
+ // If this select returns a struct, just mark the result overdefined.
+ // TODO: We could do a lot better than this if code actually uses this.
+ if (isa<StructType>(I.getType()))
+ return markAnythingOverdefined(&I);
+
LatticeVal CondValue = getValueState(I.getCondition());
if (CondValue.isUndefined())
return;
@@ -1011,7 +1066,7 @@
}
void SCCPSolver::visitExtractElementInst(ExtractElementInst &I) {
- // FIXME : SCCP does not handle vectors properly.
+ // TODO : SCCP does not handle vectors properly.
return markOverdefined(&I);
#if 0
@@ -1027,7 +1082,7 @@
}
void SCCPSolver::visitInsertElementInst(InsertElementInst &I) {
- // FIXME : SCCP does not handle vectors properly.
+ // TODO : SCCP does not handle vectors properly.
return markOverdefined(&I);
#if 0
LatticeVal &ValState = getValueState(I.getOperand(0));
@@ -1051,7 +1106,7 @@
}
void SCCPSolver::visitShuffleVectorInst(ShuffleVectorInst &I) {
- // FIXME : SCCP does not handle vectors properly.
+ // TODO : SCCP does not handle vectors properly.
return markOverdefined(&I);
#if 0
LatticeVal &V1State = getValueState(I.getOperand(0));
@@ -1105,6 +1160,10 @@
}
void SCCPSolver::visitStoreInst(StoreInst &SI) {
+ // If this store is of a struct, ignore it.
+ if (isa<StructType>(SI.getOperand(0)->getType()))
+ return;
+
if (TrackedGlobals.empty() || !isa<GlobalVariable>(SI.getOperand(1)))
return;
@@ -1122,6 +1181,10 @@
// Handle load instructions. If the operand is a constant pointer to a constant
// global, we can replace the load with the loaded constant value!
void SCCPSolver::visitLoadInst(LoadInst &I) {
+ // If this load is of a struct, just mark the result overdefined.
+ if (isa<StructType>(I.getType()))
+ return markAnythingOverdefined(&I);
+
LatticeVal PtrVal = getValueState(I.getOperand(0));
if (PtrVal.isUndefined()) return; // The pointer is not resolved yet!
@@ -1196,7 +1259,7 @@
}
// Otherwise, we don't know anything about this call, mark it overdefined.
- return markOverdefined(I);
+ return markAnythingOverdefined(I);
}
// If this is a local function that doesn't have its address taken, mark its
@@ -1216,47 +1279,33 @@
continue;
}
- mergeInValue(AI, getValueState(*CAI));
+ if (const StructType *STy = dyn_cast<StructType>(AI->getType())) {
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
+ mergeInValue(getStructValueState(AI, i), AI,
+ getStructValueState(*CAI, i));
+ } else {
+ mergeInValue(AI, getValueState(*CAI));
+ }
}
}
// If this is a single/zero retval case, see if we're tracking the function.
- DenseMap<Function*, LatticeVal>::iterator TFRVI = TrackedRetVals.find(F);
- if (TFRVI != TrackedRetVals.end()) {
+ if (const StructType *STy = dyn_cast<StructType>(F->getReturnType())) {
+ if (!MRVFunctionsTracked.count(F))
+ goto CallOverdefined; // Not tracking this callee.
+
+ // If we are tracking this callee, propagate the result of the function
+ // into this call site.
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
+ mergeInValue(getStructValueState(I, i), I,
+ TrackedMultipleRetVals[std::make_pair(F, i)]);
+ } else {
+ DenseMap<Function*, LatticeVal>::iterator TFRVI = TrackedRetVals.find(F);
+ if (TFRVI == TrackedRetVals.end())
+ goto CallOverdefined; // Not tracking this callee.
+
// If so, propagate the return value of the callee into this call result.
mergeInValue(I, TFRVI->second);
- } else if (isa<StructType>(I->getType())) {
- // Check to see if we're tracking this callee, if not, handle it in the
- // common path above.
- DenseMap<std::pair<Function*, unsigned>, LatticeVal>::iterator
- TMRVI = TrackedMultipleRetVals.find(std::make_pair(F, 0));
- if (TMRVI == TrackedMultipleRetVals.end())
- goto CallOverdefined;
-
- // Need to mark as overdefined, otherwise it stays undefined which
- // creates extractvalue undef, <idx>
- markOverdefined(I);
-
- // If we are tracking this callee, propagate the return values of the call
- // into this call site. We do this by walking all the uses. Single-index
- // ExtractValueInst uses can be tracked; anything more complicated is
- // currently handled conservatively.
- for (Value::use_iterator UI = I->use_begin(), E = I->use_end();
- UI != E; ++UI) {
- if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(*UI)) {
- if (EVI->getNumIndices() == 1) {
- mergeInValue(EVI,
- TrackedMultipleRetVals[std::make_pair(F, *EVI->idx_begin())]);
- continue;
- }
- }
- // The aggregate value is used in a way not handled here. Assume nothing.
- markOverdefined(*UI);
- }
- } else {
- // Otherwise we're not tracking this callee, so handle it in the
- // common path above.
- goto CallOverdefined;
}
}
@@ -1297,7 +1346,7 @@
// since all of its users will have already been marked as overdefined.
// Update all of the users of this instruction's value.
//
- if (!getValueState(I).isOverdefined())
+ if (isa<StructType>(I->getType()) || !getValueState(I).isOverdefined())
for (Value::use_iterator UI = I->use_begin(), E = I->use_end();
UI != E; ++UI)
if (Instruction *I = dyn_cast<Instruction>(*UI))
@@ -1345,13 +1394,35 @@
// Look for instructions which produce undef values.
if (I->getType()->isVoidTy()) continue;
+ if (const StructType *STy = dyn_cast<StructType>(I->getType())) {
+ // Only a few things that can be structs matter for undef. Just send
+ // all their results to overdefined. We could be more precise than this
+ // but it isn't worth bothering.
+ if (isa<CallInst>(I) || isa<SelectInst>(I)) {
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+ LatticeVal &LV = getStructValueState(I, i);
+ if (LV.isUndefined())
+ markOverdefined(LV, I);
+ }
+ }
+ continue;
+ }
+
LatticeVal &LV = getValueState(I);
if (!LV.isUndefined()) continue;
+ // No instructions using structs need disambiguation.
+ if (isa<StructType>(I->getOperand(0)->getType()))
+ continue;
+
// Get the lattice values of the first two operands for use below.
LatticeVal Op0LV = getValueState(I->getOperand(0));
LatticeVal Op1LV;
if (I->getNumOperands() == 2) {
+ // No instructions using structs need disambiguation.
+ if (isa<StructType>(I->getOperand(1)->getType()))
+ continue;
+
// If this is a two-operand instruction, and if both operands are
// undefs, the result stays undef.
Op1LV = getValueState(I->getOperand(1));
@@ -1547,7 +1618,7 @@
// Mark all arguments to the function as being overdefined.
for (Function::arg_iterator AI = F.arg_begin(), E = F.arg_end(); AI != E;++AI)
- Solver.markOverdefined(AI);
+ Solver.markAnythingOverdefined(AI);
// Solve for constants.
bool ResolvedUndefs = true;
@@ -1578,6 +1649,10 @@
if (Inst->getType()->isVoidTy() || isa<TerminatorInst>(Inst))
continue;
+ // TODO: Reconstruct structs from their elements.
+ if (isa<StructType>(Inst->getType()))
+ continue;
+
LatticeVal IV = Solver.getLatticeValueFor(Inst);
if (IV.isOverdefined())
continue;
@@ -1661,8 +1736,7 @@
// If this is a strong or ODR definition of this function, then we can
// propagate information about its result into callsites of it.
- if (!F->mayBeOverridden() &&
- !isa<StructType>(F->getReturnType()))
+ if (!F->mayBeOverridden())
Solver.AddTrackedFunction(F);
// If this function only has direct calls that we can see, we can track its
@@ -1679,7 +1753,7 @@
// Assume nothing about the incoming arguments.
for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end();
AI != E; ++AI)
- Solver.markOverdefined(AI);
+ Solver.markAnythingOverdefined(AI);
}
// Loop over global variables. We inform the solver about any internal global
@@ -1712,8 +1786,11 @@
if (Solver.isBlockExecutable(F->begin())) {
for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end();
AI != E; ++AI) {
- if (AI->use_empty()) continue;
+ if (AI->use_empty() || isa<StructType>(AI->getType())) continue;
+ // TODO: Could use getStructLatticeValueFor to find out if the entire
+ // result is a constant and replace it entirely if so.
+
LatticeVal IV = Solver.getLatticeValueFor(AI);
if (IV.isOverdefined()) continue;
@@ -1752,9 +1829,12 @@
for (BasicBlock::iterator BI = BB->begin(), E = BB->end(); BI != E; ) {
Instruction *Inst = BI++;
- if (Inst->getType()->isVoidTy())
+ if (Inst->getType()->isVoidTy() || isa<StructType>(Inst->getType()))
continue;
+ // TODO: Could use getStructLatticeValueFor to find out if the entire
+ // result is a constant and replace it entirely if so.
+
LatticeVal IV = Solver.getLatticeValueFor(Inst);
if (IV.isOverdefined())
continue;
Modified: llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll?rev=85973&r1=85972&r2=85973&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll (original)
+++ llvm/trunk/test/Transforms/SCCP/ipsccp-basic.ll Tue Nov 3 17:40:48 2009
@@ -1,5 +1,4 @@
; RUN: opt < %s -ipsccp -S | FileCheck %s
-; XFAIL: *
;;======================== test1
@@ -128,7 +127,7 @@
; CHECK: define i64 @test5b()
; CHECK: A:
; CHECK-NEXT: %c = call i64 @test5c(%0 %a)
-; CHECK-NEXT: ret i64 %c
+; CHECK-NEXT: ret i64 5
define internal i64 @test5c({i64,i64} %a) {
%b = extractvalue {i64,i64} %a, 0
More information about the llvm-commits
mailing list