[clang] [llvm] [ubsan] Change ubsan-unique-traps to use nomerge instead of counter (PR #117651)
Thurston Dang via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 26 14:55:31 PST 2024
https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/117651
>From cffa7c3081a1d7b9cb64ac129109cb358d11a751 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 00:33:09 +0000
Subject: [PATCH 01/14] [ubsan] Change ubsan-unique-traps to use nomerge
instead of counter
https://github.com/llvm/llvm-project/pull/65972 (continuation of https://reviews.llvm.org/D148654) had considered adding nomerge to ubsantrap, but did not proceed with that because of https://github.com/llvm/llvm-project/issues/53011. Instead, it added a counter (based on TrapBB->getParent()->size()) to each ubsantrap call. However, this counter is not guaranteed to be unique after inlining, as shown by https://github.com/llvm/llvm-project/pull/83470, which can result in ubsantraps being merged by the backend.
https://github.com/llvm/llvm-project/pull/101549 fixed has since fixed the nomerge limitation ("It sets nomerge flag for the node if the instruction has nomerge arrtibute."). This patch therefore takes advantage of nomerge instead of using the counter, guaranteeing that the ubsantraps are not merged.
This patch is equivalent to https://github.com/llvm/llvm-project/pull/83470 but also adds nomerge and updates the test that was precommitted in https://github.com/llvm/llvm-project/pull/117649.
---
clang/lib/CodeGen/CGExpr.cpp | 6 ++--
clang/test/CodeGen/bounds-checking.c | 4 +--
clang/test/CodeGen/ubsan-trap-merge.c | 24 +++++++--------
llvm/test/CodeGen/X86/ubsan-trap-merge.ll | 31 ++++++++++---------
llvm/test/CodeGen/X86/ubsan-trap-nomerge.ll | 33 ++++++++++-----------
5 files changed, 47 insertions(+), 51 deletions(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index d3f470d401b3d4..f8c1e1cd7a4d68 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3921,16 +3921,14 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
llvm::CallInst *TrapCall = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
- llvm::ConstantInt::get(CGM.Int8Ty,
- ClSanitizeDebugDeoptimization
- ? TrapBB->getParent()->size()
- : static_cast<uint64_t>(CheckHandlerID)));
+ llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID));
if (!CGM.getCodeGenOpts().TrapFuncName.empty()) {
auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name",
CGM.getCodeGenOpts().TrapFuncName);
TrapCall->addFnAttr(A);
}
+ TrapCall->addFnAttr(llvm::Attribute::NoMerge);
TrapCall->setDoesNotReturn();
TrapCall->setDoesNotThrow();
Builder.CreateUnreachable();
diff --git a/clang/test/CodeGen/bounds-checking.c b/clang/test/CodeGen/bounds-checking.c
index 8100e30d0650ad..f6c4880e70a150 100644
--- a/clang/test/CodeGen/bounds-checking.c
+++ b/clang/test/CodeGen/bounds-checking.c
@@ -74,11 +74,11 @@ char B2[10];
// CHECK-LABEL: @f8
void f8(int i, int k) {
// NOOPTLOCAL: call void @llvm.ubsantrap(i8 3)
- // NOOPTARRAY: call void @llvm.ubsantrap(i8 2)
+ // NOOPTARRAY: call void @llvm.ubsantrap(i8 18)
B[i] = '\0';
// NOOPTLOCAL: call void @llvm.ubsantrap(i8 5)
- // NOOPTARRAY: call void @llvm.ubsantrap(i8 4)
+ // NOOPTARRAY: call void @llvm.ubsantrap(i8 18)
B2[k] = '\0';
}
diff --git a/clang/test/CodeGen/ubsan-trap-merge.c b/clang/test/CodeGen/ubsan-trap-merge.c
index b4de97b5e08f33..ef32605c73174a 100644
--- a/clang/test/CodeGen/ubsan-trap-merge.c
+++ b/clang/test/CodeGen/ubsan-trap-merge.c
@@ -1,20 +1,20 @@
// NOTE: Assertions have mostly been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// The most important assertion is the attributes at the end of the file, which
-// shows that ubsan does not currently attach 'nomerge'.
+// shows that ubsan attaches 'nomerge' to each ubsantrap intrinsic.
//
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -O3 -mllvm -ubsan-unique-traps %s -o - \
// RUN: | FileCheck %s
//
// REQUIRES: x86-registered-target
-// CHECK-LABEL: define dso_local noundef i32 @f(
+// CHECK-LABEL: define dso_local range(i32 -2147483523, -2147483648) i32 @f(
// CHECK-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 125), !nosanitize [[META2:![0-9]+]]
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]]
// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]]
// CHECK: [[TRAP]]:
-// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !nosanitize [[META2]]
+// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4:[0-9]+]], !nosanitize [[META2]]
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
// CHECK: [[CONT]]:
// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]]
@@ -24,14 +24,14 @@ int f(int x) {
return x + 125;
}
-// CHECK-LABEL: define dso_local noundef i32 @g(
+// CHECK-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @g(
// CHECK-SAME: i32 noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]]
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]]
// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]]
// CHECK: [[TRAP]]:
-// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4]], !nosanitize [[META2]]
+// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]]
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
// CHECK: [[CONT]]:
// CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]]
@@ -41,21 +41,21 @@ int g(int x) {
return x + 127;
}
-// CHECK-LABEL: define dso_local noundef i32 @h(
+// CHECK-LABEL: define dso_local range(i32 -2147483521, -2147483648) i32 @h(
// CHECK-SAME: i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 127), !nosanitize [[META2]]
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]]
// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]]
// CHECK: [[TRAP]]:
-// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4]], !nosanitize [[META2]]
+// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]]
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
// CHECK: [[CONT]]:
// CHECK-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 129), !nosanitize [[META2]]
// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]]
// CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP1:.*]], label %[[CONT2:.*]], !nosanitize [[META2]]
// CHECK: [[TRAP1]]:
-// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 4) #[[ATTR4]], !nosanitize [[META2]]
+// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]]
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
// CHECK: [[CONT2]]:
// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]]
@@ -76,14 +76,14 @@ int h(int x, int y) {
// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1, !nosanitize [[META2]]
// CHECK-NEXT: br i1 [[TMP1]], label %[[TRAP_I:.*]], label %[[F_EXIT:.*]], !nosanitize [[META2]]
// CHECK: [[TRAP_I]]:
-// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4]], !nosanitize [[META2]]
+// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]]
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
// CHECK: [[F_EXIT]]:
// CHECK-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[Y]], i32 127), !nosanitize [[META2]]
// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]]
// CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP_I2:.*]], label %[[G_EXIT:.*]], !nosanitize [[META2]]
// CHECK: [[TRAP_I2]]:
-// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4]], !nosanitize [[META2]]
+// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]]
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
// CHECK: [[G_EXIT]]:
// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0, !nosanitize [[META2]]
@@ -92,7 +92,7 @@ int h(int x, int y) {
// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP6]], 1, !nosanitize [[META2]]
// CHECK-NEXT: br i1 [[TMP7]], label %[[TRAP:.*]], label %[[CONT:.*]], !nosanitize [[META2]]
// CHECK: [[TRAP]]:
-// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4]], !nosanitize [[META2]]
+// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]]
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
// CHECK: [[CONT]]:
// CHECK-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP6]], 0, !nosanitize [[META2]]
@@ -102,4 +102,4 @@ int m(int x, int y) {
return f(x) + g(y);
}
//.
-// CHECK: attributes #[[ATTR4]] = { noreturn nounwind }
+// CHECK: attributes #[[ATTR4]] = { nomerge noreturn nounwind }
diff --git a/llvm/test/CodeGen/X86/ubsan-trap-merge.ll b/llvm/test/CodeGen/X86/ubsan-trap-merge.ll
index b96c85473e5387..98244fa8157678 100644
--- a/llvm/test/CodeGen/X86/ubsan-trap-merge.ll
+++ b/llvm/test/CodeGen/X86/ubsan-trap-merge.ll
@@ -4,7 +4,8 @@
; This test shows that ubsantrap can, in the absence of nomerge, be merged by
; the backend into a single ud1 instruction (thus making debugging difficult).
;
-; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c.
+; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c with
+; 'nomerge' manually removed from ubsantraps.
;
; ModuleID = '../clang/test/CodeGen/ubsan-trap-merge.c'
source_filename = "../clang/test/CodeGen/ubsan-trap-merge.c"
@@ -21,14 +22,14 @@ define dso_local range(i32 -2147483523, -2147483648) i32 @f(i32 noundef %x) loca
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB0_1: # %trap
-; CHECK-NEXT: ud1l 2(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
entry:
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
br i1 %1, label %trap, label %cont, !nosanitize !5
trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
cont: ; preds = %entry
@@ -52,14 +53,14 @@ define dso_local range(i32 -2147483521, -2147483648) i32 @g(i32 noundef %x) loca
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB1_1: # %trap
-; CHECK-NEXT: ud1l 2(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
entry:
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
br i1 %1, label %trap, label %cont, !nosanitize !5
trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
cont: ; preds = %entry
@@ -75,23 +76,21 @@ define dso_local range(i32 -2147483521, -2147483648) i32 @h(i32 noundef %x, i32
; CHECK-NEXT: jo .LBB2_3
; CHECK-NEXT: # %bb.1: # %cont
; CHECK-NEXT: addl $129, %esi
-; CHECK-NEXT: jo .LBB2_4
+; CHECK-NEXT: jo .LBB2_3
; CHECK-NEXT: # %bb.2: # %cont2
; CHECK-NEXT: cmpl %esi, %edi
; CHECK-NEXT: cmovll %edi, %esi
; CHECK-NEXT: movl %esi, %eax
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB2_3: # %trap
-; CHECK-NEXT: ud1l 2(%eax), %eax
-; CHECK-NEXT: .LBB2_4: # %trap1
-; CHECK-NEXT: ud1l 4(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
entry:
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
br i1 %1, label %trap, label %cont, !nosanitize !5
trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
cont: ; preds = %entry
@@ -100,7 +99,7 @@ cont: ; preds = %entry
br i1 %3, label %trap1, label %cont2, !nosanitize !5
trap1: ; preds = %cont
- tail call void @llvm.ubsantrap(i8 4) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
cont2: ; preds = %cont
@@ -126,14 +125,14 @@ define dso_local noundef i32 @m(i32 noundef %x, i32 noundef %y) local_unnamed_ad
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB3_4: # %trap.i
-; CHECK-NEXT: ud1l 2(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
entry:
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
br i1 %1, label %trap.i, label %f.exit, !nosanitize !5
trap.i: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
f.exit: ; preds = %entry
@@ -142,7 +141,7 @@ f.exit: ; preds = %entry
br i1 %3, label %trap.i2, label %g.exit, !nosanitize !5
trap.i2: ; preds = %f.exit
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
g.exit: ; preds = %f.exit
@@ -153,7 +152,7 @@ g.exit: ; preds = %f.exit
br i1 %7, label %trap, label %cont, !nosanitize !5
trap: ; preds = %g.exit
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
cont: ; preds = %g.exit
@@ -177,5 +176,5 @@ attributes #4 = { noreturn nounwind }
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
-!4 = !{!"clang version 20.0.0git (https://github.com/llvm/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
+!4 = !{!"clang version 20.0.0git (https://github.com/thurstond/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
!5 = !{}
diff --git a/llvm/test/CodeGen/X86/ubsan-trap-nomerge.ll b/llvm/test/CodeGen/X86/ubsan-trap-nomerge.ll
index 683e318011b8e0..0bbb36cf63bf68 100644
--- a/llvm/test/CodeGen/X86/ubsan-trap-nomerge.ll
+++ b/llvm/test/CodeGen/X86/ubsan-trap-nomerge.ll
@@ -4,8 +4,7 @@
; This tests that the nomerge attribute for ubsantrap works correctly i.e.,
; they are lowered to separate ud1 instructions.
;
-; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c with
-; 'nomerge' manually added to ubsantraps.
+; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c.
;
; ModuleID = '../clang/test/CodeGen/ubsan-trap-merge.c'
source_filename = "../clang/test/CodeGen/ubsan-trap-merge.c"
@@ -22,14 +21,14 @@ define dso_local range(i32 -2147483523, -2147483648) i32 @f(i32 noundef %x) loca
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB0_1: # %trap
-; CHECK-NEXT: ud1l 2(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
entry:
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
br i1 %1, label %trap, label %cont, !nosanitize !5
trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
cont: ; preds = %entry
@@ -53,14 +52,14 @@ define dso_local range(i32 -2147483521, -2147483648) i32 @g(i32 noundef %x) loca
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB1_1: # %trap
-; CHECK-NEXT: ud1l 2(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
entry:
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
br i1 %1, label %trap, label %cont, !nosanitize !5
trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
cont: ; preds = %entry
@@ -83,16 +82,16 @@ define dso_local range(i32 -2147483521, -2147483648) i32 @h(i32 noundef %x, i32
; CHECK-NEXT: movl %esi, %eax
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB2_3: # %trap
-; CHECK-NEXT: ud1l 2(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
; CHECK-NEXT: .LBB2_4: # %trap1
-; CHECK-NEXT: ud1l 4(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
entry:
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
br i1 %1, label %trap, label %cont, !nosanitize !5
trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
cont: ; preds = %entry
@@ -101,7 +100,7 @@ cont: ; preds = %entry
br i1 %3, label %trap1, label %cont2, !nosanitize !5
trap1: ; preds = %cont
- tail call void @llvm.ubsantrap(i8 4) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
cont2: ; preds = %cont
@@ -127,18 +126,18 @@ define dso_local noundef i32 @m(i32 noundef %x, i32 noundef %y) local_unnamed_ad
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB3_4: # %trap.i
-; CHECK-NEXT: ud1l 2(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
; CHECK-NEXT: .LBB3_5: # %trap.i2
-; CHECK-NEXT: ud1l 2(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
; CHECK-NEXT: .LBB3_6: # %trap
-; CHECK-NEXT: ud1l 2(%eax), %eax
+; CHECK-NEXT: ud1l (%eax), %eax
entry:
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
br i1 %1, label %trap.i, label %f.exit, !nosanitize !5
trap.i: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
f.exit: ; preds = %entry
@@ -147,7 +146,7 @@ f.exit: ; preds = %entry
br i1 %3, label %trap.i2, label %g.exit, !nosanitize !5
trap.i2: ; preds = %f.exit
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
g.exit: ; preds = %f.exit
@@ -158,7 +157,7 @@ g.exit: ; preds = %f.exit
br i1 %7, label %trap, label %cont, !nosanitize !5
trap: ; preds = %g.exit
- tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
unreachable, !nosanitize !5
cont: ; preds = %g.exit
@@ -182,5 +181,5 @@ attributes #4 = { nomerge noreturn nounwind }
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
-!4 = !{!"clang version 20.0.0git (https://github.com/llvm/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
+!4 = !{!"clang version 20.0.0git (https://github.com/thurstond/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
!5 = !{}
>From 3e988788e2ddcb36bf4b2aca9ac0e641225de998 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 00:49:04 +0000
Subject: [PATCH 02/14] Add test to show that ubsantrap with nomerge is
correctly lowered by backend.
---
llvm/test/MC/X86/ubsan-trap-merge.ll | 185 +++++++++++++++++++++++++++
1 file changed, 185 insertions(+)
create mode 100644 llvm/test/MC/X86/ubsan-trap-merge.ll
diff --git a/llvm/test/MC/X86/ubsan-trap-merge.ll b/llvm/test/MC/X86/ubsan-trap-merge.ll
new file mode 100644
index 00000000000000..24eb734dbfccbf
--- /dev/null
+++ b/llvm/test/MC/X86/ubsan-trap-merge.ll
@@ -0,0 +1,185 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -O3 -mtriple x86_64 -filetype asm -o - %s | FileCheck %s
+;
+; This tests that the nomerge attribute for ubsantrap works correctly i.e.,
+; they are lowered to separate ud1 instructions.
+;
+; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c
+;
+; ModuleID = '../clang/test/CodeGen/ubsan-trap-merge.c'
+source_filename = "../clang/test/CodeGen/ubsan-trap-merge.c"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define dso_local range(i32 -2147483523, -2147483648) i32 @f(i32 noundef %x) local_unnamed_addr #0 {
+; CHECK-LABEL: f:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addl $125, %edi
+; CHECK-NEXT: jo .LBB0_1
+; CHECK-NEXT: # %bb.2: # %cont
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: retq
+; CHECK-NEXT: .LBB0_1: # %trap
+; CHECK-NEXT: ud1l (%eax), %eax
+entry:
+ %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
+ %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
+ br i1 %1, label %trap, label %cont, !nosanitize !5
+
+trap: ; preds = %entry
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+cont: ; preds = %entry
+ %2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
+ ret i32 %2
+}
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none)
+declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1
+
+; Function Attrs: cold noreturn nounwind
+declare void @llvm.ubsantrap(i8 immarg) #2
+
+; Function Attrs: nounwind uwtable
+define dso_local range(i32 -2147483521, -2147483648) i32 @g(i32 noundef %x) local_unnamed_addr #0 {
+; CHECK-LABEL: g:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addl $127, %edi
+; CHECK-NEXT: jo .LBB1_1
+; CHECK-NEXT: # %bb.2: # %cont
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: retq
+; CHECK-NEXT: .LBB1_1: # %trap
+; CHECK-NEXT: ud1l (%eax), %eax
+entry:
+ %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
+ %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
+ br i1 %1, label %trap, label %cont, !nosanitize !5
+
+trap: ; preds = %entry
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+cont: ; preds = %entry
+ %2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
+ ret i32 %2
+}
+
+; Function Attrs: nounwind uwtable
+define dso_local range(i32 -2147483521, -2147483648) i32 @h(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
+; CHECK-LABEL: h:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addl $127, %edi
+; CHECK-NEXT: jo .LBB2_3
+; CHECK-NEXT: # %bb.1: # %cont
+; CHECK-NEXT: addl $129, %esi
+; CHECK-NEXT: jo .LBB2_4
+; CHECK-NEXT: # %bb.2: # %cont2
+; CHECK-NEXT: cmpl %esi, %edi
+; CHECK-NEXT: cmovll %edi, %esi
+; CHECK-NEXT: movl %esi, %eax
+; CHECK-NEXT: retq
+; CHECK-NEXT: .LBB2_3: # %trap
+; CHECK-NEXT: ud1l (%eax), %eax
+; CHECK-NEXT: .LBB2_4: # %trap1
+; CHECK-NEXT: ud1l (%eax), %eax
+entry:
+ %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
+ %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
+ br i1 %1, label %trap, label %cont, !nosanitize !5
+
+trap: ; preds = %entry
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+cont: ; preds = %entry
+ %2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 129), !nosanitize !5
+ %3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
+ br i1 %3, label %trap1, label %cont2, !nosanitize !5
+
+trap1: ; preds = %cont
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+cont2: ; preds = %cont
+ %4 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
+ %5 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
+ %cond = tail call i32 @llvm.smin.i32(i32 %5, i32 %4)
+ ret i32 %cond
+}
+
+; Function Attrs: nounwind uwtable
+define dso_local noundef i32 @m(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
+; CHECK-LABEL: m:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addl $125, %edi
+; CHECK-NEXT: jo .LBB3_4
+; CHECK-NEXT: # %bb.1: # %f.exit
+; CHECK-NEXT: addl $127, %esi
+; CHECK-NEXT: jo .LBB3_5
+; CHECK-NEXT: # %bb.2: # %g.exit
+; CHECK-NEXT: addl %esi, %edi
+; CHECK-NEXT: jo .LBB3_6
+; CHECK-NEXT: # %bb.3: # %cont
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: retq
+; CHECK-NEXT: .LBB3_4: # %trap.i
+; CHECK-NEXT: ud1l (%eax), %eax
+; CHECK-NEXT: .LBB3_5: # %trap.i2
+; CHECK-NEXT: ud1l (%eax), %eax
+; CHECK-NEXT: .LBB3_6: # %trap
+; CHECK-NEXT: ud1l (%eax), %eax
+entry:
+ %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
+ %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
+ br i1 %1, label %trap.i, label %f.exit, !nosanitize !5
+
+trap.i: ; preds = %entry
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+f.exit: ; preds = %entry
+ %2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 127), !nosanitize !5
+ %3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
+ br i1 %3, label %trap.i2, label %g.exit, !nosanitize !5
+
+trap.i2: ; preds = %f.exit
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+g.exit: ; preds = %f.exit
+ %4 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
+ %5 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
+ %6 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %4, i32 %5), !nosanitize !5
+ %7 = extractvalue { i32, i1 } %6, 1, !nosanitize !5
+ br i1 %7, label %trap, label %cont, !nosanitize !5
+
+trap: ; preds = %g.exit
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+cont: ; preds = %g.exit
+ %8 = extractvalue { i32, i1 } %6, 0, !nosanitize !5
+ ret i32 %8
+}
+
+; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+declare i32 @llvm.smin.i32(i32, i32) #3
+
+attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+attributes #2 = { cold noreturn nounwind }
+attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+attributes #4 = { nomerge noreturn nounwind }
+
+!llvm.module.flags = !{!0, !1, !2, !3}
+!llvm.ident = !{!4}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 8, !"PIC Level", i32 2}
+!2 = !{i32 7, !"PIE Level", i32 2}
+!3 = !{i32 7, !"uwtable", i32 2}
+!4 = !{!"clang version 20.0.0git (https://github.com/thurstond/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
+!5 = !{}
>From 24a9c9ff0b22268425e2f2c7fa52de5a094735b2 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 00:51:18 +0000
Subject: [PATCH 03/14] clang-format
---
clang/lib/CodeGen/CGExpr.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index f8c1e1cd7a4d68..74e185c30c0878 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3919,9 +3919,9 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
Builder.CreateCondBr(Checked, Cont, TrapBB);
EmitBlock(TrapBB);
- llvm::CallInst *TrapCall = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
- llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID));
+ llvm::CallInst *TrapCall =
+ Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
+ llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID));
if (!CGM.getCodeGenOpts().TrapFuncName.empty()) {
auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name",
>From 0f23ce92be15163f4a28d9276379877fd4112f7a Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 02:41:11 +0000
Subject: [PATCH 04/14] Separate ubsan-trap-merge.ll and ubsan-trap-nomerge.ll
test cases per https://github.com/llvm/llvm-project/pull/117657/files
---
llvm/test/MC/X86/ubsan-trap-merge.ll | 21 ++-
llvm/test/MC/X86/ubsan-trap-nomerge.ll | 185 +++++++++++++++++++++++++
2 files changed, 193 insertions(+), 13 deletions(-)
create mode 100644 llvm/test/MC/X86/ubsan-trap-nomerge.ll
diff --git a/llvm/test/MC/X86/ubsan-trap-merge.ll b/llvm/test/MC/X86/ubsan-trap-merge.ll
index 24eb734dbfccbf..98244fa8157678 100644
--- a/llvm/test/MC/X86/ubsan-trap-merge.ll
+++ b/llvm/test/MC/X86/ubsan-trap-merge.ll
@@ -1,10 +1,11 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -O3 -mtriple x86_64 -filetype asm -o - %s | FileCheck %s
;
-; This tests that the nomerge attribute for ubsantrap works correctly i.e.,
-; they are lowered to separate ud1 instructions.
+; This test shows that ubsantrap can, in the absence of nomerge, be merged by
+; the backend into a single ud1 instruction (thus making debugging difficult).
;
-; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c
+; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c with
+; 'nomerge' manually removed from ubsantraps.
;
; ModuleID = '../clang/test/CodeGen/ubsan-trap-merge.c'
source_filename = "../clang/test/CodeGen/ubsan-trap-merge.c"
@@ -75,7 +76,7 @@ define dso_local range(i32 -2147483521, -2147483648) i32 @h(i32 noundef %x, i32
; CHECK-NEXT: jo .LBB2_3
; CHECK-NEXT: # %bb.1: # %cont
; CHECK-NEXT: addl $129, %esi
-; CHECK-NEXT: jo .LBB2_4
+; CHECK-NEXT: jo .LBB2_3
; CHECK-NEXT: # %bb.2: # %cont2
; CHECK-NEXT: cmpl %esi, %edi
; CHECK-NEXT: cmovll %edi, %esi
@@ -83,8 +84,6 @@ define dso_local range(i32 -2147483521, -2147483648) i32 @h(i32 noundef %x, i32
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB2_3: # %trap
; CHECK-NEXT: ud1l (%eax), %eax
-; CHECK-NEXT: .LBB2_4: # %trap1
-; CHECK-NEXT: ud1l (%eax), %eax
entry:
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
@@ -118,19 +117,15 @@ define dso_local noundef i32 @m(i32 noundef %x, i32 noundef %y) local_unnamed_ad
; CHECK-NEXT: jo .LBB3_4
; CHECK-NEXT: # %bb.1: # %f.exit
; CHECK-NEXT: addl $127, %esi
-; CHECK-NEXT: jo .LBB3_5
+; CHECK-NEXT: jo .LBB3_4
; CHECK-NEXT: # %bb.2: # %g.exit
; CHECK-NEXT: addl %esi, %edi
-; CHECK-NEXT: jo .LBB3_6
+; CHECK-NEXT: jo .LBB3_4
; CHECK-NEXT: # %bb.3: # %cont
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB3_4: # %trap.i
; CHECK-NEXT: ud1l (%eax), %eax
-; CHECK-NEXT: .LBB3_5: # %trap.i2
-; CHECK-NEXT: ud1l (%eax), %eax
-; CHECK-NEXT: .LBB3_6: # %trap
-; CHECK-NEXT: ud1l (%eax), %eax
entry:
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
@@ -172,7 +167,7 @@ attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-mat
attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #2 = { cold noreturn nounwind }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-attributes #4 = { nomerge noreturn nounwind }
+attributes #4 = { noreturn nounwind }
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}
diff --git a/llvm/test/MC/X86/ubsan-trap-nomerge.ll b/llvm/test/MC/X86/ubsan-trap-nomerge.ll
new file mode 100644
index 00000000000000..0bbb36cf63bf68
--- /dev/null
+++ b/llvm/test/MC/X86/ubsan-trap-nomerge.ll
@@ -0,0 +1,185 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -O3 -mtriple x86_64 -filetype asm -o - %s | FileCheck %s
+;
+; This tests that the nomerge attribute for ubsantrap works correctly i.e.,
+; they are lowered to separate ud1 instructions.
+;
+; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c.
+;
+; ModuleID = '../clang/test/CodeGen/ubsan-trap-merge.c'
+source_filename = "../clang/test/CodeGen/ubsan-trap-merge.c"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define dso_local range(i32 -2147483523, -2147483648) i32 @f(i32 noundef %x) local_unnamed_addr #0 {
+; CHECK-LABEL: f:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addl $125, %edi
+; CHECK-NEXT: jo .LBB0_1
+; CHECK-NEXT: # %bb.2: # %cont
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: retq
+; CHECK-NEXT: .LBB0_1: # %trap
+; CHECK-NEXT: ud1l (%eax), %eax
+entry:
+ %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
+ %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
+ br i1 %1, label %trap, label %cont, !nosanitize !5
+
+trap: ; preds = %entry
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+cont: ; preds = %entry
+ %2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
+ ret i32 %2
+}
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none)
+declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1
+
+; Function Attrs: cold noreturn nounwind
+declare void @llvm.ubsantrap(i8 immarg) #2
+
+; Function Attrs: nounwind uwtable
+define dso_local range(i32 -2147483521, -2147483648) i32 @g(i32 noundef %x) local_unnamed_addr #0 {
+; CHECK-LABEL: g:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addl $127, %edi
+; CHECK-NEXT: jo .LBB1_1
+; CHECK-NEXT: # %bb.2: # %cont
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: retq
+; CHECK-NEXT: .LBB1_1: # %trap
+; CHECK-NEXT: ud1l (%eax), %eax
+entry:
+ %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
+ %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
+ br i1 %1, label %trap, label %cont, !nosanitize !5
+
+trap: ; preds = %entry
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+cont: ; preds = %entry
+ %2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
+ ret i32 %2
+}
+
+; Function Attrs: nounwind uwtable
+define dso_local range(i32 -2147483521, -2147483648) i32 @h(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
+; CHECK-LABEL: h:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addl $127, %edi
+; CHECK-NEXT: jo .LBB2_3
+; CHECK-NEXT: # %bb.1: # %cont
+; CHECK-NEXT: addl $129, %esi
+; CHECK-NEXT: jo .LBB2_4
+; CHECK-NEXT: # %bb.2: # %cont2
+; CHECK-NEXT: cmpl %esi, %edi
+; CHECK-NEXT: cmovll %edi, %esi
+; CHECK-NEXT: movl %esi, %eax
+; CHECK-NEXT: retq
+; CHECK-NEXT: .LBB2_3: # %trap
+; CHECK-NEXT: ud1l (%eax), %eax
+; CHECK-NEXT: .LBB2_4: # %trap1
+; CHECK-NEXT: ud1l (%eax), %eax
+entry:
+ %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
+ %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
+ br i1 %1, label %trap, label %cont, !nosanitize !5
+
+trap: ; preds = %entry
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+cont: ; preds = %entry
+ %2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 129), !nosanitize !5
+ %3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
+ br i1 %3, label %trap1, label %cont2, !nosanitize !5
+
+trap1: ; preds = %cont
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+cont2: ; preds = %cont
+ %4 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
+ %5 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
+ %cond = tail call i32 @llvm.smin.i32(i32 %5, i32 %4)
+ ret i32 %cond
+}
+
+; Function Attrs: nounwind uwtable
+define dso_local noundef i32 @m(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
+; CHECK-LABEL: m:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addl $125, %edi
+; CHECK-NEXT: jo .LBB3_4
+; CHECK-NEXT: # %bb.1: # %f.exit
+; CHECK-NEXT: addl $127, %esi
+; CHECK-NEXT: jo .LBB3_5
+; CHECK-NEXT: # %bb.2: # %g.exit
+; CHECK-NEXT: addl %esi, %edi
+; CHECK-NEXT: jo .LBB3_6
+; CHECK-NEXT: # %bb.3: # %cont
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: retq
+; CHECK-NEXT: .LBB3_4: # %trap.i
+; CHECK-NEXT: ud1l (%eax), %eax
+; CHECK-NEXT: .LBB3_5: # %trap.i2
+; CHECK-NEXT: ud1l (%eax), %eax
+; CHECK-NEXT: .LBB3_6: # %trap
+; CHECK-NEXT: ud1l (%eax), %eax
+entry:
+ %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
+ %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
+ br i1 %1, label %trap.i, label %f.exit, !nosanitize !5
+
+trap.i: ; preds = %entry
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+f.exit: ; preds = %entry
+ %2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 127), !nosanitize !5
+ %3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
+ br i1 %3, label %trap.i2, label %g.exit, !nosanitize !5
+
+trap.i2: ; preds = %f.exit
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+g.exit: ; preds = %f.exit
+ %4 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
+ %5 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
+ %6 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %4, i32 %5), !nosanitize !5
+ %7 = extractvalue { i32, i1 } %6, 1, !nosanitize !5
+ br i1 %7, label %trap, label %cont, !nosanitize !5
+
+trap: ; preds = %g.exit
+ tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
+ unreachable, !nosanitize !5
+
+cont: ; preds = %g.exit
+ %8 = extractvalue { i32, i1 } %6, 0, !nosanitize !5
+ ret i32 %8
+}
+
+; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+declare i32 @llvm.smin.i32(i32, i32) #3
+
+attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+attributes #2 = { cold noreturn nounwind }
+attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+attributes #4 = { nomerge noreturn nounwind }
+
+!llvm.module.flags = !{!0, !1, !2, !3}
+!llvm.ident = !{!4}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 8, !"PIC Level", i32 2}
+!2 = !{i32 7, !"PIE Level", i32 2}
+!3 = !{i32 7, !"uwtable", i32 2}
+!4 = !{!"clang version 20.0.0git (https://github.com/thurstond/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
+!5 = !{}
>From cd9434164de4e2f48db7bfcb456b6fe20ab041ca Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 18:05:27 +0000
Subject: [PATCH 05/14] Use clang_cc1 and explicit triple.
---
clang/test/CodeGen/ubsan-trap-merge.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/test/CodeGen/ubsan-trap-merge.c b/clang/test/CodeGen/ubsan-trap-merge.c
index ef32605c73174a..b5b18afb2fc9de 100644
--- a/clang/test/CodeGen/ubsan-trap-merge.c
+++ b/clang/test/CodeGen/ubsan-trap-merge.c
@@ -1,3 +1,4 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// NOTE: Assertions have mostly been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// The most important assertion is the attributes at the end of the file, which
// shows that ubsan attaches 'nomerge' to each ubsantrap intrinsic.
>From 7ff5ad80c837b227ab711ff07dbbce6f46536e0a Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 18:08:17 +0000
Subject: [PATCH 06/14] Move .ll tests to CodeGen directory
---
llvm/test/MC/X86/ubsan-trap-merge.ll | 180 ------------------------
llvm/test/MC/X86/ubsan-trap-nomerge.ll | 185 -------------------------
2 files changed, 365 deletions(-)
delete mode 100644 llvm/test/MC/X86/ubsan-trap-merge.ll
delete mode 100644 llvm/test/MC/X86/ubsan-trap-nomerge.ll
diff --git a/llvm/test/MC/X86/ubsan-trap-merge.ll b/llvm/test/MC/X86/ubsan-trap-merge.ll
deleted file mode 100644
index 98244fa8157678..00000000000000
--- a/llvm/test/MC/X86/ubsan-trap-merge.ll
+++ /dev/null
@@ -1,180 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
-; RUN: llc -O3 -mtriple x86_64 -filetype asm -o - %s | FileCheck %s
-;
-; This test shows that ubsantrap can, in the absence of nomerge, be merged by
-; the backend into a single ud1 instruction (thus making debugging difficult).
-;
-; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c with
-; 'nomerge' manually removed from ubsantraps.
-;
-; ModuleID = '../clang/test/CodeGen/ubsan-trap-merge.c'
-source_filename = "../clang/test/CodeGen/ubsan-trap-merge.c"
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
-; Function Attrs: nounwind uwtable
-define dso_local range(i32 -2147483523, -2147483648) i32 @f(i32 noundef %x) local_unnamed_addr #0 {
-; CHECK-LABEL: f:
-; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: addl $125, %edi
-; CHECK-NEXT: jo .LBB0_1
-; CHECK-NEXT: # %bb.2: # %cont
-; CHECK-NEXT: movl %edi, %eax
-; CHECK-NEXT: retq
-; CHECK-NEXT: .LBB0_1: # %trap
-; CHECK-NEXT: ud1l (%eax), %eax
-entry:
- %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
- %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
- br i1 %1, label %trap, label %cont, !nosanitize !5
-
-trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-cont: ; preds = %entry
- %2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
- ret i32 %2
-}
-
-; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none)
-declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1
-
-; Function Attrs: cold noreturn nounwind
-declare void @llvm.ubsantrap(i8 immarg) #2
-
-; Function Attrs: nounwind uwtable
-define dso_local range(i32 -2147483521, -2147483648) i32 @g(i32 noundef %x) local_unnamed_addr #0 {
-; CHECK-LABEL: g:
-; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: addl $127, %edi
-; CHECK-NEXT: jo .LBB1_1
-; CHECK-NEXT: # %bb.2: # %cont
-; CHECK-NEXT: movl %edi, %eax
-; CHECK-NEXT: retq
-; CHECK-NEXT: .LBB1_1: # %trap
-; CHECK-NEXT: ud1l (%eax), %eax
-entry:
- %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
- %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
- br i1 %1, label %trap, label %cont, !nosanitize !5
-
-trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-cont: ; preds = %entry
- %2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
- ret i32 %2
-}
-
-; Function Attrs: nounwind uwtable
-define dso_local range(i32 -2147483521, -2147483648) i32 @h(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
-; CHECK-LABEL: h:
-; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: addl $127, %edi
-; CHECK-NEXT: jo .LBB2_3
-; CHECK-NEXT: # %bb.1: # %cont
-; CHECK-NEXT: addl $129, %esi
-; CHECK-NEXT: jo .LBB2_3
-; CHECK-NEXT: # %bb.2: # %cont2
-; CHECK-NEXT: cmpl %esi, %edi
-; CHECK-NEXT: cmovll %edi, %esi
-; CHECK-NEXT: movl %esi, %eax
-; CHECK-NEXT: retq
-; CHECK-NEXT: .LBB2_3: # %trap
-; CHECK-NEXT: ud1l (%eax), %eax
-entry:
- %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
- %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
- br i1 %1, label %trap, label %cont, !nosanitize !5
-
-trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-cont: ; preds = %entry
- %2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 129), !nosanitize !5
- %3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
- br i1 %3, label %trap1, label %cont2, !nosanitize !5
-
-trap1: ; preds = %cont
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-cont2: ; preds = %cont
- %4 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
- %5 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
- %cond = tail call i32 @llvm.smin.i32(i32 %5, i32 %4)
- ret i32 %cond
-}
-
-; Function Attrs: nounwind uwtable
-define dso_local noundef i32 @m(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
-; CHECK-LABEL: m:
-; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: addl $125, %edi
-; CHECK-NEXT: jo .LBB3_4
-; CHECK-NEXT: # %bb.1: # %f.exit
-; CHECK-NEXT: addl $127, %esi
-; CHECK-NEXT: jo .LBB3_4
-; CHECK-NEXT: # %bb.2: # %g.exit
-; CHECK-NEXT: addl %esi, %edi
-; CHECK-NEXT: jo .LBB3_4
-; CHECK-NEXT: # %bb.3: # %cont
-; CHECK-NEXT: movl %edi, %eax
-; CHECK-NEXT: retq
-; CHECK-NEXT: .LBB3_4: # %trap.i
-; CHECK-NEXT: ud1l (%eax), %eax
-entry:
- %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
- %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
- br i1 %1, label %trap.i, label %f.exit, !nosanitize !5
-
-trap.i: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-f.exit: ; preds = %entry
- %2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 127), !nosanitize !5
- %3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
- br i1 %3, label %trap.i2, label %g.exit, !nosanitize !5
-
-trap.i2: ; preds = %f.exit
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-g.exit: ; preds = %f.exit
- %4 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
- %5 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
- %6 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %4, i32 %5), !nosanitize !5
- %7 = extractvalue { i32, i1 } %6, 1, !nosanitize !5
- br i1 %7, label %trap, label %cont, !nosanitize !5
-
-trap: ; preds = %g.exit
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-cont: ; preds = %g.exit
- %8 = extractvalue { i32, i1 } %6, 0, !nosanitize !5
- ret i32 %8
-}
-
-; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
-declare i32 @llvm.smin.i32(i32, i32) #3
-
-attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-attributes #2 = { cold noreturn nounwind }
-attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-attributes #4 = { noreturn nounwind }
-
-!llvm.module.flags = !{!0, !1, !2, !3}
-!llvm.ident = !{!4}
-
-!0 = !{i32 1, !"wchar_size", i32 4}
-!1 = !{i32 8, !"PIC Level", i32 2}
-!2 = !{i32 7, !"PIE Level", i32 2}
-!3 = !{i32 7, !"uwtable", i32 2}
-!4 = !{!"clang version 20.0.0git (https://github.com/thurstond/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
-!5 = !{}
diff --git a/llvm/test/MC/X86/ubsan-trap-nomerge.ll b/llvm/test/MC/X86/ubsan-trap-nomerge.ll
deleted file mode 100644
index 0bbb36cf63bf68..00000000000000
--- a/llvm/test/MC/X86/ubsan-trap-nomerge.ll
+++ /dev/null
@@ -1,185 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
-; RUN: llc -O3 -mtriple x86_64 -filetype asm -o - %s | FileCheck %s
-;
-; This tests that the nomerge attribute for ubsantrap works correctly i.e.,
-; they are lowered to separate ud1 instructions.
-;
-; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c.
-;
-; ModuleID = '../clang/test/CodeGen/ubsan-trap-merge.c'
-source_filename = "../clang/test/CodeGen/ubsan-trap-merge.c"
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
-; Function Attrs: nounwind uwtable
-define dso_local range(i32 -2147483523, -2147483648) i32 @f(i32 noundef %x) local_unnamed_addr #0 {
-; CHECK-LABEL: f:
-; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: addl $125, %edi
-; CHECK-NEXT: jo .LBB0_1
-; CHECK-NEXT: # %bb.2: # %cont
-; CHECK-NEXT: movl %edi, %eax
-; CHECK-NEXT: retq
-; CHECK-NEXT: .LBB0_1: # %trap
-; CHECK-NEXT: ud1l (%eax), %eax
-entry:
- %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
- %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
- br i1 %1, label %trap, label %cont, !nosanitize !5
-
-trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-cont: ; preds = %entry
- %2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
- ret i32 %2
-}
-
-; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none)
-declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1
-
-; Function Attrs: cold noreturn nounwind
-declare void @llvm.ubsantrap(i8 immarg) #2
-
-; Function Attrs: nounwind uwtable
-define dso_local range(i32 -2147483521, -2147483648) i32 @g(i32 noundef %x) local_unnamed_addr #0 {
-; CHECK-LABEL: g:
-; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: addl $127, %edi
-; CHECK-NEXT: jo .LBB1_1
-; CHECK-NEXT: # %bb.2: # %cont
-; CHECK-NEXT: movl %edi, %eax
-; CHECK-NEXT: retq
-; CHECK-NEXT: .LBB1_1: # %trap
-; CHECK-NEXT: ud1l (%eax), %eax
-entry:
- %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
- %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
- br i1 %1, label %trap, label %cont, !nosanitize !5
-
-trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-cont: ; preds = %entry
- %2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
- ret i32 %2
-}
-
-; Function Attrs: nounwind uwtable
-define dso_local range(i32 -2147483521, -2147483648) i32 @h(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
-; CHECK-LABEL: h:
-; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: addl $127, %edi
-; CHECK-NEXT: jo .LBB2_3
-; CHECK-NEXT: # %bb.1: # %cont
-; CHECK-NEXT: addl $129, %esi
-; CHECK-NEXT: jo .LBB2_4
-; CHECK-NEXT: # %bb.2: # %cont2
-; CHECK-NEXT: cmpl %esi, %edi
-; CHECK-NEXT: cmovll %edi, %esi
-; CHECK-NEXT: movl %esi, %eax
-; CHECK-NEXT: retq
-; CHECK-NEXT: .LBB2_3: # %trap
-; CHECK-NEXT: ud1l (%eax), %eax
-; CHECK-NEXT: .LBB2_4: # %trap1
-; CHECK-NEXT: ud1l (%eax), %eax
-entry:
- %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
- %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
- br i1 %1, label %trap, label %cont, !nosanitize !5
-
-trap: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-cont: ; preds = %entry
- %2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 129), !nosanitize !5
- %3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
- br i1 %3, label %trap1, label %cont2, !nosanitize !5
-
-trap1: ; preds = %cont
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-cont2: ; preds = %cont
- %4 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
- %5 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
- %cond = tail call i32 @llvm.smin.i32(i32 %5, i32 %4)
- ret i32 %cond
-}
-
-; Function Attrs: nounwind uwtable
-define dso_local noundef i32 @m(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
-; CHECK-LABEL: m:
-; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: addl $125, %edi
-; CHECK-NEXT: jo .LBB3_4
-; CHECK-NEXT: # %bb.1: # %f.exit
-; CHECK-NEXT: addl $127, %esi
-; CHECK-NEXT: jo .LBB3_5
-; CHECK-NEXT: # %bb.2: # %g.exit
-; CHECK-NEXT: addl %esi, %edi
-; CHECK-NEXT: jo .LBB3_6
-; CHECK-NEXT: # %bb.3: # %cont
-; CHECK-NEXT: movl %edi, %eax
-; CHECK-NEXT: retq
-; CHECK-NEXT: .LBB3_4: # %trap.i
-; CHECK-NEXT: ud1l (%eax), %eax
-; CHECK-NEXT: .LBB3_5: # %trap.i2
-; CHECK-NEXT: ud1l (%eax), %eax
-; CHECK-NEXT: .LBB3_6: # %trap
-; CHECK-NEXT: ud1l (%eax), %eax
-entry:
- %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
- %1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
- br i1 %1, label %trap.i, label %f.exit, !nosanitize !5
-
-trap.i: ; preds = %entry
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-f.exit: ; preds = %entry
- %2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 127), !nosanitize !5
- %3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
- br i1 %3, label %trap.i2, label %g.exit, !nosanitize !5
-
-trap.i2: ; preds = %f.exit
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-g.exit: ; preds = %f.exit
- %4 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
- %5 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
- %6 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %4, i32 %5), !nosanitize !5
- %7 = extractvalue { i32, i1 } %6, 1, !nosanitize !5
- br i1 %7, label %trap, label %cont, !nosanitize !5
-
-trap: ; preds = %g.exit
- tail call void @llvm.ubsantrap(i8 0) #4, !nosanitize !5
- unreachable, !nosanitize !5
-
-cont: ; preds = %g.exit
- %8 = extractvalue { i32, i1 } %6, 0, !nosanitize !5
- ret i32 %8
-}
-
-; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
-declare i32 @llvm.smin.i32(i32, i32) #3
-
-attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-attributes #2 = { cold noreturn nounwind }
-attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-attributes #4 = { nomerge noreturn nounwind }
-
-!llvm.module.flags = !{!0, !1, !2, !3}
-!llvm.ident = !{!4}
-
-!0 = !{i32 1, !"wchar_size", i32 4}
-!1 = !{i32 8, !"PIC Level", i32 2}
-!2 = !{i32 7, !"PIE Level", i32 2}
-!3 = !{i32 7, !"uwtable", i32 2}
-!4 = !{!"clang version 20.0.0git (https://github.com/thurstond/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
-!5 = !{}
>From a2dd9c5d9a044fd6cd95fca88a7f3a55c3b1b9fd Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 19:06:37 +0000
Subject: [PATCH 07/14] Update catch-undef-behavior.c
---
clang/test/CodeGen/catch-undef-behavior.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/CodeGen/catch-undef-behavior.c b/clang/test/CodeGen/catch-undef-behavior.c
index af37ef9e8565b1..7580290b0b0333 100644
--- a/clang/test/CodeGen/catch-undef-behavior.c
+++ b/clang/test/CodeGen/catch-undef-behavior.c
@@ -470,4 +470,4 @@ void call_nonnull_variadic(int a, int *b) {
// CHECK-UBSAN: ![[WEIGHT_MD]] = !{!"branch_weights", i32 1048575, i32 1}
-// CHECK-TRAP: attributes [[NR_NUW]] = { noreturn nounwind }
+// CHECK-TRAP: attributes [[NR_NUW]] = { nomerge noreturn nounwind }
>From 02351fe811bb77a43c5f235ebc405b3deeaf0ccb Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 19:24:19 +0000
Subject: [PATCH 08/14] Remove duplicate header comment
---
clang/test/CodeGen/ubsan-trap-merge.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/test/CodeGen/ubsan-trap-merge.c b/clang/test/CodeGen/ubsan-trap-merge.c
index b5b18afb2fc9de..ef32605c73174a 100644
--- a/clang/test/CodeGen/ubsan-trap-merge.c
+++ b/clang/test/CodeGen/ubsan-trap-merge.c
@@ -1,4 +1,3 @@
-// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// NOTE: Assertions have mostly been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// The most important assertion is the attributes at the end of the file, which
// shows that ubsan attaches 'nomerge' to each ubsantrap intrinsic.
>From ba071bc15f76c5c8d77bc16608ee7d48d6d8f365 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 21:07:48 +0000
Subject: [PATCH 09/14] Don't apply nomerge for the first instance of each
TrapBB type, per Vitaly's feedback
---
clang/lib/CodeGen/CGExpr.cpp | 4 +++-
clang/test/CodeGen/ubsan-trap-merge.c | 5 +++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 74e185c30c0878..5b669a980ec3e7 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3915,6 +3915,7 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
Builder.getCurrentDebugLocation());
Builder.CreateCondBr(Checked, Cont, TrapBB);
} else {
+ bool NewTrapBB = (TrapBB == nullptr);
TrapBB = createBasicBlock("trap");
Builder.CreateCondBr(Checked, Cont, TrapBB);
EmitBlock(TrapBB);
@@ -3928,7 +3929,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
CGM.getCodeGenOpts().TrapFuncName);
TrapCall->addFnAttr(A);
}
- TrapCall->addFnAttr(llvm::Attribute::NoMerge);
+ if (!NewTrapBB)
+ TrapCall->addFnAttr(llvm::Attribute::NoMerge);
TrapCall->setDoesNotReturn();
TrapCall->setDoesNotThrow();
Builder.CreateUnreachable();
diff --git a/clang/test/CodeGen/ubsan-trap-merge.c b/clang/test/CodeGen/ubsan-trap-merge.c
index ef32605c73174a..c8669b9dd3a032 100644
--- a/clang/test/CodeGen/ubsan-trap-merge.c
+++ b/clang/test/CodeGen/ubsan-trap-merge.c
@@ -55,7 +55,7 @@ int g(int x) {
// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]]
// CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP1:.*]], label %[[CONT2:.*]], !nosanitize [[META2]]
// CHECK: [[TRAP1]]:
-// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]]
+// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR5:[0-9]+]], !nosanitize [[META2]]
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
// CHECK: [[CONT2]]:
// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]]
@@ -102,4 +102,5 @@ int m(int x, int y) {
return f(x) + g(y);
}
//.
-// CHECK: attributes #[[ATTR4]] = { nomerge noreturn nounwind }
+// CHECK: attributes #[[ATTR4]] = { noreturn nounwind }
+// CHECK: attributes #[[ATTR5]] = { nomerge noreturn nounwind }
>From 4fbca626de43ab5bc3ec82d56ac854032f34a2cf Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 21:09:57 +0000
Subject: [PATCH 10/14] clang-format
---
clang/lib/CodeGen/CGExpr.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 5b669a980ec3e7..59b7180091b3d5 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3930,7 +3930,7 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
TrapCall->addFnAttr(A);
}
if (!NewTrapBB)
- TrapCall->addFnAttr(llvm::Attribute::NoMerge);
+ TrapCall->addFnAttr(llvm::Attribute::NoMerge);
TrapCall->setDoesNotReturn();
TrapCall->setDoesNotThrow();
Builder.CreateUnreachable();
>From c7fb7d5064cc42ec3ca65fd84cabad5b3fafb9cf Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 21:46:15 +0000
Subject: [PATCH 11/14] Revert "clang-format"
This reverts commit aafe571a82e1f97acf1a3505eddaea8e63db1dfa.
---
clang/lib/CodeGen/CGExpr.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 59b7180091b3d5..5b669a980ec3e7 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3930,7 +3930,7 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
TrapCall->addFnAttr(A);
}
if (!NewTrapBB)
- TrapCall->addFnAttr(llvm::Attribute::NoMerge);
+ TrapCall->addFnAttr(llvm::Attribute::NoMerge);
TrapCall->setDoesNotReturn();
TrapCall->setDoesNotThrow();
Builder.CreateUnreachable();
>From e49834b47848ed0b453ab56a32d6f226070a9936 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 21:46:25 +0000
Subject: [PATCH 12/14] Revert "Don't apply nomerge for the first instance of
each TrapBB type, per"
This reverts commit 5107ce194c9b03c2f32eb1508df0c92b13b3e2fd.
Doesn't work because CodeGen happens before inlining, so the ubsantraps in functions f(), g() and m() will not have nomerge.
---
clang/lib/CodeGen/CGExpr.cpp | 4 +---
clang/test/CodeGen/ubsan-trap-merge.c | 5 ++---
2 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 5b669a980ec3e7..74e185c30c0878 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3915,7 +3915,6 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
Builder.getCurrentDebugLocation());
Builder.CreateCondBr(Checked, Cont, TrapBB);
} else {
- bool NewTrapBB = (TrapBB == nullptr);
TrapBB = createBasicBlock("trap");
Builder.CreateCondBr(Checked, Cont, TrapBB);
EmitBlock(TrapBB);
@@ -3929,8 +3928,7 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
CGM.getCodeGenOpts().TrapFuncName);
TrapCall->addFnAttr(A);
}
- if (!NewTrapBB)
- TrapCall->addFnAttr(llvm::Attribute::NoMerge);
+ TrapCall->addFnAttr(llvm::Attribute::NoMerge);
TrapCall->setDoesNotReturn();
TrapCall->setDoesNotThrow();
Builder.CreateUnreachable();
diff --git a/clang/test/CodeGen/ubsan-trap-merge.c b/clang/test/CodeGen/ubsan-trap-merge.c
index c8669b9dd3a032..ef32605c73174a 100644
--- a/clang/test/CodeGen/ubsan-trap-merge.c
+++ b/clang/test/CodeGen/ubsan-trap-merge.c
@@ -55,7 +55,7 @@ int g(int x) {
// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !nosanitize [[META2]]
// CHECK-NEXT: br i1 [[TMP3]], label %[[TRAP1:.*]], label %[[CONT2:.*]], !nosanitize [[META2]]
// CHECK: [[TRAP1]]:
-// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR5:[0-9]+]], !nosanitize [[META2]]
+// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 0) #[[ATTR4]], !nosanitize [[META2]]
// CHECK-NEXT: unreachable, !nosanitize [[META2]]
// CHECK: [[CONT2]]:
// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !nosanitize [[META2]]
@@ -102,5 +102,4 @@ int m(int x, int y) {
return f(x) + g(y);
}
//.
-// CHECK: attributes #[[ATTR4]] = { noreturn nounwind }
-// CHECK: attributes #[[ATTR5]] = { nomerge noreturn nounwind }
+// CHECK: attributes #[[ATTR4]] = { nomerge noreturn nounwind }
>From 7fec45e37190e6ab0ead35b57165bba197bcd253 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 21:54:26 +0000
Subject: [PATCH 13/14] Add comment why we unconditionally add nomerge
---
clang/lib/CodeGen/CGExpr.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 74e185c30c0878..259cd2f6bee12c 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3928,6 +3928,9 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
CGM.getCodeGenOpts().TrapFuncName);
TrapCall->addFnAttr(A);
}
+ // We unconditionally add NoMerge, even if this is the first time we've
+ // seen this type of trap in this function. This is necessary because
+ // inlining may occur in later stages.
TrapCall->addFnAttr(llvm::Attribute::NoMerge);
TrapCall->setDoesNotReturn();
TrapCall->setDoesNotThrow();
>From ee1c29918dcf80339e6fc1bd97152781c56680fc Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 22:54:30 +0000
Subject: [PATCH 14/14] Use NoMerge condition per Vitaly's feedback
---
clang/lib/CodeGen/CGExpr.cpp | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 259cd2f6bee12c..229f0e29f02341 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3905,9 +3905,11 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];
- if (!ClSanitizeDebugDeoptimization &&
- CGM.getCodeGenOpts().OptimizationLevel && TrapBB &&
- (!CurCodeDecl || !CurCodeDecl->hasAttr<OptimizeNoneAttr>())) {
+ bool NoMerge = ClSanitizeDebugDeoptimization ||
+ !CGM.getCodeGenOpts().OptimizationLevel ||
+ (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
+
+ if (TrapBB && !NoMerge) {
auto Call = TrapBB->begin();
assert(isa<llvm::CallInst>(Call) && "Expected call in trap BB");
@@ -3928,10 +3930,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
CGM.getCodeGenOpts().TrapFuncName);
TrapCall->addFnAttr(A);
}
- // We unconditionally add NoMerge, even if this is the first time we've
- // seen this type of trap in this function. This is necessary because
- // inlining may occur in later stages.
- TrapCall->addFnAttr(llvm::Attribute::NoMerge);
+ if (NoMerge)
+ TrapCall->addFnAttr(llvm::Attribute::NoMerge);
TrapCall->setDoesNotReturn();
TrapCall->setDoesNotThrow();
Builder.CreateUnreachable();
More information about the cfe-commits
mailing list