From a803f82a86b82926ced83f99a23bd71b2b7fc7e9 Mon Sep 17 00:00:00 2001 From: Ksenia Dobrovolskaya Date: Wed, 4 Mar 2026 12:07:26 +0000 Subject: [PATCH] [snippy] Removed calls from the histogram when they cannot be generated --- .../calls/erase-calls-from-histogram.yaml | 21 +++++++++ .../include/snippy/Config/Config.h | 20 +++++---- .../include/snippy/Config/OpcodeHistogram.h | 12 ++++++ .../include/snippy/Generator/Policy.h | 6 --- .../include/snippy/Support/OpcodeGenerator.h | 11 ----- llvm/tools/llvm-snippy/lib/Config/Config.cpp | 43 ++++++++++--------- .../OperandsReinitializationPolicy.cpp | 4 +- .../llvm-snippy/lib/Generator/Policy.cpp | 4 +- .../llvm-snippy/lib/PostGenVerifierPass.cpp | 3 +- .../lib/Support/OpcodeGenerator.cpp | 5 +-- .../lib/Target/RISCV/RVVUnitConfig.cpp | 4 -- 11 files changed, 72 insertions(+), 61 deletions(-) create mode 100644 llvm/test/tools/llvm-snippy/calls/erase-calls-from-histogram.yaml diff --git a/llvm/test/tools/llvm-snippy/calls/erase-calls-from-histogram.yaml b/llvm/test/tools/llvm-snippy/calls/erase-calls-from-histogram.yaml new file mode 100644 index 000000000000..a259ac1264bd --- /dev/null +++ b/llvm/test/tools/llvm-snippy/calls/erase-calls-from-histogram.yaml @@ -0,0 +1,21 @@ +# COM: This test checks that when calls can't be generated, they are removed +# from the histogram. + +# RUN: llvm-snippy %s -model-plugin None \ +# RUN: |& FileCheck %s + +options: + mtriple: riscv64 + num-instrs: 1000 + dump-mf: on + +include: + - ../Inputs/sections.yaml + +histogram: + - [ADD, 1.0] + - [JALR, 1.0] + - [JAL, 1.0] + +# CHECK: ADD +# CHECK-NOT: CALL diff --git a/llvm/tools/llvm-snippy/include/snippy/Config/Config.h b/llvm/tools/llvm-snippy/include/snippy/Config/Config.h index 6019e3d7ac3e..9577be6e216b 100644 --- a/llvm/tools/llvm-snippy/include/snippy/Config/Config.h +++ b/llvm/tools/llvm-snippy/include/snippy/Config/Config.h @@ -145,10 +145,11 @@ class DefaultPolicyConfig { DefaultPolicyConfig(const CommonPolicyConfig &Common) : Common(&Common) {} Expected - createOpcodeGenerator(const OpcodeCache &OpCC, - const std::function &OpcMask) const { + createOpcodeGenerator(const std::function &OpcMask) const { - assert(!DataFlowHistogram.empty()); + if (DataFlowHistogram.empty()) + snippy::fatal( + "OpcodeGenerator initialization failure: empty histogram specified."); std::map DFHCopy; llvm::copy_if(DataFlowHistogram, std::inserter(DFHCopy, DFHCopy.end()), @@ -348,11 +349,14 @@ class Config final { ~Config() = default; - // FIXME: legacy that must be removed - // FIXME: this should return OpcGenHolder - std::unique_ptr createDefaultOpcodeGenerator() const { - return std::make_unique(Histogram.begin(), - Histogram.end()); + std::map + getOpcodeProbabilities() const { + std::map OpcodeProb; + transform(Histogram, std::inserter(OpcodeProb, OpcodeProb.end()), + [TotalWeight = Histogram.getTotalWeight()](auto &Elem) { + return std::make_pair(Elem.first, Elem.second / TotalWeight); + }); + return OpcodeProb; } const OpcodeHistogram &getOpcodeHistogram() const { return Histogram; } diff --git a/llvm/tools/llvm-snippy/include/snippy/Config/OpcodeHistogram.h b/llvm/tools/llvm-snippy/include/snippy/Config/OpcodeHistogram.h index d89b7094a362..4a7465d3385a 100644 --- a/llvm/tools/llvm-snippy/include/snippy/Config/OpcodeHistogram.h +++ b/llvm/tools/llvm-snippy/include/snippy/Config/OpcodeHistogram.h @@ -63,6 +63,18 @@ class OpcodeHistogram : private std::map { }); } + // FIXME: We are waiting for C++20. + auto erase_if(std::function Pred) { + auto OldSize = size(); + for (auto Hist = begin(), Last = end(); Hist != Last;) { + if (Pred(Hist->first)) + Hist = erase(Hist, std::next(Hist)); + else + ++Hist; + } + return OldSize - size(); + } + double getTotalWeight() const { return getOpcodesWeight([](unsigned) { return true; }); } diff --git a/llvm/tools/llvm-snippy/include/snippy/Generator/Policy.h b/llvm/tools/llvm-snippy/include/snippy/Generator/Policy.h index 9ed3d12c3339..08dc1b2d3a5a 100644 --- a/llvm/tools/llvm-snippy/include/snippy/Generator/Policy.h +++ b/llvm/tools/llvm-snippy/include/snippy/Generator/Policy.h @@ -376,12 +376,6 @@ struct EmptyFinalizeMixin { }; } // namespace detail -OpcGenHolder createDefaultOpcGenerator( - SnippyProgramContext &ProgCtx, const Config &Cfg, - std::function Filter, bool MustHavePrimaryInstrs, - ArrayRef Overrides, - const std::unordered_map &WeightOverrides = {}); - // This policy is used to insert mode changing instructions and provide context // for other policies that follow it. class ModeChangingInstPolicy final : public detail::EmptyFinalizeMixin { diff --git a/llvm/tools/llvm-snippy/include/snippy/Support/OpcodeGenerator.h b/llvm/tools/llvm-snippy/include/snippy/Support/OpcodeGenerator.h index 28bf3b38052d..6ba3e9564ba5 100644 --- a/llvm/tools/llvm-snippy/include/snippy/Support/OpcodeGenerator.h +++ b/llvm/tools/llvm-snippy/include/snippy/Support/OpcodeGenerator.h @@ -70,17 +70,6 @@ class DefaultOpcodeGenerator final : public OpcodeGeneratorInterface { const OpcodeList &getOpcodesList() const { return Opcodes; } - std::map - getProbabilities() const { - std::map Output; - const auto OpcodeWeight = zip(Opcodes, OpcodeDist.probabilities()); - for (const auto [Opcode, Weight] : OpcodeWeight) { - assert(Output.count(Opcode) == 0); - Output[Opcode] = Weight; - } - return Output; - } - void print(llvm::raw_ostream &OS) const override; void dump() const override { print(dbgs()); } diff --git a/llvm/tools/llvm-snippy/lib/Config/Config.cpp b/llvm/tools/llvm-snippy/lib/Config/Config.cpp index 0dac36244681..8ab8574e7c71 100644 --- a/llvm/tools/llvm-snippy/lib/Config/Config.cpp +++ b/llvm/tools/llvm-snippy/lib/Config/Config.cpp @@ -1158,38 +1158,38 @@ static bool hasCallees(const FunctionDesc &FuncDesc) { return FuncDesc.Callees.size(); } -static void checkCallRequirements( - const SnippyTarget &Tgt, const OpcodeHistogram &Histogram, +static void deleteCallsIfNeeded( + const SnippyTarget &Tgt, OpcodeHistogram &Histogram, const std::variant &CGLayout) { - bool HasCalls = Histogram.getOpcodesWeight([&Tgt](unsigned Opcode) { - return Tgt.isCall(Opcode); - }) > 0.0; - bool HasNonCalls = Histogram.getOpcodesWeight([&Tgt](unsigned Opcode) { - return !Tgt.isCall(Opcode); - }) > 0.0; - if (HasCalls && !HasNonCalls) + auto IsCall = [&Tgt](unsigned Opcode) { return Tgt.isCall(Opcode); }; + auto CallsWeight = Histogram.getOpcodesWeight(IsCall); + if (CallsWeight < std::numeric_limits::epsilon()) + return; + if (std::abs(Histogram.getTotalWeight() - CallsWeight) < + std::numeric_limits::epsilon()) snippy::fatal( "for using calls you need to add to histogram non-call instructions"); - if (!HasCalls) - return; - std::visit(OverloadedCallable( - [](const FunctionDescs &Descs) -> void { + [&Histogram, IsCall](const FunctionDescs &Descs) -> void { if (!std::any_of(Descs.Descs.begin(), Descs.Descs.end(), - hasCallees)) + hasCallees)) { snippy::warn( WarningName::CannotGenerateCalls, "Provided call-graph doesn't allow generation of " "calls as no callees were found", "no calls will be generated"); + Histogram.erase_if(IsCall); + } }, - [](const CallGraphLayout &CGLayout) -> void { - if (auto NumFunc = CGLayout.FunctionNumber; NumFunc < 2) + [&Histogram, IsCall](const CallGraphLayout &CGLayout) -> void { + if (auto NumFunc = CGLayout.FunctionNumber; NumFunc < 2) { snippy::warn(WarningName::CannotGenerateCalls, "Not enough functions specified to generate " "calls (required at least 2)", "-function-number is " + Twine(NumFunc)); + Histogram.erase_if(IsCall); + } }), CGLayout); } @@ -1478,7 +1478,6 @@ void Config::validateAll(LLVMState &State, const OpcodeCache &OpCC, "it is required to enable selfcheck"); if (BurstConfig) checkBurstGram(Ctx, Histogram, OpCC, BurstConfig->Burst); - checkCallRequirements(Tgt, Histogram, CGLayout); checkMemoryRegions(Tgt, *this); Tgt.checkInstrTargetDependency(Histogram, OpCC); if (hasTrackingMode()) @@ -1606,10 +1605,12 @@ void Config::complete(LLVMState &State, const OpcodeCache &OpCC) { auto BurstOpcodes = BCfg.Burst.getAllBurstOpcodes(); return BurstOpcodes.count(Opc); }; - auto &DFHistogram = DefFlowConfig.DataFlowHistogram; - DFHistogram.clear(); - std::copy_if(Histogram.begin(), Histogram.end(), - std::inserter(DFHistogram, DFHistogram.end()), + auto DFHistogram = Histogram; + deleteCallsIfNeeded(State.getSnippyTarget(), DFHistogram, PassCfg.CGLayout); + DefFlowConfig.DataFlowHistogram.clear(); + std::copy_if(DFHistogram.begin(), DFHistogram.end(), + std::inserter(DefFlowConfig.DataFlowHistogram, + DefFlowConfig.DataFlowHistogram.end()), [&](const auto &Hist) { auto *Desc = OpCC.desc(Hist.first); assert(Desc); diff --git a/llvm/tools/llvm-snippy/lib/Generator/OperandsReinitializationPolicy.cpp b/llvm/tools/llvm-snippy/lib/Generator/OperandsReinitializationPolicy.cpp index 9f1660454419..482a70413f30 100644 --- a/llvm/tools/llvm-snippy/lib/Generator/OperandsReinitializationPolicy.cpp +++ b/llvm/tools/llvm-snippy/lib/Generator/OperandsReinitializationPolicy.cpp @@ -173,9 +173,7 @@ void ValuegramGenPolicy::initialize(InstructionGenerationContext &InstrGenCtx, const auto &Filter = ModeChangingPolicy ? ModeChangingPolicy->getOpcodeFilter() : getDefaultFilter(Tgt); - auto Err = - Cfg->createOpcodeGenerator(InstrGenCtx.ProgCtx.getOpcodeCache(), Filter) - .moveInto(OpcGen); + auto Err = Cfg->createOpcodeGenerator(Filter).moveInto(OpcGen); if (Err) snippy::fatal( Twine("Failed to create OpcodeGenerator in ValuegramGenPolicy: ") + diff --git a/llvm/tools/llvm-snippy/lib/Generator/Policy.cpp b/llvm/tools/llvm-snippy/lib/Generator/Policy.cpp index 67e7e7196829..126d3c629e95 100644 --- a/llvm/tools/llvm-snippy/lib/Generator/Policy.cpp +++ b/llvm/tools/llvm-snippy/lib/Generator/Policy.cpp @@ -151,9 +151,7 @@ void DefaultGenPolicy::initialize(InstructionGenerationContext &InstrGenCtx, const auto &Filter = ModeChangingPolicy ? ModeChangingPolicy->getOpcodeFilter() : getDefaultFilter(Tgt); - auto Err = - Cfg->createOpcodeGenerator(InstrGenCtx.ProgCtx.getOpcodeCache(), Filter) - .moveInto(OpcGen); + auto Err = Cfg->createOpcodeGenerator(Filter).moveInto(OpcGen); if (Err) snippy::fatal( Twine("Failed to create OpcodeGenerator in DefaultGenPolicy: ") + diff --git a/llvm/tools/llvm-snippy/lib/PostGenVerifierPass.cpp b/llvm/tools/llvm-snippy/lib/PostGenVerifierPass.cpp index 779c39f9c5ce..51ba36e260a8 100644 --- a/llvm/tools/llvm-snippy/lib/PostGenVerifierPass.cpp +++ b/llvm/tools/llvm-snippy/lib/PostGenVerifierPass.cpp @@ -131,8 +131,7 @@ void PostGenVerifier::printData(const MachineFunction &MF) const { const GeneratorContext &SGCtx = CtxWrapper.getContext(); const OpcodeCache &OpCache = SGCtx.getProgramContext().getOpcodeCache(); - auto ExpectedDist = - SGCtx.getConfig().createDefaultOpcodeGenerator()->getProbabilities(); + auto ExpectedDist = SGCtx.getConfig().getOpcodeProbabilities(); auto &Output = outs(); constexpr unsigned OpcodeWidth = 12; diff --git a/llvm/tools/llvm-snippy/lib/Support/OpcodeGenerator.cpp b/llvm/tools/llvm-snippy/lib/Support/OpcodeGenerator.cpp index 06e8af47d50e..f227cab5542c 100644 --- a/llvm/tools/llvm-snippy/lib/Support/OpcodeGenerator.cpp +++ b/llvm/tools/llvm-snippy/lib/Support/OpcodeGenerator.cpp @@ -15,9 +15,8 @@ namespace snippy { void DefaultOpcodeGenerator::print(llvm::raw_ostream &OS) const { OS << "OpcodeGen:\n"; - auto Prob = getProbabilities(); - for (const auto &[Opcode, P] : Prob) - OS << " Opcode: " << Opcode << ": " << floatToString(P, 3) << "\n"; + for (const auto &[Opcode, Prob] : zip(Opcodes, OpcodeDist.probabilities())) + OS << " Opcode: " << Opcode << ": " << floatToString(Prob, 3) << "\n"; } unsigned DefaultOpcodeGenerator::generate() { diff --git a/llvm/tools/llvm-snippy/lib/Target/RISCV/RVVUnitConfig.cpp b/llvm/tools/llvm-snippy/lib/Target/RISCV/RVVUnitConfig.cpp index c667edab456e..1903a706d600 100644 --- a/llvm/tools/llvm-snippy/lib/Target/RISCV/RVVUnitConfig.cpp +++ b/llvm/tools/llvm-snippy/lib/Target/RISCV/RVVUnitConfig.cpp @@ -310,10 +310,6 @@ static auto extractElementsWithProbabilities(const SliceType &ConfSlice) { ModeChangeInfo deriveModeSwitchingProbability(const Config &Cfg, const ModeChangeBias &Bias) { - // FIXME: This is here only to cause fatal errors in case we can't create - // OpcGen (e.g. empty histogram) - Cfg.createDefaultOpcodeGenerator(); - const auto &Hist = Cfg.Histogram; double TotalWeight = Hist.getTotalWeight(); ModeChangeInfo Result;