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