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 @@ -1378,6 +1378,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) @@ -1520,9 +1555,11 @@ GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion, IsPresentOpConversion, LoadOpConversion, NegcOpConversion, MulcOpConversion, SelectCaseOpConversion, SelectOpConversion, - SelectRankOpConversion, SelectTypeOpConversion, StoreOpConversion, - SubcOpConversion, UnboxCharOpConversion, UndefOpConversion, - UnreachableOpConversion, ZeroOpConversion>(typeConverter); + SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion, + ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion, + StoreOpConversion, 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 @@ -83,3 +83,51 @@ %0 = fir.undefined !fir.type fir.has_value %0 : !fir.type } + +// ----- + +// 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 @@ -1200,3 +1200,51 @@ // CHECK-NEXT: %[[ptr:.*]] = llvm.mlir.null : !llvm.ptr // CHECK-NEXT: %[[ret_val:.*]] = llvm.call @is_present(%[[ptr]]) : (!llvm.ptr) -> i1 // CHECK-NEXT: llvm.return %[[ret_val]] : i1 + +// ----- + +// 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