summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Majnemer <david.majnemer@gmail.com>2016-04-22 06:37:45 +0000
committerDavid Majnemer <david.majnemer@gmail.com>2016-04-22 06:37:45 +0000
commit9554c1339c02857bdb46c81d444dae245f7ff1c1 (patch)
treef50d5e9f8cfd7b41e18f7d23dceb9fcdea642664
parentefdeb45ffdc561ece0aaf0ee38f46920257bc513 (diff)
downloadbcm5719-llvm-9554c1339c02857bdb46c81d444dae245f7ff1c1.tar.gz
bcm5719-llvm-9554c1339c02857bdb46c81d444dae245f7ff1c1.zip
[EarlyCSE] Take the intersection of flags on instructions
EarlyCSE had inconsistent behavior with regards to flag'd instructions: - In some cases, it would pessimize if the available instruction had different flags by not performing CSE. - In other cases, it would miscompile if it replaced an instruction which had no flags with an instruction which has flags. Fix this by being more consistent with our flag handling by utilizing andIRFlags. llvm-svn: 267111
-rw-r--r--llvm/include/llvm/IR/InstrTypes.h29
-rw-r--r--llvm/include/llvm/IR/Instruction.h29
-rw-r--r--llvm/include/llvm/IR/Operator.h4
-rw-r--r--llvm/lib/IR/Instruction.cpp55
-rw-r--r--llvm/lib/IR/Instructions.cpp56
-rw-r--r--llvm/lib/Transforms/Scalar/EarlyCSE.cpp13
-rw-r--r--llvm/test/Transforms/EarlyCSE/flags.ll18
7 files changed, 107 insertions, 97 deletions
diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index 4e85d830d2c..b7446852a0d 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -535,35 +535,6 @@ public:
///
bool swapOperands();
- /// Set or clear the nsw flag on this instruction, which must be an operator
- /// which supports this flag. See LangRef.html for the meaning of this flag.
- void setHasNoUnsignedWrap(bool b = true);
-
- /// Set or clear the nsw flag on this instruction, which must be an operator
- /// which supports this flag. See LangRef.html for the meaning of this flag.
- void setHasNoSignedWrap(bool b = true);
-
- /// Set or clear the exact flag on this instruction, which must be an operator
- /// which supports this flag. See LangRef.html for the meaning of this flag.
- void setIsExact(bool b = true);
-
- /// Determine whether the no unsigned wrap flag is set.
- bool hasNoUnsignedWrap() const;
-
- /// Determine whether the no signed wrap flag is set.
- bool hasNoSignedWrap() const;
-
- /// Determine whether the exact flag is set.
- bool isExact() const;
-
- /// Convenience method to copy supported wrapping, exact, and fast-math flags
- /// from V to this instruction.
- void copyIRFlags(const Value *V);
-
- /// Logical 'and' of any supported wrapping, exact, and fast-math flags of
- /// V and this instruction.
- void andIRFlags(const Value *V);
-
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Instruction *I) {
return I->isBinaryOp();
diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 12cbcce4c09..e44b23db8cb 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -223,6 +223,27 @@ public:
/// Return the debug location for this node as a DebugLoc.
const DebugLoc &getDebugLoc() const { return DbgLoc; }
+ /// Set or clear the nsw flag on this instruction, which must be an operator
+ /// which supports this flag. See LangRef.html for the meaning of this flag.
+ void setHasNoUnsignedWrap(bool b = true);
+
+ /// Set or clear the nsw flag on this instruction, which must be an operator
+ /// which supports this flag. See LangRef.html for the meaning of this flag.
+ void setHasNoSignedWrap(bool b = true);
+
+ /// Set or clear the exact flag on this instruction, which must be an operator
+ /// which supports this flag. See LangRef.html for the meaning of this flag.
+ void setIsExact(bool b = true);
+
+ /// Determine whether the no unsigned wrap flag is set.
+ bool hasNoUnsignedWrap() const;
+
+ /// Determine whether the no signed wrap flag is set.
+ bool hasNoSignedWrap() const;
+
+ /// Determine whether the exact flag is set.
+ bool isExact() const;
+
/// Set or clear the unsafe-algebra flag on this instruction, which must be an
/// operator which supports this flag. See LangRef.html for the meaning of
/// this flag.
@@ -281,6 +302,14 @@ public:
/// Copy I's fast-math flags
void copyFastMathFlags(const Instruction *I);
+ /// Convenience method to copy supported wrapping, exact, and fast-math flags
+ /// from V to this instruction.
+ void copyIRFlags(const Value *V);
+
+ /// Logical 'and' of any supported wrapping, exact, and fast-math flags of
+ /// V and this instruction.
+ void andIRFlags(const Value *V);
+
private:
/// Return true if we have an entry in the on-the-side metadata hash.
bool hasMetadataHashEntry() const {
diff --git a/llvm/include/llvm/IR/Operator.h b/llvm/include/llvm/IR/Operator.h
index 50f34665a8e..5880290f3d9 100644
--- a/llvm/include/llvm/IR/Operator.h
+++ b/llvm/include/llvm/IR/Operator.h
@@ -79,7 +79,7 @@ public:
};
private:
- friend class BinaryOperator;
+ friend class Instruction;
friend class ConstantExpr;
void setHasNoUnsignedWrap(bool B) {
SubclassOptionalData =
@@ -130,7 +130,7 @@ public:
};
private:
- friend class BinaryOperator;
+ friend class Instruction;
friend class ConstantExpr;
void setIsExact(bool B) {
SubclassOptionalData = (SubclassOptionalData & ~IsExact) | (B * IsExact);
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 9b996efb5af..dd28b5c506a 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -96,6 +96,30 @@ void Instruction::moveBefore(Instruction *MovePos) {
MovePos->getIterator(), getParent()->getInstList(), getIterator());
}
+void Instruction::setHasNoUnsignedWrap(bool b) {
+ cast<OverflowingBinaryOperator>(this)->setHasNoUnsignedWrap(b);
+}
+
+void Instruction::setHasNoSignedWrap(bool b) {
+ cast<OverflowingBinaryOperator>(this)->setHasNoSignedWrap(b);
+}
+
+void Instruction::setIsExact(bool b) {
+ cast<PossiblyExactOperator>(this)->setIsExact(b);
+}
+
+bool Instruction::hasNoUnsignedWrap() const {
+ return cast<OverflowingBinaryOperator>(this)->hasNoUnsignedWrap();
+}
+
+bool Instruction::hasNoSignedWrap() const {
+ return cast<OverflowingBinaryOperator>(this)->hasNoSignedWrap();
+}
+
+bool Instruction::isExact() const {
+ return cast<PossiblyExactOperator>(this)->isExact();
+}
+
/// Set or clear the unsafe-algebra flag on this instruction, which must be an
/// operator which supports this flag. See LangRef.html for the meaning of this
/// flag.
@@ -190,6 +214,37 @@ void Instruction::copyFastMathFlags(const Instruction *I) {
copyFastMathFlags(I->getFastMathFlags());
}
+void Instruction::copyIRFlags(const Value *V) {
+ // Copy the wrapping flags.
+ if (auto *OB = dyn_cast<OverflowingBinaryOperator>(V)) {
+ setHasNoSignedWrap(OB->hasNoSignedWrap());
+ setHasNoUnsignedWrap(OB->hasNoUnsignedWrap());
+ }
+
+ // Copy the exact flag.
+ if (auto *PE = dyn_cast<PossiblyExactOperator>(V))
+ setIsExact(PE->isExact());
+
+ // Copy the fast-math flags.
+ if (auto *FP = dyn_cast<FPMathOperator>(V))
+ copyFastMathFlags(FP->getFastMathFlags());
+}
+
+void Instruction::andIRFlags(const Value *V) {
+ if (auto *OB = dyn_cast<OverflowingBinaryOperator>(V)) {
+ setHasNoSignedWrap(hasNoSignedWrap() & OB->hasNoSignedWrap());
+ setHasNoUnsignedWrap(hasNoUnsignedWrap() & OB->hasNoUnsignedWrap());
+ }
+
+ if (auto *PE = dyn_cast<PossiblyExactOperator>(V))
+ setIsExact(isExact() & PE->isExact());
+
+ if (auto *FP = dyn_cast<FPMathOperator>(V)) {
+ FastMathFlags FM = getFastMathFlags();
+ FM &= FP->getFastMathFlags();
+ copyFastMathFlags(FM);
+ }
+}
const char *Instruction::getOpcodeName(unsigned OpCode) {
switch (OpCode) {
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 65703d13ec0..e17db659c2a 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -2201,62 +2201,6 @@ bool BinaryOperator::swapOperands() {
return false;
}
-void BinaryOperator::setHasNoUnsignedWrap(bool b) {
- cast<OverflowingBinaryOperator>(this)->setHasNoUnsignedWrap(b);
-}
-
-void BinaryOperator::setHasNoSignedWrap(bool b) {
- cast<OverflowingBinaryOperator>(this)->setHasNoSignedWrap(b);
-}
-
-void BinaryOperator::setIsExact(bool b) {
- cast<PossiblyExactOperator>(this)->setIsExact(b);
-}
-
-bool BinaryOperator::hasNoUnsignedWrap() const {
- return cast<OverflowingBinaryOperator>(this)->hasNoUnsignedWrap();
-}
-
-bool BinaryOperator::hasNoSignedWrap() const {
- return cast<OverflowingBinaryOperator>(this)->hasNoSignedWrap();
-}
-
-bool BinaryOperator::isExact() const {
- return cast<PossiblyExactOperator>(this)->isExact();
-}
-
-void BinaryOperator::copyIRFlags(const Value *V) {
- // Copy the wrapping flags.
- if (auto *OB = dyn_cast<OverflowingBinaryOperator>(V)) {
- setHasNoSignedWrap(OB->hasNoSignedWrap());
- setHasNoUnsignedWrap(OB->hasNoUnsignedWrap());
- }
-
- // Copy the exact flag.
- if (auto *PE = dyn_cast<PossiblyExactOperator>(V))
- setIsExact(PE->isExact());
-
- // Copy the fast-math flags.
- if (auto *FP = dyn_cast<FPMathOperator>(V))
- copyFastMathFlags(FP->getFastMathFlags());
-}
-
-void BinaryOperator::andIRFlags(const Value *V) {
- if (auto *OB = dyn_cast<OverflowingBinaryOperator>(V)) {
- setHasNoSignedWrap(hasNoSignedWrap() & OB->hasNoSignedWrap());
- setHasNoUnsignedWrap(hasNoUnsignedWrap() & OB->hasNoUnsignedWrap());
- }
-
- if (auto *PE = dyn_cast<PossiblyExactOperator>(V))
- setIsExact(isExact() & PE->isExact());
-
- if (auto *FP = dyn_cast<FPMathOperator>(V)) {
- FastMathFlags FM = getFastMathFlags();
- FM &= FP->getFastMathFlags();
- copyFastMathFlags(FM);
- }
-}
-
//===----------------------------------------------------------------------===//
// FPMathOperator Class
diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index 7be3aab272d..1d7da48321d 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -153,7 +153,7 @@ bool DenseMapInfo<SimpleValue>::isEqual(SimpleValue LHS, SimpleValue RHS) {
if (LHSI->getOpcode() != RHSI->getOpcode())
return false;
- if (LHSI->isIdenticalTo(RHSI))
+ if (LHSI->isIdenticalToWhenDefined(RHSI))
return true;
// If we're not strictly identical, we still might be a commutable instruction
@@ -165,15 +165,6 @@ bool DenseMapInfo<SimpleValue>::isEqual(SimpleValue LHS, SimpleValue RHS) {
"same opcode, but different instruction type?");
BinaryOperator *RHSBinOp = cast<BinaryOperator>(RHSI);
- // Check overflow attributes
- if (isa<OverflowingBinaryOperator>(LHSBinOp)) {
- assert(isa<OverflowingBinaryOperator>(RHSBinOp) &&
- "same opcode, but different operator type?");
- if (LHSBinOp->hasNoUnsignedWrap() != RHSBinOp->hasNoUnsignedWrap() ||
- LHSBinOp->hasNoSignedWrap() != RHSBinOp->hasNoSignedWrap())
- return false;
- }
-
// Commuted equality
return LHSBinOp->getOperand(0) == RHSBinOp->getOperand(1) &&
LHSBinOp->getOperand(1) == RHSBinOp->getOperand(0);
@@ -584,6 +575,8 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// See if the instruction has an available value. If so, use it.
if (Value *V = AvailableValues.lookup(Inst)) {
DEBUG(dbgs() << "EarlyCSE CSE: " << *Inst << " to: " << *V << '\n');
+ if (auto *I = dyn_cast<Instruction>(V))
+ I->andIRFlags(Inst);
Inst->replaceAllUsesWith(V);
Inst->eraseFromParent();
Changed = true;
diff --git a/llvm/test/Transforms/EarlyCSE/flags.ll b/llvm/test/Transforms/EarlyCSE/flags.ll
new file mode 100644
index 00000000000..d189012e4be
--- /dev/null
+++ b/llvm/test/Transforms/EarlyCSE/flags.ll
@@ -0,0 +1,18 @@
+; RUN: opt -early-cse -S < %s | FileCheck %s
+
+declare void @use(i1)
+
+define void @test1(float %x, float %y) {
+entry:
+ %cmp1 = fcmp nnan oeq float %y, %x
+ %cmp2 = fcmp oeq float %x, %y
+ call void @use(i1 %cmp1)
+ call void @use(i1 %cmp2)
+ ret void
+}
+
+; CHECK-LABEL: define void @test1(
+; CHECK: %[[cmp:.*]] = fcmp oeq float %y, %x
+; CHECK-NEXT: call void @use(i1 %[[cmp]])
+; CHECK-NEXT: call void @use(i1 %[[cmp]])
+; CHECK-NEXT: ret void
OpenPOWER on IntegriCloud