| 1 | //===-------------------------- CodeRegion.cpp -----------------*- C++ -* -===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | /// \file |
| 9 | /// |
| 10 | /// This file implements methods from the CodeRegions interface. |
| 11 | /// |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "CodeRegion.h" |
| 15 | |
| 16 | namespace llvm { |
| 17 | namespace mca { |
| 18 | |
| 19 | bool CodeRegion::isLocInRange(SMLoc Loc) const { |
| 20 | if (RangeEnd.isValid() && Loc.getPointer() > RangeEnd.getPointer()) |
| 21 | return false; |
| 22 | if (RangeStart.isValid() && Loc.getPointer() < RangeStart.getPointer()) |
| 23 | return false; |
| 24 | return true; |
| 25 | } |
| 26 | |
| 27 | void CodeRegions::addInstruction(const MCInst &Instruction) { |
| 28 | SMLoc Loc = Instruction.getLoc(); |
| 29 | for (UniqueCodeRegion &Region : Regions) |
| 30 | if (Region->isLocInRange(Loc)) |
| 31 | Region->addInstruction(Instruction); |
| 32 | } |
| 33 | |
| 34 | AnalysisRegions::AnalysisRegions(llvm::SourceMgr &S) : CodeRegions(S) { |
| 35 | // Create a default region for the input code sequence. |
| 36 | Regions.emplace_back(args: std::make_unique<CodeRegion>(args: "" , args: SMLoc())); |
| 37 | } |
| 38 | |
| 39 | void AnalysisRegions::beginRegion(StringRef Description, SMLoc Loc) { |
| 40 | if (ActiveRegions.empty()) { |
| 41 | // Remove the default region if there is at least one user defined region. |
| 42 | // By construction, only the default region has an invalid start location. |
| 43 | if (Regions.size() == 1 && !Regions[0]->startLoc().isValid() && |
| 44 | !Regions[0]->endLoc().isValid()) { |
| 45 | ActiveRegions[Description] = 0; |
| 46 | Regions[0] = std::make_unique<CodeRegion>(args&: Description, args&: Loc); |
| 47 | return; |
| 48 | } |
| 49 | } else { |
| 50 | auto It = ActiveRegions.find(Key: Description); |
| 51 | if (It != ActiveRegions.end()) { |
| 52 | const CodeRegion &R = *Regions[It->second]; |
| 53 | if (Description.empty()) { |
| 54 | SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Error, |
| 55 | Msg: "found multiple overlapping anonymous regions" ); |
| 56 | SM.PrintMessage(Loc: R.startLoc(), Kind: llvm::SourceMgr::DK_Note, |
| 57 | Msg: "Previous anonymous region was defined here" ); |
| 58 | FoundErrors = true; |
| 59 | return; |
| 60 | } |
| 61 | |
| 62 | SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Error, |
| 63 | Msg: "overlapping regions cannot have the same name" ); |
| 64 | SM.PrintMessage(Loc: R.startLoc(), Kind: llvm::SourceMgr::DK_Note, |
| 65 | Msg: "region " + Description + " was previously defined here" ); |
| 66 | FoundErrors = true; |
| 67 | return; |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | ActiveRegions[Description] = Regions.size(); |
| 72 | Regions.emplace_back(args: std::make_unique<CodeRegion>(args&: Description, args&: Loc)); |
| 73 | } |
| 74 | |
| 75 | void AnalysisRegions::endRegion(StringRef Description, SMLoc Loc) { |
| 76 | if (Description.empty()) { |
| 77 | // Special case where there is only one user defined region, |
| 78 | // and this LLVM-MCA-END directive doesn't provide a region name. |
| 79 | // In this case, we assume that the user simply wanted to just terminate |
| 80 | // the only active region. |
| 81 | if (ActiveRegions.size() == 1) { |
| 82 | auto It = ActiveRegions.begin(); |
| 83 | Regions[It->second]->setEndLocation(Loc); |
| 84 | ActiveRegions.erase(I: It); |
| 85 | return; |
| 86 | } |
| 87 | |
| 88 | // Special case where the region end marker applies to the default region. |
| 89 | if (ActiveRegions.empty() && Regions.size() == 1 && |
| 90 | !Regions[0]->startLoc().isValid() && !Regions[0]->endLoc().isValid()) { |
| 91 | Regions[0]->setEndLocation(Loc); |
| 92 | return; |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | auto It = ActiveRegions.find(Key: Description); |
| 97 | if (It != ActiveRegions.end()) { |
| 98 | Regions[It->second]->setEndLocation(Loc); |
| 99 | ActiveRegions.erase(I: It); |
| 100 | return; |
| 101 | } |
| 102 | |
| 103 | FoundErrors = true; |
| 104 | SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Error, |
| 105 | Msg: "found an invalid region end directive" ); |
| 106 | if (!Description.empty()) { |
| 107 | SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Note, |
| 108 | Msg: "unable to find an active region named " + Description); |
| 109 | } else { |
| 110 | SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Note, |
| 111 | Msg: "unable to find an active anonymous region" ); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | InstrumentRegions::InstrumentRegions(llvm::SourceMgr &S) : CodeRegions(S) {} |
| 116 | |
| 117 | void InstrumentRegions::beginRegion(StringRef Description, SMLoc Loc, |
| 118 | UniqueInstrument I) { |
| 119 | if (Description.empty()) { |
| 120 | SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Error, |
| 121 | Msg: "anonymous instrumentation regions are not permitted" ); |
| 122 | FoundErrors = true; |
| 123 | return; |
| 124 | } |
| 125 | |
| 126 | auto [It, Inserted] = ActiveRegions.try_emplace(Key: Description, Args: Regions.size()); |
| 127 | if (!Inserted) { |
| 128 | const CodeRegion &R = *Regions[It->second]; |
| 129 | SM.PrintMessage( |
| 130 | Loc, Kind: llvm::SourceMgr::DK_Error, |
| 131 | Msg: "overlapping instrumentation regions cannot be of the same kind" ); |
| 132 | SM.PrintMessage(Loc: R.startLoc(), Kind: llvm::SourceMgr::DK_Note, |
| 133 | Msg: "instrumentation region " + Description + |
| 134 | " was previously defined here" ); |
| 135 | FoundErrors = true; |
| 136 | return; |
| 137 | } |
| 138 | |
| 139 | Regions.emplace_back( |
| 140 | args: std::make_unique<InstrumentRegion>(args&: Description, args&: Loc, args: std::move(I))); |
| 141 | } |
| 142 | |
| 143 | void InstrumentRegions::endRegion(StringRef Description, SMLoc Loc) { |
| 144 | auto It = ActiveRegions.find(Key: Description); |
| 145 | if (It != ActiveRegions.end()) { |
| 146 | Regions[It->second]->setEndLocation(Loc); |
| 147 | ActiveRegions.erase(I: It); |
| 148 | return; |
| 149 | } |
| 150 | |
| 151 | FoundErrors = true; |
| 152 | SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Error, |
| 153 | Msg: "found an invalid instrumentation region end directive" ); |
| 154 | if (!Description.empty()) { |
| 155 | SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Note, |
| 156 | Msg: "unable to find an active instrumentation region named " + |
| 157 | Description); |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | SmallVector<Instrument *> |
| 162 | InstrumentRegions::getActiveInstruments(SMLoc Loc) const { |
| 163 | SmallVector<Instrument *> AI; |
| 164 | for (auto &R : Regions) { |
| 165 | if (R->isLocInRange(Loc)) { |
| 166 | InstrumentRegion *IR = static_cast<InstrumentRegion *>(R.get()); |
| 167 | AI.push_back(Elt: IR->getInstrument()); |
| 168 | } |
| 169 | } |
| 170 | return AI; |
| 171 | } |
| 172 | |
| 173 | } // namespace mca |
| 174 | } // namespace llvm |
| 175 | |