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 17*5ffd83dbSDimitry Andric #include "llvm/IR/AbstractCallSite.h" 180b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 190b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define DEBUG_TYPE "abstract-call-sites" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric STATISTIC(NumCallbackCallSites, "Number of callback call sites created"); 260b57cec5SDimitry Andric STATISTIC(NumDirectAbstractCallSites, 270b57cec5SDimitry Andric "Number of direct abstract call sites created"); 280b57cec5SDimitry Andric STATISTIC(NumInvalidAbstractCallSitesUnknownUse, 290b57cec5SDimitry Andric "Number of invalid abstract call sites created (unknown use)"); 300b57cec5SDimitry Andric STATISTIC(NumInvalidAbstractCallSitesUnknownCallee, 310b57cec5SDimitry Andric "Number of invalid abstract call sites created (unknown callee)"); 320b57cec5SDimitry Andric STATISTIC(NumInvalidAbstractCallSitesNoCallback, 330b57cec5SDimitry Andric "Number of invalid abstract call sites created (no callback)"); 340b57cec5SDimitry Andric 35*5ffd83dbSDimitry Andric void AbstractCallSite::getCallbackUses( 36*5ffd83dbSDimitry Andric const CallBase &CB, SmallVectorImpl<const Use *> &CallbackUses) { 37*5ffd83dbSDimitry Andric const Function *Callee = CB.getCalledFunction(); 38480093f4SDimitry Andric if (!Callee) 39480093f4SDimitry Andric return; 40480093f4SDimitry Andric 41480093f4SDimitry Andric MDNode *CallbackMD = Callee->getMetadata(LLVMContext::MD_callback); 42480093f4SDimitry Andric if (!CallbackMD) 43480093f4SDimitry Andric return; 44480093f4SDimitry Andric 45480093f4SDimitry Andric for (const MDOperand &Op : CallbackMD->operands()) { 46480093f4SDimitry Andric MDNode *OpMD = cast<MDNode>(Op.get()); 47480093f4SDimitry Andric auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(0)); 48480093f4SDimitry Andric uint64_t CBCalleeIdx = 49480093f4SDimitry Andric cast<ConstantInt>(CBCalleeIdxAsCM->getValue())->getZExtValue(); 50*5ffd83dbSDimitry Andric if (CBCalleeIdx < CB.arg_size()) 51*5ffd83dbSDimitry Andric CallbackUses.push_back(CB.arg_begin() + CBCalleeIdx); 52480093f4SDimitry Andric } 53480093f4SDimitry Andric } 54480093f4SDimitry Andric 550b57cec5SDimitry Andric /// Create an abstract call site from a use. 56*5ffd83dbSDimitry Andric AbstractCallSite::AbstractCallSite(const Use *U) 57*5ffd83dbSDimitry Andric : CB(dyn_cast<CallBase>(U->getUser())) { 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric // First handle unknown users. 60*5ffd83dbSDimitry Andric if (!CB) { 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric // If the use is actually in a constant cast expression which itself 630b57cec5SDimitry Andric // has only one use, we look through the constant cast expression. 640b57cec5SDimitry Andric // This happens by updating the use @p U to the use of the constant 65*5ffd83dbSDimitry Andric // cast expression and afterwards re-initializing CB accordingly. 660b57cec5SDimitry Andric if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U->getUser())) 67*5ffd83dbSDimitry Andric if (CE->hasOneUse() && CE->isCast()) { 680b57cec5SDimitry Andric U = &*CE->use_begin(); 69*5ffd83dbSDimitry Andric CB = dyn_cast<CallBase>(U->getUser()); 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 72*5ffd83dbSDimitry Andric if (!CB) { 730b57cec5SDimitry Andric NumInvalidAbstractCallSitesUnknownUse++; 740b57cec5SDimitry Andric return; 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric // Then handle direct or indirect calls. Thus, if U is the callee of the 79*5ffd83dbSDimitry Andric // call site CB it is not a callback and we are done. 80*5ffd83dbSDimitry Andric if (CB->isCallee(U)) { 810b57cec5SDimitry Andric NumDirectAbstractCallSites++; 820b57cec5SDimitry Andric return; 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric // If we cannot identify the broker function we cannot create a callback and 860b57cec5SDimitry Andric // invalidate the abstract call site. 87*5ffd83dbSDimitry Andric Function *Callee = CB->getCalledFunction(); 880b57cec5SDimitry Andric if (!Callee) { 890b57cec5SDimitry Andric NumInvalidAbstractCallSitesUnknownCallee++; 90*5ffd83dbSDimitry Andric CB = nullptr; 910b57cec5SDimitry Andric return; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric MDNode *CallbackMD = Callee->getMetadata(LLVMContext::MD_callback); 950b57cec5SDimitry Andric if (!CallbackMD) { 960b57cec5SDimitry Andric NumInvalidAbstractCallSitesNoCallback++; 97*5ffd83dbSDimitry Andric CB = nullptr; 980b57cec5SDimitry Andric return; 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 101*5ffd83dbSDimitry Andric unsigned UseIdx = CB->getArgOperandNo(U); 1020b57cec5SDimitry Andric MDNode *CallbackEncMD = nullptr; 1030b57cec5SDimitry Andric for (const MDOperand &Op : CallbackMD->operands()) { 1040b57cec5SDimitry Andric MDNode *OpMD = cast<MDNode>(Op.get()); 1050b57cec5SDimitry Andric auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(0)); 1060b57cec5SDimitry Andric uint64_t CBCalleeIdx = 1070b57cec5SDimitry Andric cast<ConstantInt>(CBCalleeIdxAsCM->getValue())->getZExtValue(); 1080b57cec5SDimitry Andric if (CBCalleeIdx != UseIdx) 1090b57cec5SDimitry Andric continue; 1100b57cec5SDimitry Andric CallbackEncMD = OpMD; 1110b57cec5SDimitry Andric break; 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric if (!CallbackEncMD) { 1150b57cec5SDimitry Andric NumInvalidAbstractCallSitesNoCallback++; 116*5ffd83dbSDimitry Andric CB = nullptr; 1170b57cec5SDimitry Andric return; 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric NumCallbackCallSites++; 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric assert(CallbackEncMD->getNumOperands() >= 2 && "Incomplete !callback metadata"); 1230b57cec5SDimitry Andric 124*5ffd83dbSDimitry Andric unsigned NumCallOperands = CB->getNumArgOperands(); 1250b57cec5SDimitry Andric // Skip the var-arg flag at the end when reading the metadata. 1260b57cec5SDimitry Andric for (unsigned u = 0, e = CallbackEncMD->getNumOperands() - 1; u < e; u++) { 1270b57cec5SDimitry Andric Metadata *OpAsM = CallbackEncMD->getOperand(u).get(); 1280b57cec5SDimitry Andric auto *OpAsCM = cast<ConstantAsMetadata>(OpAsM); 1290b57cec5SDimitry Andric assert(OpAsCM->getType()->isIntegerTy(64) && 1300b57cec5SDimitry Andric "Malformed !callback metadata"); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric int64_t Idx = cast<ConstantInt>(OpAsCM->getValue())->getSExtValue(); 1330b57cec5SDimitry Andric assert(-1 <= Idx && Idx <= NumCallOperands && 1340b57cec5SDimitry Andric "Out-of-bounds !callback metadata index"); 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric CI.ParameterEncoding.push_back(Idx); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric if (!Callee->isVarArg()) 1400b57cec5SDimitry Andric return; 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric Metadata *VarArgFlagAsM = 1430b57cec5SDimitry Andric CallbackEncMD->getOperand(CallbackEncMD->getNumOperands() - 1).get(); 1440b57cec5SDimitry Andric auto *VarArgFlagAsCM = cast<ConstantAsMetadata>(VarArgFlagAsM); 1450b57cec5SDimitry Andric assert(VarArgFlagAsCM->getType()->isIntegerTy(1) && 1460b57cec5SDimitry Andric "Malformed !callback metadata var-arg flag"); 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric if (VarArgFlagAsCM->getValue()->isNullValue()) 1490b57cec5SDimitry Andric return; 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric // Add all variadic arguments at the end. 1520b57cec5SDimitry Andric for (unsigned u = Callee->arg_size(); u < NumCallOperands; u++) 1530b57cec5SDimitry Andric CI.ParameterEncoding.push_back(u); 1540b57cec5SDimitry Andric } 155