[llvm] [LLVM][CodeGen][SVE] Add lowering for single type constrained operations. (PR #215232)

via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 10 03:10:47 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: Paul Walker (paulwalker-arm)

<details>
<summary>Changes</summary>

This formalises a long standing requirement of SVE instructions selection to not introduce new faulting behaviour. This is why the strict and non-strict ops are combined to the existing ops (e.g. AArch64fadd_p). That means other than not crashing when trying to select these constrained operations the PR is NFC like.  Following work will relax patterns that are currently restricted to all-active predicates by using the new _nonstrict ops that have no no-new-faults requirement.

NOTE: Excludes bfloat16 support because most lowerings require cast operations.

NOTE: Streaming mode has a different fp environment, specifically FP exceptions are disabled, but given things like rounding modes are still in play I figure it makes sense to match the non-streaming mode lowering.

---

Patch is 60.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/215232.diff


3 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+114-37) 
- (modified) llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td (+39-16) 
- (added) llvm/test/CodeGen/AArch64/sve-fp-constrained-intrinsics.ll (+1084) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index b01dc35531f4b..6c9627ee7711a 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -364,6 +364,13 @@ static bool isMergePassthruOpcode(unsigned Opc) {
   case AArch64ISD::FSQRT_MERGE_PASSTHRU:
   case AArch64ISD::FRECPX_MERGE_PASSTHRU:
   case AArch64ISD::FABS_MERGE_PASSTHRU:
+  case AArch64ISD::STRICT_FCEIL_MERGE_PASSTHRU:
+  case AArch64ISD::STRICT_FFLOOR_MERGE_PASSTHRU:
+  case AArch64ISD::STRICT_FNEARBYINT_MERGE_PASSTHRU:
+  case AArch64ISD::STRICT_FROUND_MERGE_PASSTHRU:
+  case AArch64ISD::STRICT_FROUNDEVEN_MERGE_PASSTHRU:
+  case AArch64ISD::STRICT_FTRUNC_MERGE_PASSTHRU:
+  case AArch64ISD::STRICT_FSQRT_MERGE_PASSTHRU:
     return true;
   }
 }
@@ -1826,30 +1833,30 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
       setOperationAction(ISD::SPLAT_VECTOR, VT, Legal);
       setOperationAction(ISD::SELECT, VT, Custom);
       setOperationAction(ISD::SETCC, VT, Custom);
-      setOperationAction(ISD::FADD, VT, Custom);
+      setOperationAction({ISD::FADD, ISD::STRICT_FADD}, VT, Custom);
       setOperationAction(ISD::FCANONICALIZE, VT, Custom);
       setOperationAction(ISD::FCOPYSIGN, VT, Custom);
-      setOperationAction(ISD::FDIV, VT, Custom);
-      setOperationAction(ISD::FMA, VT, Custom);
-      setOperationAction(ISD::FMAXIMUM, VT, Custom);
-      setOperationAction(ISD::FMAXNUM, VT, Custom);
+      setOperationAction({ISD::FDIV, ISD::STRICT_FDIV}, VT, Custom);
+      setOperationAction({ISD::FMA, ISD::STRICT_FMA}, VT, Custom);
+      setOperationAction({ISD::FMAXIMUM, ISD::STRICT_FMAXIMUM}, VT, Custom);
+      setOperationAction({ISD::FMAXNUM, ISD::STRICT_FMAXNUM}, VT, Custom);
       setOperationAction(ISD::FMAXNUM_IEEE, VT, Custom);
-      setOperationAction(ISD::FMINIMUM, VT, Custom);
-      setOperationAction(ISD::FMINNUM, VT, Custom);
+      setOperationAction({ISD::FMINIMUM, ISD::STRICT_FMINIMUM}, VT, Custom);
+      setOperationAction({ISD::FMINNUM, ISD::STRICT_FMINNUM}, VT, Custom);
       setOperationAction(ISD::FMINNUM_IEEE, VT, Custom);
-      setOperationAction(ISD::FMUL, VT, Custom);
+      setOperationAction({ISD::FMUL, ISD::STRICT_FMUL}, VT, Custom);
       setOperationAction(ISD::FNEG, VT, Custom);
