Skip to content

Commit e9e6ba6

Browse files
authored
[msan] Handle single-parameter Arm NEON vector convert intrinsics (#126136)
This handles the following llvm.aarch64.neon intrinsics, which were suboptimally handled by visitInstruction: - fcvtas, fcvtau - fcvtms, fcvtmu - fcvtns, fcvtnu - fcvtps, fcvtpu - fcvtzs, fcvtzu The old instrumentation checked that the shadow of every element of the input vector was fully initialized, and aborted otherwise. The new instrumentation propagates the shadow: for each element of the output, the shadow is initialized iff the corresponding element of the input is *fully* initialized (since these are floating-point to integer conversions). Updates the tests from #126095
1 parent 8260528 commit e9e6ba6

File tree

3 files changed

+262
-587
lines changed

3 files changed

+262
-587
lines changed

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3172,7 +3172,31 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
31723172
setOriginForNaryOp(I);
31733173
}
31743174

3175-
// Instrument vector convert intrinsic.
3175+
/// Handle Arm NEON vector convert intrinsics.
3176+
///
3177+
/// e.g., <4 x i32> @llvm.aarch64.neon.fcvtpu.v4i32.v4f32(<4 x float>)
3178+
/// i32 @llvm.aarch64.neon.fcvtms.i32.f64(double)
3179+
///
3180+
/// For x86 SSE vector convert intrinsics, see
3181+
/// handleSSEVectorConvertIntrinsic().
3182+
void handleNEONVectorConvertIntrinsic(IntrinsicInst &I) {
3183+
assert(I.arg_size() == 1);
3184+
3185+
IRBuilder<> IRB(&I);
3186+
Value *S0 = getShadow(&I, 0);
3187+
3188+
/// For scalars:
3189+
/// Since they are converting from floating-point to integer, the output is
3190+
/// - fully uninitialized if *any* bit of the input is uninitialized
3191+
/// - fully ininitialized if all bits of the input are ininitialized
3192+
/// We apply the same principle on a per-field basis for vectors.
3193+
Value *OutShadow = IRB.CreateSExt(IRB.CreateICmpNE(S0, getCleanShadow(S0)),
3194+
getShadowTy(&I));
3195+
setShadow(&I, OutShadow);
3196+
setOriginForNaryOp(I);
3197+
}
3198+
3199+
// Instrument x86 SSE vector convert intrinsic.
31763200
//
31773201
// This function instruments intrinsics like cvtsi2ss:
31783202
// %Out = int_xxx_cvtyyy(%ConvertOp)
@@ -3187,8 +3211,11 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
31873211
// We copy the shadow of \p CopyOp[NumUsedElements:] to \p
31883212
// Out[NumUsedElements:]. This means that intrinsics without \p CopyOp always
31893213
// return a fully initialized value.
3190-
void handleVectorConvertIntrinsic(IntrinsicInst &I, int NumUsedElements,
3191-
bool HasRoundingMode = false) {
3214+
//
3215+
// For Arm NEON vector convert intrinsics, see
3216+
// handleNEONVectorConvertIntrinsic().
3217+
void handleSSEVectorConvertIntrinsic(IntrinsicInst &I, int NumUsedElements,
3218+
bool HasRoundingMode = false) {
31923219
IRBuilder<> IRB(&I);
31933220
Value *CopyOp, *ConvertOp;
31943221

@@ -4477,7 +4504,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
44774504
case Intrinsic::x86_avx512_cvtusi2ss:
44784505
case Intrinsic::x86_avx512_cvtusi642sd:
44794506
case Intrinsic::x86_avx512_cvtusi642ss:
4480-
handleVectorConvertIntrinsic(I, 1, true);
4507+
handleSSEVectorConvertIntrinsic(I, 1, true);
44814508
break;
44824509
case Intrinsic::x86_sse2_cvtsd2si64:
44834510
case Intrinsic::x86_sse2_cvtsd2si:
@@ -4488,11 +4515,11 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
44884515
case Intrinsic::x86_sse_cvtss2si:
44894516
case Intrinsic::x86_sse_cvttss2si64:
44904517
case Intrinsic::x86_sse_cvttss2si:
4491-
handleVectorConvertIntrinsic(I, 1);
4518+
handleSSEVectorConvertIntrinsic(I, 1);
44924519
break;
44934520
case Intrinsic::x86_sse_cvtps2pi:
44944521
case Intrinsic::x86_sse_cvttps2pi:
4495-
handleVectorConvertIntrinsic(I, 2);
4522+
handleSSEVectorConvertIntrinsic(I, 2);
44964523
break;
44974524

44984525
case Intrinsic::x86_avx512_psll_w_512:
@@ -4846,6 +4873,27 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
48464873
break;
48474874
}
48484875

4876+
// Floating-point Convert to integer, rounding to nearest with ties to Away
4877+
case Intrinsic::aarch64_neon_fcvtas:
4878+
case Intrinsic::aarch64_neon_fcvtau:
4879+
// Floating-point convert to integer, rounding toward minus infinity
4880+
case Intrinsic::aarch64_neon_fcvtms:
4881+
case Intrinsic::aarch64_neon_fcvtmu:
4882+
// Floating-point convert to integer, rounding to nearest with ties to even
4883+
case Intrinsic::aarch64_neon_fcvtns:
4884+
case Intrinsic::aarch64_neon_fcvtnu:
4885+
// Floating-point convert to integer, rounding toward plus infinity
4886+
case Intrinsic::aarch64_neon_fcvtps:
4887+
case Intrinsic::aarch64_neon_fcvtpu:
4888+
// Floating-point Convert to integer, rounding toward Zero
4889+
case Intrinsic::aarch64_neon_fcvtzs:
4890+
case Intrinsic::aarch64_neon_fcvtzu:
4891+
// Floating-point convert to lower precision narrow, rounding to odd
4892+
case Intrinsic::aarch64_neon_fcvtxn: {
4893+
handleNEONVectorConvertIntrinsic(I);
4894+
break;
4895+
}
4896+
48494897
case Intrinsic::aarch64_neon_st1x2:
48504898
case Intrinsic::aarch64_neon_st1x3:
48514899
case Intrinsic::aarch64_neon_st1x4:

0 commit comments

Comments
 (0)