mirror of
https://github.com/open-goal/jak-project
synced 2026-07-10 07:07:04 -04:00
add all loads
This commit is contained in:
+334
-2
@@ -115,8 +115,12 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
// todo - GPR64 -> XMM64 (zext)
|
||||
// todo - XMM -> GPR64
|
||||
// todo - XMM128 - XMM128
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// LOADS n' STORES - reg + reg addr
|
||||
// GOAL Loads
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
/*!
|
||||
@@ -138,6 +142,42 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load8s_gpr64_gpr64_plus_gpr64_plus_s8(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
Instruction instr(0xf);
|
||||
instr.set_op2(0xbe);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load8s_gpr64_gpr64_plus_gpr64_plus_s32(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
Instruction instr(0xf);
|
||||
instr.set_op2(0xbe);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* movzx dst, BYTE PTR [addr1 + addr2]
|
||||
* addr1 and addr2 have to be different registers.
|
||||
@@ -157,6 +197,42 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load8u_gpr64_gpr64_plus_gpr64_plus_s8(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
Instruction instr(0xf);
|
||||
instr.set_op2(0xb6);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load8u_gpr64_gpr64_plus_gpr64_plus_s32(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
Instruction instr(0xf);
|
||||
instr.set_op2(0xb6);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* movsx dst, WORD PTR [addr1 + addr2]
|
||||
* addr1 and addr2 have to be different registers.
|
||||
@@ -176,6 +252,41 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load16s_gpr64_gpr64_plus_gpr64_plus_s8(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
Instruction instr(0xf);
|
||||
instr.set_op2(0xbf);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load16s_gpr64_gpr64_plus_gpr64_plus_s32(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
Instruction instr(0xf);
|
||||
instr.set_op2(0xbf);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* movzx dst, WORD PTR [addr1 + addr2]
|
||||
@@ -196,6 +307,42 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load16u_gpr64_gpr64_plus_gpr64_plus_s8(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
Instruction instr(0xf);
|
||||
instr.set_op2(0xb7);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load16u_gpr64_gpr64_plus_gpr64_plus_s32(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
Instruction instr(0xf);
|
||||
instr.set_op2(0xb7);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* movsxd dst, DWORD PTR [addr1 + addr2]
|
||||
* addr1 and addr2 have to be different registers.
|
||||
@@ -213,6 +360,40 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load32s_gpr64_gpr64_plus_gpr64_plus_s8(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
Instruction instr(0x63);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load32s_gpr64_gpr64_plus_gpr64_plus_s32(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
Instruction instr(0x63);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* movzxd dst, DWORD PTR [addr1 + addr2]
|
||||
* addr1 and addr2 have to be different registers.
|
||||
@@ -230,6 +411,40 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load32u_gpr64_gpr64_plus_gpr64_plus_s8(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
Instruction instr(0x8b);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, false);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load32u_gpr64_gpr64_plus_gpr64_plus_s32(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
Instruction instr(0x8b);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, false);
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* mov dst, QWORD PTR [addr1 + addr2]
|
||||
* addr1 and addr2 have to be different registers.
|
||||
@@ -247,8 +462,125 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load64_gpr64_gpr64_plus_gpr64_plus_s8(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT8_MIN && offset <= INT8_MAX);
|
||||
Instruction instr(0x8b);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s8(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load64_gpr64_gpr64_plus_gpr64_plus_s32(Register dst,
|
||||
Register addr1,
|
||||
Register addr2,
|
||||
s64 offset) {
|
||||
assert(dst.is_gpr());
|
||||
assert(addr1.is_gpr());
|
||||
assert(addr2.is_gpr());
|
||||
assert(addr1 != addr2);
|
||||
assert(addr1 != RSP);
|
||||
assert(addr2 != RSP);
|
||||
assert(offset >= INT32_MIN && offset <= INT32_MAX);
|
||||
Instruction instr(0x8b);
|
||||
instr.set_modrm_and_rex_for_reg_plus_reg_plus_s32(dst.hw_id(), addr1.hw_id(), addr2.hw_id(),
|
||||
offset, true);
|
||||
return instr;
|
||||
}
|
||||
|
||||
static Instruction load_goal_gpr(Register dst,
|
||||
Register addr,
|
||||
Register off,
|
||||
int offset,
|
||||
int size,
|
||||
bool sign_extend) {
|
||||
switch (size) {
|
||||
case 1:
|
||||
if (offset == 0) {
|
||||
if (sign_extend) {
|
||||
return load8s_gpr64_gpr64_plus_gpr64(dst, addr, off);
|
||||
} else {
|
||||
return load8u_gpr64_gpr64_plus_gpr64(dst, addr, off);
|
||||
}
|
||||
} else if (offset >= INT8_MIN && offset <= INT8_MAX) {
|
||||
if (sign_extend) {
|
||||
return load8s_gpr64_gpr64_plus_gpr64_plus_s8(dst, addr, off, offset);
|
||||
} else {
|
||||
return load8u_gpr64_gpr64_plus_gpr64_plus_s8(dst, addr, off, offset);
|
||||
}
|
||||
} else if (offset >= INT32_MIN && offset <= INT32_MAX) {
|
||||
if (sign_extend) {
|
||||
return load8s_gpr64_gpr64_plus_gpr64_plus_s32(dst, addr, off, offset);
|
||||
} else {
|
||||
return load8u_gpr64_gpr64_plus_gpr64_plus_s32(dst, addr, off, offset);
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
case 2:
|
||||
if (offset == 0) {
|
||||
if (sign_extend) {
|
||||
return load16s_gpr64_gpr64_plus_gpr64(dst, addr, off);
|
||||
} else {
|
||||
return load16u_gpr64_gpr64_plus_gpr64(dst, addr, off);
|
||||
}
|
||||
} else if (offset >= INT8_MIN && offset <= INT8_MAX) {
|
||||
if (sign_extend) {
|
||||
return load16s_gpr64_gpr64_plus_gpr64_plus_s8(dst, addr, off, offset);
|
||||
} else {
|
||||
return load16u_gpr64_gpr64_plus_gpr64_plus_s8(dst, addr, off, offset);
|
||||
}
|
||||
} else if (offset >= INT32_MIN && offset <= INT32_MAX) {
|
||||
if (sign_extend) {
|
||||
return load16s_gpr64_gpr64_plus_gpr64_plus_s32(dst, addr, off, offset);
|
||||
} else {
|
||||
return load16u_gpr64_gpr64_plus_gpr64_plus_s32(dst, addr, off, offset);
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
case 4:
|
||||
if (offset == 0) {
|
||||
if (sign_extend) {
|
||||
return load32s_gpr64_gpr64_plus_gpr64(dst, addr, off);
|
||||
} else {
|
||||
return load32u_gpr64_gpr64_plus_gpr64(dst, addr, off);
|
||||
}
|
||||
} else if (offset >= INT8_MIN && offset <= INT8_MAX) {
|
||||
if (sign_extend) {
|
||||
return load32s_gpr64_gpr64_plus_gpr64_plus_s8(dst, addr, off, offset);
|
||||
} else {
|
||||
return load32u_gpr64_gpr64_plus_gpr64_plus_s8(dst, addr, off, offset);
|
||||
}
|
||||
} else if (offset >= INT32_MIN && offset <= INT32_MAX) {
|
||||
if (sign_extend) {
|
||||
return load32s_gpr64_gpr64_plus_gpr64_plus_s32(dst, addr, off, offset);
|
||||
} else {
|
||||
return load32u_gpr64_gpr64_plus_gpr64_plus_s32(dst, addr, off, offset);
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
case 8:
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// LOADS n' STORES - XMM128
|
||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
/*!
|
||||
* Store a 128-bit xmm into a register, no offset
|
||||
* Store a 128-bit xmm into an address stored in a register, no offset
|
||||
*/
|
||||
static Instruction store128_gpr64_xmm128(Register gpr_addr, Register xmm_value) {
|
||||
assert(gpr_addr.is_gpr());
|
||||
|
||||
+110
-2
@@ -169,6 +169,114 @@ struct Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
void set_modrm_and_rex_for_reg_plus_reg_plus_s8(uint8_t reg, uint8_t addr1, uint8_t addr2, s8 offset, bool rex_w) {
|
||||
bool rex_b = false, rex_r = false, rex_x = false;
|
||||
bool addr1_ext = false;
|
||||
bool addr2_ext = false;
|
||||
|
||||
if (addr1 >= 8) {
|
||||
addr1 -= 8;
|
||||
addr1_ext = true;
|
||||
}
|
||||
|
||||
if (addr2 >= 8) {
|
||||
addr2 -= 8;
|
||||
addr2_ext = true;
|
||||
}
|
||||
|
||||
if (reg >= 8) {
|
||||
reg -= 8;
|
||||
rex_r = true;
|
||||
}
|
||||
|
||||
ModRM modrm;
|
||||
modrm.mod = 1; // no disp
|
||||
modrm.rm = 4; // sib!
|
||||
modrm.reg_op = reg;
|
||||
|
||||
SIB sib;
|
||||
sib.scale = 0;
|
||||
|
||||
Imm imm2(1, offset);
|
||||
|
||||
// default addr1 in index
|
||||
if(addr1 == 4) {
|
||||
sib.index = addr2;
|
||||
sib.base = addr1;
|
||||
rex_x = addr2_ext;
|
||||
rex_b = addr1_ext;
|
||||
} else {
|
||||
// addr1 in index
|
||||
sib.index = addr1;
|
||||
sib.base = addr2;
|
||||
rex_x = addr1_ext;
|
||||
rex_b = addr2_ext;
|
||||
}
|
||||
assert(sib.index != 4);
|
||||
|
||||
if(rex_b || rex_w || rex_r || rex_x) {
|
||||
set(REX(rex_w, rex_r, rex_x, rex_b));
|
||||
}
|
||||
|
||||
set(modrm);
|
||||
set(sib);
|
||||
set_disp(imm2);
|
||||
}
|
||||
|
||||
void set_modrm_and_rex_for_reg_plus_reg_plus_s32(uint8_t reg, uint8_t addr1, uint8_t addr2, s8 offset, bool rex_w) {
|
||||
bool rex_b = false, rex_r = false, rex_x = false;
|
||||
bool addr1_ext = false;
|
||||
bool addr2_ext = false;
|
||||
|
||||
if (addr1 >= 8) {
|
||||
addr1 -= 8;
|
||||
addr1_ext = true;
|
||||
}
|
||||
|
||||
if (addr2 >= 8) {
|
||||
addr2 -= 8;
|
||||
addr2_ext = true;
|
||||
}
|
||||
|
||||
if (reg >= 8) {
|
||||
reg -= 8;
|
||||
rex_r = true;
|
||||
}
|
||||
|
||||
ModRM modrm;
|
||||
modrm.mod = 2; // no disp
|
||||
modrm.rm = 4; // sib!
|
||||
modrm.reg_op = reg;
|
||||
|
||||
SIB sib;
|
||||
sib.scale = 0;
|
||||
|
||||
Imm imm2(4, offset);
|
||||
|
||||
// default addr1 in index
|
||||
if(addr1 == 4) {
|
||||
sib.index = addr2;
|
||||
sib.base = addr1;
|
||||
rex_x = addr2_ext;
|
||||
rex_b = addr1_ext;
|
||||
} else {
|
||||
// addr1 in index
|
||||
sib.index = addr1;
|
||||
sib.base = addr2;
|
||||
rex_x = addr1_ext;
|
||||
rex_b = addr2_ext;
|
||||
}
|
||||
assert(sib.index != 4);
|
||||
|
||||
if(rex_b || rex_w || rex_r || rex_x) {
|
||||
set(REX(rex_w, rex_r, rex_x, rex_b));
|
||||
}
|
||||
|
||||
set(modrm);
|
||||
set(sib);
|
||||
set_disp(imm2);
|
||||
}
|
||||
|
||||
void set_modrm_and_rex_for_reg_plus_reg_addr(uint8_t reg, uint8_t addr1, uint8_t addr2, bool rex_w = false, bool rex_always = false) {
|
||||
bool rex_b = false, rex_r = false, rex_x = false;
|
||||
bool addr1_ext = false;
|
||||
@@ -203,7 +311,7 @@ struct Instruction {
|
||||
rex_x = addr1_ext;
|
||||
rex_b = addr2_ext;
|
||||
modrm.mod = 1;
|
||||
set(Imm(1, 0));
|
||||
set_disp(Imm(1, 0));
|
||||
|
||||
} else {
|
||||
// default addr1 in index
|
||||
@@ -267,7 +375,7 @@ struct Instruction {
|
||||
|
||||
if (rm == 5) {
|
||||
modrm.mod = 1; // 1 byte imm
|
||||
set(Imm(1, 0));
|
||||
set_disp(Imm(1, 0));
|
||||
}
|
||||
|
||||
set(modrm);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user