Skip to content

Commit 0eff46f

Browse files
committed
[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
1 parent 683b83a commit 0eff46f

File tree

6 files changed

+153
-29
lines changed

6 files changed

+153
-29
lines changed

clang/lib/CodeGen/TargetInfo.cpp

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7418,18 +7418,28 @@ class SystemZABIInfo : public ABIInfo {
74187418
};
74197419

74207420
class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
7421+
ASTContext &Ctx;
7422+
7423+
const SystemZABIInfo &getABIInfo() const {
7424+
return static_cast<const SystemZABIInfo&>(TargetCodeGenInfo::getABIInfo());
7425+
}
7426+
74217427
// These are used for speeding up the search for a visible vector ABI.
74227428
mutable bool HasVisibleVecABIFlag = false;
74237429
mutable std::set<const Type *> SeenTypes;
74247430

7425-
// Returns true (the first time) if Ty is or found to make use of a vector
7426-
// type (e.g. as a function argument).
7427-
bool isVectorTypeBased(const Type *Ty) const;
7431+
// Returns true (the first time) if Ty is, or is found to include, a vector
7432+
// type that exposes the vector ABI. This is any vector >=16 bytes which
7433+
// with vector support are aligned to only 8 bytes. When IsParam is true,
7434+
// the type belongs to a value as passed between functions. If it is a
7435+
// vector <=16 bytes it will be passed in a vector register (if supported).
7436+
bool isVectorTypeBased(const Type *Ty, bool IsParam) const;
74287437

74297438
public:
74307439
SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI)
74317440
: TargetCodeGenInfo(
7432-
std::make_unique<SystemZABIInfo>(CGT, HasVector, SoftFloatABI)) {
7441+
std::make_unique<SystemZABIInfo>(CGT, HasVector, SoftFloatABI)),
7442+
Ctx(CGT.getContext()) {
74337443
SwiftInfo =
74347444
std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
74357445
}
@@ -7439,9 +7449,9 @@ class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
74397449
// indicating a visible vector ABI is added. Eventually this will result in
74407450
// a GNU attribute indicating the vector ABI of the module. Ty is the type
74417451
// of a variable or function parameter that is globally visible.
7442-
void handleExternallyVisibleObjABI(const Type *Ty,
7443-
CodeGen::CodeGenModule &M) const {
7444-
if (!HasVisibleVecABIFlag && isVectorTypeBased(Ty)) {
7452+
void handleExternallyVisibleObjABI(const Type *Ty, CodeGen::CodeGenModule &M,
7453+
bool IsParam) const {
7454+
if (!HasVisibleVecABIFlag && isVectorTypeBased(Ty, IsParam)) {
74457455
M.getModule().addModuleFlag(llvm::Module::Warning,
74467456
"s390x-visible-vector-ABI", 1);
74477457
HasVisibleVecABIFlag = true;
@@ -7457,11 +7467,13 @@ class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
74577467
// variable or function.
74587468
if (const auto *VD = dyn_cast<VarDecl>(D)) {
74597469
if (VD->isExternallyVisible())
7460-
handleExternallyVisibleObjABI(VD->getType().getTypePtr(), M);
7470+
handleExternallyVisibleObjABI(VD->getType().getTypePtr(), M,
7471+
/*IsParam*/false);
74617472
}
74627473
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
74637474
if (FD->isExternallyVisible())
7464-
handleExternallyVisibleObjABI(FD->getType().getTypePtr(), M);
7475+
handleExternallyVisibleObjABI(FD->getType().getTypePtr(), M,
7476+
/*IsParam*/false);
74657477
}
74667478
}
74677479

@@ -7571,17 +7583,18 @@ QualType SystemZABIInfo::GetSingleElementType(QualType Ty) const {
75717583

75727584
// If this is a C++ record, check the bases first.
75737585
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
7574-
for (const auto &I : CXXRD->bases()) {
7575-
QualType Base = I.getType();
7586+
if (CXXRD->hasDefinition())
7587+
for (const auto &I : CXXRD->bases()) {
7588+
QualType Base = I.getType();
75767589

7577-
// Empty bases don't affect things either way.
7578-
if (isEmptyRecord(getContext(), Base, true))
7579-
continue;
7590+
// Empty bases don't affect things either way.
7591+
if (isEmptyRecord(getContext(), Base, true))
7592+
continue;
75807593

7581-
if (!Found.isNull())
7582-
return Ty;
7583-
Found = GetSingleElementType(Base);
7584-
}
7594+
if (!Found.isNull())
7595+
return Ty;
7596+
Found = GetSingleElementType(Base);
7597+
}
75857598

75867599
// Check the fields.
75877600
for (const auto *FD : RD->fields()) {
@@ -7635,7 +7648,8 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
76357648
bool IsVector = false;
76367649
CharUnits UnpaddedSize;
76377650
CharUnits DirectAlign;
7638-
SZCGI.handleExternallyVisibleObjABI(Ty.getTypePtr(), CGT.getCGM());
7651+
SZCGI.handleExternallyVisibleObjABI(Ty.getTypePtr(), CGT.getCGM(),
7652+
/*IsParam*/true);
76397653
if (IsIndirect) {
76407654
DirectTy = llvm::PointerType::getUnqual(DirectTy);
76417655
UnpaddedSize = DirectAlign = CharUnits::fromQuantity(8);
@@ -7843,35 +7857,57 @@ void SystemZABIInfo::computeInfo(CGFunctionInfo &FI) const {
78437857
// Check if a vararg vector argument is passed, in which case the
78447858
// vector ABI becomes visible as the va_list could be passed on to
78457859
// other functions.
7846-
SZCGI.handleExternallyVisibleObjABI(I.type.getTypePtr(), CGT.getCGM());
7860+
SZCGI.handleExternallyVisibleObjABI(I.type.getTypePtr(), CGT.getCGM(),
7861+
/*IsParam*/true);
78477862
}
78487863
}
78497864

7850-
bool SystemZTargetCodeGenInfo::isVectorTypeBased(const Type *Ty) const {
7851-
while (Ty->isPointerType() || Ty->isArrayType())
7852-
Ty = Ty->getPointeeOrArrayElementType();
7865+
bool SystemZTargetCodeGenInfo::isVectorTypeBased(const Type *Ty,
7866+
bool IsParam) const {
78537867
if (!SeenTypes.insert(Ty).second)
78547868
return false;
7855-
if (Ty->isVectorType())
7856-
return true;
7869+
7870+
if (IsParam) {
7871+
// A narrow (<16 bytes) vector will as a parameter also expose the ABI as
7872+
// it will be passed in a vector register. A wide (>16 bytes) vector will
7873+
// be passed via "hidden" pointer where any extra alignment is not
7874+
// required (per GCC).
7875+
const Type *SingleEltTy =
7876+
getABIInfo().GetSingleElementType(QualType(Ty, 0)).getTypePtr();
7877+
bool SingleVecEltStruct = SingleEltTy != Ty && SingleEltTy->isVectorType() &&
7878+
Ctx.getTypeSize(SingleEltTy) == Ctx.getTypeSize(Ty);
7879+
if (Ty->isVectorType() || SingleVecEltStruct)
7880+
return Ctx.getTypeSize(Ty) / 8 <= 16;
7881+
}
7882+
7883+
// Assume pointers are dereferenced.
7884+
while (Ty->isPointerType() || Ty->isArrayType())
7885+
Ty = Ty->getPointeeOrArrayElementType();
7886+
7887+
// Vectors >= 16 bytes expose the ABI through alignment requirements.
7888+
if (Ty->isVectorType() && Ctx.getTypeSize(Ty) / 8 >= 16)
7889+
return true;
7890+
78577891
if (const auto *RecordTy = Ty->getAs<RecordType>()) {
78587892
const RecordDecl *RD = RecordTy->getDecl();
78597893
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
78607894
if (CXXRD->hasDefinition())
78617895
for (const auto &I : CXXRD->bases())
7862-
if (isVectorTypeBased(I.getType().getTypePtr()))
7896+
if (isVectorTypeBased(I.getType().getTypePtr(), /*IsParam*/false))
78637897
return true;
78647898
for (const auto *FD : RD->fields())
7865-
if (isVectorTypeBased(FD->getType().getTypePtr()))
7899+
if (isVectorTypeBased(FD->getType().getTypePtr(), /*IsParam*/false))
78667900
return true;
78677901
}
7902+
78687903
if (const auto *FT = Ty->getAs<FunctionType>())
7869-
if (isVectorTypeBased(FT->getReturnType().getTypePtr()))
7904+
if (isVectorTypeBased(FT->getReturnType().getTypePtr(), /*IsParam*/true))
78707905
return true;
78717906
if (const FunctionProtoType *Proto = Ty->getAs<FunctionProtoType>())
78727907
for (auto ParamType : Proto->getParamTypes())
7873-
if (isVectorTypeBased(ParamType.getTypePtr()))
7908+
if (isVectorTypeBased(ParamType.getTypePtr(), /*IsParam*/true))
78747909
return true;
7910+
78757911
return false;
78767912
}
78777913

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm -fzvector -o - %s 2>&1 \
2+
// RUN: | FileCheck %s
3+
//
4+
// Test that the "s390x-visible-vector-ABI" module flag is emitted.
5+
6+
// Call to external function with with narrow vector argument.
7+
8+
typedef __attribute__((vector_size(8))) int v2i32;
9+
10+
void bar(v2i32 arg);
11+
12+
void foo() {
13+
v2i32 Var = {0, 0};
14+
bar(Var);
15+
}
16+
17+
//CHECK: !llvm.module.flags = !{!0, !1}
18+
//CHECK: !0 = !{i32 2, !"s390x-visible-vector-ABI", i32 1}
19+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm -fzvector -o - %s 2>&1 \
2+
// RUN: | FileCheck %s
3+
//
4+
// Test the emission of the "s390x-visible-vector-ABI" module flag.
5+
6+
// Passing a single element struct containing a narrow (8 byte) vector element.
7+
8+
typedef __attribute__((vector_size(8))) int v2i32;
9+
10+
struct S {
11+
v2i32 B;
12+
};
13+
14+
void bar(struct S Arg);
15+
16+
void foo() {
17+
struct S Var = {{0, 0}};
18+
bar(Var);
19+
}
20+
21+
//CHECK: !llvm.module.flags = !{!0, !1}
22+
//CHECK: !0 = !{i32 2, !"s390x-visible-vector-ABI", i32 1}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm -fzvector -o - %s 2>&1 \
2+
// RUN: | FileCheck %s
3+
//
4+
// Test the emission of the "s390x-visible-vector-ABI" module flag.
5+
6+
// Call to vararg function with a narrow (8 bytes) vector argument.
7+
8+
typedef __attribute__((vector_size(8))) int v2i32;
9+
10+
void bar(int N, ...);
11+
12+
void foo() {
13+
v2i32 Var = {0, 0};
14+
bar(0, Var);
15+
}
16+
17+
//CHECK: !llvm.module.flags = !{!0, !1}
18+
//CHECK: !0 = !{i32 2, !"s390x-visible-vector-ABI", i32 1}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm -fzvector -o - %s 2>&1 \
2+
// RUN: | FileCheck %s
3+
//
4+
// Test that the "s390x-visible-vector-ABI" module flag is emitted.
5+
6+
// Globally visible function pointer with narrow vector argument.
7+
8+
typedef __attribute__((vector_size(8))) int v2i32;
9+
10+
void (*bar)(v2i32 Arg);
11+
12+
//CHECK: !llvm.module.flags = !{!0, !1}
13+
//CHECK: !0 = !{i32 2, !"s390x-visible-vector-ABI", i32 1}

clang/test/CodeGen/SystemZ/vec-abi-gnuattr-24.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,20 @@ int fun1() {
3434
return foo(V)[0] + GlobVal + GlobExtVar;
3535
}
3636

37+
// Globally visible vector variable less than 16 bytes in size.
38+
typedef __attribute__((vector_size(8))) int v2i32;
39+
v2i32 NarrowVecVar;
40+
41+
// Global function taking narrow vector array and pointer.
42+
void bar(v2i32 VArr[4], v2i32 *Dst) { *Dst = VArr[3]; }
43+
44+
// Wide vector parameters via "hidden" pointers.
45+
typedef __attribute__((vector_size(32))) int v8i32;
46+
v8i32 bar2(v8i32 Arg) { return Arg; }
47+
48+
// Same but with a single element struct.
49+
struct SingleElStruct { v8i32 B; };
50+
struct SingleElStruct bar3(struct SingleElStruct Arg) { return Arg; }
51+
52+
3753
//CHECK-NOT: !{i32 2, !"s390x-visible-vector-ABI", i32 1}

0 commit comments

Comments
 (0)