Peter Waller 5f79f7506a
[llvm-mca] Add -skip-unsupported-instructions option (#89733)
Prior to this patch, if llvm-mca encountered an instruction which parses
but has no scheduler info, the instruction is always reported as
unsupported, and llvm-mca halts with an error.

However, it would still be useful to allow MCA to continue even in the
case of instructions lacking scheduling information. Obviously if
scheduling information is lacking, it's not possible to give an accurate
analysis for those instructions, and therefore a warning is emitted.

A user could previously have worked around such unsupported instructions
manually by deleting such instructions from the input, but this provides
them a way of doing this for bulk inputs where they may not have a list
of such unsupported instructions to drop up front.

Note that this behaviour of instructions with no scheduling information
under -skip-unsupported-instructions is analagous to current
instructions which fail to parse: those are currently dropped from the
input with a message printed, after which the analysis continues.

~Testing the feature is a little awkward currently, it relies on an
instruction
which is currently marked as unsupported, which may not remain so;
should the
situation change it would be necessary to find an alternative
unsupported
instruction or drop the test.~

A test is added to check that analysis still reports an error if all
instructions are removed from the input, to mirror the current behaviour
of giving an error if no instructions are supplied.
2024-04-29 08:39:15 +01:00

222 lines
7.5 KiB
C++

//===-------------------------- CodeRegion.h -------------------*- C++ -* -===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This file implements class CodeRegion and CodeRegions, InstrumentRegion,
/// AnalysisRegions, and InstrumentRegions.
///
/// A CodeRegion describes a region of assembly code guarded by special LLVM-MCA
/// comment directives.
///
/// # LLVM-MCA-BEGIN foo
/// ... ## asm
/// # LLVM-MCA-END
///
/// A comment starting with substring LLVM-MCA-BEGIN marks the beginning of a
/// new region of code.
/// A comment starting with substring LLVM-MCA-END marks the end of the
/// last-seen region of code.
///
/// Code regions are not allowed to overlap. Each region can have a optional
/// description; internally, regions are described by a range of source
/// locations (SMLoc objects).
///
/// An instruction (a MCInst) is added to a CodeRegion R only if its
/// location is in range [R.RangeStart, R.RangeEnd].
///
/// A InstrumentRegion describes a region of assembly code guarded by
/// special LLVM-MCA comment directives.
///
/// # LLVM-MCA-<INSTRUMENTATION_TYPE> <data>
/// ... ## asm
///
/// where INSTRUMENTATION_TYPE is a type defined in llvm and expects to use
/// data.
///
/// A comment starting with substring LLVM-MCA-<INSTRUMENTATION_TYPE>
/// brings data into scope for llvm-mca to use in its analysis for
/// all following instructions.
///
/// If the same INSTRUMENTATION_TYPE is found later in the instruction list,
/// then the original InstrumentRegion will be automatically ended,
/// and a new InstrumentRegion will begin.
///
/// If there are comments containing the different INSTRUMENTATION_TYPEs,
/// then both data sets remain available. In contrast with a CodeRegion,
/// an InstrumentRegion does not need a comment to end the region.
//
// An instruction (a MCInst) is added to an InstrumentRegion R only
// if its location is in range [R.RangeStart, R.RangeEnd].
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_MCA_CODEREGION_H
#define LLVM_TOOLS_LLVM_MCA_CODEREGION_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MCA/CustomBehaviour.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/SourceMgr.h"
#include <vector>
namespace llvm {
namespace mca {
/// A region of assembly code.
///
/// It identifies a sequence of machine instructions.
class CodeRegion {
// An optional descriptor for this region.
llvm::StringRef Description;
// Instructions that form this region.
llvm::SmallVector<llvm::MCInst, 16> Instructions;
// Source location range.
llvm::SMLoc RangeStart;
llvm::SMLoc RangeEnd;
CodeRegion(const CodeRegion &) = delete;
CodeRegion &operator=(const CodeRegion &) = delete;
public:
CodeRegion(llvm::StringRef Desc, llvm::SMLoc Start)
: Description(Desc), RangeStart(Start) {}
virtual ~CodeRegion() = default;
void addInstruction(const llvm::MCInst &Instruction) {
Instructions.emplace_back(Instruction);
}
// Remove the given instructions from the set, for unsupported instructions
// being skipped. Returns an ArrayRef for the updated vector of Instructions.
[[nodiscard]] llvm::ArrayRef<llvm::MCInst>
dropInstructions(const llvm::SmallPtrSetImpl<const llvm::MCInst *> &Insts) {
if (Insts.empty())
return Instructions;
Instructions.erase(std::remove_if(Instructions.begin(), Instructions.end(),
[&Insts](const llvm::MCInst &Inst) {
return Insts.contains(&Inst);
}),
Instructions.end());
return Instructions;
}
llvm::SMLoc startLoc() const { return RangeStart; }
llvm::SMLoc endLoc() const { return RangeEnd; }
void setEndLocation(llvm::SMLoc End) { RangeEnd = End; }
bool empty() const { return Instructions.empty(); }
bool isLocInRange(llvm::SMLoc Loc) const;
llvm::ArrayRef<llvm::MCInst> getInstructions() const { return Instructions; }
llvm::StringRef getDescription() const { return Description; }
};
/// Alias AnalysisRegion with CodeRegion since CodeRegionGenerator
/// is absract and AnalysisRegionGenerator operates on AnalysisRegions
using AnalysisRegion = CodeRegion;
/// A CodeRegion that contains instrumentation that can be used
/// in analysis of the region.
class InstrumentRegion : public CodeRegion {
/// Instrument for this region.
UniqueInstrument I;
public:
InstrumentRegion(llvm::StringRef Desc, llvm::SMLoc Start, UniqueInstrument I)
: CodeRegion(Desc, Start), I(std::move(I)) {}
public:
Instrument *getInstrument() const { return I.get(); }
};
class CodeRegionParseError final : public Error {};
class CodeRegions {
CodeRegions(const CodeRegions &) = delete;
CodeRegions &operator=(const CodeRegions &) = delete;
protected:
// A source manager. Used by the tool to generate meaningful warnings.
llvm::SourceMgr &SM;
using UniqueCodeRegion = std::unique_ptr<CodeRegion>;
std::vector<UniqueCodeRegion> Regions;
llvm::StringMap<unsigned> ActiveRegions;
bool FoundErrors;
public:
CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {}
virtual ~CodeRegions() = default;
typedef std::vector<UniqueCodeRegion>::iterator iterator;
typedef std::vector<UniqueCodeRegion>::const_iterator const_iterator;
iterator begin() { return Regions.begin(); }
iterator end() { return Regions.end(); }
const_iterator begin() const { return Regions.cbegin(); }
const_iterator end() const { return Regions.cend(); }
void addInstruction(const llvm::MCInst &Instruction);
llvm::SourceMgr &getSourceMgr() const { return SM; }
llvm::ArrayRef<llvm::MCInst> getInstructionSequence(unsigned Idx) const {
return Regions[Idx]->getInstructions();
}
bool empty() const {
return llvm::all_of(Regions, [](const UniqueCodeRegion &Region) {
return Region->empty();
});
}
bool isValid() const { return !FoundErrors; }
bool isRegionActive(llvm::StringRef Description) const {
return ActiveRegions.contains(Description);
}
virtual void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc) = 0;
virtual void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc,
UniqueInstrument Instrument) = 0;
virtual void endRegion(llvm::StringRef Description, llvm::SMLoc Loc) = 0;
};
struct AnalysisRegions : public CodeRegions {
AnalysisRegions(llvm::SourceMgr &S);
void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc) override;
void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc,
UniqueInstrument Instrument) override {}
void endRegion(llvm::StringRef Description, llvm::SMLoc Loc) override;
};
struct InstrumentRegions : public CodeRegions {
InstrumentRegions(llvm::SourceMgr &S);
void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc) override{};
void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc,
UniqueInstrument Instrument) override;
void endRegion(llvm::StringRef Description, llvm::SMLoc Loc) override;
const SmallVector<Instrument *> getActiveInstruments(llvm::SMLoc Loc) const;
};
} // namespace mca
} // namespace llvm
#endif