| 291 | } |
| 292 | |
| 293 | void OpDispatchBuilder::FSUB(OpcodeArgs, IR::OpSize Width, bool Integer, bool Reverse, OpDispatchBuilder::OpResult ResInST0) { |
| 294 | if (Op->Src[0].IsNone()) { |
| 295 | const auto Offset = Op->OP & 7; |
| 296 | const auto St0 = 0; |
| 297 | const auto Result = (ResInST0 == OpResult::RES_STI) ? Offset : St0; |
| 298 | |
| 299 | if (Reverse ^ (ResInST0 == OpResult::RES_STI)) { |
| 300 | _F80SubStack(Result, Offset, St0); |
| 301 | } else { |
| 302 | _F80SubStack(Result, St0, Offset); |
| 303 | } |
| 304 | |
| 305 | if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) { |
| 306 | _PopStackDestroy(); |
| 307 | } |
| 308 | return; |
| 309 | } |
| 310 | |
| 311 | LOGMAN_THROW_A_FMT(Width != OpSize::f80Bit, "No 80-bit floats from memory"); |
| 312 | // We have one memory argument |
| 313 | Ref Arg {}; |
| 314 | if (Integer) { |
| 315 | Arg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); |
| 316 | Arg = _F80CVTToInt(Arg, Width); |
| 317 | } else { |
| 318 | Arg = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags); |
| 319 | Arg = _F80CVTTo(Arg, Width); |
| 320 | } |
| 321 | |
| 322 | // top of stack is at offset zero |
| 323 | if (Reverse) { |
| 324 | _F80SubRValue(Arg, 0); |
| 325 | } else { |
| 326 | _F80SubValue(0, Arg); |
| 327 | } |
| 328 | |
| 329 | if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) { |
| 330 | _PopStackDestroy(); |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | Ref OpDispatchBuilder::GetX87FTW_Helper() { |
| 335 | // AbridgedFTWIndex has 1-bit per slot (8 slots). Duplicate each bit to get |