| // Copyright 2022 The IREE Authors |
| // |
| // Licensed under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| #include "iree/compiler/Codegen/LLVMCPU/Passes.h" |
| #include "llvm/ADT/MapVector.h" |
| #include "mlir/Dialect/LLVMIR/LLVMDialect.h" |
| #include "mlir/Pass/Pass.h" |
| |
| namespace mlir::iree_compiler { |
| |
| #define GEN_PASS_DEF_LLVMCPUASSIGNIMPORTORDINALSPASS |
| #include "iree/compiler/Codegen/LLVMCPU/Passes.h.inc" |
| |
| namespace { |
| |
| struct LLVMCPUAssignImportOrdinalsPass |
| : public impl::LLVMCPUAssignImportOrdinalsPassBase< |
| LLVMCPUAssignImportOrdinalsPass> { |
| void runOnOperation() override { |
| auto variantOp = getOperation(); |
| |
| auto *context = variantOp.getContext(); |
| auto unitAttr = UnitAttr::get(context); |
| auto importKeyAttr = StringAttr::get(context, "hal.executable.import.key"); |
| auto importWeakAttr = |
| StringAttr::get(context, "hal.executable.import.weak"); |
| |
| // Scan the module for the used imports and sort by name. |
| // This allows us to assign ordinals deterministically regardless of what |
| // order the imports are declared which may not always be stable. |
| SetVector<StringAttr> uniqueKeys; |
| DenseMap<StringAttr, SmallVector<LLVM::GlobalOp>> ordinalGlobals; |
| auto moduleOp = variantOp.getInnerModule(); |
| for (auto globalOp : |
| llvm::make_early_inc_range(moduleOp.getOps<LLVM::GlobalOp>())) { |
| auto keyAttr = globalOp->getAttrOfType<StringAttr>(importKeyAttr); |
| if (!keyAttr) |
| continue; |
| uniqueKeys.insert(keyAttr); |
| ordinalGlobals[keyAttr].push_back(globalOp); |
| } |
| if (uniqueKeys.empty()) |
| return; |
| auto sortedKeys = uniqueKeys.takeVector(); |
| llvm::stable_sort(sortedKeys, [](auto lhs, auto rhs) { |
| return lhs.getValue() < rhs.getValue(); |
| }); |
| |
| // Build the attribute used during serialization to emit the import table. |
| SmallVector<Attribute> importAttrs; |
| for (auto keyAttr : sortedKeys) { |
| auto anyGlobalOp = ordinalGlobals[keyAttr].front(); |
| bool isWeak = anyGlobalOp->hasAttr(importWeakAttr); |
| auto isWeakAttr = BoolAttr::get(context, isWeak); |
| importAttrs.push_back(ArrayAttr::get(context, {keyAttr, isWeakAttr})); |
| } |
| variantOp->setAttr("hal.executable.imports", |
| ArrayAttr::get(context, importAttrs)); |
| |
| // Update placeholders to hold the concrete ordinal values. |
| // Eventually MLIR or LLVM will inline them. |
| for (auto [ordinal, keyAttr] : llvm::enumerate(sortedKeys)) { |
| for (auto globalOp : ordinalGlobals[keyAttr]) { |
| globalOp->removeAttr(importKeyAttr); |
| globalOp->removeAttr(importWeakAttr); |
| globalOp.setConstantAttr(unitAttr); |
| globalOp.setValueAttr(IntegerAttr::get( |
| IntegerType::get(globalOp.getContext(), 32), ordinal)); |
| } |
| } |
| } |
| }; |
| } // namespace |
| } // namespace mlir::iree_compiler |