--- /dev/null
+diff --git a/mlir/examples/standalone/standalone-translate/standalone-translate.cpp b/mlir/examples/standalone/standalone-translate/standalone-translate.cpp
+index 2c2f275..31ddef4 100644
+--- a/mlir/examples/standalone/standalone-translate/standalone-translate.cpp
++++ b/mlir/examples/standalone/standalone-translate/standalone-translate.cpp
+@@ -1,27 +1,34 @@
+ //===- standalone-translate.cpp ---------------------------------*- C++ -*-===//
+ //
+ // This file is 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
+ //
+ //===----------------------------------------------------------------------===//
+ //
+ // This is a command line utility that translates a file from/to MLIR using one
+ // of the registered translations.
+ //
+ //===----------------------------------------------------------------------===//
+
++#include "Standalone/StandaloneDialect.h"
++#include "mlir/IR/BuiltinOps.h"
+ #include "mlir/InitAllTranslations.h"
+ #include "mlir/Support/LogicalResult.h"
+ #include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
+-
+-#include "Standalone/StandaloneDialect.h"
++#include "mlir/Tools/mlir-translate/Translation.h"
+
+ int main(int argc, char **argv) {
+ mlir::registerAllTranslations();
+
+ // TODO: Register standalone translations here.
++ mlir::TranslateFromMLIRRegistration withdescription(
++ "option", "different from option",
++ [](mlir::ModuleOp op, llvm::raw_ostream &output) {
++ return mlir::LogicalResult::success();
++ },
++ [](mlir::DialectRegistry &a) {});
+
+ return failed(
+ mlir::mlirTranslateMain(argc, argv, "MLIR Translation Testing Tool"));
+ }
+diff --git a/mlir/include/mlir/Tools/mlir-translate/Translation.h b/mlir/include/mlir/Tools/mlir-translate/Translation.h
+index d91e479..c8b5b70 100644
+--- a/mlir/include/mlir/Tools/mlir-translate/Translation.h
++++ b/mlir/include/mlir/Tools/mlir-translate/Translation.h
+@@ -1,102 +1,103 @@
+ //===- Translation.h - Translation registry ---------------------*- 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
+ //
+ //===----------------------------------------------------------------------===//
+ //
+ // Registry for user-provided translations.
+ //
+ //===----------------------------------------------------------------------===//
+
+ #ifndef MLIR_TOOLS_MLIRTRANSLATE_TRANSLATION_H
+ #define MLIR_TOOLS_MLIRTRANSLATE_TRANSLATION_H
+
+ #include "llvm/Support/CommandLine.h"
+
+ namespace llvm {
+ class MemoryBuffer;
+ class SourceMgr;
+ class StringRef;
+ } // namespace llvm
+
+ namespace mlir {
+ class DialectRegistry;
+ struct LogicalResult;
+ class MLIRContext;
+ class ModuleOp;
+ template <typename OpTy>
+ class OwningOpRef;
+
+ /// Interface of the function that translates the sources managed by `sourceMgr`
+ /// to MLIR. The source manager has at least one buffer. The implementation
+ /// should create a new MLIR ModuleOp in the given context and return a pointer
+ /// to it, or a nullptr in case of any error.
+ using TranslateSourceMgrToMLIRFunction = std::function<OwningOpRef<ModuleOp>(
+ llvm::SourceMgr &sourceMgr, MLIRContext *)>;
+
+ /// Interface of the function that translates the given string to MLIR. The
+ /// implementation should create a new MLIR ModuleOp in the given context. If
+ /// source-related error reporting is required from within the function, use
+ /// TranslateSourceMgrToMLIRFunction instead.
+ using TranslateStringRefToMLIRFunction =
+ std::function<OwningOpRef<ModuleOp>(llvm::StringRef, MLIRContext *)>;
+
+ /// Interface of the function that translates MLIR to a different format and
+ /// outputs the result to a stream. It is allowed to modify the module.
+ using TranslateFromMLIRFunction =
+ std::function<LogicalResult(ModuleOp, llvm::raw_ostream &output)>;
+
+ /// Interface of the function that performs file-to-file translation involving
+ /// MLIR. The input file is held in the given MemoryBuffer; the output file
+ /// should be written to the given raw_ostream. The implementation should create
+ /// all MLIR constructs needed during the process inside the given context. This
+ /// can be used for round-tripping external formats through the MLIR system.
+ using TranslateFunction = std::function<LogicalResult(
+ llvm::SourceMgr &sourceMgr, llvm::raw_ostream &output, MLIRContext *)>;
+
+ /// Use Translate[ToMLIR|FromMLIR]Registration as an initializer that
+ /// registers a function and associates it with name. This requires that a
+ /// translation has not been registered to a given name.
+ ///
+ /// Usage:
+ ///
+ /// // At file scope.
+ /// namespace mlir {
+ /// void registerTRexToMLIRRegistration() {
+ /// TranslateToMLIRRegistration Unused(&MySubCommand, [] { ... });
+ /// }
+ /// } // namespace mlir
+ ///
+ /// \{
+ struct TranslateToMLIRRegistration {
+- TranslateToMLIRRegistration(llvm::StringRef name,
++ TranslateToMLIRRegistration(llvm::StringRef name, llvm::StringRef description,
+ const TranslateSourceMgrToMLIRFunction &function);
+- TranslateToMLIRRegistration(llvm::StringRef name,
++ TranslateToMLIRRegistration(llvm::StringRef name, llvm::StringRef description,
+ const TranslateStringRefToMLIRFunction &function);
+ };
+
+ struct TranslateFromMLIRRegistration {
+ TranslateFromMLIRRegistration(
+- llvm::StringRef name, const TranslateFromMLIRFunction &function,
++ llvm::StringRef name, llvm::StringRef description,
++ const TranslateFromMLIRFunction &function,
+ const std::function<void(DialectRegistry &)> &dialectRegistration =
+ [](DialectRegistry &) {});
+ };
+ struct TranslateRegistration {
+- TranslateRegistration(llvm::StringRef name,
++ TranslateRegistration(llvm::StringRef name, llvm::StringRef description,
+ const TranslateFunction &function);
+ };
+ /// \}
+
+ /// A command line parser for translation functions.
+ struct TranslationParser : public llvm::cl::parser<const TranslateFunction *> {
+ TranslationParser(llvm::cl::Option &opt);
+
+ void printOptionInfo(const llvm::cl::Option &o,
+ size_t globalWidth) const override;
+ };
+
+ } // namespace mlir
+
+ #endif // MLIR_TOOLS_MLIRTRANSLATE_TRANSLATION_H
+# diff --git a/mlir/lib/Target/Cpp/TranslateRegistration.cpp b/mlir/lib/Target/Cpp/TranslateRegistration.cpp
+# index c4d26ea..c85dd0d 100644
+# --- a/mlir/lib/Target/Cpp/TranslateRegistration.cpp
+# +++ b/mlir/lib/Target/Cpp/TranslateRegistration.cpp
+# @@ -1,54 +1,54 @@
+# //===- TranslateRegistration.cpp - Register translation -------------------===//
+# //
+# // 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
+# //
+# //===----------------------------------------------------------------------===//
+
+# #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h"
+# #include "mlir/Dialect/ControlFlow/IR/ControlFlow.h"
+# #include "mlir/Dialect/EmitC/IR/EmitC.h"
+# #include "mlir/Dialect/Func/IR/FuncOps.h"
+# #include "mlir/Dialect/Math/IR/Math.h"
+# #include "mlir/Dialect/SCF/IR/SCF.h"
+# #include "mlir/IR/BuiltinOps.h"
+# #include "mlir/IR/Dialect.h"
+# #include "mlir/Target/Cpp/CppEmitter.h"
+# #include "mlir/Tools/mlir-translate/Translation.h"
+# #include "llvm/Support/CommandLine.h"
+
+# using namespace mlir;
+
+# namespace mlir {
+
+# //===----------------------------------------------------------------------===//
+# // Cpp registration
+# //===----------------------------------------------------------------------===//
+
+# void registerToCppTranslation() {
+# static llvm::cl::opt<bool> declareVariablesAtTop(
+# "declare-variables-at-top",
+# llvm::cl::desc("Declare variables at top when emitting C/C++"),
+# llvm::cl::init(false));
+
+# TranslateFromMLIRRegistration reg(
+# - "mlir-to-cpp",
+# + "mlir-to-cpp", "translate mlir to cpp",
+# [](ModuleOp module, raw_ostream &output) {
+# return emitc::translateToCpp(
+# module, output,
+# /*declareVariablesAtTop=*/declareVariablesAtTop);
+# },
+# [](DialectRegistry ®istry) {
+# // clang-format off
+# registry.insert<arith::ArithmeticDialect,
+# cf::ControlFlowDialect,
+# emitc::EmitCDialect,
+# func::FuncDialect,
+# math::MathDialect,
+# scf::SCFDialect>();
+# // clang-format on
+# });
+# }
+
+# } // namespace mlir
+# diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
+# index 9c47d36..b839bba 100644
+# --- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
+# +++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
+# @@ -1,1415 +1,1416 @@
+# //===- ConvertFromLLVMIR.cpp - MLIR to LLVM IR conversion -----------------===//
+# //
+# // 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 file implements a translation between LLVM IR and the MLIR LLVM dialect.
+# //
+# //===----------------------------------------------------------------------===//
+
+# #include "mlir/Target/LLVMIR/Import.h"
+
+# #include "mlir/Dialect/DLTI/DLTI.h"
+# #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+# #include "mlir/IR/Builders.h"
+# #include "mlir/IR/BuiltinOps.h"
+# #include "mlir/IR/BuiltinTypes.h"
+# #include "mlir/IR/MLIRContext.h"
+# #include "mlir/Interfaces/DataLayoutInterfaces.h"
+# #include "mlir/Target/LLVMIR/TypeFromLLVM.h"
+# #include "mlir/Tools/mlir-translate/Translation.h"
+
+# #include "llvm/ADT/StringSet.h"
+# #include "llvm/ADT/TypeSwitch.h"
+# #include "llvm/IR/Attributes.h"
+# #include "llvm/IR/Constants.h"
+# #include "llvm/IR/DerivedTypes.h"
+# #include "llvm/IR/Function.h"
+# #include "llvm/IR/InlineAsm.h"
+# #include "llvm/IR/Instructions.h"
+# #include "llvm/IR/Intrinsics.h"
+# #include "llvm/IR/Type.h"
+# #include "llvm/IRReader/IRReader.h"
+# #include "llvm/Support/Error.h"
+# #include "llvm/Support/SourceMgr.h"
+
+# using namespace mlir;
+# using namespace mlir::LLVM;
+
+# #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsFromLLVM.inc"
+
+# // Utility to print an LLVM value as a string for passing to emitError().
+# // FIXME: Diagnostic should be able to natively handle types that have
+# // operator << (raw_ostream&) defined.
+# static std::string diag(llvm::Value &v) {
+# std::string s;
+# llvm::raw_string_ostream os(s);
+# os << v;
+# return os.str();
+# }
+
+# /// Creates an attribute containing ABI and preferred alignment numbers parsed
+# /// a string. The string may be either "abi:preferred" or just "abi". In the
+# /// latter case, the prefrred alignment is considered equal to ABI alignment.
+# static DenseIntElementsAttr parseDataLayoutAlignment(MLIRContext &ctx,
+# StringRef spec) {
+# auto i32 = IntegerType::get(&ctx, 32);
+
+# StringRef abiString, preferredString;
+# std::tie(abiString, preferredString) = spec.split(':');
+# int abi, preferred;
+# if (abiString.getAsInteger(/*Radix=*/10, abi))
+# return nullptr;
+
+# if (preferredString.empty())
+# preferred = abi;
+# else if (preferredString.getAsInteger(/*Radix=*/10, preferred))
+# return nullptr;
+
+# return DenseIntElementsAttr::get(VectorType::get({2}, i32), {abi, preferred});
+# }
+
+# /// Returns a supported MLIR floating point type of the given bit width or null
+# /// if the bit width is not supported.
+# static FloatType getDLFloatType(MLIRContext &ctx, int32_t bitwidth) {
+# switch (bitwidth) {
+# case 16:
+# return FloatType::getF16(&ctx);
+# case 32:
+# return FloatType::getF32(&ctx);
+# case 64:
+# return FloatType::getF64(&ctx);
+# case 80:
+# return FloatType::getF80(&ctx);
+# case 128:
+# return FloatType::getF128(&ctx);
+# default:
+# return nullptr;
+# }
+# }
+
+# DataLayoutSpecInterface
+# mlir::translateDataLayout(const llvm::DataLayout &dataLayout,
+# MLIRContext *context) {
+# assert(context && "expected MLIR context");
+# std::string layoutstr = dataLayout.getStringRepresentation();
+
+# // Remaining unhandled default layout defaults
+# // e (little endian if not set)
+# // p[n]:64:64:64 (non zero address spaces have 64-bit properties)
+# std::string append =
+# "p:64:64:64-S0-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f16:16:16-f64:"
+# "64:64-f128:128:128-v64:64:64-v128:128:128-a:0:64";
+# if (layoutstr.empty())
+# layoutstr = append;
+# else
+# layoutstr = layoutstr + "-" + append;
+
+# StringRef layout(layoutstr);
+
+# SmallVector<DataLayoutEntryInterface> entries;
+# StringSet<> seen;
+# while (!layout.empty()) {
+# // Split at '-'.
+# std::pair<StringRef, StringRef> split = layout.split('-');
+# StringRef current;
+# std::tie(current, layout) = split;
+
+# // Split at ':'.
+# StringRef kind, spec;
+# std::tie(kind, spec) = current.split(':');
+# if (seen.contains(kind))
+# continue;
+# seen.insert(kind);
+
+# char symbol = kind.front();
+# StringRef parameter = kind.substr(1);
+
+# if (symbol == 'i' || symbol == 'f') {
+# unsigned bitwidth;
+# if (parameter.getAsInteger(/*Radix=*/10, bitwidth))
+# return nullptr;
+# DenseIntElementsAttr params = parseDataLayoutAlignment(*context, spec);
+# if (!params)
+# return nullptr;
+# auto entry = DataLayoutEntryAttr::get(
+# symbol == 'i' ? static_cast<Type>(IntegerType::get(context, bitwidth))
+# : getDLFloatType(*context, bitwidth),
+# params);
+# entries.emplace_back(entry);
+# } else if (symbol == 'e' || symbol == 'E') {
+# auto value = StringAttr::get(
+# context, symbol == 'e' ? DLTIDialect::kDataLayoutEndiannessLittle
+# : DLTIDialect::kDataLayoutEndiannessBig);
+# auto entry = DataLayoutEntryAttr::get(
+# StringAttr::get(context, DLTIDialect::kDataLayoutEndiannessKey),
+# value);
+# entries.emplace_back(entry);
+# }
+# }
+
+# return DataLayoutSpecAttr::get(context, entries);
+# }
+
+# // Handles importing globals and functions from an LLVM module.
+# namespace {
+# class Importer {
+# public:
+# Importer(MLIRContext *context, ModuleOp module)
+# : b(context), context(context), module(module),
+# unknownLoc(FileLineColLoc::get(context, "imported-bitcode", 0, 0)),
+# typeTranslator(*context) {
+# b.setInsertionPointToStart(module.getBody());
+# }
+
+# /// Imports `f` into the current module.
+# LogicalResult processFunction(llvm::Function *f);
+
+# /// Converts function attributes of LLVM Function \p f
+# /// into LLVM dialect attributes of LLVMFuncOp \p funcOp.
+# void processFunctionAttributes(llvm::Function *f, LLVMFuncOp funcOp);
+
+# /// Imports GV as a GlobalOp, creating it if it doesn't exist.
+# GlobalOp processGlobal(llvm::GlobalVariable *gv);
+
+# private:
+# /// Returns personality of `f` as a FlatSymbolRefAttr.
+# FlatSymbolRefAttr getPersonalityAsAttr(llvm::Function *f);
+# /// Imports `bb` into `block`, which must be initially empty.
+# LogicalResult processBasicBlock(llvm::BasicBlock *bb, Block *block);
+# /// Imports `inst` and populates instMap[inst] with the imported Value.
+# LogicalResult processInstruction(llvm::Instruction *inst);
+# /// Creates an LLVM-compatible MLIR type for `type`.
+# Type processType(llvm::Type *type);
+# /// `value` is an SSA-use. Return the remapped version of `value` or a
+# /// placeholder that will be remapped later if this is an instruction that
+# /// has not yet been visited.
+# Value processValue(llvm::Value *value);
+# /// Create the most accurate Location possible using a llvm::DebugLoc and
+# /// possibly an llvm::Instruction to narrow the Location if debug information
+# /// is unavailable.
+# Location processDebugLoc(const llvm::DebugLoc &loc,
+# llvm::Instruction *inst = nullptr);
+# /// `br` branches to `target`. Append the block arguments to attach to the
+# /// generated branch op to `blockArguments`. These should be in the same order
+# /// as the PHIs in `target`.
+# LogicalResult processBranchArgs(llvm::Instruction *br,
+# llvm::BasicBlock *target,
+# SmallVectorImpl<Value> &blockArguments);
+# /// Returns the builtin type equivalent to be used in attributes for the given
+# /// LLVM IR dialect type.
+# Type getStdTypeForAttr(Type type);
+# /// Return `value` as an attribute to attach to a GlobalOp.
+# Attribute getConstantAsAttr(llvm::Constant *value);
+# /// Return `c` as an MLIR Value. This could either be a ConstantOp, or
+# /// an expanded sequence of ops in the current function's entry block (for
+# /// ConstantExprs or ConstantGEPs).
+# Value processConstant(llvm::Constant *c);
+
+# /// The current builder, pointing at where the next Instruction should be
+# /// generated.
+# OpBuilder b;
+# /// The current context.
+# MLIRContext *context;
+# /// The current module being created.
+# ModuleOp module;
+# /// The entry block of the current function being processed.
+# Block *currentEntryBlock = nullptr;
+
+# /// Globals are inserted before the first function, if any.
+# Block::iterator getGlobalInsertPt() {
+# auto it = module.getBody()->begin();
+# auto endIt = module.getBody()->end();
+# while (it != endIt && !isa<LLVMFuncOp>(it))
+# ++it;
+# return it;
+# }
+
+# /// Functions are always inserted before the module terminator.
+# Block::iterator getFuncInsertPt() {
+# return std::prev(module.getBody()->end());
+# }
+
+# /// Remapped blocks, for the current function.
+# DenseMap<llvm::BasicBlock *, Block *> blocks;
+# /// Remapped values. These are function-local.
+# DenseMap<llvm::Value *, Value> instMap;
+# /// Instructions that had not been defined when first encountered as a use.
+# /// Maps to the dummy Operation that was created in processValue().
+# DenseMap<llvm::Value *, Operation *> unknownInstMap;
+# /// Uniquing map of GlobalVariables.
+# DenseMap<llvm::GlobalVariable *, GlobalOp> globals;
+# /// Cached FileLineColLoc::get("imported-bitcode", 0, 0).
+# Location unknownLoc;
+# /// The stateful type translator (contains named structs).
+# LLVM::TypeFromLLVMIRTranslator typeTranslator;
+# };
+# } // namespace
+
+# Location Importer::processDebugLoc(const llvm::DebugLoc &loc,
+# llvm::Instruction *inst) {
+# if (!loc)
+# return unknownLoc;
+
+# // FIXME: Obtain the filename from DILocationInfo.
+# return FileLineColLoc::get(context, "imported-bitcode", loc.getLine(),
+# loc.getCol());
+# }
+
+# Type Importer::processType(llvm::Type *type) {
+# if (Type result = typeTranslator.translateType(type))
+# return result;
+
+# // FIXME: Diagnostic should be able to natively handle types that have
+# // operator<<(raw_ostream&) defined.
+# std::string s;
+# llvm::raw_string_ostream os(s);
+# os << *type;
+# emitError(unknownLoc) << "unhandled type: " << os.str();
+# return nullptr;
+# }
+
+# // We only need integers, floats, doubles, and vectors and tensors thereof for
+# // attributes. Scalar and vector types are converted to the standard
+# // equivalents. Array types are converted to ranked tensors; nested array types
+# // are converted to multi-dimensional tensors or vectors, depending on the
+# // innermost type being a scalar or a vector.
+# Type Importer::getStdTypeForAttr(Type type) {
+# if (!type)
+# return nullptr;
+
+# if (type.isa<IntegerType, FloatType>())
+# return type;
+
+# // LLVM vectors can only contain scalars.
+# if (LLVM::isCompatibleVectorType(type)) {
+# auto numElements = LLVM::getVectorNumElements(type);
+# if (numElements.isScalable()) {
+# emitError(unknownLoc) << "scalable vectors not supported";
+# return nullptr;
+# }
+# Type elementType = getStdTypeForAttr(LLVM::getVectorElementType(type));
+# if (!elementType)
+# return nullptr;
+# return VectorType::get(numElements.getKnownMinValue(), elementType);
+# }
+
+# // LLVM arrays can contain other arrays or vectors.
+# if (auto arrayType = type.dyn_cast<LLVMArrayType>()) {
+# // Recover the nested array shape.
+# SmallVector<int64_t, 4> shape;
+# shape.push_back(arrayType.getNumElements());
+# while (arrayType.getElementType().isa<LLVMArrayType>()) {
+# arrayType = arrayType.getElementType().cast<LLVMArrayType>();
+# shape.push_back(arrayType.getNumElements());
+# }
+
+# // If the innermost type is a vector, use the multi-dimensional vector as
+# // attribute type.
+# if (LLVM::isCompatibleVectorType(arrayType.getElementType())) {
+# auto numElements = LLVM::getVectorNumElements(arrayType.getElementType());
+# if (numElements.isScalable()) {
+# emitError(unknownLoc) << "scalable vectors not supported";
+# return nullptr;
+# }
+# shape.push_back(numElements.getKnownMinValue());
+
+# Type elementType = getStdTypeForAttr(
+# LLVM::getVectorElementType(arrayType.getElementType()));
+# if (!elementType)
+# return nullptr;
+# return VectorType::get(shape, elementType);
+# }
+
+# // Otherwise use a tensor.
+# Type elementType = getStdTypeForAttr(arrayType.getElementType());
+# if (!elementType)
+# return nullptr;
+# return RankedTensorType::get(shape, elementType);
+# }
+
+# return nullptr;
+# }
+
+# // Get the given constant as an attribute. Not all constants can be represented
+# // as attributes.
+# Attribute Importer::getConstantAsAttr(llvm::Constant *value) {
+# if (auto *ci = dyn_cast<llvm::ConstantInt>(value))
+# return b.getIntegerAttr(
+# IntegerType::get(context, ci->getType()->getBitWidth()),
+# ci->getValue());
+# if (auto *c = dyn_cast<llvm::ConstantDataArray>(value))
+# if (c->isString())
+# return b.getStringAttr(c->getAsString());
+# if (auto *c = dyn_cast<llvm::ConstantFP>(value)) {
+# auto *type = c->getType();
+# FloatType floatTy;
+# if (type->isBFloatTy())
+# floatTy = FloatType::getBF16(context);
+# else
+# floatTy = getDLFloatType(*context, type->getScalarSizeInBits());
+# assert(floatTy && "unsupported floating point type");
+# return b.getFloatAttr(floatTy, c->getValueAPF());
+# }
+# if (auto *f = dyn_cast<llvm::Function>(value))
+# return SymbolRefAttr::get(b.getContext(), f->getName());
+
+# // Convert constant data to a dense elements attribute.
+# if (auto *cd = dyn_cast<llvm::ConstantDataSequential>(value)) {
+# Type type = processType(cd->getElementType());
+# if (!type)
+# return nullptr;
+
+# auto attrType = getStdTypeForAttr(processType(cd->getType()))
+# .dyn_cast_or_null<ShapedType>();
+# if (!attrType)
+# return nullptr;
+
+# if (type.isa<IntegerType>()) {
+# SmallVector<APInt, 8> values;
+# values.reserve(cd->getNumElements());
+# for (unsigned i = 0, e = cd->getNumElements(); i < e; ++i)
+# values.push_back(cd->getElementAsAPInt(i));
+# return DenseElementsAttr::get(attrType, values);
+# }
+
+# if (type.isa<Float32Type, Float64Type>()) {
+# SmallVector<APFloat, 8> values;
+# values.reserve(cd->getNumElements());
+# for (unsigned i = 0, e = cd->getNumElements(); i < e; ++i)
+# values.push_back(cd->getElementAsAPFloat(i));
+# return DenseElementsAttr::get(attrType, values);
+# }
+
+# return nullptr;
+# }
+
+# // Unpack constant aggregates to create dense elements attribute whenever
+# // possible. Return nullptr (failure) otherwise.
+# if (isa<llvm::ConstantAggregate>(value)) {
+# auto outerType = getStdTypeForAttr(processType(value->getType()))
+# .dyn_cast_or_null<ShapedType>();
+# if (!outerType)
+# return nullptr;
+
+# SmallVector<Attribute, 8> values;
+# SmallVector<int64_t, 8> shape;
+
+# for (unsigned i = 0, e = value->getNumOperands(); i < e; ++i) {
+# auto nested = getConstantAsAttr(value->getAggregateElement(i))
+# .dyn_cast_or_null<DenseElementsAttr>();
+# if (!nested)
+# return nullptr;
+
+# values.append(nested.value_begin<Attribute>(),
+# nested.value_end<Attribute>());
+# }
+
+# return DenseElementsAttr::get(outerType, values);
+# }
+
+# return nullptr;
+# }
+
+# GlobalOp Importer::processGlobal(llvm::GlobalVariable *gv) {
+# auto it = globals.find(gv);
+# if (it != globals.end())
+# return it->second;
+
+# OpBuilder b(module.getBody(), getGlobalInsertPt());
+# Attribute valueAttr;
+# if (gv->hasInitializer())
+# valueAttr = getConstantAsAttr(gv->getInitializer());
+# Type type = processType(gv->getValueType());
+# if (!type)
+# return nullptr;
+
+# uint64_t alignment = 0;
+# llvm::MaybeAlign maybeAlign = gv->getAlign();
+# if (maybeAlign.has_value()) {
+# llvm::Align align = maybeAlign.value();
+# alignment = align.value();
+# }
+
+# GlobalOp op = b.create<GlobalOp>(
+# UnknownLoc::get(context), type, gv->isConstant(),
+# convertLinkageFromLLVM(gv->getLinkage()), gv->getName(), valueAttr,
+# alignment, /*addr_space=*/gv->getAddressSpace(),
+# /*dso_local=*/gv->isDSOLocal(), /*thread_local=*/gv->isThreadLocal());
+
+# if (gv->hasInitializer() && !valueAttr) {
+# Region &r = op.getInitializerRegion();
+# currentEntryBlock = b.createBlock(&r);
+# b.setInsertionPoint(currentEntryBlock, currentEntryBlock->begin());
+# Value v = processConstant(gv->getInitializer());
+# if (!v)
+# return nullptr;
+# b.create<ReturnOp>(op.getLoc(), ArrayRef<Value>({v}));
+# }
+# if (gv->hasAtLeastLocalUnnamedAddr())
+# op.setUnnamedAddrAttr(UnnamedAddrAttr::get(
+# context, convertUnnamedAddrFromLLVM(gv->getUnnamedAddr())));
+# if (gv->hasSection())
+# op.setSectionAttr(b.getStringAttr(gv->getSection()));
+
+# return globals[gv] = op;
+# }
+
+# Value Importer::processConstant(llvm::Constant *c) {
+# OpBuilder bEntry(currentEntryBlock, currentEntryBlock->begin());
+# if (Attribute attr = getConstantAsAttr(c)) {
+# // These constants can be represented as attributes.
+# OpBuilder b(currentEntryBlock, currentEntryBlock->begin());
+# Type type = processType(c->getType());
+# if (!type)
+# return nullptr;
+# if (auto symbolRef = attr.dyn_cast<FlatSymbolRefAttr>())
+# return bEntry.create<AddressOfOp>(unknownLoc, type, symbolRef.getValue());
+# return bEntry.create<ConstantOp>(unknownLoc, type, attr);
+# }
+# if (auto *cn = dyn_cast<llvm::ConstantPointerNull>(c)) {
+# Type type = processType(cn->getType());
+# if (!type)
+# return nullptr;
+# return bEntry.create<NullOp>(unknownLoc, type);
+# }
+# if (auto *gv = dyn_cast<llvm::GlobalVariable>(c))
+# return bEntry.create<AddressOfOp>(UnknownLoc::get(context),
+# processGlobal(gv));
+
+# if (auto *ce = dyn_cast<llvm::ConstantExpr>(c)) {
+# llvm::Instruction *i = ce->getAsInstruction();
+# OpBuilder::InsertionGuard guard(b);
+# b.setInsertionPoint(currentEntryBlock, currentEntryBlock->begin());
+# if (failed(processInstruction(i)))
+# return nullptr;
+# assert(instMap.count(i));
+
+# // If we don't remove entry of `i` here, it's totally possible that the
+# // next time llvm::ConstantExpr::getAsInstruction is called again, which
+# // always allocates a new Instruction, memory address of the newly
+# // created Instruction might be the same as `i`. Making processInstruction
+# // falsely believe that the new Instruction has been processed before
+# // and raised an assertion error.
+# Value value = instMap[i];
+# instMap.erase(i);
+# // Remove this zombie LLVM instruction now, leaving us only with the MLIR
+# // op.
+# i->deleteValue();
+# return value;
+# }
+# if (auto *ue = dyn_cast<llvm::UndefValue>(c)) {
+# Type type = processType(ue->getType());
+# if (!type)
+# return nullptr;
+# return bEntry.create<UndefOp>(UnknownLoc::get(context), type);
+# }
+
+# if (isa<llvm::ConstantAggregate>(c) || isa<llvm::ConstantAggregateZero>(c)) {
+# unsigned numElements = c->getNumOperands();
+# std::function<llvm::Constant *(unsigned)> getElement =
+# [&](unsigned index) -> llvm::Constant * {
+# return c->getAggregateElement(index);
+# };
+# // llvm::ConstantAggregateZero doesn't take any operand
+# // so its getNumOperands is always zero.
+# if (auto *caz = dyn_cast<llvm::ConstantAggregateZero>(c)) {
+# numElements = caz->getElementCount().getFixedValue();
+# // We want to capture the pointer rather than reference
+# // to the pointer since the latter will become dangling upon
+# // exiting the scope.
+# getElement = [=](unsigned index) -> llvm::Constant * {
+# return caz->getElementValue(index);
+# };
+# }
+
+# // Generate a llvm.undef as the root value first.
+# Type rootType = processType(c->getType());
+# if (!rootType)
+# return nullptr;
+# bool useInsertValue = rootType.isa<LLVMArrayType, LLVMStructType>();
+# assert((useInsertValue || LLVM::isCompatibleVectorType(rootType)) &&
+# "unrecognized aggregate type");
+# Value root = bEntry.create<UndefOp>(unknownLoc, rootType);
+# for (unsigned i = 0; i < numElements; ++i) {
+# llvm::Constant *element = getElement(i);
+# Value elementValue = processConstant(element);
+# if (!elementValue)
+# return nullptr;
+# if (useInsertValue) {
+# root = bEntry.create<InsertValueOp>(UnknownLoc::get(context), root,
+# elementValue, i);
+# } else {
+# Attribute indexAttr = bEntry.getI32IntegerAttr(static_cast<int32_t>(i));
+# Value indexValue = bEntry.create<ConstantOp>(
+# unknownLoc, bEntry.getI32Type(), indexAttr);
+# if (!indexValue)
+# return nullptr;
+# root = bEntry.create<InsertElementOp>(
+# UnknownLoc::get(context), rootType, root, elementValue, indexValue);
+# }
+# }
+# return root;
+# }
+
+# emitError(unknownLoc) << "unhandled constant: " << diag(*c);
+# return nullptr;
+# }
+
+# Value Importer::processValue(llvm::Value *value) {
+# auto it = instMap.find(value);
+# if (it != instMap.end())
+# return it->second;
+
+# // We don't expect to see instructions in dominator order. If we haven't seen
+# // this instruction yet, create an unknown op and remap it later.
+# if (isa<llvm::Instruction>(value)) {
+# Type type = processType(value->getType());
+# if (!type)
+# return nullptr;
+# unknownInstMap[value] =
+# b.create(UnknownLoc::get(context), b.getStringAttr("llvm.unknown"),
+# /*operands=*/{}, type);
+# return unknownInstMap[value]->getResult(0);
+# }
+
+# if (auto *c = dyn_cast<llvm::Constant>(value))
+# return processConstant(c);
+
+# emitError(unknownLoc) << "unhandled value: " << diag(*value);
+# return nullptr;
+# }
+
+# /// Return the MLIR OperationName for the given LLVM opcode.
+# static StringRef lookupOperationNameFromOpcode(unsigned opcode) {
+# // Maps from LLVM opcode to MLIR OperationName. This is deliberately ordered
+# // as in llvm/IR/Instructions.def to aid comprehension and spot missing
+# // instructions.
+# #define INST(llvm_n, mlir_n) \
+# { llvm::Instruction::llvm_n, LLVM::mlir_n##Op::getOperationName() }
+# static const DenseMap<unsigned, StringRef> opcMap = {
+# // clang-format off
+# INST(Ret, Return),
+# // Br is handled specially.
+# // Switch is handled specially.
+# // FIXME: indirectbr
+# // Invoke is handled specially.
+# INST(Resume, Resume),
+# INST(Unreachable, Unreachable),
+# // FIXME: cleanupret
+# // FIXME: catchret
+# // FIXME: catchswitch
+# // FIXME: callbr
+# INST(FNeg, FNeg),
+# INST(Add, Add),
+# INST(FAdd, FAdd),
+# INST(Sub, Sub),
+# INST(FSub, FSub),
+# INST(Mul, Mul),
+# INST(FMul, FMul),
+# INST(UDiv, UDiv),
+# INST(SDiv, SDiv),
+# INST(FDiv, FDiv),
+# INST(URem, URem),
+# INST(SRem, SRem),
+# INST(FRem, FRem),
+# INST(Shl, Shl),
+# INST(LShr, LShr),
+# INST(AShr, AShr),
+# INST(And, And),
+# INST(Or, Or),
+# INST(Xor, XOr),
+# INST(ExtractElement, ExtractElement),
+# INST(InsertElement, InsertElement),
+# // ShuffleVector is handled specially.
+# // ExtractValue is handled specially.
+# // InsertValue is handled specially.
+# INST(Alloca, Alloca),
+# INST(Load, Load),
+# INST(Store, Store),
+# INST(Fence, Fence),
+# // AtomicCmpXchg is handled specially.
+# // AtomicRMW is handled specially.
+# // Getelementptr is handled specially.
+# INST(Trunc, Trunc),
+# INST(ZExt, ZExt),
+# INST(SExt, SExt),
+# INST(FPToUI, FPToUI),
+# INST(FPToSI, FPToSI),
+# INST(UIToFP, UIToFP),
+# INST(SIToFP, SIToFP),
+# INST(FPTrunc, FPTrunc),
+# INST(FPExt, FPExt),
+# INST(PtrToInt, PtrToInt),
+# INST(IntToPtr, IntToPtr),
+# INST(BitCast, Bitcast),
+# INST(AddrSpaceCast, AddrSpaceCast),
+# // ICmp is handled specially.
+# // FCmp is handled specially.
+# // PHI is handled specially.
+# INST(Select, Select),
+# INST(Freeze, Freeze),
+# INST(Call, Call),
+# // FIXME: vaarg
+# // FIXME: landingpad
+# // FIXME: catchpad
+# // FIXME: cleanuppad
+# // clang-format on
+# };
+# #undef INST
+
+# return opcMap.lookup(opcode);
+# }
+
+# /// Return the MLIR OperationName for the given LLVM intrinsic ID.
+# static StringRef lookupOperationNameFromIntrinsicID(unsigned id) {
+# // Maps from LLVM intrinsic ID to MLIR OperationName.
+# static const DenseMap<unsigned, StringRef> intrMap = {
+# #include "mlir/Dialect/LLVMIR/LLVMIntrinsicToLLVMIROpPairs.inc"
+# };
+# return intrMap.lookup(id);
+# }
+
+# static ICmpPredicate getICmpPredicate(llvm::CmpInst::Predicate p) {
+# switch (p) {
+# default:
+# llvm_unreachable("incorrect comparison predicate");
+# case llvm::CmpInst::Predicate::ICMP_EQ:
+# return LLVM::ICmpPredicate::eq;
+# case llvm::CmpInst::Predicate::ICMP_NE:
+# return LLVM::ICmpPredicate::ne;
+# case llvm::CmpInst::Predicate::ICMP_SLT:
+# return LLVM::ICmpPredicate::slt;
+# case llvm::CmpInst::Predicate::ICMP_SLE:
+# return LLVM::ICmpPredicate::sle;
+# case llvm::CmpInst::Predicate::ICMP_SGT:
+# return LLVM::ICmpPredicate::sgt;
+# case llvm::CmpInst::Predicate::ICMP_SGE:
+# return LLVM::ICmpPredicate::sge;
+# case llvm::CmpInst::Predicate::ICMP_ULT:
+# return LLVM::ICmpPredicate::ult;
+# case llvm::CmpInst::Predicate::ICMP_ULE:
+# return LLVM::ICmpPredicate::ule;
+# case llvm::CmpInst::Predicate::ICMP_UGT:
+# return LLVM::ICmpPredicate::ugt;
+# case llvm::CmpInst::Predicate::ICMP_UGE:
+# return LLVM::ICmpPredicate::uge;
+# }
+# llvm_unreachable("incorrect integer comparison predicate");
+# }
+
+# static FCmpPredicate getFCmpPredicate(llvm::CmpInst::Predicate p) {
+# switch (p) {
+# default:
+# llvm_unreachable("incorrect comparison predicate");
+# case llvm::CmpInst::Predicate::FCMP_FALSE:
+# return LLVM::FCmpPredicate::_false;
+# case llvm::CmpInst::Predicate::FCMP_TRUE:
+# return LLVM::FCmpPredicate::_true;
+# case llvm::CmpInst::Predicate::FCMP_OEQ:
+# return LLVM::FCmpPredicate::oeq;
+# case llvm::CmpInst::Predicate::FCMP_ONE:
+# return LLVM::FCmpPredicate::one;
+# case llvm::CmpInst::Predicate::FCMP_OLT:
+# return LLVM::FCmpPredicate::olt;
+# case llvm::CmpInst::Predicate::FCMP_OLE:
+# return LLVM::FCmpPredicate::ole;
+# case llvm::CmpInst::Predicate::FCMP_OGT:
+# return LLVM::FCmpPredicate::ogt;
+# case llvm::CmpInst::Predicate::FCMP_OGE:
+# return LLVM::FCmpPredicate::oge;
+# case llvm::CmpInst::Predicate::FCMP_ORD:
+# return LLVM::FCmpPredicate::ord;
+# case llvm::CmpInst::Predicate::FCMP_ULT:
+# return LLVM::FCmpPredicate::ult;
+# case llvm::CmpInst::Predicate::FCMP_ULE:
+# return LLVM::FCmpPredicate::ule;
+# case llvm::CmpInst::Predicate::FCMP_UGT:
+# return LLVM::FCmpPredicate::ugt;
+# case llvm::CmpInst::Predicate::FCMP_UGE:
+# return LLVM::FCmpPredicate::uge;
+# case llvm::CmpInst::Predicate::FCMP_UNO:
+# return LLVM::FCmpPredicate::uno;
+# case llvm::CmpInst::Predicate::FCMP_UEQ:
+# return LLVM::FCmpPredicate::ueq;
+# case llvm::CmpInst::Predicate::FCMP_UNE:
+# return LLVM::FCmpPredicate::une;
+# }
+# llvm_unreachable("incorrect floating point comparison predicate");
+# }
+
+# static AtomicOrdering getLLVMAtomicOrdering(llvm::AtomicOrdering ordering) {
+# switch (ordering) {
+# case llvm::AtomicOrdering::NotAtomic:
+# return LLVM::AtomicOrdering::not_atomic;
+# case llvm::AtomicOrdering::Unordered:
+# return LLVM::AtomicOrdering::unordered;
+# case llvm::AtomicOrdering::Monotonic:
+# return LLVM::AtomicOrdering::monotonic;
+# case llvm::AtomicOrdering::Acquire:
+# return LLVM::AtomicOrdering::acquire;
+# case llvm::AtomicOrdering::Release:
+# return LLVM::AtomicOrdering::release;
+# case llvm::AtomicOrdering::AcquireRelease:
+# return LLVM::AtomicOrdering::acq_rel;
+# case llvm::AtomicOrdering::SequentiallyConsistent:
+# return LLVM::AtomicOrdering::seq_cst;
+# }
+# llvm_unreachable("incorrect atomic ordering");
+# }
+
+# static AtomicBinOp getLLVMAtomicBinOp(llvm::AtomicRMWInst::BinOp binOp) {
+# switch (binOp) {
+# case llvm::AtomicRMWInst::Xchg:
+# return LLVM::AtomicBinOp::xchg;
+# case llvm::AtomicRMWInst::Add:
+# return LLVM::AtomicBinOp::add;
+# case llvm::AtomicRMWInst::Sub:
+# return LLVM::AtomicBinOp::sub;
+# case llvm::AtomicRMWInst::And:
+# return LLVM::AtomicBinOp::_and;
+# case llvm::AtomicRMWInst::Nand:
+# return LLVM::AtomicBinOp::nand;
+# case llvm::AtomicRMWInst::Or:
+# return LLVM::AtomicBinOp::_or;
+# case llvm::AtomicRMWInst::Xor:
+# return LLVM::AtomicBinOp::_xor;
+# case llvm::AtomicRMWInst::Max:
+# return LLVM::AtomicBinOp::max;
+# case llvm::AtomicRMWInst::Min:
+# return LLVM::AtomicBinOp::min;
+# case llvm::AtomicRMWInst::UMax:
+# return LLVM::AtomicBinOp::umax;
+# case llvm::AtomicRMWInst::UMin:
+# return LLVM::AtomicBinOp::umin;
+# case llvm::AtomicRMWInst::FAdd:
+# return LLVM::AtomicBinOp::fadd;
+# case llvm::AtomicRMWInst::FSub:
+# return LLVM::AtomicBinOp::fsub;
+# default:
+# llvm_unreachable("unsupported atomic binary operation");
+# }
+# }
+
+# // `br` branches to `target`. Return the branch arguments to `br`, in the
+# // same order of the PHIs in `target`.
+# LogicalResult
+# Importer::processBranchArgs(llvm::Instruction *br, llvm::BasicBlock *target,
+# SmallVectorImpl<Value> &blockArguments) {
+# for (auto inst = target->begin(); isa<llvm::PHINode>(inst); ++inst) {
+# auto *pn = cast<llvm::PHINode>(&*inst);
+# Value value = processValue(pn->getIncomingValueForBlock(br->getParent()));
+# if (!value)
+# return failure();
+# blockArguments.push_back(value);
+# }
+# return success();
+# }
+
+# LogicalResult Importer::processInstruction(llvm::Instruction *inst) {
+# // FIXME: Support uses of SubtargetData. Currently inbounds GEPs, fast-math
+# // flags and call / operand attributes are not supported.
+# Location loc = processDebugLoc(inst->getDebugLoc(), inst);
+# assert(!instMap.count(inst) &&
+# "processInstruction must be called only once per instruction!");
+# switch (inst->getOpcode()) {
+# default:
+# return emitError(loc) << "unknown instruction: " << diag(*inst);
+# case llvm::Instruction::Add:
+# case llvm::Instruction::FAdd:
+# case llvm::Instruction::Sub:
+# case llvm::Instruction::FSub:
+# case llvm::Instruction::Mul:
+# case llvm::Instruction::FMul:
+# case llvm::Instruction::UDiv:
+# case llvm::Instruction::SDiv:
+# case llvm::Instruction::FDiv:
+# case llvm::Instruction::URem:
+# case llvm::Instruction::SRem:
+# case llvm::Instruction::FRem:
+# case llvm::Instruction::Shl:
+# case llvm::Instruction::LShr:
+# case llvm::Instruction::AShr:
+# case llvm::Instruction::And:
+# case llvm::Instruction::Or:
+# case llvm::Instruction::Xor:
+# case llvm::Instruction::Load:
+# case llvm::Instruction::Store:
+# case llvm::Instruction::Ret:
+# case llvm::Instruction::Resume:
+# case llvm::Instruction::Trunc:
+# case llvm::Instruction::ZExt:
+# case llvm::Instruction::SExt:
+# case llvm::Instruction::FPToUI:
+# case llvm::Instruction::FPToSI:
+# case llvm::Instruction::UIToFP:
+# case llvm::Instruction::SIToFP:
+# case llvm::Instruction::FPTrunc:
+# case llvm::Instruction::FPExt:
+# case llvm::Instruction::PtrToInt:
+# case llvm::Instruction::IntToPtr:
+# case llvm::Instruction::AddrSpaceCast:
+# case llvm::Instruction::Freeze:
+# case llvm::Instruction::BitCast:
+# case llvm::Instruction::ExtractElement:
+# case llvm::Instruction::InsertElement:
+# case llvm::Instruction::Select:
+# case llvm::Instruction::FNeg:
+# case llvm::Instruction::Unreachable: {
+# OperationState state(loc, lookupOperationNameFromOpcode(inst->getOpcode()));
+# SmallVector<Value, 4> ops;
+# ops.reserve(inst->getNumOperands());
+# for (auto *op : inst->operand_values()) {
+# Value value = processValue(op);
+# if (!value)
+# return failure();
+# ops.push_back(value);
+# }
+# state.addOperands(ops);
+# if (!inst->getType()->isVoidTy()) {
+# Type type = processType(inst->getType());
+# if (!type)
+# return failure();
+# state.addTypes(type);
+# }
+# Operation *op = b.create(state);
+# if (!inst->getType()->isVoidTy())
+# instMap[inst] = op->getResult(0);
+# return success();
+# }
+# case llvm::Instruction::Alloca: {
+# Value size = processValue(inst->getOperand(0));
+# if (!size)
+# return failure();
+
+# auto *allocaInst = cast<llvm::AllocaInst>(inst);
+# instMap[inst] =
+# b.create<AllocaOp>(loc, processType(inst->getType()),
+# processType(allocaInst->getAllocatedType()), size,
+# allocaInst->getAlign().value());
+# return success();
+# }
+# case llvm::Instruction::ICmp: {
+# Value lhs = processValue(inst->getOperand(0));
+# Value rhs = processValue(inst->getOperand(1));
+# if (!lhs || !rhs)
+# return failure();
+# instMap[inst] = b.create<ICmpOp>(
+# loc, getICmpPredicate(cast<llvm::ICmpInst>(inst)->getPredicate()), lhs,
+# rhs);
+# return success();
+# }
+# case llvm::Instruction::FCmp: {
+# Value lhs = processValue(inst->getOperand(0));
+# Value rhs = processValue(inst->getOperand(1));
+# if (!lhs || !rhs)
+# return failure();
+
+# if (lhs.getType() != rhs.getType())
+# return failure();
+
+# Type boolType = b.getI1Type();
+# Type resType = boolType;
+# if (LLVM::isCompatibleVectorType(lhs.getType())) {
+# unsigned numElements =
+# LLVM::getVectorNumElements(lhs.getType()).getFixedValue();
+# resType = VectorType::get({numElements}, boolType);
+# }
+
+# instMap[inst] = b.create<FCmpOp>(
+# loc, resType,
+# getFCmpPredicate(cast<llvm::FCmpInst>(inst)->getPredicate()), lhs, rhs);
+# return success();
+# }
+# case llvm::Instruction::Br: {
+# auto *brInst = cast<llvm::BranchInst>(inst);
+# OperationState state(loc,
+# brInst->isConditional() ? "llvm.cond_br" : "llvm.br");
+# if (brInst->isConditional()) {
+# Value condition = processValue(brInst->getCondition());
+# if (!condition)
+# return failure();
+# state.addOperands(condition);
+# }
+
+# std::array<int32_t, 3> operandSegmentSizes = {1, 0, 0};
+# for (int i : llvm::seq<int>(0, brInst->getNumSuccessors())) {
+# auto *succ = brInst->getSuccessor(i);
+# SmallVector<Value, 4> blockArguments;
+# if (failed(processBranchArgs(brInst, succ, blockArguments)))
+# return failure();
+# state.addSuccessors(blocks[succ]);
+# state.addOperands(blockArguments);
+# operandSegmentSizes[i + 1] = blockArguments.size();
+# }
+
+# if (brInst->isConditional()) {
+# state.addAttribute(LLVM::CondBrOp::getOperandSegmentSizeAttr(),
+# b.getDenseI32ArrayAttr(operandSegmentSizes));
+# }
+
+# b.create(state);
+# return success();
+# }
+# case llvm::Instruction::Switch: {
+# auto *swInst = cast<llvm::SwitchInst>(inst);
+# // Process the condition value.
+# Value condition = processValue(swInst->getCondition());
+# if (!condition)
+# return failure();
+
+# SmallVector<Value> defaultBlockArgs;
+# // Process the default case.
+# llvm::BasicBlock *defaultBB = swInst->getDefaultDest();
+# if (failed(processBranchArgs(swInst, defaultBB, defaultBlockArgs)))
+# return failure();
+
+# // Process the cases.
+# unsigned numCases = swInst->getNumCases();
+# SmallVector<SmallVector<Value>> caseOperands(numCases);
+# SmallVector<ValueRange> caseOperandRefs(numCases);
+# SmallVector<int32_t> caseValues(numCases);
+# SmallVector<Block *> caseBlocks(numCases);
+# for (const auto &en : llvm::enumerate(swInst->cases())) {
+# const llvm::SwitchInst::CaseHandle &caseHandle = en.value();
+# unsigned i = en.index();
+# llvm::BasicBlock *succBB = caseHandle.getCaseSuccessor();
+# if (failed(processBranchArgs(swInst, succBB, caseOperands[i])))
+# return failure();
+# caseOperandRefs[i] = caseOperands[i];
+# caseValues[i] = caseHandle.getCaseValue()->getSExtValue();
+# caseBlocks[i] = blocks[succBB];
+# }
+
+# b.create<SwitchOp>(loc, condition, blocks[defaultBB], defaultBlockArgs,
+# caseValues, caseBlocks, caseOperandRefs);
+# return success();
+# }
+# case llvm::Instruction::PHI: {
+# Type type = processType(inst->getType());
+# if (!type)
+# return failure();
+# instMap[inst] = b.getInsertionBlock()->addArgument(
+# type, processDebugLoc(inst->getDebugLoc(), inst));
+# return success();
+# }
+# case llvm::Instruction::Call: {
+# llvm::CallInst *ci = cast<llvm::CallInst>(inst);
+# SmallVector<Value, 4> ops;
+# ops.reserve(inst->getNumOperands());
+# for (auto &op : ci->args()) {
+# Value arg = processValue(op.get());
+# if (!arg)
+# return failure();
+# ops.push_back(arg);
+# }
+
+# SmallVector<Type, 2> tys;
+# if (!ci->getType()->isVoidTy()) {
+# Type type = processType(inst->getType());
+# if (!type)
+# return failure();
+# tys.push_back(type);
+# }
+# Operation *op;
+# if (llvm::Function *callee = ci->getCalledFunction()) {
+# // For all intrinsics, try to generate to the corresponding op.
+# if (callee->isIntrinsic()) {
+# auto id = callee->getIntrinsicID();
+# StringRef opName = lookupOperationNameFromIntrinsicID(id);
+# if (!opName.empty()) {
+# OperationState state(loc, opName);
+# state.addOperands(ops);
+# state.addTypes(tys);
+# Operation *op = b.create(state);
+# if (!inst->getType()->isVoidTy())
+# instMap[inst] = op->getResult(0);
+# return success();
+# }
+# }
+# op = b.create<CallOp>(
+# loc, tys, SymbolRefAttr::get(b.getContext(), callee->getName()), ops);
+# } else {
+# Value calledValue = processValue(ci->getCalledOperand());
+# if (!calledValue)
+# return failure();
+# ops.insert(ops.begin(), calledValue);
+# op = b.create<CallOp>(loc, tys, ops);
+# }
+# if (!ci->getType()->isVoidTy())
+# instMap[inst] = op->getResult(0);
+# return success();
+# }
+# case llvm::Instruction::LandingPad: {
+# llvm::LandingPadInst *lpi = cast<llvm::LandingPadInst>(inst);
+# SmallVector<Value, 4> ops;
+
+# for (unsigned i = 0, ie = lpi->getNumClauses(); i < ie; i++)
+# ops.push_back(processConstant(lpi->getClause(i)));
+
+# Type ty = processType(lpi->getType());
+# if (!ty)
+# return failure();
+
+# instMap[inst] = b.create<LandingpadOp>(loc, ty, lpi->isCleanup(), ops);
+# return success();
+# }
+# case llvm::Instruction::Invoke: {
+# llvm::InvokeInst *ii = cast<llvm::InvokeInst>(inst);
+
+# SmallVector<Type, 2> tys;
+# if (!ii->getType()->isVoidTy())
+# tys.push_back(processType(inst->getType()));
+
+# SmallVector<Value, 4> ops;
+# ops.reserve(inst->getNumOperands() + 1);
+# for (auto &op : ii->args())
+# ops.push_back(processValue(op.get()));
+
+# SmallVector<Value, 4> normalArgs, unwindArgs;
+# (void)processBranchArgs(ii, ii->getNormalDest(), normalArgs);
+# (void)processBranchArgs(ii, ii->getUnwindDest(), unwindArgs);
+
+# Operation *op;
+# if (llvm::Function *callee = ii->getCalledFunction()) {
+# op = b.create<InvokeOp>(
+# loc, tys, SymbolRefAttr::get(b.getContext(), callee->getName()), ops,
+# blocks[ii->getNormalDest()], normalArgs, blocks[ii->getUnwindDest()],
+# unwindArgs);
+# } else {
+# ops.insert(ops.begin(), processValue(ii->getCalledOperand()));
+# op = b.create<InvokeOp>(loc, tys, ops, blocks[ii->getNormalDest()],
+# normalArgs, blocks[ii->getUnwindDest()],
+# unwindArgs);
+# }
+
+# if (!ii->getType()->isVoidTy())
+# instMap[inst] = op->getResult(0);
+# return success();
+# }
+# case llvm::Instruction::Fence: {
+# StringRef syncscope;
+# SmallVector<StringRef, 4> ssNs;
+# llvm::LLVMContext &llvmContext = inst->getContext();
+# llvm::FenceInst *fence = cast<llvm::FenceInst>(inst);
+# llvmContext.getSyncScopeNames(ssNs);
+# int fenceSyncScopeID = fence->getSyncScopeID();
+# for (unsigned i = 0, e = ssNs.size(); i != e; i++) {
+# if (fenceSyncScopeID == llvmContext.getOrInsertSyncScopeID(ssNs[i])) {
+# syncscope = ssNs[i];
+# break;
+# }
+# }
+# b.create<FenceOp>(loc, getLLVMAtomicOrdering(fence->getOrdering()),
+# syncscope);
+# return success();
+# }
+# case llvm::Instruction::AtomicRMW: {
+# auto *atomicInst = cast<llvm::AtomicRMWInst>(inst);
+# Value ptr = processValue(atomicInst->getPointerOperand());
+# Value val = processValue(atomicInst->getValOperand());
+# if (!ptr || !val)
+# return failure();
+
+# LLVM::AtomicBinOp binOp = getLLVMAtomicBinOp(atomicInst->getOperation());
+# LLVM::AtomicOrdering ordering =
+# getLLVMAtomicOrdering(atomicInst->getOrdering());
+
+# Type type = processType(inst->getType());
+# if (!type)
+# return failure();
+
+# instMap[inst] = b.create<AtomicRMWOp>(loc, type, binOp, ptr, val, ordering);
+# return success();
+# }
+# case llvm::Instruction::AtomicCmpXchg: {
+# auto *cmpXchgInst = cast<llvm::AtomicCmpXchgInst>(inst);
+# Value ptr = processValue(cmpXchgInst->getPointerOperand());
+# Value cmpVal = processValue(cmpXchgInst->getCompareOperand());
+# Value newVal = processValue(cmpXchgInst->getNewValOperand());
+# if (!ptr || !cmpVal || !newVal)
+# return failure();
+
+# LLVM::AtomicOrdering ordering =
+# getLLVMAtomicOrdering(cmpXchgInst->getSuccessOrdering());
+# LLVM::AtomicOrdering failOrdering =
+# getLLVMAtomicOrdering(cmpXchgInst->getFailureOrdering());
+
+# Type type = processType(inst->getType());
+# if (!type)
+# return failure();
+
+# instMap[inst] = b.create<AtomicCmpXchgOp>(loc, type, ptr, cmpVal, newVal,
+# ordering, failOrdering);
+# return success();
+# }
+# case llvm::Instruction::GetElementPtr: {
+# // FIXME: Support inbounds GEPs.
+# llvm::GetElementPtrInst *gep = cast<llvm::GetElementPtrInst>(inst);
+# Value basePtr = processValue(gep->getOperand(0));
+# Type sourceElementType = processType(gep->getSourceElementType());
+
+# // Treat every indices as dynamic since GEPOp::build will refine those
+# // indices into static attributes later. One small downside of this
+# // approach is that many unused `llvm.mlir.constant` would be emitted
+# // at first place.
+# SmallVector<GEPArg> indices;
+# for (llvm::Value *operand : llvm::drop_begin(gep->operand_values())) {
+# Value val = processValue(operand);
+# if (!val)
+# return failure();
+# indices.push_back(val);
+# }
+
+# Type type = processType(inst->getType());
+# if (!type)
+# return failure();
+# instMap[inst] =
+# b.create<GEPOp>(loc, type, sourceElementType, basePtr, indices);
+# return success();
+# }
+# case llvm::Instruction::InsertValue: {
+# auto *ivInst = cast<llvm::InsertValueInst>(inst);
+# Value inserted = processValue(ivInst->getInsertedValueOperand());
+# if (!inserted)
+# return failure();
+# Value aggOperand = processValue(ivInst->getAggregateOperand());
+# if (!aggOperand)
+# return failure();
+
+# SmallVector<int64_t> indices;
+# llvm::append_range(indices, ivInst->getIndices());
+# instMap[inst] = b.create<InsertValueOp>(loc, aggOperand, inserted, indices);
+# return success();
+# }
+# case llvm::Instruction::ExtractValue: {
+# auto *evInst = cast<llvm::ExtractValueInst>(inst);
+# Value aggOperand = processValue(evInst->getAggregateOperand());
+# if (!aggOperand)
+# return failure();
+
+# Type type = processType(inst->getType());
+# if (!type)
+# return failure();
+
+# SmallVector<int64_t> indices;
+# llvm::append_range(indices, evInst->getIndices());
+# instMap[inst] = b.create<ExtractValueOp>(loc, aggOperand, indices);
+# return success();
+# }
+# case llvm::Instruction::ShuffleVector: {
+# auto *svInst = cast<llvm::ShuffleVectorInst>(inst);
+# Value vec1 = processValue(svInst->getOperand(0));
+# if (!vec1)
+# return failure();
+# Value vec2 = processValue(svInst->getOperand(1));
+# if (!vec2)
+# return failure();
+
+# SmallVector<int32_t> mask(svInst->getShuffleMask());
+# instMap[inst] = b.create<ShuffleVectorOp>(loc, vec1, vec2, mask);
+# return success();
+# }
+# }
+# }
+
+# FlatSymbolRefAttr Importer::getPersonalityAsAttr(llvm::Function *f) {
+# if (!f->hasPersonalityFn())
+# return nullptr;
+
+# llvm::Constant *pf = f->getPersonalityFn();
+
+# // If it directly has a name, we can use it.
+# if (pf->hasName())
+# return SymbolRefAttr::get(b.getContext(), pf->getName());
+
+# // If it doesn't have a name, currently, only function pointers that are
+# // bitcast to i8* are parsed.
+# if (auto *ce = dyn_cast<llvm::ConstantExpr>(pf)) {
+# if (ce->getOpcode() == llvm::Instruction::BitCast &&
+# ce->getType() == llvm::Type::getInt8PtrTy(f->getContext())) {
+# if (auto *func = dyn_cast<llvm::Function>(ce->getOperand(0)))
+# return SymbolRefAttr::get(b.getContext(), func->getName());
+# }
+# }
+# return FlatSymbolRefAttr();
+# }
+
+# void Importer::processFunctionAttributes(llvm::Function *func,
+# LLVMFuncOp funcOp) {
+# auto addNamedUnitAttr = [&](StringRef name) {
+# return funcOp->setAttr(name, UnitAttr::get(context));
+# };
+# if (func->hasFnAttribute(llvm::Attribute::ReadNone))
+# addNamedUnitAttr(LLVMDialect::getReadnoneAttrName());
+# }
+
+# LogicalResult Importer::processFunction(llvm::Function *f) {
+# blocks.clear();
+# instMap.clear();
+# unknownInstMap.clear();
+
+# auto functionType =
+# processType(f->getFunctionType()).dyn_cast<LLVMFunctionType>();
+# if (!functionType)
+# return failure();
+
+# if (f->isIntrinsic()) {
+# StringRef opName = lookupOperationNameFromIntrinsicID(f->getIntrinsicID());
+# // Skip the intrinsic decleration if we could found a corresponding op.
+# if (!opName.empty())
+# return success();
+# }
+
+# bool dsoLocal = f->hasLocalLinkage();
+# CConv cconv = convertCConvFromLLVM(f->getCallingConv());
+
+# b.setInsertionPoint(module.getBody(), getFuncInsertPt());
+# LLVMFuncOp fop = b.create<LLVMFuncOp>(
+# UnknownLoc::get(context), f->getName(), functionType,
+# convertLinkageFromLLVM(f->getLinkage()), dsoLocal, cconv);
+
+# for (const auto &arg : llvm::enumerate(functionType.getParams())) {
+# llvm::SmallVector<NamedAttribute, 1> argAttrs;
+# if (auto *type = f->getParamByValType(arg.index())) {
+# auto mlirType = processType(type);
+# argAttrs.push_back(
+# NamedAttribute(b.getStringAttr(LLVMDialect::getByValAttrName()),
+# TypeAttr::get(mlirType)));
+# }
+# if (auto *type = f->getParamByRefType(arg.index())) {
+# auto mlirType = processType(type);
+# argAttrs.push_back(
+# NamedAttribute(b.getStringAttr(LLVMDialect::getByRefAttrName()),
+# TypeAttr::get(mlirType)));
+# }
+# if (auto *type = f->getParamStructRetType(arg.index())) {
+# auto mlirType = processType(type);
+# argAttrs.push_back(
+# NamedAttribute(b.getStringAttr(LLVMDialect::getStructRetAttrName()),
+# TypeAttr::get(mlirType)));
+# }
+# if (auto *type = f->getParamInAllocaType(arg.index())) {
+# auto mlirType = processType(type);
+# argAttrs.push_back(
+# NamedAttribute(b.getStringAttr(LLVMDialect::getInAllocaAttrName()),
+# TypeAttr::get(mlirType)));
+# }
+
+# fop.setArgAttrs(arg.index(), argAttrs);
+# }
+
+# if (FlatSymbolRefAttr personality = getPersonalityAsAttr(f))
+# fop->setAttr(b.getStringAttr("personality"), personality);
+# else if (f->hasPersonalityFn())
+# emitWarning(UnknownLoc::get(context),
+# "could not deduce personality, skipping it");
+
+# if (f->hasGC())
+# fop.setGarbageCollectorAttr(b.getStringAttr(f->getGC()));
+
+# // Handle Function attributes.
+# processFunctionAttributes(f, fop);
+
+# if (f->isDeclaration())
+# return success();
+
+# // Eagerly create all blocks.
+# SmallVector<Block *, 4> blockList;
+# for (llvm::BasicBlock &bb : *f) {
+# blockList.push_back(b.createBlock(&fop.getBody(), fop.getBody().end()));
+# blocks[&bb] = blockList.back();
+# }
+# currentEntryBlock = blockList[0];
+
+# // Add function arguments to the entry block.
+# for (const auto &kv : llvm::enumerate(f->args())) {
+# instMap[&kv.value()] = blockList[0]->addArgument(
+# functionType.getParamType(kv.index()), fop.getLoc());
+# }
+
+# for (auto bbs : llvm::zip(*f, blockList)) {
+# if (failed(processBasicBlock(&std::get<0>(bbs), std::get<1>(bbs))))
+# return failure();
+# }
+
+# // Now that all instructions are guaranteed to have been visited, ensure
+# // any unknown uses we encountered are remapped.
+# for (auto &llvmAndUnknown : unknownInstMap) {
+# assert(instMap.count(llvmAndUnknown.first));
+# Value newValue = instMap[llvmAndUnknown.first];
+# Value oldValue = llvmAndUnknown.second->getResult(0);
+# oldValue.replaceAllUsesWith(newValue);
+# llvmAndUnknown.second->erase();
+# }
+# return success();
+# }
+
+# LogicalResult Importer::processBasicBlock(llvm::BasicBlock *bb, Block *block) {
+# b.setInsertionPointToStart(block);
+# for (llvm::Instruction &inst : *bb) {
+# if (failed(processInstruction(&inst)))
+# return failure();
+# }
+# return success();
+# }
+
+# OwningOpRef<ModuleOp>
+# mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
+# MLIRContext *context) {
+# context->loadDialect<LLVMDialect>();
+# context->loadDialect<DLTIDialect>();
+# OwningOpRef<ModuleOp> module(ModuleOp::create(
+# FileLineColLoc::get(context, "", /*line=*/0, /*column=*/0)));
+
+# DataLayoutSpecInterface dlSpec =
+# translateDataLayout(llvmModule->getDataLayout(), context);
+# if (!dlSpec) {
+# emitError(UnknownLoc::get(context), "can't translate data layout");
+# return {};
+# }
+
+# module.get()->setAttr(DLTIDialect::kDataLayoutAttrName, dlSpec);
+
+# Importer deserializer(context, module.get());
+# for (llvm::GlobalVariable &gv : llvmModule->globals()) {
+# if (!deserializer.processGlobal(&gv))
+# return {};
+# }
+# for (llvm::Function &f : llvmModule->functions()) {
+# if (failed(deserializer.processFunction(&f)))
+# return {};
+# }
+
+# return module;
+# }
+
+ // Deserializes the LLVM bitcode stored in `input` into an MLIR module in the
+ // LLVM dialect.
+ OwningOpRef<ModuleOp> translateLLVMIRToModule(llvm::SourceMgr &sourceMgr,
+ MLIRContext *context) {
+ llvm::SMDiagnostic err;
+ llvm::LLVMContext llvmContext;
+ std::unique_ptr<llvm::Module> llvmModule = llvm::parseIR(
+ *sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID()), err, llvmContext);
+ if (!llvmModule) {
+ std::string errStr;
+ llvm::raw_string_ostream errStream(errStr);
+ err.print(/*ProgName=*/"", errStream);
+ emitError(UnknownLoc::get(context)) << errStream.str();
+ return {};
+ }
+ return translateLLVMIRToModule(std::move(llvmModule), context);
+ }
+
+ namespace mlir {
+ void registerFromLLVMIRTranslation() {
+ TranslateToMLIRRegistration fromLLVM(
+- "import-llvm", [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
++ "import-llvm", "from llvm to mlir",
++ [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
+ return ::translateLLVMIRToModule(sourceMgr, context);
+ });
+ }
+ } // namespace mlir
+diff --git a/mlir/lib/Target/LLVMIR/ConvertToLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertToLLVMIR.cpp
+index 70f86d2..1ae7b83 100644
+--- a/mlir/lib/Target/LLVMIR/ConvertToLLVMIR.cpp
++++ b/mlir/lib/Target/LLVMIR/ConvertToLLVMIR.cpp
+@@ -1,42 +1,42 @@
+ //===- ConvertToLLVMIR.cpp - MLIR to LLVM IR conversion -------------------===//
+ //
+ // 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 file implements a translation between the MLIR LLVM dialect and LLVM IR.
+ //
+ //===----------------------------------------------------------------------===//
+
+ #include "mlir/Dialect/DLTI/DLTI.h"
+ #include "mlir/Dialect/Func/IR/FuncOps.h"
+ #include "mlir/IR/BuiltinOps.h"
+ #include "mlir/Target/LLVMIR/Dialect/All.h"
+ #include "mlir/Target/LLVMIR/Export.h"
+ #include "mlir/Tools/mlir-translate/Translation.h"
+ #include "llvm/IR/LLVMContext.h"
+ #include "llvm/IR/Module.h"
+
+ using namespace mlir;
+
+ namespace mlir {
+ void registerToLLVMIRTranslation() {
+ TranslateFromMLIRRegistration registration(
+- "mlir-to-llvmir",
++ "mlir-to-llvmir", "translate mlir to llvmir",
+ [](ModuleOp module, raw_ostream &output) {
+ llvm::LLVMContext llvmContext;
+ auto llvmModule = translateModuleToLLVMIR(module, llvmContext);
+ if (!llvmModule)
+ return failure();
+
+ llvmModule->print(output, nullptr);
+ return success();
+ },
+ [](DialectRegistry ®istry) {
+ registry.insert<DLTIDialect, func::FuncDialect>();
+ registerAllToLLVMIRTranslations(registry);
+ });
+ }
+ } // namespace mlir
+diff --git a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp
+index 664b796..d24e578 100644
+--- a/mlir/lib/Target/SPIRV/TranslateRegistration.cpp
++++ b/mlir/lib/Target/SPIRV/TranslateRegistration.cpp
+@@ -1,184 +1,184 @@
+ //===- TranslateRegistration.cpp - hooks to mlir-translate ----------------===//
+ //
+ // 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 file implements a translation from SPIR-V binary module to MLIR SPIR-V
+ // ModuleOp.
+ //
+ //===----------------------------------------------------------------------===//
+
+ #include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"
+ #include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"
+ #include "mlir/IR/Builders.h"
+ #include "mlir/IR/BuiltinOps.h"
+ #include "mlir/IR/Dialect.h"
+ #include "mlir/IR/Verifier.h"
+ #include "mlir/Parser/Parser.h"
+ #include "mlir/Support/FileUtilities.h"
+ #include "mlir/Target/SPIRV/Deserialization.h"
+ #include "mlir/Target/SPIRV/Serialization.h"
+ #include "mlir/Tools/mlir-translate/Translation.h"
+ #include "llvm/ADT/StringRef.h"
+ #include "llvm/Support/MemoryBuffer.h"
+ #include "llvm/Support/SMLoc.h"
+ #include "llvm/Support/SourceMgr.h"
+ #include "llvm/Support/ToolOutputFile.h"
+
+ using namespace mlir;
+
+ //===----------------------------------------------------------------------===//
+ // Deserialization registration
+ //===----------------------------------------------------------------------===//
+
+ // Deserializes the SPIR-V binary module stored in the file named as
+ // `inputFilename` and returns a module containing the SPIR-V module.
+ static OwningOpRef<ModuleOp> deserializeModule(const llvm::MemoryBuffer *input,
+ MLIRContext *context) {
+ context->loadDialect<spirv::SPIRVDialect>();
+
+ // Make sure the input stream can be treated as a stream of SPIR-V words
+ auto *start = input->getBufferStart();
+ auto size = input->getBufferSize();
+ if (size % sizeof(uint32_t) != 0) {
+ emitError(UnknownLoc::get(context))
+ << "SPIR-V binary module must contain integral number of 32-bit words";
+ return {};
+ }
+
+ auto binary = llvm::makeArrayRef(reinterpret_cast<const uint32_t *>(start),
+ size / sizeof(uint32_t));
+
+ OwningOpRef<spirv::ModuleOp> spirvModule =
+ spirv::deserialize(binary, context);
+ if (!spirvModule)
+ return {};
+
+ OwningOpRef<ModuleOp> module(ModuleOp::create(FileLineColLoc::get(
+ context, input->getBufferIdentifier(), /*line=*/0, /*column=*/0)));
+ module->getBody()->push_front(spirvModule.release());
+
+ return module;
+ }
+
+ namespace mlir {
+ void registerFromSPIRVTranslation() {
+ TranslateToMLIRRegistration fromBinary(
+- "deserialize-spirv",
++ "deserialize-spirv", "deserializes the SPIR-V module",
+ [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
+ assert(sourceMgr.getNumBuffers() == 1 && "expected one buffer");
+ return deserializeModule(
+ sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID()), context);
+ });
+ }
+ } // namespace mlir
+
+ //===----------------------------------------------------------------------===//
+ // Serialization registration
+ //===----------------------------------------------------------------------===//
+
+ static LogicalResult serializeModule(ModuleOp module, raw_ostream &output) {
+ if (!module)
+ return failure();
+
+ SmallVector<uint32_t, 0> binary;
+
+ SmallVector<spirv::ModuleOp, 1> spirvModules;
+ module.walk([&](spirv::ModuleOp op) { spirvModules.push_back(op); });
+
+ if (spirvModules.empty())
+ return module.emitError("found no 'spirv.module' op");
+
+ if (spirvModules.size() != 1)
+ return module.emitError("found more than one 'spirv.module' op");
+
+ if (failed(spirv::serialize(spirvModules[0], binary)))
+ return failure();
+
+ output.write(reinterpret_cast<char *>(binary.data()),
+ binary.size() * sizeof(uint32_t));
+
+ return mlir::success();
+ }
+
+ namespace mlir {
+ void registerToSPIRVTranslation() {
+ TranslateFromMLIRRegistration toBinary(
+- "serialize-spirv",
++ "serialize-spirv", "serialize SPIR-V dialect",
+ [](ModuleOp module, raw_ostream &output) {
+ return serializeModule(module, output);
+ },
+ [](DialectRegistry ®istry) {
+ registry.insert<spirv::SPIRVDialect>();
+ });
+ }
+ } // namespace mlir
+
+ //===----------------------------------------------------------------------===//
+ // Round-trip registration
+ //===----------------------------------------------------------------------===//
+
+ static LogicalResult roundTripModule(ModuleOp srcModule, bool emitDebugInfo,
+ raw_ostream &output) {
+ SmallVector<uint32_t, 0> binary;
+ MLIRContext *context = srcModule.getContext();
+ auto spirvModules = srcModule.getOps<spirv::ModuleOp>();
+
+ if (spirvModules.begin() == spirvModules.end())
+ return srcModule.emitError("found no 'spirv.module' op");
+
+ if (std::next(spirvModules.begin()) != spirvModules.end())
+ return srcModule.emitError("found more than one 'spirv.module' op");
+
+ spirv::SerializationOptions options;
+ options.emitDebugInfo = emitDebugInfo;
+ if (failed(spirv::serialize(*spirvModules.begin(), binary, options)))
+ return failure();
+
+ MLIRContext deserializationContext(context->getDialectRegistry());
+ // TODO: we should only load the required dialects instead of all dialects.
+ deserializationContext.loadAllAvailableDialects();
+ // Then deserialize to get back a SPIR-V module.
+ OwningOpRef<spirv::ModuleOp> spirvModule =
+ spirv::deserialize(binary, &deserializationContext);
+ if (!spirvModule)
+ return failure();
+
+ // Wrap around in a new MLIR module.
+ OwningOpRef<ModuleOp> dstModule(ModuleOp::create(
+ FileLineColLoc::get(&deserializationContext,
+ /*filename=*/"", /*line=*/0, /*column=*/0)));
+ dstModule->getBody()->push_front(spirvModule.release());
+ if (failed(verify(*dstModule)))
+ return failure();
+ dstModule->print(output);
+
+ return mlir::success();
+ }
+
+ namespace mlir {
+ void registerTestRoundtripSPIRV() {
+ TranslateFromMLIRRegistration roundtrip(
+- "test-spirv-roundtrip",
++ "test-spirv-roundtrip", "test roundtrip in SPIR-V dialect",
+ [](ModuleOp module, raw_ostream &output) {
+ return roundTripModule(module, /*emitDebugInfo=*/false, output);
+ },
+ [](DialectRegistry ®istry) {
+ registry.insert<spirv::SPIRVDialect>();
+ });
+ }
+
+ void registerTestRoundtripDebugSPIRV() {
+ TranslateFromMLIRRegistration roundtrip(
+- "test-spirv-roundtrip-debug",
++ "test-spirv-roundtrip-debug", "test roundtrip debug in SPIR-V",
+ [](ModuleOp module, raw_ostream &output) {
+ return roundTripModule(module, /*emitDebugInfo=*/true, output);
+ },
+ [](DialectRegistry ®istry) {
+ registry.insert<spirv::SPIRVDialect>();
+ });
+ }
+ } // namespace mlir
+diff --git a/mlir/lib/Tools/mlir-translate/Translation.cpp b/mlir/lib/Tools/mlir-translate/Translation.cpp
+index 50b8547..7517ae0 100644
+--- a/mlir/lib/Tools/mlir-translate/Translation.cpp
++++ b/mlir/lib/Tools/mlir-translate/Translation.cpp
+@@ -1,126 +1,140 @@
+ //===- Translation.cpp - Translation registry -----------------------------===//
+ //
+ // 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
+ //
+ //===----------------------------------------------------------------------===//
+ //
+ // Definitions of the translation registry.
+ //
+ //===----------------------------------------------------------------------===//
+
+ #include "mlir/Tools/mlir-translate/Translation.h"
+ #include "mlir/IR/AsmState.h"
+ #include "mlir/IR/BuiltinOps.h"
+ #include "mlir/IR/Dialect.h"
+ #include "mlir/IR/Verifier.h"
+ #include "mlir/Parser/Parser.h"
+ #include "llvm/Support/SourceMgr.h"
+
+ using namespace mlir;
+
+ //===----------------------------------------------------------------------===//
+ // Translation Registry
+ //===----------------------------------------------------------------------===//
+
++struct TranslationBundle {
++ TranslateFunction translateFunction;
++ StringRef translateDescription;
++};
++
+ /// Get the mutable static map between registered file-to-file MLIR translations
+-/// and the TranslateFunctions that perform those translations.
+-static llvm::StringMap<TranslateFunction> &getTranslationRegistry() {
+- static llvm::StringMap<TranslateFunction> translationRegistry;
+- return translationRegistry;
++/// and TranslateFunctions with its description that perform those translations.
++static llvm::StringMap<TranslationBundle> &getTranslationRegistry() {
++ static llvm::StringMap<TranslationBundle> translationBundle;
++ return translationBundle;
+ }
+
+ /// Register the given translation.
+-static void registerTranslation(StringRef name,
++static void registerTranslation(StringRef name, StringRef description,
+ const TranslateFunction &function) {
+ auto &translationRegistry = getTranslationRegistry();
+ if (translationRegistry.find(name) != translationRegistry.end())
+ llvm::report_fatal_error(
+ "Attempting to overwrite an existing <file-to-file> function");
+ assert(function &&
+ "Attempting to register an empty translate <file-to-file> function");
+- translationRegistry[name] = function;
++ translationRegistry[name].translateFunction = function;
++ translationRegistry[name].translateDescription = description;
+ }
+
+ TranslateRegistration::TranslateRegistration(
+- StringRef name, const TranslateFunction &function) {
+- registerTranslation(name, function);
++ StringRef name, StringRef description, const TranslateFunction &function) {
++ registerTranslation(name, description, function);
+ }
+
+ //===----------------------------------------------------------------------===//
+ // Translation to MLIR
+ //===----------------------------------------------------------------------===//
+
+ // Puts `function` into the to-MLIR translation registry unless there is already
+ // a function registered for the same name.
+ static void registerTranslateToMLIRFunction(
+- StringRef name, const TranslateSourceMgrToMLIRFunction &function) {
++ StringRef name, StringRef description,
++ const TranslateSourceMgrToMLIRFunction &function) {
+ auto wrappedFn = [function](llvm::SourceMgr &sourceMgr, raw_ostream &output,
+ MLIRContext *context) {
+ OwningOpRef<ModuleOp> module = function(sourceMgr, context);
+ if (!module || failed(verify(*module)))
+ return failure();
+ module->print(output);
+ return success();
+ };
+- registerTranslation(name, wrappedFn);
++ registerTranslation(name, description, wrappedFn);
+ }
+
+ TranslateToMLIRRegistration::TranslateToMLIRRegistration(
+- StringRef name, const TranslateSourceMgrToMLIRFunction &function) {
+- registerTranslateToMLIRFunction(name, function);
++ StringRef name, StringRef description,
++ const TranslateSourceMgrToMLIRFunction &function) {
++ registerTranslateToMLIRFunction(name, description, function);
+ }
+-
+ /// Wraps `function` with a lambda that extracts a StringRef from a source
+ /// manager and registers the wrapper lambda as a to-MLIR conversion.
+ TranslateToMLIRRegistration::TranslateToMLIRRegistration(
+- StringRef name, const TranslateStringRefToMLIRFunction &function) {
++ StringRef name, StringRef description,
++ const TranslateStringRefToMLIRFunction &function) {
+ registerTranslateToMLIRFunction(
+- name, [function](llvm::SourceMgr &sourceMgr, MLIRContext *ctx) {
++ name, description,
++ [function](llvm::SourceMgr &sourceMgr, MLIRContext *ctx) {
+ const llvm::MemoryBuffer *buffer =
+ sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
+ return function(buffer->getBuffer(), ctx);
+ });
+ }
+
+ //===----------------------------------------------------------------------===//
+ // Translation from MLIR
+ //===----------------------------------------------------------------------===//
+
+ TranslateFromMLIRRegistration::TranslateFromMLIRRegistration(
+- StringRef name, const TranslateFromMLIRFunction &function,
++ StringRef name, StringRef description,
++ const TranslateFromMLIRFunction &function,
+ const std::function<void(DialectRegistry &)> &dialectRegistration) {
+- registerTranslation(name, [function, dialectRegistration](
+- llvm::SourceMgr &sourceMgr, raw_ostream &output,
+- MLIRContext *context) {
+- DialectRegistry registry;
+- dialectRegistration(registry);
+- context->appendDialectRegistry(registry);
+- auto module = parseSourceFile<ModuleOp>(sourceMgr, context);
+- if (!module || failed(verify(*module)))
+- return failure();
+- return function(module.get(), output);
+- });
++ registerTranslation(name, description,
++ [function, dialectRegistration](
++ llvm::SourceMgr &sourceMgr, raw_ostream &output,
++ MLIRContext *context) {
++ DialectRegistry registry;
++ dialectRegistration(registry);
++ context->appendDialectRegistry(registry);
++ auto module =
++ parseSourceFile<ModuleOp>(sourceMgr, context);
++ if (!module || failed(verify(*module)))
++ return failure();
++ return function(module.get(), output);
++ });
+ }
+
+ //===----------------------------------------------------------------------===//
+ // Translation Parser
+ //===----------------------------------------------------------------------===//
+
+ TranslationParser::TranslationParser(llvm::cl::Option &opt)
+ : llvm::cl::parser<const TranslateFunction *>(opt) {
+- for (const auto &kv : getTranslationRegistry())
+- addLiteralOption(kv.first(), &kv.second, kv.first());
++ for (const auto &kv : getTranslationRegistry()) {
++ addLiteralOption(kv.first(), &kv.second.translateFunction,
++ kv.second.translateDescription);
++ }
+ }
+
+ void TranslationParser::printOptionInfo(const llvm::cl::Option &o,
+ size_t globalWidth) const {
+ TranslationParser *tp = const_cast<TranslationParser *>(this);
+ llvm::array_pod_sort(tp->Values.begin(), tp->Values.end(),
+ [](const TranslationParser::OptionInfo *lhs,
+ const TranslationParser::OptionInfo *rhs) {
+ return lhs->Name.compare(rhs->Name);
+ });
+ llvm::cl::parser<const TranslateFunction *>::printOptionInfo(o, globalWidth);
+ }