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