[clang] [llvm] [PowerPC] Fix codegen for transparent_union function params (PR #101738)

Lei Huang via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 2 12:12:19 PDT 2024


https://github.com/lei137 created https://github.com/llvm/llvm-project/pull/101738

Update codegen for func param with transparent_union attr to be that of the first union member.

>From f25e4ab65ed16a1e1a3bde91efe24bd0d52e0e74 Mon Sep 17 00:00:00 2001
From: Lei Huang <lei at ca.ibm.com>
Date: Fri, 2 Aug 2024 13:58:37 -0400
Subject: [PATCH] [PowerPC] Fix codegen for transparent_union function params

Update codegen for func param with transparent_union attr to be that
of the first union member.
---
 clang/lib/CodeGen/ABIInfoImpl.cpp             |  7 ++
 clang/lib/CodeGen/ABIInfoImpl.h               |  4 ++
 clang/lib/CodeGen/Targets/PPC.cpp             | 26 +++++--
 .../test/CodeGen/PowerPC/transparent_union.c  | 54 +++++++++++++++
 .../test/CodeGen/PowerPC/transparent_union.ll | 67 +++++++++++++++++++
 5 files changed, 152 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/CodeGen/PowerPC/transparent_union.c
 create mode 100644 llvm/test/CodeGen/PowerPC/transparent_union.ll

diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp
index 35e8f79ba1bac..d73b7e882fe65 100644
--- a/clang/lib/CodeGen/ABIInfoImpl.cpp
+++ b/clang/lib/CodeGen/ABIInfoImpl.cpp
@@ -143,13 +143,20 @@ bool CodeGen::classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI,
 }
 
 QualType CodeGen::useFirstFieldIfTransparentUnion(QualType Ty) {
+  bool IsTransparentUnion;
+  return useFirstFieldIfTransparentUnion(Ty, IsTransparentUnion);
+}
+
+QualType CodeGen::useFirstFieldIfTransparentUnion(QualType Ty, bool &TU) {
   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");
+      TU = true;
       return UD->field_begin()->getType();
     }
   }
+  TU = false;
   return Ty;
 }
 
diff --git a/clang/lib/CodeGen/ABIInfoImpl.h b/clang/lib/CodeGen/ABIInfoImpl.h
index 2a3ef6b8a6c96..95e48ee49d5a4 100644
--- a/clang/lib/CodeGen/ABIInfoImpl.h
+++ b/clang/lib/CodeGen/ABIInfoImpl.h
@@ -65,6 +65,10 @@ CGCXXABI::RecordArgABI getRecordArgABI(QualType T, CGCXXABI &CXXABI);
 bool classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI,
                         const ABIInfo &Info);
 
+// For transparent union types, return the type of the first element.
+// Set reference TU to true if Ty given was a transparent union.
+QualType useFirstFieldIfTransparentUnion(QualType Ty, bool &TU);
+
 /// 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".
 QualType useFirstFieldIfTransparentUnion(QualType Ty);
diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp
index e4155810963eb..d2a3abbe24861 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -196,7 +196,8 @@ ABIArgInfo AIXABIInfo::classifyReturnType(QualType RetTy) const {
 }
 
 ABIArgInfo AIXABIInfo::classifyArgumentType(QualType Ty) const {
-  Ty = useFirstFieldIfTransparentUnion(Ty);
+  bool IsTransparentUnion;
+  Ty = useFirstFieldIfTransparentUnion(Ty, IsTransparentUnion);
 
   if (Ty->isAnyComplexType())
     return ABIArgInfo::getDirect();
@@ -217,8 +218,14 @@ ABIArgInfo AIXABIInfo::classifyArgumentType(QualType Ty) const {
                                    /*Realign*/ TyAlign > CCAlign);
   }
 
-  return (isPromotableTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)
-                                     : ABIArgInfo::getDirect());
+  if (isPromotableTypeForABI(Ty))
+    return (IsTransparentUnion ?
+        ABIArgInfo::getExtend(Ty,
+            llvm::IntegerType::get(getVMContext(),
+                                   getContext().getTypeSize(Ty)))
+        : ABIArgInfo::getExtend(Ty));
+
+  return (ABIArgInfo::getDirect());
 }
 
 CharUnits AIXABIInfo::getParamTypeAlignment(QualType Ty) const {
@@ -822,7 +829,8 @@ bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateSmallEnough(
 
 ABIArgInfo
 PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
-  Ty = useFirstFieldIfTransparentUnion(Ty);
+  bool IsTransparentUnion;
+  Ty = useFirstFieldIfTransparentUnion(Ty, IsTransparentUnion);
 
   if (Ty->isAnyComplexType())
     return ABIArgInfo::getDirect();
@@ -891,8 +899,14 @@ PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
                                    /*Realign=*/TyAlign > ABIAlign);
   }
 
-  return (isPromotableTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)
-                                     : ABIArgInfo::getDirect());
+  if (isPromotableTypeForABI(Ty))
+    return (IsTransparentUnion ?
+        ABIArgInfo::getExtend(Ty,
+            llvm::IntegerType::get(getVMContext(),
+                                   getContext().getTypeSize(Ty)))
+        : ABIArgInfo::getExtend(Ty));
+
+  return ABIArgInfo::getDirect();
 }
 
 ABIArgInfo
