1336809Sdim//===-------------------------- CodeRegion.cpp -----------------*- C++ -* -===//
2336809Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6336809Sdim//
7336809Sdim//===----------------------------------------------------------------------===//
8336809Sdim/// \file
9336809Sdim///
10336809Sdim/// This file implements methods from the CodeRegions interface.
11336809Sdim///
12336809Sdim//===----------------------------------------------------------------------===//
13336809Sdim
14336809Sdim#include "CodeRegion.h"
15336809Sdim
16344779Sdimnamespace llvm {
17336809Sdimnamespace mca {
18336809Sdim
19353358SdimCodeRegions::CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {
20353358Sdim  // Create a default region for the input code sequence.
21360784Sdim  Regions.emplace_back(std::make_unique<CodeRegion>("", SMLoc()));
22353358Sdim}
23353358Sdim
24353358Sdimbool CodeRegion::isLocInRange(SMLoc Loc) const {
25336809Sdim  if (RangeEnd.isValid() && Loc.getPointer() > RangeEnd.getPointer())
26336809Sdim    return false;
27336809Sdim  if (RangeStart.isValid() && Loc.getPointer() < RangeStart.getPointer())
28336809Sdim    return false;
29336809Sdim  return true;
30336809Sdim}
31336809Sdim
32353358Sdimvoid CodeRegions::beginRegion(StringRef Description, SMLoc Loc) {
33353358Sdim  if (ActiveRegions.empty()) {
34353358Sdim    // Remove the default region if there is at least one user defined region.
35353358Sdim    // By construction, only the default region has an invalid start location.
36353358Sdim    if (Regions.size() == 1 && !Regions[0]->startLoc().isValid() &&
37353358Sdim        !Regions[0]->endLoc().isValid()) {
38353358Sdim      ActiveRegions[Description] = 0;
39360784Sdim      Regions[0] = std::make_unique<CodeRegion>(Description, Loc);
40353358Sdim      return;
41353358Sdim    }
42353358Sdim  } else {
43353358Sdim    auto It = ActiveRegions.find(Description);
44353358Sdim    if (It != ActiveRegions.end()) {
45353358Sdim      const CodeRegion &R = *Regions[It->second];
46353358Sdim      if (Description.empty()) {
47353358Sdim        SM.PrintMessage(Loc, SourceMgr::DK_Error,
48353358Sdim                        "found multiple overlapping anonymous regions");
49353358Sdim        SM.PrintMessage(R.startLoc(), SourceMgr::DK_Note,
50353358Sdim                        "Previous anonymous region was defined here");
51353358Sdim        FoundErrors = true;
52353358Sdim        return;
53353358Sdim      }
54353358Sdim
55353358Sdim      SM.PrintMessage(Loc, SourceMgr::DK_Error,
56353358Sdim                      "overlapping regions cannot have the same name");
57353358Sdim      SM.PrintMessage(R.startLoc(), SourceMgr::DK_Note,
58353358Sdim                      "region " + Description + " was previously defined here");
59353358Sdim      FoundErrors = true;
60353358Sdim      return;
61353358Sdim    }
62336809Sdim  }
63336809Sdim
64353358Sdim  ActiveRegions[Description] = Regions.size();
65360784Sdim  Regions.emplace_back(std::make_unique<CodeRegion>(Description, Loc));
66353358Sdim  return;
67336809Sdim}
68336809Sdim
69353358Sdimvoid CodeRegions::endRegion(StringRef Description, SMLoc Loc) {
70353358Sdim  if (Description.empty()) {
71353358Sdim    // Special case where there is only one user defined region,
72353358Sdim    // and this LLVM-MCA-END directive doesn't provide a region name.
73353358Sdim    // In this case, we assume that the user simply wanted to just terminate
74353358Sdim    // the only active region.
75353358Sdim    if (ActiveRegions.size() == 1) {
76353358Sdim      auto It = ActiveRegions.begin();
77353358Sdim      Regions[It->second]->setEndLocation(Loc);
78353358Sdim      ActiveRegions.erase(It);
79353358Sdim      return;
80353358Sdim    }
81353358Sdim
82353358Sdim    // Special case where the region end marker applies to the default region.
83353358Sdim    if (ActiveRegions.empty() && Regions.size() == 1 &&
84353358Sdim        !Regions[0]->startLoc().isValid() && !Regions[0]->endLoc().isValid()) {
85353358Sdim      Regions[0]->setEndLocation(Loc);
86353358Sdim      return;
87353358Sdim    }
88353358Sdim  }
89353358Sdim
90353358Sdim  auto It = ActiveRegions.find(Description);
91353358Sdim  if (It != ActiveRegions.end()) {
92353358Sdim    Regions[It->second]->setEndLocation(Loc);
93353358Sdim    ActiveRegions.erase(It);
94336809Sdim    return;
95336809Sdim  }
96336809Sdim
97353358Sdim  FoundErrors = true;
98353358Sdim  SM.PrintMessage(Loc, SourceMgr::DK_Error,
99353358Sdim                  "found an invalid region end directive");
100353358Sdim  if (!Description.empty()) {
101353358Sdim    SM.PrintMessage(Loc, SourceMgr::DK_Note,
102353358Sdim                    "unable to find an active region named " + Description);
103353358Sdim  } else {
104353358Sdim    SM.PrintMessage(Loc, SourceMgr::DK_Note,
105353358Sdim                    "unable to find an active anonymous region");
106353358Sdim  }
107336809Sdim}
108336809Sdim
109353358Sdimvoid CodeRegions::addInstruction(const MCInst &Instruction) {
110353358Sdim  SMLoc Loc = Instruction.getLoc();
111353358Sdim  for (UniqueCodeRegion &Region : Regions)
112353358Sdim    if (Region->isLocInRange(Loc))
113353358Sdim      Region->addInstruction(Instruction);
114336809Sdim}
115336809Sdim
116336809Sdim} // namespace mca
117344779Sdim} // namespace llvm
118