[clang] [z/OS] Add option to target older versions of LE on z/OS (PR #123399)

Sean Perry via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 31 11:58:40 PST 2025


https://github.com/perry-ca updated https://github.com/llvm/llvm-project/pull/123399

>From 9f5763faa81691f540af42721147daf50042e549 Mon Sep 17 00:00:00 2001
From: Sean Perry <perry at ca.ibm.com>
Date: Wed, 27 Nov 2024 18:33:09 -0600
Subject: [PATCH 1/3] Add -mzos-target

---
 .../clang/Basic/DiagnosticDriverKinds.td      |  5 ++
 clang/include/clang/Driver/Options.td         |  1 +
 clang/lib/Basic/Targets/SystemZ.cpp           | 15 ++++
 clang/lib/Driver/Driver.cpp                   | 72 +++++++++++++++++++
 clang/lib/Driver/ToolChain.cpp                | 15 ++++
 clang/test/Preprocessor/zos-target.c          | 18 +++++
 6 files changed, 126 insertions(+)
 create mode 100644 clang/test/Preprocessor/zos-target.c

diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 5155b23d151c04..140bc52af12b25 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -277,6 +277,11 @@ def err_cpu_unsupported_isa
 def err_arch_unsupported_isa
   : Error<"architecture '%0' does not support '%1' execution mode">;
 
+def err_zos_target_release_discontinued
+  : Error<"z/OS target level \"%0\" is discontinued.  Unexpected behavior might occur if an out-of-support target level is specified.  Use z/OS target level \"zOSv2r4\", or later instead">;
+def err_zos_target_unrecognized_release
+  : Error<"\"%0\" is not recognized as a valid z/OS target level.  The z/OS target level must be \"current\", or of the form \"zosvVrR\", where \"V\" is the version and \"R\" is the release, or given as a \"0x\"-prefixed eight digit hexadecimal value">;
+
 def err_drv_I_dash_not_supported : Error<
   "'%0' not supported, please use -iquote instead">;
 def err_drv_unknown_argument : Error<"unknown argument: '%0'">;
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 40fd48761928b3..ddbd857414e714 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4734,6 +4734,7 @@ def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=
 def march_EQ : Joined<["-"], "march=">, Group<m_Group>,
   Flags<[TargetSpecific]>, Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>,
   HelpText<"For a list of available architectures for the target use '-mcpu=help'">;
+def mzos_target_EQ : Joined<["-"], "mzos-target=">, Group<m_Group>, Visibility<[ClangOption, CC1Option]>, HelpText<"Set the z/OS release of the runtime environment">;
 def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Visibility<[ClangOption, FlangOption]>;
 def inline_asm_EQ : Joined<["-"], "inline-asm=">, Group<m_Group>,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Basic/Targets/SystemZ.cpp b/clang/lib/Basic/Targets/SystemZ.cpp
index 06f08db2eadd47..2c749c0ba76937 100644
--- a/clang/lib/Basic/Targets/SystemZ.cpp
+++ b/clang/lib/Basic/Targets/SystemZ.cpp
@@ -168,6 +168,21 @@ void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts,
     Builder.defineMacro("__VX__");
   if (Opts.ZVector)
     Builder.defineMacro("__VEC__", "10304");
+
+  /* Set __TARGET_LIB__ only if a value was given.  If no value was given  */
+  /* we rely on the LE headers to define __TARGET_LIB__.                   */
+  if (!getTriple().getOSVersion().empty()) {
+    llvm::VersionTuple V = getTriple().getOSVersion();
+    // Create string with form: 0xPVRRMMMM, where P=4
+    std::string Str("0x");
+    unsigned int Librel = 0x40000000;
+    Librel |= V.getMajor() << 24;
+    Librel |= (V.getMinor() ? V.getMinor().value() : 1) << 16;
+    Librel |= V.getSubminor() ? V.getSubminor().value() : 0;
+    Str += llvm::utohexstr(Librel);
+
+    Builder.defineMacro("__TARGET_LIB__", Str.c_str());
+  }
 }
 
 ArrayRef<Builtin::Info> SystemZTargetInfo::getTargetBuiltins() const {
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index ad14b5c9b6dc80..eebe60648ed22b 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -517,6 +517,72 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
   return DAL;
 }
 
