Skip to content

[TableGen] Enhance testability of TableGen-based macro fusion #73075

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,43 @@ class TargetRegisterInfo;
class TargetSchedModel;
class Triple;

//===----------------------------------------------------------------------===//

/// Used to provide information for macro fusion.
struct MacroFusionEntry {
const char *Name; ///< Name of macro fusion
MacroFusionPredTy Pred; ///< Predicator function of macro fusion

/// Compare routine for std::lower_bound
bool operator<(StringRef S) const { return StringRef(Name) < S; }

/// Compare routine for std::is_sorted.
bool operator<(const MacroFusionEntry &Other) const {
return StringRef(Name) < StringRef(Other.Name);
}
};

//===----------------------------------------------------------------------===//
///
/// TargetSubtargetInfo - Generic base class for all target subtargets. All
/// Target-specific options that control code generation and printing should
/// be exposed through a TargetSubtargetInfo-derived class.
///
class TargetSubtargetInfo : public MCSubtargetInfo {
private:
ArrayRef<MacroFusionEntry> MacroFusionTable;

protected: // Can only create subclasses...
TargetSubtargetInfo(const Triple &TT, StringRef CPU, StringRef TuneCPU,
StringRef FS, ArrayRef<SubtargetFeatureKV> PF,
ArrayRef<SubtargetSubTypeKV> PD,
const MCWriteProcResEntry *WPR,
const MCWriteLatencyEntry *WL,
const MCReadAdvanceEntry *RA, const InstrStage *IS,
const unsigned *OC, const unsigned *FP);
const unsigned *OC, const unsigned *FP,
ArrayRef<MacroFusionEntry> MF);

void overrideFusionBits();

