[Mlir-commits] [mlir] [MLIR][LLVM] Add bytecode support for several attributes (PR #162577)
Bruno Cardoso Lopes
llvmlistbot at llvm.org
Fri Oct 10 12:03:59 PDT 2025
https://github.com/bcardosolopes updated https://github.com/llvm/llvm-project/pull/162577
>From bce08030595c63a2afe5a438079d6d15d2c2232e Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Wed, 8 Oct 2025 17:25:08 -0700
Subject: [PATCH 1/4] [MLIR][LLVM] Add bytecode support for several attributes
---
.../mlir/Dialect/LLVMIR/CMakeLists.txt | 4 +
.../Dialect/LLVMIR/LLVMDialectBytecode.td | 357 ++++++++++++++++++
mlir/lib/Dialect/LLVMIR/CMakeLists.txt | 2 +
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 3 +
.../Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp | 155 ++++++++
.../Dialect/LLVMIR/IR/LLVMDialectBytecode.h | 27 ++
mlir/test/Dialect/LLVMIR/bytecode.mlir | 69 ++++
mlir/test/Dialect/LLVMIR/debuginfo.mlir | 1 +
mlir/test/Dialect/LLVMIR/roundtrip.mlir | 5 +-
9 files changed, 621 insertions(+), 2 deletions(-)
create mode 100644 mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
create mode 100644 mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp
create mode 100644 mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.h
create mode 100644 mlir/test/Dialect/LLVMIR/bytecode.mlir
diff --git a/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt b/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
index 8d9474bf37894..c301e0b40e8fe 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
@@ -48,6 +48,10 @@ mlir_tablegen(LLVMIntrinsicFromLLVMIRConversions.inc -gen-intr-from-llvmir-conve
mlir_tablegen(LLVMConvertibleLLVMIRIntrinsics.inc -gen-convertible-llvmir-intrinsics)
add_mlir_dialect_tablegen_target(MLIRLLVMIntrinsicConversionsIncGen)
+set(LLVM_TARGET_DEFINITIONS LLVMDialectBytecode.td)
+mlir_tablegen(LLVMDialectBytecode.cpp.inc -gen-bytecode -bytecode-dialect="LLVM")
+add_public_tablegen_target(MLIRLLVMDialectBytecodeIncGen)
+
set(LLVM_TARGET_DEFINITIONS BasicPtxBuilderInterface.td)
mlir_tablegen(BasicPtxBuilderInterface.h.inc -gen-op-interface-decls)
mlir_tablegen(BasicPtxBuilderInterface.cpp.inc -gen-op-interface-defs)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
new file mode 100644
index 0000000000000..2474dece3f7c3
--- /dev/null
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
@@ -0,0 +1,357 @@
+//===-- LLVMDialectBytecode.td - LLVM bytecode defs --------*- tablegen -*-===//
+//
+// 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 is the LLVM bytecode reader/writer definition file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DIALECT_BYTECODE
+#define LLVM_DIALECT_BYTECODE
+
+include "mlir/IR/BytecodeBase.td"
+
+//===----------------------------------------------------------------------===//
+// Bytecode classes for attributes and types.
+//===----------------------------------------------------------------------===//
+
+def String :
+ WithParser <"succeeded($_reader.readString($_var))",
+ WithBuilder<"$_args",
+ WithPrinter<"$_writer.writeOwnedString($_getter)",
+ WithType <"StringRef">>>>;
+
+class Attr<string type> : WithType<type, Attribute>;
+
+class OptionalAttribute<string type> :
+ WithParser <"succeeded($_reader.readOptionalAttribute($_var))",
+ WithPrinter<"$_writer.writeOptionalAttribute($_getter)",
+ WithType<type, Attribute>>>;
+
+class OptionalInt<string type> :
+ WithParser <"succeeded(readOptionalInt($_reader, $_var))",
+ WithPrinter<"writeOptionalInt($_writer, $_getter)",
+ WithType<"std::optional<" # type # ">", VarInt>>>;
+
+class OptionalArrayRef<string eltType> :
+ WithParser <"succeeded(readOptionalArrayRef<"
+ # eltType # ">($_reader, $_var))",
+ WithPrinter<"writeOptionalArrayRef<"
+ # eltType # ">($_writer, $_getter)",
+ WithType<"SmallVector<"
+ # eltType # ">", Attribute>>>;
+
+class EnumClassFlag<string flag, string getter> :
+ WithParser<"succeeded($_reader.readVarInt($_var))",
+ WithBuilder<"(" # flag # ")$_args",
+ WithPrinter<"$_writer.writeVarInt((uint64_t)$_name." # getter # ")",
+ WithType<"uint64_t", VarInt>>>>;
+
+//===----------------------------------------------------------------------===//
+// General notes
+// - For each attribute or type entry, the argument names should match
+// LLVMAttrDefs.td
+// - The mnemonics are either LLVM or builtin MLIR attributes and types, but
+// regular C++ types are also allowed to match builders and parsers.
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// AliasScopeAttr
+//===----------------------------------------------------------------------===//
+
+def AliasScopeAttr : DialectAttribute<(attr
+ Attr<"Attribute">:$id,
+ Attr<"AliasScopeDomainAttr">:$domain,
+ OptionalAttribute<"StringAttr">:$description
+)>;
+
+//===----------------------------------------------------------------------===//
+// DIBasicTypeAttr
+//===----------------------------------------------------------------------===//
+
+def DIBasicTypeAttr : DialectAttribute<(attr
+ VarInt:$tag,
+ String:$name,
+ VarInt:$sizeInBits,
+ VarInt:$encoding
+)>;
+
+//===----------------------------------------------------------------------===//
+// DIExpressionAttr, DIExpressionElemAttr
+//===----------------------------------------------------------------------===//
+
+def DIExpressionElemAttr : DialectAttribute<(attr
+ VarInt:$opcode,
+ OptionalArrayRef<"uint64_t">:$arguments
+)>;
+
+def DIExpressionAttr : DialectAttribute<(attr
+ OptionalArrayRef<"DIExpressionElemAttr">:$operations
+)>;
+
+//===----------------------------------------------------------------------===//
+// DIFileAttr
+//===----------------------------------------------------------------------===//
+
+def DIFileAttr : DialectAttribute<(attr
+ String:$name,
+ String:$directory
+)>;
+
+//===----------------------------------------------------------------------===//
+// DILocalVariableAttr
+//===----------------------------------------------------------------------===//
+
+def DILocalVariableAttr : DialectAttribute<(attr
+ Attr<"DIScopeAttr">:$scope, // Non-optional attribute
+ OptionalAttribute<"StringAttr">:$name,
+ OptionalAttribute<"DIFileAttr">:$file,
+ VarInt:$line,
+ VarInt:$arg,
+ VarInt:$alignInBits,
+ OptionalAttribute<"DITypeAttr">:$type,
+ EnumClassFlag<"DIFlags", "getFlags()">:$_rawflags,
+ LocalVar<"DIFlags", "(DIFlags)_rawflags">:$flags
+)> {
+ // DILocalVariableAttr direct getter uses a `StringRef` for `name`. Since the
+ // more direct getter is prefered during bytecode reading, force the base one
+ // and prevent crashes for empty `StringAttr`.
+ let cBuilder = "$_resultType::get(context, $_args)";
+}
+
+//===----------------------------------------------------------------------===//
+// DISubroutineTypeAttr
+//===----------------------------------------------------------------------===//
+
+def DISubroutineTypeAttr : DialectAttribute<(attr
+ VarInt:$callingConvention,
+ OptionalArrayRef<"DITypeAttr">:$types
+)>;
+
+//===----------------------------------------------------------------------===//
+// DICompileUnitAttr
+//===----------------------------------------------------------------------===//
+
+def DICompileUnitAttr : DialectAttribute<(attr
+ Attr<"DistinctAttr">:$id,
+ VarInt:$sourceLanguage,
+ Attr<"DIFileAttr">:$file,
+ OptionalAttribute<"StringAttr">:$producer,
+ Bool:$isOptimized,
+ EnumClassFlag<"DIEmissionKind", "getEmissionKind()">:$_rawEmissionKind,
+ LocalVar<"DIEmissionKind", "(DIEmissionKind)_rawEmissionKind">:$emissionKind,
+ EnumClassFlag<"DINameTableKind", "getNameTableKind()">:$_rawNameTableKind,
+ LocalVar<"DINameTableKind",
+ "(DINameTableKind)_rawNameTableKind">:$nameTableKind
+)>;
+
+//===----------------------------------------------------------------------===//
+// DISubprogramAttr
+//===----------------------------------------------------------------------===//
+
+def DISubprogramAttr : DialectAttribute<(attr
+ OptionalAttribute<"DistinctAttr">:$recId,
+ Bool:$isRecSelf,
+ OptionalAttribute<"DistinctAttr">:$id,
+ OptionalAttribute<"DICompileUnitAttr">:$compileUnit,
+ OptionalAttribute<"DIScopeAttr">:$scope, // TODO: DIScopeAttr
+ OptionalAttribute<"StringAttr">:$name,
+ OptionalAttribute<"StringAttr">:$linkageName,
+ OptionalAttribute<"DIFileAttr">:$file,
+ VarInt:$line,
+ VarInt:$scopeLine,
+ EnumClassFlag<"DISubprogramFlags", "getSubprogramFlags()">:$_rawflags,
+ LocalVar<"DISubprogramFlags", "(DISubprogramFlags)_rawflags">:$subprogramFlags,
+ OptionalAttribute<"DISubroutineTypeAttr">:$type,
+ OptionalArrayRef<"DINodeAttr">:$retainedNodes,
+ OptionalArrayRef<"DINodeAttr">:$annotations
+)>;
+
+//===----------------------------------------------------------------------===//
+// DICompositeTypeAttr
+//===----------------------------------------------------------------------===//
+
+def DICompositeTypeAttr : DialectAttribute<(attr
+ OptionalAttribute<"DistinctAttr">:$recId,
+ Bool:$isRecSelf,
+ VarInt:$tag,
+ OptionalAttribute<"StringAttr">:$name,
+ OptionalAttribute<"DIFileAttr">:$file,
+ VarInt:$line,
+ OptionalAttribute<"DIScopeAttr">:$scope,
+ OptionalAttribute<"DITypeAttr">:$baseType,
+ EnumClassFlag<"DIFlags", "getFlags()">:$_rawflags,
+ LocalVar<"DIFlags", "(DIFlags)_rawflags">:$flags,
+ VarInt:$sizeInBits,
+ VarInt:$alignInBits,
+ OptionalArrayRef<"DINodeAttr">:$elements,
+ OptionalAttribute<"DIExpressionAttr">:$dataLocation,
+ OptionalAttribute<"DIExpressionAttr">:$rank,
+ OptionalAttribute<"DIExpressionAttr">:$allocated,
+ OptionalAttribute<"DIExpressionAttr">:$associated
+)>;
+
+//===----------------------------------------------------------------------===//
+// DIDerivedTypeAttr
+//===----------------------------------------------------------------------===//
+
+def DIDerivedTypeAttr : DialectAttribute<(attr
+ VarInt:$tag,
+ OptionalAttribute<"StringAttr">:$name,
+ OptionalAttribute<"DITypeAttr">:$baseType,
+ VarInt:$sizeInBits,
+ VarInt:$alignInBits,
+ VarInt:$offsetInBits,
+ OptionalInt<"unsigned">:$dwarfAddressSpace,
+ OptionalAttribute<"DINodeAttr">:$extraData // TODO: DINodeAttr
+)>;
+
+//===----------------------------------------------------------------------===//
+// DIImportedEntityAttr
+//===----------------------------------------------------------------------===//
+
+def DIImportedEntityAttr : DialectAttribute<(attr
+ VarInt:$tag,
+ Attr<"DIScopeAttr">:$scope,
+ Attr<"DINodeAttr">:$entity,
+ OptionalAttribute<"DIFileAttr">:$file,
+ VarInt:$line,
+ OptionalAttribute<"StringAttr">:$name,
+ OptionalArrayRef<"DINodeAttr">:$elements
+)>;
+
+//===----------------------------------------------------------------------===//
+// DIGlobalVariableAttr, DIGlobalVariableExpressionAttr
+//===----------------------------------------------------------------------===//
+
+def DIGlobalVariableAttr : DialectAttribute<(attr
+ OptionalAttribute<"DIScopeAttr">:$scope,
+ OptionalAttribute<"StringAttr">:$name,
+ OptionalAttribute<"StringAttr">:$linkageName,
+ Attr<"DIFileAttr">:$file,
+ VarInt:$line,
+ Attr<"DITypeAttr">:$type,
+ Bool:$isLocalToUnit,
+ Bool:$isDefined,
+ VarInt:$alignInBits
+)>;
+
+def DIGlobalVariableExpressionAttr : DialectAttribute<(attr
+ Attr<"DIGlobalVariableAttr">:$var,
+ OptionalAttribute<"DIExpressionAttr">:$expr
+)>;
+
+//===----------------------------------------------------------------------===//
+// DILabelAttr
+//===----------------------------------------------------------------------===//
+
+def DILabelAttr : DialectAttribute<(attr
+ Attr<"DIScopeAttr">:$scope,
+ OptionalAttribute<"StringAttr">:$name,
+ OptionalAttribute<"DIFileAttr">:$file,
+ VarInt:$line
+)> {
+ // DILabelAttr direct getter uses a `StringRef` for `name`. Since the
+ // more direct getter is prefered during bytecode reading, force the base one
+ // and prevent crashes for empty `StringAttr`.
+ let cBuilder = "$_resultType::get(context, $_args)";
+}
+
+//===----------------------------------------------------------------------===//
+// DILexicalBlockAttr, DILexicalBlockFileAttr
+//===----------------------------------------------------------------------===//
+
+def DILexicalBlockAttr : DialectAttribute<(attr
+ Attr<"DIScopeAttr">:$scope,
+ OptionalAttribute<"DIFileAttr">:$file,
+ VarInt:$line,
+ VarInt:$column
+)>;
+
+def DILexicalBlockFileAttr : DialectAttribute<(attr
+ Attr<"DIScopeAttr">:$scope,
+ OptionalAttribute<"DIFileAttr">:$file,
+ VarInt:$discriminator
+)>;
+
+//===----------------------------------------------------------------------===//
+// DINamespaceAttr
+//===----------------------------------------------------------------------===//
+
+def DINamespaceAttr : DialectAttribute<(attr
+ OptionalAttribute<"StringAttr">:$name,
+ OptionalAttribute<"DIScopeAttr">:$scope,
+ Bool:$exportSymbols
+)>;
+
+//===----------------------------------------------------------------------===//
+// DISubrangeAttr
+//===----------------------------------------------------------------------===//
+
+def DISubrangeAttr : DialectAttribute<(attr
+ OptionalAttribute<"Attribute">:$count,
+ OptionalAttribute<"Attribute">:$lowerBound,
+ OptionalAttribute<"Attribute">:$upperBound,
+ OptionalAttribute<"Attribute">:$stride
+)>;
+
+//===----------------------------------------------------------------------===//
+// LoopAnnotationAttr
+//===----------------------------------------------------------------------===//
+
+def LoopAnnotationAttr : DialectAttribute<(attr
+ OptionalAttribute<"BoolAttr">:$disableNonforced,
+ OptionalAttribute<"LoopVectorizeAttr">:$vectorize, // TODO: LoopVectorizeAttr
+ OptionalAttribute<"LoopInterleaveAttr">:$interleave, // TODO: LoopInterleaveAttr
+ OptionalAttribute<"LoopUnrollAttr">:$unroll, // TODO: LoopUnrollAttr
+ OptionalAttribute<"LoopUnrollAndJamAttr">:$unrollAndJam, // TODO: LoopUnrollAndJamAttr
+ OptionalAttribute<"LoopLICMAttr">:$licm, // TODO: LoopLICMAttr
+ OptionalAttribute<"LoopDistributeAttr">:$distribute, // TODO: LoopDistributeAttr
+ OptionalAttribute<"LoopPipelineAttr">:$pipeline, // TODO: LoopPipelineAttr
+ OptionalAttribute<"LoopPeeledAttr">:$peeled, // TODO: LoopPeeledAttr
+ OptionalAttribute<"LoopUnswitchAttr">:$unswitch, // TODO: LoopUnswitchAttr
+ OptionalAttribute<"BoolAttr">:$mustProgress,
+ OptionalAttribute<"BoolAttr">:$isVectorized,
+ OptionalAttribute<"FusedLoc">:$startLoc,
+ OptionalAttribute<"FusedLoc">:$endLoc,
+ OptionalArrayRef<"AccessGroupAttr">:$parallelAccesses // TODO: AccessGroupAttr
+)>;
+
+//===----------------------------------------------------------------------===//
+// Attributes & Types with custom bytecode handling.
+//===----------------------------------------------------------------------===//
+
+def LLVMDialectAttributes : DialectAttributes<"LLVM"> {
+ let elems = [
+ AliasScopeAttr,
+ DIBasicTypeAttr,
+ DICompileUnitAttr,
+ DICompositeTypeAttr,
+ DIDerivedTypeAttr,
+ DIExpressionElemAttr,
+ DIExpressionAttr,
+ DIFileAttr,
+ DIGlobalVariableAttr,
+ DIGlobalVariableExpressionAttr,
+ DIImportedEntityAttr,
+ DILabelAttr,
+ DILexicalBlockAttr,
+ DILexicalBlockFileAttr,
+ DILocalVariableAttr,
+ DINamespaceAttr,
+ DISubprogramAttr,
+ DISubrangeAttr,
+ DISubroutineTypeAttr,
+ LoopAnnotationAttr
+ ];
+}
+
+def LLVMDialectTypes : DialectTypes<"LLVM"> {
+ let elems = [];
+}
+
+#endif // LLVM_DIALECT_BYTECODE
diff --git a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
index ec581ac7277e3..cc66face1c002 100644
--- a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
+++ b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
@@ -8,11 +8,13 @@ add_mlir_dialect_library(MLIRLLVMDialect
IR/LLVMMemorySlot.cpp
IR/LLVMTypes.cpp
IR/LLVMTypeSyntax.cpp
+ IR/LLVMDialectBytecode.cpp
ADDITIONAL_HEADER_DIRS
${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/LLVMIR
DEPENDS
+ MLIRLLVMDialectBytecodeIncGen
MLIRLLVMOpsIncGen
MLIRLLVMTypesIncGen
MLIRLLVMIntrinsicOpsIncGen
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 5d08cccb4faab..7ca09d9c943e0 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -29,6 +29,8 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/Support/Error.h"
+#include "LLVMDialectBytecode.h"
+
#include <numeric>
#include <optional>
@@ -4237,6 +4239,7 @@ void LLVMDialect::initialize() {
// Support unknown operations because not all LLVM operations are registered.
allowUnknownOperations();
declarePromisedInterface<DialectInlinerInterface, LLVMDialect>();
+ detail::addBytecodeInterface(this);
}
#define GET_OP_CLASSES
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp
new file mode 100644
index 0000000000000..f06c764ab5f6d
--- /dev/null
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp
@@ -0,0 +1,155 @@
+//===- LLVMDialectBytecode.cpp - LLVM Bytecode Implementation -------------===//
+//
+// 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 "LLVMDialectBytecode.h"
+#include "mlir/Bytecode/BytecodeImplementation.h"
+#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/IR/Diagnostics.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/TypeSwitch.h"
+#include <type_traits>
+
+using namespace mlir;
+using namespace mlir::LLVM;
+
+namespace {
+
+// Provide some forward declarations of the functions that will be generated by
+// the include below.
+static void write(DIExpressionElemAttr attribute,
+ DialectBytecodeWriter &writer);
+static LogicalResult writeAttribute(Attribute attribute,
+ DialectBytecodeWriter &writer);
+
+//===--------------------------------------------------------------------===//
+// Optional ArrayRefs
+//
+// Note that both the writer and reader functions consider attributes to be
+// optional. This is because the attribute may be present by empty.
+//===--------------------------------------------------------------------===//
+
+template <class EntryTy>
+static void writeOptionalArrayRef(DialectBytecodeWriter &writer,
+ ArrayRef<EntryTy> storage) {
+ if (!storage.empty()) {
+ writer.writeOwnedBool(true);
+ writer.writeList(storage, [&](EntryTy val) {
+ if constexpr (std::is_base_of_v<Attribute, EntryTy>) {
+ (void)writer.writeOptionalAttribute(val);
+ } else if constexpr (std::is_integral_v<EntryTy>) {
+ (void)writer.writeVarInt(val);
+ } else
+ static_assert(true, "EntryTy not supported");
+ });
+ } else {
+ writer.writeOwnedBool(false);
+ }
+}
+
+template <class EntryTy>
+static LogicalResult readOptionalArrayRef(DialectBytecodeReader &reader,
+ SmallVectorImpl<EntryTy> &storage) {
+ bool isPresent = false;
+ if (failed(reader.readBool(isPresent)))
+ return failure();
+ // Nothing to do here, the array is empty.
+ if (!isPresent)
+ return success();
+
+ auto readOperations = [&]() -> FailureOr<EntryTy> {
+ EntryTy temp;
+ if constexpr (std::is_base_of_v<Attribute, EntryTy>) {
+ if (succeeded(reader.readOptionalAttribute(temp)))
+ return temp;
+ } else if constexpr (std::is_integral_v<EntryTy>) {
+ if (succeeded(reader.readVarInt(temp)))
+ return temp;
+ } else
+ static_assert(true, "EntryTy not supported");
+ return failure();
+ };
+
+ return reader.readList(storage, readOperations);
+}
+
+//===--------------------------------------------------------------------===//
+// Optional integral types
+//===--------------------------------------------------------------------===//
+
+template <class EntryTy>
+static void writeOptionalInt(DialectBytecodeWriter &writer,
+ std::optional<EntryTy> storage) {
+ static_assert(std::is_integral_v<EntryTy>,
+ "EntryTy must be an integral type");
+ EntryTy val = storage.value_or(0);
+ writer.writeVarIntWithFlag(val, storage.has_value());
+}
+
+template <class EntryTy>
+static LogicalResult readOptionalInt(DialectBytecodeReader &reader,
+ std::optional<EntryTy> &storage) {
+ static_assert(std::is_integral_v<EntryTy>,
+ "EntryTy must be an integral type");
+ uint64_t result = 0;
+ bool flag = false;
+ if (failed(reader.readVarIntWithFlag(result, flag)))
+ return failure();
+ if (flag)
+ storage = (decltype(storage.value()))result;
+ else
+ storage = std::nullopt;
+ return success();
+}
+
+//===--------------------------------------------------------------------===//
+// Tablegen generated bytecode functions
+//===--------------------------------------------------------------------===//
+
+#include "mlir/Dialect/LLVMIR/LLVMDialectBytecode.cpp.inc"
+
+//===--------------------------------------------------------------------===//
+// LLVMDialectBytecodeInterface
+//===--------------------------------------------------------------------===//
+
+/// This class implements the bytecode interface for the LLVM dialect.
+struct LLVMDialectBytecodeInterface : public BytecodeDialectInterface {
+ LLVMDialectBytecodeInterface(Dialect *dialect)
+ : BytecodeDialectInterface(dialect) {}
+
+ //===--------------------------------------------------------------------===//
+ // Attributes
+
+ Attribute readAttribute(DialectBytecodeReader &reader) const override {
+ return ::readAttribute(getContext(), reader);
+ }
+
+ LogicalResult writeAttribute(Attribute attr,
+ DialectBytecodeWriter &writer) const override {
+ return ::writeAttribute(attr, writer);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Types
+
+ Type readType(DialectBytecodeReader &reader) const override {
+ return ::readType(getContext(), reader);
+ }
+
+ LogicalResult writeType(Type type,
+ DialectBytecodeWriter &writer) const override {
+ return ::writeType(type, writer);
+ }
+};
+} // namespace
+
+void LLVM::detail::addBytecodeInterface(LLVMDialect *dialect) {
+ dialect->addInterfaces<LLVMDialectBytecodeInterface>();
+}
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.h b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.h
new file mode 100644
index 0000000000000..5e25d3948afb9
--- /dev/null
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.h
@@ -0,0 +1,27 @@
+//===- LLVMDialectBytecode.h - LLVM Bytecode Implementation -----*- 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 defines hooks into the LLVMization dialect bytecode
+// implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LIB_MLIR_DIALECT_LLVM_IR_LLVMDIALECTBYTECODE_H
+#define LIB_MLIR_DIALECT_LLVM_IR_LLVMDIALECTBYTECODE_H
+
+namespace mlir::LLVM {
+class LLVMDialect;
+
+namespace detail {
+/// Add the interfaces necessary for encoding the LLVMization dialect
+/// components in bytecode.
+void addBytecodeInterface(LLVMDialect *dialect);
+} // namespace detail
+} // namespace mlir::LLVM
+
+#endif // LIB_MLIR_DIALECT_LLVM_IR_LLVMDIALECTBYTECODE_H
diff --git a/mlir/test/Dialect/LLVMIR/bytecode.mlir b/mlir/test/Dialect/LLVMIR/bytecode.mlir
new file mode 100644
index 0000000000000..6f273ea2d90e9
--- /dev/null
+++ b/mlir/test/Dialect/LLVMIR/bytecode.mlir
@@ -0,0 +1,69 @@
+// RUN: mlir-opt -emit-bytecode %s | mlir-opt --mlir-print-debuginfo | FileCheck %s
+
+#access_group = #llvm.access_group<id = distinct[0]<>>
+#access_group1 = #llvm.access_group<id = distinct[1]<>>
+#di_subprogram = #llvm.di_subprogram<recId = distinct[2]<>>
+#loc1 = loc("test.f90":12:14)
+#loc2 = loc("test":4:3)
+#loc6 = loc(fused<#di_subprogram>[#loc1])
+#loc7 = loc(fused<#di_subprogram>[#loc2])
+#loop_annotation = #llvm.loop_annotation<disableNonforced = false, mustProgress = true, startLoc = #loc6, endLoc = #loc7, parallelAccesses = #access_group, #access_group1>
+module {
+ llvm.func @imp_fn() {
+ llvm.return loc(#loc2)
+ } loc(#loc8)
+ llvm.func @loop_annotation_with_locs() {
+ llvm.br ^bb1 {loop_annotation = #loop_annotation} loc(#loc4)
+ ^bb1: // pred: ^bb0
+ llvm.return loc(#loc5)
+ } loc(#loc3)
+} loc(#loc)
+#di_file = #llvm.di_file<"test.f90" in "">
+#di_subroutine_type = #llvm.di_subroutine_type<callingConvention = DW_CC_program>
+#loc = loc("test":0:0)
+#loc3 = loc("test-path":36:3)
+#loc4 = loc("test-path":37:5)
+#loc5 = loc("test-path":39:5)
+#di_compile_unit = #llvm.di_compile_unit<id = distinct[3]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
+#di_compile_unit1 = #llvm.di_compile_unit<id = distinct[4]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
+#di_compile_unit2 = #llvm.di_compile_unit<id = distinct[5]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
+#di_module = #llvm.di_module<file = #di_file, scope = #di_compile_unit1, name = "mod1">
+#di_module1 = #llvm.di_module<file = #di_file, scope = #di_compile_unit2, name = "mod2">
+#di_imported_entity = #llvm.di_imported_entity<tag = DW_TAG_imported_module, scope = #di_subprogram, entity = #di_module, file = #di_file, line = 1>
+#di_imported_entity1 = #llvm.di_imported_entity<tag = DW_TAG_imported_module, scope = #di_subprogram, entity = #di_module1, file = #di_file, line = 1>
+#di_subprogram1 = #llvm.di_subprogram<recId = distinct[2]<>, id = distinct[6]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "imp_fn", file = #di_file, subprogramFlags = Definition, type = #di_subroutine_type, retainedNodes = #di_imported_entity, #di_imported_entity1>
+#loc8 = loc(fused<#di_subprogram1>[#loc1])
+
+// CHECK: #access_group = #llvm.access_group<id = distinct[0]<>>
+// CHECK: #access_group1 = #llvm.access_group<id = distinct[1]<>>
+// CHECK: #di_subprogram = #llvm.di_subprogram<recId = distinct[2]<>>
+// CHECK: {{.*}} = loc("test.f90":12:14)
+// CHECK: {{.*}} = loc("test":4:3)
+// CHECK: {{.*}} = loc(fused<#di_subprogram>[{{.*}}])
+// CHECK: {{.*}} = loc(fused<#di_subprogram>[{{.*}}])
+// CHECK: #loop_annotation = #llvm.loop_annotation<disableNonforced = false, mustProgress = true, startLoc = {{.*}}, endLoc = {{.*}}, parallelAccesses = #access_group, #access_group1>
+// CHECK: module {
+// CHECK: llvm.func @imp_fn() {
+// CHECK: llvm.return loc({{.*}})
+// CHECK: } loc({{.*}})
+// CHECK: llvm.func @loop_annotation_with_locs() {
+// CHECK: llvm.br ^bb1 {loop_annotation = #loop_annotation} loc({{.*}})
+// CHECK: ^bb1: // pred: ^bb0
+// CHECK: llvm.return loc({{.*}})
+// CHECK: } loc({{.*}})
+// CHECK: } loc({{.*}})
+// CHECK: #di_file = #llvm.di_file<"test.f90" in "">
+// CHECK: #di_subroutine_type = #llvm.di_subroutine_type<callingConvention = DW_CC_program>
+// CHECK: {{.*}} = loc("test":0:0)
+// CHECK: {{.*}} = loc("test-path":36:3)
+// CHECK: {{.*}} = loc("test-path":37:5)
+// CHECK: {{.*}} = loc("test-path":39:5)
+// CHECK: #di_compile_unit = #llvm.di_compile_unit<id = distinct[3]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
+// CHECK: #di_compile_unit1 = #llvm.di_compile_unit<id = distinct[4]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
+// CHECK: #di_compile_unit2 = #llvm.di_compile_unit<id = distinct[5]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
+// CHECK: #di_module = #llvm.di_module<file = #di_file, scope = #di_compile_unit1, name = "mod1">
+// CHECK: #di_module1 = #llvm.di_module<file = #di_file, scope = #di_compile_unit2, name = "mod2">
+// CHECK: #di_imported_entity = #llvm.di_imported_entity<tag = DW_TAG_imported_module, scope = #di_subprogram, entity = #di_module, file = #di_file, line = 1>
+// CHECK: #di_imported_entity1 = #llvm.di_imported_entity<tag = DW_TAG_imported_module, scope = #di_subprogram, entity = #di_module1, file = #di_file, line = 1>
+// CHECK: #di_subprogram1 = #llvm.di_subprogram<recId = distinct[2]<>, id = distinct[6]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "imp_fn", file = #di_file, subprogramFlags = Definition, type = #di_subroutine_type, retainedNodes = #di_imported_entity, #di_imported_entity1>
+// CHECK: {{.*}} = loc(fused<#di_subprogram1>[{{.*}}])
diff --git a/mlir/test/Dialect/LLVMIR/debuginfo.mlir b/mlir/test/Dialect/LLVMIR/debuginfo.mlir
index 1834b0a524705..d7bf99bfaed7f 100644
--- a/mlir/test/Dialect/LLVMIR/debuginfo.mlir
+++ b/mlir/test/Dialect/LLVMIR/debuginfo.mlir
@@ -1,4 +1,5 @@
// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+// RUN: mlir-opt -emit-bytecode %s | mlir-opt | FileCheck %s
// CHECK-DAG: #[[FILE:.*]] = #llvm.di_file<"debuginfo.mlir" in "/test/">
#file = #llvm.di_file<"debuginfo.mlir" in "/test/">
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 73447978341dc..f1dfb6ab456ca 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -1,4 +1,5 @@
// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+// RUN: mlir-opt %s -emit-bytecode | mlir-opt | FileCheck %s
// CHECK-LABEL: func @baz
@@ -757,7 +758,7 @@ llvm.func @stackrestore(%arg0: !llvm.ptr) {
// CHECK-LABEL: @experimental_noalias_scope_decl
llvm.func @experimental_noalias_scope_decl() {
- // CHECK: llvm.intr.experimental.noalias.scope.decl #{{.*}}
+ // CHECK: llvm.intr.experimental.noalias.scope.decl #alias_scope{{.*}}
llvm.intr.experimental.noalias.scope.decl #alias_scope
llvm.return
}
@@ -767,7 +768,7 @@ llvm.func @experimental_noalias_scope_decl() {
// CHECK-LABEL: @experimental_noalias_scope_with_string_id
llvm.func @experimental_noalias_scope_with_string_id() {
- // CHECK: llvm.intr.experimental.noalias.scope.decl #{{.*}}
+ // CHECK: llvm.intr.experimental.noalias.scope.decl #alias_scope{{.*}}
llvm.intr.experimental.noalias.scope.decl #alias_scope2
llvm.return
}
>From eff046f3b2b720b6b58ea7d5a011ff6ddf5312c8 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Wed, 8 Oct 2025 19:01:55 -0700
Subject: [PATCH 2/4] Update order of elements to match upstream
---
mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
index 2474dece3f7c3..fedb76b7f3123 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
@@ -188,11 +188,11 @@ def DICompositeTypeAttr : DialectAttribute<(attr
LocalVar<"DIFlags", "(DIFlags)_rawflags">:$flags,
VarInt:$sizeInBits,
VarInt:$alignInBits,
- OptionalArrayRef<"DINodeAttr">:$elements,
OptionalAttribute<"DIExpressionAttr">:$dataLocation,
OptionalAttribute<"DIExpressionAttr">:$rank,
OptionalAttribute<"DIExpressionAttr">:$allocated,
- OptionalAttribute<"DIExpressionAttr">:$associated
+ OptionalAttribute<"DIExpressionAttr">:$associated,
+ OptionalArrayRef<"DINodeAttr">:$elements
)>;
//===----------------------------------------------------------------------===//
>From dd8aa3d0fd75e15b1079f5e0b5b195929c422b2a Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Thu, 9 Oct 2025 12:17:59 -0700
Subject: [PATCH 3/4] Address review feedback
---
.../Dialect/LLVMIR/LLVMDialectBytecode.td | 33 +++++++++++--------
.../Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp | 12 +++----
.../Dialect/LLVMIR/IR/LLVMDialectBytecode.h | 6 ++--
mlir/test/Dialect/LLVMIR/bytecode.mlir | 22 ++++++++++---
4 files changed, 44 insertions(+), 29 deletions(-)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
index fedb76b7f3123..7eea9e4d7e1f4 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
@@ -57,6 +57,8 @@ class EnumClassFlag<string flag, string getter> :
// LLVMAttrDefs.td
// - The mnemonics are either LLVM or builtin MLIR attributes and types, but
// regular C++ types are also allowed to match builders and parsers.
+// - DIScopeAttr and DINodeAttr are empty base classes, custom encoding not
+// needed.
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@@ -107,7 +109,7 @@ def DIFileAttr : DialectAttribute<(attr
//===----------------------------------------------------------------------===//
def DILocalVariableAttr : DialectAttribute<(attr
- Attr<"DIScopeAttr">:$scope, // Non-optional attribute
+ Attr<"DIScopeAttr">:$scope,
OptionalAttribute<"StringAttr">:$name,
OptionalAttribute<"DIFileAttr">:$file,
VarInt:$line,
@@ -158,7 +160,7 @@ def DISubprogramAttr : DialectAttribute<(attr
Bool:$isRecSelf,
OptionalAttribute<"DistinctAttr">:$id,
OptionalAttribute<"DICompileUnitAttr">:$compileUnit,
- OptionalAttribute<"DIScopeAttr">:$scope, // TODO: DIScopeAttr
+ OptionalAttribute<"DIScopeAttr">:$scope,
OptionalAttribute<"StringAttr">:$name,
OptionalAttribute<"StringAttr">:$linkageName,
OptionalAttribute<"DIFileAttr">:$file,
@@ -207,7 +209,7 @@ def DIDerivedTypeAttr : DialectAttribute<(attr
VarInt:$alignInBits,
VarInt:$offsetInBits,
OptionalInt<"unsigned">:$dwarfAddressSpace,
- OptionalAttribute<"DINodeAttr">:$extraData // TODO: DINodeAttr
+ OptionalAttribute<"DINodeAttr">:$extraData
)>;
//===----------------------------------------------------------------------===//
@@ -305,26 +307,27 @@ def DISubrangeAttr : DialectAttribute<(attr
def LoopAnnotationAttr : DialectAttribute<(attr
OptionalAttribute<"BoolAttr">:$disableNonforced,
- OptionalAttribute<"LoopVectorizeAttr">:$vectorize, // TODO: LoopVectorizeAttr
- OptionalAttribute<"LoopInterleaveAttr">:$interleave, // TODO: LoopInterleaveAttr
- OptionalAttribute<"LoopUnrollAttr">:$unroll, // TODO: LoopUnrollAttr
- OptionalAttribute<"LoopUnrollAndJamAttr">:$unrollAndJam, // TODO: LoopUnrollAndJamAttr
- OptionalAttribute<"LoopLICMAttr">:$licm, // TODO: LoopLICMAttr
- OptionalAttribute<"LoopDistributeAttr">:$distribute, // TODO: LoopDistributeAttr
- OptionalAttribute<"LoopPipelineAttr">:$pipeline, // TODO: LoopPipelineAttr
- OptionalAttribute<"LoopPeeledAttr">:$peeled, // TODO: LoopPeeledAttr
- OptionalAttribute<"LoopUnswitchAttr">:$unswitch, // TODO: LoopUnswitchAttr
+ OptionalAttribute<"LoopVectorizeAttr">:$vectorize,
+ OptionalAttribute<"LoopInterleaveAttr">:$interleave,
+ OptionalAttribute<"LoopUnrollAttr">:$unroll,
+ OptionalAttribute<"LoopUnrollAndJamAttr">:$unrollAndJam,
+ OptionalAttribute<"LoopLICMAttr">:$licm,
+ OptionalAttribute<"LoopDistributeAttr">:$distribute,
+ OptionalAttribute<"LoopPipelineAttr">:$pipeline,
+ OptionalAttribute<"LoopPeeledAttr">:$peeled,
+ OptionalAttribute<"LoopUnswitchAttr">:$unswitch,
OptionalAttribute<"BoolAttr">:$mustProgress,
OptionalAttribute<"BoolAttr">:$isVectorized,
OptionalAttribute<"FusedLoc">:$startLoc,
OptionalAttribute<"FusedLoc">:$endLoc,
- OptionalArrayRef<"AccessGroupAttr">:$parallelAccesses // TODO: AccessGroupAttr
+ OptionalArrayRef<"AccessGroupAttr">:$parallelAccesses
)>;
//===----------------------------------------------------------------------===//
// Attributes & Types with custom bytecode handling.
//===----------------------------------------------------------------------===//
+// All the attributes with custom bytecode handling.
def LLVMDialectAttributes : DialectAttributes<"LLVM"> {
let elems = [
AliasScopeAttr,
@@ -347,6 +350,10 @@ def LLVMDialectAttributes : DialectAttributes<"LLVM"> {
DISubrangeAttr,
DISubroutineTypeAttr,
LoopAnnotationAttr
+ // Referenced attributes currently missing support:
+ // AccessGroupAttr, LoopVectorizeAttr, LoopInterleaveAttr, LoopUnrollAttr,
+ // LoopUnrollAndJamAttr, LoopLICMAttr, LoopDistributeAttr, LoopPipelineAttr,
+ // LoopPeeledAttr, LoopUnswitchAttr
];
}
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp
index f06c764ab5f6d..113637d479d0f 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp
@@ -33,7 +33,7 @@ static LogicalResult writeAttribute(Attribute attribute,
// Optional ArrayRefs
//
// Note that both the writer and reader functions consider attributes to be
-// optional. This is because the attribute may be present by empty.
+// optional. This is because the attribute may be present or empty.
//===--------------------------------------------------------------------===//
template <class EntryTy>
@@ -64,7 +64,7 @@ static LogicalResult readOptionalArrayRef(DialectBytecodeReader &reader,
if (!isPresent)
return success();
- auto readOperations = [&]() -> FailureOr<EntryTy> {
+ auto readEntry = [&]() -> FailureOr<EntryTy> {
EntryTy temp;
if constexpr (std::is_base_of_v<Attribute, EntryTy>) {
if (succeeded(reader.readOptionalAttribute(temp)))
@@ -77,7 +77,7 @@ static LogicalResult readOptionalArrayRef(DialectBytecodeReader &reader,
return failure();
};
- return reader.readList(storage, readOperations);
+ return reader.readList(storage, readEntry);
}
//===--------------------------------------------------------------------===//
@@ -103,7 +103,7 @@ static LogicalResult readOptionalInt(DialectBytecodeReader &reader,
if (failed(reader.readVarIntWithFlag(result, flag)))
return failure();
if (flag)
- storage = (decltype(storage.value()))result;
+ storage = static_cast<EntryTy>(result);
else
storage = std::nullopt;
return success();
@@ -124,9 +124,7 @@ struct LLVMDialectBytecodeInterface : public BytecodeDialectInterface {
LLVMDialectBytecodeInterface(Dialect *dialect)
: BytecodeDialectInterface(dialect) {}
- //===--------------------------------------------------------------------===//
// Attributes
-
Attribute readAttribute(DialectBytecodeReader &reader) const override {
return ::readAttribute(getContext(), reader);
}
@@ -136,9 +134,7 @@ struct LLVMDialectBytecodeInterface : public BytecodeDialectInterface {
return ::writeAttribute(attr, writer);
}
- //===--------------------------------------------------------------------===//
// Types
-
Type readType(DialectBytecodeReader &reader) const override {
return ::readType(getContext(), reader);
}
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.h b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.h
index 5e25d3948afb9..1a17cb462ccf3 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.h
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.h
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This header defines hooks into the LLVMization dialect bytecode
+// This header defines hooks into the LLVM dialect bytecode
// implementation.
//
//===----------------------------------------------------------------------===//
@@ -18,8 +18,8 @@ namespace mlir::LLVM {
class LLVMDialect;
namespace detail {
-/// Add the interfaces necessary for encoding the LLVMization dialect
-/// components in bytecode.
+/// Add the interfaces necessary for encoding the LLVM dialect components in
+/// bytecode.
void addBytecodeInterface(LLVMDialect *dialect);
} // namespace detail
} // namespace mlir::LLVM
diff --git a/mlir/test/Dialect/LLVMIR/bytecode.mlir b/mlir/test/Dialect/LLVMIR/bytecode.mlir
index 6f273ea2d90e9..b8b95acfd5457 100644
--- a/mlir/test/Dialect/LLVMIR/bytecode.mlir
+++ b/mlir/test/Dialect/LLVMIR/bytecode.mlir
@@ -8,6 +8,8 @@
#loc6 = loc(fused<#di_subprogram>[#loc1])
#loc7 = loc(fused<#di_subprogram>[#loc2])
#loop_annotation = #llvm.loop_annotation<disableNonforced = false, mustProgress = true, startLoc = #loc6, endLoc = #loc7, parallelAccesses = #access_group, #access_group1>
+#alias_scope_domain = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
+#alias_scope = #llvm.alias_scope<id = distinct[0]<>, domain = #alias_scope_domain, description = "The domain">
module {
llvm.func @imp_fn() {
llvm.return loc(#loc2)
@@ -17,6 +19,10 @@ module {
^bb1: // pred: ^bb0
llvm.return loc(#loc5)
} loc(#loc3)
+ llvm.func @experimental_noalias_scope_decl() {
+ llvm.intr.experimental.noalias.scope.decl #alias_scope
+ llvm.return
+ }
} loc(#loc)
#di_file = #llvm.di_file<"test.f90" in "">
#di_subroutine_type = #llvm.di_subroutine_type<callingConvention = DW_CC_program>
@@ -36,9 +42,11 @@ module {
// CHECK: #access_group = #llvm.access_group<id = distinct[0]<>>
// CHECK: #access_group1 = #llvm.access_group<id = distinct[1]<>>
-// CHECK: #di_subprogram = #llvm.di_subprogram<recId = distinct[2]<>>
+// CHECK: #alias_scope_domain = #llvm.alias_scope_domain<id = distinct[2]<>, description = "The domain">
+// CHECK: #di_subprogram = #llvm.di_subprogram<recId = distinct[3]<>>
// CHECK: {{.*}} = loc("test.f90":12:14)
// CHECK: {{.*}} = loc("test":4:3)
+// CHECK: #alias_scope = #llvm.alias_scope<id = distinct[4]<>, domain = #alias_scope_domain, description = "The domain">
// CHECK: {{.*}} = loc(fused<#di_subprogram>[{{.*}}])
// CHECK: {{.*}} = loc(fused<#di_subprogram>[{{.*}}])
// CHECK: #loop_annotation = #llvm.loop_annotation<disableNonforced = false, mustProgress = true, startLoc = {{.*}}, endLoc = {{.*}}, parallelAccesses = #access_group, #access_group1>
@@ -51,6 +59,10 @@ module {
// CHECK: ^bb1: // pred: ^bb0
// CHECK: llvm.return loc({{.*}})
// CHECK: } loc({{.*}})
+// CHECK: llvm.func @experimental_noalias_scope_decl() {
+// CHECK: llvm.intr.experimental.noalias.scope.decl #alias_scope loc({{.*}})
+// CHECK: llvm.return loc({{.*}})
+// CHECK: } loc({{.*}})
// CHECK: } loc({{.*}})
// CHECK: #di_file = #llvm.di_file<"test.f90" in "">
// CHECK: #di_subroutine_type = #llvm.di_subroutine_type<callingConvention = DW_CC_program>
@@ -58,12 +70,12 @@ module {
// CHECK: {{.*}} = loc("test-path":36:3)
// CHECK: {{.*}} = loc("test-path":37:5)
// CHECK: {{.*}} = loc("test-path":39:5)
-// CHECK: #di_compile_unit = #llvm.di_compile_unit<id = distinct[3]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
-// CHECK: #di_compile_unit1 = #llvm.di_compile_unit<id = distinct[4]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
-// CHECK: #di_compile_unit2 = #llvm.di_compile_unit<id = distinct[5]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
+// CHECK: #di_compile_unit = #llvm.di_compile_unit<id = distinct[5]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
+// CHECK: #di_compile_unit1 = #llvm.di_compile_unit<id = distinct[6]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
+// CHECK: #di_compile_unit2 = #llvm.di_compile_unit<id = distinct[7]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full>
// CHECK: #di_module = #llvm.di_module<file = #di_file, scope = #di_compile_unit1, name = "mod1">
// CHECK: #di_module1 = #llvm.di_module<file = #di_file, scope = #di_compile_unit2, name = "mod2">
// CHECK: #di_imported_entity = #llvm.di_imported_entity<tag = DW_TAG_imported_module, scope = #di_subprogram, entity = #di_module, file = #di_file, line = 1>
// CHECK: #di_imported_entity1 = #llvm.di_imported_entity<tag = DW_TAG_imported_module, scope = #di_subprogram, entity = #di_module1, file = #di_file, line = 1>
-// CHECK: #di_subprogram1 = #llvm.di_subprogram<recId = distinct[2]<>, id = distinct[6]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "imp_fn", file = #di_file, subprogramFlags = Definition, type = #di_subroutine_type, retainedNodes = #di_imported_entity, #di_imported_entity1>
+// CHECK: #di_subprogram1 = #llvm.di_subprogram<recId = distinct[3]<>, id = distinct[8]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "imp_fn", file = #di_file, subprogramFlags = Definition, type = #di_subroutine_type, retainedNodes = #di_imported_entity, #di_imported_entity1>
// CHECK: {{.*}} = loc(fused<#di_subprogram1>[{{.*}}])
>From 753f296504d7ea6d845a7d38c9b4678aa0c2b830 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Fri, 10 Oct 2025 11:39:59 -0700
Subject: [PATCH 4/4] Address more comments and use -verify-roundtrip
---
.../Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp | 27 ++++++++++---------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp
index 113637d479d0f..41d1f80580cf7 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialectBytecode.cpp
@@ -39,19 +39,21 @@ static LogicalResult writeAttribute(Attribute attribute,
template <class EntryTy>
static void writeOptionalArrayRef(DialectBytecodeWriter &writer,
ArrayRef<EntryTy> storage) {
- if (!storage.empty()) {
- writer.writeOwnedBool(true);
- writer.writeList(storage, [&](EntryTy val) {
- if constexpr (std::is_base_of_v<Attribute, EntryTy>) {
- (void)writer.writeOptionalAttribute(val);
- } else if constexpr (std::is_integral_v<EntryTy>) {
- (void)writer.writeVarInt(val);
- } else
- static_assert(true, "EntryTy not supported");
- });
- } else {
+ if (storage.empty()) {
writer.writeOwnedBool(false);
+ return;
}
+
+ writer.writeOwnedBool(true);
+ writer.writeList(storage, [&](EntryTy val) {
+ if constexpr (std::is_base_of_v<Attribute, EntryTy>) {
+ (void)writer.writeOptionalAttribute(val);
+ } else if constexpr (std::is_integral_v<EntryTy>) {
+ (void)writer.writeVarInt(val);
+ } else {
+ static_assert(true, "EntryTy not supported");
+ }
+ });
}
template <class EntryTy>
@@ -72,8 +74,9 @@ static LogicalResult readOptionalArrayRef(DialectBytecodeReader &reader,
} else if constexpr (std::is_integral_v<EntryTy>) {
if (succeeded(reader.readVarInt(temp)))
return temp;
- } else
+ } else {
static_assert(true, "EntryTy not supported");
+ }
return failure();
};
More information about the Mlir-commits
mailing list