+static void setZosTargetVersion(const Driver &D, llvm::Triple &Target,
+                                StringRef ArgTarget) {
+
+  static bool BeSilent = false;
+  auto IsTooOldToBeSupported = [](int v, int r) -> bool {
+    return ((v < 2) || ((v == 2) && (r < 4)));
+  };
+
+  /* expect CURRENT, zOSV2R[45], or 0xnnnnnnnn */
+  if (ArgTarget.equals_insensitive("CURRENT")) {
+    /* If the user gives CURRENT, then we rely on the LE to set   */
+    /* __TARGET_LIB__.  There's nothing more we need to do.       */
+  } else {
+    unsigned int Version = 0;
+    unsigned int Release = 0;
+    unsigned int Modification = 0;
+    bool IsOk = true;
+    llvm::Regex ZOsvRegex("[zZ][oO][sS][vV]([0-9])[rR]([0-9])");
+    llvm::Regex HexRegex(
+        "0x4"                      /* product      */
+        "([0-9a-fA-F])"            /* version     */
+        "([0-9a-fA-F][0-9a-fA-F])" /* release */
+        "([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])" /* modification */);
+    SmallVector<StringRef> Matches;
+
+    if (ZOsvRegex.match(ArgTarget, &Matches)) {
+      Matches[1].getAsInteger(10, Version);
+      Matches[2].getAsInteger(10, Release);
+      Modification = 0;
+      if (IsTooOldToBeSupported(Version, Release)) {
+        if (!BeSilent)
+          D.Diag(diag::err_zos_target_release_discontinued) << ArgTarget;
+        IsOk = false;
+      }
+    } else if (HexRegex.match(ArgTarget, &Matches)) {
+      Matches[1].getAsInteger(16, Version);
+      Matches[2].getAsInteger(16, Release);
+      Matches[3].getAsInteger(16, Modification);
+      if (IsTooOldToBeSupported(Version, Release)) {
+        if (!BeSilent)
+          D.Diag(diag::err_zos_target_release_discontinued) << ArgTarget;
+        IsOk = false;
+      }
+    } else {
+      /* something else: need to report an error */
+      if (!BeSilent)
+        D.Diag(diag::err_zos_target_unrecognized_release) << ArgTarget;
+      IsOk = false;
+    }
+
+    if (IsOk) {
+      llvm::VersionTuple V(Version, Release, Modification);
+      llvm::VersionTuple TV = Target.getOSVersion();
+      // The goal is to pick the minimally supported version of
+      // the OS.  Pick the lesser as the target.
+      if (TV.empty() || V < TV) {
+        SmallString<16> Str;
+        Str = llvm::Triple::getOSTypeName(Target.getOS());
+        Str += V.getAsString();
+        Target.setOSName(Str);
+      }
+    }
+  }
+  BeSilent = true;
+}
+
 /// Compute target triple from args.
 ///
 /// This routine provides the logic to compute a target triple from various
@@ -638,6 +704,12 @@ static llvm::Triple computeTargetTriple(const Driver &D,
     }
   }
 
