2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 #define POWER_RC 0x00000001U
20 #define POWER_OE 0x00000400U
21 #define POWER_CMP_L 0x00200000U
23 #define POWER_MULLI 0x1c000000U
24 #define POWER_SUBFIC 0x20000000U
25 #define POWER_CMPLI 0x28000000U
26 #define POWER_CMPI 0x2c000000U
27 #define POWER_ADDIC 0x30000000U
28 #define POWER_ADDIC_ 0x34000000U
29 #define POWER_ADDI 0x38000000U
30 #define POWER_ADDIS 0x3c000000U
31 #define POWER_BGE 0x40800000U
32 #define POWER_BLE 0x40810000U
33 #define POWER_BNE 0x40820000U
34 #define POWER_BNS 0x40830000U
35 #define POWER_BLT 0x41800000U
36 #define POWER_BGT 0x41810000U
37 #define POWER_BEQ 0x41820000U
38 #define POWER_BSO 0x41830000U
39 #define POWER_B 0x48000000U
40 #define POWER_BLR 0x4e800020U
41 #define POWER_BCTR 0x4e800420U
42 #define POWER_BCTRL 0x4e800421U
43 #define POWER_RLWINM 0x54000000U
44 #define POWER_RLWNM 0x5c000000U
45 #define POWER_ORI 0x60000000U
46 #define POWER_ORIS 0x64000000U
47 #define POWER_XORI 0x68000000U
48 #define POWER_XORIS 0x6c000000U
49 #define POWER_ANDI_ 0x70000000U
50 #define POWER_ANDIS_ 0x74000000U
51 #define POWER_RLDICL 0x78000000U
52 #define POWER_RLDICR 0x78000004U
53 #define POWER_RLDCL 0x78000010U
54 #define POWER_RLDCR 0x78000012U
55 #define POWER_CMP 0x7c000000U
56 #define POWER_SUBFC 0x7c000010U
57 #define POWER_ADDC 0x7c000014U
58 #define POWER_ISELLT 0x7c00001eU
59 #define POWER_LDX 0x7c00002aU
60 #define POWER_LWZX 0x7c00002eU
61 #define POWER_SLW 0x7c000030U
62 #define POWER_CNTLZW 0x7c000034U
63 #define POWER_SLD 0x7c000036U
64 #define POWER_AND 0x7c000038U
65 #define POWER_CMPL 0x7c000040U
66 #define POWER_SUBF 0x7c000050U
67 #define POWER_ISELGT 0x7c00005eU
68 #define POWER_CNTLZD 0x7c000074U
69 #define POWER_ANDC 0x7c000078U
70 #define POWER_ISELEQ 0x7c00009eU
71 #define POWER_LBZX 0x7c0000aeU
72 #define POWER_NEG 0x7c0000d0U
73 #define POWER_ISELSO 0x7c0000deU
74 #define POWER_NOR 0x7c0000f8U
75 #define POWER_SUBFE 0x7c000110U
76 #define POWER_ADDE 0x7c000114U
77 #define POWER_STDX 0x7c00012aU
78 #define POWER_STWX 0x7c00012eU
79 #define POWER_SUBFZE 0x7c000190U
80 #define POWER_ADDZE 0x7c000194U
81 #define POWER_STBX 0x7c0001aeU
82 #define POWER_MULLD 0x7c0001d2U
83 #define POWER_ADDME 0x7c0001d4U
84 #define POWER_MULLW 0x7c0001d6U
85 #define POWER_MODUD 0x7c000212U
86 #define POWER_MODUW 0x7c000216U
87 #define POWER_ADD 0x7c000214U
88 #define POWER_LXVX 0x7c000218U
89 #define POWER_LHZX 0x7c00022eU
90 #define POWER_EQV 0x7c000238U
91 #define POWER_XOR 0x7c000278U
92 #define POWER_LWAX 0x7c0002aaU
93 #define POWER_LHAX 0x7c0002aeU
94 #define POWER_POPCNTW 0x7c0002f4U
95 #define POWER_STXVX 0x7c000318U
96 #define POWER_STHX 0x7c00032eU
97 #define POWER_ORC 0x7c000338U
98 #define POWER_OR 0x7c000378U
99 #define POWER_DIVDU 0x7c000392U
100 #define POWER_DIVWU 0x7c000396U
101 #define POWER_NAND 0x7c0003b8U
102 #define POWER_DIVD 0x7c0003d2U
103 #define POWER_DIVW 0x7c0003d6U
104 #define POWER_POPCNTD 0x7c0003f4U
105 #define POWER_LFSX 0x7c00042eU
106 #define POWER_SRW 0x7c000430U
107 #define POWER_CNTTZW 0x7c000434U
108 #define POWER_SRD 0x7c000436U
109 #define POWER_CNTTZD 0x7c000474U
110 #define POWER_LXSDX 0x7c000498U
111 #define POWER_LFDX 0x7c0004aeU
112 #define POWER_STFSX 0x7c00052eU
113 #define POWER_STXSDX 0x7c000598U
114 #define POWER_STFDX 0x7c0005aeU
115 #define POWER_MODSD 0x7c000612U
116 #define POWER_MODSW 0x7c000616U
117 #define POWER_SRAW 0x7c000630U
118 #define POWER_SRAD 0x7c000634U
119 #define POWER_SRAWI 0x7c000670U
120 #define POWER_SRADI 0x7c000674U
121 #define POWER_EXTSH 0x7c000734U
122 #define POWER_EXTSB 0x7c000774U
123 #define POWER_EXTSW 0x7c0007b4U
124 #define POWER_MFXER 0x7c0102a6U
125 #define POWER_MTXER 0x7c0103a6U
126 #define POWER_MFLR 0x7c0802a6U
127 #define POWER_MTLR 0x7c0803a6U
128 #define POWER_MFCTR 0x7c0902a6U
129 #define POWER_MTCTR 0x7c0903a6U
130 #define POWER_LWZ 0x80000000U
131 #define POWER_LBZ 0x88000000U
132 #define POWER_STW 0x90000000U
133 #define POWER_STWU 0x94000000U
134 #define POWER_STB 0x98000000U
135 #define POWER_STBU 0x9c000000U
136 #define POWER_LHZ 0xa0000000U
137 #define POWER_LHA 0xa8000000U
138 #define POWER_STH 0xb0000000U
139 #define POWER_STHU 0xb4000000U
140 #define POWER_LFS 0xc0000000U
141 #define POWER_STFS 0xd0000000U
142 #define POWER_LFD 0xc8000000U
143 #define POWER_STFD 0xd8000000U
144 #define POWER_LXSD 0xe4000002U
145 #define POWER_LD 0xe8000000U
146 #define POWER_LWA 0xe8000002U
147 #define POWER_FDIVS 0xec000024U
148 #define POWER_FSUBS 0xec000028U
149 #define POWER_FADDS 0xec00002aU
150 #define POWER_FSQRTS 0xec00002cU
151 #define POWER_FMULS 0xec000032U
152 #define POWER_FCFIDS 0xec00069cU
153 #define POWER_XXLOR 0xf0000497U
154 #define POWER_LXV 0xf4000001U
155 #define POWER_STXSD 0xf4000002U
156 #define POWER_STXV 0xf4000005U
157 #define POWER_STD 0xf8000000U
158 #define POWER_STDU 0xf8000001U
159 #define POWER_FCMPU 0xfc000000U
160 #define POWER_XSADDQP 0xfc000008U
161 #define POWER_FDIV 0xfc000024U
162 #define POWER_FSUB 0xfc000028U
163 #define POWER_FADD 0xfc00002aU
164 #define POWER_FSQRT 0xfc00002cU
165 #define POWER_FMUL 0xfc000032U
166 #define POWER_FCMPO 0xfc000040U
167 #define POWER_XSMULQP 0xfc000048U
168 #define POWER_FNEG 0xfc000050U
169 #define POWER_FMR 0xfc000090U
170 #define POWER_XSCMPOQP 0xfc000108U
171 #define POWER_XSSUBQP 0xfc000408U
172 #define POWER_XSDIVQP 0xfc000448U
173 #define POWER_XSCMPUQP 0xfc000508U
174 #define POWER_FCTIDZ 0xfc00065eU
175 #define POWER_FCFID 0xfc00069cU
176 #define POWER_XSCVSDQP 0xfc0a0688U
177 #define POWER_XSNEGQP 0xfc100648U
178 #define POWER_XSCVQPSDZ 0xfc190688U
181 #define cgen_xform(mc, rt, ra, rb, flags) \
182 cgen_four((mc) | ((uint32_t)(rt) << 21) | ((uint32_t)((ra) << 16)) | ((uint32_t)(rb) << 11) | (((uint32_t)(flags) & 1) * POWER_RC))
184 #define cgen_dform(mc, rt, ra, imm) \
185 cgen_four((mc) | ((uint32_t)(rt) << 21) | ((uint32_t)((ra) << 16)) | (uint16_t)(imm))
187 static const uint32_t load_a1[8] = { POWER_LBZ, POWER_LHZ, POWER_LWZ, POWER_LD, 0, POWER_LHA, POWER_LWA, 0 };
188 static const uint32_t load_a2[8] = { POWER_LBZX, POWER_LHZX, POWER_LWZX, POWER_LDX, 0, POWER_LHAX, POWER_LWAX, 0 };
190 static const uint32_t store_a1[4] = { POWER_STB, POWER_STH, POWER_STW, POWER_STD };
191 static const uint32_t store_a1u[4] = { POWER_STBU, POWER_STHU, POWER_STWU, POWER_STDU };
192 static const uint32_t store_a2[4] = { POWER_STBX, POWER_STHX, POWER_STWX, POWER_STDX };
194 static const uint32_t alu_imm[0x22] = {
195 POWER_ADDI, POWER_ADDIS,
196 POWER_ORI, POWER_ORIS,
199 POWER_ANDI_, POWER_ANDIS_,
201 POWER_XORI, POWER_XORIS,
216 static const uint32_t alu_reg[0x45] = {
217 POWER_ADD, POWER_ADD, 1,
218 POWER_OR, POWER_OR, 0,
219 POWER_ADDE, POWER_ADDE, 1,
220 POWER_SUBFE, POWER_SUBFE, 3,
221 POWER_AND, POWER_AND, 0,
222 POWER_SUBF, POWER_SUBF, 3,
223 POWER_XOR, POWER_XOR, 0,
226 POWER_ORC, POWER_ORC, 0,
227 POWER_ANDC, POWER_ANDC, 0,
228 POWER_EQV, POWER_EQV, 0,
235 POWER_MULLW, POWER_MULLD, 1,
238 POWER_DIVWU, POWER_DIVDU, 1,
239 POWER_DIVW, POWER_DIVD, 1,
240 POWER_MODUW, POWER_MODUD, 1,
241 POWER_MODSW, POWER_MODSD, 1,
244 static const uint32_t jmp_cond[0x2c] = {
245 POWER_BSO, POWER_BNS, 0, 0,
246 POWER_BEQ, POWER_BNE, 0, 0,
248 POWER_BLT, POWER_BGE, POWER_BLE, POWER_BGT,
254 0, 0, POWER_BLT, POWER_BGE,
255 POWER_BEQ, POWER_BNE, POWER_BLE, POWER_BGT,
256 0, 0, POWER_BSO, POWER_BNS,
259 static const uint32_t jmp_cond_logical[0x8] = {
260 0, 0, POWER_BLT, POWER_BGE,
261 POWER_BEQ, POWER_BNE, POWER_BLE, POWER_BGT,
264 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
269 uint8_t *arg1 = ctx->code_position;
270 uint8_t *arg2 = arg1 + arg_size(*arg1);
271 ctx->code_position = arg2 + arg_size(*arg2);
272 if (size >= OP_SIZE_NATIVE)
276 if (unlikely(size == OP_SIZE_NATIVE)) {
277 cgen_xform(POWER_OR, arg2[0], arg1[0], arg2[0], false);
282 case OP_SIZE_1: mc = POWER_EXTSB; break;
283 case OP_SIZE_2: mc = POWER_EXTSH; break;
284 case OP_SIZE_4: mc = POWER_EXTSW; break;
289 case OP_SIZE_1: mc = POWER_RLWINM | 0x063eU; break;
290 case OP_SIZE_2: mc = POWER_RLWINM | 0x043eU; break;
291 case OP_SIZE_4: mc = POWER_RLDICL | 0x0020U; break;
295 cgen_xform(mc, arg2[0], arg1[0], 0, false);
298 if (arg2[0] == R_CTR) {
300 mc |= (uint32_t)arg1[0] << 21;
304 if (arg2[0] == R_LR) {
306 mc |= (uint32_t)arg1[0] << 21;
310 if (arg2[0] == ARG_IMM) {
311 imm = get_imm(&arg2[1]);
312 if (imm >= -0x8000 && imm < 0x8000) {
313 cgen_dform(POWER_ADDI, arg1[0], 0, imm);
317 internal(file_line, "cgen_mov: invalid imm");
318 cgen_dform(POWER_ADDIS, arg1[0], 0, (uint64_t)imm >> 16);
322 if (arg2[0] == ARG_ADDRESS_1) {
323 mc = load_a1[size + (unsigned)sx * 4];
326 imm = get_imm(&arg2[2]);
327 cgen_dform(mc, arg1[0], arg2[1], imm);
330 if (arg2[0] == ARG_ADDRESS_2) {
331 mc = load_a2[size + (unsigned)sx * 4];
334 imm = get_imm(&arg2[3]);
336 internal(file_line, "cgen_mov: imm is not zero");
337 cgen_xform(mc, arg1[0], arg2[1], arg2[2], false);
341 if (arg2[0] == ARG_IMM) {
342 imm = get_imm(&arg2[1]);
343 if (unlikely(imm != 0))
347 if (arg1[0] == R_CTR && arg2[0] < 32) {
349 mc |= (uint32_t)arg2[0] << 21;
353 if (arg1[0] == R_LR && arg2[0] < 32) {
355 mc |= (uint32_t)arg2[0] << 21;
360 if (arg1[0] == ARG_ADDRESS_1) {
362 imm = get_imm(&arg1[2]);
363 cgen_dform(mc, arg2[0], arg1[1], imm);
366 if (arg1[0] == ARG_ADDRESS_1_PRE_I) {
367 mc = store_a1u[size];
368 imm = get_imm(&arg1[2]);
369 cgen_dform(mc, arg2[0], arg1[1], imm);
372 if (arg1[0] == ARG_ADDRESS_2) {
374 imm = get_imm(&arg1[3]);
376 internal(file_line, "cgen_mov: imm is not zero");
377 cgen_xform(mc, arg2[0], arg1[1], arg1[2], false);
381 if (reg_is_fp(arg1[0]) && size == OP_SIZE_16) {
382 if (unlikely(arg2[0] == ARG_ADDRESS_1)) {
383 imm = get_imm(&arg2[2]);
385 mc |= (arg1[0] & 32) >> 2;
386 cgen_dform(mc, arg1[0] & 31, arg2[1], imm);
389 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
390 imm = get_imm(&arg2[3]);
392 internal(file_line, "cgen_mov: imm is not zero");
394 cgen_xform(mc, arg1[0] & 31, arg2[1], arg2[2], !!(arg1[0] & 32));
398 if (reg_is_fp(arg2[0]) && size == OP_SIZE_16) {
399 if (unlikely(arg1[0] == ARG_ADDRESS_1)) {
400 imm = get_imm(&arg1[2]);
402 mc |= (arg2[0] & 32) >> 2;
403 cgen_dform(mc, arg2[0] & 31, arg1[1], imm);
406 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
407 imm = get_imm(&arg1[3]);
409 internal(file_line, "cgen_mov: imm is not zero");
411 cgen_xform(mc, arg2[0] & 31, arg1[1], arg1[2], !!(arg2[0] & 32));
415 if (reg_is_vs(arg1[0]) && size == OP_SIZE_8) {
416 if (unlikely(arg2[0] == ARG_ADDRESS_1)) {
417 imm = get_imm(&arg2[2]);
419 cgen_dform(mc, arg1[0] & 31, arg2[1], imm);
422 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
423 imm = get_imm(&arg2[3]);
425 internal(file_line, "cgen_mov: imm is not zero");
427 cgen_xform(mc, arg1[0] & 31, arg2[1], arg2[2], false);
431 if (reg_is_vs(arg2[0]) && size == OP_SIZE_8) {
432 if (unlikely(arg1[0] == ARG_ADDRESS_1)) {
433 imm = get_imm(&arg1[2]);
435 cgen_dform(mc, arg2[0] & 31, arg1[1], imm);
438 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
439 imm = get_imm(&arg1[3]);
441 internal(file_line, "cgen_mov: imm is not zero");
443 cgen_xform(mc, arg2[0] & 31, arg1[1], arg1[2], false);
447 if (reg_is_fp(arg1[0]) && !reg_is_vs(arg1[0])) {
448 if (unlikely(arg2[0] == ARG_ADDRESS_1)) {
449 imm = get_imm(&arg2[2]);
450 mc = size == OP_SIZE_4 ? POWER_LFS : POWER_LFD;
451 cgen_dform(mc, arg1[0] & 31, arg2[1], imm);
454 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
455 imm = get_imm(&arg2[3]);
457 internal(file_line, "cgen_mov: imm is not zero");
458 mc = size == OP_SIZE_4 ? POWER_LFSX : POWER_LFDX;
459 cgen_xform(mc, arg1[0] & 31, arg2[1], arg2[2], false);
463 if (reg_is_fp(arg2[0]) && !reg_is_vs(arg2[0])) {
464 if (unlikely(arg1[0] == ARG_ADDRESS_1)) {
465 imm = get_imm(&arg1[2]);
466 mc = size == OP_SIZE_4 ? POWER_STFS : POWER_STFD;
467 cgen_dform(mc, arg2[0] & 31, arg1[1], imm);
470 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
471 imm = get_imm(&arg1[3]);
473 internal(file_line, "cgen_mov: imm is not zero");
474 mc = size == OP_SIZE_4 ? POWER_STFSX : POWER_STFDX;
475 cgen_xform(mc, arg2[0] & 31, arg1[1], arg1[2], false);
479 if (reg_is_fp(arg1[0]) && !reg_is_vs(arg1[0]) && reg_is_fp(arg2[0]) && !reg_is_vs(arg2[0])) {
481 cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
484 if (reg_is_vs(arg1[0]) && reg_is_vs(arg2[0])) {
486 cgen_xform(mc, arg1[0] & 31, arg2[0] & 31, arg2[0] & 31, false);
491 internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
495 static bool attr_w cgen_cmp(struct codegen_context *ctx, unsigned size, unsigned writes_flags)
499 uint8_t *arg1 = ctx->code_position;
500 uint8_t *arg2 = arg1 + arg_size(*arg1);
501 ctx->code_position = arg2 + arg_size(*arg2);
503 if (arg2[0] == ARG_IMM) {
504 imm = get_imm(&arg2[1]);
505 mc = writes_flags == 1 ? POWER_CMPI : POWER_CMPLI;
506 if (size == OP_SIZE_8)
508 cgen_dform(mc, 0, arg1[0], imm);
511 mc = writes_flags == 1 ? POWER_CMP : POWER_CMPL;
512 if (size == OP_SIZE_8)
514 cgen_xform(mc, 0, arg1[0], arg2[0], false);
518 internal(file_line, "cgen_cmp: invalid arguments %u, %02x, %02x, %u", size, *arg1, *arg2, writes_flags);
522 static bool attr_w cgen_test(struct codegen_context *ctx)
525 uint8_t *arg1 = ctx->code_position;
526 uint8_t *arg2 = arg1 + arg_size(*arg1);
527 ctx->code_position = arg2 + arg_size(*arg2);
529 if (arg2[0] == ARG_IMM) {
530 imm = get_imm(&arg2[1]);
531 if (imm >= 0 && imm < 0x10000) {
532 cgen_dform(POWER_ANDI_, arg1[0], R_CG_SCRATCH, imm);
537 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL)) {
538 cgen_dform(POWER_ANDIS_, arg1[0], R_CG_SCRATCH, (uint64_t)imm >> 16);
543 cgen_xform(POWER_AND, arg1[0], R_CG_SCRATCH, arg2[0], 1);
548 internal(file_line, "cgen_test: invalid arguments %02x, %02x", *arg1, *arg2);
552 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
556 uint8_t *arg1 = ctx->code_position;
557 uint8_t *arg2 = arg1 + arg_size(*arg1);
558 uint8_t *arg3 = arg2 + arg_size(*arg2);
559 ctx->code_position = arg3 + arg_size(*arg3);
561 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32))
564 if (arg3[0] == ARG_IMM) {
565 bool shifted = false;
566 imm = get_imm(&arg3[1]);
567 if (!imm && (alu == ALU_ADC || alu == ALU_SBB)) {
568 mc = alu == ALU_ADC ? POWER_ADDZE : POWER_ADDME;
569 if (writes_flags & 1) {
570 cgen_four(POWER_MFXER | ((uint32_t)R_CG_SCRATCH << 21));
571 cgen_dform(POWER_ANDIS_, R_CG_SCRATCH, R_CG_SCRATCH, 0x2004U);
572 cgen_four(POWER_MTXER | ((uint32_t)R_CG_SCRATCH << 21));
575 cgen_xform(mc, arg1[0], arg2[0], 0, writes_flags);
578 if (unlikely(writes_flags != (alu == ALU_AND)))
580 if (alu == ALU_SUB) {
581 imm = -(uint64_t)imm;
584 if (alu == ALU_MUL && size == OP_SIZE_8)
589 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
593 if (likely(imm >= -0x80000000LL) && likely(imm < 0x80000000LL)) {
601 if (likely(imm >= 0) && likely(imm < 0x10000))
605 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL)) {
613 if (unlikely(alu * 2 + (unsigned)shifted >= n_array_elements(alu_imm)))
615 mc = alu_imm[alu * 2 + (unsigned)shifted];
619 imm = (uint64_t)imm >> 16;
620 if (alu == ALU_ADD || alu == ALU_MUL)
621 cgen_dform(mc, arg1[0], arg2[0], imm);
623 cgen_dform(mc, arg2[0], arg1[0], imm);
628 if (unlikely(alu * 3 + 2 >= n_array_elements(alu_reg)))
630 mc = alu_reg[alu * 3 + (size == OP_SIZE_8)];
631 flag = alu_reg[alu * 3 + 2];
634 if (writes_flags & 2) {
636 case ALU_ADD: mc = POWER_ADDC; break;
637 case ALU_SUB: mc = POWER_SUBFC; break;
643 if (flag & 1 && writes_flags & 1) {
644 if (alu == ALU_ADC || alu == ALU_SBB) {
645 cgen_four(POWER_MFXER | ((uint32_t)R_CG_SCRATCH << 21));
646 cgen_dform(POWER_ANDIS_, R_CG_SCRATCH, R_CG_SCRATCH, 0x2004U);
647 cgen_four(POWER_MTXER | ((uint32_t)R_CG_SCRATCH << 21));
649 cgen_four(POWER_MTXER | ((uint32_t)R_ZERO << 21));
659 cgen_xform(mc, arg1[0], arg2[0], arg3[0], writes_flags);
661 cgen_xform(mc, arg2[0], arg1[0], arg3[0], writes_flags);
666 internal(file_line, "cgen_alu: invalid arguments %u, %u, %02x, %02x, %02x, %u", size, alu, *arg1, *arg2, *arg3, writes_flags);
670 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
673 uint8_t *arg1 = ctx->code_position;
674 uint8_t *arg2 = arg1 + arg_size(*arg1);
675 ctx->code_position = arg2 + arg_size(*arg2);
677 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32))
682 cgen_xform(POWER_NOR, arg2[0], arg1[0], arg2[0], writes_flags);
685 if (writes_flags & 2)
686 cgen_dform(POWER_SUBFIC, arg1[0], arg2[0], 0);
688 cgen_xform(POWER_NEG, arg1[0], arg2[0], 0, writes_flags);
692 if (writes_flags & 1) {
693 cgen_four(POWER_MFXER | ((uint32_t)R_CG_SCRATCH << 21));
694 cgen_dform(POWER_ANDIS_, R_CG_SCRATCH, R_CG_SCRATCH, 0x2004U);
695 cgen_four(POWER_MTXER | ((uint32_t)R_CG_SCRATCH << 21));
698 cgen_xform(mc, arg1[0], arg2[0], 0, writes_flags);
701 cgen_xform(size == OP_SIZE_4 ? POWER_CNTTZW : POWER_CNTTZD, arg2[0], arg1[0], 0, writes_flags);
704 cgen_xform(size == OP_SIZE_4 ? POWER_CNTLZW : POWER_CNTLZD, arg2[0], arg1[0], 0, writes_flags);
707 if (unlikely(writes_flags))
709 cgen_xform(size == OP_SIZE_4 ? POWER_POPCNTW : POWER_POPCNTD, arg2[0], arg1[0], 0, 0);
716 internal(file_line, "cgen_alu1: invalid arguments %u, %u, %02x, %02x, %u", size, alu, *arg1, *arg2, writes_flags);
720 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
724 uint8_t *arg1 = ctx->code_position;
725 uint8_t *arg2 = arg1 + arg_size(*arg1);
726 uint8_t *arg3 = arg2 + arg_size(*arg2);
727 ctx->code_position = arg3 + arg_size(*arg3);
729 if (unlikely(size < OP_SIZE_4))
734 case ROT_ROL: mc = size == OP_SIZE_4 ? POWER_RLWNM | (31 << 1) : POWER_RLDCL; break;
735 case ROT_SHL: mc = size == OP_SIZE_4 ? POWER_SLW : POWER_SLD; break;
736 case ROT_SHR: mc = size == OP_SIZE_4 ? POWER_SRW : POWER_SRD; break;
737 case ROT_SAR: mc = size == OP_SIZE_4 ? POWER_SRAW : POWER_SRAD; break;
740 cgen_xform(mc, arg2[0], arg1[0], arg3[0], writes_flags);
742 } else if (arg3[0] == ARG_IMM) {
744 imm = get_imm(&arg3[1]);
746 if (size == OP_SIZE_4) {
749 mc = POWER_RLWINM | (i32 << 11) | 0x3e;
752 mc = POWER_RLWINM | (i32 << 11) | ((31 - i32) << 1);
755 mc = POWER_RLWINM | ((-i32 << 11) & 0xf800U) | (i32 << 6) | 0x3eU;
758 mc = POWER_SRAWI | (i32 << 11);
767 mc |= (i32 & 0x1f) << 11;
768 mc |= (i32 & 0x20) >> 4;
772 mc |= (i32 << 11) & 0xf800U;
773 mc |= (i32 >> 4) & 0x2U;
774 mc |= ((63 - i32) << 6) & 0x07c0U;
775 mc |= (63 - i32) & 0x0020U;
779 mc |= (-i32 << 11) & 0xf800U;
780 mc |= (-i32 >> 4) & 0x2U;
781 mc |= (i32 << 6) & 0x07c0U;
786 mc |= (i32 << 11) & 0xf800U;
787 mc |= (i32 >> 4) & 0x2U;
793 cgen_xform(mc, arg2[0], arg1[0], 0, writes_flags);
798 internal(file_line, "cgen_rot: invalid arguments %u, %u, %02x, %02x, %02x", size, alu, *arg1, *arg2, *arg3);
802 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned aux)
808 uint8_t *arg1 = ctx->code_position;
809 uint8_t *arg2 = arg1 + arg_size(*arg1);
810 uint8_t *arg3 = arg2 + arg_size(*arg2);
811 ctx->code_position = arg3 + arg_size(*arg3);
813 if (arg2[0] == ARG_IMM) {
814 imm = get_imm(&arg2[1]);
815 if (unlikely(imm != 0))
819 if (arg3[0] == ARG_IMM) {
820 imm = get_imm(&arg3[1]);
821 if (unlikely(imm != 0))
827 case COND_B: aux = COND_L; break;
828 case COND_BE: aux = COND_LE; break;
829 case COND_A: aux = COND_G; break;
830 case COND_AE: aux = COND_GE; break;
834 case COND_O: mc = POWER_ISELSO; swap = false; break;
835 case COND_E: mc = POWER_ISELEQ; swap = false; break;
836 case COND_L: mc = POWER_ISELLT; swap = false; break;
837 case COND_G: mc = POWER_ISELGT; swap = false; break;
838 case COND_NO: mc = POWER_ISELSO; swap = true; break;
839 case COND_NE: mc = POWER_ISELEQ; swap = true; break;
840 case COND_GE: mc = POWER_ISELLT; swap = true; break;
841 case COND_LE: mc = POWER_ISELGT; swap = true; break;
842 case FP_COND_P: mc = POWER_ISELSO; swap = false; break;
843 case FP_COND_E: mc = POWER_ISELEQ; swap = false; break;
844 case FP_COND_B: mc = POWER_ISELLT; swap = false; break;
845 case FP_COND_A: mc = POWER_ISELGT; swap = false; break;
846 case FP_COND_NP:mc = POWER_ISELSO; swap = true; break;
847 case FP_COND_NE:mc = POWER_ISELEQ; swap = true; break;
848 case FP_COND_AE:mc = POWER_ISELLT; swap = true; break;
849 case FP_COND_BE:mc = POWER_ISELGT; swap = true; break;
859 cgen_xform(mc, arg1[0], arg3[0], arg2[0], false);
863 internal(file_line, "cgen_cmov: invalid arguments %u, %02x, %02x, %02x", aux, *arg1, *arg2, *arg3);
867 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned attr_unused op_size)
870 uint8_t *arg1 = ctx->code_position;
871 uint8_t *arg2 = arg1 + arg_size(*arg1);
872 ctx->code_position = arg2 + arg_size(*arg2);
873 mc = op_size != OP_SIZE_16 ? POWER_FCMPU : POWER_XSCMPUQP;
874 cgen_xform(mc, 0, arg1[0] & 31, arg2[0] & 31, false);
878 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
880 bool use_s = op_size == OP_SIZE_4;
881 bool use_vs = op_size == OP_SIZE_16;
883 uint8_t *arg1 = ctx->code_position;
884 uint8_t *arg2 = arg1 + arg_size(*arg1);
885 uint8_t *arg3 = arg2 + arg_size(*arg2);
886 ctx->code_position = arg3 + arg_size(*arg3);
888 case FP_ALU_ADD: mc = use_vs ? POWER_XSADDQP : use_s ? POWER_FADDS : POWER_FADD; break;
889 case FP_ALU_SUB: mc = use_vs ? POWER_XSSUBQP : use_s ? POWER_FSUBS : POWER_FSUB; break;
890 case FP_ALU_MUL: mc = use_vs ? POWER_XSMULQP : use_s ? POWER_FMULS : POWER_FMUL; break;
891 case FP_ALU_DIV: mc = use_vs ? POWER_XSDIVQP : use_s ? POWER_FDIVS : POWER_FDIV; break;
894 if (aux == FP_ALU_MUL && !use_vs)
895 cgen_xform(mc | ((arg3[0] & 31) << 6), arg1[0] & 31, arg2[0] & 31, 0, false);
897 cgen_xform(mc, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31, false);
900 internal(file_line, "cgen_fp_alu: invalid arguments %u, %u, %02x, %02x, %02x", op_size, aux, *arg1, *arg2, *arg3);
904 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
906 bool use_s = op_size == OP_SIZE_4 && cpu_test_feature(CPU_FEATURE_ppc);
907 bool use_vs = op_size == OP_SIZE_16;
909 uint8_t *arg1 = ctx->code_position;
910 uint8_t *arg2 = arg1 + arg_size(*arg1);
911 ctx->code_position = arg2 + arg_size(*arg2);
913 case FP_ALU1_NEG: mc = use_vs ? POWER_XSNEGQP : POWER_FNEG;
915 case FP_ALU1_SQRT: if (unlikely(use_vs))
917 mc = use_s ? POWER_FSQRTS : POWER_FSQRT; break;
920 cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
923 internal(file_line, "cgen_fp_alu1: invalid arguments %u, %u, %02x, %02x", op_size, aux, *arg1, *arg2);
927 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned fp_op_size)
930 uint8_t *arg1 = ctx->code_position;
931 uint8_t *arg2 = arg1 + arg_size(*arg1);
932 ctx->code_position = arg2 + arg_size(*arg2);
933 mc = fp_op_size <= OP_SIZE_8 ? POWER_FCTIDZ : POWER_XSCVQPSDZ;
934 cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
938 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
941 uint8_t *arg1 = ctx->code_position;
942 uint8_t *arg2 = arg1 + arg_size(*arg1);
943 ctx->code_position = arg2 + arg_size(*arg2);
944 mc = fp_op_size == OP_SIZE_4 ? POWER_FCFIDS : fp_op_size == OP_SIZE_8 ? POWER_FCFID : POWER_XSCVSDQP;
945 cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
949 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, bool lng, unsigned aux, bool logical)
953 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
958 if (unlikely(aux >= n_array_elements(jmp_cond)))
962 if (unlikely(aux >= n_array_elements(jmp_cond_logical)))
964 mc = jmp_cond_logical[aux];
973 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
980 internal(file_line, "cgen_jmp_cond: invalid %scondition %x", logical ? "logical " : "", aux);
984 static bool attr_w cgen_jmp_indirect(struct codegen_context *ctx)
987 unsigned reg = cget_one(ctx);
990 mc |= (uint32_t)reg << 21;
999 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1002 int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)reloc->position;
1003 switch (reloc->length) {
1005 if (unlikely(offs < -0x8000) || unlikely(offs >= 0x8000))
1007 memcpy(&mc, ctx->mcode + reloc->position, 4);
1009 mc |= offs & 0xfffcU;
1010 memcpy(ctx->mcode + reloc->position, &mc, 4);
1013 if (unlikely(offs < -0x01000000) || unlikely(offs >= 0x01000000))
1015 memcpy(&mc, ctx->mcode + reloc->position, 4);
1017 mc |= offs & 0x3fffffcU;
1018 memcpy(ctx->mcode + reloc->position, &mc, 4);
1021 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1026 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1029 switch (insn_opcode(insn)) {
1037 cgen_four(POWER_BLR);
1039 case INSN_CALL_INDIRECT:
1040 reg = cget_one(ctx);
1041 if (unlikely(reg != R_CTR))
1043 cgen_four(POWER_BCTRL);
1046 g(cgen_mov(ctx, insn_op_size(insn), false));
1049 g(cgen_mov(ctx, insn_op_size(insn), true));
1052 g(cgen_cmp(ctx, insn_op_size(insn), insn_writes_flags(insn)));
1055 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1060 case INSN_ALU_FLAGS:
1061 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE) && !((insn_aux(insn) >= ALU_UDIV && insn_aux(insn) <= ALU_SREM) || insn_aux(insn) == ALU_MUL))
1063 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1066 case INSN_ALU1_FLAGS:
1067 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1069 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1072 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1076 if (unlikely(!cpu_test_feature(CPU_FEATURE_v203)))
1078 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1080 g(cgen_cmov(ctx, insn_aux(insn)));
1083 g(cgen_fp_cmp(ctx, insn_op_size(insn)));
1086 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1089 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1091 case INSN_FP_TO_INT64:
1092 g(cgen_fp_to_int(ctx, insn_op_size(insn)));
1094 case INSN_FP_FROM_INT64:
1095 g(cgen_fp_from_int(ctx, insn_op_size(insn)));
1098 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1102 g(cgen_jmp_cond(ctx, insn_jump_size(insn) == JMP_SHORT, insn_aux(insn), false));
1104 case INSN_JMP_COND_LOGICAL:
1105 g(cgen_jmp_cond(ctx, insn_jump_size(insn) == JMP_SHORT, insn_aux(insn), true));
1107 case INSN_JMP_INDIRECT:
1108 g(cgen_jmp_indirect(ctx));
1112 internal(file_line, "cgen_insn: invalid insn %08x", insn);