codegen: keep the registers holding boolean values extended, so that we
[ajla.git] / c1-power.inc
blob526d0949150de9353eee1d5ee9edafc562a71c69
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_JMP_2REGS(cond)        0
74 #define ARCH_HAS_FLAGS                  1
75 #define ARCH_PREFERS_SX(size)           0
76 #define ARCH_HAS_BWX                    1
77 #define ARCH_HAS_MUL                    1
78 #define ARCH_HAS_DIV                    cpu_test_feature(CPU_FEATURE_ppc)
79 #define ARCH_HAS_ANDN                   1
80 #define ARCH_HAS_SHIFTED_ADD(bits)      0
81 #define ARCH_HAS_BTX(btx, size, cnst)   0
82 #define ARCH_SHIFT_SIZE                 OP_SIZE_16
83 #define ARCH_BOOL_SIZE                  OP_SIZE_NATIVE
84 #define ARCH_HAS_FP_GP_MOV              0
85 #define ARCH_NEEDS_BARRIER              0
87 #define i_size(size)                    OP_SIZE_NATIVE
88 #define i_size_rot(size)                maximum(size, OP_SIZE_4)
89 #define i_size_cmp(size)                maximum(size, OP_SIZE_4)
91 #define R_0                             0x00
92 #define R_1                             0x01
93 #define R_2                             0x02
94 #define R_3                             0x03
95 #define R_4                             0x04
96 #define R_5                             0x05
97 #define R_6                             0x06
98 #define R_7                             0x07
99 #define R_8                             0x08
100 #define R_9                             0x09
101 #define R_10                            0x0a
102 #define R_11                            0x0b
103 #define R_12                            0x0c
104 #define R_13                            0x0d
105 #define R_14                            0x0e
106 #define R_15                            0x0f
107 #define R_16                            0x10
108 #define R_17                            0x11
109 #define R_18                            0x12
110 #define R_19                            0x13
111 #define R_20                            0x14
112 #define R_21                            0x15
113 #define R_22                            0x16
114 #define R_23                            0x17
115 #define R_24                            0x18
116 #define R_25                            0x19
117 #define R_26                            0x1a
118 #define R_27                            0x1b
119 #define R_28                            0x1c
120 #define R_29                            0x1d
121 #define R_30                            0x1e
122 #define R_31                            0x1f
124 #define R_LR                            0x20
125 #define R_CTR                           0x21
127 #define R_F0                            0x40
128 #define R_F1                            0x41
129 #define R_F2                            0x42
130 #define R_F3                            0x43
131 #define R_F4                            0x44
132 #define R_F5                            0x45
133 #define R_F6                            0x46
134 #define R_F7                            0x47
135 #define R_F8                            0x48
136 #define R_F9                            0x49
137 #define R_F10                           0x4a
138 #define R_F11                           0x4b
139 #define R_F12                           0x4c
140 #define R_F13                           0x4d
141 #define R_F14                           0x4e
142 #define R_F15                           0x4f
143 #define R_F16                           0x50
144 #define R_F17                           0x51
145 #define R_F18                           0x52
146 #define R_F19                           0x53
147 #define R_F20                           0x54
148 #define R_F21                           0x55
149 #define R_F22                           0x56
150 #define R_F23                           0x57
151 #define R_F24                           0x58
152 #define R_F25                           0x59
153 #define R_F26                           0x5a
154 #define R_F27                           0x5b
155 #define R_F28                           0x5c
156 #define R_F29                           0x5d
157 #define R_F30                           0x5e
158 #define R_F31                           0x5f
159 #define R_VS32                          0x60
160 #define R_VS33                          0x61
161 #define R_VS34                          0x62
162 #define R_VS35                          0x63
163 #define R_VS36                          0x64
164 #define R_VS37                          0x65
165 #define R_VS38                          0x66
166 #define R_VS39                          0x67
167 #define R_VS40                          0x68
168 #define R_VS41                          0x69
169 #define R_VS42                          0x6a
170 #define R_VS43                          0x6b
171 #define R_VS44                          0x6c
172 #define R_VS45                          0x6d
173 #define R_VS46                          0x6e
174 #define R_VS47                          0x6f
175 #define R_VS48                          0x70
176 #define R_VS49                          0x71
177 #define R_VS50                          0x72
178 #define R_VS51                          0x73
179 #define R_VS52                          0x74
180 #define R_VS53                          0x75
181 #define R_VS54                          0x76
182 #define R_VS55                          0x77
183 #define R_VS56                          0x78
184 #define R_VS57                          0x79
185 #define R_VS58                          0x7a
186 #define R_VS59                          0x7b
187 #define R_VS60                          0x7c
188 #define R_VS61                          0x7d
189 #define R_VS62                          0x7e
190 #define R_VS63                          0x7f
192 #define R_CG_SCRATCH                    R_0
194 #define R_SP                            R_1
196 #define R_SCRATCH_1                     R_3
197 #define R_SCRATCH_2                     R_4
198 #define R_SCRATCH_3                     R_5
199 #define R_SCRATCH_4                     R_SAVED_2
201 #define R_SCRATCH_NA_1                  R_7
202 #define R_SCRATCH_NA_2                  R_8
203 #define R_SCRATCH_NA_3                  R_9
205 #define R_FRAME                         R_31
206 #define R_UPCALL                        R_30
207 #define R_TIMESTAMP                     R_29
209 #define R_SAVED_1                       R_28
210 #define R_SAVED_2                       R_27
211 #define R_ZERO                          R_26
213 #define R_LOWEST_SAVED                  R_14
215 #define R_ARG0                          R_3
216 #define R_ARG1                          R_4
217 #define R_ARG2                          R_5
218 #define R_ARG3                          R_6
219 #define R_ARG4                          R_7
220 #define R_RET0                          R_3
221 #define R_RET1                          R_4
223 #define R_OFFSET_IMM                    R_10
224 #define R_CONST_IMM                     R_11
226 #define FR_SCRATCH_1                    (real_type == 4 ? R_VS32 : R_F0)
227 #define FR_SCRATCH_2                    (real_type == 4 ? R_VS33 : R_F1)
228 #define FR_SCRATCH_3                    (real_type == 4 ? R_VS34 : R_F2)
230 #define SUPPORTED_FP                    (cpu_test_feature(CPU_FEATURE_ppc) * 0x2 + 0x4 + cpu_test_feature(CPU_FEATURE_v30) * 0x10)
232 static bool reg_is_fp(unsigned reg)
234         return reg >= 0x40 && reg < 0x80;
237 static bool reg_is_vs(unsigned reg)
239         return reg >= 0x60 && reg < 0x80;
242 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 };
243 static const uint8_t regs_volatile[] = { R_6, R_12 };
244 static const uint8_t fp_saved[] = { 0 };
245 #define n_fp_saved 0U
246 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 };
247 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 };
248 #define reg_is_saved(r) (((r) >= R_14 && (r) <= R_31) || ((r) >= R_F14 && (r) <= R_F31) || ((r) >= R_VS52 && (r) <= R_VS63))
250 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
252         unsigned xreg = R_ZERO;
253         if (OP_SIZE_NATIVE == OP_SIZE_4)
254                 c = (int32_t)c;
255         if (c == (uint64_t)(int32_t)c) {
256                 if (c == (uint64_t)(int16_t)c) {
257                         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
258                         gen_one(reg);
259                         gen_one(ARG_IMM);
260                         gen_eight((int16_t)c);
261                         return true;
262                 }
263                 if (c & 0xffffffffffff0000ULL) {
264                         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
265                         gen_one(reg);
266                         gen_one(ARG_IMM);
267                         gen_eight(c & 0xffffffffffff0000ULL);
268                         xreg = reg;
269                 }
270         } else {
271                 if (c >> 48) {
272                         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
273                         gen_one(reg);
274                         gen_one(ARG_IMM);
275                         gen_eight((int32_t)((c >> 32) & 0xffff0000U));
276                         xreg = reg;
277                 }
278                 if (c & 0x0000ffff00000000ULL) {
279                         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
280                         gen_one(reg);
281                         gen_one(xreg);
282                         gen_one(ARG_IMM);
283                         gen_eight((uint16_t)(c >> 32));
284                         xreg = reg;
285                 }
286                 if (xreg != R_ZERO) {
287                         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
288                         gen_one(reg);
289                         gen_one(reg);
290                         gen_one(ARG_IMM);
291                         gen_eight(32);
292                 }
293                 if (c & 0xffff0000U) {
294                         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
295                         gen_one(reg);
296                         gen_one(xreg);
297                         gen_one(ARG_IMM);
298                         gen_eight(c & 0xffff0000U);
299                         xreg = reg;
300                 }
301         }
302         if (c & 0xffffU) {
303                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
304                 gen_one(reg);
305                 gen_one(xreg);
306                 gen_one(ARG_IMM);
307                 gen_eight(c & 0xffffU);
308                 xreg = reg;
309         }
310         if (xreg == R_ZERO) {
311                 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
312                 gen_one(reg);
313                 gen_one(ARG_IMM);
314                 gen_eight(0);
315         }
316         return true;
319 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned size)
321         ctx->base_reg = base;
322         ctx->offset_imm = imm;
323         ctx->offset_reg = false;
324         switch (purpose) {
325                 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
326                         if (size >= OP_SIZE_16 && imm & 15)
327                                 break;
328                         /*-fallthrough*/
329                 case IMM_PURPOSE_LDR_SX_OFFSET:
330                         if (size >= OP_SIZE_4 && imm & 3)
331                                 break;
332                         /*-fallthrough*/
333                 case IMM_PURPOSE_LDR_OFFSET:
334                 case IMM_PURPOSE_STR_OFFSET:
335                         if (size >= OP_SIZE_8 && imm & 3)
336                                 break;
337                         /*-fallthrough*/
338                 case IMM_PURPOSE_MVI_CLI_OFFSET:
339                         if (likely(imm >= -0x8000) && likely(imm < 0x8000))
340                                 return true;
341                         break;
342                 default:
343                         internal(file_line, "gen_address: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
344         }
345         g(gen_load_constant(ctx, R_OFFSET_IMM, imm));
346         ctx->offset_reg = true;
347         return true;
350 static bool is_direct_const(int64_t imm, unsigned purpose, unsigned size)
352         switch (purpose) {
353                 case IMM_PURPOSE_STORE_VALUE:
354                 case IMM_PURPOSE_CMOV:
355                         if (!imm)
356                                 return true;
357                         break;
358                 case IMM_PURPOSE_ANDN:
359                         break;
360                 case IMM_PURPOSE_ADD:
361                 case IMM_PURPOSE_CMP:
362                         if (likely(imm >= -0x8000) && likely(imm < 0x8000))
363                                 return true;
364                         if (imm & 0xffff)
365                                 break;
366                         if (likely(imm >= -0x80000000L) && likely(imm < 0x80000000L))
367                                 return true;
368                         break;
369                 case IMM_PURPOSE_SUB:
370                         if (likely(imm > -0x8000) && likely(imm <= 0x8000))
371                                 return true;
372                         if (imm & 0xffff)
373                                 break;
374                         if (likely(imm > -0x80000000L) && likely(imm <= 0x80000000L))
375                                 return true;
376                         break;
377                 case IMM_PURPOSE_CMP_LOGICAL:
378                 case IMM_PURPOSE_AND:
379                 case IMM_PURPOSE_OR:
380                 case IMM_PURPOSE_XOR:
381                 case IMM_PURPOSE_TEST:
382                         if (likely(imm >= 0) && likely(imm < 0x10000))
383                                 return true;
384                         if (imm & 0xffff)
385                                 break;
386                         if (likely(imm >= 0LL) && likely(imm < 0x100000000LL))
387                                 return true;
388                         break;
389                 case IMM_PURPOSE_MUL:
390                         if (size != OP_SIZE_4)
391                                 break;
392                         if (likely(imm >= -0x8000) && likely(imm < 0x8000))
393                                 return true;
394                         break;
395                 default:
396                         internal(file_line, "is_direct_const: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
397         }
398         return false;
401 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
403         if (is_direct_const(imm, purpose, size)) {
404                 ctx->const_imm = imm;
405                 ctx->const_reg = false;
406         } else {
407                 g(gen_load_constant(ctx, R_CONST_IMM, imm));
408                 ctx->const_reg = true;
409         }
410         return true;
413 static bool attr_w gen_entry(struct codegen_context *ctx)
415         int i, offs;
417         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
418         gen_one(ARG_ADDRESS_1_PRE_I);
419         gen_one(R_SP);
420         gen_eight(-FRAME_SIZE);
421         gen_one(R_SP);
423         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
424         gen_one(R_SCRATCH_NA_3);
425         gen_one(R_LR);
427         for (i = R_LOWEST_SAVED, offs = REGS_OFFSET; i <= R_31; i++, offs += 1 << OP_SIZE_ADDRESS) {
428                 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
429                 gen_one(ARG_ADDRESS_1);
430                 gen_one(R_SP);
431                 gen_eight(offs);
432                 gen_one(i);
433         }
435         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
436         gen_one(ARG_ADDRESS_1);
437         gen_one(R_SP);
438         gen_eight(LR_OFFSET);
439         gen_one(R_SCRATCH_NA_3);
441         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
442         gen_one(R_ZERO);
443         gen_one(ARG_IMM);
444         gen_eight(0);
446 #if !defined(STRUCT_RET_OFFSET)
447         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
448         gen_one(R_FRAME);
449         gen_one(R_ARG0);
451         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
452         gen_one(R_UPCALL);
453         gen_one(R_ARG1);
455         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
456         gen_one(R_TIMESTAMP);
457         gen_one(R_ARG2);
459         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
460         gen_one(R_ARG3);
461 #else
462         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
463         gen_one(ARG_ADDRESS_1);
464         gen_one(R_SP);
465         gen_eight(STRUCT_RET_OFFSET);
466         gen_one(R_ARG0);
468         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
469         gen_one(R_FRAME);
470         gen_one(R_ARG1);
472         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
473         gen_one(R_UPCALL);
474         gen_one(R_ARG2);
476         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
477         gen_one(R_TIMESTAMP);
478         gen_one(R_ARG3);
480         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
481         gen_one(R_ARG4);
482 #endif
484         return true;
487 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
489         g(gen_load_constant(ctx, R_RET1, ip));
491         gen_insn(INSN_JMP, 0, 0, 0);
492         gen_four(escape_label);
494         return true;
497 static bool attr_w gen_escape(struct codegen_context *ctx)
499         int i, offs;
501 #if !defined(STRUCT_RET_OFFSET)
502         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
503         gen_one(R_RET0);
504         gen_one(R_FRAME);
505 #else
506         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
507         gen_one(R_RET0);
508         gen_one(ARG_ADDRESS_1);
509         gen_one(R_SP);
510         gen_eight(STRUCT_RET_OFFSET);
512         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
513         gen_one(ARG_ADDRESS_1);
514         gen_one(R_RET0);
515         gen_eight(0);
516         gen_one(R_FRAME);
518         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
519         gen_one(ARG_ADDRESS_1);
520         gen_one(R_RET0);
521         gen_eight(1U << OP_SIZE_NATIVE);
522         gen_one(R_RET1);
523 #endif
524         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
525         gen_one(R_SCRATCH_NA_1);
526         gen_one(ARG_ADDRESS_1);
527         gen_one(R_SP);
528         gen_eight(LR_OFFSET);
530         for (i = R_LOWEST_SAVED, offs = REGS_OFFSET; i <= R_31; i++, offs += 1 << OP_SIZE_ADDRESS) {
531                 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
532                 gen_one(i);
533                 gen_one(ARG_ADDRESS_1);
534                 gen_one(R_SP);
535                 gen_eight(offs);
536         }
538         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
539         gen_one(R_LR);
540         gen_one(R_SCRATCH_NA_1);
542         gen_insn(INSN_ALU, OP_SIZE_NATIVE, 0, 0);
543         gen_one(R_SP);
544         gen_one(R_SP);
545         gen_one(ARG_IMM);
546         gen_eight(FRAME_SIZE);
548         gen_insn(INSN_RET, 0, 0, 0);
550         return true;
553 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
555         return true;
558 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
560 #ifndef AIX_CALL
561         g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
562         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
563         gen_one(R_12);
564         gen_address_offset();
566         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
567         gen_one(R_CTR);
568         gen_one(R_12);
570         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_NATIVE, 0, 0);
571         gen_one(R_CTR);
572 #else
573         g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
574         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
575         gen_one(R_SCRATCH_NA_2);
576         gen_address_offset();
578         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
579         gen_one(R_SCRATCH_NA_1);
580         gen_one(ARG_ADDRESS_1);
581         gen_one(R_SCRATCH_NA_2);
582         gen_eight(0);
584         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
585         gen_one(R_CTR);
586         gen_one(R_SCRATCH_NA_1);
588         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
589         gen_one(R_2);
590         gen_one(ARG_ADDRESS_1);
591         gen_one(R_SCRATCH_NA_2);
592         gen_eight(1 << OP_SIZE_ADDRESS);
594         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
595         gen_one(R_11);
596         gen_one(ARG_ADDRESS_1);
597         gen_one(R_SCRATCH_NA_2);
598         gen_eight(2 << OP_SIZE_ADDRESS);
600         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_NATIVE, 0, 0);
601         gen_one(R_CTR);
602 #endif
603         g(gen_upcall_end(ctx, n_args));
605         return true;
608 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
610         g(gen_address(ctx, R_UPCALL, offsetof(struct cg_upcall_vector_s, ts), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_4));
611         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
612         gen_one(R_SCRATCH_1);
613         gen_address_offset();
615         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
616         gen_one(R_SCRATCH_1);
617         gen_one(R_TIMESTAMP);
619         gen_insn(INSN_JMP_COND, OP_SIZE_4, COND_NE, 0);
620         gen_four(escape_label);
622         return true;