1*fe6060f1SDimitry Andric //===-------- MIRFSDiscriminator.cpp: Flow Sensitive Discriminator --------===// 2*fe6060f1SDimitry Andric // 3*fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*fe6060f1SDimitry Andric // 7*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8*fe6060f1SDimitry Andric // 9*fe6060f1SDimitry Andric // This file provides the implementation of a machine pass that adds the flow 10*fe6060f1SDimitry Andric // sensitive discriminator to the instruction debug information. 11*fe6060f1SDimitry Andric // 12*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 13*fe6060f1SDimitry Andric 14*fe6060f1SDimitry Andric #include "llvm/CodeGen/MIRFSDiscriminator.h" 15*fe6060f1SDimitry Andric #include "llvm/ADT/DenseMap.h" 16*fe6060f1SDimitry Andric #include "llvm/ADT/DenseSet.h" 17*fe6060f1SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfoImpl.h" 18*fe6060f1SDimitry Andric #include "llvm/IR/Function.h" 19*fe6060f1SDimitry Andric #include "llvm/Support/CommandLine.h" 20*fe6060f1SDimitry Andric #include "llvm/Support/Debug.h" 21*fe6060f1SDimitry Andric #include "llvm/Support/raw_ostream.h" 22*fe6060f1SDimitry Andric #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h" 23*fe6060f1SDimitry Andric #include <unordered_map> 24*fe6060f1SDimitry Andric 25*fe6060f1SDimitry Andric using namespace llvm; 26*fe6060f1SDimitry Andric using namespace sampleprof; 27*fe6060f1SDimitry Andric using namespace sampleprofutil; 28*fe6060f1SDimitry Andric 29*fe6060f1SDimitry Andric #define DEBUG_TYPE "mirfs-discriminators" 30*fe6060f1SDimitry Andric 31*fe6060f1SDimitry Andric char MIRAddFSDiscriminators::ID = 0; 32*fe6060f1SDimitry Andric 33*fe6060f1SDimitry Andric INITIALIZE_PASS(MIRAddFSDiscriminators, DEBUG_TYPE, 34*fe6060f1SDimitry Andric "Add MIR Flow Sensitive Discriminators", 35*fe6060f1SDimitry Andric /* cfg = */ false, /* is_analysis = */ false) 36*fe6060f1SDimitry Andric 37*fe6060f1SDimitry Andric char &llvm::MIRAddFSDiscriminatorsID = MIRAddFSDiscriminators::ID; 38*fe6060f1SDimitry Andric 39*fe6060f1SDimitry Andric FunctionPass *llvm::createMIRAddFSDiscriminatorsPass(FSDiscriminatorPass P) { 40*fe6060f1SDimitry Andric return new MIRAddFSDiscriminators(P); 41*fe6060f1SDimitry Andric } 42*fe6060f1SDimitry Andric 43*fe6060f1SDimitry Andric // Compute a hash value using debug line number, and the line numbers from the 44*fe6060f1SDimitry Andric // inline stack. 45*fe6060f1SDimitry Andric static uint64_t getCallStackHash(const MachineBasicBlock &BB, 46*fe6060f1SDimitry Andric const MachineInstr &MI, 47*fe6060f1SDimitry Andric const DILocation *DIL) { 48*fe6060f1SDimitry Andric auto updateHash = [](const StringRef &Str) -> uint64_t { 49*fe6060f1SDimitry Andric if (Str.empty()) 50*fe6060f1SDimitry Andric return 0; 51*fe6060f1SDimitry Andric return MD5Hash(Str); 52*fe6060f1SDimitry Andric }; 53*fe6060f1SDimitry Andric uint64_t Ret = updateHash(std::to_string(DIL->getLine())); 54*fe6060f1SDimitry Andric Ret ^= updateHash(BB.getName()); 55*fe6060f1SDimitry Andric Ret ^= updateHash(DIL->getScope()->getSubprogram()->getLinkageName()); 56*fe6060f1SDimitry Andric for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) { 57*fe6060f1SDimitry Andric Ret ^= updateHash(std::to_string(DIL->getLine())); 58*fe6060f1SDimitry Andric Ret ^= updateHash(DIL->getScope()->getSubprogram()->getLinkageName()); 59*fe6060f1SDimitry Andric } 60*fe6060f1SDimitry Andric return Ret; 61*fe6060f1SDimitry Andric } 62*fe6060f1SDimitry Andric 63*fe6060f1SDimitry Andric // Traverse the CFG and assign FD discriminators. If two instructions 64*fe6060f1SDimitry Andric // have the same lineno and discriminator, but residing in different BBs, 65*fe6060f1SDimitry Andric // the latter instruction will get a new discriminator value. The new 66*fe6060f1SDimitry Andric // discriminator keeps the existing discriminator value but sets new bits 67*fe6060f1SDimitry Andric // b/w LowBit and HighBit. 68*fe6060f1SDimitry Andric bool MIRAddFSDiscriminators::runOnMachineFunction(MachineFunction &MF) { 69*fe6060f1SDimitry Andric if (!EnableFSDiscriminator) 70*fe6060f1SDimitry Andric return false; 71*fe6060f1SDimitry Andric 72*fe6060f1SDimitry Andric bool Changed = false; 73*fe6060f1SDimitry Andric using LocationDiscriminator = std::tuple<StringRef, unsigned, unsigned>; 74*fe6060f1SDimitry Andric using BBSet = DenseSet<const MachineBasicBlock *>; 75*fe6060f1SDimitry Andric using LocationDiscriminatorBBMap = DenseMap<LocationDiscriminator, BBSet>; 76*fe6060f1SDimitry Andric using LocationDiscriminatorCurrPassMap = 77*fe6060f1SDimitry Andric DenseMap<LocationDiscriminator, unsigned>; 78*fe6060f1SDimitry Andric 79*fe6060f1SDimitry Andric LocationDiscriminatorBBMap LDBM; 80*fe6060f1SDimitry Andric LocationDiscriminatorCurrPassMap LDCM; 81*fe6060f1SDimitry Andric 82*fe6060f1SDimitry Andric // Mask of discriminators before this pass. 83*fe6060f1SDimitry Andric unsigned BitMaskBefore = getN1Bits(LowBit); 84*fe6060f1SDimitry Andric // Mask of discriminators including this pass. 85*fe6060f1SDimitry Andric unsigned BitMaskNow = getN1Bits(HighBit); 86*fe6060f1SDimitry Andric // Mask of discriminators for bits specific to this pass. 87*fe6060f1SDimitry Andric unsigned BitMaskThisPass = BitMaskNow ^ BitMaskBefore; 88*fe6060f1SDimitry Andric unsigned NumNewD = 0; 89*fe6060f1SDimitry Andric 90*fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "MIRAddFSDiscriminators working on Func: " 91*fe6060f1SDimitry Andric << MF.getFunction().getName() << "\n"); 92*fe6060f1SDimitry Andric for (MachineBasicBlock &BB : MF) { 93*fe6060f1SDimitry Andric for (MachineInstr &I : BB) { 94*fe6060f1SDimitry Andric const DILocation *DIL = I.getDebugLoc().get(); 95*fe6060f1SDimitry Andric if (!DIL) 96*fe6060f1SDimitry Andric continue; 97*fe6060f1SDimitry Andric unsigned LineNo = DIL->getLine(); 98*fe6060f1SDimitry Andric if (LineNo == 0) 99*fe6060f1SDimitry Andric continue; 100*fe6060f1SDimitry Andric unsigned Discriminator = DIL->getDiscriminator(); 101*fe6060f1SDimitry Andric LocationDiscriminator LD{DIL->getFilename(), LineNo, Discriminator}; 102*fe6060f1SDimitry Andric auto &BBMap = LDBM[LD]; 103*fe6060f1SDimitry Andric auto R = BBMap.insert(&BB); 104*fe6060f1SDimitry Andric if (BBMap.size() == 1) 105*fe6060f1SDimitry Andric continue; 106*fe6060f1SDimitry Andric 107*fe6060f1SDimitry Andric unsigned DiscriminatorCurrPass; 108*fe6060f1SDimitry Andric DiscriminatorCurrPass = R.second ? ++LDCM[LD] : LDCM[LD]; 109*fe6060f1SDimitry Andric DiscriminatorCurrPass = DiscriminatorCurrPass << LowBit; 110*fe6060f1SDimitry Andric DiscriminatorCurrPass += getCallStackHash(BB, I, DIL); 111*fe6060f1SDimitry Andric DiscriminatorCurrPass &= BitMaskThisPass; 112*fe6060f1SDimitry Andric unsigned NewD = Discriminator | DiscriminatorCurrPass; 113*fe6060f1SDimitry Andric const auto *const NewDIL = DIL->cloneWithDiscriminator(NewD); 114*fe6060f1SDimitry Andric if (!NewDIL) { 115*fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Could not encode discriminator: " 116*fe6060f1SDimitry Andric << DIL->getFilename() << ":" << DIL->getLine() << ":" 117*fe6060f1SDimitry Andric << DIL->getColumn() << ":" << Discriminator << " " 118*fe6060f1SDimitry Andric << I << "\n"); 119*fe6060f1SDimitry Andric continue; 120*fe6060f1SDimitry Andric } 121*fe6060f1SDimitry Andric 122*fe6060f1SDimitry Andric I.setDebugLoc(NewDIL); 123*fe6060f1SDimitry Andric NumNewD++; 124*fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << DIL->getFilename() << ":" << DIL->getLine() << ":" 125*fe6060f1SDimitry Andric << DIL->getColumn() << ": add FS discriminator, from " 126*fe6060f1SDimitry Andric << Discriminator << " -> " << NewD << "\n"); 127*fe6060f1SDimitry Andric Changed = true; 128*fe6060f1SDimitry Andric } 129*fe6060f1SDimitry Andric } 130*fe6060f1SDimitry Andric 131*fe6060f1SDimitry Andric if (Changed) { 132*fe6060f1SDimitry Andric createFSDiscriminatorVariable(MF.getFunction().getParent()); 133*fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Num of FS Discriminators: " << NumNewD << "\n"); 134*fe6060f1SDimitry Andric } 135*fe6060f1SDimitry Andric 136*fe6060f1SDimitry Andric return Changed; 137*fe6060f1SDimitry Andric } 138