Merge pull request #4585 from alyssarosenzweig/opt/pair-push-pop

Pair push/pop
This commit is contained in:
Ryan Houdek authored and GitHub committed 2025-05-27 09:17:47 -07:00
commit 4928af5a64
19 files changed
+265 -222

No files matched your search

+65 -21
View File
@@ -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();
+18 -3
View File
@@ -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);
+1
View File
@@ -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");
+25
View File
@@ -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",
+20 -36
View File
@@ -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": {