OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [binutils-2.18.50/] [gas/] [config/] [xtensa-relax.c] - Diff between revs 156 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 156 Rev 816
/* Table of relaxations for Xtensa assembly.
/* Table of relaxations for Xtensa assembly.
   Copyright 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
   Copyright 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
 
 
   This file is part of GAS, the GNU Assembler.
   This file is part of GAS, the GNU Assembler.
 
 
   GAS is free software; you can redistribute it and/or modify
   GAS is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   the Free Software Foundation; either version 3, or (at your option)
   any later version.
   any later version.
 
 
   GAS is distributed in the hope that it will be useful,
   GAS is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with GAS; see the file COPYING.  If not, write to
   along with GAS; see the file COPYING.  If not, write to
   the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
   the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */
   MA 02110-1301, USA.  */
 
 
/* This file contains the code for generating runtime data structures
/* This file contains the code for generating runtime data structures
   for relaxation pattern matching from statically specified strings.
   for relaxation pattern matching from statically specified strings.
   Each action contains an instruction pattern to match and
   Each action contains an instruction pattern to match and
   preconditions for the match as well as an expansion if the pattern
   preconditions for the match as well as an expansion if the pattern
   matches.  The preconditions can specify that two operands are the
   matches.  The preconditions can specify that two operands are the
   same or an operand is a specific constant or register.  The expansion
   same or an operand is a specific constant or register.  The expansion
   uses the bound variables from the pattern to specify that specific
   uses the bound variables from the pattern to specify that specific
   operands from the pattern should be used in the result.
   operands from the pattern should be used in the result.
 
 
   The code determines whether the condition applies to a constant or
   The code determines whether the condition applies to a constant or
   a register depending on the type of the operand.  You may get
   a register depending on the type of the operand.  You may get
   unexpected results if you don't match the rule against the operand
   unexpected results if you don't match the rule against the operand
   type correctly.
   type correctly.
 
 
   The patterns match a language like:
   The patterns match a language like:
 
 
   INSN_PATTERN ::= INSN_TEMPL ( '|' PRECOND )* ( '?' OPTIONPRED )*
   INSN_PATTERN ::= INSN_TEMPL ( '|' PRECOND )* ( '?' OPTIONPRED )*
   INSN_TEMPL   ::= OPCODE ' ' [ OPERAND (',' OPERAND)* ]
   INSN_TEMPL   ::= OPCODE ' ' [ OPERAND (',' OPERAND)* ]
   OPCODE       ::=  id
   OPCODE       ::=  id
   OPERAND      ::= CONSTANT | VARIABLE | SPECIALFN '(' VARIABLE ')'
   OPERAND      ::= CONSTANT | VARIABLE | SPECIALFN '(' VARIABLE ')'
   SPECIALFN    ::= 'HI24S' | 'F32MINUS' | 'LOW8'
   SPECIALFN    ::= 'HI24S' | 'F32MINUS' | 'LOW8'
                    | 'HI16' | 'LOW16'
                    | 'HI16' | 'LOW16'
   VARIABLE     ::= '%' id
   VARIABLE     ::= '%' id
   PRECOND      ::= OPERAND CMPOP OPERAND
   PRECOND      ::= OPERAND CMPOP OPERAND
   CMPOP        ::= '==' | '!='
   CMPOP        ::= '==' | '!='
   OPTIONPRED   ::= OPTIONNAME ('+' OPTIONNAME)
   OPTIONPRED   ::= OPTIONNAME ('+' OPTIONNAME)
   OPTIONNAME   ::= '"' id '"'
   OPTIONNAME   ::= '"' id '"'
 
 
   The replacement language
   The replacement language
   INSN_REPL      ::= INSN_LABEL_LIT ( ';' INSN_LABEL_LIT )*
   INSN_REPL      ::= INSN_LABEL_LIT ( ';' INSN_LABEL_LIT )*
   INSN_LABEL_LIT ::= INSN_TEMPL
   INSN_LABEL_LIT ::= INSN_TEMPL
                      | 'LABEL'
                      | 'LABEL'
                      | 'LITERAL' VARIABLE
                      | 'LITERAL' VARIABLE
 
 
   The operands in a PRECOND must be constants or variables bound by
   The operands in a PRECOND must be constants or variables bound by
   the INSN_PATTERN.
   the INSN_PATTERN.
 
 
   The configuration options define a predicate on the availability of
   The configuration options define a predicate on the availability of
   options which must be TRUE for this rule to be valid.  Examples are
   options which must be TRUE for this rule to be valid.  Examples are
   requiring "density" for replacements with density instructions,
   requiring "density" for replacements with density instructions,
   requiring "const16" for replacements that require const16
   requiring "const16" for replacements that require const16
   instructions, etc.  The names are interpreted by the assembler to a
   instructions, etc.  The names are interpreted by the assembler to a
   truth value for a particular frag.
   truth value for a particular frag.
 
 
   The operands in the INSN_REPL must be constants, variables bound in
   The operands in the INSN_REPL must be constants, variables bound in
   the associated INSN_PATTERN, special variables that are bound in
   the associated INSN_PATTERN, special variables that are bound in
   the INSN_REPL by LABEL or LITERAL definitions, or special value
   the INSN_REPL by LABEL or LITERAL definitions, or special value
   manipulation functions.
   manipulation functions.
 
 
   A simple example of a replacement pattern:
   A simple example of a replacement pattern:
   {"movi.n %as,%imm", "movi %as,%imm"} would convert the narrow
   {"movi.n %as,%imm", "movi %as,%imm"} would convert the narrow
   movi.n instruction to the wide movi instruction.
   movi.n instruction to the wide movi instruction.
 
 
   A more complex example of a branch around:
   A more complex example of a branch around:
   {"beqz %as,%label", "bnez %as,%LABEL;j %label;LABEL"}
   {"beqz %as,%label", "bnez %as,%LABEL;j %label;LABEL"}
   would convert a branch to a negated branch to the following instruction
   would convert a branch to a negated branch to the following instruction
   with a jump to the original label.
   with a jump to the original label.
 
 
   An Xtensa-specific example that generates a literal:
   An Xtensa-specific example that generates a literal:
   {"movi %at,%imm", "LITERAL %imm; l32r %at,%LITERAL"}
   {"movi %at,%imm", "LITERAL %imm; l32r %at,%LITERAL"}
   will convert a movi instruction to an l32r of a literal
   will convert a movi instruction to an l32r of a literal
   literal defined in the literal pool.
   literal defined in the literal pool.
 
 
   Even more complex is a conversion of a load with immediate offset
   Even more complex is a conversion of a load with immediate offset
   to a load of a freshly generated literal, an explicit add and
   to a load of a freshly generated literal, an explicit add and
   a load with 0 offset.  This transformation is only valid, though
   a load with 0 offset.  This transformation is only valid, though
   when the first and second operands are not the same as specified
   when the first and second operands are not the same as specified
   by the "| %at!=%as" precondition clause.
   by the "| %at!=%as" precondition clause.
   {"l32i %at,%as,%imm | %at!=%as",
   {"l32i %at,%as,%imm | %at!=%as",
   "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l32i %at,%at,0"}
   "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
   There is special case for loop instructions here, but because we do
   not currently have the ability to represent the difference of two
   not currently have the ability to represent the difference of two
   symbols, the conversion requires special code in the assembler to
   symbols, the conversion requires special code in the assembler to
   write the operands of the addi/addmi pair representing the
   write the operands of the addi/addmi pair representing the
   difference of the old and new loop end label.  */
   difference of the old and new loop end label.  */
 
 
#include "as.h"
#include "as.h"
#include "xtensa-isa.h"
#include "xtensa-isa.h"
#include "xtensa-relax.h"
#include "xtensa-relax.h"
#include <stddef.h>
#include <stddef.h>
#include "xtensa-config.h"
#include "xtensa-config.h"
 
 
#ifndef XCHAL_HAVE_WIDE_BRANCHES
#ifndef XCHAL_HAVE_WIDE_BRANCHES
#define XCHAL_HAVE_WIDE_BRANCHES 0
#define XCHAL_HAVE_WIDE_BRANCHES 0
#endif
#endif
 
 
/* Imported from bfd.  */
/* Imported from bfd.  */
extern xtensa_isa xtensa_default_isa;
extern xtensa_isa xtensa_default_isa;
 
 
/* The opname_list is a small list of names that we use for opcode and
/* The opname_list is a small list of names that we use for opcode and
   operand variable names to simplify ownership of these commonly used
   operand variable names to simplify ownership of these commonly used
   strings.  Strings entered in the table can be compared by pointer
   strings.  Strings entered in the table can be compared by pointer
   equality.  */
   equality.  */
 
 
typedef struct opname_list_struct opname_list;
typedef struct opname_list_struct opname_list;
typedef opname_list opname_e;
typedef opname_list opname_e;
 
 
struct opname_list_struct
struct opname_list_struct
{
{
  char *opname;
  char *opname;
  opname_list *next;
  opname_list *next;
};
};
 
 
static opname_list *local_opnames = NULL;
static opname_list *local_opnames = NULL;
 
 
 
 
/* The "opname_map" and its element structure "opname_map_e" are used
/* The "opname_map" and its element structure "opname_map_e" are used
   for binding an operand number to a name or a constant.  */
   for binding an operand number to a name or a constant.  */
 
 
typedef struct opname_map_e_struct opname_map_e;
typedef struct opname_map_e_struct opname_map_e;
typedef struct opname_map_struct opname_map;
typedef struct opname_map_struct opname_map;
 
 
struct opname_map_e_struct
struct opname_map_e_struct
{
{
  const char *operand_name;     /* If null, then use constant_value.  */
  const char *operand_name;     /* If null, then use constant_value.  */
  int operand_num;
  int operand_num;
  unsigned constant_value;
  unsigned constant_value;
  opname_map_e *next;
  opname_map_e *next;
};
};
 
 
struct opname_map_struct
struct opname_map_struct
{
{
  opname_map_e *head;
  opname_map_e *head;
  opname_map_e **tail;
  opname_map_e **tail;
};
};
 
 
/* The "precond_list" and its element structure "precond_e" represents
/* The "precond_list" and its element structure "precond_e" represents
   explicit preconditions comparing operand variables and constants.
   explicit preconditions comparing operand variables and constants.
   In the "precond_e" structure, a variable is identified by the name
   In the "precond_e" structure, a variable is identified by the name
   in the "opname" field.   If that field is NULL, then the operand
   in the "opname" field.   If that field is NULL, then the operand
   is the constant in field "opval".  */
   is the constant in field "opval".  */
 
 
typedef struct precond_e_struct precond_e;
typedef struct precond_e_struct precond_e;
typedef struct precond_list_struct precond_list;
typedef struct precond_list_struct precond_list;
 
 
struct precond_e_struct
struct precond_e_struct
{
{
  const char *opname1;
  const char *opname1;
  unsigned opval1;
  unsigned opval1;
  CmpOp cmpop;
  CmpOp cmpop;
  const char *opname2;
  const char *opname2;
  unsigned opval2;
  unsigned opval2;
  precond_e *next;
  precond_e *next;
};
};
 
 
struct precond_list_struct
struct precond_list_struct
{
{
  precond_e *head;
  precond_e *head;
  precond_e **tail;
  precond_e **tail;
};
};
 
 
 
 
/* The insn_templ represents the INSN_TEMPL instruction template.  It
/* The insn_templ represents the INSN_TEMPL instruction template.  It
   is an opcode name with a list of operands.  These are used for
   is an opcode name with a list of operands.  These are used for
   instruction patterns and replacement patterns.  */
   instruction patterns and replacement patterns.  */
 
 
typedef struct insn_templ_struct insn_templ;
typedef struct insn_templ_struct insn_templ;
struct insn_templ_struct
struct insn_templ_struct
{
{
  const char *opcode_name;
  const char *opcode_name;
  opname_map operand_map;
  opname_map operand_map;
};
};
 
 
 
 
/* The insn_pattern represents an INSN_PATTERN instruction pattern.
/* The insn_pattern represents an INSN_PATTERN instruction pattern.
   It is an instruction template with preconditions that specify when
   It is an instruction template with preconditions that specify when
   it actually matches a given instruction.  */
   it actually matches a given instruction.  */
 
 
typedef struct insn_pattern_struct insn_pattern;
typedef struct insn_pattern_struct insn_pattern;
struct insn_pattern_struct
struct insn_pattern_struct
{
{
  insn_templ t;
  insn_templ t;
  precond_list preconds;
  precond_list preconds;
  ReqOptionList *options;
  ReqOptionList *options;
};
};
 
 
 
 
/* The "insn_repl" and associated element structure "insn_repl_e"
/* The "insn_repl" and associated element structure "insn_repl_e"
   instruction replacement list is a list of
   instruction replacement list is a list of
   instructions/LITERALS/LABELS with constant operands or operands
   instructions/LITERALS/LABELS with constant operands or operands
   with names bound to the operand names in the associated pattern.  */
   with names bound to the operand names in the associated pattern.  */
 
 
typedef struct insn_repl_e_struct insn_repl_e;
typedef struct insn_repl_e_struct insn_repl_e;
struct insn_repl_e_struct
struct insn_repl_e_struct
{
{
  insn_templ t;
  insn_templ t;
  insn_repl_e *next;
  insn_repl_e *next;
};
};
 
 
typedef struct insn_repl_struct insn_repl;
typedef struct insn_repl_struct insn_repl;
struct insn_repl_struct
struct insn_repl_struct
{
{
  insn_repl_e *head;
  insn_repl_e *head;
  insn_repl_e **tail;
  insn_repl_e **tail;
};
};
 
 
 
 
/* The split_rec is a vector of allocated char * pointers.  */
/* The split_rec is a vector of allocated char * pointers.  */
 
 
typedef struct split_rec_struct split_rec;
typedef struct split_rec_struct split_rec;
struct split_rec_struct
struct split_rec_struct
{
{
  char **vec;
  char **vec;
  int count;
  int count;
};
};
 
 
/* The "string_pattern_pair" is a set of pairs containing instruction
/* The "string_pattern_pair" is a set of pairs containing instruction
   patterns and replacement strings.  */
   patterns and replacement strings.  */
 
 
typedef struct string_pattern_pair_struct string_pattern_pair;
typedef struct string_pattern_pair_struct string_pattern_pair;
struct string_pattern_pair_struct
struct string_pattern_pair_struct
{
{
  const char *pattern;
  const char *pattern;
  const char *replacement;
  const char *replacement;
};
};
 
 


/* The widen_spec_list is a list of valid substitutions that generate
/* The widen_spec_list is a list of valid substitutions that generate
   wider representations.  These are generally used to specify
   wider representations.  These are generally used to specify
   replacements for instructions whose immediates do not fit their
   replacements for instructions whose immediates do not fit their
   encodings.  A valid transition may require multiple steps of
   encodings.  A valid transition may require multiple steps of
   one-to-one instruction replacements with a final multiple
   one-to-one instruction replacements with a final multiple
   instruction replacement.  As an example, here are the transitions
   instruction replacement.  As an example, here are the transitions
   required to replace an 'addi.n' with an 'addi', 'addmi'.
   required to replace an 'addi.n' with an 'addi', 'addmi'.
 
 
     addi.n a4, 0x1010
     addi.n a4, 0x1010
     => addi a4, 0x1010
     => addi a4, 0x1010
     => addmi a4, 0x1010
     => addmi a4, 0x1010
     => addmi a4, 0x1000, addi a4, 0x10.
     => addmi a4, 0x1000, addi a4, 0x10.
 
 
   See the comments in xg_assembly_relax for some important details
   See the comments in xg_assembly_relax for some important details
   regarding how these chains must be built.  */
   regarding how these chains must be built.  */
 
 