-      setOperationAction(ISD::FSUB, VT, Custom);
-      setOperationAction(ISD::FCEIL, VT, Custom);
-      setOperationAction(ISD::FFLOOR, VT, Custom);
-      setOperationAction(ISD::FNEARBYINT, VT, Custom);
+      setOperationAction({ISD::FSUB, ISD::STRICT_FSUB}, VT, Custom);
+      setOperationAction({ISD::FCEIL, ISD::STRICT_FCEIL}, VT, Custom);
+      setOperationAction({ISD::FFLOOR, ISD::STRICT_FFLOOR}, VT, Custom);
+      setOperationAction({ISD::FNEARBYINT, ISD::STRICT_FNEARBYINT}, VT, Custom);
       setOperationAction(ISD::FRINT, VT, Custom);
       setOperationAction(ISD::LRINT, VT, Custom);
       setOperationAction(ISD::LLRINT, VT, Custom);
-      setOperationAction(ISD::FROUND, VT, Custom);
-      setOperationAction(ISD::FROUNDEVEN, VT, Custom);
-      setOperationAction(ISD::FTRUNC, VT, Custom);
-      setOperationAction(ISD::FSQRT, VT, Custom);
+      setOperationAction({ISD::FROUND, ISD::STRICT_FROUND}, VT, Custom);
+      setOperationAction({ISD::FROUNDEVEN, ISD::STRICT_FROUNDEVEN}, VT, Custom);
+      setOperationAction({ISD::FTRUNC, ISD::STRICT_FTRUNC}, VT, Custom);
+      setOperationAction({ISD::FSQRT, ISD::STRICT_FSQRT}, VT, Custom);
       setOperationAction(ISD::FABS, VT, Custom);
       setOperationAction(ISD::FP_EXTEND, VT, Custom);
       setOperationAction(ISD::FP_ROUND, VT, Custom);
@@ -1865,27 +1872,45 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
       setOperationAction(ISD::VECTOR_INTERLEAVE, VT, Custom);
 
       setOperationAction(ISD::SELECT_CC, VT, Expand);
-      setOperationAction(ISD::FREM, VT, Expand);
-      setOperationAction(ISD::FPOW, VT, Expand);
-      setOperationAction(ISD::FPOWI, VT, Expand);
+      setOperationAction({ISD::FREM, ISD::STRICT_FREM}, VT, Expand);
+      setOperationAction({ISD::FPOW, ISD::STRICT_FPOW}, VT, Expand);
+      setOperationAction({ISD::FPOWI, ISD::STRICT_FPOWI}, VT, Expand);
       setOperationAction(ISD::FCBRT, VT, Expand);
-      setOperationAction(ISD::FCOS, VT, Expand);
-      setOperationAction(ISD::FSIN, VT, Expand);
+      setOperationAction({ISD::FCOS, ISD::STRICT_FCOS}, VT, Expand);
+      setOperationAction({ISD::FSIN, ISD::STRICT_FSIN}, VT, Expand);
       setOperationAction(ISD::FSINCOS, VT, Expand);
-      setOperationAction(ISD::FTAN, VT, Expand);
-      setOperationAction(ISD::FACOS, VT, Expand);
-      setOperationAction(ISD::FASIN, VT, Expand);
-      setOperationAction(ISD::FATAN, VT, Expand);
-      setOperationAction(ISD::FATAN2, VT, Expand);
-      setOperationAction(ISD::FCOSH, VT, Expand);
-      setOperationAction(ISD::FSINH, VT, Expand);
-      setOperationAction(ISD::FTANH, VT, Expand);
-      setOperationAction(ISD::FEXP, VT, Expand);
-      setOperationAction(ISD::FEXP2, VT, Expand);
+      setOperationAction({ISD::FTAN, ISD::STRICT_FTAN}, VT, Expand);
+      setOperationAction({ISD::FACOS, ISD::STRICT_FACOS}, VT, Expand);
+      setOperationAction({ISD::FASIN, ISD::STRICT_FASIN}, VT, Expand);
+      setOperationAction({ISD::FATAN, ISD::STRICT_FATAN}, VT, Expand);
+      setOperationAction({ISD::FATAN2, ISD::STRICT_FATAN2}, VT, Expand);
+      setOperationAction({ISD::FCOSH, ISD::STRICT_FCOSH}, VT, Expand);
+      setOperationAction({ISD::FSINH, ISD::STRICT_FSINH}, VT, Expand);
+      setOperationAction({ISD::FTANH, ISD::STRICT_FTANH}, VT, Expand);
+      setOperationAction({ISD::FEXP, ISD::STRICT_FEXP}, VT, Expand);
+      setOperationAction({ISD::FEXP2, ISD::STRICT_FEXP2}, VT, Expand);
       setOperationAction(ISD::FEXP10, VT, Expand);
