[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