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