1*b5893f02SDimitry Andric //===-- GuardUtils.cpp - Utils for work with guards -------------*- C++ -*-===//
2*b5893f02SDimitry Andric //
3*b5893f02SDimitry Andric //                     The LLVM Compiler Infrastructure
4*b5893f02SDimitry Andric //
5*b5893f02SDimitry Andric // This file is distributed under the University of Illinois Open Source
6*b5893f02SDimitry Andric // License. See LICENSE.TXT for details.
7*b5893f02SDimitry Andric //
8*b5893f02SDimitry Andric //===----------------------------------------------------------------------===//
9*b5893f02SDimitry Andric // Utils that are used to perform transformations related to guards and their
10*b5893f02SDimitry Andric // conditions.
11*b5893f02SDimitry Andric //===----------------------------------------------------------------------===//
12*b5893f02SDimitry Andric 
13*b5893f02SDimitry Andric #include "llvm/Transforms/Utils/GuardUtils.h"
14*b5893f02SDimitry Andric #include "llvm/IR/Function.h"
15*b5893f02SDimitry Andric #include "llvm/IR/Instructions.h"
16*b5893f02SDimitry Andric #include "llvm/IR/IRBuilder.h"
17*b5893f02SDimitry Andric #include "llvm/IR/MDBuilder.h"
18*b5893f02SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
19*b5893f02SDimitry Andric 
20*b5893f02SDimitry Andric using namespace llvm;
21*b5893f02SDimitry Andric 
22*b5893f02SDimitry Andric static cl::opt<uint32_t> PredicatePassBranchWeight(
23*b5893f02SDimitry Andric     "guards-predicate-pass-branch-weight", cl::Hidden, cl::init(1 << 20),
24*b5893f02SDimitry Andric     cl::desc("The probability of a guard failing is assumed to be the "
25*b5893f02SDimitry Andric              "reciprocal of this value (default = 1 << 20)"));
26*b5893f02SDimitry Andric 
makeGuardControlFlowExplicit(Function * DeoptIntrinsic,CallInst * Guard)27*b5893f02SDimitry Andric void llvm::makeGuardControlFlowExplicit(Function *DeoptIntrinsic,
28*b5893f02SDimitry Andric                                         CallInst *Guard) {
29*b5893f02SDimitry Andric   OperandBundleDef DeoptOB(*Guard->getOperandBundle(LLVMContext::OB_deopt));
30*b5893f02SDimitry Andric   SmallVector<Value *, 4> Args(std::next(Guard->arg_begin()), Guard->arg_end());
31*b5893f02SDimitry Andric 
32*b5893f02SDimitry Andric   auto *CheckBB = Guard->getParent();
33*b5893f02SDimitry Andric   auto *DeoptBlockTerm =
34*b5893f02SDimitry Andric       SplitBlockAndInsertIfThen(Guard->getArgOperand(0), Guard, true);
35*b5893f02SDimitry Andric 
36*b5893f02SDimitry Andric   auto *CheckBI = cast<BranchInst>(CheckBB->getTerminator());
37*b5893f02SDimitry Andric 
38*b5893f02SDimitry Andric   // SplitBlockAndInsertIfThen inserts control flow that branches to
39*b5893f02SDimitry Andric   // DeoptBlockTerm if the condition is true.  We want the opposite.
40*b5893f02SDimitry Andric   CheckBI->swapSuccessors();
41*b5893f02SDimitry Andric 
42*b5893f02SDimitry Andric   CheckBI->getSuccessor(0)->setName("guarded");
43*b5893f02SDimitry Andric   CheckBI->getSuccessor(1)->setName("deopt");
44*b5893f02SDimitry Andric 
45*b5893f02SDimitry Andric   if (auto *MD = Guard->getMetadata(LLVMContext::MD_make_implicit))
46*b5893f02SDimitry Andric     CheckBI->setMetadata(LLVMContext::MD_make_implicit, MD);
47*b5893f02SDimitry Andric 
48*b5893f02SDimitry Andric   MDBuilder MDB(Guard->getContext());
49*b5893f02SDimitry Andric   CheckBI->setMetadata(LLVMContext::MD_prof,
50*b5893f02SDimitry Andric                        MDB.createBranchWeights(PredicatePassBranchWeight, 1));
51*b5893f02SDimitry Andric 
52*b5893f02SDimitry Andric   IRBuilder<> B(DeoptBlockTerm);
53*b5893f02SDimitry Andric   auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, "");
54*b5893f02SDimitry Andric 
55*b5893f02SDimitry Andric   if (DeoptIntrinsic->getReturnType()->isVoidTy()) {
56*b5893f02SDimitry Andric     B.CreateRetVoid();
57*b5893f02SDimitry Andric   } else {
58*b5893f02SDimitry Andric     DeoptCall->setName("deoptcall");
59*b5893f02SDimitry Andric     B.CreateRet(DeoptCall);
60*b5893f02SDimitry Andric   }
61*b5893f02SDimitry Andric 
62*b5893f02SDimitry Andric   DeoptCall->setCallingConv(Guard->getCallingConv());
63*b5893f02SDimitry Andric   DeoptBlockTerm->eraseFromParent();
64*b5893f02SDimitry Andric }
65