10b57cec5SDimitry Andric //===-- AbstractCallSite.cpp - Implementation of abstract call sites ------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements abstract call sites which unify the interface for 100b57cec5SDimitry Andric // direct, indirect, and callback call sites. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric // For more information see: 130b57cec5SDimitry Andric // https://llvm.org/devmtg/2018-10/talk-abstracts.html#talk20 140b57cec5SDimitry Andric // 150b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 180b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 190b57cec5SDimitry Andric #include "llvm/IR/CallSite.h" 200b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric using namespace llvm; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric #define DEBUG_TYPE "abstract-call-sites" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric STATISTIC(NumCallbackCallSites, "Number of callback call sites created"); 270b57cec5SDimitry Andric STATISTIC(NumDirectAbstractCallSites, 280b57cec5SDimitry Andric "Number of direct abstract call sites created"); 290b57cec5SDimitry Andric STATISTIC(NumInvalidAbstractCallSitesUnknownUse, 300b57cec5SDimitry Andric "Number of invalid abstract call sites created (unknown use)"); 310b57cec5SDimitry Andric STATISTIC(NumInvalidAbstractCallSitesUnknownCallee, 320b57cec5SDimitry Andric "Number of invalid abstract call sites created (unknown callee)"); 330b57cec5SDimitry Andric STATISTIC(NumInvalidAbstractCallSitesNoCallback, 340b57cec5SDimitry Andric "Number of invalid abstract call sites created (no callback)"); 350b57cec5SDimitry Andric 36*480093f4SDimitry Andric void AbstractCallSite::getCallbackUses(ImmutableCallSite ICS, 37*480093f4SDimitry Andric SmallVectorImpl<const Use *> &CBUses) { 38*480093f4SDimitry Andric const Function *Callee = ICS.getCalledFunction(); 39*480093f4SDimitry Andric if (!Callee) 40*480093f4SDimitry Andric return; 41*480093f4SDimitry Andric 42*480093f4SDimitry Andric MDNode *CallbackMD = Callee->getMetadata(LLVMContext::MD_callback); 43*480093f4SDimitry Andric if (!CallbackMD) 44*480093f4SDimitry Andric return; 45*480093f4SDimitry Andric 46*480093f4SDimitry Andric for (const MDOperand &Op : CallbackMD->operands()) { 47*480093f4SDimitry Andric MDNode *OpMD = cast<MDNode>(Op.get()); 48*480093f4SDimitry Andric auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(0)); 49*480093f4SDimitry Andric uint64_t CBCalleeIdx = 50*480093f4SDimitry Andric cast<ConstantInt>(CBCalleeIdxAsCM->getValue())->getZExtValue(); 51*480093f4SDimitry Andric CBUses.push_back(ICS.arg_begin() + CBCalleeIdx); 52*480093f4SDimitry Andric } 53*480093f4SDimitry Andric } 54*480093f4SDimitry Andric 550b57cec5SDimitry Andric /// Create an abstract call site from a use. 560b57cec5SDimitry Andric AbstractCallSite::AbstractCallSite(const Use *U) : CS(U->getUser()) { 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric // First handle unknown users. 590b57cec5SDimitry Andric if (!CS) { 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric // If the use is actually in a constant cast expression which itself 620b57cec5SDimitry Andric // has only one use, we look through the constant cast expression. 630b57cec5SDimitry Andric // This happens by updating the use @p U to the use of the constant 640b57cec5SDimitry Andric // cast expression and afterwards re-initializing CS accordingly. 650b57cec5SDimitry Andric if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U->getUser())) 660b57cec5SDimitry Andric if (CE->getNumUses() == 1 && CE->isCast()) { 670b57cec5SDimitry Andric U = &*CE->use_begin(); 680b57cec5SDimitry Andric CS = CallSite(U->getUser()); 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric if (!CS) { 720b57cec5SDimitry Andric NumInvalidAbstractCallSitesUnknownUse++; 730b57cec5SDimitry Andric return; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric // Then handle direct or indirect calls. Thus, if U is the callee of the 780b57cec5SDimitry Andric // call site CS it is not a callback and we are done. 790b57cec5SDimitry Andric if (CS.isCallee(U)) { 800b57cec5SDimitry Andric NumDirectAbstractCallSites++; 810b57cec5SDimitry Andric return; 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric // If we cannot identify the broker function we cannot create a callback and 850b57cec5SDimitry Andric // invalidate the abstract call site. 860b57cec5SDimitry Andric Function *Callee = CS.getCalledFunction(); 870b57cec5SDimitry Andric if (!Callee) { 880b57cec5SDimitry Andric NumInvalidAbstractCallSitesUnknownCallee++; 890b57cec5SDimitry Andric CS = CallSite(); 900b57cec5SDimitry Andric return; 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric MDNode *CallbackMD = Callee->getMetadata(LLVMContext::MD_callback); 940b57cec5SDimitry Andric if (!CallbackMD) { 950b57cec5SDimitry Andric NumInvalidAbstractCallSitesNoCallback++; 960b57cec5SDimitry Andric CS = CallSite(); 970b57cec5SDimitry Andric return; 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric unsigned UseIdx = CS.getArgumentNo(U); 1010b57cec5SDimitry Andric MDNode *CallbackEncMD = nullptr; 1020b57cec5SDimitry Andric for (const MDOperand &Op : CallbackMD->operands()) { 1030b57cec5SDimitry Andric MDNode *OpMD = cast<MDNode>(Op.get()); 1040b57cec5SDimitry Andric auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(0)); 1050b57cec5SDimitry Andric uint64_t CBCalleeIdx = 1060b57cec5SDimitry Andric cast<ConstantInt>(CBCalleeIdxAsCM->getValue())->getZExtValue(); 1070b57cec5SDimitry Andric if (CBCalleeIdx != UseIdx) 1080b57cec5SDimitry Andric continue; 1090b57cec5SDimitry Andric CallbackEncMD = OpMD; 1100b57cec5SDimitry Andric break; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric if (!CallbackEncMD) { 1140b57cec5SDimitry Andric NumInvalidAbstractCallSitesNoCallback++; 1150b57cec5SDimitry Andric CS = CallSite(); 1160b57cec5SDimitry Andric return; 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric NumCallbackCallSites++; 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric assert(CallbackEncMD->getNumOperands() >= 2 && "Incomplete !callback metadata"); 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric unsigned NumCallOperands = CS.getNumArgOperands(); 1240b57cec5SDimitry Andric // Skip the var-arg flag at the end when reading the metadata. 1250b57cec5SDimitry Andric for (unsigned u = 0, e = CallbackEncMD->getNumOperands() - 1; u < e; u++) { 1260b57cec5SDimitry Andric Metadata *OpAsM = CallbackEncMD->getOperand(u).get(); 1270b57cec5SDimitry Andric auto *OpAsCM = cast<ConstantAsMetadata>(OpAsM); 1280b57cec5SDimitry Andric assert(OpAsCM->getType()->isIntegerTy(64) && 1290b57cec5SDimitry Andric "Malformed !callback metadata"); 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric int64_t Idx = cast<ConstantInt>(OpAsCM->getValue())->getSExtValue(); 1320b57cec5SDimitry Andric assert(-1 <= Idx && Idx <= NumCallOperands && 1330b57cec5SDimitry Andric "Out-of-bounds !callback metadata index"); 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric CI.ParameterEncoding.push_back(Idx); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric if (!Callee->isVarArg()) 1390b57cec5SDimitry Andric return; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric Metadata *VarArgFlagAsM = 1420b57cec5SDimitry Andric CallbackEncMD->getOperand(CallbackEncMD->getNumOperands() - 1).get(); 1430b57cec5SDimitry Andric auto *VarArgFlagAsCM = cast<ConstantAsMetadata>(VarArgFlagAsM); 1440b57cec5SDimitry Andric assert(VarArgFlagAsCM->getType()->isIntegerTy(1) && 1450b57cec5SDimitry Andric "Malformed !callback metadata var-arg flag"); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric if (VarArgFlagAsCM->getValue()->isNullValue()) 1480b57cec5SDimitry Andric return; 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric // Add all variadic arguments at the end. 1510b57cec5SDimitry Andric for (unsigned u = Callee->arg_size(); u < NumCallOperands; u++) 1520b57cec5SDimitry Andric CI.ParameterEncoding.push_back(u); 1530b57cec5SDimitry Andric } 154