<div dir="ltr">Hi Hal,<div><br></div><div>This change breaks a couple of sanitizer unit tests, probably because of a bug in codegen: <a href="http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-autoconf/builds/637">http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-autoconf/builds/637</a></div><div>You can probably reproduce it by running "make check-sanitizer" on Linux/x86-64 machine. Let me know if you need a better/shorter reproducer.</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Feb 16, 2015 at 5:37 PM, Hal Finkel <span dir="ltr"><<a href="mailto:hfinkel@anl.gov" target="_blank">hfinkel@anl.gov</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: hfinkel<br>
Date: Mon Feb 16 19:36:59 2015<br>
New Revision: 229462<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=229462&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=229462&view=rev</a><br>
Log:<br>
[BDCE] Add a bit-tracking DCE pass<br>
<br>
BDCE is a bit-tracking dead code elimination pass. It is based on ADCE (the<br>
"aggressive DCE" pass), with the added capability to track dead bits of integer<br>
valued instructions and remove those instructions when all of the bits are<br>
dead.<br>
<br>
Currently, it does not actually do this all-bits-dead removal, but rather<br>
replaces the instruction's uses with a constant zero, and lets instcombine (and<br>
the later run of ADCE) do the rest. Because we essentially get a run of ADCE<br>
"for free" while tracking the dead bits, we also do what ADCE does and removes<br>
actually-dead instructions as well (this includes instructions newly trivially<br>
dead because all bits were dead, but not all such instructions can be removed).<br>
<br>
The motivation for this is a case like:<br>
<br>
int __attribute__((const)) foo(int i);<br>
int bar(int x) {<br>
x |= (4 & foo(5));<br>
x |= (8 & foo(3));<br>
x |= (16 & foo(2));<br>
x |= (32 & foo(1));<br>
x |= (64 & foo(0));<br>
x |= (128& foo(4));<br>
return x >> 4;<br>
}<br>
<br>
As it turns out, if you order the bit-field insertions so that all of the dead<br>
ones come last, then instcombine will remove them. However, if you pick some<br>
other order (such as the one above), the fact that some of the calls to foo()<br>
are useless is not locally obvious, and we don't remove them (without this<br>
pass).<br>
<br>
I did a quick compile-time overhead check using sqlite from the test suite<br>
(Release+Asserts). BDCE took ~0.4% of the compilation time (making it about<br>
twice as expensive as ADCE).<br>
<br>
I've not looked at why yet, but we eliminate instructions due to having<br>
all-dead bits in:<br>
External/SPEC/CFP2006/447.dealII/447.dealII<br>
External/SPEC/CINT2006/400.perlbench/400.perlbench<br>
External/SPEC/CINT2006/403.gcc/403.gcc<br>
MultiSource/Applications/ClamAV/clamscan<br>
MultiSource/Benchmarks/7zip/7zip-benchmark<br>
<br>
Added:<br>
llvm/trunk/lib/Transforms/Scalar/BDCE.cpp<br>
llvm/trunk/test/Transforms/BDCE/<br>
llvm/trunk/test/Transforms/BDCE/basic.ll<br>
llvm/trunk/test/Transforms/BDCE/dce-pure.ll<br>
Modified:<br>
llvm/trunk/include/llvm-c/Transforms/Scalar.h<br>
llvm/trunk/include/llvm/InitializePasses.h<br>
llvm/trunk/include/llvm/LinkAllPasses.h<br>
llvm/trunk/include/llvm/Transforms/Scalar.h<br>
llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp<br>
llvm/trunk/lib/Transforms/Scalar/CMakeLists.txt<br>
llvm/trunk/lib/Transforms/Scalar/Scalar.cpp<br>
<br>
Modified: llvm/trunk/include/llvm-c/Transforms/Scalar.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/Transforms/Scalar.h?rev=229462&r1=229461&r2=229462&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/Transforms/Scalar.h?rev=229462&r1=229461&r2=229462&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm-c/Transforms/Scalar.h (original)<br>
+++ llvm/trunk/include/llvm-c/Transforms/Scalar.h Mon Feb 16 19:36:59 2015<br>
@@ -35,6 +35,9 @@ extern "C" {<br>
/** See llvm::createAggressiveDCEPass function. */<br>
void LLVMAddAggressiveDCEPass(LLVMPassManagerRef PM);<br>
<br>
+/** See llvm::createBitTrackingDCEPass function. */<br>
+void LLVMAddBitTrackingDCEPass(LLVMPassManagerRef PM);<br>
+<br>
/** See llvm::createAlignmentFromAssumptionsPass function. */<br>
void LLVMAddAlignmentFromAssumptionsPass(LLVMPassManagerRef PM);<br>
<br>
<br>
Modified: llvm/trunk/include/llvm/InitializePasses.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=229462&r1=229461&r2=229462&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=229462&r1=229461&r2=229462&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/InitializePasses.h (original)<br>
+++ llvm/trunk/include/llvm/InitializePasses.h Mon Feb 16 19:36:59 2015<br>
@@ -65,6 +65,7 @@ void initializeTarget(PassRegistry&);<br>
void initializeAAEvalPass(PassRegistry&);<br>
void initializeAddDiscriminatorsPass(PassRegistry&);<br>
void initializeADCEPass(PassRegistry&);<br>
+void initializeBDCEPass(PassRegistry&);<br>
void initializeAliasAnalysisAnalysisGroup(PassRegistry&);<br>
void initializeAliasAnalysisCounterPass(PassRegistry&);<br>
void initializeAliasDebuggerPass(PassRegistry&);<br>
<br>
Modified: llvm/trunk/include/llvm/LinkAllPasses.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/LinkAllPasses.h?rev=229462&r1=229461&r2=229462&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/LinkAllPasses.h?rev=229462&r1=229461&r2=229462&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/LinkAllPasses.h (original)<br>
+++ llvm/trunk/include/llvm/LinkAllPasses.h Mon Feb 16 19:36:59 2015<br>
@@ -49,6 +49,7 @@ namespace {<br>
<br>
(void) llvm::createAAEvalPass();<br>
(void) llvm::createAggressiveDCEPass();<br>
+ (void) llvm::createBitTrackingDCEPass();<br>
(void) llvm::createAliasAnalysisCounterPass();<br>
(void) llvm::createAliasDebugger();<br>
(void) llvm::createArgumentPromotionPass();<br>
<br>
Modified: llvm/trunk/include/llvm/Transforms/Scalar.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Scalar.h?rev=229462&r1=229461&r2=229462&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Scalar.h?rev=229462&r1=229461&r2=229462&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Transforms/Scalar.h (original)<br>
+++ llvm/trunk/include/llvm/Transforms/Scalar.h Mon Feb 16 19:36:59 2015<br>
@@ -82,6 +82,13 @@ FunctionPass *createAggressiveDCEPass();<br>
<br>
//===----------------------------------------------------------------------===//<br>
//<br>
+// BitTrackingDCE - This pass uses a bit-tracking DCE algorithm in order to<br>
+// remove computations of dead bits.<br>
+//<br>
+FunctionPass *createBitTrackingDCEPass();<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
// SROA - Replace aggregates or pieces of aggregates with scalar SSA values.<br>
//<br>
FunctionPass *createSROAPass(bool RequiresDomTree = true);<br>
<br>
Modified: llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp?rev=229462&r1=229461&r2=229462&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp?rev=229462&r1=229461&r2=229462&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp Mon Feb 16 19:36:59 2015<br>
@@ -252,6 +252,11 @@ void PassManagerBuilder::populateModuleP<br>
MPM.add(createMemCpyOptPass()); // Remove memcpy / form memset<br>
MPM.add(createSCCPPass()); // Constant prop with SCCP<br>
<br>
+ // Delete dead bit computations (instcombine runs after to fold away the dead<br>
+ // computations, and then ADCE will run later to exploit any new DCE<br>
+ // opportunities that creates).<br>
+ MPM.add(createBitTrackingDCEPass()); // Delete dead bit computations<br>
+<br>
// Run instcombine after redundancy elimination to exploit opportunities<br>
// opened up by them.<br>
MPM.add(createInstructionCombiningPass());<br>
<br>
Added: llvm/trunk/lib/Transforms/Scalar/BDCE.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/BDCE.cpp?rev=229462&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/BDCE.cpp?rev=229462&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Scalar/BDCE.cpp (added)<br>
+++ llvm/trunk/lib/Transforms/Scalar/BDCE.cpp Mon Feb 16 19:36:59 2015<br>
@@ -0,0 +1,408 @@<br>
+//===---- BDCE.cpp - Bit-tracking dead code elimination -------------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// This file implements the Bit-Tracking Dead Code Elimination pass. Some<br>
+// instructions (shifts, some ands, ors, etc.) kill some of their input bits.<br>
+// We track these dead bits and remove instructions that compute only these<br>
+// dead bits.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "llvm/Transforms/Scalar.h"<br>
+#include "llvm/ADT/DenseMap.h"<br>
+#include "llvm/ADT/DepthFirstIterator.h"<br>
+#include "llvm/ADT/SmallPtrSet.h"<br>
+#include "llvm/ADT/SmallVector.h"<br>
+#include "llvm/ADT/Statistic.h"<br>
+#include "llvm/Analysis/AssumptionCache.h"<br>
+#include "llvm/Analysis/ValueTracking.h"<br>
+#include "llvm/IR/BasicBlock.h"<br>
+#include "llvm/IR/CFG.h"<br>
+#include "llvm/IR/DataLayout.h"<br>
+#include "llvm/IR/Dominators.h"<br>
+#include "llvm/IR/InstIterator.h"<br>
+#include "llvm/IR/Instructions.h"<br>
+#include "llvm/IR/IntrinsicInst.h"<br>
+#include "llvm/IR/Module.h"<br>
+#include "llvm/IR/Operator.h"<br>
+#include "llvm/Pass.h"<br>
+#include "llvm/Support/Debug.h"<br>
+#include "llvm/Support/raw_ostream.h"<br>
+<br>
+using namespace llvm;<br>
+<br>
+#define DEBUG_TYPE "bdce"<br>
+<br>
+STATISTIC(NumRemoved, "Number of instructions removed (unused)");<br>
+STATISTIC(NumSimplified, "Number of instructions trivialized (dead bits)");<br>
+<br>
+namespace {<br>
+struct BDCE : public FunctionPass {<br>
+ static char ID; // Pass identification, replacement for typeid<br>
+ BDCE() : FunctionPass(ID) {<br>
+ initializeBDCEPass(*PassRegistry::getPassRegistry());<br>
+ }<br>
+<br>
+ bool runOnFunction(Function& F) override;<br>
+<br>
+ void getAnalysisUsage(AnalysisUsage& AU) const override {<br>
+ AU.setPreservesCFG();<br>
+ AU.addRequired<AssumptionCacheTracker>();<br>
+ AU.addRequired<DominatorTreeWrapperPass>();<br>
+ }<br>
+<br>
+ void determineLiveOperandBits(const Instruction *UserI,<br>
+ const Instruction *I, unsigned OperandNo,<br>
+ const APInt &AOut, APInt &AB,<br>
+ APInt &KnownZero, APInt &KnownOne,<br>
+ APInt &KnownZero2, APInt &KnownOne2);<br>
+<br>
+ AssumptionCache *AC;<br>
+ const DataLayout *DL;<br>
+ DominatorTree *DT;<br>
+};<br>
+}<br>
+<br>
+char BDCE::ID = 0;<br>
+INITIALIZE_PASS_BEGIN(BDCE, "bdce", "Bit-Tracking Dead Code Elimination",<br>
+ false, false)<br>
+INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)<br>
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)<br>
+INITIALIZE_PASS_END(BDCE, "bdce", "Bit-Tracking Dead Code Elimination",<br>
+ false, false)<br>
+<br>
+static bool isAlwaysLive(Instruction *I) {<br>
+ return isa<TerminatorInst>(I) || isa<DbgInfoIntrinsic>(I) ||<br>
+ isa<LandingPadInst>(I) || I->mayHaveSideEffects();<br>
+}<br>
+<br>
+void BDCE::determineLiveOperandBits(const Instruction *UserI,<br>
+ const Instruction *I, unsigned OperandNo,<br>
+ const APInt &AOut, APInt &AB,<br>
+ APInt &KnownZero, APInt &KnownOne,<br>
+ APInt &KnownZero2, APInt &KnownOne2) {<br>
+ unsigned BitWidth = AB.getBitWidth();<br>
+<br>
+ // We're called once per operand, but for some instructions, we need to<br>
+ // compute known bits of both operands in order to determine the live bits of<br>
+ // either (when both operands are instructions themselves). We don't,<br>
+ // however, want to do this twice, so we cache the result in APInts that live<br>
+ // in the caller. For the two-relevant-operands case, both operand values are<br>
+ // provided here.<br>
+ auto ComputeKnownBits = [&](unsigned BitWidth, const Value *V1,<br>
+ const Value *V2) {<br>
+ KnownZero = APInt(BitWidth, 0);<br>
+ KnownOne = APInt(BitWidth, 0);<br>
+ computeKnownBits(const_cast<Value*>(V1), KnownZero, KnownOne, DL, 0, AC,<br>
+ UserI, DT);<br>
+<br>
+ if (V2) {<br>
+ KnownZero2 = APInt(BitWidth, 0);<br>
+ KnownOne2 = APInt(BitWidth, 0);<br>
+ computeKnownBits(const_cast<Value*>(V2), KnownZero2, KnownOne2, DL, 0, AC,<br>
+ UserI, DT);<br>
+ }<br>
+ };<br>
+<br>
+ switch (UserI->getOpcode()) {<br>
+ default: break;<br>
+ case Instruction::Call:<br>
+ case Instruction::Invoke:<br>
+ if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(UserI))<br>
+ switch (II->getIntrinsicID()) {<br>
+ default: break;<br>
+ case Intrinsic::bswap:<br>
+ // The alive bits of the input are the swapped alive bits of<br>
+ // the output.<br>
+ AB = AOut.byteSwap();<br>
+ break;<br>
+ case Intrinsic::ctlz:<br>
+ if (OperandNo == 0) {<br>
+ // We need some output bits, so we need all bits of the<br>
+ // input to the left of, and including, the leftmost bit<br>
+ // known to be one.<br>
+ ComputeKnownBits(BitWidth, I, nullptr);<br>
+ AB = APInt::getHighBitsSet(BitWidth,<br>
+ std::min(BitWidth, KnownOne.countLeadingZeros()+1));<br>
+ }<br>
+ break;<br>
+ case Intrinsic::cttz:<br>
+ if (OperandNo == 0) {<br>
+ // We need some output bits, so we need all bits of the<br>
+ // input to the right of, and including, the rightmost bit<br>
+ // known to be one.<br>
+ ComputeKnownBits(BitWidth, I, nullptr);<br>
+ AB = APInt::getLowBitsSet(BitWidth,<br>
+ std::min(BitWidth, KnownOne.countTrailingZeros()+1));<br>
+ }<br>
+ break;<br>
+ }<br>
+ break;<br>
+ case Instruction::Add:<br>
+ case Instruction::Sub:<br>
+ // Find the highest live output bit. We don't need any more input<br>
+ // bits than that (adds, and thus subtracts, ripple only to the<br>
+ // left).<br>
+ AB = APInt::getLowBitsSet(BitWidth, AOut.getActiveBits());<br>
+ break;<br>
+ case Instruction::Shl:<br>
+ if (OperandNo == 0)<br>
+ if (ConstantInt *CI =<br>
+ dyn_cast<ConstantInt>(UserI->getOperand(1))) {<br>
+ uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);<br>
+ AB = AOut.lshr(ShiftAmt);<br>
+<br>
+ // If the shift is nuw/nsw, then the high bits are not dead<br>
+ // (because we've promised that they *must* be zero).<br>
+ const ShlOperator *S = cast<ShlOperator>(UserI);<br>
+ if (S->hasNoSignedWrap())<br>
+ AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt+1);<br>
+ else if (S->hasNoUnsignedWrap())<br>
+ AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt);<br>
+ }<br>
+ break;<br>
+ case Instruction::LShr:<br>
+ if (OperandNo == 0)<br>
+ if (ConstantInt *CI =<br>
+ dyn_cast<ConstantInt>(UserI->getOperand(1))) {<br>
+ uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);<br>
+ AB = AOut.shl(ShiftAmt);<br>
+<br>
+ // If the shift is exact, then the low bits are not dead<br>
+ // (they must be zero).<br>
+ if (cast<LShrOperator>(UserI)->isExact())<br>
+ AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);<br>
+ }<br>
+ break;<br>
+ case Instruction::AShr:<br>
+ if (OperandNo == 0)<br>
+ if (ConstantInt *CI =<br>
+ dyn_cast<ConstantInt>(UserI->getOperand(1))) {<br>
+ uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);<br>
+ AB = AOut.shl(ShiftAmt);<br>
+ // Because the high input bit is replicated into the<br>
+ // high-order bits of the result, if we need any of those<br>
+ // bits, then we must keep the highest input bit.<br>
+ if ((AOut & APInt::getHighBitsSet(BitWidth, ShiftAmt))<br>
+ .getBoolValue())<br>
+ AB.setBit(BitWidth-1);<br>
+<br>
+ // If the shift is exact, then the low bits are not dead<br>
+ // (they must be zero).<br>
+ if (cast<AShrOperator>(UserI)->isExact())<br>
+ AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);<br>
+ }<br>
+ break;<br>
+ case Instruction::And:<br>
+ AB = AOut;<br>
+<br>
+ // For bits that are known zero, the corresponding bits in the<br>
+ // other operand are dead (unless they're both zero, in which<br>
+ // case they can't both be dead, so just mark the LHS bits as<br>
+ // dead).<br>
+ if (OperandNo == 0) {<br>
+ ComputeKnownBits(BitWidth, I, UserI->getOperand(1));<br>
+ AB &= ~KnownZero2;<br>
+ } else {<br>
+ if (!isa<Instruction>(UserI->getOperand(0)))<br>
+ ComputeKnownBits(BitWidth, UserI->getOperand(0), I);<br>
+ AB &= ~(KnownZero & ~KnownZero2);<br>
+ }<br>
+ break;<br>
+ case Instruction::Or:<br>
+ AB = AOut;<br>
+<br>
+ // For bits that are known one, the corresponding bits in the<br>
+ // other operand are dead (unless they're both one, in which<br>
+ // case they can't both be dead, so just mark the LHS bits as<br>
+ // dead).<br>
+ if (OperandNo == 0) {<br>
+ ComputeKnownBits(BitWidth, I, UserI->getOperand(1));<br>
+ AB &= ~KnownOne2;<br>
+ } else {<br>
+ if (!isa<Instruction>(UserI->getOperand(0)))<br>
+ ComputeKnownBits(BitWidth, UserI->getOperand(0), I);<br>
+ AB &= ~(KnownOne & ~KnownOne2);<br>
+ }<br>
+ break;<br>
+ case Instruction::Xor:<br>
+ case Instruction::PHI:<br>
+ AB = AOut;<br>
+ break;<br>
+ case Instruction::Trunc:<br>
+ AB = AOut.zext(BitWidth);<br>
+ break;<br>
+ case Instruction::ZExt:<br>
+ AB = AOut.trunc(BitWidth);<br>
+ break;<br>
+ case Instruction::SExt:<br>
+ AB = AOut.trunc(BitWidth);<br>
+ // Because the high input bit is replicated into the<br>
+ // high-order bits of the result, if we need any of those<br>
+ // bits, then we must keep the highest input bit.<br>
+ if ((AOut & APInt::getHighBitsSet(AOut.getBitWidth(),<br>
+ AOut.getBitWidth() - BitWidth))<br>
+ .getBoolValue())<br>
+ AB.setBit(BitWidth-1);<br>
+ break;<br>
+ case Instruction::Select:<br>
+ if (OperandNo != 0)<br>
+ AB = AOut;<br>
+ break;<br>
+ }<br>
+}<br>
+<br>
+bool BDCE::runOnFunction(Function& F) {<br>
+ if (skipOptnoneFunction(F))<br>
+ return false;<br>
+<br>
+ AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);<br>
+ DL = F.getParent()->getDataLayout();<br>
+ DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();<br>
+<br>
+ DenseMap<Instruction *, APInt> AliveBits;<br>
+ SmallVector<Instruction*, 128> Worklist;<br>
+<br>
+ // The set of visited instructions (non-integer-typed only).<br>
+ SmallPtrSet<Instruction*, 128> Visited;<br>
+<br>
+ // Collect the set of "root" instructions that are known live.<br>
+ for (Instruction &I : inst_range(F)) {<br>
+ if (!isAlwaysLive(&I))<br>
+ continue;<br>
+<br>
+ // For integer-valued instructions, set up an initial empty set of alive<br>
+ // bits and add the instruction to the work list. For other instructions<br>
+ // add their operands to the work list (for integer values operands, mark<br>
+ // all bits as live).<br>
+ if (IntegerType *IT = dyn_cast<IntegerType>(I.getType())) {<br>
+ AliveBits[&I] = APInt(IT->getBitWidth(), 0);<br>
+ Worklist.push_back(&I);<br>
+ continue;<br>
+ }<br>
+<br>
+ // Non-integer-typed instructions...<br>
+ for (Use &OI : I.operands()) {<br>
+ if (Instruction *J = dyn_cast<Instruction>(OI)) {<br>
+ if (IntegerType *IT = dyn_cast<IntegerType>(J->getType()))<br>
+ AliveBits[J] = APInt::getAllOnesValue(IT->getBitWidth());<br>
+ Worklist.push_back(J);<br>
+ }<br>
+ }<br>
+ // To save memory, we don't add I to the Visited set here. Instead, we<br>
+ // check isAlwaysLive on every instruction when searching for dead<br>
+ // instructions later (we need to check isAlwaysLive for the<br>
+ // integer-typed instructions anyway).<br>
+ }<br>
+<br>
+ // Propagate liveness backwards to operands.<br>
+ while (!Worklist.empty()) {<br>
+ Instruction *UserI = Worklist.pop_back_val();<br>
+<br>
+ DEBUG(dbgs() << "BDCE: Visiting: " << *UserI);<br>
+ APInt AOut;<br>
+ if (UserI->getType()->isIntegerTy()) {<br>
+ AOut = AliveBits[UserI];<br>
+ DEBUG(dbgs() << " Alive Out: " << AOut);<br>
+ }<br>
+ DEBUG(dbgs() << "\n");<br>
+<br>
+ if (!UserI->getType()->isIntegerTy())<br>
+ Visited.insert(UserI);<br>
+<br>
+ APInt KnownZero, KnownOne, KnownZero2, KnownOne2;<br>
+ // Compute the set of alive bits for each operand. These are anded into the<br>
+ // existing set, if any, and if that changes the set of alive bits, the<br>
+ // operand is added to the work-list.<br>
+ for (Use &OI : UserI->operands()) {<br>
+ if (Instruction *I = dyn_cast<Instruction>(OI)) {<br>
+ if (IntegerType *IT = dyn_cast<IntegerType>(I->getType())) {<br>
+ unsigned BitWidth = IT->getBitWidth();<br>
+ APInt AB = APInt::getAllOnesValue(BitWidth);<br>
+ if (UserI->getType()->isIntegerTy() && !AOut &&<br>
+ !isAlwaysLive(UserI)) {<br>
+ AB = APInt(BitWidth, 0);<br>
+ } else {<br>
+ // If all bits of the output are dead, then all bits of the input<br>
+ // Bits of each operand that are used to compute alive bits of the<br>
+ // output are alive, all others are dead.<br>
+ determineLiveOperandBits(UserI, I, OI.getOperandNo(), AOut, AB,<br>
+ KnownZero, KnownOne,<br>
+ KnownZero2, KnownOne2);<br>
+ }<br>
+<br>
+ // If we've added to the set of alive bits (or the operand has not<br>
+ // been previously visited), then re-queue the operand to be visited<br>
+ // again.<br>
+ APInt ABPrev(BitWidth, 0);<br>
+ auto ABI = AliveBits.find(I);<br>
+ if (ABI != AliveBits.end())<br>
+ ABPrev = ABI->second;<br>
+<br>
+ APInt ABNew = AB | ABPrev;<br>
+ if (ABNew != ABPrev || ABI == AliveBits.end()) {<br>
+ AliveBits[I] = std::move(ABNew);<br>
+ Worklist.push_back(I);<br>
+ }<br>
+ } else if (!Visited.count(I)) {<br>
+ Worklist.push_back(I);<br>
+ }<br>
+ }<br>
+ }<br>
+ }<br>
+<br>
+ bool Changed = false;<br>
+ // The inverse of the live set is the dead set. These are those instructions<br>
+ // which have no side effects and do not influence the control flow or return<br>
+ // value of the function, and may therefore be deleted safely.<br>
+ // NOTE: We reuse the Worklist vector here for memory efficiency.<br>
+ for (Instruction &I : inst_range(F)) {<br>
+ // For live instructions that have all dead bits, first make them dead by<br>
+ // replacing all uses with something else. Then, if they don't need to<br>
+ // remain live (because they have side effects, etc.) we can remove them.<br>
+ if (I.getType()->isIntegerTy()) {<br>
+ auto ABI = AliveBits.find(&I);<br>
+ if (ABI != AliveBits.end()) {<br>
+ if (ABI->second.getBoolValue())<br>
+ continue;<br>
+<br>
+ DEBUG(dbgs() << "BDCE: Trivializing: " << I << " (all bits dead)\n");<br>
+ // FIXME: In theory we could substitute undef here instead of zero.<br>
+ // This should be reconsidered once we settle on the semantics of<br>
+ // undef, poison, etc.<br>
+ Value *Zero = ConstantInt::get(I.getType(), 0);<br>
+ ++NumSimplified;<br>
+ I.replaceAllUsesWith(Zero);<br>
+ Changed = true;<br>
+ }<br>
+ } else if (Visited.count(&I)) {<br>
+ continue;<br>
+ }<br>
+<br>
+ if (isAlwaysLive(&I))<br>
+ continue;<br>
+<br>
+ DEBUG(dbgs() << "BDCE: Removing: " << I << " (unused)\n");<br>
+ Worklist.push_back(&I);<br>
+ I.dropAllReferences();<br>
+ Changed = true;<br>
+ }<br>
+<br>
+ for (Instruction *&I : Worklist) {<br>
+ ++NumRemoved;<br>
+ I->eraseFromParent();<br>
+ }<br>
+<br>
+ return Changed;<br>
+}<br>
+<br>
+FunctionPass *llvm::createBitTrackingDCEPass() {<br>
+ return new BDCE();<br>
+}<br>
+<br>
<br>
Modified: llvm/trunk/lib/Transforms/Scalar/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/CMakeLists.txt?rev=229462&r1=229461&r2=229462&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/CMakeLists.txt?rev=229462&r1=229461&r2=229462&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Scalar/CMakeLists.txt (original)<br>
+++ llvm/trunk/lib/Transforms/Scalar/CMakeLists.txt Mon Feb 16 19:36:59 2015<br>
@@ -1,6 +1,7 @@<br>
add_llvm_library(LLVMScalarOpts<br>
ADCE.cpp<br>
AlignmentFromAssumptions.cpp<br>
+ BDCE.cpp<br>
ConstantHoisting.cpp<br>
ConstantProp.cpp<br>
CorrelatedValuePropagation.cpp<br>
<br>
Modified: llvm/trunk/lib/Transforms/Scalar/Scalar.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/Scalar.cpp?rev=229462&r1=229461&r2=229462&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/Scalar.cpp?rev=229462&r1=229461&r2=229462&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Scalar/Scalar.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/Scalar/Scalar.cpp Mon Feb 16 19:36:59 2015<br>
@@ -28,6 +28,7 @@ using namespace llvm;<br>
/// ScalarOpts library.<br>
void llvm::initializeScalarOpts(PassRegistry &Registry) {<br>
initializeADCEPass(Registry);<br>
+ initializeBDCEPass(Registry);<br>
initializeAlignmentFromAssumptionsPass(Registry);<br>
initializeSampleProfileLoaderPass(Registry);<br>
initializeConstantHoistingPass(Registry);<br>
@@ -83,6 +84,10 @@ void LLVMAddAggressiveDCEPass(LLVMPassMa<br>
unwrap(PM)->add(createAggressiveDCEPass());<br>
}<br>
<br>
+void LLVMAddBitTrackingDCEPass(LLVMPassManagerRef PM) {<br>
+ unwrap(PM)->add(createBitTrackingDCEPass());<br>
+}<br>
+<br>
void LLVMAddAlignmentFromAssumptionsPass(LLVMPassManagerRef PM) {<br>
unwrap(PM)->add(createAlignmentFromAssumptionsPass());<br>
}<br>
<br>
Added: llvm/trunk/test/Transforms/BDCE/basic.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/BDCE/basic.ll?rev=229462&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/BDCE/basic.ll?rev=229462&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/BDCE/basic.ll (added)<br>
+++ llvm/trunk/test/Transforms/BDCE/basic.ll Mon Feb 16 19:36:59 2015<br>
@@ -0,0 +1,348 @@<br>
+; RUN: opt -S -bdce -instsimplify < %s | FileCheck %s<br>
+; RUN: opt -S -instsimplify < %s | FileCheck %s -check-prefix=CHECK-IO<br>
+target datalayout = "E-m:e-i64:64-n32:64"<br>
+target triple = "powerpc64-unknown-linux-gnu"<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+define signext i32 @bar(i32 signext %x) #0 {<br>
+entry:<br>
+ %call = tail call signext i32 @foo(i32 signext 5) #0<br>
+ %and = and i32 %call, 4<br>
+ %or = or i32 %and, %x<br>
+ %call1 = tail call signext i32 @foo(i32 signext 3) #0<br>
+ %and2 = and i32 %call1, 8<br>
+ %or3 = or i32 %or, %and2<br>
+ %call4 = tail call signext i32 @foo(i32 signext 2) #0<br>
+ %and5 = and i32 %call4, 16<br>
+ %or6 = or i32 %or3, %and5<br>
+ %call7 = tail call signext i32 @foo(i32 signext 1) #0<br>
+ %and8 = and i32 %call7, 32<br>
+ %or9 = or i32 %or6, %and8<br>
+ %call10 = tail call signext i32 @foo(i32 signext 0) #0<br>
+ %and11 = and i32 %call10, 64<br>
+ %or12 = or i32 %or9, %and11<br>
+ %call13 = tail call signext i32 @foo(i32 signext 4) #0<br>
+ %and14 = and i32 %call13, 128<br>
+ %or15 = or i32 %or12, %and14<br>
+ %shr = ashr i32 %or15, 4<br>
+ ret i32 %shr<br>
+<br>
+; CHECK-LABEL: @bar<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 5)<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 3)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 2)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 1)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 0)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 4)<br>
+; CHECK: ret i32<br>
+<br>
+; Check that instsimplify is not doing this all on its own.<br>
+; CHECK-IO-LABEL: @bar<br>
+; CHECK-IO: tail call signext i32 @foo(i32 signext 5)<br>
+; CHECK-IO: tail call signext i32 @foo(i32 signext 3)<br>
+; CHECK-IO: tail call signext i32 @foo(i32 signext 2)<br>
+; CHECK-IO: tail call signext i32 @foo(i32 signext 1)<br>
+; CHECK-IO: tail call signext i32 @foo(i32 signext 0)<br>
+; CHECK-IO: tail call signext i32 @foo(i32 signext 4)<br>
+; CHECK-IO: ret i32<br>
+}<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+declare signext i32 @foo(i32 signext) #0<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+define signext i32 @far(i32 signext %x) #1 {<br>
+entry:<br>
+ %call = tail call signext i32 @goo(i32 signext 5) #1<br>
+ %and = and i32 %call, 4<br>
+ %or = or i32 %and, %x<br>
+ %call1 = tail call signext i32 @goo(i32 signext 3) #1<br>
+ %and2 = and i32 %call1, 8<br>
+ %or3 = or i32 %or, %and2<br>
+ %call4 = tail call signext i32 @goo(i32 signext 2) #1<br>
+ %and5 = and i32 %call4, 16<br>
+ %or6 = or i32 %or3, %and5<br>
+ %call7 = tail call signext i32 @goo(i32 signext 1) #1<br>
+ %and8 = and i32 %call7, 32<br>
+ %or9 = or i32 %or6, %and8<br>
+ %call10 = tail call signext i32 @goo(i32 signext 0) #1<br>
+ %and11 = and i32 %call10, 64<br>
+ %or12 = or i32 %or9, %and11<br>
+ %call13 = tail call signext i32 @goo(i32 signext 4) #1<br>
+ %and14 = and i32 %call13, 128<br>
+ %or15 = or i32 %or12, %and14<br>
+ %shr = ashr i32 %or15, 4<br>
+ ret i32 %shr<br>
+<br>
+; CHECK-LABEL: @far<br>
+; Calls to foo(5) and foo(3) are still there, but their results are not used.<br>
+; CHECK: tail call signext i32 @goo(i32 signext 5)<br>
+; CHECK-NEXT: tail call signext i32 @goo(i32 signext 3)<br>
+; CHECK-NEXT: tail call signext i32 @goo(i32 signext 2)<br>
+; CHECK: tail call signext i32 @goo(i32 signext 1)<br>
+; CHECK: tail call signext i32 @goo(i32 signext 0)<br>
+; CHECK: tail call signext i32 @goo(i32 signext 4)<br>
+; CHECK: ret i32<br>
+<br>
+; Check that instsimplify is not doing this all on its own.<br>
+; CHECK-IO-LABEL: @far<br>
+; CHECK-IO: tail call signext i32 @goo(i32 signext 5)<br>
+; CHECK-IO: tail call signext i32 @goo(i32 signext 3)<br>
+; CHECK-IO: tail call signext i32 @goo(i32 signext 2)<br>
+; CHECK-IO: tail call signext i32 @goo(i32 signext 1)<br>
+; CHECK-IO: tail call signext i32 @goo(i32 signext 0)<br>
+; CHECK-IO: tail call signext i32 @goo(i32 signext 4)<br>
+; CHECK-IO: ret i32<br>
+}<br>
+<br>
+declare signext i32 @goo(i32 signext) #1<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+define signext i32 @tar1(i32 signext %x) #0 {<br>
+entry:<br>
+ %call = tail call signext i32 @foo(i32 signext 5) #0<br>
+ %and = and i32 %call, 33554432<br>
+ %or = or i32 %and, %x<br>
+ %call1 = tail call signext i32 @foo(i32 signext 3) #0<br>
+ %and2 = and i32 %call1, 67108864<br>
+ %or3 = or i32 %or, %and2<br>
+ %call4 = tail call signext i32 @foo(i32 signext 2) #0<br>
+ %and5 = and i32 %call4, 16<br>
+ %or6 = or i32 %or3, %and5<br>
+ %call7 = tail call signext i32 @foo(i32 signext 1) #0<br>
+ %and8 = and i32 %call7, 32<br>
+ %or9 = or i32 %or6, %and8<br>
+ %call10 = tail call signext i32 @foo(i32 signext 0) #0<br>
+ %and11 = and i32 %call10, 64<br>
+ %or12 = or i32 %or9, %and11<br>
+ %call13 = tail call signext i32 @foo(i32 signext 4) #0<br>
+ %and14 = and i32 %call13, 128<br>
+ %or15 = or i32 %or12, %and14<br>
+ %bs = tail call i32 @llvm.bswap.i32(i32 %or15) #0<br>
+ %shr = ashr i32 %bs, 4<br>
+ ret i32 %shr<br>
+<br>
+; CHECK-LABEL: @tar1<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 5)<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 3)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 2)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 1)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 0)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 4)<br>
+; CHECK: ret i32<br>
+}<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+declare i32 @llvm.bswap.i32(i32) #0<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+define signext i32 @tar2(i32 signext %x) #0 {<br>
+entry:<br>
+ %call = tail call signext i32 @foo(i32 signext 5) #0<br>
+ %and = and i32 %call, 33554432<br>
+ %or = or i32 %and, %x<br>
+ %call1 = tail call signext i32 @foo(i32 signext 3) #0<br>
+ %and2 = and i32 %call1, 67108864<br>
+ %or3 = or i32 %or, %and2<br>
+ %call4 = tail call signext i32 @foo(i32 signext 2) #0<br>
+ %and5 = and i32 %call4, 16<br>
+ %or6 = or i32 %or3, %and5<br>
+ %call7 = tail call signext i32 @foo(i32 signext 1) #0<br>
+ %and8 = and i32 %call7, 32<br>
+ %or9 = or i32 %or6, %and8<br>
+ %call10 = tail call signext i32 @foo(i32 signext 0) #0<br>
+ %and11 = and i32 %call10, 64<br>
+ %or12 = or i32 %or9, %and11<br>
+ %call13 = tail call signext i32 @foo(i32 signext 4) #0<br>
+ %and14 = and i32 %call13, 128<br>
+ %or15 = or i32 %or12, %and14<br>
+ %shl = shl i32 %or15, 10<br>
+ ret i32 %shl<br>
+<br>
+; CHECK-LABEL: @tar2<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 5)<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 3)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 2)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 1)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 0)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 4)<br>
+; CHECK: ret i32<br>
+}<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+define signext i32 @tar3(i32 signext %x) #0 {<br>
+entry:<br>
+ %call = tail call signext i32 @foo(i32 signext 5) #0<br>
+ %and = and i32 %call, 33554432<br>
+ %or = or i32 %and, %x<br>
+ %call1 = tail call signext i32 @foo(i32 signext 3) #0<br>
+ %and2 = and i32 %call1, 67108864<br>
+ %or3 = or i32 %or, %and2<br>
+ %call4 = tail call signext i32 @foo(i32 signext 2) #0<br>
+ %and5 = and i32 %call4, 16<br>
+ %or6 = or i32 %or3, %and5<br>
+ %call7 = tail call signext i32 @foo(i32 signext 1) #0<br>
+ %and8 = and i32 %call7, 32<br>
+ %or9 = or i32 %or6, %and8<br>
+ %call10 = tail call signext i32 @foo(i32 signext 0) #0<br>
+ %and11 = and i32 %call10, 64<br>
+ %or12 = or i32 %or9, %and11<br>
+ %call13 = tail call signext i32 @foo(i32 signext 4) #0<br>
+ %and14 = and i32 %call13, 128<br>
+ %or15 = or i32 %or12, %and14<br>
+ %add = add i32 %or15, 5<br>
+ %shl = shl i32 %add, 10<br>
+ ret i32 %shl<br>
+<br>
+; CHECK-LABEL: @tar3<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 5)<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 3)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 2)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 1)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 0)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 4)<br>
+; CHECK: ret i32<br>
+}<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+define signext i32 @tar4(i32 signext %x) #0 {<br>
+entry:<br>
+ %call = tail call signext i32 @foo(i32 signext 5) #0<br>
+ %and = and i32 %call, 33554432<br>
+ %or = or i32 %and, %x<br>
+ %call1 = tail call signext i32 @foo(i32 signext 3) #0<br>
+ %and2 = and i32 %call1, 67108864<br>
+ %or3 = or i32 %or, %and2<br>
+ %call4 = tail call signext i32 @foo(i32 signext 2) #0<br>
+ %and5 = and i32 %call4, 16<br>
+ %or6 = or i32 %or3, %and5<br>
+ %call7 = tail call signext i32 @foo(i32 signext 1) #0<br>
+ %and8 = and i32 %call7, 32<br>
+ %or9 = or i32 %or6, %and8<br>
+ %call10 = tail call signext i32 @foo(i32 signext 0) #0<br>
+ %and11 = and i32 %call10, 64<br>
+ %or12 = or i32 %or9, %and11<br>
+ %call13 = tail call signext i32 @foo(i32 signext 4) #0<br>
+ %and14 = and i32 %call13, 128<br>
+ %or15 = or i32 %or12, %and14<br>
+ %sub = sub i32 %or15, 5<br>
+ %shl = shl i32 %sub, 10<br>
+ ret i32 %shl<br>
+<br>
+; CHECK-LABEL: @tar4<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 5)<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 3)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 2)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 1)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 0)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 4)<br>
+; CHECK: ret i32<br>
+}<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+define signext i32 @tar5(i32 signext %x) #0 {<br>
+entry:<br>
+ %call = tail call signext i32 @foo(i32 signext 5) #0<br>
+ %and = and i32 %call, 33554432<br>
+ %or = or i32 %and, %x<br>
+ %call1 = tail call signext i32 @foo(i32 signext 3) #0<br>
+ %and2 = and i32 %call1, 67108864<br>
+ %or3 = or i32 %or, %and2<br>
+ %call4 = tail call signext i32 @foo(i32 signext 2) #0<br>
+ %and5 = and i32 %call4, 16<br>
+ %or6 = or i32 %or3, %and5<br>
+ %call7 = tail call signext i32 @foo(i32 signext 1) #0<br>
+ %and8 = and i32 %call7, 32<br>
+ %or9 = or i32 %or6, %and8<br>
+ %call10 = tail call signext i32 @foo(i32 signext 0) #0<br>
+ %and11 = and i32 %call10, 64<br>
+ %or12 = or i32 %or9, %and11<br>
+ %call13 = tail call signext i32 @foo(i32 signext 4) #0<br>
+ %and14 = and i32 %call13, 128<br>
+ %or15 = or i32 %or12, %and14<br>
+ %xor = xor i32 %or15, 5<br>
+ %shl = shl i32 %xor, 10<br>
+ ret i32 %shl<br>
+<br>
+; CHECK-LABEL: @tar5<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 5)<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 3)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 2)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 1)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 0)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 4)<br>
+; CHECK: ret i32<br>
+}<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+define signext i32 @tar7(i32 signext %x, i1 %b) #0 {<br>
+entry:<br>
+ %call = tail call signext i32 @foo(i32 signext 5) #0<br>
+ %and = and i32 %call, 33554432<br>
+ %or = or i32 %and, %x<br>
+ %call1 = tail call signext i32 @foo(i32 signext 3) #0<br>
+ %and2 = and i32 %call1, 67108864<br>
+ %or3 = or i32 %or, %and2<br>
+ %call4 = tail call signext i32 @foo(i32 signext 2) #0<br>
+ %and5 = and i32 %call4, 16<br>
+ %or6 = or i32 %or3, %and5<br>
+ %call7 = tail call signext i32 @foo(i32 signext 1) #0<br>
+ %and8 = and i32 %call7, 32<br>
+ %or9 = or i32 %or6, %and8<br>
+ %call10 = tail call signext i32 @foo(i32 signext 0) #0<br>
+ %and11 = and i32 %call10, 64<br>
+ %or12 = or i32 %or9, %and11<br>
+ %call13 = tail call signext i32 @foo(i32 signext 4) #0<br>
+ %and14 = and i32 %call13, 128<br>
+ %or15 = or i32 %or12, %and14<br>
+ %v = select i1 %b, i32 %or15, i32 5<br>
+ %shl = shl i32 %v, 10<br>
+ ret i32 %shl<br>
+<br>
+; CHECK-LABEL: @tar7<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 5)<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 3)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 2)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 1)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 0)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 4)<br>
+; CHECK: ret i32<br>
+}<br>
+<br>
+; Function Attrs: nounwind readnone<br>
+define signext i16 @tar8(i32 signext %x) #0 {<br>
+entry:<br>
+ %call = tail call signext i32 @foo(i32 signext 5) #0<br>
+ %and = and i32 %call, 33554432<br>
+ %or = or i32 %and, %x<br>
+ %call1 = tail call signext i32 @foo(i32 signext 3) #0<br>
+ %and2 = and i32 %call1, 67108864<br>
+ %or3 = or i32 %or, %and2<br>
+ %call4 = tail call signext i32 @foo(i32 signext 2) #0<br>
+ %and5 = and i32 %call4, 16<br>
+ %or6 = or i32 %or3, %and5<br>
+ %call7 = tail call signext i32 @foo(i32 signext 1) #0<br>
+ %and8 = and i32 %call7, 32<br>
+ %or9 = or i32 %or6, %and8<br>
+ %call10 = tail call signext i32 @foo(i32 signext 0) #0<br>
+ %and11 = and i32 %call10, 64<br>
+ %or12 = or i32 %or9, %and11<br>
+ %call13 = tail call signext i32 @foo(i32 signext 4) #0<br>
+ %and14 = and i32 %call13, 128<br>
+ %or15 = or i32 %or12, %and14<br>
+ %tr = trunc i32 %or15 to i16<br>
+ ret i16 %tr<br>
+<br>
+; CHECK-LABEL: @tar8<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 5)<br>
+; CHECK-NOT: tail call signext i32 @foo(i32 signext 3)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 2)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 1)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 0)<br>
+; CHECK: tail call signext i32 @foo(i32 signext 4)<br>
+; CHECK: ret i16<br>
+}<br>
+<br>
+attributes #0 = { nounwind readnone }<br>
+attributes #1 = { nounwind }<br>
+<br>
<br>
Added: llvm/trunk/test/Transforms/BDCE/dce-pure.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/BDCE/dce-pure.ll?rev=229462&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/BDCE/dce-pure.ll?rev=229462&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/BDCE/dce-pure.ll (added)<br>
+++ llvm/trunk/test/Transforms/BDCE/dce-pure.ll Mon Feb 16 19:36:59 2015<br>
@@ -0,0 +1,33 @@<br>
+; RUN: opt -bdce -S < %s | FileCheck %s<br>
+<br>
+declare i32 @strlen(i8*) readonly nounwind<br>
+<br>
+define void @test1() {<br>
+ call i32 @strlen( i8* null )<br>
+ ret void<br>
+<br>
+; CHECK-LABEL: @test1<br>
+; CHECK-NOT: call<br>
+; CHECK: ret void<br>
+}<br>
+<br>
+define i32 @test2() {<br>
+ ; invoke of pure function should not be deleted!<br>
+ invoke i32 @strlen( i8* null ) readnone<br>
+ to label %Cont unwind label %Other<br>
+<br>
+Cont: ; preds = %0<br>
+ ret i32 0<br>
+<br>
+Other: ; preds = %0<br>
+ %exn = landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0<br>
+ cleanup<br>
+ ret i32 1<br>
+<br>
+; CHECK-LABEL: @test2<br>
+; CHECK: invoke<br>
+; CHECK: ret i32 1<br>
+}<br>
+<br>
+declare i32 @__gxx_personality_v0(...)<br>
+<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr">Alexey Samsonov<br><a href="mailto:vonosmas@gmail.com" target="_blank">vonosmas@gmail.com</a></div></div>
</div>