[MLIR][LLVM] Add import-structs-as-literals flag to the IR import (#140098)

This commit introduces the `import-structs-as-literals` option to the
MLIR import. This ensures that all struct types are imported as literal
structs, even when they are named in LLVM IR.
This commit is contained in:
Christian Ulmann
2025-05-16 08:43:06 +02:00
committed by GitHub
parent a83668c3dd
commit 1001d6a6cd
7 changed files with 48 additions and 16 deletions

View File

@@ -46,10 +46,14 @@ class ModuleOp;
/// registered an explicit intrinsic operation. Warning: passes that rely on
/// matching explicit intrinsic operations may not work properly if this flag is
/// enabled.
/// The `importStructsAsLiterals` flag (default off) ensures that all structs
/// are imported as literal structs, even when they are named in the LLVM
/// module.
OwningOpRef<ModuleOp> translateLLVMIRToModule(
std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
bool emitExpensiveWarnings = true, bool dropDICompositeTypeElements = false,
bool loadAllDialects = true, bool preferUnregisteredIntrinsics = false);
bool loadAllDialects = true, bool preferUnregisteredIntrinsics = false,
bool importStructsAsLiterals = false);
/// Translate the given LLVM data layout into an MLIR equivalent using the DLTI
/// dialect.

View File

@@ -48,7 +48,7 @@ class ModuleImport {
public:
ModuleImport(ModuleOp mlirModule, std::unique_ptr<llvm::Module> llvmModule,
bool emitExpensiveWarnings, bool importEmptyDICompositeTypes,
bool preferUnregisteredIntrinsics);
bool preferUnregisteredIntrinsics, bool importStructsAsLiterals);
/// Calls the LLVMImportInterface initialization that queries the registered
/// dialect interfaces for the supported LLVM IR intrinsics and metadata kinds

View File

