[llvm] [SelectionDAG] Fix cycle in ReplacedValues during type legalization (PR #184697)

via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 4 14:47:07 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: Peter Rong (DataCorrupted)

<details>
<summary>Changes</summary>

During type legalization, `ReplaceValueWith` handles morphed nodes by computing `OldValId` and `NewValId`, calling `ReplaceAllUsesOfValueWith` (RAUW), then adding `ReplacedValues[OldValId] = NewValId`. 

However, the RAUW call can trigger `CSE`, which fires NoteDeletion callbacks that add new  entries to `ReplacedValues`. If NoteDeletion adds `ReplacedValues[A] = B`, and the subsequent assignment adds `ReplacedValues[B] = A`, a cycle is created. RemapId then recurses infinitely following the cycle during  path compression, causing a stack overflow crash.

On AArch64, i16 is not a legal type and requires promotion to i32. When IR uses i16 values as `extractelement` indices that feed into other `extractelement` operations, the interplay between result promotion and operand promotion creates the specific CSE pattern that produces the cycle.

Fix by calling RemapId on both OldValId and NewValId after the  RAUW call to account for new ReplacedValues entries added during the RAUW cascade. In the reproducer, this causes both ids to resolve to the same value, skipping the assignment and preventing the cycle.

Fixes https://github.com/llvm/llvm-project/issues/57251

[Assisted-by](https://t.ly/Dkjjk): [Claude Opus 4.6](https://www.anthropic.com/news/claude-opus-4-6)

---
Full diff: https://github.com/llvm/llvm-project/pull/184697.diff


2 Files Affected:

- (modified) llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp (+6) 
- (added) llvm/test/CodeGen/AArch64/Issue57251.ll (+18) 


``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp
index 9634e5afdc738..74b81572b6692 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp
@@ -687,6 +687,12 @@ void DAGTypeLegalizer::ReplaceValueWith(SDValue From, SDValue To) {
           auto OldValId = getTableId(OldVal);
           auto NewValId = getTableId(NewVal);
           DAG.ReplaceAllUsesOfValueWith(OldVal, NewVal);
+          // Re-remap ids after RAUW, since the call above may have caused
+          // nodes to be deleted (via CSE), triggering NoteDeletion callbacks
+          // that added new entries to ReplacedValues. Without re-remapping,
+          // we could create a cycle like A -> B -> A.
+          RemapId(OldValId);
+          RemapId(NewValId);
           if (OldValId != NewValId)
             ReplacedValues[OldValId] = NewValId;
         }
diff --git a/llvm/test/CodeGen/AArch64/Issue57251.ll b/llvm/test/CodeGen/AArch64/Issue57251.ll
new file mode 100644
index 0000000000000..285f66b4856f9
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/Issue57251.ll
@@ -0,0 +1,18 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=aarch64 < %s | FileCheck %s
+
+define i16 @f(<4 x i16> %L) {
+; CHECK-LABEL: f:
+; CHECK:       // %bb.0: // %BB
+; CHECK-NEXT:    mov w0, wzr
+; CHECK-NEXT:    ret
+BB:
+  %B3 = sub <4 x i16> %L, %L
+  %B1 = srem <4 x i16> %L, %L
+  %E = extractelement <4 x i16> %B3, i8 0
+  %I = insertelement <4 x i16> %B1, i16 %E, i16 0
+  %E1 = extractelement <4 x i16> %I, i16 %E
+  %E2 = extractelement <4 x i16> zeroinitializer, i16 %E1
+  %E3 = extractelement <4 x i16> %I, i16 %E2
+  ret i16 %E3
+}

``````````

</details>


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


More information about the llvm-commits mailing list