127 lines · cpp
1//===-- GuardUtils.cpp - Utils for work with guards -------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8// Utils that are used to perform transformations related to guards and their9// conditions.10//===----------------------------------------------------------------------===//11 12#include "llvm/Transforms/Utils/GuardUtils.h"13#include "llvm/Analysis/GuardUtils.h"14#include "llvm/IR/Function.h"15#include "llvm/IR/IRBuilder.h"16#include "llvm/IR/Instructions.h"17#include "llvm/IR/MDBuilder.h"18#include "llvm/IR/PatternMatch.h"19#include "llvm/Support/CommandLine.h"20#include "llvm/Transforms/Utils/BasicBlockUtils.h"21 22using namespace llvm;23using namespace llvm::PatternMatch;24 25static cl::opt<uint32_t> PredicatePassBranchWeight(26 "guards-predicate-pass-branch-weight", cl::Hidden, cl::init(1 << 20),27 cl::desc("The probability of a guard failing is assumed to be the "28 "reciprocal of this value (default = 1 << 20)"));29 30void llvm::makeGuardControlFlowExplicit(Function *DeoptIntrinsic,31 CallInst *Guard, bool UseWC) {32 OperandBundleDef DeoptOB(*Guard->getOperandBundle(LLVMContext::OB_deopt));33 SmallVector<Value *, 4> Args(drop_begin(Guard->args()));34 35 auto *CheckBB = Guard->getParent();36 auto *DeoptBlockTerm =37 SplitBlockAndInsertIfThen(Guard->getArgOperand(0), Guard, true);38 39 auto *CheckBI = cast<BranchInst>(CheckBB->getTerminator());40 41 // SplitBlockAndInsertIfThen inserts control flow that branches to42 // DeoptBlockTerm if the condition is true. We want the opposite.43 CheckBI->swapSuccessors();44 45 CheckBI->getSuccessor(0)->setName("guarded");46 CheckBI->getSuccessor(1)->setName("deopt");47 48 if (auto *MD = Guard->getMetadata(LLVMContext::MD_make_implicit))49 CheckBI->setMetadata(LLVMContext::MD_make_implicit, MD);50 51 MDBuilder MDB(Guard->getContext());52 CheckBI->setMetadata(LLVMContext::MD_prof,53 MDB.createBranchWeights(PredicatePassBranchWeight, 1));54 55 IRBuilder<> B(DeoptBlockTerm);56 auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, "");57 58 if (DeoptIntrinsic->getReturnType()->isVoidTy()) {59 B.CreateRetVoid();60 } else {61 DeoptCall->setName("deoptcall");62 B.CreateRet(DeoptCall);63 }64 65 DeoptCall->setCallingConv(Guard->getCallingConv());66 DeoptBlockTerm->eraseFromParent();67 68 if (UseWC) {69 // We want the guard to be expressed as explicit control flow, but still be70 // widenable. For that, we add Widenable Condition intrinsic call to the71 // guard's condition.72 IRBuilder<> B(CheckBI);73 auto *WC = B.CreateIntrinsic(Intrinsic::experimental_widenable_condition,74 {}, nullptr, "widenable_cond");75 CheckBI->setCondition(B.CreateAnd(CheckBI->getCondition(), WC,76 "exiplicit_guard_cond"));77 assert(isWidenableBranch(CheckBI) && "Branch must be widenable.");78 }79}80 81 82void llvm::widenWidenableBranch(BranchInst *WidenableBR, Value *NewCond) {83 assert(isWidenableBranch(WidenableBR) && "precondition");84 85 // The tempting trivially option is to produce something like this:86 // br (and oldcond, newcond) where oldcond is assumed to contain a widenable87 // condition, but that doesn't match the pattern parseWidenableBranch expects88 // so we have to be more sophisticated.89 90 Use *C, *WC;91 BasicBlock *IfTrueBB, *IfFalseBB;92 parseWidenableBranch(WidenableBR, C, WC, IfTrueBB, IfFalseBB);93 if (!C) {94 // br (wc()), ... form95 IRBuilder<> B(WidenableBR);96 WidenableBR->setCondition(B.CreateAnd(NewCond, WC->get()));97 } else {98 // br (wc & C), ... form99 IRBuilder<> B(WidenableBR);100 C->set(B.CreateAnd(NewCond, C->get()));101 Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition());102 // Condition is only guaranteed to dominate branch103 WCAnd->moveBefore(WidenableBR->getIterator());104 }105 assert(isWidenableBranch(WidenableBR) && "preserve widenabiliy");106}107 108void llvm::setWidenableBranchCond(BranchInst *WidenableBR, Value *NewCond) {109 assert(isWidenableBranch(WidenableBR) && "precondition");110 111 Use *C, *WC;112 BasicBlock *IfTrueBB, *IfFalseBB;113 parseWidenableBranch(WidenableBR, C, WC, IfTrueBB, IfFalseBB);114 if (!C) {115 // br (wc()), ... form116 IRBuilder<> B(WidenableBR);117 WidenableBR->setCondition(B.CreateAnd(NewCond, WC->get()));118 } else {119 // br (wc & C), ... form120 Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition());121 // Condition is only guaranteed to dominate branch122 WCAnd->moveBefore(WidenableBR->getIterator());123 C->set(NewCond);124 }125 assert(isWidenableBranch(WidenableBR) && "preserve widenabiliy");126}127