[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:
Max Kazantsev 2019-02-13 09:56:30 +00:00
parent 84dcc8f36f
commit 2bb95e7c76
3 changed files with 1145 additions and 3 deletions

View File

@ -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

View File

@ -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}