[clang] 1b0a71c - [PowerPC][AIX] Add support for varargs for complex types on AIX

Zarko Todorovski via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 16 06:38:09 PDT 2021


Author: Zarko Todorovski
Date: 2021-09-16T09:38:03-04:00
New Revision: 1b0a71c5fc052322a45a8cb9a9fcaa2c36105b89

URL: https://github.com/llvm/llvm-project/commit/1b0a71c5fc052322a45a8cb9a9fcaa2c36105b89
DIFF: https://github.com/llvm/llvm-project/commit/1b0a71c5fc052322a45a8cb9a9fcaa2c36105b89.diff

LOG: [PowerPC][AIX] Add support for varargs for complex types on AIX

Remove the previous error and add support for special handling of small
complex types as in PPC64 ELF ABI. As in, generate code to load from
varargs location and pack it in a temp variable, then return a pointer to
the struct.

Reviewed By: sfertile

Differential Revision: https://reviews.llvm.org/D106393

Added: 
    clang/test/CodeGen/aix32-complex-varargs.c

Modified: 
    clang/lib/CodeGen/TargetInfo.cpp
    clang/test/CodeGen/ppc64-varargs-complex.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 5d33403f1233..67d0c2b5c850 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -392,6 +392,36 @@ static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,
 
 }
 
+static Address complexTempStructure(CodeGenFunction &CGF, Address VAListAddr,
+                                    QualType Ty, CharUnits SlotSize,
+                                    CharUnits EltSize, const ComplexType *CTy) {
+  Address Addr =
+      emitVoidPtrDirectVAArg(CGF, VAListAddr, CGF.Int8Ty, SlotSize * 2,
+                             SlotSize, SlotSize, /*AllowHigher*/ true);
+
+  Address RealAddr = Addr;
+  Address ImagAddr = RealAddr;
+  if (CGF.CGM.getDataLayout().isBigEndian()) {
+    RealAddr =
+        CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize - EltSize);
+    ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(ImagAddr,
+                                                      2 * SlotSize - EltSize);
+  } else {
+    ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize);
+  }
+
+  llvm::Type *EltTy = CGF.ConvertTypeForMem(CTy->getElementType());
+  RealAddr = CGF.Builder.CreateElementBitCast(RealAddr, EltTy);
+  ImagAddr = CGF.Builder.CreateElementBitCast(ImagAddr, EltTy);
+  llvm::Value *Real = CGF.Builder.CreateLoad(RealAddr, ".vareal");
+  llvm::Value *Imag = CGF.Builder.CreateLoad(ImagAddr, ".vaimag");
+
+  Address Temp = CGF.CreateMemTemp(Ty, "vacplx");
+  CGF.EmitStoreOfComplex({Real, Imag}, CGF.MakeAddrLValue(Temp, Ty),
+                         /*init*/ true);
+  return Temp;
+}
+
 static Address emitMergePHI(CodeGenFunction &CGF,
                             Address Addr1, llvm::BasicBlock *Block1,
                             Address Addr2, llvm::BasicBlock *Block2,
@@ -4631,14 +4661,25 @@ CharUnits AIXABIInfo::getParamTypeAlignment(QualType Ty) const {
 
 Address AIXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
                               QualType Ty) const {
-  if (Ty->isAnyComplexType())
-    llvm::report_fatal_error("complex type is not supported on AIX yet");
 
   auto TypeInfo = getContext().getTypeInfoInChars(Ty);
   TypeInfo.Align = getParamTypeAlignment(Ty);
 
   CharUnits SlotSize = CharUnits::fromQuantity(PtrByteSize);
 
+  // If we have a complex type and the base type is smaller than the register
+  // size, the ABI calls for the real and imaginary parts to be right-adjusted
+  // in separate words in 32bit mode or doublewords in 64bit mode. However,
+  // Clang expects us to produce a pointer to a structure with the two parts
+  // packed tightly. So generate loads of the real and imaginary parts relative
+  // to the va_list pointer, and store them to a temporary structure. We do the
+  // same as the PPC64ABI here.
+  if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
+    CharUnits EltSize = TypeInfo.Width / 2;
+    if (EltSize < SlotSize)
+      return complexTempStructure(CGF, VAListAddr, Ty, SlotSize, EltSize, CTy);
+  }
+
   return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false, TypeInfo,
                           SlotSize, /*AllowHigher*/ true);
 }
