blob: 8bfdc69522ad68c223bb363496084921f5256b4b [file] [log] [blame]
Elliott Hughes5b808042021-10-01 10:56:10 -07001/*
2 * Stack-less Just-In-Time compiler
3 *
4 * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without modification, are
7 * permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice, this list of
10 * conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 * of conditions and the following disclaimer in the documentation and/or other materials
14 * provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19 * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
28{
29 return "PowerPC" SLJIT_CPUINFO;
30}
31
32/* Length of an instruction word.
33 Both for ppc-32 and ppc-64. */
34typedef sljit_u32 sljit_ins;
35
36#if ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && (defined _AIX)) \
37 || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
38#define SLJIT_PPC_STACK_FRAME_V2 1
39#endif
40
41#ifdef _AIX
42#include <sys/cache.h>
43#endif
44
45#if (defined _CALL_ELF && _CALL_ELF == 2)
46#define SLJIT_PASS_ENTRY_ADDR_TO_CALL 1
47#endif
48
49#if (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL)
50
51static void ppc_cache_flush(sljit_ins *from, sljit_ins *to)
52{
53#ifdef _AIX
54 _sync_cache_range((caddr_t)from, (int)((size_t)to - (size_t)from));
55#elif defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM)
56# if defined(_ARCH_PWR) || defined(_ARCH_PWR2)
57 /* Cache flush for POWER architecture. */
58 while (from < to) {
59 __asm__ volatile (
60 "clf 0, %0\n"
61 "dcs\n"
62 : : "r"(from)
63 );
64 from++;
65 }
66 __asm__ volatile ( "ics" );
67# elif defined(_ARCH_COM) && !defined(_ARCH_PPC)
68# error "Cache flush is not implemented for PowerPC/POWER common mode."
69# else
70 /* Cache flush for PowerPC architecture. */
71 while (from < to) {
72 __asm__ volatile (
73 "dcbf 0, %0\n"
74 "sync\n"
75 "icbi 0, %0\n"
76 : : "r"(from)
77 );
78 from++;
79 }
80 __asm__ volatile ( "isync" );
81# endif
82# ifdef __xlc__
83# warning "This file may fail to compile if -qfuncsect is used"
84# endif
85#elif defined(__xlc__)
86#error "Please enable GCC syntax for inline assembly statements with -qasm=gcc"
87#else
88#error "This platform requires a cache flush implementation."
89#endif /* _AIX */
90}
91
92#endif /* (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL) */
93
94#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
95#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
96#define TMP_ZERO (SLJIT_NUMBER_OF_REGISTERS + 4)
97
98#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
99#define TMP_CALL_REG (SLJIT_NUMBER_OF_REGISTERS + 5)
100#else
101#define TMP_CALL_REG TMP_REG2
102#endif
103
104#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
105#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
106
107static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
108 0, 3, 4, 5, 6, 7, 8, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 1, 9, 10, 31, 12
109};
110
111static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700112 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 0, 13
Elliott Hughes5b808042021-10-01 10:56:10 -0700113};
114
115/* --------------------------------------------------------------------- */
116/* Instrucion forms */
117/* --------------------------------------------------------------------- */
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700118#define D(d) ((sljit_ins)reg_map[d] << 21)
119#define S(s) ((sljit_ins)reg_map[s] << 21)
120#define A(a) ((sljit_ins)reg_map[a] << 16)
121#define B(b) ((sljit_ins)reg_map[b] << 11)
122#define C(c) ((sljit_ins)reg_map[c] << 6)
123#define FD(fd) ((sljit_ins)freg_map[fd] << 21)
124#define FS(fs) ((sljit_ins)freg_map[fs] << 21)
125#define FA(fa) ((sljit_ins)freg_map[fa] << 16)
126#define FB(fb) ((sljit_ins)freg_map[fb] << 11)
127#define FC(fc) ((sljit_ins)freg_map[fc] << 6)
128#define IMM(imm) ((sljit_ins)(imm) & 0xffff)
129#define CRD(d) ((sljit_ins)(d) << 21)
Elliott Hughes5b808042021-10-01 10:56:10 -0700130
131/* Instruction bit sections.
132 OE and Rc flag (see ALT_SET_FLAGS). */
133#define OE(flags) ((flags) & ALT_SET_FLAGS)
134/* Rc flag (see ALT_SET_FLAGS). */
135#define RC(flags) (((flags) & ALT_SET_FLAGS) >> 10)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700136#define HI(opcode) ((sljit_ins)(opcode) << 26)
137#define LO(opcode) ((sljit_ins)(opcode) << 1)
Elliott Hughes5b808042021-10-01 10:56:10 -0700138
139#define ADD (HI(31) | LO(266))
140#define ADDC (HI(31) | LO(10))
141#define ADDE (HI(31) | LO(138))
142#define ADDI (HI(14))
143#define ADDIC (HI(13))
144#define ADDIS (HI(15))
145#define ADDME (HI(31) | LO(234))
146#define AND (HI(31) | LO(28))
147#define ANDI (HI(28))
148#define ANDIS (HI(29))
149#define Bx (HI(18))
150#define BCx (HI(16))
151#define BCCTR (HI(19) | LO(528) | (3 << 11))
152#define BLR (HI(19) | LO(16) | (0x14 << 21))
153#define CNTLZD (HI(31) | LO(58))
154#define CNTLZW (HI(31) | LO(26))
155#define CMP (HI(31) | LO(0))
156#define CMPI (HI(11))
157#define CMPL (HI(31) | LO(32))
158#define CMPLI (HI(10))
159#define CROR (HI(19) | LO(449))
160#define DCBT (HI(31) | LO(278))
161#define DIVD (HI(31) | LO(489))
162#define DIVDU (HI(31) | LO(457))
163#define DIVW (HI(31) | LO(491))
164#define DIVWU (HI(31) | LO(459))
165#define EXTSB (HI(31) | LO(954))
166#define EXTSH (HI(31) | LO(922))
167#define EXTSW (HI(31) | LO(986))
168#define FABS (HI(63) | LO(264))
169#define FADD (HI(63) | LO(21))
170#define FADDS (HI(59) | LO(21))
171#define FCFID (HI(63) | LO(846))
172#define FCMPU (HI(63) | LO(0))
173#define FCTIDZ (HI(63) | LO(815))
174#define FCTIWZ (HI(63) | LO(15))
175#define FDIV (HI(63) | LO(18))
176#define FDIVS (HI(59) | LO(18))
177#define FMR (HI(63) | LO(72))
178#define FMUL (HI(63) | LO(25))
179#define FMULS (HI(59) | LO(25))
180#define FNEG (HI(63) | LO(40))
181#define FRSP (HI(63) | LO(12))
182#define FSUB (HI(63) | LO(20))
183#define FSUBS (HI(59) | LO(20))
184#define LD (HI(58) | 0)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700185#define LFD (HI(50))
Elliott Hughes5b808042021-10-01 10:56:10 -0700186#define LWZ (HI(32))
187#define MFCR (HI(31) | LO(19))
188#define MFLR (HI(31) | LO(339) | 0x80000)
189#define MFXER (HI(31) | LO(339) | 0x10000)
190#define MTCTR (HI(31) | LO(467) | 0x90000)
191#define MTLR (HI(31) | LO(467) | 0x80000)
192#define MTXER (HI(31) | LO(467) | 0x10000)
193#define MULHD (HI(31) | LO(73))
194#define MULHDU (HI(31) | LO(9))
195#define MULHW (HI(31) | LO(75))
196#define MULHWU (HI(31) | LO(11))
197#define MULLD (HI(31) | LO(233))
198#define MULLI (HI(7))
199#define MULLW (HI(31) | LO(235))
200#define NEG (HI(31) | LO(104))
201#define NOP (HI(24))
202#define NOR (HI(31) | LO(124))
203#define OR (HI(31) | LO(444))
204#define ORI (HI(24))
205#define ORIS (HI(25))
206#define RLDICL (HI(30))
207#define RLWINM (HI(21))
208#define SLD (HI(31) | LO(27))
209#define SLW (HI(31) | LO(24))
210#define SRAD (HI(31) | LO(794))
211#define SRADI (HI(31) | LO(413 << 1))
212#define SRAW (HI(31) | LO(792))
213#define SRAWI (HI(31) | LO(824))
214#define SRD (HI(31) | LO(539))
215#define SRW (HI(31) | LO(536))
216#define STD (HI(62) | 0)
217#define STDU (HI(62) | 1)
218#define STDUX (HI(31) | LO(181))
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700219#define STFD (HI(54))
Elliott Hughes5b808042021-10-01 10:56:10 -0700220#define STFIWX (HI(31) | LO(983))
221#define STW (HI(36))
222#define STWU (HI(37))
223#define STWUX (HI(31) | LO(183))
224#define SUBF (HI(31) | LO(40))
225#define SUBFC (HI(31) | LO(8))
226#define SUBFE (HI(31) | LO(136))
227#define SUBFIC (HI(8))
228#define XOR (HI(31) | LO(316))
229#define XORI (HI(26))
230#define XORIS (HI(27))
231
232#define SIMM_MAX (0x7fff)
233#define SIMM_MIN (-0x8000)
234#define UIMM_MAX (0xffff)
235
236#define RLDI(dst, src, sh, mb, type) \
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700237 (HI(30) | S(src) | A(dst) | ((sljit_ins)(type) << 2) | (((sljit_ins)(sh) & 0x1f) << 11) \
238 | (((sljit_ins)(sh) & 0x20) >> 4) | (((sljit_ins)(mb) & 0x1f) << 6) | ((sljit_ins)(mb) & 0x20))
Elliott Hughes5b808042021-10-01 10:56:10 -0700239
240#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700241SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_uw addr, void* func)
Elliott Hughes5b808042021-10-01 10:56:10 -0700242{
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700243 sljit_uw* ptrs;
244
Elliott Hughes5b808042021-10-01 10:56:10 -0700245 if (func_ptr)
246 *func_ptr = (void*)context;
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700247
248 ptrs = (sljit_uw*)func;
Elliott Hughes5b808042021-10-01 10:56:10 -0700249 context->addr = addr ? addr : ptrs[0];
250 context->r2 = ptrs[1];
251 context->r11 = ptrs[2];
252}
253#endif
254
255static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
256{
257 sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
258 FAIL_IF(!ptr);
259 *ptr = ins;
260 compiler->size++;
261 return SLJIT_SUCCESS;
262}
263
264static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
265{
266 sljit_sw diff;
267 sljit_uw target_addr;
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700268 sljit_uw extra_jump_flags;
Elliott Hughes5b808042021-10-01 10:56:10 -0700269
270#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
271 if (jump->flags & (SLJIT_REWRITABLE_JUMP | IS_CALL))
272 return 0;
273#else
274 if (jump->flags & SLJIT_REWRITABLE_JUMP)
275 return 0;
276#endif
277
278 if (jump->flags & JUMP_ADDR)
279 target_addr = jump->u.target;
280 else {
281 SLJIT_ASSERT(jump->flags & JUMP_LABEL);
282 target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
283 }
284
285#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
286 if (jump->flags & IS_CALL)
287 goto keep_address;
288#endif
289
290 diff = ((sljit_sw)target_addr - (sljit_sw)(code_ptr) - executable_offset) & ~0x3l;
291
292 extra_jump_flags = 0;
293 if (jump->flags & IS_COND) {
294 if (diff <= 0x7fff && diff >= -0x8000) {
295 jump->flags |= PATCH_B;
296 return 1;
297 }
298 if (target_addr <= 0xffff) {
299 jump->flags |= PATCH_B | PATCH_ABS_B;
300 return 1;
301 }
302 extra_jump_flags = REMOVE_COND;
303
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700304 diff -= SSIZE_OF(ins);
Elliott Hughes5b808042021-10-01 10:56:10 -0700305 }
306
307 if (diff <= 0x01ffffff && diff >= -0x02000000) {
308 jump->flags |= PATCH_B | extra_jump_flags;
309 return 1;
310 }
311
312 if (target_addr <= 0x03ffffff) {
313 jump->flags |= PATCH_B | PATCH_ABS_B | extra_jump_flags;
314 return 1;
315 }
316
317#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
318#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
319keep_address:
320#endif
321 if (target_addr <= 0x7fffffff) {
322 jump->flags |= PATCH_ABS32;
323 return 1;
324 }
325
326 if (target_addr <= 0x7fffffffffffl) {
327 jump->flags |= PATCH_ABS48;
328 return 1;
329 }
330#endif
331
332 return 0;
333}
334
335#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
336
337static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
338{
339 if (max_label < 0x100000000l) {
340 put_label->flags = 0;
341 return 1;
342 }
343
344 if (max_label < 0x1000000000000l) {
345 put_label->flags = 1;
346 return 3;
347 }
348
349 put_label->flags = 2;
350 return 4;
351}
352
353static SLJIT_INLINE void put_label_set(struct sljit_put_label *put_label)
354{
355 sljit_uw addr = put_label->label->addr;
356 sljit_ins *inst = (sljit_ins *)put_label->addr;
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700357 sljit_u32 reg = *inst;
Elliott Hughes5b808042021-10-01 10:56:10 -0700358
359 if (put_label->flags == 0) {
360 SLJIT_ASSERT(addr < 0x100000000l);
361 inst[0] = ORIS | S(TMP_ZERO) | A(reg) | IMM(addr >> 16);
362 }
363 else {
364 if (put_label->flags == 1) {
365 SLJIT_ASSERT(addr < 0x1000000000000l);
366 inst[0] = ORI | S(TMP_ZERO) | A(reg) | IMM(addr >> 32);
367 }
368 else {
369 inst[0] = ORIS | S(TMP_ZERO) | A(reg) | IMM(addr >> 48);
370 inst[1] = ORI | S(reg) | A(reg) | IMM((addr >> 32) & 0xffff);
371 inst ++;
372 }
373
374 inst[1] = RLDI(reg, reg, 32, 31, 1);
375 inst[2] = ORIS | S(reg) | A(reg) | IMM((addr >> 16) & 0xffff);
376 inst += 2;
377 }
378
379 inst[1] = ORI | S(reg) | A(reg) | IMM(addr & 0xffff);
380}
381
382#endif
383
384SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
385{
386 struct sljit_memory_fragment *buf;
387 sljit_ins *code;
388 sljit_ins *code_ptr;
389 sljit_ins *buf_ptr;
390 sljit_ins *buf_end;
391 sljit_uw word_count;
392 sljit_uw next_addr;
393 sljit_sw executable_offset;
394 sljit_uw addr;
395
396 struct sljit_label *label;
397 struct sljit_jump *jump;
398 struct sljit_const *const_;
399 struct sljit_put_label *put_label;
400
401 CHECK_ERROR_PTR();
402 CHECK_PTR(check_sljit_generate_code(compiler));
403 reverse_buf(compiler);
404
405#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
406#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
407 compiler->size += (compiler->size & 0x1) + (sizeof(struct sljit_function_context) / sizeof(sljit_ins));
408#else
409 compiler->size += (sizeof(struct sljit_function_context) / sizeof(sljit_ins));
410#endif
411#endif
412 code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data);
413 PTR_FAIL_WITH_EXEC_IF(code);
414 buf = compiler->buf;
415
416 code_ptr = code;
417 word_count = 0;
418 next_addr = 0;
419 executable_offset = SLJIT_EXEC_OFFSET(code);
420
421 label = compiler->labels;
422 jump = compiler->jumps;
423 const_ = compiler->consts;
424 put_label = compiler->put_labels;
425
426 do {
427 buf_ptr = (sljit_ins*)buf->memory;
428 buf_end = buf_ptr + (buf->used_size >> 2);
429 do {
430 *code_ptr = *buf_ptr++;
431 if (next_addr == word_count) {
432 SLJIT_ASSERT(!label || label->size >= word_count);
433 SLJIT_ASSERT(!jump || jump->addr >= word_count);
434 SLJIT_ASSERT(!const_ || const_->addr >= word_count);
435 SLJIT_ASSERT(!put_label || put_label->addr >= word_count);
436
437 /* These structures are ordered by their address. */
438 if (label && label->size == word_count) {
439 /* Just recording the address. */
440 label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700441 label->size = (sljit_uw)(code_ptr - code);
Elliott Hughes5b808042021-10-01 10:56:10 -0700442 label = label->next;
443 }
444 if (jump && jump->addr == word_count) {
445#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
446 jump->addr = (sljit_uw)(code_ptr - 3);
447#else
448 jump->addr = (sljit_uw)(code_ptr - 6);
449#endif
450 if (detect_jump_type(jump, code_ptr, code, executable_offset)) {
451#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
452 code_ptr[-3] = code_ptr[0];
453 code_ptr -= 3;
454#else
455 if (jump->flags & PATCH_ABS32) {
456 code_ptr -= 3;
457 code_ptr[-1] = code_ptr[2];
458 code_ptr[0] = code_ptr[3];
459 }
460 else if (jump->flags & PATCH_ABS48) {
461 code_ptr--;
462 code_ptr[-1] = code_ptr[0];
463 code_ptr[0] = code_ptr[1];
464 /* rldicr rX,rX,32,31 -> rX,rX,16,47 */
465 SLJIT_ASSERT((code_ptr[-3] & 0xfc00ffff) == 0x780007c6);
466 code_ptr[-3] ^= 0x8422;
467 /* oris -> ori */
468 code_ptr[-2] ^= 0x4000000;
469 }
470 else {
471 code_ptr[-6] = code_ptr[0];
472 code_ptr -= 6;
473 }
474#endif
475 if (jump->flags & REMOVE_COND) {
476 code_ptr[0] = BCx | (2 << 2) | ((code_ptr[0] ^ (8 << 21)) & 0x03ff0001);
477 code_ptr++;
478 jump->addr += sizeof(sljit_ins);
479 code_ptr[0] = Bx;
480 jump->flags -= IS_COND;
481 }
482 }
483 jump = jump->next;
484 }
485 if (const_ && const_->addr == word_count) {
486 const_->addr = (sljit_uw)code_ptr;
487 const_ = const_->next;
488 }
489 if (put_label && put_label->addr == word_count) {
490 SLJIT_ASSERT(put_label->label);
491 put_label->addr = (sljit_uw)code_ptr;
492#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
493 code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size));
494 word_count += 4;
495#endif
496 put_label = put_label->next;
497 }
498 next_addr = compute_next_addr(label, jump, const_, put_label);
499 }
500 code_ptr ++;
501 word_count ++;
502 } while (buf_ptr < buf_end);
503
504 buf = buf->next;
505 } while (buf);
506
507 if (label && label->size == word_count) {
508 label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700509 label->size = (sljit_uw)(code_ptr - code);
Elliott Hughes5b808042021-10-01 10:56:10 -0700510 label = label->next;
511 }
512
513 SLJIT_ASSERT(!label);
514 SLJIT_ASSERT(!jump);
515 SLJIT_ASSERT(!const_);
516 SLJIT_ASSERT(!put_label);
517
518#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700519 SLJIT_ASSERT(code_ptr - code <= (sljit_sw)(compiler->size - (sizeof(struct sljit_function_context) / sizeof(sljit_ins))));
Elliott Hughes5b808042021-10-01 10:56:10 -0700520#else
521 SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size);
522#endif
523
524 jump = compiler->jumps;
525 while (jump) {
526 do {
527 addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
528 buf_ptr = (sljit_ins *)jump->addr;
529
530 if (jump->flags & PATCH_B) {
531 if (jump->flags & IS_COND) {
532 if (!(jump->flags & PATCH_ABS_B)) {
533 addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
534 SLJIT_ASSERT((sljit_sw)addr <= 0x7fff && (sljit_sw)addr >= -0x8000);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700535 *buf_ptr = BCx | ((sljit_ins)addr & 0xfffc) | ((*buf_ptr) & 0x03ff0001);
Elliott Hughes5b808042021-10-01 10:56:10 -0700536 }
537 else {
538 SLJIT_ASSERT(addr <= 0xffff);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700539 *buf_ptr = BCx | ((sljit_ins)addr & 0xfffc) | 0x2 | ((*buf_ptr) & 0x03ff0001);
Elliott Hughes5b808042021-10-01 10:56:10 -0700540 }
541 }
542 else {
543 if (!(jump->flags & PATCH_ABS_B)) {
544 addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
545 SLJIT_ASSERT((sljit_sw)addr <= 0x01ffffff && (sljit_sw)addr >= -0x02000000);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700546 *buf_ptr = Bx | ((sljit_ins)addr & 0x03fffffc) | ((*buf_ptr) & 0x1);
Elliott Hughes5b808042021-10-01 10:56:10 -0700547 }
548 else {
549 SLJIT_ASSERT(addr <= 0x03ffffff);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700550 *buf_ptr = Bx | ((sljit_ins)addr & 0x03fffffc) | 0x2 | ((*buf_ptr) & 0x1);
Elliott Hughes5b808042021-10-01 10:56:10 -0700551 }
552 }
553 break;
554 }
555
556 /* Set the fields of immediate loads. */
557#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700558 SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1]) & 0xffff) == 0);
559 buf_ptr[0] |= (sljit_ins)(addr >> 16) & 0xffff;
560 buf_ptr[1] |= (sljit_ins)addr & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -0700561#else
562 if (jump->flags & PATCH_ABS32) {
563 SLJIT_ASSERT(addr <= 0x7fffffff);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700564 SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1]) & 0xffff) == 0);
565 buf_ptr[0] |= (sljit_ins)(addr >> 16) & 0xffff;
566 buf_ptr[1] |= (sljit_ins)addr & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -0700567 break;
568 }
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700569
Elliott Hughes5b808042021-10-01 10:56:10 -0700570 if (jump->flags & PATCH_ABS48) {
571 SLJIT_ASSERT(addr <= 0x7fffffffffff);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700572 SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1] | buf_ptr[3]) & 0xffff) == 0);
573 buf_ptr[0] |= (sljit_ins)(addr >> 32) & 0xffff;
574 buf_ptr[1] |= (sljit_ins)(addr >> 16) & 0xffff;
575 buf_ptr[3] |= (sljit_ins)addr & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -0700576 break;
577 }
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700578
579 SLJIT_ASSERT(((buf_ptr[0] | buf_ptr[1] | buf_ptr[3] | buf_ptr[4]) & 0xffff) == 0);
580 buf_ptr[0] |= (sljit_ins)(addr >> 48) & 0xffff;
581 buf_ptr[1] |= (sljit_ins)(addr >> 32) & 0xffff;
582 buf_ptr[3] |= (sljit_ins)(addr >> 16) & 0xffff;
583 buf_ptr[4] |= (sljit_ins)addr & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -0700584#endif
585 } while (0);
586 jump = jump->next;
587 }
588
589 put_label = compiler->put_labels;
590 while (put_label) {
591#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
592 addr = put_label->label->addr;
593 buf_ptr = (sljit_ins *)put_label->addr;
594
595 SLJIT_ASSERT((buf_ptr[0] & 0xfc1f0000) == ADDIS && (buf_ptr[1] & 0xfc000000) == ORI);
596 buf_ptr[0] |= (addr >> 16) & 0xffff;
597 buf_ptr[1] |= addr & 0xffff;
598#else
599 put_label_set(put_label);
600#endif
601 put_label = put_label->next;
602 }
603
604 compiler->error = SLJIT_ERR_COMPILED;
605 compiler->executable_offset = executable_offset;
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700606 compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins);
Elliott Hughes5b808042021-10-01 10:56:10 -0700607
608 code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
609
610#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
611#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
612 if (((sljit_sw)code_ptr) & 0x4)
613 code_ptr++;
614#endif
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700615 sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_uw)code, (void*)sljit_generate_code);
Elliott Hughes5b808042021-10-01 10:56:10 -0700616#endif
617
618 code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
619
620 SLJIT_CACHE_FLUSH(code, code_ptr);
621 SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
622
623#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
624 return code_ptr;
625#else
626 return code;
627#endif
628}
629
630SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
631{
632 switch (feature_type) {
633 case SLJIT_HAS_FPU:
634#ifdef SLJIT_IS_FPU_AVAILABLE
635 return SLJIT_IS_FPU_AVAILABLE;
636#else
637 /* Available by default. */
638 return 1;
639#endif
640
641 /* A saved register is set to a zero value. */
642 case SLJIT_HAS_ZERO_REGISTER:
643 case SLJIT_HAS_CLZ:
644 case SLJIT_HAS_PREFETCH:
645 return 1;
646
647 default:
648 return 0;
649 }
650}
651
652/* --------------------------------------------------------------------- */
653/* Entry, exit */
654/* --------------------------------------------------------------------- */
655
656/* inp_flags: */
657
658/* Creates an index in data_transfer_insts array. */
659#define LOAD_DATA 0x01
660#define INDEXED 0x02
661#define SIGNED_DATA 0x04
662
663#define WORD_DATA 0x00
664#define BYTE_DATA 0x08
665#define HALF_DATA 0x10
666#define INT_DATA 0x18
667/* Separates integer and floating point registers */
668#define GPR_REG 0x1f
669#define DOUBLE_DATA 0x20
670
671#define MEM_MASK 0x7f
672
673/* Other inp_flags. */
674
675/* Integer opertion and set flags -> requires exts on 64 bit systems. */
676#define ALT_SIGN_EXT 0x000100
677/* This flag affects the RC() and OERC() macros. */
678#define ALT_SET_FLAGS 0x000400
679#define ALT_FORM1 0x001000
680#define ALT_FORM2 0x002000
681#define ALT_FORM3 0x004000
682#define ALT_FORM4 0x008000
683#define ALT_FORM5 0x010000
684
685/* Source and destination is register. */
686#define REG_DEST 0x000001
687#define REG1_SOURCE 0x000002
688#define REG2_SOURCE 0x000004
689/*
690ALT_SIGN_EXT 0x000100
691ALT_SET_FLAGS 0x000200
692ALT_FORM1 0x001000
693...
694ALT_FORM5 0x010000 */
695
696#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
697#include "sljitNativePPC_32.c"
698#else
699#include "sljitNativePPC_64.c"
700#endif
701
702#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
703#define STACK_STORE STW
704#define STACK_LOAD LWZ
705#else
706#define STACK_STORE STD
707#define STACK_LOAD LD
708#endif
709
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700710#if (defined SLJIT_PPC_STACK_FRAME_V2 && SLJIT_PPC_STACK_FRAME_V2)
711#define LR_SAVE_OFFSET 2 * SSIZE_OF(sw)
712#else
713#define LR_SAVE_OFFSET SSIZE_OF(sw)
714#endif
715
716#define STACK_MAX_DISTANCE (0x8000 - SSIZE_OF(sw) - LR_SAVE_OFFSET)
717
Elliott Hughes5b808042021-10-01 10:56:10 -0700718SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
719 sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
720 sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
721{
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700722 sljit_s32 i, tmp, base, offset;
723 sljit_s32 word_arg_count = 0;
724 sljit_s32 saved_arg_count = 0;
725#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
726 sljit_s32 arg_count = 0;
727#endif
Elliott Hughes5b808042021-10-01 10:56:10 -0700728
729 CHECK_ERROR();
730 CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
731 set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
732
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700733 local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1)
734 + GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
735 local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
736 compiler->local_size = local_size;
Elliott Hughes5b808042021-10-01 10:56:10 -0700737
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700738 FAIL_IF(push_inst(compiler, MFLR | D(0)));
739
740 base = SLJIT_SP;
741 offset = local_size;
742
743 if (local_size <= STACK_MAX_DISTANCE) {
744#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
745 FAIL_IF(push_inst(compiler, STWU | S(SLJIT_SP) | A(SLJIT_SP) | IMM(-local_size)));
746#else
747 FAIL_IF(push_inst(compiler, STDU | S(SLJIT_SP) | A(SLJIT_SP) | IMM(-local_size)));
748#endif
749 } else {
750 base = TMP_REG1;
751 FAIL_IF(push_inst(compiler, OR | S(SLJIT_SP) | A(TMP_REG1) | B(SLJIT_SP)));
752 FAIL_IF(load_immediate(compiler, TMP_REG2, -local_size));
753#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
754 FAIL_IF(push_inst(compiler, STWUX | S(SLJIT_SP) | A(SLJIT_SP) | B(TMP_REG2)));
755#else
756 FAIL_IF(push_inst(compiler, STDUX | S(SLJIT_SP) | A(SLJIT_SP) | B(TMP_REG2)));
757#endif
758 local_size = 0;
759 offset = 0;
760 }
761
762 tmp = SLJIT_FS0 - fsaveds;
763 for (i = SLJIT_FS0; i > tmp; i--) {
764 offset -= SSIZE_OF(f64);
765 FAIL_IF(push_inst(compiler, STFD | FS(i) | A(base) | IMM(offset)));
766 }
767
768 for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {
769 offset -= SSIZE_OF(f64);
770 FAIL_IF(push_inst(compiler, STFD | FS(i) | A(base) | IMM(offset)));
771 }
772
773 offset -= SSIZE_OF(sw);
774 FAIL_IF(push_inst(compiler, STACK_STORE | S(TMP_ZERO) | A(base) | IMM(offset)));
775
776 tmp = SLJIT_S0 - saveds;
777 for (i = SLJIT_S0; i > tmp; i--) {
778 offset -= SSIZE_OF(sw);
779 FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(base) | IMM(offset)));
Elliott Hughes5b808042021-10-01 10:56:10 -0700780 }
781
782 for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700783 offset -= SSIZE_OF(sw);
784 FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(base) | IMM(offset)));
Elliott Hughes5b808042021-10-01 10:56:10 -0700785 }
786
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700787 FAIL_IF(push_inst(compiler, STACK_STORE | S(0) | A(base) | IMM(local_size + LR_SAVE_OFFSET)));
Elliott Hughes5b808042021-10-01 10:56:10 -0700788 FAIL_IF(push_inst(compiler, ADDI | D(TMP_ZERO) | A(0) | 0));
789
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700790 arg_types >>= SLJIT_ARG_SHIFT;
Elliott Hughes5b808042021-10-01 10:56:10 -0700791
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700792 while (arg_types > 0) {
793 if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) {
794#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
795 do {
796 if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) {
797 tmp = SLJIT_S0 - saved_arg_count;
798 saved_arg_count++;
799 } else if (arg_count != word_arg_count)
800 tmp = SLJIT_R0 + word_arg_count;
801 else
802 break;
Elliott Hughes5b808042021-10-01 10:56:10 -0700803
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700804 FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0 + arg_count) | A(tmp) | B(SLJIT_R0 + arg_count)));
805 } while (0);
Elliott Hughes5b808042021-10-01 10:56:10 -0700806#else
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700807 if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) {
808 FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0 + word_arg_count) | A(SLJIT_S0 - saved_arg_count) | B(SLJIT_R0 + word_arg_count)));
809 saved_arg_count++;
810 }
Elliott Hughes5b808042021-10-01 10:56:10 -0700811#endif
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700812 word_arg_count++;
813 }
814
815#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
816 arg_count++;
817#endif
818 arg_types >>= SLJIT_ARG_SHIFT;
819 }
Elliott Hughes5b808042021-10-01 10:56:10 -0700820
821 return SLJIT_SUCCESS;
822}
823
824SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
825 sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
826 sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
827{
828 CHECK_ERROR();
829 CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
830 set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
831
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700832 local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1)
833 + GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
834 compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
Elliott Hughes5b808042021-10-01 10:56:10 -0700835 return SLJIT_SUCCESS;
836}
837
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700838
839static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler)
Elliott Hughes5b808042021-10-01 10:56:10 -0700840{
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700841 sljit_s32 i, tmp, base, offset;
842 sljit_s32 local_size = compiler->local_size;
Elliott Hughes5b808042021-10-01 10:56:10 -0700843
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700844 base = SLJIT_SP;
845 if (local_size > STACK_MAX_DISTANCE) {
846 base = TMP_REG1;
847 if (local_size > 2 * STACK_MAX_DISTANCE + LR_SAVE_OFFSET) {
848 FAIL_IF(push_inst(compiler, STACK_LOAD | D(base) | A(SLJIT_SP) | IMM(0)));
849 local_size = 0;
850 } else {
851 FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG1) | A(SLJIT_SP) | IMM(local_size - STACK_MAX_DISTANCE)));
852 local_size = STACK_MAX_DISTANCE;
853 }
854 }
855
856 offset = local_size;
857 FAIL_IF(push_inst(compiler, STACK_LOAD | S(0) | A(base) | IMM(offset + LR_SAVE_OFFSET)));
858
859 tmp = SLJIT_FS0 - compiler->fsaveds;
860 for (i = SLJIT_FS0; i > tmp; i--) {
861 offset -= SSIZE_OF(f64);
862 FAIL_IF(push_inst(compiler, LFD | FS(i) | A(base) | IMM(offset)));
863 }
864
865 for (i = compiler->fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {
866 offset -= SSIZE_OF(f64);
867 FAIL_IF(push_inst(compiler, LFD | FS(i) | A(base) | IMM(offset)));
868 }
869
870 offset -= SSIZE_OF(sw);
871 FAIL_IF(push_inst(compiler, STACK_LOAD | S(TMP_ZERO) | A(base) | IMM(offset)));
872
873 tmp = SLJIT_S0 - compiler->saveds;
874 for (i = SLJIT_S0; i > tmp; i--) {
875 offset -= SSIZE_OF(sw);
876 FAIL_IF(push_inst(compiler, STACK_LOAD | S(i) | A(base) | IMM(offset)));
877 }
878
879 for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
880 offset -= SSIZE_OF(sw);
881 FAIL_IF(push_inst(compiler, STACK_LOAD | S(i) | A(base) | IMM(offset)));
882 }
883
884 push_inst(compiler, MTLR | S(0));
885
886 if (local_size > 0)
887 return push_inst(compiler, ADDI | D(SLJIT_SP) | A(base) | IMM(local_size));
888
889 SLJIT_ASSERT(base == TMP_REG1);
890 return push_inst(compiler, OR | S(base) | A(SLJIT_SP) | B(base));
891}
892
893SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)
894{
Elliott Hughes5b808042021-10-01 10:56:10 -0700895 CHECK_ERROR();
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700896 CHECK(check_sljit_emit_return_void(compiler));
Elliott Hughes5b808042021-10-01 10:56:10 -0700897
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700898 FAIL_IF(emit_stack_frame_release(compiler));
899 return push_inst(compiler, BLR);
Elliott Hughes5b808042021-10-01 10:56:10 -0700900}
901
902#undef STACK_STORE
903#undef STACK_LOAD
904
905/* --------------------------------------------------------------------- */
906/* Operators */
907/* --------------------------------------------------------------------- */
908
909/* s/l - store/load (1 bit)
910 i/x - immediate/indexed form
911 u/s - signed/unsigned (1 bit)
912 w/b/h/i - word/byte/half/int allowed (2 bit)
913
914 Some opcodes are repeated (e.g. store signed / unsigned byte is the same instruction). */
915
916/* 64 bit only: [reg+imm] must be aligned to 4 bytes. */
917#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
918#define INT_ALIGNED 0x10000
919#endif
920
921#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
922#define ARCH_32_64(a, b) a
923#define INST_CODE_AND_DST(inst, flags, reg) \
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700924 ((sljit_ins)(inst) | (sljit_ins)(((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg)))
Elliott Hughes5b808042021-10-01 10:56:10 -0700925#else
926#define ARCH_32_64(a, b) b
927#define INST_CODE_AND_DST(inst, flags, reg) \
Elliott Hughes4e19c8e2022-04-15 15:11:02 -0700928 (((sljit_ins)(inst) & ~(sljit_ins)INT_ALIGNED) | (sljit_ins)(((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg)))
Elliott Hughes5b808042021-10-01 10:56:10 -0700929#endif
930
931static const sljit_ins data_transfer_insts[64 + 16] = {
932
933/* -------- Integer -------- */
934
935/* Word. */
936
937/* w u i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | INT_ALIGNED | 0x0 /* std */),
938/* w u i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x0 /* ld */),
939/* w u x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */),
940/* w u x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */),
941
942/* w s i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | INT_ALIGNED | 0x0 /* std */),
943/* w s i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x0 /* ld */),
944/* w s x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */),
945/* w s x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */),
946
947/* Byte. */
948
949/* b u i s */ HI(38) /* stb */,
950/* b u i l */ HI(34) /* lbz */,
951/* b u x s */ HI(31) | LO(215) /* stbx */,
952/* b u x l */ HI(31) | LO(87) /* lbzx */,
953
954/* b s i s */ HI(38) /* stb */,
955/* b s i l */ HI(34) /* lbz */ /* EXTS_REQ */,
956/* b s x s */ HI(31) | LO(215) /* stbx */,
957/* b s x l */ HI(31) | LO(87) /* lbzx */ /* EXTS_REQ */,
958
959/* Half. */
960
961/* h u i s */ HI(44) /* sth */,
962/* h u i l */ HI(40) /* lhz */,
963/* h u x s */ HI(31) | LO(407) /* sthx */,
964/* h u x l */ HI(31) | LO(279) /* lhzx */,
965
966/* h s i s */ HI(44) /* sth */,
967/* h s i l */ HI(42) /* lha */,
968/* h s x s */ HI(31) | LO(407) /* sthx */,
969/* h s x l */ HI(31) | LO(343) /* lhax */,
970
971/* Int. */
972
973/* i u i s */ HI(36) /* stw */,
974/* i u i l */ HI(32) /* lwz */,
975/* i u x s */ HI(31) | LO(151) /* stwx */,
976/* i u x l */ HI(31) | LO(23) /* lwzx */,
977
978/* i s i s */ HI(36) /* stw */,
979/* i s i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x2 /* lwa */),
980/* i s x s */ HI(31) | LO(151) /* stwx */,
981/* i s x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(341) /* lwax */),
982
983/* -------- Floating point -------- */
984
985/* d i s */ HI(54) /* stfd */,
986/* d i l */ HI(50) /* lfd */,
987/* d x s */ HI(31) | LO(727) /* stfdx */,
988/* d x l */ HI(31) | LO(599) /* lfdx */,
989
990/* s i s */ HI(52) /* stfs */,
991/* s i l */ HI(48) /* lfs */,
992/* s x s */ HI(31) | LO(663) /* stfsx */,
993/* s x l */ HI(31) | LO(535) /* lfsx */,
994};
995
996static const sljit_ins updated_data_transfer_insts[64] = {
997
998/* -------- Integer -------- */
999
1000/* Word. */
1001
1002/* w u i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | INT_ALIGNED | 0x1 /* stdu */),
1003/* w u i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | 0x1 /* ldu */),
1004/* w u x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */),
1005/* w u x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */),
1006
1007/* w s i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | INT_ALIGNED | 0x1 /* stdu */),
1008/* w s i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | 0x1 /* ldu */),
1009/* w s x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */),
1010/* w s x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */),
1011
1012/* Byte. */
1013
1014/* b u i s */ HI(39) /* stbu */,
1015/* b u i l */ HI(35) /* lbzu */,
1016/* b u x s */ HI(31) | LO(247) /* stbux */,
1017/* b u x l */ HI(31) | LO(119) /* lbzux */,
1018
1019/* b s i s */ HI(39) /* stbu */,
1020/* b s i l */ 0 /* no such instruction */,
1021/* b s x s */ HI(31) | LO(247) /* stbux */,
1022/* b s x l */ 0 /* no such instruction */,
1023
1024/* Half. */
1025
1026/* h u i s */ HI(45) /* sthu */,
1027/* h u i l */ HI(41) /* lhzu */,
1028/* h u x s */ HI(31) | LO(439) /* sthux */,
1029/* h u x l */ HI(31) | LO(311) /* lhzux */,
1030
1031/* h s i s */ HI(45) /* sthu */,
1032/* h s i l */ HI(43) /* lhau */,
1033/* h s x s */ HI(31) | LO(439) /* sthux */,
1034/* h s x l */ HI(31) | LO(375) /* lhaux */,
1035
1036/* Int. */
1037
1038/* i u i s */ HI(37) /* stwu */,
1039/* i u i l */ HI(33) /* lwzu */,
1040/* i u x s */ HI(31) | LO(183) /* stwux */,
1041/* i u x l */ HI(31) | LO(55) /* lwzux */,
1042
1043/* i s i s */ HI(37) /* stwu */,
1044/* i s i l */ ARCH_32_64(HI(33) /* lwzu */, 0 /* no such instruction */),
1045/* i s x s */ HI(31) | LO(183) /* stwux */,
1046/* i s x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(373) /* lwaux */),
1047
1048/* -------- Floating point -------- */
1049
1050/* d i s */ HI(55) /* stfdu */,
1051/* d i l */ HI(51) /* lfdu */,
1052/* d x s */ HI(31) | LO(759) /* stfdux */,
1053/* d x l */ HI(31) | LO(631) /* lfdux */,
1054
1055/* s i s */ HI(53) /* stfsu */,
1056/* s i l */ HI(49) /* lfsu */,
1057/* s x s */ HI(31) | LO(695) /* stfsux */,
1058/* s x l */ HI(31) | LO(567) /* lfsux */,
1059};
1060
1061#undef ARCH_32_64
1062
1063/* Simple cases, (no caching is required). */
1064static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg,
1065 sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg)
1066{
1067 sljit_ins inst;
1068 sljit_s32 offs_reg;
1069 sljit_sw high_short;
1070
1071 /* Should work when (arg & REG_MASK) == 0. */
1072 SLJIT_ASSERT(A(0) == 0);
1073 SLJIT_ASSERT(arg & SLJIT_MEM);
1074
1075 if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
1076 argw &= 0x3;
1077 offs_reg = OFFS_REG(arg);
1078
1079 if (argw != 0) {
1080#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001081 FAIL_IF(push_inst(compiler, RLWINM | S(OFFS_REG(arg)) | A(tmp_reg) | ((sljit_ins)argw << 11) | ((31 - (sljit_ins)argw) << 1)));
Elliott Hughes5b808042021-10-01 10:56:10 -07001082#else
1083 FAIL_IF(push_inst(compiler, RLDI(tmp_reg, OFFS_REG(arg), argw, 63 - argw, 1)));
1084#endif
1085 offs_reg = tmp_reg;
1086 }
1087
1088 inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
1089
1090#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1091 SLJIT_ASSERT(!(inst & INT_ALIGNED));
1092#endif
1093
1094 return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(offs_reg));
1095 }
1096
1097 inst = data_transfer_insts[inp_flags & MEM_MASK];
1098 arg &= REG_MASK;
1099
1100#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1101 if ((inst & INT_ALIGNED) && (argw & 0x3) != 0) {
1102 FAIL_IF(load_immediate(compiler, tmp_reg, argw));
1103
1104 inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
1105 return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | B(tmp_reg));
1106 }
1107#endif
1108
1109 if (argw <= SIMM_MAX && argw >= SIMM_MIN)
1110 return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | IMM(argw));
1111
1112#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1113 if (argw <= 0x7fff7fffl && argw >= -0x80000000l) {
1114#endif
1115
1116 high_short = (sljit_s32)(argw + ((argw & 0x8000) << 1)) & ~0xffff;
1117
1118#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1119 SLJIT_ASSERT(high_short && high_short <= 0x7fffffffl && high_short >= -0x80000000l);
1120#else
1121 SLJIT_ASSERT(high_short);
1122#endif
1123
1124 FAIL_IF(push_inst(compiler, ADDIS | D(tmp_reg) | A(arg) | IMM(high_short >> 16)));
1125 return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(tmp_reg) | IMM(argw));
1126
1127#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1128 }
1129
1130 /* The rest is PPC-64 only. */
1131
1132 FAIL_IF(load_immediate(compiler, tmp_reg, argw));
1133
1134 inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
1135 return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | B(tmp_reg));
1136#endif
1137}
1138
1139static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 input_flags,
1140 sljit_s32 dst, sljit_sw dstw,
1141 sljit_s32 src1, sljit_sw src1w,
1142 sljit_s32 src2, sljit_sw src2w)
1143{
1144 /* arg1 goes to TMP_REG1 or src reg
1145 arg2 goes to TMP_REG2, imm or src reg
1146 result goes to TMP_REG2, so put result can use TMP_REG1. */
1147 sljit_s32 dst_r = TMP_REG2;
1148 sljit_s32 src1_r;
1149 sljit_s32 src2_r;
1150 sljit_s32 sugg_src2_r = TMP_REG2;
1151 sljit_s32 flags = input_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_SIGN_EXT | ALT_SET_FLAGS);
1152
1153 /* Destination check. */
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001154 if (FAST_IS_REG(dst)) {
Elliott Hughes5b808042021-10-01 10:56:10 -07001155 dst_r = dst;
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001156 /* The REG_DEST is only used by SLJIT_MOV operations, although
1157 * it is set for op2 operations with unset destination. */
Elliott Hughes5b808042021-10-01 10:56:10 -07001158 flags |= REG_DEST;
1159
1160 if (op >= SLJIT_MOV && op <= SLJIT_MOV_P)
1161 sugg_src2_r = dst_r;
1162 }
1163
1164 /* Source 1. */
1165 if (FAST_IS_REG(src1)) {
1166 src1_r = src1;
1167 flags |= REG1_SOURCE;
1168 }
1169 else if (src1 & SLJIT_IMM) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001170 src1_r = TMP_ZERO;
1171 if (src1w != 0) {
1172 FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
1173 src1_r = TMP_REG1;
1174 }
Elliott Hughes5b808042021-10-01 10:56:10 -07001175 }
1176 else {
1177 FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
1178 src1_r = TMP_REG1;
1179 }
1180
1181 /* Source 2. */
1182 if (FAST_IS_REG(src2)) {
1183 src2_r = src2;
1184 flags |= REG2_SOURCE;
1185
1186 if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOV_P)
1187 dst_r = src2_r;
1188 }
1189 else if (src2 & SLJIT_IMM) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001190 src2_r = TMP_ZERO;
1191 if (src2w != 0) {
1192 FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w));
1193 src2_r = sugg_src2_r;
1194 }
Elliott Hughes5b808042021-10-01 10:56:10 -07001195 }
1196 else {
1197 FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w, TMP_REG2));
1198 src2_r = sugg_src2_r;
1199 }
1200
1201 FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
1202
1203 if (!(dst & SLJIT_MEM))
1204 return SLJIT_SUCCESS;
1205
1206 return emit_op_mem(compiler, input_flags, dst_r, dst, dstw, TMP_REG1);
1207}
1208
1209SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
1210{
1211#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001212 sljit_s32 int_op = op & SLJIT_32;
Elliott Hughes5b808042021-10-01 10:56:10 -07001213#endif
1214
1215 CHECK_ERROR();
1216 CHECK(check_sljit_emit_op0(compiler, op));
1217
1218 op = GET_OPCODE(op);
1219 switch (op) {
1220 case SLJIT_BREAKPOINT:
1221 case SLJIT_NOP:
1222 return push_inst(compiler, NOP);
1223 case SLJIT_LMUL_UW:
1224 case SLJIT_LMUL_SW:
1225 FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));
1226#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1227 FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
1228 return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHDU : MULHD) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
1229#else
1230 FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
1231 return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHWU : MULHW) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
1232#endif
1233 case SLJIT_DIVMOD_UW:
1234 case SLJIT_DIVMOD_SW:
1235 FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));
1236#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1237 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)));
1238 FAIL_IF(push_inst(compiler, (int_op ? MULLW : MULLD) | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
1239#else
1240 FAIL_IF(push_inst(compiler, (op == SLJIT_DIVMOD_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));
1241 FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
1242#endif
1243 return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1));
1244 case SLJIT_DIV_UW:
1245 case SLJIT_DIV_SW:
1246#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1247 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));
1248#else
1249 return push_inst(compiler, (op == SLJIT_DIV_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));
1250#endif
1251 case SLJIT_ENDBR:
1252 case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
1253 return SLJIT_SUCCESS;
1254 }
1255
1256 return SLJIT_SUCCESS;
1257}
1258
1259static sljit_s32 emit_prefetch(struct sljit_compiler *compiler,
1260 sljit_s32 src, sljit_sw srcw)
1261{
1262 if (!(src & OFFS_REG_MASK)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001263 if (srcw == 0 && (src & REG_MASK))
Elliott Hughes5b808042021-10-01 10:56:10 -07001264 return push_inst(compiler, DCBT | A(0) | B(src & REG_MASK));
1265
1266 FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
1267 /* Works with SLJIT_MEM0() case as well. */
1268 return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));
1269 }
1270
1271 srcw &= 0x3;
1272
1273 if (srcw == 0)
1274 return push_inst(compiler, DCBT | A(src & REG_MASK) | B(OFFS_REG(src)));
1275
1276#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001277 FAIL_IF(push_inst(compiler, RLWINM | S(OFFS_REG(src)) | A(TMP_REG1) | ((sljit_ins)srcw << 11) | ((31 - (sljit_ins)srcw) << 1)));
Elliott Hughes5b808042021-10-01 10:56:10 -07001278#else
1279 FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, OFFS_REG(src), srcw, 63 - srcw, 1)));
1280#endif
1281 return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));
1282}
1283
1284#define EMIT_MOV(type, type_flags, type_cast) \
1285 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)
1286
1287SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
1288 sljit_s32 dst, sljit_sw dstw,
1289 sljit_s32 src, sljit_sw srcw)
1290{
1291 sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;
1292 sljit_s32 op_flags = GET_ALL_FLAGS(op);
1293
1294 CHECK_ERROR();
1295 CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
1296 ADJUST_LOCAL_OFFSET(dst, dstw);
1297 ADJUST_LOCAL_OFFSET(src, srcw);
1298
1299 op = GET_OPCODE(op);
Elliott Hughes5b808042021-10-01 10:56:10 -07001300
1301 if (GET_FLAG_TYPE(op_flags) == SLJIT_OVERFLOW)
1302 FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
1303
1304 if (op < SLJIT_NOT && FAST_IS_REG(src) && src == dst) {
1305 if (!TYPE_CAST_NEEDED(op))
1306 return SLJIT_SUCCESS;
1307 }
1308
1309#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001310 if (op_flags & SLJIT_32) {
Elliott Hughes5b808042021-10-01 10:56:10 -07001311 if (op < SLJIT_NOT) {
1312 if (src & SLJIT_MEM) {
1313 if (op == SLJIT_MOV_S32)
1314 op = SLJIT_MOV_U32;
1315 }
1316 else if (src & SLJIT_IMM) {
1317 if (op == SLJIT_MOV_U32)
1318 op = SLJIT_MOV_S32;
1319 }
1320 }
1321 else {
1322 /* Most operations expect sign extended arguments. */
1323 flags |= INT_DATA | SIGNED_DATA;
1324 if (HAS_FLAGS(op_flags))
1325 flags |= ALT_SIGN_EXT;
1326 }
1327 }
1328#endif
1329
1330 switch (op) {
1331 case SLJIT_MOV:
Elliott Hughes5b808042021-10-01 10:56:10 -07001332#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
1333 case SLJIT_MOV_U32:
1334 case SLJIT_MOV_S32:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001335 case SLJIT_MOV32:
Elliott Hughes5b808042021-10-01 10:56:10 -07001336#endif
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001337 case SLJIT_MOV_P:
Elliott Hughes5b808042021-10-01 10:56:10 -07001338 return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
1339
1340#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1341 case SLJIT_MOV_U32:
1342 return EMIT_MOV(SLJIT_MOV_U32, INT_DATA, (sljit_u32));
1343
1344 case SLJIT_MOV_S32:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001345 case SLJIT_MOV32:
Elliott Hughes5b808042021-10-01 10:56:10 -07001346 return EMIT_MOV(SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, (sljit_s32));
1347#endif
1348
1349 case SLJIT_MOV_U8:
1350 return EMIT_MOV(SLJIT_MOV_U8, BYTE_DATA, (sljit_u8));
1351
1352 case SLJIT_MOV_S8:
1353 return EMIT_MOV(SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA, (sljit_s8));
1354
1355 case SLJIT_MOV_U16:
1356 return EMIT_MOV(SLJIT_MOV_U16, HALF_DATA, (sljit_u16));
1357
1358 case SLJIT_MOV_S16:
1359 return EMIT_MOV(SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, (sljit_s16));
1360
1361 case SLJIT_NOT:
1362 return emit_op(compiler, SLJIT_NOT, flags, dst, dstw, TMP_REG1, 0, src, srcw);
1363
Elliott Hughes5b808042021-10-01 10:56:10 -07001364 case SLJIT_CLZ:
1365#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001366 return emit_op(compiler, SLJIT_CLZ, flags | (!(op_flags & SLJIT_32) ? 0 : ALT_FORM1), dst, dstw, TMP_REG1, 0, src, srcw);
Elliott Hughes5b808042021-10-01 10:56:10 -07001367#else
1368 return emit_op(compiler, SLJIT_CLZ, flags, dst, dstw, TMP_REG1, 0, src, srcw);
1369#endif
1370 }
1371
1372 return SLJIT_SUCCESS;
1373}
1374
1375#undef EMIT_MOV
1376
1377#define TEST_SL_IMM(src, srcw) \
1378 (((src) & SLJIT_IMM) && (srcw) <= SIMM_MAX && (srcw) >= SIMM_MIN)
1379
1380#define TEST_UL_IMM(src, srcw) \
1381 (((src) & SLJIT_IMM) && !((srcw) & ~0xffff))
1382
1383#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1384#define TEST_SH_IMM(src, srcw) \
1385 (((src) & SLJIT_IMM) && !((srcw) & 0xffff) && (srcw) <= 0x7fffffffl && (srcw) >= -0x80000000l)
1386#else
1387#define TEST_SH_IMM(src, srcw) \
1388 (((src) & SLJIT_IMM) && !((srcw) & 0xffff))
1389#endif
1390
1391#define TEST_UH_IMM(src, srcw) \
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001392 (((src) & SLJIT_IMM) && !((srcw) & ~(sljit_sw)0xffff0000))
Elliott Hughes5b808042021-10-01 10:56:10 -07001393
1394#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1395#define TEST_ADD_IMM(src, srcw) \
1396 (((src) & SLJIT_IMM) && (srcw) <= 0x7fff7fffl && (srcw) >= -0x80000000l)
1397#else
1398#define TEST_ADD_IMM(src, srcw) \
1399 ((src) & SLJIT_IMM)
1400#endif
1401
1402#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1403#define TEST_UI_IMM(src, srcw) \
1404 (((src) & SLJIT_IMM) && !((srcw) & ~0xffffffff))
1405#else
1406#define TEST_UI_IMM(src, srcw) \
1407 ((src) & SLJIT_IMM)
1408#endif
1409
1410#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1411#define TEST_ADD_FORM1(op) \
1412 (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001413 || (op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_32 | SLJIT_SET_Z | SLJIT_SET_CARRY))
Elliott Hughes5b808042021-10-01 10:56:10 -07001414#define TEST_SUB_FORM2(op) \
1415 ((GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) \
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001416 || (op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_32 | SLJIT_SET_Z))
Elliott Hughes5b808042021-10-01 10:56:10 -07001417#define TEST_SUB_FORM3(op) \
1418 (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001419 || (op & (SLJIT_32 | SLJIT_SET_Z)) == (SLJIT_32 | SLJIT_SET_Z))
Elliott Hughes5b808042021-10-01 10:56:10 -07001420#else
1421#define TEST_ADD_FORM1(op) \
1422 (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
1423#define TEST_SUB_FORM2(op) \
1424 (GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL)
1425#define TEST_SUB_FORM3(op) \
1426 (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
1427#endif
1428
1429SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
1430 sljit_s32 dst, sljit_sw dstw,
1431 sljit_s32 src1, sljit_sw src1w,
1432 sljit_s32 src2, sljit_sw src2w)
1433{
1434 sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;
1435
1436 CHECK_ERROR();
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001437 CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w));
Elliott Hughes5b808042021-10-01 10:56:10 -07001438 ADJUST_LOCAL_OFFSET(dst, dstw);
1439 ADJUST_LOCAL_OFFSET(src1, src1w);
1440 ADJUST_LOCAL_OFFSET(src2, src2w);
1441
Elliott Hughes5b808042021-10-01 10:56:10 -07001442#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001443 if (op & SLJIT_32) {
Elliott Hughes5b808042021-10-01 10:56:10 -07001444 /* Most operations expect sign extended arguments. */
1445 flags |= INT_DATA | SIGNED_DATA;
1446 if (src1 & SLJIT_IMM)
1447 src1w = (sljit_s32)(src1w);
1448 if (src2 & SLJIT_IMM)
1449 src2w = (sljit_s32)(src2w);
1450 if (HAS_FLAGS(op))
1451 flags |= ALT_SIGN_EXT;
1452 }
1453#endif
1454 if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
1455 FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
1456
1457 switch (GET_OPCODE(op)) {
1458 case SLJIT_ADD:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001459 compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
1460
Elliott Hughes5b808042021-10-01 10:56:10 -07001461 if (TEST_ADD_FORM1(op))
1462 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);
1463
1464 if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
1465 if (TEST_SL_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001466 compiler->imm = (sljit_ins)src2w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001467 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
1468 }
1469 if (TEST_SL_IMM(src1, src1w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001470 compiler->imm = (sljit_ins)src1w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001471 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);
1472 }
1473 if (TEST_SH_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001474 compiler->imm = (sljit_ins)(src2w >> 16) & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001475 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
1476 }
1477 if (TEST_SH_IMM(src1, src1w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001478 compiler->imm = (sljit_ins)(src1w >> 16) & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001479 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
1480 }
1481 /* Range between -1 and -32768 is covered above. */
1482 if (TEST_ADD_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001483 compiler->imm = (sljit_ins)src2w & 0xffffffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001484 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
1485 }
1486 if (TEST_ADD_IMM(src1, src1w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001487 compiler->imm = (sljit_ins)src1w & 0xffffffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001488 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);
1489 }
1490 }
1491
1492#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001493 if ((op & (SLJIT_32 | SLJIT_SET_Z)) == (SLJIT_32 | SLJIT_SET_Z)) {
Elliott Hughes5b808042021-10-01 10:56:10 -07001494 if (TEST_SL_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001495 compiler->imm = (sljit_ins)src2w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001496 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src1, src1w, TMP_REG2, 0);
1497 }
1498 if (TEST_SL_IMM(src1, src1w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001499 compiler->imm = (sljit_ins)src1w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001500 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src2, src2w, TMP_REG2, 0);
1501 }
1502 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
1503 }
1504#endif
1505 if (HAS_FLAGS(op)) {
1506 if (TEST_SL_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001507 compiler->imm = (sljit_ins)src2w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001508 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
1509 }
1510 if (TEST_SL_IMM(src1, src1w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001511 compiler->imm = (sljit_ins)src1w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001512 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
1513 }
1514 }
1515 return emit_op(compiler, SLJIT_ADD, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);
1516
1517 case SLJIT_ADDC:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001518 compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
Elliott Hughes5b808042021-10-01 10:56:10 -07001519 return emit_op(compiler, SLJIT_ADDC, flags, dst, dstw, src1, src1w, src2, src2w);
1520
1521 case SLJIT_SUB:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001522 compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
1523
Elliott Hughes5b808042021-10-01 10:56:10 -07001524 if (GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_LESS_EQUAL) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001525 if (dst == TMP_REG2) {
Elliott Hughes5b808042021-10-01 10:56:10 -07001526 if (TEST_UL_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001527 compiler->imm = (sljit_ins)src2w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001528 return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
1529 }
1530 return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);
1531 }
1532
1533 if ((src2 & SLJIT_IMM) && src2w >= 0 && src2w <= (SIMM_MAX + 1)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001534 compiler->imm = (sljit_ins)src2w;
Elliott Hughes5b808042021-10-01 10:56:10 -07001535 return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
1536 }
1537 return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);
1538 }
1539
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001540 if (dst == TMP_REG2 && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
Elliott Hughes5b808042021-10-01 10:56:10 -07001541 if (TEST_SL_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001542 compiler->imm = (sljit_ins)src2w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001543 return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
1544 }
1545 return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, src2, src2w);
1546 }
1547
1548 if (TEST_SUB_FORM2(op)) {
1549 if ((src2 & SLJIT_IMM) && src2w >= -SIMM_MAX && src2w <= SIMM_MAX) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001550 compiler->imm = (sljit_ins)src2w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001551 return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
1552 }
1553 return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
1554 }
1555
1556 if (TEST_SUB_FORM3(op))
1557 return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);
1558
1559 if (TEST_SL_IMM(src2, -src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001560 compiler->imm = (sljit_ins)(-src2w) & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001561 return emit_op(compiler, SLJIT_ADD, flags | (!HAS_FLAGS(op) ? ALT_FORM2 : ALT_FORM3), dst, dstw, src1, src1w, TMP_REG2, 0);
1562 }
1563
1564 if (TEST_SL_IMM(src1, src1w) && !(op & SLJIT_SET_Z)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001565 compiler->imm = (sljit_ins)src1w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001566 return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);
1567 }
1568
1569 if (!HAS_FLAGS(op)) {
1570 if (TEST_SH_IMM(src2, -src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001571 compiler->imm = (sljit_ins)((-src2w) >> 16) & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001572 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
1573 }
1574 /* Range between -1 and -32768 is covered above. */
1575 if (TEST_ADD_IMM(src2, -src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001576 compiler->imm = (sljit_ins)-src2w;
Elliott Hughes5b808042021-10-01 10:56:10 -07001577 return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
1578 }
1579 }
1580
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001581 /* We know ALT_SIGN_EXT is set if it is an SLJIT_32 on 64 bit systems. */
Elliott Hughes5b808042021-10-01 10:56:10 -07001582 return emit_op(compiler, SLJIT_SUB, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);
1583
1584 case SLJIT_SUBC:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001585 compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
Elliott Hughes5b808042021-10-01 10:56:10 -07001586 return emit_op(compiler, SLJIT_SUBC, flags, dst, dstw, src1, src1w, src2, src2w);
1587
1588 case SLJIT_MUL:
1589#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001590 if (op & SLJIT_32)
Elliott Hughes5b808042021-10-01 10:56:10 -07001591 flags |= ALT_FORM2;
1592#endif
1593 if (!HAS_FLAGS(op)) {
1594 if (TEST_SL_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001595 compiler->imm = (sljit_ins)src2w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001596 return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
1597 }
1598 if (TEST_SL_IMM(src1, src1w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001599 compiler->imm = (sljit_ins)src1w & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001600 return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
1601 }
1602 }
1603 else
1604 FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
1605 return emit_op(compiler, SLJIT_MUL, flags, dst, dstw, src1, src1w, src2, src2w);
1606
1607 case SLJIT_AND:
1608 case SLJIT_OR:
1609 case SLJIT_XOR:
1610 /* Commutative unsigned operations. */
1611 if (!HAS_FLAGS(op) || GET_OPCODE(op) == SLJIT_AND) {
1612 if (TEST_UL_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001613 compiler->imm = (sljit_ins)src2w;
Elliott Hughes5b808042021-10-01 10:56:10 -07001614 return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
1615 }
1616 if (TEST_UL_IMM(src1, src1w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001617 compiler->imm = (sljit_ins)src1w;
Elliott Hughes5b808042021-10-01 10:56:10 -07001618 return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
1619 }
1620 if (TEST_UH_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001621 compiler->imm = (sljit_ins)(src2w >> 16) & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001622 return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
1623 }
1624 if (TEST_UH_IMM(src1, src1w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001625 compiler->imm = (sljit_ins)(src1w >> 16) & 0xffff;
Elliott Hughes5b808042021-10-01 10:56:10 -07001626 return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);
1627 }
1628 }
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001629 if (GET_OPCODE(op) != SLJIT_AND) {
1630 /* Unlike or and xor, the and resets unwanted bits as well. */
Elliott Hughes5b808042021-10-01 10:56:10 -07001631 if (TEST_UI_IMM(src2, src2w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001632 compiler->imm = (sljit_ins)src2w;
Elliott Hughes5b808042021-10-01 10:56:10 -07001633 return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
1634 }
1635 if (TEST_UI_IMM(src1, src1w)) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001636 compiler->imm = (sljit_ins)src1w;
Elliott Hughes5b808042021-10-01 10:56:10 -07001637 return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
1638 }
1639 }
1640 return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w);
1641
1642 case SLJIT_SHL:
1643 case SLJIT_LSHR:
1644 case SLJIT_ASHR:
1645#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001646 if (op & SLJIT_32)
Elliott Hughes5b808042021-10-01 10:56:10 -07001647 flags |= ALT_FORM2;
1648#endif
1649 if (src2 & SLJIT_IMM) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001650 compiler->imm = (sljit_ins)src2w;
Elliott Hughes5b808042021-10-01 10:56:10 -07001651 return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
1652 }
1653 return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w);
1654 }
1655
1656 return SLJIT_SUCCESS;
1657}
1658
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001659SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op,
1660 sljit_s32 src1, sljit_sw src1w,
1661 sljit_s32 src2, sljit_sw src2w)
1662{
1663 CHECK_ERROR();
1664 CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));
1665
1666#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
1667 || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
1668 compiler->skip_checks = 1;
1669#endif
1670 return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w);
1671}
1672
Elliott Hughes5b808042021-10-01 10:56:10 -07001673#undef TEST_ADD_FORM1
1674#undef TEST_SUB_FORM2
1675#undef TEST_SUB_FORM3
1676
1677SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
1678 sljit_s32 src, sljit_sw srcw)
1679{
1680 CHECK_ERROR();
1681 CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
1682 ADJUST_LOCAL_OFFSET(src, srcw);
1683
1684 switch (op) {
1685 case SLJIT_FAST_RETURN:
1686 if (FAST_IS_REG(src))
1687 FAIL_IF(push_inst(compiler, MTLR | S(src)));
1688 else {
1689 FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_REG2, 0, TMP_REG1, 0, src, srcw));
1690 FAIL_IF(push_inst(compiler, MTLR | S(TMP_REG2)));
1691 }
1692
1693 return push_inst(compiler, BLR);
1694 case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
1695 return SLJIT_SUCCESS;
1696 case SLJIT_PREFETCH_L1:
1697 case SLJIT_PREFETCH_L2:
1698 case SLJIT_PREFETCH_L3:
1699 case SLJIT_PREFETCH_ONCE:
1700 return emit_prefetch(compiler, src, srcw);
1701 }
1702
1703 return SLJIT_SUCCESS;
1704}
1705
1706SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
1707{
1708 CHECK_REG_INDEX(check_sljit_get_register_index(reg));
1709 return reg_map[reg];
1710}
1711
1712SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
1713{
1714 CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
1715 return freg_map[reg];
1716}
1717
1718SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001719 void *instruction, sljit_u32 size)
Elliott Hughes5b808042021-10-01 10:56:10 -07001720{
1721 CHECK_ERROR();
1722 CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
1723
1724 return push_inst(compiler, *(sljit_ins*)instruction);
1725}
1726
1727/* --------------------------------------------------------------------- */
1728/* Floating point operators */
1729/* --------------------------------------------------------------------- */
1730
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001731#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_32) >> 6))
1732#define SELECT_FOP(op, single, double) ((sljit_ins)((op & SLJIT_32) ? single : double))
Elliott Hughes5b808042021-10-01 10:56:10 -07001733
1734#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1735#define FLOAT_TMP_MEM_OFFSET (6 * sizeof(sljit_sw))
1736#else
1737#define FLOAT_TMP_MEM_OFFSET (2 * sizeof(sljit_sw))
1738
1739#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
1740#define FLOAT_TMP_MEM_OFFSET_LOW (2 * sizeof(sljit_sw))
1741#define FLOAT_TMP_MEM_OFFSET_HI (3 * sizeof(sljit_sw))
1742#else
1743#define FLOAT_TMP_MEM_OFFSET_LOW (3 * sizeof(sljit_sw))
1744#define FLOAT_TMP_MEM_OFFSET_HI (2 * sizeof(sljit_sw))
1745#endif
1746
1747#endif /* SLJIT_CONFIG_PPC_64 */
1748
1749static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
1750 sljit_s32 dst, sljit_sw dstw,
1751 sljit_s32 src, sljit_sw srcw)
1752{
1753 if (src & SLJIT_MEM) {
1754 /* We can ignore the temporary data store on the stack from caching point of view. */
1755 FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, TMP_REG1));
1756 src = TMP_FREG1;
1757 }
1758
1759#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1760 op = GET_OPCODE(op);
1761 FAIL_IF(push_inst(compiler, (op == SLJIT_CONV_S32_FROM_F64 ? FCTIWZ : FCTIDZ) | FD(TMP_FREG1) | FB(src)));
1762
1763 if (op == SLJIT_CONV_SW_FROM_F64) {
1764 if (FAST_IS_REG(dst)) {
1765 FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
1766 return emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1);
1767 }
1768 return emit_op_mem(compiler, DOUBLE_DATA, TMP_FREG1, dst, dstw, TMP_REG1);
1769 }
1770#else
1771 FAIL_IF(push_inst(compiler, FCTIWZ | FD(TMP_FREG1) | FB(src)));
1772#endif
1773
1774 if (FAST_IS_REG(dst)) {
1775 FAIL_IF(load_immediate(compiler, TMP_REG1, FLOAT_TMP_MEM_OFFSET));
1776 FAIL_IF(push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(SLJIT_SP) | B(TMP_REG1)));
1777 return emit_op_mem(compiler, INT_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1);
1778 }
1779
1780 SLJIT_ASSERT(dst & SLJIT_MEM);
1781
1782 if (dst & OFFS_REG_MASK) {
1783 dstw &= 0x3;
1784 if (dstw) {
1785#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001786 FAIL_IF(push_inst(compiler, RLWINM | S(OFFS_REG(dst)) | A(TMP_REG1) | ((sljit_ins)dstw << 11) | ((31 - (sljit_ins)dstw) << 1)));
Elliott Hughes5b808042021-10-01 10:56:10 -07001787#else
1788 FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, OFFS_REG(dst), dstw, 63 - dstw, 1)));
1789#endif
1790 dstw = TMP_REG1;
1791 }
1792 else
1793 dstw = OFFS_REG(dst);
1794 }
1795 else {
1796 if ((dst & REG_MASK) && !dstw) {
1797 dstw = dst & REG_MASK;
1798 dst = 0;
1799 }
1800 else {
1801 /* This works regardless we have SLJIT_MEM1 or SLJIT_MEM0. */
1802 FAIL_IF(load_immediate(compiler, TMP_REG1, dstw));
1803 dstw = TMP_REG1;
1804 }
1805 }
1806
1807 return push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(dst & REG_MASK) | B(dstw));
1808}
1809
1810static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
1811 sljit_s32 dst, sljit_sw dstw,
1812 sljit_s32 src, sljit_sw srcw)
1813{
1814#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
1815
1816 sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
1817
1818 if (src & SLJIT_IMM) {
1819 if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
1820 srcw = (sljit_s32)srcw;
1821 FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
1822 src = TMP_REG1;
1823 }
1824 else if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) {
1825 if (FAST_IS_REG(src))
1826 FAIL_IF(push_inst(compiler, EXTSW | S(src) | A(TMP_REG1)));
1827 else
1828 FAIL_IF(emit_op_mem(compiler, INT_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
1829 src = TMP_REG1;
1830 }
1831
1832 if (FAST_IS_REG(src)) {
1833 FAIL_IF(emit_op_mem(compiler, WORD_DATA, src, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
1834 FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
1835 }
1836 else
1837 FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src, srcw, TMP_REG1));
1838
1839 FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
1840
1841 if (dst & SLJIT_MEM)
1842 return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001843 if (op & SLJIT_32)
Elliott Hughes5b808042021-10-01 10:56:10 -07001844 return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r));
1845 return SLJIT_SUCCESS;
1846
1847#else
1848
1849 sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
1850 sljit_s32 invert_sign = 1;
1851
1852 if (src & SLJIT_IMM) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001853 FAIL_IF(load_immediate(compiler, TMP_REG1, srcw ^ (sljit_sw)0x80000000));
Elliott Hughes5b808042021-10-01 10:56:10 -07001854 src = TMP_REG1;
1855 invert_sign = 0;
1856 }
1857 else if (!FAST_IS_REG(src)) {
1858 FAIL_IF(emit_op_mem(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
1859 src = TMP_REG1;
1860 }
1861
1862 /* First, a special double floating point value is constructed: (2^53 + (input xor (2^31)))
1863 The double precision format has exactly 53 bit precision, so the lower 32 bit represents
1864 the lower 32 bit of such value. The result of xor 2^31 is the same as adding 0x80000000
1865 to the input, which shifts it into the 0 - 0xffffffff range. To get the converted floating
1866 point value, we need to substract 2^53 + 2^31 from the constructed value. */
1867 FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330));
1868 if (invert_sign)
1869 FAIL_IF(push_inst(compiler, XORIS | S(src) | A(TMP_REG1) | 0x8000));
1870 FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_HI, TMP_REG1));
1871 FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW, TMP_REG2));
1872 FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG1) | A(0) | 0x8000));
1873 FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
1874 FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW, TMP_REG2));
1875 FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG2, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
1876
1877 FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2)));
1878
1879 if (dst & SLJIT_MEM)
1880 return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001881 if (op & SLJIT_32)
Elliott Hughes5b808042021-10-01 10:56:10 -07001882 return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r));
1883 return SLJIT_SUCCESS;
1884
1885#endif
1886}
1887
1888static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
1889 sljit_s32 src1, sljit_sw src1w,
1890 sljit_s32 src2, sljit_sw src2w)
1891{
1892 if (src1 & SLJIT_MEM) {
1893 FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, TMP_REG1));
1894 src1 = TMP_FREG1;
1895 }
1896
1897 if (src2 & SLJIT_MEM) {
1898 FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG2));
1899 src2 = TMP_FREG2;
1900 }
1901
1902 return push_inst(compiler, FCMPU | CRD(4) | FA(src1) | FB(src2));
1903}
1904
1905SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
1906 sljit_s32 dst, sljit_sw dstw,
1907 sljit_s32 src, sljit_sw srcw)
1908{
1909 sljit_s32 dst_r;
1910
1911 CHECK_ERROR();
1912
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001913 SLJIT_COMPILE_ASSERT((SLJIT_32 == 0x100) && !(DOUBLE_DATA & 0x4), float_transfer_bit_error);
Elliott Hughes5b808042021-10-01 10:56:10 -07001914 SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
1915
1916 if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001917 op ^= SLJIT_32;
Elliott Hughes5b808042021-10-01 10:56:10 -07001918
1919 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
1920
1921 if (src & SLJIT_MEM) {
1922 FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_r, src, srcw, TMP_REG1));
1923 src = dst_r;
1924 }
1925
1926 switch (GET_OPCODE(op)) {
1927 case SLJIT_CONV_F64_FROM_F32:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07001928 op ^= SLJIT_32;
1929 if (op & SLJIT_32) {
Elliott Hughes5b808042021-10-01 10:56:10 -07001930 FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(src)));
1931 break;
1932 }
1933 /* Fall through. */
1934 case SLJIT_MOV_F64:
1935 if (src != dst_r) {
1936 if (dst_r != TMP_FREG1)
1937 FAIL_IF(push_inst(compiler, FMR | FD(dst_r) | FB(src)));
1938 else
1939 dst_r = src;
1940 }
1941 break;
1942 case SLJIT_NEG_F64:
1943 FAIL_IF(push_inst(compiler, FNEG | FD(dst_r) | FB(src)));
1944 break;
1945 case SLJIT_ABS_F64:
1946 FAIL_IF(push_inst(compiler, FABS | FD(dst_r) | FB(src)));
1947 break;
1948 }
1949
1950 if (dst & SLJIT_MEM)
1951 FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op), dst_r, dst, dstw, TMP_REG1));
1952 return SLJIT_SUCCESS;
1953}
1954
1955SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
1956 sljit_s32 dst, sljit_sw dstw,
1957 sljit_s32 src1, sljit_sw src1w,
1958 sljit_s32 src2, sljit_sw src2w)
1959{
1960 sljit_s32 dst_r;
1961
1962 CHECK_ERROR();
1963 CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
1964 ADJUST_LOCAL_OFFSET(dst, dstw);
1965 ADJUST_LOCAL_OFFSET(src1, src1w);
1966 ADJUST_LOCAL_OFFSET(src2, src2w);
1967
1968 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2;
1969
1970 if (src1 & SLJIT_MEM) {
1971 FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, TMP_REG1));
1972 src1 = TMP_FREG1;
1973 }
1974
1975 if (src2 & SLJIT_MEM) {
1976 FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG2));
1977 src2 = TMP_FREG2;
1978 }
1979
1980 switch (GET_OPCODE(op)) {
1981 case SLJIT_ADD_F64:
1982 FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADD) | FD(dst_r) | FA(src1) | FB(src2)));
1983 break;
1984
1985 case SLJIT_SUB_F64:
1986 FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUB) | FD(dst_r) | FA(src1) | FB(src2)));
1987 break;
1988
1989 case SLJIT_MUL_F64:
1990 FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMUL) | FD(dst_r) | FA(src1) | FC(src2) /* FMUL use FC as src2 */));
1991 break;
1992
1993 case SLJIT_DIV_F64:
1994 FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIV) | FD(dst_r) | FA(src1) | FB(src2)));
1995 break;
1996 }
1997
1998 if (dst & SLJIT_MEM)
1999 FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, TMP_REG1));
2000
2001 return SLJIT_SUCCESS;
2002}
2003
2004#undef SELECT_FOP
2005
2006/* --------------------------------------------------------------------- */
2007/* Other instructions */
2008/* --------------------------------------------------------------------- */
2009
2010SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
2011{
2012 CHECK_ERROR();
2013 CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
2014 ADJUST_LOCAL_OFFSET(dst, dstw);
2015
2016 if (FAST_IS_REG(dst))
2017 return push_inst(compiler, MFLR | D(dst));
2018
2019 /* Memory. */
2020 FAIL_IF(push_inst(compiler, MFLR | D(TMP_REG2)));
2021 return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
2022}
2023
2024/* --------------------------------------------------------------------- */
2025/* Conditional instructions */
2026/* --------------------------------------------------------------------- */
2027
2028SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
2029{
2030 struct sljit_label *label;
2031
2032 CHECK_ERROR_PTR();
2033 CHECK_PTR(check_sljit_emit_label(compiler));
2034
2035 if (compiler->last_label && compiler->last_label->size == compiler->size)
2036 return compiler->last_label;
2037
2038 label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
2039 PTR_FAIL_IF(!label);
2040 set_label(label, compiler);
2041 return label;
2042}
2043
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002044static sljit_ins get_bo_bi_flags(struct sljit_compiler *compiler, sljit_s32 type)
Elliott Hughes5b808042021-10-01 10:56:10 -07002045{
2046 switch (type) {
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002047 case SLJIT_NOT_CARRY:
2048 if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB)
2049 return (4 << 21) | (2 << 16);
2050 /* fallthrough */
2051
Elliott Hughes5b808042021-10-01 10:56:10 -07002052 case SLJIT_EQUAL:
2053 return (12 << 21) | (2 << 16);
2054
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002055 case SLJIT_CARRY:
2056 if (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB)
2057 return (12 << 21) | (2 << 16);
2058 /* fallthrough */
2059
Elliott Hughes5b808042021-10-01 10:56:10 -07002060 case SLJIT_NOT_EQUAL:
2061 return (4 << 21) | (2 << 16);
2062
2063 case SLJIT_LESS:
2064 case SLJIT_SIG_LESS:
2065 return (12 << 21) | (0 << 16);
2066
2067 case SLJIT_GREATER_EQUAL:
2068 case SLJIT_SIG_GREATER_EQUAL:
2069 return (4 << 21) | (0 << 16);
2070
2071 case SLJIT_GREATER:
2072 case SLJIT_SIG_GREATER:
2073 return (12 << 21) | (1 << 16);
2074
2075 case SLJIT_LESS_EQUAL:
2076 case SLJIT_SIG_LESS_EQUAL:
2077 return (4 << 21) | (1 << 16);
2078
2079 case SLJIT_LESS_F64:
2080 return (12 << 21) | ((4 + 0) << 16);
2081
2082 case SLJIT_GREATER_EQUAL_F64:
2083 return (4 << 21) | ((4 + 0) << 16);
2084
2085 case SLJIT_GREATER_F64:
2086 return (12 << 21) | ((4 + 1) << 16);
2087
2088 case SLJIT_LESS_EQUAL_F64:
2089 return (4 << 21) | ((4 + 1) << 16);
2090
2091 case SLJIT_OVERFLOW:
2092 return (12 << 21) | (3 << 16);
2093
2094 case SLJIT_NOT_OVERFLOW:
2095 return (4 << 21) | (3 << 16);
2096
2097 case SLJIT_EQUAL_F64:
2098 return (12 << 21) | ((4 + 2) << 16);
2099
2100 case SLJIT_NOT_EQUAL_F64:
2101 return (4 << 21) | ((4 + 2) << 16);
2102
2103 case SLJIT_UNORDERED_F64:
2104 return (12 << 21) | ((4 + 3) << 16);
2105
2106 case SLJIT_ORDERED_F64:
2107 return (4 << 21) | ((4 + 3) << 16);
2108
2109 default:
2110 SLJIT_ASSERT(type >= SLJIT_JUMP && type <= SLJIT_CALL_CDECL);
2111 return (20 << 21);
2112 }
2113}
2114
2115SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
2116{
2117 struct sljit_jump *jump;
2118 sljit_ins bo_bi_flags;
2119
2120 CHECK_ERROR_PTR();
2121 CHECK_PTR(check_sljit_emit_jump(compiler, type));
2122
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002123 bo_bi_flags = get_bo_bi_flags(compiler, type & 0xff);
Elliott Hughes5b808042021-10-01 10:56:10 -07002124 if (!bo_bi_flags)
2125 return NULL;
2126
2127 jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
2128 PTR_FAIL_IF(!jump);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002129 set_jump(jump, compiler, (sljit_u32)type & SLJIT_REWRITABLE_JUMP);
Elliott Hughes5b808042021-10-01 10:56:10 -07002130 type &= 0xff;
2131
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002132 if (type == SLJIT_CARRY || type == SLJIT_NOT_CARRY)
2133 PTR_FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG1) | A(TMP_ZERO) | B(TMP_ZERO)));
2134
Elliott Hughes5b808042021-10-01 10:56:10 -07002135 /* In PPC, we don't need to touch the arguments. */
2136 if (type < SLJIT_JUMP)
2137 jump->flags |= IS_COND;
2138#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
2139 if (type >= SLJIT_CALL)
2140 jump->flags |= IS_CALL;
2141#endif
2142
2143 PTR_FAIL_IF(emit_const(compiler, TMP_CALL_REG, 0));
2144 PTR_FAIL_IF(push_inst(compiler, MTCTR | S(TMP_CALL_REG)));
2145 jump->addr = compiler->size;
2146 PTR_FAIL_IF(push_inst(compiler, BCCTR | bo_bi_flags | (type >= SLJIT_FAST_CALL ? 1 : 0)));
2147 return jump;
2148}
2149
2150SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
2151 sljit_s32 arg_types)
2152{
2153 CHECK_ERROR_PTR();
2154 CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
2155
2156#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
2157 PTR_FAIL_IF(call_with_args(compiler, arg_types, NULL));
2158#endif
2159
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002160 if (type & SLJIT_CALL_RETURN) {
2161 PTR_FAIL_IF(emit_stack_frame_release(compiler));
2162 type = SLJIT_JUMP | (type & SLJIT_REWRITABLE_JUMP);
2163 }
2164
Elliott Hughes5b808042021-10-01 10:56:10 -07002165#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
2166 || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
2167 compiler->skip_checks = 1;
2168#endif
2169
2170 return sljit_emit_jump(compiler, type);
2171}
2172
2173SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
2174{
2175 struct sljit_jump *jump = NULL;
2176 sljit_s32 src_r;
2177
2178 CHECK_ERROR();
2179 CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
2180 ADJUST_LOCAL_OFFSET(src, srcw);
2181
2182 if (FAST_IS_REG(src)) {
2183#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002184 if (type >= SLJIT_CALL && src != TMP_CALL_REG) {
Elliott Hughes5b808042021-10-01 10:56:10 -07002185 FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src)));
2186 src_r = TMP_CALL_REG;
2187 }
2188 else
2189 src_r = src;
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002190#else /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
Elliott Hughes5b808042021-10-01 10:56:10 -07002191 src_r = src;
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002192#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
Elliott Hughes5b808042021-10-01 10:56:10 -07002193 } else if (src & SLJIT_IMM) {
2194 /* These jumps are converted to jump/call instructions when possible. */
2195 jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
2196 FAIL_IF(!jump);
2197 set_jump(jump, compiler, JUMP_ADDR);
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002198 jump->u.target = (sljit_uw)srcw;
2199
Elliott Hughes5b808042021-10-01 10:56:10 -07002200#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
2201 if (type >= SLJIT_CALL)
2202 jump->flags |= IS_CALL;
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002203#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
2204
Elliott Hughes5b808042021-10-01 10:56:10 -07002205 FAIL_IF(emit_const(compiler, TMP_CALL_REG, 0));
2206 src_r = TMP_CALL_REG;
2207 }
2208 else {
2209 FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_CALL_REG, 0, TMP_REG1, 0, src, srcw));
2210 src_r = TMP_CALL_REG;
2211 }
2212
2213 FAIL_IF(push_inst(compiler, MTCTR | S(src_r)));
2214 if (jump)
2215 jump->addr = compiler->size;
2216 return push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0));
2217}
2218
2219SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
2220 sljit_s32 arg_types,
2221 sljit_s32 src, sljit_sw srcw)
2222{
2223 CHECK_ERROR();
2224 CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
2225
Elliott Hughes5b808042021-10-01 10:56:10 -07002226 if (src & SLJIT_MEM) {
2227 ADJUST_LOCAL_OFFSET(src, srcw);
2228 FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_CALL_REG, 0, TMP_REG1, 0, src, srcw));
2229 src = TMP_CALL_REG;
2230 }
2231
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002232 if (type & SLJIT_CALL_RETURN) {
2233 if (src >= SLJIT_FIRST_SAVED_REG && src <= SLJIT_S0) {
2234 FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src)));
2235 src = TMP_CALL_REG;
2236 }
2237
2238 FAIL_IF(emit_stack_frame_release(compiler));
2239 type = SLJIT_JUMP;
2240 }
2241
2242#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
Elliott Hughes5b808042021-10-01 10:56:10 -07002243 FAIL_IF(call_with_args(compiler, arg_types, &src));
2244#endif
2245
2246#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
2247 || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
2248 compiler->skip_checks = 1;
2249#endif
2250
2251 return sljit_emit_ijump(compiler, type, src, srcw);
2252}
2253
2254SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
2255 sljit_s32 dst, sljit_sw dstw,
2256 sljit_s32 type)
2257{
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002258 sljit_s32 reg, invert;
2259 sljit_u32 bit, from_xer;
Elliott Hughes5b808042021-10-01 10:56:10 -07002260 sljit_s32 saved_op = op;
2261 sljit_sw saved_dstw = dstw;
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002262#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
2263 sljit_s32 input_flags = ((op & SLJIT_32) || op == SLJIT_MOV32) ? INT_DATA : WORD_DATA;
2264#else
2265 sljit_s32 input_flags = WORD_DATA;
2266#endif
Elliott Hughes5b808042021-10-01 10:56:10 -07002267
2268 CHECK_ERROR();
2269 CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
2270 ADJUST_LOCAL_OFFSET(dst, dstw);
2271
Elliott Hughes5b808042021-10-01 10:56:10 -07002272 op = GET_OPCODE(op);
2273 reg = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;
2274
2275 if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
2276 FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, dst, dstw, TMP_REG1));
2277
2278 invert = 0;
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002279 bit = 0;
2280 from_xer = 0;
Elliott Hughes5b808042021-10-01 10:56:10 -07002281
2282 switch (type & 0xff) {
2283 case SLJIT_LESS:
2284 case SLJIT_SIG_LESS:
2285 break;
2286
2287 case SLJIT_GREATER_EQUAL:
2288 case SLJIT_SIG_GREATER_EQUAL:
2289 invert = 1;
2290 break;
2291
2292 case SLJIT_GREATER:
2293 case SLJIT_SIG_GREATER:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002294 bit = 1;
Elliott Hughes5b808042021-10-01 10:56:10 -07002295 break;
2296
2297 case SLJIT_LESS_EQUAL:
2298 case SLJIT_SIG_LESS_EQUAL:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002299 bit = 1;
Elliott Hughes5b808042021-10-01 10:56:10 -07002300 invert = 1;
2301 break;
2302
2303 case SLJIT_EQUAL:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002304 bit = 2;
Elliott Hughes5b808042021-10-01 10:56:10 -07002305 break;
2306
2307 case SLJIT_NOT_EQUAL:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002308 bit = 2;
Elliott Hughes5b808042021-10-01 10:56:10 -07002309 invert = 1;
2310 break;
2311
2312 case SLJIT_OVERFLOW:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002313 from_xer = 1;
2314 bit = 1;
Elliott Hughes5b808042021-10-01 10:56:10 -07002315 break;
2316
2317 case SLJIT_NOT_OVERFLOW:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002318 from_xer = 1;
2319 bit = 1;
Elliott Hughes5b808042021-10-01 10:56:10 -07002320 invert = 1;
2321 break;
2322
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002323 case SLJIT_CARRY:
2324 from_xer = 1;
2325 bit = 2;
2326 invert = (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_SUB) != 0;
2327 break;
2328
2329 case SLJIT_NOT_CARRY:
2330 from_xer = 1;
2331 bit = 2;
2332 invert = (compiler->status_flags_state & SLJIT_CURRENT_FLAGS_ADD) != 0;
2333 break;
2334
Elliott Hughes5b808042021-10-01 10:56:10 -07002335 case SLJIT_LESS_F64:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002336 bit = 4 + 0;
Elliott Hughes5b808042021-10-01 10:56:10 -07002337 break;
2338
2339 case SLJIT_GREATER_EQUAL_F64:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002340 bit = 4 + 0;
Elliott Hughes5b808042021-10-01 10:56:10 -07002341 invert = 1;
2342 break;
2343
2344 case SLJIT_GREATER_F64:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002345 bit = 4 + 1;
Elliott Hughes5b808042021-10-01 10:56:10 -07002346 break;
2347
2348 case SLJIT_LESS_EQUAL_F64:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002349 bit = 4 + 1;
Elliott Hughes5b808042021-10-01 10:56:10 -07002350 invert = 1;
2351 break;
2352
2353 case SLJIT_EQUAL_F64:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002354 bit = 4 + 2;
Elliott Hughes5b808042021-10-01 10:56:10 -07002355 break;
2356
2357 case SLJIT_NOT_EQUAL_F64:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002358 bit = 4 + 2;
Elliott Hughes5b808042021-10-01 10:56:10 -07002359 invert = 1;
2360 break;
2361
2362 case SLJIT_UNORDERED_F64:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002363 bit = 4 + 3;
Elliott Hughes5b808042021-10-01 10:56:10 -07002364 break;
2365
2366 case SLJIT_ORDERED_F64:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002367 bit = 4 + 3;
Elliott Hughes5b808042021-10-01 10:56:10 -07002368 invert = 1;
2369 break;
2370
2371 default:
2372 SLJIT_UNREACHABLE();
2373 break;
2374 }
2375
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002376 FAIL_IF(push_inst(compiler, (from_xer ? MFXER : MFCR) | D(reg)));
2377 FAIL_IF(push_inst(compiler, RLWINM | S(reg) | A(reg) | ((1 + bit) << 11) | (31 << 6) | (31 << 1)));
Elliott Hughes5b808042021-10-01 10:56:10 -07002378
2379 if (invert)
2380 FAIL_IF(push_inst(compiler, XORI | S(reg) | A(reg) | 0x1));
2381
2382 if (op < SLJIT_ADD) {
2383 if (!(dst & SLJIT_MEM))
2384 return SLJIT_SUCCESS;
2385 return emit_op_mem(compiler, input_flags, reg, dst, dstw, TMP_REG1);
2386 }
2387
2388#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
2389 || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
2390 compiler->skip_checks = 1;
2391#endif
2392 if (dst & SLJIT_MEM)
2393 return sljit_emit_op2(compiler, saved_op, dst, saved_dstw, TMP_REG1, 0, TMP_REG2, 0);
2394 return sljit_emit_op2(compiler, saved_op, dst, 0, dst, 0, TMP_REG2, 0);
2395}
2396
2397SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
2398 sljit_s32 dst_reg,
2399 sljit_s32 src, sljit_sw srcw)
2400{
2401 CHECK_ERROR();
2402 CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
2403
2404 return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);;
2405}
2406
2407SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
2408 sljit_s32 reg,
2409 sljit_s32 mem, sljit_sw memw)
2410{
2411 sljit_s32 mem_flags;
2412 sljit_ins inst;
2413
2414 CHECK_ERROR();
2415 CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));
2416
2417 if (type & SLJIT_MEM_POST)
2418 return SLJIT_ERR_UNSUPPORTED;
2419
2420 switch (type & 0xff) {
2421 case SLJIT_MOV:
2422 case SLJIT_MOV_P:
2423#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
2424 case SLJIT_MOV_U32:
2425 case SLJIT_MOV_S32:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002426 case SLJIT_MOV32:
Elliott Hughes5b808042021-10-01 10:56:10 -07002427#endif
2428 mem_flags = WORD_DATA;
2429 break;
2430
2431#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
2432 case SLJIT_MOV_U32:
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002433 case SLJIT_MOV32:
Elliott Hughes5b808042021-10-01 10:56:10 -07002434 mem_flags = INT_DATA;
2435 break;
2436
2437 case SLJIT_MOV_S32:
2438 mem_flags = INT_DATA;
2439
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002440 if (!(type & SLJIT_MEM_STORE) && !(type & SLJIT_32)) {
Elliott Hughes5b808042021-10-01 10:56:10 -07002441 if (mem & OFFS_REG_MASK)
2442 mem_flags |= SIGNED_DATA;
2443 else
2444 return SLJIT_ERR_UNSUPPORTED;
2445 }
2446 break;
2447#endif
2448
2449 case SLJIT_MOV_U8:
2450 case SLJIT_MOV_S8:
2451 mem_flags = BYTE_DATA;
2452 break;
2453
2454 case SLJIT_MOV_U16:
2455 mem_flags = HALF_DATA;
2456 break;
2457
2458 case SLJIT_MOV_S16:
2459 mem_flags = HALF_DATA | SIGNED_DATA;
2460 break;
2461
2462 default:
2463 SLJIT_UNREACHABLE();
2464 mem_flags = WORD_DATA;
2465 break;
2466 }
2467
2468 if (!(type & SLJIT_MEM_STORE))
2469 mem_flags |= LOAD_DATA;
2470
2471 if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
2472 if (memw != 0)
2473 return SLJIT_ERR_UNSUPPORTED;
2474
2475 if (type & SLJIT_MEM_SUPP)
2476 return SLJIT_SUCCESS;
2477
2478 inst = updated_data_transfer_insts[mem_flags | INDEXED];
2479 FAIL_IF(push_inst(compiler, INST_CODE_AND_DST(inst, 0, reg) | A(mem & REG_MASK) | B(OFFS_REG(mem))));
2480 }
2481 else {
2482 if (memw > SIMM_MAX || memw < SIMM_MIN)
2483 return SLJIT_ERR_UNSUPPORTED;
2484
2485 inst = updated_data_transfer_insts[mem_flags];
2486
2487#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
2488 if ((inst & INT_ALIGNED) && (memw & 0x3) != 0)
2489 return SLJIT_ERR_UNSUPPORTED;
2490#endif
2491
2492 if (type & SLJIT_MEM_SUPP)
2493 return SLJIT_SUCCESS;
2494
2495 FAIL_IF(push_inst(compiler, INST_CODE_AND_DST(inst, 0, reg) | A(mem & REG_MASK) | IMM(memw)));
2496 }
2497
2498 if ((mem_flags & LOAD_DATA) && (type & 0xff) == SLJIT_MOV_S8)
2499 return push_inst(compiler, EXTSB | S(reg) | A(reg));
2500 return SLJIT_SUCCESS;
2501}
2502
2503SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type,
2504 sljit_s32 freg,
2505 sljit_s32 mem, sljit_sw memw)
2506{
2507 sljit_s32 mem_flags;
2508 sljit_ins inst;
2509
2510 CHECK_ERROR();
2511 CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw));
2512
2513 if (type & SLJIT_MEM_POST)
2514 return SLJIT_ERR_UNSUPPORTED;
2515
2516 if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
2517 if (memw != 0)
2518 return SLJIT_ERR_UNSUPPORTED;
2519 }
2520 else {
2521 if (memw > SIMM_MAX || memw < SIMM_MIN)
2522 return SLJIT_ERR_UNSUPPORTED;
2523 }
2524
2525 if (type & SLJIT_MEM_SUPP)
2526 return SLJIT_SUCCESS;
2527
2528 mem_flags = FLOAT_DATA(type);
2529
2530 if (!(type & SLJIT_MEM_STORE))
2531 mem_flags |= LOAD_DATA;
2532
2533 if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
2534 inst = updated_data_transfer_insts[mem_flags | INDEXED];
2535 return push_inst(compiler, INST_CODE_AND_DST(inst, DOUBLE_DATA, freg) | A(mem & REG_MASK) | B(OFFS_REG(mem)));
2536 }
2537
2538 inst = updated_data_transfer_insts[mem_flags];
2539 return push_inst(compiler, INST_CODE_AND_DST(inst, DOUBLE_DATA, freg) | A(mem & REG_MASK) | IMM(memw));
2540}
2541
2542SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
2543{
2544 struct sljit_const *const_;
2545 sljit_s32 dst_r;
2546
2547 CHECK_ERROR_PTR();
2548 CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
2549 ADJUST_LOCAL_OFFSET(dst, dstw);
2550
2551 const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
2552 PTR_FAIL_IF(!const_);
2553 set_const(const_, compiler);
2554
2555 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
2556 PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));
2557
2558 if (dst & SLJIT_MEM)
2559 PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
2560
2561 return const_;
2562}
2563
2564SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
2565{
2566 struct sljit_put_label *put_label;
2567 sljit_s32 dst_r;
2568
2569 CHECK_ERROR_PTR();
2570 CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
2571 ADJUST_LOCAL_OFFSET(dst, dstw);
2572
2573 put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
2574 PTR_FAIL_IF(!put_label);
2575 set_put_label(put_label, compiler, 0);
2576
2577 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
2578#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
2579 PTR_FAIL_IF(emit_const(compiler, dst_r, 0));
2580#else
Elliott Hughes4e19c8e2022-04-15 15:11:02 -07002581 PTR_FAIL_IF(push_inst(compiler, (sljit_ins)dst_r));
Elliott Hughes5b808042021-10-01 10:56:10 -07002582 compiler->size += 4;
2583#endif
2584
2585 if (dst & SLJIT_MEM)
2586 PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
2587
2588 return put_label;
2589}