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 
isLocInRange(SMLoc Loc) const19 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 
addInstruction(const MCInst & Instruction)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 
AnalysisRegions(llvm::SourceMgr & S)34 AnalysisRegions::AnalysisRegions(llvm::SourceMgr &S) : CodeRegions(S) {
35   // Create a default region for the input code sequence.
36   Regions.emplace_back(std::make_unique<CodeRegion>("", SMLoc()));
37 }
38 
beginRegion(StringRef Description,SMLoc Loc)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>(Description, Loc);
47       return;
48     }
49   } else {
50     auto It = ActiveRegions.find(Description);
51     if (It != ActiveRegions.end()) {
52       const CodeRegion &R = *Regions[It->second];
53       if (Description.empty()) {
54         SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
55                         "found multiple overlapping anonymous regions");
56         SM.PrintMessage(R.startLoc(), llvm::SourceMgr::DK_Note,
57                         "Previous anonymous region was defined here");
58         FoundErrors = true;
59         return;
60       }
61 
62       SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
63                       "overlapping regions cannot have the same name");
64       SM.PrintMessage(R.startLoc(), llvm::SourceMgr::DK_Note,
65                       "region " + Description + " was previously defined here");
66       FoundErrors = true;
67       return;
68     }
69   }
70 
71   ActiveRegions[Description] = Regions.size();
72   Regions.emplace_back(std::make_unique<CodeRegion>(Description, Loc));
73 }
74 
endRegion(StringRef Description,SMLoc Loc)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(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(Description);
97   if (It != ActiveRegions.end()) {
98     Regions[It->second]->setEndLocation(Loc);
99     ActiveRegions.erase(It);
100     return;
101   }
102 
103   FoundErrors = true;
104   SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
105                   "found an invalid region end directive");
106   if (!Description.empty()) {
107     SM.PrintMessage(Loc, llvm::SourceMgr::DK_Note,
108                     "unable to find an active region named " + Description);
109   } else {
110     SM.PrintMessage(Loc, llvm::SourceMgr::DK_Note,
111                     "unable to find an active anonymous region");
112   }
113 }
114 
InstrumentRegions(llvm::SourceMgr & S)115 InstrumentRegions::InstrumentRegions(llvm::SourceMgr &S) : CodeRegions(S) {}
116 
beginRegion(StringRef Description,SMLoc Loc,SharedInstrument I)117 void InstrumentRegions::beginRegion(StringRef Description, SMLoc Loc,
118                                     SharedInstrument I) {
119   if (Description.empty()) {
120     SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
121                     "anonymous instrumentation regions are not permitted");
122     FoundErrors = true;
123     return;
124   }
125 
126   auto It = ActiveRegions.find(Description);
127   if (It != ActiveRegions.end()) {
128     const CodeRegion &R = *Regions[It->second];
129     SM.PrintMessage(
130         Loc, llvm::SourceMgr::DK_Error,
131         "overlapping instrumentation regions cannot be of the same kind");
132     SM.PrintMessage(R.startLoc(), llvm::SourceMgr::DK_Note,
133                     "instrumentation region " + Description +
134                         " was previously defined here");
135     FoundErrors = true;
136     return;
137   }
138 
139   ActiveRegions[Description] = Regions.size();
140   Regions.emplace_back(std::make_unique<InstrumentRegion>(Description, Loc, I));
141 }
142 
endRegion(StringRef Description,SMLoc Loc)143 void InstrumentRegions::endRegion(StringRef Description, SMLoc Loc) {
144   auto It = ActiveRegions.find(Description);
145   if (It != ActiveRegions.end()) {
146     Regions[It->second]->setEndLocation(Loc);
147     ActiveRegions.erase(It);
148     return;
149   }
150 
151   FoundErrors = true;
152   SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
153                   "found an invalid instrumentation region end directive");
154   if (!Description.empty()) {
155     SM.PrintMessage(Loc, llvm::SourceMgr::DK_Note,
156                     "unable to find an active instrumentation region named " +
157                         Description);
158   }
159 }
160 
161 const SmallVector<SharedInstrument>
getActiveInstruments(SMLoc Loc) const162 InstrumentRegions::getActiveInstruments(SMLoc Loc) const {
163   SmallVector<SharedInstrument> AI;
164   for (auto &R : Regions) {
165     if (R->isLocInRange(Loc)) {
166       InstrumentRegion *IR = static_cast<InstrumentRegion *>(R.get());
167       AI.emplace_back(IR->getInstrument());
168     }
169   }
170   return AI;
171 }
172 
173 } // namespace mca
174 } // namespace llvm
175