Skip to content

Commit 2bb95e7

Browse files
author
Max Kazantsev
committedFeb 13, 2019
[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
1 parent 84dcc8f commit 2bb95e7

File tree

3 files changed

+1145
-3
lines changed

3 files changed

+1145
-3
lines changed
 

‎llvm/lib/Transforms/Scalar/GuardWidening.cpp

+30-3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ static cl::opt<unsigned> FrequentBranchThreshold(
8282
"it is considered frequently taken"),
8383
cl::init(1000));
8484

85+
static cl::opt<bool>
86+
WidenBranchGuards("guard-widening-widen-branch-guards", cl::Hidden,
87+
cl::desc("Whether or not we should widen guards "
88+
"expressed as branches by widenable conditions"),
89+
cl::init(true));
8590

8691
namespace {
8792

@@ -92,6 +97,10 @@ static Value *getCondition(Instruction *I) {
9297
"Bad guard intrinsic?");
9398
return GI->getArgOperand(0);
9499
}
100+
if (isGuardAsWidenableBranch(I)) {
101+
auto *Cond = cast<BranchInst>(I)->getCondition();
102+
return cast<BinaryOperator>(Cond)->getOperand(0);
103+
}
95104
return cast<BranchInst>(I)->getCondition();
96105
}
97106

@@ -262,8 +271,16 @@ class GuardWideningImpl {
262271
void widenGuard(Instruction *ToWiden, Value *NewCondition,
263272
bool InvertCondition) {
264273
Value *Result;
265-
widenCondCommon(ToWiden->getOperand(0), NewCondition, ToWiden, Result,
274+
widenCondCommon(getCondition(ToWiden), NewCondition, ToWiden, Result,
266275
InvertCondition);
276+
Value *WidenableCondition = nullptr;
277+
if (isGuardAsWidenableBranch(ToWiden)) {
278+
auto *Cond = cast<BranchInst>(ToWiden)->getCondition();
279+
WidenableCondition = cast<BinaryOperator>(Cond)->getOperand(1);
280+
}
281+
if (WidenableCondition)
282+
Result = BinaryOperator::CreateAnd(Result, WidenableCondition,
283+
"guard.chk", ToWiden);
267284
setCondition(ToWiden, Result);
268285
}
269286

@@ -281,6 +298,14 @@ class GuardWideningImpl {
281298
};
282299
}
283300

301+
static bool isSupportedGuardInstruction(const Instruction *Insn) {
302+
if (isGuard(Insn))
303+
return true;
304+
if (WidenBranchGuards && isGuardAsWidenableBranch(Insn))
305+
return true;
306+
return false;
307+
}
308+
284309
bool GuardWideningImpl::run() {
285310
DenseMap<BasicBlock *, SmallVector<Instruction *, 8>> GuardsInBlock;
286311
bool Changed = false;
@@ -300,7 +325,7 @@ bool GuardWideningImpl::run() {
300325
auto &CurrentList = GuardsInBlock[BB];
301326

302327
for (auto &I : *BB)
303-
if (isGuard(&I))
328+
if (isSupportedGuardInstruction(&I))
304329
CurrentList.push_back(cast<Instruction>(&I));
305330

306331
for (auto *II : CurrentList)
@@ -322,7 +347,7 @@ bool GuardWideningImpl::run() {
322347
for (auto *I : EliminatedGuardsAndBranches)
323348
if (!WidenedGuards.count(I)) {
324349
assert(isa<ConstantInt>(getCondition(I)) && "Should be!");
325-
if (isGuard(I))
350+
if (isSupportedGuardInstruction(I))
326351
eliminateGuard(I);
327352
else {
328353
assert(isa<BranchInst>(I) &&
@@ -452,6 +477,8 @@ GuardWideningImpl::computeWideningScore(Instruction *DominatedInstr,
452477
auto MaybeHoistingOutOfIf = [&]() {
453478
auto *DominatingBlock = DominatingGuard->getParent();
454479
auto *DominatedBlock = DominatedInstr->getParent();
480+
if (isGuardAsWidenableBranch(DominatingGuard))
481+
DominatingBlock = cast<BranchInst>(DominatingGuard)->getSuccessor(0);
455482

456483
// Same Block?
457484
if (DominatedBlock == DominatingBlock)

‎llvm/test/Transforms/GuardWidening/basic_widenable_condition_guards.ll

+1,041
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -S -guard-widening-widen-branch-guards=true -guard-widening < %s | FileCheck %s
3+
; RUN: opt -S -guard-widening-widen-branch-guards=true -passes=guard-widening < %s | FileCheck %s
4+
5+
; Interaction between intrinsic and widenable condition guards.
6+
7+
declare void @llvm.experimental.guard(i1,...)
8+
9+
declare void @llvm.experimental.deoptimize.isVoid(...)
10+
11+
; Function Attrs: inaccessiblememonly nounwind
12+
declare i1 @llvm.experimental.widenable.condition() #0
13+
14+
; Widen condition of intrinsic guard with a condition from widenable branch.
15+
define void @test_01(i1 %cond_0, i1 %cond_1) {
16+
; CHECK-LABEL: @test_01(
17+
; CHECK-NEXT: entry:
18+
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
19+
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
20+
; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
21+
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
22+
; CHECK-NEXT: br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
23+
; CHECK: deopt2:
24+
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
25+
; CHECK-NEXT: ret void
26+
; CHECK: guarded1:
27+
; CHECK-NEXT: ret void
28+
;
29+
entry:
30+
call void (i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
31+
%widenable_cond3 = call i1 @llvm.experimental.widenable.condition()
32+
%exiplicit_guard_cond4 = and i1 %cond_1, %widenable_cond3
33+
br i1 %exiplicit_guard_cond4, label %guarded1, label %deopt2, !prof !0
34+
35+
deopt2: ; preds = %guarded
36+
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
37+
ret void
38+
39+
guarded1: ; preds = %guarded
40+
ret void
41+
}
42+
43+
; Widen condition of widenable condition guard with a condition from intrinsic.
44+
define void @test_02(i1 %cond_0, i1 %cond_1) {
45+
; CHECK-LABEL: @test_02(
46+
; CHECK-NEXT: entry:
47+
; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
48+
; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND_0:%.*]], [[WIDENABLE_COND]]
49+
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1:%.*]]
50+
; CHECK-NEXT: [[GUARD_CHK:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
51+
; CHECK-NEXT: br i1 [[GUARD_CHK]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
52+
; CHECK: deopt:
53+
; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
54+
; CHECK-NEXT: ret void
55+
; CHECK: guarded:
56+
; CHECK-NEXT: ret void
57+
;
58+
entry:
59+
%widenable_cond = call i1 @llvm.experimental.widenable.condition()
60+
%exiplicit_guard_cond = and i1 %cond_0, %widenable_cond
61+
br i1 %exiplicit_guard_cond, label %guarded, label %deopt, !prof !0
62+
63+
deopt: ; preds = %entry
64+
call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
65+
ret void
66+
67+
guarded: ; preds = %entry
68+
call void (i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
69+
ret void
70+
}
71+
72+
attributes #0 = { inaccessiblememonly nounwind }
73+
74+
!0 = !{!"branch_weights", i32 1048576, i32 1}

0 commit comments

Comments
 (0)
Please sign in to comment.