|  | //===-- AbstractCallSite.cpp - Implementation of abstract call sites ------===// | 
|  | // | 
|  | // 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 implements abstract call sites which unify the interface for | 
|  | // direct, indirect, and callback call sites. | 
|  | // | 
|  | // For more information see: | 
|  | // https://llvm.org/devmtg/2018-10/talk-abstracts.html#talk20 | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/IR/AbstractCallSite.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "abstract-call-sites" | 
|  |  | 
|  | STATISTIC(NumCallbackCallSites, "Number of callback call sites created"); | 
|  | STATISTIC(NumDirectAbstractCallSites, | 
|  | "Number of direct abstract call sites created"); | 
|  | STATISTIC(NumInvalidAbstractCallSitesUnknownUse, | 
|  | "Number of invalid abstract call sites created (unknown use)"); | 
|  | STATISTIC(NumInvalidAbstractCallSitesUnknownCallee, | 
|  | "Number of invalid abstract call sites created (unknown callee)"); | 
|  | STATISTIC(NumInvalidAbstractCallSitesNoCallback, | 
|  | "Number of invalid abstract call sites created (no callback)"); | 
|  |  | 
|  | void AbstractCallSite::getCallbackUses( | 
|  | const CallBase &CB, SmallVectorImpl<const Use *> &CallbackUses) { | 
|  | const Function *Callee = CB.getCalledFunction(); | 
|  | if (!Callee) | 
|  | return; | 
|  |  | 
|  | MDNode *CallbackMD = Callee->getMetadata(LLVMContext::MD_callback); | 
|  | if (!CallbackMD) | 
|  | return; | 
|  |  | 
|  | for (const MDOperand &Op : CallbackMD->operands()) { | 
|  | MDNode *OpMD = cast<MDNode>(Op.get()); | 
|  | auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(0)); | 
|  | uint64_t CBCalleeIdx = | 
|  | cast<ConstantInt>(CBCalleeIdxAsCM->getValue())->getZExtValue(); | 
|  | if (CBCalleeIdx < CB.arg_size()) | 
|  | CallbackUses.push_back(CB.arg_begin() + CBCalleeIdx); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Create an abstract call site from a use. | 
|  | AbstractCallSite::AbstractCallSite(const Use *U) | 
|  | : CB(dyn_cast<CallBase>(U->getUser())) { | 
|  |  | 
|  | // First handle unknown users. | 
|  | if (!CB) { | 
|  |  | 
|  | // If the use is actually in a constant cast expression which itself | 
|  | // has only one use, we look through the constant cast expression. | 
|  | // This happens by updating the use @p U to the use of the constant | 
|  | // cast expression and afterwards re-initializing CB accordingly. | 
|  | if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U->getUser())) | 
|  | if (CE->hasOneUse() && CE->isCast()) { | 
|  | U = &*CE->use_begin(); | 
|  | CB = dyn_cast<CallBase>(U->getUser()); | 
|  | } | 
|  |  | 
|  | if (!CB) { | 
|  | NumInvalidAbstractCallSitesUnknownUse++; | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Then handle direct or indirect calls. Thus, if U is the callee of the | 
|  | // call site CB it is not a callback and we are done. | 
|  | if (CB->isCallee(U)) { | 
|  | NumDirectAbstractCallSites++; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // If we cannot identify the broker function we cannot create a callback and | 
|  | // invalidate the abstract call site. | 
|  | Function *Callee = CB->getCalledFunction(); | 
|  | if (!Callee) { | 
|  | NumInvalidAbstractCallSitesUnknownCallee++; | 
|  | CB = nullptr; | 
|  | return; | 
|  | } | 
|  |  | 
|  | MDNode *CallbackMD = Callee->getMetadata(LLVMContext::MD_callback); | 
|  | if (!CallbackMD) { | 
|  | NumInvalidAbstractCallSitesNoCallback++; | 
|  | CB = nullptr; | 
|  | return; | 
|  | } | 
|  |  | 
|  | unsigned UseIdx = CB->getArgOperandNo(U); | 
|  | MDNode *CallbackEncMD = nullptr; | 
|  | for (const MDOperand &Op : CallbackMD->operands()) { | 
|  | MDNode *OpMD = cast<MDNode>(Op.get()); | 
|  | auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(0)); | 
|  | uint64_t CBCalleeIdx = | 
|  | cast<ConstantInt>(CBCalleeIdxAsCM->getValue())->getZExtValue(); | 
|  | if (CBCalleeIdx != UseIdx) | 
|  | continue; | 
|  | CallbackEncMD = OpMD; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (!CallbackEncMD) { | 
|  | NumInvalidAbstractCallSitesNoCallback++; | 
|  | CB = nullptr; | 
|  | return; | 
|  | } | 
|  |  | 
|  | NumCallbackCallSites++; | 
|  |  | 
|  | assert(CallbackEncMD->getNumOperands() >= 2 && "Incomplete !callback metadata"); | 
|  |  | 
|  | unsigned NumCallOperands = CB->arg_size(); | 
|  | // Skip the var-arg flag at the end when reading the metadata. | 
|  | for (unsigned u = 0, e = CallbackEncMD->getNumOperands() - 1; u < e; u++) { | 
|  | Metadata *OpAsM = CallbackEncMD->getOperand(u).get(); | 
|  | auto *OpAsCM = cast<ConstantAsMetadata>(OpAsM); | 
|  | assert(OpAsCM->getType()->isIntegerTy(64) && | 
|  | "Malformed !callback metadata"); | 
|  |  | 
|  | int64_t Idx = cast<ConstantInt>(OpAsCM->getValue())->getSExtValue(); | 
|  | assert(-1 <= Idx && Idx <= NumCallOperands && | 
|  | "Out-of-bounds !callback metadata index"); | 
|  |  | 
|  | CI.ParameterEncoding.push_back(Idx); | 
|  | } | 
|  |  | 
|  | if (!Callee->isVarArg()) | 
|  | return; | 
|  |  | 
|  | Metadata *VarArgFlagAsM = | 
|  | CallbackEncMD->getOperand(CallbackEncMD->getNumOperands() - 1).get(); | 
|  | auto *VarArgFlagAsCM = cast<ConstantAsMetadata>(VarArgFlagAsM); | 
|  | assert(VarArgFlagAsCM->getType()->isIntegerTy(1) && | 
|  | "Malformed !callback metadata var-arg flag"); | 
|  |  | 
|  | if (VarArgFlagAsCM->getValue()->isNullValue()) | 
|  | return; | 
|  |  | 
|  | // Add all variadic arguments at the end. | 
|  | for (unsigned u = Callee->arg_size(); u < NumCallOperands; u++) | 
|  | CI.ParameterEncoding.push_back(u); | 
|  | } |