Skip to content

Commit dde7f4d

Browse files
authored
[NFC][clang] Add ubsan-trap-merge.ll test to show absence of nomerge considered harmful (llvm#117657)
These testcases demonstrate that ubsan intrinsics are merged in the backend iff nomerge is missing from ubsantrap intrinsics. This is based on the observation and testcase by Vitaly Buka in llvm#83470.
1 parent 1b68b33 commit dde7f4d

File tree

2 files changed

+367
-0
lines changed

2 files changed

+367
-0
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc -O3 -mtriple x86_64 -filetype asm -o - %s | FileCheck %s
3+
;
4+
; This test shows that ubsantrap can, in the absence of nomerge, be merged by
5+
; the backend into a single ud1 instruction (thus making debugging difficult).
6+
;
7+
; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c.
8+
;
9+
; ModuleID = '../clang/test/CodeGen/ubsan-trap-merge.c'
10+
source_filename = "../clang/test/CodeGen/ubsan-trap-merge.c"
11+
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"
12+
target triple = "x86_64-unknown-linux-gnu"
13+
14+
; Function Attrs: nounwind uwtable
15+
define dso_local range(i32 -2147483523, -2147483648) i32 @f(i32 noundef %x) local_unnamed_addr #0 {
16+
; CHECK-LABEL: f:
17+
; CHECK: # %bb.0: # %entry
18+
; CHECK-NEXT: addl $125, %edi
19+
; CHECK-NEXT: jo .LBB0_1
20+
; CHECK-NEXT: # %bb.2: # %cont
21+
; CHECK-NEXT: movl %edi, %eax
22+
; CHECK-NEXT: retq
23+
; CHECK-NEXT: .LBB0_1: # %trap
24+
; CHECK-NEXT: ud1l 2(%eax), %eax
25+
entry:
26+
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
27+
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
28+
br i1 %1, label %trap, label %cont, !nosanitize !5
29+
30+
trap: ; preds = %entry
31+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
32+
unreachable, !nosanitize !5
33+
34+
cont: ; preds = %entry
35+
%2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
36+
ret i32 %2
37+
}
38+
39+
; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none)
40+
declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1
41+
42+
; Function Attrs: cold noreturn nounwind
43+
declare void @llvm.ubsantrap(i8 immarg) #2
44+
45+
; Function Attrs: nounwind uwtable
46+
define dso_local range(i32 -2147483521, -2147483648) i32 @g(i32 noundef %x) local_unnamed_addr #0 {
47+
; CHECK-LABEL: g:
48+
; CHECK: # %bb.0: # %entry
49+
; CHECK-NEXT: addl $127, %edi
50+
; CHECK-NEXT: jo .LBB1_1
51+
; CHECK-NEXT: # %bb.2: # %cont
52+
; CHECK-NEXT: movl %edi, %eax
53+
; CHECK-NEXT: retq
54+
; CHECK-NEXT: .LBB1_1: # %trap
55+
; CHECK-NEXT: ud1l 2(%eax), %eax
56+
entry:
57+
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
58+
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
59+
br i1 %1, label %trap, label %cont, !nosanitize !5
60+
61+
trap: ; preds = %entry
62+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
63+
unreachable, !nosanitize !5
64+
65+
cont: ; preds = %entry
66+
%2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
67+
ret i32 %2
68+
}
69+
70+
; Function Attrs: nounwind uwtable
71+
define dso_local range(i32 -2147483521, -2147483648) i32 @h(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
72+
; CHECK-LABEL: h:
73+
; CHECK: # %bb.0: # %entry
74+
; CHECK-NEXT: addl $127, %edi
75+
; CHECK-NEXT: jo .LBB2_3
76+
; CHECK-NEXT: # %bb.1: # %cont
77+
; CHECK-NEXT: addl $129, %esi
78+
; CHECK-NEXT: jo .LBB2_4
79+
; CHECK-NEXT: # %bb.2: # %cont2
80+
; CHECK-NEXT: cmpl %esi, %edi
81+
; CHECK-NEXT: cmovll %edi, %esi
82+
; CHECK-NEXT: movl %esi, %eax
83+
; CHECK-NEXT: retq
84+
; CHECK-NEXT: .LBB2_3: # %trap
85+
; CHECK-NEXT: ud1l 2(%eax), %eax
86+
; CHECK-NEXT: .LBB2_4: # %trap1
87+
; CHECK-NEXT: ud1l 4(%eax), %eax
88+
entry:
89+
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
90+
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
91+
br i1 %1, label %trap, label %cont, !nosanitize !5
92+
93+
trap: ; preds = %entry
94+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
95+
unreachable, !nosanitize !5
96+
97+
cont: ; preds = %entry
98+
%2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 129), !nosanitize !5
99+
%3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
100+
br i1 %3, label %trap1, label %cont2, !nosanitize !5
101+
102+
trap1: ; preds = %cont
103+
tail call void @llvm.ubsantrap(i8 4) #4, !nosanitize !5
104+
unreachable, !nosanitize !5
105+
106+
cont2: ; preds = %cont
107+
%4 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
108+
%5 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
109+
%cond = tail call i32 @llvm.smin.i32(i32 %5, i32 %4)
110+
ret i32 %cond
111+
}
112+
113+
; Function Attrs: nounwind uwtable
114+
define dso_local noundef i32 @m(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
115+
; CHECK-LABEL: m:
116+
; CHECK: # %bb.0: # %entry
117+
; CHECK-NEXT: addl $125, %edi
118+
; CHECK-NEXT: jo .LBB3_4
119+
; CHECK-NEXT: # %bb.1: # %f.exit
120+
; CHECK-NEXT: addl $127, %esi
121+
; CHECK-NEXT: jo .LBB3_4
122+
; CHECK-NEXT: # %bb.2: # %g.exit
123+
; CHECK-NEXT: addl %esi, %edi
124+
; CHECK-NEXT: jo .LBB3_4
125+
; CHECK-NEXT: # %bb.3: # %cont
126+
; CHECK-NEXT: movl %edi, %eax
127+
; CHECK-NEXT: retq
128+
; CHECK-NEXT: .LBB3_4: # %trap.i
129+
; CHECK-NEXT: ud1l 2(%eax), %eax
130+
entry:
131+
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
132+
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
133+
br i1 %1, label %trap.i, label %f.exit, !nosanitize !5
134+
135+
trap.i: ; preds = %entry
136+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
137+
unreachable, !nosanitize !5
138+
139+
f.exit: ; preds = %entry
140+
%2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 127), !nosanitize !5
141+
%3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
142+
br i1 %3, label %trap.i2, label %g.exit, !nosanitize !5
143+
144+
trap.i2: ; preds = %f.exit
145+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
146+
unreachable, !nosanitize !5
147+
148+
g.exit: ; preds = %f.exit
149+
%4 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
150+
%5 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
151+
%6 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %4, i32 %5), !nosanitize !5
152+
%7 = extractvalue { i32, i1 } %6, 1, !nosanitize !5
153+
br i1 %7, label %trap, label %cont, !nosanitize !5
154+
155+
trap: ; preds = %g.exit
156+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
157+
unreachable, !nosanitize !5
158+
159+
cont: ; preds = %g.exit
160+
%8 = extractvalue { i32, i1 } %6, 0, !nosanitize !5
161+
ret i32 %8
162+
}
163+
164+
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
165+
declare i32 @llvm.smin.i32(i32, i32) #3
166+
167+
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" }
168+
attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) }
169+
attributes #2 = { cold noreturn nounwind }
170+
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
171+
attributes #4 = { noreturn nounwind }
172+
173+
!llvm.module.flags = !{!0, !1, !2, !3}
174+
!llvm.ident = !{!4}
175+
176+
!0 = !{i32 1, !"wchar_size", i32 4}
177+
!1 = !{i32 8, !"PIC Level", i32 2}
178+
!2 = !{i32 7, !"PIE Level", i32 2}
179+
!3 = !{i32 7, !"uwtable", i32 2}
180+
!4 = !{!"clang version 20.0.0git (https://github.com/llvm/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
181+
!5 = !{}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc -O3 -mtriple x86_64 -filetype asm -o - %s | FileCheck %s
3+
;
4+
; This tests that the nomerge attribute for ubsantrap works correctly i.e.,
5+
; they are lowered to separate ud1 instructions.
6+
;
7+
; The LLVM IR was generated from clang/test/CodeGen/ubsan-trap-merge.c with
8+
; 'nomerge' manually added to ubsantraps.
9+
;
10+
; ModuleID = '../clang/test/CodeGen/ubsan-trap-merge.c'
11+
source_filename = "../clang/test/CodeGen/ubsan-trap-merge.c"
12+
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"
13+
target triple = "x86_64-unknown-linux-gnu"
14+
15+
; Function Attrs: nounwind uwtable
16+
define dso_local range(i32 -2147483523, -2147483648) i32 @f(i32 noundef %x) local_unnamed_addr #0 {
17+
; CHECK-LABEL: f:
18+
; CHECK: # %bb.0: # %entry
19+
; CHECK-NEXT: addl $125, %edi
20+
; CHECK-NEXT: jo .LBB0_1
21+
; CHECK-NEXT: # %bb.2: # %cont
22+
; CHECK-NEXT: movl %edi, %eax
23+
; CHECK-NEXT: retq
24+
; CHECK-NEXT: .LBB0_1: # %trap
25+
; CHECK-NEXT: ud1l 2(%eax), %eax
26+
entry:
27+
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
28+
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
29+
br i1 %1, label %trap, label %cont, !nosanitize !5
30+
31+
trap: ; preds = %entry
32+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
33+
unreachable, !nosanitize !5
34+
35+
cont: ; preds = %entry
36+
%2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
37+
ret i32 %2
38+
}
39+
40+
; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none)
41+
declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1
42+
43+
; Function Attrs: cold noreturn nounwind
44+
declare void @llvm.ubsantrap(i8 immarg) #2
45+
46+
; Function Attrs: nounwind uwtable
47+
define dso_local range(i32 -2147483521, -2147483648) i32 @g(i32 noundef %x) local_unnamed_addr #0 {
48+
; CHECK-LABEL: g:
49+
; CHECK: # %bb.0: # %entry
50+
; CHECK-NEXT: addl $127, %edi
51+
; CHECK-NEXT: jo .LBB1_1
52+
; CHECK-NEXT: # %bb.2: # %cont
53+
; CHECK-NEXT: movl %edi, %eax
54+
; CHECK-NEXT: retq
55+
; CHECK-NEXT: .LBB1_1: # %trap
56+
; CHECK-NEXT: ud1l 2(%eax), %eax
57+
entry:
58+
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
59+
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
60+
br i1 %1, label %trap, label %cont, !nosanitize !5
61+
62+
trap: ; preds = %entry
63+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
64+
unreachable, !nosanitize !5
65+
66+
cont: ; preds = %entry
67+
%2 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
68+
ret i32 %2
69+
}
70+
71+
; Function Attrs: nounwind uwtable
72+
define dso_local range(i32 -2147483521, -2147483648) i32 @h(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
73+
; CHECK-LABEL: h:
74+
; CHECK: # %bb.0: # %entry
75+
; CHECK-NEXT: addl $127, %edi
76+
; CHECK-NEXT: jo .LBB2_3
77+
; CHECK-NEXT: # %bb.1: # %cont
78+
; CHECK-NEXT: addl $129, %esi
79+
; CHECK-NEXT: jo .LBB2_4
80+
; CHECK-NEXT: # %bb.2: # %cont2
81+
; CHECK-NEXT: cmpl %esi, %edi
82+
; CHECK-NEXT: cmovll %edi, %esi
83+
; CHECK-NEXT: movl %esi, %eax
84+
; CHECK-NEXT: retq
85+
; CHECK-NEXT: .LBB2_3: # %trap
86+
; CHECK-NEXT: ud1l 2(%eax), %eax
87+
; CHECK-NEXT: .LBB2_4: # %trap1
88+
; CHECK-NEXT: ud1l 4(%eax), %eax
89+
entry:
90+
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 127), !nosanitize !5
91+
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
92+
br i1 %1, label %trap, label %cont, !nosanitize !5
93+
94+
trap: ; preds = %entry
95+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
96+
unreachable, !nosanitize !5
97+
98+
cont: ; preds = %entry
99+
%2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 129), !nosanitize !5
100+
%3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
101+
br i1 %3, label %trap1, label %cont2, !nosanitize !5
102+
103+
trap1: ; preds = %cont
104+
tail call void @llvm.ubsantrap(i8 4) #4, !nosanitize !5
105+
unreachable, !nosanitize !5
106+
107+
cont2: ; preds = %cont
108+
%4 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
109+
%5 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
110+
%cond = tail call i32 @llvm.smin.i32(i32 %5, i32 %4)
111+
ret i32 %cond
112+
}
113+
114+
; Function Attrs: nounwind uwtable
115+
define dso_local noundef i32 @m(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
116+
; CHECK-LABEL: m:
117+
; CHECK: # %bb.0: # %entry
118+
; CHECK-NEXT: addl $125, %edi
119+
; CHECK-NEXT: jo .LBB3_4
120+
; CHECK-NEXT: # %bb.1: # %f.exit
121+
; CHECK-NEXT: addl $127, %esi
122+
; CHECK-NEXT: jo .LBB3_5
123+
; CHECK-NEXT: # %bb.2: # %g.exit
124+
; CHECK-NEXT: addl %esi, %edi
125+
; CHECK-NEXT: jo .LBB3_6
126+
; CHECK-NEXT: # %bb.3: # %cont
127+
; CHECK-NEXT: movl %edi, %eax
128+
; CHECK-NEXT: retq
129+
; CHECK-NEXT: .LBB3_4: # %trap.i
130+
; CHECK-NEXT: ud1l 2(%eax), %eax
131+
; CHECK-NEXT: .LBB3_5: # %trap.i2
132+
; CHECK-NEXT: ud1l 2(%eax), %eax
133+
; CHECK-NEXT: .LBB3_6: # %trap
134+
; CHECK-NEXT: ud1l 2(%eax), %eax
135+
entry:
136+
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 125), !nosanitize !5
137+
%1 = extractvalue { i32, i1 } %0, 1, !nosanitize !5
138+
br i1 %1, label %trap.i, label %f.exit, !nosanitize !5
139+
140+
trap.i: ; preds = %entry
141+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
142+
unreachable, !nosanitize !5
143+
144+
f.exit: ; preds = %entry
145+
%2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 127), !nosanitize !5
146+
%3 = extractvalue { i32, i1 } %2, 1, !nosanitize !5
147+
br i1 %3, label %trap.i2, label %g.exit, !nosanitize !5
148+
149+
trap.i2: ; preds = %f.exit
150+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
151+
unreachable, !nosanitize !5
152+
153+
g.exit: ; preds = %f.exit
154+
%4 = extractvalue { i32, i1 } %0, 0, !nosanitize !5
155+
%5 = extractvalue { i32, i1 } %2, 0, !nosanitize !5
156+
%6 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %4, i32 %5), !nosanitize !5
157+
%7 = extractvalue { i32, i1 } %6, 1, !nosanitize !5
158+
br i1 %7, label %trap, label %cont, !nosanitize !5
159+
160+
trap: ; preds = %g.exit
161+
tail call void @llvm.ubsantrap(i8 2) #4, !nosanitize !5
162+
unreachable, !nosanitize !5
163+
164+
cont: ; preds = %g.exit
165+
%8 = extractvalue { i32, i1 } %6, 0, !nosanitize !5
166+
ret i32 %8
167+
}
168+
169+
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
170+
declare i32 @llvm.smin.i32(i32, i32) #3
171+
172+
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" }
173+
attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) }
174+
attributes #2 = { cold noreturn nounwind }
175+
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
176+
attributes #4 = { nomerge noreturn nounwind }
177+
178+
!llvm.module.flags = !{!0, !1, !2, !3}
179+
!llvm.ident = !{!4}
180+
181+
!0 = !{i32 1, !"wchar_size", i32 4}
182+
!1 = !{i32 8, !"PIC Level", i32 2}
183+
!2 = !{i32 7, !"PIE Level", i32 2}
184+
!3 = !{i32 7, !"uwtable", i32 2}
185+
!4 = !{!"clang version 20.0.0git (https://github.com/llvm/llvm-project.git fe3c23b439b9a2d00442d9bc6a4ca86f73066a3d)"}
186+
!5 = !{}

0 commit comments

Comments
 (0)