Skip to content

Commit bfbe531

Browse files
authored
[msan] Add handlePairwiseShadowOrIntrinsic and use it to handle Arm NEON pairwise add (#126008)
This patch adds a function, handlePairwiseShadowOrIntrinsic that ORs pairs of adjacent shadow values; this is suitable for propagating shadow for 1- or 2-vector intrinsics that combine adjacent fields. It then applies handlePairwiseShadowOrIntrinsic to Arm NEON pairwise add: llvm.aarch64.neon.{addhn, raddhn} (currently incorrectly handled) and llvm.aarch64.neon.{saddlp, uaddlp} (currently suboptimally handled). Updates the tests from #125820.
1 parent 6de4de8 commit bfbe531

File tree

3 files changed

+291
-259
lines changed

3 files changed

+291
-259
lines changed

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2602,6 +2602,59 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
26022602
SC.Done(&I);
26032603
}
26042604

2605+
/// Propagate shadow for 1- or 2-vector intrinsics that combine adjacent
2606+
/// fields.
2607+
///
2608+
/// e.g., <2 x i32> @llvm.aarch64.neon.saddlp.v2i32.v4i16(<4 x i16>)
2609+
/// <16 x i8> @llvm.aarch64.neon.addp.v16i8(<16 x i8>, <16 x i8>)
2610+
///
2611+
/// TODO: adapt this function to handle horizontal add/sub?
2612+
void handlePairwiseShadowOrIntrinsic(IntrinsicInst &I) {
2613+
assert(I.arg_size() == 1 || I.arg_size() == 2);
2614+
2615+
assert(I.getType()->isVectorTy());
2616+
assert(I.getArgOperand(0)->getType()->isVectorTy());
2617+
2618+
FixedVectorType *ParamType =
2619+
cast<FixedVectorType>(I.getArgOperand(0)->getType());
2620+
if (I.arg_size() == 2)
2621+
assert(ParamType == cast<FixedVectorType>(I.getArgOperand(1)->getType()));
2622+
FixedVectorType *ReturnType = cast<FixedVectorType>(I.getType());
2623+
assert(ParamType->getNumElements() * I.arg_size() ==
2624+
2 * ReturnType->getNumElements());
2625+
2626+
IRBuilder<> IRB(&I);
2627+
unsigned Width = ParamType->getNumElements() * I.arg_size();
2628+
2629+
// Horizontal OR of shadow
2630+
SmallVector<int, 8> EvenMask;
2631+
SmallVector<int, 8> OddMask;
2632+
for (unsigned X = 0; X < Width; X += 2) {
2633+
EvenMask.push_back(X);
2634+
OddMask.push_back(X + 1);
2635+
}
2636+
2637+
Value *FirstArgShadow = getShadow(&I, 0);
2638+
Value *EvenShadow;
2639+
Value *OddShadow;
2640+
if (I.arg_size() == 2) {
2641+
Value *SecondArgShadow = getShadow(&I, 1);
2642+
EvenShadow =
2643+
IRB.CreateShuffleVector(FirstArgShadow, SecondArgShadow, EvenMask);
2644+
OddShadow =
2645+
IRB.CreateShuffleVector(FirstArgShadow, SecondArgShadow, OddMask);
2646+
} else {
2647+
EvenShadow = IRB.CreateShuffleVector(FirstArgShadow, EvenMask);
2648+
OddShadow = IRB.CreateShuffleVector(FirstArgShadow, OddMask);
2649+
}
2650+
2651+
Value *OrShadow = IRB.CreateOr(EvenShadow, OddShadow);
2652+
OrShadow = CreateShadowCast(IRB, OrShadow, getShadowTy(&I));
2653+
2654+
setShadow(&I, OrShadow);
2655+
setOriginForNaryOp(I);
2656+
}
2657+
26052658
void visitFNeg(UnaryOperator &I) { handleShadowOr(I); }
26062659

26072660
// Handle multiplication by constant.
@@ -4781,6 +4834,17 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
47814834
setOrigin(&I, getCleanOrigin());
47824835
break;
47834836

4837+
// Add Pairwise
4838+
case Intrinsic::aarch64_neon_addp:
4839+
// Floating-point Add Pairwise
4840+
case Intrinsic::aarch64_neon_faddp:
4841+
// Add Long Pairwise
4842+
case Intrinsic::aarch64_neon_saddlp:
4843+
case Intrinsic::aarch64_neon_uaddlp: {
4844+
handlePairwiseShadowOrIntrinsic(I);
4845+
break;
4846+
}
4847+
47844848
case Intrinsic::aarch64_neon_st1x2:
47854849
case Intrinsic::aarch64_neon_st1x3:
47864850
case Intrinsic::aarch64_neon_st1x4:

0 commit comments

Comments
 (0)