[GreedPatternRewriter] Preprocess constants while building worklist when not processing top down

This avoids accidentally reversing the order of constants during successive
application, e.g. when running the canonicalizer. This helps reduce the number
of iterations, and also avoids unnecessary changes to input IR.

Fixes #51892

Differential Revision: https://reviews.llvm.org/D122692
This commit is contained in:
River Riddle 2022-03-29 16:28:38 -07:00
parent 2e55bc9f3c
commit 59bbc7a085
13 changed files with 160 additions and 61 deletions

View file

@ -569,12 +569,12 @@ end subroutine test_proc_dummy_other
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.char<1,40>>, ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.char<1,40>>,
! CHECK-SAME: %[[VAL_1:.*]]: index, ! CHECK-SAME: %[[VAL_1:.*]]: index,
! CHECK-SAME: %[[VAL_2:.*]]: tuple<!fir.boxproc<() -> ()>, i64> {fir.char_proc}) -> !fir.boxchar<1> { ! CHECK-SAME: %[[VAL_2:.*]]: tuple<!fir.boxproc<() -> ()>, i64> {fir.char_proc}) -> !fir.boxchar<1> {
! CHECK: %[[VAL_3:.*]] = arith.constant 40 : index ! CHECK-DAG: %[[VAL_3:.*]] = arith.constant 40 : index
! CHECK: %[[VAL_4:.*]] = arith.constant 12 : index ! CHECK-DAG: %[[VAL_4:.*]] = arith.constant 12 : index
! CHECK: %[[VAL_5:.*]] = arith.constant false ! CHECK-DAG: %[[VAL_5:.*]] = arith.constant false
! CHECK: %[[VAL_6:.*]] = arith.constant 1 : index ! CHECK-DAG: %[[VAL_6:.*]] = arith.constant 1 : index
! CHECK: %[[VAL_7:.*]] = arith.constant 32 : i8 ! CHECK-DAG: %[[VAL_7:.*]] = arith.constant 32 : i8
! CHECK: %[[VAL_8:.*]] = arith.constant 0 : index ! CHECK-DAG: %[[VAL_8:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.char<1,40>>) -> !fir.ref<!fir.char<1,?>> ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.char<1,40>>) -> !fir.ref<!fir.char<1,?>>
! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref<!fir.char<1,12>> ! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref<!fir.char<1,12>>
! CHECK: %[[VAL_11:.*]] = fir.extract_value %[[VAL_2]], [0 : index] : (tuple<!fir.boxproc<() -> ()>, i64>) -> !fir.boxproc<() -> ()> ! CHECK: %[[VAL_11:.*]] = fir.extract_value %[[VAL_2]], [0 : index] : (tuple<!fir.boxproc<() -> ()>, i64>) -> !fir.boxproc<() -> ()>

View file

@ -45,6 +45,16 @@ public:
function_ref<void(Operation *)> preReplaceAction = nullptr, function_ref<void(Operation *)> preReplaceAction = nullptr,
bool *inPlaceUpdate = nullptr); bool *inPlaceUpdate = nullptr);
/// Tries to fold a pre-existing constant operation. `constValue` represents
/// the value of the constant, and can be optionally passed if the value is
/// already known (e.g. if the constant was discovered by m_Constant). This is
/// purely an optimization opportunity for callers that already know the value
/// of the constant. Returns false if an existing constant for `op` already
/// exists in the folder, in which case `op` is replaced and erased.
/// Otherwise, returns true and `op` is inserted into the folder (and
/// hoisted if necessary).
bool insertKnownConstant(Operation *op, Attribute constValue = {});
/// Notifies that the given constant `op` should be remove from this /// Notifies that the given constant `op` should be remove from this
/// OperationFolder's internal bookkeeping. /// OperationFolder's internal bookkeeping.
/// ///
@ -114,6 +124,10 @@ private:
using ConstantMap = using ConstantMap =
DenseMap<std::tuple<Dialect *, Attribute, Type>, Operation *>; DenseMap<std::tuple<Dialect *, Attribute, Type>, Operation *>;
/// Returns true if the given operation is an already folded constant that is
/// owned by this folder.
bool isFolderOwnedConstant(Operation *op) const;
/// Tries to perform folding on the given `op`. If successful, populates /// Tries to perform folding on the given `op`. If successful, populates
/// `results` with the results of the folding. /// `results` with the results of the folding.
LogicalResult tryToFold( LogicalResult tryToFold(

View file

@ -75,8 +75,14 @@ LogicalResult OperationFolder::tryToFold(
// If this is a unique'd constant, return failure as we know that it has // If this is a unique'd constant, return failure as we know that it has
// already been folded. // already been folded.
if (referencedDialects.count(op)) if (isFolderOwnedConstant(op)) {
// Check to see if we should rehoist, i.e. if a non-constant operation was
// inserted before this one.
Block *opBlock = op->getBlock();
if (&opBlock->front() != op && !isFolderOwnedConstant(op->getPrevNode()))
op->moveBefore(&opBlock->front());
return failure(); return failure();
}
// Try to fold the operation. // Try to fold the operation.
SmallVector<Value, 8> results; SmallVector<Value, 8> results;
@ -104,6 +110,59 @@ LogicalResult OperationFolder::tryToFold(
return success(); return success();
} }
bool OperationFolder::insertKnownConstant(Operation *op, Attribute constValue) {
Block *opBlock = op->getBlock();
// If this is a constant we unique'd, we don't need to insert, but we can
// check to see if we should rehoist it.
if (isFolderOwnedConstant(op)) {
if (&opBlock->front() != op && !isFolderOwnedConstant(op->getPrevNode()))
op->moveBefore(&opBlock->front());
return true;
}
// Get the constant value of the op if necessary.
if (!constValue) {
matchPattern(op, m_Constant(&constValue));
assert(constValue && "expected `op` to be a constant");
} else {
// Ensure that the provided constant was actually correct.
#ifndef NDEBUG
Attribute expectedValue;
matchPattern(op, m_Constant(&expectedValue));
assert(
expectedValue == constValue &&
"provided constant value was not the expected value of the constant");
#endif
}
// Check for an existing constant operation for the attribute value.
Region *insertRegion = getInsertionRegion(interfaces, opBlock);
auto &uniquedConstants = foldScopes[insertRegion];
Operation *&folderConstOp = uniquedConstants[std::make_tuple(
op->getDialect(), constValue, *op->result_type_begin())];
// If there is an existing constant, replace `op`.
if (folderConstOp) {
op->replaceAllUsesWith(folderConstOp);
op->erase();
return false;
}
// Otherwise, we insert `op`. If `op` is in the insertion block and is either
// already at the front of the block, or the previous operation is already a
// constant we unique'd (i.e. one we inserted), then we don't need to do
// anything. Otherwise, we move the constant to the insertion block.
Block *insertBlock = &insertRegion->front();
if (opBlock != insertBlock || (&insertBlock->front() != op &&
!isFolderOwnedConstant(op->getPrevNode())))
op->moveBefore(&insertBlock->front());
folderConstOp = op;
referencedDialects[op].push_back(op->getDialect());
return true;
}
/// Notifies that the given constant `op` should be remove from this /// Notifies that the given constant `op` should be remove from this
/// OperationFolder's internal bookkeeping. /// OperationFolder's internal bookkeeping.
void OperationFolder::notifyRemoval(Operation *op) { void OperationFolder::notifyRemoval(Operation *op) {
@ -156,6 +215,10 @@ Value OperationFolder::getOrCreateConstant(OpBuilder &builder, Dialect *dialect,
return constOp ? constOp->getResult(0) : Value(); return constOp ? constOp->getResult(0) : Value();
} }
bool OperationFolder::isFolderOwnedConstant(Operation *op) const {
return referencedDialects.count(op);
}
/// Tries to perform folding on the given `op`. If successful, populates /// Tries to perform folding on the given `op`. If successful, populates
/// `results` with the results of the folding. /// `results` with the results of the folding.
LogicalResult OperationFolder::tryToFold( LogicalResult OperationFolder::tryToFold(

View file

@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "mlir/Transforms/GreedyPatternRewriteDriver.h" #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
#include "mlir/IR/Matchers.h"
#include "mlir/Interfaces/SideEffectInterfaces.h" #include "mlir/Interfaces/SideEffectInterfaces.h"
#include "mlir/Rewrite/PatternApplicator.h" #include "mlir/Rewrite/PatternApplicator.h"
#include "mlir/Transforms/FoldUtils.h" #include "mlir/Transforms/FoldUtils.h"
@ -140,8 +141,18 @@ bool GreedyPatternRewriteDriver::simplify(MutableArrayRef<Region> regions) {
if (!config.useTopDownTraversal) { if (!config.useTopDownTraversal) {
// Add operations to the worklist in postorder. // Add operations to the worklist in postorder.
for (auto &region : regions) for (auto &region : regions) {
region.walk([this](Operation *op) { addToWorklist(op); }); region.walk([this](Operation *op) {
// If we aren't processing top-down, check for existing constants when
// populating the worklist. This avoids accidentally reversing the
// constant order during processing.
Attribute constValue;
if (matchPattern(op, m_Constant(&constValue)))
if (!folder.insertKnownConstant(op, constValue))
return;
addToWorklist(op);
});
}
} else { } else {
// Add all nested operations to the worklist in preorder. // Add all nested operations to the worklist in preorder.
for (auto &region : regions) for (auto &region : regions)

View file

@ -244,9 +244,9 @@ func @transfer_read_progressive(%A : memref<?x?xf32>, %base: index) -> vector<3x
// CHECK: } // CHECK: }
// CHECK: %[[cst:.*]] = memref.load %[[alloc]][] : memref<vector<3x15xf32>> // CHECK: %[[cst:.*]] = memref.load %[[alloc]][] : memref<vector<3x15xf32>>
// FULL-UNROLL: %[[C7:.*]] = arith.constant 7.000000e+00 : f32 // FULL-UNROLL-DAG: %[[C7:.*]] = arith.constant 7.000000e+00 : f32
// FULL-UNROLL: %[[VEC0:.*]] = arith.constant dense<7.000000e+00> : vector<3x15xf32> // FULL-UNROLL-DAG: %[[VEC0:.*]] = arith.constant dense<7.000000e+00> : vector<3x15xf32>
// FULL-UNROLL: %[[C0:.*]] = arith.constant 0 : index // FULL-UNROLL-DAG: %[[C0:.*]] = arith.constant 0 : index
// FULL-UNROLL: %[[DIM:.*]] = memref.dim %[[A]], %[[C0]] : memref<?x?xf32> // FULL-UNROLL: %[[DIM:.*]] = memref.dim %[[A]], %[[C0]] : memref<?x?xf32>
// FULL-UNROLL: cmpi sgt, %[[DIM]], %[[base]] : index // FULL-UNROLL: cmpi sgt, %[[DIM]], %[[base]] : index
// FULL-UNROLL: %[[VEC1:.*]] = scf.if %{{.*}} -> (vector<3x15xf32>) { // FULL-UNROLL: %[[VEC1:.*]] = scf.if %{{.*}} -> (vector<3x15xf32>) {

View file

@ -5,33 +5,33 @@
// CHECK: %[[MEMREF:.*]]: memref<?xf32> // CHECK: %[[MEMREF:.*]]: memref<?xf32>
func @num_worker_threads(%arg0: memref<?xf32>) { func @num_worker_threads(%arg0: memref<?xf32>) {
// CHECK: %[[scalingCstInit:.*]] = arith.constant 8.000000e+00 : f32 // CHECK-DAG: %[[scalingCstInit:.*]] = arith.constant 8.000000e+00 : f32
// CHECK: %[[bracketLowerBound4:.*]] = arith.constant 4 : index // CHECK-DAG: %[[bracketLowerBound4:.*]] = arith.constant 4 : index
// CHECK: %[[scalingCst4:.*]] = arith.constant 4.000000e+00 : f32 // CHECK-DAG: %[[scalingCst4:.*]] = arith.constant 4.000000e+00 : f32
// CHECK: %[[bracketLowerBound8:.*]] = arith.constant 8 : index // CHECK-DAG: %[[bracketLowerBound8:.*]] = arith.constant 8 : index
// CHECK: %[[scalingCst8:.*]] = arith.constant 2.000000e+00 : f32 // CHECK-DAG: %[[scalingCst8:.*]] = arith.constant 2.000000e+00 : f32
// CHECK: %[[bracketLowerBound16:.*]] = arith.constant 16 : index // CHECK-DAG: %[[bracketLowerBound16:.*]] = arith.constant 16 : index
// CHECK: %[[scalingCst16:.*]] = arith.constant 1.000000e+00 : f32 // CHECK-DAG: %[[scalingCst16:.*]] = arith.constant 1.000000e+00 : f32
// CHECK: %[[bracketLowerBound32:.*]] = arith.constant 32 : index // CHECK-DAG: %[[bracketLowerBound32:.*]] = arith.constant 32 : index
// CHECK: %[[scalingCst32:.*]] = arith.constant 8.000000e-01 : f32 // CHECK-DAG: %[[scalingCst32:.*]] = arith.constant 8.000000e-01 : f32
// CHECK: %[[bracketLowerBound64:.*]] = arith.constant 64 : index // CHECK-DAG: %[[bracketLowerBound64:.*]] = arith.constant 64 : index
// CHECK: %[[scalingCst64:.*]] = arith.constant 6.000000e-01 : f32 // CHECK-DAG: %[[scalingCst64:.*]] = arith.constant 6.000000e-01 : f32
// CHECK: %[[workersIndex:.*]] = async.runtime.num_worker_threads : index // CHECK: %[[workersIndex:.*]] = async.runtime.num_worker_threads : index
// CHECK: %[[inBracket4:.*]] = arith.cmpi sgt, %[[workersIndex]], %[[bracketLowerBound4]] : index // CHECK: %[[inBracket4:.*]] = arith.cmpi sgt, %[[workersIndex]], %[[bracketLowerBound4]] : index
// CHECK: %[[scalingFactor4:.*]] = arith.select %[[inBracket4]], %[[scalingCst4]], %[[scalingCstInit]] : f32 // CHECK: %[[scalingFactor4:.*]] = arith.select %[[inBracket4]], %[[scalingCst4]], %[[scalingCstInit]] : f32
// CHECK: %[[inBracket8:.*]] = arith.cmpi sgt, %[[workersIndex]], %[[bracketLowerBound8]] : index // CHECK: %[[inBracket8:.*]] = arith.cmpi sgt, %[[workersIndex]], %[[bracketLowerBound8]] : index
// CHECK: %[[scalingFactor8:.*]] = arith.select %[[inBracket8]], %[[scalingCst8]], %[[scalingFactor4]] : f32 // CHECK: %[[scalingFactor8:.*]] = arith.select %[[inBracket8]], %[[scalingCst8]], %[[scalingFactor4]] : f32
// CHECK: %[[inBracket16:.*]] = arith.cmpi sgt, %[[workersIndex]], %[[bracketLowerBound16]] : index // CHECK: %[[inBracket16:.*]] = arith.cmpi sgt, %[[workersIndex]], %[[bracketLowerBound16]] : index
// CHECK: %[[scalingFactor16:.*]] = arith.select %[[inBracket16]], %[[scalingCst16]], %[[scalingFactor8]] : f32 // CHECK: %[[scalingFactor16:.*]] = arith.select %[[inBracket16]], %[[scalingCst16]], %[[scalingFactor8]] : f32
// CHECK: %[[inBracket32:.*]] = arith.cmpi sgt, %[[workersIndex]], %[[bracketLowerBound32]] : index // CHECK: %[[inBracket32:.*]] = arith.cmpi sgt, %[[workersIndex]], %[[bracketLowerBound32]] : index
// CHECK: %[[scalingFactor32:.*]] = arith.select %[[inBracket32]], %[[scalingCst32]], %[[scalingFactor16]] : f32 // CHECK: %[[scalingFactor32:.*]] = arith.select %[[inBracket32]], %[[scalingCst32]], %[[scalingFactor16]] : f32
// CHECK: %[[inBracket64:.*]] = arith.cmpi sgt, %[[workersIndex]], %[[bracketLowerBound64]] : index // CHECK: %[[inBracket64:.*]] = arith.cmpi sgt, %[[workersIndex]], %[[bracketLowerBound64]] : index
// CHECK: %[[scalingFactor64:.*]] = arith.select %[[inBracket64]], %[[scalingCst64]], %[[scalingFactor32]] : f32 // CHECK: %[[scalingFactor64:.*]] = arith.select %[[inBracket64]], %[[scalingCst64]], %[[scalingFactor32]] : f32
// CHECK: %[[workersInt:.*]] = arith.index_cast %[[workersIndex]] : index to i32 // CHECK: %[[workersInt:.*]] = arith.index_cast %[[workersIndex]] : index to i32
// CHECK: %[[workersFloat:.*]] = arith.sitofp %[[workersInt]] : i32 to f32 // CHECK: %[[workersFloat:.*]] = arith.sitofp %[[workersInt]] : i32 to f32
// CHECK: %[[scaledFloat:.*]] = arith.mulf %[[scalingFactor64]], %[[workersFloat]] : f32 // CHECK: %[[scaledFloat:.*]] = arith.mulf %[[scalingFactor64]], %[[workersFloat]] : f32
// CHECK: %[[scaledInt:.*]] = arith.fptosi %[[scaledFloat]] : f32 to i32 // CHECK: %[[scaledInt:.*]] = arith.fptosi %[[scaledFloat]] : f32 to i32
// CHECK: %[[scaledIndex:.*]] = arith.index_cast %[[scaledInt]] : i32 to index // CHECK: %[[scaledIndex:.*]] = arith.index_cast %[[scaledInt]] : i32 to index
%lb = arith.constant 0 : index %lb = arith.constant 0 : index
%ub = arith.constant 100 : index %ub = arith.constant 100 : index

View file

@ -42,9 +42,9 @@ func @main() -> (tensor<i32>) attributes {} {
} }
// CHECK-LABEL: func @main() // CHECK-LABEL: func @main()
// CHECK-NEXT: arith.constant 0 // CHECK-DAG: arith.constant 0
// CHECK-NEXT: arith.constant 10 // CHECK-DAG: arith.constant 10
// CHECK-NEXT: cf.br ^[[bb1:.*]](%{{.*}}: i32) // CHECK: cf.br ^[[bb1:.*]](%{{.*}}: i32)
// CHECK-NEXT: ^[[bb1]](%{{.*}}: i32): // CHECK-NEXT: ^[[bb1]](%{{.*}}: i32):
// CHECK-NEXT: arith.cmpi slt, %{{.*}}, %{{.*}} // CHECK-NEXT: arith.cmpi slt, %{{.*}}, %{{.*}}
// CHECK-NEXT: cf.cond_br %{{.*}}, ^[[bb2:.*]](%{{.*}} : i32), ^bb3(%{{.*}} : i32) // CHECK-NEXT: cf.cond_br %{{.*}}, ^[[bb2:.*]](%{{.*}} : i32), ^bb3(%{{.*}} : i32)
@ -106,9 +106,9 @@ func @main() -> (tensor<i32>) attributes {} {
} }
// CHECK-LABEL: func @main() // CHECK-LABEL: func @main()
// CHECK-NEXT: arith.constant 0 // CHECK-DAG: arith.constant 0
// CHECK-NEXT: arith.constant 10 // CHECK-DAG: arith.constant 10
// CHECK-NEXT: cf.br ^[[bb1:.*]](%{{.*}}: i32) // CHECK: cf.br ^[[bb1:.*]](%{{.*}}: i32)
// CHECK-NEXT: ^[[bb1]](%{{.*}}: i32): // CHECK-NEXT: ^[[bb1]](%{{.*}}: i32):
// CHECK-NEXT: arith.cmpi slt, %{{.*}}, %{{.*}} // CHECK-NEXT: arith.cmpi slt, %{{.*}}, %{{.*}}
// CHECK-NEXT: cf.cond_br %{{.*}}, ^[[bb2:.*]](%{{.*}} : i32), ^bb3(%{{.*}} : i32) // CHECK-NEXT: cf.cond_br %{{.*}}, ^[[bb2:.*]](%{{.*}} : i32), ^bb3(%{{.*}} : i32)
@ -171,9 +171,9 @@ func @main() -> (tensor<i32>) attributes {} {
} }
// CHECK-LABEL: func @main() // CHECK-LABEL: func @main()
// CHECK-NEXT: arith.constant 0 // CHECK-DAG: arith.constant 0
// CHECK-NEXT: arith.constant 10 // CHECK-DAG: arith.constant 10
// CHECK-NEXT: cf.br ^[[bb1:.*]](%{{.*}}: i32) // CHECK: cf.br ^[[bb1:.*]](%{{.*}}: i32)
// CHECK-NEXT: ^[[bb1]](%{{.*}}: i32): // CHECK-NEXT: ^[[bb1]](%{{.*}}: i32):
// CHECK-NEXT: arith.cmpi slt, %{{.*}}, %{{.*}} // CHECK-NEXT: arith.cmpi slt, %{{.*}}, %{{.*}}
// CHECK-NEXT: cf.cond_br %{{.*}}, ^[[bb2:.*]](%{{.*}} : i32), ^bb2(%{{.*}} : i32) // CHECK-NEXT: cf.cond_br %{{.*}}, ^[[bb2:.*]](%{{.*}} : i32), ^bb2(%{{.*}} : i32)

View file

@ -301,7 +301,7 @@ func @aligned_promote_fill(%arg0: memref<?x?xf32, offset: ?, strides: [?, 1]>) {
return return
} }
// CHECK-LABEL: func @aligned_promote_fill // CHECK-LABEL: func @aligned_promote_fill
// CHECK: %[[cf:.*]] = arith.constant {{.*}} : f32 // CHECK: %[[cf:.*]] = arith.constant 1.{{.*}} : f32
// CHECK: %[[s0:.*]] = memref.subview {{.*}}: memref<?x?xf32, #map{{.*}}> to memref<?x?xf32, #map{{.*}}> // CHECK: %[[s0:.*]] = memref.subview {{.*}}: memref<?x?xf32, #map{{.*}}> to memref<?x?xf32, #map{{.*}}>
// CHECK: %[[a0:.*]] = memref.alloc() {alignment = 32 : i64} : memref<32000000xi8> // CHECK: %[[a0:.*]] = memref.alloc() {alignment = 32 : i64} : memref<32000000xi8>
// CHECK: %[[v0:.*]] = memref.view %[[a0]]{{.*}} : memref<32000000xi8> to memref<?x?xf32> // CHECK: %[[v0:.*]] = memref.view %[[a0]]{{.*}} : memref<32000000xi8> to memref<?x?xf32>

View file

@ -78,11 +78,11 @@ func @dense1(%arga: tensor<32x16xf32, #DenseMatrix>,
// CHECK-LABEL: func @dense2( // CHECK-LABEL: func @dense2(
// CHECK-SAME: %[[VAL_0:.*]]: tensor<32x16xf32, #sparse_tensor.encoding<{{.*}}>>, // CHECK-SAME: %[[VAL_0:.*]]: tensor<32x16xf32, #sparse_tensor.encoding<{{.*}}>>,
// CHECK-SAME: %[[VAL_1:.*]]: tensor<32x16xf32> {linalg.inplaceable = true}) -> tensor<32x16xf32> { // CHECK-SAME: %[[VAL_1:.*]]: tensor<32x16xf32> {linalg.inplaceable = true}) -> tensor<32x16xf32> {
// CHECK: %[[VAL_2:.*]] = arith.constant 1.000000e+00 : f32 // CHECK-DAG: %[[VAL_2:.*]] = arith.constant 1.000000e+00 : f32
// CHECK: %[[VAL_3:.*]] = arith.constant 32 : index // CHECK-DAG: %[[VAL_3:.*]] = arith.constant 32 : index
// CHECK: %[[VAL_4:.*]] = arith.constant 16 : index // CHECK-DAG: %[[VAL_4:.*]] = arith.constant 16 : index
// CHECK: %[[VAL_5:.*]] = arith.constant 0 : index // CHECK-DAG: %[[VAL_5:.*]] = arith.constant 0 : index
// CHECK: %[[VAL_6:.*]] = arith.constant 1 : index // CHECK-DAG: %[[VAL_6:.*]] = arith.constant 1 : index
// CHECK: %[[VAL_7:.*]] = sparse_tensor.values %[[VAL_0]] : tensor<32x16xf32, #sparse_tensor.encoding<{{.*}}>> to memref<?xf32> // CHECK: %[[VAL_7:.*]] = sparse_tensor.values %[[VAL_0]] : tensor<32x16xf32, #sparse_tensor.encoding<{{.*}}>> to memref<?xf32>
// CHECK: %[[VAL_8:.*]] = bufferization.to_memref %[[VAL_1]] : memref<32x16xf32> // CHECK: %[[VAL_8:.*]] = bufferization.to_memref %[[VAL_1]] : memref<32x16xf32>
// CHECK: scf.for %[[VAL_9:.*]] = %[[VAL_5]] to %[[VAL_3]] step %[[VAL_6]] { // CHECK: scf.for %[[VAL_9:.*]] = %[[VAL_5]] to %[[VAL_3]] step %[[VAL_6]] {

View file

@ -24,9 +24,9 @@
// CHECK-SAME: %[[VAL_2:.*2]]: f32, // CHECK-SAME: %[[VAL_2:.*2]]: f32,
// CHECK-SAME: %[[VAL_3:.*3]]: f32, // CHECK-SAME: %[[VAL_3:.*3]]: f32,
// CHECK-SAME: %[[VAL_4:.*4]]: tensor<32x16xf32> {linalg.inplaceable = true}) -> tensor<32x16xf32> { // CHECK-SAME: %[[VAL_4:.*4]]: tensor<32x16xf32> {linalg.inplaceable = true}) -> tensor<32x16xf32> {
// CHECK: %[[VAL_5:.*]] = arith.constant 2.200000e+00 : f32 // CHECK-DAG: %[[VAL_5:.*]] = arith.constant 2.200000e+00 : f32
// CHECK: %[[VAL_6:.*]] = arith.constant 0 : index // CHECK-DAG: %[[VAL_6:.*]] = arith.constant 0 : index
// CHECK: %[[VAL_7:.*]] = arith.constant 1 : index // CHECK-DAG: %[[VAL_7:.*]] = arith.constant 1 : index
// CHECK: %[[VAL_8:.*]] = arith.addf %[[VAL_2]], %[[VAL_3]] : f32 // CHECK: %[[VAL_8:.*]] = arith.addf %[[VAL_2]], %[[VAL_3]] : f32
// CHECK: %[[VAL_9:.*]] = sparse_tensor.pointers %[[VAL_0]], %[[VAL_6]] : tensor<32x16xf32, #sparse_tensor.encoding<{{.*}}>> to memref<?xindex> // CHECK: %[[VAL_9:.*]] = sparse_tensor.pointers %[[VAL_0]], %[[VAL_6]] : tensor<32x16xf32, #sparse_tensor.encoding<{{.*}}>> to memref<?xindex>
// CHECK: %[[VAL_10:.*]] = sparse_tensor.indices %[[VAL_0]], %[[VAL_6]] : tensor<32x16xf32, #sparse_tensor.encoding<{{.*}}>> to memref<?xindex> // CHECK: %[[VAL_10:.*]] = sparse_tensor.indices %[[VAL_0]], %[[VAL_6]] : tensor<32x16xf32, #sparse_tensor.encoding<{{.*}}>> to memref<?xindex>

View file

@ -180,9 +180,9 @@ func @tensor.from_elements_3d(%f0 : f32) -> tensor<3x2x2xf32> {
// CHECK-LABEL: func @tensor.generate( // CHECK-LABEL: func @tensor.generate(
// CHECK-SAME: %[[ARG:.*]]: tensor<*xf32>, // CHECK-SAME: %[[ARG:.*]]: tensor<*xf32>,
// CHECK-SAME: %[[DYNAMIC_EXTENT:.*]]: index) -> tensor<?xindex> { // CHECK-SAME: %[[DYNAMIC_EXTENT:.*]]: index) -> tensor<?xindex> {
// CHECK: %[[CASTED:.*]] = bufferization.to_memref %[[ARG]] : memref<*xf32>
// CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index // CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index
// CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index // CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index
// CHECK: %[[CASTED:.*]] = bufferization.to_memref %[[ARG]] : memref<*xf32>
// CHECK: %[[MEMREF:.*]] = memref.alloc(%[[DYNAMIC_EXTENT]]) {{.*}} : memref<?xindex> // CHECK: %[[MEMREF:.*]] = memref.alloc(%[[DYNAMIC_EXTENT]]) {{.*}} : memref<?xindex>
// CHECK: scf.parallel (%[[I:.*]]) = (%[[C0]]) to (%[[DYNAMIC_EXTENT]]) step (%[[C1]]) { // CHECK: scf.parallel (%[[I:.*]]) = (%[[C0]]) to (%[[DYNAMIC_EXTENT]]) step (%[[C1]]) {
// CHECK: %[[ELEM:.*]] = memref.dim %[[CASTED]], %[[I]] : memref<*xf32> // CHECK: %[[ELEM:.*]] = memref.dim %[[CASTED]], %[[I]] : memref<*xf32>

View file

@ -27,8 +27,8 @@ func @pad_non_zero_sizes(%input: tensor<?x?x8xf32>, %low0: index, %high1: index)
return %0 : tensor<?x?x8xf32> return %0 : tensor<?x?x8xf32>
} }
// CHECK: %[[F0:.+]] = arith.constant 0.000000e+00 : f32 // CHECK-DAG: %[[F0:.+]] = arith.constant 0.000000e+00 : f32
// CHECK: %[[C0:.+]] = arith.constant 0 : index // CHECK-DAG: %[[C0:.+]] = arith.constant 0 : index
// CHECK: %[[EQ0:.+]] = arith.cmpi eq, %[[LOW0]], %[[C0]] : index // CHECK: %[[EQ0:.+]] = arith.cmpi eq, %[[LOW0]], %[[C0]] : index
// CHECK: %[[EQ1:.+]] = arith.cmpi eq, %[[HIGH1]], %[[C0]] : index // CHECK: %[[EQ1:.+]] = arith.cmpi eq, %[[HIGH1]], %[[C0]] : index
// CHECK: %[[AND:.+]] = arith.andi %[[EQ0]], %[[EQ1]] : i1 // CHECK: %[[AND:.+]] = arith.andi %[[EQ0]], %[[EQ1]] : i1

View file

@ -1,4 +1,4 @@
// RUN: mlir-opt -test-patterns %s | FileCheck %s // RUN: mlir-opt -test-patterns -test-patterns %s | FileCheck %s
func @foo() -> i32 { func @foo() -> i32 {
%c42 = arith.constant 42 : i32 %c42 = arith.constant 42 : i32
@ -22,3 +22,14 @@ func @test_fold_before_previously_folded_op() -> (i32, i32) {
%1 = "test.cast"() {test_fold_before_previously_folded_op} : () -> (i32) %1 = "test.cast"() {test_fold_before_previously_folded_op} : () -> (i32)
return %0, %1 : i32, i32 return %0, %1 : i32, i32
} }
func @test_dont_reorder_constants() -> (i32, i32, i32) {
// Test that we don't reorder existing constants during folding if it isn't necessary.
// CHECK: %[[CST:.+]] = arith.constant 1
// CHECK-NEXT: %[[CST:.+]] = arith.constant 2
// CHECK-NEXT: %[[CST:.+]] = arith.constant 3
%0 = arith.constant 1 : i32
%1 = arith.constant 2 : i32
%2 = arith.constant 3 : i32
return %0, %1, %2 : i32, i32, i32
}