2018-08-29 18:51:59 +08:00
|
|
|
//===-- GuardUtils.cpp - Utils for work with guards -------------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08: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-29 18:51:59 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Utils that are used to perform transformations related to guards and their
|
|
|
|
// conditions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Transforms/Utils/GuardUtils.h"
|
[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-20 06:43:13 +08:00
|
|
|
#include "llvm/Analysis/GuardUtils.h"
|
2018-08-29 18:51:59 +08:00
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/IRBuilder.h"
|
2019-11-15 07:15:48 +08:00
|
|
|
#include "llvm/IR/Instructions.h"
|
2018-08-29 18:51:59 +08:00
|
|
|
#include "llvm/IR/MDBuilder.h"
|
2019-11-22 02:44:13 +08:00
|
|
|
#include "llvm/IR/PatternMatch.h"
|
2019-11-15 07:15:48 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2018-08-29 18:51:59 +08:00
|
|
|
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
2019-11-22 02:44:13 +08:00
|
|
|
using namespace llvm::PatternMatch;
|
2018-08-29 18:51:59 +08:00
|
|
|
|
|
|
|
static cl::opt<uint32_t> PredicatePassBranchWeight(
|
|
|
|
"guards-predicate-pass-branch-weight", cl::Hidden, cl::init(1 << 20),
|
|
|
|
cl::desc("The probability of a guard failing is assumed to be the "
|
|
|
|
"reciprocal of this value (default = 1 << 20)"));
|
|
|
|
|
|
|
|
void llvm::makeGuardControlFlowExplicit(Function *DeoptIntrinsic,
|
2019-11-21 04:51:37 +08:00
|
|
|
CallInst *Guard, bool UseWC) {
|
2018-08-29 18:51:59 +08:00
|
|
|
OperandBundleDef DeoptOB(*Guard->getOperandBundle(LLVMContext::OB_deopt));
|
|
|
|
SmallVector<Value *, 4> Args(std::next(Guard->arg_begin()), Guard->arg_end());
|
|
|
|
|
|
|
|
auto *CheckBB = Guard->getParent();
|
|
|
|
auto *DeoptBlockTerm =
|
|
|
|
SplitBlockAndInsertIfThen(Guard->getArgOperand(0), Guard, true);
|
|
|
|
|
|
|
|
auto *CheckBI = cast<BranchInst>(CheckBB->getTerminator());
|
|
|
|
|
|
|
|
// SplitBlockAndInsertIfThen inserts control flow that branches to
|
|
|
|
// DeoptBlockTerm if the condition is true. We want the opposite.
|
|
|
|
CheckBI->swapSuccessors();
|
|
|
|
|
|
|
|
CheckBI->getSuccessor(0)->setName("guarded");
|
|
|
|
CheckBI->getSuccessor(1)->setName("deopt");
|
|
|
|
|
|
|
|
if (auto *MD = Guard->getMetadata(LLVMContext::MD_make_implicit))
|
|
|
|
CheckBI->setMetadata(LLVMContext::MD_make_implicit, MD);
|
|
|
|
|
|
|
|
MDBuilder MDB(Guard->getContext());
|
|
|
|
CheckBI->setMetadata(LLVMContext::MD_prof,
|
|
|
|
MDB.createBranchWeights(PredicatePassBranchWeight, 1));
|
|
|
|
|
|
|
|
IRBuilder<> B(DeoptBlockTerm);
|
|
|
|
auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, "");
|
|
|
|
|
|
|
|
if (DeoptIntrinsic->getReturnType()->isVoidTy()) {
|
|
|
|
B.CreateRetVoid();
|
|
|
|
} else {
|
|
|
|
DeoptCall->setName("deoptcall");
|
|
|
|
B.CreateRet(DeoptCall);
|
|
|
|
}
|
|
|
|
|
|
|
|
DeoptCall->setCallingConv(Guard->getCallingConv());
|
|
|
|
DeoptBlockTerm->eraseFromParent();
|
2019-11-21 04:51:37 +08:00
|
|
|
|
|
|
|
if (UseWC) {
|
|
|
|
// We want the guard to be expressed as explicit control flow, but still be
|
|
|
|
// widenable. For that, we add Widenable Condition intrinsic call to the
|
|
|
|
// guard's condition.
|
|
|
|
IRBuilder<> B(CheckBI);
|
|
|
|
auto *WC = B.CreateIntrinsic(Intrinsic::experimental_widenable_condition,
|
|
|
|
{}, {}, nullptr, "widenable_cond");
|
|
|
|
CheckBI->setCondition(B.CreateAnd(CheckBI->getCondition(), WC,
|
|
|
|
"exiplicit_guard_cond"));
|
|
|
|
assert(isWidenableBranch(CheckBI) && "sanity check");
|
|
|
|
}
|
2018-08-29 18:51:59 +08: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-20 06:43:13 +08:00
|
|
|
|
|
|
|
|
|
|
|
void llvm::widenWidenableBranch(BranchInst *WidenableBR, Value *NewCond) {
|
|
|
|
assert(isWidenableBranch(WidenableBR) && "precondition");
|
|
|
|
|
2019-11-22 02:44:13 +08:00
|
|
|
// The tempting trivially option is to produce something like this:
|
|
|
|
// br (and oldcond, newcond) where oldcond is assumed to contain a widenable
|
|
|
|
// condition, but that doesn't match the pattern parseWidenableBranch expects
|
|
|
|
// so we have to be more sophisticated.
|
[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-20 06:43:13 +08:00
|
|
|
|
2019-11-22 07:06:01 +08:00
|
|
|
Use *C, *WC;
|
|
|
|
BasicBlock *IfTrueBB, *IfFalseBB;
|
|
|
|
parseWidenableBranch(WidenableBR, C, WC, IfTrueBB, IfFalseBB);
|
|
|
|
if (!C) {
|
|
|
|
// br (wc()), ... form
|
2019-11-22 02:44:13 +08:00
|
|
|
IRBuilder<> B(WidenableBR);
|
2019-11-22 07:06:01 +08:00
|
|
|
WidenableBR->setCondition(B.CreateAnd(NewCond, WC->get()));
|
2019-11-22 02:44:13 +08:00
|
|
|
} else {
|
2019-11-22 07:06:01 +08:00
|
|
|
// br (wc & C), ... form
|
|
|
|
IRBuilder<> B(WidenableBR);
|
|
|
|
C->set(B.CreateAnd(NewCond, C->get()));
|
2019-11-22 02:44:13 +08:00
|
|
|
Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition());
|
|
|
|
// Condition is only guaranteed to dominate branch
|
2019-11-22 07:06:01 +08:00
|
|
|
WCAnd->moveBefore(WidenableBR);
|
2019-11-22 02:44:13 +08: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-20 06:43:13 +08:00
|
|
|
assert(isWidenableBranch(WidenableBR) && "preserve widenabiliy");
|
|
|
|
}
|
|
|
|
|
|
|
|
void llvm::setWidenableBranchCond(BranchInst *WidenableBR, Value *NewCond) {
|
|
|
|
assert(isWidenableBranch(WidenableBR) && "precondition");
|
|
|
|
|
2019-11-22 07:06:01 +08:00
|
|
|
Use *C, *WC;
|
|
|
|
BasicBlock *IfTrueBB, *IfFalseBB;
|
|
|
|
parseWidenableBranch(WidenableBR, C, WC, IfTrueBB, IfFalseBB);
|
|
|
|
if (!C) {
|
|
|
|
// br (wc()), ... form
|
2019-11-22 02:44:13 +08:00
|
|
|
IRBuilder<> B(WidenableBR);
|
2019-11-22 07:06:01 +08:00
|
|
|
WidenableBR->setCondition(B.CreateAnd(NewCond, WC->get()));
|
2019-11-22 02:44:13 +08:00
|
|
|
} else {
|
2019-11-22 07:06:01 +08:00
|
|
|
// br (wc & C), ... form
|
2019-11-22 02:44:13 +08:00
|
|
|
Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition());
|
|
|
|
// Condition is only guaranteed to dominate branch
|
|
|
|
WCAnd->moveBefore(WidenableBR);
|
2019-11-22 07:06:01 +08:00
|
|
|
C->set(NewCond);
|
2019-11-22 02:44:13 +08: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-20 06:43:13 +08:00
|
|
|
assert(isWidenableBranch(WidenableBR) && "preserve widenabiliy");
|
|
|
|
}
|