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.