[clang] [llvm] BPU Machine basic block placement fuzz (PR #116492)

Dmitriy Sokolov via cfe-commits cfe-commits at lists.llvm.org
Sat Nov 16 09:02:02 PST 2024


https://github.com/dee-tree created https://github.com/llvm/llvm-project/pull/116492

- Non-optimal machine basic block placement via fuzz option
- machine block frequency inversion under the special option

>From 8376db35a7a7736d78bb7f0febf38203e415b489 Mon Sep 17 00:00:00 2001
From: Arseny Bochkarev <bochkarevarseny at gmail.com>
Date: Wed, 25 Sep 2024 19:59:26 +0300
Subject: [PATCH 1/4] [Fuzz] Add compiler-assisted fuzzer prototype

---
 .../clang/Basic/DiagnosticDriverKinds.td      |  6 ++
 clang/include/clang/Driver/Options.td         | 27 +++++++
 clang/lib/Driver/ToolChains/Clang.cpp         | 71 ++++++++++++++--
 llvm/CMakeLists.txt                           |  1 +
 .../llvm/CompilerAssistedFuzzing/FuzzInfo.h   | 43 ++++++++++
 llvm/lib/CMakeLists.txt                       |  2 +-
 llvm/lib/CodeGen/CMakeLists.txt               |  1 +
 .../CompilerAssistedFuzzing/CMakeLists.txt    |  9 +++
 llvm/lib/CompilerAssistedFuzzing/FuzzInfo.cpp | 81 +++++++++++++++++++
 llvm/lib/Support/CMakeLists.txt               |  1 +
 llvm/lib/Support/Statistic.cpp                | 20 ++++-
 11 files changed, 255 insertions(+), 7 deletions(-)
 create mode 100644 llvm/include/llvm/CompilerAssistedFuzzing/FuzzInfo.h
 create mode 100644 llvm/lib/CompilerAssistedFuzzing/CMakeLists.txt
 create mode 100644 llvm/lib/CompilerAssistedFuzzing/FuzzInfo.cpp

diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 97573fcf20c1fb..f59c0e286e49e9 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -826,6 +826,12 @@ def warn_android_unversioned_fallback : Warning<
 def err_drv_triple_version_invalid : Error<
   "version '%0' in target triple '%1' is invalid">;
 
+def err_empty_option_value : Error<
+  "empty value for %0 option">;
+
+def warn_use_fseed : Warning<"Fuzzing with seed: %0">,
+  InGroup<DiagGroup<"fuzzing">>;
+
 def warn_missing_include_dirs : Warning<
   "no such include directory: '%0'">, InGroup<MissingIncludeDirs>, DefaultIgnore;
 }
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 23bd686a85f526..264ebd3541de15 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -6730,6 +6730,33 @@ let Flags = [TargetSpecific] in {
 defm android_pad_segment : BooleanFFlag<"android-pad-segment">, Group<f_Group>;
 } // let Flags = [TargetSpecific]
 
+// Compiler-assisted fuzzing options
+def fuzz_EQ : Joined<["--"], "fuzz=">,
+  Flags<[NoXarchOption, HelpHidden]>, Group<f_Group>,
+  HelpText<"Fuzz selected compiler components, RISC-V only."
+  "Usage: --fuzz=\"<component1>[|<component2>...]\"">,
+  Values<"all, scheduler, mbb-placement, regalloc, isel, alloca">;
+
+def fseed_EQ : Joined<["--"], "fseed=">,
+  Flags<[NoXarchOption, HelpHidden]>, Group<f_Group>,
+  HelpText<"Specify fuzzing seed. (RISC-V only)">;
+
+def fseed_dump : Flag<["-"], "fseed-dump">,
+  Visibility<[ClangOption, CLOption]>,
+  Group<sycl_Group>, HelpText<"Dump fuzz seed. (RISC-V only)">;
+
+def fno_fseed_dump : Flag<["-"], "fno-fseed-dump">,
+  Visibility<[ClangOption, CLOption]>,
+  Group<sycl_Group>, HelpText<"Disable fuzz seed dump. (RISC-V only)">;
+
+def fuzz_stats_dump : Flag<["-"], "fuzz-stats-dump">,
+  Visibility<[ClangOption, CLOption]>,
+  Group<sycl_Group>, HelpText<"Dump only fuzz statistics.">;
+
+def fno_fuzz_stats_dump : Flag<["-"], "fno-fuzz-stats-dump">,
+  Visibility<[ClangOption, CLOption]>,
+  Group<sycl_Group>, HelpText<"Dump not only fuzz statistics.">;
+
 //===----------------------------------------------------------------------===//
 // FLangOption + NoXarchOption
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 0bab48caf1a5e2..c10cd539942040 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7646,11 +7646,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
 
   // Setup statistics file output.
   SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
