[llvm] 93509a5 - [LoongArch] Support ISD::GET_ROUNDING (llvm.get.rounding) (#207319)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 6 23:59:39 PDT 2026
Author: Zhaoxin Yang
Date: 2026-07-07T14:59:34+08:00
New Revision: 93509a564b4dda593766f4395873175ede1a30ed
URL: https://github.com/llvm/llvm-project/commit/93509a564b4dda593766f4395873175ede1a30ed
DIFF: https://github.com/llvm/llvm-project/commit/93509a564b4dda593766f4395873175ede1a30ed.diff
LOG: [LoongArch] Support ISD::GET_ROUNDING (llvm.get.rounding) (#207319)
Added:
llvm/test/CodeGen/LoongArch/get-rounding.ll
Modified:
llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
llvm/lib/Target/LoongArch/LoongArchISelLowering.h
llvm/test/CodeGen/LoongArch/set-rounding.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 6bb3ff74e5c05..bdbfe6f0918d1 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -245,6 +245,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FP_TO_BF16, MVT::f32,
Subtarget.isSoftFPABI() ? LibCall : Custom);
setOperationAction(ISD::SET_ROUNDING, MVT::Other, Custom);
+ setOperationAction(ISD::GET_ROUNDING, GRLenVT, Custom);
if (Subtarget.is64Bit())
setOperationAction(ISD::FRINT, MVT::f32, Legal);
@@ -620,6 +621,8 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
return lowerRETURNADDR(Op, DAG);
case ISD::SET_ROUNDING:
return lowerSET_ROUNDING(Op, DAG);
+ case ISD::GET_ROUNDING:
+ return lowerGET_ROUNDING(Op, DAG);
case ISD::WRITE_REGISTER:
return lowerWRITE_REGISTER(Op, DAG);
case ISD::INSERT_VECTOR_ELT:
@@ -4026,6 +4029,28 @@ SDValue LoongArchTargetLowering::lowerATOMIC_FENCE(SDValue Op,
return Op;
}
+static SDValue convertRMEncoding(SelectionDAG &DAG, const SDLoc &DL,
+ MVT GRLenVT, SDValue RMValue) {
+ // LLVM rounding mode encoding
diff ers from LoongArch FCSR encoding:
+ // LLVM: 0=RTZ, 1=RNE, 2=RUP, 3=RDN
+ // FCSR: 0=RNE, 1=RZ, 2=RP, 3=RN
+ //
+ // The conversion swaps encodings 0 and 1 while preserving 2 and 3.
+ // Since the transformation is self-inverse, it applies in both directions:
+ // LLVM RM <-> LoongArch FCSR RM
+ //
+ // 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));
+
+ return DAG.getNode(ISD::XOR, DL, GRLenVT, RMValue, SwapMask);
+}
+
SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
SelectionDAG &DAG) const {
MVT GRLenVT = Subtarget.getGRLenVT();
@@ -4046,29 +4071,8 @@ SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
}
}
- RMValue = DAG.getNode(ISD::ZERO_EXTEND, DL, GRLenVT, RMValue);
-
- // LLVM rounding mode encoding
diff ers from LoongArch FCSR encoding:
- // LLVM: 0=RTZ, 1=RNE, 2=RUP, 3=RDN
- // FCSR: 0=RNE, 1=RZ, 2=RP, 3=RN
- //
- // Need to convert argument into bits of control word:
- // 0 Round to 0 -> 01
- // 1 Round to nearest -> 00
- // 2 Round to +inf -> 10
- // 3 Round to -inf -> 11
- //
- // 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);
-
- RMValue = DAG.getNode(ISD::AND, DL, GRLenVT, RMValue,
- DAG.getConstant(0x3, DL, GRLenVT));
+ RMValue = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, RMValue);
+ RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
// The RM field in FCSR is at bits [9:8]. Shift the rounding mode value
// into position before writing via WRFCSR.
@@ -4083,6 +4087,28 @@ SDValue LoongArchTargetLowering::lowerSET_ROUNDING(SDValue Op,
return SDValue(RN, 0);
}
+SDValue LoongArchTargetLowering::lowerGET_ROUNDING(SDValue Op,
+ SelectionDAG &DAG) const {
+ MVT GRLenVT = Subtarget.getGRLenVT();
+ SDLoc DL(Op);
+ SDValue Chain = Op->getOperand(0);
+
+ // FCSR3 is an alias of the RM field.
+ SDValue FCSRNo = DAG.getTargetConstant(3, DL, GRLenVT);
+ MachineSDNode *FCSR = DAG.getMachineNode(LoongArch::RDFCSR, DL, GRLenVT,
+ MVT::Other, FCSRNo, Chain);
+ SDValue RMValue = SDValue(FCSR, 0);
+ Chain = SDValue(FCSR, 1);
+
+ // The RM field in FCSR is at bits [9:8].
+ RMValue = DAG.getNode(ISD::SRL, DL, GRLenVT, RMValue,
+ DAG.getConstant(8, DL, GRLenVT));
+ RMValue = convertRMEncoding(DAG, DL, GRLenVT, RMValue);
+
+ SDValue RetVal = DAG.getZExtOrTrunc(RMValue, DL, Op.getValueType());
+ return DAG.getMergeValues({RetVal, Chain}, DL);
+}
+
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 8d9ec6020478b..f9d7832962894 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -237,6 +237,7 @@ class LoongArchTargetLowering : public TargetLowering {
SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerSET_ROUNDING(SDValue Op, SelectionDAG &DAG) const;
+ SDValue lowerGET_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;
diff --git a/llvm/test/CodeGen/LoongArch/get-rounding.ll b/llvm/test/CodeGen/LoongArch/get-rounding.ll
new file mode 100644
index 0000000000000..6329b48ce27df
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/get-rounding.ll
@@ -0,0 +1,112 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc --mtriple=loongarch32 -mattr=+f < %s | FileCheck %s --check-prefix=LA32
+; RUN: llc --mtriple=loongarch64 -mattr=+f < %s | FileCheck %s --check-prefix=LA64
+
+define i32 @test_get_rounding() nounwind {
+; LA32-LABEL: test_get_rounding:
+; LA32: # %bb.0:
+; LA32-NEXT: movfcsr2gr $a0, $fcsr3
+; LA32-NEXT: srli.w $a0, $a0, 8
+; LA32-NEXT: nor $a1, $a0, $zero
+; LA32-NEXT: srli.w $a1, $a1, 1
+; LA32-NEXT: andi $a1, $a1, 1
+; LA32-NEXT: xor $a0, $a0, $a1
+; LA32-NEXT: ret
+;
+; LA64-LABEL: test_get_rounding:
+; LA64: # %bb.0:
+; LA64-NEXT: movfcsr2gr $a0, $fcsr3
+; LA64-NEXT: srli.d $a0, $a0, 8
+; LA64-NEXT: nor $a1, $a0, $zero
+; LA64-NEXT: bstrpick.d $a1, $a1, 1, 1
+; LA64-NEXT: xor $a0, $a0, $a1
+; LA64-NEXT: ret
+ %rm = call i32 @llvm.get.rounding()
+ ret i32 %rm
+}
+
+define i1 @test_get_rounding_sideeffect() nounwind {
+; LA32-LABEL: test_get_rounding_sideeffect:
+; LA32: # %bb.0: # %entry
+; LA32-NEXT: addi.w $sp, $sp, -16
+; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32-NEXT: ori $a0, $zero, 1
+; LA32-NEXT: bl fesetround
+; LA32-NEXT: movfcsr2gr $a0, $fcsr3
+; LA32-NEXT: srli.w $a0, $a0, 8
+; LA32-NEXT: nor $a1, $a0, $zero
+; LA32-NEXT: srli.w $a1, $a1, 1
+; LA32-NEXT: andi $a1, $a1, 1
+; LA32-NEXT: xor $a0, $a0, $a1
+; LA32-NEXT: beq $a0, $zero, .LBB1_2
+; LA32-NEXT: # %bb.1:
+; LA32-NEXT: move $a0, $zero
+; LA32-NEXT: b .LBB1_3
+; LA32-NEXT: .LBB1_2: # %if.end
+; LA32-NEXT: move $a0, $zero
+; LA32-NEXT: bl fesetround
+; LA32-NEXT: movfcsr2gr $a0, $fcsr3
+; LA32-NEXT: srli.w $a0, $a0, 8
+; LA32-NEXT: nor $a1, $a0, $zero
+; LA32-NEXT: srli.w $a1, $a1, 1
+; LA32-NEXT: andi $a1, $a1, 1
+; LA32-NEXT: xor $a0, $a0, $a1
+; LA32-NEXT: addi.w $a0, $a0, -1
+; LA32-NEXT: sltui $a0, $a0, 1
+; LA32-NEXT: .LBB1_3: # %return
+; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32-NEXT: addi.w $sp, $sp, 16
+; LA32-NEXT: ret
+;
+; LA64-LABEL: test_get_rounding_sideeffect:
+; LA64: # %bb.0: # %entry
+; LA64-NEXT: addi.d $sp, $sp, -16
+; LA64-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64-NEXT: ori $a0, $zero, 1
+; LA64-NEXT: pcaddu18i $ra, %call36(fesetround)
+; LA64-NEXT: jirl $ra, $ra, 0
+; LA64-NEXT: movfcsr2gr $a0, $fcsr3
+; LA64-NEXT: srli.d $a0, $a0, 8
+; LA64-NEXT: nor $a1, $a0, $zero
+; LA64-NEXT: bstrpick.d $a1, $a1, 1, 1
+; LA64-NEXT: xor $a0, $a0, $a1
+; LA64-NEXT: addi.w $a0, $a0, 0
+; LA64-NEXT: beqz $a0, .LBB1_2
+; LA64-NEXT: # %bb.1:
+; LA64-NEXT: move $a0, $zero
+; LA64-NEXT: b .LBB1_3
+; LA64-NEXT: .LBB1_2: # %if.end
+; LA64-NEXT: move $a0, $zero
+; LA64-NEXT: pcaddu18i $ra, %call36(fesetround)
+; LA64-NEXT: jirl $ra, $ra, 0
+; LA64-NEXT: movfcsr2gr $a0, $fcsr3
+; LA64-NEXT: srli.d $a0, $a0, 8
+; LA64-NEXT: nor $a1, $a0, $zero
+; LA64-NEXT: bstrpick.d $a1, $a1, 1, 1
+; LA64-NEXT: xor $a0, $a0, $a1
+; LA64-NEXT: addi.w $a0, $a0, 0
+; LA64-NEXT: addi.d $a0, $a0, -1
+; LA64-NEXT: sltui $a0, $a0, 1
+; LA64-NEXT: .LBB1_3: # %return
+; LA64-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64-NEXT: addi.d $sp, $sp, 16
+; LA64-NEXT: ret
+entry:
+ %call = tail call i32 @fesetround(i32 noundef 1)
+ %0 = tail call i32 @llvm.get.rounding()
+ %cmp.not = icmp eq i32 %0, 0
+ br i1 %cmp.not, label %if.end, label %return
+
+if.end:
+ %call1 = tail call i32 @fesetround(i32 noundef 0)
+ %1 = tail call i32 @llvm.get.rounding()
+ %cmp2.not = icmp eq i32 %1, 1
+ br label %return
+
+return:
+ %retval.0 = phi i1 [ false, %entry ], [ %cmp2.not, %if.end ]
+ ret i1 %retval.0
+}
+
+declare i32 @llvm.get.rounding()
+declare i32 @fesetround(i32 noundef)
diff --git a/llvm/test/CodeGen/LoongArch/set-rounding.ll b/llvm/test/CodeGen/LoongArch/set-rounding.ll
index bdbcf461c382b..2da7961c68959 100644
--- a/llvm/test/CodeGen/LoongArch/set-rounding.ll
+++ b/llvm/test/CodeGen/LoongArch/set-rounding.ll
@@ -54,17 +54,16 @@ define void @set_rounding_dynamic(i32 %rm) nounwind {
; LA32-NEXT: srli.w $a1, $a1, 1
; LA32-NEXT: andi $a1, $a1, 1
; LA32-NEXT: xor $a0, $a0, $a1
-; LA32-NEXT: andi $a0, $a0, 3
; LA32-NEXT: slli.w $a0, $a0, 8
; LA32-NEXT: movgr2fcsr $fcsr3, $a0
; LA32-NEXT: ret
;
; LA64-LABEL: set_rounding_dynamic:
; LA64: # %bb.0:
-; LA64-NEXT: nor $a1, $a0, $zero
-; LA64-NEXT: bstrpick.d $a1, $a1, 1, 1
-; LA64-NEXT: xor $a0, $a0, $a1
-; LA64-NEXT: andi $a0, $a0, 3
+; LA64-NEXT: bstrpick.d $a1, $a0, 31, 0
+; LA64-NEXT: nor $a0, $a0, $zero
+; LA64-NEXT: bstrpick.d $a0, $a0, 1, 1
+; LA64-NEXT: xor $a0, $a1, $a0
; LA64-NEXT: slli.d $a0, $a0, 8
; LA64-NEXT: movgr2fcsr $fcsr3, $a0
; LA64-NEXT: ret
More information about the llvm-commits
mailing list