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