Skip to content

[clang] Add flag fallow-runtime-check-skip-hot-cutoff #145999

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

Merged

Conversation

fmayer
Copy link
Contributor

@fmayer fmayer commented Jun 27, 2025

No description provided.

fmayer added 2 commits June 26, 2025 17:53
Created using spr 1.3.4
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. labels Jun 27, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 27, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-driver

Author: Florian Mayer (fmayer)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/145999.diff

7 Files Affected:

  • (modified) clang/include/clang/Basic/CodeGenOptions.h (+2)
  • (modified) clang/include/clang/Driver/Options.td (+10)
  • (modified) clang/lib/CodeGen/BackendUtil.cpp (+8-4)
  • (modified) clang/lib/Driver/ToolChains/Clang.cpp (+2-1)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+17)
  • (added) clang/test/CodeGen/fallow-runtime-check-skip-hot-cutoff.c (+9)
  • (added) clang/test/Driver/fallow-runtime-check-skip-hot-cutoff.c (+6)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 77a0c559f7689..1b99d56fc68e1 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -399,6 +399,8 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// with extra debug info.
   SanitizerSet SanitizeAnnotateDebugInfo;
 
+  std::optional<double> AllowRuntimeCheckSkipHotCutoff;
+
   /// List of backend command-line options for -fembed-bitcode.
   std::vector<uint8_t> CmdArgs;
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 0822df2640d23..c36daa2c3afea 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2668,6 +2668,16 @@ def fsanitize_skip_hot_cutoff_EQ
 
 } // end -f[no-]sanitize* flags
 
