[llvm] 816053b - [FPEnv][ARM] Implement lowering of llvm.set.rounding

Serge Pavlov via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 12 20:17:34 PST 2021


Author: Serge Pavlov
Date: 2021-02-13T11:16:29+07:00
New Revision: 816053bc71751cac46aef085f57b7f305c7bbcd1

URL: https://github.com/llvm/llvm-project/commit/816053bc71751cac46aef085f57b7f305c7bbcd1
DIFF: https://github.com/llvm/llvm-project/commit/816053bc71751cac46aef085f57b7f305c7bbcd1.diff

LOG: [FPEnv][ARM] Implement lowering of llvm.set.rounding

Differential Revision: https://reviews.llvm.org/D96501

Added: 
    llvm/test/CodeGen/ARM/fpenv.ll

Modified: 
    llvm/lib/Target/ARM/ARMISelLowering.cpp
    llvm/lib/Target/ARM/ARMISelLowering.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index a2613b060d98..338eb5ce7e62 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -1343,6 +1343,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
     // iff target supports vfp2.
     setOperationAction(ISD::BITCAST, MVT::i64, Custom);
     setOperationAction(ISD::FLT_ROUNDS_, MVT::i32, Custom);
+    setOperationAction(ISD::SET_ROUNDING, MVT::Other, Custom);
   }
 
   // We want to custom lower some of our intrinsics.
@@ -6118,6 +6119,48 @@ SDValue ARMTargetLowering::LowerFLT_ROUNDS_(SDValue Op,
   return DAG.getMergeValues({And, Chain}, dl);
 }
 
+SDValue ARMTargetLowering::LowerSET_ROUNDING(SDValue Op,
+                                             SelectionDAG &DAG) const {
+  SDLoc DL(Op);
+  SDValue Chain = Op->getOperand(0);
+  SDValue RMValue = Op->getOperand(1);
+
+  // The rounding mode is in bits 23:22 of the FPSCR.
+  // The llvm.set.rounding argument value to ARM rounding mode value mapping
+  // is 0->3, 1->0, 2->1, 3->2. The formula we use to implement this is
+  // ((arg - 1) & 3) << 22).
+  //
+  // It is expected that the argument of llvm.set.rounding is within the
+  // segment [0, 3], so NearestTiesToAway (4) is not handled here. It is
+  // responsibility of the code generated llvm.set.rounding to ensure this
+  // condition.
+
+  // Calculate new value of FPSCR[23:22].
+  RMValue = DAG.getNode(ISD::SUB, DL, MVT::i32, RMValue,
+                        DAG.getConstant(1, DL, MVT::i32));
+  RMValue = DAG.getNode(ISD::AND, DL, MVT::i32, RMValue,
+                        DAG.getConstant(0x3, DL, MVT::i32));
+  RMValue = DAG.getNode(ISD::SHL, DL, MVT::i32, RMValue,
+                        DAG.getConstant(ARM::RoundingBitsPos, DL, MVT::i32));
+
+  // Get current value of FPSCR.
+  SDValue Ops[] = {Chain,
+                   DAG.getConstant(Intrinsic::arm_get_fpscr, DL, MVT::i32)};
+  SDValue FPSCR =
+      DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL, {MVT::i32, MVT::Other}, Ops);
+  Chain = FPSCR.getValue(1);
+  FPSCR = FPSCR.getValue(0);
+
+  // Put new rounding mode into FPSCR[23:22].
+  const unsigned RMMask = ~(ARM::Rounding::rmMask << ARM::RoundingBitsPos);
+  FPSCR = DAG.getNode(ISD::AND, DL, MVT::i32, FPSCR,
+                      DAG.getConstant(RMMask, DL, MVT::i32));
+  FPSCR = DAG.getNode(ISD::OR, DL, MVT::i32, FPSCR, RMValue);
+  SDValue Ops2[] = {
+      Chain, DAG.getConstant(Intrinsic::arm_set_fpscr, DL, MVT::i32), FPSCR};
+  return DAG.getNode(ISD::INTRINSIC_VOID, DL, MVT::Other, Ops2);
+}
+
 static SDValue LowerCTTZ(SDNode *N, SelectionDAG &DAG,
                          const ARMSubtarget *ST) {
   SDLoc dl(N);
@@ -9849,6 +9892,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   case ISD::CONCAT_VECTORS: return LowerCONCAT_VECTORS(Op, DAG, Subtarget);
   case ISD::TRUNCATE:      return LowerTruncatei1(Op, DAG, Subtarget);
   case ISD::FLT_ROUNDS_:   return LowerFLT_ROUNDS_(Op, DAG);
+  case ISD::SET_ROUNDING:  return LowerSET_ROUNDING(Op, DAG);
   case ISD::MUL:           return LowerMUL(Op, DAG);
   case ISD::SDIV:
     if (Subtarget->isTargetWindows() && !Op.getValueType().isVector())

diff  --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h
index 8d9b703bbddf..87b9878862f8 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -332,6 +332,21 @@ class VectorType;
 
   } // end namespace ARMISD
 
