xref: /llvm-project/llvm/test/Instrumentation/NumericalStabilitySanitizer/basic.ll (revision 38fffa630ee80163dc65e759392ad29798905679)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -passes=nsan -nsan-shadow-type-mapping=dqq -nsan-truncate-fcmp-eq=false -S %s | FileCheck %s --check-prefixes=CHECK,DQQ
3; RUN: opt -passes=nsan -nsan-shadow-type-mapping=dlq -nsan-truncate-fcmp-eq=false -S %s | FileCheck %s --check-prefixes=CHECK,DLQ
4
5target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
6
7declare float @declaration_only(float %a) sanitize_numerical_stability
8
9; Tests with simple control flow.
10
11@float_const = private unnamed_addr constant float 0.5
12@x86_fp80_const = private unnamed_addr constant x86_fp80 0xK3FC9E69594BEC44DE000
13@double_const = private unnamed_addr constant double 0.5
14
15
16define float @return_param_float(float %a) sanitize_numerical_stability {
17; CHECK-LABEL: @return_param_float(
18; CHECK-NEXT:  entry:
19; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
20; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @return_param_float to i64)
21; CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1
22; CHECK-NEXT:    [[TMP3:%.*]] = fpext float [[A:%.*]] to double
23; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]]
24; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
25; CHECK-NEXT:    [[TMP5:%.*]] = call i32 @__nsan_internal_check_float_d(float [[A]], double [[TMP4]], i32 1, i64 0)
26; CHECK-NEXT:    [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 1
27; CHECK-NEXT:    [[TMP7:%.*]] = fpext float [[A]] to double
28; CHECK-NEXT:    [[TMP8:%.*]] = select i1 [[TMP6]], double [[TMP7]], double [[TMP4]]
29; CHECK-NEXT:    store i64 ptrtoint (ptr @return_param_float to i64), ptr @__nsan_shadow_ret_tag, align 8
30; CHECK-NEXT:    store double [[TMP8]], ptr @__nsan_shadow_ret_ptr, align 8
31; CHECK-NEXT:    ret float [[A]]
32;
33entry:
34  ret float %a
35}
36
37; Note that the shadow fadd should not have a `fast` flag.
38define float @param_add_return_float(float %a) sanitize_numerical_stability {
39; CHECK-LABEL: @param_add_return_float(
40; CHECK-NEXT:  entry:
41; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
42; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @param_add_return_float to i64)
43; CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1
44; CHECK-NEXT:    [[TMP3:%.*]] = fpext float [[A:%.*]] to double
45; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]]
46; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
47; CHECK-NEXT:    [[B:%.*]] = fadd fast float [[A]], 1.000000e+00
48; CHECK-NEXT:    [[TMP5:%.*]] = fadd double [[TMP4]], 1.000000e+00
49; CHECK-NEXT:    [[TMP6:%.*]] = call i32 @__nsan_internal_check_float_d(float [[B]], double [[TMP5]], i32 1, i64 0)
50; CHECK-NEXT:    [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1
51; CHECK-NEXT:    [[TMP8:%.*]] = fpext float [[B]] to double
52; CHECK-NEXT:    [[TMP9:%.*]] = select i1 [[TMP7]], double [[TMP8]], double [[TMP5]]
53; CHECK-NEXT:    store i64 ptrtoint (ptr @param_add_return_float to i64), ptr @__nsan_shadow_ret_tag, align 8
54; CHECK-NEXT:    store double [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 8
55; CHECK-NEXT:    ret float [[B]]
56;
57entry:
58  %b = fadd fast float %a, 1.0
59  ret float %b
60}
61
62define x86_fp80 @param_add_return_x86_fp80(x86_fp80 %a) sanitize_numerical_stability {
63; CHECK-LABEL: @param_add_return_x86_fp80(
64; CHECK-NEXT:  entry:
65; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
66; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @param_add_return_x86_fp80 to i64)
67; CHECK-NEXT:    [[TMP2:%.*]] = load fp128, ptr @__nsan_shadow_args_ptr, align 1
68; CHECK-NEXT:    [[TMP3:%.*]] = fpext x86_fp80 [[A:%.*]] to fp128
69; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], fp128 [[TMP2]], fp128 [[TMP3]]
70; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
71; CHECK-NEXT:    [[B:%.*]] = fadd x86_fp80 [[A]], 0xK3FC9E69594BEC44DE000
72; CHECK-NEXT:    [[TMP5:%.*]] = fadd fp128 [[TMP4]], 0xLC0000000000000003FC9CD2B297D889B
73; CHECK-NEXT:    [[TMP6:%.*]] = call i32 @__nsan_internal_check_longdouble_q(x86_fp80 [[B]], fp128 [[TMP5]], i32 1, i64 0)
74; CHECK-NEXT:    [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1
75; CHECK-NEXT:    [[TMP8:%.*]] = fpext x86_fp80 [[B]] to fp128
76; CHECK-NEXT:    [[TMP9:%.*]] = select i1 [[TMP7]], fp128 [[TMP8]], fp128 [[TMP5]]
77; CHECK-NEXT:    store i64 ptrtoint (ptr @param_add_return_x86_fp80 to i64), ptr @__nsan_shadow_ret_tag, align 8
78; CHECK-NEXT:    store fp128 [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 16
79; CHECK-NEXT:    ret x86_fp80 [[B]]
80;
81entry:
82  %b = fadd x86_fp80 %a, 0xK3FC9E69594BEC44DE000
83  ret x86_fp80 %b
84}
85
86define double @param_add_return_double(double %a) sanitize_numerical_stability {
87; DQQ-LABEL: @param_add_return_double(
88; DQQ-NEXT:  entry:
89; DQQ-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
90; DQQ-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @param_add_return_double to i64)
91; DQQ-NEXT:    [[TMP2:%.*]] = load fp128, ptr @__nsan_shadow_args_ptr, align 1
92; DQQ-NEXT:    [[TMP3:%.*]] = fpext double [[A:%.*]] to fp128
93; DQQ-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], fp128 [[TMP2]], fp128 [[TMP3]]
94; DQQ-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
95; DQQ-NEXT:    [[B:%.*]] = fadd double [[A]], 1.000000e+00
96; DQQ-NEXT:    [[TMP5:%.*]] = fadd fp128 [[TMP4]], 0xL00000000000000003FFF000000000000
97; DQQ-NEXT:    [[TMP6:%.*]] = call i32 @__nsan_internal_check_double_q(double [[B]], fp128 [[TMP5]], i32 1, i64 0)
98; DQQ-NEXT:    [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1
99; DQQ-NEXT:    [[TMP8:%.*]] = fpext double [[B]] to fp128
100; DQQ-NEXT:    [[TMP9:%.*]] = select i1 [[TMP7]], fp128 [[TMP8]], fp128 [[TMP5]]
101; DQQ-NEXT:    store i64 ptrtoint (ptr @param_add_return_double to i64), ptr @__nsan_shadow_ret_tag, align 8
102; DQQ-NEXT:    store fp128 [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 16
103; DQQ-NEXT:    ret double [[B]]
104;
105; DLQ-LABEL: @param_add_return_double(
106; DLQ-NEXT:  entry:
107; DLQ-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
108; DLQ-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @param_add_return_double to i64)
109; DLQ-NEXT:    [[TMP2:%.*]] = load x86_fp80, ptr @__nsan_shadow_args_ptr, align 1
110; DLQ-NEXT:    [[TMP3:%.*]] = fpext double [[A:%.*]] to x86_fp80
111; DLQ-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], x86_fp80 [[TMP2]], x86_fp80 [[TMP3]]
112; DLQ-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
113; DLQ-NEXT:    [[B:%.*]] = fadd double [[A]], 1.000000e+00
114; DLQ-NEXT:    [[TMP5:%.*]] = fadd x86_fp80 [[TMP4]], 0xK3FFF8000000000000000
115; DLQ-NEXT:    [[TMP6:%.*]] = call i32 @__nsan_internal_check_double_l(double [[B]], x86_fp80 [[TMP5]], i32 1, i64 0)
116; DLQ-NEXT:    [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1
117; DLQ-NEXT:    [[TMP8:%.*]] = fpext double [[B]] to x86_fp80
118; DLQ-NEXT:    [[TMP9:%.*]] = select i1 [[TMP7]], x86_fp80 [[TMP8]], x86_fp80 [[TMP5]]
119; DLQ-NEXT:    store i64 ptrtoint (ptr @param_add_return_double to i64), ptr @__nsan_shadow_ret_tag, align 8
120; DLQ-NEXT:    store x86_fp80 [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 16
121; DLQ-NEXT:    ret double [[B]]
122;
123entry:
124  %b = fadd double %a, 1.0
125  ret double %b
126}
127
128define <2 x float> @return_param_add_return_float_vector(<2 x float> %a) sanitize_numerical_stability {
129; CHECK-LABEL: @return_param_add_return_float_vector(
130; CHECK-NEXT:  entry:
131; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
132; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @return_param_add_return_float_vector to i64)
133; CHECK-NEXT:    [[TMP2:%.*]] = load <2 x double>, ptr @__nsan_shadow_args_ptr, align 1
134; CHECK-NEXT:    [[TMP3:%.*]] = fpext <2 x float> [[A:%.*]] to <2 x double>
135; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], <2 x double> [[TMP2]], <2 x double> [[TMP3]]
136; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
137; CHECK-NEXT:    [[B:%.*]] = fadd <2 x float> [[A]], splat (float 1.000000e+00)
138; CHECK-NEXT:    [[TMP5:%.*]] = fadd <2 x double> [[TMP4]], splat (double 1.000000e+00)
139; CHECK-NEXT:    [[TMP6:%.*]] = extractelement <2 x float> [[B]], i64 0
140; CHECK-NEXT:    [[TMP7:%.*]] = extractelement <2 x double> [[TMP5]], i64 0
141; CHECK-NEXT:    [[TMP8:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP6]], double [[TMP7]], i32 1, i64 0)
142; CHECK-NEXT:    [[TMP9:%.*]] = extractelement <2 x float> [[B]], i64 1
143; CHECK-NEXT:    [[TMP10:%.*]] = extractelement <2 x double> [[TMP5]], i64 1
144; CHECK-NEXT:    [[TMP11:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP9]], double [[TMP10]], i32 1, i64 0)
145; CHECK-NEXT:    [[TMP12:%.*]] = or i32 [[TMP8]], [[TMP11]]
146; CHECK-NEXT:    [[TMP13:%.*]] = icmp eq i32 [[TMP12]], 1
147; CHECK-NEXT:    [[TMP14:%.*]] = fpext <2 x float> [[B]] to <2 x double>
148; CHECK-NEXT:    [[TMP15:%.*]] = select i1 [[TMP13]], <2 x double> [[TMP14]], <2 x double> [[TMP5]]
149; CHECK-NEXT:    store i64 ptrtoint (ptr @return_param_add_return_float_vector to i64), ptr @__nsan_shadow_ret_tag, align 8
150; CHECK-NEXT:    store <2 x double> [[TMP15]], ptr @__nsan_shadow_ret_ptr, align 16
151; CHECK-NEXT:    ret <2 x float> [[B]]
152;
153entry:
154  %b = fadd <2 x float> %a, <float 1.0, float 1.0>
155  ret <2 x float> %b
156}
157
158; TODO: This is ignored for now.
159define [2 x float] @return_param_float_array([2 x float] %a) sanitize_numerical_stability {
160; CHECK-LABEL: @return_param_float_array(
161; CHECK-NEXT:  entry:
162; CHECK-NEXT:    ret [2 x float] [[A:%.*]]
163;
164entry:
165  ret [2 x float] %a
166}
167
168define void @constantload_add_store_float(ptr %dst) sanitize_numerical_stability {
169; CHECK-LABEL: @constantload_add_store_float(
170; CHECK-NEXT:  entry:
171; CHECK-NEXT:    [[B:%.*]] = load float, ptr @float_const, align 4
172; CHECK-NEXT:    [[TMP0:%.*]] = fpext float [[B]] to double
173; CHECK-NEXT:    [[C:%.*]] = fadd float [[B]], 1.000000e+00
174; CHECK-NEXT:    [[TMP1:%.*]] = fadd double [[TMP0]], 1.000000e+00
175; CHECK-NEXT:    [[TMP2:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[DST:%.*]], i64 1)
176; CHECK-NEXT:    [[TMP3:%.*]] = ptrtoint ptr [[DST]] to i64
177; CHECK-NEXT:    [[TMP4:%.*]] = call i32 @__nsan_internal_check_float_d(float [[C]], double [[TMP1]], i32 4, i64 [[TMP3]])
178; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 1
179; CHECK-NEXT:    [[TMP6:%.*]] = fpext float [[C]] to double
180; CHECK-NEXT:    [[TMP7:%.*]] = select i1 [[TMP5]], double [[TMP6]], double [[TMP1]]
181; CHECK-NEXT:    store double [[TMP7]], ptr [[TMP2]], align 1
182; CHECK-NEXT:    store float [[C]], ptr [[DST]], align 1
183; CHECK-NEXT:    ret void
184;
185entry:
186  %b = load float, ptr @float_const
187  %c = fadd float %b, 1.0
188  store float %c, ptr %dst, align 1
189  ret void
190}
191
192define void @constantload_add_store_x86_fp80(ptr %dst) sanitize_numerical_stability {
193; CHECK-LABEL: @constantload_add_store_x86_fp80(
194; CHECK-NEXT:  entry:
195; CHECK-NEXT:    [[B:%.*]] = load x86_fp80, ptr @x86_fp80_const, align 16
196; CHECK-NEXT:    [[TMP0:%.*]] = fpext x86_fp80 [[B]] to fp128
197; CHECK-NEXT:    [[C:%.*]] = fadd x86_fp80 [[B]], 0xK3FC9E69594BEC44DE000
198; CHECK-NEXT:    [[TMP1:%.*]] = fadd fp128 [[TMP0]], 0xLC0000000000000003FC9CD2B297D889B
199; CHECK-NEXT:    [[TMP2:%.*]] = call ptr @__nsan_get_shadow_ptr_for_longdouble_store(ptr [[DST:%.*]], i64 1)
200; CHECK-NEXT:    [[TMP3:%.*]] = ptrtoint ptr [[DST]] to i64
201; CHECK-NEXT:    [[TMP4:%.*]] = call i32 @__nsan_internal_check_longdouble_q(x86_fp80 [[C]], fp128 [[TMP1]], i32 4, i64 [[TMP3]])
202; CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 1
203; CHECK-NEXT:    [[TMP6:%.*]] = fpext x86_fp80 [[C]] to fp128
204; CHECK-NEXT:    [[TMP7:%.*]] = select i1 [[TMP5]], fp128 [[TMP6]], fp128 [[TMP1]]
205; CHECK-NEXT:    store fp128 [[TMP7]], ptr [[TMP2]], align 1
206; CHECK-NEXT:    store x86_fp80 [[C]], ptr [[DST]], align 1
207; CHECK-NEXT:    ret void
208;
209entry:
210  %b = load x86_fp80, ptr @x86_fp80_const
211  %c = fadd x86_fp80 %b, 0xK3FC9E69594BEC44DE000
212  store x86_fp80 %c, ptr %dst, align 1
213  ret void
214}
215
216define void @constantload_add_store_double(ptr %dst) sanitize_numerical_stability {
217; DQQ-LABEL: @constantload_add_store_double(
218; DQQ-NEXT:  entry:
219; DQQ-NEXT:    [[B:%.*]] = load double, ptr @double_const, align 8
220; DQQ-NEXT:    [[TMP0:%.*]] = fpext double [[B]] to fp128
221; DQQ-NEXT:    [[C:%.*]] = fadd double [[B]], 1.000000e+00
222; DQQ-NEXT:    [[TMP1:%.*]] = fadd fp128 [[TMP0]], 0xL00000000000000003FFF000000000000
223; DQQ-NEXT:    [[TMP2:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_store(ptr [[DST:%.*]], i64 1)
224; DQQ-NEXT:    [[TMP3:%.*]] = ptrtoint ptr [[DST]] to i64
225; DQQ-NEXT:    [[TMP4:%.*]] = call i32 @__nsan_internal_check_double_q(double [[C]], fp128 [[TMP1]], i32 4, i64 [[TMP3]])
226; DQQ-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 1
227; DQQ-NEXT:    [[TMP6:%.*]] = fpext double [[C]] to fp128
228; DQQ-NEXT:    [[TMP7:%.*]] = select i1 [[TMP5]], fp128 [[TMP6]], fp128 [[TMP1]]
229; DQQ-NEXT:    store fp128 [[TMP7]], ptr [[TMP2]], align 1
230; DQQ-NEXT:    store double [[C]], ptr [[DST]], align 1
231; DQQ-NEXT:    ret void
232;
233; DLQ-LABEL: @constantload_add_store_double(
234; DLQ-NEXT:  entry:
235; DLQ-NEXT:    [[B:%.*]] = load double, ptr @double_const, align 8
236; DLQ-NEXT:    [[TMP0:%.*]] = fpext double [[B]] to x86_fp80
237; DLQ-NEXT:    [[C:%.*]] = fadd double [[B]], 1.000000e+00
238; DLQ-NEXT:    [[TMP1:%.*]] = fadd x86_fp80 [[TMP0]], 0xK3FFF8000000000000000
239; DLQ-NEXT:    [[TMP2:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_store(ptr [[DST:%.*]], i64 1)
240; DLQ-NEXT:    [[TMP3:%.*]] = ptrtoint ptr [[DST]] to i64
241; DLQ-NEXT:    [[TMP4:%.*]] = call i32 @__nsan_internal_check_double_l(double [[C]], x86_fp80 [[TMP1]], i32 4, i64 [[TMP3]])
242; DLQ-NEXT:    [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 1
243; DLQ-NEXT:    [[TMP6:%.*]] = fpext double [[C]] to x86_fp80
244; DLQ-NEXT:    [[TMP7:%.*]] = select i1 [[TMP5]], x86_fp80 [[TMP6]], x86_fp80 [[TMP1]]
245; DLQ-NEXT:    store x86_fp80 [[TMP7]], ptr [[TMP2]], align 1
246; DLQ-NEXT:    store double [[C]], ptr [[DST]], align 1
247; DLQ-NEXT:    ret void
248;
249entry:
250  %b = load double, ptr @double_const
251  %c = fadd double %b, 1.0
252  store double %c, ptr %dst, align 1
253  ret void
254}
255
256define void @load_add_store_float(ptr %a) sanitize_numerical_stability {
257; CHECK-LABEL: @load_add_store_float(
258; CHECK-NEXT:  entry:
259; CHECK-NEXT:    [[B:%.*]] = load float, ptr [[A:%.*]], align 1
260; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[A]], i64 1)
261; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TMP0]], null
262; CHECK-NEXT:    br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]]
263; CHECK:       2:
264; CHECK-NEXT:    [[TMP3:%.*]] = load double, ptr [[TMP0]], align 1
265; CHECK-NEXT:    br label [[TMP6:%.*]]
266; CHECK:       4:
267; CHECK-NEXT:    [[TMP5:%.*]] = fpext float [[B]] to double
268; CHECK-NEXT:    br label [[TMP6]]
269; CHECK:       6:
270; CHECK-NEXT:    [[TMP7:%.*]] = phi double [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
271; CHECK-NEXT:    [[C:%.*]] = fadd float [[B]], 1.000000e+00
272; CHECK-NEXT:    [[TMP8:%.*]] = fadd double [[TMP7]], 1.000000e+00
273; CHECK-NEXT:    [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[A]], i64 1)
274; CHECK-NEXT:    [[TMP10:%.*]] = ptrtoint ptr [[A]] to i64
275; CHECK-NEXT:    [[TMP11:%.*]] = call i32 @__nsan_internal_check_float_d(float [[C]], double [[TMP8]], i32 4, i64 [[TMP10]])
276; CHECK-NEXT:    [[TMP12:%.*]] = icmp eq i32 [[TMP11]], 1
277; CHECK-NEXT:    [[TMP13:%.*]] = fpext float [[C]] to double
278; CHECK-NEXT:    [[TMP14:%.*]] = select i1 [[TMP12]], double [[TMP13]], double [[TMP8]]
279; CHECK-NEXT:    store double [[TMP14]], ptr [[TMP9]], align 1
280; CHECK-NEXT:    store float [[C]], ptr [[A]], align 1
281; CHECK-NEXT:    ret void
282;
283entry:
284  %b = load float, ptr %a, align 1
285  %c = fadd float %b, 1.0
286  store float %c, ptr %a, align 1
287  ret void
288}
289
290define void @load_add_store_x86_fp80(ptr %a) sanitize_numerical_stability {
291; CHECK-LABEL: @load_add_store_x86_fp80(
292; CHECK-NEXT:  entry:
293; CHECK-NEXT:    [[B:%.*]] = load x86_fp80, ptr [[A:%.*]], align 1
294; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_longdouble_load(ptr [[A]], i64 1)
295; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TMP0]], null
296; CHECK-NEXT:    br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]]
297; CHECK:       2:
298; CHECK-NEXT:    [[TMP3:%.*]] = load fp128, ptr [[TMP0]], align 1
299; CHECK-NEXT:    br label [[TMP6:%.*]]
300; CHECK:       4:
301; CHECK-NEXT:    [[TMP5:%.*]] = fpext x86_fp80 [[B]] to fp128
302; CHECK-NEXT:    br label [[TMP6]]
303; CHECK:       6:
304; CHECK-NEXT:    [[TMP7:%.*]] = phi fp128 [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
305; CHECK-NEXT:    [[C:%.*]] = fadd x86_fp80 [[B]], 0xK3FC9E69594BEC44DE000
306; CHECK-NEXT:    [[TMP8:%.*]] = fadd fp128 [[TMP7]], 0xLC0000000000000003FC9CD2B297D889B
307; CHECK-NEXT:    [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_longdouble_store(ptr [[A]], i64 1)
308; CHECK-NEXT:    [[TMP10:%.*]] = ptrtoint ptr [[A]] to i64
309; CHECK-NEXT:    [[TMP11:%.*]] = call i32 @__nsan_internal_check_longdouble_q(x86_fp80 [[C]], fp128 [[TMP8]], i32 4, i64 [[TMP10]])
310; CHECK-NEXT:    [[TMP12:%.*]] = icmp eq i32 [[TMP11]], 1
311; CHECK-NEXT:    [[TMP13:%.*]] = fpext x86_fp80 [[C]] to fp128
312; CHECK-NEXT:    [[TMP14:%.*]] = select i1 [[TMP12]], fp128 [[TMP13]], fp128 [[TMP8]]
313; CHECK-NEXT:    store fp128 [[TMP14]], ptr [[TMP9]], align 1
314; CHECK-NEXT:    store x86_fp80 [[C]], ptr [[A]], align 1
315; CHECK-NEXT:    ret void
316;
317entry:
318  %b = load x86_fp80, ptr %a, align 1
319  %c = fadd x86_fp80 %b, 0xK3FC9E69594BEC44DE000
320  store x86_fp80 %c, ptr %a, align 1
321  ret void
322}
323
324define void @load_add_store_double(ptr %a) sanitize_numerical_stability {
325; DQQ-LABEL: @load_add_store_double(
326; DQQ-NEXT:  entry:
327; DQQ-NEXT:    [[B:%.*]] = load double, ptr [[A:%.*]], align 1
328; DQQ-NEXT:    [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_load(ptr [[A]], i64 1)
329; DQQ-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TMP0]], null
330; DQQ-NEXT:    br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]]
331; DQQ:       2:
332; DQQ-NEXT:    [[TMP3:%.*]] = load fp128, ptr [[TMP0]], align 1
333; DQQ-NEXT:    br label [[TMP6:%.*]]
334; DQQ:       4:
335; DQQ-NEXT:    [[TMP5:%.*]] = fpext double [[B]] to fp128
336; DQQ-NEXT:    br label [[TMP6]]
337; DQQ:       6:
338; DQQ-NEXT:    [[TMP7:%.*]] = phi fp128 [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
339; DQQ-NEXT:    [[C:%.*]] = fadd double [[B]], 1.000000e+00
340; DQQ-NEXT:    [[TMP8:%.*]] = fadd fp128 [[TMP7]], 0xL00000000000000003FFF000000000000
341; DQQ-NEXT:    [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_store(ptr [[A]], i64 1)
342; DQQ-NEXT:    [[TMP10:%.*]] = ptrtoint ptr [[A]] to i64
343; DQQ-NEXT:    [[TMP11:%.*]] = call i32 @__nsan_internal_check_double_q(double [[C]], fp128 [[TMP8]], i32 4, i64 [[TMP10]])
344; DQQ-NEXT:    [[TMP12:%.*]] = icmp eq i32 [[TMP11]], 1
345; DQQ-NEXT:    [[TMP13:%.*]] = fpext double [[C]] to fp128
346; DQQ-NEXT:    [[TMP14:%.*]] = select i1 [[TMP12]], fp128 [[TMP13]], fp128 [[TMP8]]
347; DQQ-NEXT:    store fp128 [[TMP14]], ptr [[TMP9]], align 1
348; DQQ-NEXT:    store double [[C]], ptr [[A]], align 1
349; DQQ-NEXT:    ret void
350;
351; DLQ-LABEL: @load_add_store_double(
352; DLQ-NEXT:  entry:
353; DLQ-NEXT:    [[B:%.*]] = load double, ptr [[A:%.*]], align 1
354; DLQ-NEXT:    [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_load(ptr [[A]], i64 1)
355; DLQ-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TMP0]], null
356; DLQ-NEXT:    br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]]
357; DLQ:       2:
358; DLQ-NEXT:    [[TMP3:%.*]] = load x86_fp80, ptr [[TMP0]], align 1
359; DLQ-NEXT:    br label [[TMP6:%.*]]
360; DLQ:       4:
361; DLQ-NEXT:    [[TMP5:%.*]] = fpext double [[B]] to x86_fp80
362; DLQ-NEXT:    br label [[TMP6]]
363; DLQ:       6:
364; DLQ-NEXT:    [[TMP7:%.*]] = phi x86_fp80 [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
365; DLQ-NEXT:    [[C:%.*]] = fadd double [[B]], 1.000000e+00
366; DLQ-NEXT:    [[TMP8:%.*]] = fadd x86_fp80 [[TMP7]], 0xK3FFF8000000000000000
367; DLQ-NEXT:    [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_store(ptr [[A]], i64 1)
368; DLQ-NEXT:    [[TMP10:%.*]] = ptrtoint ptr [[A]] to i64
369; DLQ-NEXT:    [[TMP11:%.*]] = call i32 @__nsan_internal_check_double_l(double [[C]], x86_fp80 [[TMP8]], i32 4, i64 [[TMP10]])
370; DLQ-NEXT:    [[TMP12:%.*]] = icmp eq i32 [[TMP11]], 1
371; DLQ-NEXT:    [[TMP13:%.*]] = fpext double [[C]] to x86_fp80
372; DLQ-NEXT:    [[TMP14:%.*]] = select i1 [[TMP12]], x86_fp80 [[TMP13]], x86_fp80 [[TMP8]]
373; DLQ-NEXT:    store x86_fp80 [[TMP14]], ptr [[TMP9]], align 1
374; DLQ-NEXT:    store double [[C]], ptr [[A]], align 1
375; DLQ-NEXT:    ret void
376;
377entry:
378  %b = load double, ptr %a, align 1
379  %c = fadd double %b, 1.0
380  store double %c, ptr %a, align 1
381  ret void
382}
383
384define void @load_add_store_vector(<2 x float>* %a) sanitize_numerical_stability {
385; CHECK-LABEL: @load_add_store_vector(
386; CHECK-NEXT:  entry:
387; CHECK-NEXT:    [[B:%.*]] = load <2 x float>, ptr [[A:%.*]], align 1
388; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[A]], i64 2)
389; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TMP0]], null
390; CHECK-NEXT:    br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]]
391; CHECK:       2:
392; CHECK-NEXT:    [[TMP3:%.*]] = load <2 x double>, ptr [[TMP0]], align 1
393; CHECK-NEXT:    br label [[TMP6:%.*]]
394; CHECK:       4:
395; CHECK-NEXT:    [[TMP5:%.*]] = fpext <2 x float> [[B]] to <2 x double>
396; CHECK-NEXT:    br label [[TMP6]]
397; CHECK:       6:
398; CHECK-NEXT:    [[TMP7:%.*]] = phi <2 x double> [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
399; CHECK-NEXT:    [[C:%.*]] = fadd <2 x float> [[B]], splat (float 1.000000e+00)
400; CHECK-NEXT:    [[TMP8:%.*]] = fadd <2 x double> [[TMP7]], splat (double 1.000000e+00)
401; CHECK-NEXT:    [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[A]], i64 2)
402; CHECK-NEXT:    [[TMP10:%.*]] = extractelement <2 x float> [[C]], i64 0
403; CHECK-NEXT:    [[TMP11:%.*]] = extractelement <2 x double> [[TMP8]], i64 0
404; CHECK-NEXT:    [[TMP12:%.*]] = ptrtoint ptr [[A]] to i64
405; CHECK-NEXT:    [[TMP13:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP10]], double [[TMP11]], i32 4, i64 [[TMP12]])
406; CHECK-NEXT:    [[TMP14:%.*]] = extractelement <2 x float> [[C]], i64 1
407; CHECK-NEXT:    [[TMP15:%.*]] = extractelement <2 x double> [[TMP8]], i64 1
408; CHECK-NEXT:    [[TMP16:%.*]] = ptrtoint ptr [[A]] to i64
409; CHECK-NEXT:    [[TMP17:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP14]], double [[TMP15]], i32 4, i64 [[TMP16]])
410; CHECK-NEXT:    [[TMP18:%.*]] = or i32 [[TMP13]], [[TMP17]]
411; CHECK-NEXT:    [[TMP19:%.*]] = icmp eq i32 [[TMP18]], 1
412; CHECK-NEXT:    [[TMP20:%.*]] = fpext <2 x float> [[C]] to <2 x double>
413; CHECK-NEXT:    [[TMP21:%.*]] = select i1 [[TMP19]], <2 x double> [[TMP20]], <2 x double> [[TMP8]]
414; CHECK-NEXT:    store <2 x double> [[TMP21]], ptr [[TMP9]], align 1
415; CHECK-NEXT:    store <2 x float> [[C]], ptr [[A]], align 1
416; CHECK-NEXT:    ret void
417;
418entry:
419  %b = load <2 x float>, ptr %a, align 1
420  %c = fadd <2 x float> %b, <float 1.0, float 1.0>
421  store <2 x float> %c, ptr %a, align 1
422  ret void
423}
424
425declare float @returns_float()
426
427define void @call_fn_returning_float(ptr %dst) sanitize_numerical_stability {
428; CHECK-LABEL: @call_fn_returning_float(
429; CHECK-NEXT:  entry:
430; CHECK-NEXT:    [[B:%.*]] = call float @returns_float()
431; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8
432; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @returns_float to i64)
433; CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr @__nsan_shadow_ret_ptr, align 8
434; CHECK-NEXT:    [[TMP3:%.*]] = fpext float [[B]] to double
435; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]]
436; CHECK-NEXT:    [[C:%.*]] = fadd float [[B]], 1.000000e+00
437; CHECK-NEXT:    [[TMP5:%.*]] = fadd double [[TMP4]], 1.000000e+00
438; CHECK-NEXT:    [[TMP6:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[DST:%.*]], i64 1)
439; CHECK-NEXT:    [[TMP7:%.*]] = ptrtoint ptr [[DST]] to i64
440; CHECK-NEXT:    [[TMP8:%.*]] = call i32 @__nsan_internal_check_float_d(float [[C]], double [[TMP5]], i32 4, i64 [[TMP7]])
441; CHECK-NEXT:    [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 1
442; CHECK-NEXT:    [[TMP10:%.*]] = fpext float [[C]] to double
443; CHECK-NEXT:    [[TMP11:%.*]] = select i1 [[TMP9]], double [[TMP10]], double [[TMP5]]
444; CHECK-NEXT:    store double [[TMP11]], ptr [[TMP6]], align 1
445; CHECK-NEXT:    store float [[C]], ptr [[DST]], align 1
446; CHECK-NEXT:    ret void
447;
448entry:
449  %b = call float @returns_float()
450  %c = fadd float %b, 1.0
451  store float %c, ptr %dst, align 1
452  ret void
453}
454
455define float @return_fn_returning_float(ptr %dst) sanitize_numerical_stability {
456; CHECK-LABEL: @return_fn_returning_float(
457; CHECK-NEXT:  entry:
458; CHECK-NEXT:    [[B:%.*]] = call float @returns_float()
459; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8
460; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @returns_float to i64)
461; CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr @__nsan_shadow_ret_ptr, align 8
462; CHECK-NEXT:    [[TMP3:%.*]] = fpext float [[B]] to double
463; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]]
464; CHECK-NEXT:    [[TMP5:%.*]] = call i32 @__nsan_internal_check_float_d(float [[B]], double [[TMP4]], i32 1, i64 0)
465; CHECK-NEXT:    [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 1
466; CHECK-NEXT:    [[TMP7:%.*]] = fpext float [[B]] to double
467; CHECK-NEXT:    [[TMP8:%.*]] = select i1 [[TMP6]], double [[TMP7]], double [[TMP4]]
468; CHECK-NEXT:    store i64 ptrtoint (ptr @return_fn_returning_float to i64), ptr @__nsan_shadow_ret_tag, align 8
469; CHECK-NEXT:    store double [[TMP8]], ptr @__nsan_shadow_ret_ptr, align 8
470; CHECK-NEXT:    ret float [[B]]
471;
472entry:
473  %b = call float @returns_float()
474  ret float %b
475}
476
477declare void @takes_floats(float %a, i8 %b, double %c, x86_fp80 %d)
478
479define void @call_fn_taking_float() sanitize_numerical_stability {
480; DQQ-LABEL: @call_fn_taking_float(
481; DQQ-NEXT:  entry:
482; DQQ-NEXT:    store ptr @takes_floats, ptr @__nsan_shadow_args_tag, align 8
483; DQQ-NEXT:    store double 1.000000e+00, ptr @__nsan_shadow_args_ptr, align 1
484; DQQ-NEXT:    store fp128 0xL00000000000000004000800000000000, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 8), align 1
485; DQQ-NEXT:    store fp128 0xLC0000000000000003FC9CD2B297D889B, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 24), align 1
486; DQQ-NEXT:    call void @takes_floats(float 1.000000e+00, i8 2, double 3.000000e+00, x86_fp80 0xK3FC9E69594BEC44DE000)
487; DQQ-NEXT:    ret void
488;
489; DLQ-LABEL: @call_fn_taking_float(
490; DLQ-NEXT:  entry:
491; DLQ-NEXT:    store ptr @takes_floats, ptr @__nsan_shadow_args_tag, align 8
492; DLQ-NEXT:    store double 1.000000e+00, ptr @__nsan_shadow_args_ptr, align 1
493; DLQ-NEXT:    store x86_fp80 0xK4000C000000000000000, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 8), align 1
494; DLQ-NEXT:    store fp128 0xLC0000000000000003FC9CD2B297D889B, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 18), align 1
495; DLQ-NEXT:    call void @takes_floats(float 1.000000e+00, i8 2, double 3.000000e+00, x86_fp80 0xK3FC9E69594BEC44DE000)
496; DLQ-NEXT:    ret void
497;
498entry:
499  call void @takes_floats(float 1.0, i8 2, double 3.0, x86_fp80 0xK3FC9E69594BEC44DE000)
500  ret void
501}
502
503declare float @llvm.sin.f32(float) readnone
504
505define float @call_sin_intrinsic() sanitize_numerical_stability {
506; CHECK-LABEL: @call_sin_intrinsic(
507; CHECK-NEXT:  entry:
508; CHECK-NEXT:    [[R:%.*]] = call float @llvm.sin.f32(float 1.000000e+00)
509; CHECK-NEXT:    [[TMP0:%.*]] = call double @llvm.sin.f64(double 1.000000e+00)
510; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP0]], i32 1, i64 0)
511; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 1
512; CHECK-NEXT:    [[TMP3:%.*]] = fpext float [[R]] to double
513; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], double [[TMP3]], double [[TMP0]]
514; CHECK-NEXT:    store i64 ptrtoint (ptr @call_sin_intrinsic to i64), ptr @__nsan_shadow_ret_tag, align 8
515; CHECK-NEXT:    store double [[TMP4]], ptr @__nsan_shadow_ret_ptr, align 8
516; CHECK-NEXT:    ret float [[R]]
517;
518entry:
519  %r = call float @llvm.sin.f32(float 1.0)
520  ret float %r
521}
522
523declare float @sinf(float)
524
525define float @call_sinf_libfunc() sanitize_numerical_stability {
526; CHECK-LABEL: @call_sinf_libfunc(
527; CHECK-NEXT:  entry:
528; CHECK-NEXT:    [[R:%.*]] = call float @sinf(float 1.000000e+00) #[[ATTR4:[0-9]+]]
529; CHECK-NEXT:    [[TMP0:%.*]] = call double @llvm.sin.f64(double 1.000000e+00)
530; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP0]], i32 1, i64 0)
531; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 1
532; CHECK-NEXT:    [[TMP3:%.*]] = fpext float [[R]] to double
533; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], double [[TMP3]], double [[TMP0]]
534; CHECK-NEXT:    store i64 ptrtoint (ptr @call_sinf_libfunc to i64), ptr @__nsan_shadow_ret_tag, align 8
535; CHECK-NEXT:    store double [[TMP4]], ptr @__nsan_shadow_ret_ptr, align 8
536; CHECK-NEXT:    ret float [[R]]
537;
538entry:
539  %r = call float @sinf(float 1.0)
540  ret float %r
541}
542
543declare double @sin(double)
544
545; FIXME: nsan uses `sin(double)` for fp128.
546define double @call_sin_libfunc() sanitize_numerical_stability {
547; DQQ-LABEL: @call_sin_libfunc(
548; DQQ-NEXT:  entry:
549; DQQ-NEXT:    [[R:%.*]] = call double @sin(double 1.000000e+00) #[[ATTR4]]
550; DQQ-NEXT:    [[TMP0:%.*]] = call x86_fp80 @llvm.sin.f80(x86_fp80 0xK3FFF8000000000000000)
551; DQQ-NEXT:    [[TMP1:%.*]] = fpext x86_fp80 [[TMP0]] to fp128
552; DQQ-NEXT:    [[TMP2:%.*]] = call i32 @__nsan_internal_check_double_q(double [[R]], fp128 [[TMP1]], i32 1, i64 0)
553; DQQ-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 1
554; DQQ-NEXT:    [[TMP4:%.*]] = fpext double [[R]] to fp128
555; DQQ-NEXT:    [[TMP5:%.*]] = select i1 [[TMP3]], fp128 [[TMP4]], fp128 [[TMP1]]
556; DQQ-NEXT:    store i64 ptrtoint (ptr @call_sin_libfunc to i64), ptr @__nsan_shadow_ret_tag, align 8
557; DQQ-NEXT:    store fp128 [[TMP5]], ptr @__nsan_shadow_ret_ptr, align 16
558; DQQ-NEXT:    ret double [[R]]
559;
560; DLQ-LABEL: @call_sin_libfunc(
561; DLQ-NEXT:  entry:
562; DLQ-NEXT:    [[R:%.*]] = call double @sin(double 1.000000e+00) #[[ATTR4]]
563; DLQ-NEXT:    [[TMP0:%.*]] = call x86_fp80 @llvm.sin.f80(x86_fp80 0xK3FFF8000000000000000)
564; DLQ-NEXT:    [[TMP1:%.*]] = call i32 @__nsan_internal_check_double_l(double [[R]], x86_fp80 [[TMP0]], i32 1, i64 0)
565; DLQ-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 1
566; DLQ-NEXT:    [[TMP3:%.*]] = fpext double [[R]] to x86_fp80
567; DLQ-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], x86_fp80 [[TMP3]], x86_fp80 [[TMP0]]
568; DLQ-NEXT:    store i64 ptrtoint (ptr @call_sin_libfunc to i64), ptr @__nsan_shadow_ret_tag, align 8
569; DLQ-NEXT:    store x86_fp80 [[TMP4]], ptr @__nsan_shadow_ret_ptr, align 16
570; DLQ-NEXT:    ret double [[R]]
571;
572entry:
573  %r = call double @sin(double 1.0)
574  ret double %r
575}
576
577declare double @frexp(double, i32*)
578
579define double @call_frexp_libfunc_nointrinsic(double %0, i32* nocapture %1) sanitize_numerical_stability {
580; DQQ-LABEL: @call_frexp_libfunc_nointrinsic(
581; DQQ-NEXT:    [[TMP3:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
582; DQQ-NEXT:    [[TMP4:%.*]] = icmp eq i64 [[TMP3]], ptrtoint (ptr @call_frexp_libfunc_nointrinsic to i64)
583; DQQ-NEXT:    [[TMP5:%.*]] = load fp128, ptr @__nsan_shadow_args_ptr, align 1
584; DQQ-NEXT:    [[TMP6:%.*]] = fpext double [[TMP0:%.*]] to fp128
585; DQQ-NEXT:    [[TMP7:%.*]] = select i1 [[TMP4]], fp128 [[TMP5]], fp128 [[TMP6]]
586; DQQ-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
587; DQQ-NEXT:    [[TMP8:%.*]] = call i32 @__nsan_internal_check_double_q(double [[TMP0]], fp128 [[TMP7]], i32 2, i64 0)
588; DQQ-NEXT:    [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 1
589; DQQ-NEXT:    [[TMP10:%.*]] = fpext double [[TMP0]] to fp128
590; DQQ-NEXT:    [[TMP11:%.*]] = select i1 [[TMP9]], fp128 [[TMP10]], fp128 [[TMP7]]
591; DQQ-NEXT:    [[TMP12:%.*]] = tail call double @frexp(double [[TMP0]], ptr [[TMP1:%.*]])
592; DQQ-NEXT:    [[TMP13:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8
593; DQQ-NEXT:    [[TMP14:%.*]] = icmp eq i64 [[TMP13]], ptrtoint (ptr @frexp to i64)
594; DQQ-NEXT:    [[TMP15:%.*]] = load fp128, ptr @__nsan_shadow_ret_ptr, align 16
595; DQQ-NEXT:    [[TMP16:%.*]] = fpext double [[TMP12]] to fp128
596; DQQ-NEXT:    [[TMP17:%.*]] = select i1 [[TMP14]], fp128 [[TMP15]], fp128 [[TMP16]]
597; DQQ-NEXT:    [[TMP18:%.*]] = call i32 @__nsan_internal_check_double_q(double [[TMP12]], fp128 [[TMP17]], i32 1, i64 0)
598; DQQ-NEXT:    [[TMP19:%.*]] = icmp eq i32 [[TMP18]], 1
599; DQQ-NEXT:    [[TMP20:%.*]] = fpext double [[TMP12]] to fp128
600; DQQ-NEXT:    [[TMP21:%.*]] = select i1 [[TMP19]], fp128 [[TMP20]], fp128 [[TMP17]]
601; DQQ-NEXT:    store i64 ptrtoint (ptr @call_frexp_libfunc_nointrinsic to i64), ptr @__nsan_shadow_ret_tag, align 8
602; DQQ-NEXT:    store fp128 [[TMP21]], ptr @__nsan_shadow_ret_ptr, align 16
603; DQQ-NEXT:    ret double [[TMP12]]
604;
605; DLQ-LABEL: @call_frexp_libfunc_nointrinsic(
606; DLQ-NEXT:    [[TMP3:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
607; DLQ-NEXT:    [[TMP4:%.*]] = icmp eq i64 [[TMP3]], ptrtoint (ptr @call_frexp_libfunc_nointrinsic to i64)
608; DLQ-NEXT:    [[TMP5:%.*]] = load x86_fp80, ptr @__nsan_shadow_args_ptr, align 1
609; DLQ-NEXT:    [[TMP6:%.*]] = fpext double [[TMP0:%.*]] to x86_fp80
610; DLQ-NEXT:    [[TMP7:%.*]] = select i1 [[TMP4]], x86_fp80 [[TMP5]], x86_fp80 [[TMP6]]
611; DLQ-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
612; DLQ-NEXT:    [[TMP8:%.*]] = call i32 @__nsan_internal_check_double_l(double [[TMP0]], x86_fp80 [[TMP7]], i32 2, i64 0)
613; DLQ-NEXT:    [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 1
614; DLQ-NEXT:    [[TMP10:%.*]] = fpext double [[TMP0]] to x86_fp80
615; DLQ-NEXT:    [[TMP11:%.*]] = select i1 [[TMP9]], x86_fp80 [[TMP10]], x86_fp80 [[TMP7]]
616; DLQ-NEXT:    [[TMP12:%.*]] = tail call double @frexp(double [[TMP0]], ptr [[TMP1:%.*]])
617; DLQ-NEXT:    [[TMP13:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8
618; DLQ-NEXT:    [[TMP14:%.*]] = icmp eq i64 [[TMP13]], ptrtoint (ptr @frexp to i64)
619; DLQ-NEXT:    [[TMP15:%.*]] = load x86_fp80, ptr @__nsan_shadow_ret_ptr, align 16
620; DLQ-NEXT:    [[TMP16:%.*]] = fpext double [[TMP12]] to x86_fp80
621; DLQ-NEXT:    [[TMP17:%.*]] = select i1 [[TMP14]], x86_fp80 [[TMP15]], x86_fp80 [[TMP16]]
622; DLQ-NEXT:    [[TMP18:%.*]] = call i32 @__nsan_internal_check_double_l(double [[TMP12]], x86_fp80 [[TMP17]], i32 1, i64 0)
623; DLQ-NEXT:    [[TMP19:%.*]] = icmp eq i32 [[TMP18]], 1
624; DLQ-NEXT:    [[TMP20:%.*]] = fpext double [[TMP12]] to x86_fp80
625; DLQ-NEXT:    [[TMP21:%.*]] = select i1 [[TMP19]], x86_fp80 [[TMP20]], x86_fp80 [[TMP17]]
626; DLQ-NEXT:    store i64 ptrtoint (ptr @call_frexp_libfunc_nointrinsic to i64), ptr @__nsan_shadow_ret_tag, align 8
627; DLQ-NEXT:    store x86_fp80 [[TMP21]], ptr @__nsan_shadow_ret_ptr, align 16
628; DLQ-NEXT:    ret double [[TMP12]]
629;
630  %3 = tail call double @frexp(double %0, i32* %1)
631  ret double %3
632}
633
634define float @call_fn_taking_float_by_fn_ptr(float (float)* nocapture %fn_ptr) sanitize_numerical_stability {
635; CHECK-LABEL: @call_fn_taking_float_by_fn_ptr(
636; CHECK-NEXT:  entry:
637; CHECK-NEXT:    store ptr [[FN_PTR:%.*]], ptr @__nsan_shadow_args_tag, align 8
638; CHECK-NEXT:    store double 1.000000e+00, ptr @__nsan_shadow_args_ptr, align 1
639; CHECK-NEXT:    [[R:%.*]] = call float [[FN_PTR]](float 1.000000e+00)
640; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8
641; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[FN_PTR]] to i64
642; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP0]], [[TMP1]]
643; CHECK-NEXT:    [[TMP3:%.*]] = load double, ptr @__nsan_shadow_ret_ptr, align 8
644; CHECK-NEXT:    [[TMP4:%.*]] = fpext float [[R]] to double
645; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], double [[TMP3]], double [[TMP4]]
646; CHECK-NEXT:    [[TMP6:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP5]], i32 1, i64 0)
647; CHECK-NEXT:    [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1
648; CHECK-NEXT:    [[TMP8:%.*]] = fpext float [[R]] to double
649; CHECK-NEXT:    [[TMP9:%.*]] = select i1 [[TMP7]], double [[TMP8]], double [[TMP5]]
650; CHECK-NEXT:    store i64 ptrtoint (ptr @call_fn_taking_float_by_fn_ptr to i64), ptr @__nsan_shadow_ret_tag, align 8
651; CHECK-NEXT:    store double [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 8
652; CHECK-NEXT:    ret float [[R]]
653;
654entry:
655  %r = call float %fn_ptr(float 1.0)
656  ret float %r
657}
658
659define void @store_float(ptr %dst) sanitize_numerical_stability {
660; CHECK-LABEL: @store_float(
661; CHECK-NEXT:  entry:
662; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[DST:%.*]], i64 1)
663; CHECK-NEXT:    store double 4.200000e+01, ptr [[TMP0]], align 1
664; CHECK-NEXT:    store float 4.200000e+01, ptr [[DST]], align 1
665; CHECK-NEXT:    ret void
666;
667entry:
668  store float 42.0, ptr %dst, align 1
669  ret void
670}
671
672define i1 @inline_asm(double %0) sanitize_numerical_stability {
673; DQQ-LABEL: @inline_asm(
674; DQQ-NEXT:  entry:
675; DQQ-NEXT:    [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
676; DQQ-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @inline_asm to i64)
677; DQQ-NEXT:    [[TMP3:%.*]] = load fp128, ptr @__nsan_shadow_args_ptr, align 1
678; DQQ-NEXT:    [[TMP4:%.*]] = fpext double [[TMP0:%.*]] to fp128
679; DQQ-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], fp128 [[TMP3]], fp128 [[TMP4]]
680; DQQ-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
681; DQQ-NEXT:    [[TMP6:%.*]] = call i32 asm "pmovmskb $1, $0", "=r,x,~{dirflag},~{fpsr},~{flags}"(double [[TMP0]])
682; DQQ-NEXT:    [[TMP7:%.*]] = trunc i32 [[TMP6]] to i8
683; DQQ-NEXT:    [[TMP8:%.*]] = icmp slt i8 [[TMP7]], 0
684; DQQ-NEXT:    ret i1 [[TMP8]]
685;
686; DLQ-LABEL: @inline_asm(
687; DLQ-NEXT:  entry:
688; DLQ-NEXT:    [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
689; DLQ-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @inline_asm to i64)
690; DLQ-NEXT:    [[TMP3:%.*]] = load x86_fp80, ptr @__nsan_shadow_args_ptr, align 1
691; DLQ-NEXT:    [[TMP4:%.*]] = fpext double [[TMP0:%.*]] to x86_fp80
692; DLQ-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], x86_fp80 [[TMP3]], x86_fp80 [[TMP4]]
693; DLQ-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
694; DLQ-NEXT:    [[TMP6:%.*]] = call i32 asm "pmovmskb $1, $0", "=r,x,~{dirflag},~{fpsr},~{flags}"(double [[TMP0]])
695; DLQ-NEXT:    [[TMP7:%.*]] = trunc i32 [[TMP6]] to i8
696; DLQ-NEXT:    [[TMP8:%.*]] = icmp slt i8 [[TMP7]], 0
697; DLQ-NEXT:    ret i1 [[TMP8]]
698;
699entry:
700  %1 = call i32 asm "pmovmskb $1, $0", "=r,x,~{dirflag},~{fpsr},~{flags}"(double %0)
701  %2 = trunc i32 %1 to i8
702  %3 = icmp slt i8 %2, 0
703  ret i1 %3
704}
705
706define void @vector_extract(<2 x float> %0) sanitize_numerical_stability {
707; CHECK-LABEL: @vector_extract(
708; CHECK-NEXT:  entry:
709; CHECK-NEXT:    [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
710; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @vector_extract to i64)
711; CHECK-NEXT:    [[TMP3:%.*]] = load <2 x double>, ptr @__nsan_shadow_args_ptr, align 1
712; CHECK-NEXT:    [[TMP4:%.*]] = fpext <2 x float> [[TMP0:%.*]] to <2 x double>
713; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], <2 x double> [[TMP3]], <2 x double> [[TMP4]]
714; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
715; CHECK-NEXT:    [[TMP6:%.*]] = extractelement <2 x float> [[TMP0]], i32 1
716; CHECK-NEXT:    [[TMP7:%.*]] = extractelement <2 x double> [[TMP5]], i32 1
717; CHECK-NEXT:    ret void
718;
719entry:
720  %1 = extractelement <2 x float> %0, i32 1
721  ret void
722}
723
724define void @vector_insert(<2 x float> %0) sanitize_numerical_stability {
725; CHECK-LABEL: @vector_insert(
726; CHECK-NEXT:  entry:
727; CHECK-NEXT:    [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
728; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @vector_insert to i64)
729; CHECK-NEXT:    [[TMP3:%.*]] = load <2 x double>, ptr @__nsan_shadow_args_ptr, align 1
730; CHECK-NEXT:    [[TMP4:%.*]] = fpext <2 x float> [[TMP0:%.*]] to <2 x double>
731; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], <2 x double> [[TMP3]], <2 x double> [[TMP4]]
732; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
733; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <2 x float> [[TMP0]], float 1.000000e+00, i32 1
734; CHECK-NEXT:    [[TMP7:%.*]] = insertelement <2 x double> [[TMP5]], double 1.000000e+00, i32 1
735; CHECK-NEXT:    ret void
736;
737entry:
738  %1 = insertelement <2 x float> %0, float 1.0, i32 1
739  ret void
740}
741
742define void @freeze_vector_insert(<2 x float> %vec, i32 %idx, float %scalar) sanitize_numerical_stability {
743; CHECK-LABEL: @freeze_vector_insert(
744; CHECK-NEXT:  entry:
745; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
746; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @freeze_vector_insert to i64)
747; CHECK-NEXT:    [[TMP2:%.*]] = load <2 x double>, ptr @__nsan_shadow_args_ptr, align 1
748; CHECK-NEXT:    [[TMP3:%.*]] = fpext <2 x float> [[VEC:%.*]] to <2 x double>
749; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], <2 x double> [[TMP2]], <2 x double> [[TMP3]]
750; CHECK-NEXT:    [[TMP5:%.*]] = load double, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 16), align 1
751; CHECK-NEXT:    [[TMP6:%.*]] = fpext float [[SCALAR:%.*]] to double
752; CHECK-NEXT:    [[TMP7:%.*]] = select i1 [[TMP1]], double [[TMP5]], double [[TMP6]]
753; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
754; CHECK-NEXT:    [[TMP8:%.*]] = insertelement <2 x float> [[VEC]], float [[SCALAR]], i32 [[IDX:%.*]]
755; CHECK-NEXT:    [[TMP9:%.*]] = insertelement <2 x double> [[TMP4]], double [[TMP7]], i32 [[IDX]]
756; CHECK-NEXT:    [[FROZEN:%.*]] = freeze <2 x float> [[TMP8]]
757; CHECK-NEXT:    [[TMP10:%.*]] = freeze <2 x double> [[TMP9]]
758; CHECK-NEXT:    ret void
759;
760entry:
761  %1 = insertelement <2 x float> %vec, float %scalar, i32 %idx
762  %frozen = freeze <2 x float> %1
763  ret void
764}
765
766define void @vector_shuffle(<2 x float> %0) sanitize_numerical_stability {
767; CHECK-LABEL: @vector_shuffle(
768; CHECK-NEXT:  entry:
769; CHECK-NEXT:    [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
770; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @vector_shuffle to i64)
771; CHECK-NEXT:    [[TMP3:%.*]] = load <2 x double>, ptr @__nsan_shadow_args_ptr, align 1
772; CHECK-NEXT:    [[TMP4:%.*]] = fpext <2 x float> [[TMP0:%.*]] to <2 x double>
773; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], <2 x double> [[TMP3]], <2 x double> [[TMP4]]
774; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
775; CHECK-NEXT:    [[TMP6:%.*]] = shufflevector <2 x float> [[TMP0]], <2 x float> splat (float 1.000000e+00), <2 x i32> <i32 1, i32 3>
776; CHECK-NEXT:    [[TMP7:%.*]] = shufflevector <2 x double> [[TMP5]], <2 x double> splat (double 1.000000e+00), <2 x i32> <i32 1, i32 3>
777; CHECK-NEXT:    ret void
778;
779entry:
780  %1 = shufflevector <2 x float> %0, <2 x float> <float 1.0, float 1.0>, <2 x i32> <i32 1, i32 3>
781  ret void
782}
783
784define void @aggregate_extract({i32, {float, i1}} %0) sanitize_numerical_stability {
785; CHECK-LABEL: @aggregate_extract(
786; CHECK-NEXT:  entry:
787; CHECK-NEXT:    [[TMP1:%.*]] = extractvalue { i32, { float, i1 } } [[TMP0:%.*]], 1, 0
788; CHECK-NEXT:    [[TMP2:%.*]] = fpext float [[TMP1]] to double
789; CHECK-NEXT:    ret void
790;
791entry:
792  %1 = extractvalue {i32, {float, i1}} %0, 1, 0
793  ret void
794}
795
796define void @aggregate_insert({i32, {float, i1}} %0, float %1) sanitize_numerical_stability {
797; CHECK-LABEL: @aggregate_insert(
798; CHECK-NEXT:  entry:
799; CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
800; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i64 [[TMP2]], ptrtoint (ptr @aggregate_insert to i64)
801; CHECK-NEXT:    [[TMP4:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1
802; CHECK-NEXT:    [[TMP5:%.*]] = fpext float [[TMP1:%.*]] to double
803; CHECK-NEXT:    [[TMP6:%.*]] = select i1 [[TMP3]], double [[TMP4]], double [[TMP5]]
804; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
805; CHECK-NEXT:    [[TMP7:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP1]], double [[TMP6]], i32 5, i64 0)
806; CHECK-NEXT:    [[TMP8:%.*]] = icmp eq i32 [[TMP7]], 1
807; CHECK-NEXT:    [[TMP9:%.*]] = fpext float [[TMP1]] to double
808; CHECK-NEXT:    [[TMP10:%.*]] = select i1 [[TMP8]], double [[TMP9]], double [[TMP6]]
809; CHECK-NEXT:    [[TMP11:%.*]] = insertvalue { i32, { float, i1 } } [[TMP0:%.*]], float [[TMP1]], 1, 0
810; CHECK-NEXT:    ret void
811;
812entry:
813  %2 = insertvalue {i32, {float, i1}} %0, float %1, 1, 0
814  ret void
815}
816
817define void @aggregate_insert_avoid_const_check({i32, {float, i1}} %0) sanitize_numerical_stability {
818; CHECK-LABEL: @aggregate_insert_avoid_const_check(
819; CHECK-NEXT:  entry:
820; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i32, { float, i1 } } [[TMP0:%.*]], float 1.000000e+00, 1, 0
821; CHECK-NEXT:    ret void
822;
823entry:
824  %1 = insertvalue {i32, {float, i1}} %0, float 1.0, 1, 0
825  ret void
826}
827
828
829declare float @fabsf(float)
830
831define float @sub_fabs(float %a, float %b) sanitize_numerical_stability {
832; CHECK-LABEL: @sub_fabs(
833; CHECK-NEXT:  entry:
834; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
835; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @sub_fabs to i64)
836; CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1
837; CHECK-NEXT:    [[TMP3:%.*]] = fpext float [[A:%.*]] to double
838; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]]
839; CHECK-NEXT:    [[TMP5:%.*]] = load double, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 8), align 1
840; CHECK-NEXT:    [[TMP6:%.*]] = fpext float [[B:%.*]] to double
841; CHECK-NEXT:    [[TMP7:%.*]] = select i1 [[TMP1]], double [[TMP5]], double [[TMP6]]
842; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
843; CHECK-NEXT:    [[S:%.*]] = fsub float [[A]], [[B]]
844; CHECK-NEXT:    [[TMP8:%.*]] = fsub double [[TMP4]], [[TMP7]]
845; CHECK-NEXT:    [[TMP9:%.*]] = call i32 @__nsan_internal_check_float_d(float [[S]], double [[TMP8]], i32 2, i64 0)
846; CHECK-NEXT:    [[TMP10:%.*]] = icmp eq i32 [[TMP9]], 1
847; CHECK-NEXT:    [[TMP11:%.*]] = fpext float [[S]] to double
848; CHECK-NEXT:    [[TMP12:%.*]] = select i1 [[TMP10]], double [[TMP11]], double [[TMP8]]
849; CHECK-NEXT:    [[R:%.*]] = call float @fabsf(float [[S]]) #[[ATTR4]]
850; CHECK-NEXT:    [[TMP13:%.*]] = call double @llvm.fabs.f64(double [[TMP8]])
851; CHECK-NEXT:    [[TMP14:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP13]], i32 1, i64 0)
852; CHECK-NEXT:    [[TMP15:%.*]] = icmp eq i32 [[TMP14]], 1
853; CHECK-NEXT:    [[TMP16:%.*]] = fpext float [[R]] to double
854; CHECK-NEXT:    [[TMP17:%.*]] = select i1 [[TMP15]], double [[TMP16]], double [[TMP13]]
855; CHECK-NEXT:    store i64 ptrtoint (ptr @sub_fabs to i64), ptr @__nsan_shadow_ret_tag, align 8
856; CHECK-NEXT:    store double [[TMP17]], ptr @__nsan_shadow_ret_ptr, align 8
857; CHECK-NEXT:    ret float [[R]]
858;
859entry:
860  %s = fsub float %a, %b
861  %r = call float @fabsf(float %s)
862  ret float %r
863}
864
865; Note that the `unsafe-fp-math` from the function attributes should be moved to
866; individual instructions, with the shadow instructions NOT getting the attribute.
867define float @param_add_return_float_unsafe_fp_math(float %a) #0 {
868; CHECK-LABEL: @param_add_return_float_unsafe_fp_math(
869; CHECK-NEXT:  entry:
870; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
871; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @param_add_return_float_unsafe_fp_math to i64)
872; CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1
873; CHECK-NEXT:    [[TMP3:%.*]] = fpext float [[A:%.*]] to double
874; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]]
875; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
876; CHECK-NEXT:    [[B:%.*]] = fadd fast float [[A]], 1.000000e+00
877; CHECK-NEXT:    [[TMP5:%.*]] = fadd double [[TMP4]], 1.000000e+00
878; CHECK-NEXT:    [[TMP6:%.*]] = call i32 @__nsan_internal_check_float_d(float [[B]], double [[TMP5]], i32 1, i64 0)
879; CHECK-NEXT:    [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1
880; CHECK-NEXT:    [[TMP8:%.*]] = fpext float [[B]] to double
881; CHECK-NEXT:    [[TMP9:%.*]] = select i1 [[TMP7]], double [[TMP8]], double [[TMP5]]
882; CHECK-NEXT:    store i64 ptrtoint (ptr @param_add_return_float_unsafe_fp_math to i64), ptr @__nsan_shadow_ret_tag, align 8
883; CHECK-NEXT:    store double [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 8
884; CHECK-NEXT:    ret float [[B]]
885;
886entry:
887  %b = fadd float %a, 1.0
888  ret float %b
889}
890
891
892define void @truncate(<2 x double> %0) sanitize_numerical_stability {
893; DQQ-LABEL: @truncate(
894; DQQ-NEXT:  entry:
895; DQQ-NEXT:    [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
896; DQQ-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @truncate to i64)
897; DQQ-NEXT:    [[TMP3:%.*]] = load <2 x fp128>, ptr @__nsan_shadow_args_ptr, align 1
898; DQQ-NEXT:    [[TMP4:%.*]] = fpext <2 x double> [[TMP0:%.*]] to <2 x fp128>
899; DQQ-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], <2 x fp128> [[TMP3]], <2 x fp128> [[TMP4]]
900; DQQ-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
901; DQQ-NEXT:    [[TMP6:%.*]] = fptrunc <2 x double> [[TMP0]] to <2 x float>
902; DQQ-NEXT:    [[TMP7:%.*]] = fptrunc <2 x fp128> [[TMP5]] to <2 x double>
903; DQQ-NEXT:    ret void
904;
905; DLQ-LABEL: @truncate(
906; DLQ-NEXT:  entry:
907; DLQ-NEXT:    [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
908; DLQ-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @truncate to i64)
909; DLQ-NEXT:    [[TMP3:%.*]] = load <2 x x86_fp80>, ptr @__nsan_shadow_args_ptr, align 1
910; DLQ-NEXT:    [[TMP4:%.*]] = fpext <2 x double> [[TMP0:%.*]] to <2 x x86_fp80>
911; DLQ-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], <2 x x86_fp80> [[TMP3]], <2 x x86_fp80> [[TMP4]]
912; DLQ-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
913; DLQ-NEXT:    [[TMP6:%.*]] = fptrunc <2 x double> [[TMP0]] to <2 x float>
914; DLQ-NEXT:    [[TMP7:%.*]] = fptrunc <2 x x86_fp80> [[TMP5]] to <2 x double>
915; DLQ-NEXT:    ret void
916;
917entry:
918  %1 = fptrunc <2 x double> %0 to  <2 x float>
919  ret void
920}
921
922define void @unaryop(float %a) sanitize_numerical_stability {
923; CHECK-LABEL: @unaryop(
924; CHECK-NEXT:  entry:
925; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8
926; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @unaryop to i64)
927; CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1
928; CHECK-NEXT:    [[TMP3:%.*]] = fpext float [[A:%.*]] to double
929; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]]
930; CHECK-NEXT:    store i64 0, ptr @__nsan_shadow_args_tag, align 8
931; CHECK-NEXT:    [[C:%.*]] = fneg float [[A]]
932; CHECK-NEXT:    [[TMP5:%.*]] = fneg double [[TMP4]]
933; CHECK-NEXT:    ret void
934;
935entry:
936  %c = fneg float %a
937  ret void
938}
939
940
941attributes #0 = { nounwind readonly uwtable sanitize_numerical_stability "correctly-rounded-divide-sqrt-fp-math"="false" "denormal-fp-math"="preserve-sign,preserve-sign" "denormal-fp-math-f32"="ieee,ieee" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="true" "no-jump-tables"="false" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="true" "use-soft-float"="false" }
942