| 1 | //===--- SystemZ.h - Declare SystemZ target feature support -----*- C++ -*-===// |
| 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 declares SystemZ TargetInfo objects. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H |
| 14 | #define LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H |
| 15 | |
| 16 | #include "clang/Basic/TargetInfo.h" |
| 17 | #include "clang/Basic/TargetOptions.h" |
| 18 | #include "llvm/Support/Compiler.h" |
| 19 | #include "llvm/TargetParser/Triple.h" |
| 20 | |
| 21 | namespace clang { |
| 22 | namespace targets { |
| 23 | |
| 24 | static const unsigned ZOSAddressMap[] = { |
| 25 | 0, // Default |
| 26 | 0, // opencl_global |
| 27 | 0, // opencl_local |
| 28 | 0, // opencl_constant |
| 29 | 0, // opencl_private |
| 30 | 0, // opencl_generic |
| 31 | 0, // opencl_global_device |
| 32 | 0, // opencl_global_host |
| 33 | 0, // cuda_device |
| 34 | 0, // cuda_constant |
| 35 | 0, // cuda_shared |
| 36 | 0, // sycl_global |
| 37 | 0, // sycl_global_device |
| 38 | 0, // sycl_global_host |
| 39 | 0, // sycl_local |
| 40 | 0, // sycl_private |
| 41 | 0, // ptr32_sptr |
| 42 | 1, // ptr32_uptr |
| 43 | 0, // ptr64 |
| 44 | 0, // hlsl_groupshared |
| 45 | 0, // hlsl_constant |
| 46 | 0, // hlsl_private |
| 47 | 0, // hlsl_device |
| 48 | 0, // hlsl_input |
| 49 | 0 // wasm_funcref |
| 50 | }; |
| 51 | |
| 52 | class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { |
| 53 | |
| 54 | static const char *const GCCRegNames[]; |
| 55 | int ISARevision; |
| 56 | bool HasTransactionalExecution; |
| 57 | bool HasVector; |
| 58 | bool SoftFloat; |
| 59 | bool UnalignedSymbols; |
| 60 | enum AddrSpace { ptr32 = 1 }; |
| 61 | |
| 62 | public: |
| 63 | SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &) |
| 64 | : TargetInfo(Triple), ISARevision(getISARevision(Name: "z10" )), |
| 65 | HasTransactionalExecution(false), HasVector(false), SoftFloat(false), |
| 66 | UnalignedSymbols(false) { |
| 67 | IntMaxType = SignedLong; |
| 68 | Int64Type = SignedLong; |
| 69 | IntWidth = IntAlign = 32; |
| 70 | LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; |
| 71 | Int128Align = 64; |
| 72 | PointerWidth = PointerAlign = 64; |
| 73 | LongDoubleWidth = 128; |
| 74 | LongDoubleAlign = 64; |
| 75 | LongDoubleFormat = &llvm::APFloat::IEEEquad(); |
| 76 | DefaultAlignForAttributeAligned = 64; |
| 77 | MinGlobalAlign = 16; |
| 78 | HasUnalignedAccess = true; |
| 79 | if (Triple.isOSzOS()) { |
| 80 | if (Triple.isArch64Bit()) { |
| 81 | AddrSpaceMap = &ZOSAddressMap; |
| 82 | } |
| 83 | TLSSupported = false; |
| 84 | // All vector types are default aligned on an 8-byte boundary, even if the |
| 85 | // vector facility is not available. That is different from Linux. |
| 86 | MaxVectorAlign = 64; |
| 87 | // Compared to Linux/ELF, the data layout differs only in some details: |
| 88 | // - name mangling is GOFF. |
| 89 | // - 32 bit pointers, either as default or special address space |
| 90 | resetDataLayout(DL: "E-m:l-p1:32:32-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-" |
| 91 | "a:8:16-n32:64" ); |
| 92 | } else { |
| 93 | TLSSupported = true; |
| 94 | resetDataLayout(DL: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64" |
| 95 | "-v128:64-a:8:16-n32:64" ); |
| 96 | } |
| 97 | MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 128; |
| 98 | |
| 99 | // True if the backend supports operations on the half LLVM IR type. |
| 100 | // By setting this to false, conversions will happen for _Float16 around |
| 101 | // a statement by default, with operations done in float. However, if |
| 102 | // -ffloat16-excess-precision=none is given, no conversions will be made |
| 103 | // and instead the backend will promote each half operation to float |
| 104 | // individually. |
| 105 | HasLegalHalfType = false; |
| 106 | // Support _Float16. |
| 107 | HasFloat16 = true; |
| 108 | |
| 109 | HasStrictFP = true; |
| 110 | } |
| 111 | |
| 112 | unsigned getMinGlobalAlign(uint64_t Size, bool HasNonWeakDef) const override; |
| 113 | |
| 114 | bool useFP16ConversionIntrinsics() const override { return false; } |
| 115 | |
| 116 | void getTargetDefines(const LangOptions &Opts, |
| 117 | MacroBuilder &Builder) const override; |
| 118 | |
| 119 | llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; |
| 120 | |
| 121 | ArrayRef<const char *> getGCCRegNames() const override; |
| 122 | |
| 123 | ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { |
| 124 | // No aliases. |
| 125 | return {}; |
| 126 | } |
| 127 | |
| 128 | ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override; |
| 129 | |
| 130 | bool isSPRegName(StringRef RegName) const override { |
| 131 | return RegName == "r15" ; |
| 132 | } |
| 133 | |
| 134 | bool validateAsmConstraint(const char *&Name, |
| 135 | TargetInfo::ConstraintInfo &info) const override; |
| 136 | |
| 137 | std::string convertConstraint(const char *&Constraint) const override { |
| 138 | switch (Constraint[0]) { |
| 139 | case 'p': // Keep 'p' constraint. |
| 140 | return std::string("p" ); |
| 141 | case 'Z': |
| 142 | switch (Constraint[1]) { |
| 143 | case 'Q': // Address with base and unsigned 12-bit displacement |
| 144 | case 'R': // Likewise, plus an index |
| 145 | case 'S': // Address with base and signed 20-bit displacement |
| 146 | case 'T': // Likewise, plus an index |
| 147 | // "^" hints llvm that this is a 2 letter constraint. |
| 148 | // "Constraint++" is used to promote the string iterator |
| 149 | // to the next constraint. |
| 150 | return std::string("^" ) + std::string(Constraint++, 2); |
| 151 | default: |
| 152 | break; |
| 153 | } |
| 154 | break; |
| 155 | default: |
| 156 | break; |
| 157 | } |
| 158 | return TargetInfo::convertConstraint(Constraint); |
| 159 | } |
| 160 | |
| 161 | std::string_view getClobbers() const override { |
| 162 | // FIXME: Is this really right? |
| 163 | return "" ; |
| 164 | } |
| 165 | |
| 166 | BuiltinVaListKind getBuiltinVaListKind() const override { |
| 167 | return TargetInfo::SystemZBuiltinVaList; |
| 168 | } |
| 169 | |
| 170 | int getISARevision(StringRef Name) const; |
| 171 | |
| 172 | bool isValidCPUName(StringRef Name) const override { |
| 173 | return getISARevision(Name) != -1; |
| 174 | } |
| 175 | |
| 176 | void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; |
| 177 | |
| 178 | bool isValidTuneCPUName(StringRef Name) const override { |
| 179 | return isValidCPUName(Name); |
| 180 | } |
| 181 | |
| 182 | void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override { |
| 183 | fillValidCPUList(Values); |
| 184 | } |
| 185 | |
| 186 | bool setCPU(const std::string &Name) override { |
| 187 | ISARevision = getISARevision(Name); |
| 188 | return ISARevision != -1; |
| 189 | } |
| 190 | |
| 191 | bool |
| 192 | initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, |
| 193 | StringRef CPU, |
| 194 | const std::vector<std::string> &FeaturesVec) const override { |
| 195 | int ISARevision = getISARevision(Name: CPU); |
| 196 | if (ISARevision >= 10) |
| 197 | Features["transactional-execution" ] = true; |
| 198 | if (ISARevision >= 11) |
| 199 | Features["vector" ] = true; |
| 200 | if (ISARevision >= 12) |
| 201 | Features["vector-enhancements-1" ] = true; |
| 202 | if (ISARevision >= 13) |
| 203 | Features["vector-enhancements-2" ] = true; |
| 204 | if (ISARevision >= 14) |
| 205 | Features["nnp-assist" ] = true; |
| 206 | if (ISARevision >= 15) { |
| 207 | Features["miscellaneous-extensions-4" ] = true; |
| 208 | Features["vector-enhancements-3" ] = true; |
| 209 | } |
| 210 | return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: FeaturesVec); |
| 211 | } |
| 212 | |
| 213 | bool handleTargetFeatures(std::vector<std::string> &Features, |
| 214 | DiagnosticsEngine &Diags) override { |
| 215 | HasTransactionalExecution = false; |
| 216 | HasVector = false; |
| 217 | SoftFloat = false; |
| 218 | UnalignedSymbols = false; |
| 219 | for (const auto &Feature : Features) { |
| 220 | if (Feature == "+transactional-execution" ) |
| 221 | HasTransactionalExecution = true; |
| 222 | else if (Feature == "+vector" ) |
| 223 | HasVector = true; |
| 224 | else if (Feature == "+soft-float" ) |
| 225 | SoftFloat = true; |
| 226 | else if (Feature == "+unaligned-symbols" ) |
| 227 | UnalignedSymbols = true; |
| 228 | } |
| 229 | HasVector &= !SoftFloat; |
| 230 | |
| 231 | // If we use the vector ABI, vector types are 64-bit aligned. The |
| 232 | // DataLayout string is always set to this alignment as it is not a |
| 233 | // requirement that it follows the alignment emitted by the front end. It |
| 234 | // is assumed generally that the Datalayout should reflect only the |
| 235 | // target triple and not any specific feature. |
| 236 | if (HasVector && !getTriple().isOSzOS()) |
| 237 | MaxVectorAlign = 64; |
| 238 | |
| 239 | return true; |
| 240 | } |
| 241 | |
| 242 | bool hasFeature(StringRef Feature) const override; |
| 243 | |
| 244 | CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { |
| 245 | switch (CC) { |
| 246 | case CC_C: |
| 247 | case CC_Swift: |
| 248 | case CC_DeviceKernel: |
| 249 | return CCCR_OK; |
| 250 | case CC_SwiftAsync: |
| 251 | return CCCR_Error; |
| 252 | default: |
| 253 | return CCCR_Warning; |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | StringRef getABI() const override { |
| 258 | if (HasVector) |
| 259 | return "vector" ; |
| 260 | return "" ; |
| 261 | } |
| 262 | |
| 263 | const char *getLongDoubleMangling() const override { return "g" ; } |
| 264 | |
| 265 | bool hasBitIntType() const override { return true; } |
| 266 | |
| 267 | int getEHDataRegisterNumber(unsigned RegNo) const override { |
| 268 | return RegNo < 4 ? 6 + RegNo : -1; |
| 269 | } |
| 270 | |
| 271 | bool hasSjLjLowering() const override { return true; } |
| 272 | |
| 273 | std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override { |
| 274 | return std::make_pair(x: 256, y: 256); |
| 275 | } |
| 276 | uint64_t getPointerWidthV(LangAS AddrSpace) const override { |
| 277 | return (getTriple().isOSzOS() && getTriple().isArch64Bit() && |
| 278 | getTargetAddressSpace(AS: AddrSpace) == ptr32) |
| 279 | ? 32 |
| 280 | : PointerWidth; |
| 281 | } |
| 282 | |
| 283 | uint64_t getPointerAlignV(LangAS AddrSpace) const override { |
| 284 | return getPointerWidthV(AddrSpace); |
| 285 | } |
| 286 | }; |
| 287 | } // namespace targets |
| 288 | } // namespace clang |
| 289 | #endif // LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H |
| 290 | |