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 
134c263edeSDiana Picus #include "Target.h"
144c263edeSDiana Picus #include "flang/Optimizer/Dialect/FIRType.h"
154c263edeSDiana Picus #include "flang/Optimizer/Support/KindMapping.h"
164c263edeSDiana Picus #include "mlir/IR/BuiltinTypes.h"
174c263edeSDiana Picus #include "mlir/IR/TypeRange.h"
184c263edeSDiana Picus 
194c263edeSDiana Picus #define DEBUG_TYPE "flang-codegen-target"
204c263edeSDiana Picus 
214c263edeSDiana Picus using namespace fir;
224c263edeSDiana Picus 
2365431d3aSDiana Picus // Reduce a REAL/float type to the floating point semantics.
2465431d3aSDiana Picus static const llvm::fltSemantics &floatToSemantics(const KindMapping &kindMap,
2565431d3aSDiana Picus                                                   mlir::Type type) {
2665431d3aSDiana Picus   assert(isa_real(type));
2765431d3aSDiana Picus   if (auto ty = type.dyn_cast<fir::RealType>())
2865431d3aSDiana Picus     return kindMap.getFloatSemantics(ty.getFKind());
2965431d3aSDiana Picus   return type.cast<mlir::FloatType>().getFloatSemantics();
3065431d3aSDiana Picus }
3165431d3aSDiana Picus 
324c263edeSDiana Picus namespace {
334c263edeSDiana Picus template <typename S>
344c263edeSDiana Picus struct GenericTarget : public CodeGenSpecifics {
354c263edeSDiana Picus   using CodeGenSpecifics::CodeGenSpecifics;
364c263edeSDiana Picus   using AT = CodeGenSpecifics::Attributes;
374c263edeSDiana Picus 
387b5132daSValentin Clement   mlir::Type complexMemoryType(mlir::Type eleTy) const override {
397b5132daSValentin Clement     assert(fir::isa_real(eleTy));
407b5132daSValentin Clement     // { t, t }   struct of 2 eleTy
417b5132daSValentin Clement     mlir::TypeRange range = {eleTy, eleTy};
427b5132daSValentin Clement     return mlir::TupleType::get(eleTy.getContext(), range);
437b5132daSValentin Clement   }
447b5132daSValentin Clement 
45*bb201826SAndrzej Warzynski   mlir::Type boxcharMemoryType(mlir::Type eleTy) const override {
46*bb201826SAndrzej Warzynski     auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth);
47*bb201826SAndrzej Warzynski     auto ptrTy = fir::ReferenceType::get(eleTy);
48*bb201826SAndrzej Warzynski     // { t*, index }
49*bb201826SAndrzej Warzynski     mlir::TypeRange range = {ptrTy, idxTy};
50*bb201826SAndrzej Warzynski     return mlir::TupleType::get(eleTy.getContext(), range);
51*bb201826SAndrzej Warzynski   }
52*bb201826SAndrzej Warzynski 
534c263edeSDiana Picus   Marshalling boxcharArgumentType(mlir::Type eleTy, bool sret) const override {
544c263edeSDiana Picus     CodeGenSpecifics::Marshalling marshal;
554c263edeSDiana Picus     auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth);
564c263edeSDiana Picus     auto ptrTy = fir::ReferenceType::get(eleTy);
574c263edeSDiana Picus     marshal.emplace_back(ptrTy, AT{});
584c263edeSDiana Picus     // Return value arguments are grouped as a pair. Others are passed in a
594c263edeSDiana Picus     // split format with all pointers first (in the declared position) and all
604c263edeSDiana Picus     // LEN arguments appended after all of the dummy arguments.
614c263edeSDiana Picus     // NB: Other conventions/ABIs can/should be supported via options.
6265431d3aSDiana Picus     marshal.emplace_back(idxTy, AT{/*alignment=*/0, /*byval=*/false,
6365431d3aSDiana Picus                                    /*sret=*/sret, /*append=*/!sret});
644c263edeSDiana Picus     return marshal;
654c263edeSDiana Picus   }
664c263edeSDiana Picus };
674c263edeSDiana Picus } // namespace
684c263edeSDiana Picus 
694c263edeSDiana Picus //===----------------------------------------------------------------------===//
704c263edeSDiana Picus // i386 (x86 32 bit) linux target specifics.
714c263edeSDiana Picus //===----------------------------------------------------------------------===//
724c263edeSDiana Picus 
734c263edeSDiana Picus namespace {
744c263edeSDiana Picus struct TargetI386 : public GenericTarget<TargetI386> {
754c263edeSDiana Picus   using GenericTarget::GenericTarget;
764c263edeSDiana Picus 
774c263edeSDiana Picus   static constexpr int defaultWidth = 32;
7865431d3aSDiana Picus 
7965431d3aSDiana Picus   CodeGenSpecifics::Marshalling
8065431d3aSDiana Picus   complexArgumentType(mlir::Type eleTy) const override {
8165431d3aSDiana Picus     assert(fir::isa_real(eleTy));
8265431d3aSDiana Picus     CodeGenSpecifics::Marshalling marshal;
8365431d3aSDiana Picus     // { t, t }   struct of 2 eleTy, byval, align 4
8465431d3aSDiana Picus     mlir::TypeRange range = {eleTy, eleTy};
8565431d3aSDiana Picus     auto structTy = mlir::TupleType::get(eleTy.getContext(), range);
8665431d3aSDiana Picus     marshal.emplace_back(fir::ReferenceType::get(structTy),
8765431d3aSDiana Picus                          AT{/*alignment=*/4, /*byval=*/true});
8865431d3aSDiana Picus     return marshal;
8965431d3aSDiana Picus   }
9065431d3aSDiana Picus 
9165431d3aSDiana Picus   CodeGenSpecifics::Marshalling
9265431d3aSDiana Picus   complexReturnType(mlir::Type eleTy) const override {
9365431d3aSDiana Picus     assert(fir::isa_real(eleTy));
9465431d3aSDiana Picus     CodeGenSpecifics::Marshalling marshal;
9565431d3aSDiana Picus     const auto *sem = &floatToSemantics(kindMap, eleTy);
9665431d3aSDiana Picus     if (sem == &llvm::APFloat::IEEEsingle()) {
9765431d3aSDiana Picus       // i64   pack both floats in a 64-bit GPR
9865431d3aSDiana Picus       marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64),
9965431d3aSDiana Picus                            AT{});
10065431d3aSDiana Picus     } else if (sem == &llvm::APFloat::IEEEdouble()) {
10165431d3aSDiana Picus       // { t, t }   struct of 2 eleTy, sret, align 4
10265431d3aSDiana Picus       mlir::TypeRange range = {eleTy, eleTy};
10365431d3aSDiana Picus       auto structTy = mlir::TupleType::get(eleTy.getContext(), range);
10465431d3aSDiana Picus       marshal.emplace_back(fir::ReferenceType::get(structTy),
10565431d3aSDiana Picus                            AT{/*alignment=*/4, /*byval=*/false, /*sret=*/true});
10665431d3aSDiana Picus     } else {
10765431d3aSDiana Picus       llvm::report_fatal_error("complex for this precision not implemented");
10865431d3aSDiana Picus     }
10965431d3aSDiana Picus     return marshal;
11065431d3aSDiana Picus   }
1114c263edeSDiana Picus };
1124c263edeSDiana Picus } // namespace
1134c263edeSDiana Picus 
1144c263edeSDiana Picus //===----------------------------------------------------------------------===//
1154c263edeSDiana Picus // x86_64 (x86 64 bit) linux target specifics.
1164c263edeSDiana Picus //===----------------------------------------------------------------------===//
1174c263edeSDiana Picus 
1184c263edeSDiana Picus namespace {
1194c263edeSDiana Picus struct TargetX86_64 : public GenericTarget<TargetX86_64> {
1204c263edeSDiana Picus   using GenericTarget::GenericTarget;
1214c263edeSDiana Picus 
1224c263edeSDiana Picus   static constexpr int defaultWidth = 64;
12365431d3aSDiana Picus 
12465431d3aSDiana Picus   CodeGenSpecifics::Marshalling
12565431d3aSDiana Picus   complexArgumentType(mlir::Type eleTy) const override {
12665431d3aSDiana Picus     CodeGenSpecifics::Marshalling marshal;
12765431d3aSDiana Picus     const auto *sem = &floatToSemantics(kindMap, eleTy);
12865431d3aSDiana Picus     if (sem == &llvm::APFloat::IEEEsingle()) {
12965431d3aSDiana Picus       // <2 x t>   vector of 2 eleTy
13065431d3aSDiana Picus       marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{});
13165431d3aSDiana Picus     } else if (sem == &llvm::APFloat::IEEEdouble()) {
13265431d3aSDiana Picus       // two distinct double arguments
13365431d3aSDiana Picus       marshal.emplace_back(eleTy, AT{});
13465431d3aSDiana Picus       marshal.emplace_back(eleTy, AT{});
13565431d3aSDiana Picus     } else {
13665431d3aSDiana Picus       llvm::report_fatal_error("complex for this precision not implemented");
13765431d3aSDiana Picus     }
13865431d3aSDiana Picus     return marshal;
13965431d3aSDiana Picus   }
14065431d3aSDiana Picus 
14165431d3aSDiana Picus   CodeGenSpecifics::Marshalling
14265431d3aSDiana Picus   complexReturnType(mlir::Type eleTy) const override {
14365431d3aSDiana Picus     CodeGenSpecifics::Marshalling marshal;
14465431d3aSDiana Picus     const auto *sem = &floatToSemantics(kindMap, eleTy);
14565431d3aSDiana Picus     if (sem == &llvm::APFloat::IEEEsingle()) {
14665431d3aSDiana Picus       // <2 x t>   vector of 2 eleTy
14765431d3aSDiana Picus       marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{});
14865431d3aSDiana Picus     } else if (sem == &llvm::APFloat::IEEEdouble()) {
14965431d3aSDiana Picus       // ( t, t )   tuple of 2 eleTy
15065431d3aSDiana Picus       mlir::TypeRange range = {eleTy, eleTy};
15165431d3aSDiana Picus       marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range),
15265431d3aSDiana Picus                            AT{});
15365431d3aSDiana Picus     } else {
15465431d3aSDiana Picus       llvm::report_fatal_error("complex for this precision not implemented");
15565431d3aSDiana Picus     }
15665431d3aSDiana Picus     return marshal;
15765431d3aSDiana Picus   }
1584c263edeSDiana Picus };
1594c263edeSDiana Picus } // namespace
1604c263edeSDiana Picus 
1614c263edeSDiana Picus //===----------------------------------------------------------------------===//
1624c263edeSDiana Picus // AArch64 linux target specifics.
1634c263edeSDiana Picus //===----------------------------------------------------------------------===//
1644c263edeSDiana Picus 
1654c263edeSDiana Picus namespace {
1664c263edeSDiana Picus struct TargetAArch64 : public GenericTarget<TargetAArch64> {
1674c263edeSDiana Picus   using GenericTarget::GenericTarget;
1684c263edeSDiana Picus 
1694c263edeSDiana Picus   static constexpr int defaultWidth = 64;
17065431d3aSDiana Picus 
17165431d3aSDiana Picus   CodeGenSpecifics::Marshalling
17265431d3aSDiana Picus   complexArgumentType(mlir::Type eleTy) const override {
17365431d3aSDiana Picus     CodeGenSpecifics::Marshalling marshal;
17465431d3aSDiana Picus     const auto *sem = &floatToSemantics(kindMap, eleTy);
17565431d3aSDiana Picus     if (sem == &llvm::APFloat::IEEEsingle() ||
17665431d3aSDiana Picus         sem == &llvm::APFloat::IEEEdouble()) {
17765431d3aSDiana Picus       // [2 x t]   array of 2 eleTy
17865431d3aSDiana Picus       marshal.emplace_back(fir::SequenceType::get({2}, eleTy), AT{});
17965431d3aSDiana Picus     } else {
18065431d3aSDiana Picus       llvm::report_fatal_error("complex for this precision not implemented");
18165431d3aSDiana Picus     }
18265431d3aSDiana Picus     return marshal;
18365431d3aSDiana Picus   }
18465431d3aSDiana Picus 
18565431d3aSDiana Picus   CodeGenSpecifics::Marshalling
18665431d3aSDiana Picus   complexReturnType(mlir::Type eleTy) const override {
18765431d3aSDiana Picus     CodeGenSpecifics::Marshalling marshal;
18865431d3aSDiana Picus     const auto *sem = &floatToSemantics(kindMap, eleTy);
18965431d3aSDiana Picus     if (sem == &llvm::APFloat::IEEEsingle() ||
19065431d3aSDiana Picus         sem == &llvm::APFloat::IEEEdouble()) {
19165431d3aSDiana Picus       // ( t, t )   tuple of 2 eleTy
19265431d3aSDiana Picus       mlir::TypeRange range = {eleTy, eleTy};
19365431d3aSDiana Picus       marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range),
19465431d3aSDiana Picus                            AT{});
19565431d3aSDiana Picus     } else {
19665431d3aSDiana Picus       llvm::report_fatal_error("complex for this precision not implemented");
19765431d3aSDiana Picus     }
19865431d3aSDiana Picus     return marshal;
19965431d3aSDiana Picus   }
2004c263edeSDiana Picus };
2014c263edeSDiana Picus } // namespace
2024c263edeSDiana Picus 
2034c263edeSDiana Picus //===----------------------------------------------------------------------===//
2044c263edeSDiana Picus // PPC64le linux target specifics.
2054c263edeSDiana Picus //===----------------------------------------------------------------------===//
2064c263edeSDiana Picus 
2074c263edeSDiana Picus namespace {
2084c263edeSDiana Picus struct TargetPPC64le : public GenericTarget<TargetPPC64le> {
2094c263edeSDiana Picus   using GenericTarget::GenericTarget;
2104c263edeSDiana Picus 
2114c263edeSDiana Picus   static constexpr int defaultWidth = 64;
21265431d3aSDiana Picus 
21365431d3aSDiana Picus   CodeGenSpecifics::Marshalling
21465431d3aSDiana Picus   complexArgumentType(mlir::Type eleTy) const override {
21565431d3aSDiana Picus     CodeGenSpecifics::Marshalling marshal;
21665431d3aSDiana Picus     // two distinct element type arguments (re, im)
21765431d3aSDiana Picus     marshal.emplace_back(eleTy, AT{});
21865431d3aSDiana Picus     marshal.emplace_back(eleTy, AT{});
21965431d3aSDiana Picus     return marshal;
22065431d3aSDiana Picus   }
22165431d3aSDiana Picus 
22265431d3aSDiana Picus   CodeGenSpecifics::Marshalling
22365431d3aSDiana Picus   complexReturnType(mlir::Type eleTy) const override {
22465431d3aSDiana Picus     CodeGenSpecifics::Marshalling marshal;
22565431d3aSDiana Picus     // ( t, t )   tuple of 2 element type
22665431d3aSDiana Picus     mlir::TypeRange range = {eleTy, eleTy};
22765431d3aSDiana Picus     marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range), AT{});
22865431d3aSDiana Picus     return marshal;
22965431d3aSDiana Picus   }
2304c263edeSDiana Picus };
2314c263edeSDiana Picus } // namespace
2324c263edeSDiana Picus 
2334c263edeSDiana Picus // Instantiate the overloaded target instance based on the triple value.
2344c263edeSDiana Picus // Currently, the implementation only instantiates `i386-unknown-linux-gnu`,
2354c263edeSDiana Picus // `x86_64-unknown-linux-gnu`, aarch64 and ppc64le like triples. Other targets
2364c263edeSDiana Picus // should be added to this file as needed.
2374c263edeSDiana Picus std::unique_ptr<fir::CodeGenSpecifics>
2384c263edeSDiana Picus fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp,
2394c263edeSDiana Picus                            KindMapping &&kindMap) {
2404c263edeSDiana Picus   switch (trp.getArch()) {
2414c263edeSDiana Picus   default:
2424c263edeSDiana Picus     break;
2434c263edeSDiana Picus   case llvm::Triple::ArchType::x86:
2444c263edeSDiana Picus     switch (trp.getOS()) {
2454c263edeSDiana Picus     default:
2464c263edeSDiana Picus       break;
2474c263edeSDiana Picus     case llvm::Triple::OSType::Linux:
2484c263edeSDiana Picus     case llvm::Triple::OSType::Darwin:
2494c263edeSDiana Picus       return std::make_unique<TargetI386>(ctx, std::move(trp),
2504c263edeSDiana Picus                                           std::move(kindMap));
2514c263edeSDiana Picus     }
2524c263edeSDiana Picus     break;
2534c263edeSDiana Picus   case llvm::Triple::ArchType::x86_64:
2544c263edeSDiana Picus     switch (trp.getOS()) {
2554c263edeSDiana Picus     default:
2564c263edeSDiana Picus       break;
2574c263edeSDiana Picus     case llvm::Triple::OSType::Linux:
2584c263edeSDiana Picus     case llvm::Triple::OSType::Darwin:
2594c263edeSDiana Picus       return std::make_unique<TargetX86_64>(ctx, std::move(trp),
2604c263edeSDiana Picus                                             std::move(kindMap));
2614c263edeSDiana Picus     }
2624c263edeSDiana Picus     break;
2634c263edeSDiana Picus   case llvm::Triple::ArchType::aarch64:
2644c263edeSDiana Picus     switch (trp.getOS()) {
2654c263edeSDiana Picus     default:
2664c263edeSDiana Picus       break;
2674c263edeSDiana Picus     case llvm::Triple::OSType::Linux:
2684c263edeSDiana Picus     case llvm::Triple::OSType::Darwin:
2694c263edeSDiana Picus       return std::make_unique<TargetAArch64>(ctx, std::move(trp),
2704c263edeSDiana Picus                                              std::move(kindMap));
2714c263edeSDiana Picus     }
2724c263edeSDiana Picus     break;
2734c263edeSDiana Picus   case llvm::Triple::ArchType::ppc64le:
2744c263edeSDiana Picus     switch (trp.getOS()) {
2754c263edeSDiana Picus     default:
2764c263edeSDiana Picus       break;
2774c263edeSDiana Picus     case llvm::Triple::OSType::Linux:
2784c263edeSDiana Picus       return std::make_unique<TargetPPC64le>(ctx, std::move(trp),
2794c263edeSDiana Picus                                              std::move(kindMap));
2804c263edeSDiana Picus     }
2814c263edeSDiana Picus     break;
2824c263edeSDiana Picus   }
2834c263edeSDiana Picus   llvm::report_fatal_error("target not implemented");
2844c263edeSDiana Picus }
285