public:
// AntiDepBreakMode - Type of anti-dependence breaking that should
Expand Down Expand Up @@ -326,7 +348,7 @@ class TargetSubtargetInfo : public MCSubtargetInfo {
virtual bool enableSpillageCopyElimination() const { return false; }

/// Get the list of MacroFusion predicates.
virtual std::vector<MacroFusionPredTy> getMacroFusions() const { return {}; }
virtual std::vector<MacroFusionPredTy> getMacroFusions() const;
};

} // end namespace llvm
Expand Down
17 changes: 9 additions & 8 deletions llvm/include/llvm/MC/MCSubtargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class MCSubtargetInfo {
FeatureBitset FeatureBits; // Feature bits for current CPU + FS
std::string FeatureString; // Feature string

MacroFusionBitset FusionBits; // Fusion bits

public:
MCSubtargetInfo(const MCSubtargetInfo &) = default;
MCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef TuneCPU,
Expand Down Expand Up @@ -120,10 +122,13 @@ class MCSubtargetInfo {
return FeatureBits[Feature];
}

const MacroFusionBitset &getMacroFusionBits() const { return FusionBits; }
void enableMacroFusion(unsigned MacroFusion) { FusionBits.set(MacroFusion); }
void disableMacroFusion(unsigned MacroFusion) {
FusionBits.reset(MacroFusion);
}
bool hasMacroFusion(unsigned MacroFusion) const {
const MacroFusionBitset *MacroFusionBits =
CPUSchedModel->getMacroFusionBits();
return MacroFusionBits && MacroFusionBits->test(MacroFusion);
return FusionBits.test(MacroFusion);
}

protected:
Expand Down Expand Up @@ -303,11 +308,7 @@ class MCSubtargetInfo {
virtual bool shouldPrefetchAddressSpace(unsigned AS) const;

/// Enable macro fusion for this subtarget.
virtual bool enableMacroFusion() const {
const MacroFusionBitset *MacroFusionBits =
CPUSchedModel->getMacroFusionBits();
return MacroFusionBits && MacroFusionBits->any();
}
virtual bool enableMacroFusion() const { return FusionBits.any(); }
};

} // end namespace llvm
Expand Down
35 changes: 18 additions & 17 deletions llvm/include/llvm/Target/TargetSchedule.td
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,8 @@ def OneUse : OneUsePred;
// return true;
// }
// ```
class Fusion<list<FusionPredicate> predicates> {
class Fusion<string name, list<FusionPredicate> predicates> {
string Name = name;
list<FusionPredicate> Predicates = predicates;
}

Expand All @@ -683,21 +684,21 @@ class Fusion<list<FusionPredicate> predicates> {
// return true;
// }
// ```
class SimpleFusion<MCInstPredicate firstPred, MCInstPredicate secondPred,
class SimpleFusion<string name, MCInstPredicate firstPred, MCInstPredicate secondPred,
list<FusionPredicate> prolog = [],
list<FusionPredicate> epilog = []>
: Fusion<!listconcat(
prolog,
[
SecondFusionPredicateWithMCInstPredicate<secondPred>,
WildcardTrue,
FirstFusionPredicateWithMCInstPredicate<firstPred>,
SecondFusionPredicateWithMCInstPredicate<
CheckAny<[
CheckIsVRegOperand<0>,
CheckSameRegOperand<0, 1>
]>>,
OneUse,
TieReg<0, 1>,
],
epilog)>;
: Fusion<name, !listconcat(
prolog,
[
SecondFusionPredicateWithMCInstPredicate<secondPred>,
WildcardTrue,
FirstFusionPredicateWithMCInstPredicate<firstPred>,
SecondFusionPredicateWithMCInstPredicate<
CheckAny<[
CheckIsVRegOperand<0>,
CheckSameRegOperand<0, 1>
]>>,
OneUse,
TieReg<0, 1>,
],
epilog)>;
60 changes: 58 additions & 2 deletions llvm/lib/CodeGen/TargetSubtargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,62 @@

using namespace llvm;

static cl::list<std::string> MFusions("mfusion", cl::CommaSeparated,
cl::desc("Target specific macro fusions"),
cl::value_desc("a1,+a2,-a3,..."));

TargetSubtargetInfo::TargetSubtargetInfo(
const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS,
ArrayRef<SubtargetFeatureKV> PF, ArrayRef<SubtargetSubTypeKV> PD,
const MCWriteProcResEntry *WPR, const MCWriteLatencyEntry *WL,
const MCReadAdvanceEntry *RA, const InstrStage *IS, const unsigned *OC,
const unsigned *FP)
: MCSubtargetInfo(TT, CPU, TuneCPU, FS, PF, PD, WPR, WL, RA, IS, OC, FP) {}
const unsigned *FP, ArrayRef<MacroFusionEntry> MF)
: MCSubtargetInfo(TT, CPU, TuneCPU, FS, PF, PD, WPR, WL, RA, IS, OC, FP),
MacroFusionTable(MF) {
// assert if MacroFusionTable is not sorted.
assert(llvm::is_sorted(MacroFusionTable));
overrideFusionBits();
}

TargetSubtargetInfo::~TargetSubtargetInfo() = default;

void TargetSubtargetInfo::overrideFusionBits() {
if (MFusions.getNumOccurrences() != 0) {
for (std::string &MFusion : MFusions) {
char Prefix = MFusion[0];
bool Disable = Prefix == '-';
if (Prefix == '+' || Prefix == '-')
MFusion = MFusion.substr(1);

// MacroFusionTable is sorted.
const auto *Pos = std::lower_bound(
MacroFusionTable.begin(), MacroFusionTable.end(), MFusion,
[](const MacroFusionEntry &LHS, const std::string &RHS) {
int CmpName = StringRef(LHS.Name).compare(RHS);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this just return String(LHS.Name).compare(RHS) < 0

if (CmpName < 0)
return true;
if (CmpName > 0)
return false;
return false;
});

if (Pos == MacroFusionTable.end()) {
errs() << "'" << MFusion
<< "' is not a recognized macro fusion for this "
<< "target (ignoring it)\n";
continue;
}

// The index is the same as the enum value.
unsigned Idx = Pos - MacroFusionTable.begin();
if (Disable)
disableMacroFusion(Idx);
else
enableMacroFusion(Idx);
}
}
}

bool TargetSubtargetInfo::enableAtomicExpand() const {
return true;
}
Expand Down Expand Up @@ -58,3 +104,13 @@ bool TargetSubtargetInfo::useAA() const {
}

void TargetSubtargetInfo::mirFileLoaded(MachineFunction &MF) const { }

std::vector<MacroFusionPredTy> TargetSubtargetInfo::getMacroFusions() const {
std::vector<MacroFusionPredTy> Fusions;
const MacroFusionBitset &Bits = getMacroFusionBits();
for (unsigned I = 0; I < MacroFusionTable.size(); I++)
if (Bits[I])
Fusions.push_back(MacroFusionTable[I].Pred);

return Fusions;
}
2 changes: 2 additions & 0 deletions llvm/lib/MC/MCSubtargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ void MCSubtargetInfo::InitMCProcessorInfo(StringRef CPU, StringRef TuneCPU,
CPUSchedModel = &getSchedModelForCPU(TuneCPU);
else
CPUSchedModel = &MCSchedModel::GetDefaultSchedModel();
if (CPUSchedModel->getMacroFusionBits())
FusionBits = *CPUSchedModel->getMacroFusionBits();
}

void MCSubtargetInfo::setDefaultFeatures(StringRef CPU, StringRef TuneCPU,
Expand Down
2 changes: 1 addition & 1 deletion llvm/unittests/CodeGen/MFCommon.inc
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class BogusSubtarget : public TargetSubtargetInfo {
public:
BogusSubtarget(TargetMachine &TM)
: TargetSubtargetInfo(Triple(""), "", "", "", {}, {}, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr),
nullptr, nullptr, nullptr, nullptr, {}),
FL(), TL(TM) {}
~BogusSubtarget() override {}

Expand Down
61 changes: 33 additions & 28 deletions llvm/utils/TableGen/SubtargetEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "PredicateExpander.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCInstrItineraries.h"
Expand Down Expand Up @@ -134,7 +135,7 @@ class SubtargetEmitter {

void EmitSchedModel(raw_ostream &OS);
void emitMacroFusionBits(const CodeGenProcModel &ProcModel, raw_ostream &OS);
void emitGetMacroFusions(const std::string &ClassName, raw_ostream &OS);
void emitMacroFusionTable(RecVec Fusions, raw_ostream &OS);
void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS);
void ParseFeaturesFunction(raw_ostream &OS);

Expand Down Expand Up @@ -1789,25 +1790,23 @@ void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName,
PE.expandSTIPredicate(OS, Fn);
}

void SubtargetEmitter::emitGetMacroFusions(const std::string &ClassName,
raw_ostream &OS) {
OS << "std::vector<MacroFusionPredTy> " << ClassName
<< "::getMacroFusions() const {\n";
OS.indent(2) << "switch(getSchedModel().getProcessorID()) {\n";
for (auto &Proc : TGT.getSchedModels().procModels()) {
if (Proc.hasMacroFusions()) {
OS.indent(4) << "case " << Proc.Index << ": // " << Proc.ModelName
<< "\n";
OS.indent(4) << " return {";
std::vector<std::string> Predicates;
for (auto *R : Proc.MacroFusions)
Predicates.push_back("is" + R->getNameInitAsString());
OS << llvm::join(Predicates, ", ");
OS << "};\n";
}
void SubtargetEmitter::emitMacroFusionTable(RecVec Fusions, raw_ostream &OS) {
OS << "const llvm::MacroFusionEntry " << Target << "MacroFusionTable[] = {\n";

SmallSet<StringRef, 32> Names;
for (auto &Fusion : Fusions) {
StringRef Name = Fusion->getValueAsString("Name");
if (Name.empty())
PrintFatalError(Fusion->getLoc(),
"The name of macro fusion cannot be empty");
if (Names.contains(Name))
PrintFatalError(Fusion->getLoc(),
"The name of macro fusion already exists");
OS.indent(2) << "{\"" << Name << "\", "
<< "llvm::is" + Fusion->getNameInitAsString() << "},\n";
}
OS.indent(2) << "}\n";
OS.indent(2) << "return {};\n}\n";

OS << "};\n\n";
}

void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName,
Expand Down Expand Up @@ -2027,9 +2026,6 @@ void SubtargetEmitter::run(raw_ostream &OS) {
<< " const;\n";
if (TGT.getHwModes().getNumModeIds() > 1)
OS << " unsigned getHwMode() const override;\n";
if (TGT.getSchedModels().hasMacroFusions())
OS << " std::vector<MacroFusionPredTy> getMacroFusions() const "
"override;\n";

STIPredicateExpander PE(Target);
PE.setByRef(false);
Expand All @@ -2044,6 +2040,13 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n";
OS << "#undef GET_SUBTARGETINFO_CTOR\n\n";

std::vector<Record *> Fusions = Records.getAllDerivedDefinitions("Fusion");
// Sort macro fusions by name.
llvm::sort(Fusions, LessRecord());

if (!Fusions.empty())
emitMacroFusionTable(Fusions, OS);

OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n";
OS << "namespace llvm {\n";
OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
Expand Down Expand Up @@ -2078,17 +2081,19 @@ void SubtargetEmitter::run(raw_ostream &OS) {
<< Target << "ReadAdvanceTable, ";
OS << '\n'; OS.indent(24);
if (SchedModels.hasItineraries()) {
OS << Target << "Stages, "
<< Target << "OperandCycles, "
<< Target << "ForwardingPaths";
OS << Target << "Stages, " << Target << "OperandCycles, " << Target
<< "ForwardingPaths, ";
} else
OS << "nullptr, nullptr, nullptr";
OS << "nullptr, nullptr, nullptr, ";
if (!Fusions.empty()) {
OS << "ArrayRef(" << Target << "MacroFusionTable, " << Fusions.size()
<< ")";
} else
OS << "std::nullopt";
OS << ") {}\n\n";

EmitSchedModelHelpers(ClassName, OS);
EmitHwModeCheck(ClassName, OS);
if (TGT.getSchedModels().hasMacroFusions())
emitGetMacroFusions(ClassName, OS);

OS << "} // end namespace llvm\n\n";

Expand Down