Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/dynarec/arm64/dynarec_arm64_00.c
Original file line number Diff line number Diff line change
Expand Up @@ -4068,8 +4068,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEB(x1, 1);
u8 = F8;
MOV32w(x2, u8);
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
emit_test8c(dyn, ninst, x1, u8, x2, x4, x5);
break;
case 2:
INST_NAME("NOT Eb");
Expand Down
54 changes: 48 additions & 6 deletions src/dynarec/arm64/dynarec_arm64_emit_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,8 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4)
{
IFX_PENDOR0 {
MOV64xw(s4, 0);
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
STRxw_U12(s4, xEmu, offsetof(x64emu_t, op2));
STRxw_U12(xZR, xEmu, offsetof(x64emu_t, op2));
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
} else {
Expand Down Expand Up @@ -198,9 +197,8 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
{
IFX_PENDOR0 {
MOV32w(s3, 0);
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
STRH_U12(wZR, xEmu, offsetof(x64emu_t, op2));
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
SET_DF(s3, d_cmp16);
} else {
Expand Down Expand Up @@ -291,8 +289,7 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
{
IFX_PENDOR0 {
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
MOV32w(s4, 0);
STRB_U12(s4, xEmu, offsetof(x64emu_t, op2));
STRB_U12(wZR, xEmu, offsetof(x64emu_t, op2));
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
SET_DF(s3, d_cmp8);
} else {
Expand Down Expand Up @@ -410,6 +407,19 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
} else {
SET_DFNONE();
}
if((dyn->insts[ninst].x64.gen_flags&(X_ZF|X_PEND)) && !(dyn->insts[ninst].x64.gen_flags&~(X_ZF|X_PEND))) {
ANDSw_REG(s5, s1, s2);
IFX(X_PEND) {
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
}
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETw(s4, cEQ);
BFIw(xFlags, s4, F_ZF, 1);
}
}
return;
}
IFX(X_CF|X_ZF|X_SF|X_OF) {
LSLw(s5, s1, 16);
ANDSw_REG_LSL(s5, s5, s2, 16);
Expand Down Expand Up @@ -458,6 +468,22 @@ void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
} else {
SET_DFNONE();
}
if((dyn->insts[ninst].x64.gen_flags&(X_ZF|X_PEND)) && !(dyn->insts[ninst].x64.gen_flags&~(X_ZF|X_PEND))) {
mask = convert_bitmask_w(c);
if(mask) {
ANDSw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
IFX(X_PEND) {
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
}
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETw(s4, cEQ);
BFIw(xFlags, s4, F_ZF, 1);
}
}
return;
}
}
IFX(X_CF|X_ZF|X_SF|X_OF) {
LSLw(s5, s1, 16);
mask = convert_bitmask_w(c<<16);
Expand Down Expand Up @@ -565,6 +591,22 @@ void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
} else {
SET_DFNONE();
}
if((dyn->insts[ninst].x64.gen_flags&(X_ZF|X_PEND)) && !(dyn->insts[ninst].x64.gen_flags&~(X_ZF|X_PEND))) {
mask = convert_bitmask_w(c);
if(mask) {
ANDSw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
IFX(X_PEND) {
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
}
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETw(s4, cEQ);
BFIw(xFlags, s4, F_ZF, 1);
}
}
return;
}
}
IFX(X_CF|X_ZF|X_SF|X_OF) {
LSLw(s5, s1, 24);
mask = convert_bitmask_w(c<<24);
Expand Down
28 changes: 28 additions & 0 deletions src/dynarec/arm64/dynarec_arm64_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,34 @@ void updateNativeFlags(dynarec_native_t* dyn)
if(flag2native(dyn->insts[ninst].x64.gen_flags,(dyn->insts[ninst].set_nat_flags&NF_PF_V)?1:0) && (dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH)) {
propagateNativeFlags(dyn, ninst);
}
// BOX64_DYNAREC_LOOPFLAGS: a flag producer that ends a block has X_PEND forced
// onto it so the deferred op1/op2/res spill keeps full EFLAGS reconstructable for
// any successor or signal. When the producer's whole real flag need
// (gen_flags & X_ALL) is ZF/SF/CF/OF and reaches its downstream consumers purely
// through native NZCV (e.g. a loop-control CMP feeding a native Jcc), that spill is
// redundant for the branch. Clearing X_PEND makes emit_cmp/emit_test take the
// SET_DFNONE path. ZF/SF/CF/OF stay reconstructable at faults through adjust_arch's
// NZCV overlay (kept in need_nat_flags); only PF/AF turn approximate across the
// block exit, which the dynarec already is for native flags and which the x86 ABI
// (arithmetic flags not preserved across calls) makes safe across the exit.
if(BOX64ENV(dynarec_loopflags))
for(int ninst=0; ninst<dyn->size; ++ninst) {
uint8_t gf = dyn->insts[ninst].x64.gen_flags;
if(!(gf&X_PEND) || dyn->insts[ninst].nat_flags_op!=NAT_FLAG_OP_TOUCH)
continue;
uint8_t xflags = gf & X_ALL;
if(xflags & (X_AF|X_PF)) // native NZCV cannot carry AF/PF at a fault
continue;
int vf_is_p = (dyn->insts[ninst].set_nat_flags&NF_PF_V)?1:0;
uint8_t need_nat = flag2native(xflags, vf_is_p);
if(!need_nat || (dyn->insts[ninst].set_nat_flags & need_nat) != need_nat)
continue; // producer must emit exactly the native flags needed
if(getNativeFlagsUsed(dyn, ninst, need_nat, vf_is_p) != need_nat)
continue; // every real consumer takes them natively, nothing else
// keep all NZCV flags this op sets alive so adjust_arch reconstructs ZF/SF/CF/OF
dyn->insts[ninst].need_nat_flags |= dyn->insts[ninst].set_nat_flags & (NF_EQ|NF_SF|NF_VF|NF_CF);
dyn->insts[ninst].x64.gen_flags = gf & ~X_PEND;
}
}

void rasNativeState(dynarec_arm_t* dyn, int ninst)
Expand Down
1 change: 1 addition & 0 deletions src/include/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ extern char* ftrace_name;
INTEGER(BOX64_DYNAREC_FORWARD, dynarec_forward, 128, 0, 1024, 1, 3) \
STRING(BOX64_DYNAREC_GDBJIT, dynarec_gdbjit_str, 0, 0) \
INTEGER(BOX64_DYNAREC_LOG, dynarec_log, 0, 0, 3, 1, 0) \
INTEGER(BOX64_DYNAREC_LOOPFLAGS, dynarec_loopflags, 0, 0, 1, 1, 2) \
INTEGER(BOX64_DYNAREC_MISSING, dynarec_missing, 0, 0, 2, 1, 0) \
BOOLEAN(BOX64_DYNAREC_NATIVEFLAGS, dynarec_nativeflags, 1, 1, 1) \
STRING(BOX64_DYNAREC_NOHOSTEXT, dynarec_nohostext, 0, 0) \
Expand Down
Loading