Reapply "[LLVM][Instrumentation] Add numerical sanitizer (#85916)"

This reverts commit 493c384a7d
and includes a fix for the build breakage.
This commit is contained in:
Alexander Shaposhnikov
2024-06-29 09:00:26 +00:00
parent 4a835480fa
commit 1710679237
11 changed files with 3818 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
//===- NumericalStabilitySanitizer.h - NSan Pass ---------------*- C++ -*--===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// \file
// This file defines the numerical stability sanitizer (nsan) pass.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_NUMERICALSTABIITYSANITIZER_H
#define LLVM_TRANSFORMS_INSTRUMENTATION_NUMERICALSTABIITYSANITIZER_H
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
namespace llvm {
/// A function pass for nsan instrumentation.
///
/// Instruments functions to duplicate floating point computations in a
/// higher-precision type.
/// This pass inserts calls to runtime library functions. If the
/// functions aren't declared yet, the pass inserts the declarations.
struct NumericalStabilitySanitizerPass
: public PassInfoMixin<NumericalStabilitySanitizerPass> {
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
static bool isRequired() { return true; }
};
} // end namespace llvm
#endif // LLVM_TRANSFORMS_INSTRUMENTATION_NUMERICALSTABIITYSANITIZER_H

View File

@@ -184,6 +184,7 @@
#include "llvm/Transforms/Instrumentation/LowerAllowCheckPass.h"
#include "llvm/Transforms/Instrumentation/MemProfiler.h"
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
#include "llvm/Transforms/Instrumentation/NumericalStabilitySanitizer.h"
#include "llvm/Transforms/Instrumentation/PGOCtxProfLowering.h"
#include "llvm/Transforms/Instrumentation/PGOForceFunctionAttrs.h"
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"

View File

@@ -94,6 +94,7 @@ MODULE_PASS("metarenamer", MetaRenamerPass())
MODULE_PASS("module-inline", ModuleInlinerPass())
MODULE_PASS("name-anon-globals", NameAnonGlobalPass())
MODULE_PASS("no-op-module", NoOpModulePass())
MODULE_PASS("nsan", NumericalStabilitySanitizerPass())
MODULE_PASS("objc-arc-apelim", ObjCARCAPElimPass())
MODULE_PASS("openmp-opt", OpenMPOptPass())
MODULE_PASS("openmp-opt-postlink",

View File

@@ -8,6 +8,7 @@ add_llvm_component_library(LLVMInstrumentation
BlockCoverageInference.cpp
MemProfiler.cpp
MemorySanitizer.cpp
NumericalStabilitySanitizer.cpp
IndirectCallPromotion.cpp
Instrumentation.cpp
InstrOrderFile.cpp

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,916 @@
; 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
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"
; 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]], <float 1.000000e+00, float 1.000000e+00>
; CHECK-NEXT: [[TMP5:%.*]] = fadd <2 x double> [[TMP4]], <double 1.000000e+00, 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, <float 1.0, float 1.0>
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]], <float 1.000000e+00, float 1.000000e+00>
; CHECK-NEXT: [[TMP8:%.*]] = fadd <2 x double> [[TMP7]], <double 1.000000e+00, 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, <float 1.0, float 1.0>
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 @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> <float 1.000000e+00, float 1.000000e+00>, <2 x i32> <i32 1, i32 3>
; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x double> [[TMP5]], <2 x double> <double 1.000000e+00, double 1.000000e+00>, <2 x i32> <i32 1, i32 3>
; CHECK-NEXT: ret void
;
entry:
%1 = shufflevector <2 x float> %0, <2 x float> <float 1.0, float 1.0>, <2 x i32> <i32 1, i32 3>
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" }

View File