static string_pattern_pair widen_spec_list[] =
static string_pattern_pair widen_spec_list[] =
{
{
  {"add.n %ar,%as,%at ? IsaUseDensityInstruction", "add %ar,%as,%at"},
  {"add.n %ar,%as,%at ? IsaUseDensityInstruction", "add %ar,%as,%at"},
  {"addi.n %ar,%as,%imm ? IsaUseDensityInstruction", "addi %ar,%as,%imm"},
  {"addi.n %ar,%as,%imm ? IsaUseDensityInstruction", "addi %ar,%as,%imm"},
  {"beqz.n %as,%label ? IsaUseDensityInstruction", "beqz %as,%label"},
  {"beqz.n %as,%label ? IsaUseDensityInstruction", "beqz %as,%label"},
  {"bnez.n %as,%label ? IsaUseDensityInstruction", "bnez %as,%label"},
  {"bnez.n %as,%label ? IsaUseDensityInstruction", "bnez %as,%label"},
  {"l32i.n %at,%as,%imm ? IsaUseDensityInstruction", "l32i %at,%as,%imm"},
  {"l32i.n %at,%as,%imm ? IsaUseDensityInstruction", "l32i %at,%as,%imm"},
  {"mov.n %at,%as ? IsaUseDensityInstruction", "or %at,%as,%as"},
  {"mov.n %at,%as ? IsaUseDensityInstruction", "or %at,%as,%as"},
  {"movi.n %as,%imm ? IsaUseDensityInstruction", "movi %as,%imm"},
  {"movi.n %as,%imm ? IsaUseDensityInstruction", "movi %as,%imm"},
  {"nop.n ? IsaUseDensityInstruction ? realnop", "nop"},
  {"nop.n ? IsaUseDensityInstruction ? realnop", "nop"},
  {"nop.n ? IsaUseDensityInstruction ? no-realnop", "or 1,1,1"},
  {"nop.n ? IsaUseDensityInstruction ? no-realnop", "or 1,1,1"},
  {"ret.n %as ? IsaUseDensityInstruction", "ret %as"},
  {"ret.n %as ? IsaUseDensityInstruction", "ret %as"},
  {"retw.n %as ? IsaUseDensityInstruction", "retw %as"},
  {"retw.n %as ? IsaUseDensityInstruction", "retw %as"},
  {"s32i.n %at,%as,%imm ? IsaUseDensityInstruction", "s32i %at,%as,%imm"},
  {"s32i.n %at,%as,%imm ? IsaUseDensityInstruction", "s32i %at,%as,%imm"},
  {"srli %at,%as,%imm", "extui %at,%as,%imm,F32MINUS(%imm)"},
  {"srli %at,%as,%imm", "extui %at,%as,%imm,F32MINUS(%imm)"},
  {"slli %ar,%as,0", "or %ar,%as,%as"},
  {"slli %ar,%as,0", "or %ar,%as,%as"},
 
 
  /* Widening with literals or const16.  */
  /* Widening with literals or const16.  */
  {"movi %at,%imm ? IsaUseL32R ",
  {"movi %at,%imm ? IsaUseL32R ",
   "LITERAL %imm; l32r %at,%LITERAL"},
   "LITERAL %imm; l32r %at,%LITERAL"},
  {"movi %at,%imm ? IsaUseConst16",
  {"movi %at,%imm ? IsaUseConst16",
   "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm)"},
   "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm)"},
 
 
  {"addi %ar,%as,%imm", "addmi %ar,%as,%imm"},
  {"addi %ar,%as,%imm", "addmi %ar,%as,%imm"},
  /* LOW8 is the low 8 bits of the Immed
  /* LOW8 is the low 8 bits of the Immed
     MID8S is the middle 8 bits of the Immed */
     MID8S is the middle 8 bits of the Immed */
  {"addmi %ar,%as,%imm", "addmi %ar,%as,HI24S(%imm); addi %ar,%ar,LOW8(%imm)"},
  {"addmi %ar,%as,%imm", "addmi %ar,%as,HI24S(%imm); addi %ar,%ar,LOW8(%imm)"},
 
 
  /* In the end convert to either an l32r or const16.  */
  /* In the end convert to either an l32r or const16.  */
  {"addmi %ar,%as,%imm | %ar!=%as ? IsaUseL32R",
  {"addmi %ar,%as,%imm | %ar!=%as ? IsaUseL32R",
   "LITERAL %imm; l32r %ar,%LITERAL; add %ar,%as,%ar"},
   "LITERAL %imm; l32r %ar,%LITERAL; add %ar,%as,%ar"},
  {"addmi %ar,%as,%imm | %ar!=%as ? IsaUseConst16",
  {"addmi %ar,%as,%imm | %ar!=%as ? IsaUseConst16",
   "const16 %ar,HI16U(%imm); const16 %ar,LOW16U(%imm); add %ar,%as,%ar"},
   "const16 %ar,HI16U(%imm); const16 %ar,LOW16U(%imm); add %ar,%as,%ar"},
 
 
  /* Widening the load instructions with too-large immediates */
  /* Widening the load instructions with too-large immediates */
  {"l8ui %at,%as,%imm | %at!=%as ? IsaUseL32R",
  {"l8ui %at,%as,%imm | %at!=%as ? IsaUseL32R",
   "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l8ui %at,%at,0"},
   "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l8ui %at,%at,0"},
  {"l16si %at,%as,%imm | %at!=%as ? IsaUseL32R",
  {"l16si %at,%as,%imm | %at!=%as ? IsaUseL32R",
   "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l16si %at,%at,0"},
   "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l16si %at,%at,0"},
  {"l16ui %at,%as,%imm | %at!=%as ? IsaUseL32R",
  {"l16ui %at,%as,%imm | %at!=%as ? IsaUseL32R",
   "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l16ui %at,%at,0"},
   "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l16ui %at,%at,0"},
  {"l32i %at,%as,%imm | %at!=%as ? IsaUseL32R",
  {"l32i %at,%as,%imm | %at!=%as ? IsaUseL32R",
   "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l32i %at,%at,0"},
   "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l32i %at,%at,0"},
 
 
  /* Widening load instructions with const16s.  */
  /* Widening load instructions with const16s.  */
  {"l8ui %at,%as,%imm | %at!=%as ? IsaUseConst16",
  {"l8ui %at,%as,%imm | %at!=%as ? IsaUseConst16",
   "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l8ui %at,%at,0"},
   "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l8ui %at,%at,0"},
  {"l16si %at,%as,%imm | %at!=%as ? IsaUseConst16",
  {"l16si %at,%as,%imm | %at!=%as ? IsaUseConst16",
   "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l16si %at,%at,0"},
   "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l16si %at,%at,0"},
  {"l16ui %at,%as,%imm | %at!=%as ? IsaUseConst16",
  {"l16ui %at,%as,%imm | %at!=%as ? IsaUseConst16",
   "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l16ui %at,%at,0"},
   "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l16ui %at,%at,0"},
  {"l32i %at,%as,%imm | %at!=%as ? IsaUseConst16",
  {"l32i %at,%as,%imm | %at!=%as ? IsaUseConst16",
   "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l32i %at,%at,0"},
   "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,
  /* This is only PART of the loop instruction.  In addition,
     hardcoded into its use is a modification of the final operand in
     hardcoded into its use is a modification of the final operand in
     the instruction in bytes 9 and 12.  */
     the instruction in bytes 9 and 12.  */
  {"loop %as,%label | %as!=1 ? IsaUseLoops",
  {"loop %as,%label | %as!=1 ? IsaUseLoops",
   "loop %as,%LABEL;"
   "loop %as,%LABEL;"
   "rsr.lend    %as;"           /* LEND */
   "rsr.lend    %as;"           /* LEND */
   "wsr.lbeg    %as;"           /* LBEG */
   "wsr.lbeg    %as;"           /* LBEG */
   "addi    %as, %as, 0;"       /* lo8(%label-%LABEL1) */
   "addi    %as, %as, 0;"       /* lo8(%label-%LABEL1) */
   "addmi   %as, %as, 0;"       /* mid8(%label-%LABEL1) */
   "addmi   %as, %as, 0;"       /* mid8(%label-%LABEL1) */
   "wsr.lend    %as;"
   "wsr.lend    %as;"
   "isync;"
   "isync;"
   "rsr.lcount    %as;"         /* LCOUNT */
   "rsr.lcount    %as;"         /* LCOUNT */
   "addi    %as, %as, 1;"       /* density -> addi.n %as, %as, 1 */
   "addi    %as, %as, 1;"       /* density -> addi.n %as, %as, 1 */
   "LABEL"},
   "LABEL"},
  {"loopgtz %as,%label | %as!=1 ? IsaUseLoops",
  {"loopgtz %as,%label | %as!=1 ? IsaUseLoops",
   "beqz    %as,%label;"
   "beqz    %as,%label;"
   "bltz    %as,%label;"
   "bltz    %as,%label;"
   "loopgtz %as,%LABEL;"
   "loopgtz %as,%LABEL;"
   "rsr.lend    %as;"           /* LEND */
   "rsr.lend    %as;"           /* LEND */
   "wsr.lbeg    %as;"           /* LBEG */
   "wsr.lbeg    %as;"           /* LBEG */
   "addi    %as, %as, 0;"       /* lo8(%label-%LABEL1) */
   "addi    %as, %as, 0;"       /* lo8(%label-%LABEL1) */
   "addmi   %as, %as, 0;"       /* mid8(%label-%LABEL1) */
   "addmi   %as, %as, 0;"       /* mid8(%label-%LABEL1) */
   "wsr.lend    %as;"
   "wsr.lend    %as;"
   "isync;"
   "isync;"
   "rsr.lcount    %as;"         /* LCOUNT */
   "rsr.lcount    %as;"         /* LCOUNT */
   "addi    %as, %as, 1;"       /* density -> addi.n %as, %as, 1 */
   "addi    %as, %as, 1;"       /* density -> addi.n %as, %as, 1 */
   "LABEL"},
   "LABEL"},
  {"loopnez %as,%label | %as!=1 ? IsaUseLoops",
  {"loopnez %as,%label | %as!=1 ? IsaUseLoops",
   "beqz     %as,%label;"
   "beqz     %as,%label;"
   "loopnez %as,%LABEL;"
   "loopnez %as,%LABEL;"
   "rsr.lend    %as;"           /* LEND */
   "rsr.lend    %as;"           /* LEND */
   "wsr.lbeg    %as;"           /* LBEG */
   "wsr.lbeg    %as;"           /* LBEG */
   "addi    %as, %as, 0;"       /* lo8(%label-%LABEL1) */
   "addi    %as, %as, 0;"       /* lo8(%label-%LABEL1) */
   "addmi   %as, %as, 0;"       /* mid8(%label-%LABEL1) */
   "addmi   %as, %as, 0;"       /* mid8(%label-%LABEL1) */
   "wsr.lend    %as;"
   "wsr.lend    %as;"
   "isync;"
   "isync;"
   "rsr.lcount    %as;"         /* LCOUNT */
   "rsr.lcount    %as;"         /* LCOUNT */
   "addi    %as, %as, 1;"       /* density -> addi.n %as, %as, 1 */
   "addi    %as, %as, 1;"       /* density -> addi.n %as, %as, 1 */
   "LABEL"},
   "LABEL"},
 
 
  /* Relaxing to wide branches.  Order is important here.  With wide
  /* Relaxing to wide branches.  Order is important here.  With wide
     branches, there is more than one correct relaxation for an
     branches, there is more than one correct relaxation for an
     out-of-range branch.  Put the wide branch relaxations first in the
     out-of-range branch.  Put the wide branch relaxations first in the
     table since they are more efficient than the branch-around
     table since they are more efficient than the branch-around
     relaxations.  */
     relaxations.  */
 
 
  {"beqz %as,%label ? IsaUseWideBranches", "WIDE.beqz %as,%label"},
  {"beqz %as,%label ? IsaUseWideBranches", "WIDE.beqz %as,%label"},
  {"bnez %as,%label ? IsaUseWideBranches", "WIDE.bnez %as,%label"},
  {"bnez %as,%label ? IsaUseWideBranches", "WIDE.bnez %as,%label"},
  {"bgez %as,%label ? IsaUseWideBranches", "WIDE.bgez %as,%label"},
  {"bgez %as,%label ? IsaUseWideBranches", "WIDE.bgez %as,%label"},
  {"bltz %as,%label ? IsaUseWideBranches", "WIDE.bltz %as,%label"},
  {"bltz %as,%label ? IsaUseWideBranches", "WIDE.bltz %as,%label"},
  {"beqi %as,%imm,%label ? IsaUseWideBranches", "WIDE.beqi %as,%imm,%label"},
  {"beqi %as,%imm,%label ? IsaUseWideBranches", "WIDE.beqi %as,%imm,%label"},
  {"bnei %as,%imm,%label ? IsaUseWideBranches", "WIDE.bnei %as,%imm,%label"},
  {"bnei %as,%imm,%label ? IsaUseWideBranches", "WIDE.bnei %as,%imm,%label"},
  {"bgei %as,%imm,%label ? IsaUseWideBranches", "WIDE.bgei %as,%imm,%label"},
  {"bgei %as,%imm,%label ? IsaUseWideBranches", "WIDE.bgei %as,%imm,%label"},
  {"blti %as,%imm,%label ? IsaUseWideBranches", "WIDE.blti %as,%imm,%label"},
  {"blti %as,%imm,%label ? IsaUseWideBranches", "WIDE.blti %as,%imm,%label"},
  {"bgeui %as,%imm,%label ? IsaUseWideBranches", "WIDE.bgeui %as,%imm,%label"},
  {"bgeui %as,%imm,%label ? IsaUseWideBranches", "WIDE.bgeui %as,%imm,%label"},
  {"bltui %as,%imm,%label ? IsaUseWideBranches", "WIDE.bltui %as,%imm,%label"},
  {"bltui %as,%imm,%label ? IsaUseWideBranches", "WIDE.bltui %as,%imm,%label"},
  {"bbci %as,%imm,%label ? IsaUseWideBranches", "WIDE.bbci %as,%imm,%label"},
  {"bbci %as,%imm,%label ? IsaUseWideBranches", "WIDE.bbci %as,%imm,%label"},
  {"bbsi %as,%imm,%label ? IsaUseWideBranches", "WIDE.bbsi %as,%imm,%label"},
  {"bbsi %as,%imm,%label ? IsaUseWideBranches", "WIDE.bbsi %as,%imm,%label"},
  {"beq %as,%at,%label ? IsaUseWideBranches", "WIDE.beq %as,%at,%label"},
  {"beq %as,%at,%label ? IsaUseWideBranches", "WIDE.beq %as,%at,%label"},
  {"bne %as,%at,%label ? IsaUseWideBranches", "WIDE.bne %as,%at,%label"},
  {"bne %as,%at,%label ? IsaUseWideBranches", "WIDE.bne %as,%at,%label"},
  {"bge %as,%at,%label ? IsaUseWideBranches", "WIDE.bge %as,%at,%label"},
  {"bge %as,%at,%label ? IsaUseWideBranches", "WIDE.bge %as,%at,%label"},
  {"blt %as,%at,%label ? IsaUseWideBranches", "WIDE.blt %as,%at,%label"},
  {"blt %as,%at,%label ? IsaUseWideBranches", "WIDE.blt %as,%at,%label"},
  {"bgeu %as,%at,%label ? IsaUseWideBranches", "WIDE.bgeu %as,%at,%label"},
  {"bgeu %as,%at,%label ? IsaUseWideBranches", "WIDE.bgeu %as,%at,%label"},
  {"bltu %as,%at,%label ? IsaUseWideBranches", "WIDE.bltu %as,%at,%label"},
  {"bltu %as,%at,%label ? IsaUseWideBranches", "WIDE.bltu %as,%at,%label"},
  {"bany %as,%at,%label ? IsaUseWideBranches", "WIDE.bany %as,%at,%label"},
  {"bany %as,%at,%label ? IsaUseWideBranches", "WIDE.bany %as,%at,%label"},
  {"bnone %as,%at,%label ? IsaUseWideBranches", "WIDE.bnone %as,%at,%label"},
  {"bnone %as,%at,%label ? IsaUseWideBranches", "WIDE.bnone %as,%at,%label"},
  {"ball %as,%at,%label ? IsaUseWideBranches", "WIDE.ball %as,%at,%label"},
  {"ball %as,%at,%label ? IsaUseWideBranches", "WIDE.ball %as,%at,%label"},
  {"bnall %as,%at,%label ? IsaUseWideBranches", "WIDE.bnall %as,%at,%label"},
  {"bnall %as,%at,%label ? IsaUseWideBranches", "WIDE.bnall %as,%at,%label"},
  {"bbc %as,%at,%label ? IsaUseWideBranches", "WIDE.bbc %as,%at,%label"},
  {"bbc %as,%at,%label ? IsaUseWideBranches", "WIDE.bbc %as,%at,%label"},
  {"bbs %as,%at,%label ? IsaUseWideBranches", "WIDE.bbs %as,%at,%label"},
  {"bbs %as,%at,%label ? IsaUseWideBranches", "WIDE.bbs %as,%at,%label"},
 
 
  /* Widening branch comparisons eq/ne to zero.  Prefer relaxing to narrow
  /* Widening branch comparisons eq/ne to zero.  Prefer relaxing to narrow
     branches if the density option is available.  */
     branches if the density option is available.  */
  {"beqz %as,%label ? IsaUseDensityInstruction", "bnez.n %as,%LABEL;j %label;LABEL"},
  {"beqz %as,%label ? IsaUseDensityInstruction", "bnez.n %as,%LABEL;j %label;LABEL"},
  {"bnez %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%LABEL;j %label;LABEL"},
  {"bnez %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%LABEL;j %label;LABEL"},
  {"beqz %as,%label", "bnez %as,%LABEL;j %label;LABEL"},
  {"beqz %as,%label", "bnez %as,%LABEL;j %label;LABEL"},
  {"bnez %as,%label", "beqz %as,%LABEL;j %label;LABEL"},
  {"bnez %as,%label", "beqz %as,%LABEL;j %label;LABEL"},
  {"WIDE.beqz %as,%label ? IsaUseDensityInstruction", "bnez.n %as,%LABEL;j %label;LABEL"},
  {"WIDE.beqz %as,%label ? IsaUseDensityInstruction", "bnez.n %as,%LABEL;j %label;LABEL"},
  {"WIDE.bnez %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%LABEL;j %label;LABEL"},
  {"WIDE.bnez %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%LABEL;j %label;LABEL"},
  {"WIDE.beqz %as,%label", "bnez %as,%LABEL;j %label;LABEL"},
  {"WIDE.beqz %as,%label", "bnez %as,%LABEL;j %label;LABEL"},
  {"WIDE.bnez %as,%label", "beqz %as,%LABEL;j %label;LABEL"},
  {"WIDE.bnez %as,%label", "beqz %as,%LABEL;j %label;LABEL"},
 
 
  /* Widening expect-taken branches.  */
  /* Widening expect-taken branches.  */
  {"beqzt %as,%label ? IsaUsePredictedBranches", "bnez %as,%LABEL;j %label;LABEL"},
  {"beqzt %as,%label ? IsaUsePredictedBranches", "bnez %as,%LABEL;j %label;LABEL"},
  {"bnezt %as,%label ? IsaUsePredictedBranches", "beqz %as,%LABEL;j %label;LABEL"},
  {"bnezt %as,%label ? IsaUsePredictedBranches", "beqz %as,%LABEL;j %label;LABEL"},
  {"beqt %as,%at,%label ? IsaUsePredictedBranches", "bne %as,%at,%LABEL;j %label;LABEL"},
  {"beqt %as,%at,%label ? IsaUsePredictedBranches", "bne %as,%at,%LABEL;j %label;LABEL"},
  {"bnet %as,%at,%label ? IsaUsePredictedBranches", "beq %as,%at,%LABEL;j %label;LABEL"},
  {"bnet %as,%at,%label ? IsaUsePredictedBranches", "beq %as,%at,%LABEL;j %label;LABEL"},
 
 
  /* Widening branches from the Xtensa boolean option.  */
  /* Widening branches from the Xtensa boolean option.  */
  {"bt %bs,%label ? IsaUseBooleans", "bf %bs,%LABEL;j %label;LABEL"},
  {"bt %bs,%label ? IsaUseBooleans", "bf %bs,%LABEL;j %label;LABEL"},
  {"bf %bs,%label ? IsaUseBooleans", "bt %bs,%LABEL;j %label;LABEL"},
  {"bf %bs,%label ? IsaUseBooleans", "bt %bs,%LABEL;j %label;LABEL"},
 
 
  /* Other branch-around-jump widenings.  */
  /* Other branch-around-jump widenings.  */
  {"bgez %as,%label", "bltz %as,%LABEL;j %label;LABEL"},
  {"bgez %as,%label", "bltz %as,%LABEL;j %label;LABEL"},
  {"bltz %as,%label", "bgez %as,%LABEL;j %label;LABEL"},
  {"bltz %as,%label", "bgez %as,%LABEL;j %label;LABEL"},
  {"beqi %as,%imm,%label", "bnei %as,%imm,%LABEL;j %label;LABEL"},
  {"beqi %as,%imm,%label", "bnei %as,%imm,%LABEL;j %label;LABEL"},
  {"bnei %as,%imm,%label", "beqi %as,%imm,%LABEL;j %label;LABEL"},
  {"bnei %as,%imm,%label", "beqi %as,%imm,%LABEL;j %label;LABEL"},
  {"bgei %as,%imm,%label", "blti %as,%imm,%LABEL;j %label;LABEL"},
  {"bgei %as,%imm,%label", "blti %as,%imm,%LABEL;j %label;LABEL"},
  {"blti %as,%imm,%label", "bgei %as,%imm,%LABEL;j %label;LABEL"},
  {"blti %as,%imm,%label", "bgei %as,%imm,%LABEL;j %label;LABEL"},
  {"bgeui %as,%imm,%label", "bltui %as,%imm,%LABEL;j %label;LABEL"},
  {"bgeui %as,%imm,%label", "bltui %as,%imm,%LABEL;j %label;LABEL"},
  {"bltui %as,%imm,%label", "bgeui %as,%imm,%LABEL;j %label;LABEL"},
  {"bltui %as,%imm,%label", "bgeui %as,%imm,%LABEL;j %label;LABEL"},
  {"bbci %as,%imm,%label", "bbsi %as,%imm,%LABEL;j %label;LABEL"},
  {"bbci %as,%imm,%label", "bbsi %as,%imm,%LABEL;j %label;LABEL"},
  {"bbsi %as,%imm,%label", "bbci %as,%imm,%LABEL;j %label;LABEL"},
  {"bbsi %as,%imm,%label", "bbci %as,%imm,%LABEL;j %label;LABEL"},
  {"beq %as,%at,%label", "bne %as,%at,%LABEL;j %label;LABEL"},
  {"beq %as,%at,%label", "bne %as,%at,%LABEL;j %label;LABEL"},
  {"bne %as,%at,%label", "beq %as,%at,%LABEL;j %label;LABEL"},
  {"bne %as,%at,%label", "beq %as,%at,%LABEL;j %label;LABEL"},
  {"bge %as,%at,%label", "blt %as,%at,%LABEL;j %label;LABEL"},
  {"bge %as,%at,%label", "blt %as,%at,%LABEL;j %label;LABEL"},
  {"blt %as,%at,%label", "bge %as,%at,%LABEL;j %label;LABEL"},
  {"blt %as,%at,%label", "bge %as,%at,%LABEL;j %label;LABEL"},
  {"bgeu %as,%at,%label", "bltu %as,%at,%LABEL;j %label;LABEL"},
  {"bgeu %as,%at,%label", "bltu %as,%at,%LABEL;j %label;LABEL"},
  {"bltu %as,%at,%label", "bgeu %as,%at,%LABEL;j %label;LABEL"},
  {"bltu %as,%at,%label", "bgeu %as,%at,%LABEL;j %label;LABEL"},
  {"bany %as,%at,%label", "bnone %as,%at,%LABEL;j %label;LABEL"},
  {"bany %as,%at,%label", "bnone %as,%at,%LABEL;j %label;LABEL"},
  {"bnone %as,%at,%label", "bany %as,%at,%LABEL;j %label;LABEL"},
  {"bnone %as,%at,%label", "bany %as,%at,%LABEL;j %label;LABEL"},
  {"ball %as,%at,%label", "bnall %as,%at,%LABEL;j %label;LABEL"},
  {"ball %as,%at,%label", "bnall %as,%at,%LABEL;j %label;LABEL"},
  {"bnall %as,%at,%label", "ball %as,%at,%LABEL;j %label;LABEL"},
  {"bnall %as,%at,%label", "ball %as,%at,%LABEL;j %label;LABEL"},
  {"bbc %as,%at,%label", "bbs %as,%at,%LABEL;j %label;LABEL"},
  {"bbc %as,%at,%label", "bbs %as,%at,%LABEL;j %label;LABEL"},
  {"bbs %as,%at,%label", "bbc %as,%at,%LABEL;j %label;LABEL"},
  {"bbs %as,%at,%label", "bbc %as,%at,%LABEL;j %label;LABEL"},
 
 
  {"WIDE.bgez %as,%label", "bltz %as,%LABEL;j %label;LABEL"},
  {"WIDE.bgez %as,%label", "bltz %as,%LABEL;j %label;LABEL"},
  {"WIDE.bltz %as,%label", "bgez %as,%LABEL;j %label;LABEL"},
  {"WIDE.bltz %as,%label", "bgez %as,%LABEL;j %label;LABEL"},
  {"WIDE.beqi %as,%imm,%label", "bnei %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.beqi %as,%imm,%label", "bnei %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bnei %as,%imm,%label", "beqi %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bnei %as,%imm,%label", "beqi %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bgei %as,%imm,%label", "blti %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bgei %as,%imm,%label", "blti %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.blti %as,%imm,%label", "bgei %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.blti %as,%imm,%label", "bgei %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bgeui %as,%imm,%label", "bltui %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bgeui %as,%imm,%label", "bltui %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bltui %as,%imm,%label", "bgeui %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bltui %as,%imm,%label", "bgeui %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bbci %as,%imm,%label", "bbsi %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bbci %as,%imm,%label", "bbsi %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bbsi %as,%imm,%label", "bbci %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.bbsi %as,%imm,%label", "bbci %as,%imm,%LABEL;j %label;LABEL"},
  {"WIDE.beq %as,%at,%label", "bne %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.beq %as,%at,%label", "bne %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bne %as,%at,%label", "beq %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bne %as,%at,%label", "beq %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bge %as,%at,%label", "blt %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bge %as,%at,%label", "blt %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.blt %as,%at,%label", "bge %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.blt %as,%at,%label", "bge %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bgeu %as,%at,%label", "bltu %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bgeu %as,%at,%label", "bltu %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bltu %as,%at,%label", "bgeu %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bltu %as,%at,%label", "bgeu %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bany %as,%at,%label", "bnone %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bany %as,%at,%label", "bnone %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bnone %as,%at,%label", "bany %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bnone %as,%at,%label", "bany %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.ball %as,%at,%label", "bnall %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.ball %as,%at,%label", "bnall %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bnall %as,%at,%label", "ball %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bnall %as,%at,%label", "ball %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bbc %as,%at,%label", "bbs %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bbc %as,%at,%label", "bbs %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bbs %as,%at,%label", "bbc %as,%at,%LABEL;j %label;LABEL"},
  {"WIDE.bbs %as,%at,%label", "bbc %as,%at,%LABEL;j %label;LABEL"},
 
 
  /* Expanding calls with literals.  */
  /* Expanding calls with literals.  */
  {"call0 %label,%ar0 ? IsaUseL32R",
  {"call0 %label,%ar0 ? IsaUseL32R",
   "LITERAL %label; l32r a0,%LITERAL; callx0 a0,%ar0"},
   "LITERAL %label; l32r a0,%LITERAL; callx0 a0,%ar0"},
  {"call4 %label,%ar4 ? IsaUseL32R",
  {"call4 %label,%ar4 ? IsaUseL32R",
   "LITERAL %label; l32r a4,%LITERAL; callx4 a4,%ar4"},
   "LITERAL %label; l32r a4,%LITERAL; callx4 a4,%ar4"},
  {"call8 %label,%ar8 ? IsaUseL32R",
  {"call8 %label,%ar8 ? IsaUseL32R",
   "LITERAL %label; l32r a8,%LITERAL; callx8 a8,%ar8"},
   "LITERAL %label; l32r a8,%LITERAL; callx8 a8,%ar8"},
  {"call12 %label,%ar12 ? IsaUseL32R",
  {"call12 %label,%ar12 ? IsaUseL32R",
   "LITERAL %label; l32r a12,%LITERAL; callx12 a12,%ar12"},
   "LITERAL %label; l32r a12,%LITERAL; callx12 a12,%ar12"},
 
 
  /* Expanding calls with const16.  */
  /* Expanding calls with const16.  */
  {"call0 %label,%ar0 ? IsaUseConst16",
  {"call0 %label,%ar0 ? IsaUseConst16",
   "const16 a0,HI16U(%label); const16 a0,LOW16U(%label); callx0 a0,%ar0"},
   "const16 a0,HI16U(%label); const16 a0,LOW16U(%label); callx0 a0,%ar0"},
  {"call4 %label,%ar4 ? IsaUseConst16",
  {"call4 %label,%ar4 ? IsaUseConst16",
   "const16 a4,HI16U(%label); const16 a4,LOW16U(%label); callx4 a4,%ar4"},
   "const16 a4,HI16U(%label); const16 a4,LOW16U(%label); callx4 a4,%ar4"},
  {"call8 %label,%ar8 ? IsaUseConst16",
  {"call8 %label,%ar8 ? IsaUseConst16",
   "const16 a8,HI16U(%label); const16 a8,LOW16U(%label); callx8 a8,%ar8"},
   "const16 a8,HI16U(%label); const16 a8,LOW16U(%label); callx8 a8,%ar8"},
  {"call12 %label,%ar12 ? IsaUseConst16",
  {"call12 %label,%ar12 ? IsaUseConst16",
   "const16 a12,HI16U(%label); const16 a12,LOW16U(%label); callx12 a12,%ar12"}
   "const16 a12,HI16U(%label); const16 a12,LOW16U(%label); callx12 a12,%ar12"}
};
};
 
 
#define WIDEN_COUNT (sizeof (widen_spec_list) / sizeof (string_pattern_pair))
#define WIDEN_COUNT (sizeof (widen_spec_list) / sizeof (string_pattern_pair))
 
 
 
 
/* The simplify_spec_list specifies simplifying transformations that
/* The simplify_spec_list specifies simplifying transformations that
   will reduce the instruction width or otherwise simplify an
   will reduce the instruction width or otherwise simplify an
   instruction.  These are usually applied before relaxation in the
   instruction.  These are usually applied before relaxation in the
   assembler.  It is always legal to simplify.  Even for "addi as, 0",
   assembler.  It is always legal to simplify.  Even for "addi as, 0",
   the "addi.n as, 0" will eventually be widened back to an "addi 0"
   the "addi.n as, 0" will eventually be widened back to an "addi 0"
   after the widening table is applied.  Note: The usage of this table
   after the widening table is applied.  Note: The usage of this table
   has changed somewhat so that it is entirely specific to "narrowing"
   has changed somewhat so that it is entirely specific to "narrowing"
   instructions to use the density option.  This table is not used at
   instructions to use the density option.  This table is not used at
   all when the density option is not available.  */
   all when the density option is not available.  */
 
 
string_pattern_pair simplify_spec_list[] =
string_pattern_pair simplify_spec_list[] =
{
{
  {"add %ar,%as,%at ? IsaUseDensityInstruction", "add.n %ar,%as,%at"},
  {"add %ar,%as,%at ? IsaUseDensityInstruction", "add.n %ar,%as,%at"},
  {"addi.n %ar,%as,0 ? IsaUseDensityInstruction", "mov.n %ar,%as"},
  {"addi.n %ar,%as,0 ? IsaUseDensityInstruction", "mov.n %ar,%as"},
  {"addi %ar,%as,0 ? IsaUseDensityInstruction", "mov.n %ar,%as"},
  {"addi %ar,%as,0 ? IsaUseDensityInstruction", "mov.n %ar,%as"},
  {"addi %ar,%as,%imm ? IsaUseDensityInstruction", "addi.n %ar,%as,%imm"},
  {"addi %ar,%as,%imm ? IsaUseDensityInstruction", "addi.n %ar,%as,%imm"},
  {"addmi %ar,%as,%imm ? IsaUseDensityInstruction", "addi.n %ar,%as,%imm"},
  {"addmi %ar,%as,%imm ? IsaUseDensityInstruction", "addi.n %ar,%as,%imm"},
  {"beqz %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%label"},
  {"beqz %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%label"},
  {"bnez %as,%label ? IsaUseDensityInstruction", "bnez.n %as,%label"},
  {"bnez %as,%label ? IsaUseDensityInstruction", "bnez.n %as,%label"},
  {"l32i %at,%as,%imm ? IsaUseDensityInstruction", "l32i.n %at,%as,%imm"},
  {"l32i %at,%as,%imm ? IsaUseDensityInstruction", "l32i.n %at,%as,%imm"},
  {"movi %as,%imm ? IsaUseDensityInstruction", "movi.n %as,%imm"},
  {"movi %as,%imm ? IsaUseDensityInstruction", "movi.n %as,%imm"},
  {"nop ? realnop ? IsaUseDensityInstruction", "nop.n"},
  {"nop ? realnop ? IsaUseDensityInstruction", "nop.n"},
  {"or %ar,%as,%at | %ar==%as | %as==%at ? IsaUseDensityInstruction", "nop.n"},
  {"or %ar,%as,%at | %ar==%as | %as==%at ? IsaUseDensityInstruction", "nop.n"},
  {"or %ar,%as,%at | %ar!=%as | %as==%at ? IsaUseDensityInstruction", "mov.n %ar,%as"},
  {"or %ar,%as,%at | %ar!=%as | %as==%at ? IsaUseDensityInstruction", "mov.n %ar,%as"},
  {"ret %as ? IsaUseDensityInstruction", "ret.n %as"},
  {"ret %as ? IsaUseDensityInstruction", "ret.n %as"},
  {"retw %as ? IsaUseDensityInstruction", "retw.n %as"},
  {"retw %as ? IsaUseDensityInstruction", "retw.n %as"},
  {"s32i %at,%as,%imm ? IsaUseDensityInstruction", "s32i.n %at,%as,%imm"},
  {"s32i %at,%as,%imm ? IsaUseDensityInstruction", "s32i.n %at,%as,%imm"},
  {"slli %ar,%as,0 ? IsaUseDensityInstruction", "mov.n %ar,%as"}
  {"slli %ar,%as,0 ? IsaUseDensityInstruction", "mov.n %ar,%as"}
};
};
 
 
#define SIMPLIFY_COUNT \
#define SIMPLIFY_COUNT \
  (sizeof (simplify_spec_list) / sizeof (string_pattern_pair))
  (sizeof (simplify_spec_list) / sizeof (string_pattern_pair))
 
 


/* Externally visible functions.  */
/* Externally visible functions.  */
 
 
extern bfd_boolean xg_has_userdef_op_fn (OpType);
extern bfd_boolean xg_has_userdef_op_fn (OpType);
extern long xg_apply_userdef_op_fn (OpType, long);
extern long xg_apply_userdef_op_fn (OpType, long);
 
 
 
 
static void
static void
append_transition (TransitionTable *tt,
append_transition (TransitionTable *tt,
                   xtensa_opcode opcode,
                   xtensa_opcode opcode,
                   TransitionRule *t,
                   TransitionRule *t,
                   transition_cmp_fn cmp)
                   transition_cmp_fn cmp)
{
{
  TransitionList *tl = (TransitionList *) xmalloc (sizeof (TransitionList));
  TransitionList *tl = (TransitionList *) xmalloc (sizeof (TransitionList));
  TransitionList *prev;
  TransitionList *prev;
  TransitionList **t_p;
  TransitionList **t_p;
  assert (tt != NULL);
  assert (tt != NULL);
  assert (opcode < tt->num_opcodes);
  assert (opcode < tt->num_opcodes);
 
 
  prev = tt->table[opcode];
  prev = tt->table[opcode];
  tl->rule = t;
  tl->rule = t;
  tl->next = NULL;
  tl->next = NULL;
  if (prev == NULL)
  if (prev == NULL)
    {
    {
      tt->table[opcode] = tl;
      tt->table[opcode] = tl;
      return;
      return;
    }
    }
 
 
  for (t_p = &tt->table[opcode]; (*t_p) != NULL; t_p = &(*t_p)->next)
  for (t_p = &tt->table[opcode]; (*t_p) != NULL; t_p = &(*t_p)->next)
    {
    {
      if (cmp && cmp (t, (*t_p)->rule) < 0)
      if (cmp && cmp (t, (*t_p)->rule) < 0)
        {
        {
          /* Insert it here.  */
          /* Insert it here.  */
          tl->next = *t_p;
          tl->next = *t_p;
          *t_p = tl;
          *t_p = tl;
          return;
          return;
        }
        }
    }
    }
  (*t_p) = tl;
  (*t_p) = tl;
}
}
 
 
 
 
static void
static void
append_condition (TransitionRule *tr, Precondition *cond)
append_condition (TransitionRule *tr, Precondition *cond)
{
{
  PreconditionList *pl =
  PreconditionList *pl =
    (PreconditionList *) xmalloc (sizeof (PreconditionList));
    (PreconditionList *) xmalloc (sizeof (PreconditionList));
  PreconditionList *prev = tr->conditions;
  PreconditionList *prev = tr->conditions;
  PreconditionList *nxt;
  PreconditionList *nxt;
 
 
  pl->precond = cond;
  pl->precond = cond;
  pl->next = NULL;
  pl->next = NULL;
  if (prev == NULL)
  if (prev == NULL)
    {
    {
      tr->conditions = pl;
      tr->conditions = pl;
      return;
      return;
    }
    }
  nxt = prev->next;
  nxt = prev->next;
  while (nxt != NULL)
  while (nxt != NULL)
    {
    {
      prev = nxt;
      prev = nxt;
      nxt = nxt->next;
      nxt = nxt->next;
    }
    }
  prev->next = pl;
  prev->next = pl;
}
}
 
 
 
 
static void
static void
append_value_condition (TransitionRule *tr,
append_value_condition (TransitionRule *tr,
                        CmpOp cmp,
                        CmpOp cmp,
                        unsigned op1,
                        unsigned op1,
                        unsigned op2)
                        unsigned op2)
{
{
  Precondition *cond = (Precondition *) xmalloc (sizeof (Precondition));
  Precondition *cond = (Precondition *) xmalloc (sizeof (Precondition));
 
 
  cond->cmp = cmp;
  cond->cmp = cmp;
  cond->op_num = op1;
  cond->op_num = op1;
  cond->typ = OP_OPERAND;
  cond->typ = OP_OPERAND;
  cond->op_data = op2;
  cond->op_data = op2;
  append_condition (tr, cond);
  append_condition (tr, cond);
}
}
 
 
 
 
static void
static void
append_constant_value_condition (TransitionRule *tr,
append_constant_value_condition (TransitionRule *tr,
                                 CmpOp cmp,
                                 CmpOp cmp,
                                 unsigned op1,
                                 unsigned op1,
                                 unsigned cnst)
                                 unsigned cnst)
{
{
  Precondition *cond = (Precondition *) xmalloc (sizeof (Precondition));
  Precondition *cond = (Precondition *) xmalloc (sizeof (Precondition));
 
 
  cond->cmp = cmp;
  cond->cmp = cmp;
  cond->op_num = op1;
  cond->op_num = op1;
  cond->typ = OP_CONSTANT;
  cond->typ = OP_CONSTANT;
  cond->op_data = cnst;
  cond->op_data = cnst;
  append_condition (tr, cond);
  append_condition (tr, cond);
}
}
 
 
 
 
static void
static void
append_build_insn (TransitionRule *tr, BuildInstr *bi)
append_build_insn (TransitionRule *tr, BuildInstr *bi)
{
{
  BuildInstr *prev = tr->to_instr;
  BuildInstr *prev = tr->to_instr;
  BuildInstr *nxt;
  BuildInstr *nxt;
 
 
  bi->next = NULL;
  bi->next = NULL;
  if (prev == NULL)
  if (prev == NULL)
    {
    {
      tr->to_instr = bi;
      tr->to_instr = bi;
      return;
      return;
    }
    }
  nxt = prev->next;
  nxt = prev->next;
  while (nxt != 0)
  while (nxt != 0)
    {
    {
      prev = nxt;
      prev = nxt;
      nxt = prev->next;
      nxt = prev->next;
    }
    }
  prev->next = bi;
  prev->next = bi;
}
}
 
 
 
 
static void
static void
append_op (BuildInstr *bi, BuildOp *b_op)
append_op (BuildInstr *bi, BuildOp *b_op)
{
{
  BuildOp *prev = bi->ops;
  BuildOp *prev = bi->ops;
  BuildOp *nxt;
  BuildOp *nxt;
 
 
  if (prev == NULL)
  if (prev == NULL)
    {
    {
      bi->ops = b_op;
      bi->ops = b_op;
      return;
      return;
    }
    }
  nxt = prev->next;
  nxt = prev->next;
  while (nxt != NULL)
  while (nxt != NULL)
    {
    {
      prev = nxt;
      prev = nxt;
      nxt = nxt->next;
      nxt = nxt->next;
    }
    }
  prev->next = b_op;
  prev->next = b_op;
}
}
 
 
 
 
static void
static void
append_literal_op (BuildInstr *bi, unsigned op1)
append_literal_op (BuildInstr *bi, unsigned op1)
{
{
  BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp));
  BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp));
 
 
  b_op->op_num = op1;
  b_op->op_num = op1;
  b_op->typ = OP_LITERAL;
  b_op->typ = OP_LITERAL;
  b_op->op_data = 0;
  b_op->op_data = 0;
  b_op->next = NULL;
  b_op->next = NULL;
  append_op (bi, b_op);
  append_op (bi, b_op);
}
}
 
 
 
 
static void
static void
append_label_op (BuildInstr *bi, unsigned op1)
append_label_op (BuildInstr *bi, unsigned op1)
{
{
  BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp));
  BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp));
 
 
  b_op->op_num = op1;
  b_op->op_num = op1;
  b_op->typ = OP_LABEL;
  b_op->typ = OP_LABEL;
  b_op->op_data = 0;
  b_op->op_data = 0;
  b_op->next = NULL;
  b_op->next = NULL;
  append_op (bi, b_op);
  append_op (bi, b_op);
}
}
 
 
 
 
static void
static void
append_constant_op (BuildInstr *bi, unsigned op1, unsigned cnst)
append_constant_op (BuildInstr *bi, unsigned op1, unsigned cnst)
{
{
  BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp));
  BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp));
 
 
  b_op->op_num = op1;
  b_op->op_num = op1;
  b_op->typ = OP_CONSTANT;
  b_op->typ = OP_CONSTANT;
  b_op->op_data = cnst;
  b_op->op_data = cnst;
  b_op->next = NULL;
  b_op->next = NULL;
  append_op (bi, b_op);
  append_op (bi, b_op);
}
}
 
 
 
 
static void
static void
append_field_op (BuildInstr *bi, unsigned op1, unsigned src_op)
append_field_op (BuildInstr *bi, unsigned op1, unsigned src_op)
{
{
  BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp));
  BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp));
 
 
  b_op->op_num = op1;
  b_op->op_num = op1;
  b_op->typ = OP_OPERAND;
  b_op->typ = OP_OPERAND;
  b_op->op_data = src_op;
  b_op->op_data = src_op;
  b_op->next = NULL;
  b_op->next = NULL;
  append_op (bi, b_op);
  append_op (bi, b_op);
}
}
 
 
 
 
/* These could be generated but are not currently.  */
/* These could be generated but are not currently.  */
 
 
static void
static void
append_user_fn_field_op (BuildInstr *bi,
append_user_fn_field_op (BuildInstr *bi,
                         unsigned op1,
                         unsigned op1,
                         OpType typ,
                         OpType typ,
                         unsigned src_op)
                         unsigned src_op)
{
{
  BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp));
  BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp));
 
 
  b_op->op_num = op1;
  b_op->op_num = op1;
  b_op->typ = typ;
  b_op->typ = typ;
  b_op->op_data = src_op;
  b_op->op_data = src_op;
  b_op->next = NULL;
  b_op->next = NULL;
  append_op (bi, b_op);
  append_op (bi, b_op);
}
}
 
 
 
 
/* These operand functions are the semantics of user-defined
/* These operand functions are the semantics of user-defined
   operand functions.  */
   operand functions.  */
 
 
