[llvm] r222039 - Reapply r221924: "[GVN] Perform Scalar PRE on gep indices that feed loads before
Chad Rosier
mcrosier at codeaurora.org
Tue Nov 18 14:53:34 PST 2014
Hi Manman,
Feel free to revert the patch if you're convinced this is the problem.
Please keep Balaram, James, and I updated on the progress. This is a
performance critical fix, so we need to make sure it doesn't get lost in
the mix.
Chad
> Hi Chad,
>
> About the buildbot phase 2 failure, I now think this commit is the root
> cause.
>
> What I did was:
> 1> update the repo to r222239, then "svn merge -c -r222039 .â, made a
> release+assert build (installed to clang-install).
> 2> use clang-install binary and library to build the same repo with lto.
> make -j 4 VERBOSE=1 CLANG_REPOSITORY_STRING=clang-Rlto_master_build
> SVN_REVISION=222059
> DYLD_LIBRARY_PATH=/Users/manmanren/llvm_gmail/clang-install/lib/
> 3> the build completed
> make[1]: Nothing to be done for `all'.
> make[1]: Nothing to be done for `all'.
> llvm[0]: ***** Completed Release Build
>
> Is it okay for us to revert this commit and watch the bot? If the bot is
> still red, we can re-submit it.
>
> If you want me to do more testing (maybe a lto self host with r22239), let
> me know,
>
> Thanks,
> Manman (The build czar)
>
>> On Nov 14, 2014, at 1:09 PM, Chad Rosier <mcrosier at codeaurora.org>
>> wrote:
>>
>> Author: mcrosier
>> Date: Fri Nov 14 15:09:13 2014
>> New Revision: 222039
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=222039&view=rev
>> Log:
>> Reapply r221924: "[GVN] Perform Scalar PRE on gep indices that feed
>> loads before
>> doing Load PRE"
>>
>> This commit updates the failing test in
>> Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll
>>
>> The failing test is sensitive to the order in which we process loads.
>> This
>> version turns on the RPO traversal instead of the while DT traversal in
>> GVN.
>> The new test code is functionally same just the order of loads that are
>> eliminated is swapped.
>>
>> This new version also fixes an issue where GVN splits a critical edge
>> and
>> potentially invalidate the RPO/DT iterator.
>>
>> Added:
>> llvm/trunk/test/Transforms/GVN/pre-gep-load.ll
>> Modified:
>> llvm/trunk/lib/Transforms/Scalar/GVN.cpp
>> llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll
>>
>> Modified: llvm/trunk/lib/Transforms/Scalar/GVN.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/GVN.cpp?rev=222039&r1=222038&r2=222039&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/Transforms/Scalar/GVN.cpp (original)
>> +++ llvm/trunk/lib/Transforms/Scalar/GVN.cpp Fri Nov 14 15:09:13 2014
>> @@ -20,6 +20,7 @@
>> #include "llvm/ADT/DepthFirstIterator.h"
>> #include "llvm/ADT/Hashing.h"
>> #include "llvm/ADT/MapVector.h"
>> +#include "llvm/ADT/PostOrderIterator.h"
>> #include "llvm/ADT/SetVector.h"
>> #include "llvm/ADT/SmallPtrSet.h"
>> #include "llvm/ADT/Statistic.h"
>> @@ -709,6 +710,7 @@ namespace {
>> void dump(DenseMap<uint32_t, Value*> &d);
>> bool iterateOnFunction(Function &F);
>> bool performPRE(Function &F);
>> + bool performScalarPRE(Instruction *I);
>> Value *findLeader(const BasicBlock *BB, uint32_t num);
>> void cleanupGlobalSets();
>> void verifyRemoved(const Instruction *I) const;
>> @@ -1729,6 +1731,15 @@ bool GVN::processNonLocalLoad(LoadInst *
>> return false;
>> }
>>
>> + // If this load follows a GEP, see if we can PRE the indices before
>> analyzing.
>> + if (GetElementPtrInst *GEP =
>> dyn_cast<GetElementPtrInst>(LI->getOperand(0))) {
>> + for (GetElementPtrInst::op_iterator OI = GEP->idx_begin(),
>> + OE = GEP->idx_end();
>> + OI != OE; ++OI)
>> + if (Instruction *I = dyn_cast<Instruction>(OI->get()))
>> + performScalarPRE(I);
>> + }
>> +
>> // Step 2: Analyze the availability of the load
>> AvailValInBlkVect ValuesPerBlock;
>> UnavailBlkVect UnavailableBlocks;
>> @@ -2431,175 +2442,182 @@ bool GVN::processBlock(BasicBlock *BB) {
>> return ChangedFunction;
>> }
>>
>> -/// performPRE - Perform a purely local form of PRE that looks for
>> diamond
>> -/// control flow patterns and attempts to perform simple PRE at the
>> join point.
>> -bool GVN::performPRE(Function &F) {
>> - bool Changed = false;
>> +bool GVN::performScalarPRE(Instruction *CurInst) {
>> SmallVector<std::pair<Value*, BasicBlock*>, 8> predMap;
>> - for (BasicBlock *CurrentBlock : depth_first(&F.getEntryBlock())) {
>> - // Nothing to PRE in the entry block.
>> - if (CurrentBlock == &F.getEntryBlock()) continue;
>>
>> - // Don't perform PRE on a landing pad.
>> - if (CurrentBlock->isLandingPad()) continue;
>> + if (isa<AllocaInst>(CurInst) || isa<TerminatorInst>(CurInst) ||
>> + isa<PHINode>(CurInst) || CurInst->getType()->isVoidTy() ||
>> + CurInst->mayReadFromMemory() || CurInst->mayHaveSideEffects() ||
>> + isa<DbgInfoIntrinsic>(CurInst))
>> + return false;
>>
>> - for (BasicBlock::iterator BI = CurrentBlock->begin(),
>> - BE = CurrentBlock->end(); BI != BE; ) {
>> - Instruction *CurInst = BI++;
>> + // Don't do PRE on compares. The PHI would prevent CodeGenPrepare
>> from
>> + // sinking the compare again, and it would force the code generator
>> to
>> + // move the i1 from processor flags or predicate registers into a
>> general
>> + // purpose register.
>> + if (isa<CmpInst>(CurInst))
>> + return false;
>>
>> - if (isa<AllocaInst>(CurInst) ||
>> - isa<TerminatorInst>(CurInst) || isa<PHINode>(CurInst) ||
>> - CurInst->getType()->isVoidTy() ||
>> - CurInst->mayReadFromMemory() || CurInst->mayHaveSideEffects()
>> ||
>> - isa<DbgInfoIntrinsic>(CurInst))
>> - continue;
>> + // We don't currently value number ANY inline asm calls.
>> + if (CallInst *CallI = dyn_cast<CallInst>(CurInst))
>> + if (CallI->isInlineAsm())
>> + return false;
>>
>> - // Don't do PRE on compares. The PHI would prevent CodeGenPrepare
>> from
>> - // sinking the compare again, and it would force the code
>> generator to
>> - // move the i1 from processor flags or predicate registers into a
>> general
>> - // purpose register.
>> - if (isa<CmpInst>(CurInst))
>> - continue;
>> + uint32_t ValNo = VN.lookup(CurInst);
>>
>> - // We don't currently value number ANY inline asm calls.
>> - if (CallInst *CallI = dyn_cast<CallInst>(CurInst))
>> - if (CallI->isInlineAsm())
>> - continue;
>> + // Look for the predecessors for PRE opportunities. We're
>> + // only trying to solve the basic diamond case, where
>> + // a value is computed in the successor and one predecessor,
>> + // but not the other. We also explicitly disallow cases
>> + // where the successor is its own predecessor, because they're
>> + // more complicated to get right.
>> + unsigned NumWith = 0;
>> + unsigned NumWithout = 0;
>> + BasicBlock *PREPred = nullptr;
>> + BasicBlock *CurrentBlock = CurInst->getParent();
>> + predMap.clear();
>> +
>> + for (pred_iterator PI = pred_begin(CurrentBlock), PE =
>> pred_end(CurrentBlock);
>> + PI != PE; ++PI) {
>> + BasicBlock *P = *PI;
>> + // We're not interested in PRE where the block is its
>> + // own predecessor, or in blocks with predecessors
>> + // that are not reachable.
>> + if (P == CurrentBlock) {
>> + NumWithout = 2;
>> + break;
>> + } else if (!DT->isReachableFromEntry(P)) {
>> + NumWithout = 2;
>> + break;
>> + }
>>
>> - uint32_t ValNo = VN.lookup(CurInst);
>> + Value *predV = findLeader(P, ValNo);
>> + if (!predV) {
>> + predMap.push_back(std::make_pair(static_cast<Value *>(nullptr),
>> P));
>> + PREPred = P;
>> + ++NumWithout;
>> + } else if (predV == CurInst) {
>> + /* CurInst dominates this predecessor. */
>> + NumWithout = 2;
>> + break;
>> + } else {
>> + predMap.push_back(std::make_pair(predV, P));
>> + ++NumWith;
>> + }
>> + }
>>
>> - // Look for the predecessors for PRE opportunities. We're
>> - // only trying to solve the basic diamond case, where
>> - // a value is computed in the successor and one predecessor,
>> - // but not the other. We also explicitly disallow cases
>> - // where the successor is its own predecessor, because they're
>> - // more complicated to get right.
>> - unsigned NumWith = 0;
>> - unsigned NumWithout = 0;
>> - BasicBlock *PREPred = nullptr;
>> - predMap.clear();
>> -
>> - for (pred_iterator PI = pred_begin(CurrentBlock),
>> - PE = pred_end(CurrentBlock); PI != PE; ++PI) {
>> - BasicBlock *P = *PI;
>> - // We're not interested in PRE where the block is its
>> - // own predecessor, or in blocks with predecessors
>> - // that are not reachable.
>> - if (P == CurrentBlock) {
>> - NumWithout = 2;
>> - break;
>> - } else if (!DT->isReachableFromEntry(P)) {
>> - NumWithout = 2;
>> - break;
>> - }
>> + // Don't do PRE when it might increase code size, i.e. when
>> + // we would need to insert instructions in more than one pred.
>> + if (NumWithout != 1 || NumWith == 0)
>> + return false;
>>
>> - Value* predV = findLeader(P, ValNo);
>> - if (!predV) {
>> - predMap.push_back(std::make_pair(static_cast<Value
>> *>(nullptr), P));
>> - PREPred = P;
>> - ++NumWithout;
>> - } else if (predV == CurInst) {
>> - /* CurInst dominates this predecessor. */
>> - NumWithout = 2;
>> - break;
>> - } else {
>> - predMap.push_back(std::make_pair(predV, P));
>> - ++NumWith;
>> - }
>> - }
>> + // Don't do PRE across indirect branch.
>> + if (isa<IndirectBrInst>(PREPred->getTerminator()))
>> + return false;
>>
>> - // Don't do PRE when it might increase code size, i.e. when
>> - // we would need to insert instructions in more than one pred.
>> - if (NumWithout != 1 || NumWith == 0)
>> - continue;
>> + // We can't do PRE safely on a critical edge, so instead we schedule
>> + // the edge to be split and perform the PRE the next time we iterate
>> + // on the function.
>> + unsigned SuccNum = GetSuccessorNumber(PREPred, CurrentBlock);
>> + if (isCriticalEdge(PREPred->getTerminator(), SuccNum)) {
>> + toSplit.push_back(std::make_pair(PREPred->getTerminator(),
>> SuccNum));
>> + return false;
>> + }
>>
>> - // Don't do PRE across indirect branch.
>> - if (isa<IndirectBrInst>(PREPred->getTerminator()))
>> - continue;
>> + // Instantiate the expression in the predecessor that lacked it.
>> + // Because we are going top-down through the block, all value numbers
>> + // will be available in the predecessor by the time we need them.
>> Any
>> + // that weren't originally present will have been instantiated
>> earlier
>> + // in this loop.
>> + Instruction *PREInstr = CurInst->clone();
>> + bool success = true;
>> + for (unsigned i = 0, e = CurInst->getNumOperands(); i != e; ++i) {
>> + Value *Op = PREInstr->getOperand(i);
>> + if (isa<Argument>(Op) || isa<Constant>(Op) || isa<GlobalValue>(Op))
>> + continue;
>>
>> - // We can't do PRE safely on a critical edge, so instead we
>> schedule
>> - // the edge to be split and perform the PRE the next time we
>> iterate
>> - // on the function.
>> - unsigned SuccNum = GetSuccessorNumber(PREPred, CurrentBlock);
>> - if (isCriticalEdge(PREPred->getTerminator(), SuccNum)) {
>> - toSplit.push_back(std::make_pair(PREPred->getTerminator(),
>> SuccNum));
>> - continue;
>> - }
>> + if (Value *V = findLeader(PREPred, VN.lookup(Op))) {
>> + PREInstr->setOperand(i, V);
>> + } else {
>> + success = false;
>> + break;
>> + }
>> + }
>>
>> - // Instantiate the expression in the predecessor that lacked it.
>> - // Because we are going top-down through the block, all value
>> numbers
>> - // will be available in the predecessor by the time we need them.
>> Any
>> - // that weren't originally present will have been instantiated
>> earlier
>> - // in this loop.
>> - Instruction *PREInstr = CurInst->clone();
>> - bool success = true;
>> - for (unsigned i = 0, e = CurInst->getNumOperands(); i != e; ++i)
>> {
>> - Value *Op = PREInstr->getOperand(i);
>> - if (isa<Argument>(Op) || isa<Constant>(Op) ||
>> isa<GlobalValue>(Op))
>> - continue;
>> + // Fail out if we encounter an operand that is not available in
>> + // the PRE predecessor. This is typically because of loads which
>> + // are not value numbered precisely.
>> + if (!success) {
>> + DEBUG(verifyRemoved(PREInstr));
>> + delete PREInstr;
>> + return false;
>> + }
>>
>> - if (Value *V = findLeader(PREPred, VN.lookup(Op))) {
>> - PREInstr->setOperand(i, V);
>> - } else {
>> - success = false;
>> - break;
>> - }
>> - }
>> + PREInstr->insertBefore(PREPred->getTerminator());
>> + PREInstr->setName(CurInst->getName() + ".pre");
>> + PREInstr->setDebugLoc(CurInst->getDebugLoc());
>> + VN.add(PREInstr, ValNo);
>> + ++NumGVNPRE;
>> +
>> + // Update the availability map to include the new instruction.
>> + addToLeaderTable(ValNo, PREInstr, PREPred);
>> +
>> + // Create a PHI to make the value available in this block.
>> + PHINode *Phi =
>> + PHINode::Create(CurInst->getType(), predMap.size(),
>> + CurInst->getName() + ".pre-phi",
>> CurrentBlock->begin());
>> + for (unsigned i = 0, e = predMap.size(); i != e; ++i) {
>> + if (Value *V = predMap[i].first)
>> + Phi->addIncoming(V, predMap[i].second);
>> + else
>> + Phi->addIncoming(PREInstr, PREPred);
>> + }
>>
>> - // Fail out if we encounter an operand that is not available in
>> - // the PRE predecessor. This is typically because of loads which
>> - // are not value numbered precisely.
>> - if (!success) {
>> - DEBUG(verifyRemoved(PREInstr));
>> - delete PREInstr;
>> - continue;
>> - }
>> + VN.add(Phi, ValNo);
>> + addToLeaderTable(ValNo, Phi, CurrentBlock);
>> + Phi->setDebugLoc(CurInst->getDebugLoc());
>> + CurInst->replaceAllUsesWith(Phi);
>> + if (Phi->getType()->getScalarType()->isPointerTy()) {
>> + // Because we have added a PHI-use of the pointer value, it has now
>> + // "escaped" from alias analysis' perspective. We need to inform
>> + // AA of this.
>> + for (unsigned ii = 0, ee = Phi->getNumIncomingValues(); ii != ee;
>> ++ii) {
>> + unsigned jj = PHINode::getOperandNumForIncomingValue(ii);
>> + VN.getAliasAnalysis()->addEscapingUse(Phi->getOperandUse(jj));
>> + }
>>
>> - PREInstr->insertBefore(PREPred->getTerminator());
>> - PREInstr->setName(CurInst->getName() + ".pre");
>> - PREInstr->setDebugLoc(CurInst->getDebugLoc());
>> - VN.add(PREInstr, ValNo);
>> - ++NumGVNPRE;
>> -
>> - // Update the availability map to include the new instruction.
>> - addToLeaderTable(ValNo, PREInstr, PREPred);
>> -
>> - // Create a PHI to make the value available in this block.
>> - PHINode* Phi = PHINode::Create(CurInst->getType(),
>> predMap.size(),
>> - CurInst->getName() + ".pre-phi",
>> - CurrentBlock->begin());
>> - for (unsigned i = 0, e = predMap.size(); i != e; ++i) {
>> - if (Value *V = predMap[i].first)
>> - Phi->addIncoming(V, predMap[i].second);
>> - else
>> - Phi->addIncoming(PREInstr, PREPred);
>> - }
>> -
>> - VN.add(Phi, ValNo);
>> - addToLeaderTable(ValNo, Phi, CurrentBlock);
>> - Phi->setDebugLoc(CurInst->getDebugLoc());
>> - CurInst->replaceAllUsesWith(Phi);
>> - if (Phi->getType()->getScalarType()->isPointerTy()) {
>> - // Because we have added a PHI-use of the pointer value, it has
>> now
>> - // "escaped" from alias analysis' perspective. We need to
>> inform
>> - // AA of this.
>> - for (unsigned ii = 0, ee = Phi->getNumIncomingValues(); ii !=
>> ee;
>> - ++ii) {
>> - unsigned jj = PHINode::getOperandNumForIncomingValue(ii);
>> -
>> VN.getAliasAnalysis()->addEscapingUse(Phi->getOperandUse(jj));
>> - }
>> + if (MD)
>> + MD->invalidateCachedPointerInfo(Phi);
>> + }
>> + VN.erase(CurInst);
>> + removeFromLeaderTable(ValNo, CurInst, CurrentBlock);
>>
>> - if (MD)
>> - MD->invalidateCachedPointerInfo(Phi);
>> - }
>> - VN.erase(CurInst);
>> - removeFromLeaderTable(ValNo, CurInst, CurrentBlock);
>> + DEBUG(dbgs() << "GVN PRE removed: " << *CurInst << '\n');
>> + if (MD)
>> + MD->removeInstruction(CurInst);
>> + DEBUG(verifyRemoved(CurInst));
>> + CurInst->eraseFromParent();
>> + return true;
>> +}
>> +
>> +/// performPRE - Perform a purely local form of PRE that looks for
>> diamond
>> +/// control flow patterns and attempts to perform simple PRE at the
>> join point.
>> +bool GVN::performPRE(Function &F) {
>> + bool Changed = false;
>> + for (BasicBlock *CurrentBlock : depth_first(&F.getEntryBlock())) {
>> + // Nothing to PRE in the entry block.
>> + if (CurrentBlock == &F.getEntryBlock())
>> + continue;
>>
>> - DEBUG(dbgs() << "GVN PRE removed: " << *CurInst << '\n');
>> - if (MD) MD->removeInstruction(CurInst);
>> - DEBUG(verifyRemoved(CurInst));
>> - CurInst->eraseFromParent();
>> - Changed = true;
>> + // Don't perform PRE on a landing pad.
>> + if (CurrentBlock->isLandingPad())
>> + continue;
>> +
>> + for (BasicBlock::iterator BI = CurrentBlock->begin(),
>> + BE = CurrentBlock->end();
>> + BI != BE;) {
>> + Instruction *CurInst = BI++;
>> + Changed = performScalarPRE(CurInst);
>> }
>> }
>>
>> @@ -2637,25 +2655,21 @@ bool GVN::iterateOnFunction(Function &F)
>>
>> // Top-down walk of the dominator tree
>> bool Changed = false;
>> -#if 0
>> - // Needed for value numbering with phi construction to work.
>> - ReversePostOrderTraversal<Function*> RPOT(&F);
>> - for (ReversePostOrderTraversal<Function*>::rpo_iterator RI =
>> RPOT.begin(),
>> - RE = RPOT.end(); RI != RE; ++RI)
>> - Changed |= processBlock(*RI);
>> -#else
>> // Save the blocks this function have before transformation begins.
>> GVN may
>> // split critical edge, and hence may invalidate the RPO/DT iterator.
>> //
>> std::vector<BasicBlock *> BBVect;
>> BBVect.reserve(256);
>> - for (DomTreeNode *X : depth_first(DT->getRootNode()))
>> - BBVect.push_back(X->getBlock());
>> + // Needed for value numbering with phi construction to work.
>> + ReversePostOrderTraversal<Function *> RPOT(&F);
>> + for (ReversePostOrderTraversal<Function *>::rpo_iterator RI =
>> RPOT.begin(),
>> + RE =
>> RPOT.end();
>> + RI != RE; ++RI)
>> + BBVect.push_back(*RI);
>>
>> for (std::vector<BasicBlock *>::iterator I = BBVect.begin(), E =
>> BBVect.end();
>> I != E; I++)
>> Changed |= processBlock(*I);
>> -#endif
>>
>> return Changed;
>> }
>>
>> Modified:
>> llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll?rev=222039&r1=222038&r2=222039&view=diff
>> ==============================================================================
>> ---
>> llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll
>> (original)
>> +++
>> llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll
>> Fri Nov 14 15:09:13 2014
>> @@ -46,12 +46,12 @@ entry:
>> br i1 %c, label %if.else, label %if.then
>>
>> if.then:
>> - %t = load i32* %p, !tbaa !4
>> + %t = load i32* %p, !tbaa !3
>> store i32 %t, i32* %q
>> ret void
>>
>> if.else:
>> - %u = load i32* %p, !tbaa !3
>> + %u = load i32* %p, !tbaa !4
>> store i32 %u, i32* %q
>> ret void
>> }
>> @@ -61,11 +61,11 @@ if.else:
>>
>> ; CHECK: @watch_out_for_another_type_change
>> ; CHECK: if.then:
>> -; CHECK: %t = load i32* %p
>> -; CHECK: store i32 %t, i32* %q
>> +; CHECK: store i32 0, i32* %q
>> ; CHECK: ret void
>> ; CHECK: if.else:
>> -; CHECK: store i32 0, i32* %q
>> +; CHECK: %u = load i32* %p
>> +; CHECK: store i32 %u, i32* %q
>>
>> define void @watch_out_for_another_type_change(i1 %c, i32* %p, i32* %p1,
>> i32* %q) nounwind {
>> entry:
>> @@ -74,12 +74,12 @@ entry:
>> br i1 %c, label %if.else, label %if.then
>>
>> if.then:
>> - %t = load i32* %p, !tbaa !3
>> + %t = load i32* %p, !tbaa !4
>> store i32 %t, i32* %q
>> ret void
>>
>> if.else:
>> - %u = load i32* %p, !tbaa !4
>> + %u = load i32* %p, !tbaa !3
>> store i32 %u, i32* %q
>> ret void
>> }
>>
>> Added: llvm/trunk/test/Transforms/GVN/pre-gep-load.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GVN/pre-gep-load.ll?rev=222039&view=auto
>> ==============================================================================
>> --- llvm/trunk/test/Transforms/GVN/pre-gep-load.ll (added)
>> +++ llvm/trunk/test/Transforms/GVN/pre-gep-load.ll Fri Nov 14 15:09:13
>> 2014
>> @@ -0,0 +1,49 @@
>> +; RUN: opt < %s -basicaa -gvn -enable-load-pre -S | FileCheck %s
>> +target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
>> +target triple = "aarch64--linux-gnu"
>> +
>> +define double @foo(i32 %stat, i32 %i, double** %p) {
>> +; CHECK-LABEL: @foo(
>> +entry:
>> + switch i32 %stat, label %sw.default [
>> + i32 0, label %sw.bb
>> + i32 1, label %sw.bb
>> + i32 2, label %sw.bb2
>> + ]
>> +
>> +sw.bb: ; preds = %entry,
>> %entry
>> + %idxprom = sext i32 %i to i64
>> + %arrayidx = getelementptr inbounds double** %p, i64 0
>> + %0 = load double** %arrayidx, align 8
>> + %arrayidx1 = getelementptr inbounds double* %0, i64 %idxprom
>> + %1 = load double* %arrayidx1, align 8
>> + %sub = fsub double %1, 1.000000e+00
>> + %cmp = fcmp olt double %sub, 0.000000e+00
>> + br i1 %cmp, label %if.then, label %if.end
>> +
>> +if.then: ; preds = %sw.bb
>> + br label %return
>> +
>> +if.end: ; preds = %sw.bb
>> + br label %sw.bb2
>> +
>> +sw.bb2: ; preds = %if.end,
>> %entry
>> + %idxprom3 = sext i32 %i to i64
>> + %arrayidx4 = getelementptr inbounds double** %p, i64 0
>> + %2 = load double** %arrayidx4, align 8
>> + %arrayidx5 = getelementptr inbounds double* %2, i64 %idxprom3
>> + %3 = load double* %arrayidx5, align 8
>> +; CHECK: sw.bb2:
>> +; CHECK-NEXT-NOT: sext
>> +; CHECK-NEXT: phi double [
>> +; CHECK-NOT: load
>> + %sub6 = fsub double 3.000000e+00, %3
>> + br label %return
>> +
>> +sw.default: ; preds = %entry
>> + br label %return
>> +
>> +return: ; preds =
>> %sw.default, %sw.bb2, %if.then
>> + %retval.0 = phi double [ 0.000000e+00, %sw.default ], [ %sub6,
>> %sw.bb2 ], [ %sub, %if.then ]
>> + ret double %retval.0
>> +}
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
>
More information about the llvm-commits
mailing list