Skip to content

Commit d2d1f14

Browse files
authored
[z/OS] Add option to target older versions of LE on z/OS (#123399)
Add an option similar to the -qtarget option in XL to allow the user to say they want to be able to run the generated program on an older version of the LE environment. This option will do two things: - set the `__TARGET_LIBS` macro so the system headers exclude newer interfaces when targeting older environments - set the arch level to match the minimum arch level for that older version of LE. It doesn't happen right now since all of the supported LE versions have a the same minimum ach level. So the option doesn't change this yet. The user can specify three different kinds of arguments: 1. -mzos-target=zosv*V*r*R* - where V & R are the version and release 2. -mzos-target=0x4vrrmmmm - v, r, m, p are the hex values for the version, release, and modlevel 3. -mzos-target=current - uses the latest version of LE the system headers have support for
1 parent 481e1eb commit d2d1f14

File tree

6 files changed

+132
-4
lines changed

6 files changed

+132
-4
lines changed

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ def err_cpu_unsupported_isa
279279
def err_arch_unsupported_isa
280280
: Error<"architecture '%0' does not support '%1' execution mode">;
281281

282+
def err_zos_target_release_discontinued
283+
: Error<"z/OS target level \"%0\" is discontinued">;
284+
def err_zos_target_unrecognized_release
285+
: Error<"z/OS target level \"%0\" is invalid">;
286+
282287
def err_drv_I_dash_not_supported : Error<
283288
"'%0' not supported, please use -iquote instead">;
284289
def err_drv_unknown_argument : Error<"unknown argument: '%0'">;

clang/include/clang/Driver/Options.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4728,6 +4728,7 @@ def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=
47284728
def march_EQ : Joined<["-"], "march=">, Group<m_Group>,
47294729
Flags<[TargetSpecific]>, Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>,
47304730
HelpText<"For a list of available architectures for the target use '-mcpu=help'">;
4731+
def mzos_target_EQ : Joined<["-"], "mzos-target=">, Group<m_Group>, Visibility<[ClangOption, CC1Option]>, HelpText<"Set the z/OS release of the runtime environment">;
47314732
def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Visibility<[ClangOption, FlangOption]>;
47324733
def inline_asm_EQ : Joined<["-"], "inline-asm=">, Group<m_Group>,
47334734
Visibility<[ClangOption, CC1Option]>,

clang/lib/Basic/Targets/SystemZ.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "clang/Basic/LangOptions.h"
1616
#include "clang/Basic/MacroBuilder.h"
1717
#include "clang/Basic/TargetBuiltins.h"
18+
#include "llvm/ADT/StringExtras.h"
1819
#include "llvm/ADT/StringSwitch.h"
1920

2021
using namespace clang;
@@ -178,6 +179,21 @@ void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts,
178179
Builder.defineMacro("__VX__");
179180
if (Opts.ZVector)
180181
Builder.defineMacro("__VEC__", "10305");
182+
183+
/* Set __TARGET_LIB__ only if a value was given. If no value was given */
184+
/* we rely on the LE headers to define __TARGET_LIB__. */
185+
if (!getTriple().getOSVersion().empty()) {
186+
llvm::VersionTuple V = getTriple().getOSVersion();
187+
// Create string with form: 0xPVRRMMMM, where P=4
188+
std::string Str("0x");
189+
unsigned int Librel = 0x40000000;
190+
Librel |= V.getMajor() << 24;
191+
Librel |= (V.getMinor() ? V.getMinor().value() : 1) << 16;
192+
Librel |= V.getSubminor() ? V.getSubminor().value() : 0;
193+
Str += llvm::utohexstr(Librel);
194+
195+
Builder.defineMacro("__TARGET_LIB__", Str.c_str());
196+
}
181197
}
182198

183199
llvm::SmallVector<Builtin::InfosShard>

clang/lib/Driver/Driver.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,72 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
564564
return DAL;
565565
}
566566

