1 //===- DataLayoutImporter.cpp - LLVM to MLIR data layout conversion -------===// 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 "DataLayoutImporter.h" 10 #include "mlir/Dialect/DLTI/DLTI.h" 11 #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 12 #include "mlir/IR/Builders.h" 13 #include "mlir/IR/BuiltinAttributes.h" 14 #include "mlir/IR/BuiltinTypes.h" 15 #include "mlir/Interfaces/DataLayoutInterfaces.h" 16 #include "mlir/Target/LLVMIR/Import.h" 17 #include "llvm/IR/DataLayout.h" 18 19 using namespace mlir; 20 using namespace mlir::LLVM; 21 using namespace mlir::LLVM::detail; 22 23 /// The default data layout used during the translation. 24 static constexpr StringRef kDefaultDataLayout = 25 "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-" 26 "f16:16:16-f64:64:64-f128:128:128"; 27 28 FloatType mlir::LLVM::detail::getFloatType(MLIRContext *context, 29 unsigned width) { 30 switch (width) { 31 case 16: 32 return Float16Type::get(context); 33 case 32: 34 return Float32Type::get(context); 35 case 64: 36 return Float64Type::get(context); 37 case 80: 38 return Float80Type::get(context); 39 case 128: 40 return Float128Type::get(context); 41 default: 42 return {}; 43 } 44 } 45 46 FailureOr<StringRef> 47 DataLayoutImporter::tryToParseAlphaPrefix(StringRef &token) const { 48 if (token.empty()) 49 return failure(); 50 51 StringRef prefix = token.take_while(isalpha); 52 if (prefix.empty()) 53 return failure(); 54 55 token.consume_front(prefix); 56 return prefix; 57 } 58 59 FailureOr<uint64_t> DataLayoutImporter::tryToParseInt(StringRef &token) const { 60 uint64_t parameter; 61 if (token.consumeInteger(/*Radix=*/10, parameter)) 62 return failure(); 63 return parameter; 64 } 65 66 FailureOr<SmallVector<uint64_t>> 67 DataLayoutImporter::tryToParseIntList(StringRef token) const { 68 SmallVector<StringRef> tokens; 69 token.consume_front(":"); 70 token.split(tokens, ':'); 71 72 // Parse an integer list. 73 SmallVector<uint64_t> results(tokens.size()); 74 for (auto [result, token] : llvm::zip(results, tokens)) 75 if (token.getAsInteger(/*Radix=*/10, result)) 76 return failure(); 77 return results; 78 } 79 80 FailureOr<DenseIntElementsAttr> 81 DataLayoutImporter::tryToParseAlignment(StringRef token) const { 82 FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token); 83 if (failed(alignment)) 84 return failure(); 85 if (alignment->empty() || alignment->size() > 2) 86 return failure(); 87 88 // Alignment specifications (such as 32 or 32:64) are of the 89 // form <abi>[:<pref>], where abi specifies the minimal alignment and pref the 90 // optional preferred alignment. The preferred alignment is set to the minimal 91 // alignment if not available. 92 uint64_t minimal = (*alignment)[0]; 93 uint64_t preferred = alignment->size() == 1 ? minimal : (*alignment)[1]; 94 return DenseIntElementsAttr::get( 95 VectorType::get({2}, IntegerType::get(context, 64)), 96 {minimal, preferred}); 97 } 98 99 FailureOr<DenseIntElementsAttr> 100 DataLayoutImporter::tryToParsePointerAlignment(StringRef token) const { 101 FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token); 102 if (failed(alignment)) 103 return failure(); 104 if (alignment->size() < 2 || alignment->size() > 4) 105 return failure(); 106 107 // Pointer alignment specifications (such as 64:32:64:32 or 32:32) are of 108 // the form <size>:<abi>[:<pref>][:<idx>], where size is the pointer size, abi 109 // specifies the minimal alignment, pref the optional preferred alignment, and 110 // idx the optional index computation bit width. The preferred alignment is 111 // set to the minimal alignment if not available and the index computation 112 // width is set to the pointer size if not available. 113 uint64_t size = (*alignment)[0]; 114 uint64_t minimal = (*alignment)[1]; 115 uint64_t preferred = alignment->size() < 3 ? minimal : (*alignment)[2]; 116 uint64_t idx = alignment->size() < 4 ? size : (*alignment)[3]; 117 return DenseIntElementsAttr::get<uint64_t>( 118 VectorType::get({4}, IntegerType::get(context, 64)), 119 {size, minimal, preferred, idx}); 120 } 121 122 LogicalResult DataLayoutImporter::tryToEmplaceAlignmentEntry(Type type, 123 StringRef token) { 124 auto key = TypeAttr::get(type); 125 if (typeEntries.count(key)) 126 return success(); 127 128 FailureOr<DenseIntElementsAttr> params = tryToParseAlignment(token); 129 if (failed(params)) 130 return failure(); 131 132 typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params)); 133 return success(); 134 } 135 136 LogicalResult 137 DataLayoutImporter::tryToEmplacePointerAlignmentEntry(LLVMPointerType type, 138 StringRef token) { 139 auto key = TypeAttr::get(type); 140 if (typeEntries.count(key)) 141 return success(); 142 143 FailureOr<DenseIntElementsAttr> params = tryToParsePointerAlignment(token); 144 if (failed(params)) 145 return failure(); 146 147 typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params)); 148 return success(); 149 } 150 151 LogicalResult 152 DataLayoutImporter::tryToEmplaceEndiannessEntry(StringRef endianness, 153 StringRef token) { 154 auto key = StringAttr::get(context, DLTIDialect::kDataLayoutEndiannessKey); 155 if (keyEntries.count(key)) 156 return success(); 157 158 if (!token.empty()) 159 return failure(); 160 161 keyEntries.try_emplace( 162 key, DataLayoutEntryAttr::get(key, StringAttr::get(context, endianness))); 163 return success(); 164 } 165 166 LogicalResult 167 DataLayoutImporter::tryToEmplaceAddrSpaceEntry(StringRef token, 168 llvm::StringLiteral spaceKey) { 169 auto key = StringAttr::get(context, spaceKey); 170 if (keyEntries.count(key)) 171 return success(); 172 173 FailureOr<uint64_t> space = tryToParseInt(token); 174 if (failed(space)) 175 return failure(); 176 177 // Only store the address space if it has a non-default value. 178 if (*space == 0) 179 return success(); 180 OpBuilder builder(context); 181 keyEntries.try_emplace( 182 key, 183 DataLayoutEntryAttr::get( 184 key, builder.getIntegerAttr( 185 builder.getIntegerType(64, /*isSigned=*/false), *space))); 186 return success(); 187 } 188 189 LogicalResult 190 DataLayoutImporter::tryToEmplaceStackAlignmentEntry(StringRef token) { 191 auto key = 192 StringAttr::get(context, DLTIDialect::kDataLayoutStackAlignmentKey); 193 if (keyEntries.count(key)) 194 return success(); 195 196 FailureOr<uint64_t> alignment = tryToParseInt(token); 197 if (failed(alignment)) 198 return failure(); 199 200 // Stack alignment shouldn't be zero. 201 if (*alignment == 0) 202 return failure(); 203 OpBuilder builder(context); 204 keyEntries.try_emplace(key, DataLayoutEntryAttr::get( 205 key, builder.getI64IntegerAttr(*alignment))); 206 return success(); 207 } 208 209 void DataLayoutImporter::translateDataLayout( 210 const llvm::DataLayout &llvmDataLayout) { 211 dataLayout = {}; 212 213 // Transform the data layout to its string representation and append the 214 // default data layout string specified in the language reference 215 // (https://llvm.org/docs/LangRef.html#data-layout). The translation then 216 // parses the string and ignores the default value if a specific kind occurs 217 // in both strings. Additionally, the following default values exist: 218 // - non-default address space pointer specifications default to the default 219 // address space pointer specification 220 // - the alloca address space defaults to the default address space. 221 layoutStr = llvmDataLayout.getStringRepresentation(); 222 if (!layoutStr.empty()) 223 layoutStr += "-"; 224 layoutStr += kDefaultDataLayout; 225 StringRef layout(layoutStr); 226 227 // Split the data layout string into tokens separated by a dash. 228 SmallVector<StringRef> tokens; 229 layout.split(tokens, '-'); 230 231 for (StringRef token : tokens) { 232 lastToken = token; 233 FailureOr<StringRef> prefix = tryToParseAlphaPrefix(token); 234 if (failed(prefix)) 235 return; 236 237 // Parse the endianness. 238 if (*prefix == "e") { 239 if (failed(tryToEmplaceEndiannessEntry( 240 DLTIDialect::kDataLayoutEndiannessLittle, token))) 241 return; 242 continue; 243 } 244 if (*prefix == "E") { 245 if (failed(tryToEmplaceEndiannessEntry( 246 DLTIDialect::kDataLayoutEndiannessBig, token))) 247 return; 248 continue; 249 } 250 // Parse the program address space. 251 if (*prefix == "P") { 252 if (failed(tryToEmplaceAddrSpaceEntry( 253 token, DLTIDialect::kDataLayoutProgramMemorySpaceKey))) 254 return; 255 continue; 256 } 257 // Parse the global address space. 258 if (*prefix == "G") { 259 if (failed(tryToEmplaceAddrSpaceEntry( 260 token, DLTIDialect::kDataLayoutGlobalMemorySpaceKey))) 261 return; 262 continue; 263 } 264 // Parse the alloca address space. 265 if (*prefix == "A") { 266 if (failed(tryToEmplaceAddrSpaceEntry( 267 token, DLTIDialect::kDataLayoutAllocaMemorySpaceKey))) 268 return; 269 continue; 270 } 271 // Parse the stack alignment. 272 if (*prefix == "S") { 273 if (failed(tryToEmplaceStackAlignmentEntry(token))) 274 return; 275 continue; 276 } 277 // Parse integer alignment specifications. 278 if (*prefix == "i") { 279 FailureOr<uint64_t> width = tryToParseInt(token); 280 if (failed(width)) 281 return; 282 283 Type type = IntegerType::get(context, *width); 284 if (failed(tryToEmplaceAlignmentEntry(type, token))) 285 return; 286 continue; 287 } 288 // Parse float alignment specifications. 289 if (*prefix == "f") { 290 FailureOr<uint64_t> width = tryToParseInt(token); 291 if (failed(width)) 292 return; 293 294 Type type = getFloatType(context, *width); 295 if (failed(tryToEmplaceAlignmentEntry(type, token))) 296 return; 297 continue; 298 } 299 // Parse pointer alignment specifications. 300 if (*prefix == "p") { 301 FailureOr<uint64_t> space = 302 token.starts_with(":") ? 0 : tryToParseInt(token); 303 if (failed(space)) 304 return; 305 306 auto type = LLVMPointerType::get(context, *space); 307 if (failed(tryToEmplacePointerAlignmentEntry(type, token))) 308 return; 309 continue; 310 } 311 312 // Store all tokens that have not been handled. 313 unhandledTokens.push_back(lastToken); 314 } 315 316 // Assemble all entries to a data layout specification. 317 SmallVector<DataLayoutEntryInterface> entries; 318 entries.reserve(typeEntries.size() + keyEntries.size()); 319 for (const auto &it : typeEntries) 320 entries.push_back(it.second); 321 for (const auto &it : keyEntries) 322 entries.push_back(it.second); 323 dataLayout = DataLayoutSpecAttr::get(context, entries); 324 } 325 326 DataLayoutSpecInterface 327 mlir::translateDataLayout(const llvm::DataLayout &dataLayout, 328 MLIRContext *context) { 329 return DataLayoutImporter(context, dataLayout).getDataLayout(); 330 } 331