[llvm] [AMDGPU] Eliminate redundant s_round_mode and s_denorm_mode writes (PR #216305)
Barbara Mitic via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 20 06:08:46 PDT 2026
https://github.com/barbara-amd updated https://github.com/llvm/llvm-project/pull/216305
>From f3faa341a0131757e1e2099cb1ae0bcac486f8bc Mon Sep 17 00:00:00 2001
From: Barbara Mitic <Barbara.Mitic at amd.com>
Date: Thu, 13 Aug 2026 14:13:34 +0200
Subject: [PATCH] [AMDGPU] Eliminate redundant s_round_mode and s_denorm_mode
writes
Add a block local peephole that drops writes to the FP round mode and the
FP denorm mode which cannot be observed. A write is removed when a later
write replaces the field before any instruction reads MODE, or when the
value it writes is already live in MODE.
s_round_mode and s_denorm_mode each assign one field of MODE and preserve
the rest of the register, so the two fields are tracked independently: a
write to one field is transparent to a pending write to the other.
The analysis is intra-block only: the 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.
---
llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp | 87 +++++
...pre-emit-peephole-redundant-mode-writes.ll | 335 ++++++++++++++++++
2 files changed, 422 insertions(+)
create mode 100644 llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-redundant-mode-writes.ll
diff --git a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
index 7f87fbc0448b3..82a53dd94a83c 100644
--- a/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPreEmitPeephole.cpp
@@ -22,6 +22,7 @@
#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"
@@ -32,8 +33,21 @@ using namespace llvm;
#define DEBUG_TYPE "si-pre-emit-peephole"
+STATISTIC(NumModeWritesRemoved,
+ "Number of redundant mode register writes removed");
+
namespace {
+/// The state of one independent field of the MODE register, as tracked by
+/// removeRedundantModeWrites.
+struct ModeFieldState {
+ std::optional<int64_t> Value;
+ std::optional<int64_t> ValueBeforePendingWrite;
+ MachineInstr *PendingWrite = nullptr;
+
+ bool isTracked() const { return PendingWrite || Value; }
+};
+
class SIPreEmitPeephole {
private:
const SIInstrInfo *TII = nullptr;
@@ -52,6 +66,7 @@ class SIPreEmitPeephole {
const MachineBasicBlock &From,
const MachineBasicBlock &To) const;
bool removeExeczBranch(MachineInstr &MI, MachineBasicBlock &SrcMBB);
+ bool removeRedundantModeWrites(MachineBasicBlock &SrcMBB) const;
// Creates a list of packed instructions following an MFMA that are suitable
// for unpacking.
void collectUnpackingCandidates(MachineInstr &BeginMI,
@@ -514,6 +529,76 @@ bool SIPreEmitPeephole::removeExeczBranch(MachineInstr &MI,
return true;
}
+/// Remove writes to the FP round mode and FP denorm mode that can never be
+/// observed: either the value written is already live in MODE, or a mode write
+/// replaces the whole mode field before anything reads it.
+///
+/// s_round_mode and s_denorm_mode each assign one field of MODE and preserve
+/// the rest of the register, so the two fields are tracked independently and a
+/// write to one is transparent to the other.
+///
+/// This is a purely intra-block analysis: the mode on entry to \p SrcMBB 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::removeRedundantModeWrites(
+ MachineBasicBlock &SrcMBB) const {
+ bool Changed = false;
+ ModeFieldState DenormMode;
+ ModeFieldState RoundMode;
+
+ for (MachineInstr &MI : make_early_inc_range(SrcMBB)) {
+ if (MI.isDebugInstr())
+ continue;
+
+ unsigned Opc = MI.getOpcode();
+ if (Opc == AMDGPU::S_DENORM_MODE || Opc == AMDGPU::S_ROUND_MODE) {
+ ModeFieldState &Field =
+ Opc == AMDGPU::S_DENORM_MODE ? DenormMode : RoundMode;
+ int64_t NewValue = MI.getOperand(0).getImm();
+
+ if (Field.PendingWrite) {
+ LLVM_DEBUG(dbgs() << "Removing dead mode write: "
+ << *Field.PendingWrite);
+ Field.PendingWrite->eraseFromParent();
+ ++NumModeWritesRemoved;
+ Changed = true;
+ Field.PendingWrite = nullptr;
+ Field.Value = Field.ValueBeforePendingWrite;
+ }
+
+ if (Field.Value == NewValue) {
+ LLVM_DEBUG(dbgs() << "Removing redundant mode write: " << MI);
+ MI.eraseFromParent();
+ ++NumModeWritesRemoved;
+ Changed = true;
+ continue;
+ }
+
+ Field.ValueBeforePendingWrite = Field.Value;
+ Field.PendingWrite = &MI;
+ Field.Value = NewValue;
+ continue;
+ }
+
+ // Nothing tracked yet; skip register checks below.
+ if (!DenormMode.isTracked() && !RoundMode.isTracked())
+ continue;
+
+ // Inline asm cannot declare a MODE clobber, so assume it writes both.
+ if (MI.isInlineAsm() || MI.modifiesRegister(AMDGPU::MODE, TRI)) {
+ DenormMode = ModeFieldState();
+ RoundMode = ModeFieldState();
+ continue;
+ }
+
+ if (MI.readsRegister(AMDGPU::MODE, TRI) || MI.hasUnmodeledSideEffects()) {
+ DenormMode.PendingWrite = nullptr;
+ RoundMode.PendingWrite = nullptr;
+ }
+ }
+ return Changed;
+}
+
bool SIPreEmitPeephole::canUnpackingClobberRegister(const MachineInstr &MI) {
unsigned OpCode = MI.getOpcode();
Register DstReg = MI.getOperand(0).getReg();
@@ -793,6 +878,8 @@ bool SIPreEmitPeephole::run(MachineFunction &MF, MachineLoopInfo *LoopInfo) {
MF.RenumberBlocks();
for (MachineBasicBlock &MBB : MF) {
+ Changed |= removeRedundantModeWrites(MBB);
+
MachineBasicBlock::iterator TermI = MBB.getFirstTerminator();
// Check first terminator for branches to optimize
if (TermI != MBB.end()) {
diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-redundant-mode-writes.ll b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-redundant-mode-writes.ll
new file mode 100644
index 0000000000000..4d859f3851276
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-emit-peephole-redundant-mode-writes.ll
@@ -0,0 +1,335 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgpu12.01 < %s | FileCheck %s
+
+define amdgpu_kernel void @dead_round_write(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: dead_round_write:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_load_b128 s[0:3], s[4:5], 0x24
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_add_f32 s2, s2, s3
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3)
+; CHECK-NEXT: v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, s2
+; CHECK-NEXT: global_store_b32 v0, v1, s[0:1]
+; CHECK-NEXT: s_endpgm
+ call void @llvm.set.rounding(i32 0)
+ call void @llvm.set.rounding(i32 1)
+ %add = fadd float %a, %b
+ store float %add, ptr addrspace(1) %out
+ ret void
+}
+
+define amdgpu_kernel void @redundant_round_write(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: redundant_round_write:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_load_b128 s[0:3], s[4:5], 0x24
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_add_f32 s2, s2, s3
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; CHECK-NEXT: s_mul_f32 s2, s2, s3
+; CHECK-NEXT: v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, s2
+; CHECK-NEXT: global_store_b32 v0, v1, s[0:1]
+; CHECK-NEXT: s_endpgm
+ call void @llvm.set.rounding(i32 1)
+ %add = fadd float %a, %b
+ call void @llvm.set.rounding(i32 1)
+ %mul = fmul float %add, %b
+ store float %mul, ptr addrspace(1) %out
+ ret void
+}
+
+define amdgpu_kernel void @dead_denorm_write(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: dead_denorm_write:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_load_b128 s[0:3], s[4:5], 0x24
+; CHECK-NEXT: s_denorm_mode 12
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_add_f32 s2, s2, s3
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3)
+; CHECK-NEXT: v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, s2
+; CHECK-NEXT: global_store_b32 v0, v1, s[0:1]
+; CHECK-NEXT: s_endpgm
+ call void @llvm.amdgcn.s.setreg(i32 6401, i32 15)
+ call void @llvm.amdgcn.s.setreg(i32 6401, i32 12)
+ %add = fadd float %a, %b
+ store float %add, ptr addrspace(1) %out
+ ret void
+}
+
+define amdgpu_kernel void @redundant_denorm_write(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: redundant_denorm_write:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_load_b128 s[0:3], s[4:5], 0x24
+; CHECK-NEXT: s_denorm_mode 15
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_add_f32 s2, s2, s3
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; CHECK-NEXT: s_mul_f32 s2, s2, s3
+; CHECK-NEXT: v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, s2
+; CHECK-NEXT: global_store_b32 v0, v1, s[0:1]
+; CHECK-NEXT: s_endpgm
+ call void @llvm.amdgcn.s.setreg(i32 6401, i32 15)
+ %add = fadd float %a, %b
+ call void @llvm.amdgcn.s.setreg(i32 6401, i32 15)
+ %mul = fmul float %add, %b
+ store float %mul, ptr addrspace(1) %out
+ ret void
+}
+
+define amdgpu_kernel void @dead_round_and_denorm_writes(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: dead_round_and_denorm_writes:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_load_b128 s[0:3], s[4:5], 0x24
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: s_denorm_mode 15
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_add_f32 s2, s2, s3
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3)
+; CHECK-NEXT: v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, s2
+; CHECK-NEXT: global_store_b32 v0, v1, s[0:1]
+; CHECK-NEXT: s_endpgm
+ call void @llvm.amdgcn.s.setreg(i32 14337, i32 165)
+ call void @llvm.amdgcn.s.setreg(i32 14337, i32 240)
+ %add = fadd float %a, %b
+ store float %add, ptr addrspace(1) %out
+ ret void
+}
+
+define amdgpu_kernel void @dead_round_write_across_denorm_write(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: dead_round_write_across_denorm_write:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_load_b128 s[0:3], s[4:5], 0x24
+; CHECK-NEXT: s_denorm_mode 15
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_add_f32 s2, s2, s3
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3)
+; CHECK-NEXT: v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, s2
+; CHECK-NEXT: global_store_b32 v0, v1, s[0:1]
+; CHECK-NEXT: s_endpgm
+ call void @llvm.set.rounding(i32 0)
+ call void @llvm.amdgcn.s.setreg(i32 6401, i32 15)
+ call void @llvm.set.rounding(i32 1)
+ %add = fadd float %a, %b
+ store float %add, ptr addrspace(1) %out
+ ret void
+}
+
+define amdgpu_kernel void @dead_denorm_write_across_round_write(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: dead_denorm_write_across_round_write:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_load_b128 s[0:3], s[4:5], 0x24
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: s_denorm_mode 15
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_add_f32 s2, s2, s3
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_3)
+; CHECK-NEXT: v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, s2
+; CHECK-NEXT: global_store_b32 v0, v1, s[0:1]
+; CHECK-NEXT: s_endpgm
+ call void @llvm.amdgcn.s.setreg(i32 6401, i32 12)
+ call void @llvm.set.rounding(i32 1)
+ call void @llvm.amdgcn.s.setreg(i32 6401, i32 15)
+ %add = fadd float %a, %b
+ store float %add, ptr addrspace(1) %out
+ ret void
+}
+
+define void @round_write_kept_across_inline_asm(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: round_write_kept_across_inline_asm:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_expcnt 0x0
+; CHECK-NEXT: s_wait_samplecnt 0x0
+; CHECK-NEXT: s_wait_bvhcnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: ;;#ASMSTART
+; CHECK-NEXT: ;;#ASMEND
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: v_add_f32_e32 v2, v2, v3
+; CHECK-NEXT: global_store_b32 v[0:1], v2, off
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @llvm.set.rounding(i32 1)
+ call void asm sideeffect "", ""()
+ call void @llvm.set.rounding(i32 1)
+ %add = fadd float %a, %b
+ store float %add, ptr addrspace(1) %out
+ ret void
+}
+
+define void @round_write_kept_across_call() {
+; CHECK-LABEL: round_write_kept_across_call:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_expcnt 0x0
+; CHECK-NEXT: s_wait_samplecnt 0x0
+; CHECK-NEXT: s_wait_bvhcnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_mov_b32 s0, s33
+; CHECK-NEXT: s_mov_b32 s33, s32
+; CHECK-NEXT: s_or_saveexec_b32 s1, -1
+; CHECK-NEXT: scratch_store_b32 off, v40, s33 ; 4-byte Folded Spill
+; CHECK-NEXT: s_wait_alu depctr_sa_sdst(0)
+; CHECK-NEXT: s_mov_b32 exec_lo, s1
+; CHECK-NEXT: v_writelane_b32 v40, s0, 2
+; CHECK-NEXT: v_writelane_b32 v40, s30, 0
+; CHECK-NEXT: s_add_co_i32 s32, s32, 16
+; CHECK-NEXT: v_writelane_b32 v40, s31, 1
+; CHECK-NEXT: s_getpc_b64 s[0:1]
+; CHECK-NEXT: s_wait_alu depctr_sa_sdst(0)
+; CHECK-NEXT: s_sext_i32_i16 s1, s1
+; CHECK-NEXT: s_add_co_u32 s0, s0, extern_func at gotpcrel32@lo+12
+; CHECK-NEXT: s_wait_alu depctr_sa_sdst(0)
+; CHECK-NEXT: s_add_co_ci_u32 s1, s1, extern_func at gotpcrel32@hi+24
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: s_load_b64 s[0:1], s[0:1], 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_swappc_b64 s[30:31], s[0:1]
+; CHECK-NEXT: v_readlane_b32 s30, v40, 0
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: v_readlane_b32 s31, v40, 1
+; CHECK-NEXT: s_mov_b32 s32, s33
+; CHECK-NEXT: v_readlane_b32 s0, v40, 2
+; CHECK-NEXT: s_or_saveexec_b32 s1, -1
+; CHECK-NEXT: scratch_load_b32 v40, off, s33 ; 4-byte Folded Reload
+; CHECK-NEXT: s_wait_alu depctr_sa_sdst(0)
+; CHECK-NEXT: s_mov_b32 exec_lo, s1
+; CHECK-NEXT: s_mov_b32 s33, s0
+; CHECK-NEXT: s_wait_loadcnt 0x0
+; CHECK-NEXT: s_wait_alu depctr_sa_sdst(0)
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @llvm.set.rounding(i32 1)
+ call void @extern_func()
+ call void @llvm.set.rounding(i32 1)
+ ret void
+}
+
+define void @round_write_kept_across_setreg(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: round_write_kept_across_setreg:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_expcnt 0x0
+; CHECK-NEXT: s_wait_samplecnt 0x0
+; CHECK-NEXT: s_wait_bvhcnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 8, 4), 1
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: v_add_f32_e32 v2, v2, v3
+; CHECK-NEXT: global_store_b32 v[0:1], v2, off
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @llvm.set.rounding(i32 1)
+ call void @llvm.amdgcn.s.setreg(i32 6657, i32 1)
+ call void @llvm.set.rounding(i32 1)
+ %add = fadd float %a, %b
+ store float %add, ptr addrspace(1) %out
+ ret void
+}
+
+define void @round_write_kept_across_side_effect(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: round_write_kept_across_side_effect:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_expcnt 0x0
+; CHECK-NEXT: s_wait_samplecnt 0x0
+; CHECK-NEXT: s_wait_bvhcnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: s_nop 0
+; CHECK-NEXT: s_round_mode 0xf
+; CHECK-NEXT: v_add_f32_e32 v2, v2, v3
+; CHECK-NEXT: global_store_b32 v[0:1], v2, off
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @llvm.set.rounding(i32 1)
+ call void @llvm.amdgcn.s.nop(i16 0)
+ call void @llvm.set.rounding(i32 0)
+ %add = fadd float %a, %b
+ store float %add, ptr addrspace(1) %out
+ ret void
+}
+
+define void @dead_round_write_then_restore(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: dead_round_write_then_restore:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_expcnt 0x0
+; CHECK-NEXT: s_wait_samplecnt 0x0
+; CHECK-NEXT: s_wait_bvhcnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_round_mode 0xf
+; CHECK-NEXT: v_add_f32_e32 v2, v2, v3
+; CHECK-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; CHECK-NEXT: v_mul_f32_e32 v2, v2, v3
+; CHECK-NEXT: global_store_b32 v[0:1], v2, off
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @llvm.set.rounding(i32 0)
+ %add = fadd float %a, %b
+ call void @llvm.set.rounding(i32 1)
+ call void @llvm.set.rounding(i32 0)
+ %mul = fmul float %add, %b
+ store float %mul, ptr addrspace(1) %out
+ ret void
+}
+
+define void @round_write_kept_across_fp_reader(ptr addrspace(1) %out, float %a, float %b) {
+; CHECK-LABEL: round_write_kept_across_fp_reader:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_expcnt 0x0
+; CHECK-NEXT: s_wait_samplecnt 0x0
+; CHECK-NEXT: s_wait_bvhcnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: v_add_f32_e32 v2, v2, v3
+; CHECK-NEXT: s_round_mode 0xf
+; CHECK-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; CHECK-NEXT: v_mul_f32_e32 v2, v2, v3
+; CHECK-NEXT: global_store_b32 v[0:1], v2, off
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+ call void @llvm.set.rounding(i32 1)
+ %add = fadd float %a, %b
+ call void @llvm.set.rounding(i32 0)
+ %mul = fmul float %add, %b
+ store float %mul, ptr addrspace(1) %out
+ ret void
+}
+
+define void @round_write_live_out(ptr addrspace(1) %out, float %a, float %b, i1 %c) {
+; CHECK-LABEL: round_write_live_out:
+; CHECK: ; %bb.0: ; %entry
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_expcnt 0x0
+; CHECK-NEXT: s_wait_samplecnt 0x0
+; CHECK-NEXT: s_wait_bvhcnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: v_and_b32_e32 v4, 1, v4
+; CHECK-NEXT: s_mov_b32 s0, exec_lo
+; CHECK-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; CHECK-NEXT: v_cmpx_eq_u32_e32 1, v4
+; CHECK-NEXT: s_cbranch_execz .LBB13_2
+; CHECK-NEXT: ; %bb.1: ; %then
+; CHECK-NEXT: s_round_mode 0x0
+; CHECK-NEXT: .LBB13_2: ; %join
+; CHECK-NEXT: s_wait_alu depctr_sa_sdst(0)
+; CHECK-NEXT: s_or_b32 exec_lo, exec_lo, s0
+; CHECK-NEXT: s_round_mode 0xf
+; CHECK-NEXT: v_add_f32_e32 v2, v2, v3
+; CHECK-NEXT: global_store_b32 v[0:1], v2, off
+; CHECK-NEXT: s_setpc_b64 s[30:31]
+entry:
+ br i1 %c, label %then, label %join
+
+then:
+ call void @llvm.set.rounding(i32 1)
+ br label %join
+
+join:
+ call void @llvm.set.rounding(i32 0)
+ %add = fadd float %a, %b
+ store float %add, ptr addrspace(1) %out
+ ret void
+}
+
+declare void @extern_func()
More information about the llvm-commits
mailing list