| 2101 | template void OpDispatchBuilder::AVXCVTGPR_To_FPR<OpSize::i64Bit>(OpcodeArgs); |
| 2102 | |
| 2103 | Ref OpDispatchBuilder::CVTFPR_To_GPRImpl(OpcodeArgs, Ref Src, IR::OpSize SrcElementSize, bool HostRoundingMode) { |
| 2104 | // GPR size is determined by REX.W |
| 2105 | // Source Element size is determined by instruction |
| 2106 | const auto GPRSize = OpSizeFromDst(Op); |
| 2107 | |
| 2108 | if (CTX->HostFeatures.SupportsFRINTTS) { |
| 2109 | // When we have FRINTTS, this is a two-step process. First, we round to the |
| 2110 | // right integer (where _Vector_FToISized matches x86 semantics), then just |
| 2111 | // convert that to a GPR. |
| 2112 | Src = _Vector_FToISized(SrcElementSize, SrcElementSize, Src, HostRoundingMode, GPRSize); |
| 2113 | return _Float_ToGPR_ZS(GPRSize, SrcElementSize, Src); |
| 2114 | } else { |
| 2115 | // When we lack hardware support, we need a bit of a convoluted sequence of |
| 2116 | // fixups before before and after conversion to emulate x86 semantics. |
| 2117 | if (HostRoundingMode) { |
| 2118 | Src = _Vector_FToI(SrcElementSize, SrcElementSize, Src, Round_Host); |
| 2119 | } |
| 2120 | |
| 2121 | Ref Converted = _Float_ToGPR_ZS(GPRSize, SrcElementSize, Src); |
| 2122 | |
| 2123 | bool Dst32 = GPRSize == OpSize::i32Bit; |
| 2124 | Ref MaxI = Dst32 ? Constant(0x80000000) : Constant(0x8000000000000000); |
| 2125 | Ref MaxF = LoadAndCacheNamedVectorConstant(SrcElementSize, (SrcElementSize == OpSize::i32Bit) ? |
| 2126 | (Dst32 ? NAMED_VECTOR_CVTMAX_F32_I32 : NAMED_VECTOR_CVTMAX_F32_I64) : |
| 2127 | (Dst32 ? NAMED_VECTOR_CVTMAX_F64_I32 : NAMED_VECTOR_CVTMAX_F64_I64)); |
| 2128 | return _Select(GPRSize, SrcElementSize, CondClassType {FEXCore::IR::COND_FGT}, MaxF, Src, Converted, MaxI); |
| 2129 | } |
| 2130 | } |
| 2131 | |
| 2132 | template<IR::OpSize SrcElementSize, bool HostRoundingMode> |
| 2133 | void OpDispatchBuilder::CVTFPR_To_GPR(OpcodeArgs) { |
nothing calls this directly
no outgoing calls
no test coverage detected