Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Utils/GuardUtils.cpp
35271 views
//===-- GuardUtils.cpp - Utils for work with guards -------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7// Utils that are used to perform transformations related to guards and their8// conditions.9//===----------------------------------------------------------------------===//1011#include "llvm/Transforms/Utils/GuardUtils.h"12#include "llvm/Analysis/GuardUtils.h"13#include "llvm/IR/Function.h"14#include "llvm/IR/IRBuilder.h"15#include "llvm/IR/Instructions.h"16#include "llvm/IR/MDBuilder.h"17#include "llvm/IR/PatternMatch.h"18#include "llvm/Support/CommandLine.h"19#include "llvm/Transforms/Utils/BasicBlockUtils.h"2021using namespace llvm;22using namespace llvm::PatternMatch;2324static cl::opt<uint32_t> PredicatePassBranchWeight(25"guards-predicate-pass-branch-weight", cl::Hidden, cl::init(1 << 20),26cl::desc("The probability of a guard failing is assumed to be the "27"reciprocal of this value (default = 1 << 20)"));2829void llvm::makeGuardControlFlowExplicit(Function *DeoptIntrinsic,30CallInst *Guard, bool UseWC) {31OperandBundleDef DeoptOB(*Guard->getOperandBundle(LLVMContext::OB_deopt));32SmallVector<Value *, 4> Args(drop_begin(Guard->args()));3334auto *CheckBB = Guard->getParent();35auto *DeoptBlockTerm =36SplitBlockAndInsertIfThen(Guard->getArgOperand(0), Guard, true);3738auto *CheckBI = cast<BranchInst>(CheckBB->getTerminator());3940// SplitBlockAndInsertIfThen inserts control flow that branches to41// DeoptBlockTerm if the condition is true. We want the opposite.42CheckBI->swapSuccessors();4344CheckBI->getSuccessor(0)->setName("guarded");45CheckBI->getSuccessor(1)->setName("deopt");4647if (auto *MD = Guard->getMetadata(LLVMContext::MD_make_implicit))48CheckBI->setMetadata(LLVMContext::MD_make_implicit, MD);4950MDBuilder MDB(Guard->getContext());51CheckBI->setMetadata(LLVMContext::MD_prof,52MDB.createBranchWeights(PredicatePassBranchWeight, 1));5354IRBuilder<> B(DeoptBlockTerm);55auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, "");5657if (DeoptIntrinsic->getReturnType()->isVoidTy()) {58B.CreateRetVoid();59} else {60DeoptCall->setName("deoptcall");61B.CreateRet(DeoptCall);62}6364DeoptCall->setCallingConv(Guard->getCallingConv());65DeoptBlockTerm->eraseFromParent();6667if (UseWC) {68// We want the guard to be expressed as explicit control flow, but still be69// widenable. For that, we add Widenable Condition intrinsic call to the70// guard's condition.71IRBuilder<> B(CheckBI);72auto *WC = B.CreateIntrinsic(Intrinsic::experimental_widenable_condition,73{}, {}, nullptr, "widenable_cond");74CheckBI->setCondition(B.CreateAnd(CheckBI->getCondition(), WC,75"exiplicit_guard_cond"));76assert(isWidenableBranch(CheckBI) && "Branch must be widenable.");77}78}798081void llvm::widenWidenableBranch(BranchInst *WidenableBR, Value *NewCond) {82assert(isWidenableBranch(WidenableBR) && "precondition");8384// The tempting trivially option is to produce something like this:85// br (and oldcond, newcond) where oldcond is assumed to contain a widenable86// condition, but that doesn't match the pattern parseWidenableBranch expects87// so we have to be more sophisticated.8889Use *C, *WC;90BasicBlock *IfTrueBB, *IfFalseBB;91parseWidenableBranch(WidenableBR, C, WC, IfTrueBB, IfFalseBB);92if (!C) {93// br (wc()), ... form94IRBuilder<> B(WidenableBR);95WidenableBR->setCondition(B.CreateAnd(NewCond, WC->get()));96} else {97// br (wc & C), ... form98IRBuilder<> B(WidenableBR);99C->set(B.CreateAnd(NewCond, C->get()));100Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition());101// Condition is only guaranteed to dominate branch102WCAnd->moveBefore(WidenableBR);103}104assert(isWidenableBranch(WidenableBR) && "preserve widenabiliy");105}106107void llvm::setWidenableBranchCond(BranchInst *WidenableBR, Value *NewCond) {108assert(isWidenableBranch(WidenableBR) && "precondition");109110Use *C, *WC;111BasicBlock *IfTrueBB, *IfFalseBB;112parseWidenableBranch(WidenableBR, C, WC, IfTrueBB, IfFalseBB);113if (!C) {114// br (wc()), ... form115IRBuilder<> B(WidenableBR);116WidenableBR->setCondition(B.CreateAnd(NewCond, WC->get()));117} else {118// br (wc & C), ... form119Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition());120// Condition is only guaranteed to dominate branch121WCAnd->moveBefore(WidenableBR);122C->set(NewCond);123}124assert(isWidenableBranch(WidenableBR) && "preserve widenabiliy");125}126127128