Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:13

0001 //===-- IndirectCallVisitor.h - indirect call visitor ---------------------===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file implements defines a visitor class and a helper function that find
0010 // all indirect call-sites in a function.
0011 
0012 #ifndef LLVM_ANALYSIS_INDIRECTCALLVISITOR_H
0013 #define LLVM_ANALYSIS_INDIRECTCALLVISITOR_H
0014 
0015 #include "llvm/IR/InstVisitor.h"
0016 #include <vector>
0017 
0018 namespace llvm {
0019 // Visitor class that finds indirect calls or instructions that gives vtable
0020 // value, depending on Type.
0021 struct PGOIndirectCallVisitor : public InstVisitor<PGOIndirectCallVisitor> {
0022   enum class InstructionType {
0023     kIndirectCall = 0,
0024     kVTableVal = 1,
0025   };
0026   std::vector<CallBase *> IndirectCalls;
0027   std::vector<Instruction *> ProfiledAddresses;
0028   PGOIndirectCallVisitor(InstructionType Type) : Type(Type) {}
0029 
0030   // Given an indirect call instruction, try to find the the following pattern
0031   //
0032   // %vtable = load ptr, ptr %obj
0033   // %vfn = getelementptr inbounds ptr, ptr %vtable, i64 1
0034   // %2 = load ptr, ptr %vfn
0035   // $call = tail call i32 %2
0036   //
0037   // A heuristic is used to find the address feeding instructions.
0038   static Instruction *tryGetVTableInstruction(CallBase *CB) {
0039     assert(CB != nullptr && "Caller guaranteed");
0040     if (!CB->isIndirectCall())
0041       return nullptr;
0042 
0043     LoadInst *LI = dyn_cast<LoadInst>(CB->getCalledOperand());
0044     if (LI != nullptr) {
0045       Value *FuncPtr = LI->getPointerOperand(); // GEP (or bitcast)
0046       Value *VTablePtr = FuncPtr->stripInBoundsConstantOffsets();
0047       // FIXME: Add support in the frontend so LLVM type intrinsics are
0048       // emitted without LTO. This way, added intrinsics could filter
0049       // non-vtable instructions and reduce instrumentation overhead.
0050       // Since a non-vtable profiled address is not within the address
0051       // range of vtable objects, it's stored as zero in indexed profiles.
0052       // A pass that looks up symbol with an zero hash will (almost) always
0053       // find nullptr and skip the actual transformation (e.g., comparison
0054       // of symbols). So the performance overhead from non-vtable profiled
0055       // address is negligible if exists at all. Comparing loaded address
0056       // with symbol address guarantees correctness.
0057       if (VTablePtr != nullptr && isa<Instruction>(VTablePtr))
0058         return cast<Instruction>(VTablePtr);
0059     }
0060     return nullptr;
0061   }
0062 
0063   void visitCallBase(CallBase &Call) {
0064     if (Call.isIndirectCall()) {
0065       IndirectCalls.push_back(&Call);
0066 
0067       if (Type != InstructionType::kVTableVal)
0068         return;
0069 
0070       Instruction *VPtr =
0071           PGOIndirectCallVisitor::tryGetVTableInstruction(&Call);
0072       if (VPtr)
0073         ProfiledAddresses.push_back(VPtr);
0074     }
0075   }
0076 
0077 private:
0078   InstructionType Type;
0079 };
0080 
0081 inline std::vector<CallBase *> findIndirectCalls(Function &F) {
0082   PGOIndirectCallVisitor ICV(
0083       PGOIndirectCallVisitor::InstructionType::kIndirectCall);
0084   ICV.visit(F);
0085   return ICV.IndirectCalls;
0086 }
0087 
0088 inline std::vector<Instruction *> findVTableAddrs(Function &F) {
0089   PGOIndirectCallVisitor ICV(
0090       PGOIndirectCallVisitor::InstructionType::kVTableVal);
0091   ICV.visit(F);
0092   return ICV.ProfiledAddresses;
0093 }
0094 
0095 } // namespace llvm
0096 
0097 #endif