1//===--- SystemZ.cpp - Implement SystemZ target feature support -----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements SystemZ TargetInfo objects.
10//
11//===----------------------------------------------------------------------===//
12
13#include "SystemZ.h"
14#include "clang/Basic/Builtins.h"
15#include "clang/Basic/LangOptions.h"
16#include "clang/Basic/MacroBuilder.h"
17#include "clang/Basic/TargetBuiltins.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/ADT/StringSwitch.h"
20
21using namespace clang;
22using namespace clang::targets;
23
24static constexpr int NumBuiltins =
25 clang::SystemZ::LastSystemZBuiltin - Builtin::FirstTSBuiltin + 1;
26static constexpr int NumBuiltinsZOS =
27 clang::SystemZ::LastTSBuiltin - clang::SystemZ::LastSystemZBuiltin - 1;
28
29#define GET_BUILTIN_STR_TABLE
30#include "clang/Basic/BuiltinsSystemZ.inc"
31#undef GET_BUILTIN_STR_TABLE
32
33static constexpr Builtin::Info BuiltinInfos[] = {
34#define GET_BUILTIN_INFOS
35#include "clang/Basic/BuiltinsSystemZ.inc"
36#undef GET_BUILTIN_INFOS
37};
38
39static constexpr Builtin::Info PrefixedBuiltinInfos[] = {
40#define GET_BUILTIN_PREFIXED_INFOS
41#include "clang/Basic/BuiltinsSystemZ.inc"
42#undef GET_BUILTIN_PREFIXED_INFOS
43};
44static_assert((std::size(BuiltinInfos) + std::size(PrefixedBuiltinInfos)) ==
45 NumBuiltins);
46namespace clang {
47namespace ZOS {
48#define GET_BUILTIN_STR_TABLE
49#include "clang/Basic/BuiltinsZOS.inc"
50#undef GET_BUILTIN_STR_TABLE
51
52static constexpr Builtin::Info BuiltinInfos[] = {
53#define GET_BUILTIN_INFOS
54#include "clang/Basic/BuiltinsZOS.inc"
55#undef GET_BUILTIN_INFOS
56};
57static_assert((std::size(BuiltinInfos)) == NumBuiltinsZOS);
58} // namespace ZOS
59} // namespace clang
60
61const char *const SystemZTargetInfo::GCCRegNames[] = {
62 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
63 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
64 "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7",
65 "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15",
66 /*ap*/"", "cc", /*fp*/"", /*rp*/"", "a0", "a1",
67 "v16", "v18", "v20", "v22", "v17", "v19", "v21", "v23",
68 "v24", "v26", "v28", "v30", "v25", "v27", "v29", "v31"
69};
70
71const TargetInfo::AddlRegName GCCAddlRegNames[] = {
72 {.Names: {"v0"}, .RegNum: 16}, {.Names: {"v2"}, .RegNum: 17}, {.Names: {"v4"}, .RegNum: 18}, {.Names: {"v6"}, .RegNum: 19},
73 {.Names: {"v1"}, .RegNum: 20}, {.Names: {"v3"}, .RegNum: 21}, {.Names: {"v5"}, .RegNum: 22}, {.Names: {"v7"}, .RegNum: 23},
74 {.Names: {"v8"}, .RegNum: 24}, {.Names: {"v10"}, .RegNum: 25}, {.Names: {"v12"}, .RegNum: 26}, {.Names: {"v14"}, .RegNum: 27},
75 {.Names: {"v9"}, .RegNum: 28}, {.Names: {"v11"}, .RegNum: 29}, {.Names: {"v13"}, .RegNum: 30}, {.Names: {"v15"}, .RegNum: 31}
76};
77
78ArrayRef<const char *> SystemZTargetInfo::getGCCRegNames() const {
79 return llvm::ArrayRef(GCCRegNames);
80}
81
82ArrayRef<TargetInfo::AddlRegName> SystemZTargetInfo::getGCCAddlRegNames() const {
83 return llvm::ArrayRef(GCCAddlRegNames);
84}
85
86bool SystemZTargetInfo::validateAsmConstraint(
87 const char *&Name, TargetInfo::ConstraintInfo &Info) const {
88 switch (*Name) {
89 default:
90 return false;
91
92 case 'Z':
93 switch (Name[1]) {
94 default:
95 return false;
96 case 'Q': // Address with base and unsigned 12-bit displacement
97 case 'R': // Likewise, plus an index
98 case 'S': // Address with base and signed 20-bit displacement
99 case 'T': // Likewise, plus an index
100 break;
101 }
102 [[fallthrough]];
103 case 'a': // Address register
104 case 'd': // Data register (equivalent to 'r')
105 case 'f': // Floating-point register
106 case 'v': // Vector register
107 Info.setAllowsRegister();
108 return true;
109
110 case 'I': // Unsigned 8-bit constant
111 case 'J': // Unsigned 12-bit constant
112 case 'K': // Signed 16-bit constant
113 case 'L': // Signed 20-bit displacement (on all targets we support)
114 case 'M': // 0x7fffffff
115 return true;
116
117 case 'Q': // Memory with base and unsigned 12-bit displacement
118 case 'R': // Likewise, plus an index
119 case 'S': // Memory with base and signed 20-bit displacement
120 case 'T': // Likewise, plus an index
121 Info.setAllowsMemory();
122 return true;
123 case '@':
124 // CC condition changes.
125 if (StringRef(Name) == "@cc") {
126 Name += 2;
127 Info.setAllowsRegister();
128 // SystemZ has 2-bits CC, and hence Interval [0, 4).
129 Info.setOutputOperandBounds(Min: 0, Max: 4);
130 return true;
131 }
132 return false;
133 }
134}
135
136struct ISANameRevision {
137 llvm::StringLiteral Name;
138 int ISARevisionID;
139};
140static constexpr ISANameRevision ISARevisions[] = {
141 {.Name: {"arch8"}, .ISARevisionID: 8}, {.Name: {"z10"}, .ISARevisionID: 8},
142 {.Name: {"arch9"}, .ISARevisionID: 9}, {.Name: {"z196"}, .ISARevisionID: 9},
143 {.Name: {"arch10"}, .ISARevisionID: 10}, {.Name: {"zEC12"}, .ISARevisionID: 10},
144 {.Name: {"arch11"}, .ISARevisionID: 11}, {.Name: {"z13"}, .ISARevisionID: 11},
145 {.Name: {"arch12"}, .ISARevisionID: 12}, {.Name: {"z14"}, .ISARevisionID: 12},
146 {.Name: {"arch13"}, .ISARevisionID: 13}, {.Name: {"z15"}, .ISARevisionID: 13},
147 {.Name: {"arch14"}, .ISARevisionID: 14}, {.Name: {"z16"}, .ISARevisionID: 14},
148 {.Name: {"arch15"}, .ISARevisionID: 15}, {.Name: {"z17"}, .ISARevisionID: 15},
149};
150
151int SystemZTargetInfo::getISARevision(StringRef Name) const {
152 const auto Rev =
153 llvm::find_if(Range: ISARevisions, P: [Name](const ISANameRevision &CR) {
154 return CR.Name == Name;
155 });
156 if (Rev == std::end(arr: ISARevisions))
157 return -1;
158 return Rev->ISARevisionID;
159}
160
161void SystemZTargetInfo::fillValidCPUList(
162 SmallVectorImpl<StringRef> &Values) const {
163 for (const ISANameRevision &Rev : ISARevisions)
164 Values.push_back(Elt: Rev.Name);
165}
166
167bool SystemZTargetInfo::hasFeature(StringRef Feature) const {
168 return llvm::StringSwitch<bool>(Feature)
169 .Case(S: "systemz", Value: true)
170 .Case(S: "arch8", Value: ISARevision >= 8)
171 .Case(S: "arch9", Value: ISARevision >= 9)
172 .Case(S: "arch10", Value: ISARevision >= 10)
173 .Case(S: "arch11", Value: ISARevision >= 11)
174 .Case(S: "arch12", Value: ISARevision >= 12)
175 .Case(S: "arch13", Value: ISARevision >= 13)
176 .Case(S: "arch14", Value: ISARevision >= 14)
177 .Case(S: "arch15", Value: ISARevision >= 15)
178 .Case(S: "htm", Value: HasTransactionalExecution)
179 .Case(S: "vx", Value: HasVector)
180 .Default(Value: false);
181}
182
183unsigned SystemZTargetInfo::getMinGlobalAlign(uint64_t Size,
184 bool HasNonWeakDef) const {
185 // Don't enforce the minimum alignment on an external or weak symbol if
186 // -munaligned-symbols is passed.
187 if (UnalignedSymbols && !HasNonWeakDef)
188 return 0;
189
190 return MinGlobalAlign;
191}
192
193void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts,
194 MacroBuilder &Builder) const {
195 // Inline assembly supports SystemZ flag outputs.
196 Builder.defineMacro(Name: "__GCC_ASM_FLAG_OUTPUTS__");
197
198 Builder.defineMacro(Name: "__s390__");
199 Builder.defineMacro(Name: "__s390x__");
200 Builder.defineMacro(Name: "__zarch__");
201 Builder.defineMacro(Name: "__LONG_DOUBLE_128__");
202
203 Builder.defineMacro(Name: "__ARCH__", Value: Twine(ISARevision));
204
205 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
206 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
207 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
208 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
209
210 if (HasTransactionalExecution)
211 Builder.defineMacro(Name: "__HTM__");
212 if (HasVector)
213 Builder.defineMacro(Name: "__VX__");
214 if (Opts.ZVector)
215 Builder.defineMacro(Name: "__VEC__", Value: "10305");
216
217 /* Set __TARGET_LIB__ only if a value was given. If no value was given */
218 /* we rely on the LE headers to define __TARGET_LIB__. */
219 if (!getTriple().getOSVersion().empty()) {
220 llvm::VersionTuple V = getTriple().getOSVersion();
221 // Create string with form: 0xPVRRMMMM, where P=4
222 std::string Str("0x");
223 unsigned int Librel = 0x40000000;
224 Librel |= V.getMajor() << 24;
225 Librel |= V.getMinor().value_or(u: 1) << 16;
226 Librel |= V.getSubminor().value_or(u: 0);
227 Str += llvm::utohexstr(X: Librel);
228
229 Builder.defineMacro(Name: "__TARGET_LIB__", Value: Str);
230 }
231}
232
233llvm::SmallVector<Builtin::InfosShard>
234SystemZTargetInfo::getTargetBuiltins() const {
235 if (getTriple().isOSzOS())
236 return {{.Strings: &BuiltinStrings, .Infos: BuiltinInfos},
237 {.Strings: &BuiltinStrings, .Infos: PrefixedBuiltinInfos, .NamePrefix: "__builtin_s390_"},
238 {.Strings: &ZOS::BuiltinStrings, .Infos: ZOS::BuiltinInfos}};
239 return {{.Strings: &BuiltinStrings, .Infos: BuiltinInfos},
240 {.Strings: &BuiltinStrings, .Infos: PrefixedBuiltinInfos, .NamePrefix: "__builtin_s390_"}};
241}
242