[llvm] X86: Preserve dead flags on EFLAGS when lowering CMPXCHG16B pseudos (PR #227278)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 29 04:20:55 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: Matt Arsenault (arsenm)

<details>
<summary>Changes</summary>

Co-Authored-By: Claude Opus 5 <noreply@<!-- -->anthropic.com>

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


4 Files Affected:

- (modified) llvm/lib/Target/X86/X86ExpandPseudo.cpp (+1) 
- (modified) llvm/lib/Target/X86/X86ISelLowering.cpp (+3) 
- (added) llvm/test/CodeGen/X86/cmpxchg16b-dead-eflags.ll (+90) 
- (added) llvm/test/CodeGen/X86/cmpxchg16b-dead-eflags.mir (+40) 


``````````diff
diff --git a/llvm/lib/Target/X86/X86ExpandPseudo.cpp b/llvm/lib/Target/X86/X86ExpandPseudo.cpp
index b5c196b29f958d..b36951a91da6bf 100644
--- a/llvm/lib/Target/X86/X86ExpandPseudo.cpp
+++ b/llvm/lib/Target/X86/X86ExpandPseudo.cpp
@@ -484,6 +484,7 @@ bool X86ExpandPseudoImpl::expandMI(MachineBasicBlock &MBB,
       NewInstr->addOperand(Base);
     for (unsigned Idx = 1 + 1; Idx < 1 + X86::AddrNumOperands; ++Idx)
       NewInstr->addOperand(MBBI->getOperand(Idx));
+    NewInstr->getOperand(7).setIsDead(MBBI->getOperand(11).isDead());
     // Finally, restore the value of RBX.
     TII->copyPhysReg(MBB, MBBI, DL, X86::RBX, SaveRbx,
                      /*SrcIsKill*/ true);
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index ddf9241ef7956c..ffd64c7715192e 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -39268,6 +39268,7 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
   case X86::LCMPXCHG16B_NO_RBX: {
     const X86RegisterInfo *TRI = Subtarget.getRegisterInfo();
     Register BasePtr = TRI->getBaseRegister();
+    bool DeadEFLAGS = MI.getOperand(8).isDead(); // implicit-def $eflags
     if (TRI->hasBasePointer(*MF) &&
         (BasePtr == X86::RBX || BasePtr == X86::EBX)) {
       if (!BB->isLiveIn(BasePtr))
@@ -39284,6 +39285,7 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
         MIB.add(MI.getOperand(Idx));
       MIB.add(MI.getOperand(X86::AddrNumOperands));
       MIB.addReg(SaveRBX);
+      MIB->getOperand(11).setIsDead(DeadEFLAGS); // implicit-def $eflags
     } else {
       // Simple case, just copy the virtual register to RBX.
       BuildMI(*BB, MI, MIMD, TII->get(TargetOpcode::COPY), X86::RBX)
@@ -39292,6 +39294,7 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
           BuildMI(*BB, MI, MIMD, TII->get(X86::LCMPXCHG16B));
       for (unsigned Idx = 0; Idx < X86::AddrNumOperands; ++Idx)
         MIB.add(MI.getOperand(Idx));
+      MIB->getOperand(7).setIsDead(DeadEFLAGS); // implicit-def $eflags
     }
     MI.eraseFromParent();
     return BB;
diff --git a/llvm/test/CodeGen/X86/cmpxchg16b-dead-eflags.ll b/llvm/test/CodeGen/X86/cmpxchg16b-dead-eflags.ll
new file mode 100644
index 00000000000000..7ae91473222ead
--- /dev/null
+++ b/llvm/test/CodeGen/X86/cmpxchg16b-dead-eflags.ll
@@ -0,0 +1,90 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=x86_64-- -mattr=+cx16 -stop-after=finalize-isel < %s | FileCheck %s
+
+define i128 @cmpxchg_i128_unused_success(ptr %p, i128 %cmp, i128 %new) {
+  ; CHECK-LABEL: name: cmpxchg_i128_unused_success
+  ; CHECK: bb.0 (%ir-block.0):
+  ; CHECK-NEXT:   liveins: $rdi, $rsi, $rdx, $rcx, $r8
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr64 = COPY $r8
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gr64 = COPY $rcx
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gr64 = COPY $rdx
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gr64 = COPY $rsi
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gr64 = COPY $rdi
+  ; CHECK-NEXT:   $rax = COPY [[COPY3]]
+  ; CHECK-NEXT:   $rdx = COPY [[COPY2]]
+  ; CHECK-NEXT:   $rcx = COPY [[COPY]]
+  ; CHECK-NEXT:   $rbx = COPY [[COPY1]]
+  ; CHECK-NEXT:   LCMPXCHG16B [[COPY4]], 1, $noreg, 0, $noreg, implicit-def $rax, implicit-def $rdx, implicit-def dead $eflags, implicit $rax, implicit $rbx, implicit $rcx, implicit $rdx
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:gr64 = COPY $rax
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:gr64 = COPY $rdx
+  ; CHECK-NEXT:   $rax = COPY [[COPY5]]
+  ; CHECK-NEXT:   $rdx = COPY [[COPY6]]
+  ; CHECK-NEXT:   RET 0, $rax, $rdx
+  %pair = cmpxchg ptr %p, i128 %cmp, i128 %new seq_cst seq_cst
+  %val = extractvalue { i128, i1 } %pair, 0
+  ret i128 %val
+}
+
+define i1 @cmpxchg_i128_used_success(ptr %p, i128 %cmp, i128 %new) {
+  ; CHECK-LABEL: name: cmpxchg_i128_used_success
+  ; CHECK: bb.0 (%ir-block.0):
+  ; CHECK-NEXT:   liveins: $rdi, $rsi, $rdx, $rcx, $r8
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr64 = COPY $r8
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gr64 = COPY $rcx
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gr64 = COPY $rdx
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gr64 = COPY $rsi
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gr64 = COPY $rdi
+  ; CHECK-NEXT:   $rax = COPY [[COPY3]]
+  ; CHECK-NEXT:   $rdx = COPY [[COPY2]]
+  ; CHECK-NEXT:   $rcx = COPY [[COPY]]
+  ; CHECK-NEXT:   $rbx = COPY [[COPY1]]
+  ; CHECK-NEXT:   LCMPXCHG16B [[COPY4]], 1, $noreg, 0, $noreg, implicit-def $rax, implicit-def $rdx, implicit-def $eflags, implicit $rax, implicit $rbx, implicit $rcx, implicit $rdx
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:gr64 = COPY $rax
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:gr64 = COPY $rdx
+  ; CHECK-NEXT:   [[SETCCr:%[0-9]+]]:gr8 = SETCCr 4, implicit $eflags
+  ; CHECK-NEXT:   $al = COPY [[SETCCr]]
+  ; CHECK-NEXT:   RET 0, $al
+  %pair = cmpxchg ptr %p, i128 %cmp, i128 %new seq_cst seq_cst
+  %success = extractvalue { i128, i1 } %pair, 1
+  ret i1 %success
+}
+
+; Force a base pointer in RBX, which selects LCMPXCHG16B_SAVE_RBX.
+define i128 @cmpxchg_i128_unused_success_base_ptr(ptr %p, i128 %cmp, i128 %new, i64 %n) {
+  ; CHECK-LABEL: name: cmpxchg_i128_unused_success_base_ptr
+  ; CHECK: bb.0 (%ir-block.0):
+  ; CHECK-NEXT:   liveins: $rdi, $rsi, $rdx, $rcx, $r8, $r9, $rbx
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr64 = COPY $r9
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gr64 = COPY $r8
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gr64 = COPY $rcx
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gr64 = COPY $rdx
+  ; CHECK-NEXT:   [[COPY4:%[0-9]+]]:gr64 = COPY $rsi
+  ; CHECK-NEXT:   [[COPY5:%[0-9]+]]:gr64 = COPY $rdi
+  ; CHECK-NEXT:   ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
+  ; CHECK-NEXT:   [[ADD64ri32_:%[0-9]+]]:gr64 = nuw ADD64ri32 [[COPY]], 15, implicit-def dead $eflags
+  ; CHECK-NEXT:   [[AND64ri32_:%[0-9]+]]:gr64 = AND64ri32 [[ADD64ri32_]], -16, implicit-def dead $eflags
+  ; CHECK-NEXT:   [[COPY6:%[0-9]+]]:gr64 = COPY $rsp
+  ; CHECK-NEXT:   [[SUB64rr:%[0-9]+]]:gr64 = SUB64rr [[COPY6]], killed [[AND64ri32_]], implicit-def dead $eflags
+  ; CHECK-NEXT:   $rsp = COPY [[SUB64rr]]
+  ; CHECK-NEXT:   ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
+  ; CHECK-NEXT:   MOV64mr %stack.1.over, 1, $noreg, 0, $noreg, [[SUB64rr]] :: (store (s64) into %ir.over, align 64)
+  ; CHECK-NEXT:   $rax = COPY [[COPY4]]
+  ; CHECK-NEXT:   $rdx = COPY [[COPY3]]
+  ; CHECK-NEXT:   $rcx = COPY [[COPY1]]
+  ; CHECK-NEXT:   [[COPY7:%[0-9]+]]:gr64 = COPY $rbx
+  ; CHECK-NEXT:   [[LCMPXCHG16B_SAVE_RBX:%[0-9]+]]:gr64 = LCMPXCHG16B_SAVE_RBX [[COPY5]], 1, $noreg, 0, $noreg, [[COPY2]], [[COPY7]], implicit-def $rax, implicit-def $rdx, implicit-def $rbx, implicit-def dead $eflags, implicit $rax, implicit $rcx, implicit $rdx
+  ; CHECK-NEXT:   [[COPY8:%[0-9]+]]:gr64 = COPY $rax
+  ; CHECK-NEXT:   [[COPY9:%[0-9]+]]:gr64 = COPY $rdx
+  ; CHECK-NEXT:   $rax = COPY [[COPY8]]
+  ; CHECK-NEXT:   $rdx = COPY [[COPY9]]
+  ; CHECK-NEXT:   RET 0, $rax, $rdx
+  %dyn = alloca i8, i64 %n
+  %over = alloca i64, align 64
+  store ptr %dyn, ptr %over
+  %pair = cmpxchg ptr %p, i128 %cmp, i128 %new seq_cst seq_cst
+  %val = extractvalue { i128, i1 } %pair, 0
+  ret i128 %val
+}
diff --git a/llvm/test/CodeGen/X86/cmpxchg16b-dead-eflags.mir b/llvm/test/CodeGen/X86/cmpxchg16b-dead-eflags.mir
new file mode 100644
index 00000000000000..f8db2870ad31b7
--- /dev/null
+++ b/llvm/test/CodeGen/X86/cmpxchg16b-dead-eflags.mir
@@ -0,0 +1,40 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=x86_64-- -mattr=+cx16 -run-pass=x86-expand-pseudo -o - %s | FileCheck %s
+
+---
+name:            expand_save_rbx_dead_eflags
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $rdi, $rsi, $rax, $rcx, $rdx, $r14
+
+    ; CHECK-LABEL: name: expand_save_rbx_dead_eflags
+    ; CHECK: liveins: $rdi, $rsi, $rax, $rcx, $rdx, $r14
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $rbx = MOV64rr $rsi
+    ; CHECK-NEXT: LCMPXCHG16B $rdi, 1, $noreg, 0, $noreg, implicit-def $rax, implicit-def $rdx, implicit-def dead $eflags, implicit $rax, implicit $rbx, implicit $rcx, implicit $rdx
+    ; CHECK-NEXT: $rbx = MOV64rr killed $r14
+    ; CHECK-NEXT: RET64 implicit $rax, implicit $rdx
+    $r14 = LCMPXCHG16B_SAVE_RBX $rdi, 1, $noreg, 0, $noreg, $rsi, $r14, implicit-def $rax, implicit-def $rdx, implicit-def $rbx, implicit-def dead $eflags, implicit $rax, implicit $rcx, implicit $rdx
+    RET64 implicit $rax, implicit $rdx
+...
+
+---
+name:            expand_save_rbx_live_eflags
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $rdi, $rsi, $rax, $rcx, $rdx, $r14
+
+    ; CHECK-LABEL: name: expand_save_rbx_live_eflags
+    ; CHECK: liveins: $rdi, $rsi, $rax, $rcx, $rdx, $r14
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $rbx = MOV64rr $rsi
+    ; CHECK-NEXT: LCMPXCHG16B $rdi, 1, $noreg, 0, $noreg, implicit-def $rax, implicit-def $rdx, implicit-def $eflags, implicit $rax, implicit $rbx, implicit $rcx, implicit $rdx
+    ; CHECK-NEXT: $rbx = MOV64rr killed $r14
+    ; CHECK-NEXT: $al = SETCCr 4, implicit $eflags
+    ; CHECK-NEXT: RET64 implicit $al
+    $r14 = LCMPXCHG16B_SAVE_RBX $rdi, 1, $noreg, 0, $noreg, $rsi, $r14, implicit-def $rax, implicit-def $rdx, implicit-def $rbx, implicit-def $eflags, implicit $rax, implicit $rcx, implicit $rdx
+    $al = SETCCr 4, implicit $eflags
+    RET64 implicit $al
+...

``````````

</details>


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


More information about the llvm-commits mailing list