Skip to content

Commit

Permalink
Improve rewritable consts (#299)
Browse files Browse the repository at this point in the history
  • Loading branch information
zherczeg authored Jan 31, 2025
1 parent 959c135 commit f578900
Show file tree
Hide file tree
Showing 18 changed files with 665 additions and 127 deletions.
4 changes: 4 additions & 0 deletions API_CHANGES
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
This file is the short summary of the API changes:

31.01.2025 - Non-backward compatible
The sljit_emit_const and sljit_set_const
functions can specify the operation type.

17.07.2024 - Non-backward compatible
Passing float scratch or saved register count
to emit_enter / set_context is reworked.
Expand Down
9 changes: 7 additions & 2 deletions sljit_src/sljitLir.c
Original file line number Diff line number Diff line change
Expand Up @@ -3231,16 +3231,21 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_co
CHECK_RETURN_OK;
}

static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_sw init_value)
{
SLJIT_UNUSED_ARG(init_value);

#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT(op == SLJIT_MOV || op == SLJIT_MOV_S32
|| op == SLJIT_MOV32 || (op | SLJIT_32) == SLJIT_MOV32_U8);
FUNCTION_CHECK_DST(dst, dstw);
#endif /* SLJIT_ARGUMENT_CHECKS */
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
fprintf(compiler->verbose, " const ");
fprintf(compiler->verbose, " const%s%s ",
!(op & SLJIT_32) ? "" : "32", op1_types[GET_OPCODE(op) - SLJIT_OP1_BASE]);
sljit_verbose_param(compiler, dst, dstw);
fprintf(compiler->verbose, ", #%" SLJIT_PRINT_D "d\n", init_value);
}
Expand Down
17 changes: 14 additions & 3 deletions sljit_src/sljitLir.h
Original file line number Diff line number Diff line change
Expand Up @@ -2326,9 +2326,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
Flags: - (may destroy flags) */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset);

/* Store a value that can be changed runtime (see: sljit_get_const_addr / sljit_set_const)
/* Store a value that can be changed at runtime. The constant
can be managed by sljit_get_const_addr and sljit_set_const.
op must be SLJIT_MOV, SLJIT_MOV32, SLJIT_MOV_S32,
SLJIT_MOV_U8, SLJIT_MOV32_U8
Note: when SLJIT_MOV_U8 is used, and dst is a register,
init_value supports a 9 bit signed value between [-256..255]
Flags: - (does not modify flags) */
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value);
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_sw init_value);

/* Store the value of a label (see: sljit_set_label / sljit_set_target)
Flags: - (does not modify flags) */
Expand All @@ -2345,7 +2355,8 @@ static SLJIT_INLINE sljit_uw sljit_get_const_addr(struct sljit_const *const_) {
/* Only the address and executable offset are required to perform dynamic
code modifications. See sljit_get_executable_offset function. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset);
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset);
/* The op opcode must be set to the same value that was passed to sljit_emit_const. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset);

/* --------------------------------------------------------------------- */
/* CPU specific functions */
Expand Down
70 changes: 51 additions & 19 deletions sljit_src/sljitNativeARM_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -1111,17 +1111,23 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
const_ = compiler->consts;
while (const_) {
buf_ptr = (sljit_ins*)const_->addr;
const_->addr = (sljit_uw)code_ptr;

code_ptr[0] = (sljit_ins)buf_ptr;
code_ptr[1] = *buf_ptr;
if (*buf_ptr & (1 << 23))
buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;
else
buf_ptr += 1;
/* Set the value again (can be a simple constant). */
set_const_value((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0);
code_ptr += 2;
/* Note: MVN = (MOV ^ 0x400000) */
SLJIT_ASSERT((*buf_ptr & 0xfdb00000) == MOV || (*buf_ptr & 0xfd100000) == LDR);

if ((*buf_ptr & 0x4000000) != 0) {
const_->addr = (sljit_uw)code_ptr;

code_ptr[0] = (sljit_ins)buf_ptr;
code_ptr[1] = *buf_ptr;
if (*buf_ptr & (1 << 23))
buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;
else
buf_ptr += 1;
/* Set the value again (can be a simple constant). */
set_const_value((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0);
code_ptr += 2;
}

const_ = const_->next;
}
Expand Down Expand Up @@ -4688,13 +4694,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
return SLJIT_SUCCESS;
}

SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
#define SLJIT_EMIT_CONST_U8(c) \
(((c) & 0x100) != 0 ? (MVN | SRC2_IMM | (~(c) & 0xff)) : (MOV | SRC2_IMM | ((c) & 0xff)))

SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_sw init_value)
{
struct sljit_const *const_;
sljit_s32 dst_r;
sljit_s32 mem_flags = WORD_SIZE;

CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
ADJUST_LOCAL_OFFSET(dst, dstw);

const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
Expand All @@ -4703,16 +4715,22 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi

dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;

if (GET_OPCODE(op) == SLJIT_MOV_U8) {
PTR_FAIL_IF(push_inst(compiler, SLJIT_EMIT_CONST_U8(init_value) | RD(dst_r)));
mem_flags = BYTE_SIZE;
} else {
#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
PTR_FAIL_IF(push_inst_with_unique_literal(compiler,
EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), (sljit_ins)init_value));
compiler->patches++;
PTR_FAIL_IF(push_inst_with_unique_literal(compiler,
EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), (sljit_ins)init_value));
compiler->patches++;
#else /* !SLJIT_CONFIG_ARM_V6 */
PTR_FAIL_IF(emit_imm(compiler, dst_r, init_value));
PTR_FAIL_IF(emit_imm(compiler, dst_r, init_value));
#endif /* SLJIT_CONFIG_ARM_V6 */
}

if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1));
PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG2, dst, dstw, TMP_REG1));

return const_;
}

Expand Down Expand Up @@ -4752,7 +4770,21 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
set_jump_addr(addr, executable_offset, new_target, 1);
}

SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
{
set_const_value(addr, executable_offset, (sljit_uw)new_constant, 1);
sljit_ins *inst;

if (GET_OPCODE(op) != SLJIT_MOV_U8) {
set_const_value(addr, executable_offset, (sljit_uw)new_constant, 1);
return;
}

inst = (sljit_ins*)addr;
SLJIT_ASSERT((inst[0] & 0xfff00000) == (MOV | SRC2_IMM) || (inst[0] & 0xfff00000) == (MVN | SRC2_IMM));

SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
*inst = SLJIT_EMIT_CONST_U8(new_constant) | (*inst & 0xf000);
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
77 changes: 71 additions & 6 deletions sljit_src/sljitNativeARM_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -3501,24 +3501,54 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *c
return SLJIT_SUCCESS;
}

SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
#define SLJIT_EMIT_CONST_U8(c) \
(((c) & 0x100) != 0 ? (MOVN | (sljit_ins)((~(c) & 0xff) << 5)) : (MOVZ | (sljit_ins)(((c) & 0xff) << 5)))
#define SLJIT_EMIT_CONST_S32(c) \
(((c) < 0) ? (MOVN | (sljit_ins)((~(c) & 0xffff) << 5)) : (MOVZ | (sljit_ins)(((c) & 0xffff) << 5)))

SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_sw init_value)
{
struct sljit_const *const_;
sljit_s32 dst_r;
sljit_s32 mem_flags = WORD_SIZE | STORE;

CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
ADJUST_LOCAL_OFFSET(dst, dstw);

const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
PTR_FAIL_IF(!const_);
set_const(const_, compiler);

dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
PTR_FAIL_IF(emit_imm64_const(compiler, dst_r, (sljit_uw)init_value));

switch (GET_OPCODE(op)) {
case SLJIT_MOV_U8:
PTR_FAIL_IF(push_inst(compiler, SLJIT_EMIT_CONST_U8(init_value) | RD(dst_r)));
mem_flags = BYTE_SIZE | STORE;
break;

case SLJIT_MOV32:
case SLJIT_MOV_S32:
if (GET_OPCODE(op) == SLJIT_MOV32) {
init_value = (sljit_u32)init_value;
mem_flags = INT_SIZE | STORE;
} else
init_value = (sljit_s32)init_value;

PTR_FAIL_IF(push_inst(compiler, SLJIT_EMIT_CONST_S32(init_value) | RD(dst_r)));
PTR_FAIL_IF(push_inst(compiler, MOVK | (1 << 21) | (sljit_ins)((init_value >> 11) & 0x1fffe0) | RD(dst_r)));
break;

default:
PTR_FAIL_IF(emit_imm64_const(compiler, dst_r, (sljit_uw)init_value));
break;
}

if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, dst, dstw, TMP_REG2));
return const_;
}

Expand Down Expand Up @@ -3566,7 +3596,42 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
SLJIT_CACHE_FLUSH(inst, inst + 4);
}

SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
{
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
sljit_ins* inst;

switch (GET_OPCODE(op)) {
case SLJIT_MOV_U8:
inst = (sljit_ins*)addr;
SLJIT_ASSERT((inst[0] & 0xffe00000) == MOVZ || (inst[0] & 0xffe00000) == MOVN);

SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
inst[0] = SLJIT_EMIT_CONST_U8(new_constant) | (inst[0] & 0x1f);
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
return;

case SLJIT_MOV32:
case SLJIT_MOV_S32:
if (GET_OPCODE(op) == SLJIT_MOV32)
new_constant = (sljit_u32)new_constant;
else
new_constant = (sljit_s32)new_constant;

inst = (sljit_ins*)addr;
SLJIT_ASSERT(((inst[0] & 0xffe00000) == MOVZ || (inst[0] & 0xffe00000) == MOVN) && (inst[1] & 0xffe00000) == (MOVK | (1 << 21)));

SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
inst[0] = SLJIT_EMIT_CONST_S32(new_constant) | (inst[0] & 0x1f);
inst[1] = MOVK | (1 << 21) | (sljit_ins)((new_constant >> 11) & 0x1fffe0) | (inst[1] & 0x1f);
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 2);
return;

default:
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
return;
}
}
42 changes: 36 additions & 6 deletions sljit_src/sljitNativeARM_T2_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -4357,24 +4357,33 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler
return SLJIT_SUCCESS;
}

SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_sw init_value)
{
struct sljit_const *const_;
sljit_s32 dst_r;
sljit_s32 mem_flags = WORD_SIZE | STORE;

CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));
ADJUST_LOCAL_OFFSET(dst, dstw);

const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
PTR_FAIL_IF(!const_);
set_const(const_, compiler);

dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
PTR_FAIL_IF(emit_imm32_const(compiler, dst_r, (sljit_uw)init_value));

if (GET_OPCODE(op) == SLJIT_MOV_U8) {
PTR_FAIL_IF(push_inst32(compiler,
((init_value & 0x100) != 0 ? (MVN_WI | (~init_value & 0xff)) : (MOV_WI | (init_value & 0xff))) | RD4(dst_r)));
mem_flags = BYTE_SIZE | STORE;
} else
PTR_FAIL_IF(emit_imm32_const(compiler, dst_r, (sljit_uw)init_value));

if (dst & SLJIT_MEM)
PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, dst, dstw, TMP_REG2));
return const_;
}

Expand Down Expand Up @@ -4412,7 +4421,28 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
SLJIT_CACHE_FLUSH(inst, inst + 4);
}

SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)
{
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
sljit_u16 *inst;

if (GET_OPCODE(op) != SLJIT_MOV_U8) {
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
return;
}

inst = (sljit_u16*)addr;
SLJIT_ASSERT(inst[0] == (MOV_WI >> 16) || inst[0] == (MVN_WI >> 16));

SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);

if ((new_constant & 0x100) != 0) {
inst[0] = (sljit_u16)(MVN_WI >> 16);
new_constant = ~new_constant;
} else
inst[0] = (sljit_u16)(MOV_WI >> 16);

inst[1] = (sljit_u16)((new_constant & 0xff) | (inst[1] & 0xf00));
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst + 1, inst + 2);
}
9 changes: 2 additions & 7 deletions sljit_src/sljitNativeMIPS_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,18 +196,13 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta

SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
SLJIT_ASSERT((inst[0] & 0xffe00000) == LUI && (inst[1] & 0xfc000000) == ORI);
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
inst[0] = (inst[0] & 0xffff0000) | IMM(new_target >> 16);
inst[1] = (inst[1] & 0xffff0000) | IMM(new_target);
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}

SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
{
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
}

static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr, sljit_u32 *extra_space)
{
sljit_u32 is_tail_call = *extra_space & SLJIT_CALL_RETURN;
Expand Down
13 changes: 4 additions & 9 deletions sljit_src/sljitNativeMIPS_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,20 +202,15 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ta
SLJIT_UNUSED_ARG(executable_offset);

SLJIT_UPDATE_WX_FLAGS(inst, inst + 6, 0);
inst[0] = (inst[0] & 0xffff0000) | ((sljit_ins)(new_target >> 48) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | ((sljit_ins)(new_target >> 32) & 0xffff);
inst[3] = (inst[3] & 0xffff0000) | ((sljit_ins)(new_target >> 16) & 0xffff);
inst[5] = (inst[5] & 0xffff0000) | ((sljit_ins)new_target & 0xffff);
inst[0] = (inst[0] & 0xffff0000) | IMM(new_target >> 48);
inst[1] = (inst[1] & 0xffff0000) | IMM(new_target >> 32);
inst[3] = (inst[3] & 0xffff0000) | IMM(new_target >> 16);
inst[5] = (inst[5] & 0xffff0000) | IMM(new_target);
SLJIT_UPDATE_WX_FLAGS(inst, inst + 6, 1);
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 6);
}

SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
{
sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);
}

static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr)
{
sljit_s32 arg_count = 0;
Expand Down
Loading

0 comments on commit f578900

Please sign in to comment.