Skip to content

Conversation

@joker-eph
Copy link
Collaborator

@joker-eph joker-eph commented Jun 18, 2025

Debugging issues with this pass is quite difficult at the moment, this should help.

@llvmbot llvmbot added mlir:core MLIR Core Infrastructure mlir labels Jun 18, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 18, 2025

@llvm/pr-subscribers-mlir-core

@llvm/pr-subscribers-mlir

Author: Mehdi Amini (joker-eph)

Changes

Debugging issue with this pass is quite difficult at the moment, this should help.


Patch is 31.24 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144695.diff

3 Files Affected:

  • (modified) mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp (+121-5)
  • (modified) mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp (+58-2)
  • (modified) mlir/lib/Transforms/RemoveDeadValues.cpp (+58-5)
diff --git a/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp b/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp
index e805e21d878bf..21e62a7d06a4f 100644
--- a/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp
+++ b/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp
@@ -22,9 +22,12 @@
 #include "mlir/Interfaces/ControlFlowInterfaces.h"
 #include "mlir/Support/LLVM.h"
 #include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
 #include <cassert>
 #include <optional>
 
+#define DEBUG_TYPE "dead-code-analysis"
+
 using namespace mlir;
 using namespace mlir::dataflow;
 
@@ -122,6 +125,9 @@ DeadCodeAnalysis::DeadCodeAnalysis(DataFlowSolver &solver)
 }
 
 LogicalResult DeadCodeAnalysis::initialize(Operation *top) {
+  LLVM_DEBUG(
+      llvm::dbgs() << "DCA: Initializing DeadCodeAnalysis for top-level op: "
+                   << top->getName() << "\n");
   // Mark the top-level blocks as executable.
   for (Region &region : top->getRegions()) {
     if (region.empty())
@@ -129,6 +135,8 @@ LogicalResult DeadCodeAnalysis::initialize(Operation *top) {
     auto *state =
         getOrCreate<Executable>(getProgramPointBefore(&region.front()));
     propagateIfChanged(state, state->setToLive());
+    LLVM_DEBUG(llvm::dbgs() << "DCA: Marked entry block live for region in op: "
+                            << top->getName() << "\n");
   }
 
   // Mark as overdefined the predecessors of symbol callables with potentially
@@ -139,13 +147,21 @@ LogicalResult DeadCodeAnalysis::initialize(Operation *top) {
 }
 
 void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
+  LLVM_DEBUG(
+      llvm::dbgs()
+      << "DCA: [init] Entering initializeSymbolCallables for top-level op: "
+      << top->getName() << "\n");
   analysisScope = top;
   auto walkFn = [&](Operation *symTable, bool allUsesVisible) {
+    LLVM_DEBUG(llvm::dbgs() << "DCA: [init] Processing symbol table op: "
+                            << symTable->getName() << "\n");
     Region &symbolTableRegion = symTable->getRegion(0);
     Block *symbolTableBlock = &symbolTableRegion.front();
 
     bool foundSymbolCallable = false;
     for (auto callable : symbolTableBlock->getOps<CallableOpInterface>()) {
+      LLVM_DEBUG(llvm::dbgs() << "DCA: [init] Found CallableOpInterface: "
+                              << callable.getOperation()->getName() << "\n");
       Region *callableRegion = callable.getCallableRegion();
       if (!callableRegion)
         continue;
@@ -159,6 +175,10 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
         auto *state =
             getOrCreate<PredecessorState>(getProgramPointAfter(callable));
         propagateIfChanged(state, state->setHasUnknownPredecessors());
+        LLVM_DEBUG(
+            llvm::dbgs()
+            << "DCA: [init] Marked callable as having unknown predecessors: "
+            << callable.getOperation()->getName() << "\n");
       }
       foundSymbolCallable = true;
     }
@@ -173,10 +193,17 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
     if (!uses) {
       // If we couldn't gather the symbol uses, conservatively assume that
       // we can't track information for any nested symbols.
+      LLVM_DEBUG(
+          llvm::dbgs()
+          << "DCA: [init] Could not gather symbol uses, conservatively marking "
+             "all nested callables as having unknown predecessors\n");
       return top->walk([&](CallableOpInterface callable) {
         auto *state =
             getOrCreate<PredecessorState>(getProgramPointAfter(callable));
         propagateIfChanged(state, state->setHasUnknownPredecessors());
+        LLVM_DEBUG(llvm::dbgs() << "DCA: [init] Marked nested callable as "
+                                   "having unknown predecessors: "
+                                << callable.getOperation()->getName() << "\n");
       });
     }
 
@@ -190,10 +217,17 @@ void DeadCodeAnalysis::initializeSymbolCallables(Operation *top) {
         continue;
       auto *state = getOrCreate<PredecessorState>(getProgramPointAfter(symbol));
       propagateIfChanged(state, state->setHasUnknownPredecessors());
+      LLVM_DEBUG(llvm::dbgs() << "DCA: [init] Found non-call use for symbol, "
+                                 "marked as having unknown predecessors: "
+                              << symbol->getName() << "\n");
     }
   };
   SymbolTable::walkSymbolTables(top, /*allSymUsesVisible=*/!top->getBlock(),
                                 walkFn);
+  LLVM_DEBUG(
+      llvm::dbgs()
+      << "DCA: [init] Finished initializeSymbolCallables for top-level op: "
+      << top->getName() << "\n");
 }
 
 /// Returns true if the operation is a returning terminator in region
