Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -4450,6 +4450,11 @@ } QualType CodeGenFunction::getVarArgType(const Expr *Arg) { + + // SystemZ needs to keep track of when the vector ABI becomes visible, + // which happens when passing a vector var arg. + CGM.getTargetCodeGenInfo().checkVarArgABI(Arg, CGM); + // System headers on Windows define NULL to 0 instead of 0LL on Win64. MSVC // implicitly widens null pointer constants that are arguments to varargs // functions to pointer-sized ints. Index: clang/lib/CodeGen/TargetInfo.h =================================================================== --- clang/lib/CodeGen/TargetInfo.h +++ clang/lib/CodeGen/TargetInfo.h @@ -83,6 +83,11 @@ const FunctionDecl *Callee, const CallArgList &Args) const {} + /// Let target inspect any variadic call args including those made via + /// function pointers. + virtual void checkVarArgABI(const Expr *Arg, + CodeGen::CodeGenModule &M) const {} + /// Determines the size of struct _Unwind_Exception on this platform, /// in 8-bit units. The Itanium ABI defines this as: /// struct _Unwind_Exception { Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -7413,6 +7413,47 @@ }; class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { + mutable bool HasVisibleVecABIFlag = false; + mutable std::set SeenTypes; + + // The vector ABI is different in later CPU generations with hardware + // vector support. Add a flag indicating that the module makes the vector + // ABI visible, by e.g. defining a global vector variable. + void addVisibleVecABIModuleFlag(CodeGen::CodeGenModule &M) const { + assert(!HasVisibleVecABIFlag && "Module flag already added."); + M.getModule().addModuleFlag(llvm::Module::Warning, + "s390x-visible-vector-ABI", 1); + HasVisibleVecABIFlag = true; + } + + // Returns true the first time Ty is found to be or contain a vector + // type. The caller is responsible for also calling + // addVisibleVecABIModuleFlag() if true is returned. + bool 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(); + for (RecordDecl::field_iterator Field = RD->field_begin(); + Field != RD->field_end(); ++Field) { + if (isVectorTypeBased(Field->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; + } + public: SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI) : TargetCodeGenInfo( @@ -7421,6 +7462,36 @@ std::make_unique(CGT, /*SwiftErrorInRegister=*/false); } + // Check if the vector ABI is visible by inspecting variables and + // functions. + void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const override { + if (HasVisibleVecABIFlag || !D) + return; + + bool VecABIExposed = false; + if (const auto *VD = dyn_cast(D)) { + if (M.getContext().GetGVALinkageForVariable(VD) != GVA_Internal && + isVectorTypeBased(VD->getType().getTypePtr())) + VecABIExposed = true; + } + else if (const FunctionDecl *FD = dyn_cast(D)) { + if (M.getContext().GetGVALinkageForFunction(FD) != GVA_Internal && + isVectorTypeBased(FD->getType().getTypePtr())) + VecABIExposed = true; + } + + if (VecABIExposed) + addVisibleVecABIModuleFlag(M); + } + + // Check if the vector ABI is visible by inspecting vararg arguments. + void checkVarArgABI(const Expr *Arg, + CodeGen::CodeGenModule &M) const override { + if (!HasVisibleVecABIFlag && isVectorTypeBased(Arg->getType().getTypePtr())) + addVisibleVecABIModuleFlag(M); + } + llvm::Value *testFPKind(llvm::Value *V, unsigned BuiltinID, CGBuilderTy &Builder, CodeGenModule &CGM) const override { @@ -7588,6 +7659,10 @@ bool IsVector = false; CharUnits UnpaddedSize; CharUnits DirectAlign; + llvm::Module &M = CGF.CGM.getModule(); + if (!CGF.CurFn->hasLocalLinkage() && ArgTy->isVectorTy() && + !M.getModuleFlag("s390x-visible-vector-ABI")) + M.addModuleFlag(llvm::Module::Warning, "s390x-visible-vector-ABI", 1); if (IsIndirect) { DirectTy = llvm::PointerType::getUnqual(DirectTy); UnpaddedSize = DirectAlign = CharUnits::fromQuantity(8); Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-00.c =================================================================== --- /dev/null +++ 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 Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-01.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-02.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-03.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-04.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-05.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-06.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-07.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-08.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-09.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-10.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-11.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-12.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-13.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-14.c =================================================================== --- /dev/null +++ clang/test/CodeGen/SystemZ/vec-abi-gnuattr-14.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. + +// Use of va_arg with a vector type exposes the vector ABI. + +#include + +int fun(va_list vl) { + return va_arg(vl, vector int)[0]; +} + +//CHECK: !llvm.module.flags = !{!0, !1} +//CHECK: !0 = !{i32 2, !"s390x-visible-vector-ABI", i32 1} + Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-15.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-16.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-17.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-18.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-19.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-20.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/SystemZ/vec-abi-gnuattr-20.cpp @@ -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. + +// Globally visible C++ object with vector member. + +typedef __attribute__((vector_size(16))) int v4i32; + +class C { + int i; + v4i32 v; + 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-21.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-22.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-23.c =================================================================== --- /dev/null +++ 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} Index: clang/test/CodeGen/SystemZ/vec-abi-gnuattr-24.c =================================================================== --- /dev/null +++ clang/test/CodeGen/SystemZ/vec-abi-gnuattr-24.c @@ -0,0 +1,31 @@ +// 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. + +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 fun() { + v4i32 V = {1, 2, 3, 4}; + return foo(V)[0] + GlobVal + GlobExtVar; +} + +//CHECK-NOT: !{i32 2, !"s390x-visible-vector-ABI", i32 1} Index: llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp =================================================================== --- llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ 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; Index: llvm/lib/Target/SystemZ/SystemZAsmPrinter.h =================================================================== --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.h +++ 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 Index: llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ 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 Index: llvm/test/MC/SystemZ/gnu-attributes.s =================================================================== --- /dev/null +++ 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