-      setOperationAction(ISD::FLOG, VT, Expand);
-      setOperationAction(ISD::FLOG2, VT, Expand);
-      setOperationAction(ISD::FLOG10, VT, Expand);
+      setOperationAction({ISD::FLOG, ISD::STRICT_FLOG}, VT, Expand);
+      setOperationAction({ISD::FLOG2, ISD::STRICT_FLOG2}, VT, Expand);
+      setOperationAction({ISD::FLOG10, ISD::STRICT_FLOG10}, VT, Expand);
+
+      // TODO: These require custom lowering.
+      setOperationAction(ISD::STRICT_FLDEXP, VT, Expand);
+      setOperationAction(ISD::STRICT_FRINT, VT, Expand);
+      setOperationAction(ISD::STRICT_PSEUDO_FMIN, VT, Expand);
+      setOperationAction(ISD::STRICT_PSEUDO_FMAX, VT, Expand);
+      setOperationAction(ISD::STRICT_LROUND, VT, Expand);
+      setOperationAction(ISD::STRICT_LLROUND, VT, Expand);
+      setOperationAction(ISD::STRICT_LRINT, VT, Expand);
+      setOperationAction(ISD::STRICT_LLRINT, VT, Expand);
+      setOperationAction(ISD::STRICT_FP_TO_SINT, VT, Expand);
+      setOperationAction(ISD::STRICT_FP_TO_UINT, VT, Expand);
+      setOperationAction(ISD::STRICT_SINT_TO_FP, VT, Expand);
+      setOperationAction(ISD::STRICT_UINT_TO_FP, VT, Expand);
+      setOperationAction(ISD::STRICT_FP_ROUND, VT, Expand);
+      setOperationAction(ISD::STRICT_FP_EXTEND, VT, Expand);
+      setOperationAction(ISD::STRICT_FSETCC, VT, Expand);
+      setOperationAction(ISD::STRICT_FSETCCS, VT, Expand);
 
       setCondCodeAction(ISD::SETO, VT, Expand);
       setCondCodeAction(ISD::SETOLT, VT, Expand);
@@ -8595,32 +8620,63 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
     return LowerXALUO(Op, DAG);
   case ISD::FADD:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FADD_PRED);
+  case ISD::STRICT_FADD:
+    return LowerToPredicatedOp(Op, DAG, AArch64ISD::STRICT_FADD_PRED);
   case ISD::FSUB:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FSUB_PRED);
+  case ISD::STRICT_FSUB:
+    return LowerToPredicatedOp(Op, DAG, AArch64ISD::STRICT_FSUB_PRED);
   case ISD::FMUL:
     return LowerFMUL(Op, DAG);
+  case ISD::STRICT_FMUL:
+    return LowerToPredicatedOp(Op, DAG, AArch64ISD::STRICT_FMUL_PRED);
   case ISD::FMA:
     return LowerFMA(Op, DAG);
+  case ISD::STRICT_FMA:
+    return LowerToPredicatedOp(Op, DAG, AArch64ISD::STRICT_FMA_PRED);
   case ISD::FDIV:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FDIV_PRED);
+  case ISD::STRICT_FDIV:
+    return LowerToPredicatedOp(Op, DAG, AArch64ISD::STRICT_FDIV_PRED);
   case ISD::FNEG:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FNEG_MERGE_PASSTHRU);
   case ISD::FCEIL:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FCEIL_MERGE_PASSTHRU);
