1 //===-- KindMapping.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 "flang/Optimizer/Support/KindMapping.h"
14 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
15 #include "llvm/Support/CommandLine.h"
16 
17 /// Allow the user to set the FIR intrinsic type kind value to LLVM type
18 /// mappings.  Note that these are not mappings from kind values to any
19 /// other MLIR dialect, only to LLVM IR. The default values follow the f18
20 /// front-end kind mappings.
21 
22 using Bitsize = fir::KindMapping::Bitsize;
23 using KindTy = fir::KindMapping::KindTy;
24 using LLVMTypeID = fir::KindMapping::LLVMTypeID;
25 using MatchResult = fir::KindMapping::MatchResult;
26 
27 static llvm::cl::opt<std::string> clKindMapping(
28     "kind-mapping", llvm::cl::desc("kind mapping string to set kind precision"),
29     llvm::cl::value_desc("kind-mapping-string"), llvm::cl::init(""));
30 
31 /// Integral types default to the kind value being the size of the value in
32 /// bytes. The default is to scale from bytes to bits.
33 static Bitsize defaultScalingKind(KindTy kind) {
34   const unsigned BITS_IN_BYTE = 8;
35   return kind * BITS_IN_BYTE;
36 }
37 
38 /// Floating-point types default to the kind value being the size of the value
39 /// in bytes. The default is to translate kinds of 2, 3, 4, 8, 10, and 16 to a
40 /// valid llvm::Type::TypeID value. Otherwise, the default is FloatTyID.
41 static LLVMTypeID defaultRealKind(KindTy kind) {
42   switch (kind) {
43   case 2:
44     return LLVMTypeID::HalfTyID;
45   case 3:
46     return LLVMTypeID::BFloatTyID;
47   case 4:
48     return LLVMTypeID::FloatTyID;
49   case 8:
50     return LLVMTypeID::DoubleTyID;
51   case 10:
52     return LLVMTypeID::X86_FP80TyID;
53   case 16:
54     return LLVMTypeID::FP128TyID;
55   default:
56     return LLVMTypeID::FloatTyID;
57   }
58 }
59 
60 // lookup the kind-value given the defaults, the mappings, and a KIND key
61 template <typename RT, char KEY>
62 static RT doLookup(std::function<RT(KindTy)> def,
63                    const llvm::DenseMap<std::pair<char, KindTy>, RT> &map,
64                    KindTy kind) {
65   std::pair<char, KindTy> key{KEY, kind};
66   auto iter = map.find(key);
67   if (iter != map.end())
68     return iter->second;
69   return def(kind);
70 }
71 
72 // do a lookup for INTERGER, LOGICAL, or CHARACTER
73 template <char KEY, typename MAP>
74 static Bitsize getIntegerLikeBitsize(KindTy kind, const MAP &map) {
75   return doLookup<Bitsize, KEY>(defaultScalingKind, map, kind);
76 }
77 
78 // do a lookup for REAL or COMPLEX
79 template <char KEY, typename MAP>
80 static LLVMTypeID getFloatLikeTypeID(KindTy kind, const MAP &map) {
81   return doLookup<LLVMTypeID, KEY>(defaultRealKind, map, kind);
82 }
83 
84 template <char KEY, typename MAP>
85 static const llvm::fltSemantics &getFloatSemanticsOfKind(KindTy kind,
86                                                          const MAP &map) {
87   switch (doLookup<LLVMTypeID, KEY>(defaultRealKind, map, kind)) {
88   case LLVMTypeID::HalfTyID:
89     return llvm::APFloat::IEEEhalf();
90   case LLVMTypeID::BFloatTyID:
91     return llvm::APFloat::BFloat();
92   case LLVMTypeID::FloatTyID:
93     return llvm::APFloat::IEEEsingle();
94   case LLVMTypeID::DoubleTyID:
95     return llvm::APFloat::IEEEdouble();
96   case LLVMTypeID::X86_FP80TyID:
97     return llvm::APFloat::x87DoubleExtended();
98   case LLVMTypeID::FP128TyID:
99     return llvm::APFloat::IEEEquad();
100   case LLVMTypeID::PPC_FP128TyID:
101     return llvm::APFloat::PPCDoubleDouble();
102   default:
103     llvm_unreachable("Invalid floating type");
104   }
105 }
106 
107 static MatchResult parseCode(char &code, const char *&ptr) {
108   if (*ptr != 'a' && *ptr != 'c' && *ptr != 'i' && *ptr != 'l' && *ptr != 'r')
109     return mlir::failure();
110   code = *ptr++;
111   return mlir::success();
112 }
113 
114 template <char ch>
115 static MatchResult parseSingleChar(const char *&ptr) {
116   if (*ptr != ch)
117     return mlir::failure();
118   ++ptr;
119   return mlir::success();
120 }
121 
122 static MatchResult parseColon(const char *&ptr) {
123   return parseSingleChar<':'>(ptr);
124 }
125 
126 static MatchResult parseComma(const char *&ptr) {
127   return parseSingleChar<','>(ptr);
128 }
129 
130 static MatchResult parseInt(unsigned &result, const char *&ptr) {
131   const char *beg = ptr;
132   while (*ptr >= '0' && *ptr <= '9')
133     ptr++;
134   if (beg == ptr)
135     return mlir::failure();
136   llvm::StringRef ref(beg, ptr - beg);
137   int temp;
138   if (ref.consumeInteger(10, temp))
139     return mlir::failure();
140   result = temp;
141   return mlir::success();
142 }
143 
144 static mlir::LogicalResult matchString(const char *&ptr,
145                                        llvm::StringRef literal) {
146   llvm::StringRef s(ptr);
147   if (s.startswith(literal)) {
148     ptr += literal.size();
149     return mlir::success();
150   }
151   return mlir::failure();
152 }
153 
154 static MatchResult parseTypeID(LLVMTypeID &result, const char *&ptr) {
155   if (mlir::succeeded(matchString(ptr, "Half"))) {
156     result = LLVMTypeID::HalfTyID;
157     return mlir::success();
158   }
159   if (mlir::succeeded(matchString(ptr, "BFloat"))) {
160     result = LLVMTypeID::BFloatTyID;
161     return mlir::success();
162   }
163   if (mlir::succeeded(matchString(ptr, "Float"))) {
164     result = LLVMTypeID::FloatTyID;
165     return mlir::success();
166   }
167   if (mlir::succeeded(matchString(ptr, "Double"))) {
168     result = LLVMTypeID::DoubleTyID;
169     return mlir::success();
170   }
171   if (mlir::succeeded(matchString(ptr, "X86_FP80"))) {
172     result = LLVMTypeID::X86_FP80TyID;
173     return mlir::success();
174   }
175   if (mlir::succeeded(matchString(ptr, "FP128"))) {
176     result = LLVMTypeID::FP128TyID;
177     return mlir::success();
178   }
179   if (mlir::succeeded(matchString(ptr, "PPC_FP128"))) {
180     result = LLVMTypeID::PPC_FP128TyID;
181     return mlir::success();
182   }
183   return mlir::failure();
184 }
185 
186 fir::KindMapping::KindMapping(mlir::MLIRContext *context, llvm::StringRef map,
187                               llvm::ArrayRef<KindTy> defs)
188     : context{context} {
189   if (mlir::failed(setDefaultKinds(defs)))
190     llvm::report_fatal_error("bad default kinds");
191   if (mlir::failed(parse(map)))
192     llvm::report_fatal_error("could not parse kind map");
193 }
194 
195 fir::KindMapping::KindMapping(mlir::MLIRContext *context,
196                               llvm::ArrayRef<KindTy> defs)
197     : KindMapping{context, clKindMapping, defs} {}
198 
199 MatchResult fir::KindMapping::badMapString(const llvm::Twine &ptr) {
200   auto unknown = mlir::UnknownLoc::get(context);
201   mlir::emitError(unknown, ptr);
202   return mlir::failure();
203 }
204 
205 MatchResult fir::KindMapping::parse(llvm::StringRef kindMap) {
206   if (kindMap.empty())
207     return mlir::success();
208   const char *srcPtr = kindMap.begin();
209   while (true) {
210     char code = '\0';
211     KindTy kind = 0;
212     if (parseCode(code, srcPtr) || parseInt(kind, srcPtr))
213       return badMapString(srcPtr);
214     if (code == 'a' || code == 'i' || code == 'l') {
215       Bitsize bits = 0;
216       if (parseColon(srcPtr) || parseInt(bits, srcPtr))
217         return badMapString(srcPtr);
218       intMap[std::pair<char, KindTy>{code, kind}] = bits;
219     } else if (code == 'r' || code == 'c') {
220       LLVMTypeID id{};
221       if (parseColon(srcPtr) || parseTypeID(id, srcPtr))
222         return badMapString(srcPtr);
223       floatMap[std::pair<char, KindTy>{code, kind}] = id;
224     } else {
225       return badMapString(srcPtr);
226     }
227     if (parseComma(srcPtr))
228       break;
229   }
230   if (*srcPtr)
231     return badMapString(srcPtr);
232   return mlir::success();
233 }
234 
235 Bitsize fir::KindMapping::getCharacterBitsize(KindTy kind) const {
236   return getIntegerLikeBitsize<'a'>(kind, intMap);
237 }
238 
239 Bitsize fir::KindMapping::getIntegerBitsize(KindTy kind) const {
240   return getIntegerLikeBitsize<'i'>(kind, intMap);
241 }
242 
243 Bitsize fir::KindMapping::getLogicalBitsize(KindTy kind) const {
244   return getIntegerLikeBitsize<'l'>(kind, intMap);
245 }
246 
247 LLVMTypeID fir::KindMapping::getRealTypeID(KindTy kind) const {
248   return getFloatLikeTypeID<'r'>(kind, floatMap);
249 }
250 
251 LLVMTypeID fir::KindMapping::getComplexTypeID(KindTy kind) const {
252   return getFloatLikeTypeID<'c'>(kind, floatMap);
253 }
254 
255 Bitsize fir::KindMapping::getRealBitsize(KindTy kind) const {
256   auto typeId = getFloatLikeTypeID<'r'>(kind, floatMap);
257   llvm::LLVMContext llCtxt; // FIXME
258   return llvm::Type::getPrimitiveType(llCtxt, typeId)->getPrimitiveSizeInBits();
259 }
260 
261 const llvm::fltSemantics &
262 fir::KindMapping::getFloatSemantics(KindTy kind) const {
263   return getFloatSemanticsOfKind<'r'>(kind, floatMap);
264 }
265 
266 mlir::LogicalResult
267 fir::KindMapping::setDefaultKinds(llvm::ArrayRef<KindTy> defs) {
268   if (defs.empty()) {
269     // generic front-end defaults
270     const KindTy genericKind = 4;
271     defaultMap.insert({'a', 1});
272     defaultMap.insert({'c', genericKind});
273     defaultMap.insert({'d', 2 * genericKind});
274     defaultMap.insert({'i', genericKind});
275     defaultMap.insert({'l', genericKind});
276     defaultMap.insert({'r', genericKind});
277     return mlir::success();
278   }
279   if (defs.size() != 6)
280     return mlir::failure();
281 
282   // defaults determined after command-line processing
283   defaultMap.insert({'a', defs[0]});
284   defaultMap.insert({'c', defs[1]});
285   defaultMap.insert({'d', defs[2]});
286   defaultMap.insert({'i', defs[3]});
287   defaultMap.insert({'l', defs[4]});
288   defaultMap.insert({'r', defs[5]});
289   return mlir::success();
290 }
291 
292 KindTy fir::KindMapping::defaultCharacterKind() const {
293   auto iter = defaultMap.find('a');
294   assert(iter != defaultMap.end());
295   return iter->second;
296 }
297 
298 KindTy fir::KindMapping::defaultComplexKind() const {
299   auto iter = defaultMap.find('c');
300   assert(iter != defaultMap.end());
301   return iter->second;
302 }
303 
304 KindTy fir::KindMapping::defaultDoubleKind() const {
305   auto iter = defaultMap.find('d');
306   assert(iter != defaultMap.end());
307   return iter->second;
308 }
309 
310 KindTy fir::KindMapping::defaultIntegerKind() const {
311   auto iter = defaultMap.find('i');
312   assert(iter != defaultMap.end());
313   return iter->second;
314 }
315 
316 KindTy fir::KindMapping::defaultLogicalKind() const {
317   auto iter = defaultMap.find('l');
318   assert(iter != defaultMap.end());
319   return iter->second;
320 }
321 
322 KindTy fir::KindMapping::defaultRealKind() const {
323   auto iter = defaultMap.find('r');
324   assert(iter != defaultMap.end());
325   return iter->second;
326 }
327