1 //===-- Target.cpp --------------------------------------------------------===// 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 #include "Target.h" 14 #include "flang/Optimizer/Dialect/FIRType.h" 15 #include "flang/Optimizer/Support/KindMapping.h" 16 #include "mlir/IR/BuiltinTypes.h" 17 #include "mlir/IR/TypeRange.h" 18 19 #define DEBUG_TYPE "flang-codegen-target" 20 21 using namespace fir; 22 23 // Reduce a REAL/float type to the floating point semantics. 24 static const llvm::fltSemantics &floatToSemantics(const KindMapping &kindMap, 25 mlir::Type type) { 26 assert(isa_real(type)); 27 if (auto ty = type.dyn_cast<fir::RealType>()) 28 return kindMap.getFloatSemantics(ty.getFKind()); 29 return type.cast<mlir::FloatType>().getFloatSemantics(); 30 } 31 32 namespace { 33 template <typename S> 34 struct GenericTarget : public CodeGenSpecifics { 35 using CodeGenSpecifics::CodeGenSpecifics; 36 using AT = CodeGenSpecifics::Attributes; 37 38 mlir::Type complexMemoryType(mlir::Type eleTy) const override { 39 assert(fir::isa_real(eleTy)); 40 // { t, t } struct of 2 eleTy 41 mlir::TypeRange range = {eleTy, eleTy}; 42 return mlir::TupleType::get(eleTy.getContext(), range); 43 } 44 45 mlir::Type boxcharMemoryType(mlir::Type eleTy) const override { 46 auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth); 47 auto ptrTy = fir::ReferenceType::get(eleTy); 48 // { t*, index } 49 mlir::TypeRange range = {ptrTy, idxTy}; 50 return mlir::TupleType::get(eleTy.getContext(), range); 51 } 52 53 Marshalling boxcharArgumentType(mlir::Type eleTy, bool sret) const override { 54 CodeGenSpecifics::Marshalling marshal; 55 auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth); 56 auto ptrTy = fir::ReferenceType::get(eleTy); 57 marshal.emplace_back(ptrTy, AT{}); 58 // Return value arguments are grouped as a pair. Others are passed in a 59 // split format with all pointers first (in the declared position) and all 60 // LEN arguments appended after all of the dummy arguments. 61 // NB: Other conventions/ABIs can/should be supported via options. 62 marshal.emplace_back(idxTy, AT{/*alignment=*/0, /*byval=*/false, 63 /*sret=*/sret, /*append=*/!sret}); 64 return marshal; 65 } 66 }; 67 } // namespace 68 69 //===----------------------------------------------------------------------===// 70 // i386 (x86 32 bit) linux target specifics. 71 //===----------------------------------------------------------------------===// 72 73 namespace { 74 struct TargetI386 : public GenericTarget<TargetI386> { 75 using GenericTarget::GenericTarget; 76 77 static constexpr int defaultWidth = 32; 78 79 CodeGenSpecifics::Marshalling 80 complexArgumentType(mlir::Type eleTy) const override { 81 assert(fir::isa_real(eleTy)); 82 CodeGenSpecifics::Marshalling marshal; 83 // { t, t } struct of 2 eleTy, byval, align 4 84 mlir::TypeRange range = {eleTy, eleTy}; 85 auto structTy = mlir::TupleType::get(eleTy.getContext(), range); 86 marshal.emplace_back(fir::ReferenceType::get(structTy), 87 AT{/*alignment=*/4, /*byval=*/true}); 88 return marshal; 89 } 90 91 CodeGenSpecifics::Marshalling 92 complexReturnType(mlir::Type eleTy) const override { 93 assert(fir::isa_real(eleTy)); 94 CodeGenSpecifics::Marshalling marshal; 95 const auto *sem = &floatToSemantics(kindMap, eleTy); 96 if (sem == &llvm::APFloat::IEEEsingle()) { 97 // i64 pack both floats in a 64-bit GPR 98 marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64), 99 AT{}); 100 } else if (sem == &llvm::APFloat::IEEEdouble()) { 101 // { t, t } struct of 2 eleTy, sret, align 4 102 mlir::TypeRange range = {eleTy, eleTy}; 103 auto structTy = mlir::TupleType::get(eleTy.getContext(), range); 104 marshal.emplace_back(fir::ReferenceType::get(structTy), 105 AT{/*alignment=*/4, /*byval=*/false, /*sret=*/true}); 106 } else { 107 llvm::report_fatal_error("complex for this precision not implemented"); 108 } 109 return marshal; 110 } 111 }; 112 } // namespace 113 114 //===----------------------------------------------------------------------===// 115 // x86_64 (x86 64 bit) linux target specifics. 116 //===----------------------------------------------------------------------===// 117 118 namespace { 119 struct TargetX86_64 : public GenericTarget<TargetX86_64> { 120 using GenericTarget::GenericTarget; 121 122 static constexpr int defaultWidth = 64; 123 124 CodeGenSpecifics::Marshalling 125 complexArgumentType(mlir::Type eleTy) const override { 126 CodeGenSpecifics::Marshalling marshal; 127 const auto *sem = &floatToSemantics(kindMap, eleTy); 128 if (sem == &llvm::APFloat::IEEEsingle()) { 129 // <2 x t> vector of 2 eleTy 130 marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{}); 131 } else if (sem == &llvm::APFloat::IEEEdouble()) { 132 // two distinct double arguments 133 marshal.emplace_back(eleTy, AT{}); 134 marshal.emplace_back(eleTy, AT{}); 135 } else { 136 llvm::report_fatal_error("complex for this precision not implemented"); 137 } 138 return marshal; 139 } 140 141 CodeGenSpecifics::Marshalling 142 complexReturnType(mlir::Type eleTy) const override { 143 CodeGenSpecifics::Marshalling marshal; 144 const auto *sem = &floatToSemantics(kindMap, eleTy); 145 if (sem == &llvm::APFloat::IEEEsingle()) { 146 // <2 x t> vector of 2 eleTy 147 marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{}); 148 } else if (sem == &llvm::APFloat::IEEEdouble()) { 149 // ( t, t ) tuple of 2 eleTy 150 mlir::TypeRange range = {eleTy, eleTy}; 151 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range), 152 AT{}); 153 } else { 154 llvm::report_fatal_error("complex for this precision not implemented"); 155 } 156 return marshal; 157 } 158 }; 159 } // namespace 160 161 //===----------------------------------------------------------------------===// 162 // AArch64 linux target specifics. 163 //===----------------------------------------------------------------------===// 164 165 namespace { 166 struct TargetAArch64 : public GenericTarget<TargetAArch64> { 167 using GenericTarget::GenericTarget; 168 169 static constexpr int defaultWidth = 64; 170 171 CodeGenSpecifics::Marshalling 172 complexArgumentType(mlir::Type eleTy) const override { 173 CodeGenSpecifics::Marshalling marshal; 174 const auto *sem = &floatToSemantics(kindMap, eleTy); 175 if (sem == &llvm::APFloat::IEEEsingle() || 176 sem == &llvm::APFloat::IEEEdouble()) { 177 // [2 x t] array of 2 eleTy 178 marshal.emplace_back(fir::SequenceType::get({2}, eleTy), AT{}); 179 } else { 180 llvm::report_fatal_error("complex for this precision not implemented"); 181 } 182 return marshal; 183 } 184 185 CodeGenSpecifics::Marshalling 186 complexReturnType(mlir::Type eleTy) const override { 187 CodeGenSpecifics::Marshalling marshal; 188 const auto *sem = &floatToSemantics(kindMap, eleTy); 189 if (sem == &llvm::APFloat::IEEEsingle() || 190 sem == &llvm::APFloat::IEEEdouble()) { 191 // ( t, t ) tuple of 2 eleTy 192 mlir::TypeRange range = {eleTy, eleTy}; 193 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range), 194 AT{}); 195 } else { 196 llvm::report_fatal_error("complex for this precision not implemented"); 197 } 198 return marshal; 199 } 200 }; 201 } // namespace 202 203 //===----------------------------------------------------------------------===// 204 // PPC64le linux target specifics. 205 //===----------------------------------------------------------------------===// 206 207 namespace { 208 struct TargetPPC64le : public GenericTarget<TargetPPC64le> { 209 using GenericTarget::GenericTarget; 210 211 static constexpr int defaultWidth = 64; 212 213 CodeGenSpecifics::Marshalling 214 complexArgumentType(mlir::Type eleTy) const override { 215 CodeGenSpecifics::Marshalling marshal; 216 // two distinct element type arguments (re, im) 217 marshal.emplace_back(eleTy, AT{}); 218 marshal.emplace_back(eleTy, AT{}); 219 return marshal; 220 } 221 222 CodeGenSpecifics::Marshalling 223 complexReturnType(mlir::Type eleTy) const override { 224 CodeGenSpecifics::Marshalling marshal; 225 // ( t, t ) tuple of 2 element type 226 mlir::TypeRange range = {eleTy, eleTy}; 227 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range), AT{}); 228 return marshal; 229 } 230 }; 231 } // namespace 232 233 // Instantiate the overloaded target instance based on the triple value. 234 // Currently, the implementation only instantiates `i386-unknown-linux-gnu`, 235 // `x86_64-unknown-linux-gnu`, aarch64 and ppc64le like triples. Other targets 236 // should be added to this file as needed. 237 std::unique_ptr<fir::CodeGenSpecifics> 238 fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp, 239 KindMapping &&kindMap) { 240 switch (trp.getArch()) { 241 default: 242 break; 243 case llvm::Triple::ArchType::x86: 244 switch (trp.getOS()) { 245 default: 246 break; 247 case llvm::Triple::OSType::Linux: 248 case llvm::Triple::OSType::Darwin: 249 return std::make_unique<TargetI386>(ctx, std::move(trp), 250 std::move(kindMap)); 251 } 252 break; 253 case llvm::Triple::ArchType::x86_64: 254 switch (trp.getOS()) { 255 default: 256 break; 257 case llvm::Triple::OSType::Linux: 258 case llvm::Triple::OSType::Darwin: 259 return std::make_unique<TargetX86_64>(ctx, std::move(trp), 260 std::move(kindMap)); 261 } 262 break; 263 case llvm::Triple::ArchType::aarch64: 264 switch (trp.getOS()) { 265 default: 266 break; 267 case llvm::Triple::OSType::Linux: 268 case llvm::Triple::OSType::Darwin: 269 return std::make_unique<TargetAArch64>(ctx, std::move(trp), 270 std::move(kindMap)); 271 } 272 break; 273 case llvm::Triple::ArchType::ppc64le: 274 switch (trp.getOS()) { 275 default: 276 break; 277 case llvm::Triple::OSType::Linux: 278 return std::make_unique<TargetPPC64le>(ctx, std::move(trp), 279 std::move(kindMap)); 280 } 281 break; 282 } 283 llvm::report_fatal_error("target not implemented"); 284 } 285