[llvm] [DAGCombiner] Don't fold GET_FPENV_MEM into a store whose address depends on it (PR #228839)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 4 00:01:07 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-selectiondag
Author: Doha Nam (waroad)
<details>
<summary>Changes</summary>
visitGET_FPENV_MEM folds `get_fpenv_mem tmp; load tmp; store -> p` into
`get_fpenv_mem p`, and the new node replaces the original one. When the
store address depends on the original node, the DAG becomes cyclic. This
happens for `ret i256 @<!-- -->llvm.get.fpenv.i256()`: the hidden sret pointer is
read with a CopyFromReg that is chained after the load from the stack
temporary. Type legalization then stops with "Operand not processed?", and
release builds crash.
Skip the fold when the store address has the original node as a
predecessor.
Fixes #<!-- -->228828.
Co-Authored-By: Claude Opus 5.5 <noreply@<!-- -->anthropic.com>
---
Full diff: https://github.com/llvm/llvm-project/pull/228839.diff
2 Files Affected:
- (modified) llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (+6)
- (modified) llvm/test/CodeGen/X86/fpenv.ll (+100)
``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index c8a984a9dc56e..a1305a4f9b8e8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -30579,6 +30579,12 @@ SDValue DAGCombiner::visitGET_FPENV_MEM(SDNode *N) {
!StNode->getChain().reachesChainWithoutSideEffects(SDValue(LdNode, 1)))
return SDValue();
+ // The new node replaces N, so the store address must not depend on N (for
+ // example through a CopyFromReg chained after the load), or the DAG would
+ // become cyclic.
+ if (StNode->getBasePtr()->hasPredecessor(N))
+ return SDValue();
+
// Create new node GET_FPENV_MEM, which uses the store address to write FP
// environment.
SDValue Res = DAG.getGetFPEnv(Chain, SDLoc(N), StNode->getBasePtr(), MemVT,
diff --git a/llvm/test/CodeGen/X86/fpenv.ll b/llvm/test/CodeGen/X86/fpenv.ll
index 77eaaa1ca08db..ca81c27ccb809 100644
--- a/llvm/test/CodeGen/X86/fpenv.ll
+++ b/llvm/test/CodeGen/X86/fpenv.ll
@@ -74,6 +74,106 @@ entry:
ret void
}
+; The i256 result is returned through a hidden sret pointer that is copied out
+; of a virtual register after the load from the stack temporary. Folding the
+; store into GET_FPENV_MEM must not create a cycle.
+; https://github.com/llvm/llvm-project/issues/228828
+define i256 @get_fpenv_ret() nounwind {
+; X86-NOSSE-LABEL: get_fpenv_ret:
+; X86-NOSSE: # %bb.0: # %entry
+; X86-NOSSE-NEXT: pushl %ebp
+; X86-NOSSE-NEXT: pushl %ebx
+; X86-NOSSE-NEXT: pushl %edi
+; X86-NOSSE-NEXT: pushl %esi
+; X86-NOSSE-NEXT: subl $60, %esp
+; X86-NOSSE-NEXT: movl {{[0-9]+}}(%esp), %eax
+; X86-NOSSE-NEXT: fnstenv {{[0-9]+}}(%esp)
+; X86-NOSSE-NEXT: fldenv {{[0-9]+}}(%esp)
+; X86-NOSSE-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X86-NOSSE-NEXT: movl %ecx, {{[-0-9]+}}(%e{{[sb]}}p) # 4-byte Spill
+; X86-NOSSE-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X86-NOSSE-NEXT: movl %ecx, {{[-0-9]+}}(%e{{[sb]}}p) # 4-byte Spill
+; X86-NOSSE-NEXT: movl {{[0-9]+}}(%esp), %esi
+; X86-NOSSE-NEXT: movl {{[0-9]+}}(%esp), %edi
+; X86-NOSSE-NEXT: movl {{[0-9]+}}(%esp), %ebx
+; X86-NOSSE-NEXT: movl {{[0-9]+}}(%esp), %ebp
+; X86-NOSSE-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X86-NOSSE-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NOSSE-NEXT: movl %edx, 24(%eax)
+; X86-NOSSE-NEXT: movl %ecx, 28(%eax)
+; X86-NOSSE-NEXT: movl %ebp, 16(%eax)
+; X86-NOSSE-NEXT: movl %ebx, 20(%eax)
+; X86-NOSSE-NEXT: movl %edi, 8(%eax)
+; X86-NOSSE-NEXT: movl %esi, 12(%eax)
+; X86-NOSSE-NEXT: movl {{[-0-9]+}}(%e{{[sb]}}p), %ecx # 4-byte Reload
+; X86-NOSSE-NEXT: movl %ecx, (%eax)
+; X86-NOSSE-NEXT: movl {{[-0-9]+}}(%e{{[sb]}}p), %ecx # 4-byte Reload
+; X86-NOSSE-NEXT: movl %ecx, 4(%eax)
+; X86-NOSSE-NEXT: addl $60, %esp
+; X86-NOSSE-NEXT: popl %esi
+; X86-NOSSE-NEXT: popl %edi
+; X86-NOSSE-NEXT: popl %ebx
+; X86-NOSSE-NEXT: popl %ebp
+; X86-NOSSE-NEXT: retl $4
+;
+; X86-SSE-LABEL: get_fpenv_ret:
+; X86-SSE: # %bb.0: # %entry
+; X86-SSE-NEXT: pushl %ebp
+; X86-SSE-NEXT: pushl %ebx
+; X86-SSE-NEXT: pushl %edi
+; X86-SSE-NEXT: pushl %esi
+; X86-SSE-NEXT: subl $60, %esp
+; X86-SSE-NEXT: movl {{[0-9]+}}(%esp), %eax
+; X86-SSE-NEXT: fnstenv {{[0-9]+}}(%esp)
+; X86-SSE-NEXT: fldenv {{[0-9]+}}(%esp)
+; X86-SSE-NEXT: stmxcsr {{[0-9]+}}(%esp)
+; X86-SSE-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE-NEXT: movl %ecx, {{[-0-9]+}}(%e{{[sb]}}p) # 4-byte Spill
+; X86-SSE-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE-NEXT: movl %ecx, {{[-0-9]+}}(%e{{[sb]}}p) # 4-byte Spill
+; X86-SSE-NEXT: movl {{[0-9]+}}(%esp), %esi
+; X86-SSE-NEXT: movl {{[0-9]+}}(%esp), %edi
+; X86-SSE-NEXT: movl {{[0-9]+}}(%esp), %ebx
+; X86-SSE-NEXT: movl {{[0-9]+}}(%esp), %ebp
+; X86-SSE-NEXT: movl {{[0-9]+}}(%esp), %ecx
+; X86-SSE-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-SSE-NEXT: movl %edx, 24(%eax)
+; X86-SSE-NEXT: movl %ecx, 28(%eax)
+; X86-SSE-NEXT: movl %ebp, 16(%eax)
+; X86-SSE-NEXT: movl %ebx, 20(%eax)
+; X86-SSE-NEXT: movl %edi, 8(%eax)
+; X86-SSE-NEXT: movl %esi, 12(%eax)
+; X86-SSE-NEXT: movl {{[-0-9]+}}(%e{{[sb]}}p), %ecx # 4-byte Reload
+; X86-SSE-NEXT: movl %ecx, (%eax)
+; X86-SSE-NEXT: movl {{[-0-9]+}}(%e{{[sb]}}p), %ecx # 4-byte Reload
+; X86-SSE-NEXT: movl %ecx, 4(%eax)
+; X86-SSE-NEXT: addl $60, %esp
+; X86-SSE-NEXT: popl %esi
+; X86-SSE-NEXT: popl %edi
+; X86-SSE-NEXT: popl %ebx
+; X86-SSE-NEXT: popl %ebp
+; X86-SSE-NEXT: retl $4
+;
+; X64-LABEL: get_fpenv_ret:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %rax
+; X64-NEXT: fnstenv -{{[0-9]+}}(%rsp)
+; X64-NEXT: fldenv -{{[0-9]+}}(%rsp)
+; X64-NEXT: stmxcsr -{{[0-9]+}}(%rsp)
+; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
+; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rdx
+; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rsi
+; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rdi
+; X64-NEXT: movq %rdi, 16(%rax)
+; X64-NEXT: movq %rsi, 24(%rax)
+; X64-NEXT: movq %rcx, (%rax)
+; X64-NEXT: movq %rdx, 8(%rax)
+; X64-NEXT: retq
+entry:
+ %env = call i256 @llvm.get.fpenv.i256()
+ ret i256 %env
+}
+
define void @set_fpenv_01(ptr %ptr) #0 {
; X86-NOSSE-LABEL: set_fpenv_01:
; X86-NOSSE: # %bb.0: # %entry
``````````
</details>
https://github.com/llvm/llvm-project/pull/228839
More information about the llvm-commits
mailing list