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 #include "flang/Optimizer/Support/KindMapping.h"
10 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
11 #include "llvm/ADT/Optional.h"
12 #include "llvm/Support/CommandLine.h"
13 
14 /// Allow the user to set the FIR intrinsic type kind value to LLVM type
15 /// mappings.  Note that these are not mappings from kind values to any
16 /// other MLIR dialect, only to LLVM IR. The default values follow the f18
17 /// front-end kind mappings.
18 
19 using Bitsize = fir::KindMapping::Bitsize;
20 using KindTy = fir::KindMapping::KindTy;
21 using LLVMTypeID = fir::KindMapping::LLVMTypeID;
22 using MatchResult = fir::KindMapping::MatchResult;
23 
24 static llvm::cl::opt<std::string> clKindMapping(
25     "kind-mapping", llvm::cl::desc("kind mapping string to set kind precision"),
26     llvm::cl::value_desc("kind-mapping-string"), llvm::cl::init(""));
27 
28 /// Integral types default to the kind value being the size of the value in
29 /// bytes. The default is to scale from bytes to bits.
30 static Bitsize defaultScalingKind(KindTy kind) {
31   const unsigned BITS_IN_BYTE = 8;
32   return kind * BITS_IN_BYTE;
33 }
34 
35 /// Floating-point types default to the kind value being the size of the value
36 /// in bytes. The default is to translate kinds of 2, 4, 8, 10, and 16 to a
37 /// valid llvm::Type::TypeID value. Otherwise, the default is FloatTyID.
38 static LLVMTypeID defaultRealKind(KindTy kind) {
39   switch (kind) {
40   case 2:
41     return LLVMTypeID::HalfTyID;
42   case 4:
43     return LLVMTypeID::FloatTyID;
44   case 8:
45     return LLVMTypeID::DoubleTyID;
46   case 10:
47     return LLVMTypeID::X86_FP80TyID;
48   case 16:
49     return LLVMTypeID::FP128TyID;
50   default:
51     return LLVMTypeID::FloatTyID;
52   }
53 }
54 
55 // lookup the kind-value given the defaults, the mappings, and a KIND key
56 template <typename RT, char KEY>
57 static RT doLookup(std::function<RT(KindTy)> def,
58                    const llvm::DenseMap<std::pair<char, KindTy>, RT> &map,
59                    KindTy kind) {
60   std::pair<char, KindTy> key{KEY, kind};
61   auto iter = map.find(key);
62   if (iter != map.end())
63     return iter->second;
64   return def(kind);
65 }
66 
67 // do a lookup for INTERGER, LOGICAL, or CHARACTER
68 template <char KEY, typename MAP>
69 static Bitsize getIntegerLikeBitsize(KindTy kind, const MAP &map) {
70   return doLookup<Bitsize, KEY>(defaultScalingKind, map, kind);
71 }
72 
73 // do a lookup for REAL or COMPLEX
74 template <char KEY, typename MAP>
75 static LLVMTypeID getFloatLikeTypeID(KindTy kind, const MAP &map) {
76   return doLookup<LLVMTypeID, KEY>(defaultRealKind, map, kind);
77 }
78 
79 template <char KEY, typename MAP>
80 static const llvm::fltSemantics &getFloatSemanticsOfKind(KindTy kind,
81                                                          const MAP &map) {
82   switch (doLookup<LLVMTypeID, KEY>(defaultRealKind, map, kind)) {
83   case LLVMTypeID::HalfTyID:
84     return llvm::APFloat::IEEEhalf();
85   case LLVMTypeID::FloatTyID:
86     return llvm::APFloat::IEEEsingle();
87   case LLVMTypeID::DoubleTyID:
88     return llvm::APFloat::IEEEdouble();
89   case LLVMTypeID::X86_FP80TyID:
90     return llvm::APFloat::x87DoubleExtended();
91   case LLVMTypeID::FP128TyID:
92     return llvm::APFloat::IEEEquad();
93   case LLVMTypeID::PPC_FP128TyID:
94     return llvm::APFloat::PPCDoubleDouble();
95   default:
96     llvm_unreachable("Invalid floating type");
97   }
98 }
99 
100 static MatchResult parseCode(char &code, const char *&ptr) {
101   if (*ptr != 'a' && *ptr != 'c' && *ptr != 'i' && *ptr != 'l' && *ptr != 'r')
102     return mlir::failure();
103   code = *ptr++;
104   return mlir::success();
105 }
106 
107 template <char ch>
108 static MatchResult parseSingleChar(const char *&ptr) {
109   if (*ptr != ch)
110     return mlir::failure();
111   ++ptr;
112   return mlir::success();
113 }
114 
115 static MatchResult parseColon(const char *&ptr) {
116   return parseSingleChar<':'>(ptr);
117 }
118 
119 static MatchResult parseComma(const char *&ptr) {
120   return parseSingleChar<','>(ptr);
121 }
122 
123 static MatchResult parseInt(unsigned &result, const char *&ptr) {
124   const char *beg = ptr;
125   while (*ptr >= '0' && *ptr <= '9')
126     ptr++;
127   if (beg == ptr)
128     return mlir::failure();
129   llvm::StringRef ref(beg, ptr - beg);
130   int temp;
131   if (ref.consumeInteger(10, temp))
132     return mlir::failure();
133   result = temp;
134   return mlir::success();
135 }
136 
137 static mlir::LogicalResult matchString(const char *&ptr,
138                                        llvm::StringRef literal) {
139   llvm::StringRef s(ptr);
140   if (s.startswith(literal)) {
141     ptr += literal.size();
142     return mlir::success();
143   }
144   return mlir::failure();
145 }
146 
147 static MatchResult parseTypeID(LLVMTypeID &result, const char *&ptr) {
148   if (mlir::succeeded(matchString(ptr, "Half"))) {
149     result = LLVMTypeID::HalfTyID;
150     return mlir::success();
151   }
152   if (mlir::succeeded(matchString(ptr, "Float"))) {
153     result = LLVMTypeID::FloatTyID;
154     return mlir::success();
155   }
156   if (mlir::succeeded(matchString(ptr, "Double"))) {
157     result = LLVMTypeID::DoubleTyID;
158     return mlir::success();
159   }
160   if (mlir::succeeded(matchString(ptr, "X86_FP80"))) {
161     result = LLVMTypeID::X86_FP80TyID;
162     return mlir::success();
163   }
164   if (mlir::succeeded(matchString(ptr, "FP128"))) {
165     result = LLVMTypeID::FP128TyID;
166     return mlir::success();
167   }
168   if (mlir::succeeded(matchString(ptr, "PPC_FP128"))) {
169     result = LLVMTypeID::PPC_FP128TyID;
170     return mlir::success();
171   }
172   return mlir::failure();
173 }
174 
175 fir::KindMapping::KindMapping(mlir::MLIRContext *context, llvm::StringRef map)
176     : context{context} {
177   if (mlir::failed(parse(map))) {
178     intMap.clear();
179     floatMap.clear();
180   }
181 }
182 
183 fir::KindMapping::KindMapping(mlir::MLIRContext *context)
184     : KindMapping{context, clKindMapping} {}
185 
186 MatchResult fir::KindMapping::badMapString(const llvm::Twine &ptr) {
187   auto unknown = mlir::UnknownLoc::get(context);
188   mlir::emitError(unknown, ptr);
189   return mlir::failure();
190 }
191 
192 MatchResult fir::KindMapping::parse(llvm::StringRef kindMap) {
193   if (kindMap.empty())
194     return mlir::success();
195   const char *srcPtr = kindMap.begin();
196   while (true) {
197     char code = '\0';
198     KindTy kind = 0;
199     if (parseCode(code, srcPtr) || parseInt(kind, srcPtr))
200       return badMapString(srcPtr);
201     if (code == 'a' || code == 'i' || code == 'l') {
202       Bitsize bits = 0;
203       if (parseColon(srcPtr) || parseInt(bits, srcPtr))
204         return badMapString(srcPtr);
205       intMap[std::pair<char, KindTy>{code, kind}] = bits;
206     } else if (code == 'r' || code == 'c') {
207       LLVMTypeID id{};
208       if (parseColon(srcPtr) || parseTypeID(id, srcPtr))
209         return badMapString(srcPtr);
210       floatMap[std::pair<char, KindTy>{code, kind}] = id;
211     } else {
212       return badMapString(srcPtr);
213     }
214     if (parseComma(srcPtr))
215       break;
216   }
217   if (*srcPtr)
218     return badMapString(srcPtr);
219   return mlir::success();
220 }
221 
222 Bitsize fir::KindMapping::getCharacterBitsize(KindTy kind) {
223   return getIntegerLikeBitsize<'a'>(kind, intMap);
224 }
225 
226 Bitsize fir::KindMapping::getIntegerBitsize(KindTy kind) {
227   return getIntegerLikeBitsize<'i'>(kind, intMap);
228 }
229 
230 Bitsize fir::KindMapping::getLogicalBitsize(KindTy kind) {
231   return getIntegerLikeBitsize<'l'>(kind, intMap);
232 }
233 
234 LLVMTypeID fir::KindMapping::getRealTypeID(KindTy kind) {
235   return getFloatLikeTypeID<'r'>(kind, floatMap);
236 }
237 
238 LLVMTypeID fir::KindMapping::getComplexTypeID(KindTy kind) {
239   return getFloatLikeTypeID<'c'>(kind, floatMap);
240 }
241 
242 const llvm::fltSemantics &fir::KindMapping::getFloatSemantics(KindTy kind) {
243   return getFloatSemanticsOfKind<'r'>(kind, floatMap);
244 }
245