static long
static long
operand_function_HI24S (long a)
operand_function_HI24S (long a)
{
{
  if (a & 0x80)
  if (a & 0x80)
    return (a & (~0xff)) + 0x100;
    return (a & (~0xff)) + 0x100;
  else
  else
    return (a & (~0xff));
    return (a & (~0xff));
}
}
 
 
 
 
static long
static long
operand_function_F32MINUS (long a)
operand_function_F32MINUS (long a)
{
{
  return (32 - a);
  return (32 - a);
}
}
 
 
 
 
static long
static long
operand_function_LOW8 (long a)
operand_function_LOW8 (long a)
{
{
  if (a & 0x80)
  if (a & 0x80)
    return (a & 0xff) | ~0xff;
    return (a & 0xff) | ~0xff;
  else
  else
    return (a & 0xff);
    return (a & 0xff);
}
}
 
 
 
 
static long
static long
operand_function_LOW16U (long a)
operand_function_LOW16U (long a)
{
{
  return (a & 0xffff);
  return (a & 0xffff);
}
}
 
 
 
 
static long
static long
operand_function_HI16U (long a)
operand_function_HI16U (long a)
{
{
  unsigned long b = a & 0xffff0000;
  unsigned long b = a & 0xffff0000;
  return (long) (b >> 16);
  return (long) (b >> 16);
}
}
 
 
 
 
bfd_boolean
bfd_boolean
xg_has_userdef_op_fn (OpType op)
xg_has_userdef_op_fn (OpType op)
{
{
  switch (op)
  switch (op)
    {
    {
    case OP_OPERAND_F32MINUS:
    case OP_OPERAND_F32MINUS:
    case OP_OPERAND_LOW8:
    case OP_OPERAND_LOW8:
    case OP_OPERAND_HI24S:
    case OP_OPERAND_HI24S:
    case OP_OPERAND_LOW16U:
    case OP_OPERAND_LOW16U:
    case OP_OPERAND_HI16U:
    case OP_OPERAND_HI16U:
      return TRUE;
      return TRUE;
    default:
    default:
      break;
      break;
    }
    }
  return FALSE;
  return FALSE;
}
}
 
 
 
 
long
long
xg_apply_userdef_op_fn (OpType op, long a)
xg_apply_userdef_op_fn (OpType op, long a)
{
{
  switch (op)
  switch (op)
    {
    {
    case OP_OPERAND_F32MINUS:
    case OP_OPERAND_F32MINUS:
      return operand_function_F32MINUS (a);
      return operand_function_F32MINUS (a);
    case OP_OPERAND_LOW8:
    case OP_OPERAND_LOW8:
      return operand_function_LOW8 (a);
      return operand_function_LOW8 (a);
    case OP_OPERAND_HI24S:
    case OP_OPERAND_HI24S:
      return operand_function_HI24S (a);
      return operand_function_HI24S (a);
    case OP_OPERAND_LOW16U:
    case OP_OPERAND_LOW16U:
      return operand_function_LOW16U (a);
      return operand_function_LOW16U (a);
    case OP_OPERAND_HI16U:
    case OP_OPERAND_HI16U:
      return operand_function_HI16U (a);
      return operand_function_HI16U (a);
    default:
    default:
      break;
      break;
    }
    }
  return FALSE;
  return FALSE;
}
}
 
 
 
 
/* Generate a transition table.  */
/* Generate a transition table.  */
 
 
static const char *
static const char *
enter_opname_n (const char *name, int len)
enter_opname_n (const char *name, int len)
{
{
  opname_e *op;
  opname_e *op;
 
 
  for (op = local_opnames; op != NULL; op = op->next)
  for (op = local_opnames; op != NULL; op = op->next)
    {
    {
      if (strlen (op->opname) == (unsigned) len
      if (strlen (op->opname) == (unsigned) len
          && strncmp (op->opname, name, len) == 0)
          && strncmp (op->opname, name, len) == 0)
        return op->opname;
        return op->opname;
    }
    }
  op = (opname_e *) xmalloc (sizeof (opname_e));
  op = (opname_e *) xmalloc (sizeof (opname_e));
  op->opname = (char *) xmalloc (len + 1);
  op->opname = (char *) xmalloc (len + 1);
  strncpy (op->opname, name, len);
  strncpy (op->opname, name, len);
  op->opname[len] = '\0';
  op->opname[len] = '\0';
  return op->opname;
  return op->opname;
}
}
 
 
 
 
static const char *
static const char *
enter_opname (const char *name)
enter_opname (const char *name)
{
{
  opname_e *op;
  opname_e *op;
 
 
  for (op = local_opnames; op != NULL; op = op->next)
  for (op = local_opnames; op != NULL; op = op->next)
    {
    {
      if (strcmp (op->opname, name) == 0)
      if (strcmp (op->opname, name) == 0)
        return op->opname;
        return op->opname;
    }
    }
  op = (opname_e *) xmalloc (sizeof (opname_e));
  op = (opname_e *) xmalloc (sizeof (opname_e));
  op->opname = xstrdup (name);
  op->opname = xstrdup (name);
  return op->opname;
  return op->opname;
}
}
 
 
 
 
static void
static void
init_opname_map (opname_map *m)
init_opname_map (opname_map *m)
{
{
  m->head = NULL;
  m->head = NULL;
  m->tail = &m->head;
  m->tail = &m->head;
}
}
 
 
 
 
static void
static void
clear_opname_map (opname_map *m)
clear_opname_map (opname_map *m)
{
{
  opname_map_e *e;
  opname_map_e *e;
 
 
  while (m->head != NULL)
  while (m->head != NULL)
    {
    {
      e = m->head;
      e = m->head;
      m->head = e->next;
      m->head = e->next;
      free (e);
      free (e);
    }
    }
  m->tail = &m->head;
  m->tail = &m->head;
}
}
 
 
 
 
static bfd_boolean
static bfd_boolean
same_operand_name (const opname_map_e *m1, const opname_map_e *m2)
same_operand_name (const opname_map_e *m1, const opname_map_e *m2)
{
{
  if (m1->operand_name == NULL || m1->operand_name == NULL)
  if (m1->operand_name == NULL || m1->operand_name == NULL)
    return FALSE;
    return FALSE;
  return (m1->operand_name == m2->operand_name);
  return (m1->operand_name == m2->operand_name);
}
}
 
 
 
 
static opname_map_e *
static opname_map_e *
get_opmatch (opname_map *map, const char *operand_name)
get_opmatch (opname_map *map, const char *operand_name)
{
{
  opname_map_e *m;
  opname_map_e *m;
 
 
  for (m = map->head; m != NULL; m = m->next)
  for (m = map->head; m != NULL; m = m->next)
    {
    {
      if (strcmp (m->operand_name, operand_name) == 0)
      if (strcmp (m->operand_name, operand_name) == 0)
        return m;
        return m;
    }
    }
  return NULL;
  return NULL;
}
}
 
 
 
 
static bfd_boolean
static bfd_boolean
op_is_constant (const opname_map_e *m1)
op_is_constant (const opname_map_e *m1)
{
{
  return (m1->operand_name == NULL);
  return (m1->operand_name == NULL);
}
}
 
 
 
 
static unsigned
static unsigned
op_get_constant (const opname_map_e *m1)
op_get_constant (const opname_map_e *m1)
{
{
  assert (m1->operand_name == NULL);
  assert (m1->operand_name == NULL);
  return m1->constant_value;
  return m1->constant_value;
}
}
 
 
 
 
static void
static void
init_precond_list (precond_list *l)
init_precond_list (precond_list *l)
{
{
  l->head = NULL;
  l->head = NULL;
  l->tail = &l->head;
  l->tail = &l->head;
}
}
 
 
 
 
static void
static void
clear_precond_list (precond_list *l)
clear_precond_list (precond_list *l)
{
{
  precond_e *e;
  precond_e *e;
 
 
  while (l->head != NULL)
  while (l->head != NULL)
    {
    {
      e = l->head;
      e = l->head;
      l->head = e->next;
      l->head = e->next;
      free (e);
      free (e);
    }
    }
  l->tail = &l->head;
  l->tail = &l->head;
}
}
 
 
 
 
static void
static void
init_insn_templ (insn_templ *t)
init_insn_templ (insn_templ *t)
{
{
  t->opcode_name = NULL;
  t->opcode_name = NULL;
  init_opname_map (&t->operand_map);
  init_opname_map (&t->operand_map);
}
}
 
 
 
 
static void
static void
clear_insn_templ (insn_templ *t)
clear_insn_templ (insn_templ *t)
{
{
  clear_opname_map (&t->operand_map);
  clear_opname_map (&t->operand_map);
}
}
 
 
 
 
static void
static void
init_insn_pattern (insn_pattern *p)
init_insn_pattern (insn_pattern *p)
{
{
  init_insn_templ (&p->t);
  init_insn_templ (&p->t);
  init_precond_list (&p->preconds);
  init_precond_list (&p->preconds);
  p->options = NULL;
  p->options = NULL;
}
}
 
 
 
 
static void
static void
clear_insn_pattern (insn_pattern *p)
clear_insn_pattern (insn_pattern *p)
{
{
  clear_insn_templ (&p->t);
  clear_insn_templ (&p->t);
  clear_precond_list (&p->preconds);
  clear_precond_list (&p->preconds);
}
}
 
 
 
 
static void
static void
init_insn_repl (insn_repl *r)
init_insn_repl (insn_repl *r)
{
{
  r->head = NULL;
  r->head = NULL;
  r->tail = &r->head;
  r->tail = &r->head;
}
}
 
 
 
 
static void
static void
clear_insn_repl (insn_repl *r)
clear_insn_repl (insn_repl *r)
{
{
  insn_repl_e *e;
  insn_repl_e *e;
 
 
  while (r->head != NULL)
  while (r->head != NULL)
    {
    {
      e = r->head;
      e = r->head;
      r->head = e->next;
      r->head = e->next;
      clear_insn_templ (&e->t);
      clear_insn_templ (&e->t);
    }
    }
  r->tail = &r->head;
  r->tail = &r->head;
}
}
 
 
 
 
static int
static int
insn_templ_operand_count (const insn_templ *t)
insn_templ_operand_count (const insn_templ *t)
{
{
  int i = 0;
  int i = 0;
  const opname_map_e *op;
  const opname_map_e *op;
 
 
  for (op = t->operand_map.head; op != NULL; op = op->next, i++)
  for (op = t->operand_map.head; op != NULL; op = op->next, i++)
    ;
    ;
  return i;
  return i;
}
}
 
 
 
 
/* Convert a string to a number.  E.G.: parse_constant("10", &num) */
/* Convert a string to a number.  E.G.: parse_constant("10", &num) */
 
 
static bfd_boolean
static bfd_boolean
parse_constant (const char *in, unsigned *val_p)
parse_constant (const char *in, unsigned *val_p)
{
{
  unsigned val = 0;
  unsigned val = 0;
  const char *p;
  const char *p;
 
 
  if (in == NULL)
  if (in == NULL)
    return FALSE;
    return FALSE;
  p = in;
  p = in;
 
 
  while (*p != '\0')
  while (*p != '\0')
    {
    {
      if (*p >= '0' && *p <= '9')
      if (*p >= '0' && *p <= '9')
        val = val * 10 + (*p - '0');
        val = val * 10 + (*p - '0');
      else
      else
        return FALSE;
        return FALSE;
      ++p;
      ++p;
    }
    }
  *val_p = val;
  *val_p = val;
  return TRUE;
  return TRUE;
}
}
 
 
 
 
static bfd_boolean
static bfd_boolean
parse_special_fn (const char *name,
parse_special_fn (const char *name,
                  const char **fn_name_p,
                  const char **fn_name_p,
                  const char **arg_name_p)
                  const char **arg_name_p)
{
{
  char *p_start;
  char *p_start;
  const char *p_end;
  const char *p_end;
 
 
  p_start = strchr (name, '(');
  p_start = strchr (name, '(');
  if (p_start == NULL)
  if (p_start == NULL)
    return FALSE;
    return FALSE;
 
 
  p_end = strchr (p_start, ')');
  p_end = strchr (p_start, ')');
 
 
  if (p_end == NULL)
  if (p_end == NULL)
    return FALSE;
    return FALSE;
 
 
  if (p_end[1] != '\0')
  if (p_end[1] != '\0')
    return FALSE;
    return FALSE;
 
 
  *fn_name_p = enter_opname_n (name, p_start - name);
  *fn_name_p = enter_opname_n (name, p_start - name);
  *arg_name_p = enter_opname_n (p_start + 1, p_end - p_start - 1);
  *arg_name_p = enter_opname_n (p_start + 1, p_end - p_start - 1);
  return TRUE;
  return TRUE;
}
}
 
 
 
 
static const char *
static const char *
skip_white (const char *p)
skip_white (const char *p)
{
{
  if (p == NULL)
  if (p == NULL)
    return p;
    return p;
  while (*p == ' ')
  while (*p == ' ')
    ++p;
    ++p;
  return p;
  return p;
}
}
 
 
 
 
static void
static void
trim_whitespace (char *in)
trim_whitespace (char *in)
{
{
  char *last_white = NULL;
  char *last_white = NULL;
  char *p = in;
  char *p = in;
 
 
  while (p && *p != '\0')
  while (p && *p != '\0')
    {
    {
      while (*p == ' ')
      while (*p == ' ')
        {
        {
          if (last_white == NULL)
          if (last_white == NULL)
            last_white = p;
            last_white = p;
          p++;
          p++;
        }
        }
      if (*p != '\0')
      if (*p != '\0')
        {
        {
          last_white = NULL;
          last_white = NULL;
          p++;
          p++;
        }
        }
    }
    }
  if (last_white)
  if (last_white)
    *last_white = '\0';
    *last_white = '\0';
}
}
 
 
 
 
/* Split a string into component strings where "c" is the
/* Split a string into component strings where "c" is the
   delimiter.  Place the result in the split_rec.  */
   delimiter.  Place the result in the split_rec.  */
 
 
