Path: blob/master/thirdparty/pcre2/deps/sljit/sljit_src/sljitNativePPC_common.c
21827 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*/2526SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)27{28return "PowerPC" SLJIT_CPUINFO;29}3031/* Length of an instruction word.32Both for ppc-32 and ppc-64. */33typedef sljit_u32 sljit_ins;3435#if ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && (defined _AIX)) \36|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)37#define SLJIT_PPC_STACK_FRAME_V2 138#endif3940#ifdef _AIX41#include <sys/cache.h>42#endif4344#if (defined _CALL_ELF && _CALL_ELF == 2)45#define SLJIT_PASS_ENTRY_ADDR_TO_CALL 146#endif4748#if (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL)4950static void ppc_cache_flush(sljit_ins *from, sljit_ins *to)51{52#ifdef _AIX53_sync_cache_range((caddr_t)from, (int)((size_t)to - (size_t)from));54#elif defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM)55# if defined(_ARCH_PWR) || defined(_ARCH_PWR2)56/* Cache flush for POWER architecture. */57while (from < to) {58__asm__ volatile (59"clf 0, %0\n"60"dcs\n"61: : "r"(from)62);63from++;64}65__asm__ volatile ( "ics" );66# elif defined(_ARCH_COM) && !defined(_ARCH_PPC)67# error "Cache flush is not implemented for PowerPC/POWER common mode."68# else69/* Cache flush for PowerPC architecture. */70while (from < to) {71__asm__ volatile (72"dcbf 0, %0\n"73"sync\n"74"icbi 0, %0\n"75: : "r"(from)76);77from++;78}79__asm__ volatile ( "isync" );80# endif81# ifdef __xlc__82# warning "This file may fail to compile if -qfuncsect is used"83# endif84#elif defined(__xlc__)85#error "Please enable GCC syntax for inline assembly statements with -qasm=gcc"86#else87#error "This platform requires a cache flush implementation."88#endif /* _AIX */89}9091#endif /* (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL) */9293#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)94#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)95#define TMP_ZERO (SLJIT_NUMBER_OF_REGISTERS + 4)9697#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)98#define TMP_CALL_REG (SLJIT_NUMBER_OF_REGISTERS + 5)99#else100#define TMP_CALL_REG TMP_REG1101#endif102103#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)104#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)105106static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {1070, 3, 4, 5, 6, 7, 8, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 1, 9, 10, 31, 12108};109110static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {1110, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 0, 13112};113114/* --------------------------------------------------------------------- */115/* Instruction forms */116/* --------------------------------------------------------------------- */117#define D(d) ((sljit_ins)reg_map[d] << 21)118#define S(s) ((sljit_ins)reg_map[s] << 21)119#define A(a) ((sljit_ins)reg_map[a] << 16)120#define B(b) ((sljit_ins)reg_map[b] << 11)121#define C(c) ((sljit_ins)reg_map[c] << 6)122#define FD(fd) ((sljit_ins)freg_map[fd] << 21)123#define FS(fs) ((sljit_ins)freg_map[fs] << 21)124#define FA(fa) ((sljit_ins)freg_map[fa] << 16)125#define FB(fb) ((sljit_ins)freg_map[fb] << 11)126#define FC(fc) ((sljit_ins)freg_map[fc] << 6)127#define IMM(imm) ((sljit_ins)(imm) & 0xffff)128#define CRD(d) ((sljit_ins)(d) << 21)129130/* Instruction bit sections.131OE and Rc flag (see ALT_SET_FLAGS). */132#define OE(flags) ((flags) & ALT_SET_FLAGS)133/* Rc flag (see ALT_SET_FLAGS). */134#define RC(flags) ((sljit_ins)((flags) & ALT_SET_FLAGS) >> 10)135#define HI(opcode) ((sljit_ins)(opcode) << 26)136#define LO(opcode) ((sljit_ins)(opcode) << 1)137138#define ADD (HI(31) | LO(266))139#define ADDC (HI(31) | LO(10))140#define ADDE (HI(31) | LO(138))141#define ADDI (HI(14))142#define ADDIC (HI(13))143#define ADDIS (HI(15))144#define ADDME (HI(31) | LO(234))145#define AND (HI(31) | LO(28))146#define ANDI (HI(28))147#define ANDIS (HI(29))148#define Bx (HI(18))149#define BCx (HI(16))150#define BCCTR (HI(19) | LO(528) | (3 << 11))151#define BLR (HI(19) | LO(16) | (0x14 << 21))152#if defined(_ARCH_PWR10) && _ARCH_PWR10153#define BRD (HI(31) | LO(187))154#endif /* POWER10 */155#define CNTLZD (HI(31) | LO(58))156#define CNTLZW (HI(31) | LO(26))157#define CMP (HI(31) | LO(0))158#define CMPI (HI(11))159#define CMPL (HI(31) | LO(32))160#define CMPLI (HI(10))161#define CROR (HI(19) | LO(449))162#define DCBT (HI(31) | LO(278))163#define DIVD (HI(31) | LO(489))164#define DIVDU (HI(31) | LO(457))165#define DIVW (HI(31) | LO(491))166#define DIVWU (HI(31) | LO(459))167#define EXTSB (HI(31) | LO(954))168#define EXTSH (HI(31) | LO(922))169#define EXTSW (HI(31) | LO(986))170#define FABS (HI(63) | LO(264))171#define FADD (HI(63) | LO(21))172#define FADDS (HI(59) | LO(21))173#define FCFID (HI(63) | LO(846))174#define FCMPU (HI(63) | LO(0))175#define FCTIDZ (HI(63) | LO(815))176#define FCTIWZ (HI(63) | LO(15))177#define FDIV (HI(63) | LO(18))178#define FDIVS (HI(59) | LO(18))179#define FMR (HI(63) | LO(72))180#define FMUL (HI(63) | LO(25))181#define FMULS (HI(59) | LO(25))182#define FNEG (HI(63) | LO(40))183#define FRSP (HI(63) | LO(12))184#define FSUB (HI(63) | LO(20))185#define FSUBS (HI(59) | LO(20))186#define LD (HI(58) | 0)187#define LFD (HI(50))188#define LFS (HI(48))189#define LDARX (HI(31) | LO(84))190#if defined(_ARCH_PWR7) && _ARCH_PWR7191#define LDBRX (HI(31) | LO(532))192#endif /* POWER7 */193#define LHBRX (HI(31) | LO(790))194#define LWARX (HI(31) | LO(20))195#define LWBRX (HI(31) | LO(534))196#define LWZ (HI(32))197#define MFCR (HI(31) | LO(19))198#define MFLR (HI(31) | LO(339) | 0x80000)199#define MFXER (HI(31) | LO(339) | 0x10000)200#define MTCTR (HI(31) | LO(467) | 0x90000)201#define MTLR (HI(31) | LO(467) | 0x80000)202#define MTXER (HI(31) | LO(467) | 0x10000)203#define MULHD (HI(31) | LO(73))204#define MULHDU (HI(31) | LO(9))205#define MULHW (HI(31) | LO(75))206#define MULHWU (HI(31) | LO(11))207#define MULLD (HI(31) | LO(233))208#define MULLI (HI(7))209#define MULLW (HI(31) | LO(235))210#define NEG (HI(31) | LO(104))211#define NOP (HI(24))212#define NOR (HI(31) | LO(124))213#define OR (HI(31) | LO(444))214#define ORI (HI(24))215#define ORIS (HI(25))216#define RLDCL (HI(30) | LO(8))217#define RLDICL (HI(30) | LO(0 << 1))218#define RLDICR (HI(30) | LO(1 << 1))219#define RLDIMI (HI(30) | LO(3 << 1))220#define RLWIMI (HI(20))221#define RLWINM (HI(21))222#define RLWNM (HI(23))223#define SLD (HI(31) | LO(27))224#define SLW (HI(31) | LO(24))225#define SRAD (HI(31) | LO(794))226#define SRADI (HI(31) | LO(413 << 1))227#define SRAW (HI(31) | LO(792))228#define SRAWI (HI(31) | LO(824))229#define SRD (HI(31) | LO(539))230#define SRW (HI(31) | LO(536))231#define STD (HI(62) | 0)232#if defined(_ARCH_PWR7) && _ARCH_PWR7233#define STDBRX (HI(31) | LO(660))234#endif /* POWER7 */235#define STDCX (HI(31) | LO(214))236#define STDU (HI(62) | 1)237#define STDUX (HI(31) | LO(181))238#define STFD (HI(54))239#define STFIWX (HI(31) | LO(983))240#define STFS (HI(52))241#define STHBRX (HI(31) | LO(918))242#define STW (HI(36))243#define STWBRX (HI(31) | LO(662))244#define STWCX (HI(31) | LO(150))245#define STWU (HI(37))246#define STWUX (HI(31) | LO(183))247#define SUBF (HI(31) | LO(40))248#define SUBFC (HI(31) | LO(8))249#define SUBFE (HI(31) | LO(136))250#define SUBFIC (HI(8))251#define SYNC (HI(31) | LO(598))252#define XOR (HI(31) | LO(316))253#define XORI (HI(26))254#define XORIS (HI(27))255256#define SIMM_MAX (0x7fff)257#define SIMM_MIN (-0x8000)258#define UIMM_MAX (0xffff)259260/* Shift helpers. */261#define RLWI_SH(sh) ((sljit_ins)(sh) << 11)262#define RLWI_MBE(mb, me) (((sljit_ins)(mb) << 6) | ((sljit_ins)(me) << 1))263#define RLDI_SH(sh) ((((sljit_ins)(sh) & 0x1f) << 11) | (((sljit_ins)(sh) & 0x20) >> 4))264#define RLDI_MB(mb) ((((sljit_ins)(mb) & 0x1f) << 6) | ((sljit_ins)(mb) & 0x20))265#define RLDI_ME(me) RLDI_MB(me)266267#define SLWI(shift) (RLWINM | RLWI_SH(shift) | RLWI_MBE(0, 31 - (shift)))268#define SLDI(shift) (RLDICR | RLDI_SH(shift) | RLDI_ME(63 - (shift)))269/* shift > 0 */270#define SRWI(shift) (RLWINM | RLWI_SH(32 - (shift)) | RLWI_MBE((shift), 31))271#define SRDI(shift) (RLDICL | RLDI_SH(64 - (shift)) | RLDI_MB(shift))272273#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)274#define SLWI_W(shift) SLWI(shift)275#define TMP_MEM_OFFSET (2 * sizeof(sljit_sw))276#else /* !SLJIT_CONFIG_PPC_32 */277#define SLWI_W(shift) SLDI(shift)278#define TMP_MEM_OFFSET (6 * sizeof(sljit_sw))279#endif /* SLJIT_CONFIG_PPC_32 */280281#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)282#define TMP_MEM_OFFSET_LO (TMP_MEM_OFFSET)283#define TMP_MEM_OFFSET_HI (TMP_MEM_OFFSET + sizeof(sljit_s32))284#define LWBRX_FIRST_REG S(TMP_REG1)285#define LWBRX_SECOND_REG S(dst)286#else /* !SLJIT_LITTLE_ENDIAN */287#define TMP_MEM_OFFSET_LO (TMP_MEM_OFFSET + sizeof(sljit_s32))288#define TMP_MEM_OFFSET_HI (TMP_MEM_OFFSET)289#define LWBRX_FIRST_REG S(dst)290#define LWBRX_SECOND_REG S(TMP_REG1)291#endif /* SLJIT_LITTLE_ENDIAN */292293#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)294SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_uw addr, void* func)295{296sljit_uw* ptrs;297298if (func_ptr)299*func_ptr = (void*)context;300301ptrs = (sljit_uw*)func;302context->addr = addr ? addr : ptrs[0];303context->r2 = ptrs[1];304context->r11 = ptrs[2];305}306#endif307308static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)309{310sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));311FAIL_IF(!ptr);312*ptr = ins;313compiler->size++;314return SLJIT_SUCCESS;315}316317static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)318{319sljit_sw diff;320sljit_uw target_addr;321sljit_uw jump_addr = (sljit_uw)code_ptr;322sljit_uw orig_addr = jump->addr;323SLJIT_UNUSED_ARG(executable_offset);324325jump->addr = jump_addr;326#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)327if (jump->flags & (SLJIT_REWRITABLE_JUMP | IS_CALL))328goto exit;329#else330if (jump->flags & SLJIT_REWRITABLE_JUMP)331goto exit;332#endif333334if (jump->flags & JUMP_ADDR)335target_addr = jump->u.target;336else {337SLJIT_ASSERT(jump->u.label != NULL);338target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;339340if (jump->u.label->size > orig_addr)341jump_addr = (sljit_uw)(code + orig_addr);342}343344#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)345if (jump->flags & IS_CALL)346goto keep_address;347#endif348349diff = (sljit_sw)target_addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr, executable_offset);350351if (jump->flags & IS_COND) {352if (diff <= 0x7fff && diff >= -0x8000) {353jump->flags |= PATCH_B;354return code_ptr;355}356if (target_addr <= 0xffff) {357jump->flags |= PATCH_B | PATCH_ABS_B;358return code_ptr;359}360361diff -= SSIZE_OF(ins);362}363364if (diff <= 0x01ffffff && diff >= -0x02000000) {365jump->flags |= PATCH_B;366} else if (target_addr <= 0x01ffffff) {367jump->flags |= PATCH_B | PATCH_ABS_B;368}369370if (jump->flags & PATCH_B) {371if (!(jump->flags & IS_COND))372return code_ptr;373374code_ptr[0] = BCx | (2 << 2) | ((code_ptr[0] ^ (8 << 21)) & 0x03ff0001);375code_ptr[1] = Bx;376jump->addr += sizeof(sljit_ins);377jump->flags -= IS_COND;378return code_ptr + 1;379}380381#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)382#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)383keep_address:384#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */385if (target_addr < 0x80000000l) {386jump->flags |= PATCH_ABS32;387code_ptr[2] = MTCTR | S(TMP_CALL_REG);388code_ptr[3] = code_ptr[0];389return code_ptr + 3;390}391392if (target_addr < 0x800000000000l) {393jump->flags |= PATCH_ABS48;394code_ptr[4] = MTCTR | S(TMP_CALL_REG);395code_ptr[5] = code_ptr[0];396return code_ptr + 5;397}398#endif /* SLJIT_CONFIG_PPC_64 */399400exit:401#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)402code_ptr[2] = MTCTR | S(TMP_CALL_REG);403code_ptr[3] = code_ptr[0];404#else /* !SLJIT_CONFIG_PPC_32 */405code_ptr[5] = MTCTR | S(TMP_CALL_REG);406code_ptr[6] = code_ptr[0];407#endif /* SLJIT_CONFIG_PPC_32 */408return code_ptr + JUMP_MAX_SIZE - 1;409}410411#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)412413static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code, sljit_sw executable_offset)414{415sljit_uw addr;416SLJIT_UNUSED_ARG(executable_offset);417418SLJIT_ASSERT(jump->flags < ((sljit_uw)5 << JUMP_SIZE_SHIFT));419if (jump->flags & JUMP_ADDR)420addr = jump->u.target;421else422addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset);423424if (addr < 0x80000000l) {425SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT));426jump->flags |= PATCH_ABS32;427return 1;428}429430if (addr < 0x800000000000l) {431SLJIT_ASSERT(jump->flags >= ((sljit_uw)3 << JUMP_SIZE_SHIFT));432jump->flags |= PATCH_ABS48;433return 3;434}435436SLJIT_ASSERT(jump->flags >= ((sljit_uw)4 << JUMP_SIZE_SHIFT));437return 4;438}439440#endif /* SLJIT_CONFIG_PPC_64 */441442static void generate_jump_or_mov_addr(struct sljit_jump *jump, sljit_sw executable_offset)443{444sljit_uw flags = jump->flags;445sljit_uw addr = (flags & JUMP_ADDR) ? jump->u.target : jump->u.label->u.addr;446sljit_ins *ins = (sljit_ins*)jump->addr;447sljit_s32 reg;448SLJIT_UNUSED_ARG(executable_offset);449450if (flags & PATCH_B) {451if (flags & IS_COND) {452if (!(flags & PATCH_ABS_B)) {453addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(ins, executable_offset);454SLJIT_ASSERT((sljit_sw)addr <= 0x7fff && (sljit_sw)addr >= -0x8000);455ins[0] = BCx | ((sljit_ins)addr & 0xfffc) | (ins[0] & 0x03ff0001);456} else {457SLJIT_ASSERT(addr <= 0xffff);458ins[0] = BCx | ((sljit_ins)addr & 0xfffc) | 0x2 | ((*ins) & 0x03ff0001);459}460return;461}462463if (!(flags & PATCH_ABS_B)) {464addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(ins, executable_offset);465SLJIT_ASSERT((sljit_sw)addr <= 0x01ffffff && (sljit_sw)addr >= -0x02000000);466ins[0] = Bx | ((sljit_ins)addr & 0x03fffffc) | (ins[0] & 0x1);467} else {468SLJIT_ASSERT(addr <= 0x03ffffff);469ins[0] = Bx | ((sljit_ins)addr & 0x03fffffc) | 0x2 | (ins[0] & 0x1);470}471return;472}473474reg = (flags & JUMP_MOV_ADDR) ? (sljit_s32)ins[0] : TMP_CALL_REG;475476#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)477ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 16);478ins[1] = ORI | S(reg) | A(reg) | IMM(addr);479#else /* !SLJIT_CONFIG_PPC_32 */480481/* The TMP_ZERO cannot be used because it is restored for tail calls. */482if (flags & PATCH_ABS32) {483SLJIT_ASSERT(addr < 0x80000000l);484ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 16);485ins[1] = ORI | S(reg) | A(reg) | IMM(addr);486return;487}488489if (flags & PATCH_ABS48) {490SLJIT_ASSERT(addr < 0x800000000000l);491ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 32);492ins[1] = ORI | S(reg) | A(reg) | IMM(addr >> 16);493ins[2] = SLDI(16) | S(reg) | A(reg);494ins[3] = ORI | S(reg) | A(reg) | IMM(addr);495return;496}497498ins[0] = ADDIS | D(reg) | A(0) | IMM(addr >> 48);499ins[1] = ORI | S(reg) | A(reg) | IMM(addr >> 32);500ins[2] = SLDI(32) | S(reg) | A(reg);501ins[3] = ORIS | S(reg) | A(reg) | IMM(addr >> 16);502ins[4] = ORI | S(reg) | A(reg) | IMM(addr);503#endif /* SLJIT_CONFIG_PPC_32 */504}505506static SLJIT_INLINE sljit_ins *process_extended_label(sljit_ins *code_ptr, struct sljit_extended_label *ext_label)507{508SLJIT_ASSERT(ext_label->label.u.index == SLJIT_LABEL_ALIGNED);509return (sljit_ins*)((sljit_uw)code_ptr & ~(ext_label->data));510}511512static void reduce_code_size(struct sljit_compiler *compiler)513{514struct sljit_label *label;515struct sljit_jump *jump;516struct sljit_const *const_;517SLJIT_NEXT_DEFINE_TYPES;518sljit_uw total_size;519sljit_uw size_reduce = 0;520sljit_sw diff;521522label = compiler->labels;523jump = compiler->jumps;524const_ = compiler->consts;525SLJIT_NEXT_INIT_TYPES();526527while (1) {528SLJIT_GET_NEXT_MIN();529530if (next_min_addr == SLJIT_MAX_ADDRESS)531break;532533if (next_min_addr == next_label_size) {534label->size -= size_reduce;535536label = label->next;537next_label_size = SLJIT_GET_NEXT_SIZE(label);538}539540if (next_min_addr == next_const_addr) {541const_->addr -= size_reduce;542const_ = const_->next;543next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);544continue;545}546547if (next_min_addr != next_jump_addr)548continue;549550jump->addr -= size_reduce;551if (!(jump->flags & JUMP_MOV_ADDR)) {552total_size = JUMP_MAX_SIZE - 1;553554if (!(jump->flags & SLJIT_REWRITABLE_JUMP)) {555if (jump->flags & JUMP_ADDR) {556if (jump->u.target <= 0x01ffffff)557total_size = 1 - 1;558#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)559else if (jump->u.target < 0x80000000l)560total_size = 4 - 1;561else if (jump->u.target < 0x800000000000l)562total_size = 6 - 1;563#endif /* SLJIT_CONFIG_PPC_64 */564} else {565/* Unit size: instruction. */566diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr;567if (jump->u.label->size > jump->addr) {568SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr);569diff -= (sljit_sw)size_reduce;570}571572if (jump->flags & IS_COND) {573if (diff <= (0x7fff / SSIZE_OF(ins)) && diff >= (-0x8000 / SSIZE_OF(ins)))574total_size = 1 - 1;575else if ((diff - 1) <= (0x01ffffff / SSIZE_OF(ins)) && (diff - 1) >= (-0x02000000 / SSIZE_OF(ins)))576total_size = 2 - 1;577} else if (diff <= (0x01ffffff / SSIZE_OF(ins)) && diff >= (-0x02000000 / SSIZE_OF(ins)))578total_size = 1 - 1;579}580}581582size_reduce += (JUMP_MAX_SIZE - 1) - total_size;583jump->flags |= total_size << JUMP_SIZE_SHIFT;584#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)585} else {586total_size = (sljit_uw)4 << JUMP_SIZE_SHIFT;587588if (jump->flags & JUMP_ADDR) {589if (jump->u.target < 0x80000000l) {590total_size = (sljit_uw)1 << JUMP_SIZE_SHIFT;591size_reduce += 3;592} else if (jump->u.target < 0x800000000000l) {593total_size = (sljit_uw)3 << JUMP_SIZE_SHIFT;594size_reduce += 1;595}596}597jump->flags |= total_size;598#endif /* SLJIT_CONFIG_PPC_64 */599}600601jump = jump->next;602next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);603}604605compiler->size -= size_reduce;606}607608SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler, sljit_s32 options, void *exec_allocator_data)609{610struct sljit_memory_fragment *buf;611sljit_ins *code;612sljit_ins *code_ptr;613sljit_ins *buf_ptr;614sljit_ins *buf_end;615sljit_uw word_count;616#if (defined SLJIT_DEBUG && SLJIT_DEBUG)617sljit_uw jump_addr;618#endif619SLJIT_NEXT_DEFINE_TYPES;620sljit_sw executable_offset;621622struct sljit_label *label;623struct sljit_jump *jump;624struct sljit_const *const_;625626CHECK_ERROR_PTR();627CHECK_PTR(check_sljit_generate_code(compiler, options));628629reduce_code_size(compiler);630631#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)632if (!(options & SLJIT_GENERATE_CODE_NO_CONTEXT)) {633/* add to compiler->size additional instruction space to hold the trampoline and padding */634#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)635compiler->size += (compiler->size & 0x1) + (sizeof(struct sljit_function_context) / sizeof(sljit_ins));636#else /* !SLJIT_CONFIG_PPC_64 */637compiler->size += (sizeof(struct sljit_function_context) / sizeof(sljit_ins));638#endif /* SLJIT_CONFIG_PPC_64 */639}640#endif /* SLJIT_INDIRECT_CALL */641code = (sljit_ins*)allocate_executable_memory(compiler->size * sizeof(sljit_ins), options, exec_allocator_data, &executable_offset);642PTR_FAIL_WITH_EXEC_IF(code);643644reverse_buf(compiler);645buf = compiler->buf;646647code_ptr = code;648word_count = 0;649label = compiler->labels;650jump = compiler->jumps;651const_ = compiler->consts;652SLJIT_NEXT_INIT_TYPES();653SLJIT_GET_NEXT_MIN();654655do {656buf_ptr = (sljit_ins*)buf->memory;657buf_end = buf_ptr + (buf->used_size >> 2);658do {659*code_ptr = *buf_ptr++;660if (next_min_addr == word_count) {661SLJIT_ASSERT(!label || label->size >= word_count);662SLJIT_ASSERT(!jump || jump->addr >= word_count);663SLJIT_ASSERT(!const_ || const_->addr >= word_count);664665/* These structures are ordered by their address. */666if (next_min_addr == next_label_size) {667if (label->u.index >= SLJIT_LABEL_ALIGNED) {668code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);669*code_ptr = buf_ptr[-1];670}671672/* Just recording the address. */673label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);674label->size = (sljit_uw)(code_ptr - code);675label = label->next;676next_label_size = SLJIT_GET_NEXT_SIZE(label);677}678679if (next_min_addr == next_jump_addr) {680if (!(jump->flags & JUMP_MOV_ADDR)) {681word_count += jump->flags >> JUMP_SIZE_SHIFT;682#if (defined SLJIT_DEBUG && SLJIT_DEBUG)683jump_addr = (sljit_uw)code_ptr;684#endif685code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset);686SLJIT_ASSERT(((sljit_uw)code_ptr - jump_addr <= (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins)));687} else {688jump->addr = (sljit_uw)code_ptr;689#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)690word_count += jump->flags >> JUMP_SIZE_SHIFT;691code_ptr += mov_addr_get_length(jump, code, executable_offset);692#else /* !SLJIT_CONFIG_PPC_64 */693word_count++;694code_ptr++;695#endif /* SLJIT_CONFIG_PPC_64 */696}697jump = jump->next;698next_jump_addr = SLJIT_GET_NEXT_ADDRESS(jump);699} else if (next_min_addr == next_const_addr) {700const_->addr = (sljit_uw)code_ptr;701const_ = const_->next;702next_const_addr = SLJIT_GET_NEXT_ADDRESS(const_);703}704705SLJIT_GET_NEXT_MIN();706}707code_ptr++;708word_count++;709} while (buf_ptr < buf_end);710711buf = buf->next;712} while (buf);713714if (label && label->size == word_count) {715if (label->u.index >= SLJIT_LABEL_ALIGNED)716code_ptr = process_extended_label(code_ptr, (struct sljit_extended_label*)label);717718label->u.addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);719label->size = (sljit_uw)(code_ptr - code);720label = label->next;721}722723SLJIT_ASSERT(!label);724SLJIT_ASSERT(!jump);725SLJIT_ASSERT(!const_);726727#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)728SLJIT_ASSERT(code_ptr - code <= (sljit_sw)(compiler->size -729((options & SLJIT_GENERATE_CODE_NO_CONTEXT) ? 0 : (sizeof(struct sljit_function_context) / sizeof(sljit_ins)))));730#else731SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size);732#endif733734jump = compiler->jumps;735while (jump) {736generate_jump_or_mov_addr(jump, executable_offset);737jump = jump->next;738}739740compiler->error = SLJIT_ERR_COMPILED;741compiler->executable_offset = executable_offset;742743code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);744745#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)746if (!(options & SLJIT_GENERATE_CODE_NO_CONTEXT)) {747#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)748if (((sljit_sw)code_ptr) & 0x4)749code_ptr++;750#endif /* SLJIT_CONFIG_PPC_64 */751sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_uw)code, (void*)sljit_generate_code);752}753#endif /* SLJIT_INDIRECT_CALL */754755code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);756757SLJIT_CACHE_FLUSH(code, code_ptr);758SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);759760#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)761if (!(options & SLJIT_GENERATE_CODE_NO_CONTEXT)) {762compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins) + sizeof(struct sljit_function_context);763return code_ptr;764}765#endif /* SLJIT_INDIRECT_CALL */766767compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins);768return code;769}770771SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)772{773switch (feature_type) {774case SLJIT_HAS_FPU:775#ifdef SLJIT_IS_FPU_AVAILABLE776return (SLJIT_IS_FPU_AVAILABLE) != 0;777#else778/* Available by default. */779return 1;780#endif781case SLJIT_HAS_REV:782#if defined(_ARCH_PWR10) && _ARCH_PWR10783return 1;784#else /* !POWER10 */785return 2;786#endif /* POWER10 */787/* A saved register is set to a zero value. */788case SLJIT_HAS_ZERO_REGISTER:789case SLJIT_HAS_CLZ:790case SLJIT_HAS_ROT:791case SLJIT_HAS_PREFETCH:792case SLJIT_HAS_ATOMIC:793case SLJIT_HAS_MEMORY_BARRIER:794return 1;795796case SLJIT_HAS_CTZ:797return 2;798799default:800return 0;801}802}803804SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)805{806switch (type) {807case SLJIT_UNORDERED_OR_EQUAL:808case SLJIT_ORDERED_NOT_EQUAL:809case SLJIT_UNORDERED_OR_LESS:810case SLJIT_ORDERED_GREATER_EQUAL:811case SLJIT_UNORDERED_OR_GREATER:812case SLJIT_ORDERED_LESS_EQUAL:813return 1;814}815816return 0;817}818819/* --------------------------------------------------------------------- */820/* Entry, exit */821/* --------------------------------------------------------------------- */822823/* inp_flags: */824825/* Creates an index in data_transfer_insts array. */826#define LOAD_DATA 0x01827#define INDEXED 0x02828#define SIGNED_DATA 0x04829830#define WORD_DATA 0x00831#define BYTE_DATA 0x08832#define HALF_DATA 0x10833#define INT_DATA 0x18834/* Separates integer and floating point registers */835#define GPR_REG 0x1f836#define DOUBLE_DATA 0x20837838#define MEM_MASK 0x7f839840#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_32) >> 6))841842/* Other inp_flags. */843844/* Integer opertion and set flags -> requires exts on 64 bit systems. */845#define ALT_SIGN_EXT 0x000100846/* This flag affects the RC() and OERC() macros. */847#define ALT_SET_FLAGS 0x000400848#define ALT_FORM1 0x001000849#define ALT_FORM2 0x002000850#define ALT_FORM3 0x004000851#define ALT_FORM4 0x008000852#define ALT_FORM5 0x010000853854/* Source and destination is register. */855#define REG_DEST 0x000001856#define REG1_SOURCE 0x000002857#define REG2_SOURCE 0x000004858/*859ALT_SIGN_EXT 0x000100860ALT_SET_FLAGS 0x000200861ALT_FORM1 0x001000862...863ALT_FORM5 0x010000 */864865static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg,866sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg);867868#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)869#include "sljitNativePPC_32.c"870#else871#include "sljitNativePPC_64.c"872#endif873874#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)875#define STACK_STORE STW876#define STACK_LOAD LWZ877#else878#define STACK_STORE STD879#define STACK_LOAD LD880#endif881882#if (defined SLJIT_PPC_STACK_FRAME_V2 && SLJIT_PPC_STACK_FRAME_V2)883#define LR_SAVE_OFFSET (2 * SSIZE_OF(sw))884#else885#define LR_SAVE_OFFSET SSIZE_OF(sw)886#endif887888#define STACK_MAX_DISTANCE (0x8000 - SSIZE_OF(sw) - LR_SAVE_OFFSET)889890SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,891sljit_s32 options, sljit_s32 arg_types,892sljit_s32 scratches, sljit_s32 saveds, sljit_s32 local_size)893{894sljit_s32 fscratches = ENTER_GET_FLOAT_REGS(scratches);895sljit_s32 fsaveds = ENTER_GET_FLOAT_REGS(saveds);896sljit_s32 i, tmp, base, offset;897sljit_s32 word_arg_count = 0;898sljit_s32 saved_arg_count = SLJIT_KEPT_SAVEDS_COUNT(options);899#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)900sljit_s32 arg_count = 0;901#endif902903CHECK_ERROR();904CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, local_size));905set_emit_enter(compiler, options, arg_types, scratches, saveds, local_size);906907scratches = ENTER_GET_REGS(scratches);908saveds = ENTER_GET_REGS(saveds);909local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 0)910+ GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);911912if (!(options & SLJIT_ENTER_REG_ARG))913local_size += SSIZE_OF(sw);914915local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;916compiler->local_size = local_size;917918FAIL_IF(push_inst(compiler, MFLR | D(0)));919920base = SLJIT_SP;921offset = local_size;922923if (local_size <= STACK_MAX_DISTANCE) {924#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)925FAIL_IF(push_inst(compiler, STWU | S(SLJIT_SP) | A(SLJIT_SP) | IMM(-local_size)));926#else927FAIL_IF(push_inst(compiler, STDU | S(SLJIT_SP) | A(SLJIT_SP) | IMM(-local_size)));928#endif929} else {930base = TMP_REG1;931FAIL_IF(push_inst(compiler, OR | S(SLJIT_SP) | A(TMP_REG1) | B(SLJIT_SP)));932FAIL_IF(load_immediate(compiler, TMP_REG2, -local_size));933#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)934FAIL_IF(push_inst(compiler, STWUX | S(SLJIT_SP) | A(SLJIT_SP) | B(TMP_REG2)));935#else936FAIL_IF(push_inst(compiler, STDUX | S(SLJIT_SP) | A(SLJIT_SP) | B(TMP_REG2)));937#endif938local_size = 0;939offset = 0;940}941942tmp = SLJIT_FS0 - fsaveds;943for (i = SLJIT_FS0; i > tmp; i--) {944offset -= SSIZE_OF(f64);945FAIL_IF(push_inst(compiler, STFD | FS(i) | A(base) | IMM(offset)));946}947948for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {949offset -= SSIZE_OF(f64);950FAIL_IF(push_inst(compiler, STFD | FS(i) | A(base) | IMM(offset)));951}952953if (!(options & SLJIT_ENTER_REG_ARG)) {954offset -= SSIZE_OF(sw);955FAIL_IF(push_inst(compiler, STACK_STORE | S(TMP_ZERO) | A(base) | IMM(offset)));956}957958tmp = SLJIT_S0 - saveds;959for (i = SLJIT_S0 - saved_arg_count; i > tmp; i--) {960offset -= SSIZE_OF(sw);961FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(base) | IMM(offset)));962}963964for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {965offset -= SSIZE_OF(sw);966FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(base) | IMM(offset)));967}968969FAIL_IF(push_inst(compiler, STACK_STORE | S(0) | A(base) | IMM(local_size + LR_SAVE_OFFSET)));970971if (options & SLJIT_ENTER_REG_ARG)972return SLJIT_SUCCESS;973974FAIL_IF(push_inst(compiler, ADDI | D(TMP_ZERO) | A(0) | 0));975976arg_types >>= SLJIT_ARG_SHIFT;977saved_arg_count = 0;978979while (arg_types > 0) {980if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) {981#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)982do {983if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) {984tmp = SLJIT_S0 - saved_arg_count;985saved_arg_count++;986} else if (arg_count != word_arg_count)987tmp = SLJIT_R0 + word_arg_count;988else989break;990991FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0 + arg_count) | A(tmp) | B(SLJIT_R0 + arg_count)));992} while (0);993#else994if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) {995FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0 + word_arg_count) | A(SLJIT_S0 - saved_arg_count) | B(SLJIT_R0 + word_arg_count)));996saved_arg_count++;997}998#endif999word_arg_count++;1000}10011002#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1003arg_count++;1004#endif1005arg_types >>= SLJIT_ARG_SHIFT;1006}10071008return SLJIT_SUCCESS;1009}10101011SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,1012sljit_s32 options, sljit_s32 arg_types,1013sljit_s32 scratches, sljit_s32 saveds, sljit_s32 local_size)1014{1015sljit_s32 fscratches = ENTER_GET_FLOAT_REGS(scratches);1016sljit_s32 fsaveds = ENTER_GET_FLOAT_REGS(saveds);10171018CHECK_ERROR();1019CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, local_size));1020set_emit_enter(compiler, options, arg_types, scratches, saveds, local_size);10211022scratches = ENTER_GET_REGS(scratches);1023saveds = ENTER_GET_REGS(saveds);1024local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 0)1025+ GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);10261027if (!(options & SLJIT_ENTER_REG_ARG))1028local_size += SSIZE_OF(sw);10291030compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;1031return SLJIT_SUCCESS;1032}10331034static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 is_return_to)1035{1036sljit_s32 i, tmp, base, offset;1037sljit_s32 local_size = compiler->local_size;10381039SLJIT_ASSERT(TMP_CALL_REG != TMP_REG2);10401041base = SLJIT_SP;1042if (local_size > STACK_MAX_DISTANCE) {1043base = TMP_REG2;1044if (local_size > 2 * STACK_MAX_DISTANCE + LR_SAVE_OFFSET) {1045FAIL_IF(push_inst(compiler, STACK_LOAD | D(base) | A(SLJIT_SP) | IMM(0)));1046local_size = 0;1047} else {1048FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(SLJIT_SP) | IMM(local_size - STACK_MAX_DISTANCE)));1049local_size = STACK_MAX_DISTANCE;1050}1051}10521053offset = local_size;1054if (!is_return_to)1055FAIL_IF(push_inst(compiler, STACK_LOAD | S(0) | A(base) | IMM(offset + LR_SAVE_OFFSET)));10561057tmp = SLJIT_FS0 - compiler->fsaveds;1058for (i = SLJIT_FS0; i > tmp; i--) {1059offset -= SSIZE_OF(f64);1060FAIL_IF(push_inst(compiler, LFD | FS(i) | A(base) | IMM(offset)));1061}10621063for (i = compiler->fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {1064offset -= SSIZE_OF(f64);1065FAIL_IF(push_inst(compiler, LFD | FS(i) | A(base) | IMM(offset)));1066}10671068if (!(compiler->options & SLJIT_ENTER_REG_ARG)) {1069offset -= SSIZE_OF(sw);1070FAIL_IF(push_inst(compiler, STACK_LOAD | S(TMP_ZERO) | A(base) | IMM(offset)));1071}10721073tmp = SLJIT_S0 - compiler->saveds;1074for (i = SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options); i > tmp; i--) {1075offset -= SSIZE_OF(sw);1076FAIL_IF(push_inst(compiler, STACK_LOAD | S(i) | A(base) | IMM(offset)));1077}10781079for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {1080offset -= SSIZE_OF(sw);1081FAIL_IF(push_inst(compiler, STACK_LOAD | S(i) | A(base) | IMM(offset)));1082}10831084if (!is_return_to)1085push_inst(compiler, MTLR | S(0));10861087if (local_size > 0)1088return push_inst(compiler, ADDI | D(SLJIT_SP) | A(base) | IMM(local_size));10891090SLJIT_ASSERT(base == TMP_REG2);1091return push_inst(compiler, OR | S(base) | A(SLJIT_SP) | B(base));1092}10931094#undef STACK_STORE1095#undef STACK_LOAD10961097SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)1098{1099CHECK_ERROR();1100CHECK(check_sljit_emit_return_void(compiler));11011102FAIL_IF(emit_stack_frame_release(compiler, 0));1103return push_inst(compiler, BLR);1104}11051106SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler,1107sljit_s32 src, sljit_sw srcw)1108{1109CHECK_ERROR();1110CHECK(check_sljit_emit_return_to(compiler, src, srcw));11111112if (src & SLJIT_MEM) {1113ADJUST_LOCAL_OFFSET(src, srcw);1114FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_CALL_REG, src, srcw, TMP_CALL_REG));1115src = TMP_CALL_REG;1116srcw = 0;1117} else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {1118FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src)));1119src = TMP_CALL_REG;1120srcw = 0;1121}11221123FAIL_IF(emit_stack_frame_release(compiler, 1));11241125SLJIT_SKIP_CHECKS(compiler);1126return sljit_emit_ijump(compiler, SLJIT_JUMP, src, srcw);1127}11281129/* --------------------------------------------------------------------- */1130/* Operators */1131/* --------------------------------------------------------------------- */11321133/* s/l - store/load (1 bit)1134i/x - immediate/indexed form1135u/s - signed/unsigned (1 bit)1136w/b/h/i - word/byte/half/int allowed (2 bit)11371138Some opcodes are repeated (e.g. store signed / unsigned byte is the same instruction). */11391140/* 64 bit only: [reg+imm] must be aligned to 4 bytes. */1141#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1142#define INT_ALIGNED 0x100001143#endif11441145#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)1146#define ARCH_32_64(a, b) a1147#define INST_CODE_AND_DST(inst, flags, reg) \1148((sljit_ins)(inst) | (sljit_ins)(((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg)))1149#else1150#define ARCH_32_64(a, b) b1151#define INST_CODE_AND_DST(inst, flags, reg) \1152(((sljit_ins)(inst) & ~(sljit_ins)INT_ALIGNED) | (sljit_ins)(((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg)))1153#endif11541155static const sljit_ins data_transfer_insts[64 + 16] = {11561157/* -------- Integer -------- */11581159/* Word. */11601161/* w u i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | INT_ALIGNED | 0x0 /* std */),1162/* w u i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x0 /* ld */),1163/* w u x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */),1164/* w u x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */),11651166/* w s i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | INT_ALIGNED | 0x0 /* std */),1167/* w s i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x0 /* ld */),1168/* w s x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */),1169/* w s x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */),11701171/* Byte. */11721173/* b u i s */ HI(38) /* stb */,1174/* b u i l */ HI(34) /* lbz */,1175/* b u x s */ HI(31) | LO(215) /* stbx */,1176/* b u x l */ HI(31) | LO(87) /* lbzx */,11771178/* b s i s */ HI(38) /* stb */,1179/* b s i l */ HI(34) /* lbz */ /* EXTS_REQ */,1180/* b s x s */ HI(31) | LO(215) /* stbx */,1181/* b s x l */ HI(31) | LO(87) /* lbzx */ /* EXTS_REQ */,11821183/* Half. */11841185/* h u i s */ HI(44) /* sth */,1186/* h u i l */ HI(40) /* lhz */,1187/* h u x s */ HI(31) | LO(407) /* sthx */,1188/* h u x l */ HI(31) | LO(279) /* lhzx */,11891190/* h s i s */ HI(44) /* sth */,1191/* h s i l */ HI(42) /* lha */,1192/* h s x s */ HI(31) | LO(407) /* sthx */,1193/* h s x l */ HI(31) | LO(343) /* lhax */,11941195/* Int. */11961197/* i u i s */ HI(36) /* stw */,1198/* i u i l */ HI(32) /* lwz */,1199/* i u x s */ HI(31) | LO(151) /* stwx */,1200/* i u x l */ HI(31) | LO(23) /* lwzx */,12011202/* i s i s */ HI(36) /* stw */,1203/* i s i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x2 /* lwa */),1204/* i s x s */ HI(31) | LO(151) /* stwx */,1205/* i s x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(341) /* lwax */),12061207/* -------- Floating point -------- */12081209/* d i s */ HI(54) /* stfd */,1210/* d i l */ HI(50) /* lfd */,1211/* d x s */ HI(31) | LO(727) /* stfdx */,1212/* d x l */ HI(31) | LO(599) /* lfdx */,12131214/* s i s */ HI(52) /* stfs */,1215/* s i l */ HI(48) /* lfs */,1216/* s x s */ HI(31) | LO(663) /* stfsx */,1217/* s x l */ HI(31) | LO(535) /* lfsx */,1218};12191220static const sljit_ins updated_data_transfer_insts[64] = {12211222/* -------- Integer -------- */12231224/* Word. */12251226/* w u i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | INT_ALIGNED | 0x1 /* stdu */),1227/* w u i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | 0x1 /* ldu */),1228/* w u x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */),1229/* w u x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */),12301231/* w s i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | INT_ALIGNED | 0x1 /* stdu */),1232/* w s i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | 0x1 /* ldu */),1233/* w s x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */),1234/* w s x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */),12351236/* Byte. */12371238/* b u i s */ HI(39) /* stbu */,1239/* b u i l */ HI(35) /* lbzu */,1240/* b u x s */ HI(31) | LO(247) /* stbux */,1241/* b u x l */ HI(31) | LO(119) /* lbzux */,12421243/* b s i s */ HI(39) /* stbu */,1244/* b s i l */ 0 /* no such instruction */,1245/* b s x s */ HI(31) | LO(247) /* stbux */,1246/* b s x l */ 0 /* no such instruction */,12471248/* Half. */12491250/* h u i s */ HI(45) /* sthu */,1251/* h u i l */ HI(41) /* lhzu */,1252/* h u x s */ HI(31) | LO(439) /* sthux */,1253/* h u x l */ HI(31) | LO(311) /* lhzux */,12541255/* h s i s */ HI(45) /* sthu */,1256/* h s i l */ HI(43) /* lhau */,1257/* h s x s */ HI(31) | LO(439) /* sthux */,1258/* h s x l */ HI(31) | LO(375) /* lhaux */,12591260/* Int. */12611262/* i u i s */ HI(37) /* stwu */,1263/* i u i l */ HI(33) /* lwzu */,1264/* i u x s */ HI(31) | LO(183) /* stwux */,1265/* i u x l */ HI(31) | LO(55) /* lwzux */,12661267/* i s i s */ HI(37) /* stwu */,1268/* i s i l */ ARCH_32_64(HI(33) /* lwzu */, 0 /* no such instruction */),1269/* i s x s */ HI(31) | LO(183) /* stwux */,1270/* i s x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(373) /* lwaux */),12711272/* -------- Floating point -------- */12731274/* d i s */ HI(55) /* stfdu */,1275/* d i l */ HI(51) /* lfdu */,1276/* d x s */ HI(31) | LO(759) /* stfdux */,1277/* d x l */ HI(31) | LO(631) /* lfdux */,12781279/* s i s */ HI(53) /* stfsu */,1280/* s i l */ HI(49) /* lfsu */,1281/* s x s */ HI(31) | LO(695) /* stfsux */,1282/* s x l */ HI(31) | LO(567) /* lfsux */,1283};12841285#undef ARCH_32_6412861287/* Simple cases, (no caching is required). */1288static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg,1289sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg)1290{1291sljit_ins inst;1292sljit_s32 offs_reg;12931294/* Should work when (arg & REG_MASK) == 0. */1295SLJIT_ASSERT(A(0) == 0);1296SLJIT_ASSERT(arg & SLJIT_MEM);12971298if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {1299argw &= 0x3;1300offs_reg = OFFS_REG(arg);13011302if (argw != 0) {1303FAIL_IF(push_inst(compiler, SLWI_W(argw) | S(OFFS_REG(arg)) | A(tmp_reg)));1304offs_reg = tmp_reg;1305}13061307inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];13081309#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1310SLJIT_ASSERT(!(inst & INT_ALIGNED));1311#endif /* SLJIT_CONFIG_PPC_64 */13121313return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(offs_reg));1314}13151316inst = data_transfer_insts[inp_flags & MEM_MASK];1317arg &= REG_MASK;13181319#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1320if ((inst & INT_ALIGNED) && (argw & 0x3) != 0) {1321FAIL_IF(load_immediate(compiler, tmp_reg, argw));13221323inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];1324return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | B(tmp_reg));1325}1326#endif /* SLJIT_CONFIG_PPC_64 */13271328if (argw <= SIMM_MAX && argw >= SIMM_MIN)1329return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | IMM(argw));13301331#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1332if (argw <= 0x7fff7fffl && argw >= -0x80000000l) {1333#endif /* SLJIT_CONFIG_PPC_64 */1334FAIL_IF(push_inst(compiler, ADDIS | D(tmp_reg) | A(arg) | IMM((argw + 0x8000) >> 16)));1335return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(tmp_reg) | IMM(argw));1336#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1337}13381339FAIL_IF(load_immediate(compiler, tmp_reg, argw));13401341inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];1342return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | B(tmp_reg));1343#endif /* SLJIT_CONFIG_PPC_64 */1344}13451346static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 input_flags,1347sljit_s32 dst, sljit_sw dstw,1348sljit_s32 src1, sljit_sw src1w,1349sljit_s32 src2, sljit_sw src2w)1350{1351/* arg1 goes to TMP_REG1 or src reg1352arg2 goes to TMP_REG2, imm or src reg1353result goes to TMP_REG2, so put result can use TMP_REG1. */1354sljit_s32 dst_r = TMP_REG2;1355sljit_s32 src1_r;1356sljit_s32 src2_r;1357sljit_s32 src2_tmp_reg = (!(input_flags & ALT_SIGN_EXT) && GET_OPCODE(op) >= SLJIT_OP2_BASE && FAST_IS_REG(src1)) ? TMP_REG1 : TMP_REG2;1358sljit_s32 flags = input_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_SIGN_EXT | ALT_SET_FLAGS);13591360/* Destination check. */1361if (FAST_IS_REG(dst)) {1362dst_r = dst;1363/* The REG_DEST is only used by SLJIT_MOV operations, although1364* it is set for op2 operations with unset destination. */1365flags |= REG_DEST;13661367if (op >= SLJIT_MOV && op <= SLJIT_MOV_P)1368src2_tmp_reg = dst_r;1369}13701371/* Source 2. */1372if (FAST_IS_REG(src2)) {1373src2_r = src2;1374flags |= REG2_SOURCE;13751376if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOV_P)1377dst_r = src2_r;1378} else if (src2 == SLJIT_IMM) {1379src2_r = TMP_ZERO;1380if (src2w != 0) {1381FAIL_IF(load_immediate(compiler, src2_tmp_reg, src2w));1382src2_r = src2_tmp_reg;1383}1384} else {1385FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, src2_tmp_reg, src2, src2w, TMP_REG1));1386src2_r = src2_tmp_reg;1387}13881389/* Source 1. */1390if (FAST_IS_REG(src1)) {1391src1_r = src1;1392flags |= REG1_SOURCE;1393} else if (src1 == SLJIT_IMM) {1394src1_r = TMP_ZERO;1395if (src1w != 0) {1396FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));1397src1_r = TMP_REG1;1398}1399} else {1400FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));1401src1_r = TMP_REG1;1402}14031404FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));14051406if (!(dst & SLJIT_MEM))1407return SLJIT_SUCCESS;14081409return emit_op_mem(compiler, input_flags, dst_r, dst, dstw, TMP_REG1);1410}14111412SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)1413{1414#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1415sljit_s32 int_op = op & SLJIT_32;1416#endif14171418CHECK_ERROR();1419CHECK(check_sljit_emit_op0(compiler, op));14201421op = GET_OPCODE(op);1422switch (op) {1423case SLJIT_BREAKPOINT:1424case SLJIT_NOP:1425return push_inst(compiler, NOP);1426case SLJIT_LMUL_UW:1427case SLJIT_LMUL_SW:1428FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));1429#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1430FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));1431return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHDU : MULHD) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));1432#else1433FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));1434return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHWU : MULHW) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));1435#endif1436case SLJIT_DIVMOD_UW:1437case SLJIT_DIVMOD_SW:1438FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));1439#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1440FAIL_IF(push_inst(compiler, (int_op ? (op == SLJIT_DIVMOD_UW ? DIVWU : DIVW) : (op == SLJIT_DIVMOD_UW ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));1441FAIL_IF(push_inst(compiler, (int_op ? MULLW : MULLD) | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));1442#else1443FAIL_IF(push_inst(compiler, (op == SLJIT_DIVMOD_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));1444FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));1445#endif1446return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1));1447case SLJIT_DIV_UW:1448case SLJIT_DIV_SW:1449#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1450return push_inst(compiler, (int_op ? (op == SLJIT_DIV_UW ? DIVWU : DIVW) : (op == SLJIT_DIV_UW ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));1451#else1452return push_inst(compiler, (op == SLJIT_DIV_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));1453#endif1454case SLJIT_MEMORY_BARRIER:1455return push_inst(compiler, SYNC);1456case SLJIT_ENDBR:1457case SLJIT_SKIP_FRAMES_BEFORE_RETURN:1458return SLJIT_SUCCESS;1459}14601461return SLJIT_SUCCESS;1462}14631464static sljit_s32 emit_rev(struct sljit_compiler *compiler, sljit_s32 op,1465sljit_s32 dst, sljit_sw dstw,1466sljit_s32 src, sljit_sw srcw)1467{1468sljit_s32 mem, offs_reg, inp_flags;1469sljit_sw memw;1470#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1471sljit_s32 is_32 = op & SLJIT_32;14721473op = GET_OPCODE(op);1474#endif /* SLJIT_CONFIG_PPC_64 */14751476if (!((dst | src) & SLJIT_MEM)) {1477/* Both are registers. */1478if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) {1479if (src == dst) {1480FAIL_IF(push_inst(compiler, RLWIMI | S(dst) | A(dst) | RLWI_SH(16) | RLWI_MBE(8, 15)));1481FAIL_IF(push_inst(compiler, RLWINM | S(dst) | A(dst) | RLWI_SH(24) | RLWI_MBE(16, 31)));1482} else {1483FAIL_IF(push_inst(compiler, RLWINM | S(src) | A(dst) | RLWI_SH(8) | RLWI_MBE(16, 23)));1484FAIL_IF(push_inst(compiler, RLWIMI | S(src) | A(dst) | RLWI_SH(24) | RLWI_MBE(24, 31)));1485}14861487if (op == SLJIT_REV_U16)1488return SLJIT_SUCCESS;1489return push_inst(compiler, EXTSH | S(dst) | A(dst));1490}14911492#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1493if (!is_32) {1494#if defined(_ARCH_PWR10) && _ARCH_PWR101495return push_inst(compiler, BRD | S(src) | A(dst));1496#else /* !POWER10 */1497FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(0) | IMM(TMP_MEM_OFFSET_HI)));1498FAIL_IF(push_inst(compiler, RLDICL | S(src) | A(TMP_REG1) | RLDI_SH(32) | RLDI_MB(32)));1499FAIL_IF(push_inst(compiler, STWBRX | S(src) | A(SLJIT_SP) | B(TMP_REG2)));1500FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(0) | IMM(TMP_MEM_OFFSET_LO)));1501FAIL_IF(push_inst(compiler, STWBRX | S(TMP_REG1) | A(SLJIT_SP) | B(TMP_REG2)));1502return push_inst(compiler, LD | D(dst) | A(SLJIT_SP) | TMP_MEM_OFFSET);1503#endif /* POWER10 */1504}1505#endif /* SLJIT_CONFIG_PPC_64 */15061507FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(0) | IMM(TMP_MEM_OFFSET)));1508FAIL_IF(push_inst(compiler, STWBRX | S(src) | A(SLJIT_SP) | B(TMP_REG2)));1509FAIL_IF(push_inst(compiler, LWZ | D(dst) | A(SLJIT_SP) | TMP_MEM_OFFSET));15101511#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1512if (op == SLJIT_REV_S32)1513return push_inst(compiler, EXTSW | S(dst) | A(dst));1514#endif /* SLJIT_CONFIG_PPC_64 */1515return SLJIT_SUCCESS;1516}15171518mem = src;1519memw = srcw;15201521if (dst & SLJIT_MEM) {1522mem = dst;1523memw = dstw;15241525if (src & SLJIT_MEM) {1526inp_flags = HALF_DATA | LOAD_DATA;15271528if (op != SLJIT_REV_U16 && op != SLJIT_REV_S16) {1529#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1530inp_flags = (is_32 ? INT_DATA : WORD_DATA) | LOAD_DATA;1531#else /* !SLJIT_CONFIG_PPC_64 */1532inp_flags = WORD_DATA | LOAD_DATA;1533#endif /* SLJIT_CONFIG_PPC_64 */1534}15351536FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG1, src, srcw, TMP_REG2));1537src = TMP_REG1;1538}1539}15401541if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {1542offs_reg = OFFS_REG(mem);1543mem &= REG_MASK;1544memw &= 0x3;15451546if (memw != 0) {1547FAIL_IF(push_inst(compiler, SLWI_W(memw) | S(offs_reg) | A(TMP_REG2)));1548offs_reg = TMP_REG2;1549}1550#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1551} else if (memw > 0x7fff7fffl || memw < -0x80000000l) {1552FAIL_IF(load_immediate(compiler, TMP_REG2, memw));1553offs_reg = TMP_REG2;1554mem &= REG_MASK;1555#endif /* SLJIT_CONFIG_PPC_64 */1556} else {1557FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(mem & REG_MASK) | IMM(memw)));1558if (memw > SIMM_MAX || memw < SIMM_MIN)1559FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(TMP_REG2) | IMM((memw + 0x8000) >> 16)));15601561mem = 0;1562offs_reg = TMP_REG2;1563}15641565if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) {1566if (dst & SLJIT_MEM)1567return push_inst(compiler, STHBRX | S(src) | A(mem) | B(offs_reg));15681569FAIL_IF(push_inst(compiler, LHBRX | S(dst) | A(mem) | B(offs_reg)));15701571if (op == SLJIT_REV_U16)1572return SLJIT_SUCCESS;1573return push_inst(compiler, EXTSH | S(dst) | A(dst));1574}15751576#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1577if (!is_32) {1578if (dst & SLJIT_MEM) {1579#if defined(_ARCH_PWR7) && _ARCH_PWR71580return push_inst(compiler, STDBRX | S(src) | A(mem) | B(offs_reg));1581#else /* !POWER7 */1582#if defined(SLJIT_LITTLE_ENDIAN) && SLJIT_LITTLE_ENDIAN1583FAIL_IF(push_inst(compiler, RLDICL | S(src) | A(TMP_REG1) | RLDI_SH(32) | RLDI_MB(32)));1584FAIL_IF(push_inst(compiler, STWBRX | S(TMP_REG1) | A(mem) | B(offs_reg)));1585FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(offs_reg) | IMM(SSIZE_OF(s32))));1586return push_inst(compiler, STWBRX | S(src) | A(mem) | B(TMP_REG2));1587#else /* !SLJIT_LITTLE_ENDIAN */1588FAIL_IF(push_inst(compiler, STWBRX | S(src) | A(mem) | B(offs_reg)));1589FAIL_IF(push_inst(compiler, RLDICL | S(src) | A(TMP_REG1) | RLDI_SH(32) | RLDI_MB(32)));1590FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(offs_reg) | IMM(SSIZE_OF(s32))));1591return push_inst(compiler, STWBRX | S(TMP_REG1) | A(mem) | B(TMP_REG2));1592#endif /* SLJIT_LITTLE_ENDIAN */1593#endif /* POWER7 */1594}1595#if defined(_ARCH_PWR7) && _ARCH_PWR71596return push_inst(compiler, LDBRX | S(dst) | A(mem) | B(offs_reg));1597#else /* !POWER7 */1598FAIL_IF(push_inst(compiler, LWBRX | LWBRX_FIRST_REG | A(mem) | B(offs_reg)));1599FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(offs_reg) | IMM(SSIZE_OF(s32))));1600FAIL_IF(push_inst(compiler, LWBRX | LWBRX_SECOND_REG | A(mem) | B(TMP_REG2)));1601return push_inst(compiler, RLDIMI | S(TMP_REG1) | A(dst) | RLDI_SH(32) | RLDI_MB(0));1602#endif /* POWER7 */1603}1604#endif /* SLJIT_CONFIG_PPC_64 */16051606if (dst & SLJIT_MEM)1607return push_inst(compiler, STWBRX | S(src) | A(mem) | B(offs_reg));16081609FAIL_IF(push_inst(compiler, LWBRX | S(dst) | A(mem) | B(offs_reg)));1610#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1611if (op == SLJIT_REV_S32)1612return push_inst(compiler, EXTSW | S(dst) | A(dst));1613#endif /* SLJIT_CONFIG_PPC_64 */1614return SLJIT_SUCCESS;1615}16161617#define EMIT_MOV(type, type_flags, type_cast) \1618emit_op(compiler, (src == SLJIT_IMM) ? SLJIT_MOV : type, flags | (type_flags), dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? type_cast srcw : srcw)16191620SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,1621sljit_s32 dst, sljit_sw dstw,1622sljit_s32 src, sljit_sw srcw)1623{1624sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;1625sljit_s32 op_flags = GET_ALL_FLAGS(op);16261627CHECK_ERROR();1628CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));1629ADJUST_LOCAL_OFFSET(dst, dstw);1630ADJUST_LOCAL_OFFSET(src, srcw);16311632op = GET_OPCODE(op);16331634if (GET_FLAG_TYPE(op_flags) == SLJIT_OVERFLOW)1635FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));16361637if (op <= SLJIT_MOV_P && FAST_IS_REG(src) && src == dst) {1638if (!TYPE_CAST_NEEDED(op))1639return SLJIT_SUCCESS;1640}16411642#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1643if (op_flags & SLJIT_32) {1644if (op <= SLJIT_MOV_P) {1645if (src & SLJIT_MEM) {1646if (op == SLJIT_MOV_S32)1647op = SLJIT_MOV_U32;1648}1649else if (src == SLJIT_IMM) {1650if (op == SLJIT_MOV_U32)1651op = SLJIT_MOV_S32;1652}1653}1654else {1655/* Most operations expect sign extended arguments. */1656flags |= INT_DATA | SIGNED_DATA;1657if (HAS_FLAGS(op_flags))1658flags |= ALT_SIGN_EXT;1659}1660}1661#endif16621663switch (op) {1664case SLJIT_MOV:1665#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)1666case SLJIT_MOV_U32:1667case SLJIT_MOV_S32:1668case SLJIT_MOV32:1669#endif1670case SLJIT_MOV_P:1671return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);16721673#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1674case SLJIT_MOV_U32:1675return EMIT_MOV(SLJIT_MOV_U32, INT_DATA, (sljit_u32));16761677case SLJIT_MOV_S32:1678case SLJIT_MOV32:1679return EMIT_MOV(SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, (sljit_s32));1680#endif16811682case SLJIT_MOV_U8:1683return EMIT_MOV(SLJIT_MOV_U8, BYTE_DATA, (sljit_u8));16841685case SLJIT_MOV_S8:1686return EMIT_MOV(SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA, (sljit_s8));16871688case SLJIT_MOV_U16:1689return EMIT_MOV(SLJIT_MOV_U16, HALF_DATA, (sljit_u16));16901691case SLJIT_MOV_S16:1692return EMIT_MOV(SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, (sljit_s16));16931694case SLJIT_CLZ:1695case SLJIT_CTZ:1696#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1697if (op_flags & SLJIT_32)1698flags |= ALT_FORM1;1699#endif /* SLJIT_CONFIG_PPC_64 */1700return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);1701case SLJIT_REV_U32:1702case SLJIT_REV_S32:1703#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1704op |= SLJIT_32;1705#endif /* SLJIT_CONFIG_PPC_64 */1706SLJIT_FALLTHROUGH1707case SLJIT_REV:1708case SLJIT_REV_U16:1709case SLJIT_REV_S16:1710#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1711op |= (op_flags & SLJIT_32);1712#endif /* SLJIT_CONFIG_PPC_64 */1713return emit_rev(compiler, op, dst, dstw, src, srcw);1714}17151716return SLJIT_SUCCESS;1717}17181719#undef EMIT_MOV17201721/* Macros for checking different operand types / values. */1722#define TEST_SL_IMM(src, srcw) \1723((src) == SLJIT_IMM && (srcw) <= SIMM_MAX && (srcw) >= SIMM_MIN)1724#define TEST_UL_IMM(src, srcw) \1725((src) == SLJIT_IMM && !((srcw) & ~0xffff))1726#define TEST_UH_IMM(src, srcw) \1727((src) == SLJIT_IMM && !((srcw) & ~(sljit_sw)0xffff0000))17281729#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1730#define TEST_SH_IMM(src, srcw) \1731((src) == SLJIT_IMM && !((srcw) & 0xffff) && (srcw) <= 0x7fffffffl && (srcw) >= -0x80000000l)1732#define TEST_ADD_IMM(src, srcw) \1733((src) == SLJIT_IMM && (srcw) <= 0x7fff7fffl && (srcw) >= -0x80000000l)1734#define TEST_UI_IMM(src, srcw) \1735((src) == SLJIT_IMM && !((srcw) & ~0xffffffff))17361737#define TEST_ADD_FORM1(op) \1738(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \1739|| (op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_32 | SLJIT_SET_Z | SLJIT_SET_CARRY))1740#define TEST_SUB_FORM2(op) \1741((GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) \1742|| (op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_32 | SLJIT_SET_Z))1743#define TEST_SUB_FORM3(op) \1744(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \1745|| (op & (SLJIT_32 | SLJIT_SET_Z)) == (SLJIT_32 | SLJIT_SET_Z))17461747#else /* !SLJIT_CONFIG_PPC_64 */1748#define TEST_SH_IMM(src, srcw) \1749((src) == SLJIT_IMM && !((srcw) & 0xffff))1750#define TEST_ADD_IMM(src, srcw) \1751((src) == SLJIT_IMM)1752#define TEST_UI_IMM(src, srcw) \1753((src) == SLJIT_IMM)17541755#define TEST_ADD_FORM1(op) \1756(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)1757#define TEST_SUB_FORM2(op) \1758(GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL)1759#define TEST_SUB_FORM3(op) \1760(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)1761#endif /* SLJIT_CONFIG_PPC_64 */17621763SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,1764sljit_s32 dst, sljit_sw dstw,1765sljit_s32 src1, sljit_sw src1w,1766sljit_s32 src2, sljit_sw src2w)1767{1768sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;17691770CHECK_ERROR();1771CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w));1772ADJUST_LOCAL_OFFSET(dst, dstw);1773ADJUST_LOCAL_OFFSET(src1, src1w);1774ADJUST_LOCAL_OFFSET(src2, src2w);17751776#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1777if (op & SLJIT_32) {1778/* Most operations expect sign extended arguments. */1779flags |= INT_DATA | SIGNED_DATA;1780if (src1 == SLJIT_IMM)1781src1w = (sljit_s32)(src1w);1782if (src2 == SLJIT_IMM)1783src2w = (sljit_s32)(src2w);1784if (HAS_FLAGS(op))1785flags |= ALT_SIGN_EXT;1786}1787#endif1788if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)1789FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));17901791switch (GET_OPCODE(op)) {1792case SLJIT_ADD:1793compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;17941795if (TEST_ADD_FORM1(op))1796return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);17971798if (!HAS_FLAGS(op) && (src1 == SLJIT_IMM || src2 == SLJIT_IMM)) {1799if (TEST_SL_IMM(src2, src2w)) {1800compiler->imm = (sljit_ins)src2w & 0xffff;1801return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);1802}1803if (TEST_SL_IMM(src1, src1w)) {1804compiler->imm = (sljit_ins)src1w & 0xffff;1805return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);1806}1807if (TEST_SH_IMM(src2, src2w)) {1808compiler->imm = (sljit_ins)(src2w >> 16) & 0xffff;1809return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);1810}1811if (TEST_SH_IMM(src1, src1w)) {1812compiler->imm = (sljit_ins)(src1w >> 16) & 0xffff;1813return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);1814}1815/* Range between -1 and -32768 is covered above. */1816if (TEST_ADD_IMM(src2, src2w)) {1817compiler->imm = (sljit_ins)src2w & 0xffffffff;1818return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);1819}1820if (TEST_ADD_IMM(src1, src1w)) {1821compiler->imm = (sljit_ins)src1w & 0xffffffff;1822return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);1823}1824}18251826#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1827if ((op & (SLJIT_32 | SLJIT_SET_Z)) == (SLJIT_32 | SLJIT_SET_Z)) {1828if (TEST_SL_IMM(src2, src2w)) {1829compiler->imm = (sljit_ins)src2w & 0xffff;1830return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src1, src1w, TMP_REG2, 0);1831}1832if (TEST_SL_IMM(src1, src1w)) {1833compiler->imm = (sljit_ins)src1w & 0xffff;1834return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src2, src2w, TMP_REG2, 0);1835}1836return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);1837}1838#endif1839if (HAS_FLAGS(op)) {1840if (TEST_SL_IMM(src2, src2w)) {1841compiler->imm = (sljit_ins)src2w & 0xffff;1842return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);1843}1844if (TEST_SL_IMM(src1, src1w)) {1845compiler->imm = (sljit_ins)src1w & 0xffff;1846return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);1847}1848}1849return emit_op(compiler, SLJIT_ADD, flags | ((GET_FLAG_TYPE(op) == SLJIT_CARRY) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);18501851case SLJIT_ADDC:1852compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;1853return emit_op(compiler, SLJIT_ADDC, flags, dst, dstw, src1, src1w, src2, src2w);18541855case SLJIT_SUB:1856compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;18571858if (GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_LESS_EQUAL) {1859if (dst == TMP_REG1) {1860if (TEST_UL_IMM(src2, src2w)) {1861compiler->imm = (sljit_ins)src2w & 0xffff;1862return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);1863}1864return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);1865}18661867if (src2 == SLJIT_IMM && src2w >= 0 && src2w <= (SIMM_MAX + 1)) {1868compiler->imm = (sljit_ins)src2w;1869return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);1870}1871return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);1872}18731874if (dst == TMP_REG1 && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {1875if (TEST_SL_IMM(src2, src2w)) {1876compiler->imm = (sljit_ins)src2w & 0xffff;1877return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);1878}1879return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, src2, src2w);1880}18811882if (TEST_SUB_FORM2(op)) {1883if (src2 == SLJIT_IMM && src2w >= -SIMM_MAX && src2w <= SIMM_MAX) {1884compiler->imm = (sljit_ins)src2w & 0xffff;1885return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);1886}1887return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);1888}18891890if (TEST_SUB_FORM3(op))1891return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);18921893if (TEST_SL_IMM(src2, -src2w)) {1894compiler->imm = (sljit_ins)(-src2w) & 0xffff;1895return emit_op(compiler, SLJIT_ADD, flags | (!HAS_FLAGS(op) ? ALT_FORM2 : ALT_FORM3), dst, dstw, src1, src1w, TMP_REG2, 0);1896}18971898if (TEST_SL_IMM(src1, src1w) && !(op & SLJIT_SET_Z)) {1899compiler->imm = (sljit_ins)src1w & 0xffff;1900return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);1901}19021903if (!HAS_FLAGS(op)) {1904if (TEST_SH_IMM(src2, -src2w)) {1905compiler->imm = (sljit_ins)((-src2w) >> 16) & 0xffff;1906return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);1907}1908/* Range between -1 and -32768 is covered above. */1909if (TEST_ADD_IMM(src2, -src2w)) {1910compiler->imm = (sljit_ins)-src2w;1911return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);1912}1913}19141915/* We know ALT_SIGN_EXT is set if it is an SLJIT_32 on 64 bit systems. */1916return emit_op(compiler, SLJIT_SUB, flags | ((GET_FLAG_TYPE(op) == SLJIT_CARRY) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);19171918case SLJIT_SUBC:1919compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;1920return emit_op(compiler, SLJIT_SUBC, flags, dst, dstw, src1, src1w, src2, src2w);19211922case SLJIT_MUL:1923#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1924if (op & SLJIT_32)1925flags |= ALT_FORM2;1926#endif1927if (!HAS_FLAGS(op)) {1928if (TEST_SL_IMM(src2, src2w)) {1929compiler->imm = (sljit_ins)src2w & 0xffff;1930return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);1931}1932if (TEST_SL_IMM(src1, src1w)) {1933compiler->imm = (sljit_ins)src1w & 0xffff;1934return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);1935}1936}1937else1938FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));1939return emit_op(compiler, SLJIT_MUL, flags, dst, dstw, src1, src1w, src2, src2w);19401941case SLJIT_XOR:1942if (src2 == SLJIT_IMM && src2w == -1) {1943return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM4, dst, dstw, TMP_REG1, 0, src1, src1w);1944}1945if (src1 == SLJIT_IMM && src1w == -1) {1946return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM4, dst, dstw, TMP_REG1, 0, src2, src2w);1947}1948SLJIT_FALLTHROUGH1949case SLJIT_AND:1950case SLJIT_OR:1951/* Commutative unsigned operations. */1952if (!HAS_FLAGS(op) || GET_OPCODE(op) == SLJIT_AND) {1953if (TEST_UL_IMM(src2, src2w)) {1954compiler->imm = (sljit_ins)src2w;1955return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);1956}1957if (TEST_UL_IMM(src1, src1w)) {1958compiler->imm = (sljit_ins)src1w;1959return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);1960}1961if (TEST_UH_IMM(src2, src2w)) {1962compiler->imm = (sljit_ins)(src2w >> 16) & 0xffff;1963return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);1964}1965if (TEST_UH_IMM(src1, src1w)) {1966compiler->imm = (sljit_ins)(src1w >> 16) & 0xffff;1967return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);1968}1969}1970if (!HAS_FLAGS(op) && GET_OPCODE(op) != SLJIT_AND) {1971/* Unlike or and xor, the and resets unwanted bits as well. */1972if (TEST_UI_IMM(src2, src2w)) {1973compiler->imm = (sljit_ins)src2w;1974return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);1975}1976if (TEST_UI_IMM(src1, src1w)) {1977compiler->imm = (sljit_ins)src1w;1978return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);1979}1980}1981return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w);19821983case SLJIT_SHL:1984case SLJIT_MSHL:1985case SLJIT_LSHR:1986case SLJIT_MLSHR:1987case SLJIT_ASHR:1988case SLJIT_MASHR:1989case SLJIT_ROTL:1990case SLJIT_ROTR:1991#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)1992if (op & SLJIT_32)1993flags |= ALT_FORM2;1994#endif1995if (src2 == SLJIT_IMM) {1996compiler->imm = (sljit_ins)src2w;1997return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);1998}1999return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w);2000}20012002return SLJIT_SUCCESS;2003}20042005SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op,2006sljit_s32 src1, sljit_sw src1w,2007sljit_s32 src2, sljit_sw src2w)2008{2009CHECK_ERROR();2010CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));20112012SLJIT_SKIP_CHECKS(compiler);2013return sljit_emit_op2(compiler, op, TMP_REG1, 0, src1, src1w, src2, src2w);2014}20152016#undef TEST_ADD_FORM12017#undef TEST_SUB_FORM22018#undef TEST_SUB_FORM320192020SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2r(struct sljit_compiler *compiler, sljit_s32 op,2021sljit_s32 dst_reg,2022sljit_s32 src1, sljit_sw src1w,2023sljit_s32 src2, sljit_sw src2w)2024{2025CHECK_ERROR();2026CHECK(check_sljit_emit_op2r(compiler, op, dst_reg, src1, src1w, src2, src2w));20272028switch (GET_OPCODE(op)) {2029case SLJIT_MULADD:2030SLJIT_SKIP_CHECKS(compiler);2031FAIL_IF(sljit_emit_op2(compiler, SLJIT_MUL | (op & SLJIT_32), TMP_REG2, 0, src1, src1w, src2, src2w));2032return push_inst(compiler, ADD | D(dst_reg) | A(dst_reg) | B(TMP_REG2));2033}20342035return SLJIT_SUCCESS;2036}20372038SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,2039sljit_s32 dst_reg,2040sljit_s32 src1_reg,2041sljit_s32 src2_reg,2042sljit_s32 src3, sljit_sw src3w)2043{2044sljit_s32 is_right;2045#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)2046sljit_s32 inp_flags = ((op & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;2047sljit_sw bit_length = (op & SLJIT_32) ? 32 : 64;2048#else /* !SLJIT_CONFIG_PPC_64 */2049sljit_s32 inp_flags = WORD_DATA | LOAD_DATA;2050sljit_sw bit_length = 32;2051#endif /* SLJIT_CONFIG_PPC_64 */20522053CHECK_ERROR();2054CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));20552056is_right = (GET_OPCODE(op) == SLJIT_LSHR || GET_OPCODE(op) == SLJIT_MLSHR);20572058if (src1_reg == src2_reg) {2059SLJIT_SKIP_CHECKS(compiler);2060return sljit_emit_op2(compiler, (is_right ? SLJIT_ROTR : SLJIT_ROTL) | (op & SLJIT_32), dst_reg, 0, src1_reg, 0, src3, src3w);2061}20622063ADJUST_LOCAL_OFFSET(src3, src3w);20642065if (src3 == SLJIT_IMM) {2066src3w &= bit_length - 1;20672068if (src3w == 0)2069return SLJIT_SUCCESS;20702071#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)2072if (!(op & SLJIT_32)) {2073if (is_right) {2074FAIL_IF(push_inst(compiler, SRDI(src3w) | S(src1_reg) | A(dst_reg)));2075return push_inst(compiler, RLDIMI | S(src2_reg) | A(dst_reg) | RLDI_SH(64 - src3w) | RLDI_MB(0));2076}20772078FAIL_IF(push_inst(compiler, SLDI(src3w) | S(src1_reg) | A(dst_reg)));2079/* Computes SRDI(64 - src2w). */2080FAIL_IF(push_inst(compiler, RLDICL | S(src2_reg) | A(TMP_REG1) | RLDI_SH(src3w) | RLDI_MB(64 - src3w)));2081return push_inst(compiler, OR | S(dst_reg) | A(dst_reg) | B(TMP_REG1));2082}2083#endif /* SLJIT_CONFIG_PPC_64 */20842085if (is_right) {2086FAIL_IF(push_inst(compiler, SRWI(src3w) | S(src1_reg) | A(dst_reg)));2087return push_inst(compiler, RLWIMI | S(src2_reg) | A(dst_reg) | RLWI_SH(32 - src3w) | RLWI_MBE(0, src3w - 1));2088}20892090FAIL_IF(push_inst(compiler, SLWI(src3w) | S(src1_reg) | A(dst_reg)));2091return push_inst(compiler, RLWIMI | S(src2_reg) | A(dst_reg) | RLWI_SH(src3w) | RLWI_MBE(32 - src3w, 31));2092}20932094if (src3 & SLJIT_MEM) {2095FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src3, src3w, TMP_REG2));2096src3 = TMP_REG2;2097}20982099#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)2100if (!(op & SLJIT_32)) {2101if (GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR || dst_reg == src3) {2102FAIL_IF(push_inst(compiler, ANDI | S(src3) | A(TMP_REG2) | 0x3f));2103src3 = TMP_REG2;2104}21052106FAIL_IF(push_inst(compiler, (is_right ? SRD : SLD) | S(src1_reg) | A(dst_reg) | B(src3)));2107FAIL_IF(push_inst(compiler, (is_right ? SLDI(1) : SRDI(1)) | S(src2_reg) | A(TMP_REG1)));2108FAIL_IF(push_inst(compiler, XORI | S(src3) | A(TMP_REG2) | 0x3f));2109FAIL_IF(push_inst(compiler, (is_right ? SLD : SRD) | S(TMP_REG1) | A(TMP_REG1) | B(TMP_REG2)));2110return push_inst(compiler, OR | S(dst_reg) | A(dst_reg) | B(TMP_REG1));2111}2112#endif /* SLJIT_CONFIG_PPC_64 */21132114if (GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR || dst_reg == src3) {2115FAIL_IF(push_inst(compiler, ANDI | S(src3) | A(TMP_REG2) | 0x1f));2116src3 = TMP_REG2;2117}21182119FAIL_IF(push_inst(compiler, (is_right ? SRW : SLW) | S(src1_reg) | A(dst_reg) | B(src3)));2120FAIL_IF(push_inst(compiler, (is_right ? SLWI(1) : SRWI(1)) | S(src2_reg) | A(TMP_REG1)));2121FAIL_IF(push_inst(compiler, XORI | S(src3) | A(TMP_REG2) | 0x1f));2122FAIL_IF(push_inst(compiler, (is_right ? SLW : SRW) | S(TMP_REG1) | A(TMP_REG1) | B(TMP_REG2)));2123return push_inst(compiler, OR | S(dst_reg) | A(dst_reg) | B(TMP_REG1));2124}21252126SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2_shift(struct sljit_compiler *compiler, sljit_s32 op,2127sljit_s32 dst, sljit_sw dstw,2128sljit_s32 src1, sljit_sw src1w,2129sljit_s32 src2, sljit_sw src2w,2130sljit_sw shift_arg)2131{2132sljit_s32 dst_r, tmp_r;21332134CHECK_ERROR();2135CHECK(check_sljit_emit_op2_shift(compiler, op, dst, dstw, src1, src1w, src2, src2w, shift_arg));2136ADJUST_LOCAL_OFFSET(dst, dstw);2137ADJUST_LOCAL_OFFSET(src1, src1w);2138ADJUST_LOCAL_OFFSET(src2, src2w);21392140shift_arg &= (sljit_sw)((sizeof(sljit_sw) * 8) - 1);21412142if (src2 == SLJIT_IMM) {2143src2w = src2w << shift_arg;2144shift_arg = 0;2145}21462147if (shift_arg == 0) {2148SLJIT_SKIP_CHECKS(compiler);2149return sljit_emit_op2(compiler, GET_OPCODE(op), dst, dstw, src1, src1w, src2, src2w);2150}21512152if (src1 == SLJIT_IMM) {2153FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));2154src1 = TMP_REG1;2155} else if (src1 & SLJIT_MEM) {2156FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));2157src1 = TMP_REG1;2158}21592160tmp_r = (src1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;21612162if (src2 & SLJIT_MEM) {2163FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, tmp_r, src2, src2w, tmp_r));2164src2 = tmp_r;2165}21662167dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;2168FAIL_IF(push_inst(compiler, SLWI_W(shift_arg) | S(src2) | A(tmp_r)));2169FAIL_IF(push_inst(compiler, ADD | D(dst_r) | A(src1) | B(tmp_r)));21702171if (dst & SLJIT_MEM)2172return emit_op_mem(compiler, WORD_DATA, dst_r, dst, dstw, TMP_REG1);2173return SLJIT_SUCCESS;2174}21752176static sljit_s32 emit_prefetch(struct sljit_compiler *compiler,2177sljit_s32 src, sljit_sw srcw)2178{2179if (!(src & OFFS_REG_MASK)) {2180if (srcw == 0 && (src & REG_MASK))2181return push_inst(compiler, DCBT | A(0) | B(src & REG_MASK));21822183FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));2184/* Works with SLJIT_MEM0() case as well. */2185return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));2186}21872188srcw &= 0x3;21892190if (srcw == 0)2191return push_inst(compiler, DCBT | A(src & REG_MASK) | B(OFFS_REG(src)));21922193FAIL_IF(push_inst(compiler, SLWI_W(srcw) | S(OFFS_REG(src)) | A(TMP_REG1)));2194return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));2195}21962197SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,2198sljit_s32 src, sljit_sw srcw)2199{2200CHECK_ERROR();2201CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));2202ADJUST_LOCAL_OFFSET(src, srcw);22032204switch (op) {2205case SLJIT_FAST_RETURN:2206if (FAST_IS_REG(src))2207FAIL_IF(push_inst(compiler, MTLR | S(src)));2208else {2209FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG2, src, srcw, TMP_REG2));2210FAIL_IF(push_inst(compiler, MTLR | S(TMP_REG2)));2211}22122213return push_inst(compiler, BLR);2214case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:2215return SLJIT_SUCCESS;2216case SLJIT_PREFETCH_L1:2217case SLJIT_PREFETCH_L2:2218case SLJIT_PREFETCH_L3:2219case SLJIT_PREFETCH_ONCE:2220return emit_prefetch(compiler, src, srcw);2221}22222223return SLJIT_SUCCESS;2224}22252226SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,2227sljit_s32 dst, sljit_sw dstw)2228{2229sljit_s32 dst_r;22302231CHECK_ERROR();2232CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));2233ADJUST_LOCAL_OFFSET(dst, dstw);22342235switch (op) {2236case SLJIT_FAST_ENTER:2237if (FAST_IS_REG(dst))2238return push_inst(compiler, MFLR | D(dst));22392240FAIL_IF(push_inst(compiler, MFLR | D(TMP_REG1)));2241break;2242case SLJIT_GET_RETURN_ADDRESS:2243dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;2244FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst_r, SLJIT_MEM1(SLJIT_SP), compiler->local_size + LR_SAVE_OFFSET, TMP_REG2));2245break;2246}22472248if (dst & SLJIT_MEM)2249return emit_op_mem(compiler, WORD_DATA, TMP_REG1, dst, dstw, TMP_REG2);22502251return SLJIT_SUCCESS;2252}22532254SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)2255{2256CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));22572258if (type == SLJIT_GP_REGISTER)2259return reg_map[reg];22602261if (type != SLJIT_FLOAT_REGISTER)2262return -1;22632264return freg_map[reg];2265}22662267SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,2268void *instruction, sljit_u32 size)2269{2270SLJIT_UNUSED_ARG(size);22712272CHECK_ERROR();2273CHECK(check_sljit_emit_op_custom(compiler, instruction, size));22742275return push_inst(compiler, *(sljit_ins*)instruction);2276}22772278/* --------------------------------------------------------------------- */2279/* Floating point operators */2280/* --------------------------------------------------------------------- */22812282#define SELECT_FOP(op, single, double) ((sljit_ins)((op & SLJIT_32) ? single : double))22832284static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,2285sljit_s32 dst, sljit_sw dstw,2286sljit_s32 src, sljit_sw srcw)2287{2288if (src & SLJIT_MEM) {2289/* We can ignore the temporary data store on the stack from caching point of view. */2290FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, TMP_REG1));2291src = TMP_FREG1;2292}22932294#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)2295op = GET_OPCODE(op);2296FAIL_IF(push_inst(compiler, (op == SLJIT_CONV_S32_FROM_F64 ? FCTIWZ : FCTIDZ) | FD(TMP_FREG1) | FB(src)));22972298if (op == SLJIT_CONV_SW_FROM_F64) {2299if (FAST_IS_REG(dst)) {2300FAIL_IF(push_inst(compiler, STFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));2301return push_inst(compiler, LD | S(dst) | A(SLJIT_SP) | TMP_MEM_OFFSET);2302}2303return emit_op_mem(compiler, DOUBLE_DATA, TMP_FREG1, dst, dstw, TMP_REG1);2304}2305#else /* !SLJIT_CONFIG_PPC_64 */2306FAIL_IF(push_inst(compiler, FCTIWZ | FD(TMP_FREG1) | FB(src)));2307#endif /* SLJIT_CONFIG_PPC_64 */23082309if (FAST_IS_REG(dst)) {2310FAIL_IF(load_immediate(compiler, TMP_REG1, TMP_MEM_OFFSET));2311FAIL_IF(push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(SLJIT_SP) | B(TMP_REG1)));2312return push_inst(compiler, LWZ | S(dst) | A(SLJIT_SP) | TMP_MEM_OFFSET);2313}23142315SLJIT_ASSERT(dst & SLJIT_MEM);23162317if (dst & OFFS_REG_MASK) {2318dstw &= 0x3;2319if (dstw) {2320FAIL_IF(push_inst(compiler, SLWI_W(dstw) | S(OFFS_REG(dst)) | A(TMP_REG1)));2321dstw = TMP_REG1;2322} else2323dstw = OFFS_REG(dst);2324}2325else {2326if ((dst & REG_MASK) && !dstw) {2327dstw = dst & REG_MASK;2328dst = 0;2329} else {2330/* This works regardless we have SLJIT_MEM1 or SLJIT_MEM0. */2331FAIL_IF(load_immediate(compiler, TMP_REG1, dstw));2332dstw = TMP_REG1;2333}2334}23352336return push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(dst & REG_MASK) | B(dstw));2337}23382339static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,2340sljit_s32 src1, sljit_sw src1w,2341sljit_s32 src2, sljit_sw src2w)2342{2343if (src1 & SLJIT_MEM) {2344FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, TMP_REG1));2345src1 = TMP_FREG1;2346}23472348if (src2 & SLJIT_MEM) {2349FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG2));2350src2 = TMP_FREG2;2351}23522353FAIL_IF(push_inst(compiler, FCMPU | CRD(4) | FA(src1) | FB(src2)));23542355switch (GET_FLAG_TYPE(op)) {2356case SLJIT_UNORDERED_OR_EQUAL:2357return push_inst(compiler, CROR | ((4 + 2) << 21) | ((4 + 2) << 16) | ((4 + 3) << 11));2358case SLJIT_UNORDERED_OR_LESS:2359return push_inst(compiler, CROR | ((4 + 0) << 21) | ((4 + 0) << 16) | ((4 + 3) << 11));2360case SLJIT_UNORDERED_OR_GREATER:2361return push_inst(compiler, CROR | ((4 + 1) << 21) | ((4 + 1) << 16) | ((4 + 3) << 11));2362}23632364return SLJIT_SUCCESS;2365}23662367SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,2368sljit_s32 dst, sljit_sw dstw,2369sljit_s32 src, sljit_sw srcw)2370{2371sljit_s32 dst_r;23722373CHECK_ERROR();23742375SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100) && !(DOUBLE_DATA & 0x4), float_transfer_bit_error);2376SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);23772378if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)2379op ^= SLJIT_32;23802381dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;23822383if (src & SLJIT_MEM) {2384FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_r, src, srcw, TMP_REG1));2385src = dst_r;2386}23872388switch (GET_OPCODE(op)) {2389case SLJIT_CONV_F64_FROM_F32:2390op ^= SLJIT_32;2391if (op & SLJIT_32) {2392FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(src)));2393break;2394}2395SLJIT_FALLTHROUGH2396case SLJIT_MOV_F64:2397if (src != dst_r) {2398if (!(dst & SLJIT_MEM))2399FAIL_IF(push_inst(compiler, FMR | FD(dst_r) | FB(src)));2400else2401dst_r = src;2402}2403break;2404case SLJIT_NEG_F64:2405FAIL_IF(push_inst(compiler, FNEG | FD(dst_r) | FB(src)));2406break;2407case SLJIT_ABS_F64:2408FAIL_IF(push_inst(compiler, FABS | FD(dst_r) | FB(src)));2409break;2410}24112412if (dst & SLJIT_MEM)2413FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op), dst_r, dst, dstw, TMP_REG1));2414return SLJIT_SUCCESS;2415}24162417SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,2418sljit_s32 dst, sljit_sw dstw,2419sljit_s32 src1, sljit_sw src1w,2420sljit_s32 src2, sljit_sw src2w)2421{2422sljit_s32 dst_r;24232424CHECK_ERROR();2425CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));2426ADJUST_LOCAL_OFFSET(dst, dstw);2427ADJUST_LOCAL_OFFSET(src1, src1w);2428ADJUST_LOCAL_OFFSET(src2, src2w);24292430dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2;24312432if (src1 & SLJIT_MEM) {2433FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, TMP_REG1));2434src1 = TMP_FREG1;2435}24362437if (src2 & SLJIT_MEM) {2438FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG1));2439src2 = TMP_FREG2;2440}24412442switch (GET_OPCODE(op)) {2443case SLJIT_ADD_F64:2444FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADD) | FD(dst_r) | FA(src1) | FB(src2)));2445break;2446case SLJIT_SUB_F64:2447FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUB) | FD(dst_r) | FA(src1) | FB(src2)));2448break;2449case SLJIT_MUL_F64:2450FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMUL) | FD(dst_r) | FA(src1) | FC(src2) /* FMUL use FC as src2 */));2451break;2452case SLJIT_DIV_F64:2453FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIV) | FD(dst_r) | FA(src1) | FB(src2)));2454break;2455case SLJIT_COPYSIGN_F64:2456FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? STFS : STFD) | FS(src2) | A(SLJIT_SP) | TMP_MEM_OFFSET));2457#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)2458FAIL_IF(push_inst(compiler, LWZ | S(TMP_REG1) | A(SLJIT_SP) | ((op & SLJIT_32) ? TMP_MEM_OFFSET : TMP_MEM_OFFSET_HI)));2459#else /* !SLJIT_CONFIG_PPC_32 */2460FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? LWZ : LD) | S(TMP_REG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));2461#endif /* SLJIT_CONFIG_PPC_32 */2462FAIL_IF(push_inst(compiler, FABS | FD(dst_r) | FB(src1)));2463#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)2464FAIL_IF(push_inst(compiler, CMPI | CRD(0) | A(TMP_REG1) | 0));2465#else /* !SLJIT_CONFIG_PPC_32 */2466FAIL_IF(push_inst(compiler, CMPI | CRD(0 | ((op & SLJIT_32) ? 0 : 1)) | A(TMP_REG1) | 0));2467#endif /* SLJIT_CONFIG_PPC_32 */2468FAIL_IF(push_inst(compiler, BCx | (4 << 21) | (0 << 16) | 8));2469return push_inst(compiler, FNEG | FD(dst_r) | FB(dst_r));2470}24712472if (dst & SLJIT_MEM)2473FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, TMP_REG1));24742475return SLJIT_SUCCESS;2476}24772478#undef SELECT_FOP24792480SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,2481sljit_s32 freg, sljit_f32 value)2482{2483union {2484sljit_s32 imm;2485sljit_f32 value;2486} u;24872488CHECK_ERROR();2489CHECK(check_sljit_emit_fset32(compiler, freg, value));24902491u.value = value;24922493if (u.imm != 0)2494FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));24952496FAIL_IF(push_inst(compiler, STW | S(u.imm != 0 ? TMP_REG1 : TMP_ZERO) | A(SLJIT_SP) | TMP_MEM_OFFSET));2497return push_inst(compiler, LFS | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);2498}24992500/* --------------------------------------------------------------------- */2501/* Conditional instructions */2502/* --------------------------------------------------------------------- */25032504SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)2505{2506struct sljit_label *label;25072508CHECK_ERROR_PTR();2509CHECK_PTR(check_sljit_emit_label(compiler));25102511if (compiler->last_label && compiler->last_label->size == compiler->size)2512return compiler->last_label;25132514label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));2515PTR_FAIL_IF(!label);2516set_label(label, compiler);2517return label;2518}25192520SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_aligned_label(struct sljit_compiler *compiler,2521sljit_s32 alignment, struct sljit_read_only_buffer *buffers)2522{2523sljit_uw mask, i;2524struct sljit_label *label;2525struct sljit_label *next_label;2526struct sljit_extended_label *ext_label;25272528CHECK_ERROR_PTR();2529CHECK_PTR(check_sljit_emit_aligned_label(compiler, alignment, buffers));25302531sljit_reset_read_only_buffers(buffers);25322533if (alignment <= SLJIT_LABEL_ALIGN_4) {2534SLJIT_SKIP_CHECKS(compiler);2535label = sljit_emit_label(compiler);2536PTR_FAIL_IF(!label);2537} else {2538/* The used space is filled with NOPs. */2539mask = ((sljit_uw)1 << alignment) - sizeof(sljit_ins);25402541for (i = (mask >> 2); i != 0; i--)2542PTR_FAIL_IF(push_inst(compiler, NOP));25432544ext_label = (struct sljit_extended_label*)ensure_abuf(compiler, sizeof(struct sljit_extended_label));2545PTR_FAIL_IF(!ext_label);2546set_extended_label(ext_label, compiler, SLJIT_LABEL_ALIGNED, mask);2547label = &ext_label->label;2548}25492550if (buffers == NULL)2551return label;25522553next_label = label;25542555while (1) {2556buffers->u.label = next_label;25572558for (i = (buffers->size + 3) >> 2; i > 0; i--)2559PTR_FAIL_IF(push_inst(compiler, NOP));25602561buffers = buffers->next;25622563if (buffers == NULL)2564break;25652566SLJIT_SKIP_CHECKS(compiler);2567next_label = sljit_emit_label(compiler);2568PTR_FAIL_IF(!next_label);2569}25702571return label;2572}25732574static sljit_ins get_bo_bi_flags(struct sljit_compiler *compiler, sljit_s32 type)2575{2576switch (type) {2577case SLJIT_NOT_CARRY:2578if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB)2579return (4 << 21) | (2 << 16);2580SLJIT_FALLTHROUGH25812582case SLJIT_EQUAL:2583case SLJIT_ATOMIC_STORED:2584return (12 << 21) | (2 << 16);25852586case SLJIT_CARRY:2587if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB)2588return (12 << 21) | (2 << 16);2589SLJIT_FALLTHROUGH25902591case SLJIT_NOT_EQUAL:2592case SLJIT_ATOMIC_NOT_STORED:2593return (4 << 21) | (2 << 16);25942595case SLJIT_LESS:2596case SLJIT_SIG_LESS:2597return (12 << 21) | (0 << 16);25982599case SLJIT_GREATER_EQUAL:2600case SLJIT_SIG_GREATER_EQUAL:2601return (4 << 21) | (0 << 16);26022603case SLJIT_GREATER:2604case SLJIT_SIG_GREATER:2605return (12 << 21) | (1 << 16);26062607case SLJIT_LESS_EQUAL:2608case SLJIT_SIG_LESS_EQUAL:2609return (4 << 21) | (1 << 16);26102611case SLJIT_OVERFLOW:2612return (12 << 21) | (3 << 16);26132614case SLJIT_NOT_OVERFLOW:2615return (4 << 21) | (3 << 16);26162617case SLJIT_F_LESS:2618case SLJIT_ORDERED_LESS:2619case SLJIT_UNORDERED_OR_LESS:2620return (12 << 21) | ((4 + 0) << 16);26212622case SLJIT_F_GREATER_EQUAL:2623case SLJIT_ORDERED_GREATER_EQUAL:2624case SLJIT_UNORDERED_OR_GREATER_EQUAL:2625return (4 << 21) | ((4 + 0) << 16);26262627case SLJIT_F_GREATER:2628case SLJIT_ORDERED_GREATER:2629case SLJIT_UNORDERED_OR_GREATER:2630return (12 << 21) | ((4 + 1) << 16);26312632case SLJIT_F_LESS_EQUAL:2633case SLJIT_ORDERED_LESS_EQUAL:2634case SLJIT_UNORDERED_OR_LESS_EQUAL:2635return (4 << 21) | ((4 + 1) << 16);26362637case SLJIT_F_EQUAL:2638case SLJIT_ORDERED_EQUAL:2639case SLJIT_UNORDERED_OR_EQUAL:2640return (12 << 21) | ((4 + 2) << 16);26412642case SLJIT_F_NOT_EQUAL:2643case SLJIT_ORDERED_NOT_EQUAL:2644case SLJIT_UNORDERED_OR_NOT_EQUAL:2645return (4 << 21) | ((4 + 2) << 16);26462647case SLJIT_UNORDERED:2648return (12 << 21) | ((4 + 3) << 16);26492650case SLJIT_ORDERED:2651return (4 << 21) | ((4 + 3) << 16);26522653default:2654SLJIT_ASSERT(type >= SLJIT_JUMP && type <= SLJIT_CALL_REG_ARG);2655return (20 << 21);2656}2657}26582659SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)2660{2661struct sljit_jump *jump;2662sljit_ins bo_bi_flags;26632664CHECK_ERROR_PTR();2665CHECK_PTR(check_sljit_emit_jump(compiler, type));26662667bo_bi_flags = get_bo_bi_flags(compiler, type & 0xff);2668if (!bo_bi_flags)2669return NULL;26702671jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));2672PTR_FAIL_IF(!jump);2673set_jump(jump, compiler, (sljit_u32)type & SLJIT_REWRITABLE_JUMP);2674type &= 0xff;26752676if ((type | 0x1) == SLJIT_NOT_CARRY)2677PTR_FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG2) | A(TMP_ZERO) | B(TMP_ZERO)));26782679/* In PPC, we don't need to touch the arguments. */2680if (type < SLJIT_JUMP)2681jump->flags |= IS_COND;2682#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)2683if (type >= SLJIT_CALL)2684jump->flags |= IS_CALL;2685#endif26862687jump->addr = compiler->size;2688PTR_FAIL_IF(push_inst(compiler, BCCTR | bo_bi_flags | (type >= SLJIT_FAST_CALL ? 1 : 0)));26892690/* Maximum number of instructions required for generating a constant. */2691compiler->size += JUMP_MAX_SIZE - 1;2692return jump;2693}26942695SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,2696sljit_s32 arg_types)2697{2698SLJIT_UNUSED_ARG(arg_types);26992700CHECK_ERROR_PTR();2701CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));27022703#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)2704if ((type & 0xff) != SLJIT_CALL_REG_ARG)2705PTR_FAIL_IF(call_with_args(compiler, arg_types, NULL));2706#endif27072708if (type & SLJIT_CALL_RETURN) {2709PTR_FAIL_IF(emit_stack_frame_release(compiler, 0));2710type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP);2711}27122713SLJIT_SKIP_CHECKS(compiler);2714return sljit_emit_jump(compiler, type);2715}27162717SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)2718{2719struct sljit_jump *jump = NULL;2720sljit_s32 src_r;27212722CHECK_ERROR();2723CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));27242725if (src == SLJIT_IMM) {2726/* These jumps are converted to jump/call instructions when possible. */2727jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));2728FAIL_IF(!jump);2729set_jump(jump, compiler, JUMP_ADDR);2730jump->u.target = (sljit_uw)srcw;27312732#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)2733if (type >= SLJIT_CALL)2734jump->flags |= IS_CALL;2735#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */27362737jump->addr = compiler->size;2738FAIL_IF(push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0)));27392740/* Maximum number of instructions required for generating a constant. */2741compiler->size += JUMP_MAX_SIZE - 1;2742return SLJIT_SUCCESS;2743}27442745if (FAST_IS_REG(src)) {2746#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)2747if (type >= SLJIT_CALL && src != TMP_CALL_REG) {2748FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src)));2749src_r = TMP_CALL_REG;2750} else2751src_r = src;2752#else /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */2753src_r = src;2754#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */2755} else {2756ADJUST_LOCAL_OFFSET(src, srcw);2757FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_CALL_REG, src, srcw, TMP_CALL_REG));2758src_r = TMP_CALL_REG;2759}27602761FAIL_IF(push_inst(compiler, MTCTR | S(src_r)));2762return push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0));2763}27642765SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,2766sljit_s32 arg_types,2767sljit_s32 src, sljit_sw srcw)2768{2769SLJIT_UNUSED_ARG(arg_types);27702771CHECK_ERROR();2772CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));27732774if (src & SLJIT_MEM) {2775ADJUST_LOCAL_OFFSET(src, srcw);2776FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_CALL_REG, src, srcw, TMP_CALL_REG));2777src = TMP_CALL_REG;2778}27792780if (type & SLJIT_CALL_RETURN) {2781if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {2782FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src)));2783src = TMP_CALL_REG;2784}27852786FAIL_IF(emit_stack_frame_release(compiler, 0));2787type = SLJIT_JUMP;2788}27892790#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)2791if ((type & 0xff) != SLJIT_CALL_REG_ARG)2792FAIL_IF(call_with_args(compiler, arg_types, &src));2793#endif27942795SLJIT_SKIP_CHECKS(compiler);2796return sljit_emit_ijump(compiler, type, src, srcw);2797}27982799SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,2800sljit_s32 dst, sljit_sw dstw,2801sljit_s32 type)2802{2803sljit_s32 reg, invert;2804sljit_u32 bit, from_xer;2805sljit_s32 saved_op = op;2806sljit_sw saved_dstw = dstw;2807#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)2808sljit_s32 input_flags = ((op & SLJIT_32) || op == SLJIT_MOV32) ? INT_DATA : WORD_DATA;2809#else2810sljit_s32 input_flags = WORD_DATA;2811#endif28122813CHECK_ERROR();2814CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));2815ADJUST_LOCAL_OFFSET(dst, dstw);28162817op = GET_OPCODE(op);2818reg = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;28192820if (op >= SLJIT_ADD && (dst & SLJIT_MEM))2821FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, dst, dstw, TMP_REG1));28222823invert = 0;2824bit = 0;2825from_xer = 0;28262827switch (type) {2828case SLJIT_LESS:2829case SLJIT_SIG_LESS:2830break;28312832case SLJIT_GREATER_EQUAL:2833case SLJIT_SIG_GREATER_EQUAL:2834invert = 1;2835break;28362837case SLJIT_GREATER:2838case SLJIT_SIG_GREATER:2839bit = 1;2840break;28412842case SLJIT_LESS_EQUAL:2843case SLJIT_SIG_LESS_EQUAL:2844bit = 1;2845invert = 1;2846break;28472848case SLJIT_EQUAL:2849case SLJIT_ATOMIC_STORED:2850bit = 2;2851break;28522853case SLJIT_NOT_EQUAL:2854case SLJIT_ATOMIC_NOT_STORED:2855bit = 2;2856invert = 1;2857break;28582859case SLJIT_OVERFLOW:2860from_xer = 1;2861bit = 1;2862break;28632864case SLJIT_NOT_OVERFLOW:2865from_xer = 1;2866bit = 1;2867invert = 1;2868break;28692870case SLJIT_CARRY:2871from_xer = 1;2872bit = 2;2873invert = (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB) != 0;2874break;28752876case SLJIT_NOT_CARRY:2877from_xer = 1;2878bit = 2;2879invert = (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD) != 0;2880break;28812882case SLJIT_F_LESS:2883case SLJIT_ORDERED_LESS:2884case SLJIT_UNORDERED_OR_LESS:2885bit = 4 + 0;2886break;28872888case SLJIT_F_GREATER_EQUAL:2889case SLJIT_ORDERED_GREATER_EQUAL:2890case SLJIT_UNORDERED_OR_GREATER_EQUAL:2891bit = 4 + 0;2892invert = 1;2893break;28942895case SLJIT_F_GREATER:2896case SLJIT_ORDERED_GREATER:2897case SLJIT_UNORDERED_OR_GREATER:2898bit = 4 + 1;2899break;29002901case SLJIT_F_LESS_EQUAL:2902case SLJIT_ORDERED_LESS_EQUAL:2903case SLJIT_UNORDERED_OR_LESS_EQUAL:2904bit = 4 + 1;2905invert = 1;2906break;29072908case SLJIT_F_EQUAL:2909case SLJIT_ORDERED_EQUAL:2910case SLJIT_UNORDERED_OR_EQUAL:2911bit = 4 + 2;2912break;29132914case SLJIT_F_NOT_EQUAL:2915case SLJIT_ORDERED_NOT_EQUAL:2916case SLJIT_UNORDERED_OR_NOT_EQUAL:2917bit = 4 + 2;2918invert = 1;2919break;29202921case SLJIT_UNORDERED:2922bit = 4 + 3;2923break;29242925case SLJIT_ORDERED:2926bit = 4 + 3;2927invert = 1;2928break;29292930default:2931SLJIT_UNREACHABLE();2932break;2933}29342935FAIL_IF(push_inst(compiler, (from_xer ? MFXER : MFCR) | D(reg)));2936/* Simplified mnemonics: extrwi. */2937FAIL_IF(push_inst(compiler, RLWINM | S(reg) | A(reg) | RLWI_SH(1 + bit) | RLWI_MBE(31, 31)));29382939if (invert)2940FAIL_IF(push_inst(compiler, XORI | S(reg) | A(reg) | 0x1));29412942if (op < SLJIT_ADD) {2943if (!(dst & SLJIT_MEM))2944return SLJIT_SUCCESS;2945return emit_op_mem(compiler, input_flags, reg, dst, dstw, TMP_REG1);2946}29472948SLJIT_SKIP_CHECKS(compiler);29492950if (dst & SLJIT_MEM)2951return sljit_emit_op2(compiler, saved_op, dst, saved_dstw, TMP_REG1, 0, TMP_REG2, 0);2952return sljit_emit_op2(compiler, saved_op, dst, 0, dst, 0, TMP_REG2, 0);2953}29542955SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,2956sljit_s32 dst_reg,2957sljit_s32 src1, sljit_sw src1w,2958sljit_s32 src2_reg)2959{2960sljit_ins *ptr;2961sljit_uw size;2962sljit_s32 is_compare = (type & SLJIT_COMPARE_SELECT);2963sljit_ins ins;2964#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)2965sljit_s32 inp_flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;2966#else /* !SLJIT_CONFIG_PPC_64 */2967sljit_s32 inp_flags = WORD_DATA | LOAD_DATA;2968#endif /* SLJIT_CONFIG_PPC_64 */29692970CHECK_ERROR();2971CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));29722973ADJUST_LOCAL_OFFSET(src1, src1w);29742975#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)2976if (src1 == SLJIT_IMM && (type & SLJIT_32))2977src1w = (sljit_s32)src1w;2978#endif /* SLJIT_CONFIG_PPC_64 */29792980type &= ~(SLJIT_32 | SLJIT_COMPARE_SELECT);29812982if (is_compare) {2983ins = 0;29842985if (src1 & SLJIT_MEM) {2986FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG1, src1, src1w, TMP_REG1));2987src1 = TMP_REG1;2988src1w = 0;2989}29902991if (src1 == SLJIT_IMM) {2992if (type >= SLJIT_LESS && type <= SLJIT_LESS_EQUAL && src1w >= 0 && src1w <= UIMM_MAX)2993ins = CMPLI | CRD(0) | IMM(src1w);2994else if (type >= SLJIT_SIG_LESS && type <= SLJIT_SIG_LESS_EQUAL && src1w >= SIMM_MIN && src1w <= SIMM_MAX)2995ins = CMPI | CRD(0) | IMM(src1w);2996else {2997FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));2998src1 = TMP_REG1;2999src1w = 0;3000}3001}30023003if (ins == 0)3004ins = ((type >= SLJIT_LESS && type <= SLJIT_LESS_EQUAL) ? CMPL : CMP) | CRD(0) | B(src1);30053006#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)3007if (inp_flags == (WORD_DATA | LOAD_DATA))3008ins |= CRD(1);3009#endif /* SLJIT_CONFIG_PPC_64 */3010FAIL_IF(push_inst(compiler, ins | A(src2_reg)));3011type ^= 0x1;3012}30133014if (dst_reg != src2_reg) {3015if (dst_reg == src1) {3016src1 = src2_reg;3017src1w = 0;3018type ^= 0x1;3019} else {3020if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {3021FAIL_IF(push_inst(compiler, OR | S(dst_reg) | A(TMP_REG1) | B(dst_reg)));30223023if ((src1 & REG_MASK) == dst_reg)3024src1 = (src1 & ~REG_MASK) | TMP_REG1;30253026if (OFFS_REG(src1) == dst_reg)3027src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG1);3028}30293030FAIL_IF(push_inst(compiler, OR | S(src2_reg) | A(dst_reg) | B(src2_reg)));3031}3032}30333034if ((type | 0x1) == SLJIT_NOT_CARRY)3035FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG1) | A(TMP_ZERO) | B(TMP_ZERO)));30363037size = compiler->size;30383039ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));3040FAIL_IF(!ptr);3041compiler->size++;30423043if (src1 & SLJIT_MEM) {3044FAIL_IF(emit_op_mem(compiler, inp_flags, dst_reg, src1, src1w, TMP_REG1));3045} else if (src1 == SLJIT_IMM) {3046FAIL_IF(load_immediate(compiler, dst_reg, src1w));3047} else3048FAIL_IF(push_inst(compiler, OR | S(src1) | A(dst_reg) | B(src1)));30493050*ptr = BCx | get_bo_bi_flags(compiler, type ^ 0x1) | (sljit_ins)((compiler->size - size) << 2);3051return SLJIT_SUCCESS;3052}30533054SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,3055sljit_s32 dst_freg,3056sljit_s32 src1, sljit_sw src1w,3057sljit_s32 src2_freg)3058{3059sljit_ins *ptr;3060sljit_uw size;30613062CHECK_ERROR();3063CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));30643065ADJUST_LOCAL_OFFSET(src1, src1w);30663067if (dst_freg != src2_freg) {3068if (dst_freg == src1) {3069src1 = src2_freg;3070src1w = 0;3071type ^= 0x1;3072} else3073FAIL_IF(push_inst(compiler, FMR | FD(dst_freg) | FB(src2_freg)));3074}30753076if (((type & ~SLJIT_32) | 0x1) == SLJIT_NOT_CARRY)3077FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG1) | A(TMP_ZERO) | B(TMP_ZERO)));30783079size = compiler->size;30803081ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));3082FAIL_IF(!ptr);3083compiler->size++;30843085if (src1 & SLJIT_MEM)3086FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, dst_freg, src1, src1w, TMP_REG1));3087else3088FAIL_IF(push_inst(compiler, FMR | FD(dst_freg) | FB(src1)));30893090*ptr = BCx | get_bo_bi_flags(compiler, (type ^ 0x1) & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 2);3091return SLJIT_SUCCESS;3092}30933094#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)30953096#define EMIT_MEM_LOAD_IMM(inst, mem, memw) \3097((sljit_s16)(memw) > SIMM_MAX - SSIZE_OF(sw))30983099#else /* !SLJIT_CONFIG_PPC_32 */31003101#define EMIT_MEM_LOAD_IMM(inst, mem, memw) \3102((((inst) & INT_ALIGNED) && ((memw) & 0x3) != 0) \3103|| ((sljit_s16)(memw) > SIMM_MAX - SSIZE_OF(sw)) \3104|| ((memw) > 0x7fff7fffl || (memw) < -0x80000000l)) \31053106#endif /* SLJIT_CONFIG_PPC_32 */31073108SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,3109sljit_s32 reg,3110sljit_s32 mem, sljit_sw memw)3111{3112sljit_ins inst;31133114CHECK_ERROR();3115CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));31163117if (!(reg & REG_PAIR_MASK))3118return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw);31193120ADJUST_LOCAL_OFFSET(mem, memw);31213122inst = data_transfer_insts[WORD_DATA | ((type & SLJIT_MEM_STORE) ? 0 : LOAD_DATA)];31233124if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {3125memw &= 0x3;31263127if (memw != 0) {3128FAIL_IF(push_inst(compiler, SLWI_W(memw) | S(OFFS_REG(mem)) | A(TMP_REG1)));3129FAIL_IF(push_inst(compiler, ADD | D(TMP_REG1) | A(TMP_REG1) | B(mem & REG_MASK)));3130} else3131FAIL_IF(push_inst(compiler, ADD | D(TMP_REG1) | A(mem & REG_MASK) | B(OFFS_REG(mem))));31323133mem = TMP_REG1;3134memw = 0;3135} else {3136if (EMIT_MEM_LOAD_IMM(inst, mem, memw)) {3137if ((mem & REG_MASK) != 0) {3138SLJIT_SKIP_CHECKS(compiler);3139FAIL_IF(sljit_emit_op2(compiler, SLJIT_ADD, TMP_REG1, 0, mem & REG_MASK, 0, SLJIT_IMM, memw));3140} else3141FAIL_IF(load_immediate(compiler, TMP_REG1, memw));31423143memw = 0;3144mem = TMP_REG1;3145} else if (memw > SIMM_MAX || memw < SIMM_MIN) {3146FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG1) | A(mem & REG_MASK) | IMM((memw + 0x8000) >> 16)));31473148memw &= 0xffff;3149mem = TMP_REG1;3150} else {3151memw &= 0xffff;3152mem &= REG_MASK;3153}3154}31553156SLJIT_ASSERT((memw >= 0 && memw <= SIMM_MAX - SSIZE_OF(sw)) || (memw >= 0x8000 && memw <= 0xffff));31573158#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)3159inst &= (sljit_ins)~INT_ALIGNED;3160#endif /* SLJIT_CONFIG_PPC_64 */31613162if (!(type & SLJIT_MEM_STORE) && mem == REG_PAIR_FIRST(reg)) {3163FAIL_IF(push_inst(compiler, inst | D(REG_PAIR_SECOND(reg)) | A(mem) | IMM(memw + SSIZE_OF(sw))));3164return push_inst(compiler, inst | D(REG_PAIR_FIRST(reg)) | A(mem) | IMM(memw));3165}31663167FAIL_IF(push_inst(compiler, inst | D(REG_PAIR_FIRST(reg)) | A(mem) | IMM(memw)));3168return push_inst(compiler, inst | D(REG_PAIR_SECOND(reg)) | A(mem) | IMM(memw + SSIZE_OF(sw)));3169}31703171#undef EMIT_MEM_LOAD_IMM31723173SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type,3174sljit_s32 reg,3175sljit_s32 mem, sljit_sw memw)3176{3177sljit_s32 mem_flags;3178sljit_ins inst;31793180CHECK_ERROR();3181CHECK(check_sljit_emit_mem_update(compiler, type, reg, mem, memw));31823183if (type & SLJIT_MEM_POST)3184return SLJIT_ERR_UNSUPPORTED;31853186switch (type & 0xff) {3187case SLJIT_MOV:3188case SLJIT_MOV_P:3189#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)3190case SLJIT_MOV_U32:3191case SLJIT_MOV_S32:3192case SLJIT_MOV32:3193#endif3194mem_flags = WORD_DATA;3195break;31963197#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)3198case SLJIT_MOV_U32:3199case SLJIT_MOV32:3200mem_flags = INT_DATA;3201break;32023203case SLJIT_MOV_S32:3204mem_flags = INT_DATA;32053206if (!(type & SLJIT_MEM_STORE) && !(type & SLJIT_32)) {3207if (mem & OFFS_REG_MASK)3208mem_flags |= SIGNED_DATA;3209else3210return SLJIT_ERR_UNSUPPORTED;3211}3212break;3213#endif32143215case SLJIT_MOV_U8:3216case SLJIT_MOV_S8:3217mem_flags = BYTE_DATA;3218break;32193220case SLJIT_MOV_U16:3221mem_flags = HALF_DATA;3222break;32233224case SLJIT_MOV_S16:3225mem_flags = HALF_DATA | SIGNED_DATA;3226break;32273228default:3229SLJIT_UNREACHABLE();3230mem_flags = WORD_DATA;3231break;3232}32333234if (!(type & SLJIT_MEM_STORE))3235mem_flags |= LOAD_DATA;32363237if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {3238if (memw != 0)3239return SLJIT_ERR_UNSUPPORTED;32403241if (type & SLJIT_MEM_SUPP)3242return SLJIT_SUCCESS;32433244inst = updated_data_transfer_insts[mem_flags | INDEXED];3245FAIL_IF(push_inst(compiler, INST_CODE_AND_DST(inst, 0, reg) | A(mem & REG_MASK) | B(OFFS_REG(mem))));3246}3247else {3248if (memw > SIMM_MAX || memw < SIMM_MIN)3249return SLJIT_ERR_UNSUPPORTED;32503251inst = updated_data_transfer_insts[mem_flags];32523253#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)3254if ((inst & INT_ALIGNED) && (memw & 0x3) != 0)3255return SLJIT_ERR_UNSUPPORTED;3256#endif32573258if (type & SLJIT_MEM_SUPP)3259return SLJIT_SUCCESS;32603261FAIL_IF(push_inst(compiler, INST_CODE_AND_DST(inst, 0, reg) | A(mem & REG_MASK) | IMM(memw)));3262}32633264if ((mem_flags & LOAD_DATA) && (type & 0xff) == SLJIT_MOV_S8)3265return push_inst(compiler, EXTSB | S(reg) | A(reg));3266return SLJIT_SUCCESS;3267}32683269SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler *compiler, sljit_s32 type,3270sljit_s32 freg,3271sljit_s32 mem, sljit_sw memw)3272{3273sljit_s32 mem_flags;3274sljit_ins inst;32753276CHECK_ERROR();3277CHECK(check_sljit_emit_fmem_update(compiler, type, freg, mem, memw));32783279if (type & SLJIT_MEM_POST)3280return SLJIT_ERR_UNSUPPORTED;32813282if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {3283if (memw != 0)3284return SLJIT_ERR_UNSUPPORTED;3285}3286else {3287if (memw > SIMM_MAX || memw < SIMM_MIN)3288return SLJIT_ERR_UNSUPPORTED;3289}32903291if (type & SLJIT_MEM_SUPP)3292return SLJIT_SUCCESS;32933294mem_flags = FLOAT_DATA(type);32953296if (!(type & SLJIT_MEM_STORE))3297mem_flags |= LOAD_DATA;32983299if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {3300inst = updated_data_transfer_insts[mem_flags | INDEXED];3301return push_inst(compiler, INST_CODE_AND_DST(inst, DOUBLE_DATA, freg) | A(mem & REG_MASK) | B(OFFS_REG(mem)));3302}33033304inst = updated_data_transfer_insts[mem_flags];3305return push_inst(compiler, INST_CODE_AND_DST(inst, DOUBLE_DATA, freg) | A(mem & REG_MASK) | IMM(memw));3306}33073308SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler, sljit_s32 op,3309sljit_s32 dst_reg,3310sljit_s32 mem_reg)3311{3312sljit_ins ins;33133314CHECK_ERROR();3315CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg));33163317if (op & SLJIT_ATOMIC_USE_CAS)3318return SLJIT_ERR_UNSUPPORTED;33193320switch (GET_OPCODE(op)) {3321case SLJIT_MOV:3322case SLJIT_MOV_P:3323#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)3324ins = LDARX;3325break;3326#endif /* SLJIT_CONFIG_PPC_64 */3327case SLJIT_MOV_U32:3328case SLJIT_MOV32:3329ins = LWARX;3330break;33313332default:3333return SLJIT_ERR_UNSUPPORTED;3334}33353336if (op & SLJIT_ATOMIC_TEST)3337return SLJIT_SUCCESS;33383339return push_inst(compiler, ins | D(dst_reg) | B(mem_reg));3340}33413342SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler, sljit_s32 op,3343sljit_s32 src_reg,3344sljit_s32 mem_reg,3345sljit_s32 temp_reg)3346{3347sljit_ins ins;33483349/* temp_reg == mem_reg is undefined so use another temp register */3350SLJIT_UNUSED_ARG(temp_reg);33513352CHECK_ERROR();3353CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));33543355if (op & SLJIT_ATOMIC_USE_CAS)3356return SLJIT_ERR_UNSUPPORTED;33573358switch (GET_OPCODE(op)) {3359case SLJIT_MOV:3360case SLJIT_MOV_P:3361#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)3362ins = STDCX | 0x1;3363break;3364#endif /* SLJIT_CONFIG_PPC_64 */3365case SLJIT_MOV_U32:3366case SLJIT_MOV32:3367ins = STWCX | 0x1;3368break;33693370default:3371return SLJIT_ERR_UNSUPPORTED;3372}33733374if (op & SLJIT_ATOMIC_TEST)3375return SLJIT_SUCCESS;33763377return push_inst(compiler, ins | D(src_reg) | B(mem_reg));3378}33793380SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 op,3381sljit_s32 dst, sljit_sw dstw,3382sljit_sw init_value)3383{3384struct sljit_const *const_;3385sljit_s32 dst_r;3386sljit_s32 mem_flags = WORD_DATA;33873388CHECK_ERROR_PTR();3389CHECK_PTR(check_sljit_emit_const(compiler, op, dst, dstw, init_value));3390ADJUST_LOCAL_OFFSET(dst, dstw);33913392const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));3393PTR_FAIL_IF(!const_);3394set_const(const_, compiler);33953396dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;33973398switch (GET_OPCODE(op)) {3399case SLJIT_MOV_U8:3400if (init_value & 0x100)3401init_value |= 0xff00;3402else3403init_value &= 0xff;34043405PTR_FAIL_IF(push_inst(compiler, ADDI | D(dst_r) | A(0) | IMM(init_value)));3406mem_flags = BYTE_DATA;3407break;34083409#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)3410case SLJIT_MOV32:3411mem_flags = INT_DATA;3412SLJIT_FALLTHROUGH3413case SLJIT_MOV_S32:3414PTR_FAIL_IF(push_inst(compiler, ADDIS | D(dst_r) | A(0) | IMM(init_value >> 16)));3415PTR_FAIL_IF(push_inst(compiler, ORI | S(dst_r) | A(dst_r) | IMM(init_value)));3416break;3417#endif /* SLJIT_CONFIG_PPC_64 */34183419default:3420PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));3421break;3422}34233424if (dst & SLJIT_MEM)3425PTR_FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, dst, dstw, TMP_REG1));34263427return const_;3428}34293430SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_op_addr(struct sljit_compiler *compiler, sljit_s32 op,3431sljit_s32 dst, sljit_sw dstw)3432{3433struct sljit_jump *jump;3434sljit_s32 dst_r, target_r;3435SLJIT_UNUSED_ARG(op);34363437CHECK_ERROR_PTR();3438CHECK_PTR(check_sljit_emit_op_addr(compiler, op, dst, dstw));3439ADJUST_LOCAL_OFFSET(dst, dstw);34403441dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;34423443if (op != SLJIT_ADD_ABS_ADDR)3444target_r = dst_r;3445else {3446target_r = TMP_REG1;34473448if (dst & SLJIT_MEM)3449PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst_r, dst, dstw, TMP_REG1));3450}34513452jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));3453PTR_FAIL_IF(!jump);3454set_mov_addr(jump, compiler, 0);34553456PTR_FAIL_IF(push_inst(compiler, (sljit_ins)target_r));3457#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)3458compiler->size++;3459#else3460compiler->size += 4;3461#endif34623463if (op == SLJIT_ADD_ABS_ADDR)3464PTR_FAIL_IF(push_inst(compiler, ADD | D(dst_r) | A(dst_r) | B(TMP_REG1)));34653466if (dst & SLJIT_MEM)3467PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, dst_r, dst, dstw, TMP_REG1));34683469return jump;3470}34713472SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_s32 op, sljit_sw new_constant, sljit_sw executable_offset)3473{3474sljit_ins *inst;34753476switch (GET_OPCODE(op)) {3477case SLJIT_MOV_U8:3478inst = (sljit_ins *)addr;3479SLJIT_ASSERT((inst[0] & 0xfc1f0000) == ADDI);34803481if (new_constant & 0x100)3482new_constant |= 0xff00;3483else3484new_constant &= 0xff;34853486SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);3487inst[0] = (inst[0] & 0xffff0000) | IMM(new_constant);3488SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);3489inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);3490SLJIT_CACHE_FLUSH(inst, inst + 1);3491return;34923493#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)3494case SLJIT_MOV32:3495case SLJIT_MOV_S32:3496inst = (sljit_ins *)addr;3497SLJIT_ASSERT((inst[0] & 0xfc1f0000) == ADDIS && (inst[1] & 0xfc000000) == ORI);34983499SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);3500inst[0] = (inst[0] & 0xffff0000) | IMM(new_constant >> 16);3501inst[1] = (inst[1] & 0xffff0000) | IMM(new_constant);3502SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);3503inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);3504SLJIT_CACHE_FLUSH(inst, inst + 2);3505return;3506#endif /* SLJIT_CONFIG_PPC_64 */35073508default:3509sljit_set_jump_addr(addr, (sljit_uw)new_constant, executable_offset);3510return;3511}3512}351335143515