@@ -17,8 +17,6 @@
#include <memory>
namespace llvm {
class DataLayout;
class LLVMContext;
class Type;
} // namespace llvm
@@ -38,7 +36,8 @@ class TypeFromLLVMIRTranslatorImpl;
/// reused across translations.
class TypeFromLLVMIRTranslator {
public:
TypeFromLLVMIRTranslator(MLIRContext &context);
TypeFromLLVMIRTranslator(MLIRContext &context,
bool importStructsAsLiterals = false);
~TypeFromLLVMIRTranslator();
/// Translates the given LLVM IR type to the MLIR LLVM dialect.

View File

@@ -44,6 +44,12 @@ void registerFromLLVMIRTranslation() {
"of using dialect supported intrinsics"),
llvm::cl::init(false));
static llvm::cl::opt<bool> importStructsAsLiterals(
"import-structs-as-literals",
llvm::cl::desc("Controls if structs should be imported as literal "
"structs, i.e., nameless structs."),
llvm::cl::init(false));
TranslateToMLIRRegistration registration(
"import-llvm", "Translate LLVMIR to MLIR",
[](llvm::SourceMgr &sourceMgr,
@@ -70,7 +76,7 @@ void registerFromLLVMIRTranslation() {
return translateLLVMIRToModule(
std::move(llvmModule), context, emitExpensiveWarnings,
dropDICompositeTypeElements, /*loadAllDialects=*/true,
preferUnregisteredIntrinsics);
preferUnregisteredIntrinsics, importStructsAsLiterals);
},
[](DialectRegistry &registry) {
// Register the DLTI dialect used to express the data layout

View File

@@ -164,11 +164,12 @@ ModuleImport::ModuleImport(ModuleOp mlirModule,
std::unique_ptr<llvm::Module> llvmModule,
bool emitExpensiveWarnings,
bool importEmptyDICompositeTypes,
bool preferUnregisteredIntrinsics)
bool preferUnregisteredIntrinsics,
bool importStructsAsLiterals)
: builder(mlirModule->getContext()), context(mlirModule->getContext()),
mlirModule(mlirModule), llvmModule(std::move(llvmModule)),
iface(mlirModule->getContext()),
typeTranslator(*mlirModule->getContext()),
typeTranslator(*mlirModule->getContext(), importStructsAsLiterals),
debugImporter(std::make_unique<DebugImporter>(
mlirModule, importEmptyDICompositeTypes)),
loopAnnotationImporter(
@@ -3118,7 +3119,8 @@ ModuleImport::translateDereferenceableAttr(const llvm::MDNode *node,
OwningOpRef<ModuleOp> mlir::translateLLVMIRToModule(
std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
bool emitExpensiveWarnings, bool dropDICompositeTypeElements,
bool loadAllDialects, bool preferUnregisteredIntrinsics) {
bool loadAllDialects, bool preferUnregisteredIntrinsics,
bool importStructsAsLiterals) {
// Preload all registered dialects to allow the import to iterate the
// registered LLVMImportDialectInterface implementations and query the
// supported LLVM IR constructs before starting the translation. Assumes the
@@ -3136,7 +3138,8 @@ OwningOpRef<ModuleOp> mlir::translateLLVMIRToModule(
ModuleImport moduleImport(module.get(), std::move(llvmModule),
emitExpensiveWarnings, dropDICompositeTypeElements,
preferUnregisteredIntrinsics);
preferUnregisteredIntrinsics,
importStructsAsLiterals);
if (failed(moduleImport.initializeImportInterface()))
return {};
if (failed(moduleImport.convertDataLayout()))

View File

@@ -12,7 +12,6 @@
#include "mlir/IR/MLIRContext.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Type.h"
@@ -25,7 +24,9 @@ namespace detail {
class TypeFromLLVMIRTranslatorImpl {
public:
/// Constructs a class creating types in the given MLIR context.
TypeFromLLVMIRTranslatorImpl(MLIRContext &context) : context(context) {}
TypeFromLLVMIRTranslatorImpl(MLIRContext &context,
bool importStructsAsLiterals)
: context(context), importStructsAsLiterals(importStructsAsLiterals) {}
/// Translates the given type.
Type translateType(llvm::Type *type) {
@@ -103,7 +104,7 @@ private:
/// Translates the given structure type.
Type translate(llvm::StructType *type) {
SmallVector<Type, 8> subtypes;
if (type->isLiteral()) {
if (type->isLiteral() || importStructsAsLiterals) {
translateTypes(type->subtypes(), subtypes);
return LLVM::LLVMStructType::getLiteral(&context, subtypes,
type->isPacked());
@@ -132,7 +133,7 @@ private:
Type translate(llvm::ScalableVectorType *type) {
return VectorType::get(type->getMinNumElements(),
translateType(type->getElementType()),
/*scalable=*/true);
/*scalableDims=*/true);
}
/// Translates the given target extension type.
@@ -158,14 +159,20 @@ private:
/// The context in which MLIR types are created.
MLIRContext &context;
/// Controls if structs should be imported as literal structs, i.e., nameless
/// structs.
bool importStructsAsLiterals;
};
} // namespace detail
} // namespace LLVM
} // namespace mlir
LLVM::TypeFromLLVMIRTranslator::TypeFromLLVMIRTranslator(MLIRContext &context)
: impl(new detail::TypeFromLLVMIRTranslatorImpl(context)) {}
LLVM::TypeFromLLVMIRTranslator::TypeFromLLVMIRTranslator(
MLIRContext &context, bool importStructsAsLiterals)
: impl(std::make_unique<detail::TypeFromLLVMIRTranslatorImpl>(
context, importStructsAsLiterals)) {}
LLVM::TypeFromLLVMIRTranslator::~TypeFromLLVMIRTranslator() = default;

View File

@@ -0,0 +1,13 @@
; RUN: mlir-translate -import-llvm -import-structs-as-literals -split-input-file %s | FileCheck %s
%named = type {i32, i8, i16, i32}
; CHECK: @named
; CHECK-SAME: !llvm.struct<(i32, i8, i16, i32)>
@named = external global %named
%opaque = type opaque
; CHECK: @opaque
; CHECK-SAME: !llvm.struct<()>
@opaque = external global %opaque