@@ -5406,33 +5447,8 @@ Address PPC64_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
   // and store them to a temporary structure.
   if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
     CharUnits EltSize = TypeInfo.Width / 2;
-    if (EltSize < SlotSize) {
-      Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, CGF.Int8Ty,
-                                            SlotSize * 2, SlotSize,
-                                            SlotSize, /*AllowHigher*/ true);
-
-      Address RealAddr = Addr;
-      Address ImagAddr = RealAddr;
-      if (CGF.CGM.getDataLayout().isBigEndian()) {
-        RealAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr,
-                                                          SlotSize - EltSize);
-        ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(ImagAddr,
-                                                      2 * SlotSize - EltSize);
-      } else {
-        ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize);
-      }
-
-      llvm::Type *EltTy = CGF.ConvertTypeForMem(CTy->getElementType());
-      RealAddr = CGF.Builder.CreateElementBitCast(RealAddr, EltTy);
-      ImagAddr = CGF.Builder.CreateElementBitCast(ImagAddr, EltTy);
-      llvm::Value *Real = CGF.Builder.CreateLoad(RealAddr, ".vareal");
-      llvm::Value *Imag = CGF.Builder.CreateLoad(ImagAddr, ".vaimag");
-
-      Address Temp = CGF.CreateMemTemp(Ty, "vacplx");
-      CGF.EmitStoreOfComplex({Real, Imag}, CGF.MakeAddrLValue(Temp, Ty),
-                             /*init*/ true);
-      return Temp;
-    }
+    if (EltSize < SlotSize)
+      return complexTempStructure(CGF, VAListAddr, Ty, SlotSize, EltSize, CTy);
   }
 
   // Otherwise, just use the general rule.

