From bce08030595c63a2afe5a438079d6d15d2c2232e Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Wed, 8 Oct 2025 17:25:08 -0700 Subject: [PATCH 1/5] [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 : WithType; + +class OptionalAttribute : + WithParser <"succeeded($_reader.readOptionalAttribute($_var))", + WithPrinter<"$_writer.writeOptionalAttribute($_getter)", + WithType>>; + +class OptionalInt : + WithParser <"succeeded(readOptionalInt($_reader, $_var))", + WithPrinter<"writeOptionalInt($_writer, $_getter)", + WithType<"std::optional<" # type # ">", VarInt>>>; + +class OptionalArrayRef : + WithParser <"succeeded(readOptionalArrayRef<" + # eltType # ">($_reader, $_var))", + WithPrinter<"writeOptionalArrayRef<" + # eltType # ">($_writer, $_getter)", + WithType<"SmallVector<" + # eltType # ">", Attribute>>>; + +class EnumClassFlag : + 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 #include @@ -4237,6 +4239,7 @@ void LLVMDialect::initialize() { // Support unknown operations because not all LLVM operations are registered. allowUnknownOperations(); declarePromisedInterface(); + 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 + +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 +static void writeOptionalArrayRef(DialectBytecodeWriter &writer, + ArrayRef storage) { + if (!storage.empty()) { + writer.writeOwnedBool(true); + writer.writeList(storage, [&](EntryTy val) { + if constexpr (std::is_base_of_v) { + (void)writer.writeOptionalAttribute(val); + } else if constexpr (std::is_integral_v) { + (void)writer.writeVarInt(val); + } else + static_assert(true, "EntryTy not supported"); + }); + } else { + writer.writeOwnedBool(false); + } +} + +template +static LogicalResult readOptionalArrayRef(DialectBytecodeReader &reader, + SmallVectorImpl &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 temp; + if constexpr (std::is_base_of_v) { + if (succeeded(reader.readOptionalAttribute(temp))) + return temp; + } else if constexpr (std::is_integral_v) { + 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 +static void writeOptionalInt(DialectBytecodeWriter &writer, + std::optional storage) { + static_assert(std::is_integral_v, + "EntryTy must be an integral type"); + EntryTy val = storage.value_or(0); + writer.writeVarIntWithFlag(val, storage.has_value()); +} + +template +static LogicalResult readOptionalInt(DialectBytecodeReader &reader, + std::optional &storage) { + static_assert(std::is_integral_v, + "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(); +} 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> +#access_group1 = #llvm.access_group> +#di_subprogram = #llvm.di_subprogram> +#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 +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 +#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, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> +#di_compile_unit1 = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> +#di_compile_unit2 = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> +#di_module = #llvm.di_module +#di_module1 = #llvm.di_module +#di_imported_entity = #llvm.di_imported_entity +#di_imported_entity1 = #llvm.di_imported_entity +#di_subprogram1 = #llvm.di_subprogram, 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> +// CHECK: #access_group1 = #llvm.access_group> +// CHECK: #di_subprogram = #llvm.di_subprogram> +// 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 +// 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 +// 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, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> +// CHECK: #di_compile_unit1 = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> +// CHECK: #di_compile_unit2 = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> +// CHECK: #di_module = #llvm.di_module +// CHECK: #di_module1 = #llvm.di_module +// CHECK: #di_imported_entity = #llvm.di_imported_entity +// CHECK: #di_imported_entity1 = #llvm.di_imported_entity +// CHECK: #di_subprogram1 = #llvm.di_subprogram, 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 Date: Wed, 8 Oct 2025 19:01:55 -0700 Subject: [PATCH 2/5] 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 Date: Thu, 9 Oct 2025 12:17:59 -0700 Subject: [PATCH 3/5] 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 : // 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 @@ -64,7 +64,7 @@ static LogicalResult readOptionalArrayRef(DialectBytecodeReader &reader, if (!isPresent) return success(); - auto readOperations = [&]() -> FailureOr { + auto readEntry = [&]() -> FailureOr { EntryTy temp; if constexpr (std::is_base_of_v) { 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(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 +#alias_scope_domain = #llvm.alias_scope_domain, description = "The domain"> +#alias_scope = #llvm.alias_scope, 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 @@ -36,9 +42,11 @@ module { // CHECK: #access_group = #llvm.access_group> // CHECK: #access_group1 = #llvm.access_group> -// CHECK: #di_subprogram = #llvm.di_subprogram> +// CHECK: #alias_scope_domain = #llvm.alias_scope_domain, description = "The domain"> +// CHECK: #di_subprogram = #llvm.di_subprogram> // CHECK: {{.*}} = loc("test.f90":12:14) // CHECK: {{.*}} = loc("test":4:3) +// CHECK: #alias_scope = #llvm.alias_scope, domain = #alias_scope_domain, description = "The domain"> // CHECK: {{.*}} = loc(fused<#di_subprogram>[{{.*}}]) // CHECK: {{.*}} = loc(fused<#di_subprogram>[{{.*}}]) // CHECK: #loop_annotation = #llvm.loop_annotation @@ -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 @@ -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, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> -// CHECK: #di_compile_unit1 = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> -// CHECK: #di_compile_unit2 = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> +// CHECK: #di_compile_unit = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> +// CHECK: #di_compile_unit1 = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> +// CHECK: #di_compile_unit2 = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> // CHECK: #di_module = #llvm.di_module // CHECK: #di_module1 = #llvm.di_module // CHECK: #di_imported_entity = #llvm.di_imported_entity // CHECK: #di_imported_entity1 = #llvm.di_imported_entity -// CHECK: #di_subprogram1 = #llvm.di_subprogram, 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, 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 Date: Fri, 10 Oct 2025 11:39:59 -0700 Subject: [PATCH 4/5] 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 static void writeOptionalArrayRef(DialectBytecodeWriter &writer, ArrayRef storage) { - if (!storage.empty()) { - writer.writeOwnedBool(true); - writer.writeList(storage, [&](EntryTy val) { - if constexpr (std::is_base_of_v) { - (void)writer.writeOptionalAttribute(val); - } else if constexpr (std::is_integral_v) { - (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) { + (void)writer.writeOptionalAttribute(val); + } else if constexpr (std::is_integral_v) { + (void)writer.writeVarInt(val); + } else { + static_assert(true, "EntryTy not supported"); + } + }); } template @@ -72,8 +74,9 @@ static LogicalResult readOptionalArrayRef(DialectBytecodeReader &reader, } else if constexpr (std::is_integral_v) { if (succeeded(reader.readVarInt(temp))) return temp; - } else + } else { static_assert(true, "EntryTy not supported"); + } return failure(); }; From a32459585ad0deda55b27dbed59dc6e9000f851d Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Fri, 10 Oct 2025 15:33:45 -0700 Subject: [PATCH 5/5] Actually enable -verify-roundtrip, remove AliasScopeAttr for now because it cannot roundtrip --- .../Dialect/LLVMIR/LLVMDialectBytecode.td | 11 ----- mlir/test/Dialect/LLVMIR/bytecode.mlir | 48 +------------------ mlir/test/Dialect/LLVMIR/roundtrip.mlir | 3 +- 3 files changed, 2 insertions(+), 60 deletions(-) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td index 7eea9e4d7e1f4..e7b202cd4f63b 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td @@ -61,16 +61,6 @@ class EnumClassFlag : // needed. //===----------------------------------------------------------------------===// -//===----------------------------------------------------------------------===// -// AliasScopeAttr -//===----------------------------------------------------------------------===// - -def AliasScopeAttr : DialectAttribute<(attr - Attr<"Attribute">:$id, - Attr<"AliasScopeDomainAttr">:$domain, - OptionalAttribute<"StringAttr">:$description -)>; - //===----------------------------------------------------------------------===// // DIBasicTypeAttr //===----------------------------------------------------------------------===// @@ -330,7 +320,6 @@ def LoopAnnotationAttr : DialectAttribute<(attr // All the attributes with custom bytecode handling. def LLVMDialectAttributes : DialectAttributes<"LLVM"> { let elems = [ - AliasScopeAttr, DIBasicTypeAttr, DICompileUnitAttr, DICompositeTypeAttr, diff --git a/mlir/test/Dialect/LLVMIR/bytecode.mlir b/mlir/test/Dialect/LLVMIR/bytecode.mlir index b8b95acfd5457..821b0ac2196a5 100644 --- a/mlir/test/Dialect/LLVMIR/bytecode.mlir +++ b/mlir/test/Dialect/LLVMIR/bytecode.mlir @@ -1,4 +1,4 @@ -// RUN: mlir-opt -emit-bytecode %s | mlir-opt --mlir-print-debuginfo | FileCheck %s +// RUN: mlir-opt -verify-roundtrip %s #access_group = #llvm.access_group> #access_group1 = #llvm.access_group> @@ -8,8 +8,6 @@ #loc6 = loc(fused<#di_subprogram>[#loc1]) #loc7 = loc(fused<#di_subprogram>[#loc2]) #loop_annotation = #llvm.loop_annotation -#alias_scope_domain = #llvm.alias_scope_domain, description = "The domain"> -#alias_scope = #llvm.alias_scope, domain = #alias_scope_domain, description = "The domain"> module { llvm.func @imp_fn() { llvm.return loc(#loc2) @@ -19,10 +17,6 @@ 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 @@ -39,43 +33,3 @@ module { #di_imported_entity1 = #llvm.di_imported_entity #di_subprogram1 = #llvm.di_subprogram, 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> -// CHECK: #access_group1 = #llvm.access_group> -// CHECK: #alias_scope_domain = #llvm.alias_scope_domain, description = "The domain"> -// CHECK: #di_subprogram = #llvm.di_subprogram> -// CHECK: {{.*}} = loc("test.f90":12:14) -// CHECK: {{.*}} = loc("test":4:3) -// CHECK: #alias_scope = #llvm.alias_scope, domain = #alias_scope_domain, description = "The domain"> -// CHECK: {{.*}} = loc(fused<#di_subprogram>[{{.*}}]) -// CHECK: {{.*}} = loc(fused<#di_subprogram>[{{.*}}]) -// CHECK: #loop_annotation = #llvm.loop_annotation -// 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: 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 -// 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, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> -// CHECK: #di_compile_unit1 = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> -// CHECK: #di_compile_unit2 = #llvm.di_compile_unit, sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false, emissionKind = Full> -// CHECK: #di_module = #llvm.di_module -// CHECK: #di_module1 = #llvm.di_module -// CHECK: #di_imported_entity = #llvm.di_imported_entity -// CHECK: #di_imported_entity1 = #llvm.di_imported_entity -// CHECK: #di_subprogram1 = #llvm.di_subprogram, 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>[{{.*}}]) diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir index f1dfb6ab456ca..00e763a8ffc04 100644 --- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir +++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir @@ -1,5 +1,4 @@ -// RUN: mlir-opt %s | mlir-opt | FileCheck %s -// RUN: mlir-opt %s -emit-bytecode | mlir-opt | FileCheck %s +// RUN: mlir-opt -verify-roundtrip %s // CHECK-LABEL: func @baz