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(std::make_unique<CodeRegion>("", 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>(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 
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 
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, 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(
141       std::make_unique<InstrumentRegion>(Description, Loc, std::move(I)));
142 }
143 
144 void InstrumentRegions::endRegion(StringRef Description, SMLoc Loc) {
145   auto It = ActiveRegions.find(Description);
146   if (It != ActiveRegions.end()) {
147     Regions[It->second]->setEndLocation(Loc);
148     ActiveRegions.erase(It);
149     return;
150   }
151 
152   FoundErrors = true;
153   SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
154                   "found an invalid instrumentation region end directive");
155   if (!Description.empty()) {
156     SM.PrintMessage(Loc, llvm::SourceMgr::DK_Note,
157                     "unable to find an active instrumentation region named " +
158                         Description);
159   }
160 }
161 
162 const SmallVector<Instrument *>
163 InstrumentRegions::getActiveInstruments(SMLoc Loc) const {
164   SmallVector<Instrument *> AI;
165   for (auto &R : Regions) {
166     if (R->isLocInRange(Loc)) {
167       InstrumentRegion *IR = static_cast<InstrumentRegion *>(R.get());
168       AI.push_back(IR->getInstrument());
169     }
170   }
171   return AI;
172 }
173 
174 } // namespace mca
175 } // namespace llvm
176