1 /* tc-loongarch.c -- Assemble for the LoongArch ISA
3 Copyright (C) 2021-2022 Free Software Foundation, Inc.
4 Contributed by Loongson Ltd.
6 This file is part of GAS.
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.
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.
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/>. */
23 #include "dw2gencfi.h"
24 #include "loongarch-lex.h"
25 #include "elf/loongarch.h"
26 #include "opcode/loongarch.h"
28 #include "bfd/elfxx-loongarch.h"
34 /* All information about an instruction during assemble. */
35 struct loongarch_cl_insn
37 /* First split string. */
39 const char *arg_strs
[MAX_ARG_NUM_PLUS_2
];
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. */
50 const struct loongarch_opcode
*insn
;
53 offsetT args
[MAX_ARG_NUM_PLUS_2
];
54 struct reloc_info reloc_info
[MAX_RELOC_NUMBER_A_INSN
];
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
;
63 /* Then we get the binary representation of insn
64 and write it in to section. */
67 /* The frag that contains the instruction. */
69 /* The offset into FRAG of the first instruction byte. */
71 /* The relocs associated with the instruction, if any. */
72 fixS
*fixp
[MAX_RELOC_NUMBER_A_INSN
];
76 #define DEFAULT_ARCH "loongarch64"
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
[] = "#";
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
[] = "#";
92 /* This array holds machine specific line separator characters. */
93 const char line_separator_chars
[] = ";";
95 /* Chars that can be used to separate mant from exp in floating point nums. */
96 const char EXP_CHARS
[] = "eE";
98 /* Chars that mean this number is a floating point constant. */
100 /* or 0d1.2345e12. */
101 const char FLT_CHARS
[] = "rRsSfFdDxXpP";
103 const char *md_shortopts
= "O::g::G:";
105 static const char default_arch
[] = DEFAULT_ARCH
;
109 OPTION_IGNORE
= OPTION_MD_BASE
,
116 OPTION_LA_LOCAL_WITH_ABS
,
117 OPTION_LA_GLOBAL_WITH_PCREL
,
118 OPTION_LA_GLOBAL_WITH_ABS
,
123 struct option md_longopts
[] =
125 { "mabi", required_argument
, NULL
, OPTION_ABI
},
126 { "mfloat-abi", required_argument
, NULL
, OPTION_FLOAT_ABI
},
128 { "mfpu", required_argument
, NULL
, OPTION_FLOAT_ISA
},
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
},
134 { NULL
, no_argument
, NULL
, 0 }
137 size_t md_longopts_size
= sizeof (md_longopts
);
140 md_parse_option (int c
, const char *arg
)
146 if (strcasecmp (arg
, "lp64") == 0)
148 LARCH_opts
.ase_abi
|= EF_LOONGARCH_ABI_LP64
;
149 LARCH_opts
.ase_ilp32
= 1;
150 LARCH_opts
.ase_lp64
= 1;
152 else if (strcasecmp (arg
, "ilp32") == 0)
154 LARCH_opts
.ase_abi
|= EF_LOONGARCH_ABI_ILP32
;
155 LARCH_opts
.ase_ilp32
= 1;
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
;
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)
179 LARCH_opts
.ase_sf
= 1;
180 LARCH_opts
.ase_df
= 1;
186 case OPTION_LA_LOCAL_WITH_ABS
:
187 LARCH_opts
.ase_labs
= 1;
190 case OPTION_LA_GLOBAL_WITH_PCREL
:
191 LARCH_opts
.ase_gpcr
= 1;
194 case OPTION_LA_GLOBAL_WITH_ABS
:
195 LARCH_opts
.ase_gabs
= 1;
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
;
216 loongarch_after_parse_args ()
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
))
222 if (strcmp (default_arch
, "loongarch64") == 0)
224 LARCH_opts
.ase_abi
|= EF_LOONGARCH_ABI_LP64
;
225 LARCH_opts
.ase_ilp32
= 1;
226 LARCH_opts
.ase_lp64
= 1;
228 else if (strcmp (default_arch
, "loongarch32") == 0)
230 LARCH_opts
.ase_abi
|= EF_LOONGARCH_ABI_ILP32
;
231 LARCH_opts
.ase_ilp32
= 1;
234 as_bad ("unknown default architecture `%s'", default_arch
);
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
;
243 /* Set default ISA double-float. */
244 if (!LARCH_opts
.ase_nf
245 && !LARCH_opts
.ase_sf
246 && !LARCH_opts
.ase_df
)
248 LARCH_opts
.ase_sf
= 1;
249 LARCH_opts
.ase_df
= 1;
254 assert(LARCH_opts
.ase_ilp32
);
256 /* Init ilp32/lp64 registers names. */
258 r_htab
= str_htab_create (), str_hash_insert (r_htab
, "", 0, 0);
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);
264 cr_htab
= str_htab_create (), str_hash_insert (cr_htab
, "", 0, 0);
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);
269 /* Init single/double float registers names. */
270 if (LARCH_opts
.ase_sf
|| LARCH_opts
.ase_df
)
273 f_htab
= str_htab_create (), str_hash_insert (f_htab
, "", 0, 0);
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),
280 c_htab
= str_htab_create (), str_hash_insert (c_htab
, "", 0, 0);
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),
288 /* Init lsx registers names. */
289 if (LARCH_opts
.ase_lsx
)
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),
298 /* Init lasx registers names. */
299 if (LARCH_opts
.ase_lasx
)
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),
308 /* Init lp64 registers alias. */
309 if (LARCH_opts
.ase_lp64
)
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),
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),
319 /* Init float-lp64 registers alias */
320 if ((LARCH_opts
.ase_sf
|| LARCH_opts
.ase_df
) && LARCH_opts
.ase_lp64
)
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);
332 loongarch_target_format ()
334 return LARCH_opts
.ase_lp64
? "elf64-loongarch" : "elf32-loongarch";
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
++)
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 "
351 it
->name
, it
->format
);
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
);
358 /* FIXME: expressionS use 'offsetT' as constant,
359 * we want this is 64-bit type. */
360 assert (8 <= sizeof (offsetT
));
363 static const expressionS const_0
= { .X_op
= O_constant
, .X_add_number
= 0 };
366 my_getExpression (expressionS
*ep
, const char *str
)
369 save_in
= input_line_pointer
;
370 input_line_pointer
= (char *) str
;
372 ret
= input_line_pointer
;
373 input_line_pointer
= save_in
;
378 s_loongarch_align (int arg
)
380 const char *t
= input_line_pointer
;
381 while (!is_end_of_line
[(unsigned char) *t
] && *t
!= ',')
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. */
401 if (ex
.X_op
!= O_symbol
)
403 as_bad (_("Unsupported use of %s"),
404 (bytes
== 8 ? ".dtpreldword" : ".dtprelword"));
405 ignore_rest_of_line ();
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
,
412 ? BFD_RELOC_LARCH_TLS_DTPREL64
413 : BFD_RELOC_LARCH_TLS_DTPREL32
));
415 demand_empty_rest_of_line ();
418 static const pseudo_typeS loongarch_pseudo_table
[] =
420 { "align", s_loongarch_align
, -4 },
421 { "dword", cons
, 8 },
424 { "dtprelword", s_dtprel
, 4 },
425 { "dtpreldword", s_dtprel
, 8 },
430 loongarch_pop_insert (void)
432 pop_insert (loongarch_pseudo_table
);
435 #define INTERNAL_LABEL_SPECIAL 10
436 static unsigned long internal_label_count
[INTERNAL_LABEL_SPECIAL
] = { 0 };
439 loongarch_internal_label_name (unsigned long label
, int augend
)
441 static char symbol_name_build
[24];
442 unsigned long want_label
;
445 want_label
= internal_label_count
[label
] + augend
;
447 p
= symbol_name_build
;
448 #ifdef LOCAL_LABEL_PREFIX
449 *p
++ = LOCAL_LABEL_PREFIX
;
452 for (; label
; label
/= 10)
453 *p
++ = label
% 10 + '0';
454 /* Make sure internal label never belong to normal label namespace. */
456 for (; want_label
; want_label
/= 10)
457 *p
++ = want_label
% 10 + '0';
459 return symbol_name_build
;
463 setup_internal_label_here (unsigned long label
)
465 assert (label
< INTERNAL_LABEL_SPECIAL
);
466 internal_label_count
[label
]++;
467 colon (loongarch_internal_label_name (label
, 0));
471 get_internal_label (expressionS
*label_expr
, unsigned long label
,
472 int augend
/* 0 for previous, 1 for next. */)
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;
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
);
489 is_internal_label (const char *c_str
)
496 if (!('0' <= *c_str
&& *c_str
<= '9'))
498 while ('0' <= *c_str
&& *c_str
<= '9')
500 if (*c_str
!= 'b' && *c_str
!= 'f')
503 return *c_str
== '\0';
510 is_label (const char *c_str
)
512 if (is_internal_label (c_str
))
514 else if ('0' <= *c_str
&& *c_str
<= '9')
517 while ('0' <= *c_str
&& *c_str
<= '9')
519 return *c_str
== 'b' || *c_str
== 'f';
521 else if (is_name_beginner (*c_str
))
523 /* [a-zA-Z\._\$][0-9a-zA-Z\._\$]* */
525 while (is_part_of_name (*c_str
))
527 return *c_str
== '\0';
534 is_label_with_addend (const char *c_str
)
536 if (is_internal_label (c_str
))
538 else if ('0' <= *c_str
&& *c_str
<= '9')
541 while ('0' <= *c_str
&& *c_str
<= '9')
543 if (*c_str
== 'b' || *c_str
== 'f')
547 return *c_str
== '\0'
548 || ((*c_str
== '-' || *c_str
== '+')
549 && is_unsigned (c_str
+ 1));
551 else if (is_name_beginner (*c_str
))
553 /* [a-zA-Z\._\$][0-9a-zA-Z\._\$]* */
555 while (is_part_of_name (*c_str
))
557 return *c_str
== '\0'
558 || ((*c_str
== '-' || *c_str
== '+')
559 && is_unsigned (c_str
+ 1));
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
)
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;
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."));
589 ip
->match_now
= is_label_with_addend (arg
);
596 loongarch_parse_expr (arg
, ip
->reloc_info
+ ip
->reloc_num
,
597 reloc_num_we_have
, &reloc_num
, &imm
) == 0;
606 ip
->match_now
= reloc_num
== 0;
613 ip
->match_now
= reloc_num
== 0 && 0 <= imm
;
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. */);
629 if (strncmp (bit_field
, "10:12", strlen ("10:12")) == 0)
630 reloc_type
= BFD_RELOC_LARCH_SOP_POP_32_U_10_12
;
632 else if (esc_ch1
== 's')
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
;
651 if (reloc_type
== BFD_RELOC_NONE
)
653 _("not support reloc bit-field\nfmt: %c%c %s\nargs: %s"),
654 esc_ch1
, esc_ch2
, bit_field
, arg
);
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
;
662 imm
= (intptr_t) str_hash_find (r_htab
, arg
);
663 ip
->match_now
= 0 < imm
;
667 imm
= (intptr_t) str_hash_find (f_htab
, arg
);
668 ip
->match_now
= 0 < imm
;
675 imm
= (intptr_t) str_hash_find (cr_htab
, arg
);
678 imm
= (intptr_t) str_hash_find (c_htab
, arg
);
680 ip
->match_now
= 0 < imm
;
684 imm
= (intptr_t) str_hash_find (v_htab
, arg
);
685 ip
->match_now
= 0 < imm
;
689 imm
= (intptr_t) str_hash_find (x_htab
, arg
);
690 ip
->match_now
= 0 < imm
;
694 ip
->all_match
= ip
->match_now
;
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
;
701 as_fatal (_("unknown escape"));
706 /* Check imm overflow. */
707 int bit_width
, bits_needed_s
, bits_needed_u
;
716 bit_width
= loongarch_get_bit_field_width (bit_field
, &t
);
719 /* No specify bit width. */
723 if (t
[0] == '<' && t
[1] == '<')
725 int i
= strtol (t
+= 2, &t
, 10), j
;
726 for (j
= i
; 0 < j
; j
--, imm
>>= 1)
728 as_fatal (_("require imm low %d bit is 0."), i
);
732 imm
-= strtol (t
, &t
, 10);
734 bits_needed_s
= loongarch_bits_imm_needed (imm
, 1);
735 bits_needed_u
= loongarch_bits_imm_needed (imm
, 0);
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"
743 esc_ch1
, esc_ch2
, bit_field
, arg
);
749 ip
->args
[ip
->arg_num
] = ret
;
756 get_loongarch_opcode (struct loongarch_cl_insn
*insn
)
758 const struct loongarch_opcode
*it
;
759 struct loongarch_ase
*ase
;
760 for (ase
= loongarch_ASEs
; ase
->enabled
; ase
++)
762 if (!*ase
->enabled
|| (ase
->include
&& !*ase
->include
)
763 || (ase
->exclude
&& *ase
->exclude
))
766 if (!ase
->name_hash_entry
)
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);
773 if ((it
= str_hash_find (ase
->name_hash_entry
, insn
->name
)) == NULL
)
783 insn
->insn_bin
= (loongarch_foreach_args
784 (it
->format
, insn
->arg_strs
,
785 loongarch_args_parser_can_match_arg_helper
,
787 if (insn
->all_match
&& !(it
->include
&& !*it
->include
)
788 && !(it
->exclude
&& *it
->exclude
))
790 insn
->insn_bin
|= it
->match
;
795 while (it
->name
&& strcasecmp (it
->name
, insn
->name
) == 0);
800 check_this_insn_before_appending (struct loongarch_cl_insn
*ip
)
803 if (strcmp (ip
->name
, "la.abs") == 0)
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]);
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))
817 /* For AMO insn amswap.[wd], amadd.[wd], etc. */
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"));
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))
830 /* For bstr(ins|pick).[wd]. */
831 if (ip
->args
[2] < ip
->args
[3])
832 as_fatal (_("bstr(ins|pick).[wd] require msbd >= lsbd"));
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"));
843 install_insn (const struct loongarch_cl_insn
*insn
)
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
);
851 move_insn (struct loongarch_cl_insn
*insn
, fragS
*frag
, long where
)
856 for (i
= 0; i
< insn
->reloc_num
; i
++)
858 insn
->fixp
[i
]->fx_frag
= frag
;
859 insn
->fixp
[i
]->fx_where
= where
;
864 /* Add INSN to the end of the output. */
866 append_fixed_insn (struct loongarch_cl_insn
*insn
)
868 char *f
= frag_more (insn
->insn_length
);
869 move_insn (insn
, frag_now
, f
- frag_now
->fr_literal
);
873 append_fixp_and_insn (struct loongarch_cl_insn
*ip
)
875 reloc_howto_type
*howto
;
876 bfd_reloc_code_real_type reloc_type
;
877 struct reloc_info
*reloc_info
= ip
->reloc_info
;
879 for (i
= 0; i
< ip
->reloc_num
; i
++)
881 reloc_type
= reloc_info
[i
].type
;
882 howto
= bfd_reloc_type_lookup (stdoutput
, reloc_type
);
884 as_fatal (_("no HOWTO loong relocation number %d"), reloc_type
);
887 fix_new_exp (ip
->frag
, ip
->where
, bfd_get_reloc_size (howto
),
888 &reloc_info
[i
].value
, FALSE
, reloc_type
);
891 if (ip
->insn_length
< ip
->relax_max_length
)
892 as_fatal (_("Internal error: not support relax now"));
894 append_fixed_insn (ip
);
895 dwarf2_emit_insn (0);
898 /* Ask helper for returning a malloced c_str or NULL. */
900 assember_macro_helper (const char *const args
[], void *context_ptr
)
902 struct loongarch_cl_insn
*insn
= context_ptr
;
904 if ( strcmp (insn
->name
, "li.w") == 0 || strcmp (insn
->name
, "li.d") == 0)
906 char args_buf
[50], insns_buf
[200];
907 const char *arg_strs
[6];
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
;
915 lo32
= insn
->args
[1] & 0xffffffff;
916 hi32
= insn
->args
[1] >> 32;
918 if (strcmp (insn
->name
, "li.w") == 0)
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;
925 if (strcmp (insn
->name
, "li.d") == 0 && !LARCH_opts
.ase_lp64
)
926 as_fatal (_("we can't li.d on 32bit-arch"));
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
);
934 ((((hi32
& 0xfff00000) == 0) << 3) | (((hi32
& 0x000fffff) == 0) << 2)
935 | (((lo32
& 0xfffff000) == 0) << 1) | ((lo32
& 0x00000fff) == 0));
937 ((((hi32
& 0x80000000) != 0) << 3) | (((hi32
& 0x00080000) != 0) << 2)
938 | (((lo32
& 0x80000000) != 0) << 1) | ((lo32
& 0x00000800) != 0));
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));
947 static const char *const li_32bit
[] =
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;",
954 static const char *const li_hi_32bit
[] =
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;",
965 if (paritial_is_sext_of_prev
== 0x7)
967 strcat (insns_buf
, "lu52i.d %5,$r0,%1&0x800?%1-0x1000:%1;");
970 if ((all0_bit_vec
& 0x3) == 0x2)
971 strcat (insns_buf
, "ori %5,$r0,%4;");
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]);
978 ret
= loongarch_expand_macro (insns_buf
, arg_strs
, NULL
, NULL
);
983 /* Accept instructions separated by ';'
984 * assuming 'not starting with space and not ending with space' or pass in
987 loongarch_assemble_INSNs (char *str
)
991 for (rest
= str
; *rest
!= ';' && *rest
!= '\0'; rest
++);
998 setup_internal_label_here (strtol (str
, &str
, 10));
1007 struct loongarch_cl_insn the_one
= { 0 };
1010 for (; *str
&& *str
!= ' '; str
++)
1015 loongarch_split_args_by_comma (str
, the_one
.arg_strs
);
1016 get_loongarch_opcode (&the_one
);
1018 if (!the_one
.all_match
)
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
: "");
1026 if (check_this_insn_before_appending (&the_one
) != 0)
1029 append_fixp_and_insn (&the_one
);
1030 if (the_one
.insn_length
== 0 && the_one
.insn
->macro
)
1032 char *c_str
= loongarch_expand_macro (the_one
.insn
->macro
,
1034 assember_macro_helper
,
1036 loongarch_assemble_INSNs (c_str
);
1043 loongarch_assemble_INSNs (rest
);
1047 md_assemble (char *str
)
1049 loongarch_assemble_INSNs (str
);
1053 md_atof (int type
, char *litP
, int *sizeP
)
1055 return ieee_md_atof (type
, litP
, sizeP
, FALSE
);
1059 md_number_to_chars (char *buf
, valueT val
, int n
)
1061 number_to_chars_littleendian (buf
, val
, n
);
1064 /* The location from which a PC relative jump should be calculated,
1065 given a PC relative reloc. */
1067 md_pcrel_from (fixS
*fixP ATTRIBUTE_UNUSED
)
1072 static void fix_reloc_insn (fixS
*fixP
, bfd_vma reloc_val
, char *buf
)
1074 reloc_howto_type
*howto
;
1076 howto
= bfd_reloc_type_lookup (stdoutput
, fixP
->fx_r_type
);
1078 insn
= bfd_getl32 (buf
);
1080 if (!loongarch_adjust_reloc_bitsfield(howto
, &reloc_val
))
1081 as_warn_where (fixP
->fx_file
, fixP
->fx_line
, "Reloc overflow");
1083 insn
= (insn
& (insn_t
)howto
->src_mask
)
1084 | ((insn
& (~(insn_t
)howto
->dst_mask
)) | reloc_val
);
1086 bfd_putl32 (insn
, buf
);
1090 md_apply_fix (fixS
*fixP
, valueT
*valP
, segT seg ATTRIBUTE_UNUSED
)
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;
1097 char *buf
= fixP
->fx_frag
->fr_literal
+ fixP
->fx_where
;
1098 switch (fixP
->fx_r_type
)
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"));
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
);
1114 if (fixP
->fx_r_type
== BFD_RELOC_LARCH_SOP_PUSH_PCREL
)
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
));
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
)
1137 fix_reloc_insn (fixP
, (bfd_vma
)stack_top
, buf
);
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
;
1153 switch (fixP
->fx_r_type
)
1156 fixP
->fx_r_type
= BFD_RELOC_LARCH_ADD64
;
1157 fixP
->fx_next
->fx_r_type
= BFD_RELOC_LARCH_SUB64
;
1160 fixP
->fx_r_type
= BFD_RELOC_LARCH_ADD32
;
1161 fixP
->fx_next
->fx_r_type
= BFD_RELOC_LARCH_SUB32
;
1164 fixP
->fx_r_type
= BFD_RELOC_LARCH_ADD24
;
1165 fixP
->fx_next
->fx_r_type
= BFD_RELOC_LARCH_SUB24
;
1168 fixP
->fx_r_type
= BFD_RELOC_LARCH_ADD16
;
1169 fixP
->fx_next
->fx_r_type
= BFD_RELOC_LARCH_SUB16
;
1172 fixP
->fx_r_type
= BFD_RELOC_LARCH_ADD8
;
1173 fixP
->fx_next
->fx_r_type
= BFD_RELOC_LARCH_SUB8
;
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;
1182 if (fixP
->fx_addsy
== NULL
)
1185 md_number_to_chars (buf
, *valP
, fixP
->fx_size
);
1195 loongarch_relax_frag (asection
*sec ATTRIBUTE_UNUSED
,
1196 fragS
*fragp ATTRIBUTE_UNUSED
,
1197 long stretch ATTRIBUTE_UNUSED
)
1203 md_estimate_size_before_relax (fragS
*fragp ATTRIBUTE_UNUSED
,
1204 asection
*segtype ATTRIBUTE_UNUSED
)
1209 /* Translate internal representation of relocation info to BFD target
1212 tc_gen_reloc (asection
*section ATTRIBUTE_UNUSED
, fixS
*fixp
)
1214 arelent
*reloc
= (arelent
*) xmalloc (sizeof (arelent
));
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
;
1221 reloc
->howto
= bfd_reloc_type_lookup (stdoutput
, fixp
->fx_r_type
);
1222 if (reloc
->howto
== NULL
)
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
));
1233 /* Convert a machine dependent frag. */
1235 md_convert_frag (bfd
*abfd ATTRIBUTE_UNUSED
, segT asec ATTRIBUTE_UNUSED
,
1236 fragS
*fragp ATTRIBUTE_UNUSED
)
1238 /* fragp->fr_fix += 8; */
1241 /* Standard calling conventions leave the CFA at SP on entry. */
1243 loongarch_cfi_frame_initial_instructions (void)
1245 cfi_add_CFA_def_cfa_register (3 /* $sp */);
1249 loongarch_dwarf2_addr_size (void)
1251 return LARCH_opts
.ase_lp64
? 8 : 4;
1255 tc_loongarch_parse_to_dw2regnum (expressionS
*exp
)
1257 expression_and_evaluate (exp
);
1261 md_show_usage (FILE *stream
)
1263 fprintf (stream
, _("LARCH options:\n"));
1267 /* Fill in an rs_align_code fragment. We want to fill 'andi $r0,$r0,0'. */
1269 loongarch_handle_align (fragS
*fragp
)
1271 /* char nop_opcode; */
1273 int bytes
, size
, excess
;
1276 if (fragp
->fr_type
!= rs_align_code
)
1279 struct loongarch_cl_insn nop
=
1280 { .name
= "andi", .arg_strs
= { "$r0", "$r0", "0", NULL
} };
1282 get_loongarch_opcode (&nop
);
1283 gas_assert (nop
.all_match
);
1285 p
= fragp
->fr_literal
+ fragp
->fr_fix
;
1286 opcode
= nop
.insn_bin
;
1289 bytes
= fragp
->fr_next
->fr_address
- fragp
->fr_address
- fragp
->fr_fix
;
1290 excess
= bytes
% size
;
1292 gas_assert (excess
< 4);
1293 fragp
->fr_fix
+= excess
;
1295 while (excess
-- != 0)
1298 md_number_to_chars (p
, opcode
, size
);
1299 fragp
->fr_var
= size
;
1303 loongarch_elf_final_processing (void)
1305 elf_elfheader (stdoutput
)->e_flags
|= LARCH_opts
.ase_abi
;