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