llvm.org GIT mirror llvm / 133b6ea
[MSan] [PowerPC] Implement PowerPC64 vararg helper. Differential Revision: http://reviews.llvm.org/D20000 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@269518 91177308-0d34-0410-b5e6-96231b3b80d8 Marcin Koscielnicki 4 years ago
3 changed file(s) with 371 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
378378 friend struct VarArgAMD64Helper;
379379 friend struct VarArgMIPS64Helper;
380380 friend struct VarArgAArch64Helper;
381 friend struct VarArgPowerPC64Helper;
381382 };
382383 } // anonymous namespace
383384
33733374 }
33743375 };
33753376
3377 /// \brief PowerPC64-specific implementation of VarArgHelper.
3378 struct VarArgPowerPC64Helper : public VarArgHelper {
3379 Function &F;
3380 MemorySanitizer &MS;
3381 MemorySanitizerVisitor &MSV;
3382 Value *VAArgTLSCopy;
3383 Value *VAArgSize;
3384
3385 SmallVector VAStartInstrumentationList;
3386
3387 VarArgPowerPC64Helper(Function &F, MemorySanitizer &MS,
3388 MemorySanitizerVisitor &MSV)
3389 : F(F), MS(MS), MSV(MSV), VAArgTLSCopy(nullptr),
3390 VAArgSize(nullptr) {}
3391
3392 void visitCallSite(CallSite &CS, IRBuilder<> &IRB) override {
3393 // For PowerPC, we need to deal with alignment of stack arguments -
3394 // they are mostly aligned to 8 bytes, but vectors and i128 arrays
3395 // are aligned to 16 bytes, byvals can be aligned to 8 or 16 bytes,
3396 // and QPX vectors are aligned to 32 bytes. For that reason, we
3397 // compute current offset from stack pointer (which is always properly
3398 // aligned), and offset for the first vararg, then subtract them.
3399 unsigned VAArgBase;
3400 llvm::Triple TargetTriple(F.getParent()->getTargetTriple());
3401 // Parameter save area starts at 48 bytes from frame pointer for ABIv1,
3402 // and 32 bytes for ABIv2. This is usually determined by target
3403 // endianness, but in theory could be overriden by function attribute.
3404 // For simplicity, we ignore it here (it'd only matter for QPX vectors).
3405 if (TargetTriple.getArch() == llvm::Triple::ppc64)
3406 VAArgBase = 48;
3407 else
3408 VAArgBase = 32;
3409 unsigned VAArgOffset = VAArgBase;
3410 const DataLayout &DL = F.getParent()->getDataLayout();
3411 for (CallSite::arg_iterator ArgIt = CS.arg_begin(), End = CS.arg_end();
3412 ArgIt != End; ++ArgIt) {
3413 Value *A = *ArgIt;
3414 unsigned ArgNo = CS.getArgumentNo(ArgIt);
3415 bool IsFixed = ArgNo < CS.getFunctionType()->getNumParams();
3416 bool IsByVal = CS.paramHasAttr(ArgNo + 1, Attribute::ByVal);
3417 if (IsByVal) {
3418 assert(A->getType()->isPointerTy());
3419 Type *RealTy = A->getType()->getPointerElementType();
3420 uint64_t ArgSize = DL.getTypeAllocSize(RealTy);
3421 uint64_t ArgAlign = CS.getParamAlignment(ArgNo + 1);
3422 if (ArgAlign < 8)
3423 ArgAlign = 8;
3424 VAArgOffset = alignTo(VAArgOffset, ArgAlign);
3425 if (!IsFixed) {
3426 Value *Base = getShadowPtrForVAArgument(RealTy, IRB,
3427 VAArgOffset - VAArgBase);
3428 IRB.CreateMemCpy(Base, MSV.getShadowPtr(A, IRB.getInt8Ty(), IRB),
3429 ArgSize, kShadowTLSAlignment);
3430 }
3431 VAArgOffset += alignTo(ArgSize, 8);
3432 } else {
3433 Value *Base;
3434 uint64_t ArgSize = DL.getTypeAllocSize(A->getType());
3435 uint64_t ArgAlign = 8;
3436 if (A->getType()->isArrayTy()) {
3437 // Arrays are aligned to element size, except for long double
3438 // arrays, which are aligned to 8 bytes.
3439 Type *ElementTy = A->getType()->getArrayElementType();
3440 if (!ElementTy->isPPC_FP128Ty())
3441 ArgAlign = DL.getTypeAllocSize(ElementTy);
3442 } else if (A->getType()->isVectorTy()) {
3443 // Vectors are naturally aligned.
3444 ArgAlign = DL.getTypeAllocSize(A->getType());
3445 }
3446 if (ArgAlign < 8)
3447 ArgAlign = 8;
3448 VAArgOffset = alignTo(VAArgOffset, ArgAlign);
3449 if (DL.isBigEndian()) {
3450 // Adjusting the shadow for argument with size < 8 to match the placement
3451 // of bits in big endian system
3452 if (ArgSize < 8)
3453 VAArgOffset += (8 - ArgSize);
3454 }
3455 if (!IsFixed) {
3456 Base = getShadowPtrForVAArgument(A->getType(), IRB,
3457 VAArgOffset - VAArgBase);
3458 IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment);
3459 }
3460 VAArgOffset += ArgSize;
3461 VAArgOffset = alignTo(VAArgOffset, 8);
3462 }
3463 if (IsFixed)
3464 VAArgBase = VAArgOffset;
3465 }
3466
3467 Constant *TotalVAArgSize = ConstantInt::get(IRB.getInt64Ty(),
3468 VAArgOffset - VAArgBase);
3469 // Here using VAArgOverflowSizeTLS as VAArgSizeTLS to avoid creation of
3470 // a new class member i.e. it is the total size of all VarArgs.
3471 IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS);
3472 }
3473
3474 /// \brief Compute the shadow address for a given va_arg.
3475 Value *getShadowPtrForVAArgument(Type *Ty, IRBuilder<> &IRB,
3476 int ArgOffset) {
3477 Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy);
3478 Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset));
3479 return IRB.CreateIntToPtr(Base, PointerType::get(MSV.getShadowTy(Ty), 0),
3480 "_msarg");
3481 }
3482
3483 void visitVAStartInst(VAStartInst &I) override {
3484 IRBuilder<> IRB(&I);
3485 VAStartInstrumentationList.push_back(&I);
3486 Value *VAListTag = I.getArgOperand(0);
3487 Value *ShadowPtr = MSV.getShadowPtr(VAListTag, IRB.getInt8Ty(), IRB);
3488 IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()),
3489 /* size */8, /* alignment */8, false);
3490 }
3491
3492 void visitVACopyInst(VACopyInst &I) override {
3493 IRBuilder<> IRB(&I);
3494 Value *VAListTag = I.getArgOperand(0);
3495 Value *ShadowPtr = MSV.getShadowPtr(VAListTag, IRB.getInt8Ty(), IRB);
3496 // Unpoison the whole __va_list_tag.
3497 // FIXME: magic ABI constants.
3498 IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()),
3499 /* size */8, /* alignment */8, false);
3500 }
3501
3502 void finalizeInstrumentation() override {
3503 assert(!VAArgSize && !VAArgTLSCopy &&
3504 "finalizeInstrumentation called twice");
3505 IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI());
3506 VAArgSize = IRB.CreateLoad(MS.VAArgOverflowSizeTLS);
3507 Value *CopySize = IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, 0),
3508 VAArgSize);
3509
3510 if (!VAStartInstrumentationList.empty()) {
3511 // If there is a va_start in this function, make a backup copy of
3512 // va_arg_tls somewhere in the function entry block.
3513 VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);
3514 IRB.CreateMemCpy(VAArgTLSCopy, MS.VAArgTLS, CopySize, 8);
3515 }
3516
3517 // Instrument va_start.
3518 // Copy va_list shadow from the backup copy of the TLS contents.
3519 for (size_t i = 0, n = VAStartInstrumentationList.size(); i < n; i++) {
3520 CallInst *OrigInst = VAStartInstrumentationList[i];
3521 IRBuilder<> IRB(OrigInst->getNextNode());
3522 Value *VAListTag = OrigInst->getArgOperand(0);
3523 Value *RegSaveAreaPtrPtr =
3524 IRB.CreateIntToPtr(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy),
3525 Type::getInt64PtrTy(*MS.C));
3526 Value *RegSaveAreaPtr = IRB.CreateLoad(RegSaveAreaPtrPtr);
3527 Value *RegSaveAreaShadowPtr =
3528 MSV.getShadowPtr(RegSaveAreaPtr, IRB.getInt8Ty(), IRB);
3529 IRB.CreateMemCpy(RegSaveAreaShadowPtr, VAArgTLSCopy, CopySize, 8);
3530 }
3531 }
3532 };
3533
33763534 /// \brief A no-op implementation of VarArgHelper.
33773535 struct VarArgNoOpHelper : public VarArgHelper {
33783536 VarArgNoOpHelper(Function &F, MemorySanitizer &MS,
33993557 return new VarArgMIPS64Helper(Func, Msan, Visitor);
34003558 else if (TargetTriple.getArch() == llvm::Triple::aarch64)
34013559 return new VarArgAArch64Helper(Func, Msan, Visitor);
3560 else if (TargetTriple.getArch() == llvm::Triple::ppc64 ||
3561 TargetTriple.getArch() == llvm::Triple::ppc64le)
3562 return new VarArgPowerPC64Helper(Func, Msan, Visitor);
34023563 else
34033564 return new VarArgNoOpHelper(Func, Msan, Visitor);
34043565 }
0 ; RUN: opt < %s -msan -S | FileCheck %s
1
2 target datalayout = "E-m:e-i64:64-n32:64"
3 target triple = "powerpc64--linux"
4
5 define i32 @foo(i32 %guard, ...) {
6 %vl = alloca i8*, align 8
7 %1 = bitcast i8** %vl to i8*
8 call void @llvm.lifetime.start(i64 32, i8* %1)
9 call void @llvm.va_start(i8* %1)
10 call void @llvm.va_end(i8* %1)
11 call void @llvm.lifetime.end(i64 32, i8* %1)
12 ret i32 0
13 }
14
15 ; First, check allocation of the save area.
16
17 ; CHECK-LABEL: @foo
18 ; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls
19 ; CHECK: [[B:%.*]] = add i64 0, [[A]]
20 ; CHECK: [[C:%.*]] = alloca {{.*}} [[B]]
21
22 ; CHECK: [[STACK:%.*]] = bitcast {{.*}} @__msan_va_arg_tls to i8*
23 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[C]], i8* [[STACK]], i64 [[B]], i32 8, i1 false)
24
25 declare void @llvm.lifetime.start(i64, i8* nocapture) #1
26 declare void @llvm.va_start(i8*) #2
27 declare void @llvm.va_end(i8*) #2
28 declare void @llvm.lifetime.end(i64, i8* nocapture) #1
29
30 define i32 @bar() {
31 %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i64 2, double 3.000000e+00)
32 ret i32 %1
33 }
34
35 ; Save the incoming shadow value from the arguments in the __msan_va_arg_tls
36 ; array. The first argument is stored at position 4, since it's right
37 ; justified.
38 ; CHECK-LABEL: @bar
39 ; CHECK: store i32 0, i32* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 4) to i32*), align 8
40 ; CHECK: store i64 0, i64* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to i64*), align 8
41 ; CHECK: store i64 0, i64* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 16) to i64*), align 8
42 ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls
43
44 ; Check vector argument.
45 define i32 @bar2() {
46 %1 = call i32 (i32, ...) @foo(i32 0, <2 x i64> )
47 ret i32 %1
48 }
49
50 ; The vector is at offset 16 of parameter save area, but __msan_va_arg_tls
51 ; corresponds to offset 8+ of parameter save area - so the offset from
52 ; __msan_va_arg_tls is actually misaligned.
53 ; CHECK-LABEL: @bar2
54 ; CHECK: store <2 x i64> zeroinitializer, <2 x i64>* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to <2 x i64>*), align 8
55 ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls
56
57 ; Check QPX vector argument.
58 define i32 @bar3() "target-features"="+qpx" {
59 %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i32 2, <4 x double> )
60 ret i32 %1
61 }
62
63 ; That one is even stranger: the parameter save area starts at offset 48 from
64 ; (32-byte aligned) stack pointer, the vector parameter is at 96 bytes from
65 ; the stack pointer, so its offset from parameter save area is misaligned.
66 ; CHECK-LABEL: @bar3
67 ; CHECK: store i32 0, i32* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 4) to i32*), align 8
68 ; CHECK: store i32 0, i32* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 12) to i32*), align 8
69 ; CHECK: store <4 x i64> zeroinitializer, <4 x i64>* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 40) to <4 x i64>*), align 8
70 ; CHECK: store {{.*}} 72, {{.*}} @__msan_va_arg_overflow_size_tls
71
72 ; Check i64 array.
73 define i32 @bar4() {
74 %1 = call i32 (i32, ...) @foo(i32 0, [2 x i64] [i64 1, i64 2])
75 ret i32 %1
76 }
77
78 ; CHECK-LABEL: @bar4
79 ; CHECK: store [2 x i64] zeroinitializer, [2 x i64]* bitcast ([100 x i64]* @__msan_va_arg_tls to [2 x i64]*), align 8
80 ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls
81
82 ; Check i128 array.
83 define i32 @bar5() {
84 %1 = call i32 (i32, ...) @foo(i32 0, [2 x i128] [i128 1, i128 2])
85 ret i32 %1
86 }
87
88 ; CHECK-LABEL: @bar5
89 ; CHECK: store [2 x i128] zeroinitializer, [2 x i128]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to [2 x i128]*), align 8
90 ; CHECK: store {{.*}} 40, {{.*}} @__msan_va_arg_overflow_size_tls
91
92 ; Check 8-aligned byval.
93 define i32 @bar6([2 x i64]* %arg) {
94 %1 = call i32 (i32, ...) @foo(i32 0, [2 x i64]* byval align 8 %arg)
95 ret i32 %1
96 }
97
98 ; CHECK-LABEL: @bar6
99 ; CHECK: [[SHADOW:%[0-9]+]] = bitcast [2 x i64]* bitcast ([100 x i64]* @__msan_va_arg_tls to [2 x i64]*) to i8*
100 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[SHADOW]], i8* {{.*}}, i64 16, i32 8, i1 false)
101 ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls
102
103 ; Check 16-aligned byval.
104 define i32 @bar7([4 x i64]* %arg) {
105 %1 = call i32 (i32, ...) @foo(i32 0, [4 x i64]* byval align 16 %arg)
106 ret i32 %1
107 }
108
109 ; CHECK-LABEL: @bar7
110 ; CHECK: [[SHADOW:%[0-9]+]] = bitcast [4 x i64]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to [4 x i64]*)
111 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[SHADOW]], i8* {{.*}}, i64 32, i32 8, i1 false)
112 ; CHECK: store {{.*}} 40, {{.*}} @__msan_va_arg_overflow_size_tls
0 ; RUN: opt < %s -msan -S | FileCheck %s
1
2 target datalayout = "e-m:e-i64:64-n32:64"
3 target triple = "powerpc64le--linux"
4
5 define i32 @foo(i32 %guard, ...) {
6 %vl = alloca i8*, align 8
7 %1 = bitcast i8** %vl to i8*
8 call void @llvm.lifetime.start(i64 32, i8* %1)
9 call void @llvm.va_start(i8* %1)
10 call void @llvm.va_end(i8* %1)
11 call void @llvm.lifetime.end(i64 32, i8* %1)
12 ret i32 0
13 }
14
15 ; First, check allocation of the save area.
16
17 ; CHECK-LABEL: @foo
18 ; CHECK: [[A:%.*]] = load {{.*}} @__msan_va_arg_overflow_size_tls
19 ; CHECK: [[B:%.*]] = add i64 0, [[A]]
20 ; CHECK: [[C:%.*]] = alloca {{.*}} [[B]]
21
22 ; CHECK: [[STACK:%.*]] = bitcast {{.*}} @__msan_va_arg_tls to i8*
23 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[C]], i8* [[STACK]], i64 [[B]], i32 8, i1 false)
24
25 declare void @llvm.lifetime.start(i64, i8* nocapture) #1
26 declare void @llvm.va_start(i8*) #2
27 declare void @llvm.va_end(i8*) #2
28 declare void @llvm.lifetime.end(i64, i8* nocapture) #1
29
30 define i32 @bar() {
31 %1 = call i32 (i32, ...) @foo(i32 0, i32 1, i64 2, double 3.000000e+00)
32 ret i32 %1
33 }
34
35 ; Save the incoming shadow value from the arguments in the __msan_va_arg_tls
36 ; array.
37 ; CHECK-LABEL: @bar
38 ; CHECK: store i32 0, i32* bitcast ([100 x i64]* @__msan_va_arg_tls to i32*), align 8
39 ; CHECK: store i64 0, i64* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to i64*), align 8
40 ; CHECK: store i64 0, i64* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 16) to i64*), align 8
41 ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls
42
43 ; Check vector argument.
44 define i32 @bar2() {
45 %1 = call i32 (i32, ...) @foo(i32 0, <2 x i64> )
46 ret i32 %1
47 }
48
49 ; The vector is at offset 16 of parameter save area, but __msan_va_arg_tls
50 ; corresponds to offset 8+ of parameter save area - so the offset from
51 ; __msan_va_arg_tls is actually misaligned.
52 ; CHECK-LABEL: @bar2
53 ; CHECK: store <2 x i64> zeroinitializer, <2 x i64>* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to <2 x i64>*), align 8
54 ; CHECK: store {{.*}} 24, {{.*}} @__msan_va_arg_overflow_size_tls
55
56 ; Check i64 array.
57 define i32 @bar4() {
58 %1 = call i32 (i32, ...) @foo(i32 0, [2 x i64] [i64 1, i64 2])
59 ret i32 %1
60 }
61
62 ; CHECK-LABEL: @bar4
63 ; CHECK: store [2 x i64] zeroinitializer, [2 x i64]* bitcast ([100 x i64]* @__msan_va_arg_tls to [2 x i64]*), align 8
64 ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls
65
66 ; Check i128 array.
67 define i32 @bar5() {
68 %1 = call i32 (i32, ...) @foo(i32 0, [2 x i128] [i128 1, i128 2])
69 ret i32 %1
70 }
71
72 ; CHECK-LABEL: @bar5
73 ; CHECK: store [2 x i128] zeroinitializer, [2 x i128]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to [2 x i128]*), align 8
74 ; CHECK: store {{.*}} 40, {{.*}} @__msan_va_arg_overflow_size_tls
75
76 ; Check 8-aligned byval.
77 define i32 @bar6([2 x i64]* %arg) {
78 %1 = call i32 (i32, ...) @foo(i32 0, [2 x i64]* byval align 8 %arg)
79 ret i32 %1
80 }
81
82 ; CHECK-LABEL: @bar6
83 ; CHECK: [[SHADOW:%[0-9]+]] = bitcast [2 x i64]* bitcast ([100 x i64]* @__msan_va_arg_tls to [2 x i64]*) to i8*
84 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[SHADOW]], i8* {{.*}}, i64 16, i32 8, i1 false)
85 ; CHECK: store {{.*}} 16, {{.*}} @__msan_va_arg_overflow_size_tls
86
87 ; Check 16-aligned byval.
88 define i32 @bar7([4 x i64]* %arg) {
89 %1 = call i32 (i32, ...) @foo(i32 0, [4 x i64]* byval align 16 %arg)
90 ret i32 %1
91 }
92
93 ; CHECK-LABEL: @bar7
94 ; CHECK: [[SHADOW:%[0-9]+]] = bitcast [4 x i64]* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__msan_va_arg_tls to i64), i64 8) to [4 x i64]*)
95 ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[SHADOW]], i8* {{.*}}, i64 32, i32 8, i1 false)
96 ; CHECK: store {{.*}} 40, {{.*}} @__msan_va_arg_overflow_size_tls