@@ -3944,6 +3944,56 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
3944
3944
}
3945
3945
}
3946
3946
3947
+ // / Handle intrinsics by applying the intrinsic to the shadows.
3948
+ // /
3949
+ // / The trailing arguments are passed verbatim to the intrinsic, though any
3950
+ // / uninitialized trailing arguments can also taint the shadow e.g., for an
3951
+ // / intrinsic with one trailing verbatim argument:
3952
+ // / out = intrinsic(var1, var2, opType)
3953
+ // / we compute:
3954
+ // / shadow[out] =
3955
+ // / intrinsic(shadow[var1], shadow[var2], opType) | shadow[opType]
3956
+ // /
3957
+ // / For example, this can be applied to the Arm NEON vector table intrinsics
3958
+ // / (tbl{1,2,3,4}).
3959
+ // /
3960
+ // / The origin is approximated using setOriginForNaryOp.
3961
+ void handleIntrinsicByApplyingToShadow (IntrinsicInst &I,
3962
+ unsigned int trailingVerbatimArgs) {
3963
+ IRBuilder<> IRB (&I);
3964
+
3965
+ assert (trailingVerbatimArgs < I.arg_size ());
3966
+
3967
+ SmallVector<Value *, 8 > ShadowArgs;
3968
+ // Don't use getNumOperands() because it includes the callee
3969
+ for (unsigned int i = 0 ; i < I.arg_size () - trailingVerbatimArgs; i++) {
3970
+ Value *Shadow = getShadow (&I, i);
3971
+ ShadowArgs.push_back (Shadow);
3972
+ }
3973
+
3974
+ for (unsigned int i = I.arg_size () - trailingVerbatimArgs; i < I.arg_size ();
3975
+ i++) {
3976
+ Value *Arg = I.getArgOperand (i);
3977
+ ShadowArgs.push_back (Arg);
3978
+ }
3979
+
3980
+ CallInst *CI =
3981
+ IRB.CreateIntrinsic (I.getType (), I.getIntrinsicID (), ShadowArgs);
3982
+ Value *CombinedShadow = CI;
3983
+
3984
+ // Combine the computed shadow with the shadow of trailing args
3985
+ for (unsigned int i = I.arg_size () - trailingVerbatimArgs; i < I.arg_size ();
3986
+ i++) {
3987
+ Value *Shadow =
3988
+ CreateShadowCast (IRB, getShadow (&I, i), CombinedShadow->getType ());
3989
+ CombinedShadow = IRB.CreateOr (Shadow, CombinedShadow, " _msprop" );
3990
+ }
3991
+
3992
+ setShadow (&I, CombinedShadow);
3993
+
3994
+ setOriginForNaryOp (I);
3995
+ }
3996
+
3947
3997
void visitIntrinsicInst (IntrinsicInst &I) {
3948
3998
switch (I.getIntrinsicID ()) {
3949
3999
case Intrinsic::uadd_with_overflow:
@@ -4319,6 +4369,28 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
4319
4369
break ;
4320
4370
}
4321
4371
4372
+ // Arm NEON vector table intrinsics have the source/table register(s) as
4373
+ // arguments, followed by the index register. They return the output.
4374
+ //
4375
+ // 'TBL writes a zero if an index is out-of-range, while TBX leaves the
4376
+ // original value unchanged in the destination register.'
4377
+ // Conveniently, zero denotes a clean shadow, which means out-of-range
4378
+ // indices for TBL will initialize the user data with zero and also clean
4379
+ // the shadow. (For TBX, neither the user data nor the shadow will be
4380
+ // updated, which is also correct.)
4381
+ case Intrinsic::aarch64_neon_tbl1:
4382
+ case Intrinsic::aarch64_neon_tbl2:
4383
+ case Intrinsic::aarch64_neon_tbl3:
4384
+ case Intrinsic::aarch64_neon_tbl4:
4385
+ case Intrinsic::aarch64_neon_tbx1:
4386
+ case Intrinsic::aarch64_neon_tbx2:
4387
+ case Intrinsic::aarch64_neon_tbx3:
4388
+ case Intrinsic::aarch64_neon_tbx4: {
4389
+ // The last trailing argument (index register) should be handled verbatim
4390
+ handleIntrinsicByApplyingToShadow (I, 1 );
4391
+ break ;
4392
+ }
4393
+
4322
4394
default :
4323
4395
if (!handleUnknownIntrinsic (I))
4324
4396
visitInstruction (I);
0 commit comments