[clang] [clang][PowerPC] Add flag to enable compatibility with GNU for complex arguments (PR #77732)

Kishan Parmar via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 27 06:16:51 PDT 2024


================
@@ -396,12 +405,85 @@ CharUnits PPC32_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
   return CharUnits::fromQuantity(4);
 }
 
+ABIArgInfo PPC32_SVR4_ABIInfo::handleComplex(uint64_t &TypeSize) const {
+  llvm::Type *ElemTy;
+  unsigned RegsNeeded; // Registers Needed for Complex.
+
+  // Choice of using llvm::Type::getInt64Ty(getVMContext()) for complex
+  // single-precision floats is based on the ABI ATR-PASS-COMPLEX-IN-GPRS
+  // specification. According to the specification:
+  // - For complex single-precision floats: If the register (gr) is even, it's
+  // incremented by one, and the lower-addressed word of the argument is loaded
+  // into gr, while the higher-addressed word is loaded into gr + 1. Then, gr is
+  // incremented by 2.
+  // - For complex double-precision floats: The words of the argument are loaded
+  // in memory-address order into gr, gr + 1, gr + 2, and gr + 3, with gr being
+  // incremented by 4. Thus, to maintain even alignment and adhere to the ABI
+  // specification, llvm::Type::getInt64Ty(getVMContext()) is used when TypeSize
+  // is 64. Powerpc backend handles this alignment requirement. Specifically,
+  // you can refer to the CC_PPC32_SVR4_Custom_AlignArgRegs method from
+  // PPCCallingconvention.cpp. For more context, refer to the previous
+  // discussion: https://reviews.llvm.org/D146942 and the related LLVM pull
+  // request: #77732
+
+  if (TypeSize == 64) {
+    ElemTy = llvm::Type::getInt64Ty(getVMContext());
+    RegsNeeded = 1;
+  } else {
+    ElemTy = llvm::Type::getInt32Ty(getVMContext());
+    RegsNeeded = TypeSize >> 5;
+  }
+  return ABIArgInfo::getDirect(llvm::ArrayType::get(ElemTy, RegsNeeded));
+}
+
+ABIArgInfo PPC32_SVR4_ABIInfo::classifyArgumentType(QualType Ty,
+                                                    int &ArgGPRsLeft) const {
+  Ty = useFirstFieldIfTransparentUnion(Ty);
+
+  if (!(getCodeGenOpts().getComplexInRegABI() == CodeGenOptions::CMPLX_InGPR) ||
+      !ArgGPRsLeft)
+    return DefaultABIInfo::classifyArgumentType(Ty);
+
+  assert(ArgGPRsLeft >= 0 && "Arg GPR must be large or equal than zero");
+  ASTContext &Context = getContext();
+  uint64_t TypeSize = Context.getTypeSize(Ty);
+
+  if (Ty->isAnyComplexType()) {
+    // If gr is even set gr = gr + 1 for TypeSize=64.
+    if (TypeSize == 64 && ArgGPRsLeft % 2 == 1)
+      --ArgGPRsLeft;
+
+    if (TypeSize <= RegLen * ArgGPRsLeft) {
+      ArgGPRsLeft -= TypeSize / RegLen;
+      return handleComplex(TypeSize);
+    }
+  }
+
+  // Records with non-trivial destructors/copy-constructors should not be
+  // passed by value.
+  if (isAggregateTypeForABI(Ty))
+    --ArgGPRsLeft;
+  else if (!Ty->isFloatingType()) {
+    // For other primitive types.
+    if (TypeSize == 64) {
+      // If gr is even set gr = gr + 1 for TypeSize=64.
+      if (ArgGPRsLeft % 2 == 1)
+        --ArgGPRsLeft;
+      if (TypeSize <= ArgGPRsLeft * RegLen) {
+        ArgGPRsLeft -= TypeSize / RegLen;
+      }
+    } else
+      --ArgGPRsLeft;
----------------
Long5hot wrote:

I missed the part for soft-float, for soft-float we pass long-double(128) in GPRs, Below change works.

```
else if (!Ty->isFloatingType() || (Ty->isFloatingType() && IsSoftFloatABI)) { 
if (TypeSize == 64 && ArgGPRsLeft % 2 == 1)
     --ArgGPRsLeft; // If gr is even set gr = gr + 1 for TypeSize=64.
if (TypeSize <= ArgGPRsLeft * RegLen)
     ArgGPRsLeft -= TypeSize / RegLen;
   }
```

I will update the review as your comments. Do i need to add the tests for soft-floats as well??

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


More information about the cfe-commits mailing list