+  case ISD::STRICT_FCEIL:
+    return LowerToPredicatedOp(Op, DAG,
+                               AArch64ISD::STRICT_FCEIL_MERGE_PASSTHRU);
   case ISD::FFLOOR:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FFLOOR_MERGE_PASSTHRU);
+  case ISD::STRICT_FFLOOR:
+    return LowerToPredicatedOp(Op, DAG,
+                               AArch64ISD::STRICT_FFLOOR_MERGE_PASSTHRU);
   case ISD::FNEARBYINT:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FNEARBYINT_MERGE_PASSTHRU);
+  case ISD::STRICT_FNEARBYINT:
+    return LowerToPredicatedOp(Op, DAG,
+                               AArch64ISD::STRICT_FNEARBYINT_MERGE_PASSTHRU);
   case ISD::FRINT:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FRINT_MERGE_PASSTHRU);
   case ISD::FROUND:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FROUND_MERGE_PASSTHRU);
+  case ISD::STRICT_FROUND:
+    return LowerToPredicatedOp(Op, DAG,
+                               AArch64ISD::STRICT_FROUND_MERGE_PASSTHRU);
   case ISD::FROUNDEVEN:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FROUNDEVEN_MERGE_PASSTHRU);
+  case ISD::STRICT_FROUNDEVEN:
+    return LowerToPredicatedOp(Op, DAG,
+                               AArch64ISD::STRICT_FROUNDEVEN_MERGE_PASSTHRU);
   case ISD::FTRUNC:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FTRUNC_MERGE_PASSTHRU);
+  case ISD::STRICT_FTRUNC:
+    return LowerToPredicatedOp(Op, DAG,
+                               AArch64ISD::STRICT_FTRUNC_MERGE_PASSTHRU);
   case ISD::FSQRT:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FSQRT_MERGE_PASSTHRU);
+  case ISD::STRICT_FSQRT:
+    return LowerToPredicatedOp(Op, DAG,
+                               AArch64ISD::STRICT_FSQRT_MERGE_PASSTHRU);
   case ISD::FABS:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FABS_MERGE_PASSTHRU);
   case ISD::FP_ROUND:
@@ -8795,14 +8851,22 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
     return LowerToScalableOp(Op, DAG);
   case ISD::FMAXIMUM:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FMAX_PRED);
+  case ISD::STRICT_FMAXIMUM:
+    return LowerToPredicatedOp(Op, DAG, AArch64ISD::STRICT_FMAX_PRED);
   case ISD::FMAXNUM:
   case ISD::FMAXNUM_IEEE:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FMAXNM_PRED);
+  case ISD::STRICT_FMAXNUM:
+    return LowerToPredicatedOp(Op, DAG, AArch64ISD::STRICT_FMAXNM_PRED);
   case ISD::FMINIMUM:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FMIN_PRED);
+  case ISD::STRICT_FMINIMUM:
+    return LowerToPredicatedOp(Op, DAG, AArch64ISD::STRICT_FMIN_PRED);
   case ISD::FMINNUM:
   case ISD::FMINNUM_IEEE:
     return LowerToPredicatedOp(Op, DAG, AArch64ISD::FMINNM_PRED);
+  case ISD::STRICT_FMINNUM:
+    return LowerToPredicatedOp(Op, DAG, AArch64ISD::STRICT_FMINNM_PRED);
   case ISD::VSELECT:
     return LowerFixedLengthVectorSelectToSVE(Op, DAG);
   case ISD::ABS:
