llvm.org GIT mirror llvm / c05ba54
Introduce llvm.experimental.widenable_condition intrinsic This patch introduces a new instinsic `@llvm.experimental.widenable_condition` that allows explicit representation for guards. It is an alternative to using `@llvm.experimental.guard` intrinsic that does not contain implicit control flow. We keep finding places where `@llvm.experimental.guard` is not supported or treated too conservatively, and there are 2 reasons to that: - `@llvm.experimental.guard` has memory write side effect to model implicit control flow, and this sometimes confuses passes and analyzes that work with memory; - Not all passes and analysis are aware of the semantics of guards. These passes treat them as regular throwing call and have no idea that the condition of guard may be used to prove something. One well-known place which had caused us troubles in the past is explicit loop iteration count calculation in SCEV. Another example is new loop unswitching which is not aware of guards. Whenever a new pass appears, we potentially have this problem there. Rather than go and fix all these places (and commit to keep track of them and add support in future), it seems more reasonable to leverage the existing optimizer's logic as much as possible. The only significant difference between guards and regular explicit branches is that guard's condition can be widened. It means that a guard contains (explicitly or implicitly) a `deopt` block successor, and it is always legal to go there no matter what the guard condition is. The other successor is a guarded block, and it is only legal to go there if the condition is true. This patch introduces a new explicit form of guards alternative to `@llvm.experimental.guard` intrinsic. Now a widenable guard can be represented in the CFG explicitly like this: %widenable_condition = call i1 @llvm.experimental.widenable.condition() %new_condition = and i1 %cond, %widenable_condition br i1 %new_condition, label %guarded, label %deopt guarded: ; Guarded instructions deopt: call type @llvm.experimental.deoptimize(<args...>) [ "deopt"(<deopt_args...>) ] The new intrinsic `@llvm.experimental.widenable.condition` has semantics of an `undef`, but the intrinsic prevents the optimizer from folding it early. This form should exploit all optimization boons provided to `br` instuction, and it still can be widened by replacing the result of `@llvm.experimental.widenable.condition()` with `and` with any arbitrary boolean value (as long as the branch that is taken when it is `false` has a deopt and has no side-effects). For more motivation, please check llvm-dev discussion "[llvm-dev] Giving up using implicit control flow in guards". This patch introduces this new intrinsic with respective LangRef changes and a pass that converts old-style guards (expressed as intrinsics) into the new form. The naming discussion is still ungoing. Merging this to unblock further items. We can later change the name of this intrinsic. Reviewed By: reames, fedor.sergeev, sanjoy Differential Revision: https://reviews.llvm.org/D51207 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@348593 91177308-0d34-0410-b5e6-96231b3b80d8 Max Kazantsev 9 months ago
11 changed file(s) with 532 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
1560315603 ``@llvm.experimental.guard`` cannot be invoked.
1560415604
1560515605
15606 '``llvm.experimental.widenable.condition``' Intrinsic
15607 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15608
15609 Syntax:
15610 """""""
15611
15612 ::
15613
15614 declare i1 @llvm.experimental.widenable.condition()
15615
15616 Overview:
15617 """""""""
15618
15619 This intrinsic represents a "widenable condition" which is
15620 boolean expressions with the following property: whether this
15621 expression is `true` or `false`, the program is correct and
15622 well-defined.
15623
15624 Together with :ref:`deoptimization operand bundles `,
15625 ``@llvm.experimental.widenable.condition`` allows frontends to
15626 express guards or checks on optimistic assumptions made during
15627 compilation and represent them as branch instructions on special
15628 conditions.
15629
15630 While this may appear similar in semantics to `undef`, it is very
15631 different in that an invocation produces a particular, singular
15632 value. It is also intended to be lowered late, and remain available
15633 for specific optimizations and transforms that can benefit from its
15634 special properties.
15635
15636 Arguments:
15637 """"""""""
15638
15639 None.
15640
15641 Semantics:
15642 """"""""""
15643
15644 The intrinsic ``@llvm.experimental.widenable.condition()``
15645 returns either `true` or `false`. For each evaluation of a call
15646 to this intrinsic, the program must be valid and correct both if
15647 it returns `true` and if it returns `false`. This allows
15648 transformation passes to replace evaluations of this intrinsic
15649 with either value whenever one is beneficial.
15650
15651 When used in a branch condition, it allows us to choose between
15652 two alternative correct solutions for the same problem, like
15653 in example below:
15654
15655 .. code-block:: text
15656
15657 %cond = call i1 @llvm.experimental.widenable.condition()
15658 br i1 %cond, label %solution_1, label %solution_2
15659
15660 label %fast_path:
15661 ; Apply memory-consuming but fast solution for a task.
15662
15663 label %slow_path:
15664 ; Cheap in memory but slow solution.
15665
15666 Whether the result of intrinsic's call is `true` or `false`,
15667 it should be correct to pick either solution. We can switch
15668 between them by replacing the result of
15669 ``@llvm.experimental.widenable.condition`` with different
15670 `i1` expressions.
15671
15672 This is how it can be used to represent guards as widenable branches:
15673
15674 .. code-block:: text
15675
15676 block:
15677 ; Unguarded instructions
15678 call void @llvm.experimental.guard(i1 %cond, ) ["deopt"()]
15679 ; Guarded instructions
15680
15681 Can be expressed in an alternative equivalent form of explicit branch using
15682 ``@llvm.experimental.widenable.condition``:
15683
15684 .. code-block:: text
15685
15686 block:
15687 ; Unguarded instructions
15688 %widenable_condition = call i1 @llvm.experimental.widenable.condition()
15689 %guard_condition = and i1 %cond, %widenable_condition
15690 br i1 %guard_condition, label %guarded, label %deopt
15691
15692 guarded:
15693 ; Guarded instructions
15694
15695 deopt:
15696 call type @llvm.experimental.deoptimize() [ "deopt"() ]
15697
15698 So the block `guarded` is only reachable when `%cond` is `true`,
15699 and it should be valid to go to the block `deopt` whenever `%cond`
15700 is `true` or `false`.
15701
15702 ``@llvm.experimental.widenable.condition`` will never throw, thus
15703 it cannot be invoked.
15704
15705 Guard widening:
15706 """""""""""""""
15707
15708 When ``@llvm.experimental.widenable.condition()`` is used in
15709 condition of a guard represented as explicit branch, it is
15710 legal to widen the guard's condition with any additional
15711 conditions.
15712
15713 Guard widening looks like replacement of
15714
15715 .. code-block:: text
15716
15717 %widenable_cond = call i1 @llvm.experimental.widenable.condition()
15718 %guard_cond = and i1 %cond, %widenable_cond
15719 br i1 %guard_cond, label %guarded, label %deopt
15720
15721 with
15722
15723 .. code-block:: text
15724
15725 %widenable_cond = call i1 @llvm.experimental.widenable.condition()
15726 %new_cond = and i1 %any_other_cond, %widenable_cond
15727 %new_guard_cond = and i1 %cond, %new_cond
15728 br i1 %new_guard_cond, label %guarded, label %deopt
15729
15730 for this branch. Here `%any_other_cond` is an arbitrarily chosen
15731 well-defined `i1` value. By making guard widening, we may
15732 impose stricter conditions on `guarded` block and bail to the
15733 deopt when the new condition is not met.
15734
15735 Lowering:
15736 """""""""
15737
15738 Default lowering strategy is replacing the result of
15739 call of ``@llvm.experimental.widenable.condition`` with
15740 constant `true`. However it is always correct to replace
15741 it with any other `i1` value. Any pass can
15742 freely do it if it can benefit from non-default lowering.
15743
15744
1560615745 '``llvm.load.relative``' Intrinsic
1560715746 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1560815747
926926 // Support for speculative runtime guards
927927 def int_experimental_guard : Intrinsic<[], [llvm_i1_ty, llvm_vararg_ty],
928928 [Throws]>;
929
930 // Supports widenable conditions for guards represented as explicit branches.
931 def int_experimental_widenable_condition : Intrinsic<[llvm_i1_ty], [],
932 [IntrInaccessibleMemOnly]>;
929933
930934 // NOP: calls/invokes to this intrinsic are removed by codegen
931935 def int_donothing : Intrinsic<[], [], [IntrNoMem]>;
139139 void initializeExpandMemCmpPassPass(PassRegistry&);
140140 void initializeExpandPostRAPass(PassRegistry&);
141141 void initializeExpandReductionsPass(PassRegistry&);
142 void initializeMakeGuardsExplicitLegacyPassPass(PassRegistry&);
142143 void initializeExternalAAWrapperPassPass(PassRegistry&);
143144 void initializeFEntryInserterPass(PassRegistry&);
144145 void initializeFinalizeMachineBundlesPass(PassRegistry&);
0 //===-- MakeGuardsExplicit.h - Turn guard intrinsics into guard branches --===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This pass lowers the @llvm.experimental.guard intrinsic to the new form of
10 // guard represented as widenable explicit branch to the deopt block. The
11 // difference between this pass and LowerGuardIntrinsic is that after this pass
12 // the guard represented as intrinsic:
13 //
14 // call void(i1, ...) @llvm.experimental.guard(i1 %old_cond) [ "deopt"() ]
15 //
16 // transforms to a guard represented as widenable explicit branch:
17 //
18 // %widenable_cond = call i1 @llvm.experimental.widenable.condition()
19 // br i1 (%old_cond & %widenable_cond), label %guarded, label %deopt
20 //
21 // Here:
22 // - The semantics of @llvm.experimental.widenable.condition allows to replace
23 // %widenable_cond with the construction (%widenable_cond & %any_other_cond)
24 // without loss of correctness;
25 // - %guarded is the lower part of old guard intrinsic's parent block split by
26 // the intrinsic call;
27 // - %deopt is a block containing a sole call to @llvm.experimental.deoptimize
28 // intrinsic.
29 //
30 // Therefore, this branch preserves the property of widenability.
31 //
32 //===----------------------------------------------------------------------===//
33 #ifndef LLVM_TRANSFORMS_SCALAR_MAKEGUARDSEXPLICIT_H
34 #define LLVM_TRANSFORMS_SCALAR_MAKEGUARDSEXPLICIT_H
35
36 #include "llvm/IR/PassManager.h"
37
38 namespace llvm {
39
40 struct MakeGuardsExplicitPass : public PassInfoMixin {
41 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
42 };
43
44 } // namespace llvm
45
46 #endif //LLVM_TRANSFORMS_SCALAR_MAKEGUARDSEXPLICIT_H
130130 #include "llvm/Transforms/Scalar/LowerAtomic.h"
131131 #include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h"
132132 #include "llvm/Transforms/Scalar/LowerGuardIntrinsic.h"
133 #include "llvm/Transforms/Scalar/MakeGuardsExplicit.h"
133134 #include "llvm/Transforms/Scalar/MemCpyOptimizer.h"
134135 #include "llvm/Transforms/Scalar/MergedLoadStoreMotion.h"
135136 #include "llvm/Transforms/Scalar/NaryReassociate.h"
164164 FUNCTION_PASS("early-cse", EarlyCSEPass(/*UseMemorySSA=*/false))
165165 FUNCTION_PASS("early-cse-memssa", EarlyCSEPass(/*UseMemorySSA=*/true))
166166 FUNCTION_PASS("ee-instrument", EntryExitInstrumenterPass(/*PostInlining=*/false))
167 FUNCTION_PASS("make-guards-explicit", MakeGuardsExplicitPass())
167168 FUNCTION_PASS("post-inline-ee-instrument", EntryExitInstrumenterPass(/*PostInlining=*/true))
168169 FUNCTION_PASS("gvn-hoist", GVNHoistPass())
169170 FUNCTION_PASS("instcombine", InstCombinePass())
4444 LowerAtomic.cpp
4545 LowerExpectIntrinsic.cpp
4646 LowerGuardIntrinsic.cpp
47 MakeGuardsExplicit.cpp
4748 MemCpyOptimizer.cpp
4849 MergeICmps.cpp
4950 MergedLoadStoreMotion.cpp
0 //===- MakeGuardsExplicit.cpp - Turn guard intrinsics into guard branches -===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This pass lowers the @llvm.experimental.guard intrinsic to the new form of
10 // guard represented as widenable explicit branch to the deopt block. The
11 // difference between this pass and LowerGuardIntrinsic is that after this pass
12 // the guard represented as intrinsic:
13 //
14 // call void(i1, ...) @llvm.experimental.guard(i1 %old_cond) [ "deopt"() ]
15 //
16 // transforms to a guard represented as widenable explicit branch:
17 //
18 // %widenable_cond = call i1 @llvm.experimental.widenable.condition()
19 // br i1 (%old_cond & %widenable_cond), label %guarded, label %deopt
20 //
21 // Here:
22 // - The semantics of @llvm.experimental.widenable.condition allows to replace
23 // %widenable_cond with the construction (%widenable_cond & %any_other_cond)
24 // without loss of correctness;
25 // - %guarded is the lower part of old guard intrinsic's parent block split by
26 // the intrinsic call;
27 // - %deopt is a block containing a sole call to @llvm.experimental.deoptimize
28 // intrinsic.
29 //
30 // Therefore, this branch preserves the property of widenability.
31 //
32 //===----------------------------------------------------------------------===//
33
34 #include "llvm/Transforms/Scalar/MakeGuardsExplicit.h"
35 #include "llvm/Analysis/GuardUtils.h"
36 #include "llvm/IR/InstIterator.h"
37 #include "llvm/IR/IntrinsicInst.h"
38 #include "llvm/IR/Intrinsics.h"
39 #include "llvm/IR/IRBuilder.h"
40 #include "llvm/Pass.h"
41 #include "llvm/Transforms/Scalar.h"
42 #include "llvm/Transforms/Utils/GuardUtils.h"
43
44 using namespace llvm;
45
46 namespace {
47 struct MakeGuardsExplicitLegacyPass : public FunctionPass {
48 static char ID;
49 MakeGuardsExplicitLegacyPass() : FunctionPass(ID) {
50 initializeMakeGuardsExplicitLegacyPassPass(*PassRegistry::getPassRegistry());
51 }
52
53 bool runOnFunction(Function &F) override;
54 };
55 }
56
57 static void turnToExplicitForm(CallInst *Guard, Function *DeoptIntrinsic) {
58 // Replace the guard with an explicit branch (just like in GuardWidening).
59 BasicBlock *BB = Guard->getParent();
60 makeGuardControlFlowExplicit(DeoptIntrinsic, Guard);
61 BranchInst *ExplicitGuard = cast(BB->getTerminator());
62 assert(ExplicitGuard->isConditional() && "Must be!");
63
64 // We want the guard to be expressed as explicit control flow, but still be
65 // widenable. For that, we add Widenable Condition intrinsic call to the
66 // guard's condition.
67 IRBuilder<> B(ExplicitGuard);
68 auto *WidenableCondition =
69 B.CreateIntrinsic(Intrinsic::experimental_widenable_condition,
70 {}, {}, nullptr, "widenable_cond");
71 WidenableCondition->setCallingConv(Guard->getCallingConv());
72 auto *NewCond =
73 B.CreateAnd(ExplicitGuard->getCondition(), WidenableCondition);
74 NewCond->setName("exiplicit_guard_cond");
75 ExplicitGuard->setCondition(NewCond);
76 Guard->eraseFromParent();
77 }
78
79 static bool explicifyGuards(Function &F) {
80 // Check if we can cheaply rule out the possibility of not having any work to
81 // do.
82 auto *GuardDecl = F.getParent()->getFunction(
83 Intrinsic::getName(Intrinsic::experimental_guard));
84 if (!GuardDecl || GuardDecl->use_empty())
85 return false;
86
87 SmallVector GuardIntrinsics;
88 for (auto &I : instructions(F))
89 if (isGuard(&I))
90 GuardIntrinsics.push_back(cast(&I));
91
92 if (GuardIntrinsics.empty())
93 return false;
94
95 auto *DeoptIntrinsic = Intrinsic::getDeclaration(
96 F.getParent(), Intrinsic::experimental_deoptimize, {F.getReturnType()});
97 DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv());
98
99 for (auto *Guard : GuardIntrinsics)
100 turnToExplicitForm(Guard, DeoptIntrinsic);
101
102 return true;
103 }
104
105 bool MakeGuardsExplicitLegacyPass::runOnFunction(Function &F) {
106 return explicifyGuards(F);
107 }
108
109 char MakeGuardsExplicitLegacyPass::ID = 0;
110 INITIALIZE_PASS(MakeGuardsExplicitLegacyPass, "make-guards-explicit",
111 "Lower the guard intrinsic to explicit control flow form",
112 false, false)
113
114 PreservedAnalyses MakeGuardsExplicitPass::run(Function &F,
115 FunctionAnalysisManager &) {
116 if (explicifyGuards(F))
117 return PreservedAnalyses::none();
118 return PreservedAnalyses::all();
119 }
5151 initializeNewGVNLegacyPassPass(Registry);
5252 initializeEarlyCSELegacyPassPass(Registry);
5353 initializeEarlyCSEMemSSALegacyPassPass(Registry);
54 initializeMakeGuardsExplicitLegacyPassPass(Registry);
5455 initializeGVNHoistLegacyPassPass(Registry);
5556 initializeGVNSinkLegacyPassPass(Registry);
5657 initializeFlattenCFGPassPass(Registry);
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt -S -make-guards-explicit -basicaa -licm < %s | FileCheck %s
2 ; RUN: opt -S -aa-pipeline=basic-aa -passes='require,make-guards-explicit,loop(licm)' < %s | FileCheck %s
3
4 ; Test interaction between explicit guards and LICM: make sure that we do not
5 ; hoist explicit conditions while we can hoist invariant loads in presence of
6 ; explicit guards.
7
8 declare void @llvm.experimental.guard(i1,...)
9
10 ; Make sure that we do not hoist widenable_cond out of loop.
11 define void @do_not_hoist_widenable_cond(i1 %cond, i32 %N, i32 %M) {
12 ; CHECK-LABEL: @do_not_hoist_widenable_cond(
13 ; CHECK-NEXT: entry:
14 ; CHECK-NEXT: br label [[LOOP:%.*]]
15 ; CHECK: loop:
16 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
17 ; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N:%.*]]
18 ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
19 ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]]
20 ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
21 ; CHECK: deopt:
22 ; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
23 ; CHECK-NEXT: ret void
24 ; CHECK: guarded:
25 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]]
26 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
27 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
28 ; CHECK: exit:
29 ; CHECK-NEXT: ret void
30 ;
31 entry:
32 br label %loop
33
34 loop:
35 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
36 %guard_cond = icmp slt i32 %iv, %N
37 call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ]
38 %loop_cond = icmp slt i32 %iv, %M
39 %iv.next = add i32 %iv, 1
40 br i1 %loop_cond, label %loop, label %exit
41
42 exit:
43 ret void
44 }
45
46 define void @hoist_invariant_load(i1 %cond, i32* %np, i32 %M) {
47 ; CHECK-LABEL: @hoist_invariant_load(
48 ; CHECK-NEXT: entry:
49 ; CHECK-NEXT: [[N:%.*]] = load i32, i32* [[NP:%.*]]
50 ; CHECK-NEXT: br label [[LOOP:%.*]]
51 ; CHECK: loop:
52 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
53 ; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N]]
54 ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
55 ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]]
56 ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
57 ; CHECK: deopt:
58 ; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
59 ; CHECK-NEXT: ret void
60 ; CHECK: guarded:
61 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]]
62 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
63 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
64 ; CHECK: exit:
65 ; CHECK-NEXT: ret void
66 ;
67 entry:
68 br label %loop
69
70 loop:
71 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
72 %N = load i32, i32* %np
73 %guard_cond = icmp slt i32 %iv, %N
74 call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ]
75 %loop_cond = icmp slt i32 %iv, %M
76 %iv.next = add i32 %iv, 1
77 br i1 %loop_cond, label %loop, label %exit
78
79 exit:
80 ret void
81 }
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt -S -make-guards-explicit < %s | FileCheck %s
2 ; RUN: opt -S -passes=make-guards-explicit < %s | FileCheck %s
3
4 declare void @llvm.experimental.guard(i1,...)
5
6 ; Check that a sole guard can be turned into explicit guards form.
7 define void @trivial_guard(i1 %cond) {
8 ; CHECK-LABEL: @trivial_guard(
9 ; CHECK-NEXT: entry:
10 ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
11 ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND:%.*]], [[WIDENABLE_COND]]
12 ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
13 ; CHECK: deopt:
14 ; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 123, i64 456) ]
15 ; CHECK-NEXT: ret void
16 ; CHECK: guarded:
17 ; CHECK-NEXT: ret void
18 ;
19 entry:
20 call void(i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"(i32 123, i64 456) ]
21 ret void
22 }
23
24 ; Check that a sequence of guards can be turned into explicit guards form.
25 define void @trivial_guard_sequence(i1 %cond1, i1 %cond2, i1 %cond3) {
26 ; CHECK-LABEL: @trivial_guard_sequence(
27 ; CHECK-NEXT: entry:
28 ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
29 ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND1:%.*]], [[WIDENABLE_COND]]
30 ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
31 ; CHECK: deopt:
32 ; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 123, i64 456) ]
33 ; CHECK-NEXT: ret void
34 ; CHECK: guarded:
35 ; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
36 ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND2:%.*]], [[WIDENABLE_COND3]]
37 ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
38 ; CHECK: deopt2:
39 ; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 789, i64 123) ]
40 ; CHECK-NEXT: ret void
41 ; CHECK: guarded1:
42 ; CHECK-NEXT: [[WIDENABLE_COND7:%.*]] = call i1 @llvm.experimental.widenable.condition()
43 ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND8:%.*]] = and i1 [[COND3:%.*]], [[WIDENABLE_COND7]]
44 ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND8]], label [[GUARDED5:%.*]], label [[DEOPT6:%.*]], !prof !0
45 ; CHECK: deopt6:
46 ; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 456, i64 789) ]
47 ; CHECK-NEXT: ret void
48 ; CHECK: guarded5:
49 ; CHECK-NEXT: ret void
50 ;
51 entry:
52 call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"(i32 123, i64 456) ]
53 call void(i1, ...) @llvm.experimental.guard(i1 %cond2) [ "deopt"(i32 789, i64 123) ]
54 call void(i1, ...) @llvm.experimental.guard(i1 %cond3) [ "deopt"(i32 456, i64 789) ]
55 ret void
56 }
57
58 ; Check that all instructions between the guards preserve.
59 define void @split_block_contents(i1 %cond1, i1 %cond2, i1 %cond3, i32* %p) {
60 ; CHECK-LABEL: @split_block_contents(
61 ; CHECK-NEXT: entry:
62 ; CHECK-NEXT: store i32 0, i32* [[P:%.*]]
63 ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
64 ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[COND1:%.*]], [[WIDENABLE_COND]]
65 ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof !0
66 ; CHECK: deopt:
67 ; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 123, i64 456) ]
68 ; CHECK-NEXT: ret void
69 ; CHECK: guarded:
70 ; CHECK-NEXT: store i32 1, i32* [[P]]
71 ; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
72 ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND2:%.*]], [[WIDENABLE_COND3]]
73 ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof !0
74 ; CHECK: deopt2:
75 ; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 789, i64 123) ]
76 ; CHECK-NEXT: ret void
77 ; CHECK: guarded1:
78 ; CHECK-NEXT: store i32 2, i32* [[P]]
79 ; CHECK-NEXT: [[WIDENABLE_COND7:%.*]] = call i1 @llvm.experimental.widenable.condition()
80 ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND8:%.*]] = and i1 [[COND3:%.*]], [[WIDENABLE_COND7]]
81 ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND8]], label [[GUARDED5:%.*]], label [[DEOPT6:%.*]], !prof !0
82 ; CHECK: deopt6:
83 ; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 456, i64 789) ]
84 ; CHECK-NEXT: ret void
85 ; CHECK: guarded5:
86 ; CHECK-NEXT: store i32 3, i32* [[P]]
87 ; CHECK-NEXT: ret void
88 ;
89 entry:
90 store i32 0, i32* %p
91 call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"(i32 123, i64 456) ]
92 store i32 1, i32* %p
93 call void(i1, ...) @llvm.experimental.guard(i1 %cond2) [ "deopt"(i32 789, i64 123) ]
94 store i32 2, i32* %p
95 call void(i1, ...) @llvm.experimental.guard(i1 %cond3) [ "deopt"(i32 456, i64 789) ]
96 store i32 3, i32* %p
97 ret void
98 }
99
100 ; Check that the guard can split a loop properly.
101 define void @split_loop(i1 %cond, i32 %N, i32 %M) {
102 ; CHECK-LABEL: @split_loop(
103 ; CHECK-NEXT: entry:
104 ; CHECK-NEXT: br label [[LOOP:%.*]]
105 ; CHECK: loop:
106 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
107 ; CHECK-NEXT: [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N:%.*]]
108 ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
109 ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]]
110 ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
111 ; CHECK: deopt:
112 ; CHECK-NEXT: call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 123, i64 456) ]
113 ; CHECK-NEXT: ret void
114 ; CHECK: guarded:
115 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]]
116 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
117 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
118 ; CHECK: exit:
119 ; CHECK-NEXT: ret void
120 ;
121 entry:
122 br label %loop
123
124 loop:
125 %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
126 %guard_cond = icmp slt i32 %iv, %N
127 call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"(i32 123, i64 456) ]
128 %loop_cond = icmp slt i32 %iv, %M
129 %iv.next = add i32 %iv, 1
130 br i1 %loop_cond, label %loop, label %exit
131
132 exit:
133 ret void
134 }