diff options
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/picochip/constraints.md | 64 | ||||
-rw-r--r-- | gcc/config/picochip/dfa_space.md | 43 | ||||
-rw-r--r-- | gcc/config/picochip/dfa_speed.md | 123 | ||||
-rw-r--r-- | gcc/config/picochip/picochip-protos.h | 129 | ||||
-rw-r--r-- | gcc/config/picochip/picochip.c | 4705 | ||||
-rw-r--r-- | gcc/config/picochip/picochip.h | 661 | ||||
-rw-r--r-- | gcc/config/picochip/picochip.md | 2623 | ||||
-rw-r--r-- | gcc/config/picochip/picochip.opt | 46 | ||||
-rw-r--r-- | gcc/config/picochip/predicates.md | 72 | ||||
-rw-r--r-- | gcc/config/picochip/t-picochip | 24 |
10 files changed, 0 insertions, 8490 deletions
diff --git a/gcc/config/picochip/constraints.md b/gcc/config/picochip/constraints.md deleted file mode 100644 index ba7eb74..0000000 --- a/gcc/config/picochip/constraints.md +++ /dev/null @@ -1,64 +0,0 @@ -;; GCC machine description for picochip -;; Copyright (C) 2008-2014 Free Software Foundation, Inc. -;; Contributed by Picochip Ltd (http://www.picochip.com) -;; Maintained by Daniel Towner (dant@picochip.com) and Hariharan -;; Sandanagobalane (hariharan@picochip.com) -;; -;; This file is part of GCC. -;; -;; GCC 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 3, or (at your option) -;; any later version. -;; -;; GCC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not, see -;; <http://www.gnu.org/licenses/>. - -(define_constraint "I" - "4-bits signed value" - (and (match_code "const_int") - (match_test " ival >= -8 && ival< 8"))) - -(define_constraint "J" - "4-bits unsigned value" - (and (match_code "const_int") - (match_test "ival>=0 && ival < 16"))) - -(define_constraint "K" - "8-bits signed value" - (and (match_code "const_int") - (match_test " ival >= -128 && ival < 128"))) - -(define_constraint "M" - "4-bits magnitude" - (and (match_code "const_int") - (match_test " abs(ival) < 16"))) - -(define_constraint "N" - "10-bits signed value" - (and (match_code "const_int") - (match_test "ival >= -512 && ival < 512"))) - -(define_constraint "O" - "16-bits signed value" - (and (match_code "const_int") - (match_test " ival >= -32768 && ival < 32768 "))) - -(define_constraint "a" - "See if this is an absolute address in memory" - (and (match_code "mem") - (match_test "picochip_absolute_memory_operand(op,mode) == 1"))) - -(define_register_constraint "k" "FRAME_REGS" - "Frame regs") -(define_register_constraint "f" "PTR_REGS" - "Pointer regs") -(define_register_constraint "t" "TWIN_REGS" - "Twin regs") - diff --git a/gcc/config/picochip/dfa_space.md b/gcc/config/picochip/dfa_space.md deleted file mode 100644 index b455103..0000000 --- a/gcc/config/picochip/dfa_space.md +++ /dev/null @@ -1,43 +0,0 @@ -;; GCC machine description for picochip -;; Copyright (C) 2008-2014 Free Software Foundation, Inc. -;; Contributed by Picochip Ltd (http://www.picochip.com) -;; Maintained by Daniel Towner (dant@picochip.com) and Hariharan -;; Sandanagobalane (hariharan@picochip.com) -;; -;; This file is part of GCC. -;; -;; GCC 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 3, or (at your option) -;; any later version. -;; -;; GCC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not, see -;; <http://www.gnu.org/licenses/>. - -;; The following DFA description schedules instructions for space. The -;; schedule seeks to avoid stall cycles (e.g., memory load), but the -;; instructions are not VLIW packed (whenever instructions are packed -;; together, an additional byte is used to denote this, which -;; increases the code size). - -;; No special handling of the long constants is necessary (as in -;; dfa_speed.md), since VLIW packing is not used. - -;; Memory instructions stall for one cycle. All other instructions -;; complete ready for the next cycle. - -(define_insn_reservation "nonStallInsn" 1 - (and (eq_attr "schedType" "space") - (eq_attr "type" "!mem")) - "slot0+slot1+slot2") - -(define_insn_reservation "stallInsn" 2 - (and (eq_attr "schedType" "space") - (eq_attr "type" "mem")) - "slot0+slot1+slot2") diff --git a/gcc/config/picochip/dfa_speed.md b/gcc/config/picochip/dfa_speed.md deleted file mode 100644 index 20b893b..0000000 --- a/gcc/config/picochip/dfa_speed.md +++ /dev/null @@ -1,123 +0,0 @@ -;; GCC machine description for picochip -;; Copyright (C) 2008-2014 Free Software Foundation, Inc. -;; Contributed by Picochip Ltd (http://www.picochip.com) -;; Maintained by Daniel Towner (dant@picochip.com) and Hariharan -;; Sandanagobalane (hariharan@picochip.com). -;; -;; This file is part of GCC. -;; -;; GCC 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 3, or (at your option) -;; any later version. -;; -;; GCC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not, see -;; <http://www.gnu.org/licenses/>. - -;; The following DFA description schedules instructions for speed. In -;; addition to the scheduling of instructions to remove stall cycles -;; (e.g., memory load), the scheduler will also pack multiple -;; instructions into a single cycle, using VLIW. - -;; Each instruction comes in forms with and without long -;; constants. The long constant is treated as though it were also an -;; instruction. Thus, an instruction which used slot0, will use slot0 -;; plus one of the other slots for the constant. This mechanism -;; ensures that it is impossible for 3 instructions to be issued, if -;; one of them has a long constant. This is necessary, because the -;; encoding of 3 instructions, plus a constant, will overrun the -;; 64-bit limit. - -; Extended ALU - Slot 0 -(define_insn_reservation "picoAluInsn" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "picoAlu") (eq_attr "longConstant" "false"))) - "slot0") -(define_insn_reservation "picoAluInsnWithConst" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "picoAlu") (eq_attr "longConstant" "true"))) - "(slot0+slot1)|(slot0+slot2)") - -; Basic ALU - Slot 0 or 1 -(define_insn_reservation "basicAluInsn" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "basicAlu") (eq_attr "longConstant" "false"))) - "(slot0|slot1)") -(define_insn_reservation "basicAluInsnWithConst" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "basicAlu") (eq_attr "longConstant" "true"))) - "(slot0+slot1) | (slot1+slot2) | (slot0+slot2)") - -; ALU which must not set flags - Slot 1 -(define_insn_reservation "nonCcAluInsn" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "nonCcAlu") (eq_attr "longConstant" "false"))) - "slot1") -(define_insn_reservation "nonCcAluInsnWithConst" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "nonCcAlu") (eq_attr "longConstant" "true"))) - "(slot1+slot0) | (slot1+slot2)") - -; Memory - Slot 1 -(define_insn_reservation "memInsn" 2 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "mem") (eq_attr "longConstant" "false"))) - "slot1,nothing") -(define_insn_reservation "memInsnWithConst" 2 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "mem") (eq_attr "longConstant" "true"))) - "slot1+(slot0|slot2),nothing") - -; Multiply - Slot 2 -(define_insn_reservation "mulInsn" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "mul") (eq_attr "longConstant" "false"))) - "slot2") -(define_insn_reservation "mulInsnWithConst" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "mul") (eq_attr "longConstant" "true"))) - "(slot2+slot0)|(slot2+slot1)") - -; MAC - Slot 2 -(define_insn_reservation "macInsn" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "mac") (eq_attr "longConstant" "false"))) - "slot2") -(define_insn_reservation "macInsnWithConst" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "mac") (eq_attr "longConstant" "true"))) - "(slot2+slot0)|(slot2+slot1)") - -; Branch - Real branches use slot2, while macro branches use unknown -; resources. -(define_insn_reservation "branchInsn" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "realBranch") (eq_attr "longConstant" "false"))) - "slot2") -(define_insn_reservation "branchInsnWithConst" 1 - (and (eq_attr "schedType" "speed") - (and (eq_attr "type" "realBranch") (eq_attr "longConstant" "true"))) - "(slot2+slot0)|(slot2+slot1)") -(define_insn_reservation "branchInsnMacro" 1 - (and (eq_attr "schedType" "speed") - (eq_attr "type" "realBranch")) - "(slot0+slot1+slot2)") - -; Call instructions use all slots to prevent inadvertent scheduling -; alongside instructions which set R12. - -(define_insn_reservation "callInsn" 1 - (and (eq_attr "schedType" "speed") (eq_attr "type" "call")) - "slot0+slot1+slot2") - -; Communications - Slot 1 -(define_insn_reservation "commsInsn" 1 - (and (eq_attr "schedType" "speed") (eq_attr "type" "comms")) - "slot1") - diff --git a/gcc/config/picochip/picochip-protos.h b/gcc/config/picochip/picochip-protos.h deleted file mode 100644 index e7efc40..0000000 --- a/gcc/config/picochip/picochip-protos.h +++ /dev/null @@ -1,129 +0,0 @@ -/* Prototypes for exported functions defined in picochip.c - - Copyright (C) 2000-2014 Free Software Foundation, Inc. - Contributed by Picochip Ltd. (http://www.picochip.com) - Maintained by Daniel Towner (daniel.towner@picochip.com) and - Hariharan Sandanagobalane (hariharan@picochip.com). - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GCC; see the file COPYING3. If not, see - <http://www.gnu.org/licenses/>. */ - -extern void picochip_function_prologue (FILE *, HOST_WIDE_INT); -extern void picochip_function_epilogue (FILE *, HOST_WIDE_INT); - -extern enum reg_class picochip_reg_class_from_letter (unsigned); -extern int picochip_const_ok_for_letter_p (unsigned HOST_WIDE_INT value, unsigned c); - -#ifdef RTX_CODE /* inside TREE_CODE */ - -extern int picochip_reg_mode_ok_for_base_p (int mode, rtx x, unsigned strict); -extern void picochip_print_operand (FILE * file, rtx op, int letter); -extern void picochip_print_operand_address (FILE * file, rtx operand); - -extern const char *picochip_output_cbranch (rtx operands[]); -extern const char *picochip_output_branch (rtx operands[], rtx insn); -extern const char *picochip_output_compare (rtx operands[]); -extern const char *picochip_output_jump (rtx insn); - -extern const char *picochip_output_put_array (int alternative, - rtx operands[]); -extern const char *picochip_output_get_array (int alternative, - rtx operands[]); -extern const char *picochip_output_testport_array (int alternative, - rtx operands[]); - -extern int picochip_expand_movmemhi (rtx *operands); - -extern rtx gen_SImode_mem(rtx opnd1,rtx opnd2); -extern bool ok_to_peephole_stw(rtx opnd0, rtx opnd1, rtx opnd2, rtx opnd3); -extern bool ok_to_peephole_ldw(rtx opnd0, rtx opnd1, rtx opnd2, rtx opnd3); - -extern rtx gen_min_reg(rtx opnd1,rtx opnd2); - -extern int picochip_regno_nregs (int regno, enum machine_mode mode); -extern int picochip_class_max_nregs (int klass, enum machine_mode mode); - -extern void picochip_order_regs_for_local_alloc (void); - -extern int picochip_word_aligned_memory_reference (rtx operand); -extern int picochip_alignable_memory_operand (rtx operand, enum machine_mode mode); -extern int picochip_absolute_memory_operand (rtx op, enum machine_mode mode); - -extern rtx picochip_function_value (const_tree valtype, const_tree func, bool outgoing); -extern int picochip_symbol_offset (rtx operand); - -extern void picochip_get_hi_aligned_mem (rtx ref, rtx * paligned_mem, rtx * pbitnum); - -extern rtx picochip_get_low_const (rtx value); -extern rtx picochip_get_high_const (rtx value); - -extern void picochip_expand_prologue (void); -extern void picochip_expand_epilogue (int is_sibling_call); - -extern void picochip_final_prescan_insn (rtx_insn *insn, rtx * operand, - int num_operands); -extern const char *picochip_asm_output_opcode (FILE * f, const char *ptr); - -extern int picochip_check_conditional_copy (rtx * operands); - -extern rtx picochip_return_addr_rtx(int count, rtx frameaddr); -extern rtx picochip_struct_value_rtx(tree fntype ATTRIBUTE_UNUSED, - int incoming ATTRIBUTE_UNUSED); - -#endif /* RTX_CODE inside TREE_CODE */ - -extern int picochip_legitimize_reload_address (rtx *x, enum machine_mode mode, - int opnum, int type, int ind_levels); - - -void picochip_output_ascii (FILE * file, const char *str, int length); - -extern int picochip_hard_regno_mode_ok (int regno, enum machine_mode mode); -extern void picochip_generate_internal_label (char *str, const char *prefix, - long num); - -extern bool picochip_return_in_memory(const_tree type, - const_tree fntype ATTRIBUTE_UNUSED); - -extern int initial_elimination_offset (int from, int to); - -extern void picochip_output_aligned_common (FILE * stream, const char *name, - unsigned size, unsigned align); - -extern void picochip_output_global (FILE * stream, const char *name); - -extern void picochip_output_aligned_local (FILE * stream, const char *name, - unsigned size, unsigned alignment); - -extern void picochip_output_label (FILE * stream, const char name[]); -extern void picochip_output_labelref (FILE * stream, const char name[]); -extern void picochip_weaken_label (FILE * stream, const char name[]); -extern void picochip_output_internal_label (FILE * stream, const char *prefix, - unsigned long num); - -extern void warn_of_byte_access (void); - -/* True if VLIW scheduling is enabled (i.e., second scheduling pass). */ -extern int picochip_flag_schedule_insns2; - -extern void picochip_asm_output_anchor (rtx symbol); - -/* Instruction set capability flags. These are initialised to the - appropriate values by picochip_option_override, once the user has - selected a CPU type. */ -extern bool picochip_has_mul_unit; -extern bool picochip_has_mac_unit; - diff --git a/gcc/config/picochip/picochip.c b/gcc/config/picochip/picochip.c deleted file mode 100644 index 3e532f4..0000000 --- a/gcc/config/picochip/picochip.c +++ /dev/null @@ -1,4705 +0,0 @@ -/* Subroutines used for code generation on picoChip processors. - Copyright (C) 2001-2014 Free Software Foundation, Inc. - Contributed by Picochip Ltd. (http://www.picochip.com) - Maintained by Daniel Towner (daniel.towner@picochip.com) and - Hariharan Sandanagobalane (hariharan@picochip.com) - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not, see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "rtl.h" -#include "regs.h" -#include "hard-reg-set.h" -#include "insn-config.h" -#include "conditions.h" -#include "insn-attr.h" -#include "flags.h" -#include "recog.h" -#include "obstack.h" -#include "tree.h" -#include "calls.h" -#include "stor-layout.h" -#include "stringpool.h" -#include "varasm.h" -#include "expr.h" -#include "optabs.h" -#include "except.h" -#include "function.h" -#include "output.h" -#include "basic-block.h" -#include "diagnostic-core.h" -#include "ggc.h" -#include "hashtab.h" -#include "tm_p.h" -#include "target.h" -#include "target-def.h" -#include "langhooks.h" -#include "reload.h" -#include "params.h" - -#include "picochip-protos.h" - -#include "insn-attr.h" /* For DFA state_t. */ -#include "insn-config.h" /* Required by recog.h */ -#include "insn-codes.h" /* For CODE_FOR_? */ -#include "optabs.h" /* For GEN_FCN */ -#include "basic-block.h" /* UPDATE_LIFE_GLOBAL* for picochip_reorg. */ -#include "timevar.h" /* For TV_SCHED2, in picochip_reorg. */ -#include "libfuncs.h" /* For memcpy_libfuncs, etc. */ -#include "df.h" /* For df_regs_ever_live_df_regs_ever_live_pp, etc. */ -#include "dbxout.h" -#include "builtins.h" - - -/* Target AE ISA information. */ -enum picochip_dfa_type picochip_schedule_type; - -bool picochip_has_mul_unit = false; -bool picochip_has_mac_unit = false; - -/* targetm hook function prototypes. */ - -void picochip_asm_file_start (void); -void picochip_asm_file_end (void); - -void picochip_init_libfuncs (void); -void picochip_reorg (void); - -int picochip_arg_partial_bytes (cumulative_args_t p_cum, - enum machine_mode mode, - tree type, bool named); -rtx picochip_function_arg (cumulative_args_t p_cum, - enum machine_mode mode, - const_tree type, bool named); -rtx picochip_incoming_function_arg (cumulative_args_t p_cum, - enum machine_mode mode, - const_tree type, bool named); -void picochip_arg_advance (cumulative_args_t p_cum, enum machine_mode mode, - const_tree type, bool named); -unsigned int picochip_function_arg_boundary (enum machine_mode mode, - const_tree type); - -int picochip_sched_lookahead (void); -int picochip_sched_issue_rate (void); -int picochip_sched_adjust_cost (rtx_insn *insn, rtx link, - rtx_insn *dep_insn, int cost); -int picochip_sched_reorder (FILE * file, int verbose, rtx_insn ** ready, - int *n_readyp, int clock); - -void picochip_init_builtins (void); -rtx picochip_expand_builtin (tree, rtx, rtx, enum machine_mode, int); - -bool picochip_rtx_costs (rtx x, int code, int outer_code, int opno, - int* total, bool speed); -bool picochip_return_in_memory(const_tree type, - const_tree fntype ATTRIBUTE_UNUSED); -bool picochip_legitimate_address_p (enum machine_mode, rtx, bool); -rtx picochip_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, - enum machine_mode mode); -int picochip_legitimize_reload_address (rtx *x, enum machine_mode mode, - int opnum, int type, int ind_levels); - -rtx picochip_struct_value_rtx(tree fntype ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED); -rtx picochip_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED, - bool outgoing ATTRIBUTE_UNUSED); -static reg_class_t -picochip_secondary_reload (bool in_p, - rtx x ATTRIBUTE_UNUSED, - reg_class_t cla ATTRIBUTE_UNUSED, - enum machine_mode mode, - secondary_reload_info *sri); -void -picochip_asm_named_section (const char *name, - unsigned int flags ATTRIBUTE_UNUSED, - tree decl ATTRIBUTE_UNUSED); - -static rtx picochip_static_chain (const_tree, bool); - -static void picochip_option_override (void); - -/* Lookup table mapping a register number to the earliest containing - class. Used by REGNO_REG_CLASS. */ -const enum reg_class picochip_regno_reg_class[FIRST_PSEUDO_REGISTER] = -{ - TWIN_REGS, TWIN_REGS, TWIN_REGS, TWIN_REGS, - TWIN_REGS, TWIN_REGS, TWIN_REGS, TWIN_REGS, - TWIN_REGS, TWIN_REGS, TWIN_REGS, TWIN_REGS, - GR_REGS, FRAME_REGS, PTR_REGS, CONST_REGS, - ACC_REGS, CC_REGS, GR_REGS, GR_REGS -}; - -/* picoChip register names. */ -const char *picochip_regnames[] = REGISTER_NAMES; - -/* Define the maximum number of registers which may be used to pass - * parameters to functions. */ -#define MAX_CALL_PARAMETER_REGS 6 - - -/* Target scheduling information. */ - -/* This flag indicates whether the next instruction to be output is a - VLIW continuation instruction. It is used to communicate between - final_prescan_insn and asm_output_opcode. */ -static int picochip_vliw_continuation = 0; - -/* This variable is used to communicate the current instruction - between final_prescan_insn and functions such as asm_output_opcode, - and picochip_get_vliw_alu_id (which are otherwise unable to determine the - current instruction. */ -static rtx_insn *picochip_current_prescan_insn; - -static bool picochip_is_delay_slot_pending = 0; - -/* When final_prescan_insn is called, it computes information about - the current VLIW packet, and stores it in this structure. When - instructions are output, this state is used to make sure that the - instructions are output in the correct way (e.g., which ALU to use, - whether a macro branch was ever previously a real branch, etc.). */ -struct vliw_state -{ - int contains_pico_alu_insn; - int contains_non_cc_alu_insn; - int num_alu_insns_so_far; - - /* Record how many instructions are contained in the packet. */ - int num_insns_in_packet; - - /* There was a case for this to be more than 1 */ - int num_cfi_labels_deferred; - char cfi_label_name[2][256]; /* Used to record the name of a CFI label - emitted inside a VLIW packet. */ - char lm_label_name[256]; /* Used to record the name of an LM label. */ -}; - -struct vliw_state picochip_current_vliw_state; - -/* Save/restore recog_data. */ -static int picochip_saved_which_alternative; -static struct recog_data_d picochip_saved_recog_data; - -/* Determine which ALU to use for the instruction in - picochip_current_prescan_insn. */ -static char picochip_get_vliw_alu_id (void); - -/* Initialize the GCC target structure. */ - -#undef TARGET_ASM_FUNCTION_PROLOGUE -#define TARGET_ASM_FUNCTION_PROLOGUE picochip_function_prologue - -#undef TARGET_ASM_FUNCTION_EPILOGUE -#define TARGET_ASM_FUNCTION_EPILOGUE picochip_function_epilogue - -#undef TARGET_ASM_INTERNAL_LABEL -#define TARGET_ASM_INTERNAL_LABEL picochip_output_internal_label - -#undef TARGET_ASM_GLOBALIZE_LABEL -#define TARGET_ASM_GLOBALIZE_LABEL picochip_output_global - -#undef TARGET_ASM_BYTE_OP -#define TARGET_ASM_BYTE_OP ".initByte " -#undef TARGET_ASM_ALIGNED_HI_OP -#define TARGET_ASM_ALIGNED_HI_OP ".initWord " -#undef TARGET_ASM_UNALIGNED_HI_OP -#define TARGET_ASM_UNALIGNED_HI_OP ".unalignedInitWord " -#undef TARGET_ASM_ALIGNED_SI_OP -#define TARGET_ASM_ALIGNED_SI_OP ".initLong " -#undef TARGET_ASM_UNALIGNED_SI_OP -#define TARGET_ASM_UNALIGNED_SI_OP ".unalignedInitLong " - -#undef TARGET_INIT_BUILTINS -#define TARGET_INIT_BUILTINS picochip_init_builtins - -#undef TARGET_EXPAND_BUILTIN -#define TARGET_EXPAND_BUILTIN picochip_expand_builtin - -#undef TARGET_RTX_COSTS -#define TARGET_RTX_COSTS picochip_rtx_costs - -#undef TARGET_SCHED_ISSUE_RATE -#define TARGET_SCHED_ISSUE_RATE picochip_sched_issue_rate - -#undef TARGET_SCHED_REORDER -#define TARGET_SCHED_REORDER picochip_sched_reorder - -#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD -#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \ - picochip_sched_lookahead - -#undef TARGET_SCHED_ADJUST_COST -#define TARGET_SCHED_ADJUST_COST picochip_sched_adjust_cost - -#undef TARGET_ASM_NAMED_SECTION -#define TARGET_ASM_NAMED_SECTION picochip_asm_named_section - -#undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS -#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS 1 - -#undef TARGET_INIT_LIBFUNCS -#define TARGET_INIT_LIBFUNCS picochip_init_libfuncs - -#undef TARGET_ASM_FILE_START -#define TARGET_ASM_FILE_START picochip_asm_file_start - -#undef TARGET_ASM_FILE_END -#define TARGET_ASM_FILE_END picochip_asm_file_end - -#undef TARGET_MACHINE_DEPENDENT_REORG -#define TARGET_MACHINE_DEPENDENT_REORG picochip_reorg - -#undef TARGET_ARG_PARTIAL_BYTES -#define TARGET_ARG_PARTIAL_BYTES picochip_arg_partial_bytes - -#undef TARGET_FUNCTION_ARG -#define TARGET_FUNCTION_ARG picochip_function_arg - -#undef TARGET_FUNCTION_INCOMING_ARG -#define TARGET_FUNCTION_INCOMING_ARG picochip_incoming_function_arg - -#undef TARGET_FUNCTION_ARG_ADVANCE -#define TARGET_FUNCTION_ARG_ADVANCE picochip_arg_advance - -#undef TARGET_FUNCTION_ARG_BOUNDARY -#define TARGET_FUNCTION_ARG_BOUNDARY picochip_function_arg_boundary - -#undef TARGET_PROMOTE_FUNCTION_MODE -#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote -#undef TARGET_PROMOTE_PROTOTYPES -#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true - -/* Target support for Anchored Addresses optimization */ -#undef TARGET_MIN_ANCHOR_OFFSET -#define TARGET_MIN_ANCHOR_OFFSET 0 -#undef TARGET_MAX_ANCHOR_OFFSET -#define TARGET_MAX_ANCHOR_OFFSET 7 -#undef TARGET_ASM_OUTPUT_ANCHOR -#define TARGET_ASM_OUTPUT_ANCHOR picochip_asm_output_anchor - -#undef TARGET_FUNCTION_VALUE -#define TARGET_FUNCTION_VALUE picochip_function_value -/* -#undef TARGET_LIBGCC_CMP_RETURN_MODE -#define TARGET_LIBGCC_CMP_RETURN_MODE picochip_libgcc_cmp_return_mode -*/ - -#undef TARGET_LEGITIMATE_ADDRESS_P -#define TARGET_LEGITIMATE_ADDRESS_P picochip_legitimate_address_p - -#undef TARGET_LEGITIMIZE_ADDRESS -#define TARGET_LEGITIMIZE_ADDRESS picochip_legitimize_address - -/* Loading and storing QImode values to and from memory - usually requires a scratch register. */ -#undef TARGET_SECONDARY_RELOAD -#define TARGET_SECONDARY_RELOAD picochip_secondary_reload - -/* How Large Values are Returned */ - -#undef TARGET_RETURN_IN_MEMORY -#define TARGET_RETURN_IN_MEMORY picochip_return_in_memory - -#undef TARGET_STATIC_CHAIN -#define TARGET_STATIC_CHAIN picochip_static_chain - -#undef TARGET_OPTION_OVERRIDE -#define TARGET_OPTION_OVERRIDE picochip_option_override - -#undef TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE -#define TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE picochip_option_override - -/* The 2nd scheduling pass option is switched off, and a machine - dependent reorganisation ensures that it is run later on, after the - second jump optimisation. */ -#undef TARGET_DELAY_SCHED2 -#define TARGET_DELAY_SCHED2 true - -/* Variable tracking should be run after all optimizations which - change order of insns. It also needs a valid CFG. */ -#undef TARGET_DELAY_VARTRACK -#define TARGET_DELAY_VARTRACK true - -struct gcc_target targetm = TARGET_INITIALIZER; - - -/* Only return a value in memory if it is greater than 4 bytes. - int_size_in_bytes returns -1 for variable size objects, which go in - memory always. The cast to unsigned makes -1 > 8. */ - -bool -picochip_return_in_memory(const_tree type, const_tree fntype ATTRIBUTE_UNUSED) -{ - return ((unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 4); -} - -/* Allow some options to be overriden. */ - -static void -picochip_option_override (void) -{ - /* If we are optimizing for stack, dont let inliner to inline functions - that could potentially increase stack size.*/ - if (flag_conserve_stack) - { - maybe_set_param_value (PARAM_LARGE_STACK_FRAME, 0, - global_options.x_param_values, - global_options_set.x_param_values); - maybe_set_param_value (PARAM_STACK_FRAME_GROWTH, 0, - global_options.x_param_values, - global_options_set.x_param_values); - } - - /* Turn off the elimination of unused types. The elaborator - generates various interesting types to represent constants, - generics, and so on, and it is useful to retain this information - in the debug output. The increased size of the debug information - is not really an issue for us. */ - flag_eliminate_unused_debug_types = 0; - - /* Even if the user specifies a -fno-omit-frame-pointer on the - command line, we still want to go ahead and omit frame pointer - usages, since we dont really have a frame pointer register. - So, all accesses to FP need to be converted to accesses off - stack pointer.*/ - flag_omit_frame_pointer = 1; - - /* Turning on anchored addresses by default. This is an optimization - that could decrease the code size by placing anchors in data and - accessing offsets from the anchor for file local data variables.*/ - if (optimize >= 1) - flag_section_anchors = 1; - - /* The second scheduling pass runs within picochip_reorg, to avoid - having the second jump optimisation trash the instruction modes - (e.g., instructions are changed to TImode to mark the beginning - of cycles). Two types of DFA scheduling are possible: space and - speed. In both cases, instructions are reordered to avoid stalls - (e.g., memory loads stall for one cycle). Speed scheduling will - also enable VLIW instruction packing. VLIW instructions use more - code space, so VLIW scheduling is disabled when scheduling for - size. */ - if (flag_schedule_insns_after_reload) - { - if (optimize_size) - picochip_schedule_type = DFA_TYPE_SPACE; - else - { - picochip_schedule_type = DFA_TYPE_SPEED; - flag_delayed_branch = 0; - } - } - else - picochip_schedule_type = DFA_TYPE_NONE; - - /* Ensure that the debug level is always at least -g2. The flow - analyser works at its best if it always has debug - information. DWARF is non-intrusive, so it makes no difference to - code quality if debug is always enabled. */ - if (debug_info_level < DINFO_LEVEL_NORMAL) - { - debug_info_level = DINFO_LEVEL_NORMAL; - write_symbols = DWARF2_DEBUG; - } - - /* Options of the form -mae=mac, and so on will be substituted by - the compiler driver for the appropriate byte access and multiply - unit ISA options. Any unrecognised AE types will end up being - passed to the compiler, which should reject them as invalid. */ - if (picochip_ae_type_string != NULL) - error ("invalid AE type specified (%s)", picochip_ae_type_string); - - /* Override any specific capabilities of the instruction set. These - take precedence over any capabilities inferred from the AE type, - regardless of where the options appear on the command line. */ - if (picochip_mul_type_string == NULL) - { - /* Default to MEM-type multiply, for historical compatibility. */ - picochip_has_mac_unit = false; - picochip_has_mul_unit = true; - } - else - { - picochip_has_mac_unit = false; - picochip_has_mul_unit = false; - - if (strcmp (picochip_mul_type_string, "mul") == 0) - picochip_has_mul_unit = true; - else if (strcmp (picochip_mul_type_string, "mac") == 0) - picochip_has_mac_unit = true; - else if (strcmp (picochip_mul_type_string, "none") == 0) - { /* Do nothing. Unit types already set to false. */ } - else - error ("invalid mul type specified (%s) - expected mac, mul or none", - picochip_mul_type_string); - } -} - - -/* Initialise the library functions to handle arithmetic on some of - the larger modes. */ -void -picochip_init_libfuncs (void) -{ - /* 64-bit shifts */ - set_optab_libfunc (ashr_optab, DImode, "__ashrdi3"); - set_optab_libfunc (ashl_optab, DImode, "__ashldi3"); - set_optab_libfunc (lshr_optab, DImode, "__lshrdi3"); - - /* 64-bit signed multiplication. */ - set_optab_libfunc (smul_optab, DImode, "__muldi3"); - - /* Signed division */ - set_optab_libfunc (sdiv_optab, HImode, "__divhi3"); - set_optab_libfunc (sdiv_optab, DImode, "__divdi3"); - - /* Signed modulus */ - set_optab_libfunc (smod_optab, HImode, "__modhi3"); - set_optab_libfunc (smod_optab, DImode, "__moddi3"); - - /* 32-bit count leading Zeros*/ - set_optab_libfunc (clz_optab, SImode, "_clzsi2"); - - /* 64-bit comparison */ - set_optab_libfunc (ucmp_optab, DImode, "__ucmpdi2"); - set_optab_libfunc (cmp_optab, DImode, "__cmpdi2"); - - /* 64-bit addition and subtraction*/ - set_optab_libfunc (add_optab, DImode, "_adddi3"); - set_optab_libfunc (sub_optab, DImode, "_subdi3"); -} - -/* Memcpy function */ -int -picochip_expand_movmemhi (rtx *operands) -{ - rtx src_addr_reg, dst_addr_reg, count_reg, src_mem, dst_mem, tmp_reg; - rtx start_label; - int align, size; - src_addr_reg = gen_reg_rtx(HImode); - dst_addr_reg = gen_reg_rtx(HImode); - count_reg = gen_reg_rtx(HImode); - emit_insn (gen_movhi (count_reg, operands[2])); - emit_insn (gen_movqi (src_addr_reg, XEXP(operands[1], 0))); - emit_insn (gen_movqi (dst_addr_reg, XEXP(operands[0], 0))); - gcc_assert (GET_CODE(count_reg) == REG); - start_label = gen_label_rtx (); - emit_label (start_label); - - /* We can specialise the code for different alignments */ - align = INTVAL(operands[3]); - size = INTVAL(operands[2]); - gcc_assert(align >= 0 && size >= 0); - if (size != 0) - { - if (size % 4 == 0 && align % 4 == 0) - { - src_mem = gen_rtx_MEM(SImode, src_addr_reg); - dst_mem = gen_rtx_MEM(SImode, dst_addr_reg); - tmp_reg = gen_reg_rtx(SImode); - emit_insn (gen_movsi (tmp_reg, src_mem)); - emit_insn (gen_movsi (dst_mem, tmp_reg)); - emit_insn (gen_addhi3 (dst_addr_reg, dst_addr_reg, GEN_INT(4))); - emit_insn (gen_addhi3 (src_addr_reg, src_addr_reg, GEN_INT(4))); - emit_insn (gen_addhi3 (count_reg, count_reg, GEN_INT(-4))); - /* The sub instruction above generates cc, but we cannot just emit the branch.*/ - emit_cmp_and_jump_insns (count_reg, const0_rtx, GT, 0, HImode, 0, start_label); - } - else if (size % 2 == 0 && align % 2 == 0) - { - src_mem = gen_rtx_MEM(HImode, src_addr_reg); - dst_mem = gen_rtx_MEM(HImode, dst_addr_reg); - tmp_reg = gen_reg_rtx(HImode); - emit_insn (gen_movhi (tmp_reg, src_mem)); - emit_insn (gen_movhi (dst_mem, tmp_reg)); - emit_insn (gen_addhi3 (dst_addr_reg, dst_addr_reg, const2_rtx)); - emit_insn (gen_addhi3 (src_addr_reg, src_addr_reg, const2_rtx)); - emit_insn (gen_addhi3 (count_reg, count_reg, GEN_INT(-2))); - /* The sub instruction above generates cc, but we cannot just emit the branch.*/ - emit_cmp_and_jump_insns (count_reg, const0_rtx, GT, 0, HImode, 0, start_label); - } - else - { - src_mem = gen_rtx_MEM(QImode, src_addr_reg); - dst_mem = gen_rtx_MEM(QImode, dst_addr_reg); - tmp_reg = gen_reg_rtx(QImode); - emit_insn (gen_movqi (tmp_reg, src_mem)); - emit_insn (gen_movqi (dst_mem, tmp_reg)); - emit_insn (gen_addhi3 (dst_addr_reg, dst_addr_reg, const1_rtx)); - emit_insn (gen_addhi3 (src_addr_reg, src_addr_reg, const1_rtx)); - emit_insn (gen_addhi3 (count_reg, count_reg, GEN_INT(-1))); - /* The sub instruction above generates cc, but we cannot just emit the branch.*/ - emit_cmp_and_jump_insns (count_reg, const0_rtx, GT, 0, HImode, 0, start_label); - } - } - return 1; -} - - -/* Return the register class for letter C. */ -enum reg_class -picochip_reg_class_from_letter (unsigned c) -{ - switch (c) - { - case 'k': - return FRAME_REGS; - case 'f': - return PTR_REGS; - case 't': - return TWIN_REGS; - case 'r': - return GR_REGS; - default: - return NO_REGS; - } -} - -static const int -pico_leaf_reg_alloc_order[] = LEAF_REG_ALLOC_ORDER; -static const int -pico_nonleaf_reg_alloc_order[] = REG_ALLOC_ORDER; - -void -picochip_order_regs_for_local_alloc (void) -{ - /* We change the order for leaf functions alone. We put r12 at - the end since using it will prevent us to combine stw/ldws to - stl/ldl and it gives no benefit. In non-leaf functions, we - would anyway saveup/restore r12, so it makes sense to use it.*/ - - if (leaf_function_p()) - { - memcpy ((char *)reg_alloc_order, (const char *) pico_leaf_reg_alloc_order, - FIRST_PSEUDO_REGISTER * sizeof (int)); - } - else - { - memcpy ((char *)reg_alloc_order, (const char *) pico_nonleaf_reg_alloc_order, - FIRST_PSEUDO_REGISTER * sizeof (int)); - } -} - -/* Check that VALUE (an INT_CST) is ok as a constant of type C. */ -int -picochip_const_ok_for_letter_p (unsigned HOST_WIDE_INT value, unsigned c) -{ - - switch (c) - { - case 'I': /* 4 bits signed. */ - return value + 8 < 16; - case 'J': /* 4 bits unsigned. */ - return value < 16; - case 'K': /* 8 bits signed. */ - return value + 128 < 256; - case 'M': /* 4-bit magnitude. */ - return abs (value) < 16; - case 'N': /* 10 bits signed. */ - return value + 512 > 1024; - case 'O': /* 16 bits signed. */ - return value + 32768 < 65536; - default: /* Unknown letter. */ - return 0; - } -} - -/* Stack utility functions. */ -rtx -picochip_return_addr_rtx(int count, rtx frameaddr ATTRIBUTE_UNUSED) -{ - if (count==0) - return gen_rtx_REG (Pmode, LINK_REGNUM); - else - return NULL_RTX; -} - - -/* Emit a set of parallel register expressions used to store - blockmode values to pass to functions. */ -static rtx -picochip_emit_register_parallel (int size_in_units, int offset) -{ - int num_regs = 0; - rtx result; - rtx vector[MAX_CALL_PARAMETER_REGS]; - int base_reg = 0; - int i = 0; - - /* Compute the base register, and number of required registers. */ - base_reg = offset / 2; - num_regs = size_in_units / 2; - if (size_in_units % 2 == 1) - num_regs++; - - /* Emit a register for each part of the block mode value to be - passed in a register. */ - for (i = 0; i < num_regs; i++) - vector[i] = gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (HImode, base_reg + i), - GEN_INT (i * 2)); - result = gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (num_regs, vector)); - - return result; - -} - -/* Emit an instruction to allocate a suitable amount of space on the - stack, by decrementing the stack pointer. */ -static void -picochip_emit_stack_allocate (int adjustment) -{ - rtx insn; - rtx stack_pointer_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); - - /* Use an addition of a negative value. */ - insn = emit_insn (gen_addhi3 (stack_pointer_reg, stack_pointer_reg, - GEN_INT (-adjustment))); - - /* Make the instruction frame related. Also add an expression note, - so that the correct Dwarf information is generated (see documention - for RTX_FRAME_RELATED_P for more details). */ - RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, stack_pointer_reg, - gen_rtx_PLUS (Pmode, stack_pointer_reg, - GEN_INT (-adjustment)))); - -} - -/* Emit an instruction to save a register of the given mode. The - offset at which to save the register is given relative to the stack - pointer. */ -static void -picochip_emit_save_register (rtx reg, int offset) -{ - rtx stack_pointer, address, mem, insn; - - stack_pointer = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); - - address = gen_rtx_PLUS (Pmode, stack_pointer, GEN_INT (offset)); - - mem = gen_rtx_MEM (GET_MODE (reg), address); - - insn = emit_move_insn (mem, reg); - RTX_FRAME_RELATED_P (insn) = 1; - - /* For modes other than HImode, create a note explaining that - multiple registers have been saved. This allows the correct DWARF - call frame information to be generated. */ - switch (GET_MODE (reg)) - { - case HImode: - /* The RTL is sufficient to explain HImode register saves. */ - break; - - case SImode: - /* SImode must be broken down into parallel HImode register saves. */ - { - rtvec p; - p = rtvec_alloc (2); - - RTVEC_ELT (p, 0) = - gen_rtx_SET (HImode, - gen_rtx_MEM (HImode, - gen_rtx_PLUS (Pmode, stack_pointer, - GEN_INT (offset))), - gen_rtx_REG (HImode, REGNO (reg))); - RTX_FRAME_RELATED_P (RTVEC_ELT (p, 0)) = 1; - - RTVEC_ELT (p, 1) = - gen_rtx_SET (HImode, gen_rtx_MEM (HImode, - gen_rtx_PLUS (Pmode, - stack_pointer, - GEN_INT (offset + - 2))), - gen_rtx_REG (HImode, REGNO (reg) + 1)); - RTX_FRAME_RELATED_P (RTVEC_ELT (p, 1)) = 1; - - add_reg_note (insn, REG_FRAME_RELATED_EXPR, - gen_rtx_PARALLEL (VOIDmode, p)); - - } - break; - - default: - internal_error - ("unexpected mode %s encountered in picochip_emit_save_register", - GET_MODE_NAME (GET_MODE (reg))); - } - -} - -/* Emit an instruction to restore a register of the given mode. The - offset from which to restore the register is given relative to the - stack pointer. */ -static void -picochip_emit_restore_register (rtx reg, int offset) -{ - rtx stack_pointer, address, mem; - - stack_pointer = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); - - address = gen_rtx_PLUS (Pmode, stack_pointer, GEN_INT (offset)); - - mem = gen_rtx_MEM (GET_MODE (reg), address); - - emit_move_insn (reg, mem); - -} - -/* Check that the given byte offset is aligned to the given number of - bits. */ -static int -picochip_is_aligned (int byte_offset, int bit_alignment) -{ - int byte_alignment = bit_alignment / BITS_PER_UNIT; - return (byte_offset % byte_alignment) == 0; -} - -/***************************************************************************** - * Stack layout. - * - * The following section contains code which controls how the stack is - * laid out. - * - * The stack is laid out as follows (high addresses first): - * - * Incoming arguments - * Pretend arguments (ARG PTR) - * Special registers - * General registers - * Frame (FP) - * Outgoing arguments (SP) - * - * The (constant) offsets of the different areas must be calculated - * relative to the stack area immediately below, and aligned - * appropriately. For example, the frame offset is computed by - * determining the offset of the special register area, adding the - * size of the special register area, and then aligning the resulting - * offset correctly. In turn, the special register offset is computed - * from the general register offset, and so on. This enables the - * different offsets to change size and alignment, without requiring - * the code for other offset calculations to be rewritten. - * - * The argument pointer, and the frame pointer are eliminated wherever - * possible, by replacing them with a constant offset from the stack - * pointer. In the rare cases where constant offsets from the stack - * pointer cannot be computed, another register will be allocated to - * serve as the argument pointer, or the frame pointer. - * - * The save registers are stored at small offsets from the caller, to - * enable the more efficient SP-based ISA instructions to be used. - * - ****************************************************************************/ - -/* Compute the size of an argument in units. */ -static int -picochip_compute_arg_size (const_tree type, enum machine_mode mode) -{ - int type_size_in_units = 0; - - if (type) - type_size_in_units = tree_to_uhwi (TYPE_SIZE_UNIT (type)); - else - type_size_in_units = GET_MODE_SIZE (mode); - - return type_size_in_units; - -} - -/* Determine where the next outgoing arg should be placed. */ -rtx -picochip_function_arg (cumulative_args_t cum_v, enum machine_mode mode, - const_tree type, bool named ATTRIBUTE_UNUSED) -{ - CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); - int reg = 0; - int type_align_in_units = 0; - int type_size_in_units; - int new_offset = 0; - int offset_overflow = 0; - - /* VOIDmode is passed when computing the second argument to a `call' - pattern. This can be ignored. */ - if (mode == VOIDmode) - return 0; - - /* Compute the alignment and size of the parameter. */ - type_align_in_units = - picochip_function_arg_boundary (mode, type) / BITS_PER_UNIT; - type_size_in_units = picochip_compute_arg_size (type, mode); - - /* Compute the correct offset (i.e., ensure that the offset meets - the alignment requirements). */ - offset_overflow = *cum % type_align_in_units; - if (offset_overflow == 0) - new_offset = *cum; - else - new_offset = (*cum - offset_overflow) + type_align_in_units; - - if (TARGET_DEBUG) - { - printf ("Function arg:\n"); - printf (" Type valid: %s\n", (type ? "yes" : "no")); - printf (" Cumulative Value: %d\n", *cum); - printf (" Mode: %s\n", GET_MODE_NAME (mode)); - printf (" Type size: %i units\n", type_size_in_units); - printf (" Alignment: %i units\n", type_align_in_units); - printf (" New offset: %i\n", new_offset); - printf ("\n"); - } - - /* If the new offset is outside the register space, return. */ - if (new_offset >= MAX_CALL_PARAMETER_REGS * 2) - return 0; - - /* If the end of the argument is outside the register space, then - the argument must overlap the register space. Return the first - available register. */ - if ((new_offset + type_size_in_units) > (MAX_CALL_PARAMETER_REGS * 2)) - return gen_rtx_REG (HImode, new_offset / 2); - - /* Create a register of the required mode to hold the parameter. */ - reg = new_offset / 2; - switch (mode) - { - case QImode: - case HImode: - case SImode: - case SFmode: - case DImode: - case DFmode: - case SDmode: - case DDmode: - case CHImode: - case CSImode: - case SCmode: - case CQImode: - return gen_rtx_REG (mode, reg); - - case BLKmode: - { - /* Empty blockmode values can be passed as arguments (e.g., - * empty structs). These require no registers - * whatsoever. Non-empty blockmode values are passed in a set - * of parallel registers. */ - if (type_size_in_units == 0) - return 0; - else - return picochip_emit_register_parallel (type_size_in_units, new_offset); - } - - default: - warning - (0, "defaulting to stack for %s register creation", - GET_MODE_NAME (mode)); - break; - } - - return 0; - -} - -/* Determine where the next incoming function argument will - appear. Normally, this works in exactly the same way as - picochip_function_arg, except when the function in question is a - varadic function. In this case, the incoming arguments all appear - to be passed on the stack (actually, some of the arguments are - passed in registers, which are then pushed onto the stack by the - function prologue). */ -rtx -picochip_incoming_function_arg (cumulative_args_t cum, - enum machine_mode mode, - const_tree type, bool named) -{ - - if (cfun->stdarg) - return 0; - else - return picochip_function_arg (cum, mode, type, named); - -} - -/* Gives the alignment boundary, in bits, of an argument with the - specified mode. */ -unsigned int -picochip_function_arg_boundary (enum machine_mode mode, - const_tree type ATTRIBUTE_UNUSED) -{ - int align; - - if (mode == BLKmode) - align = STACK_BOUNDARY; - else - align = GET_MODE_ALIGNMENT (mode); - - if (align < PARM_BOUNDARY) - align = PARM_BOUNDARY; - - return align; - -} - -/* Compute partial registers. */ -int -picochip_arg_partial_bytes (cumulative_args_t p_cum, enum machine_mode mode, - tree type, bool named ATTRIBUTE_UNUSED) -{ - int type_align_in_units = 0; - int type_size_in_units; - int new_offset = 0; - int offset_overflow = 0; - - unsigned cum = *get_cumulative_args (p_cum); - - /* VOIDmode is passed when computing the second argument to a `call' - pattern. This can be ignored. */ - if (mode == VOIDmode) - return 0; - - /* Compute the alignment and size of the parameter. */ - type_align_in_units = - picochip_function_arg_boundary (mode, type) / BITS_PER_UNIT; - type_size_in_units = picochip_compute_arg_size (type, mode); - - /* Compute the correct offset (i.e., ensure that the offset meets - the alignment requirements). */ - offset_overflow = cum % type_align_in_units; - if (offset_overflow == 0) - new_offset = cum; - else - new_offset = (cum - offset_overflow) + type_align_in_units; - - if (TARGET_DEBUG) - { - printf ("Partial function arg nregs:\n"); - printf (" Type valid: %s\n", (type ? "yes" : "no")); - printf (" Cumulative Value: %d\n", cum); - printf (" Mode: %s\n", GET_MODE_NAME (mode)); - printf (" Type size: %i units\n", type_size_in_units); - printf (" Alignment: %i units\n", type_align_in_units); - printf (" New offset: %i\n", new_offset); - printf ("\n"); - } - - /* If the new offset is outside the register space, return. */ - if (new_offset >= (MAX_CALL_PARAMETER_REGS * 2)) - return 0; - - /* If the end of the argument is outside the register space, then - the argument must overlap the register space. Return the number - of bytes which are passed in registers. */ - if ((new_offset + type_size_in_units) > (MAX_CALL_PARAMETER_REGS * 2)) - return ((MAX_CALL_PARAMETER_REGS * 2) - new_offset); - - return 0; - -} - -/* Advance the cumulative args counter CUM. */ -void -picochip_arg_advance (cumulative_args_t cum_v, enum machine_mode mode, - const_tree type, bool named ATTRIBUTE_UNUSED) -{ - CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); - int type_align_in_units = 0; - int type_size_in_units; - int new_offset = 0; - int offset_overflow = 0; - - /* VOIDmode is passed when computing the second argument to a `call' - pattern. This can be ignored. */ - if (mode == VOIDmode) - return; - - /* Compute the alignment and size of the parameter. */ - type_align_in_units = - picochip_function_arg_boundary (mode, type) / BITS_PER_UNIT; - type_size_in_units = picochip_compute_arg_size (type, mode); - - /* Compute the correct offset (i.e., ensure that the offset meets - the alignment requirements). */ - offset_overflow = *cum % type_align_in_units; - if (offset_overflow == 0) - new_offset = *cum; - else - new_offset = (*cum - offset_overflow) + type_align_in_units; - - /* Advance past the last argument. */ - new_offset += type_size_in_units; - - *cum = new_offset; -} - -/* Determine whether a register needs saving/restoring. It does if it - is live in a function, and isn't a call-used register. */ -static int -picochip_reg_needs_saving (int reg_num) -{ - return df_regs_ever_live_p(reg_num) && !call_used_regs[reg_num]; -} - -/* Compute and return offset of the main frame. */ -static int -picochip_frame_byte_offset (void) -{ - gcc_assert(picochip_is_aligned - (crtl->outgoing_args_size, BITS_PER_WORD)); - - return crtl->outgoing_args_size; -} - -/* Return the size of the main frame. */ -static int -picochip_frame_size_in_bytes (void) -{ - int frame_size = get_frame_size(); - int stack_align = STACK_BOUNDARY/BITS_PER_UNIT; - if (!picochip_is_aligned (frame_size, STACK_BOUNDARY)) - frame_size = frame_size + (stack_align - frame_size%stack_align); - gcc_assert(picochip_is_aligned (frame_size, STACK_BOUNDARY)); - return frame_size; -} - -/* Compute and return the size (in bytes) of the register save/restore - area for the current function. This only includes the general - purpose registers - the special purpose stack pointer and link - registers are not included in this area. */ -static int -picochip_save_area_size_in_bytes (void) -{ - int num_regs_to_save = 0; - int i = 0; - - /* Read through all the registers, determining which need to be saved. */ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - { - if (picochip_reg_needs_saving (i)) - num_regs_to_save += 1; - } - - return num_regs_to_save * UNITS_PER_WORD; - -} - -/* Compute and return offset of the save area base. */ -static int -picochip_save_area_byte_offset (void) -{ - int base_offset = (picochip_frame_byte_offset () + - picochip_frame_size_in_bytes ()); - - gcc_assert(picochip_is_aligned (base_offset, BITS_PER_WORD)); - - return base_offset; - -} - -/* Compute and return offset of the special register save area. This - area can be found immediately above the normal save area. It must - be aligned, to allow the registers to be saved and restored as a - pair. */ -static int -picochip_special_save_area_byte_offset (void) -{ - int byte_alignment = STACK_BOUNDARY / BITS_PER_UNIT; - int offset = (picochip_save_area_byte_offset () + - picochip_save_area_size_in_bytes ()); - - if ((offset % byte_alignment) != 0) - offset = ((offset / byte_alignment) + 1) * byte_alignment; - - return offset; - -} - -/* Determine whether the LNK/SP register save/restores can be eliminated. */ -static int -picochip_can_eliminate_link_sp_save (void) -{ - /* This deserves some reasoning. The df_regs_ever_live_p call keeps - changing during optimizations phases. So, this function returns different - values when called from initial_elimination_offset and then again when it - is called from prologue/epilogue generation. This means that argument - accesses become wrong. This wouldnt happen only if we were not using the - stack at all. The following conditions ensures that.*/ - - return (crtl->is_leaf && - !df_regs_ever_live_p(LINK_REGNUM) && - !df_regs_ever_live_p(STACK_POINTER_REGNUM) && - (picochip_special_save_area_byte_offset() == 0) && - (crtl->args.size == 0) && - (crtl->args.pretend_args_size == 0)); -} - -/* Compute the size of the special reg save area (SP and LNK). If the - SP/LNK registers don't need to be saved, this area can shrink to - nothing. */ -static int -picochip_special_save_area_size_in_bytes (void) -{ - - - if (picochip_can_eliminate_link_sp_save ()) - return 0; - else - return 2 * UNITS_PER_WORD; -} - -/* Return the number of pretend arguments. If this function is - varadic, all the incoming arguments are effectively passed on the - stack. If this function has real pretend arguments (caused by a - value being passed partially on the stack and partially in - registers), then return the number of registers used. */ -static int -picochip_pretend_arg_area_size (void) -{ - - if (crtl->args.pretend_args_size != 0) - { - gcc_assert(crtl->args.pretend_args_size % 4 == 0); - - return crtl->args.pretend_args_size; - } - else if (cfun->stdarg) - return 12; - else - return 0; - -} - -/* Compute and return the offset of the pretend arguments. The pretend - arguments are contiguous with the incoming arguments, and must be - correctly aligned. */ -static int -picochip_pretend_arg_area_byte_offset (void) -{ - int base_offset = 0; - - base_offset = (picochip_special_save_area_byte_offset () + - picochip_special_save_area_size_in_bytes ()); - - gcc_assert(picochip_is_aligned (base_offset, STACK_BOUNDARY)); - gcc_assert(picochip_is_aligned - (base_offset + picochip_pretend_arg_area_size (), STACK_BOUNDARY)); - - return base_offset; - -} - -/* Compute and return the offset of the incoming arguments. If a - static chain is in use, this will be passed just before the other - arguments. This means that the pretend argument mechanism, used in - variadic functions, doesn't work properly. Thus, static chains work - on their own, as do variadic functions, but not the combination of - the two. This isn't really a problem. */ -static int -picochip_arg_area_byte_offset (void) -{ - int base_offset = (picochip_pretend_arg_area_byte_offset () + - picochip_pretend_arg_area_size ()); - - /* Add an extra 4 bytes - only an extra 16-bits are required, but - the alignment on a 32-bit boundary must be maintained. */ - if (cfun->static_chain_decl != NULL) - { - gcc_assert (!cfun->stdarg); - base_offset += 4; - } - - gcc_assert(picochip_is_aligned (base_offset, STACK_BOUNDARY)); - - return base_offset; - -} - -int -picochip_regno_nregs (int regno ATTRIBUTE_UNUSED, enum machine_mode mode) -{ - - /* Special case - only one register needed. */ - if (GET_MODE_CLASS (mode) == MODE_CC) - return 1; - - /* We actually do not allocate acc0 ever. But, it seems like we need to - make it look like a allocatable register for the dataflow checks to work - properly. Note that hard_regno_mode_ok will always return 0 for acc0*/ - - if (regno == 16) - return 1; - - /* General case - compute how much space in terms of units. */ - return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD); - -} - -int -picochip_class_max_nregs (int reg_class, enum machine_mode mode) -{ - int size = ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD); - - if (reg_class == ACC_REGS) - return 1; - - if (GET_MODE_CLASS (mode) == MODE_CC) - return 1; - else - return size; - -} - -/* Eliminate a register that addresses the stack (e.g., frame pointer, - argument pointer) by replacing it with a constant offset from the - main stack register. */ -int -initial_elimination_offset (int from, int to) -{ - int offset_from_sp = 0; - - if (FRAME_POINTER_REGNUM == from && STACK_POINTER_REGNUM == to) - offset_from_sp = picochip_frame_byte_offset (); - else if (ARG_POINTER_REGNUM == from && STACK_POINTER_REGNUM == to) - offset_from_sp = picochip_pretend_arg_area_byte_offset (); - else - gcc_unreachable(); - - return offset_from_sp; - -} - -/* Compute and return the size of the incoming argument area. */ -static int -picochip_arg_area_size_in_bytes (void) -{ - return crtl->args.size; -} - -/* Determine whether the given register is valid. When the strict mode - is used, only hard registers are valid, otherwise any register is - valid. */ -static int -picochip_legitimate_address_register (rtx x, unsigned strict) -{ - - /* Sanity check - non-registers shouldn't make it here, but... */ - if (REG != GET_CODE (x)) - return 0; - - if (strict) - return REGNO (x) < FIRST_NONHARD_REGISTER; - else - return 1; - -} - -/* Determine whether the given constant is in the range required for - the given base register. */ -static int -picochip_const_ok_for_base (enum machine_mode mode, int regno, int offset) -{ - HOST_WIDE_INT corrected_offset; - - if (GET_MODE_SIZE (mode) != 0) - { - if (GET_MODE_SIZE(mode) <= 4) - { - /* We used to allow incorrect offsets if strict is 0. But, this would - then rely on reload doing the right thing. We have had problems - there before, and on > 4.3 compiler, there are no benefits. */ - if (offset % GET_MODE_SIZE (mode) != 0) - return 0; - corrected_offset = offset / GET_MODE_SIZE (mode); - } - else - { - if (offset % 4 != 0) - return 0; - corrected_offset = offset / 4; - } - } - else - { - /* Default to the byte offset as supplied. */ - corrected_offset = offset; - } - - /* The offset from the base register can be different depending upon - the base register. The stack/frame/argument pointer offsets can - all be greater than a simple register-based offset. Note that the - frame/argument pointer registers are actually eliminations of the - stack pointer, so a value which is valid for an offset to, for - example, the frame pointer, might be invalid for the stack - pointer once the elimination has occurred. However, there is no - need to handle this special case here, as the stack offset is - always checked after elimination anyway, and the generated code - seems to have identical performance. */ - if (regno == STACK_POINTER_REGNUM || - regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM) - return picochip_const_ok_for_letter_p (corrected_offset, 'K'); - else - return picochip_const_ok_for_letter_p (corrected_offset, 'J'); - -} - -/* Determine whether a given rtx is a legitimate address for machine_mode - MODE. STRICT is non-zero if we're being strict - any pseudo that - is not a hard register must be a memory reference. */ -bool -picochip_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) -{ - int valid = 0; - - switch (GET_CODE (x)) - { - case REG: - valid = picochip_legitimate_address_register (x, strict); - break; - - case PLUS: - { - rtx base = XEXP (x, 0); - rtx offset = XEXP (x, 1); - if (strict && !REGNO_OK_FOR_BASE_P (REGNO(base))) - { - valid = 0; - break; - } - - valid = (REG == GET_CODE (base) && - picochip_legitimate_address_register (base, strict) && - CONST_INT == GET_CODE (offset) && - picochip_const_ok_for_base (mode, REGNO (base), - INTVAL (offset))); - break; - } - - case SYMBOL_REF: - /* The user can select whether a symbol can be used as a memory - address. Typically, this will decrease execution time (no - register load is required first), but will increase code size - (because the symbol will be used several times, rather than - loaded once into a register.*/ - valid = TARGET_SYMBOL_AS_ADDRESS; - break; - - case CONST: - { - /* A constant memory address must be a (plus (symbol_ref) - (const_int)), and is only allowed when the symbols are - permitted addresses. */ - rtx inner = XEXP (x, 0); - - valid = (TARGET_SYMBOL_AS_ADDRESS && - PLUS == GET_CODE (inner) && - SYMBOL_REF == GET_CODE (XEXP (inner, 0)) && - CONST_INT == GET_CODE (XEXP (inner, 1))); - - break; - - } - - default: - valid = 0; - } - - return valid; - -} - -/* For all memory operations, picochip allows a uconst4 offset value. It - is hence beneficial to turn an - addr = <reg + long_const> - ld/st addr - - into - - X = reg + long_const & FFF0 - diff = long_const - (long_const & FFF0) - ld/st <X + diff> - - X can be reused in subsequent memory operations. - */ -rtx -picochip_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, - enum machine_mode mode) -{ - unsigned mask_val; - - if (!optimize) - return x; - - /* Depending on mode, the offsets allowed are either 16/32/64.*/ - switch (mode) - { - case QImode: - mask_val = 0xFFF0; - break; - case HImode: - mask_val = 0xFFE0; - break; - case SImode: - mask_val = 0xFFC0; - break; - default: - return x; - } - - if (GET_CODE (x) == PLUS - && GET_CODE (XEXP (x, 0)) == REG - && GET_CODE (XEXP (x, 1)) == CONST_INT) - { - int high_val, low_val, offset; - offset = INTVAL (XEXP (x, 1)); - /* Ignore cases with negative offsets. */ - if (offset < 0) - return x; - high_val = offset & mask_val; - low_val = offset - high_val; - if (high_val != 0) - { - rtx temp_reg = force_reg (Pmode, gen_rtx_PLUS (Pmode, XEXP (x, 0), GEN_INT(high_val))); - x = gen_rtx_PLUS (Pmode, temp_reg, GEN_INT(low_val)); - return x; - } - } - return x; -} - -/* For all memory operations, picochip allows a uconst4 offset value. It - is hence beneficial to turn an - addr = <reg + long_const> - ld/st addr - - into - - X = reg + long_const & FFF0 - diff = long_const - (long_const & FFF0) - ld/st <X + diff> - - X can be reused in subsequent memory operations. - */ -int -picochip_legitimize_reload_address (rtx *x, - enum machine_mode mode, - int opnum, int type, - int ind_levels ATTRIBUTE_UNUSED) -{ - unsigned mask_val; - - if (picochip_symbol_offset(*x)) - { - *x = gen_rtx_CONST(mode, *x); - return 0; - } - if (!optimize) - return 0; - - /* We should recognise addresses that we created.*/ - if (GET_CODE (*x) == PLUS - && GET_CODE (XEXP (*x, 0)) == PLUS - && GET_CODE (XEXP (XEXP (*x, 0), 0)) == REG - && GET_CODE (XEXP (XEXP (*x, 0), 1)) == CONST_INT - && GET_CODE (XEXP (*x, 1)) == CONST_INT) - { - push_reload (XEXP (*x, 0), NULL_RTX, &XEXP (*x, 0), NULL, - BASE_REG_CLASS, GET_MODE (*x), VOIDmode, 0, 0, - opnum, (enum reload_type)type); - return 1; - } - - /* Depending on mode, the offsets allowed are either 16/32/64. */ - switch (mode) - { - case QImode: - mask_val = 0xFFF0; - break; - case HImode: - mask_val = 0xFFE0; - break; - case SImode: - mask_val = 0xFFC0; - break; - default: - return 0; - } - - if (GET_CODE (*x) == PLUS - && GET_CODE (XEXP (*x, 0)) == REG - && GET_CODE (XEXP (*x, 1)) == CONST_INT) - { - int high_val, low_val, offset; - offset = INTVAL (XEXP (*x, 1)); - /* Ignore cases with negative offsets. */ - if (offset < 0) - return 0; - high_val = offset & mask_val; - low_val = offset - high_val; - if (high_val != 0) - { - rtx temp_reg = gen_rtx_PLUS (Pmode, XEXP (*x, 0), GEN_INT(high_val)); - *x = gen_rtx_PLUS (Pmode, temp_reg, GEN_INT(low_val)); - push_reload (XEXP (*x, 0), NULL_RTX, &XEXP (*x, 0), NULL, - BASE_REG_CLASS, GET_MODE (*x), VOIDmode, 0, 0, - opnum, (enum reload_type)type); - return 1; - } - } - - return 0; -} - -/* Detect an rtx which matches (plus (symbol_ref) (const_int)). */ -int -picochip_symbol_offset (rtx operand) -{ - - return (PLUS == GET_CODE (operand) && - SYMBOL_REF == GET_CODE (XEXP (operand, 0)) && - CONST_INT == GET_CODE (XEXP (operand, 1))); - -} - -/* Assembly output. */ - -/* The format here should match the format used in the output of - symbol_ref's elsewhere in this file. */ -void -picochip_output_label (FILE * stream, const char name[]) -{ - int is_cfi_label = (strncmp (name, "picoMark_LCFI", 13) == 0); - - /* If VLIW scheduling is in use, any Call Frame Information labels - generated inside a packet must have their output deferred until - the end of the packet. */ - if (picochip_schedule_type == DFA_TYPE_SPEED && - is_cfi_label && picochip_vliw_continuation) - { - if (picochip_current_vliw_state.num_cfi_labels_deferred == 2) - { - internal_error ("LCFI labels have already been deferred"); - } - strcpy (picochip_current_vliw_state.cfi_label_name[ - picochip_current_vliw_state.num_cfi_labels_deferred], name); - picochip_current_vliw_state.num_cfi_labels_deferred++; - } - else - { - assemble_name (stream, name); - - if (strncmp (name, "picoMark_", 9) == 0) - fprintf (stream, "=\n"); - else - fprintf (stream, ":\n"); - - } - -} - -/* The format here should match the format used in the output of - symbol_ref's elsewhere in this file. */ -void -picochip_output_labelref (FILE * stream, const char name[]) -{ - fprintf (stream, "_%s", name); -} - -void -picochip_weaken_label (FILE * stream, const char name[]) -{ - fprintf (stream, ".weak "); - assemble_name (stream, name); - fprintf (stream, "\n"); -} - -/* Return true if the given label (or label prefix) denotes a marker - label which should be emitted in the form LABEL= */ -static int -picochip_is_marker_prefix (const char *prefix) -{ - return (strcmp (prefix, "L") != 0 && strcmp (prefix, "LC") != 0 - && strcmp (prefix, "LP") != 0); -} - -void -picochip_output_internal_label (FILE * stream, const char *prefix, - unsigned long num) -{ - - /* Emit different types of label, based upon their prefix. They - are handled differently to allow the assembler to ensure that - branch target labels are properly aligned, while other labels - will only serve as code markers, not branch targets. Aligning - labels unnecessarily can result in much code wastage. */ - if (picochip_is_marker_prefix (prefix)) - { - /* Special label marker. If it appears in the middle of a VLIW - packet, defer it until the end of the packet. There has - never been a need to handle more than one lm label at a time. */ - if (picochip_schedule_type == DFA_TYPE_SPEED && - (strcmp (prefix, "LM")) == 0 && picochip_vliw_continuation) - { - if (strlen (picochip_current_vliw_state.lm_label_name) != 0) - internal_error ("LM label has already been deferred"); - - sprintf (picochip_current_vliw_state.lm_label_name, - "picoMark_%s%ld", prefix, num); - } - else if (picochip_schedule_type == DFA_TYPE_SPEED && - (strcmp (prefix, "LCFI")) == 0 && picochip_vliw_continuation) - { - if (picochip_current_vliw_state.num_cfi_labels_deferred == 2) - { - internal_error ("LCFI labels have already been deferred."); - } - sprintf(picochip_current_vliw_state.cfi_label_name[ - picochip_current_vliw_state.num_cfi_labels_deferred], - "picoMark_%s%ld", prefix, num); - picochip_current_vliw_state.num_cfi_labels_deferred++; - } - else - { - /* Marker label. */ - fprintf (stream, "_picoMark_%s%ld=\n", prefix, num); - } - - } - else - { - /* Normal label. */ - fprintf (stream, "_%s%ld:\n", prefix, num); - } - -} - -void -picochip_generate_internal_label (char *str, const char *prefix, long num) -{ - /* Two types of internal label can be generated: branch target - labels and code marker labels. Branch target labels must always - be aligned (since code will execute at these - points). Differentiate between the two by prepending markers with - a unique prefix, which can later be used in output_label to - figure out which label syntax to use. */ - if (picochip_is_marker_prefix (prefix)) - sprintf (str, "picoMark_%s%ld", prefix, num); - else - sprintf (str, "%s%ld", prefix, num); - -} - -void -picochip_asm_output_anchor (rtx symbol) -{ - fprintf (asm_out_file, ".offsetData _%s, ",XSTR (symbol, 0)); - fprintf (asm_out_file, "+ " HOST_WIDE_INT_PRINT_DEC"\n",SYMBOL_REF_BLOCK_OFFSET(symbol)); -} - -void -picochip_output_aligned_common (FILE * stream, const char *name, - unsigned size, unsigned alignment) -{ - - fprintf (stream, ".commonData "); - assemble_name (stream, name); - fprintf (stream, ", %u, %u\n", size, alignment / 8); - picochip_output_global (stream, name); - -} - -void -picochip_output_aligned_local (FILE * stream, const char *name, - unsigned size, unsigned alignment) -{ - - fprintf (stream, ".commonData "); - assemble_name (stream, name); - fprintf (stream, ", %u, %u\n", size, alignment / 8); - -} - -void -picochip_output_global (FILE * stream, const char *name) -{ - fprintf (stream, ".global "); - assemble_name (stream, name); - fprintf (stream, "\n"); -} - -/* Output an assembly language string. Output as a sequence of decimal - numbers, followed by the literal string to make it obvious what the - numbers represent. */ -void -picochip_output_ascii (FILE * file, const char *str, int length) -{ - int i = 0; - - fprintf (file, ".ascii "); - - for (i = 0; i < length; ++i) - { - fprintf (file, "16#%x# ", (char) (str[i])); - } - - fprintf (file, " ; "); - - for (i = 0; i < length; ++i) - { - char c = str[i]; - - switch (c) - { - case '\n': - fprintf (file, "\\n"); - break; - case '\t': - fprintf (file, "\\t"); - break; - case '\0': - fprintf (file, "\\0"); - break; - default: - fprintf (file, "%c", c); - } - - } - - fprintf (file, "\n"); - -} - -/* Output the beginning of an ASM file. */ -void -picochip_asm_file_start (void) -{ - default_file_start (); - - fprintf (asm_out_file, "// picoChip ASM file\n"); - fprintf (asm_out_file, "//.file \"%s\"\n", main_input_filename); - - fprintf (asm_out_file, "// Has byte access: %s\n", - (TARGET_HAS_BYTE_ACCESS ? "Yes" : "No")); - - if (TARGET_HAS_MUL_UNIT) - fprintf (asm_out_file, "// Has multiply: Yes (Multiply unit)\n"); - else if (TARGET_HAS_MAC_UNIT) - fprintf (asm_out_file, "// Has multiply: Yes (Mac unit)\n"); - else - fprintf (asm_out_file, "// Has multiply: No\n"); -} - -/* Output the end of an ASM file. */ -void -picochip_asm_file_end (void) -{ - /* Include a segment end to make it easy for PERL scripts to grab - segments. This is now done by assembler*/ - - fprintf (asm_out_file, "// End of picoChip ASM file\n"); - -} - -/* Output frame debug information to the given stream. */ -static void -picochip_output_frame_debug (FILE * file) -{ - int i = 0; - - if (crtl->is_leaf) - fprintf (file, "\t\t// Leaf function\n"); - else - fprintf (file, "\t\t// Non-leaf function\n"); - - if (picochip_can_eliminate_link_sp_save ()) - fprintf (file, "\t\t// Link/fp save/restore can be eliminated\n"); - - if (cfun->static_chain_decl != NULL) - fprintf (file, "\t\t// Static chain in use\n"); - - fprintf (file, "\t\t// Incoming argument size: %d bytes\n", - picochip_arg_area_size_in_bytes ()); - fprintf (file, "\t\t// Incoming arg offset: %d\n", - picochip_arg_area_byte_offset ()); - fprintf (file, "\t\t// Pretend arg size: %d\n", - picochip_pretend_arg_area_size ()); - fprintf (file, "\t\t// Pretend arg offset (ARGP): %d\n", - picochip_pretend_arg_area_byte_offset ()); - fprintf (file, "\t\t// Special reg area size: %d bytes\n", - picochip_special_save_area_size_in_bytes ()); - fprintf (file, "\t\t// Special reg area offset: %d\n", - picochip_special_save_area_byte_offset ()); - - /* Output which registers are saved. */ - fprintf (file, "\t\t// Saved regs: "); - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - { - if (picochip_reg_needs_saving (i)) - fprintf (file, "%s ", picochip_regnames[i]); - } - fprintf (file, "\t\t\n"); - - fprintf (file, "\t\t// Save area size: %d bytes\n", - picochip_save_area_size_in_bytes ()); - fprintf (file, "\t\t// Save area offset: %d\n", - picochip_save_area_byte_offset ()); - - fprintf (file, "\t\t// Frame size: %ld bytes\n", get_frame_size ()); - fprintf (file, "\t\t// Frame offset (FP): %d\n", - picochip_frame_byte_offset ()); - - fprintf (file, "\t\t// Outgoing argument area size: %d bytes\n", - crtl->outgoing_args_size); - -} - -/* Output picoChip function prologue. This contains human-readable - information about the function. */ -void -picochip_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) -{ - /* Get the function's name, as described by its RTL. This may be - different from the DECL_NAME name used in the source file. The - real declaration name must be used, to ensure that the prologue - emits the right information for the linker. */ - rtx x; - const char *fnname; - x = DECL_RTL (current_function_decl); - gcc_assert (MEM_P (x)); - x = XEXP (x, 0); - gcc_assert (GET_CODE (x) == SYMBOL_REF); - fnname = XSTR (x, 0); - - /* Note that the name of the function is given in the &_%s - form. This matches the name of the function as used in labels, - and function calls, and enables processCallGraph to match - function calls to the name of the function, as defined here. */ - fprintf (file, "// picoChip Function Prologue : &_%s = %d bytes\n", - fnname, picochip_arg_area_byte_offset ()); - - picochip_output_frame_debug (file); - fprintf (file, "\n"); - -} - -/* Output picoChip function epilogue. */ -void -picochip_function_epilogue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) -{ - - rtx x; - const char *fnname; - x = DECL_RTL (current_function_decl); - gcc_assert (MEM_P (x)); - x = XEXP (x, 0); - gcc_assert (GET_CODE (x) == SYMBOL_REF); - fnname = XSTR (x, 0); - fprintf (file, "\n// picoChip Function Epilogue : %s\n\n", - fnname); -} - -/* Manipulate the asm output. Some machines only execute the code when - there is actually a chance of needing it (e.g., FRV doesn't execute - it if the scheduling pass wasn't used). We always execute it, - simple to ensure that it is exercised more often, and bugs are more - likely to be found. - - This function's prime reason for existence is to insert the VLIW - separators where appropriate. The separators must be inserted - before any comments which appear at the end of the file. - -*/ -const char * -picochip_asm_output_opcode (FILE * f, const char *ptr) -{ - int c; - - /* Flag to specify when a VLIW continuation has been inserted onto - the line. Continuations are either inserted before any comments, - or before the end of the line is reached. The flag ensures that - we don't insert continuations twice (i.e., at the comment and the - end of line). */ - int continuation_inserted = 0; - - /* If the instruction uses multiple lines (i.e., a new line - character appears in the opcode), then ensure that no attempt is - made to pack it into a VLIW. */ - if (strchr (ptr, '\n') != NULL && picochip_vliw_continuation) - internal_error - ("picochip_asm_output_opcode - Found multiple lines in VLIW packet %s", - ptr); - - - /* If a delay slot is pending, output the directive to the assembler - before the instruction. */ - if (picochip_is_delay_slot_pending) - { - picochip_is_delay_slot_pending = 0; - fputs ("=->\t", f); - } - - /* Keep going for entire opcode. All substitution performed ourselves. */ - while (*ptr) - { - c = *ptr++; - - /* Determine whether a VLIW continuation must be inserted before - any comments, or the end of the opcode. A flag is set to show - that we have inserted a continuation on this line, so that we - don't try to insert another continuation when the end of the - opcode is reached. The only other case for a continuation - might have been a newline, but these aren't allowed in - conjunction with VLIW continuations (see above code). */ - if (picochip_vliw_continuation && - !continuation_inserted && - ((c == '/' && (*ptr == '/')) || *ptr == '\0')) - { - fprintf (f, "\\ "); - continuation_inserted = 1; - } - - /* Detect an explicit VLIW separator. */ - if (c == '%' && (*ptr == '|')) - { - fprintf (f, "\\"); - ptr++; - } - /* Detect the need for an ALU id operand. */ - else if (c == '%' && (*ptr == '#')) - { - fputc (picochip_get_vliw_alu_id (), f); - - if (TARGET_DEBUG) - printf ("Generated ALU char at %s for insn %d\n", ptr, - INSN_UID (picochip_current_prescan_insn)); - - /* Skip past unwanted # */ - ptr++; - } - /* Detect the need for branch delay slot. */ - else if (c == '%' && (*ptr == '>')) - { - /* Only emit delay slots (NOP's, or otherwise) when delay - * slot scheduling has actually been enabled, otherwise VLIW - * scheduling and delay slot scheduling output combine to - * produce nasty effects. */ - if (flag_delayed_branch) - { - if (dbr_sequence_length () == 0) - fputs ("\n=->\tNOP", f); - else - picochip_is_delay_slot_pending = 1; - } - - /* Skip past unwanted > */ - ptr++; - } - /* Detect any %digit specifiers. */ - else if (c == '%' && (*ptr >= '0' && *ptr <= '9')) - { - c = atoi (ptr); - picochip_print_operand (f, recog_data.operand[c], 0); - while ((c = *ptr) >= '0' && c <= '9') - ptr++; - } - /* Detect any %letterdigit specifiers. */ - else if (c == '%' && ((*ptr >= 'a' && *ptr <= 'z') - || (*ptr >= 'A' && *ptr <= 'Z'))) - { - int letter = *ptr++; - - c = atoi (ptr); - - switch (letter) - { - case 'l': - output_asm_label (recog_data.operand[c]); - break; - - case 'a': - output_address (recog_data.operand[c]); - break; - - default: - picochip_print_operand (f, recog_data.operand[c], letter); - } - - while ((c = *ptr) >= '0' && c <= '9') - ptr++; - } - else if (c == '%') - internal_error - ("picochip_asm_output_opcode - can%'t output unknown operator %c", - *ptr); - else - fputc (c, f); - } - - /* Reached the end of the packet. If any labels were deferred - during output, emit them now. */ - if (!picochip_vliw_continuation) - { - if (picochip_current_vliw_state.num_cfi_labels_deferred != 0) - { - fprintf (f, "\n"); - assemble_name (f, picochip_current_vliw_state.cfi_label_name[0]); - fprintf (f, "="); - if (picochip_current_vliw_state.num_cfi_labels_deferred == 2) - { - fprintf (f, "\n"); - assemble_name (f, picochip_current_vliw_state.cfi_label_name[1]); - fprintf (f, "="); - } - } - - if (strlen (picochip_current_vliw_state.lm_label_name) != 0) - { - fprintf (f, "\n"); - assemble_name (f, picochip_current_vliw_state.lm_label_name); - fprintf (f, "="); - } - } - - /* Output an end-of-packet marker if requested. */ - if (!picochip_vliw_continuation && - TARGET_DEBUG && picochip_schedule_type == DFA_TYPE_SPEED) - fprintf (f, "\n\t//-------------- End of VLIW packet -----------------"); - - return ptr; -} - -/* Function RTL expansion. */ - -/* Expand the prologue into RTL. */ -void -picochip_expand_prologue (void) -{ - int stack_adjustment = 0; - int special_save_offset = 0; - int general_save_offset = 0; - int reg_save_offset = 0; - int i = 0; - - stack_adjustment = picochip_arg_area_byte_offset (); - general_save_offset = - -(stack_adjustment - picochip_save_area_byte_offset ()); - special_save_offset = - -(stack_adjustment - picochip_special_save_area_byte_offset ()); - - /* Save the link registers. We could try to save just one register - here. This would reduce the amount of stack space required. - There hasn't been a good reason to do that so far. */ - if (!picochip_can_eliminate_link_sp_save ()) - picochip_emit_save_register (gen_rtx_REG (SImode, LINK_REGNUM), - special_save_offset); - - /* Save callee-save registers. */ - reg_save_offset = 0; - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - { - if (picochip_reg_needs_saving (i)) - { - - /* If this register is an even numbered register, and the - next register also needs to be saved, use a SImode save, - which does both in one instruction. Note that a special - check is performed to ensure that the double word aligned - store is valid (e.g., it is possible that r6, r8, r9 need - to be saved, in which case once r6 has been saved, the - stored offset is no longer aligned, and an STL/LDL - instruction becomes invalid). Alternately, we could store all - aligned registers first and then save the single one(s). */ - if ((i % 2 == 0) && - picochip_reg_needs_saving (i + 1) && - picochip_is_aligned (reg_save_offset, LONG_TYPE_SIZE)) - { - picochip_emit_save_register (gen_rtx_REG (SImode, i), - general_save_offset + - reg_save_offset); - reg_save_offset += 2 * UNITS_PER_WORD; - i++; - } - else - { - picochip_emit_save_register (gen_rtx_REG (HImode, i), - general_save_offset + - reg_save_offset); - reg_save_offset += UNITS_PER_WORD; - } - } - - } - - /* Emit a stack adjustment where required. */ - if (stack_adjustment != 0) - picochip_emit_stack_allocate (stack_adjustment); - - /* If this function uses varadic arguments, write any unnamed - registers to the stack. */ - if (cfun->stdarg) - { - int stdarg_offset = picochip_pretend_arg_area_byte_offset (); - - /* Sanity check. The pretend argument offset should be 32-bit aligned. */ - gcc_assert(picochip_pretend_arg_area_byte_offset () % 4 == 0); - - picochip_emit_save_register (gen_rtx_REG (SImode, 0), stdarg_offset); - picochip_emit_save_register (gen_rtx_REG (SImode, 2), - stdarg_offset + 4); - picochip_emit_save_register (gen_rtx_REG (SImode, 4), - stdarg_offset + 8); - - } - -} - -/* Expand the epilogue into RTL. */ -void -picochip_expand_epilogue (int is_sibling_call ATTRIBUTE_UNUSED) -{ - int stack_adjustment = 0; - int special_save_offset = 0; - int general_save_offset = 0; - int reg_save_offset = 0; - int i = 0; - int use_link_fp_restore_stack_adjust = 0; /* Default to using an explicit - stack restore. */ - - stack_adjustment = picochip_arg_area_byte_offset (); - general_save_offset = - -(stack_adjustment - picochip_save_area_byte_offset ()); - special_save_offset = - -(stack_adjustment - picochip_special_save_area_byte_offset ()); - - /* Emit a stack adjustment where required. */ - if (stack_adjustment != 0) - { - /* If the link/fp is already being restored, and the offset to - their save location is small enough, don't bother adjusting - the stack explicitly. */ - if (picochip_special_save_area_byte_offset () < 512 && - !picochip_can_eliminate_link_sp_save ()) - use_link_fp_restore_stack_adjust = 1; - else - /* Explicitly restore the stack. */ - picochip_emit_stack_allocate (-stack_adjustment); - } - - /* Restore the Link/FP registers. Only save the link register? */ - if (!picochip_can_eliminate_link_sp_save ()) - { - if (use_link_fp_restore_stack_adjust) - picochip_emit_restore_register (gen_rtx_REG (SImode, LINK_REGNUM), - picochip_special_save_area_byte_offset - ()); - else - picochip_emit_restore_register (gen_rtx_REG (SImode, LINK_REGNUM), - special_save_offset); - } - - /* Restore callee-save registers. */ - reg_save_offset = 0; - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - { - if (picochip_reg_needs_saving (i)) - { - - /* If this register is an even numbered register, and the - next register also needs to be saved, use a SImode save, - which does both in one instruction. Note that a special - check is performed to ensure that the double word aligned - store is valid (e.g., it is possible that r6, r8, r9 need - to be saved, in which case once r6 has been saved, the - stored offset is no longer aligned, and an STL/LDL - instruction becomes invalid). We could store all aligned - registers first, and then save the single one(s). */ - if ((i % 2 == 0) && - picochip_reg_needs_saving (i + 1) && - picochip_is_aligned (reg_save_offset, LONG_TYPE_SIZE)) - { - picochip_emit_restore_register (gen_rtx_REG (SImode, i), - general_save_offset + - reg_save_offset); - reg_save_offset += 2 * UNITS_PER_WORD; - i++; - } - else - { - picochip_emit_restore_register (gen_rtx_REG (HImode, i), - general_save_offset + - reg_save_offset); - reg_save_offset += UNITS_PER_WORD; - } - } - - } - - /* Emit a return instruction, which matches a (parallel - [(return) (use r12)]) */ - { - rtvec p; - p = rtvec_alloc (2); - - RTVEC_ELT (p, 0) = ret_rtx; - RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, - gen_rtx_REG (Pmode, LINK_REGNUM)); - emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p)); - } - -} - -/* Assembly instruction output. */ - -/* Test whether the given branch instruction is short, or long. Short - * branches are equivalent to real branches, and may be DFA - * scheduled. Long branches expand to a macro which is handled by the - * elaborator, and cannot be scheduled. Occasionally, the branch - * shortening pass, which is run after DFA scheduling, will change the - * code layout and cause the short branch to be reverted into a long - * branch. Instead of having to fix this up by emitting new assembly, - * the short branch is emitted anyway. There is plenty of slack in the - * calculation of long and short branches (10-bit offset, but only - * 9-bits used in computation), so there is enough slack for this to - * be safe. */ -static int -picochip_is_short_branch (rtx insn) -{ - int isRealShortBranch = (get_attr_length(insn) == SHORT_BRANCH_LENGTH); - - return (isRealShortBranch || - picochip_current_vliw_state.num_insns_in_packet > 1); -} - -/* Output a compare-and-branch instruction (matching the cbranch - pattern). */ -const char * -picochip_output_cbranch (rtx operands[]) -{ - - if (HImode != GET_MODE (operands[1]) || - (HImode != GET_MODE (operands[2]) && - GET_CODE (operands[2]) != CONST_INT)) - { - internal_error ("%s: at least one operand can%'t be handled", - __FUNCTION__); - } - - /* Use the type of comparison to output the appropriate condition - test. */ - switch (GET_CODE (operands[0])) - { - case NE: - return ("// if (%1 != %2) goto %l3\n\tSUB.%# %1,%2,r15\n\tJMPNE %l3"); - - case EQ: - return ("// if (%1 == %2) goto %l3\n\tSUB.%# %1,%2,r15\n\tJMPEQ %l3"); - - case LE: - /* Reverse the operand order to be GE */ - return ("// if (%1 <= %2) goto %l3\n\tSUB.%# %2,%1,r15\n\tJMPGE %l3"); - - case LEU: - /* Reverse operand order of GEU. */ - return ("// if (%1 <= %2) goto %l3\n\tSUB.%# %2,%1,r15\n\tJMPHS %l3"); - - case GE: - return ("// if (%1 >= %2) goto %l3\n\tSUB.%# %1,%2,r15\n\tJMPGE %l3"); - - case GEU: - return ("// if (%1 >= %2) goto %l3\n\tSUB.%# %1,%2,r15\n\tJMPHS %l3"); - - case LT: - return ("// if (%1 < %2) goto %l3\n\tSUB.%# %1,%2,r15\n\tJMPLT %l3"); - - case LTU: - return ("// if (%1 <{U} %2) goto %l3\n\tSUB.%# %1,%2,r15\n\tJMPLO %l3"); - - case GT: - /* Reversed operand version of LT. */ - return ("// if (%1 > %2) goto %l3\n\tSUB.%# %2,%1,r15\n\tJMPLT %l3"); - - case GTU: - /* Reverse an LTU. */ - return ("// if (%1 >{U} %2) goto %l3\n\tSUB.%# %2,%1,r15\n\tJMPLO %l3"); - - default: - gcc_unreachable(); - } -} - -/* Output a compare-and-branch instruction (matching the cbranch - pattern). This function is current unused since the cbranch - split is disabled. The function is kept around so we can use - it when we understand how to do cbranch split safely. */ -const char * -picochip_output_compare (rtx operands[]) -{ - int code; - - if (HImode != GET_MODE (operands[1]) || - (HImode != GET_MODE (operands[2]) && - GET_CODE (operands[2]) != CONST_INT)) - { - internal_error ("%s: at least one operand can%'t be handled", - __FUNCTION__); - } - - code = GET_CODE (operands[0]); - /* Use the type of comparison to output the appropriate condition - test. */ - switch (code) - { - case NE: - return ("SUB.%# %1,%2,r15\t// CC := (%0)"); - - case EQ: - return ("SUB.%# %1,%2,r15\t// CC := (%0)"); - - case LE: - /* Reverse the operand order to be GE */ - return ("SUB.%# %2,%1,r15\t// CC := (%0)"); - - case LEU: - /* Reverse operand order of GEU. */ - return ("SUB.%# %2,%1,r15\t// CC := (%0)"); - - case GE: - return ("SUB.%# %1,%2,r15\t// CC := (%0)"); - - case GEU: - return ("SUB.%# %1,%2,r15\t// CC := (%0)"); - - case LT: - return ("SUB.%# %1,%2,r15\t// CC := (%0)"); - - case LTU: - return ("SUB.%# %1,%2,r15\t// CC := (%0)"); - - case GT: - /* Reversed operand version of LT. */ - return ("SUB.%# %2,%1,r15\t// CC := (%0)"); - - case GTU: - /* Reverse an LTU. */ - return ("SUB.%# %2,%1,r15\t// CC := (%0)"); - - default: - gcc_unreachable(); - } -} - -/* Output the branch insn part of a compare-and-branch split. */ -const char * -picochip_output_branch (rtx operands[], rtx insn) -{ - - int code = GET_CODE(operands[2]); - if (picochip_is_short_branch (insn)) - { - /* Short branches can be output directly using the - appropriate instruction. */ - switch (code) - { - case NE: - return ("BNE %l0 %>"); - case EQ: - return ("BEQ %l0 %>"); - case LE: - return ("BGE %l0 %>"); - case LEU: - return ("BHS %l0 %>"); - case GE: - return ("BGE %l0 %>"); - case GEU: - return ("BHS %l0 %>"); - case LT: - return ("BLT %l0 %>"); - case LTU: - return ("BLO %l0 %>"); - case GT: - return ("BLT %l0 %>"); - case GTU: - return ("BLO %l0 %>"); - default: - internal_error ("unknown short branch in %s (type %d)", - __FUNCTION__, (int) INTVAL (operands[1])); - return "UNKNOWN_BRANCH"; - } - } - else - { - /* Long branches result in the emission of a special - instruction, which the assembler expands into a suitable long - branch. */ - - /* Use the type of comparison to output the appropriate condition - test. */ - switch (code) - { - case NE: - return ("JMPNE %l0 %>"); - case EQ: - return ("JMPEQ %l0 %>"); - case LE: - return ("JMPGE %l0 %>"); - case LEU: - return ("JMPHS %l0 %>"); - case GE: - return ("JMPGE %l0 %>"); - case GEU: - return ("JMPHS %l0 %>"); - case LT: - return ("JMPLT %l0 %>"); - case LTU: - return ("JMPLO %l0 %>"); - case GT: - return ("JMPLT %l0 %>"); - case GTU: - return ("JMPLO %l0 %>"); - - default: - internal_error ("unknown long branch in %s (type %d)", - __FUNCTION__, (int) INTVAL (operands[1])); - return "UNKNOWN_BRANCH"; - } - - } -} - -/* Output a jump instruction. */ -const char * -picochip_output_jump (rtx insn) -{ - if (picochip_is_short_branch (insn)) - return "BRA %l0%>"; - else - return "JMPRA %l0%>"; -} - -const char * -picochip_output_put_array (int alternative, rtx operands[]) -{ - /* Local output buffer. */ - char buf[256]; - - int portArraySize = INTVAL(operands[1]); - int portBaseIndex = INTVAL(operands[2]); - - if (alternative == 0) - { - sprintf (buf, "// Array put\n\tadd.0 [lsl %%0,2],&__commTable_put_%d_%d,lr\n\tjl (lr)", - portArraySize, portBaseIndex); - output_asm_insn (buf, operands); - } - else if (alternative == 1) - { - /* Constant port id. Emit a real instruction. */ - int portIndex = INTVAL(operands[0]) + portBaseIndex; - if (portIndex < portBaseIndex || - portIndex >= (portBaseIndex + portArraySize)) - { - error ("PUT uses port array index %d, which is out of range [%d..%d)", - portIndex, portBaseIndex, portBaseIndex + portArraySize); - } - sprintf(buf, "PUT R[0:1],%d", portIndex); - output_asm_insn (buf, operands); - } - else - gcc_unreachable(); - - /* Both alternatives output the insn directly. */ - return ""; -} - -const char *picochip_output_get_array (int alternative, rtx operands[]) -{ - /* Local output buffer. */ - char buf[256]; - - int portArraySize = INTVAL(operands[1]); - int portBaseIndex = INTVAL(operands[2]); - - if (alternative == 0) - { - sprintf (buf, "// Array get\n\tadd.0 [lsl %%0,2],&__commTable_get_%d_%d,lr\n\tjl (lr)", - portArraySize, portBaseIndex); - output_asm_insn (buf, operands); - } - else if (alternative == 1) - { - /* Constant port id. Emit a real instruction. */ - int portIndex = INTVAL(operands[0]) + portBaseIndex; - if (portIndex < portBaseIndex || - portIndex >= (portBaseIndex + portArraySize)) - { - error ("GET uses port array index %d, which is out of range [%d..%d)", - portIndex, portBaseIndex, portBaseIndex + portArraySize); - } - sprintf(buf, "GET %d,R[0:1]", portIndex); - output_asm_insn (buf, operands); - } - else - gcc_unreachable(); - - /* Both alternatives output the insn directly. */ - return ""; -} - -const char *picochip_output_testport_array (int alternative, rtx operands[]) -{ - /* Local output buffer. */ - char buf[256]; - - int portArraySize = INTVAL(operands[2]); - int portBaseIndex = INTVAL(operands[3]); - - if (alternative == 0) - { - sprintf (buf, "// Array tstport\n\tadd.0 [lsl %%1,2],&__commTable_tstport_%d_%d,lr\n\tjl (lr)\n=->\tcopy.0 0,%%0\n\tcopyeq 1,%%0", - portArraySize, portBaseIndex); - output_asm_insn (buf, operands); - } - else if (alternative == 1) - { - /* Constant port id. Emit a real instruction. */ - int portIndex = INTVAL(operands[1]) + portBaseIndex; - if (portIndex < portBaseIndex || - portIndex >= (portBaseIndex + portArraySize)) - { - error ("PUT uses port array index %d, which is out of range [%d..%d)", - portIndex, portBaseIndex, portBaseIndex + portArraySize); - } - sprintf(buf, "copy.1 0,%%0 %%| TSTPORT %d\n\tcopyeq 1,%%0", portIndex); - output_asm_insn (buf, operands); - } - else - gcc_unreachable(); - - /* Both alternatives output the insn directly. */ - return ""; -} - -/* Output a comparison operand as a symbol (e.g., >). */ -static void -picochip_print_comparison (FILE * file, rtx operand, int letter) -{ - - if (letter == 'i') - { - /* Output just the comparison symbol. */ - switch (GET_CODE (operand)) - { - case NE: - fprintf (file, "!="); - break; - case EQ: - fprintf (file, "=="); - break; - case GE: - fprintf (file, ">="); - break; - case GEU: - fprintf (file, ">={U}"); - break; - case LT: - fprintf (file, "<"); - break; - case LTU: - fprintf (file, "<{U}"); - break; - case LE: - fprintf (file, "<="); - break; - case LEU: - fprintf (file, "<={U}"); - break; - case GT: - fprintf (file, ">"); - break; - case GTU: - fprintf (file, ">{U}"); - break; - default: - gcc_unreachable(); - } - } - else - { - /* Output the comparison formatted as operand,symbol,operand */ - rtx op0 = XEXP (operand, 0); - rtx op1 = XEXP (operand, 1); - - picochip_print_operand (file, op0, 0); - picochip_print_comparison (file, operand, 'i'); - picochip_print_operand (file, op1, 0); - } -} - -/* This function generates a memory address operand in the given - mode. That is, if the address contains a constant offset, then the - offset is divided by the required mode size to compute the - mode specific offset. By default, picochip_print_operand_address calls - this function using the natural mode of the operand, but special - operand codes can be used to invoke the computation using an - unnatural mode (e.g., compute the HI aligned address of an SI mode - address). */ -static void -picochip_print_memory_address (FILE * file, rtx operand, - enum machine_mode mode) -{ - rtx address = XEXP (operand, 0); - - /* Sanity check. */ - if (MEM != GET_CODE (operand)) - fatal_insn ("picochip_print_memory_address - Operand isn't memory based", - operand); - - if (TARGET_DEBUG) - { - printf ("picochip_print_memory_address: "); - print_rtl (stdout, operand); - printf ("\n"); - } - - switch (GET_CODE (address)) - { - case PLUS: - { - /* Grab the address components. */ - rtx base = XEXP (address, 0); - rtx offset = XEXP (address, 1); - - /* Only handle reg+const addresses */ - if (REG == GET_CODE (base) && CONST_INT == GET_CODE (offset)) - { - /* Sanity check. If an FP+offset address is given, ensure - that the offset lies within the given frame, or a lower - frame. */ - if (REGNO (base) == STACK_POINTER_REGNUM ) - gcc_assert (INTVAL (offset) <= (picochip_arg_area_byte_offset () + - crtl->args.size)); - - /* Print the base register - identical for all modes. */ - fprintf (file, "("); - picochip_print_operand (file, base, 'r'); - fprintf (file, ")"); - - /* Print the constant offset with compensation for the mode. */ - switch (mode) - { - case QImode: - picochip_print_operand (file, offset, 'Q'); - break; - - case HImode: - picochip_print_operand (file, offset, 'H'); - break; - - case SImode: - case SFmode: - picochip_print_operand (file, offset, 'S'); - break; - - case DImode: - picochip_print_operand (file, offset, 'D'); - break; - - default: - gcc_unreachable(); - } - - } - - } - - break; - - case SYMBOL_REF: - picochip_print_operand (file, address, 's'); - break; - - case CONST: - { - rtx inner; - rtx base; - rtx offset; - - inner = XEXP (address, 0); - - /* Sanity check - the CONST memory address must be a base+offset. */ - gcc_assert (PLUS == GET_CODE (inner)); - - base = XEXP (inner, 0); - offset = XEXP (inner, 1); - - fprintf (file, "&_%s%+d", XSTR (base, 0), XINT (offset, 0)); - - break; - } - - case REG: - /* Register operand. Provide a zero offset. */ - fprintf (file, "("); - picochip_print_operand (file, address, 'r'); - fprintf (file, ")0"); - break; - - default: - gcc_unreachable(); - } - -} - -/* Output an operand. Formatting letters allow particular parts of - the operand to be output. */ -void -picochip_print_operand (FILE * file, rtx operand, int letter) -{ - - /* Handle special cases. */ - switch (letter) - { - /* VLIW continuation, for explicit VLIW sequences. */ - case '|': - fprintf (file, "\\"); - return; - - /* ALU selector. */ - case '#': - fputc (picochip_get_vliw_alu_id (), file); - return; - - /* Delay slot specifier. */ - case '>': - /* This should be handled in asm_output_opcode. */ - gcc_unreachable(); - - /* Instruction mnemonics (e.g., lshift becomes LSL). */ - case 'I': - switch (GET_CODE (operand)) - { - case AND: - fprintf (file, "AND"); - break; - case IOR: - fprintf (file, "OR"); - break; - case XOR: - fprintf (file, "XOR"); - break; - case PLUS: - fprintf (file, "ADD"); - break; - case MINUS: - fprintf (file, "SUB"); - break; - default: - gcc_unreachable(); - } - return; - - /* Symbolic instructions (e.g., lshift becomes <<). */ - case 'i': - switch (GET_CODE (operand)) - { - case AND: - fprintf (file, "&"); - break; - case IOR: - fprintf (file, "|"); - break; - case XOR: - fprintf (file, "^"); - break; - case PLUS: - fprintf (file, "+"); - break; - case MINUS: - fprintf (file, "-"); - break; - default: - fprintf (file, "UNKNOWN_INSN"); - break; - } - return; - - default: /* Not a punctuation character - process as normal. */ - break; - } - - switch (GET_CODE (operand)) - { - case REG: - switch (letter) - { - case 'R': - /* Write a range of registers. */ - fprintf (file, "R[%d:%d]", REGNO (operand) + 1, REGNO (operand)); - break; - - case 'U': - /* The upper register of a pair is requested. */ - fprintf (file, "%s", picochip_regnames[REGNO (operand) + 1]); - break; - - case 'L': - /* The lower register of a pair is requested. Equivalent to the - default, but included for completeness. */ - fprintf (file, "%s", picochip_regnames[REGNO (operand)]); - break; - - case 'X': - /* The 3rd register of a DI mode register. */ - fprintf (file, "%s", picochip_regnames[REGNO (operand) + 2]); - break; - - case 'Y': - /* The 4th register of a DI mode register. */ - fprintf (file, "%s", picochip_regnames[REGNO (operand) + 3]); - break; - - default: - fprintf (file, "%s", picochip_regnames[REGNO (operand)]); - } - break; - - case CONST_INT: - /* A range of letters can be used to format integers. The - letters Q/H/S are used to divide the constant by the width of - QI/HI/SI mode integers in bytes. The U/L modifiers are used - to obtain the upper and lower 16-bits of a 32-bit - constant. Where possible, signed numbers are used, since - signed representations of numbers may be more compact (e.g., - 65535 can be represented as -1, which fits into a small - constant, whereas 65535 requires a large constant). */ - switch (letter) - { - case 'Q': - fprintf (file, "%ld", INTVAL (operand)); - break; - - case 'H': - fprintf (file, "%ld", INTVAL (operand) / 2); - break; - - case 'S': - fprintf (file, "%ld", INTVAL (operand) / 4); - break; - - case 'P': - fprintf (file, "%d", exact_log2 (INTVAL(operand))); - break; - - case 'U': - fprintf (file, "%hi", (short) ((INTVAL (operand) >> 16) & 0xFFFF)); - break; - - case 'L': - fprintf (file, "%hi", (short) (INTVAL (operand) & 0xFFFF)); - break; - - default: - fprintf (file, "%ld", INTVAL (operand)); - break; - } - break; - - case CONST_DOUBLE: - { - long val; - REAL_VALUE_TYPE rv; - - if (GET_MODE (operand) != SFmode) - fatal_insn ("Unknown mode in print_operand (CONST_DOUBLE) :", - operand); - REAL_VALUE_FROM_CONST_DOUBLE (rv, operand); - REAL_VALUE_TO_TARGET_SINGLE (rv, val); - - switch (letter) - { - case 'U': - fprintf (file, "%hi", (short) ((val >> 16) & 0xFFFF)); - break; - - case 'L': - fprintf (file, "%hi", (short) (val & 0xFFFF)); - break; - } - - break; - - } - - /* Output a symbol. The output format must match that of - picochip_output_label. */ - case SYMBOL_REF: - /* Ensure that the symbol is marked as referenced. Gcc can - occasionally omit the function bodies when it believes them - to be unreferenced. */ - if (SYMBOL_REF_DECL (operand)) - mark_decl_referenced (SYMBOL_REF_DECL (operand)); - fprintf (file, "&"); - assemble_name (file, XSTR (operand, 0)); - break; - - case LABEL_REF: - /* This format must match that of picochip_output_label. */ - fprintf (file, "&"); - output_asm_label (operand); - break; - - case MEM: - { - rtx addr = XEXP (operand, 0); - - switch (letter) - { - case 'o': - if (PLUS != GET_CODE (addr)) - fatal_insn ("Bad address, not (reg+disp):", addr); - else - picochip_print_operand (file, XEXP (addr, 1), 0); - break; - - case 'M': - /* Output a memory address in byte mode notation (i.e., the - constant address (if any) is the actual byte address. */ - picochip_print_memory_address (file, operand, QImode); - break; - - /* Output a constant offset of the given mode (i.e., divide - the constant by the number of units in the mode to get the - constant). */ - case 'Q': - picochip_print_memory_address (file, operand, QImode); - break; - - case 'H': - picochip_print_memory_address (file, operand, HImode); - break; - - case 'S': - picochip_print_memory_address (file, operand, SImode); - break; - - case 'F': - picochip_print_memory_address (file, operand, SFmode); - break; - - case 'b': - if (PLUS != GET_CODE (addr)) - fatal_insn ("Bad address, not (reg+disp):", addr); - else - picochip_print_operand (file, XEXP (addr, 0), 0); - break; - - /* When the mem operand is (reg + big offset) which cannot - be represented in an instruction as operand, the compiler - automatically generates the instruction to put in (reg + - big offset) into another register. In such cases, it - returns '0' as the character. This needs to be handled - as well. */ - case 0: - case 'r': - if (REG != GET_CODE (addr)) - fatal_insn ("Bad address, not register:", addr); - else - picochip_print_operand (file, addr, 0); - break; - - default: - fprintf (file, "Unknown mem operand - letter %c ", - (char) (letter)); - print_rtl (file, operand); - } - - break; - } - - case CONST: - { - rtx const_exp = XEXP (operand, 0); - - /* Handle constant offsets to symbol references. */ - if (PLUS == GET_CODE (const_exp) && - SYMBOL_REF == GET_CODE (XEXP (const_exp, 0)) && - CONST_INT == GET_CODE (XEXP (const_exp, 1))) - { - - picochip_print_operand (file, XEXP (const_exp, 0), 0); - if (INTVAL (XEXP (const_exp, 1)) >= 0) - fprintf (file, "+"); - /* else use the - from the operand (i.e., AP-2)) */ - - picochip_print_operand (file, XEXP (const_exp, 1), letter); - - } - } - break; - - - case PLUS: - { - /* PLUS expressions are of the form (base + offset). Different - options (analagous to those of memory PLUS expressions) are used - to extract the base and offset components. */ - - switch (letter) - { - case 'b': - picochip_print_operand (file, XEXP (operand, 0), 0); - break; - - case 'o': - picochip_print_operand (file, XEXP (operand, 1), 0); - break; - - default: - - /* If the expression is composed entirely of constants, - evaluate the result. This should only occur with the - picoChip specific comms instructions, which are emitted as - base+offset expressions. */ - if (CONST_INT == GET_CODE (XEXP (operand, 0)) && - CONST_INT == GET_CODE (XEXP (operand, 1))) - { - HOST_WIDE_INT result = (XINT (XEXP (operand, 0), 0) + - XINT (XEXP (operand, 1), 0)); - fprintf (file, "%ld", result); - } - else - { - fprintf (file, "("); - picochip_print_operand (file, XEXP (operand, 0), 0); - fprintf (file, "+"); - picochip_print_operand (file, XEXP (operand, 1), 0); - fprintf (file, ")"); - } - } - - break; - } - - /* Comparison operations. */ - case NE: - case EQ: - case GE: - case GEU: - case LT: - case LTU: - case LE: - case LEU: - case GT: - case GTU: - picochip_print_comparison (file, operand, letter); - return; - - default: - fprintf (stderr, "Unknown operand encountered in %s\n", __FUNCTION__); - print_rtl (file, operand); - break; - - } - -} - -/* Output an operand address */ -void -picochip_print_operand_address (FILE * file, rtx operand) -{ - - switch (GET_CODE (operand)) - { - - case SYMBOL_REF: - /* This format must match that of picochip_output_label. */ - assemble_name (file, XSTR (operand, 0)); - break; - - case CODE_LABEL: - /* Note this format must match that of picochip_output_label. */ - fprintf (file, "_L%d", XINT (operand, 5)); - break; - - case MEM: - /* Pass on to a specialised memory address generator. */ - picochip_print_memory_address (file, operand, GET_MODE (operand)); - break; - - default: - gcc_unreachable(); - - } - -} - - -/* Scheduling functions. */ - -/* Save some of the contents of recog_data. */ -static void -picochip_save_recog_data (void) -{ - picochip_saved_which_alternative = which_alternative; - memcpy (&picochip_saved_recog_data, &recog_data, - sizeof (struct recog_data_d)); -} - -/* Restore some of the contents of global variable recog_data. */ -static void -picochip_restore_recog_data (void) -{ - which_alternative = picochip_saved_which_alternative; - memcpy (&recog_data, &picochip_saved_recog_data, - sizeof (struct recog_data_d)); -} - -/* Ensure that no var tracking notes are emitted in the middle of a - three-instruction bundle. */ -static void -reorder_var_tracking_notes (void) -{ - basic_block bb; - - FOR_EACH_BB_FN (bb, cfun) - { - rtx_insn *insn, *next, *last_insn = NULL; - rtx_insn *queue = NULL; - - /* Iterate through the bb and find the last non-debug insn */ - for (insn = BB_HEAD (bb); insn != NEXT_INSN(BB_END (bb)); insn = NEXT_INSN(insn)) - { - if (NONDEBUG_INSN_P(insn)) - last_insn = insn; - } - - /* In all normal cases, queue up notes and emit them just before a TImode - instruction. For the last instruction, emit the queued notes just after - the last instruction. */ - for (insn = BB_HEAD (bb); insn != NEXT_INSN(BB_END (bb)); insn = next) - { - next = NEXT_INSN (insn); - - if (insn == last_insn) - { - while (queue) - { - rtx_insn *next_queue = PREV_INSN (queue); - SET_PREV_INSN (NEXT_INSN(insn)) = queue; - SET_NEXT_INSN(queue) = NEXT_INSN(insn); - SET_PREV_INSN(queue) = insn; - SET_NEXT_INSN(insn) = queue; - queue = next_queue; - } - /* There is no more to do for this bb. break*/ - break; - } - else if (NONDEBUG_INSN_P (insn)) - { - /* Emit queued up notes before the first instruction of a bundle. */ - if (GET_MODE (insn) == TImode) - { - while (queue) - { - rtx_insn *next_queue = PREV_INSN (queue); - SET_NEXT_INSN (PREV_INSN(insn)) = queue; - SET_PREV_INSN (queue) = PREV_INSN(insn); - SET_PREV_INSN (insn) = queue; - SET_NEXT_INSN (queue) = insn; - queue = next_queue; - } - } - } - else if (NOTE_P (insn)) - { - rtx_insn *prev = PREV_INSN (insn); - SET_PREV_INSN (next) = prev; - SET_NEXT_INSN (prev) = next; - /* Ignore call_arg notes. They are expected to be just after the - call insn. If the call is start of a long VLIW, labels are - emitted in the middle of a VLIW, which our assembler can not - handle. */ - if (NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION) - { - SET_PREV_INSN (insn) = queue; - queue = insn; - } - } - } - /* Make sure we are not dropping debug instructions.*/ - gcc_assert (queue == NULL_RTX); - } -} - -/* Perform machine dependent operations on the rtl chain INSNS. */ -void -picochip_reorg (void) -{ - rtx_insn *insn, *insn1, *vliw_start = NULL; - int vliw_insn_location = 0; - - /* We are freeing block_for_insn in the toplev to keep compatibility - with old MDEP_REORGS that are not CFG based. Recompute it now. */ - compute_bb_for_insn (); - - if (optimize == 0) - split_all_insns (); - - if (picochip_schedule_type != DFA_TYPE_NONE) - { - timevar_push (TV_SCHED2); - - /* Process the instruction list, computing the sizes of each - instruction, and consequently branch distances. This can - result in some branches becoming short enough to be treated - as a real branch instruction, rather than an assembly branch - macro which may expand into multiple instructions. The - benefit of shortening branches is that real branch - instructions can be properly DFA scheduled, whereas macro - branches cannot. */ - shorten_branches (get_insns ()); - - /* Do control and data sched analysis again, - and write some more of the results to dump file. */ - - split_all_insns (); - - schedule_ebbs (); - - timevar_pop (TV_SCHED2); - - ggc_collect (); - - if (picochip_schedule_type == DFA_TYPE_SPEED) - { - /* Whenever a VLIW packet is generated, all instructions in - that packet must appear to come from the same source - location. The following code finds all the VLIW packets, - and tags their instructions with the location of the first - instruction from the packet. Clearly this will result in - strange behaviour when debugging the code, but since - debugging and optimisation are being used in conjunction, - strange behaviour is certain to occur anyway. */ - /* Slight bit of change. If the vliw set contains a branch - or call instruction, we pick its location.*/ - for (insn = get_insns (); insn; insn = next_real_insn (insn)) - { - - /* If this is the first instruction in the VLIW packet, - extract its location. */ - if (GET_MODE (insn) == TImode) - { - vliw_start = insn; - vliw_insn_location = INSN_LOCATION (insn); - } - if (JUMP_P (insn) || CALL_P(insn)) - { - vliw_insn_location = INSN_LOCATION (insn); - for (insn1 = vliw_start; insn1 != insn ; insn1 = next_real_insn (insn1)) - INSN_LOCATION (insn1) = vliw_insn_location; - } - /* Tag subsequent instructions with the same location. */ - INSN_LOCATION (insn) = vliw_insn_location; - } - } - - } - - /* Locate the note marking the end of the function's prologue. If - the note appears in the middle of a VLIW packet, move the note to - the end. This avoids unpleasant consequences such as trying to - emit prologue markers (e.g., .loc/.file directives) in the middle - of VLIW packets. */ - if (picochip_schedule_type == DFA_TYPE_SPEED) - { - rtx_insn *prologue_end_note = NULL; - rtx_insn *last_insn_in_packet = NULL; - - for (insn = get_insns (); insn; insn = next_insn (insn)) - { - /* The prologue end must be moved to the end of the VLIW packet. */ - if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END) - { - prologue_end_note = insn; - break; - } - } - - /* Find the last instruction in this packet. */ - for (insn = prologue_end_note; insn; insn = next_real_insn (insn)) - { - if (GET_MODE (insn) == TImode) - break; - else - last_insn_in_packet = insn; - } - - if (last_insn_in_packet != NULL) - { - rtx tmp_note - = emit_note_after ((enum insn_note) NOTE_KIND (prologue_end_note), - last_insn_in_packet); - memcpy(&NOTE_DATA (tmp_note), &NOTE_DATA(prologue_end_note), sizeof(NOTE_DATA(prologue_end_note))); - delete_insn (prologue_end_note); - } - } - - if (flag_var_tracking) - { - timevar_push (TV_VAR_TRACKING); - variable_tracking_main (); - /* We also have to deal with variable tracking notes in the - middle of VLIW packets. */ - reorder_var_tracking_notes(); - timevar_pop (TV_VAR_TRACKING); - } -} - -/* Return the ALU character identifier for the current - instruction. This will be 0 or 1. */ -static char -picochip_get_vliw_alu_id (void) -{ - int attr_type = 0; - - /* Always use ALU 0 if VLIW scheduling is disabled. */ - if (picochip_schedule_type != DFA_TYPE_SPEED) - return '0'; - - /* Get the attribute type of the instruction. Note that this can - ruin the contents of recog_data, so save/restore around the - call. */ - picochip_save_recog_data (); - attr_type = get_attr_type (picochip_current_prescan_insn); - picochip_restore_recog_data (); - - if (picochip_current_vliw_state.contains_pico_alu_insn) - { - - /* If this a picoAlu insn? If it is, then stuff it into ALU 0, - else it must be the other ALU (either basic or nonCc) - instruction which goes into 1. */ - if (attr_type == TYPE_PICOALU) - return '0'; - else - return '1'; - - } - else if (picochip_current_vliw_state.contains_non_cc_alu_insn) - { - /* Is this the non CC instruction? If it is, then stuff it into - ALU 1, else it must be a picoAlu or basicAlu, in which case - it goes into ALU 0. */ - if (attr_type == TYPE_NONCCALU) - return '1'; - else - return '0'; - } - else - { - /* No picoAlu/nonCc instructions in use, so purely dependent upon - whether an ALU instruction has already been scheduled in this - cycle. */ - switch (picochip_current_vliw_state.num_alu_insns_so_far) - { - case 0: - picochip_current_vliw_state.num_alu_insns_so_far++; - return '0'; - - case 1: - picochip_current_vliw_state.num_alu_insns_so_far++; - return '1'; - - default: - internal_error ("too many ALU instructions emitted (%d)", - picochip_current_vliw_state.num_alu_insns_so_far); - return 'X'; - } - } - -} - -/* Reset any information about the current VLIW packing status. */ -static void -picochip_reset_vliw (rtx_insn *insn) -{ - rtx_insn *local_insn = insn; - - /* Nothing to do if VLIW scheduling isn't being used. */ - if (picochip_schedule_type != DFA_TYPE_SPEED) - return; - - if (TARGET_DEBUG) - printf ("%s on insn %d\n", __FUNCTION__, INSN_UID (insn)); - - /* Reset. */ - picochip_current_vliw_state.contains_pico_alu_insn = 0; - picochip_current_vliw_state.contains_non_cc_alu_insn = 0; - picochip_current_vliw_state.num_alu_insns_so_far = 0; - picochip_current_vliw_state.num_cfi_labels_deferred = 0; - picochip_current_vliw_state.lm_label_name[0] = 0; - picochip_current_vliw_state.num_insns_in_packet = 0; - - /* Read through the VLIW packet, classifying the instructions where - appropriate. */ - local_insn = insn; - do - { - if (NOTE_P (local_insn) || DEBUG_INSN_P(local_insn)) - { - local_insn = NEXT_INSN (local_insn); - continue; - } - else if (!INSN_P (local_insn)) - break; - else - { - /* It is an instruction, but is it ours? */ - if (INSN_CODE (local_insn) != -1) - { - int attr_type = 0; - - picochip_current_vliw_state.num_insns_in_packet += 1; - - /* Is it a picoAlu or nonCcAlu instruction? Note that the - get_attr_type function can overwrite the values in - the recog_data global, hence this is saved and - restored around the call. Not doing so results in - asm_output_opcode being called with a different - instruction to final_prescan_insn, which is fatal. */ - picochip_save_recog_data (); - attr_type = get_attr_type (local_insn); - picochip_restore_recog_data (); - - if (attr_type == TYPE_PICOALU) - picochip_current_vliw_state.contains_pico_alu_insn = 1; - if (attr_type == TYPE_NONCCALU) - picochip_current_vliw_state.contains_non_cc_alu_insn = 1; - - } - } - - /* Get the next instruction. */ - local_insn = NEXT_INSN (local_insn); - - /* Keep going while the next instruction is part of the same - VLIW packet (i.e., its a valid instruction and doesn't mark - the start of a new VLIW packet. */ - } - while (local_insn && - (GET_MODE (local_insn) != TImode) && (INSN_CODE (local_insn) != -1)); - -} - -int -picochip_sched_reorder (FILE * file, int verbose, - rtx_insn ** ready ATTRIBUTE_UNUSED, - int *n_readyp ATTRIBUTE_UNUSED, int clock) -{ - - if (verbose > 0) - fprintf (file, ";;\tClock %d\n", clock); - - return picochip_sched_issue_rate (); - -} - -int -picochip_sched_lookahead (void) -{ - /* It should always be enough to lookahead by 2 insns. Only slot0/1 could - have a conflict. */ - return 2; -} - -int -picochip_sched_issue_rate (void) -{ - return 3; -} - -/* Adjust the scheduling cost between the two given instructions, - which have the given dependency. */ -int -picochip_sched_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, - int cost) -{ - - if (TARGET_DEBUG) - { - printf ("Sched Adjust Cost: %d->%d is %d\n", - INSN_UID (insn), INSN_UID (dep_insn), cost); - - printf (" Dependency type:"); - switch (REG_NOTE_KIND (link)) - { - case 0: - printf ("Data\n"); - break; - case REG_DEP_ANTI: - printf ("ANTI\n"); - break; - case REG_DEP_OUTPUT: - printf ("OUTPUT\n"); - break; - default: - printf ("Unknown (%d)\n", REG_NOTE_KIND (link)); - } - } - - /* Anti-dependencies are used to enforce the ordering between a - * branch, and any subsequent instructions. For example: - * - * BNE someLabel - * ADD.0 r0,r1,r2 - * - * The ADD instruction must execute after the branch, and this is - * enforced using an anti-dependency. Unfortunately, VLIW machines - * are happy to execute anti-dependent instructions in the same - * cycle, which then results in a schedule like the following being - * created: - * - * BNE someLabel \ ADD.0 r0,r1,r2 - * - * The instruction which would normally be conditionally executed - * depending upon the outcome of the branch, is now unconditionally - * executed every time. To prevent this happening, any - * anti-dependencies between a branch and another instruction are - * promoted to become real dependencies. - */ - if ((JUMP_P (dep_insn) || CALL_P(dep_insn)) && REG_NOTE_KIND (link) == REG_DEP_ANTI) - { - - if (TARGET_DEBUG) - printf ("Promoting anti-dependency %d->%d to a true-dependency\n", - INSN_UID (insn), INSN_UID (dep_insn)); - - return 1; - } - - return cost; - -} - -/* Return the minimum of the two values */ -static int -minimum (int a, int b) -{ - if (a < b) - return a; - if (b < a) - return b; - /* I dont expect to get to this function with a==b.*/ - gcc_unreachable(); -} - - -/* This function checks if the memory of the two stores are just off by 2 bytes. - It returns the lower memory operand's index.*/ - -static int -memory_just_off (rtx opnd1, rtx opnd2) -{ - int offset1 = 0, offset2 = 0; - int reg1, reg2; - - if (GET_CODE(XEXP(opnd1, 0)) == PLUS && GET_CODE(XEXP(XEXP(opnd1, 0),1)) == CONST_INT) - { - offset1 = INTVAL(XEXP(XEXP(opnd1, 0), 1)); - reg1 = REGNO(XEXP(XEXP(opnd1, 0), 0)); - } - else - { - reg1 = REGNO(XEXP(opnd1, 0)); - } - if (GET_CODE(XEXP(opnd2, 0)) == PLUS && GET_CODE(XEXP(XEXP(opnd2, 0), 1)) == CONST_INT) - { - offset2 = INTVAL(XEXP(XEXP(opnd2, 0), 1)); - reg2 = REGNO(XEXP(XEXP(opnd2, 0), 0)); - } - else - { - reg2 = REGNO(XEXP(opnd2, 0)); - } - - /* Peepholing 2 STW/LDWs has the restriction that the resulting STL/LDL's address - should be 4 byte aligned. We can currently guarantee that only if the base - address is FP(R13) and the offset is aligned. */ - - if (reg1 == reg2 && reg1 == 13 && abs(offset1-offset2) == 2 && minimum(offset1, offset2) % 4 == 0) - return (minimum(offset1, offset2) == offset1) ? 1:2; - - return 0; -} - -static int -registers_just_off (rtx opnd1, rtx opnd2) -{ - int reg1, reg2; - reg1 = REGNO(opnd1); - reg2 = REGNO(opnd2); - if (abs(reg1-reg2) == 1 && minimum(reg1, reg2) % 2 == 0) - return (minimum(reg1, reg2) == reg1)?1:2; - return 0; -} - -/* Check to see if the two LDWs can be peepholed together into a LDL - They can be if the registers getting loaded into are contiguous - and the memory addresses are contiguous as well. - for eg. - LDW r2,[r11]x - LDW r3,[r11]x+1 - can be merged together into - LDL r[3:2],[r11] - - NOTE: - 1. The LDWs themselves only guarantee that r11 will be a 2-byte - aligned address. Only FP can be assumed to be 4 byte aligned. - 2. The progression of addresses and the register numbers should - be similar. For eg., if you swap r2 and r3 in the above instructions, - the resultant pair cannot be merged. - -*/ -bool -ok_to_peephole_ldw(rtx opnd0, rtx opnd1, rtx opnd2, rtx opnd3) -{ - int memtest=0,regtest=0; - regtest = registers_just_off(opnd1,opnd3); - if (regtest == 0) - return false; - - memtest = memory_just_off(opnd0,opnd2); - if (memtest == 0) - return false; - - if (regtest == memtest) - { - return true; - } - return false; -} - -/* Similar to LDW peephole */ -bool -ok_to_peephole_stw(rtx opnd0, rtx opnd1, rtx opnd2, rtx opnd3) -{ - int memtest=0,regtest=0; - regtest = registers_just_off(opnd1,opnd3); - if (regtest == 0) - return false; - - memtest = memory_just_off(opnd0,opnd2); - if (memtest == 0) - return false; - - if (regtest == memtest) - { - return true; - } - return false; -} - - -/* Generate a SImode register with the register number that is the smaller of the two */ -rtx -gen_min_reg(rtx opnd1,rtx opnd2) -{ - return gen_rtx_REG (SImode, minimum(REGNO(opnd1),REGNO(opnd2))); -} - -/* Generate a SImode memory with the address that is the smaller of the two */ -rtx -gen_SImode_mem(rtx opnd1,rtx opnd2) -{ - int offset1=0,offset2=0; - rtx reg; - rtx address; - if (GET_CODE(XEXP(opnd1,0)) == PLUS && GET_CODE(XEXP(XEXP(opnd1,0),1)) == CONST_INT) - { - offset1 = INTVAL(XEXP(XEXP(opnd1,0),1)); - reg = XEXP(XEXP(opnd1,0),0); - } - else - { - reg = XEXP(opnd1,0); - } - if (GET_CODE(XEXP(opnd2,0)) == PLUS && GET_CODE(XEXP(XEXP(opnd2,0),1)) == CONST_INT) - { - offset2 = INTVAL(XEXP(XEXP(opnd2,0),1)); - } - address = gen_rtx_PLUS (HImode, reg, GEN_INT(minimum(offset1,offset2))); - return gen_rtx_MEM(SImode,address); -} - -bool -picochip_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, - int opno ATTRIBUTE_UNUSED, int* total, bool speed) -{ - - int localTotal = 0; - - if (!speed) - { - /* Need to penalize immediates that need to be encoded as long constants.*/ - if (code == CONST_INT && !(INTVAL (x) >= 0 && INTVAL (x) < 16)) - { - *total = COSTS_N_INSNS(1); - return true; - } - } - switch (code) - { - case SYMBOL_REF: - case LABEL_REF: - *total = COSTS_N_INSNS (outer_code != MEM); - return true; - break; - - case IF_THEN_ELSE: - /* if_then_else come out of cbranch instructions. It will get split into - a condition code generating subtraction and a branch */ - *total = COSTS_N_INSNS (2); - return true; - break; - - case AND: - case IOR: - case XOR: - if (GET_MODE(x) == SImode) - *total = COSTS_N_INSNS (2); - if (GET_MODE(x) == DImode) - *total = COSTS_N_INSNS (4); - return false; - - case MEM: - /* Byte Memory access on a NO_BYTE_ACCESS machine would be expensive */ - if (GET_MODE(x) == QImode && !TARGET_HAS_BYTE_ACCESS) - *total = COSTS_N_INSNS (10); - - /* 64-bit accesses have to be done through 2 32-bit access */ - if (GET_MODE(x) == DImode) - *total = COSTS_N_INSNS (2); - return false; - break; - - case ASHIFTRT: - - /* SImode shifts are expensive */ - if (GET_MODE(x) == SImode) - *total = COSTS_N_INSNS (10); - - /* Register shift by constant is cheap. */ - if ((GET_MODE(x) == QImode || GET_MODE(x) == HImode) - && GET_CODE(XEXP(x, 0)) == REG - && GET_CODE(XEXP(x, 1)) == CONST_INT) - *total = COSTS_N_INSNS (1); - else - *total = COSTS_N_INSNS (4); - return false; - break; - - case DIV: - case MOD: - - /* Divisions are more expensive than the default 7*/ - if (GET_MODE(x) == SImode) - *total = COSTS_N_INSNS (20); - else - *total = COSTS_N_INSNS (12); - return false; - break; - - case MULT: - /* Look for the simple cases of multiplying register*register or - register*constant. */ - if ((GET_MODE(x) == QImode || GET_MODE(x) == HImode) - && ((GET_CODE(XEXP(x, 0)) == REG - && (GET_CODE(XEXP(x, 1)) == REG || GET_CODE(XEXP(x,1)) == CONST_INT)) - || (GET_CODE(XEXP(x, 0)) == ZERO_EXTEND - && GET_CODE(XEXP(XEXP(x, 0),0)) == REG - && GET_CODE(XEXP(x, 1)) == ZERO_EXTEND - && GET_CODE(XEXP(XEXP(x, 1),0)) == REG))) - { - - /* When optimising for size, multiplication by constant - should be discouraged slightly over multiplication by a - register. */ - if (picochip_has_mac_unit) - { - /* Single cycle multiplication, but the result must be - loaded back into a general register afterwards. */ - *total = COSTS_N_INSNS(2); - return true; - } - else if (picochip_has_mul_unit) - { - /* Single cycle multiplication. */ - *total = COSTS_N_INSNS(1); - return true; - } - /* Else no multiply available. Use default cost. */ - - } - break; - - default: - /* Do nothing. */ - break; - } - - if (localTotal != 0) - { - *total = localTotal; - return true; - } - else - { - return false; - } - -} - -void -picochip_final_prescan_insn (rtx_insn *insn, rtx * opvec ATTRIBUTE_UNUSED, - int num_operands ATTRIBUTE_UNUSED) -{ - rtx_insn *local_insn; - - picochip_current_prescan_insn = insn; - - if (TARGET_DEBUG) - printf ("Final prescan on INSN %d with mode %s\n", - INSN_UID (insn), GET_MODE_NAME (GET_MODE (insn))); - - /* If this is the start of a new instruction cycle, or no scheduling - is used, then reset the VLIW status. */ - if (GET_MODE (insn) == TImode || !picochip_schedule_type == DFA_TYPE_SPEED) - picochip_reset_vliw (insn); - - /* No VLIW scheduling occurred, so don't go any further. */ - if (picochip_schedule_type != DFA_TYPE_SPEED) - return; - - /* Look for the next printable instruction. This loop terminates on - any recognisable instruction, and on any unrecognisable - instruction with TImode. */ - local_insn = insn; - for (local_insn = NEXT_INSN (local_insn); local_insn; - local_insn = NEXT_INSN (local_insn)) - { - if (NOTE_P (local_insn) || DEBUG_INSN_P(local_insn)) - continue; - else if (!INSN_P (local_insn)) - break; - else if (GET_MODE (local_insn) == TImode - || INSN_CODE (local_insn) != -1) - break; - } - - /* Set the continuation flag if the next instruction can be packed - with the current instruction (i.e., the next instruction is - valid, and isn't the start of a new cycle). */ - picochip_vliw_continuation = (local_insn && NONDEBUG_INSN_P (local_insn) && - (GET_MODE (local_insn) != TImode)); - -} - -/* Builtin functions. */ -/* Given a builtin function taking 2 operands (i.e., target + source), - emit the RTL for the underlying instruction. */ -static rtx -picochip_expand_builtin_2op (enum insn_code icode, tree call, rtx target) -{ - tree arg0; - rtx op0, pat; - enum machine_mode tmode, mode0; - - /* Grab the incoming argument and emit its RTL. */ - arg0 = CALL_EXPR_ARG (call, 0); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - - /* Determine the modes of the instruction operands. */ - tmode = insn_data[icode].operand[0].mode; - mode0 = insn_data[icode].operand[1].mode; - - /* Ensure that the incoming argument RTL is in a register of the - correct mode. */ - if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - - /* If there isn't a suitable target, emit a target register. */ - if (target == 0 - || GET_MODE (target) != tmode - || !(*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); - - /* Emit and return the new instruction. */ - pat = GEN_FCN (icode) (target, op0); - if (!pat) - return 0; - emit_insn (pat); - - return target; - -} - -/* Given a builtin function taking 3 operands (i.e., target + two - source), emit the RTL for the underlying instruction. */ -static rtx -picochip_expand_builtin_3op (enum insn_code icode, tree call, rtx target) -{ - tree arg0, arg1; - rtx op0, op1, pat; - enum machine_mode tmode, mode0, mode1; - - /* Grab the function's arguments. */ - arg0 = CALL_EXPR_ARG (call, 0); - arg1 = CALL_EXPR_ARG (call, 1); - - /* Emit rtl sequences for the function arguments. */ - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL); - - /* Get the mode's of each of the instruction operands. */ - tmode = insn_data[icode].operand[0].mode; - mode0 = insn_data[icode].operand[1].mode; - mode1 = insn_data[icode].operand[2].mode; - - /* Ensure that each of the function argument rtl sequences are in a - register of the correct mode. */ - if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - if (!(*insn_data[icode].operand[2].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - - /* If no target has been given, create a register to use as the target. */ - if (target == 0 - || GET_MODE (target) != tmode - || !(*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); - - /* Emit and return the new instruction. */ - pat = GEN_FCN (icode) (target, op0, op1); - if (!pat) - return 0; - emit_insn (pat); - - return target; - -} - -/* Expand a builtin function which takes two arguments, and returns a void. */ -static rtx -picochip_expand_builtin_2opvoid (enum insn_code icode, tree call) -{ - tree arg0, arg1; - rtx op0, op1, pat; - enum machine_mode mode0, mode1; - - /* Grab the function's arguments. */ - arg0 = CALL_EXPR_ARG (call, 0); - arg1 = CALL_EXPR_ARG (call, 1); - - /* Emit rtl sequences for the function arguments. */ - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL); - - /* Get the mode's of each of the instruction operands. */ - mode0 = insn_data[icode].operand[0].mode; - mode1 = insn_data[icode].operand[1].mode; - - /* Ensure that each of the function argument rtl sequences are in a - register of the correct mode. */ - if (!(*insn_data[icode].operand[0].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - if (!(*insn_data[icode].operand[1].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - - /* Emit and return the new instruction. */ - pat = GEN_FCN (icode) (op0, op1); - if (!pat) - return 0; - emit_insn (pat); - - return NULL_RTX; - -} - -/* Expand an array get into the corresponding RTL. */ -static rtx -picochip_expand_array_get (tree call, rtx target) -{ - tree arg0, arg1, arg2; - rtx op0, op1, op2, pat; - - /* Grab the function's arguments. */ - arg0 = CALL_EXPR_ARG (call, 0); - arg1 = CALL_EXPR_ARG (call, 1); - arg2 = CALL_EXPR_ARG (call, 2) ; - - /* Emit rtl sequences for the function arguments. */ - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL); - op2 = expand_expr (arg2, NULL_RTX, VOIDmode, EXPAND_NORMAL); - - /* The second and third operands must be constant. Nothing else will - do. */ - if (CONST_INT != GET_CODE (op1)) - internal_error ("%s: Second source operand is not a constant", - __FUNCTION__); - if (CONST_INT != GET_CODE (op2)) - internal_error ("%s: Third source operand is not a constant", - __FUNCTION__); - - /* If no target has been given, create a register to use as the target. */ - if (target == 0 || GET_MODE (target) != SImode) - target = gen_reg_rtx (SImode); - - /* The first operand must be a HImode register or a constant. If it - isn't, force it into a HImode register. */ - if (GET_MODE (op0) != HImode || REG != GET_CODE (op0)) - op0 = copy_to_mode_reg (HImode, op0); - - - /* Emit and return the new instruction. */ - pat = gen_commsArrayGet (target, op0, op1, op2); - emit_insn (pat); - - return target; - -} - -/* Expand an array put into the corresponding RTL. */ -static rtx -picochip_expand_array_put (tree call, rtx target) -{ - tree arg0, arg1, arg2, arg3; - rtx op0, op1, op2, op3, pat; - - /* Grab the function's arguments. */ - arg0 = CALL_EXPR_ARG (call, 0); - arg1 = CALL_EXPR_ARG (call, 1); - arg2 = CALL_EXPR_ARG (call, 2); - arg3 = CALL_EXPR_ARG (call, 3); - - /* Emit rtl sequences for the function arguments. */ - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL); - op2 = expand_expr (arg2, NULL_RTX, VOIDmode, EXPAND_NORMAL); - op3 = expand_expr (arg3, NULL_RTX, VOIDmode, EXPAND_NORMAL); - - /* The first operand must be an SImode register. */ - if (GET_MODE (op0) != SImode || REG != GET_CODE (op0)) - op0 = copy_to_mode_reg (SImode, op0); - - /* The second (index) operand must be a HImode register, or a - constant. If it isn't, force it into a HImode register. */ - if (GET_MODE (op1) != HImode || REG != GET_CODE (op1)) - op1 = copy_to_mode_reg (HImode, op1); - - /* The remaining operands must be constant. Nothing else will do. */ - if (CONST_INT != GET_CODE (op2)) - internal_error ("%s: Third source operand is not a constant", - __FUNCTION__); - if (CONST_INT != GET_CODE (op3)) - internal_error ("%s: Fourth source operand is not a constant", - __FUNCTION__); - - /* Emit and return the new instruction. */ - pat = gen_commsArrayPut (op0, op1, op2, op3); - emit_insn (pat); - - return target; - -} - -/* Expand an array testport into the corresponding RTL. */ -static rtx -picochip_expand_array_testport (tree call, rtx target) -{ - tree arg0, arg1, arg2; - rtx op0, op1, op2, pat; - - /* Grab the function's arguments. */ - arg0 = CALL_EXPR_ARG (call, 0); - arg1 = CALL_EXPR_ARG (call, 1); - arg2 = CALL_EXPR_ARG (call, 2); - - /* Emit rtl sequences for the function arguments. */ - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL); - op2 = expand_expr (arg2, NULL_RTX, VOIDmode, EXPAND_NORMAL); - - /* The first operand must be a HImode register, or a constant. If it - isn't, force it into a HImode register. */ - if (GET_MODE (op0) != HImode || REG != GET_CODE (op0)) - op0 = copy_to_mode_reg (HImode, op0); - - /* The second and third operands must be constant. Nothing else will - do. */ - if (CONST_INT != GET_CODE (op1)) - internal_error ("%s: Second source operand is not a constant", - __FUNCTION__); - if (CONST_INT != GET_CODE (op2)) - internal_error ("%s: Third source operand is not a constant", - __FUNCTION__); - - /* If no target has been given, create a HImode register to use as - the target. */ - if (target == 0 || GET_MODE (target) != HImode) - target = gen_reg_rtx (HImode); - - /* Emit and return the new instruction. */ - pat = gen_commsArrayTestPort (target, op0, op1, op2); - emit_insn (pat); - - return target; - -} - -/* Generate a unique HALT instruction by giving the instruction a - unique integer. This integer makes no difference to the assembly - output (other than a comment indicating the supplied id), but the - presence of the unique integer prevents the compiler from combining - several different halt instructions into one instruction. This - means that each use of the halt instruction is unique, which in - turn means that assertions work as expected. */ -static rtx -picochip_generate_halt (void) -{ - static int currentId = 0; - rtx insns; - rtx id = GEN_INT (currentId); - currentId += 1; - - start_sequence(); - emit_insn (gen_halt (id)); - - /* A barrier is inserted to prevent the compiler from thinking that - it has to continue execution after the HALT.*/ - emit_barrier (); - - insns = get_insns(); - end_sequence(); - emit_insn (insns); - - return const0_rtx; -} - -/* Initialise the builtin functions. Start by initialising - descriptions of different types of functions (e.g., void fn(int), - int fn(void)), and then use these to define the builtins. */ -void -picochip_init_builtins (void) -{ - tree noreturn; - - tree int_ftype_int, int_ftype_int_int; - tree long_ftype_int, long_ftype_int_int_int; - tree void_ftype_int_long, int_ftype_int_int_int, - void_ftype_long_int_int_int; - tree void_ftype_void, unsigned_ftype_unsigned; - - /* void func (void) */ - void_ftype_void = build_function_type_list (void_type_node, NULL_TREE); - - /* int func (int) */ - int_ftype_int = build_function_type_list (integer_type_node, - integer_type_node, NULL_TREE); - - /* unsigned int func (unsigned int) */ - unsigned_ftype_unsigned - = build_function_type_list (unsigned_type_node, - unsigned_type_node, NULL_TREE); - - /* int func(int, int) */ - int_ftype_int_int - = build_function_type_list (integer_type_node, - integer_type_node, integer_type_node, - NULL_TREE); - - /* long func(int) */ - long_ftype_int = build_function_type_list (long_integer_type_node, - integer_type_node, NULL_TREE); - - /* long func(int, int, int) */ - long_ftype_int_int_int - = build_function_type_list (long_integer_type_node, - integer_type_node, integer_type_node, - integer_type_node, NULL_TREE); - - /* int func(int, int, int) */ - int_ftype_int_int_int - = build_function_type_list (integer_type_node, - integer_type_node, integer_type_node, - integer_type_node, NULL_TREE); - - /* void func(int, long) */ - void_ftype_int_long - = build_function_type_list (void_type_node, - integer_type_node, long_integer_type_node, - NULL_TREE); - - /* void func(long, int, int, int) */ - void_ftype_long_int_int_int - = build_function_type_list (void_type_node, - long_integer_type_node, integer_type_node, - integer_type_node, integer_type_node, - NULL_TREE); - - /* Initialise the sign-bit-count function. */ - add_builtin_function ("__builtin_sbc", int_ftype_int, - PICOCHIP_BUILTIN_SBC, BUILT_IN_MD, NULL, - NULL_TREE); - add_builtin_function ("picoSbc", int_ftype_int, PICOCHIP_BUILTIN_SBC, - BUILT_IN_MD, NULL, NULL_TREE); - - /* Initialise the bit reverse function. */ - add_builtin_function ("__builtin_brev", unsigned_ftype_unsigned, - PICOCHIP_BUILTIN_BREV, BUILT_IN_MD, NULL, - NULL_TREE); - add_builtin_function ("picoBrev", unsigned_ftype_unsigned, - PICOCHIP_BUILTIN_BREV, BUILT_IN_MD, NULL, - NULL_TREE); - - /* Initialise the byte swap function. */ - add_builtin_function ("__builtin_byteswap", unsigned_ftype_unsigned, - PICOCHIP_BUILTIN_BYTESWAP, BUILT_IN_MD, NULL, - NULL_TREE); - add_builtin_function ("picoByteSwap", unsigned_ftype_unsigned, - PICOCHIP_BUILTIN_BYTESWAP, BUILT_IN_MD, NULL, - NULL_TREE); - - /* Initialise the ASRI function (note that while this can be coded - using a signed shift in C, extra scratch registers are required, - which we avoid by having a direct builtin to map to the - instruction). */ - add_builtin_function ("__builtin_asri", int_ftype_int_int, - PICOCHIP_BUILTIN_ASRI, BUILT_IN_MD, NULL, - NULL_TREE); - - /* Initialise saturating addition. */ - add_builtin_function ("__builtin_adds", int_ftype_int_int, - PICOCHIP_BUILTIN_ADDS, BUILT_IN_MD, NULL, - NULL_TREE); - add_builtin_function ("picoAdds", int_ftype_int_int, - PICOCHIP_BUILTIN_ADDS, BUILT_IN_MD, NULL, - NULL_TREE); - - /* Initialise saturating subtraction. */ - add_builtin_function ("__builtin_subs", int_ftype_int_int, - PICOCHIP_BUILTIN_SUBS, BUILT_IN_MD, NULL, - NULL_TREE); - add_builtin_function ("picoSubs", int_ftype_int_int, - PICOCHIP_BUILTIN_SUBS, BUILT_IN_MD, NULL, - NULL_TREE); - - /* Scalar comms builtins. */ - add_builtin_function ("__builtin_get", long_ftype_int, - PICOCHIP_BUILTIN_GET, BUILT_IN_MD, NULL, - NULL_TREE); - add_builtin_function ("__builtin_put", void_ftype_int_long, - PICOCHIP_BUILTIN_PUT, BUILT_IN_MD, NULL, - NULL_TREE); - add_builtin_function ("__builtin_testport", int_ftype_int, - PICOCHIP_BUILTIN_TESTPORT, BUILT_IN_MD, NULL, - NULL_TREE); - - /* Array comms builtins. */ - add_builtin_function ("__builtin_put_array", - void_ftype_long_int_int_int, - PICOCHIP_BUILTIN_PUT_ARRAY, BUILT_IN_MD, NULL, - NULL_TREE); - add_builtin_function ("__builtin_get_array", long_ftype_int_int_int, - PICOCHIP_BUILTIN_GET_ARRAY, BUILT_IN_MD, NULL, - NULL_TREE); - add_builtin_function ("__builtin_testport_array", - int_ftype_int_int_int, - PICOCHIP_BUILTIN_TESTPORT_ARRAY, BUILT_IN_MD, - NULL, NULL_TREE); - - /* Halt instruction. Note that the builtin function is marked as - having the attribute `noreturn' so that the compiler realises - that the halt stops the program dead. */ - noreturn = tree_cons (get_identifier ("noreturn"), NULL, NULL); - add_builtin_function ("__builtin_halt", void_ftype_void, - PICOCHIP_BUILTIN_HALT, BUILT_IN_MD, NULL, - noreturn); - add_builtin_function ("picoHalt", void_ftype_void, - PICOCHIP_BUILTIN_HALT, BUILT_IN_MD, NULL, - noreturn); - -} - -/* Expand a call to a builtin function. */ -rtx -picochip_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED, - int ignore ATTRIBUTE_UNUSED) -{ - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - int fcode = DECL_FUNCTION_CODE (fndecl); - - switch (fcode) - { - case PICOCHIP_BUILTIN_ASRI: - return picochip_expand_builtin_3op (CODE_FOR_builtin_asri, exp, - target); - - case PICOCHIP_BUILTIN_ADDS: - return picochip_expand_builtin_3op (CODE_FOR_sataddhi3, exp, - target); - - case PICOCHIP_BUILTIN_SUBS: - return picochip_expand_builtin_3op (CODE_FOR_satsubhi3, exp, - target); - - case PICOCHIP_BUILTIN_SBC: - return picochip_expand_builtin_2op (CODE_FOR_sbc, exp, target); - - case PICOCHIP_BUILTIN_BREV: - return picochip_expand_builtin_2op (CODE_FOR_brev, exp, target); - - case PICOCHIP_BUILTIN_BYTESWAP: - return picochip_expand_builtin_2op (CODE_FOR_bswaphi2, exp, target); - - case PICOCHIP_BUILTIN_GET: - return picochip_expand_builtin_2op (CODE_FOR_commsGet, exp, target); - - case PICOCHIP_BUILTIN_PUT: - return picochip_expand_builtin_2opvoid (CODE_FOR_commsPut, exp); - - case PICOCHIP_BUILTIN_TESTPORT: - return picochip_expand_builtin_2op (CODE_FOR_commsTestPort, exp, - target); - - case PICOCHIP_BUILTIN_PUT_ARRAY: - return picochip_expand_array_put (exp, target); - - case PICOCHIP_BUILTIN_GET_ARRAY: - return picochip_expand_array_get (exp, target); - - case PICOCHIP_BUILTIN_TESTPORT_ARRAY: - return picochip_expand_array_testport (exp, target); - - case PICOCHIP_BUILTIN_HALT: - return picochip_generate_halt (); - - default: - gcc_unreachable(); - - } - - /* Should really do something sensible here. */ - return NULL_RTX; -} - -/* Emit warnings. */ -static void -picochip_warn_inefficient (const char *msg) -{ - if (TARGET_INEFFICIENT_WARNINGS) - warning (OPT_minefficient_warnings, - "%s (disable warning using -mno-inefficient-warnings)", msg); -} - -void -warn_of_byte_access (void) -{ - static int warned = 0; - - if (!warned) - { - picochip_warn_inefficient - ("byte access is synthesised - consider using MUL AE"); - warned = 1; - } - -} - -rtx -picochip_function_value (const_tree valtype, const_tree func, - bool outgoing ATTRIBUTE_UNUSED) -{ - enum machine_mode mode = TYPE_MODE (valtype); - int unsignedp = TYPE_UNSIGNED (valtype); - - /* Since we define PROMOTE_FUNCTION_RETURN, we must promote the mode - just as PROMOTE_MODE does. */ - mode = promote_function_mode (valtype, mode, &unsignedp, func, 1); - - return gen_rtx_REG (mode, 0); - -} - -/* Check that the value of the given mode will fit in the register of - the given mode. */ -int -picochip_hard_regno_mode_ok (int regno, enum machine_mode mode) -{ - - if (GET_MODE_CLASS (mode) == MODE_CC) - return regno == CC_REGNUM; - - /* If the CC register is being used, then only CC mode values are - allowed (which have already been tested). */ - if (regno == CC_REGNUM || regno == ACC_REGNUM) - return 0; - - /* Must be a valid register. */ - if (regno > 16) - return 0; - - /* Modes QI and HI may be placed in any register except the CC. */ - if (mode == QImode || mode == HImode) - return 1; - - /* DI must be in a quad register. */ - if (mode == DImode) - return (regno % 4 == 0); - - /* All other modes must be placed in a even numbered register. */ - return !(regno & 1); - -} - -/* Extract the lower and upper components of a constant value. */ - -rtx -picochip_get_low_const (rtx value) -{ - return gen_int_mode (INTVAL (value) & 0xFFFF, HImode); -} - -rtx -picochip_get_high_const (rtx value) -{ - /*return GEN_INT ((((INTVAL (value) >> 16) & 0xFFFF) ^ 0x8000) - 0x8000); */ - return gen_int_mode ((INTVAL (value) >> 16) & 0xFFFF, HImode); -} - - -/* Loading and storing QImode values to and from memory in a machine - without byte access requires might require a scratch - register. However, the scratch register might correspond to the - register in which the value is being loaded. To ensure that a - scratch register is supplied which is definitely different to the - output register, request a register pair. This effectively gives a - choice of two registers to choose from, so that we a guaranteed to - get at least one register which is different to the output - register. This trick is taken from the alpha implementation. */ -static reg_class_t -picochip_secondary_reload (bool in_p, - rtx x ATTRIBUTE_UNUSED, - reg_class_t cla ATTRIBUTE_UNUSED, - enum machine_mode mode, - secondary_reload_info *sri) -{ - if (mode == QImode && !TARGET_HAS_BYTE_ACCESS) - { - if (in_p == 0) - sri->icode = CODE_FOR_reload_outqi; - else - sri->icode = CODE_FOR_reload_inqi; - } - - /* We dont need to return a register class type when we need only a - scratch register. It realizes the scratch register type by looking - at the instruction definition for sri->icode. We only need to - return the register type when we need intermediaries for copies.*/ - return NO_REGS; -} - -/* Return true if the given memory operand can be aligned to a - word+offset memory reference (e.g., FP+3 can be converted into the - memory operand FP+2, with the offset 1). */ -int -picochip_alignable_memory_operand (rtx mem_operand, - enum machine_mode mode ATTRIBUTE_UNUSED) -{ - rtx address; - - /* Not a mem operand. Refuse immediately. */ - if (MEM != GET_CODE (mem_operand)) - return 0; - - address = XEXP (mem_operand, 0); - - /* Return true if a PLUS of the SP and a (valid) constant, or SP itself. */ - return ((PLUS == GET_CODE (address) && - REGNO (XEXP (address, 0)) == STACK_POINTER_REGNUM && - CONST_INT == GET_CODE (XEXP (address, 1)) && - picochip_const_ok_for_letter_p (INTVAL (XEXP (address, 1)), 'K')) - || (REG == GET_CODE (address) - && REGNO (address) == STACK_POINTER_REGNUM)); - -} - -/* Return true if the given memory reference is to a word aligned - address. Currently this means it must be either SP, or - SP+offset. We could replace this function with alignable - memory references in the above function?. */ -int -picochip_word_aligned_memory_reference (rtx operand) -{ - - - /* The address must be the SP register, or a constant, aligned - offset from SP which doesn't exceed the FP+offset - restrictions. */ - return ((PLUS == GET_CODE (operand) - && REGNO (XEXP (operand, 0)) == STACK_POINTER_REGNUM - && picochip_is_aligned (INTVAL (XEXP (operand, 1)), 16) - && picochip_const_ok_for_letter_p (INTVAL (XEXP (operand, 1)), - 'K')) - || (REG == GET_CODE (operand) - && REGNO (operand) == STACK_POINTER_REGNUM)); - -} - -/* Given an alignable memory location, convert the memory location - into a HI mode access, storing the new memory reference in - paligned_mem, and the number of bits by which to shift in pbitnum - (i.e., given a reference to FP+3, this creates an aligned reference - of FP+2, with an 8-bit shift). This code is a modification of that - found in the Alpha port. */ -void -picochip_get_hi_aligned_mem (rtx ref, rtx * paligned_mem, rtx * pbitnum) -{ - rtx base; - HOST_WIDE_INT offset = 0; - - gcc_assert (GET_CODE (ref) == MEM); - - if (reload_in_progress && !memory_address_p (GET_MODE (ref), XEXP (ref, 0))) - { - base = find_replacement (&XEXP (ref, 0)); - - gcc_assert(memory_address_p (GET_MODE (ref), base)); - } - else - { - base = XEXP (ref, 0); - } - - if (GET_CODE (base) == PLUS) - { - offset += INTVAL (XEXP (base, 1)); - base = XEXP (base, 0); - } - - *paligned_mem = widen_memory_access (ref, HImode, (offset & ~1) - offset); - - if (offset > 0) - { - if (TARGET_DEBUG) - { - printf - ("Found non-zero offset in get_hi_aligned_mem - check that the correct value is being used (as this functionality hasn't been exploited yet).\n"); - } - } - - *pbitnum = GEN_INT ((offset & 1) * 8); - -} - -/* Return true if the given operand is an absolute address in memory - (i.e., a symbolic offset). */ -int -picochip_absolute_memory_operand (rtx op, - enum machine_mode mode ATTRIBUTE_UNUSED) -{ - - if (MEM == GET_CODE (op)) - { - rtx address = XEXP (op, 0); - - /* Symbols are valid absolute addresses. */ - if (SYMBOL_REF == GET_CODE (address)) - return 1; - - /* Constant offsets to symbols are valid absolute addresses. */ - if (CONST == GET_CODE (address) && - PLUS == GET_CODE (XEXP (address, 0)) && - SYMBOL_REF == GET_CODE (XEXP (XEXP (address, 0), 0)) && - CONST_INT == GET_CODE (XEXP (XEXP (address, 0), 1))) - return 1; - - } - else - return 0; - - /* Symbols are valid absolute addresses. */ - if (SYMBOL_REF == GET_CODE (XEXP (op, 0))) - return 1; - - - return 0; - -} - -void -picochip_asm_named_section (const char *name, - unsigned int flags ATTRIBUTE_UNUSED, - tree decl ATTRIBUTE_UNUSED) -{ - fprintf (asm_out_file, ".section %s\n", name); -} - - -/* Check if we can make a conditional copy instruction. This is emitted as an - instruction to set the condition register, followed by an instruction which - uses the condition registers to perform the conditional move. */ -int -picochip_check_conditional_copy (rtx * operands) -{ - - rtx branch_op_0 = XEXP (operands[1], 0); - rtx branch_op_1 = XEXP (operands[1], 1); - - /* Only HI mode conditional moves are currently allowed. Can we add - SI mode moves? */ - if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE) - return 0; - - /* Is the comparison valid? Only allow operands which are registers - if they are HImode. SI mode comparisons against 0 could be - handled using logical operations (e.g., SIreg != 0 when low || - high). Need to find test cases to provoke this though (fixunssfdi - in libgcc does, but is complicated). */ - if (register_operand(branch_op_0, GET_MODE(branch_op_0)) && - GET_MODE(branch_op_0) != HImode) - return 0; - if (register_operand(branch_op_1, GET_MODE(branch_op_1)) && - GET_MODE(branch_op_1) != HImode) - return 0; - - return 1; - -} - - -static rtx -picochip_static_chain (const_tree ARG_UNUSED (fndecl), bool incoming_p) -{ - rtx addr; - if (incoming_p) - addr = arg_pointer_rtx; - else - addr = plus_constant (Pmode, stack_pointer_rtx, -2 * UNITS_PER_WORD); - return gen_frame_mem (Pmode, addr); -} diff --git a/gcc/config/picochip/picochip.h b/gcc/config/picochip/picochip.h deleted file mode 100644 index 1daf93c..0000000 --- a/gcc/config/picochip/picochip.h +++ /dev/null @@ -1,661 +0,0 @@ -/* Definitions of target machine for GNU compiler for picoChip - Copyright (C) 2001-2014 Free Software Foundation, Inc. - - Contributed by Picochip Ltd. (http://www.picochip.com) - Maintained by Daniel Towner (daniel.towner@picochip.com) and - Hariharan Sandanagobalane (hariharan@picochip.com). - -This file is part of GCC. - -GCC 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 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not, see -<http://www.gnu.org/licenses/>. */ - -/* Which type of DFA scheduling to use - schedule for speed (VLIW), or - schedule for space. When scheduling for space, attempt to schedule - into stall cycles, but don't pack instructions. */ - -enum picochip_dfa_type -{ - DFA_TYPE_NONE, - DFA_TYPE_SPACE, - DFA_TYPE_SPEED -}; - -extern enum picochip_dfa_type picochip_schedule_type; - -/* Controlling the Compilation Driver */ - -/* Pass through the save-temps command option. */ -#define LINK_SPEC " %{save-temps:--save-temps}" - -/* This is an embedded processor, and only supports a cut-down version of - * the standard C library. */ -#define LIB_SPEC "-lpicoC" - -/* The start file is automatically provided by the linker. */ -#define STARTFILE_SPEC "" - -/* Run-time Target Specification */ - -/* Define some additional pre-processor macros. */ -#define TARGET_CPU_CPP_BUILTINS() \ - do \ - { \ - builtin_define ("NO_TRAMPOLINES"); \ - builtin_define ("PICOCHIP"); \ - builtin_define ("__PICOCHIP__"); \ - } \ - while (0) - -/* Translate requests for particular AEs into their respective ISA - options. Note that byte access is enabled by default. */ -#define DRIVER_SELF_SPECS \ - "%{mae=ANY:-mmul-type=none -mno-byte-access} %<mae=ANY", \ - "%{mae=ANY2:-mmul-type=none -mno-byte-access} %<mae=ANY2", \ - "%{mae=ANY3:-mmul-type=none} %<mae=ANY3", \ - "%{mae=STAN:-mmul-type=none -mno-byte-access} %<mae=STAN", \ - "%{mae=STAN2:-mmul-type=mac -mno-byte-access} %<mae=STAN2", \ - "%{mae=STAN3:-mmul-type=mac} %<mae=STAN3", \ - "%{mae=MAC:-mmul-type=mac -mno-byte-access} %<mae=MAC", \ - "%{mae=MUL:-mmul-type=mul} %<mae=MUL", \ - "%{mae=MEM:-mmul-type=mul} %<mae=MEM", \ - "%{mae=MEM2:-mmul-type=mul} %<mae=MEM2", \ - "%{mae=CTRL:-mmul-type=mul} %<mae=CTRL", \ - "%{mae=CTRL2:-mmul-type=mul} %<mae=CTRL2" - -/* Specify the default options, so that the multilib build doesn't - need to provide special cases for the defaults. */ -#define MULTILIB_DEFAULTS \ - { "mmul-type=mul", "mbyte-access"} - -#define TARGET_HAS_BYTE_ACCESS (picochip_has_byte_access) -#define TARGET_HAS_MUL_UNIT (picochip_has_mul_unit) -#define TARGET_HAS_MAC_UNIT (picochip_has_mac_unit) -#define TARGET_HAS_MULTIPLY (picochip_has_mac_unit || picochip_has_mul_unit) - -/* Storage Layout */ - -/* picoChip processors are 16-bit machines, little endian. */ - -#define BITS_BIG_ENDIAN 0 -#define BYTES_BIG_ENDIAN 0 -#define WORDS_BIG_ENDIAN 0 - -#define BITS_PER_WORD 16 -#define UNITS_PER_WORD (BITS_PER_WORD / BITS_PER_UNIT) - -#define POINTER_SIZE BITS_PER_WORD - -/* Promote those modes that are smaller than an int, to int mode. */ -#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \ - ((GET_MODE_CLASS (MODE) == MODE_INT \ - && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \ - ? (MODE) = HImode : 0) - -/* All parameters are at least this aligned. Parameters are passed - one-per-register. */ -#define PARM_BOUNDARY BITS_PER_WORD - -/* The main stack pointer is guaranteed to be aligned to the most - strict data alignment. */ -#define STACK_BOUNDARY 32 - -/* Function entry point is byte aligned. */ -#define FUNCTION_BOUNDARY 8 - -/* This is the biggest alignment that can be allowed on this machine. - Since the STANs have only 256 byte memory, it doesn't make sense - to have alignments greater than 32 bytes. Hence the value */ -#define MAX_OFILE_ALIGNMENT 32*8 - -/* The strictest data object alignment, which repesents a register pair. */ -#define BIGGEST_ALIGNMENT 32 - -/* The hardware doesn't allow unaligned memory access. */ -#define STRICT_ALIGNMENT 1 - -/* We want the 'unix' style bitfield packing algorithm. */ -#define PCC_BITFIELD_TYPE_MATTERS 1 - -/* Support up to 64-bit integers. */ -#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (DImode) - -/* We don't support floating point, but give it a sensible definition. */ -#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT - -/* Layout of Source Language Data Types. */ - -#define INT_TYPE_SIZE BITS_PER_WORD - -/* The normal sizes for C scalar data. */ -#define CHAR_TYPE_SIZE 8 -#define SHORT_TYPE_SIZE 16 -#define LONG_TYPE_SIZE 32 -#define LONG_LONG_TYPE_SIZE 64 - -/* We don't support the following data types, but still give them - sensible values. */ -#define FLOAT_TYPE_SIZE 32 -#define DOUBLE_TYPE_SIZE 32 -#define LONG_DOUBLE_TYPE_SIZE 32 - -/* Plain `char' is a signed type, since the hardware sign-extends - bytes when loading them from memory into a register. */ -#define DEFAULT_SIGNED_CHAR 1 - -/* Note that the names of the types used in the following macros must - be precisely the same as those defined internally in gcc. For - example, `unsigned short' wouldn't work as a type string, since gcc - doesn't define any type with this exact string. The correct string - to use is `short unsigned int'. */ - -#define SIZE_TYPE "unsigned int" - -#define PTRDIFF_TYPE "int" - -#define WCHAR_TYPE "short unsigned int" -#define WCHAR_TYPE_SIZE 16 - -#define WINT_TYPE "unsigned int" - -/* Register Usage */ - -/* Picochip has 16 16-bit registers, a condition code register and an - (inaccessible) instruction pointer. One of these registers (r15) is - special, and is either used to load a constant anywhere a register - can normally be used, or is used to specify a dummy destination - (e.g., when setting condition flags). We also define some pseudo - registers to represent condition codes, the frame pointer and the - argument pointer. The latter two are eliminated wherever possible. - - Pairs of general registers may be combined to form 32-bit registers. - - The picoChip registers are as follows: - - 0..1 - function return value - 0..5 - first 6 function parameters - 6..11 - General purpose - 12 - link register - 13 - stack pointer - 14 - specialized pointer - 15 - long constant or /dev/null - (16) acc0 - (17) pseudo condition code - (18) pseudo frame pointer - (19) pseudo arg pointer - - Registers 0..6, 12, 13, 14, 15 are caller save - Registers 0..12, 14 are available to the register allocator. - - In addition, the DSP variant of the ISA allows extra accumulator - registers to be accessed. These are special purpose registers, - which are not currently used by the compiler. - - */ - -/* Basic Characteristics of Registers */ - -/* We have 16 hard registers plus 3 pseudo hard registers and an accumulator. */ -#define FIRST_PSEUDO_REGISTER 20 - -/* The first non-hard register. Only used internally by the picoChip port. */ -#define FIRST_NONHARD_REGISTER 18 - -/* Cannot use SP, CST, CC, FP, AP */ -#define FIXED_REGISTERS {0,0,0,0,0,0,0,0, 0,0,0,0,0,1,0,1, 1,1,1,1} - -/* Those that are clobbered by a function call (includes pseudo-regs) */ -#define CALL_USED_REGISTERS {1,1,1,1,1,1,0,0, 0,0,0,0,1,1,0,1, 1,1,1,1} -#define CALL_REALLY_USED_REGISTERS {1,1,1,1,1,1,0,0, 0,0,0,0,1,1,0,0, 0,1,0,0} - -/* Define the number of the picoChip link and condition pseudo registers. */ -#define LINK_REGNUM 12 -#define CC_REGNUM 17 -#define ACC_REGNUM 16 - -/* Order of Allocation of Registers */ - -/* The registers are allocated starting with the caller-clobbered - registers, in reverse order. The registers are then listed in an - order which means that they are efficiently saved in pairs (i.e., - one 32-bit store can be used instead of two 16-bit stores to save - the registers into the stack). The exception to this is the use of - r14 (AP) register, which also appears early on. This is because the - AP register can be used to encode memory operations more - efficiently than other registers. Some code can be made more - compact as a result. */ - /* My current feeling is that r14 should go to the end and maybe even r12. - It seems like the overhead of store/load that will occur since we cant - pair anything up with r14 will be higher than the advantage of smaller - encoding. - Also r12 is put towards the end for leaf functions. Since leaf functions - do not have any calls, the prologue/epilogue for them wouldnt save up/ - restore its value. So, it doesn't make sense for us to use it in the middle, - if we can avoid it. */ -#define REG_ALLOC_ORDER {5,4,3,2,1,0,12,6,7,8,9,10,11,14,16,0,0,0,0,0} -#define LEAF_REG_ALLOC_ORDER {5,4,3,2,1,0,6,7,8,9,10,11,14,12,16,0,0,0,0,0} - -/* We can dynamically change the REG_ALLOC_ORDER using the following hook. - It would be desirable to change it for leaf functions so we can put - r12 at the end of this list.*/ -#define ADJUST_REG_ALLOC_ORDER picochip_order_regs_for_local_alloc () - -/* How Values Fit in Registers */ - -/* Number of consecutive hard regs needed starting at reg REGNO - to hold something of mode MODE. */ -#define HARD_REGNO_NREGS(REGNO, MODE) picochip_regno_nregs((REGNO), (MODE)) - -/* Is it ok to place MODE in REGNO? Require that the register number - be aligned. */ -#define HARD_REGNO_MODE_OK(REGNO, MODE) picochip_hard_regno_mode_ok(REGNO, MODE) - -#define MODES_TIEABLE_P(MODE1,MODE2) 1 - -/* Don't copy the cc register ('cos you can't put it back). */ -#define AVOID_CCMODE_COPIES 1 - -/* Register Classes */ - -enum reg_class -{ - NO_REGS, /* no registers in set */ - FRAME_REGS, /* registers with a long offset */ - PTR_REGS, /* registers without an offset */ - CONST_REGS, /* registers for long constants */ - NULL_REGS, /* registers which ignore writes */ - CC_REGS, /* condition code registers */ - ACC_REGS, /* Accumulator registers */ - TWIN_REGS, /* registers which can be paired */ - GR_REGS, /* general purpose registers */ - ALL_REGS, /* all registers */ - LIM_REG_CLASSES, /* max value + 1 */ - - /* Some aliases */ - GENERAL_REGS = GR_REGS -}; - -#define N_REG_CLASSES (int) LIM_REG_CLASSES - - -/* The names of the register classes */ -#define REG_CLASS_NAMES \ -{ \ - "NO_REGS", \ - "FRAME_REGS", \ - "PTR_REGS", \ - "CONST_REGS", \ - "NULL_REGS", \ - "CC_REGS", \ - "ACC_REGS", \ - "TWIN_REGS", \ - "GR_REGS", \ - "ALL_REGS" \ -} - -/* Each reg class is an array of 32-bit integers. Each array must be - long enough to store one bit for every pseudo register. Thus in the - following code, each array only stores one 32-bit value. */ -#define REG_CLASS_CONTENTS \ -{ \ - {0x00000000}, /* no registers */ \ - {0x00002000}, /* frame */ \ - {0x00004000}, /* pointer */ \ - {0x00008000}, /* const */ \ - {0x00008000}, /* null */ \ - {0x00020000}, /* cc */ \ - {0x00010000}, /* acc0 */ \ - {0x00000FFF}, /* twin */ \ - {0x000CFFFF}, /* general registers - includes pseudo-arg */ \ - {0x000FFFFF} /* all registers - includes pseudo-arg */ \ -} - -/* The earliest register class containing the given register. */ -extern const enum reg_class picochip_regno_reg_class[FIRST_PSEUDO_REGISTER]; -#define REGNO_REG_CLASS(REGNO) picochip_regno_reg_class[REGNO] - -/* Any register can be a base pointer. */ -#define BASE_REG_CLASS GR_REGS - -/* Any register can be an index. */ -#define INDEX_REG_CLASS GR_REGS - -#define REGNO_OK_FOR_BASE_P(REGNO) \ - (REGNO_REG_CLASS (REGNO) != CC_REGS && REGNO_REG_CLASS (REGNO) != ACC_REGS) - -#define REGNO_OK_FOR_INDEX_P(REGNO) 0 - -#define CLASS_MAX_NREGS(CLASS, MODE) picochip_class_max_nregs(CLASS, MODE) - - -/* Stack Layout and Calling Conventions */ - -#define STACK_GROWS_DOWNWARD 1 - -/* The frame pointer points to the outgoing argument area, so the - locals are above that. */ -#define STARTING_FRAME_OFFSET 0 - -#define FIRST_PARM_OFFSET(FNDECL) 0 - -/* Specify where the return address lives before entry to the - prologue. This is required to enable DWARF debug information to be - generated. */ -#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LINK_REGNUM) - -#define RETURN_ADDR_RTX(count,frameaddr) picochip_return_addr_rtx(count,frameaddr) - -#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (LINK_REGNUM) - -/* Registers that Address the Stack Frame */ - -#define STACK_POINTER_REGNUM 13 -#define FRAME_POINTER_REGNUM 18 -#define ARG_POINTER_REGNUM 19 - -/* Eliminating Frame Pointer and Arg Pointer. The frame and argument - pointers are eliminated wherever possible, by replacing them with - offsets from the stack pointer. */ - -#define ELIMINABLE_REGS \ - {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ - {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} - -#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ - OFFSET = initial_elimination_offset(FROM, TO); - -#define ACCUMULATE_OUTGOING_ARGS 1 - -#define PUSH_ARGS 0 - -/* Passing Arguments in Registers */ - -/* Store the offset of the next argument. */ -#define CUMULATIVE_ARGS unsigned - -#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT,N_NAMED_ARGS) \ - ((CUM) = 0) - -/* The first 6 registers can hold parameters. */ -#define FUNCTION_ARG_REGNO_P(REGNO) ((REGNO) < 6) - -/* How Scalar Function Values are Returned - Do we need this?? */ -#define FUNCTION_VALUE(VALTYPE,FUNC) picochip_function_value(VALTYPE, FUNC, 0) - -#define LIBCALL_VALUE(MODE) (gen_rtx_REG (MODE, 0)) - -/* Results are in register zero. If an SImode register is returned, - reg0 will suffice to mean R[0:1]. */ -#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) - -/* Don't automatically pass struct's in memory - use the - * RETURN_IN_MEMORY macro to determine when structs are returned in - * memory, and when in registers. */ -#define DEFAULT_PCC_STRUCT_RETURN 0 - -/* Function Entry and Exit */ - -/* The epilogue doesn't clobber anything. */ -#define EPILOGUE_USES(REGNO) 0 - -/* Generating Code for Profiling. No profiling implemented */ - -#define FUNCTION_PROFILER(FILE,LABELNO) - -/* Trampolines for Nested Functions */ - -/* No trampolines. */ -#define TRAMPOLINE_SIZE 0 - -/* Addressing Modes */ - -#define MAX_REGS_PER_ADDRESS 1 - -/* Legitimize reload address tries machine dependent means of - reloading addresses. There seems to be a strange error in gcc, - which necessitates this macro. Consider: - - set (reg A) (symbol_ref) - set (reg B) (plus (reg A) (const_int)) - - A symbol_ref is a valid constant, so the symbol_ref is propagated - into the second instruction to generate the instruction: - - set (reg B) (plus (symbol_ref) (const_int)) - - This is an invalid address, and find_reloads_address correctly - determines this. However, that function doesn't generate a valid - replacement for the now invalid address, and the invalid address is - output into the assembly language. To fix the problem without - changing gcc itself, the following macro tests when such an invalid - address has been computed, and wraps it up inside a constant rtx. A - constant rtx can be correctly reloaded by the function, and hence - correct code is generated. */ - -#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ -do { \ - if (picochip_legitimize_reload_address(&X,MODE,OPNUM,TYPE,IND_LEVELS)) \ - goto WIN; \ - } while(0); \ - - -/* Condition Code Status */ - -#define CC_STATUS_MDEP unsigned -#define CC_STATUS_MDEP_INIT (cc_status.mdep = 0) - -/* Describing Relative Costs of Operations */ - -/* Bytes are no faster than words. */ -#define SLOW_BYTE_ACCESS 1 - -/* The assembler is often able to optimise function call branches, so - don't try to CSE them in the compiler. This was the thinking before. - But now, we realise that the benefits from CSE would mostly outweigh - the disadvantages. */ -#define NO_FUNCTION_CSE - - -/* Dividing the Output into Sections */ - -#define TEXT_SECTION_ASM_OP ".section .text\n" -#define DATA_SECTION_ASM_OP ".section .data\n" -#define BSS_SECTION_ASM_OP ".section .bss\n" -/* picoChip is Harvard (separate data/instruction memories), so - read-only data must go into the data section. */ -#define READONLY_DATA_SECTION_ASM_OP ".section .data\n" - -/* Defining the Output Assembler Language */ - -/* The Overall Framework of an Assembler File */ - -#define ASM_FILE_COMMENT "// " - -#define ASM_APP_ON "// High-level ASM start\n" -#define ASM_APP_OFF "// High-level ASM end\n" - -#undef TARGET_ASM_OUTPUT_IDENT -#define TARGET_ASM_OUTPUT_IDENT default_asm_output_ident_directive - -/* Output of Data */ - -#define ASM_OUTPUT_ASCII(FILE, PTR, LEN) picochip_output_ascii(FILE, PTR, LEN); - -/* Output of Uninitialized Variables */ -#define ASM_OUTPUT_ALIGNED_COMMON(FILE,NAME,SIZE,ALIGN) \ - picochip_output_aligned_common(FILE, NAME, SIZE, ALIGN) - -#define ASM_OUTPUT_ALIGNED_LOCAL(FILE,NAME,SIZE,ALIGN) \ - picochip_output_aligned_local(FILE, NAME, SIZE, ALIGN) - -/* Output and Generation of Labels */ - -#define ASM_OUTPUT_LABEL(STREAM,NAME) \ - do { picochip_output_label(STREAM, NAME); } while (0); - -#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ - { picochip_output_labelref(STREAM, NAME); } - -/* Format must match that of picochip_output_label. */ -#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ - picochip_generate_internal_label(STRING,PREFIX,(long)NUM) - -#define ASM_WEAKEN_LABEL(STREAM,NAME) picochip_weaken_label(STREAM,NAME); - -/* Store in OUTPUT a string (made with alloca) containing an - assembler-name for a local static variable named NAME. LABELNO is - an integer which is different for each call. The assembler can't - use periods to generate the name, so we use a ___ separator - instead. */ - -#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ -( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 15), \ - sprintf ((OUTPUT), "%s___%lu", (NAME), (unsigned long)(LABELNO))) - -/* Macros Controlling Initialization Routines */ - -/* By defining this, the main function won't try to call `__main'. */ -#define HAS_INIT_SECTION - -/* Output of Assembler Instructions */ - -#define REGISTER_NAMES \ -{"R0", "R1", "R2", "R3", \ - "R4", "R5", "R6", "R7", \ - "R8", "R9", "R10", "R11", \ - "R12", "FP", "R14", "R15", \ - "acc0", "pseudoCC", "pseudoFP", "pseudoAP"} - -#define ADDITIONAL_REGISTER_NAMES \ -{ \ - { "R0", 0}, \ - { "R1", 1}, \ - { "R2", 2}, \ - { "R3", 3}, \ - { "R4", 4}, \ - { "R5", 5}, \ - { "R6", 6}, \ - { "R7", 7}, \ - { "R8", 8}, \ - { "R9", 9}, \ - { "R10", 10}, \ - { "R11", 11}, \ - { "R12", 12}, \ - { "FP", 13}, \ - { "R14", 14}, \ - { "R15", 15}, \ - { "acc0", 16}, \ - { "sp", 12}, /* ABI stack pointer */ \ - { "ln", 13}, /* arch link register */ \ - { "ptr", 14}, /* arch constant pointer */ \ - { "rc", 15}, /* arch constant register */ \ - { "rz", 15}, /* arch zero */ \ -} - -/* Final prescan insn is called just before an instruction is - output. In our case, we use this to detect the VLIW slot to which - the instruction has been assigned, preparatory to generating the - VLIW output in ASM_OUTPUT_OPCODE. */ -#define FINAL_PRESCAN_INSN(insn, operand, nop) \ - picochip_final_prescan_insn (insn, operand,nop) - -#define ASM_OUTPUT_OPCODE(FILE,PTR) \ - { PTR = picochip_asm_output_opcode(FILE, PTR); } - -#define PRINT_OPERAND(STREAM,X,CODE) \ - picochip_print_operand(STREAM, X, CODE) - -#define PRINT_OPERAND_PUNCT_VALID_P(code) \ - (((code) == '|') || ((code) == '#') || ((code) == '>')) - -#define PRINT_OPERAND_ADDRESS(STREAM,X) \ - picochip_print_operand_address(STREAM,X) - -/* Output of Dispatch Tables */ - -/* Initialise a data memory location to an absolute code label. Used - for building switch statement jump tables. Note - the format of the - label must match that of the function picochip_output_label. */ -#define ASM_OUTPUT_ADDR_VEC_ELT(stream, value) \ - fprintf (stream, ".initWord _L%d\n", value); - -/* Assembler Commands for Alignment */ - -#define ASM_OUTPUT_SKIP(STREAM,BYTES) \ - fprintf(STREAM, ".skip "HOST_WIDE_INT_PRINT_UNSIGNED"\n", BYTES); -#define ASM_OUTPUT_ALIGN(STREAM,POWER) \ - fprintf(STREAM, ".align %u\n", 1 << POWER); - -/* The elaborator doesn't output zero bytes in the text section. */ -#define ASM_NO_SKIP_IN_TEXT 1 - -/* Controlling Debugging Information Format */ - -/* Macros Affecting All Debugging Formats */ - -#define DBX_REGISTER_NUMBER(REGNO) (REGNO) - -#define DWARF2_DEBUGGING_INFO -#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG -#define DWARF2_FRAME_INFO 1 - -/* Generate .file/.loc directives, so that the assembler generates the - line table. */ -#define DWARF2_ASM_LINE_DEBUG_INFO 1 - -/* Miscellaneous Parameters */ - -#define CASE_VECTOR_MODE HImode -#define WORD_REGISTER_OPERATIONS -#define LOAD_EXTEND_OP(MODE) ((MODE) == QImode ? SIGN_EXTEND : ZERO_EXTEND) -#define MOVE_MAX 4 -#define SHIFT_COUNT_TRUNCATED 1 -#define Pmode HImode -#define FUNCTION_MODE QImode -#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 - -#define ASM_LONG ":TODO:.word\t" - -/* Define builtins for selected special-purpose instructions. */ -enum picochip_builtins -{ - PICOCHIP_BUILTIN_SBC, - PICOCHIP_BUILTIN_PUT, - PICOCHIP_BUILTIN_GET, - PICOCHIP_BUILTIN_TESTPORT, - PICOCHIP_BUILTIN_COPYSW, - PICOCHIP_BUILTIN_ADDS, - PICOCHIP_BUILTIN_SUBS, - PICOCHIP_BUILTIN_BREV, - PICOCHIP_BUILTIN_BYTESWAP, - PICOCHIP_BUILTIN_GET_ARRAY, - PICOCHIP_BUILTIN_PUT_ARRAY, - PICOCHIP_BUILTIN_TESTPORT_ARRAY, - PICOCHIP_BUILTIN_ASRI, - PICOCHIP_BUILTIN_HALT -}; - -#define NO_DOLLAR_IN_LABEL 1 -#define NO_DOT_IN_LABEL 1 - -/* The assembler does support LEB128, despite the auto-configure test - not detecting this. */ -#define HAVE_AS_LEB128 1 - -/* picochip-unknown-none target has no support of C99 runtime */ -#undef TARGET_LIBC_HAS_FUNCTION -#define TARGET_LIBC_HAS_FUNCTION no_c99_libc_has_function - -/* The End */ diff --git a/gcc/config/picochip/picochip.md b/gcc/config/picochip/picochip.md deleted file mode 100644 index f565c66..0000000 --- a/gcc/config/picochip/picochip.md +++ /dev/null @@ -1,2623 +0,0 @@ -;; GCC machine description for picochip -;; Copyright (C) 2008-2014 Free Software Foundation, Inc. -;; Contributed by Picochip Ltd (http://www.picochip.com) -;; Maintained by Daniel Towner (dant@picochip.com) and Hariharan -;; Sandanagobalane (hariharan@picochip.com) -;; -;; This file is part of GCC. -;; -;; GCC 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 3, or (at your option) -;; any later version. -;; -;; GCC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not, see -;; <http://www.gnu.org/licenses/>. - -;; ------------------------------------------------------------------------- - -;; In addition to the normal output operand formats, the following -;; letter formats are also available: -;; -;; The following can be used for constants, or the constant part of a -;; memory offset. -;; Q - Output constant unaltered (byte mode). -;; M - Alias for Q, which only works with memory operands. -;; H - Divide constant by 2 (i.e., HImode is 2 bytes) -;; S - Divide constant by 4 (i.e., SImode is 4 bytes) -;; -;; The following can be used for two part addresses (i.e., base + -;; offset or base[offset]). -;; o - Output offset only. -;; b - Output base only. -;; -;; The following are used on SI registers and constants -;; R - Output register pair (i.e., R[n:m]) -;; L - Output lower word/register -;; U - Output upper word/register -;; -;; The following are used on DI mode registers. -;; X - Output 3rd register -;; Y - Output 4th register -;; -;; Miscellaneous -;; | - Output VLIW separator -;; r - Output register value of memory operand. -;; I - Output an opcode (e.g., ADD for plus, LSL for lshift) -;; i - Output an opcode in symbolic notation (e.g., + for plus) - -;; Define the length of an instruction. Used to allow different types -;; of branches to be used for different branch offsets. Default to 6 -;; bytes, which is the longest possible single instruction. -(define_attr "length" "" (const_int 6)) - -;; Define some constants which are used in conjuction with branch -;; scheduling. Branches must be 10-bit signed, which equates to -;; [-512,511]. However, to compensate for the lack of branch alignment -;; these offsets are reduced by a factor of 2. - -(define_constants - [ - (MIN_BRANCH_OFFSET -256) - (MAX_BRANCH_OFFSET 255) - (SHORT_BRANCH_LENGTH 6) ; The size of a schedulable short branch. - (LONG_BRANCH_LENGTH 16) ; The size of an expanded JMP?? macro. - ] -) - -;; Define identifiers for various special instructions. These -;; instructions may then be used in RTL expansions, or builtins. -(define_constants - [ - ; Special instruction builtins. - (UNSPEC_SBC 0) ; Sign-bit count - (UNSPEC_ADDS 1) ; Saturating addition - (UNSPEC_SUBS 2) ; Saturating subtraction - (UNSPEC_BREV 3) ; Bit reversal - - ; Special internal instructions (only used by compiler) - (UNSPEC_COPYSW 5) ; Get status word - (UNSPEC_ADDC 6) ; Add with carry. - - ; Scalar port communication builtins - (UNSPEC_PUT 7) ; Communication (put): port[op0] := op1 - (UNSPEC_GET 8) ; Communication (get): op0 := get_port[op1] - (UNSPEC_TESTPORT 9) ; Communication (test): op0 := testport[op1] - - ; Array port communication builtins. These all take extra - ; arguments giving information about the array access being used. - (UNSPEC_PUT_ARRAY 10) ; Array put - (UNSPEC_GET_ARRAY 11) ; Array get - (UNSPEC_TESTPORT_ARRAY 12) ; Array test port - - ;; Array port expansions - (UNSPEC_CALL_GET_ARRAY 13) ; - (UNSPEC_CALL_PUT_ARRAY 14) ; - (UNSPEC_CALL_TESTPORT_ARRAY 15) ; - - ; Array port low-level fn calls - (UNSPEC_CALL_GET_FN 16) - (UNSPEC_CALL_TESTPORT_FN 17) - - ; Halt instruction. - (UNSPEC_HALT 18) - - ; Internal TSTPORT instruction, used to generate a single TSTPORT - ; instruction for use in the testport branch split. - (UNSPEC_INTERNAL_TESTPORT 19) - ] -) - -;; Register ID's -(define_constants - [ - (LINK_REGNUM 12) ; Function link register. - (CC_REGNUM 17) ; Condition flags. - (ACC_REGNUM 16) ; Condition flags. - ] -) - -;;============================================================================ -;; Predicates and constraints -;;============================================================================ - -(include "predicates.md") -(include "constraints.md") - -;;============================================================================ -;; First operand shifting patterns. These allow certain instructions -;; (e.g., add, and, or, xor, sub) to apply a shift-by-constant to -;; their first operand. -;; -;; Note that only the first operand is matched by the shift, to ensure -;; that non-commutative instructions (like subtract) work -;; properly. When a commutative instruction, with a shift in the -;; second operand is found, the compiler will reorder the operands to -;; match. -;;============================================================================ - -(define_insn "*firstOpGenericAshift" - [(set (match_operand:HI 0 "register_operand" "=r") - (match_operator:HI 1 "picochip_first_op_shift_operator" - [(ashift:HI - (match_operand:HI 2 "register_operand" "r") - (match_operand:HI 3 "picochip_J_operand" "J")) - (match_operand:HI 4 "picochip_register_or_immediate_operand" "ri")])) - (clobber (reg:CC CC_REGNUM))] - "" - "%I1.0 [LSL %2,%3],%4,%0\t// %0 := (%2 << %3) %i1 %4" - [(set_attr "type" "picoAlu") - ;; A long constant must be used if the operator instruction doesn't - ;; accept immediates, or if the constant is too big to fit the - ;; immediate. Note that the following condition is written in the - ;; way which uses the least number of predicates. - (set (attr "longConstant") - (cond [(ior (match_operand 4 "register_operand") - (and (match_operand 1 "picochip_first_op_shift_operator_imm") - (match_operand 1 "picochip_J_operand"))) - (const_string "false")] - (const_string "true")))]) - -;; During combine, ashift gets converted into a multiply, necessitating the following pattern. -;; Note that we do a log_2(imm) to get the actual LSL operand. - -(define_insn "*firstOpGenericAshift" - [(set (match_operand:HI 0 "register_operand" "=r") - (match_operator:HI 1 "picochip_first_op_shift_operator" - [(mult:HI - (match_operand:HI 2 "register_operand" "r") - (match_operand:HI 3 "power_of_2_imm_operand" "n")) - (match_operand:HI 4 "picochip_register_or_immediate_operand" "ri")])) - (clobber (reg:CC CC_REGNUM))] - "" - "%I1.0 [LSL %2,%P3],%4,%0\t// %0 := (%2 << %3) %i1 %4" - [(set_attr "type" "picoAlu") - ;; A long constant must be used if the operator instruction doesn't - ;; accept immediates, or if the constant is too big to fit the - ;; immediate. Note that the following condition is written in the - ;; way which uses the least number of predicates. - (set (attr "longConstant") - (cond [(ior (match_operand 4 "register_operand") - (and (match_operand 1 "picochip_first_op_shift_operator_imm") - (match_operand 1 "picochip_J_operand"))) - (const_string "false")] - (const_string "true")))]) - -(define_insn "*firstOpGenericAshiftrt" - [(set (match_operand:HI 0 "register_operand" "=r") - (match_operator:HI 1 "picochip_first_op_shift_operator" - [(ashiftrt:HI - (match_operand:HI 2 "register_operand" "r") - (match_operand:HI 3 "picochip_J_operand" "J")) - (match_operand:HI 4 "picochip_register_or_immediate_operand" "ri")])) - (clobber (reg:CC CC_REGNUM))] - "" - "%I1.0 [ASR %2,%3],%4,%0\t// %0 := (%2 >>{arith} %3) %i1 %4" - [(set_attr "type" "picoAlu") - ;; A long constant must be used if the operator instruction doesn't - ;; accept immediates, or if the constant is too big to fit the - ;; immediate. Note that the following condition is written in the - ;; way which uses the least number of predicates. - (set (attr "longConstant") - (cond [(ior (match_operand 4 "register_operand") - (and (match_operand 1 "picochip_first_op_shift_operator_imm") - (match_operand 1 "picochip_J_operand"))) - (const_string "false")] - (const_string "true")))]) - -(define_insn "*firstOpGenericLshiftrt" - [(set (match_operand:HI 0 "register_operand" "=r") - (match_operator:HI 1 "picochip_first_op_shift_operator" - [(lshiftrt:HI - (match_operand:HI 2 "register_operand" "r") - (match_operand:HI 3 "picochip_J_operand" "J")) - (match_operand:HI 4 "picochip_register_or_immediate_operand" "ri")])) - (clobber (reg:CC CC_REGNUM))] - "" - "%I1.0 [LSR %2,%3],%4,%0\t// %0 := (%2 >> %3) %i1 %4" - [(set_attr "type" "picoAlu") - ;; A long constant must be used if the operator instruction doesn't - ;; accept immediates, or if the constant is too big to fit the - ;; immediate. Note that the following condition is written in the - ;; way which uses the least number of predicates. - (set (attr "longConstant") - (cond [(ior (match_operand 4 "register_operand") - (and (match_operand 1 "picochip_first_op_shift_operator_imm") - (match_operand 1 "picochip_J_operand"))) - (const_string "false")] - (const_string "true")))]) - -;;=========================================================================== -;; Jump instructions. -;;=========================================================================== - -(define_insn "indirect_jump" - [(set (pc) (match_operand:HI 0 "register_operand" "r"))] - "" - "JR (%0)\t// Indirect_jump to %0 %>" - [(set_attr "type" "realBranch") - (set_attr "length" "3")]) - -(define_insn "jump" - [(set (pc) - (label_ref (match_operand 0 "" "")))] - "" - "* return picochip_output_jump(insn);" - [(set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int MIN_BRANCH_OFFSET)) - (le (minus (match_dup 0) (pc)) (const_int MAX_BRANCH_OFFSET))) - (const_int SHORT_BRANCH_LENGTH) - (const_int LONG_BRANCH_LENGTH))) - (set (attr "type") - (if_then_else - (eq_attr "length" "6") - (const_string "realBranch") - (const_string "unknown")))]) - -(define_insn "*fn_return" - [(return) - (use (reg:HI LINK_REGNUM))] - "" - "JR (R12)\t// Return to caller %>" - [(set_attr "length" "2") - (set_attr "type" "realBranch") - (set_attr "longConstant" "false")]) - -;; Peephole either 2 LDWs or STWs into LDL/STL. -(define_peephole2 - [(set (match_operand:HI 0 "register_operand" "") - (match_operand:HI 1 "memory_operand" "")) - (set (match_operand:HI 2 "register_operand" "") - (match_operand:HI 3 "memory_operand" ""))] - "ok_to_peephole_ldw(operands[0],operands[1],operands[2],operands[3])" - [(set (match_dup 4) (match_dup 5))] - "{ - operands[4] = gen_min_reg(operands[0],operands[2]); - operands[5] = gen_SImode_mem(operands[1],operands[3]); - }") - -(define_peephole2 - [(set (match_operand:HI 0 "memory_operand" "") - (match_operand:HI 1 "register_operand" "")) - (set (match_operand:HI 2 "memory_operand" "") - (match_operand:HI 3 "register_operand" ""))] - "ok_to_peephole_stw(operands[0],operands[1],operands[2],operands[3])" - [(set (match_dup 4) (match_dup 5))] - "{ - operands[4] = gen_SImode_mem(operands[0],operands[2]); - operands[5] = gen_min_reg(operands[1],operands[3]); - }") - - -;; We have instructions like add,subtract,ior,and that set condition -;; codes if they are executed on slot 0. If we have -;; add a = b + c -;; if (a!=0) -;; {} -;; We would have RTL sequence like -;; add.# rb,rc,ra # will be replaced by slot no, after scheduling -;; sub.0 ra,0,r15 -;; bnz -;; Instead, we can just do -;; add.0 rb,rc,ra -;; bnz - -(define_peephole2 - [(parallel [(set (match_operand:HI 0 "register_operand" "") - (plus:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))]) - (parallel [(set (pc) - (if_then_else - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(match_dup 0) (const_int 0)]) - (label_ref (match_operand 6 "" "")) - (pc))) - (clobber (reg:CC CC_REGNUM))])] - "" - [(parallel [(set (match_dup 0) - (plus:HI (match_dup 1) (match_dup 2))) - (set (reg:CC CC_REGNUM) - (match_op_dup 3 [(const_int 0) (const_int 0)]))]) - (parallel [(set (pc) - (if_then_else - (match_op_dup:HI 3 [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 6)) - (pc))) - (use (match_dup 7))])] - "{ - operands[7] = GEN_INT(0); - }") - -(define_peephole2 - [(parallel [(set (match_operand:HI 0 "register_operand" "") - (plus:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))]) - (set (reg:CC CC_REGNUM) - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(match_dup 0) (const_int 0)])) - (parallel [(set (pc) - (if_then_else - (match_operator 4 "comparison_operator" - [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_operand 5 "" "")) - (pc))) - (use (match_operand:HI 6 "const_int_operand" ""))])] - "" - [(parallel [(set (match_dup 0) - (plus:HI (match_dup 1) (match_dup 2))) - (set (reg:CC CC_REGNUM) - (match_op_dup 3 [(const_int 0) (const_int 0)]))]) - (parallel [(set (pc) - (if_then_else (match_op_dup:HI 4 [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 5)) - (pc))) - (use (match_dup 6))])] - "{ - operands[7] = GEN_INT(0); - }") - - -;; If peephole happens before the cbranch split - -(define_peephole2 - [(parallel [(set (match_operand:HI 0 "register_operand" "") - (minus:HI (match_operand:HI 1 "general_operand" "") - (match_operand:HI 2 "register_operand" ""))) - (clobber (reg:CC CC_REGNUM))]) - (parallel [(set (pc) - (if_then_else - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(match_dup 0) (const_int 0)]) - (label_ref (match_operand 6 "" "")) - (pc))) - (clobber (reg:CC CC_REGNUM))])] - "" - [(parallel [(set (match_dup 0) - (minus:HI (match_dup 1) (match_dup 2))) - (set (reg:CC CC_REGNUM) - (match_op_dup 3 [(const_int 0) (const_int 0)]))]) - (parallel [(set (pc) - (if_then_else - (match_op_dup:HI 3 [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 6)) - (pc))) - (use (match_dup 7))])] - "{ - operands[7] = GEN_INT(0); - }") - - -;; If peephole happens after the cbranch split - -(define_peephole2 - [(parallel [(set (match_operand:HI 0 "register_operand" "") - (minus:HI (match_operand:HI 1 "general_operand" "") - (match_operand:HI 2 "register_operand" ""))) - (clobber (reg:CC CC_REGNUM))]) - (set (reg:CC CC_REGNUM) - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(match_dup 0) (const_int 0)])) - (parallel [(set (pc) - (if_then_else - (match_operator 4 "comparison_operator" - [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_operand 5 "" "")) - (pc))) - (use (match_operand:HI 6 "const_int_operand" ""))])] - "" - [(parallel [(set (match_dup 0) - (minus:HI (match_dup 1) (match_dup 2))) - (set (reg:CC CC_REGNUM) - (match_op_dup 3 [(const_int 0) (const_int 0)]))]) - (parallel [(set (pc) - (if_then_else (match_op_dup:HI 4 [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 5)) - (pc))) - (use (match_dup 6))])] - "{ - operands[7] = GEN_INT(0); - }") - -;; If peephole happens before the cbranch split - -(define_peephole2 - [(parallel[(set (match_operand:HI 0 "register_operand" "") - (and:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))]) - (parallel [(set (pc) - (if_then_else - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(match_dup 0) (const_int 0)]) - (label_ref (match_operand 6 "" "")) - (pc))) - (clobber (reg:CC CC_REGNUM))])] - "" - [(parallel [(set (match_dup 0) - (and:HI (match_dup 1) (match_dup 2))) - (set (reg:CC CC_REGNUM) - (match_op_dup 3 [(const_int 0) (const_int 0)]))]) - (parallel [(set (pc) - (if_then_else - (match_op_dup:HI 3 [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 6)) - (pc))) - (use (match_dup 7))])] - "{ - operands[7] = GEN_INT(0); - }") - -(define_peephole2 - [(parallel[(set (match_operand:HI 0 "register_operand" "") - (and:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))]) - (set (reg:CC CC_REGNUM) - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(match_dup 0) (const_int 0)])) - (parallel [(set (pc) - (if_then_else - (match_operator 4 "comparison_operator" - [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_operand 5 "" "")) - (pc))) - (use (match_operand:HI 6 "const_int_operand" ""))])] - "" - [(parallel [(set (match_dup 0) - (and:HI (match_dup 1) (match_dup 2))) - (set (reg:CC CC_REGNUM) - (match_op_dup 3 [(const_int 0) (const_int 0)]))]) - (parallel [(set (pc) - (if_then_else (match_op_dup:HI 4 [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 5)) - (pc))) - (use (match_dup 6))])] - "{ - operands[7] = GEN_INT(0); - }") - -;; If peephole happens before the cbranch split - -(define_peephole2 - [(parallel[(set (match_operand:HI 0 "register_operand" "") - (ior:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))]) - (parallel [(set (pc) - (if_then_else - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(match_dup 0) (const_int 0)]) - (label_ref (match_operand 6 "" "")) - (pc))) - (clobber (reg:CC CC_REGNUM))])] - "" - [(parallel [(set (match_dup 0) - (ior:HI (match_dup 1) (match_dup 2))) - (set (reg:CC CC_REGNUM) - (match_op_dup 3 [(const_int 0) (const_int 0)]))]) - (parallel [(set (pc) - (if_then_else - (match_op_dup:HI 3 [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 6)) - (pc))) - (use (match_dup 7))])] - "{ - operands[7] = GEN_INT(0); - }") - -(define_peephole2 - [(parallel[(set (match_operand:HI 0 "register_operand" "") - (ior:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC CC_REGNUM))]) - (set (reg:CC CC_REGNUM) - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(match_dup 0) (const_int 0)])) - (parallel [(set (pc) - (if_then_else - (match_operator 4 "comparison_operator" - [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_operand 5 "" "")) - (pc))) - (use (match_operand:HI 6 "const_int_operand" ""))])] - "" - [(parallel [(set (match_dup 0) - (ior:HI (match_dup 1) (match_dup 2))) - (set (reg:CC CC_REGNUM) - (match_op_dup 3 [(const_int 0) (const_int 0)]))]) - (parallel [(set (pc) - (if_then_else (match_op_dup:HI 4 [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 5)) - (pc))) - (use (match_dup 6))])] - "{ - operands[7] = GEN_INT(0); - }") - -;; Conditional branch (HI). This is split into separate compare and -;; branch instructions if scheduling is enabled. The branch -;; instruction is supplied with the type of comparison on which the -;; branch should occur. - -(define_insn_and_split "cbranchhi4" - [(set (pc) - (if_then_else - (match_operator 0 "ordered_comparison_operator" - [(match_operand:HI 1 "register_operand" "r") - (match_operand:HI 2 "picochip_comparison_operand" "ri")]) - (label_ref (match_operand 3 "" "")) - (pc))) - (clobber (reg:CC CC_REGNUM))] - "" - "* return picochip_output_cbranch(operands);" - "reload_completed - && (picochip_schedule_type != DFA_TYPE_NONE || flag_delayed_branch)" - [(const_int 0)] - "{ - rtx const_int_opnd; - const_int_opnd = GEN_INT(GET_CODE(operands[0])); - if (picochip_supported_comparison_operator (operands[0], HImode)) - emit_insn (gen_supported_compare (operands[0], operands[1], operands[2])); - else - emit_insn (gen_compare (operands[0], operands[1], operands[2])); - emit_jump_insn (gen_branch (operands[3], const_int_opnd, operands[0])); - }") - -;; The only difference between this and the next pattern is that the next pattern -;; might introduce subtracts whose first operand is a constant. This would have to -;; be a longConstant. But, we know that such a situation wouldnt arise for supported -;; comparison operator and hence this pattern assumes that the second constraint combo -;; would still generate a normal instruction. - -(define_insn "supported_compare" - [(set (reg:CC CC_REGNUM) - (match_operator:CC 0 "picochip_supported_comparison_operator" - [(match_operand:HI 1 "register_operand" "r,r,r") - (match_operand:HI 2 "picochip_comparison_operand" "r,J,i")]))] - "" - "* return picochip_output_compare(operands);" - [; Must be picoAlu because it sets the condition flags. - (set_attr "type" "picoAlu,picoAlu,picoAlu") - (set_attr "longConstant" "false,false,true") - (set_attr "length" "2,2,4") - ]) - -;; This pattern was added to match the previous pattern. When doing if-convert -;; the pattern generated using movhicc does not have a eq:CC but only a eq for -;; operator. If this pattern were not to be there, Gcc decides not to use -;; movhicc at all. Whereas, in Gcc 4.4, it seems to be cleverer. -(define_insn "*supported_compare1" - [(set (reg:CC CC_REGNUM) - (match_operator 0 "picochip_supported_comparison_operator" - [(match_operand:HI 1 "register_operand" "r,r,r") - (match_operand:HI 2 "picochip_comparison_operand" "r,J,i")]))] - "" - "* return picochip_output_compare(operands);" - [; Must be picoAlu because it sets the condition flags. - (set_attr "type" "picoAlu,picoAlu,picoAlu") - (set_attr "longConstant" "false,false,true") - (set_attr "length" "2,2,4") - ]) - -(define_insn "compare" - [(set (reg:CC CC_REGNUM) - (match_operator:CC 0 "comparison_operator" - [(match_operand:HI 1 "register_operand" "r,r,r") - (match_operand:HI 2 "picochip_comparison_operand" "r,M,i")]))] - "" - "* return picochip_output_compare(operands);" - [; Must be picoAlu because it sets the condition flags. - (set_attr "type" "picoAlu,picoAlu,picoAlu") - (set_attr "longConstant" "false,true,true") - (set_attr "length" "2,4,4") - ]) - -; Match a branch instruction, created from a tstport/cbranch split. -; We use a "use" clause so GCC doesnt try to use this pattern generally. -(define_insn "branch" - [(set (pc) - (if_then_else - (match_operator 2 "comparison_operator" - [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc))) - (use (match_operand:HI 1 "const_int_operand" ""))] - "" - "* return picochip_output_branch(operands, insn);" - [(set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int MIN_BRANCH_OFFSET)) - (le (minus (match_dup 0) (pc)) (const_int MAX_BRANCH_OFFSET))) - (const_int SHORT_BRANCH_LENGTH) - (const_int LONG_BRANCH_LENGTH))) - (set (attr "type") - (if_then_else - (eq_attr "length" "6") - (const_string "realBranch") - (const_string "unknown")))]) - -;; If a movqi is used which accesses memory on a machine which doesn't -;; have byte addressing, synthesise the instruction using word load/store -;; operations. The movqi's that are required during reload phase are -;; handled using reload_inqi/reload_outqi. - -(define_expand "movqi" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "" -{ - - if (!reload_completed && - !TARGET_HAS_BYTE_ACCESS && - (MEM == GET_CODE(operands[0]) || MEM == GET_CODE(operands[1]))) - { - rtx address; - rtx wordAddress; - rtx const1; - rtx shiftVal; - rtx loadedValue; - rtx addressMask; - rtx topByteValue; - rtx signExtendedValue; - - - warn_of_byte_access(); - - /* Load the constant 1 into a register. */ - const1 = gen_reg_rtx(HImode); - emit_insn(gen_rtx_SET(HImode, const1, GEN_INT(1))); - - /* Load the address mask with the bitwise complement of 1. */ - addressMask = gen_reg_rtx(HImode); - emit_insn(gen_rtx_SET(HImode, addressMask, GEN_INT(-2))); - - /* Handle loads first, in case we are dealing with a mem := mem - * instruction. */ - if (MEM == GET_CODE(operands[1])) - { - /* Loads work as follows. The entire word containing the desired byte - * is loaded. The bottom bit of the address indicates which - * byte is required. The desired byte is moved into the most - * significant byte, and then an arithmetic shift right - * invoked to achieve sign extension. The desired byte is - * moved to the MSB by XOR'ing the bottom address bit by 1, - * multiplying the result by 8, and then shifting left by - * that amount. Note that shifts only operate on the bottom - * 4-bits of the source offset, so although the XOR may - * produce a value which has its upper bits set, only bit 4 - * (i.e., the inverted, shifted bottom address bit) actually - * gets used. - */ - - /* Ensure the address is in a register. */ - address = gen_reg_rtx(HImode); - emit_insn(gen_rtx_SET(HImode, address, XEXP(operands[1], 0))); - - /* Compute the word address by masking out the bottom bit. */ - wordAddress = gen_reg_rtx(HImode); - emit_insn(gen_andhi3(wordAddress, address, addressMask)); - - /* Compute the shift value. This is the bottom address bit, - * inverted, and multiplied by 8. */ - shiftVal = gen_reg_rtx(HImode); - emit_insn(gen_xorhi3(shiftVal, address, const1)); - emit_insn(gen_ashlhi3(shiftVal, shiftVal, GEN_INT(3))); - - /* Emit the memory load. */ - loadedValue = gen_reg_rtx(HImode); - emit_insn(gen_rtx_SET(HImode, loadedValue, gen_rtx_MEM(HImode, wordAddress))); - - /* Shift the desired byte to the most significant byte. */ - topByteValue = gen_reg_rtx (HImode); - emit_insn (gen_ashlhi3 (topByteValue, loadedValue, shiftVal)); - - /* Sign extend the top-byte back into the bottom byte. */ - signExtendedValue = gen_reg_rtx(HImode); - emit_insn(gen_ashrhi3(signExtendedValue, topByteValue, GEN_INT(8))); - - /* Final extraction of QI mode register. */ - operands[1] = gen_rtx_SUBREG(QImode, signExtendedValue, 0); - - } - - if (MEM == GET_CODE(operands[0]) && GET_CODE(operands[1]) != MEM) - { - rtx zeroingByteMask; - rtx temp; - rtx tempHiMode; - rtx lsbByteMask; - - /* Get the address. */ - address = gen_reg_rtx(HImode); - emit_insn(gen_rtx_SET(HImode, address, XEXP(operands[0], 0))); - - /* Compute the word aligned address. */ - wordAddress = gen_reg_rtx(HImode); - emit_insn(gen_andhi3(wordAddress, address, addressMask)); - - /* Compute the shift value. */ - shiftVal = gen_reg_rtx(HImode); - emit_insn(gen_andhi3(shiftVal, address, const1)); - emit_insn(gen_ashlhi3(shiftVal, shiftVal, GEN_INT(3))); - - /* Emit the memory load. */ - loadedValue = gen_reg_rtx(HImode); - emit_insn(gen_rtx_SET(HImode, loadedValue, gen_rtx_MEM(HImode, wordAddress))); - - /* Zero out the destination bits by AND'ing with 0xFF00 - * shifted appropriately. */ - zeroingByteMask = gen_reg_rtx(HImode); - emit_insn(gen_rtx_SET(HImode, zeroingByteMask, GEN_INT(-256))); - emit_insn(gen_lshrhi3(zeroingByteMask, zeroingByteMask, shiftVal)); - emit_insn(gen_andhi3(loadedValue, loadedValue, zeroingByteMask)); - - /* Grab the incoming QI register, and ensure that the top bits - * are zeroed out. This is because the register may be - * storing a signed value, in which case the top-bits will be - * sign bits. These must be removed to ensure that the - * read-modify-write (which uses an OR) doesn't pick up those - * bits, instead of the original memory value which is being - * modified. - */ - tempHiMode = simplify_gen_subreg(HImode, operands[1], QImode, 0); - temp = gen_reg_rtx(HImode); - emit_insn(gen_rtx_SET(HImode, temp, tempHiMode)); - lsbByteMask = gen_reg_rtx (HImode); - emit_insn (gen_rtx_SET (HImode, lsbByteMask, GEN_INT (0xFF))); - emit_insn (gen_andhi3 (temp, temp, lsbByteMask)); - - /* Shift the incoming byte value by the appropriate amount, - * and OR into the load value. */ - emit_insn(gen_ashlhi3(temp, temp, shiftVal)); - emit_insn(gen_iorhi3(loadedValue, loadedValue, temp)); - - /* Rewrite the original assignment, to assign the new value - * to the word address. */ - operands[0] = gen_rtx_MEM(HImode, wordAddress); - operands[1] = loadedValue; - - } - - } -}) - -(define_insn "*movqi_sign_extend" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (sign_extend:HI (match_operand:QI 1 "memory_operand" "a,m")))] - "TARGET_HAS_BYTE_ACCESS" - "@ - LDB (%a1),%0\t\t// %0 = Mem(%a1) - LDB %a1,%0\t\t// %0 = Mem(%M1{byte})" - [(set_attr "type" "mem,mem") - (set_attr "longConstant" "true,false") - (set_attr "length" "4,4")]) - -;; movqi instructions for machines with and without byte access. -(define_insn "*movqi_byte" - [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,r,r,a,m") - (match_operand:QI 1 "general_operand" "r,a,m,I,i,r,r"))] - "TARGET_HAS_BYTE_ACCESS" - "@ - COPY.%# %1, %0\t// %0 := %1 - LDB (%a1),%0\t\t// %0 = Mem(%a1) - LDB %a1,%0\t\t// %0 = Mem(%M1{byte}) - COPY.%# %1,%0\t\t// %0 := #%1 (QI) (short constant) - COPY.%# %1,%0\t\t// %0 := #%1 (QI) (long constant) - STB %1,(%a0)\t\t// Mem(%a0) := %1 - STB %1,%a0\t\t// Mem(%M0{byte}) := %1" - [(set_attr "type" "basicAlu,mem,mem,basicAlu,basicAlu,mem,mem") - (set_attr "longConstant" "false,true,false,false,true,true,false") - (set_attr "length" "2,4,4,2,4,4,4")]) - -;; Machines which don't have byte access can copy registers, and load -;; constants, but can't access memory. The define_expand for movqi -;; should already have rewritten memory accesses using word -;; operations. The exception is qi reloads, which are handled using -;; the reload_? patterns. -(define_insn "*movqi_nobyte" - [(set (match_operand:QI 0 "register_operand" "=r,r") - (match_operand:QI 1 "picochip_register_or_immediate_operand" "r,i"))] - "!TARGET_HAS_BYTE_ACCESS" - "@ - COPY.%# %1,%0\t// %0 := %1 - COPY.%# %1,%0\t\t// %0 := #%1 (QI)") - -(define_insn "movhi" - [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,a,m,r,r") - (match_operand:HI 1 "general_operand" "r,a,m,r,r,I,i"))] - "" - "@ - COPY.%# %1,%0\t\t// %0 := %1 - LDW (%a1),%0\t\t// %0 := Mem(%a1) - LDW %a1,%0\t\t// %0 = Mem(%M1{byte}) - STW %1,(%a0)\t\t// Mem(%a0) := %1 - STW %1,%a0\t\t// Mem(%M0{byte}) := %1 - COPY.%# %1,%0\t// %0 := %1 (short constant) - COPY.%# %1,%0\t// %0 := %1 (long constant)" - [(set_attr "type" "basicAlu,mem,mem,mem,mem,basicAlu,basicAlu") - (set_attr "longConstant" "false,true,false,true,false,false,true") - (set_attr "length" "2,4,4,4,4,2,4")]) - -(define_insn "movsi" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,a,m") - (match_operand:SI 1 "general_operand" "r,a,m,i,r,r"))] - "" - "@ - // %R0 := %R1 (SI)\n\tCOPY.%# %L1,%L0 %| COPY.1 %U1,%U0 - LDL (%a1),%R0\t\t// %R0 = Mem(%a1) - LDL %a1,%R0\t\t// %R0 = Mem(%M1{byte}) - // %R0 := #%1 (SI)\n\tCOPY.%# %L1,%L0 %| COPY.%# %U1,%U0 - STL %R1,(%a0)\t\t// Mem(%a0) := %R1 - STL %R1,%a0\t\t// Mem(%M0{byte}) := %R1" - [(set_attr "type" "unknown,mem,mem,unknown,mem,mem") - (set_attr "longConstant" "false,true,false,true,false,false") - (set_attr "length" "4,4,4,6,4,4")]) - -; Split an SI mode register copy into separate HI mode copies, which -; can be VLIW'd with other instructions. Only split the instruction -; when VLIW scheduling is enabled. Splitting the instruction saves -; some code space. -; -; This is predicated in reload_completed. This ensures that the -; instructions aren't broken up too early which can result in the -; SImode code being converted into inefficient HI mode code. - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "register_operand" ""))] - "reload_completed && picochip_schedule_type == DFA_TYPE_SPEED" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 4) (match_dup 5))] - "{ - operands[2] = gen_lowpart (HImode, operands[0]); - operands[3] = gen_lowpart (HImode, operands[1]); - operands[4] = gen_highpart (HImode, operands[0]); - operands[5] = gen_highpart (HImode, operands[1]); - }") - -; SI Mode split for load constant. -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "reload_completed" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 4) (match_dup 5))] - "{ - operands[2] = gen_lowpart (HImode, operands[0]); - operands[3] = picochip_get_low_const(operands[1]); - operands[4] = gen_highpart (HImode, operands[0]); - operands[5] = picochip_get_high_const(operands[1]); - }") - -(define_insn "movsf" - [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r,m") - (match_operand:SF 1 "general_operand" "r,m,i,r"))] - "" - "@ - // %R0 := %R1 (SF)\n\tCOPY.%# %L1,%L0 %| COPY.1 %U1,%U0 - LDL %a1,%R0\t\t// %R0 :={SF} Mem(%M1{byte}) - // %R0 := #%1 (SF)\n\tCOPY.%# %L1,%L0\n\tCOPY.%# %U1,%U0 - STL %R1,%a0\t\t// Mem(%M0{byte}) :={SF} %R1") - -;; memcpy pattern -;; 0 = destination (mem:BLK ...) -;; 1 = source (mem:BLK ...) -;; 2 = count -;; 3 = alignment -(define_expand "movmemhi" - [(match_operand 0 "memory_operand" "") - (match_operand 1 "memory_operand" "") - (match_operand:HI 2 "immediate_operand" "") - (match_operand 3 "" "")] - "picochip_schedule_type != DFA_TYPE_NONE" - "if (picochip_expand_movmemhi(operands)) DONE; FAIL;" -) - -;;=========================================================================== -;; NOP -;;=========================================================================== - -;; No-operation (NOP) -(define_insn "nop" - [(const_int 0)] - "" - "NOP\t// nop" - [(set_attr "length" "1")]) - -;;=========================================================================== -;; Function Calls. Define expands are used to ensure that the correct -;; type of pattern is emitted, and then the define_insn's match the -;; pattern using the correct types. -;; -;; Note: The comments output as part of these instructions are detected by -;; the linker. Don't change the comments! -;;=========================================================================== - -(define_expand "call" - [(parallel [(call (match_operand:QI 0 "memory_operand" "") - (match_operand 1 "const_int_operand" "")) - (clobber (reg:HI LINK_REGNUM))])] - "" - "") - -(define_insn "call_for_divmod" - [(call (match_operand:QI 0 "memory_operand" "") - (match_operand 1 "const_int_operand" ""))] - "" - "JL (%M0)\t// fn_call %M0%>" - [(set_attr "length" "4") - (set_attr "type" "realBranch") - (set_attr "longConstant" "true")]) - -(define_insn "*call_using_symbol" - [(call (mem:QI (match_operand:HI 0 "immediate_operand" "i")) - (match_operand 1 "const_int_operand" "")) - (clobber (reg:HI LINK_REGNUM))] - "" - "JL (%M0)\t// fn_call %M0%>" - [(set_attr "length" "4") - (set_attr "type" "realBranch") - (set_attr "longConstant" "true")]) - -(define_insn "*call_using_register" - [(call (mem:QI (match_operand:HI 0 "register_operand" "r")) - (match_operand 1 "const_int_operand" "")) - (clobber (reg:HI LINK_REGNUM))] - "" - "JL (%r0)\t// fn_call_unknown %r0%>" - [(set_attr "length" "2") - (set_attr "type" "realBranch") - (set_attr "longConstant" "false")]) - -(define_expand "call_value" - [(parallel [(set (match_operand:HI 0 "" "") - (call:HI (match_operand:QI 1 "memory_operand" "g") - (match_operand 2 "const_int_operand" ""))) - (clobber (reg:HI LINK_REGNUM))])] - "" - "") - -(define_insn "*call_value_using_symbol" - [(set (match_operand:HI 0 "" "") - (call:HI (mem:QI (match_operand:HI 1 "immediate_operand" "i")) - (match_operand 2 "const_int_operand" ""))) - (clobber (reg:HI LINK_REGNUM))] - "" - "JL (%M1)\t// fn_call %M1 (value return)%>" - [(set_attr "length" "4") - (set_attr "type" "realBranch") - (set_attr "longConstant" "true")]) - -(define_insn "*call_value_using_register" - [(set (match_operand:HI 0 "" "") - (call:HI (mem:QI (match_operand:HI 1 "register_operand" "r")) - (match_operand 2 "const_int_operand" ""))) - (clobber (reg:HI LINK_REGNUM))] - "" - "JL (%r1)// fn_call_unknown %r1 (value return)%>" - [(set_attr "length" "2") - (set_attr "type" "realBranch") - (set_attr "longConstant" "false")]) - -;;=========================================================================== -;; Addition -;;=========================================================================== - -;; Note that the addition of a negative value is transformed into the -;; subtraction of a positive value, so that the add/sub immediate slot -;; can make better use of the 4-bit range. - -(define_insn "addhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r,r,r") - (plus:HI (match_operand:HI 1 "register_operand" "r,r,r,r") - (match_operand:HI 2 "general_operand" "r,M,n,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - { if (CONST_INT == GET_CODE(operands[2]) && - INTVAL(operands[2]) > -16 && - INTVAL(operands[2]) < 0) - return "SUB.%# %1,-(%2),%0\t// %0 := %1 + %2 (HI)"; - else - return "ADD.%# %1,%2,%0\t// %0 := %1 + %2 (HI)"; - } - [(set_attr "type" "basicAlu,basicAlu,basicAlu,basicAlu") - (set_attr "longConstant" "false,false,true,true") - (set_attr "length" "2,2,4,4")] - ) - - -;; If we peepholed the compare instruction out, we need to make sure the add -;; goes in slot 0. This pattern is just to accomplish that. - -(define_insn "addhi3_with_use_clause" - [(set (match_operand:HI 0 "register_operand" "=r,r,r,r") - (plus:HI (match_operand:HI 1 "register_operand" "r,r,r,r") - (match_operand:HI 2 "general_operand" "r,M,n,i"))) - (set (reg:CC CC_REGNUM) - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(const_int 0) - (const_int 0)]))] - "" - { if (CONST_INT == GET_CODE(operands[2]) && - INTVAL(operands[2]) > -16 && - INTVAL(operands[2]) < 0) - return "SUB.0 %1,-(%2),%0\t// %0 := %1 + %2 (HI)"; - else - return "ADD.0 %1,%2,%0\t// %0 := %1 + %2 (HI)"; - } - [(set_attr "type" "picoAlu,picoAlu,picoAlu,picoAlu") - (set_attr "longConstant" "false,false,true,true") - (set_attr "length" "2,2,4,4")] - ) - -;; Match an addition in which the first operand has been shifted -;; (e.g., the comms array functions can emit such instructions). -(define_insn "*addWith1stOpShift" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (plus:HI (ashift:HI (match_operand:HI 1 "register_operand" "r,r") - (match_operand:HI 2 "const_int_operand" "")) - (match_operand:HI 3 "immediate_operand" "I,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - "ADD.0 [LSL %1,%2],%3,%0\t// %0 := (%1 << %2) + %3" - [(set_attr "type" "picoAlu,picoAlu") - (set_attr "longConstant" "false,true")]) - -(define_insn_and_split "addsi3" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (plus:SI (match_operand:SI 1 "register_operand" "r,r") - (match_operand:SI 2 "general_operand" "r,i"))) - (clobber (reg:CC CC_REGNUM))] - "" - "// %0 := %1 + %2 (SI)\n\tADD.0 %L1,%L2,%L0\n\tADDC.0 %U1,%U2,%U0" - "reload_completed && picochip_schedule_type != DFA_TYPE_NONE" - [(match_dup 4) - (match_dup 5)] - " -{ - rtx op0_high = gen_highpart (HImode, operands[0]); - rtx op1_high = gen_highpart (HImode, operands[1]); - rtx op0_low = gen_lowpart (HImode, operands[0]); - rtx op1_low = gen_lowpart (HImode, operands[1]); - rtx op2_high, op2_low; - - if (CONST_INT == GET_CODE(operands[2])) - { - op2_high = picochip_get_high_const(operands[2]); - op2_low = picochip_get_low_const(operands[2]); - } else { - op2_high = gen_highpart (HImode, operands[2]); - op2_low = gen_lowpart (HImode, operands[2]); - } - - operands[4] = gen_add_multi_lower (op0_low, op1_low, op2_low); - operands[5] = gen_add_multi_upper (op0_high, op1_high, op2_high); - -}") - -;; Perform the lowest part of a multi-part addition (SI/DI). This sets -;; the flags, so is an picoAlu instruction (we could use a -;; conventional addhi, but the addhi is better off being a treated as -;; a basicAlu instruction, rather than a picoAlu instruction). -(define_insn "add_multi_lower" - [(set (match_operand:HI 0 "register_operand" "=r,r,r") - (plus:HI (match_operand:HI 1 "register_operand" "r,r,r") - (match_operand:HI 2 "general_operand" "r,M,i"))) - (set (reg:CC CC_REGNUM) - (compare:CC (plus:HI (match_dup 1) - (match_dup 2)) - (const_int 0)))] - "" - { if (CONST_INT == GET_CODE(operands[2]) && - INTVAL(operands[2]) > -16 && - INTVAL(operands[2]) < 0) - return "SUB.%# %1,-(%2),%0\t// %0+carry := %1 + %2 (low multi-part)"; - else - return "ADD.%# %1,%2,%0\t// %0+carry := %1 + %2 (low multi-part)"; - } - [(set_attr "type" "picoAlu,picoAlu,picoAlu") - (set_attr "longConstant" "false,false,true") - (set_attr "length" "2,2,4")]) - -;; Perform the central part of a multi-part addition (DI). This uses -;; the CC register, and also sets the CC register, so needs to be -;; placed in the first ALU slot. Note that the ADDC must -;; use the long constant to represent immediates. -(define_insn "add_multi_mid" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (plus:HI (match_operand:HI 1 "register_operand" "r,r") - (plus:HI (match_operand:HI 2 "general_operand" "r,i") - (reg:CC CC_REGNUM)))) - (set (reg:CC CC_REGNUM) - (compare:CC (plus:HI (match_dup 1) - (match_dup 2)) - (const_int 0)))] - "" - "ADDC.%# %1,%2,%0\t// %0+carry := carry + %1 + %2 (mid multi-part)" - [(set_attr "type" "picoAlu,picoAlu") - (set_attr "longConstant" "false,true") - (set_attr "length" "2,4")]) - -;; Perform the highest part of a multi-part addition (SI/DI). This -;; uses the CC register, but doesn't require any registers to be set, -;; so may be scheduled in either of the ALU's. Note that the ADDC must -;; use the long constant to represent immediates. -(define_insn "add_multi_upper" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (plus:HI (match_operand:HI 1 "register_operand" "r,r") - (plus:HI (match_operand:HI 2 "general_operand" "r,i") - (reg:CC CC_REGNUM)))) - (clobber (reg:CC CC_REGNUM))] - "" - "ADDC.%# %1,%2,%0\t// %0 := carry + %1 + %2 (high multi-part)" - [(set_attr "type" "basicAlu,basicAlu") - (set_attr "longConstant" "false,true") - (set_attr "length" "2,4")]) - -;; The lea instruction is a special type of add operation, which looks -;; like a movhi (reg := address). It expands into reg := fp + -;; offset. Ideally there should be two variants, which take different -;; sized offsets (i.e., using the long constant, or not, as -;; appropriate). However, the address operand may have arbitrary -;; values added to it later (i.e., the AP will be eliminated, possibly -;; converting a small offset into a long offset), so a long offset is -;; always assumed. - -;; Note that the lea can use an addition, and hence may modify the CC -;; register. This upsets scheduling, so instead the lea is placed in -;; ALU 1 where it cannot modify CC. - -(define_insn "*lea_add" - [(set (match_operand:HI 0 "nonimmediate_operand" "=r") - (plus:HI (match_operand:HI 1 "register_operand" "r") - (match_operand:HI 2 "immediate_operand" "i")))] - "" - "ADD.1 %1,%2,%0\t// lea (add)") - -;; Note that, though this instruction looks similar to movhi pattern, -;; "p" constraint cannot be specified for operands other than -;; address_operand, hence the extra pattern below. -(define_insn "*lea_move" - [(set (match_operand:HI 0 "nonimmediate_operand" "=r") - (match_operand:HI 1 "address_operand" "p"))] - "" - { - if (REG == GET_CODE(operands[1])) - return "COPY.1 %1,%0\t// %0 := %1 (lea)"; - else - return "ADD.1 %b1,%o1,%0\t\t// %0 := %b1 + %o1 (lea)"; - } - [(set_attr "type" "nonCcAlu") - (set_attr "longConstant" "true") - (set_attr "length" "4")]) - - -;;=========================================================================== -;; Subtraction. Note that these patterns never take immediate second -;; operands, since those cases are handled by canonicalising the -;; instruction into the addition of a negative costant. -;; But, if the first operand needs to be a negative constant, it -;; is supported here. -;;=========================================================================== - -(define_insn "subhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r,r") - (minus:HI (match_operand:HI 1 "general_operand" "r,I,i") - (match_operand:HI 2 "register_operand" "r,r,r"))) - (clobber (reg:CC CC_REGNUM))] - "" - "SUB.%# %1,%2,%0 // %0 := %1 - %2 (HI)" - [(set_attr "type" "basicAlu,basicAlu,basicAlu") - (set_attr "longConstant" "false,true,true") - (set_attr "length" "2,4,4")]) - -;; If we peepholed the compare instruction out, we need to make sure the -;; sub goes in slot 0. This pattern is just to accomplish that. - -(define_insn "subhi3_with_use_clause" - [(set (match_operand:HI 0 "register_operand" "=r,r,r") - (minus:HI (match_operand:HI 1 "general_operand" "r,I,i") - (match_operand:HI 2 "register_operand" "r,r,r"))) - (set (reg:CC CC_REGNUM) - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(const_int 0) - (const_int 0)]))] - "" - "SUB.0 %1,%2,%0 // %0 := %1 - %2 (HI)" - [(set_attr "type" "picoAlu,picoAlu,picoAlu") - (set_attr "longConstant" "false,true,true") - (set_attr "length" "2,4,4")]) - -(define_insn_and_split "subsi3" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (minus:SI (match_operand:SI 1 "general_operand" "r,i") - (match_operand:SI 2 "register_operand" "r,r"))) - (clobber (reg:CC CC_REGNUM))] - "" - "// %0 := %1 - %2 (SI)\n\tSUB.%# %L1,%L2,%L0\n\tSUBB.%# %U1,%U2,%U0" - "reload_completed && picochip_schedule_type != DFA_TYPE_NONE" - [(match_dup 4) - (match_dup 5)] - " -{ - rtx op0_high = gen_highpart (HImode, operands[0]); - rtx op0_low = gen_lowpart (HImode, operands[0]); - rtx op2_high = gen_highpart (HImode, operands[2]); - rtx op2_low = gen_lowpart (HImode, operands[2]); - rtx op1_high,op1_low; - - if (CONST_INT == GET_CODE(operands[1])) - { - op1_high = picochip_get_high_const(operands[1]); - op1_low = picochip_get_low_const(operands[1]); - } else { - op1_high = gen_highpart (HImode, operands[1]); - op1_low = gen_lowpart (HImode, operands[1]); - } - - - operands[4] = gen_sub_multi_lower (op0_low, op1_low, op2_low); - operands[5] = gen_sub_multi_upper (op0_high, op1_high, op2_high); - -}") - -;; Match the patterns emitted by the multi-part subtraction splitting. -;; This sets the CC register, so it needs to go into slot 0. -(define_insn "sub_multi_lower" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (minus:HI (match_operand:HI 1 "general_operand" "r,i") - (match_operand:HI 2 "register_operand" "r,r"))) - (set (reg:CC CC_REGNUM) - (compare:CC (minus:HI (match_dup 1) (match_dup 2)) - (const_int 0)))] - "" - "SUB.%# %1,%2,%0\t// %0+carry := %1 - %2 (lower SI)" - [(set_attr "type" "picoAlu,picoAlu") - (set_attr "longConstant" "false,true") - (set_attr "length" "2,4")]) - -;; Perform the central part of a multi-part addition (DI). This uses -;; the CC register, and also sets the CC register, so needs to be -;; placed in the first ALU. -(define_insn "sub_multi_mid" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (minus:HI (match_operand:HI 1 "general_operand" "r,i") - (minus:HI (match_operand:HI 2 "register_operand" "r,r") - (reg:CC CC_REGNUM)))) - (set (reg:CC CC_REGNUM) - (compare:CC (minus:HI (match_dup 1) - (match_dup 2)) - (const_int 0)))] - "" - "SUBB.%# %1,%2,%0\t// %0+carry := carry - %1 - %2 (mid multi-part)" - [(set_attr "type" "picoAlu,picoAlu") - (set_attr "longConstant" "false,true") - (set_attr "length" "2,4")]) - -(define_insn "sub_multi_upper" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (minus:HI (match_operand:HI 1 "general_operand" "r,i") - (minus:HI (match_operand:HI 2 "register_operand" "r,r") - (reg:CC CC_REGNUM)))) - (clobber (reg:CC CC_REGNUM))] - "" - "SUBB.%# %1,%2,%0\t// %0 := carry - %1 - %2 (upper SI)" - [(set_attr "type" "basicAlu,basicAlu") - (set_attr "longConstant" "false,true") - (set_attr "length" "2,4")]) - -;;=========================================================================== -;; Multiplication (signed) -;;=========================================================================== - -(define_insn "multiply_machi" - [(set (reg:HI ACC_REGNUM) - (mult:HI (match_operand:HI 0 "register_operand" "r,r") - (match_operand:HI 1 - "picochip_register_or_immediate_operand" "r,i")))] - "TARGET_HAS_MAC_UNIT" - "MUL %0,%1,acc0\t// acc0 := %0 * %1 (signed)" - [(set_attr "length" "3,5") - (set_attr "type" "mac,mac") - (set_attr "longConstant" "false,true")]) - -(define_expand "mulhi3" - [(set (match_operand:HI 0 "register_operand" "") - (mult:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "picochip_register_or_immediate_operand" "")))] - "TARGET_HAS_MULTIPLY" - "") - -;; Different types of mulhi, depending on the AE type. If the AE has MUL unit, -;; use the following pattern. -(define_insn "*mulhi3_mul" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (mult:HI (match_operand:HI 1 "register_operand" "r,r") - (match_operand:HI 2 - "picochip_register_or_immediate_operand" "r,i")))] - "TARGET_HAS_MUL_UNIT" - "MULL %1,%2,%0 // %0 := %1 * %2 (HI)" - [(set_attr "length" "3,5") - (set_attr "type" "mul,mul") - (set_attr "longConstant" "false,true")]) - -;; If the AE has MAC unit, instead, use the following pattern. -(define_insn_and_split "*mulhi3_mac" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (mult:HI (match_operand:HI 1 "register_operand" "r,r") - (match_operand:HI 2 - "picochip_register_or_immediate_operand" "r,i")))] - "TARGET_HAS_MAC_UNIT" - "// %0 := %1 * %2\n\tMUL %1,%2,acc0\n\tREADACC acc0,frac,%0" - "TARGET_HAS_MAC_UNIT && reload_completed" - [(match_dup 3) - (match_dup 4)] - " -{ - rtx const_rtx = GEN_INT(0); - operands[3] = (gen_multiply_machi(operands[1], operands[2])); - operands[4] = (gen_movhi_mac(operands[0],const_rtx)); -} " -) - -(define_insn "umultiply_machisi" - [(set (reg:SI ACC_REGNUM) - (mult:SI (zero_extend:SI (match_operand:HI 0 "register_operand" "r")) - (zero_extend:SI (match_operand:HI 1 "register_operand" "r"))))] - "TARGET_HAS_MAC_UNIT" - "MULUU %0,%1,acc0\t// acc0 := %0 * %1 (unsigned)" - [(set_attr "length" "3") - (set_attr "type" "mac") - (set_attr "longConstant" "false")]) - -(define_insn "multiply_machisi" - [(set (reg:SI ACC_REGNUM) - (mult:SI (sign_extend:SI (match_operand:HI 0 "register_operand" "r,r")) - (sign_extend:SI (match_operand:HI 1 - "picochip_register_or_immediate_operand" "r,i"))))] - "TARGET_HAS_MAC_UNIT" - "MUL %0,%1,acc0\t// acc0 := %0 * %1 (signed)" - [(set_attr "length" "3,5") - (set_attr "type" "mac,mac") - (set_attr "longConstant" "false,true")]) - -;; We want to prevent GCC from thinking ACC is a normal register and using -;; this pattern. We want it to be used only when you use MAC unit -;; multiplication. Added a "use" clause for that sake. -(define_insn "movsi_mac" - [(set (match_operand:SI 0 "register_operand" "=r") - (reg:SI ACC_REGNUM)) - (use (match_operand:SI 1 "const_int_operand" ""))] - "TARGET_HAS_MAC_UNIT" - "READACC32 acc0,%R0 \t// %0 := acc0 " - [(set_attr "length" "3") - (set_attr "type" "mac") - (set_attr "longConstant" "false")]) - -;; We want to prevent GCC from thinking ACC is a normal register and using -;; this pattern. We want it to be used only when you use MAC unit -;; multiplication. Added a "use" clause for that sake. -(define_insn "movhi_mac" - [(set (match_operand:HI 0 "register_operand" "=r") - (reg:HI ACC_REGNUM) ) - (use (match_operand:HI 1 "const_int_operand" ""))] - "TARGET_HAS_MAC_UNIT" - "READACC acc0,frac,%0 \t// %0 := acc0 " - [(set_attr "length" "3") - (set_attr "type" "mac") - (set_attr "longConstant" "false")]) - -;; 16-bit to 32-bit widening signed multiplication. -(define_expand "mulhisi3" - [(set (match_operand:SI 0 "register_operand" "=&r") - (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "r")) - (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] - "TARGET_HAS_MULTIPLY" - "" -) - -(define_insn_and_split "*mulhisi3_mul" - [(set (match_operand:SI 0 "register_operand" "=&r") - (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "r")) - (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] - "TARGET_HAS_MUL_UNIT" - "// %0 := %1 * %2 (HI->SI)\;MULL %1,%2,%L0\;MULH %1,%2,%U0"; - "TARGET_HAS_MUL_UNIT && reload_completed && picochip_schedule_type != DFA_TYPE_NONE" - [(match_dup 3) - (match_dup 4)] - " -{ - rtx op0_high = gen_highpart (HImode, operands[0]); - rtx op0_low = gen_lowpart (HImode, operands[0]); - operands[3] = gen_mulhisi3_mul_lower(op0_low,operands[1],operands[2]); - operands[4] = gen_mulhisi3_mul_higher(op0_high,operands[1],operands[2]); -} - " -) - -(define_insn "mulhisi3_mul_lower" - [(set (match_operand:HI 0 "register_operand" "=&r") - (subreg:HI - (mult:SI - (sign_extend:SI (match_operand:HI 1 "register_operand" "r")) - (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))) 0))] - "TARGET_HAS_MUL_UNIT" - "MULL %1,%2,%0" - [(set_attr "length" "3") - (set_attr "type" "mul") - (set_attr "longConstant" "false")]) - -(define_insn "mulhisi3_mul_higher" - [(set (match_operand:HI 0 "register_operand" "=&r") - (subreg:HI - (mult:SI - (sign_extend:SI (match_operand:HI 1 "register_operand" "r")) - (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))) 2))] - "TARGET_HAS_MUL_UNIT" - "MULH %1,%2,%0" - [(set_attr "length" "3") - (set_attr "type" "mul") - (set_attr "longConstant" "false")]) - -(define_insn_and_split "*mulhisi3_mac" - [(set (match_operand:SI 0 "register_operand" "=&r") - (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "r")) - (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] - "TARGET_HAS_MAC_UNIT" - "// %0 := %1 * %2 (HI->SI) STAN2\;MUL %1,%2,acc0\;READACC32 acc0,%R0"; - "TARGET_HAS_MAC_UNIT && reload_completed" - [(match_dup 3) - (match_dup 4)] - " -{ - rtx const_rtx = gen_int_mode(0,SImode); - operands[3] = (gen_multiply_machisi(operands[1], operands[2])); - operands[4] = (gen_movsi_mac(operands[0],const_rtx)); -} " -) - -;;=========================================================================== -;; Widening multiplication (unsigned) -;;=========================================================================== - -(define_expand "umulhisi3" - [(set (match_operand:SI 0 "register_operand" "=&r") - (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) - (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] - "TARGET_HAS_MULTIPLY" - "" -) - -(define_insn_and_split "*umulhisi3_mul" - [(set (match_operand:SI 0 "register_operand" "=&r") - (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) - (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] - "TARGET_HAS_MUL_UNIT" - "// %0 := %1 * %2 (uHI->uSI Type 1)\;MULUL %1,%2,%L0\n\tMULUH %1,%2,%U0"; - "TARGET_HAS_MUL_UNIT && reload_completed && picochip_schedule_type != DFA_TYPE_NONE" - [(match_dup 3) - (match_dup 4)] - " -{ - rtx op0_high = gen_highpart (HImode, operands[0]); - rtx op0_low = gen_lowpart (HImode, operands[0]); - operands[3] = gen_umulhisi3_mul_lower(op0_low,operands[1],operands[2]); - operands[4] = gen_umulhisi3_mul_higher(op0_high,operands[1],operands[2]); -} - " - ) - -(define_insn "umulhisi3_mul_lower" - [(set (match_operand:HI 0 "register_operand" "=&r") - (subreg:HI - (mult:SI - (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) - (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))) 0))] - "TARGET_HAS_MUL_UNIT" - "MULUL %1,%2,%0" - [(set_attr "length" "3") - (set_attr "type" "mul") - (set_attr "longConstant" "false")]) - -(define_insn "umulhisi3_mul_higher" - [(set (match_operand:HI 0 "register_operand" "=&r") - (subreg:HI - (mult:SI - (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) - (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))) 2))] - "TARGET_HAS_MUL_UNIT" - "MULUH %1,%2,%0" - [(set_attr "length" "3") - (set_attr "type" "mul") - (set_attr "longConstant" "false")]) - -(define_insn_and_split "*umulhisi3_mac" - [(set (match_operand:SI 0 "register_operand" "=&r") - (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) - (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] - "TARGET_HAS_MAC_UNIT" - "// %0 := %1 * %2 (uHI->uSI Type 3)\;MULUU %1,%2,acc0\;READACC32 acc0,%R0"; - "TARGET_HAS_MAC_UNIT && reload_completed" - [(match_dup 3) - (match_dup 4)] - " -{ - rtx const_rtx = gen_int_mode(0,SImode); - operands[3] = (gen_umultiply_machisi(operands[1], operands[2])); - operands[4] = (gen_movsi_mac(operands[0],const_rtx)); -} " -) - -;;=========================================================================== -;; Division (signed) -;;=========================================================================== - -;; Perform a divmod operation as a function call. This results in some -;; registers being clobbered (r0-6, r12 - ignore r13,14 as these are -;; known not to be affected). -(define_expand "divmodhi4" - [ - ; Copy the inputs to r0 and r1. - (set (reg:HI 0) (match_operand:HI 1 "register_operand" "")) - (set (reg:HI 1) (match_operand:HI 2 "register_operand" "")) - ; Make the function call - note that r12 (link) is clobbered. Note also - ; that an explicit call is generated. This ensures that gcc notices that - ; any function containing a div/mod is not a leaf function. - (parallel [(match_dup 4) - (set (reg:HI 0) (div:HI (reg:HI 0) (reg:HI 1))) - (set (reg:HI 1) (mod:HI (reg:HI 0) (reg:HI 1))) - (clobber (reg:HI 2)) - (clobber (reg:HI 3)) - (clobber (reg:HI 4)) - (clobber (reg:HI 5)) - (clobber (reg:HI 12)) - (clobber (reg:CC CC_REGNUM)) - ]) - ; Set the quotient (returned in register 0) - (set (match_operand:HI 0 "register_operand" "") (reg:HI 0)) - ; Set the remainder (returned in register 1) - (set (match_operand:HI 3 "register_operand" "") (reg:HI 1))] - "" -{ - rtx fnName = gen_rtx_SYMBOL_REF (HImode, "_divmodhi4"); - operands[4] = gen_call_for_divmod (gen_rtx_MEM (QImode, fnName), GEN_INT(0)); -}) - -; Match a call to divmodhi4. As this is a call, the link register -; (r12), and registers r0-5 must be clobbered. Ignore clobbering of -; r13/4 as these aren't used by the divide function). -(define_insn "*divmodhi4_call" - [(call (mem:QI (match_operand:HI 0 "immediate_operand" "i")) - (match_operand 1 "const_int_operand" "")) - (set (reg:HI 0) (div:HI (reg:HI 0) (reg:HI 1))) - (set (reg:HI 1) (mod:HI (reg:HI 0) (reg:HI 1))) - (clobber (reg:HI 2)) - (clobber (reg:HI 3)) - (clobber (reg:HI 4)) - (clobber (reg:HI 5)) - (clobber (reg:HI 12)) - (clobber (reg:CC CC_REGNUM)) -] - "" - "JL (%0)\t// call %0%>" - [(set_attr "length" "4") - (set_attr "longConstant" "true") - (set_attr "type" "call")]) - -;; Perform a udivmod operation as a function call. This results in some -;; registers being clobbered (r0-6, r12 - ignore r13,14 as these are -;; known not to be affected). -(define_expand "udivmodhi4" - [ - ; Copy the inputs to r0 and r1. - (set (reg:HI 0) (match_operand:HI 1 "register_operand" "")) - (set (reg:HI 1) (match_operand:HI 2 "register_operand" "")) - ; Make the function call - note that r12 (link) is clobbered. Note also - ; that an explicit call is generated. This ensures that gcc notices that - ; any function containing a div/mod is not a leaf function. - (parallel [(match_dup 4) - (set (reg:HI 0) (udiv:HI (reg:HI 0) (reg:HI 1))) - (set (reg:HI 1) (umod:HI (reg:HI 0) (reg:HI 1))) - (clobber (reg:HI 2)) - (clobber (reg:HI 3)) - (clobber (reg:HI 4)) - (clobber (reg:HI 5)) - (clobber (reg:HI 12)) - (clobber (reg:CC CC_REGNUM)) - ]) - ; Set the quotient (returned in register 0) - (set (match_operand:HI 0 "register_operand" "") (reg:HI 0)) - ; Set the remainder (returned in register 1) - (set (match_operand:HI 3 "register_operand" "") (reg:HI 1))] - "" -{ - rtx fnName = gen_rtx_SYMBOL_REF (HImode, "_udivmodhi4"); - operands[4] = gen_call_for_divmod (gen_rtx_MEM (QImode, fnName), GEN_INT(0)); -}) - -; Match a call to udivmodhi4. As this is a call, the link register -; (r12), and registers r0-5 must be clobbered. Ignore clobbering of -; r13/4 as these aren't used by the divide function). -(define_insn "*udivmodhi4_call" - [(call (mem:QI (match_operand:HI 0 "immediate_operand" "i")) - (match_operand 1 "const_int_operand" "")) - (set (reg:HI 0) (udiv:HI (reg:HI 0) (reg:HI 1))) - (set (reg:HI 1) (umod:HI (reg:HI 0) (reg:HI 1))) - (clobber (reg:HI 2)) - (clobber (reg:HI 3)) - (clobber (reg:HI 4)) - (clobber (reg:HI 5)) - (clobber (reg:HI 12)) - (clobber (reg:CC CC_REGNUM))] - "" - "JL (%0)\t// call %0%>" - [(set_attr "length" "4") - (set_attr "longConstant" "true") - (set_attr "type" "call")]) - -(define_expand "udivmodsi4" - [ - ; Make the function call - (set (reg:SI 0) (match_operand:SI 1 "register_operand" "")) - (set (reg:SI 2) (match_operand:SI 2 "register_operand" "")) - (parallel [ - (match_dup 4) - (set (reg:SI 4) (udiv:SI (reg:SI 0) (reg:SI 2))) - (set (reg:SI 6) (umod:SI (reg:SI 0) (reg:SI 2))) - (clobber (reg:SI 0)) - (clobber (reg:SI 2)) - (clobber (reg:HI 12)) - (clobber (reg:CC CC_REGNUM))]) - (set (match_operand:SI 0 "register_operand" "") (reg:SI 4)) - (set (match_operand:SI 3 "register_operand" "") (reg:SI 6))] - "" -{ - rtx fnName = gen_rtx_SYMBOL_REF (HImode, "_udivmodsi4"); - operands[4] = gen_call_for_divmod (gen_rtx_MEM (QImode, fnName), GEN_INT(0)); -}) - -(define_insn "*udivmodsi4_call" - [(call (mem:QI (match_operand:HI 0 "immediate_operand" "i")) - (match_operand 1 "const_int_operand" "")) - (set (reg:SI 4) (udiv:SI (reg:SI 0) (reg:SI 2))) - (set (reg:SI 6) (umod:SI (reg:SI 0) (reg:SI 2))) - (clobber (reg:SI 0)) - (clobber (reg:SI 2)) - (clobber (reg:HI 12)) - (clobber (reg:CC CC_REGNUM))] - "" - "JL (%0)\t// call %0%>" - [(set_attr "length" "4") - (set_attr "longConstant" "true") - (set_attr "type" "call")]) - -(define_expand "divmodsi4" - [ - ; Make the function call - (set (reg:SI 0) (match_operand:SI 1 "register_operand" "")) - (set (reg:SI 2) (match_operand:SI 2 "register_operand" "")) - (parallel [ - (match_dup 4) - (set (reg:SI 4) (div:SI (reg:SI 0) (reg:SI 2))) - (set (reg:SI 6) (mod:SI (reg:SI 0) (reg:SI 2))) - (clobber (reg:SI 0)) - (clobber (reg:SI 2)) - (clobber (reg:HI 12)) - (clobber (reg:CC CC_REGNUM))]) - (set (match_operand:SI 0 "register_operand" "") (reg:SI 4)) - (set (match_operand:SI 3 "register_operand" "") (reg:SI 6))] - "" -{ - rtx fnName = gen_rtx_SYMBOL_REF (HImode, "_divmodsi4"); - operands[4] = gen_call_for_divmod (gen_rtx_MEM (QImode, fnName), GEN_INT(0)); -}) - -(define_insn "*divmodsi4_call" - [(call (mem:QI (match_operand:HI 0 "immediate_operand" "i")) - (match_operand 1 "const_int_operand" "")) - (set (reg:SI 4) (div:SI (reg:SI 0) (reg:SI 2))) - (set (reg:SI 6) (mod:SI (reg:SI 0) (reg:SI 2))) - (clobber (reg:SI 0)) - (clobber (reg:SI 2)) - (clobber (reg:HI 12)) - (clobber (reg:CC CC_REGNUM))] - "" - "JL (%0)\t// call %0%>" - [(set_attr "length" "4") - (set_attr "longConstant" "true") - (set_attr "type" "call")]) - -;;=========================================================================== -;; Bitwise AND. The QI/SI mode instructions are automatically -;; synthesised from the HI mode instruction. -;;=========================================================================== - -(define_insn "andhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (and:HI (match_operand:HI 1 "register_operand" "r,r") - (match_operand:HI 2 "general_operand" "r,n"))) - (clobber (reg:CC CC_REGNUM))] - "" - "AND.%# %1,%2,%0 // %0 := %1 AND %2 (HI)" - [(set_attr "type" "basicAlu,basicAlu") - (set_attr "longConstant" "false,true") - (set_attr "length" "3,5")]) - -;; If we peepholed the compare instruction out, we need to make sure the -;; "and" goes in slot 0. This pattern is just to accomplish that. - -(define_insn "andhi3_with_use_clause" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (and:HI (match_operand:HI 1 "register_operand" "r,r") - (match_operand:HI 2 "general_operand" "r,n"))) - (set (reg:CC CC_REGNUM) - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(const_int 0) - (const_int 0)]))] - "" - "AND.0 %1,%2,%0 // %0 := %1 AND %2 (HI)" - [(set_attr "type" "picoAlu,picoAlu") - (set_attr "longConstant" "false,true") - (set_attr "length" "3,5")]) - -;;=========================================================================== -;; Bitwise inclusive-OR. The QI mode instruction is automatically -;; synthesised from the HI mode instruction. -;;=========================================================================== - -(define_insn "iorhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (ior:HI (match_operand:HI 1 "register_operand" "r,r") - (match_operand:HI 2 "register_operand" "r,n"))) - (clobber (reg:CC CC_REGNUM))] - "" - "OR.%# %1,%2,%0 // %0 := %1 IOR %2 (HI)" - [(set_attr "type" "basicAlu,basicAlu") - (set_attr "longConstant" "false,true") - (set_attr "length" "3,5")]) - -(define_insn "iorhi3_with_use_clause" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (ior:HI (match_operand:HI 1 "register_operand" "r,r") - (match_operand:HI 2 "general_operand" "r,n"))) - (set (reg:CC CC_REGNUM) - (match_operator:CC 3 "picochip_peephole_comparison_operator" - [(const_int 0) - (const_int 0)]))] - "" - "OR.0 %1,%2,%0 // %0 := %1 IOR %2 (HI)" - [(set_attr "type" "picoAlu,picoAlu") - (set_attr "longConstant" "false,true") - (set_attr "length" "3,5")]) - -;;=========================================================================== -;; Bitwise exclusive-OR. The QI/SI mode instructions are automatically -;; synthesised from the HI mode instruction. -;;=========================================================================== - -(define_insn "xorhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (xor:HI (match_operand:HI 1 "register_operand" "r,r") - (match_operand:HI 2 "picochip_register_or_immediate_operand" "r,n"))) - (clobber (reg:CC CC_REGNUM))] - "" - "XOR.%# %1,%2,%0 // %0 := %1 XOR %2 (HI)" - [(set_attr "type" "basicAlu,basicAlu") - (set_attr "longConstant" "false,true") - (set_attr "length" "3,5")]) - -;;=========================================================================== -;; Arithmetic shift left. -;;=========================================================================== - -(define_insn "ashlhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (ashift:HI (match_operand:HI 1 "register_operand" "r,r") - (match_operand:HI 2 "general_operand" "r,J")))] - "" - "LSL.%# %1,%2,%0 // %0 := %1 << %2" - [(set_attr "type" "picoAlu,basicAlu") - (set_attr "length" "3,3")]) - -;;=========================================================================== -;; Arithmetic shift right. -;;=========================================================================== - -(define_insn "builtin_asri" - [(set (match_operand:HI 0 "register_operand" "=r") - (ashiftrt:HI (match_operand:HI 1 "register_operand" "r") - (match_operand:HI 2 "immediate_operand" ""))) - (clobber (reg:CC CC_REGNUM))] - "" - "ASR.%# %1,%2,%0\t// %0 = %1 >>{arith} %2" - [(set_attr "type" "basicAlu") - (set_attr "length" "3")]) - -;; The picoChip ISA doesn't have a variable arithmetic shift right, so -;; synthesise it. Shifts by constants are directly supported. - -(define_expand "ashrhi3" - [(match_operand:HI 0 "register_operand" "") - (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "picochip_register_or_immediate_operand" "")] - "" -{ - if (GET_CODE(operands[2]) == CONST_INT) - /* Shift by constant is easy. */ - emit_insn (gen_builtin_asri (operands[0], operands[1], operands[2])); - else - { - /* Synthesise a variable shift. */ - - rtx tmp1; - rtx tmp2; - rtx tmp3; - rtx minus_one; - rtx tmp4; - - /* Fill a temporary with the sign bits. */ - tmp1 = gen_reg_rtx (HImode); - emit_insn (gen_builtin_asri (tmp1, operands[1], GEN_INT(15))); - - /* Shift the unsigned value. */ - tmp2 = gen_reg_rtx (HImode); - emit_insn (gen_lshrhi3 (tmp2, operands[1], operands[2])); - - /* The word of sign bits must be shifted back to the left, to zero - * out the unwanted lower bits. The amount to shift left by is (15 - - * count). Since the shifts are computed modulo 16 (i.e., only the - * lower 4 bits of the count are used), the shift amount (15 - count) - * is equivalent to !count. */ - tmp3 = gen_reg_rtx (HImode); - minus_one = GEN_INT (-1); - emit_insn (gen_xorhi3 (tmp3, operands[2], minus_one)); - tmp4 = gen_reg_rtx (HImode); - emit_insn (gen_ashlhi3 (tmp4, tmp1, tmp3)); - - /* Combine the sign bits with the shifted value. */ - emit_insn (gen_iorhi3 (operands[0], tmp2, tmp4)); - - } - DONE; -}) - -;;=========================================================================== -;; Logical shift right. -;;=========================================================================== - -(define_insn "lshrhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (lshiftrt:HI (match_operand:HI 1 "register_operand" "r,r") - (match_operand:HI 2 "general_operand" "r,J")))] - "" - "LSR.%# %1,%2,%0 // %0 := %1 >> %2" - [(set_attr "type" "picoAlu,basicAlu") - (set_attr "length" "3,3")]) - -;;=========================================================================== -;; Negate. -;;=========================================================================== - -;; Negations are performed by subtracting from the constant 0, which -;; is loaded into a register. By using a register containing 0, the -;; chances of being able to CSE with another 0 value are increased. - -(define_expand "neghi2" - [(set (match_dup 2) (match_dup 3)) - (parallel [(set (match_operand:HI 0 "register_operand" "=r") - (minus:HI (match_dup 2) - (match_operand:HI 1 "register_operand" "r"))) - (clobber (reg:CC CC_REGNUM))])] - "" - "operands[2] = gen_reg_rtx(HImode); - operands[3] = GEN_INT(0x00000000);") - -(define_expand "negsi2" - [(set (match_dup 2) (match_dup 3)) - (parallel [(set (match_operand:SI 0 "register_operand" "=r") - (minus:SI (match_dup 2) - (match_operand:SI 1 "register_operand" "r"))) - (clobber (reg:CC CC_REGNUM))])] - "" - "operands[2] = gen_reg_rtx(SImode); - operands[3] = GEN_INT(0x00000000);") - -;;=========================================================================== -;; Absolute value. Taken from the Hacker's Delight, page 17. The second of the -;; four options given there produces the smallest, fastest code. -;;=========================================================================== - -(define_insn_and_split "abshi2" - [(set (match_operand:HI 0 "register_operand" "") - (abs:HI (match_operand:HI 1 "register_operand" "")))] - "" - "#" - "" - [(parallel [(set (match_dup 2) - (plus:HI (ashiftrt:HI (match_dup 1) (const_int 15)) - (match_dup 1))) - (clobber (reg:CC CC_REGNUM))]) - (parallel [(set (match_dup 0) - (xor:HI (ashiftrt:HI (match_dup 1) (const_int 15)) - (match_dup 2))) - (clobber (reg:CC CC_REGNUM))])] -{ - operands[2] = gen_reg_rtx (HImode); -}) - -;;=========================================================================== -;; Bitwise complement. Use auto-synthesised variant for SI mode. Though this -;; internally uses xor, the compiler doesnt automatically synthesize it using -;; xor, if this pattern was removed. -;;=========================================================================== - -(define_insn "one_cmplhi2" - [(set (match_operand:HI 0 "register_operand" "=r") - (not:HI (match_operand:HI 1 "register_operand" "0"))) - (clobber (reg:CC CC_REGNUM))] - "" - "XOR.%# %1,-1,%0 // %0 := ~%1" - [(set_attr "type" "basicAlu") - (set_attr "longConstant" "true") - (set_attr "length" "5")]) - -;;=========================================================================== -;; Count leading zeros. The special sign-bit-count instruction can be used -;; to help us here. -;; op1:=clz(op1) -;; The code works by checking to see if the top bit is set. If it is, -;; then there are no leading zeros. If the top bit is cleared, then -;; the SBC instruction is used to determine how many more leading -;; zeros are present, and adding one more for the initial zero. -;;=========================================================================== - -(define_insn "clzhi2" - [(set (match_operand:HI 0 "register_operand" "=&r") - (clz:HI (match_operand:HI 1 "register_operand" "r")))] - "" - "// Count leading zeros\;SBC %1,%0\;ASR.0 %1,15,r15 %| ADD.1 %0,1,%0\;COPYNE 0,%0" - [(set_attr "length" "11")]) - -;;=========================================================================== -;; Count trailing zeros. This can be achieved efficiently by reversing -;; using the bitrev instruction, and then counting the leading zeros as -;; described above. -;;=========================================================================== - -(define_insn "ctzhi2" - [(set (match_operand:HI 0 "register_operand" "=&r") - (ctz:HI (match_operand:HI 1 "register_operand" "r")))] - "" - "// Count trailing zeros\;BREV %1,%0\;SBC %0,%0\;AND.0 %1,0x0001,r15 %| ADD.1 %0,1,%0\;COPYNE 0,%0" - [(set_attr "length" "15")]) - -;;=========================================================================== -;; Find the first set bit, starting from the least significant bit position. -;; This is very similar to the ctz function, except that the bit index is one -;; greater than the number of trailing zeros (i.e., SBC + 2), and the -;; result of ffs on the zero value is defined. -;;=========================================================================== - -(define_insn "ffshi2" - [(set (match_operand:HI 0 "register_operand" "=&r") - (ffs:HI (match_operand:HI 1 "register_operand" "r")))] - "" - "// First first bit\;BREV %1,%0\;SBC %0,%0\;AND.0 %1,0x0001,r15 %| ADD.1 %0,2,%0\;COPYNE 1,%0\;SUB.0 %1,0x0000,r15\;COPYEQ 0,%0" - [(set_attr "length" "20")]) - -;;=========================================================================== -;; Tablejump Instruction. Jump to an absolute address. -;;=========================================================================== - -(define_insn "tablejump" - [(set (pc) (unspec:HI [(match_operand:HI 0 "register_operand" "r")] 1)) - (use (label_ref (match_operand 1 "" ""))) - (clobber (match_dup 0))] - "" - "JR (%0)\t // Table jump to %0 %>" - [(set_attr "length" "2") - (set_attr "type" "realBranch")]) - -;; Given the memory address of a QImode value, and a scratch register, -;; store the memory operand into the given output operand. The scratch -;; operand will not conflict with either of the operands. The other -;; two operands may conflict with each other. - -(define_insn "synthesised_loadqi_unaligned" - [(set (match_operand:QI 0 "register_operand" "=r") - (match_operand:QI 1 "memory_operand" "m")) - (clobber (match_operand:HI 2 "register_operand" "=&r")) - (clobber (reg:CC CC_REGNUM))] - "" - "// Synthesised loadqi %0 = Mem(%1) (Scratch %2)\n\tAND.0 %1,-2,%2\n\tLDW (%2)0,%0 %| AND.0 %1,1,%2\n\tLSL.0 %2,3,%2\n\tSUB.0 8,%2,%2\n\tLSL.0 %0,%2,%0\n\tASR.0 %0,8,%0" - ; Approximate length only. Probably a little shorter than this. - [(set_attr "length" "40")]) - -;; Given a memory operand whose alignment is known (the HImode aligned -;; base is operand 0, and the number of bits by which to shift is in -;; operand 5), -(define_expand "synthesised_storeqi_aligned" - [; s1 = mem_op - (set (match_operand:HI 2 "register_operand" "") - (match_operand:HI 0 "memory_operand" "")) - ; s1 = s1 and mask - (parallel [(set (match_dup 2) (and:HI (match_dup 2) (match_dup 5))) - (clobber (reg:CC CC_REGNUM))]) - ; s2 = source << bitShift - (set (match_dup 3) - (ashift:HI (subreg:HI (match_operand:QI 1 "register_operand" "") 0) - (match_operand:HI 4 "const_int_operand" ""))) - ; s1 = s1 or s2 - (parallel [(set (match_dup 2) (ior:HI (match_dup 2) (match_dup 3))) - (clobber (reg:CC CC_REGNUM))]) - ; mem_op = s1 - (set (match_dup 0) (match_dup 2))] - "!TARGET_HAS_BYTE_ACCESS" -{ - /* Create the byte mask 0xFF00. */ - operands[5] = gen_int_mode(((~0xFF) >> INTVAL (operands[4])), HImode); -}) - -;; Reload instructions. See picochip_secondary_reload for an -;; explanation of why an SI mode register is used as a scratch. The -;; memory operand must be stored in a register (i.e., it can't be an -;; offset to another register - this would require another scratch -;; register into which the address of the offset could be computed). - -(define_expand "reload_inqi" - [(parallel [(match_operand:QI 0 "register_operand" "=&r") - (match_operand:QI 1 "memory_operand" "m") - (match_operand:SI 2 "register_operand" "=&r")])] - "!TARGET_HAS_BYTE_ACCESS" -{ - rtx scratch, seq; - - /* Get the scratch register. Given an SI mode value, we have a - choice of two HI mode scratch registers, so we can be sure that at - least one of the scratch registers will be different to the output - register, operand[0]. */ - - if (REGNO (operands[0]) == REGNO (operands[2])) - scratch = gen_rtx_REG (HImode, REGNO (operands[2]) + 1); - else - scratch = gen_rtx_REG (HImode, REGNO (operands[2])); - - /* Ensure that the scratch doesn't overlap either of the other - two operands - however, the other two may overlap each - other. */ - gcc_assert (REGNO(scratch) != REGNO(operands[0])); - gcc_assert (REGNO(scratch) != REGNO(operands[1])); - - gcc_assert (GET_CODE (operands[1]) == MEM); - - if (picochip_word_aligned_memory_reference(XEXP(operands[1], 0))) - { - /* Aligned reloads are easy, since they can use word-loads. */ - seq = gen_synthesised_loadqi_aligned(operands[0], operands[1], scratch); - } - else - { - /* Emit the instruction using a define_insn. */ - seq = gen_synthesised_loadqi_unaligned(operands[0], operands[1], scratch); - } - emit_insn (seq); - - DONE; - -}) - -(define_expand "reload_outqi" - [(parallel [(match_operand 0 "memory_operand" "=m") - (match_operand:QI 1 "register_operand" "r") - (match_operand:SI 2 "register_operand" "=&r")])] - "!TARGET_HAS_BYTE_ACCESS" -{ - rtx scratch1 = gen_rtx_REG(HImode, REGNO(operands[2])); - rtx scratch2 = gen_rtx_REG(HImode, REGNO(operands[2]) + 1); - rtx seq; - - gcc_assert (GET_CODE (operands[0]) == MEM); - - if (picochip_word_aligned_memory_reference(XEXP(operands[0], 0))) - { - rtx alignedAddr, bitShift; - - /* Convert the address of the known alignment into two operands - * representing the aligned base address, and the number of shift bits - * required to access the required value. */ - picochip_get_hi_aligned_mem(operands[0], &alignedAddr, &bitShift); - - /* Emit an aligned store of the source, with the given bit offset. */ - seq = gen_synthesised_storeqi_aligned(alignedAddr, operands[1], scratch1, scratch2, bitShift); - - } - else - { - /* This isnt exercised at all. Moreover, with new devices, byte access - is available in all variants. */ - gcc_unreachable(); - } - - emit_insn (seq); - DONE; - -}) - -;; Perform a byte load of an alignable memory operand. -; op0 = register to load. op1 = memory operand from which to load -; op2 = op1, aligned to HI, op3 = const bit shift required to extract byte, -; op4 = INTVAL(8 - op3) -(define_expand "synthesised_loadqi_aligned" - [; Load memory operand into register - (set (match_operand:HI 2 "register_operand" "=r") - (match_dup 3)) - ; Shift required byte into top byte of word. - (set (match_dup 2) - (ashift:HI (match_dup 2) - (match_dup 4))) - ; Arithmetic shift of byte to sign extend, and move to lowest register. - (parallel[(set (subreg:HI (match_dup 0) 0) - (ashiftrt:HI (match_dup 2) - (const_int 8))) - (clobber (reg:CC CC_REGNUM))]) - (use (match_operand:QI 1 "picochip_alignable_memory_operand" "g"))] - "!TARGET_HAS_BYTE_ACCESS" -{ - rtx alignedAddr, bitShift; - - /* Convert the address of the known alignment into two operands - * representing the aligned base address, and the number of shift bits - * required to access the required value. */ - picochip_get_hi_aligned_mem(operands[1], &alignedAddr, &bitShift); - - operands[3] = alignedAddr; - operands[4] = GEN_INT(8 - INTVAL(bitShift)); -}) - -;;============================================================================ -;; Special instructions. -;;============================================================================ - -; Count sign-bits. -(define_insn "sbc" - [(set (match_operand:HI 0 "register_operand" "=r") - (unspec:HI [(match_operand:HI 1 "register_operand" "r")] - UNSPEC_SBC))] - "" - "SBC %1,%0\t\t// %0 := SBC(%1)" - [(set_attr "type" "picoAlu") - (set_attr "length" "2")]) - -; Bit reversal. -(define_insn "brev" - [(set (match_operand:HI 0 "register_operand" "=r") - (unspec:HI [(match_operand:HI 1 "register_operand" "r")] - UNSPEC_BREV))] - "" - "BREV %1,%0\t\t// %0 := BREV(%1)" - [(set_attr "length" "2") - (set_attr "type" "picoAlu")]) - -; Byte swap. -(define_insn "bswaphi2" - [(set (match_operand:HI 0 "register_operand" "=r") - (bswap:HI (match_operand:HI 1 "register_operand" "r")))] - "" - "BYTESWAP %1,%0\t\t// %0 := ByteSwap(%1)" - [(set_attr "length" "2") - (set_attr "type" "picoAlu")]) - -; Read status word. -(define_insn "copysw" - [(set (match_operand:HI 0 "register_operand" "=r") - (unspec_volatile:HI [(reg:CC CC_REGNUM)] UNSPEC_COPYSW))] - "" - "COPYSW.%# %0\t// %0 := Flags" - [(set_attr "type" "basicAlu") - (set_attr "length" "2")]) - -; Saturating addition. -(define_insn "sataddhi3" - [(set (match_operand:HI 0 "register_operand" "=r") - (unspec:HI [(match_operand:HI 1 "register_operand" "r") - (match_operand:HI 2 "register_operand" "r")] - UNSPEC_ADDS)) - (clobber (reg:CC CC_REGNUM))] - "" - "ADDS %1,%2,%0\t// %0 := sat(%1 + %2)" - [(set_attr "type" "picoAlu") - (set_attr "length" "3")]) - -; Saturating subtraction. -(define_insn "satsubhi3" - [(set (match_operand:HI 0 "register_operand" "=r") - (unspec:HI [(match_operand:HI 1 "register_operand" "r") - (match_operand:HI 2 "register_operand" "r")] - UNSPEC_SUBS)) - (clobber (reg:CC CC_REGNUM))] - "" - "SUBS %1,%2,%0\t// %0 := sat(%1 - %2)" - [(set_attr "type" "picoAlu") - (set_attr "length" "3")]) - -(define_insn "halt" - [(unspec_volatile [(match_operand:HI 0 "const_int_operand" "i")] - UNSPEC_HALT)] - "" - "HALT\t// (id %0)" - [(set_attr "length" "1") - (set_attr "type" "unknown")]) - -(define_insn "internal_testport" - [(set (reg:CC CC_REGNUM) - (unspec_volatile:CC [(match_operand:HI 0 "const_int_operand" "i")] - UNSPEC_INTERNAL_TESTPORT))] - "" - "TSTPORT %0" - [(set_attr "length" "2") - (set_attr "longConstant" "false") - (set_attr "type" "picoAlu")]) - -;;============================================================================ -;; Communications builtins. -;; -;; Each builtin comes in two forms: a single port version, which maps -;; to a single instruction, and an array port version. The array port -;; version is treated as a special type of instruction, which is then -;; split into a number of smaller instructions, if the index of the -;; port can't be converted into a constant. When the RTL split is -;; performed, a function call is emitted, in which the index of the -;; port to use is used to compute the address of the function to call -;; (i.e., each array port is a function in its own right, and the -;; functions are stored as an array which is then indexed to determine -;; the correct function). The communication function port array is -;; created by the linker if and only if it is required (in a -;; collect2-like manner). -;;============================================================================ - -; Simple scalar get. -(define_insn "commsGet" - [(set (match_operand:SI 0 "register_operand" "=r") - (unspec_volatile:SI - [(match_operand:HI 1 "immediate_operand" "n")] - UNSPEC_GET))] - "" - "GET %1,%R0\t// %R0 := PORT(%1)" - [(set_attr "type" "comms") - (set_attr "length" "2")]) - -; Entry point for array get (the actual port index is computed as the -; sum of the index, and the base). -; -; op0 - Destination -; op1 - Requested port index -; op2 - size of port array (constant) -; op3 - base index of port array (constant) - -(define_expand "commsArrayGet" - [(parallel - [(set (reg:SI 0) - (unspec_volatile:SI [(match_operand:HI 1 "general_operand" "") - (match_operand:HI 2 "immediate_operand" "") - (match_operand:HI 3 "immediate_operand" "")] - UNSPEC_CALL_GET_ARRAY)) - (clobber (reg:HI LINK_REGNUM))]) - (set (match_operand:SI 0 "register_operand" "") (reg:SI 0))] - "" - "") - -;; The actual array get instruction. When the array index is a constant, -;; an exact instruction may be generated. When the index is variable, -;; a call to a special function is generated. This code could be -;; split into individual RTL instructions, but it is so rarely -;; used, that we won't bother. -(define_insn "*commsArrayGetInstruction" - [(set (reg:SI 0) - (unspec_volatile:SI [(match_operand:HI 0 "general_operand" "r,i") - (match_operand:HI 1 "immediate_operand" "") - (match_operand:HI 2 "immediate_operand" "")] - UNSPEC_CALL_GET_ARRAY)) - (clobber (reg:HI LINK_REGNUM))] - "" -{ - return picochip_output_get_array (which_alternative, operands); -}) - -; Scalar Put instruction. -(define_insn "commsPut" - [(unspec_volatile [(match_operand:HI 0 "const_int_operand" "") - (match_operand:SI 1 "register_operand" "r")] - UNSPEC_PUT)] - "" - "PUT %R1,%0\t// PORT(%0) := %R1" - [(set_attr "type" "comms") - (set_attr "length" "2")]) - -; Entry point for array put. The operands accepted are: -; op0 - Value to put -; op1 - Requested port index -; op2 - size of port array -; op3 - base index of port array -; The arguments are marshalled into the fixed registers, so that -; the actual put instruction can expand into a call if necessary -; (e.g., if the index is variable at run-time). - -(define_expand "commsArrayPut" - [(set (reg:SI 0) (match_operand:SI 0 "general_operand" "")) - (parallel - [(unspec_volatile [(match_operand:HI 1 "general_operand" "") - (match_operand:HI 2 "immediate_operand" "") - (match_operand:HI 3 "immediate_operand" "")] - UNSPEC_CALL_PUT_ARRAY) - (use (reg:SI 0)) - (clobber (reg:HI LINK_REGNUM))])] - "" - "") - -;; The actual array put instruction. When the array index is a constant, -;; an exact instruction may be generated. When the index is variable, -;; a call to a special function is generated. This code could be -;; split into individual RTL instructions, but it is so rarely -;; used, that we won't bother. -(define_insn "*commsArrayPutInstruction" - [(unspec_volatile [(match_operand:HI 0 "general_operand" "r,i") - (match_operand:HI 1 "immediate_operand" "") - (match_operand:HI 2 "immediate_operand" "")] - UNSPEC_CALL_PUT_ARRAY) - (use (reg:SI 0)) - (clobber (reg:HI LINK_REGNUM))] - "" -{ - return picochip_output_put_array (which_alternative, operands); -}) - -;; Scalar test port instruction. -(define_insn "commsTestPort" - [(set (match_operand:HI 0 "register_operand" "=r") - (unspec_volatile:HI [(match_operand:HI 1 "const_int_operand" "")] - UNSPEC_TESTPORT)) - (clobber (reg:CC CC_REGNUM))] - "" - "// %0 := TestPort(%1)\;COPY.1 0,%0 %| TSTPORT %1\;COPYEQ 1,%0" - [(set_attr "length" "9")]) - -; Entry point for array tstport (the actual port index is computed as the -; sum of the index, and the base). -; -; op0 - Test value. -; op1 - Requested port index -; op2 - size of port array (constant) -; op3 - base index of port array (constant) - -(define_expand "commsArrayTestPort" - [(parallel - [(set (match_operand:HI 0 "register_operand" "") - (unspec_volatile:HI [(match_operand:HI 1 "general_operand" "") - (match_operand:HI 2 "immediate_operand" "") - (match_operand:HI 3 "immediate_operand" "")] - UNSPEC_CALL_TESTPORT_ARRAY)) - (clobber (reg:HI LINK_REGNUM))])] - "" - "") - -;; The actual array testport instruction. When the array index is a constant, -;; an exact instruction may be generated. When the index is variable, -;; a call to a special function is generated. This code could be -;; split into individual RTL instructions, but it is so rarely -;; used, that we won't bother. -(define_insn "*commsArrayTestportInstruction" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (unspec_volatile:HI [(match_operand:HI 1 "general_operand" "r,i") - (match_operand:HI 2 "immediate_operand" "") - (match_operand:HI 3 "immediate_operand" "")] - UNSPEC_CALL_TESTPORT_ARRAY)) - (clobber (reg:HI LINK_REGNUM))] - "" -{ - return picochip_output_testport_array (which_alternative, operands); -}) - -;; Merge a TSTPORT instruction with the branch to which it -;; relates. Often the TSTPORT function (generated by a built-in), is -;; used to control conditional execution. The normal sequence of -;; instructions would be: -;; TSTPORT p -;; COPYSW temp -;; AND temp, 0x0008, temp -;; SUB temp,0,discard -;; BEQ label -;; This can be made more efficient by detecting the special case where -;; the result of a TSTPORT is used to branch, to allow the following -;; RTL sequence to be generated instead: -;; TSTPORT p -;; BEQ label -;; A big saving in cycles and bytes! - -(define_insn_and_split "tstport_branch" - [(set (pc) - (if_then_else - (match_operator 0 "comparison_operator" - [(unspec_volatile:HI - [(match_operand:HI 1 "const_int_operand" "")] - UNSPEC_TESTPORT) - (const_int 0)]) - (label_ref (match_operand 2 "" "")) - (pc))) - (clobber (reg:CC CC_REGNUM))] - "" - "#" - "" - [(set (reg:CC CC_REGNUM) - (unspec_volatile:CC [(match_dup 1)] UNSPEC_INTERNAL_TESTPORT)) - (parallel [(set (pc) - (if_then_else - (match_op_dup:HI 4 [(reg:CC CC_REGNUM) (const_int 0)]) - (label_ref (match_dup 2)) - (pc))) - (use (match_dup 3))])] - "{ - /* Note that the sense of the branch is reversed, since we are - * comparing flag != 0. */ - gcc_assert (GET_CODE(operands[0]) == NE || GET_CODE(operands[0]) == EQ); - operands[4] = gen_rtx_fmt_ee(reverse_condition(GET_CODE(operands[0])), - GET_MODE(operands[0]), XEXP(operands[0], 0), XEXP(operands[0], 1)); - operands[3] = GEN_INT (0); - }") - -;;============================================================================ -;; Epilogue/Epilogue expansion. -;;============================================================================ - -(define_expand "prologue" - [(clobber (const_int 0))] - "" -{ - picochip_expand_prologue (); - DONE; -}) - -(define_expand "epilogue" - [(use (const_int 0))] - "" -{ - picochip_expand_epilogue (FALSE); - DONE; -}) - -;;============================================================================ -;; Trap instruction. This is used to indicate an error. For the -;; picoChip processors this is handled by calling a HALT instruction, -;; which stops the processor. -;;============================================================================ - -(define_insn "trap" - [(trap_if (const_int 1) (const_int 6))] - "" - "HALT\t// (Trap)" - [(set_attr "length" "2")]) - -;;============================================================================ -;; Conditional copy instructions. Only equal/not-equal comparisons are -;; supported. All other types of comparison remain as branch -;; sequences. -;;============================================================================ - -;; Define expand seems to consider the resulting two instructions to be -;; independent. With a split, guarded by reload, it works correctly. -(define_expand "movhicc" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (if_then_else:HI (match_operand:HI 1 "" "") - (match_operand:HI 2 "register_operand" "0,0") - (match_operand:HI 3 "picochip_register_or_immediate_operand" "r,i")))] - "" - {if (!picochip_check_conditional_copy (operands)) - FAIL; - }) - -(define_insn_and_split "*checked_movhicc" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (if_then_else:HI (match_operator 1 "picochip_peephole_comparison_operator" - [(match_operand:HI 4 "register_operand" "r,r") - (match_operand:HI 5 "picochip_comparison_operand" "r,i")]) - (match_operand:HI 2 "register_operand" "0,0") - (match_operand:HI 3 "picochip_register_or_immediate_operand" "r,i")))] - "" - "#" - "reload_completed" - [(set (reg:CC CC_REGNUM) (match_dup 1)) - (parallel [(set (match_operand:HI 0 "register_operand" "=r,r") - (if_then_else:HI (match_op_dup:HI 1 [(reg:CC CC_REGNUM) (const_int 0)]) - (match_operand:HI 2 "picochip_register_or_immediate_operand" "0,0") - (match_operand:HI 3 "picochip_register_or_immediate_operand" "r,i"))) - (use (match_dup 6))])] - "{ - operands[6] = GEN_INT(GET_CODE(operands[0])); - }") - -;; We dont do any checks here. But this pattern is used only when movhicc -;; was checked. Put a "use" clause to make sure. -(define_insn "*conditional_copy" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (if_then_else:HI - (match_operator:HI 4 "picochip_peephole_comparison_operator" - [(reg:CC CC_REGNUM) (const_int 0)]) - (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "picochip_register_or_immediate_operand" "r,i"))) - (use (match_operand:HI 3 "const_int_operand" ""))] - "" -{ - - gcc_assert (GET_CODE(operands[4]) == EQ || GET_CODE(operands[4]) == NE); - /* Note that the comparison is reversed as the pattern matches - the *else* part of the if_then_else */ - switch (GET_CODE(operands[4])) - { - case EQ: return "COPYNE %2,%0\t// if (NE) %0 := %2"; - case NE: return "COPYEQ %2,%0\t// if (EQ) %0 := %2"; - default: - gcc_unreachable(); - } -} - [(set_attr "length" "2") - (set_attr "type" "picoAlu,picoAlu") - (set_attr "longConstant" "false,true")]) - -;;============================================================================ -;; Scheduling, including delay slot scheduling. -;;============================================================================ - -(automata_option "v") -(automata_option "ndfa") - -;; Define each VLIW slot as a CPU resource. Note the three flavours of -;; branch. `realBranch' is an actual branch instruction. `macroBranch' -;; is a directive to the assembler, which may expand into multiple -;; instructions. `call' is an actual branch instruction, but one which -;; sets the link register, and hence can't be scheduled alongside -;; other instructions which set the link register. When the DFA -;; scheduler is fixed to prevent it scheduling a JL with an R12 -;; setting register, the call type branches can be replaced by -;; realBranch types instead. - -(define_attr "type" - "picoAlu,basicAlu,nonCcAlu,mem,call,realBranch,macroBranch,mul,mac,app,comms,unknown" - (const_string "unknown")) - -(define_attr "schedType" "none,space,speed" - (const (symbol_ref "(enum attr_schedType) picochip_schedule_type"))) - -;; Define whether an instruction uses a long constant. - -(define_attr "longConstant" - "true,false" (const_string "false")) - -;; Define three EU slots. -(define_query_cpu_unit "slot0,slot1,slot2") - -;; Pull in the pipeline descriptions for speed or space scheduling. -(include "dfa_speed.md") -(include "dfa_space.md") - -; Unknown instructions are assumed to take a single cycle, and use all -; slots. This enables them to actually output a sequence of -; instructions without any limitation. For the purposes of -; scheduling, unknown instructions are a pain, and should be removed -; completely. This means that RTL patterns should always be used to -; reduce complex sequences of instructions to individual instructions. -(define_insn_reservation "unknownInsn" 1 - (eq_attr "type" "unknown") - "(slot0+slot1+slot2)") - -; Allow any non-branch instructions to be placed in the branch -; slot. Branch slots are always executed. -(define_delay (eq_attr "type" "realBranch,call") - [(eq_attr "type" "!realBranch,macroBranch,call,unknown") (nil) (nil)]) diff --git a/gcc/config/picochip/picochip.opt b/gcc/config/picochip/picochip.opt deleted file mode 100644 index 910775c..0000000 --- a/gcc/config/picochip/picochip.opt +++ /dev/null @@ -1,46 +0,0 @@ -; Options for the picoChip port of the compiler. - -; Copyright (C) 2008-2014 Free Software Foundation, Inc. -; -; This file is part of GCC. -; -; GCC 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 3, or (at your option) any later -; version. -; -; GCC is distributed in the hope that it will be useful, but WITHOUT ANY -; WARRANTY; without even the implied warranty of MERCHANTABILITY or -; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -; for more details. -; -; You should have received a copy of the GNU General Public License -; along with GCC; see the file COPYING3. If not, see -; <http://www.gnu.org/licenses/>. - -mae= -Target RejectNegative Joined Var(picochip_ae_type_string) -Specify which type of AE to target. This option sets the mul-type and byte-access. - -mmul-type= -Target RejectNegative Undocumented Joined Var(picochip_mul_type_string) -Specify which type of multiplication to use. Can be mem, mac or none. - -mbyte-access -Target Undocumented Var(picochip_has_byte_access,1) Init(1) -Specify whether the byte access instructions should be used. Enabled by default. - -mdebug -Target RejectNegative Undocumented Mask(DEBUG) -Enable debug output to be generated. - -msymbol-as-address -Target Mask(SYMBOL_AS_ADDRESS) -Allow a symbol value to be used as an immediate value in an instruction. - -minefficient-warnings -Target Mask(INEFFICIENT_WARNINGS) -Generate warnings when inefficient code is known to be generated. - -minefficient -Target Mask(INEFFICIENT_WARNINGS) Undocumented diff --git a/gcc/config/picochip/predicates.md b/gcc/config/picochip/predicates.md deleted file mode 100644 index 3431a36..0000000 --- a/gcc/config/picochip/predicates.md +++ /dev/null @@ -1,72 +0,0 @@ -;; GCC machine description for picochip -;; Copyright (C) 2008-2014 Free Software Foundation, Inc. -;; Contributed by Picochip Ltd (http://www.picochip.com) -;; Maintained by Daniel Towner (dant@picochip.com) and Hariharan -;; Sandanagobalane (hariharan@picochip.com) -;; -;; This file is part of GCC. -;; -;; GCC 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 3, or (at your option) -;; any later version. -;; -;; GCC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GCC; see the file COPYING3. If not, see -;; <http://www.gnu.org/licenses/>. - -(define_predicate "picochip_register_or_immediate_operand" - (ior (match_operand 0 "register_operand") - (match_operand 0 "immediate_operand"))) - -(define_predicate "power_of_2_imm_operand" - (match_code "const_int") -{ - if (GET_CODE (op) == CONST_INT) - { - if (exact_log2 (INTVAL (op)) <= 16 && exact_log2 (INTVAL (op)) > 0) - return 1; - } - - return 0; -}) - -;; Limit the comparison operators to a selected subset. -(define_predicate "picochip_supported_comparison_operator" - (and (match_operand 0 "comparison_operator") - (match_code "ne,eq,ge,geu,lt,ltu"))) -(define_predicate "picochip_peephole_comparison_operator" - (and (match_operand 0 "comparison_operator") - (match_code "ne,eq"))) - -;; Allow selected arithmetic operators to apply a shift to their first -;; operands - -(define_predicate "picochip_first_op_shift_operator" - (match_code "and,plus,minus,ior,xor")) - -;; The same as the previous predicate, but only allowing those -;; operators which can accept an immediate. -(define_predicate "picochip_first_op_shift_operator_imm" - (match_code "plus,minus")) - -;; Predicate on a J type integer. -(define_predicate "picochip_J_operand" - (match_operand 0 "immediate_operand") - { - return (CONST_INT == GET_CODE(op) && - picochip_const_ok_for_letter_p (INTVAL(op), 'J')); - }) - -;; Is the operand suitable for use in a compare? - -(define_predicate "picochip_comparison_operand" - (ior (match_operand 0 "register_operand") - (and (match_operand 0 "immediate_operand") - (match_test "picochip_const_ok_for_letter_p(INTVAL(op), 'O')")))) - diff --git a/gcc/config/picochip/t-picochip b/gcc/config/picochip/t-picochip deleted file mode 100644 index ac785e5..0000000 --- a/gcc/config/picochip/t-picochip +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) 2008-2014 Free Software Foundation, Inc. -# -# This file is part of GCC. -# -# GCC 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 3, or (at your option) -# any later version. -# -# GCC is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GCC; see the file COPYING3. If not see -# <http://www.gnu.org/licenses/>. - -# Build all combinations of library for different multiply units, and -# presence/absence of byte access. -MULTILIB_OPTIONS = mmul-type=none/mmul-type=mac/mmul-type=mul mno-byte-access/mbyte-access - -# Using a mul unit (currently) implies that byte access is available. -MULTILIB_EXCEPTIONS = mmul-type=mul/mno-byte-access |