[llvm] 2c4f60e - [FPEnv][AArch64] Implement lowering of llvm.set.rounding

Serge Pavlov via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 18 22:17:46 PST 2021


Author: Serge Pavlov
Date: 2021-02-19T13:16:51+07:00
New Revision: 2c4f60e45b3856d1a2d408f91db7432d4b7d9376

URL: https://github.com/llvm/llvm-project/commit/2c4f60e45b3856d1a2d408f91db7432d4b7d9376
DIFF: https://github.com/llvm/llvm-project/commit/2c4f60e45b3856d1a2d408f91db7432d4b7d9376.diff

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

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

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

Modified: 
    llvm/include/llvm/IR/IntrinsicsAArch64.td
    llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
    llvm/lib/Target/AArch64/AArch64ISelLowering.h
    llvm/lib/Target/AArch64/AArch64InstrInfo.td

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td
index de8553cc51a8..9ee478c485eb 100644
--- a/llvm/include/llvm/IR/IntrinsicsAArch64.td
+++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td
@@ -675,10 +675,13 @@ def int_aarch64_neon_tbx4 : AdvSIMD_Tbx4_Intrinsic;
 let TargetPrefix = "aarch64" in {
   class FPCR_Get_Intrinsic
     : DefaultAttrsIntrinsic<[llvm_i64_ty], [], [IntrNoMem, IntrHasSideEffects]>;
+  class FPCR_Set_Intrinsic
+    : DefaultAttrsIntrinsic<[], [llvm_i64_ty], [IntrNoMem, IntrHasSideEffects]>;
 }
 
 // FPCR
 def int_aarch64_get_fpcr : FPCR_Get_Intrinsic;
+def int_aarch64_set_fpcr : FPCR_Set_Intrinsic;
 
 let TargetPrefix = "aarch64" in {
   class Crypto_AES_DataKey_Intrinsic

diff  --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 624f89b780e9..036932d90f78 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -693,6 +693,7 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
   setOperationAction(ISD::PREFETCH, MVT::Other, Custom);
 
   setOperationAction(ISD::FLT_ROUNDS_, MVT::i32, Custom);
+  setOperationAction(ISD::SET_ROUNDING, MVT::Other, Custom);
 
   setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i128, Custom);
   setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i32, Custom);
@@ -3455,6 +3456,50 @@ SDValue AArch64TargetLowering::LowerFLT_ROUNDS_(SDValue Op,
   return DAG.getMergeValues({AND, Chain}, dl);
 }
 