@@ -33923,6 +33987,9 @@ SDValue AArch64TargetLowering::LowerToPredicatedOp(SDValue Op,
   SDLoc DL(Op);
   auto Pg = getPredicateForVector(DAG, DL, VT);
 
+  bool IsStrictFP = Op->isStrictFPOpcode();
+  unsigned OpStartIdx = IsStrictFP ? 1 : 0;
+
   if (VT.isFixedLengthVector()) {
     assert(isTypeLegal(VT) && "Expected only legal fixed-width types");
     EVT ContainerVT = getContainerForFixedLengthVector(DAG, VT);
@@ -33957,8 +34024,18 @@ SDValue AArch64TargetLowering::LowerToPredicatedOp(SDValue Op,
 
   assert(VT.isScalableVector() && "Only expect to lower scalable vector op!");
 
-  SmallVector<SDValue, 4> Operands = {Pg};
-  for (const SDValue &V : Op->op_values()) {
+  SmallVector<SDValue, 4> Operands;
+
+  // Chain
+  if (IsStrictFP)
+    Operands.push_back(Op.getOperand(0));
+
+  // Predicate
+  Operands.push_back(Pg);
+
+  // Regular operands
+  for (unsigned OpIdx = OpStartIdx; OpIdx < Op.getNumOperands(); OpIdx++) {
+    SDValue V = Op.getOperand(OpIdx);
     assert((!V.getValueType().isVector() ||
             V.getValueType().isScalableVector()) &&
            "Only scalable vectors are supported!");
@@ -33968,7 +34045,7 @@ SDValue AArch64TargetLowering::LowerToPredicatedOp(SDValue Op,
   if (isMergePassthruOpcode(NewOp))
     Operands.push_back(DAG.getPOISON(VT));
 
-  return DAG.getNode(NewOp, DL, VT, Operands, Op->getFlags());
+  return DAG.getNode(NewOp, DL, Op->getVTList(), Operands, Op->getFlags());
 }
 
 // If a fixed length vector operation has no side effects when applied to
diff --git a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
index bc9fa998cea8f..01c834355d2a2 100644
--- a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
@@ -236,15 +236,6 @@ def SDT_AArch64FMA : SDTypeProfile<1, 4, [
 
 // Predicated operations with the result of inactive lanes being unspecified.
 def AArch64asr_p  : SDNode<"AArch64ISD::SRA_PRED",  SDT_AArch64Arith>;
-def AArch64fadd_p : SDNode<"AArch64ISD::FADD_PRED", SDT_AArch64Arith>;
-def AArch64fdiv_p : SDNode<"AArch64ISD::FDIV_PRED", SDT_AArch64Arith>;
-def AArch64fma_p  : SDNode<"AArch64ISD::FMA_PRED",  SDT_AArch64FMA>;
-def AArch64fmax_p : SDNode<"AArch64ISD::FMAX_PRED", SDT_AArch64Arith>;
-def AArch64fmaxnm_p : SDNode<"AArch64ISD::FMAXNM_PRED", SDT_AArch64Arith>;
-def AArch64fmin_p : SDNode<"AArch64ISD::FMIN_PRED", SDT_AArch64Arith>;
-def AArch64fminnm_p : SDNode<"AArch64ISD::FMINNM_PRED", SDT_AArch64Arith>;
-def AArch64fmul_p : SDNode<"AArch64ISD::FMUL_PRED", SDT_AArch64Arith>;
-def AArch64fsub_p : SDNode<"AArch64ISD::FSUB_PRED", SDT_AArch64Arith>;
 def AArch64lsl_p  : SDNode<"AArch64ISD::SHL_PRED",  SDT_AArch64Arith>;
 def AArch64lsr_p  : SDNode<"AArch64ISD::SRL_PRED",  SDT_AArch64Arith>;
 def AArch64mul_p  : SDNode<"AArch64ISD::MUL_PRED",  SDT_AArch64Arith>;
@@ -261,6 +252,37 @@ def AArch64umax_p : SDNode<"AArch64ISD::UMAX_PRED", SDT_AArch64Arith>;
 def AArch64umin_p : SDNode<"AArch64ISD::UMIN_PRED", SDT_AArch64Arith>;
 def AArch64umulh_p : SDNode<"AArch64ISD::MULHU_PRED", SDT_AArch64Arith>;
 
+multiclass def_strict_fp_op<string short_opcode, SDTypeProfile typeprof> {
+  def _nonstrict : SDNode<"AArch64ISD::" # short_opcode,        typeprof>;
+  def _strict    : SDNode<"AArch64ISD::STRICT_" # short_opcode, typeprof, [SDNPHasChain]>;
+}
+
+multiclass def_strict_fp_3op<string short_opcode, SDTypeProfile typeprof>
+: def_strict_fp_op<short_opcode, typeprof> {
+  def NAME : PatFrags<
+    (ops node:$op1, node:$op2, node:$op3),
+    [(!cast<SDPatternOperator>(NAME # "_nonstrict") node:$op1, node:$op2, node:$op3),
+     (!cast<SDPatternOperator>(NAME # "_strict")    node:$op1, node:$op2, node:$op3)]>;
+}
+
+multiclass def_strict_fp_4op<string short_opcode, SDTypeProfile typeprof>
+: def_strict_fp_op<short_opcode, typeprof> {
+  def NAME : PatFrags<
+    (ops node:$op1, node:$op2, node:$op3, node:$op4),
+    [(!cast<SDPatternOperator>(NAME # "_nonstrict") node:$op1, node:$op2, node:$op3, node:$op4),
+     (!cast<SDPatternOperator>(NAME # "_strict")    node:$op1, node:$op2, node:$op3, node:$op4)]>;
+}
+
+defm AArch64fadd_p   : def_strict_fp_3op<"FADD_PRED",   SDT_AArch64Arith>;
+defm AArch64fdiv_p   : def_strict_fp_3op<"FDIV_PRED",   SDT_AArch64Arith>;
+defm AArch64fma_p    : def_strict_fp_4op<"FMA_PRED",    SDT_AArch64FMA>;
+defm AArch64fmax_p   : def_strict_fp_3op<"FMAX_PRED",   SDT_AArch64Arith>;
+defm AArch64fmaxnm_p : def_strict_fp_3op<"FMAXNM_PRED", SDT_AArch64Arith>;
+defm AArch64fmin_p   : def_strict_fp_3op<"FMIN_PRED",   SDT_AArch64Arith>;
+defm AArch64fminnm_p : def_strict_fp_3op<"FMINNM_PRED", SDT_AArch64Arith>;
+defm AArch64fmul_p   : def_strict_fp_3op<"FMUL_PRED",   SDT_AArch64Arith>;
+defm AArch64fsub_p   : def_strict_fp_3op<"FSUB_PRED",   SDT_AArch64Arith>;
+
 def AArch64fadd_p_contract : PatFrag<(ops node:$op1, node:$op2, node:$op3),
                                      (AArch64fadd_p node:$op1, node:$op2, node:$op3), [{
   return N->getFlags().hasAllowContract();
@@ -313,18 +335,11 @@ def AArch64abs_mt    : SDNode<"AArch64ISD::ABS_MERGE_PASSTHRU", SDT_AArch64Arith
 def AArch64neg_mt    : SDNode<"AArch64ISD::NEG_MERGE_PASSTHRU", SDT_AArch64Arith>;
 def AArch64sxt_mt    : SDNode<"AArch64ISD::SIGN_EXTEND_INREG_MERGE_PASSTHRU", SDT_AArch64IntExtend>;
 def AArch64uxt_mt    : SDNode<"AArch64ISD::ZERO_EXTEND_INREG_MERGE_PASSTHRU", SDT_AArch64IntExtend>;
-def AArch64frintp_mt : SDNode<"AArch64ISD::FCEIL_MERGE_PASSTHRU", SDT_AArch64Arith>;
-def AArch64frintm_mt : SDNode<"AArch64ISD::FFLOOR_MERGE_PASSTHRU", SDT_AArch64Arith>;
-def AArch64frinti_mt : SDNode<"AArch64ISD::FNEARBYINT_MERGE_PASSTHRU", SDT_AArch64Arith>;
 def AArch64frintx_mt : SDNode<"AArch64ISD::FRINT_MERGE_PASSTHRU", SDT_AArch64Arith>;
 def AArch64frint32x_mt : SDNode<"AArch64ISD::FRINT32_MERGE_PASSTHRU", SDT_AArch64Arith>;
 def AArch64frint64x_mt : SDNode<"AArch64ISD::FRINT64_MERGE_PASSTHRU", SDT_AArch64Arith>;
-def AArch64frinta_mt : SDNode<"AArch64ISD::FROUND_MERGE_PASSTHRU", SDT_AArch64Arith>;
-def AArch64frintn_mt : SDNode<"AArch64ISD::FROUNDEVEN_MERGE_PASSTHRU", SDT_AArch64Arith>;
-def AArch64frintz_mt : SDNode<"AArch64ISD::FTRUNC_MERGE_PASSTHRU", SDT_AArch64Arith>;
 def AArch64frint32z_mt : SDNode<"AArch64ISD::FTRUNC32_MERGE_PASSTHRU", SDT_AArch64Arith>;
 def AArch64frint64z_mt : SDNode<"AArch64ISD::FTRUNC64_MERGE_PASSTHRU", SDT_AArch64Arith>;
-def AArch64fsqrt_mt  : SDNode<"AArch64ISD::FSQRT_MERGE_PASSTHRU", SDT_AArch64Arith>;
 def AArch64frecpx_mt : SDNode<"AArch64ISD::FRECPX_MERGE_PASSTHRU", SDT_AArch64Arith>;
 def AArch64rbit_mt   : SDNode<"AArch64ISD::BITREVERSE_MERGE_PASSTHRU", SDT_AArch64Arith>;
 def AArch64revb_mt   : SDNode<"AArch64ISD::BSWAP_MERGE_PASSTHRU", SDT_AArch64Arith>;
@@ -332,6 +347,14 @@ def AArch64revh_mt   : SDNode<"AArch64ISD::REVH_MERGE_PASSTHRU", SDT_AArch64Arit
 def AArch64revw_mt   : SDNode<"AArch64ISD::REVW_MERGE_PASSTHRU", SDT_AArch64Arith>;
 def AArch64revd_mt   : SDNode<"AArch64ISD::REVD_MERGE_PASSTHRU", SDT_AArch64Arith>;
 
+defm AArch64frintp_mt : def_strict_fp_3op<"FCEIL_MERGE_PASSTHRU",      SDT_AArch64Arith>;
+defm AArch64frintm_mt : def_strict_fp_3op<"FFLOOR_MERGE_PASSTHRU",     SDT_AArch64Arith>;
+defm AArch64frinti_mt : def_strict_fp_3op<"FNEARBYINT_MERGE_PASSTHRU", SDT_AArch64Arith>;
+defm AArch64frinta_mt : def_strict_fp_3op<"FROUND_MERGE_PASSTHRU",     SDT_AArch64Arith>;
+defm AArch64frintn_mt : def_strict_fp_3op<"FROUNDEVEN_MERGE_PASSTHRU", SDT_AArch64Arith>;
+defm AArch64frintz_mt : def_strict_fp_3op<"FTRUNC_MERGE_PASSTHRU",     SDT_AArch64Arith>;
+defm AArch64fsqrt_mt  : def_strict_fp_3op<"FSQRT_MERGE_PASSTHRU",      SDT_AArch64Arith>;
+
 def AArch64fneg_mt_nsz : PatFrag<(ops node:$pred, node:$op, node:$pt),
                                  (AArch64fneg_mt node:$pred, node:$op, node:$pt), [{
   return N->getFlags().hasNoSignedZeros();
diff --git a/llvm/test/CodeGen/AArch64/sve-fp-constrained-intrinsics.ll b/llvm/test/CodeGen/AArch64/sve-fp-constrained-intrinsics.ll
new file mode 100644
index 0000000000000..b1e1ebdf5b094
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sve-fp-constrained-intrinsics.ll
@@ -0,0 +1,1084 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mattr=+sve < %s -o - | FileCheck %s
+; RUN: llc -mattr=+sme --force-streaming < %s -o - | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+;
+; constrained.ceil
+;
+
+define <vscale x 2 x half> @ceil_nxv2f16(<vscale x 2 x half> %a) {
+; CHECK-LABEL: ceil_nxv2f16:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ptrue p0.d
+; CHECK-NEXT:    frintp z0.h, p0/m, z0.h
+; CHECK-NEXT:    ret
+  %r = call <vscale x 2 x half> @llvm.experimental.constrained.ceil(<vscale x 2 x half> %a, metadata !"fpexcept.strict")
+  ret <vscale x 2 x half> %r
+}
+
+define <vscale x 4 x half> @ceil_nxv4f16(<vscale x 4 x half> %a) {
+; CHECK-LABEL: ceil_nxv4f16:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ptrue p0.s
+; CHECK-NEXT:    frintp z0.h, p0/m, z0.h
+; CHECK-NEXT:    ret
+  %r = call <vscale x 4 x half> ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/215232


More information about the llvm-commits mailing list