mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
1b3aa514d1
Summary: This patch changes call graph analysis to recognize callback call sites and add an artificial 'reference' call record from the broker function caller to the callback function in the call graph. A presence of such reference enforces bottom-up traversal order for callback functions in CG SCC pass manager because callback function logically becomes a callee of the broker function caller. Reviewers: jdoerfert, hfinkel, sstefan1, baziotis Reviewed By: jdoerfert Subscribers: hiraditya, kuter, sstefan1, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D82572
248 lines
9.5 KiB
C++
248 lines
9.5 KiB
C++
//===- AbstractCallSite.h - Abstract call sites -----------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the AbstractCallSite class, which is a is a wrapper that
|
|
// allows treating direct, indirect, and callback calls the same.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_IR_ABSTRACTCALLSITE_H
|
|
#define LLVM_IR_ABSTRACTCALLSITE_H
|
|
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/InstrTypes.h"
|
|
#include "llvm/IR/Instruction.h"
|
|
#include "llvm/IR/Use.h"
|
|
#include "llvm/IR/User.h"
|
|
#include "llvm/IR/Value.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include <cassert>
|
|
|
|
namespace llvm {
|
|
|
|
/// AbstractCallSite
|
|
///
|
|
/// An abstract call site is a wrapper that allows to treat direct,
|
|
/// indirect, and callback calls the same. If an abstract call site
|
|
/// represents a direct or indirect call site it behaves like a stripped
|
|
/// down version of a normal call site object. The abstract call site can
|
|
/// also represent a callback call, thus the fact that the initially
|
|
/// called function (=broker) may invoke a third one (=callback callee).
|
|
/// In this case, the abstract call site hides the middle man, hence the
|
|
/// broker function. The result is a representation of the callback call,
|
|
/// inside the broker, but in the context of the original call to the broker.
|
|
///
|
|
/// There are up to three functions involved when we talk about callback call
|
|
/// sites. The caller (1), which invokes the broker function. The broker
|
|
/// function (2), that will invoke the callee zero or more times. And finally
|
|
/// the callee (3), which is the target of the callback call.
|
|
///
|
|
/// The abstract call site will handle the mapping from parameters to arguments
|
|
/// depending on the semantic of the broker function. However, it is important
|
|
/// to note that the mapping is often partial. Thus, some arguments of the
|
|
/// call/invoke instruction are mapped to parameters of the callee while others
|
|
/// are not.
|
|
class AbstractCallSite {
|
|
public:
|
|
|
|
/// The encoding of a callback with regards to the underlying instruction.
|
|
struct CallbackInfo {
|
|
|
|
/// For direct/indirect calls the parameter encoding is empty. If it is not,
|
|
/// the abstract call site represents a callback. In that case, the first
|
|
/// element of the encoding vector represents which argument of the call
|
|
/// site CB is the callback callee. The remaining elements map parameters
|
|
/// (identified by their position) to the arguments that will be passed
|
|
/// through (also identified by position but in the call site instruction).
|
|
///
|
|
/// NOTE that we use LLVM argument numbers (starting at 0) and not
|
|
/// clang/source argument numbers (starting at 1). The -1 entries represent
|
|
/// unknown values that are passed to the callee.
|
|
using ParameterEncodingTy = SmallVector<int, 0>;
|
|
ParameterEncodingTy ParameterEncoding;
|
|
|
|
};
|
|
|
|
private:
|
|
|
|
/// The underlying call site:
|
|
/// caller -> callee, if this is a direct or indirect call site
|
|
/// caller -> broker function, if this is a callback call site
|
|
CallBase *CB;
|
|
|
|
/// The encoding of a callback with regards to the underlying instruction.
|
|
CallbackInfo CI;
|
|
|
|
public:
|
|
/// Sole constructor for abstract call sites (ACS).
|
|
///
|
|
/// An abstract call site can only be constructed through a llvm::Use because
|
|
/// each operand (=use) of an instruction could potentially be a different
|
|
/// abstract call site. Furthermore, even if the value of the llvm::Use is the
|
|
/// same, and the user is as well, the abstract call sites might not be.
|
|
///
|
|
/// If a use is not associated with an abstract call site the constructed ACS
|
|
/// will evaluate to false if converted to a boolean.
|
|
///
|
|
/// If the use is the callee use of a call or invoke instruction, the
|
|
/// constructed abstract call site will behave as a llvm::CallSite would.
|
|
///
|
|
/// If the use is not a callee use of a call or invoke instruction, the
|
|
/// callback metadata is used to determine the argument <-> parameter mapping
|
|
/// as well as the callee of the abstract call site.
|
|
AbstractCallSite(const Use *U);
|
|
|
|
/// Add operand uses of \p CB that represent callback uses into
|
|
/// \p CallbackUses.
|
|
///
|
|
/// All uses added to \p CallbackUses can be used to create abstract call
|
|
/// sites for which AbstractCallSite::isCallbackCall() will return true.
|
|
static void getCallbackUses(const CallBase &CB,
|
|
SmallVectorImpl<const Use *> &CallbackUses);
|
|
|
|
/// Conversion operator to conveniently check for a valid/initialized ACS.
|
|
explicit operator bool() const { return CB != nullptr; }
|
|
|
|
/// Return the underlying instruction.
|
|
CallBase *getInstruction() const { return CB; }
|
|
|
|
/// Return true if this ACS represents a direct call.
|
|
bool isDirectCall() const {
|
|
return !isCallbackCall() && !CB->isIndirectCall();
|
|
}
|
|
|
|
/// Return true if this ACS represents an indirect call.
|
|
bool isIndirectCall() const {
|
|
return !isCallbackCall() && CB->isIndirectCall();
|
|
}
|
|
|
|
/// Return true if this ACS represents a callback call.
|
|
bool isCallbackCall() const {
|
|
// For a callback call site the callee is ALWAYS stored first in the
|
|
// transitive values vector. Thus, a non-empty vector indicates a callback.
|
|
return !CI.ParameterEncoding.empty();
|
|
}
|
|
|
|
/// Return true if @p UI is the use that defines the callee of this ACS.
|
|
bool isCallee(Value::const_user_iterator UI) const {
|
|
return isCallee(&UI.getUse());
|
|
}
|
|
|
|
/// Return true if @p U is the use that defines the callee of this ACS.
|
|
bool isCallee(const Use *U) const {
|
|
if (isDirectCall())
|
|
return CB->isCallee(U);
|
|
|
|
assert(!CI.ParameterEncoding.empty() &&
|
|
"Callback without parameter encoding!");
|
|
|
|
// If the use is actually in a constant cast expression which itself
|
|
// has only one use, we look through the constant cast expression.
|
|
if (auto *CE = dyn_cast<ConstantExpr>(U->getUser()))
|
|
if (CE->hasOneUse() && CE->isCast())
|
|
U = &*CE->use_begin();
|
|
|
|
return (int)CB->getArgOperandNo(U) == CI.ParameterEncoding[0];
|
|
}
|
|
|
|
/// Return the number of parameters of the callee.
|
|
unsigned getNumArgOperands() const {
|
|
if (isDirectCall())
|
|
return CB->getNumArgOperands();
|
|
// Subtract 1 for the callee encoding.
|
|
return CI.ParameterEncoding.size() - 1;
|
|
}
|
|
|
|
/// Return the operand index of the underlying instruction associated with @p
|
|
/// Arg.
|
|
int getCallArgOperandNo(Argument &Arg) const {
|
|
return getCallArgOperandNo(Arg.getArgNo());
|
|
}
|
|
|
|
/// Return the operand index of the underlying instruction associated with
|
|
/// the function parameter number @p ArgNo or -1 if there is none.
|
|
int getCallArgOperandNo(unsigned ArgNo) const {
|
|
if (isDirectCall())
|
|
return ArgNo;
|
|
// Add 1 for the callee encoding.
|
|
return CI.ParameterEncoding[ArgNo + 1];
|
|
}
|
|
|
|
/// Return the operand of the underlying instruction associated with @p Arg.
|
|
Value *getCallArgOperand(Argument &Arg) const {
|
|
return getCallArgOperand(Arg.getArgNo());
|
|
}
|
|
|
|
/// Return the operand of the underlying instruction associated with the
|
|
/// function parameter number @p ArgNo or nullptr if there is none.
|
|
Value *getCallArgOperand(unsigned ArgNo) const {
|
|
if (isDirectCall())
|
|
return CB->getArgOperand(ArgNo);
|
|
// Add 1 for the callee encoding.
|
|
return CI.ParameterEncoding[ArgNo + 1] >= 0
|
|
? CB->getArgOperand(CI.ParameterEncoding[ArgNo + 1])
|
|
: nullptr;
|
|
}
|
|
|
|
/// Return the operand index of the underlying instruction associated with the
|
|
/// callee of this ACS. Only valid for callback calls!
|
|
int getCallArgOperandNoForCallee() const {
|
|
assert(isCallbackCall());
|
|
assert(CI.ParameterEncoding.size() && CI.ParameterEncoding[0] >= 0);
|
|
return CI.ParameterEncoding[0];
|
|
}
|
|
|
|
/// Return the use of the callee value in the underlying instruction. Only
|
|
/// valid for callback calls!
|
|
const Use &getCalleeUseForCallback() const {
|
|
int CalleeArgIdx = getCallArgOperandNoForCallee();
|
|
assert(CalleeArgIdx >= 0 &&
|
|
unsigned(CalleeArgIdx) < getInstruction()->getNumOperands());
|
|
return getInstruction()->getOperandUse(CalleeArgIdx);
|
|
}
|
|
|
|
/// Return the pointer to function that is being called.
|
|
Value *getCalledOperand() const {
|
|
if (isDirectCall())
|
|
return CB->getCalledOperand();
|
|
return CB->getArgOperand(getCallArgOperandNoForCallee());
|
|
}
|
|
|
|
/// Return the function being called if this is a direct call, otherwise
|
|
/// return null (if it's an indirect call).
|
|
Function *getCalledFunction() const {
|
|
Value *V = getCalledOperand();
|
|
return V ? dyn_cast<Function>(V->stripPointerCasts()) : nullptr;
|
|
}
|
|
};
|
|
|
|
/// Apply function Func to each CB's callback call site.
|
|
template <typename UnaryFunction>
|
|
void forEachCallbackCallSite(const CallBase &CB, UnaryFunction Func) {
|
|
SmallVector<const Use *, 4u> CallbackUses;
|
|
AbstractCallSite::getCallbackUses(CB, CallbackUses);
|
|
for (const Use *U : CallbackUses) {
|
|
AbstractCallSite ACS(U);
|
|
assert(ACS && ACS.isCallbackCall() && "must be a callback call");
|
|
Func(ACS);
|
|
}
|
|
}
|
|
|
|
/// Apply function Func to each CB's callback function.
|
|
template <typename UnaryFunction>
|
|
void forEachCallbackFunction(const CallBase &CB, UnaryFunction Func) {
|
|
forEachCallbackCallSite(CB, [&Func](AbstractCallSite &ACS) {
|
|
if (Function *Callback = ACS.getCalledFunction())
|
|
Func(Callback);
|
|
});
|
|
}
|
|
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_IR_ABSTRACTCALLSITE_H
|