diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h --- a/clang/lib/CodeGen/CodeGenTypes.h +++ b/clang/lib/CodeGen/CodeGenTypes.h @@ -109,6 +109,7 @@ const llvm::DataLayout &getDataLayout() const { return TheModule.getDataLayout(); } + CodeGenModule &getCGM() const { return CGM; } ASTContext &getContext() const { return Context; } const ABIInfo &getABIInfo() const { return TheABIInfo; } const TargetInfo &getTarget() const { return Target; } diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -7402,18 +7402,20 @@ ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType ArgTy) const; - void computeInfo(CGFunctionInfo &FI) const override { - if (!getCXXABI().classifyReturnType(FI)) - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); - for (auto &I : FI.arguments()) - I.info = classifyArgumentType(I.type); - } - + void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { + // These are used for speeding up the search for a visible vector ABI. + mutable bool HasVisibleVecABIFlag = false; + mutable std::set 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; + public: SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI) : TargetCodeGenInfo( @@ -7422,6 +7424,37 @@ std::make_unique(CGT, /*SwiftErrorInRegister=*/false); } + // The vector ABI is different when the vector facility is present and when + // a module e.g. defines an externally visible vector variable, a flag + // 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)) { + M.getModule().addModuleFlag(llvm::Module::Warning, + "s390x-visible-vector-ABI", 1); + HasVisibleVecABIFlag = true; + } + } + + void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const override { + if (!D) + return; + + // Check if the vector ABI becomes visible by an externally visible + // variable or function. + if (const auto *VD = dyn_cast(D)) { + if (VD->isExternallyVisible()) + handleExternallyVisibleObjABI(VD->getType().getTypePtr(), M); + } + else if (const FunctionDecl *FD = dyn_cast(D)) { + if (FD->isExternallyVisible()) + handleExternallyVisibleObjABI(FD->getType().getTypePtr(), M); + } + } + llvm::Value *testFPKind(llvm::Value *V, unsigned BuiltinID, CGBuilderTy &Builder, CodeGenModule &CGM) const override { @@ -7579,6 +7612,9 @@ // Every non-vector argument occupies 8 bytes and is passed by preference // in either GPRs or FPRs. Vector arguments occupy 8 or 16 bytes and are // always passed on the stack. + const SystemZTargetCodeGenInfo &SZCGI = + static_cast( + CGT.getCGM().getTargetCodeGenInfo()); Ty = getContext().getCanonicalType(Ty); auto TyInfo = getContext().getTypeInfoInChars(Ty); llvm::Type *ArgTy = CGF.ConvertTypeForMem(Ty); @@ -7589,6 +7625,7 @@ bool IsVector = false; CharUnits UnpaddedSize; CharUnits DirectAlign; + SZCGI.handleExternallyVisibleObjABI(Ty.getTypePtr(), CGT.getCGM()); if (IsIndirect) { DirectTy = llvm::PointerType::getUnqual(DirectTy); UnpaddedSize = DirectAlign = CharUnits::fromQuantity(8); @@ -7783,6 +7820,51 @@ return ABIArgInfo::getDirect(nullptr); } +void SystemZABIInfo::computeInfo(CGFunctionInfo &FI) const { + const SystemZTargetCodeGenInfo &SZCGI = + static_cast( + CGT.getCGM().getTargetCodeGenInfo()); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + unsigned Idx = 0; + for (auto &I : FI.arguments()) { + I.info = classifyArgumentType(I.type); + if (FI.isVariadic() && Idx++ >= FI.getNumRequiredArgs()) + // 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()); + } +} + +bool SystemZTargetCodeGenInfo::isVectorTypeBased(const Type *Ty) const { + while (Ty->isPointerType() || Ty->isArrayType()) + Ty = Ty->getPointeeOrArrayElementType(); + if (!SeenTypes.insert(Ty).second) + return false; + if (Ty->isVectorType()) + return true; + if (const auto *RecordTy = Ty->getAs()) { + const RecordDecl *RD = RecordTy->getDecl(); + if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) + if (CXXRD->hasDefinition()) + for (const auto &I : CXXRD->bases()) + if (isVectorTypeBased(I.getType().getTypePtr())) + return true; + for (const auto *FD : RD->fields()) + if (isVectorTypeBased(FD->getType().getTypePtr())) + return true; + } + if (const auto *FT = Ty->getAs()) + if (isVectorTypeBased(FT->getReturnType().getTypePtr())) + return true; + if (const FunctionProtoType *Proto = Ty->getAs()) + for (auto ParamType : Proto->getParamTypes()) + if (isVectorTypeBased(ParamType.getTypePtr())) + return true; + return false; +} + //===----------------------------------------------------------------------===// // MSP430 ABI Implementation //===----------------------------------------------------------------------===// diff --git a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-00.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-00.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-00.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple s390x-ibm-linux -target-cpu arch10 -emit-llvm \ +// RUN: -fzvector -o - %s 2>&1 | FileCheck %s --check-prefix=MODFLAG +// +// Test the emission of the "s390x-visible-vector-ABI" module flag. + +// RUN: %clang_cc1 -triple s390x-ibm-linux -target-cpu arch10 -S \ +// RUN: -fzvector -o - %s 2>&1 | FileCheck %s --check-prefix=ARCH10-ASM +// RUN: %clang_cc1 -triple s390x-ibm-linux -target-cpu arch13 -S \ +// RUN: -fzvector -o - %s 2>&1 | FileCheck %s --check-prefix=ARCH13-ASM +// +// Test the emission of a gnu attribute describing the vector ABI. + +// Call to external function with vector argument. + +typedef __attribute__((vector_size(16))) int v4i32; + +void bar(v4i32 Arg); + +void foo() { + v4i32 Var = {0, 0, 0, 0}; + bar(Var); +} + +//MODFLAG: !llvm.module.flags = !{!0, !1} +//MODFLAG: !0 = !{i32 2, !"s390x-visible-vector-ABI", i32 1} + +//ARCH10-ASM: .gnu_attribute 8, 1 +//ARCH13-ASM: .gnu_attribute 8, 2 diff --git a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-01.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-01.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-01.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple s390x-ibm-linux -target-cpu arch13 -emit-llvm \ +// RUN: -fzvector -o - %s 2>&1 | FileCheck %s +// +// Test the emission of the "s390x-visible-vector-ABI" module flag. + +// Call to external function with vector return value. + +typedef __attribute__((vector_size(16))) int v4i32; + +v4i32 bar(void); + +void foo(v4i32 *Dst) { + v4i32 Var = bar(); + *Dst = 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-02.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-02.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-02.c @@ -0,0 +1,15 @@ +// 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 not emitted. + +// Call to external function *without* vector argument. + +void bar(int arg); + +void foo() { + int Var = 0; + bar(Var); +} + +//CHECK-NOT: !{i32 2, !"s390x-visible-vector-ABI", i32 1} diff --git a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-03.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-03.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-03.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm -fzvector -o - %s \ +// RUN: -Wno-undefined-internal 2>&1 | FileCheck %s +// +// Test that the "s390x-visible-vector-ABI" module flag is not emitted. + +// Calling *local* function with vector argument. + +typedef __attribute__((vector_size(16))) int v4i32; + +static void bar(v4i32 arg); + +void foo() { + v4i32 Var = {0, 0, 0, 0}; + bar(Var); +} + +//CHECK-NOT: !{i32 2, !"s390x-visible-vector-ABI", i32 1} diff --git a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-04.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-04.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-04.c @@ -0,0 +1,20 @@ +// 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 via global function pointer in internal function, with vector argument. + +typedef __attribute__((vector_size(16))) int v4i32; + +void (*bar)(v4i32 Arg); + +static void foo() { + v4i32 Var = {0, 0, 0, 0}; + (*bar)(Var); +} + +void fun() { foo(); } + +//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-05.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-05.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-05.c @@ -0,0 +1,20 @@ +// 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 via global function pointer in internal function, with vector return +// value. + +typedef __attribute__((vector_size(16))) int v4i32; + +v4i32 (*bar)(int); + +static int foo() { + (*bar)(0)[0]; +} + +int fun() { return foo(); } + +//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-06.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-06.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-06.c @@ -0,0 +1,21 @@ +// 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 address of local function with vector arg to global function. + +typedef __attribute__((vector_size(16))) int v4i32; + +void GlobFun(v4i32 (*f)(v4i32)); + +static v4i32 foo(v4i32 Arg) { + return Arg; +} + +void fun() { + GlobFun(foo); +} + +//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-07.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-07.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-07.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. + +// Passing an array of vectors. + +typedef __attribute__((vector_size(16))) int v4i32; + +void bar(v4i32 Arg[2]); + +void foo() { + v4i32 Var[2] = {{0, 0, 0, 0}, {0, 0, 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-08.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-08.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-08.c @@ -0,0 +1,23 @@ +// 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 struct containing a vector element. + +typedef __attribute__((vector_size(16))) int v4i32; + +struct S { + int A; + v4i32 B; +}; + +void bar(struct S Arg); + +void foo() { + struct S Var = {0, {0, 0, 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-09.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-09.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-09.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 vector argument. + +typedef __attribute__((vector_size(16))) int v4i32; + +void bar(int N, ...); + +void foo() { + v4i32 Var = {0, 0, 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-10.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-10.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-10.c @@ -0,0 +1,17 @@ +// 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 *without* any vector argument. + +typedef __attribute__((vector_size(16))) int v4i32; + +void bar(int N, ...); + +void foo() { + int Var = 0; + bar(0, Var); +} + +//CHECK-NOT: !{i32 2, !"s390x-visible-vector-ABI", i32 1} diff --git a/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-11.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-11.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-11.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 varargs function via global pointer to pointer to function. + +typedef __attribute__((vector_size(16))) int v4i32; + +void (**bar)(int N, ...); + +void foo() { + v4i32 Var = {0, 0, 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-12.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-12.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-12.c @@ -0,0 +1,16 @@ +// 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 vector argument to varargs function via local function pointer. + +typedef __attribute__((vector_size(16))) int v4i32; + +void foo(void (*bar)(int, ...)) { + v4i32 Var = {0, 0, 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-13.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-13.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-13.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple s390x-ibm-linux -emit-llvm -fzvector -o - %s \ +// RUN: -Wno-undefined-internal 2>&1 | FileCheck %s +// +// Test the emission of the "s390x-visible-vector-ABI" module flag. + +// Passing vector argument to varargs function between static functions. This +// also potentially exposes the vector ABI as the va_list may be passed on to +// another (global) function. + +typedef __attribute__((vector_size(16))) int v4i32; + +static int bar(int N, ...); + +static void foo() { + v4i32 Var = {0, 0, 0, 0}; + bar(0, Var); +} + +void fun() { foo(); } + +//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-14.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-14.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-14.c @@ -0,0 +1,20 @@ +// 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. + +// Use of va_arg with a vector type exposes the vector ABI. + +#include + +static int bar(va_list vl) { + return va_arg(vl, vector int)[0]; +} + +int foo(va_list vl) { + return bar(vl); +} + +//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-15.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-15.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-15.c @@ -0,0 +1,15 @@ +// 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. + +// Defining globally visible function with vector argument. + +typedef __attribute__((vector_size(16))) int v4i32; + +void fun(v4i32 Arg, v4i32 *Dst) { + *Dst = 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-16.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-16.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-16.c @@ -0,0 +1,16 @@ +// 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. + +// Defining globally visible function with vector return value. + +typedef __attribute__((vector_size(16))) int v4i32; + +v4i32 fun(int v) { + v4i32 Val = {v, v, v, v}; + return Val; +} + +//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-17.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-17.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-17.c @@ -0,0 +1,13 @@ +// 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. + +// Globally visible vector variable. + +typedef __attribute__((vector_size(16))) int v4i32; + +v4i32 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-18.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-18.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-18.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. + +// Globally visible struct array with vector element. + +typedef __attribute__((vector_size(16))) int v4i32; + +struct S { + int i; + v4i32 Var; +}; + +struct S Arr[16]; + +//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-19.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-19.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-19.c @@ -0,0 +1,19 @@ +// 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. + +// Globally visible struct with function pointer array member with vector +// return values. + +typedef __attribute__((vector_size(16))) int v4i32; + +struct S { + int i; + v4i32 (*funcptr[4])(int); +}; + +struct S Arr[16]; + +//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-20.cpp b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-20.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-20.cpp @@ -0,0 +1,28 @@ +// 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. + +// Globally visible C++ object with vector member. + +typedef __attribute__((vector_size(16))) int v4i32; + +class Base { +protected: + v4i32 v; +}; + +class C : public Base { + int i; + +public: + C() { + i = 1; + v = {1, 2, 3, 4}; + } +}; + +C Obj; + +//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-21.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-21.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-21.c @@ -0,0 +1,16 @@ +// 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. + +// Globally visible struct with a zero (variable) length array of vector values. + +typedef __attribute__((vector_size(16))) int v4i32; + +struct S { + int A; + v4i32 B[0]; +} s; + +//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-22.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-22.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-22.c @@ -0,0 +1,16 @@ +// 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. + +// Globally visible pointer to a vector variable. An unused pointer doesn't +// really expose the vector ABI, but as there seems to be no easy way to +// check if a pointer is dereferenced or not (when compiling C++ at least), +// this is treated conservatively. + +typedef __attribute__((vector_size(16))) int v4i32; + +v4i32 *VecPtr; + +//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-23.c b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-23.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-23.c @@ -0,0 +1,27 @@ +// 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. + +// Using external vector variable (twice to test that the module flag is only +// added once, which would be an error). + +typedef __attribute__((vector_size(16))) int v4i32; + +extern v4i32 Var; + +static void foo() { + v4i32 Loc = {1, 1, 1, 1}; + Var = Var + Loc; +} + +static void bar() { + v4i32 Loc = {1, 2, 3, 4}; + Var = Var + Loc; +} + +void fun1() { foo(); } +void fun2() { bar(); } + +//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 new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/SystemZ/vec-abi-gnuattr-24.c @@ -0,0 +1,37 @@ +// 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 not emitted. + +// Use of va_arg with a scalar type. +#include +int fun0(va_list vl) { + return va_arg(vl, int); +} + +typedef __attribute__((vector_size(16))) int v4i32; + +// Declaring unused global function with vector argument and return values; +v4i32 globfun(v4i32 Arg); + +// Declaring global scalar variable used below. +int GlobVal; + +// Declaring extern global scalar variable used below. +extern int GlobExtVar; + +// Local vector variable used below. +static v4i32 Var; + +// Local function with vector argument and return values; +static v4i32 foo(v4i32 Arg) { + Var = Var + Arg; + return Var; +} + +int fun1() { + v4i32 V = {1, 2, 3, 4}; + return foo(V)[0] + GlobVal + GlobExtVar; +} + +//CHECK-NOT: !{i32 2, !"s390x-visible-vector-ABI", i32 1} diff --git a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp --- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -432,6 +432,7 @@ bool ParseDirectiveInsn(SMLoc L); bool ParseDirectiveMachine(SMLoc L); + bool ParseGNUAttribute(SMLoc L); OperandMatchResultTy parseAddress(OperandVector &Operands, MemoryKind MemKind, @@ -1224,6 +1225,8 @@ return ParseDirectiveInsn(DirectiveID.getLoc()); if (IDVal == ".machine") return ParseDirectiveMachine(DirectiveID.getLoc()); + if (IDVal.startswith(".gnu_attribute")) + return ParseGNUAttribute(DirectiveID.getLoc()); return true; } @@ -1358,6 +1361,24 @@ return false; } +bool SystemZAsmParser::ParseGNUAttribute(SMLoc L) { + int64_t Tag; + int64_t IntegerValue; + if (!Parser.parseGNUAttribute(L, Tag, IntegerValue)) + return false; + + // Tag_GNU_S390_ABI_Vector tag is '8' and can be 0, 1, or 2. + if (Tag != 8 || (IntegerValue < 0 || IntegerValue > 2)) { + Error(Parser.getTok().getLoc(), + "Unrecognized .gnu_attribute tag/value pair."); + return false; + } + + Parser.getStreamer().emitGNUAttribute(Tag, IntegerValue); + + return true; +} + bool SystemZAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc, bool RestoreOnFailure) { Register Reg; diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h @@ -57,6 +57,7 @@ StringRef getPassName() const override { return "SystemZ Assembly Printer"; } void emitInstruction(const MachineInstr *MI) override; void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override; + void emitEndOfAsmFile(Module &M) override; bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, @@ -74,6 +75,7 @@ void LowerFENTRY_CALL(const MachineInstr &MI, SystemZMCInstLower &MCIL); void LowerSTACKMAP(const MachineInstr &MI); void LowerPATCHPOINT(const MachineInstr &MI, SystemZMCInstLower &Lower); + void emitAttributes(Module &M); }; } // end namespace llvm diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -759,6 +759,17 @@ getSubtargetInfo()); } +// The *alignment* of 128-bit vector types is different between the software +// and hardware vector ABIs. If the there is an externally visible use of a +// vector type in the module it should be annotated with an attribute. +void SystemZAsmPrinter::emitAttributes(Module &M) { + if (M.getModuleFlag("s390x-visible-vector-ABI")) { + bool HasVectorFeature = + TM.getMCSubtargetInfo()->getFeatureBits()[SystemZ::FeatureVector]; + OutStreamer->emitGNUAttribute(8, HasVectorFeature ? 2 : 1); + } +} + // Convert a SystemZ-specific constant pool modifier into the associated // MCSymbolRefExpr variant kind. static MCSymbolRefExpr::VariantKind @@ -859,6 +870,10 @@ return false; } +void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) { + emitAttributes(M); +} + void SystemZAsmPrinter::emitFunctionBodyEnd() { if (TM.getTargetTriple().isOSzOS()) { // Emit symbol for the end of function if the z/OS target streamer diff --git a/llvm/test/MC/SystemZ/gnu-attributes.s b/llvm/test/MC/SystemZ/gnu-attributes.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/SystemZ/gnu-attributes.s @@ -0,0 +1,17 @@ +# RUN: llvm-mc -triple s390x-linux-gnu -filetype=asm %s | \ +# RUN: FileCheck %s --check-prefix=ASM +# RUN: llvm-mc -triple s390x-linux-gnu -filetype=obj %s | \ +# RUN: llvm-objdump --mcpu=z14 -D - | FileCheck %s --check-prefix=OBJ + +#ASM: .text +#ASM: .gnu_attribute 8, 2 + +#OBJ: 0000000000000000 <.gnu.attributes>: +#OBJ: 0: 41 00 00 00 +#OBJ: 4: 0f 67 +#OBJ: 6: 6e 75 00 01 +#OBJ: a: 00 00 +#OBJ: c: 00 07 +#OBJ: e: 08 02 + + .gnu_attribute 8, 2