|
27 | 27 | #include "mlir/IR/Attributes.h"
|
28 | 28 | #include "mlir/IR/BuiltinOps.h"
|
29 | 29 | #include "mlir/IR/BuiltinTypes.h"
|
| 30 | +#include "mlir/IR/DialectResourceBlobManager.h" |
30 | 31 | #include "mlir/IR/RegionGraphTraits.h"
|
31 | 32 | #include "mlir/Support/LLVM.h"
|
32 | 33 | #include "mlir/Support/LogicalResult.h"
|
@@ -446,6 +447,99 @@ convertDenseElementsAttr(Location loc, DenseElementsAttr denseElementsAttr,
|
446 | 447 | return buildSequentialConstant(constantsRef, outerShape, llvmType, loc);
|
447 | 448 | }
|
448 | 449 |
|
| 450 | +/// Convert a dense resource elements attribute to an LLVM IR constant using its |
| 451 | +/// raw data storage if possible. This supports elements attributes of tensor or |
| 452 | +/// vector type and avoids constructing separate objects for individual values |
| 453 | +/// of the innermost dimension. Constants for other dimensions are still |
| 454 | +/// constructed recursively. Returns nullptr on failure and emits errors at |
| 455 | +/// `loc`. |
| 456 | +static llvm::Constant *convertDenseResourceElementsAttr( |
| 457 | + Location loc, DenseResourceElementsAttr denseResourceAttr, |
| 458 | + llvm::Type *llvmType, const ModuleTranslation &moduleTranslation) { |
| 459 | + assert(denseResourceAttr && "expected non-null attribute"); |
| 460 | + |
| 461 | + llvm::Type *innermostLLVMType = getInnermostElementType(llvmType); |
| 462 | + if (!llvm::ConstantDataSequential::isElementTypeCompatible( |
| 463 | + innermostLLVMType)) { |
| 464 | + emitError(loc, "no known conversion for innermost element type"); |
| 465 | + return nullptr; |
| 466 | + } |
| 467 | + |
| 468 | + ShapedType type = denseResourceAttr.getType(); |
| 469 | + assert(type.getNumElements() > 0 && "Expected non-empty elements attribute"); |
| 470 | + |
| 471 | + AsmResourceBlob *blob = denseResourceAttr.getRawHandle().getBlob(); |
| 472 | + if (!blob) { |
| 473 | + emitError(loc, "resource does not exist"); |
| 474 | + return nullptr; |
| 475 | + } |
| 476 | + |
| 477 | + ArrayRef<char> rawData = blob->getData(); |
| 478 | + |
| 479 | + // Check that the raw data size matches what is expected for the scalar size. |
| 480 | + // TODO: in theory, we could repack the data here to keep constructing from |
| 481 | + // raw data. |
| 482 | + // TODO: we may also need to consider endianness when cross-compiling to an |
| 483 | + // architecture where it is different. |
| 484 | + int64_t numElements = denseResourceAttr.getType().getNumElements(); |
| 485 | + int64_t elementByteSize = rawData.size() / numElements; |
| 486 | + if (8 * elementByteSize != innermostLLVMType->getScalarSizeInBits()) { |
| 487 | + emitError(loc, "raw data size does not match element type size"); |
| 488 | + return nullptr; |
| 489 | + } |
| 490 | + |
| 491 | + // Compute the shape of all dimensions but the innermost. Note that the |
| 492 | + // innermost dimension may be that of the vector element type. |
| 493 | + bool hasVectorElementType = isa<VectorType>(type.getElementType()); |
| 494 | + int64_t numAggregates = |
| 495 | + numElements / (hasVectorElementType |
| 496 | + ? 1 |
| 497 | + : denseResourceAttr.getType().getShape().back()); |
| 498 | + ArrayRef<int64_t> outerShape = type.getShape(); |
| 499 | + if (!hasVectorElementType) |
| 500 | + outerShape = outerShape.drop_back(); |
| 501 | + |
| 502 | + // Create a constructor for the innermost constant from a piece of raw data. |
| 503 | + std::function<llvm::Constant *(StringRef)> buildCstData; |
| 504 | + if (isa<TensorType>(type)) { |
| 505 | + auto vectorElementType = dyn_cast<VectorType>(type.getElementType()); |
| 506 | + if (vectorElementType && vectorElementType.getRank() == 1) { |
| 507 | + buildCstData = [&](StringRef data) { |
| 508 | + return llvm::ConstantDataVector::getRaw( |
| 509 | + data, vectorElementType.getShape().back(), innermostLLVMType); |
| 510 | + }; |
| 511 | + } else if (!vectorElementType) { |
| 512 | + buildCstData = [&](StringRef data) { |
| 513 | + return llvm::ConstantDataArray::getRaw(data, type.getShape().back(), |
| 514 | + innermostLLVMType); |
| 515 | + }; |
| 516 | + } |
| 517 | + } else if (isa<VectorType>(type)) { |
| 518 | + buildCstData = [&](StringRef data) { |
| 519 | + return llvm::ConstantDataVector::getRaw(data, type.getShape().back(), |
| 520 | + innermostLLVMType); |
| 521 | + }; |
| 522 | + } |
| 523 | + if (!buildCstData) { |
| 524 | + emitError(loc, "unsupported dense_resource type"); |
| 525 | + return nullptr; |
| 526 | + } |
| 527 | + |
| 528 | + // Create innermost constants and defer to the default constant creation |
| 529 | + // mechanism for other dimensions. |
| 530 | + SmallVector<llvm::Constant *> constants; |
| 531 | + int64_t aggregateSize = denseResourceAttr.getType().getShape().back() * |
| 532 | + (innermostLLVMType->getScalarSizeInBits() / 8); |
| 533 | + constants.reserve(numAggregates); |
| 534 | + for (unsigned i = 0; i < numAggregates; ++i) { |
| 535 | + StringRef data(rawData.data() + i * aggregateSize, aggregateSize); |
| 536 | + constants.push_back(buildCstData(data)); |
| 537 | + } |
| 538 | + |
| 539 | + ArrayRef<llvm::Constant *> constantsRef = constants; |
| 540 | + return buildSequentialConstant(constantsRef, outerShape, llvmType, loc); |
| 541 | +} |
| 542 | + |
449 | 543 | /// Create an LLVM IR constant of `llvmType` from the MLIR attribute `attr`.
|
450 | 544 | /// This currently supports integer, floating point, splat and dense element
|
451 | 545 | /// attributes and combinations thereof. Also, an array attribute with two
|
@@ -546,6 +640,11 @@ llvm::Constant *mlir::LLVM::detail::getLLVMConstant(
|
546 | 640 | return result;
|
547 | 641 | }
|
548 | 642 |
|
| 643 | + if (auto denseResourceAttr = dyn_cast<DenseResourceElementsAttr>(attr)) { |
| 644 | + return convertDenseResourceElementsAttr(loc, denseResourceAttr, llvmType, |
| 645 | + moduleTranslation); |
| 646 | + } |
| 647 | + |
549 | 648 | // Fall back to element-by-element construction otherwise.
|
550 | 649 | if (auto elementsAttr = dyn_cast<ElementsAttr>(attr)) {
|
551 | 650 | assert(elementsAttr.getShapedType().hasStaticShape());
|
|
0 commit comments