]> granicus.if.org Git - clang/commitdiff
Fix IRGen for passing transparent unions
authorReid Kleckner <reid@kleckner.net>
Sat, 15 Nov 2014 01:41:41 +0000 (01:41 +0000)
committerReid Kleckner <reid@kleckner.net>
Sat, 15 Nov 2014 01:41:41 +0000 (01:41 +0000)
We have had a test for this for a long time with a FIXME saying what we
should be doing. This just does it.

Fixes PR21573.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@222074 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/TargetInfo.cpp
test/CodeGen/transparent-union.c

index ec82c4124078bedb48d062dcba3c852557f56877..c46c3eb6edb63c0e02b51f482110dd98393ddc14 100644 (file)
@@ -65,6 +65,19 @@ static CGCXXABI::RecordArgABI getRecordArgABI(QualType T,
   return getRecordArgABI(RT, CXXABI);
 }
 
+/// Pass transparent unions as if they were the type of the first element. Sema
+/// should ensure that all elements of the union have the same "machine type".
+static QualType useFirstFieldIfTransparentUnion(QualType Ty) {
+  if (const RecordType *UT = Ty->getAsUnionType()) {
+    const RecordDecl *UD = UT->getDecl();
+    if (UD->hasAttr<TransparentUnionAttr>()) {
+      assert(!UD->field_empty() && "sema created an empty transparent union");
+      return UD->field_begin()->getType();
+    }
+  }
+  return Ty;
+}
+
 CGCXXABI &ABIInfo::getCXXABI() const {
   return CGT.getCXXABI();
 }
@@ -1006,6 +1019,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
                                                CCState &State) const {
   // FIXME: Set alignment on indirect arguments.
 
+  Ty = useFirstFieldIfTransparentUnion(Ty);
+
   // Check with the C++ ABI first.
   const RecordType *RT = Ty->getAs<RecordType>();
   if (RT) {
@@ -2543,6 +2558,8 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(
   bool isNamedArg)
   const
 {
+  Ty = useFirstFieldIfTransparentUnion(Ty);
+
   X86_64ABIInfo::Class Lo, Hi;
   classify(Ty, 0, Lo, Hi, isNamedArg);
 
@@ -3520,6 +3537,8 @@ bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateSmallEnough(
 
 ABIArgInfo
 PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
+  Ty = useFirstFieldIfTransparentUnion(Ty);
+
   if (Ty->isAnyComplexType())
     return ABIArgInfo::getDirect();
 
@@ -3911,6 +3930,8 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty,
                                                 unsigned &AllocatedGPR,
                                                 bool &IsSmallAggr,
                                                 bool IsNamedArg) const {
+  Ty = useFirstFieldIfTransparentUnion(Ty);
+
   // Handle illegal vector types here.
   if (isIllegalVectorType(Ty)) {
     uint64_t Size = getContext().getTypeSize(Ty);
@@ -4692,6 +4713,8 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
   //   to four Elements.
   bool IsEffectivelyAAPCS_VFP = getABIKind() == AAPCS_VFP && !isVariadic;
 
+  Ty = useFirstFieldIfTransparentUnion(Ty);
+
   // Handle illegal vector types here.
   if (isIllegalVectorType(Ty)) {
     uint64_t Size = getContext().getTypeSize(Ty);
index 21040e4da05b34a713b49d74d0c2f90e2c65c39c..2f00c2d21a05f96c6f12f7692d937664d32aeaf2 100644 (file)
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -Werror -triple i386-unknown-unknown -emit-llvm -o %t %s
-// RUN: FileCheck < %t %s
-//
-// FIXME: Note that we don't currently get the ABI right here. f0() should be
-// f0(i8*).
+// RUN: %clang_cc1 -Werror -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Werror -triple i386-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Werror -triple armv7-linux -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM
+// RUN: %clang_cc1 -Werror -triple powerpc64le-linux -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Werror -triple aarch64-linux -emit-llvm -o - %s | FileCheck %s
 
 typedef union {
   void *f0;
@@ -10,10 +10,15 @@ typedef union {
 
 void f0(transp_t0 obj);
 
-// CHECK-LABEL: define void @f1_0(i32* %a0) 
-// CHECK:  call void @f0(%union.transp_t0* byval align 4 %{{.*}})
+// CHECK-LABEL: define void @f1_0(i32* %a0)
+// CHECK:  call void @f0(i8* %{{.*}})
 // CHECK:  call void %{{.*}}(i8* %{{[a-z0-9]*}})
 // CHECK: }
+
+// ARM-LABEL: define arm_aapcscc void @f1_0(i32* %a0)
+// ARM:  call arm_aapcscc void @f0(i8* %{{.*}})
+// ARM:  call arm_aapcscc void %{{.*}}(i8* %{{[a-z0-9]*}})
+// ARM: }
 void f1_0(int *a0) {
   void (*f0p)(void *) = f0;
   f0(a0);