From 90551efeae60f56bb58a2cd94262f398b9260d9c Mon Sep 17 00:00:00 2001 From: jasonwucj Date: Fri, 4 Jul 2014 07:35:43 +0000 Subject: [PATCH] Move some external functions used by machine description patterns to nds32-md-auxiliary.c module. gcc/ * config/nds32/nds32.c (nds32_byte_to_size): Move to ... (nds32_output_casesi_pc_relative): Move to ... (nds32_output_casesi): Move to ... (nds32_mem_format): Move to ... (nds32_output_16bit_store): Move to ... (nds32_output_16bit_load): Move to ... (nds32_output_32bit_store): Move to ... (nds32_output_32bit_load): Move to ... (nds32_output_32bit_load_s): Move to ... (nds32_output_stack_push): Move to ... (nds32_output_stack_pop): Move to ... * config/nds32/nds32-md-auxiliary.c: ... here. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@212286 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 17 + gcc/config/nds32/nds32-md-auxiliary.c | 815 ++++++++++++++++++++++++++++++++++ gcc/config/nds32/nds32.c | 779 -------------------------------- 3 files changed, 832 insertions(+), 779 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 10ded35..cc364eb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,4 +1,21 @@ 2014-07-04 Chung-Ju Wu + Kito Cheng + Monk Chiang + + * config/nds32/nds32.c (nds32_byte_to_size): Move to ... + (nds32_output_casesi_pc_relative): Move to ... + (nds32_output_casesi): Move to ... + (nds32_mem_format): Move to ... + (nds32_output_16bit_store): Move to ... + (nds32_output_16bit_load): Move to ... + (nds32_output_32bit_store): Move to ... + (nds32_output_32bit_load): Move to ... + (nds32_output_32bit_load_s): Move to ... + (nds32_output_stack_push): Move to ... + (nds32_output_stack_pop): Move to ... + * config/nds32/nds32-md-auxiliary.c: ... here. + +2014-07-04 Chung-Ju Wu Ling-Hua Tseng * config/nds32/nds32-pipelines-auxiliary.c: Add comment to describe diff --git a/gcc/config/nds32/nds32-md-auxiliary.c b/gcc/config/nds32/nds32-md-auxiliary.c index c3dcbba..419f4ef 100644 --- a/gcc/config/nds32/nds32-md-auxiliary.c +++ b/gcc/config/nds32/nds32-md-auxiliary.c @@ -18,3 +18,818 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ + +/* ------------------------------------------------------------------------ */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "stor-layout.h" +#include "varasm.h" +#include "calls.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "insn-config.h" /* Required by recog.h. */ +#include "conditions.h" +#include "output.h" +#include "insn-attr.h" /* For DFA state_t. */ +#include "insn-codes.h" /* For CODE_FOR_xxx. */ +#include "reload.h" /* For push_reload(). */ +#include "flags.h" +#include "function.h" +#include "expr.h" +#include "recog.h" +#include "diagnostic-core.h" +#include "df.h" +#include "tm_p.h" +#include "tm-constrs.h" +#include "optabs.h" /* For GEN_FCN. */ +#include "target.h" +#include "target-def.h" +#include "langhooks.h" /* For add_builtin_function(). */ +#include "ggc.h" +#include "builtins.h" + +/* ------------------------------------------------------------------------ */ + +/* A helper function to return character based on byte size. */ +static char +nds32_byte_to_size (int byte) +{ + switch (byte) + { + case 4: + return 'w'; + case 2: + return 'h'; + case 1: + return 'b'; + default: + /* Normally it should not be here. */ + gcc_unreachable (); + } +} + +/* A helper function to return memory format. */ +enum nds32_16bit_address_type +nds32_mem_format (rtx op) +{ + enum machine_mode mode_test; + int val; + int regno; + + if (!TARGET_16_BIT) + return ADDRESS_NOT_16BIT_FORMAT; + + mode_test = GET_MODE (op); + + op = XEXP (op, 0); + + /* 45 format. */ + if (GET_CODE (op) == REG && (mode_test == SImode)) + return ADDRESS_REG; + + /* 333 format for QI/HImode. */ + if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM)) + return ADDRESS_LO_REG_IMM3U; + + /* post_inc 333 format. */ + if ((GET_CODE (op) == POST_INC) && (mode_test == SImode)) + { + regno = REGNO(XEXP (op, 0)); + + if (regno < 8) + return ADDRESS_POST_INC_LO_REG_IMM3U; + } + + /* post_inc 333 format. */ + if ((GET_CODE (op) == POST_MODIFY) + && (mode_test == SImode) + && (REG_P (XEXP (XEXP (op, 1), 0))) + && (CONST_INT_P (XEXP (XEXP (op, 1), 1)))) + { + regno = REGNO (XEXP (XEXP (op, 1), 0)); + val = INTVAL (XEXP (XEXP (op, 1), 1)); + if (regno < 8 && val < 32) + return ADDRESS_POST_INC_LO_REG_IMM3U; + } + + if ((GET_CODE (op) == PLUS) + && (GET_CODE (XEXP (op, 0)) == REG) + && (GET_CODE (XEXP (op, 1)) == CONST_INT)) + { + val = INTVAL (XEXP (op, 1)); + + regno = REGNO(XEXP (op, 0)); + + if (regno > 7 + && regno != SP_REGNUM + && regno != FP_REGNUM) + return ADDRESS_NOT_16BIT_FORMAT; + + switch (mode_test) + { + case QImode: + /* 333 format. */ + if (val >= 0 && val < 8 && regno < 8) + return ADDRESS_LO_REG_IMM3U; + break; + + case HImode: + /* 333 format. */ + if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8) + return ADDRESS_LO_REG_IMM3U; + break; + + case SImode: + case SFmode: + case DFmode: + /* fp imply 37 format. */ + if ((regno == FP_REGNUM) && + (val >= 0 && val < 512 && (val % 4 == 0))) + return ADDRESS_FP_IMM7U; + /* sp imply 37 format. */ + else if ((regno == SP_REGNUM) && + (val >= 0 && val < 512 && (val % 4 == 0))) + return ADDRESS_SP_IMM7U; + /* 333 format. */ + else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8) + return ADDRESS_LO_REG_IMM3U; + break; + + default: + break; + } + } + + return ADDRESS_NOT_16BIT_FORMAT; +} + +/* Output 16-bit store. */ +const char * +nds32_output_16bit_store (rtx *operands, int byte) +{ + char pattern[100]; + char size; + rtx code = XEXP (operands[0], 0); + + size = nds32_byte_to_size (byte); + + switch (nds32_mem_format (operands[0])) + { + case ADDRESS_REG: + operands[0] = code; + output_asm_insn ("swi450\t%1, [%0]", operands); + break; + case ADDRESS_LO_REG_IMM3U: + snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size); + output_asm_insn (pattern, operands); + break; + case ADDRESS_POST_INC_LO_REG_IMM3U: + snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size); + output_asm_insn (pattern, operands); + break; + case ADDRESS_FP_IMM7U: + output_asm_insn ("swi37\t%1, %0", operands); + break; + case ADDRESS_SP_IMM7U: + /* Get immediate value and set back to operands[1]. */ + operands[0] = XEXP (code, 1); + output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands); + break; + default: + break; + } + + return ""; +} + +/* Output 16-bit load. */ +const char * +nds32_output_16bit_load (rtx *operands, int byte) +{ + char pattern[100]; + unsigned char size; + rtx code = XEXP (operands[1], 0); + + size = nds32_byte_to_size (byte); + + switch (nds32_mem_format (operands[1])) + { + case ADDRESS_REG: + operands[1] = code; + output_asm_insn ("lwi450\t%0, [%1]", operands); + break; + case ADDRESS_LO_REG_IMM3U: + snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size); + output_asm_insn (pattern, operands); + break; + case ADDRESS_POST_INC_LO_REG_IMM3U: + snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size); + output_asm_insn (pattern, operands); + break; + case ADDRESS_FP_IMM7U: + output_asm_insn ("lwi37\t%0, %1", operands); + break; + case ADDRESS_SP_IMM7U: + /* Get immediate value and set back to operands[0]. */ + operands[1] = XEXP (code, 1); + output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands); + break; + default: + break; + } + + return ""; +} + +/* Output 32-bit store. */ +const char * +nds32_output_32bit_store (rtx *operands, int byte) +{ + char pattern[100]; + unsigned char size; + rtx code = XEXP (operands[0], 0); + + size = nds32_byte_to_size (byte); + + switch (GET_CODE (code)) + { + case REG: + /* (mem (reg X)) + => access location by using register, + use "sbi / shi / swi" */ + snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size); + break; + + case SYMBOL_REF: + case CONST: + /* (mem (symbol_ref X)) + (mem (const (...))) + => access global variables, + use "sbi.gp / shi.gp / swi.gp" */ + operands[0] = XEXP (operands[0], 0); + snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size); + break; + + case POST_INC: + /* (mem (post_inc reg)) + => access location by using register which will be post increment, + use "sbi.bi / shi.bi / swi.bi" */ + snprintf (pattern, sizeof (pattern), + "s%ci.bi\t%%1, %%0, %d", size, byte); + break; + + case POST_DEC: + /* (mem (post_dec reg)) + => access location by using register which will be post decrement, + use "sbi.bi / shi.bi / swi.bi" */ + snprintf (pattern, sizeof (pattern), + "s%ci.bi\t%%1, %%0, -%d", size, byte); + break; + + case POST_MODIFY: + switch (GET_CODE (XEXP (XEXP (code, 1), 1))) + { + case REG: + case SUBREG: + /* (mem (post_modify (reg) (plus (reg) (reg)))) + => access location by using register which will be + post modified with reg, + use "sb.bi/ sh.bi / sw.bi" */ + snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size); + break; + case CONST_INT: + /* (mem (post_modify (reg) (plus (reg) (const_int)))) + => access location by using register which will be + post modified with const_int, + use "sbi.bi/ shi.bi / swi.bi" */ + snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size); + break; + default: + abort (); + } + break; + + case PLUS: + switch (GET_CODE (XEXP (code, 1))) + { + case REG: + case SUBREG: + /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) + => access location by adding two registers, + use "sb / sh / sw" */ + snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size); + break; + case CONST_INT: + /* (mem (plus reg const_int)) + => access location by adding one register with const_int, + use "sbi / shi / swi" */ + snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size); + break; + default: + abort (); + } + break; + + case LO_SUM: + operands[2] = XEXP (code, 1); + operands[0] = XEXP (code, 0); + snprintf (pattern, sizeof (pattern), + "s%ci\t%%1, [%%0 + lo12(%%2)]", size); + break; + + default: + abort (); + } + + output_asm_insn (pattern, operands); + return ""; +} + +/* Output 32-bit load. */ +const char * +nds32_output_32bit_load (rtx *operands, int byte) +{ + char pattern[100]; + unsigned char size; + rtx code; + + code = XEXP (operands[1], 0); + + size = nds32_byte_to_size (byte); + + switch (GET_CODE (code)) + { + case REG: + /* (mem (reg X)) + => access location by using register, + use "lbi / lhi / lwi" */ + snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size); + break; + + case SYMBOL_REF: + case CONST: + /* (mem (symbol_ref X)) + (mem (const (...))) + => access global variables, + use "lbi.gp / lhi.gp / lwi.gp" */ + operands[1] = XEXP (operands[1], 0); + snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size); + break; + + case POST_INC: + /* (mem (post_inc reg)) + => access location by using register which will be post increment, + use "lbi.bi / lhi.bi / lwi.bi" */ + snprintf (pattern, sizeof (pattern), + "l%ci.bi\t%%0, %%1, %d", size, byte); + break; + + case POST_DEC: + /* (mem (post_dec reg)) + => access location by using register which will be post decrement, + use "lbi.bi / lhi.bi / lwi.bi" */ + snprintf (pattern, sizeof (pattern), + "l%ci.bi\t%%0, %%1, -%d", size, byte); + break; + + case POST_MODIFY: + switch (GET_CODE (XEXP (XEXP (code, 1), 1))) + { + case REG: + case SUBREG: + /* (mem (post_modify (reg) (plus (reg) (reg)))) + => access location by using register which will be + post modified with reg, + use "lb.bi/ lh.bi / lw.bi" */ + snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size); + break; + case CONST_INT: + /* (mem (post_modify (reg) (plus (reg) (const_int)))) + => access location by using register which will be + post modified with const_int, + use "lbi.bi/ lhi.bi / lwi.bi" */ + snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size); + break; + default: + abort (); + } + break; + + case PLUS: + switch (GET_CODE (XEXP (code, 1))) + { + case REG: + case SUBREG: + /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) + use "lb / lh / lw" */ + snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size); + break; + case CONST_INT: + /* (mem (plus reg const_int)) + => access location by adding one register with const_int, + use "lbi / lhi / lwi" */ + snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size); + break; + default: + abort (); + } + break; + + case LO_SUM: + operands[2] = XEXP (code, 1); + operands[1] = XEXP (code, 0); + snprintf (pattern, sizeof (pattern), + "l%ci\t%%0, [%%1 + lo12(%%2)]", size); + break; + + default: + abort (); + } + + output_asm_insn (pattern, operands); + return ""; +} + +/* Output 32-bit load with signed extension. */ +const char * +nds32_output_32bit_load_s (rtx *operands, int byte) +{ + char pattern[100]; + unsigned char size; + rtx code; + + code = XEXP (operands[1], 0); + + size = nds32_byte_to_size (byte); + + switch (GET_CODE (code)) + { + case REG: + /* (mem (reg X)) + => access location by using register, + use "lbsi / lhsi" */ + snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size); + break; + + case SYMBOL_REF: + case CONST: + /* (mem (symbol_ref X)) + (mem (const (...))) + => access global variables, + use "lbsi.gp / lhsi.gp" */ + operands[1] = XEXP (operands[1], 0); + snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size); + break; + + case POST_INC: + /* (mem (post_inc reg)) + => access location by using register which will be post increment, + use "lbsi.bi / lhsi.bi" */ + snprintf (pattern, sizeof (pattern), + "l%csi.bi\t%%0, %%1, %d", size, byte); + break; + + case POST_DEC: + /* (mem (post_dec reg)) + => access location by using register which will be post decrement, + use "lbsi.bi / lhsi.bi" */ + snprintf (pattern, sizeof (pattern), + "l%csi.bi\t%%0, %%1, -%d", size, byte); + break; + + case POST_MODIFY: + switch (GET_CODE (XEXP (XEXP (code, 1), 1))) + { + case REG: + case SUBREG: + /* (mem (post_modify (reg) (plus (reg) (reg)))) + => access location by using register which will be + post modified with reg, + use "lbs.bi/ lhs.bi" */ + snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size); + break; + case CONST_INT: + /* (mem (post_modify (reg) (plus (reg) (const_int)))) + => access location by using register which will be + post modified with const_int, + use "lbsi.bi/ lhsi.bi" */ + snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size); + break; + default: + abort (); + } + break; + + case PLUS: + switch (GET_CODE (XEXP (code, 1))) + { + case REG: + case SUBREG: + /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) + use "lbs / lhs" */ + snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size); + break; + case CONST_INT: + /* (mem (plus reg const_int)) + => access location by adding one register with const_int, + use "lbsi / lhsi" */ + snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size); + break; + default: + abort (); + } + break; + + case LO_SUM: + operands[2] = XEXP (code, 1); + operands[1] = XEXP (code, 0); + snprintf (pattern, sizeof (pattern), + "l%csi\t%%0, [%%1 + lo12(%%2)]", size); + break; + + default: + abort (); + } + + output_asm_insn (pattern, operands); + return ""; +} + +/* Function to output stack push operation. + We need to deal with normal stack push multiple or stack v3push. */ +const char * +nds32_output_stack_push (void) +{ + /* A string pattern for output_asm_insn(). */ + char pattern[100]; + /* The operands array which will be used in output_asm_insn(). */ + rtx operands[3]; + /* Pick up callee-saved first regno and last regno for further use. */ + int rb_regno = cfun->machine->callee_saved_regs_first_regno; + int re_regno = cfun->machine->callee_saved_regs_last_regno; + + if (TARGET_V3PUSH) + { + /* For stack v3push: + operands[0]: Re + operands[1]: imm8u */ + + /* This variable is to check if 'push25 Re,imm8u' is available. */ + int sp_adjust; + + /* Set operands[0]. */ + operands[0] = gen_rtx_REG (SImode, re_regno); + + /* Check if we can generate 'push25 Re,imm8u', + otherwise, generate 'push25 Re,0'. */ + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_padding_bytes; + if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) + && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)) + operands[1] = GEN_INT (sp_adjust); + else + operands[1] = GEN_INT (0); + + /* Create assembly code pattern. */ + snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1"); + } + else + { + /* For normal stack push multiple: + operands[0]: Rb + operands[1]: Re + operands[2]: En4 */ + + /* This variable is used to check if we only need to generate En4 field. + As long as Rb==Re=SP_REGNUM, we set this variable to 1. */ + int push_en4_only_p = 0; + + /* Set operands[0] and operands[1]. */ + operands[0] = gen_rtx_REG (SImode, rb_regno); + operands[1] = gen_rtx_REG (SImode, re_regno); + + /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */ + if (!cfun->machine->fp_size + && !cfun->machine->gp_size + && !cfun->machine->lp_size + && REGNO (operands[0]) == SP_REGNUM + && REGNO (operands[1]) == SP_REGNUM) + { + /* No need to generate instruction. */ + return ""; + } + else + { + /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */ + if (REGNO (operands[0]) == SP_REGNUM + && REGNO (operands[1]) == SP_REGNUM) + push_en4_only_p = 1; + + /* Create assembly code pattern. + We need to handle the form: "Rb, Re, { $fp $gp $lp }". */ + snprintf (pattern, sizeof (pattern), + "push.s\t%s{%s%s%s }", + push_en4_only_p ? "" : "%0, %1, ", + cfun->machine->fp_size ? " $fp" : "", + cfun->machine->gp_size ? " $gp" : "", + cfun->machine->lp_size ? " $lp" : ""); + } + } + + /* We use output_asm_insn() to output assembly code by ourself. */ + output_asm_insn (pattern, operands); + return ""; +} + +/* Function to output stack pop operation. + We need to deal with normal stack pop multiple or stack v3pop. */ +const char * +nds32_output_stack_pop (void) +{ + /* A string pattern for output_asm_insn(). */ + char pattern[100]; + /* The operands array which will be used in output_asm_insn(). */ + rtx operands[3]; + /* Pick up callee-saved first regno and last regno for further use. */ + int rb_regno = cfun->machine->callee_saved_regs_first_regno; + int re_regno = cfun->machine->callee_saved_regs_last_regno; + + if (TARGET_V3PUSH) + { + /* For stack v3pop: + operands[0]: Re + operands[1]: imm8u */ + + /* This variable is to check if 'pop25 Re,imm8u' is available. */ + int sp_adjust; + + /* Set operands[0]. */ + operands[0] = gen_rtx_REG (SImode, re_regno); + + /* Check if we can generate 'pop25 Re,imm8u', + otherwise, generate 'pop25 Re,0'. + We have to consider alloca issue as well. + If the function does call alloca(), the stack pointer is not fixed. + In that case, we cannot use 'pop25 Re,imm8u' directly. + We have to caculate stack pointer from frame pointer + and then use 'pop25 Re,0'. */ + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_padding_bytes; + if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) + && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust) + && !cfun->calls_alloca) + operands[1] = GEN_INT (sp_adjust); + else + operands[1] = GEN_INT (0); + + /* Create assembly code pattern. */ + snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1"); + } + else + { + /* For normal stack pop multiple: + operands[0]: Rb + operands[1]: Re + operands[2]: En4 */ + + /* This variable is used to check if we only need to generate En4 field. + As long as Rb==Re=SP_REGNUM, we set this variable to 1. */ + int pop_en4_only_p = 0; + + /* Set operands[0] and operands[1]. */ + operands[0] = gen_rtx_REG (SImode, rb_regno); + operands[1] = gen_rtx_REG (SImode, re_regno); + + /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */ + if (!cfun->machine->fp_size + && !cfun->machine->gp_size + && !cfun->machine->lp_size + && REGNO (operands[0]) == SP_REGNUM + && REGNO (operands[1]) == SP_REGNUM) + { + /* No need to generate instruction. */ + return ""; + } + else + { + /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */ + if (REGNO (operands[0]) == SP_REGNUM + && REGNO (operands[1]) == SP_REGNUM) + pop_en4_only_p = 1; + + /* Create assembly code pattern. + We need to handle the form: "Rb, Re, { $fp $gp $lp }". */ + snprintf (pattern, sizeof (pattern), + "pop.s\t%s{%s%s%s }", + pop_en4_only_p ? "" : "%0, %1, ", + cfun->machine->fp_size ? " $fp" : "", + cfun->machine->gp_size ? " $gp" : "", + cfun->machine->lp_size ? " $lp" : ""); + } + } + + /* We use output_asm_insn() to output assembly code by ourself. */ + output_asm_insn (pattern, operands); + return ""; +} + +/* Function to generate PC relative jump table. + Refer to nds32.md for more details. + + The following is the sample for the case that diff value + can be presented in '.short' size. + + addi $r1, $r1, -(case_lower_bound) + slti $ta, $r1, (case_number) + beqz $ta, .L_skip_label + + la $ta, .L35 ! get jump table address + lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry + addi $ta, $r1, $ta + jr5 $ta + + ! jump table entry + L35: + .short .L25-.L35 + .short .L26-.L35 + .short .L27-.L35 + .short .L28-.L35 + .short .L29-.L35 + .short .L30-.L35 + .short .L31-.L35 + .short .L32-.L35 + .short .L33-.L35 + .short .L34-.L35 */ +const char * +nds32_output_casesi_pc_relative (rtx *operands) +{ + enum machine_mode mode; + rtx diff_vec; + + diff_vec = PATTERN (NEXT_INSN (operands[1])); + + gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); + + /* Step C: "t <-- operands[1]". */ + output_asm_insn ("la\t$ta, %l1", operands); + + /* Get the mode of each element in the difference vector. */ + mode = GET_MODE (diff_vec); + + /* Step D: "z <-- (mem (plus (operands[0] << m) t))", + where m is 0, 1, or 2 to load address-diff value from table. */ + switch (mode) + { + case QImode: + output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands); + break; + case HImode: + output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands); + break; + case SImode: + output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); + break; + default: + gcc_unreachable (); + } + + /* Step E: "t <-- z + t". + Add table label_ref with address-diff value to + obtain target case address. */ + output_asm_insn ("add\t$ta, %2, $ta", operands); + + /* Step F: jump to target with register t. */ + if (TARGET_16_BIT) + return "jr5\t$ta"; + else + return "jr\t$ta"; +} + +/* Function to generate normal jump table. */ +const char * +nds32_output_casesi (rtx *operands) +{ + /* Step C: "t <-- operands[1]". */ + output_asm_insn ("la\t$ta, %l1", operands); + + /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */ + output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); + + /* No need to perform Step E, which is only used for + pc relative jump table. */ + + /* Step F: jump to target with register z. */ + if (TARGET_16_BIT) + return "jr5\t%2"; + else + return "jr\t%2"; +} + +/* ------------------------------------------------------------------------ */ diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c index 7361912..eb3fbef 100644 --- a/gcc/config/nds32/nds32.c +++ b/gcc/config/nds32/nds32.c @@ -1106,24 +1106,6 @@ nds32_legitimate_index_p (enum machine_mode outer_mode, } } -/* A helper function to return character based on byte size. */ -static char -nds32_byte_to_size (int byte) -{ - switch (byte) - { - case 4: - return 'w'; - case 2: - return 'h'; - case 1: - return 'b'; - default: - /* Normally it should not be here. */ - gcc_unreachable (); - } -} - /* A helper function to check if this function should contain prologue. */ static int nds32_have_prologue_p (void) @@ -3436,767 +3418,6 @@ nds32_fp_as_gp_check_available (void) return 0; } - -/* Function to generate PC relative jump table. - Refer to nds32.md for more details. - - The following is the sample for the case that diff value - can be presented in '.short' size. - - addi $r1, $r1, -(case_lower_bound) - slti $ta, $r1, (case_number) - beqz $ta, .L_skip_label - - la $ta, .L35 ! get jump table address - lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry - addi $ta, $r1, $ta - jr5 $ta - - ! jump table entry - L35: - .short .L25-.L35 - .short .L26-.L35 - .short .L27-.L35 - .short .L28-.L35 - .short .L29-.L35 - .short .L30-.L35 - .short .L31-.L35 - .short .L32-.L35 - .short .L33-.L35 - .short .L34-.L35 */ -const char * -nds32_output_casesi_pc_relative (rtx *operands) -{ - enum machine_mode mode; - rtx diff_vec; - - diff_vec = PATTERN (NEXT_INSN (operands[1])); - - gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); - - /* Step C: "t <-- operands[1]". */ - output_asm_insn ("la\t$ta, %l1", operands); - - /* Get the mode of each element in the difference vector. */ - mode = GET_MODE (diff_vec); - - /* Step D: "z <-- (mem (plus (operands[0] << m) t))", - where m is 0, 1, or 2 to load address-diff value from table. */ - switch (mode) - { - case QImode: - output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands); - break; - case HImode: - output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands); - break; - case SImode: - output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); - break; - default: - gcc_unreachable (); - } - - /* Step E: "t <-- z + t". - Add table label_ref with address-diff value to - obtain target case address. */ - output_asm_insn ("add\t$ta, %2, $ta", operands); - - /* Step F: jump to target with register t. */ - if (TARGET_16_BIT) - return "jr5\t$ta"; - else - return "jr\t$ta"; -} - -/* Function to generate normal jump table. */ -const char * -nds32_output_casesi (rtx *operands) -{ - /* Step C: "t <-- operands[1]". */ - output_asm_insn ("la\t$ta, %l1", operands); - - /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */ - output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); - - /* No need to perform Step E, which is only used for - pc relative jump table. */ - - /* Step F: jump to target with register z. */ - if (TARGET_16_BIT) - return "jr5\t%2"; - else - return "jr\t%2"; -} - - -/* Function to return memory format. */ -enum nds32_16bit_address_type -nds32_mem_format (rtx op) -{ - enum machine_mode mode_test; - int val; - int regno; - - if (!TARGET_16_BIT) - return ADDRESS_NOT_16BIT_FORMAT; - - mode_test = GET_MODE (op); - - op = XEXP (op, 0); - - /* 45 format. */ - if (GET_CODE (op) == REG && (mode_test == SImode)) - return ADDRESS_REG; - - /* 333 format for QI/HImode. */ - if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM)) - return ADDRESS_LO_REG_IMM3U; - - /* post_inc 333 format. */ - if ((GET_CODE (op) == POST_INC) && (mode_test == SImode)) - { - regno = REGNO(XEXP (op, 0)); - - if (regno < 8) - return ADDRESS_POST_INC_LO_REG_IMM3U; - } - - /* post_inc 333 format. */ - if ((GET_CODE (op) == POST_MODIFY) - && (mode_test == SImode) - && (REG_P (XEXP (XEXP (op, 1), 0))) - && (CONST_INT_P (XEXP (XEXP (op, 1), 1)))) - { - regno = REGNO (XEXP (XEXP (op, 1), 0)); - val = INTVAL (XEXP (XEXP (op, 1), 1)); - if (regno < 8 && val < 32) - return ADDRESS_POST_INC_LO_REG_IMM3U; - } - - if ((GET_CODE (op) == PLUS) - && (GET_CODE (XEXP (op, 0)) == REG) - && (GET_CODE (XEXP (op, 1)) == CONST_INT)) - { - val = INTVAL (XEXP (op, 1)); - - regno = REGNO(XEXP (op, 0)); - - if (regno > 7 - && regno != SP_REGNUM - && regno != FP_REGNUM) - return ADDRESS_NOT_16BIT_FORMAT; - - switch (mode_test) - { - case QImode: - /* 333 format. */ - if (val >= 0 && val < 8 && regno < 8) - return ADDRESS_LO_REG_IMM3U; - break; - - case HImode: - /* 333 format. */ - if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8) - return ADDRESS_LO_REG_IMM3U; - break; - - case SImode: - case SFmode: - case DFmode: - /* fp imply 37 format. */ - if ((regno == FP_REGNUM) && - (val >= 0 && val < 512 && (val % 4 == 0))) - return ADDRESS_FP_IMM7U; - /* sp imply 37 format. */ - else if ((regno == SP_REGNUM) && - (val >= 0 && val < 512 && (val % 4 == 0))) - return ADDRESS_SP_IMM7U; - /* 333 format. */ - else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8) - return ADDRESS_LO_REG_IMM3U; - break; - - default: - break; - } - } - - return ADDRESS_NOT_16BIT_FORMAT; -} - -/* Output 16-bit store. */ -const char * -nds32_output_16bit_store (rtx *operands, int byte) -{ - char pattern[100]; - char size; - rtx code = XEXP (operands[0], 0); - - size = nds32_byte_to_size (byte); - - switch (nds32_mem_format (operands[0])) - { - case ADDRESS_REG: - operands[0] = code; - output_asm_insn ("swi450\t%1, [%0]", operands); - break; - case ADDRESS_LO_REG_IMM3U: - snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size); - output_asm_insn (pattern, operands); - break; - case ADDRESS_POST_INC_LO_REG_IMM3U: - snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size); - output_asm_insn (pattern, operands); - break; - case ADDRESS_FP_IMM7U: - output_asm_insn ("swi37\t%1, %0", operands); - break; - case ADDRESS_SP_IMM7U: - /* Get immediate value and set back to operands[1]. */ - operands[0] = XEXP (code, 1); - output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands); - break; - default: - break; - } - - return ""; -} - -/* Output 16-bit load. */ -const char * -nds32_output_16bit_load (rtx *operands, int byte) -{ - char pattern[100]; - unsigned char size; - rtx code = XEXP (operands[1], 0); - - size = nds32_byte_to_size (byte); - - switch (nds32_mem_format (operands[1])) - { - case ADDRESS_REG: - operands[1] = code; - output_asm_insn ("lwi450\t%0, [%1]", operands); - break; - case ADDRESS_LO_REG_IMM3U: - snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size); - output_asm_insn (pattern, operands); - break; - case ADDRESS_POST_INC_LO_REG_IMM3U: - snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size); - output_asm_insn (pattern, operands); - break; - case ADDRESS_FP_IMM7U: - output_asm_insn ("lwi37\t%0, %1", operands); - break; - case ADDRESS_SP_IMM7U: - /* Get immediate value and set back to operands[0]. */ - operands[1] = XEXP (code, 1); - output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands); - break; - default: - break; - } - - return ""; -} - -/* Output 32-bit store. */ -const char * -nds32_output_32bit_store (rtx *operands, int byte) -{ - char pattern[100]; - unsigned char size; - rtx code = XEXP (operands[0], 0); - - size = nds32_byte_to_size (byte); - - switch (GET_CODE (code)) - { - case REG: - /* (mem (reg X)) - => access location by using register, - use "sbi / shi / swi" */ - snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size); - break; - - case SYMBOL_REF: - case CONST: - /* (mem (symbol_ref X)) - (mem (const (...))) - => access global variables, - use "sbi.gp / shi.gp / swi.gp" */ - operands[0] = XEXP (operands[0], 0); - snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size); - break; - - case POST_INC: - /* (mem (post_inc reg)) - => access location by using register which will be post increment, - use "sbi.bi / shi.bi / swi.bi" */ - snprintf (pattern, sizeof (pattern), - "s%ci.bi\t%%1, %%0, %d", size, byte); - break; - - case POST_DEC: - /* (mem (post_dec reg)) - => access location by using register which will be post decrement, - use "sbi.bi / shi.bi / swi.bi" */ - snprintf (pattern, sizeof (pattern), - "s%ci.bi\t%%1, %%0, -%d", size, byte); - break; - - case POST_MODIFY: - switch (GET_CODE (XEXP (XEXP (code, 1), 1))) - { - case REG: - case SUBREG: - /* (mem (post_modify (reg) (plus (reg) (reg)))) - => access location by using register which will be - post modified with reg, - use "sb.bi/ sh.bi / sw.bi" */ - snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size); - break; - case CONST_INT: - /* (mem (post_modify (reg) (plus (reg) (const_int)))) - => access location by using register which will be - post modified with const_int, - use "sbi.bi/ shi.bi / swi.bi" */ - snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size); - break; - default: - abort (); - } - break; - - case PLUS: - switch (GET_CODE (XEXP (code, 1))) - { - case REG: - case SUBREG: - /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) - => access location by adding two registers, - use "sb / sh / sw" */ - snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size); - break; - case CONST_INT: - /* (mem (plus reg const_int)) - => access location by adding one register with const_int, - use "sbi / shi / swi" */ - snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size); - break; - default: - abort (); - } - break; - - case LO_SUM: - operands[2] = XEXP (code, 1); - operands[0] = XEXP (code, 0); - snprintf (pattern, sizeof (pattern), - "s%ci\t%%1, [%%0 + lo12(%%2)]", size); - break; - - default: - abort (); - } - - output_asm_insn (pattern, operands); - return ""; -} - -/* Output 32-bit load. */ -const char * -nds32_output_32bit_load (rtx *operands, int byte) -{ - char pattern[100]; - unsigned char size; - rtx code; - - code = XEXP (operands[1], 0); - - size = nds32_byte_to_size (byte); - - switch (GET_CODE (code)) - { - case REG: - /* (mem (reg X)) - => access location by using register, - use "lbi / lhi / lwi" */ - snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size); - break; - - case SYMBOL_REF: - case CONST: - /* (mem (symbol_ref X)) - (mem (const (...))) - => access global variables, - use "lbi.gp / lhi.gp / lwi.gp" */ - operands[1] = XEXP (operands[1], 0); - snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size); - break; - - case POST_INC: - /* (mem (post_inc reg)) - => access location by using register which will be post increment, - use "lbi.bi / lhi.bi / lwi.bi" */ - snprintf (pattern, sizeof (pattern), - "l%ci.bi\t%%0, %%1, %d", size, byte); - break; - - case POST_DEC: - /* (mem (post_dec reg)) - => access location by using register which will be post decrement, - use "lbi.bi / lhi.bi / lwi.bi" */ - snprintf (pattern, sizeof (pattern), - "l%ci.bi\t%%0, %%1, -%d", size, byte); - break; - - case POST_MODIFY: - switch (GET_CODE (XEXP (XEXP (code, 1), 1))) - { - case REG: - case SUBREG: - /* (mem (post_modify (reg) (plus (reg) (reg)))) - => access location by using register which will be - post modified with reg, - use "lb.bi/ lh.bi / lw.bi" */ - snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size); - break; - case CONST_INT: - /* (mem (post_modify (reg) (plus (reg) (const_int)))) - => access location by using register which will be - post modified with const_int, - use "lbi.bi/ lhi.bi / lwi.bi" */ - snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size); - break; - default: - abort (); - } - break; - - case PLUS: - switch (GET_CODE (XEXP (code, 1))) - { - case REG: - case SUBREG: - /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) - use "lb / lh / lw" */ - snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size); - break; - case CONST_INT: - /* (mem (plus reg const_int)) - => access location by adding one register with const_int, - use "lbi / lhi / lwi" */ - snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size); - break; - default: - abort (); - } - break; - - case LO_SUM: - operands[2] = XEXP (code, 1); - operands[1] = XEXP (code, 0); - snprintf (pattern, sizeof (pattern), - "l%ci\t%%0, [%%1 + lo12(%%2)]", size); - break; - - default: - abort (); - } - - output_asm_insn (pattern, operands); - return ""; -} - -/* Output 32-bit load with signed extension. */ -const char * -nds32_output_32bit_load_s (rtx *operands, int byte) -{ - char pattern[100]; - unsigned char size; - rtx code; - - code = XEXP (operands[1], 0); - - size = nds32_byte_to_size (byte); - - switch (GET_CODE (code)) - { - case REG: - /* (mem (reg X)) - => access location by using register, - use "lbsi / lhsi" */ - snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size); - break; - - case SYMBOL_REF: - case CONST: - /* (mem (symbol_ref X)) - (mem (const (...))) - => access global variables, - use "lbsi.gp / lhsi.gp" */ - operands[1] = XEXP (operands[1], 0); - snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size); - break; - - case POST_INC: - /* (mem (post_inc reg)) - => access location by using register which will be post increment, - use "lbsi.bi / lhsi.bi" */ - snprintf (pattern, sizeof (pattern), - "l%csi.bi\t%%0, %%1, %d", size, byte); - break; - - case POST_DEC: - /* (mem (post_dec reg)) - => access location by using register which will be post decrement, - use "lbsi.bi / lhsi.bi" */ - snprintf (pattern, sizeof (pattern), - "l%csi.bi\t%%0, %%1, -%d", size, byte); - break; - - case POST_MODIFY: - switch (GET_CODE (XEXP (XEXP (code, 1), 1))) - { - case REG: - case SUBREG: - /* (mem (post_modify (reg) (plus (reg) (reg)))) - => access location by using register which will be - post modified with reg, - use "lbs.bi/ lhs.bi" */ - snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size); - break; - case CONST_INT: - /* (mem (post_modify (reg) (plus (reg) (const_int)))) - => access location by using register which will be - post modified with const_int, - use "lbsi.bi/ lhsi.bi" */ - snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size); - break; - default: - abort (); - } - break; - - case PLUS: - switch (GET_CODE (XEXP (code, 1))) - { - case REG: - case SUBREG: - /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) - use "lbs / lhs" */ - snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size); - break; - case CONST_INT: - /* (mem (plus reg const_int)) - => access location by adding one register with const_int, - use "lbsi / lhsi" */ - snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size); - break; - default: - abort (); - } - break; - - case LO_SUM: - operands[2] = XEXP (code, 1); - operands[1] = XEXP (code, 0); - snprintf (pattern, sizeof (pattern), - "l%csi\t%%0, [%%1 + lo12(%%2)]", size); - break; - - default: - abort (); - } - - output_asm_insn (pattern, operands); - return ""; -} - -/* Function to output stack push operation. - We need to deal with normal stack push multiple or stack v3push. */ -const char * -nds32_output_stack_push (void) -{ - /* A string pattern for output_asm_insn(). */ - char pattern[100]; - /* The operands array which will be used in output_asm_insn(). */ - rtx operands[3]; - /* Pick up callee-saved first regno and last regno for further use. */ - int rb_regno = cfun->machine->callee_saved_regs_first_regno; - int re_regno = cfun->machine->callee_saved_regs_last_regno; - - if (TARGET_V3PUSH) - { - /* For stack v3push: - operands[0]: Re - operands[1]: imm8u */ - - /* This variable is to check if 'push25 Re,imm8u' is available. */ - int sp_adjust; - - /* Set operands[0]. */ - operands[0] = gen_rtx_REG (SImode, re_regno); - - /* Check if we can generate 'push25 Re,imm8u', - otherwise, generate 'push25 Re,0'. */ - sp_adjust = cfun->machine->local_size - + cfun->machine->out_args_size - + cfun->machine->callee_saved_area_padding_bytes; - if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) - && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)) - operands[1] = GEN_INT (sp_adjust); - else - operands[1] = GEN_INT (0); - - /* Create assembly code pattern. */ - snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1"); - } - else - { - /* For normal stack push multiple: - operands[0]: Rb - operands[1]: Re - operands[2]: En4 */ - - /* This variable is used to check if we only need to generate En4 field. - As long as Rb==Re=SP_REGNUM, we set this variable to 1. */ - int push_en4_only_p = 0; - - /* Set operands[0] and operands[1]. */ - operands[0] = gen_rtx_REG (SImode, rb_regno); - operands[1] = gen_rtx_REG (SImode, re_regno); - - /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */ - if (!cfun->machine->fp_size - && !cfun->machine->gp_size - && !cfun->machine->lp_size - && REGNO (operands[0]) == SP_REGNUM - && REGNO (operands[1]) == SP_REGNUM) - { - /* No need to generate instruction. */ - return ""; - } - else - { - /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */ - if (REGNO (operands[0]) == SP_REGNUM - && REGNO (operands[1]) == SP_REGNUM) - push_en4_only_p = 1; - - /* Create assembly code pattern. - We need to handle the form: "Rb, Re, { $fp $gp $lp }". */ - snprintf (pattern, sizeof (pattern), - "push.s\t%s{%s%s%s }", - push_en4_only_p ? "" : "%0, %1, ", - cfun->machine->fp_size ? " $fp" : "", - cfun->machine->gp_size ? " $gp" : "", - cfun->machine->lp_size ? " $lp" : ""); - } - } - - /* We use output_asm_insn() to output assembly code by ourself. */ - output_asm_insn (pattern, operands); - return ""; -} - -/* Function to output stack pop operation. - We need to deal with normal stack pop multiple or stack v3pop. */ -const char * -nds32_output_stack_pop (void) -{ - /* A string pattern for output_asm_insn(). */ - char pattern[100]; - /* The operands array which will be used in output_asm_insn(). */ - rtx operands[3]; - /* Pick up callee-saved first regno and last regno for further use. */ - int rb_regno = cfun->machine->callee_saved_regs_first_regno; - int re_regno = cfun->machine->callee_saved_regs_last_regno; - - if (TARGET_V3PUSH) - { - /* For stack v3pop: - operands[0]: Re - operands[1]: imm8u */ - - /* This variable is to check if 'pop25 Re,imm8u' is available. */ - int sp_adjust; - - /* Set operands[0]. */ - operands[0] = gen_rtx_REG (SImode, re_regno); - - /* Check if we can generate 'pop25 Re,imm8u', - otherwise, generate 'pop25 Re,0'. - We have to consider alloca issue as well. - If the function does call alloca(), the stack pointer is not fixed. - In that case, we cannot use 'pop25 Re,imm8u' directly. - We have to caculate stack pointer from frame pointer - and then use 'pop25 Re,0'. */ - sp_adjust = cfun->machine->local_size - + cfun->machine->out_args_size - + cfun->machine->callee_saved_area_padding_bytes; - if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) - && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust) - && !cfun->calls_alloca) - operands[1] = GEN_INT (sp_adjust); - else - operands[1] = GEN_INT (0); - - /* Create assembly code pattern. */ - snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1"); - } - else - { - /* For normal stack pop multiple: - operands[0]: Rb - operands[1]: Re - operands[2]: En4 */ - - /* This variable is used to check if we only need to generate En4 field. - As long as Rb==Re=SP_REGNUM, we set this variable to 1. */ - int pop_en4_only_p = 0; - - /* Set operands[0] and operands[1]. */ - operands[0] = gen_rtx_REG (SImode, rb_regno); - operands[1] = gen_rtx_REG (SImode, re_regno); - - /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */ - if (!cfun->machine->fp_size - && !cfun->machine->gp_size - && !cfun->machine->lp_size - && REGNO (operands[0]) == SP_REGNUM - && REGNO (operands[1]) == SP_REGNUM) - { - /* No need to generate instruction. */ - return ""; - } - else - { - /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */ - if (REGNO (operands[0]) == SP_REGNUM - && REGNO (operands[1]) == SP_REGNUM) - pop_en4_only_p = 1; - - /* Create assembly code pattern. - We need to handle the form: "Rb, Re, { $fp $gp $lp }". */ - snprintf (pattern, sizeof (pattern), - "pop.s\t%s{%s%s%s }", - pop_en4_only_p ? "" : "%0, %1, ", - cfun->machine->fp_size ? " $fp" : "", - cfun->machine->gp_size ? " $gp" : "", - cfun->machine->lp_size ? " $lp" : ""); - } - } - - /* We use output_asm_insn() to output assembly code by ourself. */ - output_asm_insn (pattern, operands); - return ""; -} - /* Return align 2 (log base 2) if the next instruction of LABEL is 4 byte. */ int nds32_target_alignment (rtx label) -- 2.7.4