diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index 1699d7890fb04..481aeefb0ab2e 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -1907,21 +1907,38 @@ def fir_SliceOp : fir_Op<"slice", [NoSideEffect, AttrSizedOperandSegments]> { ```mlir %fld = fir.field_index component, !fir.type - %d = fir.slice %lo, %hi, %step path %fld : (index, index, index, !fir.field) -> !fir.slice<1> + %d = fir.slice %lo, %hi, %step path %fld : + (index, index, index, !fir.field) -> !fir.slice<1> + ``` + + Projections of `!fir.char` type can be further narrowed to invariant + substrings. + + ```mlir + %d = fir.slice %lo, %hi, %step substr %offset, %width : + (index, index, index, index, index) -> !fir.slice<1> ``` }]; let arguments = (ins - Variadic:$triples, - Variadic:$fields + Variadic:$triples, + Variadic:$fields, + Variadic:$substr ); let results = (outs fir_SliceType); let assemblyFormat = [{ - $triples (`path` $fields^)? attr-dict `:` functional-type(operands, results) + $triples (`path` $fields^)? (`substr` $substr^)? attr-dict `:` + functional-type(operands, results) }]; + let builders = [ + OpBuilder<(ins "mlir::ValueRange":$triples, + CArg<"mlir::ValueRange", "llvm::None">:$fields, + CArg<"mlir::ValueRange", "llvm::None">:$substr)> + ]; + let verifier = "return ::verify(*this);"; let extraClassDeclaration = [{ diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index 64174b8892dfc..ee9cb5372c58b 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -2811,13 +2811,21 @@ static mlir::LogicalResult verify(fir::ShiftOp &op) { // SliceOp //===----------------------------------------------------------------------===// +void fir::SliceOp::build(mlir::OpBuilder &builder, mlir::OperationState &result, + mlir::ValueRange trips, mlir::ValueRange path, + mlir::ValueRange substr) { + const auto rank = trips.size() / 3; + auto sliceTy = fir::SliceType::get(builder.getContext(), rank); + build(builder, result, sliceTy, trips, path, substr); +} + /// Return the output rank of a slice op. The output rank must be between 1 and /// the rank of the array being sliced (inclusive). unsigned fir::SliceOp::getOutputRank(mlir::ValueRange triples) { unsigned rank = 0; if (!triples.empty()) { for (unsigned i = 1, end = triples.size(); i < end; i += 3) { - auto op = triples[i].getDefiningOp(); + auto *op = triples[i].getDefiningOp(); if (!mlir::isa_and_nonnull(op)) ++rank; } diff --git a/flang/test/Fir/fir-ops.fir b/flang/test/Fir/fir-ops.fir index 2323cbc71ff1a..47805bf83b0a7 100644 --- a/flang/test/Fir/fir-ops.fir +++ b/flang/test/Fir/fir-ops.fir @@ -699,3 +699,13 @@ func @char_convert() { fir.char_convert %2 for %1 to %3 : !fir.ref>, i32, !fir.ref>> return } + +func @slice_substr() { + %lb = arith.constant 0 : index + %ub = arith.constant 42 : index + %c1 = arith.constant 1 : index + %offset = arith.constant 10 : index + %0 = fir.slice %lb, %ub, %c1 substr %offset, %c1 : (index, index, index, index, index) -> !fir.slice<1> + // CHECK: fir.slice %{{.*}}, %{{.*}}, %{{.*}} substr %{{.*}}, %{{.*}} : (index, index, index, index, index) -> !fir.slice<1> + return +} diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir index a43c5614ec860..ca9c3b69bd2f9 100644 --- a/flang/test/Fir/invalid.fir +++ b/flang/test/Fir/invalid.fir @@ -606,3 +606,13 @@ func @bad_array_modify(%arr1 : !fir.ref>, %m : index, %n : i fir.array_merge_store %av1, %av2 to %arr1 : !fir.array, !fir.array, !fir.ref> return } + +// ----- + +func @slice_must_be_integral() { + %0 = arith.constant 42 : i32 + %1 = fir.field_index field, !fir.type (%0 : i32) + // expected-error@+1 {{'fir.slice' op operand #0 must be any integer, but got '!fir.field'}} + %2 = fir.slice %1, %1, %1 : (!fir.field, !fir.field, !fir.field) -> !fir.slice<1> + return +}