+  namespace ARM {
+  /// Possible values of current rounding mode, which is specified in bits
+  /// 23:22 of FPSCR.
+  enum Rounding {
+    RN = 0,    // Round to Nearest
+    RP = 1,    // Round towards Plus infinity
+    RM = 2,    // Round towards Minus infinity
+    RZ = 3,    // Round towards Zero
+    rmMask = 3 // Bit mask selecting rounding mode
+  };
+
+  // Bit position of rounding mode bits in FPSCR.
+  const unsigned RoundingBitsPos = 22;
+  } // namespace ARM
+
   /// Define some predicates that are used for node matching.
   namespace ARM {
 
@@ -767,6 +782,7 @@ class VectorType;
     SDValue LowerShiftRightParts(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerFLT_ROUNDS_(SDValue Op, SelectionDAG &DAG) const;
+    SDValue LowerSET_ROUNDING(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerConstantFP(SDValue Op, SelectionDAG &DAG,
                             const ARMSubtarget *ST) const;
     SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG,

diff  --git a/llvm/test/CodeGen/ARM/fpenv.ll b/llvm/test/CodeGen/ARM/fpenv.ll
new file mode 100644
index 000000000000..30562cf89111
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/fpenv.ll
@@ -0,0 +1,69 @@
+; RUN: llc -mtriple=arm-eabi -float-abi=soft -mattr=+vfp2 %s -o - | FileCheck %s
+
+define void @func_02(i32 %rm) {
+  call void @llvm.set.rounding(i32 %rm)
+  ret void
+}
+
+; CHECK-LABEL: func_02:
+; CHECK:       vmrs  r1, fpscr
+; CHECK:       sub   r0, r0, #1
+; CHECK:       and   r0, r0, #3
+; CHECK:       bic   r1, r1, #12582912
+; CHECK:       orr   r0, r1, r0, lsl #22
+; CHECK:       vmsr  fpscr, r0
+; CHECK:       mov   pc, lr
+
+
+define void @func_03() {
+  call void @llvm.set.rounding(i32 0)
+  ret void
+}
+
+; CHECK-LABEL: func_03
+; CHECK:       vmrs  r0, fpscr
+; CHECK:       orr   r0, r0, #12582912
+; CHECK:       vmsr  fpscr, r0
+; CHECK:       mov   pc, lr
+
+
+define void @func_04() {
+  call void @llvm.set.rounding(i32 1)
+  ret void
+}
+
+; CHECK-LABEL: func_04
+; CHECK:       vmrs    r0, fpscr
+; CHECK:       bic     r0, r0, #12582912
+; CHECK:       vmsr    fpscr, r0
+; CHECK:       mov     pc, lr
+
+
+define void @func_05() {
+  call void @llvm.set.rounding(i32 2)
+  ret void
+}
+
+
+; CHECK-LABEL: func_05
+; CHECK:       vmrs    r0, fpscr
+; CHECK:       bic     r0, r0, #12582912
+; CHECK:       orr     r0, r0, #4194304
+; CHECK:       vmsr    fpscr, r0
+; CHECK:       mov     pc, lr
+
+
+define void @func_06() {
+  call void @llvm.set.rounding(i32 3)
+  ret void
+}
+
+; CHECK-LABEL: func_06
+; CHECK:       vmrs   r0, fpscr
+; CHECK:       bic    r0, r0, #12582912
+; CHECK:       orr    r0, r0, #8388608
+; CHECK:       vmsr   fpscr, r0
+; CHECK:       mov    pc, lr
+
+
+declare void @llvm.set.rounding(i32)


        


More information about the llvm-commits mailing list