x86: fix a bug that we misgenerated the the 8-bit imul with a constant
[ajla.git] / c1-mips.inc
blob9e2eacfb02bae70b0e3d88cfa5b08ec32fa4ee68
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 ARCH_MIPS_O32
20 #define OP_SIZE_NATIVE  OP_SIZE_4
21 #else
22 #define OP_SIZE_NATIVE  OP_SIZE_8
23 #endif
25 #ifdef ARCH_MIPS32
26 #define OP_SIZE_ADDRESS OP_SIZE_4
27 #else
28 #define OP_SIZE_ADDRESS OP_SIZE_8
29 #endif
31 #define JMP_LIMIT       JMP_EXTRA_LONG
33 #define UNALIGNED_TRAP                  (!MIPS_R6)
35 #define ALU_WRITES_FLAGS(alu, im)       0
36 #define ALU1_WRITES_FLAGS(alu)          0
37 #define ROT_WRITES_FLAGS(alu, size, im) 0
38 #define COND_IS_LOGICAL(cond)           0
40 #define ARCH_PARTIAL_ALU(size)          0
41 #define ARCH_IS_3ADDRESS(alu, f)        1
42 #define ARCH_IS_3ADDRESS_IMM(alu, f)    1
43 #define ARCH_IS_3ADDRESS_ROT(alu, size) 1
44 #define ARCH_IS_3ADDRESS_ROT_IMM(alu)   1
45 #define ARCH_IS_2ADDRESS(alu)           1
46 #define ARCH_IS_3ADDRESS_FP             1
47 #define ARCH_HAS_JMP_2REGS(cond)        ((cond) == COND_E || (cond) == COND_NE || MIPS_R6)
48 #define ARCH_HAS_FLAGS                  0
49 #define ARCH_SUPPORTS_TRAPS             OS_SUPPORTS_TRAPS
50 #define ARCH_TRAP_BEFORE                1
51 #define ARCH_PREFERS_SX(size)           0
52 #define ARCH_HAS_BWX                    1
53 #define ARCH_HAS_MUL                    1
54 #define ARCH_HAS_DIV                    1
55 #define ARCH_HAS_ANDN                   0
56 #define ARCH_HAS_SHIFTED_ADD(bits)      (MIPS_R6 && (bits) >= 1 && (bits) <= 4)
57 #define ARCH_HAS_BTX(btx, size, cnst)   0
58 #define ARCH_SHIFT_SIZE                 OP_SIZE_4
59 #define ARCH_BOOL_SIZE                  OP_SIZE_NATIVE
60 #define ARCH_HAS_FP_GP_MOV              1
61 #define ARCH_NEEDS_BARRIER              0
63 #define i_size(size)                    OP_SIZE_NATIVE
64 #define i_size_rot(size)                maximum(size, OP_SIZE_4)
65 #define i_size_cmp(size)                OP_SIZE_NATIVE
67 #if __mips < 2
68 #define MIPS_LOAD_DELAY_SLOTS           1
69 #define MIPS_HAS_LS_DOUBLE              0
70 #define MIPS_HAS_SQRT                   0
71 #define MIPS_HAS_TRUNC                  0
72 #else
73 #define MIPS_LOAD_DELAY_SLOTS           0
74 #define MIPS_HAS_LS_DOUBLE              1
75 #define MIPS_HAS_SQRT                   1
76 #define MIPS_HAS_TRUNC                  1
77 #endif
79 #if __mips < 4
80 #define MIPS_R4000_ERRATA               1
81 #define MIPS_FCMP_DELAY_SLOTS           1
82 #define MIPS_HAS_MOVT                   0
83 #else
84 #define MIPS_R4000_ERRATA               0
85 #define MIPS_FCMP_DELAY_SLOTS           0
86 #define MIPS_HAS_MOVT                   1
87 #endif
89 #if __mips < 32
90 #define MIPS_HAS_CLZ                    0
91 #define MIPS_HAS_MUL                    0
92 #else
93 #define MIPS_HAS_CLZ                    1
94 #define MIPS_HAS_MUL                    1
95 #endif
97 #if __mips < 32 || !defined(__mips_isa_rev) || __mips_isa_rev < 2
98 #define MIPS_HAS_ROT                    0
99 #else
100 #define MIPS_HAS_ROT                    1
101 #endif
103 #if __mips < 32 || !defined(__mips_isa_rev) || __mips_isa_rev < 6
104 #define MIPS_R6                         0
105 #else
106 #define MIPS_R6                         1
107 #endif
109 #define R_ZERO          0x00
110 #define R_AT            0x01
111 #define R_V0            0x02
112 #define R_V1            0x03
113 #define R_A0            0x04
114 #define R_A1            0x05
115 #define R_A2            0x06
116 #define R_A3            0x07
117 #define R_T0            0x08
118 #define R_T1            0x09
119 #define R_T2            0x0a
120 #define R_T3            0x0b
121 #define R_T4            0x0c
122 #define R_T5            0x0d
123 #define R_T6            0x0e
124 #define R_T7            0x0f
125 #define R_S0            0x10
126 #define R_S1            0x11
127 #define R_S2            0x12
128 #define R_S3            0x13
129 #define R_S4            0x14
130 #define R_S5            0x15
131 #define R_S6            0x16
132 #define R_S7            0x17
133 #define R_T8            0x18
134 #define R_T9            0x19
135 #define R_K0            0x1a
136 #define R_K1            0x1b
137 #define R_GP            0x1c
138 #define R_SP            0x1d
139 #define R_FP            0x1e
140 #define R_RA            0x1f
142 #define R_F0            0x20
143 #define R_F1            0x21
144 #define R_F2            0x22
145 #define R_F3            0x23
146 #define R_F4            0x24
147 #define R_F5            0x25
148 #define R_F6            0x26
149 #define R_F7            0x27
150 #define R_F8            0x28
151 #define R_F9            0x29
152 #define R_F10           0x2a
153 #define R_F11           0x2b
154 #define R_F12           0x2c
155 #define R_F13           0x2d
156 #define R_F14           0x2e
157 #define R_F15           0x2f
158 #define R_F16           0x30
159 #define R_F17           0x31
160 #define R_F18           0x32
161 #define R_F19           0x33
162 #define R_F20           0x34
163 #define R_F21           0x35
164 #define R_F22           0x36
165 #define R_F23           0x37
166 #define R_F24           0x38
167 #define R_F25           0x39
168 #define R_F26           0x3a
169 #define R_F27           0x3b
170 #define R_F28           0x3c
171 #define R_F29           0x3d
172 #define R_F30           0x3e
173 #define R_F31           0x3f
175 #define R_FRAME         R_S0
176 #define R_UPCALL        R_S1
178 #define R_SCRATCH_1     R_A0
179 #define R_SCRATCH_2     R_A1
180 #define R_SCRATCH_3     R_A2
181 #define R_SCRATCH_4     R_SAVED_2
182 #define R_SCRATCH_NA_1  R_T0
183 #define R_SCRATCH_NA_2  R_T1
184 #define R_SCRATCH_NA_3  R_T2
186 #define R_SAVED_1       R_S2
187 #define R_SAVED_2       R_S3
189 #define R_ARG0          R_A0
190 #define R_ARG1          R_A1
191 #define R_ARG2          R_A2
192 #define R_ARG3          R_A3
194 #define R_RET0          R_V0
195 #define R_RET1          R_V1
197 #define R_OFFSET_IMM    R_T3
198 #define R_CONST_IMM     R_T4
199 #define R_CMP_RESULT    R_T5
201 #define FR_SCRATCH_1    R_F0
202 #define FR_SCRATCH_2    R_F2
203 #define FR_SCRATCH_3    R_F4
204 #define FR_CMP_RESULT   R_F6
206 #define SUPPORTED_FP    0x6
208 #ifdef ARCH_MIPS_O32
209 #define FRAME_SIZE      64
210 #define SAVE_OFFSET     20
211 #else
212 #define FRAME_SIZE      96
213 #define SAVE_OFFSET     0
214 #endif
216 static bool reg_is_fp(unsigned reg)
218         return reg >= 0x20 && reg < 0x40;
221 static const uint8_t regs_saved[] = { R_S4, R_S5, R_S6, R_S7,
222 #ifndef ARCH_MIPS_O32
223         R_GP,
224 #endif
225         R_FP };
226 static const uint8_t regs_volatile[] = { R_A3, R_T6, R_T7, R_T8, R_T9 };
227 static const uint8_t fp_saved[] = { 0 };
228 #define n_fp_saved 0U
229 static const uint8_t fp_volatile[] = { R_F8, R_F10, R_F12, R_F14, R_F16, R_F18 };
230 #define reg_is_saved(r) (((r) >= R_S0 && (r) <= R_S7) || (r) == R_GP || (r) == R_FP)
232 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
234         if (OP_SIZE_NATIVE == OP_SIZE_4)
235                 c = (int32_t)c;
236         if ((int64_t)c != (int32_t)c) {
237                 if (MIPS_R6) {
238                         g(gen_load_constant(ctx, reg, (int32_t)c));
239                         if ((int32_t)c < 0) {
240                                 c += 0x100000000ULL;
241                         }
242                         c &= ~0xFFFFFFFFULL;
243                         c >>= 32;
244                         if (c & 0xFFFFULL) {
245                                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_ADD, 0);
246                                 gen_one(reg);
247                                 gen_one(reg);
248                                 gen_one(ARG_IMM);
249                                 gen_eight((uint64_t)(int16_t)c << 32);
250                         }
251                         if ((int16_t)c < 0) {
252                                 c += 0x10000ULL;
253                         }
254                         c &= ~0xFFFFULL;
255                         c >>= 16;
256                         if (c & 0xFFFFULL) {
257                                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_ADD, 0);
258                                 gen_one(reg);
259                                 gen_one(reg);
260                                 gen_one(ARG_IMM);
261                                 gen_eight(c << 48);
262                         }
263                         return true;
264                 }
265                 if (c && !(c & (c - 1))) {
266                         int bit = -1;
267                         uint64_t cc = c;
268                         do {
269                                 cc >>= 1;
270                                 bit++;
271                         } while (cc);
272                         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
273                         gen_one(reg);
274                         gen_one(R_ZERO);
275                         gen_one(ARG_IMM);
276                         gen_eight(1);
278                         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
279                         gen_one(reg);
280                         gen_one(reg);
281                         gen_one(ARG_IMM);
282                         gen_eight(bit);
284                         return true;
285                 }
286                 if (~c && !(~c & (~c - 1))) {
287                         g(gen_load_constant(ctx, reg, ~c));
289                         gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_NOT, 0);
290                         gen_one(reg);
291                         gen_one(reg);
293                         return true;
294                 }
295                 g(gen_load_constant(ctx, reg, (int32_t)((c & 0xFFFFFFFF00000000ULL) >> 32)));
296                 c &= 0xFFFFFFFFULL;
297                 if (c & 0xFFFF0000ULL) {
298                         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
299                         gen_one(reg);
300                         gen_one(reg);
301                         gen_one(ARG_IMM);
302                         gen_eight(16);
304                         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
305                         gen_one(reg);
306                         gen_one(reg);
307                         gen_one(ARG_IMM);
308                         gen_eight(c >> 16);
310                         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
311                         gen_one(reg);
312                         gen_one(reg);
313                         gen_one(ARG_IMM);
314                         gen_eight(16);
315                 } else {
316                         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
317                         gen_one(reg);
318                         gen_one(reg);
319                         gen_one(ARG_IMM);
320                         gen_eight(32);
321                 }
322                 if (c & 0xFFFFULL) {
323                         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
324                         gen_one(reg);
325                         gen_one(reg);
326                         gen_one(ARG_IMM);
327                         gen_eight(c & 0xFFFFULL);
328                 }
329                 return true;
330         }
331         if (c == (uint16_t)c) {
332                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
333                 gen_one(reg);
334                 gen_one(R_ZERO);
335                 gen_one(ARG_IMM);
336                 gen_eight(c);
337                 return true;
338         }
339         if ((int64_t)c == (int16_t)c) {
340                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_ADD, 0);
341                 gen_one(reg);
342                 gen_one(R_ZERO);
343                 gen_one(ARG_IMM);
344                 gen_eight(c);
345                 return true;
346         }
347         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
348         gen_one(reg);
349         gen_one(ARG_IMM);
350         gen_eight(c & ~0xffffULL);
351         if (c & 0xFFFFULL) {
352                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
353                 gen_one(reg);
354                 gen_one(reg);
355                 gen_one(ARG_IMM);
356                 gen_eight(c & 0xFFFFULL);
357         }
358         return true;
361 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned size)
363         ctx->base_reg = base;
364         ctx->offset_imm = imm;
365         ctx->offset_reg = false;
366         switch (purpose) {
367                 case IMM_PURPOSE_LDR_OFFSET:
368                 case IMM_PURPOSE_LDR_SX_OFFSET:
369                 case IMM_PURPOSE_STR_OFFSET:
370                 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
371                 case IMM_PURPOSE_MVI_CLI_OFFSET:
372                         if (likely(imm == (int16_t)imm))
373                                 return true;
374                         break;
375                 default:
376                         internal(file_line, "gen_address: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
377         }
378         g(gen_load_constant(ctx, R_OFFSET_IMM, imm));
379         gen_insn(INSN_ALU, OP_SIZE_ADDRESS, ALU_ADD, 0);
380         gen_one(R_OFFSET_IMM);
381         gen_one(R_OFFSET_IMM);
382         gen_one(base);
383         ctx->base_reg = R_OFFSET_IMM;
384         ctx->offset_imm = 0;
385         return true;
388 static bool is_direct_const(int64_t imm, unsigned purpose, unsigned size)
390         if (MIPS_R4000_ERRATA && (purpose == IMM_PURPOSE_ADD_TRAP || purpose == IMM_PURPOSE_SUB_TRAP) && size == OP_SIZE_8)
391                 return false;
392         switch (purpose) {
393                 case IMM_PURPOSE_STORE_VALUE:
394                         if (!imm)
395                                 return true;
396                         break;
397                 case IMM_PURPOSE_ADD:
398                 case IMM_PURPOSE_CMP:
399                 case IMM_PURPOSE_CMP_LOGICAL:
400                         if (likely(imm == (int16_t)imm))
401                                 return true;
402                         break;
403                 case IMM_PURPOSE_SUB:
404                         if (likely(imm > -0x8000) && likely(imm <= 0x8000))
405                                 return true;
406                         break;
407                 case IMM_PURPOSE_AND:
408                 case IMM_PURPOSE_OR:
409                 case IMM_PURPOSE_XOR:
410                 case IMM_PURPOSE_TEST:
411                         if (likely((uint64_t)imm == (uint16_t)imm))
412                                 return true;
413                         break;
414                 case IMM_PURPOSE_MUL:
415                         break;
416                 case IMM_PURPOSE_ADD_TRAP:
417                         if (MIPS_R6)
418                                 break;
419                         if (likely(imm == (int16_t)imm))
420                                 return true;
421                         break;
422                 case IMM_PURPOSE_SUB_TRAP:
423                         if (MIPS_R6)
424                                 break;
425                         if (likely(imm > -0x8000) && likely(imm <= 0x8000))
426                                 return true;
427                         break;
428                 default:
429                         internal(file_line, "is_direct_const: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
430         }
431         return false;
434 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
436         if (is_direct_const(imm, purpose, size)) {
437                 ctx->const_imm = imm;
438                 ctx->const_reg = false;
439         } else {
440                 g(gen_load_constant(ctx, R_CONST_IMM, imm));
441                 ctx->const_reg = true;
442         }
443         return true;
446 static bool attr_w gen_entry(struct codegen_context *ctx)
448         int save_offset;
449         unsigned reg;
451         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_SUB, 0);
452         gen_one(R_SP);
453         gen_one(R_SP);
454         gen_one(ARG_IMM);
455         gen_eight(FRAME_SIZE);
457         save_offset = SAVE_OFFSET;
459         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
460         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
461         gen_address_offset();
462         gen_one(R_ARG2);
463         save_offset += 1 << OP_SIZE_NATIVE;
465         for (reg = R_S0; reg <= R_S7; reg++) {
466                 g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
467                 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
468                 gen_address_offset();
469                 gen_one(reg);
470                 save_offset += 1 << OP_SIZE_NATIVE;
471         }
472 #ifndef ARCH_MIPS_O32
473         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
474         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
475         gen_address_offset();
476         gen_one(R_GP);
477         save_offset += 1 << OP_SIZE_NATIVE;
478 #endif
479         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
480         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
481         gen_address_offset();
482         gen_one(R_FP);
483         save_offset += 1 << OP_SIZE_NATIVE;
485         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
486         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
487         gen_address_offset();
488         gen_one(R_RA);
490         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
491         gen_one(R_FRAME);
492         gen_one(R_ARG0);
494         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
495         gen_one(R_UPCALL);
496         gen_one(R_ARG1);
498         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
499         gen_one(R_ARG3);
501         return true;
504 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
506         g(gen_load_constant(ctx, R_RET1, (int32_t)ip));
508         gen_insn(INSN_JMP, 0, 0, 0);
509         gen_four(escape_label);
511         return true;
514 static bool attr_w gen_escape(struct codegen_context *ctx)
516         int save_offset;
517         unsigned reg;
519 #if defined(ARCH_MIPS_N32)
520         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
521         gen_one(R_RET1);
522         gen_one(R_RET1);
523         gen_one(ARG_IMM);
524         gen_eight(32);
526         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
527         gen_one(R_RET0);
528         gen_one(R_FRAME);
529         gen_one(R_RET1);
530 #else
531         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
532         gen_one(R_RET0);
533         gen_one(R_FRAME);
534 #endif
536         save_offset = SAVE_OFFSET + (1 << OP_SIZE_NATIVE);
537         for (reg = R_S0; reg <= R_S7; reg++) {
538                 g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
539                 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
540                 gen_one(reg);
541                 gen_address_offset();
542                 save_offset += 1 << OP_SIZE_NATIVE;
543         }
544 #ifndef ARCH_MIPS_O32
545         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
546         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
547         gen_one(R_GP);
548         gen_address_offset();
549         save_offset += 1 << OP_SIZE_NATIVE;
550 #endif
551         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
552         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
553         gen_one(R_FP);
554         gen_address_offset();
555         save_offset += 1 << OP_SIZE_NATIVE;
557         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
558         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
559         gen_one(R_RA);
560         gen_address_offset();
562         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_ADD, 0);
563         gen_one(R_SP);
564         gen_one(R_SP);
565         gen_one(ARG_IMM);
566         gen_eight(FRAME_SIZE);
568         gen_insn(INSN_RET, 0, 0, 0);
570         return true;
573 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
575         return true;
578 static bool attr_w gen_get_upcall_pointer(struct codegen_context *ctx, unsigned offset, unsigned reg)
580         g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
581         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
582         gen_one(reg);
583         gen_address_offset();
585         return true;
588 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
590         g(gen_get_upcall_pointer(ctx, offset, R_T9));
592         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_ADDRESS, 0, 0);
593         gen_one(R_T9);
595         g(gen_upcall_end(ctx, n_args));
597         return true;
600 static bool attr_w gen_cmp_test_jmp(struct codegen_context *ctx, unsigned insn, unsigned op_size, unsigned reg1, unsigned reg2, unsigned cond, uint32_t label);
602 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
604         g(gen_address(ctx, R_UPCALL, offsetof(struct cg_upcall_vector_s, ts), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_4));
605         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
606         gen_one(R_SCRATCH_1);
607         gen_address_offset();
609         g(gen_address(ctx, R_SP, SAVE_OFFSET, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
610         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
611         gen_one(R_SCRATCH_2);
612         gen_address_offset();
614         g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, R_SCRATCH_1, R_SCRATCH_2, COND_NE, escape_label));
616         return true;