+SDValue AArch64TargetLowering::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 FPCR.
+  // The llvm.set.rounding argument value to the rounding mode in FPCR mapping
+  // is 0->3, 1->0, 2->1, 3->2. The formula we use to implement this is
+  // ((arg - 1) & 3) << 22).
+  //
+  // The argument of llvm.set.rounding must be 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 FPCR[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(AArch64::RoundingBitsPos, DL, MVT::i32));
+  RMValue = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, RMValue);
+
+  // Get current value of FPCR.
+  SDValue Ops[] = {
+      Chain, DAG.getTargetConstant(Intrinsic::aarch64_get_fpcr, DL, MVT::i64)};
+  SDValue FPCR =
+      DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL, {MVT::i64, MVT::Other}, Ops);
+  Chain = FPCR.getValue(1);
+  FPCR = FPCR.getValue(0);
+
+  // Put new rounding mode into FPSCR[23:22].
+  const int RMMask = ~(AArch64::Rounding::rmMask << AArch64::RoundingBitsPos);
+  FPCR = DAG.getNode(ISD::AND, DL, MVT::i64, FPCR,
+                     DAG.getConstant(RMMask, DL, MVT::i64));
+  FPCR = DAG.getNode(ISD::OR, DL, MVT::i64, FPCR, RMValue);
+  SDValue Ops2[] = {
+      Chain, DAG.getTargetConstant(Intrinsic::aarch64_set_fpcr, DL, MVT::i64),
+      FPCR};
+  return DAG.getNode(ISD::INTRINSIC_VOID, DL, MVT::Other, Ops2);
+}
+
 SDValue AArch64TargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const {
   EVT VT = Op.getValueType();
 
@@ -4378,6 +4423,8 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
     return LowerFSINCOS(Op, DAG);
   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::INTRINSIC_WO_CHAIN:

diff  --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 8db2c232f360..94aef30b21b1 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -449,6 +449,21 @@ static inline bool isDef32(const SDNode &N) {
 
 } // end anonymous namespace
 
+namespace AArch64 {
+/// Possible values of current rounding mode, which is specified in bits
+/// 23:22 of FPCR.
+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 FPCR.
+const unsigned RoundingBitsPos = 22;
+} // namespace AArch64
+
 class AArch64Subtarget;
 class AArch64TargetMachine;
 
@@ -898,6 +913,7 @@ class AArch64TargetLowering : public TargetLowering {
   SDValue LowerSPONENTRY(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerFLT_ROUNDS_(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerSET_ROUNDING(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerINSERT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerSCALAR_TO_VECTOR(SDValue Op, SelectionDAG &DAG) const;

diff  --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 1876dee38837..e41da0cb657e 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -1247,6 +1247,7 @@ def : Pat<(readcyclecounter), (MRS 0xdce8)>;
 
 // FPCR register
 def : Pat<(i64 (int_aarch64_get_fpcr)), (MRS 0xda20)>;
+def : Pat<(int_aarch64_set_fpcr i64:$val), (MSR 0xda20, GPR64:$val)>;
 
 // Generic system instructions
 def SYSxt  : SystemXtI<0, "sys">;

diff  --git a/llvm/test/CodeGen/AArch64/fpenv.ll b/llvm/test/CodeGen/AArch64/fpenv.ll
new file mode 100644
index 000000000000..14bf7888918e
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/fpenv.ll
@@ -0,0 +1,70 @@
+; RUN: llc -mtriple=aarch64-none-linux-gnu %s -o - | FileCheck %s
+
+define void @func_02(i32 %rm) {
+  call void @llvm.set.rounding(i32 %rm)
+  ret void
+}
+
+; CHECK-LABEL: func_02:
+; CHECK:       sub   w9, w0, #1
+; CHECK:       mrs   x8, FPCR
+; CHECK:       and   w9, w9, #0x3
+; CHECK:       and   x8, x8, #0xffffffffff3fffff
+; CHECK:       lsl   w9, w9, #22
+; CHECK:       orr   x8, x8, x9
+; CHECK:       msr   FPCR, x8
+; CHECK:       ret
+
+
+define void @func_03() {
+  call void @llvm.set.rounding(i32 0)
+  ret void
+}
+
+; CHECK-LABEL: func_03
+; CHECK:       mrs   x8, FPCR
+; CHECK:       orr   x8, x8, #0xc00000
+; CHECK:       msr   FPCR, x8
+; CHECK:       ret
+
+
+define void @func_04() {
+  call void @llvm.set.rounding(i32 1)
+  ret void
+}
+
+; CHECK-LABEL: func_04
+; CHECK:       mrs   x8, FPCR
+; CHECK:       and   x8, x8, #0xffffffffff3fffff
+; CHECK:       msr   FPCR, x8
+; CHECK:       ret
+
+
+define void @func_05() {
+  call void @llvm.set.rounding(i32 2)
+  ret void
+}
+
+
+; CHECK-LABEL: func_05
+; CHECK:       mrs   x8, FPCR
+; CHECK:       and   x8, x8, #0xffffffffff3fffff
+; CHECK:       orr   x8, x8, #0x400000
+; CHECK:       msr   FPCR, x8
+; CHECK:       ret
+
+
+define void @func_06() {
+  call void @llvm.set.rounding(i32 3)
+  ret void
+}
+
+; CHECK-LABEL: func_06
+; CHECK:       mrs   x8, FPCR
+; CHECK:       and   x8, x8, #0xffffffffff3fffff
+; CHECK:       orr   x8, x8, #0x800000
+; CHECK:       msr   FPCR, x8
+; CHECK:       ret
+
+
+declare void @llvm.set.rounding(i32)


        


More information about the llvm-commits mailing list