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"
140c1cf585SEric Schweitz #include "flang/Optimizer/Builder/Todo.h"
154c263edeSDiana Picus #include "flang/Optimizer/Dialect/FIRType.h"
160c1cf585SEric Schweitz #include "flang/Optimizer/Support/FatalError.h"
174c263edeSDiana Picus #include "flang/Optimizer/Support/KindMapping.h"
184c263edeSDiana Picus #include "mlir/IR/BuiltinTypes.h"
194c263edeSDiana Picus #include "mlir/IR/TypeRange.h"
204c263edeSDiana Picus
214c263edeSDiana Picus #define DEBUG_TYPE "flang-codegen-target"
224c263edeSDiana Picus
234c263edeSDiana Picus using namespace fir;
244c263edeSDiana Picus
2565431d3aSDiana Picus // Reduce a REAL/float type to the floating point semantics.
floatToSemantics(const KindMapping & kindMap,mlir::Type type)2665431d3aSDiana Picus static const llvm::fltSemantics &floatToSemantics(const KindMapping &kindMap,
2765431d3aSDiana Picus mlir::Type type) {
2865431d3aSDiana Picus assert(isa_real(type));
2965431d3aSDiana Picus if (auto ty = type.dyn_cast<fir::RealType>())
3065431d3aSDiana Picus return kindMap.getFloatSemantics(ty.getFKind());
3165431d3aSDiana Picus return type.cast<mlir::FloatType>().getFloatSemantics();
3265431d3aSDiana Picus }
3365431d3aSDiana Picus
344c263edeSDiana Picus namespace {
354c263edeSDiana Picus template <typename S>
364c263edeSDiana Picus struct GenericTarget : public CodeGenSpecifics {
374c263edeSDiana Picus using CodeGenSpecifics::CodeGenSpecifics;
384c263edeSDiana Picus using AT = CodeGenSpecifics::Attributes;
394c263edeSDiana Picus
complexMemoryType__anonc3f2b8ea0111::GenericTarget407b5132daSValentin Clement mlir::Type complexMemoryType(mlir::Type eleTy) const override {
417b5132daSValentin Clement assert(fir::isa_real(eleTy));
42faf869dcSDiana Picus // Use a type that will be translated into LLVM as:
437b5132daSValentin Clement // { t, t } struct of 2 eleTy
447b5132daSValentin Clement mlir::TypeRange range = {eleTy, eleTy};
457b5132daSValentin Clement return mlir::TupleType::get(eleTy.getContext(), range);
467b5132daSValentin Clement }
477b5132daSValentin Clement
boxcharMemoryType__anonc3f2b8ea0111::GenericTarget48bb201826SAndrzej Warzynski mlir::Type boxcharMemoryType(mlir::Type eleTy) const override {
49bb201826SAndrzej Warzynski auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth);
50bb201826SAndrzej Warzynski auto ptrTy = fir::ReferenceType::get(eleTy);
51faf869dcSDiana Picus // Use a type that will be translated into LLVM as:
52bb201826SAndrzej Warzynski // { t*, index }
53bb201826SAndrzej Warzynski mlir::TypeRange range = {ptrTy, idxTy};
54bb201826SAndrzej Warzynski return mlir::TupleType::get(eleTy.getContext(), range);
55bb201826SAndrzej Warzynski }
56bb201826SAndrzej Warzynski
boxcharArgumentType__anonc3f2b8ea0111::GenericTarget574c263edeSDiana Picus Marshalling boxcharArgumentType(mlir::Type eleTy, bool sret) const override {
584c263edeSDiana Picus CodeGenSpecifics::Marshalling marshal;
594c263edeSDiana Picus auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth);
604c263edeSDiana Picus auto ptrTy = fir::ReferenceType::get(eleTy);
614c263edeSDiana Picus marshal.emplace_back(ptrTy, AT{});
624c263edeSDiana Picus // Return value arguments are grouped as a pair. Others are passed in a
634c263edeSDiana Picus // split format with all pointers first (in the declared position) and all
644c263edeSDiana Picus // LEN arguments appended after all of the dummy arguments.
654c263edeSDiana Picus // NB: Other conventions/ABIs can/should be supported via options.
6665431d3aSDiana Picus marshal.emplace_back(idxTy, AT{/*alignment=*/0, /*byval=*/false,
6765431d3aSDiana Picus /*sret=*/sret, /*append=*/!sret});
684c263edeSDiana Picus return marshal;
694c263edeSDiana Picus }
704c263edeSDiana Picus };
714c263edeSDiana Picus } // namespace
724c263edeSDiana Picus
734c263edeSDiana Picus //===----------------------------------------------------------------------===//
744c263edeSDiana Picus // i386 (x86 32 bit) linux target specifics.
754c263edeSDiana Picus //===----------------------------------------------------------------------===//
764c263edeSDiana Picus
774c263edeSDiana Picus namespace {
784c263edeSDiana Picus struct TargetI386 : public GenericTarget<TargetI386> {
794c263edeSDiana Picus using GenericTarget::GenericTarget;
804c263edeSDiana Picus
814c263edeSDiana Picus static constexpr int defaultWidth = 32;
8265431d3aSDiana Picus
8365431d3aSDiana Picus CodeGenSpecifics::Marshalling
complexArgumentType__anonc3f2b8ea0211::TargetI386840c1cf585SEric Schweitz complexArgumentType(mlir::Location, mlir::Type eleTy) const override {
8565431d3aSDiana Picus assert(fir::isa_real(eleTy));
8665431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal;
87faf869dcSDiana Picus // Use a type that will be translated into LLVM as:
8865431d3aSDiana Picus // { t, t } struct of 2 eleTy, byval, align 4
8965431d3aSDiana Picus mlir::TypeRange range = {eleTy, eleTy};
9065431d3aSDiana Picus auto structTy = mlir::TupleType::get(eleTy.getContext(), range);
9165431d3aSDiana Picus marshal.emplace_back(fir::ReferenceType::get(structTy),
9265431d3aSDiana Picus AT{/*alignment=*/4, /*byval=*/true});
9365431d3aSDiana Picus return marshal;
9465431d3aSDiana Picus }
9565431d3aSDiana Picus
9665431d3aSDiana Picus CodeGenSpecifics::Marshalling
complexReturnType__anonc3f2b8ea0211::TargetI386970c1cf585SEric Schweitz complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
9865431d3aSDiana Picus assert(fir::isa_real(eleTy));
9965431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal;
10065431d3aSDiana Picus const auto *sem = &floatToSemantics(kindMap, eleTy);
10165431d3aSDiana Picus if (sem == &llvm::APFloat::IEEEsingle()) {
10265431d3aSDiana Picus // i64 pack both floats in a 64-bit GPR
10365431d3aSDiana Picus marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64),
10465431d3aSDiana Picus AT{});
10565431d3aSDiana Picus } else if (sem == &llvm::APFloat::IEEEdouble()) {
106faf869dcSDiana Picus // Use a type that will be translated into LLVM as:
10765431d3aSDiana Picus // { t, t } struct of 2 eleTy, sret, align 4
10865431d3aSDiana Picus mlir::TypeRange range = {eleTy, eleTy};
10965431d3aSDiana Picus auto structTy = mlir::TupleType::get(eleTy.getContext(), range);
11065431d3aSDiana Picus marshal.emplace_back(fir::ReferenceType::get(structTy),
11165431d3aSDiana Picus AT{/*alignment=*/4, /*byval=*/false, /*sret=*/true});
11265431d3aSDiana Picus } else {
1130c1cf585SEric Schweitz TODO(loc, "complex for this precision");
11465431d3aSDiana Picus }
11565431d3aSDiana Picus return marshal;
11665431d3aSDiana Picus }
1174c263edeSDiana Picus };
1184c263edeSDiana Picus } // namespace
1194c263edeSDiana Picus
1204c263edeSDiana Picus //===----------------------------------------------------------------------===//
1214c263edeSDiana Picus // x86_64 (x86 64 bit) linux target specifics.
1224c263edeSDiana Picus //===----------------------------------------------------------------------===//
1234c263edeSDiana Picus
1244c263edeSDiana Picus namespace {
1254c263edeSDiana Picus struct TargetX86_64 : public GenericTarget<TargetX86_64> {
1264c263edeSDiana Picus using GenericTarget::GenericTarget;
1274c263edeSDiana Picus
1284c263edeSDiana Picus static constexpr int defaultWidth = 64;
12965431d3aSDiana Picus
13065431d3aSDiana Picus CodeGenSpecifics::Marshalling
complexArgumentType__anonc3f2b8ea0311::TargetX86_641310c1cf585SEric Schweitz complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override {
13265431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal;
13365431d3aSDiana Picus const auto *sem = &floatToSemantics(kindMap, eleTy);
13465431d3aSDiana Picus if (sem == &llvm::APFloat::IEEEsingle()) {
13565431d3aSDiana Picus // <2 x t> vector of 2 eleTy
13665431d3aSDiana Picus marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{});
13765431d3aSDiana Picus } else if (sem == &llvm::APFloat::IEEEdouble()) {
13865431d3aSDiana Picus // two distinct double arguments
13965431d3aSDiana Picus marshal.emplace_back(eleTy, AT{});
14065431d3aSDiana Picus marshal.emplace_back(eleTy, AT{});
1411906188fSValentin Clement } else if (sem == &llvm::APFloat::IEEEquad()) {
1421906188fSValentin Clement // Use a type that will be translated into LLVM as:
1431906188fSValentin Clement // { fp128, fp128 } struct of 2 fp128, byval, align 16
1441906188fSValentin Clement mlir::TypeRange range = {eleTy, eleTy};
1451906188fSValentin Clement marshal.emplace_back(fir::ReferenceType::get(
1461906188fSValentin Clement mlir::TupleType::get(eleTy.getContext(), range)),
1471906188fSValentin Clement AT{/*align=*/16, /*byval=*/true});
14865431d3aSDiana Picus } else {
1490c1cf585SEric Schweitz TODO(loc, "complex for this precision");
15065431d3aSDiana Picus }
15165431d3aSDiana Picus return marshal;
15265431d3aSDiana Picus }
15365431d3aSDiana Picus
15465431d3aSDiana Picus CodeGenSpecifics::Marshalling
complexReturnType__anonc3f2b8ea0311::TargetX86_641550c1cf585SEric Schweitz complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
15665431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal;
15765431d3aSDiana Picus const auto *sem = &floatToSemantics(kindMap, eleTy);
15865431d3aSDiana Picus if (sem == &llvm::APFloat::IEEEsingle()) {
15965431d3aSDiana Picus // <2 x t> vector of 2 eleTy
16065431d3aSDiana Picus marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{});
16165431d3aSDiana Picus } else if (sem == &llvm::APFloat::IEEEdouble()) {
162faf869dcSDiana Picus // Use a type that will be translated into LLVM as:
163faf869dcSDiana Picus // { double, double } struct of 2 double
16465431d3aSDiana Picus mlir::TypeRange range = {eleTy, eleTy};
16565431d3aSDiana Picus marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range),
16665431d3aSDiana Picus AT{});
1671906188fSValentin Clement } else if (sem == &llvm::APFloat::IEEEquad()) {
1681906188fSValentin Clement // Use a type that will be translated into LLVM as:
1691906188fSValentin Clement // { fp128, fp128 } struct of 2 fp128, sret, align 16
1701906188fSValentin Clement mlir::TypeRange range = {eleTy, eleTy};
1711906188fSValentin Clement marshal.emplace_back(fir::ReferenceType::get(
1721906188fSValentin Clement mlir::TupleType::get(eleTy.getContext(), range)),
1731906188fSValentin Clement AT{/*align=*/16, /*byval=*/false, /*sret=*/true});
17465431d3aSDiana Picus } else {
1750c1cf585SEric Schweitz TODO(loc, "complex for this precision");
17665431d3aSDiana Picus }
17765431d3aSDiana Picus return marshal;
17865431d3aSDiana Picus }
1794c263edeSDiana Picus };
1804c263edeSDiana Picus } // namespace
1814c263edeSDiana Picus
1824c263edeSDiana Picus //===----------------------------------------------------------------------===//
1834c263edeSDiana Picus // AArch64 linux target specifics.
1844c263edeSDiana Picus //===----------------------------------------------------------------------===//
1854c263edeSDiana Picus
1864c263edeSDiana Picus namespace {
1874c263edeSDiana Picus struct TargetAArch64 : public GenericTarget<TargetAArch64> {
1884c263edeSDiana Picus using GenericTarget::GenericTarget;
1894c263edeSDiana Picus
1904c263edeSDiana Picus static constexpr int defaultWidth = 64;
19165431d3aSDiana Picus
19265431d3aSDiana Picus CodeGenSpecifics::Marshalling
complexArgumentType__anonc3f2b8ea0411::TargetAArch641930c1cf585SEric Schweitz complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override {
19465431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal;
19565431d3aSDiana Picus const auto *sem = &floatToSemantics(kindMap, eleTy);
19665431d3aSDiana Picus if (sem == &llvm::APFloat::IEEEsingle() ||
19765431d3aSDiana Picus sem == &llvm::APFloat::IEEEdouble()) {
19865431d3aSDiana Picus // [2 x t] array of 2 eleTy
19965431d3aSDiana Picus marshal.emplace_back(fir::SequenceType::get({2}, eleTy), AT{});
20065431d3aSDiana Picus } else {
2010c1cf585SEric Schweitz TODO(loc, "complex for this precision");
20265431d3aSDiana Picus }
20365431d3aSDiana Picus return marshal;
20465431d3aSDiana Picus }
20565431d3aSDiana Picus
20665431d3aSDiana Picus CodeGenSpecifics::Marshalling
complexReturnType__anonc3f2b8ea0411::TargetAArch642070c1cf585SEric Schweitz complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
20865431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal;
20965431d3aSDiana Picus const auto *sem = &floatToSemantics(kindMap, eleTy);
21065431d3aSDiana Picus if (sem == &llvm::APFloat::IEEEsingle() ||
21165431d3aSDiana Picus sem == &llvm::APFloat::IEEEdouble()) {
212faf869dcSDiana Picus // Use a type that will be translated into LLVM as:
213faf869dcSDiana Picus // { t, t } struct of 2 eleTy
21465431d3aSDiana Picus mlir::TypeRange range = {eleTy, eleTy};
21565431d3aSDiana Picus marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range),
21665431d3aSDiana Picus AT{});
21765431d3aSDiana Picus } else {
2180c1cf585SEric Schweitz TODO(loc, "complex for this precision");
21965431d3aSDiana Picus }
22065431d3aSDiana Picus return marshal;
22165431d3aSDiana Picus }
2224c263edeSDiana Picus };
2234c263edeSDiana Picus } // namespace
2244c263edeSDiana Picus
2254c263edeSDiana Picus //===----------------------------------------------------------------------===//
2264c263edeSDiana Picus // PPC64le linux target specifics.
2274c263edeSDiana Picus //===----------------------------------------------------------------------===//
2284c263edeSDiana Picus
2294c263edeSDiana Picus namespace {
2304c263edeSDiana Picus struct TargetPPC64le : public GenericTarget<TargetPPC64le> {
2314c263edeSDiana Picus using GenericTarget::GenericTarget;
2324c263edeSDiana Picus
2334c263edeSDiana Picus static constexpr int defaultWidth = 64;
23465431d3aSDiana Picus
23565431d3aSDiana Picus CodeGenSpecifics::Marshalling
complexArgumentType__anonc3f2b8ea0511::TargetPPC64le2360c1cf585SEric Schweitz complexArgumentType(mlir::Location, mlir::Type eleTy) const override {
23765431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal;
23865431d3aSDiana Picus // two distinct element type arguments (re, im)
23965431d3aSDiana Picus marshal.emplace_back(eleTy, AT{});
24065431d3aSDiana Picus marshal.emplace_back(eleTy, AT{});
24165431d3aSDiana Picus return marshal;
24265431d3aSDiana Picus }
24365431d3aSDiana Picus
24465431d3aSDiana Picus CodeGenSpecifics::Marshalling
complexReturnType__anonc3f2b8ea0511::TargetPPC64le2450c1cf585SEric Schweitz complexReturnType(mlir::Location, mlir::Type eleTy) const override {
24665431d3aSDiana Picus CodeGenSpecifics::Marshalling marshal;
247faf869dcSDiana Picus // Use a type that will be translated into LLVM as:
248faf869dcSDiana Picus // { t, t } struct of 2 element type
24965431d3aSDiana Picus mlir::TypeRange range = {eleTy, eleTy};
25065431d3aSDiana Picus marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range), AT{});
25165431d3aSDiana Picus return marshal;
25265431d3aSDiana Picus }
2534c263edeSDiana Picus };
2544c263edeSDiana Picus } // namespace
2554c263edeSDiana Picus
2564c263edeSDiana Picus // Instantiate the overloaded target instance based on the triple value.
257b389fbd0SAndrzej Warzynski // TODO: Add other targets to this file as needed.
2584c263edeSDiana Picus std::unique_ptr<fir::CodeGenSpecifics>
get(mlir::MLIRContext * ctx,llvm::Triple && trp,KindMapping && kindMap)2594c263edeSDiana Picus fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp,
2604c263edeSDiana Picus KindMapping &&kindMap) {
2614c263edeSDiana Picus switch (trp.getArch()) {
2624c263edeSDiana Picus default:
2634c263edeSDiana Picus break;
2644c263edeSDiana Picus case llvm::Triple::ArchType::x86:
2654c263edeSDiana Picus switch (trp.getOS()) {
2664c263edeSDiana Picus default:
2674c263edeSDiana Picus break;
2684c263edeSDiana Picus case llvm::Triple::OSType::Linux:
2694c263edeSDiana Picus case llvm::Triple::OSType::Darwin:
270e601b2a1SAndrzej Warzynski case llvm::Triple::OSType::MacOSX:
271*67ea7a1bSRainer Orth case llvm::Triple::OSType::Solaris:
272b389fbd0SAndrzej Warzynski case llvm::Triple::OSType::Win32:
2734c263edeSDiana Picus return std::make_unique<TargetI386>(ctx, std::move(trp),
2744c263edeSDiana Picus std::move(kindMap));
2754c263edeSDiana Picus }
2764c263edeSDiana Picus break;
2774c263edeSDiana Picus case llvm::Triple::ArchType::x86_64:
2784c263edeSDiana Picus switch (trp.getOS()) {
2794c263edeSDiana Picus default:
2804c263edeSDiana Picus break;
2814c263edeSDiana Picus case llvm::Triple::OSType::Linux:
2824c263edeSDiana Picus case llvm::Triple::OSType::Darwin:
283e601b2a1SAndrzej Warzynski case llvm::Triple::OSType::MacOSX:
284*67ea7a1bSRainer Orth case llvm::Triple::OSType::Solaris:
285b389fbd0SAndrzej Warzynski case llvm::Triple::OSType::Win32:
2864c263edeSDiana Picus return std::make_unique<TargetX86_64>(ctx, std::move(trp),
2874c263edeSDiana Picus std::move(kindMap));
2884c263edeSDiana Picus }
2894c263edeSDiana Picus break;
2904c263edeSDiana Picus case llvm::Triple::ArchType::aarch64:
2914c263edeSDiana Picus switch (trp.getOS()) {
2924c263edeSDiana Picus default:
2934c263edeSDiana Picus break;
2944c263edeSDiana Picus case llvm::Triple::OSType::Linux:
2954c263edeSDiana Picus case llvm::Triple::OSType::Darwin:
296e601b2a1SAndrzej Warzynski case llvm::Triple::OSType::MacOSX:
297b389fbd0SAndrzej Warzynski case llvm::Triple::OSType::Win32:
2984c263edeSDiana Picus return std::make_unique<TargetAArch64>(ctx, std::move(trp),
2994c263edeSDiana Picus std::move(kindMap));
3004c263edeSDiana Picus }
3014c263edeSDiana Picus break;
3024c263edeSDiana Picus case llvm::Triple::ArchType::ppc64le:
3034c263edeSDiana Picus switch (trp.getOS()) {
3044c263edeSDiana Picus default:
3054c263edeSDiana Picus break;
3064c263edeSDiana Picus case llvm::Triple::OSType::Linux:
3074c263edeSDiana Picus return std::make_unique<TargetPPC64le>(ctx, std::move(trp),
3084c263edeSDiana Picus std::move(kindMap));
3094c263edeSDiana Picus }
3104c263edeSDiana Picus break;
3114c263edeSDiana Picus }
3120c1cf585SEric Schweitz TODO(mlir::UnknownLoc::get(ctx), "target not implemented");
3134c263edeSDiana Picus }
314