[llvm] [IROutliner] Correctly Replace Outlined Constants with Arguments (PR #179885)

Yunbo Ni via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 6 11:07:12 PST 2026


cardigan1008 wrote:

Hi @lenary , there is a related crash case:

```llvm
declare void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i32, i1 immarg)

define void @test_immarg(ptr %p1, ptr %p2) {
entry:
  br label %block1

block1:
  %x = add i32 1, 2
  call void @llvm.memcpy.p0.p0.i32(ptr %p1, ptr %p2, i32 4, i1 false)
  %y = add i32 %x, 3
  ret void

block2:
  br label %block3

block3:
  %x2 = add i32 1, 2
  call void @llvm.memcpy.p0.p0.i32(ptr %p1, ptr %p2, i32 4, i1 true)
  %y2 = add i32 %x2, 3
  ret void
}
```

With opt built on this patch, a crash occurred:

```sh
immarg operand has non-immediate parameter
i1 %2
  call void @llvm.memcpy.p0.p0.i32(ptr %0, ptr %1, i32 4, i1 %2)
LLVM ERROR: Broken module found, compilation aborted!
```

**Command:**
```bash
opt -S -passes=iroutliner -ir-outlining-no-cost
```

This might not be directly related to the current patch, as I got the same result with opt built on llvm without this patch: https://alive2.llvm.org/ce/z/SDMtP4. But the test case is derived from this PR. If it is an issue required to be filed, please let me know. Thanks.

> Note: This is a review assisted with a self-built agent. The reproducer was validated manually. Please let me know if anything is wrong.

**Bug Triggering Analysis:**
The provided test case contains two regions that are structurally identical except for the `isvolatile` parameter of the `llvm.memcpy` intrinsic. In one region, it is `false`, and in the other, it is `true`. The `isvolatile` parameter is marked with the `immarg` attribute, which means it must be a constant immediate value.
The `IROutliner` pass identifies these two regions as similar and decides to outline them into a single function. Because the `isvolatile` parameter differs between the two regions, the outliner elevates this constant to an argument of the newly created outlined function.
When the outliner replaces the constants in the outlined function with the new argument, it replaces the `immarg` parameter of the `llvm.memcpy` call with an `Argument` value. This violates the `immarg` constraint, causing the LLVM IR verifier to crash with the error `immarg operand has non-immediate parameter`.

**Fix Weakness Analysis:**
The fix in the patch changed how constants are replaced in the outlined function. Instead of using `ValueMapper` (which incorrectly replaced constants inside `ConstantExpr`s), the new code manually iterates over the direct operands of instructions and replaces them if they match the constant being elevated.
However, the fix assumes that *any* direct operand of an instruction can be safely replaced with an `Argument`. It fails to account for instructions or intrinsics that require certain operands to be constants (e.g., `immarg` parameters, `switch` cases, `getelementptr` struct indices). By blindly replacing these required-constant operands with non-constant `Argument`s, the outliner generates invalid IR, leading to compiler crashes during verification. The fix only addressed the `ConstantExpr` issue but introduced or left exposed this broader issue of replacing constants that must remain constants.



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


More information about the llvm-commits mailing list