xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegion.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-------------------------- CodeRegion.h -------------------*- C++ -* -===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
10bdd1243dSDimitry Andric /// This file implements class CodeRegion and CodeRegions, InstrumentRegion,
11bdd1243dSDimitry Andric /// AnalysisRegions, and InstrumentRegions.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric /// A CodeRegion describes a region of assembly code guarded by special LLVM-MCA
140b57cec5SDimitry Andric /// comment directives.
150b57cec5SDimitry Andric ///
160b57cec5SDimitry Andric ///   # LLVM-MCA-BEGIN foo
170b57cec5SDimitry Andric ///     ...  ## asm
180b57cec5SDimitry Andric ///   # LLVM-MCA-END
190b57cec5SDimitry Andric ///
200b57cec5SDimitry Andric /// A comment starting with substring LLVM-MCA-BEGIN marks the beginning of a
210b57cec5SDimitry Andric /// new region of code.
220b57cec5SDimitry Andric /// A comment starting with substring LLVM-MCA-END marks the end of the
230b57cec5SDimitry Andric /// last-seen region of code.
240b57cec5SDimitry Andric ///
250b57cec5SDimitry Andric /// Code regions are not allowed to overlap. Each region can have a optional
260b57cec5SDimitry Andric /// description; internally, regions are described by a range of source
270b57cec5SDimitry Andric /// locations (SMLoc objects).
280b57cec5SDimitry Andric ///
29bdd1243dSDimitry Andric /// An instruction (a MCInst) is added to a CodeRegion R only if its
30bdd1243dSDimitry Andric /// location is in range [R.RangeStart, R.RangeEnd].
31bdd1243dSDimitry Andric ///
32bdd1243dSDimitry Andric /// A InstrumentRegion describes a region of assembly code guarded by
33bdd1243dSDimitry Andric /// special LLVM-MCA comment directives.
34bdd1243dSDimitry Andric ///
35bdd1243dSDimitry Andric ///   # LLVM-MCA-<INSTRUMENTATION_TYPE> <data>
36bdd1243dSDimitry Andric ///     ...  ## asm
37bdd1243dSDimitry Andric ///
38bdd1243dSDimitry Andric /// where INSTRUMENTATION_TYPE is a type defined in llvm and expects to use
39bdd1243dSDimitry Andric /// data.
40bdd1243dSDimitry Andric ///
41bdd1243dSDimitry Andric /// A comment starting with substring LLVM-MCA-<INSTRUMENTATION_TYPE>
42bdd1243dSDimitry Andric /// brings data into scope for llvm-mca to use in its analysis for
43bdd1243dSDimitry Andric /// all following instructions.
44bdd1243dSDimitry Andric ///
45bdd1243dSDimitry Andric /// If the same INSTRUMENTATION_TYPE is found later in the instruction list,
46bdd1243dSDimitry Andric /// then the original InstrumentRegion will be automatically ended,
47bdd1243dSDimitry Andric /// and a new InstrumentRegion will begin.
48bdd1243dSDimitry Andric ///
49bdd1243dSDimitry Andric /// If there are comments containing the different INSTRUMENTATION_TYPEs,
50bdd1243dSDimitry Andric /// then both data sets remain available. In contrast with a CodeRegion,
51bdd1243dSDimitry Andric /// an InstrumentRegion does not need a comment to end the region.
52bdd1243dSDimitry Andric //
53bdd1243dSDimitry Andric // An instruction (a MCInst) is added to an InstrumentRegion R only
54bdd1243dSDimitry Andric // if its location is in range [R.RangeStart, R.RangeEnd].
550b57cec5SDimitry Andric //
560b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric #ifndef LLVM_TOOLS_LLVM_MCA_CODEREGION_H
590b57cec5SDimitry Andric #define LLVM_TOOLS_LLVM_MCA_CODEREGION_H
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
62*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
630b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
645ffd83dbSDimitry Andric #include "llvm/ADT/StringMap.h"
650b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
660b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
67bdd1243dSDimitry Andric #include "llvm/MCA/CustomBehaviour.h"
685ffd83dbSDimitry Andric #include "llvm/Support/Error.h"
690b57cec5SDimitry Andric #include "llvm/Support/SMLoc.h"
700b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h"
710b57cec5SDimitry Andric #include <vector>
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric namespace llvm {
740b57cec5SDimitry Andric namespace mca {
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric /// A region of assembly code.
770b57cec5SDimitry Andric ///
780b57cec5SDimitry Andric /// It identifies a sequence of machine instructions.
790b57cec5SDimitry Andric class CodeRegion {
800b57cec5SDimitry Andric   // An optional descriptor for this region.
810b57cec5SDimitry Andric   llvm::StringRef Description;
820b57cec5SDimitry Andric   // Instructions that form this region.
83fe6060f1SDimitry Andric   llvm::SmallVector<llvm::MCInst, 16> Instructions;
840b57cec5SDimitry Andric   // Source location range.
850b57cec5SDimitry Andric   llvm::SMLoc RangeStart;
860b57cec5SDimitry Andric   llvm::SMLoc RangeEnd;
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   CodeRegion(const CodeRegion &) = delete;
890b57cec5SDimitry Andric   CodeRegion &operator=(const CodeRegion &) = delete;
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric public:
CodeRegion(llvm::StringRef Desc,llvm::SMLoc Start)920b57cec5SDimitry Andric   CodeRegion(llvm::StringRef Desc, llvm::SMLoc Start)
9304eeddc0SDimitry Andric       : Description(Desc), RangeStart(Start) {}
940b57cec5SDimitry Andric 
9506c3fb27SDimitry Andric   virtual ~CodeRegion() = default;
9606c3fb27SDimitry Andric 
addInstruction(const llvm::MCInst & Instruction)970b57cec5SDimitry Andric   void addInstruction(const llvm::MCInst &Instruction) {
980b57cec5SDimitry Andric     Instructions.emplace_back(Instruction);
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
101*0fca6ea1SDimitry Andric   // Remove the given instructions from the set, for unsupported instructions
102*0fca6ea1SDimitry Andric   // being skipped. Returns an ArrayRef for the updated vector of Instructions.
103*0fca6ea1SDimitry Andric   [[nodiscard]] llvm::ArrayRef<llvm::MCInst>
dropInstructions(const llvm::SmallPtrSetImpl<const llvm::MCInst * > & Insts)104*0fca6ea1SDimitry Andric   dropInstructions(const llvm::SmallPtrSetImpl<const llvm::MCInst *> &Insts) {
105*0fca6ea1SDimitry Andric     if (Insts.empty())
106*0fca6ea1SDimitry Andric       return Instructions;
107*0fca6ea1SDimitry Andric     llvm::erase_if(Instructions, [&Insts](const llvm::MCInst &Inst) {
108*0fca6ea1SDimitry Andric       return Insts.contains(&Inst);
109*0fca6ea1SDimitry Andric     });
110*0fca6ea1SDimitry Andric     return Instructions;
111*0fca6ea1SDimitry Andric   }
112*0fca6ea1SDimitry Andric 
startLoc()1130b57cec5SDimitry Andric   llvm::SMLoc startLoc() const { return RangeStart; }
endLoc()1140b57cec5SDimitry Andric   llvm::SMLoc endLoc() const { return RangeEnd; }
1150b57cec5SDimitry Andric 
setEndLocation(llvm::SMLoc End)1160b57cec5SDimitry Andric   void setEndLocation(llvm::SMLoc End) { RangeEnd = End; }
empty()1170b57cec5SDimitry Andric   bool empty() const { return Instructions.empty(); }
1180b57cec5SDimitry Andric   bool isLocInRange(llvm::SMLoc Loc) const;
1190b57cec5SDimitry Andric 
getInstructions()1200b57cec5SDimitry Andric   llvm::ArrayRef<llvm::MCInst> getInstructions() const { return Instructions; }
1210b57cec5SDimitry Andric 
getDescription()1220b57cec5SDimitry Andric   llvm::StringRef getDescription() const { return Description; }
1230b57cec5SDimitry Andric };
1240b57cec5SDimitry Andric 
125bdd1243dSDimitry Andric /// Alias AnalysisRegion with CodeRegion since CodeRegionGenerator
126bdd1243dSDimitry Andric /// is absract and AnalysisRegionGenerator operates on AnalysisRegions
127bdd1243dSDimitry Andric using AnalysisRegion = CodeRegion;
128bdd1243dSDimitry Andric 
129bdd1243dSDimitry Andric /// A CodeRegion that contains instrumentation that can be used
130bdd1243dSDimitry Andric /// in analysis of the region.
131bdd1243dSDimitry Andric class InstrumentRegion : public CodeRegion {
132bdd1243dSDimitry Andric   /// Instrument for this region.
13306c3fb27SDimitry Andric   UniqueInstrument I;
134bdd1243dSDimitry Andric 
135bdd1243dSDimitry Andric public:
InstrumentRegion(llvm::StringRef Desc,llvm::SMLoc Start,UniqueInstrument I)13606c3fb27SDimitry Andric   InstrumentRegion(llvm::StringRef Desc, llvm::SMLoc Start, UniqueInstrument I)
13706c3fb27SDimitry Andric       : CodeRegion(Desc, Start), I(std::move(I)) {}
138bdd1243dSDimitry Andric 
139bdd1243dSDimitry Andric public:
getInstrument()14006c3fb27SDimitry Andric   Instrument *getInstrument() const { return I.get(); }
141bdd1243dSDimitry Andric };
142bdd1243dSDimitry Andric 
1430b57cec5SDimitry Andric class CodeRegionParseError final : public Error {};
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric class CodeRegions {
146bdd1243dSDimitry Andric   CodeRegions(const CodeRegions &) = delete;
147bdd1243dSDimitry Andric   CodeRegions &operator=(const CodeRegions &) = delete;
148bdd1243dSDimitry Andric 
149bdd1243dSDimitry Andric protected:
1500b57cec5SDimitry Andric   // A source manager. Used by the tool to generate meaningful warnings.
1510b57cec5SDimitry Andric   llvm::SourceMgr &SM;
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   using UniqueCodeRegion = std::unique_ptr<CodeRegion>;
1540b57cec5SDimitry Andric   std::vector<UniqueCodeRegion> Regions;
1550b57cec5SDimitry Andric   llvm::StringMap<unsigned> ActiveRegions;
1560b57cec5SDimitry Andric   bool FoundErrors;
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric public:
CodeRegions(llvm::SourceMgr & S)159bdd1243dSDimitry Andric   CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {}
16006c3fb27SDimitry Andric   virtual ~CodeRegions() = default;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   typedef std::vector<UniqueCodeRegion>::iterator iterator;
1630b57cec5SDimitry Andric   typedef std::vector<UniqueCodeRegion>::const_iterator const_iterator;
1640b57cec5SDimitry Andric 
begin()1650b57cec5SDimitry Andric   iterator begin() { return Regions.begin(); }
end()1660b57cec5SDimitry Andric   iterator end() { return Regions.end(); }
begin()1670b57cec5SDimitry Andric   const_iterator begin() const { return Regions.cbegin(); }
end()1680b57cec5SDimitry Andric   const_iterator end() const { return Regions.cend(); }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   void addInstruction(const llvm::MCInst &Instruction);
getSourceMgr()1710b57cec5SDimitry Andric   llvm::SourceMgr &getSourceMgr() const { return SM; }
1720b57cec5SDimitry Andric 
getInstructionSequence(unsigned Idx)1730b57cec5SDimitry Andric   llvm::ArrayRef<llvm::MCInst> getInstructionSequence(unsigned Idx) const {
1740b57cec5SDimitry Andric     return Regions[Idx]->getInstructions();
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric 
empty()1770b57cec5SDimitry Andric   bool empty() const {
1780b57cec5SDimitry Andric     return llvm::all_of(Regions, [](const UniqueCodeRegion &Region) {
1790b57cec5SDimitry Andric       return Region->empty();
1800b57cec5SDimitry Andric     });
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric 
isValid()1830b57cec5SDimitry Andric   bool isValid() const { return !FoundErrors; }
184bdd1243dSDimitry Andric 
isRegionActive(llvm::StringRef Description)185bdd1243dSDimitry Andric   bool isRegionActive(llvm::StringRef Description) const {
18606c3fb27SDimitry Andric     return ActiveRegions.contains(Description);
187bdd1243dSDimitry Andric   }
18806c3fb27SDimitry Andric 
18906c3fb27SDimitry Andric   virtual void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc) = 0;
19006c3fb27SDimitry Andric   virtual void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc,
19106c3fb27SDimitry Andric                            UniqueInstrument Instrument) = 0;
19206c3fb27SDimitry Andric   virtual void endRegion(llvm::StringRef Description, llvm::SMLoc Loc) = 0;
193bdd1243dSDimitry Andric };
194bdd1243dSDimitry Andric 
195bdd1243dSDimitry Andric struct AnalysisRegions : public CodeRegions {
196bdd1243dSDimitry Andric   AnalysisRegions(llvm::SourceMgr &S);
197bdd1243dSDimitry Andric 
19806c3fb27SDimitry Andric   void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc) override;
beginRegionAnalysisRegions19906c3fb27SDimitry Andric   void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc,
20006c3fb27SDimitry Andric                    UniqueInstrument Instrument) override {}
20106c3fb27SDimitry Andric   void endRegion(llvm::StringRef Description, llvm::SMLoc Loc) override;
202bdd1243dSDimitry Andric };
203bdd1243dSDimitry Andric 
204bdd1243dSDimitry Andric struct InstrumentRegions : public CodeRegions {
20506c3fb27SDimitry Andric 
206bdd1243dSDimitry Andric   InstrumentRegions(llvm::SourceMgr &S);
207bdd1243dSDimitry Andric 
beginRegionInstrumentRegions20806c3fb27SDimitry Andric   void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc) override{};
209bdd1243dSDimitry Andric   void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc,
21006c3fb27SDimitry Andric                    UniqueInstrument Instrument) override;
21106c3fb27SDimitry Andric   void endRegion(llvm::StringRef Description, llvm::SMLoc Loc) override;
212bdd1243dSDimitry Andric 
21306c3fb27SDimitry Andric   const SmallVector<Instrument *> getActiveInstruments(llvm::SMLoc Loc) const;
2140b57cec5SDimitry Andric };
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric } // namespace mca
2170b57cec5SDimitry Andric } // namespace llvm
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric #endif
220