diff --git a/clang/test/CodeGen/PowerPC/transparent_union.c b/clang/test/CodeGen/PowerPC/transparent_union.c
new file mode 100644
index 0000000000000..6c61ce553ba7d
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/transparent_union.c
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -O2 -target-cpu pwr7 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -O2 -target-cpu pwr7 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64
+// RUN: %clang_cc1 -triple powerpc64-unknown-aix -O2 -target-cpu pwr7 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64
+// RUN: %clang_cc1 -triple powerpc-unknown-aix -O2 -target-cpu pwr7 \
+// RUN:   -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-AIX-32
+
+typedef union tu_c {
+	char a;
+	char b;
+} tu_c_t __attribute__((transparent_union));
+
+typedef union tu_s {
+	short a;
+} tu_s_t __attribute__((transparent_union));
+
+typedef union tu_us {
+	unsigned short a;
+} tu_us_t __attribute__((transparent_union));
+
+typedef union tu_l {
+	long a;
+} tu_l_t __attribute__((transparent_union));
+
+// CHECK-LABEL: define{{.*}} void @ftest0(
+// CHECK-SAME: i8 noundef signext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    ret void
+void ftest0(tu_c_t uc) { }
+
+// CHECK-LABEL: define{{.*}} void @ftest1(
+// CHECK-SAME: i16 noundef signext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    ret void
+void ftest1(tu_s_t uc) { }
+
+// CHECK-LABEL: define{{.*}} void @ftest2(
+// CHECK-SAME: i16 noundef zeroext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    ret void
+void ftest2(tu_us_t uc) { }
+
+// CHECK-64-LABEL: define{{.*}} void @ftest3(
+// CHECK-64-SAME: i64 [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-64-NEXT:  [[ENTRY:.*:]]
+// CHECK-64-NEXT:    ret void
+//
+// CHECK-AIX-32-LABEL: define void @ftest3(
+// CHECK-AIX-32-SAME: i32 [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-AIX-32-NEXT:  [[ENTRY:.*:]]
+// CHECK-AIX-32-NEXT:    ret void
+void ftest3(tu_l_t uc) { }
diff --git a/llvm/test/CodeGen/PowerPC/transparent_union.ll b/llvm/test/CodeGen/PowerPC/transparent_union.ll
new file mode 100644
index 0000000000000..d04a010737421
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/transparent_union.ll
@@ -0,0 +1,67 @@
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux -mcpu=pwr7 \
+; RUN:   -O2 -o - < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-64
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux -mcpu=pwr7 \
+; RUN:   -O2 -o - < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-64
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix -mcpu=pwr7 \
+; RUN:   -O2 -o - < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-64
+; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-aix -mcpu=pwr7 \
+; RUN:   -O2 -o - < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-AIX-32
+
+%union.tu_c = type { i8 }
+%union.tu_s = type { i16 }
+%union.tu_us = type { i16 }
+%union.tu_l = type { i64 }
+
+define void @ftest0(i8 noundef zeroext %uc.coerce) {
+; CHECK-LABEL: ftest0:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stb 3, -1(1)
+; CHECK-NEXT:    blr
+entry:
+  %uc = alloca %union.tu_c, align 1
+  %coerce.dive = getelementptr inbounds %union.tu_c, ptr %uc, i32 0, i32 0
+  store i8 %uc.coerce, ptr %coerce.dive, align 1
+  ret void
+}
+
+define void @ftest1(i16 noundef signext %uc.coerce) {
+; CHECK-LABEL: ftest1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    sth 3, -2(1)
+; CHECK-NEXT:    blr
+entry:
+  %uc = alloca %union.tu_s, align 2
+  %coerce.dive = getelementptr inbounds %union.tu_s, ptr %uc, i32 0, i32 0
+  store i16 %uc.coerce, ptr %coerce.dive, align 2
+  ret void
+}
+
+define void @ftest2(i16 noundef zeroext %uc.coerce) {
+; CHECK-LABEL: ftest2:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    sth 3, -2(1)
+; CHECK-NEXT:    blr
+entry:
+  %uc = alloca %union.tu_us, align 2
+  %coerce.dive = getelementptr inbounds %union.tu_us, ptr %uc, i32 0, i32 0
+  store i16 %uc.coerce, ptr %coerce.dive, align 2
+  ret void
+}
+
+define void @ftest3(i64 %uc.coerce) {
+; CHECK-64-LABEL: ftest3:
+; CHECK-64:       # %bb.0: # %entry
+; CHECK-64-NEXT:    std 3, -8(1)
+; CHECK-64-NEXT:    blr
+;
+; CHECK-AIX-32-LABEL: ftest3:
+; CHECK-AIX-32:       # %bb.0: # %entry
+; CHECK-AIX-32-NEXT:    stw 4, -4(1)
+; CHECK-AIX-32-NEXT:    stw 3, -8(1)
+; CHECK-AIX-32-NEXT:    blr
+entry:
+  %uc = alloca %union.tu_l, align 8
+  %coerce.dive = getelementptr inbounds %union.tu_l, ptr %uc, i32 0, i32 0
+  store i64 %uc.coerce, ptr %coerce.dive, align 8
+  ret void
+}



More information about the cfe-commits mailing list