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,32 @@ SOC.Done(&I); } + // Instrument _mm_*_sd intrinsics + void handleUnarySdIntrinsic(IntrinsicInst &I) { + IRBuilder<> IRB(&I); + Value *First = getShadow(&I, 0); + Value *Second = getShadow(&I, 1); + // High word of first operand, low word of second + Value *Shadow = + IRB.CreateShuffleVector(First, Second, llvm::ArrayRef({2, 1})); + + setShadow(&I, Shadow); + setOriginForNaryOp(I); + } + + void handleBinarySdIntrinsic(IntrinsicInst &I) { + IRBuilder<> IRB(&I); + Value *First = getShadow(&I, 0); + Value *Second = getShadow(&I, 1); + Value *OrShadow = IRB.CreateOr(First, Second); + // High word of first operand, low word of both OR'd together + Value *Shadow = + IRB.CreateShuffleVector(First, OrShadow, llvm::ArrayRef({2, 1})); + + setShadow(&I, Shadow); + setOriginForNaryOp(I); + } + void visitIntrinsicInst(IntrinsicInst &I) { switch (I.getIntrinsicID()) { case Intrinsic::lifetime_start: @@ -3293,6 +3319,24 @@ 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::x86_avx512_mask_add_sd_round: + // case Intrinsic::x86_avx512_mask_sub_sd_round: + // case Intrinsic::x86_avx512_mask_mul_sd_round: + // case Intrinsic::x86_avx512_mask_div_sd_round: + // case Intrinsic::x86_avx512_mask_max_sd_round: + // case Intrinsic::x86_avx512_mask_min_sd_round: + // case Intrinsic::x86_avx512_mask_sqrt_sd: + // case Intrinsic::x86_avx512_mask_getexp_sd: + // handleSdIntrinsic(I, /* masked */ true); + // break; + case Intrinsic::is_constant: // The result of llvm.is.constant() is always defined. setShadow(&I, getCleanShadow(&I)); diff --git a/llvm/test/Instrumentation/MemorySanitizer/vector_sd.ll b/llvm/test/Instrumentation/MemorySanitizer/vector_sd.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/MemorySanitizer/vector_sd.ll @@ -0,0 +1,48 @@ +; RUN: opt < %s -msan-check-access-address=0 -S -passes=msan 2>&1 | FileCheck \ +; RUN: %s +; RUN: opt < %s -msan -msan-check-access-address=0 -S | FileCheck %s +; REQUIRES: x86-registered-target + +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" +target triple = "x86_64-unknown-linux-gnu" + +declare <2 x double> @llvm.x86.sse41.round.sd(<2 x double>, <2 x double>, i32) nounwind readnone +declare <2 x double> @llvm.x86.sse2.min.sd(<2 x double>, <2 x double>) nounwind readnone + +define <2 x double> @test_sse_round_sd(double %lowval, double %hival) sanitize_memory { +entry: + ; CHECK: [[HIVAL_SHADOW:%[0-9]+]] = load {{.*}} @__msan_param_tls + ; CHECK: [[LOWVAL_SHADOW:%[0-9]+]] = load {{.*}} @__msan_param_tls + ; CHECK: [[OP2VEC_SHADOW:%.+]] = insertelement <2 x i64> , i64 [[LOWVAL_SHADOW]], i32 0 + %op2vec = insertelement <2 x double> undef, double %lowval, i32 0 + ; CHECK: [[OP1VEC_SHADOW:%.+]] = insertelement <2 x i64> , i64 [[HIVAL_SHADOW]], i32 1 + %op1vec = insertelement <2 x double> undef, double %hival, i32 1 + ; CHECK: [[OUT_SHADOW:%.+]] = shufflevector <2 x i64> [[OP1VEC_SHADOW]], <2 x i64> [[OP2VEC_SHADOW]], <2 x i32> + ; CHECK-NOT: call void @msan_warning + ; CHECK: call <2 x double> @llvm.x86.sse41.round.sd + %0 = tail call <2 x double> @llvm.x86.sse41.round.sd(<2 x double> %op1vec, <2 x double> %op2vec, i32 0) + ; CHECK: store <2 x i64> [[OUT_SHADOW]], {{.*}} @__msan_retval_tls + ; CHECK: ret <2 x double> + ret <2 x double> %0 +} + +define <2 x double> @test_sse_min_sd(double %lowval0, double %lowval1, double %hival) sanitize_memory { +entry: + ; CHECK: [[LOWVAL1_SHADOW:%[0-9]+]] = load {{.*}} @__msan_param_tls + ; CHECK: [[HIVAL_SHADOW:%[0-9]+]] = load {{.*}} @__msan_param_tls + ; CHECK: [[LOWVAL0_SHADOW:%[0-9]+]] = load {{.*}} @__msan_param_tls + ; CHECK: [[OP2_SHADOW:%.+]] = insertelement <2 x i64> , i64 [[LOWVAL0_SHADOW]], i32 0 + %op2vec = insertelement <2 x double> undef, double %lowval0, i32 0 + ; CHECK: [[HIVEC_SHADOW:%.+]] = insertelement <2 x i64> , i64 [[HIVAL_SHADOW]], i32 1 + %hivec = insertelement <2 x double> undef, double %hival, i32 1 + ; CHECK: [[OP1_SHADOW:%.+]] = insertelement <2 x i64> [[HIVEC_SHADOW]], i64 [[LOWVAL1_SHADOW]], i32 0 + %op1vec = insertelement <2 x double> %hivec, double %lowval1, i32 0 + ; CHECK: [[OR_SHADOW:%.+]] = or <2 x i64> [[OP1_SHADOW]], [[OP2_SHADOW]] + ; CHECK: [[OUT_SHADOW_VEC:%.+]] = shufflevector <2 x i64> [[OP1_SHADOW]], <2 x i64> [[OR_SHADOW]], <2 x i32> + ; CHECK-NOT: call void @msan_warning + ; CHECK: call <2 x double> @llvm.x86.sse2.min.sd + %0 = tail call <2 x double> @llvm.x86.sse2.min.sd(<2 x double> %op1vec, <2 x double> %op2vec) + ; CHECK: store <2 x i64> [[OUT_SHADOW_VEC]], {{.*}} @__msan_retval_tls + ; CHECK: ret <2 x double> + ret <2 x double> %0 +}