Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
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
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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?

: 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

"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

"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">,
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
});
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
15 changes: 15 additions & 0 deletions clang/test/CodeGen/fallow-runtime-check-skip-hot-cutoff.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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
// RUN: not %clang -fallow-runtime-check-skip-hot-cutoff=6.0 -S -emit-llvm %s -o - -O2 2>&1 | FileCheck --check-prefix=SIX %s
// RUN: not %clang -fallow-runtime-check-skip-hot-cutoff=-1.0 -S -emit-llvm %s -o - -O2 2>&1 | FileCheck --check-prefix=MINUSONE %s
// RUN: not %clang -fallow-runtime-check-skip-hot-cutoff=string -S -emit-llvm %s -o - -O2 2>&1 | FileCheck --check-prefix=STRING %s

// ONE: ret i32 0
// ZERO: ret i32 1
// SIX: invalid value '6.0' in '-fallow-runtime-check-skip-hot-cutoff='
// MINUSONE: invalid value '-1.0' in '-fallow-runtime-check-skip-hot-cutoff='
// STRING: invalid value 'string' in '-fallow-runtime-check-skip-hot-cutoff='

int main(int argc, char** argv) {
return __builtin_allow_runtime_check("foo");
}
6 changes: 6 additions & 0 deletions clang/test/Driver/fallow-runtime-check-skip-hot-cutoff.c
Original file line number Diff line number Diff line change
@@ -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");
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class LowerAllowCheckPass : public PassInfoMixin<LowerAllowCheckPass> {
public:
struct Options {
std::vector<unsigned int> cutoffs;
uint64_t runtime_check;
};

explicit LowerAllowCheckPass(LowerAllowCheckPass::Options Opts)
Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,19 @@ parseLowerAllowCheckPassOptions(StringRef Params) {

Result.cutoffs[index] = cutoff;
}
} else if (ParamName.starts_with("runtime_check")) {
StringRef ValueString;
std::tie(std::ignore, ValueString) = ParamName.split("=");
int runtime_check;
if (ValueString.getAsInteger(0, runtime_check)) {
return make_error<StringError>(
formatv("invalid LowerAllowCheck pass runtime_check parameter '{}' "
"({})",
ValueString, Params)
.str(),
inconvertibleErrorCode());
}
Result.runtime_check = runtime_check;
} else {
return make_error<StringError>(
formatv("invalid LowerAllowCheck pass parameter '{}'", ParamName)
Expand Down
18 changes: 14 additions & 4 deletions llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ static void emitRemark(IntrinsicInst *II, OptimizationRemarkEmitter &ORE,
static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI,
const ProfileSummaryInfo *PSI,
OptimizationRemarkEmitter &ORE,
const std::vector<unsigned int> &cutoffs) {
const LowerAllowCheckPass::Options &Opts) {
SmallVector<std::pair<IntrinsicInst *, bool>, 16> ReplaceWithValue;
std::unique_ptr<RandomNumberGenerator> Rng;

Expand All @@ -89,8 +89,10 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI,
return HotPercentileCutoff;
else if (II->getIntrinsicID() == Intrinsic::allow_ubsan_check) {
auto *Kind = cast<ConstantInt>(II->getArgOperand(0));
if (Kind->getZExtValue() < cutoffs.size())
return cutoffs[Kind->getZExtValue()];
if (Kind->getZExtValue() < Opts.cutoffs.size())
return Opts.cutoffs[Kind->getZExtValue()];
} else if (II->getIntrinsicID() == Intrinsic::allow_runtime_check) {
return Opts.runtime_check;
}

return 0;
Expand Down Expand Up @@ -157,7 +159,7 @@ PreservedAnalyses LowerAllowCheckPass::run(Function &F,
OptimizationRemarkEmitter &ORE =
AM.getResult<OptimizationRemarkEmitterAnalysis>(F);

return removeUbsanTraps(F, BFI, PSI, ORE, Opts.cutoffs)
return removeUbsanTraps(F, BFI, PSI, ORE, Opts)
// We do not change the CFG, we only replace the intrinsics with
// true or false.
? PreservedAnalyses::none().preserveSet<CFGAnalyses>()
Expand All @@ -182,14 +184,22 @@ void LowerAllowCheckPass::printPipeline(
// correctness.
// TODO: print shorter output by combining adjacent runs, etc.
int i = 0;
bool printed = false;
for (unsigned int cutoff : Opts.cutoffs) {
if (cutoff > 0) {
if (i > 0)
OS << ";";
OS << "cutoffs[" << i << "]=" << cutoff;
printed = true;
}

i++;
}
if (Opts.runtime_check) {
if (printed)
OS << ";";
OS << "runtime_check=" << Opts.runtime_check;
}

OS << '>';
}
9 changes: 9 additions & 0 deletions llvm/test/Transforms/lower-builtin-allow-check-remarks.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@
; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check)' -lower-allow-check-percentile-cutoff-hot=0 -pass-remarks=lower-allow-check -pass-remarks-missed=lower-allow-check -S 2>&1 | FileCheck %s
; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check)' -lower-allow-check-percentile-cutoff-hot=1000000 -pass-remarks=lower-allow-check -pass-remarks-missed=lower-allow-check -S 2>&1 | FileCheck %s --check-prefixes=REMOVE

; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs[7]=0;runtime_check=1000000>)' -pass-remarks=lower-allow-check -pass-remarks-missed=lower-allow-check -S 2>&1 | FileCheck %s --check-prefixes=MIXED
; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs[7]=1000000;runtime_check=0>)' -pass-remarks=lower-allow-check -pass-remarks-missed=lower-allow-check -S 2>&1 | FileCheck %s --check-prefixes=MIXED2

; CHECK: remark: <unknown>:0:0: Allowed check: Kind=test_check F=test_runtime BB=entry1
; CHECK: remark: <unknown>:0:0: Allowed check: Kind=7 F=test_ubsan BB=entry2

; REMOVE: remark: <unknown>:0:0: Removed check: Kind=test_check F=test_runtime BB=entry1
; REMOVE: remark: <unknown>:0:0: Removed check: Kind=7 F=test_ubsan BB=entry2

; MIXED: remark: <unknown>:0:0: Removed check: Kind=test_check F=test_runtime BB=entry1
; MIXED: remark: <unknown>:0:0: Allowed check: Kind=7 F=test_ubsan BB=entry2

; MIXED2: remark: <unknown>:0:0: Allowed check: Kind=test_check F=test_runtime BB=entry1
; MIXED2: remark: <unknown>:0:0: Removed check: Kind=7 F=test_ubsan BB=entry2

target triple = "x86_64-pc-linux-gnu"

define i1 @test_runtime() local_unnamed_addr {
Expand Down