[llvm] [MSan] Separated PPC32 va_arg helper from PPC64 (PR #131827)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 9 07:00:18 PDT 2025


================
@@ -6601,45 +6576,51 @@ struct VarArgPowerPC32Helper : public VarArgHelperBase {
                              kShadowTLSAlignment, ArgSize);
           }
         }
-        VAArgOffset += alignTo(ArgSize, Align(8));
+        VAArgOffset += alignTo(ArgSize, Align(IntptrSize));
       } else {
         Value *Base;
-        uint64_t ArgSize = DL.getTypeAllocSize(A->getType());
-        Align ArgAlign = Align(8);
-        if (A->getType()->isArrayTy()) {
-          // Arrays are aligned to element size, except for long double
-          // arrays, which are aligned to 8 bytes.
-          Type *ElementTy = A->getType()->getArrayElementType();
-          if (!ElementTy->isPPC_FP128Ty())
-            ArgAlign = Align(DL.getTypeAllocSize(ElementTy));
-        } else if (A->getType()->isVectorTy()) {
-          // Vectors are naturally aligned.
-          ArgAlign = Align(ArgSize);
-        }
-        if (ArgAlign < 8)
-          ArgAlign = Align(8);
-        VAArgOffset = alignTo(VAArgOffset, ArgAlign);
-        if (DL.isBigEndian()) {
-          // Adjusting the shadow for argument with size < 8 to match the
-          // placement of bits in big endian system
-          if (ArgSize < 8)
-            VAArgOffset += (8 - ArgSize);
-        }
-        if (!IsFixed) {
-          Base =
-              getShadowPtrForVAArgument(IRB, VAArgOffset - VAArgBase, ArgSize);
-          if (Base)
-            IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment);
+        Type *ArgTy = A->getType();
+
+        // On PPC 32 floating point variable arguments are stored in separate
+        // area: fp_save_area = reg_save_area + 4*8. We do not copy shaodow for
+        // them as they will be found when checking call arguments.
+        if (!ArgTy->isFloatingPointTy()) {
+          uint64_t ArgSize = DL.getTypeAllocSize(ArgTy);
+          Align ArgAlign = Align(IntptrSize);
+          if (ArgTy->isArrayTy()) {
+            // Arrays are aligned to element size, except for long double
+            // arrays, which are aligned to 8 bytes.
+            Type *ElementTy = ArgTy->getArrayElementType();
+            if (!ElementTy->isPPC_FP128Ty())
+              ArgAlign = Align(DL.getTypeAllocSize(ElementTy));
+          } else if (ArgTy->isVectorTy()) {
+            // Vectors are naturally aligned.
+            ArgAlign = Align(ArgSize);
+          }
+          if (ArgAlign < IntptrSize)
+            ArgAlign = Align(IntptrSize);
+          VAArgOffset = alignTo(VAArgOffset, ArgAlign);
+          if (DL.isBigEndian()) {
+            // Adjusting the shadow for argument with size < IntptrSize to match
+            // the placement of bits in big endian system
+            if (ArgSize < IntptrSize)
+              VAArgOffset += (IntptrSize - ArgSize);
+          }
+          if (!IsFixed) {
+            Base = getShadowPtrForVAArgument(IRB, VAArgOffset - VAArgBase,
+                                             ArgSize);
+            if (Base)
+              IRB.CreateAlignedStore(MSV.getShadow(A), Base,
+                                     kShadowTLSAlignment);
+          }
+          VAArgOffset += ArgSize;
+          VAArgOffset = alignTo(VAArgOffset, Align(IntptrSize));
         }
-        VAArgOffset += ArgSize;
-        VAArgOffset = alignTo(VAArgOffset, Align(8));
       }
-      if (IsFixed)
-        VAArgBase = VAArgOffset;
     }
 
     Constant *TotalVAArgSize =
-        ConstantInt::get(MS.IntptrTy, VAArgOffset - VAArgBase);
+        ConstantInt::get(IRB.getInt32Ty(), VAArgOffset - VAArgBase);
----------------
k-kashapov wrote:

I've tried to change the type to `MS.IntptrTy` and added this line:
```cpp
llvm::outs() << "IntPtrTy = " << *MS.IntptrTy << "\n";
```

Here's the output from opt:
```bash
$ bin/opt < ../llvm/test/Instrumentation/MemorySanitizer/PowerPC32/vararg-ppcle.ll -S -passes=msan -msan-origin-base=0x40000000 -msan-and-mask=0x80000000 2>&1

IntPtrTy = i64
; ModuleID = '<stdin>'
source_filename = "<stdin>"
target datalayout = "e-m:e-i32:32-n32"
target triple = "powerpcle--linux"
...
define i32 @foo(i32 %guard, ...) {
  %1 = load i64, ptr @__msan_va_arg_overflow_size_tls, align 4
  %2 = alloca i8, i64 %1, align 8
  call void @llvm.memset.p0.i64(ptr align 8 %2, i8 0, i64 %1, i1 false)
  %3 = call i64 @llvm.umin.i64(i64 %1, i64 800)
  call void @llvm.memcpy.p0.p0.i64(ptr align 8 %2, ptr align 8 @__msan_va_arg_tls, i64 %3, i1 false)
...
```

As you can see, opt uses i64 as `MS.IntptrTy`. However when compiling with clang, it suddenly becomes i32:
```bash
$ clang test.c -target powerpc-gnu-linux-eabi -c -fsanitize=memory -mllvm -msan-shadow-base=0x40000000
IntPtrTy = i32
```
I don't know what may cause this, so i've decided to keep `getInt32Ty()` for now.

https://github.com/llvm/llvm-project/pull/131827


More information about the llvm-commits mailing list