+def fallow_runtime_check_skip_hot_cutoff_EQ
+    : Joined<["-"], "fallow-runtime-check-skip-hot-cutoff=">,
+      Group<f_clang_Group>,
+      Visibility<[ClangOption, CC1Option]>,
+      HelpText<"Exclude __allow_runtime_check for the top hottest code "
+               "responsible for "
+               "the given fraction of PGO counters "
+               "(0.0 [default] = skip none; 1/.0 = skip all). "
+               "Argument format: <value>">;
+
 def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
   Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
   HelpText<"Allow unsafe floating-point math optimizations which may decrease precision">,
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 97bc063ad34e5..1c92ea45c7458 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -805,17 +805,21 @@ static void addSanitizers(const Triple &TargetTriple,
   // SanitizeSkipHotCutoffs: doubles with range [0, 1]
   // Opts.cutoffs: unsigned ints with range [0, 1000000]
   auto ScaledCutoffs = CodeGenOpts.SanitizeSkipHotCutoffs.getAllScaled(1000000);
-
+  uint64_t AllowRuntimeCheckSkipHotCutoff =
+      CodeGenOpts.AllowRuntimeCheckSkipHotCutoff.value_or(0.0) * 1000000;
   // TODO: remove IsRequested()
-  if (LowerAllowCheckPass::IsRequested() || ScaledCutoffs.has_value()) {
+  if (LowerAllowCheckPass::IsRequested() || ScaledCutoffs.has_value() ||
+      CodeGenOpts.AllowRuntimeCheckSkipHotCutoff.has_value()) {
     // We want to call it after inline, which is about OptimizerEarlyEPCallback.
     PB.registerOptimizerEarlyEPCallback(
-        [ScaledCutoffs](ModulePassManager &MPM, OptimizationLevel Level,
-                        ThinOrFullLTOPhase Phase) {
+        [ScaledCutoffs, AllowRuntimeCheckSkipHotCutoff](
+            ModulePassManager &MPM, OptimizationLevel Level,
+            ThinOrFullLTOPhase Phase) {
           LowerAllowCheckPass::Options Opts;
           // TODO: after removing IsRequested(), make this unconditional
           if (ScaledCutoffs.has_value())
             Opts.cutoffs = ScaledCutoffs.value();
+          Opts.runtime_check = AllowRuntimeCheckSkipHotCutoff;
           MPM.addPass(
               createModuleToFunctionPassAdaptor(LowerAllowCheckPass(Opts)));
         });
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 8a18865b899d2..ceb592d1548f5 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6028,7 +6028,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
   // complicated ways.
   auto SanitizeArgs = TC.getSanitizerArgs(Args);
-
+  Args.AddLastArg(CmdArgs,
+                  options::OPT_fallow_runtime_check_skip_hot_cutoff_EQ);
   bool IsAsyncUnwindTablesDefault =
       TC.getDefaultUnwindTableLevel(Args) == ToolChain::UnwindTableLevel::Asynchronous;
   bool IsSyncUnwindTablesDefault =
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 9e269ab244d4c..f366e90945dac 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1820,6 +1820,11 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
   for (std::string Sanitizer : Values)
     GenerateArg(Consumer, OPT_fsanitize_skip_hot_cutoff_EQ, Sanitizer);
 
+  if (Opts.AllowRuntimeCheckSkipHotCutoff) {
+    GenerateArg(Consumer, OPT_fallow_runtime_check_skip_hot_cutoff_EQ,
+                std::to_string(*Opts.AllowRuntimeCheckSkipHotCutoff));
+  }
+
   for (StringRef Sanitizer :
        serializeSanitizerKinds(Opts.SanitizeAnnotateDebugInfo))
     GenerateArg(Consumer, OPT_fsanitize_annotate_debug_info_EQ, Sanitizer);
@@ -2322,6 +2327,18 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
       Args.getAllArgValues(OPT_fsanitize_annotate_debug_info_EQ), Diags,
       Opts.SanitizeAnnotateDebugInfo);
 
+  if (StringRef V =
+          Args.getLastArgValue(OPT_fallow_runtime_check_skip_hot_cutoff_EQ);
+      !V.empty()) {
+    double A;
+    if (V.getAsDouble(A) || A < 0.0 || A > 1.0) {
+      Diags.Report(diag::err_drv_invalid_value)
+          << "-fallow-runtime-check-skip-hot-cutoff=" << V;
+    } else {
+      Opts.AllowRuntimeCheckSkipHotCutoff = A;
+    }
+  }
+
   Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
 
   if (!LangOpts->CUDAIsDevice)
diff --git a/clang/test/CodeGen/fallow-runtime-check-skip-hot-cutoff.c b/clang/test/CodeGen/fallow-runtime-check-skip-hot-cutoff.c
new file mode 100644
index 0000000000000..cede7530d2a22
--- /dev/null
+++ b/clang/test/CodeGen/fallow-runtime-check-skip-hot-cutoff.c
@@ -0,0 +1,9 @@
+// RUN: %clang -fallow-runtime-check-skip-hot-cutoff=1.0 -S -emit-llvm %s -o - -O2 | FileCheck --check-prefix=ONE %s
+// RUN: %clang -fallow-runtime-check-skip-hot-cutoff=0.0 -S -emit-llvm %s -o - -O2 | FileCheck --check-prefix=ZERO %s
+
+// ONE: ret i32 0
+// ZERO: ret i32 1
+
+int main(int argc, char** argv) {
+    return __builtin_allow_runtime_check("foo");
+}
diff --git a/clang/test/Driver/fallow-runtime-check-skip-hot-cutoff.c b/clang/test/Driver/fallow-runtime-check-skip-hot-cutoff.c
new file mode 100644
index 0000000000000..b186e6e74f162
--- /dev/null
+++ b/clang/test/Driver/fallow-runtime-check-skip-hot-cutoff.c
@@ -0,0 +1,6 @@
+// RUN: %clang -### -fallow-runtime-check-skip-hot-cutoff=1.0 %s 2>&1 | FileCheck %s
+// CHECK: -fallow-runtime-check-skip-hot-cutoff=1.0
+
+int main(int argc, char** argv) {
+    return __builtin_allow_runtime_check("foo");
+}

@fmayer fmayer changed the title Add flag fallow-runtime-check-skip-hot-cutoff [clang] Add flag fallow-runtime-check-skip-hot-cutoff Jun 27, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 27, 2025

@llvm/pr-subscribers-clang-codegen

Author: Florian Mayer (fmayer)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/145999.diff

7 Files Affected:

  • (modified) clang/include/clang/Basic/CodeGenOptions.h (+2)
  • (modified) clang/include/clang/Driver/Options.td (+10)
  • (modified) clang/lib/CodeGen/BackendUtil.cpp (+8-4)
  • (modified) clang/lib/Driver/ToolChains/Clang.cpp (+2-1)
  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+17)
  • (added) clang/test/CodeGen/fallow-runtime-check-skip-hot-cutoff.c (+9)
  • (added) clang/test/Driver/fallow-runtime-check-skip-hot-cutoff.c (+6)
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 77a0c559f7689..1b99d56fc68e1 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -399,6 +399,8 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// with extra debug info.
   SanitizerSet SanitizeAnnotateDebugInfo;
 
+  std::optional<double> AllowRuntimeCheckSkipHotCutoff;
+
   /// List of backend command-line options for -fembed-bitcode.
   std::vector<uint8_t> CmdArgs;
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 0822df2640d23..c36daa2c3afea 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2668,6 +2668,16 @@ def fsanitize_skip_hot_cutoff_EQ
 
 } // end -f[no-]sanitize* flags
 
+def fallow_runtime_check_skip_hot_cutoff_EQ
+    : Joined<["-"], "fallow-runtime-check-skip-hot-cutoff=">,
+      Group<f_clang_Group>,
+      Visibility<[ClangOption, CC1Option]>,
+      HelpText<"Exclude __allow_runtime_check for the top hottest code "
+               "responsible for "
+               "the given fraction of PGO counters "
+               "(0.0 [default] = skip none; 1/.0 = skip all). "
+               "Argument format: <value>">;
+
 def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
   Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
   HelpText<"Allow unsafe floating-point math optimizations which may decrease precision">,
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 97bc063ad34e5..1c92ea45c7458 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -805,17 +805,21 @@ static void addSanitizers(const Triple &TargetTriple,
   // SanitizeSkipHotCutoffs: doubles with range [0, 1]
   // Opts.cutoffs: unsigned ints with range [0, 1000000]
   auto ScaledCutoffs = CodeGenOpts.SanitizeSkipHotCutoffs.getAllScaled(1000000);
-
+  uint64_t AllowRuntimeCheckSkipHotCutoff =
+      CodeGenOpts.AllowRuntimeCheckSkipHotCutoff.value_or(0.0) * 1000000;
   // TODO: remove IsRequested()
-  if (LowerAllowCheckPass::IsRequested() || ScaledCutoffs.has_value()) {
+  if (LowerAllowCheckPass::IsRequested() || ScaledCutoffs.has_value() ||
+      CodeGenOpts.AllowRuntimeCheckSkipHotCutoff.has_value()) {
     // We want to call it after inline, which is about OptimizerEarlyEPCallback.
     PB.registerOptimizerEarlyEPCallback(
-        [ScaledCutoffs](ModulePassManager &MPM, OptimizationLevel Level,
-                        ThinOrFullLTOPhase Phase) {
+        [ScaledCutoffs, AllowRuntimeCheckSkipHotCutoff](
+            ModulePassManager &MPM, OptimizationLevel Level,
+            ThinOrFullLTOPhase Phase) {
           LowerAllowCheckPass::Options Opts;
           // TODO: after removing IsRequested(), make this unconditional
           if (ScaledCutoffs.has_value())
             Opts.cutoffs = ScaledCutoffs.value();
+          Opts.runtime_check = AllowRuntimeCheckSkipHotCutoff;
           MPM.addPass(
               createModuleToFunctionPassAdaptor(LowerAllowCheckPass(Opts)));
         });
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 8a18865b899d2..ceb592d1548f5 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6028,7 +6028,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
   // complicated ways.
   auto SanitizeArgs = TC.getSanitizerArgs(Args);
-
+  Args.AddLastArg(CmdArgs,
+                  options::OPT_fallow_runtime_check_skip_hot_cutoff_EQ);
   bool IsAsyncUnwindTablesDefault =
       TC.getDefaultUnwindTableLevel(Args) == ToolChain::UnwindTableLevel::Asynchronous;
   bool IsSyncUnwindTablesDefault =
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 9e269ab244d4c..f366e90945dac 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1820,6 +1820,11 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
   for (std::string Sanitizer : Values)
     GenerateArg(Consumer, OPT_fsanitize_skip_hot_cutoff_EQ, Sanitizer);
 
+  if (Opts.AllowRuntimeCheckSkipHotCutoff) {
+    GenerateArg(Consumer, OPT_fallow_runtime_check_skip_hot_cutoff_EQ,
+                std::to_string(*Opts.AllowRuntimeCheckSkipHotCutoff));
+  }
+
   for (StringRef Sanitizer :
        serializeSanitizerKinds(Opts.SanitizeAnnotateDebugInfo))
     GenerateArg(Consumer, OPT_fsanitize_annotate_debug_info_EQ, Sanitizer);
@@ -2322,6 +2327,18 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
       Args.getAllArgValues(OPT_fsanitize_annotate_debug_info_EQ), Diags,
       Opts.SanitizeAnnotateDebugInfo);
 
+  if (StringRef V =
+          Args.getLastArgValue(OPT_fallow_runtime_check_skip_hot_cutoff_EQ);
+      !V.empty()) {
+    double A;
+    if (V.getAsDouble(A) || A < 0.0 || A > 1.0) {
+      Diags.Report(diag::err_drv_invalid_value)
+          << "-fallow-runtime-check-skip-hot-cutoff=" << V;
+    } else {
+      Opts.AllowRuntimeCheckSkipHotCutoff = A;
+    }
+  }
+
   Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
 
   if (!LangOpts->CUDAIsDevice)
diff --git a/clang/test/CodeGen/fallow-runtime-check-skip-hot-cutoff.c b/clang/test/CodeGen/fallow-runtime-check-skip-hot-cutoff.c
new file mode 100644
index 0000000000000..cede7530d2a22
--- /dev/null
+++ b/clang/test/CodeGen/fallow-runtime-check-skip-hot-cutoff.c
@@ -0,0 +1,9 @@
+// RUN: %clang -fallow-runtime-check-skip-hot-cutoff=1.0 -S -emit-llvm %s -o - -O2 | FileCheck --check-prefix=ONE %s
+// RUN: %clang -fallow-runtime-check-skip-hot-cutoff=0.0 -S -emit-llvm %s -o - -O2 | FileCheck --check-prefix=ZERO %s
+
+// ONE: ret i32 0
+// ZERO: ret i32 1
+
+int main(int argc, char** argv) {
+    return __builtin_allow_runtime_check("foo");
+}
diff --git a/clang/test/Driver/fallow-runtime-check-skip-hot-cutoff.c b/clang/test/Driver/fallow-runtime-check-skip-hot-cutoff.c
new file mode 100644
index 0000000000000..b186e6e74f162
--- /dev/null
+++ b/clang/test/Driver/fallow-runtime-check-skip-hot-cutoff.c
@@ -0,0 +1,6 @@
+// RUN: %clang -### -fallow-runtime-check-skip-hot-cutoff=1.0 %s 2>&1 | FileCheck %s
+// CHECK: -fallow-runtime-check-skip-hot-cutoff=1.0
+
+int main(int argc, char** argv) {
+    return __builtin_allow_runtime_check("foo");
+}

@fmayer fmayer requested review from thurstond and delcypher and removed request for thurstond June 27, 2025 00:55
Created using spr 1.3.4
Copy link
Contributor

@thurstond thurstond left a comment

Choose a reason for hiding this comment

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

[this page intentionally left blank]

HelpText<"Exclude __allow_runtime_check for the top hottest code "
"responsible for "
"the given fraction of PGO counters "
"(0.0 [default] = skip none; 1/.0 = skip all). "
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: "1/.0"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -2668,6 +2668,16 @@ def fsanitize_skip_hot_cutoff_EQ

} // end -f[no-]sanitize* flags

def fallow_runtime_check_skip_hot_cutoff_EQ
Copy link
Contributor

Choose a reason for hiding this comment

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

"fallow" is either unfortunate or brilliant naming, similar to fun safe math. (I'm looking forward to the "fallow_fields" flag.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks?

@@ -2668,6 +2668,16 @@ def fsanitize_skip_hot_cutoff_EQ

} // end -f[no-]sanitize* flags

def fallow_runtime_check_skip_hot_cutoff_EQ
: Joined<["-"], "fallow-runtime-check-skip-hot-cutoff=">,
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be more user-friendly (and possibly less code duplication) to add "allow_runtime_check" as one of the options for the existing -fsanitize-skip-hot-cutoff (possibly renaming the flag since it would no longer be entirely sanitizers)? e.g., allow -fsanitize-skip-hot-cutoff=undefined=0.999999,allow_runtime_check=1.0

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not really about sanitizers though. Also if we want to teach this flag about kind=blah, that would become very messy.

Group<f_clang_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Exclude __allow_runtime_check for the top hottest code "
"responsible for "
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: string split is awkward

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

kazutakahirata and others added 2 commits June 27, 2025 11:41
Created using spr 1.3.4

[skip ci]
Created using spr 1.3.4
@fmayer fmayer changed the base branch from users/fmayer/spr/main.add-flag-fallow-runtime-check-skip-hot-cutoff to main June 27, 2025 18:51
@fmayer fmayer merged commit 8d2034c into main Jun 27, 2025
14 of 16 checks passed
@fmayer fmayer deleted the users/fmayer/spr/add-flag-fallow-runtime-check-skip-hot-cutoff branch June 27, 2025 20:46
rlavaee pushed a commit to rlavaee/llvm-project that referenced this pull request Jul 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants