From 5b183535843f5a969f486cae73b1b51d95fca81d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Nov 2014 08:36:23 -0800 Subject: [PATCH] mips: Add helpers for constant loads. --- Common/MipsEmitter.cpp | 93 +++++++++++++++++++++++++++++++++++++----- Common/MipsEmitter.h | 28 +++++++++++-- 2 files changed, 106 insertions(+), 15 deletions(-) diff --git a/Common/MipsEmitter.cpp b/Common/MipsEmitter.cpp index 910e222ac..33e1d2d6a 100644 --- a/Common/MipsEmitter.cpp +++ b/Common/MipsEmitter.cpp @@ -34,15 +34,6 @@ void MIPSXEmitter::SetCodePtr(u8 *ptr) { lastCacheFlushEnd_ = ptr; } -void MIPSXEmitter::QuickCallFunction(MIPSReg reg, const void *func) { -// if (BLInRange(func)) { -// J(func); -// } else { -// MOVP2R(reg, func); -// JR(reg); -// } -} - void MIPSXEmitter::ReserveCodeSpace(u32 bytes) { for (u32 i = 0; i < bytes / 4; ++i) { BREAK(0); @@ -163,6 +154,14 @@ void MIPSXEmitter::SetJumpTarget(const FixupBranch &branch) { SetJumpTarget(branch, code_); } +bool MIPSXEmitter::BInRange(const void *func) { + return BInRange(code_, func); +} + +bool MIPSXEmitter::JInRange(const void *func) { + return JInRange(code_, func); +} + void MIPSXEmitter::SetJumpTarget(const FixupBranch &branch, const void *dst) { const intptr_t srcp = (intptr_t)branch.ptr; const intptr_t dstp = (intptr_t)dst; @@ -173,15 +172,44 @@ void MIPSXEmitter::SetJumpTarget(const FixupBranch &branch, const void *dst) { if (branch.type == BRANCH_16) { // The distance is encoded as words from the delay slot. ptrdiff_t distance = (dstp - srcp - 4) >> 2; - _dbg_assert_msg_(JIT, distance >= -0x8000 && distance < 0x8000, "Destination is too far away (%p -> %p)", branch.ptr, dst); + _dbg_assert_msg_(JIT, BInRange(branch.ptr, dst), "Destination is too far away (%p -> %p)", branch.ptr, dst); *fixup = (*fixup & 0xffff0000) | (distance & 0x0000ffff); } else { // Absolute, easy. - _dbg_assert_msg_(JIT, (srcp & 0xf0000000) != (dstp & 0xf0000000), "Destination is too far away (%p -> %p)", branch.ptr, dst); + _dbg_assert_msg_(JIT, JInRange(branch.ptr, dst), "Destination is too far away (%p -> %p)", branch.ptr, dst); *fixup = (*fixup & 0xfc000000) | ((dstp >> 2) & 0x03ffffff); } } +bool MIPSXEmitter::BInRange(const void *src, const void *dst) { + const intptr_t srcp = (intptr_t)src; + const intptr_t dstp = (intptr_t)dst; + + // The distance is encoded as words from the delay slot. + ptrdiff_t distance = (dstp - srcp - 4) >> 2; + return distance >= -0x8000 && distance < 0x8000; +} + +bool MIPSXEmitter::JInRange(const void *src, const void *dst) { + const intptr_t srcp = (intptr_t)src; + const intptr_t dstp = (intptr_t)dst; + + return (srcp - (srcp & 0x0fffffff)) == (dstp - (dstp & 0x0fffffff)); +} + +void MIPSXEmitter::QuickCallFunction(MIPSReg scratchreg, const void *func) { + _dbg_assert_msg_(JIT, scratchreg < F_BASE, "Bad emitter arguments"); + if (BInRange(func)) { + B(func); + } else if (JInRange(func)) { + J(func); + } else { + // This may never happen. + MOVP2R(reg, func); + JR(reg); + } +} + FixupBranch MIPSXEmitter::MakeFixupBranch(FixupBranchType type) { FixupBranch b; b.ptr = code_; @@ -333,6 +361,49 @@ void MIPSXEmitter::LUI(MIPSReg rt, s16 imm) { Write32Fields(26, 0x0f, 21, rt, 0, (u16)imm); } +void MIPSXEmitter::DSLL(MIPSReg rd, MIPSReg rt, u8 sa) { + // 000000 xxxxx ttttt ddddd aaaaa 111000 DSLL + // 000000 xxxxx ttttt ddddd aaaaa 111100 DSLL32 + _dbg_assert_msg_(JIT, rd < F_BASE && rt < F_BASE && sa <= 0x3f, "Bad emitter arguments"); + // TODO: Assert MIPS64. + if (sa >= 32) { + Write32Fields(26, 0x00, 16, rt, 11, rd, 6, (sa - 32) & 0x1f, 0, 0x3c); + } else { + Write32Fields(26, 0x00, 16, rt, 11, rd, 6, sa & 0x1f, 0, 0x38); + } +} + +void MIPSXEmitter::MOVI2R(MIPSReg reg, u64 imm) { + _dbg_assert_msg_(JIT, reg < F_BASE, "Bad emitter arguments"); + // TODO: Assert MIPS64. + + // Probably better to use a literal pool and load. + LUI(reg, imm >> 48); + ORI(reg, reg, (imm >> 32) & 0x0000ffff); + DSLL(reg, reg, 16); + ORI(reg, reg, (imm >> 16) & 0x0000ffff); + DSLL(reg, reg, 16); + ORI(reg, reg, (imm >> 0) & 0x0000ffff); +} + +void MIPSXEmitter::MOVI2R(MIPSReg reg, u32 imm) { + _dbg_assert_msg_(JIT, reg < F_BASE, "Bad emitter arguments"); + + if ((imm & 0xffff0000) != 0) { +#if 0 + // TODO: CPUDetect MIPS64. Ideally allow emitter to emit MIPS32 on x64. + ORI(reg, R_ZERO, imm >> 16); + DSLL(reg, reg, 16); + ORI(reg, reg, imm & 0x0000ffff); +#else + LUI(reg, imm >> 16); + ORI(reg, reg, imm & 0x0000ffff); +#endif + } else { + ORI(reg, R_ZERO, imm & 0x0000ffff); + } +} + void MIPSXCodeBlock::AllocCodeSpace(int size) { region_size = size; region = (u8 *)AllocateExecutableMemory(region_size); diff --git a/Common/MipsEmitter.h b/Common/MipsEmitter.h index 94120b6dd..71a1c0d1e 100644 --- a/Common/MipsEmitter.h +++ b/Common/MipsEmitter.h @@ -128,6 +128,14 @@ public: void BGTZ(MIPSReg rs, const void *func); void SetJumpTarget(const FixupBranch &branch); + bool BInRange(const void *func); + bool JInRange(const void *func); + + // R_AT is the stereotypical scratch reg, but it is not likely to be used. + void QuickCallFunction(MIPSReg scratchreg, const void *func); + template void QuickCallFunction(MIPSReg scratchreg, T func) { + QuickCallFunction(scratchreg, (const void *)func); + } void LB(MIPSReg dest, MIPSReg base, s16 offset); void LW(MIPSReg dest, MIPSReg base, s16 offset); @@ -162,12 +170,22 @@ public: void ORI(MIPSReg rt, MIPSReg rs, s16 imm); void XORI(MIPSReg rt, MIPSReg rs, s16 imm); - // Clears the lower bits. + // Clears the lower bits. On MIPS64, the result is sign extended. void LUI(MIPSReg rt, s16 imm); - void QuickCallFunction(MIPSReg scratchreg, const void *func); - template void QuickCallFunction(MIPSReg scratchreg, T func) { - QuickCallFunction(scratchreg, (const void *)func); + // MIPS64 only. Transparently uses DSLL32 to shift 32-63 bits. + void DSLL(MIPSReg rd, MIPSReg rt, u8 sa); + + void MOVI2R(MIPSReg reg, u64 val); + void MOVI2R(MIPSReg reg, s64 val) { + MOVI2R(reg, (u64)val); + } + void MOVI2R(MIPSReg reg, u32 val); + void MOVI2R(MIPSReg reg, s32 val) { + MOVI2R(reg, (u32)val); + } + template void MOVP2R(MIPSReg reg, T *val) { + MOVI2R(reg, (intptr_t)(const void *)val); } protected: @@ -196,6 +214,8 @@ protected: } static void SetJumpTarget(const FixupBranch &branch, const void *dst); + static bool BInRange(const void *src, const void *dst); + static bool JInRange(const void *src, const void *dst); FixupBranch MakeFixupBranch(FixupBranchType type); private: