in pcre/sljit/sljitNativePPC_common.c [947:1112]
static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
sljit_s32 tmp_r;
sljit_ins inst;
sljit_sw high_short, next_high_short;
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
sljit_sw diff;
#endif
SLJIT_ASSERT(arg & SLJIT_MEM);
tmp_r = ((inp_flags & LOAD_DATA) && ((inp_flags) & MEM_MASK) <= GPR_REG) ? reg : TMP_REG1;
/* Special case for "mov reg, [reg, ... ]". */
if ((arg & REG_MASK) == tmp_r)
tmp_r = TMP_REG1;
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
argw &= 0x3;
/* Otherwise getput_arg_fast would capture it. */
SLJIT_ASSERT(argw);
if ((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg && argw == compiler->cache_argw)
tmp_r = TMP_REG3;
else {
if ((arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK) && argw == (next_argw & 0x3)) {
compiler->cache_arg = SLJIT_MEM | (arg & OFFS_REG_MASK);
compiler->cache_argw = argw;
tmp_r = TMP_REG3;
}
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
FAIL_IF(push_inst(compiler, RLWINM | S(OFFS_REG(arg)) | A(tmp_r) | (argw << 11) | ((31 - argw) << 1)));
#else
FAIL_IF(push_inst(compiler, RLDI(tmp_r, OFFS_REG(arg), argw, 63 - argw, 1)));
#endif
}
inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
SLJIT_ASSERT(!(inst & (INT_ALIGNED | UPDATE_REQ)));
return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(tmp_r));
}
if (SLJIT_UNLIKELY(!(arg & REG_MASK)))
inp_flags &= ~WRITE_BACK;
inst = data_transfer_insts[inp_flags & MEM_MASK];
SLJIT_ASSERT((arg & REG_MASK) || !(inst & UPDATE_REQ));
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
if (argw <= 0x7fff7fffl && argw >= -0x80000000l
&& (!(inst & INT_ALIGNED) || !(argw & 0x3)) && !(inst & UPDATE_REQ)) {
#endif
arg &= REG_MASK;
high_short = (sljit_s32)(argw + ((argw & 0x8000) << 1)) & ~0xffff;
/* The getput_arg_fast should handle this otherwise. */
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
SLJIT_ASSERT(high_short && high_short <= 0x7fffffffl && high_short >= -0x80000000l);
#else
SLJIT_ASSERT(high_short && !(inst & (INT_ALIGNED | UPDATE_REQ)));
#endif
if (inp_flags & WRITE_BACK) {
if (arg == reg) {
FAIL_IF(push_inst(compiler, OR | S(reg) | A(tmp_r) | B(reg)));
reg = tmp_r;
}
tmp_r = arg;
FAIL_IF(push_inst(compiler, ADDIS | D(arg) | A(arg) | IMM(high_short >> 16)));
}
else if (compiler->cache_arg != (SLJIT_MEM | arg) || high_short != compiler->cache_argw) {
if ((next_arg & SLJIT_MEM) && !(next_arg & OFFS_REG_MASK)) {
next_high_short = (sljit_s32)(next_argw + ((next_argw & 0x8000) << 1)) & ~0xffff;
if (high_short == next_high_short) {
compiler->cache_arg = SLJIT_MEM | arg;
compiler->cache_argw = high_short;
tmp_r = TMP_REG3;
}
}
FAIL_IF(push_inst(compiler, ADDIS | D(tmp_r) | A(arg & REG_MASK) | IMM(high_short >> 16)));
}
else
tmp_r = TMP_REG3;
return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(tmp_r) | IMM(argw));
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
}
/* Everything else is PPC-64 only. */
if (SLJIT_UNLIKELY(!(arg & REG_MASK))) {
diff = argw - compiler->cache_argw;
if ((compiler->cache_arg & SLJIT_IMM) && diff <= SIMM_MAX && diff >= SIMM_MIN) {
ADJUST_CACHED_IMM(diff);
return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(TMP_REG3) | IMM(diff));
}
diff = argw - next_argw;
if ((next_arg & SLJIT_MEM) && diff <= SIMM_MAX && diff >= SIMM_MIN) {
SLJIT_ASSERT(inp_flags & LOAD_DATA);
compiler->cache_arg = SLJIT_IMM;
compiler->cache_argw = argw;
tmp_r = TMP_REG3;
}
FAIL_IF(load_immediate(compiler, tmp_r, argw));
return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(tmp_r));
}
diff = argw - compiler->cache_argw;
if (compiler->cache_arg == arg && diff <= SIMM_MAX && diff >= SIMM_MIN) {
SLJIT_ASSERT(!(inp_flags & WRITE_BACK) && !(inst & UPDATE_REQ));
ADJUST_CACHED_IMM(diff);
return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(TMP_REG3) | IMM(diff));
}
if ((compiler->cache_arg & SLJIT_IMM) && diff <= SIMM_MAX && diff >= SIMM_MIN) {
inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
SLJIT_ASSERT(!(inst & (INT_ALIGNED | UPDATE_REQ)));
if (compiler->cache_argw != argw) {
FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG3) | A(TMP_REG3) | IMM(diff)));
compiler->cache_argw = argw;
}
return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(TMP_REG3));
}
if (argw == next_argw && (next_arg & SLJIT_MEM)) {
SLJIT_ASSERT(inp_flags & LOAD_DATA);
FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
compiler->cache_arg = SLJIT_IMM;
compiler->cache_argw = argw;
inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
SLJIT_ASSERT(!(inst & (INT_ALIGNED | UPDATE_REQ)));
return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(TMP_REG3));
}
diff = argw - next_argw;
if (arg == next_arg && !(inp_flags & WRITE_BACK) && diff <= SIMM_MAX && diff >= SIMM_MIN) {
SLJIT_ASSERT(inp_flags & LOAD_DATA);
FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
FAIL_IF(push_inst(compiler, ADD | D(TMP_REG3) | A(TMP_REG3) | B(arg & REG_MASK)));
compiler->cache_arg = arg;
compiler->cache_argw = argw;
return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(TMP_REG3));
}
if ((next_arg & SLJIT_MEM) && !(next_arg & OFFS_REG_MASK) && diff <= SIMM_MAX && diff >= SIMM_MIN) {
SLJIT_ASSERT(inp_flags & LOAD_DATA);
FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
compiler->cache_arg = SLJIT_IMM;
compiler->cache_argw = argw;
tmp_r = TMP_REG3;
}
else
FAIL_IF(load_immediate(compiler, tmp_r, argw));
/* Get the indexed version instead of the normal one. */
inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
SLJIT_ASSERT(!(inst & (INT_ALIGNED | UPDATE_REQ)));
return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(tmp_r));
#endif
}