@@ -0,0 +1,112 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=nsan -nsan-shadow-type-mapping=dqq -S | FileCheck %s
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"
; Tests with more involved control flow to check lazy construction of the
; shadow values.
define float @forward_use() sanitize_numerical_stability {
; CHECK-LABEL: @forward_use(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[BLOCK1:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[D:%.*]] = fadd float [[B:%.*]], 2.000000e+00
; CHECK-NEXT: [[TMP0:%.*]] = fadd double [[TMP2:%.*]], 2.000000e+00
; CHECK-NEXT: br label [[BLOCK1]]
; CHECK: block1:
; CHECK-NEXT: [[A:%.*]] = phi float [ [[D]], [[LOOP:%.*]] ], [ 1.000000e+00, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[TMP1:%.*]] = phi double [ [[TMP0]], [[LOOP]] ], [ 1.000000e+00, [[ENTRY]] ]
; CHECK-NEXT: [[B]] = fadd float [[A]], 1.000000e+00
; CHECK-NEXT: [[TMP2]] = fadd double [[TMP1]], 1.000000e+00
; CHECK-NEXT: br label [[LOOP]]
;
entry:
br label %block1
loop:
%d = fadd float %b, 2.0 ; this is a forward reference, requiring shadow(%b) to be available.
br label %block1
block1:
%a = phi float [ %d, %loop], [ 1.0, %entry ]
%b = fadd float %a, 1.0
br label %loop
}
define float @forward_use_with_load(float* %p) sanitize_numerical_stability {
; CHECK-LABEL: @forward_use_with_load(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[BLOCK1:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[D:%.*]] = fadd float [[B:%.*]], 2.000000e+00
; CHECK-NEXT: [[TMP0:%.*]] = fadd double [[TMP10:%.*]], 2.000000e+00
; CHECK-NEXT: br label [[BLOCK1]]
; CHECK: block1:
; CHECK-NEXT: [[A:%.*]] = phi float [ [[D]], [[LOOP:%.*]] ], [ 1.000000e+00, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[TMP1:%.*]] = phi double [ [[TMP0]], [[LOOP]] ], [ 1.000000e+00, [[ENTRY]] ]
; CHECK-NEXT: [[L:%.*]] = load float, ptr [[P:%.*]], align 4
; CHECK-NEXT: [[TMP2:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[P]], i64 1)
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq ptr [[TMP2]], null
; CHECK-NEXT: br i1 [[TMP3]], label [[TMP6:%.*]], label [[TMP4:%.*]]
; CHECK: 4:
; CHECK-NEXT: [[TMP5:%.*]] = load double, ptr [[TMP2]], align 1
; CHECK-NEXT: br label [[TMP8:%.*]]
; CHECK: 6:
; CHECK-NEXT: [[TMP7:%.*]] = fpext float [[L]] to double
; CHECK-NEXT: br label [[TMP8]]
; CHECK: 8:
; CHECK-NEXT: [[TMP9:%.*]] = phi double [ [[TMP5]], [[TMP4]] ], [ [[TMP7]], [[TMP6]] ]
; CHECK-NEXT: [[B]] = fadd float [[L]], 1.000000e+00
; CHECK-NEXT: [[TMP10]] = fadd double [[TMP9]], 1.000000e+00
; CHECK-NEXT: br label [[LOOP]]
;
entry:
br label %block1
loop:
%d = fadd float %b, 2.0 ; this is a forward reference, requiring shadow(%b) to be available.
br label %block1
block1:
%a = phi float [ %d, %loop], [ 1.0, %entry ]
%l = load float, float* %p ; the load creates a new block
%b = fadd float %l, 1.0 ; this requires shadow(%l).
br label %loop
}
define float @forward_use_with_two_uses() sanitize_numerical_stability {
; CHECK-LABEL: @forward_use_with_two_uses(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[BLOCK1:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[D:%.*]] = fadd float [[B:%.*]], 2.000000e+00
; CHECK-NEXT: [[TMP0:%.*]] = fadd double [[TMP4:%.*]], 2.000000e+00
; CHECK-NEXT: br label [[BLOCK1]]
; CHECK: block1:
; CHECK-NEXT: [[A:%.*]] = phi float [ [[D]], [[LOOP:%.*]] ], [ 1.000000e+00, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[TMP1:%.*]] = phi double [ [[TMP0]], [[LOOP]] ], [ 1.000000e+00, [[ENTRY]] ]
; CHECK-NEXT: [[T1:%.*]] = fadd float [[A]], 1.000000e+00
; CHECK-NEXT: [[TMP2:%.*]] = fadd double [[TMP1]], 1.000000e+00
; CHECK-NEXT: [[T2:%.*]] = fadd float [[T1]], 3.000000e+00
; CHECK-NEXT: [[TMP3:%.*]] = fadd double [[TMP2]], 3.000000e+00
; CHECK-NEXT: [[B]] = fadd float [[T1]], [[T2]]
; CHECK-NEXT: [[TMP4]] = fadd double [[TMP2]], [[TMP3]]
; CHECK-NEXT: br label [[LOOP]]
;
entry:
br label %block1
loop:
%d = fadd float %b, 2.0 ; this is a forward reference, requiring shadow(%b) to be available.
br label %block1
block1:
%a = phi float [ %d, %loop], [ 1.0, %entry ]
%t1 = fadd float %a, 1.0
%t2 = fadd float %t1, 3.0 ; this requires shadow(%t1)
%b = fadd float %t1, %t2 ; this requires shadow(%t2) and shadow(%t1).
br label %loop
}

View File

@@ -0,0 +1,148 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=nsan -nsan-shadow-type-mapping=dqq -S %s | FileCheck %s
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"
; Tests for invoke instructions that require special handling of the phis.
declare float @may_throw()
declare void @personalityFn()
define float @invoke1() sanitize_numerical_stability personality void ()* @personalityFn {
; CHECK-LABEL: @invoke1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = invoke float @may_throw()
; CHECK-NEXT: to label [[TMP0:%.*]] unwind label [[LAND:%.*]]
; CHECK: 0:
; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @may_throw to i64)
; CHECK-NEXT: [[TMP3:%.*]] = load double, ptr @__nsan_shadow_ret_ptr, align 8
; CHECK-NEXT: [[TMP4:%.*]] = fpext float [[C]] to double
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], double [[TMP3]], double [[TMP4]]
; CHECK-NEXT: br label [[CONTINUE:%.*]]
; CHECK: continue:
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: land:
; CHECK-NEXT: [[RES:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: [[LV:%.*]] = uitofp i32 1 to float
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[R:%.*]] = phi float [ [[LV]], [[LAND]] ], [ [[C]], [[CONTINUE]] ]
; CHECK-NEXT: [[TMP6:%.*]] = phi double [ 1.000000e+00, [[LAND]] ], [ [[TMP5]], [[CONTINUE]] ]
; CHECK-NEXT: [[TMP7:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP6]], i32 1, i64 0)
; CHECK-NEXT: [[TMP8:%.*]] = icmp eq i32 [[TMP7]], 1
; CHECK-NEXT: [[TMP9:%.*]] = fpext float [[R]] to double
; CHECK-NEXT: [[TMP10:%.*]] = select i1 [[TMP8]], double [[TMP9]], double [[TMP6]]
; CHECK-NEXT: store i64 ptrtoint (ptr @invoke1 to i64), ptr @__nsan_shadow_ret_tag, align 8
; CHECK-NEXT: store double [[TMP10]], ptr @__nsan_shadow_ret_ptr, align 8
; CHECK-NEXT: ret float [[R]]
;
entry:
%c = invoke float @may_throw() to label %continue unwind label %land
continue:
br label %exit
land:
%res = landingpad { ptr, i32 } cleanup
%lv = uitofp i32 1 to float
br label %exit
exit:
%r = phi float [ %lv, %land], [ %c, %continue ]
ret float %r
}
define float @invoke2() sanitize_numerical_stability personality void ()* @personalityFn {
; CHECK-LABEL: @invoke2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = invoke float @may_throw()
; CHECK-NEXT: to label [[TMP0:%.*]] unwind label [[LAND:%.*]]
; CHECK: 0:
; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @may_throw to i64)
; CHECK-NEXT: [[TMP3:%.*]] = load double, ptr @__nsan_shadow_ret_ptr, align 8
; CHECK-NEXT: [[TMP4:%.*]] = fpext float [[C]] to double
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], double [[TMP3]], double [[TMP4]]
; CHECK-NEXT: br label [[CONTINUE:%.*]]
; CHECK: continue:
; CHECK-NEXT: [[CV:%.*]] = fadd float [[C]], 2.000000e+00
; CHECK-NEXT: [[TMP6:%.*]] = fadd double [[TMP5]], 2.000000e+00
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: land:
; CHECK-NEXT: [[RES:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: [[LV:%.*]] = uitofp i32 1 to float
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[R:%.*]] = phi float [ [[LV]], [[LAND]] ], [ [[CV]], [[CONTINUE]] ]
; CHECK-NEXT: [[TMP7:%.*]] = phi double [ 1.000000e+00, [[LAND]] ], [ [[TMP6]], [[CONTINUE]] ]
; CHECK-NEXT: [[TMP8:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP7]], i32 1, i64 0)
; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 1
; CHECK-NEXT: [[TMP10:%.*]] = fpext float [[R]] to double
; CHECK-NEXT: [[TMP11:%.*]] = select i1 [[TMP9]], double [[TMP10]], double [[TMP7]]
; CHECK-NEXT: store i64 ptrtoint (ptr @invoke2 to i64), ptr @__nsan_shadow_ret_tag, align 8
; CHECK-NEXT: store double [[TMP11]], ptr @__nsan_shadow_ret_ptr, align 8
; CHECK-NEXT: ret float [[R]]
;
entry:
%c = invoke float @may_throw() to label %continue unwind label %land
continue:
%cv = fadd float %c, 2.0
br label %exit
land:
%res = landingpad { ptr, i32 } cleanup
%lv = uitofp i32 1 to float
br label %exit
exit:
%r = phi float [ %lv, %land], [ %cv, %continue ]
ret float %r
}
define float @invoke3() sanitize_numerical_stability personality void ()* @personalityFn {
; CHECK-LABEL: @invoke3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = invoke float @may_throw()
; CHECK-NEXT: to label [[TMP0:%.*]] unwind label [[LAND:%.*]]
; CHECK: land:
; CHECK-NEXT: [[RES:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: [[LV:%.*]] = uitofp i32 1 to float
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: 0:
; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__nsan_shadow_ret_tag, align 8
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], ptrtoint (ptr @may_throw to i64)
; CHECK-NEXT: [[TMP3:%.*]] = load double, ptr @__nsan_shadow_ret_ptr, align 8
; CHECK-NEXT: [[TMP4:%.*]] = fpext float [[C]] to double
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], double [[TMP3]], double [[TMP4]]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[R:%.*]] = phi float [ [[LV]], [[LAND]] ], [ [[C]], [[TMP0]] ]
; CHECK-NEXT: [[TMP6:%.*]] = phi double [ 1.000000e+00, [[LAND]] ], [ [[TMP5]], [[TMP0]] ]
; CHECK-NEXT: [[TMP7:%.*]] = call i32 @__nsan_internal_check_float_d(float [[R]], double [[TMP6]], i32 1, i64 0)
; CHECK-NEXT: [[TMP8:%.*]] = icmp eq i32 [[TMP7]], 1
; CHECK-NEXT: [[TMP9:%.*]] = fpext float [[R]] to double
; CHECK-NEXT: [[TMP10:%.*]] = select i1 [[TMP8]], double [[TMP9]], double [[TMP6]]
; CHECK-NEXT: store i64 ptrtoint (ptr @invoke3 to i64), ptr @__nsan_shadow_ret_tag, align 8
; CHECK-NEXT: store double [[TMP10]], ptr @__nsan_shadow_ret_ptr, align 8
; CHECK-NEXT: ret float [[R]]
;
entry:
%c = invoke float @may_throw() to label %exit unwind label %land
land:
%res = landingpad { ptr, i32 } cleanup
%lv = uitofp i32 1 to float
br label %exit
exit:
%r = phi float [ %lv, %land], [ %c, %entry ]
ret float %r
}

