[llvm] 481bb44 - [SystemZ] Emit a .gnu_attribute for an externally visible vector abi.

Jonas Paulsson via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 6 10:54:26 PST 2022


Author: Jonas Paulsson
Date: 2022-12-06T12:53:40-06:00
New Revision: 481bb44baab5ce7a005b7d7eee6cafbde672695c

URL: https://github.com/llvm/llvm-project/commit/481bb44baab5ce7a005b7d7eee6cafbde672695c
DIFF: https://github.com/llvm/llvm-project/commit/481bb44baab5ce7a005b7d7eee6cafbde672695c.diff

LOG: [SystemZ] Emit a .gnu_attribute for an externally visible vector abi.

On SystemZ, the vector ABI changes depending on the presence of hardware
vector support. Therefore, each binary compiled with a visible vector ABI
(e.g. one that calls an external function with a vector argument) should be
marked with a .gnu_attribute describing this.

Reviewed By: uweigand

Differential Revision: https://reviews.llvm.org/D105067

Added: 
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-00.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-01.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-02.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-03.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-04.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-05.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-06.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-07.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-08.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-09.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-10.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-11.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-12.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-13.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-14.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-15.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-16.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-17.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-18.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-19.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-20.cpp
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-21.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-22.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-23.c
    clang/test/CodeGen/SystemZ/vec-abi-gnuattr-24.c
    llvm/test/MC/SystemZ/gnu-attributes.s

Modified: 
    clang/lib/CodeGen/CodeGenTypes.h
    clang/lib/CodeGen/TargetInfo.cpp
    llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
    llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
    llvm/lib/Target/SystemZ/SystemZAsmPrinter.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h
index 69acf605dc36b..e76fda95513f6 100644
--- a/clang/lib/CodeGen/CodeGenTypes.h
+++ b/clang/lib/CodeGen/CodeGenTypes.h
@@ -109,6 +109,7 @@ class CodeGenTypes {
   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
index 8be0625120ec8..bcb0e7b085743 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -7402,18 +7402,20 @@ class SystemZABIInfo : public ABIInfo {
   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<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;
+
 public:
   SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI)
       : TargetCodeGenInfo(
@@ -7422,6 +7424,37 @@ class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
         std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
   }
 
+  // The vector ABI is 
diff erent 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<VarDecl>(D)) {
+      if (VD->isExternallyVisible())
+        handleExternallyVisibleObjABI(VD->getType().getTypePtr(), M);
+    }
+    else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(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 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
   // 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<const SystemZTargetCodeGenInfo &>(
+          CGT.getCGM().getTargetCodeGenInfo());
   Ty = getContext().getCanonicalType(Ty);
   auto TyInfo = getContext().getTypeInfoInChars(Ty);
   llvm::Type *ArgTy = CGF.ConvertTypeForMem(Ty);
@@ -7589,6 +7625,7 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
   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 @@ ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
   return ABIArgInfo::getDirect(nullptr);
 }
 
+void SystemZABIInfo::computeInfo(CGFunctionInfo &FI) const {
+  const SystemZTargetCodeGenInfo &SZCGI =
+      static_cast<const SystemZTargetCodeGenInfo &>(
+          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<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()))
+            return true;
+    for (const auto *FD : RD->fields())
+      if (isVectorTypeBased(FD->getType().getTypePtr()))
+        return true;
+  }
+  if (const auto *FT = Ty->getAs<FunctionType>())
+    if (isVectorTypeBased(FT->getReturnType().getTypePtr()))
+      return true;
+  if (const FunctionProtoType *Proto = Ty->getAs<FunctionProtoType>())
+    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
index 0000000000000..8f2569e1248cb
--- /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
index 0000000000000..5a33acd857e44
--- /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
index 0000000000000..8c44c14cc2459
--- /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
index 0000000000000..caba77d206576
--- /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
index 0000000000000..70d31f36b22ab
--- /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
index 0000000000000..c19fd17a9684d
--- /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
index 0000000000000..b8cee2aeefb96
--- /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
index 0000000000000..7c99e5f71e1ff
--- /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
index 0000000000000..38c7e86b0e24e
--- /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
index 0000000000000..e30e560a1f6cf
--- /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
index 0000000000000..f9729e0581db5
--- /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
index 0000000000000..fc6cf0f7e643e
--- /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
index 0000000000000..cd7c89b72ea2d
--- /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
index 0000000000000..8fbd2e918db3c
--- /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
index 0000000000000..795807f5b92a0
--- /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 <stdarg.h>
+
+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
index 0000000000000..2c1c40d119ee6
--- /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
index 0000000000000..66e21e44d2d7e
--- /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
index 0000000000000..192fe89590aee
--- /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
index 0000000000000..ced54b02d1576
--- /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
index 0000000000000..8065121434c87
--- /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
index 0000000000000..66c2ba23fede9
--- /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
index 0000000000000..5589d6cddfe48
--- /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
index 0000000000000..8a0ff9c5f8263
--- /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
index 0000000000000..3e9ffbb563522
--- /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
index 0000000000000..a18fe924dc2d9
--- /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 <stdarg.h>
+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
index 60e1b05a6d1ab..92186b7538286 100644
--- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
+++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
@@ -432,6 +432,7 @@ class SystemZAsmParser : public MCTargetAsmParser {
 
   bool ParseDirectiveInsn(SMLoc L);
   bool ParseDirectiveMachine(SMLoc L);
+  bool ParseGNUAttribute(SMLoc L);
 
   OperandMatchResultTy parseAddress(OperandVector &Operands,
                                     MemoryKind MemKind,
@@ -1224,6 +1225,8 @@ bool SystemZAsmParser::ParseDirective(AsmToken DirectiveID) {
     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 @@ bool SystemZAsmParser::ParseDirectiveMachine(SMLoc L) {
   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.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index d72a58057b941..20c666a643407 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -759,6 +759,17 @@ void SystemZAsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
                             getSubtargetInfo());
 }
 
+// The *alignment* of 128-bit vector types is 
diff erent 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 @@ bool SystemZAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
   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/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 044dfbcd3316a..c99fcda6dcc52 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -57,6 +57,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   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 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   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/test/MC/SystemZ/gnu-attributes.s b/llvm/test/MC/SystemZ/gnu-attributes.s
new file mode 100644
index 0000000000000..fc62062b7c50c
--- /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


        


More information about the llvm-commits mailing list