; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes=nsan -nsan-shadow-type-mapping=dqq -nsan-truncate-fcmp-eq=false -S %s | FileCheck %s --check-prefixes=CHECK,DQQ ; RUN: opt -passes=nsan -nsan-shadow-type-mapping=dlq -nsan-truncate-fcmp-eq=false -S %s | FileCheck %s --check-prefixes=CHECK,DLQ ; RUN: opt -passes=nsan -nsan-shadow-type-mapping=dqq -nsan-truncate-fcmp-eq=false -use-constant-fp-for-fixed-length-splat -S %s | FileCheck %s --check-prefixes=CHECK,DQQ ; RUN: opt -passes=nsan -nsan-shadow-type-mapping=dlq -nsan-truncate-fcmp-eq=false -use-constant-fp-for-fixed-length-splat -S %s | FileCheck %s --check-prefixes=CHECK,DLQ target 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" declare float @declaration_only(float %a) sanitize_numerical_stability ; Tests with simple control flow. @float_const = private unnamed_addr constant float 0.5 @x86_fp80_const = private unnamed_addr constant x86_fp80 0xK3FC9E69594BEC44DE000 @double_const = private unnamed_addr constant double 0.5 define float @return_param_float(float %a) sanitize_numerical_stability { ; CHECK-LABEL: @return_param_float( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @return_param_float to i64) ; CHECK-NEXT: [[TMP2:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP3:%.*]] = fpext float [[A:%.*]] to double ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP5:%.*]] = call i32 @__nsan_internal_check_float_d(float [[A]], double [[TMP4]], i32 1, i64 0) ; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 1 ; CHECK-NEXT: [[TMP7:%.*]] = fpext float [[A]] to double ; CHECK-NEXT: [[TMP8:%.*]] = select i1 [[TMP6]], double [[TMP7]], double [[TMP4]] ; CHECK-NEXT: store i64 ptrtoint (ptr @return_param_float to i64), ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: store double [[TMP8]], ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: ret float [[A]] ; entry: ret float %a } ; Note that the shadow fadd should not have a `fast` flag. define float @param_add_return_float(float %a) sanitize_numerical_stability { ; CHECK-LABEL: @param_add_return_float( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @param_add_return_float to i64) ; CHECK-NEXT: [[TMP2:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP3:%.*]] = fpext float [[A:%.*]] to double ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[B:%.*]] = fadd fast float [[A]], 1.000000e+00 ; CHECK-NEXT: [[TMP5:%.*]] = fadd double [[TMP4]], 1.000000e+00 ; CHECK-NEXT: [[TMP6:%.*]] = call i32 @__nsan_internal_check_float_d(float [[B]], double [[TMP5]], i32 1, i64 0) ; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1 ; CHECK-NEXT: [[TMP8:%.*]] = fpext float [[B]] to double ; CHECK-NEXT: [[TMP9:%.*]] = select i1 [[TMP7]], double [[TMP8]], double [[TMP5]] ; CHECK-NEXT: store i64 ptrtoint (ptr @param_add_return_float to i64), ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: store double [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: ret float [[B]] ; entry: %b = fadd fast float %a, 1.0 ret float %b } define x86_fp80 @param_add_return_x86_fp80(x86_fp80 %a) sanitize_numerical_stability { ; CHECK-LABEL: @param_add_return_x86_fp80( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @param_add_return_x86_fp80 to i64) ; CHECK-NEXT: [[TMP2:%.*]] = load fp128, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP3:%.*]] = fpext x86_fp80 [[A:%.*]] to fp128 ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], fp128 [[TMP2]], fp128 [[TMP3]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[B:%.*]] = fadd x86_fp80 [[A]], 0xK3FC9E69594BEC44DE000 ; CHECK-NEXT: [[TMP5:%.*]] = fadd fp128 [[TMP4]], 0xLC0000000000000003FC9CD2B297D889B ; CHECK-NEXT: [[TMP6:%.*]] = call i32 @__nsan_internal_check_longdouble_q(x86_fp80 [[B]], fp128 [[TMP5]], i32 1, i64 0) ; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1 ; CHECK-NEXT: [[TMP8:%.*]] = fpext x86_fp80 [[B]] to fp128 ; CHECK-NEXT: [[TMP9:%.*]] = select i1 [[TMP7]], fp128 [[TMP8]], fp128 [[TMP5]] ; CHECK-NEXT: store i64 ptrtoint (ptr @param_add_return_x86_fp80 to i64), ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: store fp128 [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 16 ; CHECK-NEXT: ret x86_fp80 [[B]] ; entry: %b = fadd x86_fp80 %a, 0xK3FC9E69594BEC44DE000 ret x86_fp80 %b } define double @param_add_return_double(double %a) sanitize_numerical_stability { ; DQQ-LABEL: @param_add_return_double( ; DQQ-NEXT: entry: ; DQQ-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; DQQ-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @param_add_return_double to i64) ; DQQ-NEXT: [[TMP2:%.*]] = load fp128, ptr @__nsan_shadow_args_ptr, align 1 ; DQQ-NEXT: [[TMP3:%.*]] = fpext double [[A:%.*]] to fp128 ; DQQ-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], fp128 [[TMP2]], fp128 [[TMP3]] ; DQQ-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; DQQ-NEXT: [[B:%.*]] = fadd double [[A]], 1.000000e+00 ; DQQ-NEXT: [[TMP5:%.*]] = fadd fp128 [[TMP4]], 0xL00000000000000003FFF000000000000 ; DQQ-NEXT: [[TMP6:%.*]] = call i32 @__nsan_internal_check_double_q(double [[B]], fp128 [[TMP5]], i32 1, i64 0) ; DQQ-NEXT: [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1 ; DQQ-NEXT: [[TMP8:%.*]] = fpext double [[B]] to fp128 ; DQQ-NEXT: [[TMP9:%.*]] = select i1 [[TMP7]], fp128 [[TMP8]], fp128 [[TMP5]] ; DQQ-NEXT: store i64 ptrtoint (ptr @param_add_return_double to i64), ptr @__nsan_shadow_ret_tag, align 8 ; DQQ-NEXT: store fp128 [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 16 ; DQQ-NEXT: ret double [[B]] ; ; DLQ-LABEL: @param_add_return_double( ; DLQ-NEXT: entry: ; DLQ-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; DLQ-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @param_add_return_double to i64) ; DLQ-NEXT: [[TMP2:%.*]] = load x86_fp80, ptr @__nsan_shadow_args_ptr, align 1 ; DLQ-NEXT: [[TMP3:%.*]] = fpext double [[A:%.*]] to x86_fp80 ; DLQ-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], x86_fp80 [[TMP2]], x86_fp80 [[TMP3]] ; DLQ-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; DLQ-NEXT: [[B:%.*]] = fadd double [[A]], 1.000000e+00 ; DLQ-NEXT: [[TMP5:%.*]] = fadd x86_fp80 [[TMP4]], 0xK3FFF8000000000000000 ; DLQ-NEXT: [[TMP6:%.*]] = call i32 @__nsan_internal_check_double_l(double [[B]], x86_fp80 [[TMP5]], i32 1, i64 0) ; DLQ-NEXT: [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1 ; DLQ-NEXT: [[TMP8:%.*]] = fpext double [[B]] to x86_fp80 ; DLQ-NEXT: [[TMP9:%.*]] = select i1 [[TMP7]], x86_fp80 [[TMP8]], x86_fp80 [[TMP5]] ; DLQ-NEXT: store i64 ptrtoint (ptr @param_add_return_double to i64), ptr @__nsan_shadow_ret_tag, align 8 ; DLQ-NEXT: store x86_fp80 [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 16 ; DLQ-NEXT: ret double [[B]] ; entry: %b = fadd double %a, 1.0 ret double %b } define <2 x float> @return_param_add_return_float_vector(<2 x float> %a) sanitize_numerical_stability { ; CHECK-LABEL: @return_param_add_return_float_vector( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @return_param_add_return_float_vector to i64) ; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP3:%.*]] = fpext <2 x float> [[A:%.*]] to <2 x double> ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], <2 x double> [[TMP2]], <2 x double> [[TMP3]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[B:%.*]] = fadd <2 x float> [[A]], splat (float 1.000000e+00) ; CHECK-NEXT: [[TMP5:%.*]] = fadd <2 x double> [[TMP4]], splat (double 1.000000e+00) ; CHECK-NEXT: [[TMP6:%.*]] = extractelement <2 x float> [[B]], i64 0 ; CHECK-NEXT: [[TMP7:%.*]] = extractelement <2 x double> [[TMP5]], i64 0 ; CHECK-NEXT: [[TMP8:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP6]], double [[TMP7]], i32 1, i64 0) ; CHECK-NEXT: [[TMP9:%.*]] = extractelement <2 x float> [[B]], i64 1 ; CHECK-NEXT: [[TMP10:%.*]] = extractelement <2 x double> [[TMP5]], i64 1 ; CHECK-NEXT: [[TMP11:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP9]], double [[TMP10]], i32 1, i64 0) ; CHECK-NEXT: [[TMP12:%.*]] = or i32 [[TMP8]], [[TMP11]] ; CHECK-NEXT: [[TMP13:%.*]] = icmp eq i32 [[TMP12]], 1 ; CHECK-NEXT: [[TMP14:%.*]] = fpext <2 x float> [[B]] to <2 x double> ; CHECK-NEXT: [[TMP15:%.*]] = select i1 [[TMP13]], <2 x double> [[TMP14]], <2 x double> [[TMP5]] ; CHECK-NEXT: store i64 ptrtoint (ptr @return_param_add_return_float_vector to i64), ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: store <2 x double> [[TMP15]], ptr @__nsan_shadow_ret_ptr, align 16 ; CHECK-NEXT: ret <2 x float> [[B]] ; entry: %b = fadd <2 x float> %a, ret <2 x float> %b } ; TODO: This is ignored for now. define [2 x float] @return_param_float_array([2 x float] %a) sanitize_numerical_stability { ; CHECK-LABEL: @return_param_float_array( ; CHECK-NEXT: entry: ; CHECK-NEXT: ret [2 x float] [[A:%.*]] ; entry: ret [2 x float] %a } define void @constantload_add_store_float(ptr %dst) sanitize_numerical_stability { ; CHECK-LABEL: @constantload_add_store_float( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[B:%.*]] = load float, ptr @float_const, align 4 ; CHECK-NEXT: [[TMP0:%.*]] = fpext float [[B]] to double ; CHECK-NEXT: [[C:%.*]] = fadd float [[B]], 1.000000e+00 ; CHECK-NEXT: [[TMP1:%.*]] = fadd double [[TMP0]], 1.000000e+00 ; CHECK-NEXT: [[TMP2:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[DST:%.*]], i64 1) ; CHECK-NEXT: [[TMP3:%.*]] = ptrtoint ptr [[DST]] to i64 ; CHECK-NEXT: [[TMP4:%.*]] = call i32 @__nsan_internal_check_float_d(float [[C]], double [[TMP1]], i32 4, i64 [[TMP3]]) ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 1 ; CHECK-NEXT: [[TMP6:%.*]] = fpext float [[C]] to double ; CHECK-NEXT: [[TMP7:%.*]] = select i1 [[TMP5]], double [[TMP6]], double [[TMP1]] ; CHECK-NEXT: store double [[TMP7]], ptr [[TMP2]], align 1 ; CHECK-NEXT: store float [[C]], ptr [[DST]], align 1 ; CHECK-NEXT: ret void ; entry: %b = load float, ptr @float_const %c = fadd float %b, 1.0 store float %c, ptr %dst, align 1 ret void } define void @constantload_add_store_x86_fp80(ptr %dst) sanitize_numerical_stability { ; CHECK-LABEL: @constantload_add_store_x86_fp80( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[B:%.*]] = load x86_fp80, ptr @x86_fp80_const, align 16 ; CHECK-NEXT: [[TMP0:%.*]] = fpext x86_fp80 [[B]] to fp128 ; CHECK-NEXT: [[C:%.*]] = fadd x86_fp80 [[B]], 0xK3FC9E69594BEC44DE000 ; CHECK-NEXT: [[TMP1:%.*]] = fadd fp128 [[TMP0]], 0xLC0000000000000003FC9CD2B297D889B ; CHECK-NEXT: [[TMP2:%.*]] = call ptr @__nsan_get_shadow_ptr_for_longdouble_store(ptr [[DST:%.*]], i64 1) ; CHECK-NEXT: [[TMP3:%.*]] = ptrtoint ptr [[DST]] to i64 ; CHECK-NEXT: [[TMP4:%.*]] = call i32 @__nsan_internal_check_longdouble_q(x86_fp80 [[C]], fp128 [[TMP1]], i32 4, i64 [[TMP3]]) ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 1 ; CHECK-NEXT: [[TMP6:%.*]] = fpext x86_fp80 [[C]] to fp128 ; CHECK-NEXT: [[TMP7:%.*]] = select i1 [[TMP5]], fp128 [[TMP6]], fp128 [[TMP1]] ; CHECK-NEXT: store fp128 [[TMP7]], ptr [[TMP2]], align 1 ; CHECK-NEXT: store x86_fp80 [[C]], ptr [[DST]], align 1 ; CHECK-NEXT: ret void ; entry: %b = load x86_fp80, ptr @x86_fp80_const %c = fadd x86_fp80 %b, 0xK3FC9E69594BEC44DE000 store x86_fp80 %c, ptr %dst, align 1 ret void } define void @constantload_add_store_double(ptr %dst) sanitize_numerical_stability { ; DQQ-LABEL: @constantload_add_store_double( ; DQQ-NEXT: entry: ; DQQ-NEXT: [[B:%.*]] = load double, ptr @double_const, align 8 ; DQQ-NEXT: [[TMP0:%.*]] = fpext double [[B]] to fp128 ; DQQ-NEXT: [[C:%.*]] = fadd double [[B]], 1.000000e+00 ; DQQ-NEXT: [[TMP1:%.*]] = fadd fp128 [[TMP0]], 0xL00000000000000003FFF000000000000 ; DQQ-NEXT: [[TMP2:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_store(ptr [[DST:%.*]], i64 1) ; DQQ-NEXT: [[TMP3:%.*]] = ptrtoint ptr [[DST]] to i64 ; DQQ-NEXT: [[TMP4:%.*]] = call i32 @__nsan_internal_check_double_q(double [[C]], fp128 [[TMP1]], i32 4, i64 [[TMP3]]) ; DQQ-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 1 ; DQQ-NEXT: [[TMP6:%.*]] = fpext double [[C]] to fp128 ; DQQ-NEXT: [[TMP7:%.*]] = select i1 [[TMP5]], fp128 [[TMP6]], fp128 [[TMP1]] ; DQQ-NEXT: store fp128 [[TMP7]], ptr [[TMP2]], align 1 ; DQQ-NEXT: store double [[C]], ptr [[DST]], align 1 ; DQQ-NEXT: ret void ; ; DLQ-LABEL: @constantload_add_store_double( ; DLQ-NEXT: entry: ; DLQ-NEXT: [[B:%.*]] = load double, ptr @double_const, align 8 ; DLQ-NEXT: [[TMP0:%.*]] = fpext double [[B]] to x86_fp80 ; DLQ-NEXT: [[C:%.*]] = fadd double [[B]], 1.000000e+00 ; DLQ-NEXT: [[TMP1:%.*]] = fadd x86_fp80 [[TMP0]], 0xK3FFF8000000000000000 ; DLQ-NEXT: [[TMP2:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_store(ptr [[DST:%.*]], i64 1) ; DLQ-NEXT: [[TMP3:%.*]] = ptrtoint ptr [[DST]] to i64 ; DLQ-NEXT: [[TMP4:%.*]] = call i32 @__nsan_internal_check_double_l(double [[C]], x86_fp80 [[TMP1]], i32 4, i64 [[TMP3]]) ; DLQ-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 1 ; DLQ-NEXT: [[TMP6:%.*]] = fpext double [[C]] to x86_fp80 ; DLQ-NEXT: [[TMP7:%.*]] = select i1 [[TMP5]], x86_fp80 [[TMP6]], x86_fp80 [[TMP1]] ; DLQ-NEXT: store x86_fp80 [[TMP7]], ptr [[TMP2]], align 1 ; DLQ-NEXT: store double [[C]], ptr [[DST]], align 1 ; DLQ-NEXT: ret void ; entry: %b = load double, ptr @double_const %c = fadd double %b, 1.0 store double %c, ptr %dst, align 1 ret void } define void @load_add_store_float(ptr %a) sanitize_numerical_stability { ; CHECK-LABEL: @load_add_store_float( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[B:%.*]] = load float, ptr [[A:%.*]], align 1 ; CHECK-NEXT: [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[A]], i64 1) ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[TMP0]], null ; CHECK-NEXT: br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]] ; CHECK: 2: ; CHECK-NEXT: [[TMP3:%.*]] = load double, ptr [[TMP0]], align 1 ; CHECK-NEXT: br label [[TMP6:%.*]] ; CHECK: 4: ; CHECK-NEXT: [[TMP5:%.*]] = fpext float [[B]] to double ; CHECK-NEXT: br label [[TMP6]] ; CHECK: 6: ; CHECK-NEXT: [[TMP7:%.*]] = phi double [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ] ; CHECK-NEXT: [[C:%.*]] = fadd float [[B]], 1.000000e+00 ; CHECK-NEXT: [[TMP8:%.*]] = fadd double [[TMP7]], 1.000000e+00 ; CHECK-NEXT: [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[A]], i64 1) ; CHECK-NEXT: [[TMP10:%.*]] = ptrtoint ptr [[A]] to i64 ; CHECK-NEXT: [[TMP11:%.*]] = call i32 @__nsan_internal_check_float_d(float [[C]], double [[TMP8]], i32 4, i64 [[TMP10]]) ; CHECK-NEXT: [[TMP12:%.*]] = icmp eq i32 [[TMP11]], 1 ; CHECK-NEXT: [[TMP13:%.*]] = fpext float [[C]] to double ; CHECK-NEXT: [[TMP14:%.*]] = select i1 [[TMP12]], double [[TMP13]], double [[TMP8]] ; CHECK-NEXT: store double [[TMP14]], ptr [[TMP9]], align 1 ; CHECK-NEXT: store float [[C]], ptr [[A]], align 1 ; CHECK-NEXT: ret void ; entry: %b = load float, ptr %a, align 1 %c = fadd float %b, 1.0 store float %c, ptr %a, align 1 ret void } define void @load_add_store_x86_fp80(ptr %a) sanitize_numerical_stability { ; CHECK-LABEL: @load_add_store_x86_fp80( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[B:%.*]] = load x86_fp80, ptr [[A:%.*]], align 1 ; CHECK-NEXT: [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_longdouble_load(ptr [[A]], i64 1) ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[TMP0]], null ; CHECK-NEXT: br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]] ; CHECK: 2: ; CHECK-NEXT: [[TMP3:%.*]] = load fp128, ptr [[TMP0]], align 1 ; CHECK-NEXT: br label [[TMP6:%.*]] ; CHECK: 4: ; CHECK-NEXT: [[TMP5:%.*]] = fpext x86_fp80 [[B]] to fp128 ; CHECK-NEXT: br label [[TMP6]] ; CHECK: 6: ; CHECK-NEXT: [[TMP7:%.*]] = phi fp128 [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ] ; CHECK-NEXT: [[C:%.*]] = fadd x86_fp80 [[B]], 0xK3FC9E69594BEC44DE000 ; CHECK-NEXT: [[TMP8:%.*]] = fadd fp128 [[TMP7]], 0xLC0000000000000003FC9CD2B297D889B ; CHECK-NEXT: [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_longdouble_store(ptr [[A]], i64 1) ; CHECK-NEXT: [[TMP10:%.*]] = ptrtoint ptr [[A]] to i64 ; CHECK-NEXT: [[TMP11:%.*]] = call i32 @__nsan_internal_check_longdouble_q(x86_fp80 [[C]], fp128 [[TMP8]], i32 4, i64 [[TMP10]]) ; CHECK-NEXT: [[TMP12:%.*]] = icmp eq i32 [[TMP11]], 1 ; CHECK-NEXT: [[TMP13:%.*]] = fpext x86_fp80 [[C]] to fp128 ; CHECK-NEXT: [[TMP14:%.*]] = select i1 [[TMP12]], fp128 [[TMP13]], fp128 [[TMP8]] ; CHECK-NEXT: store fp128 [[TMP14]], ptr [[TMP9]], align 1 ; CHECK-NEXT: store x86_fp80 [[C]], ptr [[A]], align 1 ; CHECK-NEXT: ret void ; entry: %b = load x86_fp80, ptr %a, align 1 %c = fadd x86_fp80 %b, 0xK3FC9E69594BEC44DE000 store x86_fp80 %c, ptr %a, align 1 ret void } define void @load_add_store_double(ptr %a) sanitize_numerical_stability { ; DQQ-LABEL: @load_add_store_double( ; DQQ-NEXT: entry: ; DQQ-NEXT: [[B:%.*]] = load double, ptr [[A:%.*]], align 1 ; DQQ-NEXT: [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_load(ptr [[A]], i64 1) ; DQQ-NEXT: [[TMP1:%.*]] = icmp eq ptr [[TMP0]], null ; DQQ-NEXT: br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]] ; DQQ: 2: ; DQQ-NEXT: [[TMP3:%.*]] = load fp128, ptr [[TMP0]], align 1 ; DQQ-NEXT: br label [[TMP6:%.*]] ; DQQ: 4: ; DQQ-NEXT: [[TMP5:%.*]] = fpext double [[B]] to fp128 ; DQQ-NEXT: br label [[TMP6]] ; DQQ: 6: ; DQQ-NEXT: [[TMP7:%.*]] = phi fp128 [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ] ; DQQ-NEXT: [[C:%.*]] = fadd double [[B]], 1.000000e+00 ; DQQ-NEXT: [[TMP8:%.*]] = fadd fp128 [[TMP7]], 0xL00000000000000003FFF000000000000 ; DQQ-NEXT: [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_store(ptr [[A]], i64 1) ; DQQ-NEXT: [[TMP10:%.*]] = ptrtoint ptr [[A]] to i64 ; DQQ-NEXT: [[TMP11:%.*]] = call i32 @__nsan_internal_check_double_q(double [[C]], fp128 [[TMP8]], i32 4, i64 [[TMP10]]) ; DQQ-NEXT: [[TMP12:%.*]] = icmp eq i32 [[TMP11]], 1 ; DQQ-NEXT: [[TMP13:%.*]] = fpext double [[C]] to fp128 ; DQQ-NEXT: [[TMP14:%.*]] = select i1 [[TMP12]], fp128 [[TMP13]], fp128 [[TMP8]] ; DQQ-NEXT: store fp128 [[TMP14]], ptr [[TMP9]], align 1 ; DQQ-NEXT: store double [[C]], ptr [[A]], align 1 ; DQQ-NEXT: ret void ; ; DLQ-LABEL: @load_add_store_double( ; DLQ-NEXT: entry: ; DLQ-NEXT: [[B:%.*]] = load double, ptr [[A:%.*]], align 1 ; DLQ-NEXT: [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_load(ptr [[A]], i64 1) ; DLQ-NEXT: [[TMP1:%.*]] = icmp eq ptr [[TMP0]], null ; DLQ-NEXT: br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]] ; DLQ: 2: ; DLQ-NEXT: [[TMP3:%.*]] = load x86_fp80, ptr [[TMP0]], align 1 ; DLQ-NEXT: br label [[TMP6:%.*]] ; DLQ: 4: ; DLQ-NEXT: [[TMP5:%.*]] = fpext double [[B]] to x86_fp80 ; DLQ-NEXT: br label [[TMP6]] ; DLQ: 6: ; DLQ-NEXT: [[TMP7:%.*]] = phi x86_fp80 [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ] ; DLQ-NEXT: [[C:%.*]] = fadd double [[B]], 1.000000e+00 ; DLQ-NEXT: [[TMP8:%.*]] = fadd x86_fp80 [[TMP7]], 0xK3FFF8000000000000000 ; DLQ-NEXT: [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_double_store(ptr [[A]], i64 1) ; DLQ-NEXT: [[TMP10:%.*]] = ptrtoint ptr [[A]] to i64 ; DLQ-NEXT: [[TMP11:%.*]] = call i32 @__nsan_internal_check_double_l(double [[C]], x86_fp80 [[TMP8]], i32 4, i64 [[TMP10]]) ; DLQ-NEXT: [[TMP12:%.*]] = icmp eq i32 [[TMP11]], 1 ; DLQ-NEXT: [[TMP13:%.*]] = fpext double [[C]] to x86_fp80 ; DLQ-NEXT: [[TMP14:%.*]] = select i1 [[TMP12]], x86_fp80 [[TMP13]], x86_fp80 [[TMP8]] ; DLQ-NEXT: store x86_fp80 [[TMP14]], ptr [[TMP9]], align 1 ; DLQ-NEXT: store double [[C]], ptr [[A]], align 1 ; DLQ-NEXT: ret void ; entry: %b = load double, ptr %a, align 1 %c = fadd double %b, 1.0 store double %c, ptr %a, align 1 ret void } define void @load_add_store_vector(<2 x float>* %a) sanitize_numerical_stability { ; CHECK-LABEL: @load_add_store_vector( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[B:%.*]] = load <2 x float>, ptr [[A:%.*]], align 1 ; CHECK-NEXT: [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[A]], i64 2) ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq ptr [[TMP0]], null ; CHECK-NEXT: br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]] ; CHECK: 2: ; CHECK-NEXT: [[TMP3:%.*]] = load <2 x double>, ptr [[TMP0]], align 1 ; CHECK-NEXT: br label [[TMP6:%.*]] ; CHECK: 4: ; CHECK-NEXT: [[TMP5:%.*]] = fpext <2 x float> [[B]] to <2 x double> ; CHECK-NEXT: br label [[TMP6]] ; CHECK: 6: ; CHECK-NEXT: [[TMP7:%.*]] = phi <2 x double> [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ] ; CHECK-NEXT: [[C:%.*]] = fadd <2 x float> [[B]], splat (float 1.000000e+00) ; CHECK-NEXT: [[TMP8:%.*]] = fadd <2 x double> [[TMP7]], splat (double 1.000000e+00) ; CHECK-NEXT: [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[A]], i64 2) ; CHECK-NEXT: [[TMP10:%.*]] = extractelement <2 x float> [[C]], i64 0 ; CHECK-NEXT: [[TMP11:%.*]] = extractelement <2 x double> [[TMP8]], i64 0 ; CHECK-NEXT: [[TMP12:%.*]] = ptrtoint ptr [[A]] to i64 ; CHECK-NEXT: [[TMP13:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP10]], double [[TMP11]], i32 4, i64 [[TMP12]]) ; CHECK-NEXT: [[TMP14:%.*]] = extractelement <2 x float> [[C]], i64 1 ; CHECK-NEXT: [[TMP15:%.*]] = extractelement <2 x double> [[TMP8]], i64 1 ; CHECK-NEXT: [[TMP16:%.*]] = ptrtoint ptr [[A]] to i64 ; CHECK-NEXT: [[TMP17:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP14]], double [[TMP15]], i32 4, i64 [[TMP16]]) ; CHECK-NEXT: [[TMP18:%.*]] = or i32 [[TMP13]], [[TMP17]] ; CHECK-NEXT: [[TMP19:%.*]] = icmp eq i32 [[TMP18]], 1 ; CHECK-NEXT: [[TMP20:%.*]] = fpext <2 x float> [[C]] to <2 x double> ; CHECK-NEXT: [[TMP21:%.*]] = select i1 [[TMP19]], <2 x double> [[TMP20]], <2 x double> [[TMP8]] ; CHECK-NEXT: store <2 x double> [[TMP21]], ptr [[TMP9]], align 1 ; CHECK-NEXT: store <2 x float> [[C]], ptr [[A]], align 1 ; CHECK-NEXT: ret void ; entry: %b = load <2 x float>, ptr %a, align 1 %c = fadd <2 x float> %b, store <2 x float> %c, ptr %a, align 1 ret void } declare float @returns_float() define void @call_fn_returning_float(ptr %dst) sanitize_numerical_stability { ; CHECK-LABEL: @call_fn_returning_float( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[B:%.*]] = call float @returns_float() ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @returns_float to i64) ; CHECK-NEXT: [[TMP2:%.*]] = load double, ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: [[TMP3:%.*]] = fpext float [[B]] to double ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]] ; CHECK-NEXT: [[C:%.*]] = fadd float [[B]], 1.000000e+00 ; CHECK-NEXT: [[TMP5:%.*]] = fadd double [[TMP4]], 1.000000e+00 ; CHECK-NEXT: [[TMP6:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[DST:%.*]], i64 1) ; CHECK-NEXT: [[TMP7:%.*]] = ptrtoint ptr [[DST]] to i64 ; CHECK-NEXT: [[TMP8:%.*]] = call i32 @__nsan_internal_check_float_d(float [[C]], double [[TMP5]], i32 4, i64 [[TMP7]]) ; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 1 ; CHECK-NEXT: [[TMP10:%.*]] = fpext float [[C]] to double ; CHECK-NEXT: [[TMP11:%.*]] = select i1 [[TMP9]], double [[TMP10]], double [[TMP5]] ; CHECK-NEXT: store double [[TMP11]], ptr [[TMP6]], align 1 ; CHECK-NEXT: store float [[C]], ptr [[DST]], align 1 ; CHECK-NEXT: ret void ; entry: %b = call float @returns_float() %c = fadd float %b, 1.0 store float %c, ptr %dst, align 1 ret void } define float @return_fn_returning_float(ptr %dst) sanitize_numerical_stability { ; CHECK-LABEL: @return_fn_returning_float( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[B:%.*]] = call float @returns_float() ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @returns_float to i64) ; CHECK-NEXT: [[TMP2:%.*]] = load double, ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: [[TMP3:%.*]] = fpext float [[B]] to double ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]] ; CHECK-NEXT: [[TMP5:%.*]] = call i32 @__nsan_internal_check_float_d(float [[B]], double [[TMP4]], i32 1, i64 0) ; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 1 ; CHECK-NEXT: [[TMP7:%.*]] = fpext float [[B]] to double ; CHECK-NEXT: [[TMP8:%.*]] = select i1 [[TMP6]], double [[TMP7]], double [[TMP4]] ; CHECK-NEXT: store i64 ptrtoint (ptr @return_fn_returning_float to i64), ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: store double [[TMP8]], ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: ret float [[B]] ; entry: %b = call float @returns_float() ret float %b } declare void @takes_floats(float %a, i8 %b, double %c, x86_fp80 %d) define void @call_fn_taking_float() sanitize_numerical_stability { ; DQQ-LABEL: @call_fn_taking_float( ; DQQ-NEXT: entry: ; DQQ-NEXT: store ptr @takes_floats, ptr @__nsan_shadow_args_tag, align 8 ; DQQ-NEXT: store double 1.000000e+00, ptr @__nsan_shadow_args_ptr, align 1 ; DQQ-NEXT: store fp128 0xL00000000000000004000800000000000, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 8), align 1 ; DQQ-NEXT: store fp128 0xLC0000000000000003FC9CD2B297D889B, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 24), align 1 ; DQQ-NEXT: call void @takes_floats(float 1.000000e+00, i8 2, double 3.000000e+00, x86_fp80 0xK3FC9E69594BEC44DE000) ; DQQ-NEXT: ret void ; ; DLQ-LABEL: @call_fn_taking_float( ; DLQ-NEXT: entry: ; DLQ-NEXT: store ptr @takes_floats, ptr @__nsan_shadow_args_tag, align 8 ; DLQ-NEXT: store double 1.000000e+00, ptr @__nsan_shadow_args_ptr, align 1 ; DLQ-NEXT: store x86_fp80 0xK4000C000000000000000, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 8), align 1 ; DLQ-NEXT: store fp128 0xLC0000000000000003FC9CD2B297D889B, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 18), align 1 ; DLQ-NEXT: call void @takes_floats(float 1.000000e+00, i8 2, double 3.000000e+00, x86_fp80 0xK3FC9E69594BEC44DE000) ; DLQ-NEXT: ret void ; entry: call void @takes_floats(float 1.0, i8 2, double 3.0, x86_fp80 0xK3FC9E69594BEC44DE000) ret void } declare float @llvm.sin.f32(float) readnone define float @call_sin_intrinsic() sanitize_numerical_stability { ; CHECK-LABEL: @call_sin_intrinsic( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[R:%.*]] = call float @llvm.sin.f32(float 1.000000e+00) ; CHECK-NEXT: [[TMP0:%.*]] = call double @llvm.sin.f64(double 1.000000e+00) ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP0]], i32 1, i64 0) ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 1 ; CHECK-NEXT: [[TMP3:%.*]] = fpext float [[R]] to double ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], double [[TMP3]], double [[TMP0]] ; CHECK-NEXT: store i64 ptrtoint (ptr @call_sin_intrinsic to i64), ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: store double [[TMP4]], ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: ret float [[R]] ; entry: %r = call float @llvm.sin.f32(float 1.0) ret float %r } declare float @sinf(float) define float @call_sinf_libfunc() sanitize_numerical_stability { ; CHECK-LABEL: @call_sinf_libfunc( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[R:%.*]] = call float @sinf(float 1.000000e+00) #[[ATTR4:[0-9]+]] ; CHECK-NEXT: [[TMP0:%.*]] = call double @llvm.sin.f64(double 1.000000e+00) ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP0]], i32 1, i64 0) ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 1 ; CHECK-NEXT: [[TMP3:%.*]] = fpext float [[R]] to double ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], double [[TMP3]], double [[TMP0]] ; CHECK-NEXT: store i64 ptrtoint (ptr @call_sinf_libfunc to i64), ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: store double [[TMP4]], ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: ret float [[R]] ; entry: %r = call float @sinf(float 1.0) ret float %r } declare double @sin(double) ; FIXME: nsan uses `sin(double)` for fp128. define double @call_sin_libfunc() sanitize_numerical_stability { ; DQQ-LABEL: @call_sin_libfunc( ; DQQ-NEXT: entry: ; DQQ-NEXT: [[R:%.*]] = call double @sin(double 1.000000e+00) #[[ATTR4]] ; DQQ-NEXT: [[TMP0:%.*]] = call x86_fp80 @llvm.sin.f80(x86_fp80 0xK3FFF8000000000000000) ; DQQ-NEXT: [[TMP1:%.*]] = fpext x86_fp80 [[TMP0]] to fp128 ; DQQ-NEXT: [[TMP2:%.*]] = call i32 @__nsan_internal_check_double_q(double [[R]], fp128 [[TMP1]], i32 1, i64 0) ; DQQ-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 1 ; DQQ-NEXT: [[TMP4:%.*]] = fpext double [[R]] to fp128 ; DQQ-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], fp128 [[TMP4]], fp128 [[TMP1]] ; DQQ-NEXT: store i64 ptrtoint (ptr @call_sin_libfunc to i64), ptr @__nsan_shadow_ret_tag, align 8 ; DQQ-NEXT: store fp128 [[TMP5]], ptr @__nsan_shadow_ret_ptr, align 16 ; DQQ-NEXT: ret double [[R]] ; ; DLQ-LABEL: @call_sin_libfunc( ; DLQ-NEXT: entry: ; DLQ-NEXT: [[R:%.*]] = call double @sin(double 1.000000e+00) #[[ATTR4]] ; DLQ-NEXT: [[TMP0:%.*]] = call x86_fp80 @llvm.sin.f80(x86_fp80 0xK3FFF8000000000000000) ; DLQ-NEXT: [[TMP1:%.*]] = call i32 @__nsan_internal_check_double_l(double [[R]], x86_fp80 [[TMP0]], i32 1, i64 0) ; DLQ-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 1 ; DLQ-NEXT: [[TMP3:%.*]] = fpext double [[R]] to x86_fp80 ; DLQ-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], x86_fp80 [[TMP3]], x86_fp80 [[TMP0]] ; DLQ-NEXT: store i64 ptrtoint (ptr @call_sin_libfunc to i64), ptr @__nsan_shadow_ret_tag, align 8 ; DLQ-NEXT: store x86_fp80 [[TMP4]], ptr @__nsan_shadow_ret_ptr, align 16 ; DLQ-NEXT: ret double [[R]] ; entry: %r = call double @sin(double 1.0) ret double %r } declare double @frexp(double, i32*) define double @call_frexp_libfunc_nointrinsic(double %0, i32* nocapture %1) sanitize_numerical_stability { ; DQQ-LABEL: @call_frexp_libfunc_nointrinsic( ; DQQ-NEXT: [[TMP3:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; DQQ-NEXT: [[TMP4:%.*]] = icmp eq i64 [[TMP3]], ptrtoint (ptr @call_frexp_libfunc_nointrinsic to i64) ; DQQ-NEXT: [[TMP5:%.*]] = load fp128, ptr @__nsan_shadow_args_ptr, align 1 ; DQQ-NEXT: [[TMP6:%.*]] = fpext double [[TMP0:%.*]] to fp128 ; DQQ-NEXT: [[TMP7:%.*]] = select i1 [[TMP4]], fp128 [[TMP5]], fp128 [[TMP6]] ; DQQ-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; DQQ-NEXT: [[TMP8:%.*]] = call i32 @__nsan_internal_check_double_q(double [[TMP0]], fp128 [[TMP7]], i32 2, i64 0) ; DQQ-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 1 ; DQQ-NEXT: [[TMP10:%.*]] = fpext double [[TMP0]] to fp128 ; DQQ-NEXT: [[TMP11:%.*]] = select i1 [[TMP9]], fp128 [[TMP10]], fp128 [[TMP7]] ; DQQ-NEXT: [[TMP12:%.*]] = tail call double @frexp(double [[TMP0]], ptr [[TMP1:%.*]]) ; DQQ-NEXT: [[TMP13:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8 ; DQQ-NEXT: [[TMP14:%.*]] = icmp eq i64 [[TMP13]], ptrtoint (ptr @frexp to i64) ; DQQ-NEXT: [[TMP15:%.*]] = load fp128, ptr @__nsan_shadow_ret_ptr, align 16 ; DQQ-NEXT: [[TMP16:%.*]] = fpext double [[TMP12]] to fp128 ; DQQ-NEXT: [[TMP17:%.*]] = select i1 [[TMP14]], fp128 [[TMP15]], fp128 [[TMP16]] ; DQQ-NEXT: [[TMP18:%.*]] = call i32 @__nsan_internal_check_double_q(double [[TMP12]], fp128 [[TMP17]], i32 1, i64 0) ; DQQ-NEXT: [[TMP19:%.*]] = icmp eq i32 [[TMP18]], 1 ; DQQ-NEXT: [[TMP20:%.*]] = fpext double [[TMP12]] to fp128 ; DQQ-NEXT: [[TMP21:%.*]] = select i1 [[TMP19]], fp128 [[TMP20]], fp128 [[TMP17]] ; DQQ-NEXT: store i64 ptrtoint (ptr @call_frexp_libfunc_nointrinsic to i64), ptr @__nsan_shadow_ret_tag, align 8 ; DQQ-NEXT: store fp128 [[TMP21]], ptr @__nsan_shadow_ret_ptr, align 16 ; DQQ-NEXT: ret double [[TMP12]] ; ; DLQ-LABEL: @call_frexp_libfunc_nointrinsic( ; DLQ-NEXT: [[TMP3:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; DLQ-NEXT: [[TMP4:%.*]] = icmp eq i64 [[TMP3]], ptrtoint (ptr @call_frexp_libfunc_nointrinsic to i64) ; DLQ-NEXT: [[TMP5:%.*]] = load x86_fp80, ptr @__nsan_shadow_args_ptr, align 1 ; DLQ-NEXT: [[TMP6:%.*]] = fpext double [[TMP0:%.*]] to x86_fp80 ; DLQ-NEXT: [[TMP7:%.*]] = select i1 [[TMP4]], x86_fp80 [[TMP5]], x86_fp80 [[TMP6]] ; DLQ-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; DLQ-NEXT: [[TMP8:%.*]] = call i32 @__nsan_internal_check_double_l(double [[TMP0]], x86_fp80 [[TMP7]], i32 2, i64 0) ; DLQ-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 1 ; DLQ-NEXT: [[TMP10:%.*]] = fpext double [[TMP0]] to x86_fp80 ; DLQ-NEXT: [[TMP11:%.*]] = select i1 [[TMP9]], x86_fp80 [[TMP10]], x86_fp80 [[TMP7]] ; DLQ-NEXT: [[TMP12:%.*]] = tail call double @frexp(double [[TMP0]], ptr [[TMP1:%.*]]) ; DLQ-NEXT: [[TMP13:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8 ; DLQ-NEXT: [[TMP14:%.*]] = icmp eq i64 [[TMP13]], ptrtoint (ptr @frexp to i64) ; DLQ-NEXT: [[TMP15:%.*]] = load x86_fp80, ptr @__nsan_shadow_ret_ptr, align 16 ; DLQ-NEXT: [[TMP16:%.*]] = fpext double [[TMP12]] to x86_fp80 ; DLQ-NEXT: [[TMP17:%.*]] = select i1 [[TMP14]], x86_fp80 [[TMP15]], x86_fp80 [[TMP16]] ; DLQ-NEXT: [[TMP18:%.*]] = call i32 @__nsan_internal_check_double_l(double [[TMP12]], x86_fp80 [[TMP17]], i32 1, i64 0) ; DLQ-NEXT: [[TMP19:%.*]] = icmp eq i32 [[TMP18]], 1 ; DLQ-NEXT: [[TMP20:%.*]] = fpext double [[TMP12]] to x86_fp80 ; DLQ-NEXT: [[TMP21:%.*]] = select i1 [[TMP19]], x86_fp80 [[TMP20]], x86_fp80 [[TMP17]] ; DLQ-NEXT: store i64 ptrtoint (ptr @call_frexp_libfunc_nointrinsic to i64), ptr @__nsan_shadow_ret_tag, align 8 ; DLQ-NEXT: store x86_fp80 [[TMP21]], ptr @__nsan_shadow_ret_ptr, align 16 ; DLQ-NEXT: ret double [[TMP12]] ; %3 = tail call double @frexp(double %0, i32* %1) ret double %3 } define float @call_fn_taking_float_by_fn_ptr(float (float)* nocapture %fn_ptr) sanitize_numerical_stability { ; CHECK-LABEL: @call_fn_taking_float_by_fn_ptr( ; CHECK-NEXT: entry: ; CHECK-NEXT: store ptr [[FN_PTR:%.*]], ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: store double 1.000000e+00, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[R:%.*]] = call float [[FN_PTR]](float 1.000000e+00) ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[FN_PTR]] to i64 ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP0]], [[TMP1]] ; CHECK-NEXT: [[TMP3:%.*]] = load double, ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: [[TMP4:%.*]] = fpext float [[R]] to double ; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], double [[TMP3]], double [[TMP4]] ; CHECK-NEXT: [[TMP6:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP5]], i32 1, i64 0) ; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1 ; CHECK-NEXT: [[TMP8:%.*]] = fpext float [[R]] to double ; CHECK-NEXT: [[TMP9:%.*]] = select i1 [[TMP7]], double [[TMP8]], double [[TMP5]] ; CHECK-NEXT: store i64 ptrtoint (ptr @call_fn_taking_float_by_fn_ptr to i64), ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: store double [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: ret float [[R]] ; entry: %r = call float %fn_ptr(float 1.0) ret float %r } define void @store_float(ptr %dst) sanitize_numerical_stability { ; CHECK-LABEL: @store_float( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[DST:%.*]], i64 1) ; CHECK-NEXT: store double 4.200000e+01, ptr [[TMP0]], align 1 ; CHECK-NEXT: store float 4.200000e+01, ptr [[DST]], align 1 ; CHECK-NEXT: ret void ; entry: store float 42.0, ptr %dst, align 1 ret void } define i1 @inline_asm(double %0) sanitize_numerical_stability { ; DQQ-LABEL: @inline_asm( ; DQQ-NEXT: entry: ; DQQ-NEXT: [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; DQQ-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @inline_asm to i64) ; DQQ-NEXT: [[TMP3:%.*]] = load fp128, ptr @__nsan_shadow_args_ptr, align 1 ; DQQ-NEXT: [[TMP4:%.*]] = fpext double [[TMP0:%.*]] to fp128 ; DQQ-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], fp128 [[TMP3]], fp128 [[TMP4]] ; DQQ-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; DQQ-NEXT: [[TMP6:%.*]] = call i32 asm "pmovmskb $1, $0", "=r,x,~{dirflag},~{fpsr},~{flags}"(double [[TMP0]]) ; DQQ-NEXT: [[TMP7:%.*]] = trunc i32 [[TMP6]] to i8 ; DQQ-NEXT: [[TMP8:%.*]] = icmp slt i8 [[TMP7]], 0 ; DQQ-NEXT: ret i1 [[TMP8]] ; ; DLQ-LABEL: @inline_asm( ; DLQ-NEXT: entry: ; DLQ-NEXT: [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; DLQ-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @inline_asm to i64) ; DLQ-NEXT: [[TMP3:%.*]] = load x86_fp80, ptr @__nsan_shadow_args_ptr, align 1 ; DLQ-NEXT: [[TMP4:%.*]] = fpext double [[TMP0:%.*]] to x86_fp80 ; DLQ-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], x86_fp80 [[TMP3]], x86_fp80 [[TMP4]] ; DLQ-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; DLQ-NEXT: [[TMP6:%.*]] = call i32 asm "pmovmskb $1, $0", "=r,x,~{dirflag},~{fpsr},~{flags}"(double [[TMP0]]) ; DLQ-NEXT: [[TMP7:%.*]] = trunc i32 [[TMP6]] to i8 ; DLQ-NEXT: [[TMP8:%.*]] = icmp slt i8 [[TMP7]], 0 ; DLQ-NEXT: ret i1 [[TMP8]] ; entry: %1 = call i32 asm "pmovmskb $1, $0", "=r,x,~{dirflag},~{fpsr},~{flags}"(double %0) %2 = trunc i32 %1 to i8 %3 = icmp slt i8 %2, 0 ret i1 %3 } define void @vector_extract(<2 x float> %0) sanitize_numerical_stability { ; CHECK-LABEL: @vector_extract( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @vector_extract to i64) ; CHECK-NEXT: [[TMP3:%.*]] = load <2 x double>, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP4:%.*]] = fpext <2 x float> [[TMP0:%.*]] to <2 x double> ; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], <2 x double> [[TMP3]], <2 x double> [[TMP4]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP6:%.*]] = extractelement <2 x float> [[TMP0]], i32 1 ; CHECK-NEXT: [[TMP7:%.*]] = extractelement <2 x double> [[TMP5]], i32 1 ; CHECK-NEXT: ret void ; entry: %1 = extractelement <2 x float> %0, i32 1 ret void } define void @vector_insert(<2 x float> %0) sanitize_numerical_stability { ; CHECK-LABEL: @vector_insert( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @vector_insert to i64) ; CHECK-NEXT: [[TMP3:%.*]] = load <2 x double>, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP4:%.*]] = fpext <2 x float> [[TMP0:%.*]] to <2 x double> ; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], <2 x double> [[TMP3]], <2 x double> [[TMP4]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP6:%.*]] = insertelement <2 x float> [[TMP0]], float 1.000000e+00, i32 1 ; CHECK-NEXT: [[TMP7:%.*]] = insertelement <2 x double> [[TMP5]], double 1.000000e+00, i32 1 ; CHECK-NEXT: ret void ; entry: %1 = insertelement <2 x float> %0, float 1.0, i32 1 ret void } define void @freeze_vector_insert(<2 x float> %vec, i32 %idx, float %scalar) sanitize_numerical_stability { ; CHECK-LABEL: @freeze_vector_insert( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @freeze_vector_insert to i64) ; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP3:%.*]] = fpext <2 x float> [[VEC:%.*]] to <2 x double> ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], <2 x double> [[TMP2]], <2 x double> [[TMP3]] ; CHECK-NEXT: [[TMP5:%.*]] = load double, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 16), align 1 ; CHECK-NEXT: [[TMP6:%.*]] = fpext float [[SCALAR:%.*]] to double ; CHECK-NEXT: [[TMP7:%.*]] = select i1 [[TMP1]], double [[TMP5]], double [[TMP6]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP8:%.*]] = insertelement <2 x float> [[VEC]], float [[SCALAR]], i32 [[IDX:%.*]] ; CHECK-NEXT: [[TMP9:%.*]] = insertelement <2 x double> [[TMP4]], double [[TMP7]], i32 [[IDX]] ; CHECK-NEXT: [[FROZEN:%.*]] = freeze <2 x float> [[TMP8]] ; CHECK-NEXT: [[TMP10:%.*]] = freeze <2 x double> [[TMP9]] ; CHECK-NEXT: ret void ; entry: %1 = insertelement <2 x float> %vec, float %scalar, i32 %idx %frozen = freeze <2 x float> %1 ret void } define void @vector_shuffle(<2 x float> %0) sanitize_numerical_stability { ; CHECK-LABEL: @vector_shuffle( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @vector_shuffle to i64) ; CHECK-NEXT: [[TMP3:%.*]] = load <2 x double>, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP4:%.*]] = fpext <2 x float> [[TMP0:%.*]] to <2 x double> ; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], <2 x double> [[TMP3]], <2 x double> [[TMP4]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <2 x float> [[TMP0]], <2 x float> splat (float 1.000000e+00), <2 x i32> ; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x double> [[TMP5]], <2 x double> splat (double 1.000000e+00), <2 x i32> ; CHECK-NEXT: ret void ; entry: %1 = shufflevector <2 x float> %0, <2 x float> , <2 x i32> ret void } define void @aggregate_extract({i32, {float, i1}} %0) sanitize_numerical_stability { ; CHECK-LABEL: @aggregate_extract( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, { float, i1 } } [[TMP0:%.*]], 1, 0 ; CHECK-NEXT: [[TMP2:%.*]] = fpext float [[TMP1]] to double ; CHECK-NEXT: ret void ; entry: %1 = extractvalue {i32, {float, i1}} %0, 1, 0 ret void } define void @aggregate_insert({i32, {float, i1}} %0, float %1) sanitize_numerical_stability { ; CHECK-LABEL: @aggregate_insert( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], ptrtoint (ptr @aggregate_insert to i64) ; CHECK-NEXT: [[TMP4:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP5:%.*]] = fpext float [[TMP1:%.*]] to double ; CHECK-NEXT: [[TMP6:%.*]] = select i1 [[TMP3]], double [[TMP4]], double [[TMP5]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP7:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP1]], double [[TMP6]], i32 5, i64 0) ; CHECK-NEXT: [[TMP8:%.*]] = icmp eq i32 [[TMP7]], 1 ; CHECK-NEXT: [[TMP9:%.*]] = fpext float [[TMP1]] to double ; CHECK-NEXT: [[TMP10:%.*]] = select i1 [[TMP8]], double [[TMP9]], double [[TMP6]] ; CHECK-NEXT: [[TMP11:%.*]] = insertvalue { i32, { float, i1 } } [[TMP0:%.*]], float [[TMP1]], 1, 0 ; CHECK-NEXT: ret void ; entry: %2 = insertvalue {i32, {float, i1}} %0, float %1, 1, 0 ret void } define void @aggregate_insert_avoid_const_check({i32, {float, i1}} %0) sanitize_numerical_stability { ; CHECK-LABEL: @aggregate_insert_avoid_const_check( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, { float, i1 } } [[TMP0:%.*]], float 1.000000e+00, 1, 0 ; CHECK-NEXT: ret void ; entry: %1 = insertvalue {i32, {float, i1}} %0, float 1.0, 1, 0 ret void } declare float @fabsf(float) define float @sub_fabs(float %a, float %b) sanitize_numerical_stability { ; CHECK-LABEL: @sub_fabs( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @sub_fabs to i64) ; CHECK-NEXT: [[TMP2:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP3:%.*]] = fpext float [[A:%.*]] to double ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]] ; CHECK-NEXT: [[TMP5:%.*]] = load double, ptr getelementptr ([16384 x i8], ptr @__nsan_shadow_args_ptr, i64 0, i64 8), align 1 ; CHECK-NEXT: [[TMP6:%.*]] = fpext float [[B:%.*]] to double ; CHECK-NEXT: [[TMP7:%.*]] = select i1 [[TMP1]], double [[TMP5]], double [[TMP6]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[S:%.*]] = fsub float [[A]], [[B]] ; CHECK-NEXT: [[TMP8:%.*]] = fsub double [[TMP4]], [[TMP7]] ; CHECK-NEXT: [[TMP9:%.*]] = call i32 @__nsan_internal_check_float_d(float [[S]], double [[TMP8]], i32 2, i64 0) ; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i32 [[TMP9]], 1 ; CHECK-NEXT: [[TMP11:%.*]] = fpext float [[S]] to double ; CHECK-NEXT: [[TMP12:%.*]] = select i1 [[TMP10]], double [[TMP11]], double [[TMP8]] ; CHECK-NEXT: [[R:%.*]] = call float @fabsf(float [[S]]) #[[ATTR4]] ; CHECK-NEXT: [[TMP13:%.*]] = call double @llvm.fabs.f64(double [[TMP8]]) ; CHECK-NEXT: [[TMP14:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP13]], i32 1, i64 0) ; CHECK-NEXT: [[TMP15:%.*]] = icmp eq i32 [[TMP14]], 1 ; CHECK-NEXT: [[TMP16:%.*]] = fpext float [[R]] to double ; CHECK-NEXT: [[TMP17:%.*]] = select i1 [[TMP15]], double [[TMP16]], double [[TMP13]] ; CHECK-NEXT: store i64 ptrtoint (ptr @sub_fabs to i64), ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: store double [[TMP17]], ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: ret float [[R]] ; entry: %s = fsub float %a, %b %r = call float @fabsf(float %s) ret float %r } ; Note that the `unsafe-fp-math` from the function attributes should be moved to ; individual instructions, with the shadow instructions NOT getting the attribute. define float @param_add_return_float_unsafe_fp_math(float %a) #0 { ; CHECK-LABEL: @param_add_return_float_unsafe_fp_math( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @param_add_return_float_unsafe_fp_math to i64) ; CHECK-NEXT: [[TMP2:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP3:%.*]] = fpext float [[A:%.*]] to double ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[B:%.*]] = fadd fast float [[A]], 1.000000e+00 ; CHECK-NEXT: [[TMP5:%.*]] = fadd double [[TMP4]], 1.000000e+00 ; CHECK-NEXT: [[TMP6:%.*]] = call i32 @__nsan_internal_check_float_d(float [[B]], double [[TMP5]], i32 1, i64 0) ; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 1 ; CHECK-NEXT: [[TMP8:%.*]] = fpext float [[B]] to double ; CHECK-NEXT: [[TMP9:%.*]] = select i1 [[TMP7]], double [[TMP8]], double [[TMP5]] ; CHECK-NEXT: store i64 ptrtoint (ptr @param_add_return_float_unsafe_fp_math to i64), ptr @__nsan_shadow_ret_tag, align 8 ; CHECK-NEXT: store double [[TMP9]], ptr @__nsan_shadow_ret_ptr, align 8 ; CHECK-NEXT: ret float [[B]] ; entry: %b = fadd float %a, 1.0 ret float %b } define void @truncate(<2 x double> %0) sanitize_numerical_stability { ; DQQ-LABEL: @truncate( ; DQQ-NEXT: entry: ; DQQ-NEXT: [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; DQQ-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @truncate to i64) ; DQQ-NEXT: [[TMP3:%.*]] = load <2 x fp128>, ptr @__nsan_shadow_args_ptr, align 1 ; DQQ-NEXT: [[TMP4:%.*]] = fpext <2 x double> [[TMP0:%.*]] to <2 x fp128> ; DQQ-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], <2 x fp128> [[TMP3]], <2 x fp128> [[TMP4]] ; DQQ-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; DQQ-NEXT: [[TMP6:%.*]] = fptrunc <2 x double> [[TMP0]] to <2 x float> ; DQQ-NEXT: [[TMP7:%.*]] = fptrunc <2 x fp128> [[TMP5]] to <2 x double> ; DQQ-NEXT: ret void ; ; DLQ-LABEL: @truncate( ; DLQ-NEXT: entry: ; DLQ-NEXT: [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; DLQ-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @truncate to i64) ; DLQ-NEXT: [[TMP3:%.*]] = load <2 x x86_fp80>, ptr @__nsan_shadow_args_ptr, align 1 ; DLQ-NEXT: [[TMP4:%.*]] = fpext <2 x double> [[TMP0:%.*]] to <2 x x86_fp80> ; DLQ-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], <2 x x86_fp80> [[TMP3]], <2 x x86_fp80> [[TMP4]] ; DLQ-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; DLQ-NEXT: [[TMP6:%.*]] = fptrunc <2 x double> [[TMP0]] to <2 x float> ; DLQ-NEXT: [[TMP7:%.*]] = fptrunc <2 x x86_fp80> [[TMP5]] to <2 x double> ; DLQ-NEXT: ret void ; entry: %1 = fptrunc <2 x double> %0 to <2 x float> ret void } define void @unaryop(float %a) sanitize_numerical_stability { ; CHECK-LABEL: @unaryop( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], ptrtoint (ptr @unaryop to i64) ; CHECK-NEXT: [[TMP2:%.*]] = load double, ptr @__nsan_shadow_args_ptr, align 1 ; CHECK-NEXT: [[TMP3:%.*]] = fpext float [[A:%.*]] to double ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP1]], double [[TMP2]], double [[TMP3]] ; CHECK-NEXT: store i64 0, ptr @__nsan_shadow_args_tag, align 8 ; CHECK-NEXT: [[C:%.*]] = fneg float [[A]] ; CHECK-NEXT: [[TMP5:%.*]] = fneg double [[TMP4]] ; CHECK-NEXT: ret void ; entry: %c = fneg float %a ret void } attributes #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" }