2 * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "qemu/osdep.h"
20 #include "exec/exec-all.h"
21 #include "exec/cpu_ldst.h"
22 #include "exec/helper-proto.h"
23 #include "fpu/softfloat.h"
28 #include "hex_arch_types.h"
30 #include "mmvec/mmvec.h"
31 #include "mmvec/macros.h"
32 #include "op_helper.h"
33 #include "translate.h"
36 #define SF_MANTBITS 23
38 /* Exceptions processing helpers */
40 void do_raise_exception_err(CPUHexagonState
*env
,
44 CPUState
*cs
= env_cpu(env
);
45 qemu_log_mask(CPU_LOG_INT
, "%s: %d\n", __func__
, exception
);
46 cs
->exception_index
= exception
;
47 cpu_loop_exit_restore(cs
, pc
);
50 G_NORETURN
void HELPER(raise_exception
)(CPUHexagonState
*env
, uint32_t excp
)
52 do_raise_exception_err(env
, excp
, 0);
55 void log_reg_write(CPUHexagonState
*env
, int rnum
,
56 target_ulong val
, uint32_t slot
)
58 HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld
" (0x" TARGET_FMT_lx
")",
60 if (val
== env
->gpr
[rnum
]) {
61 HEX_DEBUG_LOG(" NO CHANGE");
65 env
->new_value
[rnum
] = val
;
67 /* Do this so HELPER(debug_commit_end) will know */
68 env
->reg_written
[rnum
] = 1;
72 static void log_pred_write(CPUHexagonState
*env
, int pnum
, target_ulong val
)
74 HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
75 " (0x" TARGET_FMT_lx
")\n",
78 /* Multiple writes to the same preg are and'ed together */
79 if (env
->pred_written
& (1 << pnum
)) {
80 env
->new_pred_value
[pnum
] &= val
& 0xff;
82 env
->new_pred_value
[pnum
] = val
& 0xff;
83 env
->pred_written
|= 1 << pnum
;
87 void log_store32(CPUHexagonState
*env
, target_ulong addr
,
88 target_ulong val
, int width
, int slot
)
90 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
91 ", %" PRId32
" [0x08%" PRIx32
"])\n",
92 width
, addr
, val
, val
);
93 env
->mem_log_stores
[slot
].va
= addr
;
94 env
->mem_log_stores
[slot
].width
= width
;
95 env
->mem_log_stores
[slot
].data32
= val
;
98 void log_store64(CPUHexagonState
*env
, target_ulong addr
,
99 int64_t val
, int width
, int slot
)
101 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
102 ", %" PRId64
" [0x016%" PRIx64
"])\n",
103 width
, addr
, val
, val
);
104 env
->mem_log_stores
[slot
].va
= addr
;
105 env
->mem_log_stores
[slot
].width
= width
;
106 env
->mem_log_stores
[slot
].data64
= val
;
109 /* Handy place to set a breakpoint */
110 void HELPER(debug_start_packet
)(CPUHexagonState
*env
)
112 HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx
"\n",
113 env
->gpr
[HEX_REG_PC
]);
115 for (int i
= 0; i
< TOTAL_PER_THREAD_REGS
; i
++) {
116 env
->reg_written
[i
] = 0;
120 /* Checks for bookkeeping errors between disassembly context and runtime */
121 void HELPER(debug_check_store_width
)(CPUHexagonState
*env
, int slot
, int check
)
123 if (env
->mem_log_stores
[slot
].width
!= check
) {
124 HEX_DEBUG_LOG("ERROR: %d != %d\n",
125 env
->mem_log_stores
[slot
].width
, check
);
126 g_assert_not_reached();
130 void HELPER(commit_store
)(CPUHexagonState
*env
, int slot_num
)
132 uintptr_t ra
= GETPC();
133 uint8_t width
= env
->mem_log_stores
[slot_num
].width
;
134 target_ulong va
= env
->mem_log_stores
[slot_num
].va
;
138 cpu_stb_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data32
, ra
);
141 cpu_stw_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data32
, ra
);
144 cpu_stl_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data32
, ra
);
147 cpu_stq_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data64
, ra
);
150 g_assert_not_reached();
154 void HELPER(gather_store
)(CPUHexagonState
*env
, uint32_t addr
, int slot
)
156 mem_gather_store(env
, addr
, slot
);
159 void HELPER(commit_hvx_stores
)(CPUHexagonState
*env
)
161 uintptr_t ra
= GETPC();
164 /* Normal (possibly masked) vector store */
165 for (i
= 0; i
< VSTORES_MAX
; i
++) {
166 if (env
->vstore_pending
[i
]) {
167 env
->vstore_pending
[i
] = 0;
168 target_ulong va
= env
->vstore
[i
].va
;
169 int size
= env
->vstore
[i
].size
;
170 for (int j
= 0; j
< size
; j
++) {
171 if (test_bit(j
, env
->vstore
[i
].mask
)) {
172 cpu_stb_data_ra(env
, va
+ j
, env
->vstore
[i
].data
.ub
[j
], ra
);
179 if (env
->vtcm_pending
) {
180 env
->vtcm_pending
= false;
181 if (env
->vtcm_log
.op
) {
182 /* Need to perform the scatter read/modify/write at commit time */
183 if (env
->vtcm_log
.op_size
== 2) {
184 SCATTER_OP_WRITE_TO_MEM(uint16_t);
185 } else if (env
->vtcm_log
.op_size
== 4) {
186 /* Word Scatter += */
187 SCATTER_OP_WRITE_TO_MEM(uint32_t);
189 g_assert_not_reached();
192 for (i
= 0; i
< sizeof(MMVector
); i
++) {
193 if (test_bit(i
, env
->vtcm_log
.mask
)) {
194 cpu_stb_data_ra(env
, env
->vtcm_log
.va
[i
],
195 env
->vtcm_log
.data
.ub
[i
], ra
);
196 clear_bit(i
, env
->vtcm_log
.mask
);
197 env
->vtcm_log
.data
.ub
[i
] = 0;
205 static void print_store(CPUHexagonState
*env
, int slot
)
207 if (!(env
->slot_cancelled
& (1 << slot
))) {
208 uint8_t width
= env
->mem_log_stores
[slot
].width
;
210 uint32_t data
= env
->mem_log_stores
[slot
].data32
& 0xff;
211 HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx
"] = %" PRId32
212 " (0x%02" PRIx32
")\n",
213 env
->mem_log_stores
[slot
].va
, data
, data
);
214 } else if (width
== 2) {
215 uint32_t data
= env
->mem_log_stores
[slot
].data32
& 0xffff;
216 HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx
"] = %" PRId32
217 " (0x%04" PRIx32
")\n",
218 env
->mem_log_stores
[slot
].va
, data
, data
);
219 } else if (width
== 4) {
220 uint32_t data
= env
->mem_log_stores
[slot
].data32
;
221 HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx
"] = %" PRId32
222 " (0x%08" PRIx32
")\n",
223 env
->mem_log_stores
[slot
].va
, data
, data
);
224 } else if (width
== 8) {
225 HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx
"] = %" PRId64
226 " (0x%016" PRIx64
")\n",
227 env
->mem_log_stores
[slot
].va
,
228 env
->mem_log_stores
[slot
].data64
,
229 env
->mem_log_stores
[slot
].data64
);
231 HEX_DEBUG_LOG("\tBad store width %d\n", width
);
232 g_assert_not_reached();
237 /* This function is a handy place to set a breakpoint */
238 void HELPER(debug_commit_end
)(CPUHexagonState
*env
, int has_st0
, int has_st1
)
240 bool reg_printed
= false;
241 bool pred_printed
= false;
244 HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx
"\n",
246 HEX_DEBUG_LOG("slot_cancelled = %d\n", env
->slot_cancelled
);
248 for (i
= 0; i
< TOTAL_PER_THREAD_REGS
; i
++) {
249 if (env
->reg_written
[i
]) {
251 HEX_DEBUG_LOG("Regs written\n");
254 HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld
" (0x" TARGET_FMT_lx
")\n",
255 i
, env
->new_value
[i
], env
->new_value
[i
]);
259 for (i
= 0; i
< NUM_PREGS
; i
++) {
260 if (env
->pred_written
& (1 << i
)) {
262 HEX_DEBUG_LOG("Predicates written\n");
265 HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx
"\n",
266 i
, env
->new_pred_value
[i
]);
270 if (has_st0
|| has_st1
) {
271 HEX_DEBUG_LOG("Stores\n");
280 HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx
"\n", env
->gpr
[HEX_REG_PC
]);
281 HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
282 ", insn = " TARGET_FMT_lx
283 ", hvx = " TARGET_FMT_lx
"\n",
284 env
->gpr
[HEX_REG_QEMU_PKT_CNT
],
285 env
->gpr
[HEX_REG_QEMU_INSN_CNT
],
286 env
->gpr
[HEX_REG_QEMU_HVX_CNT
]);
290 int32_t HELPER(fcircadd
)(int32_t RxV
, int32_t offset
, int32_t M
, int32_t CS
)
292 uint32_t K_const
= extract32(M
, 24, 4);
293 uint32_t length
= extract32(M
, 0, 17);
294 uint32_t new_ptr
= RxV
+ offset
;
298 if (K_const
== 0 && length
>= 4) {
300 end_addr
= start_addr
+ length
;
303 * Versions v3 and earlier used the K value to specify a power-of-2 size
304 * 2^(K+2) that is greater than the buffer length
306 int32_t mask
= (1 << (K_const
+ 2)) - 1;
307 start_addr
= RxV
& (~mask
);
308 end_addr
= start_addr
| length
;
311 if (new_ptr
>= end_addr
) {
313 } else if (new_ptr
< start_addr
) {
320 uint32_t HELPER(fbrev
)(uint32_t addr
)
323 * Bit reverse the low 16 bits of the address
325 return deposit32(addr
, 0, 16, revbit16(addr
));
328 static float32
build_float32(uint8_t sign
, uint32_t exp
, uint32_t mant
)
332 ((exp
& 0xff) << SF_MANTBITS
) |
333 (mant
& ((1 << SF_MANTBITS
) - 1)));
337 * sfrecipa, sfinvsqrta have two 32-bit results
338 * r0,p0=sfrecipa(r1,r2)
339 * r0,p0=sfinvsqrta(r1)
341 * Since helpers can only return a single value, we pack the two results
342 * into a 64-bit value.
344 uint64_t HELPER(sfrecipa
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
353 arch_fpop_start(env
);
354 if (arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
)) {
356 idx
= (RtV
>> 16) & 0x7f;
357 mant
= (recip_lookup_table
[idx
] << 15) | 1;
358 exp
= SF_BIAS
- (float32_getexp(RtV
) - SF_BIAS
) - 1;
359 RdV
= build_float32(extract32(RtV
, 31, 1), exp
, mant
);
362 return ((uint64_t)RdV
<< 32) | PeV
;
365 uint64_t HELPER(sfinvsqrta
)(CPUHexagonState
*env
, float32 RsV
)
374 arch_fpop_start(env
);
375 if (arch_sf_invsqrt_common(&RsV
, &RdV
, &adjust
, &env
->fp_status
)) {
377 idx
= (RsV
>> 17) & 0x7f;
378 mant
= (invsqrt_lookup_table
[idx
] << 15);
379 exp
= SF_BIAS
- ((float32_getexp(RsV
) - SF_BIAS
) >> 1) - 1;
380 RdV
= build_float32(extract32(RsV
, 31, 1), exp
, mant
);
383 return ((uint64_t)RdV
<< 32) | PeV
;
386 int64_t HELPER(vacsh_val
)(CPUHexagonState
*env
,
387 int64_t RxxV
, int64_t RssV
, int64_t RttV
)
389 for (int i
= 0; i
< 4; i
++) {
390 int xv
= sextract64(RxxV
, i
* 16, 16);
391 int sv
= sextract64(RssV
, i
* 16, 16);
392 int tv
= sextract64(RttV
, i
* 16, 16);
396 max
= xv
> sv
? xv
: sv
;
397 /* Note that fSATH can set the OVF bit in usr */
398 RxxV
= deposit64(RxxV
, i
* 16, 16, fSATH(max
));
403 int32_t HELPER(vacsh_pred
)(CPUHexagonState
*env
,
404 int64_t RxxV
, int64_t RssV
, int64_t RttV
)
407 for (int i
= 0; i
< 4; i
++) {
408 int xv
= sextract64(RxxV
, i
* 16, 16);
409 int sv
= sextract64(RssV
, i
* 16, 16);
410 int tv
= sextract64(RttV
, i
* 16, 16);
413 PeV
= deposit32(PeV
, i
* 2, 1, (xv
> sv
));
414 PeV
= deposit32(PeV
, i
* 2 + 1, 1, (xv
> sv
));
419 static void probe_store(CPUHexagonState
*env
, int slot
, int mmu_idx
,
422 if (!is_predicated
|| !(env
->slot_cancelled
& (1 << slot
))) {
423 size1u_t width
= env
->mem_log_stores
[slot
].width
;
424 target_ulong va
= env
->mem_log_stores
[slot
].va
;
425 uintptr_t ra
= GETPC();
426 probe_write(env
, va
, width
, mmu_idx
, ra
);
431 * Called from a mem_noshuf packet to make sure the load doesn't
434 void HELPER(probe_noshuf_load
)(CPUHexagonState
*env
, target_ulong va
,
435 int size
, int mmu_idx
)
437 uintptr_t retaddr
= GETPC();
438 probe_read(env
, va
, size
, mmu_idx
, retaddr
);
441 /* Called during packet commit when there are two scalar stores */
442 void HELPER(probe_pkt_scalar_store_s0
)(CPUHexagonState
*env
, int args
)
444 int mmu_idx
= FIELD_EX32(args
, PROBE_PKT_SCALAR_STORE_S0
, MMU_IDX
);
446 FIELD_EX32(args
, PROBE_PKT_SCALAR_STORE_S0
, IS_PREDICATED
);
447 probe_store(env
, 0, mmu_idx
, is_predicated
);
450 void HELPER(probe_hvx_stores
)(CPUHexagonState
*env
, int mmu_idx
)
452 uintptr_t retaddr
= GETPC();
455 /* Normal (possibly masked) vector store */
456 for (i
= 0; i
< VSTORES_MAX
; i
++) {
457 if (env
->vstore_pending
[i
]) {
458 target_ulong va
= env
->vstore
[i
].va
;
459 int size
= env
->vstore
[i
].size
;
460 for (int j
= 0; j
< size
; j
++) {
461 if (test_bit(j
, env
->vstore
[i
].mask
)) {
462 probe_write(env
, va
+ j
, 1, mmu_idx
, retaddr
);
469 if (env
->vtcm_pending
) {
470 if (env
->vtcm_log
.op
) {
471 /* Need to perform the scatter read/modify/write at commit time */
472 if (env
->vtcm_log
.op_size
== 2) {
473 SCATTER_OP_PROBE_MEM(size2u_t
, mmu_idx
, retaddr
);
474 } else if (env
->vtcm_log
.op_size
== 4) {
475 /* Word Scatter += */
476 SCATTER_OP_PROBE_MEM(size4u_t
, mmu_idx
, retaddr
);
478 g_assert_not_reached();
481 for (int i
= 0; i
< sizeof(MMVector
); i
++) {
482 if (test_bit(i
, env
->vtcm_log
.mask
)) {
483 probe_write(env
, env
->vtcm_log
.va
[i
], 1, mmu_idx
, retaddr
);
491 void HELPER(probe_pkt_scalar_hvx_stores
)(CPUHexagonState
*env
, int mask
,
494 bool has_st0
= FIELD_EX32(mask
, PROBE_PKT_SCALAR_HVX_STORES
, HAS_ST0
);
495 bool has_st1
= FIELD_EX32(mask
, PROBE_PKT_SCALAR_HVX_STORES
, HAS_ST1
);
496 bool has_hvx_stores
=
497 FIELD_EX32(mask
, PROBE_PKT_SCALAR_HVX_STORES
, HAS_HVX_STORES
);
498 bool s0_is_pred
= FIELD_EX32(mask
, PROBE_PKT_SCALAR_HVX_STORES
, S0_IS_PRED
);
499 bool s1_is_pred
= FIELD_EX32(mask
, PROBE_PKT_SCALAR_HVX_STORES
, S1_IS_PRED
);
502 probe_store(env
, 0, mmu_idx
, s0_is_pred
);
505 probe_store(env
, 1, mmu_idx
, s1_is_pred
);
507 if (has_hvx_stores
) {
508 HELPER(probe_hvx_stores
)(env
, mmu_idx
);
514 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
516 * If the load is in slot 0 and there is a store in slot1 (that
517 * wasn't cancelled), we have to do the store first.
519 static void check_noshuf(CPUHexagonState
*env
, uint32_t slot
,
520 target_ulong vaddr
, int size
)
522 if (slot
== 0 && env
->pkt_has_store_s1
&&
523 ((env
->slot_cancelled
& (1 << 1)) == 0)) {
524 HELPER(probe_noshuf_load
)(env
, vaddr
, size
, MMU_USER_IDX
);
525 HELPER(commit_store
)(env
, 1);
529 uint8_t mem_load1(CPUHexagonState
*env
, uint32_t slot
, target_ulong vaddr
)
531 uintptr_t ra
= GETPC();
532 check_noshuf(env
, slot
, vaddr
, 1);
533 return cpu_ldub_data_ra(env
, vaddr
, ra
);
536 uint16_t mem_load2(CPUHexagonState
*env
, uint32_t slot
, target_ulong vaddr
)
538 uintptr_t ra
= GETPC();
539 check_noshuf(env
, slot
, vaddr
, 2);
540 return cpu_lduw_data_ra(env
, vaddr
, ra
);
543 uint32_t mem_load4(CPUHexagonState
*env
, uint32_t slot
, target_ulong vaddr
)
545 uintptr_t ra
= GETPC();
546 check_noshuf(env
, slot
, vaddr
, 4);
547 return cpu_ldl_data_ra(env
, vaddr
, ra
);
550 uint64_t mem_load8(CPUHexagonState
*env
, uint32_t slot
, target_ulong vaddr
)
552 uintptr_t ra
= GETPC();
553 check_noshuf(env
, slot
, vaddr
, 8);
554 return cpu_ldq_data_ra(env
, vaddr
, ra
);
558 float64
HELPER(conv_sf2df
)(CPUHexagonState
*env
, float32 RsV
)
561 arch_fpop_start(env
);
562 out_f64
= float32_to_float64(RsV
, &env
->fp_status
);
567 float32
HELPER(conv_df2sf
)(CPUHexagonState
*env
, float64 RssV
)
570 arch_fpop_start(env
);
571 out_f32
= float64_to_float32(RssV
, &env
->fp_status
);
576 float32
HELPER(conv_uw2sf
)(CPUHexagonState
*env
, int32_t RsV
)
579 arch_fpop_start(env
);
580 RdV
= uint32_to_float32(RsV
, &env
->fp_status
);
585 float64
HELPER(conv_uw2df
)(CPUHexagonState
*env
, int32_t RsV
)
588 arch_fpop_start(env
);
589 RddV
= uint32_to_float64(RsV
, &env
->fp_status
);
594 float32
HELPER(conv_w2sf
)(CPUHexagonState
*env
, int32_t RsV
)
597 arch_fpop_start(env
);
598 RdV
= int32_to_float32(RsV
, &env
->fp_status
);
603 float64
HELPER(conv_w2df
)(CPUHexagonState
*env
, int32_t RsV
)
606 arch_fpop_start(env
);
607 RddV
= int32_to_float64(RsV
, &env
->fp_status
);
612 float32
HELPER(conv_ud2sf
)(CPUHexagonState
*env
, int64_t RssV
)
615 arch_fpop_start(env
);
616 RdV
= uint64_to_float32(RssV
, &env
->fp_status
);
621 float64
HELPER(conv_ud2df
)(CPUHexagonState
*env
, int64_t RssV
)
624 arch_fpop_start(env
);
625 RddV
= uint64_to_float64(RssV
, &env
->fp_status
);
630 float32
HELPER(conv_d2sf
)(CPUHexagonState
*env
, int64_t RssV
)
633 arch_fpop_start(env
);
634 RdV
= int64_to_float32(RssV
, &env
->fp_status
);
639 float64
HELPER(conv_d2df
)(CPUHexagonState
*env
, int64_t RssV
)
642 arch_fpop_start(env
);
643 RddV
= int64_to_float64(RssV
, &env
->fp_status
);
648 uint32_t HELPER(conv_sf2uw
)(CPUHexagonState
*env
, float32 RsV
)
651 arch_fpop_start(env
);
652 /* Hexagon checks the sign before rounding */
653 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
654 float_raise(float_flag_invalid
, &env
->fp_status
);
657 RdV
= float32_to_uint32(RsV
, &env
->fp_status
);
663 int32_t HELPER(conv_sf2w
)(CPUHexagonState
*env
, float32 RsV
)
666 arch_fpop_start(env
);
667 /* Hexagon returns -1 for NaN */
668 if (float32_is_any_nan(RsV
)) {
669 float_raise(float_flag_invalid
, &env
->fp_status
);
672 RdV
= float32_to_int32(RsV
, &env
->fp_status
);
678 uint64_t HELPER(conv_sf2ud
)(CPUHexagonState
*env
, float32 RsV
)
681 arch_fpop_start(env
);
682 /* Hexagon checks the sign before rounding */
683 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
684 float_raise(float_flag_invalid
, &env
->fp_status
);
687 RddV
= float32_to_uint64(RsV
, &env
->fp_status
);
693 int64_t HELPER(conv_sf2d
)(CPUHexagonState
*env
, float32 RsV
)
696 arch_fpop_start(env
);
697 /* Hexagon returns -1 for NaN */
698 if (float32_is_any_nan(RsV
)) {
699 float_raise(float_flag_invalid
, &env
->fp_status
);
702 RddV
= float32_to_int64(RsV
, &env
->fp_status
);
708 uint32_t HELPER(conv_df2uw
)(CPUHexagonState
*env
, float64 RssV
)
711 arch_fpop_start(env
);
712 /* Hexagon checks the sign before rounding */
713 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
714 float_raise(float_flag_invalid
, &env
->fp_status
);
717 RdV
= float64_to_uint32(RssV
, &env
->fp_status
);
723 int32_t HELPER(conv_df2w
)(CPUHexagonState
*env
, float64 RssV
)
726 arch_fpop_start(env
);
727 /* Hexagon returns -1 for NaN */
728 if (float64_is_any_nan(RssV
)) {
729 float_raise(float_flag_invalid
, &env
->fp_status
);
732 RdV
= float64_to_int32(RssV
, &env
->fp_status
);
738 uint64_t HELPER(conv_df2ud
)(CPUHexagonState
*env
, float64 RssV
)
741 arch_fpop_start(env
);
742 /* Hexagon checks the sign before rounding */
743 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
744 float_raise(float_flag_invalid
, &env
->fp_status
);
747 RddV
= float64_to_uint64(RssV
, &env
->fp_status
);
753 int64_t HELPER(conv_df2d
)(CPUHexagonState
*env
, float64 RssV
)
756 arch_fpop_start(env
);
757 /* Hexagon returns -1 for NaN */
758 if (float64_is_any_nan(RssV
)) {
759 float_raise(float_flag_invalid
, &env
->fp_status
);
762 RddV
= float64_to_int64(RssV
, &env
->fp_status
);
768 uint32_t HELPER(conv_sf2uw_chop
)(CPUHexagonState
*env
, float32 RsV
)
771 arch_fpop_start(env
);
772 /* Hexagon checks the sign before rounding */
773 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
774 float_raise(float_flag_invalid
, &env
->fp_status
);
777 RdV
= float32_to_uint32_round_to_zero(RsV
, &env
->fp_status
);
783 int32_t HELPER(conv_sf2w_chop
)(CPUHexagonState
*env
, float32 RsV
)
786 arch_fpop_start(env
);
787 /* Hexagon returns -1 for NaN */
788 if (float32_is_any_nan(RsV
)) {
789 float_raise(float_flag_invalid
, &env
->fp_status
);
792 RdV
= float32_to_int32_round_to_zero(RsV
, &env
->fp_status
);
798 uint64_t HELPER(conv_sf2ud_chop
)(CPUHexagonState
*env
, float32 RsV
)
801 arch_fpop_start(env
);
802 /* Hexagon checks the sign before rounding */
803 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
804 float_raise(float_flag_invalid
, &env
->fp_status
);
807 RddV
= float32_to_uint64_round_to_zero(RsV
, &env
->fp_status
);
813 int64_t HELPER(conv_sf2d_chop
)(CPUHexagonState
*env
, float32 RsV
)
816 arch_fpop_start(env
);
817 /* Hexagon returns -1 for NaN */
818 if (float32_is_any_nan(RsV
)) {
819 float_raise(float_flag_invalid
, &env
->fp_status
);
822 RddV
= float32_to_int64_round_to_zero(RsV
, &env
->fp_status
);
828 uint32_t HELPER(conv_df2uw_chop
)(CPUHexagonState
*env
, float64 RssV
)
831 arch_fpop_start(env
);
832 /* Hexagon checks the sign before rounding */
833 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
834 float_raise(float_flag_invalid
, &env
->fp_status
);
837 RdV
= float64_to_uint32_round_to_zero(RssV
, &env
->fp_status
);
843 int32_t HELPER(conv_df2w_chop
)(CPUHexagonState
*env
, float64 RssV
)
846 arch_fpop_start(env
);
847 /* Hexagon returns -1 for NaN */
848 if (float64_is_any_nan(RssV
)) {
849 float_raise(float_flag_invalid
, &env
->fp_status
);
852 RdV
= float64_to_int32_round_to_zero(RssV
, &env
->fp_status
);
858 uint64_t HELPER(conv_df2ud_chop
)(CPUHexagonState
*env
, float64 RssV
)
861 arch_fpop_start(env
);
862 /* Hexagon checks the sign before rounding */
863 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
864 float_raise(float_flag_invalid
, &env
->fp_status
);
867 RddV
= float64_to_uint64_round_to_zero(RssV
, &env
->fp_status
);
873 int64_t HELPER(conv_df2d_chop
)(CPUHexagonState
*env
, float64 RssV
)
876 arch_fpop_start(env
);
877 /* Hexagon returns -1 for NaN */
878 if (float64_is_any_nan(RssV
)) {
879 float_raise(float_flag_invalid
, &env
->fp_status
);
882 RddV
= float64_to_int64_round_to_zero(RssV
, &env
->fp_status
);
888 float32
HELPER(sfadd
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
891 arch_fpop_start(env
);
892 RdV
= float32_add(RsV
, RtV
, &env
->fp_status
);
897 float32
HELPER(sfsub
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
900 arch_fpop_start(env
);
901 RdV
= float32_sub(RsV
, RtV
, &env
->fp_status
);
906 int32_t HELPER(sfcmpeq
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
909 arch_fpop_start(env
);
910 PdV
= f8BITSOF(float32_eq_quiet(RsV
, RtV
, &env
->fp_status
));
915 int32_t HELPER(sfcmpgt
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
919 arch_fpop_start(env
);
920 cmp
= float32_compare_quiet(RsV
, RtV
, &env
->fp_status
);
921 PdV
= f8BITSOF(cmp
== float_relation_greater
);
926 int32_t HELPER(sfcmpge
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
930 arch_fpop_start(env
);
931 cmp
= float32_compare_quiet(RsV
, RtV
, &env
->fp_status
);
932 PdV
= f8BITSOF(cmp
== float_relation_greater
||
933 cmp
== float_relation_equal
);
938 int32_t HELPER(sfcmpuo
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
941 arch_fpop_start(env
);
942 PdV
= f8BITSOF(float32_unordered_quiet(RsV
, RtV
, &env
->fp_status
));
947 float32
HELPER(sfmax
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
950 arch_fpop_start(env
);
951 RdV
= float32_maximum_number(RsV
, RtV
, &env
->fp_status
);
956 float32
HELPER(sfmin
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
959 arch_fpop_start(env
);
960 RdV
= float32_minimum_number(RsV
, RtV
, &env
->fp_status
);
965 int32_t HELPER(sfclass
)(CPUHexagonState
*env
, float32 RsV
, int32_t uiV
)
968 arch_fpop_start(env
);
969 if (fGETBIT(0, uiV
) && float32_is_zero(RsV
)) {
972 if (fGETBIT(1, uiV
) && float32_is_normal(RsV
)) {
975 if (fGETBIT(2, uiV
) && float32_is_denormal(RsV
)) {
978 if (fGETBIT(3, uiV
) && float32_is_infinity(RsV
)) {
981 if (fGETBIT(4, uiV
) && float32_is_any_nan(RsV
)) {
984 set_float_exception_flags(0, &env
->fp_status
);
989 float32
HELPER(sffixupn
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
993 arch_fpop_start(env
);
994 arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
);
1000 float32
HELPER(sffixupd
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
1004 arch_fpop_start(env
);
1005 arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
);
1011 float32
HELPER(sffixupr
)(CPUHexagonState
*env
, float32 RsV
)
1015 arch_fpop_start(env
);
1016 arch_sf_invsqrt_common(&RsV
, &RdV
, &adjust
, &env
->fp_status
);
1022 float64
HELPER(dfadd
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1025 arch_fpop_start(env
);
1026 RddV
= float64_add(RssV
, RttV
, &env
->fp_status
);
1031 float64
HELPER(dfsub
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1034 arch_fpop_start(env
);
1035 RddV
= float64_sub(RssV
, RttV
, &env
->fp_status
);
1040 float64
HELPER(dfmax
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1043 arch_fpop_start(env
);
1044 RddV
= float64_maximum_number(RssV
, RttV
, &env
->fp_status
);
1049 float64
HELPER(dfmin
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1052 arch_fpop_start(env
);
1053 RddV
= float64_minimum_number(RssV
, RttV
, &env
->fp_status
);
1058 int32_t HELPER(dfcmpeq
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1061 arch_fpop_start(env
);
1062 PdV
= f8BITSOF(float64_eq_quiet(RssV
, RttV
, &env
->fp_status
));
1067 int32_t HELPER(dfcmpgt
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1071 arch_fpop_start(env
);
1072 cmp
= float64_compare_quiet(RssV
, RttV
, &env
->fp_status
);
1073 PdV
= f8BITSOF(cmp
== float_relation_greater
);
1078 int32_t HELPER(dfcmpge
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1082 arch_fpop_start(env
);
1083 cmp
= float64_compare_quiet(RssV
, RttV
, &env
->fp_status
);
1084 PdV
= f8BITSOF(cmp
== float_relation_greater
||
1085 cmp
== float_relation_equal
);
1090 int32_t HELPER(dfcmpuo
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1093 arch_fpop_start(env
);
1094 PdV
= f8BITSOF(float64_unordered_quiet(RssV
, RttV
, &env
->fp_status
));
1099 int32_t HELPER(dfclass
)(CPUHexagonState
*env
, float64 RssV
, int32_t uiV
)
1102 arch_fpop_start(env
);
1103 if (fGETBIT(0, uiV
) && float64_is_zero(RssV
)) {
1106 if (fGETBIT(1, uiV
) && float64_is_normal(RssV
)) {
1109 if (fGETBIT(2, uiV
) && float64_is_denormal(RssV
)) {
1112 if (fGETBIT(3, uiV
) && float64_is_infinity(RssV
)) {
1115 if (fGETBIT(4, uiV
) && float64_is_any_nan(RssV
)) {
1118 set_float_exception_flags(0, &env
->fp_status
);
1123 float32
HELPER(sfmpy
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
1126 arch_fpop_start(env
);
1127 RdV
= internal_mpyf(RsV
, RtV
, &env
->fp_status
);
1132 float32
HELPER(sffma
)(CPUHexagonState
*env
, float32 RxV
,
1133 float32 RsV
, float32 RtV
)
1135 arch_fpop_start(env
);
1136 RxV
= internal_fmafx(RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1141 static bool is_zero_prod(float32 a
, float32 b
)
1143 return ((float32_is_zero(a
) && is_finite(b
)) ||
1144 (float32_is_zero(b
) && is_finite(a
)));
1147 static float32
check_nan(float32 dst
, float32 x
, float_status
*fp_status
)
1150 if (float32_is_any_nan(x
)) {
1151 if (extract32(x
, 22, 1) == 0) {
1152 float_raise(float_flag_invalid
, fp_status
);
1154 ret
= make_float32(0xffffffff); /* nan */
1159 float32
HELPER(sffma_sc
)(CPUHexagonState
*env
, float32 RxV
,
1160 float32 RsV
, float32 RtV
, float32 PuV
)
1163 arch_fpop_start(env
);
1164 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1165 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1166 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1167 tmp
= internal_fmafx(RsV
, RtV
, RxV
, fSXTN(8, 64, PuV
), &env
->fp_status
);
1168 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1175 float32
HELPER(sffms
)(CPUHexagonState
*env
, float32 RxV
,
1176 float32 RsV
, float32 RtV
)
1179 arch_fpop_start(env
);
1180 neg_RsV
= float32_set_sign(RsV
, float32_is_neg(RsV
) ? 0 : 1);
1181 RxV
= internal_fmafx(neg_RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1186 static bool is_inf_prod(int32_t a
, int32_t b
)
1188 return (float32_is_infinity(a
) && float32_is_infinity(b
)) ||
1189 (float32_is_infinity(a
) && is_finite(b
) && !float32_is_zero(b
)) ||
1190 (float32_is_infinity(b
) && is_finite(a
) && !float32_is_zero(a
));
1193 float32
HELPER(sffma_lib
)(CPUHexagonState
*env
, float32 RxV
,
1194 float32 RsV
, float32 RtV
)
1200 arch_fpop_start(env
);
1201 set_float_rounding_mode(float_round_nearest_even
, &env
->fp_status
);
1202 infminusinf
= float32_is_infinity(RxV
) &&
1203 is_inf_prod(RsV
, RtV
) &&
1204 (fGETBIT(31, RsV
^ RxV
^ RtV
) != 0);
1205 infinp
= float32_is_infinity(RxV
) ||
1206 float32_is_infinity(RtV
) ||
1207 float32_is_infinity(RsV
);
1208 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1209 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1210 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1211 tmp
= internal_fmafx(RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1212 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1215 set_float_exception_flags(0, &env
->fp_status
);
1216 if (float32_is_infinity(RxV
) && !infinp
) {
1226 float32
HELPER(sffms_lib
)(CPUHexagonState
*env
, float32 RxV
,
1227 float32 RsV
, float32 RtV
)
1233 arch_fpop_start(env
);
1234 set_float_rounding_mode(float_round_nearest_even
, &env
->fp_status
);
1235 infminusinf
= float32_is_infinity(RxV
) &&
1236 is_inf_prod(RsV
, RtV
) &&
1237 (fGETBIT(31, RsV
^ RxV
^ RtV
) == 0);
1238 infinp
= float32_is_infinity(RxV
) ||
1239 float32_is_infinity(RtV
) ||
1240 float32_is_infinity(RsV
);
1241 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1242 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1243 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1244 float32 minus_RsV
= float32_sub(float32_zero
, RsV
, &env
->fp_status
);
1245 tmp
= internal_fmafx(minus_RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1246 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1249 set_float_exception_flags(0, &env
->fp_status
);
1250 if (float32_is_infinity(RxV
) && !infinp
) {
1260 float64
HELPER(dfmpyfix
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1263 arch_fpop_start(env
);
1264 if (float64_is_denormal(RssV
) &&
1265 (float64_getexp(RttV
) >= 512) &&
1266 float64_is_normal(RttV
)) {
1267 RddV
= float64_mul(RssV
, make_float64(0x4330000000000000),
1269 } else if (float64_is_denormal(RttV
) &&
1270 (float64_getexp(RssV
) >= 512) &&
1271 float64_is_normal(RssV
)) {
1272 RddV
= float64_mul(RssV
, make_float64(0x3cb0000000000000),
1281 float64
HELPER(dfmpyhh
)(CPUHexagonState
*env
, float64 RxxV
,
1282 float64 RssV
, float64 RttV
)
1284 arch_fpop_start(env
);
1285 RxxV
= internal_mpyhh(RssV
, RttV
, RxxV
, &env
->fp_status
);
1290 /* Histogram instructions */
1292 void HELPER(vhist
)(CPUHexagonState
*env
)
1294 MMVector
*input
= &env
->tmp_VRegs
[0];
1296 for (int lane
= 0; lane
< 8; lane
++) {
1297 for (int i
= 0; i
< sizeof(MMVector
) / 8; ++i
) {
1298 unsigned char value
= input
->ub
[(sizeof(MMVector
) / 8) * lane
+ i
];
1299 unsigned char regno
= value
>> 3;
1300 unsigned char element
= value
& 7;
1302 env
->VRegs
[regno
].uh
[(sizeof(MMVector
) / 16) * lane
+ element
]++;
1307 void HELPER(vhistq
)(CPUHexagonState
*env
)
1309 MMVector
*input
= &env
->tmp_VRegs
[0];
1311 for (int lane
= 0; lane
< 8; lane
++) {
1312 for (int i
= 0; i
< sizeof(MMVector
) / 8; ++i
) {
1313 unsigned char value
= input
->ub
[(sizeof(MMVector
) / 8) * lane
+ i
];
1314 unsigned char regno
= value
>> 3;
1315 unsigned char element
= value
& 7;
1317 if (fGETQBIT(env
->qtmp
, sizeof(MMVector
) / 8 * lane
+ i
)) {
1318 env
->VRegs
[regno
].uh
[
1319 (sizeof(MMVector
) / 16) * lane
+ element
]++;
1325 void HELPER(vwhist256
)(CPUHexagonState
*env
)
1327 MMVector
*input
= &env
->tmp_VRegs
[0];
1329 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1330 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1331 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1332 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1333 unsigned int elindex
= ((i
>> 0) & (~7)) | ((bucket
>> 0) & 7);
1335 env
->VRegs
[vindex
].uh
[elindex
] =
1336 env
->VRegs
[vindex
].uh
[elindex
] + weight
;
1340 void HELPER(vwhist256q
)(CPUHexagonState
*env
)
1342 MMVector
*input
= &env
->tmp_VRegs
[0];
1344 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1345 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1346 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1347 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1348 unsigned int elindex
= ((i
>> 0) & (~7)) | ((bucket
>> 0) & 7);
1350 if (fGETQBIT(env
->qtmp
, 2 * i
)) {
1351 env
->VRegs
[vindex
].uh
[elindex
] =
1352 env
->VRegs
[vindex
].uh
[elindex
] + weight
;
1357 void HELPER(vwhist256_sat
)(CPUHexagonState
*env
)
1359 MMVector
*input
= &env
->tmp_VRegs
[0];
1361 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1362 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1363 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1364 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1365 unsigned int elindex
= ((i
>> 0) & (~7)) | ((bucket
>> 0) & 7);
1367 env
->VRegs
[vindex
].uh
[elindex
] =
1368 fVSATUH(env
->VRegs
[vindex
].uh
[elindex
] + weight
);
1372 void HELPER(vwhist256q_sat
)(CPUHexagonState
*env
)
1374 MMVector
*input
= &env
->tmp_VRegs
[0];
1376 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1377 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1378 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1379 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1380 unsigned int elindex
= ((i
>> 0) & (~7)) | ((bucket
>> 0) & 7);
1382 if (fGETQBIT(env
->qtmp
, 2 * i
)) {
1383 env
->VRegs
[vindex
].uh
[elindex
] =
1384 fVSATUH(env
->VRegs
[vindex
].uh
[elindex
] + weight
);
1389 void HELPER(vwhist128
)(CPUHexagonState
*env
)
1391 MMVector
*input
= &env
->tmp_VRegs
[0];
1393 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1394 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1395 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1396 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1397 unsigned int elindex
= ((i
>> 1) & (~3)) | ((bucket
>> 1) & 3);
1399 env
->VRegs
[vindex
].uw
[elindex
] =
1400 env
->VRegs
[vindex
].uw
[elindex
] + weight
;
1404 void HELPER(vwhist128q
)(CPUHexagonState
*env
)
1406 MMVector
*input
= &env
->tmp_VRegs
[0];
1408 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1409 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1410 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1411 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1412 unsigned int elindex
= ((i
>> 1) & (~3)) | ((bucket
>> 1) & 3);
1414 if (fGETQBIT(env
->qtmp
, 2 * i
)) {
1415 env
->VRegs
[vindex
].uw
[elindex
] =
1416 env
->VRegs
[vindex
].uw
[elindex
] + weight
;
1421 void HELPER(vwhist128m
)(CPUHexagonState
*env
, int32_t uiV
)
1423 MMVector
*input
= &env
->tmp_VRegs
[0];
1425 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1426 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1427 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1428 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1429 unsigned int elindex
= ((i
>> 1) & (~3)) | ((bucket
>> 1) & 3);
1431 if ((bucket
& 1) == uiV
) {
1432 env
->VRegs
[vindex
].uw
[elindex
] =
1433 env
->VRegs
[vindex
].uw
[elindex
] + weight
;
1438 void HELPER(vwhist128qm
)(CPUHexagonState
*env
, int32_t uiV
)
1440 MMVector
*input
= &env
->tmp_VRegs
[0];
1442 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1443 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1444 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1445 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1446 unsigned int elindex
= ((i
>> 1) & (~3)) | ((bucket
>> 1) & 3);
1448 if (((bucket
& 1) == uiV
) && fGETQBIT(env
->qtmp
, 2 * i
)) {
1449 env
->VRegs
[vindex
].uw
[elindex
] =
1450 env
->VRegs
[vindex
].uw
[elindex
] + weight
;
1455 /* These macros can be referenced in the generated helper functions */
1456 #define warn(...) /* Nothing */
1457 #define fatal(...) g_assert_not_reached();
1459 #define BOGUS_HELPER(tag) \
1460 printf("ERROR: bogus helper: " #tag "\n")
1462 #include "helper_funcs_generated.c.inc"