| 10 | |
| 11 | namespace FEXCore::CPU { |
| 12 | DEF_OP(VInsGPR) { |
| 13 | const auto Op = IROp->C<IR::IROp_VInsGPR>(); |
| 14 | const auto OpSize = IROp->Size; |
| 15 | |
| 16 | const auto DestIdx = Op->DestIdx; |
| 17 | const auto ElementSize = Op->Header.ElementSize; |
| 18 | const auto Is256Bit = OpSize == IR::OpSize::i256Bit; |
| 19 | LOGMAN_THROW_A_FMT(!Is256Bit || HostSupportsSVE256, "Need SVE256 support in order to use {} with 256-bit operation", __func__); |
| 20 | |
| 21 | const auto SubEmitSize = ConvertSubRegSize8(IROp); |
| 22 | const auto ElementsPer128Bit = IR::NumElements(IR::OpSize::i128Bit, ElementSize); |
| 23 | |
| 24 | const auto Dst = GetVReg(Node); |
| 25 | const auto DestVector = GetVReg(Op->DestVector); |
| 26 | const auto Src = GetReg(Op->Src); |
| 27 | |
| 28 | if (HostSupportsSVE256 && Is256Bit) { |
| 29 | const auto ElementSizeBits = IR::OpSizeAsBits(ElementSize); |
| 30 | const auto Offset = ElementSizeBits * DestIdx; |
| 31 | |
| 32 | const auto SSEBitSize = Core::CPUState::XMM_SSE_REG_SIZE * 8; |
| 33 | const auto InUpperLane = Offset >= SSEBitSize; |
| 34 | |
| 35 | // This is going to be a little gross. Pls forgive me. |
| 36 | // Since SVE has the whole vector length agnostic programming |
| 37 | // thing going on, we can't exactly freely insert entries into |
| 38 | // arbitrary locations in the vector. |
| 39 | // |
| 40 | // SVE *does* have INSR, however this only shifts the entire |
| 41 | // vector to the left by an element size and inserts a value |
| 42 | // at the beginning of the vector. Not *quite* what we need. |
| 43 | // (though INSR *is* very useful for other things). |
| 44 | // |
| 45 | // The idea is (in the case of the upper lane), move the upper |
| 46 | // lane down, insert into it and recombine with the lower lane. |
| 47 | // |
| 48 | // In the case of the lower lane, insert and then recombine with |
| 49 | // the upper lane. |
| 50 | |
| 51 | if (InUpperLane) { |
| 52 | // Move the upper lane down for the insertion. |
| 53 | const auto CompactPred = ARMEmitter::PReg::p0; |
| 54 | not_(CompactPred, PRED_TMP_32B.Zeroing(), PRED_TMP_16B); |
| 55 | compact(ARMEmitter::SubRegSize::i64Bit, VTMP1.Z(), CompactPred, DestVector.Z()); |
| 56 | } |
| 57 | |
| 58 | // Put data in place for destructive SPLICE below. |
| 59 | mov(Dst.Z(), DestVector.Z()); |
| 60 | |
| 61 | // Inserts the GPR value into the given V register. |
| 62 | // Also automatically adjusts the index in the case of using the |
| 63 | // moved upper lane. |
| 64 | const auto Insert = [&](const ARMEmitter::VRegister& reg, int index) { |
| 65 | if (InUpperLane) { |
| 66 | index -= ElementsPer128Bit; |
| 67 | } |
| 68 | ins(SubEmitSize, reg, index, Src); |
| 69 | }; |
nothing calls this directly
no test coverage detected