diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -1469,6 +1469,41 @@ } }; +/// Conversion pattern for operation that must be dead. The information in these +/// operations is used by other operation. At this point they should not have +/// anymore uses. +template +struct MustBeDeadConversion : public FIROpConversion { + explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering) + : FIROpConversion(lowering) {} + using OpAdaptor = typename FromOp::Adaptor; + + mlir::LogicalResult + matchAndRewrite(FromOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const final { + if (!op->getUses().empty()) + return rewriter.notifyMatchFailure(op, "op must be dead"); + rewriter.eraseOp(op); + return success(); + } +}; + +struct ShapeOpConversion : public MustBeDeadConversion { + using MustBeDeadConversion::MustBeDeadConversion; +}; + +struct ShapeShiftOpConversion : public MustBeDeadConversion { + using MustBeDeadConversion::MustBeDeadConversion; +}; + +struct ShiftOpConversion : public MustBeDeadConversion { + using MustBeDeadConversion::MustBeDeadConversion; +}; + +struct SliceOpConversion : public MustBeDeadConversion { + using MustBeDeadConversion::MustBeDeadConversion; +}; + /// `fir.is_present` --> /// ``` /// %0 = llvm.mlir.constant(0 : i64) @@ -1635,10 +1670,11 @@ GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion, IsPresentOpConversion, LoadOpConversion, NegcOpConversion, MulcOpConversion, SelectCaseOpConversion, SelectOpConversion, - SelectRankOpConversion, SelectTypeOpConversion, StoreOpConversion, - StringLitOpConversion, SubcOpConversion, UnboxCharOpConversion, - UndefOpConversion, UnreachableOpConversion, ZeroOpConversion>( - typeConverter); + SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion, + ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion, + StoreOpConversion, StringLitOpConversion, SubcOpConversion, + UnboxCharOpConversion, UndefOpConversion, UnreachableOpConversion, + ZeroOpConversion>(typeConverter); mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, pattern); diff --git a/flang/test/Fir/convert-to-llvm-invalid.fir b/flang/test/Fir/convert-to-llvm-invalid.fir --- a/flang/test/Fir/convert-to-llvm-invalid.fir +++ b/flang/test/Fir/convert-to-llvm-invalid.fir @@ -100,3 +100,51 @@ // expected-error@+1{{'fir.dt_entry' op expects parent op 'fir.dispatch_table'}} fir.dt_entry "method", @method_impl + +// ----- + +// Test `fir.shape` conversion failure because the op has uses. + +func @shape_not_dead(%arg0: !fir.ref>, %i: index, %j: index) { + %c0 = arith.constant 1 : index + // expected-error@+1{{failed to legalize operation 'fir.shape'}} + %0 = fir.shape %c0, %c0 : (index, index) -> !fir.shape<2> + %1 = fir.array_coor %arg0(%0) %i, %j : (!fir.ref>, !fir.shape<2>, index, index) -> !fir.ref + return +} + +// ----- + +// Test `fir.slice` conversion failure because the op has uses. + +func @slice_not_dead(%arg0: !fir.ref>, %i: index, %j: index) { + %c0 = arith.constant 1 : index + // expected-error@+1{{failed to legalize operation 'fir.slice'}} + %0 = fir.slice %c0, %c0, %c0, %c0, %c0, %c0 : (index, index, index, index, index, index) -> !fir.slice<2> + %1 = fir.array_coor %arg0[%0] %i, %j : (!fir.ref>, !fir.slice<2>, index, index) -> !fir.ref + return +} + +// ----- + +// Test `fir.shift` conversion failure because the op has uses. + +func @shift_not_dead(%arg0: !fir.box>, %i: index) { + %c0 = arith.constant 1 : index + // expected-error@+1{{failed to legalize operation 'fir.shift'}} + %0 = fir.shift %c0 : (index) -> !fir.shift<1> + %1 = fir.array_coor %arg0(%0) %i : (!fir.box>, !fir.shift<1>, index) -> !fir.ref + return +} + +// ----- + +// Test `fir.shape_shift` conversion failure because the op has uses. + +func @shape_shift_not_dead(%arg0: !fir.ref>, %i: index, %j: index) { + %c0 = arith.constant 1 : index + // expected-error@+1{{failed to legalize operation 'fir.shape_shift'}} + %0 = fir.shape_shift %c0, %c0, %c0, %c0 : (index, index, index, index) -> !fir.shapeshift<2> + %1 = fir.array_coor %arg0(%0) %i, %j : (!fir.ref>, !fir.shapeshift<2>, index, index) -> !fir.ref + return +} diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir --- a/flang/test/Fir/convert-to-llvm.fir +++ b/flang/test/Fir/convert-to-llvm.fir @@ -1271,3 +1271,51 @@ // CHECK-LABEL: llvm.func @string_lit1 // %{{.*}} = llvm.mlir.constant(dense<[158, 2345]> : vector<2xi16>) : !llvm.array<2 x i16> + +// ----- + +// Test must be dead conversion. + +func @dead_shift() { + %c0 = arith.constant 0 : index + %0 = fir.shift %c0 : (index) -> !fir.shift<1> + return +} + +// CHECK-LABEL: llvm.func @dead_shift +// CHECK-NOT: fir.shift +// CHECK: %{{.*}} = llvm.mlir.constant(0 : index) : i{{.*}} +// CHECK-NEXT: llvm.return + +func @dead_shape() { + %c0 = arith.constant 0 : index + %0 = fir.shape %c0 : (index) -> !fir.shape<1> + return +} + +// CHECK-LABEL: llvm.func @dead_shape +// CHECK-NOT: fir.shape +// CHECK: %{{.*}} = llvm.mlir.constant(0 : index) : i{{.*}} +// CHECK-NEXT: llvm.return + +func @dead_shapeshift() { + %c0 = arith.constant 0 : index + %0 = fir.shape_shift %c0, %c0 : (index, index) -> !fir.shapeshift<1> + return +} + +// CHECK-LABEL: llvm.func @dead_shapeshift +// CHECK-NOT: fir.shape_shift +// CHECK: %{{.*}} = llvm.mlir.constant(0 : index) : i{{.*}} +// CHECK-NEXT: llvm.return + +func @dead_slice() { + %c0 = arith.constant 0 : index + %0 = fir.slice %c0, %c0, %c0 : (index, index, index) -> !fir.slice<1> + return +} + +// CHECK-LABEL: llvm.func @dead_slice +// CHECK-NOT: fir.slice +// CHECK: %{{.*}} = llvm.mlir.constant(0 : index) : i{{.*}} +// CHECK-NEXT: llvm.return