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 "flang/Optimizer/CodeGen/Target.h" 14 #include "flang/Optimizer/Builder/Todo.h" 15 #include "flang/Optimizer/Dialect/FIRType.h" 16 #include "flang/Optimizer/Dialect/Support/KindMapping.h" 17 #include "flang/Optimizer/Support/FatalError.h" 18 #include "flang/Optimizer/Support/Utils.h" 19 #include "mlir/IR/BuiltinTypes.h" 20 #include "mlir/IR/TypeRange.h" 21 #include "llvm/ADT/TypeSwitch.h" 22 23 #define DEBUG_TYPE "flang-codegen-target" 24 25 using namespace fir; 26 27 namespace fir::details { 28 llvm::StringRef Attributes::getIntExtensionAttrName() const { 29 // The attribute names are available via LLVM dialect interfaces 30 // like getZExtAttrName(), getByValAttrName(), etc., so we'd better 31 // use them than literals. 32 if (isZeroExt()) 33 return "llvm.zeroext"; 34 else if (isSignExt()) 35 return "llvm.signext"; 36 return {}; 37 } 38 } // namespace fir::details 39 40 // Reduce a REAL/float type to the floating point semantics. 41 static const llvm::fltSemantics &floatToSemantics(const KindMapping &kindMap, 42 mlir::Type type) { 43 assert(isa_real(type)); 44 if (auto ty = type.dyn_cast<fir::RealType>()) 45 return kindMap.getFloatSemantics(ty.getFKind()); 46 return type.cast<mlir::FloatType>().getFloatSemantics(); 47 } 48 49 static void typeTodo(const llvm::fltSemantics *sem, mlir::Location loc, 50 std::string context) { 51 if (sem == &llvm::APFloat::IEEEhalf()) { 52 TODO(loc, "COMPLEX(KIND=2): for " + context + " type"); 53 } else if (sem == &llvm::APFloat::BFloat()) { 54 TODO(loc, "COMPLEX(KIND=3): " + context + " type"); 55 } else if (sem == &llvm::APFloat::x87DoubleExtended()) { 56 TODO(loc, "COMPLEX(KIND=10): " + context + " type"); 57 } else { 58 TODO(loc, "complex for this precision for " + context + " type"); 59 } 60 } 61 62 /// Return the size and alignment of FIR types. 63 /// TODO: consider moving this to a DataLayoutTypeInterface implementation 64 /// for FIR types. It should first be ensured that it is OK to open the gate of 65 /// target dependent type size inquiries in lowering. It would also not be 66 /// straightforward given the need for a kind map that would need to be 67 /// converted in terms of mlir::DataLayoutEntryKey. 68 static std::pair<std::uint64_t, unsigned short> 69 getSizeAndAlignment(mlir::Location loc, mlir::Type ty, 70 const mlir::DataLayout &dl, 71 const fir::KindMapping &kindMap) { 72 if (mlir::isa<mlir::IntegerType, mlir::FloatType, mlir::ComplexType>(ty)) { 73 llvm::TypeSize size = dl.getTypeSize(ty); 74 unsigned short alignment = dl.getTypeABIAlignment(ty); 75 return {size, alignment}; 76 } 77 if (auto firCmplx = mlir::dyn_cast<fir::ComplexType>(ty)) { 78 auto [floatSize, floatAlign] = 79 getSizeAndAlignment(loc, firCmplx.getEleType(kindMap), dl, kindMap); 80 return {llvm::alignTo(floatSize, floatAlign) + floatSize, floatAlign}; 81 } 82 if (auto real = mlir::dyn_cast<fir::RealType>(ty)) 83 return getSizeAndAlignment(loc, real.getFloatType(kindMap), dl, kindMap); 84 85 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty)) { 86 auto [eleSize, eleAlign] = 87 getSizeAndAlignment(loc, seqTy.getEleTy(), dl, kindMap); 88 89 std::uint64_t size = 90 llvm::alignTo(eleSize, eleAlign) * seqTy.getConstantArraySize(); 91 return {size, eleAlign}; 92 } 93 if (auto recTy = mlir::dyn_cast<fir::RecordType>(ty)) { 94 std::uint64_t size = 0; 95 unsigned short align = 1; 96 for (auto component : recTy.getTypeList()) { 97 auto [compSize, compAlign] = 98 getSizeAndAlignment(loc, component.second, dl, kindMap); 99 size = 100 llvm::alignTo(size, compAlign) + llvm::alignTo(compSize, compAlign); 101 align = std::max(align, compAlign); 102 } 103 return {size, align}; 104 } 105 if (auto logical = mlir::dyn_cast<fir::LogicalType>(ty)) { 106 mlir::Type intTy = mlir::IntegerType::get( 107 logical.getContext(), kindMap.getLogicalBitsize(logical.getFKind())); 108 return getSizeAndAlignment(loc, intTy, dl, kindMap); 109 } 110 if (auto character = mlir::dyn_cast<fir::CharacterType>(ty)) { 111 mlir::Type intTy = mlir::IntegerType::get( 112 character.getContext(), 113 kindMap.getCharacterBitsize(character.getFKind())); 114 return getSizeAndAlignment(loc, intTy, dl, kindMap); 115 } 116 TODO(loc, "computing size of a component"); 117 } 118 119 namespace { 120 template <typename S> 121 struct GenericTarget : public CodeGenSpecifics { 122 using CodeGenSpecifics::CodeGenSpecifics; 123 using AT = CodeGenSpecifics::Attributes; 124 125 mlir::Type complexMemoryType(mlir::Type eleTy) const override { 126 assert(fir::isa_real(eleTy)); 127 // Use a type that will be translated into LLVM as: 128 // { t, t } struct of 2 eleTy 129 return mlir::TupleType::get(eleTy.getContext(), 130 mlir::TypeRange{eleTy, eleTy}); 131 } 132 133 mlir::Type boxcharMemoryType(mlir::Type eleTy) const override { 134 auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth); 135 auto ptrTy = fir::ReferenceType::get(eleTy); 136 // Use a type that will be translated into LLVM as: 137 // { t*, index } 138 return mlir::TupleType::get(eleTy.getContext(), 139 mlir::TypeRange{ptrTy, idxTy}); 140 } 141 142 Marshalling boxcharArgumentType(mlir::Type eleTy, bool sret) const override { 143 CodeGenSpecifics::Marshalling marshal; 144 auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth); 145 auto ptrTy = fir::ReferenceType::get(eleTy); 146 marshal.emplace_back(ptrTy, AT{}); 147 // Return value arguments are grouped as a pair. Others are passed in a 148 // split format with all pointers first (in the declared position) and all 149 // LEN arguments appended after all of the dummy arguments. 150 // NB: Other conventions/ABIs can/should be supported via options. 151 marshal.emplace_back(idxTy, AT{/*alignment=*/0, /*byval=*/false, 152 /*sret=*/sret, /*append=*/!sret}); 153 return marshal; 154 } 155 156 CodeGenSpecifics::Marshalling 157 structArgumentType(mlir::Location loc, fir::RecordType, 158 const Marshalling &) const override { 159 TODO(loc, "passing VALUE BIND(C) derived type for this target"); 160 } 161 162 CodeGenSpecifics::Marshalling 163 integerArgumentType(mlir::Location loc, 164 mlir::IntegerType argTy) const override { 165 CodeGenSpecifics::Marshalling marshal; 166 AT::IntegerExtension intExt = AT::IntegerExtension::None; 167 if (argTy.getWidth() < getCIntTypeWidth()) { 168 // isSigned() and isUnsigned() branches below are dead code currently. 169 // If needed, we can generate calls with signed/unsigned argument types 170 // to more precisely match C side (e.g. for Fortran runtime functions 171 // with 'unsigned short' arguments). 172 if (argTy.isSigned()) 173 intExt = AT::IntegerExtension::Sign; 174 else if (argTy.isUnsigned()) 175 intExt = AT::IntegerExtension::Zero; 176 else if (argTy.isSignless()) { 177 // Zero extend for 'i1' and sign extend for other types. 178 if (argTy.getWidth() == 1) 179 intExt = AT::IntegerExtension::Zero; 180 else 181 intExt = AT::IntegerExtension::Sign; 182 } 183 } 184 185 marshal.emplace_back(argTy, AT{/*alignment=*/0, /*byval=*/false, 186 /*sret=*/false, /*append=*/false, 187 /*intExt=*/intExt}); 188 return marshal; 189 } 190 191 CodeGenSpecifics::Marshalling 192 integerReturnType(mlir::Location loc, 193 mlir::IntegerType argTy) const override { 194 return integerArgumentType(loc, argTy); 195 } 196 197 // Width of 'int' type is 32-bits for almost all targets, except 198 // for AVR and MSP430 (see TargetInfo initializations 199 // in clang/lib/Basic/Targets). 200 unsigned char getCIntTypeWidth() const override { return 32; } 201 }; 202 } // namespace 203 204 //===----------------------------------------------------------------------===// 205 // i386 (x86 32 bit) linux target specifics. 206 //===----------------------------------------------------------------------===// 207 208 namespace { 209 struct TargetI386 : public GenericTarget<TargetI386> { 210 using GenericTarget::GenericTarget; 211 212 static constexpr int defaultWidth = 32; 213 214 CodeGenSpecifics::Marshalling 215 complexArgumentType(mlir::Location, mlir::Type eleTy) const override { 216 assert(fir::isa_real(eleTy)); 217 CodeGenSpecifics::Marshalling marshal; 218 // Use a type that will be translated into LLVM as: 219 // { t, t } struct of 2 eleTy, byval, align 4 220 auto structTy = 221 mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}); 222 marshal.emplace_back(fir::ReferenceType::get(structTy), 223 AT{/*alignment=*/4, /*byval=*/true}); 224 return marshal; 225 } 226 227 CodeGenSpecifics::Marshalling 228 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 229 assert(fir::isa_real(eleTy)); 230 CodeGenSpecifics::Marshalling marshal; 231 const auto *sem = &floatToSemantics(kindMap, eleTy); 232 if (sem == &llvm::APFloat::IEEEsingle()) { 233 // i64 pack both floats in a 64-bit GPR 234 marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64), 235 AT{}); 236 } else if (sem == &llvm::APFloat::IEEEdouble()) { 237 // Use a type that will be translated into LLVM as: 238 // { t, t } struct of 2 eleTy, sret, align 4 239 auto structTy = mlir::TupleType::get(eleTy.getContext(), 240 mlir::TypeRange{eleTy, eleTy}); 241 marshal.emplace_back(fir::ReferenceType::get(structTy), 242 AT{/*alignment=*/4, /*byval=*/false, /*sret=*/true}); 243 } else { 244 typeTodo(sem, loc, "return"); 245 } 246 return marshal; 247 } 248 }; 249 } // namespace 250 251 //===----------------------------------------------------------------------===// 252 // i386 (x86 32 bit) Windows target specifics. 253 //===----------------------------------------------------------------------===// 254 255 namespace { 256 struct TargetI386Win : public GenericTarget<TargetI386Win> { 257 using GenericTarget::GenericTarget; 258 259 static constexpr int defaultWidth = 32; 260 261 CodeGenSpecifics::Marshalling 262 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 263 CodeGenSpecifics::Marshalling marshal; 264 // Use a type that will be translated into LLVM as: 265 // { t, t } struct of 2 eleTy, byval, align 4 266 auto structTy = 267 mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}); 268 marshal.emplace_back(fir::ReferenceType::get(structTy), 269 AT{/*align=*/4, /*byval=*/true}); 270 return marshal; 271 } 272 273 CodeGenSpecifics::Marshalling 274 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 275 CodeGenSpecifics::Marshalling marshal; 276 const auto *sem = &floatToSemantics(kindMap, eleTy); 277 if (sem == &llvm::APFloat::IEEEsingle()) { 278 // i64 pack both floats in a 64-bit GPR 279 marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64), 280 AT{}); 281 } else if (sem == &llvm::APFloat::IEEEdouble()) { 282 // Use a type that will be translated into LLVM as: 283 // { double, double } struct of 2 double, sret, align 8 284 marshal.emplace_back( 285 fir::ReferenceType::get(mlir::TupleType::get( 286 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 287 AT{/*align=*/8, /*byval=*/false, /*sret=*/true}); 288 } else if (sem == &llvm::APFloat::IEEEquad()) { 289 // Use a type that will be translated into LLVM as: 290 // { fp128, fp128 } struct of 2 fp128, sret, align 16 291 marshal.emplace_back( 292 fir::ReferenceType::get(mlir::TupleType::get( 293 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 294 AT{/*align=*/16, /*byval=*/false, /*sret=*/true}); 295 } else if (sem == &llvm::APFloat::x87DoubleExtended()) { 296 // Use a type that will be translated into LLVM as: 297 // { x86_fp80, x86_fp80 } struct of 2 x86_fp80, sret, align 4 298 marshal.emplace_back( 299 fir::ReferenceType::get(mlir::TupleType::get( 300 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 301 AT{/*align=*/4, /*byval=*/false, /*sret=*/true}); 302 } else { 303 typeTodo(sem, loc, "return"); 304 } 305 return marshal; 306 } 307 }; 308 } // namespace 309 310 //===----------------------------------------------------------------------===// 311 // x86_64 (x86 64 bit) linux target specifics. 312 //===----------------------------------------------------------------------===// 313 314 namespace { 315 struct TargetX86_64 : public GenericTarget<TargetX86_64> { 316 using GenericTarget::GenericTarget; 317 318 static constexpr int defaultWidth = 64; 319 320 CodeGenSpecifics::Marshalling 321 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 322 CodeGenSpecifics::Marshalling marshal; 323 const auto *sem = &floatToSemantics(kindMap, eleTy); 324 if (sem == &llvm::APFloat::IEEEsingle()) { 325 // <2 x t> vector of 2 eleTy 326 marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{}); 327 } else if (sem == &llvm::APFloat::IEEEdouble()) { 328 // FIXME: In case of SSE register exhaustion, the ABI here may be 329 // incorrect since LLVM may pass the real via register and the imaginary 330 // part via the stack while the ABI it should be all in register or all 331 // in memory. Register occupancy must be analyzed here. 332 // two distinct double arguments 333 marshal.emplace_back(eleTy, AT{}); 334 marshal.emplace_back(eleTy, AT{}); 335 } else if (sem == &llvm::APFloat::x87DoubleExtended()) { 336 // Use a type that will be translated into LLVM as: 337 // { x86_fp80, x86_fp80 } struct of 2 fp128, byval, align 16 338 marshal.emplace_back( 339 fir::ReferenceType::get(mlir::TupleType::get( 340 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 341 AT{/*align=*/16, /*byval=*/true}); 342 } else if (sem == &llvm::APFloat::IEEEquad()) { 343 // Use a type that will be translated into LLVM as: 344 // { fp128, fp128 } struct of 2 fp128, byval, align 16 345 marshal.emplace_back( 346 fir::ReferenceType::get(mlir::TupleType::get( 347 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 348 AT{/*align=*/16, /*byval=*/true}); 349 } else { 350 typeTodo(sem, loc, "argument"); 351 } 352 return marshal; 353 } 354 355 CodeGenSpecifics::Marshalling 356 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 357 CodeGenSpecifics::Marshalling marshal; 358 const auto *sem = &floatToSemantics(kindMap, eleTy); 359 if (sem == &llvm::APFloat::IEEEsingle()) { 360 // <2 x t> vector of 2 eleTy 361 marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{}); 362 } else if (sem == &llvm::APFloat::IEEEdouble()) { 363 // Use a type that will be translated into LLVM as: 364 // { double, double } struct of 2 double 365 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), 366 mlir::TypeRange{eleTy, eleTy}), 367 AT{}); 368 } else if (sem == &llvm::APFloat::x87DoubleExtended()) { 369 // { x86_fp80, x86_fp80 } 370 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), 371 mlir::TypeRange{eleTy, eleTy}), 372 AT{}); 373 } else if (sem == &llvm::APFloat::IEEEquad()) { 374 // Use a type that will be translated into LLVM as: 375 // { fp128, fp128 } struct of 2 fp128, sret, align 16 376 marshal.emplace_back( 377 fir::ReferenceType::get(mlir::TupleType::get( 378 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 379 AT{/*align=*/16, /*byval=*/false, /*sret=*/true}); 380 } else { 381 typeTodo(sem, loc, "return"); 382 } 383 return marshal; 384 } 385 386 /// X86-64 argument classes from System V ABI version 1.0 section 3.2.3. 387 enum ArgClass { 388 Integer = 0, 389 SSE, 390 SSEUp, 391 X87, 392 X87Up, 393 ComplexX87, 394 NoClass, 395 Memory 396 }; 397 398 /// Classify an argument type or a field of an aggregate type argument. 399 /// See System V ABI version 1.0 section 3.2.3. 400 /// The Lo and Hi class are set to the class of the lower eight eightbytes 401 /// and upper eight eightbytes on return. 402 /// If this is called for an aggregate field, the caller is responsible to 403 /// do the post-merge. 404 void classify(mlir::Location loc, mlir::Type type, std::uint64_t byteOffset, 405 ArgClass &Lo, ArgClass &Hi) const { 406 Hi = Lo = ArgClass::NoClass; 407 ArgClass ¤t = byteOffset < 8 ? Lo : Hi; 408 // System V AMD64 ABI 3.2.3. version 1.0 409 llvm::TypeSwitch<mlir::Type>(type) 410 .template Case<mlir::IntegerType>([&](mlir::IntegerType intTy) { 411 if (intTy.getWidth() == 128) 412 Hi = Lo = ArgClass::Integer; 413 else 414 current = ArgClass::Integer; 415 }) 416 .template Case<mlir::FloatType, fir::RealType>([&](mlir::Type floatTy) { 417 const auto *sem = &floatToSemantics(kindMap, floatTy); 418 if (sem == &llvm::APFloat::x87DoubleExtended()) { 419 Lo = ArgClass::X87; 420 Hi = ArgClass::X87Up; 421 } else if (sem == &llvm::APFloat::IEEEquad()) { 422 Lo = ArgClass::SSE; 423 Hi = ArgClass::SSEUp; 424 } else { 425 current = ArgClass::SSE; 426 } 427 }) 428 .template Case<fir::ComplexType>([&](fir::ComplexType cmplx) { 429 const auto *sem = &floatToSemantics(kindMap, cmplx.getElementType()); 430 if (sem == &llvm::APFloat::x87DoubleExtended()) { 431 current = ArgClass::ComplexX87; 432 } else { 433 fir::SequenceType::Shape shape{2}; 434 classifyArray(loc, 435 fir::SequenceType::get(shape, cmplx.getElementType()), 436 byteOffset, Lo, Hi); 437 } 438 }) 439 .template Case<fir::LogicalType>([&](fir::LogicalType logical) { 440 if (kindMap.getLogicalBitsize(logical.getFKind()) == 128) 441 Hi = Lo = ArgClass::Integer; 442 else 443 current = ArgClass::Integer; 444 }) 445 .template Case<fir::CharacterType>( 446 [&](fir::CharacterType character) { current = ArgClass::Integer; }) 447 .template Case<fir::SequenceType>([&](fir::SequenceType seqTy) { 448 // Array component. 449 classifyArray(loc, seqTy, byteOffset, Lo, Hi); 450 }) 451 .template Case<fir::RecordType>([&](fir::RecordType recTy) { 452 // Component that is a derived type. 453 classifyStruct(loc, recTy, byteOffset, Lo, Hi); 454 }) 455 .template Case<fir::VectorType>([&](fir::VectorType vecTy) { 456 // Previously marshalled SSE eight byte for a previous struct 457 // argument. 458 auto *sem = fir::isa_real(vecTy.getEleTy()) 459 ? &floatToSemantics(kindMap, vecTy.getEleTy()) 460 : nullptr; 461 // Not expecting to hit this todo in standard code (it would 462 // require some vector type extension). 463 if (!(sem == &llvm::APFloat::IEEEsingle() && vecTy.getLen() <= 2) && 464 !(sem == &llvm::APFloat::IEEEhalf() && vecTy.getLen() <= 4)) 465 TODO(loc, "passing vector argument to C by value"); 466 current = SSE; 467 }) 468 .Default([&](mlir::Type ty) { 469 if (fir::conformsWithPassByRef(ty)) 470 current = ArgClass::Integer; // Pointers. 471 else 472 TODO(loc, "unsupported component type for BIND(C), VALUE derived " 473 "type argument"); 474 }); 475 } 476 477 // Classify fields of a derived type starting at \p offset. Returns the new 478 // offset. Post-merge is left to the caller. 479 std::uint64_t classifyStruct(mlir::Location loc, fir::RecordType recTy, 480 std::uint64_t byteOffset, ArgClass &Lo, 481 ArgClass &Hi) const { 482 for (auto component : recTy.getTypeList()) { 483 if (byteOffset > 16) { 484 // See 3.2.3 p. 1 and note 15. Note that when the offset is bigger 485 // than 16 bytes here, it is not a single _m256 and or _m512 entity 486 // that could fit in AVX registers. 487 Lo = Hi = ArgClass::Memory; 488 return byteOffset; 489 } 490 mlir::Type compType = component.second; 491 auto [compSize, compAlign] = 492 getSizeAndAlignment(loc, compType, getDataLayout(), kindMap); 493 byteOffset = llvm::alignTo(byteOffset, compAlign); 494 ArgClass LoComp, HiComp; 495 classify(loc, compType, byteOffset, LoComp, HiComp); 496 Lo = mergeClass(Lo, LoComp); 497 Hi = mergeClass(Hi, HiComp); 498 byteOffset = byteOffset + llvm::alignTo(compSize, compAlign); 499 if (Lo == ArgClass::Memory || Hi == ArgClass::Memory) 500 return byteOffset; 501 } 502 return byteOffset; 503 } 504 505 // Classify fields of a constant size array type starting at \p offset. 506 // Returns the new offset. Post-merge is left to the caller. 507 void classifyArray(mlir::Location loc, fir::SequenceType seqTy, 508 std::uint64_t byteOffset, ArgClass &Lo, 509 ArgClass &Hi) const { 510 mlir::Type eleTy = seqTy.getEleTy(); 511 const std::uint64_t arraySize = seqTy.getConstantArraySize(); 512 auto [eleSize, eleAlign] = 513 getSizeAndAlignment(loc, eleTy, getDataLayout(), kindMap); 514 std::uint64_t eleStorageSize = llvm::alignTo(eleSize, eleAlign); 515 for (std::uint64_t i = 0; i < arraySize; ++i) { 516 byteOffset = llvm::alignTo(byteOffset, eleAlign); 517 if (byteOffset > 16) { 518 // See 3.2.3 p. 1 and note 15. Same as in classifyStruct. 519 Lo = Hi = ArgClass::Memory; 520 return; 521 } 522 ArgClass LoComp, HiComp; 523 classify(loc, eleTy, byteOffset, LoComp, HiComp); 524 Lo = mergeClass(Lo, LoComp); 525 Hi = mergeClass(Hi, HiComp); 526 byteOffset = byteOffset + eleStorageSize; 527 if (Lo == ArgClass::Memory || Hi == ArgClass::Memory) 528 return; 529 } 530 } 531 532 // Goes through the previously marshalled arguments and count the 533 // register occupancy to check if there are enough registers left. 534 bool hasEnoughRegisters(mlir::Location loc, int neededIntRegisters, 535 int neededSSERegisters, 536 const Marshalling &previousArguments) const { 537 int availIntRegisters = 6; 538 int availSSERegisters = 8; 539 for (auto typeAndAttr : previousArguments) { 540 const auto &attr = std::get<Attributes>(typeAndAttr); 541 if (attr.isByVal()) 542 continue; // Previous argument passed on the stack. 543 ArgClass Lo, Hi; 544 Lo = Hi = ArgClass::NoClass; 545 classify(loc, std::get<mlir::Type>(typeAndAttr), 0, Lo, Hi); 546 // post merge is not needed here since previous aggregate arguments 547 // were marshalled into simpler arguments. 548 if (Lo == ArgClass::Integer) 549 --availIntRegisters; 550 else if (Lo == SSE) 551 --availSSERegisters; 552 if (Hi == ArgClass::Integer) 553 --availIntRegisters; 554 else if (Hi == ArgClass::SSE) 555 --availSSERegisters; 556 } 557 return availSSERegisters >= neededSSERegisters && 558 availIntRegisters >= neededIntRegisters; 559 } 560 561 /// Argument class merging as described in System V ABI 3.2.3 point 4. 562 ArgClass mergeClass(ArgClass accum, ArgClass field) const { 563 assert((accum != ArgClass::Memory && accum != ArgClass::ComplexX87) && 564 "Invalid accumulated classification during merge."); 565 if (accum == field || field == NoClass) 566 return accum; 567 if (field == ArgClass::Memory) 568 return ArgClass::Memory; 569 if (accum == NoClass) 570 return field; 571 if (accum == Integer || field == Integer) 572 return ArgClass::Integer; 573 if (field == ArgClass::X87 || field == ArgClass::X87Up || 574 field == ArgClass::ComplexX87 || accum == ArgClass::X87 || 575 accum == ArgClass::X87Up) 576 return Memory; 577 return SSE; 578 } 579 580 /// Argument class post merging as described in System V ABI 3.2.3 point 5. 581 void postMerge(std::uint64_t byteSize, ArgClass &Lo, ArgClass &Hi) const { 582 if (Hi == ArgClass::Memory) 583 Lo = ArgClass::Memory; 584 if (Hi == ArgClass::X87Up && Lo != ArgClass::X87) 585 Lo = ArgClass::Memory; 586 if (byteSize > 16 && (Lo != ArgClass::SSE || Hi != ArgClass::SSEUp)) 587 Lo = ArgClass::Memory; 588 if (Hi == ArgClass::SSEUp && Lo != ArgClass::SSE) 589 Hi = SSE; 590 } 591 592 /// When \p recTy is a one field record type that can be passed 593 /// like the field on its own, returns the field type. Returns 594 /// a null type otherwise. 595 mlir::Type passAsFieldIfOneFieldStruct(fir::RecordType recTy) const { 596 auto typeList = recTy.getTypeList(); 597 if (typeList.size() != 1) 598 return {}; 599 mlir::Type fieldType = typeList[0].second; 600 if (mlir::isa<mlir::FloatType, mlir::IntegerType, fir::RealType, 601 fir::CharacterType, fir::LogicalType>(fieldType)) 602 return fieldType; 603 // Complex field that needs to be split, or array. 604 return {}; 605 } 606 607 /// Marshal a derived type passed by value like a C struct. 608 CodeGenSpecifics::Marshalling 609 structArgumentType(mlir::Location loc, fir::RecordType recTy, 610 const Marshalling &previousArguments) const override { 611 std::uint64_t byteOffset = 0; 612 ArgClass Lo, Hi; 613 Lo = Hi = ArgClass::NoClass; 614 byteOffset = classifyStruct(loc, recTy, byteOffset, Lo, Hi); 615 postMerge(byteOffset, Lo, Hi); 616 if (Lo == ArgClass::Memory || Lo == ArgClass::X87 || 617 Lo == ArgClass::ComplexX87) 618 return passOnTheStack(loc, recTy); 619 int neededIntRegisters = 0; 620 int neededSSERegisters = 0; 621 if (Lo == ArgClass::SSE) 622 ++neededSSERegisters; 623 else if (Lo == ArgClass::Integer) 624 ++neededIntRegisters; 625 if (Hi == ArgClass::SSE) 626 ++neededSSERegisters; 627 else if (Hi == ArgClass::Integer) 628 ++neededIntRegisters; 629 // C struct should not be split into LLVM registers if LLVM codegen is not 630 // able to later assign actual registers to all of them (struct passing is 631 // all in registers or all on the stack). 632 if (!hasEnoughRegisters(loc, neededIntRegisters, neededSSERegisters, 633 previousArguments)) 634 return passOnTheStack(loc, recTy); 635 636 if (auto fieldType = passAsFieldIfOneFieldStruct(recTy)) { 637 CodeGenSpecifics::Marshalling marshal; 638 marshal.emplace_back(fieldType, AT{}); 639 return marshal; 640 } 641 // TODO, marshal the struct with several components, or with a single 642 // complex, array, or derived type component into registers. 643 TODO(loc, "passing BIND(C), VALUE derived type in registers on X86-64"); 644 } 645 646 /// Marshal an argument that must be passed on the stack. 647 CodeGenSpecifics::Marshalling passOnTheStack(mlir::Location loc, 648 mlir::Type ty) const { 649 CodeGenSpecifics::Marshalling marshal; 650 auto sizeAndAlign = getSizeAndAlignment(loc, ty, getDataLayout(), kindMap); 651 // The stack is always 8 byte aligned (note 14 in 3.2.3). 652 unsigned short align = 653 std::max(sizeAndAlign.second, static_cast<unsigned short>(8)); 654 marshal.emplace_back(fir::ReferenceType::get(ty), 655 AT{align, /*byval=*/true, /*sret=*/false}); 656 return marshal; 657 } 658 }; 659 } // namespace 660 661 //===----------------------------------------------------------------------===// 662 // x86_64 (x86 64 bit) Windows target specifics. 663 //===----------------------------------------------------------------------===// 664 665 namespace { 666 struct TargetX86_64Win : public GenericTarget<TargetX86_64Win> { 667 using GenericTarget::GenericTarget; 668 669 static constexpr int defaultWidth = 64; 670 671 CodeGenSpecifics::Marshalling 672 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 673 CodeGenSpecifics::Marshalling marshal; 674 const auto *sem = &floatToSemantics(kindMap, eleTy); 675 if (sem == &llvm::APFloat::IEEEsingle()) { 676 // i64 pack both floats in a 64-bit GPR 677 marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64), 678 AT{}); 679 } else if (sem == &llvm::APFloat::IEEEdouble()) { 680 // Use a type that will be translated into LLVM as: 681 // { double, double } struct of 2 double, byval, align 8 682 marshal.emplace_back( 683 fir::ReferenceType::get(mlir::TupleType::get( 684 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 685 AT{/*align=*/8, /*byval=*/true}); 686 } else if (sem == &llvm::APFloat::IEEEquad() || 687 sem == &llvm::APFloat::x87DoubleExtended()) { 688 // Use a type that will be translated into LLVM as: 689 // { t, t } struct of 2 eleTy, byval, align 16 690 marshal.emplace_back( 691 fir::ReferenceType::get(mlir::TupleType::get( 692 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 693 AT{/*align=*/16, /*byval=*/true}); 694 } else { 695 typeTodo(sem, loc, "argument"); 696 } 697 return marshal; 698 } 699 700 CodeGenSpecifics::Marshalling 701 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 702 CodeGenSpecifics::Marshalling marshal; 703 const auto *sem = &floatToSemantics(kindMap, eleTy); 704 if (sem == &llvm::APFloat::IEEEsingle()) { 705 // i64 pack both floats in a 64-bit GPR 706 marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64), 707 AT{}); 708 } else if (sem == &llvm::APFloat::IEEEdouble()) { 709 // Use a type that will be translated into LLVM as: 710 // { double, double } struct of 2 double, sret, align 8 711 marshal.emplace_back( 712 fir::ReferenceType::get(mlir::TupleType::get( 713 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 714 AT{/*align=*/8, /*byval=*/false, /*sret=*/true}); 715 } else if (sem == &llvm::APFloat::IEEEquad() || 716 sem == &llvm::APFloat::x87DoubleExtended()) { 717 // Use a type that will be translated into LLVM as: 718 // { t, t } struct of 2 eleTy, sret, align 16 719 marshal.emplace_back( 720 fir::ReferenceType::get(mlir::TupleType::get( 721 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 722 AT{/*align=*/16, /*byval=*/false, /*sret=*/true}); 723 } else { 724 typeTodo(sem, loc, "return"); 725 } 726 return marshal; 727 } 728 }; 729 } // namespace 730 731 //===----------------------------------------------------------------------===// 732 // AArch64 linux target specifics. 733 //===----------------------------------------------------------------------===// 734 735 namespace { 736 struct TargetAArch64 : public GenericTarget<TargetAArch64> { 737 using GenericTarget::GenericTarget; 738 739 static constexpr int defaultWidth = 64; 740 741 CodeGenSpecifics::Marshalling 742 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 743 CodeGenSpecifics::Marshalling marshal; 744 const auto *sem = &floatToSemantics(kindMap, eleTy); 745 if (sem == &llvm::APFloat::IEEEsingle() || 746 sem == &llvm::APFloat::IEEEdouble()) { 747 // [2 x t] array of 2 eleTy 748 marshal.emplace_back(fir::SequenceType::get({2}, eleTy), AT{}); 749 } else { 750 typeTodo(sem, loc, "argument"); 751 } 752 return marshal; 753 } 754 755 CodeGenSpecifics::Marshalling 756 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 757 CodeGenSpecifics::Marshalling marshal; 758 const auto *sem = &floatToSemantics(kindMap, eleTy); 759 if (sem == &llvm::APFloat::IEEEsingle() || 760 sem == &llvm::APFloat::IEEEdouble()) { 761 // Use a type that will be translated into LLVM as: 762 // { t, t } struct of 2 eleTy 763 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), 764 mlir::TypeRange{eleTy, eleTy}), 765 AT{}); 766 } else { 767 typeTodo(sem, loc, "return"); 768 } 769 return marshal; 770 } 771 }; 772 } // namespace 773 774 //===----------------------------------------------------------------------===// 775 // PPC64 (AIX 64 bit) target specifics. 776 //===----------------------------------------------------------------------===// 777 778 namespace { 779 struct TargetPPC64 : public GenericTarget<TargetPPC64> { 780 using GenericTarget::GenericTarget; 781 782 static constexpr int defaultWidth = 64; 783 784 CodeGenSpecifics::Marshalling 785 complexArgumentType(mlir::Location, mlir::Type eleTy) const override { 786 CodeGenSpecifics::Marshalling marshal; 787 // two distinct element type arguments (re, im) 788 marshal.emplace_back(eleTy, AT{}); 789 marshal.emplace_back(eleTy, AT{}); 790 return marshal; 791 } 792 793 CodeGenSpecifics::Marshalling 794 complexReturnType(mlir::Location, mlir::Type eleTy) const override { 795 CodeGenSpecifics::Marshalling marshal; 796 // Use a type that will be translated into LLVM as: 797 // { t, t } struct of 2 element type 798 marshal.emplace_back( 799 mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}), 800 AT{}); 801 return marshal; 802 } 803 }; 804 } // namespace 805 806 //===----------------------------------------------------------------------===// 807 // PPC64le linux target specifics. 808 //===----------------------------------------------------------------------===// 809 810 namespace { 811 struct TargetPPC64le : public GenericTarget<TargetPPC64le> { 812 using GenericTarget::GenericTarget; 813 814 static constexpr int defaultWidth = 64; 815 816 CodeGenSpecifics::Marshalling 817 complexArgumentType(mlir::Location, mlir::Type eleTy) const override { 818 CodeGenSpecifics::Marshalling marshal; 819 // two distinct element type arguments (re, im) 820 marshal.emplace_back(eleTy, AT{}); 821 marshal.emplace_back(eleTy, AT{}); 822 return marshal; 823 } 824 825 CodeGenSpecifics::Marshalling 826 complexReturnType(mlir::Location, mlir::Type eleTy) const override { 827 CodeGenSpecifics::Marshalling marshal; 828 // Use a type that will be translated into LLVM as: 829 // { t, t } struct of 2 element type 830 marshal.emplace_back( 831 mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}), 832 AT{}); 833 return marshal; 834 } 835 }; 836 } // namespace 837 838 //===----------------------------------------------------------------------===// 839 // sparc (sparc 32 bit) target specifics. 840 //===----------------------------------------------------------------------===// 841 842 namespace { 843 struct TargetSparc : public GenericTarget<TargetSparc> { 844 using GenericTarget::GenericTarget; 845 846 static constexpr int defaultWidth = 32; 847 848 CodeGenSpecifics::Marshalling 849 complexArgumentType(mlir::Location, mlir::Type eleTy) const override { 850 assert(fir::isa_real(eleTy)); 851 CodeGenSpecifics::Marshalling marshal; 852 // Use a type that will be translated into LLVM as: 853 // { t, t } struct of 2 eleTy 854 auto structTy = 855 mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}); 856 marshal.emplace_back(fir::ReferenceType::get(structTy), AT{}); 857 return marshal; 858 } 859 860 CodeGenSpecifics::Marshalling 861 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 862 assert(fir::isa_real(eleTy)); 863 CodeGenSpecifics::Marshalling marshal; 864 // Use a type that will be translated into LLVM as: 865 // { t, t } struct of 2 eleTy, byval 866 auto structTy = 867 mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}); 868 marshal.emplace_back(fir::ReferenceType::get(structTy), 869 AT{/*alignment=*/0, /*byval=*/true}); 870 return marshal; 871 } 872 }; 873 } // namespace 874 875 //===----------------------------------------------------------------------===// 876 // sparcv9 (sparc 64 bit) target specifics. 877 //===----------------------------------------------------------------------===// 878 879 namespace { 880 struct TargetSparcV9 : public GenericTarget<TargetSparcV9> { 881 using GenericTarget::GenericTarget; 882 883 static constexpr int defaultWidth = 64; 884 885 CodeGenSpecifics::Marshalling 886 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 887 CodeGenSpecifics::Marshalling marshal; 888 const auto *sem = &floatToSemantics(kindMap, eleTy); 889 if (sem == &llvm::APFloat::IEEEsingle() || 890 sem == &llvm::APFloat::IEEEdouble()) { 891 // two distinct float, double arguments 892 marshal.emplace_back(eleTy, AT{}); 893 marshal.emplace_back(eleTy, AT{}); 894 } else if (sem == &llvm::APFloat::IEEEquad()) { 895 // Use a type that will be translated into LLVM as: 896 // { fp128, fp128 } struct of 2 fp128, byval, align 16 897 marshal.emplace_back( 898 fir::ReferenceType::get(mlir::TupleType::get( 899 eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 900 AT{/*align=*/16, /*byval=*/true}); 901 } else { 902 typeTodo(sem, loc, "argument"); 903 } 904 return marshal; 905 } 906 907 CodeGenSpecifics::Marshalling 908 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 909 CodeGenSpecifics::Marshalling marshal; 910 // Use a type that will be translated into LLVM as: 911 // { eleTy, eleTy } struct of 2 eleTy 912 marshal.emplace_back( 913 mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}), 914 AT{}); 915 return marshal; 916 } 917 }; 918 } // namespace 919 920 //===----------------------------------------------------------------------===// 921 // RISCV64 linux target specifics. 922 //===----------------------------------------------------------------------===// 923 924 namespace { 925 struct TargetRISCV64 : public GenericTarget<TargetRISCV64> { 926 using GenericTarget::GenericTarget; 927 928 static constexpr int defaultWidth = 64; 929 930 CodeGenSpecifics::Marshalling 931 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 932 CodeGenSpecifics::Marshalling marshal; 933 const auto *sem = &floatToSemantics(kindMap, eleTy); 934 if (sem == &llvm::APFloat::IEEEsingle() || 935 sem == &llvm::APFloat::IEEEdouble()) { 936 // Two distinct element type arguments (re, im) 937 marshal.emplace_back(eleTy, AT{}); 938 marshal.emplace_back(eleTy, AT{}); 939 } else { 940 typeTodo(sem, loc, "argument"); 941 } 942 return marshal; 943 } 944 945 CodeGenSpecifics::Marshalling 946 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 947 CodeGenSpecifics::Marshalling marshal; 948 const auto *sem = &floatToSemantics(kindMap, eleTy); 949 if (sem == &llvm::APFloat::IEEEsingle() || 950 sem == &llvm::APFloat::IEEEdouble()) { 951 // Use a type that will be translated into LLVM as: 952 // { t, t } struct of 2 eleTy, byVal 953 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), 954 mlir::TypeRange{eleTy, eleTy}), 955 AT{/*alignment=*/0, /*byval=*/true}); 956 } else { 957 typeTodo(sem, loc, "return"); 958 } 959 return marshal; 960 } 961 }; 962 } // namespace 963 964 //===----------------------------------------------------------------------===// 965 // AMDGPU linux target specifics. 966 //===----------------------------------------------------------------------===// 967 968 namespace { 969 struct TargetAMDGPU : public GenericTarget<TargetAMDGPU> { 970 using GenericTarget::GenericTarget; 971 972 // Default size (in bits) of the index type for strings. 973 static constexpr int defaultWidth = 64; 974 975 CodeGenSpecifics::Marshalling 976 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 977 CodeGenSpecifics::Marshalling marshal; 978 TODO(loc, "handle complex argument types"); 979 return marshal; 980 } 981 982 CodeGenSpecifics::Marshalling 983 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 984 CodeGenSpecifics::Marshalling marshal; 985 TODO(loc, "handle complex return types"); 986 return marshal; 987 } 988 }; 989 } // namespace 990 991 //===----------------------------------------------------------------------===// 992 // NVPTX linux target specifics. 993 //===----------------------------------------------------------------------===// 994 995 namespace { 996 struct TargetNVPTX : public GenericTarget<TargetNVPTX> { 997 using GenericTarget::GenericTarget; 998 999 // Default size (in bits) of the index type for strings. 1000 static constexpr int defaultWidth = 64; 1001 1002 CodeGenSpecifics::Marshalling 1003 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 1004 CodeGenSpecifics::Marshalling marshal; 1005 TODO(loc, "handle complex argument types"); 1006 return marshal; 1007 } 1008 1009 CodeGenSpecifics::Marshalling 1010 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 1011 CodeGenSpecifics::Marshalling marshal; 1012 TODO(loc, "handle complex return types"); 1013 return marshal; 1014 } 1015 }; 1016 } // namespace 1017 1018 //===----------------------------------------------------------------------===// 1019 // LoongArch64 linux target specifics. 1020 //===----------------------------------------------------------------------===// 1021 1022 namespace { 1023 struct TargetLoongArch64 : public GenericTarget<TargetLoongArch64> { 1024 using GenericTarget::GenericTarget; 1025 1026 static constexpr int defaultWidth = 64; 1027 1028 CodeGenSpecifics::Marshalling 1029 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 1030 CodeGenSpecifics::Marshalling marshal; 1031 const auto *sem = &floatToSemantics(kindMap, eleTy); 1032 if (sem == &llvm::APFloat::IEEEsingle() || 1033 sem == &llvm::APFloat::IEEEdouble()) { 1034 // Two distinct element type arguments (re, im) 1035 marshal.emplace_back(eleTy, AT{}); 1036 marshal.emplace_back(eleTy, AT{}); 1037 } else { 1038 typeTodo(sem, loc, "argument"); 1039 } 1040 return marshal; 1041 } 1042 1043 CodeGenSpecifics::Marshalling 1044 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 1045 CodeGenSpecifics::Marshalling marshal; 1046 const auto *sem = &floatToSemantics(kindMap, eleTy); 1047 if (sem == &llvm::APFloat::IEEEsingle() || 1048 sem == &llvm::APFloat::IEEEdouble()) { 1049 // Use a type that will be translated into LLVM as: 1050 // { t, t } struct of 2 eleTy, byVal 1051 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), 1052 mlir::TypeRange{eleTy, eleTy}), 1053 AT{/*alignment=*/0, /*byval=*/true}); 1054 } else { 1055 typeTodo(sem, loc, "return"); 1056 } 1057 return marshal; 1058 } 1059 }; 1060 } // namespace 1061 1062 // Instantiate the overloaded target instance based on the triple value. 1063 // TODO: Add other targets to this file as needed. 1064 std::unique_ptr<fir::CodeGenSpecifics> 1065 fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp, 1066 KindMapping &&kindMap, const mlir::DataLayout &dl) { 1067 switch (trp.getArch()) { 1068 default: 1069 break; 1070 case llvm::Triple::ArchType::x86: 1071 if (trp.isOSWindows()) 1072 return std::make_unique<TargetI386Win>(ctx, std::move(trp), 1073 std::move(kindMap), dl); 1074 else 1075 return std::make_unique<TargetI386>(ctx, std::move(trp), 1076 std::move(kindMap), dl); 1077 case llvm::Triple::ArchType::x86_64: 1078 if (trp.isOSWindows()) 1079 return std::make_unique<TargetX86_64Win>(ctx, std::move(trp), 1080 std::move(kindMap), dl); 1081 else 1082 return std::make_unique<TargetX86_64>(ctx, std::move(trp), 1083 std::move(kindMap), dl); 1084 case llvm::Triple::ArchType::aarch64: 1085 return std::make_unique<TargetAArch64>(ctx, std::move(trp), 1086 std::move(kindMap), dl); 1087 case llvm::Triple::ArchType::ppc64: 1088 return std::make_unique<TargetPPC64>(ctx, std::move(trp), 1089 std::move(kindMap), dl); 1090 case llvm::Triple::ArchType::ppc64le: 1091 return std::make_unique<TargetPPC64le>(ctx, std::move(trp), 1092 std::move(kindMap), dl); 1093 case llvm::Triple::ArchType::sparc: 1094 return std::make_unique<TargetSparc>(ctx, std::move(trp), 1095 std::move(kindMap), dl); 1096 case llvm::Triple::ArchType::sparcv9: 1097 return std::make_unique<TargetSparcV9>(ctx, std::move(trp), 1098 std::move(kindMap), dl); 1099 case llvm::Triple::ArchType::riscv64: 1100 return std::make_unique<TargetRISCV64>(ctx, std::move(trp), 1101 std::move(kindMap), dl); 1102 case llvm::Triple::ArchType::amdgcn: 1103 return std::make_unique<TargetAMDGPU>(ctx, std::move(trp), 1104 std::move(kindMap), dl); 1105 case llvm::Triple::ArchType::nvptx64: 1106 return std::make_unique<TargetNVPTX>(ctx, std::move(trp), 1107 std::move(kindMap), dl); 1108 case llvm::Triple::ArchType::loongarch64: 1109 return std::make_unique<TargetLoongArch64>(ctx, std::move(trp), 1110 std::move(kindMap), dl); 1111 } 1112 TODO(mlir::UnknownLoc::get(ctx), "target not implemented"); 1113 } 1114