diff  --git a/clang/test/CodeGen/aix32-complex-varargs.c b/clang/test/CodeGen/aix32-complex-varargs.c
new file mode 100644
index 000000000000..e843b401c601
--- /dev/null
+++ b/clang/test/CodeGen/aix32-complex-varargs.c
@@ -0,0 +1,66 @@
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -emit-llvm -o - %s | FileCheck %s
+
+#include <stdarg.h>
+
+void testva (int n, ...)
+{
+  va_list ap;
+
+  _Complex int i   = va_arg(ap, _Complex int);
+// CHECK:  %[[VAR40:[A-Za-z0-9.]+]] = load i8*, i8** %[[VAR100:[A-Za-z0-9.]+]]
+// CHECK-NEXT:  %[[VAR41:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR40]]
+// CHECK-NEXT:  store i8* %[[VAR41]], i8** %[[VAR100]], align 4
+// CHECK-NEXT:  %[[VAR4:[A-Za-z0-9.]+]] = bitcast i8* %[[VAR40]] to { i32, i32 }*
+// CHECK-NEXT:  %[[VAR6:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* %[[VAR4]], i32 0, i32 0
+// CHECK-NEXT:  %[[VAR7:[A-Za-z0-9.]+]] = load i32, i32* %[[VAR6]]
+// CHECK-NEXT:  %[[VAR8:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* %[[VAR4]], i32 0, i32 1
+// CHECK-NEXT:  %[[VAR9:[A-Za-z0-9.]+]] = load i32, i32* %[[VAR8]]
+// CHECK-NEXT:  %[[VAR10:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* %[[VARINT:[A-Za-z0-9.]+]], i32 0, i32 0
+// CHECK-NEXT:  %[[VAR11:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }, { i32, i32 }* %[[VARINT]], i32 0, i32 1
+// CHECK-NEXT:  store i32 %[[VAR7]], i32* %[[VAR10]]
+// CHECK-NEXT:  store i32 %[[VAR9]], i32* %[[VAR11]]
+
+  _Complex short s = va_arg(ap, _Complex short);
+// CHECK:  %[[VAR50:[A-Za-z0-9.]+]] = load i8*, i8** %[[VAR100:[A-Za-z0-9.]+]]
+// CHECK-NEXT:  %[[VAR51:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR50]]
+// CHECK-NEXT:  store i8* %[[VAR51]], i8** %[[VAR100]], align 4
+// CHECK-NEXT:  %[[VAR12:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR50]], i32 2
+// CHECK-NEXT:  %[[VAR13:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR50]], i32 6
+// CHECK-NEXT:  %[[VAR14:[A-Za-z0-9.]+]] = bitcast i8* %[[VAR12]] to i16*
+// CHECK-NEXT:  %[[VAR15:[A-Za-z0-9.]+]] = bitcast i8* %[[VAR13]] to i16*
+// CHECK-NEXT:  %[[VAR16:[A-Za-z0-9.]+]] = load i16, i16* %[[VAR14]], align 2
+// CHECK-NEXT:  %[[VAR17:[A-Za-z0-9.]+]] = load i16, i16* %[[VAR15]], align 2
+// CHECK-NEXT:  %[[VAR18:[A-Za-z0-9.]+]] = getelementptr inbounds { i16, i16 }, { i16, i16 }* %[[VAR19:[A-Za-z0-9.]+]], i32 0, i32 0
+// CHECK-NEXT:  %[[VAR20:[A-Za-z0-9.]+]] = getelementptr inbounds { i16, i16 }, { i16, i16 }* %[[VAR19]], i32 0, i32 1
+// CHECK-NEXT:  store i16 %[[VAR16]], i16* %[[VAR18]]
+// CHECK-NEXT:  store i16 %[[VAR17]], i16* %[[VAR20]]
+
+
+  _Complex char c  = va_arg(ap, _Complex char);
+// CHECK:  %[[VAR60:[A-Za-z0-9.]+]] = load i8*, i8** %[[VAR100:[A-Za-z0-9.]+]]
+// CHECK-NEXT:  %[[VAR61:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR60]]
+// CHECK-NEXT:  store i8* %[[VAR61]], i8** %[[VAR100]], align 4
+// CHECK-NEXT:  %[[VAR21:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR60]], i32 3
+// CHECK-NEXT:  %[[VAR22:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR60]], i32 7
+// CHECK-NEXT:  %[[VAR23:[A-Za-z0-9.]+]] = load i8, i8* %[[VAR21]]
+// CHECK-NEXT:  %[[VAR24:[A-Za-z0-9.]+]] = load i8, i8* %[[VAR22]]
+// CHECK-NEXT:  %[[VAR25:[A-Za-z0-9.]+]] = getelementptr inbounds { i8, i8 }, { i8, i8 }* %[[VAR26:[A-Za-z0-9.]+]], i32 0, i32 0
+// CHECK-NEXT:  %[[VAR27:[A-Za-z0-9.]+]] = getelementptr inbounds { i8, i8 }, { i8, i8 }* %[[VAR26]], i32 0, i32 1
+// CHECK-NEXT:  store i8 %[[VAR23]], i8* %[[VAR25]]
+// CHECK-NEXT:  store i8 %[[VAR24]], i8* %[[VAR27]]
+
+
+  _Complex float f = va_arg(ap, _Complex float);
+// CHECK:  %[[VAR70:[A-Za-z0-9.]+]] = getelementptr inbounds i8, i8* %[[VAR71:[A-Za-z0-9.]+]], i32 8
+// CHECK-NEXT:  store i8* %[[VAR70]], i8** %[[VAR100:[A-Za-z0-9.]+]]
+// CHECK-NEXT:  %[[VAR28:[A-Za-z0-9.]+]] = bitcast i8* %[[VAR71]] to { float, float }*
+// CHECK-NEXT:  %[[VAR29:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, { float, float }* %[[VAR28]], i32 0, i32 0
+// CHECK-NEXT:  %[[VAR30:[A-Za-z0-9.]+]] = load float, float* %[[VAR29]]
+// CHECK-NEXT:  %[[VAR31:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, { float, float }* %[[VAR28]], i32 0, i32 1
+// CHECK-NEXT:  %[[VAR32:[A-Za-z0-9.]+]] = load float, float* %[[VAR31]]
+// CHECK-NEXT:  %[[VAR33:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, { float, float }* %f, i32 0, i32 0
+// CHECK-NEXT:  %[[VAR34:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }, { float, float }* %f, i32 0, i32 1
+// CHECK-NEXT:  store float %[[VAR30]], float* %[[VAR33]]
+// CHECK-NEXT:  store float %[[VAR32]], float* %[[VAR34]]
+}

diff  --git a/clang/test/CodeGen/ppc64-varargs-complex.c b/clang/test/CodeGen/ppc64-varargs-complex.c
index 58206801ac24..5f5f26ca8d4f 100644
--- a/clang/test/CodeGen/ppc64-varargs-complex.c
+++ b/clang/test/CodeGen/ppc64-varargs-complex.c
@@ -1,5 +1,6 @@
 // REQUIRES: powerpc-registered-target
 // RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -emit-llvm -o - %s | FileCheck %s
 
 #include <stdarg.h>
 


        


More information about the cfe-commits mailing list