View File

@@ -0,0 +1,404 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=nsan -nsan-shadow-type-mapping=dqq -S %s | FileCheck %s
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"
; Tests with memory manipulation (memcpy, llvm.memcpy, ...).
declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1)
define void @call_memcpy_intrinsic(i8* nonnull align 8 dereferenceable(16) %a, i8* nonnull align 8 dereferenceable(16) %b) sanitize_numerical_stability {
; CHECK-LABEL: @call_memcpy_intrinsic(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @__nsan_copy_values(ptr [[A:%.*]], ptr [[B:%.*]], i64 16)
; CHECK-NEXT: tail call void @llvm.memcpy.p0.p0.i64(ptr nonnull align 8 dereferenceable(16) [[A]], ptr nonnull align 8 dereferenceable(16) [[B]], i64 16, i1 false)
; CHECK-NEXT: ret void
;
entry:
tail call void @llvm.memcpy.p0i8.p0i8.i64(ptr nonnull align 8 dereferenceable(16) %a, ptr nonnull align 8 dereferenceable(16) %b, i64 16, i1 false)
ret void
}
declare dso_local i8* @memcpy(i8*, i8*, i64) local_unnamed_addr
define void @call_memcpy(i8* nonnull align 8 dereferenceable(16) %a, i8* nonnull align 8 dereferenceable(16) %b) sanitize_numerical_stability {
; CHECK-LABEL: @call_memcpy(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = tail call ptr @memcpy(ptr nonnull align 8 dereferenceable(16) [[A:%.*]], ptr nonnull align 8 dereferenceable(16) [[B:%.*]], i64 16) #[[ATTR3:[0-9]+]]
; CHECK-NEXT: ret void
;
entry:
tail call i8* @memcpy(ptr nonnull align 8 dereferenceable(16) %a, ptr nonnull align 8 dereferenceable(16) %b, i64 16)
ret void
}
define void @transfer_float(float* %dst, float* %src) sanitize_numerical_stability {
; CHECK-LABEL: @transfer_float(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[T:%.*]] = load float, ptr [[SRC:%.*]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[SRC]], 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 [[T]] to double
; CHECK-NEXT: br label [[TMP6]]
; CHECK: 6:
; CHECK-NEXT: [[TMP7:%.*]] = phi double [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
; CHECK-NEXT: [[TMP8:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[DST:%.*]], i64 1)
; CHECK-NEXT: [[TMP9:%.*]] = ptrtoint ptr [[DST]] to i64
; CHECK-NEXT: [[TMP10:%.*]] = call i32 @__nsan_internal_check_float_d(float [[T]], double [[TMP7]], i32 4, i64 [[TMP9]])
; CHECK-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], 1
; CHECK-NEXT: [[TMP12:%.*]] = fpext float [[T]] to double
; CHECK-NEXT: [[TMP13:%.*]] = select i1 [[TMP11]], double [[TMP12]], double [[TMP7]]
; CHECK-NEXT: store double [[TMP13]], ptr [[TMP8]], align 1
; CHECK-NEXT: store float [[T]], ptr [[DST]], align 1
; CHECK-NEXT: ret void
;
entry:
%t = load float, ptr %src
store float %t, ptr %dst, align 1
ret void
}
define void @transfer_non_float(i32* %dst, i32* %src) sanitize_numerical_stability {
; CHECK-LABEL: @transfer_non_float(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[T:%.*]] = load i32, ptr [[SRC:%.*]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[SRC]])
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 1
; CHECK-NEXT: [[TMP2:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[SRC]])
; CHECK-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 1
; CHECK-NEXT: store i32 [[T]], ptr [[DST:%.*]], align 1
; CHECK-NEXT: [[TMP4:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[DST]])
; CHECK-NEXT: store i32 [[TMP1]], ptr [[TMP4]], align 1
; CHECK-NEXT: [[TMP5:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[DST]])
; CHECK-NEXT: store i64 [[TMP3]], ptr [[TMP5]], align 1
; CHECK-NEXT: ret void
;
entry:
%t = load i32, ptr %src
store i32 %t, ptr %dst, align 1
ret void
}
define void @transfer_array([2 x float]* %a) sanitize_numerical_stability {
; CHECK-LABEL: @transfer_array(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B:%.*]] = load [2 x float], ptr [[A:%.*]], align 1
; CHECK-NEXT: [[TMP0:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[A]])
; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[TMP0]], align 1
; CHECK-NEXT: [[TMP2:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[A]])
; CHECK-NEXT: [[TMP3:%.*]] = load i128, ptr [[TMP2]], align 1
; CHECK-NEXT: store [2 x float] [[B]], ptr [[A]], align 1
; CHECK-NEXT: [[TMP4:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[A]])
; CHECK-NEXT: store i64 [[TMP1]], ptr [[TMP4]], align 1
; CHECK-NEXT: [[TMP5:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[A]])
; CHECK-NEXT: store i128 [[TMP3]], ptr [[TMP5]], align 1
; CHECK-NEXT: ret void
;
entry:
%b = load [2 x float], ptr %a, align 1
store [2 x float] %b, ptr %a, align 1
ret void
}
define void @swap_untyped1(i64* nonnull align 8 %p, i64* nonnull align 8 %q) sanitize_numerical_stability {
; CHECK-LABEL: @swap_untyped1(
; CHECK-NEXT: [[QV:%.*]] = load i64, ptr [[Q:%.*]], align 8
; CHECK-NEXT: [[TMP1:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[Q]])
; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 1
; CHECK-NEXT: [[TMP3:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[Q]])
; CHECK-NEXT: [[TMP4:%.*]] = load i128, ptr [[TMP3]], align 1
; CHECK-NEXT: [[PV:%.*]] = load i64, ptr [[P:%.*]], align 8
; CHECK-NEXT: [[TMP5:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[P]])
; CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr [[TMP5]], align 1
; CHECK-NEXT: [[TMP7:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[P]])
; CHECK-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP7]], align 1
; CHECK-NEXT: store i64 [[PV]], ptr [[Q]], align 8
; CHECK-NEXT: [[TMP9:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[Q]])
; CHECK-NEXT: store i64 [[TMP6]], ptr [[TMP9]], align 1
; CHECK-NEXT: [[TMP10:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[Q]])
; CHECK-NEXT: store i128 [[TMP8]], ptr [[TMP10]], align 1
; CHECK-NEXT: store i64 [[QV]], ptr [[P]], align 8
; CHECK-NEXT: [[TMP11:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[P]])
; CHECK-NEXT: store i64 [[TMP2]], ptr [[TMP11]], align 1
; CHECK-NEXT: [[TMP12:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[P]])
; CHECK-NEXT: store i128 [[TMP4]], ptr [[TMP12]], align 1
; CHECK-NEXT: ret void
;
%qv = load i64, ptr %q
%pv = load i64, ptr %p
store i64 %pv, ptr %q, align 8
store i64 %qv, ptr %p, align 8
ret void
}
; Same as swap_untyped1, but the load/stores are in the opposite order.
define void @swap_untyped2(i64* nonnull align 8 %p, i64* nonnull align 8 %q) sanitize_numerical_stability {
; CHECK-LABEL: @swap_untyped2(
; CHECK-NEXT: [[PV:%.*]] = load i64, ptr [[P:%.*]], align 8
; CHECK-NEXT: [[TMP1:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[P]])
; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 1
; CHECK-NEXT: [[TMP3:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[P]])
; CHECK-NEXT: [[TMP4:%.*]] = load i128, ptr [[TMP3]], align 1
; CHECK-NEXT: [[QV:%.*]] = load i64, ptr [[Q:%.*]], align 8
; CHECK-NEXT: [[TMP5:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[Q]])
; CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr [[TMP5]], align 1
; CHECK-NEXT: [[TMP7:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[Q]])
; CHECK-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP7]], align 1
; CHECK-NEXT: store i64 [[PV]], ptr [[Q]], align 8
; CHECK-NEXT: [[TMP9:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[Q]])
; CHECK-NEXT: store i64 [[TMP2]], ptr [[TMP9]], align 1
; CHECK-NEXT: [[TMP10:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[Q]])
; CHECK-NEXT: store i128 [[TMP4]], ptr [[TMP10]], align 1
; CHECK-NEXT: store i64 [[QV]], ptr [[P]], align 8
; CHECK-NEXT: [[TMP11:%.*]] = call ptr @__nsan_internal_get_raw_shadow_type_ptr(ptr [[P]])
; CHECK-NEXT: store i64 [[TMP6]], ptr [[TMP11]], align 1
; CHECK-NEXT: [[TMP12:%.*]] = call ptr @__nsan_internal_get_raw_shadow_ptr(ptr [[P]])
; CHECK-NEXT: store i128 [[TMP8]], ptr [[TMP12]], align 1
; CHECK-NEXT: ret void
;
%pv = load i64, ptr %p
%qv = load i64, ptr %q
store i64 %pv, ptr %q, align 8
store i64 %qv, ptr %p, align 8
ret void
}
define void @swap_ft1(float* nonnull align 8 %p, float* nonnull align 8 %q) sanitize_numerical_stability {
; CHECK-LABEL: @swap_ft1(
; CHECK-NEXT: [[QV:%.*]] = load float, ptr [[Q:%.*]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[Q]], i64 1)
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
; CHECK: 3:
; CHECK-NEXT: [[TMP4:%.*]] = load double, ptr [[TMP1]], align 1
; CHECK-NEXT: br label [[TMP7:%.*]]
; CHECK: 5:
; CHECK-NEXT: [[TMP6:%.*]] = fpext float [[QV]] to double
; CHECK-NEXT: br label [[TMP7]]
; CHECK: 7:
; CHECK-NEXT: [[TMP8:%.*]] = phi double [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ]
; CHECK-NEXT: [[PV:%.*]] = load float, ptr [[P:%.*]], align 4
; CHECK-NEXT: [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[P]], i64 1)
; CHECK-NEXT: [[TMP10:%.*]] = icmp eq ptr [[TMP9]], null
; CHECK-NEXT: br i1 [[TMP10]], label [[TMP13:%.*]], label [[TMP11:%.*]]
; CHECK: 11:
; CHECK-NEXT: [[TMP12:%.*]] = load double, ptr [[TMP9]], align 1
; CHECK-NEXT: br label [[TMP15:%.*]]
; CHECK: 13:
; CHECK-NEXT: [[TMP14:%.*]] = fpext float [[PV]] to double
; CHECK-NEXT: br label [[TMP15]]
; CHECK: 15:
; CHECK-NEXT: [[TMP16:%.*]] = phi double [ [[TMP12]], [[TMP11]] ], [ [[TMP14]], [[TMP13]] ]
; CHECK-NEXT: [[TMP17:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[Q]], i64 1)
; CHECK-NEXT: [[TMP18:%.*]] = ptrtoint ptr [[Q]] to i64
; CHECK-NEXT: [[TMP19:%.*]] = call i32 @__nsan_internal_check_float_d(float [[PV]], double [[TMP16]], i32 4, i64 [[TMP18]])
; CHECK-NEXT: [[TMP20:%.*]] = icmp eq i32 [[TMP19]], 1
; CHECK-NEXT: [[TMP21:%.*]] = fpext float [[PV]] to double
; CHECK-NEXT: [[TMP22:%.*]] = select i1 [[TMP20]], double [[TMP21]], double [[TMP16]]
; CHECK-NEXT: store double [[TMP22]], ptr [[TMP17]], align 1
; CHECK-NEXT: store float [[PV]], ptr [[Q]], align 8
; CHECK-NEXT: [[TMP23:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[P]], i64 1)
; CHECK-NEXT: [[TMP24:%.*]] = ptrtoint ptr [[P]] to i64
; CHECK-NEXT: [[TMP25:%.*]] = call i32 @__nsan_internal_check_float_d(float [[QV]], double [[TMP8]], i32 4, i64 [[TMP24]])
; CHECK-NEXT: [[TMP26:%.*]] = icmp eq i32 [[TMP25]], 1
; CHECK-NEXT: [[TMP27:%.*]] = fpext float [[QV]] to double
; CHECK-NEXT: [[TMP28:%.*]] = select i1 [[TMP26]], double [[TMP27]], double [[TMP8]]
; CHECK-NEXT: store double [[TMP28]], ptr [[TMP23]], align 1
; CHECK-NEXT: store float [[QV]], ptr [[P]], align 8
; CHECK-NEXT: ret void
;
%qv = load float, ptr %q
%pv = load float, ptr %p
store float %pv, ptr %q, align 8
store float %qv, ptr %p, align 8
ret void
}
; Same as swap_ft1, but the load/stores are in the opposite order.
define void @swap_ft2(float* nonnull align 8 %p, float* nonnull align 8 %q) sanitize_numerical_stability {
; CHECK-LABEL: @swap_ft2(
; CHECK-NEXT: [[PV:%.*]] = load float, ptr [[P:%.*]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[P]], i64 1)
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
; CHECK: 3:
; CHECK-NEXT: [[TMP4:%.*]] = load double, ptr [[TMP1]], align 1
; CHECK-NEXT: br label [[TMP7:%.*]]
; CHECK: 5:
; CHECK-NEXT: [[TMP6:%.*]] = fpext float [[PV]] to double
; CHECK-NEXT: br label [[TMP7]]
; CHECK: 7:
; CHECK-NEXT: [[TMP8:%.*]] = phi double [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ]
; CHECK-NEXT: [[QV:%.*]] = load float, ptr [[Q:%.*]], align 4
; CHECK-NEXT: [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[Q]], i64 1)
; CHECK-NEXT: [[TMP10:%.*]] = icmp eq ptr [[TMP9]], null
; CHECK-NEXT: br i1 [[TMP10]], label [[TMP13:%.*]], label [[TMP11:%.*]]
; CHECK: 11:
; CHECK-NEXT: [[TMP12:%.*]] = load double, ptr [[TMP9]], align 1
; CHECK-NEXT: br label [[TMP15:%.*]]
; CHECK: 13:
; CHECK-NEXT: [[TMP14:%.*]] = fpext float [[QV]] to double
; CHECK-NEXT: br label [[TMP15]]
; CHECK: 15:
; CHECK-NEXT: [[TMP16:%.*]] = phi double [ [[TMP12]], [[TMP11]] ], [ [[TMP14]], [[TMP13]] ]
; CHECK-NEXT: [[TMP17:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[Q]], i64 1)
; CHECK-NEXT: [[TMP18:%.*]] = ptrtoint ptr [[Q]] to i64
; CHECK-NEXT: [[TMP19:%.*]] = call i32 @__nsan_internal_check_float_d(float [[PV]], double [[TMP8]], i32 4, i64 [[TMP18]])
; CHECK-NEXT: [[TMP20:%.*]] = icmp eq i32 [[TMP19]], 1
; CHECK-NEXT: [[TMP21:%.*]] = fpext float [[PV]] to double
; CHECK-NEXT: [[TMP22:%.*]] = select i1 [[TMP20]], double [[TMP21]], double [[TMP8]]
; CHECK-NEXT: store double [[TMP22]], ptr [[TMP17]], align 1
; CHECK-NEXT: store float [[PV]], ptr [[Q]], align 8
; CHECK-NEXT: [[TMP23:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[P]], i64 1)
; CHECK-NEXT: [[TMP24:%.*]] = ptrtoint ptr [[P]] to i64
; CHECK-NEXT: [[TMP25:%.*]] = call i32 @__nsan_internal_check_float_d(float [[QV]], double [[TMP16]], i32 4, i64 [[TMP24]])
; CHECK-NEXT: [[TMP26:%.*]] = icmp eq i32 [[TMP25]], 1
; CHECK-NEXT: [[TMP27:%.*]] = fpext float [[QV]] to double
; CHECK-NEXT: [[TMP28:%.*]] = select i1 [[TMP26]], double [[TMP27]], double [[TMP16]]
; CHECK-NEXT: store double [[TMP28]], ptr [[TMP23]], align 1
; CHECK-NEXT: store float [[QV]], ptr [[P]], align 8
; CHECK-NEXT: ret void
;
%pv = load float, ptr %p
%qv = load float, ptr %q
store float %pv, ptr %q, align 8
store float %qv, ptr %p, align 8
ret void
}
define void @swap_vectorft1(<2 x float>* nonnull align 16 %p, <2 x float>* nonnull align 16 %q) sanitize_numerical_stability {
; CHECK-LABEL: @swap_vectorft1(
; CHECK-NEXT: [[QV:%.*]] = load <2 x float>, ptr [[Q:%.*]], align 8
; CHECK-NEXT: [[TMP1:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[Q]], i64 2)
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
; CHECK: 3:
; CHECK-NEXT: [[TMP4:%.*]] = load <2 x double>, ptr [[TMP1]], align 1
; CHECK-NEXT: br label [[TMP7:%.*]]
; CHECK: 5:
; CHECK-NEXT: [[TMP6:%.*]] = fpext <2 x float> [[QV]] to <2 x double>
; CHECK-NEXT: br label [[TMP7]]
; CHECK: 7:
; CHECK-NEXT: [[TMP8:%.*]] = phi <2 x double> [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ]
; CHECK-NEXT: [[PV:%.*]] = load <2 x float>, ptr [[P:%.*]], align 8
; CHECK-NEXT: [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[P]], i64 2)
; CHECK-NEXT: [[TMP10:%.*]] = icmp eq ptr [[TMP9]], null
; CHECK-NEXT: br i1 [[TMP10]], label [[TMP13:%.*]], label [[TMP11:%.*]]
; CHECK: 11:
; CHECK-NEXT: [[TMP12:%.*]] = load <2 x double>, ptr [[TMP9]], align 1
; CHECK-NEXT: br label [[TMP15:%.*]]
; CHECK: 13:
; CHECK-NEXT: [[TMP14:%.*]] = fpext <2 x float> [[PV]] to <2 x double>
; CHECK-NEXT: br label [[TMP15]]
; CHECK: 15:
; CHECK-NEXT: [[TMP16:%.*]] = phi <2 x double> [ [[TMP12]], [[TMP11]] ], [ [[TMP14]], [[TMP13]] ]
; CHECK-NEXT: [[TMP17:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[Q]], i64 2)
; CHECK-NEXT: [[TMP18:%.*]] = extractelement <2 x float> [[PV]], i64 0
; CHECK-NEXT: [[TMP19:%.*]] = extractelement <2 x double> [[TMP16]], i64 0
; CHECK-NEXT: [[TMP20:%.*]] = ptrtoint ptr [[Q]] to i64
; CHECK-NEXT: [[TMP21:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP18]], double [[TMP19]], i32 4, i64 [[TMP20]])
; CHECK-NEXT: [[TMP22:%.*]] = extractelement <2 x float> [[PV]], i64 1
; CHECK-NEXT: [[TMP23:%.*]] = extractelement <2 x double> [[TMP16]], i64 1
; CHECK-NEXT: [[TMP24:%.*]] = ptrtoint ptr [[Q]] to i64
; CHECK-NEXT: [[TMP25:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP22]], double [[TMP23]], i32 4, i64 [[TMP24]])
; CHECK-NEXT: [[TMP26:%.*]] = or i32 [[TMP21]], [[TMP25]]
; CHECK-NEXT: [[TMP27:%.*]] = icmp eq i32 [[TMP26]], 1
; CHECK-NEXT: [[TMP28:%.*]] = fpext <2 x float> [[PV]] to <2 x double>
; CHECK-NEXT: [[TMP29:%.*]] = select i1 [[TMP27]], <2 x double> [[TMP28]], <2 x double> [[TMP16]]
; CHECK-NEXT: store <2 x double> [[TMP29]], ptr [[TMP17]], align 1
; CHECK-NEXT: store <2 x float> [[PV]], ptr [[Q]], align 16
; CHECK-NEXT: [[TMP30:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[P]], i64 2)
; CHECK-NEXT: [[TMP31:%.*]] = extractelement <2 x float> [[QV]], i64 0
; CHECK-NEXT: [[TMP32:%.*]] = extractelement <2 x double> [[TMP8]], i64 0
; CHECK-NEXT: [[TMP33:%.*]] = ptrtoint ptr [[P]] to i64
; CHECK-NEXT: [[TMP34:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP31]], double [[TMP32]], i32 4, i64 [[TMP33]])
; CHECK-NEXT: [[TMP35:%.*]] = extractelement <2 x float> [[QV]], i64 1
; CHECK-NEXT: [[TMP36:%.*]] = extractelement <2 x double> [[TMP8]], i64 1
; CHECK-NEXT: [[TMP37:%.*]] = ptrtoint ptr [[P]] to i64
; CHECK-NEXT: [[TMP38:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP35]], double [[TMP36]], i32 4, i64 [[TMP37]])
; CHECK-NEXT: [[TMP39:%.*]] = or i32 [[TMP34]], [[TMP38]]
; CHECK-NEXT: [[TMP40:%.*]] = icmp eq i32 [[TMP39]], 1
; CHECK-NEXT: [[TMP41:%.*]] = fpext <2 x float> [[QV]] to <2 x double>
; CHECK-NEXT: [[TMP42:%.*]] = select i1 [[TMP40]], <2 x double> [[TMP41]], <2 x double> [[TMP8]]
; CHECK-NEXT: store <2 x double> [[TMP42]], ptr [[TMP30]], align 1
; CHECK-NEXT: store <2 x float> [[QV]], ptr [[P]], align 16
; CHECK-NEXT: ret void
;
%qv = load <2 x float>, ptr %q
%pv = load <2 x float>, ptr %p
store <2 x float> %pv, ptr %q, align 16
store <2 x float> %qv, ptr %p, align 16
ret void
}
; Same as swap_vectorft1, but the load/stores are in the opposite order.
define void @swap_vectorft2(<2 x float>* nonnull align 16 %p, <2 x float>* nonnull align 16 %q) sanitize_numerical_stability {
; CHECK-LABEL: @swap_vectorft2(
; CHECK-NEXT: [[PV:%.*]] = load <2 x float>, ptr [[P:%.*]], align 8
; CHECK-NEXT: [[TMP1:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[P]], i64 2)
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
; CHECK: 3:
; CHECK-NEXT: [[TMP4:%.*]] = load <2 x double>, ptr [[TMP1]], align 1
; CHECK-NEXT: br label [[TMP7:%.*]]
; CHECK: 5:
; CHECK-NEXT: [[TMP6:%.*]] = fpext <2 x float> [[PV]] to <2 x double>
; CHECK-NEXT: br label [[TMP7]]
; CHECK: 7:
; CHECK-NEXT: [[TMP8:%.*]] = phi <2 x double> [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ]
; CHECK-NEXT: [[QV:%.*]] = load <2 x float>, ptr [[Q:%.*]], align 8
; CHECK-NEXT: [[TMP9:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_load(ptr [[Q]], i64 2)
; CHECK-NEXT: [[TMP10:%.*]] = icmp eq ptr [[TMP9]], null
; CHECK-NEXT: br i1 [[TMP10]], label [[TMP13:%.*]], label [[TMP11:%.*]]
; CHECK: 11:
; CHECK-NEXT: [[TMP12:%.*]] = load <2 x double>, ptr [[TMP9]], align 1
; CHECK-NEXT: br label [[TMP15:%.*]]
; CHECK: 13:
; CHECK-NEXT: [[TMP14:%.*]] = fpext <2 x float> [[QV]] to <2 x double>
; CHECK-NEXT: br label [[TMP15]]
; CHECK: 15:
; CHECK-NEXT: [[TMP16:%.*]] = phi <2 x double> [ [[TMP12]], [[TMP11]] ], [ [[TMP14]], [[TMP13]] ]
; CHECK-NEXT: [[TMP17:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[Q]], i64 2)
; CHECK-NEXT: [[TMP18:%.*]] = extractelement <2 x float> [[PV]], i64 0
; CHECK-NEXT: [[TMP19:%.*]] = extractelement <2 x double> [[TMP8]], i64 0
; CHECK-NEXT: [[TMP20:%.*]] = ptrtoint ptr [[Q]] to i64
; CHECK-NEXT: [[TMP21:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP18]], double [[TMP19]], i32 4, i64 [[TMP20]])
; CHECK-NEXT: [[TMP22:%.*]] = extractelement <2 x float> [[PV]], i64 1
; CHECK-NEXT: [[TMP23:%.*]] = extractelement <2 x double> [[TMP8]], i64 1
; CHECK-NEXT: [[TMP24:%.*]] = ptrtoint ptr [[Q]] to i64
; CHECK-NEXT: [[TMP25:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP22]], double [[TMP23]], i32 4, i64 [[TMP24]])
; CHECK-NEXT: [[TMP26:%.*]] = or i32 [[TMP21]], [[TMP25]]
; CHECK-NEXT: [[TMP27:%.*]] = icmp eq i32 [[TMP26]], 1
; CHECK-NEXT: [[TMP28:%.*]] = fpext <2 x float> [[PV]] to <2 x double>
; CHECK-NEXT: [[TMP29:%.*]] = select i1 [[TMP27]], <2 x double> [[TMP28]], <2 x double> [[TMP8]]
; CHECK-NEXT: store <2 x double> [[TMP29]], ptr [[TMP17]], align 1
; CHECK-NEXT: store <2 x float> [[PV]], ptr [[Q]], align 16
; CHECK-NEXT: [[TMP30:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[P]], i64 2)
; CHECK-NEXT: [[TMP31:%.*]] = extractelement <2 x float> [[QV]], i64 0
; CHECK-NEXT: [[TMP32:%.*]] = extractelement <2 x double> [[TMP16]], i64 0
; CHECK-NEXT: [[TMP33:%.*]] = ptrtoint ptr [[P]] to i64
; CHECK-NEXT: [[TMP34:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP31]], double [[TMP32]], i32 4, i64 [[TMP33]])
; CHECK-NEXT: [[TMP35:%.*]] = extractelement <2 x float> [[QV]], i64 1
; CHECK-NEXT: [[TMP36:%.*]] = extractelement <2 x double> [[TMP16]], i64 1
; CHECK-NEXT: [[TMP37:%.*]] = ptrtoint ptr [[P]] to i64
; CHECK-NEXT: [[TMP38:%.*]] = call i32 @__nsan_internal_check_float_d(float [[TMP35]], double [[TMP36]], i32 4, i64 [[TMP37]])
; CHECK-NEXT: [[TMP39:%.*]] = or i32 [[TMP34]], [[TMP38]]
; CHECK-NEXT: [[TMP40:%.*]] = icmp eq i32 [[TMP39]], 1
; CHECK-NEXT: [[TMP41:%.*]] = fpext <2 x float> [[QV]] to <2 x double>
; CHECK-NEXT: [[TMP42:%.*]] = select i1 [[TMP40]], <2 x double> [[TMP41]], <2 x double> [[TMP16]]
; CHECK-NEXT: store <2 x double> [[TMP42]], ptr [[TMP30]], align 1
; CHECK-NEXT: store <2 x float> [[QV]], ptr [[P]], align 16
; CHECK-NEXT: ret void
;
%pv = load <2 x float>, ptr %p
%qv = load <2 x float>, ptr %q
store <2 x float> %pv, ptr %q, align 16
store <2 x float> %qv, ptr %p, align 16
ret void
}

