107 lines
3.3 KiB
C++
107 lines
3.3 KiB
C++
//===-- GuardUtils.cpp - Utils for work with guards -------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
// Utils that are used to perform analyzes related to guards and their
|
|
// conditions.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Analysis/GuardUtils.h"
|
|
#include "llvm/IR/PatternMatch.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::PatternMatch;
|
|
|
|
bool llvm::isGuard(const User *U) {
|
|
return match(U, m_Intrinsic<Intrinsic::experimental_guard>());
|
|
}
|
|
|
|
bool llvm::isWidenableBranch(const User *U) {
|
|
Value *Condition, *WidenableCondition;
|
|
BasicBlock *GuardedBB, *DeoptBB;
|
|
return parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,
|
|
DeoptBB);
|
|
}
|
|
|
|
bool llvm::isGuardAsWidenableBranch(const User *U) {
|
|
Value *Condition, *WidenableCondition;
|
|
BasicBlock *GuardedBB, *DeoptBB;
|
|
if (!parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,
|
|
DeoptBB))
|
|
return false;
|
|
for (auto &Insn : *DeoptBB) {
|
|
if (match(&Insn, m_Intrinsic<Intrinsic::experimental_deoptimize>()))
|
|
return true;
|
|
if (Insn.mayHaveSideEffects())
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool llvm::parseWidenableBranch(const User *U, Value *&Condition,
|
|
Value *&WidenableCondition,
|
|
BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
|
|
|
|
Use *C, *WC;
|
|
if (parseWidenableBranch(const_cast<User*>(U), C, WC, IfTrueBB, IfFalseBB)) {
|
|
if (C)
|
|
Condition = C->get();
|
|
else
|
|
Condition = ConstantInt::getTrue(IfTrueBB->getContext());
|
|
WidenableCondition = WC->get();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool llvm::parseWidenableBranch(User *U, Use *&C,Use *&WC,
|
|
BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
|
|
|
|
auto *BI = dyn_cast<BranchInst>(U);
|
|
if (!BI || !BI->isConditional())
|
|
return false;
|
|
auto *Cond = BI->getCondition();
|
|
if (!Cond->hasOneUse())
|
|
return false;
|
|
|
|
IfTrueBB = BI->getSuccessor(0);
|
|
IfFalseBB = BI->getSuccessor(1);
|
|
|
|
if (match(Cond, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
|
|
WC = &BI->getOperandUse(0);
|
|
C = nullptr;
|
|
return true;
|
|
}
|
|
|
|
// Check for two cases:
|
|
// 1) br (i1 (and A, WC())), label %IfTrue, label %IfFalse
|
|
// 2) br (i1 (and WC(), B)), label %IfTrue, label %IfFalse
|
|
// We do not check for more generalized and trees as we should canonicalize
|
|
// to the form above in instcombine. (TODO)
|
|
Value *A, *B;
|
|
if (!match(Cond, m_And(m_Value(A), m_Value(B))))
|
|
return false;
|
|
auto *And = dyn_cast<Instruction>(Cond);
|
|
if (!And)
|
|
// Could be a constexpr
|
|
return false;
|
|
|
|
if (match(A, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
|
|
A->hasOneUse()) {
|
|
WC = &And->getOperandUse(0);
|
|
C = &And->getOperandUse(1);
|
|
return true;
|
|
}
|
|
|
|
if (match(B, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
|
|
B->hasOneUse()) {
|
|
WC = &And->getOperandUse(1);
|
|
C = &And->getOperandUse(0);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|