123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- 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
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|