Skip to content

Commit bb737b0

Browse files
committed
[NFC][clang] Add ubsan-trap-merge.ll test to show absence of nomerge considered harmful
This testcase demonstrates that when nomerge is missing from ubsantrap intrinsics, they may be merged when inlining. This is based on the observation and testcase by Vitaly Buka in llvm#83470
1 parent fe3c23b commit bb737b0

File tree

1 file changed

+181
-0
lines changed

1 file changed

+181
-0
lines changed

llvm/test/MC/X86/ubsan-trap-merge.ll

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 = !{}

0 commit comments

Comments
 (0)