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