Path: blob/master/thirdparty/pcre2/deps/sljit/sljit_src/sljitNativeRISCV_64.c
22214 views
/*1* Stack-less Just-In-Time compiler2*3* Copyright Zoltan Herczeg ([email protected]). All rights reserved.4*5* Redistribution and use in source and binary forms, with or without modification, are6* permitted provided that the following conditions are met:7*8* 1. Redistributions of source code must retain the above copyright notice, this list of9* conditions and the following disclaimer.10*11* 2. Redistributions in binary form must reproduce the above copyright notice, this list12* of conditions and the following disclaimer in the documentation and/or other materials13* provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY16* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES17* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT18* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,19* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED20* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR21* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN22* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN23* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.24*/2526static sljit_s32 load_immediate32(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm)27{28SLJIT_ASSERT((imm <= 0x7fffffffl && imm > SIMM_MAX) || (imm >= S32_MIN && imm < SIMM_MIN));2930if (imm > S32_MAX) {31SLJIT_ASSERT((imm & 0x800) != 0);32FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u));33return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));34}3536if (RISCV_HAS_COMPRESSED(200) && imm <= 0x1ffff && imm >= -0x20000) {37if (imm > 0x1f7ff) {38SLJIT_ASSERT((imm & 0x800) != 0);39FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | (sljit_u16)0x1000));40return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));41}4243if ((imm & 0x800) != 0)44imm += 0x1000;4546FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | ((sljit_u16)(((imm) & 0x1f000) >> 10) | ((imm) & 0x20000) >> 5)));47} else {48if ((imm & 0x800) != 0)49imm += 0x1000;5051FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~(sljit_sw)0xfff)));52}5354imm &= 0xfff;5556if (imm == 0)57return SLJIT_SUCCESS;5859if (RISCV_HAS_COMPRESSED(200) && (imm <= 0x1f || imm >= 0xfe0))60return push_inst16(compiler, C_ADDI | C_RD(dst_r) | C_IMM_I(imm));6162return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));63}6465static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm, sljit_s32 tmp_r)66{67sljit_sw high, shift;6869if (RISCV_HAS_COMPRESSED(200) && imm <= SIMM16_MAX && imm >= SIMM16_MIN)70return push_inst16(compiler, C_LI | C_RD(dst_r) | C_IMM_I(imm));7172if (imm <= SIMM_MAX && imm >= SIMM_MIN)73return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm));7475if (imm <= 0x7fffffffl && imm >= S32_MIN)76return load_immediate32(compiler, dst_r, imm);7778/* Shifted small immediates. */7980high = imm;81shift = 0;82while ((high & 0xff) == 0) {83high >>= 8;84shift += 8;85}8687if ((high & 0xf) == 0) {88high >>= 4;89shift += 4;90}9192if ((high & 0x3) == 0) {93high >>= 2;94shift += 2;95}9697if ((high & 0x1) == 0) {98high >>= 1;99shift += 1;100}101102if (high <= 0x7fffffffl && high >= S32_MIN) {103load_immediate(compiler, dst_r, high, tmp_r);104105if (RISCV_HAS_COMPRESSED(200))106return push_inst16(compiler, C_SLLI | C_RD(dst_r) | C_IMM_I(shift));107return push_inst(compiler, SLLI | RD(dst_r) | RS1(dst_r) | IMM_I(shift));108}109110/* Trailing zeroes could be used to produce shifted immediates. */111112if (imm <= 0x7ffffffffffl && imm >= -0x80000000000l) {113high = imm >> 12;114115if (imm & 0x800)116high = ~high;117118FAIL_IF(load_immediate32(compiler, dst_r, high));119120if (RISCV_HAS_COMPRESSED(200))121FAIL_IF(push_inst16(compiler, C_SLLI | C_RD(dst_r) | (sljit_u16)(12 << 2)));122else123FAIL_IF(push_inst(compiler, SLLI | RD(dst_r) | RS1(dst_r) | IMM_I(12)));124125SLJIT_ASSERT((imm & 0xfff) != 0);126return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));127}128129SLJIT_ASSERT(dst_r != tmp_r);130131high = imm >> 32;132imm = (sljit_s32)imm;133134if ((imm & 0x80000000l) != 0)135high = ~high;136137if (high <= 0x7ffff && high >= -0x80000) {138FAIL_IF(push_inst(compiler, LUI | RD(tmp_r) | (sljit_ins)(high << 12)));139high = 0x1000;140} else {141if ((high & 0x800) != 0)142high += 0x1000;143144FAIL_IF(push_inst(compiler, LUI | RD(tmp_r) | (sljit_ins)(high & ~0xfff)));145high &= 0xfff;146}147148if (imm <= SIMM_MAX && imm >= SIMM_MIN) {149if (RISCV_HAS_COMPRESSED(200) && imm <= 0x1f && imm >= -0x20)150FAIL_IF(push_inst16(compiler, C_LI | C_RD(dst_r) | C_IMM_I(imm)));151else152FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm)));153imm = 0;154} else if (imm > S32_MAX) {155SLJIT_ASSERT((imm & 0x800) != 0);156157FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u));158imm = 0x1000 | (imm & 0xfff);159} else {160if ((imm & 0x800) != 0)161imm += 0x1000;162163if (RISCV_HAS_COMPRESSED(200) && imm <= 0x1ffff && imm >= -0x20000)164FAIL_IF(push_inst16(compiler, C_LUI | C_RD(dst_r) | ((sljit_u16)(((imm) & 0x1f000) >> 10) | ((imm) & 0x20000) >> 5)));165else166FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~0xfff)));167imm &= 0xfff;168}169170if ((high & 0xfff) != 0) {171SLJIT_ASSERT(high <= 0xfff);172if (RISCV_HAS_COMPRESSED(200) && (high <= 0x1f || high >= 0xfe0))173FAIL_IF(push_inst16(compiler, C_ADDI | C_RD(tmp_r) | C_IMM_I(high)));174else175FAIL_IF(push_inst(compiler, ADDI | RD(tmp_r) | RS1(tmp_r) | IMM_I(high)));176}177178if (imm & 0x1000)179FAIL_IF(push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)));180else if (imm != 0) {181SLJIT_ASSERT(imm <= 0xfff);182if (RISCV_HAS_COMPRESSED(200) && (imm <= 0x1f || imm >= 0xfe0))183FAIL_IF(push_inst16(compiler, C_ADDI | C_RD(dst_r) | C_IMM_I(imm)));184else185FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)));186}187188if (RISCV_HAS_COMPRESSED(200))189FAIL_IF(push_inst16(compiler, C_SLLI | C_RD(tmp_r) | (sljit_u16)((high & 0x1000) ? (20 << 2) : (1 << 12))));190else191FAIL_IF(push_inst(compiler, SLLI | RD(tmp_r) | RS1(tmp_r) | IMM_I((high & 0x1000) ? 20 : 32)));192return push_inst(compiler, XOR | RD(dst_r) | RS1(dst_r) | RS2(tmp_r));193}194195SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,196sljit_s32 freg, sljit_f64 value)197{198union {199sljit_sw imm;200sljit_f64 value;201} u;202203CHECK_ERROR();204CHECK(check_sljit_emit_fset64(compiler, freg, value));205206u.value = value;207208if (u.imm == 0)209return push_inst(compiler, FMV_W_X | (1 << 25) | RS1(TMP_ZERO) | FRD(freg));210211FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm, TMP_REG3));212return push_inst(compiler, FMV_W_X | (1 << 25) | RS1(TMP_REG1) | FRD(freg));213}214215SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,216sljit_s32 freg, sljit_s32 reg)217{218sljit_ins inst;219220CHECK_ERROR();221CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));222223if (GET_OPCODE(op) == SLJIT_COPY_TO_F64)224inst = FMV_W_X | RS1(reg) | FRD(freg);225else226inst = FMV_X_W | FRS1(freg) | RD(reg);227228if (!(op & SLJIT_32))229inst |= (sljit_ins)1 << 25;230231return push_inst(compiler, inst);232}233234static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins)235{236sljit_sw high;237238if ((init_value & 0x800) != 0)239init_value += 0x1000;240241high = init_value >> 32;242243if ((init_value & 0x80000000l) != 0)244high = ~high;245246if ((high & 0x800) != 0)247high += 0x1000;248249FAIL_IF(push_inst(compiler, LUI | RD(TMP_REG3) | (sljit_ins)(high & ~0xfff)));250FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(high)));251FAIL_IF(push_inst(compiler, LUI | RD(dst) | (sljit_ins)(init_value & ~0xfff)));252FAIL_IF(push_inst(compiler, SLLI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(32)));253FAIL_IF(push_inst(compiler, XOR | RD(dst) | RS1(dst) | RS2(TMP_REG3)));254return push_inst(compiler, last_ins | RS1(dst) | IMM_I(init_value));255}256257SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)258{259sljit_u16 *inst = (sljit_u16*)addr;260sljit_sw high;261SLJIT_UNUSED_ARG(executable_offset);262263if ((new_target & 0x800) != 0)264new_target += 0x1000;265266high = (sljit_sw)new_target >> 32;267268if ((new_target & 0x80000000l) != 0)269high = ~high;270271if ((high & 0x800) != 0)272high += 0x1000;273274SLJIT_UPDATE_WX_FLAGS(inst, inst + 12, 0);275276SLJIT_ASSERT((inst[0] & 0x7f) == LUI);277inst[0] = (sljit_u16)((inst[0] & 0xfff) | (high & 0xf000));278inst[1] = (sljit_u16)(high >> 16);279SLJIT_ASSERT((inst[2] & 0x707f) == ADDI);280inst[3] = (sljit_u16)((inst[3] & 0xf) | (high << 4));281SLJIT_ASSERT((inst[4] & 0x7f) == LUI);282inst[4] = (sljit_u16)((inst[4] & 0xfff) | (new_target & 0xf000));283inst[5] = (sljit_u16)(new_target >> 16);284SLJIT_ASSERT((inst[10] & 0x707f) == ADDI || (inst[10] & 0x707f) == JALR);285inst[11] = (sljit_u16)((inst[11] & 0xf) | (new_target << 4));286SLJIT_UPDATE_WX_FLAGS(inst, inst + 12, 1);287288inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);289SLJIT_CACHE_FLUSH(inst, inst + 12);290}291292293