[Mlir-commits] [flang] [mlir] [mlir][CSE] Introduce hoist-pure-ops logic to CSE pass (PR #180556)

lonely eagle llvmlistbot at llvm.org
Thu Apr 2 09:58:00 PDT 2026


linuxlonelyeagle wrote:

Thank you for looking into this. Let me describe the issue you encountered above. I have logged the changes locally after each call to the `hoistPureOp` function. I’ve included some comments, which I hope will help clarify the logic. Note: `replaceAllUsesWith`  is not used here.
```
[cse CSE.cpp:248 1] module {
[cse CSE.cpp:248 1]   func.func @cse_multiple_regions(%arg0: i1, %arg1: i32) -> (i32, i32) {
[cse CSE.cpp:248 1]     %0 = "test.producer"() : () -> i32
[cse CSE.cpp:248 1]     %1 = scf.if %arg0 -> (i32) {
                                     //
                                     // hoist the arith.add op.
                                    //
[cse CSE.cpp:248 1]       %3 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]       %4 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]       %5 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]         scf.yield %3 : i32
[cse CSE.cpp:248 1]       } else {
[cse CSE.cpp:248 1]         scf.yield %4 : i32
[cse CSE.cpp:248 1]       }
[cse CSE.cpp:248 1]       scf.yield %5 : i32
[cse CSE.cpp:248 1]     } else {
[cse CSE.cpp:248 1]       scf.yield %arg1 : i32
[cse CSE.cpp:248 1]     }
[cse CSE.cpp:248 1]     %2 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]       %3 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]         %4 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]         scf.yield %4 : i32
[cse CSE.cpp:248 1]       } else {
[cse CSE.cpp:248 1]         %4 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]         scf.yield %4 : i32
[cse CSE.cpp:248 1]       }
[cse CSE.cpp:248 1]       scf.yield %3 : i32
[cse CSE.cpp:248 1]     } else {
[cse CSE.cpp:248 1]       scf.yield %arg1 : i32
[cse CSE.cpp:248 1]     }
[cse CSE.cpp:248 1]     return %1, %2 : i32, i32
[cse CSE.cpp:248 1]   }
[cse CSE.cpp:248 1] }
```

```
[cse CSE.cpp:248 1] moduleOp:
[cse CSE.cpp:248 1] module {
[cse CSE.cpp:248 1]   func.func @cse_multiple_regions(%arg0: i1, %arg1: i32) -> (i32, i32) {
[cse CSE.cpp:248 1]     %0 = "test.producer"() : () -> i32

// we hoist all add op, during the second hoisting of %1, 
// the operation %2 used to be left behind in the outer scf.if, 
// which prevented the scf.if from being simplified or removed. 
// Now, %2 is hoisted along with %1.

[cse CSE.cpp:248 1]     %1 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]     %2 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]     %3 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]     %4 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]       %6 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]         scf.yield %1 : i32
[cse CSE.cpp:248 1]       } else {
[cse CSE.cpp:248 1]         scf.yield %1 : i32 //  use replaceAllUse.
[cse CSE.cpp:248 1]       }
[cse CSE.cpp:248 1]       scf.yield %6 : i32
[cse CSE.cpp:248 1]     } else {
[cse CSE.cpp:248 1]       scf.yield %arg1 : i32
[cse CSE.cpp:248 1]     }
[cse CSE.cpp:248 1]     %5 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]       %6 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]         scf.yield %3 : i32
[cse CSE.cpp:248 1]       } else {
[cse CSE.cpp:248 1]         %7 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]         scf.yield %7 : i32
[cse CSE.cpp:248 1]       }
[cse CSE.cpp:248 1]       scf.yield %6 : i32
[cse CSE.cpp:248 1]     } else {
[cse CSE.cpp:248 1]       scf.yield %arg1 : i32
[cse CSE.cpp:248 1]     }
[cse CSE.cpp:248 1]     return %4, %5 : i32, i32
[cse CSE.cpp:248 1]   }
[cse CSE.cpp:248 1] }

```

```
[cse CSE.cpp:248 1] module {
[cse CSE.cpp:248 1]   func.func @cse_multiple_regions(%arg0: i1, %arg1: i32) -> (i32, i32) {
[cse CSE.cpp:248 1]     %0 = "test.producer"() : () -> i32
[cse CSE.cpp:248 1]     %1 = arith.addi %0, %0 : i32

// We hoist the scf.if, the reason for the invalid IR generated above is
//  that the use of %1 within the scf.if region was not taken into account. 
// Since %1 is now defined before the scf.if, this issue no longer exists.

[cse CSE.cpp:248 1]     %2 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]       scf.yield %1 : i32
[cse CSE.cpp:248 1]     } else {
[cse CSE.cpp:248 1]       scf.yield %1 : i32
[cse CSE.cpp:248 1]     }
[cse CSE.cpp:248 1]     %3 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]       scf.yield %1 : i32
[cse CSE.cpp:248 1]     } else {
[cse CSE.cpp:248 1]       scf.yield %1 : i32
[cse CSE.cpp:248 1]     }
[cse CSE.cpp:248 1]     %4 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]     %5 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]     %6 = arith.addi %0, %0 : i32
[cse CSE.cpp:248 1]     %7 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]       scf.yield %2 : i32
[cse CSE.cpp:248 1]     } else {
[cse CSE.cpp:248 1]       scf.yield %arg1 : i32
[cse CSE.cpp:248 1]     }
[cse CSE.cpp:248 1]     %8 = scf.if %arg0 -> (i32) {
[cse CSE.cpp:248 1]       scf.yield %3 : i32
[cse CSE.cpp:248 1]     } else {
[cse CSE.cpp:248 1]       scf.yield %arg1 : i32
[cse CSE.cpp:248 1]     }
[cse CSE.cpp:248 1]     return %7, %8 : i32, i32
[cse CSE.cpp:248 1]   }
[cse CSE.cpp:248 1] }
[cse CSE.cpp:276 1] replace %3 = scf.if %arg0 -> (i32) {...} else {...} with %2 = scf.if %arg0 -> (i32) {...} else {...}
[cse CSE.cpp:279 1] add %3 = scf.if %arg0 -> (i32) {...} else {...} to opsToErase
[cse CSE.cpp:406 1] visit operation: scf.yield %2 : i32
[cse CSE.cpp:515 1] visit region #1 of %8 = scf.if %arg0 -> (i32) {...} else {...}
[cse CSE.cpp:479 1] visit block #0 of %8 = scf.if %arg0 -> (i32) {...} else {...}
[cse CSE.cpp:406 1] visit operation: scf.yield %arg1 : i32
[cse CSE.cpp:406 1] visit operation: %8 = scf.if %arg0 -> (i32) {...} else {...}
[cse CSE.cpp:276 1] replace %8 = scf.if %arg0 -> (i32) {...} else {...} with %7 = scf.if %arg0 -> (i32) {...} else {...}
[cse CSE.cpp:279 1] add %8 = scf.if %arg0 -> (i32) {...} else {...} to opsToErase
[cse CSE.cpp:406 1] visit operation: func.return %7, %7 : i32, i32
[cse CSE.cpp:406 1] visit operation: func.func @cse_multiple_regions(%arg0: i1, %arg1: i32) -> (i32, i32) {...}
module {
  func.func @cse_multiple_regions(%arg0: i1, %arg1: i32) -> (i32, i32) {
    %0 = "test.producer"() : () -> i32
    %1 = arith.addi %0, %0 : i32
    %2 = scf.if %arg0 -> (i32) {
      scf.yield %1 : i32
    } else {
      scf.yield %1 : i32
    }
    %3 = scf.if %arg0 -> (i32) {
      scf.yield %2 : i32
    } else {
      scf.yield %arg1 : i32
    }
    return %3, %3 : i32, i32
  }
}
```
If you have any further questions, please let me know.😉

https://github.com/llvm/llvm-project/pull/180556


More information about the Mlir-commits mailing list