brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.8 KiB · 46ad951 Raw
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