forked from OSchip/llvm-project
[GuardWidening] Support widening of explicitly expressed guards
This patch adds support of guards expressed in explicit form via `widenable_condition` in Guard Widening pass. Differential Revision: https://reviews.llvm.org/D56075 Reviewed By: reames llvm-svn: 353932
This commit is contained in:
parent
84dcc8f36f
commit
2bb95e7c76
|
@ -82,6 +82,11 @@ static cl::opt<unsigned> FrequentBranchThreshold(
|
|||
"it is considered frequently taken"),
|
||||
cl::init(1000));
|
||||
|
||||
static cl::opt<bool>
|
||||
WidenBranchGuards("guard-widening-widen-branch-guards", cl::Hidden,
|
||||
cl::desc("Whether or not we should widen guards "
|
||||
"expressed as branches by widenable conditions"),
|
||||
cl::init(true));
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -92,6 +97,10 @@ static Value *getCondition(Instruction *I) {
|
|||
"Bad guard intrinsic?");
|
||||
return GI->getArgOperand(0);
|
||||
}
|
||||
if (isGuardAsWidenableBranch(I)) {
|
||||
auto *Cond = cast<BranchInst>(I)->getCondition();
|
||||
return cast<BinaryOperator>(Cond)->getOperand(0);
|
||||
}
|
||||
return cast<BranchInst>(I)->getCondition();
|
||||
}
|
||||
|
||||
|
@ -262,8 +271,16 @@ class GuardWideningImpl {
|
|||
void widenGuard(Instruction *ToWiden, Value *NewCondition,
|
||||
bool InvertCondition) {
|
||||
Value *Result;
|
||||
widenCondCommon(ToWiden->getOperand(0), NewCondition, ToWiden, Result,
|
||||
widenCondCommon(getCondition(ToWiden), NewCondition, ToWiden, Result,
|
||||
InvertCondition);
|
||||
Value *WidenableCondition = nullptr;
|
||||
if (isGuardAsWidenableBranch(ToWiden)) {
|
||||
auto *Cond = cast<BranchInst>(ToWiden)->getCondition();
|
||||
WidenableCondition = cast<BinaryOperator>(Cond)->getOperand(1);
|
||||
}
|
||||
if (WidenableCondition)
|
||||
Result = BinaryOperator::CreateAnd(Result, WidenableCondition,
|
||||
"guard.chk", ToWiden);
|
||||
setCondition(ToWiden, Result);
|
||||
}
|
||||
|
||||
|
@ -281,6 +298,14 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
static bool isSupportedGuardInstruction(const Instruction *Insn) {
|
||||
if (isGuard(Insn))
|
||||
return true;
|
||||
if (WidenBranchGuards && isGuardAsWidenableBranch(Insn))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GuardWideningImpl::run() {
|
||||
DenseMap<BasicBlock *, SmallVector<Instruction *, 8>> GuardsInBlock;
|
||||
bool Changed = false;
|
||||
|
@ -300,7 +325,7 @@ bool GuardWideningImpl::run() {
|
|||
auto &CurrentList = GuardsInBlock[BB];
|
||||
|
||||
for (auto &I : *BB)
|
||||
if (isGuard(&I))
|
||||
if (isSupportedGuardInstruction(&I))
|
||||
CurrentList.push_back(cast<Instruction>(&I));
|
||||
|
||||
for (auto *II : CurrentList)
|
||||
|
@ -322,7 +347,7 @@ bool GuardWideningImpl::run() {
|
|||
for (auto *I : EliminatedGuardsAndBranches)
|
||||
if (!WidenedGuards.count(I)) {
|
||||
assert(isa<ConstantInt>(getCondition(I)) && "Should be!");
|
||||
if (isGuard(I))
|
||||
if (isSupportedGuardInstruction(I))
|
||||
eliminateGuard(I);
|
||||
else {
|
||||
assert(isa<BranchInst>(I) &&
|
||||
|
@ -452,6 +477,8 @@ GuardWideningImpl::computeWideningScore(Instruction *DominatedInstr,
|
|||
auto MaybeHoistingOutOfIf = [&]() {
|
||||
auto *DominatingBlock = DominatingGuard->getParent();
|
||||
auto *DominatedBlock = DominatedInstr->getParent();
|
||||
if (isGuardAsWidenableBranch(DominatingGuard))
|
||||
DominatingBlock = cast<BranchInst>(DominatingGuard)->getSuccessor(0);
|
||||
|
||||
// Same Block?
|
||||
if (DominatedBlock == DominatingBlock)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,74 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -S -guard-widening-widen-branch-guards=true -guard-widening < %s | FileCheck %s
|
||||
; RUN: opt -S -guard-widening-widen-branch-guards=true -passes=guard-widening < %s | FileCheck %s
|
||||
|
||||
; Interaction between intrinsic and widenable condition guards.
|
||||
|
||||
declare void @llvm.experimental.guard(i1,...)
|
||||
|
||||
declare void @llvm.experimental.deoptimize.isVoid(...)
|
||||
|
||||
; Function Attrs: inaccessiblememonly nounwind
|
||||
declare i1 @llvm.experimental.widenable.condition() #0
|
||||
|
||||
; Widen condition of intrinsic guard with a condition from widenable branch.
|
||||
define void @test_01(i1 %cond_0, i1 %cond_1) {
|
||||
; CHECK-LABEL: @test_01(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
|
||||
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
|
||||
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
||||
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
|
||||
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
|
||||
; CHECK: deopt2:
|
||||
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: guarded1:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
call void (i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
|
||||
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
|
||||
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
|
||||
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
|
||||
|
||||
deopt2: ; preds = %guarded
|
||||
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
||||
ret void
|
||||
|
||||
guarded1: ; preds = %guarded
|
||||
ret void
|
||||
}
|
||||
|
||||
; Widen condition of widenable condition guard with a condition from intrinsic.
|
||||
define void @test_02(i1 %cond_0, i1 %cond_1) {
|
||||
; CHECK-LABEL: @test_02(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
|
||||
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0:%.*]], [[WIDENABLE_COND]]
|
||||
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1:%.*]]
|
||||
; CHECK-NEXT: [[GUARD_CHK:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
|
||||
; CHECK-NEXT: br i1 [[GUARD_CHK]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
|
||||
; CHECK: deopt:
|
||||
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: guarded:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
|
||||
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
|
||||
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
|
||||
|
||||
deopt: ; preds = %entry
|
||||
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
|
||||
ret void
|
||||
|
||||
guarded: ; preds = %entry
|
||||
call void (i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { inaccessiblememonly nounwind }
|
||||
|
||||
!0 = !{!"branch_weights", i32 1048576, i32 1}
|
Loading…
Reference in New Issue