1 //===-- Target.cpp --------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "Target.h"
14 #include "flang/Optimizer/Builder/Todo.h"
15 #include "flang/Optimizer/Dialect/FIRType.h"
16 #include "flang/Optimizer/Support/FatalError.h"
17 #include "flang/Optimizer/Support/KindMapping.h"
18 #include "mlir/IR/BuiltinTypes.h"
19 #include "mlir/IR/TypeRange.h"
20
21 #define DEBUG_TYPE "flang-codegen-target"
22
23 using namespace fir;
24
25 // Reduce a REAL/float type to the floating point semantics.
floatToSemantics(const KindMapping & kindMap,mlir::Type type)26 static const llvm::fltSemantics &floatToSemantics(const KindMapping &kindMap,
27 mlir::Type type) {
28 assert(isa_real(type));
29 if (auto ty = type.dyn_cast<fir::RealType>())
30 return kindMap.getFloatSemantics(ty.getFKind());
31 return type.cast<mlir::FloatType>().getFloatSemantics();
32 }
33
34 namespace {
35 template <typename S>
36 struct GenericTarget : public CodeGenSpecifics {
37 using CodeGenSpecifics::CodeGenSpecifics;
38 using AT = CodeGenSpecifics::Attributes;
39
complexMemoryType__anonc3f2b8ea0111::GenericTarget40 mlir::Type complexMemoryType(mlir::Type eleTy) const override {
41 assert(fir::isa_real(eleTy));
42 // Use a type that will be translated into LLVM as:
43 // { t, t } struct of 2 eleTy
44 mlir::TypeRange range = {eleTy, eleTy};
45 return mlir::TupleType::get(eleTy.getContext(), range);
46 }
47
boxcharMemoryType__anonc3f2b8ea0111::GenericTarget48 mlir::Type boxcharMemoryType(mlir::Type eleTy) const override {
49 auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth);
50 auto ptrTy = fir::ReferenceType::get(eleTy);
51 // Use a type that will be translated into LLVM as:
52 // { t*, index }
53 mlir::TypeRange range = {ptrTy, idxTy};
54 return mlir::TupleType::get(eleTy.getContext(), range);
55 }
56
boxcharArgumentType__anonc3f2b8ea0111::GenericTarget57 Marshalling boxcharArgumentType(mlir::Type eleTy, bool sret) const override {
58 CodeGenSpecifics::Marshalling marshal;
59 auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth);
60 auto ptrTy = fir::ReferenceType::get(eleTy);
61 marshal.emplace_back(ptrTy, AT{});
62 // Return value arguments are grouped as a pair. Others are passed in a
63 // split format with all pointers first (in the declared position) and all
64 // LEN arguments appended after all of the dummy arguments.
65 // NB: Other conventions/ABIs can/should be supported via options.
66 marshal.emplace_back(idxTy, AT{/*alignment=*/0, /*byval=*/false,
67 /*sret=*/sret, /*append=*/!sret});
68 return marshal;
69 }
70 };
71 } // namespace
72
73 //===----------------------------------------------------------------------===//
74 // i386 (x86 32 bit) linux target specifics.
75 //===----------------------------------------------------------------------===//
76
77 namespace {
78 struct TargetI386 : public GenericTarget<TargetI386> {
79 using GenericTarget::GenericTarget;
80
81 static constexpr int defaultWidth = 32;
82
83 CodeGenSpecifics::Marshalling
complexArgumentType__anonc3f2b8ea0211::TargetI38684 complexArgumentType(mlir::Location, mlir::Type eleTy) const override {
85 assert(fir::isa_real(eleTy));
86 CodeGenSpecifics::Marshalling marshal;
87 // Use a type that will be translated into LLVM as:
88 // { t, t } struct of 2 eleTy, byval, align 4
89 mlir::TypeRange range = {eleTy, eleTy};
90 auto structTy = mlir::TupleType::get(eleTy.getContext(), range);
91 marshal.emplace_back(fir::ReferenceType::get(structTy),
92 AT{/*alignment=*/4, /*byval=*/true});
93 return marshal;
94 }
95
96 CodeGenSpecifics::Marshalling
complexReturnType__anonc3f2b8ea0211::TargetI38697 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
98 assert(fir::isa_real(eleTy));
99 CodeGenSpecifics::Marshalling marshal;
100 const auto *sem = &floatToSemantics(kindMap, eleTy);
101 if (sem == &llvm::APFloat::IEEEsingle()) {
102 // i64 pack both floats in a 64-bit GPR
103 marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64),
104 AT{});
105 } else if (sem == &llvm::APFloat::IEEEdouble()) {
106 // Use a type that will be translated into LLVM as:
107 // { t, t } struct of 2 eleTy, sret, align 4
108 mlir::TypeRange range = {eleTy, eleTy};
109 auto structTy = mlir::TupleType::get(eleTy.getContext(), range);
110 marshal.emplace_back(fir::ReferenceType::get(structTy),
111 AT{/*alignment=*/4, /*byval=*/false, /*sret=*/true});
112 } else {
113 TODO(loc, "complex for this precision");
114 }
115 return marshal;
116 }
117 };
118 } // namespace
119
120 //===----------------------------------------------------------------------===//
121 // x86_64 (x86 64 bit) linux target specifics.
122 //===----------------------------------------------------------------------===//
123
124 namespace {
125 struct TargetX86_64 : public GenericTarget<TargetX86_64> {
126 using GenericTarget::GenericTarget;
127
128 static constexpr int defaultWidth = 64;
129
130 CodeGenSpecifics::Marshalling
complexArgumentType__anonc3f2b8ea0311::TargetX86_64131 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override {
132 CodeGenSpecifics::Marshalling marshal;
133 const auto *sem = &floatToSemantics(kindMap, eleTy);
134 if (sem == &llvm::APFloat::IEEEsingle()) {
135 // <2 x t> vector of 2 eleTy
136 marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{});
137 } else if (sem == &llvm::APFloat::IEEEdouble()) {
138 // two distinct double arguments
139 marshal.emplace_back(eleTy, AT{});
140 marshal.emplace_back(eleTy, AT{});
141 } else if (sem == &llvm::APFloat::IEEEquad()) {
142 // Use a type that will be translated into LLVM as:
143 // { fp128, fp128 } struct of 2 fp128, byval, align 16
144 mlir::TypeRange range = {eleTy, eleTy};
145 marshal.emplace_back(fir::ReferenceType::get(
146 mlir::TupleType::get(eleTy.getContext(), range)),
147 AT{/*align=*/16, /*byval=*/true});
148 } else {
149 TODO(loc, "complex for this precision");
150 }
151 return marshal;
152 }
153
154 CodeGenSpecifics::Marshalling
complexReturnType__anonc3f2b8ea0311::TargetX86_64155 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
156 CodeGenSpecifics::Marshalling marshal;
157 const auto *sem = &floatToSemantics(kindMap, eleTy);
158 if (sem == &llvm::APFloat::IEEEsingle()) {
159 // <2 x t> vector of 2 eleTy
160 marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{});
161 } else if (sem == &llvm::APFloat::IEEEdouble()) {
162 // Use a type that will be translated into LLVM as:
163 // { double, double } struct of 2 double
164 mlir::TypeRange range = {eleTy, eleTy};
165 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range),
166 AT{});
167 } else if (sem == &llvm::APFloat::IEEEquad()) {
168 // Use a type that will be translated into LLVM as:
169 // { fp128, fp128 } struct of 2 fp128, sret, align 16
170 mlir::TypeRange range = {eleTy, eleTy};
171 marshal.emplace_back(fir::ReferenceType::get(
172 mlir::TupleType::get(eleTy.getContext(), range)),
173 AT{/*align=*/16, /*byval=*/false, /*sret=*/true});
174 } else {
175 TODO(loc, "complex for this precision");
176 }
177 return marshal;
178 }
179 };
180 } // namespace
181
182 //===----------------------------------------------------------------------===//
183 // AArch64 linux target specifics.
184 //===----------------------------------------------------------------------===//
185
186 namespace {
187 struct TargetAArch64 : public GenericTarget<TargetAArch64> {
188 using GenericTarget::GenericTarget;
189
190 static constexpr int defaultWidth = 64;
191
192 CodeGenSpecifics::Marshalling
complexArgumentType__anonc3f2b8ea0411::TargetAArch64193 complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override {
194 CodeGenSpecifics::Marshalling marshal;
195 const auto *sem = &floatToSemantics(kindMap, eleTy);
196 if (sem == &llvm::APFloat::IEEEsingle() ||
197 sem == &llvm::APFloat::IEEEdouble()) {
198 // [2 x t] array of 2 eleTy
199 marshal.emplace_back(fir::SequenceType::get({2}, eleTy), AT{});
200 } else {
201 TODO(loc, "complex for this precision");
202 }
203 return marshal;
204 }
205
206 CodeGenSpecifics::Marshalling
complexReturnType__anonc3f2b8ea0411::TargetAArch64207 complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
208 CodeGenSpecifics::Marshalling marshal;
209 const auto *sem = &floatToSemantics(kindMap, eleTy);
210 if (sem == &llvm::APFloat::IEEEsingle() ||
211 sem == &llvm::APFloat::IEEEdouble()) {
212 // Use a type that will be translated into LLVM as:
213 // { t, t } struct of 2 eleTy
214 mlir::TypeRange range = {eleTy, eleTy};
215 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range),
216 AT{});
217 } else {
218 TODO(loc, "complex for this precision");
219 }
220 return marshal;
221 }
222 };
223 } // namespace
224
225 //===----------------------------------------------------------------------===//
226 // PPC64le linux target specifics.
227 //===----------------------------------------------------------------------===//
228
229 namespace {
230 struct TargetPPC64le : public GenericTarget<TargetPPC64le> {
231 using GenericTarget::GenericTarget;
232
233 static constexpr int defaultWidth = 64;
234
235 CodeGenSpecifics::Marshalling
complexArgumentType__anonc3f2b8ea0511::TargetPPC64le236 complexArgumentType(mlir::Location, mlir::Type eleTy) const override {
237 CodeGenSpecifics::Marshalling marshal;
238 // two distinct element type arguments (re, im)
239 marshal.emplace_back(eleTy, AT{});
240 marshal.emplace_back(eleTy, AT{});
241 return marshal;
242 }
243
244 CodeGenSpecifics::Marshalling
complexReturnType__anonc3f2b8ea0511::TargetPPC64le245 complexReturnType(mlir::Location, mlir::Type eleTy) const override {
246 CodeGenSpecifics::Marshalling marshal;
247 // Use a type that will be translated into LLVM as:
248 // { t, t } struct of 2 element type
249 mlir::TypeRange range = {eleTy, eleTy};
250 marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range), AT{});
251 return marshal;
252 }
253 };
254 } // namespace
255
256 // Instantiate the overloaded target instance based on the triple value.
257 // TODO: Add other targets to this file as needed.
258 std::unique_ptr<fir::CodeGenSpecifics>
get(mlir::MLIRContext * ctx,llvm::Triple && trp,KindMapping && kindMap)259 fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp,
260 KindMapping &&kindMap) {
261 switch (trp.getArch()) {
262 default:
263 break;
264 case llvm::Triple::ArchType::x86:
265 switch (trp.getOS()) {
266 default:
267 break;
268 case llvm::Triple::OSType::Linux:
269 case llvm::Triple::OSType::Darwin:
270 case llvm::Triple::OSType::MacOSX:
271 case llvm::Triple::OSType::Solaris:
272 case llvm::Triple::OSType::Win32:
273 return std::make_unique<TargetI386>(ctx, std::move(trp),
274 std::move(kindMap));
275 }
276 break;
277 case llvm::Triple::ArchType::x86_64:
278 switch (trp.getOS()) {
279 default:
280 break;
281 case llvm::Triple::OSType::Linux:
282 case llvm::Triple::OSType::Darwin:
283 case llvm::Triple::OSType::MacOSX:
284 case llvm::Triple::OSType::Solaris:
285 case llvm::Triple::OSType::Win32:
286 return std::make_unique<TargetX86_64>(ctx, std::move(trp),
287 std::move(kindMap));
288 }
289 break;
290 case llvm::Triple::ArchType::aarch64:
291 switch (trp.getOS()) {
292 default:
293 break;
294 case llvm::Triple::OSType::Linux:
295 case llvm::Triple::OSType::Darwin:
296 case llvm::Triple::OSType::MacOSX:
297 case llvm::Triple::OSType::Win32:
298 return std::make_unique<TargetAArch64>(ctx, std::move(trp),
299 std::move(kindMap));
300 }
301 break;
302 case llvm::Triple::ArchType::ppc64le:
303 switch (trp.getOS()) {
304 default:
305 break;
306 case llvm::Triple::OSType::Linux:
307 return std::make_unique<TargetPPC64le>(ctx, std::move(trp),
308 std::move(kindMap));
309 }
310 break;
311 }
312 TODO(mlir::UnknownLoc::get(ctx), "target not implemented");
313 }
314