| 4219 | |
| 4220 | |
| 4221 | Ref OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, const X86Tables::DecodedOp& Op, const X86Tables::DecodedOperand& Operand, |
| 4222 | IR::OpSize OpSize, uint32_t Flags, const LoadSourceOptions& Options) { |
| 4223 | auto [Align, LoadData, ForceLoad, AccessType, AllowUpperGarbage] = Options; |
| 4224 | AddressMode A = DecodeAddress(Op, Operand, AccessType, true /* IsLoad */); |
| 4225 | |
| 4226 | if (Operand.IsGPR()) { |
| 4227 | const auto gpr = Operand.Data.GPR.GPR; |
| 4228 | const auto highIndex = Operand.Data.GPR.HighBits ? 1 : 0; |
| 4229 | |
| 4230 | if (gpr >= FEXCore::X86State::REG_MM_0) { |
| 4231 | LOGMAN_THROW_A_FMT(OpSize == OpSize::i64Bit, "full"); |
| 4232 | |
| 4233 | A.Base = LoadContext(OpSize::i64Bit, MM0Index + gpr - FEXCore::X86State::REG_MM_0); |
| 4234 | } else if (gpr >= FEXCore::X86State::REG_XMM_0) { |
| 4235 | const auto gprIndex = gpr - X86State::REG_XMM_0; |
| 4236 | |
| 4237 | // Load the full register size if it is a XMM register source. |
| 4238 | A.Base = LoadXMMRegister(gprIndex); |
| 4239 | |
| 4240 | // Now extract the subregister if it was a partial load /smaller/ than SSE size |
| 4241 | // TODO: Instead of doing the VMov implicitly on load, hunt down all use cases that require partial loads and do it after load. |
| 4242 | // We don't have information here to know if the operation needs zero upper bits or can contain data. |
| 4243 | if (!AllowUpperGarbage && OpSize < OpSize::i128Bit) { |
| 4244 | A.Base = _VMov(OpSize, A.Base); |
| 4245 | } |
| 4246 | } else { |
| 4247 | A.Base = LoadGPRRegister(gpr, OpSize, highIndex ? 8 : 0, AllowUpperGarbage); |
| 4248 | } |
| 4249 | } |
| 4250 | |
| 4251 | if ((IsOperandMem(Operand, true) && LoadData) || ForceLoad) { |
| 4252 | if (OpSize == OpSize::f80Bit) { |
| 4253 | Ref MemSrc = LoadEffectiveAddress(this, A, GetGPROpSize(), true); |
| 4254 | if (CTX->HostFeatures.SupportsSVE128 || CTX->HostFeatures.SupportsSVE256) { |
| 4255 | return _LoadMemX87SVEOptPredicate(OpSize::i128Bit, OpSize::i16Bit, MemSrc); |
| 4256 | } else { |
| 4257 | // For X87 extended doubles, Split the load. |
| 4258 | auto Res = _LoadMem(Class, OpSize::i64Bit, MemSrc, Align == OpSize::iInvalid ? OpSize : Align); |
| 4259 | return _VLoadVectorElement(OpSize::i128Bit, OpSize::i16Bit, Res, 4, Add(OpSize::i64Bit, MemSrc, 8)); |
| 4260 | } |
| 4261 | } |
| 4262 | |
| 4263 | return _LoadMemAutoTSO(Class, OpSize, A, Align == OpSize::iInvalid ? OpSize : Align); |
| 4264 | } else { |
| 4265 | return LoadEffectiveAddress(this, A, GetGPROpSize(), false, AllowUpperGarbage); |
| 4266 | } |
| 4267 | } |
| 4268 | |
| 4269 | Ref OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, IR::OpSize Size, uint8_t Offset, bool AllowUpperGarbage) { |
| 4270 | const auto GPRSize = GetGPROpSize(); |
nothing calls this directly
no test coverage detected