[llvm] [SelectionDAG] Keep inline asm clobbers live when read by a glued CopyFromReg (PR #227203)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 29 00:04:24 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: Fangrui Song (MaskRay)
<details>
<summary>Changes</summary>
PR #<!-- -->227026 marks every clobber def dead, but a flag output such as X86
`={@<!-- -->ccz}` is lowered to a glued `CopyFromReg $eflags` whose only
definition is the `~{flags}` clobber. With EXPENSIVE_CHECKS the verifier
reports "Using an undefined physical register" for the SETcc that reads
EFLAGS (bittest-intrin.ll, inline-asm-flag-output.ll, pr40737.ll).
Don't set the dead flag on a clobber that overlaps a physical register
read by a glued CopyFromReg.
Aided by Opus 5.5
---
Full diff: https://github.com/llvm/llvm-project/pull/227203.diff
2 Files Affected:
- (modified) llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp (+17-1)
- (modified) llvm/test/CodeGen/X86/inline-asm-default-clobbers.ll (+12-1)
``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
index 6db23303bbc13..0b32c30b446a2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
@@ -1369,6 +1369,19 @@ EmitSpecialNode(SDNode *Node, bool IsClone, bool IsCloned,
// Remember registers that are part of early-clobber defs.
SmallVector<Register, 8> ECRegs;
+ // A glued CopyFromReg may read a clobbered register, e.g. a flag output
+ // like X86 "={@ccz}" reads EFLAGS defined only by "~{flags}".
+ SmallVector<Register, 2> GluedUses;
+ if (Node->getValueType(Node->getNumValues() - 1) == MVT::Glue) {
+ for (SDNode *G = Node->getGluedUser(); G; G = G->getGluedUser()) {
+ if (G->getOpcode() != ISD::CopyFromReg)
+ continue;
+ Register Reg = cast<RegisterSDNode>(G->getOperand(1))->getReg();
+ if (Reg.isPhysical())
+ GluedUses.push_back(Reg);
+ }
+ }
+
// Add all of the operand registers to the instruction.
for (unsigned i = InlineAsm::Op_FirstOperand; i != NumOps;) {
unsigned Flags = Node->getConstantOperandVal(i);
@@ -1393,8 +1406,11 @@ EmitSpecialNode(SDNode *Node, bool IsClone, bool IsCloned,
case InlineAsm::Kind::Clobber:
for (unsigned j = 0; j != NumVals; ++j, ++i) {
Register Reg = cast<RegisterSDNode>(Node->getOperand(i))->getReg();
+ bool IsDead = F.isClobberKind() && none_of(GluedUses, [&](Register U) {
+ return TRI->regsOverlap(U, Reg);
+ });
MIB.addReg(Reg, RegState::Define | RegState::EarlyClobber |
- getDeadRegState(F.isClobberKind()) |
+ getDeadRegState(IsDead) |
getImplRegState(Reg.isPhysical()));
ECRegs.push_back(Reg);
}
diff --git a/llvm/test/CodeGen/X86/inline-asm-default-clobbers.ll b/llvm/test/CodeGen/X86/inline-asm-default-clobbers.ll
index 7a23b6ec2e9e4..61023b5e92e21 100644
--- a/llvm/test/CodeGen/X86/inline-asm-default-clobbers.ll
+++ b/llvm/test/CodeGen/X86/inline-asm-default-clobbers.ll
@@ -1,8 +1,19 @@
-; RUN: llc < %s -mtriple=i686 -stop-after=finalize-isel | FileCheck %s
+; RUN: llc < %s -mtriple=i686 -stop-after=finalize-isel -verify-machineinstrs | FileCheck %s
+; CHECK-LABEL: name: foo
; CHECK: INLINEASM &"", sideeffect attdialect, clobber, implicit-def dead early-clobber $df, clobber, implicit-def dead early-clobber $fpsw, clobber, implicit-def dead early-clobber $eflags
define void @foo() {
entry:
call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
ret void
}
+
+;; The flag output reads EFLAGS, which only the clobber defines.
+; CHECK-LABEL: name: flag_output
+; CHECK: INLINEASM &"", maystore attdialect, regdef:GR32, def %{{[0-9]+}}, clobber, implicit-def dead early-clobber $df, clobber, implicit-def dead early-clobber $fpsw, clobber, implicit-def early-clobber $eflags
+; CHECK-NEXT: SETCCr 4, implicit $eflags
+define i8 @flag_output() {
+entry:
+ %r = call i8 asm "", "={@ccz},~{dirflag},~{fpsr},~{flags}"()
+ ret i8 %r
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/227203
More information about the llvm-commits
mailing list