/* Table of relaxations for Xtensa assembly.
- Copyright (C) 2003-2017 Free Software Foundation, Inc.
+ Copyright (C) 2003-2021 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
when the first and second operands are not the same as specified
by the "| %at!=%as" precondition clause.
{"l32i %at,%as,%imm | %at!=%as",
- "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l32i %at,%at,0"}
-
- There is special case for loop instructions here, but because we do
- not currently have the ability to represent the difference of two
- symbols, the conversion requires special code in the assembler to
- write the operands of the addi/addmi pair representing the
- difference of the old and new loop end label. */
+ "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l32i %at,%at,0"} */
#include "as.h"
#include "xtensa-isa.h"
{"l32i %at,%as,%imm | %at!=%as ? IsaUseConst16",
"const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l32i %at,%at,0"},
- /* This is only PART of the loop instruction. In addition,
- hardcoded into its use is a modification of the final operand in
- the instruction in bytes 9 and 12. */
- {"loop %as,%label | %as!=1 ? IsaUseLoops",
+ /* Widening loops with literals. */
+ {"loop %as,%label | %as!=1 ? IsaUseLoops ? IsaUseL32R",
"loop %as,%LABEL;"
"rsr.lend %as;" /* LEND */
"wsr.lbeg %as;" /* LBEG */
- "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */
- "addmi %as, %as, 0;" /* mid8(%label-%LABEL1) */
+ "LITERAL %label;"
+ "l32r %as, %LITERAL;"
+ "nop;"
"wsr.lend %as;"
"isync;"
"rsr.lcount %as;" /* LCOUNT */
- "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */
+ "addi %as, %as, 1;"
"LABEL"},
- {"loopgtz %as,%label | %as!=1 ? IsaUseLoops",
+ {"loopgtz %as,%label | %as!=1 ? IsaUseLoops ? IsaUseL32R",
"beqz %as,%label;"
"bltz %as,%label;"
"loopgtz %as,%LABEL;"
"rsr.lend %as;" /* LEND */
"wsr.lbeg %as;" /* LBEG */
- "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */
- "addmi %as, %as, 0;" /* mid8(%label-%LABEL1) */
+ "LITERAL %label;"
+ "l32r %as, %LITERAL;"
+ "nop;"
"wsr.lend %as;"
"isync;"
"rsr.lcount %as;" /* LCOUNT */
- "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */
+ "addi %as, %as, 1;"
"LABEL"},
- {"loopnez %as,%label | %as!=1 ? IsaUseLoops",
+ {"loopnez %as,%label | %as!=1 ? IsaUseLoops ? IsaUseL32R",
"beqz %as,%label;"
"loopnez %as,%LABEL;"
"rsr.lend %as;" /* LEND */
"wsr.lbeg %as;" /* LBEG */
- "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */
- "addmi %as, %as, 0;" /* mid8(%label-%LABEL1) */
+ "LITERAL %label;"
+ "l32r %as, %LITERAL;"
+ "nop;"
"wsr.lend %as;"
"isync;"
"rsr.lcount %as;" /* LCOUNT */
- "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */
+ "addi %as, %as, 1;"
+ "LABEL"},
+
+ /* Widening loops with const16. */
+ {"loop %as,%label | %as!=1 ? IsaUseLoops ? IsaUseConst16",
+ "loop %as,%LABEL;"
+ "rsr.lend %as;" /* LEND */
+ "wsr.lbeg %as;" /* LBEG */
+ "const16 %as,HI16U(%label);"
+ "const16 %as,LOW16U(%label);"
+ "wsr.lend %as;"
+ "isync;"
+ "rsr.lcount %as;" /* LCOUNT */
+ "addi %as, %as, 1;"
+ "LABEL"},
+ {"loopgtz %as,%label | %as!=1 ? IsaUseLoops ? IsaUseConst16",
+ "beqz %as,%label;"
+ "bltz %as,%label;"
+ "loopgtz %as,%LABEL;"
+ "rsr.lend %as;" /* LEND */
+ "wsr.lbeg %as;" /* LBEG */
+ "const16 %as,HI16U(%label);"
+ "const16 %as,LOW16U(%label);"
+ "wsr.lend %as;"
+ "isync;"
+ "rsr.lcount %as;" /* LCOUNT */
+ "addi %as, %as, 1;"
+ "LABEL"},
+ {"loopnez %as,%label | %as!=1 ? IsaUseLoops ? IsaUseConst16",
+ "beqz %as,%label;"
+ "loopnez %as,%LABEL;"
+ "rsr.lend %as;" /* LEND */
+ "wsr.lbeg %as;" /* LBEG */
+ "const16 %as,HI16U(%label);"
+ "const16 %as,LOW16U(%label);"
+ "wsr.lend %as;"
+ "isync;"
+ "rsr.lcount %as;" /* LCOUNT */
+ "addi %as, %as, 1;"
"LABEL"},
/* Relaxing to wide branches. Order is important here. With wide
\f
/* Externally visible functions. */
-extern bfd_boolean xg_has_userdef_op_fn (OpType);
+extern bool xg_has_userdef_op_fn (OpType);
extern long xg_apply_userdef_op_fn (OpType, long);
}
-bfd_boolean
+bool
xg_has_userdef_op_fn (OpType op)
{
switch (op)
case OP_OPERAND_HI24S:
case OP_OPERAND_LOW16U:
case OP_OPERAND_HI16U:
- return TRUE;
+ return true;
default:
break;
}
- return FALSE;
+ return false;
}
default:
break;
}
- return FALSE;
+ return false;
}
}
-static bfd_boolean
+static bool
same_operand_name (const opname_map_e *m1, const opname_map_e *m2)
{
if (m1->operand_name == NULL || m2->operand_name == NULL)
- return FALSE;
+ return false;
return (m1->operand_name == m2->operand_name);
}
}
-static bfd_boolean
+static bool
op_is_constant (const opname_map_e *m1)
{
return (m1->operand_name == NULL);
/* Convert a string to a number. E.G.: parse_constant("10", &num) */
-static bfd_boolean
+static bool
parse_constant (const char *in, unsigned *val_p)
{
unsigned val = 0;
const char *p;
if (in == NULL)
- return FALSE;
+ return false;
p = in;
while (*p != '\0')
if (*p >= '0' && *p <= '9')
val = val * 10 + (*p - '0');
else
- return FALSE;
+ return false;
++p;
}
*val_p = val;
- return TRUE;
+ return true;
}
-static bfd_boolean
+static bool
parse_special_fn (const char *name,
const char **fn_name_p,
const char **arg_name_p)
p_start = strchr (name, '(');
if (p_start == NULL)
- return FALSE;
+ return false;
p_end = strchr (p_start, ')');
if (p_end == NULL)
- return FALSE;
+ return false;
if (p_end[1] != '\0')
- return FALSE;
+ return false;
*fn_name_p = enter_opname_n (name, p_start - name);
*arg_name_p = enter_opname_n (p_start + 1, p_end - p_start - 1);
- return TRUE;
+ return true;
}
split_string (split_rec *rec,
const char *in,
char c,
- bfd_boolean elide_whitespace)
+ bool elide_whitespace)
{
int cnt = 0;
int i;
/* Parse an instruction template like "insn op1, op2, op3". */
-static bfd_boolean
+static bool
parse_insn_templ (const char *s, insn_templ *t)
{
const char *p = s;
p = skip_white (p);
insn_name_len = strcspn (s, " ");
if (insn_name_len == 0)
- return FALSE;
+ return false;
init_insn_templ (t);
t->opcode_name = enter_opname_n (p, insn_name_len);
p = p + insn_name_len;
/* Split by ',' and skip beginning and trailing whitespace. */
- split_string (&oprec, p, ',', TRUE);
+ split_string (&oprec, p, ',', true);
for (i = 0; i < oprec.count; i++)
{
free (e);
clear_split_rec (&oprec);
clear_insn_templ (t);
- return FALSE;
+ return false;
}
}
else
t->operand_map.tail = &e->next;
}
clear_split_rec (&oprec);
- return TRUE;
+ return true;
}
-static bfd_boolean
+static bool
parse_precond (const char *s, precond_e *precond)
{
/* All preconditions are currently of the form:
len = strcspn (p, " !=");
if (len == 0)
- return FALSE;
+ return false;
precond->opname1 = enter_opname_n (p, len);
p = p + len;
p = skip_white (p);
/* Check for "==" and "!=". */
- if (strncmp (p, "==", 2) == 0)
+ if (startswith (p, "=="))
precond->cmpop = OP_EQUAL;
- else if (strncmp (p, "!=", 2) == 0)
+ else if (startswith (p, "!="))
precond->cmpop = OP_NOTEQUAL;
else
- return FALSE;
+ return false;
p = p + 2;
p = skip_white (p);
if (parse_constant (p, &val))
precond->opval2 = val;
else
- return FALSE;
+ return false;
}
else
precond->opname2 = enter_opname (p);
- return TRUE;
+ return true;
}
}
-static bfd_boolean
+static bool
parse_option_cond (const char *s, ReqOption *option)
{
int i;
"Ands" are divided by "?". */
init_split_rec (&option_term_rec);
- split_string (&option_term_rec, s, '+', TRUE);
+ split_string (&option_term_rec, s, '+', true);
if (option_term_rec.count == 0)
{
clear_split_rec (&option_term_rec);
- return FALSE;
+ return false;
}
for (i = 0; i < option_term_rec.count; i++)
{
char *option_name = option_term_rec.vec[i];
- bfd_boolean is_true = TRUE;
+ bool is_true = true;
ReqOrOption *req;
ReqOrOption **r_p;
- if (strncmp (option_name, "no-", 3) == 0)
+ if (startswith (option_name, "no-"))
{
option_name = xstrdup (&option_name[3]);
- is_true = FALSE;
+ is_true = false;
}
else
option_name = xstrdup (option_name);
;
(*r_p) = req;
}
- return TRUE;
+ return true;
}
split_string, it requires that '|' and '?' are only used as
delimiters for predicates and required options. */
-static bfd_boolean
+static bool
parse_insn_pattern (const char *in, insn_pattern *insn)
{
split_rec rec;
init_insn_pattern (insn);
init_split_rec (&optionrec);
- split_string (&optionrec, in, '?', TRUE);
+ split_string (&optionrec, in, '?', true);
if (optionrec.count == 0)
{
clear_split_rec (&optionrec);
- return FALSE;
+ return false;
}
init_split_rec (&rec);
- split_string (&rec, optionrec.vec[0], '|', TRUE);
+ split_string (&rec, optionrec.vec[0], '|', true);
if (rec.count == 0)
{
clear_split_rec (&rec);
clear_split_rec (&optionrec);
- return FALSE;
+ return false;
}
if (!parse_insn_templ (rec.vec[0], &insn->t))
{
clear_split_rec (&rec);
clear_split_rec (&optionrec);
- return FALSE;
+ return false;
}
for (i = 1; i < rec.count; i++)
clear_split_rec (&rec);
clear_split_rec (&optionrec);
clear_insn_pattern (insn);
- return FALSE;
+ return false;
}
/* Append the condition. */
clear_split_rec (&optionrec);
clear_insn_pattern (insn);
clear_req_option_list (&req_option);
- return FALSE;
+ return false;
}
/* Append the condition. */
clear_split_rec (&rec);
clear_split_rec (&optionrec);
- return TRUE;
+ return true;
}
-static bfd_boolean
+static bool
parse_insn_repl (const char *in, insn_repl *r_p)
{
/* This is a list of instruction templates separated by ';'. */
split_rec rec;
int i;
- split_string (&rec, in, ';', TRUE);
+ split_string (&rec, in, ';', true);
for (i = 0; i < rec.count; i++)
{
{
free (e);
clear_insn_repl (r_p);
- return FALSE;
+ return false;
}
*r_p->tail = e;
r_p->tail = &e->next;
}
- return TRUE;
+ return true;
}
-static bfd_boolean
+static bool
transition_applies (insn_pattern *initial_insn,
const char *from_string ATTRIBUTE_UNUSED,
const char *to_string ATTRIBUTE_UNUSED)
|| req_or_option->next != NULL)
continue;
- if (strncmp (req_or_option->option_name, "IsaUse", 6) == 0)
+ if (startswith (req_or_option->option_name, "IsaUse"))
{
- bfd_boolean option_available = FALSE;
+ bool option_available = false;
char *option_name = req_or_option->option_name + 6;
if (!strcmp (option_name, "DensityInstruction"))
option_available = (XCHAL_HAVE_DENSITY == 1);
as_warn (_("invalid configuration option '%s' in transition rule '%s'"),
req_or_option->option_name, from_string);
if ((option_available ^ req_or_option->is_true) != 0)
- return FALSE;
+ return false;
}
else if (strcmp (req_or_option->option_name, "realnop") == 0)
{
- bfd_boolean nop_available =
+ bool nop_available =
(xtensa_opcode_lookup (xtensa_default_isa, "nop")
!= XTENSA_UNDEFINED);
if ((nop_available ^ req_or_option->is_true) != 0)
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
-static bfd_boolean
+static bool
wide_branch_opcode (const char *opcode_name,
const char *suffix,
xtensa_opcode *popcode)
xtensa_opcode opcode;
static char wbr_name_buf[20];
- if (strncmp (opcode_name, "WIDE.", 5) != 0)
- return FALSE;
+ if (!startswith (opcode_name, "WIDE."))
+ return false;
strcpy (wbr_name_buf, opcode_name + 5);
strcat (wbr_name_buf, suffix);
if (opcode != XTENSA_UNDEFINED)
{
*popcode = opcode;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
op2 = get_opmatch (&initial_insn->t.operand_map, precond->opname2);
if (op2 == NULL)
as_fatal (_("opcode '%s': no bound opname '%s' "
- "for precondition in %s"),
+ "for precondition in '%s'"),
xtensa_opcode_name (isa, opcode),
precond->opname2, from_string);
}
/* Check for the right number of ops. */
if (xtensa_opcode_num_operands (isa, bi->opcode)
!= (int) operand_count)
- as_fatal (_("opcode '%s': replacement does not have %d ops"),
+ as_fatal (ngettext ("opcode '%s': replacement does not have %d op",
+ "opcode '%s': replacement does not have %d ops",
+ xtensa_opcode_num_operands (isa, bi->opcode)),
opcode_name,
xtensa_opcode_num_operands (isa, bi->opcode));
}
orig_op = get_opmatch (&initial_insn->t.operand_map,
op->operand_name);
if (orig_op == NULL)
- as_fatal (_("opcode %s: unidentified operand '%s' in '%s'"),
+ as_fatal (_("opcode '%s': unidentified operand '%s' in '%s'"),
opcode_name, op->operand_name, to_string);
append_field_op (bi, op->operand_num, orig_op->operand_num);
}
orig_op = get_opmatch (&initial_insn->t.operand_map,
operand_arg_name);
if (orig_op == NULL)
- as_fatal (_("opcode %s: unidentified operand '%s' in '%s'"),
+ as_fatal (_("opcode '%s': unidentified operand '%s' in '%s'"),
opcode_name, op->operand_name, to_string);
append_user_fn_field_op (bi, op->operand_num,
typ, orig_op->operand_num);
}
else
- as_fatal (_("opcode %s: could not parse operand '%s' in '%s'"),
+ as_fatal (_("opcode '%s': could not parse operand '%s' in '%s'"),
opcode_name, op->operand_name, to_string);
}
}