| 471 | } |
| 472 | |
| 473 | bool ConstrainedRAPass::TryPostRAMerge(Ref LastNode, Ref CodeNode, IROp_Header* IROp) { |
| 474 | auto LastOp = IR->GetOp<IROp_Header>(LastNode); |
| 475 | |
| 476 | if (IROp->Op == OP_PUSH && LastOp->Op == OP_PUSH) { |
| 477 | auto SP = PhysicalRegister(CodeNode); |
| 478 | auto Push = IR->GetOp<IROp_Push>(CodeNode); |
| 479 | auto LastPush = IR->GetOp<IROp_Push>(LastNode); |
| 480 | |
| 481 | if (LastOp->Size == IROp->Size && LastPush->ValueSize == Push->ValueSize && SP == PhysicalRegister(LastNode) && |
| 482 | SP == PhysicalRegister(IROp->Args[1]) && SP == PhysicalRegister(LastOp->Args[1]) && SP != PhysicalRegister(IROp->Args[0]) && |
| 483 | SP != PhysicalRegister(LastOp->Args[0]) && Push->ValueSize >= OpSize::i32Bit) { |
| 484 | |
| 485 | IREmit->SetWriteCursorBefore(LastNode); |
| 486 | IREmit->_PushTwo(IROp->Size, Push->ValueSize, IROp->Args[0], LastOp->Args[0], IROp->Args[1]); |
| 487 | IREmit->RemovePostRA(CodeNode); |
| 488 | return true; |
| 489 | } |
| 490 | } else if (IROp->Op == OP_POP) { |
| 491 | auto SP = PhysicalRegister(IROp->Args[0]); |
| 492 | |
| 493 | if (LastOp->Op == OP_POP && LastOp->Size == IROp->Size && IROp->Size >= OpSize::i32Bit && SP == PhysicalRegister(LastOp->Args[0])) { |
| 494 | IREmit->SetWriteCursorBefore(LastNode); |
| 495 | IREmit->_PopTwo(IROp->Size, IROp->Args[0], LastOp->Args[1], IROp->Args[1]); |
| 496 | IREmit->RemovePostRA(CodeNode); |
| 497 | return true; |
| 498 | } |
| 499 | } else if ((IROp->Op == OP_DIV || IROp->Op == OP_UDIV) && IROp->Size >= OpSize::i32Bit) { |
| 500 | // If Upper came from a sign/zero extension, we only need a 64-bit division. |
| 501 | auto Op = IROp->CW<IR::IROp_Div>(); |
| 502 | if (!Op->Upper.IsInvalid() && PhysicalRegister(Op->Upper) == PhysicalRegister(LastNode)) { |
| 503 | if (IROp->Op == OP_DIV ? IsSignext(LastOp, Op->Lower, IROp->Size) : IsZero(LastOp)) { |
| 504 | Op->Upper.SetInvalid(); |
| 505 | return PhysicalRegister(LastNode) == PhysicalRegister(Op->OutRemainder); |
| 506 | } |
| 507 | } |
| 508 | } else if (IROp->Op == OP_XGETBV && PhysicalRegister(IROp->Args[0]) == PhysicalRegister(LastNode) && LastOp->Op == OP_CONSTANT) { |
| 509 | // Try to constant fold |
| 510 | uint64_t ConstantFunction = LastOp->C<IROp_Constant>()->Constant; |
| 511 | auto Op = IROp->CW<IR::IROp_XGetBV>(); |
| 512 | if (CPUID->DoesXCRFunctionReportConstantData(ConstantFunction)) { |
| 513 | const auto Result = CPUID->RunXCRFunction(ConstantFunction); |
| 514 | IREmit->SetWriteCursorBefore(CodeNode); |
| 515 | IREmit->_Constant(Result.eax).Node->Reg = PhysicalRegister(Op->OutEAX).Raw; |
| 516 | IREmit->_Constant(Result.edx).Node->Reg = PhysicalRegister(Op->OutEDX).Raw; |
| 517 | IREmit->RemovePostRA(CodeNode); |
| 518 | return false; |
| 519 | } |
| 520 | } else if (IROp->Op == OP_CPUID && PhysicalRegister(IROp->Args[0]) == PhysicalRegister(LastNode) && LastOp->Op == OP_CONSTANT) { |
| 521 | // Try to constant fold. As a limitation of merging only 2 instructions, we |
| 522 | // can only handle constant functions, not constant leafs. This could be |
| 523 | // lifted if we generalized at a (significant) complexity cost. |
| 524 | uint64_t ConstantFunction = LastOp->C<IROp_Constant>()->Constant; |
| 525 | auto Op = IROp->CW<IR::IROp_CPUID>(); |
| 526 | |
| 527 | const auto SupportsConstant = CPUID->DoesFunctionReportConstantData(ConstantFunction); |
| 528 | if (SupportsConstant.SupportsConstantFunction == CPUIDEmu::SupportsConstant::CONSTANT && |
| 529 | SupportsConstant.NeedsLeaf != CPUIDEmu::NeedsLeafConstant::NEEDSLEAFCONSTANT) { |
| 530 | const auto Result = CPUID->RunFunction(ConstantFunction, 0 /* leaf */); |
nothing calls this directly
no test coverage detected