1 //===- Target.h - target specific details -----------------------*- 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 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef FORTRAN_OPTMIZER_CODEGEN_TARGET_H 14 #define FORTRAN_OPTMIZER_CODEGEN_TARGET_H 15 16 #include "flang/Optimizer/Dialect/FIRType.h" 17 #include "flang/Optimizer/Dialect/Support/KindMapping.h" 18 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" 19 #include "mlir/IR/BuiltinTypes.h" 20 #include "llvm/TargetParser/Triple.h" 21 #include <memory> 22 #include <tuple> 23 #include <vector> 24 25 namespace mlir { 26 class DataLayout; 27 } 28 29 namespace fir { 30 31 namespace details { 32 /// Extra information about how to marshal an argument or return value that 33 /// modifies a signature per a particular ABI's calling convention. 34 /// Note: llvm::Attribute is not used directly, because its use depends on an 35 /// LLVMContext. 36 class Attributes { 37 public: 38 enum class IntegerExtension { None, Zero, Sign }; 39 40 Attributes(unsigned short alignment = 0, bool byval = false, 41 bool sret = false, bool append = false, 42 IntegerExtension intExt = IntegerExtension::None) 43 : alignment{alignment}, byval{byval}, sret{sret}, append{append}, 44 intExt{intExt} {} 45 46 unsigned getAlignment() const { return alignment; } 47 bool hasAlignment() const { return alignment != 0; } 48 bool isByVal() const { return byval; } 49 bool isSRet() const { return sret; } 50 bool isAppend() const { return append; } 51 bool isZeroExt() const { return intExt == IntegerExtension::Zero; } 52 bool isSignExt() const { return intExt == IntegerExtension::Sign; } 53 llvm::StringRef getIntExtensionAttrName() const; 54 55 private: 56 unsigned short alignment{}; 57 bool byval : 1; 58 bool sret : 1; 59 bool append : 1; 60 IntegerExtension intExt; 61 }; 62 63 } // namespace details 64 65 /// Some details of how to represent certain features depend on the target and 66 /// ABI that is being used. These specifics are captured here and guide the 67 /// lowering of FIR to LLVM-IR dialect. 68 class CodeGenSpecifics { 69 public: 70 using Attributes = details::Attributes; 71 using TypeAndAttr = std::tuple<mlir::Type, Attributes>; 72 using Marshalling = std::vector<TypeAndAttr>; 73 74 static std::unique_ptr<CodeGenSpecifics> 75 get(mlir::MLIRContext *ctx, llvm::Triple &&trp, KindMapping &&kindMap, 76 llvm::StringRef targetCPU, mlir::LLVM::TargetFeaturesAttr targetFeatures, 77 const mlir::DataLayout &dl); 78 79 static std::unique_ptr<CodeGenSpecifics> 80 get(mlir::MLIRContext *ctx, llvm::Triple &&trp, KindMapping &&kindMap, 81 llvm::StringRef targetCPU, mlir::LLVM::TargetFeaturesAttr targetFeatures, 82 const mlir::DataLayout &dl, llvm::StringRef tuneCPU); 83 84 static TypeAndAttr getTypeAndAttr(mlir::Type t) { return TypeAndAttr{t, {}}; } 85 86 CodeGenSpecifics(mlir::MLIRContext *ctx, llvm::Triple &&trp, 87 KindMapping &&kindMap, llvm::StringRef targetCPU, 88 mlir::LLVM::TargetFeaturesAttr targetFeatures, 89 const mlir::DataLayout &dl) 90 : context{*ctx}, triple{std::move(trp)}, kindMap{std::move(kindMap)}, 91 targetCPU{targetCPU}, targetFeatures{targetFeatures}, dataLayout{&dl}, 92 tuneCPU{""} {} 93 94 CodeGenSpecifics(mlir::MLIRContext *ctx, llvm::Triple &&trp, 95 KindMapping &&kindMap, llvm::StringRef targetCPU, 96 mlir::LLVM::TargetFeaturesAttr targetFeatures, 97 const mlir::DataLayout &dl, llvm::StringRef tuneCPU) 98 : context{*ctx}, triple{std::move(trp)}, kindMap{std::move(kindMap)}, 99 targetCPU{targetCPU}, targetFeatures{targetFeatures}, dataLayout{&dl}, 100 tuneCPU{tuneCPU} {} 101 102 CodeGenSpecifics() = delete; 103 virtual ~CodeGenSpecifics() {} 104 105 /// Type presentation of a `complex<ele>` type value in memory. 106 virtual mlir::Type complexMemoryType(mlir::Type eleTy) const = 0; 107 108 /// Type representation of a `complex<eleTy>` type argument when passed by 109 /// value. An argument value may need to be passed as a (safe) reference 110 /// argument. 111 virtual Marshalling complexArgumentType(mlir::Location loc, 112 mlir::Type eleTy) const = 0; 113 114 /// Type representation of a `complex<eleTy>` type return value. Such a return 115 /// value may need to be converted to a hidden reference argument. 116 virtual Marshalling complexReturnType(mlir::Location loc, 117 mlir::Type eleTy) const = 0; 118 119 /// Type presentation of a `boxchar<n>` type value in memory. 120 virtual mlir::Type boxcharMemoryType(mlir::Type eleTy) const = 0; 121 122 /// Type representation of a `fir.type<T>` type argument when passed by 123 /// value. It may have to be split into several arguments, or be passed 124 /// as a byval reference argument (on the stack). 125 virtual Marshalling 126 structArgumentType(mlir::Location loc, fir::RecordType recTy, 127 const Marshalling &previousArguments) const = 0; 128 129 /// Type representation of a `fir.type<T>` type argument when returned by 130 /// value. Such value may need to be converted to a hidden reference argument. 131 virtual Marshalling structReturnType(mlir::Location loc, 132 fir::RecordType eleTy) const = 0; 133 134 /// Type representation of a `boxchar<n>` type argument when passed by value. 135 /// An argument value may need to be passed as a (safe) reference argument. 136 virtual Marshalling boxcharArgumentType(mlir::Type eleTy) const = 0; 137 138 // Compute ABI rules for an integer argument of the given mlir::IntegerType 139 // \p argTy. Note that this methods is supposed to be called for 140 // arguments passed by value not via reference, e.g. the 'i1' argument here: 141 // declare i1 @_FortranAioOutputLogical(ptr, i1) 142 // 143 // \p loc is the location of the operation using/specifying the argument. 144 // 145 // Currently, the only supported marshalling is whether the argument 146 // should be zero or sign extended. 147 // 148 // The zero/sign extension is especially important to comply with the ABI 149 // used by C/C++ compiler that builds Fortran runtime. As in the above 150 // example the callee will expect the caller to zero extend the second 151 // argument up to the size of the C/C++'s 'int' type. 152 // The corresponding handling in clang is done in 153 // DefaultABIInfo::classifyArgumentType(), and the logic may brielfy 154 // be explained as some sort of extension is required if the integer 155 // type is shorter than the size of 'int' for the target. 156 // The related code is located in ASTContext::isPromotableIntegerType() 157 // and ABIInfo::isPromotableIntegerTypeForABI(). 158 // In particular, the latter returns 'true' for 'bool', several kinds 159 // of 'char', 'short', 'wchar' and enumerated types. 160 // The type of the extensions (zero or sign) depends on the signedness 161 // of the original language type. 162 // 163 // It is not clear how to handle signless integer types. 164 // From the point of Fortran-C interface all supported integer types 165 // seem to be signed except for CFI_type_Bool/bool that is supported 166 // via signless 'i1', but that is treated as unsigned type by clang 167 // (e.g. 'bool' arguments are using 'zeroext' ABI). 168 virtual Marshalling integerArgumentType(mlir::Location loc, 169 mlir::IntegerType argTy) const = 0; 170 171 // By default, integer argument and return values use the same 172 // zero/sign extension rules. 173 virtual Marshalling integerReturnType(mlir::Location loc, 174 mlir::IntegerType argTy) const = 0; 175 176 // Returns width in bits of C/C++ 'int' type size. 177 virtual unsigned char getCIntTypeWidth() const = 0; 178 179 llvm::StringRef getTargetCPU() const { return targetCPU; } 180 llvm::StringRef getTuneCPU() const { return tuneCPU; } 181 182 mlir::LLVM::TargetFeaturesAttr getTargetFeatures() const { 183 return targetFeatures; 184 } 185 186 const mlir::DataLayout &getDataLayout() const { 187 assert(dataLayout && "dataLayout must be set"); 188 return *dataLayout; 189 } 190 191 protected: 192 mlir::MLIRContext &context; 193 llvm::Triple triple; 194 KindMapping kindMap; 195 llvm::StringRef targetCPU; 196 mlir::LLVM::TargetFeaturesAttr targetFeatures; 197 const mlir::DataLayout *dataLayout = nullptr; 198 llvm::StringRef tuneCPU; 199 }; 200 201 } // namespace fir 202 203 #endif // FORTRAN_OPTMIZER_CODEGEN_TARGET_H 204