Skip to content

Commit

Permalink
[msan] Handle single-parameter Arm NEON vector convert intrinsics (#1…
Browse files Browse the repository at this point in the history
…26136)

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 llvm/llvm-project#126095
  • Loading branch information
thurstond authored Feb 12, 2025
1 parent 8260528 commit e9e6ba6
Show file tree
Hide file tree
Showing 3 changed files with 262 additions and 587 deletions.
60 changes: 54 additions & 6 deletions llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3172,7 +3172,31 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
setOriginForNaryOp(I);
}

// Instrument vector convert intrinsic.
/// Handle Arm NEON vector convert intrinsics.
///
/// e.g., <4 x i32> @llvm.aarch64.neon.fcvtpu.v4i32.v4f32(<4 x float>)
/// i32 @llvm.aarch64.neon.fcvtms.i32.f64(double)
///
/// For x86 SSE vector convert intrinsics, see
/// handleSSEVectorConvertIntrinsic().
void handleNEONVectorConvertIntrinsic(IntrinsicInst &I) {
assert(I.arg_size() == 1);

IRBuilder<> IRB(&I);
Value *S0 = getShadow(&I, 0);

/// For scalars:
/// Since they are converting from floating-point to integer, the output is
/// - fully uninitialized if *any* bit of the input is uninitialized
/// - fully ininitialized if all bits of the input are ininitialized
/// We apply the same principle on a per-field basis for vectors.
Value *OutShadow = IRB.CreateSExt(IRB.CreateICmpNE(S0, getCleanShadow(S0)),
getShadowTy(&I));
setShadow(&I, OutShadow);
setOriginForNaryOp(I);
}

// Instrument x86 SSE vector convert intrinsic.
//
// This function instruments intrinsics like cvtsi2ss:
// %Out = int_xxx_cvtyyy(%ConvertOp)
Expand All @@ -3187,8 +3211,11 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
// We copy the shadow of \p CopyOp[NumUsedElements:] to \p
// Out[NumUsedElements:]. This means that intrinsics without \p CopyOp always
// return a fully initialized value.
void handleVectorConvertIntrinsic(IntrinsicInst &I, int NumUsedElements,
bool HasRoundingMode = false) {
//
// For Arm NEON vector convert intrinsics, see
// handleNEONVectorConvertIntrinsic().
void handleSSEVectorConvertIntrinsic(IntrinsicInst &I, int NumUsedElements,
bool HasRoundingMode = false) {
IRBuilder<> IRB(&I);
Value *CopyOp, *ConvertOp;

Expand Down Expand Up @@ -4477,7 +4504,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
case Intrinsic::x86_avx512_cvtusi2ss:
case Intrinsic::x86_avx512_cvtusi642sd:
case Intrinsic::x86_avx512_cvtusi642ss:
handleVectorConvertIntrinsic(I, 1, true);
handleSSEVectorConvertIntrinsic(I, 1, true);
break;
case Intrinsic::x86_sse2_cvtsd2si64:
case Intrinsic::x86_sse2_cvtsd2si:
Expand All @@ -4488,11 +4515,11 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
case Intrinsic::x86_sse_cvtss2si:
case Intrinsic::x86_sse_cvttss2si64:
case Intrinsic::x86_sse_cvttss2si:
handleVectorConvertIntrinsic(I, 1);
handleSSEVectorConvertIntrinsic(I, 1);
break;
case Intrinsic::x86_sse_cvtps2pi:
case Intrinsic::x86_sse_cvttps2pi:
handleVectorConvertIntrinsic(I, 2);
handleSSEVectorConvertIntrinsic(I, 2);
break;

case Intrinsic::x86_avx512_psll_w_512:
Expand Down Expand Up @@ -4846,6 +4873,27 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
break;
}

// Floating-point Convert to integer, rounding to nearest with ties to Away
case Intrinsic::aarch64_neon_fcvtas:
case Intrinsic::aarch64_neon_fcvtau:
// Floating-point convert to integer, rounding toward minus infinity
case Intrinsic::aarch64_neon_fcvtms:
case Intrinsic::aarch64_neon_fcvtmu:
// Floating-point convert to integer, rounding to nearest with ties to even
case Intrinsic::aarch64_neon_fcvtns:
case Intrinsic::aarch64_neon_fcvtnu:
// Floating-point convert to integer, rounding toward plus infinity
case Intrinsic::aarch64_neon_fcvtps:
case Intrinsic::aarch64_neon_fcvtpu:
// Floating-point Convert to integer, rounding toward Zero
case Intrinsic::aarch64_neon_fcvtzs:
case Intrinsic::aarch64_neon_fcvtzu:
// Floating-point convert to lower precision narrow, rounding to odd
case Intrinsic::aarch64_neon_fcvtxn: {
handleNEONVectorConvertIntrinsic(I);
break;
}

case Intrinsic::aarch64_neon_st1x2:
case Intrinsic::aarch64_neon_st1x3:
case Intrinsic::aarch64_neon_st1x4:
Expand Down
Loading

0 comments on commit e9e6ba6

Please sign in to comment.