View File

@@ -0,0 +1,19 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=nsan -nsan-shadow-type-mapping=dqq -nsan-propagate-non-ft-const-stores-as-ft -S %s | FileCheck %s
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"
define void @store_non_float(ptr %dst) sanitize_numerical_stability {
; CHECK-LABEL: @store_non_float(
; CHECK-NEXT: entry:
; CHECK-NEXT: store i32 42, ptr [[DST:%.*]], align 1
; CHECK-NEXT: [[TMP0:%.*]] = call ptr @__nsan_get_shadow_ptr_for_float_store(ptr [[DST]], i64 1)
; CHECK-NEXT: store double 0x36F5000000000000, ptr [[TMP0]], align 1
; CHECK-NEXT: ret void
;
entry:
store i32 42, ptr %dst, align 1
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" }

View File

@@ -0,0 +1,15 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=nsan -nsan-shadow-type-mapping=dqq -S %s | FileCheck %s
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"
define void @add_scalable_vector(<vscale x 2 x double> %a) sanitize_numerical_stability {
; CHECK-LABEL: @add_scalable_vector(
; CHECK-NEXT: [[ADD:%.*]] = fadd <vscale x 2 x double> [[A:%.*]], [[A]]
; CHECK-NEXT: ret void
;
%add = fadd <vscale x 2 x double> %a, %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" }