Skip to content

Commit 7c7b758

Browse files
thurstondyuxuanchen1997
authored andcommitted
[msan] Implement support for Arm NEON vst{2,3,4} instructions (#99360)
Summary: This adds support for vst{2,3,4}, which are not correctly handled by handleUnknownIntrinsic/handleVector{Load,Store}Intrinsic. This patch also updates the tests introduced in #98247 and #99555 --------- Co-authored-by: Vitaly Buka <[email protected]> Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251436
1 parent 9bc1d57 commit 7c7b758

File tree

3 files changed

+1367
-821
lines changed

3 files changed

+1367
-821
lines changed

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@
181181
#include "llvm/IR/Instructions.h"
182182
#include "llvm/IR/IntrinsicInst.h"
183183
#include "llvm/IR/Intrinsics.h"
184+
#include "llvm/IR/IntrinsicsAArch64.h"
184185
#include "llvm/IR/IntrinsicsX86.h"
185186
#include "llvm/IR/MDBuilder.h"
186187
#include "llvm/IR/Module.h"
@@ -2498,6 +2499,15 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
24982499
MSV->setOrigin(I, Origin);
24992500
}
25002501
}
2502+
2503+
/// Store the current combined value at the specified origin
2504+
/// location.
2505+
void DoneAndStoreOrigin(TypeSize TS, Value *OriginPtr) {
2506+
if (MSV->MS.TrackOrigins) {
2507+
assert(Origin);
2508+
MSV->paintOrigin(IRB, Origin, OriginPtr, TS, kMinOriginAlignment);
2509+
}
2510+
}
25012511
};
25022512

25032513
using ShadowAndOriginCombiner = Combiner<true>;
@@ -3865,6 +3875,69 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
38653875
setOriginForNaryOp(I);
38663876
}
38673877

3878+
/// Handle Arm NEON vector store intrinsics (vst{2,3,4}).
3879+
///
3880+
/// Arm NEON vector store intrinsics have the output address (pointer) as the
3881+
/// last argument, with the initial arguments being the inputs. They return
3882+
/// void.
3883+
void handleNEONVectorStoreIntrinsic(IntrinsicInst &I) {
3884+
IRBuilder<> IRB(&I);
3885+
3886+
// Don't use getNumOperands() because it includes the callee
3887+
int numArgOperands = I.arg_size();
3888+
assert(numArgOperands >= 1);
3889+
3890+
// The last arg operand is the output
3891+
Value *Addr = I.getArgOperand(numArgOperands - 1);
3892+
assert(Addr->getType()->isPointerTy());
3893+
3894+
if (ClCheckAccessAddress)
3895+
insertShadowCheck(Addr, &I);
3896+
3897+
// Every arg operand, other than the last one, is an input vector
3898+
IntrinsicInst *ShadowI = cast<IntrinsicInst>(I.clone());
3899+
for (int i = 0; i < numArgOperands - 1; i++) {
3900+
assert(isa<FixedVectorType>(I.getArgOperand(i)->getType()));
3901+
ShadowI->setArgOperand(i, getShadow(&I, i));
3902+
}
3903+
3904+
// MSan's GetShadowTy assumes the LHS is the type we want the shadow for
3905+
// e.g., for:
3906+
// [[TMP5:%.*]] = bitcast <16 x i8> [[TMP2]] to i128
3907+
// we know the type of the output (and its shadow) is <16 x i8>.
3908+
//
3909+
// Arm NEON VST is unusual because the last argument is the output address:
3910+
// define void @st2_16b(<16 x i8> %A, <16 x i8> %B, ptr %P) {
3911+
// call void @llvm.aarch64.neon.st2.v16i8.p0
3912+
// (<16 x i8> [[A]], <16 x i8> [[B]], ptr [[P]])
3913+
// and we have no type information about P's operand. We must manually
3914+
// compute the type (<16 x i8> x 2).
3915+
FixedVectorType *OutputVectorTy = FixedVectorType::get(
3916+
cast<FixedVectorType>(I.getArgOperand(0)->getType())->getElementType(),
3917+
cast<FixedVectorType>(I.getArgOperand(0)->getType())->getNumElements() *
3918+
(numArgOperands - 1));
3919+
Type *ShadowTy = getShadowTy(OutputVectorTy);
3920+
Value *ShadowPtr, *OriginPtr;
3921+
// AArch64 NEON does not need alignment (unless OS requires it)
3922+
std::tie(ShadowPtr, OriginPtr) =
3923+
getShadowOriginPtr(Addr, IRB, ShadowTy, Align(1), /*isStore*/ true);
3924+
ShadowI->setArgOperand(numArgOperands - 1, ShadowPtr);
3925+
ShadowI->insertAfter(&I);
3926+
3927+
if (MS.TrackOrigins) {
3928+
// TODO: if we modelled the vst* instruction more precisely, we could
3929+
// more accurately track the origins (e.g., if both inputs are
3930+
// uninitialized for vst2, we currently blame the second input, even
3931+
// though part of the output depends only on the first input).
3932+
OriginCombiner OC(this, IRB);
3933+
for (int i = 0; i < numArgOperands - 1; i++)
3934+
OC.Add(I.getArgOperand(i));
3935+
3936+
const DataLayout &DL = F.getDataLayout();
3937+
OC.DoneAndStoreOrigin(DL.getTypeStoreSize(OutputVectorTy), OriginPtr);
3938+
}
3939+
}
3940+
38683941
void visitIntrinsicInst(IntrinsicInst &I) {
38693942
switch (I.getIntrinsicID()) {
38703943
case Intrinsic::uadd_with_overflow:
@@ -4204,6 +4277,13 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
42044277
setOrigin(&I, getCleanOrigin());
42054278
break;
42064279

4280+
case Intrinsic::aarch64_neon_st2:
4281+
case Intrinsic::aarch64_neon_st3:
4282+
case Intrinsic::aarch64_neon_st4: {
4283+
handleNEONVectorStoreIntrinsic(I);
4284+
break;
4285+
}
4286+
42074287
default:
42084288
if (!handleUnknownIntrinsic(I))
42094289
visitInstruction(I);

0 commit comments

Comments
 (0)