• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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