blob: 86bcd580c1b449625f59f299733905d6fc57b328 [file] [log] [blame]
//===- LLVMImportInterface.h - Import from LLVM interface -------*- C++ -*-===//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//
//
// This header file defines dialect interfaces for the LLVM IR import.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_TARGET_LLVMIR_LLVMIMPORTINTERFACE_H
#define MLIR_TARGET_LLVMIR_LLVMIMPORTINTERFACE_H
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/DialectInterface.h"
#include "mlir/IR/Location.h"
#include "mlir/Support/LogicalResult.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Support/FormatVariadic.h"
namespace llvm {
class IRBuilderBase;
} // namespace llvm
namespace mlir {
namespace LLVM {
class ModuleImport;
} // namespace LLVM
/// Base class for dialect interfaces used to import LLVM IR. Dialects that can
/// be imported should provide an implementation of this interface for the
/// supported intrinsics. The interface may be implemented in a separate library
/// to avoid the "main" dialect library depending on LLVM IR. The interface can
/// be attached using the delayed registration mechanism available in
/// DialectRegistry.
class LLVMImportDialectInterface
: public DialectInterface::Base<LLVMImportDialectInterface> {
public:
LLVMImportDialectInterface(Dialect *dialect) : Base(dialect) {}
/// Hook for derived dialect interfaces to implement the import of
/// intrinsics into MLIR.
virtual LogicalResult
convertIntrinsic(OpBuilder &builder, llvm::CallInst *inst,
LLVM::ModuleImport &moduleImport) const {
return failure();
}
/// Hook for derived dialect interfaces to implement the import of
/// instructions into MLIR.
virtual LogicalResult
convertInstruction(OpBuilder &builder, llvm::Instruction *inst,
ArrayRef<llvm::Value *> llvmOperands,
LLVM::ModuleImport &moduleImport) const {
return failure();
}
/// Hook for derived dialect interfaces to implement the import of metadata
/// into MLIR. Attaches the converted metadata kind and node to the provided
/// operation.
virtual LogicalResult
setMetadataAttrs(OpBuilder &builder, unsigned kind, llvm::MDNode *node,
Operation *op, LLVM::ModuleImport &moduleImport) const {
return failure();
}
/// Hook for derived dialect interfaces to publish the supported intrinsics.
/// As every LLVM IR intrinsic has a unique integer identifier, the function
/// returns the list of supported intrinsic identifiers.
virtual ArrayRef<unsigned> getSupportedIntrinsics() const { return {}; }
/// Hook for derived dialect interfaces to publish the supported instructions.
/// As every LLVM IR instruction has a unique integer identifier, the function
/// returns the list of supported instruction identifiers. These identifiers
/// will then be used to match LLVM instructions to the appropriate import
/// interface and `convertInstruction` method. It is an error to have multiple
/// interfaces overriding the same instruction.
virtual ArrayRef<unsigned> getSupportedInstructions() const { return {}; }
/// Hook for derived dialect interfaces to publish the supported metadata
/// kinds. As every metadata kind has a unique integer identifier, the
/// function returns the list of supported metadata identifiers.
virtual ArrayRef<unsigned> getSupportedMetadata() const { return {}; }
};
/// Interface collection for the import of LLVM IR that dispatches to a concrete
/// dialect interface implementation. Queries the dialect interfaces to obtain a
/// list of the supported LLVM IR constructs and then builds a mapping for the
/// efficient dispatch.
class LLVMImportInterface
: public DialectInterfaceCollection<LLVMImportDialectInterface> {
public:
using Base::Base;
/// Queries all registered dialect interfaces for the supported LLVM IR
/// intrinsic and metadata kinds and builds the dispatch tables for the
/// conversion. Returns failure if multiple dialect interfaces translate the
/// same LLVM IR intrinsic.
LogicalResult initializeImport() {
for (const LLVMImportDialectInterface &iface : *this) {
// Verify the supported intrinsics have not been mapped before.
const auto *intrinsicIt =
llvm::find_if(iface.getSupportedIntrinsics(), [&](unsigned id) {
return intrinsicToDialect.count(id);
});
if (intrinsicIt != iface.getSupportedIntrinsics().end()) {
return emitError(
UnknownLoc::get(iface.getContext()),
llvm::formatv(
"expected unique conversion for intrinsic ({0}), but "
"got conflicting {1} and {2} conversions",
*intrinsicIt, iface.getDialect()->getNamespace(),
intrinsicToDialect.lookup(*intrinsicIt)->getNamespace()));
}
const auto *instructionIt =
llvm::find_if(iface.getSupportedInstructions(), [&](unsigned id) {
return instructionToDialect.count(id);
});
if (instructionIt != iface.getSupportedInstructions().end()) {
return emitError(
UnknownLoc::get(iface.getContext()),
llvm::formatv(
"expected unique conversion for instruction ({0}), but "
"got conflicting {1} and {2} conversions",
*intrinsicIt, iface.getDialect()->getNamespace(),
instructionToDialect.lookup(*intrinsicIt)
->getDialect()
->getNamespace()));
}
// Add a mapping for all supported intrinsic identifiers.
for (unsigned id : iface.getSupportedIntrinsics())
intrinsicToDialect[id] = iface.getDialect();
// Add a mapping for all supported instruction identifiers.
for (unsigned id : iface.getSupportedInstructions())
instructionToDialect[id] = &iface;
// Add a mapping for all supported metadata kinds.
for (unsigned kind : iface.getSupportedMetadata())
metadataToDialect[kind].push_back(iface.getDialect());
}
return success();
}
/// Converts the LLVM intrinsic to an MLIR operation if a conversion exists.
/// Returns failure otherwise.
LogicalResult convertIntrinsic(OpBuilder &builder, llvm::CallInst *inst,
LLVM::ModuleImport &moduleImport) const {
// Lookup the dialect interface for the given intrinsic.
Dialect *dialect = intrinsicToDialect.lookup(inst->getIntrinsicID());
if (!dialect)
return failure();
// Dispatch the conversion to the dialect interface.
const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
assert(iface && "expected to find a dialect interface");
return iface->convertIntrinsic(builder, inst, moduleImport);
}
/// Returns true if the given LLVM IR intrinsic is convertible to an MLIR
/// operation.
bool isConvertibleIntrinsic(llvm::Intrinsic::ID id) {
return intrinsicToDialect.count(id);
}
/// Converts the LLVM instruction to an MLIR operation if a conversion exists.
/// Returns failure otherwise.
LogicalResult convertInstruction(OpBuilder &builder, llvm::Instruction *inst,
ArrayRef<llvm::Value *> llvmOperands,
LLVM::ModuleImport &moduleImport) const {
// Lookup the dialect interface for the given instruction.
const LLVMImportDialectInterface *iface =
instructionToDialect.lookup(inst->getOpcode());
if (!iface)
return failure();
return iface->convertInstruction(builder, inst, llvmOperands, moduleImport);
}
/// Returns true if the given LLVM IR instruction is convertible to an MLIR
/// operation.
bool isConvertibleInstruction(unsigned id) {
return instructionToDialect.count(id);
}
/// Attaches the given LLVM metadata to the imported operation if a conversion
/// to one or more MLIR dialect attributes exists and succeeds. Returns
/// success if at least one of the conversions is successful and failure if
/// all of them fail.
LogicalResult setMetadataAttrs(OpBuilder &builder, unsigned kind,
llvm::MDNode *node, Operation *op,
LLVM::ModuleImport &moduleImport) const {
// Lookup the dialect interfaces for the given metadata.
auto it = metadataToDialect.find(kind);
if (it == metadataToDialect.end())
return failure();
// Dispatch the conversion to the dialect interfaces.
bool isSuccess = false;
for (Dialect *dialect : it->getSecond()) {
const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
assert(iface && "expected to find a dialect interface");
if (succeeded(
iface->setMetadataAttrs(builder, kind, node, op, moduleImport)))
isSuccess = true;
}
// Returns failure if all conversions fail.
return success(isSuccess);
}
/// Returns true if the given LLVM IR metadata is convertible to an MLIR
/// attribute.
bool isConvertibleMetadata(unsigned kind) {
return metadataToDialect.count(kind);
}
private:
DenseMap<unsigned, Dialect *> intrinsicToDialect;
DenseMap<unsigned, const LLVMImportDialectInterface *> instructionToDialect;
DenseMap<unsigned, SmallVector<Dialect *, 1>> metadataToDialect;
};
} // namespace mlir
#endif // MLIR_TARGET_LLVMIR_LLVMIMPORTINTERFACE_H