static void
static void
split_string (split_rec *rec,
split_string (split_rec *rec,
              const char *in,
              const char *in,
              char c,
              char c,
              bfd_boolean elide_whitespace)
              bfd_boolean elide_whitespace)
{
{
  int cnt = 0;
  int cnt = 0;
  int i;
  int i;
  const char *p = in;
  const char *p = in;
 
 
  while (p != NULL && *p != '\0')
  while (p != NULL && *p != '\0')
    {
    {
      cnt++;
      cnt++;
      p = strchr (p, c);
      p = strchr (p, c);
      if (p)
      if (p)
        p++;
        p++;
    }
    }
  rec->count = cnt;
  rec->count = cnt;
  rec->vec = NULL;
  rec->vec = NULL;
 
 
  if (rec->count == 0)
  if (rec->count == 0)
    return;
    return;
 
 
  rec->vec = (char **) xmalloc (sizeof (char *) * cnt);
  rec->vec = (char **) xmalloc (sizeof (char *) * cnt);
  for (i = 0; i < cnt; i++)
  for (i = 0; i < cnt; i++)
    rec->vec[i] = 0;
    rec->vec[i] = 0;
 
 
  p = in;
  p = in;
  for (i = 0; i < cnt; i++)
  for (i = 0; i < cnt; i++)
    {
    {
      const char *q;
      const char *q;
      int len;
      int len;
 
 
      q = p;
      q = p;
      if (elide_whitespace)
      if (elide_whitespace)
        q = skip_white (q);
        q = skip_white (q);
 
 
      p = strchr (q, c);
      p = strchr (q, c);
      if (p == NULL)
      if (p == NULL)
        rec->vec[i] = xstrdup (q);
        rec->vec[i] = xstrdup (q);
      else
      else
        {
        {
          len = p - q;
          len = p - q;
          rec->vec[i] = (char *) xmalloc (sizeof (char) * (len + 1));
          rec->vec[i] = (char *) xmalloc (sizeof (char) * (len + 1));
          strncpy (rec->vec[i], q, len);
          strncpy (rec->vec[i], q, len);
          rec->vec[i][len] = '\0';
          rec->vec[i][len] = '\0';
          p++;
          p++;
        }
        }
 
 
      if (elide_whitespace)
      if (elide_whitespace)
        trim_whitespace (rec->vec[i]);
        trim_whitespace (rec->vec[i]);
    }
    }
}
}
 
 
 
 
static void
static void
clear_split_rec (split_rec *rec)
clear_split_rec (split_rec *rec)
{
{
  int i;
  int i;
 
 
  for (i = 0; i < rec->count; i++)
  for (i = 0; i < rec->count; i++)
    free (rec->vec[i]);
    free (rec->vec[i]);
 
 
  if (rec->count > 0)
  if (rec->count > 0)
    free (rec->vec);
    free (rec->vec);
}
}
 
 
 
 
/* Initialize a split record.  The split record must be initialized
/* Initialize a split record.  The split record must be initialized
   before split_string is called.  */
   before split_string is called.  */
 
 
