Path: blob/master/thirdparty/pcre2/deps/sljit/sljit_src/sljitNativeMIPS_32.c
9913 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*/2526/* mips 32-bit arch dependent functions. */2728static sljit_s32 emit_copysign(struct sljit_compiler *compiler, sljit_s32 op,29sljit_sw src1, sljit_sw src2, sljit_sw dst)30{31int is_32 = (op & SLJIT_32);32sljit_ins mfhc = MFC1, mthc = MTC1;33sljit_ins src1_r = FS(src1), src2_r = FS(src2), dst_r = FS(dst);3435if (!is_32) {36switch (cpu_feature_list & CPU_FEATURE_FR) {37#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 238case CPU_FEATURE_FR:39mfhc = MFHC1;40mthc = MTHC1;41break;42#endif /* SLJIT_MIPS_REV >= 2 */43default:44src1_r |= (1 << 11);45src2_r |= (1 << 11);46dst_r |= (1 << 11);47break;48}49}5051FAIL_IF(push_inst(compiler, mfhc | T(TMP_REG1) | src1_r, DR(TMP_REG1)));52FAIL_IF(push_inst(compiler, mfhc | T(TMP_REG2) | src2_r, DR(TMP_REG2)));53if (!is_32 && src1 != dst)54FAIL_IF(push_inst(compiler, MOV_fmt(FMT_S) | FS(src1) | FD(dst), MOVABLE_INS));55#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 156else57FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));58#endif /* MIPS III */59FAIL_IF(push_inst(compiler, XOR | T(TMP_REG1) | D(TMP_REG2) | S(TMP_REG2), DR(TMP_REG2)));60FAIL_IF(push_inst(compiler, SRL | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));61FAIL_IF(push_inst(compiler, SLL | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));62FAIL_IF(push_inst(compiler, XOR | T(TMP_REG2) | D(TMP_REG1) | S(TMP_REG1), DR(TMP_REG1)));63FAIL_IF(push_inst(compiler, mthc | T(TMP_REG1) | dst_r, MOVABLE_INS));64#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 165if (mthc == MTC1)66return push_inst(compiler, NOP, UNMOVABLE_INS);67#endif /* MIPS III */68return SLJIT_SUCCESS;69}7071static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)72{73if (!(imm & ~0xffff))74return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);7576if (imm < 0 && imm >= SIMM_MIN)77return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);7879FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));80return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;81}8283static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)84{85FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));86return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));87}8889SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,90sljit_s32 freg, sljit_f64 value)91{92union {93struct {94#if defined(SLJIT_LITTLE_ENDIAN) && SLJIT_LITTLE_ENDIAN95sljit_s32 lo;96sljit_s32 hi;97#else /* !SLJIT_LITTLE_ENDIAN */98sljit_s32 hi;99sljit_s32 lo;100#endif /* SLJIT_LITTLE_ENDIAN */101} bin;102sljit_f64 value;103} u;104105CHECK_ERROR();106CHECK(check_sljit_emit_fset64(compiler, freg, value));107108u.value = value;109110if (u.bin.lo != 0)111FAIL_IF(load_immediate(compiler, DR(TMP_REG1), u.bin.lo));112if (u.bin.hi != 0)113FAIL_IF(load_immediate(compiler, DR(TMP_REG2), u.bin.hi));114115FAIL_IF(push_inst(compiler, MTC1 | (u.bin.lo != 0 ? T(TMP_REG1) : TA(0)) | FS(freg), MOVABLE_INS));116switch (cpu_feature_list & CPU_FEATURE_FR) {117#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2118case CPU_FEATURE_FR:119return push_inst(compiler, MTHC1 | (u.bin.hi != 0 ? T(TMP_REG2) : TA(0)) | FS(freg), MOVABLE_INS);120#endif /* SLJIT_MIPS_REV >= 2 */121default:122FAIL_IF(push_inst(compiler, MTC1 | (u.bin.hi != 0 ? T(TMP_REG2) : TA(0)) | FS(freg) | (1 << 11), MOVABLE_INS));123break;124}125#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1126FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));127#endif /* MIPS III */128return SLJIT_SUCCESS;129}130131SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,132sljit_s32 freg, sljit_s32 reg)133{134sljit_s32 reg2 = 0;135sljit_ins inst = FS(freg);136sljit_ins mthc = MTC1, mfhc = MFC1;137int is_32 = (op & SLJIT_32);138139CHECK_ERROR();140CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));141142op = GET_OPCODE(op);143if (reg & REG_PAIR_MASK) {144reg2 = REG_PAIR_SECOND(reg);145reg = REG_PAIR_FIRST(reg);146147inst |= T(reg2);148149if (op == SLJIT_COPY_TO_F64)150FAIL_IF(push_inst(compiler, MTC1 | inst, MOVABLE_INS));151else152FAIL_IF(push_inst(compiler, MFC1 | inst, DR(reg2)));153154inst = FS(freg) | (1 << 11);155#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2156if (cpu_feature_list & CPU_FEATURE_FR) {157mthc = MTHC1;158mfhc = MFHC1;159inst = FS(freg);160}161#endif /* SLJIT_MIPS_REV >= 2 */162}163164inst |= T(reg);165if (!is_32 && !reg2) {166switch (cpu_feature_list & CPU_FEATURE_FR) {167#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2168case CPU_FEATURE_FR:169mthc = MTHC1;170mfhc = MFHC1;171break;172#endif /* SLJIT_MIPS_REV >= 2 */173default:174inst |= (1 << 11);175break;176}177}178179if (op == SLJIT_COPY_TO_F64)180FAIL_IF(push_inst(compiler, mthc | inst, MOVABLE_INS));181else182FAIL_IF(push_inst(compiler, mfhc | inst, DR(reg)));183184#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1185if (mthc == MTC1 || mfhc == MFC1)186return push_inst(compiler, NOP, UNMOVABLE_INS);187#endif /* MIPS III */188return SLJIT_SUCCESS;189}190191SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)192{193sljit_ins *inst = (sljit_ins *)addr;194SLJIT_UNUSED_ARG(executable_offset);195196SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);197SLJIT_ASSERT((inst[0] & 0xffe00000) == LUI && (inst[1] & 0xfc000000) == ORI);198inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);199inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);200SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);201inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);202SLJIT_CACHE_FLUSH(inst, inst + 2);203}204205SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)206{207sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);208}209210static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr, sljit_u32 *extra_space)211{212sljit_u32 is_tail_call = *extra_space & SLJIT_CALL_RETURN;213sljit_u32 offset = 0;214sljit_s32 float_arg_count = 0;215sljit_s32 word_arg_count = 0;216sljit_s32 types = 0;217sljit_ins prev_ins = NOP;218sljit_ins ins = NOP;219sljit_u8 offsets[4];220sljit_u8 *offsets_ptr = offsets;221#if defined(SLJIT_LITTLE_ENDIAN) && SLJIT_LITTLE_ENDIAN222sljit_ins f64_hi = TA(7), f64_lo = TA(6);223#else224sljit_ins f64_hi = TA(6), f64_lo = TA(7);225#endif /* SLJIT_LITTLE_ENDIAN */226227SLJIT_ASSERT(reg_map[TMP_REG2] == 4 && freg_map[TMP_FREG1] == 12);228229arg_types >>= SLJIT_ARG_SHIFT;230231/* See ABI description in sljit_emit_enter. */232233while (arg_types) {234types = (types << SLJIT_ARG_SHIFT) | (arg_types & SLJIT_ARG_MASK);235*offsets_ptr = (sljit_u8)offset;236237switch (arg_types & SLJIT_ARG_MASK) {238case SLJIT_ARG_TYPE_F64:239if (offset & 0x7) {240offset += sizeof(sljit_sw);241*offsets_ptr = (sljit_u8)offset;242}243244if (word_arg_count == 0 && float_arg_count <= 1)245*offsets_ptr = (sljit_u8)(254 + float_arg_count);246247offset += sizeof(sljit_f64);248float_arg_count++;249break;250case SLJIT_ARG_TYPE_F32:251if (word_arg_count == 0 && float_arg_count <= 1)252*offsets_ptr = (sljit_u8)(254 + float_arg_count);253254offset += sizeof(sljit_f32);255float_arg_count++;256break;257default:258offset += sizeof(sljit_sw);259word_arg_count++;260break;261}262263arg_types >>= SLJIT_ARG_SHIFT;264offsets_ptr++;265}266267/* Stack is aligned to 16 bytes. */268SLJIT_ASSERT(offset <= 8 * sizeof(sljit_sw));269270if (offset > 4 * sizeof(sljit_sw) && (!is_tail_call || offset > compiler->args_size)) {271if (is_tail_call) {272offset = (offset + sizeof(sljit_sw) + 15) & ~(sljit_uw)0xf;273FAIL_IF(emit_stack_frame_release(compiler, (sljit_s32)offset, &prev_ins));274*extra_space = offset;275} else {276FAIL_IF(push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(-16), DR(SLJIT_SP)));277*extra_space = 16;278}279} else {280if (is_tail_call)281FAIL_IF(emit_stack_frame_release(compiler, 0, &prev_ins));282*extra_space = 0;283}284285while (types) {286--offsets_ptr;287288switch (types & SLJIT_ARG_MASK) {289case SLJIT_ARG_TYPE_F64:290if (*offsets_ptr < 4 * sizeof(sljit_sw)) {291if (prev_ins != NOP)292FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));293294/* Must be preceded by at least one other argument,295* and its starting offset must be 8 because of alignment. */296SLJIT_ASSERT((*offsets_ptr >> 2) == 2);297switch (cpu_feature_list & CPU_FEATURE_FR) {298#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2299case CPU_FEATURE_FR:300prev_ins = MFHC1 | f64_hi | FS(float_arg_count);301break;302#endif /* SLJIT_MIPS_REV >= 2 */303default:304prev_ins = MFC1 | f64_hi | FS(float_arg_count) | (1 << 11);305break;306}307ins = MFC1 | f64_lo | FS(float_arg_count);308} else if (*offsets_ptr < 254)309ins = SDC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(*offsets_ptr);310else if (*offsets_ptr == 254)311ins = MOV_fmt(FMT_D) | FS(SLJIT_FR0) | FD(TMP_FREG1);312313float_arg_count--;314break;315case SLJIT_ARG_TYPE_F32:316if (*offsets_ptr < 4 * sizeof (sljit_sw))317ins = MFC1 | TA(4 + (*offsets_ptr >> 2)) | FS(float_arg_count);318else if (*offsets_ptr < 254)319ins = SWC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(*offsets_ptr);320else if (*offsets_ptr == 254)321ins = MOV_fmt(FMT_S) | FS(SLJIT_FR0) | FD(TMP_FREG1);322323float_arg_count--;324break;325default:326if (*offsets_ptr >= 4 * sizeof (sljit_sw))327ins = SW | S(SLJIT_SP) | T(word_arg_count) | IMM(*offsets_ptr);328else if ((*offsets_ptr >> 2) != word_arg_count - 1)329ins = ADDU | S(word_arg_count) | TA(0) | DA(4 + (*offsets_ptr >> 2));330else if (*offsets_ptr == 0)331ins = ADDU | S(SLJIT_R0) | TA(0) | DA(4);332333word_arg_count--;334break;335}336337if (ins != NOP) {338if (prev_ins != NOP)339FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));340prev_ins = ins;341ins = NOP;342}343344types >>= SLJIT_ARG_SHIFT;345}346347*ins_ptr = prev_ins;348349return SLJIT_SUCCESS;350}351352SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,353sljit_s32 arg_types)354{355struct sljit_jump *jump;356sljit_u32 extra_space = 0;357sljit_ins ins = NOP;358359CHECK_ERROR_PTR();360CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));361362jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));363PTR_FAIL_IF(!jump);364set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);365366if ((type & 0xff) != SLJIT_CALL_REG_ARG) {367extra_space = (sljit_u32)type;368PTR_FAIL_IF(call_with_args(compiler, arg_types, &ins, &extra_space));369} else if (type & SLJIT_CALL_RETURN)370PTR_FAIL_IF(emit_stack_frame_release(compiler, 0, &ins));371372SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25);373374if (ins == NOP && compiler->delay_slot != UNMOVABLE_INS)375jump->flags |= IS_MOVABLE;376377if (!(type & SLJIT_CALL_RETURN) || extra_space > 0) {378jump->flags |= IS_JAL;379380if ((type & 0xff) != SLJIT_CALL_REG_ARG)381jump->flags |= IS_CALL;382383PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));384} else385PTR_FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS));386387jump->addr = compiler->size;388PTR_FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));389390/* Maximum number of instructions required for generating a constant. */391compiler->size += 2;392393if (extra_space == 0)394return jump;395396if (type & SLJIT_CALL_RETURN)397PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG,398SLJIT_MEM1(SLJIT_SP), (sljit_sw)(extra_space - sizeof(sljit_sw))));399400if (type & SLJIT_CALL_RETURN)401PTR_FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS));402403PTR_FAIL_IF(push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(extra_space),404(type & SLJIT_CALL_RETURN) ? UNMOVABLE_INS : DR(SLJIT_SP)));405return jump;406}407408SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,409sljit_s32 arg_types,410sljit_s32 src, sljit_sw srcw)411{412sljit_u32 extra_space = (sljit_u32)type;413sljit_ins ins;414415CHECK_ERROR();416CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));417418if (src & SLJIT_MEM) {419ADJUST_LOCAL_OFFSET(src, srcw);420FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw));421src = PIC_ADDR_REG;422srcw = 0;423}424425if ((type & 0xff) == SLJIT_CALL_REG_ARG) {426if (type & SLJIT_CALL_RETURN) {427if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {428FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));429src = PIC_ADDR_REG;430srcw = 0;431}432433FAIL_IF(emit_stack_frame_release(compiler, 0, &ins));434435if (ins != NOP)436FAIL_IF(push_inst(compiler, ins, MOVABLE_INS));437}438439SLJIT_SKIP_CHECKS(compiler);440return sljit_emit_ijump(compiler, type, src, srcw);441}442443SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25);444445if (src == SLJIT_IMM)446FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));447else if (src != PIC_ADDR_REG)448FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));449450FAIL_IF(call_with_args(compiler, arg_types, &ins, &extra_space));451452/* Register input. */453if (!(type & SLJIT_CALL_RETURN) || extra_space > 0)454FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));455else456FAIL_IF(push_inst(compiler, JR | S(PIC_ADDR_REG), UNMOVABLE_INS));457FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));458459if (extra_space == 0)460return SLJIT_SUCCESS;461462if (type & SLJIT_CALL_RETURN)463FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG,464SLJIT_MEM1(SLJIT_SP), (sljit_sw)(extra_space - sizeof(sljit_sw))));465466if (type & SLJIT_CALL_RETURN)467FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS));468469return push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(extra_space),470(type & SLJIT_CALL_RETURN) ? UNMOVABLE_INS : DR(SLJIT_SP));471}472473474