Path: blob/main/contrib/llvm-project/llvm/lib/Analysis/GuardUtils.cpp
35233 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 analyzes related to guards and their8// conditions.9//===----------------------------------------------------------------------===//1011#include "llvm/Analysis/GuardUtils.h"12#include "llvm/IR/PatternMatch.h"1314using namespace llvm;15using namespace llvm::PatternMatch;1617bool llvm::isGuard(const User *U) {18return match(U, m_Intrinsic<Intrinsic::experimental_guard>());19}2021bool llvm::isWidenableCondition(const Value *V) {22return match(V, m_Intrinsic<Intrinsic::experimental_widenable_condition>());23}2425bool llvm::isWidenableBranch(const User *U) {26Value *Condition, *WidenableCondition;27BasicBlock *GuardedBB, *DeoptBB;28return parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,29DeoptBB);30}3132bool llvm::isGuardAsWidenableBranch(const User *U) {33if (!isWidenableBranch(U))34return false;35BasicBlock *DeoptBB = cast<BranchInst>(U)->getSuccessor(1);36SmallPtrSet<const BasicBlock *, 2> Visited;37Visited.insert(DeoptBB);38do {39for (auto &Insn : *DeoptBB) {40if (match(&Insn, m_Intrinsic<Intrinsic::experimental_deoptimize>()))41return true;42if (Insn.mayHaveSideEffects())43return false;44}45DeoptBB = DeoptBB->getUniqueSuccessor();46if (!DeoptBB)47return false;48} while (Visited.insert(DeoptBB).second);49return false;50}5152bool llvm::parseWidenableBranch(const User *U, Value *&Condition,53Value *&WidenableCondition,54BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {5556Use *C, *WC;57if (parseWidenableBranch(const_cast<User*>(U), C, WC, IfTrueBB, IfFalseBB)) {58if (C)59Condition = C->get();60else61Condition = ConstantInt::getTrue(IfTrueBB->getContext());62WidenableCondition = WC->get();63return true;64}65return false;66}6768bool llvm::parseWidenableBranch(User *U, Use *&C,Use *&WC,69BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {7071auto *BI = dyn_cast<BranchInst>(U);72if (!BI || !BI->isConditional())73return false;74auto *Cond = BI->getCondition();75if (!Cond->hasOneUse())76return false;7778IfTrueBB = BI->getSuccessor(0);79IfFalseBB = BI->getSuccessor(1);8081if (match(Cond, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {82WC = &BI->getOperandUse(0);83C = nullptr;84return true;85}8687// Check for two cases:88// 1) br (i1 (and A, WC())), label %IfTrue, label %IfFalse89// 2) br (i1 (and WC(), B)), label %IfTrue, label %IfFalse90// We do not check for more generalized and trees as we should canonicalize91// to the form above in instcombine. (TODO)92Value *A, *B;93if (!match(Cond, m_And(m_Value(A), m_Value(B))))94return false;95auto *And = dyn_cast<Instruction>(Cond);96if (!And)97// Could be a constexpr98return false;99100if (match(A, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&101A->hasOneUse()) {102WC = &And->getOperandUse(0);103C = &And->getOperandUse(1);104return true;105}106107if (match(B, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&108B->hasOneUse()) {109WC = &And->getOperandUse(1);110C = &And->getOperandUse(0);111return true;112}113return false;114}115116template <typename CallbackType>117static void parseCondition(Value *Condition,118CallbackType RecordCheckOrWidenableCond) {119SmallVector<Value *, 4> Worklist(1, Condition);120SmallPtrSet<Value *, 4> Visited;121Visited.insert(Condition);122do {123Value *Check = Worklist.pop_back_val();124Value *LHS, *RHS;125if (match(Check, m_And(m_Value(LHS), m_Value(RHS)))) {126if (Visited.insert(LHS).second)127Worklist.push_back(LHS);128if (Visited.insert(RHS).second)129Worklist.push_back(RHS);130continue;131}132if (!RecordCheckOrWidenableCond(Check))133break;134} while (!Worklist.empty());135}136137void llvm::parseWidenableGuard(const User *U,138llvm::SmallVectorImpl<Value *> &Checks) {139assert((isGuard(U) || isWidenableBranch(U)) && "Should be");140Value *Condition = isGuard(U) ? cast<IntrinsicInst>(U)->getArgOperand(0)141: cast<BranchInst>(U)->getCondition();142143parseCondition(Condition, [&](Value *Check) {144if (!isWidenableCondition(Check))145Checks.push_back(Check);146return true;147});148}149150Value *llvm::extractWidenableCondition(const User *U) {151auto *BI = dyn_cast<BranchInst>(U);152if (!BI || !BI->isConditional())153return nullptr;154155auto Condition = BI->getCondition();156if (!Condition->hasOneUse())157return nullptr;158159Value *WidenableCondition = nullptr;160parseCondition(Condition, [&](Value *Check) {161// We require widenable_condition has only one use, otherwise we don't162// consider appropriate branch as widenable.163if (isWidenableCondition(Check) && Check->hasOneUse()) {164WidenableCondition = Check;165return false;166}167return true;168});169return WidenableCondition;170}171172173