2018-08-30 05:39:16 +02:00
|
|
|
//===-- GuardUtils.cpp - Utils for work with guards -------------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// 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
|
2018-08-30 05:39:16 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// 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;
|
2019-11-21 19:44:13 +01:00
|
|
|
using namespace llvm::PatternMatch;
|
2018-08-30 05:39:16 +02:00
|
|
|
|
|
|
|
bool llvm::isGuard(const User *U) {
|
|
|
|
return match(U, m_Intrinsic<Intrinsic::experimental_guard>());
|
|
|
|
}
|
2019-01-22 10:36:22 +01:00
|
|
|
|
[NFC] Factor out utilities for manipulating widenable branches
With the widenable condition construct, we have the ability to reason about branches which can be 'widened' (i.e. made to fail more often). We've got a couple o transforms which leverage this. This patch just cleans up the API a bit.
This is prep work for generalizing our definition of a widenable branch slightly. At the moment "br i1 (and A, wc()), ..." is considered widenable, but oddly, neither "br i1 (and wc(), B), ..." or "br i1 wc(), ..." is. That clearly needs addressed, so first, let's centralize the code in one place.
2019-11-19 23:43:13 +01:00
|
|
|
bool llvm::isWidenableBranch(const User *U) {
|
|
|
|
Value *Condition, *WidenableCondition;
|
|
|
|
BasicBlock *GuardedBB, *DeoptBB;
|
|
|
|
return parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,
|
|
|
|
DeoptBB);
|
|
|
|
}
|
|
|
|
|
2019-01-22 10:36:22 +01:00
|
|
|
bool llvm::isGuardAsWidenableBranch(const User *U) {
|
2019-01-22 12:21:32 +01:00
|
|
|
Value *Condition, *WidenableCondition;
|
|
|
|
BasicBlock *GuardedBB, *DeoptBB;
|
|
|
|
if (!parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,
|
|
|
|
DeoptBB))
|
2019-01-22 10:36:22 +01:00
|
|
|
return false;
|
2019-01-22 12:21:32 +01:00
|
|
|
for (auto &Insn : *DeoptBB) {
|
2019-01-22 10:36:22 +01:00
|
|
|
if (match(&Insn, m_Intrinsic<Intrinsic::experimental_deoptimize>()))
|
|
|
|
return true;
|
|
|
|
if (Insn.mayHaveSideEffects())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2019-01-22 12:21:32 +01:00
|
|
|
|
|
|
|
bool llvm::parseWidenableBranch(const User *U, Value *&Condition,
|
|
|
|
Value *&WidenableCondition,
|
|
|
|
BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
|
2019-11-22 00:06:01 +01:00
|
|
|
|
|
|
|
Use *C, *WC;
|
|
|
|
if (parseWidenableBranch(const_cast<User*>(U), C, WC, IfTrueBB, IfFalseBB)) {
|
2020-02-18 03:48:38 +01:00
|
|
|
if (C)
|
2019-11-22 00:06:01 +01:00
|
|
|
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;
|
2020-02-18 03:48:38 +01:00
|
|
|
|
2019-11-22 00:06:01 +01:00
|
|
|
IfTrueBB = BI->getSuccessor(0);
|
|
|
|
IfFalseBB = BI->getSuccessor(1);
|
2020-02-18 03:48:38 +01:00
|
|
|
|
2019-11-22 00:06:01 +01:00
|
|
|
if (match(Cond, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
|
|
|
|
WC = &BI->getOperandUse(0);
|
|
|
|
C = nullptr;
|
2019-11-21 19:44:13 +01:00
|
|
|
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)
|
2019-11-22 00:06:01 +01:00
|
|
|
Value *A, *B;
|
|
|
|
if (!match(Cond, m_And(m_Value(A), m_Value(B))))
|
2019-04-02 18:51:43 +02:00
|
|
|
return false;
|
2019-11-22 20:37:04 +01:00
|
|
|
auto *And = dyn_cast<Instruction>(Cond);
|
|
|
|
if (!And)
|
|
|
|
// Could be a constexpr
|
|
|
|
return false;
|
2020-02-18 03:48:38 +01:00
|
|
|
|
2019-11-22 00:06:01 +01:00
|
|
|
if (match(A, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
|
|
|
|
A->hasOneUse()) {
|
|
|
|
WC = &And->getOperandUse(0);
|
|
|
|
C = &And->getOperandUse(1);
|
|
|
|
return true;
|
2019-11-21 19:44:13 +01:00
|
|
|
}
|
2019-11-22 00:06:01 +01:00
|
|
|
|
|
|
|
if (match(B, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
|
|
|
|
B->hasOneUse()) {
|
|
|
|
WC = &And->getOperandUse(1);
|
|
|
|
C = &And->getOperandUse(0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2019-01-22 12:21:32 +01:00
|
|
|
}
|