teak-llvm/llvm/lib/Analysis/GuardUtils.cpp
Philip Reames 686f449e3d [WC] Fix a subtle bug in our definition of widenable branch
We had a subtle, but nasty bug in our definition of a widenable branch, and thus in the transforms which used that utility. Specifically, we returned true for any branch which included a widenable condition within it's condition, regardless of whether that widenable condition also had other uses.

The problem is that the result of the WC() call is defined to be one particular value. As such, all users must agree as to what that value is. If we widen a branch without also updating *all other users* of the WC in the same way, we have broken the required semantics.

Most of the textual diff is updating existing transforms not to leave dead uses hanging around. They're largely NFC as the dead instructions would be immediately deleted by other passes. The reason to make these changes is so that the transforms preserve the widenable branch form.

In practice, we don't get bitten by this only because it isn't profitable to CSE WC() calls and the lowering pass from guards uses distinct WC calls per branch.

Differential Revision: https://reviews.llvm.org/D69916
2019-11-06 14:16:34 -08:00

55 lines
2.1 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;
bool llvm::isGuard(const User *U) {
using namespace llvm::PatternMatch;
return match(U, m_Intrinsic<Intrinsic::experimental_guard>());
}
bool llvm::isGuardAsWidenableBranch(const User *U) {
Value *Condition, *WidenableCondition;
BasicBlock *GuardedBB, *DeoptBB;
if (!parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,
DeoptBB))
return false;
using namespace llvm::PatternMatch;
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) {
using namespace llvm::PatternMatch;
if (!match(U, m_Br(m_And(m_Value(Condition), m_Value(WidenableCondition)),
IfTrueBB, IfFalseBB)))
return false;
// For the branch to be (easily) widenable, it must not correlate with other
// branches. Thus, the widenable condition must have a single use.
if (!WidenableCondition->hasOneUse() ||
!cast<BranchInst>(U)->getCondition()->hasOneUse())
return false;
// TODO: At the moment, we only recognize the branch if the WC call in this
// specific position. We should generalize!
return match(WidenableCondition,
m_Intrinsic<Intrinsic::experimental_widenable_condition>());
}