[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 15:14:16 PST 2024
https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/117651
>From e635c76812eb8a6346e8602ec2eb6e4c389fcf6c 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/16] [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 | 18 +++++------
llvm/test/CodeGen/X86/ubsan-trap-merge.ll | 31 ++++++++++---------
llvm/test/CodeGen/X86/ubsan-trap-nomerge.ll | 33 ++++++++++-----------
5 files changed, 44 insertions(+), 48 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 0f50d8c1ff47f2..ef32605c73174a 100644
--- a/clang/test/CodeGen/ubsan-trap-merge.c
+++ b/clang/test/CodeGen/ubsan-trap-merge.c
@@ -1,6 +1,6 @@
// 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
@@ -14,7 +14,7 @@
// 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]]
@@ -31,7 +31,7 @@ int f(int x) {
// 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]]
@@ -48,14 +48,14 @@ int g(int x) {
// 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 8e8d8fd91479a4b3de8762c1b74901e7f0c4d51e 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/16] 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 0536132f1ca4431c2b2e2c4d5e9b505c8d2b26b6 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/16] 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 e1e7db6c6f0762a81dc8266af30009ffbb09f097 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/16] 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 bcf1ba2585f1e70be1e2b268009627db0e23b826 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/16] 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 363ca325870757aa8559e43fb6bfe2b4deb6f38b 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/16] 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 178b0a994d74f38f6e30ff28c71ecac7a554a859 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/16] 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 8c7eb2b274000f47c1d095c6df61c69f04e037d8 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/16] 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 09252c7cc700e1c470e2db8cea7ef91a37cffa6a 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/16] 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 ead3feae1c8c92755ffffcaab05e2cf72228d719 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/16] 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 965068336c411b53ecaaa557f231b656098544fc 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/16] 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 e752957962a38b4c7f3091ebe7304e88cb217610 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/16] 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 2389667b85668d809f5d38925887a12b1075b01d 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/16] 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 0e8a4143ddc7b5c6e9ca7e64729ba5adcb0d92fb 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/16] 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();
>From 7812ff586b37bf36f551ab81ddf3e70807392b86 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 23:08:16 +0000
Subject: [PATCH 15/16] Replace repo name
---
llvm/test/CodeGen/X86/ubsan-trap-merge.ll | 2 +-
llvm/test/CodeGen/X86/ubsan-trap-nomerge.ll | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/CodeGen/X86/ubsan-trap-merge.ll b/llvm/test/CodeGen/X86/ubsan-trap-merge.ll
index 98244fa8157678..878260cbcaec2f 100644
--- a/llvm/test/CodeGen/X86/ubsan-trap-merge.ll
+++ b/llvm/test/CodeGen/X86/ubsan-trap-merge.ll
@@ -176,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/thurstond/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
+!4 = !{!"clang version 20.0.0git (https://github.com/llvm/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 0bbb36cf63bf68..ffcbaac382d56c 100644
--- a/llvm/test/CodeGen/X86/ubsan-trap-nomerge.ll
+++ b/llvm/test/CodeGen/X86/ubsan-trap-nomerge.ll
@@ -181,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/thurstond/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
+!4 = !{!"clang version 20.0.0git (https://github.com/llvm/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
!5 = !{}
>From 8d1de2b35ff166f716cf9c5ff2988c6fa55756bb Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 26 Nov 2024 23:13:52 +0000
Subject: [PATCH 16/16] Clarify test comment
---
clang/test/CodeGen/ubsan-trap-merge.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/CodeGen/ubsan-trap-merge.c b/clang/test/CodeGen/ubsan-trap-merge.c
index ef32605c73174a..dccce0ce4c56b6 100644
--- a/clang/test/CodeGen/ubsan-trap-merge.c
+++ b/clang/test/CodeGen/ubsan-trap-merge.c
@@ -1,6 +1,6 @@
// 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.
+// shows that -ubsan-unique-traps 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
More information about the cfe-commits
mailing list