[libc-commits] [libc] [llvm] [LoongArch] Support ISD::SET_ROUNDING (llvm.set.rounding) (PR #205051)

via libc-commits libc-commits at lists.llvm.org
Mon Jun 22 23:48:55 PDT 2026


================
@@ -4015,6 +4019,53 @@ SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
   return Op;
 }
 
+SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
+                                                   SelectionDAG &DAG) const {
+  MVT GRLenVT = Subtarget.getGRLenVT();
+  SDLoc DL(Op);
+  SDValue Chain = Op.getOperand(0);
+  SDValue RMValue = Op.getOperand(1);
+
+  // LLVM rounding mode encoding: 0=RTZ, 1=RNE, 2=RUP, 3=RDN.
+  if (auto *CVal = dyn_cast<ConstantSDNode>(RMValue)) {
+    uint64_t RM = CVal->getZExtValue();
+    if (RM > 3) {
+      DAG.getContext()->emitError("invalid rounding mode");
+      return Chain;
+    }
+  }
+
+  // Zero-extend i32 rounding mode to GRLenVT.
+  RMValue = DAG.getNode(ISD::ZERO_EXTEND, DL, GRLenVT, RMValue);
+
+  // LLVM rounding mode encoding differs from LoongArch FCSR encoding:
+  //   LLVM: 0=RTZ, 1=RNE, 2=RUP, 3=RDN
+  //   FCSR: 0=RNE, 1=RZ,  2=RP,  3=RN
+  // Translate by swapping 0↔1 (XOR with 1 when RM < 2), keep 2 and 3.
+  //   0 (RTZ) → 1 (RZ), 1 (RNE) → 0 (RNE), 2 (RUP) → 2 (RP), 3 (RDN) → 3 (RN)
+  // Transformation: RM ^ (~(RM >> 1) & 1)
+  SDValue ShiftRight1 = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
+                                    DAG.getConstant(1, DL, GRLenVT));
+  SDValue SwapMask = DAG.getNode(ISD::AND, DL, GRLenVT,
+      DAG.getNode(ISD::XOR, DL, GRLenVT, ShiftRight1,
+                  DAG.getConstant(1, DL, GRLenVT)),
+      DAG.getConstant(1, DL, GRLenVT));
+  RMValue = DAG.getNode(ISD::XOR, DL, GRLenVT, RMValue, SwapMask);
+
+  // Mask to 2 bits to guard against invalid values.
+  RMValue = DAG.getNode(ISD::AND, DL, GRLenVT, RMValue,
+                        DAG.getConstant(0x3, DL, GRLenVT));
+
+  // Build MachineInstr node for WRFCSR (pseudo for MOVGR2FCSR).
+  // WRFCSR takes (uimm2:$fcsr, GPR:$src).
+  // FCSR3 is an alias of the RM field; writing it avoids clobbering
+  // unrelated fields in FCSR0.
+  SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
+  MachineSDNode *RN = DAG.getMachineNode(LoongArch::WRFCSR, DL, MVT::Other,
+                                         FCSRNo, RMValue, Chain);
----------------
wangleiat wrote:

`RMValue` should be left-shifted by 8 bits before being written.

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


More information about the libc-commits mailing list