forked from OSchip/llvm-project
[CVP] Use LVI to constant fold deopt operands
Deopt operands are generally intended to record information about a site in code with minimal perturbation of the surrounding code. Idiomatically, they also tend to appear down rare paths. Putting these together, we have an obvious case for extending CVP w/deopt operand constant folding. Arguably, we should be doing this for all operands on all instructions, but that's definitely a much larger and risky change. Differential Revision: https://reviews.llvm.org/D55678 llvm-svn: 351774
This commit is contained in:
parent
9846f5f792
commit
390c0e2f72
|
@ -823,7 +823,9 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
|
|||
if (!GuardDecl || GuardDecl->use_empty())
|
||||
return;
|
||||
|
||||
for (Instruction &I : make_range(BBI->getIterator().getReverse(),
|
||||
if (BBI->getIterator() == BBI->getParent()->begin())
|
||||
return;
|
||||
for (Instruction &I : make_range(std::next(BBI->getIterator().getReverse()),
|
||||
BBI->getParent()->rend())) {
|
||||
Value *Cond = nullptr;
|
||||
if (match(&I, m_Intrinsic<Intrinsic::experimental_guard>(m_Value(Cond))))
|
||||
|
|
|
@ -462,6 +462,30 @@ static bool processCallSite(CallSite CS, LazyValueInfo *LVI) {
|
|||
}
|
||||
}
|
||||
|
||||
// Deopt bundle operands are intended to capture state with minimal
|
||||
// perturbance of the code otherwise. If we can find a constant value for
|
||||
// any such operand and remove a use of the original value, that's
|
||||
// desireable since it may allow further optimization of that value (e.g. via
|
||||
// single use rules in instcombine). Since deopt uses tend to,
|
||||
// idiomatically, appear along rare conditional paths, it's reasonable likely
|
||||
// we may have a conditional fact with which LVI can fold.
|
||||
if (auto DeoptBundle = CS.getOperandBundle(LLVMContext::OB_deopt)) {
|
||||
bool Progress = false;
|
||||
for (const Use &ConstU : DeoptBundle->Inputs) {
|
||||
Use &U = const_cast<Use&>(ConstU);
|
||||
Value *V = U.get();
|
||||
if (V->getType()->isVectorTy()) continue;
|
||||
if (isa<Constant>(V)) continue;
|
||||
|
||||
Constant *C = LVI->getConstant(V, CS.getParent(), CS.getInstruction());
|
||||
if (!C) continue;
|
||||
U.set(C);
|
||||
Progress = true;
|
||||
}
|
||||
if (Progress)
|
||||
return true;
|
||||
}
|
||||
|
||||
for (Value *V : CS.args()) {
|
||||
PointerType *Type = dyn_cast<PointerType>(V->getType());
|
||||
// Try to mark pointer typed parameters as non-null. We skip the
|
||||
|
|
|
@ -11,7 +11,7 @@ define void @test1(i1 %c, i1 %c2) {
|
|||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[SEL2]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
|
||||
; CHECK: taken:
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 [[SEL2]]) ]
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 1) ]
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: untaken:
|
||||
; CHECK-NEXT: ret void
|
||||
|
@ -37,7 +37,7 @@ define void @test1_assume(i1 %c, i1 %c2) {
|
|||
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[C2:%.*]], i64 [[SEL]], i64 0
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[SEL2]], 0
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 [[SEL2]]) ]
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 1) ]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%sel = select i1 %c, i64 -1, i64 1
|
||||
|
@ -55,7 +55,7 @@ define void @test1_guard(i1 %c, i1 %c2) {
|
|||
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[C2:%.*]], i64 [[SEL]], i64 0
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[SEL2]], 0
|
||||
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[CMP]]) [ "deopt"(i64 [[SEL2]]) ]
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 [[SEL2]]) ]
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 1) ]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%sel = select i1 %c, i64 -1, i64 1
|
||||
|
@ -76,7 +76,7 @@ define void @test2(i1 %c, i1 %c2) {
|
|||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[SEL2]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
|
||||
; CHECK: taken:
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 [[SEL2]]) ]
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 1) ]
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: untaken:
|
||||
; CHECK-NEXT: ret void
|
||||
|
@ -98,7 +98,7 @@ define void @test3(i1 %c, i1 %c2) {
|
|||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[SEL2]], 1
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
|
||||
; CHECK: taken:
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 [[SEL2]]) ]
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 2) ]
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: untaken:
|
||||
; CHECK-NEXT: ret void
|
||||
|
@ -120,10 +120,10 @@ define void @test4(i1 %c, i1 %c2) {
|
|||
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[C2:%.*]], i64 0, i64 1
|
||||
; CHECK-NEXT: [[ADD1:%.*]] = add i64 0, [[SEL]]
|
||||
; CHECK-NEXT: [[ADD2:%.*]] = add i64 [[ADD1]], [[SEL2]]
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[ADD2]], 0
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[ADD2]], 1
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]]
|
||||
; CHECK: taken:
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 [[ADD2]]) ]
|
||||
; CHECK-NEXT: call void @use() [ "deopt"(i64 2) ]
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: untaken:
|
||||
; CHECK-NEXT: ret void
|
||||
|
@ -132,7 +132,7 @@ define void @test4(i1 %c, i1 %c2) {
|
|||
%sel2 = select i1 %c2, i64 0, i64 1
|
||||
%add1 = add i64 0, %sel
|
||||
%add2 = add i64 %add1, %sel2
|
||||
%cmp = icmp sgt i64 %add2, 0
|
||||
%cmp = icmp sgt i64 %add2, 1
|
||||
br i1 %cmp, label %taken, label %untaken
|
||||
taken:
|
||||
call void @use() ["deopt" (i64 %add2)]
|
||||
|
|
Loading…
Reference in New Issue