[llvm] [RISCV] Explicitly set FRM defs as non-dead to prevent their reordering with instructions that may use it (PR #135176)

Sergey Kachkov via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 10 06:24:36 PDT 2025


https://github.com/skachkov-sc created https://github.com/llvm/llvm-project/pull/135176

Fixes #135172. The proposed solution is to conservatively reset dead flag from all $frm defs in AdjustInstrPostInstrSelection (this is probably a bit hacky, so I'm open to the better ideas)

>From c24c643b0ed323c0cc2d4ef6cd82eecca78c79e4 Mon Sep 17 00:00:00 2001
From: Sergey Kachkov <sergey.kachkov at syntacore.com>
Date: Thu, 10 Apr 2025 12:56:12 +0300
Subject: [PATCH 1/2] [RISCV][NFC] Add pre-commit test

---
 llvm/test/CodeGen/RISCV/frm-write-in-loop.ll | 35 ++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/frm-write-in-loop.ll

diff --git a/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll b/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll
new file mode 100644
index 0000000000000..9501b93cd11b9
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll
@@ -0,0 +1,35 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -O3 -mtriple=riscv64 -mattr=+f,+d < %s | FileCheck %s
+
+; Make sure WriteFRM is not hoisted out of loop due to dead implicit-def.
+
+define double @foo(double %0, double %1, i64 %n) strictfp {
+; CHECK-LABEL: foo:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    fmv.d.x fa5, zero
+; CHECK-NEXT:    fsrmi 3
+; CHECK-NEXT:    fsrmi 0
+; CHECK-NEXT:  .LBB0_1: # %loop
+; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    fadd.d fa5, fa5, fa0
+; CHECK-NEXT:    addi a0, a0, -1
+; CHECK-NEXT:    fadd.d fa5, fa5, fa1
+; CHECK-NEXT:    beqz a0, .LBB0_1
+; CHECK-NEXT:  # %bb.2: # %exit
+; CHECK-NEXT:    fmv.d fa0, fa5
+; CHECK-NEXT:    ret
+entry:
+    br label %loop
+loop:
+    %cnt = phi i64 [0, %entry], [%cnt_inc, %loop]
+    %acc = phi double [0.0, %entry], [%f2, %loop]
+    call void @llvm.set.rounding(i32 2) strictfp
+    %f1 = call double @llvm.experimental.constrained.fadd.f64(double %acc, double %0, metadata !"round.dynamic", metadata !"fpexcept.ignore") strictfp
+    call void @llvm.set.rounding(i32 1) strictfp
+    %f2 = call double @llvm.experimental.constrained.fadd.f64(double %f1, double %1, metadata !"round.dynamic", metadata !"fpexcept.ignore") strictfp
+    %cnt_inc = add i64 %cnt, 1
+    %cond = icmp eq i64 %cnt_inc, %n
+    br i1 %cond, label %loop, label %exit
+exit:
+    ret double %f2
+}

>From 9b559ca74069fe242eaf87d35000d50e8255af60 Mon Sep 17 00:00:00 2001
From: Sergey Kachkov <sergey.kachkov at syntacore.com>
Date: Thu, 10 Apr 2025 12:48:08 +0300
Subject: [PATCH 2/2] [RISCV] Explicitly set FRM defs as non-dead to prevent
 their reordering with instructions that may use it

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp  | 9 +++++++++
 llvm/lib/Target/RISCV/RISCVInstrInfo.td      | 2 ++
 llvm/test/CodeGen/RISCV/frm-write-in-loop.ll | 4 ++--
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index f7d192756fd56..414fb58f0cbeb 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -20926,6 +20926,15 @@ RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
 
 void RISCVTargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI,
                                                         SDNode *Node) const {
+  // If instruction defines FRM operand, conservatively set it as non-dead to
+  // express data dependency with FRM users and prevent incorrect instruction
+  // reordering (these defs are marked as dead because at the moment of
+  // instruction emission they actually don't have any uses - they are added
+  // later in this hook).
+  if (auto *FRMDef = MI.findRegisterDefOperand(RISCV::FRM, /*TRI=*/nullptr)) {
+    FRMDef->setIsDead(false);
+    return;
+  }
   // Add FRM dependency to any instructions with dynamic rounding mode.
   int Idx = RISCV::getNamedOperandIdx(MI.getOpcode(), RISCV::OpName::frm);
   if (Idx < 0) {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index c87452171f090..1104d9089536f 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1941,9 +1941,11 @@ class SwapSysRegImm<SysReg SR, list<Register> Regs>
 }
 
 def ReadFRM : ReadSysReg<SysRegFRM, [FRM]>;
+let hasPostISelHook = 1 in {
 def WriteFRM : WriteSysReg<SysRegFRM, [FRM]>;
 def WriteFRMImm : WriteSysRegImm<SysRegFRM, [FRM]>;
 def SwapFRMImm : SwapSysRegImm<SysRegFRM, [FRM]>;
+}
 
 def WriteVXRMImm : WriteSysRegImm<SysRegVXRM, [VXRM]>;
 
diff --git a/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll b/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll
index 9501b93cd11b9..9ef8e4b67edd7 100644
--- a/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll
+++ b/llvm/test/CodeGen/RISCV/frm-write-in-loop.ll
@@ -7,11 +7,11 @@ define double @foo(double %0, double %1, i64 %n) strictfp {
 ; CHECK-LABEL: foo:
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    fmv.d.x fa5, zero
-; CHECK-NEXT:    fsrmi 3
-; CHECK-NEXT:    fsrmi 0
 ; CHECK-NEXT:  .LBB0_1: # %loop
 ; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    fsrmi 3
 ; CHECK-NEXT:    fadd.d fa5, fa5, fa0
+; CHECK-NEXT:    fsrmi 0
 ; CHECK-NEXT:    addi a0, a0, -1
 ; CHECK-NEXT:    fadd.d fa5, fa5, fa1
 ; CHECK-NEXT:    beqz a0, .LBB0_1



More information about the llvm-commits mailing list