diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td index 9123ac34af67d..0d16255c5a994 100644 --- a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td @@ -70,6 +70,86 @@ def OpenACC_PointerLikeTypeInterface : TypeInterface<"PointerLikeType"> { return ::mlir::acc::VariableTypeCategory::uncategorized; }] >, + InterfaceMethod< + /*description=*/[{ + Generates allocation operations for the pointer-like type. It will create + an allocate that produces memory space for an instance of the current type. + + The `varName` parameter is optional and can be used to provide a name + for the allocated variable. If the current type is represented + in a way that it does not capture the pointee type, `varType` must be + passed in to provide the necessary type information. + + The `originalVar` parameter is optional but enables support for dynamic + types (e.g., dynamic memrefs). When provided, implementations can extract + runtime dimension information from the original variable to create + allocations with matching dynamic sizes. + + Returns a Value representing the result of the allocation. If no value + is returned, it means the allocation was not successfully generated. + }], + /*retTy=*/"::mlir::Value", + /*methodName=*/"genAllocate", + /*args=*/(ins "::mlir::OpBuilder &":$builder, + "::mlir::Location":$loc, + "::llvm::StringRef":$varName, + "::mlir::Type":$varType, + "::mlir::Value":$originalVar), + /*methodBody=*/"", + /*defaultImplementation=*/[{ + return {}; + }] + >, + InterfaceMethod< + /*description=*/[{ + Generates deallocation operations for the pointer-like type. It deallocates + the instance provided. + + The `varPtr` parameter is required and must represent an instance that was + previously allocated. If the current type is represented in a way that it + does not capture the pointee type, `varType` must be passed in to provide + the necessary type information. Nothing is generated in case the allocate + is `alloca`-like. + + Returns true if deallocation was successfully generated or successfully + deemed as not needed to be generated, false otherwise. + }], + /*retTy=*/"bool", + /*methodName=*/"genFree", + /*args=*/(ins "::mlir::OpBuilder &":$builder, + "::mlir::Location":$loc, + "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$varPtr, + "::mlir::Type":$varType), + /*methodBody=*/"", + /*defaultImplementation=*/[{ + return false; + }] + >, + InterfaceMethod< + /*description=*/[{ + Generates copy operations for the pointer-like type. It copies the memory + from the source to the destination. Typically used to initialize one + variable of this type from another. + + The `destination` and `source` parameters represent the target and source + instances respectively. If the current type is represented in a way that it + does not capture the pointee type, `varType` must be passed in to provide + the necessary type information. + + Returns true if copy was successfully generated, false otherwise. + }], + /*retTy=*/"bool", + /*methodName=*/"genCopy", + /*args=*/(ins "::mlir::OpBuilder &":$builder, + "::mlir::Location":$loc, + "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$destination, + "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$source, + "::mlir::Type":$varType), + /*methodBody=*/"", + /*defaultImplementation=*/[{ + return false; + }] + >, ]; } diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp index 6598ac141008f..6564a4ecdccd3 100644 --- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp +++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp @@ -7,6 +7,7 @@ // ============================================================================= #include "mlir/Dialect/OpenACC/OpenACC.h" +#include "mlir/Dialect/Arith/IR/Arith.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" @@ -44,6 +45,7 @@ struct MemRefPointerLikeModel Type getElementType(Type pointer) const { return cast(pointer).getElementType(); } + mlir::acc::VariableTypeCategory getPointeeTypeCategory(Type pointer, TypedValue varPtr, Type varType) const { @@ -70,6 +72,115 @@ struct MemRefPointerLikeModel assert(memrefTy.getRank() > 0 && "rank expected to be positive"); return mlir::acc::VariableTypeCategory::array; } + + mlir::Value genAllocate(Type pointer, OpBuilder &builder, Location loc, + StringRef varName, Type varType, + Value originalVar) const { + auto memrefTy = cast(pointer); + + // Check if this is a static memref (all dimensions are known) - if yes + // then we can generate an alloca operation. + if (memrefTy.hasStaticShape()) + return memref::AllocaOp::create(builder, loc, memrefTy).getResult(); + + // For dynamic memrefs, extract sizes from the original variable if + // provided. Otherwise they cannot be handled. + if (originalVar && originalVar.getType() == memrefTy && + memrefTy.hasRank()) { + SmallVector dynamicSizes; + for (int64_t i = 0; i < memrefTy.getRank(); ++i) { + if (memrefTy.isDynamicDim(i)) { + // Extract the size of dimension i from the original variable + auto indexValue = arith::ConstantIndexOp::create(builder, loc, i); + auto dimSize = + memref::DimOp::create(builder, loc, originalVar, indexValue); + dynamicSizes.push_back(dimSize); + } + // Note: We only add dynamic sizes to the dynamicSizes array + // Static dimensions are handled automatically by AllocOp + } + return memref::AllocOp::create(builder, loc, memrefTy, dynamicSizes) + .getResult(); + } + + // TODO: Unranked not yet supported. + return {}; + } + + bool genFree(Type pointer, OpBuilder &builder, Location loc, + TypedValue varPtr, Type varType) const { + if (auto memrefValue = dyn_cast>(varPtr)) { + // Walk through casts to find the original allocation + Value currentValue = memrefValue; + Operation *originalAlloc = nullptr; + + // Follow the chain of operations to find the original allocation + // even if a casted result is provided. + while (currentValue) { + if (auto *definingOp = currentValue.getDefiningOp()) { + // Check if this is an allocation operation + if (isa(definingOp)) { + originalAlloc = definingOp; + break; + } + + // Check if this is a cast operation we can look through + if (auto castOp = dyn_cast(definingOp)) { + currentValue = castOp.getSource(); + continue; + } + + // Check for other cast-like operations + if (auto reinterpretCastOp = + dyn_cast(definingOp)) { + currentValue = reinterpretCastOp.getSource(); + continue; + } + + // If we can't look through this operation, stop + break; + } + // This is a block argument or similar - can't trace further. + break; + } + + if (originalAlloc) { + if (isa(originalAlloc)) { + // This is an alloca - no dealloc needed, but return true (success) + return true; + } + if (isa(originalAlloc)) { + // This is an alloc - generate dealloc + memref::DeallocOp::create(builder, loc, memrefValue); + return true; + } + } + } + + return false; + } + + bool genCopy(Type pointer, OpBuilder &builder, Location loc, + TypedValue destination, + TypedValue source, Type varType) const { + // Generate a copy operation between two memrefs + auto destMemref = dyn_cast_if_present>(destination); + auto srcMemref = dyn_cast_if_present>(source); + + // As per memref documentation, source and destination must have same + // element type and shape in order to be compatible. We do not want to fail + // with an IR verification error - thus check that before generating the + // copy operation. + if (destMemref && srcMemref && + destMemref.getType().getElementType() == + srcMemref.getType().getElementType() && + destMemref.getType().getShape() == srcMemref.getType().getShape()) { + memref::CopyOp::create(builder, loc, srcMemref, destMemref); + return true; + } + + return false; + } }; struct LLVMPointerPointerLikeModel diff --git a/mlir/test/Dialect/OpenACC/pointer-like-interface-alloc.mlir b/mlir/test/Dialect/OpenACC/pointer-like-interface-alloc.mlir new file mode 100644 index 0000000000000..603ace85072ac --- /dev/null +++ b/mlir/test/Dialect/OpenACC/pointer-like-interface-alloc.mlir @@ -0,0 +1,24 @@ +// RUN: mlir-opt %s --split-input-file --pass-pipeline="builtin.module(func.func(test-acc-pointer-like-interface{test-mode=alloc}))" 2>&1 | FileCheck %s + +func.func @test_static_memref_alloc() { + %0 = memref.alloca() {test.ptr} : memref<10x20xf32> + // CHECK: Successfully generated alloc for operation: %[[ORIG:.*]] = memref.alloca() {test.ptr} : memref<10x20xf32> + // CHECK: Generated: %{{.*}} = memref.alloca() : memref<10x20xf32> + return +} + +// ----- + +func.func @test_dynamic_memref_alloc() { + %c10 = arith.constant 10 : index + %c20 = arith.constant 20 : index + %orig = memref.alloc(%c10, %c20) {test.ptr} : memref + + // CHECK: Successfully generated alloc for operation: %[[ORIG:.*]] = memref.alloc(%[[C10:.*]], %[[C20:.*]]) {test.ptr} : memref + // CHECK: Generated: %[[C0:.*]] = arith.constant 0 : index + // CHECK: Generated: %[[DIM0:.*]] = memref.dim %[[ORIG]], %[[C0]] : memref + // CHECK: Generated: %[[C1:.*]] = arith.constant 1 : index + // CHECK: Generated: %[[DIM1:.*]] = memref.dim %[[ORIG]], %[[C1]] : memref + // CHECK: Generated: %{{.*}} = memref.alloc(%[[DIM0]], %[[DIM1]]) : memref + return +} diff --git a/mlir/test/Dialect/OpenACC/pointer-like-interface-copy.mlir b/mlir/test/Dialect/OpenACC/pointer-like-interface-copy.mlir new file mode 100644 index 0000000000000..9220d84a29f94 --- /dev/null +++ b/mlir/test/Dialect/OpenACC/pointer-like-interface-copy.mlir @@ -0,0 +1,23 @@ +// RUN: mlir-opt %s --split-input-file --pass-pipeline="builtin.module(func.func(test-acc-pointer-like-interface{test-mode=copy}))" 2>&1 | FileCheck %s + +func.func @test_copy_static() { + %src = memref.alloca() {test.src_ptr} : memref<10x20xf32> + %dest = memref.alloca() {test.dest_ptr} : memref<10x20xf32> + + // CHECK: Successfully generated copy from source: %[[SRC:.*]] = memref.alloca() {test.src_ptr} : memref<10x20xf32> to destination: %[[DEST:.*]] = memref.alloca() {test.dest_ptr} : memref<10x20xf32> + // CHECK: Generated: memref.copy %[[SRC]], %[[DEST]] : memref<10x20xf32> to memref<10x20xf32> + return +} + +// ----- + +func.func @test_copy_dynamic() { + %c10 = arith.constant 10 : index + %c20 = arith.constant 20 : index + %src = memref.alloc(%c10, %c20) {test.src_ptr} : memref + %dest = memref.alloc(%c10, %c20) {test.dest_ptr} : memref + + // CHECK: Successfully generated copy from source: %[[SRC:.*]] = memref.alloc(%[[C10:.*]], %[[C20:.*]]) {test.src_ptr} : memref to destination: %[[DEST:.*]] = memref.alloc(%[[C10]], %[[C20]]) {test.dest_ptr} : memref + // CHECK: Generated: memref.copy %[[SRC]], %[[DEST]] : memref to memref + return +} diff --git a/mlir/test/Dialect/OpenACC/pointer-like-interface-free.mlir b/mlir/test/Dialect/OpenACC/pointer-like-interface-free.mlir new file mode 100644 index 0000000000000..ecf4f75fe06d1 --- /dev/null +++ b/mlir/test/Dialect/OpenACC/pointer-like-interface-free.mlir @@ -0,0 +1,31 @@ +// RUN: mlir-opt %s --split-input-file --pass-pipeline="builtin.module(func.func(test-acc-pointer-like-interface{test-mode=free}))" 2>&1 | FileCheck %s + +func.func @test_static_memref_free() { + %0 = memref.alloca() {test.ptr} : memref<10x20xf32> + // CHECK: Successfully generated free for operation: %[[ORIG:.*]] = memref.alloca() {test.ptr} : memref<10x20xf32> + // CHECK-NOT: Generated + return +} + +// ----- + +func.func @test_dynamic_memref_free() { + %c10 = arith.constant 10 : index + %c20 = arith.constant 20 : index + %orig = memref.alloc(%c10, %c20) {test.ptr} : memref + + // CHECK: Successfully generated free for operation: %[[ORIG:.*]] = memref.alloc(%[[C10:.*]], %[[C20:.*]]) {test.ptr} : memref + // CHECK: Generated: memref.dealloc %[[ORIG]] : memref + return +} + +// ----- + +func.func @test_cast_walking_free() { + %0 = memref.alloca() : memref<10x20xf32> + %1 = memref.cast %0 {test.ptr} : memref<10x20xf32> to memref + + // CHECK: Successfully generated free for operation: %[[CAST:.*]] = memref.cast %[[ALLOCA:.*]] {test.ptr} : memref<10x20xf32> to memref + // CHECK-NOT: Generated + return +} diff --git a/mlir/test/lib/Dialect/CMakeLists.txt b/mlir/test/lib/Dialect/CMakeLists.txt index 3b7bd9b9637a8..e31140a6f6ba7 100644 --- a/mlir/test/lib/Dialect/CMakeLists.txt +++ b/mlir/test/lib/Dialect/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(Math) add_subdirectory(MemRef) add_subdirectory(Shard) add_subdirectory(NVGPU) +add_subdirectory(OpenACC) add_subdirectory(SCF) add_subdirectory(Shape) add_subdirectory(SPIRV) diff --git a/mlir/test/lib/Dialect/OpenACC/CMakeLists.txt b/mlir/test/lib/Dialect/OpenACC/CMakeLists.txt new file mode 100644 index 0000000000000..f84055df1b6c6 --- /dev/null +++ b/mlir/test/lib/Dialect/OpenACC/CMakeLists.txt @@ -0,0 +1,16 @@ +add_mlir_library(MLIROpenACCTestPasses + TestOpenACC.cpp + TestPointerLikeTypeInterface.cpp + + EXCLUDE_FROM_LIBMLIR +) +mlir_target_link_libraries(MLIROpenACCTestPasses PUBLIC + MLIRIR + MLIRArithDialect + MLIRFuncDialect + MLIRMemRefDialect + MLIROpenACCDialect + MLIRPass + MLIRSupport +) + diff --git a/mlir/test/lib/Dialect/OpenACC/TestOpenACC.cpp b/mlir/test/lib/Dialect/OpenACC/TestOpenACC.cpp new file mode 100644 index 0000000000000..98862401748e1 --- /dev/null +++ b/mlir/test/lib/Dialect/OpenACC/TestOpenACC.cpp @@ -0,0 +1,23 @@ +//===- TestOpenACC.cpp - OpenACC Test Registration ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains unified registration for all OpenACC test passes. +// +//===----------------------------------------------------------------------===// + +namespace mlir { +namespace test { + +// Forward declarations of individual test pass registration functions +void registerTestPointerLikeTypeInterfacePass(); + +// Unified registration function for all OpenACC tests +void registerTestOpenACC() { registerTestPointerLikeTypeInterfacePass(); } + +} // namespace test +} // namespace mlir diff --git a/mlir/test/lib/Dialect/OpenACC/TestPointerLikeTypeInterface.cpp b/mlir/test/lib/Dialect/OpenACC/TestPointerLikeTypeInterface.cpp new file mode 100644 index 0000000000000..85f92833a3269 --- /dev/null +++ b/mlir/test/lib/Dialect/OpenACC/TestPointerLikeTypeInterface.cpp @@ -0,0 +1,305 @@ +//===- TestPointerLikeTypeInterface.cpp - Test PointerLikeType interface -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains test passes for testing the OpenACC PointerLikeType +// interface methods. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Dialect/Arith/IR/Arith.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/MemRef/IR/MemRef.h" +#include "mlir/Dialect/OpenACC/OpenACC.h" +#include "mlir/IR/Builders.h" +#include "mlir/Pass/Pass.h" +#include "llvm/Support/CommandLine.h" + +using namespace mlir; +using namespace mlir::acc; + +namespace { + +struct OperationTracker : public OpBuilder::Listener { + SmallVector insertedOps; + + void notifyOperationInserted(Operation *op, + OpBuilder::InsertPoint previous) override { + insertedOps.push_back(op); + } +}; + +struct TestPointerLikeTypeInterfacePass + : public PassWrapper> { + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestPointerLikeTypeInterfacePass) + + TestPointerLikeTypeInterfacePass() = default; + TestPointerLikeTypeInterfacePass(const TestPointerLikeTypeInterfacePass &pass) + : PassWrapper(pass) { + testMode = pass.testMode; + } + + Pass::Option testMode{ + *this, "test-mode", + llvm::cl::desc("Test mode: walk, alloc, copy, or free"), + llvm::cl::init("walk")}; + + StringRef getArgument() const override { + return "test-acc-pointer-like-interface"; + } + + StringRef getDescription() const override { + return "Test OpenACC PointerLikeType interface methods on any implementing " + "type"; + } + + void runOnOperation() override; + + void getDependentDialects(DialectRegistry ®istry) const override { + registry.insert(); + registry.insert(); + registry.insert(); + } + +private: + void walkAndPrint(); + void testGenAllocate(Operation *op, Value result, PointerLikeType pointerType, + OpBuilder &builder); + void testGenFree(Operation *op, Value result, PointerLikeType pointerType, + OpBuilder &builder); + void testGenCopy(Operation *srcOp, Operation *destOp, Value srcResult, + Value destResult, PointerLikeType pointerType, + OpBuilder &builder); + + struct PointerCandidate { + Operation *op; + Value result; + PointerLikeType pointerType; + }; +}; + +void TestPointerLikeTypeInterfacePass::runOnOperation() { + if (testMode == "walk") { + walkAndPrint(); + return; + } + + auto func = getOperation(); + OpBuilder builder(&getContext()); + + if (testMode == "alloc" || testMode == "free") { + // Collect all candidates first + SmallVector candidates; + func.walk([&](Operation *op) { + if (op->hasAttr("test.ptr")) { + for (auto result : op->getResults()) { + if (isa(result.getType())) { + candidates.push_back( + {op, result, cast(result.getType())}); + break; // Only take the first PointerLikeType result + } + } + } + }); + + // Now test all candidates + for (const auto &candidate : candidates) { + if (testMode == "alloc") + testGenAllocate(candidate.op, candidate.result, candidate.pointerType, + builder); + else if (testMode == "free") + testGenFree(candidate.op, candidate.result, candidate.pointerType, + builder); + } + } else if (testMode == "copy") { + // Collect all source and destination candidates + SmallVector sources, destinations; + + func.walk([&](Operation *op) { + if (op->hasAttr("test.src_ptr")) { + for (auto result : op->getResults()) { + if (isa(result.getType())) { + sources.push_back( + {op, result, cast(result.getType())}); + break; + } + } + } + if (op->hasAttr("test.dest_ptr")) { + for (auto result : op->getResults()) { + if (isa(result.getType())) { + destinations.push_back( + {op, result, cast(result.getType())}); + break; + } + } + } + }); + + // Try copying from each source to each destination + for (const auto &src : sources) + for (const auto &dest : destinations) + testGenCopy(src.op, dest.op, src.result, dest.result, src.pointerType, + builder); + } +} + +void TestPointerLikeTypeInterfacePass::walkAndPrint() { + auto func = getOperation(); + + func.walk([&](Operation *op) { + // Look for operations marked with "test.ptr", "test.src_ptr", or + // "test.dest_ptr" + if (op->hasAttr("test.ptr") || op->hasAttr("test.src_ptr") || + op->hasAttr("test.dest_ptr")) { + llvm::errs() << "Operation: "; + op->print(llvm::errs()); + llvm::errs() << "\n"; + + // Check each result to see if it's a PointerLikeType + for (auto result : op->getResults()) { + if (isa(result.getType())) { + llvm::errs() << " Result " << result.getResultNumber() + << " is PointerLikeType: "; + result.getType().print(llvm::errs()); + llvm::errs() << "\n"; + } else { + llvm::errs() << " Result " << result.getResultNumber() + << " is NOT PointerLikeType: "; + result.getType().print(llvm::errs()); + llvm::errs() << "\n"; + } + } + + if (op->getNumResults() == 0) + llvm::errs() << " Operation has no results\n"; + + llvm::errs() << "\n"; + } + }); +} + +void TestPointerLikeTypeInterfacePass::testGenAllocate( + Operation *op, Value result, PointerLikeType pointerType, + OpBuilder &builder) { + Location loc = op->getLoc(); + + // Create a new builder with the listener and set insertion point + OperationTracker tracker; + OpBuilder newBuilder(op->getContext()); + newBuilder.setListener(&tracker); + newBuilder.setInsertionPointAfter(op); + + // Call the genAllocate API + Value allocRes = pointerType.genAllocate(newBuilder, loc, "test_alloc", + result.getType(), result); + + if (allocRes) { + llvm::errs() << "Successfully generated alloc for operation: "; + op->print(llvm::errs()); + llvm::errs() << "\n"; + + // Print all operations that were inserted + for (Operation *insertedOp : tracker.insertedOps) { + llvm::errs() << "\tGenerated: "; + insertedOp->print(llvm::errs()); + llvm::errs() << "\n"; + } + } else { + llvm::errs() << "Failed to generate alloc for operation: "; + op->print(llvm::errs()); + llvm::errs() << "\n"; + } +} + +void TestPointerLikeTypeInterfacePass::testGenFree(Operation *op, Value result, + PointerLikeType pointerType, + OpBuilder &builder) { + Location loc = op->getLoc(); + + // Create a new builder with the listener and set insertion point + OperationTracker tracker; + OpBuilder newBuilder(op->getContext()); + newBuilder.setListener(&tracker); + newBuilder.setInsertionPointAfter(op); + + // Call the genFree API + auto typedResult = cast>(result); + bool success = + pointerType.genFree(newBuilder, loc, typedResult, result.getType()); + + if (success) { + llvm::errs() << "Successfully generated free for operation: "; + op->print(llvm::errs()); + llvm::errs() << "\n"; + + // Print all operations that were inserted + for (Operation *insertedOp : tracker.insertedOps) { + llvm::errs() << "\tGenerated: "; + insertedOp->print(llvm::errs()); + llvm::errs() << "\n"; + } + } else { + llvm::errs() << "Failed to generate free for operation: "; + op->print(llvm::errs()); + llvm::errs() << "\n"; + } +} + +void TestPointerLikeTypeInterfacePass::testGenCopy( + Operation *srcOp, Operation *destOp, Value srcResult, Value destResult, + PointerLikeType pointerType, OpBuilder &builder) { + Location loc = destOp->getLoc(); + + // Create a new builder with the listener and set insertion point + OperationTracker tracker; + OpBuilder newBuilder(destOp->getContext()); + newBuilder.setListener(&tracker); + newBuilder.setInsertionPointAfter(destOp); + + // Call the genCopy API with the provided source and destination + auto typedSrc = cast>(srcResult); + auto typedDest = cast>(destResult); + bool success = pointerType.genCopy(newBuilder, loc, typedDest, typedSrc, + srcResult.getType()); + + if (success) { + llvm::errs() << "Successfully generated copy from source: "; + srcOp->print(llvm::errs()); + llvm::errs() << " to destination: "; + destOp->print(llvm::errs()); + llvm::errs() << "\n"; + + // Print all operations that were inserted + for (Operation *insertedOp : tracker.insertedOps) { + llvm::errs() << "\tGenerated: "; + insertedOp->print(llvm::errs()); + llvm::errs() << "\n"; + } + } else { + llvm::errs() << "Failed to generate copy from source: "; + srcOp->print(llvm::errs()); + llvm::errs() << " to destination: "; + destOp->print(llvm::errs()); + llvm::errs() << "\n"; + } +} + +} // namespace + +//===----------------------------------------------------------------------===// +// Pass Registration +//===----------------------------------------------------------------------===// + +namespace mlir { +namespace test { +void registerTestPointerLikeTypeInterfacePass() { + PassRegistration(); +} +} // namespace test +} // namespace mlir diff --git a/mlir/tools/mlir-opt/CMakeLists.txt b/mlir/tools/mlir-opt/CMakeLists.txt index 7cc6e78ca08c2..c607ccfa80e3c 100644 --- a/mlir/tools/mlir-opt/CMakeLists.txt +++ b/mlir/tools/mlir-opt/CMakeLists.txt @@ -28,6 +28,7 @@ if(MLIR_INCLUDE_TESTS) MLIRTestMemRefToLLVMWithTransforms MLIRShardTest MLIRNVGPUTestPasses + MLIROpenACCTestPasses MLIRSCFTestPasses MLIRShapeTestPasses MLIRSPIRVTestPasses diff --git a/mlir/tools/mlir-opt/mlir-opt.cpp b/mlir/tools/mlir-opt/mlir-opt.cpp index e4620c009af8c..6432fae615f88 100644 --- a/mlir/tools/mlir-opt/mlir-opt.cpp +++ b/mlir/tools/mlir-opt/mlir-opt.cpp @@ -135,6 +135,7 @@ void registerTestShardSimplificationsPass(); void registerTestMultiBuffering(); void registerTestNextAccessPass(); void registerTestNVGPULowerings(); +void registerTestOpenACC(); void registerTestOneShotModuleBufferizePass(); void registerTestOpaqueLoc(); void registerTestOpLoweringPasses(); @@ -282,6 +283,7 @@ void registerTestPasses() { mlir::test::registerTestMultiBuffering(); mlir::test::registerTestNextAccessPass(); mlir::test::registerTestNVGPULowerings(); + mlir::test::registerTestOpenACC(); mlir::test::registerTestOneShotModuleBufferizePass(); mlir::test::registerTestOpaqueLoc(); mlir::test::registerTestOpLoweringPasses();