[EarlyCSE] Add debug counter for debugging mis-optimizations. NFC.

Reviewers: reames, spatel, davide, dberlin

Subscribers: mcrosier, llvm-commits

Differential Revision: https://reviews.llvm.org/D45162

llvm-svn: 329443
This commit is contained in:
Geoff Berry 2018-04-06 18:47:33 +00:00
parent 398e5f03a7
commit 18fcd57acc
2 changed files with 87 additions and 24 deletions

View File

@ -50,6 +50,7 @@
#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DebugCounter.h"
#include "llvm/Support/RecyclingAllocator.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
@ -70,6 +71,9 @@ STATISTIC(NumCSELoad, "Number of load instructions CSE'd");
STATISTIC(NumCSECall, "Number of call instructions CSE'd");
STATISTIC(NumDSE, "Number of trivial dead stores removed");
DEBUG_COUNTER(CSECounter, "early-cse",
"Controls which instructions are removed");
//===----------------------------------------------------------------------===//
// SimpleValue
//===----------------------------------------------------------------------===//
@ -727,11 +731,15 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
DEBUG(dbgs() << "EarlyCSE CVP: Add conditional value for '"
<< CondInst->getName() << "' as " << *TorF << " in "
<< BB->getName() << "\n");
// Replace all dominated uses with the known value.
if (unsigned Count = replaceDominatedUsesWith(
CondInst, TorF, DT, BasicBlockEdge(Pred, BB))) {
Changed = true;
NumCSECVP += Count;
if (!DebugCounter::shouldExecute(CSECounter)) {
DEBUG(dbgs() << "Skipping due to debug counter\n");
} else {
// Replace all dominated uses with the known value.
if (unsigned Count = replaceDominatedUsesWith(
CondInst, TorF, DT, BasicBlockEdge(Pred, BB))) {
Changed = true;
NumCSECVP += Count;
}
}
}
}
@ -751,6 +759,10 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// Dead instructions should just be removed.
if (isInstructionTriviallyDead(Inst, &TLI)) {
DEBUG(dbgs() << "EarlyCSE DCE: " << *Inst << '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
salvageDebugInfo(*Inst);
removeMSSA(Inst);
Inst->eraseFromParent();
@ -840,21 +852,25 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// its simpler value.
if (Value *V = SimplifyInstruction(Inst, SQ)) {
DEBUG(dbgs() << "EarlyCSE Simplify: " << *Inst << " to: " << *V << '\n');
bool Killed = false;
if (!Inst->use_empty()) {
Inst->replaceAllUsesWith(V);
Changed = true;
if (!DebugCounter::shouldExecute(CSECounter)) {
DEBUG(dbgs() << "Skipping due to debug counter\n");
} else {
bool Killed = false;
if (!Inst->use_empty()) {
Inst->replaceAllUsesWith(V);
Changed = true;
}
if (isInstructionTriviallyDead(Inst, &TLI)) {
removeMSSA(Inst);
Inst->eraseFromParent();
Changed = true;
Killed = true;
}
if (Changed)
++NumSimplify;
if (Killed)
continue;
}
if (isInstructionTriviallyDead(Inst, &TLI)) {
removeMSSA(Inst);
Inst->eraseFromParent();
Changed = true;
Killed = true;
}
if (Changed)
++NumSimplify;
if (Killed)
continue;
}
// If this is a simple instruction that we can value number, process it.
@ -862,6 +878,10 @@ 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 (!DebugCounter::shouldExecute(CSECounter)) {
DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
if (auto *I = dyn_cast<Instruction>(V))
I->andIRFlags(Inst);
Inst->replaceAllUsesWith(V);
@ -919,6 +939,10 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
if (Op != nullptr) {
DEBUG(dbgs() << "EarlyCSE CSE LOAD: " << *Inst
<< " to: " << *InVal.DefInst << '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
if (!Inst->use_empty())
Inst->replaceAllUsesWith(Op);
removeMSSA(Inst);
@ -958,6 +982,10 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
Inst)) {
DEBUG(dbgs() << "EarlyCSE CSE CALL: " << *Inst
<< " to: " << *InVal.first << '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
if (!Inst->use_empty())
Inst->replaceAllUsesWith(InVal.first);
removeMSSA(Inst);
@ -1009,6 +1037,10 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
MSSA) &&
"can't have an intervening store if not using MemorySSA!");
DEBUG(dbgs() << "EarlyCSE DSE (writeback): " << *Inst << '\n');
if (!DebugCounter::shouldExecute(CSECounter)) {
DEBUG(dbgs() << "Skipping due to debug counter\n");
continue;
}
removeMSSA(Inst);
Inst->eraseFromParent();
Changed = true;
@ -1041,11 +1073,15 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
if (LastStoreMemInst.isMatchingMemLoc(MemInst)) {
DEBUG(dbgs() << "EarlyCSE DEAD STORE: " << *LastStore
<< " due to: " << *Inst << '\n');
removeMSSA(LastStore);
LastStore->eraseFromParent();
Changed = true;
++NumDSE;
LastStore = nullptr;
if (!DebugCounter::shouldExecute(CSECounter)) {
DEBUG(dbgs() << "Skipping due to debug counter\n");
} else {
removeMSSA(LastStore);
LastStore->eraseFromParent();
Changed = true;
++NumDSE;
LastStore = nullptr;
}
}
// fallthrough - we can exploit information about this store
}

View File

@ -0,0 +1,27 @@
; REQUIRES: asserts
; RUN: opt -S -debug-counter=early-cse-skip=1,early-cse-count=1 -early-cse < %s 2>&1 | FileCheck %s
;; Test that, with debug counters on, we only optimize the second CSE opportunity.
define i32 @test(i32 %a, i32 %b) {
; CHECK-LABEL: @test(
; CHECK-NEXT: bb:
; CHECK-NEXT: %add1 = add i32 %a, %b
; CHECK-NEXT: %add2 = add i32 %a, %b
; CHECK-NEXT: %add4 = add i32 %a, %b
; CHECK-NEXT: %ret1 = add i32 %add1, %add2
; CHECK-NEXT: %ret2 = add i32 %add1, %add4
; CHECK-NEXT: %ret = add i32 %ret1, %ret2
; CHECK-NEXT: ret i32 %ret
;
bb:
%add1 = add i32 %a, %b
%add2 = add i32 %a, %b
%add3 = add i32 %a, %b
%add4 = add i32 %a, %b
%ret1 = add i32 %add1, %add2
%ret2 = add i32 %add3, %add4
%ret = add i32 %ret1, %ret2
ret i32 %ret
}