| 4311 | } |
| 4312 | |
| 4313 | void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, |
| 4314 | const FEXCore::X86Tables::DecodedOperand& Operand, const Ref Src, IR::OpSize OpSize, |
| 4315 | IR::OpSize Align, MemoryAccessType AccessType) { |
| 4316 | if (Operand.IsGPR()) { |
| 4317 | // 8Bit and 16bit destination types store their result without effecting the upper bits |
| 4318 | // 32bit ops ZEXT the result to 64bit |
| 4319 | const auto GPRSize = GetGPROpSize(); |
| 4320 | |
| 4321 | const auto gpr = Operand.Data.GPR.GPR; |
| 4322 | if (gpr >= FEXCore::X86State::REG_MM_0) { |
| 4323 | LOGMAN_THROW_A_FMT(OpSize == OpSize::i64Bit, "full"); |
| 4324 | LOGMAN_THROW_A_FMT(Class == FPRClass, "MMX is floaty"); |
| 4325 | |
| 4326 | if (MMXState != MMXState_MMX) { |
| 4327 | ChgStateX87_MMX(); |
| 4328 | } |
| 4329 | |
| 4330 | uint8_t Index = MM0Index + gpr - FEXCore::X86State::REG_MM_0; |
| 4331 | StoreContext(Index, Src); |
| 4332 | RegCache.Partial |= (1ull << (uint64_t)Index); |
| 4333 | } else if (gpr >= FEXCore::X86State::REG_XMM_0) { |
| 4334 | const auto gprIndex = gpr - X86State::REG_XMM_0; |
| 4335 | const auto VectorSize = GetGuestVectorLength(); |
| 4336 | |
| 4337 | auto Result = Src; |
| 4338 | if (OpSize != VectorSize) { |
| 4339 | // Partial writes can come from FPRs. |
| 4340 | // TODO: Fix the instructions doing partial writes rather than dealing with it here. |
| 4341 | |
| 4342 | LOGMAN_THROW_A_FMT(Class != IR::GPRClass, "Partial writes from GPR not allowed. Instruction: {}", Op->TableInfo->Name); |
| 4343 | |
| 4344 | // XMM-size is handled in implementations. |
| 4345 | if (VectorSize != OpSize::i256Bit || OpSize != OpSize::i128Bit) { |
| 4346 | auto SrcVector = LoadXMMRegister(gprIndex); |
| 4347 | Result = _VInsElement(VectorSize, OpSize, 0, 0, SrcVector, Src); |
| 4348 | } |
| 4349 | } |
| 4350 | |
| 4351 | StoreXMMRegister(gprIndex, Result); |
| 4352 | } else { |
| 4353 | if (GPRSize == OpSize::i64Bit && OpSize == OpSize::i32Bit) { |
| 4354 | // If the Source IR op is 64 bits, we need to zext the upper bits |
| 4355 | // For all other sizes, the upper bits are guaranteed to already be zero |
| 4356 | Ref Value = GetOpSize(Src) == OpSize::i64Bit ? ARef(Src).Bfe(0, 32).Ref() : Src; |
| 4357 | StoreGPRRegister(gpr, Value, GPRSize); |
| 4358 | |
| 4359 | LOGMAN_THROW_A_FMT(!Operand.Data.GPR.HighBits, "Can't handle 32bit store to high 8bit register"); |
| 4360 | } else { |
| 4361 | LOGMAN_THROW_A_FMT(!(GPRSize == OpSize::i32Bit && OpSize > OpSize::i32Bit), "Oops had a {} GPR load", OpSize); |
| 4362 | |
| 4363 | if (GPRSize != OpSize) { |
| 4364 | // if the GPR isn't the full size then we need to insert. |
| 4365 | // eg: |
| 4366 | // mov al, 2 ; Move in to lower 8-bits. |
| 4367 | // mov ah, 2 ; Move in to upper 8-bits of 16-bit reg. |
| 4368 | // mov ax, 2 ; Move in to lower 16-bits of reg. |
| 4369 | StoreGPRRegister(gpr, Src, OpSize, Operand.Data.GPR.HighBits * 8); |
| 4370 | } else { |
nothing calls this directly
no test coverage detected