1*632be62bSalnsn /* $NetBSD: sljitNativePPC_common.c,v 1.8 2019/01/20 23:14:16 alnsn Exp $ */
2637c186aSalnsn
30675068dSalnsn /*
40675068dSalnsn * Stack-less Just-In-Time compiler
50675068dSalnsn *
6*632be62bSalnsn * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
70675068dSalnsn *
80675068dSalnsn * Redistribution and use in source and binary forms, with or without modification, are
90675068dSalnsn * permitted provided that the following conditions are met:
100675068dSalnsn *
110675068dSalnsn * 1. Redistributions of source code must retain the above copyright notice, this list of
120675068dSalnsn * conditions and the following disclaimer.
130675068dSalnsn *
140675068dSalnsn * 2. Redistributions in binary form must reproduce the above copyright notice, this list
150675068dSalnsn * of conditions and the following disclaimer in the documentation and/or other materials
160675068dSalnsn * provided with the distribution.
170675068dSalnsn *
180675068dSalnsn * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
190675068dSalnsn * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
200675068dSalnsn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
210675068dSalnsn * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
220675068dSalnsn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
230675068dSalnsn * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
240675068dSalnsn * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
250675068dSalnsn * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
260675068dSalnsn * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
270675068dSalnsn */
280675068dSalnsn
sljit_get_platform_name(void)29dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
300675068dSalnsn {
310675068dSalnsn return "PowerPC" SLJIT_CPUINFO;
320675068dSalnsn }
330675068dSalnsn
340675068dSalnsn /* Length of an instruction word.
350675068dSalnsn Both for ppc-32 and ppc-64. */
36dfd7d8b1Salnsn typedef sljit_u32 sljit_ins;
370675068dSalnsn
3856b25969Salnsn #if ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && (defined _AIX)) \
3956b25969Salnsn || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
4056b25969Salnsn #define SLJIT_PPC_STACK_FRAME_V2 1
4156b25969Salnsn #endif
4256b25969Salnsn
430675068dSalnsn #ifdef _AIX
440675068dSalnsn #include <sys/cache.h>
450675068dSalnsn #endif
460675068dSalnsn
4756b25969Salnsn #if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
4856b25969Salnsn #define SLJIT_PASS_ENTRY_ADDR_TO_CALL 1
4956b25969Salnsn #endif
5056b25969Salnsn
519b498555Salnsn #if (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL)
529b498555Salnsn
ppc_cache_flush(sljit_ins * from,sljit_ins * to)539b498555Salnsn static void ppc_cache_flush(sljit_ins *from, sljit_ins *to)
549b498555Salnsn {
559b498555Salnsn #ifdef _AIX
569b498555Salnsn _sync_cache_range((caddr_t)from, (int)((size_t)to - (size_t)from));
579b498555Salnsn #elif defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM)
589b498555Salnsn # if defined(_ARCH_PWR) || defined(_ARCH_PWR2)
599b498555Salnsn /* Cache flush for POWER architecture. */
609b498555Salnsn while (from < to) {
619b498555Salnsn __asm__ volatile (
629b498555Salnsn "clf 0, %0\n"
639b498555Salnsn "dcs\n"
649b498555Salnsn : : "r"(from)
659b498555Salnsn );
669b498555Salnsn from++;
679b498555Salnsn }
689b498555Salnsn __asm__ volatile ( "ics" );
699b498555Salnsn # elif defined(_ARCH_COM) && !defined(_ARCH_PPC)
709b498555Salnsn # error "Cache flush is not implemented for PowerPC/POWER common mode."
719b498555Salnsn # else
729b498555Salnsn /* Cache flush for PowerPC architecture. */
739b498555Salnsn while (from < to) {
749b498555Salnsn __asm__ volatile (
759b498555Salnsn "dcbf 0, %0\n"
769b498555Salnsn "sync\n"
779b498555Salnsn "icbi 0, %0\n"
789b498555Salnsn : : "r"(from)
799b498555Salnsn );
809b498555Salnsn from++;
819b498555Salnsn }
829b498555Salnsn __asm__ volatile ( "isync" );
839b498555Salnsn # endif
849b498555Salnsn # ifdef __xlc__
859b498555Salnsn # warning "This file may fail to compile if -qfuncsect is used"
869b498555Salnsn # endif
879b498555Salnsn #elif defined(__xlc__)
889b498555Salnsn #error "Please enable GCC syntax for inline assembly statements with -qasm=gcc"
899b498555Salnsn #else
909b498555Salnsn #error "This platform requires a cache flush implementation."
919b498555Salnsn #endif /* _AIX */
929b498555Salnsn }
939b498555Salnsn
949b498555Salnsn #endif /* (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL) */
959b498555Salnsn
960197013aSalnsn #define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
970197013aSalnsn #define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
980197013aSalnsn #define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4)
990197013aSalnsn #define TMP_ZERO (SLJIT_NUMBER_OF_REGISTERS + 5)
1000675068dSalnsn
10156b25969Salnsn #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
102dfd7d8b1Salnsn #define TMP_CALL_REG (SLJIT_NUMBER_OF_REGISTERS + 6)
10356b25969Salnsn #else
10456b25969Salnsn #define TMP_CALL_REG TMP_REG2
10556b25969Salnsn #endif
1060675068dSalnsn
10756b25969Salnsn #define TMP_FREG1 (0)
108dfd7d8b1Salnsn #define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
10956b25969Salnsn
110dfd7d8b1Salnsn static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
111dfd7d8b1Salnsn 0, 3, 4, 5, 6, 7, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 1, 8, 9, 10, 31, 12
1124bc045d4Salnsn };
1134bc045d4Salnsn
1140675068dSalnsn /* --------------------------------------------------------------------- */
1150675068dSalnsn /* Instrucion forms */
1160675068dSalnsn /* --------------------------------------------------------------------- */
1170675068dSalnsn #define D(d) (reg_map[d] << 21)
1180675068dSalnsn #define S(s) (reg_map[s] << 21)
1190675068dSalnsn #define A(a) (reg_map[a] << 16)
1200675068dSalnsn #define B(b) (reg_map[b] << 11)
1210675068dSalnsn #define C(c) (reg_map[c] << 6)
1220675068dSalnsn #define FD(fd) ((fd) << 21)
123dfd7d8b1Salnsn #define FS(fs) ((fs) << 21)
1240675068dSalnsn #define FA(fa) ((fa) << 16)
1250675068dSalnsn #define FB(fb) ((fb) << 11)
1260675068dSalnsn #define FC(fc) ((fc) << 6)
1270675068dSalnsn #define IMM(imm) ((imm) & 0xffff)
1280675068dSalnsn #define CRD(d) ((d) << 21)
1290675068dSalnsn
1300675068dSalnsn /* Instruction bit sections.
1310675068dSalnsn OE and Rc flag (see ALT_SET_FLAGS). */
1320675068dSalnsn #define OERC(flags) (((flags & ALT_SET_FLAGS) >> 10) | (flags & ALT_SET_FLAGS))
1330675068dSalnsn /* Rc flag (see ALT_SET_FLAGS). */
1340675068dSalnsn #define RC(flags) ((flags & ALT_SET_FLAGS) >> 10)
1350675068dSalnsn #define HI(opcode) ((opcode) << 26)
1360675068dSalnsn #define LO(opcode) ((opcode) << 1)
1370675068dSalnsn
1380675068dSalnsn #define ADD (HI(31) | LO(266))
1390675068dSalnsn #define ADDC (HI(31) | LO(10))
1400675068dSalnsn #define ADDE (HI(31) | LO(138))
1410675068dSalnsn #define ADDI (HI(14))
1420675068dSalnsn #define ADDIC (HI(13))
1430675068dSalnsn #define ADDIS (HI(15))
1440675068dSalnsn #define ADDME (HI(31) | LO(234))
1450675068dSalnsn #define AND (HI(31) | LO(28))
1460675068dSalnsn #define ANDI (HI(28))
1470675068dSalnsn #define ANDIS (HI(29))
1480675068dSalnsn #define Bx (HI(18))
1490675068dSalnsn #define BCx (HI(16))
1500675068dSalnsn #define BCCTR (HI(19) | LO(528) | (3 << 11))
1510675068dSalnsn #define BLR (HI(19) | LO(16) | (0x14 << 21))
1520675068dSalnsn #define CNTLZD (HI(31) | LO(58))
1530675068dSalnsn #define CNTLZW (HI(31) | LO(26))
1540675068dSalnsn #define CMP (HI(31) | LO(0))
1550675068dSalnsn #define CMPI (HI(11))
1560675068dSalnsn #define CMPL (HI(31) | LO(32))
1570675068dSalnsn #define CMPLI (HI(10))
1580675068dSalnsn #define CROR (HI(19) | LO(449))
1590675068dSalnsn #define DIVD (HI(31) | LO(489))
1600675068dSalnsn #define DIVDU (HI(31) | LO(457))
1610675068dSalnsn #define DIVW (HI(31) | LO(491))
1620675068dSalnsn #define DIVWU (HI(31) | LO(459))
1630675068dSalnsn #define EXTSB (HI(31) | LO(954))
1640675068dSalnsn #define EXTSH (HI(31) | LO(922))
1650675068dSalnsn #define EXTSW (HI(31) | LO(986))
1660675068dSalnsn #define FABS (HI(63) | LO(264))
1670675068dSalnsn #define FADD (HI(63) | LO(21))
16856b25969Salnsn #define FADDS (HI(59) | LO(21))
169dfd7d8b1Salnsn #define FCFID (HI(63) | LO(846))
1700675068dSalnsn #define FCMPU (HI(63) | LO(0))
171dfd7d8b1Salnsn #define FCTIDZ (HI(63) | LO(815))
172dfd7d8b1Salnsn #define FCTIWZ (HI(63) | LO(15))
1730675068dSalnsn #define FDIV (HI(63) | LO(18))
17456b25969Salnsn #define FDIVS (HI(59) | LO(18))
1750675068dSalnsn #define FMR (HI(63) | LO(72))
1760675068dSalnsn #define FMUL (HI(63) | LO(25))
17756b25969Salnsn #define FMULS (HI(59) | LO(25))
1780675068dSalnsn #define FNEG (HI(63) | LO(40))
179dfd7d8b1Salnsn #define FRSP (HI(63) | LO(12))
1800675068dSalnsn #define FSUB (HI(63) | LO(20))
18156b25969Salnsn #define FSUBS (HI(59) | LO(20))
1820675068dSalnsn #define LD (HI(58) | 0)
1830675068dSalnsn #define LWZ (HI(32))
1840675068dSalnsn #define MFCR (HI(31) | LO(19))
1850675068dSalnsn #define MFLR (HI(31) | LO(339) | 0x80000)
1860675068dSalnsn #define MFXER (HI(31) | LO(339) | 0x10000)
1870675068dSalnsn #define MTCTR (HI(31) | LO(467) | 0x90000)
1880675068dSalnsn #define MTLR (HI(31) | LO(467) | 0x80000)
1890675068dSalnsn #define MTXER (HI(31) | LO(467) | 0x10000)
1900675068dSalnsn #define MULHD (HI(31) | LO(73))
1910675068dSalnsn #define MULHDU (HI(31) | LO(9))
1920675068dSalnsn #define MULHW (HI(31) | LO(75))
1930675068dSalnsn #define MULHWU (HI(31) | LO(11))
1940675068dSalnsn #define MULLD (HI(31) | LO(233))
1950675068dSalnsn #define MULLI (HI(7))
1960675068dSalnsn #define MULLW (HI(31) | LO(235))
1970675068dSalnsn #define NEG (HI(31) | LO(104))
1980675068dSalnsn #define NOP (HI(24))
1990675068dSalnsn #define NOR (HI(31) | LO(124))
2000675068dSalnsn #define OR (HI(31) | LO(444))
2010675068dSalnsn #define ORI (HI(24))
2020675068dSalnsn #define ORIS (HI(25))
2030675068dSalnsn #define RLDICL (HI(30))
2040675068dSalnsn #define RLWINM (HI(21))
2050675068dSalnsn #define SLD (HI(31) | LO(27))
2060675068dSalnsn #define SLW (HI(31) | LO(24))
2070675068dSalnsn #define SRAD (HI(31) | LO(794))
2080675068dSalnsn #define SRADI (HI(31) | LO(413 << 1))
2090675068dSalnsn #define SRAW (HI(31) | LO(792))
2100675068dSalnsn #define SRAWI (HI(31) | LO(824))
2110675068dSalnsn #define SRD (HI(31) | LO(539))
2120675068dSalnsn #define SRW (HI(31) | LO(536))
2130675068dSalnsn #define STD (HI(62) | 0)
2140675068dSalnsn #define STDU (HI(62) | 1)
2150675068dSalnsn #define STDUX (HI(31) | LO(181))
216dfd7d8b1Salnsn #define STFIWX (HI(31) | LO(983))
2170675068dSalnsn #define STW (HI(36))
2180675068dSalnsn #define STWU (HI(37))
2190675068dSalnsn #define STWUX (HI(31) | LO(183))
2200675068dSalnsn #define SUBF (HI(31) | LO(40))
2210675068dSalnsn #define SUBFC (HI(31) | LO(8))
2220675068dSalnsn #define SUBFE (HI(31) | LO(136))
2230675068dSalnsn #define SUBFIC (HI(8))
2240675068dSalnsn #define XOR (HI(31) | LO(316))
2250675068dSalnsn #define XORI (HI(26))
2260675068dSalnsn #define XORIS (HI(27))
2270675068dSalnsn
2280675068dSalnsn #define SIMM_MAX (0x7fff)
2290675068dSalnsn #define SIMM_MIN (-0x8000)
2300675068dSalnsn #define UIMM_MAX (0xffff)
2310675068dSalnsn
2320675068dSalnsn #if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
sljit_set_function_context(void ** func_ptr,struct sljit_function_context * context,sljit_sw addr,void * func)23356b25969Salnsn SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_sw addr, void* func)
2340675068dSalnsn {
23556b25969Salnsn sljit_sw* ptrs;
2360675068dSalnsn if (func_ptr)
2370675068dSalnsn *func_ptr = (void*)context;
23856b25969Salnsn ptrs = (sljit_sw*)func;
2390675068dSalnsn context->addr = addr ? addr : ptrs[0];
2400675068dSalnsn context->r2 = ptrs[1];
2410675068dSalnsn context->r11 = ptrs[2];
2420675068dSalnsn }
2430675068dSalnsn #endif
2440675068dSalnsn
push_inst(struct sljit_compiler * compiler,sljit_ins ins)245dfd7d8b1Salnsn static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
2460675068dSalnsn {
2470675068dSalnsn sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
2480675068dSalnsn FAIL_IF(!ptr);
2490675068dSalnsn *ptr = ins;
2500675068dSalnsn compiler->size++;
2510675068dSalnsn return SLJIT_SUCCESS;
2520675068dSalnsn }
2530675068dSalnsn
detect_jump_type(struct sljit_jump * jump,sljit_ins * code_ptr,sljit_ins * code,sljit_sw executable_offset)254*632be62bSalnsn static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
2550675068dSalnsn {
25656b25969Salnsn sljit_sw diff;
2570675068dSalnsn sljit_uw target_addr;
25856b25969Salnsn sljit_sw extra_jump_flags;
2590675068dSalnsn
26056b25969Salnsn #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
26156b25969Salnsn if (jump->flags & (SLJIT_REWRITABLE_JUMP | IS_CALL))
26256b25969Salnsn return 0;
26356b25969Salnsn #else
2640675068dSalnsn if (jump->flags & SLJIT_REWRITABLE_JUMP)
2650675068dSalnsn return 0;
26656b25969Salnsn #endif
2670675068dSalnsn
2680675068dSalnsn if (jump->flags & JUMP_ADDR)
2690675068dSalnsn target_addr = jump->u.target;
2700675068dSalnsn else {
2710675068dSalnsn SLJIT_ASSERT(jump->flags & JUMP_LABEL);
272*632be62bSalnsn target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
2730675068dSalnsn }
2740675068dSalnsn
27556b25969Salnsn #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
27656b25969Salnsn if (jump->flags & IS_CALL)
27756b25969Salnsn goto keep_address;
27856b25969Salnsn #endif
27956b25969Salnsn
280*632be62bSalnsn diff = ((sljit_sw)target_addr - (sljit_sw)(code_ptr) - executable_offset) & ~0x3l;
28156b25969Salnsn
28256b25969Salnsn extra_jump_flags = 0;
28356b25969Salnsn if (jump->flags & IS_COND) {
2840675068dSalnsn if (diff <= 0x7fff && diff >= -0x8000) {
2850675068dSalnsn jump->flags |= PATCH_B;
2860675068dSalnsn return 1;
2870675068dSalnsn }
2880675068dSalnsn if (target_addr <= 0xffff) {
28956b25969Salnsn jump->flags |= PATCH_B | PATCH_ABS_B;
2900675068dSalnsn return 1;
2910675068dSalnsn }
29256b25969Salnsn extra_jump_flags = REMOVE_COND;
29356b25969Salnsn
29456b25969Salnsn diff -= sizeof(sljit_ins);
2950675068dSalnsn }
29656b25969Salnsn
29756b25969Salnsn if (diff <= 0x01ffffff && diff >= -0x02000000) {
29856b25969Salnsn jump->flags |= PATCH_B | extra_jump_flags;
29956b25969Salnsn return 1;
30056b25969Salnsn }
301*632be62bSalnsn
30256b25969Salnsn if (target_addr <= 0x03ffffff) {
30356b25969Salnsn jump->flags |= PATCH_B | PATCH_ABS_B | extra_jump_flags;
30456b25969Salnsn return 1;
30556b25969Salnsn }
30656b25969Salnsn
30756b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
30856b25969Salnsn #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
30956b25969Salnsn keep_address:
31056b25969Salnsn #endif
31156b25969Salnsn if (target_addr <= 0x7fffffff) {
31256b25969Salnsn jump->flags |= PATCH_ABS32;
31356b25969Salnsn return 1;
31456b25969Salnsn }
315*632be62bSalnsn
31656b25969Salnsn if (target_addr <= 0x7fffffffffffl) {
31756b25969Salnsn jump->flags |= PATCH_ABS48;
31856b25969Salnsn return 1;
31956b25969Salnsn }
32056b25969Salnsn #endif
32156b25969Salnsn
3220675068dSalnsn return 0;
3230675068dSalnsn }
3240675068dSalnsn
sljit_generate_code(struct sljit_compiler * compiler)3250675068dSalnsn SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
3260675068dSalnsn {
3270675068dSalnsn struct sljit_memory_fragment *buf;
3280675068dSalnsn sljit_ins *code;
3290675068dSalnsn sljit_ins *code_ptr;
3300675068dSalnsn sljit_ins *buf_ptr;
3310675068dSalnsn sljit_ins *buf_end;
3320675068dSalnsn sljit_uw word_count;
333*632be62bSalnsn sljit_sw executable_offset;
3340675068dSalnsn sljit_uw addr;
3350675068dSalnsn
3360675068dSalnsn struct sljit_label *label;
3370675068dSalnsn struct sljit_jump *jump;
3380675068dSalnsn struct sljit_const *const_;
3390675068dSalnsn
3400675068dSalnsn CHECK_ERROR_PTR();
341dfd7d8b1Salnsn CHECK_PTR(check_sljit_generate_code(compiler));
3420675068dSalnsn reverse_buf(compiler);
3430675068dSalnsn
3440675068dSalnsn #if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
3450675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
3460675068dSalnsn compiler->size += (compiler->size & 0x1) + (sizeof(struct sljit_function_context) / sizeof(sljit_ins));
3470675068dSalnsn #else
3480675068dSalnsn compiler->size += (sizeof(struct sljit_function_context) / sizeof(sljit_ins));
3490675068dSalnsn #endif
3500675068dSalnsn #endif
3510675068dSalnsn code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins));
3520675068dSalnsn PTR_FAIL_WITH_EXEC_IF(code);
3530675068dSalnsn buf = compiler->buf;
3540675068dSalnsn
3550675068dSalnsn code_ptr = code;
3560675068dSalnsn word_count = 0;
357*632be62bSalnsn executable_offset = SLJIT_EXEC_OFFSET(code);
358*632be62bSalnsn
3590675068dSalnsn label = compiler->labels;
3600675068dSalnsn jump = compiler->jumps;
3610675068dSalnsn const_ = compiler->consts;
362*632be62bSalnsn
3630675068dSalnsn do {
3640675068dSalnsn buf_ptr = (sljit_ins*)buf->memory;
3650675068dSalnsn buf_end = buf_ptr + (buf->used_size >> 2);
3660675068dSalnsn do {
3670675068dSalnsn *code_ptr = *buf_ptr++;
3680675068dSalnsn SLJIT_ASSERT(!label || label->size >= word_count);
3690675068dSalnsn SLJIT_ASSERT(!jump || jump->addr >= word_count);
3700675068dSalnsn SLJIT_ASSERT(!const_ || const_->addr >= word_count);
3710675068dSalnsn /* These structures are ordered by their address. */
3720675068dSalnsn if (label && label->size == word_count) {
3730675068dSalnsn /* Just recording the address. */
374*632be62bSalnsn label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
3750675068dSalnsn label->size = code_ptr - code;
3760675068dSalnsn label = label->next;
3770675068dSalnsn }
3780675068dSalnsn if (jump && jump->addr == word_count) {
3790675068dSalnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
3800675068dSalnsn jump->addr = (sljit_uw)(code_ptr - 3);
3810675068dSalnsn #else
3820675068dSalnsn jump->addr = (sljit_uw)(code_ptr - 6);
3830675068dSalnsn #endif
384*632be62bSalnsn if (detect_jump_type(jump, code_ptr, code, executable_offset)) {
3850675068dSalnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
3860675068dSalnsn code_ptr[-3] = code_ptr[0];
3870675068dSalnsn code_ptr -= 3;
3880675068dSalnsn #else
38956b25969Salnsn if (jump->flags & PATCH_ABS32) {
39056b25969Salnsn code_ptr -= 3;
39156b25969Salnsn code_ptr[-1] = code_ptr[2];
39256b25969Salnsn code_ptr[0] = code_ptr[3];
39356b25969Salnsn }
39456b25969Salnsn else if (jump->flags & PATCH_ABS48) {
39556b25969Salnsn code_ptr--;
39656b25969Salnsn code_ptr[-1] = code_ptr[0];
39756b25969Salnsn code_ptr[0] = code_ptr[1];
39856b25969Salnsn /* rldicr rX,rX,32,31 -> rX,rX,16,47 */
39956b25969Salnsn SLJIT_ASSERT((code_ptr[-3] & 0xfc00ffff) == 0x780007c6);
40056b25969Salnsn code_ptr[-3] ^= 0x8422;
40156b25969Salnsn /* oris -> ori */
40256b25969Salnsn code_ptr[-2] ^= 0x4000000;
40356b25969Salnsn }
40456b25969Salnsn else {
4050675068dSalnsn code_ptr[-6] = code_ptr[0];
4060675068dSalnsn code_ptr -= 6;
40756b25969Salnsn }
4080675068dSalnsn #endif
40956b25969Salnsn if (jump->flags & REMOVE_COND) {
41056b25969Salnsn code_ptr[0] = BCx | (2 << 2) | ((code_ptr[0] ^ (8 << 21)) & 0x03ff0001);
41156b25969Salnsn code_ptr++;
41256b25969Salnsn jump->addr += sizeof(sljit_ins);
41356b25969Salnsn code_ptr[0] = Bx;
41456b25969Salnsn jump->flags -= IS_COND;
41556b25969Salnsn }
4160675068dSalnsn }
4170675068dSalnsn jump = jump->next;
4180675068dSalnsn }
4190675068dSalnsn if (const_ && const_->addr == word_count) {
4200675068dSalnsn const_->addr = (sljit_uw)code_ptr;
4210675068dSalnsn const_ = const_->next;
4220675068dSalnsn }
4230675068dSalnsn code_ptr ++;
4240675068dSalnsn word_count ++;
4250675068dSalnsn } while (buf_ptr < buf_end);
4260675068dSalnsn
4270675068dSalnsn buf = buf->next;
4280675068dSalnsn } while (buf);
4290675068dSalnsn
4300675068dSalnsn if (label && label->size == word_count) {
431*632be62bSalnsn label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
4320675068dSalnsn label->size = code_ptr - code;
4330675068dSalnsn label = label->next;
4340675068dSalnsn }
4350675068dSalnsn
4360675068dSalnsn SLJIT_ASSERT(!label);
4370675068dSalnsn SLJIT_ASSERT(!jump);
4380675068dSalnsn SLJIT_ASSERT(!const_);
4390675068dSalnsn #if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
44056b25969Salnsn SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size - (sizeof(struct sljit_function_context) / sizeof(sljit_ins)));
4410675068dSalnsn #else
44256b25969Salnsn SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size);
4430675068dSalnsn #endif
4440675068dSalnsn
4450675068dSalnsn jump = compiler->jumps;
4460675068dSalnsn while (jump) {
4470675068dSalnsn do {
4480675068dSalnsn addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
4490675068dSalnsn buf_ptr = (sljit_ins *)jump->addr;
450*632be62bSalnsn
4510675068dSalnsn if (jump->flags & PATCH_B) {
45256b25969Salnsn if (jump->flags & IS_COND) {
45356b25969Salnsn if (!(jump->flags & PATCH_ABS_B)) {
454*632be62bSalnsn addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
45556b25969Salnsn SLJIT_ASSERT((sljit_sw)addr <= 0x7fff && (sljit_sw)addr >= -0x8000);
45656b25969Salnsn *buf_ptr = BCx | (addr & 0xfffc) | ((*buf_ptr) & 0x03ff0001);
45756b25969Salnsn }
45856b25969Salnsn else {
45956b25969Salnsn SLJIT_ASSERT(addr <= 0xffff);
46056b25969Salnsn *buf_ptr = BCx | (addr & 0xfffc) | 0x2 | ((*buf_ptr) & 0x03ff0001);
46156b25969Salnsn }
46256b25969Salnsn }
46356b25969Salnsn else {
46456b25969Salnsn if (!(jump->flags & PATCH_ABS_B)) {
465*632be62bSalnsn addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
46656b25969Salnsn SLJIT_ASSERT((sljit_sw)addr <= 0x01ffffff && (sljit_sw)addr >= -0x02000000);
4670675068dSalnsn *buf_ptr = Bx | (addr & 0x03fffffc) | ((*buf_ptr) & 0x1);
4680675068dSalnsn }
4690675068dSalnsn else {
4700675068dSalnsn SLJIT_ASSERT(addr <= 0x03ffffff);
4710675068dSalnsn *buf_ptr = Bx | (addr & 0x03fffffc) | 0x2 | ((*buf_ptr) & 0x1);
4720675068dSalnsn }
4730675068dSalnsn }
4740675068dSalnsn break;
4750675068dSalnsn }
476*632be62bSalnsn
4770675068dSalnsn /* Set the fields of immediate loads. */
4780675068dSalnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
4790675068dSalnsn buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 16) & 0xffff);
4800675068dSalnsn buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | (addr & 0xffff);
4810675068dSalnsn #else
48256b25969Salnsn if (jump->flags & PATCH_ABS32) {
48356b25969Salnsn SLJIT_ASSERT(addr <= 0x7fffffff);
48456b25969Salnsn buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 16) & 0xffff);
48556b25969Salnsn buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | (addr & 0xffff);
48656b25969Salnsn break;
48756b25969Salnsn }
48856b25969Salnsn if (jump->flags & PATCH_ABS48) {
48956b25969Salnsn SLJIT_ASSERT(addr <= 0x7fffffffffff);
49056b25969Salnsn buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 32) & 0xffff);
49156b25969Salnsn buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | ((addr >> 16) & 0xffff);
49256b25969Salnsn buf_ptr[3] = (buf_ptr[3] & 0xffff0000) | (addr & 0xffff);
49356b25969Salnsn break;
49456b25969Salnsn }
4950675068dSalnsn buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 48) & 0xffff);
4960675068dSalnsn buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | ((addr >> 32) & 0xffff);
4970675068dSalnsn buf_ptr[3] = (buf_ptr[3] & 0xffff0000) | ((addr >> 16) & 0xffff);
4980675068dSalnsn buf_ptr[4] = (buf_ptr[4] & 0xffff0000) | (addr & 0xffff);
4990675068dSalnsn #endif
5000675068dSalnsn } while (0);
5010675068dSalnsn jump = jump->next;
5020675068dSalnsn }
5030675068dSalnsn
5040675068dSalnsn compiler->error = SLJIT_ERR_COMPILED;
505*632be62bSalnsn compiler->executable_offset = executable_offset;
50656b25969Salnsn compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
507*632be62bSalnsn
508*632be62bSalnsn code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
5090675068dSalnsn
5100675068dSalnsn #if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
5110675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
51256b25969Salnsn if (((sljit_sw)code_ptr) & 0x4)
5130675068dSalnsn code_ptr++;
5140675068dSalnsn #endif
515*632be62bSalnsn sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_sw)code, (void*)sljit_generate_code);
516*632be62bSalnsn #endif
517*632be62bSalnsn
518*632be62bSalnsn code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
519*632be62bSalnsn
520*632be62bSalnsn SLJIT_CACHE_FLUSH(code, code_ptr);
521*632be62bSalnsn
522*632be62bSalnsn #if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
523*632be62bSalnsn return code_ptr;
5240675068dSalnsn #else
5250675068dSalnsn return code;
5260675068dSalnsn #endif
5270675068dSalnsn }
5280675068dSalnsn
5294bc045d4Salnsn /* --------------------------------------------------------------------- */
5304bc045d4Salnsn /* Entry, exit */
5314bc045d4Salnsn /* --------------------------------------------------------------------- */
5324bc045d4Salnsn
5330675068dSalnsn /* inp_flags: */
5340675068dSalnsn
5350675068dSalnsn /* Creates an index in data_transfer_insts array. */
5364bc045d4Salnsn #define LOAD_DATA 0x01
5374bc045d4Salnsn #define INDEXED 0x02
5384bc045d4Salnsn #define WRITE_BACK 0x04
5390675068dSalnsn #define WORD_DATA 0x00
5404bc045d4Salnsn #define BYTE_DATA 0x08
5414bc045d4Salnsn #define HALF_DATA 0x10
5424bc045d4Salnsn #define INT_DATA 0x18
5434bc045d4Salnsn #define SIGNED_DATA 0x20
5444bc045d4Salnsn /* Separates integer and floating point registers */
5454bc045d4Salnsn #define GPR_REG 0x3f
5464bc045d4Salnsn #define DOUBLE_DATA 0x40
5470675068dSalnsn
5484bc045d4Salnsn #define MEM_MASK 0x7f
5490675068dSalnsn
5500675068dSalnsn /* Other inp_flags. */
5510675068dSalnsn
5520675068dSalnsn #define ARG_TEST 0x000100
5530675068dSalnsn /* Integer opertion and set flags -> requires exts on 64 bit systems. */
5540675068dSalnsn #define ALT_SIGN_EXT 0x000200
5550675068dSalnsn /* This flag affects the RC() and OERC() macros. */
5560675068dSalnsn #define ALT_SET_FLAGS 0x000400
55756b25969Salnsn #define ALT_KEEP_CACHE 0x000800
5580675068dSalnsn #define ALT_FORM1 0x010000
5590675068dSalnsn #define ALT_FORM2 0x020000
5600675068dSalnsn #define ALT_FORM3 0x040000
5610675068dSalnsn #define ALT_FORM4 0x080000
5620675068dSalnsn #define ALT_FORM5 0x100000
5630675068dSalnsn #define ALT_FORM6 0x200000
564*632be62bSalnsn #define ALT_FORM7 0x400000
5650675068dSalnsn
5660675068dSalnsn /* Source and destination is register. */
5670675068dSalnsn #define REG_DEST 0x000001
5680675068dSalnsn #define REG1_SOURCE 0x000002
5690675068dSalnsn #define REG2_SOURCE 0x000004
5700675068dSalnsn /* getput_arg_fast returned true. */
5710675068dSalnsn #define FAST_DEST 0x000008
5720675068dSalnsn /* Multiple instructions are required. */
5730675068dSalnsn #define SLOW_DEST 0x000010
5740675068dSalnsn /*
5750675068dSalnsn ALT_SIGN_EXT 0x000200
5760675068dSalnsn ALT_SET_FLAGS 0x000400
5770675068dSalnsn ALT_FORM1 0x010000
5780675068dSalnsn ...
579*632be62bSalnsn ALT_FORM7 0x400000 */
5800675068dSalnsn
5810675068dSalnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
5820675068dSalnsn #include "sljitNativePPC_32.c"
5830675068dSalnsn #else
5840675068dSalnsn #include "sljitNativePPC_64.c"
5850675068dSalnsn #endif
5860675068dSalnsn
5870675068dSalnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
5880675068dSalnsn #define STACK_STORE STW
5890675068dSalnsn #define STACK_LOAD LWZ
5900675068dSalnsn #else
5910675068dSalnsn #define STACK_STORE STD
5920675068dSalnsn #define STACK_LOAD LD
5930675068dSalnsn #endif
5940675068dSalnsn
sljit_emit_enter(struct sljit_compiler * compiler,sljit_s32 options,sljit_s32 args,sljit_s32 scratches,sljit_s32 saveds,sljit_s32 fscratches,sljit_s32 fsaveds,sljit_s32 local_size)595dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
596dfd7d8b1Salnsn sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
597dfd7d8b1Salnsn sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
5980675068dSalnsn {
599dfd7d8b1Salnsn sljit_s32 i, tmp, offs;
6000675068dSalnsn
601dfd7d8b1Salnsn CHECK_ERROR();
602dfd7d8b1Salnsn CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
603dfd7d8b1Salnsn set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
6040675068dSalnsn
6050675068dSalnsn FAIL_IF(push_inst(compiler, MFLR | D(0)));
606dfd7d8b1Salnsn offs = -(sljit_s32)(sizeof(sljit_sw));
607dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STACK_STORE | S(TMP_ZERO) | A(SLJIT_SP) | IMM(offs)));
608dfd7d8b1Salnsn
609dfd7d8b1Salnsn tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
610dfd7d8b1Salnsn for (i = SLJIT_S0; i >= tmp; i--) {
611dfd7d8b1Salnsn offs -= (sljit_s32)(sizeof(sljit_sw));
612dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(SLJIT_SP) | IMM(offs)));
613dfd7d8b1Salnsn }
614dfd7d8b1Salnsn
615dfd7d8b1Salnsn for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
616dfd7d8b1Salnsn offs -= (sljit_s32)(sizeof(sljit_sw));
617dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(SLJIT_SP) | IMM(offs)));
618dfd7d8b1Salnsn }
619dfd7d8b1Salnsn
620dfd7d8b1Salnsn SLJIT_ASSERT(offs == -(sljit_s32)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1));
621dfd7d8b1Salnsn
62256b25969Salnsn #if (defined SLJIT_PPC_STACK_FRAME_V2 && SLJIT_PPC_STACK_FRAME_V2)
623dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STACK_STORE | S(0) | A(SLJIT_SP) | IMM(2 * sizeof(sljit_sw))));
6240675068dSalnsn #else
625dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STACK_STORE | S(0) | A(SLJIT_SP) | IMM(sizeof(sljit_sw))));
62656b25969Salnsn #endif
62756b25969Salnsn
62856b25969Salnsn FAIL_IF(push_inst(compiler, ADDI | D(TMP_ZERO) | A(0) | 0));
62956b25969Salnsn if (args >= 1)
630dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(SLJIT_S0) | B(SLJIT_R0)));
63156b25969Salnsn if (args >= 2)
632dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, OR | S(SLJIT_R1) | A(SLJIT_S1) | B(SLJIT_R1)));
63356b25969Salnsn if (args >= 3)
634dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, OR | S(SLJIT_R2) | A(SLJIT_S2) | B(SLJIT_R2)));
63556b25969Salnsn
636dfd7d8b1Salnsn local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1) + SLJIT_LOCALS_OFFSET;
637dfd7d8b1Salnsn local_size = (local_size + 15) & ~0xf;
638dfd7d8b1Salnsn compiler->local_size = local_size;
6390675068dSalnsn
6400675068dSalnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
641dfd7d8b1Salnsn if (local_size <= SIMM_MAX)
642dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STWU | S(SLJIT_SP) | A(SLJIT_SP) | IMM(-local_size)));
6430675068dSalnsn else {
644dfd7d8b1Salnsn FAIL_IF(load_immediate(compiler, 0, -local_size));
645dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STWUX | S(SLJIT_SP) | A(SLJIT_SP) | B(0)));
6460675068dSalnsn }
6470675068dSalnsn #else
648dfd7d8b1Salnsn if (local_size <= SIMM_MAX)
649dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STDU | S(SLJIT_SP) | A(SLJIT_SP) | IMM(-local_size)));
6500675068dSalnsn else {
651dfd7d8b1Salnsn FAIL_IF(load_immediate(compiler, 0, -local_size));
652dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STDUX | S(SLJIT_SP) | A(SLJIT_SP) | B(0)));
6530675068dSalnsn }
6540675068dSalnsn #endif
6550675068dSalnsn
6560675068dSalnsn return SLJIT_SUCCESS;
6570675068dSalnsn }
6580675068dSalnsn
sljit_set_context(struct sljit_compiler * compiler,sljit_s32 options,sljit_s32 args,sljit_s32 scratches,sljit_s32 saveds,sljit_s32 fscratches,sljit_s32 fsaveds,sljit_s32 local_size)659dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
660dfd7d8b1Salnsn sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
661dfd7d8b1Salnsn sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
6620675068dSalnsn {
6630675068dSalnsn CHECK_ERROR();
664dfd7d8b1Salnsn CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
665dfd7d8b1Salnsn set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
666dfd7d8b1Salnsn
667dfd7d8b1Salnsn local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1) + SLJIT_LOCALS_OFFSET;
668dfd7d8b1Salnsn compiler->local_size = (local_size + 15) & ~0xf;
669dfd7d8b1Salnsn return SLJIT_SUCCESS;
670dfd7d8b1Salnsn }
671dfd7d8b1Salnsn
sljit_emit_return(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 src,sljit_sw srcw)672dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
673dfd7d8b1Salnsn {
674dfd7d8b1Salnsn sljit_s32 i, tmp, offs;
675dfd7d8b1Salnsn
676dfd7d8b1Salnsn CHECK_ERROR();
677dfd7d8b1Salnsn CHECK(check_sljit_emit_return(compiler, op, src, srcw));
6780675068dSalnsn
6790675068dSalnsn FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
6800675068dSalnsn
6810675068dSalnsn if (compiler->local_size <= SIMM_MAX)
682dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, ADDI | D(SLJIT_SP) | A(SLJIT_SP) | IMM(compiler->local_size)));
6830675068dSalnsn else {
6840675068dSalnsn FAIL_IF(load_immediate(compiler, 0, compiler->local_size));
685dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, ADD | D(SLJIT_SP) | A(SLJIT_SP) | B(0)));
6860675068dSalnsn }
6870675068dSalnsn
68856b25969Salnsn #if (defined SLJIT_PPC_STACK_FRAME_V2 && SLJIT_PPC_STACK_FRAME_V2)
689dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STACK_LOAD | D(0) | A(SLJIT_SP) | IMM(2 * sizeof(sljit_sw))));
69056b25969Salnsn #else
691dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STACK_LOAD | D(0) | A(SLJIT_SP) | IMM(sizeof(sljit_sw))));
69256b25969Salnsn #endif
693dfd7d8b1Salnsn
694dfd7d8b1Salnsn offs = -(sljit_s32)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1);
695dfd7d8b1Salnsn
696dfd7d8b1Salnsn tmp = compiler->scratches;
697dfd7d8b1Salnsn for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
698dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STACK_LOAD | D(i) | A(SLJIT_SP) | IMM(offs)));
699dfd7d8b1Salnsn offs += (sljit_s32)(sizeof(sljit_sw));
700dfd7d8b1Salnsn }
701dfd7d8b1Salnsn
702dfd7d8b1Salnsn tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
703dfd7d8b1Salnsn for (i = tmp; i <= SLJIT_S0; i++) {
704dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STACK_LOAD | D(i) | A(SLJIT_SP) | IMM(offs)));
705dfd7d8b1Salnsn offs += (sljit_s32)(sizeof(sljit_sw));
706dfd7d8b1Salnsn }
707dfd7d8b1Salnsn
708dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STACK_LOAD | D(TMP_ZERO) | A(SLJIT_SP) | IMM(offs)));
709dfd7d8b1Salnsn SLJIT_ASSERT(offs == -(sljit_sw)(sizeof(sljit_sw)));
7100675068dSalnsn
7110675068dSalnsn FAIL_IF(push_inst(compiler, MTLR | S(0)));
7120675068dSalnsn FAIL_IF(push_inst(compiler, BLR));
7130675068dSalnsn
7140675068dSalnsn return SLJIT_SUCCESS;
7150675068dSalnsn }
7160675068dSalnsn
7170675068dSalnsn #undef STACK_STORE
7180675068dSalnsn #undef STACK_LOAD
7190675068dSalnsn
7200675068dSalnsn /* --------------------------------------------------------------------- */
7210675068dSalnsn /* Operators */
7220675068dSalnsn /* --------------------------------------------------------------------- */
7230675068dSalnsn
7240675068dSalnsn /* i/x - immediate/indexed form
7250675068dSalnsn n/w - no write-back / write-back (1 bit)
7260675068dSalnsn s/l - store/load (1 bit)
7270675068dSalnsn u/s - signed/unsigned (1 bit)
7280675068dSalnsn w/b/h/i - word/byte/half/int allowed (2 bit)
7290675068dSalnsn It contans 32 items, but not all are different. */
7300675068dSalnsn
7310675068dSalnsn /* 64 bit only: [reg+imm] must be aligned to 4 bytes. */
73256b25969Salnsn #define INT_ALIGNED 0x10000
7330675068dSalnsn /* 64-bit only: there is no lwau instruction. */
7340675068dSalnsn #define UPDATE_REQ 0x20000
7350675068dSalnsn
7360675068dSalnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
7374bc045d4Salnsn #define ARCH_32_64(a, b) a
7384bc045d4Salnsn #define INST_CODE_AND_DST(inst, flags, reg) \
7394bc045d4Salnsn ((inst) | (((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg)))
7400675068dSalnsn #else
7414bc045d4Salnsn #define ARCH_32_64(a, b) b
7424bc045d4Salnsn #define INST_CODE_AND_DST(inst, flags, reg) \
74356b25969Salnsn (((inst) & ~(INT_ALIGNED | UPDATE_REQ)) | (((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg)))
7440675068dSalnsn #endif
7450675068dSalnsn
746dfd7d8b1Salnsn static const sljit_ins data_transfer_insts[64 + 8] = {
7470675068dSalnsn
7484bc045d4Salnsn /* -------- Unsigned -------- */
7490675068dSalnsn
7504bc045d4Salnsn /* Word. */
7510675068dSalnsn
75256b25969Salnsn /* u w n i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | INT_ALIGNED | 0x0 /* std */),
75356b25969Salnsn /* u w n i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x0 /* ld */),
7544bc045d4Salnsn /* u w n x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */),
7554bc045d4Salnsn /* u w n x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */),
7560675068dSalnsn
75756b25969Salnsn /* u w w i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | INT_ALIGNED | 0x1 /* stdu */),
75856b25969Salnsn /* u w w i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | 0x1 /* ldu */),
7594bc045d4Salnsn /* u w w x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */),
7604bc045d4Salnsn /* u w w x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */),
7610675068dSalnsn
7624bc045d4Salnsn /* Byte. */
7630675068dSalnsn
7644bc045d4Salnsn /* u b n i s */ HI(38) /* stb */,
7654bc045d4Salnsn /* u b n i l */ HI(34) /* lbz */,
7664bc045d4Salnsn /* u b n x s */ HI(31) | LO(215) /* stbx */,
7674bc045d4Salnsn /* u b n x l */ HI(31) | LO(87) /* lbzx */,
7680675068dSalnsn
7694bc045d4Salnsn /* u b w i s */ HI(39) /* stbu */,
7704bc045d4Salnsn /* u b w i l */ HI(35) /* lbzu */,
7714bc045d4Salnsn /* u b w x s */ HI(31) | LO(247) /* stbux */,
7724bc045d4Salnsn /* u b w x l */ HI(31) | LO(119) /* lbzux */,
7730675068dSalnsn
7744bc045d4Salnsn /* Half. */
7750675068dSalnsn
7764bc045d4Salnsn /* u h n i s */ HI(44) /* sth */,
7774bc045d4Salnsn /* u h n i l */ HI(40) /* lhz */,
7784bc045d4Salnsn /* u h n x s */ HI(31) | LO(407) /* sthx */,
7794bc045d4Salnsn /* u h n x l */ HI(31) | LO(279) /* lhzx */,
7800675068dSalnsn
7814bc045d4Salnsn /* u h w i s */ HI(45) /* sthu */,
7824bc045d4Salnsn /* u h w i l */ HI(41) /* lhzu */,
7834bc045d4Salnsn /* u h w x s */ HI(31) | LO(439) /* sthux */,
7844bc045d4Salnsn /* u h w x l */ HI(31) | LO(311) /* lhzux */,
7850675068dSalnsn
7864bc045d4Salnsn /* Int. */
7870675068dSalnsn
7884bc045d4Salnsn /* u i n i s */ HI(36) /* stw */,
7894bc045d4Salnsn /* u i n i l */ HI(32) /* lwz */,
7904bc045d4Salnsn /* u i n x s */ HI(31) | LO(151) /* stwx */,
7914bc045d4Salnsn /* u i n x l */ HI(31) | LO(23) /* lwzx */,
7920675068dSalnsn
7934bc045d4Salnsn /* u i w i s */ HI(37) /* stwu */,
7944bc045d4Salnsn /* u i w i l */ HI(33) /* lwzu */,
7954bc045d4Salnsn /* u i w x s */ HI(31) | LO(183) /* stwux */,
7964bc045d4Salnsn /* u i w x l */ HI(31) | LO(55) /* lwzux */,
7970675068dSalnsn
7984bc045d4Salnsn /* -------- Signed -------- */
7990675068dSalnsn
8004bc045d4Salnsn /* Word. */
8010675068dSalnsn
80256b25969Salnsn /* s w n i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | INT_ALIGNED | 0x0 /* std */),
80356b25969Salnsn /* s w n i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x0 /* ld */),
8044bc045d4Salnsn /* s w n x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */),
8054bc045d4Salnsn /* s w n x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */),
8060675068dSalnsn
80756b25969Salnsn /* s w w i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | INT_ALIGNED | 0x1 /* stdu */),
80856b25969Salnsn /* s w w i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | 0x1 /* ldu */),
8094bc045d4Salnsn /* s w w x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */),
8104bc045d4Salnsn /* s w w x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */),
8110675068dSalnsn
8124bc045d4Salnsn /* Byte. */
8130675068dSalnsn
8144bc045d4Salnsn /* s b n i s */ HI(38) /* stb */,
8154bc045d4Salnsn /* s b n i l */ HI(34) /* lbz */ /* EXTS_REQ */,
8164bc045d4Salnsn /* s b n x s */ HI(31) | LO(215) /* stbx */,
8174bc045d4Salnsn /* s b n x l */ HI(31) | LO(87) /* lbzx */ /* EXTS_REQ */,
8180675068dSalnsn
8194bc045d4Salnsn /* s b w i s */ HI(39) /* stbu */,
8204bc045d4Salnsn /* s b w i l */ HI(35) /* lbzu */ /* EXTS_REQ */,
8214bc045d4Salnsn /* s b w x s */ HI(31) | LO(247) /* stbux */,
8224bc045d4Salnsn /* s b w x l */ HI(31) | LO(119) /* lbzux */ /* EXTS_REQ */,
8230675068dSalnsn
8244bc045d4Salnsn /* Half. */
8254bc045d4Salnsn
8264bc045d4Salnsn /* s h n i s */ HI(44) /* sth */,
8274bc045d4Salnsn /* s h n i l */ HI(42) /* lha */,
8284bc045d4Salnsn /* s h n x s */ HI(31) | LO(407) /* sthx */,
8294bc045d4Salnsn /* s h n x l */ HI(31) | LO(343) /* lhax */,
8304bc045d4Salnsn
8314bc045d4Salnsn /* s h w i s */ HI(45) /* sthu */,
8324bc045d4Salnsn /* s h w i l */ HI(43) /* lhau */,
8334bc045d4Salnsn /* s h w x s */ HI(31) | LO(439) /* sthux */,
8344bc045d4Salnsn /* s h w x l */ HI(31) | LO(375) /* lhaux */,
8354bc045d4Salnsn
8364bc045d4Salnsn /* Int. */
8374bc045d4Salnsn
8384bc045d4Salnsn /* s i n i s */ HI(36) /* stw */,
83956b25969Salnsn /* s i n i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x2 /* lwa */),
8404bc045d4Salnsn /* s i n x s */ HI(31) | LO(151) /* stwx */,
8414bc045d4Salnsn /* s i n x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(341) /* lwax */),
8424bc045d4Salnsn
8434bc045d4Salnsn /* s i w i s */ HI(37) /* stwu */,
84456b25969Salnsn /* s i w i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | UPDATE_REQ | 0x2 /* lwa */),
8454bc045d4Salnsn /* s i w x s */ HI(31) | LO(183) /* stwux */,
8464bc045d4Salnsn /* s i w x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(373) /* lwaux */),
8474bc045d4Salnsn
8484bc045d4Salnsn /* -------- Double -------- */
8494bc045d4Salnsn
8504bc045d4Salnsn /* d n i s */ HI(54) /* stfd */,
8514bc045d4Salnsn /* d n i l */ HI(50) /* lfd */,
8524bc045d4Salnsn /* d n x s */ HI(31) | LO(727) /* stfdx */,
8534bc045d4Salnsn /* d n x l */ HI(31) | LO(599) /* lfdx */,
8540675068dSalnsn
85556b25969Salnsn /* s n i s */ HI(52) /* stfs */,
85656b25969Salnsn /* s n i l */ HI(48) /* lfs */,
85756b25969Salnsn /* s n x s */ HI(31) | LO(663) /* stfsx */,
85856b25969Salnsn /* s n x l */ HI(31) | LO(535) /* lfsx */,
85956b25969Salnsn
8600675068dSalnsn };
8610675068dSalnsn
8624bc045d4Salnsn #undef ARCH_32_64
8630675068dSalnsn
8640675068dSalnsn /* Simple cases, (no caching is required). */
getput_arg_fast(struct sljit_compiler * compiler,sljit_s32 inp_flags,sljit_s32 reg,sljit_s32 arg,sljit_sw argw)865dfd7d8b1Salnsn static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
8660675068dSalnsn {
8670675068dSalnsn sljit_ins inst;
8680675068dSalnsn
86956b25969Salnsn /* Should work when (arg & REG_MASK) == 0. */
870*632be62bSalnsn SLJIT_ASSERT(A(0) == 0);
8710675068dSalnsn SLJIT_ASSERT(arg & SLJIT_MEM);
8720675068dSalnsn
87356b25969Salnsn if (arg & OFFS_REG_MASK) {
87456b25969Salnsn if (argw & 0x3)
8754bc045d4Salnsn return 0;
8760675068dSalnsn if (inp_flags & ARG_TEST)
8770675068dSalnsn return 1;
8780675068dSalnsn
8790675068dSalnsn inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
88056b25969Salnsn SLJIT_ASSERT(!(inst & (INT_ALIGNED | UPDATE_REQ)));
88156b25969Salnsn FAIL_IF(push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(OFFS_REG(arg))));
8820675068dSalnsn return -1;
8830675068dSalnsn }
88456b25969Salnsn
88556b25969Salnsn if (SLJIT_UNLIKELY(!(arg & REG_MASK)))
88656b25969Salnsn inp_flags &= ~WRITE_BACK;
88756b25969Salnsn
88856b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
88956b25969Salnsn inst = data_transfer_insts[inp_flags & MEM_MASK];
89056b25969Salnsn SLJIT_ASSERT((arg & REG_MASK) || !(inst & UPDATE_REQ));
89156b25969Salnsn
89256b25969Salnsn if (argw > SIMM_MAX || argw < SIMM_MIN || ((inst & INT_ALIGNED) && (argw & 0x3)) || (inst & UPDATE_REQ))
8934bc045d4Salnsn return 0;
89456b25969Salnsn if (inp_flags & ARG_TEST)
89556b25969Salnsn return 1;
89656b25969Salnsn #endif
89756b25969Salnsn
89856b25969Salnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
89956b25969Salnsn if (argw > SIMM_MAX || argw < SIMM_MIN)
90056b25969Salnsn return 0;
90156b25969Salnsn if (inp_flags & ARG_TEST)
90256b25969Salnsn return 1;
90356b25969Salnsn
90456b25969Salnsn inst = data_transfer_insts[inp_flags & MEM_MASK];
90556b25969Salnsn SLJIT_ASSERT(!(inst & (INT_ALIGNED | UPDATE_REQ)));
90656b25969Salnsn #endif
90756b25969Salnsn
90856b25969Salnsn FAIL_IF(push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | IMM(argw)));
90956b25969Salnsn return -1;
9100675068dSalnsn }
9110675068dSalnsn
9120675068dSalnsn /* See getput_arg below.
9130675068dSalnsn Note: can_cache is called only for binary operators. Those operator always
9140675068dSalnsn uses word arguments without write back. */
can_cache(sljit_s32 arg,sljit_sw argw,sljit_s32 next_arg,sljit_sw next_argw)915dfd7d8b1Salnsn static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
9160675068dSalnsn {
91756b25969Salnsn sljit_sw high_short, next_high_short;
91856b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
91956b25969Salnsn sljit_sw diff;
92056b25969Salnsn #endif
92156b25969Salnsn
9224bc045d4Salnsn SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
9230675068dSalnsn
92456b25969Salnsn if (arg & OFFS_REG_MASK)
92556b25969Salnsn return ((arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK) && (argw & 0x3) == (next_argw & 0x3));
9260675068dSalnsn
92756b25969Salnsn if (next_arg & OFFS_REG_MASK)
92856b25969Salnsn return 0;
9290675068dSalnsn
93056b25969Salnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
93156b25969Salnsn high_short = (argw + ((argw & 0x8000) << 1)) & ~0xffff;
93256b25969Salnsn next_high_short = (next_argw + ((next_argw & 0x8000) << 1)) & ~0xffff;
93356b25969Salnsn return high_short == next_high_short;
93456b25969Salnsn #else
93556b25969Salnsn if (argw <= 0x7fffffffl && argw >= -0x80000000l) {
93656b25969Salnsn high_short = (argw + ((argw & 0x8000) << 1)) & ~0xffff;
93756b25969Salnsn next_high_short = (next_argw + ((next_argw & 0x8000) << 1)) & ~0xffff;
93856b25969Salnsn if (high_short == next_high_short)
9390675068dSalnsn return 1;
9400675068dSalnsn }
9410675068dSalnsn
94256b25969Salnsn diff = argw - next_argw;
94356b25969Salnsn if (!(arg & REG_MASK))
94456b25969Salnsn return diff <= SIMM_MAX && diff >= SIMM_MIN;
94556b25969Salnsn
94656b25969Salnsn if (arg == next_arg && diff <= SIMM_MAX && diff >= SIMM_MIN)
9470675068dSalnsn return 1;
9480675068dSalnsn
9490675068dSalnsn return 0;
95056b25969Salnsn #endif
9510675068dSalnsn }
9520675068dSalnsn
9530675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
9540675068dSalnsn #define ADJUST_CACHED_IMM(imm) \
95556b25969Salnsn if ((inst & INT_ALIGNED) && (imm & 0x3)) { \
9560675068dSalnsn /* Adjust cached value. Fortunately this is really a rare case */ \
9570675068dSalnsn compiler->cache_argw += imm & 0x3; \
9580675068dSalnsn FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG3) | A(TMP_REG3) | (imm & 0x3))); \
9590675068dSalnsn imm &= ~0x3; \
9600675068dSalnsn }
9610675068dSalnsn #endif
9620675068dSalnsn
9630675068dSalnsn /* Emit the necessary instructions. See can_cache above. */
getput_arg(struct sljit_compiler * compiler,sljit_s32 inp_flags,sljit_s32 reg,sljit_s32 arg,sljit_sw argw,sljit_s32 next_arg,sljit_sw next_argw)964dfd7d8b1Salnsn static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
9650675068dSalnsn {
966dfd7d8b1Salnsn sljit_s32 tmp_r;
9670675068dSalnsn sljit_ins inst;
96856b25969Salnsn sljit_sw high_short, next_high_short;
96956b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
97056b25969Salnsn sljit_sw diff;
97156b25969Salnsn #endif
9720675068dSalnsn
9730675068dSalnsn SLJIT_ASSERT(arg & SLJIT_MEM);
9740675068dSalnsn
9754bc045d4Salnsn tmp_r = ((inp_flags & LOAD_DATA) && ((inp_flags) & MEM_MASK) <= GPR_REG) ? reg : TMP_REG1;
9764bc045d4Salnsn /* Special case for "mov reg, [reg, ... ]". */
97756b25969Salnsn if ((arg & REG_MASK) == tmp_r)
9784bc045d4Salnsn tmp_r = TMP_REG1;
9790675068dSalnsn
98056b25969Salnsn if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
98156b25969Salnsn argw &= 0x3;
98256b25969Salnsn /* Otherwise getput_arg_fast would capture it. */
98356b25969Salnsn SLJIT_ASSERT(argw);
98456b25969Salnsn
98556b25969Salnsn if ((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg && argw == compiler->cache_argw)
98656b25969Salnsn tmp_r = TMP_REG3;
98756b25969Salnsn else {
98856b25969Salnsn if ((arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK) && argw == (next_argw & 0x3)) {
98956b25969Salnsn compiler->cache_arg = SLJIT_MEM | (arg & OFFS_REG_MASK);
99056b25969Salnsn compiler->cache_argw = argw;
99156b25969Salnsn tmp_r = TMP_REG3;
99256b25969Salnsn }
99356b25969Salnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
99456b25969Salnsn FAIL_IF(push_inst(compiler, RLWINM | S(OFFS_REG(arg)) | A(tmp_r) | (argw << 11) | ((31 - argw) << 1)));
99556b25969Salnsn #else
99656b25969Salnsn FAIL_IF(push_inst(compiler, RLDI(tmp_r, OFFS_REG(arg), argw, 63 - argw, 1)));
99756b25969Salnsn #endif
99856b25969Salnsn }
99956b25969Salnsn inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
100056b25969Salnsn SLJIT_ASSERT(!(inst & (INT_ALIGNED | UPDATE_REQ)));
100156b25969Salnsn return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(tmp_r));
10020675068dSalnsn }
10030675068dSalnsn
100456b25969Salnsn if (SLJIT_UNLIKELY(!(arg & REG_MASK)))
100556b25969Salnsn inp_flags &= ~WRITE_BACK;
100656b25969Salnsn
100756b25969Salnsn inst = data_transfer_insts[inp_flags & MEM_MASK];
100856b25969Salnsn SLJIT_ASSERT((arg & REG_MASK) || !(inst & UPDATE_REQ));
100956b25969Salnsn
101056b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
101156b25969Salnsn if (argw <= 0x7fff7fffl && argw >= -0x80000000l
101256b25969Salnsn && (!(inst & INT_ALIGNED) || !(argw & 0x3)) && !(inst & UPDATE_REQ)) {
101356b25969Salnsn #endif
101456b25969Salnsn
101556b25969Salnsn arg &= REG_MASK;
1016dfd7d8b1Salnsn high_short = (sljit_s32)(argw + ((argw & 0x8000) << 1)) & ~0xffff;
101756b25969Salnsn /* The getput_arg_fast should handle this otherwise. */
101856b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
101956b25969Salnsn SLJIT_ASSERT(high_short && high_short <= 0x7fffffffl && high_short >= -0x80000000l);
102056b25969Salnsn #else
102156b25969Salnsn SLJIT_ASSERT(high_short && !(inst & (INT_ALIGNED | UPDATE_REQ)));
102256b25969Salnsn #endif
102356b25969Salnsn
102456b25969Salnsn if (inp_flags & WRITE_BACK) {
102556b25969Salnsn tmp_r = arg;
102656b25969Salnsn FAIL_IF(push_inst(compiler, ADDIS | D(arg) | A(arg) | IMM(high_short >> 16)));
102756b25969Salnsn }
1028dfd7d8b1Salnsn else if (compiler->cache_arg != (SLJIT_MEM | arg) || high_short != compiler->cache_argw) {
102956b25969Salnsn if ((next_arg & SLJIT_MEM) && !(next_arg & OFFS_REG_MASK)) {
1030dfd7d8b1Salnsn next_high_short = (sljit_s32)(next_argw + ((next_argw & 0x8000) << 1)) & ~0xffff;
103156b25969Salnsn if (high_short == next_high_short) {
1032dfd7d8b1Salnsn compiler->cache_arg = SLJIT_MEM | arg;
1033dfd7d8b1Salnsn compiler->cache_argw = high_short;
103456b25969Salnsn tmp_r = TMP_REG3;
103556b25969Salnsn }
103656b25969Salnsn }
103756b25969Salnsn FAIL_IF(push_inst(compiler, ADDIS | D(tmp_r) | A(arg & REG_MASK) | IMM(high_short >> 16)));
103856b25969Salnsn }
103956b25969Salnsn else
104056b25969Salnsn tmp_r = TMP_REG3;
104156b25969Salnsn
104256b25969Salnsn return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(tmp_r) | IMM(argw));
104356b25969Salnsn
104456b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
104556b25969Salnsn }
104656b25969Salnsn
104756b25969Salnsn /* Everything else is PPC-64 only. */
104856b25969Salnsn if (SLJIT_UNLIKELY(!(arg & REG_MASK))) {
104956b25969Salnsn diff = argw - compiler->cache_argw;
105056b25969Salnsn if ((compiler->cache_arg & SLJIT_IMM) && diff <= SIMM_MAX && diff >= SIMM_MIN) {
105156b25969Salnsn ADJUST_CACHED_IMM(diff);
105256b25969Salnsn return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(TMP_REG3) | IMM(diff));
105356b25969Salnsn }
105456b25969Salnsn
105556b25969Salnsn diff = argw - next_argw;
105656b25969Salnsn if ((next_arg & SLJIT_MEM) && diff <= SIMM_MAX && diff >= SIMM_MIN) {
10570675068dSalnsn SLJIT_ASSERT(inp_flags & LOAD_DATA);
10580675068dSalnsn
10590675068dSalnsn compiler->cache_arg = SLJIT_IMM;
10600675068dSalnsn compiler->cache_argw = argw;
10610675068dSalnsn tmp_r = TMP_REG3;
10620675068dSalnsn }
10630675068dSalnsn
10640675068dSalnsn FAIL_IF(load_immediate(compiler, tmp_r, argw));
10654bc045d4Salnsn return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(tmp_r));
10660675068dSalnsn }
10670675068dSalnsn
106856b25969Salnsn diff = argw - compiler->cache_argw;
106956b25969Salnsn if (compiler->cache_arg == arg && diff <= SIMM_MAX && diff >= SIMM_MIN) {
107056b25969Salnsn SLJIT_ASSERT(!(inp_flags & WRITE_BACK) && !(inst & UPDATE_REQ));
107156b25969Salnsn ADJUST_CACHED_IMM(diff);
107256b25969Salnsn return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(TMP_REG3) | IMM(diff));
107356b25969Salnsn }
10744bc045d4Salnsn
107556b25969Salnsn if ((compiler->cache_arg & SLJIT_IMM) && diff <= SIMM_MAX && diff >= SIMM_MIN) {
107656b25969Salnsn inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
107756b25969Salnsn SLJIT_ASSERT(!(inst & (INT_ALIGNED | UPDATE_REQ)));
107856b25969Salnsn if (compiler->cache_argw != argw) {
107956b25969Salnsn FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG3) | A(TMP_REG3) | IMM(diff)));
10804bc045d4Salnsn compiler->cache_argw = argw;
10814bc045d4Salnsn }
108256b25969Salnsn return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(TMP_REG3));
10830675068dSalnsn }
10840675068dSalnsn
10850675068dSalnsn if (argw == next_argw && (next_arg & SLJIT_MEM)) {
10860675068dSalnsn SLJIT_ASSERT(inp_flags & LOAD_DATA);
10870675068dSalnsn FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
10880675068dSalnsn
10890675068dSalnsn compiler->cache_arg = SLJIT_IMM;
10900675068dSalnsn compiler->cache_argw = argw;
10910675068dSalnsn
10920675068dSalnsn inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
109356b25969Salnsn SLJIT_ASSERT(!(inst & (INT_ALIGNED | UPDATE_REQ)));
109456b25969Salnsn return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(TMP_REG3));
10950675068dSalnsn }
10960675068dSalnsn
109756b25969Salnsn diff = argw - next_argw;
109856b25969Salnsn if (arg == next_arg && !(inp_flags & WRITE_BACK) && diff <= SIMM_MAX && diff >= SIMM_MIN) {
10990675068dSalnsn SLJIT_ASSERT(inp_flags & LOAD_DATA);
11000675068dSalnsn FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
110156b25969Salnsn FAIL_IF(push_inst(compiler, ADD | D(TMP_REG3) | A(TMP_REG3) | B(arg & REG_MASK)));
11020675068dSalnsn
11030675068dSalnsn compiler->cache_arg = arg;
11040675068dSalnsn compiler->cache_argw = argw;
11050675068dSalnsn
11064bc045d4Salnsn return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(TMP_REG3));
11070675068dSalnsn }
11080675068dSalnsn
110956b25969Salnsn if ((next_arg & SLJIT_MEM) && !(next_arg & OFFS_REG_MASK) && diff <= SIMM_MAX && diff >= SIMM_MIN) {
111056b25969Salnsn SLJIT_ASSERT(inp_flags & LOAD_DATA);
111156b25969Salnsn FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
111256b25969Salnsn
111356b25969Salnsn compiler->cache_arg = SLJIT_IMM;
111456b25969Salnsn compiler->cache_argw = argw;
111556b25969Salnsn tmp_r = TMP_REG3;
111656b25969Salnsn }
111756b25969Salnsn else
111856b25969Salnsn FAIL_IF(load_immediate(compiler, tmp_r, argw));
111956b25969Salnsn
11200675068dSalnsn /* Get the indexed version instead of the normal one. */
11210675068dSalnsn inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
112256b25969Salnsn SLJIT_ASSERT(!(inst & (INT_ALIGNED | UPDATE_REQ)));
112356b25969Salnsn return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(tmp_r));
112456b25969Salnsn #endif
11250675068dSalnsn }
11260675068dSalnsn
emit_op_mem2(struct sljit_compiler * compiler,sljit_s32 flags,sljit_s32 reg,sljit_s32 arg1,sljit_sw arg1w,sljit_s32 arg2,sljit_sw arg2w)1127dfd7d8b1Salnsn static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
11284bc045d4Salnsn {
11294bc045d4Salnsn if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
11304bc045d4Salnsn return compiler->error;
11314bc045d4Salnsn return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
11324bc045d4Salnsn }
11334bc045d4Salnsn
emit_op(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 input_flags,sljit_s32 dst,sljit_sw dstw,sljit_s32 src1,sljit_sw src1w,sljit_s32 src2,sljit_sw src2w)1134dfd7d8b1Salnsn static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 input_flags,
1135dfd7d8b1Salnsn sljit_s32 dst, sljit_sw dstw,
1136dfd7d8b1Salnsn sljit_s32 src1, sljit_sw src1w,
1137dfd7d8b1Salnsn sljit_s32 src2, sljit_sw src2w)
11380675068dSalnsn {
11390675068dSalnsn /* arg1 goes to TMP_REG1 or src reg
11400675068dSalnsn arg2 goes to TMP_REG2, imm or src reg
11410675068dSalnsn TMP_REG3 can be used for caching
11420675068dSalnsn result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
1143dfd7d8b1Salnsn sljit_s32 dst_r;
1144dfd7d8b1Salnsn sljit_s32 src1_r;
1145dfd7d8b1Salnsn sljit_s32 src2_r;
1146dfd7d8b1Salnsn sljit_s32 sugg_src2_r = TMP_REG2;
1147*632be62bSalnsn sljit_s32 flags = input_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_FORM6 | ALT_FORM7 | ALT_SIGN_EXT | ALT_SET_FLAGS);
11480675068dSalnsn
114956b25969Salnsn if (!(input_flags & ALT_KEEP_CACHE)) {
11500675068dSalnsn compiler->cache_arg = 0;
11510675068dSalnsn compiler->cache_argw = 0;
115256b25969Salnsn }
11530675068dSalnsn
11540675068dSalnsn /* Destination check. */
115556b25969Salnsn if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
1156dfd7d8b1Salnsn if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32 && !(src2 & SLJIT_MEM))
115756b25969Salnsn return SLJIT_SUCCESS;
115856b25969Salnsn dst_r = TMP_REG2;
115956b25969Salnsn }
116056b25969Salnsn else if (FAST_IS_REG(dst)) {
11610675068dSalnsn dst_r = dst;
11620675068dSalnsn flags |= REG_DEST;
1163dfd7d8b1Salnsn if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
11640675068dSalnsn sugg_src2_r = dst_r;
11650675068dSalnsn }
11660675068dSalnsn else {
11670675068dSalnsn SLJIT_ASSERT(dst & SLJIT_MEM);
11684bc045d4Salnsn if (getput_arg_fast(compiler, input_flags | ARG_TEST, TMP_REG2, dst, dstw)) {
11690675068dSalnsn flags |= FAST_DEST;
11700675068dSalnsn dst_r = TMP_REG2;
11710675068dSalnsn }
11720675068dSalnsn else {
11730675068dSalnsn flags |= SLOW_DEST;
11740675068dSalnsn dst_r = 0;
11750675068dSalnsn }
11760675068dSalnsn }
11770675068dSalnsn
11780675068dSalnsn /* Source 1. */
117956b25969Salnsn if (FAST_IS_REG(src1)) {
11800675068dSalnsn src1_r = src1;
11810675068dSalnsn flags |= REG1_SOURCE;
11820675068dSalnsn }
11830675068dSalnsn else if (src1 & SLJIT_IMM) {
11840675068dSalnsn FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
11850675068dSalnsn src1_r = TMP_REG1;
11860675068dSalnsn }
11874bc045d4Salnsn else if (getput_arg_fast(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w)) {
11880675068dSalnsn FAIL_IF(compiler->error);
11890675068dSalnsn src1_r = TMP_REG1;
11900675068dSalnsn }
11910675068dSalnsn else
11920675068dSalnsn src1_r = 0;
11930675068dSalnsn
11940675068dSalnsn /* Source 2. */
119556b25969Salnsn if (FAST_IS_REG(src2)) {
11960675068dSalnsn src2_r = src2;
11970675068dSalnsn flags |= REG2_SOURCE;
1198dfd7d8b1Salnsn if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
11990675068dSalnsn dst_r = src2_r;
12000675068dSalnsn }
12010675068dSalnsn else if (src2 & SLJIT_IMM) {
12020675068dSalnsn FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w));
12030675068dSalnsn src2_r = sugg_src2_r;
12040675068dSalnsn }
12054bc045d4Salnsn else if (getput_arg_fast(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w)) {
12060675068dSalnsn FAIL_IF(compiler->error);
12070675068dSalnsn src2_r = sugg_src2_r;
12080675068dSalnsn }
12090675068dSalnsn else
12100675068dSalnsn src2_r = 0;
12110675068dSalnsn
12120675068dSalnsn /* src1_r, src2_r and dst_r can be zero (=unprocessed).
12130675068dSalnsn All arguments are complex addressing modes, and it is a binary operator. */
12140675068dSalnsn if (src1_r == 0 && src2_r == 0 && dst_r == 0) {
12150675068dSalnsn if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
12164bc045d4Salnsn FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG2, src2, src2w, src1, src1w));
12174bc045d4Salnsn FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
12180675068dSalnsn }
12190675068dSalnsn else {
12204bc045d4Salnsn FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
12214bc045d4Salnsn FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw));
12220675068dSalnsn }
12230675068dSalnsn src1_r = TMP_REG1;
12240675068dSalnsn src2_r = TMP_REG2;
12250675068dSalnsn }
12260675068dSalnsn else if (src1_r == 0 && src2_r == 0) {
12274bc045d4Salnsn FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
12280675068dSalnsn src1_r = TMP_REG1;
12290675068dSalnsn }
12300675068dSalnsn else if (src1_r == 0 && dst_r == 0) {
12314bc045d4Salnsn FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
12320675068dSalnsn src1_r = TMP_REG1;
12330675068dSalnsn }
12340675068dSalnsn else if (src2_r == 0 && dst_r == 0) {
12354bc045d4Salnsn FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw));
12360675068dSalnsn src2_r = sugg_src2_r;
12370675068dSalnsn }
12380675068dSalnsn
12390675068dSalnsn if (dst_r == 0)
12400675068dSalnsn dst_r = TMP_REG2;
12410675068dSalnsn
12420675068dSalnsn if (src1_r == 0) {
12434bc045d4Salnsn FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, 0, 0));
12440675068dSalnsn src1_r = TMP_REG1;
12450675068dSalnsn }
12460675068dSalnsn
12470675068dSalnsn if (src2_r == 0) {
12484bc045d4Salnsn FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w, 0, 0));
12490675068dSalnsn src2_r = sugg_src2_r;
12500675068dSalnsn }
12510675068dSalnsn
12520675068dSalnsn FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
12530675068dSalnsn
12540675068dSalnsn if (flags & (FAST_DEST | SLOW_DEST)) {
12550675068dSalnsn if (flags & FAST_DEST)
12564bc045d4Salnsn FAIL_IF(getput_arg_fast(compiler, input_flags, dst_r, dst, dstw));
12570675068dSalnsn else
12584bc045d4Salnsn FAIL_IF(getput_arg(compiler, input_flags, dst_r, dst, dstw, 0, 0));
12590675068dSalnsn }
12600675068dSalnsn return SLJIT_SUCCESS;
12610675068dSalnsn }
12620675068dSalnsn
sljit_emit_op0(struct sljit_compiler * compiler,sljit_s32 op)1263dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
12640675068dSalnsn {
126556b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1266dfd7d8b1Salnsn sljit_s32 int_op = op & SLJIT_I32_OP;
126756b25969Salnsn #endif
126856b25969Salnsn
12690675068dSalnsn CHECK_ERROR();
1270dfd7d8b1Salnsn CHECK(check_sljit_emit_op0(compiler, op));
12710675068dSalnsn
127256b25969Salnsn op = GET_OPCODE(op);
127356b25969Salnsn switch (op) {
12740675068dSalnsn case SLJIT_BREAKPOINT:
12750675068dSalnsn case SLJIT_NOP:
12760675068dSalnsn return push_inst(compiler, NOP);
1277dfd7d8b1Salnsn case SLJIT_LMUL_UW:
1278dfd7d8b1Salnsn case SLJIT_LMUL_SW:
1279dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));
12800675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1281dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
1282dfd7d8b1Salnsn return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHDU : MULHD) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
12830675068dSalnsn #else
1284dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
1285dfd7d8b1Salnsn return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHWU : MULHW) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
12860675068dSalnsn #endif
1287dfd7d8b1Salnsn case SLJIT_DIVMOD_UW:
1288dfd7d8b1Salnsn case SLJIT_DIVMOD_SW:
1289dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));
12900675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1291dfd7d8b1Salnsn FAIL_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)));
1292dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, (int_op ? MULLW : MULLD) | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
12930675068dSalnsn #else
1294dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, (op == SLJIT_DIVMOD_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));
1295dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
1296dfd7d8b1Salnsn #endif
1297dfd7d8b1Salnsn return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1));
1298dfd7d8b1Salnsn case SLJIT_DIV_UW:
1299dfd7d8b1Salnsn case SLJIT_DIV_SW:
1300dfd7d8b1Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1301dfd7d8b1Salnsn return 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));
1302dfd7d8b1Salnsn #else
1303dfd7d8b1Salnsn return push_inst(compiler, (op == SLJIT_DIV_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));
13040675068dSalnsn #endif
13050675068dSalnsn }
13060675068dSalnsn
13070675068dSalnsn return SLJIT_SUCCESS;
13080675068dSalnsn }
13090675068dSalnsn
13104bc045d4Salnsn #define EMIT_MOV(type, type_flags, type_cast) \
13114bc045d4Salnsn emit_op(compiler, (src & SLJIT_IMM) ? SLJIT_MOV : type, flags | (type_flags), dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? type_cast srcw : srcw)
13124bc045d4Salnsn
sljit_emit_op1(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 dst,sljit_sw dstw,sljit_s32 src,sljit_sw srcw)1313dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
1314dfd7d8b1Salnsn sljit_s32 dst, sljit_sw dstw,
1315dfd7d8b1Salnsn sljit_s32 src, sljit_sw srcw)
13160675068dSalnsn {
1317*632be62bSalnsn sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;
1318dfd7d8b1Salnsn sljit_s32 op_flags = GET_ALL_FLAGS(op);
13190675068dSalnsn
13200675068dSalnsn CHECK_ERROR();
1321dfd7d8b1Salnsn CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
13220675068dSalnsn ADJUST_LOCAL_OFFSET(dst, dstw);
13230675068dSalnsn ADJUST_LOCAL_OFFSET(src, srcw);
13240675068dSalnsn
132556b25969Salnsn op = GET_OPCODE(op);
132656b25969Salnsn if ((src & SLJIT_IMM) && srcw == 0)
132756b25969Salnsn src = TMP_ZERO;
13280675068dSalnsn
1329*632be62bSalnsn if (GET_FLAG_TYPE(op_flags) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op_flags) == SLJIT_NOT_OVERFLOW)
133056b25969Salnsn FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
133156b25969Salnsn
1332dfd7d8b1Salnsn if (op_flags & SLJIT_I32_OP) {
133356b25969Salnsn if (op < SLJIT_NOT) {
133456b25969Salnsn if (FAST_IS_REG(src) && src == dst) {
133556b25969Salnsn if (!TYPE_CAST_NEEDED(op))
133656b25969Salnsn return SLJIT_SUCCESS;
133756b25969Salnsn }
13380675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1339dfd7d8b1Salnsn if (op == SLJIT_MOV_S32 && (src & SLJIT_MEM))
1340dfd7d8b1Salnsn op = SLJIT_MOV_U32;
1341dfd7d8b1Salnsn if (op == SLJIT_MOVU_S32 && (src & SLJIT_MEM))
1342dfd7d8b1Salnsn op = SLJIT_MOVU_U32;
1343dfd7d8b1Salnsn if (op == SLJIT_MOV_U32 && (src & SLJIT_IMM))
1344dfd7d8b1Salnsn op = SLJIT_MOV_S32;
1345dfd7d8b1Salnsn if (op == SLJIT_MOVU_U32 && (src & SLJIT_IMM))
1346dfd7d8b1Salnsn op = SLJIT_MOVU_S32;
134756b25969Salnsn #endif
134856b25969Salnsn }
134956b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
135056b25969Salnsn else {
135156b25969Salnsn /* Most operations expect sign extended arguments. */
13524bc045d4Salnsn flags |= INT_DATA | SIGNED_DATA;
13530675068dSalnsn if (src & SLJIT_IMM)
1354dfd7d8b1Salnsn srcw = (sljit_s32)srcw;
13550675068dSalnsn }
13560675068dSalnsn #endif
135756b25969Salnsn }
13580675068dSalnsn
135956b25969Salnsn switch (op) {
13600675068dSalnsn case SLJIT_MOV:
136156b25969Salnsn case SLJIT_MOV_P:
136256b25969Salnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
1363dfd7d8b1Salnsn case SLJIT_MOV_U32:
1364dfd7d8b1Salnsn case SLJIT_MOV_S32:
136556b25969Salnsn #endif
13664bc045d4Salnsn return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
13670675068dSalnsn
136856b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1369dfd7d8b1Salnsn case SLJIT_MOV_U32:
1370dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_U32, INT_DATA, (sljit_u32));
13710675068dSalnsn
1372dfd7d8b1Salnsn case SLJIT_MOV_S32:
1373dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, (sljit_s32));
137456b25969Salnsn #endif
13750675068dSalnsn
1376dfd7d8b1Salnsn case SLJIT_MOV_U8:
1377dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_U8, BYTE_DATA, (sljit_u8));
13780675068dSalnsn
1379dfd7d8b1Salnsn case SLJIT_MOV_S8:
1380dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA, (sljit_s8));
13810675068dSalnsn
1382dfd7d8b1Salnsn case SLJIT_MOV_U16:
1383dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_U16, HALF_DATA, (sljit_u16));
13840675068dSalnsn
1385dfd7d8b1Salnsn case SLJIT_MOV_S16:
1386dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, (sljit_s16));
13870675068dSalnsn
13880675068dSalnsn case SLJIT_MOVU:
138956b25969Salnsn case SLJIT_MOVU_P:
139056b25969Salnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
1391dfd7d8b1Salnsn case SLJIT_MOVU_U32:
1392dfd7d8b1Salnsn case SLJIT_MOVU_S32:
139356b25969Salnsn #endif
13944bc045d4Salnsn return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
13950675068dSalnsn
139656b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1397dfd7d8b1Salnsn case SLJIT_MOVU_U32:
1398dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_U32, INT_DATA | WRITE_BACK, (sljit_u32));
13990675068dSalnsn
1400dfd7d8b1Salnsn case SLJIT_MOVU_S32:
1401dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | WRITE_BACK, (sljit_s32));
140256b25969Salnsn #endif
14030675068dSalnsn
1404dfd7d8b1Salnsn case SLJIT_MOVU_U8:
1405dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_U8, BYTE_DATA | WRITE_BACK, (sljit_u8));
14060675068dSalnsn
1407dfd7d8b1Salnsn case SLJIT_MOVU_S8:
1408dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA | WRITE_BACK, (sljit_s8));
14090675068dSalnsn
1410dfd7d8b1Salnsn case SLJIT_MOVU_U16:
1411dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_U16, HALF_DATA | WRITE_BACK, (sljit_u16));
14120675068dSalnsn
1413dfd7d8b1Salnsn case SLJIT_MOVU_S16:
1414dfd7d8b1Salnsn return EMIT_MOV(SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA | WRITE_BACK, (sljit_s16));
14150675068dSalnsn
14160675068dSalnsn case SLJIT_NOT:
14174bc045d4Salnsn return emit_op(compiler, SLJIT_NOT, flags, dst, dstw, TMP_REG1, 0, src, srcw);
14180675068dSalnsn
14190675068dSalnsn case SLJIT_NEG:
14204bc045d4Salnsn return emit_op(compiler, SLJIT_NEG, flags, dst, dstw, TMP_REG1, 0, src, srcw);
14210675068dSalnsn
14220675068dSalnsn case SLJIT_CLZ:
14230675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1424dfd7d8b1Salnsn return emit_op(compiler, SLJIT_CLZ, flags | (!(op_flags & SLJIT_I32_OP) ? 0 : ALT_FORM1), dst, dstw, TMP_REG1, 0, src, srcw);
14250675068dSalnsn #else
14264bc045d4Salnsn return emit_op(compiler, SLJIT_CLZ, flags, dst, dstw, TMP_REG1, 0, src, srcw);
14270675068dSalnsn #endif
14280675068dSalnsn }
14290675068dSalnsn
14300675068dSalnsn return SLJIT_SUCCESS;
14310675068dSalnsn }
14320675068dSalnsn
14334bc045d4Salnsn #undef EMIT_MOV
14344bc045d4Salnsn
14350675068dSalnsn #define TEST_SL_IMM(src, srcw) \
14360675068dSalnsn (((src) & SLJIT_IMM) && (srcw) <= SIMM_MAX && (srcw) >= SIMM_MIN)
14370675068dSalnsn
14380675068dSalnsn #define TEST_UL_IMM(src, srcw) \
14390675068dSalnsn (((src) & SLJIT_IMM) && !((srcw) & ~0xffff))
14400675068dSalnsn
14410675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
14420675068dSalnsn #define TEST_SH_IMM(src, srcw) \
144356b25969Salnsn (((src) & SLJIT_IMM) && !((srcw) & 0xffff) && (srcw) <= 0x7fffffffl && (srcw) >= -0x80000000l)
14440675068dSalnsn #else
14450675068dSalnsn #define TEST_SH_IMM(src, srcw) \
14460675068dSalnsn (((src) & SLJIT_IMM) && !((srcw) & 0xffff))
14470675068dSalnsn #endif
14480675068dSalnsn
14490675068dSalnsn #define TEST_UH_IMM(src, srcw) \
14500675068dSalnsn (((src) & SLJIT_IMM) && !((srcw) & ~0xffff0000))
14510675068dSalnsn
14520675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
14530675068dSalnsn #define TEST_ADD_IMM(src, srcw) \
145456b25969Salnsn (((src) & SLJIT_IMM) && (srcw) <= 0x7fff7fffl && (srcw) >= -0x80000000l)
14550675068dSalnsn #else
14560675068dSalnsn #define TEST_ADD_IMM(src, srcw) \
14570675068dSalnsn ((src) & SLJIT_IMM)
14580675068dSalnsn #endif
14590675068dSalnsn
14600675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
14610675068dSalnsn #define TEST_UI_IMM(src, srcw) \
14620675068dSalnsn (((src) & SLJIT_IMM) && !((srcw) & ~0xffffffff))
14630675068dSalnsn #else
14640675068dSalnsn #define TEST_UI_IMM(src, srcw) \
14650675068dSalnsn ((src) & SLJIT_IMM)
14660675068dSalnsn #endif
14670675068dSalnsn
sljit_emit_op2(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 dst,sljit_sw dstw,sljit_s32 src1,sljit_sw src1w,sljit_s32 src2,sljit_sw src2w)1468dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
1469dfd7d8b1Salnsn sljit_s32 dst, sljit_sw dstw,
1470dfd7d8b1Salnsn sljit_s32 src1, sljit_sw src1w,
1471dfd7d8b1Salnsn sljit_s32 src2, sljit_sw src2w)
14720675068dSalnsn {
1473*632be62bSalnsn sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;
14740675068dSalnsn
14750675068dSalnsn CHECK_ERROR();
1476dfd7d8b1Salnsn CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
14770675068dSalnsn ADJUST_LOCAL_OFFSET(dst, dstw);
14780675068dSalnsn ADJUST_LOCAL_OFFSET(src1, src1w);
14790675068dSalnsn ADJUST_LOCAL_OFFSET(src2, src2w);
14800675068dSalnsn
14810675068dSalnsn if ((src1 & SLJIT_IMM) && src1w == 0)
148256b25969Salnsn src1 = TMP_ZERO;
14830675068dSalnsn if ((src2 & SLJIT_IMM) && src2w == 0)
148456b25969Salnsn src2 = TMP_ZERO;
14850675068dSalnsn
14860675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1487dfd7d8b1Salnsn if (op & SLJIT_I32_OP) {
148856b25969Salnsn /* Most operations expect sign extended arguments. */
14894bc045d4Salnsn flags |= INT_DATA | SIGNED_DATA;
14900675068dSalnsn if (src1 & SLJIT_IMM)
1491dfd7d8b1Salnsn src1w = (sljit_s32)(src1w);
14920675068dSalnsn if (src2 & SLJIT_IMM)
1493dfd7d8b1Salnsn src2w = (sljit_s32)(src2w);
1494*632be62bSalnsn if (HAS_FLAGS(op))
14954bc045d4Salnsn flags |= ALT_SIGN_EXT;
14960675068dSalnsn }
14970675068dSalnsn #endif
1498*632be62bSalnsn if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW)
149956b25969Salnsn FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
150056b25969Salnsn if (src2 == TMP_REG2)
150156b25969Salnsn flags |= ALT_KEEP_CACHE;
15020675068dSalnsn
15030675068dSalnsn switch (GET_OPCODE(op)) {
15040675068dSalnsn case SLJIT_ADD:
1505*632be62bSalnsn if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
15060675068dSalnsn if (TEST_SL_IMM(src2, src2w)) {
15070675068dSalnsn compiler->imm = src2w & 0xffff;
15084bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
15090675068dSalnsn }
15100675068dSalnsn if (TEST_SL_IMM(src1, src1w)) {
15110675068dSalnsn compiler->imm = src1w & 0xffff;
15124bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
15130675068dSalnsn }
15140675068dSalnsn if (TEST_SH_IMM(src2, src2w)) {
15150675068dSalnsn compiler->imm = (src2w >> 16) & 0xffff;
15164bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
15170675068dSalnsn }
15180675068dSalnsn if (TEST_SH_IMM(src1, src1w)) {
15190675068dSalnsn compiler->imm = (src1w >> 16) & 0xffff;
15204bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);
15210675068dSalnsn }
15220675068dSalnsn /* Range between -1 and -32768 is covered above. */
15230675068dSalnsn if (TEST_ADD_IMM(src2, src2w)) {
15240675068dSalnsn compiler->imm = src2w & 0xffffffff;
15254bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
15260675068dSalnsn }
15270675068dSalnsn if (TEST_ADD_IMM(src1, src1w)) {
15280675068dSalnsn compiler->imm = src1w & 0xffffffff;
15294bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);
15300675068dSalnsn }
15310675068dSalnsn }
1532*632be62bSalnsn if (HAS_FLAGS(op)) {
15330675068dSalnsn if (TEST_SL_IMM(src2, src2w)) {
15340675068dSalnsn compiler->imm = src2w & 0xffff;
15354bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
15360675068dSalnsn }
15370675068dSalnsn if (TEST_SL_IMM(src1, src1w)) {
15380675068dSalnsn compiler->imm = src1w & 0xffff;
15394bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
15400675068dSalnsn }
15410675068dSalnsn }
15424bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags, dst, dstw, src1, src1w, src2, src2w);
15430675068dSalnsn
15440675068dSalnsn case SLJIT_ADDC:
1545*632be62bSalnsn return emit_op(compiler, SLJIT_ADDC, flags, dst, dstw, src1, src1w, src2, src2w);
15460675068dSalnsn
15470675068dSalnsn case SLJIT_SUB:
1548*632be62bSalnsn if (GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_LESS_EQUAL)
1549*632be62bSalnsn {
1550*632be62bSalnsn if (dst == SLJIT_UNUSED)
1551*632be62bSalnsn {
1552*632be62bSalnsn if (TEST_UL_IMM(src2, src2w)) {
1553*632be62bSalnsn compiler->imm = src2w & 0xffff;
1554*632be62bSalnsn return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
1555*632be62bSalnsn }
1556*632be62bSalnsn return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM5, dst, dstw, src1, src1w, src2, src2w);
1557*632be62bSalnsn }
1558*632be62bSalnsn
1559*632be62bSalnsn if ((src2 & SLJIT_IMM) && src2w >= 0 && src2w <= (SIMM_MAX + 1))
1560*632be62bSalnsn {
1561*632be62bSalnsn compiler->imm = src2w;
1562*632be62bSalnsn return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM6, dst, dstw, src1, src1w, TMP_REG2, 0);
1563*632be62bSalnsn }
1564*632be62bSalnsn return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM7, dst, dstw, src1, src1w, src2, src2w);
1565*632be62bSalnsn }
1566*632be62bSalnsn
1567*632be62bSalnsn if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
15680675068dSalnsn if (TEST_SL_IMM(src2, -src2w)) {
15690675068dSalnsn compiler->imm = (-src2w) & 0xffff;
15704bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
15710675068dSalnsn }
15720675068dSalnsn if (TEST_SL_IMM(src1, src1w)) {
15730675068dSalnsn compiler->imm = src1w & 0xffff;
15744bc045d4Salnsn return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
15750675068dSalnsn }
15760675068dSalnsn if (TEST_SH_IMM(src2, -src2w)) {
15770675068dSalnsn compiler->imm = ((-src2w) >> 16) & 0xffff;
15784bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
15790675068dSalnsn }
15800675068dSalnsn /* Range between -1 and -32768 is covered above. */
15810675068dSalnsn if (TEST_ADD_IMM(src2, -src2w)) {
15820675068dSalnsn compiler->imm = -src2w & 0xffffffff;
15834bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
15840675068dSalnsn }
15850675068dSalnsn }
1586*632be62bSalnsn
1587*632be62bSalnsn if (dst == SLJIT_UNUSED && GET_FLAG_TYPE(op) != GET_FLAG_TYPE(SLJIT_SET_CARRY)
1588*632be62bSalnsn && GET_FLAG_TYPE(op) == SLJIT_OVERFLOW && GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW) {
15890675068dSalnsn if (TEST_SL_IMM(src2, src2w)) {
15900675068dSalnsn compiler->imm = src2w & 0xffff;
15914bc045d4Salnsn return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
15920675068dSalnsn }
15934bc045d4Salnsn return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
15940675068dSalnsn }
1595*632be62bSalnsn
15960675068dSalnsn if (TEST_SL_IMM(src2, -src2w)) {
15970675068dSalnsn compiler->imm = (-src2w) & 0xffff;
15984bc045d4Salnsn return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
15990675068dSalnsn }
1600dfd7d8b1Salnsn /* We know ALT_SIGN_EXT is set if it is an SLJIT_I32_OP on 64 bit systems. */
1601*632be62bSalnsn return emit_op(compiler, SLJIT_SUB, flags, dst, dstw, src1, src1w, src2, src2w);
16020675068dSalnsn
16030675068dSalnsn case SLJIT_SUBC:
1604*632be62bSalnsn return emit_op(compiler, SLJIT_SUBC, flags, dst, dstw, src1, src1w, src2, src2w);
16050675068dSalnsn
16060675068dSalnsn case SLJIT_MUL:
16070675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1608dfd7d8b1Salnsn if (op & SLJIT_I32_OP)
16094bc045d4Salnsn flags |= ALT_FORM2;
16100675068dSalnsn #endif
1611*632be62bSalnsn if (!HAS_FLAGS(op)) {
16120675068dSalnsn if (TEST_SL_IMM(src2, src2w)) {
16130675068dSalnsn compiler->imm = src2w & 0xffff;
16144bc045d4Salnsn return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
16150675068dSalnsn }
16160675068dSalnsn if (TEST_SL_IMM(src1, src1w)) {
16170675068dSalnsn compiler->imm = src1w & 0xffff;
16184bc045d4Salnsn return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
16190675068dSalnsn }
16200675068dSalnsn }
1621*632be62bSalnsn else
1622*632be62bSalnsn FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
16234bc045d4Salnsn return emit_op(compiler, SLJIT_MUL, flags, dst, dstw, src1, src1w, src2, src2w);
16240675068dSalnsn
16250675068dSalnsn case SLJIT_AND:
16260675068dSalnsn case SLJIT_OR:
16270675068dSalnsn case SLJIT_XOR:
16280675068dSalnsn /* Commutative unsigned operations. */
1629*632be62bSalnsn if (!HAS_FLAGS(op) || GET_OPCODE(op) == SLJIT_AND) {
16300675068dSalnsn if (TEST_UL_IMM(src2, src2w)) {
16310675068dSalnsn compiler->imm = src2w;
16324bc045d4Salnsn return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
16330675068dSalnsn }
16340675068dSalnsn if (TEST_UL_IMM(src1, src1w)) {
16350675068dSalnsn compiler->imm = src1w;
16364bc045d4Salnsn return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
16370675068dSalnsn }
16380675068dSalnsn if (TEST_UH_IMM(src2, src2w)) {
16390675068dSalnsn compiler->imm = (src2w >> 16) & 0xffff;
16404bc045d4Salnsn return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
16410675068dSalnsn }
16420675068dSalnsn if (TEST_UH_IMM(src1, src1w)) {
16430675068dSalnsn compiler->imm = (src1w >> 16) & 0xffff;
16444bc045d4Salnsn return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);
16450675068dSalnsn }
16460675068dSalnsn }
1647*632be62bSalnsn if (GET_OPCODE(op) != SLJIT_AND && GET_OPCODE(op) != SLJIT_AND) {
1648*632be62bSalnsn /* Unlike or and xor, and resets unwanted bits as well. */
16490675068dSalnsn if (TEST_UI_IMM(src2, src2w)) {
16500675068dSalnsn compiler->imm = src2w;
16514bc045d4Salnsn return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
16520675068dSalnsn }
16530675068dSalnsn if (TEST_UI_IMM(src1, src1w)) {
16540675068dSalnsn compiler->imm = src1w;
16554bc045d4Salnsn return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
16560675068dSalnsn }
16570675068dSalnsn }
16584bc045d4Salnsn return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w);
16590675068dSalnsn
16600675068dSalnsn case SLJIT_SHL:
16610675068dSalnsn case SLJIT_LSHR:
1662*632be62bSalnsn case SLJIT_ASHR:
16630675068dSalnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1664dfd7d8b1Salnsn if (op & SLJIT_I32_OP)
16654bc045d4Salnsn flags |= ALT_FORM2;
16660675068dSalnsn #endif
16670675068dSalnsn if (src2 & SLJIT_IMM) {
16680675068dSalnsn compiler->imm = src2w;
16694bc045d4Salnsn return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
16700675068dSalnsn }
16714bc045d4Salnsn return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w);
16720675068dSalnsn }
16730675068dSalnsn
16740675068dSalnsn return SLJIT_SUCCESS;
16750675068dSalnsn }
16760675068dSalnsn
sljit_get_register_index(sljit_s32 reg)1677dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
16780675068dSalnsn {
1679dfd7d8b1Salnsn CHECK_REG_INDEX(check_sljit_get_register_index(reg));
16800675068dSalnsn return reg_map[reg];
16810675068dSalnsn }
16820675068dSalnsn
sljit_get_float_register_index(sljit_s32 reg)1683dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
168456b25969Salnsn {
1685dfd7d8b1Salnsn CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
168656b25969Salnsn return reg;
168756b25969Salnsn }
168856b25969Salnsn
sljit_emit_op_custom(struct sljit_compiler * compiler,void * instruction,sljit_s32 size)1689dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
1690dfd7d8b1Salnsn void *instruction, sljit_s32 size)
16910675068dSalnsn {
16920675068dSalnsn CHECK_ERROR();
1693dfd7d8b1Salnsn CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
16940675068dSalnsn
16950675068dSalnsn return push_inst(compiler, *(sljit_ins*)instruction);
16960675068dSalnsn }
16970675068dSalnsn
16980675068dSalnsn /* --------------------------------------------------------------------- */
16990675068dSalnsn /* Floating point operators */
17000675068dSalnsn /* --------------------------------------------------------------------- */
17010675068dSalnsn
sljit_is_fpu_available(void)1702dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_is_fpu_available(void)
17030675068dSalnsn {
170456b25969Salnsn #ifdef SLJIT_IS_FPU_AVAILABLE
170556b25969Salnsn return SLJIT_IS_FPU_AVAILABLE;
170656b25969Salnsn #else
170756b25969Salnsn /* Available by default. */
17080675068dSalnsn return 1;
170956b25969Salnsn #endif
17100675068dSalnsn }
17110675068dSalnsn
1712dfd7d8b1Salnsn #define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_F32_OP) >> 6))
1713dfd7d8b1Salnsn #define SELECT_FOP(op, single, double) ((op & SLJIT_F32_OP) ? single : double)
171456b25969Salnsn
1715dfd7d8b1Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1716dfd7d8b1Salnsn #define FLOAT_TMP_MEM_OFFSET (6 * sizeof(sljit_sw))
1717dfd7d8b1Salnsn #else
1718dfd7d8b1Salnsn #define FLOAT_TMP_MEM_OFFSET (2 * sizeof(sljit_sw))
1719dfd7d8b1Salnsn
1720dfd7d8b1Salnsn #if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
1721dfd7d8b1Salnsn #define FLOAT_TMP_MEM_OFFSET_LOW (2 * sizeof(sljit_sw))
1722dfd7d8b1Salnsn #define FLOAT_TMP_MEM_OFFSET_HI (3 * sizeof(sljit_sw))
1723dfd7d8b1Salnsn #else
1724dfd7d8b1Salnsn #define FLOAT_TMP_MEM_OFFSET_LOW (3 * sizeof(sljit_sw))
1725dfd7d8b1Salnsn #define FLOAT_TMP_MEM_OFFSET_HI (2 * sizeof(sljit_sw))
1726dfd7d8b1Salnsn #endif
1727dfd7d8b1Salnsn
1728dfd7d8b1Salnsn #endif /* SLJIT_CONFIG_PPC_64 */
1729dfd7d8b1Salnsn
sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 dst,sljit_sw dstw,sljit_s32 src,sljit_sw srcw)1730dfd7d8b1Salnsn static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
1731dfd7d8b1Salnsn sljit_s32 dst, sljit_sw dstw,
1732dfd7d8b1Salnsn sljit_s32 src, sljit_sw srcw)
17330675068dSalnsn {
1734dfd7d8b1Salnsn if (src & SLJIT_MEM) {
1735dfd7d8b1Salnsn /* We can ignore the temporary data store on the stack from caching point of view. */
1736dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, dst, dstw));
1737dfd7d8b1Salnsn src = TMP_FREG1;
1738dfd7d8b1Salnsn }
1739dfd7d8b1Salnsn
1740dfd7d8b1Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1741dfd7d8b1Salnsn op = GET_OPCODE(op);
1742dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, (op == SLJIT_CONV_S32_FROM_F64 ? FCTIWZ : FCTIDZ) | FD(TMP_FREG1) | FB(src)));
1743dfd7d8b1Salnsn
1744dfd7d8b1Salnsn if (dst == SLJIT_UNUSED)
1745dfd7d8b1Salnsn return SLJIT_SUCCESS;
1746dfd7d8b1Salnsn
1747dfd7d8b1Salnsn if (op == SLJIT_CONV_SW_FROM_F64) {
1748dfd7d8b1Salnsn if (FAST_IS_REG(dst)) {
1749dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, 0, 0));
1750dfd7d8b1Salnsn return emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, 0, 0);
1751dfd7d8b1Salnsn }
1752dfd7d8b1Salnsn return emit_op_mem2(compiler, DOUBLE_DATA, TMP_FREG1, dst, dstw, 0, 0);
1753dfd7d8b1Salnsn }
1754dfd7d8b1Salnsn
1755dfd7d8b1Salnsn #else
1756dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, FCTIWZ | FD(TMP_FREG1) | FB(src)));
1757dfd7d8b1Salnsn
1758dfd7d8b1Salnsn if (dst == SLJIT_UNUSED)
1759dfd7d8b1Salnsn return SLJIT_SUCCESS;
1760dfd7d8b1Salnsn #endif
1761dfd7d8b1Salnsn
1762dfd7d8b1Salnsn if (FAST_IS_REG(dst)) {
1763dfd7d8b1Salnsn FAIL_IF(load_immediate(compiler, TMP_REG1, FLOAT_TMP_MEM_OFFSET));
1764dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(SLJIT_SP) | B(TMP_REG1)));
1765dfd7d8b1Salnsn return emit_op_mem2(compiler, INT_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, 0, 0);
1766dfd7d8b1Salnsn }
1767dfd7d8b1Salnsn
1768dfd7d8b1Salnsn SLJIT_ASSERT(dst & SLJIT_MEM);
1769dfd7d8b1Salnsn
1770dfd7d8b1Salnsn if (dst & OFFS_REG_MASK) {
1771dfd7d8b1Salnsn dstw &= 0x3;
1772dfd7d8b1Salnsn if (dstw) {
1773dfd7d8b1Salnsn #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
1774dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, RLWINM | S(OFFS_REG(dst)) | A(TMP_REG1) | (dstw << 11) | ((31 - dstw) << 1)));
1775dfd7d8b1Salnsn #else
1776dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, OFFS_REG(dst), dstw, 63 - dstw, 1)));
1777dfd7d8b1Salnsn #endif
1778dfd7d8b1Salnsn dstw = TMP_REG1;
1779dfd7d8b1Salnsn }
1780dfd7d8b1Salnsn else
1781dfd7d8b1Salnsn dstw = OFFS_REG(dst);
1782dfd7d8b1Salnsn }
1783dfd7d8b1Salnsn else {
1784dfd7d8b1Salnsn if ((dst & REG_MASK) && !dstw) {
1785dfd7d8b1Salnsn dstw = dst & REG_MASK;
1786dfd7d8b1Salnsn dst = 0;
1787dfd7d8b1Salnsn }
1788dfd7d8b1Salnsn else {
1789dfd7d8b1Salnsn /* This works regardless we have SLJIT_MEM1 or SLJIT_MEM0. */
1790dfd7d8b1Salnsn FAIL_IF(load_immediate(compiler, TMP_REG1, dstw));
1791dfd7d8b1Salnsn dstw = TMP_REG1;
1792dfd7d8b1Salnsn }
1793dfd7d8b1Salnsn }
1794dfd7d8b1Salnsn
1795dfd7d8b1Salnsn return push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(dst & REG_MASK) | B(dstw));
1796dfd7d8b1Salnsn }
1797dfd7d8b1Salnsn
sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 dst,sljit_sw dstw,sljit_s32 src,sljit_sw srcw)1798dfd7d8b1Salnsn static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
1799dfd7d8b1Salnsn sljit_s32 dst, sljit_sw dstw,
1800dfd7d8b1Salnsn sljit_s32 src, sljit_sw srcw)
1801dfd7d8b1Salnsn {
1802dfd7d8b1Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1803dfd7d8b1Salnsn
1804dfd7d8b1Salnsn sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
1805dfd7d8b1Salnsn
1806dfd7d8b1Salnsn if (src & SLJIT_IMM) {
1807dfd7d8b1Salnsn if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
1808dfd7d8b1Salnsn srcw = (sljit_s32)srcw;
1809dfd7d8b1Salnsn FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
1810dfd7d8b1Salnsn src = TMP_REG1;
1811dfd7d8b1Salnsn }
1812dfd7d8b1Salnsn else if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) {
1813dfd7d8b1Salnsn if (FAST_IS_REG(src))
1814dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, EXTSW | S(src) | A(TMP_REG1)));
1815dfd7d8b1Salnsn else
1816dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, INT_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET));
1817dfd7d8b1Salnsn src = TMP_REG1;
1818dfd7d8b1Salnsn }
1819dfd7d8b1Salnsn
1820dfd7d8b1Salnsn if (FAST_IS_REG(src)) {
1821dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, WORD_DATA, src, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET));
1822dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, dst, dstw));
1823dfd7d8b1Salnsn }
1824dfd7d8b1Salnsn else
1825dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src, srcw, dst, dstw));
1826dfd7d8b1Salnsn
1827dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
1828dfd7d8b1Salnsn
1829dfd7d8b1Salnsn if (dst & SLJIT_MEM)
1830dfd7d8b1Salnsn return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
1831dfd7d8b1Salnsn if (op & SLJIT_F32_OP)
1832dfd7d8b1Salnsn return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r));
1833dfd7d8b1Salnsn return SLJIT_SUCCESS;
1834dfd7d8b1Salnsn
1835dfd7d8b1Salnsn #else
1836dfd7d8b1Salnsn
1837dfd7d8b1Salnsn sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
1838dfd7d8b1Salnsn sljit_s32 invert_sign = 1;
1839dfd7d8b1Salnsn
1840dfd7d8b1Salnsn if (src & SLJIT_IMM) {
1841dfd7d8b1Salnsn FAIL_IF(load_immediate(compiler, TMP_REG1, srcw ^ 0x80000000));
1842dfd7d8b1Salnsn src = TMP_REG1;
1843dfd7d8b1Salnsn invert_sign = 0;
1844dfd7d8b1Salnsn }
1845dfd7d8b1Salnsn else if (!FAST_IS_REG(src)) {
1846dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW));
1847dfd7d8b1Salnsn src = TMP_REG1;
1848dfd7d8b1Salnsn }
1849dfd7d8b1Salnsn
1850dfd7d8b1Salnsn /* First, a special double floating point value is constructed: (2^53 + (input xor (2^31)))
1851dfd7d8b1Salnsn The double precision format has exactly 53 bit precision, so the lower 32 bit represents
1852dfd7d8b1Salnsn the lower 32 bit of such value. The result of xor 2^31 is the same as adding 0x80000000
1853dfd7d8b1Salnsn to the input, which shifts it into the 0 - 0xffffffff range. To get the converted floating
1854dfd7d8b1Salnsn point value, we need to substract 2^53 + 2^31 from the constructed value. */
1855dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330));
1856dfd7d8b1Salnsn if (invert_sign)
1857dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, XORIS | S(src) | A(TMP_REG1) | 0x8000));
1858dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, WORD_DATA, TMP_REG2, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_HI, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET));
1859dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, WORD_DATA, TMP_REG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_HI));
1860dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG1) | A(0) | 0x8000));
1861dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW));
1862dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, WORD_DATA, TMP_REG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET));
1863dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG2, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW));
1864dfd7d8b1Salnsn
1865dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2)));
1866dfd7d8b1Salnsn
1867dfd7d8b1Salnsn if (dst & SLJIT_MEM)
1868dfd7d8b1Salnsn return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
1869dfd7d8b1Salnsn if (op & SLJIT_F32_OP)
1870dfd7d8b1Salnsn return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r));
1871dfd7d8b1Salnsn return SLJIT_SUCCESS;
1872dfd7d8b1Salnsn
1873dfd7d8b1Salnsn #endif
1874dfd7d8b1Salnsn }
1875dfd7d8b1Salnsn
sljit_emit_fop1_cmp(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 src1,sljit_sw src1w,sljit_s32 src2,sljit_sw src2w)1876dfd7d8b1Salnsn static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
1877dfd7d8b1Salnsn sljit_s32 src1, sljit_sw src1w,
1878dfd7d8b1Salnsn sljit_s32 src2, sljit_sw src2w)
1879dfd7d8b1Salnsn {
1880dfd7d8b1Salnsn if (src1 & SLJIT_MEM) {
1881dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
1882dfd7d8b1Salnsn src1 = TMP_FREG1;
1883dfd7d8b1Salnsn }
1884dfd7d8b1Salnsn
1885dfd7d8b1Salnsn if (src2 & SLJIT_MEM) {
1886dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, 0, 0));
1887dfd7d8b1Salnsn src2 = TMP_FREG2;
1888dfd7d8b1Salnsn }
1889dfd7d8b1Salnsn
1890dfd7d8b1Salnsn return push_inst(compiler, FCMPU | CRD(4) | FA(src1) | FB(src2));
1891dfd7d8b1Salnsn }
1892dfd7d8b1Salnsn
sljit_emit_fop1(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 dst,sljit_sw dstw,sljit_s32 src,sljit_sw srcw)1893dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
1894dfd7d8b1Salnsn sljit_s32 dst, sljit_sw dstw,
1895dfd7d8b1Salnsn sljit_s32 src, sljit_sw srcw)
1896dfd7d8b1Salnsn {
1897dfd7d8b1Salnsn sljit_s32 dst_r;
18980675068dSalnsn
18990675068dSalnsn CHECK_ERROR();
19000675068dSalnsn compiler->cache_arg = 0;
19010675068dSalnsn compiler->cache_argw = 0;
19020675068dSalnsn
1903dfd7d8b1Salnsn SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100) && !(DOUBLE_DATA & 0x4), float_transfer_bit_error);
1904dfd7d8b1Salnsn SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
1905dfd7d8b1Salnsn
1906dfd7d8b1Salnsn if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
1907dfd7d8b1Salnsn op ^= SLJIT_F32_OP;
1908dfd7d8b1Salnsn
1909dfd7d8b1Salnsn dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
19104bc045d4Salnsn
191156b25969Salnsn if (src & SLJIT_MEM) {
1912dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_r, src, srcw, dst, dstw));
1913dfd7d8b1Salnsn src = dst_r;
19140675068dSalnsn }
19150675068dSalnsn
191656b25969Salnsn switch (GET_OPCODE(op)) {
1917dfd7d8b1Salnsn case SLJIT_CONV_F64_FROM_F32:
1918dfd7d8b1Salnsn op ^= SLJIT_F32_OP;
1919dfd7d8b1Salnsn if (op & SLJIT_F32_OP) {
1920dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(src)));
19210675068dSalnsn break;
1922dfd7d8b1Salnsn }
1923dfd7d8b1Salnsn /* Fall through. */
1924dfd7d8b1Salnsn case SLJIT_MOV_F64:
1925dfd7d8b1Salnsn if (src != dst_r) {
1926dfd7d8b1Salnsn if (dst_r != TMP_FREG1)
1927dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, FMR | FD(dst_r) | FB(src)));
1928dfd7d8b1Salnsn else
1929dfd7d8b1Salnsn dst_r = src;
1930dfd7d8b1Salnsn }
19310675068dSalnsn break;
1932dfd7d8b1Salnsn case SLJIT_NEG_F64:
1933dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, FNEG | FD(dst_r) | FB(src)));
1934dfd7d8b1Salnsn break;
1935dfd7d8b1Salnsn case SLJIT_ABS_F64:
1936dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, FABS | FD(dst_r) | FB(src)));
19370675068dSalnsn break;
19380675068dSalnsn }
19390675068dSalnsn
1940dfd7d8b1Salnsn if (dst & SLJIT_MEM)
1941dfd7d8b1Salnsn FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), dst_r, dst, dstw, 0, 0));
19420675068dSalnsn return SLJIT_SUCCESS;
19430675068dSalnsn }
19440675068dSalnsn
sljit_emit_fop2(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 dst,sljit_sw dstw,sljit_s32 src1,sljit_sw src1w,sljit_s32 src2,sljit_sw src2w)1945dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
1946dfd7d8b1Salnsn sljit_s32 dst, sljit_sw dstw,
1947dfd7d8b1Salnsn sljit_s32 src1, sljit_sw src1w,
1948dfd7d8b1Salnsn sljit_s32 src2, sljit_sw src2w)
19490675068dSalnsn {
1950dfd7d8b1Salnsn sljit_s32 dst_r, flags = 0;
19510675068dSalnsn
19520675068dSalnsn CHECK_ERROR();
1953dfd7d8b1Salnsn CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
1954dfd7d8b1Salnsn ADJUST_LOCAL_OFFSET(dst, dstw);
1955dfd7d8b1Salnsn ADJUST_LOCAL_OFFSET(src1, src1w);
1956dfd7d8b1Salnsn ADJUST_LOCAL_OFFSET(src2, src2w);
19570675068dSalnsn
19580675068dSalnsn compiler->cache_arg = 0;
19590675068dSalnsn compiler->cache_argw = 0;
19600675068dSalnsn
1961dfd7d8b1Salnsn dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2;
19620675068dSalnsn
196356b25969Salnsn if (src1 & SLJIT_MEM) {
196456b25969Salnsn if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w)) {
19654bc045d4Salnsn FAIL_IF(compiler->error);
19660675068dSalnsn src1 = TMP_FREG1;
19674bc045d4Salnsn } else
19684bc045d4Salnsn flags |= ALT_FORM1;
19690675068dSalnsn }
19700675068dSalnsn
197156b25969Salnsn if (src2 & SLJIT_MEM) {
197256b25969Salnsn if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w)) {
19734bc045d4Salnsn FAIL_IF(compiler->error);
19744bc045d4Salnsn src2 = TMP_FREG2;
19754bc045d4Salnsn } else
19764bc045d4Salnsn flags |= ALT_FORM2;
19774bc045d4Salnsn }
19784bc045d4Salnsn
19794bc045d4Salnsn if ((flags & (ALT_FORM1 | ALT_FORM2)) == (ALT_FORM1 | ALT_FORM2)) {
19804bc045d4Salnsn if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
198156b25969Salnsn FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, src1, src1w));
198256b25969Salnsn FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
19834bc045d4Salnsn }
19844bc045d4Salnsn else {
198556b25969Salnsn FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
198656b25969Salnsn FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
19874bc045d4Salnsn }
19884bc045d4Salnsn }
19894bc045d4Salnsn else if (flags & ALT_FORM1)
199056b25969Salnsn FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
19914bc045d4Salnsn else if (flags & ALT_FORM2)
199256b25969Salnsn FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
19934bc045d4Salnsn
19944bc045d4Salnsn if (flags & ALT_FORM1)
19954bc045d4Salnsn src1 = TMP_FREG1;
19964bc045d4Salnsn if (flags & ALT_FORM2)
19974bc045d4Salnsn src2 = TMP_FREG2;
19984bc045d4Salnsn
199956b25969Salnsn switch (GET_OPCODE(op)) {
2000dfd7d8b1Salnsn case SLJIT_ADD_F64:
2001dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADD) | FD(dst_r) | FA(src1) | FB(src2)));
20020675068dSalnsn break;
20030675068dSalnsn
2004dfd7d8b1Salnsn case SLJIT_SUB_F64:
2005dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUB) | FD(dst_r) | FA(src1) | FB(src2)));
20060675068dSalnsn break;
20070675068dSalnsn
2008dfd7d8b1Salnsn case SLJIT_MUL_F64:
2009dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMUL) | FD(dst_r) | FA(src1) | FC(src2) /* FMUL use FC as src2 */));
20100675068dSalnsn break;
20110675068dSalnsn
2012dfd7d8b1Salnsn case SLJIT_DIV_F64:
2013dfd7d8b1Salnsn FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIV) | FD(dst_r) | FA(src1) | FB(src2)));
20140675068dSalnsn break;
20150675068dSalnsn }
20160675068dSalnsn
2017dfd7d8b1Salnsn if (dst_r == TMP_FREG2)
201856b25969Salnsn FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0));
20190675068dSalnsn
20200675068dSalnsn return SLJIT_SUCCESS;
20210675068dSalnsn }
20220675068dSalnsn
202356b25969Salnsn #undef FLOAT_DATA
202456b25969Salnsn #undef SELECT_FOP
202556b25969Salnsn
20260675068dSalnsn /* --------------------------------------------------------------------- */
20270675068dSalnsn /* Other instructions */
20280675068dSalnsn /* --------------------------------------------------------------------- */
20290675068dSalnsn
sljit_emit_fast_enter(struct sljit_compiler * compiler,sljit_s32 dst,sljit_sw dstw)2030dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
20310675068dSalnsn {
20320675068dSalnsn CHECK_ERROR();
2033dfd7d8b1Salnsn CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
20340675068dSalnsn ADJUST_LOCAL_OFFSET(dst, dstw);
20350675068dSalnsn
203656b25969Salnsn /* For UNUSED dst. Uncommon, but possible. */
203756b25969Salnsn if (dst == SLJIT_UNUSED)
203856b25969Salnsn return SLJIT_SUCCESS;
203956b25969Salnsn
204056b25969Salnsn if (FAST_IS_REG(dst))
20410675068dSalnsn return push_inst(compiler, MFLR | D(dst));
204256b25969Salnsn
204356b25969Salnsn /* Memory. */
20440675068dSalnsn FAIL_IF(push_inst(compiler, MFLR | D(TMP_REG2)));
20450675068dSalnsn return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
20460675068dSalnsn }
20470675068dSalnsn
sljit_emit_fast_return(struct sljit_compiler * compiler,sljit_s32 src,sljit_sw srcw)2048dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
20490675068dSalnsn {
20500675068dSalnsn CHECK_ERROR();
2051dfd7d8b1Salnsn CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
20520675068dSalnsn ADJUST_LOCAL_OFFSET(src, srcw);
20530675068dSalnsn
205456b25969Salnsn if (FAST_IS_REG(src))
20550675068dSalnsn FAIL_IF(push_inst(compiler, MTLR | S(src)));
20560675068dSalnsn else {
20570675068dSalnsn if (src & SLJIT_MEM)
20580675068dSalnsn FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_REG2, 0, TMP_REG1, 0, src, srcw));
20590675068dSalnsn else if (src & SLJIT_IMM)
20600675068dSalnsn FAIL_IF(load_immediate(compiler, TMP_REG2, srcw));
20610675068dSalnsn FAIL_IF(push_inst(compiler, MTLR | S(TMP_REG2)));
20620675068dSalnsn }
20630675068dSalnsn return push_inst(compiler, BLR);
20640675068dSalnsn }
20650675068dSalnsn
20660675068dSalnsn /* --------------------------------------------------------------------- */
20670675068dSalnsn /* Conditional instructions */
20680675068dSalnsn /* --------------------------------------------------------------------- */
20690675068dSalnsn
sljit_emit_label(struct sljit_compiler * compiler)20700675068dSalnsn SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
20710675068dSalnsn {
20720675068dSalnsn struct sljit_label *label;
20730675068dSalnsn
20740675068dSalnsn CHECK_ERROR_PTR();
2075dfd7d8b1Salnsn CHECK_PTR(check_sljit_emit_label(compiler));
20760675068dSalnsn
20770675068dSalnsn if (compiler->last_label && compiler->last_label->size == compiler->size)
20780675068dSalnsn return compiler->last_label;
20790675068dSalnsn
20800675068dSalnsn label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
20810675068dSalnsn PTR_FAIL_IF(!label);
20820675068dSalnsn set_label(label, compiler);
20830675068dSalnsn return label;
20840675068dSalnsn }
20850675068dSalnsn
get_bo_bi_flags(sljit_s32 type)2086dfd7d8b1Salnsn static sljit_ins get_bo_bi_flags(sljit_s32 type)
20870675068dSalnsn {
20880675068dSalnsn switch (type) {
2089dfd7d8b1Salnsn case SLJIT_EQUAL:
20900675068dSalnsn return (12 << 21) | (2 << 16);
20910675068dSalnsn
2092dfd7d8b1Salnsn case SLJIT_NOT_EQUAL:
20930675068dSalnsn return (4 << 21) | (2 << 16);
20940675068dSalnsn
2095dfd7d8b1Salnsn case SLJIT_LESS:
2096dfd7d8b1Salnsn case SLJIT_SIG_LESS:
20970675068dSalnsn return (12 << 21) | (0 << 16);
20980675068dSalnsn
2099*632be62bSalnsn case SLJIT_GREATER_EQUAL:
2100dfd7d8b1Salnsn case SLJIT_SIG_GREATER_EQUAL:
21010675068dSalnsn return (4 << 21) | (0 << 16);
21020675068dSalnsn
2103*632be62bSalnsn case SLJIT_GREATER:
2104dfd7d8b1Salnsn case SLJIT_SIG_GREATER:
21050675068dSalnsn return (12 << 21) | (1 << 16);
21060675068dSalnsn
2107*632be62bSalnsn case SLJIT_LESS_EQUAL:
2108dfd7d8b1Salnsn case SLJIT_SIG_LESS_EQUAL:
21090675068dSalnsn return (4 << 21) | (1 << 16);
21100675068dSalnsn
2111*632be62bSalnsn case SLJIT_LESS_F64:
2112*632be62bSalnsn return (12 << 21) | ((4 + 0) << 16);
2113*632be62bSalnsn
2114*632be62bSalnsn case SLJIT_GREATER_EQUAL_F64:
2115*632be62bSalnsn return (4 << 21) | ((4 + 0) << 16);
2116*632be62bSalnsn
2117*632be62bSalnsn case SLJIT_GREATER_F64:
2118*632be62bSalnsn return (12 << 21) | ((4 + 1) << 16);
2119*632be62bSalnsn
2120*632be62bSalnsn case SLJIT_LESS_EQUAL_F64:
2121*632be62bSalnsn return (4 << 21) | ((4 + 1) << 16);
2122*632be62bSalnsn
2123dfd7d8b1Salnsn case SLJIT_OVERFLOW:
2124dfd7d8b1Salnsn case SLJIT_MUL_OVERFLOW:
21250675068dSalnsn return (12 << 21) | (3 << 16);
21260675068dSalnsn
2127dfd7d8b1Salnsn case SLJIT_NOT_OVERFLOW:
2128dfd7d8b1Salnsn case SLJIT_MUL_NOT_OVERFLOW:
21290675068dSalnsn return (4 << 21) | (3 << 16);
21300675068dSalnsn
2131dfd7d8b1Salnsn case SLJIT_EQUAL_F64:
21320675068dSalnsn return (12 << 21) | ((4 + 2) << 16);
21330675068dSalnsn
2134dfd7d8b1Salnsn case SLJIT_NOT_EQUAL_F64:
21350675068dSalnsn return (4 << 21) | ((4 + 2) << 16);
21360675068dSalnsn
2137dfd7d8b1Salnsn case SLJIT_UNORDERED_F64:
21380675068dSalnsn return (12 << 21) | ((4 + 3) << 16);
21390675068dSalnsn
2140dfd7d8b1Salnsn case SLJIT_ORDERED_F64:
21410675068dSalnsn return (4 << 21) | ((4 + 3) << 16);
21420675068dSalnsn
21430675068dSalnsn default:
21440675068dSalnsn SLJIT_ASSERT(type >= SLJIT_JUMP && type <= SLJIT_CALL3);
21450675068dSalnsn return (20 << 21);
21460675068dSalnsn }
21470675068dSalnsn }
21480675068dSalnsn
sljit_emit_jump(struct sljit_compiler * compiler,sljit_s32 type)2149dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
21500675068dSalnsn {
21510675068dSalnsn struct sljit_jump *jump;
21520675068dSalnsn sljit_ins bo_bi_flags;
21530675068dSalnsn
21540675068dSalnsn CHECK_ERROR_PTR();
2155dfd7d8b1Salnsn CHECK_PTR(check_sljit_emit_jump(compiler, type));
21560675068dSalnsn
21574bc045d4Salnsn bo_bi_flags = get_bo_bi_flags(type & 0xff);
21580675068dSalnsn if (!bo_bi_flags)
21590675068dSalnsn return NULL;
21600675068dSalnsn
21610675068dSalnsn jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
21620675068dSalnsn PTR_FAIL_IF(!jump);
21630675068dSalnsn set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
21640675068dSalnsn type &= 0xff;
21650675068dSalnsn
21660675068dSalnsn /* In PPC, we don't need to touch the arguments. */
216756b25969Salnsn if (type < SLJIT_JUMP)
216856b25969Salnsn jump->flags |= IS_COND;
216956b25969Salnsn #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
217056b25969Salnsn if (type >= SLJIT_CALL0)
217156b25969Salnsn jump->flags |= IS_CALL;
217256b25969Salnsn #endif
21730675068dSalnsn
217456b25969Salnsn PTR_FAIL_IF(emit_const(compiler, TMP_CALL_REG, 0));
217556b25969Salnsn PTR_FAIL_IF(push_inst(compiler, MTCTR | S(TMP_CALL_REG)));
21760675068dSalnsn jump->addr = compiler->size;
21770675068dSalnsn PTR_FAIL_IF(push_inst(compiler, BCCTR | bo_bi_flags | (type >= SLJIT_FAST_CALL ? 1 : 0)));
21780675068dSalnsn return jump;
21790675068dSalnsn }
21800675068dSalnsn
sljit_emit_ijump(struct sljit_compiler * compiler,sljit_s32 type,sljit_s32 src,sljit_sw srcw)2181dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
21820675068dSalnsn {
21830675068dSalnsn struct sljit_jump *jump = NULL;
2184dfd7d8b1Salnsn sljit_s32 src_r;
21850675068dSalnsn
21860675068dSalnsn CHECK_ERROR();
2187dfd7d8b1Salnsn CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
21880675068dSalnsn ADJUST_LOCAL_OFFSET(src, srcw);
21890675068dSalnsn
219056b25969Salnsn if (FAST_IS_REG(src)) {
219156b25969Salnsn #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
219256b25969Salnsn if (type >= SLJIT_CALL0) {
219356b25969Salnsn FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src)));
219456b25969Salnsn src_r = TMP_CALL_REG;
219556b25969Salnsn }
219656b25969Salnsn else
21970675068dSalnsn src_r = src;
219856b25969Salnsn #else
219956b25969Salnsn src_r = src;
220056b25969Salnsn #endif
220156b25969Salnsn } else if (src & SLJIT_IMM) {
22020675068dSalnsn jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
22030675068dSalnsn FAIL_IF(!jump);
220456b25969Salnsn set_jump(jump, compiler, JUMP_ADDR);
22050675068dSalnsn jump->u.target = srcw;
220656b25969Salnsn #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
220756b25969Salnsn if (type >= SLJIT_CALL0)
220856b25969Salnsn jump->flags |= IS_CALL;
220956b25969Salnsn #endif
221056b25969Salnsn FAIL_IF(emit_const(compiler, TMP_CALL_REG, 0));
221156b25969Salnsn src_r = TMP_CALL_REG;
22120675068dSalnsn }
22130675068dSalnsn else {
221456b25969Salnsn FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_CALL_REG, 0, TMP_REG1, 0, src, srcw));
221556b25969Salnsn src_r = TMP_CALL_REG;
22160675068dSalnsn }
22170675068dSalnsn
22180675068dSalnsn FAIL_IF(push_inst(compiler, MTCTR | S(src_r)));
22190675068dSalnsn if (jump)
22200675068dSalnsn jump->addr = compiler->size;
22214bc045d4Salnsn return push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0));
22220675068dSalnsn }
22230675068dSalnsn
22240675068dSalnsn /* Get a bit from CR, all other bits are zeroed. */
22250675068dSalnsn #define GET_CR_BIT(bit, dst) \
22260675068dSalnsn FAIL_IF(push_inst(compiler, RLWINM | S(dst) | A(dst) | ((1 + (bit)) << 11) | (31 << 6) | (31 << 1)));
22270675068dSalnsn
22280675068dSalnsn #define INVERT_BIT(dst) \
22290675068dSalnsn FAIL_IF(push_inst(compiler, XORI | S(dst) | A(dst) | 0x1));
22300675068dSalnsn
sljit_emit_op_flags(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 dst,sljit_sw dstw,sljit_s32 src,sljit_sw srcw,sljit_s32 type)2231dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
2232dfd7d8b1Salnsn sljit_s32 dst, sljit_sw dstw,
2233dfd7d8b1Salnsn sljit_s32 src, sljit_sw srcw,
2234dfd7d8b1Salnsn sljit_s32 type)
22350675068dSalnsn {
2236dfd7d8b1Salnsn sljit_s32 reg, input_flags;
2237dfd7d8b1Salnsn sljit_s32 flags = GET_ALL_FLAGS(op);
223856b25969Salnsn sljit_sw original_dstw = dstw;
22390675068dSalnsn
22400675068dSalnsn CHECK_ERROR();
2241dfd7d8b1Salnsn CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type));
22420675068dSalnsn ADJUST_LOCAL_OFFSET(dst, dstw);
22430675068dSalnsn
22440675068dSalnsn if (dst == SLJIT_UNUSED)
22450675068dSalnsn return SLJIT_SUCCESS;
22460675068dSalnsn
224756b25969Salnsn op = GET_OPCODE(op);
224856b25969Salnsn reg = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;
224956b25969Salnsn
225056b25969Salnsn compiler->cache_arg = 0;
225156b25969Salnsn compiler->cache_argw = 0;
225256b25969Salnsn if (op >= SLJIT_ADD && (src & SLJIT_MEM)) {
225356b25969Salnsn ADJUST_LOCAL_OFFSET(src, srcw);
225456b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
2255dfd7d8b1Salnsn input_flags = (flags & SLJIT_I32_OP) ? INT_DATA : WORD_DATA;
225656b25969Salnsn #else
225756b25969Salnsn input_flags = WORD_DATA;
225856b25969Salnsn #endif
225956b25969Salnsn FAIL_IF(emit_op_mem2(compiler, input_flags | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
226056b25969Salnsn src = TMP_REG1;
226156b25969Salnsn srcw = 0;
226256b25969Salnsn }
22630675068dSalnsn
2264*632be62bSalnsn FAIL_IF(push_inst(compiler, MFCR | D(reg)));
2265*632be62bSalnsn
2266dfd7d8b1Salnsn switch (type & 0xff) {
2267dfd7d8b1Salnsn case SLJIT_EQUAL:
22680675068dSalnsn GET_CR_BIT(2, reg);
22690675068dSalnsn break;
22700675068dSalnsn
2271dfd7d8b1Salnsn case SLJIT_NOT_EQUAL:
22720675068dSalnsn GET_CR_BIT(2, reg);
22730675068dSalnsn INVERT_BIT(reg);
22740675068dSalnsn break;
22750675068dSalnsn
2276dfd7d8b1Salnsn case SLJIT_LESS:
2277dfd7d8b1Salnsn case SLJIT_SIG_LESS:
22780675068dSalnsn GET_CR_BIT(0, reg);
22790675068dSalnsn break;
22800675068dSalnsn
2281*632be62bSalnsn case SLJIT_GREATER_EQUAL:
2282dfd7d8b1Salnsn case SLJIT_SIG_GREATER_EQUAL:
22830675068dSalnsn GET_CR_BIT(0, reg);
22840675068dSalnsn INVERT_BIT(reg);
22850675068dSalnsn break;
22860675068dSalnsn
2287*632be62bSalnsn case SLJIT_GREATER:
2288dfd7d8b1Salnsn case SLJIT_SIG_GREATER:
22890675068dSalnsn GET_CR_BIT(1, reg);
22900675068dSalnsn break;
22910675068dSalnsn
2292*632be62bSalnsn case SLJIT_LESS_EQUAL:
2293dfd7d8b1Salnsn case SLJIT_SIG_LESS_EQUAL:
22940675068dSalnsn GET_CR_BIT(1, reg);
22950675068dSalnsn INVERT_BIT(reg);
22960675068dSalnsn break;
22970675068dSalnsn
2298*632be62bSalnsn case SLJIT_LESS_F64:
2299*632be62bSalnsn GET_CR_BIT(4 + 0, reg);
2300*632be62bSalnsn break;
2301*632be62bSalnsn
2302*632be62bSalnsn case SLJIT_GREATER_EQUAL_F64:
2303*632be62bSalnsn GET_CR_BIT(4 + 0, reg);
2304*632be62bSalnsn INVERT_BIT(reg);
2305*632be62bSalnsn break;
2306*632be62bSalnsn
2307*632be62bSalnsn case SLJIT_GREATER_F64:
2308*632be62bSalnsn GET_CR_BIT(4 + 1, reg);
2309*632be62bSalnsn break;
2310*632be62bSalnsn
2311*632be62bSalnsn case SLJIT_LESS_EQUAL_F64:
2312*632be62bSalnsn GET_CR_BIT(4 + 1, reg);
2313*632be62bSalnsn INVERT_BIT(reg);
2314*632be62bSalnsn break;
2315*632be62bSalnsn
2316dfd7d8b1Salnsn case SLJIT_OVERFLOW:
2317dfd7d8b1Salnsn case SLJIT_MUL_OVERFLOW:
23180675068dSalnsn GET_CR_BIT(3, reg);
23190675068dSalnsn break;
23200675068dSalnsn
2321dfd7d8b1Salnsn case SLJIT_NOT_OVERFLOW:
2322dfd7d8b1Salnsn case SLJIT_MUL_NOT_OVERFLOW:
23230675068dSalnsn GET_CR_BIT(3, reg);
23240675068dSalnsn INVERT_BIT(reg);
23250675068dSalnsn break;
23260675068dSalnsn
2327dfd7d8b1Salnsn case SLJIT_EQUAL_F64:
23280675068dSalnsn GET_CR_BIT(4 + 2, reg);
23290675068dSalnsn break;
23300675068dSalnsn
2331dfd7d8b1Salnsn case SLJIT_NOT_EQUAL_F64:
23320675068dSalnsn GET_CR_BIT(4 + 2, reg);
23330675068dSalnsn INVERT_BIT(reg);
23340675068dSalnsn break;
23350675068dSalnsn
2336dfd7d8b1Salnsn case SLJIT_UNORDERED_F64:
23370675068dSalnsn GET_CR_BIT(4 + 3, reg);
23380675068dSalnsn break;
23390675068dSalnsn
2340dfd7d8b1Salnsn case SLJIT_ORDERED_F64:
23410675068dSalnsn GET_CR_BIT(4 + 3, reg);
23420675068dSalnsn INVERT_BIT(reg);
23430675068dSalnsn break;
23440675068dSalnsn
23450675068dSalnsn default:
2346*632be62bSalnsn SLJIT_UNREACHABLE();
23470675068dSalnsn break;
23480675068dSalnsn }
23490675068dSalnsn
235056b25969Salnsn if (op < SLJIT_ADD) {
235156b25969Salnsn #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
235256b25969Salnsn if (op == SLJIT_MOV)
235356b25969Salnsn input_flags = WORD_DATA;
235456b25969Salnsn else {
2355dfd7d8b1Salnsn op = SLJIT_MOV_U32;
235656b25969Salnsn input_flags = INT_DATA;
235756b25969Salnsn }
235856b25969Salnsn #else
235956b25969Salnsn op = SLJIT_MOV;
236056b25969Salnsn input_flags = WORD_DATA;
236156b25969Salnsn #endif
236256b25969Salnsn if (reg != TMP_REG2)
236356b25969Salnsn return SLJIT_SUCCESS;
236456b25969Salnsn return emit_op(compiler, op, input_flags, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
23650675068dSalnsn }
23660675068dSalnsn
2367dfd7d8b1Salnsn #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
2368dfd7d8b1Salnsn || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
236956b25969Salnsn compiler->skip_checks = 1;
237056b25969Salnsn #endif
237156b25969Salnsn return sljit_emit_op2(compiler, op | flags, dst, original_dstw, src, srcw, TMP_REG2, 0);
237256b25969Salnsn }
237356b25969Salnsn
sljit_emit_const(struct sljit_compiler * compiler,sljit_s32 dst,sljit_sw dstw,sljit_sw init_value)2374dfd7d8b1Salnsn SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
23750675068dSalnsn {
23760675068dSalnsn struct sljit_const *const_;
2377dfd7d8b1Salnsn sljit_s32 reg;
23780675068dSalnsn
23790675068dSalnsn CHECK_ERROR_PTR();
2380dfd7d8b1Salnsn CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
23810675068dSalnsn ADJUST_LOCAL_OFFSET(dst, dstw);
23820675068dSalnsn
23830675068dSalnsn const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
23840675068dSalnsn PTR_FAIL_IF(!const_);
23850675068dSalnsn set_const(const_, compiler);
23860675068dSalnsn
238756b25969Salnsn reg = SLOW_IS_REG(dst) ? dst : TMP_REG2;
23880675068dSalnsn
23890675068dSalnsn PTR_FAIL_IF(emit_const(compiler, reg, init_value));
23900675068dSalnsn
23910675068dSalnsn if (dst & SLJIT_MEM)
23920675068dSalnsn PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
23930675068dSalnsn return const_;
23940675068dSalnsn }
2395