https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/124211
>From 5d1944f522152a7356d8e8147d3b3c5939c32526 Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Wed, 22 Jan 2025 18:59:07 +0000 Subject: [PATCH 1/7] [ubsan] Plumb through -fsanitize-skip-hot-cutoff to LowerAllowCheckPass This passes through the values of -fsanitize-skip-hot-cutoff (introduced patch in https://github.com/llvm/llvm-project/pull/121619) to the LowerAllowCheckPass, via the Options parameter (introduced in https://github.com/llvm/llvm-project/pull/122994), and adjusts the instrumentation accordingly. The net effect is that -fsanitize-skip-hot-cutoff now combines the functionality of -ubsan-guard-checks and -lower-allow-check-percentile-cutoff (though this patch does not remove those yet), and generalizes the latter to allow per-sanitizer cutoffs. Note: this patch replaces Intrinsic::allow_ubsan_check's SanitizerHandler parameter with SanitizerOrdinal; this is necessary because the hot cutoffs are specified in terms of SanitizerOrdinal (e.g., null, alignment), not SanitizerHandler (e.g., TypeMismatch). --- clang/lib/CodeGen/BackendUtil.cpp | 27 +++- clang/lib/CodeGen/CGExpr.cpp | 30 ++-- clang/lib/Frontend/CompilerInvocation.cpp | 1 - clang/test/CodeGen/allow-ubsan-check-inline.c | 5 + clang/test/CodeGen/allow-ubsan-check.c | 145 +++++++++++------- .../Instrumentation/LowerAllowCheckPass.h | 4 +- llvm/lib/Passes/PassBuilder.cpp | 31 +++- .../Instrumentation/BoundsChecking.cpp | 11 +- .../Instrumentation/LowerAllowCheckPass.cpp | 53 +++++-- .../Transforms/lower-builtin-allow-check.ll | 8 + 10 files changed, 221 insertions(+), 94 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index f60f8672e6a0b8..d6d8d83638ef20 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -794,12 +794,37 @@ static void addSanitizers(const Triple &TargetTriple, PB.registerOptimizerLastEPCallback(SanitizersCallback); } - if (LowerAllowCheckPass::IsRequested()) { + bool lowerAllowCheck = LowerAllowCheckPass::IsRequested(); + // Is there a non-zero cutoff? + static const double SanitizerMaskCutoffsEps = 0.000000001f; + for (unsigned int i = 0; i < SanitizerKind::SO_Count; ++i) { + std::optional<double> maybeCutoff = CodeGenOpts.SanitizeSkipHotCutoffs[i]; + lowerAllowCheck |= (maybeCutoff.has_value() && + (maybeCutoff.value() > SanitizerMaskCutoffsEps)); + } + + if (lowerAllowCheck) { // We want to call it after inline, which is about OptimizerEarlyEPCallback. PB.registerOptimizerEarlyEPCallback([&](ModulePassManager &MPM, OptimizationLevel Level, ThinOrFullLTOPhase Phase) { LowerAllowCheckPass::Options Opts; + + // SanitizeSkipHotCutoffs stores doubles with range [0, 1] + // Opts.cutoffs wants ints with range [0, 999999] + for (unsigned int i = 0; i < SanitizerKind::SO_Count; ++i) { + std::optional<double> maybeCutoff = + CodeGenOpts.SanitizeSkipHotCutoffs[i]; + if (maybeCutoff.has_value() && + (maybeCutoff.value() > SanitizerMaskCutoffsEps)) { + Opts.cutoffs.push_back( + std::clamp((int)(maybeCutoff.value() * 1000000), 0, 999999)); + } else { + // Default is don't skip the check + Opts.cutoffs.push_back(0); + } + } + MPM.addPass(createModuleToFunctionPassAdaptor(LowerAllowCheckPass(Opts))); }); } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 054f8d1eadb8c5..32f6904b124f77 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3607,29 +3607,35 @@ void CodeGenFunction::EmitCheck( llvm::Value *RecoverableCond = nullptr; llvm::Value *TrapCond = nullptr; bool NoMerge = false; + // Expand checks into: + // (Check1 || !allow_ubsan_check) && (Check2 || !allow_ubsan_check) ... + // We need separate allow_ubsan_check intrinsics because they have separately + // specified cutoffs. + // This expression looks expensive but will be simplified after + // LowerAllowCheckPass. + static const double SanitizerMaskCutoffsEps = 0.000000001f; for (auto &[Check, Ord] : Checked) { + llvm::Value *GuardedCheck = Check; + if (ClSanitizeGuardChecks || + (CGM.getCodeGenOpts().SanitizeSkipHotCutoffs[Ord] > + SanitizerMaskCutoffsEps)) { + llvm::Value *Allow = Builder.CreateCall( + CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check), + llvm::ConstantInt::get(CGM.Int8Ty, Ord)); + GuardedCheck = Builder.CreateOr(Check, Builder.CreateNot(Allow)); + } + // -fsanitize-trap= overrides -fsanitize-recover=. llvm::Value *&Cond = CGM.getCodeGenOpts().SanitizeTrap.has(Ord) ? TrapCond : CGM.getCodeGenOpts().SanitizeRecover.has(Ord) ? RecoverableCond : FatalCond; - Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check; + Cond = Cond ? Builder.CreateAnd(Cond, GuardedCheck) : GuardedCheck; if (!CGM.getCodeGenOpts().SanitizeMergeHandlers.has(Ord)) NoMerge = true; } - if (ClSanitizeGuardChecks) { - llvm::Value *Allow = - Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check), - llvm::ConstantInt::get(CGM.Int8Ty, CheckHandler)); - - for (llvm::Value **Cond : {&FatalCond, &RecoverableCond, &TrapCond}) { - if (*Cond) - *Cond = Builder.CreateOr(*Cond, Builder.CreateNot(Allow)); - } - } - if (TrapCond) EmitTrapCheck(TrapCond, CheckHandler, NoMerge); if (!FatalCond && !RecoverableCond) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 58658dedbaf1ee..461710cfb85eb7 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2314,7 +2314,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.SanitizeSkipHotCutoffs = parseSanitizerWeightedKinds( "-fsanitize-skip-hot-cutoff=", Args.getAllArgValues(OPT_fsanitize_skip_hot_cutoff_EQ), Diags); - Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); if (!LangOpts->CUDAIsDevice) diff --git a/clang/test/CodeGen/allow-ubsan-check-inline.c b/clang/test/CodeGen/allow-ubsan-check-inline.c index 1de24ab90dac0e..eed48cf15ecca4 100644 --- a/clang/test/CodeGen/allow-ubsan-check-inline.c +++ b/clang/test/CodeGen/allow-ubsan-check-inline.c @@ -1,3 +1,8 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -fsanitize-skip-hot-cutoff=signed-integer-overflow=0.000001 -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check -fno-inline 2>&1 | FileCheck %s --check-prefixes=NOINL --implicit-check-not="remark:" +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -fsanitize-skip-hot-cutoff=signed-integer-overflow=0.000001 -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check 2>&1 | FileCheck %s --check-prefixes=INLINE --implicit-check-not="remark:" +// +// -ubsan-guard-checks is deprecated and will be removed in the future; +// use -fsanitize-skip-hot-cutoff, as shown above. // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -mllvm -ubsan-guard-checks -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check -fno-inline 2>&1 | FileCheck %s --check-prefixes=NOINL --implicit-check-not="remark:" // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -mllvm -ubsan-guard-checks -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check 2>&1 | FileCheck %s --check-prefixes=INLINE --implicit-check-not="remark:" diff --git a/clang/test/CodeGen/allow-ubsan-check.c b/clang/test/CodeGen/allow-ubsan-check.c index 38b4848c1edc14..0cd81a77f5cc59 100644 --- a/clang/test/CodeGen/allow-ubsan-check.c +++ b/clang/test/CodeGen/allow-ubsan-check.c @@ -1,4 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// +// We can't use -fsanitize-skip-hot-cutoff because that includes both -ubsan-guard-checks and +//-lower-allow-check-percentile-cutoff. // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -O1 -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null,local-bounds -mllvm -ubsan-guard-checks | FileCheck %s // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -O1 -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null,local-bounds -mllvm -ubsan-guard-checks -fsanitize-trap=signed-integer-overflow,integer-divide-by-zero,null,local-bounds | FileCheck %s --check-prefixes=TR // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -O1 -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null,local-bounds -mllvm -ubsan-guard-checks -fsanitize-recover=signed-integer-overflow,integer-divide-by-zero,null,local-bounds | FileCheck %s --check-prefixes=REC @@ -7,18 +10,26 @@ // CHECK-LABEL: define dso_local noundef i32 @div( // CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = icmp eq i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] -// CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X]], -2147483648, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[Y]], -1, !nosanitize [[META2]] -// CHECK-NEXT: [[OR_NOT5:%.*]] = and i1 [[TMP1]], [[TMP2]] -// CHECK-NEXT: [[DOTNOT3:%.*]] = or i1 [[TMP0]], [[OR_NOT5]] -// CHECK-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 3), !nosanitize [[META2]] -// CHECK-NEXT: [[DOTNOT1:%.*]] = and i1 [[DOTNOT3]], [[TMP3]] -// CHECK-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_DIVREM_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] +// CHECK-NEXT: [[TMP0:%.*]] = icmp ne i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] +// CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X]], -2147483648, !nosanitize [[META2]] +// CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[Y]], -1, !nosanitize [[META2]] +// CHECK-NEXT: [[OR:%.*]] = or i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]] +// +// 27 == SO_IntegerDivideByZero +// CHECK-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 27), !nosanitize [[META2]] +// CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true, !nosanitize [[META2]] +// CHECK-NEXT: [[TMP5:%.*]] = or i1 [[TMP0]], [[TMP4]], !nosanitize [[META2]] +// +// 41 == SO_SignedIntegerOverflow +// CHECK-NEXT: [[TMP6:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] +// CHECK-NEXT: [[TMP7:%.*]] = xor i1 [[TMP6]], true, !nosanitize [[META2]] +// CHECK-NEXT: [[TMP8:%.*]] = or i1 [[OR]], [[TMP7]], !nosanitize [[META2]] +// CHECK-NEXT: [[TMP9:%.*]] = and i1 [[TMP5]], [[TMP8]], !nosanitize [[META2]] +// CHECK-NEXT: br i1 [[TMP9]], label %[[CONT:.*]], label %[[HANDLER_DIVREM_OVERFLOW:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] // CHECK: [[HANDLER_DIVREM_OVERFLOW]]: -// CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP5:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] -// CHECK-NEXT: tail call void @__ubsan_handle_divrem_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP4]], i64 [[TMP5]]) #[[ATTR6:[0-9]+]], !nosanitize [[META2]] +// CHECK-NEXT: [[TMP10:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] +// CHECK-NEXT: [[TMP11:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] +// CHECK-NEXT: tail call void @__ubsan_handle_divrem_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR6:[0-9]+]], !nosanitize [[META2]] // CHECK-NEXT: unreachable, !nosanitize [[META2]] // CHECK: [[CONT]]: // CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X]], [[Y]] @@ -27,14 +38,18 @@ // TR-LABEL: define dso_local noundef i32 @div( // TR-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // TR-NEXT: [[ENTRY:.*:]] -// TR-NEXT: [[TMP0:%.*]] = icmp eq i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] -// TR-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X]], -2147483648, !nosanitize [[META2]] -// TR-NEXT: [[TMP2:%.*]] = icmp eq i32 [[Y]], -1, !nosanitize [[META2]] -// TR-NEXT: [[OR_NOT5:%.*]] = and i1 [[TMP1]], [[TMP2]] -// TR-NEXT: [[DOTNOT3:%.*]] = or i1 [[TMP0]], [[OR_NOT5]] -// TR-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 3), !nosanitize [[META2]] -// TR-NEXT: [[DOTNOT1:%.*]] = and i1 [[DOTNOT3]], [[TMP3]] -// TR-NEXT: br i1 [[DOTNOT1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] +// TR-NEXT: [[TMP0:%.*]] = icmp ne i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] +// TR-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X]], -2147483648, !nosanitize [[META2]] +// TR-NEXT: [[TMP2:%.*]] = icmp ne i32 [[Y]], -1, !nosanitize [[META2]] +// TR-NEXT: [[OR:%.*]] = or i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]] +// TR-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 27), !nosanitize [[META2]] +// TR-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true, !nosanitize [[META2]] +// TR-NEXT: [[TMP5:%.*]] = or i1 [[TMP0]], [[TMP4]], !nosanitize [[META2]] +// TR-NEXT: [[TMP6:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] +// TR-NEXT: [[TMP7:%.*]] = xor i1 [[TMP6]], true, !nosanitize [[META2]] +// TR-NEXT: [[TMP8:%.*]] = or i1 [[OR]], [[TMP7]], !nosanitize [[META2]] +// TR-NEXT: [[TMP9:%.*]] = and i1 [[TMP5]], [[TMP8]], !nosanitize [[META2]] +// TR-NEXT: br i1 [[TMP9]], label %[[CONT:.*]], label %[[TRAP:.*]], !nosanitize [[META2]] // TR: [[TRAP]]: // TR-NEXT: tail call void @llvm.ubsantrap(i8 3) #[[ATTR5:[0-9]+]], !nosanitize [[META2]] // TR-NEXT: unreachable, !nosanitize [[META2]] @@ -45,18 +60,22 @@ // REC-LABEL: define dso_local noundef i32 @div( // REC-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // REC-NEXT: [[ENTRY:.*:]] -// REC-NEXT: [[TMP0:%.*]] = icmp eq i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] -// REC-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X]], -2147483648, !nosanitize [[META2]] -// REC-NEXT: [[TMP2:%.*]] = icmp eq i32 [[Y]], -1, !nosanitize [[META2]] -// REC-NEXT: [[OR_NOT5:%.*]] = and i1 [[TMP1]], [[TMP2]] -// REC-NEXT: [[DOTNOT3:%.*]] = or i1 [[TMP0]], [[OR_NOT5]] -// REC-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 3), !nosanitize [[META2]] -// REC-NEXT: [[DOTNOT1:%.*]] = and i1 [[DOTNOT3]], [[TMP3]] -// REC-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_DIVREM_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] +// REC-NEXT: [[TMP0:%.*]] = icmp ne i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] +// REC-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X]], -2147483648, !nosanitize [[META2]] +// REC-NEXT: [[TMP2:%.*]] = icmp ne i32 [[Y]], -1, !nosanitize [[META2]] +// REC-NEXT: [[OR:%.*]] = or i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]] +// REC-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 27), !nosanitize [[META2]] +// REC-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true, !nosanitize [[META2]] +// REC-NEXT: [[TMP5:%.*]] = or i1 [[TMP0]], [[TMP4]], !nosanitize [[META2]] +// REC-NEXT: [[TMP6:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] +// REC-NEXT: [[TMP7:%.*]] = xor i1 [[TMP6]], true, !nosanitize [[META2]] +// REC-NEXT: [[TMP8:%.*]] = or i1 [[OR]], [[TMP7]], !nosanitize [[META2]] +// REC-NEXT: [[TMP9:%.*]] = and i1 [[TMP5]], [[TMP8]], !nosanitize [[META2]] +// REC-NEXT: br i1 [[TMP9]], label %[[CONT:.*]], label %[[HANDLER_DIVREM_OVERFLOW:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] // REC: [[HANDLER_DIVREM_OVERFLOW]]: -// REC-NEXT: [[TMP4:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] -// REC-NEXT: [[TMP5:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] -// REC-NEXT: tail call void @__ubsan_handle_divrem_overflow(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP4]], i64 [[TMP5]]) #[[ATTR6:[0-9]+]], !nosanitize [[META2]] +// REC-NEXT: [[TMP10:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] +// REC-NEXT: [[TMP11:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] +// REC-NEXT: tail call void @__ubsan_handle_divrem_overflow(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR6:[0-9]+]], !nosanitize [[META2]] // REC-NEXT: br label %[[CONT]], !nosanitize [[META2]] // REC: [[CONT]]: // REC-NEXT: [[DIV:%.*]] = sdiv i32 [[X]], [[Y]] @@ -70,21 +89,23 @@ int div(int x, int y) { // CHECK-SAME: ptr noundef readonly [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 22), !nosanitize [[META2]] +// +// 29 == SO_Null +// CHECK-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 29), !nosanitize [[META2]] // CHECK-NEXT: [[DOTNOT1:%.*]] = and i1 [[TMP0]], [[TMP1]] -// CHECK-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_TYPE_MISMATCH:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// CHECK-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_TYPE_MISMATCH:.*]], label %[[CONT:.*]], !prof [[PROF4:![0-9]+]], !nosanitize [[META2]] // CHECK: [[HANDLER_TYPE_MISMATCH]]: // CHECK-NEXT: tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 0) #[[ATTR6]], !nosanitize [[META2]] // CHECK-NEXT: unreachable, !nosanitize [[META2]] // CHECK: [[CONT]]: -// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4, !tbaa [[TBAA4:![0-9]+]] +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4, !tbaa [[TBAA5:![0-9]+]] // CHECK-NEXT: ret i32 [[TMP2]] // // TR-LABEL: define dso_local i32 @null( // TR-SAME: ptr noundef readonly [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // TR-NEXT: [[ENTRY:.*:]] // TR-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]] -// TR-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 22), !nosanitize [[META2]] +// TR-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 29), !nosanitize [[META2]] // TR-NEXT: [[DOTNOT1:%.*]] = and i1 [[TMP0]], [[TMP1]] // TR-NEXT: br i1 [[DOTNOT1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] // TR: [[TRAP]]: @@ -98,14 +119,14 @@ int div(int x, int y) { // REC-SAME: ptr noundef readonly [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // REC-NEXT: [[ENTRY:.*:]] // REC-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]] -// REC-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 22), !nosanitize [[META2]] +// REC-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 29), !nosanitize [[META2]] // REC-NEXT: [[DOTNOT1:%.*]] = and i1 [[TMP0]], [[TMP1]] -// REC-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_TYPE_MISMATCH:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// REC-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_TYPE_MISMATCH:.*]], label %[[CONT:.*]], !prof [[PROF4:![0-9]+]], !nosanitize [[META2]] // REC: [[HANDLER_TYPE_MISMATCH]]: // REC-NEXT: tail call void @__ubsan_handle_type_mismatch_v1(ptr nonnull @[[GLOB2:[0-9]+]], i64 0) #[[ATTR6]], !nosanitize [[META2]] // REC-NEXT: br label %[[CONT]], !nosanitize [[META2]] // REC: [[CONT]]: -// REC-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4, !tbaa [[TBAA4:![0-9]+]] +// REC-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4, !tbaa [[TBAA5:![0-9]+]] // REC-NEXT: ret i32 [[TMP2]] // int null(int* x) { @@ -117,9 +138,11 @@ int null(int* x) { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 [[Y]]), !nosanitize [[META2]] // CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 0), !nosanitize [[META2]] +// +// 41 == SO_SignedIntegerOverflow +// CHECK-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] // CHECK-NEXT: [[DOTDEMORGAN:%.*]] = and i1 [[TMP1]], [[TMP2]] -// CHECK-NEXT: br i1 [[DOTDEMORGAN]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// CHECK-NEXT: br i1 [[DOTDEMORGAN]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF4]], !nosanitize [[META2]] // CHECK: [[HANDLER_ADD_OVERFLOW]]: // CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] // CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] @@ -134,7 +157,7 @@ int null(int* x) { // TR-NEXT: [[ENTRY:.*:]] // TR-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 [[Y]]), !nosanitize [[META2]] // TR-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] -// TR-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 0), !nosanitize [[META2]] +// TR-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] // TR-NEXT: [[DOTDEMORGAN:%.*]] = and i1 [[TMP1]], [[TMP2]] // TR-NEXT: br i1 [[DOTDEMORGAN]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] // TR: [[TRAP]]: @@ -149,9 +172,9 @@ int null(int* x) { // REC-NEXT: [[ENTRY:.*:]] // REC-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 [[Y]]), !nosanitize [[META2]] // REC-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] -// REC-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 0), !nosanitize [[META2]] +// REC-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] // REC-NEXT: [[DOTDEMORGAN:%.*]] = and i1 [[TMP1]], [[TMP2]] -// REC-NEXT: br i1 [[DOTDEMORGAN]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] +// REC-NEXT: br i1 [[DOTDEMORGAN]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF4]], !nosanitize [[META2]] // REC: [[HANDLER_ADD_OVERFLOW]]: // REC-NEXT: [[TMP3:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] // REC-NEXT: [[TMP4:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] @@ -175,12 +198,14 @@ void use(double*); // CHECK-NEXT: call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR7:[0-9]+]] // CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 // CHECK-NEXT: [[TMP1:%.*]] = icmp ule i64 [[TMP0]], [[IDXPROM]] +// +// 71 == SO_LocalBounds // CHECK-NEXT: [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 71), !nosanitize [[META2]] // CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP:.*]], label %[[BB4:.*]] // CHECK: [[BB4]]: // CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds double, ptr [[VLA]], i64 [[IDXPROM]] -// CHECK-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]] +// CHECK-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA9:![0-9]+]] // CHECK-NEXT: ret double [[TMP5]] // CHECK: [[TRAP]]: // CHECK-NEXT: call void @__ubsan_handle_local_out_of_bounds_abort() #[[ATTR6]], !nosanitize [[META2]] @@ -202,7 +227,7 @@ void use(double*); // TR-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA7:![0-9]+]] // TR-NEXT: ret double [[TMP5]] // TR: [[TRAP]]: -// TR-NEXT: call void @llvm.ubsantrap(i8 3) #[[ATTR5]], !nosanitize [[META2]] +// TR-NEXT: call void @llvm.ubsantrap(i8 71) #[[ATTR5]], !nosanitize [[META2]] // TR-NEXT: unreachable, !nosanitize [[META2]] // // REC-LABEL: define dso_local double @lbounds( @@ -218,7 +243,7 @@ void use(double*); // REC-NEXT: br i1 [[TMP3]], label %[[TRAP:.*]], label %[[BB4:.*]] // REC: [[BB4]]: // REC-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds double, ptr [[VLA]], i64 [[IDXPROM]] -// REC-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]] +// REC-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA9:![0-9]+]] // REC-NEXT: ret double [[TMP5]] // REC: [[TRAP]]: // REC-NEXT: call void @__ubsan_handle_local_out_of_bounds() #[[ATTR6]], !nosanitize [[META2]] @@ -232,13 +257,14 @@ double lbounds(int b, int i) { //. // CHECK: [[META2]] = !{} -// CHECK: [[PROF3]] = !{!"branch_weights", i32 1, i32 1048575} -// CHECK: [[TBAA4]] = !{[[META5:![0-9]+]], [[META5]], i64 0} -// CHECK: [[META5]] = !{!"int", [[META6:![0-9]+]], i64 0} -// CHECK: [[META6]] = !{!"omnipotent char", [[META7:![0-9]+]], i64 0} -// CHECK: [[META7]] = !{!"Simple C/C++ TBAA"} -// CHECK: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0} -// CHECK: [[META9]] = !{!"double", [[META6]], i64 0} +// CHECK: [[PROF3]] = !{!"branch_weights", i32 1048575, i32 1} +// CHECK: [[PROF4]] = !{!"branch_weights", i32 1, i32 1048575} +// CHECK: [[TBAA5]] = !{[[META6:![0-9]+]], [[META6]], i64 0} +// CHECK: [[META6]] = !{!"int", [[META7:![0-9]+]], i64 0} +// CHECK: [[META7]] = !{!"omnipotent char", [[META8:![0-9]+]], i64 0} +// CHECK: [[META8]] = !{!"Simple C/C++ TBAA"} +// CHECK: [[TBAA9]] = !{[[META10:![0-9]+]], [[META10]], i64 0} +// CHECK: [[META10]] = !{!"double", [[META7]], i64 0} //. // TR: [[META2]] = !{} // TR: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0} @@ -249,11 +275,12 @@ double lbounds(int b, int i) { // TR: [[META8]] = !{!"double", [[META5]], i64 0} //. // REC: [[META2]] = !{} -// REC: [[PROF3]] = !{!"branch_weights", i32 1, i32 1048575} -// REC: [[TBAA4]] = !{[[META5:![0-9]+]], [[META5]], i64 0} -// REC: [[META5]] = !{!"int", [[META6:![0-9]+]], i64 0} -// REC: [[META6]] = !{!"omnipotent char", [[META7:![0-9]+]], i64 0} -// REC: [[META7]] = !{!"Simple C/C++ TBAA"} -// REC: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0} -// REC: [[META9]] = !{!"double", [[META6]], i64 0} +// REC: [[PROF3]] = !{!"branch_weights", i32 1048575, i32 1} +// REC: [[PROF4]] = !{!"branch_weights", i32 1, i32 1048575} +// REC: [[TBAA5]] = !{[[META6:![0-9]+]], [[META6]], i64 0} +// REC: [[META6]] = !{!"int", [[META7:![0-9]+]], i64 0} +// REC: [[META7]] = !{!"omnipotent char", [[META8:![0-9]+]], i64 0} +// REC: [[META8]] = !{!"Simple C/C++ TBAA"} +// REC: [[TBAA9]] = !{[[META10:![0-9]+]], [[META10]], i64 0} +// REC: [[META10]] = !{!"double", [[META7]], i64 0} //. diff --git a/llvm/include/llvm/Transforms/Instrumentation/LowerAllowCheckPass.h b/llvm/include/llvm/Transforms/Instrumentation/LowerAllowCheckPass.h index 3ee907606e12b8..2c6e60138f2aab 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/LowerAllowCheckPass.h +++ b/llvm/include/llvm/Transforms/Instrumentation/LowerAllowCheckPass.h @@ -25,7 +25,7 @@ namespace llvm { class LowerAllowCheckPass : public PassInfoMixin<LowerAllowCheckPass> { public: struct Options { - std::vector<unsigned int> placeholder; // TODO: cutoffs + std::vector<unsigned int> cutoffs; }; explicit LowerAllowCheckPass(LowerAllowCheckPass::Options Opts) @@ -33,6 +33,8 @@ class LowerAllowCheckPass : public PassInfoMixin<LowerAllowCheckPass> { PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); static bool IsRequested(); + void printPipeline(raw_ostream &OS, + function_ref<StringRef(StringRef)> MapClassName2PassName); private: LowerAllowCheckPass::Options Opts; diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 1e97cef22045d4..e3828d2be96042 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -828,11 +828,34 @@ parseLowerAllowCheckPassOptions(StringRef Params) { StringRef ParamName; std::tie(ParamName, Params) = Params.split(';'); - return make_error<StringError>( - formatv("invalid LowerAllowCheck pass parameter '{0}' ", ParamName) - .str(), - inconvertibleErrorCode()); + // cutoffs=990000|990000|0|...100000 + if (ParamName.starts_with("cutoffs=")) { + StringRef CutoffsStr; + std::tie(ParamName, CutoffsStr) = ParamName.split('='); + + while (CutoffsStr != "") { + StringRef firstCutoffStr; + std::tie(firstCutoffStr, CutoffsStr) = CutoffsStr.split('|'); + + int cutoff; + if (firstCutoffStr.getAsInteger(0, cutoff)) + return make_error<StringError>( + formatv("invalid LowerAllowCheck pass cutoffs parameter '{0}' " + "({1}) {2}", + firstCutoffStr, Params, Result.cutoffs.size()) + .str(), + inconvertibleErrorCode()); + + Result.cutoffs.push_back(cutoff); + } + } else { + return make_error<StringError>( + formatv("invalid LowerAllowCheck pass parameter '{0}' ", ParamName) + .str(), + inconvertibleErrorCode()); + } } + return Result; } diff --git a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp index 609678f9979c63..14c331b3b748e0 100644 --- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp +++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -108,14 +108,17 @@ static Value *getBoundsCheckCond(Value *Ptr, Value *InstVal, return Or; } -static CallInst *InsertTrap(BuilderTy &IRB, bool DebugTrapBB) { +static CallInst *InsertTrap(BuilderTy &IRB, bool DebugTrapBB, + std::optional<int8_t> GuardKind) { if (!DebugTrapBB) return IRB.CreateIntrinsic(Intrinsic::trap, {}, {}); - // FIXME: Ideally we would use the SanitizerHandler::OutOfBounds constant. + return IRB.CreateIntrinsic( Intrinsic::ubsantrap, {}, ConstantInt::get(IRB.getInt8Ty(), - IRB.GetInsertBlock()->getParent()->size())); + GuardKind.has_value() + ? GuardKind.value() + : IRB.GetInsertBlock()->getParent()->size())); } static CallInst *InsertCall(BuilderTy &IRB, bool MayReturn, StringRef Name) { @@ -250,7 +253,7 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI, bool DebugTrapBB = !Opts.Merge; CallInst *TrapCall = Opts.Rt ? InsertCall(IRB, Opts.Rt->MayReturn, Name) - : InsertTrap(IRB, DebugTrapBB); + : InsertTrap(IRB, DebugTrapBB, Opts.GuardKind); if (DebugTrapBB) TrapCall->addFnAttr(llvm::Attribute::NoMerge); diff --git a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp index f27798cfd228c3..fbf413251424aa 100644 --- a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp +++ b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/RandomNumberGenerator.h" #include <memory> #include <random> @@ -71,7 +72,8 @@ static void emitRemark(IntrinsicInst *II, OptimizationRemarkEmitter &ORE, static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI, const ProfileSummaryInfo *PSI, - OptimizationRemarkEmitter &ORE) { + OptimizationRemarkEmitter &ORE, + std::vector<unsigned int> &cutoffs) { SmallVector<std::pair<IntrinsicInst *, bool>, 16> ReplaceWithValue; std::unique_ptr<RandomNumberGenerator> Rng; @@ -81,10 +83,9 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI, return *Rng; }; - auto ShouldRemoveHot = [&](const BasicBlock &BB) { - return HotPercentileCutoff.getNumOccurrences() && PSI && - PSI->isHotCountNthPercentile( - HotPercentileCutoff, BFI.getBlockProfileCount(&BB).value_or(0)); + auto ShouldRemoveHot = [&](const BasicBlock &BB, const unsigned int &cutoff) { + return PSI && PSI->isHotCountNthPercentile( + cutoff, BFI.getBlockProfileCount(&BB).value_or(0)); }; auto ShouldRemoveRandom = [&]() { @@ -92,10 +93,10 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI, !std::bernoulli_distribution(RandomRate)(GetRng()); }; - auto ShouldRemove = [&](const BasicBlock &BB) { - return ShouldRemoveRandom() || ShouldRemoveHot(BB); - }; - + // In some cases, EmitCheck was called with multiple checks (e.g., + // SanitizerKind::{Null,ObjectSize,Alignment}, which fall under the umbrella + // of SanitizerHandler::TypeMismatch). We use the threshold for each + // corresponding SanitizerKind. for (BasicBlock &BB : F) { for (Instruction &I : BB) { IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I); @@ -107,7 +108,18 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI, case Intrinsic::allow_runtime_check: { ++NumChecksTotal; - bool ToRemove = ShouldRemove(BB); + bool ToRemove = ShouldRemoveRandom(); + + unsigned int cutoff = 0; + if (ID == Intrinsic::allow_ubsan_check) { + auto *Kind = cast<ConstantInt>(II->getArgOperand(0)); + if (Kind->getZExtValue() < cutoffs.size()) + cutoff = cutoffs[Kind->getZExtValue()]; + } + if (HotPercentileCutoff.getNumOccurrences()) + cutoff = HotPercentileCutoff; + ToRemove |= ShouldRemoveHot(BB, cutoff); + ReplaceWithValue.push_back({ II, ToRemove, @@ -142,11 +154,28 @@ PreservedAnalyses LowerAllowCheckPass::run(Function &F, OptimizationRemarkEmitter &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F); - return removeUbsanTraps(F, BFI, PSI, ORE) ? PreservedAnalyses::none() - : PreservedAnalyses::all(); + return removeUbsanTraps(F, BFI, PSI, ORE, Opts.cutoffs) + ? PreservedAnalyses::none() + : PreservedAnalyses::all(); } bool LowerAllowCheckPass::IsRequested() { return RandomRate.getNumOccurrences() || HotPercentileCutoff.getNumOccurrences(); } + +void LowerAllowCheckPass::printPipeline( + raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) { + static_cast<PassInfoMixin<LowerAllowCheckPass> *>(this)->printPipeline( + OS, MapClassName2PassName); + OS << "<cutoffs="; + + bool first = true; + for (unsigned int cutoff : Opts.cutoffs) { + if (!first) + OS << "|"; + OS << cutoff; + first = false; + } + OS << '>'; +} diff --git a/llvm/test/Transforms/lower-builtin-allow-check.ll b/llvm/test/Transforms/lower-builtin-allow-check.ll index bcd9722d2b289d..57fc845dbcda7c 100644 --- a/llvm/test/Transforms/lower-builtin-allow-check.ll +++ b/llvm/test/Transforms/lower-builtin-allow-check.ll @@ -2,6 +2,14 @@ ; RUN: opt < %s -passes='function(lower-allow-check)' -S | FileCheck %s --check-prefixes=NOPROFILE ; RUN: opt < %s -passes='function(lower-allow-check)' -lower-allow-check-random-rate=0 -S | FileCheck %s --check-prefixes=NONE ; RUN: opt < %s -passes='function(lower-allow-check)' -lower-allow-check-random-rate=1 -S | FileCheck %s --check-prefixes=ALL +; +; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs=990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000>)' -S | FileCheck %s --check-prefixes=HOT99 +; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs=700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000>)' -S | FileCheck %s --check-prefixes=HOT70 +; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs=990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000>)' -lower-allow-check-random-rate=0 -S | FileCheck %s --check-prefixes=NONE99 +; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs=700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000>)' -lower-allow-check-random-rate=1 -S | FileCheck %s --check-prefixes=ALL70 +; +; -lower-allow-check-percentile-cutoff is deprecated and will be removed in the future; +; use the cutoffs parameter to the lower-allow-check pass, as shown above. ; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check)' -lower-allow-check-percentile-cutoff-hot=990000 -S | FileCheck %s --check-prefixes=HOT99 ; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check)' -lower-allow-check-percentile-cutoff-hot=700000 -S | FileCheck %s --check-prefixes=HOT70 ; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check)' -lower-allow-check-random-rate=0 -lower-allow-check-percentile-cutoff-hot=990000 -S | FileCheck %s --check-prefixes=NONE99 >From fca3e2b0d62ca5de10c1fc064cc810b75472385d Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Mon, 27 Jan 2025 22:28:56 +0000 Subject: [PATCH 2/7] Remove clang-related changes (for future patch TBA) --- clang/lib/CodeGen/BackendUtil.cpp | 27 +--- clang/lib/CodeGen/CGExpr.cpp | 30 ++-- clang/test/CodeGen/allow-ubsan-check-inline.c | 5 - clang/test/CodeGen/allow-ubsan-check.c | 145 +++++++----------- 4 files changed, 72 insertions(+), 135 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index d6d8d83638ef20..f60f8672e6a0b8 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -794,37 +794,12 @@ static void addSanitizers(const Triple &TargetTriple, PB.registerOptimizerLastEPCallback(SanitizersCallback); } - bool lowerAllowCheck = LowerAllowCheckPass::IsRequested(); - // Is there a non-zero cutoff? - static const double SanitizerMaskCutoffsEps = 0.000000001f; - for (unsigned int i = 0; i < SanitizerKind::SO_Count; ++i) { - std::optional<double> maybeCutoff = CodeGenOpts.SanitizeSkipHotCutoffs[i]; - lowerAllowCheck |= (maybeCutoff.has_value() && - (maybeCutoff.value() > SanitizerMaskCutoffsEps)); - } - - if (lowerAllowCheck) { + if (LowerAllowCheckPass::IsRequested()) { // We want to call it after inline, which is about OptimizerEarlyEPCallback. PB.registerOptimizerEarlyEPCallback([&](ModulePassManager &MPM, OptimizationLevel Level, ThinOrFullLTOPhase Phase) { LowerAllowCheckPass::Options Opts; - - // SanitizeSkipHotCutoffs stores doubles with range [0, 1] - // Opts.cutoffs wants ints with range [0, 999999] - for (unsigned int i = 0; i < SanitizerKind::SO_Count; ++i) { - std::optional<double> maybeCutoff = - CodeGenOpts.SanitizeSkipHotCutoffs[i]; - if (maybeCutoff.has_value() && - (maybeCutoff.value() > SanitizerMaskCutoffsEps)) { - Opts.cutoffs.push_back( - std::clamp((int)(maybeCutoff.value() * 1000000), 0, 999999)); - } else { - // Default is don't skip the check - Opts.cutoffs.push_back(0); - } - } - MPM.addPass(createModuleToFunctionPassAdaptor(LowerAllowCheckPass(Opts))); }); } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 32f6904b124f77..054f8d1eadb8c5 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3607,35 +3607,29 @@ void CodeGenFunction::EmitCheck( llvm::Value *RecoverableCond = nullptr; llvm::Value *TrapCond = nullptr; bool NoMerge = false; - // Expand checks into: - // (Check1 || !allow_ubsan_check) && (Check2 || !allow_ubsan_check) ... - // We need separate allow_ubsan_check intrinsics because they have separately - // specified cutoffs. - // This expression looks expensive but will be simplified after - // LowerAllowCheckPass. - static const double SanitizerMaskCutoffsEps = 0.000000001f; for (auto &[Check, Ord] : Checked) { - llvm::Value *GuardedCheck = Check; - if (ClSanitizeGuardChecks || - (CGM.getCodeGenOpts().SanitizeSkipHotCutoffs[Ord] > - SanitizerMaskCutoffsEps)) { - llvm::Value *Allow = Builder.CreateCall( - CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check), - llvm::ConstantInt::get(CGM.Int8Ty, Ord)); - GuardedCheck = Builder.CreateOr(Check, Builder.CreateNot(Allow)); - } - // -fsanitize-trap= overrides -fsanitize-recover=. llvm::Value *&Cond = CGM.getCodeGenOpts().SanitizeTrap.has(Ord) ? TrapCond : CGM.getCodeGenOpts().SanitizeRecover.has(Ord) ? RecoverableCond : FatalCond; - Cond = Cond ? Builder.CreateAnd(Cond, GuardedCheck) : GuardedCheck; + Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check; if (!CGM.getCodeGenOpts().SanitizeMergeHandlers.has(Ord)) NoMerge = true; } + if (ClSanitizeGuardChecks) { + llvm::Value *Allow = + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check), + llvm::ConstantInt::get(CGM.Int8Ty, CheckHandler)); + + for (llvm::Value **Cond : {&FatalCond, &RecoverableCond, &TrapCond}) { + if (*Cond) + *Cond = Builder.CreateOr(*Cond, Builder.CreateNot(Allow)); + } + } + if (TrapCond) EmitTrapCheck(TrapCond, CheckHandler, NoMerge); if (!FatalCond && !RecoverableCond) diff --git a/clang/test/CodeGen/allow-ubsan-check-inline.c b/clang/test/CodeGen/allow-ubsan-check-inline.c index eed48cf15ecca4..1de24ab90dac0e 100644 --- a/clang/test/CodeGen/allow-ubsan-check-inline.c +++ b/clang/test/CodeGen/allow-ubsan-check-inline.c @@ -1,8 +1,3 @@ -// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -fsanitize-skip-hot-cutoff=signed-integer-overflow=0.000001 -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check -fno-inline 2>&1 | FileCheck %s --check-prefixes=NOINL --implicit-check-not="remark:" -// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -fsanitize-skip-hot-cutoff=signed-integer-overflow=0.000001 -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check 2>&1 | FileCheck %s --check-prefixes=INLINE --implicit-check-not="remark:" -// -// -ubsan-guard-checks is deprecated and will be removed in the future; -// use -fsanitize-skip-hot-cutoff, as shown above. // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -mllvm -ubsan-guard-checks -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check -fno-inline 2>&1 | FileCheck %s --check-prefixes=NOINL --implicit-check-not="remark:" // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s -fsanitize=signed-integer-overflow -mllvm -ubsan-guard-checks -O3 -mllvm -lower-allow-check-random-rate=1 -Rpass=lower-allow-check -Rpass-missed=lower-allow-check 2>&1 | FileCheck %s --check-prefixes=INLINE --implicit-check-not="remark:" diff --git a/clang/test/CodeGen/allow-ubsan-check.c b/clang/test/CodeGen/allow-ubsan-check.c index 0cd81a77f5cc59..38b4848c1edc14 100644 --- a/clang/test/CodeGen/allow-ubsan-check.c +++ b/clang/test/CodeGen/allow-ubsan-check.c @@ -1,7 +1,4 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 -// -// We can't use -fsanitize-skip-hot-cutoff because that includes both -ubsan-guard-checks and -//-lower-allow-check-percentile-cutoff. // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -O1 -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null,local-bounds -mllvm -ubsan-guard-checks | FileCheck %s // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -O1 -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null,local-bounds -mllvm -ubsan-guard-checks -fsanitize-trap=signed-integer-overflow,integer-divide-by-zero,null,local-bounds | FileCheck %s --check-prefixes=TR // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -O1 -o - %s -fsanitize=signed-integer-overflow,integer-divide-by-zero,null,local-bounds -mllvm -ubsan-guard-checks -fsanitize-recover=signed-integer-overflow,integer-divide-by-zero,null,local-bounds | FileCheck %s --check-prefixes=REC @@ -10,26 +7,18 @@ // CHECK-LABEL: define dso_local noundef i32 @div( // CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = icmp ne i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] -// CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X]], -2147483648, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[Y]], -1, !nosanitize [[META2]] -// CHECK-NEXT: [[OR:%.*]] = or i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]] -// -// 27 == SO_IntegerDivideByZero -// CHECK-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 27), !nosanitize [[META2]] -// CHECK-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP5:%.*]] = or i1 [[TMP0]], [[TMP4]], !nosanitize [[META2]] -// -// 41 == SO_SignedIntegerOverflow -// CHECK-NEXT: [[TMP6:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] -// CHECK-NEXT: [[TMP7:%.*]] = xor i1 [[TMP6]], true, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP8:%.*]] = or i1 [[OR]], [[TMP7]], !nosanitize [[META2]] -// CHECK-NEXT: [[TMP9:%.*]] = and i1 [[TMP5]], [[TMP8]], !nosanitize [[META2]] -// CHECK-NEXT: br i1 [[TMP9]], label %[[CONT:.*]], label %[[HANDLER_DIVREM_OVERFLOW:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] +// CHECK-NEXT: [[TMP0:%.*]] = icmp eq i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] +// CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X]], -2147483648, !nosanitize [[META2]] +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[Y]], -1, !nosanitize [[META2]] +// CHECK-NEXT: [[OR_NOT5:%.*]] = and i1 [[TMP1]], [[TMP2]] +// CHECK-NEXT: [[DOTNOT3:%.*]] = or i1 [[TMP0]], [[OR_NOT5]] +// CHECK-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 3), !nosanitize [[META2]] +// CHECK-NEXT: [[DOTNOT1:%.*]] = and i1 [[DOTNOT3]], [[TMP3]] +// CHECK-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_DIVREM_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] // CHECK: [[HANDLER_DIVREM_OVERFLOW]]: -// CHECK-NEXT: [[TMP10:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] -// CHECK-NEXT: [[TMP11:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] -// CHECK-NEXT: tail call void @__ubsan_handle_divrem_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR6:[0-9]+]], !nosanitize [[META2]] +// CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] +// CHECK-NEXT: [[TMP5:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] +// CHECK-NEXT: tail call void @__ubsan_handle_divrem_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP4]], i64 [[TMP5]]) #[[ATTR6:[0-9]+]], !nosanitize [[META2]] // CHECK-NEXT: unreachable, !nosanitize [[META2]] // CHECK: [[CONT]]: // CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X]], [[Y]] @@ -38,18 +27,14 @@ // TR-LABEL: define dso_local noundef i32 @div( // TR-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // TR-NEXT: [[ENTRY:.*:]] -// TR-NEXT: [[TMP0:%.*]] = icmp ne i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] -// TR-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X]], -2147483648, !nosanitize [[META2]] -// TR-NEXT: [[TMP2:%.*]] = icmp ne i32 [[Y]], -1, !nosanitize [[META2]] -// TR-NEXT: [[OR:%.*]] = or i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]] -// TR-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 27), !nosanitize [[META2]] -// TR-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true, !nosanitize [[META2]] -// TR-NEXT: [[TMP5:%.*]] = or i1 [[TMP0]], [[TMP4]], !nosanitize [[META2]] -// TR-NEXT: [[TMP6:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] -// TR-NEXT: [[TMP7:%.*]] = xor i1 [[TMP6]], true, !nosanitize [[META2]] -// TR-NEXT: [[TMP8:%.*]] = or i1 [[OR]], [[TMP7]], !nosanitize [[META2]] -// TR-NEXT: [[TMP9:%.*]] = and i1 [[TMP5]], [[TMP8]], !nosanitize [[META2]] -// TR-NEXT: br i1 [[TMP9]], label %[[CONT:.*]], label %[[TRAP:.*]], !nosanitize [[META2]] +// TR-NEXT: [[TMP0:%.*]] = icmp eq i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] +// TR-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X]], -2147483648, !nosanitize [[META2]] +// TR-NEXT: [[TMP2:%.*]] = icmp eq i32 [[Y]], -1, !nosanitize [[META2]] +// TR-NEXT: [[OR_NOT5:%.*]] = and i1 [[TMP1]], [[TMP2]] +// TR-NEXT: [[DOTNOT3:%.*]] = or i1 [[TMP0]], [[OR_NOT5]] +// TR-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 3), !nosanitize [[META2]] +// TR-NEXT: [[DOTNOT1:%.*]] = and i1 [[DOTNOT3]], [[TMP3]] +// TR-NEXT: br i1 [[DOTNOT1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] // TR: [[TRAP]]: // TR-NEXT: tail call void @llvm.ubsantrap(i8 3) #[[ATTR5:[0-9]+]], !nosanitize [[META2]] // TR-NEXT: unreachable, !nosanitize [[META2]] @@ -60,22 +45,18 @@ // REC-LABEL: define dso_local noundef i32 @div( // REC-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // REC-NEXT: [[ENTRY:.*:]] -// REC-NEXT: [[TMP0:%.*]] = icmp ne i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] -// REC-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X]], -2147483648, !nosanitize [[META2]] -// REC-NEXT: [[TMP2:%.*]] = icmp ne i32 [[Y]], -1, !nosanitize [[META2]] -// REC-NEXT: [[OR:%.*]] = or i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]] -// REC-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 27), !nosanitize [[META2]] -// REC-NEXT: [[TMP4:%.*]] = xor i1 [[TMP3]], true, !nosanitize [[META2]] -// REC-NEXT: [[TMP5:%.*]] = or i1 [[TMP0]], [[TMP4]], !nosanitize [[META2]] -// REC-NEXT: [[TMP6:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] -// REC-NEXT: [[TMP7:%.*]] = xor i1 [[TMP6]], true, !nosanitize [[META2]] -// REC-NEXT: [[TMP8:%.*]] = or i1 [[OR]], [[TMP7]], !nosanitize [[META2]] -// REC-NEXT: [[TMP9:%.*]] = and i1 [[TMP5]], [[TMP8]], !nosanitize [[META2]] -// REC-NEXT: br i1 [[TMP9]], label %[[CONT:.*]], label %[[HANDLER_DIVREM_OVERFLOW:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] +// REC-NEXT: [[TMP0:%.*]] = icmp eq i32 [[Y]], 0, !nosanitize [[META2:![0-9]+]] +// REC-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X]], -2147483648, !nosanitize [[META2]] +// REC-NEXT: [[TMP2:%.*]] = icmp eq i32 [[Y]], -1, !nosanitize [[META2]] +// REC-NEXT: [[OR_NOT5:%.*]] = and i1 [[TMP1]], [[TMP2]] +// REC-NEXT: [[DOTNOT3:%.*]] = or i1 [[TMP0]], [[OR_NOT5]] +// REC-NEXT: [[TMP3:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 3), !nosanitize [[META2]] +// REC-NEXT: [[DOTNOT1:%.*]] = and i1 [[DOTNOT3]], [[TMP3]] +// REC-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_DIVREM_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3:![0-9]+]], !nosanitize [[META2]] // REC: [[HANDLER_DIVREM_OVERFLOW]]: -// REC-NEXT: [[TMP10:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] -// REC-NEXT: [[TMP11:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] -// REC-NEXT: tail call void @__ubsan_handle_divrem_overflow(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP10]], i64 [[TMP11]]) #[[ATTR6:[0-9]+]], !nosanitize [[META2]] +// REC-NEXT: [[TMP4:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] +// REC-NEXT: [[TMP5:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] +// REC-NEXT: tail call void @__ubsan_handle_divrem_overflow(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP4]], i64 [[TMP5]]) #[[ATTR6:[0-9]+]], !nosanitize [[META2]] // REC-NEXT: br label %[[CONT]], !nosanitize [[META2]] // REC: [[CONT]]: // REC-NEXT: [[DIV:%.*]] = sdiv i32 [[X]], [[Y]] @@ -89,23 +70,21 @@ int div(int x, int y) { // CHECK-SAME: ptr noundef readonly [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]] -// -// 29 == SO_Null -// CHECK-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 29), !nosanitize [[META2]] +// CHECK-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 22), !nosanitize [[META2]] // CHECK-NEXT: [[DOTNOT1:%.*]] = and i1 [[TMP0]], [[TMP1]] -// CHECK-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_TYPE_MISMATCH:.*]], label %[[CONT:.*]], !prof [[PROF4:![0-9]+]], !nosanitize [[META2]] +// CHECK-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_TYPE_MISMATCH:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] // CHECK: [[HANDLER_TYPE_MISMATCH]]: // CHECK-NEXT: tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 0) #[[ATTR6]], !nosanitize [[META2]] // CHECK-NEXT: unreachable, !nosanitize [[META2]] // CHECK: [[CONT]]: -// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4, !tbaa [[TBAA5:![0-9]+]] +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4, !tbaa [[TBAA4:![0-9]+]] // CHECK-NEXT: ret i32 [[TMP2]] // // TR-LABEL: define dso_local i32 @null( // TR-SAME: ptr noundef readonly [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // TR-NEXT: [[ENTRY:.*:]] // TR-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]] -// TR-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 29), !nosanitize [[META2]] +// TR-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 22), !nosanitize [[META2]] // TR-NEXT: [[DOTNOT1:%.*]] = and i1 [[TMP0]], [[TMP1]] // TR-NEXT: br i1 [[DOTNOT1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] // TR: [[TRAP]]: @@ -119,14 +98,14 @@ int div(int x, int y) { // REC-SAME: ptr noundef readonly [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { // REC-NEXT: [[ENTRY:.*:]] // REC-NEXT: [[TMP0:%.*]] = icmp eq ptr [[X]], null, !nosanitize [[META2]] -// REC-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 29), !nosanitize [[META2]] +// REC-NEXT: [[TMP1:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 22), !nosanitize [[META2]] // REC-NEXT: [[DOTNOT1:%.*]] = and i1 [[TMP0]], [[TMP1]] -// REC-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_TYPE_MISMATCH:.*]], label %[[CONT:.*]], !prof [[PROF4:![0-9]+]], !nosanitize [[META2]] +// REC-NEXT: br i1 [[DOTNOT1]], label %[[HANDLER_TYPE_MISMATCH:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] // REC: [[HANDLER_TYPE_MISMATCH]]: // REC-NEXT: tail call void @__ubsan_handle_type_mismatch_v1(ptr nonnull @[[GLOB2:[0-9]+]], i64 0) #[[ATTR6]], !nosanitize [[META2]] // REC-NEXT: br label %[[CONT]], !nosanitize [[META2]] // REC: [[CONT]]: -// REC-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4, !tbaa [[TBAA5:![0-9]+]] +// REC-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4, !tbaa [[TBAA4:![0-9]+]] // REC-NEXT: ret i32 [[TMP2]] // int null(int* x) { @@ -138,11 +117,9 @@ int null(int* x) { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 [[Y]]), !nosanitize [[META2]] // CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] -// -// 41 == SO_SignedIntegerOverflow -// CHECK-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] +// CHECK-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 0), !nosanitize [[META2]] // CHECK-NEXT: [[DOTDEMORGAN:%.*]] = and i1 [[TMP1]], [[TMP2]] -// CHECK-NEXT: br i1 [[DOTDEMORGAN]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF4]], !nosanitize [[META2]] +// CHECK-NEXT: br i1 [[DOTDEMORGAN]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] // CHECK: [[HANDLER_ADD_OVERFLOW]]: // CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] // CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] @@ -157,7 +134,7 @@ int null(int* x) { // TR-NEXT: [[ENTRY:.*:]] // TR-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 [[Y]]), !nosanitize [[META2]] // TR-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] -// TR-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] +// TR-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 0), !nosanitize [[META2]] // TR-NEXT: [[DOTDEMORGAN:%.*]] = and i1 [[TMP1]], [[TMP2]] // TR-NEXT: br i1 [[DOTDEMORGAN]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]] // TR: [[TRAP]]: @@ -172,9 +149,9 @@ int null(int* x) { // REC-NEXT: [[ENTRY:.*:]] // REC-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 [[Y]]), !nosanitize [[META2]] // REC-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]] -// REC-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 41), !nosanitize [[META2]] +// REC-NEXT: [[TMP2:%.*]] = tail call i1 @llvm.allow.ubsan.check(i8 0), !nosanitize [[META2]] // REC-NEXT: [[DOTDEMORGAN:%.*]] = and i1 [[TMP1]], [[TMP2]] -// REC-NEXT: br i1 [[DOTDEMORGAN]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF4]], !nosanitize [[META2]] +// REC-NEXT: br i1 [[DOTDEMORGAN]], label %[[HANDLER_ADD_OVERFLOW:.*]], label %[[CONT:.*]], !prof [[PROF3]], !nosanitize [[META2]] // REC: [[HANDLER_ADD_OVERFLOW]]: // REC-NEXT: [[TMP3:%.*]] = zext i32 [[X]] to i64, !nosanitize [[META2]] // REC-NEXT: [[TMP4:%.*]] = zext i32 [[Y]] to i64, !nosanitize [[META2]] @@ -198,14 +175,12 @@ void use(double*); // CHECK-NEXT: call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR7:[0-9]+]] // CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 // CHECK-NEXT: [[TMP1:%.*]] = icmp ule i64 [[TMP0]], [[IDXPROM]] -// -// 71 == SO_LocalBounds // CHECK-NEXT: [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 71), !nosanitize [[META2]] // CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP1]], [[TMP2]], !nosanitize [[META2]] // CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP:.*]], label %[[BB4:.*]] // CHECK: [[BB4]]: // CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds double, ptr [[VLA]], i64 [[IDXPROM]] -// CHECK-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA9:![0-9]+]] +// CHECK-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]] // CHECK-NEXT: ret double [[TMP5]] // CHECK: [[TRAP]]: // CHECK-NEXT: call void @__ubsan_handle_local_out_of_bounds_abort() #[[ATTR6]], !nosanitize [[META2]] @@ -227,7 +202,7 @@ void use(double*); // TR-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA7:![0-9]+]] // TR-NEXT: ret double [[TMP5]] // TR: [[TRAP]]: -// TR-NEXT: call void @llvm.ubsantrap(i8 71) #[[ATTR5]], !nosanitize [[META2]] +// TR-NEXT: call void @llvm.ubsantrap(i8 3) #[[ATTR5]], !nosanitize [[META2]] // TR-NEXT: unreachable, !nosanitize [[META2]] // // REC-LABEL: define dso_local double @lbounds( @@ -243,7 +218,7 @@ void use(double*); // REC-NEXT: br i1 [[TMP3]], label %[[TRAP:.*]], label %[[BB4:.*]] // REC: [[BB4]]: // REC-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds double, ptr [[VLA]], i64 [[IDXPROM]] -// REC-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA9:![0-9]+]] +// REC-NEXT: [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]] // REC-NEXT: ret double [[TMP5]] // REC: [[TRAP]]: // REC-NEXT: call void @__ubsan_handle_local_out_of_bounds() #[[ATTR6]], !nosanitize [[META2]] @@ -257,14 +232,13 @@ double lbounds(int b, int i) { //. // CHECK: [[META2]] = !{} -// CHECK: [[PROF3]] = !{!"branch_weights", i32 1048575, i32 1} -// CHECK: [[PROF4]] = !{!"branch_weights", i32 1, i32 1048575} -// CHECK: [[TBAA5]] = !{[[META6:![0-9]+]], [[META6]], i64 0} -// CHECK: [[META6]] = !{!"int", [[META7:![0-9]+]], i64 0} -// CHECK: [[META7]] = !{!"omnipotent char", [[META8:![0-9]+]], i64 0} -// CHECK: [[META8]] = !{!"Simple C/C++ TBAA"} -// CHECK: [[TBAA9]] = !{[[META10:![0-9]+]], [[META10]], i64 0} -// CHECK: [[META10]] = !{!"double", [[META7]], i64 0} +// CHECK: [[PROF3]] = !{!"branch_weights", i32 1, i32 1048575} +// CHECK: [[TBAA4]] = !{[[META5:![0-9]+]], [[META5]], i64 0} +// CHECK: [[META5]] = !{!"int", [[META6:![0-9]+]], i64 0} +// CHECK: [[META6]] = !{!"omnipotent char", [[META7:![0-9]+]], i64 0} +// CHECK: [[META7]] = !{!"Simple C/C++ TBAA"} +// CHECK: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0} +// CHECK: [[META9]] = !{!"double", [[META6]], i64 0} //. // TR: [[META2]] = !{} // TR: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0} @@ -275,12 +249,11 @@ double lbounds(int b, int i) { // TR: [[META8]] = !{!"double", [[META5]], i64 0} //. // REC: [[META2]] = !{} -// REC: [[PROF3]] = !{!"branch_weights", i32 1048575, i32 1} -// REC: [[PROF4]] = !{!"branch_weights", i32 1, i32 1048575} -// REC: [[TBAA5]] = !{[[META6:![0-9]+]], [[META6]], i64 0} -// REC: [[META6]] = !{!"int", [[META7:![0-9]+]], i64 0} -// REC: [[META7]] = !{!"omnipotent char", [[META8:![0-9]+]], i64 0} -// REC: [[META8]] = !{!"Simple C/C++ TBAA"} -// REC: [[TBAA9]] = !{[[META10:![0-9]+]], [[META10]], i64 0} -// REC: [[META10]] = !{!"double", [[META7]], i64 0} +// REC: [[PROF3]] = !{!"branch_weights", i32 1, i32 1048575} +// REC: [[TBAA4]] = !{[[META5:![0-9]+]], [[META5]], i64 0} +// REC: [[META5]] = !{!"int", [[META6:![0-9]+]], i64 0} +// REC: [[META6]] = !{!"omnipotent char", [[META7:![0-9]+]], i64 0} +// REC: [[META7]] = !{!"Simple C/C++ TBAA"} +// REC: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0} +// REC: [[META9]] = !{!"double", [[META6]], i64 0} //. >From 0f5593f325b0dde5deafd0f632eba785fffc0451 Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Mon, 27 Jan 2025 22:57:14 +0000 Subject: [PATCH 3/7] Address Vitaly's feedback (options format coming in next commit) --- .../Instrumentation/LowerAllowCheckPass.cpp | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp index fbf413251424aa..491af0eb9f2f97 100644 --- a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp +++ b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp @@ -73,7 +73,7 @@ static void emitRemark(IntrinsicInst *II, OptimizationRemarkEmitter &ORE, static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI, const ProfileSummaryInfo *PSI, OptimizationRemarkEmitter &ORE, - std::vector<unsigned int> &cutoffs) { + std::vector<unsigned int> const &cutoffs) { SmallVector<std::pair<IntrinsicInst *, bool>, 16> ReplaceWithValue; std::unique_ptr<RandomNumberGenerator> Rng; @@ -83,7 +83,20 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI, return *Rng; }; - auto ShouldRemoveHot = [&](const BasicBlock &BB, const unsigned int &cutoff) { + auto GetCutoff = [&](const IntrinsicInst *II) { + unsigned int cutoff = 0; + if (HotPercentileCutoff.getNumOccurrences()) + cutoff = HotPercentileCutoff; + else if (II->getIntrinsicID() == Intrinsic::allow_ubsan_check) { + auto *Kind = cast<ConstantInt>(II->getArgOperand(0)); + if (Kind->getZExtValue() < cutoffs.size()) + cutoff = cutoffs[Kind->getZExtValue()]; + } + + return cutoff; + }; + + auto ShouldRemoveHot = [&](const BasicBlock &BB, unsigned int &cutoff) { return PSI && PSI->isHotCountNthPercentile( cutoff, BFI.getBlockProfileCount(&BB).value_or(0)); }; @@ -93,10 +106,11 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI, !std::bernoulli_distribution(RandomRate)(GetRng()); }; - // In some cases, EmitCheck was called with multiple checks (e.g., - // SanitizerKind::{Null,ObjectSize,Alignment}, which fall under the umbrella - // of SanitizerHandler::TypeMismatch). We use the threshold for each - // corresponding SanitizerKind. + auto ShouldRemove = [&](const BasicBlock &BB, const IntrinsicInst *II) { + unsigned int cutoff = GetCutoff(II); + return ShouldRemoveRandom() || ShouldRemoveHot(BB, cutoff); + }; + for (BasicBlock &BB : F) { for (Instruction &I : BB) { IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I); @@ -108,17 +122,7 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI, case Intrinsic::allow_runtime_check: { ++NumChecksTotal; - bool ToRemove = ShouldRemoveRandom(); - - unsigned int cutoff = 0; - if (ID == Intrinsic::allow_ubsan_check) { - auto *Kind = cast<ConstantInt>(II->getArgOperand(0)); - if (Kind->getZExtValue() < cutoffs.size()) - cutoff = cutoffs[Kind->getZExtValue()]; - } - if (HotPercentileCutoff.getNumOccurrences()) - cutoff = HotPercentileCutoff; - ToRemove |= ShouldRemoveHot(BB, cutoff); + bool ToRemove = ShouldRemove(BB, II); ReplaceWithValue.push_back({ II, >From 7b6b0166835faff53665321342b47b0887ee99a6 Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Tue, 28 Jan 2025 00:38:34 +0000 Subject: [PATCH 4/7] Change options format --- llvm/lib/Passes/PassBuilder.cpp | 56 +++++++++++++++---- .../Instrumentation/LowerAllowCheckPass.cpp | 23 +++++--- .../Transforms/lower-builtin-allow-check.ll | 8 +-- 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index e3828d2be96042..abe97d8d3df5c3 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -828,25 +828,57 @@ parseLowerAllowCheckPassOptions(StringRef Params) { StringRef ParamName; std::tie(ParamName, Params) = Params.split(';'); - // cutoffs=990000|990000|0|...100000 - if (ParamName.starts_with("cutoffs=")) { - StringRef CutoffsStr; - std::tie(ParamName, CutoffsStr) = ParamName.split('='); + // Format is <cutoffs[1,2,3]=70000;cutoffs[5,6,8]=90000> + // + // Parsing allows duplicate indices (last one takes precedence). + // It would technically be in spec to specify + // cutoffs[0]=70000,cutoffs[1]=90000,cutoffs[0]=80000,... + if (ParamName.starts_with("cutoffs[")) { + StringRef IndicesStr; + StringRef CutoffStr; + + std::tie(IndicesStr, CutoffStr) = ParamName.split('='); + // cutoffs[1,2,3] + // 70000 + + int cutoff; + if (CutoffStr.getAsInteger(0, cutoff)) + return make_error<StringError>( + formatv("invalid LowerAllowCheck pass cutoffs parameter '{0}' " + "({1})", + CutoffStr, Params) + .str(), + inconvertibleErrorCode()); + + if (!IndicesStr.consume_front("cutoffs[") || !IndicesStr.consume_back("]") + || IndicesStr == "") + return make_error<StringError>( + formatv("invalid LowerAllowCheck pass index parameter '{0}' " + "({1})", + IndicesStr, CutoffStr) + .str(), + inconvertibleErrorCode()); - while (CutoffsStr != "") { - StringRef firstCutoffStr; - std::tie(firstCutoffStr, CutoffsStr) = CutoffsStr.split('|'); + while (IndicesStr != "") { + StringRef firstIndexStr; + std::tie(firstIndexStr, IndicesStr) = IndicesStr.split('|'); - int cutoff; - if (firstCutoffStr.getAsInteger(0, cutoff)) + unsigned int index; + if (firstIndexStr.getAsInteger(0, index)) return make_error<StringError>( - formatv("invalid LowerAllowCheck pass cutoffs parameter '{0}' " + formatv("invalid LowerAllowCheck pass index parameter '{0}' " "({1}) {2}", - firstCutoffStr, Params, Result.cutoffs.size()) + firstIndexStr, IndicesStr) .str(), inconvertibleErrorCode()); - Result.cutoffs.push_back(cutoff); + // In the common case (sequentially increasing indices), we will issue + // O(n) resize requests. We assume the underlying data structure has + // O(1) runtime for each added element. + if (index >= Result.cutoffs.size()) + Result.cutoffs.resize(index + 1, 0); + + Result.cutoffs[index] = cutoff; } } else { return make_error<StringError>( diff --git a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp index 491af0eb9f2f97..ba69987672d1fc 100644 --- a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp +++ b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp @@ -172,14 +172,23 @@ void LowerAllowCheckPass::printPipeline( raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) { static_cast<PassInfoMixin<LowerAllowCheckPass> *>(this)->printPipeline( OS, MapClassName2PassName); - OS << "<cutoffs="; - - bool first = true; + OS << "<"; + + // Format is <cutoffs[0,1,2]=70000;cutoffs[5,6,8]=90000> + // but it's equally valid to specify + // cutoffs[0]=70000;cutoffs[1]=70000;cutoffs[2]=70000;cutoffs[5]=90000;... + // and that's what we do here. It is verbose but valid and easy to verify + // correctness. + // TODO: print shorter output by combining adjacent runs, etc. + int i = 0; for (unsigned int cutoff : Opts.cutoffs) { - if (!first) - OS << "|"; - OS << cutoff; - first = false; + if (cutoff > 0) { + if (i > 0) + OS << ";"; + OS << "cutoffs[" << i << "]=" << cutoff; + } + + i++; } OS << '>'; } diff --git a/llvm/test/Transforms/lower-builtin-allow-check.ll b/llvm/test/Transforms/lower-builtin-allow-check.ll index 57fc845dbcda7c..59bc0abd098fd8 100644 --- a/llvm/test/Transforms/lower-builtin-allow-check.ll +++ b/llvm/test/Transforms/lower-builtin-allow-check.ll @@ -3,10 +3,10 @@ ; RUN: opt < %s -passes='function(lower-allow-check)' -lower-allow-check-random-rate=0 -S | FileCheck %s --check-prefixes=NONE ; RUN: opt < %s -passes='function(lower-allow-check)' -lower-allow-check-random-rate=1 -S | FileCheck %s --check-prefixes=ALL ; -; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs=990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000>)' -S | FileCheck %s --check-prefixes=HOT99 -; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs=700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000>)' -S | FileCheck %s --check-prefixes=HOT70 -; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs=990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000|990000>)' -lower-allow-check-random-rate=0 -S | FileCheck %s --check-prefixes=NONE99 -; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs=700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000|700000>)' -lower-allow-check-random-rate=1 -S | FileCheck %s --check-prefixes=ALL70 +; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs[0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80]=990000;cutoffs[81]=100000>)' -S | FileCheck %s --check-prefixes=HOT99 +; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs[0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80]=700000>)' -S | FileCheck %s --check-prefixes=HOT70 +; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs[0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80]=990000>)' -lower-allow-check-random-rate=0 -S | FileCheck %s --check-prefixes=NONE99 +; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check<cutoffs[0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80]=700000>)' -lower-allow-check-random-rate=1 -S | FileCheck %s --check-prefixes=ALL70 ; ; -lower-allow-check-percentile-cutoff is deprecated and will be removed in the future; ; use the cutoffs parameter to the lower-allow-check pass, as shown above. >From bdb502e60269be5fbc68872866d7841d2395bbe5 Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Tue, 28 Jan 2025 00:52:40 +0000 Subject: [PATCH 5/7] Remove & --- llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp index ba69987672d1fc..a8e5d473d26a49 100644 --- a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp +++ b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp @@ -96,7 +96,7 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI, return cutoff; }; - auto ShouldRemoveHot = [&](const BasicBlock &BB, unsigned int &cutoff) { + auto ShouldRemoveHot = [&](const BasicBlock &BB, unsigned int cutoff) { return PSI && PSI->isHotCountNthPercentile( cutoff, BFI.getBlockProfileCount(&BB).value_or(0)); }; >From e183793fdb3902b0ffb0be8e7042c51b46a870cc Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Tue, 28 Jan 2025 00:55:49 +0000 Subject: [PATCH 6/7] clang-format --- llvm/lib/Passes/PassBuilder.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index abe97d8d3df5c3..bc4aba48a4ed05 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -850,14 +850,14 @@ parseLowerAllowCheckPassOptions(StringRef Params) { .str(), inconvertibleErrorCode()); - if (!IndicesStr.consume_front("cutoffs[") || !IndicesStr.consume_back("]") - || IndicesStr == "") - return make_error<StringError>( - formatv("invalid LowerAllowCheck pass index parameter '{0}' " - "({1})", - IndicesStr, CutoffStr) - .str(), - inconvertibleErrorCode()); + if (!IndicesStr.consume_front("cutoffs[") || + !IndicesStr.consume_back("]") || IndicesStr == "") + return make_error<StringError>( + formatv("invalid LowerAllowCheck pass index parameter '{0}' " + "({1})", + IndicesStr, CutoffStr) + .str(), + inconvertibleErrorCode()); while (IndicesStr != "") { StringRef firstIndexStr; >From e514a83b8a70ea6eac141415125444861ce0bb74 Mon Sep 17 00:00:00 2001 From: Thurston Dang <thurs...@google.com> Date: Tue, 28 Jan 2025 00:56:46 +0000 Subject: [PATCH 7/7] Remove unnecessary whitespace change --- clang/lib/Frontend/CompilerInvocation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 461710cfb85eb7..58658dedbaf1ee 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2314,6 +2314,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.SanitizeSkipHotCutoffs = parseSanitizerWeightedKinds( "-fsanitize-skip-hot-cutoff=", Args.getAllArgValues(OPT_fsanitize_skip_hot_cutoff_EQ), Diags); + Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); if (!LangOpts->CUDAIsDevice) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits