mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 21:00:17 +02:00
Merge pull request #4585 from alyssarosenzweig/opt/pair-push-pop
Pair push/pop
This commit is contained in:
19 files changed
+265
-222
No files matched your search
@@ -136,11 +136,8 @@ DEF_OP(LoadRegister) {
|
||||
|
||||
if (Op->Class == IR::GPRClass) {
|
||||
LOGMAN_THROW_A_FMT(Op->Reg < StaticRegisters.size(), "out of range reg");
|
||||
const auto reg = StaticRegisters[Op->Reg];
|
||||
|
||||
if (GetReg(Node).Idx() != reg.Idx()) {
|
||||
mov(GetReg(Node).X(), reg.X());
|
||||
}
|
||||
mov(GetReg(Node).X(), StaticRegisters[Op->Reg].X());
|
||||
} else if (Op->Class == IR::FPRClass) {
|
||||
[[maybe_unused]] const auto regSize = HostSupportsAVX256 ? IR::OpSize::i256Bit : IR::OpSize::i128Bit;
|
||||
LOGMAN_THROW_A_FMT(Op->Reg < StaticFPRegisters.size(), "out of range reg");
|
||||
@@ -149,12 +146,10 @@ DEF_OP(LoadRegister) {
|
||||
const auto guest = StaticFPRegisters[Op->Reg];
|
||||
const auto host = GetVReg(Node);
|
||||
|
||||
if (host.Idx() != guest.Idx()) {
|
||||
if (HostSupportsAVX256) {
|
||||
mov(ARMEmitter::SubRegSize::i64Bit, host.Z(), PRED_TMP_32B.Merging(), guest.Z());
|
||||
} else {
|
||||
mov(host.Q(), guest.Q());
|
||||
}
|
||||
if (HostSupportsAVX256) {
|
||||
mov(ARMEmitter::SubRegSize::i64Bit, host.Z(), PRED_TMP_32B.Merging(), guest.Z());
|
||||
} else {
|
||||
mov(host.Q(), guest.Q());
|
||||
}
|
||||
} else {
|
||||
LOGMAN_THROW_A_FMT(false, "Unhandled Op->Class {}", Op->Class);
|
||||
@@ -187,12 +182,9 @@ DEF_OP(StoreRegister) {
|
||||
|
||||
LOGMAN_THROW_A_FMT(Reg < StaticRegisters.size(), "out of range reg");
|
||||
const auto reg = StaticRegisters[Reg];
|
||||
const auto Src = GetReg(Op->Value);
|
||||
|
||||
if (Src.Idx() != reg.Idx()) {
|
||||
// Always use 64-bit, it's faster. Upper bits ignored for 32-bit mode.
|
||||
mov(ARMEmitter::Size::i64Bit, reg, Src);
|
||||
}
|
||||
// Always use 64-bit, it's faster. Upper bits ignored for 32-bit mode.
|
||||
mov(ARMEmitter::Size::i64Bit, reg, GetReg(Op->Value));
|
||||
} else if (Op->Class == IR::FPRClass) {
|
||||
[[maybe_unused]] const auto regSize = HostSupportsAVX256 ? IR::OpSize::i256Bit : IR::OpSize::i128Bit;
|
||||
LOGMAN_THROW_A_FMT(Op->Reg < StaticFPRegisters.size(), "reg out of range");
|
||||
@@ -201,12 +193,10 @@ DEF_OP(StoreRegister) {
|
||||
const auto guest = StaticFPRegisters[Op->Reg];
|
||||
const auto host = GetVReg(Op->Value);
|
||||
|
||||
if (guest.Idx() != host.Idx()) {
|
||||
if (HostSupportsAVX256) {
|
||||
mov(ARMEmitter::SubRegSize::i64Bit, guest.Z(), PRED_TMP_32B.Merging(), host.Z());
|
||||
} else {
|
||||
mov(guest.Q(), host.Q());
|
||||
}
|
||||
if (HostSupportsAVX256) {
|
||||
mov(ARMEmitter::SubRegSize::i64Bit, guest.Z(), PRED_TMP_32B.Merging(), host.Z());
|
||||
} else {
|
||||
mov(guest.Q(), host.Q());
|
||||
}
|
||||
} else {
|
||||
LOGMAN_THROW_A_FMT(false, "Unhandled Op->Class {}", Op->Class);
|
||||
@@ -1525,6 +1515,29 @@ DEF_OP(Push) {
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(PushTwo) {
|
||||
const auto Op = IROp->C<IR::IROp_PushTwo>();
|
||||
const auto ValueSize = IR::OpSizeToSize(Op->ValueSize);
|
||||
auto Src1 = GetReg(Op->Value1);
|
||||
auto Src2 = GetReg(Op->Value2);
|
||||
const auto Dst = GetReg(Op->Addr);
|
||||
|
||||
switch (ValueSize) {
|
||||
case 4: {
|
||||
stp<ARMEmitter::IndexType::PRE>(Src1.W(), Src2.W(), Dst, -2 * ValueSize);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
stp<ARMEmitter::IndexType::PRE>(Src1.X(), Src2.X(), Dst, -2 * ValueSize);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, ValueSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(Pop) {
|
||||
const auto Op = IROp->C<IR::IROp_Pop>();
|
||||
const auto Size = IR::OpSizeToSize(Op->Size);
|
||||
@@ -1557,6 +1570,37 @@ DEF_OP(Pop) {
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(PopTwo) {
|
||||
const auto Op = IROp->C<IR::IROp_PopTwo>();
|
||||
const auto Size = IR::OpSizeToSize(Op->Size);
|
||||
const auto Addr = GetReg(Op->InoutAddr);
|
||||
auto Dst1 = GetReg(Op->OutValue1);
|
||||
const auto Dst2 = GetReg(Op->OutValue2);
|
||||
|
||||
// ldp x, x is invalid. Explicitly discard the first destination to encode.
|
||||
if (Dst1 == Dst2) {
|
||||
Dst1 = ARMEmitter::Reg::zr;
|
||||
}
|
||||
|
||||
LOGMAN_THROW_A_FMT(Dst1 != Addr && Dst2 != Addr, "Invalid");
|
||||
LOGMAN_THROW_A_FMT(Dst1 != Dst2, "Invalid");
|
||||
|
||||
switch (Size) {
|
||||
case 4: {
|
||||
ldp<ARMEmitter::IndexType::POST>(Dst1.W(), Dst2.W(), Addr, 2 * Size);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
ldp<ARMEmitter::IndexType::POST>(Dst1.X(), Dst2.X(), Addr, 2 * Size);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOGMAN_MSG_A_FMT("Unhandled {} size: {}", __func__, Op->Size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(StoreMem) {
|
||||
const auto Op = IROp->C<IR::IROp_StoreMem>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
@@ -17,10 +17,6 @@ $end_info$
|
||||
|
||||
namespace FEXCore::CPU {
|
||||
|
||||
DEF_OP(AllocateGPR) {}
|
||||
DEF_OP(AllocateGPRAfter) {}
|
||||
DEF_OP(AllocateFPR) {}
|
||||
|
||||
DEF_OP(GuestOpcode) {
|
||||
auto Op = IROp->C<IR::IROp_GuestOpcode>();
|
||||
// metadata
|
||||
|
||||
@@ -15,13 +15,7 @@ DEF_OP(Copy) {
|
||||
}
|
||||
|
||||
DEF_OP(RMWHandle) {
|
||||
auto Op = IROp->C<IR::IROp_RMWHandle>();
|
||||
auto Dest = GetReg(Node);
|
||||
auto Src = GetReg(Op->Value);
|
||||
|
||||
if (Dest != Src) {
|
||||
mov(ARMEmitter::Size::i64Bit, Dest, Src);
|
||||
}
|
||||
mov(ARMEmitter::Size::i64Bit, GetReg(Node), GetReg(IROp->Args[0]));
|
||||
}
|
||||
|
||||
DEF_OP(Swap1) {
|
||||
|
||||
@@ -355,68 +355,29 @@ void OpDispatchBuilder::SALCOp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::PUSHOp(OpcodeArgs) {
|
||||
const auto Size = OpSizeFromSrc(Op);
|
||||
|
||||
Ref Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
Push(Size, Src);
|
||||
FlushRegisterCache();
|
||||
Push(Size, LoadSource(GPRClass, Op, Op->Src[0], Op->Flags));
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::PUSHREGOp(OpcodeArgs) {
|
||||
const auto Size = OpSizeFromSrc(Op);
|
||||
|
||||
Ref Src = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true});
|
||||
|
||||
Push(Size, Src);
|
||||
FlushRegisterCache();
|
||||
Push(Size, LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}));
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::PUSHAOp(OpcodeArgs) {
|
||||
// 32bit only
|
||||
const auto Size = OpSizeFromSrc(Op);
|
||||
|
||||
auto OldSP = LoadGPRRegister(X86State::REG_RSP);
|
||||
Ref OldSP = _Copy(LoadGPRRegister(X86State::REG_RSP));
|
||||
|
||||
// PUSHA order:
|
||||
// Tmp = SP
|
||||
// push EAX
|
||||
// push ECX
|
||||
// push EDX
|
||||
// push EBX
|
||||
// push Tmp
|
||||
// push EBP
|
||||
// push ESI
|
||||
// push EDI
|
||||
|
||||
Ref Src {};
|
||||
Ref NewSP = OldSP;
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
|
||||
Src = LoadGPRRegister(X86State::REG_RAX);
|
||||
NewSP = _Push(GPRSize, Size, Src, NewSP);
|
||||
|
||||
Src = LoadGPRRegister(X86State::REG_RCX);
|
||||
NewSP = _Push(GPRSize, Size, Src, NewSP);
|
||||
|
||||
Src = LoadGPRRegister(X86State::REG_RDX);
|
||||
NewSP = _Push(GPRSize, Size, Src, NewSP);
|
||||
|
||||
Src = LoadGPRRegister(X86State::REG_RBX);
|
||||
NewSP = _Push(GPRSize, Size, Src, NewSP);
|
||||
|
||||
// Push old-sp
|
||||
NewSP = _Push(GPRSize, Size, OldSP, NewSP);
|
||||
|
||||
Src = LoadGPRRegister(X86State::REG_RBP);
|
||||
NewSP = _Push(GPRSize, Size, Src, NewSP);
|
||||
|
||||
Src = LoadGPRRegister(X86State::REG_RSI);
|
||||
NewSP = _Push(GPRSize, Size, Src, NewSP);
|
||||
|
||||
Src = LoadGPRRegister(X86State::REG_RDI);
|
||||
NewSP = _Push(GPRSize, Size, Src, NewSP);
|
||||
|
||||
// Store the new stack pointer
|
||||
StoreGPRRegister(X86State::REG_RSP, NewSP, OpSize::i32Bit);
|
||||
FlushRegisterCache();
|
||||
Push(Size, LoadGPRRegister(X86State::REG_RAX));
|
||||
Push(Size, LoadGPRRegister(X86State::REG_RCX));
|
||||
Push(Size, LoadGPRRegister(X86State::REG_RDX));
|
||||
Push(Size, LoadGPRRegister(X86State::REG_RBX));
|
||||
Push(Size, OldSP);
|
||||
Push(Size, LoadGPRRegister(X86State::REG_RBP));
|
||||
Push(Size, LoadGPRRegister(X86State::REG_RSI));
|
||||
Push(Size, LoadGPRRegister(X86State::REG_RDI));
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::PUSHSegmentOp(OpcodeArgs, uint32_t SegmentReg) {
|
||||
@@ -3594,8 +3555,7 @@ void OpDispatchBuilder::BSWAPOp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::PUSHFOp(OpcodeArgs) {
|
||||
const auto Size = OpSizeFromSrc(Op);
|
||||
|
||||
Ref Src = GetPackedRFLAG();
|
||||
Push(Size, Src);
|
||||
Push(Size, GetPackedRFLAG());
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::POPFOp(OpcodeArgs) {
|
||||
|
||||
@@ -2498,6 +2498,7 @@ private:
|
||||
auto OldSP = LoadGPRRegister(X86State::REG_RSP);
|
||||
auto NewSP = _Push(CTX->GetGPROpSize(), Size, Value, OldSP);
|
||||
StoreGPRRegister(X86State::REG_RSP, NewSP);
|
||||
FlushRegisterCache();
|
||||
}
|
||||
|
||||
void InstallHostSpecificOpcodeHandlers();
|
||||
|
||||
@@ -254,19 +254,22 @@
|
||||
"it cannot use a regular destination too. This ensures RA correctness.",
|
||||
"This is a kludge to deal with the IR's lack of multiple destinations",
|
||||
"If ForPair is set, RA will try to allocate the base of a register pair"],
|
||||
"DestSize": "OpSize::i64Bit"
|
||||
"DestSize": "OpSize::i64Bit",
|
||||
"JITDispatch": false
|
||||
},
|
||||
"FPR = AllocateFPR OpSize:#RegisterSize, OpSize:#ElementSize": {
|
||||
"Desc": ["Like AllocateGPR, but for FPR"],
|
||||
"DestSize": "RegisterSize",
|
||||
"ElementSize": "ElementSize"
|
||||
"ElementSize": "ElementSize",
|
||||
"JITDispatch": false
|
||||
},
|
||||
"GPR = AllocateGPRAfter GPR:$After": {
|
||||
"Desc": ["Silly pseudo-instruction to allocate a register for a future destination",
|
||||
"This is a kludge to deal with the IR's lack of multiple destinations",
|
||||
"RA will attempt to allocate to the register after $After.",
|
||||
"It may not succeed."],
|
||||
"DestSize": "OpSize::i64Bit"
|
||||
"DestSize": "OpSize::i64Bit",
|
||||
"JITDispatch": false
|
||||
},
|
||||
"GPR = RDRAND i1:$GetReseeded": {
|
||||
"Desc": ["Uses the hardware random number generator to generate a 64bit number",
|
||||
@@ -668,6 +671,13 @@
|
||||
"HasSideEffects": true,
|
||||
"DestSize": "Size"
|
||||
},
|
||||
"PushTwo OpSize:#Size, OpSize:$ValueSize, GPR:$Value1, GPR:$Value2, GPR:$Addr": {
|
||||
"Desc": [
|
||||
"Push two values to the address, incrementing the pointer in the place.",
|
||||
"Fused post-RA so doesn't have a destination."
|
||||
],
|
||||
"HasSideEffects": true
|
||||
},
|
||||
"GPR = RMWHandle GPR:$Value": {
|
||||
"Desc": [
|
||||
"This is a special move that indicates the result will be poisoned by a non-SSA instruction writing to its result.",
|
||||
@@ -685,6 +695,11 @@
|
||||
"HasSideEffects": true,
|
||||
"DestSize": "Size"
|
||||
},
|
||||
"GPR:$Addr, GPR:$Value1, GPR:$Value2 = PopTwo OpSize:$Size, GPR:$Addr": {
|
||||
"Desc": ["Pop two values from the address. Fused post-RA."],
|
||||
"HasSideEffects": true,
|
||||
"DestSize": "Size"
|
||||
},
|
||||
"GPR = MemSet i1:$IsAtomic, OpSize:$Size, GPR:$Prefix, GPR:$Addr, GPR:$Value, GPR:$Length, GPR:$Direction": {
|
||||
"Desc": ["Duplicates behaviour of x86 STOS repeat",
|
||||
"Returns the final address that gets generated without the prefix appended."
|
||||
|
||||
@@ -146,6 +146,10 @@ void IREmitter::RemoveArgUses(Ref Node) {
|
||||
}
|
||||
}
|
||||
|
||||
void IREmitter::RemovePostRA(Ref Node) {
|
||||
Node->Unlink(DualListData.ListBegin());
|
||||
}
|
||||
|
||||
void IREmitter::Remove(Ref Node) {
|
||||
RemoveArgUses(Node);
|
||||
|
||||
|
||||
@@ -219,6 +219,7 @@ public:
|
||||
void ReplaceNodeArgument(Ref Node, uint8_t Arg, Ref NewArg);
|
||||
|
||||
void Remove(Ref Node);
|
||||
void RemovePostRA(Ref Node);
|
||||
|
||||
void SetPackedRFLAG(bool Lower8, Ref Src);
|
||||
Ref GetPackedRFLAG(bool Lower8);
|
||||
|
||||
@@ -57,6 +57,7 @@ class ConstrainedRAPass final : public RegisterAllocationPass {
|
||||
public:
|
||||
void Run(IREmitter* IREmit) override;
|
||||
void AddRegisters(IR::RegisterClassType Class, uint32_t RegisterCount) override;
|
||||
bool TryPostRAMerge(Ref LastNode, Ref CodeNode, IROp_Header* IROp);
|
||||
|
||||
private:
|
||||
RegisterClass Classes[INVALID_CLASS];
|
||||
@@ -197,6 +198,18 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
bool IsTrivial(Ref Node, const IROp_Header* Header) {
|
||||
switch (Header->Op) {
|
||||
case OP_ALLOCATEGPR: return true;
|
||||
case OP_ALLOCATEGPRAFTER: return true;
|
||||
case OP_ALLOCATEFPR: return true;
|
||||
case OP_RMWHANDLE: return PhysicalRegister(Node) == PhysicalRegister(Header->Args[0]);
|
||||
case OP_LOADREGISTER: return PhysicalRegister(Node) == DecodeSRAReg(Header);
|
||||
case OP_STOREREGISTER: return PhysicalRegister(Header->Args[0]) == DecodeSRAReg(Header);
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper macro to walk the set bits b in a 32-bit word x, using ffs to get
|
||||
// the next set bit and then clearing on each iteration.
|
||||
#define foreach_bit(b, x) for (uint32_t __x = (x), b; ((b) = __builtin_ffs(__x) - 1, __x); __x &= ~(1 << (b)))
|
||||
@@ -362,10 +375,6 @@ private:
|
||||
unsigned Reg = std::countr_zero(Class->Available);
|
||||
SetReg(CodeNode, PhysicalRegister(ClassType, Reg));
|
||||
};
|
||||
|
||||
bool IsRAOp(IROps Op) {
|
||||
return Op == OP_SPILLREGISTER || Op == OP_FILLREGISTER || Op == OP_COPY;
|
||||
};
|
||||
};
|
||||
|
||||
void ConstrainedRAPass::AddRegisters(IR::RegisterClassType Class, uint32_t RegisterCount) {
|
||||
@@ -374,6 +383,37 @@ void ConstrainedRAPass::AddRegisters(IR::RegisterClassType Class, uint32_t Regis
|
||||
Classes[Class].Count = RegisterCount;
|
||||
}
|
||||
|
||||
bool ConstrainedRAPass::TryPostRAMerge(Ref LastNode, Ref CodeNode, IROp_Header* IROp) {
|
||||
if (IROp->Op == OP_PUSH) {
|
||||
auto LastOp = IR->GetOp<IROp_Header>(LastNode);
|
||||
if (LastOp->Op == OP_PUSH) {
|
||||
auto SP = PhysicalRegister(CodeNode);
|
||||
auto Push = IR->GetOp<IROp_Push>(CodeNode);
|
||||
auto LastPush = IR->GetOp<IROp_Push>(LastNode);
|
||||
|
||||
if (LastOp->Size == IROp->Size && LastPush->ValueSize == Push->ValueSize && SP == PhysicalRegister(LastNode) &&
|
||||
SP == PhysicalRegister(IROp->Args[1]) && SP == PhysicalRegister(LastOp->Args[1]) && SP != PhysicalRegister(IROp->Args[0]) &&
|
||||
SP != PhysicalRegister(LastOp->Args[0]) && Push->ValueSize >= OpSize::i32Bit) {
|
||||
|
||||
IREmit->SetWriteCursorBefore(LastNode);
|
||||
IREmit->_PushTwo(IROp->Size, Push->ValueSize, IROp->Args[0], LastOp->Args[0], IROp->Args[1]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (IROp->Op == OP_POP) {
|
||||
auto LastOp = IR->GetOp<IROp_Header>(LastNode);
|
||||
auto SP = PhysicalRegister(IROp->Args[0]);
|
||||
|
||||
if (LastOp->Op == OP_POP && LastOp->Size == IROp->Size && IROp->Size >= OpSize::i32Bit && SP == PhysicalRegister(LastOp->Args[0])) {
|
||||
IREmit->SetWriteCursorBefore(LastNode);
|
||||
IREmit->_PopTwo(IROp->Size, IROp->Args[0], LastOp->Args[1], IROp->Args[1]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConstrainedRAPass::Run(IREmitter* IREmit_) {
|
||||
FEXCORE_PROFILE_SCOPED("PassManager::RA");
|
||||
|
||||
@@ -474,9 +514,17 @@ void ConstrainedRAPass::Run(IREmitter* IREmit_) {
|
||||
// SourcesNextUses is read backwards, this tracks the index
|
||||
int64_t SourceIndex = SourcesNextUses.size();
|
||||
|
||||
// Forward pass: Assign registers, spilling as we go.
|
||||
// Last nontrivial instruction, for merging as we go.
|
||||
Ref LastNode = nullptr;
|
||||
|
||||
// Forward pass: Assign registers, spilling & optimizing as we go.
|
||||
for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) {
|
||||
LOGMAN_THROW_A_FMT(!IsRAOp(IROp->Op), "RA ops inserted before, so not seen iterating forward");
|
||||
// GuestOpcode does not read or write registers, and must be skipped for
|
||||
// push/pop merging. Since we'd be doing this check anyway for merging, do
|
||||
// the check now so we can skip the rest of the logic too.
|
||||
if (IROp->Op == OP_GUESTOPCODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Static registers must be consistent at SRA load/store. Evict to ensure.
|
||||
if (auto Node = DecodeSRANode(IROp, CodeNode); Node != nullptr) {
|
||||
@@ -555,8 +603,17 @@ void ConstrainedRAPass::Run(IREmitter* IREmit_) {
|
||||
AssignReg(IROp, CodeNode, IROp);
|
||||
}
|
||||
|
||||
LOGMAN_THROW_A_FMT(IP >= 1, "IP relative to end of block, iterating forward");
|
||||
--IP;
|
||||
if (IsTrivial(CodeNode, IROp)) {
|
||||
// Delete instructions that only exist for RA
|
||||
IREmit->RemovePostRA(CodeNode);
|
||||
} else if (LastNode && TryPostRAMerge(LastNode, CodeNode, IROp)) {
|
||||
// Merge adjacent instructions
|
||||
IREmit->RemovePostRA(CodeNode);
|
||||
IREmit->RemovePostRA(LastNode);
|
||||
LastNode = nullptr;
|
||||
} else {
|
||||
LastNode = CodeNode;
|
||||
}
|
||||
}
|
||||
|
||||
LOGMAN_THROW_A_FMT(SourceIndex == 0, "Consistent source count in block");
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "123",
|
||||
"RBX": "456",
|
||||
"RCX": "123"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
; FEX had a bug merging pops to the same register
|
||||
|
||||
; Push some stuff
|
||||
mov rsp, 0xe0000010
|
||||
mov rax, 123
|
||||
mov rbx, 456
|
||||
push rax
|
||||
push rbx
|
||||
|
||||
; Pop into the same register
|
||||
pop rcx
|
||||
pop rcx
|
||||
|
||||
; rcx now equals rax
|
||||
hlt
|
||||
@@ -34,7 +34,7 @@
|
||||
},
|
||||
"push rax, rbx": {
|
||||
"x86InstructionCount": 2,
|
||||
"ExpectedInstructionCount": 2,
|
||||
"ExpectedInstructionCount": 1,
|
||||
"Comment": [
|
||||
"Mergable 64-bit pushes"
|
||||
],
|
||||
@@ -43,8 +43,7 @@
|
||||
"push rbx"
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"str x4, [x8, #-8]!",
|
||||
"str x6, [x8, #-8]!"
|
||||
"stp x6, x4, [x8, #-16]!"
|
||||
]
|
||||
},
|
||||
"adds xmm0, xmm1, xmm2": {
|
||||
@@ -1056,7 +1055,7 @@
|
||||
},
|
||||
"Sekiro spill block": {
|
||||
"x86InstructionCount": 119,
|
||||
"ExpectedInstructionCount": 126,
|
||||
"ExpectedInstructionCount": 118,
|
||||
"Comment": [
|
||||
"This block of code came from the settings screen when it loaded",
|
||||
"It was originally at RIP: 0x14232cca0 and has been deobfuscated"
|
||||
@@ -1184,14 +1183,10 @@
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"str x7, [x8, #8]",
|
||||
"str x6, [x8, #-8]!",
|
||||
"str x9, [x8, #-8]!",
|
||||
"str x10, [x8, #-8]!",
|
||||
"str x11, [x8, #-8]!",
|
||||
"str x16, [x8, #-8]!",
|
||||
"str x17, [x8, #-8]!",
|
||||
"str x19, [x8, #-8]!",
|
||||
"str x29, [x8, #-8]!",
|
||||
"stp x9, x6, [x8, #-16]!",
|
||||
"stp x11, x10, [x8, #-16]!",
|
||||
"stp x17, x16, [x8, #-16]!",
|
||||
"stp x29, x19, [x8, #-16]!",
|
||||
"sub x8, x8, #0x18 (24)",
|
||||
"ldr w7, [x5, #36]",
|
||||
"ldr w10, [x5]",
|
||||
@@ -1300,14 +1295,10 @@
|
||||
"mvn w27, w8",
|
||||
"adds x26, x8, #0x18 (24)",
|
||||
"mov x8, x26",
|
||||
"ldr x29, [x8], #8",
|
||||
"ldr x19, [x8], #8",
|
||||
"ldr x17, [x8], #8",
|
||||
"ldr x16, [x8], #8",
|
||||
"ldr x11, [x8], #8",
|
||||
"ldr x10, [x8], #8",
|
||||
"ldr x9, [x8], #8",
|
||||
"ldr x6, [x8], #8",
|
||||
"ldp x29, x19, [x8], #16",
|
||||
"ldp x17, x16, [x8], #16",
|
||||
"ldp x11, x10, [x8], #16",
|
||||
"ldp x9, x6, [x8], #16",
|
||||
"cfinv"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -253,7 +253,7 @@
|
||||
},
|
||||
"bytemark DivideInternalFPF": {
|
||||
"x86InstructionCount": 13,
|
||||
"ExpectedInstructionCount": 15,
|
||||
"ExpectedInstructionCount": 12,
|
||||
"Comment": [
|
||||
"Saw this in bytemark"
|
||||
],
|
||||
@@ -273,12 +273,9 @@
|
||||
"cmp eax,0x18"
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"str x9, [x8, #-8]!",
|
||||
"str x29, [x8, #-8]!",
|
||||
"str x19, [x8, #-8]!",
|
||||
"str x17, [x8, #-8]!",
|
||||
"str x16, [x8, #-8]!",
|
||||
"str x6, [x8, #-8]!",
|
||||
"stp x29, x9, [x8, #-16]!",
|
||||
"stp x17, x19, [x8, #-16]!",
|
||||
"stp x6, x16, [x8, #-16]!",
|
||||
"sub x8, x8, #0x18 (24)",
|
||||
"str x5, [x8]",
|
||||
"ldrb w14, [x11]",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"Instructions": {
|
||||
"The Sims 1 hot block": {
|
||||
"x86InstructionCount": 47,
|
||||
"ExpectedInstructionCount": 98,
|
||||
"ExpectedInstructionCount": 97,
|
||||
"Comment": [
|
||||
"Hottest in-game block from The Sims 1, Legacy Collection",
|
||||
"Consumed 6.13% of a CPU core on Oryon-1",
|
||||
@@ -92,8 +92,7 @@
|
||||
"stlur w4, [x9, #-4]",
|
||||
"ldapur w5, [x9, #8]",
|
||||
"nop",
|
||||
"str w6, [x8, #-4]!",
|
||||
"str w10, [x8, #-4]!",
|
||||
"stp w10, w6, [x8, #-8]!",
|
||||
"ldapur w10, [x9, #24]",
|
||||
"nop",
|
||||
"str w11, [x8, #-4]!",
|
||||
|
||||
@@ -247,67 +247,51 @@
|
||||
]
|
||||
},
|
||||
"pusha": {
|
||||
"ExpectedInstructionCount": 10,
|
||||
"ExpectedInstructionCount": 5,
|
||||
"Comment": "0x60",
|
||||
"ExpectedArm64ASM": [
|
||||
"mov w20, w8",
|
||||
"str w4, [x20, #-4]!",
|
||||
"str w7, [x20, #-4]!",
|
||||
"str w5, [x20, #-4]!",
|
||||
"str w6, [x20, #-4]!",
|
||||
"str w8, [x20, #-4]!",
|
||||
"str w9, [x20, #-4]!",
|
||||
"str w10, [x20, #-4]!",
|
||||
"mov w8, w20",
|
||||
"str w11, [x8, #-4]!"
|
||||
"mov x20, x8",
|
||||
"stp w7, w4, [x8, #-8]!",
|
||||
"stp w6, w5, [x8, #-8]!",
|
||||
"stp w9, w20, [x8, #-8]!",
|
||||
"stp w11, w10, [x8, #-8]!"
|
||||
]
|
||||
},
|
||||
"pushad": {
|
||||
"ExpectedInstructionCount": 10,
|
||||
"ExpectedInstructionCount": 5,
|
||||
"Comment": "0x60",
|
||||
"ExpectedArm64ASM": [
|
||||
"mov w20, w8",
|
||||
"str w4, [x20, #-4]!",
|
||||
"str w7, [x20, #-4]!",
|
||||
"str w5, [x20, #-4]!",
|
||||
"str w6, [x20, #-4]!",
|
||||
"str w8, [x20, #-4]!",
|
||||
"str w9, [x20, #-4]!",
|
||||
"str w10, [x20, #-4]!",
|
||||
"mov w8, w20",
|
||||
"str w11, [x8, #-4]!"
|
||||
"mov x20, x8",
|
||||
"stp w7, w4, [x8, #-8]!",
|
||||
"stp w6, w5, [x8, #-8]!",
|
||||
"stp w9, w20, [x8, #-8]!",
|
||||
"stp w11, w10, [x8, #-8]!"
|
||||
]
|
||||
},
|
||||
"popa": {
|
||||
"ExpectedInstructionCount": 10,
|
||||
"ExpectedInstructionCount": 7,
|
||||
"Comment": "0x61",
|
||||
"ExpectedArm64ASM": [
|
||||
"mov x20, x8",
|
||||
"ldr w11, [x20], #4",
|
||||
"ldr w10, [x20], #4",
|
||||
"ldp w11, w10, [x20], #8",
|
||||
"ldr w9, [x20], #4",
|
||||
"add x20, x20, #0x4 (4)",
|
||||
"mov x8, x20",
|
||||
"ldr w6, [x8], #4",
|
||||
"ldr w5, [x8], #4",
|
||||
"ldr w7, [x8], #4",
|
||||
"ldr w4, [x8], #4"
|
||||
"ldp w6, w5, [x8], #8",
|
||||
"ldp w7, w4, [x8], #8"
|
||||
]
|
||||
},
|
||||
"popad": {
|
||||
"ExpectedInstructionCount": 10,
|
||||
"ExpectedInstructionCount": 7,
|
||||
"Comment": "0x61",
|
||||
"ExpectedArm64ASM": [
|
||||
"mov x20, x8",
|
||||
"ldr w11, [x20], #4",
|
||||
"ldr w10, [x20], #4",
|
||||
"ldp w11, w10, [x20], #8",
|
||||
"ldr w9, [x20], #4",
|
||||
"add x20, x20, #0x4 (4)",
|
||||
"mov x8, x20",
|
||||
"ldr w6, [x8], #4",
|
||||
"ldr w5, [x8], #4",
|
||||
"ldr w7, [x8], #4",
|
||||
"ldr w4, [x8], #4"
|
||||
"ldp w6, w5, [x8], #8",
|
||||
"ldp w7, w4, [x8], #8"
|
||||
]
|
||||
},
|
||||
"o16 pushf": {
|
||||
|
||||
@@ -8585,8 +8585,7 @@
|
||||
"fmov s2, s0",
|
||||
"str s2, [x7, #960]",
|
||||
"mov x8, x9",
|
||||
"ldr w9, [x8], #4",
|
||||
"ldr w20, [x8], #4",
|
||||
"ldp w9, w20, [x8], #8",
|
||||
"ldrb w21, [x28, #1019]",
|
||||
"add w21, w21, #0x3 (3)",
|
||||
"and w21, w21, #0x7",
|
||||
@@ -8597,7 +8596,7 @@
|
||||
"strb w21, [x28, #1298]"
|
||||
],
|
||||
"x86InstructionCount": 809,
|
||||
"ExpectedInstructionCount": 7770
|
||||
"ExpectedInstructionCount": 7769
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1063,7 +1063,7 @@
|
||||
},
|
||||
"Block4": {
|
||||
"x86InstructionCount": 54,
|
||||
"ExpectedInstructionCount": 80,
|
||||
"ExpectedInstructionCount": 78,
|
||||
"x86Insts": [
|
||||
"push ebp",
|
||||
"push edi",
|
||||
@@ -1121,10 +1121,8 @@
|
||||
"fld dword [esp + 0x2c]"
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"str w9, [x8, #-4]!",
|
||||
"str w11, [x8, #-4]!",
|
||||
"str w10, [x8, #-4]!",
|
||||
"str w6, [x8, #-4]!",
|
||||
"stp w11, w9, [x8, #-8]!",
|
||||
"stp w6, w10, [x8, #-8]!",
|
||||
"subs w26, w8, #0x4c (76)",
|
||||
"mov x27, x8",
|
||||
"mov x8, x26",
|
||||
@@ -1564,7 +1562,7 @@
|
||||
},
|
||||
"Block6": {
|
||||
"x86InstructionCount": 39,
|
||||
"ExpectedInstructionCount": 297,
|
||||
"ExpectedInstructionCount": 295,
|
||||
"x86Insts": [
|
||||
"push ebp",
|
||||
"push edi",
|
||||
@@ -1607,10 +1605,8 @@
|
||||
"fstp st1"
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"str w9, [x8, #-4]!",
|
||||
"str w11, [x8, #-4]!",
|
||||
"str w10, [x8, #-4]!",
|
||||
"str w6, [x8, #-4]!",
|
||||
"stp w11, w9, [x8, #-8]!",
|
||||
"stp w6, w10, [x8, #-8]!",
|
||||
"subs w20, w8, #0x4 (4)",
|
||||
"mov x27, x8",
|
||||
"mov x8, x20",
|
||||
@@ -2611,7 +2607,7 @@
|
||||
},
|
||||
"Block10": {
|
||||
"x86InstructionCount": 125,
|
||||
"ExpectedInstructionCount": 22,
|
||||
"ExpectedInstructionCount": 21,
|
||||
"x86Insts": [
|
||||
"push esi",
|
||||
"push ebx",
|
||||
@@ -2740,8 +2736,7 @@
|
||||
"xor eax,dword gs:[0x14]"
|
||||
],
|
||||
"ExpectedArm64ASM": [
|
||||
"str w10, [x8, #-4]!",
|
||||
"str w6, [x8, #-4]!",
|
||||
"stp w6, w10, [x8, #-8]!",
|
||||
"sub w8, w8, #0xa4 (164)",
|
||||
"ldr w6, [x8, #176]",
|
||||
"add w10, w8, #0x18 (24)",
|
||||
|
||||
@@ -17705,7 +17705,7 @@
|
||||
},
|
||||
"Block4": {
|
||||
"x86InstructionCount": 2050,
|
||||
"ExpectedInstructionCount": 40,
|
||||
"ExpectedInstructionCount": 39,
|
||||
"x86Insts": [
|
||||
"fldz",
|
||||
"push 0x0",
|
||||
@@ -19768,8 +19768,7 @@
|
||||
"movk w21, #0x100, lsl #16",
|
||||
"str w21, [x8, #-4]!",
|
||||
"mov w21, #0x37",
|
||||
"str w21, [x8, #-4]!",
|
||||
"str w7, [x8, #-4]!",
|
||||
"stp w7, w21, [x8, #-8]!",
|
||||
"str x30, [sp, #-16]!",
|
||||
"mov v0.16b, v2.16b",
|
||||
"ldr x0, [x28, #1456]",
|
||||
|
||||
@@ -26756,7 +26756,7 @@
|
||||
},
|
||||
"Block8": {
|
||||
"x86InstructionCount": 231,
|
||||
"ExpectedInstructionCount": 3724,
|
||||
"ExpectedInstructionCount": 3723,
|
||||
"x86Insts": [
|
||||
"fadd dword [esp + 0x40]",
|
||||
"lea edx,[ecx + ecx*0x2]",
|
||||
@@ -30693,8 +30693,7 @@
|
||||
"add w20, w20, #0x1 (1)",
|
||||
"and w20, w20, #0x7",
|
||||
"strb w20, [x28, #1019]",
|
||||
"ldr w11, [x8], #4",
|
||||
"ldr w10, [x8], #4",
|
||||
"ldp w11, w10, [x8], #8",
|
||||
"ldrb w22, [x28, #1298]",
|
||||
"lsl w23, w21, w20",
|
||||
"bic w22, w22, w23",
|
||||
@@ -30719,7 +30718,7 @@
|
||||
},
|
||||
"Block9": {
|
||||
"x86InstructionCount": 222,
|
||||
"ExpectedInstructionCount": 3646,
|
||||
"ExpectedInstructionCount": 3645,
|
||||
"x86Insts": [
|
||||
"fadd dword [esp + 0x40]",
|
||||
"lea edx,[ecx + ecx*0x2]",
|
||||
@@ -34569,8 +34568,7 @@
|
||||
"add w20, w20, #0x1 (1)",
|
||||
"and w20, w20, #0x7",
|
||||
"strb w20, [x28, #1019]",
|
||||
"ldr w11, [x8], #4",
|
||||
"ldr w10, [x8], #4",
|
||||
"ldp w11, w10, [x8], #8",
|
||||
"ldrb w22, [x28, #1298]",
|
||||
"lsl w23, w21, w20",
|
||||
"bic w22, w22, w23",
|
||||
|
||||
@@ -262,67 +262,51 @@
|
||||
]
|
||||
},
|
||||
"pusha": {
|
||||
"ExpectedInstructionCount": 10,
|
||||
"ExpectedInstructionCount": 5,
|
||||
"Comment": "0x60",
|
||||
"ExpectedArm64ASM": [
|
||||
"mov w20, w8",
|
||||
"str w4, [x20, #-4]!",
|
||||
"str w7, [x20, #-4]!",
|
||||
"str w5, [x20, #-4]!",
|
||||
"str w6, [x20, #-4]!",
|
||||
"str w8, [x20, #-4]!",
|
||||
"str w9, [x20, #-4]!",
|
||||
"str w10, [x20, #-4]!",
|
||||
"mov w8, w20",
|
||||
"str w11, [x8, #-4]!"
|
||||
"mov x20, x8",
|
||||
"stp w7, w4, [x8, #-8]!",
|
||||
"stp w6, w5, [x8, #-8]!",
|
||||
"stp w9, w20, [x8, #-8]!",
|
||||
"stp w11, w10, [x8, #-8]!"
|
||||
]
|
||||
},
|
||||
"pushad": {
|
||||
"ExpectedInstructionCount": 10,
|
||||
"ExpectedInstructionCount": 5,
|
||||
"Comment": "0x60",
|
||||
"ExpectedArm64ASM": [
|
||||
"mov w20, w8",
|
||||
"str w4, [x20, #-4]!",
|
||||
"str w7, [x20, #-4]!",
|
||||
"str w5, [x20, #-4]!",
|
||||
"str w6, [x20, #-4]!",
|
||||
"str w8, [x20, #-4]!",
|
||||
"str w9, [x20, #-4]!",
|
||||
"str w10, [x20, #-4]!",
|
||||
"mov w8, w20",
|
||||
"str w11, [x8, #-4]!"
|
||||
"mov x20, x8",
|
||||
"stp w7, w4, [x8, #-8]!",
|
||||
"stp w6, w5, [x8, #-8]!",
|
||||
"stp w9, w20, [x8, #-8]!",
|
||||
"stp w11, w10, [x8, #-8]!"
|
||||
]
|
||||
},
|
||||
"popa": {
|
||||
"ExpectedInstructionCount": 10,
|
||||
"ExpectedInstructionCount": 7,
|
||||
"Comment": "0x61",
|
||||
"ExpectedArm64ASM": [
|
||||
"mov x20, x8",
|
||||
"ldr w11, [x20], #4",
|
||||
"ldr w10, [x20], #4",
|
||||
"ldp w11, w10, [x20], #8",
|
||||
"ldr w9, [x20], #4",
|
||||
"add x20, x20, #0x4 (4)",
|
||||
"mov x8, x20",
|
||||
"ldr w6, [x8], #4",
|
||||
"ldr w5, [x8], #4",
|
||||
"ldr w7, [x8], #4",
|
||||
"ldr w4, [x8], #4"
|
||||
"ldp w6, w5, [x8], #8",
|
||||
"ldp w7, w4, [x8], #8"
|
||||
]
|
||||
},
|
||||
"popad": {
|
||||
"ExpectedInstructionCount": 10,
|
||||
"ExpectedInstructionCount": 7,
|
||||
"Comment": "0x61",
|
||||
"ExpectedArm64ASM": [
|
||||
"mov x20, x8",
|
||||
"ldr w11, [x20], #4",
|
||||
"ldr w10, [x20], #4",
|
||||
"ldp w11, w10, [x20], #8",
|
||||
"ldr w9, [x20], #4",
|
||||
"add x20, x20, #0x4 (4)",
|
||||
"mov x8, x20",
|
||||
"ldr w6, [x8], #4",
|
||||
"ldr w5, [x8], #4",
|
||||
"ldr w7, [x8], #4",
|
||||
"ldr w4, [x8], #4"
|
||||
"ldp w6, w5, [x8], #8",
|
||||
"ldp w7, w4, [x8], #8"
|
||||
]
|
||||
},
|
||||
"aam": {
|
||||
|
||||
Reference in new issue
Block a user