X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Fxtensa-relax.c;h=3adbf2aa60a68fc308ade94f2836f0b7416b8c01;hb=945e0f82dad31db89a107b496532886fe215c011;hp=5f85840cfd0fa6a99e8d8001a391088c583b9be5;hpb=b2d179bedabd1313a50f2c9f71f782c3e8d69046;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/xtensa-relax.c b/gas/config/xtensa-relax.c index 5f85840cfd..3adbf2aa60 100644 --- a/gas/config/xtensa-relax.c +++ b/gas/config/xtensa-relax.c @@ -1,11 +1,11 @@ /* Table of relaxations for Xtensa assembly. - Copyright 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003-2016 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) + the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -49,8 +49,8 @@ The replacement language INSN_REPL ::= INSN_LABEL_LIT ( ';' INSN_LABEL_LIT )* INSN_LABEL_LIT ::= INSN_TEMPL - | 'LABEL' num - | 'LITERAL' num ' ' VARIABLE + | 'LABEL' + | 'LITERAL' VARIABLE The operands in a PRECOND must be constants or variables bound by the INSN_PATTERN. @@ -72,12 +72,12 @@ movi.n instruction to the wide movi instruction. A more complex example of a branch around: - {"beqz %as,%label", "bnez %as,%LABEL0;j %label;LABEL0"} + {"beqz %as,%label", "bnez %as,%LABEL;j %label;LABEL"} would convert a branch to a negated branch to the following instruction with a jump to the original label. An Xtensa-specific example that generates a literal: - {"movi %at,%imm", "LITERAL0 %imm; l32r %at,%LITERAL0"} + {"movi %at,%imm", "LITERAL %imm; l32r %at,%LITERAL"} will convert a movi instruction to an l32r of a literal literal defined in the literal pool. @@ -87,7 +87,7 @@ when the first and second operands are not the same as specified by the "| %at!=%as" precondition clause. {"l32i %at,%as,%imm | %at!=%as", - "LITERAL0 %imm; l32r %at,%LITERAL0; 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 not currently have the ability to represent the difference of two @@ -101,6 +101,10 @@ #include #include "xtensa-config.h" +#ifndef XCHAL_HAVE_WIDE_BRANCHES +#define XCHAL_HAVE_WIDE_BRANCHES 0 +#endif + /* Imported from bfd. */ extern xtensa_isa xtensa_default_isa; @@ -243,7 +247,10 @@ struct string_pattern_pair_struct addi.n a4, 0x1010 => addi 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 + regarding how these chains must be built. */ static string_pattern_pair widen_spec_list[] = { @@ -264,7 +271,7 @@ static string_pattern_pair widen_spec_list[] = /* Widening with literals or const16. */ {"movi %at,%imm ? IsaUseL32R ", - "LITERAL0 %imm; l32r %at,%LITERAL0"}, + "LITERAL %imm; l32r %at,%LITERAL"}, {"movi %at,%imm ? IsaUseConst16", "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm)"}, @@ -275,19 +282,19 @@ static string_pattern_pair widen_spec_list[] = /* In the end convert to either an l32r or const16. */ {"addmi %ar,%as,%imm | %ar!=%as ? IsaUseL32R", - "LITERAL0 %imm; l32r %ar,%LITERAL0; add %ar,%as,%ar"}, + "LITERAL %imm; l32r %ar,%LITERAL; add %ar,%as,%ar"}, {"addmi %ar,%as,%imm | %ar!=%as ? IsaUseConst16", "const16 %ar,HI16U(%imm); const16 %ar,LOW16U(%imm); add %ar,%as,%ar"}, /* Widening the load instructions with too-large immediates */ {"l8ui %at,%as,%imm | %at!=%as ? IsaUseL32R", - "LITERAL0 %imm; l32r %at,%LITERAL0; 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", - "LITERAL0 %imm; l32r %at,%LITERAL0; 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", - "LITERAL0 %imm; l32r %at,%LITERAL0; 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", - "LITERAL0 %imm; l32r %at,%LITERAL0; 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. */ {"l8ui %at,%as,%imm | %at!=%as ? IsaUseConst16", @@ -303,7 +310,7 @@ static string_pattern_pair widen_spec_list[] = hardcoded into its use is a modification of the final operand in the instruction in bytes 9 and 12. */ {"loop %as,%label | %as!=1 ? IsaUseLoops", - "loop %as,%LABEL0;" + "loop %as,%LABEL;" "rsr.lend %as;" /* LEND */ "wsr.lbeg %as;" /* LBEG */ "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */ @@ -312,11 +319,11 @@ static string_pattern_pair widen_spec_list[] = "isync;" "rsr.lcount %as;" /* LCOUNT */ "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */ - "LABEL0"}, + "LABEL"}, {"loopgtz %as,%label | %as!=1 ? IsaUseLoops", "beqz %as,%label;" "bltz %as,%label;" - "loopgtz %as,%LABEL0;" + "loopgtz %as,%LABEL;" "rsr.lend %as;" /* LEND */ "wsr.lbeg %as;" /* LBEG */ "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */ @@ -325,10 +332,10 @@ static string_pattern_pair widen_spec_list[] = "isync;" "rsr.lcount %as;" /* LCOUNT */ "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */ - "LABEL0"}, + "LABEL"}, {"loopnez %as,%label | %as!=1 ? IsaUseLoops", "beqz %as,%label;" - "loopnez %as,%LABEL0;" + "loopnez %as,%LABEL;" "rsr.lend %as;" /* LEND */ "wsr.lbeg %as;" /* LBEG */ "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */ @@ -337,89 +344,116 @@ static string_pattern_pair widen_spec_list[] = "isync;" "rsr.lcount %as;" /* LCOUNT */ "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */ - "LABEL0"}, + "LABEL"}, /* Relaxing to wide branches. Order is important here. With wide branches, there is more than one correct relaxation for an out-of-range branch. Put the wide branch relaxations first in the table since they are more efficient than the branch-around relaxations. */ - - {"beqz %as,%label ? IsaUseWideBranches", "beqz.w18 %as,%label"}, - {"bnez %as,%label ? IsaUseWideBranches", "bnez.w18 %as,%label"}, - {"bgez %as,%label ? IsaUseWideBranches", "bgez.w18 %as,%label"}, - {"bltz %as,%label ? IsaUseWideBranches", "bltz.w18 %as,%label"}, - {"beqi %as,%imm,%label ? IsaUseWideBranches", "beqi.w18 %as,%imm,%label"}, - {"bnei %as,%imm,%label ? IsaUseWideBranches", "bnei.w18 %as,%imm,%label"}, - {"bgei %as,%imm,%label ? IsaUseWideBranches", "bgei.w18 %as,%imm,%label"}, - {"blti %as,%imm,%label ? IsaUseWideBranches", "blti.w18 %as,%imm,%label"}, - {"bgeui %as,%imm,%label ? IsaUseWideBranches", "bgeui.w18 %as,%imm,%label"}, - {"bltui %as,%imm,%label ? IsaUseWideBranches", "bltui.w18 %as,%imm,%label"}, - {"bbci %as,%imm,%label ? IsaUseWideBranches", "bbci.w18 %as,%imm,%label"}, - {"bbsi %as,%imm,%label ? IsaUseWideBranches", "bbsi.w18 %as,%imm,%label"}, - {"beq %as,%at,%label ? IsaUseWideBranches", "beq.w18 %as,%at,%label"}, - {"bne %as,%at,%label ? IsaUseWideBranches", "bne.w18 %as,%at,%label"}, - {"bge %as,%at,%label ? IsaUseWideBranches", "bge.w18 %as,%at,%label"}, - {"blt %as,%at,%label ? IsaUseWideBranches", "blt.w18 %as,%at,%label"}, - {"bgeu %as,%at,%label ? IsaUseWideBranches", "bgeu.w18 %as,%at,%label"}, - {"bltu %as,%at,%label ? IsaUseWideBranches", "bltu.w18 %as,%at,%label"}, - {"bany %as,%at,%label ? IsaUseWideBranches", "bany.w18 %as,%at,%label"}, - {"bnone %as,%at,%label ? IsaUseWideBranches", "bnone.w18 %as,%at,%label"}, - {"ball %as,%at,%label ? IsaUseWideBranches", "ball.w18 %as,%at,%label"}, - {"bnall %as,%at,%label ? IsaUseWideBranches", "bnall.w18 %as,%at,%label"}, - {"bbc %as,%at,%label ? IsaUseWideBranches", "bbc.w18 %as,%at,%label"}, - {"bbs %as,%at,%label ? IsaUseWideBranches", "bbs.w18 %as,%at,%label"}, - + + {"beqz %as,%label ? IsaUseWideBranches", "WIDE.beqz %as,%label"}, + {"bnez %as,%label ? IsaUseWideBranches", "WIDE.bnez %as,%label"}, + {"bgez %as,%label ? IsaUseWideBranches", "WIDE.bgez %as,%label"}, + {"bltz %as,%label ? IsaUseWideBranches", "WIDE.bltz %as,%label"}, + {"beqi %as,%imm,%label ? IsaUseWideBranches", "WIDE.beqi %as,%imm,%label"}, + {"bnei %as,%imm,%label ? IsaUseWideBranches", "WIDE.bnei %as,%imm,%label"}, + {"bgei %as,%imm,%label ? IsaUseWideBranches", "WIDE.bgei %as,%imm,%label"}, + {"blti %as,%imm,%label ? IsaUseWideBranches", "WIDE.blti %as,%imm,%label"}, + {"bgeui %as,%imm,%label ? IsaUseWideBranches", "WIDE.bgeui %as,%imm,%label"}, + {"bltui %as,%imm,%label ? IsaUseWideBranches", "WIDE.bltui %as,%imm,%label"}, + {"bbci %as,%imm,%label ? IsaUseWideBranches", "WIDE.bbci %as,%imm,%label"}, + {"bbsi %as,%imm,%label ? IsaUseWideBranches", "WIDE.bbsi %as,%imm,%label"}, + {"beq %as,%at,%label ? IsaUseWideBranches", "WIDE.beq %as,%at,%label"}, + {"bne %as,%at,%label ? IsaUseWideBranches", "WIDE.bne %as,%at,%label"}, + {"bge %as,%at,%label ? IsaUseWideBranches", "WIDE.bge %as,%at,%label"}, + {"blt %as,%at,%label ? IsaUseWideBranches", "WIDE.blt %as,%at,%label"}, + {"bgeu %as,%at,%label ? IsaUseWideBranches", "WIDE.bgeu %as,%at,%label"}, + {"bltu %as,%at,%label ? IsaUseWideBranches", "WIDE.bltu %as,%at,%label"}, + {"bany %as,%at,%label ? IsaUseWideBranches", "WIDE.bany %as,%at,%label"}, + {"bnone %as,%at,%label ? IsaUseWideBranches", "WIDE.bnone %as,%at,%label"}, + {"ball %as,%at,%label ? IsaUseWideBranches", "WIDE.ball %as,%at,%label"}, + {"bnall %as,%at,%label ? IsaUseWideBranches", "WIDE.bnall %as,%at,%label"}, + {"bbc %as,%at,%label ? IsaUseWideBranches", "WIDE.bbc %as,%at,%label"}, + {"bbs %as,%at,%label ? IsaUseWideBranches", "WIDE.bbs %as,%at,%label"}, + /* Widening branch comparisons eq/ne to zero. Prefer relaxing to narrow branches if the density option is available. */ - {"beqz %as,%label ? IsaUseDensityInstruction", "bnez.n %as,%LABEL0;j %label;LABEL0"}, - {"bnez %as,%label ? IsaUseDensityInstruction", "beqz.n %as,%LABEL0;j %label;LABEL0"}, - {"beqz %as,%label", "bnez %as,%LABEL0;j %label;LABEL0"}, - {"bnez %as,%label", "beqz %as,%LABEL0;j %label;LABEL0"}, + {"beqz %as,%label ? IsaUseDensityInstruction", "bnez.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"}, + {"bnez %as,%label", "beqz %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.beqz %as,%label", "bnez %as,%LABEL;j %label;LABEL"}, + {"WIDE.bnez %as,%label", "beqz %as,%LABEL;j %label;LABEL"}, /* Widening expect-taken branches. */ - {"beqzt %as,%label ? IsaUsePredictedBranches", "bnez %as,%LABEL0;j %label;LABEL0"}, - {"bnezt %as,%label ? IsaUsePredictedBranches", "beqz %as,%LABEL0;j %label;LABEL0"}, - {"beqt %as,%at,%label ? IsaUsePredictedBranches", "bne %as,%at,%LABEL0;j %label;LABEL0"}, - {"bnet %as,%at,%label ? IsaUsePredictedBranches", "beq %as,%at,%LABEL0;j %label;LABEL0"}, + {"beqzt %as,%label ? IsaUsePredictedBranches", "bnez %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"}, + {"bnet %as,%at,%label ? IsaUsePredictedBranches", "beq %as,%at,%LABEL;j %label;LABEL"}, /* Widening branches from the Xtensa boolean option. */ - {"bt %bs,%label ? IsaUseBooleans", "bf %bs,%LABEL0;j %label;LABEL0"}, - {"bf %bs,%label ? IsaUseBooleans", "bt %bs,%LABEL0;j %label;LABEL0"}, + {"bt %bs,%label ? IsaUseBooleans", "bf %bs,%LABEL;j %label;LABEL"}, + {"bf %bs,%label ? IsaUseBooleans", "bt %bs,%LABEL;j %label;LABEL"}, /* Other branch-around-jump widenings. */ - {"bgez %as,%label", "bltz %as,%LABEL0;j %label;LABEL0"}, - {"bltz %as,%label", "bgez %as,%LABEL0;j %label;LABEL0"}, - {"beqi %as,%imm,%label", "bnei %as,%imm,%LABEL0;j %label;LABEL0"}, - {"bnei %as,%imm,%label", "beqi %as,%imm,%LABEL0;j %label;LABEL0"}, - {"bgei %as,%imm,%label", "blti %as,%imm,%LABEL0;j %label;LABEL0"}, - {"blti %as,%imm,%label", "bgei %as,%imm,%LABEL0;j %label;LABEL0"}, - {"bgeui %as,%imm,%label", "bltui %as,%imm,%LABEL0;j %label;LABEL0"}, - {"bltui %as,%imm,%label", "bgeui %as,%imm,%LABEL0;j %label;LABEL0"}, - {"bbci %as,%imm,%label", "bbsi %as,%imm,%LABEL0;j %label;LABEL0"}, - {"bbsi %as,%imm,%label", "bbci %as,%imm,%LABEL0;j %label;LABEL0"}, - {"beq %as,%at,%label", "bne %as,%at,%LABEL0;j %label;LABEL0"}, - {"bne %as,%at,%label", "beq %as,%at,%LABEL0;j %label;LABEL0"}, - {"bge %as,%at,%label", "blt %as,%at,%LABEL0;j %label;LABEL0"}, - {"blt %as,%at,%label", "bge %as,%at,%LABEL0;j %label;LABEL0"}, - {"bgeu %as,%at,%label", "bltu %as,%at,%LABEL0;j %label;LABEL0"}, - {"bltu %as,%at,%label", "bgeu %as,%at,%LABEL0;j %label;LABEL0"}, - {"bany %as,%at,%label", "bnone %as,%at,%LABEL0;j %label;LABEL0"}, - {"bnone %as,%at,%label", "bany %as,%at,%LABEL0;j %label;LABEL0"}, - {"ball %as,%at,%label", "bnall %as,%at,%LABEL0;j %label;LABEL0"}, - {"bnall %as,%at,%label", "ball %as,%at,%LABEL0;j %label;LABEL0"}, - {"bbc %as,%at,%label", "bbs %as,%at,%LABEL0;j %label;LABEL0"}, - {"bbs %as,%at,%label", "bbc %as,%at,%LABEL0;j %label;LABEL0"}, + {"bgez %as,%label", "bltz %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"}, + {"bnei %as,%imm,%label", "beqi %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"}, + {"bgeui %as,%imm,%label", "bltui %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"}, + {"bbsi %as,%imm,%label", "bbci %as,%imm,%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"}, + {"bge %as,%at,%label", "blt %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"}, + {"bltu %as,%at,%label", "bgeu %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"}, + {"ball %as,%at,%label", "bnall %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"}, + {"bbs %as,%at,%label", "bbc %as,%at,%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.beqi %as,%imm,%label", "bnei %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.blti %as,%imm,%label", "bgei %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.bbci %as,%imm,%label", "bbsi %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.bne %as,%at,%label", "beq %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.bgeu %as,%at,%label", "bltu %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.bnone %as,%at,%label", "bany %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.bbc %as,%at,%label", "bbs %as,%at,%LABEL;j %label;LABEL"}, + {"WIDE.bbs %as,%at,%label", "bbc %as,%at,%LABEL;j %label;LABEL"}, /* Expanding calls with literals. */ {"call0 %label,%ar0 ? IsaUseL32R", - "LITERAL0 %label; l32r a0,%LITERAL0; callx0 a0,%ar0"}, + "LITERAL %label; l32r a0,%LITERAL; callx0 a0,%ar0"}, {"call4 %label,%ar4 ? IsaUseL32R", - "LITERAL0 %label; l32r a4,%LITERAL0; callx4 a4,%ar4"}, + "LITERAL %label; l32r a4,%LITERAL; callx4 a4,%ar4"}, {"call8 %label,%ar8 ? IsaUseL32R", - "LITERAL0 %label; l32r a8,%LITERAL0; callx8 a8,%ar8"}, + "LITERAL %label; l32r a8,%LITERAL; callx8 a8,%ar8"}, {"call12 %label,%ar12 ? IsaUseL32R", - "LITERAL0 %label; l32r a12,%LITERAL0; callx12 a12,%ar12"}, + "LITERAL %label; l32r a12,%LITERAL; callx12 a12,%ar12"}, /* Expanding calls with const16. */ {"call0 %label,%ar0 ? IsaUseConst16", @@ -429,7 +463,14 @@ static string_pattern_pair widen_spec_list[] = {"call8 %label,%ar8 ? IsaUseConst16", "const16 a8,HI16U(%label); const16 a8,LOW16U(%label); callx8 a8,%ar8"}, {"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"}, + + /* Expanding j.l with literals. */ + {"j %label ? FREEREG ? IsaUseL32R", + "LITERAL %label; l32r FREEREG,%LITERAL; jx FREEREG"}, + /* Expanding j.l with const16. */ + {"j %label ? FREEREG ? IsaUseConst16", + "const16 FREEREG,HI16U(%label); const16 FREEREG,LOW16U(%label); jx FREEREG"}, }; #define WIDEN_COUNT (sizeof (widen_spec_list) / sizeof (string_pattern_pair)) @@ -484,8 +525,8 @@ append_transition (TransitionTable *tt, TransitionList *tl = (TransitionList *) xmalloc (sizeof (TransitionList)); TransitionList *prev; TransitionList **t_p; - assert (tt != NULL); - assert (opcode < tt->num_opcodes); + gas_assert (tt != NULL); + gas_assert (opcode < tt->num_opcodes); prev = tt->table[opcode]; tl->rule = t; @@ -611,26 +652,26 @@ append_op (BuildInstr *bi, BuildOp *b_op) static void -append_literal_op (BuildInstr *bi, unsigned op1, unsigned litnum) +append_literal_op (BuildInstr *bi, unsigned op1, unsigned src_op) { BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp)); b_op->op_num = op1; b_op->typ = OP_LITERAL; - b_op->op_data = litnum; + b_op->op_data = src_op; b_op->next = NULL; append_op (bi, b_op); } static void -append_label_op (BuildInstr *bi, unsigned op1, unsigned labnum) +append_label_op (BuildInstr *bi, unsigned op1) { BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp)); b_op->op_num = op1; b_op->typ = OP_LABEL; - b_op->op_data = labnum; + b_op->op_data = 0; b_op->next = NULL; append_op (bi, b_op); } @@ -828,7 +869,7 @@ clear_opname_map (opname_map *m) static bfd_boolean 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 || m2->operand_name == NULL) return FALSE; return (m1->operand_name == m2->operand_name); } @@ -858,7 +899,7 @@ op_is_constant (const opname_map_e *m1) static unsigned op_get_constant (const opname_map_e *m1) { - assert (m1->operand_name == NULL); + gas_assert (m1->operand_name == NULL); return m1->constant_value; } @@ -978,36 +1019,12 @@ parse_constant (const char *in, unsigned *val_p) } -/* Match a pattern like "foo1" with - parse_id_constant("foo1", "foo", &num). - This may also be used to just match a number. */ - -static bfd_boolean -parse_id_constant (const char *in, const char *name, unsigned *val_p) -{ - unsigned namelen = 0; - const char *p; - - if (in == NULL) - return FALSE; - - if (name != NULL) - namelen = strlen (name); - - if (name != NULL && strncmp (in, name, namelen) != 0) - return FALSE; - - p = &in[namelen]; - return parse_constant (p, val_p); -} - - static bfd_boolean parse_special_fn (const char *name, const char **fn_name_p, const char **arg_name_p) { - char *p_start; + const char *p_start; const char *p_end; p_start = strchr (name, '('); @@ -1526,9 +1543,12 @@ transition_applies (insn_pattern *initial_insn, else if (!strcmp (option_name, "Loops")) option_available = (XCHAL_HAVE_LOOPS == 1); else if (!strcmp (option_name, "WideBranches")) - option_available = (XCHAL_HAVE_WIDE_BRANCHES == 1); + option_available + = (XCHAL_HAVE_WIDE_BRANCHES == 1 && produce_flix == FLIX_ALL); else if (!strcmp (option_name, "PredictedBranches")) - option_available = (XCHAL_HAVE_PREDICTED_BRANCHES == 1); + option_available + = (XCHAL_HAVE_PREDICTED_BRANCHES == 1 + && produce_flix == FLIX_ALL); else if (!strcmp (option_name, "Booleans")) option_available = (XCHAL_HAVE_BOOLEANS == 1); else @@ -1550,6 +1570,31 @@ transition_applies (insn_pattern *initial_insn, } +static bfd_boolean +wide_branch_opcode (const char *opcode_name, + const char *suffix, + xtensa_opcode *popcode) +{ + xtensa_isa isa = xtensa_default_isa; + xtensa_opcode opcode; + static char wbr_name_buf[20]; + + if (strncmp (opcode_name, "WIDE.", 5) != 0) + return FALSE; + + strcpy (wbr_name_buf, opcode_name + 5); + strcat (wbr_name_buf, suffix); + opcode = xtensa_opcode_lookup (isa, wbr_name_buf); + if (opcode != XTENSA_UNDEFINED) + { + *popcode = opcode; + return TRUE; + } + + return FALSE; +} + + static TransitionRule * build_transition (insn_pattern *initial_insn, insn_repl *replace_insns, @@ -1559,18 +1604,18 @@ build_transition (insn_pattern *initial_insn, TransitionRule *tr = NULL; xtensa_opcode opcode; xtensa_isa isa = xtensa_default_isa; + BuildInstr *literal_bi; opname_map_e *op1; opname_map_e *op2; precond_e *precond; insn_repl_e *r; - unsigned label_count = 0; - unsigned max_label_count = 0; - bfd_boolean has_label = FALSE; - unsigned literal_count = 0; - opcode = xtensa_opcode_lookup (isa, initial_insn->t.opcode_name); + if (!wide_branch_opcode (initial_insn->t.opcode_name, ".w18", &opcode) + && !wide_branch_opcode (initial_insn->t.opcode_name, ".w15", &opcode)) + opcode = xtensa_opcode_lookup (isa, initial_insn->t.opcode_name); + if (opcode == XTENSA_UNDEFINED) { /* It is OK to not be able to translate some of these opcodes. */ @@ -1632,35 +1677,26 @@ build_transition (insn_pattern *initial_insn, { op1 = get_opmatch (&initial_insn->t.operand_map, precond->opname1); if (op1 == NULL) - { - as_fatal (_("opcode '%s': no bound opname '%s' " - "for precondition in '%s'"), - xtensa_opcode_name (isa, opcode), - precond->opname1, from_string); - return NULL; - } + as_fatal (_("opcode '%s': no bound opname '%s' " + "for precondition in '%s'"), + xtensa_opcode_name (isa, opcode), + precond->opname1, from_string); } if (precond->opname2) { op2 = get_opmatch (&initial_insn->t.operand_map, precond->opname2); if (op2 == NULL) - { - as_fatal (_("opcode '%s': no bound opname '%s' " - "for precondition in %s"), - xtensa_opcode_name (isa, opcode), - precond->opname2, from_string); - return NULL; - } + as_fatal (_("opcode '%s': no bound opname '%s' " + "for precondition in %s"), + xtensa_opcode_name (isa, opcode), + precond->opname2, from_string); } if (op1 == NULL && op2 == NULL) - { - as_fatal (_("opcode '%s': precondition only contains " - "constants in '%s'"), - xtensa_opcode_name (isa, opcode), from_string); - return NULL; - } + as_fatal (_("opcode '%s': precondition only contains " + "constants in '%s'"), + xtensa_opcode_name (isa, opcode), from_string); else if (op1 != NULL && op2 != NULL) append_value_condition (tr, precond->cmpop, op1->operand_num, op2->operand_num); @@ -1675,27 +1711,25 @@ build_transition (insn_pattern *initial_insn, tr->options = clone_req_option_list (initial_insn->options); /* Generate the replacement instructions. Some of these - "instructions" are actually labels and literals. The literals - must be defined in order 0..n and a literal must be defined - (e.g., "LITERAL0 %imm") before use (e.g., "%LITERAL0"). The - labels must be defined in order, but they can be used before they - are defined. Also there are a number of special operands (e.g., - HI24S). */ + "instructions" are actually labels and literals. There can be at + most one literal and at most one label. A literal must be defined + (e.g., "LITERAL %imm") before use (e.g., "%LITERAL"). The labels + can be used before they are defined. Also there are a number of + special operands (e.g., HI24S). */ + literal_bi = NULL; for (r = replace_insns->head; r != NULL; r = r->next) { BuildInstr *bi; const char *opcode_name; int operand_count; opname_map_e *op; - unsigned idnum = 0; const char *fn_name; const char *operand_arg_name; bi = (BuildInstr *) xmalloc (sizeof (BuildInstr)); append_build_insn (tr, bi); - bi->id = 0; bi->opcode = XTENSA_UNDEFINED; bi->ops = NULL; bi->next = NULL; @@ -1703,37 +1737,35 @@ build_transition (insn_pattern *initial_insn, opcode_name = r->t.opcode_name; operand_count = insn_templ_operand_count (&r->t); - if (parse_id_constant (opcode_name, "LITERAL", &idnum)) + if (strcmp (opcode_name, "LITERAL") == 0) { bi->typ = INSTR_LITERAL_DEF; - bi->id = idnum; - if (idnum != literal_count) - as_fatal (_("generated literals must be numbered consecutively")); - ++literal_count; if (operand_count != 1) as_fatal (_("expected one operand for generated literal")); - + literal_bi = bi; } - else if (parse_id_constant (opcode_name, "LABEL", &idnum)) + else if (strcmp (opcode_name, "LABEL") == 0) { bi->typ = INSTR_LABEL_DEF; - bi->id = idnum; - if (idnum != label_count) - as_fatal (_("generated labels must be numbered consecutively")); - ++label_count; if (operand_count != 0) as_fatal (_("expected 0 operands for generated label")); } else { bi->typ = INSTR_INSTR; - bi->opcode = xtensa_opcode_lookup (isa, r->t.opcode_name); + if (wide_branch_opcode (opcode_name, ".w18", &bi->opcode) + || wide_branch_opcode (opcode_name, ".w15", &bi->opcode)) + opcode_name = xtensa_opcode_name (isa, bi->opcode); + else + bi->opcode = xtensa_opcode_lookup (isa, opcode_name); + if (bi->opcode == XTENSA_UNDEFINED) { as_warn (_("invalid opcode '%s' in transition rule '%s'"), - r->t.opcode_name, to_string); + opcode_name, to_string); return NULL; } + /* Check for the right number of ops. */ if (xtensa_opcode_num_operands (isa, bi->opcode) != (int) operand_count) @@ -1748,22 +1780,18 @@ build_transition (insn_pattern *initial_insn, if (op_is_constant (op)) append_constant_op (bi, op->operand_num, op_get_constant (op)); - else if (parse_id_constant (op->operand_name, "%LITERAL", &idnum)) + else if (strcmp (op->operand_name, "%LITERAL") == 0) { - if (idnum >= literal_count) - as_fatal (_("opcode %s: replacement " - "literal %d >= literal_count(%d)"), - opcode_name, idnum, literal_count); - append_literal_op (bi, op->operand_num, idnum); + if (! literal_bi || ! literal_bi->ops || literal_bi->ops->next) + as_fatal (_("opcode '%s': cannot find literal definition"), + opcode_name); + append_literal_op (bi, op->operand_num, + literal_bi->ops->op_data); } - else if (parse_id_constant (op->operand_name, "%LABEL", &idnum)) - { - has_label = TRUE; - if (idnum > max_label_count) - max_label_count = idnum; - append_label_op (bi, op->operand_num, idnum); - } - else if (parse_id_constant (op->operand_name, "a", &idnum)) + else if (strcmp (op->operand_name, "%LABEL") == 0) + append_label_op (bi, op->operand_num); + else if (op->operand_name[0] == 'a' + && parse_constant (op->operand_name + 1, &idnum)) append_constant_op (bi, op->operand_num, idnum); else if (op->operand_name[0] == '%') { @@ -1771,14 +1799,13 @@ build_transition (insn_pattern *initial_insn, orig_op = get_opmatch (&initial_insn->t.operand_map, op->operand_name); if (orig_op == NULL) - { - as_fatal (_("opcode %s: unidentified operand '%s' in '%s'"), - opcode_name, op->operand_name, to_string); - - append_constant_op (bi, op->operand_num, 0); - } - else - append_field_op (bi, op->operand_num, orig_op->operand_num); + as_fatal (_("opcode %s: unidentified operand '%s' in '%s'"), + opcode_name, op->operand_name, to_string); + append_field_op (bi, op->operand_num, orig_op->operand_num); + } + else if (strcmp (op->operand_name, "FREEREG") == 0) + { + append_user_fn_field_op (bi, op->operand_num, OP_FREEREG, 0); } else if (parse_special_fn (op->operand_name, &fn_name, &operand_arg_name)) @@ -1802,30 +1829,16 @@ build_transition (insn_pattern *initial_insn, orig_op = get_opmatch (&initial_insn->t.operand_map, operand_arg_name); if (orig_op == NULL) - { - as_fatal (_("opcode %s: unidentified operand '%s' in '%s'"), - opcode_name, op->operand_name, to_string); - append_constant_op (bi, op->operand_num, 0); - } - else - append_user_fn_field_op (bi, op->operand_num, - typ, orig_op->operand_num); + as_fatal (_("opcode %s: unidentified operand '%s' in '%s'"), + opcode_name, op->operand_name, to_string); + append_user_fn_field_op (bi, op->operand_num, + typ, orig_op->operand_num); } else - { - as_fatal (_("opcode %s: could not parse operand '%s' in '%s'"), - opcode_name, op->operand_name, to_string); - append_constant_op (bi, op->operand_num, 0); - } + as_fatal (_("opcode %s: could not parse operand '%s' in '%s'"), + opcode_name, op->operand_name, to_string); } } - if (has_label && max_label_count >= label_count) - { - as_fatal (_("opcode %s: replacement label %d >= label_count(%d)"), - xtensa_opcode_name (isa, opcode), - max_label_count, label_count); - return NULL; - } return tr; } @@ -1863,20 +1876,11 @@ build_transition_table (const string_pattern_pair *transitions, init_insn_pattern (&initial_insn); if (!parse_insn_pattern (from_string, &initial_insn)) - { - as_fatal (_("could not parse INSN_PATTERN '%s'"), from_string); - clear_insn_pattern (&initial_insn); - continue; - } + as_fatal (_("could not parse INSN_PATTERN '%s'"), from_string); init_insn_repl (&replace_insns); if (!parse_insn_repl (to_string, &replace_insns)) - { - as_fatal (_("could not parse INSN_REPL '%s'"), to_string); - clear_insn_pattern (&initial_insn); - clear_insn_repl (&replace_insns); - continue; - } + as_fatal (_("could not parse INSN_REPL '%s'"), to_string); if (transition_applies (&initial_insn, from_string, to_string)) {