ssa: delete unused label skip_must_be_flat
[ajla.git] / c2-power.inc
blobdffa09572e58ec987138597fb9b209b1c508b690
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_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,
196         0, 0,
197         0, 0,
198         POWER_ANDI_, POWER_ANDIS_,
199         0, 0,
200         POWER_XORI, POWER_XORIS,
201         0, 0,
203         0, 0,
204         0, 0,
205         0, 0,
206         0, 0,
207         0, 0,
208         0, 0,
209         0, 0,
210         0, 0,
212         POWER_MULLI, 0,
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,
223         0, 0, 0,
225         POWER_ORC, POWER_ORC, 0,
226         POWER_ANDC, POWER_ANDC, 0,
227         POWER_EQV, POWER_EQV, 0,
228         0, 0, 0,
229         0, 0, 0,
230         0, 0, 0,
231         0, 0, 0,
232         0, 0, 0,
234         POWER_MULLW, POWER_MULLD, 1,
235         0, 0, 0,
236         0, 0, 0,
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,
246         0, 0, 0, 0,
247         POWER_BLT, POWER_BGE, POWER_BLE, POWER_BGT,
248         0, 0, 0, 0,
249         0, 0, 0, 0,
250         0, 0, 0, 0,
251         0, 0, 0, 0,
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)
265         uint32_t mc;
266         int64_t imm;
267         uint8_t z = R_ZERO;
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)
272                 sx = false;
273         if (arg1[0] < 32) {
274                 if (arg2[0] < 32) {
275                         if (unlikely(size == OP_SIZE_NATIVE)) {
276                                 cgen_xform(POWER_OR, arg2[0], arg1[0], arg2[0], false);
277                                 return true;
278                         }
279                         if (sx) {
280                                 switch (size) {
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;
284                                         default:        goto invl;
285                                 }
286                         } else {
287                                 switch (size) {
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;
291                                         default:        goto invl;
292                                 }
293                         }
294                         cgen_xform(mc, arg2[0], arg1[0], 0, false);
295                         return true;
296                 }
297                 if (arg2[0] == R_CTR) {
298                         mc = POWER_MFCTR;
299                         mc |= (uint32_t)arg1[0] << 21;
300                         cgen_four(mc);
301                         return true;
302                 }
303                 if (arg2[0] == R_LR) {
304                         mc = POWER_MFLR;
305                         mc |= (uint32_t)arg1[0] << 21;
306                         cgen_four(mc);
307                         return true;
308                 }
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);
313                                 return true;
314                         } else {
315                                 if (imm & 0xffffULL)
316                                         internal(file_line, "cgen_mov: invalid imm");
317                                 cgen_dform(POWER_ADDIS, arg1[0], 0, (uint64_t)imm >> 16);
318                                 return true;
319                         }
320                 }
321                 if (arg2[0] == ARG_ADDRESS_1) {
322                         mc = load_a1[size + (unsigned)sx * 4];
323                         if (unlikely(!mc))
324                                 goto invl;
325                         imm = get_imm(&arg2[2]);
326                         cgen_dform(mc, arg1[0], arg2[1], imm);
327                         return true;
328                 }
329                 if (arg2[0] == ARG_ADDRESS_2) {
330                         mc = load_a2[size + (unsigned)sx * 4];
331                         if (unlikely(!mc))
332                                 goto invl;
333                         imm = get_imm(&arg2[3]);
334                         if (imm)
335                                 internal(file_line, "cgen_mov: imm is not zero");
336                         cgen_xform(mc, arg1[0], arg2[1], arg2[2], false);
337                         return true;
338                 }
339         }
340         if (arg2[0] == ARG_IMM) {
341                 imm = get_imm(&arg2[1]);
342                 if (unlikely(imm != 0))
343                         goto invl;
344                 arg2 = &z;
345         }
346         if (arg1[0] == R_CTR && arg2[0] < 32) {
347                 mc = POWER_MTCTR;
348                 mc |= (uint32_t)arg2[0] << 21;
349                 cgen_four(mc);
350                 return true;
351         }
352         if (arg1[0] == R_LR && arg2[0] < 32) {
353                 mc = POWER_MTLR;
354                 mc |= (uint32_t)arg2[0] << 21;
355                 cgen_four(mc);
356                 return true;
357         }
358         if (arg2[0] < 32) {
359                 if (arg1[0] == ARG_ADDRESS_1) {
360                         mc = store_a1[size];
361                         imm = get_imm(&arg1[2]);
362                         cgen_dform(mc, arg2[0], arg1[1], imm);
363                         return true;
364                 }
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);
369                         return true;
370                 }
371                 if (arg1[0] == ARG_ADDRESS_2) {
372                         mc = store_a2[size];
373                         imm = get_imm(&arg1[3]);
374                         if (imm)
375                                 internal(file_line, "cgen_mov: imm is not zero");
376                         cgen_xform(mc, arg2[0], arg1[1], arg1[2], false);
377                         return true;
378                 }
379         }
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]);
383                         mc = POWER_LXV;
384                         mc |= (arg1[0] & 32) >> 2;
385                         cgen_dform(mc, arg1[0] & 31, arg2[1], imm);
386                         return true;
387                 }
388                 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
389                         imm = get_imm(&arg2[3]);
390                         if (imm)
391                                 internal(file_line, "cgen_mov: imm is not zero");
392                         mc = POWER_LXVX;
393                         cgen_xform(mc, arg1[0] & 31, arg2[1], arg2[2], !!(arg1[0] & 32));
394                         return true;
395                 }
396         }
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]);
400                         mc = POWER_STXV;
401                         mc |= (arg2[0] & 32) >> 2;
402                         cgen_dform(mc, arg2[0] & 31, arg1[1], imm);
403                         return true;
404                 }
405                 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
406                         imm = get_imm(&arg1[3]);
407                         if (imm)
408                                 internal(file_line, "cgen_mov: imm is not zero");
409                         mc = POWER_STXVX;
410                         cgen_xform(mc, arg2[0] & 31, arg1[1], arg1[2], !!(arg2[0] & 32));
411                         return true;
412                 }
413         }
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]);
417                         mc = POWER_LXSD;
418                         cgen_dform(mc, arg1[0] & 31, arg2[1], imm);
419                         return true;
420                 }
421                 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
422                         imm = get_imm(&arg2[3]);
423                         if (imm)
424                                 internal(file_line, "cgen_mov: imm is not zero");
425                         mc = POWER_LXSDX;
426                         cgen_xform(mc, arg1[0] & 31, arg2[1], arg2[2], false);
427                         return true;
428                 }
429         }
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]);
433                         mc = POWER_STXSD;
434                         cgen_dform(mc, arg2[0] & 31, arg1[1], imm);
435                         return true;
436                 }
437                 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
438                         imm = get_imm(&arg1[3]);
439                         if (imm)
440                                 internal(file_line, "cgen_mov: imm is not zero");
441                         mc = POWER_STXSDX;
442                         cgen_xform(mc, arg2[0] & 31, arg1[1], arg1[2], false);
443                         return true;
444                 }
445         }
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);
451                         return true;
452                 }
453                 if (unlikely(arg2[0] == ARG_ADDRESS_2)) {
454                         imm = get_imm(&arg2[3]);
455                         if (imm)
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);
459                         return true;
460                 }
461         }
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);
467                         return true;
468                 }
469                 if (unlikely(arg1[0] == ARG_ADDRESS_2)) {
470                         imm = get_imm(&arg1[3]);
471                         if (imm)
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);
475                         return true;
476                 }
477         }
478         if (reg_is_fp(arg1[0]) && !reg_is_vs(arg1[0]) && reg_is_fp(arg2[0]) && !reg_is_vs(arg2[0])) {
479                 mc = POWER_FMR;
480                 cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
481                 return true;
482         }
483         if (reg_is_vs(arg1[0]) && reg_is_vs(arg2[0])) {
484                 mc = POWER_XXLOR;
485                 cgen_xform(mc, arg1[0] & 31, arg2[0] & 31, arg2[0] & 31, false);
486                 return true;
487         }
489 invl:
490         internal(file_line, "cgen_mov: invalid arguments %u, %02x, %02x", size, arg1[0], arg2[0]);
491         return false;
494 static bool attr_w cgen_cmp(struct codegen_context *ctx, unsigned size, unsigned writes_flags)
496         uint32_t mc;
497         int64_t imm;
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)
506                         mc |= POWER_CMP_L;
507                 cgen_dform(mc, 0, arg1[0], imm);
508                 return true;
509         } else {
510                 mc = writes_flags == 1 ? POWER_CMP : POWER_CMPL;
511                 if (size == OP_SIZE_8)
512                         mc |= POWER_CMP_L;
513                 cgen_xform(mc, 0, arg1[0], arg2[0], false);
514                 return true;
515         }
517         internal(file_line, "cgen_cmp: invalid arguments %u, %02x, %02x, %u", size, *arg1, *arg2, writes_flags);
518         return false;
521 static bool attr_w cgen_test(struct codegen_context *ctx)
523         int64_t imm;
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);
532                         return true;
533                 }
534                 if (imm & 0xffff)
535                         goto invl;
536                 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL)) {
537                         cgen_dform(POWER_ANDIS_, arg1[0], R_CG_SCRATCH, (uint64_t)imm >> 16);
538                         return true;
539                 }
540                 goto invl;
541         } else {
542                 cgen_xform(POWER_AND, arg1[0], R_CG_SCRATCH, arg2[0], 1);
543                 return true;
544         }
546 invl:
547         internal(file_line, "cgen_test: invalid arguments %02x, %02x", *arg1, *arg2);
548         return false;
551 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
553         uint32_t mc;
554         int64_t imm;
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))
561                 goto invl;
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));
572                                 mc |= POWER_OE;
573                         }
574                         cgen_xform(mc, arg1[0], arg2[0], 0, writes_flags);
575                         return true;
576                 }
577                 if (unlikely(writes_flags != (alu == ALU_AND)))
578                         goto invl;
579                 if (alu == ALU_SUB) {
580                         imm = -(uint64_t)imm;
581                         alu = ALU_ADD;
582                 }
583                 if (alu == ALU_MUL && size == OP_SIZE_8)
584                         goto invl;
585                 switch (alu) {
586                         case ALU_ADD:
587                         case ALU_MUL:
588                                 if (likely(imm >= -0x8000) && likely(imm < 0x8000))
589                                         break;
590                                 if (imm & 0xffff)
591                                         goto invl;
592                                 if (likely(imm >= -0x80000000LL) && likely(imm < 0x80000000LL)) {
593                                         shifted = true;
594                                         break;
595                                 }
596                                 goto invl;
597                         case ALU_AND:
598                         case ALU_OR:
599                         case ALU_XOR:
600                                 if (likely(imm >= 0) && likely(imm < 0x10000))
601                                         break;
602                                 if (imm & 0xffff)
603                                         goto invl;
604                                 if (likely(imm >= 0LL) && likely(imm < 0x100000000LL)) {
605                                         shifted = true;
606                                         break;
607                                 }
608                                 goto invl;
609                         default:
610                                 goto invl;
611                 }
612                 if (unlikely(alu * 2 + (unsigned)shifted >= n_array_elements(alu_imm)))
613                         goto invl;
614                 mc = alu_imm[alu * 2 + (unsigned)shifted];
615                 if (unlikely(!mc))
616                         goto invl;
617                 if (shifted)
618                         imm = (uint64_t)imm >> 16;
619                 if (alu == ALU_ADD || alu == ALU_MUL)
620                         cgen_dform(mc, arg1[0], arg2[0], imm);
621                 else
622                         cgen_dform(mc, arg2[0], arg1[0], imm);
623                 return true;
624         }
625         if (arg3[0] < 32) {
626                 int flag;
627                 if (unlikely(alu * 3 + 2 >= n_array_elements(alu_reg)))
628                         goto invl;
629                 mc = alu_reg[alu * 3 + (size == OP_SIZE_8)];
630                 flag = alu_reg[alu * 3 + 2];
631                 if (unlikely(!mc))
632                         goto invl;
633                 if (writes_flags & 2) {
634                         switch (alu) {
635                                 case ALU_ADD:   mc = POWER_ADDC; break;
636                                 case ALU_SUB:   mc = POWER_SUBFC; break;
637                                 case ALU_ADC:
638                                 case ALU_SBB:   break;
639                                 default:        goto invl;
640                         }
641                 }
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));
647                         } else {
648                                 cgen_four(POWER_MTXER | ((uint32_t)R_ZERO << 21));
649                         }
650                         mc |= POWER_OE;
651                 }
652                 if (flag & 2) {
653                         uint8_t *t = arg2;
654                         arg2 = arg3;
655                         arg3 = t;
656                 }
657                 if (flag & 1)
658                         cgen_xform(mc, arg1[0], arg2[0], arg3[0], writes_flags);
659                 else
660                         cgen_xform(mc, arg2[0], arg1[0], arg3[0], writes_flags);
661                 return true;
662         }
664 invl:
665         internal(file_line, "cgen_alu: invalid arguments %u, %u, %02x, %02x, %02x, %u", size, alu, *arg1, *arg2, *arg3, writes_flags);
666         return false;
669 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
671         uint32_t mc;
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))
677                 goto invl;
679         switch (alu) {
680                 case ALU1_NOT:
681                         cgen_xform(POWER_NOR, arg2[0], arg1[0], arg2[0], writes_flags);
682                         return true;
683                 case ALU1_NEG:
684                         if (writes_flags & 2)
685                                 cgen_dform(POWER_SUBFIC, arg1[0], arg2[0], 0);
686                         else
687                                 cgen_xform(POWER_NEG, arg1[0], arg2[0], 0, writes_flags);
688                         return true;
689                 case ALU1_NGC:
690                         mc = POWER_SUBFZE;
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));
695                                 mc |= POWER_OE;
696                         }
697                         cgen_xform(mc, arg1[0], arg2[0], 0, writes_flags);
698                         return true;
699                 case ALU1_INC:
700                         if (unlikely(writes_flags & 2))
701                                 cgen_dform(POWER_ADDIC, arg1[0], arg2[0], 1);
702                         else
703                                 cgen_dform(POWER_ADDI, arg1[0], arg2[0], 1);
704                         return true;
705                 case ALU1_DEC:
706                         if (unlikely(writes_flags & 2))
707                                 cgen_dform(POWER_ADDIC, arg1[0], arg2[0], -1);
708                         else
709                                 cgen_dform(POWER_ADDI, arg1[0], arg2[0], -1);
710                         return true;
711                 case ALU1_BSF:
712                         cgen_xform(size == OP_SIZE_4 ? POWER_CNTTZW : POWER_CNTTZD, arg2[0], arg1[0], 0, writes_flags);
713                         return true;
714                 case ALU1_LZCNT:
715                         cgen_xform(size == OP_SIZE_4 ? POWER_CNTLZW : POWER_CNTLZD, arg2[0], arg1[0], 0, writes_flags);
716                         return true;
717                 case ALU1_POPCNT:
718                         if (unlikely(writes_flags))
719                                 goto invl;
720                         cgen_xform(size == OP_SIZE_4 ? POWER_POPCNTW : POWER_POPCNTD, arg2[0], arg1[0], 0, 0);
721                         return true;
722                 default:
723                         goto invl;
724         }
726 invl:
727         internal(file_line, "cgen_alu1: invalid arguments %u, %u, %02x, %02x, %u", size, alu, *arg1, *arg2, writes_flags);
728         return false;
731 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
733         uint32_t mc;
734         int64_t imm;
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))
741                 goto invl;
743         if (arg3[0] < 32) {
744                 switch (alu) {
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;
749                         default: goto invl;
750                 }
751                 cgen_xform(mc, arg2[0], arg1[0], arg3[0], writes_flags);
752                 return true;
753         } else if (arg3[0] == ARG_IMM) {
754                 uint32_t i32;
755                 imm = get_imm(&arg3[1]);
756                 i32 = (uint32_t)imm;
757                 if (size == OP_SIZE_4) {
758                         switch (alu) {
759                                 case ROT_SHL:
760                                         mc = POWER_RLWINM | (i32 << 11) | ((31 - i32) << 1);
761                                         break;
762                                 case ROT_SHR:
763                                         mc = POWER_RLWINM | ((-i32 << 11) & 0xf800U) | (i32 << 6) | 0x3eU;
764                                         break;
765                                 case ROT_SAR:
766                                         mc = POWER_SRAWI | (i32 << 11);
767                                         break;
768                                 default:
769                                         goto invl;
770                         }
771                 } else {
772                         switch (alu) {
773                                 case ROT_SHL:
774                                         mc = POWER_RLDICR;
775                                         mc |= (i32 << 11) & 0xf800U;
776                                         mc |= (i32 >> 4) & 0x2U;
777                                         mc |= ((63 - i32) << 6) & 0x07c0U;
778                                         mc |= (63 - i32) & 0x0020U;
779                                         break;
780                                 case ROT_SHR:
781                                         mc = POWER_RLDICL;
782                                         mc |= (-i32 << 11) & 0xf800U;
783                                         mc |= (-i32 >> 4) & 0x2U;
784                                         mc |= (i32 << 6) & 0x07c0U;
785                                         mc |= i32 & 0x0020U;
786                                         break;
787                                 case ROT_SAR:
788                                         mc = POWER_SRADI;
789                                         mc |= (i32 << 11) & 0xf800U;
790                                         mc |= (i32 >> 4) & 0x2U;
791                                         break;
792                                 default:
793                                         goto invl;
794                         }
795                 }
796                 cgen_xform(mc, arg2[0], arg1[0], 0, writes_flags);
797                 return true;
798         }
800 invl:
801         internal(file_line, "cgen_rot: invalid arguments %u, %u, %02x, %02x, %02x", size, alu, *arg1, *arg2, *arg3);
802         return false;
805 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned aux)
807         bool swap;
808         uint32_t mc;
809         int64_t imm;
810         uint8_t z = R_ZERO;
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))
819                         goto invl;
820                 arg2 = &z;
821         }
822         if (arg3[0] == ARG_IMM) {
823                 imm = get_imm(&arg3[1]);
824                 if (unlikely(imm != 0))
825                         goto invl;
826                 arg3 = &z;
827         }
829         switch (aux) {
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;
834         }
836         switch (aux) {
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;
853                 default:        goto invl;
854         }
856         if (swap) {
857                 uint8_t *t = arg2;
858                 arg2 = arg3;
859                 arg3 = t;
860         }
862         cgen_xform(mc, arg1[0], arg3[0], arg2[0], false);
863         return true;
865 invl:
866         internal(file_line, "cgen_cmov: invalid arguments %u, %02x, %02x, %02x", aux, *arg1, *arg2, *arg3);
867         return false;
870 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned attr_unused op_size)
872         uint32_t mc;
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);
878         return true;
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;
885         uint32_t mc;
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);
890         switch (aux) {
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;
895                 default:                goto invl;
896         }
897         if (aux == FP_ALU_MUL && !use_vs)
898                 cgen_xform(mc | ((arg3[0] & 31) << 6), arg1[0] & 31, arg2[0] & 31, 0, false);
899         else
900                 cgen_xform(mc, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31, false);
901         return true;
902 invl:
903         internal(file_line, "cgen_fp_alu: invalid arguments %u, %u, %02x, %02x, %02x", op_size, aux, *arg1, *arg2, *arg3);
904         return false;
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;
911         uint32_t mc;
912         uint8_t *arg1 = ctx->code_position;
913         uint8_t *arg2 = arg1 + arg_size(*arg1);
914         ctx->code_position = arg2 + arg_size(*arg2);
915         switch (aux) {
916                 case FP_ALU1_NEG:       mc = use_vs ? POWER_XSNEGQP : POWER_FNEG;
917                                         break;
918                 case FP_ALU1_SQRT:      if (unlikely(use_vs))
919                                                 goto invl;
920                                         mc = use_s ? POWER_FSQRTS : POWER_FSQRT; break;
921                 default:                goto invl;
922         }
923         cgen_xform(mc, arg1[0] & 31, 0, arg2[0] & 31, false);
924         return true;
925 invl:
926         internal(file_line, "cgen_fp_alu1: invalid arguments %u, %u, %02x, %02x", op_size, aux, *arg1, *arg2);
927         return false;
930 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned fp_op_size)
932         uint32_t mc;
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);
938         return true;
941 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
943         uint32_t mc;
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);
949         return true;
952 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, bool lng, unsigned aux, bool logical)
954         uint32_t mc;
955         if (!lng) {
956                 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
957         } else {
958                 aux ^= 1;
959         }
960         if (!logical) {
961                 if (unlikely(aux >= n_array_elements(jmp_cond)))
962                         goto invl;
963                 mc = jmp_cond[aux];
964         } else {
965                 if (unlikely(aux >= n_array_elements(jmp_cond_logical)))
966                         goto invl;
967                 mc = jmp_cond_logical[aux];
968         }
969         if (unlikely(!mc))
970                 goto invl;
972         if (!lng) {
973                 cgen_four(mc);
974         } else {
975                 cgen_four(mc | 0x8);
976                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
977                 cgen_four(POWER_B);
978         }
980         return true;
982 invl:
983         internal(file_line, "cgen_jmp_cond: invalid %scondition %x", logical ? "logical " : "", aux);
984         return false;
987 static bool attr_w cgen_jmp_indirect(struct codegen_context *ctx)
989         uint32_t mc;
990         unsigned reg = cget_one(ctx);
992         mc = POWER_MTCTR;
993         mc |= (uint32_t)reg << 21;
994         cgen_four(mc);
996         mc = POWER_BCTR;
997         cgen_four(mc);
999         return true;
1002 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1004         uint32_t mc;
1005         int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)reloc->position;
1006         switch (reloc->length) {
1007                 case JMP_SHORTEST:
1008                         if (unlikely(offs < -0x8000) || unlikely(offs >= 0x8000))
1009                                 return false;
1010                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1011                         mc &= 0xffff0003U;
1012                         mc |= offs & 0xfffcU;
1013                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1014                         return true;
1015                 case JMP_SHORT:
1016                         if (unlikely(offs < -0x01000000) || unlikely(offs >= 0x01000000))
1017                                 return false;
1018                         memcpy(&mc, ctx->mcode + reloc->position, 4);
1019                         mc &= 0xfc000003U;
1020                         mc |= offs & 0x3fffffcU;
1021                         memcpy(ctx->mcode + reloc->position, &mc, 4);
1022                         return true;
1023                 default:
1024                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1025         }
1026         return false;
1029 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1031         uint32_t reg;
1032         switch (insn_opcode(insn)) {
1033                 case INSN_ENTRY:
1034                         g(cgen_entry(ctx));
1035                         return true;
1036                 case INSN_LABEL:
1037                         g(cgen_label(ctx));
1038                         return true;
1039                 case INSN_RET:
1040                         cgen_four(POWER_BLR);
1041                         return true;
1042                 case INSN_CALL_INDIRECT:
1043                         reg = cget_one(ctx);
1044                         if (unlikely(reg != R_CTR))
1045                                 goto invalid_insn;
1046                         cgen_four(POWER_BCTRL);
1047                         return true;
1048                 case INSN_MOV:
1049                         g(cgen_mov(ctx, insn_op_size(insn), false));
1050                         return true;
1051                 case INSN_MOVSX:
1052                         g(cgen_mov(ctx, insn_op_size(insn), true));
1053                         return true;
1054                 case INSN_CMP:
1055                         g(cgen_cmp(ctx, insn_op_size(insn), insn_writes_flags(insn)));
1056                         return true;
1057                 case INSN_TEST:
1058                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1059                                 goto invalid_insn;
1060                         g(cgen_test(ctx));
1061                         return true;
1062                 case INSN_ALU:
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))
1065                                 goto invalid_insn;
1066                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1067                         return true;
1068                 case INSN_ALU1:
1069                 case INSN_ALU1_FLAGS:
1070                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1071                                 goto invalid_insn;
1072                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1073                         return true;
1074                 case INSN_ROT:
1075                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1076                         return true;
1077                 case INSN_CMOV:
1078                 case INSN_CMOV_XCC:
1079                         if (unlikely(!cpu_test_feature(CPU_FEATURE_v203)))
1080                                 goto invalid_insn;
1081                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
1082                                 goto invalid_insn;
1083                         g(cgen_cmov(ctx, insn_aux(insn)));
1084                         return true;
1085                 case INSN_FP_CMP:
1086                         g(cgen_fp_cmp(ctx, insn_op_size(insn)));
1087                         return true;
1088                 case INSN_FP_ALU:
1089                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1090                         return true;
1091                 case INSN_FP_ALU1:
1092                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1093                         return true;
1094                 case INSN_FP_TO_INT64:
1095                         g(cgen_fp_to_int(ctx, insn_op_size(insn)));
1096                         return true;
1097                 case INSN_FP_FROM_INT64:
1098                         g(cgen_fp_from_int(ctx, insn_op_size(insn)));
1099                         return true;
1100                 case INSN_JMP:
1101                         g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1102                         cgen_four(POWER_B);
1103                         return true;
1104                 case INSN_JMP_COND:
1105                         g(cgen_jmp_cond(ctx, insn_jump_size(insn) == JMP_SHORT, insn_aux(insn), false));
1106                         return true;
1107                 case INSN_JMP_COND_LOGICAL:
1108                         g(cgen_jmp_cond(ctx, insn_jump_size(insn) == JMP_SHORT, insn_aux(insn), true));
1109                         return true;
1110                 case INSN_JMP_INDIRECT:
1111                         g(cgen_jmp_indirect(ctx));
1112                         return true;
1113                 invalid_insn:
1114                 default:
1115                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
1116                         return false;
1117         }