codegen: add a 'size' argument to ALU_WRITES_FLAGS
[ajla.git] / c2-power.inc
bloba3a1651cb27085d100996f4574eb7ca026ba74f5
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
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
9  * version.
10  *
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.
14  *
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/>.
17  */
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,
197         0, 0,
198         0, 0,
199         POWER_ANDI_, POWER_ANDIS_,
200         0, 0,
201         POWER_XORI, POWER_XORIS,
202         0, 0,
204         0, 0,
205         0, 0,
206         0, 0,
207         0, 0,
208         0, 0,
209         0, 0,
210         0, 0,
211         0, 0,
213         POWER_MULLI, 0,
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,
224         0, 0, 0,
226         POWER_ORC, POWER_ORC, 0,
227         POWER_ANDC, POWER_ANDC, 0,
228         POWER_EQV, POWER_EQV, 0,
229         0, 0, 0,
230         0, 0, 0,
231         0, 0, 0,
232         0, 0, 0,
233         0, 0, 0,
235         POWER_MULLW, POWER_MULLD, 1,
236         0, 0, 0,
237         0, 0, 0,
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,
247         0, 0, 0, 0,
248         POWER_BLT, POWER_BGE, POWER_BLE, POWER_BGT,
249         0, 0, 0, 0,
250         0, 0, 0, 0,
251         0, 0, 0, 0,
252         0, 0, 0, 0,
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)
266         uint32_t mc;
267         int64_t imm;
268         uint8_t z = R_ZERO;
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)
273                 sx = false;
274         if (arg1[0] < 32) {
275                 if (arg2[0] < 32) {
276                         if (unlikely(size == OP_SIZE_NATIVE)) {
277                                 cgen_xform(POWER_OR, arg2[0], arg1[0], arg2[0], false);
278                                 return true;
279                         }
280                         if (sx) {
281                                 switch (size) {
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;
285                                         default:        goto invl;
286                                 }
287                         } else {
288                                 switch (size) {
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;
292                                         default:        goto invl;
293                                 }
294                         }
295                         cgen_xform(mc, arg2[0], arg1[0], 0, false);
296                         return true;
297                 }
298                 if (arg2[0] == R_CTR) {
299                         mc = POWER_MFCTR;
300                         mc |= (uint32_t)arg1[0] << 21;
301                         cgen_four(mc);
302                         return true;
303                 }
304                 if (arg2[0] == R_LR) {
305                         mc = POWER_MFLR;
306                         mc |= (uint32_t)arg1[0] << 21;
307                         cgen_four(mc);
308                         return true;
309                 }
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);
314                                 return true;
315                         } else {
316                                 if (imm & 0xffffULL)
317                                         internal(file_line, "cgen_mov: invalid imm");
318                                 cgen_dform(POWER_ADDIS, arg1[0], 0, (uint64_t)imm >> 16);
319                                 return true;
320                         }
321                 }
322                 if (arg2[0] == ARG_ADDRESS_1) {
323                         mc = load_a1[size + (unsigned)sx * 4];
324                         if (unlikely(!mc))
325                                 goto invl;
326                         imm = get_imm(&arg2[2]);
327                         cgen_dform(mc, arg1[0], arg2[1], imm);
328                         return true;
329                 }
330                 if (arg2[0] == ARG_ADDRESS_2) {
331                         mc = load_a2[size + (unsigned)sx * 4];
332                         if (unlikely(!mc))
333                                 goto invl;
334                         imm = get_imm(&arg2[3]);
335                         if (imm)
336                                 internal(file_line, "cgen_mov: imm is not zero");
337                         cgen_xform(mc, arg1[0], arg2[1], arg2[2], false);
338                         return true;
339                 }
340         }
341         if (arg2[0] == ARG_IMM) {
342                 imm = get_imm(&arg2[1]);
343                 if (unlikely(imm != 0))
344                         goto invl;
345                 arg2 = &z;
346         }
347         if (arg1[0] == R_CTR && arg2[0] < 32) {
348                 mc = POWER_MTCTR;
349                 mc |= (uint32_t)arg2[0] << 21;
350                 cgen_four(mc);
351                 return true;
352         }
353         if (arg1[0] == R_LR && arg2[0] < 32) {
354                 mc = POWER_MTLR;
355                 mc |= (uint32_t)arg2[0] << 21;
356                 cgen_four(mc);
357                 return true;
358         }
359         if (arg2[0] < 32) {
360                 if (arg1[0] == ARG_ADDRESS_1) {
361                         mc = store_a1[size];
362                         imm = get_imm(&arg1[2]);
363                         cgen_dform(mc, arg2[0], arg1[1], imm);
364                         return true;
365                 }
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);
370                         return true;
371                 }
372                 if (arg1[0] == ARG_ADDRESS_2) {
373                         mc = store_a2[size];
374                         imm = get_imm(&arg1[3]);
375                         if (imm)
376                                 internal(file_line, "cgen_mov: imm is not zero");
377                         cgen_xform(mc, arg2[0], arg1[1], arg1[2], false);
378                         return true;
379                 }
380         }
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]);
384                         mc = POWER_LXV;
385                         mc |= (arg1[0] & 32) >> 2;
386                         cgen_dform(mc, arg1[0] & 31, arg2[1], imm);
387                         return true;
388                 }
389                 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
390                         imm = get_imm(&arg2[3]);
391                         if (imm)
392                                 internal(file_line, "cgen_mov: imm is not zero");
393                         mc = POWER_LXVX;
394                         cgen_xform(mc, arg1[0] & 31, arg2[1], arg2[2], !!(arg1[0] & 32));
395                         return true;
396                 }
397         }
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]);
401                         mc = POWER_STXV;
402                         mc |= (arg2[0] & 32) >> 2;
403                         cgen_dform(mc, arg2[0] & 31, arg1[1], imm);
404                         return true;
405                 }
406                 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
407                         imm = get_imm(&arg1[3]);
408                         if (imm)
409                                 internal(file_line, "cgen_mov: imm is not zero");
410                         mc = POWER_STXVX;
411                         cgen_xform(mc, arg2[0] & 31, arg1[1], arg1[2], !!(arg2[0] & 32));
412                         return true;
413                 }
414         }
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]);
418                         mc = POWER_LXSD;
419                         cgen_dform(mc, arg1[0] & 31, arg2[1], imm);
420                         return true;
421                 }
422                 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
423                         imm = get_imm(&arg2[3]);
424                         if (imm)
425                                 internal(file_line, "cgen_mov: imm is not zero");
426                         mc = POWER_LXSDX;
427                         cgen_xform(mc, arg1[0] & 31, arg2[1], arg2[2], false);
428                         return true;
429                 }
430         }
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]);
434                         mc = POWER_STXSD;
435                         cgen_dform(mc, arg2[0] & 31, arg1[1], imm);
436                         return true;
437                 }
438                 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
439                         imm = get_imm(&arg1[3]);
440                         if (imm)
441                                 internal(file_line, "cgen_mov: imm is not zero");
442                         mc = POWER_STXSDX;
443                         cgen_xform(mc, arg2[0] & 31, arg1[1], arg1[2], false);
444                         return true;
445                 }
446         }
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);
452                         return true;
453                 }
454                 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
455                         imm = get_imm(&arg2[3]);
456                         if (imm)
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);
460                         return true;
461                 }
462         }
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);
468                         return true;
469                 }
470                 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
471                         imm = get_imm(&arg1[3]);
472                         if (imm)
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);
476                         return true;
477                 }
478         }
479         if (reg_is_fp(arg1[0]) && !reg_is_vs(arg1[0]) && reg_is_fp(arg2[0]) && !reg_is_vs(arg2[0])) {
480                 mc = POWER_FMR;
481                 cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
482                 return true;
483         }
484         if (reg_is_vs(arg1[0]) && reg_is_vs(arg2[0])) {
485                 mc = POWER_XXLOR;
486                 cgen_xform(mc, arg1[0] & 31, arg2[0] & 31, arg2[0] & 31, false);
487                 return true;
488         }
490 invl:
491         internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
492         return false;
495 static bool attr_w cgen_cmp(struct codegen_context *ctx, unsigned size, unsigned writes_flags)
497         uint32_t mc;
498         int64_t imm;
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)
507                         mc |= POWER_CMP_L;
508                 cgen_dform(mc, 0, arg1[0], imm);
509                 return true;
510         } else {
511                 mc = writes_flags == 1 ? POWER_CMP : POWER_CMPL;
512                 if (size == OP_SIZE_8)
513                         mc |= POWER_CMP_L;
514                 cgen_xform(mc, 0, arg1[0], arg2[0], false);
515                 return true;
516         }
518         internal(file_line, "cgen_cmp: invalid arguments %u, %02x, %02x, %u", size, *arg1, *arg2, writes_flags);
519         return false;
522 static bool attr_w cgen_test(struct codegen_context *ctx)
524         int64_t imm;
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);
533                         return true;
534                 }
535                 if (imm & 0xffff)
536                         goto invl;
537                 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL)) {
538                         cgen_dform(POWER_ANDIS_, arg1[0], R_CG_SCRATCH, (uint64_t)imm >> 16);
539                         return true;
540                 }
541                 goto invl;
542         } else {
543                 cgen_xform(POWER_AND, arg1[0], R_CG_SCRATCH, arg2[0], 1);
544                 return true;
545         }
547 invl:
548         internal(file_line, "cgen_test: invalid arguments %02x, %02x", *arg1, *arg2);
549         return false;
552 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
554         uint32_t mc;
555         int64_t imm;
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))
562                 goto invl;
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));
573                                 mc |= POWER_OE;
574                         }
575                         cgen_xform(mc, arg1[0], arg2[0], 0, writes_flags);
576                         return true;
577                 }
578                 if (unlikely(writes_flags != (alu == ALU_AND)))
579                         goto invl;
580                 if (alu == ALU_SUB) {
581                         imm = -(uint64_t)imm;
582                         alu = ALU_ADD;
583                 }
584                 if (alu == ALU_MUL && size == OP_SIZE_8)
585                         goto invl;
586                 switch (alu) {
587                         case ALU_ADD:
588                         case ALU_MUL:
589                                 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
590                                         break;
591                                 if (imm & 0xffff)
592                                         goto invl;
593                                 if (likely(imm >= -0x80000000LL) && likely(imm < 0x80000000LL)) {
594                                         shifted = true;
595                                         break;
596                                 }
597                                 goto invl;
598                         case ALU_AND:
599                         case ALU_OR:
600                         case ALU_XOR:
601                                 if (likely(imm >= 0) && likely(imm < 0x10000))
602                                         break;
603                                 if (imm & 0xffff)
604                                         goto invl;
605                                 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL)) {
606                                         shifted = true;
607                                         break;
608                                 }
609                                 goto invl;
610                         default:
611                                 goto invl;
612                 }
613                 if (unlikely(alu * 2 + (unsigned)shifted >= n_array_elements(alu_imm)))
614                         goto invl;
615                 mc = alu_imm[alu * 2 + (unsigned)shifted];
616                 if (unlikely(!mc))
617                         goto invl;
618                 if (shifted)
619                         imm = (uint64_t)imm >> 16;
620                 if (alu == ALU_ADD || alu == ALU_MUL)
621                         cgen_dform(mc, arg1[0], arg2[0], imm);
622                 else
623                         cgen_dform(mc, arg2[0], arg1[0], imm);
624                 return true;
625         }
626         if (arg3[0] < 32) {
627                 int flag;
628                 if (unlikely(alu * 3 + 2 >= n_array_elements(alu_reg)))
629                         goto invl;
630                 mc = alu_reg[alu * 3 + (size == OP_SIZE_8)];
631                 flag = alu_reg[alu * 3 + 2];
632                 if (unlikely(!mc))
633                         goto invl;
634                 if (writes_flags & 2) {
635                         switch (alu) {
636                                 case ALU_ADD:   mc = POWER_ADDC; break;
637                                 case ALU_SUB:   mc = POWER_SUBFC; break;
638                                 case ALU_ADC:
639                                 case ALU_SBB:   break;
640                                 default:        goto invl;
641                         }
642                 }
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));
648                         } else {
649                                 cgen_four(POWER_MTXER | ((uint32_t)R_ZERO << 21));
650                         }
651                         mc |= POWER_OE;
652                 }
653                 if (flag & 2) {
654                         uint8_t *t = arg2;
655                         arg2 = arg3;
656                         arg3 = t;
657                 }
658                 if (flag & 1)
659                         cgen_xform(mc, arg1[0], arg2[0], arg3[0], writes_flags);
660                 else
661                         cgen_xform(mc, arg2[0], arg1[0], arg3[0], writes_flags);
662                 return true;
663         }
665 invl:
666         internal(file_line, "cgen_alu: invalid arguments %u, %u, %02x, %02x, %02x, %u", size, alu, *arg1, *arg2, *arg3, writes_flags);
667         return false;
670 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
672         uint32_t mc;
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))
678                 goto invl;
680         switch (alu) {
681                 case ALU1_NOT:
682                         cgen_xform(POWER_NOR, arg2[0], arg1[0], arg2[0], writes_flags);
683                         return true;
684                 case ALU1_NEG:
685                         if (writes_flags & 2)
686                                 cgen_dform(POWER_SUBFIC, arg1[0], arg2[0], 0);
687                         else
688                                 cgen_xform(POWER_NEG, arg1[0], arg2[0], 0, writes_flags);
689                         return true;
690                 case ALU1_NGC:
691                         mc = POWER_SUBFZE;
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));
696                                 mc |= POWER_OE;
697                         }
698                         cgen_xform(mc, arg1[0], arg2[0], 0, writes_flags);
699                         return true;
700                 case ALU1_BSF:
701                         cgen_xform(size == OP_SIZE_4 ? POWER_CNTTZW : POWER_CNTTZD, arg2[0], arg1[0], 0, writes_flags);
702                         return true;
703                 case ALU1_LZCNT:
704                         cgen_xform(size == OP_SIZE_4 ? POWER_CNTLZW : POWER_CNTLZD, arg2[0], arg1[0], 0, writes_flags);
705                         return true;
706                 case ALU1_POPCNT:
707                         if (unlikely(writes_flags))
708                                 goto invl;
709                         cgen_xform(size == OP_SIZE_4 ? POWER_POPCNTW : POWER_POPCNTD, arg2[0], arg1[0], 0, 0);
710                         return true;
711                 default:
712                         goto invl;
713         }
715 invl:
716         internal(file_line, "cgen_alu1: invalid arguments %u, %u, %02x, %02x, %u", size, alu, *arg1, *arg2, writes_flags);
717         return false;
720 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
722         uint32_t mc;
723         int64_t imm;
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))
730                 goto invl;
732         if (arg3[0] < 32) {
733                 switch (alu) {
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;
738                         default: goto invl;
739                 }
740                 cgen_xform(mc, arg2[0], arg1[0], arg3[0], writes_flags);
741                 return true;
742         } else if (arg3[0] == ARG_IMM) {
743                 uint32_t i32;
744                 imm = get_imm(&arg3[1]);
745                 i32 = (uint32_t)imm;
746                 if (size == OP_SIZE_4) {
747                         switch (alu) {
748                                 case ROT_ROL:
749                                         mc = POWER_RLWINM | (i32 << 11) | 0x3e;
750                                         break;
751                                 case ROT_SHL:
752                                         mc = POWER_RLWINM | (i32 << 11) | ((31 - i32) << 1);
753                                         break;
754                                 case ROT_SHR:
755                                         mc = POWER_RLWINM | ((-i32 << 11) & 0xf800U) | (i32 << 6) | 0x3eU;
756                                         break;
757                                 case ROT_SAR:
758                                         mc = POWER_SRAWI | (i32 << 11);
759                                         break;
760                                 default:
761                                         goto invl;
762                         }
763                 } else {
764                         switch (alu) {
765                                 case ROT_ROL:
766                                         mc = POWER_RLDICL;
767                                         mc |= (i32 & 0x1f) << 11;
768                                         mc |= (i32 & 0x20) >> 4;
769                                         break;
770                                 case ROT_SHL:
771                                         mc = POWER_RLDICR;
772                                         mc |= (i32 << 11) & 0xf800U;
773                                         mc |= (i32 >> 4) & 0x2U;
774                                         mc |= ((63 - i32) << 6) & 0x07c0U;
775                                         mc |= (63 - i32) & 0x0020U;
776                                         break;
777                                 case ROT_SHR:
778                                         mc = POWER_RLDICL;
779                                         mc |= (-i32 << 11) & 0xf800U;
780                                         mc |= (-i32 >> 4) & 0x2U;
781                                         mc |= (i32 << 6) & 0x07c0U;
782                                         mc |= i32 & 0x0020U;
783                                         break;
784                                 case ROT_SAR:
785                                         mc = POWER_SRADI;
786                                         mc |= (i32 << 11) & 0xf800U;
787                                         mc |= (i32 >> 4) & 0x2U;
788                                         break;
789                                 default:
790                                         goto invl;
791                         }
792                 }
793                 cgen_xform(mc, arg2[0], arg1[0], 0, writes_flags);
794                 return true;
795         }
797 invl:
798         internal(file_line, "cgen_rot: invalid arguments %u, %u, %02x, %02x, %02x", size, alu, *arg1, *arg2, *arg3);
799         return false;
802 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned aux)
804         bool swap;
805         uint32_t mc;
806         int64_t imm;
807         uint8_t z = R_ZERO;
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))
816                         goto invl;
817                 arg2 = &z;
818         }
819         if (arg3[0] == ARG_IMM) {
820                 imm = get_imm(&arg3[1]);
821                 if (unlikely(imm != 0))
822                         goto invl;
823                 arg3 = &z;
824         }
826         switch (aux) {
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;
831         }
833         switch (aux) {
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;
850                 default:        goto invl;
851         }
853         if (swap) {
854                 uint8_t *t = arg2;
855                 arg2 = arg3;
856                 arg3 = t;
857         }
859         cgen_xform(mc, arg1[0], arg3[0], arg2[0], false);
860         return true;
862 invl:
863         internal(file_line, "cgen_cmov: invalid arguments %u, %02x, %02x, %02x", aux, *arg1, *arg2, *arg3);
864         return false;
867 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned attr_unused op_size)
869         uint32_t mc;
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);
875         return true;
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;
882         uint32_t mc;
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);
887         switch (aux) {
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;
892                 default:                goto invl;
893         }
894         if (aux == FP_ALU_MUL && !use_vs)
895                 cgen_xform(mc | ((arg3[0] & 31) << 6), arg1[0] & 31, arg2[0] & 31, 0, false);
896         else
897                 cgen_xform(mc, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31, false);
898         return true;
899 invl:
900         internal(file_line, "cgen_fp_alu: invalid arguments %u, %u, %02x, %02x, %02x", op_size, aux, *arg1, *arg2, *arg3);
901         return false;
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;
908         uint32_t mc;
909         uint8_t *arg1 = ctx->code_position;
910         uint8_t *arg2 = arg1 + arg_size(*arg1);
911         ctx->code_position = arg2 + arg_size(*arg2);
912         switch (aux) {
913                 case FP_ALU1_NEG:       mc = use_vs ? POWER_XSNEGQP : POWER_FNEG;
914                                         break;
915                 case FP_ALU1_SQRT:      if (unlikely(use_vs))
916                                                 goto invl;
917                                         mc = use_s ? POWER_FSQRTS : POWER_FSQRT; break;
918                 default:                goto invl;
919         }
920         cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
921         return true;
922 invl:
923         internal(file_line, "cgen_fp_alu1: invalid arguments %u, %u, %02x, %02x", op_size, aux, *arg1, *arg2);
924         return false;
927 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned fp_op_size)
929         uint32_t mc;
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);
935         return true;
938 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
940         uint32_t mc;
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);
946         return true;
949 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, bool lng, unsigned aux, bool logical)
951         uint32_t mc;
952         if (!lng) {
953                 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
954         } else {
955                 aux ^= 1;
956         }
957         if (!logical) {
958                 if (unlikely(aux >= n_array_elements(jmp_cond)))
959                         goto invl;
960                 mc = jmp_cond[aux];
961         } else {
962                 if (unlikely(aux >= n_array_elements(jmp_cond_logical)))
963                         goto invl;
964                 mc = jmp_cond_logical[aux];
965         }
966         if (unlikely(!mc))
967                 goto invl;
969         if (!lng) {
970                 cgen_four(mc);
971         } else {
972                 cgen_four(mc | 0x8);
973                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
974                 cgen_four(POWER_B);
975         }
977         return true;
979 invl:
980         internal(file_line, "cgen_jmp_cond: invalid %scondition %x", logical ? "logical " : "", aux);
981         return false;
984 static bool attr_w cgen_jmp_indirect(struct codegen_context *ctx)
986         uint32_t mc;
987         unsigned reg = cget_one(ctx);
989         mc = POWER_MTCTR;
990         mc |= (uint32_t)reg << 21;
991         cgen_four(mc);
993         mc = POWER_BCTR;
994         cgen_four(mc);
996         return true;
999 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1001         uint32_t mc;
1002         int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)reloc->position;
1003         switch (reloc->length) {
1004                 case JMP_SHORTEST:
1005                         if (unlikely(offs < -0x8000) || unlikely(offs >= 0x8000))
1006                                 return false;
1007                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1008                         mc &= 0xffff0003U;
1009                         mc |= offs & 0xfffcU;
1010                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1011                         return true;
1012                 case JMP_SHORT:
1013                         if (unlikely(offs < -0x01000000) || unlikely(offs >= 0x01000000))
1014                                 return false;
1015                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1016                         mc &= 0xfc000003U;
1017                         mc |= offs & 0x3fffffcU;
1018                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1019                         return true;
1020                 default:
1021                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1022         }
1023         return false;
1026 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1028         uint32_t reg;
1029         switch (insn_opcode(insn)) {
1030                 case INSN_ENTRY:
1031                         g(cgen_entry(ctx));
1032                         return true;
1033                 case INSN_LABEL:
1034                         g(cgen_label(ctx));
1035                         return true;
1036                 case INSN_RET:
1037                         cgen_four(POWER_BLR);
1038                         return true;
1039                 case INSN_CALL_INDIRECT:
1040                         reg = cget_one(ctx);
1041                         if (unlikely(reg != R_CTR))
1042                                 goto invalid_insn;
1043                         cgen_four(POWER_BCTRL);
1044                         return true;
1045                 case INSN_MOV:
1046                         g(cgen_mov(ctx, insn_op_size(insn), false));
1047                         return true;
1048                 case INSN_MOVSX:
1049                         g(cgen_mov(ctx, insn_op_size(insn), true));
1050                         return true;
1051                 case INSN_CMP:
1052                         g(cgen_cmp(ctx, insn_op_size(insn), insn_writes_flags(insn)));
1053                         return true;
1054                 case INSN_TEST:
1055                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1056                                 goto invalid_insn;
1057                         g(cgen_test(ctx));
1058                         return true;
1059                 case INSN_ALU:
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))
1062                                 goto invalid_insn;
1063                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1064                         return true;
1065                 case INSN_ALU1:
1066                 case INSN_ALU1_FLAGS:
1067                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1068                                 goto invalid_insn;
1069                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1070                         return true;
1071                 case INSN_ROT:
1072                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1073                         return true;
1074                 case INSN_CMOV:
1075                 case INSN_CMOV_XCC:
1076                         if (unlikely(!cpu_test_feature(CPU_FEATURE_v203)))
1077                                 goto invalid_insn;
1078                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1079                                 goto invalid_insn;
1080                         g(cgen_cmov(ctx, insn_aux(insn)));
1081                         return true;
1082                 case INSN_FP_CMP:
1083                         g(cgen_fp_cmp(ctx, insn_op_size(insn)));
1084                         return true;
1085                 case INSN_FP_ALU:
1086                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1087                         return true;
1088                 case INSN_FP_ALU1:
1089                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1090                         return true;
1091                 case INSN_FP_TO_INT64:
1092                         g(cgen_fp_to_int(ctx, insn_op_size(insn)));
1093                         return true;
1094                 case INSN_FP_FROM_INT64:
1095                         g(cgen_fp_from_int(ctx, insn_op_size(insn)));
1096                         return true;
1097                 case INSN_JMP:
1098                         g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1099                         cgen_four(POWER_B);
1100                         return true;
1101                 case INSN_JMP_COND:
1102                         g(cgen_jmp_cond(ctx, insn_jump_size(insn) == JMP_SHORT, insn_aux(insn), false));
1103                         return true;
1104                 case INSN_JMP_COND_LOGICAL:
1105                         g(cgen_jmp_cond(ctx, insn_jump_size(insn) == JMP_SHORT, insn_aux(insn), true));
1106                         return true;
1107                 case INSN_JMP_INDIRECT:
1108                         g(cgen_jmp_indirect(ctx));
1109                         return true;
1110                 invalid_insn:
1111                 default:
1112                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
1113                         return false;
1114         }