Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -12881,7 +12881,7 @@ accurately preserve exception behavior without compromising LLVM's ability to optimize FP code when the default behavior is used. -Each of these intrinsics corresponds to a normal floating point operation. The +Each of these intrinsics corresponds to a normal floating point operation. The first two arguments and the return value are the same as the corresponding FP operation. @@ -13178,6 +13178,189 @@ operand computed with infinite precision, and then rounded to the target precision. +'``llvm.experimental.constrained.fptoui``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare + @llvm.experimental.constrained.fptoui( , + metadata , + metadata ) + +Overview: +""""""""" + +The '``llvm.experimental.constrained.fptoui``' intrinsic returns the result of a +conversion of a floating point operand to an unsigned integer. + +Arguments: +"""""""""" + +The first argument to the '``llvm.experimental.constrained.fptoui``' +intrinsic must be :ref:`floating point ` or :ref:`vector +` of floating point values. + +The second and third arguments specify the rounding mode and exception behavior +as described above. + +Semantics: +"""""""""" + +The result produced is an unsigned integer converted from the floating +point operand. + +'``llvm.experimental.constrained.fptosi``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare + @llvm.experimental.constrained.fptosi( , + metadata , + metadata ) + +Overview: +""""""""" + +The '``llvm.experimental.constrained.fptosi``' intrinsic returns the result of a +conversion of a floating point operand to a signed integer. + +Arguments: +"""""""""" + +The first argument to the '``llvm.experimental.constrained.fptoui``' +intrinsic must be :ref:`floating point ` or :ref:`vector +` of floating point values. + +The second and third arguments specify the rounding mode and exception behavior +as described above. + +Semantics: +"""""""""" + +The result produced is a signed integer converted from the floating +point operand. + +'``llvm.experimental.constrained.round``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare + @llvm.experimental.constrained.round( , + metadata , + metadata ) + +Overview: +""""""""" + +The '``llvm.experimental.constrained.round``' intrinsic returns the result of a +rounding of a floating point operand into a smaller floating point result. + +Arguments: +"""""""""" + +The first argument to the '``llvm.experimental.constrained.round``' +intrinsic must be :ref:`floating point ` or :ref:`vector +` of floating point values. This argument must be larger in size +than the result. + +The second and third arguments specify the rounding mode and exception behavior +as described above. + +Semantics: +"""""""""" + +The result produced is a floating point value rounded to be smaller in size +than the operand. + +'``llvm.experimental.constrained.round.inreg``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare + @llvm.experimental.constrained.round.inreg( , + , + metadata , + metadata ) + +Overview: +""""""""" + +The '``llvm.experimental.constrained.round.inreg``' intrinsic returns the result +of a rounding of a floating point operand into a smaller floating point type +and then extended back to the original size. + +Arguments: +"""""""""" + +The first argument to the '``llvm.experimental.constrained.round.inreg``' +intrinsic must be :ref:`floating point ` or :ref:`vector +` of floating point values. This argument must be larger in size +than the second operand, and must be the same size as the result. + +The second argument specifies the smaller size the first argument is to +be rounded to fit. + +The third and fourth arguments specify the rounding mode and exception behavior +as described above. + +Semantics: +"""""""""" + +The result produced is a floating point value the same size as the first operand +but with an intermediate rounding to a smaller size. + +'``llvm.experimental.constrained.extend``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare + @llvm.experimental.constrained.extend( , + metadata , + metadata ) + +Overview: +""""""""" + +The '``llvm.experimental.constrained.extend``' intrinsic returns the result of +an enlarging of a floating point operand. + +Arguments: +"""""""""" + +The first argument to the '``llvm.experimental.constrained.extend``' +intrinsic must be :ref:`floating point ` or :ref:`vector +` of floating point values. This argument must be smaller in size +than the result. + +The second and third arguments specify the rounding mode and exception behavior +as described above. + +Semantics: +"""""""""" + +The result produced is a floating point value extended to be larger in size +than the operand. + Constrained libm-equivalent Intrinsics -------------------------------------- Index: include/llvm/CodeGen/ISDOpcodes.h =================================================================== --- include/llvm/CodeGen/ISDOpcodes.h +++ include/llvm/CodeGen/ISDOpcodes.h @@ -530,6 +530,12 @@ /// X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type. FP_EXTEND, + STRICT_FP_TO_SINT, + STRICT_FP_TO_UINT, + STRICT_FP_ROUND, + STRICT_FP_ROUND_INREG, + STRICT_FP_EXTEND, + /// BITCAST - This operator converts between integer, vector and FP /// values, as if the value was stored to memory with one type and loaded /// from the same address with the other type (or equivalently for vector Index: include/llvm/CodeGen/SelectionDAGNodes.h =================================================================== --- include/llvm/CodeGen/SelectionDAGNodes.h +++ include/llvm/CodeGen/SelectionDAGNodes.h @@ -643,6 +643,11 @@ case ISD::STRICT_FLOG2: case ISD::STRICT_FRINT: case ISD::STRICT_FNEARBYINT: + case ISD::STRICT_FP_TO_SINT: + case ISD::STRICT_FP_TO_UINT: + case ISD::STRICT_FP_ROUND: + case ISD::STRICT_FP_ROUND_INREG: + case ISD::STRICT_FP_EXTEND: return true; } } Index: include/llvm/IR/IntrinsicInst.h =================================================================== --- include/llvm/IR/IntrinsicInst.h +++ include/llvm/IR/IntrinsicInst.h @@ -192,6 +192,11 @@ case Intrinsic::experimental_constrained_fdiv: case Intrinsic::experimental_constrained_frem: case Intrinsic::experimental_constrained_fma: + case Intrinsic::experimental_constrained_fptosi: + case Intrinsic::experimental_constrained_fptoui: + case Intrinsic::experimental_constrained_round: + case Intrinsic::experimental_constrained_round_inreg: + case Intrinsic::experimental_constrained_extend: case Intrinsic::experimental_constrained_sqrt: case Intrinsic::experimental_constrained_pow: case Intrinsic::experimental_constrained_powi: Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -499,6 +499,32 @@ llvm_metadata_ty, llvm_metadata_ty ]>; + def int_experimental_constrained_fptosi : Intrinsic<[ llvm_anyint_ty ], + [ llvm_anyfloat_ty, + llvm_metadata_ty, + llvm_metadata_ty ]>; + + def int_experimental_constrained_fptoui : Intrinsic<[ llvm_anyint_ty ], + [ llvm_anyfloat_ty, + llvm_metadata_ty, + llvm_metadata_ty ]>; + + def int_experimental_constrained_round : Intrinsic<[ llvm_anyfloat_ty ], + [ llvm_anyfloat_ty, + llvm_metadata_ty, + llvm_metadata_ty ]>; + + def int_experimental_constrained_round_inreg : Intrinsic<[ llvm_anyfloat_ty ], + [ llvm_anyfloat_ty, + llvm_anyfloat_ty, + llvm_metadata_ty, + llvm_metadata_ty ]>; + + def int_experimental_constrained_extend : Intrinsic<[ llvm_anyfloat_ty ], + [ llvm_anyfloat_ty, + llvm_metadata_ty, + llvm_metadata_ty ]>; + // These intrinsics are sensitive to the rounding mode so we need constrained // versions of each of them. When strict rounding and exception control are // not required the non-constrained versions of these intrinsics should be Index: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -965,6 +965,11 @@ case ISD::STRICT_FLOG2: EqOpc = ISD::FLOG2; break; case ISD::STRICT_FRINT: EqOpc = ISD::FRINT; break; case ISD::STRICT_FNEARBYINT: EqOpc = ISD::FNEARBYINT; break; + case ISD::STRICT_FP_TO_SINT: EqOpc = ISD::FP_TO_SINT; break; + case ISD::STRICT_FP_TO_UINT: EqOpc = ISD::FP_TO_UINT; break; + case ISD::STRICT_FP_ROUND: EqOpc = ISD::FP_ROUND; break; + case ISD::STRICT_FP_ROUND_INREG: EqOpc = ISD::FP_ROUND_INREG; break; + case ISD::STRICT_FP_EXTEND: EqOpc = ISD::FP_EXTEND; break; } auto Action = TLI.getOperationAction(EqOpc, VT); @@ -1135,12 +1140,22 @@ case ISD::STRICT_FLOG2: case ISD::STRICT_FRINT: case ISD::STRICT_FNEARBYINT: + case ISD::STRICT_FP_TO_SINT: + case ISD::STRICT_FP_TO_UINT: + case ISD::STRICT_FP_ROUND: + case ISD::STRICT_FP_ROUND_INREG: + case ISD::STRICT_FP_EXTEND: // These pseudo-ops get legalized as if they were their non-strict // equivalent. For instance, if ISD::FSQRT is legal then ISD::STRICT_FSQRT // is also legal, but if ISD::FSQRT requires expansion then so does // ISD::STRICT_FSQRT. - Action = getStrictFPOpcodeAction(TLI, Node->getOpcode(), - Node->getValueType(0)); + if (Node->getOpcode() == ISD::STRICT_FP_ROUND_INREG) { + EVT InnerType = cast(Node->getOperand(1))->getVT(); + Action = getStrictFPOpcodeAction(TLI, Node->getOpcode(), + InnerType); + } + else Action = getStrictFPOpcodeAction(TLI, Node->getOpcode(), + Node->getValueType(0)); break; default: if (Node->getOpcode() >= ISD::BUILTIN_OP_END) { @@ -3011,12 +3026,14 @@ break; } case ISD::FP_ROUND: + case ISD::STRICT_FP_ROUND: case ISD::BITCAST: Tmp1 = EmitStackConvert(Node->getOperand(0), Node->getValueType(0), Node->getValueType(0), dl); Results.push_back(Tmp1); break; case ISD::FP_EXTEND: + case ISD::STRICT_FP_EXTEND: Tmp1 = EmitStackConvert(Node->getOperand(0), Node->getOperand(0).getValueType(), Node->getValueType(0), dl); @@ -3054,7 +3071,8 @@ Results.push_back(Tmp1); break; } - case ISD::FP_ROUND_INREG: { + case ISD::FP_ROUND_INREG: + case ISD::STRICT_FP_ROUND_INREG: { // The only way we can lower this is to turn it into a TRUNCSTORE, // EXTLOAD pair, targeting a temporary location (a stack slot). @@ -3074,10 +3092,12 @@ Results.push_back(Tmp1); break; case ISD::FP_TO_SINT: + case ISD::STRICT_FP_TO_SINT: if (TLI.expandFP_TO_SINT(Node, Tmp1, DAG)) Results.push_back(Tmp1); break; - case ISD::FP_TO_UINT: { + case ISD::FP_TO_UINT: + case ISD::STRICT_FP_TO_UINT: { SDValue True, False; EVT VT = Node->getOperand(0).getValueType(); EVT NVT = Node->getValueType(0); Index: lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -6835,6 +6835,9 @@ unsigned NewOpc; bool IsUnary = false; bool IsTernary = false; + DEBUG(dbgs() << "mutateStrictFPtoFP starting node: "; + Node->dump(); + dbgs() << '\n'); switch (OrigOpc) { default: llvm_unreachable("mutateStrictFPToFP called with unexpected opcode!"); @@ -6859,16 +6862,50 @@ NewOpc = ISD::FNEARBYINT; IsUnary = true; break; + case ISD::STRICT_FP_TO_SINT: NewOpc = ISD::FP_TO_SINT; break; + case ISD::STRICT_FP_TO_UINT: NewOpc = ISD::FP_TO_UINT; break; + case ISD::STRICT_FP_ROUND: NewOpc = ISD::FP_ROUND; IsUnary = true; break; + case ISD::STRICT_FP_ROUND_INREG: + NewOpc = ISD::FP_ROUND_INREG; + IsUnary = true; + break; + case ISD::STRICT_FP_EXTEND: NewOpc = ISD::FP_EXTEND; IsUnary = true; break; } // We're taking this node out of the chain, so we need to re-link things. - SDValue InputChain = Node->getOperand(0); - SDValue OutputChain = SDValue(Node, 1); - ReplaceAllUsesOfValueWith(OutputChain, InputChain); + if (OrigOpc != ISD::STRICT_FP_TO_SINT && + OrigOpc != ISD::STRICT_FP_TO_UINT && + OrigOpc != ISD::STRICT_FP_ROUND_INREG) { + SDValue InputChain = Node->getOperand(0); + SDValue OutputChain = SDValue(Node, 1); + ReplaceAllUsesOfValueWith(OutputChain, InputChain); + DEBUG(dbgs() << "mutateStrictFPtoFP node after RAUOVW: "; + Node->dump(); + dbgs() << '\n'); + } - SDVTList VTs = getVTList(Node->getOperand(1).getValueType()); + SDVTList VTs; SDNode *Res = nullptr; - if (IsUnary) + + switch (OrigOpc) { + default: + VTs = getVTList(Node->getOperand(1).getValueType()); + break; + case ISD::STRICT_FP_TO_SINT: + case ISD::STRICT_FP_TO_UINT: + case ISD::STRICT_FP_ROUND: + case ISD::STRICT_FP_ROUND_INREG: + case ISD::STRICT_FP_EXTEND: + VTs = getVTList(Node->ValueList[0]); + break; + } + + if (OrigOpc == ISD::STRICT_FP_TO_SINT || OrigOpc == ISD::STRICT_FP_TO_UINT) + Res = MorphNodeTo(Node, NewOpc, VTs, { Node->getOperand(0) }); + else if (OrigOpc == ISD::STRICT_FP_ROUND_INREG) + Res = MorphNodeTo(Node, NewOpc, VTs, { Node->getOperand(0), + Node->getOperand(1) }); + else if (IsUnary) Res = MorphNodeTo(Node, NewOpc, VTs, { Node->getOperand(1) }); else if (IsTernary) Res = MorphNodeTo(Node, NewOpc, VTs, { Node->getOperand(1), @@ -6877,6 +6914,9 @@ else Res = MorphNodeTo(Node, NewOpc, VTs, { Node->getOperand(1), Node->getOperand(2) }); + DEBUG(dbgs() << "mutateStrictFPtoFP node after MorphNodeTo: "; + Node->dump(); + dbgs() << '\n'); // MorphNodeTo can operate in two ways: if an existing node with the // specified operands exists, it can just return it. Otherwise, it @@ -6889,6 +6929,9 @@ ReplaceAllUsesWith(Node, Res); RemoveDeadNode(Node); } + DEBUG(dbgs() << "mutateStrictFPtoFP node ends: "; + Node->dump(); + dbgs() << '\n'); return Res; } Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5528,6 +5528,11 @@ case Intrinsic::experimental_constrained_fdiv: case Intrinsic::experimental_constrained_frem: case Intrinsic::experimental_constrained_fma: + case Intrinsic::experimental_constrained_fptosi: + case Intrinsic::experimental_constrained_fptoui: + case Intrinsic::experimental_constrained_round: + case Intrinsic::experimental_constrained_round_inreg: + case Intrinsic::experimental_constrained_extend: case Intrinsic::experimental_constrained_sqrt: case Intrinsic::experimental_constrained_pow: case Intrinsic::experimental_constrained_powi: @@ -6070,6 +6075,21 @@ case Intrinsic::experimental_constrained_fma: Opcode = ISD::STRICT_FMA; break; + case Intrinsic::experimental_constrained_fptosi: + Opcode = ISD::STRICT_FP_TO_SINT; + break; + case Intrinsic::experimental_constrained_fptoui: + Opcode = ISD::STRICT_FP_TO_UINT; + break; + case Intrinsic::experimental_constrained_round: + Opcode = ISD::STRICT_FP_ROUND; + break; + case Intrinsic::experimental_constrained_round_inreg: + Opcode = ISD::STRICT_FP_ROUND_INREG; + break; + case Intrinsic::experimental_constrained_extend: + Opcode = ISD::STRICT_FP_EXTEND; + break; case Intrinsic::experimental_constrained_sqrt: Opcode = ISD::STRICT_FSQRT; break; @@ -6111,12 +6131,26 @@ SDValue Chain = getRoot(); SmallVector ValueVTs; ComputeValueVTs(TLI, DAG.getDataLayout(), FPI.getType(), ValueVTs); - ValueVTs.push_back(MVT::Other); // Out chain + if (!(Opcode == ISD::STRICT_FP_TO_UINT || + Opcode == ISD::STRICT_FP_TO_SINT || + Opcode == ISD::STRICT_FP_ROUND_INREG)) { + ValueVTs.push_back(MVT::Other); // Out chain + } SDVTList VTs = DAG.getVTList(ValueVTs); SDValue Result; - if (FPI.isUnaryOp()) + if (Opcode == ISD::STRICT_FP_TO_UINT || Opcode == ISD::STRICT_FP_TO_SINT) Result = DAG.getNode(Opcode, sdl, VTs, + { getValue(FPI.getArgOperand(0)) }); + else if (Opcode == ISD::STRICT_FP_ROUND_INREG) { + Type *T = FPI.getArgOperand(1)->getType(); + EVT RT = TLI.getValueType(DAG.getDataLayout(), T, true); + Result = DAG.getNode(Opcode, sdl, VTs, + { getValue(FPI.getArgOperand(0)), + DAG.getValueType(RT) }); + } + else if (FPI.isUnaryOp()) + Result = DAG.getNode(Opcode, sdl, VTs, { Chain, getValue(FPI.getArgOperand(0)) }); else if (FPI.isTernaryOp()) Result = DAG.getNode(Opcode, sdl, VTs, @@ -6128,9 +6162,13 @@ { Chain, getValue(FPI.getArgOperand(0)), getValue(FPI.getArgOperand(1)) }); - assert(Result.getNode()->getNumValues() == 2); - SDValue OutChain = Result.getValue(1); - DAG.setRoot(OutChain); + if (!(Opcode == ISD::STRICT_FP_TO_UINT || + Opcode == ISD::STRICT_FP_TO_SINT || + Opcode == ISD::STRICT_FP_ROUND_INREG)) { + assert(Result.getNode()->getNumValues() == 2); + SDValue OutChain = Result.getValue(1); + DAG.setRoot(OutChain); + } SDValue FPResult = Result.getValue(0); setValue(&FPI, FPResult); } Index: lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -289,14 +289,19 @@ case ISD::ZERO_EXTEND_VECTOR_INREG: return "zero_extend_vector_inreg"; case ISD::TRUNCATE: return "truncate"; case ISD::FP_ROUND: return "fp_round"; + case ISD::STRICT_FP_ROUND: return "strict_fp_round"; case ISD::FLT_ROUNDS_: return "flt_rounds"; case ISD::FP_ROUND_INREG: return "fp_round_inreg"; + case ISD::STRICT_FP_ROUND_INREG: return "strict_fp_round_inreg"; case ISD::FP_EXTEND: return "fp_extend"; + case ISD::STRICT_FP_EXTEND: return "strict_fp_extend"; case ISD::SINT_TO_FP: return "sint_to_fp"; case ISD::UINT_TO_FP: return "uint_to_fp"; case ISD::FP_TO_SINT: return "fp_to_sint"; + case ISD::STRICT_FP_TO_SINT: return "strict_fp_to_sint"; case ISD::FP_TO_UINT: return "fp_to_uint"; + case ISD::STRICT_FP_TO_UINT: return "strict_fp_to_uint"; case ISD::BITCAST: return "bitcast"; case ISD::ADDRSPACECAST: return "addrspacecast"; case ISD::FP16_TO_FP: return "fp16_to_fp"; Index: lib/IR/IntrinsicInst.cpp =================================================================== --- lib/IR/IntrinsicInst.cpp +++ lib/IR/IntrinsicInst.cpp @@ -134,6 +134,11 @@ switch (getIntrinsicID()) { default: return false; + case Intrinsic::experimental_constrained_fptosi: + case Intrinsic::experimental_constrained_fptoui: + case Intrinsic::experimental_constrained_round: + case Intrinsic::experimental_constrained_round_inreg: + case Intrinsic::experimental_constrained_extend: case Intrinsic::experimental_constrained_sqrt: case Intrinsic::experimental_constrained_sin: case Intrinsic::experimental_constrained_cos: Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -4030,6 +4030,11 @@ case Intrinsic::experimental_constrained_fdiv: case Intrinsic::experimental_constrained_frem: case Intrinsic::experimental_constrained_fma: + case Intrinsic::experimental_constrained_fptosi: + case Intrinsic::experimental_constrained_fptoui: + case Intrinsic::experimental_constrained_round: + case Intrinsic::experimental_constrained_round_inreg: + case Intrinsic::experimental_constrained_extend: case Intrinsic::experimental_constrained_sqrt: case Intrinsic::experimental_constrained_pow: case Intrinsic::experimental_constrained_powi: Index: test/CodeGen/X86/fp-intrinsics.ll =================================================================== --- test/CodeGen/X86/fp-intrinsics.ll +++ test/CodeGen/X86/fp-intrinsics.ll @@ -274,6 +274,59 @@ ret double %result } +; Verify that fptoui(42.1) isn't simplified when the rounding mode is +; unknown. +; Verify that no gross errors happen. +; CHECK-LABEL: @f19 +; COMMON: movl +define zeroext i32 @f19() { +entry: + %result = call zeroext i32 @llvm.experimental.constrained.fptoui.f64( + double 42.1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") + ret i32 %result +} + +; Verify that fptosi(42.1) isn't simplified when the rounding mode is +; unknown. +; Verify that no gross errors happen. +; CHECK-LABEL: @f20 +; COMMON: cvttsd2si +define i32 @f20() { +entry: + %result = call i32 @llvm.experimental.constrained.fptosi.f64(double 42.1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") + ret i32 %result +} + +; Verify that round(42.1) isn't simplified when the rounding mode is +; unknown. +; Verify that no gross errors happen. +; CHECK-LABEL: @f21 +; COMMON: cvtsd2ss +define float @f21() { +entry: + %result = call float @llvm.experimental.constrained.round.f64(double 42.1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") + ret float %result +} + +; Verify that extend(42.1) isn't simplified when the rounding mode is +; unknown. +; Verify that no gross errors happen. +; CHECK-LABEL: @f23 +; COMMON: cvtss2sd +define double @f23(float %x) { +entry: + %result = call double @llvm.experimental.constrained.extend.f32(float %x, + metadata !"round.dynamic", + metadata !"fpexcept.strict") + ret double %result +} + @llvm.fp.env = thread_local global i8 zeroinitializer, section "llvm.metadata" declare double @llvm.experimental.constrained.fdiv.f64(double, double, metadata, metadata) declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata) @@ -293,3 +346,8 @@ declare double @llvm.experimental.constrained.nearbyint.f64(double, metadata, metadata) declare float @llvm.experimental.constrained.fma.f32(float, float, float, metadata, metadata) declare double @llvm.experimental.constrained.fma.f64(double, double, double, metadata, metadata) +declare zeroext i32 @llvm.experimental.constrained.fptoui.f64(double, metadata, metadata) +declare i32 @llvm.experimental.constrained.fptosi.f64(double, metadata, metadata) +declare float @llvm.experimental.constrained.round.f64(double, metadata, metadata) +declare double @llvm.experimental.constrained.extend.f32(float, metadata, metadata) + Index: test/Feature/fp-intrinsics.ll =================================================================== --- test/Feature/fp-intrinsics.ll +++ test/Feature/fp-intrinsics.ll @@ -242,6 +242,68 @@ ret double %result } +; Verify that fptoui(42.1) isn't simplified when the rounding mode is +; unknown. +; CHECK-LABEL: f18 +; CHECK: call zeroext i32 @llvm.experimental.constrained.fptoui +define zeroext i32 @f18() { +entry: + %result = call zeroext i32 @llvm.experimental.constrained.fptoui.f64( + double 42.1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") + ret i32 %result +} + +; Verify that fptosi(42.1) isn't simplified when the rounding mode is +; unknown. +; CHECK-LABEL: f19 +; CHECK: call i32 @llvm.experimental.constrained.fptosi +define i32 @f19() { +entry: + %result = call i32 @llvm.experimental.constrained.fptosi.f64(double 42.1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") + ret i32 %result +} + +; Verify that round(42.1) isn't simplified when the rounding mode is +; unknown. +; CHECK-LABEL: f20 +; CHECK: call float @llvm.experimental.constrained.round +define float @f20() { +entry: + %result = call float @llvm.experimental.constrained.round.f32(double 42.1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") + ret float %result +} + +; Verify that round_in_reg(42.1) isn't simplified when the rounding mode is +; unknown. +; CHECK-LABEL: f21 +; CHECK: call float @llvm.experimental.constrained.round.in.reg +define float @f21() { +entry: + %result = call float @llvm.experimental.constrained.round.in.reg.f32( + double 42.1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") + ret float %result +} + +; Verify that extend(42.1) isn't simplified when the rounding mode is +; unknown. +; CHECK-LABEL: f22 +; CHECK: call double @llvm.experimental.constrained.extend +define double @f22() { +entry: + %result = call double @llvm.experimental.constrained.extend.f64(double 42.1, + metadata !"round.dynamic", + metadata !"fpexcept.strict") + ret double %result +} + @llvm.fp.env = thread_local global i8 zeroinitializer, section "llvm.metadata" declare double @llvm.experimental.constrained.fdiv.f64(double, double, metadata, metadata) declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata) @@ -260,3 +322,8 @@ declare double @llvm.experimental.constrained.rint.f64(double, metadata, metadata) declare double @llvm.experimental.constrained.nearbyint.f64(double, metadata, metadata) declare double @llvm.experimental.constrained.fma.f64(double, double, double, metadata, metadata) +declare zeroext i32 @llvm.experimental.constrained.fptoui.f64(double, metadata, metadata) +declare i32 @llvm.experimental.constrained.fptosi.f64(double, metadata, metadata) +declare float @llvm.experimental.constrained.round.f32(double, metadata, metadata) +declare float @llvm.experimental.constrained.round.in.reg.f32(double, metadata, metadata) +declare double @llvm.experimental.constrained.extend.f64(double, metadata, metadata)