codegen: a small improvement in do_bswap and do_brev
[ajla.git] / c1-power.inc
blob6bec91b11a578b80e16137d86dc067dda3ffa5c3
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 #ifdef _CALL_AIXDESC
20 #define AIX_CALL
21 #endif
23 #if !defined(ARCH_POWER64)
25 #define OP_SIZE_NATIVE                  OP_SIZE_4
26 #define OP_SIZE_ADDRESS                 OP_SIZE_4
27 #ifdef AIX_CALL
28 #define FRAME_SIZE                      128
29 #define REGS_OFFSET                     56
30 #define LR_OFFSET                       (FRAME_SIZE + 8)
31 #else
32 #define FRAME_SIZE                      80
33 #define REGS_OFFSET                     8
34 #define LR_OFFSET                       (FRAME_SIZE + 4)
35 #endif
37 #else
39 #define OP_SIZE_NATIVE                  OP_SIZE_8
40 #define OP_SIZE_ADDRESS                 OP_SIZE_8
41 #ifdef AIX_CALL
42 #define FRAME_SIZE                      256
43 #define REGS_OFFSET                     112
44 #define LR_OFFSET                       (FRAME_SIZE + 16)
45 #define STRUCT_RET_OFFSET               304
46 #else
47 #define FRAME_SIZE                      176
48 #define REGS_OFFSET                     32
49 #define LR_OFFSET                       (FRAME_SIZE + 16)
50 #endif
52 #endif
54 #define JMP_LIMIT                       JMP_SHORT
56 #define UNALIGNED_TRAP                  0
58 #define ALU_WRITES_FLAGS(alu, im)       (!(im) ?                        \
59                                                 ((alu) == ALU_SUB && !cpu_test_feature(CPU_FEATURE_ppc) ? 2 : (alu) == ALU_ADC || (alu) == ALU_SBB ? 2 : 0) :\
60                                                 ((alu) == ALU_AND ? 1 : 0)\
61                                         )
62 #define ALU1_WRITES_FLAGS(alu)          0
63 #define ROT_WRITES_FLAGS(alu, size, im) 0
64 #define COND_IS_LOGICAL(cond)           ((cond) == COND_B || (cond) == COND_AE || (cond) == COND_BE || (cond) == COND_A)
66 #define ARCH_PARTIAL_ALU(size)          0
67 #define ARCH_IS_3ADDRESS(alu, f)        1
68 #define ARCH_IS_3ADDRESS_IMM(alu, f)    1
69 #define ARCH_IS_3ADDRESS_ROT(alu, size) 1
70 #define ARCH_IS_3ADDRESS_ROT_IMM(alu)   1
71 #define ARCH_IS_2ADDRESS(alu)           1
72 #define ARCH_IS_3ADDRESS_FP             1
73 #define ARCH_HAS_FLAGS                  1
74 #define ARCH_PREFERS_SX(size)           0
75 #define ARCH_HAS_BWX                    1
76 #define ARCH_HAS_MUL                    1
77 #define ARCH_HAS_DIV                    cpu_test_feature(CPU_FEATURE_ppc)
78 #define ARCH_HAS_ANDN                   1
79 #define ARCH_HAS_SHIFTED_ADD(bits)      0
80 #define ARCH_HAS_BTX(btx, size, cnst)   0
81 #define ARCH_SHIFT_SIZE                 OP_SIZE_16
82 #define ARCH_NEEDS_BARRIER              0
84 #define i_size(size)                    OP_SIZE_NATIVE
85 #define i_size_rot(size)                maximum(size, OP_SIZE_4)
86 #define i_size_cmp(size)                maximum(size, OP_SIZE_4)
88 #define R_0                             0x00
89 #define R_1                             0x01
90 #define R_2                             0x02
91 #define R_3                             0x03
92 #define R_4                             0x04
93 #define R_5                             0x05
94 #define R_6                             0x06
95 #define R_7                             0x07
96 #define R_8                             0x08
97 #define R_9                             0x09
98 #define R_10                            0x0a
99 #define R_11                            0x0b
100 #define R_12                            0x0c
101 #define R_13                            0x0d
102 #define R_14                            0x0e
103 #define R_15                            0x0f
104 #define R_16                            0x10
105 #define R_17                            0x11
106 #define R_18                            0x12
107 #define R_19                            0x13
108 #define R_20                            0x14
109 #define R_21                            0x15
110 #define R_22                            0x16
111 #define R_23                            0x17
112 #define R_24                            0x18
113 #define R_25                            0x19
114 #define R_26                            0x1a
115 #define R_27                            0x1b
116 #define R_28                            0x1c
117 #define R_29                            0x1d
118 #define R_30                            0x1e
119 #define R_31                            0x1f
121 #define R_LR                            0x20
122 #define R_CTR                           0x21
124 #define R_F0                            0x40
125 #define R_F1                            0x41
126 #define R_F2                            0x42
127 #define R_F3                            0x43
128 #define R_F4                            0x44
129 #define R_F5                            0x45
130 #define R_F6                            0x46
131 #define R_F7                            0x47
132 #define R_F8                            0x48
133 #define R_F9                            0x49
134 #define R_F10                           0x4a
135 #define R_F11                           0x4b
136 #define R_F12                           0x4c
137 #define R_F13                           0x4d
138 #define R_F14                           0x4e
139 #define R_F15                           0x4f
140 #define R_F16                           0x50
141 #define R_F17                           0x51
142 #define R_F18                           0x52
143 #define R_F19                           0x53
144 #define R_F20                           0x54
145 #define R_F21                           0x55
146 #define R_F22                           0x56
147 #define R_F23                           0x57
148 #define R_F24                           0x58
149 #define R_F25                           0x59
150 #define R_F26                           0x5a
151 #define R_F27                           0x5b
152 #define R_F28                           0x5c
153 #define R_F29                           0x5d
154 #define R_F30                           0x5e
155 #define R_F31                           0x5f
156 #define R_VS32                          0x60
157 #define R_VS33                          0x61
158 #define R_VS34                          0x62
159 #define R_VS35                          0x63
160 #define R_VS36                          0x64
161 #define R_VS37                          0x65
162 #define R_VS38                          0x66
163 #define R_VS39                          0x67
164 #define R_VS40                          0x68
165 #define R_VS41                          0x69
166 #define R_VS42                          0x6a
167 #define R_VS43                          0x6b
168 #define R_VS44                          0x6c
169 #define R_VS45                          0x6d
170 #define R_VS46                          0x6e
171 #define R_VS47                          0x6f
172 #define R_VS48                          0x70
173 #define R_VS49                          0x71
174 #define R_VS50                          0x72
175 #define R_VS51                          0x73
176 #define R_VS52                          0x74
177 #define R_VS53                          0x75
178 #define R_VS54                          0x76
179 #define R_VS55                          0x77
180 #define R_VS56                          0x78
181 #define R_VS57                          0x79
182 #define R_VS58                          0x7a
183 #define R_VS59                          0x7b
184 #define R_VS60                          0x7c
185 #define R_VS61                          0x7d
186 #define R_VS62                          0x7e
187 #define R_VS63                          0x7f
189 #define R_CG_SCRATCH                    R_0
191 #define R_SP                            R_1
193 #define R_SCRATCH_1                     R_3
194 #define R_SCRATCH_2                     R_4
195 #define R_SCRATCH_3                     R_5
196 #define R_SCRATCH_4                     R_SAVED_2
198 #define R_SCRATCH_NA_1                  R_7
199 #define R_SCRATCH_NA_2                  R_8
200 #define R_SCRATCH_NA_3                  R_9
202 #define R_FRAME                         R_31
203 #define R_UPCALL                        R_30
204 #define R_TIMESTAMP                     R_29
206 #define R_SAVED_1                       R_28
207 #define R_SAVED_2                       R_27
208 #define R_ZERO                          R_26
210 #define R_LOWEST_SAVED                  R_14
212 #define R_ARG0                          R_3
213 #define R_ARG1                          R_4
214 #define R_ARG2                          R_5
215 #define R_ARG3                          R_6
216 #define R_ARG4                          R_7
217 #define R_RET0                          R_3
218 #define R_RET1                          R_4
220 #define R_OFFSET_IMM                    R_10
221 #define R_CONST_IMM                     R_11
223 #define FR_SCRATCH_1                    (real_type == 4 ? R_VS32 : R_F0)
224 #define FR_SCRATCH_2                    (real_type == 4 ? R_VS33 : R_F1)
225 #define FR_SCRATCH_3                    (real_type == 4 ? R_VS34 : R_F2)
227 #define SUPPORTED_FP                    (cpu_test_feature(CPU_FEATURE_ppc) * 0x2 + 0x4 + cpu_test_feature(CPU_FEATURE_v30) * 0x10)
229 static bool reg_is_fp(unsigned reg)
231         return reg >= 0x40 && reg < 0x80;
234 static bool reg_is_vs(unsigned reg)
236         return reg >= 0x60 && reg < 0x80;
239 static const uint8_t regs_saved[] = { R_14, R_15, R_16, R_17, R_18, R_19, R_20, R_21, R_22, R_23, R_24, R_25 };
240 static const uint8_t regs_volatile[] = { R_6, R_12 };
241 static const uint8_t fp_saved[] = { 0 };
242 #define n_fp_saved 0U
243 static const uint8_t fp_volatile[] = { R_F3, R_F4, R_F5, R_F6, R_F7, R_F8, R_F9, R_F10, R_F11, R_F12, R_F13 };
244 static const uint8_t vector_volatile[] = { R_VS35, R_VS36, R_VS37, R_VS38, R_VS39, R_VS40, R_VS41, R_VS42, R_VS43, R_VS44, R_VS45, R_VS46, R_VS47, R_VS48, R_VS49, R_VS50, R_VS51 };
245 #define reg_is_saved(r) (((r) >= R_14 && (r) <= R_31) || ((r) >= R_F14 && (r) <= R_F31) || ((r) >= R_VS52 && (r) <= R_VS63))
247 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
249         unsigned xreg = R_ZERO;
250         if (OP_SIZE_NATIVE == OP_SIZE_4)
251                 c = (int32_t)c;
252         if (c == (uint64_t)(int32_t)c) {
253                 if (c == (uint64_t)(int16_t)c) {
254                         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
255                         gen_one(reg);
256                         gen_one(ARG_IMM);
257                         gen_eight((int16_t)c);
258                         return true;
259                 }
260                 if (c & 0xffffffffffff0000ULL) {
261                         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
262                         gen_one(reg);
263                         gen_one(ARG_IMM);
264                         gen_eight(c & 0xffffffffffff0000ULL);
265                         xreg = reg;
266                 }
267         } else {
268                 if (c >> 48) {
269                         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
270                         gen_one(reg);
271                         gen_one(ARG_IMM);
272                         gen_eight((int32_t)((c >> 32) & 0xffff0000U));
273                         xreg = reg;
274                 }
275                 if (c & 0x0000ffff00000000ULL) {
276                         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
277                         gen_one(reg);
278                         gen_one(xreg);
279                         gen_one(ARG_IMM);
280                         gen_eight((uint16_t)(c >> 32));
281                         xreg = reg;
282                 }
283                 if (xreg != R_ZERO) {
284                         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
285                         gen_one(reg);
286                         gen_one(reg);
287                         gen_one(ARG_IMM);
288                         gen_eight(32);
289                 }
290                 if (c & 0xffff0000U) {
291                         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
292                         gen_one(reg);
293                         gen_one(xreg);
294                         gen_one(ARG_IMM);
295                         gen_eight(c & 0xffff0000U);
296                         xreg = reg;
297                 }
298         }
299         if (c & 0xffffU) {
300                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
301                 gen_one(reg);
302                 gen_one(xreg);
303                 gen_one(ARG_IMM);
304                 gen_eight(c & 0xffffU);
305                 xreg = reg;
306         }
307         if (xreg == R_ZERO) {
308                 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
309                 gen_one(reg);
310                 gen_one(ARG_IMM);
311                 gen_eight(0);
312         }
313         return true;
316 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned size)
318         ctx->base_reg = base;
319         ctx->offset_imm = imm;
320         ctx->offset_reg = false;
321         switch (purpose) {
322                 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
323                         if (size >= OP_SIZE_16 && imm & 15)
324                                 break;
325                         /*-fallthrough*/
326                 case IMM_PURPOSE_LDR_SX_OFFSET:
327                         if (size >= OP_SIZE_4 && imm & 3)
328                                 break;
329                         /*-fallthrough*/
330                 case IMM_PURPOSE_LDR_OFFSET:
331                 case IMM_PURPOSE_STR_OFFSET:
332                         if (size >= OP_SIZE_8 && imm & 3)
333                                 break;
334                         /*-fallthrough*/
335                 case IMM_PURPOSE_MVI_CLI_OFFSET:
336                         if (likely(imm >= -0x8000) && likely(imm < 0x8000))
337                                 return true;
338                         break;
339                 default:
340                         internal(file_line, "gen_address: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
341         }
342         g(gen_load_constant(ctx, R_OFFSET_IMM, imm));
343         ctx->offset_reg = true;
344         return true;
347 static bool is_direct_const(int64_t imm, unsigned purpose, unsigned size)
349         switch (purpose) {
350                 case IMM_PURPOSE_STORE_VALUE:
351                 case IMM_PURPOSE_CMOV:
352                         if (!imm)
353                                 return true;
354                         break;
355                 case IMM_PURPOSE_ANDN:
356                         break;
357                 case IMM_PURPOSE_ADD:
358                 case IMM_PURPOSE_CMP:
359                         if (likely(imm >= -0x8000) && likely(imm < 0x8000))
360                                 return true;
361                         if (imm & 0xffff)
362                                 break;
363                         if (likely(imm >= -0x80000000L) && likely(imm < 0x80000000L))
364                                 return true;
365                         break;
366                 case IMM_PURPOSE_SUB:
367                         if (likely(imm > -0x8000) && likely(imm <= 0x8000))
368                                 return true;
369                         if (imm & 0xffff)
370                                 break;
371                         if (likely(imm > -0x80000000L) && likely(imm <= 0x80000000L))
372                                 return true;
373                         break;
374                 case IMM_PURPOSE_CMP_LOGICAL:
375                 case IMM_PURPOSE_AND:
376                 case IMM_PURPOSE_OR:
377                 case IMM_PURPOSE_XOR:
378                 case IMM_PURPOSE_TEST:
379                         if (likely(imm >= 0) && likely(imm < 0x10000))
380                                 return true;
381                         if (imm & 0xffff)
382                                 break;
383                         if (likely(imm >= 0LL) && likely(imm < 0x100000000LL))
384                                 return true;
385                         break;
386                 case IMM_PURPOSE_MUL:
387                         if (size != OP_SIZE_4)
388                                 break;
389                         if (likely(imm >= -0x8000) && likely(imm < 0x8000))
390                                 return true;
391                         break;
392                 default:
393                         internal(file_line, "is_direct_const: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
394         }
395         return false;
398 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
400         if (is_direct_const(imm, purpose, size)) {
401                 ctx->const_imm = imm;
402                 ctx->const_reg = false;
403         } else {
404                 g(gen_load_constant(ctx, R_CONST_IMM, imm));
405                 ctx->const_reg = true;
406         }
407         return true;
410 static bool attr_w gen_entry(struct codegen_context *ctx)
412         int i, offs;
414         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
415         gen_one(ARG_ADDRESS_1_PRE_I);
416         gen_one(R_SP);
417         gen_eight(-FRAME_SIZE);
418         gen_one(R_SP);
420         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
421         gen_one(R_SCRATCH_NA_3);
422         gen_one(R_LR);
424         for (i = R_LOWEST_SAVED, offs = REGS_OFFSET; i <= R_31; i++, offs += 1 << OP_SIZE_ADDRESS) {
425                 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
426                 gen_one(ARG_ADDRESS_1);
427                 gen_one(R_SP);
428                 gen_eight(offs);
429                 gen_one(i);
430         }
432         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
433         gen_one(ARG_ADDRESS_1);
434         gen_one(R_SP);
435         gen_eight(LR_OFFSET);
436         gen_one(R_SCRATCH_NA_3);
438         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
439         gen_one(R_ZERO);
440         gen_one(ARG_IMM);
441         gen_eight(0);
443 #if !defined(STRUCT_RET_OFFSET)
444         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
445         gen_one(R_FRAME);
446         gen_one(R_ARG0);
448         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
449         gen_one(R_UPCALL);
450         gen_one(R_ARG1);
452         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
453         gen_one(R_TIMESTAMP);
454         gen_one(R_ARG2);
456         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
457         gen_one(R_ARG3);
458 #else
459         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
460         gen_one(ARG_ADDRESS_1);
461         gen_one(R_SP);
462         gen_eight(STRUCT_RET_OFFSET);
463         gen_one(R_ARG0);
465         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
466         gen_one(R_FRAME);
467         gen_one(R_ARG1);
469         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
470         gen_one(R_UPCALL);
471         gen_one(R_ARG2);
473         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
474         gen_one(R_TIMESTAMP);
475         gen_one(R_ARG3);
477         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
478         gen_one(R_ARG4);
479 #endif
481         return true;
484 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
486         g(gen_load_constant(ctx, R_RET1, ip));
488         gen_insn(INSN_JMP, 0, 0, 0);
489         gen_four(escape_label);
491         return true;
494 static bool attr_w gen_escape(struct codegen_context *ctx)
496         int i, offs;
498 #if !defined(STRUCT_RET_OFFSET)
499         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
500         gen_one(R_RET0);
501         gen_one(R_FRAME);
502 #else
503         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
504         gen_one(R_RET0);
505         gen_one(ARG_ADDRESS_1);
506         gen_one(R_SP);
507         gen_eight(STRUCT_RET_OFFSET);
509         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
510         gen_one(ARG_ADDRESS_1);
511         gen_one(R_RET0);
512         gen_eight(0);
513         gen_one(R_FRAME);
515         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
516         gen_one(ARG_ADDRESS_1);
517         gen_one(R_RET0);
518         gen_eight(1U << OP_SIZE_NATIVE);
519         gen_one(R_RET1);
520 #endif
521         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
522         gen_one(R_SCRATCH_NA_1);
523         gen_one(ARG_ADDRESS_1);
524         gen_one(R_SP);
525         gen_eight(LR_OFFSET);
527         for (i = R_LOWEST_SAVED, offs = REGS_OFFSET; i <= R_31; i++, offs += 1 << OP_SIZE_ADDRESS) {
528                 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
529                 gen_one(i);
530                 gen_one(ARG_ADDRESS_1);
531                 gen_one(R_SP);
532                 gen_eight(offs);
533         }
535         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
536         gen_one(R_LR);
537         gen_one(R_SCRATCH_NA_1);
539         gen_insn(INSN_ALU, OP_SIZE_NATIVE, 0, 0);
540         gen_one(R_SP);
541         gen_one(R_SP);
542         gen_one(ARG_IMM);
543         gen_eight(FRAME_SIZE);
545         gen_insn(INSN_RET, 0, 0, 0);
547         return true;
550 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
552         return true;
555 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
557 #ifndef AIX_CALL
558         g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
559         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
560         gen_one(R_12);
561         gen_address_offset();
563         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
564         gen_one(R_CTR);
565         gen_one(R_12);
567         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_NATIVE, 0, 0);
568         gen_one(R_CTR);
569 #else
570         g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
571         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
572         gen_one(R_SCRATCH_NA_2);
573         gen_address_offset();
575         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
576         gen_one(R_SCRATCH_NA_1);
577         gen_one(ARG_ADDRESS_1);
578         gen_one(R_SCRATCH_NA_2);
579         gen_eight(0);
581         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
582         gen_one(R_CTR);
583         gen_one(R_SCRATCH_NA_1);
585         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
586         gen_one(R_2);
587         gen_one(ARG_ADDRESS_1);
588         gen_one(R_SCRATCH_NA_2);
589         gen_eight(1 << OP_SIZE_ADDRESS);
591         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
592         gen_one(R_11);
593         gen_one(ARG_ADDRESS_1);
594         gen_one(R_SCRATCH_NA_2);
595         gen_eight(2 << OP_SIZE_ADDRESS);
597         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_NATIVE, 0, 0);
598         gen_one(R_CTR);
599 #endif
600         g(gen_upcall_end(ctx, n_args));
602         return true;
605 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
607         g(gen_address(ctx, R_UPCALL, offsetof(struct cg_upcall_vector_s, ts), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_4));
608         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
609         gen_one(R_SCRATCH_1);
610         gen_address_offset();
612         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
613         gen_one(R_SCRATCH_1);
614         gen_one(R_TIMESTAMP);
616         gen_insn(INSN_JMP_COND, OP_SIZE_4, COND_NE, 0);
617         gen_four(escape_label);
619         return true;