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