567+
static void setZosTargetVersion(const Driver &D, llvm::Triple &Target,
568+
StringRef ArgTarget) {
569+
570+
static bool BeSilent = false;
571+
auto IsTooOldToBeSupported = [](int v, int r) -> bool {
572+
return ((v < 2) || ((v == 2) && (r < 4)));
573+
};
574+
575+
/* expect CURRENT, zOSV2R[45], or 0xnnnnnnnn */
576+
if (ArgTarget.equals_insensitive("CURRENT")) {
577+
/* If the user gives CURRENT, then we rely on the LE to set */
578+
/* __TARGET_LIB__. There's nothing more we need to do. */
579+
} else {
580+
unsigned int Version = 0;
581+
unsigned int Release = 0;
582+
unsigned int Modification = 0;
583+
bool IsOk = true;
584+
llvm::Regex ZOsvRegex("[zZ][oO][sS][vV]([0-9])[rR]([0-9])");
585+
llvm::Regex HexRegex(
586+
"0x4" /* product */
587+
"([0-9a-fA-F])" /* version */
588+
"([0-9a-fA-F][0-9a-fA-F])" /* release */
589+
"([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])" /* modification */);
590+
SmallVector<StringRef> Matches;
591+
592+
if (ZOsvRegex.match(ArgTarget, &Matches)) {
593+
Matches[1].getAsInteger(10, Version);
594+
Matches[2].getAsInteger(10, Release);
595+
Modification = 0;
596+
if (IsTooOldToBeSupported(Version, Release)) {
597+
if (!BeSilent)
598+
D.Diag(diag::err_zos_target_release_discontinued) << ArgTarget;
599+
IsOk = false;
600+
}
601+
} else if (HexRegex.match(ArgTarget, &Matches)) {
602+
Matches[1].getAsInteger(16, Version);
603+
Matches[2].getAsInteger(16, Release);
604+
Matches[3].getAsInteger(16, Modification);
605+
if (IsTooOldToBeSupported(Version, Release)) {
606+
if (!BeSilent)
607+
D.Diag(diag::err_zos_target_release_discontinued) << ArgTarget;
608+
IsOk = false;
609+
}
610+
} else {
611+
/* something else: need to report an error */
612+
if (!BeSilent)
613+
D.Diag(diag::err_zos_target_unrecognized_release) << ArgTarget;
614+
IsOk = false;
615+
}
616+
617+
if (IsOk) {
618+
llvm::VersionTuple V(Version, Release, Modification);
619+
llvm::VersionTuple TV = Target.getOSVersion();
620+
// The goal is to pick the minimally supported version of
621+
// the OS. Pick the lesser as the target.
622+
if (TV.empty() || V < TV) {
623+
SmallString<16> Str;
624+
Str = llvm::Triple::getOSTypeName(Target.getOS());
625+
Str += V.getAsString();
626+
Target.setOSName(Str);
627+
}
628+
}
629+
}
630+
BeSilent = true;
631+
}
632+
567633
/// Compute target triple from args.
568634
///
569635
/// This routine provides the logic to compute a target triple from various
@@ -689,6 +755,12 @@ static llvm::Triple computeTargetTriple(const Driver &D,
689755
}
690756
}
691757

758+
if (Target.isOSzOS()) {
759+
if ((A = Args.getLastArg(options::OPT_mzos_target_EQ))) {
760+
setZosTargetVersion(D, Target, A->getValue());
761+
}
762+
}
763+
692764
// Handle -miamcu flag.
693765
if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) {
694766
if (Target.get32BitArchVariant().getArch() != llvm::Triple::x86)

clang/lib/Driver/ToolChain.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -854,9 +854,25 @@ ToolChain::getTargetSubDirPath(StringRef BaseDir) const {
854854
return {};
855855
};
856856

857-
if (auto Path = getPathForTriple(getTriple()))
857+
const llvm::Triple &T = getTriple();
858+
if (auto Path = getPathForTriple(T))
858859
return *Path;
859860

861+
if (T.isOSzOS() &&
862+
(!T.getOSVersion().empty() || !T.getEnvironmentVersion().empty())) {
863+
// Build the triple without version information
864+
const llvm::Triple &TripleWithoutVersion =
865+
(T.hasEnvironment()
866+
? llvm::Triple(
867+
T.getArchName(), T.getVendorName(),
868+
llvm::Triple::getOSTypeName(T.getOS()),
869+
llvm::Triple::getEnvironmentTypeName(T.getEnvironment()))
870+
: llvm::Triple(T.getArchName(), T.getVendorName(),
871+
llvm::Triple::getOSTypeName(T.getOS())));
872+
if (auto Path = getPathForTriple(TripleWithoutVersion))
873+
return *Path;
874+
}
875+
860876
// When building with per target runtime directories, various ways of naming
861877
// the Arm architecture may have been normalised to simply "arm".
862878
// For example "armv8l" (Armv8 AArch32 little endian) is replaced with "arm".
@@ -872,14 +888,14 @@ ToolChain::getTargetSubDirPath(StringRef BaseDir) const {
872888
//
873889
// M profile Arm is bare metal and we know they will not be using the per
874890
// target runtime directory layout.
875-
if (getTriple().getArch() == Triple::arm && !getTriple().isArmMClass()) {
876-
llvm::Triple ArmTriple = getTriple();
891+
if (T.getArch() == Triple::arm && !T.isArmMClass()) {
892+
llvm::Triple ArmTriple = T;
877893
ArmTriple.setArch(Triple::arm);
878894
if (auto Path = getPathForTriple(ArmTriple))
879895
return *Path;
880896
}
881897

882-
if (getTriple().isAndroid())
898+
if (T.isAndroid())
883899
return getFallbackAndroidTargetPath(BaseDir);
884900

885901
return {};

clang/test/Preprocessor/zos-target.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// REQUIRES: target={{s390x-ibm-zos}}
2+
3+
// In this case we expect __TARGET_LIB__ not to be defined because we don't
4+
// include any files here, and in particular, any from the LE.
5+
// RUN: %clang -mzos-target=current -dM -E %s | FileCheck --check-prefix=CURRENT %s
6+
// CURRENT-NOT: #define __TARGET_LIB__
7+
8+
// RUN: %clang -mzos-target=zosv2r5 -dM -E %s | FileCheck --check-prefix=ZOSVR %s
9+
// ZOSVR: #define __TARGET_LIB__ 0x42050000
10+
11+
// RUN: %clang -mzos-target=0x4204001f -dM -E %s | FileCheck --check-prefix=HEX %s
12+
// HEX: #define __TARGET_LIB__ 0x4204001F
13+
14+
// RUN: not %clang -mzos-target=0x42010000 -dM -E %s 2>&1 | FileCheck --check-prefix=ERR-DISCONTINUED %s
15+
// 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
16+
17+
// RUN: not %clang -mzos-target=Rubbish -dM -E %s 2>&1 | FileCheck --check-prefix=ERR-INVALID-ARG %s
18+
// 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

0 commit comments

Comments
 (0)