fis-gtm/sr_x86_64/emit_code_sp.h

503 lines
14 KiB
C

/****************************************************************
* *
* Copyright 2007, 2009 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#include "x86_64.h"
#ifdef DEBUG
void format_machine_inst(void);
void initialize_registers(void);
void reset_instruction(void);
void print_source_operand(void);
void print_destination_operand(void);
void print_instruction(void);
void set_memory_reg(void);
void set_register_reg(void);
void clear_memory_reg(void);
#endif
void emit_base_offset(int base, int offset);
/* Define the COND values for use in the 2 byte JCC instructions.. */
#define INST_SIZE 1
#define XFER_BYTE_INST_SIZE 3
#define XFER_LONG_INST_SIZE 6
#define BRB_INST_SIZE 2
#define JMP_LONG_INST_SIZE 5
#define CALL_4LCLDO_XFER 2 /* index in ttt from start of call[sp] and forlcldo to xfer_table index */
#define MAX_BRANCH_CODEGEN_SIZE 32 /* The length in bytes, of the longest form of branch instruction sequence */
int x86_64_arg_reg(int indx);
#define GET_ARG_REG(indx) x86_64_arg_reg(indx)
/* Should be offset from RSP */
#define STACK_ARG_OFFSET(indx) (8 * indx)
enum condition
{
JO,
JNO,
JB,
JC = JB,
JNAE = JC,
JNB,
JNC = JNB,
JAE = JNB,
JZ,
JE = JZ,
JNZ,
JNE = JNZ,
JBE,
JNA = JBE,
JNBE,
JA = JNBE,
JS,
JNS,
JP,
JPE = JP,
JNP,
JPO = JNP,
JL,
JNGE = JL,
JNL,
JGE = JNL,
JLE,
JNG = JLE,
JNLE,
JG = JNLE
};
#define REX_FIELD char
#define REX_OP 0x40
#define REX_B 0x01
#define REX_X 0x02
#define REX_R 0x04
#define REX_W 0x08
/* Note that while the register number we use in gtm can go from 0-15, the number of bits in the modrm/sib regfields are only 3.
* So if we need to use the regs r8-r15, then a bit in the REX field should be set (depending on whether the register is encoded
* in the sib or opcode or modrm, etc.
*/
#define SET_REX_PREFIX(REX_MANDATORY, REX_COND, reg) \
{ \
if (reg & 0x8) { /* If bit 3 (index starting from 0) is set, set the specified REX bit */ \
emit_base_info.rex |= REX_COND; \
} \
emit_base_info.rex |= REX_OP | REX_MANDATORY; \
emit_base_info.rex_set = 1; \
}
typedef union
{
ModR_M modrm;
unsigned char byte;
} modrm_byte_type;
typedef union
{
SIB sib;
unsigned char byte;
} sib_byte_type;
/* Instead of filling up the code buf, emit_base_offset will instead fill this structure, which will be used by the
* macro which actually creates the instruction stream
*/
struct emit_base_info
{
REX_FIELD rex;
modrm_byte_type modrm_byte;
sib_byte_type sib_byte;
char offset8;
int offset32;
int64_t offset64;
char imm8;
int imm32;
int64_t imm64;
int rex_set;
int modrm_byte_set;
int sib_byte_set; /* Not using bitfields, since this would generate faster code. Since this is a one-type only
* created object, no real need for space optimization
*/
int offset8_set;
int offset32_set;
int offset64_set;
int imm8_set;
int imm32_set;
int imm64_set;
};
GBLREF struct emit_base_info emit_base_info;
/* Define the macros for the instructions to be generated.. */
#define GENERIC_OPCODE_BEQ 1
#define GENERIC_OPCODE_BGE 2
#define GENERIC_OPCODE_BGT 3
#define GENERIC_OPCODE_BLE 4
#define GENERIC_OPCODE_BLT 5
#define GENERIC_OPCODE_BNE 6
#define GENERIC_OPCODE_BLBC 7
#define GENERIC_OPCODE_BLBS 8
#define GENERIC_OPCODE_BR 9
#define GENERIC_OPCODE_LDA 11
#define GENERIC_OPCODE_LOAD 12
#define GENERIC_OPCODE_STORE 13
#define GENERIC_OPCODE_STORE_ZERO 14
#define GENERIC_OPCODE_NOP 15
#define LONG_JUMP_OFFSET (0x7ffffffc)
#define MAX_OFFSET 0xffffffff
#define EMIT_JMP_ADJUST_BRANCH_OFFSET branch_offset -= 5
#define EMIT_BASE_CODE_SIZE ((emit_base_info.rex_set ? 1 : 0) /* REX */ + 1 /* OPCODE */ + \
(emit_base_info.modrm_byte_set ? 1 : 0) /* MODRM */ + \
(emit_base_info.sib_byte_set ? 1 : 0) + (emit_base_info.offset8_set ? 1 : 0) + \
(emit_base_info.offset32_set ? 4 : 0) + (emit_base_info.offset64_set ? 8 : 0) + \
(emit_base_info.imm8_set ? 1 : 0) + (emit_base_info.imm32_set ? 4 : 0) + \
(emit_base_info.imm64_set ? 8 : 0))
#define CODE_BUF_GEN(op_code) \
{ \
(emit_base_info.rex_set) ? (code_buf[code_idx++] = emit_base_info.rex):0; \
code_buf[code_idx++] = (char) op_code; \
if (emit_base_info.modrm_byte_set) { \
code_buf[code_idx++] = emit_base_info.modrm_byte.byte; \
} \
if (emit_base_info.sib_byte_set) { \
code_buf[code_idx++] = emit_base_info.sib_byte.byte; \
} \
if (emit_base_info.offset8_set) { \
code_buf[code_idx++] = emit_base_info.offset8; \
} \
if (emit_base_info.offset32_set) { \
*((int4 *)&code_buf[code_idx]) = emit_base_info.offset32; \
code_idx += SIZEOF(int4) ; \
} \
if (emit_base_info.offset64_set) { \
*((int64_t *)&code_buf[code_idx]) = emit_base_info.offset64; \
code_idx += SIZEOF(int64_t) ; \
} \
if (emit_base_info.imm8_set) { \
code_buf[code_idx++] = emit_base_info.imm8; \
} \
if (emit_base_info.imm32_set) { \
*((int4 *)&code_buf[code_idx]) = emit_base_info.imm32; \
code_idx += SIZEOF(int4) ; \
} \
if (emit_base_info.imm64_set) { \
*((int64_t *)&code_buf[code_idx]) = emit_base_info.imm64; \
code_idx += SIZEOF(int64_t) ; \
} \
}
#define IGEN_LOAD_WORD_REG_8(reg) \
{ \
SET_REX_PREFIX(REX_W, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(I386_INS_MOV_Gv_Ev) \
}
#define IGEN_LOAD_NATIVE_REG(reg) IGEN_LOAD_WORD_REG_8(reg)
/* Sign extended load */
#define IGEN_LOAD_WORD_REG_4(reg) \
{ \
SET_REX_PREFIX(REX_W, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(I386_INS_MOVSXD_Gv_Ev) \
}
#define IGEN_STORE_WORD_REG_8(reg) \
{ \
SET_REX_PREFIX(REX_W, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(I386_INS_MOV_Ev_Gv) \
}
#define IGEN_STORE_WORD_REG_4(reg) \
{ \
SET_REX_PREFIX(0, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(I386_INS_MOV_Ev_Gv) \
}
#define IGEN_STORE_ZERO_REG_8(reg) \
{ \
SET_REX_PREFIX(REX_W, 0, 0) \
emit_base_info.imm32 = 0; \
emit_base_info.imm32_set = 1; \
CODE_BUF_GEN(I386_INS_MOV_Ev_Iv) \
}
#define IGEN_STORE_ZERO_REG_4(reg) \
{ \
emit_base_info.imm32 = 0; \
emit_base_info.imm32_set = 1; \
CODE_BUF_GEN(I386_INS_MOV_Ev_Iv) \
}
#define IGEN_GENERIC_REG(opcode, reg) \
{\
switch(opcode) \
{\
case GENERIC_OPCODE_LDA:\
IGEN_LOAD_ADDR_REG(reg)\
break;\
case GENERIC_OPCODE_LOAD:\
if ( next_ptr_offset == 4 ) { \
IGEN_LOAD_WORD_REG_4(reg); \
} else {\
IGEN_LOAD_WORD_REG_8(reg); \
} \
next_ptr_offset = 8; \
break;\
case GENERIC_OPCODE_STORE:\
if ( next_ptr_offset == 4 ) { \
IGEN_STORE_WORD_REG_4(reg); \
} else {\
IGEN_STORE_WORD_REG_8(reg); \
} \
next_ptr_offset = 8; \
break;\
case GENERIC_OPCODE_STORE_ZERO:\
if ( next_ptr_offset == 4 ) { \
IGEN_STORE_ZERO_REG_4(reg); \
} else {\
IGEN_STORE_ZERO_REG_8(reg); \
} \
next_ptr_offset = 8; \
break;\
default: /* which opcode ? */ \
GTMASSERT;\
break;\
}\
}
#define IGEN_LOAD_LINKAGE(reg) IGEN_LOAD_WORD_REG_8(reg)
#define IGEN_LOAD_ADDR_REG(reg) \
{ \
SET_REX_PREFIX(REX_W, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(I386_INS_LEA_Gv_M) \
}
#define GEN_STORE_ARG(reg, offset) \
{ \
X86_64_ONLY(force_32 = TRUE;) \
GEN_STORE_WORD_8(reg, I386_REG_RSP, offset) \
X86_64_ONLY(force_32 = FALSE;) \
}
#define GEN_LOAD_WORD_8(reg, base_reg, offset) \
{ \
emit_base_offset(base_reg, offset); \
SET_REX_PREFIX(REX_W, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(I386_INS_MOV_Gv_Ev) \
}
/* Load 4 bytes with sign extension */
#define GEN_LOAD_WORD_4(reg, base_reg, offset) \
{ \
emit_base_offset(base_reg, offset); \
SET_REX_PREFIX(REX_W, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(I386_INS_MOVSXD_Gv_Ev) \
}
#define GEN_STORE_WORD_8(reg, base_reg, offset) \
{ \
emit_base_offset(base_reg, offset); \
SET_REX_PREFIX(REX_W, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(I386_INS_MOV_Ev_Gv) \
}
#define GEN_STORE_WORD_4(reg, base_reg, offset) \
{ \
emit_base_offset(base_reg, offset); \
SET_REX_PREFIX(0, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(I386_INS_MOV_Ev_Gv) \
}
#define GEN_LOAD_IMMED(reg, imval) \
{ \
int op_code = I386_INS_MOV_eAX + (reg & 0x7); \
memset((void *)&emit_base_info, 0, SIZEOF(emit_base_info)); \
SET_REX_PREFIX(0, REX_B, reg) \
emit_base_info.imm32 = (int) imval & 0xffffffff; \
emit_base_info.imm32_set = 1; \
CODE_BUF_GEN(op_code) \
}
#define GEN_CLEAR_WORD_EMIT(reg) emit_trip(*(fst_opr + *inst++), TRUE, GENERIC_OPCODE_STORE_ZERO, reg)
#define GEN_LOAD_WORD_EMIT(reg) emit_trip(*(fst_opr + *inst++), TRUE, GENERIC_OPCODE_LOAD, reg)
#define EMIT_TRIP_ILIT_GEN GEN_LOAD_IMMED(trg_reg, immediate)
#define GEN_XFER_TBL_CALL(xfer) \
{ \
emit_base_offset(GTM_REG_XFER_TABLE, xfer); \
emit_base_info.rex_set = 0; \
assert(GTM_REG_XFER_TABLE <= 7); /* if its a 64 bit register, we might need to set the REX bit */ \
emit_base_info.modrm_byte.modrm.reg_opcode = (char) I386_INS_CALL_Ev; \
CODE_BUF_GEN(I386_INS_Grp5_Prefix) \
}
#define GEN_CMP_EAX_IMM32(imm) \
{ \
int op_code = I386_INS_CMP_eAX_Iv ; \
memset((void *)&emit_base_info, 0, SIZEOF(emit_base_info)); \
emit_base_info.imm32 = (int4) imm & 0xffffffff; \
emit_base_info.imm32_set = 1; \
CODE_BUF_GEN(op_code) \
}
#define GEN_CMP_MEM64_ZERO(base_reg, offset) \
{ \
int op_code = I386_INS_Grp1_Ev_Iv_Prefix; \
emit_base_offset(base_reg, offset); \
SET_REX_PREFIX(REX_W, 0, 0) \
emit_base_info.modrm_byte.modrm.reg_opcode = I386_INS_CMP__; \
emit_base_info.imm32 = (int4) 0; \
emit_base_info.imm32_set = 1; \
CODE_BUF_GEN(op_code) \
}
#define GEN_CMP_MEM32_ZERO(base_reg, offset) \
{ \
int op_code = I386_INS_Grp1_Ev_Iv_Prefix; \
emit_base_offset(base_reg, offset); \
emit_base_info.modrm_byte.modrm.reg_opcode = I386_INS_CMP__; \
emit_base_info.imm32 = (int4) 0 ; \
emit_base_info.imm32_set = 1; \
CODE_BUF_GEN(op_code) \
}
#define GEN_CMP_REG_MEM32(reg, base_reg, offset) \
{ \
int op_code = I386_INS_CMP_Gv_Ev; \
emit_base_offset(base_reg, offset); \
SET_REX_PREFIX(0, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(op_code) \
}
#define GEN_CMP_REG_MEM64(reg, base_reg, offset) \
{ \
int op_code = I386_INS_CMP_Gv_Ev; \
emit_base_offset(base_reg, offset); \
SET_REX_PREFIX(REX_W, REX_R, reg) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg & 0x7; \
CODE_BUF_GEN(op_code) \
}
#define GEN_CMP_REGS(reg1, reg2) \
{ \
int op_code = I386_INS_CMP_Gv_Ev; \
memset((void *)&emit_base_info, 0, SIZEOF(emit_base_info)); \
SET_REX_PREFIX(REX_W, REX_R, reg1) \
SET_REX_PREFIX(0, REX_B, reg2) \
emit_base_info.modrm_byte.modrm.reg_opcode = reg1 & 0x7; \
emit_base_info.modrm_byte.modrm.mod = I386_MOD32_REGISTER; \
emit_base_info.modrm_byte.modrm.r_m = reg2 & 0x7; \
emit_base_info.modrm_byte_set = 1; \
CODE_BUF_GEN(op_code) \
}
/* Note that there is no CMP_IMM64 in AMD64 */
#define GEN_CMP_IMM32(reg, imm) \
{ \
int op_code = I386_INS_Grp1_Ev_Iv_Prefix; \
memset((void *)&emit_base_info, 0, SIZEOF(emit_base_info)); \
emit_base_info.modrm_byte.modrm.reg_opcode = I386_INS_CMP__; \
emit_base_info.modrm_byte.modrm.mod = I386_MOD32_REGISTER; \
emit_base_info.modrm_byte.modrm.r_m = reg & 0x7; \
emit_base_info.modrm_byte_set = 1; \
SET_REX_PREFIX(0, REX_B, reg) \
emit_base_info.imm32 = (int4) imm & 0xffffffff; \
emit_base_info.imm32_set = 1; \
CODE_BUF_GEN(op_code) \
}
#define GEN_SUBTRACT_REGS(src1, src2, trgt) GTMASSERT;
#define GEN_ADD_IMMED(reg, imval) \
{ \
int op_code = I386_INS_Grp1_Ev_Iv_Prefix; \
memset((void *)&emit_base_info, 0, SIZEOF(emit_base_info)); \
SET_REX_PREFIX(REX_W, REX_B, reg) \
emit_base_info.modrm_byte_set = 1; \
emit_base_info.modrm_byte.modrm.mod = I386_MOD32_REGISTER; \
emit_base_info.modrm_byte.modrm.reg_opcode = I386_INS_ADD__; \
emit_base_info.modrm_byte.modrm.r_m = reg & 0x7; \
emit_base_info.imm32 = (int4) imval; \
emit_base_info.imm32_set = 1; \
CODE_BUF_GEN(op_code) \
}
#define GEN_MOVE_REG(trg, src) \
{ \
int op_code = I386_INS_MOV_Ev_Gv; \
memset((void *)&emit_base_info, 0, SIZEOF(emit_base_info)); \
SET_REX_PREFIX(REX_W, REX_B, trg) \
SET_REX_PREFIX(0, REX_R, src) \
emit_base_info.modrm_byte_set = 1; \
emit_base_info.modrm_byte.modrm.mod = I386_MOD32_REGISTER; \
emit_base_info.modrm_byte.modrm.reg_opcode = src; \
emit_base_info.modrm_byte.modrm.r_m = trg & 0x7; \
CODE_BUF_GEN(op_code) \
}
#define GEN_JUMP_REG(reg) \
{ \
int op_code = I386_INS_Grp5_Prefix; \
memset((void *)&emit_base_info, 0, SIZEOF(emit_base_info)); \
SET_REX_PREFIX(REX_OP | REX_W, REX_B, reg) \
emit_base_info.modrm_byte_set = 1; \
emit_base_info.modrm_byte.modrm.mod = I386_MOD32_REGISTER; \
emit_base_info.modrm_byte.modrm.reg_opcode = I386_INS_JMP_Ev; \
emit_base_info.modrm_byte.modrm.r_m = reg & 0x7; \
CODE_BUF_GEN(op_code) \
}
#define GEN_PCREL \
{ \
int op_code = I386_INS_CALL_Jv; \
memset((void *)&emit_base_info, 0, SIZEOF(emit_base_info)); \
emit_base_info.imm32 = 0; \
emit_base_info.imm32_set = 1; \
CODE_BUF_GEN(op_code) \
memset((void *)&emit_base_info, 0, SIZEOF(emit_base_info)); \
op_code = I386_INS_POP_eAX + (GTM_REG_CODEGEN_TEMP & 0x7); \
SET_REX_PREFIX(0, REX_B, GTM_REG_CODEGEN_TEMP) \
assert(GTM_REG_CODEGEN_TEMP > 7); \
CODE_BUF_GEN(op_code) \
}
/*
* GT.M on AIX and SPARC is 64bit
* By default the loads/stores use ldd/std(load double),
* but if the value being dealt with is a word,the
* opcode in generic_inst is changed to ldw/stw
* On other platforms, it is defined to null
*/
#define REVERT_GENERICINST_TO_WORD(inst)