[libc-commits] [libc] [llvm] [LoongArch] Support ISD::SET_ROUNDING (llvm.set.rounding) (PR #205051)
Paper Moon via libc-commits
libc-commits at lists.llvm.org
Mon Jun 22 21:07:36 PDT 2026
https://github.com/tangyuan0821 updated https://github.com/llvm/llvm-project/pull/205051
>From 152f23515b7d900fe0a698a2b479ab4bfbdc982a Mon Sep 17 00:00:00 2001
From: tangyuan0821 <tangyuan0821 at email.cn>
Date: Mon, 22 Jun 2026 16:00:05 +0800
Subject: [PATCH 1/4] [LoongArch] Support ISD::SET_ROUNDING (llvm.set.rounding)
Fixes "Cannot select: set_rounding" for loongarch64. The rounding mode
encoding matches LoongArch FCSR hardware, so no translation is needed.
---
libc/shared/fp_bits.h | 2 +-
.../LoongArch/LoongArchISelLowering.cpp | 28 +++++++++++++++++++
.../Target/LoongArch/LoongArchISelLowering.h | 1 +
3 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/libc/shared/fp_bits.h b/libc/shared/fp_bits.h
index e6bb1e17b80c9..1a7544be7519d 100644
--- a/libc/shared/fp_bits.h
+++ b/libc/shared/fp_bits.h
@@ -1,4 +1,4 @@
-//===-- Floating point number utils -----------------------------*- C++ -*-===//
+comm//===-- Floating point number utils -----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 8748f4723339b..9438608fac82a 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -125,6 +125,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction({ISD::VAARG, ISD::VACOPY, ISD::VAEND}, MVT::Other, Expand);
+ setOperationAction(ISD::SET_ROUNDING, MVT::Other, Custom);
setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
setOperationAction(ISD::TRAP, MVT::Other, Legal);
@@ -613,6 +614,8 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
return lowerFRAMEADDR(Op, DAG);
case ISD::RETURNADDR:
return lowerRETURNADDR(Op, DAG);
+ case ISD::SET_ROUNDING:
+ return lowerSET_ROUNDING(Op, DAG);
case ISD::WRITE_REGISTER:
return lowerWRITE_REGISTER(Op, DAG);
case ISD::INSERT_VECTOR_ELT:
@@ -4015,6 +4018,31 @@ 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);
+
+ // Zero-extend i32 rounding mode to GRLenVT.
+ RMValue = DAG.getNode(ISD::ZERO_EXTEND, DL, GRLenVT, RMValue);
+
+ // The rounding mode in FCSR0 occupies bits 1:0.
+ // LLVM rounding mode encoding (0=RNE,1=RTZ,2=RDN,3=RUP) matches
+ // the LoongArch FCSR hardware encoding, so no translation needed.
+ // We 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).
+ SDValue FCSRNo = DAG.getTargetConstant(0, DL, GRLenVT); // FCSR0
+ MachineSDNode *RN = DAG.getMachineNode(LoongArch::WRFCSR, DL, MVT::Other,
+ FCSRNo, RMValue, Chain);
+ return SDValue(RN, 0);
+}
+
SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
SelectionDAG &DAG) const {
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 2f2eda1e2c7d9..8d9ec6020478b 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -236,6 +236,7 @@ class LoongArchTargetLowering : public TargetLowering {
SDValue lowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
+ SDValue lowerSET_ROUNDING(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerWRITE_REGISTER(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerINSERT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
>From 881f6eb14e7a14040e19ef93d4bbb960b0b5a256 Mon Sep 17 00:00:00 2001
From: tangyuan0821 <tangyuan0821 at email.cn>
Date: Mon, 22 Jun 2026 19:37:20 +0800
Subject: [PATCH 2/4] [libc] Fix corrupted header comment in fp_bits.h
---
libc/shared/fp_bits.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/shared/fp_bits.h b/libc/shared/fp_bits.h
index 1a7544be7519d..e6bb1e17b80c9 100644
--- a/libc/shared/fp_bits.h
+++ b/libc/shared/fp_bits.h
@@ -1,4 +1,4 @@
-comm//===-- Floating point number utils -----------------------------*- C++ -*-===//
+//===-- Floating point number utils -----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
>From 9e422ffc2d5619cd8a829b5ba0bc902388058338 Mon Sep 17 00:00:00 2001
From: tangyuan0821 <tangyuan0821 at email.cn>
Date: Mon, 22 Jun 2026 21:10:27 +0800
Subject: [PATCH 3/4] [LoongArch] Fix SET_ROUNDING lowering: use FCSR3, add
diagnostics, guard with hasBasicF()
---
.../LoongArch/LoongArchISelLowering.cpp | 24 ++++++++++++++-----
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 9438608fac82a..c95bfc5e5e7d9 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -125,7 +125,6 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction({ISD::VAARG, ISD::VACOPY, ISD::VAEND}, MVT::Other, Expand);
- setOperationAction(ISD::SET_ROUNDING, MVT::Other, Custom);
setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
setOperationAction(ISD::TRAP, MVT::Other, Legal);
@@ -256,6 +255,8 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::UINT_TO_FP, MVT::i64, Custom);
}
}
+
+ setOperationAction(ISD::SET_ROUNDING, MVT::Other, Custom);
}
// Set operations for 'D' feature.
@@ -4025,21 +4026,32 @@ SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
SDValue Chain = Op.getOperand(0);
SDValue RMValue = Op.getOperand(1);
+ // LLVM rounding mode encoding (0=RNE, 1=RTZ, 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);
- // The rounding mode in FCSR0 occupies bits 1:0.
- // LLVM rounding mode encoding (0=RNE,1=RTZ,2=RDN,3=RUP) matches
- // the LoongArch FCSR hardware encoding, so no translation needed.
+ // The rounding mode in FCSR occupies bits 1:0.
+ // LLVM rounding mode encoding matches the LoongArch FCSR hardware
+ // encoding, so no translation needed.
// We 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).
- SDValue FCSRNo = DAG.getTargetConstant(0, DL, GRLenVT); // FCSR0
+ // 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);
+ FCSRNo, RMValue, Chain);
return SDValue(RN, 0);
}
>From ce94bcc19bd8bdd88839bf4c2aa66b31d53fb554 Mon Sep 17 00:00:00 2001
From: tangyuan0821 <tangyuan0821 at email.cn>
Date: Tue, 23 Jun 2026 12:07:19 +0800
Subject: [PATCH 4/4] [LoongArch] Fix SET_ROUNDING encoding translation for
LLVM rounding modes
---
.../LoongArch/LoongArchISelLowering.cpp | 21 ++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index c95bfc5e5e7d9..62c0c7b4408ff 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -4026,7 +4026,7 @@ SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
SDValue Chain = Op.getOperand(0);
SDValue RMValue = Op.getOperand(1);
- // LLVM rounding mode encoding (0=RNE, 1=RTZ, 2=RUP, 3=RDN).
+ // 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) {
@@ -4038,10 +4038,21 @@ SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
// Zero-extend i32 rounding mode to GRLenVT.
RMValue = DAG.getNode(ISD::ZERO_EXTEND, DL, GRLenVT, RMValue);
- // The rounding mode in FCSR occupies bits 1:0.
- // LLVM rounding mode encoding matches the LoongArch FCSR hardware
- // encoding, so no translation needed.
- // We mask to 2 bits to guard against invalid values.
+ // 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));
More information about the libc-commits
mailing list