
cg-rewrite runs regionDCE to get rid of the unused fir.shape/shift/slice before codegen since those operations have no codegen. I came across an issue where unreachable code would cause the pass to fail with `error: loc(...): null operand found`. It turns out `mlir::RegionDCE` does not work properly in presence of unreachable code because it delete operations in reachable code that are unused in reachable code, but still used in unreachable code (like the constant in the added test case). It seems `mlir::RegionDCE` is always run after `mlir::eraseUnreachableBlock` outside of this pass. A solution could be to run `mlir::eraseUnreachableBlock` here or to try modifying `mlir::RegionDCE`. But the current behavior may be intentional, and both of these calls are actually quite expensive. For instance, RegionDCE will does liveness analysis, and removes unused block arguments, which is way more than what is needed here. I am not very found of having this rather heavy transformation inside this pass (they should be run after or before if they matter in the overall pipeline). Do a naïve backward deletion of the trivially dead operations instead. It is cheaper, and works with unreachable code.
55 lines
2.4 KiB
Plaintext
55 lines
2.4 KiB
Plaintext
// Test rewrite of fir.declare. The result is replaced by the memref operand.
|
|
// RUN: fir-opt --cg-rewrite="preserve-declare=true" %s -o - | FileCheck %s --check-prefixes DECL
|
|
// RUN: fir-opt --cg-rewrite="preserve-declare=false" %s -o - | FileCheck %s --check-prefixes NODECL
|
|
// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s --check-prefixes NODECL
|
|
|
|
|
|
func.func @test(%arg0: !fir.ref<!fir.array<12x23xi32>>) {
|
|
%c-1 = arith.constant -1 : index
|
|
%c12 = arith.constant 12 : index
|
|
%c-2 = arith.constant -2 : index
|
|
%c23 = arith.constant 23 : index
|
|
%0 = fir.shape_shift %c12, %c-1, %c23, %c-2 : (index, index, index, index) -> !fir.shapeshift<2>
|
|
%1 = fir.declare %arg0(%0) {uniq_name = "_QFarray_numeric_lboundsEx"} : (!fir.ref<!fir.array<12x23xi32>>, !fir.shapeshift<2>) -> !fir.ref<!fir.array<12x23xi32>>
|
|
fir.call @bar(%1) : (!fir.ref<!fir.array<12x23xi32>>) -> ()
|
|
return
|
|
}
|
|
func.func private @bar(%arg0: !fir.ref<!fir.array<12x23xi32>>)
|
|
|
|
|
|
// NODECL-LABEL: func.func @test(
|
|
// NODECL-SAME: %[[arg0:.*]]: !fir.ref<!fir.array<12x23xi32>>) {
|
|
// NODECL-NEXT: fir.call @bar(%[[arg0]]) : (!fir.ref<!fir.array<12x23xi32>>) -> ()
|
|
|
|
// DECL-LABEL: func.func @test(
|
|
// DECL-SAME: %[[arg0:.*]]: !fir.ref<!fir.array<12x23xi32>>) {
|
|
// DECL: fircg.ext_declare
|
|
|
|
|
|
func.func @useless_shape_with_duplicate_extent_operand(%arg0: !fir.ref<!fir.array<3x3xf32>>) {
|
|
%c3 = arith.constant 3 : index
|
|
%1 = fir.shape %c3, %c3 : (index, index) -> !fir.shape<2>
|
|
%2 = fir.declare %arg0(%1) {uniq_name = "u"} : (!fir.ref<!fir.array<3x3xf32>>, !fir.shape<2>) -> !fir.ref<!fir.array<3x3xf32>>
|
|
return
|
|
}
|
|
|
|
// NODECL-LABEL: func.func @useless_shape_with_duplicate_extent_operand(
|
|
// NODECL-NEXT: return
|
|
|
|
// DECL-LABEL: func.func @useless_shape_with_duplicate_extent_operand(
|
|
// DECL: fircg.ext_declare
|
|
|
|
// Test DCE does not crash because of unreachable code.
|
|
func.func @unreachable_code(%arg0: !fir.ref<!fir.char<1,10>>) {
|
|
%c10 = arith.constant 10 : index
|
|
%2 = fir.declare %arg0 typeparams %c10 {uniq_name = "live_code"} : (!fir.ref<!fir.char<1,10>>, index) -> (!fir.ref<!fir.char<1,10>>)
|
|
return
|
|
^bb2: // no predecessors
|
|
%3 = fir.declare %arg0 typeparams %c10 {uniq_name = "dead_code"} : (!fir.ref<!fir.char<1,10>>, index) -> (!fir.ref<!fir.char<1,10>>)
|
|
fir.unreachable
|
|
}
|
|
// NODECL-LABEL: func.func @unreachable_code(
|
|
// NODECL-NOT: uniq_name = "live_code"
|
|
// DECL-LABEL: func.func @unreachable_code(
|
|
// DECL: uniq_name = "live_code"
|