[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