diff --git a/src/alloy/backend/x64/lowering/lowering_sequences.cc b/src/alloy/backend/x64/lowering/lowering_sequences.cc index 943a28a5a..d02bcd18d 100644 --- a/src/alloy/backend/x64/lowering/lowering_sequences.cc +++ b/src/alloy/backend/x64/lowering/lowering_sequences.cc @@ -113,13 +113,6 @@ uint64_t LoadClock(void* raw_context) { return time; } -void CallNative(X64Emitter& e, void* target) { - e.mov(e.rax, (uint64_t)target); - e.call(e.rax); - e.mov(e.rcx, e.qword[e.rsp + 0]); - e.mov(e.rdx, e.qword[e.rcx + 8]); // membase -} - // TODO(benvanik): fancy stuff. void* ResolveFunctionSymbol(void* raw_context, FunctionInfo* symbol_info) { // TODO(benvanik): generate this thunk at runtime? or a shim? @@ -1161,6 +1154,8 @@ table->AddSequence(OPCODE_STORE, [](X64Emitter& e, Instr*& i) { // eh? e.bswap(e.r8); CallNative(e, cbs->write); + i = e.Advance(i); + return true; } cbs = cbs->next; } @@ -1534,6 +1529,7 @@ table->AddSequence(OPCODE_COMPARE_UGE, [](X64Emitter& e, Instr*& i) { table->AddSequence(OPCODE_DID_CARRY, [](X64Emitter& e, Instr*& i) { Reg8 dest; e.BeginOp(i->dest, dest, REG_DEST); + LoadEflags(e); e.setc(dest); e.EndOp(dest); i = e.Advance(i); @@ -1543,6 +1539,7 @@ table->AddSequence(OPCODE_DID_CARRY, [](X64Emitter& e, Instr*& i) { table->AddSequence(OPCODE_DID_OVERFLOW, [](X64Emitter& e, Instr*& i) { Reg8 dest; e.BeginOp(i->dest, dest, REG_DEST); + LoadEflags(e); e.seto(dest); e.EndOp(dest); i = e.Advance(i); diff --git a/src/alloy/backend/x64/lowering/op_utils.inl b/src/alloy/backend/x64/lowering/op_utils.inl index 17c947ef8..d519b634c 100644 --- a/src/alloy/backend/x64/lowering/op_utils.inl +++ b/src/alloy/backend/x64/lowering/op_utils.inl @@ -17,6 +17,30 @@ namespace { #define LIKE_REG(dest, like) Reg(dest.getIdx(), dest.getKind(), like.getBit(), false) #define NAX_LIKE(like) Reg(e.rax.getIdx(), e.rax.getKind(), like.getBit(), false) +// If we are running with tracing on we have to store the EFLAGS in the stack, +// otherwise our calls out to C to print will clear it before DID_CARRY/etc +// can get the value. +#define STORE_EFLAGS 1 + +void LoadEflags(X64Emitter& e) { +#if STORE_EFLAGS + e.mov(e.eax, e.dword[e.rsp + 40]); + e.push(e.ax); + e.popf(); +#else + // EFLAGS already present. +#endif // STORE_EFLAGS +} +void StoreEflags(X64Emitter& e) { +#if STORE_EFLAGS + e.pushf(); + e.pop(e.word[e.rsp + 40]); +#else + // EFLAGS should have CA set? + // (so long as we don't fuck with it) +#endif // STORE_EFLAGS +} + Address Stash(X64Emitter& e, const Xmm& r) { // TODO(benvanik): ensure aligned. auto addr = e.ptr[e.rsp + 48]; @@ -39,6 +63,15 @@ void MovMem64(X64Emitter& e, RegExp& addr, uint64_t v) { } } +void CallNative(X64Emitter& e, void* target) { + e.sub(e.rsp, 0x18); + e.mov(e.rax, (uint64_t)target); + e.call(e.rax); + e.mov(e.rcx, e.qword[e.rsp + 0]); + e.mov(e.rdx, e.qword[e.rcx + 8]); // membase + e.add(e.rsp, 0x18); +} + // Sets EFLAGs with zf for the given value. // ZF = 1 if false, 0 = true (so jz = jump if false) void CheckBoolean(X64Emitter& e, Value* v) { @@ -421,9 +454,7 @@ void IntUnaryOp(X64Emitter& e, Instr*& i, v_fn v_fn) { ASSERT_INVALID_TYPE(); } if (i->flags & ARITHMETIC_SET_CARRY) { - // EFLAGS should have CA set? - // (so long as we don't fuck with it) - // UNIMPLEMENTED_SEQ(); + StoreEflags(e); } }; @@ -598,9 +629,7 @@ void IntBinaryOp(X64Emitter& e, Instr*& i, vv_fn vv_fn, vc_fn vc_fn) { ASSERT_INVALID_TYPE(); } if (i->flags & ARITHMETIC_SET_CARRY) { - // EFLAGS should have CA set? - // (so long as we don't fuck with it) - // UNIMPLEMENTED_SEQ(); + StoreEflags(e); } }; @@ -777,9 +806,7 @@ void IntTernaryOp(X64Emitter& e, Instr*& i, vvv_fn vvv_fn, vvc_fn vvc_fn, vcv_fn ASSERT_INVALID_TYPE(); } if (i->flags & ARITHMETIC_SET_CARRY) { - // EFLAGS should have CA set? - // (so long as we don't fuck with it) - // UNIMPLEMENTED_SEQ(); + StoreEflags(e); } } @@ -946,9 +973,7 @@ void XmmBinaryOp(X64Emitter& e, Instr*& i, uint32_t flags, xmm_vv_fn vv_fn) { ASSERT_INVALID_TYPE(); } if (flags & ARITHMETIC_SET_CARRY) { - // EFLAGS should have CA set? - // (so long as we don't fuck with it) - // UNIMPLEMENTED_SEQ(); + StoreEflags(e); } }; @@ -992,9 +1017,7 @@ void XmmTernaryOp(X64Emitter& e, Instr*& i, uint32_t flags, xmm_vvv_fn vvv_fn) { ASSERT_INVALID_TYPE(); } if (flags & ARITHMETIC_SET_CARRY) { - // EFLAGS should have CA set? - // (so long as we don't fuck with it) - // UNIMPLEMENTED_SEQ(); + StoreEflags(e); } };