From f3c694541685334b1630602c5fd93c11639dc67d Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Wed, 9 Oct 2024 11:09:34 -0700 Subject: [PATCH 01/23] [CIR][Lowering][NFC] Expose cir::prepareTypeConverter() Export this function so it can be used by other projects. --- clang/include/clang/CIR/LowerToMLIR.h | 2 ++ clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/CIR/LowerToMLIR.h b/clang/include/clang/CIR/LowerToMLIR.h index 1ddced958cee..bab13bb5700b 100644 --- a/clang/include/clang/CIR/LowerToMLIR.h +++ b/clang/include/clang/CIR/LowerToMLIR.h @@ -19,6 +19,8 @@ namespace cir { void populateCIRLoopToSCFConversionPatterns(mlir::RewritePatternSet &patterns, mlir::TypeConverter &converter); +mlir::TypeConverter prepareTypeConverter(); + mlir::ModuleOp lowerFromCIRToMLIRToLLVMDialect(mlir::ModuleOp theModule, mlir::MLIRContext *mlirCtx = nullptr); diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 326152783980..ebd472d79810 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -1294,7 +1294,7 @@ void populateCIRToMLIRConversionPatterns(mlir::RewritePatternSet &patterns, CIRTrapOpLowering>(converter, patterns.getContext()); } -static mlir::TypeConverter prepareTypeConverter() { +mlir::TypeConverter prepareTypeConverter() { mlir::TypeConverter converter; converter.addConversion([&](cir::PointerType type) -> mlir::Type { auto ty = convertTypeForMemory(converter, type.getPointee()); From 1013314b75a7dd0e78aff5d1c4ebd22ac025619a Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Wed, 20 Nov 2024 14:19:53 -0800 Subject: [PATCH 02/23] [CIR] Add inline interface to CIR dialect This allows the inliner to work with the CIR dialect. --- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 37 ++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 948a955141d6..cc9a16f3ea88 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -41,6 +41,7 @@ #include "mlir/Interfaces/InferTypeOpInterface.h" #include "mlir/Support/LLVM.h" #include "mlir/Support/LogicalResult.h" +#include "mlir/Transforms/InliningUtils.h" using namespace mlir; @@ -117,6 +118,40 @@ struct CIROpAsmDialectInterface : public OpAsmDialectInterface { .Default([](Attribute) { return AliasResult::NoAlias; }); } }; + +// Minimal interface to inline region with only one block for now (not handling +// the terminator remapping), assuming everything is inlinable. +struct CIRInlinerInterface : DialectInlinerInterface { + using DialectInlinerInterface::DialectInlinerInterface; + // Always allows inlining. + bool isLegalToInline(Operation *call, Operation *callable, + bool wouldBeCloned) const final override { + return true; + } + + // Always allows inlining. + bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned, + IRMapping &valueMapping) const final override { + return true; + } + + // Always allows inlining. + bool isLegalToInline(Operation *op, Region *, bool wouldBeCloned, + IRMapping &) const final override { + return true; + } + + // Handle the terminator in the case of a single block + void handleTerminator(Operation *op, + ValueRange valuesToReplace) const final override { + // Only handle cir.return for now + if (auto returnOp = dyn_cast(op)) + for (auto &&[value, operand] : + llvm::zip(valuesToReplace, returnOp.getOperands())) + value.replaceAllUsesWith(operand); + } +}; + } // namespace /// Dialect initialization, the instance will be owned by the context. This is @@ -128,7 +163,7 @@ void cir::CIRDialect::initialize() { #define GET_OP_LIST #include "clang/CIR/Dialect/IR/CIROps.cpp.inc" >(); - addInterfaces(); + addInterfaces(); } Operation *cir::CIRDialect::materializeConstant(mlir::OpBuilder &builder, From e775742039583915419d0f69d2e5c9102f18b26a Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Wed, 4 Dec 2024 14:53:18 -0800 Subject: [PATCH 03/23] [CIR] Add runAtStartOfConvertCIRToMLIRPass() to ConvertCIRToMLIRPass This allows injecting some dialects and patterns to the cir::ConvertCIRToMLIRPass lowering pass. --- clang/include/clang/CIR/LowerToMLIR.h | 3 +++ .../CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/clang/include/clang/CIR/LowerToMLIR.h b/clang/include/clang/CIR/LowerToMLIR.h index bab13bb5700b..490b2a74c972 100644 --- a/clang/include/clang/CIR/LowerToMLIR.h +++ b/clang/include/clang/CIR/LowerToMLIR.h @@ -13,6 +13,7 @@ #define CLANG_CIR_LOWERTOMLIR_H #include "mlir/Transforms/DialectConversion.h" +#include namespace cir { @@ -21,6 +22,8 @@ void populateCIRLoopToSCFConversionPatterns(mlir::RewritePatternSet &patterns, mlir::TypeConverter prepareTypeConverter(); +void runAtStartOfConvertCIRToMLIRPass(std::function); + mlir::ModuleOp lowerFromCIRToMLIRToLLVMDialect(mlir::ModuleOp theModule, mlir::MLIRContext *mlirCtx = nullptr); diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index ebd472d79810..8e5f67785bc0 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +#include + #include "LowerToMLIRHelpers.h" #include "mlir/Conversion/AffineToStandard/AffineToStandard.h" #include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h" @@ -88,6 +90,8 @@ struct ConvertCIRToMLIRPass } StringRef getArgument() const override { return "cir-to-mlir"; } + + inline static std::function runAtStartHook; }; class CIRCallOpLowering : public mlir::OpConversionPattern { @@ -1380,10 +1384,20 @@ void ConvertCIRToMLIRPass::runOnOperation() { mlir::LLVM::LLVMDialect>(); target.addIllegalDialect(); + if (runAtStartHook) + runAtStartHook(target); + if (failed(applyPartialConversion(module, target, std::move(patterns)))) signalPassFailure(); } +/// Set a hook to be called just before applying the dialect conversion so other +/// dialects or patterns can be added +void runAtStartOfConvertCIRToMLIRPass( + std::function hook) { + ConvertCIRToMLIRPass::runAtStartHook = std::move(hook); +} + mlir::ModuleOp lowerFromCIRToMLIRToLLVMDialect(mlir::ModuleOp theModule, mlir::MLIRContext *mlirCtx) { llvm::TimeTraceScope scope("Lower from CIR to MLIR To LLVM Dialect"); From 8bd9a8dcf0b26fbb81541f7868e549432ef7b393 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Wed, 18 Dec 2024 07:19:28 -0800 Subject: [PATCH 04/23] [CIR] Add runAtStartOfConvertCIRToLLVMPass() to ConvertCIRToLLVMPass This allows injecting some dialects and patterns to the cir::direct::ConvertCIRToLLVMPass lowering pass. --- clang/include/clang/CIR/LowerToLLVM.h | 5 +++++ clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/clang/include/clang/CIR/LowerToLLVM.h b/clang/include/clang/CIR/LowerToLLVM.h index dfa4e59b5e1c..530480b67c02 100644 --- a/clang/include/clang/CIR/LowerToLLVM.h +++ b/clang/include/clang/CIR/LowerToLLVM.h @@ -13,7 +13,9 @@ #define CLANG_CIR_LOWERTOLLVM_H #include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" +#include #include namespace llvm { @@ -34,6 +36,9 @@ mlir::ModuleOp lowerDirectlyFromCIRToLLVMDialect(mlir::ModuleOp theModule, bool disableCCLowering = false, bool disableDebugInfo = false); +void runAtStartOfConvertCIRToLLVMPass( + std::function); + // Lower directly from pristine CIR to LLVMIR. std::unique_ptr lowerDirectlyFromCIRToLLVMIR( mlir::ModuleOp theModule, llvm::LLVMContext &llvmCtx, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 4840637171ed..6984efa84e42 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1381,6 +1381,8 @@ struct ConvertCIRToLLVMPass void processCIRAttrs(mlir::ModuleOp moduleOp); + inline static std::function runAtStartHook; + StringRef getDescription() const override { return "Convert the prepared CIR dialect module to LLVM dialect"; } @@ -4781,6 +4783,9 @@ void ConvertCIRToLLVMPass::runOnOperation() { // ,YieldOp >(); // clang-format on + if (runAtStartHook) + runAtStartHook(target); + target.addLegalDialect(); target.addIllegalDialect(); @@ -4818,6 +4823,13 @@ void ConvertCIRToLLVMPass::runOnOperation() { processCIRAttrs(module); } +/// Set a hook to be called just before applying the dialect conversion so other +/// dialects or patterns can be added +void runAtStartOfConvertCIRToLLVMPass( + std::function hook) { + ConvertCIRToLLVMPass::runAtStartHook = std::move(hook); +} + std::unique_ptr createConvertCIRToLLVMPass() { return std::make_unique(); } From e705fadb6f7e88a760b0927dd987ea62332bc9ef Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Tue, 14 Jan 2025 12:51:08 -0800 Subject: [PATCH 05/23] [CIR] Lower struct/union/class to tuple Forward the data layout to the type converter. This is not a current solution since it is not possible for now to have a memref of tuple in MLIR yet. --- clang/include/clang/CIR/LowerToMLIR.h | 2 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 2 +- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 33 +++++++++++++++++-- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/CIR/LowerToMLIR.h b/clang/include/clang/CIR/LowerToMLIR.h index 490b2a74c972..ac505e044c2c 100644 --- a/clang/include/clang/CIR/LowerToMLIR.h +++ b/clang/include/clang/CIR/LowerToMLIR.h @@ -20,7 +20,7 @@ namespace cir { void populateCIRLoopToSCFConversionPatterns(mlir::RewritePatternSet &patterns, mlir::TypeConverter &converter); -mlir::TypeConverter prepareTypeConverter(); +mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout); void runAtStartOfConvertCIRToMLIRPass(std::function); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 6984efa84e42..70a528cd11f7 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -584,7 +584,7 @@ mlir::Value CirAttrToValue::visitCirAttr(cir::ConstArrayAttr constArr) { auto loc = parentOp->getLoc(); mlir::Value result; - if (auto zeros = constArr.getTrailingZerosNum()) { + if (constArr.getTrailingZerosNum()) { auto arrayTy = constArr.getType(); result = rewriter.create( loc, converter->convertType(arrayTy)); diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 8e5f67785bc0..7239ecd980e9 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -1298,7 +1298,7 @@ void populateCIRToMLIRConversionPatterns(mlir::RewritePatternSet &patterns, CIRTrapOpLowering>(converter, patterns.getContext()); } -mlir::TypeConverter prepareTypeConverter() { +mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { mlir::TypeConverter converter; converter.addConversion([&](cir::PointerType type) -> mlir::Type { auto ty = convertTypeForMemory(converter, type.getPointee()); @@ -1361,14 +1361,41 @@ mlir::TypeConverter prepareTypeConverter() { auto ty = converter.convertType(type.getEltType()); return mlir::VectorType::get(type.getSize(), ty); }); + converter.addConversion([&](cir::StructType type) -> mlir::Type { + // FIXME(cir): create separate unions, struct, and classes types. + // Convert struct members. + llvm::SmallVector mlirMembers; + switch (type.getKind()) { + case cir::StructType::Class: + // TODO(cir): This should be properly validated. + case cir::StructType::Struct: + for (auto ty : type.getMembers()) + mlirMembers.push_back(converter.convertType(ty)); + break; + // Unions are lowered as only the largest member. + case cir::StructType::Union: { + auto largestMember = type.getLargestMember(dataLayout); + if (largestMember) + mlirMembers.push_back(converter.convertType(largestMember)); + break; + } + } + + // Struct has a name: lower as an identified struct. + mlir::TupleType tuple; + // FIXME(cir): all the following has to be somehow kept. With some + // attributes? + tuple = mlir::TupleType::get(type.getContext(), mlirMembers); + return tuple; + }); return converter; } void ConvertCIRToMLIRPass::runOnOperation() { auto module = getOperation(); - - auto converter = prepareTypeConverter(); + mlir::DataLayout dataLayout{module}; + auto converter = prepareTypeConverter(dataLayout); mlir::RewritePatternSet patterns(&getContext()); From 3793fc3e43f44d702d6810e4d4150897c1229638 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Wed, 22 Jan 2025 14:31:25 -0800 Subject: [PATCH 06/23] [CIR][MLIR] Allow memref of tuple --- clang/test/CIR/Lowering/ThroughMLIR/struct.cpp | 9 +++++++++ mlir/include/mlir/IR/BuiltinTypes.td | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 clang/test/CIR/Lowering/ThroughMLIR/struct.cpp diff --git a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp new file mode 100644 index 000000000000..497feb821961 --- /dev/null +++ b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-clangir-direct-lowering -emit-mlir %s -o %t.mlir +// RUN: FileCheck --input-file=%t.mlir %s + +struct s { + int a; + float b; +}; +int main() { s v; } +// CHECK: memref> diff --git a/mlir/include/mlir/IR/BuiltinTypes.td b/mlir/include/mlir/IR/BuiltinTypes.td index af474b3e3ec4..72a26c5fad5a 100644 --- a/mlir/include/mlir/IR/BuiltinTypes.td +++ b/mlir/include/mlir/IR/BuiltinTypes.td @@ -1055,7 +1055,7 @@ def Builtin_RankedTensor : Builtin_Type<"RankedTensor", "tensor", [ // TupleType //===----------------------------------------------------------------------===// -def Builtin_Tuple : Builtin_Type<"Tuple", "tuple"> { +def Builtin_Tuple : Builtin_Type<"Tuple", "tuple", [MemRefElementTypeInterface]> { let summary = "Fixed-sized collection of other types"; let description = [{ Syntax: @@ -1145,10 +1145,10 @@ def Builtin_UnrankedMemRef : Builtin_Type<"UnrankedMemRef", "unranked_memref", [ #### Examples: ```mlir - memref<*f32> + memref<*xf32> // An unranked memref with a memory space of 10. - memref<*f32, 10> + memref<*xf32, 10> ``` }]; let parameters = (ins "Type":$elementType, "Attribute":$memorySpace); From ce2133d51471b5a982b201ff833773cdc35ced66 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Wed, 29 Jan 2025 15:25:28 -0800 Subject: [PATCH 07/23] [CIR][MLIR] Add minimal NamedTuple to core MLIR No operation yet. Just lowering to memref> for now. --- .../CIR/Lowering/ThroughMLIR/CMakeLists.txt | 1 + .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 9 ++- .../test/CIR/Lowering/ThroughMLIR/struct.cpp | 2 +- mlir/include/mlir/Dialect/CMakeLists.txt | 1 + .../mlir/Dialect/NamedTuple/CMakeLists.txt | 1 + .../mlir/Dialect/NamedTuple/IR/CMakeLists.txt | 4 + .../mlir/Dialect/NamedTuple/IR/NamedTuple.h | 21 ++++++ .../mlir/Dialect/NamedTuple/IR/NamedTuple.td | 21 ++++++ .../Dialect/NamedTuple/IR/NamedTupleDialect.h | 21 ++++++ .../NamedTuple/IR/NamedTupleDialect.td | 25 +++++++ .../Dialect/NamedTuple/IR/NamedTupleOps.h | 24 ++++++ .../Dialect/NamedTuple/IR/NamedTupleOps.td | 14 ++++ .../Dialect/NamedTuple/IR/NamedTupleTypes.h | 23 ++++++ .../Dialect/NamedTuple/IR/NamedTupleTypes.td | 73 +++++++++++++++++++ mlir/include/mlir/InitAllDialects.h | 2 + mlir/lib/Dialect/CMakeLists.txt | 1 + mlir/lib/Dialect/NamedTuple/CMakeLists.txt | 1 + mlir/lib/Dialect/NamedTuple/IR/CMakeLists.txt | 13 ++++ .../NamedTuple/IR/NamedTupleDialect.cpp | 35 +++++++++ .../Dialect/NamedTuple/IR/NamedTupleOps.cpp | 20 +++++ 20 files changed, 307 insertions(+), 5 deletions(-) create mode 100644 mlir/include/mlir/Dialect/NamedTuple/CMakeLists.txt create mode 100644 mlir/include/mlir/Dialect/NamedTuple/IR/CMakeLists.txt create mode 100644 mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h create mode 100644 mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.td create mode 100644 mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h create mode 100644 mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.td create mode 100644 mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.h create mode 100644 mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.td create mode 100644 mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h create mode 100644 mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td create mode 100644 mlir/lib/Dialect/NamedTuple/CMakeLists.txt create mode 100644 mlir/lib/Dialect/NamedTuple/IR/CMakeLists.txt create mode 100644 mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp create mode 100644 mlir/lib/Dialect/NamedTuple/IR/NamedTupleOps.cpp diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt b/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt index 8c2631ab57d8..89bc98fc0668 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt +++ b/clang/lib/CIR/Lowering/ThroughMLIR/CMakeLists.txt @@ -41,6 +41,7 @@ add_clang_library(clangCIRLoweringThroughMLIR MLIRTransforms MLIRSupport MLIRMemRefDialect + MLIRNamedTupleDialect MLIROpenMPDialect MLIROpenMPToLLVMIRTranslation ) diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 7239ecd980e9..1c4caa3f9704 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -27,6 +27,7 @@ #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/Math/IR/Math.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" +#include "mlir/Dialect/NamedTuple/IR/NamedTuple.h" #include "mlir/Dialect/SCF/IR/SCF.h" #include "mlir/Dialect/Vector/IR/VectorOps.h" #include "mlir/IR/BuiltinDialect.h" @@ -81,6 +82,7 @@ struct ConvertCIRToMLIRPass mlir::affine::AffineDialect, mlir::memref::MemRefDialect, mlir::arith::ArithDialect, mlir::cf::ControlFlowDialect, mlir::scf::SCFDialect, mlir::math::MathDialect, + mlir::named_tuple::NamedTupleDialect, mlir::vector::VectorDialect, mlir::LLVM::LLVMDialect>(); } void runOnOperation() final; @@ -1381,12 +1383,11 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { } } - // Struct has a name: lower as an identified struct. - mlir::TupleType tuple; // FIXME(cir): all the following has to be somehow kept. With some // attributes? - tuple = mlir::TupleType::get(type.getContext(), mlirMembers); - return tuple; + // Struct has a name: lower as an identified struct. + return mlir::named_tuple::NamedTupleType::get( + type.getContext(), type.getName().strref(), mlirMembers); }); return converter; diff --git a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp index 497feb821961..654009cc9e46 100644 --- a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp +++ b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp @@ -6,4 +6,4 @@ struct s { float b; }; int main() { s v; } -// CHECK: memref> +// CHECK: memref> diff --git a/mlir/include/mlir/Dialect/CMakeLists.txt b/mlir/include/mlir/Dialect/CMakeLists.txt index f71023519733..944cdc715a36 100644 --- a/mlir/include/mlir/Dialect/CMakeLists.txt +++ b/mlir/include/mlir/Dialect/CMakeLists.txt @@ -22,6 +22,7 @@ add_subdirectory(MemRef) add_subdirectory(Mesh) add_subdirectory(MLProgram) add_subdirectory(MPI) +add_subdirectory(NamedTuple) add_subdirectory(NVGPU) add_subdirectory(OpenACC) add_subdirectory(OpenACCMPCommon) diff --git a/mlir/include/mlir/Dialect/NamedTuple/CMakeLists.txt b/mlir/include/mlir/Dialect/NamedTuple/CMakeLists.txt new file mode 100644 index 000000000000..f33061b2d87c --- /dev/null +++ b/mlir/include/mlir/Dialect/NamedTuple/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(IR) diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/NamedTuple/IR/CMakeLists.txt new file mode 100644 index 000000000000..224206c53b8e --- /dev/null +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/CMakeLists.txt @@ -0,0 +1,4 @@ +add_mlir_dialect(NamedTuple named_tuple) +add_mlir_doc(NamedTuple NamedTuple Dialects/ -gen-dialect-doc) +add_mlir_doc(NamedTupleOps NamedTupleOps Dialects/ -gen-op-doc) +add_mlir_doc(NamedTupleTypes NamedTupleTypes Dialects/ -gen-typedef-doc) diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h new file mode 100644 index 000000000000..8eedde8da636 --- /dev/null +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the NamedTuple dialect operations. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_H +#define MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_H + +#include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h" +#include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h" + +#include "mlir/Dialect/NamedTuple/IR/NamedTuple.h.inc" + +#endif // MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_H diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.td b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.td new file mode 100644 index 000000000000..d2c8da6b0bed --- /dev/null +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.td @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Main file processed by tablegen to generate the NamedTuple dialect, types and +// operations +// +//===----------------------------------------------------------------------===// + +#ifndef NAMED_TUPLE +#define NAMED_TUPLE + +include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.td" +include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td" +include "mlir/Dialect/NamedTuple/IR/NamedTupleOps.td" + +#endif // NAMED_TUPLE diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h new file mode 100644 index 000000000000..03a9ce5b3df7 --- /dev/null +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the NamedTuple dialect. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_DIALECT_H +#define MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_DIALECT_H + +#include "mlir/IR/Dialect.h" + +#include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h.inc" + + +#endif // MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_DIALECT_H diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.td b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.td new file mode 100644 index 000000000000..0ca80f25acf7 --- /dev/null +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.td @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef NAMED_TUPLE_DIALECT +#define NAMED_TUPLE_DIALECT + +include "mlir/IR/DialectBase.td" + +//===----------------------------------------------------------------------===// +// NamedTuple dialect definition. +//===----------------------------------------------------------------------===// + +def NamedTuple_Dialect : Dialect { + let name = "named_tuple"; + let summary = "NamedTuple dialect providing a tuple type with member names"; + let cppNamespace = "::mlir::named_tuple"; + let useDefaultTypePrinterParser = 1; +} + +#endif // NAMED_TUPLE_DIALECT diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.h b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.h new file mode 100644 index 000000000000..e6aacf73b53d --- /dev/null +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.h @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the operations in the NamedTuple dialect. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_OPS_H +#define MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_OPS_H + +#include "mlir/Bytecode/BytecodeOpInterface.h" +#include "mlir/Dialect/NamedTuple/IR/NamedTuple.h" +#include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h" +#include "mlir/IR/OpDefinition.h" + +#define GET_OP_CLASSES +#include "mlir/Dialect/NamedTuple/IR/NamedTupleOps.h.inc" + +#endif // MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_OPS_H diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.td b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.td new file mode 100644 index 000000000000..08bf3036935d --- /dev/null +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.td @@ -0,0 +1,14 @@ +//===----------------------------------------------------------------------===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef NAMED_TUPLE_OPS +#define NAMED_TUPLE_OPS + +include "mlir/IR/OpAsmInterface.td" + +#endif // NAMED_TUPLE_OPS diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h new file mode 100644 index 000000000000..e699892abc3d --- /dev/null +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the types in the NamedTuple dialect. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_TYPES_H +#define MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_TYPES_H + +//#include "mlir/Bytecode/BytecodeOpInterface.h" +#include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h" +//#include "mlir/IR/OpDefinition.h" + +#define GET_TYPEDEF_CLASSES +#include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h.inc" + +#endif // MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_TYPES_H diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td new file mode 100644 index 000000000000..7a64fac2e6b6 --- /dev/null +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef NAMED_TUPLE_TYPES +#define NAMED_TUPLE_TYPES + +include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.td" +include "mlir/Interfaces/DataLayoutInterfaces.td" +include "mlir/IR/AttrTypeBase.td" +include "mlir/IR/BuiltinAttributes.td" +include "mlir/IR/BuiltinTypeInterfaces.td" +include "mlir/IR/BuiltinTypes.td" +include "mlir/IR/Traits.td" + +//===----------------------------------------------------------------------===// +// NamedTupletype definitions +//===----------------------------------------------------------------------===// + +class NamedTuple_Type traits = []> + : TypeDef { + let mnemonic = typeMnemonic; +} + +def NamedTuple_NamedTupleType : NamedTuple_Type<"NamedTuple", "named_tuple", [ + MemRefElementTypeInterface//, + //DeclareTypeInterfaceMethods + ]> { + let summary = "Fixed-sized collection of other types with a name for each" + " type"; + let description = [{ + }]; + let parameters = (ins "StringAttr":$name, Builtin_ArrayAttr:$member_types); + let assemblyFormat = "`<` $name `,` $member_types `>`"; + let builders = [ + TypeBuilder<(ins "StringRef":$name, "ArrayRef":$types), [{ + llvm::SmallVector typeAttrs; + for (auto &t : types) + typeAttrs.push_back(mlir::TypeAttr::get(t)); + return $_get($_ctxt, mlir::StringAttr::get($_ctxt, name), + mlir::ArrayAttr::get($_ctxt, typeAttrs)); + }]>, + // Empty tuple + TypeBuilder<(ins "StringRef":$name), [{ + return $_get($_ctxt, mlir::StringAttr::get($_ctxt, name), + mlir::ArrayAttr::get($_ctxt, + std::array{})); + }]> + ]; + + // let extraClassDeclaration = [{ + // /// Return the number of held types. + // size_t size() const; + + // /// Iterate over the held elements. + // using iterator = ArrayRef::iterator; + // iterator begin() const { return getTypes().begin(); } + // iterator end() const { return getTypes().end(); } + + // /// Return the element type at index 'index'. + // Type getType(size_t index) const { + // assert(index < size() && "invalid index for tuple type"); + // return getTypes()[index]; + // } + // }]; +} + +#endif // NAMED_TUPLE_TYPES diff --git a/mlir/include/mlir/InitAllDialects.h b/mlir/include/mlir/InitAllDialects.h index 33bc89279c08..0781aea8b7c1 100644 --- a/mlir/include/mlir/InitAllDialects.h +++ b/mlir/include/mlir/InitAllDialects.h @@ -60,6 +60,7 @@ #include "mlir/Dialect/MemRef/Transforms/BufferViewFlowOpInterfaceImpl.h" #include "mlir/Dialect/MemRef/Transforms/RuntimeOpVerification.h" #include "mlir/Dialect/Mesh/IR/MeshDialect.h" +#include "mlir/Dialect/NamedTuple/IR/NamedTuple.h" #include "mlir/Dialect/NVGPU/IR/NVGPUDialect.h" #include "mlir/Dialect/OpenACC/OpenACC.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" @@ -132,6 +133,7 @@ inline void registerAllDialects(DialectRegistry ®istry) { mesh::MeshDialect, ml_program::MLProgramDialect, mpi::MPIDialect, + named_tuple::NamedTupleDialect, nvgpu::NVGPUDialect, NVVM::NVVMDialect, omp::OpenMPDialect, diff --git a/mlir/lib/Dialect/CMakeLists.txt b/mlir/lib/Dialect/CMakeLists.txt index 80b0ef068d96..0a3abb934a5e 100644 --- a/mlir/lib/Dialect/CMakeLists.txt +++ b/mlir/lib/Dialect/CMakeLists.txt @@ -22,6 +22,7 @@ add_subdirectory(MemRef) add_subdirectory(Mesh) add_subdirectory(MLProgram) add_subdirectory(MPI) +add_subdirectory(NamedTuple) add_subdirectory(NVGPU) add_subdirectory(OpenACC) add_subdirectory(OpenACCMPCommon) diff --git a/mlir/lib/Dialect/NamedTuple/CMakeLists.txt b/mlir/lib/Dialect/NamedTuple/CMakeLists.txt new file mode 100644 index 000000000000..f33061b2d87c --- /dev/null +++ b/mlir/lib/Dialect/NamedTuple/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(IR) diff --git a/mlir/lib/Dialect/NamedTuple/IR/CMakeLists.txt b/mlir/lib/Dialect/NamedTuple/IR/CMakeLists.txt new file mode 100644 index 000000000000..196e2c5f2112 --- /dev/null +++ b/mlir/lib/Dialect/NamedTuple/IR/CMakeLists.txt @@ -0,0 +1,13 @@ +add_mlir_dialect_library(MLIRNamedTupleDialect + NamedTupleDialect.cpp + NamedTupleOps.cpp + + ADDITIONAL_HEADER_DIRS + ${PROJECT_SOURCE_DIR}/include/mlir/Dialect/NamedTuple + + DEPENDS + MLIRNamedTupleIncGen + + LINK_LIBS PUBLIC + MLIRIR +) diff --git a/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp b/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp new file mode 100644 index 000000000000..524f71d9a135 --- /dev/null +++ b/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Concrete implementation of NamedTuple dialect +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/TypeSwitch.h" +#include "mlir/Dialect/NamedTuple/IR/NamedTuple.h" +#include "mlir/IR/Builders.h" +#include "mlir/IR/DialectImplementation.h" + +#include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.cpp.inc" + +#define GET_TYPEDEF_CLASSES +#include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.cpp.inc" + +void mlir::named_tuple::NamedTupleDialect::initialize() { + // Add the defined types to the dialect. + addTypes< +#define GET_TYPEDEF_LIST +#include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.cpp.inc" + >(); + + // Add the defined operations to the dialect. + addOperations< +#define GET_OP_LIST +#include "mlir/Dialect/NamedTuple/IR/NamedTuple.cpp.inc" + >(); +} diff --git a/mlir/lib/Dialect/NamedTuple/IR/NamedTupleOps.cpp b/mlir/lib/Dialect/NamedTuple/IR/NamedTupleOps.cpp new file mode 100644 index 000000000000..d5d30762e079 --- /dev/null +++ b/mlir/lib/Dialect/NamedTuple/IR/NamedTupleOps.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Concrete implementation of NamedTuple operations +// +//===----------------------------------------------------------------------===// + +#include "mlir/Dialect/NamedTuple/IR/NamedTuple.h" + +//===----------------------------------------------------------------------===// +// TableGen'd op method definitions +//===----------------------------------------------------------------------===// + +#define GET_OP_CLASSES +#include "mlir/Dialect/NamedTuple/IR/NamedTuple.cpp.inc" From 762695a212b1c90d22031bc07bb23e24a7f98d41 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Mon, 10 Feb 2025 15:06:29 -0800 Subject: [PATCH 08/23] [CIR][MLIR] named_tuple.cast operation WIP memref cast operation for NamedTuple hack. The `named_tuple.cast` operation converts a memref of `named_tuple` to a 1D memref of `i8` of the same size to emulate later the struct element access. Example: %0 = named_tuple.cast %alloca_0 : memref> to memref<8xi8> loc(#loc6) --- .../mlir/Dialect/NamedTuple/IR/NamedTuple.h | 2 + .../Dialect/NamedTuple/IR/NamedTupleOps.td | 33 +++++++++++++++- .../Dialect/NamedTuple/IR/NamedTupleTypes.h | 3 +- .../Dialect/NamedTuple/IR/NamedTupleTypes.td | 15 ++++---- mlir/lib/Dialect/NamedTuple/IR/CMakeLists.txt | 1 - .../NamedTuple/IR/NamedTupleDialect.cpp | 38 ++++++++++++++++++- .../Dialect/NamedTuple/IR/NamedTupleOps.cpp | 20 ---------- 7 files changed, 79 insertions(+), 33 deletions(-) delete mode 100644 mlir/lib/Dialect/NamedTuple/IR/NamedTupleOps.cpp diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h index 8eedde8da636..2e97b9b193c7 100644 --- a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h @@ -13,9 +13,11 @@ #ifndef MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_H #define MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_H +//#include "mlir/IR/Dialect.h" #include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h" #include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h" +#define GET_OP_CLASSES #include "mlir/Dialect/NamedTuple/IR/NamedTuple.h.inc" #endif // MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_H diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.td b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.td index 08bf3036935d..ad223ee2fdd3 100644 --- a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.td +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleOps.td @@ -9,6 +9,37 @@ #ifndef NAMED_TUPLE_OPS #define NAMED_TUPLE_OPS -include "mlir/IR/OpAsmInterface.td" +include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.td" +include "mlir/Dialect/Arith/IR/ArithBase.td" +include "mlir/Interfaces/CastInterfaces.td" +include "mlir/Interfaces/SideEffectInterfaces.td" +include "mlir/IR/OpBase.td" + +class NamedTuple_Op traits = []> + : Op; + +//===----------------------------------------------------------------------===// +// CastOp +//===----------------------------------------------------------------------===// + +def NamedTuple_CastOp : NamedTuple_Op<"cast", [ + DeclareOpInterfaceMethods, + Pure, + ]> { + let summary = "WIP memref cast operation for NamedTuple hack"; + let description = [{ + The `named_tuple.cast` operation converts a memref of `named_tuple` to a 1D memref of `i8` of the same size to emulate later the struct element access. + + Example: + + ```mlir + %0 = named_tuple.cast %alloca_0 : memref> to memref<8xi8> loc(#loc6) + ``` + }]; + + let arguments = (ins AnyRankedOrUnrankedMemRef:$source); + let results = (outs AnyRankedOrUnrankedMemRef:$dest); + let assemblyFormat = "$source attr-dict `:` type($source) `to` type($dest)"; +} #endif // NAMED_TUPLE_OPS diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h index e699892abc3d..d375ba5b9c30 100644 --- a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h @@ -13,9 +13,8 @@ #ifndef MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_TYPES_H #define MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_TYPES_H -//#include "mlir/Bytecode/BytecodeOpInterface.h" #include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h" -//#include "mlir/IR/OpDefinition.h" +#include "mlir/Interfaces/DataLayoutInterfaces.h" #define GET_TYPEDEF_CLASSES #include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h.inc" diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td index 7a64fac2e6b6..69162dabb89b 100644 --- a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td @@ -27,12 +27,10 @@ class NamedTuple_Type traits = []> } def NamedTuple_NamedTupleType : NamedTuple_Type<"NamedTuple", "named_tuple", [ - MemRefElementTypeInterface//, - //DeclareTypeInterfaceMethods + MemRefElementTypeInterface, + DeclareTypeInterfaceMethods ]> { - let summary = "Fixed-sized collection of other types with a name for each" - " type"; + let summary = "Fixed-sized collection of other types with a name"; let description = [{ }]; let parameters = (ins "StringAttr":$name, Builtin_ArrayAttr:$member_types); @@ -41,9 +39,9 @@ def NamedTuple_NamedTupleType : NamedTuple_Type<"NamedTuple", "named_tuple", [ TypeBuilder<(ins "StringRef":$name, "ArrayRef":$types), [{ llvm::SmallVector typeAttrs; for (auto &t : types) - typeAttrs.push_back(mlir::TypeAttr::get(t)); - return $_get($_ctxt, mlir::StringAttr::get($_ctxt, name), - mlir::ArrayAttr::get($_ctxt, typeAttrs)); + typeAttrs.push_back(mlir::TypeAttr::get(t)); + return $_get($_ctxt, mlir::StringAttr::get($_ctxt, name), + mlir::ArrayAttr::get($_ctxt, typeAttrs)); }]>, // Empty tuple TypeBuilder<(ins "StringRef":$name), [{ @@ -53,6 +51,7 @@ def NamedTuple_NamedTupleType : NamedTuple_Type<"NamedTuple", "named_tuple", [ }]> ]; + // \todo // let extraClassDeclaration = [{ // /// Return the number of held types. // size_t size() const; diff --git a/mlir/lib/Dialect/NamedTuple/IR/CMakeLists.txt b/mlir/lib/Dialect/NamedTuple/IR/CMakeLists.txt index 196e2c5f2112..bfc0ebee48d8 100644 --- a/mlir/lib/Dialect/NamedTuple/IR/CMakeLists.txt +++ b/mlir/lib/Dialect/NamedTuple/IR/CMakeLists.txt @@ -1,6 +1,5 @@ add_mlir_dialect_library(MLIRNamedTupleDialect NamedTupleDialect.cpp - NamedTupleOps.cpp ADDITIONAL_HEADER_DIRS ${PROJECT_SOURCE_DIR}/include/mlir/Dialect/NamedTuple diff --git a/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp b/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp index 524f71d9a135..67c65f8a35f1 100644 --- a/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp +++ b/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp @@ -10,16 +10,52 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/TypeSwitch.h" +#include "mlir/Dialect/MemRef/IR/MemRef.h" #include "mlir/Dialect/NamedTuple/IR/NamedTuple.h" #include "mlir/IR/Builders.h" #include "mlir/IR/DialectImplementation.h" +#include "llvm/ADT/TypeSwitch.h" +#include "llvm/Support/ErrorHandling.h" #include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.cpp.inc" #define GET_TYPEDEF_CLASSES #include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.cpp.inc" +// Dummy implementation for now +// TODO(cir) +llvm::TypeSize mlir::named_tuple::NamedTupleType::getTypeSizeInBits( + mlir::DataLayout const &, + llvm::ArrayRef) const { + llvm_unreachable("getTypeSizeInBits() not implemented"); + return llvm::TypeSize::getFixed(8); +} + +uint64_t mlir::named_tuple::NamedTupleType::getABIAlignment( + mlir::DataLayout const &, + llvm::ArrayRef) const { + llvm_unreachable("getABIAlignment() not implemented"); + return 8; +} + +uint64_t mlir::named_tuple::NamedTupleType::getPreferredAlignment( + mlir::DataLayout const &, + llvm::ArrayRef) const { + llvm_unreachable("getPreferredAlignment() not implemented"); + return 8; +} + +//===----------------------------------------------------------------------===// +// TableGen'd op method definitions +//===----------------------------------------------------------------------===// +#define GET_OP_CLASSES +#include "mlir/Dialect/NamedTuple/IR/NamedTuple.cpp.inc" + +bool mlir::named_tuple::CastOp::areCastCompatible(mlir::TypeRange inputs, + mlir::TypeRange outputs) { + return true; +} + void mlir::named_tuple::NamedTupleDialect::initialize() { // Add the defined types to the dialect. addTypes< diff --git a/mlir/lib/Dialect/NamedTuple/IR/NamedTupleOps.cpp b/mlir/lib/Dialect/NamedTuple/IR/NamedTupleOps.cpp deleted file mode 100644 index d5d30762e079..000000000000 --- a/mlir/lib/Dialect/NamedTuple/IR/NamedTupleOps.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Concrete implementation of NamedTuple operations -// -//===----------------------------------------------------------------------===// - -#include "mlir/Dialect/NamedTuple/IR/NamedTuple.h" - -//===----------------------------------------------------------------------===// -// TableGen'd op method definitions -//===----------------------------------------------------------------------===// - -#define GET_OP_CLASSES -#include "mlir/Dialect/NamedTuple/IR/NamedTuple.cpp.inc" From a09a2e8e6d45a20c859de5593fb16967d05627b9 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Mon, 10 Feb 2025 18:20:08 -0800 Subject: [PATCH 09/23] [CIR][MLIR] Add some named_tuple type introspection functions --- .../Dialect/NamedTuple/IR/NamedTupleTypes.td | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td index 69162dabb89b..31b22f29cd5e 100644 --- a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleTypes.td @@ -51,22 +51,25 @@ def NamedTuple_NamedTupleType : NamedTuple_Type<"NamedTuple", "named_tuple", [ }]> ]; - // \todo - // let extraClassDeclaration = [{ - // /// Return the number of held types. - // size_t size() const; + let extraClassDeclaration = [{ + /// Return the number of held types. + size_t size() const { + return getMemberTypes().size(); + } - // /// Iterate over the held elements. - // using iterator = ArrayRef::iterator; - // iterator begin() const { return getTypes().begin(); } - // iterator end() const { return getTypes().end(); } + // TODO: needs a more complex iterator since the storage is not an + // ArrayRef. + /// Iterate over the held elements. + // using iterator = ArrayRef::iterator; + // iterator begin() const { return getTypes().begin(); } + // iterator end() const { return getTypes().end(); } - // /// Return the element type at index 'index'. - // Type getType(size_t index) const { - // assert(index < size() && "invalid index for tuple type"); - // return getTypes()[index]; - // } - // }]; + /// Return the element type at index 'index'. + Type getType(size_t index) const { + assert(index < size() && "invalid index for named_tuple type"); + return mlir::cast(getMemberTypes()[index]).getValue(); + } + }]; } #endif // NAMED_TUPLE_TYPES From 12626d19976cb8a4db833cb0377e2e0ce58343a9 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Mon, 10 Feb 2025 18:25:20 -0800 Subject: [PATCH 10/23] [CIR] Lower cir.get_member to named_tuple + memref casts Emulate the member access through memory for now. --- clang/include/clang/CIR/LowerToMLIR.h | 3 +- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 86 ++++++++++++++++++- .../test/CIR/Lowering/ThroughMLIR/struct.cpp | 37 +++++++- .../mlir/Dialect/NamedTuple/IR/NamedTuple.h | 1 - mlir/include/mlir/InitAllDialects.h | 2 +- 5 files changed, 119 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/CIR/LowerToMLIR.h b/clang/include/clang/CIR/LowerToMLIR.h index ac505e044c2c..9a60d979aa9c 100644 --- a/clang/include/clang/CIR/LowerToMLIR.h +++ b/clang/include/clang/CIR/LowerToMLIR.h @@ -22,7 +22,8 @@ void populateCIRLoopToSCFConversionPatterns(mlir::RewritePatternSet &patterns, mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout); -void runAtStartOfConvertCIRToMLIRPass(std::function); +void runAtStartOfConvertCIRToMLIRPass( + std::function); mlir::ModuleOp lowerFromCIRToMLIRToLLVMDialect(mlir::ModuleOp theModule, diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 1c4caa3f9704..e4c3c0756155 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -27,10 +27,16 @@ #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/Math/IR/Math.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" +#include "mlir/Dialect/MemRef/Utils/MemRefUtils.h" #include "mlir/Dialect/NamedTuple/IR/NamedTuple.h" +#include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h" +#include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h" #include "mlir/Dialect/SCF/IR/SCF.h" #include "mlir/Dialect/Vector/IR/VectorOps.h" +#include "mlir/IR/Attributes.h" +#include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/BuiltinDialect.h" +#include "mlir/IR/BuiltinOps.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/Operation.h" #include "mlir/IR/Region.h" @@ -45,12 +51,14 @@ #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Export.h" #include "mlir/Transforms/DialectConversion.h" +#include "clang/CIR/Dialect/IR/CIRDataLayout.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/LowerToLLVM.h" #include "clang/CIR/LowerToMLIR.h" #include "clang/CIR/LoweringHelpers.h" #include "clang/CIR/Passes.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TypeSwitch.h" @@ -172,7 +180,7 @@ class CIRAllocaOpLowering : public mlir::OpConversionPattern { mlir::Type mlirType = convertTypeForMemory(*getTypeConverter(), adaptor.getAllocaType()); - // FIXME: Some types can not be converted yet (e.g. struct) + // FIXME: Some types can not be converted yet if (!mlirType) return mlir::LogicalResult::failure(); @@ -281,6 +289,71 @@ class CIRStoreOpLowering : public mlir::OpConversionPattern { } }; +// Lower cir.get_member +// +// clang-format off +// +// %5 = cir.get_member %1[1] {name = "b"} : !cir.ptr> -> !cir.ptr +// +// to something like +// +// %1 = named_tuple.cast %alloca_0 : memref> to memref<24xi8> +// %c8 = arith.constant 8 : index +// %view_1 = memref.view %1[%c8][] : memref<24xi8> to memref +// clang-format on +class CIRGetMemberOpLowering + : public mlir::OpConversionPattern { + cir::CIRDataLayout const &dataLayout; + +public: + using mlir::OpConversionPattern::OpConversionPattern; + + CIRGetMemberOpLowering(const mlir::TypeConverter &typeConverter, + mlir::MLIRContext *context, + cir::CIRDataLayout const &dataLayout) + : OpConversionPattern{typeConverter, context}, dataLayout{dataLayout} {} + + mlir::LogicalResult + matchAndRewrite(cir::GetMemberOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + auto pointeeType = op.getAddrTy().getPointee(); + if (!mlir::isa(pointeeType)) + op.emitError("GetMemberOp only works on pointer to cir::StructType"); + auto structType = mlir::cast(pointeeType); + // For now, just rely on the datalayout of the high-level type since the + // datalayout of low-level type is not implemented yet. But since C++ is a + // concrete datalayout, both datalayouts are the same. + auto *structLayout = dataLayout.getStructLayout(structType); + + // Get the lowered type: memref> + auto memref = mlir::cast(adaptor.getAddr().getType()); + // Alias the memref of struct to a memref of an i8 array of the same size. + const std::array linearizedSize{ + static_cast(dataLayout.getTypeStoreSize(structType))}; + auto flattenMemRef = mlir::MemRefType::get( + linearizedSize, mlir::IntegerType::get(memref.getContext(), 8)); + // Use a special cast because normal memref cast cannot do such an extreme + // cast. + auto bytesMemRef = rewriter.create( + op.getLoc(), mlir::TypeRange{flattenMemRef}, + mlir::ValueRange{adaptor.getAddr()}); + + auto memberIndex = op.getIndex(); + auto namedTupleType = + mlir::cast(memref.getElementType()); + // The lowered type of the element to access in the named_tuple. + auto loweredMemberType = namedTupleType.getType(memberIndex); + auto elementMemRefTy = mlir::MemRefType::get({}, loweredMemberType); + auto offset = structLayout->getElementOffset(memberIndex); + // Synthesize the byte access to right lowered type. + auto byteShift = + rewriter.create(op.getLoc(), offset); + rewriter.replaceOpWithNewOp( + op, elementMemRefTy, bytesMemRef, byteShift, mlir::ValueRange{}); + return mlir::LogicalResult::success(); + } +}; + /// Converts CIR unary math ops (e.g., cir::SinOp) to their MLIR equivalents /// (e.g., math::SinOp) using a generic template to avoid redundant boilerplate /// matchAndRewrite definitions. @@ -1277,7 +1350,8 @@ class CIRTrapOpLowering : public mlir::OpConversionPattern { }; void populateCIRToMLIRConversionPatterns(mlir::RewritePatternSet &patterns, - mlir::TypeConverter &converter) { + mlir::TypeConverter &converter, + cir::CIRDataLayout &cirDataLayout) { patterns.add(patterns.getContext()); patterns @@ -1298,6 +1372,8 @@ void populateCIRToMLIRConversionPatterns(mlir::RewritePatternSet &patterns, CIRVectorExtractLowering, CIRVectorCmpOpLowering, CIRACosOpLowering, CIRASinOpLowering, CIRUnreachableOpLowering, CIRTanOpLowering, CIRTrapOpLowering>(converter, patterns.getContext()); + patterns.add(converter, patterns.getContext(), + cirDataLayout); } mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { @@ -1354,7 +1430,7 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { curType = arrayType.getEltType(); } auto elementType = converter.convertType(curType); - // FIXME: The element type might not be converted (e.g. struct) + // FIXME: The element type might not be converted if (!elementType) return nullptr; return mlir::MemRefType::get(shape, elementType); @@ -1396,12 +1472,13 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { void ConvertCIRToMLIRPass::runOnOperation() { auto module = getOperation(); mlir::DataLayout dataLayout{module}; + cir::CIRDataLayout cirDataLayout{module}; auto converter = prepareTypeConverter(dataLayout); mlir::RewritePatternSet patterns(&getContext()); populateCIRLoopToSCFConversionPatterns(patterns, converter); - populateCIRToMLIRConversionPatterns(patterns, converter); + populateCIRToMLIRConversionPatterns(patterns, converter, cirDataLayout); mlir::ConversionTarget target(getContext()); target.addLegalOp(); @@ -1409,6 +1486,7 @@ void ConvertCIRToMLIRPass::runOnOperation() { mlir::memref::MemRefDialect, mlir::func::FuncDialect, mlir::scf::SCFDialect, mlir::cf::ControlFlowDialect, mlir::math::MathDialect, mlir::vector::VectorDialect, + mlir::named_tuple::NamedTupleDialect, mlir::LLVM::LLVMDialect>(); target.addIllegalDialect(); diff --git a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp index 654009cc9e46..faf250a24351 100644 --- a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp +++ b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp @@ -3,7 +3,38 @@ struct s { int a; - float b; + double b; + char c; }; -int main() { s v; } -// CHECK: memref> + +int main() { + s v; + // CHECK: %[[ALLOCA:.+]] = memref.alloca() {alignment = 8 : i64} : memref> + v.a = 7; + // CHECK: %[[C_7:.+]] = arith.constant 7 : i32 + // CHECK: %[[I8_EQUIV_A:.+]] = named_tuple.cast %[[ALLOCA]] : memref> to memref<24xi8> + // CHECK: %[[OFFSET_A:.+]] = arith.constant 0 : index + // CHECK: %[[VIEW_A:.+]] = memref.view %[[I8_EQUIV_A]][%[[OFFSET_A]]][] : memref<24xi8> to memref + // CHECK: memref.store %[[C_7]], %[[VIEW_A]][] : memref + + v.b = 3.; + // CHECK: %[[C_3:.+]] = arith.constant 3.000000e+00 : f64 + // CHECK: %[[I8_EQUIV_B:.+]] = named_tuple.cast %[[ALLOCA]] : memref> to memref<24xi8> + // CHECK: %[[OFFSET_B:.+]] = arith.constant 8 : index + // CHECK: %[[VIEW_B:.+]] = memref.view %[[I8_EQUIV_B]][%[[OFFSET_B]]][] : memref<24xi8> to memref + // CHECK: memref.store %[[C_3]], %[[VIEW_B]][] : memref + + v.c = 'z'; + // CHECK: %[[C_122:.+]] = arith.constant 122 : i8 + // CHECK: %[[I8_EQUIV_C:.+]] = named_tuple.cast %[[ALLOCA]] : memref> to memref<24xi8> + // CHECK: %[[OFFSET_C:.+]] = arith.constant 16 : index + // CHECK: %[[VIEW_C:.+]] = memref.view %[[I8_EQUIV_C]][%[[OFFSET_C]]][] : memref<24xi8> to memref + // memref.store %[[C_122]], %[[VIEW_C]][] : memref + + return v.c; + // CHECK: %[[I8_EQUIV_C_1:.+]] = named_tuple.cast %[[ALLOCA]] : memref> to memref<24xi8> + // CHECK: %[[OFFSET_C_1:.+]] = arith.constant 16 : index + // CHECK: %[[VIEW_C_1:.+]] = memref.view %[[I8_EQUIV_C_1]][%[[OFFSET_C_1]]][] : memref<24xi8> to memref + // CHECK: %[[VALUE_C:.+]] = memref.load %[[VIEW_C_1]][] : memref + // CHECK: %[[VALUE_RET:.+]] = arith.extsi %[[VALUE_C]] : i8 to i32 + } diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h index 2e97b9b193c7..79bc3ac601fc 100644 --- a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTuple.h @@ -13,7 +13,6 @@ #ifndef MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_H #define MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_H -//#include "mlir/IR/Dialect.h" #include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h" #include "mlir/Dialect/NamedTuple/IR/NamedTupleTypes.h" diff --git a/mlir/include/mlir/InitAllDialects.h b/mlir/include/mlir/InitAllDialects.h index 0781aea8b7c1..242eca648b5f 100644 --- a/mlir/include/mlir/InitAllDialects.h +++ b/mlir/include/mlir/InitAllDialects.h @@ -60,8 +60,8 @@ #include "mlir/Dialect/MemRef/Transforms/BufferViewFlowOpInterfaceImpl.h" #include "mlir/Dialect/MemRef/Transforms/RuntimeOpVerification.h" #include "mlir/Dialect/Mesh/IR/MeshDialect.h" -#include "mlir/Dialect/NamedTuple/IR/NamedTuple.h" #include "mlir/Dialect/NVGPU/IR/NVGPUDialect.h" +#include "mlir/Dialect/NamedTuple/IR/NamedTuple.h" #include "mlir/Dialect/OpenACC/OpenACC.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/Dialect/PDL/IR/PDL.h" From 64a0abd9292a46e9d6613f3fa03294e6c4be5ca7 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Fri, 14 Feb 2025 10:17:47 -0800 Subject: [PATCH 11/23] [CIR] Lower to MLIR struct with array member Do not go through a memref of memref. --- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 10 ++++-- .../test/CIR/Lowering/ThroughMLIR/struct.cpp | 32 +++++++++++++------ .../Dialect/NamedTuple/IR/NamedTupleDialect.h | 1 - 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index e4c3c0756155..fdd04ed417b6 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -343,7 +343,13 @@ class CIRGetMemberOpLowering mlir::cast(memref.getElementType()); // The lowered type of the element to access in the named_tuple. auto loweredMemberType = namedTupleType.getType(memberIndex); - auto elementMemRefTy = mlir::MemRefType::get({}, loweredMemberType); + // memref.view can only cast to another memref. Wrap the target type if it + // is not already a memref (like with a struct with an array member) + mlir::MemRefType elementMemRefTy; + if (mlir::isa(loweredMemberType)) + elementMemRefTy = mlir::cast(loweredMemberType); + else + elementMemRefTy = mlir::MemRefType::get({}, loweredMemberType); auto offset = structLayout->getElementOffset(memberIndex); // Synthesize the byte access to right lowered type. auto byteShift = @@ -1262,7 +1268,7 @@ class CIRPtrStrideOpLowering // Return true if all the PtrStrideOp users are load, store or cast // with array_to_ptrdecay kind and they are in the same block. - inline bool isLoadStoreOrCastArrayToPtrProduer(cir::PtrStrideOp op) const { + inline bool isLoadStoreOrCastArrayToPtrProducer(cir::PtrStrideOp op) const { if (op.use_empty()) return false; for (auto *user : op->getUsers()) { diff --git a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp index faf250a24351..5be0b690f9ec 100644 --- a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp +++ b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp @@ -1,40 +1,52 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-clangir-direct-lowering -emit-mlir %s -o %t.mlir // RUN: FileCheck --input-file=%t.mlir %s +// Check the MLIR lowering of struct and member accesses struct s { int a; double b; char c; + float d[5]; }; int main() { s v; - // CHECK: %[[ALLOCA:.+]] = memref.alloca() {alignment = 8 : i64} : memref> + // CHECK: %[[ALLOCA:.+]] = memref.alloca() {alignment = 8 : i64} : memref]>> v.a = 7; // CHECK: %[[C_7:.+]] = arith.constant 7 : i32 - // CHECK: %[[I8_EQUIV_A:.+]] = named_tuple.cast %[[ALLOCA]] : memref> to memref<24xi8> + // CHECK: %[[I8_EQUIV_A:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> // CHECK: %[[OFFSET_A:.+]] = arith.constant 0 : index - // CHECK: %[[VIEW_A:.+]] = memref.view %[[I8_EQUIV_A]][%[[OFFSET_A]]][] : memref<24xi8> to memref + // CHECK: %[[VIEW_A:.+]] = memref.view %[[I8_EQUIV_A]][%[[OFFSET_A]]][] : memref<40xi8> to memref // CHECK: memref.store %[[C_7]], %[[VIEW_A]][] : memref v.b = 3.; // CHECK: %[[C_3:.+]] = arith.constant 3.000000e+00 : f64 - // CHECK: %[[I8_EQUIV_B:.+]] = named_tuple.cast %[[ALLOCA]] : memref> to memref<24xi8> + // CHECK: %[[I8_EQUIV_B:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> // CHECK: %[[OFFSET_B:.+]] = arith.constant 8 : index - // CHECK: %[[VIEW_B:.+]] = memref.view %[[I8_EQUIV_B]][%[[OFFSET_B]]][] : memref<24xi8> to memref + // CHECK: %[[VIEW_B:.+]] = memref.view %[[I8_EQUIV_B]][%[[OFFSET_B]]][] : memref<40xi8> to memref // CHECK: memref.store %[[C_3]], %[[VIEW_B]][] : memref v.c = 'z'; - // CHECK: %[[C_122:.+]] = arith.constant 122 : i8 - // CHECK: %[[I8_EQUIV_C:.+]] = named_tuple.cast %[[ALLOCA]] : memref> to memref<24xi8> + // CHECK: %[[C_122:.+]] = arith.constant 122 : i8 + // CHECK: %[[I8_EQUIV_C:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> // CHECK: %[[OFFSET_C:.+]] = arith.constant 16 : index - // CHECK: %[[VIEW_C:.+]] = memref.view %[[I8_EQUIV_C]][%[[OFFSET_C]]][] : memref<24xi8> to memref + // CHECK: %[[VIEW_C:.+]] = memref.view %[[I8_EQUIV_C]][%[[OFFSET_C]]][] : memref<40xi8> to memref // memref.store %[[C_122]], %[[VIEW_C]][] : memref + v.d[4] = 6.f; + // CHECK: %[[C_6:.+]] = arith.constant 6.000000e+00 : f32 + // CHECK: %[[I8_EQUIV_D:.+]] = named_tuple.cast %alloca_0 : memref]>> to memref<40xi8> + // CHECK: %[[OFFSET_D:.+]] = arith.constant 20 : index + // Do not lower to a memref of memref + // CHECK: %[[VIEW_D:.+]] = memref.view %3[%c20][] : memref<40xi8> to memref<5xf32> + // CHECK: %[[C_4:.+]] = arith.constant 4 : i32 + // CHECK: %[[I_D:.+]] = arith.index_cast %[[C_4]] : i32 to index + // CHECK: memref.store %[[C_6]], %[[VIEW_D]][%[[I_D]]] : memref<5xf32> + return v.c; - // CHECK: %[[I8_EQUIV_C_1:.+]] = named_tuple.cast %[[ALLOCA]] : memref> to memref<24xi8> + // CHECK: %[[I8_EQUIV_C_1:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> // CHECK: %[[OFFSET_C_1:.+]] = arith.constant 16 : index - // CHECK: %[[VIEW_C_1:.+]] = memref.view %[[I8_EQUIV_C_1]][%[[OFFSET_C_1]]][] : memref<24xi8> to memref + // CHECK: %[[VIEW_C_1:.+]] = memref.view %[[I8_EQUIV_C_1]][%[[OFFSET_C_1]]][] : memref<40xi8> to memref // CHECK: %[[VALUE_C:.+]] = memref.load %[[VIEW_C_1]][] : memref // CHECK: %[[VALUE_RET:.+]] = arith.extsi %[[VALUE_C]] : i8 to i32 } diff --git a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h index 03a9ce5b3df7..11315defc9e0 100644 --- a/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h +++ b/mlir/include/mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h @@ -17,5 +17,4 @@ #include "mlir/Dialect/NamedTuple/IR/NamedTupleDialect.h.inc" - #endif // MLIR_DIALECT_NAMED_TUPLE_IR_NAMED_TUPLE_DIALECT_H From a967bc7bb3755b77aca8d4cd914e6e40b9c77b13 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Fri, 14 Feb 2025 11:02:19 -0800 Subject: [PATCH 12/23] [CIR][Lowering] Lower arrays in class/struct/union as tensor Arrays in C/C++ have usually a reference semantics and can be lowered to memref. But when inside a class/struct/union, arrays hav a value semantics and can be lowered as tensor. --- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 85 +++++++++++-------- .../test/CIR/Lowering/ThroughMLIR/struct.cpp | 16 ++-- 2 files changed, 59 insertions(+), 42 deletions(-) diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index fdd04ed417b6..4441defe0572 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -289,13 +289,13 @@ class CIRStoreOpLowering : public mlir::OpConversionPattern { } }; -// Lower cir.get_member +// Lower cir.get_member by aliasing the result memref to the member inside the +// flattened structure as a byte array. For example // // clang-format off -// // %5 = cir.get_member %1[1] {name = "b"} : !cir.ptr> -> !cir.ptr // -// to something like +// is lowered to something like // // %1 = named_tuple.cast %alloca_0 : memref> to memref<24xi8> // %c8 = arith.constant 8 : index @@ -325,37 +325,30 @@ class CIRGetMemberOpLowering // concrete datalayout, both datalayouts are the same. auto *structLayout = dataLayout.getStructLayout(structType); - // Get the lowered type: memref> - auto memref = mlir::cast(adaptor.getAddr().getType()); // Alias the memref of struct to a memref of an i8 array of the same size. const std::array linearizedSize{ static_cast(dataLayout.getTypeStoreSize(structType))}; - auto flattenMemRef = mlir::MemRefType::get( - linearizedSize, mlir::IntegerType::get(memref.getContext(), 8)); + auto flattenedMemRef = mlir::MemRefType::get( + linearizedSize, mlir::IntegerType::get(getContext(), 8)); // Use a special cast because normal memref cast cannot do such an extreme // cast. auto bytesMemRef = rewriter.create( - op.getLoc(), mlir::TypeRange{flattenMemRef}, + op.getLoc(), mlir::TypeRange{flattenedMemRef}, mlir::ValueRange{adaptor.getAddr()}); + auto pointerToMemberTypeToLower = op.getResultTy(); + // The lowered type of the cir.ptr to the cir.struct member. + auto memrefToLoweredMemberType = + typeConverter->convertType(pointerToMemberTypeToLower); + // Synthesize the byte access to right lowered type. auto memberIndex = op.getIndex(); - auto namedTupleType = - mlir::cast(memref.getElementType()); - // The lowered type of the element to access in the named_tuple. - auto loweredMemberType = namedTupleType.getType(memberIndex); - // memref.view can only cast to another memref. Wrap the target type if it - // is not already a memref (like with a struct with an array member) - mlir::MemRefType elementMemRefTy; - if (mlir::isa(loweredMemberType)) - elementMemRefTy = mlir::cast(loweredMemberType); - else - elementMemRefTy = mlir::MemRefType::get({}, loweredMemberType); auto offset = structLayout->getElementOffset(memberIndex); - // Synthesize the byte access to right lowered type. auto byteShift = rewriter.create(op.getLoc(), offset); + // Create the memref pointing to the flattened member location. rewriter.replaceOpWithNewOp( - op, elementMemRefTy, bytesMemRef, byteShift, mlir::ValueRange{}); + op, memrefToLoweredMemberType, bytesMemRef, byteShift, + mlir::ValueRange{}); return mlir::LogicalResult::success(); } }; @@ -1382,6 +1375,29 @@ void populateCIRToMLIRConversionPatterns(mlir::RewritePatternSet &patterns, cirDataLayout); } +namespace { +// Lower a cir.array either as a memref when it has a reference semantics or as +// a tensor when it has a value semantics (like inside a struct or union) +mlir::Type lowerArrayType(cir::ArrayType type, bool hasValueSemantics, + mlir::TypeConverter &converter) { + SmallVector shape; + mlir::Type curType = type; + while (auto arrayType = dyn_cast(curType)) { + shape.push_back(arrayType.getSize()); + curType = arrayType.getEltType(); + } + auto elementType = converter.convertType(curType); + // FIXME: The element type might not be converted + if (!elementType) + return nullptr; + // Arrays in C/C++ have a reference semantics when not in a struct, so use + // a memref + if (hasValueSemantics) + return mlir::RankedTensorType::get(shape, elementType); + return mlir::MemRefType::get(shape, elementType); +} +} // namespace + mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { mlir::TypeConverter converter; converter.addConversion([&](cir::PointerType type) -> mlir::Type { @@ -1390,6 +1406,7 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { if (!ty) return nullptr; if (isa(type.getPointee())) + // An array is already lowered as a memref with reference semantics return ty; return mlir::MemRefType::get({}, ty); }); @@ -1429,23 +1446,23 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { return mlir::BFloat16Type::get(type.getContext()); }); converter.addConversion([&](cir::ArrayType type) -> mlir::Type { - SmallVector shape; - mlir::Type curType = type; - while (auto arrayType = dyn_cast(curType)) { - shape.push_back(arrayType.getSize()); - curType = arrayType.getEltType(); - } - auto elementType = converter.convertType(curType); - // FIXME: The element type might not be converted - if (!elementType) - return nullptr; - return mlir::MemRefType::get(shape, elementType); + // Arrays in C/C++ have a reference semantics when not in a + // class/struct/union, so use a memref. + return lowerArrayType(type, /* hasValueSemantics */ false, converter); }); converter.addConversion([&](cir::VectorType type) -> mlir::Type { auto ty = converter.convertType(type.getEltType()); return mlir::VectorType::get(type.getSize(), ty); }); converter.addConversion([&](cir::StructType type) -> mlir::Type { + auto convertWithValueSemanticsArray = [&](mlir::Type t) { + if (mlir::isa(t)) + // Inside a class/struct/union, an array has value semantics and is + // lowered as a tensor. + return lowerArrayType(mlir::cast(t), + /* hasValueSemantics */ true, converter); + return converter.convertType(t); + }; // FIXME(cir): create separate unions, struct, and classes types. // Convert struct members. llvm::SmallVector mlirMembers; @@ -1454,13 +1471,13 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { // TODO(cir): This should be properly validated. case cir::StructType::Struct: for (auto ty : type.getMembers()) - mlirMembers.push_back(converter.convertType(ty)); + mlirMembers.push_back(convertWithValueSemanticsArray(ty)); break; // Unions are lowered as only the largest member. case cir::StructType::Union: { auto largestMember = type.getLargestMember(dataLayout); if (largestMember) - mlirMembers.push_back(converter.convertType(largestMember)); + mlirMembers.push_back(convertWithValueSemanticsArray(largestMember)); break; } } diff --git a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp index 5be0b690f9ec..1fffe5543ab9 100644 --- a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp +++ b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp @@ -11,40 +11,40 @@ struct s { int main() { s v; - // CHECK: %[[ALLOCA:.+]] = memref.alloca() {alignment = 8 : i64} : memref]>> + // CHECK: %[[ALLOCA:.+]] = memref.alloca() {alignment = 8 : i64} : memref]>> v.a = 7; // CHECK: %[[C_7:.+]] = arith.constant 7 : i32 - // CHECK: %[[I8_EQUIV_A:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> + // CHECK: %[[I8_EQUIV_A:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> // CHECK: %[[OFFSET_A:.+]] = arith.constant 0 : index // CHECK: %[[VIEW_A:.+]] = memref.view %[[I8_EQUIV_A]][%[[OFFSET_A]]][] : memref<40xi8> to memref // CHECK: memref.store %[[C_7]], %[[VIEW_A]][] : memref v.b = 3.; // CHECK: %[[C_3:.+]] = arith.constant 3.000000e+00 : f64 - // CHECK: %[[I8_EQUIV_B:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> + // CHECK: %[[I8_EQUIV_B:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> // CHECK: %[[OFFSET_B:.+]] = arith.constant 8 : index // CHECK: %[[VIEW_B:.+]] = memref.view %[[I8_EQUIV_B]][%[[OFFSET_B]]][] : memref<40xi8> to memref // CHECK: memref.store %[[C_3]], %[[VIEW_B]][] : memref v.c = 'z'; // CHECK: %[[C_122:.+]] = arith.constant 122 : i8 - // CHECK: %[[I8_EQUIV_C:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> + // CHECK: %[[I8_EQUIV_C:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> // CHECK: %[[OFFSET_C:.+]] = arith.constant 16 : index // CHECK: %[[VIEW_C:.+]] = memref.view %[[I8_EQUIV_C]][%[[OFFSET_C]]][] : memref<40xi8> to memref // memref.store %[[C_122]], %[[VIEW_C]][] : memref + auto& a = v.d; v.d[4] = 6.f; // CHECK: %[[C_6:.+]] = arith.constant 6.000000e+00 : f32 - // CHECK: %[[I8_EQUIV_D:.+]] = named_tuple.cast %alloca_0 : memref]>> to memref<40xi8> + // CHECK: %[[I8_EQUIV_D:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> // CHECK: %[[OFFSET_D:.+]] = arith.constant 20 : index - // Do not lower to a memref of memref - // CHECK: %[[VIEW_D:.+]] = memref.view %3[%c20][] : memref<40xi8> to memref<5xf32> + // CHECK: %[[VIEW_D:.+]] = memref.view %[[I8_EQUIV_D]][%[[OFFSET_D]]][] : memref<40xi8> to memref<5xf32> // CHECK: %[[C_4:.+]] = arith.constant 4 : i32 // CHECK: %[[I_D:.+]] = arith.index_cast %[[C_4]] : i32 to index // CHECK: memref.store %[[C_6]], %[[VIEW_D]][%[[I_D]]] : memref<5xf32> return v.c; - // CHECK: %[[I8_EQUIV_C_1:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> + // CHECK: %[[I8_EQUIV_C_1:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> // CHECK: %[[OFFSET_C_1:.+]] = arith.constant 16 : index // CHECK: %[[VIEW_C_1:.+]] = memref.view %[[I8_EQUIV_C_1]][%[[OFFSET_C_1]]][] : memref<40xi8> to memref // CHECK: %[[VALUE_C:.+]] = memref.load %[[VIEW_C_1]][] : memref From 9ce66f23d6f5e487f5b157eccdbf8ccdc9290738 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Fri, 14 Feb 2025 17:05:26 -0800 Subject: [PATCH 13/23] [CIR][Lowering] Handle pointer of pointer of struct or array Remove a shortcut preventing some level of memref recursion. --- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 4441defe0572..55bd2dc2185c 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -1386,7 +1386,7 @@ mlir::Type lowerArrayType(cir::ArrayType type, bool hasValueSemantics, shape.push_back(arrayType.getSize()); curType = arrayType.getEltType(); } - auto elementType = converter.convertType(curType); + auto elementType = convertTypeForMemory(converter, curType); // FIXME: The element type might not be converted if (!elementType) return nullptr; @@ -1401,13 +1401,17 @@ mlir::Type lowerArrayType(cir::ArrayType type, bool hasValueSemantics, mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { mlir::TypeConverter converter; converter.addConversion([&](cir::PointerType type) -> mlir::Type { - auto ty = convertTypeForMemory(converter, type.getPointee()); + auto pointeeType = type.getPointee(); + if (mlir::isa(pointeeType)) + // A pointer to an array gives the array a reference semantics, lower to a + // memref. + return lowerArrayType(mlir::cast(pointeeType), + /* hasValueSemantics */ false, converter); + auto ty = convertTypeForMemory(converter, pointeeType); // FIXME: The pointee type might not be converted (e.g. struct) if (!ty) return nullptr; - if (isa(type.getPointee())) - // An array is already lowered as a memref with reference semantics - return ty; + // Each level of pointer becomes a level of memref return mlir::MemRefType::get({}, ty); }); converter.addConversion( @@ -1446,23 +1450,15 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { return mlir::BFloat16Type::get(type.getContext()); }); converter.addConversion([&](cir::ArrayType type) -> mlir::Type { - // Arrays in C/C++ have a reference semantics when not in a - // class/struct/union, so use a memref. - return lowerArrayType(type, /* hasValueSemantics */ false, converter); + // Assume we are in a class/struct/union context with value semantics, so + // lower as a tensor. + return lowerArrayType(type, /* hasValueSemantics */ true, converter); }); converter.addConversion([&](cir::VectorType type) -> mlir::Type { auto ty = converter.convertType(type.getEltType()); return mlir::VectorType::get(type.getSize(), ty); }); converter.addConversion([&](cir::StructType type) -> mlir::Type { - auto convertWithValueSemanticsArray = [&](mlir::Type t) { - if (mlir::isa(t)) - // Inside a class/struct/union, an array has value semantics and is - // lowered as a tensor. - return lowerArrayType(mlir::cast(t), - /* hasValueSemantics */ true, converter); - return converter.convertType(t); - }; // FIXME(cir): create separate unions, struct, and classes types. // Convert struct members. llvm::SmallVector mlirMembers; @@ -1471,13 +1467,13 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { // TODO(cir): This should be properly validated. case cir::StructType::Struct: for (auto ty : type.getMembers()) - mlirMembers.push_back(convertWithValueSemanticsArray(ty)); + mlirMembers.push_back(converter.convertType(ty)); break; // Unions are lowered as only the largest member. case cir::StructType::Union: { auto largestMember = type.getLargestMember(dataLayout); if (largestMember) - mlirMembers.push_back(convertWithValueSemanticsArray(largestMember)); + mlirMembers.push_back(converter.convertType(largestMember)); break; } } From c1ddaff2229c65a840f749f604196bc5cd07fe8f Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Mon, 17 Feb 2025 19:07:37 -0800 Subject: [PATCH 14/23] [CIR][Lowering][MLIR] Export cir::lowerArrayType() Export cir::lowerArrayType() so a CIR client can use this function to lower some !cir.array. --- clang/include/clang/CIR/LowerToMLIR.h | 5 +++++ clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 4 +--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/CIR/LowerToMLIR.h b/clang/include/clang/CIR/LowerToMLIR.h index 9a60d979aa9c..4caa35f40086 100644 --- a/clang/include/clang/CIR/LowerToMLIR.h +++ b/clang/include/clang/CIR/LowerToMLIR.h @@ -12,6 +12,8 @@ #ifndef CLANG_CIR_LOWERTOMLIR_H #define CLANG_CIR_LOWERTOMLIR_H +#include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "mlir/Interfaces/DataLayoutInterfaces.h" #include "mlir/Transforms/DialectConversion.h" #include @@ -20,6 +22,9 @@ namespace cir { void populateCIRLoopToSCFConversionPatterns(mlir::RewritePatternSet &patterns, mlir::TypeConverter &converter); +mlir::Type lowerArrayType(cir::ArrayType type, bool hasValueSemantics, + mlir::TypeConverter &converter); + mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout); void runAtStartOfConvertCIRToMLIRPass( diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 55bd2dc2185c..f0d9857e0703 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -1295,7 +1295,7 @@ class CIRPtrStrideOpLowering mlir::ConversionPatternRewriter &rewriter) const override { if (!isCastArrayToPtrConsumer(op)) return mlir::failure(); - if (!isLoadStoreOrCastArrayToPtrProduer(op)) + if (!isLoadStoreOrCastArrayToPtrProducer(op)) return mlir::failure(); auto baseOp = adaptor.getBase().getDefiningOp(); if (!baseOp) @@ -1375,7 +1375,6 @@ void populateCIRToMLIRConversionPatterns(mlir::RewritePatternSet &patterns, cirDataLayout); } -namespace { // Lower a cir.array either as a memref when it has a reference semantics or as // a tensor when it has a value semantics (like inside a struct or union) mlir::Type lowerArrayType(cir::ArrayType type, bool hasValueSemantics, @@ -1396,7 +1395,6 @@ mlir::Type lowerArrayType(cir::ArrayType type, bool hasValueSemantics, return mlir::RankedTensorType::get(shape, elementType); return mlir::MemRefType::get(shape, elementType); } -} // namespace mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { mlir::TypeConverter converter; From 1097f87bd8c05cb676f0c3e2aa75ce7d4ec949fb Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Wed, 19 Feb 2025 15:55:29 -0800 Subject: [PATCH 15/23] [CIR][Lowering][MLIR] Lower class/struct/union to memref by default Just keep the lowering inside a named_type as a tensor. This fix cir.alloca lowering issue. --- clang/include/clang/CIR/LowerToMLIR.h | 2 +- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 33 +++++++++++-------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/CIR/LowerToMLIR.h b/clang/include/clang/CIR/LowerToMLIR.h index 4caa35f40086..4ab5d3864028 100644 --- a/clang/include/clang/CIR/LowerToMLIR.h +++ b/clang/include/clang/CIR/LowerToMLIR.h @@ -12,9 +12,9 @@ #ifndef CLANG_CIR_LOWERTOMLIR_H #define CLANG_CIR_LOWERTOMLIR_H -#include "clang/CIR/Dialect/IR/CIRTypes.h" #include "mlir/Interfaces/DataLayoutInterfaces.h" #include "mlir/Transforms/DialectConversion.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" #include namespace cir { diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index f0d9857e0703..4268e8186ee9 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -1399,16 +1399,15 @@ mlir::Type lowerArrayType(cir::ArrayType type, bool hasValueSemantics, mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { mlir::TypeConverter converter; converter.addConversion([&](cir::PointerType type) -> mlir::Type { - auto pointeeType = type.getPointee(); - if (mlir::isa(pointeeType)) - // A pointer to an array gives the array a reference semantics, lower to a - // memref. - return lowerArrayType(mlir::cast(pointeeType), - /* hasValueSemantics */ false, converter); - auto ty = convertTypeForMemory(converter, pointeeType); - // FIXME: The pointee type might not be converted (e.g. struct) + auto ty = convertTypeForMemory( + converter, type.getPointee()); // FIXME: The pointee type might not be + // converted (e.g. struct) if (!ty) return nullptr; + if (isa(type.getPointee())) + // An array is already lowered as a memref with reference semantics by + // default + return ty; // Each level of pointer becomes a level of memref return mlir::MemRefType::get({}, ty); }); @@ -1448,15 +1447,23 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { return mlir::BFloat16Type::get(type.getContext()); }); converter.addConversion([&](cir::ArrayType type) -> mlir::Type { - // Assume we are in a class/struct/union context with value semantics, so - // lower as a tensor. - return lowerArrayType(type, /* hasValueSemantics */ true, converter); + // Assume we are not in a class/struct/union context with value semantics, + // so lower it as a memref to provide reference semantics. + return lowerArrayType(type, /* hasValueSemantics */ false, converter); }); converter.addConversion([&](cir::VectorType type) -> mlir::Type { auto ty = converter.convertType(type.getEltType()); return mlir::VectorType::get(type.getSize(), ty); }); converter.addConversion([&](cir::StructType type) -> mlir::Type { + auto convertWithValueSemanticsArray = [&](mlir::Type t) { + if (mlir::isa(t)) + // Inside a class/struct/union, an array has value semantics and is + // lowered as a tensor. + return lowerArrayType(mlir::cast(t), + /* hasValueSemantics */ true, converter); + return converter.convertType(t); + }; // FIXME(cir): create separate unions, struct, and classes types. // Convert struct members. llvm::SmallVector mlirMembers; @@ -1465,13 +1472,13 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { // TODO(cir): This should be properly validated. case cir::StructType::Struct: for (auto ty : type.getMembers()) - mlirMembers.push_back(converter.convertType(ty)); + mlirMembers.push_back(convertWithValueSemanticsArray(ty)); break; // Unions are lowered as only the largest member. case cir::StructType::Union: { auto largestMember = type.getLargestMember(dataLayout); if (largestMember) - mlirMembers.push_back(converter.convertType(largestMember)); + mlirMembers.push_back(convertWithValueSemanticsArray(largestMember)); break; } } From 6c35a8f401ca6a95252064ae09bd87f5edbd59b3 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Fri, 21 Feb 2025 15:24:37 -0800 Subject: [PATCH 16/23] [CIR][Lowering][MLIR] Lower cir.cast(bitcast) between !cir.ptr --- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 4268e8186ee9..6efd07634d2c 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -207,9 +207,11 @@ static bool findBaseAndIndices(mlir::Value addr, mlir::Value &base, while (mlir::Operation *addrOp = addr.getDefiningOp()) { if (!isa(addrOp)) break; - indices.push_back(addrOp->getOperand(1)); addr = addrOp->getOperand(0); eraseList.push_back(addrOp); + // If there is another operand, assume it is the lowered index + if (addrOp->getNumOperands() == 2) + indices.push_back(addrOp->getOperand(1)); } base = addr; if (indices.size() == 0) @@ -1150,6 +1152,23 @@ class CIRCastOpLowering : public mlir::OpConversionPattern { op, newDstType, src, 0, std::nullopt, std::nullopt); return mlir::success(); } + case CIR::bitcast: { + // clang-format off + // %7 = cir.cast(bitcast, %6 : !cir.ptr), !cir.ptr> + // Is lowered as + // memref → memref.reinterpret_cast → memref<8192xi32> + // clang-format on + auto newDstType = convertTy(dstType); + if (!(mlir::isa(adaptor.getSrc().getType()) && + mlir::isa(newDstType))) + return op.emitError() << "NYI bitcast from " << op.getSrc().getType() + << " to " << dstType; + auto dstMR = mlir::cast(newDstType); + auto [strides, offset] = dstMR.getStridesAndOffset(); + rewriter.replaceOpWithNewOp( + op, dstMR, src, offset, dstMR.getShape(), strides); + return mlir::success(); + } case CIR::int_to_bool: { auto zero = rewriter.create( src.getLoc(), op.getSrc().getType(), From a207932f7bbaa12208919ffbe81ae05ab35e0a4e Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Fri, 21 Feb 2025 19:18:01 -0800 Subject: [PATCH 17/23] [CIR][Lowering][MLIR] Rework the !cir.array lowering Split completely the !cir.array lowering, like in struct/class/union, from any reference with memref construction. Rationalize the approach inside convertToReferenceType() instead of ad-hoc cases all-over the place. Fix a test which seems to have been wrong from the beginning. --- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 122 +++++++++--------- 1 file changed, 58 insertions(+), 64 deletions(-) diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 6efd07634d2c..d415a8f338df 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -69,6 +69,55 @@ using namespace llvm; namespace cir { +/// Given a type convertor and a data layout, convert the given type to a type +/// that is suitable for memory operations. For example, this can be used to +/// lower cir.bool accesses to i8. +static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter, + mlir::Type type) { + // TODO(cir): Handle other types similarly to clang's codegen + // convertTypeForMemory + if (isa(type)) { + // TODO: Use datalayout to get the size of bool + return mlir::IntegerType::get(type.getContext(), 8); + } + + return converter.convertType(type); +} + +// Create a reference to an MLIR type. This creates a memref of the element type +// with the requested shape except when it is a tensor because it represents a +// !cir.array which has to be blessed as a memref of the tensor element type +// instead. +static mlir::MemRefType convertToReferenceType(ArrayRef shape, + mlir::Type elementType) { + if (auto t = mlir::dyn_cast(elementType)) + return mlir::MemRefType::get(t.getShape(), t.getElementType()); + return mlir::MemRefType::get(shape, elementType); +} + +// Lower a cir.array either as a memref when it has a reference semantics or as +// a tensor when it has a value semantics (like inside a struct or union). +mlir::Type lowerArrayType(cir::ArrayType type, bool hasValueSemantics, + mlir::TypeConverter &converter) { + SmallVector shape; + mlir::Type curType = type; + while (auto arrayType = dyn_cast(curType)) { + shape.push_back(arrayType.getSize()); + curType = arrayType.getEltType(); + } + auto elementType = convertTypeForMemory(converter, curType); + // FIXME: The element type might not be converted. + if (!elementType) + return nullptr; + // Arrays in C/C++ have a value semantics when in a struct, so use + // a tensor. + // TODO: tensors cannot contain most built-in types like memref. + if (hasValueSemantics) + return mlir::RankedTensorType::get(shape, elementType); + // Otherwise, go to a memref. + return convertToReferenceType(shape, elementType); +} + class CIRReturnLowering : public mlir::OpConversionPattern { public: using OpConversionPattern::OpConversionPattern; @@ -121,21 +170,6 @@ class CIRCallOpLowering : public mlir::OpConversionPattern { } }; -/// Given a type convertor and a data layout, convert the given type to a type -/// that is suitable for memory operations. For example, this can be used to -/// lower cir.bool accesses to i8. -static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter, - mlir::Type type) { - // TODO(cir): Handle other types similarly to clang's codegen - // convertTypeForMemory - if (isa(type)) { - // TODO: Use datalayout to get the size of bool - return mlir::IntegerType::get(type.getContext(), 8); - } - - return converter.convertType(type); -} - /// Emits the value from memory as expected by its users. Should be called when /// the memory represetnation of a CIR type is not equal to its scalar /// representation. @@ -184,14 +218,7 @@ class CIRAllocaOpLowering : public mlir::OpConversionPattern { if (!mlirType) return mlir::LogicalResult::failure(); - auto memreftype = mlir::dyn_cast(mlirType); - if (memreftype && mlir::isa(adaptor.getAllocaType())) { - // if the type is an array, - // we don't need to wrap with memref. - } else { - memreftype = mlir::MemRefType::get({}, mlirType); - } - + auto memreftype = convertToReferenceType({}, mlirType); rewriter.replaceOpWithNewOp(op, memreftype, op.getAlignmentAttr()); return mlir::LogicalResult::success(); @@ -333,7 +360,7 @@ class CIRGetMemberOpLowering auto flattenedMemRef = mlir::MemRefType::get( linearizedSize, mlir::IntegerType::get(getContext(), 8)); // Use a special cast because normal memref cast cannot do such an extreme - // cast. + // cast. Could be an UnrealizedCastOp instead? auto bytesMemRef = rewriter.create( op.getLoc(), mlir::TypeRange{flattenedMemRef}, mlir::ValueRange{adaptor.getAddr()}); @@ -949,7 +976,7 @@ class CIRGlobalOpLowering : public mlir::OpConversionPattern { return mlir::failure(); auto memrefType = dyn_cast(convertedType); if (!memrefType) - memrefType = mlir::MemRefType::get({}, convertedType); + memrefType = convertToReferenceType({}, convertedType); // Add an optional alignment to the global memref. mlir::IntegerAttr memrefAlignment = op.getAlignment() @@ -1394,27 +1421,6 @@ void populateCIRToMLIRConversionPatterns(mlir::RewritePatternSet &patterns, cirDataLayout); } -// Lower a cir.array either as a memref when it has a reference semantics or as -// a tensor when it has a value semantics (like inside a struct or union) -mlir::Type lowerArrayType(cir::ArrayType type, bool hasValueSemantics, - mlir::TypeConverter &converter) { - SmallVector shape; - mlir::Type curType = type; - while (auto arrayType = dyn_cast(curType)) { - shape.push_back(arrayType.getSize()); - curType = arrayType.getEltType(); - } - auto elementType = convertTypeForMemory(converter, curType); - // FIXME: The element type might not be converted - if (!elementType) - return nullptr; - // Arrays in C/C++ have a reference semantics when not in a struct, so use - // a memref - if (hasValueSemantics) - return mlir::RankedTensorType::get(shape, elementType); - return mlir::MemRefType::get(shape, elementType); -} - mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { mlir::TypeConverter converter; converter.addConversion([&](cir::PointerType type) -> mlir::Type { @@ -1423,12 +1429,8 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { // converted (e.g. struct) if (!ty) return nullptr; - if (isa(type.getPointee())) - // An array is already lowered as a memref with reference semantics by - // default - return ty; // Each level of pointer becomes a level of memref - return mlir::MemRefType::get({}, ty); + return convertToReferenceType({}, ty); }); converter.addConversion( [&](mlir::IntegerType type) -> mlir::Type { return type; }); @@ -1466,23 +1468,15 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { return mlir::BFloat16Type::get(type.getContext()); }); converter.addConversion([&](cir::ArrayType type) -> mlir::Type { - // Assume we are not in a class/struct/union context with value semantics, - // so lower it as a memref to provide reference semantics. - return lowerArrayType(type, /* hasValueSemantics */ false, converter); + // Assume we are in a class/struct/union context with value semantics, + // so lower it as a tensor to provide value semantics. + return lowerArrayType(type, /* hasValueSemantics */ true, converter); }); converter.addConversion([&](cir::VectorType type) -> mlir::Type { auto ty = converter.convertType(type.getEltType()); return mlir::VectorType::get(type.getSize(), ty); }); converter.addConversion([&](cir::StructType type) -> mlir::Type { - auto convertWithValueSemanticsArray = [&](mlir::Type t) { - if (mlir::isa(t)) - // Inside a class/struct/union, an array has value semantics and is - // lowered as a tensor. - return lowerArrayType(mlir::cast(t), - /* hasValueSemantics */ true, converter); - return converter.convertType(t); - }; // FIXME(cir): create separate unions, struct, and classes types. // Convert struct members. llvm::SmallVector mlirMembers; @@ -1491,13 +1485,13 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { // TODO(cir): This should be properly validated. case cir::StructType::Struct: for (auto ty : type.getMembers()) - mlirMembers.push_back(convertWithValueSemanticsArray(ty)); + mlirMembers.push_back(converter.convertType(ty)); break; // Unions are lowered as only the largest member. case cir::StructType::Union: { auto largestMember = type.getLargestMember(dataLayout); if (largestMember) - mlirMembers.push_back(convertWithValueSemanticsArray(largestMember)); + mlirMembers.push_back(converter.convertType(largestMember)); break; } } From 90b70f41c64cef7ab7436c2c5f05012528900a30 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Wed, 26 Feb 2025 11:37:23 -0800 Subject: [PATCH 18/23] =?UTF-8?q?[CIR][Doc]=20Add=20some=20top-level=20doc?= =?UTF-8?q?umentation=20on=20CIR=E2=86=92MLIR=20WIP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/README.md b/README.md index 3dd79abc4b3e..9c113d22a584 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,35 @@ # ClangIR (CIR) +## Work-in-progress on CIR→MLIR lowering + +This is a huge work-in-progress version adding new features used by [`aie++` C++ +programming model](https://github.com/keryell/mlir-aie/tree/clangir), such as +better support for lowering through MLIR standard dialects. + +What is experimented here: +- adding new features to CIR→MLIR lowering; +- cleaner lowering C/C++arrays as `tensor` for value semantics (for example in + structs) and `memref` for reference semantics (all the other uses); +- fixing array support and allocation; +- allowing pointer to array or struct; +- adding support for class/struct/union by first experimenting with `tuple` and + then introducing a new `named_tuple` dialect; +- implementation of more type of C/C++ casts; +- support struct member access through some `memref` flattening and casting + casting; +- fixing a lot of verification bugs which are triggered when using ClangIR in a + broader framework; +- enabling in-lining interface to CIR dialect; +- exposing some API to use ClangIR from a broader framework. + +The output of this new lowering flow has not been tested yet followed by the +MLIR std→LLVMIR. + +An alternative design could be to rely on some MLIR std→LLVMIR→MLIR std +back-and-forth traveling in the same module to have some parts of the LLVMIR +dialect to implement some missing features like it is done in the +[Polygeist](https://github.com/llvm/Polygeist) project. + +## Main documentation + Check https://clangir.org for general information, build instructions and documentation. From 15abba41bfb6008c16febd5a04e1bd022f2eae1e Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Thu, 27 Feb 2025 17:02:24 -0800 Subject: [PATCH 19/23] [CIR][Lower][MLIR] Handle pointer decay of higher dimensions arrays --- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 19 +++++++++++-- clang/test/CIR/Lowering/ThroughMLIR/cast.cpp | 28 +++++++++++++++++++ mlir/utils/emacs/mlir-lsp-client.el | 4 +-- 3 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 clang/test/CIR/Lowering/ThroughMLIR/cast.cpp diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index d415a8f338df..9f128194ebc8 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -45,6 +45,7 @@ #include "mlir/IR/ValueRange.h" #include "mlir/Pass/Pass.h" #include "mlir/Pass/PassManager.h" +#include "mlir/Support/LLVM.h" #include "mlir/Support/LogicalResult.h" #include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" @@ -118,6 +119,17 @@ mlir::Type lowerArrayType(cir::ArrayType type, bool hasValueSemantics, return convertToReferenceType(shape, elementType); } +// Compute the identity stride for the default layout of a memref +static llvm::SmallVector identityStrides(mlir::MemRefType t) { + llvm::SmallVector strides(t.getShape().size()); + if (!strides.empty()) + strides.back() = 1; + // To replace by range algorithms with an exclusive scan... + for (auto i = strides.size(); i > 1; --i) + strides[i - 2] = t.getShape()[i - 1] * strides[i - 1]; + return strides; +} + class CIRReturnLowering : public mlir::OpConversionPattern { public: using OpConversionPattern::OpConversionPattern; @@ -171,7 +183,7 @@ class CIRCallOpLowering : public mlir::OpConversionPattern { }; /// Emits the value from memory as expected by its users. Should be called when -/// the memory represetnation of a CIR type is not equal to its scalar +/// the memory representation of a CIR type is not equal to its scalar /// representation. static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter, cir::LoadOp op, mlir::Value value) { @@ -1176,7 +1188,8 @@ class CIRCastOpLowering : public mlir::OpConversionPattern { case CIR::array_to_ptrdecay: { auto newDstType = mlir::cast(convertTy(dstType)); rewriter.replaceOpWithNewOp( - op, newDstType, src, 0, std::nullopt, std::nullopt); + op, newDstType, src, 0, newDstType.getShape(), + identityStrides(newDstType)); return mlir::success(); } case CIR::bitcast: { @@ -1334,7 +1347,7 @@ class CIRPtrStrideOpLowering // memref.reinterpret_cast (%base, %stride) // // MemRef Dialect doesn't have GEP-like operation. memref.reinterpret_cast - // only been used to propogate %base and %stride to memref.load/store and + // only been used to propagate %base and %stride to memref.load/store and // should be erased after the conversion. mlir::LogicalResult matchAndRewrite(cir::PtrStrideOp op, OpAdaptor adaptor, diff --git a/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp b/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp new file mode 100644 index 000000000000..da3b89f069d4 --- /dev/null +++ b/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-clangir-direct-lowering -emit-mlir %s -o %t.mlir +// RUN: FileCheck --input-file=%t.mlir %s + + +int main() { + int a[10]; + int b[4][7]; + int *aa = a; + int *p = &a[0]; + auto *ap = &a; + *ap[3] = 7; + auto *ap10 = (int (*)[10]) p; + + auto v15 = b[1][5]; + int *bpd = b[0]; + auto pb36 = &b[3][6]; + auto pb2 = &b[2]; + auto pb2a = b[2]; + + return a[3]; + + // CHECK: %[[ALLOCA:.+]] = memref.alloca() {alignment = 8 : i64} : memref]>> + // CHECK: %[[C_7:.+]] = arith.constant 7 : i32/home/rkeryell/Xilinx/Projects/LLVM/worktrees/clangir/build/bin/clang -cc1 -internal-isystem /home/rkeryell/Xilinx/Projects/LLVM/worktrees/clangir/build/lib/clang/20/include -nostdsysteminc -triple x86_64-unknown-linux-gnu -fno-clangir-direct-lowering -emit-mlir /home/rkeryell/Xilinx/Projects/LLVM/worktrees/clangir/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp -o + // CHECK: %[[I8_EQUIV_A:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> + // CHECK: %[[OFFSET_A:.+]] = arith.constant 0 : index + // CHECK: %[[VIEW_A:.+]] = memref.view %[[I8_EQUIV_A]][%[[OFFSET_A]]][] : memref<40xi8> to memref + // CHECK: memref.store %[[C_7]], %[[VIEW_A]][] : memref + } diff --git a/mlir/utils/emacs/mlir-lsp-client.el b/mlir/utils/emacs/mlir-lsp-client.el index 4397a55e7206..2dbb67b94c07 100644 --- a/mlir/utils/emacs/mlir-lsp-client.el +++ b/mlir/utils/emacs/mlir-lsp-client.el @@ -1,4 +1,4 @@ -;;; mlir-lsp-clinet.el --- LSP clinet for the MLIR. +;;; mlir-lsp-client.el --- LSP clinet for the MLIR. ;; Copyright (C) 2022 The MLIR Authors. ;; @@ -18,7 +18,7 @@ ;;; Commentary: -;; LSP clinet to use with `mlir-mode' that uses `mlir-lsp-server' or any +;; LSP client to use with `mlir-mode' that uses `mlir-lsp-server' or any ;; user made compatible server. ;;; Code: From 429b8aebcc3997d5017f928eb01830ebdb8660a8 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Thu, 27 Feb 2025 18:44:54 -0800 Subject: [PATCH 20/23] [CIR][Lowering][MLIR] Generalize the lowering of cir.ptr_stride Handle pointer strides in quite more contexts. Make the code type-safe with the right memref layouts matching the reinterpret_cast details to avoid tripping the verifiers. This problem was hidden in the past due to the fact that the load/store lowering discarded some intermediate incorrect code for the tested simple cases. --- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 50 +++++---- clang/test/CIR/Lowering/ThroughMLIR/cast.cpp | 100 ++++++++++++++++-- 2 files changed, 123 insertions(+), 27 deletions(-) diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 9f128194ebc8..8fa162e5a7e5 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -1340,39 +1340,51 @@ class CIRPtrStrideOpLowering return getTypeConverter()->convertType(ty); } - // Rewrite - // %0 = cir.cast(array_to_ptrdecay, %base) - // cir.ptr_stride(%0, %stride) - // to - // memref.reinterpret_cast (%base, %stride) - // // MemRef Dialect doesn't have GEP-like operation. memref.reinterpret_cast // only been used to propagate %base and %stride to memref.load/store and // should be erased after the conversion. mlir::LogicalResult matchAndRewrite(cir::PtrStrideOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override { - if (!isCastArrayToPtrConsumer(op)) - return mlir::failure(); - if (!isLoadStoreOrCastArrayToPtrProducer(op)) - return mlir::failure(); - auto baseOp = adaptor.getBase().getDefiningOp(); - if (!baseOp) - return mlir::failure(); - if (!isa(baseOp)) - return mlir::failure(); - auto base = baseOp->getOperand(0); + // Most of the complexity here is to insure type-safety between the + // different memref and cast operations to avoid triggering the verifier. + auto base = adaptor.getBase(); + // The lowered result type is a memref with a static 0 offset. auto dstType = op.getResult().getType(); auto newDstType = mlir::cast(convertTy(dstType)); + // Construct a new memref with an identity layout which is the same as the + // output type but with an offset in the last dimension to take into account + // the offset introduced by the memref.reinterpret_cast. + auto elementType = newDstType.getElementType(); + auto strides = identityStrides(newDstType); + auto layoutAttr = mlir::StridedLayoutAttr::get( + getContext(), mlir::ShapedType::kDynamic, strides); + auto as = newDstType.getMemorySpace(); + auto sm = mlir::MemRefType::get(newDstType.getShape(), elementType, + layoutAttr, as); + + // The lowered cir::PtrStrideOp offset. The use of the words offset and + // stride according to the context is confusing. auto stride = adaptor.getStride(); auto indexType = rewriter.getIndexType(); // Generate casting if the stride is not index type. if (stride.getType() != indexType) stride = rewriter.create(op.getLoc(), indexType, stride); - rewriter.replaceOpWithNewOp( - op, newDstType, base, stride, std::nullopt, std::nullopt); - rewriter.eraseOp(baseOp); + // TODO: check that the real address computation is correct when lowering + // later to LLVM. + // Generate something like: %reinterpret_cast_25 = + // memref.reinterpret_cast %reinterpret_cast_24 to offset: [%7], sizes: [7], + // strides: [1] : memref<7xi32> to memref<7xi32, strided<[1], offset: ?>> + auto rc = rewriter.create( + op.getLoc(), sm, base, /* offsets */ stride, + mlir::ValueRange{/* sizes */}, mlir::ValueRange{/* strides */}, + /* static_offsets */ mlir::ShapedType::kDynamic, + /* static_sizes */ newDstType.getShape(), /* static_strides */ strides); + // Then remove the offset from the type with something like: + // %cast_26 = memref.cast %reinterpret_cast_25 : memref<7xi32, strided<[1], + // offset: ?>> to memref<7xi32> + rewriter.replaceOpWithNewOp(op, newDstType, rc); return mlir::success(); } }; diff --git a/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp b/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp index da3b89f069d4..805dac2299e3 100644 --- a/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp +++ b/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp @@ -4,12 +4,29 @@ int main() { int a[10]; + // CHECK: %[[ALLOCA_0:.+]] = memref.alloca() {alignment = 16 : i64} : memref<10xi32> int b[4][7]; - int *aa = a; + // CHECK: %[[ALLOCA_1:.+]] = memref.alloca() {alignment = 16 : i64} : memref<4x7xi32> + +int *aa = a; + // CHECK: %[[ALLOCA_2:.+]] = memref.alloca() {alignment = 8 : i64} : memref> + // CHECK: %[[REINTERPRET:.+]] = memref.reinterpret_cast %[[ALLOCA_0]] to offset: [0], sizes: [], strides: [] : memref<10xi32> to memref + // CHECK: memref.store %[[REINTERPRET:.+]], %[[ALLOCA_2:.+]][] : memref + int *p = &a[0]; + // CHECK: %[[C0:.+]] = arith.constant 0 : i32 + // CHECK: %[[REINTERPRET_11:.+]] = memref.reinterpret_cast %[[ALLOCA_0]] to offset: [0], sizes: [], strides: [] : memref<10xi32> to memref + // CHECK: %[[C0_i:.+]] = arith.index_cast %[[C0]] : i32 to index + // CHECK: %[[REINTERPRET_12:.+]] = memref.reinterpret_cast %[[REINTERPRET_11]] to offset: [%0], sizes: [], strides: [] : memref to memref> + // CHECK: %[[CAST:.+]] = memref.cast %[[REINTERPRET_12]] : memref> to memref + // CHECK: memref.store %[[CAST]], %[[ALLOCA_3:.+]][] : memref> auto *ap = &a; *ap[3] = 7; + auto *ap10 = (int (*)[10]) p; + // CHECK: %[[p3:.+]] = memref.load %[[ALLOCA_3]][] : memref> + // CHECK: %[[REINTERPRET_16:.+]] = memref.reinterpret_cast %[[p3]] to offset: [0], sizes: [10], strides: [1] : memref to memref<10xi32> + // CHECK: memref.store %[[REINTERPRET_16]], %[[ALLOCA_5:.+]][] : memref> auto v15 = b[1][5]; int *bpd = b[0]; @@ -18,11 +35,78 @@ int main() { auto pb2a = b[2]; return a[3]; +} +/* func.func @main() -> i32 { + %alloca_3 = memref.alloca() {alignment = 8 : i64} : memref> loc(#loc54) + %alloca_4 = memref.alloca() {alignment = 8 : i64} : memref> loc(#loc55) + %alloca_5 = memref.alloca() {alignment = 8 : i64} : memref> loc(#loc56) + %alloca_6 = memref.alloca() {alignment = 4 : i64} : memref loc(#loc57) + %alloca_7 = memref.alloca() {alignment = 8 : i64} : memref> loc(#loc58) + %alloca_8 = memref.alloca() {alignment = 8 : i64} : memref> loc(#loc59) + %alloca_9 = memref.alloca() {alignment = 8 : i64} : memref> loc(#loc60) + %alloca_10 = memref.alloca() {alignment = 8 : i64} : memref> loc(#loc61) - // CHECK: %[[ALLOCA:.+]] = memref.alloca() {alignment = 8 : i64} : memref]>> - // CHECK: %[[C_7:.+]] = arith.constant 7 : i32/home/rkeryell/Xilinx/Projects/LLVM/worktrees/clangir/build/bin/clang -cc1 -internal-isystem /home/rkeryell/Xilinx/Projects/LLVM/worktrees/clangir/build/lib/clang/20/include -nostdsysteminc -triple x86_64-unknown-linux-gnu -fno-clangir-direct-lowering -emit-mlir /home/rkeryell/Xilinx/Projects/LLVM/worktrees/clangir/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp -o - // CHECK: %[[I8_EQUIV_A:.+]] = named_tuple.cast %[[ALLOCA]] : memref]>> to memref<40xi8> - // CHECK: %[[OFFSET_A:.+]] = arith.constant 0 : index - // CHECK: %[[VIEW_A:.+]] = memref.view %[[I8_EQUIV_A]][%[[OFFSET_A]]][] : memref<40xi8> to memref - // CHECK: memref.store %[[C_7]], %[[VIEW_A]][] : memref - } + memref.store %alloca_0, %alloca_4[] : memref> loc(#loc55) + %c7_i32 = arith.constant 7 : i32 loc(#loc27) + %1 = memref.load %alloca_4[] : memref> loc(#loc28) + %c3_i32 = arith.constant 3 : i32 loc(#loc29) + %2 = arith.index_cast %c3_i32 : i32 to index loc(#loc30) + %reinterpret_cast_13 = memref.reinterpret_cast %1 to offset: [%2], sizes: [10], strides: [1] : memref<10xi32> to memref<10xi32, strided<[1], offset: ?>> loc(#loc30) + %cast_14 = memref.cast %reinterpret_cast_13 : memref<10xi32, strided<[1], offset: ?>> to memref<10xi32> loc(#loc30) + %reinterpret_cast_15 = memref.reinterpret_cast %cast_14 to offset: [0], sizes: [], strides: [] : memref<10xi32> to memref loc(#loc62) + memref.store %c7_i32, %reinterpret_cast_15[] : memref loc(#loc63) + %c1_i32 = arith.constant 1 : i32 loc(#loc32) + %reinterpret_cast_17 = memref.reinterpret_cast %alloca_1 to offset: [0], sizes: [7], strides: [1] : memref<4x7xi32> to memref<7xi32> loc(#loc33) + %4 = arith.index_cast %c1_i32 : i32 to index loc(#loc33) + %reinterpret_cast_18 = memref.reinterpret_cast %reinterpret_cast_17 to offset: [%4], sizes: [7], strides: [1] : memref<7xi32> to memref<7xi32, strided<[1], offset: ?>> loc(#loc33) + %cast_19 = memref.cast %reinterpret_cast_18 : memref<7xi32, strided<[1], offset: ?>> to memref<7xi32> loc(#loc33) + %c5_i32 = arith.constant 5 : i32 loc(#loc34) + %reinterpret_cast_20 = memref.reinterpret_cast %cast_19 to offset: [0], sizes: [], strides: [] : memref<7xi32> to memref loc(#loc33) + %5 = arith.index_cast %c5_i32 : i32 to index loc(#loc35) + %reinterpret_cast_21 = memref.reinterpret_cast %reinterpret_cast_20 to offset: [%5], sizes: [], strides: [] : memref to memref> loc(#loc35) + %cast_22 = memref.cast %reinterpret_cast_21 : memref> to memref loc(#loc35) + %6 = memref.load %cast_22[] : memref loc(#loc33) + memref.store %6, %alloca_6[] : memref loc(#loc57) + %c0_i32_23 = arith.constant 0 : i32 loc(#loc36) + %reinterpret_cast_24 = memref.reinterpret_cast %alloca_1 to offset: [0], sizes: [7], strides: [1] : memref<4x7xi32> to memref<7xi32> loc(#loc37) + %7 = arith.index_cast %c0_i32_23 : i32 to index loc(#loc37) + %reinterpret_cast_25 = memref.reinterpret_cast %reinterpret_cast_24 to offset: [%7], sizes: [7], strides: [1] : memref<7xi32> to memref<7xi32, strided<[1], offset: ?>> loc(#loc37) + %cast_26 = memref.cast %reinterpret_cast_25 : memref<7xi32, strided<[1], offset: ?>> to memref<7xi32> loc(#loc37) + %reinterpret_cast_27 = memref.reinterpret_cast %cast_26 to offset: [0], sizes: [], strides: [] : memref<7xi32> to memref loc(#loc64) + memref.store %reinterpret_cast_27, %alloca_7[] : memref> loc(#loc58) + %c3_i32_28 = arith.constant 3 : i32 loc(#loc38) + %reinterpret_cast_29 = memref.reinterpret_cast %alloca_1 to offset: [0], sizes: [7], strides: [1] : memref<4x7xi32> to memref<7xi32> loc(#loc39) + %8 = arith.index_cast %c3_i32_28 : i32 to index loc(#loc39) + %reinterpret_cast_30 = memref.reinterpret_cast %reinterpret_cast_29 to offset: [%8], sizes: [7], strides: [1] : memref<7xi32> to memref<7xi32, strided<[1], offset: ?>> loc(#loc39) + %cast_31 = memref.cast %reinterpret_cast_30 : memref<7xi32, strided<[1], offset: ?>> to memref<7xi32> loc(#loc39) + %c6_i32 = arith.constant 6 : i32 loc(#loc40) + %reinterpret_cast_32 = memref.reinterpret_cast %cast_31 to offset: [0], sizes: [], strides: [] : memref<7xi32> to memref loc(#loc39) + %9 = arith.index_cast %c6_i32 : i32 to index loc(#loc41) + %reinterpret_cast_33 = memref.reinterpret_cast %reinterpret_cast_32 to offset: [%9], sizes: [], strides: [] : memref to memref> loc(#loc41) + %cast_34 = memref.cast %reinterpret_cast_33 : memref> to memref loc(#loc41) + memref.store %cast_34, %alloca_8[] : memref> loc(#loc59) + %c2_i32 = arith.constant 2 : i32 loc(#loc42) + %reinterpret_cast_35 = memref.reinterpret_cast %alloca_1 to offset: [0], sizes: [7], strides: [1] : memref<4x7xi32> to memref<7xi32> loc(#loc43) + %10 = arith.index_cast %c2_i32 : i32 to index loc(#loc43) + %reinterpret_cast_36 = memref.reinterpret_cast %reinterpret_cast_35 to offset: [%10], sizes: [7], strides: [1] : memref<7xi32> to memref<7xi32, strided<[1], offset: ?>> loc(#loc43) + %cast_37 = memref.cast %reinterpret_cast_36 : memref<7xi32, strided<[1], offset: ?>> to memref<7xi32> loc(#loc43) + memref.store %cast_37, %alloca_9[] : memref> loc(#loc60) + %c2_i32_38 = arith.constant 2 : i32 loc(#loc44) + %reinterpret_cast_39 = memref.reinterpret_cast %alloca_1 to offset: [0], sizes: [7], strides: [1] : memref<4x7xi32> to memref<7xi32> loc(#loc45) + %11 = arith.index_cast %c2_i32_38 : i32 to index loc(#loc45) + %reinterpret_cast_40 = memref.reinterpret_cast %reinterpret_cast_39 to offset: [%11], sizes: [7], strides: [1] : memref<7xi32> to memref<7xi32, strided<[1], offset: ?>> loc(#loc45) + %cast_41 = memref.cast %reinterpret_cast_40 : memref<7xi32, strided<[1], offset: ?>> to memref<7xi32> loc(#loc45) + %reinterpret_cast_42 = memref.reinterpret_cast %cast_41 to offset: [0], sizes: [], strides: [] : memref<7xi32> to memref loc(#loc65) + memref.store %reinterpret_cast_42, %alloca_10[] : memref> loc(#loc61) + %c3_i32_43 = arith.constant 3 : i32 loc(#loc46) + %reinterpret_cast_44 = memref.reinterpret_cast %alloca_0 to offset: [0], sizes: [], strides: [] : memref<10xi32> to memref loc(#loc47) + %12 = arith.index_cast %c3_i32_43 : i32 to index loc(#loc47) + %reinterpret_cast_45 = memref.reinterpret_cast %reinterpret_cast_44 to offset: [%12], sizes: [], strides: [] : memref to memref> loc(#loc47) + %cast_46 = memref.cast %reinterpret_cast_45 : memref> to memref loc(#loc47) + %13 = memref.load %cast_46[] : memref loc(#loc47) + memref.store %13, %alloca[] : memref loc(#loc66) + %14 = memref.load %alloca[] : memref loc(#loc66) + return %14 : i32 loc(#loc66) + } loc(#loc50) +} loc(#loc) +*/ From 9338d3f372e2295d3854fa44527bc5e75aea160e Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Fri, 21 Mar 2025 16:22:20 -0700 Subject: [PATCH 21/23] [CIR][Lowering][MLIR] Remove a layout API It was removed upstream from mlir::DataLayoutEntryInterface. See: - https://github.com/llvm/llvm-project/pull/128772 - https://github.com/llvm/llvm-project/pull/128754 --- mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp b/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp index 67c65f8a35f1..b2a00a0fde72 100644 --- a/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp +++ b/mlir/lib/Dialect/NamedTuple/IR/NamedTupleDialect.cpp @@ -38,13 +38,6 @@ uint64_t mlir::named_tuple::NamedTupleType::getABIAlignment( return 8; } -uint64_t mlir::named_tuple::NamedTupleType::getPreferredAlignment( - mlir::DataLayout const &, - llvm::ArrayRef) const { - llvm_unreachable("getPreferredAlignment() not implemented"); - return 8; -} - //===----------------------------------------------------------------------===// // TableGen'd op method definitions //===----------------------------------------------------------------------===// From 39b162f5c078e892294b53f6d86b3409e9c5b651 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Thu, 17 Apr 2025 14:51:46 -0700 Subject: [PATCH 22/23] [CIR][Lowering][NFC] Update code to upstream cir::RecordType cir::StructType has been renamed to cir::RecordType. --- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 8fa162e5a7e5..f78b5d7a1905 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -358,13 +358,13 @@ class CIRGetMemberOpLowering matchAndRewrite(cir::GetMemberOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override { auto pointeeType = op.getAddrTy().getPointee(); - if (!mlir::isa(pointeeType)) - op.emitError("GetMemberOp only works on pointer to cir::StructType"); - auto structType = mlir::cast(pointeeType); + if (!mlir::isa(pointeeType)) + op.emitError("GetMemberOp only works on pointer to cir::RecordType"); + auto structType = mlir::cast(pointeeType); // For now, just rely on the datalayout of the high-level type since the // datalayout of low-level type is not implemented yet. But since C++ is a // concrete datalayout, both datalayouts are the same. - auto *structLayout = dataLayout.getStructLayout(structType); + auto *structLayout = dataLayout.getRecordLayout(structType); // Alias the memref of struct to a memref of an i8 array of the same size. const std::array linearizedSize{ @@ -1501,19 +1501,19 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { auto ty = converter.convertType(type.getEltType()); return mlir::VectorType::get(type.getSize(), ty); }); - converter.addConversion([&](cir::StructType type) -> mlir::Type { + converter.addConversion([&](cir::RecordType type) -> mlir::Type { // FIXME(cir): create separate unions, struct, and classes types. // Convert struct members. llvm::SmallVector mlirMembers; switch (type.getKind()) { - case cir::StructType::Class: + case cir::RecordType::Class: // TODO(cir): This should be properly validated. - case cir::StructType::Struct: + case cir::RecordType::Struct: for (auto ty : type.getMembers()) mlirMembers.push_back(converter.convertType(ty)); break; // Unions are lowered as only the largest member. - case cir::StructType::Union: { + case cir::RecordType::Union: { auto largestMember = type.getLargestMember(dataLayout); if (largestMember) mlirMembers.push_back(converter.convertType(largestMember)); @@ -1523,7 +1523,7 @@ mlir::TypeConverter prepareTypeConverter(mlir::DataLayout &dataLayout) { // FIXME(cir): all the following has to be somehow kept. With some // attributes? - // Struct has a name: lower as an identified struct. + // Record has a name: lower as an identified record. return mlir::named_tuple::NamedTupleType::get( type.getContext(), type.getName().strref(), mlirMembers); }); From 7275515ff7867776f8ee2031e5d296e3f5d278a8 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Thu, 17 Apr 2025 17:33:20 -0700 Subject: [PATCH 23/23] [CIR][ThroughMLIR][NFC] Fix test syntax The -emit-mlir syntax has changed and now requires the kind of MLIR to be specified. --- clang/test/CIR/Lowering/ThroughMLIR/cast.cpp | 2 +- clang/test/CIR/Lowering/ThroughMLIR/struct.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp b/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp index 805dac2299e3..9c724c13a419 100644 --- a/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp +++ b/clang/test/CIR/Lowering/ThroughMLIR/cast.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-clangir-direct-lowering -emit-mlir %s -o %t.mlir +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-clangir-direct-lowering -emit-mlir=core %s -o %t.mlir // RUN: FileCheck --input-file=%t.mlir %s diff --git a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp index 1fffe5543ab9..dc927221f196 100644 --- a/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp +++ b/clang/test/CIR/Lowering/ThroughMLIR/struct.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-clangir-direct-lowering -emit-mlir %s -o %t.mlir +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-clangir-direct-lowering -emit-mlir=core %s -o %t.mlir // RUN: FileCheck --input-file=%t.mlir %s // Check the MLIR lowering of struct and member accesses