| 2058 | } |
| 2059 | |
| 2060 | Ref OpDispatchBuilder::CVTGPR_To_FPRImpl(OpcodeArgs, IR::OpSize DstElementSize, const X86Tables::DecodedOperand& Src1Op, |
| 2061 | const X86Tables::DecodedOperand& Src2Op) { |
| 2062 | const auto SrcSize = OpSizeFromSrc(Op); |
| 2063 | |
| 2064 | Ref Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, OpSize::i128Bit, Op->Flags); |
| 2065 | Ref Converted {}; |
| 2066 | if (Src2Op.IsGPR()) { |
| 2067 | // If the source is a GPR then convert directly from the GPR. |
| 2068 | auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, GetGPROpSize(), Op->Flags); |
| 2069 | Converted = _Float_FromGPR_S(DstElementSize, SrcSize, Src2); |
| 2070 | } else if (SrcSize != DstElementSize) { |
| 2071 | // If the source is from memory but the Source size and destination size aren't the same, |
| 2072 | // then it is more optimal to load in to a GPR and convert between GPR->FPR. |
| 2073 | // ARM GPR->FPR conversion supports different size source and destinations while FPR->FPR doesn't. |
| 2074 | auto Src2 = LoadSource(GPRClass, Op, Src2Op, Op->Flags); |
| 2075 | Converted = _Float_FromGPR_S(DstElementSize, SrcSize, Src2); |
| 2076 | } else { |
| 2077 | // In the case of cvtsi2s{s,d} where the source and destination are the same size, |
| 2078 | // then it is more optimal to load in to the FPR register directly and convert there. |
| 2079 | auto Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags); |
| 2080 | Converted = _Vector_SToF(SrcSize, SrcSize, Src2); |
| 2081 | } |
| 2082 | |
| 2083 | return _VInsElement(OpSize::i128Bit, DstElementSize, 0, 0, Src1, Converted); |
| 2084 | } |
| 2085 | |
| 2086 | template<IR::OpSize DstElementSize> |
| 2087 | void OpDispatchBuilder::CVTGPR_To_FPR(OpcodeArgs) { |