blob: c43fc8be75c60f1a09aba41ea87a98742dbdbb89 [file]
// 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