@@ -205,9 +239,15 @@ static bool isRegionOrCallableReturn(Operation *op) {
 }
 
 LogicalResult DeadCodeAnalysis::initializeRecursively(Operation *op) {
+  LLVM_DEBUG(
+      llvm::dbgs() << "DCA: [init] Entering initializeRecursively for op: "
+                   << op->getName() << " at " << op << "\n");
   // Initialize the analysis by visiting every op with control-flow semantics.
   if (op->getNumRegions() || op->getNumSuccessors() ||
       isRegionOrCallableReturn(op) || isa<CallOpInterface>(op)) {
+    LLVM_DEBUG(llvm::dbgs()
+               << "DCA: [init] Visiting op with control-flow semantics: " << *op
+               << "\n");
     // When the liveness of the parent block changes, make sure to re-invoke the
     // analysis on the op.
     if (op->getBlock())
@@ -218,14 +258,26 @@ LogicalResult DeadCodeAnalysis::initializeRecursively(Operation *op) {
       return failure();
   }
   // Recurse on nested operations.
-  for (Region &region : op->getRegions())
-    for (Operation &op : region.getOps())
-      if (failed(initializeRecursively(&op)))
+  for (Region &region : op->getRegions()) {
+    LLVM_DEBUG(llvm::dbgs() << "DCA: [init] Recursing into region of op: "
+                            << op->getName() << "\n");
+    for (Operation &nestedOp : region.getOps()) {
+      LLVM_DEBUG(llvm::dbgs()
+                 << "DCA: [init] Recursing into nested op: "
+                 << nestedOp.getName() << " at " << &nestedOp << "\n");
+      if (failed(initializeRecursively(&nestedOp)))
         return failure();
+    }
+  }
+  LLVM_DEBUG(
+      llvm::dbgs() << "DCA: [init] Finished initializeRecursively for op: "
+                   << op->getName() << " at " << op << "\n");
   return success();
 }
 
 void DeadCodeAnalysis::markEdgeLive(Block *from, Block *to) {
+  LLVM_DEBUG(llvm::dbgs() << "DCA: Marking edge live from block " << from
+                          << " to block " << to << "\n");
   auto *state = getOrCreate<Executable>(getProgramPointBefore(to));
   propagateIfChanged(state, state->setToLive());
   auto *edgeState =
@@ -234,37 +286,54 @@ void DeadCodeAnalysis::markEdgeLive(Block *from, Block *to) {
 }
 
 void DeadCodeAnalysis::markEntryBlocksLive(Operation *op) {
+  LLVM_DEBUG(llvm::dbgs() << "DCA: Marking entry blocks live for op: "
+                          << op->getName() << "\n");
   for (Region &region : op->getRegions()) {
     if (region.empty())
       continue;
     auto *state =
         getOrCreate<Executable>(getProgramPointBefore(&region.front()));
     propagateIfChanged(state, state->setToLive());
+    LLVM_DEBUG(llvm::dbgs() << "DCA: Marked entry block live for region in op: "
+                            << op->getName() << "\n");
   }
 }
 
 LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
+  LLVM_DEBUG(llvm::dbgs() << "DCA: Visiting program point: " << point << " "
+                          << *point << "\n");
   if (point->isBlockStart())
     return success();
   Operation *op = point->getPrevOp();
+  LLVM_DEBUG(llvm::dbgs() << "DCA: Visiting operation: " << *op << "\n");
 
   // If the parent block is not executable, there is nothing to do.
   if (op->getBlock() != nullptr &&
-      !getOrCreate<Executable>(getProgramPointBefore(op->getBlock()))->isLive())
+      !getOrCreate<Executable>(getProgramPointBefore(op->getBlock()))
+           ->isLive()) {
+    LLVM_DEBUG(llvm::dbgs()
+               << "DCA: Parent block not live, skipping op: " << *op << "\n");
     return success();
+  }
 
   // We have a live call op. Add this as a live predecessor of the callee.
-  if (auto call = dyn_cast<CallOpInterface>(op))
+  if (auto call = dyn_cast<CallOpInterface>(op)) {
+    LLVM_DEBUG(llvm::dbgs() << "DCA: Visiting call operation: " << *op << "\n");
     visitCallOperation(call);
+  }
 
   // Visit the regions.
   if (op->getNumRegions()) {
     // Check if we can reason about the region control-flow.
     if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
+      LLVM_DEBUG(llvm::dbgs()
+                 << "DCA: Visiting region branch operation: " << *op << "\n");
       visitRegionBranchOperation(branch);
 
       // Check if this is a callable operation.
     } else if (auto callable = dyn_cast<CallableOpInterface>(op)) {
+      LLVM_DEBUG(llvm::dbgs()
+                 << "DCA: Visiting callable operation: " << *op << "\n");
       const auto *callsites = getOrCreateFor<PredecessorState>(
           getProgramPointAfter(op), getProgramPointAfter(callable));
 
@@ -276,16 +345,22 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
 
       // Otherwise, conservatively mark all entry blocks as executable.
     } else {
+      LLVM_DEBUG(llvm::dbgs() << "DCA: Marking all entry blocks live for op: "
+                              << *op << "\n");
       markEntryBlocksLive(op);
     }
   }
 
   if (isRegionOrCallableReturn(op)) {
     if (auto branch = dyn_cast<RegionBranchOpInterface>(op->getParentOp())) {
+      LLVM_DEBUG(llvm::dbgs()
+                 << "DCA: Visiting region terminator: " << *op << "\n");
       // Visit the exiting terminator of a region.
       visitRegionTerminator(op, branch);
     } else if (auto callable =
                    dyn_cast<CallableOpInterface>(op->getParentOp())) {
+      LLVM_DEBUG(llvm::dbgs()
+                 << "DCA: Visiting callable terminator: " << *op << "\n");
       // Visit the exiting terminator of a callable.
       visitCallableTerminator(op, callable);
     }
@@ -294,10 +369,14 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
   if (op->getNumSuccessors()) {
     // Check if we can reason about the control-flow.
     if (auto branch = dyn_cast<BranchOpInterface>(op)) {
+      LLVM_DEBUG(llvm::dbgs()
+                 << "DCA: Visiting branch operation: " << *op << "\n");
       visitBranchOperation(branch);
 
       // Otherwise, conservatively mark all successors as exectuable.
     } else {
+      LLVM_DEBUG(llvm::dbgs()
+                 << "DCA: Marking all successors live for op: " << *op << "\n");
       for (Block *successor : op->getSuccessors())
         markEdgeLive(op->getBlock(), successor);
     }
@@ -307,6 +386,8 @@ LogicalResult DeadCodeAnalysis::visit(ProgramPoint *point) {
 }
 
 void DeadCodeAnalysis::visitCallOperation(CallOpInterface call) {
+  LLVM_DEBUG(llvm::dbgs() << "DCA: visitCallOperation: "
+                          << call.getOperation()->getName() << "\n");
   Operation *callableOp = call.resolveCallableInTable(&symbolTable);
 
   // A call to a externally-defined callable has unknown predecessors.
@@ -329,11 +410,17 @@ void DeadCodeAnalysis::visitCallOperation(CallOpInterface call) {
     auto *callsites =
         getOrCreate<PredecessorState>(getProgramPointAfter(callableOp));
     propagateIfChanged(callsites, callsites->join(call));
+    LLVM_DEBUG(llvm::dbgs()
+               << "DCA: Added callsite as predecessor for callable: "
+               << callableOp->getName() << "\n");
   } else {
     // Mark this call op's predecessors as overdefined.
     auto *predecessors =
         getOrCreate<PredecessorState>(getProgramPointAfter(call));
     propagateIfChanged(predecessors, predecessors->setHasUnknownPredecessors());
+    LLVM_DEBUG(llvm::dbgs()
+               << "DCA: Marked call op's predecessors as unknown for: "
+               << call.getOperation()->getName() << "\n");
   }
 }
 
@@ -365,6 +452,8 @@ DeadCodeAnalysis::getOperandValues(Operation *op) {
 }
 
 void DeadCodeAnalysis::visitBranchOperation(BranchOpInterface branch) {
+  LLVM_DEBUG(llvm::dbgs() << "DCA: visitBranchOperation: "
+                          << branch.getOperation()->getName() << "\n");
   // Try to deduce a single successor for the branch.
   std::optional<SmallVector<Attribute>> operands = getOperandValues(branch);
   if (!operands)
@@ -372,15 +461,21 @@ void DeadCodeAnalysis::visitBranchOperation(BranchOpInterface branch) {
 
   if (Block *successor = branch.getSuccessorForOperands(*operands)) {
     markEdgeLive(branch->getBlock(), successor);
+    LLVM_DEBUG(llvm::dbgs()
+               << "DCA: Branch has single successor: " << successor << "\n");
   } else {
     // Otherwise, mark all successors as executable and outgoing edges.
     for (Block *successor : branch->getSuccessors())
       markEdgeLive(branch->getBlock(), successor);
+    LLVM_DEBUG(llvm::dbgs()
+               << "DCA: Branch has multiple/all successors live\n");
   }
 }
 
 void DeadCodeAnalysis::visitRegionBranchOperation(
     RegionBranchOpInterface branch) {
+  LLVM_DEBUG(llvm::dbgs() << "DCA: visitRegionBranchOperation: "
+                          << branch.getOperation()->getName() << "\n");
   // Try to deduce which regions are executable.
   std::optional<SmallVector<Attribute>> operands = getOperandValues(branch);
   if (!operands)
@@ -397,16 +492,22 @@ void DeadCodeAnalysis::visitRegionBranchOperation(
     // Mark the entry block as executable.
     auto *state = getOrCreate<Executable>(point);
     propagateIfChanged(state, state->setToLive());
+    LLVM_DEBUG(llvm::dbgs()
+               << "DCA: Marked region successor live: " << point << "\n");
     // Add the parent op as a predecessor.
     auto *predecessors = getOrCreate<PredecessorState>(point);
     propagateIfChanged(
         predecessors,
         predecessors->join(branch, successor.getSuccessorInputs()));
+    LLVM_DEBUG(llvm::dbgs()
+               << "DCA: Added region branch as predecessor for successor: "
+               << point << "\n");
   }
 }
 
 void DeadCodeAnalysis::visitRegionTerminator(Operation *op,
                                              RegionBranchOpInterface branch) {
+  LLVM_DEBUG(llvm::dbgs() << "DCA: visitRegionTerminator: " << *op << "\n");
   std::optional<SmallVector<Attribute>> operands = getOperandValues(op);
   if (!operands)
     return;
@@ -425,6 +526,9 @@ void DeadCodeAnalysis::visitRegionTerminator(Operation *op,
       auto *state =
           getOrCreate<Executable>(getProgramPointBefore(&region->front()));
       propagateIfChanged(state, state->setToLive());
+      LLVM_DEBUG(llvm::dbgs()
+                 << "DCA: Marked region entry block live for region: " << region
+                 << "\n");
       predecessors = getOrCreate<PredecessorState>(
           getProgramPointBefore(&region->front()));
     } else {
@@ -434,11 +538,16 @@ void DeadCodeAnalysis::visitRegionTerminator(Operation *op,
     }
     propagateIfChanged(predecessors,
                        predecessors->join(op, successor.getSuccessorInputs()));
+    LLVM_DEBUG(llvm::dbgs()
+               << "DCA: Added region terminator as predecessor for successor: "
+               << (successor.getSuccessor() ? "region entry" : "parent op")
+               << "\n");
   }
 }
 
 void DeadCodeAnalysis::visitCallableTerminator(Operation *op,
                                                CallableOpInterface callable) {
+  LLVM_DEBUG(llvm::dbgs() << "DCA: visitCallableTerminator: " << *op << "\n");
   // Add as predecessors to all callsites this return op.
   auto *callsites = getOrCreateFor<PredecessorState>(
       getProgramPointAfter(op), getProgramPointAfter(callable));
@@ -449,11 +558,18 @@ void DeadCodeAnalysis::visitCallableTerminator(Operation *op,
         getOrCreate<PredecessorState>(getProgramPointAfter(predecessor));
     if (canResolve) {
       propagateIfChanged(predecessors, predecessors->join(op));
+      LLVM_DEBUG(
+          llvm::dbgs()
+          << "DCA: Added callable terminator as predecessor for callsite: "
+          << predecessor->getName() << "\n");
     } else {
       // If the terminator is not a return-like, then conservatively assume we
       // can't resolve the predecessor.
       propagateIfChanged(predecessors,
                          predecessors->setHasUnknownPredecessors());
+      LLVM_DEBUG(llvm::dbgs()
+                 << "DCA: Could not resolve callable terminator for callsite: "
+                 << predecessor->getName() << "\n");
     }
   }
 }
diff --git a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
index d61cdb143e7dd..8d8af7a92ac23 100644
--- a/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
+++ b/mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp
@@ -10,6 +10,7 @@
 #include <cassert>
 #include <mlir/Analysis/DataFlow/LivenessAnalysis.h>
 
+#include "llvm/Support/Debug.h"
 #include <mlir/Analysis/DataFlow/ConstantPropagationAnalysis.h>
 #include <mlir/Analysis/DataFlow/DeadCodeAnalysis.h>
 #include <mlir/Analysis/DataFlow/SparseAnalysis.h>
@@ -20,6 +21,8 @@
 #include <mlir/Interfaces/SideEffectInterfaces.h>
 #include <mlir/Support/LLVM.h>
 
+#define DEBUG_TYPE "liveness-analysis"
+
 using namespace mlir;
 using namespace mlir::dataflow;
 
@@ -77,28 +80,46 @@ ChangeResult Liveness::meet(const AbstractSparseLattice &other) {
 LogicalResult
 LivenessAnalysis::visitOperation(Operation *op, ArrayRef<Liveness *> operands,
                                  ArrayRef<const Liveness *> results) {
+  LLVM_DEBUG(llvm::dbgs() << "LNA: Visiting operation: " << *op << "\n");
   // This marks values of type (1.a) and (4) liveness as "live".
   if (!isMemoryEffectFree(op) || op->hasTrait<OpTrait::ReturnLike>()) {
-    for (auto *operand : operands)
+    LLVM_DEBUG(llvm::dbgs()
+               << "LNA: [visitOperation] Operation has memory effects or is "
+                  "return-like, marking operands live\n");
+    for (auto *operand : operands) {
+      LLVM_DEBUG(llvm::dbgs() << "LNA:  [visitOperation] Marking operand live: "
+                              << operand << " (" << operand->isLive << ")\n");
       propagateIfChanged(operand, operand->markLive());
+    }
   }
 
   // This marks values of type (3) liveness as "live".
   bool foundLiveResult = false;
   for (const Liveness *r : results) {
     if (r->isLive && !foundLiveResult) {
+      LLVM_DEBUG(llvm::dbgs() << "LNA: [visitOperation] Found live result, "
+                                 "meeting all operands with result: "
+                              << r << "\n");
       // It is assumed that each operand is used to compute each result of an
       // op. Thus, if at least one result is live, each operand is live.
-      for (Liveness *operand : operands)
+      for (Liveness *operand : operands) {
+        LLVM_DEBUG(llvm::dbgs() << "LNA:  [visitOperation] Meeting operand: "
+                                << operand << " with result: " << r << "\n");
         meet(operand, *r);
+      }
       foundLiveResult = true;
     }
+    LLVM_DEBUG(llvm::dbgs()
+               << "LNA: [visitOperation] Adding dependency for result: " << r
+               << " after op: " << *op << "\n");
     addDependency(const_cast<Liveness *>(r), getProgramPointAfter(op));
   }
   return success();
 }
 
 void LivenessAnalysis::visitBranchOperand(OpOperand &operand) {
+  LLVM_DEBUG(llvm::dbgs() << "LNA: Visiting branch operand: " << operand.get()
+                          << " in op: " << *operand.getOwner() << "\n");
   // We know (at the moment) and assume (for the future) that `operand` is a
   // non-forwarded branch operand of a `RegionBranchOpInterface`,
   // `BranchOpInterface`, `RegionBranchTerminatorOpInterface` or return-like op.
@@ -130,6 +151,10 @@ void LivenessAnalysis::visitBranchOperand(OpOperand &operand) {
       for (Value result : op->getResults()) {
         if (getLatticeElement(result)->isLive) {
           mayLive = true;
+          LLVM_DEBUG(llvm::dbgs()
+                     << "LNA: [visitBranchOperand] Non-forwarded branch "
+                        "operand may be live due to live result: "
+                     << result << "\n");
           break;
         }
       }
@@ -149,6 +174,9 ...
[truncated]

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request adds extensive LLVM_DEBUG logging to the DataFlow analysis, particularly for the RemoveDeadValues pass, LivenessAnalysis, and DeadCodeAnalysis, to ease debugging of these passes.

  • Adds debug messages in RemoveDeadValues.cpp to trace liveness computations and dead value marking.
  • Enhances LivenessAnalysis.cpp and DeadCodeAnalysis.cpp with detailed logging for operation visits, branch operand handling, and control-flow analysis.

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
mlir/lib/Transforms/RemoveDeadValues.cpp Introduces debug logging in liveness checks and value marking.
mlir/lib/Analysis/DataFlow/LivenessAnalysis.cpp Adds LLVM_DEBUG messages to track operation processing and operand liveness.
mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp Integrates detailed logging in control-flow analysis and state propagation.
Comments suppressed due to low confidence (1)

mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp:263

  • [nitpick] Including additional unique identifiers (such as region indices or operation IDs) in the debug logs could further improve traceability in deeply nested control flows.
                            << op->getName() << "\n");

…(NFC)

Debugging issue with this pass is quite difficult at the moment, this
should help.
@joker-eph joker-eph merged commit 075cb69 into llvm:main Jun 22, 2025
5 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mlir:core MLIR Core Infrastructure mlir

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants