[SCCP] Turn sext into zext for non-negative ranges.

This patch updates SCCP/IPSCCP to use the computed range info to turn
sexts into zexts, if the value is known to be non-negative. We already
to a similar transform in CorrelatedValuePropagation, but it seems like
we can catch a lot of additional cases by doing it in SCCP/IPSCCP as
well.

The transform is limited to ranges that are known to not include undef.

Currently constant ranges from conditions are treated as potentially
containing undef, due to PR46144. Once we flip this, the transform will
be more effective in practice.

Reviewers: efriedma, davide

Reviewed By: efriedma

Differential Revision: https://reviews.llvm.org/D81756
This commit is contained in:
Florian Hahn 2020-06-19 09:27:52 +01:00
parent 7cdf4326a8
commit f9d8e33c32
5 changed files with 45 additions and 16 deletions

View File

@ -67,10 +67,15 @@ using namespace llvm;
STATISTIC(NumInstRemoved, "Number of instructions removed");
STATISTIC(NumDeadBlocks , "Number of basic blocks unreachable");
STATISTIC(NumInstReplaced,
"Number of instructions replaced with (simpler) instruction");
STATISTIC(IPNumInstRemoved, "Number of instructions removed by IPSCCP");
STATISTIC(IPNumArgsElimed ,"Number of arguments constant propagated by IPSCCP");
STATISTIC(IPNumGlobalConst, "Number of globals found to be constant by IPSCCP");
STATISTIC(
IPNumInstReplaced,
"Number of instructions replaced with (simpler) instruction by IPSCCP");
// The maximum number of range extensions allowed for operations requiring
// widening.
@ -283,6 +288,8 @@ public:
return StructValues;
}
void removeLatticeValueFor(Value *V) { ValueState.erase(V); }
const ValueLatticeElement &getLatticeValueFor(Value *V) const {
assert(!V->getType()->isStructTy() &&
"Should use getStructLatticeValueFor");
@ -1607,7 +1614,9 @@ static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) {
}
static bool simplifyInstsInBlock(SCCPSolver &Solver, BasicBlock &BB,
Statistic &InstRemovedStat) {
SmallPtrSetImpl<Value *> &InsertedValues,
Statistic &InstRemovedStat,
Statistic &InstReplacedStat) {
bool MadeChanges = false;
for (Instruction &Inst : make_early_inc_range(BB)) {
if (Inst.getType()->isVoidTy())
@ -1618,6 +1627,22 @@ static bool simplifyInstsInBlock(SCCPSolver &Solver, BasicBlock &BB,
// Hey, we just changed something!
MadeChanges = true;
++InstRemovedStat;
} else if (isa<SExtInst>(&Inst)) {
Value *ExtOp = Inst.getOperand(0);
if (isa<Constant>(ExtOp) || InsertedValues.count(ExtOp))
continue;
const ValueLatticeElement &IV = Solver.getLatticeValueFor(ExtOp);
if (!IV.isConstantRange(/*UndefAllowed=*/false))
continue;
if (IV.getConstantRange().isAllNonNegative()) {
auto *ZExt = new ZExtInst(ExtOp, Inst.getType(), "", &Inst);
InsertedValues.insert(ZExt);
Inst.replaceAllUsesWith(ZExt);
Solver.removeLatticeValueFor(&Inst);
Inst.eraseFromParent();
InstReplacedStat++;
MadeChanges = true;
}
}
}
return MadeChanges;
@ -1653,6 +1678,7 @@ static bool runSCCP(Function &F, const DataLayout &DL,
// delete their contents now. Note that we cannot actually delete the blocks,
// as we cannot modify the CFG of the function.
SmallPtrSet<Value *, 32> InsertedValues;
for (BasicBlock &BB : F) {
if (!Solver.isBlockExecutable(&BB)) {
LLVM_DEBUG(dbgs() << " BasicBlock Dead:" << BB);
@ -1664,7 +1690,8 @@ static bool runSCCP(Function &F, const DataLayout &DL,
continue;
}
MadeChanges |= simplifyInstsInBlock(Solver, BB, NumInstRemoved);
MadeChanges |= simplifyInstsInBlock(Solver, BB, InsertedValues,
NumInstRemoved, NumInstReplaced);
}
return MadeChanges;
@ -1893,6 +1920,7 @@ bool llvm::runIPSCCP(
}
}
SmallPtrSet<Value *, 32> InsertedValues;
for (BasicBlock &BB : F) {
if (!Solver.isBlockExecutable(&BB)) {
LLVM_DEBUG(dbgs() << " BasicBlock Dead:" << BB);
@ -1905,7 +1933,8 @@ bool llvm::runIPSCCP(
continue;
}
MadeChanges |= simplifyInstsInBlock(Solver, BB, IPNumInstRemoved);
MadeChanges |= simplifyInstsInBlock(Solver, BB, InsertedValues,
IPNumInstRemoved, IPNumInstReplaced);
}
DomTreeUpdater DTU = Solver.getDTU(F);

View File

@ -109,9 +109,9 @@ define i1 @caller.zext() {
; x = [100, 301)
define internal i1 @f.sext(i32 %x, i32 %y) {
; CHECK-LABEL: define internal i1 @f.sext(i32 %x, i32 %y) {
; CHECK-NEXT: %t.1 = sext i32 %x to i64
; CHECK-NEXT: %c.2 = icmp sgt i64 %t.1, 299
; CHECK-NEXT: %c.4 = icmp slt i64 %t.1, 101
; CHECK-NEXT: [[T_1:%.*]] = zext i32 %x to i64
; CHECK-NEXT: %c.2 = icmp sgt i64 [[T_1]], 299
; CHECK-NEXT: %c.4 = icmp slt i64 [[T_1]], 101
; CHECK-NEXT: %res.1 = add i1 false, %c.2
; CHECK-NEXT: %res.2 = add i1 %res.1, false
; CHECK-NEXT: %res.3 = add i1 %res.2, %c.4

View File

@ -105,8 +105,8 @@ exit:
define i64 @test5(i32 %x) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: [[P:%.*]] = and i32 [[X:%.*]], 15
; CHECK-NEXT: [[EXT:%.*]] = sext i32 [[P]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[P]] to i64
; CHECK-NEXT: ret i64 [[TMP1]]
;
%p = and i32 %x, 15
%ext = sext i32 %p to i64
@ -126,8 +126,8 @@ define i64 @test6(i32 %x) {
define i64 @test7(i16 %x) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: [[P:%.*]] = and i16 [[X:%.*]], 15
; CHECK-NEXT: [[EXT_1:%.*]] = sext i16 [[P]] to i32
; CHECK-NEXT: [[EXT_2:%.*]] = sext i32 [[EXT_1]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = zext i16 [[P]] to i32
; CHECK-NEXT: [[EXT_2:%.*]] = sext i32 [[TMP1]] to i64
; CHECK-NEXT: ret i64 [[EXT_2]]
;
%p = and i16 %x, 15

View File

@ -35,8 +35,8 @@ exit:
define i64 @test2(i32 %x) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: [[P:%.*]] = and i32 [[X:%.*]], 15
; CHECK-NEXT: [[EXT:%.*]] = sext i32 [[P]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[P]] to i64
; CHECK-NEXT: ret i64 [[TMP1]]
;
%p = and i32 %x, 15
%ext = sext i32 %p to i64
@ -54,8 +54,8 @@ define i64 @test3(i1 %c.1, i1 %c.2) {
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[TRUE_1]] ], [ 1, [[TRUE_2]] ], [ 3, [[FALSE]] ]
; CHECK-NEXT: [[EXT:%.*]] = sext i32 [[P]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[P]] to i64
; CHECK-NEXT: ret i64 [[TMP1]]
;
br i1 %c.1, label %true.1, label %false

View File

@ -451,7 +451,7 @@ define void @foo(i64* %arg) {
; SCCP-NEXT: [[TMP7:%.*]] = sub i64 3, [[TMP6]]
; SCCP-NEXT: [[TMP8:%.*]] = shl i64 [[TMP7]], 1
; SCCP-NEXT: [[TMP9:%.*]] = trunc i64 [[TMP8]] to i32
; SCCP-NEXT: [[TMP10:%.*]] = sext i32 [[TMP9]] to i64
; SCCP-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
; SCCP-NEXT: br label [[BB11:%.*]]
; SCCP: bb11:
; SCCP-NEXT: [[TMP12:%.*]] = phi i64 [ [[TMP10]], [[BB4]] ], [ [[TMP17:%.*]], [[BB18:%.*]] ]
@ -489,7 +489,7 @@ define void @foo(i64* %arg) {
; IPSCCP-NEXT: [[TMP7:%.*]] = sub i64 3, [[TMP6]]
; IPSCCP-NEXT: [[TMP8:%.*]] = shl i64 [[TMP7]], 1
; IPSCCP-NEXT: [[TMP9:%.*]] = trunc i64 [[TMP8]] to i32
; IPSCCP-NEXT: [[TMP10:%.*]] = sext i32 [[TMP9]] to i64
; IPSCCP-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
; IPSCCP-NEXT: br label [[BB11:%.*]]
; IPSCCP: bb11:
; IPSCCP-NEXT: [[TMP12:%.*]] = phi i64 [ [[TMP10]], [[BB4]] ], [ [[TMP17:%.*]], [[BB18:%.*]] ]