[clang] [X86_64] Fix empty field error in vaarg of C++. (PR #101639)

Eli Friedman via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 8 12:33:27 PDT 2024


================
@@ -3124,26 +3124,40 @@ RValue X86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
     CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
 
     RegAddr = Tmp.withElementType(LTy);
-  } else if (neededInt) {
-    RegAddr = Address(CGF.Builder.CreateGEP(CGF.Int8Ty, RegSaveArea, gp_offset),
-                      LTy, CharUnits::fromQuantity(8));
-
+  } else if (neededInt || neededSSE == 1) {
     // Copy to a temporary if necessary to ensure the appropriate alignment.
     auto TInfo = getContext().getTypeInfoInChars(Ty);
     uint64_t TySize = TInfo.Width.getQuantity();
     CharUnits TyAlign = TInfo.Align;
 
+    llvm::Value *GpOrFpOffset = neededInt ? gp_offset : fp_offset;
+    uint64_t Alignment = neededInt ? 8 : 16;
+    if (auto Offset = AI.getDirectOffset()) {
+      Address Tmp = CGF.CreateMemTemp(Ty);
+      llvm::Type *TyHi = AI.getCoerceToType();
+      llvm::Value *Addr =
+          CGF.Builder.CreateGEP(CGF.Int8Ty, RegSaveArea, GpOrFpOffset);
+      llvm::Value *Src = CGF.Builder.CreateAlignedLoad(TyHi, Addr, TyAlign);
+      llvm::Value *PtrOffset = llvm::ConstantInt::get(CGF.Int32Ty, Offset);
+      Address Dst = Address(
+          CGF.Builder.CreateGEP(CGF.Int8Ty, Tmp.getBasePointer(), PtrOffset),
+          LTy, TyAlign);
+      CGF.Builder.CreateStore(Src, Dst);
+      RegAddr = Tmp.withElementType(LTy);
+    } else {
+      RegAddr =
+          Address(CGF.Builder.CreateGEP(CGF.Int8Ty, RegSaveArea, GpOrFpOffset),
+                  LTy, CharUnits::fromQuantity(Alignment));
+    }
+
     // Copy into a temporary if the type is more aligned than the
     // register save area.
-    if (TyAlign.getQuantity() > 8) {
+    if (neededInt && TyAlign.getQuantity() > 8) {
----------------
efriedma-quic wrote:

Can we refactor the code so it's clear we never create two temporaries for the same va_arg?  Use an else-if instead of a separate if.

It looks it's possible that we end up reading past the end of the register save area for something like:

```
struct {
  long long b;
  struct{} a;
};
```

Can you also fix that while you're here?  (Not sure that actually has any visible effect, but better to be on the safe side.)

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


More information about the cfe-commits mailing list