14c263edeSDiana Picus //===-- Target.cpp --------------------------------------------------------===// 24c263edeSDiana Picus // 34c263edeSDiana Picus // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44c263edeSDiana Picus // See https://llvm.org/LICENSE.txt for license information. 54c263edeSDiana Picus // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64c263edeSDiana Picus // 74c263edeSDiana Picus //===----------------------------------------------------------------------===// 84c263edeSDiana Picus // 94c263edeSDiana Picus // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 104c263edeSDiana Picus // 114c263edeSDiana Picus //===----------------------------------------------------------------------===// 124c263edeSDiana Picus 1330408f5cSValentin Clement #include "flang/Optimizer/CodeGen/Target.h" 140c1cf585SEric Schweitz #include "flang/Optimizer/Builder/Todo.h" 154c263edeSDiana Picus #include "flang/Optimizer/Dialect/FIRType.h" 16b07ef9e7SRenaud-K #include "flang/Optimizer/Dialect/Support/KindMapping.h" 170c1cf585SEric Schweitz #include "flang/Optimizer/Support/FatalError.h" 1804b18530SPete Steinfeld #include "flang/Optimizer/Support/Utils.h" 194c263edeSDiana Picus #include "mlir/IR/BuiltinTypes.h" 204c263edeSDiana Picus #include "mlir/IR/TypeRange.h" 2127d9a479SjeanPerier #include "llvm/ADT/TypeSwitch.h" 224c263edeSDiana Picus 234c263edeSDiana Picus #define DEBUG_TYPE "flang-codegen-target" 244c263edeSDiana Picus 254c263edeSDiana Picus using namespace fir; 264c263edeSDiana Picus 27ff794116SSlava Zakharin namespace fir::details { 28ff794116SSlava Zakharin llvm::StringRef Attributes::getIntExtensionAttrName() const { 29ff794116SSlava Zakharin // The attribute names are available via LLVM dialect interfaces 30ff794116SSlava Zakharin // like getZExtAttrName(), getByValAttrName(), etc., so we'd better 31ff794116SSlava Zakharin // use them than literals. 32ff794116SSlava Zakharin if (isZeroExt()) 33ff794116SSlava Zakharin return "llvm.zeroext"; 34ff794116SSlava Zakharin else if (isSignExt()) 35ff794116SSlava Zakharin return "llvm.signext"; 36ff794116SSlava Zakharin return {}; 37ff794116SSlava Zakharin } 38ff794116SSlava Zakharin } // namespace fir::details 39ff794116SSlava Zakharin 4065431d3aSDiana Picus // Reduce a REAL/float type to the floating point semantics. 4165431d3aSDiana Picus static const llvm::fltSemantics &floatToSemantics(const KindMapping &kindMap, 4265431d3aSDiana Picus mlir::Type type) { 4365431d3aSDiana Picus assert(isa_real(type)); 44fac349a1SChristian Sigg return mlir::cast<mlir::FloatType>(type).getFloatSemantics(); 4565431d3aSDiana Picus } 4665431d3aSDiana Picus 4704b18530SPete Steinfeld static void typeTodo(const llvm::fltSemantics *sem, mlir::Location loc, 485a20a208SPeter Klausler const std::string &context) { 4904b18530SPete Steinfeld if (sem == &llvm::APFloat::IEEEhalf()) { 5004b18530SPete Steinfeld TODO(loc, "COMPLEX(KIND=2): for " + context + " type"); 5104b18530SPete Steinfeld } else if (sem == &llvm::APFloat::BFloat()) { 5204b18530SPete Steinfeld TODO(loc, "COMPLEX(KIND=3): " + context + " type"); 5304b18530SPete Steinfeld } else if (sem == &llvm::APFloat::x87DoubleExtended()) { 5404b18530SPete Steinfeld TODO(loc, "COMPLEX(KIND=10): " + context + " type"); 5504b18530SPete Steinfeld } else { 5604b18530SPete Steinfeld TODO(loc, "complex for this precision for " + context + " type"); 5704b18530SPete Steinfeld } 5804b18530SPete Steinfeld } 5904b18530SPete Steinfeld 604c263edeSDiana Picus namespace { 614c263edeSDiana Picus template <typename S> 624c263edeSDiana Picus struct GenericTarget : public CodeGenSpecifics { 634c263edeSDiana Picus using CodeGenSpecifics::CodeGenSpecifics; 644c263edeSDiana Picus using AT = CodeGenSpecifics::Attributes; 654c263edeSDiana Picus 667b5132daSValentin Clement mlir::Type complexMemoryType(mlir::Type eleTy) const override { 677b5132daSValentin Clement assert(fir::isa_real(eleTy)); 68faf869dcSDiana Picus // Use a type that will be translated into LLVM as: 697b5132daSValentin Clement // { t, t } struct of 2 eleTy 70ff794116SSlava Zakharin return mlir::TupleType::get(eleTy.getContext(), 71ff794116SSlava Zakharin mlir::TypeRange{eleTy, eleTy}); 727b5132daSValentin Clement } 737b5132daSValentin Clement 74bb201826SAndrzej Warzynski mlir::Type boxcharMemoryType(mlir::Type eleTy) const override { 75bb201826SAndrzej Warzynski auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth); 76bb201826SAndrzej Warzynski auto ptrTy = fir::ReferenceType::get(eleTy); 77faf869dcSDiana Picus // Use a type that will be translated into LLVM as: 78bb201826SAndrzej Warzynski // { t*, index } 79ff794116SSlava Zakharin return mlir::TupleType::get(eleTy.getContext(), 80ff794116SSlava Zakharin mlir::TypeRange{ptrTy, idxTy}); 81bb201826SAndrzej Warzynski } 82bb201826SAndrzej Warzynski 83cbb49d4bSjeanPerier Marshalling boxcharArgumentType(mlir::Type eleTy) const override { 844c263edeSDiana Picus CodeGenSpecifics::Marshalling marshal; 854c263edeSDiana Picus auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth); 864c263edeSDiana Picus auto ptrTy = fir::ReferenceType::get(eleTy); 874c263edeSDiana Picus marshal.emplace_back(ptrTy, AT{}); 88cbb49d4bSjeanPerier // Characters are passed in a split format with all pointers first (in the 89cbb49d4bSjeanPerier // declared position) and all LEN arguments appended after all of the dummy 90cbb49d4bSjeanPerier // arguments. 914c263edeSDiana Picus // NB: Other conventions/ABIs can/should be supported via options. 9265431d3aSDiana Picus marshal.emplace_back(idxTy, AT{/*alignment=*/0, /*byval=*/false, 93cbb49d4bSjeanPerier /*sret=*/false, /*append=*/true}); 944c263edeSDiana Picus return marshal; 954c263edeSDiana Picus } 96ff794116SSlava Zakharin 97ff794116SSlava Zakharin CodeGenSpecifics::Marshalling 9827d9a479SjeanPerier structArgumentType(mlir::Location loc, fir::RecordType, 9927d9a479SjeanPerier const Marshalling &) const override { 10027d9a479SjeanPerier TODO(loc, "passing VALUE BIND(C) derived type for this target"); 10127d9a479SjeanPerier } 10227d9a479SjeanPerier 10327d9a479SjeanPerier CodeGenSpecifics::Marshalling 104367c3c96SjeanPerier structReturnType(mlir::Location loc, fir::RecordType ty) const override { 105367c3c96SjeanPerier TODO(loc, "returning BIND(C) derived type for this target"); 106367c3c96SjeanPerier } 107367c3c96SjeanPerier 108367c3c96SjeanPerier CodeGenSpecifics::Marshalling 109ff794116SSlava Zakharin integerArgumentType(mlir::Location loc, 110ff794116SSlava Zakharin mlir::IntegerType argTy) const override { 111ff794116SSlava Zakharin CodeGenSpecifics::Marshalling marshal; 112ff794116SSlava Zakharin AT::IntegerExtension intExt = AT::IntegerExtension::None; 113ff794116SSlava Zakharin if (argTy.getWidth() < getCIntTypeWidth()) { 114ff794116SSlava Zakharin // isSigned() and isUnsigned() branches below are dead code currently. 115ff794116SSlava Zakharin // If needed, we can generate calls with signed/unsigned argument types 116ff794116SSlava Zakharin // to more precisely match C side (e.g. for Fortran runtime functions 117ff794116SSlava Zakharin // with 'unsigned short' arguments). 118ff794116SSlava Zakharin if (argTy.isSigned()) 119ff794116SSlava Zakharin intExt = AT::IntegerExtension::Sign; 120ff794116SSlava Zakharin else if (argTy.isUnsigned()) 121ff794116SSlava Zakharin intExt = AT::IntegerExtension::Zero; 122ff794116SSlava Zakharin else if (argTy.isSignless()) { 123ff794116SSlava Zakharin // Zero extend for 'i1' and sign extend for other types. 124ff794116SSlava Zakharin if (argTy.getWidth() == 1) 125ff794116SSlava Zakharin intExt = AT::IntegerExtension::Zero; 126ff794116SSlava Zakharin else 127ff794116SSlava Zakharin intExt = AT::IntegerExtension::Sign; 128ff794116SSlava Zakharin } 129ff794116SSlava Zakharin } 130ff794116SSlava Zakharin 131ff794116SSlava Zakharin marshal.emplace_back(argTy, AT{/*alignment=*/0, /*byval=*/false, 132ff794116SSlava Zakharin /*sret=*/false, /*append=*/false, 133ff794116SSlava Zakharin /*intExt=*/intExt}); 134ff794116SSlava Zakharin return marshal; 135ff794116SSlava Zakharin } 136ff794116SSlava Zakharin 137ff794116SSlava Zakharin CodeGenSpecifics::Marshalling 138ff794116SSlava Zakharin integerReturnType(mlir::Location loc, 139ff794116SSlava Zakharin mlir::IntegerType argTy) const override { 140ff794116SSlava Zakharin return integerArgumentType(loc, argTy); 141ff794116SSlava Zakharin } 142ff794116SSlava Zakharin 143ff794116SSlava Zakharin // Width of 'int' type is 32-bits for almost all targets, except 144ff794116SSlava Zakharin // for AVR and MSP430 (see TargetInfo initializations 145ff794116SSlava Zakharin // in clang/lib/Basic/Targets). 146ff794116SSlava Zakharin unsigned char getCIntTypeWidth() const override { return 32; } 1474c263edeSDiana Picus }; 1484c263edeSDiana Picus } // namespace 1494c263edeSDiana Picus 1504c263edeSDiana Picus //===----------------------------------------------------------------------===// 1514c263edeSDiana Picus // i386 (x86 32 bit) linux target specifics. 1524c263edeSDiana Picus //===----------------------------------------------------------------------===// 1534c263edeSDiana Picus 1544c263edeSDiana Picus namespace { 1554c263edeSDiana Picus struct TargetI386 : public GenericTarget<TargetI386> { 1564c263edeSDiana Picus using GenericTarget::GenericTarget; 1574c263edeSDiana Picus 1584c263edeSDiana Picus static constexpr int defaultWidth = 32; 15965431d3aSDiana Picus 16065431d3aSDiana Picus CodeGenSpecifics::Marshalling 1610c1cf585SEric Schweitz complexArgumentType(mlir::Location, mlir::Type eleTy) const override { 16265431d3aSDiana Picus assert(fir::isa_real(eleTy)); 16365431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal; 164faf869dcSDiana Picus // Use a type that will be translated into LLVM as: 16565431d3aSDiana Picus // { t, t } struct of 2 eleTy, byval, align 4 166ff794116SSlava Zakharin auto structTy = 167ff794116SSlava Zakharin mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}); 16865431d3aSDiana Picus marshal.emplace_back(fir::ReferenceType::get(structTy), 16965431d3aSDiana Picus AT{/*alignment=*/4, /*byval=*/true}); 17065431d3aSDiana Picus return marshal; 17165431d3aSDiana Picus } 17265431d3aSDiana Picus 17365431d3aSDiana Picus CodeGenSpecifics::Marshalling 1740c1cf585SEric Schweitz complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 17565431d3aSDiana Picus assert(fir::isa_real(eleTy)); 17665431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal; 17765431d3aSDiana Picus const auto *sem = &floatToSemantics(kindMap, eleTy); 17865431d3aSDiana Picus if (sem == &llvm::APFloat::IEEEsingle()) { 17965431d3aSDiana Picus // i64 pack both floats in a 64-bit GPR 18065431d3aSDiana Picus marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64), 18165431d3aSDiana Picus AT{}); 18265431d3aSDiana Picus } else if (sem == &llvm::APFloat::IEEEdouble()) { 183faf869dcSDiana Picus // Use a type that will be translated into LLVM as: 18465431d3aSDiana Picus // { t, t } struct of 2 eleTy, sret, align 4 185ff794116SSlava Zakharin auto structTy = mlir::TupleType::get(eleTy.getContext(), 186ff794116SSlava Zakharin mlir::TypeRange{eleTy, eleTy}); 18765431d3aSDiana Picus marshal.emplace_back(fir::ReferenceType::get(structTy), 18865431d3aSDiana Picus AT{/*alignment=*/4, /*byval=*/false, /*sret=*/true}); 18965431d3aSDiana Picus } else { 19004b18530SPete Steinfeld typeTodo(sem, loc, "return"); 19165431d3aSDiana Picus } 19265431d3aSDiana Picus return marshal; 19365431d3aSDiana Picus } 1944c263edeSDiana Picus }; 1954c263edeSDiana Picus } // namespace 1964c263edeSDiana Picus 1974c263edeSDiana Picus //===----------------------------------------------------------------------===// 198774703ecSMarkus Mützel // i386 (x86 32 bit) Windows target specifics. 199774703ecSMarkus Mützel //===----------------------------------------------------------------------===// 200774703ecSMarkus Mützel 201774703ecSMarkus Mützel namespace { 202774703ecSMarkus Mützel struct TargetI386Win : public GenericTarget<TargetI386Win> { 203774703ecSMarkus Mützel using GenericTarget::GenericTarget; 204774703ecSMarkus Mützel 205774703ecSMarkus Mützel static constexpr int defaultWidth = 32; 206774703ecSMarkus Mützel 207774703ecSMarkus Mützel CodeGenSpecifics::Marshalling 208774703ecSMarkus Mützel complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 209774703ecSMarkus Mützel CodeGenSpecifics::Marshalling marshal; 210774703ecSMarkus Mützel // Use a type that will be translated into LLVM as: 211774703ecSMarkus Mützel // { t, t } struct of 2 eleTy, byval, align 4 212774703ecSMarkus Mützel auto structTy = 213774703ecSMarkus Mützel mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}); 214774703ecSMarkus Mützel marshal.emplace_back(fir::ReferenceType::get(structTy), 215774703ecSMarkus Mützel AT{/*align=*/4, /*byval=*/true}); 216774703ecSMarkus Mützel return marshal; 217774703ecSMarkus Mützel } 218774703ecSMarkus Mützel 219774703ecSMarkus Mützel CodeGenSpecifics::Marshalling 220774703ecSMarkus Mützel complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 221774703ecSMarkus Mützel CodeGenSpecifics::Marshalling marshal; 222774703ecSMarkus Mützel const auto *sem = &floatToSemantics(kindMap, eleTy); 223774703ecSMarkus Mützel if (sem == &llvm::APFloat::IEEEsingle()) { 224774703ecSMarkus Mützel // i64 pack both floats in a 64-bit GPR 225774703ecSMarkus Mützel marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64), 226774703ecSMarkus Mützel AT{}); 227774703ecSMarkus Mützel } else if (sem == &llvm::APFloat::IEEEdouble()) { 228774703ecSMarkus Mützel // Use a type that will be translated into LLVM as: 229774703ecSMarkus Mützel // { double, double } struct of 2 double, sret, align 8 230774703ecSMarkus Mützel marshal.emplace_back( 231774703ecSMarkus Mützel fir::ReferenceType::get(mlir::TupleType::get( 232774703ecSMarkus Mützel eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 233774703ecSMarkus Mützel AT{/*align=*/8, /*byval=*/false, /*sret=*/true}); 234774703ecSMarkus Mützel } else if (sem == &llvm::APFloat::IEEEquad()) { 235774703ecSMarkus Mützel // Use a type that will be translated into LLVM as: 236774703ecSMarkus Mützel // { fp128, fp128 } struct of 2 fp128, sret, align 16 237774703ecSMarkus Mützel marshal.emplace_back( 238774703ecSMarkus Mützel fir::ReferenceType::get(mlir::TupleType::get( 239774703ecSMarkus Mützel eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 240774703ecSMarkus Mützel AT{/*align=*/16, /*byval=*/false, /*sret=*/true}); 241774703ecSMarkus Mützel } else if (sem == &llvm::APFloat::x87DoubleExtended()) { 242774703ecSMarkus Mützel // Use a type that will be translated into LLVM as: 243774703ecSMarkus Mützel // { x86_fp80, x86_fp80 } struct of 2 x86_fp80, sret, align 4 244774703ecSMarkus Mützel marshal.emplace_back( 245774703ecSMarkus Mützel fir::ReferenceType::get(mlir::TupleType::get( 246774703ecSMarkus Mützel eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 247774703ecSMarkus Mützel AT{/*align=*/4, /*byval=*/false, /*sret=*/true}); 248774703ecSMarkus Mützel } else { 24904b18530SPete Steinfeld typeTodo(sem, loc, "return"); 250774703ecSMarkus Mützel } 251774703ecSMarkus Mützel return marshal; 252774703ecSMarkus Mützel } 253774703ecSMarkus Mützel }; 254774703ecSMarkus Mützel } // namespace 255774703ecSMarkus Mützel 256774703ecSMarkus Mützel //===----------------------------------------------------------------------===// 2574c263edeSDiana Picus // x86_64 (x86 64 bit) linux target specifics. 2584c263edeSDiana Picus //===----------------------------------------------------------------------===// 2594c263edeSDiana Picus 2604c263edeSDiana Picus namespace { 2614c263edeSDiana Picus struct TargetX86_64 : public GenericTarget<TargetX86_64> { 2624c263edeSDiana Picus using GenericTarget::GenericTarget; 2634c263edeSDiana Picus 2644c263edeSDiana Picus static constexpr int defaultWidth = 64; 26565431d3aSDiana Picus 26665431d3aSDiana Picus CodeGenSpecifics::Marshalling 2670c1cf585SEric Schweitz complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 26865431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal; 26965431d3aSDiana Picus const auto *sem = &floatToSemantics(kindMap, eleTy); 27065431d3aSDiana Picus if (sem == &llvm::APFloat::IEEEsingle()) { 27165431d3aSDiana Picus // <2 x t> vector of 2 eleTy 27265431d3aSDiana Picus marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{}); 27365431d3aSDiana Picus } else if (sem == &llvm::APFloat::IEEEdouble()) { 274f65e3af7SjeanPerier // FIXME: In case of SSE register exhaustion, the ABI here may be 275f65e3af7SjeanPerier // incorrect since LLVM may pass the real via register and the imaginary 276f65e3af7SjeanPerier // part via the stack while the ABI it should be all in register or all 277f65e3af7SjeanPerier // in memory. Register occupancy must be analyzed here. 27865431d3aSDiana Picus // two distinct double arguments 27965431d3aSDiana Picus marshal.emplace_back(eleTy, AT{}); 28065431d3aSDiana Picus marshal.emplace_back(eleTy, AT{}); 281f65e3af7SjeanPerier } else if (sem == &llvm::APFloat::x87DoubleExtended()) { 282f65e3af7SjeanPerier // Use a type that will be translated into LLVM as: 283f65e3af7SjeanPerier // { x86_fp80, x86_fp80 } struct of 2 fp128, byval, align 16 284f65e3af7SjeanPerier marshal.emplace_back( 285f65e3af7SjeanPerier fir::ReferenceType::get(mlir::TupleType::get( 286f65e3af7SjeanPerier eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 287f65e3af7SjeanPerier AT{/*align=*/16, /*byval=*/true}); 2881906188fSValentin Clement } else if (sem == &llvm::APFloat::IEEEquad()) { 2891906188fSValentin Clement // Use a type that will be translated into LLVM as: 2901906188fSValentin Clement // { fp128, fp128 } struct of 2 fp128, byval, align 16 291ff794116SSlava Zakharin marshal.emplace_back( 292ff794116SSlava Zakharin fir::ReferenceType::get(mlir::TupleType::get( 293ff794116SSlava Zakharin eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 2941906188fSValentin Clement AT{/*align=*/16, /*byval=*/true}); 29565431d3aSDiana Picus } else { 29604b18530SPete Steinfeld typeTodo(sem, loc, "argument"); 29765431d3aSDiana Picus } 29865431d3aSDiana Picus return marshal; 29965431d3aSDiana Picus } 30065431d3aSDiana Picus 30165431d3aSDiana Picus CodeGenSpecifics::Marshalling 3020c1cf585SEric Schweitz complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 30365431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal; 30465431d3aSDiana Picus const auto *sem = &floatToSemantics(kindMap, eleTy); 30565431d3aSDiana Picus if (sem == &llvm::APFloat::IEEEsingle()) { 30665431d3aSDiana Picus // <2 x t> vector of 2 eleTy 30765431d3aSDiana Picus marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{}); 30865431d3aSDiana Picus } else if (sem == &llvm::APFloat::IEEEdouble()) { 309faf869dcSDiana Picus // Use a type that will be translated into LLVM as: 310faf869dcSDiana Picus // { double, double } struct of 2 double 311ff794116SSlava Zakharin marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), 312ff794116SSlava Zakharin mlir::TypeRange{eleTy, eleTy}), 31365431d3aSDiana Picus AT{}); 314f65e3af7SjeanPerier } else if (sem == &llvm::APFloat::x87DoubleExtended()) { 315f65e3af7SjeanPerier // { x86_fp80, x86_fp80 } 316f65e3af7SjeanPerier marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), 317f65e3af7SjeanPerier mlir::TypeRange{eleTy, eleTy}), 318f65e3af7SjeanPerier AT{}); 3191906188fSValentin Clement } else if (sem == &llvm::APFloat::IEEEquad()) { 3201906188fSValentin Clement // Use a type that will be translated into LLVM as: 3211906188fSValentin Clement // { fp128, fp128 } struct of 2 fp128, sret, align 16 322ff794116SSlava Zakharin marshal.emplace_back( 323ff794116SSlava Zakharin fir::ReferenceType::get(mlir::TupleType::get( 324ff794116SSlava Zakharin eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 3251906188fSValentin Clement AT{/*align=*/16, /*byval=*/false, /*sret=*/true}); 32665431d3aSDiana Picus } else { 32704b18530SPete Steinfeld typeTodo(sem, loc, "return"); 32865431d3aSDiana Picus } 32965431d3aSDiana Picus return marshal; 33065431d3aSDiana Picus } 33127d9a479SjeanPerier 33227d9a479SjeanPerier /// X86-64 argument classes from System V ABI version 1.0 section 3.2.3. 33327d9a479SjeanPerier enum ArgClass { 33427d9a479SjeanPerier Integer = 0, 33527d9a479SjeanPerier SSE, 33627d9a479SjeanPerier SSEUp, 33727d9a479SjeanPerier X87, 33827d9a479SjeanPerier X87Up, 33927d9a479SjeanPerier ComplexX87, 34027d9a479SjeanPerier NoClass, 34127d9a479SjeanPerier Memory 34227d9a479SjeanPerier }; 34327d9a479SjeanPerier 34427d9a479SjeanPerier /// Classify an argument type or a field of an aggregate type argument. 34527d9a479SjeanPerier /// See System V ABI version 1.0 section 3.2.3. 34627d9a479SjeanPerier /// The Lo and Hi class are set to the class of the lower eight eightbytes 34727d9a479SjeanPerier /// and upper eight eightbytes on return. 34827d9a479SjeanPerier /// If this is called for an aggregate field, the caller is responsible to 34927d9a479SjeanPerier /// do the post-merge. 35027d9a479SjeanPerier void classify(mlir::Location loc, mlir::Type type, std::uint64_t byteOffset, 35127d9a479SjeanPerier ArgClass &Lo, ArgClass &Hi) const { 35227d9a479SjeanPerier Hi = Lo = ArgClass::NoClass; 35327d9a479SjeanPerier ArgClass ¤t = byteOffset < 8 ? Lo : Hi; 35427d9a479SjeanPerier // System V AMD64 ABI 3.2.3. version 1.0 35527d9a479SjeanPerier llvm::TypeSwitch<mlir::Type>(type) 35627d9a479SjeanPerier .template Case<mlir::IntegerType>([&](mlir::IntegerType intTy) { 35727d9a479SjeanPerier if (intTy.getWidth() == 128) 35827d9a479SjeanPerier Hi = Lo = ArgClass::Integer; 35927d9a479SjeanPerier else 36027d9a479SjeanPerier current = ArgClass::Integer; 36127d9a479SjeanPerier }) 3621753de2dSjeanPerier .template Case<mlir::FloatType>([&](mlir::Type floatTy) { 36327d9a479SjeanPerier const auto *sem = &floatToSemantics(kindMap, floatTy); 36427d9a479SjeanPerier if (sem == &llvm::APFloat::x87DoubleExtended()) { 36527d9a479SjeanPerier Lo = ArgClass::X87; 36627d9a479SjeanPerier Hi = ArgClass::X87Up; 36727d9a479SjeanPerier } else if (sem == &llvm::APFloat::IEEEquad()) { 36827d9a479SjeanPerier Lo = ArgClass::SSE; 36927d9a479SjeanPerier Hi = ArgClass::SSEUp; 37027d9a479SjeanPerier } else { 37127d9a479SjeanPerier current = ArgClass::SSE; 37227d9a479SjeanPerier } 37327d9a479SjeanPerier }) 374c4204c0bSjeanPerier .template Case<mlir::ComplexType>([&](mlir::ComplexType cmplx) { 37527d9a479SjeanPerier const auto *sem = &floatToSemantics(kindMap, cmplx.getElementType()); 37627d9a479SjeanPerier if (sem == &llvm::APFloat::x87DoubleExtended()) { 37727d9a479SjeanPerier current = ArgClass::ComplexX87; 37827d9a479SjeanPerier } else { 37927d9a479SjeanPerier fir::SequenceType::Shape shape{2}; 38027d9a479SjeanPerier classifyArray(loc, 38127d9a479SjeanPerier fir::SequenceType::get(shape, cmplx.getElementType()), 38227d9a479SjeanPerier byteOffset, Lo, Hi); 38327d9a479SjeanPerier } 38427d9a479SjeanPerier }) 38527d9a479SjeanPerier .template Case<fir::LogicalType>([&](fir::LogicalType logical) { 38627d9a479SjeanPerier if (kindMap.getLogicalBitsize(logical.getFKind()) == 128) 38727d9a479SjeanPerier Hi = Lo = ArgClass::Integer; 38827d9a479SjeanPerier else 38927d9a479SjeanPerier current = ArgClass::Integer; 39027d9a479SjeanPerier }) 39127d9a479SjeanPerier .template Case<fir::CharacterType>( 39227d9a479SjeanPerier [&](fir::CharacterType character) { current = ArgClass::Integer; }) 39327d9a479SjeanPerier .template Case<fir::SequenceType>([&](fir::SequenceType seqTy) { 39427d9a479SjeanPerier // Array component. 39527d9a479SjeanPerier classifyArray(loc, seqTy, byteOffset, Lo, Hi); 39627d9a479SjeanPerier }) 39727d9a479SjeanPerier .template Case<fir::RecordType>([&](fir::RecordType recTy) { 39827d9a479SjeanPerier // Component that is a derived type. 39927d9a479SjeanPerier classifyStruct(loc, recTy, byteOffset, Lo, Hi); 40027d9a479SjeanPerier }) 40127d9a479SjeanPerier .template Case<fir::VectorType>([&](fir::VectorType vecTy) { 40227d9a479SjeanPerier // Previously marshalled SSE eight byte for a previous struct 40327d9a479SjeanPerier // argument. 40427d9a479SjeanPerier auto *sem = fir::isa_real(vecTy.getEleTy()) 40527d9a479SjeanPerier ? &floatToSemantics(kindMap, vecTy.getEleTy()) 40627d9a479SjeanPerier : nullptr; 40727d9a479SjeanPerier // Not expecting to hit this todo in standard code (it would 40827d9a479SjeanPerier // require some vector type extension). 40927d9a479SjeanPerier if (!(sem == &llvm::APFloat::IEEEsingle() && vecTy.getLen() <= 2) && 41027d9a479SjeanPerier !(sem == &llvm::APFloat::IEEEhalf() && vecTy.getLen() <= 4)) 41127d9a479SjeanPerier TODO(loc, "passing vector argument to C by value"); 41227d9a479SjeanPerier current = SSE; 41327d9a479SjeanPerier }) 41427d9a479SjeanPerier .Default([&](mlir::Type ty) { 41527d9a479SjeanPerier if (fir::conformsWithPassByRef(ty)) 41627d9a479SjeanPerier current = ArgClass::Integer; // Pointers. 41727d9a479SjeanPerier else 41827d9a479SjeanPerier TODO(loc, "unsupported component type for BIND(C), VALUE derived " 41927d9a479SjeanPerier "type argument"); 42027d9a479SjeanPerier }); 42127d9a479SjeanPerier } 42227d9a479SjeanPerier 42327d9a479SjeanPerier // Classify fields of a derived type starting at \p offset. Returns the new 42427d9a479SjeanPerier // offset. Post-merge is left to the caller. 42527d9a479SjeanPerier std::uint64_t classifyStruct(mlir::Location loc, fir::RecordType recTy, 42627d9a479SjeanPerier std::uint64_t byteOffset, ArgClass &Lo, 42727d9a479SjeanPerier ArgClass &Hi) const { 42827d9a479SjeanPerier for (auto component : recTy.getTypeList()) { 42927d9a479SjeanPerier if (byteOffset > 16) { 43027d9a479SjeanPerier // See 3.2.3 p. 1 and note 15. Note that when the offset is bigger 43127d9a479SjeanPerier // than 16 bytes here, it is not a single _m256 and or _m512 entity 43227d9a479SjeanPerier // that could fit in AVX registers. 43327d9a479SjeanPerier Lo = Hi = ArgClass::Memory; 43427d9a479SjeanPerier return byteOffset; 43527d9a479SjeanPerier } 43627d9a479SjeanPerier mlir::Type compType = component.second; 437d07dc73bSAbid Qadeer auto [compSize, compAlign] = fir::getTypeSizeAndAlignmentOrCrash( 438d07dc73bSAbid Qadeer loc, compType, getDataLayout(), kindMap); 43927d9a479SjeanPerier byteOffset = llvm::alignTo(byteOffset, compAlign); 44027d9a479SjeanPerier ArgClass LoComp, HiComp; 44127d9a479SjeanPerier classify(loc, compType, byteOffset, LoComp, HiComp); 44227d9a479SjeanPerier Lo = mergeClass(Lo, LoComp); 44327d9a479SjeanPerier Hi = mergeClass(Hi, HiComp); 44427d9a479SjeanPerier byteOffset = byteOffset + llvm::alignTo(compSize, compAlign); 44527d9a479SjeanPerier if (Lo == ArgClass::Memory || Hi == ArgClass::Memory) 44627d9a479SjeanPerier return byteOffset; 44727d9a479SjeanPerier } 44827d9a479SjeanPerier return byteOffset; 44927d9a479SjeanPerier } 45027d9a479SjeanPerier 45127d9a479SjeanPerier // Classify fields of a constant size array type starting at \p offset. 45227d9a479SjeanPerier // Returns the new offset. Post-merge is left to the caller. 45327d9a479SjeanPerier void classifyArray(mlir::Location loc, fir::SequenceType seqTy, 45427d9a479SjeanPerier std::uint64_t byteOffset, ArgClass &Lo, 45527d9a479SjeanPerier ArgClass &Hi) const { 45627d9a479SjeanPerier mlir::Type eleTy = seqTy.getEleTy(); 45727d9a479SjeanPerier const std::uint64_t arraySize = seqTy.getConstantArraySize(); 458d07dc73bSAbid Qadeer auto [eleSize, eleAlign] = fir::getTypeSizeAndAlignmentOrCrash( 459d07dc73bSAbid Qadeer loc, eleTy, getDataLayout(), kindMap); 46027d9a479SjeanPerier std::uint64_t eleStorageSize = llvm::alignTo(eleSize, eleAlign); 46127d9a479SjeanPerier for (std::uint64_t i = 0; i < arraySize; ++i) { 46227d9a479SjeanPerier byteOffset = llvm::alignTo(byteOffset, eleAlign); 46327d9a479SjeanPerier if (byteOffset > 16) { 46427d9a479SjeanPerier // See 3.2.3 p. 1 and note 15. Same as in classifyStruct. 46527d9a479SjeanPerier Lo = Hi = ArgClass::Memory; 46627d9a479SjeanPerier return; 46727d9a479SjeanPerier } 46827d9a479SjeanPerier ArgClass LoComp, HiComp; 46927d9a479SjeanPerier classify(loc, eleTy, byteOffset, LoComp, HiComp); 47027d9a479SjeanPerier Lo = mergeClass(Lo, LoComp); 47127d9a479SjeanPerier Hi = mergeClass(Hi, HiComp); 47227d9a479SjeanPerier byteOffset = byteOffset + eleStorageSize; 47327d9a479SjeanPerier if (Lo == ArgClass::Memory || Hi == ArgClass::Memory) 47427d9a479SjeanPerier return; 47527d9a479SjeanPerier } 47627d9a479SjeanPerier } 47727d9a479SjeanPerier 47827d9a479SjeanPerier // Goes through the previously marshalled arguments and count the 47927d9a479SjeanPerier // register occupancy to check if there are enough registers left. 48027d9a479SjeanPerier bool hasEnoughRegisters(mlir::Location loc, int neededIntRegisters, 48127d9a479SjeanPerier int neededSSERegisters, 48227d9a479SjeanPerier const Marshalling &previousArguments) const { 48327d9a479SjeanPerier int availIntRegisters = 6; 48427d9a479SjeanPerier int availSSERegisters = 8; 48527d9a479SjeanPerier for (auto typeAndAttr : previousArguments) { 48627d9a479SjeanPerier const auto &attr = std::get<Attributes>(typeAndAttr); 48727d9a479SjeanPerier if (attr.isByVal()) 48827d9a479SjeanPerier continue; // Previous argument passed on the stack. 48927d9a479SjeanPerier ArgClass Lo, Hi; 49027d9a479SjeanPerier Lo = Hi = ArgClass::NoClass; 49127d9a479SjeanPerier classify(loc, std::get<mlir::Type>(typeAndAttr), 0, Lo, Hi); 49227d9a479SjeanPerier // post merge is not needed here since previous aggregate arguments 49327d9a479SjeanPerier // were marshalled into simpler arguments. 49427d9a479SjeanPerier if (Lo == ArgClass::Integer) 49527d9a479SjeanPerier --availIntRegisters; 49627d9a479SjeanPerier else if (Lo == SSE) 49727d9a479SjeanPerier --availSSERegisters; 49827d9a479SjeanPerier if (Hi == ArgClass::Integer) 49927d9a479SjeanPerier --availIntRegisters; 50027d9a479SjeanPerier else if (Hi == ArgClass::SSE) 50127d9a479SjeanPerier --availSSERegisters; 50227d9a479SjeanPerier } 50327d9a479SjeanPerier return availSSERegisters >= neededSSERegisters && 50427d9a479SjeanPerier availIntRegisters >= neededIntRegisters; 50527d9a479SjeanPerier } 50627d9a479SjeanPerier 50727d9a479SjeanPerier /// Argument class merging as described in System V ABI 3.2.3 point 4. 50827d9a479SjeanPerier ArgClass mergeClass(ArgClass accum, ArgClass field) const { 50927d9a479SjeanPerier assert((accum != ArgClass::Memory && accum != ArgClass::ComplexX87) && 51027d9a479SjeanPerier "Invalid accumulated classification during merge."); 51127d9a479SjeanPerier if (accum == field || field == NoClass) 51227d9a479SjeanPerier return accum; 51327d9a479SjeanPerier if (field == ArgClass::Memory) 51427d9a479SjeanPerier return ArgClass::Memory; 51527d9a479SjeanPerier if (accum == NoClass) 51627d9a479SjeanPerier return field; 51727d9a479SjeanPerier if (accum == Integer || field == Integer) 51827d9a479SjeanPerier return ArgClass::Integer; 51927d9a479SjeanPerier if (field == ArgClass::X87 || field == ArgClass::X87Up || 52027d9a479SjeanPerier field == ArgClass::ComplexX87 || accum == ArgClass::X87 || 52127d9a479SjeanPerier accum == ArgClass::X87Up) 52227d9a479SjeanPerier return Memory; 52327d9a479SjeanPerier return SSE; 52427d9a479SjeanPerier } 52527d9a479SjeanPerier 52627d9a479SjeanPerier /// Argument class post merging as described in System V ABI 3.2.3 point 5. 52727d9a479SjeanPerier void postMerge(std::uint64_t byteSize, ArgClass &Lo, ArgClass &Hi) const { 52827d9a479SjeanPerier if (Hi == ArgClass::Memory) 52927d9a479SjeanPerier Lo = ArgClass::Memory; 53027d9a479SjeanPerier if (Hi == ArgClass::X87Up && Lo != ArgClass::X87) 53127d9a479SjeanPerier Lo = ArgClass::Memory; 53227d9a479SjeanPerier if (byteSize > 16 && (Lo != ArgClass::SSE || Hi != ArgClass::SSEUp)) 53327d9a479SjeanPerier Lo = ArgClass::Memory; 53427d9a479SjeanPerier if (Hi == ArgClass::SSEUp && Lo != ArgClass::SSE) 53527d9a479SjeanPerier Hi = SSE; 53627d9a479SjeanPerier } 53727d9a479SjeanPerier 5381d57b9a5SjeanPerier /// When \p recTy is a one field record type that can be passed 5391d57b9a5SjeanPerier /// like the field on its own, returns the field type. Returns 5401d57b9a5SjeanPerier /// a null type otherwise. 541367c3c96SjeanPerier mlir::Type passAsFieldIfOneFieldStruct(fir::RecordType recTy, 542367c3c96SjeanPerier bool allowComplex = false) const { 5431d57b9a5SjeanPerier auto typeList = recTy.getTypeList(); 5441d57b9a5SjeanPerier if (typeList.size() != 1) 5451d57b9a5SjeanPerier return {}; 5461d57b9a5SjeanPerier mlir::Type fieldType = typeList[0].second; 5471753de2dSjeanPerier if (mlir::isa<mlir::FloatType, mlir::IntegerType, fir::LogicalType>( 5481753de2dSjeanPerier fieldType)) 5491d57b9a5SjeanPerier return fieldType; 550367c3c96SjeanPerier if (allowComplex && mlir::isa<mlir::ComplexType>(fieldType)) 551367c3c96SjeanPerier return fieldType; 5521753de2dSjeanPerier if (mlir::isa<fir::CharacterType>(fieldType)) { 5531753de2dSjeanPerier // Only CHARACTER(1) are expected in BIND(C) contexts, which is the only 5541753de2dSjeanPerier // contexts where derived type may be passed in registers. 5551753de2dSjeanPerier assert(mlir::cast<fir::CharacterType>(fieldType).getLen() == 1 && 5561753de2dSjeanPerier "fir.type value arg character components must have length 1"); 5571753de2dSjeanPerier return fieldType; 5581753de2dSjeanPerier } 5591d57b9a5SjeanPerier // Complex field that needs to be split, or array. 5601d57b9a5SjeanPerier return {}; 5611d57b9a5SjeanPerier } 5621d57b9a5SjeanPerier 563011ba725SjeanPerier mlir::Type pickLLVMArgType(mlir::Location loc, mlir::MLIRContext *context, 564011ba725SjeanPerier ArgClass argClass, 565011ba725SjeanPerier std::uint64_t partByteSize) const { 566011ba725SjeanPerier if (argClass == ArgClass::SSE) { 567011ba725SjeanPerier if (partByteSize > 16) 568011ba725SjeanPerier TODO(loc, "passing struct as a real > 128 bits in register"); 569011ba725SjeanPerier // Clang uses vector type when several fp fields are marshalled 570011ba725SjeanPerier // into a single SSE register (like <n x smallest fp field> ). 571011ba725SjeanPerier // It should make no difference from an ABI point of view to just 572011ba725SjeanPerier // select an fp type of the right size, and it makes things simpler 573011ba725SjeanPerier // here. 574011ba725SjeanPerier if (partByteSize > 8) 575*f023da12SMatthias Springer return mlir::Float128Type::get(context); 576011ba725SjeanPerier if (partByteSize > 4) 577*f023da12SMatthias Springer return mlir::Float64Type::get(context); 578011ba725SjeanPerier if (partByteSize > 2) 579*f023da12SMatthias Springer return mlir::Float32Type::get(context); 580*f023da12SMatthias Springer return mlir::Float16Type::get(context); 581011ba725SjeanPerier } 582011ba725SjeanPerier assert(partByteSize <= 8 && 583011ba725SjeanPerier "expect integer part of aggregate argument to fit into eight bytes"); 584011ba725SjeanPerier if (partByteSize > 4) 585011ba725SjeanPerier return mlir::IntegerType::get(context, 64); 586011ba725SjeanPerier if (partByteSize > 2) 587011ba725SjeanPerier return mlir::IntegerType::get(context, 32); 588011ba725SjeanPerier if (partByteSize > 1) 589011ba725SjeanPerier return mlir::IntegerType::get(context, 16); 590011ba725SjeanPerier return mlir::IntegerType::get(context, 8); 591011ba725SjeanPerier } 592011ba725SjeanPerier 59327d9a479SjeanPerier /// Marshal a derived type passed by value like a C struct. 59427d9a479SjeanPerier CodeGenSpecifics::Marshalling 59527d9a479SjeanPerier structArgumentType(mlir::Location loc, fir::RecordType recTy, 59627d9a479SjeanPerier const Marshalling &previousArguments) const override { 59727d9a479SjeanPerier std::uint64_t byteOffset = 0; 59827d9a479SjeanPerier ArgClass Lo, Hi; 59927d9a479SjeanPerier Lo = Hi = ArgClass::NoClass; 60027d9a479SjeanPerier byteOffset = classifyStruct(loc, recTy, byteOffset, Lo, Hi); 60127d9a479SjeanPerier postMerge(byteOffset, Lo, Hi); 60227d9a479SjeanPerier if (Lo == ArgClass::Memory || Lo == ArgClass::X87 || 60327d9a479SjeanPerier Lo == ArgClass::ComplexX87) 604367c3c96SjeanPerier return passOnTheStack(loc, recTy, /*isResult=*/false); 60527d9a479SjeanPerier int neededIntRegisters = 0; 60627d9a479SjeanPerier int neededSSERegisters = 0; 60727d9a479SjeanPerier if (Lo == ArgClass::SSE) 60827d9a479SjeanPerier ++neededSSERegisters; 60927d9a479SjeanPerier else if (Lo == ArgClass::Integer) 61027d9a479SjeanPerier ++neededIntRegisters; 61127d9a479SjeanPerier if (Hi == ArgClass::SSE) 61227d9a479SjeanPerier ++neededSSERegisters; 61327d9a479SjeanPerier else if (Hi == ArgClass::Integer) 61427d9a479SjeanPerier ++neededIntRegisters; 61527d9a479SjeanPerier // C struct should not be split into LLVM registers if LLVM codegen is not 61627d9a479SjeanPerier // able to later assign actual registers to all of them (struct passing is 61727d9a479SjeanPerier // all in registers or all on the stack). 61827d9a479SjeanPerier if (!hasEnoughRegisters(loc, neededIntRegisters, neededSSERegisters, 61927d9a479SjeanPerier previousArguments)) 620367c3c96SjeanPerier return passOnTheStack(loc, recTy, /*isResult=*/false); 6211d57b9a5SjeanPerier 6221d57b9a5SjeanPerier if (auto fieldType = passAsFieldIfOneFieldStruct(recTy)) { 6231d57b9a5SjeanPerier CodeGenSpecifics::Marshalling marshal; 6241d57b9a5SjeanPerier marshal.emplace_back(fieldType, AT{}); 6251d57b9a5SjeanPerier return marshal; 6261d57b9a5SjeanPerier } 627011ba725SjeanPerier if (Hi == ArgClass::NoClass || Hi == ArgClass::SSEUp) { 628011ba725SjeanPerier // Pass a single integer or floating point argument. 629011ba725SjeanPerier mlir::Type lowType = 630011ba725SjeanPerier pickLLVMArgType(loc, recTy.getContext(), Lo, byteOffset); 631011ba725SjeanPerier CodeGenSpecifics::Marshalling marshal; 632011ba725SjeanPerier marshal.emplace_back(lowType, AT{}); 633011ba725SjeanPerier return marshal; 634011ba725SjeanPerier } 635011ba725SjeanPerier // Split into two integer or floating point arguments. 636011ba725SjeanPerier // Note that for the first argument, this will always pick i64 or f64 which 637011ba725SjeanPerier // may be bigger than needed if some struct padding ends the first eight 638011ba725SjeanPerier // byte (e.g. for `{i32, f64}`). It is valid from an X86-64 ABI and 639011ba725SjeanPerier // semantic point of view, but it may not match the LLVM IR interface clang 640011ba725SjeanPerier // would produce for the equivalent C code (the assembly will still be 641011ba725SjeanPerier // compatible). This allows keeping the logic simpler here since it 642011ba725SjeanPerier // avoids computing the "data" size of the Lo part. 643011ba725SjeanPerier mlir::Type lowType = pickLLVMArgType(loc, recTy.getContext(), Lo, 8u); 644011ba725SjeanPerier mlir::Type hiType = 645011ba725SjeanPerier pickLLVMArgType(loc, recTy.getContext(), Hi, byteOffset - 8u); 646011ba725SjeanPerier CodeGenSpecifics::Marshalling marshal; 647011ba725SjeanPerier marshal.emplace_back(lowType, AT{}); 648011ba725SjeanPerier marshal.emplace_back(hiType, AT{}); 649011ba725SjeanPerier return marshal; 65027d9a479SjeanPerier } 65127d9a479SjeanPerier 652367c3c96SjeanPerier CodeGenSpecifics::Marshalling 653367c3c96SjeanPerier structReturnType(mlir::Location loc, fir::RecordType recTy) const override { 654367c3c96SjeanPerier std::uint64_t byteOffset = 0; 655367c3c96SjeanPerier ArgClass Lo, Hi; 656367c3c96SjeanPerier Lo = Hi = ArgClass::NoClass; 657367c3c96SjeanPerier byteOffset = classifyStruct(loc, recTy, byteOffset, Lo, Hi); 658367c3c96SjeanPerier mlir::MLIRContext *context = recTy.getContext(); 659367c3c96SjeanPerier postMerge(byteOffset, Lo, Hi); 660367c3c96SjeanPerier if (Lo == ArgClass::Memory) 661367c3c96SjeanPerier return passOnTheStack(loc, recTy, /*isResult=*/true); 662367c3c96SjeanPerier 663367c3c96SjeanPerier // Note that X87/ComplexX87 are passed in memory, but returned via %st0 664367c3c96SjeanPerier // %st1 registers. Here, they are returned as fp80 or {fp80, fp80} by 665367c3c96SjeanPerier // passAsFieldIfOneFieldStruct, and LLVM will use the expected registers. 666367c3c96SjeanPerier 667367c3c96SjeanPerier // Note that {_Complex long double} is not 100% clear from an ABI 668367c3c96SjeanPerier // perspective because the aggregate post merger rules say it should be 669367c3c96SjeanPerier // passed in memory because it is bigger than 2 eight bytes. This has the 670367c3c96SjeanPerier // funny effect of 671367c3c96SjeanPerier // {_Complex long double} return to be dealt with differently than 672367c3c96SjeanPerier // _Complex long double. 673367c3c96SjeanPerier 674367c3c96SjeanPerier if (auto fieldType = 675367c3c96SjeanPerier passAsFieldIfOneFieldStruct(recTy, /*allowComplex=*/true)) { 676367c3c96SjeanPerier if (auto complexType = mlir::dyn_cast<mlir::ComplexType>(fieldType)) 677367c3c96SjeanPerier return complexReturnType(loc, complexType.getElementType()); 678367c3c96SjeanPerier CodeGenSpecifics::Marshalling marshal; 679367c3c96SjeanPerier marshal.emplace_back(fieldType, AT{}); 680367c3c96SjeanPerier return marshal; 681367c3c96SjeanPerier } 682367c3c96SjeanPerier 683367c3c96SjeanPerier if (Hi == ArgClass::NoClass || Hi == ArgClass::SSEUp) { 684367c3c96SjeanPerier // Return a single integer or floating point argument. 685367c3c96SjeanPerier mlir::Type lowType = pickLLVMArgType(loc, context, Lo, byteOffset); 686367c3c96SjeanPerier CodeGenSpecifics::Marshalling marshal; 687367c3c96SjeanPerier marshal.emplace_back(lowType, AT{}); 688367c3c96SjeanPerier return marshal; 689367c3c96SjeanPerier } 690367c3c96SjeanPerier // Will be returned in two different registers. Generate {lowTy, HiTy} for 691367c3c96SjeanPerier // the LLVM IR result type. 692367c3c96SjeanPerier CodeGenSpecifics::Marshalling marshal; 693367c3c96SjeanPerier mlir::Type lowType = pickLLVMArgType(loc, context, Lo, 8u); 694367c3c96SjeanPerier mlir::Type hiType = pickLLVMArgType(loc, context, Hi, byteOffset - 8u); 695367c3c96SjeanPerier marshal.emplace_back(mlir::TupleType::get(context, {lowType, hiType}), 696367c3c96SjeanPerier AT{}); 697367c3c96SjeanPerier return marshal; 698367c3c96SjeanPerier } 699367c3c96SjeanPerier 70027d9a479SjeanPerier /// Marshal an argument that must be passed on the stack. 701367c3c96SjeanPerier CodeGenSpecifics::Marshalling 702367c3c96SjeanPerier passOnTheStack(mlir::Location loc, mlir::Type ty, bool isResult) const { 70327d9a479SjeanPerier CodeGenSpecifics::Marshalling marshal; 7043e47e75fSSlava Zakharin auto sizeAndAlign = 705d07dc73bSAbid Qadeer fir::getTypeSizeAndAlignmentOrCrash(loc, ty, getDataLayout(), kindMap); 70627d9a479SjeanPerier // The stack is always 8 byte aligned (note 14 in 3.2.3). 70727d9a479SjeanPerier unsigned short align = 70827d9a479SjeanPerier std::max(sizeAndAlign.second, static_cast<unsigned short>(8)); 70927d9a479SjeanPerier marshal.emplace_back(fir::ReferenceType::get(ty), 710367c3c96SjeanPerier AT{align, /*byval=*/!isResult, /*sret=*/isResult}); 71127d9a479SjeanPerier return marshal; 71227d9a479SjeanPerier } 7134c263edeSDiana Picus }; 7144c263edeSDiana Picus } // namespace 7154c263edeSDiana Picus 7164c263edeSDiana Picus //===----------------------------------------------------------------------===// 717774703ecSMarkus Mützel // x86_64 (x86 64 bit) Windows target specifics. 718774703ecSMarkus Mützel //===----------------------------------------------------------------------===// 719774703ecSMarkus Mützel 720774703ecSMarkus Mützel namespace { 721774703ecSMarkus Mützel struct TargetX86_64Win : public GenericTarget<TargetX86_64Win> { 722774703ecSMarkus Mützel using GenericTarget::GenericTarget; 723774703ecSMarkus Mützel 724774703ecSMarkus Mützel static constexpr int defaultWidth = 64; 725774703ecSMarkus Mützel 726774703ecSMarkus Mützel CodeGenSpecifics::Marshalling 727774703ecSMarkus Mützel complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 728774703ecSMarkus Mützel CodeGenSpecifics::Marshalling marshal; 729774703ecSMarkus Mützel const auto *sem = &floatToSemantics(kindMap, eleTy); 730774703ecSMarkus Mützel if (sem == &llvm::APFloat::IEEEsingle()) { 731774703ecSMarkus Mützel // i64 pack both floats in a 64-bit GPR 732774703ecSMarkus Mützel marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64), 733774703ecSMarkus Mützel AT{}); 734774703ecSMarkus Mützel } else if (sem == &llvm::APFloat::IEEEdouble()) { 735774703ecSMarkus Mützel // Use a type that will be translated into LLVM as: 736774703ecSMarkus Mützel // { double, double } struct of 2 double, byval, align 8 737774703ecSMarkus Mützel marshal.emplace_back( 738774703ecSMarkus Mützel fir::ReferenceType::get(mlir::TupleType::get( 739774703ecSMarkus Mützel eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 740774703ecSMarkus Mützel AT{/*align=*/8, /*byval=*/true}); 741774703ecSMarkus Mützel } else if (sem == &llvm::APFloat::IEEEquad() || 742774703ecSMarkus Mützel sem == &llvm::APFloat::x87DoubleExtended()) { 743774703ecSMarkus Mützel // Use a type that will be translated into LLVM as: 744774703ecSMarkus Mützel // { t, t } struct of 2 eleTy, byval, align 16 745774703ecSMarkus Mützel marshal.emplace_back( 746774703ecSMarkus Mützel fir::ReferenceType::get(mlir::TupleType::get( 747774703ecSMarkus Mützel eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 748774703ecSMarkus Mützel AT{/*align=*/16, /*byval=*/true}); 749774703ecSMarkus Mützel } else { 75004b18530SPete Steinfeld typeTodo(sem, loc, "argument"); 751774703ecSMarkus Mützel } 752774703ecSMarkus Mützel return marshal; 753774703ecSMarkus Mützel } 754774703ecSMarkus Mützel 755774703ecSMarkus Mützel CodeGenSpecifics::Marshalling 756774703ecSMarkus Mützel complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 757774703ecSMarkus Mützel CodeGenSpecifics::Marshalling marshal; 758774703ecSMarkus Mützel const auto *sem = &floatToSemantics(kindMap, eleTy); 759774703ecSMarkus Mützel if (sem == &llvm::APFloat::IEEEsingle()) { 760774703ecSMarkus Mützel // i64 pack both floats in a 64-bit GPR 761774703ecSMarkus Mützel marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64), 762774703ecSMarkus Mützel AT{}); 763774703ecSMarkus Mützel } else if (sem == &llvm::APFloat::IEEEdouble()) { 764774703ecSMarkus Mützel // Use a type that will be translated into LLVM as: 765774703ecSMarkus Mützel // { double, double } struct of 2 double, sret, align 8 766774703ecSMarkus Mützel marshal.emplace_back( 767774703ecSMarkus Mützel fir::ReferenceType::get(mlir::TupleType::get( 768774703ecSMarkus Mützel eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 769774703ecSMarkus Mützel AT{/*align=*/8, /*byval=*/false, /*sret=*/true}); 770774703ecSMarkus Mützel } else if (sem == &llvm::APFloat::IEEEquad() || 771774703ecSMarkus Mützel sem == &llvm::APFloat::x87DoubleExtended()) { 772774703ecSMarkus Mützel // Use a type that will be translated into LLVM as: 773774703ecSMarkus Mützel // { t, t } struct of 2 eleTy, sret, align 16 774774703ecSMarkus Mützel marshal.emplace_back( 775774703ecSMarkus Mützel fir::ReferenceType::get(mlir::TupleType::get( 776774703ecSMarkus Mützel eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 777774703ecSMarkus Mützel AT{/*align=*/16, /*byval=*/false, /*sret=*/true}); 778774703ecSMarkus Mützel } else { 77904b18530SPete Steinfeld typeTodo(sem, loc, "return"); 780774703ecSMarkus Mützel } 781774703ecSMarkus Mützel return marshal; 782774703ecSMarkus Mützel } 783774703ecSMarkus Mützel }; 784774703ecSMarkus Mützel } // namespace 785774703ecSMarkus Mützel 786774703ecSMarkus Mützel //===----------------------------------------------------------------------===// 7874c263edeSDiana Picus // AArch64 linux target specifics. 7884c263edeSDiana Picus //===----------------------------------------------------------------------===// 7894c263edeSDiana Picus 7904c263edeSDiana Picus namespace { 79144aa476aSDavid Truby // AArch64 procedure call standard: 79244aa476aSDavid Truby // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#parameter-passing 7934c263edeSDiana Picus struct TargetAArch64 : public GenericTarget<TargetAArch64> { 7944c263edeSDiana Picus using GenericTarget::GenericTarget; 7954c263edeSDiana Picus 7964c263edeSDiana Picus static constexpr int defaultWidth = 64; 79765431d3aSDiana Picus 79865431d3aSDiana Picus CodeGenSpecifics::Marshalling 7990c1cf585SEric Schweitz complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 80065431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal; 80165431d3aSDiana Picus const auto *sem = &floatToSemantics(kindMap, eleTy); 80265431d3aSDiana Picus if (sem == &llvm::APFloat::IEEEsingle() || 803d7428722SKiran Chandramohan sem == &llvm::APFloat::IEEEdouble() || 804d7428722SKiran Chandramohan sem == &llvm::APFloat::IEEEquad()) { 80565431d3aSDiana Picus // [2 x t] array of 2 eleTy 80665431d3aSDiana Picus marshal.emplace_back(fir::SequenceType::get({2}, eleTy), AT{}); 80765431d3aSDiana Picus } else { 80804b18530SPete Steinfeld typeTodo(sem, loc, "argument"); 80965431d3aSDiana Picus } 81065431d3aSDiana Picus return marshal; 81165431d3aSDiana Picus } 81265431d3aSDiana Picus 81365431d3aSDiana Picus CodeGenSpecifics::Marshalling 8140c1cf585SEric Schweitz complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 81565431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal; 81665431d3aSDiana Picus const auto *sem = &floatToSemantics(kindMap, eleTy); 81765431d3aSDiana Picus if (sem == &llvm::APFloat::IEEEsingle() || 818d7428722SKiran Chandramohan sem == &llvm::APFloat::IEEEdouble() || 819d7428722SKiran Chandramohan sem == &llvm::APFloat::IEEEquad()) { 820faf869dcSDiana Picus // Use a type that will be translated into LLVM as: 821faf869dcSDiana Picus // { t, t } struct of 2 eleTy 822ff794116SSlava Zakharin marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), 823ff794116SSlava Zakharin mlir::TypeRange{eleTy, eleTy}), 82465431d3aSDiana Picus AT{}); 82565431d3aSDiana Picus } else { 82604b18530SPete Steinfeld typeTodo(sem, loc, "return"); 82765431d3aSDiana Picus } 82865431d3aSDiana Picus return marshal; 82965431d3aSDiana Picus } 8302d62daabSDavid Truby 83144aa476aSDavid Truby // Flatten a RecordType::TypeList containing more record types or array type 8322d62daabSDavid Truby static std::optional<std::vector<mlir::Type>> 8332d62daabSDavid Truby flattenTypeList(const RecordType::TypeList &types) { 8342d62daabSDavid Truby std::vector<mlir::Type> flatTypes; 8352d62daabSDavid Truby // The flat list will be at least the same size as the non-flat list. 8362d62daabSDavid Truby flatTypes.reserve(types.size()); 8372d62daabSDavid Truby for (auto [c, type] : types) { 8382d62daabSDavid Truby // Flatten record type 8392d62daabSDavid Truby if (auto recTy = mlir::dyn_cast<RecordType>(type)) { 8402d62daabSDavid Truby auto subTypeList = flattenTypeList(recTy.getTypeList()); 8412d62daabSDavid Truby if (!subTypeList) 8422d62daabSDavid Truby return std::nullopt; 8432d62daabSDavid Truby llvm::copy(*subTypeList, std::back_inserter(flatTypes)); 8442d62daabSDavid Truby continue; 8452d62daabSDavid Truby } 8462d62daabSDavid Truby 8472d62daabSDavid Truby // Flatten array type 8482d62daabSDavid Truby if (auto seqTy = mlir::dyn_cast<SequenceType>(type)) { 8492d62daabSDavid Truby if (seqTy.hasDynamicExtents()) 8502d62daabSDavid Truby return std::nullopt; 8512d62daabSDavid Truby std::size_t n = seqTy.getConstantArraySize(); 8522d62daabSDavid Truby auto eleTy = seqTy.getElementType(); 8532d62daabSDavid Truby // Flatten array of record types 8542d62daabSDavid Truby if (auto recTy = mlir::dyn_cast<RecordType>(eleTy)) { 8552d62daabSDavid Truby auto subTypeList = flattenTypeList(recTy.getTypeList()); 8562d62daabSDavid Truby if (!subTypeList) 8572d62daabSDavid Truby return std::nullopt; 8582d62daabSDavid Truby for (std::size_t i = 0; i < n; ++i) 8592d62daabSDavid Truby llvm::copy(*subTypeList, std::back_inserter(flatTypes)); 8602d62daabSDavid Truby } else { 8612d62daabSDavid Truby std::fill_n(std::back_inserter(flatTypes), 8622d62daabSDavid Truby seqTy.getConstantArraySize(), eleTy); 8632d62daabSDavid Truby } 8642d62daabSDavid Truby continue; 8652d62daabSDavid Truby } 8662d62daabSDavid Truby 8672d62daabSDavid Truby // Other types are already flat 8682d62daabSDavid Truby flatTypes.push_back(type); 8692d62daabSDavid Truby } 8702d62daabSDavid Truby return flatTypes; 8712d62daabSDavid Truby } 8722d62daabSDavid Truby 8732d62daabSDavid Truby // Determine if the type is a Homogenous Floating-point Aggregate (HFA). An 8742d62daabSDavid Truby // HFA is a record type with up to 4 floating-point members of the same type. 87544aa476aSDavid Truby static std::optional<int> usedRegsForHFA(fir::RecordType ty) { 8762d62daabSDavid Truby RecordType::TypeList types = ty.getTypeList(); 8772d62daabSDavid Truby if (types.empty() || types.size() > 4) 87844aa476aSDavid Truby return std::nullopt; 8792d62daabSDavid Truby 8802d62daabSDavid Truby std::optional<std::vector<mlir::Type>> flatTypes = flattenTypeList(types); 8812d62daabSDavid Truby if (!flatTypes || flatTypes->size() > 4) { 88244aa476aSDavid Truby return std::nullopt; 8832d62daabSDavid Truby } 8842d62daabSDavid Truby 8852d62daabSDavid Truby if (!isa_real(flatTypes->front())) { 88644aa476aSDavid Truby return std::nullopt; 8872d62daabSDavid Truby } 8882d62daabSDavid Truby 88944aa476aSDavid Truby return llvm::all_equal(*flatTypes) ? std::optional<int>{flatTypes->size()} 89044aa476aSDavid Truby : std::nullopt; 8912d62daabSDavid Truby } 8922d62daabSDavid Truby 89344aa476aSDavid Truby struct NRegs { 89444aa476aSDavid Truby int n{0}; 89544aa476aSDavid Truby bool isSimd{false}; 89644aa476aSDavid Truby }; 89744aa476aSDavid Truby 89844aa476aSDavid Truby NRegs usedRegsForRecordType(mlir::Location loc, fir::RecordType type) const { 89944aa476aSDavid Truby if (std::optional<int> size = usedRegsForHFA(type)) 90044aa476aSDavid Truby return {*size, true}; 90144aa476aSDavid Truby 90244aa476aSDavid Truby auto [size, align] = fir::getTypeSizeAndAlignmentOrCrash( 90344aa476aSDavid Truby loc, type, getDataLayout(), kindMap); 90444aa476aSDavid Truby 90544aa476aSDavid Truby if (size <= 16) 90644aa476aSDavid Truby return {static_cast<int>((size + 7) / 8), false}; 90744aa476aSDavid Truby 90844aa476aSDavid Truby // Pass on the stack, i.e. no registers used 90944aa476aSDavid Truby return {}; 91044aa476aSDavid Truby } 91144aa476aSDavid Truby 91244aa476aSDavid Truby NRegs usedRegsForType(mlir::Location loc, mlir::Type type) const { 91344aa476aSDavid Truby return llvm::TypeSwitch<mlir::Type, NRegs>(type) 91444aa476aSDavid Truby .Case<mlir::IntegerType>([&](auto intTy) { 91544aa476aSDavid Truby return intTy.getWidth() == 128 ? NRegs{2, false} : NRegs{1, false}; 91644aa476aSDavid Truby }) 91744aa476aSDavid Truby .Case<mlir::FloatType>([&](auto) { return NRegs{1, true}; }) 91844aa476aSDavid Truby .Case<mlir::ComplexType>([&](auto) { return NRegs{2, true}; }) 91944aa476aSDavid Truby .Case<fir::LogicalType>([&](auto) { return NRegs{1, false}; }) 92044aa476aSDavid Truby .Case<fir::CharacterType>([&](auto) { return NRegs{1, false}; }) 92144aa476aSDavid Truby .Case<fir::SequenceType>([&](auto ty) { 92244aa476aSDavid Truby assert(ty.getShape().size() == 1 && 92344aa476aSDavid Truby "invalid array dimensions in BIND(C)"); 92444aa476aSDavid Truby NRegs nregs = usedRegsForType(loc, ty.getEleTy()); 92544aa476aSDavid Truby nregs.n *= ty.getShape()[0]; 92644aa476aSDavid Truby return nregs; 92744aa476aSDavid Truby }) 92844aa476aSDavid Truby .Case<fir::RecordType>( 92944aa476aSDavid Truby [&](auto ty) { return usedRegsForRecordType(loc, ty); }) 93044aa476aSDavid Truby .Case<fir::VectorType>([&](auto) { 93144aa476aSDavid Truby TODO(loc, "passing vector argument to C by value is not supported"); 93244aa476aSDavid Truby return NRegs{}; 93344aa476aSDavid Truby }); 93444aa476aSDavid Truby } 93544aa476aSDavid Truby 93644aa476aSDavid Truby bool hasEnoughRegisters(mlir::Location loc, fir::RecordType type, 93744aa476aSDavid Truby const Marshalling &previousArguments) const { 93844aa476aSDavid Truby int availIntRegisters = 8; 93944aa476aSDavid Truby int availSIMDRegisters = 8; 94044aa476aSDavid Truby 94144aa476aSDavid Truby // Check previous arguments to see how many registers are used already 94244aa476aSDavid Truby for (auto [type, attr] : previousArguments) { 94344aa476aSDavid Truby if (availIntRegisters <= 0 || availSIMDRegisters <= 0) 94444aa476aSDavid Truby break; 94544aa476aSDavid Truby 94644aa476aSDavid Truby if (attr.isByVal()) 94744aa476aSDavid Truby continue; // Previous argument passed on the stack 94844aa476aSDavid Truby 94944aa476aSDavid Truby NRegs nregs = usedRegsForType(loc, type); 95044aa476aSDavid Truby if (nregs.isSimd) 95144aa476aSDavid Truby availSIMDRegisters -= nregs.n; 95244aa476aSDavid Truby else 95344aa476aSDavid Truby availIntRegisters -= nregs.n; 95444aa476aSDavid Truby } 95544aa476aSDavid Truby 95644aa476aSDavid Truby NRegs nregs = usedRegsForRecordType(loc, type); 95744aa476aSDavid Truby 95844aa476aSDavid Truby if (nregs.isSimd) 95944aa476aSDavid Truby return nregs.n <= availSIMDRegisters; 96044aa476aSDavid Truby 96144aa476aSDavid Truby return nregs.n <= availIntRegisters; 96244aa476aSDavid Truby } 96344aa476aSDavid Truby 9642d62daabSDavid Truby CodeGenSpecifics::Marshalling 96544aa476aSDavid Truby passOnTheStack(mlir::Location loc, mlir::Type ty, bool isResult) const { 96644aa476aSDavid Truby CodeGenSpecifics::Marshalling marshal; 96744aa476aSDavid Truby auto sizeAndAlign = 96844aa476aSDavid Truby fir::getTypeSizeAndAlignmentOrCrash(loc, ty, getDataLayout(), kindMap); 96944aa476aSDavid Truby // The stack is always 8 byte aligned 97044aa476aSDavid Truby unsigned short align = 97144aa476aSDavid Truby std::max(sizeAndAlign.second, static_cast<unsigned short>(8)); 97244aa476aSDavid Truby marshal.emplace_back(fir::ReferenceType::get(ty), 97344aa476aSDavid Truby AT{align, /*byval=*/!isResult, /*sret=*/isResult}); 97444aa476aSDavid Truby return marshal; 97544aa476aSDavid Truby } 97644aa476aSDavid Truby 97744aa476aSDavid Truby CodeGenSpecifics::Marshalling 97844aa476aSDavid Truby structType(mlir::Location loc, fir::RecordType type, bool isResult) const { 97944aa476aSDavid Truby NRegs nregs = usedRegsForRecordType(loc, type); 98044aa476aSDavid Truby 98144aa476aSDavid Truby // If the type needs no registers it must need to be passed on the stack 98244aa476aSDavid Truby if (nregs.n == 0) 98344aa476aSDavid Truby return passOnTheStack(loc, type, isResult); 98444aa476aSDavid Truby 9852d62daabSDavid Truby CodeGenSpecifics::Marshalling marshal; 9862d62daabSDavid Truby 98744aa476aSDavid Truby mlir::Type pcsType; 98844aa476aSDavid Truby if (nregs.isSimd) { 98944aa476aSDavid Truby pcsType = type; 99044aa476aSDavid Truby } else { 99144aa476aSDavid Truby pcsType = fir::SequenceType::get( 99244aa476aSDavid Truby nregs.n, mlir::IntegerType::get(type.getContext(), 64)); 99344aa476aSDavid Truby } 99444aa476aSDavid Truby 99544aa476aSDavid Truby marshal.emplace_back(pcsType, AT{}); 9962d62daabSDavid Truby return marshal; 9972d62daabSDavid Truby } 9982d62daabSDavid Truby 99944aa476aSDavid Truby CodeGenSpecifics::Marshalling 100044aa476aSDavid Truby structArgumentType(mlir::Location loc, fir::RecordType ty, 100144aa476aSDavid Truby const Marshalling &previousArguments) const override { 100244aa476aSDavid Truby if (!hasEnoughRegisters(loc, ty, previousArguments)) { 100344aa476aSDavid Truby return passOnTheStack(loc, ty, /*isResult=*/false); 10042d62daabSDavid Truby } 10052d62daabSDavid Truby 100644aa476aSDavid Truby return structType(loc, ty, /*isResult=*/false); 100744aa476aSDavid Truby } 100844aa476aSDavid Truby 100944aa476aSDavid Truby CodeGenSpecifics::Marshalling 101044aa476aSDavid Truby structReturnType(mlir::Location loc, fir::RecordType ty) const override { 101144aa476aSDavid Truby return structType(loc, ty, /*isResult=*/true); 10122d62daabSDavid Truby } 10134c263edeSDiana Picus }; 10144c263edeSDiana Picus } // namespace 10154c263edeSDiana Picus 10164c263edeSDiana Picus //===----------------------------------------------------------------------===// 1017320fbff4SMark Danial // PPC64 (AIX 64 bit) target specifics. 1018320fbff4SMark Danial //===----------------------------------------------------------------------===// 1019320fbff4SMark Danial 1020320fbff4SMark Danial namespace { 1021320fbff4SMark Danial struct TargetPPC64 : public GenericTarget<TargetPPC64> { 1022320fbff4SMark Danial using GenericTarget::GenericTarget; 1023320fbff4SMark Danial 1024320fbff4SMark Danial static constexpr int defaultWidth = 64; 1025320fbff4SMark Danial 1026320fbff4SMark Danial CodeGenSpecifics::Marshalling 1027320fbff4SMark Danial complexArgumentType(mlir::Location, mlir::Type eleTy) const override { 1028320fbff4SMark Danial CodeGenSpecifics::Marshalling marshal; 1029320fbff4SMark Danial // two distinct element type arguments (re, im) 1030320fbff4SMark Danial marshal.emplace_back(eleTy, AT{}); 1031320fbff4SMark Danial marshal.emplace_back(eleTy, AT{}); 1032320fbff4SMark Danial return marshal; 1033320fbff4SMark Danial } 1034320fbff4SMark Danial 1035320fbff4SMark Danial CodeGenSpecifics::Marshalling 1036320fbff4SMark Danial complexReturnType(mlir::Location, mlir::Type eleTy) const override { 1037320fbff4SMark Danial CodeGenSpecifics::Marshalling marshal; 1038320fbff4SMark Danial // Use a type that will be translated into LLVM as: 1039320fbff4SMark Danial // { t, t } struct of 2 element type 1040ff794116SSlava Zakharin marshal.emplace_back( 1041ff794116SSlava Zakharin mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}), 1042ff794116SSlava Zakharin AT{}); 1043320fbff4SMark Danial return marshal; 1044320fbff4SMark Danial } 1045320fbff4SMark Danial }; 1046320fbff4SMark Danial } // namespace 1047320fbff4SMark Danial 1048320fbff4SMark Danial //===----------------------------------------------------------------------===// 10494c263edeSDiana Picus // PPC64le linux target specifics. 10504c263edeSDiana Picus //===----------------------------------------------------------------------===// 10514c263edeSDiana Picus 10524c263edeSDiana Picus namespace { 10534c263edeSDiana Picus struct TargetPPC64le : public GenericTarget<TargetPPC64le> { 10544c263edeSDiana Picus using GenericTarget::GenericTarget; 10554c263edeSDiana Picus 10564c263edeSDiana Picus static constexpr int defaultWidth = 64; 105765431d3aSDiana Picus 105865431d3aSDiana Picus CodeGenSpecifics::Marshalling 10590c1cf585SEric Schweitz complexArgumentType(mlir::Location, mlir::Type eleTy) const override { 106065431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal; 106165431d3aSDiana Picus // two distinct element type arguments (re, im) 106265431d3aSDiana Picus marshal.emplace_back(eleTy, AT{}); 106365431d3aSDiana Picus marshal.emplace_back(eleTy, AT{}); 106465431d3aSDiana Picus return marshal; 106565431d3aSDiana Picus } 106665431d3aSDiana Picus 106765431d3aSDiana Picus CodeGenSpecifics::Marshalling 10680c1cf585SEric Schweitz complexReturnType(mlir::Location, mlir::Type eleTy) const override { 106965431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal; 1070faf869dcSDiana Picus // Use a type that will be translated into LLVM as: 1071faf869dcSDiana Picus // { t, t } struct of 2 element type 1072ff794116SSlava Zakharin marshal.emplace_back( 1073ff794116SSlava Zakharin mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}), 1074ff794116SSlava Zakharin AT{}); 107565431d3aSDiana Picus return marshal; 107665431d3aSDiana Picus } 10774c263edeSDiana Picus }; 10784c263edeSDiana Picus } // namespace 10794c263edeSDiana Picus 10801774a8a7SRainer Orth //===----------------------------------------------------------------------===// 10811774a8a7SRainer Orth // sparc (sparc 32 bit) target specifics. 10821774a8a7SRainer Orth //===----------------------------------------------------------------------===// 10831774a8a7SRainer Orth 10841774a8a7SRainer Orth namespace { 10851774a8a7SRainer Orth struct TargetSparc : public GenericTarget<TargetSparc> { 10861774a8a7SRainer Orth using GenericTarget::GenericTarget; 10871774a8a7SRainer Orth 10881774a8a7SRainer Orth static constexpr int defaultWidth = 32; 10891774a8a7SRainer Orth 10901774a8a7SRainer Orth CodeGenSpecifics::Marshalling 10911774a8a7SRainer Orth complexArgumentType(mlir::Location, mlir::Type eleTy) const override { 10921774a8a7SRainer Orth assert(fir::isa_real(eleTy)); 10931774a8a7SRainer Orth CodeGenSpecifics::Marshalling marshal; 10941774a8a7SRainer Orth // Use a type that will be translated into LLVM as: 10951774a8a7SRainer Orth // { t, t } struct of 2 eleTy 1096ff794116SSlava Zakharin auto structTy = 1097ff794116SSlava Zakharin mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}); 10981774a8a7SRainer Orth marshal.emplace_back(fir::ReferenceType::get(structTy), AT{}); 10991774a8a7SRainer Orth return marshal; 11001774a8a7SRainer Orth } 11011774a8a7SRainer Orth 11021774a8a7SRainer Orth CodeGenSpecifics::Marshalling 11031774a8a7SRainer Orth complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 11041774a8a7SRainer Orth assert(fir::isa_real(eleTy)); 11051774a8a7SRainer Orth CodeGenSpecifics::Marshalling marshal; 11061774a8a7SRainer Orth // Use a type that will be translated into LLVM as: 11071774a8a7SRainer Orth // { t, t } struct of 2 eleTy, byval 1108ff794116SSlava Zakharin auto structTy = 1109ff794116SSlava Zakharin mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}); 11101774a8a7SRainer Orth marshal.emplace_back(fir::ReferenceType::get(structTy), 11111774a8a7SRainer Orth AT{/*alignment=*/0, /*byval=*/true}); 11121774a8a7SRainer Orth return marshal; 11131774a8a7SRainer Orth } 11141774a8a7SRainer Orth }; 11151774a8a7SRainer Orth } // namespace 11161774a8a7SRainer Orth 11171774a8a7SRainer Orth //===----------------------------------------------------------------------===// 11181774a8a7SRainer Orth // sparcv9 (sparc 64 bit) target specifics. 11191774a8a7SRainer Orth //===----------------------------------------------------------------------===// 11201774a8a7SRainer Orth 11211774a8a7SRainer Orth namespace { 11221774a8a7SRainer Orth struct TargetSparcV9 : public GenericTarget<TargetSparcV9> { 11231774a8a7SRainer Orth using GenericTarget::GenericTarget; 11241774a8a7SRainer Orth 11251774a8a7SRainer Orth static constexpr int defaultWidth = 64; 11261774a8a7SRainer Orth 11271774a8a7SRainer Orth CodeGenSpecifics::Marshalling 11281774a8a7SRainer Orth complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 11291774a8a7SRainer Orth CodeGenSpecifics::Marshalling marshal; 11301774a8a7SRainer Orth const auto *sem = &floatToSemantics(kindMap, eleTy); 11311774a8a7SRainer Orth if (sem == &llvm::APFloat::IEEEsingle() || 11321774a8a7SRainer Orth sem == &llvm::APFloat::IEEEdouble()) { 11331774a8a7SRainer Orth // two distinct float, double arguments 11341774a8a7SRainer Orth marshal.emplace_back(eleTy, AT{}); 11351774a8a7SRainer Orth marshal.emplace_back(eleTy, AT{}); 11361774a8a7SRainer Orth } else if (sem == &llvm::APFloat::IEEEquad()) { 11371774a8a7SRainer Orth // Use a type that will be translated into LLVM as: 11381774a8a7SRainer Orth // { fp128, fp128 } struct of 2 fp128, byval, align 16 1139ff794116SSlava Zakharin marshal.emplace_back( 1140ff794116SSlava Zakharin fir::ReferenceType::get(mlir::TupleType::get( 1141ff794116SSlava Zakharin eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 11421774a8a7SRainer Orth AT{/*align=*/16, /*byval=*/true}); 11431774a8a7SRainer Orth } else { 114404b18530SPete Steinfeld typeTodo(sem, loc, "argument"); 11451774a8a7SRainer Orth } 11461774a8a7SRainer Orth return marshal; 11471774a8a7SRainer Orth } 11481774a8a7SRainer Orth 11491774a8a7SRainer Orth CodeGenSpecifics::Marshalling 11501774a8a7SRainer Orth complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 11511774a8a7SRainer Orth CodeGenSpecifics::Marshalling marshal; 11521774a8a7SRainer Orth // Use a type that will be translated into LLVM as: 11531774a8a7SRainer Orth // { eleTy, eleTy } struct of 2 eleTy 1154ff794116SSlava Zakharin marshal.emplace_back( 1155ff794116SSlava Zakharin mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy}), 1156ff794116SSlava Zakharin AT{}); 11571774a8a7SRainer Orth return marshal; 11581774a8a7SRainer Orth } 11591774a8a7SRainer Orth }; 11601774a8a7SRainer Orth } // namespace 11611774a8a7SRainer Orth 1162bac88e89SQihan Cai //===----------------------------------------------------------------------===// 1163bac88e89SQihan Cai // RISCV64 linux target specifics. 1164bac88e89SQihan Cai //===----------------------------------------------------------------------===// 1165bac88e89SQihan Cai 1166bac88e89SQihan Cai namespace { 1167bac88e89SQihan Cai struct TargetRISCV64 : public GenericTarget<TargetRISCV64> { 1168bac88e89SQihan Cai using GenericTarget::GenericTarget; 1169bac88e89SQihan Cai 1170bac88e89SQihan Cai static constexpr int defaultWidth = 64; 1171bac88e89SQihan Cai 1172bac88e89SQihan Cai CodeGenSpecifics::Marshalling 1173bac88e89SQihan Cai complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 1174bac88e89SQihan Cai CodeGenSpecifics::Marshalling marshal; 1175bac88e89SQihan Cai const auto *sem = &floatToSemantics(kindMap, eleTy); 1176bac88e89SQihan Cai if (sem == &llvm::APFloat::IEEEsingle() || 1177bac88e89SQihan Cai sem == &llvm::APFloat::IEEEdouble()) { 1178bac88e89SQihan Cai // Two distinct element type arguments (re, im) 1179bac88e89SQihan Cai marshal.emplace_back(eleTy, AT{}); 1180bac88e89SQihan Cai marshal.emplace_back(eleTy, AT{}); 1181bac88e89SQihan Cai } else { 118204b18530SPete Steinfeld typeTodo(sem, loc, "argument"); 1183bac88e89SQihan Cai } 1184bac88e89SQihan Cai return marshal; 1185bac88e89SQihan Cai } 1186bac88e89SQihan Cai 1187bac88e89SQihan Cai CodeGenSpecifics::Marshalling 1188bac88e89SQihan Cai complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 1189bac88e89SQihan Cai CodeGenSpecifics::Marshalling marshal; 1190bac88e89SQihan Cai const auto *sem = &floatToSemantics(kindMap, eleTy); 1191bac88e89SQihan Cai if (sem == &llvm::APFloat::IEEEsingle() || 1192bac88e89SQihan Cai sem == &llvm::APFloat::IEEEdouble()) { 1193bac88e89SQihan Cai // Use a type that will be translated into LLVM as: 1194bac88e89SQihan Cai // { t, t } struct of 2 eleTy, byVal 1195ff794116SSlava Zakharin marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), 1196ff794116SSlava Zakharin mlir::TypeRange{eleTy, eleTy}), 1197bac88e89SQihan Cai AT{/*alignment=*/0, /*byval=*/true}); 1198bac88e89SQihan Cai } else { 119904b18530SPete Steinfeld typeTodo(sem, loc, "return"); 1200bac88e89SQihan Cai } 1201bac88e89SQihan Cai return marshal; 1202bac88e89SQihan Cai } 1203bac88e89SQihan Cai }; 1204bac88e89SQihan Cai } // namespace 1205bac88e89SQihan Cai 120608749a91SJan Sjodin //===----------------------------------------------------------------------===// 120708749a91SJan Sjodin // AMDGPU linux target specifics. 120808749a91SJan Sjodin //===----------------------------------------------------------------------===// 120908749a91SJan Sjodin 121008749a91SJan Sjodin namespace { 121108749a91SJan Sjodin struct TargetAMDGPU : public GenericTarget<TargetAMDGPU> { 121208749a91SJan Sjodin using GenericTarget::GenericTarget; 121308749a91SJan Sjodin 121408749a91SJan Sjodin // Default size (in bits) of the index type for strings. 121508749a91SJan Sjodin static constexpr int defaultWidth = 64; 121608749a91SJan Sjodin 121708749a91SJan Sjodin CodeGenSpecifics::Marshalling 121808749a91SJan Sjodin complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 121908749a91SJan Sjodin CodeGenSpecifics::Marshalling marshal; 122008749a91SJan Sjodin TODO(loc, "handle complex argument types"); 122108749a91SJan Sjodin return marshal; 122208749a91SJan Sjodin } 122308749a91SJan Sjodin 122408749a91SJan Sjodin CodeGenSpecifics::Marshalling 122508749a91SJan Sjodin complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 122608749a91SJan Sjodin CodeGenSpecifics::Marshalling marshal; 122708749a91SJan Sjodin TODO(loc, "handle complex return types"); 122808749a91SJan Sjodin return marshal; 122908749a91SJan Sjodin } 123008749a91SJan Sjodin }; 123108749a91SJan Sjodin } // namespace 123208749a91SJan Sjodin 1233720f728dSWeining Lu //===----------------------------------------------------------------------===// 1234be9fa9deSFabian Mora // NVPTX linux target specifics. 1235be9fa9deSFabian Mora //===----------------------------------------------------------------------===// 1236be9fa9deSFabian Mora 1237be9fa9deSFabian Mora namespace { 1238be9fa9deSFabian Mora struct TargetNVPTX : public GenericTarget<TargetNVPTX> { 1239be9fa9deSFabian Mora using GenericTarget::GenericTarget; 1240be9fa9deSFabian Mora 1241be9fa9deSFabian Mora // Default size (in bits) of the index type for strings. 1242be9fa9deSFabian Mora static constexpr int defaultWidth = 64; 1243be9fa9deSFabian Mora 1244be9fa9deSFabian Mora CodeGenSpecifics::Marshalling 1245be9fa9deSFabian Mora complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 1246be9fa9deSFabian Mora CodeGenSpecifics::Marshalling marshal; 1247be9fa9deSFabian Mora TODO(loc, "handle complex argument types"); 1248be9fa9deSFabian Mora return marshal; 1249be9fa9deSFabian Mora } 1250be9fa9deSFabian Mora 1251be9fa9deSFabian Mora CodeGenSpecifics::Marshalling 1252be9fa9deSFabian Mora complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 1253be9fa9deSFabian Mora CodeGenSpecifics::Marshalling marshal; 1254be9fa9deSFabian Mora TODO(loc, "handle complex return types"); 1255be9fa9deSFabian Mora return marshal; 1256be9fa9deSFabian Mora } 1257be9fa9deSFabian Mora }; 1258be9fa9deSFabian Mora } // namespace 1259be9fa9deSFabian Mora 1260be9fa9deSFabian Mora //===----------------------------------------------------------------------===// 1261720f728dSWeining Lu // LoongArch64 linux target specifics. 1262720f728dSWeining Lu //===----------------------------------------------------------------------===// 1263720f728dSWeining Lu 1264720f728dSWeining Lu namespace { 1265720f728dSWeining Lu struct TargetLoongArch64 : public GenericTarget<TargetLoongArch64> { 1266720f728dSWeining Lu using GenericTarget::GenericTarget; 1267720f728dSWeining Lu 1268720f728dSWeining Lu static constexpr int defaultWidth = 64; 1269dab9fa2dSZhaoxin Yang static constexpr int GRLen = defaultWidth; /* eight bytes */ 1270dab9fa2dSZhaoxin Yang static constexpr int GRLenInChar = GRLen / 8; 1271dab9fa2dSZhaoxin Yang static constexpr int FRLen = defaultWidth; /* eight bytes */ 1272720f728dSWeining Lu 1273720f728dSWeining Lu CodeGenSpecifics::Marshalling 1274720f728dSWeining Lu complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override { 1275720f728dSWeining Lu CodeGenSpecifics::Marshalling marshal; 1276720f728dSWeining Lu const auto *sem = &floatToSemantics(kindMap, eleTy); 1277720f728dSWeining Lu if (sem == &llvm::APFloat::IEEEsingle() || 1278720f728dSWeining Lu sem == &llvm::APFloat::IEEEdouble()) { 1279720f728dSWeining Lu // Two distinct element type arguments (re, im) 1280720f728dSWeining Lu marshal.emplace_back(eleTy, AT{}); 1281720f728dSWeining Lu marshal.emplace_back(eleTy, AT{}); 128220b442a2SZhaoxin Yang } else if (sem == &llvm::APFloat::IEEEquad()) { 128320b442a2SZhaoxin Yang // Use a type that will be translated into LLVM as: 128420b442a2SZhaoxin Yang // { fp128, fp128 } struct of 2 fp128, byval 128520b442a2SZhaoxin Yang marshal.emplace_back( 128620b442a2SZhaoxin Yang fir::ReferenceType::get(mlir::TupleType::get( 128720b442a2SZhaoxin Yang eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 128820b442a2SZhaoxin Yang AT{/*align=*/16, /*byval=*/true}); 1289720f728dSWeining Lu } else { 129004b18530SPete Steinfeld typeTodo(sem, loc, "argument"); 1291720f728dSWeining Lu } 1292720f728dSWeining Lu return marshal; 1293720f728dSWeining Lu } 1294720f728dSWeining Lu 1295720f728dSWeining Lu CodeGenSpecifics::Marshalling 1296720f728dSWeining Lu complexReturnType(mlir::Location loc, mlir::Type eleTy) const override { 1297720f728dSWeining Lu CodeGenSpecifics::Marshalling marshal; 1298720f728dSWeining Lu const auto *sem = &floatToSemantics(kindMap, eleTy); 1299720f728dSWeining Lu if (sem == &llvm::APFloat::IEEEsingle() || 1300720f728dSWeining Lu sem == &llvm::APFloat::IEEEdouble()) { 1301720f728dSWeining Lu // Use a type that will be translated into LLVM as: 1302720f728dSWeining Lu // { t, t } struct of 2 eleTy, byVal 1303720f728dSWeining Lu marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), 1304720f728dSWeining Lu mlir::TypeRange{eleTy, eleTy}), 1305720f728dSWeining Lu AT{/*alignment=*/0, /*byval=*/true}); 130620b442a2SZhaoxin Yang } else if (sem == &llvm::APFloat::IEEEquad()) { 130720b442a2SZhaoxin Yang // Use a type that will be translated into LLVM as: 130820b442a2SZhaoxin Yang // { fp128, fp128 } struct of 2 fp128, sret, align 16 130920b442a2SZhaoxin Yang marshal.emplace_back( 131020b442a2SZhaoxin Yang fir::ReferenceType::get(mlir::TupleType::get( 131120b442a2SZhaoxin Yang eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})), 131220b442a2SZhaoxin Yang AT{/*align=*/16, /*byval=*/false, /*sret=*/true}); 1313720f728dSWeining Lu } else { 131404b18530SPete Steinfeld typeTodo(sem, loc, "return"); 1315720f728dSWeining Lu } 1316720f728dSWeining Lu return marshal; 1317720f728dSWeining Lu } 1318b24acc06SZhaoxin Yang 1319b24acc06SZhaoxin Yang CodeGenSpecifics::Marshalling 1320b24acc06SZhaoxin Yang integerArgumentType(mlir::Location loc, 1321b24acc06SZhaoxin Yang mlir::IntegerType argTy) const override { 1322b24acc06SZhaoxin Yang if (argTy.getWidth() == 32) { 1323b24acc06SZhaoxin Yang // LA64 LP64D ABI requires unsigned 32 bit integers to be sign extended. 1324b24acc06SZhaoxin Yang // Therefore, Flang also follows it if a function needs to be 1325b24acc06SZhaoxin Yang // interoperable with C. 1326b24acc06SZhaoxin Yang // 1327b24acc06SZhaoxin Yang // Currently, it only adds `signext` attribute to the dummy arguments and 1328b24acc06SZhaoxin Yang // return values in the function signatures, but it does not add the 1329b24acc06SZhaoxin Yang // corresponding attribute to the actual arguments and return values in 1330b24acc06SZhaoxin Yang // `fir.call` instruction. Thanks to LLVM's integration of all these 1331b24acc06SZhaoxin Yang // attributes, the modification is still effective. 1332b24acc06SZhaoxin Yang CodeGenSpecifics::Marshalling marshal; 1333b24acc06SZhaoxin Yang AT::IntegerExtension intExt = AT::IntegerExtension::Sign; 1334b24acc06SZhaoxin Yang marshal.emplace_back(argTy, AT{/*alignment=*/0, /*byval=*/false, 1335b24acc06SZhaoxin Yang /*sret=*/false, /*append=*/false, 1336b24acc06SZhaoxin Yang /*intExt=*/intExt}); 1337b24acc06SZhaoxin Yang return marshal; 1338b24acc06SZhaoxin Yang } 1339b24acc06SZhaoxin Yang 1340b24acc06SZhaoxin Yang return GenericTarget::integerArgumentType(loc, argTy); 1341b24acc06SZhaoxin Yang } 1342dab9fa2dSZhaoxin Yang 1343dab9fa2dSZhaoxin Yang /// Flatten non-basic types, resulting in an array of types containing only 1344dab9fa2dSZhaoxin Yang /// `IntegerType` and `FloatType`. 1345dab9fa2dSZhaoxin Yang llvm::SmallVector<mlir::Type> flattenTypeList(mlir::Location loc, 1346dab9fa2dSZhaoxin Yang const mlir::Type type) const { 1347dab9fa2dSZhaoxin Yang llvm::SmallVector<mlir::Type> flatTypes; 1348dab9fa2dSZhaoxin Yang 1349dab9fa2dSZhaoxin Yang llvm::TypeSwitch<mlir::Type>(type) 1350dab9fa2dSZhaoxin Yang .template Case<mlir::IntegerType>([&](mlir::IntegerType intTy) { 1351dab9fa2dSZhaoxin Yang if (intTy.getWidth() != 0) 1352dab9fa2dSZhaoxin Yang flatTypes.push_back(intTy); 1353dab9fa2dSZhaoxin Yang }) 1354dab9fa2dSZhaoxin Yang .template Case<mlir::FloatType>([&](mlir::FloatType floatTy) { 1355dab9fa2dSZhaoxin Yang if (floatTy.getWidth() != 0) 1356dab9fa2dSZhaoxin Yang flatTypes.push_back(floatTy); 1357dab9fa2dSZhaoxin Yang }) 1358dab9fa2dSZhaoxin Yang .template Case<mlir::ComplexType>([&](mlir::ComplexType cmplx) { 1359dab9fa2dSZhaoxin Yang const auto *sem = &floatToSemantics(kindMap, cmplx.getElementType()); 1360dab9fa2dSZhaoxin Yang if (sem == &llvm::APFloat::IEEEsingle() || 1361dab9fa2dSZhaoxin Yang sem == &llvm::APFloat::IEEEdouble() || 1362dab9fa2dSZhaoxin Yang sem == &llvm::APFloat::IEEEquad()) 1363dab9fa2dSZhaoxin Yang std::fill_n(std::back_inserter(flatTypes), 2, 1364dab9fa2dSZhaoxin Yang cmplx.getElementType()); 1365dab9fa2dSZhaoxin Yang else 1366dab9fa2dSZhaoxin Yang TODO(loc, "unsupported complex type(not IEEEsingle, IEEEdouble, " 1367dab9fa2dSZhaoxin Yang "IEEEquad) as a structure component for BIND(C), " 1368dab9fa2dSZhaoxin Yang "VALUE derived type argument and type return"); 1369dab9fa2dSZhaoxin Yang }) 1370dab9fa2dSZhaoxin Yang .template Case<fir::LogicalType>([&](fir::LogicalType logicalTy) { 1371dab9fa2dSZhaoxin Yang const unsigned width = 1372dab9fa2dSZhaoxin Yang kindMap.getLogicalBitsize(logicalTy.getFKind()); 1373dab9fa2dSZhaoxin Yang if (width != 0) 1374dab9fa2dSZhaoxin Yang flatTypes.push_back( 1375dab9fa2dSZhaoxin Yang mlir::IntegerType::get(type.getContext(), width)); 1376dab9fa2dSZhaoxin Yang }) 1377dab9fa2dSZhaoxin Yang .template Case<fir::CharacterType>([&](fir::CharacterType charTy) { 1378dab9fa2dSZhaoxin Yang assert(kindMap.getCharacterBitsize(charTy.getFKind()) <= 8 && 1379dab9fa2dSZhaoxin Yang "the bit size of characterType as an interoperable type must " 1380dab9fa2dSZhaoxin Yang "not exceed 8"); 1381dab9fa2dSZhaoxin Yang for (unsigned i = 0; i < charTy.getLen(); ++i) 1382dab9fa2dSZhaoxin Yang flatTypes.push_back(mlir::IntegerType::get(type.getContext(), 8)); 1383dab9fa2dSZhaoxin Yang }) 1384dab9fa2dSZhaoxin Yang .template Case<fir::SequenceType>([&](fir::SequenceType seqTy) { 1385dab9fa2dSZhaoxin Yang if (!seqTy.hasDynamicExtents()) { 1386dab9fa2dSZhaoxin Yang const std::uint64_t numOfEle = seqTy.getConstantArraySize(); 1387dab9fa2dSZhaoxin Yang mlir::Type eleTy = seqTy.getEleTy(); 1388dab9fa2dSZhaoxin Yang if (!mlir::isa<mlir::IntegerType, mlir::FloatType>(eleTy)) { 1389dab9fa2dSZhaoxin Yang llvm::SmallVector<mlir::Type> subTypeList = 1390dab9fa2dSZhaoxin Yang flattenTypeList(loc, eleTy); 1391dab9fa2dSZhaoxin Yang if (subTypeList.size() != 0) 1392dab9fa2dSZhaoxin Yang for (std::uint64_t i = 0; i < numOfEle; ++i) 1393dab9fa2dSZhaoxin Yang llvm::copy(subTypeList, std::back_inserter(flatTypes)); 1394dab9fa2dSZhaoxin Yang } else { 1395dab9fa2dSZhaoxin Yang std::fill_n(std::back_inserter(flatTypes), numOfEle, eleTy); 1396dab9fa2dSZhaoxin Yang } 1397dab9fa2dSZhaoxin Yang } else 1398dab9fa2dSZhaoxin Yang TODO(loc, "unsupported dynamic extent sequence type as a structure " 1399dab9fa2dSZhaoxin Yang "component for BIND(C), " 1400dab9fa2dSZhaoxin Yang "VALUE derived type argument and type return"); 1401dab9fa2dSZhaoxin Yang }) 1402dab9fa2dSZhaoxin Yang .template Case<fir::RecordType>([&](fir::RecordType recTy) { 1403dab9fa2dSZhaoxin Yang for (auto &component : recTy.getTypeList()) { 1404dab9fa2dSZhaoxin Yang mlir::Type eleTy = component.second; 1405dab9fa2dSZhaoxin Yang llvm::SmallVector<mlir::Type> subTypeList = 1406dab9fa2dSZhaoxin Yang flattenTypeList(loc, eleTy); 1407dab9fa2dSZhaoxin Yang if (subTypeList.size() != 0) 1408dab9fa2dSZhaoxin Yang llvm::copy(subTypeList, std::back_inserter(flatTypes)); 1409dab9fa2dSZhaoxin Yang } 1410dab9fa2dSZhaoxin Yang }) 1411dab9fa2dSZhaoxin Yang .template Case<fir::VectorType>([&](fir::VectorType vecTy) { 1412dab9fa2dSZhaoxin Yang auto sizeAndAlign = fir::getTypeSizeAndAlignmentOrCrash( 1413dab9fa2dSZhaoxin Yang loc, vecTy, getDataLayout(), kindMap); 1414dab9fa2dSZhaoxin Yang if (sizeAndAlign.first == 2 * GRLenInChar) 1415dab9fa2dSZhaoxin Yang flatTypes.push_back( 1416dab9fa2dSZhaoxin Yang mlir::IntegerType::get(type.getContext(), 2 * GRLen)); 1417dab9fa2dSZhaoxin Yang else 1418dab9fa2dSZhaoxin Yang TODO(loc, "unsupported vector width(must be 128 bits)"); 1419dab9fa2dSZhaoxin Yang }) 1420dab9fa2dSZhaoxin Yang .Default([&](mlir::Type ty) { 1421dab9fa2dSZhaoxin Yang if (fir::conformsWithPassByRef(ty)) 1422dab9fa2dSZhaoxin Yang flatTypes.push_back( 1423dab9fa2dSZhaoxin Yang mlir::IntegerType::get(type.getContext(), GRLen)); 1424dab9fa2dSZhaoxin Yang else 1425dab9fa2dSZhaoxin Yang TODO(loc, "unsupported component type for BIND(C), VALUE derived " 1426dab9fa2dSZhaoxin Yang "type argument and type return"); 1427dab9fa2dSZhaoxin Yang }); 1428dab9fa2dSZhaoxin Yang 1429dab9fa2dSZhaoxin Yang return flatTypes; 1430dab9fa2dSZhaoxin Yang } 1431dab9fa2dSZhaoxin Yang 1432dab9fa2dSZhaoxin Yang /// Determine if a struct is eligible to be passed in FARs (and GARs) (i.e., 1433dab9fa2dSZhaoxin Yang /// when flattened it contains a single fp value, fp+fp, or int+fp of 1434dab9fa2dSZhaoxin Yang /// appropriate size). 1435dab9fa2dSZhaoxin Yang bool detectFARsEligibleStruct(mlir::Location loc, fir::RecordType recTy, 1436dab9fa2dSZhaoxin Yang mlir::Type &field1Ty, 1437dab9fa2dSZhaoxin Yang mlir::Type &field2Ty) const { 1438dab9fa2dSZhaoxin Yang field1Ty = field2Ty = nullptr; 1439dab9fa2dSZhaoxin Yang llvm::SmallVector<mlir::Type> flatTypes = flattenTypeList(loc, recTy); 1440dab9fa2dSZhaoxin Yang size_t flatSize = flatTypes.size(); 1441dab9fa2dSZhaoxin Yang 1442dab9fa2dSZhaoxin Yang // Cannot be eligible if the number of flattened types is equal to 0 or 1443dab9fa2dSZhaoxin Yang // greater than 2. 1444dab9fa2dSZhaoxin Yang if (flatSize == 0 || flatSize > 2) 1445dab9fa2dSZhaoxin Yang return false; 1446dab9fa2dSZhaoxin Yang 1447dab9fa2dSZhaoxin Yang bool isFirstAvaliableFloat = false; 1448dab9fa2dSZhaoxin Yang 1449dab9fa2dSZhaoxin Yang assert((mlir::isa<mlir::IntegerType, mlir::FloatType>(flatTypes[0])) && 1450dab9fa2dSZhaoxin Yang "Type must be integerType or floatType after flattening"); 1451dab9fa2dSZhaoxin Yang if (auto floatTy = mlir::dyn_cast<mlir::FloatType>(flatTypes[0])) { 1452dab9fa2dSZhaoxin Yang const unsigned Size = floatTy.getWidth(); 1453dab9fa2dSZhaoxin Yang // Can't be eligible if larger than the FP registers. Half precision isn't 1454dab9fa2dSZhaoxin Yang // currently supported on LoongArch and the ABI hasn't been confirmed, so 1455dab9fa2dSZhaoxin Yang // default to the integer ABI in that case. 1456dab9fa2dSZhaoxin Yang if (Size > FRLen || Size < 32) 1457dab9fa2dSZhaoxin Yang return false; 1458dab9fa2dSZhaoxin Yang isFirstAvaliableFloat = true; 1459dab9fa2dSZhaoxin Yang field1Ty = floatTy; 1460dab9fa2dSZhaoxin Yang } else if (auto intTy = mlir::dyn_cast<mlir::IntegerType>(flatTypes[0])) { 1461dab9fa2dSZhaoxin Yang if (intTy.getWidth() > GRLen) 1462dab9fa2dSZhaoxin Yang return false; 1463dab9fa2dSZhaoxin Yang field1Ty = intTy; 1464dab9fa2dSZhaoxin Yang } 1465dab9fa2dSZhaoxin Yang 1466dab9fa2dSZhaoxin Yang // flatTypes has two elements 1467dab9fa2dSZhaoxin Yang if (flatSize == 2) { 1468dab9fa2dSZhaoxin Yang assert((mlir::isa<mlir::IntegerType, mlir::FloatType>(flatTypes[1])) && 1469dab9fa2dSZhaoxin Yang "Type must be integerType or floatType after flattening"); 1470dab9fa2dSZhaoxin Yang if (auto floatTy = mlir::dyn_cast<mlir::FloatType>(flatTypes[1])) { 1471dab9fa2dSZhaoxin Yang const unsigned Size = floatTy.getWidth(); 1472dab9fa2dSZhaoxin Yang if (Size > FRLen || Size < 32) 1473dab9fa2dSZhaoxin Yang return false; 1474dab9fa2dSZhaoxin Yang field2Ty = floatTy; 1475dab9fa2dSZhaoxin Yang return true; 1476dab9fa2dSZhaoxin Yang } else if (auto intTy = mlir::dyn_cast<mlir::IntegerType>(flatTypes[1])) { 1477dab9fa2dSZhaoxin Yang // Can't be eligible if an integer type was already found (int+int pairs 1478dab9fa2dSZhaoxin Yang // are not eligible). 1479dab9fa2dSZhaoxin Yang if (!isFirstAvaliableFloat) 1480dab9fa2dSZhaoxin Yang return false; 1481dab9fa2dSZhaoxin Yang if (intTy.getWidth() > GRLen) 1482dab9fa2dSZhaoxin Yang return false; 1483dab9fa2dSZhaoxin Yang field2Ty = intTy; 1484dab9fa2dSZhaoxin Yang return true; 1485dab9fa2dSZhaoxin Yang } 1486dab9fa2dSZhaoxin Yang } 1487dab9fa2dSZhaoxin Yang 1488dab9fa2dSZhaoxin Yang // return isFirstAvaliableFloat if flatTypes only has one element 1489dab9fa2dSZhaoxin Yang return isFirstAvaliableFloat; 1490dab9fa2dSZhaoxin Yang } 1491dab9fa2dSZhaoxin Yang 1492dab9fa2dSZhaoxin Yang bool checkTypeHasEnoughRegs(mlir::Location loc, int &GARsLeft, int &FARsLeft, 1493dab9fa2dSZhaoxin Yang const mlir::Type type) const { 1494dab9fa2dSZhaoxin Yang if (!type) 1495dab9fa2dSZhaoxin Yang return true; 1496dab9fa2dSZhaoxin Yang 1497dab9fa2dSZhaoxin Yang llvm::TypeSwitch<mlir::Type>(type) 1498dab9fa2dSZhaoxin Yang .template Case<mlir::IntegerType>([&](mlir::IntegerType intTy) { 1499dab9fa2dSZhaoxin Yang const unsigned width = intTy.getWidth(); 1500dab9fa2dSZhaoxin Yang if (width > 128) 1501dab9fa2dSZhaoxin Yang TODO(loc, 1502dab9fa2dSZhaoxin Yang "integerType with width exceeding 128 bits is unsupported"); 1503dab9fa2dSZhaoxin Yang if (width == 0) 1504dab9fa2dSZhaoxin Yang return; 1505dab9fa2dSZhaoxin Yang if (width <= GRLen) 1506dab9fa2dSZhaoxin Yang --GARsLeft; 1507dab9fa2dSZhaoxin Yang else if (width <= 2 * GRLen) 1508dab9fa2dSZhaoxin Yang GARsLeft = GARsLeft - 2; 1509dab9fa2dSZhaoxin Yang }) 1510dab9fa2dSZhaoxin Yang .template Case<mlir::FloatType>([&](mlir::FloatType floatTy) { 1511dab9fa2dSZhaoxin Yang const unsigned width = floatTy.getWidth(); 1512dab9fa2dSZhaoxin Yang if (width > 128) 1513dab9fa2dSZhaoxin Yang TODO(loc, "floatType with width exceeding 128 bits is unsupported"); 1514dab9fa2dSZhaoxin Yang if (width == 0) 1515dab9fa2dSZhaoxin Yang return; 1516dab9fa2dSZhaoxin Yang if (width == 32 || width == 64) 1517dab9fa2dSZhaoxin Yang --FARsLeft; 1518dab9fa2dSZhaoxin Yang else if (width <= GRLen) 1519dab9fa2dSZhaoxin Yang --GARsLeft; 1520dab9fa2dSZhaoxin Yang else if (width <= 2 * GRLen) 1521dab9fa2dSZhaoxin Yang GARsLeft = GARsLeft - 2; 1522dab9fa2dSZhaoxin Yang }) 1523dab9fa2dSZhaoxin Yang .Default([&](mlir::Type ty) { 1524dab9fa2dSZhaoxin Yang if (fir::conformsWithPassByRef(ty)) 1525dab9fa2dSZhaoxin Yang --GARsLeft; // Pointers. 1526dab9fa2dSZhaoxin Yang else 1527dab9fa2dSZhaoxin Yang TODO(loc, "unsupported component type for BIND(C), VALUE derived " 1528dab9fa2dSZhaoxin Yang "type argument and type return"); 1529dab9fa2dSZhaoxin Yang }); 1530dab9fa2dSZhaoxin Yang 1531dab9fa2dSZhaoxin Yang return GARsLeft >= 0 && FARsLeft >= 0; 1532dab9fa2dSZhaoxin Yang } 1533dab9fa2dSZhaoxin Yang 1534dab9fa2dSZhaoxin Yang bool hasEnoughRegisters(mlir::Location loc, int GARsLeft, int FARsLeft, 1535dab9fa2dSZhaoxin Yang const Marshalling &previousArguments, 1536dab9fa2dSZhaoxin Yang const mlir::Type &field1Ty, 1537dab9fa2dSZhaoxin Yang const mlir::Type &field2Ty) const { 1538dab9fa2dSZhaoxin Yang for (auto &typeAndAttr : previousArguments) { 1539dab9fa2dSZhaoxin Yang const auto &attr = std::get<Attributes>(typeAndAttr); 1540dab9fa2dSZhaoxin Yang if (attr.isByVal()) { 1541dab9fa2dSZhaoxin Yang // Previous argument passed on the stack, and its address is passed in 1542dab9fa2dSZhaoxin Yang // GAR. 1543dab9fa2dSZhaoxin Yang --GARsLeft; 1544dab9fa2dSZhaoxin Yang continue; 1545dab9fa2dSZhaoxin Yang } 1546dab9fa2dSZhaoxin Yang 1547dab9fa2dSZhaoxin Yang // Previous aggregate arguments were marshalled into simpler arguments. 1548dab9fa2dSZhaoxin Yang const auto &type = std::get<mlir::Type>(typeAndAttr); 1549dab9fa2dSZhaoxin Yang llvm::SmallVector<mlir::Type> flatTypes = flattenTypeList(loc, type); 1550dab9fa2dSZhaoxin Yang 1551dab9fa2dSZhaoxin Yang for (auto &flatTy : flatTypes) { 1552dab9fa2dSZhaoxin Yang if (!checkTypeHasEnoughRegs(loc, GARsLeft, FARsLeft, flatTy)) 1553dab9fa2dSZhaoxin Yang return false; 1554dab9fa2dSZhaoxin Yang } 1555dab9fa2dSZhaoxin Yang } 1556dab9fa2dSZhaoxin Yang 1557dab9fa2dSZhaoxin Yang if (!checkTypeHasEnoughRegs(loc, GARsLeft, FARsLeft, field1Ty)) 1558dab9fa2dSZhaoxin Yang return false; 1559dab9fa2dSZhaoxin Yang if (!checkTypeHasEnoughRegs(loc, GARsLeft, FARsLeft, field2Ty)) 1560dab9fa2dSZhaoxin Yang return false; 1561dab9fa2dSZhaoxin Yang return true; 1562dab9fa2dSZhaoxin Yang } 1563dab9fa2dSZhaoxin Yang 1564dab9fa2dSZhaoxin Yang /// LoongArch64 subroutine calling sequence ABI in: 1565dab9fa2dSZhaoxin Yang /// https://github.com/loongson/la-abi-specs/blob/release/lapcs.adoc#subroutine-calling-sequence 1566dab9fa2dSZhaoxin Yang CodeGenSpecifics::Marshalling 1567dab9fa2dSZhaoxin Yang classifyStruct(mlir::Location loc, fir::RecordType recTy, int GARsLeft, 1568dab9fa2dSZhaoxin Yang int FARsLeft, bool isResult, 1569dab9fa2dSZhaoxin Yang const Marshalling &previousArguments) const { 1570dab9fa2dSZhaoxin Yang CodeGenSpecifics::Marshalling marshal; 1571dab9fa2dSZhaoxin Yang 1572dab9fa2dSZhaoxin Yang auto [recSize, recAlign] = fir::getTypeSizeAndAlignmentOrCrash( 1573dab9fa2dSZhaoxin Yang loc, recTy, getDataLayout(), kindMap); 1574dab9fa2dSZhaoxin Yang mlir::MLIRContext *context = recTy.getContext(); 1575dab9fa2dSZhaoxin Yang 1576dab9fa2dSZhaoxin Yang if (recSize == 0) { 1577dab9fa2dSZhaoxin Yang TODO(loc, "unsupported empty struct type for BIND(C), " 1578dab9fa2dSZhaoxin Yang "VALUE derived type argument and type return"); 1579dab9fa2dSZhaoxin Yang } 1580dab9fa2dSZhaoxin Yang 1581dab9fa2dSZhaoxin Yang if (recSize > 2 * GRLenInChar) { 1582dab9fa2dSZhaoxin Yang marshal.emplace_back( 1583dab9fa2dSZhaoxin Yang fir::ReferenceType::get(recTy), 1584dab9fa2dSZhaoxin Yang AT{recAlign, /*byval=*/!isResult, /*sret=*/isResult}); 1585dab9fa2dSZhaoxin Yang return marshal; 1586dab9fa2dSZhaoxin Yang } 1587dab9fa2dSZhaoxin Yang 1588dab9fa2dSZhaoxin Yang // Pass by FARs(and GARs) 1589dab9fa2dSZhaoxin Yang mlir::Type field1Ty = nullptr, field2Ty = nullptr; 1590dab9fa2dSZhaoxin Yang if (detectFARsEligibleStruct(loc, recTy, field1Ty, field2Ty) && 1591dab9fa2dSZhaoxin Yang hasEnoughRegisters(loc, GARsLeft, FARsLeft, previousArguments, field1Ty, 1592dab9fa2dSZhaoxin Yang field2Ty)) { 1593dab9fa2dSZhaoxin Yang if (!isResult) { 1594dab9fa2dSZhaoxin Yang if (field1Ty) 1595dab9fa2dSZhaoxin Yang marshal.emplace_back(field1Ty, AT{}); 1596dab9fa2dSZhaoxin Yang if (field2Ty) 1597dab9fa2dSZhaoxin Yang marshal.emplace_back(field2Ty, AT{}); 1598dab9fa2dSZhaoxin Yang } else { 1599dab9fa2dSZhaoxin Yang // field1Ty is always preferred over field2Ty for assignment, so there 1600dab9fa2dSZhaoxin Yang // will never be a case where field1Ty == nullptr and field2Ty != 1601dab9fa2dSZhaoxin Yang // nullptr. 1602dab9fa2dSZhaoxin Yang if (field1Ty && !field2Ty) 1603dab9fa2dSZhaoxin Yang marshal.emplace_back(field1Ty, AT{}); 1604dab9fa2dSZhaoxin Yang else if (field1Ty && field2Ty) 1605dab9fa2dSZhaoxin Yang marshal.emplace_back( 1606dab9fa2dSZhaoxin Yang mlir::TupleType::get(context, 1607dab9fa2dSZhaoxin Yang mlir::TypeRange{field1Ty, field2Ty}), 1608dab9fa2dSZhaoxin Yang AT{/*alignment=*/0, /*byval=*/true}); 1609dab9fa2dSZhaoxin Yang } 1610dab9fa2dSZhaoxin Yang return marshal; 1611dab9fa2dSZhaoxin Yang } 1612dab9fa2dSZhaoxin Yang 1613dab9fa2dSZhaoxin Yang if (recSize <= GRLenInChar) { 1614dab9fa2dSZhaoxin Yang marshal.emplace_back(mlir::IntegerType::get(context, GRLen), AT{}); 1615dab9fa2dSZhaoxin Yang return marshal; 1616dab9fa2dSZhaoxin Yang } 1617dab9fa2dSZhaoxin Yang 1618dab9fa2dSZhaoxin Yang if (recAlign == 2 * GRLenInChar) { 1619dab9fa2dSZhaoxin Yang marshal.emplace_back(mlir::IntegerType::get(context, 2 * GRLen), AT{}); 1620dab9fa2dSZhaoxin Yang return marshal; 1621dab9fa2dSZhaoxin Yang } 1622dab9fa2dSZhaoxin Yang 1623dab9fa2dSZhaoxin Yang // recSize > GRLenInChar && recSize <= 2 * GRLenInChar 1624dab9fa2dSZhaoxin Yang marshal.emplace_back( 1625dab9fa2dSZhaoxin Yang fir::SequenceType::get({2}, mlir::IntegerType::get(context, GRLen)), 1626dab9fa2dSZhaoxin Yang AT{}); 1627dab9fa2dSZhaoxin Yang return marshal; 1628dab9fa2dSZhaoxin Yang } 1629dab9fa2dSZhaoxin Yang 1630dab9fa2dSZhaoxin Yang /// Marshal a derived type passed by value like a C struct. 1631dab9fa2dSZhaoxin Yang CodeGenSpecifics::Marshalling 1632dab9fa2dSZhaoxin Yang structArgumentType(mlir::Location loc, fir::RecordType recTy, 1633dab9fa2dSZhaoxin Yang const Marshalling &previousArguments) const override { 1634dab9fa2dSZhaoxin Yang int GARsLeft = 8; 1635dab9fa2dSZhaoxin Yang int FARsLeft = FRLen ? 8 : 0; 1636dab9fa2dSZhaoxin Yang 1637dab9fa2dSZhaoxin Yang return classifyStruct(loc, recTy, GARsLeft, FARsLeft, /*isResult=*/false, 1638dab9fa2dSZhaoxin Yang previousArguments); 1639dab9fa2dSZhaoxin Yang } 1640dab9fa2dSZhaoxin Yang 1641dab9fa2dSZhaoxin Yang CodeGenSpecifics::Marshalling 1642dab9fa2dSZhaoxin Yang structReturnType(mlir::Location loc, fir::RecordType recTy) const override { 1643dab9fa2dSZhaoxin Yang // The rules for return and argument types are the same. 1644dab9fa2dSZhaoxin Yang int GARsLeft = 2; 1645dab9fa2dSZhaoxin Yang int FARsLeft = FRLen ? 2 : 0; 1646dab9fa2dSZhaoxin Yang return classifyStruct(loc, recTy, GARsLeft, FARsLeft, /*isResult=*/true, 1647dab9fa2dSZhaoxin Yang {}); 1648dab9fa2dSZhaoxin Yang } 1649720f728dSWeining Lu }; 1650720f728dSWeining Lu } // namespace 1651720f728dSWeining Lu 16524c263edeSDiana Picus // Instantiate the overloaded target instance based on the triple value. 1653b389fbd0SAndrzej Warzynski // TODO: Add other targets to this file as needed. 16544c263edeSDiana Picus std::unique_ptr<fir::CodeGenSpecifics> 16554c263edeSDiana Picus fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp, 1656837bff11SSergio Afonso KindMapping &&kindMap, llvm::StringRef targetCPU, 1657837bff11SSergio Afonso mlir::LLVM::TargetFeaturesAttr targetFeatures, 1658837bff11SSergio Afonso const mlir::DataLayout &dl) { 16594c263edeSDiana Picus switch (trp.getArch()) { 16604c263edeSDiana Picus default: 16614c263edeSDiana Picus break; 16624c263edeSDiana Picus case llvm::Triple::ArchType::x86: 1663774703ecSMarkus Mützel if (trp.isOSWindows()) 1664774703ecSMarkus Mützel return std::make_unique<TargetI386Win>(ctx, std::move(trp), 1665837bff11SSergio Afonso std::move(kindMap), targetCPU, 1666837bff11SSergio Afonso targetFeatures, dl); 1667774703ecSMarkus Mützel else 16684c263edeSDiana Picus return std::make_unique<TargetI386>(ctx, std::move(trp), 1669837bff11SSergio Afonso std::move(kindMap), targetCPU, 1670837bff11SSergio Afonso targetFeatures, dl); 16714c263edeSDiana Picus case llvm::Triple::ArchType::x86_64: 1672774703ecSMarkus Mützel if (trp.isOSWindows()) 1673774703ecSMarkus Mützel return std::make_unique<TargetX86_64Win>(ctx, std::move(trp), 1674837bff11SSergio Afonso std::move(kindMap), targetCPU, 1675837bff11SSergio Afonso targetFeatures, dl); 1676774703ecSMarkus Mützel else 16774c263edeSDiana Picus return std::make_unique<TargetX86_64>(ctx, std::move(trp), 1678837bff11SSergio Afonso std::move(kindMap), targetCPU, 1679837bff11SSergio Afonso targetFeatures, dl); 16804c263edeSDiana Picus case llvm::Triple::ArchType::aarch64: 1681837bff11SSergio Afonso return std::make_unique<TargetAArch64>( 1682837bff11SSergio Afonso ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); 1683320fbff4SMark Danial case llvm::Triple::ArchType::ppc64: 1684837bff11SSergio Afonso return std::make_unique<TargetPPC64>( 1685837bff11SSergio Afonso ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); 16864c263edeSDiana Picus case llvm::Triple::ArchType::ppc64le: 1687837bff11SSergio Afonso return std::make_unique<TargetPPC64le>( 1688837bff11SSergio Afonso ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); 16891774a8a7SRainer Orth case llvm::Triple::ArchType::sparc: 1690837bff11SSergio Afonso return std::make_unique<TargetSparc>( 1691837bff11SSergio Afonso ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); 16921774a8a7SRainer Orth case llvm::Triple::ArchType::sparcv9: 1693837bff11SSergio Afonso return std::make_unique<TargetSparcV9>( 1694837bff11SSergio Afonso ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); 1695bac88e89SQihan Cai case llvm::Triple::ArchType::riscv64: 1696837bff11SSergio Afonso return std::make_unique<TargetRISCV64>( 1697837bff11SSergio Afonso ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); 169808749a91SJan Sjodin case llvm::Triple::ArchType::amdgcn: 1699837bff11SSergio Afonso return std::make_unique<TargetAMDGPU>( 1700837bff11SSergio Afonso ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); 1701be9fa9deSFabian Mora case llvm::Triple::ArchType::nvptx64: 1702837bff11SSergio Afonso return std::make_unique<TargetNVPTX>( 1703837bff11SSergio Afonso ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); 1704720f728dSWeining Lu case llvm::Triple::ArchType::loongarch64: 1705837bff11SSergio Afonso return std::make_unique<TargetLoongArch64>( 1706837bff11SSergio Afonso ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); 17071774a8a7SRainer Orth } 17080c1cf585SEric Schweitz TODO(mlir::UnknownLoc::get(ctx), "target not implemented"); 17094c263edeSDiana Picus } 1710f1d3fe7aSAlexis Perry-Holby 1711f1d3fe7aSAlexis Perry-Holby std::unique_ptr<fir::CodeGenSpecifics> fir::CodeGenSpecifics::get( 1712f1d3fe7aSAlexis Perry-Holby mlir::MLIRContext *ctx, llvm::Triple &&trp, KindMapping &&kindMap, 1713f1d3fe7aSAlexis Perry-Holby llvm::StringRef targetCPU, mlir::LLVM::TargetFeaturesAttr targetFeatures, 1714f1d3fe7aSAlexis Perry-Holby const mlir::DataLayout &dl, llvm::StringRef tuneCPU) { 1715f1d3fe7aSAlexis Perry-Holby std::unique_ptr<fir::CodeGenSpecifics> CGS = fir::CodeGenSpecifics::get( 1716f1d3fe7aSAlexis Perry-Holby ctx, std::move(trp), std::move(kindMap), targetCPU, targetFeatures, dl); 1717f1d3fe7aSAlexis Perry-Holby 1718f1d3fe7aSAlexis Perry-Holby CGS->tuneCPU = tuneCPU; 1719f1d3fe7aSAlexis Perry-Holby return CGS; 1720f1d3fe7aSAlexis Perry-Holby } 1721