409 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "mlir/Target/LLVMIR/DataLayoutImporter.h"10#include "mlir/Dialect/DLTI/DLTI.h"11#include "mlir/IR/Builders.h"12#include "mlir/IR/BuiltinAttributes.h"13#include "mlir/IR/BuiltinTypes.h"14#include "mlir/Interfaces/DataLayoutInterfaces.h"15#include "mlir/Target/LLVMIR/Import.h"16 17#include "llvm/IR/DataLayout.h"18 19using namespace mlir;20using namespace mlir::LLVM;21using namespace mlir::LLVM::detail;22 23/// The default data layout used during the translation.24static 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 28FloatType 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 46FailureOr<StringRef>47DataLayoutImporter::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 59FailureOr<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 66template <class T>67static FailureOr<SmallVector<T>> tryToParseIntListImpl(StringRef token) {68 SmallVector<StringRef> tokens;69 token.consume_front(":");70 token.split(tokens, ':');71 72 // Parse an integer list.73 SmallVector<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 80FailureOr<SmallVector<uint64_t>>81DataLayoutImporter::tryToParseIntList(StringRef token) const {82 return tryToParseIntListImpl<uint64_t>(token);83}84 85FailureOr<DenseIntElementsAttr>86DataLayoutImporter::tryToParseAlignment(StringRef token) const {87 FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token);88 if (failed(alignment))89 return failure();90 if (alignment->empty() || alignment->size() > 2)91 return failure();92 93 // Alignment specifications (such as 32 or 32:64) are of the94 // form <abi>[:<pref>], where abi specifies the minimal alignment and pref the95 // optional preferred alignment. The preferred alignment is set to the minimal96 // alignment if not available.97 uint64_t minimal = (*alignment)[0];98 uint64_t preferred = alignment->size() == 1 ? minimal : (*alignment)[1];99 return DenseIntElementsAttr::get(100 VectorType::get({2}, IntegerType::get(context, 64)),101 {minimal, preferred});102}103 104FailureOr<DenseIntElementsAttr>105DataLayoutImporter::tryToParsePointerAlignment(StringRef token) const {106 FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token);107 if (failed(alignment))108 return failure();109 if (alignment->size() < 2 || alignment->size() > 4)110 return failure();111 112 // Pointer alignment specifications (such as 64:32:64:32 or 32:32) are of113 // the form <size>:<abi>[:<pref>][:<idx>], where size is the pointer size, abi114 // specifies the minimal alignment, pref the optional preferred alignment, and115 // idx the optional index computation bit width. The preferred alignment is116 // set to the minimal alignment if not available and the index computation117 // width is set to the pointer size if not available.118 uint64_t size = (*alignment)[0];119 uint64_t minimal = (*alignment)[1];120 uint64_t preferred = alignment->size() < 3 ? minimal : (*alignment)[2];121 uint64_t idx = alignment->size() < 4 ? size : (*alignment)[3];122 return DenseIntElementsAttr::get<uint64_t>(123 VectorType::get({4}, IntegerType::get(context, 64)),124 {size, minimal, preferred, idx});125}126 127LogicalResult DataLayoutImporter::tryToEmplaceAlignmentEntry(Type type,128 StringRef token) {129 auto key = TypeAttr::get(type);130 if (typeEntries.count(key))131 return success();132 133 FailureOr<DenseIntElementsAttr> params = tryToParseAlignment(token);134 if (failed(params))135 return failure();136 137 typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params));138 return success();139}140 141LogicalResult142DataLayoutImporter::tryToEmplacePointerAlignmentEntry(LLVMPointerType type,143 StringRef token) {144 auto key = TypeAttr::get(type);145 if (typeEntries.count(key))146 return success();147 148 FailureOr<DenseIntElementsAttr> params = tryToParsePointerAlignment(token);149 if (failed(params))150 return failure();151 152 typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params));153 return success();154}155 156LogicalResult157DataLayoutImporter::tryToEmplaceEndiannessEntry(StringRef endianness,158 StringRef token) {159 auto key = StringAttr::get(context, DLTIDialect::kDataLayoutEndiannessKey);160 if (keyEntries.count(key))161 return success();162 163 if (!token.empty())164 return failure();165 166 keyEntries.try_emplace(167 key, DataLayoutEntryAttr::get(key, StringAttr::get(context, endianness)));168 return success();169}170 171LogicalResult DataLayoutImporter::tryToEmplaceManglingModeEntry(172 StringRef token, llvm::StringLiteral manglingKey) {173 auto key = StringAttr::get(context, manglingKey);174 if (keyEntries.count(key))175 return success();176 177 token.consume_front(":");178 if (token.empty())179 return failure();180 181 keyEntries.try_emplace(182 key, DataLayoutEntryAttr::get(key, StringAttr::get(context, token)));183 return success();184}185 186LogicalResult187DataLayoutImporter::tryToEmplaceAddrSpaceEntry(StringRef token,188 llvm::StringLiteral spaceKey) {189 auto key = StringAttr::get(context, spaceKey);190 if (keyEntries.count(key))191 return success();192 193 FailureOr<uint64_t> space = tryToParseInt(token);194 if (failed(space))195 return failure();196 197 // Only store the address space if it has a non-default value.198 if (*space == 0)199 return success();200 OpBuilder builder(context);201 keyEntries.try_emplace(202 key,203 DataLayoutEntryAttr::get(204 key, builder.getIntegerAttr(205 builder.getIntegerType(64, /*isSigned=*/false), *space)));206 return success();207}208 209LogicalResult210DataLayoutImporter::tryToEmplaceStackAlignmentEntry(StringRef token) {211 auto key =212 StringAttr::get(context, DLTIDialect::kDataLayoutStackAlignmentKey);213 if (keyEntries.count(key))214 return success();215 216 FailureOr<uint64_t> alignment = tryToParseInt(token);217 if (failed(alignment))218 return failure();219 220 // Stack alignment shouldn't be zero.221 if (*alignment == 0)222 return failure();223 OpBuilder builder(context);224 keyEntries.try_emplace(key, DataLayoutEntryAttr::get(225 key, builder.getI64IntegerAttr(*alignment)));226 return success();227}228 229LogicalResult DataLayoutImporter::tryToEmplaceFunctionPointerAlignmentEntry(230 StringRef fnPtrString, StringRef token) {231 auto key = StringAttr::get(232 context, DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);233 if (keyEntries.count(key))234 return success();235 236 // The data layout entry for "F<type><abi>". <abi> is the aligment value,237 // preceded by one of the two possible <types>:238 // "i": The alignment of function pointers is independent of the alignment of239 // functions, and is a multiple of <abi>.240 // "n": The alignment of function pointers is a multiple of the explicit241 // alignment specified on the function, and is a multiple of <abi>.242 bool functionDependent = false;243 if (fnPtrString == "n")244 functionDependent = true;245 else if (fnPtrString != "i")246 return failure();247 248 FailureOr<uint64_t> alignment = tryToParseInt(token);249 if (failed(alignment))250 return failure();251 252 keyEntries.try_emplace(253 key, DataLayoutEntryAttr::get(254 key, FunctionPointerAlignmentAttr::get(255 key.getContext(), *alignment, functionDependent)));256 return success();257}258 259LogicalResult260DataLayoutImporter::tryToEmplaceLegalIntWidthsEntry(StringRef token) {261 auto key =262 StringAttr::get(context, DLTIDialect::kDataLayoutLegalIntWidthsKey);263 if (keyEntries.count(key))264 return success();265 266 FailureOr<SmallVector<int32_t>> intWidths =267 tryToParseIntListImpl<int32_t>(token);268 if (failed(intWidths) || intWidths->empty())269 return failure();270 271 OpBuilder builder(context);272 keyEntries.try_emplace(273 key,274 DataLayoutEntryAttr::get(key, builder.getDenseI32ArrayAttr(*intWidths)));275 return success();276}277 278DataLayoutSpecInterface DataLayoutImporter::dataLayoutSpecFromDataLayoutStr() {279 if (!dataLayoutStr.empty())280 dataLayoutStr += "-";281 dataLayoutStr += kDefaultDataLayout;282 283 // Split the data layout string into tokens separated by a dash.284 SmallVector<StringRef> tokens;285 StringRef(dataLayoutStr).split(tokens, '-');286 287 for (StringRef token : tokens) {288 lastToken = token;289 FailureOr<StringRef> prefix = tryToParseAlphaPrefix(token);290 if (failed(prefix))291 return {};292 293 // Parse the endianness.294 if (*prefix == "e") {295 if (failed(tryToEmplaceEndiannessEntry(296 DLTIDialect::kDataLayoutEndiannessLittle, token)))297 return {};298 continue;299 }300 if (*prefix == "E") {301 if (failed(tryToEmplaceEndiannessEntry(302 DLTIDialect::kDataLayoutEndiannessBig, token)))303 return {};304 continue;305 }306 // Parse the program address space.307 if (*prefix == "P") {308 if (failed(tryToEmplaceAddrSpaceEntry(309 token, DLTIDialect::kDataLayoutProgramMemorySpaceKey)))310 return {};311 continue;312 }313 // Parse the mangling mode.314 if (*prefix == "m") {315 if (failed(tryToEmplaceManglingModeEntry(316 token, DLTIDialect::kDataLayoutManglingModeKey)))317 return {};318 continue;319 }320 // Parse the global address space.321 if (*prefix == "G") {322 if (failed(tryToEmplaceAddrSpaceEntry(323 token, DLTIDialect::kDataLayoutGlobalMemorySpaceKey)))324 return {};325 continue;326 }327 // Parse the alloca address space.328 if (*prefix == "A") {329 if (failed(tryToEmplaceAddrSpaceEntry(330 token, DLTIDialect::kDataLayoutAllocaMemorySpaceKey)))331 return {};332 continue;333 }334 // Parse the stack alignment.335 if (*prefix == "S") {336 if (failed(tryToEmplaceStackAlignmentEntry(token)))337 return {};338 continue;339 }340 // Parse integer alignment specifications.341 if (*prefix == "i") {342 FailureOr<uint64_t> width = tryToParseInt(token);343 if (failed(width))344 return {};345 346 Type type = IntegerType::get(context, *width);347 if (failed(tryToEmplaceAlignmentEntry(type, token)))348 return {};349 continue;350 }351 // Parse float alignment specifications.352 if (*prefix == "f") {353 FailureOr<uint64_t> width = tryToParseInt(token);354 if (failed(width))355 return {};356 357 Type type = getFloatType(context, *width);358 if (failed(tryToEmplaceAlignmentEntry(type, token)))359 return {};360 continue;361 }362 // Parse pointer alignment specifications.363 if (*prefix == "p") {364 FailureOr<uint64_t> space =365 token.starts_with(":") ? 0 : tryToParseInt(token);366 if (failed(space))367 return {};368 369 auto type = LLVMPointerType::get(context, *space);370 if (failed(tryToEmplacePointerAlignmentEntry(type, token)))371 return {};372 continue;373 }374 // Parse native integer widths specifications.375 if (*prefix == "n") {376 if (failed(tryToEmplaceLegalIntWidthsEntry(token)))377 return {};378 continue;379 }380 // Parse function pointer alignment specifications.381 // Note that prefix here is "Fn" or "Fi", not a single character.382 if (prefix->starts_with("F")) {383 StringRef nextPrefix = prefix->drop_front(1);384 if (failed(tryToEmplaceFunctionPointerAlignmentEntry(nextPrefix, token)))385 return {};386 continue;387 }388 389 // Store all tokens that have not been handled.390 unhandledTokens.push_back(lastToken);391 }392 393 // Assemble all entries to a data layout specification.394 SmallVector<DataLayoutEntryInterface> entries;395 entries.reserve(typeEntries.size() + keyEntries.size());396 for (const auto &it : typeEntries)397 entries.push_back(it.second);398 for (const auto &it : keyEntries)399 entries.push_back(it.second);400 return DataLayoutSpecAttr::get(context, entries);401}402 403DataLayoutSpecInterface404mlir::translateDataLayout(const llvm::DataLayout &dataLayout,405 MLIRContext *context) {406 return DataLayoutImporter(context, dataLayout.getStringRepresentation())407 .getDataLayoutSpec();408}409