xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/Scalar/MakeGuardsExplicit.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- MakeGuardsExplicit.cpp - Turn guard intrinsics into guard branches -===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass lowers the @llvm.experimental.guard intrinsic to the new form of
100b57cec5SDimitry Andric // guard represented as widenable explicit branch to the deopt block. The
110b57cec5SDimitry Andric // difference between this pass and LowerGuardIntrinsic is that after this pass
120b57cec5SDimitry Andric // the guard represented as intrinsic:
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric //   call void(i1, ...) @llvm.experimental.guard(i1 %old_cond) [ "deopt"() ]
150b57cec5SDimitry Andric //
160b57cec5SDimitry Andric // transforms to a guard represented as widenable explicit branch:
170b57cec5SDimitry Andric //
180b57cec5SDimitry Andric //   %widenable_cond = call i1 @llvm.experimental.widenable.condition()
190b57cec5SDimitry Andric //   br i1 (%old_cond & %widenable_cond), label %guarded, label %deopt
200b57cec5SDimitry Andric //
210b57cec5SDimitry Andric // Here:
220b57cec5SDimitry Andric //   - The semantics of @llvm.experimental.widenable.condition allows to replace
230b57cec5SDimitry Andric //     %widenable_cond with the construction (%widenable_cond & %any_other_cond)
240b57cec5SDimitry Andric //     without loss of correctness;
250b57cec5SDimitry Andric //   - %guarded is the lower part of old guard intrinsic's parent block split by
260b57cec5SDimitry Andric //     the intrinsic call;
270b57cec5SDimitry Andric //   - %deopt is a block containing a sole call to @llvm.experimental.deoptimize
280b57cec5SDimitry Andric //     intrinsic.
290b57cec5SDimitry Andric //
300b57cec5SDimitry Andric // Therefore, this branch preserves the property of widenability.
310b57cec5SDimitry Andric //
320b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric #include "llvm/Transforms/Scalar/MakeGuardsExplicit.h"
350b57cec5SDimitry Andric #include "llvm/Analysis/GuardUtils.h"
360b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h"
3781ad6265SDimitry Andric #include "llvm/IR/Instructions.h"
380b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
39*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h"
40480093f4SDimitry Andric #include "llvm/InitializePasses.h"
410b57cec5SDimitry Andric #include "llvm/Pass.h"
420b57cec5SDimitry Andric #include "llvm/Transforms/Utils/GuardUtils.h"
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric using namespace llvm;
450b57cec5SDimitry Andric 
turnToExplicitForm(CallInst * Guard,Function * DeoptIntrinsic)460b57cec5SDimitry Andric static void turnToExplicitForm(CallInst *Guard, Function *DeoptIntrinsic) {
470b57cec5SDimitry Andric   // Replace the guard with an explicit branch (just like in GuardWidening).
48480093f4SDimitry Andric   BasicBlock *OriginalBB = Guard->getParent();
49480093f4SDimitry Andric   (void)OriginalBB;
50480093f4SDimitry Andric   makeGuardControlFlowExplicit(DeoptIntrinsic, Guard, true);
51480093f4SDimitry Andric   assert(isWidenableBranch(OriginalBB->getTerminator()) && "should hold");
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   Guard->eraseFromParent();
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric 
explicifyGuards(Function & F)560b57cec5SDimitry Andric static bool explicifyGuards(Function &F) {
570b57cec5SDimitry Andric   // Check if we can cheaply rule out the possibility of not having any work to
580b57cec5SDimitry Andric   // do.
590b57cec5SDimitry Andric   auto *GuardDecl = F.getParent()->getFunction(
600b57cec5SDimitry Andric       Intrinsic::getName(Intrinsic::experimental_guard));
610b57cec5SDimitry Andric   if (!GuardDecl || GuardDecl->use_empty())
620b57cec5SDimitry Andric     return false;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   SmallVector<CallInst *, 8> GuardIntrinsics;
650b57cec5SDimitry Andric   for (auto &I : instructions(F))
660b57cec5SDimitry Andric     if (isGuard(&I))
670b57cec5SDimitry Andric       GuardIntrinsics.push_back(cast<CallInst>(&I));
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   if (GuardIntrinsics.empty())
700b57cec5SDimitry Andric     return false;
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   auto *DeoptIntrinsic = Intrinsic::getDeclaration(
730b57cec5SDimitry Andric       F.getParent(), Intrinsic::experimental_deoptimize, {F.getReturnType()});
740b57cec5SDimitry Andric   DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv());
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   for (auto *Guard : GuardIntrinsics)
770b57cec5SDimitry Andric     turnToExplicitForm(Guard, DeoptIntrinsic);
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   return true;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
run(Function & F,FunctionAnalysisManager &)820b57cec5SDimitry Andric PreservedAnalyses MakeGuardsExplicitPass::run(Function &F,
830b57cec5SDimitry Andric                                            FunctionAnalysisManager &) {
840b57cec5SDimitry Andric   if (explicifyGuards(F))
850b57cec5SDimitry Andric     return PreservedAnalyses::none();
860b57cec5SDimitry Andric   return PreservedAnalyses::all();
870b57cec5SDimitry Andric }
88