[llvm] [AMDGPU] Eliminate redundant s_round_mode writes (PR #216305)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 14 04:16:54 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-amdgpu

Author: Barbara Mitic (barbara-amd)

<details>
<summary>Changes</summary>

Add a block local peephole that drops writes to the FP round mode which cannot be observed. A write is removed when a later s_round_mode replaces the whole round mode field before any instruction reads MODE, or when the value it writes is already live in MODE.

The analysis is intra-block only: the round mode on entry to a block is treated as unknown, and a write still live at the end of a block is kept for its successors.

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


2 Files Affected:

- (modified) llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp (+73) 
- (added) llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-redundant-round-mode.mir (+317) 


``````````diff
diff --git a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
index 7f87fbc0448b3..3cb75e88f42c7 100644
--- a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
@@ -22,16 +22,22 @@
 #include "GCNSubtarget.h"
 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
 #include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/Statistic.h"
 #include "llvm/CodeGen/MachineDominators.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineLoopInfo.h"
 #include "llvm/CodeGen/MachinePostDominators.h"
 #include "llvm/CodeGen/TargetSchedule.h"
 #include "llvm/Support/BranchProbability.h"
+#include <cstdint>
+#include <optional>
 using namespace llvm;
 
 #define DEBUG_TYPE "si-pre-emit-peephole"
 
+STATISTIC(NumRoundModeWritesRemoved,
+          "Number of redundant s_round_mode writes removed");
+
 namespace {
 
 class SIPreEmitPeephole {
@@ -52,6 +58,7 @@ class SIPreEmitPeephole {
                              const MachineBasicBlock &From,
                              const MachineBasicBlock &To) const;
   bool removeExeczBranch(MachineInstr &MI, MachineBasicBlock &SrcMBB);
+  bool removeRedundantRoundMode(MachineBasicBlock &SrcMBB) const;
   // Creates a list of packed instructions following an MFMA that are suitable
   // for unpacking.
   void collectUnpackingCandidates(MachineInstr &BeginMI,
@@ -514,6 +521,68 @@ bool SIPreEmitPeephole::removeExeczBranch(MachineInstr &MI,
   return true;
 }
 
+/// Remove writes to the FP round mode that can never be observed: either the
+/// value written is already live in MODE, or a later s_round_mode overwrites
+/// the whole round mode field before anything reads it.
+///
+/// This is a purely intra-block analysis: the round mode on entry to \p MBB is
+/// unknown, and a write that is still live at the end of the block is kept for
+/// the benefit of the successors.
+bool SIPreEmitPeephole::removeRedundantRoundMode(
+    MachineBasicBlock &SrcMBB) const {
+  MachineInstr *PendingWrite = nullptr;
+  std::optional<int64_t> CurrentRoundMode;
+  std::optional<int64_t> RoundModeBeforePendingWrite;
+  bool Changed = false;
+
+  for (MachineInstr &MI : make_early_inc_range(SrcMBB.instrs())) {
+    if (MI.isDebugInstr())
+      continue;
+
+    if (MI.getOpcode() == AMDGPU::S_ROUND_MODE) {
+      int64_t NewRoundMode = MI.getOperand(0).getImm();
+
+      if (PendingWrite && CurrentRoundMode != NewRoundMode) {
+        LLVM_DEBUG(dbgs() << "Removing dead round mode write: "
+                          << *PendingWrite);
+        PendingWrite->eraseFromParent();
+        ++NumRoundModeWritesRemoved;
+        Changed = true;
+        PendingWrite = nullptr;
+        CurrentRoundMode = RoundModeBeforePendingWrite;
+      }
+
+      if (CurrentRoundMode == NewRoundMode) {
+        LLVM_DEBUG(dbgs() << "Removing redundant round mode write: " << MI);
+        MI.eraseFromParent();
+        ++NumRoundModeWritesRemoved;
+        Changed = true;
+        continue;
+      }
+
+      RoundModeBeforePendingWrite = CurrentRoundMode;
+      PendingWrite = &MI;
+      CurrentRoundMode = NewRoundMode;
+      continue;
+    }
+
+    if (!PendingWrite && !CurrentRoundMode)
+      continue;
+
+    if (MI.isCall() || MI.isInlineAsm() ||
+        MI.modifiesRegister(AMDGPU::MODE, TRI)) {
+      PendingWrite = nullptr;
+      CurrentRoundMode.reset();
+      continue;
+    }
+
+    if (MI.readsRegister(AMDGPU::MODE, TRI) || MI.hasUnmodeledSideEffects()) {
+      PendingWrite = nullptr;
+    }
+  }
+  return Changed;
+}
+
 bool SIPreEmitPeephole::canUnpackingClobberRegister(const MachineInstr &MI) {
   unsigned OpCode = MI.getOpcode();
   Register DstReg = MI.getOperand(0).getReg();
@@ -792,6 +861,10 @@ bool SIPreEmitPeephole::run(MachineFunction &MF, MachineLoopInfo *LoopInfo) {
 
   MF.RenumberBlocks();
 
+  for (MachineBasicBlock &MBB : MF) {
+    Changed |= removeRedundantRoundMode(MBB);
+  }
+
   for (MachineBasicBlock &MBB : MF) {
     MachineBasicBlock::iterator TermI = MBB.getFirstTerminator();
     // Check first terminator for branches to optimize
diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-redundant-round-mode.mir b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-redundant-round-mode.mir
new file mode 100644
index 0000000000000..e678714815021
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-redundant-round-mode.mir
@@ -0,0 +1,317 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc --mtriple=amdgpu12.01 -run-pass=si-pre-emit-peephole -verify-machineinstrs %s -o - | FileCheck %s
+# RUN: llc --mtriple=amdgpu12.01 -passes=si-pre-emit-peephole %s -o - | FileCheck %s
+
+---
+name: dead_write_pair
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: dead_write_pair
+    ; CHECK: $sgpr2 = S_MOV_B32 0
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    $sgpr2 = S_MOV_B32 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: dead_write_run_of_three
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: dead_write_run_of_three
+    ; CHECK: $sgpr2 = S_MOV_B32 0
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    $sgpr2 = S_MOV_B32 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    S_ROUND_MODE 10, implicit-def $mode, implicit $mode
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: dead_write_across_non_mode_instr
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: dead_write_across_non_mode_instr
+    ; CHECK: $sgpr2 = S_MOV_B32 0
+    ; CHECK-NEXT: $vgpr3 = V_ADD_U32_e32 $vgpr1, $vgpr2, implicit $exec
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    $sgpr2 = S_MOV_B32 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    $vgpr3 = V_ADD_U32_e32 $vgpr1, $vgpr2, implicit $exec
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: dead_write_across_fp_instr_not_reading_mode
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: dead_write_across_fp_instr_not_reading_mode
+    ; CHECK: $sgpr2 = S_MOV_B32 0
+    ; CHECK-NEXT: $vgpr3 = V_CVT_F32_UBYTE0_e32 $vgpr1, implicit $exec
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    $sgpr2 = S_MOV_B32 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    $vgpr3 = V_CVT_F32_UBYTE0_e32 $vgpr1, implicit $exec
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: redundant_write_after_reader
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: redundant_write_after_reader
+    ; CHECK: S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: $vgpr3 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    $vgpr3 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: duplicate_adjacent_writes
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: duplicate_adjacent_writes
+    ; CHECK: S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: redundant_write_across_side_effecting_instr
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: redundant_write_across_side_effecting_instr
+    ; CHECK: S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_NOP 0
+    ; CHECK-NEXT: $vgpr3 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_NOP 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    $vgpr3 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: unknown_mode_on_entry
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: unknown_mode_on_entry
+    ; CHECK: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: fp_reader_between
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: fp_reader_between
+    ; CHECK: S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr3 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr3 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: getreg_reader_between
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: getreg_reader_between
+    ; CHECK: S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $sgpr0 = S_GETREG_B32 1, implicit $mode
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    $sgpr0 = S_GETREG_B32 1, implicit $mode
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: write_kept_across_side_effecting_instr
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: write_kept_across_side_effecting_instr
+    ; CHECK: S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: S_NOP 0
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    S_NOP 0
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: partial_setreg_between
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: partial_setreg_between
+    ; CHECK: S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: S_SETREG_IMM32_B32_mode 1, 1, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    S_SETREG_IMM32_B32_mode 1, 1, implicit-def $mode, implicit $mode
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: denorm_mode_between
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: denorm_mode_between
+    ; CHECK: S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: S_DENORM_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    S_DENORM_MODE 0, implicit-def $mode, implicit $mode
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: call_between
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: call_between
+    ; CHECK: S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $sgpr30_sgpr31 = SI_CALL killed $sgpr0_sgpr1, 0, csr_amdgpu
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    $sgpr30_sgpr31 = SI_CALL killed $sgpr0_sgpr1, 0, csr_amdgpu
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: inline_asm_between
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: inline_asm_between
+    ; CHECK: S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: INLINEASM &"s_nop 0", attdialect
+    ; CHECK-NEXT: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    INLINEASM &"s_nop 0", 0
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: write_live_out_of_block
+body: |
+  ; CHECK-LABEL: name: write_live_out_of_block
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+  ; CHECK-NEXT:   $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+  ; CHECK-NEXT:   S_ENDPGM 0
+  bb.0:
+    successors: %bb.1
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+
+  bb.1:
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: same_value_in_predecessor
+body: |
+  ; CHECK-LABEL: name: same_value_in_predecessor
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+  ; CHECK-NEXT:   $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+  ; CHECK-NEXT:   $vgpr3 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+  ; CHECK-NEXT:   S_ENDPGM 0
+  bb.0:
+    successors: %bb.1
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+
+  bb.1:
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr3 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...
+
+---
+name: dead_write_then_restore_makes_redundant
+body: |
+  bb.0:
+    ; CHECK-LABEL: name: dead_write_then_restore_makes_redundant
+    ; CHECK: S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    ; CHECK-NEXT: $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: $vgpr3 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    ; CHECK-NEXT: S_ENDPGM 0
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr0 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ROUND_MODE 5, implicit-def $mode, implicit $mode
+    S_ROUND_MODE 0, implicit-def $mode, implicit $mode
+    $vgpr3 = V_ADD_F32_e32 $vgpr1, $vgpr2, implicit $mode, implicit $exec
+    S_ENDPGM 0
+...

``````````

</details>


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


More information about the llvm-commits mailing list