@@ -3944,6 +3944,56 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
39443944 }
39453945 }
39463946
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+
39473997 void visitIntrinsicInst (IntrinsicInst &I) {
39483998 switch (I.getIntrinsicID ()) {
39493999 case Intrinsic::uadd_with_overflow:
@@ -4319,6 +4369,28 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
43194369 break ;
43204370 }
43214371
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+
43224394 default :
43234395 if (!handleUnknownIntrinsic (I))
43244396 visitInstruction (I);
0 commit comments