|
181 | 181 | #include "llvm/IR/Instructions.h"
|
182 | 182 | #include "llvm/IR/IntrinsicInst.h"
|
183 | 183 | #include "llvm/IR/Intrinsics.h"
|
| 184 | +#include "llvm/IR/IntrinsicsAArch64.h" |
184 | 185 | #include "llvm/IR/IntrinsicsX86.h"
|
185 | 186 | #include "llvm/IR/MDBuilder.h"
|
186 | 187 | #include "llvm/IR/Module.h"
|
@@ -2498,6 +2499,15 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
|
2498 | 2499 | MSV->setOrigin(I, Origin);
|
2499 | 2500 | }
|
2500 | 2501 | }
|
| 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 | + } |
2501 | 2511 | };
|
2502 | 2512 |
|
2503 | 2513 | using ShadowAndOriginCombiner = Combiner<true>;
|
@@ -3865,6 +3875,69 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
|
3865 | 3875 | setOriginForNaryOp(I);
|
3866 | 3876 | }
|
3867 | 3877 |
|
| 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 | + |
3868 | 3941 | void visitIntrinsicInst(IntrinsicInst &I) {
|
3869 | 3942 | switch (I.getIntrinsicID()) {
|
3870 | 3943 | case Intrinsic::uadd_with_overflow:
|
@@ -4204,6 +4277,13 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
|
4204 | 4277 | setOrigin(&I, getCleanOrigin());
|
4205 | 4278 | break;
|
4206 | 4279 |
|
| 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 | + |
4207 | 4287 | default:
|
4208 | 4288 | if (!handleUnknownIntrinsic(I))
|
4209 | 4289 | visitInstruction(I);
|
|
0 commit comments