Agree with Robin and Andrew. I was thinking we may not need to take care of vxrm similar as frm in previous, but seems not that simple up to a point after Richard S points it out.
I also failed to locate some spec/doc about the details. I remember Jeff has some findings/comments, and may wait for a while if we need to tweak the vxrm behaviors, like set, consume, global_reg, ... etc. Pan -----Original Message----- From: Robin Dapp <rdapp....@gmail.com> Sent: Tuesday, March 4, 2025 8:51 PM To: Vineet Gupta <vine...@rivosinc.com>; Andrew Waterman <aswater...@gmail.com> Cc: Li, Pan2 <pan2...@intel.com>; jeffreya...@gmail.com; gcc-patches@gcc.gnu.org; juzhe.zh...@rivai.ai; kito.ch...@gmail.com; richard.sandif...@arm.com; Robin Dapp <rdapp....@gmail.com> Subject: Re: FRM ABI semantics (was Re: [PATCH v1] RISC-V: Make VXRM as global register [PR118103]) > Yeah I didn't know how to articulate it (and perhaps this still requires > clarification) > > Say we have following > > // reduced version of gcc.target/riscv/rvv/base/float-point-frm-run-1.c > main > set_frm (4); // orig global FRM update > > test_float_point_frm_run_1 (op1, op2, vl) > set_frm (0); > result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl); > assert_equal (1, get_frm ()) > // restore global 4 before returning > > assert_equal (4, get_frm () <-- here call restores global > > vs. > > // reduced version of gcc.target/riscv/rvv/base/float-point-frm-run-5.c > main > set_frm (1); // orig global FRM update > > test_float_point_frm_run_1 (op1, op2, vl) > other_function() > set_frm (2); // also global update > > assert_equal (2, get_frm () <-- here call doesn't restore > > There's no explicit annotation or anything about the FRM, yet in 2nd example > other_function () we consider frm write a global event but not in > test_float_point_frm_run_1 () in 1st example: I'm missing words how to explain > that :-) AFAIR the general idea is that every function can potentially "clobber", i.e. set FRM globally. The intent of the first test is to save and restore the global rounding mode because we modify it locally by a rounding-mode changing intrinsic. However, as you note, the set_frm at the beginning of test_float_point_frm_run_1 has no effect. What should intuitively(?) happen is that it sets a new global FRM that we restore upon exit. We, however, restore the previous global FRM. I believe that's because set_frm is an inline assembly, inlined into test_float_point_frm_run_1 and we expect inline assemblies to _not_ change the rounding mode. That was one of my concerns during the review some time in 2023. If set_frm were a non-inlined function we'd need to assume it changes the rounding mode and restore the value it has after the set_frm call. And that's also what is different in frm-run-5.c (your second snippet). We wrap the set_frm call in another non-inlinable call. Thus, we need to assume the global rounding mode changes and save/restore. I guess it was a deliberate decision to handle asm snippets different. At least as long as they are in the same visible scope it's obvious when they're changing the rounding mode. One could argue that users doing that are on their own. Not sure that argument has worked very well, historically, though ;) -- Regards Robin