-  if (!StatsFile.empty()) {
-    CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile));
-    if (D.CCPrintInternalStats)
-      CmdArgs.push_back("-stats-file-append");
-  }
+  auto FuzzStatsDump = Args.hasFlag(options::OPT_fuzz_stats_dump,
+                                    options::OPT_fno_fuzz_stats_dump, false);
+  if (!StatsFile.empty() || FuzzStatsDump) {
+    if (FuzzStatsDump) {
+      CmdArgs.push_back("-mllvm");
+      CmdArgs.push_back("-fuzz-only-stats");
+    }
+    if (StatsFile.empty()) {
+      StatsFile.assign(Output.getFilename());
+      llvm::sys::path::replace_extension(StatsFile, "stats");
+    }
 
   // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
   // parser.
@@ -8050,6 +8056,61 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
       Input.getInputArg().renderAsInput(Args, CmdArgs);
   }
 
+  // Handle --fuzz=<fuzz options>
+  StringRef FuzzOptions = Args.getLastArgValue(options::OPT_fuzz_EQ).trim();
+  if (!FuzzOptions.empty()) {
+    auto Tail = FuzzOptions;
+    llvm::SmallVector<StringRef> ActualOpts;
+
+    do {
+      auto Pair = Tail.split('|');
+
+      StringRef Fst = Pair.first.trim();
+      Tail = Pair.second.trim();
+
+      if (!Fst.empty()) {
+        ActualOpts.push_back(Fst);
+      }
+    } while (!Tail.empty());
+
+    if (ActualOpts.empty()) {
+      D.Diag(diag::err_empty_option_value) << "fuzz";
+    }
+
+    llvm::SmallVector<StringRef> CorrectOpts = {
+        "all", "scheduler", "mbb-placement", "regalloc", "isel", "alloca"};
+
+    for (const auto &ActualOpt : ActualOpts)
+      if (llvm::find(CorrectOpts, ActualOpt) == CorrectOpts.end())
+        D.Diag(diag::err_analyzer_checker_option_unknown)
+            << "fuzzer" << ActualOpt;
+
+    // Pass correct arguments to LLVM
+    CmdArgs.push_back("-mllvm");
+    std::string FuzzComponentsArgStr = "-fuzz-components=";
+    const char *FuzzComponentsArg =
+        Args.MakeArgStringRef(FuzzComponentsArgStr + FuzzOptions.data());
+    CmdArgs.push_back(FuzzComponentsArg);
+
+    StringRef FuzzSeedStr = Args.getLastArgValue(options::OPT_fseed_EQ).trim();
+    int64_t SeedValue;
+    if (FuzzSeedStr.empty() ||
+        FuzzSeedStr.getAsInteger<int64_t>(0, SeedValue)) {
+      SeedValue = std::chrono::system_clock::now().time_since_epoch().count();
+    }
+
+    auto StrSeed = std::to_string(SeedValue);
+
+    if (Args.hasFlag(options::OPT_fseed_dump, options::OPT_fno_fseed_dump,
+                     false))
+      D.Diag(diag::warn_use_fseed) << StrSeed;
+
+    CmdArgs.push_back("-mllvm");
+    std::string FuzzSeedArgStr = "-fuzz-seed=";
+    const char *FuzzSeedArg = Args.MakeArgStringRef(FuzzSeedArgStr + StrSeed);
+    CmdArgs.push_back(FuzzSeedArg);
+  }
+
   if (D.CC1Main && !D.CCGenDiagnostics) {
     // Invoke the CC1 directly in this process
     C.addCommand(std::make_unique<CC1Command>(
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 330db65e85cabb..5bcfc6cac475f4 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -1242,6 +1242,7 @@ endif()
 # Put this before tblgen. Else we have a circular dependence.
 add_subdirectory(lib/Demangle)
 add_subdirectory(lib/Support)
+add_subdirectory(lib/CompilerAssistedFuzzing)
 add_subdirectory(lib/TableGen)
 
 add_subdirectory(utils/TableGen)
diff --git a/llvm/include/llvm/CompilerAssistedFuzzing/FuzzInfo.h b/llvm/include/llvm/CompilerAssistedFuzzing/FuzzInfo.h
new file mode 100644
index 00000000000000..9f908d0f64ed86
--- /dev/null
+++ b/llvm/include/llvm/CompilerAssistedFuzzing/FuzzInfo.h
@@ -0,0 +1,43 @@
+#ifndef LLVM_FUZZINFO_H
+#define LLVM_FUZZINFO_H
+
+#include "llvm/ADT/Statistic.h"
+#include <functional>
+#include <string>
+#include <vector>
+
+namespace fuzz {
+using StatRefWrapper = std::reference_wrapper<llvm::TrackingStatistic>;
+
+class Component final {
+  std::string Name;
+  std::vector<StatRefWrapper> Stats;
+
+public:
+  Component(std::string &&n) noexcept : Name(std::move(n)) {}
+
+  Component &operator=(const Component &) = delete;
+  Component(const Component &) = delete;
+
+  Component &operator=(Component &&) = delete;
+  Component(Component &&) = delete;
+
+  const Component &operator+=(llvm::TrackingStatistic &Stat);
+  const std::string &GetName() const { return Name; }
+  const std::vector<StatRefWrapper> &GetStats() const { return Stats; }
+};
+
+extern Component Scheduler;
+extern Component MBBPlacement;
+extern Component RegAlloc;
+extern Component ISel;
+extern Component Alloca;
+
+bool isFuzzed(fuzz::Component &Comp, llvm::TrackingStatistic &Stat);
+int64_t fuzzedIntRange(fuzz::Component &Comp, llvm::TrackingStatistic &Stat,
+                       int64_t Start, int64_t End, int64_t Default);
+
+bool CheckStat(const llvm::TrackingStatistic &Stat);
+} // namespace fuzz
+
+#endif // LLVM_FUZZINFO_H
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index 503c77cb13bd07..f8bbec50153c5e 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -1,6 +1,6 @@
 include(LLVM-Build)
 
-# `Demangle', `Support' and `TableGen' libraries are added on the top-level
+# `CompilerAssistedFuzzing`, `Demangle', `Support' and `TableGen' libraries are added on the top-level
 # CMakeLists.txt
 
 add_subdirectory(IR)
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index 5a17944db0ae03..ba573578a68887 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -270,6 +270,7 @@ add_llvm_component_library(LLVMCodeGen
   BitWriter
   CGData
   CodeGenTypes
+  CompilerAssistedFuzzing
   Core
   MC
   ObjCARC
diff --git a/llvm/lib/CompilerAssistedFuzzing/CMakeLists.txt b/llvm/lib/CompilerAssistedFuzzing/CMakeLists.txt
new file mode 100644
index 00000000000000..25e8eba2eeb871
--- /dev/null
+++ b/llvm/lib/CompilerAssistedFuzzing/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_llvm_component_library(LLVMCompilerAssistedFuzzing
+  FuzzInfo.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  "${LLVM_MAIN_INCLUDE_DIR}/llvm/CompilerAssistedFuzzing"
+
+  LINK_COMPONENTS
+  Support
+)
diff --git a/llvm/lib/CompilerAssistedFuzzing/FuzzInfo.cpp b/llvm/lib/CompilerAssistedFuzzing/FuzzInfo.cpp
new file mode 100644
index 00000000000000..4d3d1eb4cf31ce
--- /dev/null
+++ b/llvm/lib/CompilerAssistedFuzzing/FuzzInfo.cpp
@@ -0,0 +1,81 @@
+#include "llvm/CompilerAssistedFuzzing/FuzzInfo.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/CommandLine.h"
+
+#include <cassert>
+#include <cmath>
+
+#define DEBUG_TYPE "fuzz"
+
+using namespace llvm;
+
+std::string FuzzComponents;
+static cl::opt<std::string, true>
+    FuzzingComponents("fuzz-components",
+                      cl::desc("Compiler components to fuzz."),
+                      cl::location(FuzzComponents), cl::init(""));
+
+int64_t FuzzSeed;
+static cl::opt<int64_t, true> FuzzingSeed("fuzz-seed",
+                                          cl::desc("Compiler fuzzing seed."),
+                                          cl::location(FuzzSeed), cl::init(0));
+
+using fuzz::Component;
+
+Component fuzz::Scheduler("scheduler");
+Component fuzz::MBBPlacement("mbb-placement");
+Component fuzz::RegAlloc("regalloc");
+Component fuzz::ISel("isel");
+Component fuzz::Alloca("alloca");
+std::array<std::reference_wrapper<Component>, 5> Components{
+    fuzz::Scheduler, fuzz::MBBPlacement, fuzz::RegAlloc, fuzz::ISel,
+    fuzz::Alloca};
+
+inline bool isCompUsed(const Component &Comp) {
+  if (FuzzComponents.find("all") != std::string::npos)
+    return true;
+
+  return FuzzComponents.find(Comp.GetName()) != std::string::npos;
+}
+
+const Component &Component::operator+=(llvm::TrackingStatistic &Stat) {
+  if (llvm::find_if(Stats, [&Stat](const fuzz::StatRefWrapper &St) -> bool {
+        return St.get().getName() == Stat.getName();
+      }) == Stats.end()) {
+    Stats.emplace_back(Stat);
+  }
+  Stat++;
+  return *this;
+}
+
+bool fuzz::isFuzzed(Component &Comp, llvm::TrackingStatistic &Stat) {
+  if (isCompUsed(Comp)) {
+    Comp += Stat;
+    return true;
+  }
+
+  return false;
+}
+
+int64_t fuzz::fuzzedIntRange(Component &Comp, llvm::TrackingStatistic &Stat,
+                             int64_t Start, int64_t End, int64_t Default) {
+  if (!isFuzzed(Comp, Stat)) {
+    return Default;
+  }
+
+  int64_t Length = End - Start;
+  assert(Length > 0 && "Length must be non negative");
+
+  return (std::abs(FuzzSeed) % Length) + Start;
+}
+
+bool fuzz::CheckStat(const llvm::TrackingStatistic &Stat) {
+  for (const auto &C : Components) {
+    for (const auto &St : C.get().GetStats()) {
+      if (Stat.getName() == St.get().getName())
+        return true;
+    }
+  }
+
+  return false;
+}
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 97188b0672f032..ee7df40ba1de5c 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -299,6 +299,7 @@ add_llvm_component_library(LLVMSupport
 
   LINK_COMPONENTS
   Demangle
+  CompilerAssistedFuzzing
   )
 
 set(llvm_system_libs ${system_libs})
diff --git a/llvm/lib/Support/Statistic.cpp b/llvm/lib/Support/Statistic.cpp
index 24ef3e9abaebce..7961a68adc0c56 100644
--- a/llvm/lib/Support/Statistic.cpp
+++ b/llvm/lib/Support/Statistic.cpp
@@ -25,6 +25,7 @@
 #include "DebugOptions.h"
 
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/CompilerAssistedFuzzing/FuzzInfo.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Debug.h"
@@ -45,6 +46,7 @@ static bool EnableStats;
 static bool StatsAsJSON;
 static bool Enabled;
 static bool PrintOnExit;
+static bool FuzzOnlyStats;
 
 void llvm::initStatisticOptions() {
   static cl::opt<bool, true> registerEnableStats{
@@ -55,6 +57,9 @@ void llvm::initStatisticOptions() {
   static cl::opt<bool, true> registerStatsAsJson{
       "stats-json", cl::desc("Display statistics as json data"),
       cl::location(StatsAsJSON), cl::Hidden};
+  static cl::opt<bool, true> registerFuzzOnlyStats{
+      "fuzz-only-stats", cl::desc("Dump only fuzz stats."),
+      cl::location(FuzzOnlyStats), cl::Hidden};
 }
 
 namespace {
@@ -173,6 +178,14 @@ void StatisticInfo::reset() {
   Stats.clear();
 }
 
+static bool isPrintValid(const TrackingStatistic *Stat) {
+  if (!FuzzOnlyStats) {
+    return true;
+  }
+
+  return fuzz::CheckStat(*Stat);
+}
+
 void llvm::PrintStatistics(raw_ostream &OS) {
   StatisticInfo &Stats = *StatInfo;
 
@@ -192,9 +205,12 @@ void llvm::PrintStatistics(raw_ostream &OS) {
      << "===" << std::string(73, '-') << "===\n\n";
 
   // Print all of the statistics.
-  for (TrackingStatistic *Stat : Stats.Stats)
+  for (TrackingStatistic *Stat : Stats.Stats) {
+    if (!isPrintValid(Stat))
+      continue;
     OS << format("%*" PRIu64 " %-*s - %s\n", MaxValLen, Stat->getValue(),
                  MaxDebugTypeLen, Stat->getDebugType(), Stat->getDesc());
+  }
 
   OS << '\n';  // Flush the output stream.
   OS.flush();
@@ -210,6 +226,8 @@ void llvm::PrintStatisticsJSON(raw_ostream &OS) {
   OS << "{\n";
   const char *delim = "";
   for (const TrackingStatistic *Stat : Stats.Stats) {
+    if (!isPrintValid(Stat))
+      continue;
     OS << delim;
     assert(yaml::needsQuotes(Stat->getDebugType()) == yaml::QuotingType::None &&
            "Statistic group/type name is simple.");

>From a0255d0935d19446a6e52660c6b4585fd370d140 Mon Sep 17 00:00:00 2001
From: d-tolmachev <den.filipchenko0000 at gmail.com>
Date: Mon, 7 Oct 2024 14:08:05 +0300
Subject: [PATCH 2/4] Bug fixes

---
 clang/include/clang/Basic/DiagnosticDriverKinds.td | 2 +-
 clang/lib/Driver/ToolChains/Clang.cpp              | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index f59c0e286e49e9..73766d45c29a58 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -829,7 +829,7 @@ def err_drv_triple_version_invalid : Error<
 def err_empty_option_value : Error<
   "empty value for %0 option">;
 
-def warn_use_fseed : Warning<"Fuzzing with seed: %0">,
+def warn_use_fseed : Warning<"fuzzing with seed: %0">,
   InGroup<DiagGroup<"fuzzing">>;
 
 def warn_missing_include_dirs : Warning<
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index c10cd539942040..82232856324078 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7657,6 +7657,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
       StatsFile.assign(Output.getFilename());
       llvm::sys::path::replace_extension(StatsFile, "stats");
     }
+  }
 
   // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
   // parser.

>From 5ab8f99993dcdd755b22f44cdbda2360f6db8b0b Mon Sep 17 00:00:00 2001
From: Arseny Bochkarev <arseny.bochkarev at syntacore.com>
Date: Sun, 13 Oct 2024 18:49:46 +0300
Subject: [PATCH 3/4] [Options] Add a BPU component to fuzz

---
 clang/include/clang/Driver/Options.td                | 2 +-
 clang/lib/Driver/ToolChains/Clang.cpp                | 2 +-
 llvm/include/llvm/CompilerAssistedFuzzing/FuzzInfo.h | 1 +
 llvm/lib/CompilerAssistedFuzzing/FuzzInfo.cpp        | 5 +++--
 4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 264ebd3541de15..502826ff325524 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -6735,7 +6735,7 @@ def fuzz_EQ : Joined<["--"], "fuzz=">,
   Flags<[NoXarchOption, HelpHidden]>, Group<f_Group>,
   HelpText<"Fuzz selected compiler components, RISC-V only."
   "Usage: --fuzz=\"<component1>[|<component2>...]\"">,
-  Values<"all, scheduler, mbb-placement, regalloc, isel, alloca">;
+  Values<"all, scheduler, mbb-placement, regalloc, isel, alloca, bpu">;
 
 def fseed_EQ : Joined<["--"], "fseed=">,
   Flags<[NoXarchOption, HelpHidden]>, Group<f_Group>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 82232856324078..563adaa813eb09 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -8079,7 +8079,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     }
 
     llvm::SmallVector<StringRef> CorrectOpts = {
-        "all", "scheduler", "mbb-placement", "regalloc", "isel", "alloca"};
+        "all", "scheduler", "mbb-placement", "regalloc", "isel", "alloca", "bpu"};
 
     for (const auto &ActualOpt : ActualOpts)
       if (llvm::find(CorrectOpts, ActualOpt) == CorrectOpts.end())
diff --git a/llvm/include/llvm/CompilerAssistedFuzzing/FuzzInfo.h b/llvm/include/llvm/CompilerAssistedFuzzing/FuzzInfo.h
index 9f908d0f64ed86..1d2cf45103ba3a 100644
--- a/llvm/include/llvm/CompilerAssistedFuzzing/FuzzInfo.h
+++ b/llvm/include/llvm/CompilerAssistedFuzzing/FuzzInfo.h
@@ -32,6 +32,7 @@ extern Component MBBPlacement;
 extern Component RegAlloc;
 extern Component ISel;
 extern Component Alloca;
+extern Component BPU;
 
 bool isFuzzed(fuzz::Component &Comp, llvm::TrackingStatistic &Stat);
 int64_t fuzzedIntRange(fuzz::Component &Comp, llvm::TrackingStatistic &Stat,
diff --git a/llvm/lib/CompilerAssistedFuzzing/FuzzInfo.cpp b/llvm/lib/CompilerAssistedFuzzing/FuzzInfo.cpp
index 4d3d1eb4cf31ce..17df4e399299ce 100644
--- a/llvm/lib/CompilerAssistedFuzzing/FuzzInfo.cpp
+++ b/llvm/lib/CompilerAssistedFuzzing/FuzzInfo.cpp
@@ -24,12 +24,13 @@ using fuzz::Component;
 
 Component fuzz::Scheduler("scheduler");
 Component fuzz::MBBPlacement("mbb-placement");
+Component fuzz::BPU("bpu");
 Component fuzz::RegAlloc("regalloc");
 Component fuzz::ISel("isel");
 Component fuzz::Alloca("alloca");
-std::array<std::reference_wrapper<Component>, 5> Components{
+std::array<std::reference_wrapper<Component>, 6> Components{
     fuzz::Scheduler, fuzz::MBBPlacement, fuzz::RegAlloc, fuzz::ISel,
-    fuzz::Alloca};
+    fuzz::Alloca, fuzz::BPU};
 
 inline bool isCompUsed(const Component &Comp) {
   if (FuzzComponents.find("all") != std::string::npos)

>From 095597422083749054462fae3b58f81f162ea314 Mon Sep 17 00:00:00 2001
From: dmitriy sokolov <codemitry at gmail.com>
Date: Sat, 16 Nov 2024 19:58:21 +0300
Subject: [PATCH 4/4] bpu: machine basic block placement fuzzing (unoptimal
 placement)

block frequency inversion added under special flag
---
 llvm/lib/Analysis/BlockFrequencyInfoImpl.cpp | 16 ++++++
 llvm/lib/CodeGen/MachineBlockPlacement.cpp   | 57 +++++++++++++++-----
 2 files changed, 60 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Analysis/BlockFrequencyInfoImpl.cpp b/llvm/lib/Analysis/BlockFrequencyInfoImpl.cpp
index 9f6e53ba15b6a6..40b028ca225125 100644
--- a/llvm/lib/Analysis/BlockFrequencyInfoImpl.cpp
+++ b/llvm/lib/Analysis/BlockFrequencyInfoImpl.cpp
@@ -15,6 +15,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SCCIterator.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Statistic.h"
 #include "llvm/Config/llvm-config.h"
 #include "llvm/IR/Function.h"
 #include "llvm/Support/BlockFrequency.h"
@@ -62,6 +63,13 @@ cl::opt<double> IterativeBFIPrecision(
              "typically lead to better results at the cost of worsen runtime"));
 } // namespace llvm
 
+static cl::opt<bool> BFIInverse("bfi-invert",
+                       cl::desc("Force inverting of BFI values during computation."),
+                       cl::init(false), cl::Hidden);
+
+ALWAYS_ENABLED_STATISTIC(NumInvertedBFI, "BFI: inverted frequences amount");
+
+
 ScaledNumber<uint64_t> BlockMass::toScaled() const {
   if (isFull())
     return ScaledNumber<uint64_t>(1, 0);
@@ -554,6 +562,14 @@ void BlockFrequencyInfoImplBase::finalizeMetrics() {
     Max = std::max(Max, Freqs[Index].Scaled);
   }
 
+  if (BFIInverse) {
+    for (size_t Index = 0; Index < Working.size(); ++Index) {
+      Freqs[Index].Scaled = Max + Min - Freqs[Index].Scaled;
+      NumInvertedBFI++;
+    }
+  }
+  
+
   // Convert to integers.
   convertFloatingToInteger(*this, Min, Max);
 
diff --git a/llvm/lib/CodeGen/MachineBlockPlacement.cpp b/llvm/lib/CodeGen/MachineBlockPlacement.cpp
index a52c82d77ca644..0a9316ffeae0ce 100644
--- a/llvm/lib/CodeGen/MachineBlockPlacement.cpp
+++ b/llvm/lib/CodeGen/MachineBlockPlacement.cpp
@@ -48,6 +48,7 @@
 #include "llvm/CodeGen/TargetLowering.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/CompilerAssistedFuzzing/FuzzInfo.h"
 #include "llvm/IR/DebugLoc.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/PrintPasses.h"
@@ -84,6 +85,14 @@ STATISTIC(CondBranchTakenFreq,
 STATISTIC(UncondBranchTakenFreq,
           "Potential frequency of taking unconditional branches");
 
+ALWAYS_ENABLED_STATISTIC(NumHasBadCfgConflict, "Machine Basic Block Placement num of bad layout predecessors found");
+ALWAYS_ENABLED_STATISTIC(NumSingleSuccessorTailDup, "Machine Basic Block Placement: tail duplication if BB has a single successor");
+ALWAYS_ENABLED_STATISTIC(NumBestNonConflictingEdgesComparatorGet, "Machine Basic Block Placement: best non-conflicting edges comparator get");
+ALWAYS_ENABLED_STATISTIC(NumBestNonConflictingEdgesExchange, "Machine Basic Block Placement: best non-conflicting edges exchange");
+ALWAYS_ENABLED_STATISTIC(NumBestSuccessorCheck, "Machine Basic Block Placement: best successor search");
+ALWAYS_ENABLED_STATISTIC(NumSuitableTailDupCheck, "Machine Basic Block Placement: best candidate for tail dup check");
+ALWAYS_ENABLED_STATISTIC(NumSelectBestCandidateBlock, "Machine Basic Block Placement: best candidate block selection");
+
 static cl::opt<unsigned> AlignAllBlock(
     "align-all-blocks",
     cl::desc("Force the alignment of all blocks in the function in log2 format "
@@ -799,7 +808,7 @@ bool MachineBlockPlacement::shouldTailDuplicate(MachineBasicBlock *BB) {
   bool IsSimple = TailDup.isSimpleBB(BB);
 
   if (BB->succ_size() == 1)
-    return false;
+    return isFuzzed(fuzz::BPU, NumSingleSuccessorTailDup); // return false;
   return TailDup.shouldTailDuplicate(IsSimple, *BB);
 }
 
@@ -1037,7 +1046,7 @@ MachineBlockPlacement::getBestNonConflictingEdges(
   // compare which combination is better overall.
 
   // Sort for highest frequency.
-  auto Cmp = [](WeightedEdge A, WeightedEdge B) { return A.Weight > B.Weight; };
+  auto Cmp = isFuzzed(fuzz::BPU, NumBestNonConflictingEdgesComparatorGet) ? [](WeightedEdge A, WeightedEdge B) { return A.Weight < B.Weight; } : [](WeightedEdge A, WeightedEdge B) { return A.Weight > B.Weight; };
 
   llvm::stable_sort(Edges[0], Cmp);
   llvm::stable_sort(Edges[1], Cmp);
@@ -1051,10 +1060,18 @@ MachineBlockPlacement::getBestNonConflictingEdges(
     auto SecondBestB = std::next(BestB);
     BlockFrequency BestAScore = BestA->Weight + SecondBestB->Weight;
     BlockFrequency BestBScore = BestB->Weight + SecondBestA->Weight;
-    if (BestAScore < BestBScore)
-      BestA = SecondBestA;
-    else
-      BestB = SecondBestB;
+
+    if (isFuzzed(fuzz::BPU, NumBestNonConflictingEdgesExchange)) {
+      if (BestAScore > BestBScore)
+        BestA = SecondBestA;
+      else
+        BestB = SecondBestB;
+    } else {
+      if (BestAScore < BestBScore)
+        BestA = SecondBestA;
+      else
+        BestB = SecondBestB;
+      }
   }
   // Arrange for the BB edge to be in BestA if it exists.
   if (BestB->Src == BB)
@@ -1576,7 +1593,9 @@ bool MachineBlockPlacement::hasBetterLayoutPredecessor(
     BlockFrequency PredEdgeFreq =
         MBFI->getBlockFreq(Pred) * MBPI->getEdgeProbability(Pred, Succ);
     if (PredEdgeFreq * HotProb >= CandidateEdgeFreq * HotProb.getCompl()) {
-      BadCFGConflict = true;
+      if (!isFuzzed(fuzz::BPU, NumHasBadCfgConflict)) {
+        BadCFGConflict = true;
+      }
       break;
     }
   }
@@ -1661,9 +1680,16 @@ MachineBlockPlacement::selectBestSuccessor(const MachineBasicBlock *BB,
                << (SuccChain.UnscheduledPredecessors != 0 ? " (CFG break)" : "")
                << "\n");
 
-    if (BestSucc.BB && BestProb >= SuccProb) {
-      LLVM_DEBUG(dbgs() << "    Not the best candidate, continuing\n");
-      continue;
+    if (isFuzzed(fuzz::BPU, NumBestSuccessorCheck)) {
+      if (BestSucc.BB && BestProb <= SuccProb) {
+        LLVM_DEBUG(dbgs() << "    Not the worst candidate, continuing\n");
+        continue;
+      }
+    } else {
+      if (BestSucc.BB && BestProb >= SuccProb) {
+        LLVM_DEBUG(dbgs() << "    Not the best candidate, continuing\n");
+        continue;
+      }
     }
 
     LLVM_DEBUG(dbgs() << "    Setting it as best candidate\n");
@@ -1684,7 +1710,7 @@ MachineBlockPlacement::selectBestSuccessor(const MachineBasicBlock *BB,
     BranchProbability DupProb;
     MachineBasicBlock *Succ;
     std::tie(DupProb, Succ) = Tup;
-    if (DupProb < BestProb)
+    if (DupProb < BestProb && !isFuzzed(fuzz::BPU, NumSuitableTailDupCheck))
       break;
     if (canTailDuplicateUnplacedPreds(BB, Succ, Chain, BlockFilter) &&
         (isProfitableToTailDup(BB, Succ, BestProb, Chain, BlockFilter))) {
@@ -1764,8 +1790,13 @@ MachineBasicBlock *MachineBlockPlacement::selectBestCandidateBlock(
     //                 +-------------------------------------+
     //                 V                                     |
     // OuterLp -> OuterCleanup -> Resume     InnerLp -> InnerCleanup
-    if (BestBlock && (IsEHPad ^ (BestFreq >= CandidateFreq)))
-      continue;
+    if (isFuzzed(fuzz::BPU, NumSelectBestCandidateBlock)) {
+      if (BestBlock && (IsEHPad ^ (BestFreq <= CandidateFreq)))
+        continue;
+    } else {
+      if (BestBlock && (IsEHPad ^ (BestFreq >= CandidateFreq)))
+        continue;
+    }
 
     BestBlock = MBB;
     BestFreq = CandidateFreq;



More information about the cfe-commits mailing list