+  if (Target.isOSzOS()) {
+    if ((A = Args.getLastArg(options::OPT_mzos_target_EQ))) {
+      setZosTargetVersion(D, Target, A->getValue());
+    }
+  }
+
   // Handle -miamcu flag.
   if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) {
     if (Target.get32BitArchVariant().getArch() != llvm::Triple::x86)
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 0d426a467e9a3b..24f8ba447052c1 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -846,6 +846,21 @@ ToolChain::getTargetSubDirPath(StringRef BaseDir) const {
   if (auto Path = getPathForTriple(getTriple()))
     return *Path;
 
+  if (T.isOSzOS() &&
+      (!T.getOSVersion().empty() || !T.getEnvironmentVersion().empty())) {
+    // Build the triple without version information
+    const llvm::Triple &TripleWithoutVersion =
+        (T.hasEnvironment()
+             ? llvm::Triple(
+                   T.getArchName(), T.getVendorName(),
+                   llvm::Triple::getOSTypeName(T.getOS()),
+                   llvm::Triple::getEnvironmentTypeName(T.getEnvironment()))
+             : llvm::Triple(T.getArchName(), T.getVendorName(),
+                            llvm::Triple::getOSTypeName(T.getOS())));
+    if (auto Path = getPathForTriple(TripleWithoutVersion))
+      return *Path;
+  }
+
   // When building with per target runtime directories, various ways of naming
   // the Arm architecture may have been normalised to simply "arm".
   // For example "armv8l" (Armv8 AArch32 little endian) is replaced with "arm".
diff --git a/clang/test/Preprocessor/zos-target.c b/clang/test/Preprocessor/zos-target.c
new file mode 100644
index 00000000000000..9768812948bfc1
--- /dev/null
+++ b/clang/test/Preprocessor/zos-target.c
@@ -0,0 +1,18 @@
+// REQUIRES: target={{s390x-ibm-zos}}
+
+// In this case we expect __TARGET_LIB__ not to be defined because we don't
+// include any files here, and in particular, any from the LE.
+// RUN: %clang -mzos-target=current -dM -E %s | FileCheck --check-prefix=CURRENT %s
+// CURRENT-NOT: #define __TARGET_LIB__
+
+// RUN: %clang -mzos-target=zosv2r5 -dM -E %s | FileCheck --check-prefix=ZOSVR %s
+// ZOSVR: #define __TARGET_LIB__ 0x42050000
+
+// RUN: %clang -mzos-target=0x4204001f  -dM -E %s | FileCheck --check-prefix=HEX %s
+// HEX: #define __TARGET_LIB__ 0x4204001F
+
+// RUN: not %clang -mzos-target=0x42010000 -dM -E %s 2>&1 | FileCheck --check-prefix=ERR-DISCONTINUED %s
+// ERR-DISCONTINUED: z/OS target level "0x42010000" is discontinued. Unexpected behavior might occur if an out-of-support target level is specified. Use z/OS target level "zosv2r4", or later instead
+
+// RUN: not %clang -mzos-target=Rubbish -dM -E %s 2>&1 | FileCheck --check-prefix=ERR-INVALID-ARG   %s
+// ERR-INVALID-ARG: "Rubbish" is not recognized as a valid z/OS target level. The z/OS target level must be "current", or of the form "zosvVrR", where "V" is the version and "R" is the release, or given as a "0x"-prefixed eight digit hexadecimal value

>From 5bd29a0c12926e136cf15f18837f37bbdb9bbe0c Mon Sep 17 00:00:00 2001
From: Sean Perry <perry at ca.ibm.com>
Date: Fri, 17 Jan 2025 15:01:02 -0500
Subject: [PATCH 2/3] build on latest source

---
 clang/lib/Basic/Targets/SystemZ.cpp | 1 +
 clang/lib/Driver/ToolChain.cpp      | 9 +++++----
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Basic/Targets/SystemZ.cpp b/clang/lib/Basic/Targets/SystemZ.cpp
index 2c749c0ba76937..2731cb596fd27a 100644
--- a/clang/lib/Basic/Targets/SystemZ.cpp
+++ b/clang/lib/Basic/Targets/SystemZ.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/MacroBuilder.h"
 #include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringSwitch.h"
 
 using namespace clang;
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 9a2f438cc45d22..0da0de2e254948 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -855,7 +855,8 @@ ToolChain::getTargetSubDirPath(StringRef BaseDir) const {
     return {};
   };
 
-  if (auto Path = getPathForTriple(getTriple()))
+  const llvm::Triple &T = getTriple();
+  if (auto Path = getPathForTriple(T))
     return *Path;
 
   if (T.isOSzOS() &&
@@ -888,14 +889,14 @@ ToolChain::getTargetSubDirPath(StringRef BaseDir) const {
   //
   // M profile Arm is bare metal and we know they will not be using the per
   // target runtime directory layout.
-  if (getTriple().getArch() == Triple::arm && !getTriple().isArmMClass()) {
-    llvm::Triple ArmTriple = getTriple();
+  if (T.getArch() == Triple::arm && !T.isArmMClass()) {
+    llvm::Triple ArmTriple = T;
     ArmTriple.setArch(Triple::arm);
     if (auto Path = getPathForTriple(ArmTriple))
       return *Path;
   }
 
-  if (getTriple().isAndroid())
+  if (T.isAndroid())
     return getFallbackAndroidTargetPath(BaseDir);
 
   return {};

>From d532181334436832f74257478d1b7e3610134085 Mon Sep 17 00:00:00 2001
From: Sean Perry <perry at ca.ibm.com>
Date: Fri, 31 Jan 2025 14:58:06 -0500
Subject: [PATCH 3/3] Simplify & shorten the wording of the messages

---
 clang/include/clang/Basic/DiagnosticDriverKinds.td | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 1b679302197a2a..4020861e0d9a01 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -278,9 +278,9 @@ def err_arch_unsupported_isa
   : Error<"architecture '%0' does not support '%1' execution mode">;
 
 def err_zos_target_release_discontinued
-  : Error<"z/OS target level \"%0\" is discontinued.  Unexpected behavior might occur if an out-of-support target level is specified.  Use z/OS target level \"zOSv2r4\", or later instead">;
+  : Error<"z/OS target level \"%0\" is discontinued">;
 def err_zos_target_unrecognized_release
-  : Error<"\"%0\" is not recognized as a valid z/OS target level.  The z/OS target level must be \"current\", or of the form \"zosvVrR\", where \"V\" is the version and \"R\" is the release, or given as a \"0x\"-prefixed eight digit hexadecimal value">;
+  : Error<"z/OS target level \"%0\" is invalid">;
 
 def err_drv_I_dash_not_supported : Error<
   "'%0' not supported, please use -iquote instead">;



More information about the cfe-commits mailing list