xref: /llvm-project/flang/lib/Optimizer/CodeGen/Target.cpp (revision 1d57b9a5b1bb99334139ce671ab15650cc96cbc8)
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 &current = 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