[clang] 0eff46f - [SystemZ] Fix handling of vectors and their exposure of the vector ABI.
Jonas Paulsson via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 27 11:24:21 PST 2023
Author: Jonas Paulsson
Date: 2023-01-27T20:24:09+01:00
New Revision: 0eff46f87f16772f93bdc584865e945162aff170
URL: https://github.com/llvm/llvm-project/commit/0eff46f87f16772f93bdc584865e945162aff170
DIFF: https://github.com/llvm/llvm-project/commit/0eff46f87f16772f93bdc584865e945162aff170.diff
LOG: [SystemZ] Fix handling of vectors and their exposure of the vector ABI.
- Global vector variables expose the vector ABI through their alignments only
if they are >=16 bytes in size.
- Vectors passed between functions expose the vector ABI only if they are
<=16 bytes in size.
LLVM test suite builds with gcc/clang now give the same gnu attributes emitted.
Reviewed By: Ulrich Weigand
Differential Revision: https://reviews.llvm.org/D141409
Added:
clang/test/CodeGen/SystemZ/vec-abi-gnuattr-03b.c
clang/test/CodeGen/SystemZ/vec-abi-gnuattr-08b.c
clang/test/CodeGen/SystemZ/vec-abi-gnuattr-09b.c
clang/test/CodeGen/SystemZ/vec-abi-gnuattr-17b.c
Modified:
clang/lib/CodeGen/TargetInfo.cpp
clang/test/CodeGen/SystemZ/vec-abi-gnuattr-24.c
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index be1dbe8480c6e..a9119abad81d8 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -7418,18 +7418,28 @@ class SystemZABIInfo : public ABIInfo {
};
class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
+ ASTContext &Ctx;
+
+ const SystemZABIInfo &getABIInfo() const {
+ return static_cast<const SystemZABIInfo&>(TargetCodeGenInfo::getABIInfo());
+ }
+
// These are used for speeding up the search for a visible vector ABI.
mutable bool HasVisibleVecABIFlag = false;
mutable std::set<const Type *> SeenTypes;
- // Returns true (the first time) if Ty is or found to make use of a vector
- // type (e.g. as a function argument).
- bool isVectorTypeBased(const Type *Ty) const;
+ // Returns true (the first time) if Ty is, or is found to include, a vector
+ // type that exposes the vector ABI. This is any vector >=16 bytes which
+ // with vector support are aligned to only 8 bytes. When IsParam is true,
+ // the type belongs to a value as passed between functions. If it is a
+ // vector <=16 bytes it will be passed in a vector register (if supported).
+ bool isVectorTypeBased(const Type *Ty, bool IsParam) const;
public:
SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI)
: TargetCodeGenInfo(
- std::make_unique<SystemZABIInfo>(CGT, HasVector, SoftFloatABI)) {
+ std::make_unique<SystemZABIInfo>(CGT, HasVector, SoftFloatABI)),
+ Ctx(CGT.getContext()) {
SwiftInfo =
std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
}
@@ -7439,9 +7449,9 @@ class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
// indicating a visible vector ABI is added. Eventually this will result in
// a GNU attribute indicating the vector ABI of the module. Ty is the type
// of a variable or function parameter that is globally visible.
- void handleExternallyVisibleObjABI(const Type *Ty,
- CodeGen::CodeGenModule &M) const {
- if (!HasVisibleVecABIFlag && isVectorTypeBased(Ty)) {
+ void handleExternallyVisibleObjABI(const Type *Ty, CodeGen::CodeGenModule &M,
+ bool IsParam) const {
+ if (!HasVisibleVecABIFlag && isVectorTypeBased(Ty, IsParam)) {
M.getModule().addModuleFlag(llvm::Module::Warning,
"s390x-visible-vector-ABI", 1);
HasVisibleVecABIFlag = true;
@@ -7457,11 +7467,13 @@ class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
// variable or function.
if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (VD->isExternallyVisible())
- handleExternallyVisibleObjABI(VD->getType().getTypePtr(), M);
+ handleExternallyVisibleObjABI(VD->getType().getTypePtr(), M,
+ /*IsParam*/false);
}
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isExternallyVisible())
- handleExternallyVisibleObjABI(FD->getType().getTypePtr(), M);
+ handleExternallyVisibleObjABI(FD->getType().getTypePtr(), M,
+ /*IsParam*/false);
}
}
@@ -7571,17 +7583,18 @@ QualType SystemZABIInfo::GetSingleElementType(QualType Ty) const {
// If this is a C++ record, check the bases first.
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- for (const auto &I : CXXRD->bases()) {
- QualType Base = I.getType();
+ if (CXXRD->hasDefinition())
+ for (const auto &I : CXXRD->bases()) {
+ QualType Base = I.getType();
- // Empty bases don't affect things either way.
- if (isEmptyRecord(getContext(), Base, true))
- continue;
+ // Empty bases don't affect things either way.
+ if (isEmptyRecord(getContext(), Base, true))
+ continue;
- if (!Found.isNull())
- return Ty;
- Found = GetSingleElementType(Base);
- }
+ if (!Found.isNull())
+ return Ty;
+ Found = GetSingleElementType(Base);
+ }
// Check the fields.
for (const auto *FD : RD->fields()) {
@@ -7635,7 +7648,8 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
bool IsVector = false;
CharUnits UnpaddedSize;
CharUnits DirectAlign;
- SZCGI.handleExternallyVisibleObjABI(Ty.getTypePtr(), CGT.getCGM());
+ SZCGI.handleExternallyVisibleObjABI(Ty.getTypePtr(), CGT.getCGM(),
+ /*IsParam*/true);
if (IsIndirect) {
DirectTy = llvm::PointerType::getUnqual(DirectTy);
UnpaddedSize = DirectAlign = CharUnits::fromQuantity(8);
@@ -7843,35 +7857,57 @@ void SystemZABIInfo::computeInfo(CGFunctionInfo &FI) const {
// Check if a vararg vector argument is passed, in which case the
// vector ABI becomes visible as the va_list could be passed on to
// other functions.
- SZCGI.handleExternallyVisibleObjABI(I.type.getTypePtr(), CGT.getCGM());
+ SZCGI.handleExternallyVisibleObjABI(I.type.getTypePtr(), CGT.getCGM(),
+ /*IsParam*/true);
}
}
-bool SystemZTargetCodeGenInfo::isVectorTypeBased(const Type *Ty) const {
- while (Ty->isPointerType() || Ty->isArrayType())
- Ty = Ty->getPointeeOrArrayElementType();
+bool SystemZTargetCodeGenInfo::isVectorTypeBased(const Type *Ty,
+ bool IsParam) const {
if (!SeenTypes.insert(Ty).second)
return false;
- if (Ty->isVectorType())
- return true;
+
+ if (IsParam) {
+ // A narrow (<16 bytes) vector will as a parameter also expose the ABI as
+ // it will be passed in a vector register. A wide (>16 bytes) vector will
+ // be passed via "hidden" pointer where any extra alignment is not
+ // required (per GCC).
+ const Type *SingleEltTy =
+ getABIInfo().GetSingleElementType(QualType(Ty, 0)).getTypePtr();
+ bool SingleVecEltStruct = SingleEltTy != Ty && SingleEltTy->isVectorType() &&
+ Ctx.getTypeSize(SingleEltTy) == Ctx.getTypeSize(Ty);
+ if (Ty->isVectorType() || SingleVecEltStruct)
+ return Ctx.getTypeSize(Ty) / 8 <= 16;
+ }
+
+ // Assume pointers are dereferenced.
+ while (Ty->isPointerType() || Ty->isArrayType())
+ Ty = Ty->getPointeeOrArrayElementType();
+
+ // Vectors >= 16 bytes expose the ABI through alignment requirements.
+ if (Ty->isVectorType() && Ctx.getTypeSize(Ty) / 8 >= 16)
+ return true;
+
if (const auto *RecordTy = Ty->getAs<RecordType>()) {
const RecordDecl *RD = RecordTy->getDecl();
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
if (CXXRD->hasDefinition())
for (const auto &I : CXXRD->bases())
- if (isVectorTypeBased(I.getType().getTypePtr()))
+ if (isVectorTypeBased(I.getType().getTypePtr(), /*IsParam*/false))
return true;
for (const auto *FD : RD->fields())
- if (isVectorTypeBased(FD->getType().getTypePtr()))
+ if (isVectorTypeBased(FD->getType().getTypePtr(), /*IsParam*/false))
return true;
}
+
if (const auto *FT = Ty->getAs<FunctionType>())
- if (isVectorTypeBased(FT->getReturnType().getTypePtr()))
+ if (isVectorTypeBased(FT->getReturnType().getTypePtr(), /*IsParam*/true))
return true;
if (const FunctionProtoType *Proto = Ty->getAs<FunctionProtoType>())
for (auto ParamType : Proto->getParamTypes())
- if (isVectorTypeBased(ParamType.getTypePtr()))
+ if (isVectorTypeBased(ParamType.getTypePtr(), /*IsParam*/true))
return true;
+
return false;
}
diff --git a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-03b.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-03b.c
new file mode 100644
index 0000000000000..6cf6c50be259f
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-03b.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm -fzvector -o - %s 2>&1 \
+// RUN: | FileCheck %s
+//
+// Test that the "s390x-visible-vector-ABI" module flag is emitted.
+
+// Call to external function with with narrow vector argument.
+
+typedef __attribute__((vector_size(8))) int v2i32;
+
+void bar(v2i32 arg);
+
+void foo() {
+ v2i32 Var = {0, 0};
+ bar(Var);
+}
+
+//CHECK: !llvm.module.flags = !{!0, !1}
+//CHECK: !0 = !{i32 2, !"s390x-visible-vector-ABI", i32 1}
+
diff --git a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-08b.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-08b.c
new file mode 100644
index 0000000000000..7f99198b687ac
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-08b.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm -fzvector -o - %s 2>&1 \
+// RUN: | FileCheck %s
+//
+// Test the emission of the "s390x-visible-vector-ABI" module flag.
+
+// Passing a single element struct containing a narrow (8 byte) vector element.
+
+typedef __attribute__((vector_size(8))) int v2i32;
+
+struct S {
+ v2i32 B;
+};
+
+void bar(struct S Arg);
+
+void foo() {
+ struct S Var = {{0, 0}};
+ bar(Var);
+}
+
+//CHECK: !llvm.module.flags = !{!0, !1}
+//CHECK: !0 = !{i32 2, !"s390x-visible-vector-ABI", i32 1}
diff --git a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-09b.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-09b.c
new file mode 100644
index 0000000000000..b4de233550079
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-09b.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm -fzvector -o - %s 2>&1 \
+// RUN: | FileCheck %s
+//
+// Test the emission of the "s390x-visible-vector-ABI" module flag.
+
+// Call to vararg function with a narrow (8 bytes) vector argument.
+
+typedef __attribute__((vector_size(8))) int v2i32;
+
+void bar(int N, ...);
+
+void foo() {
+ v2i32 Var = {0, 0};
+ bar(0, Var);
+}
+
+//CHECK: !llvm.module.flags = !{!0, !1}
+//CHECK: !0 = !{i32 2, !"s390x-visible-vector-ABI", i32 1}
diff --git a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-17b.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-17b.c
new file mode 100644
index 0000000000000..d75e3ec6edcc1
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-17b.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm -fzvector -o - %s 2>&1 \
+// RUN: | FileCheck %s
+//
+// Test that the "s390x-visible-vector-ABI" module flag is emitted.
+
+// Globally visible function pointer with narrow vector argument.
+
+typedef __attribute__((vector_size(8))) int v2i32;
+
+void (*bar)(v2i32 Arg);
+
+//CHECK: !llvm.module.flags = !{!0, !1}
+//CHECK: !0 = !{i32 2, !"s390x-visible-vector-ABI", i32 1}
diff --git a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-24.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-24.c
index a18fe924dc2d9..54d7dc915cec2 100644
--- a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-24.c
+++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-24.c
@@ -34,4 +34,20 @@ int fun1() {
return foo(V)[0] + GlobVal + GlobExtVar;
}
+// Globally visible vector variable less than 16 bytes in size.
+typedef __attribute__((vector_size(8))) int v2i32;
+v2i32 NarrowVecVar;
+
+// Global function taking narrow vector array and pointer.
+void bar(v2i32 VArr[4], v2i32 *Dst) { *Dst = VArr[3]; }
+
+// Wide vector parameters via "hidden" pointers.
+typedef __attribute__((vector_size(32))) int v8i32;
+v8i32 bar2(v8i32 Arg) { return Arg; }
+
+// Same but with a single element struct.
+struct SingleElStruct { v8i32 B; };
+struct SingleElStruct bar3(struct SingleElStruct Arg) { return Arg; }
+
+
//CHECK-NOT: !{i32 2, !"s390x-visible-vector-ABI", i32 1}
More information about the cfe-commits
mailing list