static void
static void
init_split_rec (split_rec *rec)
init_split_rec (split_rec *rec)
{
{
  rec->vec = NULL;
  rec->vec = NULL;
  rec->count = 0;
  rec->count = 0;
}
}
 
 
 
 
/* Parse an instruction template like "insn op1, op2, op3".  */
/* Parse an instruction template like "insn op1, op2, op3".  */
 
 
static bfd_boolean
static bfd_boolean
parse_insn_templ (const char *s, insn_templ *t)
parse_insn_templ (const char *s, insn_templ *t)
{
{
  const char *p = s;
  const char *p = s;
  int insn_name_len;
  int insn_name_len;
  split_rec oprec;
  split_rec oprec;
  int i;
  int i;
 
 
  /* First find the first whitespace.  */
  /* First find the first whitespace.  */
 
 
  init_split_rec (&oprec);
  init_split_rec (&oprec);
 
 
  p = skip_white (p);
  p = skip_white (p);
  insn_name_len = strcspn (s, " ");
  insn_name_len = strcspn (s, " ");
  if (insn_name_len == 0)
  if (insn_name_len == 0)
    return FALSE;
    return FALSE;
 
 
  init_insn_templ (t);
  init_insn_templ (t);
  t->opcode_name = enter_opname_n (p, insn_name_len);
  t->opcode_name = enter_opname_n (p, insn_name_len);
 
 
  p = p + insn_name_len;
  p = p + insn_name_len;
 
 
  /* Split by ',' and skip beginning and trailing whitespace.  */
  /* 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++)
  for (i = 0; i < oprec.count; i++)
    {
    {
      const char *opname = oprec.vec[i];
      const char *opname = oprec.vec[i];
      opname_map_e *e = (opname_map_e *) xmalloc (sizeof (opname_map_e));
      opname_map_e *e = (opname_map_e *) xmalloc (sizeof (opname_map_e));
      e->next = NULL;
      e->next = NULL;
      e->operand_name = NULL;
      e->operand_name = NULL;
      e->constant_value = 0;
      e->constant_value = 0;
      e->operand_num = i;
      e->operand_num = i;
 
 
      /* If it begins with a number, assume that it is a number.  */
      /* If it begins with a number, assume that it is a number.  */
      if (opname && opname[0] >= '0' && opname[0] <= '9')
      if (opname && opname[0] >= '0' && opname[0] <= '9')
        {
        {
          unsigned val;
          unsigned val;
 
 
          if (parse_constant (opname, &val))
          if (parse_constant (opname, &val))
            e->constant_value = val;
            e->constant_value = val;
          else
          else
            {
            {
              free (e);
              free (e);
              clear_split_rec (&oprec);
              clear_split_rec (&oprec);
              clear_insn_templ (t);
              clear_insn_templ (t);
              return FALSE;
              return FALSE;
            }
            }
        }
        }
      else
      else
        e->operand_name = enter_opname (oprec.vec[i]);
        e->operand_name = enter_opname (oprec.vec[i]);
 
 
      *t->operand_map.tail = e;
      *t->operand_map.tail = e;
      t->operand_map.tail = &e->next;
      t->operand_map.tail = &e->next;
    }
    }
  clear_split_rec (&oprec);
  clear_split_rec (&oprec);
  return TRUE;
  return TRUE;
}
}
 
 
 
 
static bfd_boolean
static bfd_boolean
parse_precond (const char *s, precond_e *precond)
parse_precond (const char *s, precond_e *precond)
{
{
  /* All preconditions are currently of the form:
  /* All preconditions are currently of the form:
     a == b or a != b or a == k (where k is a constant).
     a == b or a != b or a == k (where k is a constant).
     Later we may use some special functions like DENSITY == 1
     Later we may use some special functions like DENSITY == 1
     to identify when density is available.  */
     to identify when density is available.  */
 
 
  const char *p = s;
  const char *p = s;
  int len;
  int len;
  precond->opname1 = NULL;
  precond->opname1 = NULL;
  precond->opval1 = 0;
  precond->opval1 = 0;
  precond->cmpop = OP_EQUAL;
  precond->cmpop = OP_EQUAL;
  precond->opname2 = NULL;
  precond->opname2 = NULL;
  precond->opval2 = 0;
  precond->opval2 = 0;
  precond->next = NULL;
  precond->next = NULL;
 
 
  p = skip_white (p);
  p = skip_white (p);
 
 
  len = strcspn (p, " !=");
  len = strcspn (p, " !=");
 
 
  if (len == 0)
  if (len == 0)
    return FALSE;
    return FALSE;
 
 
  precond->opname1 = enter_opname_n (p, len);
  precond->opname1 = enter_opname_n (p, len);
  p = p + len;
  p = p + len;
  p = skip_white (p);
  p = skip_white (p);
 
 
  /* Check for "==" and "!=".  */
  /* Check for "==" and "!=".  */
  if (strncmp (p, "==", 2) == 0)
  if (strncmp (p, "==", 2) == 0)
    precond->cmpop = OP_EQUAL;
    precond->cmpop = OP_EQUAL;
  else if (strncmp (p, "!=", 2) == 0)
  else if (strncmp (p, "!=", 2) == 0)
    precond->cmpop = OP_NOTEQUAL;
    precond->cmpop = OP_NOTEQUAL;
  else
  else
    return FALSE;
    return FALSE;
 
 
  p = p + 2;
  p = p + 2;
  p = skip_white (p);
  p = skip_white (p);
 
 
  /* No trailing whitespace from earlier parsing.  */
  /* No trailing whitespace from earlier parsing.  */
  if (p[0] >= '0' && p[0] <= '9')
  if (p[0] >= '0' && p[0] <= '9')
    {
    {
      unsigned val;
      unsigned val;
      if (parse_constant (p, &val))
      if (parse_constant (p, &val))
        precond->opval2 = val;
        precond->opval2 = val;
      else
      else
        return FALSE;
        return FALSE;
    }
    }
  else
  else
    precond->opname2 = enter_opname (p);
    precond->opname2 = enter_opname (p);
  return TRUE;
  return TRUE;
}
}
 
 
 
 
static void
static void
clear_req_or_option_list (ReqOrOption **r_p)
clear_req_or_option_list (ReqOrOption **r_p)
{
{
  if (*r_p == NULL)
  if (*r_p == NULL)
    return;
    return;
 
 
  free ((*r_p)->option_name);
  free ((*r_p)->option_name);
  clear_req_or_option_list (&(*r_p)->next);
  clear_req_or_option_list (&(*r_p)->next);
  *r_p = NULL;
  *r_p = NULL;
}
}
 
 
 
 
static void
static void
clear_req_option_list (ReqOption **r_p)
clear_req_option_list (ReqOption **r_p)
{
{
  if (*r_p == NULL)
  if (*r_p == NULL)
    return;
    return;
 
 
  clear_req_or_option_list (&(*r_p)->or_option_terms);
  clear_req_or_option_list (&(*r_p)->or_option_terms);
  clear_req_option_list (&(*r_p)->next);
  clear_req_option_list (&(*r_p)->next);
  *r_p = NULL;
  *r_p = NULL;
}
}
 
 
 
 
static ReqOrOption *
static ReqOrOption *
clone_req_or_option_list (ReqOrOption *req_or_option)
clone_req_or_option_list (ReqOrOption *req_or_option)
{
{
  ReqOrOption *new_req_or_option;
  ReqOrOption *new_req_or_option;
 
 
  if (req_or_option == NULL)
  if (req_or_option == NULL)
    return NULL;
    return NULL;
 
 
  new_req_or_option = (ReqOrOption *) xmalloc (sizeof (ReqOrOption));
  new_req_or_option = (ReqOrOption *) xmalloc (sizeof (ReqOrOption));
  new_req_or_option->option_name = xstrdup (req_or_option->option_name);
  new_req_or_option->option_name = xstrdup (req_or_option->option_name);
  new_req_or_option->is_true = req_or_option->is_true;
  new_req_or_option->is_true = req_or_option->is_true;
  new_req_or_option->next = NULL;
  new_req_or_option->next = NULL;
  new_req_or_option->next = clone_req_or_option_list (req_or_option->next);
  new_req_or_option->next = clone_req_or_option_list (req_or_option->next);
  return new_req_or_option;
  return new_req_or_option;
}
}
 
 
 
 
static ReqOption *
static ReqOption *
clone_req_option_list (ReqOption *req_option)
clone_req_option_list (ReqOption *req_option)
{
{
  ReqOption *new_req_option;
  ReqOption *new_req_option;
 
 
  if (req_option == NULL)
  if (req_option == NULL)
    return NULL;
    return NULL;
 
 
  new_req_option = (ReqOption *) xmalloc (sizeof (ReqOption));
  new_req_option = (ReqOption *) xmalloc (sizeof (ReqOption));
  new_req_option->or_option_terms = NULL;
  new_req_option->or_option_terms = NULL;
  new_req_option->next = NULL;
  new_req_option->next = NULL;
  new_req_option->or_option_terms =
  new_req_option->or_option_terms =
    clone_req_or_option_list (req_option->or_option_terms);
    clone_req_or_option_list (req_option->or_option_terms);
  new_req_option->next = clone_req_option_list (req_option->next);
  new_req_option->next = clone_req_option_list (req_option->next);
  return new_req_option;
  return new_req_option;
}
}
 
 
 
 
static bfd_boolean
static bfd_boolean
parse_option_cond (const char *s, ReqOption *option)
parse_option_cond (const char *s, ReqOption *option)
{
{
  int i;
  int i;
  split_rec option_term_rec;
  split_rec option_term_rec;
 
 
  /* All option or conditions are of the form:
  /* All option or conditions are of the form:
     optionA + no-optionB + ...
     optionA + no-optionB + ...
     "Ands" are divided by "?".  */
     "Ands" are divided by "?".  */
 
 
  init_split_rec (&option_term_rec);
  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)
  if (option_term_rec.count == 0)
    {
    {
      clear_split_rec (&option_term_rec);
      clear_split_rec (&option_term_rec);
      return FALSE;
      return FALSE;
    }
    }
 
 
  for (i = 0; i < option_term_rec.count; i++)
  for (i = 0; i < option_term_rec.count; i++)
    {
    {
      char *option_name = option_term_rec.vec[i];
      char *option_name = option_term_rec.vec[i];
      bfd_boolean is_true = TRUE;
      bfd_boolean is_true = TRUE;
      ReqOrOption *req;
      ReqOrOption *req;
      ReqOrOption **r_p;
      ReqOrOption **r_p;
 
 
      if (strncmp (option_name, "no-", 3) == 0)
      if (strncmp (option_name, "no-", 3) == 0)
        {
        {
          option_name = xstrdup (&option_name[3]);
          option_name = xstrdup (&option_name[3]);
          is_true = FALSE;
          is_true = FALSE;
        }
        }
      else
      else
        option_name = xstrdup (option_name);
        option_name = xstrdup (option_name);
 
 
      req = (ReqOrOption *) xmalloc (sizeof (ReqOrOption));
      req = (ReqOrOption *) xmalloc (sizeof (ReqOrOption));
      req->option_name = option_name;
      req->option_name = option_name;
      req->is_true = is_true;
      req->is_true = is_true;
      req->next = NULL;
      req->next = NULL;
 
 
      /* Append to list.  */
      /* Append to list.  */
      for (r_p = &option->or_option_terms; (*r_p) != NULL;
      for (r_p = &option->or_option_terms; (*r_p) != NULL;
           r_p = &(*r_p)->next)
           r_p = &(*r_p)->next)
        ;
        ;
      (*r_p) = req;
      (*r_p) = req;
    }
    }
  return TRUE;
  return TRUE;
}
}
 
 
 
 
/* Parse a string like:
/* Parse a string like:
   "insn op1, op2, op3, op4 | op1 != op2 | op2 == op3 | op4 == 1".
   "insn op1, op2, op3, op4 | op1 != op2 | op2 == op3 | op4 == 1".
   I.E., instruction "insn" with 4 operands where operand 1 and 2 are not
   I.E., instruction "insn" with 4 operands where operand 1 and 2 are not
   the same and operand 2 and 3 are the same and operand 4 is 1.
   the same and operand 2 and 3 are the same and operand 4 is 1.
 
 
   or:
   or:
 
 
   "insn op1 | op1 == 1 / density + boolean / no-useroption".
   "insn op1 | op1 == 1 / density + boolean / no-useroption".
   i.e. instruction "insn" with 1 operands where operand 1 is 1
   i.e. instruction "insn" with 1 operands where operand 1 is 1
   when "density" or "boolean" options are available and
   when "density" or "boolean" options are available and
   "useroption" is not available.
   "useroption" is not available.
 
 
   Because the current implementation of this parsing scheme uses
   Because the current implementation of this parsing scheme uses
   split_string, it requires that '|' and '?' are only used as
   split_string, it requires that '|' and '?' are only used as
   delimiters for predicates and required options.  */
   delimiters for predicates and required options.  */
 
 
