LoongArch: Use functions instead of magic numbers.
[binutils-gdb.git] / gas / config / tc-loongarch.c
1 /* tc-loongarch.c -- Assemble for the LoongArch ISA
2
3 Copyright (C) 2021-2022 Free Software Foundation, Inc.
4 Contributed by Loongson Ltd.
5
6 This file is part of GAS.
7
8 GAS is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the license, or
11 (at your option) any later version.
12
13 GAS is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING3. If not,
20 see <http://www.gnu.org/licenses/>. */
21
22 #include "as.h"
23 #include "dw2gencfi.h"
24 #include "loongarch-lex.h"
25 #include "elf/loongarch.h"
26 #include "opcode/loongarch.h"
27 #include "obj-elf.h"
28 #include "bfd/elfxx-loongarch.h"
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <assert.h>
33
34 /* All information about an instruction during assemble. */
35 struct loongarch_cl_insn
36 {
37 /* First split string. */
38 const char *name;
39 const char *arg_strs[MAX_ARG_NUM_PLUS_2];
40 size_t arg_num;
41
42 /* Second analyze name_str and each actual args string to match the insn
43 in 'loongarch-opc.c'. And actual args may need be relocated.
44 We get length of insn. If 'insn_length == 0 && insn_mo->macro != NULL',
45 it's a macro insntruction and we call 'md_assemble' recursively
46 after expanding it. */
47 int match_now;
48 int all_match;
49
50 const struct loongarch_opcode *insn;
51 size_t insn_length;
52
53 offsetT args[MAX_ARG_NUM_PLUS_2];
54 struct reloc_info reloc_info[MAX_RELOC_NUMBER_A_INSN];
55 size_t reloc_num;
56
57 /* For relax reserved. We not support relax now.
58 'insn_length < relax_max_length' means need to relax.
59 And 'insn_length == relax_max_length' means no need to relax. */
60 size_t relax_max_length;
61 relax_substateT subtype;
62
63 /* Then we get the binary representation of insn
64 and write it in to section. */
65 insn_t insn_bin;
66
67 /* The frag that contains the instruction. */
68 struct frag *frag;
69 /* The offset into FRAG of the first instruction byte. */
70 long where;
71 /* The relocs associated with the instruction, if any. */
72 fixS *fixp[MAX_RELOC_NUMBER_A_INSN];
73 };
74
75 #ifndef DEFAULT_ARCH
76 #define DEFAULT_ARCH "loongarch64"
77 #endif
78
79 /* This array holds the chars that always start a comment. If the
80 pre-processor is disabled, these aren't very useful. */
81 const char comment_chars[] = "#";
82
83 /* This array holds the chars that only start a comment at the beginning of
84 a line. If the line seems to have the form '# 123 filename'
85 .line and .file directives will appear in the pre-processed output. */
86 /* Note that input_file.c hand checks for '#' at the beginning of the
87 first line of the input file. This is because the compiler outputs
88 #NO_APP at the beginning of its output. */
89 /* Also note that C style comments are always supported. */
90 const char line_comment_chars[] = "#";
91
92 /* This array holds machine specific line separator characters. */
93 const char line_separator_chars[] = ";";
94
95 /* Chars that can be used to separate mant from exp in floating point nums. */
96 const char EXP_CHARS[] = "eE";
97
98 /* Chars that mean this number is a floating point constant. */
99 /* As in 0f12.456. */
100 /* or 0d1.2345e12. */
101 const char FLT_CHARS[] = "rRsSfFdDxXpP";
102
103 const char *md_shortopts = "O::g::G:";
104
105 static const char default_arch[] = DEFAULT_ARCH;
106
107 enum options
108 {
109 OPTION_IGNORE = OPTION_MD_BASE,
110
111 OPTION_ABI,
112 OPTION_FLOAT_ABI,
113
114 OPTION_FLOAT_ISA,
115
116 OPTION_LA_LOCAL_WITH_ABS,
117 OPTION_LA_GLOBAL_WITH_PCREL,
118 OPTION_LA_GLOBAL_WITH_ABS,
119
120 OPTION_END_OF_ENUM,
121 };
122
123 struct option md_longopts[] =
124 {
125 { "mabi", required_argument, NULL, OPTION_ABI },
126 { "mfloat-abi", required_argument, NULL, OPTION_FLOAT_ABI },
127
128 { "mfpu", required_argument, NULL, OPTION_FLOAT_ISA },
129
130 { "mla-local-with-abs", no_argument, NULL, OPTION_LA_LOCAL_WITH_ABS },
131 { "mla-global-with-pcrel", no_argument, NULL, OPTION_LA_GLOBAL_WITH_PCREL },
132 { "mla-global-with-abs", no_argument, NULL, OPTION_LA_GLOBAL_WITH_ABS },
133
134 { NULL, no_argument, NULL, 0 }
135 };
136
137 size_t md_longopts_size = sizeof (md_longopts);
138
139 int
140 md_parse_option (int c, const char *arg)
141 {
142 int ret = 1;
143 switch (c)
144 {
145 case OPTION_ABI:
146 if (strcasecmp (arg, "lp64") == 0)
147 {
148 LARCH_opts.ase_abi |= EF_LOONGARCH_ABI_LP64;
149 LARCH_opts.ase_ilp32 = 1;
150 LARCH_opts.ase_lp64 = 1;
151 }
152 else if (strcasecmp (arg, "ilp32") == 0)
153 {
154 LARCH_opts.ase_abi |= EF_LOONGARCH_ABI_ILP32;
155 LARCH_opts.ase_ilp32 = 1;
156 }
157 else
158 ret = 0;
159 break;
160
161 case OPTION_FLOAT_ABI:
162 if (strcasecmp (arg, "soft") == 0)
163 LARCH_opts.ase_abi |= EF_LOONGARCH_FLOAT_ABI_SOFT;
164 else if (strcasecmp (arg, "single") == 0)
165 LARCH_opts.ase_abi |= EF_LOONGARCH_FLOAT_ABI_SINGLE;
166 else if (strcasecmp (arg, "double") == 0)
167 LARCH_opts.ase_abi |= EF_LOONGARCH_FLOAT_ABI_DOUBLE;
168 else
169 ret = 0;
170 break;
171
172 case OPTION_FLOAT_ISA:
173 if (strcasecmp (arg, "soft") == 0)
174 LARCH_opts.ase_nf = 1;
175 else if (strcasecmp (arg, "single") == 0)
176 LARCH_opts.ase_sf = 1;
177 else if (strcasecmp (arg, "double") == 0)
178 {
179 LARCH_opts.ase_sf = 1;
180 LARCH_opts.ase_df = 1;
181 }
182 else
183 ret = 0;
184 break;
185
186 case OPTION_LA_LOCAL_WITH_ABS:
187 LARCH_opts.ase_labs = 1;
188 break;
189
190 case OPTION_LA_GLOBAL_WITH_PCREL:
191 LARCH_opts.ase_gpcr = 1;
192 break;
193
194 case OPTION_LA_GLOBAL_WITH_ABS:
195 LARCH_opts.ase_gabs = 1;
196 break;
197
198 case OPTION_IGNORE:
199 break;
200
201 default:
202 ret = 0;
203 break;
204 }
205 return ret;
206 }
207
208 static struct htab *r_htab = NULL;
209 static struct htab *f_htab = NULL;
210 static struct htab *c_htab = NULL;
211 static struct htab *cr_htab = NULL;
212 static struct htab *v_htab = NULL;
213 static struct htab *x_htab = NULL;
214
215 void
216 loongarch_after_parse_args ()
217 {
218 /* Set default ABI/ISA LP64. */
219 if (!EF_LOONGARCH_IS_LP64(LARCH_opts.ase_abi)
220 && !EF_LOONGARCH_IS_ILP32(LARCH_opts.ase_abi))
221 {
222 if (strcmp (default_arch, "loongarch64") == 0)
223 {
224 LARCH_opts.ase_abi |= EF_LOONGARCH_ABI_LP64;
225 LARCH_opts.ase_ilp32 = 1;
226 LARCH_opts.ase_lp64 = 1;
227 }
228 else if (strcmp (default_arch, "loongarch32") == 0)
229 {
230 LARCH_opts.ase_abi |= EF_LOONGARCH_ABI_ILP32;
231 LARCH_opts.ase_ilp32 = 1;
232 }
233 else
234 as_bad ("unknown default architecture `%s'", default_arch);
235 }
236
237 /* Set default ABI double-float. */
238 if (!EF_LOONGARCH_IS_SOFT_FLOAT(LARCH_opts.ase_abi)
239 && !EF_LOONGARCH_IS_SINGLE_FLOAT(LARCH_opts.ase_abi)
240 && !EF_LOONGARCH_IS_DOUBLE_FLOAT(LARCH_opts.ase_abi))
241 LARCH_opts.ase_abi |= EF_LOONGARCH_FLOAT_ABI_DOUBLE;
242
243 /* Set default ISA double-float. */
244 if (!LARCH_opts.ase_nf
245 && !LARCH_opts.ase_sf
246 && !LARCH_opts.ase_df)
247 {
248 LARCH_opts.ase_sf = 1;
249 LARCH_opts.ase_df = 1;
250 }
251
252 size_t i;
253
254 assert(LARCH_opts.ase_ilp32);
255
256 /* Init ilp32/lp64 registers names. */
257 if (!r_htab)
258 r_htab = str_htab_create (), str_hash_insert (r_htab, "", 0, 0);
259
260 for (i = 0; i < ARRAY_SIZE (loongarch_r_normal_name); i++)
261 str_hash_insert (r_htab, loongarch_r_normal_name[i], (void *) (i + 1), 0);
262
263 if (!cr_htab)
264 cr_htab = str_htab_create (), str_hash_insert (cr_htab, "", 0, 0);
265
266 for (i = 0; i < ARRAY_SIZE (loongarch_cr_normal_name); i++)
267 str_hash_insert (cr_htab, loongarch_cr_normal_name[i], (void *) (i + 1), 0);
268
269 /* Init single/double float registers names. */
270 if (LARCH_opts.ase_sf || LARCH_opts.ase_df)
271 {
272 if (!f_htab)
273 f_htab = str_htab_create (), str_hash_insert (f_htab, "", 0, 0);
274
275 for (i = 0; i < ARRAY_SIZE (loongarch_f_normal_name); i++)
276 str_hash_insert (f_htab, loongarch_f_normal_name[i], (void *) (i + 1),
277 0);
278
279 if (!c_htab)
280 c_htab = str_htab_create (), str_hash_insert (c_htab, "", 0, 0);
281
282 for (i = 0; i < ARRAY_SIZE (loongarch_c_normal_name); i++)
283 str_hash_insert (c_htab, loongarch_c_normal_name[i], (void *) (i + 1),
284 0);
285
286 }
287
288 /* Init lsx registers names. */
289 if (LARCH_opts.ase_lsx)
290 {
291 if (!v_htab)
292 v_htab = str_htab_create (), str_hash_insert (v_htab, "", 0, 0);
293 for (i = 0; i < ARRAY_SIZE (loongarch_v_normal_name); i++)
294 str_hash_insert (v_htab, loongarch_v_normal_name[i], (void *) (i + 1),
295 0);
296 }
297
298 /* Init lasx registers names. */
299 if (LARCH_opts.ase_lasx)
300 {
301 if (!x_htab)
302 x_htab = str_htab_create (), str_hash_insert (x_htab, "", 0, 0);
303 for (i = 0; i < ARRAY_SIZE (loongarch_x_normal_name); i++)
304 str_hash_insert (x_htab, loongarch_x_normal_name[i], (void *) (i + 1),
305 0);
306 }
307
308 /* Init lp64 registers alias. */
309 if (LARCH_opts.ase_lp64)
310 {
311 for (i = 0; i < ARRAY_SIZE (loongarch_r_lp64_name); i++)
312 str_hash_insert (r_htab, loongarch_r_lp64_name[i], (void *) (i + 1),
313 0);
314 for (i = 0; i < ARRAY_SIZE (loongarch_r_lp64_name1); i++)
315 str_hash_insert (r_htab, loongarch_r_lp64_name1[i], (void *) (i + 1),
316 0);
317 }
318
319 /* Init float-lp64 registers alias */
320 if ((LARCH_opts.ase_sf || LARCH_opts.ase_df) && LARCH_opts.ase_lp64)
321 {
322 for (i = 0; i < ARRAY_SIZE (loongarch_f_lp64_name); i++)
323 str_hash_insert (f_htab, loongarch_f_lp64_name[i],
324 (void *) (i + 1), 0);
325 for (i = 0; i < ARRAY_SIZE (loongarch_f_lp64_name1); i++)
326 str_hash_insert (f_htab, loongarch_f_lp64_name1[i],
327 (void *) (i + 1), 0);
328 }
329 }
330
331 const char *
332 loongarch_target_format ()
333 {
334 return LARCH_opts.ase_lp64 ? "elf64-loongarch" : "elf32-loongarch";
335 }
336
337 void
338 md_begin ()
339 {
340 const struct loongarch_opcode *it;
341 struct loongarch_ase *ase;
342 for (ase = loongarch_ASEs; ase->enabled; ase++)
343 for (it = ase->opcodes; it->name; it++)
344 {
345 if (loongarch_check_format (it->format) != 0)
346 as_fatal (_("insn name: %s\tformat: %s\tsyntax error"),
347 it->name, it->format);
348 if (it->mask == 0 && it->macro == 0)
349 as_fatal (_("insn name: %s\nformat: %s\nwe want macro but "
350 "macro is NULL"),
351 it->name, it->format);
352 if (it->macro
353 && loongarch_check_macro (it->format, it->macro) != 0)
354 as_fatal (_("insn name: %s\nformat: %s\nmacro: %s\tsyntax error"),
355 it->name, it->format, it->macro);
356 }
357
358 /* FIXME: expressionS use 'offsetT' as constant,
359 * we want this is 64-bit type. */
360 assert (8 <= sizeof (offsetT));
361 }
362
363 static const expressionS const_0 = { .X_op = O_constant, .X_add_number = 0 };
364
365 static const char *
366 my_getExpression (expressionS *ep, const char *str)
367 {
368 char *save_in, *ret;
369 save_in = input_line_pointer;
370 input_line_pointer = (char *) str;
371 expression (ep);
372 ret = input_line_pointer;
373 input_line_pointer = save_in;
374 return ret;
375 }
376
377 static void
378 s_loongarch_align (int arg)
379 {
380 const char *t = input_line_pointer;
381 while (!is_end_of_line[(unsigned char) *t] && *t != ',')
382 ++t;
383 if (*t == ',')
384 s_align_ptwo (arg);
385 else
386 s_align_ptwo (0);
387 }
388
389 /* Handle the .dtprelword and .dtpreldword pseudo-ops. They generate
390 a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for
391 use in DWARF debug information. */
392
393 static void
394 s_dtprel (int bytes)
395 {
396 expressionS ex;
397 char *p;
398
399 expression (&ex);
400
401 if (ex.X_op != O_symbol)
402 {
403 as_bad (_("Unsupported use of %s"),
404 (bytes == 8 ? ".dtpreldword" : ".dtprelword"));
405 ignore_rest_of_line ();
406 }
407
408 p = frag_more (bytes);
409 md_number_to_chars (p, 0, bytes);
410 fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE,
411 (bytes == 8
412 ? BFD_RELOC_LARCH_TLS_DTPREL64
413 : BFD_RELOC_LARCH_TLS_DTPREL32));
414
415 demand_empty_rest_of_line ();
416 }
417
418 static const pseudo_typeS loongarch_pseudo_table[] =
419 {
420 { "align", s_loongarch_align, -4 },
421 { "dword", cons, 8 },
422 { "word", cons, 4 },
423 { "half", cons, 2 },
424 { "dtprelword", s_dtprel, 4 },
425 { "dtpreldword", s_dtprel, 8 },
426 { NULL, NULL, 0 },
427 };
428
429 void
430 loongarch_pop_insert (void)
431 {
432 pop_insert (loongarch_pseudo_table);
433 }
434
435 #define INTERNAL_LABEL_SPECIAL 10
436 static unsigned long internal_label_count[INTERNAL_LABEL_SPECIAL] = { 0 };
437
438 static const char *
439 loongarch_internal_label_name (unsigned long label, int augend)
440 {
441 static char symbol_name_build[24];
442 unsigned long want_label;
443 char *p;
444
445 want_label = internal_label_count[label] + augend;
446
447 p = symbol_name_build;
448 #ifdef LOCAL_LABEL_PREFIX
449 *p++ = LOCAL_LABEL_PREFIX;
450 #endif
451 *p++ = 'L';
452 for (; label; label /= 10)
453 *p++ = label % 10 + '0';
454 /* Make sure internal label never belong to normal label namespace. */
455 *p++ = ':';
456 for (; want_label; want_label /= 10)
457 *p++ = want_label % 10 + '0';
458 *p++ = '\0';
459 return symbol_name_build;
460 }
461
462 static void
463 setup_internal_label_here (unsigned long label)
464 {
465 assert (label < INTERNAL_LABEL_SPECIAL);
466 internal_label_count[label]++;
467 colon (loongarch_internal_label_name (label, 0));
468 }
469
470 void
471 get_internal_label (expressionS *label_expr, unsigned long label,
472 int augend /* 0 for previous, 1 for next. */)
473 {
474 assert (label < INTERNAL_LABEL_SPECIAL);
475 if (augend == 0 && internal_label_count[label] == 0)
476 as_fatal (_("internal error: we have no internal label yet"));
477 label_expr->X_op = O_symbol;
478 label_expr->X_add_symbol =
479 symbol_find_or_make (loongarch_internal_label_name (label, augend));
480 label_expr->X_add_number = 0;
481 }
482
483 extern int loongarch_parse_expr (const char *expr,
484 struct reloc_info *reloc_stack_top,
485 size_t max_reloc_num, size_t *reloc_num,
486 offsetT *imm_if_no_reloc);
487
488 static int
489 is_internal_label (const char *c_str)
490 {
491 do
492 {
493 if (*c_str != ':')
494 break;
495 c_str++;
496 if (!('0' <= *c_str && *c_str <= '9'))
497 break;
498 while ('0' <= *c_str && *c_str <= '9')
499 c_str++;
500 if (*c_str != 'b' && *c_str != 'f')
501 break;
502 c_str++;
503 return *c_str == '\0';
504 }
505 while (0);
506 return 0;
507 }
508
509 static int
510 is_label (const char *c_str)
511 {
512 if (is_internal_label (c_str))
513 return 1;
514 else if ('0' <= *c_str && *c_str <= '9')
515 {
516 /* [0-9]+[bf] */
517 while ('0' <= *c_str && *c_str <= '9')
518 c_str++;
519 return *c_str == 'b' || *c_str == 'f';
520 }
521 else if (is_name_beginner (*c_str))
522 {
523 /* [a-zA-Z\._\$][0-9a-zA-Z\._\$]* */
524 c_str++;
525 while (is_part_of_name (*c_str))
526 c_str++;
527 return *c_str == '\0';
528 }
529 else
530 return 0;
531 }
532
533 static int
534 is_label_with_addend (const char *c_str)
535 {
536 if (is_internal_label (c_str))
537 return 1;
538 else if ('0' <= *c_str && *c_str <= '9')
539 {
540 /* [0-9]+[bf] */
541 while ('0' <= *c_str && *c_str <= '9')
542 c_str++;
543 if (*c_str == 'b' || *c_str == 'f')
544 c_str++;
545 else
546 return 0;
547 return *c_str == '\0'
548 || ((*c_str == '-' || *c_str == '+')
549 && is_unsigned (c_str + 1));
550 }
551 else if (is_name_beginner (*c_str))
552 {
553 /* [a-zA-Z\._\$][0-9a-zA-Z\._\$]* */
554 c_str++;
555 while (is_part_of_name (*c_str))
556 c_str++;
557 return *c_str == '\0'
558 || ((*c_str == '-' || *c_str == '+')
559 && is_unsigned (c_str + 1));
560 }
561 else
562 return 0;
563 }
564
565 static int32_t
566 loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2,
567 const char *bit_field,
568 const char *arg, void *context)
569 {
570 struct loongarch_cl_insn *ip = context;
571 offsetT imm, ret = 0;
572 size_t reloc_num_we_have = MAX_RELOC_NUMBER_A_INSN - ip->reloc_num;
573 size_t reloc_num = 0;
574
575 if (!ip->match_now)
576 return 0;
577
578 switch (esc_ch1)
579 {
580 case 'l':
581 switch (esc_ch2)
582 {
583 default:
584 ip->match_now = is_label (arg);
585 if (!ip->match_now && is_label_with_addend (arg))
586 as_fatal (_("This label shouldn't be with addend."));
587 break;
588 case 'a':
589 ip->match_now = is_label_with_addend (arg);
590 break;
591 }
592 break;
593 case 's':
594 case 'u':
595 ip->match_now =
596 loongarch_parse_expr (arg, ip->reloc_info + ip->reloc_num,
597 reloc_num_we_have, &reloc_num, &imm) == 0;
598
599 if (!ip->match_now)
600 break;
601
602 if (esc_ch1 == 's')
603 switch (esc_ch2)
604 {
605 case 'c':
606 ip->match_now = reloc_num == 0;
607 break;
608 }
609 else
610 switch (esc_ch2)
611 {
612 case 'c':
613 ip->match_now = reloc_num == 0 && 0 <= imm;
614 break;
615 }
616
617 if (!ip->match_now)
618 break;
619
620 ret = imm;
621 if (reloc_num)
622 {
623 bfd_reloc_code_real_type reloc_type = BFD_RELOC_NONE;
624 reloc_num_we_have -= reloc_num;
625 if (reloc_num_we_have == 0)
626 as_fatal (_("expr too huge") /* Want one more reloc. */);
627 if (esc_ch1 == 'u')
628 {
629 if (strncmp (bit_field, "10:12", strlen ("10:12")) == 0)
630 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_U_10_12;
631 }
632 else if (esc_ch1 == 's')
633 {
634 if (strncmp (bit_field, "10:16<<2", strlen ("10:16<<2")) == 0)
635 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2;
636 else if (strncmp (bit_field, "0:5|10:16<<2",
637 strlen ("0:5|10:16<<2")) == 0)
638 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2;
639 else if (strncmp (bit_field, "0:10|10:16<<2",
640 strlen ("0:10|10:16<<2")) == 0)
641 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2;
642 else if (strncmp (bit_field, "10:12", strlen ("10:12")) == 0)
643 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_12;
644 else if (strncmp (bit_field, "5:20", strlen ("5:20")) == 0)
645 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_5_20;
646 else if (strncmp (bit_field, "10:16", strlen ("10:16")) == 0)
647 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_16;
648 else if (strncmp (bit_field, "10:5", strlen ("10:5")) == 0)
649 reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_5;
650 }
651 if (reloc_type == BFD_RELOC_NONE)
652 as_fatal (
653 _("not support reloc bit-field\nfmt: %c%c %s\nargs: %s"),
654 esc_ch1, esc_ch2, bit_field, arg);
655 reloc_num++;
656 ip->reloc_num += reloc_num;
657 ip->reloc_info[ip->reloc_num - 1].type = reloc_type;
658 ip->reloc_info[ip->reloc_num - 1].value = const_0;
659 }
660 break;
661 case 'r':
662 imm = (intptr_t) str_hash_find (r_htab, arg);
663 ip->match_now = 0 < imm;
664 ret = imm - 1;
665 break;
666 case 'f':
667 imm = (intptr_t) str_hash_find (f_htab, arg);
668 ip->match_now = 0 < imm;
669 ret = imm - 1;
670 break;
671 case 'c':
672 switch (esc_ch2)
673 {
674 case 'r':
675 imm = (intptr_t) str_hash_find (cr_htab, arg);
676 break;
677 default:
678 imm = (intptr_t) str_hash_find (c_htab, arg);
679 }
680 ip->match_now = 0 < imm;
681 ret = imm - 1;
682 break;
683 case 'v':
684 imm = (intptr_t) str_hash_find (v_htab, arg);
685 ip->match_now = 0 < imm;
686 ret = imm - 1;
687 break;
688 case 'x':
689 imm = (intptr_t) str_hash_find (x_htab, arg);
690 ip->match_now = 0 < imm;
691 ret = imm - 1;
692 break;
693 case '\0':
694 ip->all_match = ip->match_now;
695 ip->insn_length =
696 ip->insn->mask ? loongarch_insn_length (ip->insn->match) : 0;
697 /* FIXME: now we have no relax insn. */
698 ip->relax_max_length = ip->insn_length;
699 break;
700 default:
701 as_fatal (_("unknown escape"));
702 }
703
704 do
705 {
706 /* Check imm overflow. */
707 int bit_width, bits_needed_s, bits_needed_u;
708 char *t;
709
710 if (!ip->match_now)
711 break;
712
713 if (0 < reloc_num)
714 break;
715
716 bit_width = loongarch_get_bit_field_width (bit_field, &t);
717
718 if (bit_width == -1)
719 /* No specify bit width. */
720 break;
721
722 imm = ret;
723 if (t[0] == '<' && t[1] == '<')
724 {
725 int i = strtol (t += 2, &t, 10), j;
726 for (j = i; 0 < j; j--, imm >>= 1)
727 if (imm & 1)
728 as_fatal (_("require imm low %d bit is 0."), i);
729 }
730
731 if (*t == '+')
732 imm -= strtol (t, &t, 10);
733
734 bits_needed_s = loongarch_bits_imm_needed (imm, 1);
735 bits_needed_u = loongarch_bits_imm_needed (imm, 0);
736
737 if ((esc_ch1 == 's' && bit_width < bits_needed_s)
738 || (esc_ch1 != 's' && bit_width < bits_needed_u))
739 /* How to do after we detect overflow. */
740 as_fatal (_("Immediate overflow.\n"
741 "format: %c%c%s\n"
742 "arg: %s"),
743 esc_ch1, esc_ch2, bit_field, arg);
744 }
745 while (0);
746
747 if (esc_ch1 != '\0')
748 {
749 ip->args[ip->arg_num] = ret;
750 ip->arg_num++;
751 }
752 return ret;
753 }
754
755 static void
756 get_loongarch_opcode (struct loongarch_cl_insn *insn)
757 {
758 const struct loongarch_opcode *it;
759 struct loongarch_ase *ase;
760 for (ase = loongarch_ASEs; ase->enabled; ase++)
761 {
762 if (!*ase->enabled || (ase->include && !*ase->include)
763 || (ase->exclude && *ase->exclude))
764 continue;
765
766 if (!ase->name_hash_entry)
767 {
768 ase->name_hash_entry = str_htab_create ();
769 for (it = ase->opcodes; it->name; it++)
770 str_hash_insert (ase->name_hash_entry, it->name, (void *) it, 0);
771 }
772
773 if ((it = str_hash_find (ase->name_hash_entry, insn->name)) == NULL)
774 continue;
775
776 do
777 {
778 insn->insn = it;
779 insn->match_now = 1;
780 insn->all_match = 0;
781 insn->arg_num = 0;
782 insn->reloc_num = 0;
783 insn->insn_bin = (loongarch_foreach_args
784 (it->format, insn->arg_strs,
785 loongarch_args_parser_can_match_arg_helper,
786 insn));
787 if (insn->all_match && !(it->include && !*it->include)
788 && !(it->exclude && *it->exclude))
789 {
790 insn->insn_bin |= it->match;
791 return;
792 }
793 it++;
794 }
795 while (it->name && strcasecmp (it->name, insn->name) == 0);
796 }
797 }
798
799 static int
800 check_this_insn_before_appending (struct loongarch_cl_insn *ip)
801 {
802 int ret = 0;
803 if (strcmp (ip->name, "la.abs") == 0)
804 {
805 ip->reloc_info[ip->reloc_num].type = BFD_RELOC_LARCH_MARK_LA;
806 my_getExpression (&ip->reloc_info[ip->reloc_num].value, ip->arg_strs[1]);
807 ip->reloc_num++;
808 }
809 else if (ip->insn->mask == 0xffff8000
810 /* amswap.w rd, rk, rj */
811 && ((ip->insn_bin & 0xfff00000) == 0x38600000
812 /* ammax_db.wu rd, rk, rj */
813 || (ip->insn_bin & 0xffff0000) == 0x38700000
814 /* ammin_db.wu rd, rk, rj */
815 || (ip->insn_bin & 0xffff0000) == 0x38710000))
816 {
817 /* For AMO insn amswap.[wd], amadd.[wd], etc. */
818 if (ip->args[0] != 0
819 && (ip->args[0] == ip->args[1] || ip->args[0] == ip->args[2]))
820 as_fatal (_("AMO insns require rd != base && rd != rt"
821 " when rd isn't $r0"));
822 }
823 else if ((ip->insn->mask == 0xffe08000
824 /* bstrins.w rd, rj, msbw, lsbw */
825 && (ip->insn_bin & 0xffe00000) == 0x00600000)
826 || (ip->insn->mask == 0xffc00000
827 /* bstrins.d rd, rj, msbd, lsbd */
828 && (ip->insn_bin & 0xff800000) == 0x00800000))
829 {
830 /* For bstr(ins|pick).[wd]. */
831 if (ip->args[2] < ip->args[3])
832 as_fatal (_("bstr(ins|pick).[wd] require msbd >= lsbd"));
833 }
834 else if (ip->insn->mask != 0 && (ip->insn_bin & 0xfe0003c0) == 0x04000000
835 /* csrxchg rd, rj, csr_num */
836 && (strcmp ("csrxchg", ip->name) == 0))
837 as_fatal (_("csrxchg require rj != $r0 && rj != $r1"));
838
839 return ret;
840 }
841
842 static void
843 install_insn (const struct loongarch_cl_insn *insn)
844 {
845 char *f = insn->frag->fr_literal + insn->where;
846 if (0 < insn->insn_length)
847 md_number_to_chars (f, insn->insn_bin, insn->insn_length);
848 }
849
850 static void
851 move_insn (struct loongarch_cl_insn *insn, fragS *frag, long where)
852 {
853 size_t i;
854 insn->frag = frag;
855 insn->where = where;
856 for (i = 0; i < insn->reloc_num; i++)
857 {
858 insn->fixp[i]->fx_frag = frag;
859 insn->fixp[i]->fx_where = where;
860 }
861 install_insn (insn);
862 }
863
864 /* Add INSN to the end of the output. */
865 static void
866 append_fixed_insn (struct loongarch_cl_insn *insn)
867 {
868 char *f = frag_more (insn->insn_length);
869 move_insn (insn, frag_now, f - frag_now->fr_literal);
870 }
871
872 static void
873 append_fixp_and_insn (struct loongarch_cl_insn *ip)
874 {
875 reloc_howto_type *howto;
876 bfd_reloc_code_real_type reloc_type;
877 struct reloc_info *reloc_info = ip->reloc_info;
878 size_t i;
879 for (i = 0; i < ip->reloc_num; i++)
880 {
881 reloc_type = reloc_info[i].type;
882 howto = bfd_reloc_type_lookup (stdoutput, reloc_type);
883 if (howto == NULL)
884 as_fatal (_("no HOWTO loong relocation number %d"), reloc_type);
885
886 ip->fixp[i] =
887 fix_new_exp (ip->frag, ip->where, bfd_get_reloc_size (howto),
888 &reloc_info[i].value, FALSE, reloc_type);
889 }
890
891 if (ip->insn_length < ip->relax_max_length)
892 as_fatal (_("Internal error: not support relax now"));
893 else
894 append_fixed_insn (ip);
895 dwarf2_emit_insn (0);
896 }
897
898 /* Ask helper for returning a malloced c_str or NULL. */
899 static char *
900 assember_macro_helper (const char *const args[], void *context_ptr)
901 {
902 struct loongarch_cl_insn *insn = context_ptr;
903 char *ret = NULL;
904 if ( strcmp (insn->name, "li.w") == 0 || strcmp (insn->name, "li.d") == 0)
905 {
906 char args_buf[50], insns_buf[200];
907 const char *arg_strs[6];
908 uint32_t hi32, lo32;
909
910 /* We pay attention to sign extend beacause it is chance of reduce insn.
911 The exception is 12-bit and hi-12-bit unsigned,
912 we need a 'ori' or a 'lu52i.d' accordingly. */
913 char all0_bit_vec, sign_bit_vec, allf_bit_vec, paritial_is_sext_of_prev;
914
915 lo32 = insn->args[1] & 0xffffffff;
916 hi32 = insn->args[1] >> 32;
917
918 if (strcmp (insn->name, "li.w") == 0)
919 {
920 if (hi32 != 0 && hi32 != 0xffffffff)
921 as_fatal (_("li overflow: hi32:0x%x lo32:0x%x"), hi32, lo32);
922 hi32 = lo32 & 0x80000000 ? 0xffffffff : 0;
923 }
924
925 if (strcmp (insn->name, "li.d") == 0 && !LARCH_opts.ase_lp64)
926 as_fatal (_("we can't li.d on 32bit-arch"));
927
928 snprintf (args_buf, sizeof (args_buf), "0x%x,0x%x,0x%x,0x%x,%s",
929 (hi32 >> 20) & 0xfff, hi32 & 0xfffff, (lo32 >> 12) & 0xfffff,
930 lo32 & 0xfff, args[0]);
931 loongarch_split_args_by_comma (args_buf, arg_strs);
932
933 all0_bit_vec =
934 ((((hi32 & 0xfff00000) == 0) << 3) | (((hi32 & 0x000fffff) == 0) << 2)
935 | (((lo32 & 0xfffff000) == 0) << 1) | ((lo32 & 0x00000fff) == 0));
936 sign_bit_vec =
937 ((((hi32 & 0x80000000) != 0) << 3) | (((hi32 & 0x00080000) != 0) << 2)
938 | (((lo32 & 0x80000000) != 0) << 1) | ((lo32 & 0x00000800) != 0));
939 allf_bit_vec =
940 ((((hi32 & 0xfff00000) == 0xfff00000) << 3)
941 | (((hi32 & 0x000fffff) == 0x000fffff) << 2)
942 | (((lo32 & 0xfffff000) == 0xfffff000) << 1)
943 | ((lo32 & 0x00000fff) == 0x00000fff));
944 paritial_is_sext_of_prev =
945 (all0_bit_vec ^ allf_bit_vec) & (all0_bit_vec ^ (sign_bit_vec << 1));
946
947 static const char *const li_32bit[] =
948 {
949 "lu12i.w %5,%3&0x80000?%3-0x100000:%3;ori %5,%5,%4;",
950 "lu12i.w %5,%3&0x80000?%3-0x100000:%3;",
951 "addi.w %5,$r0,%4&0x800?%4-0x1000:%4;",
952 "or %5,$r0,$r0;",
953 };
954 static const char *const li_hi_32bit[] =
955 {
956 "lu32i.d %5,%2&0x80000?%2-0x100000:%2;"
957 "lu52i.d %5,%5,%1&0x800?%1-0x1000:%1;",
958 "lu52i.d %5,%5,%1&0x800?%1-0x1000:%1;",
959 "lu32i.d %5,%2&0x80000?%2-0x100000:%2;",
960 "",
961 };
962 do
963 {
964 insns_buf[0] = '\0';
965 if (paritial_is_sext_of_prev == 0x7)
966 {
967 strcat (insns_buf, "lu52i.d %5,$r0,%1&0x800?%1-0x1000:%1;");
968 break;
969 }
970 if ((all0_bit_vec & 0x3) == 0x2)
971 strcat (insns_buf, "ori %5,$r0,%4;");
972 else
973 strcat (insns_buf, li_32bit[paritial_is_sext_of_prev & 0x3]);
974 strcat (insns_buf, li_hi_32bit[paritial_is_sext_of_prev >> 2]);
975 }
976 while (0);
977
978 ret = loongarch_expand_macro (insns_buf, arg_strs, NULL, NULL);
979 }
980 return ret;
981 }
982
983 /* Accept instructions separated by ';'
984 * assuming 'not starting with space and not ending with space' or pass in
985 * empty c_str. */
986 static void
987 loongarch_assemble_INSNs (char *str)
988 {
989 char *rest;
990
991 for (rest = str; *rest != ';' && *rest != '\0'; rest++);
992 if (*rest == ';')
993 *rest++ = '\0';
994
995 if (*str == ':')
996 {
997 str++;
998 setup_internal_label_here (strtol (str, &str, 10));
999 str++;
1000 }
1001
1002 do
1003 {
1004 if (*str == '\0')
1005 break;
1006
1007 struct loongarch_cl_insn the_one = { 0 };
1008 the_one.name = str;
1009
1010 for (; *str && *str != ' '; str++)
1011 ;
1012 if (*str == ' ')
1013 *str++ = '\0';
1014
1015 loongarch_split_args_by_comma (str, the_one.arg_strs);
1016 get_loongarch_opcode (&the_one);
1017
1018 if (!the_one.all_match)
1019 {
1020 char *ss = loongarch_cat_splited_strs (the_one.arg_strs);
1021 as_bad (_("no match insn: %s\t%s"), the_one.name, ss ? ss : "");
1022 free(ss);
1023 return;
1024 }
1025
1026 if (check_this_insn_before_appending (&the_one) != 0)
1027 break;
1028
1029 append_fixp_and_insn (&the_one);
1030 if (the_one.insn_length == 0 && the_one.insn->macro)
1031 {
1032 char *c_str = loongarch_expand_macro (the_one.insn->macro,
1033 the_one.arg_strs,
1034 assember_macro_helper,
1035 &the_one);
1036 loongarch_assemble_INSNs (c_str);
1037 free (c_str);
1038 }
1039 }
1040 while (0);
1041
1042 if (*rest != '\0')
1043 loongarch_assemble_INSNs (rest);
1044 }
1045
1046 void
1047 md_assemble (char *str)
1048 {
1049 loongarch_assemble_INSNs (str);
1050 }
1051
1052 const char *
1053 md_atof (int type, char *litP, int *sizeP)
1054 {
1055 return ieee_md_atof (type, litP, sizeP, FALSE);
1056 }
1057
1058 void
1059 md_number_to_chars (char *buf, valueT val, int n)
1060 {
1061 number_to_chars_littleendian (buf, val, n);
1062 }
1063
1064 /* The location from which a PC relative jump should be calculated,
1065 given a PC relative reloc. */
1066 long
1067 md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED)
1068 {
1069 return 0;
1070 }
1071
1072 static void fix_reloc_insn (fixS *fixP, bfd_vma reloc_val, char *buf)
1073 {
1074 reloc_howto_type *howto;
1075 insn_t insn;
1076 howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
1077
1078 insn = bfd_getl32 (buf);
1079
1080 if (!loongarch_adjust_reloc_bitsfield(howto, &reloc_val))
1081 as_warn_where (fixP->fx_file, fixP->fx_line, "Reloc overflow");
1082
1083 insn = (insn & (insn_t)howto->src_mask)
1084 | ((insn & (~(insn_t)howto->dst_mask)) | reloc_val);
1085
1086 bfd_putl32 (insn, buf);
1087 }
1088
1089 void
1090 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
1091 {
1092 static int64_t stack_top;
1093 static int last_reloc_is_sop_push_pcrel_1 = 0;
1094 int last_reloc_is_sop_push_pcrel = last_reloc_is_sop_push_pcrel_1;
1095 last_reloc_is_sop_push_pcrel_1 = 0;
1096
1097 char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
1098 switch (fixP->fx_r_type)
1099 {
1100 case BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL:
1101 case BFD_RELOC_LARCH_SOP_PUSH_TLS_GD:
1102 case BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT:
1103 case BFD_RELOC_LARCH_SOP_PUSH_PCREL:
1104 case BFD_RELOC_LARCH_SOP_PUSH_PLT_PCREL:
1105 if (fixP->fx_addsy == NULL)
1106 as_bad_where (fixP->fx_file, fixP->fx_line,
1107 _("Relocation against a constant"));
1108
1109 if (fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL
1110 || fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_GD
1111 || fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT)
1112 S_SET_THREAD_LOCAL (fixP->fx_addsy);
1113
1114 if (fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_PCREL)
1115 {
1116 last_reloc_is_sop_push_pcrel_1 = 1;
1117 if (S_GET_SEGMENT (fixP->fx_addsy) == seg)
1118 stack_top = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
1119 - (fixP->fx_where + fixP->fx_frag->fr_address));
1120 else
1121 stack_top = 0;
1122 }
1123 break;
1124
1125 case BFD_RELOC_LARCH_SOP_POP_32_S_10_5:
1126 case BFD_RELOC_LARCH_SOP_POP_32_S_10_12:
1127 case BFD_RELOC_LARCH_SOP_POP_32_U_10_12:
1128 case BFD_RELOC_LARCH_SOP_POP_32_S_10_16:
1129 case BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2:
1130 case BFD_RELOC_LARCH_SOP_POP_32_S_5_20:
1131 case BFD_RELOC_LARCH_SOP_POP_32_U:
1132 case BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2:
1133 case BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2:
1134 if (!last_reloc_is_sop_push_pcrel)
1135 break;
1136
1137 fix_reloc_insn (fixP, (bfd_vma)stack_top, buf);
1138 break;
1139
1140 case BFD_RELOC_64:
1141 case BFD_RELOC_32:
1142 if (fixP->fx_subsy)
1143 {
1144 case BFD_RELOC_24:
1145 case BFD_RELOC_16:
1146 case BFD_RELOC_8:
1147 fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
1148 fixP->fx_next->fx_addsy = fixP->fx_subsy;
1149 fixP->fx_next->fx_subsy = NULL;
1150 fixP->fx_next->fx_offset = 0;
1151 fixP->fx_subsy = NULL;
1152
1153 switch (fixP->fx_r_type)
1154 {
1155 case BFD_RELOC_64:
1156 fixP->fx_r_type = BFD_RELOC_LARCH_ADD64;
1157 fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB64;
1158 break;
1159 case BFD_RELOC_32:
1160 fixP->fx_r_type = BFD_RELOC_LARCH_ADD32;
1161 fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB32;
1162 break;
1163 case BFD_RELOC_24:
1164 fixP->fx_r_type = BFD_RELOC_LARCH_ADD24;
1165 fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB24;
1166 break;
1167 case BFD_RELOC_16:
1168 fixP->fx_r_type = BFD_RELOC_LARCH_ADD16;
1169 fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB16;
1170 break;
1171 case BFD_RELOC_8:
1172 fixP->fx_r_type = BFD_RELOC_LARCH_ADD8;
1173 fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB8;
1174 break;
1175 default:
1176 break;
1177 }
1178 md_number_to_chars (buf, 0, fixP->fx_size);
1179 if (fixP->fx_next->fx_addsy == NULL)
1180 fixP->fx_next->fx_done = 1;
1181 }
1182 if (fixP->fx_addsy == NULL)
1183 {
1184 fixP->fx_done = 1;
1185 md_number_to_chars (buf, *valP, fixP->fx_size);
1186 }
1187 break;
1188
1189 default:
1190 break;
1191 }
1192 }
1193
1194 int
1195 loongarch_relax_frag (asection *sec ATTRIBUTE_UNUSED,
1196 fragS *fragp ATTRIBUTE_UNUSED,
1197 long stretch ATTRIBUTE_UNUSED)
1198 {
1199 return 0;
1200 }
1201
1202 int
1203 md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
1204 asection *segtype ATTRIBUTE_UNUSED)
1205 {
1206 return 0;
1207 }
1208
1209 /* Translate internal representation of relocation info to BFD target
1210 format. */
1211 arelent *
1212 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
1213 {
1214 arelent *reloc = (arelent *) xmalloc (sizeof (arelent));
1215
1216 reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
1217 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1218 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1219 reloc->addend = fixp->fx_offset;
1220
1221 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
1222 if (reloc->howto == NULL)
1223 {
1224 as_bad_where (fixp->fx_file, fixp->fx_line,
1225 _("cannot represent %s relocation in object file"),
1226 bfd_get_reloc_code_name (fixp->fx_r_type));
1227 return NULL;
1228 }
1229
1230 return reloc;
1231 }
1232
1233 /* Convert a machine dependent frag. */
1234 void
1235 md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec ATTRIBUTE_UNUSED,
1236 fragS *fragp ATTRIBUTE_UNUSED)
1237 {
1238 /* fragp->fr_fix += 8; */
1239 }
1240
1241 /* Standard calling conventions leave the CFA at SP on entry. */
1242 void
1243 loongarch_cfi_frame_initial_instructions (void)
1244 {
1245 cfi_add_CFA_def_cfa_register (3 /* $sp */);
1246 }
1247
1248 int
1249 loongarch_dwarf2_addr_size (void)
1250 {
1251 return LARCH_opts.ase_lp64 ? 8 : 4;
1252 }
1253
1254 void
1255 tc_loongarch_parse_to_dw2regnum (expressionS *exp)
1256 {
1257 expression_and_evaluate (exp);
1258 }
1259
1260 void
1261 md_show_usage (FILE *stream)
1262 {
1263 fprintf (stream, _("LARCH options:\n"));
1264 /* FIXME */
1265 }
1266
1267 /* Fill in an rs_align_code fragment. We want to fill 'andi $r0,$r0,0'. */
1268 void
1269 loongarch_handle_align (fragS *fragp)
1270 {
1271 /* char nop_opcode; */
1272 char *p;
1273 int bytes, size, excess;
1274 valueT opcode;
1275
1276 if (fragp->fr_type != rs_align_code)
1277 return;
1278
1279 struct loongarch_cl_insn nop =
1280 { .name = "andi", .arg_strs = { "$r0", "$r0", "0", NULL } };
1281
1282 get_loongarch_opcode (&nop);
1283 gas_assert (nop.all_match);
1284
1285 p = fragp->fr_literal + fragp->fr_fix;
1286 opcode = nop.insn_bin;
1287 size = 4;
1288
1289 bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
1290 excess = bytes % size;
1291
1292 gas_assert (excess < 4);
1293 fragp->fr_fix += excess;
1294
1295 while (excess-- != 0)
1296 *p++ = 0;
1297
1298 md_number_to_chars (p, opcode, size);
1299 fragp->fr_var = size;
1300 }
1301
1302 void
1303 loongarch_elf_final_processing (void)
1304 {
1305 elf_elfheader (stdoutput)->e_flags |= LARCH_opts.ase_abi;
1306 }