Path: blob/main/contrib/llvm-project/llvm/lib/IR/AbstractCallSite.cpp
35233 views
//===-- AbstractCallSite.cpp - Implementation of abstract call sites ------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements abstract call sites which unify the interface for9// direct, indirect, and callback call sites.10//11// For more information see:12// https://llvm.org/devmtg/2018-10/talk-abstracts.html#talk2013//14//===----------------------------------------------------------------------===//1516#include "llvm/IR/AbstractCallSite.h"17#include "llvm/ADT/Statistic.h"1819using namespace llvm;2021#define DEBUG_TYPE "abstract-call-sites"2223STATISTIC(NumCallbackCallSites, "Number of callback call sites created");24STATISTIC(NumDirectAbstractCallSites,25"Number of direct abstract call sites created");26STATISTIC(NumInvalidAbstractCallSitesUnknownUse,27"Number of invalid abstract call sites created (unknown use)");28STATISTIC(NumInvalidAbstractCallSitesUnknownCallee,29"Number of invalid abstract call sites created (unknown callee)");30STATISTIC(NumInvalidAbstractCallSitesNoCallback,31"Number of invalid abstract call sites created (no callback)");3233void AbstractCallSite::getCallbackUses(34const CallBase &CB, SmallVectorImpl<const Use *> &CallbackUses) {35const Function *Callee = CB.getCalledFunction();36if (!Callee)37return;3839MDNode *CallbackMD = Callee->getMetadata(LLVMContext::MD_callback);40if (!CallbackMD)41return;4243for (const MDOperand &Op : CallbackMD->operands()) {44MDNode *OpMD = cast<MDNode>(Op.get());45auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(0));46uint64_t CBCalleeIdx =47cast<ConstantInt>(CBCalleeIdxAsCM->getValue())->getZExtValue();48if (CBCalleeIdx < CB.arg_size())49CallbackUses.push_back(CB.arg_begin() + CBCalleeIdx);50}51}5253/// Create an abstract call site from a use.54AbstractCallSite::AbstractCallSite(const Use *U)55: CB(dyn_cast<CallBase>(U->getUser())) {5657// First handle unknown users.58if (!CB) {5960// If the use is actually in a constant cast expression which itself61// has only one use, we look through the constant cast expression.62// This happens by updating the use @p U to the use of the constant63// cast expression and afterwards re-initializing CB accordingly.64if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U->getUser()))65if (CE->hasOneUse() && CE->isCast()) {66U = &*CE->use_begin();67CB = dyn_cast<CallBase>(U->getUser());68}6970if (!CB) {71NumInvalidAbstractCallSitesUnknownUse++;72return;73}74}7576// Then handle direct or indirect calls. Thus, if U is the callee of the77// call site CB it is not a callback and we are done.78if (CB->isCallee(U)) {79NumDirectAbstractCallSites++;80return;81}8283// If we cannot identify the broker function we cannot create a callback and84// invalidate the abstract call site.85Function *Callee = CB->getCalledFunction();86if (!Callee) {87NumInvalidAbstractCallSitesUnknownCallee++;88CB = nullptr;89return;90}9192MDNode *CallbackMD = Callee->getMetadata(LLVMContext::MD_callback);93if (!CallbackMD) {94NumInvalidAbstractCallSitesNoCallback++;95CB = nullptr;96return;97}9899unsigned UseIdx = CB->getArgOperandNo(U);100MDNode *CallbackEncMD = nullptr;101for (const MDOperand &Op : CallbackMD->operands()) {102MDNode *OpMD = cast<MDNode>(Op.get());103auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(0));104uint64_t CBCalleeIdx =105cast<ConstantInt>(CBCalleeIdxAsCM->getValue())->getZExtValue();106if (CBCalleeIdx != UseIdx)107continue;108CallbackEncMD = OpMD;109break;110}111112if (!CallbackEncMD) {113NumInvalidAbstractCallSitesNoCallback++;114CB = nullptr;115return;116}117118NumCallbackCallSites++;119120assert(CallbackEncMD->getNumOperands() >= 2 && "Incomplete !callback metadata");121122unsigned NumCallOperands = CB->arg_size();123// Skip the var-arg flag at the end when reading the metadata.124for (unsigned u = 0, e = CallbackEncMD->getNumOperands() - 1; u < e; u++) {125Metadata *OpAsM = CallbackEncMD->getOperand(u).get();126auto *OpAsCM = cast<ConstantAsMetadata>(OpAsM);127assert(OpAsCM->getType()->isIntegerTy(64) &&128"Malformed !callback metadata");129130int64_t Idx = cast<ConstantInt>(OpAsCM->getValue())->getSExtValue();131assert(-1 <= Idx && Idx <= NumCallOperands &&132"Out-of-bounds !callback metadata index");133134CI.ParameterEncoding.push_back(Idx);135}136137if (!Callee->isVarArg())138return;139140Metadata *VarArgFlagAsM =141CallbackEncMD->getOperand(CallbackEncMD->getNumOperands() - 1).get();142auto *VarArgFlagAsCM = cast<ConstantAsMetadata>(VarArgFlagAsM);143assert(VarArgFlagAsCM->getType()->isIntegerTy(1) &&144"Malformed !callback metadata var-arg flag");145146if (VarArgFlagAsCM->getValue()->isNullValue())147return;148149// Add all variadic arguments at the end.150for (unsigned u = Callee->arg_size(); u < NumCallOperands; u++)151CI.ParameterEncoding.push_back(u);152}153154155