diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td --- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td +++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td @@ -604,7 +604,6 @@ let hasCanonicalizer = 1; let hasFolder = 1; - let hasVerifier = 1; } //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/Tensor/IR/TensorOps.td b/mlir/include/mlir/Dialect/Tensor/IR/TensorOps.td --- a/mlir/include/mlir/Dialect/Tensor/IR/TensorOps.td +++ b/mlir/include/mlir/Dialect/Tensor/IR/TensorOps.td @@ -143,7 +143,6 @@ let hasCanonicalizer = 1; let hasFolder = 1; - let hasVerifier = 1; } //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp --- a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp +++ b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp @@ -495,14 +495,16 @@ MemRefType memRefType = operandType.cast(); if (std::optional index = getConstantDimIndex(dimOp)) { int64_t i = *index; - if (memRefType.isDynamicDim(i)) { - // extract dynamic size from the memref descriptor. - MemRefDescriptor descriptor(adaptor.getSource()); - return descriptor.size(rewriter, loc, i); + if (i >= 0 && i < memRefType.getRank()) { + if (memRefType.isDynamicDim(i)) { + // extract dynamic size from the memref descriptor. + MemRefDescriptor descriptor(adaptor.getSource()); + return descriptor.size(rewriter, loc, i); + } + // Use constant for static size. + int64_t dimSize = memRefType.getDimSize(i); + return createIndexConstant(rewriter, loc, dimSize); } - // Use constant for static size. - int64_t dimSize = memRefType.getDimSize(i); - return createIndexConstant(rewriter, loc, dimSize); } Value index = adaptor.getIndex(); int64_t rank = memRefType.getRank(); diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp --- a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp +++ b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp @@ -941,25 +941,6 @@ return Speculation::Speculatable; } -LogicalResult DimOp::verify() { - // Assume unknown index to be in range. - std::optional index = getConstantIndex(); - if (!index) - return success(); - - // Check that constant index is not knowingly out of range. - auto type = getSource().getType(); - if (auto memrefType = type.dyn_cast()) { - if (*index >= memrefType.getRank()) - return emitOpError("index is out of range"); - } else if (type.isa()) { - // Assume index to be in range. - } else { - llvm_unreachable("expected operand with memref type"); - } - return success(); -} - /// Return a map with key being elements in `vals` and data being number of /// occurences of it. Use std::map, since the `vals` here are strides and the /// dynamic stride value is the same as the tombstone value for @@ -1067,6 +1048,12 @@ if (!memrefType) return {}; + // Out of bound indices produce undefined behavior but are still valid IR. + // Don't choke on them. + int64_t indexVal = index.getInt(); + if (indexVal < 0 || indexVal >= memrefType.getRank()) + return {}; + // Fold if the shape extent along the given index is known. if (!memrefType.isDynamicDim(index.getInt())) { Builder builder(getContext()); diff --git a/mlir/lib/Dialect/Tensor/IR/TensorOps.cpp b/mlir/lib/Dialect/Tensor/IR/TensorOps.cpp --- a/mlir/lib/Dialect/Tensor/IR/TensorOps.cpp +++ b/mlir/lib/Dialect/Tensor/IR/TensorOps.cpp @@ -399,25 +399,6 @@ return Speculation::Speculatable; } -LogicalResult DimOp::verify() { - // Assume unknown index to be in range. - std::optional index = getConstantIndex(); - if (!index) - return success(); - - // Check that constant index is not knowingly out of range. - auto type = getSource().getType(); - if (auto tensorType = type.dyn_cast()) { - if (*index >= tensorType.getRank()) - return emitOpError("index is out of range"); - } else if (type.isa()) { - // Assume index to be in range. - } else { - llvm_unreachable("expected operand with tensor type"); - } - return success(); -} - OpFoldResult DimOp::fold(FoldAdaptor adaptor) { // All forms of folding require a known index. auto index = adaptor.getIndex().dyn_cast_or_null(); @@ -429,6 +410,12 @@ if (!tensorType) return {}; + // Out of bound indices produce undefined behavior but are still valid IR. + // Don't choke on them. + int64_t indexVal = index.getInt(); + if (indexVal < 0 || indexVal >= tensorType.getRank()) + return {}; + // Fold if the shape extent along the given index is known. if (!tensorType.isDynamicDim(index.getInt())) { Builder builder(getContext()); diff --git a/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir b/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir --- a/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir +++ b/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir @@ -188,6 +188,20 @@ // ----- +// CHECK-LABEL: func @static_out_of_bound_memref_dim +func.func @static_out_of_bound_memref_dim(%static : memref<42x32x15x13x27xf32>) -> index { +// CHECK: %[[C_MINUS_7:.*]] = arith.constant -7 : index +// CHECK: %[[C_MINUS_7_I64:.*]] = builtin.unrealized_conversion_cast %[[C_MINUS_7]] : index to i64 +// CHECK: %[[UB_IDX:.*]] = llvm.getelementptr %{{.*}}[0, %[[C_MINUS_7_I64]]] : (!llvm.ptr, i64) -> !llvm.ptr +// CHECK: %[[UB_DIM_I64:.*]] = llvm.load %[[UB_IDX]] : !llvm.ptr +// CHECK: %[[UB_DIM:.*]] = builtin.unrealized_conversion_cast %[[UB_DIM_I64]] : i64 to index +// CHECK: return %[[UB_DIM]] : index + %c-7 = arith.constant -7 : index + %1 = memref.dim %static, %c-7 : memref<42x32x15x13x27xf32> + return %1 : index +} +// ----- + // Check that consistent types are emitted in address arithemic in presence of // a data layout specification. module attributes { dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry> } { diff --git a/mlir/test/Dialect/Tensor/invalid.mlir b/mlir/test/Dialect/Tensor/invalid.mlir --- a/mlir/test/Dialect/Tensor/invalid.mlir +++ b/mlir/test/Dialect/Tensor/invalid.mlir @@ -1,13 +1,5 @@ // RUN: mlir-opt <%s -split-input-file -verify-diagnostics -func.func @dim(%arg : tensor<1x?xf32>) { - %c2 = arith.constant 2 : index - tensor.dim %arg, %c2 : tensor<1x?xf32> // expected-error {{'tensor.dim' op index is out of range}} - return -} - -// ----- - // Asking the dimension of a 0-D shape doesn't make sense. func.func @dim_0_ranked(%arg : tensor, %arg1 : index) { tensor.dim %arg, %arg1 : tensor // expected-error {{'tensor.dim' op operand #0 must be unranked.tensor of any type values or non-0-ranked.tensor of any type values, but got 'tensor'}}