From: Nick Clifton Date: Fri, 12 May 2000 20:57:57 +0000 (+0000) Subject: Add movdi pattern to FR30 port. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=aeb4f5ef5d18088fc00cdf76f39c7f3268b3547e;p=gcc.git Add movdi pattern to FR30 port. From-SVN: r33885 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9eae7dd9515..a8cdab98426 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2000-05-12 Nick Clifton + + * config/fr30/fr30.c (fr30_move_double): New function: Emit code + to move a double word value. + (di_operand): New function: Return true if the operand is suitbale + for a double word move operation. + (nonimmediate_di_operand): New function: Return true if the + operand is a DImode register or MEM. + + * config/fr30/fr30.h (PREDICATE_CODES): Add di_operand and + nonimmediate_di_operand. + + * config/fr30/fr30-protos.h Add fr30_move_double, di_operand, and + nonimmediate_di_operand. + + * config/fr30/fr30.md (movdi): New pattern. Required because + other patterns generate DImode results. + (movdi_insn): New pattern. + 2000-05-12 Richard Henderson * config/alpha/alpha.c (struct shadow_summary): Define diff --git a/gcc/config/fr30/fr30-protos.h b/gcc/config/fr30/fr30-protos.h index aa183992a7e..e6d31388767 100644 --- a/gcc/config/fr30/fr30-protos.h +++ b/gcc/config/fr30/fr30-protos.h @@ -26,6 +26,7 @@ extern unsigned int fr30_compute_frame_size PARAMS ((int, int)); extern int fr30_check_multiple_regs PARAMS ((rtx *, int, int)); extern void fr30_print_operand PARAMS ((FILE *, rtx, int)); extern void fr30_print_operand_address PARAMS ((FILE *, rtx)); +extern rtx fr30_move_double PARAMS ((rtx *)); #ifdef TREE_CODE extern rtx fr30_va_arg PARAMS ((tree, tree)); #endif /* TREE_CODE */ @@ -36,6 +37,8 @@ extern int add_immediate_operand PARAMS ((rtx, Mmode)); extern int high_register_operand PARAMS ((rtx, Mmode)); extern int low_register_operand PARAMS ((rtx, Mmode)); extern int call_operand PARAMS ((rtx, Mmode)); +extern int di_operand PARAMS ((rtx, Mmode)); +extern int nonimmediate_di_operand PARAMS ((rtx, Mmode)); #undef Mmode #endif /* HAVE_MACHINE_MODES */ #endif /* RTX_CODE */ diff --git a/gcc/config/fr30/fr30.c b/gcc/config/fr30/fr30.c index 26b3d8282a3..68bae05ceac 100644 --- a/gcc/config/fr30/fr30.c +++ b/gcc/config/fr30/fr30.c @@ -24,10 +24,8 @@ Boston, MA 02111-1307, USA. */ /*}}}*/ /*{{{ Includes */ -#include -#include -#include /* so that MIn and MAX are defined before machmode.h */ #include "config.h" +#include "system.h" #include "rtl.h" #include "regs.h" #include "hard-reg-set.h" @@ -44,7 +42,7 @@ Boston, MA 02111-1307, USA. */ #include "obstack.h" #include "except.h" #include "function.h" -#include "fr30-protos.h" +#include "tm_p.h" /*}}}*/ /*{{{ Function Prologues & Epilogues */ @@ -839,8 +837,7 @@ low_register_operand (operand, mode) { return (GET_CODE (operand) == REG - && REGNO (operand) <= 7 - && REGNO (operand) >= 0); + && REGNO (operand) <= 7); } /* Returns true if OPERAND is suitable for use in a CALL insn. */ @@ -854,6 +851,56 @@ call_operand (operand, mode) || GET_CODE (XEXP (operand, 0)) == REG)); } +/* Returns TRUE if OP is a valid operand of a DImode operation. */ +int +di_operand (op, mode) + rtx op; + Mmode mode; +{ + if (register_operand (op, mode)) + return TRUE; + + if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode) + return FALSE; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + switch (GET_CODE (op)) + { + case CONST_DOUBLE: + case CONST_INT: + return TRUE; + + case MEM: + return memory_address_p (DImode, XEXP (op, 0)); + + default: + return FALSE; + } +} + +/* Returns TRUE if OP is a DImode register or MEM. */ +int +nonimmediate_di_operand (op, mode) + rtx op; + Mmode mode; +{ + if (register_operand (op, mode)) + return TRUE; + + if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode) + return FALSE; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (GET_CODE (op) == MEM) + return memory_address_p (DImode, XEXP (op, 0)); + + return FALSE; +} + /* Returns true iff all the registers in the operands array are in descending or ascending order. */ int @@ -864,9 +911,9 @@ fr30_check_multiple_regs (operands, num_operands, descending) { if (descending) { - int prev_regno = -1; + unsigned int prev_regno = 0; - while (num_operands--) + while (num_operands --) { if (GET_CODE (operands [num_operands]) != REG) return 0; @@ -879,9 +926,9 @@ fr30_check_multiple_regs (operands, num_operands, descending) } else { - int prev_regno = CONDITION_CODE_REGNUM; + unsigned int prev_regno = CONDITION_CODE_REGNUM; - while (num_operands--) + while (num_operands --) { if (GET_CODE (operands [num_operands]) != REG) return 0; @@ -896,6 +943,146 @@ fr30_check_multiple_regs (operands, num_operands, descending) return 1; } +/*}}}*/ +/*{{{ Instruction Output Routines */ + +/* Output a double word move. + It must be REG<-REG, REG<-MEM, MEM<-REG or REG<-CONST. + On the FR30 we are contrained by the fact that it does not + support offsetable addresses, and so we have to load the + address of the secnd word into the second destination register + before we can use it. */ + +rtx +fr30_move_double (operands) + rtx * operands; +{ + rtx src = operands[1]; + rtx dest = operands[0]; + enum rtx_code src_code = GET_CODE (src); + enum rtx_code dest_code = GET_CODE (dest); + enum machine_mode mode = GET_MODE (dest); + rtx val; + + start_sequence (); + + if (dest_code == REG) + { + if (src_code == REG) + { + int reverse = (REGNO (dest) == REGNO (src) + 1); + + /* We normally copy the low-numbered register first. However, if + the first register of operand 0 is the same as the second register + of operand 1, we must copy in the opposite order. */ + emit_insn (gen_rtx_SET (VOIDmode, + operand_subword (dest, reverse, TRUE, mode), + operand_subword (src, reverse, TRUE, mode))); + + emit_insn (gen_rtx_SET (VOIDmode, + operand_subword (dest, !reverse, TRUE, mode), + operand_subword (src, !reverse, TRUE, mode))); + } + else if (src_code == MEM) + { + rtx addr = XEXP (src, 0); + int dregno = REGNO (dest); + rtx dest0; + rtx dest1; + rtx new_mem; + + /* If the high-address word is used in the address, we + must load it last. Otherwise, load it first. */ + int reverse = (refers_to_regno_p (dregno, dregno + 1, addr, 0) != 0); + + if (GET_CODE (addr) != REG) + abort (); + + dest0 = operand_subword (dest, reverse, TRUE, mode); + dest1 = operand_subword (dest, !reverse, TRUE, mode); + + if (reverse) + { + emit_insn (gen_rtx_SET (VOIDmode, dest1, change_address (src, SImode, addr))); + emit_insn (gen_rtx_SET (SImode, dest0, gen_rtx_REG (SImode, REGNO (addr)))); + emit_insn (gen_rtx_SET (SImode, dest0, plus_constant (dest0, UNITS_PER_WORD))); + + new_mem = gen_rtx_MEM (SImode, dest0); + MEM_COPY_ATTRIBUTES (new_mem, src); + + emit_insn (gen_rtx_SET (VOIDmode, dest0, new_mem)); + } + else + { + emit_insn (gen_rtx_SET (VOIDmode, dest0, change_address (src, SImode, addr))); + emit_insn (gen_rtx_SET (SImode, dest1, gen_rtx_REG (SImode, REGNO (addr)))); + emit_insn (gen_rtx_SET (SImode, dest1, plus_constant (dest1, UNITS_PER_WORD))); + + new_mem = gen_rtx_MEM (SImode, dest1); + MEM_COPY_ATTRIBUTES (new_mem, src); + + emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem)); + } + } + else if (src_code == CONST_INT || src_code == CONST_DOUBLE) + { + rtx words[2]; + split_double (src, &words[0], &words[1]); + emit_insn (gen_rtx_SET (VOIDmode, + operand_subword (dest, 0, TRUE, mode), + words[0])); + + emit_insn (gen_rtx_SET (VOIDmode, + operand_subword (dest, 1, TRUE, mode), + words[1])); + } + } + else if (src_code == REG && dest_code == MEM) + { + rtx addr = XEXP (dest, 0); + rtx src0; + rtx src1; + + if (GET_CODE (addr) != REG) + abort (); + + src0 = operand_subword (src, 0, TRUE, mode); + src1 = operand_subword (src, 1, TRUE, mode); + + emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, addr), src0)); + + if (REGNO (addr) == STACK_POINTER_REGNUM) + emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, plus_constant (stack_pointer_rtx, UNITS_PER_WORD)), src1)); + else if (REGNO (addr) == FRAME_POINTER_REGNUM) + emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, plus_constant (frame_pointer_rtx, UNITS_PER_WORD)), src1)); + else + { + rtx new_mem; + + /* We need a scratch register to hold the value of 'address + 4'. + We ought to allow gcc to find one for us, but for now, just + push one of the source registers. */ + emit_insn (gen_movsi_push (src0)); + emit_insn (gen_movsi_internal (src0, addr)); + emit_insn (gen_addsi_small_int (src0, src0, GEN_INT (UNITS_PER_WORD))); + + new_mem = gen_rtx_MEM (SImode, src0); + MEM_COPY_ATTRIBUTES (new_mem, dest); + + emit_insn (gen_rtx_SET (VOIDmode, new_mem, src1)); + emit_insn (gen_movsi_pop (src0)); + } + } + else + /* This should have been prevented by the contraints on movdi_insn. */ + abort (); + + val = gen_sequence (); + end_sequence (); + + return val; +} + /*}}}*/ /* Local Variables: */ diff --git a/gcc/config/fr30/fr30.h b/gcc/config/fr30/fr30.h index 4d934bab7c0..2bd1b6f3b52 100644 --- a/gcc/config/fr30/fr30.h +++ b/gcc/config/fr30/fr30.h @@ -84,7 +84,7 @@ extern int target_flags; { "small-model", TARGET_SMALL_MODEL_MASK, "Assume small address space" }, \ { "no-small-model", - TARGET_SMALL_MODEL_MASK, "" }, \ { "no-lsim", 0, "" }, \ - { "", TARGET_DEFAULT } \ + { "", TARGET_DEFAULT, "" } \ } #define TARGET_VERSION fprintf (stderr, " (fr30)"); @@ -889,9 +889,10 @@ enum reg_class into the stack) - if the type is a structure or union. */ -#define MUST_PASS_IN_STACK(MODE,TYPE) \ +#define MUST_PASS_IN_STACK(MODE, TYPE) \ (((MODE) == BLKmode) \ - || ((TYPE) != 0 \ + || ((TYPE) != NULL \ + && TYPE_SIZE (TYPE) != NULL \ && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \ || TREE_CODE (TYPE) == RECORD_TYPE \ || TREE_CODE (TYPE) == UNION_TYPE \ @@ -1763,6 +1764,8 @@ extern struct rtx_def * fr30_compare_op1; { "call_operand", { MEM }}, \ { "fp_displacement_operand", { CONST_INT }}, \ { "sp_displacement_operand", { CONST_INT }}, \ + { "di_operand", { CONST_INT, CONST_DOUBLE, REG, MEM }}, \ + { "nonimmediate_di_operand", { REG, MEM }}, \ { "add_immediate_operand", { REG, CONST_INT }}, /*}}}*/ diff --git a/gcc/config/fr30/fr30.md b/gcc/config/fr30/fr30.md index 1b8d310d838..296cdb27eb2 100644 --- a/gcc/config/fr30/fr30.md +++ b/gcc/config/fr30/fr30.md @@ -367,6 +367,43 @@ (const_int 2)))] ) +;;}}} +;;{{{ 8 Byte Moves + +;; Note - the FR30 does not have an 8 byte load/store instruction +;; but we have to support this pattern because some other patterns +;; (eg muldisi2) can produce a DImode result. +;; (This code is stolen from the M32R port.) + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + " + /* Everything except mem = const or mem = mem can be done easily. */ + + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (DImode, operands[1]); + ") + +;; We use an insn and a split so that we can generate +;; RTL rather than text from fr30_move_double(). + +(define_insn "*movdi_insn" + [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,m,r") + (match_operand:DI 1 "di_operand" "r,m,r,nF"))] + "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)" + "#" + [(set_attr "length" "4,8,12,12")] +) + +(define_split + [(set (match_operand:DI 0 "nonimmediate_di_operand" "") + (match_operand:DI 1 "di_operand" ""))] + "reload_completed" + [(match_dup 2)] + "operands[2] = fr30_move_double (operands);") + ;;}}} ;;{{{ Load & Store Multiple Registers