static bfd_boolean
static bfd_boolean
parse_insn_pattern (const char *in, insn_pattern *insn)
parse_insn_pattern (const char *in, insn_pattern *insn)
{
{
  split_rec rec;
  split_rec rec;
  split_rec optionrec;
  split_rec optionrec;
  int i;
  int i;
 
 
  init_insn_pattern (insn);
  init_insn_pattern (insn);
 
 
  init_split_rec (&optionrec);
  init_split_rec (&optionrec);
  split_string (&optionrec, in, '?', TRUE);
  split_string (&optionrec, in, '?', TRUE);
  if (optionrec.count == 0)
  if (optionrec.count == 0)
    {
    {
      clear_split_rec (&optionrec);
      clear_split_rec (&optionrec);
      return FALSE;
      return FALSE;
    }
    }
 
 
  init_split_rec (&rec);
  init_split_rec (&rec);
 
 
  split_string (&rec, optionrec.vec[0], '|', TRUE);
  split_string (&rec, optionrec.vec[0], '|', TRUE);
 
 
  if (rec.count == 0)
  if (rec.count == 0)
    {
    {
      clear_split_rec (&rec);
      clear_split_rec (&rec);
      clear_split_rec (&optionrec);
      clear_split_rec (&optionrec);
      return FALSE;
      return FALSE;
    }
    }
 
 
  if (!parse_insn_templ (rec.vec[0], &insn->t))
  if (!parse_insn_templ (rec.vec[0], &insn->t))
    {
    {
      clear_split_rec (&rec);
      clear_split_rec (&rec);
      clear_split_rec (&optionrec);
      clear_split_rec (&optionrec);
      return FALSE;
      return FALSE;
    }
    }
 
 
  for (i = 1; i < rec.count; i++)
  for (i = 1; i < rec.count; i++)
    {
    {
      precond_e *cond = (precond_e *) xmalloc (sizeof (precond_e));
      precond_e *cond = (precond_e *) xmalloc (sizeof (precond_e));
 
 
      if (!parse_precond (rec.vec[i], cond))
      if (!parse_precond (rec.vec[i], cond))
        {
        {
          clear_split_rec (&rec);
          clear_split_rec (&rec);
          clear_split_rec (&optionrec);
          clear_split_rec (&optionrec);
          clear_insn_pattern (insn);
          clear_insn_pattern (insn);
          return FALSE;
          return FALSE;
        }
        }
 
 
      /* Append the condition.  */
      /* Append the condition.  */
      *insn->preconds.tail = cond;
      *insn->preconds.tail = cond;
      insn->preconds.tail = &cond->next;
      insn->preconds.tail = &cond->next;
    }
    }
 
 
  for (i = 1; i < optionrec.count; i++)
  for (i = 1; i < optionrec.count; i++)
    {
    {
      /* Handle the option conditions.  */
      /* Handle the option conditions.  */
      ReqOption **r_p;
      ReqOption **r_p;
      ReqOption *req_option = (ReqOption *) xmalloc (sizeof (ReqOption));
      ReqOption *req_option = (ReqOption *) xmalloc (sizeof (ReqOption));
      req_option->or_option_terms = NULL;
      req_option->or_option_terms = NULL;
      req_option->next = NULL;
      req_option->next = NULL;
 
 
      if (!parse_option_cond (optionrec.vec[i], req_option))
      if (!parse_option_cond (optionrec.vec[i], req_option))
        {
        {
          clear_split_rec (&rec);
          clear_split_rec (&rec);
          clear_split_rec (&optionrec);
          clear_split_rec (&optionrec);
          clear_insn_pattern (insn);
          clear_insn_pattern (insn);
          clear_req_option_list (&req_option);
          clear_req_option_list (&req_option);
          return FALSE;
          return FALSE;
        }
        }
 
 
      /* Append the condition.  */
      /* Append the condition.  */
      for (r_p = &insn->options; (*r_p) != NULL; r_p = &(*r_p)->next)
      for (r_p = &insn->options; (*r_p) != NULL; r_p = &(*r_p)->next)
        ;
        ;
 
 
      (*r_p) = req_option;
      (*r_p) = req_option;
    }
    }
 
 
  clear_split_rec (&rec);
  clear_split_rec (&rec);
  clear_split_rec (&optionrec);
  clear_split_rec (&optionrec);
  return TRUE;
  return TRUE;
}
}
 
 
 
 
static bfd_boolean
static bfd_boolean
parse_insn_repl (const char *in, insn_repl *r_p)
parse_insn_repl (const char *in, insn_repl *r_p)
{
{
  /* This is a list of instruction templates separated by ';'.  */
  /* This is a list of instruction templates separated by ';'.  */
  split_rec rec;
  split_rec rec;
  int i;
  int i;
 
 
  split_string (&rec, in, ';', TRUE);
  split_string (&rec, in, ';', TRUE);
 
 
  for (i = 0; i < rec.count; i++)
  for (i = 0; i < rec.count; i++)
    {
    {
      insn_repl_e *e = (insn_repl_e *) xmalloc (sizeof (insn_repl_e));
      insn_repl_e *e = (insn_repl_e *) xmalloc (sizeof (insn_repl_e));
 
 
      e->next = NULL;
      e->next = NULL;
 
 
      if (!parse_insn_templ (rec.vec[i], &e->t))
      if (!parse_insn_templ (rec.vec[i], &e->t))
        {
        {
          free (e);
          free (e);
          clear_insn_repl (r_p);
          clear_insn_repl (r_p);
          return FALSE;
          return FALSE;
        }
        }
      *r_p->tail = e;
      *r_p->tail = e;
      r_p->tail = &e->next;
      r_p->tail = &e->next;
    }
    }
  return TRUE;
  return TRUE;
}
}
 
 
 
 
static bfd_boolean
static bfd_boolean
transition_applies (insn_pattern *initial_insn,
transition_applies (insn_pattern *initial_insn,
                    const char *from_string ATTRIBUTE_UNUSED,
                    const char *from_string ATTRIBUTE_UNUSED,
                    const char *to_string ATTRIBUTE_UNUSED)
                    const char *to_string ATTRIBUTE_UNUSED)
{
{
  ReqOption *req_option;
  ReqOption *req_option;
 
 
  for (req_option = initial_insn->options;
  for (req_option = initial_insn->options;
       req_option != NULL;
       req_option != NULL;
       req_option = req_option->next)
       req_option = req_option->next)
    {
    {
      ReqOrOption *req_or_option = req_option->or_option_terms;
      ReqOrOption *req_or_option = req_option->or_option_terms;
 
 
      if (req_or_option == NULL
      if (req_or_option == NULL
          || req_or_option->next != NULL)
          || req_or_option->next != NULL)
        continue;
        continue;
 
 
      if (strncmp (req_or_option->option_name, "IsaUse", 6) == 0)
      if (strncmp (req_or_option->option_name, "IsaUse", 6) == 0)
        {
        {
          bfd_boolean option_available = FALSE;
          bfd_boolean option_available = FALSE;
          char *option_name = req_or_option->option_name + 6;
          char *option_name = req_or_option->option_name + 6;
          if (!strcmp (option_name, "DensityInstruction"))
          if (!strcmp (option_name, "DensityInstruction"))
            option_available = (XCHAL_HAVE_DENSITY == 1);
            option_available = (XCHAL_HAVE_DENSITY == 1);
          else if (!strcmp (option_name, "L32R"))
          else if (!strcmp (option_name, "L32R"))
            option_available = (XCHAL_HAVE_L32R == 1);
            option_available = (XCHAL_HAVE_L32R == 1);
          else if (!strcmp (option_name, "Const16"))
          else if (!strcmp (option_name, "Const16"))
            option_available = (XCHAL_HAVE_CONST16 == 1);
            option_available = (XCHAL_HAVE_CONST16 == 1);
          else if (!strcmp (option_name, "Loops"))
          else if (!strcmp (option_name, "Loops"))
            option_available = (XCHAL_HAVE_LOOPS == 1);
            option_available = (XCHAL_HAVE_LOOPS == 1);
          else if (!strcmp (option_name, "WideBranches"))
          else if (!strcmp (option_name, "WideBranches"))
            option_available = (XCHAL_HAVE_WIDE_BRANCHES == 1);
            option_available = (XCHAL_HAVE_WIDE_BRANCHES == 1);
          else if (!strcmp (option_name, "PredictedBranches"))
          else if (!strcmp (option_name, "PredictedBranches"))
            option_available = (XCHAL_HAVE_PREDICTED_BRANCHES == 1);
            option_available = (XCHAL_HAVE_PREDICTED_BRANCHES == 1);
          else if (!strcmp (option_name, "Booleans"))
          else if (!strcmp (option_name, "Booleans"))
            option_available = (XCHAL_HAVE_BOOLEANS == 1);
            option_available = (XCHAL_HAVE_BOOLEANS == 1);
          else
          else
            as_warn (_("invalid configuration option '%s' in transition rule '%s'"),
            as_warn (_("invalid configuration option '%s' in transition rule '%s'"),
                     req_or_option->option_name, from_string);
                     req_or_option->option_name, from_string);
          if ((option_available ^ req_or_option->is_true) != 0)
          if ((option_available ^ req_or_option->is_true) != 0)
            return FALSE;
            return FALSE;
        }
        }
      else if (strcmp (req_or_option->option_name, "realnop") == 0)
      else if (strcmp (req_or_option->option_name, "realnop") == 0)
        {
        {
          bfd_boolean nop_available =
          bfd_boolean nop_available =
            (xtensa_opcode_lookup (xtensa_default_isa, "nop")
            (xtensa_opcode_lookup (xtensa_default_isa, "nop")
             != XTENSA_UNDEFINED);
             != XTENSA_UNDEFINED);
          if ((nop_available ^ req_or_option->is_true) != 0)
          if ((nop_available ^ req_or_option->is_true) != 0)
            return FALSE;
            return FALSE;
        }
        }
    }
    }
  return TRUE;
  return TRUE;
}
}
 
 
 
 
static bfd_boolean
static bfd_boolean
wide_branch_opcode (const char *opcode_name,
wide_branch_opcode (const char *opcode_name,
                    char *suffix,
                    char *suffix,
                    xtensa_opcode *popcode)
                    xtensa_opcode *popcode)
{
{
  xtensa_isa isa = xtensa_default_isa;
  xtensa_isa isa = xtensa_default_isa;
  xtensa_opcode opcode;
  xtensa_opcode opcode;
  static char wbr_name_buf[20];
  static char wbr_name_buf[20];
 
 
  if (strncmp (opcode_name, "WIDE.", 5) != 0)
  if (strncmp (opcode_name, "WIDE.", 5) != 0)
    return FALSE;
    return FALSE;
 
 
  strcpy (wbr_name_buf, opcode_name + 5);
  strcpy (wbr_name_buf, opcode_name + 5);
  strcat (wbr_name_buf, suffix);
  strcat (wbr_name_buf, suffix);
  opcode = xtensa_opcode_lookup (isa, wbr_name_buf);
  opcode = xtensa_opcode_lookup (isa, wbr_name_buf);
  if (opcode != XTENSA_UNDEFINED)
  if (opcode != XTENSA_UNDEFINED)
    {
    {
      *popcode = opcode;
      *popcode = opcode;
      return TRUE;
      return TRUE;
    }
    }
 
 
  return FALSE;
  return FALSE;
}
}
 
 
 
 
static TransitionRule *
static TransitionRule *
build_transition (insn_pattern *initial_insn,
build_transition (insn_pattern *initial_insn,
                  insn_repl *replace_insns,
                  insn_repl *replace_insns,
                  const char *from_string,
                  const char *from_string,
                  const char *to_string)
                  const char *to_string)
{
{
  TransitionRule *tr = NULL;
  TransitionRule *tr = NULL;
  xtensa_opcode opcode;
  xtensa_opcode opcode;
  xtensa_isa isa = xtensa_default_isa;
  xtensa_isa isa = xtensa_default_isa;
 
 
  opname_map_e *op1;
  opname_map_e *op1;
  opname_map_e *op2;
  opname_map_e *op2;
 
 
  precond_e *precond;
  precond_e *precond;
  insn_repl_e *r;
  insn_repl_e *r;
 
 
  if (!wide_branch_opcode (initial_insn->t.opcode_name, ".w18", &opcode)
  if (!wide_branch_opcode (initial_insn->t.opcode_name, ".w18", &opcode)
      && !wide_branch_opcode (initial_insn->t.opcode_name, ".w15", &opcode))
      && !wide_branch_opcode (initial_insn->t.opcode_name, ".w15", &opcode))
    opcode = xtensa_opcode_lookup (isa, initial_insn->t.opcode_name);
    opcode = xtensa_opcode_lookup (isa, initial_insn->t.opcode_name);
 
 
  if (opcode == XTENSA_UNDEFINED)
  if (opcode == XTENSA_UNDEFINED)
    {
    {
      /* It is OK to not be able to translate some of these opcodes.  */
      /* It is OK to not be able to translate some of these opcodes.  */
      return NULL;
      return NULL;
    }
    }
 
 
 
 
  if (xtensa_opcode_num_operands (isa, opcode)
  if (xtensa_opcode_num_operands (isa, opcode)
      != insn_templ_operand_count (&initial_insn->t))
      != insn_templ_operand_count (&initial_insn->t))
    {
    {
      /* This is also OK because there are opcodes that
      /* This is also OK because there are opcodes that
         have different numbers of operands on different
         have different numbers of operands on different
         architecture variations.  */
         architecture variations.  */
      return NULL;
      return NULL;
    }
    }
 
 
  tr = (TransitionRule *) xmalloc (sizeof (TransitionRule));
  tr = (TransitionRule *) xmalloc (sizeof (TransitionRule));
  tr->opcode = opcode;
  tr->opcode = opcode;
  tr->conditions = NULL;
  tr->conditions = NULL;
  tr->to_instr = NULL;
  tr->to_instr = NULL;
 
 
  /* Build the conditions. First, equivalent operand condition....  */
  /* Build the conditions. First, equivalent operand condition....  */
  for (op1 = initial_insn->t.operand_map.head; op1 != NULL; op1 = op1->next)
  for (op1 = initial_insn->t.operand_map.head; op1 != NULL; op1 = op1->next)
    {
    {
      for (op2 = op1->next; op2 != NULL; op2 = op2->next)
      for (op2 = op1->next; op2 != NULL; op2 = op2->next)
        {
        {
          if (same_operand_name (op1, op2))
          if (same_operand_name (op1, op2))
            {
            {
              append_value_condition (tr, OP_EQUAL,
              append_value_condition (tr, OP_EQUAL,
                                      op1->operand_num, op2->operand_num);
                                      op1->operand_num, op2->operand_num);
            }
            }
        }
        }
    }
    }
 
 
  /* Now the condition that an operand value must be a constant....  */
  /* Now the condition that an operand value must be a constant....  */
  for (op1 = initial_insn->t.operand_map.head; op1 != NULL; op1 = op1->next)
  for (op1 = initial_insn->t.operand_map.head; op1 != NULL; op1 = op1->next)
    {
    {
      if (op_is_constant (op1))
      if (op_is_constant (op1))
        {
        {
          append_constant_value_condition (tr,
          append_constant_value_condition (tr,
                                           OP_EQUAL,
                                           OP_EQUAL,
                                           op1->operand_num,
                                           op1->operand_num,
                                           op_get_constant (op1));
                                           op_get_constant (op1));
        }
        }
    }
    }
 
 
 
 
  /* Now add the explicit preconditions listed after the "|" in the spec.
  /* Now add the explicit preconditions listed after the "|" in the spec.
     These are currently very limited, so we do a special case
     These are currently very limited, so we do a special case
     parse for them.  We expect spaces, opname != opname.  */
     parse for them.  We expect spaces, opname != opname.  */
  for (precond = initial_insn->preconds.head;
  for (precond = initial_insn->preconds.head;
       precond != NULL;
       precond != NULL;
       precond = precond->next)
       precond = precond->next)
    {
    {
      op1 = NULL;
      op1 = NULL;
      op2 = NULL;
      op2 = NULL;
 
 
      if (precond->opname1)
      if (precond->opname1)
        {
        {
          op1 = get_opmatch (&initial_insn->t.operand_map, precond->opname1);
          op1 = get_opmatch (&initial_insn->t.operand_map, precond->opname1);
          if (op1 == NULL)
          if (op1 == NULL)
            as_fatal (_("opcode '%s': no bound opname '%s' "
            as_fatal (_("opcode '%s': no bound opname '%s' "
                        "for precondition in '%s'"),
                        "for precondition in '%s'"),
                      xtensa_opcode_name (isa, opcode),
                      xtensa_opcode_name (isa, opcode),
                      precond->opname1, from_string);
                      precond->opname1, from_string);
        }
        }
 
 
      if (precond->opname2)
      if (precond->opname2)
        {
        {
          op2 = get_opmatch (&initial_insn->t.operand_map, precond->opname2);
          op2 = get_opmatch (&initial_insn->t.operand_map, precond->opname2);
          if (op2 == NULL)
          if (op2 == NULL)
            as_fatal (_("opcode '%s': no bound opname '%s' "
            as_fatal (_("opcode '%s': no bound opname '%s' "
                        "for precondition in %s"),
                        "for precondition in %s"),
                      xtensa_opcode_name (isa, opcode),
                      xtensa_opcode_name (isa, opcode),
                      precond->opname2, from_string);
                      precond->opname2, from_string);
        }
        }
 
 
      if (op1 == NULL && op2 == NULL)
      if (op1 == NULL && op2 == NULL)
        as_fatal (_("opcode '%s': precondition only contains "
        as_fatal (_("opcode '%s': precondition only contains "
                    "constants in '%s'"),
                    "constants in '%s'"),
                  xtensa_opcode_name (isa, opcode), from_string);
                  xtensa_opcode_name (isa, opcode), from_string);
      else if (op1 != NULL && op2 != NULL)
      else if (op1 != NULL && op2 != NULL)
        append_value_condition (tr, precond->cmpop,
        append_value_condition (tr, precond->cmpop,
                                op1->operand_num, op2->operand_num);
                                op1->operand_num, op2->operand_num);
      else if (op2 == NULL)
      else if (op2 == NULL)
        append_constant_value_condition (tr, precond->cmpop,
        append_constant_value_condition (tr, precond->cmpop,
                                         op1->operand_num, precond->opval2);
                                         op1->operand_num, precond->opval2);
      else
      else
        append_constant_value_condition (tr, precond->cmpop,
        append_constant_value_condition (tr, precond->cmpop,
                                         op2->operand_num, precond->opval1);
                                         op2->operand_num, precond->opval1);
    }
    }
 
 
  tr->options = clone_req_option_list (initial_insn->options);
  tr->options = clone_req_option_list (initial_insn->options);
 
 
  /* Generate the replacement instructions.  Some of these
  /* Generate the replacement instructions.  Some of these
     "instructions" are actually labels and literals.  There can be at
     "instructions" are actually labels and literals.  There can be at
     most one literal and at most one label.  A literal must be defined
     most one literal and at most one label.  A literal must be defined
     (e.g., "LITERAL %imm") before use (e.g., "%LITERAL").  The labels
     (e.g., "LITERAL %imm") before use (e.g., "%LITERAL").  The labels
     can be used before they are defined.  Also there are a number of
     can be used before they are defined.  Also there are a number of
     special operands (e.g., HI24S).  */
     special operands (e.g., HI24S).  */
 
 
  for (r = replace_insns->head; r != NULL; r = r->next)
  for (r = replace_insns->head; r != NULL; r = r->next)
    {
    {
      BuildInstr *bi;
      BuildInstr *bi;
      const char *opcode_name;
      const char *opcode_name;
      int operand_count;
      int operand_count;
      opname_map_e *op;
      opname_map_e *op;
      const char *fn_name;
      const char *fn_name;
      const char *operand_arg_name;
      const char *operand_arg_name;
 
 
      bi = (BuildInstr *) xmalloc (sizeof (BuildInstr));
      bi = (BuildInstr *) xmalloc (sizeof (BuildInstr));
      append_build_insn (tr, bi);
      append_build_insn (tr, bi);
 
 
      bi->opcode = XTENSA_UNDEFINED;
      bi->opcode = XTENSA_UNDEFINED;
      bi->ops = NULL;
      bi->ops = NULL;
      bi->next = NULL;
      bi->next = NULL;
 
 
      opcode_name = r->t.opcode_name;
      opcode_name = r->t.opcode_name;
      operand_count = insn_templ_operand_count (&r->t);
      operand_count = insn_templ_operand_count (&r->t);
 
 
      if (strcmp (opcode_name, "LITERAL") == 0)
      if (strcmp (opcode_name, "LITERAL") == 0)
        {
        {
          bi->typ = INSTR_LITERAL_DEF;
          bi->typ = INSTR_LITERAL_DEF;
          if (operand_count != 1)
          if (operand_count != 1)
            as_fatal (_("expected one operand for generated literal"));
            as_fatal (_("expected one operand for generated literal"));
        }
        }
      else if (strcmp (opcode_name, "LABEL") == 0)
      else if (strcmp (opcode_name, "LABEL") == 0)
        {
        {
          bi->typ = INSTR_LABEL_DEF;
          bi->typ = INSTR_LABEL_DEF;
          if (operand_count != 0)
          if (operand_count != 0)
            as_fatal (_("expected 0 operands for generated label"));
            as_fatal (_("expected 0 operands for generated label"));
        }
        }
      else
      else
        {
        {
          bi->typ = INSTR_INSTR;
          bi->typ = INSTR_INSTR;
          if (wide_branch_opcode (opcode_name, ".w18", &bi->opcode)
          if (wide_branch_opcode (opcode_name, ".w18", &bi->opcode)
              || wide_branch_opcode (opcode_name, ".w15", &bi->opcode))
              || wide_branch_opcode (opcode_name, ".w15", &bi->opcode))
            opcode_name = xtensa_opcode_name (isa, bi->opcode);
            opcode_name = xtensa_opcode_name (isa, bi->opcode);
          else
          else
            bi->opcode = xtensa_opcode_lookup (isa, opcode_name);
            bi->opcode = xtensa_opcode_lookup (isa, opcode_name);
 
 
          if (bi->opcode == XTENSA_UNDEFINED)
          if (bi->opcode == XTENSA_UNDEFINED)
            {
            {
              as_warn (_("invalid opcode '%s' in transition rule '%s'"),
              as_warn (_("invalid opcode '%s' in transition rule '%s'"),
                       opcode_name, to_string);
                       opcode_name, to_string);
              return NULL;
              return NULL;
            }
            }
 
 
          /* Check for the right number of ops.  */
          /* Check for the right number of ops.  */
          if (xtensa_opcode_num_operands (isa, bi->opcode)
          if (xtensa_opcode_num_operands (isa, bi->opcode)
              != (int) operand_count)
              != (int) operand_count)
            as_fatal (_("opcode '%s': replacement does not have %d ops"),
            as_fatal (_("opcode '%s': replacement does not have %d ops"),
                      opcode_name,
                      opcode_name,
                      xtensa_opcode_num_operands (isa, bi->opcode));
                      xtensa_opcode_num_operands (isa, bi->opcode));
        }
        }
 
 
      for (op = r->t.operand_map.head; op != NULL; op = op->next)
      for (op = r->t.operand_map.head; op != NULL; op = op->next)
        {
        {
          unsigned idnum;
          unsigned idnum;
 
 
          if (op_is_constant (op))
          if (op_is_constant (op))
            append_constant_op (bi, op->operand_num, op_get_constant (op));
            append_constant_op (bi, op->operand_num, op_get_constant (op));
          else if (strcmp (op->operand_name, "%LITERAL") == 0)
          else if (strcmp (op->operand_name, "%LITERAL") == 0)
            append_literal_op (bi, op->operand_num);
            append_literal_op (bi, op->operand_num);
          else if (strcmp (op->operand_name, "%LABEL") == 0)
          else if (strcmp (op->operand_name, "%LABEL") == 0)
            append_label_op (bi, op->operand_num);
            append_label_op (bi, op->operand_num);
          else if (op->operand_name[0] == 'a'
          else if (op->operand_name[0] == 'a'
                   && parse_constant (op->operand_name + 1, &idnum))
                   && parse_constant (op->operand_name + 1, &idnum))
            append_constant_op (bi, op->operand_num, idnum);
            append_constant_op (bi, op->operand_num, idnum);
          else if (op->operand_name[0] == '%')
          else if (op->operand_name[0] == '%')
            {
            {
              opname_map_e *orig_op;
              opname_map_e *orig_op;
              orig_op = get_opmatch (&initial_insn->t.operand_map,
              orig_op = get_opmatch (&initial_insn->t.operand_map,
                                     op->operand_name);
                                     op->operand_name);
              if (orig_op == NULL)
              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);
                          opcode_name, op->operand_name, to_string);
              append_field_op (bi, op->operand_num, orig_op->operand_num);
              append_field_op (bi, op->operand_num, orig_op->operand_num);
            }
            }
          else if (parse_special_fn (op->operand_name,
          else if (parse_special_fn (op->operand_name,
                                     &fn_name, &operand_arg_name))
                                     &fn_name, &operand_arg_name))
            {
            {
              opname_map_e *orig_op;
              opname_map_e *orig_op;
              OpType typ = OP_CONSTANT;
              OpType typ = OP_CONSTANT;
 
 
              if (strcmp (fn_name, "LOW8") == 0)
              if (strcmp (fn_name, "LOW8") == 0)
                typ = OP_OPERAND_LOW8;
                typ = OP_OPERAND_LOW8;
              else if (strcmp (fn_name, "HI24S") == 0)
              else if (strcmp (fn_name, "HI24S") == 0)
                typ = OP_OPERAND_HI24S;
                typ = OP_OPERAND_HI24S;
              else if (strcmp (fn_name, "F32MINUS") == 0)
              else if (strcmp (fn_name, "F32MINUS") == 0)
                typ = OP_OPERAND_F32MINUS;
                typ = OP_OPERAND_F32MINUS;
              else if (strcmp (fn_name, "LOW16U") == 0)
              else if (strcmp (fn_name, "LOW16U") == 0)
                typ = OP_OPERAND_LOW16U;
                typ = OP_OPERAND_LOW16U;
              else if (strcmp (fn_name, "HI16U") == 0)
              else if (strcmp (fn_name, "HI16U") == 0)
                typ = OP_OPERAND_HI16U;
                typ = OP_OPERAND_HI16U;
              else
              else
                as_fatal (_("unknown user-defined function %s"), fn_name);
                as_fatal (_("unknown user-defined function %s"), fn_name);
 
 
              orig_op = get_opmatch (&initial_insn->t.operand_map,
              orig_op = get_opmatch (&initial_insn->t.operand_map,
                                     operand_arg_name);
                                     operand_arg_name);
              if (orig_op == NULL)
              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);
                          opcode_name, op->operand_name, to_string);
              append_user_fn_field_op (bi, op->operand_num,
              append_user_fn_field_op (bi, op->operand_num,
                                       typ, orig_op->operand_num);
                                       typ, orig_op->operand_num);
            }
            }
          else
          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);
                      opcode_name, op->operand_name, to_string);
        }
        }
    }
    }
 
 
  return tr;
  return tr;
}
}
 
 
 
 
static TransitionTable *
static TransitionTable *
build_transition_table (const string_pattern_pair *transitions,
build_transition_table (const string_pattern_pair *transitions,
                        int transition_count,
                        int transition_count,
                        transition_cmp_fn cmp)
                        transition_cmp_fn cmp)
{
{
  TransitionTable *table = NULL;
  TransitionTable *table = NULL;
  int num_opcodes = xtensa_isa_num_opcodes (xtensa_default_isa);
  int num_opcodes = xtensa_isa_num_opcodes (xtensa_default_isa);
  int i, tnum;
  int i, tnum;
 
 
  if (table != NULL)
  if (table != NULL)
    return table;
    return table;
 
 
  /* Otherwise, build it now.  */
  /* Otherwise, build it now.  */
  table = (TransitionTable *) xmalloc (sizeof (TransitionTable));
  table = (TransitionTable *) xmalloc (sizeof (TransitionTable));
  table->num_opcodes = num_opcodes;
  table->num_opcodes = num_opcodes;
  table->table =
  table->table =
    (TransitionList **) xmalloc (sizeof (TransitionTable *) * num_opcodes);
    (TransitionList **) xmalloc (sizeof (TransitionTable *) * num_opcodes);
 
 
  for (i = 0; i < num_opcodes; i++)
  for (i = 0; i < num_opcodes; i++)
    table->table[i] = NULL;
    table->table[i] = NULL;
 
 
  for (tnum = 0; tnum < transition_count; tnum++)
  for (tnum = 0; tnum < transition_count; tnum++)
    {
    {
      const char *from_string = transitions[tnum].pattern;
      const char *from_string = transitions[tnum].pattern;
      const char *to_string = transitions[tnum].replacement;
      const char *to_string = transitions[tnum].replacement;
 
 
      insn_pattern initial_insn;
      insn_pattern initial_insn;
      insn_repl replace_insns;
      insn_repl replace_insns;
      TransitionRule *tr;
      TransitionRule *tr;
 
 
      init_insn_pattern (&initial_insn);
      init_insn_pattern (&initial_insn);
      if (!parse_insn_pattern (from_string, &initial_insn))
      if (!parse_insn_pattern (from_string, &initial_insn))
        as_fatal (_("could not parse INSN_PATTERN '%s'"), from_string);
        as_fatal (_("could not parse INSN_PATTERN '%s'"), from_string);
 
 
      init_insn_repl (&replace_insns);
      init_insn_repl (&replace_insns);
      if (!parse_insn_repl (to_string, &replace_insns))
      if (!parse_insn_repl (to_string, &replace_insns))
        as_fatal (_("could not parse INSN_REPL '%s'"), to_string);
        as_fatal (_("could not parse INSN_REPL '%s'"), to_string);
 
 
      if (transition_applies (&initial_insn, from_string, to_string))
      if (transition_applies (&initial_insn, from_string, to_string))
        {
        {
          tr = build_transition (&initial_insn, &replace_insns,
          tr = build_transition (&initial_insn, &replace_insns,
                                 from_string, to_string);
                                 from_string, to_string);
          if (tr)
          if (tr)
            append_transition (table, tr->opcode, tr, cmp);
            append_transition (table, tr->opcode, tr, cmp);
          else
          else
            {
            {
#if TENSILICA_DEBUG
#if TENSILICA_DEBUG
              as_warn (_("could not build transition for %s => %s"),
              as_warn (_("could not build transition for %s => %s"),
                       from_string, to_string);
                       from_string, to_string);
#endif
#endif
            }
            }
        }
        }
 
 
      clear_insn_repl (&replace_insns);
      clear_insn_repl (&replace_insns);
      clear_insn_pattern (&initial_insn);
      clear_insn_pattern (&initial_insn);
    }
    }
  return table;
  return table;
}
}
 
 


extern TransitionTable *
extern TransitionTable *
xg_build_widen_table (transition_cmp_fn cmp)
xg_build_widen_table (transition_cmp_fn cmp)
{
{
  static TransitionTable *table = NULL;
  static TransitionTable *table = NULL;
  if (table == NULL)
  if (table == NULL)
    table = build_transition_table (widen_spec_list, WIDEN_COUNT, cmp);
    table = build_transition_table (widen_spec_list, WIDEN_COUNT, cmp);
  return table;
  return table;
}
}
 
 
 
 
extern TransitionTable *
extern TransitionTable *
xg_build_simplify_table (transition_cmp_fn cmp)
xg_build_simplify_table (transition_cmp_fn cmp)
{
{
  static TransitionTable *table = NULL;
  static TransitionTable *table = NULL;
  if (table == NULL)
  if (table == NULL)
    table = build_transition_table (simplify_spec_list, SIMPLIFY_COUNT, cmp);
    table = build_transition_table (simplify_spec_list, SIMPLIFY_COUNT, cmp);
  return table;
  return table;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.