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_ADDI 0x38000000U
29 #define POWER_ADDIS 0x3c000000U
30 #define POWER_BGE 0x40800000U
31 #define POWER_BLE 0x40810000U
32 #define POWER_BNE 0x40820000U
33 #define POWER_BNS 0x40830000U
34 #define POWER_BLT 0x41800000U
35 #define POWER_BGT 0x41810000U
36 #define POWER_BEQ 0x41820000U
37 #define POWER_BSO 0x41830000U
38 #define POWER_B 0x48000000U
39 #define POWER_BLR 0x4e800020U
40 #define POWER_BCTR 0x4e800420U
41 #define POWER_BCTRL 0x4e800421U
42 #define POWER_RLWINM 0x54000000U
43 #define POWER_RLWNM 0x5c000000U
44 #define POWER_ORI 0x60000000U
45 #define POWER_ORIS 0x64000000U
46 #define POWER_XORI 0x68000000U
47 #define POWER_XORIS 0x6c000000U
48 #define POWER_ANDI_ 0x70000000U
49 #define POWER_ANDIS_ 0x74000000U
50 #define POWER_RLDICL 0x78000000U
51 #define POWER_RLDICR 0x78000004U
52 #define POWER_RLDCL 0x78000010U
53 #define POWER_RLDCR 0x78000012U
54 #define POWER_CMP 0x7c000000U
55 #define POWER_SUBFC 0x7c000010U
56 #define POWER_ADDC 0x7c000014U
57 #define POWER_ISELLT 0x7c00001eU
58 #define POWER_LDX 0x7c00002aU
59 #define POWER_LWZX 0x7c00002eU
60 #define POWER_SLW 0x7c000030U
61 #define POWER_CNTLZW 0x7c000034U
62 #define POWER_SLD 0x7c000036U
63 #define POWER_AND 0x7c000038U
64 #define POWER_CMPL 0x7c000040U
65 #define POWER_SUBF 0x7c000050U
66 #define POWER_ISELGT 0x7c00005eU
67 #define POWER_CNTLZD 0x7c000074U
68 #define POWER_ANDC 0x7c000078U
69 #define POWER_ISELEQ 0x7c00009eU
70 #define POWER_LBZX 0x7c0000aeU
71 #define POWER_NEG 0x7c0000d0U
72 #define POWER_ISELSO 0x7c0000deU
73 #define POWER_NOR 0x7c0000f8U
74 #define POWER_SUBFE 0x7c000110U
75 #define POWER_ADDE 0x7c000114U
76 #define POWER_STDX 0x7c00012aU
77 #define POWER_STWX 0x7c00012eU
78 #define POWER_SUBFZE 0x7c000190U
79 #define POWER_ADDZE 0x7c000194U
80 #define POWER_STBX 0x7c0001aeU
81 #define POWER_MULLD 0x7c0001d2U
82 #define POWER_ADDME 0x7c0001d4U
83 #define POWER_MULLW 0x7c0001d6U
84 #define POWER_MODUD 0x7c000212U
85 #define POWER_MODUW 0x7c000216U
86 #define POWER_ADD 0x7c000214U
87 #define POWER_LXVX 0x7c000218U
88 #define POWER_LHZX 0x7c00022eU
89 #define POWER_EQV 0x7c000238U
90 #define POWER_XOR 0x7c000278U
91 #define POWER_LWAX 0x7c0002aaU
92 #define POWER_LHAX 0x7c0002aeU
93 #define POWER_POPCNTW 0x7c0002f4U
94 #define POWER_STXVX 0x7c000318U
95 #define POWER_STHX 0x7c00032eU
96 #define POWER_ORC 0x7c000338U
97 #define POWER_OR 0x7c000378U
98 #define POWER_DIVDU 0x7c000392U
99 #define POWER_DIVWU 0x7c000396U
100 #define POWER_NAND 0x7c0003b8U
101 #define POWER_DIVD 0x7c0003d2U
102 #define POWER_DIVW 0x7c0003d6U
103 #define POWER_POPCNTD 0x7c0003f4U
104 #define POWER_LFSX 0x7c00042eU
105 #define POWER_SRW 0x7c000430U
106 #define POWER_CNTTZW 0x7c000434U
107 #define POWER_SRD 0x7c000436U
108 #define POWER_CNTTZD 0x7c000474U
109 #define POWER_LXSDX 0x7c000498U
110 #define POWER_LFDX 0x7c0004aeU
111 #define POWER_STFSX 0x7c00052eU
112 #define POWER_STXSDX 0x7c000598U
113 #define POWER_STFDX 0x7c0005aeU
114 #define POWER_MODSD 0x7c000612U
115 #define POWER_MODSW 0x7c000616U
116 #define POWER_SRAW 0x7c000630U
117 #define POWER_SRAD 0x7c000634U
118 #define POWER_SRAWI 0x7c000670U
119 #define POWER_SRADI 0x7c000674U
120 #define POWER_EXTSH 0x7c000734U
121 #define POWER_EXTSB 0x7c000774U
122 #define POWER_EXTSW 0x7c0007b4U
123 #define POWER_MFXER 0x7c0102a6U
124 #define POWER_MTXER 0x7c0103a6U
125 #define POWER_MFLR 0x7c0802a6U
126 #define POWER_MTLR 0x7c0803a6U
127 #define POWER_MFCTR 0x7c0902a6U
128 #define POWER_MTCTR 0x7c0903a6U
129 #define POWER_LWZ 0x80000000U
130 #define POWER_LBZ 0x88000000U
131 #define POWER_STW 0x90000000U
132 #define POWER_STWU 0x94000000U
133 #define POWER_STB 0x98000000U
134 #define POWER_STBU 0x9c000000U
135 #define POWER_LHZ 0xa0000000U
136 #define POWER_LHA 0xa8000000U
137 #define POWER_STH 0xb0000000U
138 #define POWER_STHU 0xb4000000U
139 #define POWER_LFS 0xc0000000U
140 #define POWER_STFS 0xd0000000U
141 #define POWER_LFD 0xc8000000U
142 #define POWER_STFD 0xd8000000U
143 #define POWER_LXSD 0xe4000002U
144 #define POWER_LD 0xe8000000U
145 #define POWER_LWA 0xe8000002U
146 #define POWER_FDIVS 0xec000024U
147 #define POWER_FSUBS 0xec000028U
148 #define POWER_FADDS 0xec00002aU
149 #define POWER_FSQRTS 0xec00002cU
150 #define POWER_FMULS 0xec000032U
151 #define POWER_FCFIDS 0xec00069cU
152 #define POWER_XXLOR 0xf0000497U
153 #define POWER_LXV 0xf4000001U
154 #define POWER_STXSD 0xf4000002U
155 #define POWER_STXV 0xf4000005U
156 #define POWER_STD 0xf8000000U
157 #define POWER_STDU 0xf8000001U
158 #define POWER_FCMPU 0xfc000000U
159 #define POWER_XSADDQP 0xfc000008U
160 #define POWER_FDIV 0xfc000024U
161 #define POWER_FSUB 0xfc000028U
162 #define POWER_FADD 0xfc00002aU
163 #define POWER_FSQRT 0xfc00002cU
164 #define POWER_FMUL 0xfc000032U
165 #define POWER_FCMPO 0xfc000040U
166 #define POWER_XSMULQP 0xfc000048U
167 #define POWER_FNEG 0xfc000050U
168 #define POWER_FMR 0xfc000090U
169 #define POWER_XSCMPOQP 0xfc000108U
170 #define POWER_XSSUBQP 0xfc000408U
171 #define POWER_XSDIVQP 0xfc000448U
172 #define POWER_XSCMPUQP 0xfc000508U
173 #define POWER_FCTIDZ 0xfc00065eU
174 #define POWER_FCFID 0xfc00069cU
175 #define POWER_XSCVSDQP 0xfc0a0688U
176 #define POWER_XSNEGQP 0xfc100648U
177 #define POWER_XSCVQPSDZ 0xfc190688U
180 #define cgen_xform(mc, rt, ra, rb, flags) \
181 cgen_four((mc) | ((uint32_t)(rt) << 21) | ((uint32_t)((ra) << 16)) | ((uint32_t)(rb) << 11) | (((uint32_t)(flags) & 1) * POWER_RC))
183 #define cgen_dform(mc, rt, ra, imm) \
184 cgen_four((mc) | ((uint32_t)(rt) << 21) | ((uint32_t)((ra) << 16)) | (uint16_t)(imm))
186 static const uint32_t load_a1[8] = { POWER_LBZ, POWER_LHZ, POWER_LWZ, POWER_LD, 0, POWER_LHA, POWER_LWA, 0 };
187 static const uint32_t load_a2[8] = { POWER_LBZX, POWER_LHZX, POWER_LWZX, POWER_LDX, 0, POWER_LHAX, POWER_LWAX, 0 };
189 static const uint32_t store_a1[4] = { POWER_STB, POWER_STH, POWER_STW, POWER_STD };
190 static const uint32_t store_a1u[4] = { POWER_STBU, POWER_STHU, POWER_STWU, POWER_STDU };
191 static const uint32_t store_a2[4] = { POWER_STBX, POWER_STHX, POWER_STWX, POWER_STDX };
193 static const uint32_t alu_imm[0x22] = {
194 POWER_ADDI, POWER_ADDIS,
195 POWER_ORI, POWER_ORIS,
198 POWER_ANDI_, POWER_ANDIS_,
200 POWER_XORI, POWER_XORIS,
215 static const uint32_t alu_reg[0x45] = {
216 POWER_ADD, POWER_ADD, 1,
217 POWER_OR, POWER_OR, 0,
218 POWER_ADDE, POWER_ADDE, 1,
219 POWER_SUBFE, POWER_SUBFE, 3,
220 POWER_AND, POWER_AND, 0,
221 POWER_SUBF, POWER_SUBF, 3,
222 POWER_XOR, POWER_XOR, 0,
225 POWER_ORC, POWER_ORC, 0,
226 POWER_ANDC, POWER_ANDC, 0,
227 POWER_EQV, POWER_EQV, 0,
234 POWER_MULLW, POWER_MULLD, 1,
237 POWER_DIVWU, POWER_DIVDU, 1,
238 POWER_DIVW, POWER_DIVD, 1,
239 POWER_MODUW, POWER_MODUD, 1,
240 POWER_MODSW, POWER_MODSD, 1,
243 static const uint32_t jmp_cond[0x2c] = {
244 POWER_BSO, POWER_BNS, 0, 0,
245 POWER_BEQ, POWER_BNE, 0, 0,
247 POWER_BLT, POWER_BGE, POWER_BLE, POWER_BGT,
253 0, 0, POWER_BLT, POWER_BGE,
254 POWER_BEQ, POWER_BNE, POWER_BLE, POWER_BGT,
255 0, 0, POWER_BSO, POWER_BNS,
258 static const uint32_t jmp_cond_logical[0x8] = {
259 0, 0, POWER_BLT, POWER_BGE,
260 POWER_BEQ, POWER_BNE, POWER_BLE, POWER_BGT,
263 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
268 uint8_t *arg1 = ctx->code_position;
269 uint8_t *arg2 = arg1 + arg_size(*arg1);
270 ctx->code_position = arg2 + arg_size(*arg2);
271 if (size >= OP_SIZE_NATIVE)
275 if (unlikely(size == OP_SIZE_NATIVE)) {
276 cgen_xform(POWER_OR, arg2[0], arg1[0], arg2[0], false);
281 case OP_SIZE_1: mc = POWER_EXTSB; break;
282 case OP_SIZE_2: mc = POWER_EXTSH; break;
283 case OP_SIZE_4: mc = POWER_EXTSW; break;
288 case OP_SIZE_1: mc = POWER_RLWINM | 0x063eU; break;
289 case OP_SIZE_2: mc = POWER_RLWINM | 0x043eU; break;
290 case OP_SIZE_4: mc = POWER_RLDICL | 0x0020U; break;
294 cgen_xform(mc, arg2[0], arg1[0], 0, false);
297 if (arg2[0] == R_CTR) {
299 mc |= (uint32_t)arg1[0] << 21;
303 if (arg2[0] == R_LR) {
305 mc |= (uint32_t)arg1[0] << 21;
309 if (arg2[0] == ARG_IMM) {
310 imm = get_imm(&arg2[1]);
311 if (imm >= -0x8000 && imm < 0x8000) {
312 cgen_dform(POWER_ADDI, arg1[0], 0, imm);
316 internal(file_line, "cgen_mov: invalid imm");
317 cgen_dform(POWER_ADDIS, arg1[0], 0, (uint64_t)imm >> 16);
321 if (arg2[0] == ARG_ADDRESS_1) {
322 mc = load_a1[size + (unsigned)sx * 4];
325 imm = get_imm(&arg2[2]);
326 cgen_dform(mc, arg1[0], arg2[1], imm);
329 if (arg2[0] == ARG_ADDRESS_2) {
330 mc = load_a2[size + (unsigned)sx * 4];
333 imm = get_imm(&arg2[3]);
335 internal(file_line, "cgen_mov: imm is not zero");
336 cgen_xform(mc, arg1[0], arg2[1], arg2[2], false);
340 if (arg2[0] == ARG_IMM) {
341 imm = get_imm(&arg2[1]);
342 if (unlikely(imm != 0))
346 if (arg1[0] == R_CTR && arg2[0] < 32) {
348 mc |= (uint32_t)arg2[0] << 21;
352 if (arg1[0] == R_LR && arg2[0] < 32) {
354 mc |= (uint32_t)arg2[0] << 21;
359 if (arg1[0] == ARG_ADDRESS_1) {
361 imm = get_imm(&arg1[2]);
362 cgen_dform(mc, arg2[0], arg1[1], imm);
365 if (arg1[0] == ARG_ADDRESS_1_PRE_I) {
366 mc = store_a1u[size];
367 imm = get_imm(&arg1[2]);
368 cgen_dform(mc, arg2[0], arg1[1], imm);
371 if (arg1[0] == ARG_ADDRESS_2) {
373 imm = get_imm(&arg1[3]);
375 internal(file_line, "cgen_mov: imm is not zero");
376 cgen_xform(mc, arg2[0], arg1[1], arg1[2], false);
380 if (reg_is_fp(arg1[0]) && size == OP_SIZE_16) {
381 if (unlikely(arg2[0] == ARG_ADDRESS_1)) {
382 imm = get_imm(&arg2[2]);
384 mc |= (arg1[0] & 32) >> 2;
385 cgen_dform(mc, arg1[0] & 31, arg2[1], imm);
388 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
389 imm = get_imm(&arg2[3]);
391 internal(file_line, "cgen_mov: imm is not zero");
393 cgen_xform(mc, arg1[0] & 31, arg2[1], arg2[2], !!(arg1[0] & 32));
397 if (reg_is_fp(arg2[0]) && size == OP_SIZE_16) {
398 if (unlikely(arg1[0] == ARG_ADDRESS_1)) {
399 imm = get_imm(&arg1[2]);
401 mc |= (arg2[0] & 32) >> 2;
402 cgen_dform(mc, arg2[0] & 31, arg1[1], imm);
405 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
406 imm = get_imm(&arg1[3]);
408 internal(file_line, "cgen_mov: imm is not zero");
410 cgen_xform(mc, arg2[0] & 31, arg1[1], arg1[2], !!(arg2[0] & 32));
414 if (reg_is_vs(arg1[0]) && size == OP_SIZE_8) {
415 if (unlikely(arg2[0] == ARG_ADDRESS_1)) {
416 imm = get_imm(&arg2[2]);
418 cgen_dform(mc, arg1[0] & 31, arg2[1], imm);
421 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
422 imm = get_imm(&arg2[3]);
424 internal(file_line, "cgen_mov: imm is not zero");
426 cgen_xform(mc, arg1[0] & 31, arg2[1], arg2[2], false);
430 if (reg_is_vs(arg2[0]) && size == OP_SIZE_8) {
431 if (unlikely(arg1[0] == ARG_ADDRESS_1)) {
432 imm = get_imm(&arg1[2]);
434 cgen_dform(mc, arg2[0] & 31, arg1[1], imm);
437 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
438 imm = get_imm(&arg1[3]);
440 internal(file_line, "cgen_mov: imm is not zero");
442 cgen_xform(mc, arg2[0] & 31, arg1[1], arg1[2], false);
446 if (reg_is_fp(arg1[0]) && !reg_is_vs(arg1[0])) {
447 if (unlikely(arg2[0] == ARG_ADDRESS_1)) {
448 imm = get_imm(&arg2[2]);
449 mc = size == OP_SIZE_4 ? POWER_LFS : POWER_LFD;
450 cgen_dform(mc, arg1[0] & 31, arg2[1], imm);
453 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
454 imm = get_imm(&arg2[3]);
456 internal(file_line, "cgen_mov: imm is not zero");
457 mc = size == OP_SIZE_4 ? POWER_LFSX : POWER_LFDX;
458 cgen_xform(mc, arg1[0] & 31, arg2[1], arg2[2], false);
462 if (reg_is_fp(arg2[0]) && !reg_is_vs(arg2[0])) {
463 if (unlikely(arg1[0] == ARG_ADDRESS_1)) {
464 imm = get_imm(&arg1[2]);
465 mc = size == OP_SIZE_4 ? POWER_STFS : POWER_STFD;
466 cgen_dform(mc, arg2[0] & 31, arg1[1], imm);
469 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
470 imm = get_imm(&arg1[3]);
472 internal(file_line, "cgen_mov: imm is not zero");
473 mc = size == OP_SIZE_4 ? POWER_STFSX : POWER_STFDX;
474 cgen_xform(mc, arg2[0] & 31, arg1[1], arg1[2], false);
478 if (reg_is_fp(arg1[0]) && !reg_is_vs(arg1[0]) && reg_is_fp(arg2[0]) && !reg_is_vs(arg2[0])) {
480 cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
483 if (reg_is_vs(arg1[0]) && reg_is_vs(arg2[0])) {
485 cgen_xform(mc, arg1[0] & 31, arg2[0] & 31, arg2[0] & 31, false);
490 internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
494 static bool attr_w cgen_cmp(struct codegen_context *ctx, unsigned size, unsigned writes_flags)
498 uint8_t *arg1 = ctx->code_position;
499 uint8_t *arg2 = arg1 + arg_size(*arg1);
500 ctx->code_position = arg2 + arg_size(*arg2);
502 if (arg2[0] == ARG_IMM) {
503 imm = get_imm(&arg2[1]);
504 mc = writes_flags == 1 ? POWER_CMPI : POWER_CMPLI;
505 if (size == OP_SIZE_8)
507 cgen_dform(mc, 0, arg1[0], imm);
510 mc = writes_flags == 1 ? POWER_CMP : POWER_CMPL;
511 if (size == OP_SIZE_8)
513 cgen_xform(mc, 0, arg1[0], arg2[0], false);
517 internal(file_line, "cgen_cmp: invalid arguments %u, %02x, %02x, %u", size, *arg1, *arg2, writes_flags);
521 static bool attr_w cgen_test(struct codegen_context *ctx)
524 uint8_t *arg1 = ctx->code_position;
525 uint8_t *arg2 = arg1 + arg_size(*arg1);
526 ctx->code_position = arg2 + arg_size(*arg2);
528 if (arg2[0] == ARG_IMM) {
529 imm = get_imm(&arg2[1]);
530 if (imm >= 0 && imm < 0x10000) {
531 cgen_dform(POWER_ANDI_, arg1[0], R_CG_SCRATCH, imm);
536 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL)) {
537 cgen_dform(POWER_ANDIS_, arg1[0], R_CG_SCRATCH, (uint64_t)imm >> 16);
542 cgen_xform(POWER_AND, arg1[0], R_CG_SCRATCH, arg2[0], 1);
547 internal(file_line, "cgen_test: invalid arguments %02x, %02x", *arg1, *arg2);
551 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
555 uint8_t *arg1 = ctx->code_position;
556 uint8_t *arg2 = arg1 + arg_size(*arg1);
557 uint8_t *arg3 = arg2 + arg_size(*arg2);
558 ctx->code_position = arg3 + arg_size(*arg3);
560 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32))
563 if (arg3[0] == ARG_IMM) {
564 bool shifted = false;
565 imm = get_imm(&arg3[1]);
566 if (!imm && (alu == ALU_ADC || alu == ALU_SBB)) {
567 mc = alu == ALU_ADC ? POWER_ADDZE : POWER_ADDME;
568 if (writes_flags & 1) {
569 cgen_four(POWER_MFXER | ((uint32_t)R_CG_SCRATCH << 21));
570 cgen_dform(POWER_ANDIS_, R_CG_SCRATCH, R_CG_SCRATCH, 0x2004U);
571 cgen_four(POWER_MTXER | ((uint32_t)R_CG_SCRATCH << 21));
574 cgen_xform(mc, arg1[0], arg2[0], 0, writes_flags);
577 if (unlikely(writes_flags != (alu == ALU_AND)))
579 if (alu == ALU_SUB) {
580 imm = -(uint64_t)imm;
583 if (alu == ALU_MUL && size == OP_SIZE_8)
588 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
592 if (likely(imm >= -0x80000000LL) && likely(imm < 0x80000000LL)) {
600 if (likely(imm >= 0) && likely(imm < 0x10000))
604 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL)) {
612 if (unlikely(alu * 2 + (unsigned)shifted >= n_array_elements(alu_imm)))
614 mc = alu_imm[alu * 2 + (unsigned)shifted];
618 imm = (uint64_t)imm >> 16;
619 if (alu == ALU_ADD || alu == ALU_MUL)
620 cgen_dform(mc, arg1[0], arg2[0], imm);
622 cgen_dform(mc, arg2[0], arg1[0], imm);
627 if (unlikely(alu * 3 + 2 >= n_array_elements(alu_reg)))
629 mc = alu_reg[alu * 3 + (size == OP_SIZE_8)];
630 flag = alu_reg[alu * 3 + 2];
633 if (writes_flags & 2) {
635 case ALU_ADD: mc = POWER_ADDC; break;
636 case ALU_SUB: mc = POWER_SUBFC; break;
642 if (flag & 1 && writes_flags & 1) {
643 if (alu == ALU_ADC || alu == ALU_SBB) {
644 cgen_four(POWER_MFXER | ((uint32_t)R_CG_SCRATCH << 21));
645 cgen_dform(POWER_ANDIS_, R_CG_SCRATCH, R_CG_SCRATCH, 0x2004U);
646 cgen_four(POWER_MTXER | ((uint32_t)R_CG_SCRATCH << 21));
648 cgen_four(POWER_MTXER | ((uint32_t)R_ZERO << 21));
658 cgen_xform(mc, arg1[0], arg2[0], arg3[0], writes_flags);
660 cgen_xform(mc, arg2[0], arg1[0], arg3[0], writes_flags);
665 internal(file_line, "cgen_alu: invalid arguments %u, %u, %02x, %02x, %02x, %u", size, alu, *arg1, *arg2, *arg3, writes_flags);
669 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
672 uint8_t *arg1 = ctx->code_position;
673 uint8_t *arg2 = arg1 + arg_size(*arg1);
674 ctx->code_position = arg2 + arg_size(*arg2);
676 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32))
681 cgen_xform(POWER_NOR, arg2[0], arg1[0], arg2[0], writes_flags);
684 if (writes_flags & 2)
685 cgen_dform(POWER_SUBFIC, arg1[0], arg2[0], 0);
687 cgen_xform(POWER_NEG, arg1[0], arg2[0], 0, writes_flags);
691 if (writes_flags & 1) {
692 cgen_four(POWER_MFXER | ((uint32_t)R_CG_SCRATCH << 21));
693 cgen_dform(POWER_ANDIS_, R_CG_SCRATCH, R_CG_SCRATCH, 0x2004U);
694 cgen_four(POWER_MTXER | ((uint32_t)R_CG_SCRATCH << 21));
697 cgen_xform(mc, arg1[0], arg2[0], 0, writes_flags);
700 if (unlikely(writes_flags & 2))
701 cgen_dform(POWER_ADDIC, arg1[0], arg2[0], 1);
703 cgen_dform(POWER_ADDI, arg1[0], arg2[0], 1);
706 if (unlikely(writes_flags & 2))
707 cgen_dform(POWER_ADDIC, arg1[0], arg2[0], -1);
709 cgen_dform(POWER_ADDI, arg1[0], arg2[0], -1);
712 cgen_xform(size == OP_SIZE_4 ? POWER_CNTTZW : POWER_CNTTZD, arg2[0], arg1[0], 0, writes_flags);
715 cgen_xform(size == OP_SIZE_4 ? POWER_CNTLZW : POWER_CNTLZD, arg2[0], arg1[0], 0, writes_flags);
718 if (unlikely(writes_flags))
720 cgen_xform(size == OP_SIZE_4 ? POWER_POPCNTW : POWER_POPCNTD, arg2[0], arg1[0], 0, 0);
727 internal(file_line, "cgen_alu1: invalid arguments %u, %u, %02x, %02x, %u", size, alu, *arg1, *arg2, writes_flags);
731 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
735 uint8_t *arg1 = ctx->code_position;
736 uint8_t *arg2 = arg1 + arg_size(*arg1);
737 uint8_t *arg3 = arg2 + arg_size(*arg2);
738 ctx->code_position = arg3 + arg_size(*arg3);
740 if (unlikely(size < OP_SIZE_4))
745 case ROT_ROL: mc = size == OP_SIZE_4 ? POWER_RLWNM | (31 << 1) : POWER_RLDCL; break;
746 case ROT_SHL: mc = size == OP_SIZE_4 ? POWER_SLW : POWER_SLD; break;
747 case ROT_SHR: mc = size == OP_SIZE_4 ? POWER_SRW : POWER_SRD; break;
748 case ROT_SAR: mc = size == OP_SIZE_4 ? POWER_SRAW : POWER_SRAD; break;
751 cgen_xform(mc, arg2[0], arg1[0], arg3[0], writes_flags);
753 } else if (arg3[0] == ARG_IMM) {
755 imm = get_imm(&arg3[1]);
757 if (size == OP_SIZE_4) {
760 mc = POWER_RLWINM | (i32 << 11) | ((31 - i32) << 1);
763 mc = POWER_RLWINM | ((-i32 << 11) & 0xf800U) | (i32 << 6) | 0x3eU;
766 mc = POWER_SRAWI | (i32 << 11);
775 mc |= (i32 << 11) & 0xf800U;
776 mc |= (i32 >> 4) & 0x2U;
777 mc |= ((63 - i32) << 6) & 0x07c0U;
778 mc |= (63 - i32) & 0x0020U;
782 mc |= (-i32 << 11) & 0xf800U;
783 mc |= (-i32 >> 4) & 0x2U;
784 mc |= (i32 << 6) & 0x07c0U;
789 mc |= (i32 << 11) & 0xf800U;
790 mc |= (i32 >> 4) & 0x2U;
796 cgen_xform(mc, arg2[0], arg1[0], 0, writes_flags);
801 internal(file_line, "cgen_rot: invalid arguments %u, %u, %02x, %02x, %02x", size, alu, *arg1, *arg2, *arg3);
805 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned aux)
811 uint8_t *arg1 = ctx->code_position;
812 uint8_t *arg2 = arg1 + arg_size(*arg1);
813 uint8_t *arg3 = arg2 + arg_size(*arg2);
814 ctx->code_position = arg3 + arg_size(*arg3);
816 if (arg2[0] == ARG_IMM) {
817 imm = get_imm(&arg2[1]);
818 if (unlikely(imm != 0))
822 if (arg3[0] == ARG_IMM) {
823 imm = get_imm(&arg3[1]);
824 if (unlikely(imm != 0))
830 case COND_B: aux = COND_L; break;
831 case COND_BE: aux = COND_LE; break;
832 case COND_A: aux = COND_G; break;
833 case COND_AE: aux = COND_GE; break;
837 case COND_O: mc = POWER_ISELSO; swap = false; break;
838 case COND_E: mc = POWER_ISELEQ; swap = false; break;
839 case COND_L: mc = POWER_ISELLT; swap = false; break;
840 case COND_G: mc = POWER_ISELGT; swap = false; break;
841 case COND_NO: mc = POWER_ISELSO; swap = true; break;
842 case COND_NE: mc = POWER_ISELEQ; swap = true; break;
843 case COND_GE: mc = POWER_ISELLT; swap = true; break;
844 case COND_LE: mc = POWER_ISELGT; swap = true; break;
845 case FP_COND_P: mc = POWER_ISELSO; swap = false; break;
846 case FP_COND_E: mc = POWER_ISELEQ; swap = false; break;
847 case FP_COND_B: mc = POWER_ISELLT; swap = false; break;
848 case FP_COND_A: mc = POWER_ISELGT; swap = false; break;
849 case FP_COND_NP:mc = POWER_ISELSO; swap = true; break;
850 case FP_COND_NE:mc = POWER_ISELEQ; swap = true; break;
851 case FP_COND_AE:mc = POWER_ISELLT; swap = true; break;
852 case FP_COND_BE:mc = POWER_ISELGT; swap = true; break;
862 cgen_xform(mc, arg1[0], arg3[0], arg2[0], false);
866 internal(file_line, "cgen_cmov: invalid arguments %u, %02x, %02x, %02x", aux, *arg1, *arg2, *arg3);
870 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned attr_unused op_size)
873 uint8_t *arg1 = ctx->code_position;
874 uint8_t *arg2 = arg1 + arg_size(*arg1);
875 ctx->code_position = arg2 + arg_size(*arg2);
876 mc = op_size != OP_SIZE_16 ? POWER_FCMPU : POWER_XSCMPUQP;
877 cgen_xform(mc, 0, arg1[0] & 31, arg2[0] & 31, false);
881 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
883 bool use_s = op_size == OP_SIZE_4;
884 bool use_vs = op_size == OP_SIZE_16;
886 uint8_t *arg1 = ctx->code_position;
887 uint8_t *arg2 = arg1 + arg_size(*arg1);
888 uint8_t *arg3 = arg2 + arg_size(*arg2);
889 ctx->code_position = arg3 + arg_size(*arg3);
891 case FP_ALU_ADD: mc = use_vs ? POWER_XSADDQP : use_s ? POWER_FADDS : POWER_FADD; break;
892 case FP_ALU_SUB: mc = use_vs ? POWER_XSSUBQP : use_s ? POWER_FSUBS : POWER_FSUB; break;
893 case FP_ALU_MUL: mc = use_vs ? POWER_XSMULQP : use_s ? POWER_FMULS : POWER_FMUL; break;
894 case FP_ALU_DIV: mc = use_vs ? POWER_XSDIVQP : use_s ? POWER_FDIVS : POWER_FDIV; break;
897 if (aux == FP_ALU_MUL && !use_vs)
898 cgen_xform(mc | ((arg3[0] & 31) << 6), arg1[0] & 31, arg2[0] & 31, 0, false);
900 cgen_xform(mc, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31, false);
903 internal(file_line, "cgen_fp_alu: invalid arguments %u, %u, %02x, %02x, %02x", op_size, aux, *arg1, *arg2, *arg3);
907 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
909 bool use_s = op_size == OP_SIZE_4 && cpu_test_feature(CPU_FEATURE_ppc);
910 bool use_vs = op_size == OP_SIZE_16;
912 uint8_t *arg1 = ctx->code_position;
913 uint8_t *arg2 = arg1 + arg_size(*arg1);
914 ctx->code_position = arg2 + arg_size(*arg2);
916 case FP_ALU1_NEG: mc = use_vs ? POWER_XSNEGQP : POWER_FNEG;
918 case FP_ALU1_SQRT: if (unlikely(use_vs))
920 mc = use_s ? POWER_FSQRTS : POWER_FSQRT; break;
923 cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
926 internal(file_line, "cgen_fp_alu1: invalid arguments %u, %u, %02x, %02x", op_size, aux, *arg1, *arg2);
930 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned fp_op_size)
933 uint8_t *arg1 = ctx->code_position;
934 uint8_t *arg2 = arg1 + arg_size(*arg1);
935 ctx->code_position = arg2 + arg_size(*arg2);
936 mc = fp_op_size <= OP_SIZE_8 ? POWER_FCTIDZ : POWER_XSCVQPSDZ;
937 cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
941 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
944 uint8_t *arg1 = ctx->code_position;
945 uint8_t *arg2 = arg1 + arg_size(*arg1);
946 ctx->code_position = arg2 + arg_size(*arg2);
947 mc = fp_op_size == OP_SIZE_4 ? POWER_FCFIDS : fp_op_size == OP_SIZE_8 ? POWER_FCFID : POWER_XSCVSDQP;
948 cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
952 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, bool lng, unsigned aux, bool logical)
956 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
961 if (unlikely(aux >= n_array_elements(jmp_cond)))
965 if (unlikely(aux >= n_array_elements(jmp_cond_logical)))
967 mc = jmp_cond_logical[aux];
976 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
983 internal(file_line, "cgen_jmp_cond: invalid %scondition %x", logical ? "logical " : "", aux);
987 static bool attr_w cgen_jmp_indirect(struct codegen_context *ctx)
990 unsigned reg = cget_one(ctx);
993 mc |= (uint32_t)reg << 21;
1002 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1005 int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)reloc->position;
1006 switch (reloc->length) {
1008 if (unlikely(offs < -0x8000) || unlikely(offs >= 0x8000))
1010 memcpy(&mc, ctx->mcode + reloc->position, 4);
1012 mc |= offs & 0xfffcU;
1013 memcpy(ctx->mcode + reloc->position, &mc, 4);
1016 if (unlikely(offs < -0x01000000) || unlikely(offs >= 0x01000000))
1018 memcpy(&mc, ctx->mcode + reloc->position, 4);
1020 mc |= offs & 0x3fffffcU;
1021 memcpy(ctx->mcode + reloc->position, &mc, 4);
1024 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1029 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1032 switch (insn_opcode(insn)) {
1040 cgen_four(POWER_BLR);
1042 case INSN_CALL_INDIRECT:
1043 reg = cget_one(ctx);
1044 if (unlikely(reg != R_CTR))
1046 cgen_four(POWER_BCTRL);
1049 g(cgen_mov(ctx, insn_op_size(insn), false));
1052 g(cgen_mov(ctx, insn_op_size(insn), true));
1055 g(cgen_cmp(ctx, insn_op_size(insn), insn_writes_flags(insn)));
1058 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1063 case INSN_ALU_FLAGS:
1064 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE) && !((insn_aux(insn) >= ALU_UDIV && insn_aux(insn) <= ALU_SREM) || insn_aux(insn) == ALU_MUL))
1066 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1069 case INSN_ALU1_FLAGS:
1070 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1072 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1075 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1079 if (unlikely(!cpu_test_feature(CPU_FEATURE_v203)))
1081 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1083 g(cgen_cmov(ctx, insn_aux(insn)));
1086 g(cgen_fp_cmp(ctx, insn_op_size(insn)));
1089 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1092 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1094 case INSN_FP_TO_INT64:
1095 g(cgen_fp_to_int(ctx, insn_op_size(insn)));
1097 case INSN_FP_FROM_INT64:
1098 g(cgen_fp_from_int(ctx, insn_op_size(insn)));
1101 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1105 g(cgen_jmp_cond(ctx, insn_jump_size(insn) == JMP_SHORT, insn_aux(insn), false));
1107 case INSN_JMP_COND_LOGICAL:
1108 g(cgen_jmp_cond(ctx, insn_jump_size(insn) == JMP_SHORT, insn_aux(insn), true));
1110 case INSN_JMP_INDIRECT:
1111 g(cgen_jmp_indirect(ctx));
1115 internal(file_line, "cgen_insn: invalid insn %08x", insn);