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