diff --git a/clang/test/CodeGen/msan-intrinsics.c b/clang/test/CodeGen/msan-intrinsics.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/msan-intrinsics.c @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -fsanitize=memory -triple x86_64-linux-gnu -emit-llvm %s -O3 -o - | FileCheck %s + +typedef double double2 __attribute__((vector_size(16))); + +__attribute__((target("sse4.1"))) +double2 RoundSD(double theta, double top) { + // CHECK: [[IN_SHADOW1:%[0-9]+]] = load {{.*}} @__msan_param_tls + // CHECK: [[IN_SHADOW2:%[0-9]+]] = load {{.*}} @__msan_param_tls + double2 vec; + double2 unused; + unused[1] = top; + vec[0] = theta; + return __builtin_ia32_roundsd(unused, vec, 1); + // CHECK: [[TMP_SHADOW:%.+]] = insertelement <2 x i64> undef, i64 [[IN_SHADOW2]], i32 1 + // CHECK: [[OUT_SHADOW:%.+]] = insertelement <2 x i64> [[TMP_SHADOW]], i64 [[IN_SHADOW1]], i32 0 + + // CHECK-NOT: call void @msan_warning + // CHECK: call <2 x double> @llvm.x86.sse41.round.sd + // CHECK: store <2 x i64> [[OUT_SHADOW]], {{.*}} @__msan_retval_tls + // CHECK: ret <2 x double> +} + +__attribute__((target("sse2"))) +double MinSD(double t1, double t2) { + // CHECK: [[IN_SHADOW1:%[0-9]+]] = load {{.*}} @__msan_param_tls + // CHECK: [[IN_SHADOW2:%[0-9]+]] = load {{.*}} @__msan_param_tls + // CHECK: [[COMB_SHADOW:%[0-9]+]] = or i64 [[IN_SHADOW2]], [[IN_SHADOW1]] + double2 first; + double2 second; + first[0] = t1; + second[0] = t2; + double min = __builtin_ia32_minsd(first, second)[0]; + // CHECK-NOT: call void @msan_warning + // CHECK: call <2 x double> @llvm.x86.sse2.min.sd + return min; + // CHECK: store i64 [[COMB_SHADOW]], {{.*}} @__msan_retval_tls + // CHECK: ret double +} \ No newline at end of file diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -3054,6 +3054,31 @@ SOC.Done(&I); } + // Instrument _mm_*_sd intrinsics + void handleUnarySdIntrinsic(IntrinsicInst &I) { + IRBuilder<> IRB(&I); + Value *First = getShadow(&I, 0); + Value *Second = getShadow(&I, 1); + Value *LowShadow = IRB.CreateExtractElement(Second, IRB.getInt32(0), "_lo_a"); + Value *Shadow = IRB.CreateInsertElement(First, LowShadow, IRB.getInt32(0)); + + setShadow(&I, Shadow); + setOriginForNaryOp(I); + } + + void handleBinarySdIntrinsic(IntrinsicInst &I) { + IRBuilder<> IRB(&I); + Value *First = getShadow(&I, 0); + Value *Second = getShadow(&I, 1); + Value *LowA = IRB.CreateExtractElement(First, IRB.getInt32(0), "_lo_a"); + Value *LowB = IRB.CreateExtractElement(Second, IRB.getInt32(0), "_lo_b"); + Value *LowShadow = IRB.CreateOr(LowA, LowB); + Value *Shadow = IRB.CreateInsertElement(Second, LowShadow, IRB.getInt32(0)); + + setShadow(&I, Shadow); + setOriginForNaryOp(I); + } + void visitIntrinsicInst(IntrinsicInst &I) { switch (I.getIntrinsicID()) { case Intrinsic::lifetime_start: @@ -3293,6 +3318,13 @@ handlePclmulIntrinsic(I); break; + case Intrinsic::x86_sse41_round_sd: + handleUnarySdIntrinsic(I); + break; + case Intrinsic::x86_sse2_max_sd: + case Intrinsic::x86_sse2_min_sd: + handleBinarySdIntrinsic(I); + break; case Intrinsic::is_constant: // The result of llvm.is.constant() is always defined. setShadow(&I, getCleanShadow(&I));