diff options
Diffstat (limited to 'gcc')
62 files changed, 2470 insertions, 2480 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c343b1685d2..28ff47174c1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,137 @@ +2011-07-03 Ira Rosen <ira.rosen@linaro.org> + + PR tree-optimization/49610 + * tree-vect-loop.c (vect_is_slp_reduction): Check that DEF_STMT has + a basic block. + +2011-07-02 Eric Botcazou <ebotcazou@adacore.com> + Olivier Hainque <hainque@adacore.com> + Nicolas Setton <setton@adacore.com> + + * tree.h (TYPE_ARTIFICIAL): New flag. + * dwarf2out.c (modified_type_die): Add a DW_AT_artificial attribute to + the DIE of the type if it is artificial. + (gen_array_type_die): Likewise. + (gen_enumeration_type_die): Likewise. + (gen_struct_or_union_type_die): Likewise. + * lto-streamer-in.c (unpack_ts_base_value_fields): Use TYPE_ARTIFICIAL. + * lto-streamer-out.c (pack_ts_base_value_fields): Likewise. + +2011-07-01 Jakub Jelinek <jakub@redhat.com> + + * tree-object-size.c (pass_through_call): Handle + BUILT_IN_ASSUME_ALIGNED. + +2011-07-01 Martin Jambor <mjambor@suse.cz> + + * tree-sra.c (tree_non_mode_aligned_mem_p): Also ignore MEM_REFs. + +2011-07-01 H.J. Lu <hongjiu.lu@intel.com> + + PR middle-end/48016 + * explow.c (update_nonlocal_goto_save_area): Use proper mode + for stack save area. + * function.c (expand_function_start): Likewise. + +2011-07-01 Richard Guenther <rguenther@suse.de> + + PR middle-end/49596 + * cgraph.h (varpool_all_refs_explicit_p): Not analyzed nodes + may have unknown refs. + +2011-07-01 Kai Tietz <ktietz@redhat.com> + + * tree-ssa-forwprop.c (simplify_bitwise_binary): Fix typo. + +2011-07-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * config.gcc: Obsolete alpha*-dec-osf5.1, mips-sgi-irix6.5. + * doc/install.texi (Specific, alpha*-dec-osf5.1): Document it. + (Specific, mips-sgi-irix6): Likewise. + +2011-07-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + PR libmudflap/49549 + * doc/sourcebuild.texi (Effective-Target Keywords): Document gld. + +2011-07-01 Jakub Jelinek <jakub@redhat.com> + + * tree-pretty-print.c (dump_generic_code) <case CONSTRUCTOR>: Print + [idx]= and [idx1 ... idx2]= before initializers if needed for + array initializers. + +2011-07-01 Chen Liqin <liqin.gcc@gmail.com> + + * config.gcc (score-*-elf): Remove score7.o. + * config/score/t-score-elf: Likewise. + * config/score/score.c: Merge score7 to score.c and + remove forwarding functions. + * config/score/score7.c: Deleted. + * config/score/score7.h: Deleted. + +2011-07-01 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/49603 + * tree-vect-stmts.c (vectorizable_load): Remove unnecessary + assert. + +2011-06-30 Martin Jambor <mjambor@suse.cz> + + * tree-sra.c (struct access): Rename total_scalarization to + grp_total_scalarization + (completely_scalarize_var): New function. + (sort_and_splice_var_accesses): Set total_scalarization in the + representative access. + (analyze_access_subtree): Propagate total scalarization accross the + tree, no holes in totally scalarized trees, simplify coverage + computation. + (analyze_all_variable_accesses): Call completely_scalarize_var instead + of completely_scalarize_record. + +2011-06-30 Richard Henderson <rth@redhat.com> + + * config/i386/i386.h (X86_TUNE_DEEP_BRANCH_PREDICTION): Remove. + (TARGET_DEEP_BRANCH_PREDICTION): Remove. + * config/i386/i386.c: Don't include dwarf2out.h. + (initial_ix86_tune_features): Remove X86_TUNE_DEEP_BRANCH_PREDICTION. + (output_set_got): Don't test TARGET_DEEP_BRANCH_PREDICTION, delete + all code dead thereafter. Don't do dwarf2out_flush_queued_reg_saves. + (ix86_expand_prologue): Set REG_CFA_FLUSH_QUEUE on set_got insn. + (machopic_output_stub): Don't test TARGET_DEEP_BRANCH_PREDICTION. + +2011-06-30 Richard Henderson <rth@redhat.com> + + * reg-notes.def (REG_CFA_FLUSH_QUEUE): New. + * dwarf2out.c (dwarf2out_frame_debug): Handle it. + * final.c (final_scan_insn): Look for it, and invoke + dwarf2out_frame_debug before the insn if found. + +2011-06-30 Richard Henderson <rth@redhat.com> + + * dwarf2out.c (dwarf2out_frame_debug_cfa_offset): Allow PC_RTX + as a source, and interpret that as DWARF_FRAME_RETURN_COLUMN. + +2011-06-30 Richard Henderson <rth@redhat.com> + + * dwarf2out.c (struct reg_saved_in_data): Provide a typedef. + Define a vector of this type. + (regs_saved_in_regs): Use a VEC. + (num_regs_saved_in_regs): Remove. + (compare_reg_or_pc): New. + (record_reg_saved_in_reg): Split out from... + (dwarf2out_flush_queued_reg_saves): ... here. + (clobbers_queued_reg_save): Update for VEC. + (reg_saved_in): Likewise. + (dwarf2out_frame_debug_init): Likewise. + (dwarf2out_reg_save_reg): Use record_reg_saved_in_reg. + (dwarf2out_frame_debug_cfa_register): Likewise. + +2011-06-30 Eric Botcazou <ebotcazou@adacore.com> + + PR tree-optimization/49572 + * tree-ssa-dom.c (initialize_hash_element) <GIMPLE_SINGLE_RHS>: Use the + type of the RHS instead of that of the LHS for the expression type. + 2011-06-30 Eric Botcazou <ebotcazou@adacore.com> * df-scan.c (df_get_entry_block_def_set): Use INCOMING_REGNO macro diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index f853878b12c..fc7a4fff175 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20110630 +20110704 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 6c9f757036d..9e778c102c5 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,17 @@ +2011-07-02 Eric Botcazou <ebotcazou@adacore.com> + Olivier Hainque <hainque@adacore.com> + Nicolas Setton <setton@adacore.com> + + * gcc-interface/utils.c (record_builtin_type): Set TYPE_ARTIFICIAL on + the type according to the ARTIFICIAL_P parameter. + (create_type_decl): Likewise. + (create_type_stub_decl): Set TYPE_ARTIFICIAL on the type to 1. + +2011-07-01 Eric Botcazou <ebotcazou@adacore.com> + + * gcc-interface/Make-lang.in (gnat1): Prepend '+' to the command. + (gnatbind): Likewise. + 2011-06-29 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> * gcc-interface/Makefile.in (TOOLS_LIBS): Add $(LIBINTL). diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in index 2e73363298b..d4344cc0f39 100644 --- a/gcc/ada/gcc-interface/Make-lang.in +++ b/gcc/ada/gcc-interface/Make-lang.in @@ -476,11 +476,11 @@ TARGET_ADA_SRCS = # Since the RTL should be built with the latest compiler, remove the # stamp target in the parent directory whenever gnat1 is rebuilt gnat1$(exeext): $(TARGET_ADA_SRCS) $(GNAT1_OBJS) $(ADA_BACKEND) libcommon-target.a $(LIBDEPS) - $(GCC_LINK) -o $@ $(GNAT1_OBJS) $(ADA_BACKEND) libcommon-target.a $(LIBS) $(SYSLIBS) $(BACKENDLIBS) $(CFLAGS) + +$(GCC_LINK) -o $@ $(GNAT1_OBJS) $(ADA_BACKEND) libcommon-target.a $(LIBS) $(SYSLIBS) $(BACKENDLIBS) $(CFLAGS) $(RM) stamp-gnatlib2-rts stamp-tools gnatbind$(exeext): ada/b_gnatb.o $(CONFIG_H) $(GNATBIND_OBJS) ggc-none.o libcommon-target.a $(LIBDEPS) - $(GCC_LINK) -o $@ ada/b_gnatb.o $(GNATBIND_OBJS) ggc-none.o libcommon-target.a $(LIBS) $(SYSLIBS) $(CFLAGS) + +$(GCC_LINK) -o $@ ada/b_gnatb.o $(GNATBIND_OBJS) ggc-none.o libcommon-target.a $(LIBS) $(SYSLIBS) $(CFLAGS) # use cross-gcc gnat-cross: force diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index e7496321702..9b6e7211bfe 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -614,6 +614,7 @@ record_builtin_type (const char *name, tree type, bool artificial_p) tree type_decl = build_decl (input_location, TYPE_DECL, get_identifier (name), type); DECL_ARTIFICIAL (type_decl) = artificial_p; + TYPE_ARTIFICIAL (type) = artificial_p; gnat_pushdecl (type_decl, Empty); if (debug_hooks->type_decl) @@ -1297,6 +1298,7 @@ create_type_stub_decl (tree type_name, tree type) tree type_decl = build_decl (input_location, TYPE_DECL, type_name, type); DECL_ARTIFICIAL (type_decl) = 1; + TYPE_ARTIFICIAL (type) = 1; return type_decl; } @@ -1329,6 +1331,7 @@ create_type_decl (tree type_name, tree type, struct attrib *attr_list, TYPE_DECL, type_name, type); DECL_ARTIFICIAL (type_decl) = artificial_p; + TYPE_ARTIFICIAL (type) = artificial_p; /* Add this decl to the current binding level. */ gnat_pushdecl (type_decl, gnat_node); diff --git a/gcc/cgraph.h b/gcc/cgraph.h index f912af2a393..91339230a16 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -947,7 +947,8 @@ varpool_can_remove_if_no_refs (struct varpool_node *node) static inline bool varpool_all_refs_explicit_p (struct varpool_node *vnode) { - return (!vnode->externally_visible + return (vnode->analyzed + && !vnode->externally_visible && !vnode->used_from_other_partition && !vnode->force_output); } diff --git a/gcc/config.gcc b/gcc/config.gcc index 73c47d72efe..c77f40b0199 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -245,7 +245,9 @@ md_file= # Obsolete configurations. case ${target} in - i[34567]86-*-interix3* \ + alpha*-dec-osf5.1* \ + | i[34567]86-*-interix3* \ + | mips-sgi-irix6.5 \ | mips*-*-openbsd* \ | score-* \ | *-*-solaris2.8* \ @@ -2245,7 +2247,6 @@ score-*-elf) tm_file="dbxelf.h elfos.h score/elf.h score/score.h newlib-stdint.h" extra_parts="crti.o crtn.o crtbegin.o crtend.o" tmake_file="${tmake_file} score/t-score-elf score/t-score-softfp soft-fp/t-softfp" - extra_objs="score7.o" ;; sh-*-elf* | sh[12346l]*-*-elf* | \ sh-*-linux* | sh[2346lbe]*-*-linux* | \ diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index b3434dd96d9..04cb07d5740 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -55,7 +55,6 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "cselib.h" #include "debug.h" -#include "dwarf2out.h" #include "sched-int.h" #include "sbitmap.h" #include "fibheap.h" @@ -1847,10 +1846,6 @@ static unsigned int initial_ix86_tune_features[X86_TUNE_LAST] = { m_486 | m_PENT | m_ATOM | m_PPRO | m_AMD_MULTIPLE | m_K6 | m_CORE2I7 | m_GENERIC, - /* X86_TUNE_DEEP_BRANCH_PREDICTION */ - m_ATOM | m_PPRO | m_K6_GEODE | m_AMD_MULTIPLE | m_PENT4 - | m_CORE2I7 | m_GENERIC, - /* X86_TUNE_BRANCH_PREDICTION_HINTS: Branch hints were put in P4 based on simulation result. But after P4 was made, no performance benefit was observed with branch hints. It also increases the code size. @@ -8331,31 +8326,11 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED) xops[1] = gen_rtx_SYMBOL_REF (Pmode, GOT_SYMBOL_NAME); - if (! TARGET_DEEP_BRANCH_PREDICTION || !flag_pic) + if (!flag_pic) { xops[2] = gen_rtx_LABEL_REF (Pmode, label ? label : gen_label_rtx ()); - if (!flag_pic) - output_asm_insn ("mov%z0\t{%2, %0|%0, %2}", xops); - else - { - output_asm_insn ("call\t%a2", xops); -#ifdef DWARF2_UNWIND_INFO - /* The call to next label acts as a push. */ - if (dwarf2out_do_frame ()) - { - rtx insn; - start_sequence (); - insn = emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, - gen_rtx_PLUS (Pmode, - stack_pointer_rtx, - GEN_INT (-4)))); - RTX_FRAME_RELATED_P (insn) = 1; - dwarf2out_frame_debug (insn, true); - end_sequence (); - } -#endif - } + output_asm_insn ("mov%z0\t{%2, %0|%0, %2}", xops); #if TARGET_MACHO /* Output the Mach-O "canonical" label name ("Lxx$pb") here too. This @@ -8366,29 +8341,6 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED) targetm.asm_out.internal_label (asm_out_file, "L", CODE_LABEL_NUMBER (XEXP (xops[2], 0))); - - if (flag_pic) - { - output_asm_insn ("pop%z0\t%0", xops); -#ifdef DWARF2_UNWIND_INFO - /* The pop is a pop and clobbers dest, but doesn't restore it - for unwind info purposes. */ - if (dwarf2out_do_frame ()) - { - rtx insn; - start_sequence (); - insn = emit_insn (gen_rtx_SET (VOIDmode, dest, const0_rtx)); - dwarf2out_frame_debug (insn, true); - insn = emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, - gen_rtx_PLUS (Pmode, - stack_pointer_rtx, - GEN_INT (4)))); - RTX_FRAME_RELATED_P (insn) = 1; - dwarf2out_frame_debug (insn, true); - end_sequence (); - } -#endif - } } else { @@ -8396,12 +8348,6 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED) get_pc_thunk_name (name, REGNO (dest)); pic_labels_used |= 1 << REGNO (dest); -#ifdef DWARF2_UNWIND_INFO - /* Ensure all queued register saves are flushed before the - call. */ - if (dwarf2out_do_frame ()) - dwarf2out_flush_queued_reg_saves (); -#endif xops[2] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); xops[2] = gen_rtx_MEM (QImode, xops[2]); output_asm_insn ("call\t%X2", xops); @@ -8416,13 +8362,8 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED) #endif } - if (TARGET_MACHO) - return ""; - - if (!flag_pic || TARGET_DEEP_BRANCH_PREDICTION) + if (!TARGET_MACHO) output_asm_insn ("add%z0\t{%1, %0|%0, %1}", xops); - else - output_asm_insn ("add%z0\t{%1+[.-%a2], %0|%0, %1+(.-%a2)}", xops); return ""; } @@ -10146,7 +10087,11 @@ ix86_expand_prologue (void) insn = emit_insn (gen_set_got_rex64 (pic_offset_table_rtx)); } else - insn = emit_insn (gen_set_got (pic_offset_table_rtx)); + { + insn = emit_insn (gen_set_got (pic_offset_table_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL_RTX); + } } /* In the pic_reg_used case, make sure that the got load isn't deleted @@ -28987,12 +28932,7 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) if (MACHOPIC_ATT_STUB) switch_to_section (darwin_sections[machopic_picsymbol_stub3_section]); else if (MACHOPIC_PURE) - { - if (TARGET_DEEP_BRANCH_PREDICTION) - switch_to_section (darwin_sections[machopic_picsymbol_stub2_section]); - else - switch_to_section (darwin_sections[machopic_picsymbol_stub_section]); - } + switch_to_section (darwin_sections[machopic_picsymbol_stub2_section]); else switch_to_section (darwin_sections[machopic_symbol_stub_section]); @@ -29006,19 +28946,11 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) else if (MACHOPIC_PURE) { /* PIC stub. */ - if (TARGET_DEEP_BRANCH_PREDICTION) - { - /* 25-byte PIC stub using "CALL get_pc_thunk". */ - rtx tmp = gen_rtx_REG (SImode, 2 /* ECX */); - output_set_got (tmp, NULL_RTX); /* "CALL ___<cpu>.get_pc_thunk.cx". */ - fprintf (file, "LPC$%d:\tmovl\t%s-LPC$%d(%%ecx),%%ecx\n", label, lazy_ptr_name, label); - } - else - { - /* 26-byte PIC stub using inline picbase: "CALL L42 ! L42: pop %eax". */ - fprintf (file, "\tcall LPC$%d\nLPC$%d:\tpopl %%ecx\n", label, label); - fprintf (file, "\tmovl %s-LPC$%d(%%ecx),%%ecx\n", lazy_ptr_name, label); - } + /* 25-byte PIC stub using "CALL get_pc_thunk". */ + rtx tmp = gen_rtx_REG (SImode, 2 /* ECX */); + output_set_got (tmp, NULL_RTX); /* "CALL ___<cpu>.get_pc_thunk.cx". */ + fprintf (file, "LPC$%d:\tmovl\t%s-LPC$%d(%%ecx),%%ecx\n", + label, lazy_ptr_name, label); fprintf (file, "\tjmp\t*%%ecx\n"); } else @@ -29047,13 +28979,8 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub) compatibility with existing dylibs. */ if (MACHOPIC_PURE) { - /* PIC stubs. */ - if (TARGET_DEEP_BRANCH_PREDICTION) - /* 25-byte PIC stub using "CALL get_pc_thunk". */ - switch_to_section (darwin_sections[machopic_lazy_symbol_ptr2_section]); - else - /* 26-byte PIC stub using inline picbase: "CALL L42 ! L42: pop %ebx". */ - switch_to_section (darwin_sections[machopic_lazy_symbol_ptr_section]); + /* 25-byte PIC stub using "CALL get_pc_thunk". */ + switch_to_section (darwin_sections[machopic_lazy_symbol_ptr2_section]); } else /* 16-byte -mdynamic-no-pic stub. */ diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index d9317ed739c..a1ac6b656da 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -249,7 +249,6 @@ enum ix86_tune_indices { X86_TUNE_PUSH_MEMORY, X86_TUNE_ZERO_EXTEND_WITH_AND, X86_TUNE_UNROLL_STRLEN, - X86_TUNE_DEEP_BRANCH_PREDICTION, X86_TUNE_BRANCH_PREDICTION_HINTS, X86_TUNE_DOUBLE_WITH_ADD, X86_TUNE_USE_SAHF, @@ -324,8 +323,6 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST]; #define TARGET_ZERO_EXTEND_WITH_AND \ ix86_tune_features[X86_TUNE_ZERO_EXTEND_WITH_AND] #define TARGET_UNROLL_STRLEN ix86_tune_features[X86_TUNE_UNROLL_STRLEN] -#define TARGET_DEEP_BRANCH_PREDICTION \ - ix86_tune_features[X86_TUNE_DEEP_BRANCH_PREDICTION] #define TARGET_BRANCH_PREDICTION_HINTS \ ix86_tune_features[X86_TUNE_BRANCH_PREDICTION_HINTS] #define TARGET_DOUBLE_WITH_ADD ix86_tune_features[X86_TUNE_DOUBLE_WITH_ADD] diff --git a/gcc/config/score/score.c b/gcc/config/score/score.c index a9b6013bda2..6325dd9b7a5 100644 --- a/gcc/config/score/score.c +++ b/gcc/config/score/score.c @@ -47,11 +47,65 @@ #include "target-def.h" #include "integrate.h" #include "langhooks.h" -#include "score7.h" +#include "cfglayout.h" #include "df.h" #include "opts.h" -static void score_option_override (void); +#define SCORE_SDATA_MAX score_sdata_max +#define SCORE_STACK_ALIGN(LOC) (((LOC) + 3) & ~3) +#define SCORE_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8) +#define SCORE_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8) +#define SCORE_DEFAULT_SDATA_MAX 8 + +#define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0) +#define INS_BUF_SZ 128 + +enum score_address_type +{ + SCORE_ADD_REG, + SCORE_ADD_CONST_INT, + SCORE_ADD_SYMBOLIC +}; + +struct score_frame_info +{ + HOST_WIDE_INT total_size; /* bytes that the entire frame takes up */ + HOST_WIDE_INT var_size; /* bytes that variables take up */ + HOST_WIDE_INT args_size; /* bytes that outgoing arguments take up */ + HOST_WIDE_INT gp_reg_size; /* bytes needed to store gp regs */ + HOST_WIDE_INT gp_sp_offset; /* offset from new sp to store gp registers */ + HOST_WIDE_INT cprestore_size; /* # bytes that the .cprestore slot takes up */ + unsigned int mask; /* mask of saved gp registers */ + int num_gp; /* number of gp registers saved */ +}; + +struct score_arg_info +{ + unsigned int num_bytes; /* The argument's size in bytes */ + unsigned int reg_words; /* The number of words passed in registers */ + unsigned int reg_offset; /* The offset of the first register from */ + /* GP_ARG_FIRST or FP_ARG_FIRST etc */ + unsigned int stack_words; /* The number of words that must be passed */ + /* on the stack */ + unsigned int stack_offset; /* The offset from the start of the stack */ + /* overflow area */ +}; + +#ifdef RTX_CODE +struct score_address_info +{ + enum score_address_type type; + rtx reg; + rtx offset; + enum rtx_code code; + enum score_symbol_type symbol_type; +}; +#endif + +static int score_sdata_max; +static char score_ins[INS_BUF_SZ + 8]; + +struct extern_list *extern_head = 0; #undef TARGET_ASM_FILE_START #define TARGET_ASM_FILE_START score_asm_file_start @@ -133,10 +187,235 @@ static void score_option_override (void); #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT score_trampoline_init -struct extern_list *extern_head = 0; +/* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points + to the same object as SYMBOL. */ +static int +score_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset) +{ + if (GET_CODE (symbol) != SYMBOL_REF) + return 0; + + if (CONSTANT_POOL_ADDRESS_P (symbol) + && offset >= 0 + && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol))) + return 1; + + if (SYMBOL_REF_DECL (symbol) != 0 + && offset >= 0 + && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol)))) + return 1; + + return 0; +} + +/* Split X into a base and a constant offset, storing them in *BASE + and *OFFSET respectively. */ +static void +score_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset) +{ + *offset = 0; + + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + + if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT) + { + *offset += INTVAL (XEXP (x, 1)); + x = XEXP (x, 0); + } + + *base = x; +} + +/* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */ +static enum score_symbol_type +score_classify_symbol (rtx x) +{ + if (GET_CODE (x) == LABEL_REF) + return SYMBOL_GENERAL; + + gcc_assert (GET_CODE (x) == SYMBOL_REF); + + if (CONSTANT_POOL_ADDRESS_P (x)) + { + if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE_SDATA_MAX) + return SYMBOL_SMALL_DATA; + return SYMBOL_GENERAL; + } + if (SYMBOL_REF_SMALL_P (x)) + return SYMBOL_SMALL_DATA; + return SYMBOL_GENERAL; +} -/* default 0 = NO_REGS */ -enum reg_class score_char_to_class[256]; +/* Return true if the current function must save REGNO. */ +static int +score_save_reg_p (unsigned int regno) +{ + /* Check call-saved registers. */ + if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) + return 1; + + /* We need to save the old frame pointer before setting up a new one. */ + if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) + return 1; + + /* We need to save the incoming return address if it is ever clobbered + within the function. */ + if (regno == RA_REGNUM && df_regs_ever_live_p (regno)) + return 1; + + return 0; +} + +/* Return one word of double-word value OP, taking into account the fixed + endianness of certain registers. HIGH_P is true to select the high part, + false to select the low part. */ +static rtx +score_subw (rtx op, int high_p) +{ + unsigned int byte; + enum machine_mode mode = GET_MODE (op); + + if (mode == VOIDmode) + mode = DImode; + + byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0; + + if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM) + return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM); + + if (GET_CODE (op) == MEM) + return adjust_address (op, SImode, byte); + + return simplify_gen_subreg (SImode, op, mode, byte); +} + +static struct score_frame_info * +score_cached_frame (void) +{ + static struct score_frame_info _frame_info; + return &_frame_info; +} + +/* Return the bytes needed to compute the frame pointer from the current + stack pointer. SIZE is the size (in bytes) of the local variables. */ +static struct score_frame_info * +score_compute_frame_size (HOST_WIDE_INT size) +{ + unsigned int regno; + struct score_frame_info *f = score_cached_frame (); + + memset (f, 0, sizeof (struct score_frame_info)); + f->gp_reg_size = 0; + f->mask = 0; + f->var_size = SCORE_STACK_ALIGN (size); + f->args_size = crtl->outgoing_args_size; + f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0; + if (f->var_size == 0 && current_function_is_leaf) + f->args_size = f->cprestore_size = 0; + + if (f->args_size == 0 && cfun->calls_alloca) + f->args_size = UNITS_PER_WORD; + + f->total_size = f->var_size + f->args_size + f->cprestore_size; + for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) + { + if (score_save_reg_p (regno)) + { + f->gp_reg_size += GET_MODE_SIZE (SImode); + f->mask |= 1 << (regno - GP_REG_FIRST); + } + } + + if (crtl->calls_eh_return) + { + unsigned int i; + for (i = 0;; ++i) + { + regno = EH_RETURN_DATA_REGNO (i); + if (regno == INVALID_REGNUM) + break; + f->gp_reg_size += GET_MODE_SIZE (SImode); + f->mask |= 1 << (regno - GP_REG_FIRST); + } + } + + f->total_size += f->gp_reg_size; + f->num_gp = f->gp_reg_size / UNITS_PER_WORD; + + if (f->mask) + { + HOST_WIDE_INT offset; + offset = (f->args_size + f->cprestore_size + f->var_size + + f->gp_reg_size - GET_MODE_SIZE (SImode)); + f->gp_sp_offset = offset; + } + else + f->gp_sp_offset = 0; + + return f; +} + +/* Return true if X is a valid base register for the given mode. + Allow only hard registers if STRICT. */ +static int +score_valid_base_register_p (rtx x, int strict) +{ + if (!strict && GET_CODE (x) == SUBREG) + x = SUBREG_REG (x); + + return (GET_CODE (x) == REG + && score_regno_mode_ok_for_base_p (REGNO (x), strict)); +} + +/* Return true if X is a valid address for machine mode MODE. If it is, + fill in INFO appropriately. STRICT is true if we should only accept + hard base registers. */ +static int +score_classify_address (struct score_address_info *info, + enum machine_mode mode, rtx x, int strict) +{ + info->code = GET_CODE (x); + + switch (info->code) + { + case REG: + case SUBREG: + info->type = SCORE_ADD_REG; + info->reg = x; + info->offset = const0_rtx; + return score_valid_base_register_p (info->reg, strict); + case PLUS: + info->type = SCORE_ADD_REG; + info->reg = XEXP (x, 0); + info->offset = XEXP (x, 1); + return (score_valid_base_register_p (info->reg, strict) + && GET_CODE (info->offset) == CONST_INT + && IMM_IN_RANGE (INTVAL (info->offset), 15, 1)); + case PRE_DEC: + case POST_DEC: + case PRE_INC: + case POST_INC: + if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode)) + return false; + info->type = SCORE_ADD_REG; + info->reg = XEXP (x, 0); + info->offset = GEN_INT (GET_MODE_SIZE (mode)); + return score_valid_base_register_p (info->reg, strict); + case CONST_INT: + info->type = SCORE_ADD_CONST_INT; + return IMM_IN_RANGE (INTVAL (x), 15, 1); + case CONST: + case LABEL_REF: + case SYMBOL_REF: + info->type = SCORE_ADD_SYMBOLIC; + return (score_symbolic_constant_p (x, &info->symbol_type) + && (info->symbol_type == SYMBOL_GENERAL + || info->symbol_type == SYMBOL_SMALL_DATA)); + default: + return 0; + } +} /* Implement TARGET_RETURN_IN_MEMORY. In S+core, small structures are returned in a register. @@ -144,20 +423,25 @@ enum reg_class score_char_to_class[256]; static bool score_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_return_in_memory (type, fndecl); - else - gcc_unreachable (); + return ((TYPE_MODE (type) == BLKmode) + || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD) + || (int_size_in_bytes (type) == -1)); } -/* Return nonzero when an argument must be passed by reference. */ -static bool -score_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED, - enum machine_mode mode, const_tree type, - bool named ATTRIBUTE_UNUSED) +/* Return a legitimate address for REG + OFFSET. */ +static rtx +score_add_offset (rtx reg, HOST_WIDE_INT offset) { - /* If we have a variable-sized parameter, we have no choice. */ - return targetm.calls.must_pass_in_stack (mode, type); + if (!IMM_IN_RANGE (offset, 15, 1)) + { + reg = expand_simple_binop (GET_MODE (reg), PLUS, + gen_int_mode (offset & 0xffffc000, + GET_MODE (reg)), + reg, NULL, 0, OPTAB_WIDEN); + offset &= 0x3fff; + } + + return plus_constant (reg, offset); } /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text @@ -167,86 +451,288 @@ score_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, tree function) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function); + rtx this_rtx, temp1, insn, fnaddr; + + /* Pretend to be a post-reload pass while generating rtl. */ + reload_completed = 1; + + /* Mark the end of the (empty) prologue. */ + emit_note (NOTE_INSN_PROLOGUE_END); + + /* We need two temporary registers in some cases. */ + temp1 = gen_rtx_REG (Pmode, 8); + + /* Find out which register contains the "this" pointer. */ + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) + this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1); else - gcc_unreachable (); + this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST); + + /* Add DELTA to THIS_RTX. */ + if (delta != 0) + { + rtx offset = GEN_INT (delta); + if (!(delta >= -32768 && delta <= 32767)) + { + emit_move_insn (temp1, offset); + offset = temp1; + } + emit_insn (gen_add3_insn (this_rtx, this_rtx, offset)); + } + + /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */ + if (vcall_offset != 0) + { + rtx addr; + + /* Set TEMP1 to *THIS_RTX. */ + emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx)); + + /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */ + addr = score_add_offset (temp1, vcall_offset); + + /* Load the offset and add it to THIS_RTX. */ + emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr)); + emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1)); + } + + /* Jump to the target function. */ + fnaddr = XEXP (DECL_RTL (function), 0); + insn = emit_call_insn (gen_sibcall_internal_score7 (fnaddr, const0_rtx)); + SIBLING_CALL_P (insn) = 1; + + /* Run just enough of rest_of_compilation. This sequence was + "borrowed" from alpha.c. */ + insn = get_insns (); + insn_locators_alloc (); + split_all_insns_noflow (); + shorten_branches (insn); + final_start_function (insn, file, 1); + final (insn, file, 1); + final_end_function (); + + /* Clean up the vars set above. Note that final_end_function resets + the global pointer for us. */ + reload_completed = 0; } -/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */ -static bool -score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl, - ATTRIBUTE_UNUSED tree exp) +/* Copy VALUE to a register and return that register. If new psuedos + are allowed, copy it into a new register, otherwise use DEST. */ +static rtx +score_force_temporary (rtx dest, rtx value) { - return true; + if (can_create_pseudo_p ()) + return force_reg (Pmode, value); + else + { + emit_move_insn (copy_rtx (dest), value); + return dest; + } +} + +/* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary + and is used to load the high part into a register. */ +static rtx +score_split_symbol (rtx temp, rtx addr) +{ + rtx high = score_force_temporary (temp, + gen_rtx_HIGH (Pmode, copy_rtx (addr))); + return gen_rtx_LO_SUM (Pmode, high, addr); +} + +/* This function is used to implement LEGITIMIZE_ADDRESS. If X can + be legitimized in a way that the generic machinery might not expect, + return the new address. */ +static rtx +score_legitimize_address (rtx x) +{ + enum score_symbol_type symbol_type; + + if (score_symbolic_constant_p (x, &symbol_type) + && symbol_type == SYMBOL_GENERAL) + return score_split_symbol (0, x); + + if (GET_CODE (x) == PLUS + && GET_CODE (XEXP (x, 1)) == CONST_INT) + { + rtx reg = XEXP (x, 0); + if (!score_valid_base_register_p (reg, 0)) + reg = copy_to_mode_reg (Pmode, reg); + return score_add_offset (reg, INTVAL (XEXP (x, 1))); + } + + return x; +} + +/* Fill INFO with information about a single argument. CUM is the + cumulative state for earlier arguments. MODE is the mode of this + argument and TYPE is its type (if known). NAMED is true if this + is a named (fixed) argument rather than a variable one. */ +static void +score_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, + const_tree type, bool named, struct score_arg_info *info) +{ + int even_reg_p; + unsigned int num_words, max_regs; + + even_reg_p = 0; + if (GET_MODE_CLASS (mode) == MODE_INT + || GET_MODE_CLASS (mode) == MODE_FLOAT) + even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD); + else + if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named) + even_reg_p = 1; + + if (TARGET_MUST_PASS_IN_STACK (mode, type)) + info->reg_offset = ARG_REG_NUM; + else + { + info->reg_offset = cum->num_gprs; + if (even_reg_p) + info->reg_offset += info->reg_offset & 1; + } + + if (mode == BLKmode) + info->num_bytes = int_size_in_bytes (type); + else + info->num_bytes = GET_MODE_SIZE (mode); + + num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + max_regs = ARG_REG_NUM - info->reg_offset; + + /* Partition the argument between registers and stack. */ + info->reg_words = MIN (num_words, max_regs); + info->stack_words = num_words - info->reg_words; + + /* The alignment applied to registers is also applied to stack arguments. */ + if (info->stack_words) + { + info->stack_offset = cum->stack_words; + if (even_reg_p) + info->stack_offset += info->stack_offset & 1; + } } /* Set up the stack and frame (if desired) for the function. */ static void score_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_function_prologue (file, size); - else - gcc_unreachable (); + const char *fnname; + struct score_frame_info *f = score_cached_frame (); + HOST_WIDE_INT tsize = f->total_size; + + fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + if (!flag_inhibit_size_directive) + { + fputs ("\t.ent\t", file); + assemble_name (file, fnname); + fputs ("\n", file); + } + assemble_name (file, fnname); + fputs (":\n", file); + + if (!flag_inhibit_size_directive) + { + fprintf (file, + "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t" + "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d" + ", args= " HOST_WIDE_INT_PRINT_DEC + ", gp= " HOST_WIDE_INT_PRINT_DEC "\n", + (reg_names[(frame_pointer_needed) + ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]), + tsize, + reg_names[RA_REGNUM], + current_function_is_leaf ? 1 : 0, + f->var_size, + f->num_gp, + f->args_size, + f->cprestore_size); + + fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n", + f->mask, + (f->gp_sp_offset - f->total_size)); + } } /* Do any necessary cleanup after a function to restore stack, frame, and regs. */ static void -score_function_epilogue (FILE *file, - HOST_WIDE_INT size ATTRIBUTE_UNUSED) +score_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_function_epilogue (file, size); - else - gcc_unreachable (); + if (!flag_inhibit_size_directive) + { + const char *fnname; + fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + fputs ("\t.end\t", file); + assemble_name (file, fnname); + fputs ("\n", file); + } } -/* Implement TARGET_SCHED_ISSUE_RATE. */ -static int -score_issue_rate (void) +/* Returns true if X contains a SYMBOL_REF. */ +static bool +score_symbolic_expression_p (rtx x) { - return 1; + if (GET_CODE (x) == SYMBOL_REF) + return true; + + if (GET_CODE (x) == CONST) + return score_symbolic_expression_p (XEXP (x, 0)); + + if (UNARY_P (x)) + return score_symbolic_expression_p (XEXP (x, 0)); + + if (ARITHMETIC_P (x)) + return (score_symbolic_expression_p (XEXP (x, 0)) + || score_symbolic_expression_p (XEXP (x, 1))); + + return false; } /* Choose the section to use for the constant rtx expression X that has mode MODE. */ static section * -score_select_rtx_section (enum machine_mode mode, rtx x, - unsigned HOST_WIDE_INT align) +score_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_select_rtx_section (mode, x, align); + if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX) + return get_named_section (0, ".sdata", 0); + else if (flag_pic && score_symbolic_expression_p (x)) + return get_named_section (0, ".data.rel.ro", 3); else - gcc_unreachable (); + return mergeable_constant_section (mode, align, 0); } /* Implement TARGET_IN_SMALL_DATA_P. */ static bool score_in_small_data_p (const_tree decl) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_in_small_data_p (decl); - else - gcc_unreachable (); + HOST_WIDE_INT size; + + if (TREE_CODE (decl) == STRING_CST + || TREE_CODE (decl) == FUNCTION_DECL) + return false; + + if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0) + { + const char *name; + name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); + if (strcmp (name, ".sdata") != 0 + && strcmp (name, ".sbss") != 0) + return true; + if (!DECL_EXTERNAL (decl)) + return false; + } + size = int_size_in_bytes (TREE_TYPE (decl)); + return (size > 0 && size <= SCORE_SDATA_MAX); } /* Implement TARGET_ASM_FILE_START. */ static void score_asm_file_start (void) { - if (TARGET_SCORE7D) - fprintf (asm_out_file, "# Sunplus S+core7d %s rev=%s\n", - TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION); - else if (TARGET_SCORE7) - fprintf (asm_out_file, "# Sunplus S+core7 %s rev=%s\n", - TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION); - else - fprintf (asm_out_file, "# Sunplus S+core unknown %s rev=%s\n", - TARGET_LITTLE_ENDIAN ? "el" : "eb", SCORE_GCC_VERSION); - default_file_start (); + fprintf (asm_out_file, ASM_COMMENT_START + "GCC for S+core %s \n", SCORE_GCC_VERSION); if (flag_pic) fprintf (asm_out_file, "\t.set pic\n"); @@ -257,38 +743,62 @@ score_asm_file_start (void) static void score_asm_file_end (void) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_asm_file_end (); - else - gcc_unreachable (); + tree name_tree; + struct extern_list *p; + if (extern_head) + { + fputs ("\n", asm_out_file); + for (p = extern_head; p != 0; p = p->next) + { + name_tree = get_identifier (p->name); + if (!TREE_ASM_WRITTEN (name_tree) + && TREE_SYMBOL_REFERENCED (name_tree)) + { + TREE_ASM_WRITTEN (name_tree) = 1; + fputs ("\t.extern\t", asm_out_file); + assemble_name (asm_out_file, p->name); + fprintf (asm_out_file, ", %d\n", p->size); + } + } + } } /* Implement TARGET_OPTION_OVERRIDE hook. */ static void score_option_override (void) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_option_override (); + flag_pic = false; + score_sdata_max = SCORE_DEFAULT_SDATA_MAX; + } /* Implement REGNO_REG_CLASS macro. */ int score_reg_class (int regno) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_reg_class (regno); - else - gcc_unreachable (); + int c; + gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER); + + if (regno == FRAME_POINTER_REGNUM + || regno == ARG_POINTER_REGNUM) + return ALL_REGS; + + for (c = 0; c < N_REG_CLASSES; c++) + if (TEST_HARD_REG_BIT (reg_class_contents[c], regno)) + return c; + + return NO_REGS; } /* Implement PREFERRED_RELOAD_CLASS macro. */ enum reg_class score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_preferred_reload_class (x, rclass); - else - gcc_unreachable (); + if (reg_class_subset_p (G16_REGS, rclass)) + return G16_REGS; + if (reg_class_subset_p (G32_REGS, rclass)) + return G32_REGS; + return rclass; } /* Implement SECONDARY_INPUT_RELOAD_CLASS @@ -298,10 +808,13 @@ score_secondary_reload_class (enum reg_class rclass, enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_secondary_reload_class (rclass, mode, x); - else - gcc_unreachable (); + int regno = -1; + if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG) + regno = true_regnum (x); + + if (!GR_REG_CLASS_P (rclass)) + return GP_REG_P (regno) ? NO_REGS : G32_REGS; + return NO_REGS; } @@ -310,20 +823,23 @@ score_secondary_reload_class (enum reg_class rclass, int score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_hard_regno_mode_ok (regno, mode); + int size = GET_MODE_SIZE (mode); + enum mode_class mclass = GET_MODE_CLASS (mode); + + if (mclass == MODE_CC) + return regno == CC_REGNUM; + else if (regno == FRAME_POINTER_REGNUM + || regno == ARG_POINTER_REGNUM) + return mclass == MODE_INT; + else if (GP_REG_P (regno)) + /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */ + return !(regno & 1) || (size <= UNITS_PER_WORD); + else if (CE_REG_P (regno)) + return (mclass == MODE_INT + && ((size <= UNITS_PER_WORD) + || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD))); else - gcc_unreachable (); -} - -/* We can always eliminate to the hard frame pointer. We can eliminate - to the stack pointer unless a frame pointer is needed. */ - -static bool -score_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) -{ - return (to == HARD_FRAME_POINTER_REGNUM - || (to == STACK_POINTER_REGNUM && !frame_pointer_needed)); + return (mclass == MODE_INT) && (size <= UNITS_PER_WORD); } /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame @@ -333,121 +849,153 @@ HOST_WIDE_INT score_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_initial_elimination_offset (from, to); - else - gcc_unreachable (); -} - -/* Argument support functions. */ - -/* Initialize CUMULATIVE_ARGS for a function. */ -void -score_init_cumulative_args (CUMULATIVE_ARGS *cum, - tree fntype ATTRIBUTE_UNUSED, - rtx libname ATTRIBUTE_UNUSED) -{ - memset (cum, 0, sizeof (CUMULATIVE_ARGS)); + struct score_frame_info *f = score_compute_frame_size (get_frame_size ()); + switch (from) + { + case ARG_POINTER_REGNUM: + return f->total_size; + case FRAME_POINTER_REGNUM: + return 0; + default: + gcc_unreachable (); + } } /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */ static void -score_function_arg_advance (cumulative_args_t cum, enum machine_mode mode, +score_function_arg_advance (cumulative_args_t cum_args, enum machine_mode mode, const_tree type, bool named) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_function_arg_advance (get_cumulative_args (cum), mode, type, named); - else - gcc_unreachable (); + struct score_arg_info info; + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args); + score_classify_arg (cum, mode, type, named, &info); + cum->num_gprs = info.reg_offset + info.reg_words; + if (info.stack_words > 0) + cum->stack_words = info.stack_offset + info.stack_words; + cum->arg_number++; } /* Implement TARGET_ARG_PARTIAL_BYTES macro. */ int -score_arg_partial_bytes (cumulative_args_t cum, +score_arg_partial_bytes (cumulative_args_t cum_args, enum machine_mode mode, tree type, bool named) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_arg_partial_bytes (get_cumulative_args (cum), mode, type, - named); - else - gcc_unreachable (); + struct score_arg_info info; + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args); + score_classify_arg (cum, mode, type, named, &info); + return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0; } /* Implement TARGET_FUNCTION_ARG hook. */ static rtx -score_function_arg (cumulative_args_t cum, enum machine_mode mode, +score_function_arg (cumulative_args_t cum_args, enum machine_mode mode, const_tree type, bool named) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_function_arg (get_cumulative_args (cum), mode, type, named); + struct score_arg_info info; + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args); + + if (mode == VOIDmode || !named) + return 0; + + score_classify_arg (cum, mode, type, named, &info); + + if (info.reg_offset == ARG_REG_NUM) + return 0; + + if (!info.stack_words) + return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset); else - gcc_unreachable (); + { + rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words)); + unsigned int i, part_offset = 0; + for (i = 0; i < info.reg_words; i++) + { + rtx reg; + reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i); + XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg, + GEN_INT (part_offset)); + part_offset += UNITS_PER_WORD; + } + return ret; + } } /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls, VALTYPE is the return type and MODE is VOIDmode. For libcalls, VALTYPE is null and MODE is the mode of the return value. */ rtx -score_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED, - enum machine_mode mode) +score_function_value (const_tree valtype, const_tree func, enum machine_mode mode) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_function_value (valtype, func, mode); - else - gcc_unreachable (); + if (valtype) + { + int unsignedp; + mode = TYPE_MODE (valtype); + unsignedp = TYPE_UNSIGNED (valtype); + mode = promote_function_mode (valtype, mode, &unsignedp, func, 1); + } + return gen_rtx_REG (mode, RT_REGNUM); } /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */ + static void score_asm_trampoline_template (FILE *f) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_asm_trampoline_template (f); - else - gcc_unreachable (); + fprintf (f, "\t.set r1\n"); + fprintf (f, "\tmv r31, r3\n"); + fprintf (f, "\tbl nextinsn\n"); + fprintf (f, "nextinsn:\n"); + fprintf (f, "\tlw r1, [r3, 6*4-8]\n"); + fprintf (f, "\tlw r23, [r3, 6*4-4]\n"); + fprintf (f, "\tmv r3, r31\n"); + fprintf (f, "\tbr! r1\n"); + fprintf (f, "\tnop!\n"); + fprintf (f, "\t.set nor1\n"); } /* Implement TARGET_TRAMPOLINE_INIT. */ static void score_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) { - if ( TARGET_SCORE7 || TARGET_SCORE7D) - score7_trampoline_init (m_tramp, fndecl, chain_value); - else - gcc_unreachable (); +#define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD) + + rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); + rtx mem; + + emit_block_move (m_tramp, assemble_trampoline_template (), + GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); + + mem = adjust_address (m_tramp, SImode, CODE_SIZE); + emit_move_insn (mem, fnaddr); + mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode)); + emit_move_insn (mem, chain_value); + +#undef CODE_SIZE } /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */ int score_regno_mode_ok_for_base_p (int regno, int strict) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_regno_mode_ok_for_base_p (regno, strict); - else - gcc_unreachable (); + if (regno >= FIRST_PSEUDO_REGISTER) + { + if (!strict) + return 1; + regno = reg_renumber[regno]; + } + if (regno == ARG_POINTER_REGNUM + || regno == FRAME_POINTER_REGNUM) + return 1; + return GP_REG_P (regno); } -/* Implement TARGET_LEGITIMIZE_ADDRESS_P. */ +/* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */ static bool score_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_legitimate_address_p (mode, x, strict); - else - gcc_unreachable (); -} + struct score_address_info addr; -/* This function is used to implement LEGITIMIZE_ADDRESS. If X can - be legitimized in a way that the generic machinery might not expect, - return the new address, else return X. */ -static rtx -score_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED) -{ - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_legitimize_address (x); - else - gcc_unreachable (); + return score_classify_address (&addr, mode, x, strict); } /* Return a number assessing the cost of moving a register in class @@ -456,21 +1004,226 @@ int score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, enum reg_class from, enum reg_class to) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_register_move_cost (mode, from, to); + if (GR_REG_CLASS_P (from)) + { + if (GR_REG_CLASS_P (to)) + return 2; + else if (SP_REG_CLASS_P (to)) + return 4; + else if (CP_REG_CLASS_P (to)) + return 5; + else if (CE_REG_CLASS_P (to)) + return 6; + } + if (GR_REG_CLASS_P (to)) + { + if (GR_REG_CLASS_P (from)) + return 2; + else if (SP_REG_CLASS_P (from)) + return 4; + else if (CP_REG_CLASS_P (from)) + return 5; + else if (CE_REG_CLASS_P (from)) + return 6; + } + return 12; +} + +/* Return the number of instructions needed to load a symbol of the + given type into a register. */ +static int +score_symbol_insns (enum score_symbol_type type) +{ + switch (type) + { + case SYMBOL_GENERAL: + return 2; + + case SYMBOL_SMALL_DATA: + return 1; + } + + gcc_unreachable (); +} + +/* Return the number of instructions needed to load or store a value + of mode MODE at X. Return 0 if X isn't valid for MODE. */ +static int +score_address_insns (rtx x, enum machine_mode mode) +{ + struct score_address_info addr; + int factor; + + if (mode == BLKmode) + factor = 1; else - gcc_unreachable (); + factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + + if (score_classify_address (&addr, mode, x, false)) + switch (addr.type) + { + case SCORE_ADD_REG: + case SCORE_ADD_CONST_INT: + return factor; + + case SCORE_ADD_SYMBOLIC: + return factor * score_symbol_insns (addr.symbol_type); + } + return 0; } /* Implement TARGET_RTX_COSTS macro. */ bool -score_rtx_costs (rtx x, int code, int outer_code, int *total, - bool speed ATTRIBUTE_UNUSED) +score_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed ATTRIBUTE_UNUSED) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_rtx_costs (x, code, outer_code, total, speed); - else - gcc_unreachable (); + enum machine_mode mode = GET_MODE (x); + + switch (code) + { + case CONST_INT: + if (outer_code == SET) + { + if (((INTVAL (x) & 0xffff) == 0) + || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767)) + *total = COSTS_N_INSNS (1); + else + *total = COSTS_N_INSNS (2); + } + else if (outer_code == PLUS || outer_code == MINUS) + { + if (INTVAL (x) >= -8192 && INTVAL (x) <= 8191) + *total = 0; + else if (((INTVAL (x) & 0xffff) == 0) + || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767)) + *total = 1; + else + *total = COSTS_N_INSNS (2); + } + else if (outer_code == AND || outer_code == IOR) + { + if (INTVAL (x) >= 0 && INTVAL (x) <= 16383) + *total = 0; + else if (((INTVAL (x) & 0xffff) == 0) + || (INTVAL (x) >= 0 && INTVAL (x) <= 65535)) + *total = 1; + else + *total = COSTS_N_INSNS (2); + } + else + { + *total = 0; + } + return true; + + case CONST: + case SYMBOL_REF: + case LABEL_REF: + case CONST_DOUBLE: + *total = COSTS_N_INSNS (2); + return true; + + case MEM: + { + /* If the address is legitimate, return the number of + instructions it needs, otherwise use the default handling. */ + int n = score_address_insns (XEXP (x, 0), GET_MODE (x)); + if (n > 0) + { + *total = COSTS_N_INSNS (n + 1); + return true; + } + return false; + } + + case FFS: + *total = COSTS_N_INSNS (6); + return true; + + case NOT: + *total = COSTS_N_INSNS (1); + return true; + + case AND: + case IOR: + case XOR: + if (mode == DImode) + { + *total = COSTS_N_INSNS (2); + return true; + } + return false; + + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if (mode == DImode) + { + *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT) + ? 4 : 12); + return true; + } + return false; + + case ABS: + *total = COSTS_N_INSNS (4); + return true; + + case PLUS: + case MINUS: + if (mode == DImode) + { + *total = COSTS_N_INSNS (4); + return true; + } + *total = COSTS_N_INSNS (1); + return true; + + case NEG: + if (mode == DImode) + { + *total = COSTS_N_INSNS (4); + return true; + } + return false; + + case MULT: + *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12); + return true; + + case DIV: + case MOD: + case UDIV: + case UMOD: + *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33); + return true; + + case SIGN_EXTEND: + case ZERO_EXTEND: + switch (GET_MODE (XEXP (x, 0))) + { + case QImode: + case HImode: + if (GET_CODE (XEXP (x, 0)) == MEM) + { + *total = COSTS_N_INSNS (2); + + if (!TARGET_LITTLE_ENDIAN && + side_effects_p (XEXP (XEXP (x, 0), 0))) + *total = 100; + } + else + *total = COSTS_N_INSNS (1); + break; + + default: + *total = COSTS_N_INSNS (1); + break; + } + return true; + + default: + return false; + } } /* Implement TARGET_ADDRESS_COST macro. */ @@ -478,10 +1231,7 @@ int score_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_address_cost (addr); - else - gcc_unreachable (); + return score_address_insns (addr, SImode); } /* Implement ASM_OUTPUT_EXTERNAL macro. */ @@ -489,10 +1239,17 @@ int score_output_external (FILE *file ATTRIBUTE_UNUSED, tree decl, const char *name) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_output_external (file, decl, name); - else - gcc_unreachable (); + register struct extern_list *p; + + if (score_in_small_data_p (decl)) + { + p = ggc_alloc_extern_list (); + p->next = extern_head; + p->name = name; + p->size = int_size_in_bytes (TREE_TYPE (decl)); + extern_head = p; + } + return 0; } /* Implement RETURN_ADDR_RTX. Note, we do not support moving @@ -500,40 +1257,363 @@ score_output_external (FILE *file ATTRIBUTE_UNUSED, rtx score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_return_addr (count, frame); - else - gcc_unreachable (); + if (count != 0) + return const0_rtx; + return get_hard_reg_initial_val (Pmode, RA_REGNUM); } /* Implement PRINT_OPERAND macro. */ +/* Score-specific operand codes: + '[' print .set nor1 directive + ']' print .set r1 directive + 'U' print hi part of a CONST_INT rtx + 'E' print log2(v) + 'F' print log2(~v) + 'D' print SFmode const double + 'S' selectively print "!" if operand is 15bit instruction accessible + 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!" + 'L' low part of DImode reg operand + 'H' high part of DImode reg operand + 'C' print part of opcode for a branch condition. */ void score_print_operand (FILE *file, rtx op, int c) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_print_operand (file, op, c); + enum rtx_code code = UNKNOWN; + if (!PRINT_OPERAND_PUNCT_VALID_P (c)) + code = GET_CODE (op); + + if (c == '[') + { + fprintf (file, ".set r1\n"); + } + else if (c == ']') + { + fprintf (file, "\n\t.set nor1"); + } + else if (c == 'U') + { + gcc_assert (code == CONST_INT); + fprintf (file, HOST_WIDE_INT_PRINT_HEX, + (INTVAL (op) >> 16) & 0xffff); + } + else if (c == 'D') + { + if (GET_CODE (op) == CONST_DOUBLE) + { + rtx temp = gen_lowpart (SImode, op); + gcc_assert (GET_MODE (op) == SFmode); + fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff); + } + else + output_addr_const (file, op); + } + else if (c == 'S') + { + gcc_assert (code == REG); + if (G16_REG_P (REGNO (op))) + fprintf (file, "!"); + } + else if (c == 'V') + { + gcc_assert (code == REG); + fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!"); + } + else if (c == 'C') + { + enum machine_mode mode = GET_MODE (XEXP (op, 0)); + + switch (code) + { + case EQ: fputs ("eq", file); break; + case NE: fputs ("ne", file); break; + case GT: fputs ("gt", file); break; + case GE: fputs (mode != CCmode ? "pl" : "ge", file); break; + case LT: fputs (mode != CCmode ? "mi" : "lt", file); break; + case LE: fputs ("le", file); break; + case GTU: fputs ("gtu", file); break; + case GEU: fputs ("cs", file); break; + case LTU: fputs ("cc", file); break; + case LEU: fputs ("leu", file); break; + default: + output_operand_lossage ("invalid operand for code: '%c'", code); + } + } + else if (c == 'E') + { + unsigned HOST_WIDE_INT i; + unsigned HOST_WIDE_INT pow2mask = 1; + unsigned HOST_WIDE_INT val; + + val = INTVAL (op); + for (i = 0; i < 32; i++) + { + if (val == pow2mask) + break; + pow2mask <<= 1; + } + gcc_assert (i < 32); + fprintf (file, HOST_WIDE_INT_PRINT_HEX, i); + } + else if (c == 'F') + { + unsigned HOST_WIDE_INT i; + unsigned HOST_WIDE_INT pow2mask = 1; + unsigned HOST_WIDE_INT val; + + val = ~INTVAL (op); + for (i = 0; i < 32; i++) + { + if (val == pow2mask) + break; + pow2mask <<= 1; + } + gcc_assert (i < 32); + fprintf (file, HOST_WIDE_INT_PRINT_HEX, i); + } + else if (code == REG) + { + int regnum = REGNO (op); + if ((c == 'H' && !WORDS_BIG_ENDIAN) + || (c == 'L' && WORDS_BIG_ENDIAN)) + regnum ++; + fprintf (file, "%s", reg_names[regnum]); + } else - gcc_unreachable (); + { + switch (code) + { + case MEM: + score_print_operand_address (file, op); + break; + default: + output_addr_const (file, op); + } + } } /* Implement PRINT_OPERAND_ADDRESS macro. */ void score_print_operand_address (FILE *file, rtx x) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_print_operand_address (file, x); - else - gcc_unreachable (); + struct score_address_info addr; + enum rtx_code code = GET_CODE (x); + enum machine_mode mode = GET_MODE (x); + + if (code == MEM) + x = XEXP (x, 0); + + if (score_classify_address (&addr, mode, x, true)) + { + switch (addr.type) + { + case SCORE_ADD_REG: + { + switch (addr.code) + { + case PRE_DEC: + fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)], + INTVAL (addr.offset)); + break; + case POST_DEC: + fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)], + INTVAL (addr.offset)); + break; + case PRE_INC: + fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)], + INTVAL (addr.offset)); + break; + case POST_INC: + fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)], + INTVAL (addr.offset)); + break; + default: + if (INTVAL(addr.offset) == 0) + fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]); + else + fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)], + INTVAL(addr.offset)); + break; + } + } + return; + case SCORE_ADD_CONST_INT: + case SCORE_ADD_SYMBOLIC: + output_addr_const (file, x); + return; + } + } + print_rtl (stderr, x); + gcc_unreachable (); } /* Implement SELECT_CC_MODE macro. */ enum machine_mode score_select_cc_mode (enum rtx_code op, rtx x, rtx y) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_select_cc_mode (op, x, y); + if ((op == EQ || op == NE || op == LT || op == GE) + && y == const0_rtx + && GET_MODE (x) == SImode) + { + switch (GET_CODE (x)) + { + case PLUS: + case MINUS: + case NEG: + case AND: + case IOR: + case XOR: + case NOT: + case ASHIFT: + case LSHIFTRT: + case ASHIFTRT: + return CC_NZmode; + + case SIGN_EXTEND: + case ZERO_EXTEND: + case ROTATE: + case ROTATERT: + return (op == LT || op == GE) ? CC_Nmode : CCmode; + + default: + return CCmode; + } + } + + if ((op == EQ || op == NE) + && (GET_CODE (y) == NEG) + && register_operand (XEXP (y, 0), SImode) + && register_operand (x, SImode)) + { + return CC_NZmode; + } + + return CCmode; +} + +/* Generate the prologue instructions for entry into a S+core function. */ +void +score_prologue (void) +{ +#define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1 + + struct score_frame_info *f = score_compute_frame_size (get_frame_size ()); + HOST_WIDE_INT size; + int regno; + + size = f->total_size - f->gp_reg_size; + + if (flag_pic) + emit_insn (gen_cpload_score7 ()); + + for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--) + { + if (BITSET_P (f->mask, regno - GP_REG_FIRST)) + { + rtx mem = gen_rtx_MEM (SImode, + gen_rtx_PRE_DEC (SImode, stack_pointer_rtx)); + rtx reg = gen_rtx_REG (SImode, regno); + if (!crtl->calls_eh_return) + MEM_READONLY_P (mem) = 1; + EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg))); + } + } + + if (size > 0) + { + rtx insn; + + if (size >= -32768 && size <= 32767) + EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-size)))); + else + { + EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE_PROLOGUE_TEMP_REGNUM), + GEN_INT (size))); + EMIT_PL (emit_insn + (gen_sub3_insn (stack_pointer_rtx, + stack_pointer_rtx, + gen_rtx_REG (Pmode, + SCORE_PROLOGUE_TEMP_REGNUM)))); + } + insn = get_last_insn (); + REG_NOTES (insn) = + alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + -size)), + REG_NOTES (insn)); + } + + if (frame_pointer_needed) + EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); + + if (flag_pic && f->cprestore_size) + { + if (frame_pointer_needed) + emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size))); + else + emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size))); + } + +#undef EMIT_PL +} + +/* Generate the epilogue instructions in a S+core function. */ +void +score_epilogue (int sibcall_p) +{ + struct score_frame_info *f = score_compute_frame_size (get_frame_size ()); + HOST_WIDE_INT size; + int regno; + rtx base; + + size = f->total_size - f->gp_reg_size; + + if (!frame_pointer_needed) + base = stack_pointer_rtx; else - gcc_unreachable (); + base = hard_frame_pointer_rtx; + + if (size) + { + if (size >= -32768 && size <= 32767) + emit_insn (gen_add3_insn (base, base, GEN_INT (size))); + else + { + emit_move_insn (gen_rtx_REG (Pmode, SCORE_EPILOGUE_TEMP_REGNUM), + GEN_INT (size)); + emit_insn (gen_add3_insn (base, base, + gen_rtx_REG (Pmode, + SCORE_EPILOGUE_TEMP_REGNUM))); + } + } + + if (base != stack_pointer_rtx) + emit_move_insn (stack_pointer_rtx, base); + + if (crtl->calls_eh_return) + emit_insn (gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + EH_RETURN_STACKADJ_RTX)); + + for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++) + { + if (BITSET_P (f->mask, regno - GP_REG_FIRST)) + { + rtx mem = gen_rtx_MEM (SImode, + gen_rtx_POST_INC (SImode, stack_pointer_rtx)); + rtx reg = gen_rtx_REG (SImode, regno); + + if (!crtl->calls_eh_return) + MEM_READONLY_P (mem) = 1; + + emit_insn (gen_popsi_score7 (reg, mem)); + } + } + + if (!sibcall_p) + emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM))); } /* Return true if X is a symbolic constant that can be calculated in @@ -542,140 +1622,354 @@ score_select_cc_mode (enum rtx_code op, rtx x, rtx y) int score_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_symbolic_constant_p (x, symbol_type); - else - gcc_unreachable (); -} + HOST_WIDE_INT offset; -/* Generate the prologue instructions for entry into a S+core function. */ -void -score_prologue (void) -{ - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_prologue (); + score_split_const (x, &x, &offset); + if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) + *symbol_type = score_classify_symbol (x); else - gcc_unreachable (); + return 0; + + if (offset == 0) + return 1; + + /* if offset > 15bit, must reload */ + if (!IMM_IN_RANGE (offset, 15, 1)) + return 0; + + switch (*symbol_type) + { + case SYMBOL_GENERAL: + return 1; + case SYMBOL_SMALL_DATA: + return score_offset_within_object_p (x, offset); + } + gcc_unreachable (); } -/* Generate the epilogue instructions in a S+core function. */ void -score_epilogue (int sibcall_p) +score_movsicc (rtx *ops) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_epilogue (sibcall_p); - else - gcc_unreachable (); + enum machine_mode mode; + + mode = score_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]); + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM), + gen_rtx_COMPARE (mode, XEXP (ops[1], 0), + XEXP (ops[1], 1)))); } /* Call and sibcall pattern all need call this function. */ void score_call (rtx *ops, bool sib) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_call (ops, sib); + rtx addr = XEXP (ops[0], 0); + if (!call_insn_operand (addr, VOIDmode)) + { + rtx oaddr = addr; + addr = gen_reg_rtx (Pmode); + gen_move_insn (addr, oaddr); + } + + if (sib) + emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1])); else - gcc_unreachable (); + emit_call_insn (gen_call_internal_score7 (addr, ops[1])); } /* Call value and sibcall value pattern all need call this function. */ void score_call_value (rtx *ops, bool sib) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_call_value (ops, sib); - else - gcc_unreachable (); -} - -void -score_movsicc (rtx *ops) -{ - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_movsicc (ops); + rtx result = ops[0]; + rtx addr = XEXP (ops[1], 0); + rtx arg = ops[2]; + + if (!call_insn_operand (addr, VOIDmode)) + { + rtx oaddr = addr; + addr = gen_reg_rtx (Pmode); + gen_move_insn (addr, oaddr); + } + + if (sib) + emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg)); else - gcc_unreachable (); + emit_call_insn (gen_call_value_internal_score7 (result, addr, arg)); } /* Machine Split */ void score_movdi (rtx *ops) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_movdi (ops); + rtx dst = ops[0]; + rtx src = ops[1]; + rtx dst0 = score_subw (dst, 0); + rtx dst1 = score_subw (dst, 1); + rtx src0 = score_subw (src, 0); + rtx src1 = score_subw (src, 1); + + if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src)) + { + emit_move_insn (dst1, src1); + emit_move_insn (dst0, src0); + } else - gcc_unreachable (); + { + emit_move_insn (dst0, src0); + emit_move_insn (dst1, src1); + } } void score_zero_extract_andi (rtx *ops) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - score7_zero_extract_andi (ops); + if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode)) + emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2])); else - gcc_unreachable (); + { + unsigned HOST_WIDE_INT mask; + mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U)); + mask = mask << INTVAL (ops[2]); + emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0], + gen_int_mode (mask, SImode))); + } } -/* Output asm insn for move. */ -const char * -score_move (rtx *ops) +/* Check addr could be present as PRE/POST mode. */ +static bool +score_pindex_mem (rtx addr) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_move (ops); - else - gcc_unreachable (); + if (GET_CODE (addr) == MEM) + { + switch (GET_CODE (XEXP (addr, 0))) + { + case PRE_DEC: + case POST_DEC: + case PRE_INC: + case POST_INC: + return true; + default: + break; + } + } + return false; +} + +/* Output asm code for ld/sw insn. */ +static int +score_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit) +{ + struct score_address_info ai; + + gcc_assert (GET_CODE (ops[idata]) == REG); + gcc_assert (score_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true)); + + if (!score_pindex_mem (ops[iaddr]) + && ai.type == SCORE_ADD_REG + && GET_CODE (ai.offset) == CONST_INT + && G16_REG_P (REGNO (ops[idata])) + && G16_REG_P (REGNO (ai.reg))) + { + if (INTVAL (ai.offset) == 0) + { + ops[iaddr] = ai.reg; + return snprintf (ip, INS_BUF_SZ, + "!\t%%%d, [%%%d]", idata, iaddr); + } + if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM) + { + HOST_WIDE_INT offset = INTVAL (ai.offset); + if (SCORE_ALIGN_UNIT (offset, unit) + && (((offset >> unit) >= 0) && ((offset >> unit) <= 31))) + { + ops[iaddr] = ai.offset; + return snprintf (ip, INS_BUF_SZ, + "p!\t%%%d, %%c%d", idata, iaddr); + } + } + } + return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr); } /* Output asm insn for load. */ const char * score_linsn (rtx *ops, enum score_mem_unit unit, bool sign) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_linsn (ops, unit, sign); + const char *pre_ins[] = + {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"}; + char *ip; + + strcpy (score_ins, pre_ins[(sign ? 4 : 0) + unit]); + ip = score_ins + strlen (score_ins); + + if ((!sign && unit != SCORE_HWORD) + || (sign && unit != SCORE_BYTE)) + score_pr_addr_post (ops, 0, 1, ip, unit); else - gcc_unreachable (); + snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1"); + + return score_ins; } /* Output asm insn for store. */ const char * score_sinsn (rtx *ops, enum score_mem_unit unit) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_sinsn (ops, unit); - else - gcc_unreachable (); + const char *pre_ins[] = {"sb", "sh", "sw"}; + char *ip; + + strcpy (score_ins, pre_ins[unit]); + ip = score_ins + strlen (score_ins); + score_pr_addr_post (ops, 1, 0, ip, unit); + return score_ins; } /* Output asm insn for load immediate. */ const char * score_limm (rtx *ops) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_limm (ops); + HOST_WIDE_INT v; + + gcc_assert (GET_CODE (ops[0]) == REG); + gcc_assert (GET_CODE (ops[1]) == CONST_INT); + + v = INTVAL (ops[1]); + if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0)) + return "ldiu!\t%0, %c1"; + else if (IMM_IN_RANGE (v, 16, 1)) + return "ldi\t%0, %c1"; + else if ((v & 0xffff) == 0) + return "ldis\t%0, %U1"; else - gcc_unreachable (); + return "li\t%0, %c1"; } +/* Output asm insn for move. */ +const char * +score_move (rtx *ops) +{ + gcc_assert (GET_CODE (ops[0]) == REG); + gcc_assert (GET_CODE (ops[1]) == REG); + + if (G16_REG_P (REGNO (ops[0]))) + { + if (G16_REG_P (REGNO (ops[1]))) + return "mv!\t%0, %1"; + else + return "mlfh!\t%0, %1"; + } + else if (G16_REG_P (REGNO (ops[1]))) + return "mhfl!\t%0, %1"; + else + return "mv\t%0, %1"; +} /* Generate add insn. */ const char * score_select_add_imm (rtx *ops, bool set_cc) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_select_add_imm (ops, set_cc); + HOST_WIDE_INT v = INTVAL (ops[2]); + + gcc_assert (GET_CODE (ops[2]) == CONST_INT); + gcc_assert (REGNO (ops[0]) == REGNO (ops[1])); + + if (set_cc && G16_REG_P (REGNO (ops[0]))) + { + if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15)) + { + ops[2] = GEN_INT (ffs (v) - 1); + return "addei!\t%0, %c2"; + } + + if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15)) + { + ops[2] = GEN_INT (ffs (-v) - 1); + return "subei!\t%0, %c2"; + } + } + + if (set_cc) + return "addi.c\t%0, %c2"; else - gcc_unreachable (); + return "addi\t%0, %c2"; } /* Output arith insn. */ const char * score_select (rtx *ops, const char *inst_pre, - bool commu, const char *letter, bool set_cc) + bool commu, const char *letter, bool set_cc) { - if (TARGET_SCORE7 || TARGET_SCORE7D) - return score7_select (ops, inst_pre, commu, letter, set_cc); + gcc_assert (GET_CODE (ops[0]) == REG); + gcc_assert (GET_CODE (ops[1]) == REG); + + if (set_cc && G16_REG_P (REGNO (ops[0])) + && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1) + && REGNO (ops[0]) == REGNO (ops[1])) + { + snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter); + return score_ins; + } + + if (commu && set_cc && G16_REG_P (REGNO (ops[0])) + && G16_REG_P (REGNO (ops[1])) + && REGNO (ops[0]) == REGNO (ops[2])) + { + gcc_assert (GET_CODE (ops[2]) == REG); + snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter); + return score_ins; + } + + if (set_cc) + snprintf (score_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter); else - gcc_unreachable (); + snprintf (score_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter); + return score_ins; +} + +/* Return nonzero when an argument must be passed by reference. */ +static bool +score_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED, + enum machine_mode mode, const_tree type, + bool named ATTRIBUTE_UNUSED) +{ + /* If we have a variable-sized parameter, we have no choice. */ + return targetm.calls.must_pass_in_stack (mode, type); +} + +/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */ +static bool +score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl, + ATTRIBUTE_UNUSED tree exp) +{ + return true; +} + +/* Implement TARGET_SCHED_ISSUE_RATE. */ +static int +score_issue_rate (void) +{ + return 1; +} + +/* We can always eliminate to the hard frame pointer. We can eliminate + to the stack pointer unless a frame pointer is needed. */ + +static bool +score_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) +{ + return (to == HARD_FRAME_POINTER_REGNUM + || (to == STACK_POINTER_REGNUM && !frame_pointer_needed)); +} + +/* Argument support functions. */ + +/* Initialize CUMULATIVE_ARGS for a function. */ +void +score_init_cumulative_args (CUMULATIVE_ARGS *cum, + tree fntype ATTRIBUTE_UNUSED, + rtx libname ATTRIBUTE_UNUSED) +{ + memset (cum, 0, sizeof (CUMULATIVE_ARGS)); } static void diff --git a/gcc/config/score/score7.c b/gcc/config/score/score7.c deleted file mode 100644 index 8a57362bab8..00000000000 --- a/gcc/config/score/score7.c +++ /dev/null @@ -1,1797 +0,0 @@ -/* score7.c for Sunplus S+CORE processor - Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. - Contributed by Sunnorth - - 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 "recog.h" -#include "diagnostic-core.h" -#include "output.h" -#include "tree.h" -#include "function.h" -#include "expr.h" -#include "optabs.h" -#include "flags.h" -#include "reload.h" -#include "tm_p.h" -#include "ggc.h" -#include "gstab.h" -#include "hashtab.h" -#include "debug.h" -#include "target.h" -#include "target-def.h" -#include "integrate.h" -#include "langhooks.h" -#include "cfglayout.h" -#include "score7.h" -#include "df.h" - -#define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0) -#define INS_BUF_SZ 128 - -extern enum reg_class score_char_to_class[256]; - -static int score7_sdata_max; -static char score7_ins[INS_BUF_SZ + 8]; - -/* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points - to the same object as SYMBOL. */ -static int -score7_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset) -{ - if (GET_CODE (symbol) != SYMBOL_REF) - return 0; - - if (CONSTANT_POOL_ADDRESS_P (symbol) - && offset >= 0 - && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol))) - return 1; - - if (SYMBOL_REF_DECL (symbol) != 0 - && offset >= 0 - && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol)))) - return 1; - - return 0; -} - -/* Split X into a base and a constant offset, storing them in *BASE - and *OFFSET respectively. */ -static void -score7_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset) -{ - *offset = 0; - - if (GET_CODE (x) == CONST) - x = XEXP (x, 0); - - if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT) - { - *offset += INTVAL (XEXP (x, 1)); - x = XEXP (x, 0); - } - - *base = x; -} - -/* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */ -static enum score_symbol_type -score7_classify_symbol (rtx x) -{ - if (GET_CODE (x) == LABEL_REF) - return SYMBOL_GENERAL; - - gcc_assert (GET_CODE (x) == SYMBOL_REF); - - if (CONSTANT_POOL_ADDRESS_P (x)) - { - if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE7_SDATA_MAX) - return SYMBOL_SMALL_DATA; - return SYMBOL_GENERAL; - } - if (SYMBOL_REF_SMALL_P (x)) - return SYMBOL_SMALL_DATA; - return SYMBOL_GENERAL; -} - -/* Return true if the current function must save REGNO. */ -static int -score7_save_reg_p (unsigned int regno) -{ - /* Check call-saved registers. */ - if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) - return 1; - - /* We need to save the old frame pointer before setting up a new one. */ - if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) - return 1; - - /* We need to save the incoming return address if it is ever clobbered - within the function. */ - if (regno == RA_REGNUM && df_regs_ever_live_p (regno)) - return 1; - - return 0; -} - -/* Return one word of double-word value OP, taking into account the fixed - endianness of certain registers. HIGH_P is true to select the high part, - false to select the low part. */ -static rtx -score7_subw (rtx op, int high_p) -{ - unsigned int byte; - enum machine_mode mode = GET_MODE (op); - - if (mode == VOIDmode) - mode = DImode; - - byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0; - - if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM) - return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM); - - if (GET_CODE (op) == MEM) - return adjust_address (op, SImode, byte); - - return simplify_gen_subreg (SImode, op, mode, byte); -} - -static struct score7_frame_info * -score7_cached_frame (void) -{ - static struct score7_frame_info _frame_info; - return &_frame_info; -} - -/* Return the bytes needed to compute the frame pointer from the current - stack pointer. SIZE is the size (in bytes) of the local variables. */ -static struct score7_frame_info * -score7_compute_frame_size (HOST_WIDE_INT size) -{ - unsigned int regno; - struct score7_frame_info *f = score7_cached_frame (); - - memset (f, 0, sizeof (struct score7_frame_info)); - f->gp_reg_size = 0; - f->mask = 0; - f->var_size = SCORE7_STACK_ALIGN (size); - f->args_size = crtl->outgoing_args_size; - f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0; - if (f->var_size == 0 && current_function_is_leaf) - f->args_size = f->cprestore_size = 0; - - if (f->args_size == 0 && cfun->calls_alloca) - f->args_size = UNITS_PER_WORD; - - f->total_size = f->var_size + f->args_size + f->cprestore_size; - for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) - { - if (score7_save_reg_p (regno)) - { - f->gp_reg_size += GET_MODE_SIZE (SImode); - f->mask |= 1 << (regno - GP_REG_FIRST); - } - } - - if (crtl->calls_eh_return) - { - unsigned int i; - for (i = 0;; ++i) - { - regno = EH_RETURN_DATA_REGNO (i); - if (regno == INVALID_REGNUM) - break; - f->gp_reg_size += GET_MODE_SIZE (SImode); - f->mask |= 1 << (regno - GP_REG_FIRST); - } - } - - f->total_size += f->gp_reg_size; - f->num_gp = f->gp_reg_size / UNITS_PER_WORD; - - if (f->mask) - { - HOST_WIDE_INT offset; - offset = (f->args_size + f->cprestore_size + f->var_size - + f->gp_reg_size - GET_MODE_SIZE (SImode)); - f->gp_sp_offset = offset; - } - else - f->gp_sp_offset = 0; - - return f; -} - -/* Return true if X is a valid base register for the given mode. - Allow only hard registers if STRICT. */ -static int -score7_valid_base_register_p (rtx x, int strict) -{ - if (!strict && GET_CODE (x) == SUBREG) - x = SUBREG_REG (x); - - return (GET_CODE (x) == REG - && score7_regno_mode_ok_for_base_p (REGNO (x), strict)); -} - -/* Return true if X is a valid address for machine mode MODE. If it is, - fill in INFO appropriately. STRICT is true if we should only accept - hard base registers. */ -static int -score7_classify_address (struct score7_address_info *info, - enum machine_mode mode, rtx x, int strict) -{ - info->code = GET_CODE (x); - - switch (info->code) - { - case REG: - case SUBREG: - info->type = SCORE7_ADD_REG; - info->reg = x; - info->offset = const0_rtx; - return score7_valid_base_register_p (info->reg, strict); - case PLUS: - info->type = SCORE7_ADD_REG; - info->reg = XEXP (x, 0); - info->offset = XEXP (x, 1); - return (score7_valid_base_register_p (info->reg, strict) - && GET_CODE (info->offset) == CONST_INT - && IMM_IN_RANGE (INTVAL (info->offset), 15, 1)); - case PRE_DEC: - case POST_DEC: - case PRE_INC: - case POST_INC: - if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode)) - return false; - info->type = SCORE7_ADD_REG; - info->reg = XEXP (x, 0); - info->offset = GEN_INT (GET_MODE_SIZE (mode)); - return score7_valid_base_register_p (info->reg, strict); - case CONST_INT: - info->type = SCORE7_ADD_CONST_INT; - return IMM_IN_RANGE (INTVAL (x), 15, 1); - case CONST: - case LABEL_REF: - case SYMBOL_REF: - info->type = SCORE7_ADD_SYMBOLIC; - return (score7_symbolic_constant_p (x, &info->symbol_type) - && (info->symbol_type == SYMBOL_GENERAL - || info->symbol_type == SYMBOL_SMALL_DATA)); - default: - return 0; - } -} - -bool -score7_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) -{ - return ((TYPE_MODE (type) == BLKmode) - || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD) - || (int_size_in_bytes (type) == -1)); -} - -/* Return a legitimate address for REG + OFFSET. */ -static rtx -score7_add_offset (rtx reg, HOST_WIDE_INT offset) -{ - if (!IMM_IN_RANGE (offset, 15, 1)) - { - reg = expand_simple_binop (GET_MODE (reg), PLUS, - gen_int_mode (offset & 0xffffc000, - GET_MODE (reg)), - reg, NULL, 0, OPTAB_WIDEN); - offset &= 0x3fff; - } - - return plus_constant (reg, offset); -} - -/* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text - in order to avoid duplicating too much logic from elsewhere. */ -void -score7_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, - HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, - tree function) -{ - rtx this_rtx, temp1, insn, fnaddr; - - /* Pretend to be a post-reload pass while generating rtl. */ - reload_completed = 1; - - /* Mark the end of the (empty) prologue. */ - emit_note (NOTE_INSN_PROLOGUE_END); - - /* We need two temporary registers in some cases. */ - temp1 = gen_rtx_REG (Pmode, 8); - - /* Find out which register contains the "this" pointer. */ - if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) - this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1); - else - this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST); - - /* Add DELTA to THIS_RTX. */ - if (delta != 0) - { - rtx offset = GEN_INT (delta); - if (!(delta >= -32768 && delta <= 32767)) - { - emit_move_insn (temp1, offset); - offset = temp1; - } - emit_insn (gen_add3_insn (this_rtx, this_rtx, offset)); - } - - /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */ - if (vcall_offset != 0) - { - rtx addr; - - /* Set TEMP1 to *THIS_RTX. */ - emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx)); - - /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */ - addr = score7_add_offset (temp1, vcall_offset); - - /* Load the offset and add it to THIS_RTX. */ - emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr)); - emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1)); - } - - /* Jump to the target function. */ - fnaddr = XEXP (DECL_RTL (function), 0); - insn = emit_call_insn (gen_sibcall_internal_score7 (fnaddr, const0_rtx)); - SIBLING_CALL_P (insn) = 1; - - /* Run just enough of rest_of_compilation. This sequence was - "borrowed" from alpha.c. */ - insn = get_insns (); - insn_locators_alloc (); - split_all_insns_noflow (); - shorten_branches (insn); - final_start_function (insn, file, 1); - final (insn, file, 1); - final_end_function (); - - /* Clean up the vars set above. Note that final_end_function resets - the global pointer for us. */ - reload_completed = 0; -} - -/* Copy VALUE to a register and return that register. If new psuedos - are allowed, copy it into a new register, otherwise use DEST. */ -static rtx -score7_force_temporary (rtx dest, rtx value) -{ - if (can_create_pseudo_p ()) - return force_reg (Pmode, value); - else - { - emit_move_insn (copy_rtx (dest), value); - return dest; - } -} - -/* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary - and is used to load the high part into a register. */ -static rtx -score7_split_symbol (rtx temp, rtx addr) -{ - rtx high = score7_force_temporary (temp, - gen_rtx_HIGH (Pmode, copy_rtx (addr))); - return gen_rtx_LO_SUM (Pmode, high, addr); -} - -/* This function is used to implement LEGITIMIZE_ADDRESS. If X can - be legitimized in a way that the generic machinery might not expect, - return the new address. */ -rtx -score7_legitimize_address (rtx x) -{ - enum score_symbol_type symbol_type; - - if (score7_symbolic_constant_p (x, &symbol_type) - && symbol_type == SYMBOL_GENERAL) - return score7_split_symbol (0, x); - - if (GET_CODE (x) == PLUS - && GET_CODE (XEXP (x, 1)) == CONST_INT) - { - rtx reg = XEXP (x, 0); - if (!score7_valid_base_register_p (reg, 0)) - reg = copy_to_mode_reg (Pmode, reg); - return score7_add_offset (reg, INTVAL (XEXP (x, 1))); - } - - return x; -} - -/* Fill INFO with information about a single argument. CUM is the - cumulative state for earlier arguments. MODE is the mode of this - argument and TYPE is its type (if known). NAMED is true if this - is a named (fixed) argument rather than a variable one. */ -static void -score7_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, - const_tree type, bool named, struct score7_arg_info *info) -{ - int even_reg_p; - unsigned int num_words, max_regs; - - even_reg_p = 0; - if (GET_MODE_CLASS (mode) == MODE_INT - || GET_MODE_CLASS (mode) == MODE_FLOAT) - even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD); - else - if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named) - even_reg_p = 1; - - if (TARGET_MUST_PASS_IN_STACK (mode, type)) - info->reg_offset = ARG_REG_NUM; - else - { - info->reg_offset = cum->num_gprs; - if (even_reg_p) - info->reg_offset += info->reg_offset & 1; - } - - if (mode == BLKmode) - info->num_bytes = int_size_in_bytes (type); - else - info->num_bytes = GET_MODE_SIZE (mode); - - num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; - max_regs = ARG_REG_NUM - info->reg_offset; - - /* Partition the argument between registers and stack. */ - info->reg_words = MIN (num_words, max_regs); - info->stack_words = num_words - info->reg_words; - - /* The alignment applied to registers is also applied to stack arguments. */ - if (info->stack_words) - { - info->stack_offset = cum->stack_words; - if (even_reg_p) - info->stack_offset += info->stack_offset & 1; - } -} - -/* Set up the stack and frame (if desired) for the function. */ -void -score7_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) -{ - const char *fnname; - struct score7_frame_info *f = score7_cached_frame (); - HOST_WIDE_INT tsize = f->total_size; - - fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); - if (!flag_inhibit_size_directive) - { - fputs ("\t.ent\t", file); - assemble_name (file, fnname); - fputs ("\n", file); - } - assemble_name (file, fnname); - fputs (":\n", file); - - if (!flag_inhibit_size_directive) - { - fprintf (file, - "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t" - "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d" - ", args= " HOST_WIDE_INT_PRINT_DEC - ", gp= " HOST_WIDE_INT_PRINT_DEC "\n", - (reg_names[(frame_pointer_needed) - ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]), - tsize, - reg_names[RA_REGNUM], - current_function_is_leaf ? 1 : 0, - f->var_size, - f->num_gp, - f->args_size, - f->cprestore_size); - - fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n", - f->mask, - (f->gp_sp_offset - f->total_size)); - } -} - -/* Do any necessary cleanup after a function to restore stack, frame, - and regs. */ -void -score7_function_epilogue (FILE *file, - HOST_WIDE_INT size ATTRIBUTE_UNUSED) -{ - if (!flag_inhibit_size_directive) - { - const char *fnname; - fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); - fputs ("\t.end\t", file); - assemble_name (file, fnname); - fputs ("\n", file); - } -} - -/* Returns true if X contains a SYMBOL_REF. */ -static bool -score7_symbolic_expression_p (rtx x) -{ - if (GET_CODE (x) == SYMBOL_REF) - return true; - - if (GET_CODE (x) == CONST) - return score7_symbolic_expression_p (XEXP (x, 0)); - - if (UNARY_P (x)) - return score7_symbolic_expression_p (XEXP (x, 0)); - - if (ARITHMETIC_P (x)) - return (score7_symbolic_expression_p (XEXP (x, 0)) - || score7_symbolic_expression_p (XEXP (x, 1))); - - return false; -} - -/* Choose the section to use for the constant rtx expression X that has - mode MODE. */ -section * -score7_select_rtx_section (enum machine_mode mode, rtx x, - unsigned HOST_WIDE_INT align) -{ - if (GET_MODE_SIZE (mode) <= SCORE7_SDATA_MAX) - return get_named_section (0, ".sdata", 0); - else if (flag_pic && score7_symbolic_expression_p (x)) - return get_named_section (0, ".data.rel.ro", 3); - else - return mergeable_constant_section (mode, align, 0); -} - -/* Implement TARGET_IN_SMALL_DATA_P. */ -bool -score7_in_small_data_p (const_tree decl) -{ - HOST_WIDE_INT size; - - if (TREE_CODE (decl) == STRING_CST - || TREE_CODE (decl) == FUNCTION_DECL) - return false; - - if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0) - { - const char *name; - name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); - if (strcmp (name, ".sdata") != 0 - && strcmp (name, ".sbss") != 0) - return true; - if (!DECL_EXTERNAL (decl)) - return false; - } - size = int_size_in_bytes (TREE_TYPE (decl)); - return (size > 0 && size <= SCORE7_SDATA_MAX); -} - -/* Implement TARGET_ASM_FILE_START. */ -void -score7_asm_file_start (void) -{ - default_file_start (); - fprintf (asm_out_file, ASM_COMMENT_START - "GCC for S+core %s \n", SCORE_GCC_VERSION); - - if (flag_pic) - fprintf (asm_out_file, "\t.set pic\n"); -} - -/* Implement TARGET_ASM_FILE_END. When using assembler macros, emit - .externs for any small-data variables that turned out to be external. */ -void -score7_asm_file_end (void) -{ - tree name_tree; - struct extern_list *p; - if (extern_head) - { - fputs ("\n", asm_out_file); - for (p = extern_head; p != 0; p = p->next) - { - name_tree = get_identifier (p->name); - if (!TREE_ASM_WRITTEN (name_tree) - && TREE_SYMBOL_REFERENCED (name_tree)) - { - TREE_ASM_WRITTEN (name_tree) = 1; - fputs ("\t.extern\t", asm_out_file); - assemble_name (asm_out_file, p->name); - fprintf (asm_out_file, ", %d\n", p->size); - } - } - } -} - -/* Implement TARGET_OPTION_OVERRIDE hook. */ -void -score7_option_override (void) -{ - flag_pic = false; - score7_sdata_max = SCORE7_DEFAULT_SDATA_MAX; - -} - -/* Implement REGNO_REG_CLASS macro. */ -int -score7_reg_class (int regno) -{ - int c; - gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER); - - if (regno == FRAME_POINTER_REGNUM - || regno == ARG_POINTER_REGNUM) - return ALL_REGS; - - for (c = 0; c < N_REG_CLASSES; c++) - if (TEST_HARD_REG_BIT (reg_class_contents[c], regno)) - return c; - - return NO_REGS; -} - -/* Implement PREFERRED_RELOAD_CLASS macro. */ -enum reg_class -score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass) -{ - if (reg_class_subset_p (G16_REGS, rclass)) - return G16_REGS; - if (reg_class_subset_p (G32_REGS, rclass)) - return G32_REGS; - return rclass; -} - -/* Implement SECONDARY_INPUT_RELOAD_CLASS - and SECONDARY_OUTPUT_RELOAD_CLASS macro. */ -enum reg_class -score7_secondary_reload_class (enum reg_class rclass, - enum machine_mode mode ATTRIBUTE_UNUSED, - rtx x) -{ - int regno = -1; - if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG) - regno = true_regnum (x); - - if (!GR_REG_CLASS_P (rclass)) - return GP_REG_P (regno) ? NO_REGS : G32_REGS; - return NO_REGS; -} - - -/* Return truth value on whether or not a given hard register - can support a given mode. */ -int -score7_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) -{ - int size = GET_MODE_SIZE (mode); - enum mode_class mclass = GET_MODE_CLASS (mode); - - if (mclass == MODE_CC) - return regno == CC_REGNUM; - else if (regno == FRAME_POINTER_REGNUM - || regno == ARG_POINTER_REGNUM) - return mclass == MODE_INT; - else if (GP_REG_P (regno)) - /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */ - return !(regno & 1) || (size <= UNITS_PER_WORD); - else if (CE_REG_P (regno)) - return (mclass == MODE_INT - && ((size <= UNITS_PER_WORD) - || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD))); - else - return (mclass == MODE_INT) && (size <= UNITS_PER_WORD); -} - -/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame - pointer or argument pointer. TO is either the stack pointer or - hard frame pointer. */ -HOST_WIDE_INT -score7_initial_elimination_offset (int from, - int to ATTRIBUTE_UNUSED) -{ - struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ()); - switch (from) - { - case ARG_POINTER_REGNUM: - return f->total_size; - case FRAME_POINTER_REGNUM: - return 0; - default: - gcc_unreachable (); - } -} - -/* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */ -void -score7_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, - const_tree type, bool named) -{ - struct score7_arg_info info; - score7_classify_arg (cum, mode, type, named, &info); - cum->num_gprs = info.reg_offset + info.reg_words; - if (info.stack_words > 0) - cum->stack_words = info.stack_offset + info.stack_words; - cum->arg_number++; -} - -/* Implement TARGET_ARG_PARTIAL_BYTES macro. */ -int -score7_arg_partial_bytes (CUMULATIVE_ARGS *cum, - enum machine_mode mode, tree type, bool named) -{ - struct score7_arg_info info; - score7_classify_arg (cum, mode, type, named, &info); - return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0; -} - -/* Implement TARGET_FUNCTION_ARG hook. */ -rtx -score7_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, - const_tree type, bool named) -{ - struct score7_arg_info info; - - if (mode == VOIDmode || !named) - return 0; - - score7_classify_arg (cum, mode, type, named, &info); - - if (info.reg_offset == ARG_REG_NUM) - return 0; - - if (!info.stack_words) - return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset); - else - { - rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words)); - unsigned int i, part_offset = 0; - for (i = 0; i < info.reg_words; i++) - { - rtx reg; - reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i); - XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg, - GEN_INT (part_offset)); - part_offset += UNITS_PER_WORD; - } - return ret; - } -} - -/* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls, - VALTYPE is the return type and MODE is VOIDmode. For libcalls, - VALTYPE is null and MODE is the mode of the return value. */ -rtx -score7_function_value (const_tree valtype, const_tree func, - enum machine_mode mode) -{ - if (valtype) - { - int unsignedp; - mode = TYPE_MODE (valtype); - unsignedp = TYPE_UNSIGNED (valtype); - mode = promote_function_mode (valtype, mode, &unsignedp, func, 1); - } - return gen_rtx_REG (mode, RT_REGNUM); -} - -/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */ - -void -score7_asm_trampoline_template (FILE *f) -{ - fprintf (f, "\t.set r1\n"); - fprintf (f, "\tmv r31, r3\n"); - fprintf (f, "\tbl nextinsn\n"); - fprintf (f, "nextinsn:\n"); - fprintf (f, "\tlw r1, [r3, 6*4-8]\n"); - fprintf (f, "\tlw r23, [r3, 6*4-4]\n"); - fprintf (f, "\tmv r3, r31\n"); - fprintf (f, "\tbr! r1\n"); - fprintf (f, "\tnop!\n"); - fprintf (f, "\t.set nor1\n"); -} - -/* Implement TARGET_TRAMPOLINE_INIT. */ -void -score7_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) -{ -#define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD) - - rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); - rtx addr = XEXP (m_tramp, 0); - rtx mem; - - emit_block_move (m_tramp, assemble_trampoline_template (), - GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); - - mem = adjust_address (m_tramp, SImode, CODE_SIZE); - emit_move_insn (mem, fnaddr); - mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode)); - emit_move_insn (mem, chain_value); - -#undef CODE_SIZE -} - -/* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */ -int -score7_regno_mode_ok_for_base_p (int regno, int strict) -{ - if (regno >= FIRST_PSEUDO_REGISTER) - { - if (!strict) - return 1; - regno = reg_renumber[regno]; - } - if (regno == ARG_POINTER_REGNUM - || regno == FRAME_POINTER_REGNUM) - return 1; - return GP_REG_P (regno); -} - -/* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */ -bool -score7_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) -{ - struct score7_address_info addr; - - return score7_classify_address (&addr, mode, x, strict); -} - -/* Return a number assessing the cost of moving a register in class - FROM to class TO. */ -int -score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, - enum reg_class from, enum reg_class to) -{ - if (GR_REG_CLASS_P (from)) - { - if (GR_REG_CLASS_P (to)) - return 2; - else if (SP_REG_CLASS_P (to)) - return 4; - else if (CP_REG_CLASS_P (to)) - return 5; - else if (CE_REG_CLASS_P (to)) - return 6; - } - if (GR_REG_CLASS_P (to)) - { - if (GR_REG_CLASS_P (from)) - return 2; - else if (SP_REG_CLASS_P (from)) - return 4; - else if (CP_REG_CLASS_P (from)) - return 5; - else if (CE_REG_CLASS_P (from)) - return 6; - } - return 12; -} - -/* Return the number of instructions needed to load a symbol of the - given type into a register. */ -static int -score7_symbol_insns (enum score_symbol_type type) -{ - switch (type) - { - case SYMBOL_GENERAL: - return 2; - - case SYMBOL_SMALL_DATA: - return 1; - } - - gcc_unreachable (); -} - -/* Return the number of instructions needed to load or store a value - of mode MODE at X. Return 0 if X isn't valid for MODE. */ -static int -score7_address_insns (rtx x, enum machine_mode mode) -{ - struct score7_address_info addr; - int factor; - - if (mode == BLKmode) - factor = 1; - else - factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; - - if (score7_classify_address (&addr, mode, x, false)) - switch (addr.type) - { - case SCORE7_ADD_REG: - case SCORE7_ADD_CONST_INT: - return factor; - - case SCORE7_ADD_SYMBOLIC: - return factor * score7_symbol_insns (addr.symbol_type); - } - return 0; -} - -/* Implement TARGET_RTX_COSTS macro. */ -bool -score7_rtx_costs (rtx x, int code, int outer_code, int *total, - bool speed ATTRIBUTE_UNUSED) -{ - enum machine_mode mode = GET_MODE (x); - - switch (code) - { - case CONST_INT: - if (outer_code == SET) - { - if (((INTVAL (x) & 0xffff) == 0) - || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767)) - *total = COSTS_N_INSNS (1); - else - *total = COSTS_N_INSNS (2); - } - else if (outer_code == PLUS || outer_code == MINUS) - { - if (INTVAL (x) >= -8192 && INTVAL (x) <= 8191) - *total = 0; - else if (((INTVAL (x) & 0xffff) == 0) - || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767)) - *total = 1; - else - *total = COSTS_N_INSNS (2); - } - else if (outer_code == AND || outer_code == IOR) - { - if (INTVAL (x) >= 0 && INTVAL (x) <= 16383) - *total = 0; - else if (((INTVAL (x) & 0xffff) == 0) - || (INTVAL (x) >= 0 && INTVAL (x) <= 65535)) - *total = 1; - else - *total = COSTS_N_INSNS (2); - } - else - { - *total = 0; - } - return true; - - case CONST: - case SYMBOL_REF: - case LABEL_REF: - case CONST_DOUBLE: - *total = COSTS_N_INSNS (2); - return true; - - case MEM: - { - /* If the address is legitimate, return the number of - instructions it needs, otherwise use the default handling. */ - int n = score7_address_insns (XEXP (x, 0), GET_MODE (x)); - if (n > 0) - { - *total = COSTS_N_INSNS (n + 1); - return true; - } - return false; - } - - case FFS: - *total = COSTS_N_INSNS (6); - return true; - - case NOT: - *total = COSTS_N_INSNS (1); - return true; - - case AND: - case IOR: - case XOR: - if (mode == DImode) - { - *total = COSTS_N_INSNS (2); - return true; - } - return false; - - case ASHIFT: - case ASHIFTRT: - case LSHIFTRT: - if (mode == DImode) - { - *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT) - ? 4 : 12); - return true; - } - return false; - - case ABS: - *total = COSTS_N_INSNS (4); - return true; - - case PLUS: - case MINUS: - if (mode == DImode) - { - *total = COSTS_N_INSNS (4); - return true; - } - *total = COSTS_N_INSNS (1); - return true; - - case NEG: - if (mode == DImode) - { - *total = COSTS_N_INSNS (4); - return true; - } - return false; - - case MULT: - *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12); - return true; - - case DIV: - case MOD: - case UDIV: - case UMOD: - *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33); - return true; - - case SIGN_EXTEND: - case ZERO_EXTEND: - switch (GET_MODE (XEXP (x, 0))) - { - case QImode: - case HImode: - if (GET_CODE (XEXP (x, 0)) == MEM) - { - *total = COSTS_N_INSNS (2); - - if (!TARGET_LITTLE_ENDIAN && - side_effects_p (XEXP (XEXP (x, 0), 0))) - *total = 100; - } - else - *total = COSTS_N_INSNS (1); - break; - - default: - *total = COSTS_N_INSNS (1); - break; - } - return true; - - default: - return false; - } -} - -/* Implement TARGET_ADDRESS_COST macro. */ -int -score7_address_cost (rtx addr) -{ - return score7_address_insns (addr, SImode); -} - -/* Implement ASM_OUTPUT_EXTERNAL macro. */ -int -score7_output_external (FILE *file ATTRIBUTE_UNUSED, - tree decl, const char *name) -{ - register struct extern_list *p; - - if (score7_in_small_data_p (decl)) - { - p = ggc_alloc_extern_list (); - p->next = extern_head; - p->name = name; - p->size = int_size_in_bytes (TREE_TYPE (decl)); - extern_head = p; - } - return 0; -} - -/* Implement RETURN_ADDR_RTX. Note, we do not support moving - back to a previous frame. */ -rtx -score7_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) -{ - if (count != 0) - return const0_rtx; - return get_hard_reg_initial_val (Pmode, RA_REGNUM); -} - -/* Implement PRINT_OPERAND macro. */ -/* Score-specific operand codes: - '[' print .set nor1 directive - ']' print .set r1 directive - 'U' print hi part of a CONST_INT rtx - 'E' print log2(v) - 'F' print log2(~v) - 'D' print SFmode const double - 'S' selectively print "!" if operand is 15bit instruction accessible - 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!" - 'L' low part of DImode reg operand - 'H' high part of DImode reg operand - 'C' print part of opcode for a branch condition. */ -void -score7_print_operand (FILE *file, rtx op, int c) -{ - enum rtx_code code = UNKNOWN; - if (!PRINT_OPERAND_PUNCT_VALID_P (c)) - code = GET_CODE (op); - - if (c == '[') - { - fprintf (file, ".set r1\n"); - } - else if (c == ']') - { - fprintf (file, "\n\t.set nor1"); - } - else if (c == 'U') - { - gcc_assert (code == CONST_INT); - fprintf (file, HOST_WIDE_INT_PRINT_HEX, - (INTVAL (op) >> 16) & 0xffff); - } - else if (c == 'D') - { - if (GET_CODE (op) == CONST_DOUBLE) - { - rtx temp = gen_lowpart (SImode, op); - gcc_assert (GET_MODE (op) == SFmode); - fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff); - } - else - output_addr_const (file, op); - } - else if (c == 'S') - { - gcc_assert (code == REG); - if (G16_REG_P (REGNO (op))) - fprintf (file, "!"); - } - else if (c == 'V') - { - gcc_assert (code == REG); - fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!"); - } - else if (c == 'C') - { - enum machine_mode mode = GET_MODE (XEXP (op, 0)); - - switch (code) - { - case EQ: fputs ("eq", file); break; - case NE: fputs ("ne", file); break; - case GT: fputs ("gt", file); break; - case GE: fputs (mode != CCmode ? "pl" : "ge", file); break; - case LT: fputs (mode != CCmode ? "mi" : "lt", file); break; - case LE: fputs ("le", file); break; - case GTU: fputs ("gtu", file); break; - case GEU: fputs ("cs", file); break; - case LTU: fputs ("cc", file); break; - case LEU: fputs ("leu", file); break; - default: - output_operand_lossage ("invalid operand for code: '%c'", code); - } - } - else if (c == 'E') - { - unsigned HOST_WIDE_INT i; - unsigned HOST_WIDE_INT pow2mask = 1; - unsigned HOST_WIDE_INT val; - - val = INTVAL (op); - for (i = 0; i < 32; i++) - { - if (val == pow2mask) - break; - pow2mask <<= 1; - } - gcc_assert (i < 32); - fprintf (file, HOST_WIDE_INT_PRINT_HEX, i); - } - else if (c == 'F') - { - unsigned HOST_WIDE_INT i; - unsigned HOST_WIDE_INT pow2mask = 1; - unsigned HOST_WIDE_INT val; - - val = ~INTVAL (op); - for (i = 0; i < 32; i++) - { - if (val == pow2mask) - break; - pow2mask <<= 1; - } - gcc_assert (i < 32); - fprintf (file, HOST_WIDE_INT_PRINT_HEX, i); - } - else if (code == REG) - { - int regnum = REGNO (op); - if ((c == 'H' && !WORDS_BIG_ENDIAN) - || (c == 'L' && WORDS_BIG_ENDIAN)) - regnum ++; - fprintf (file, "%s", reg_names[regnum]); - } - else - { - switch (code) - { - case MEM: - score7_print_operand_address (file, op); - break; - default: - output_addr_const (file, op); - } - } -} - -/* Implement PRINT_OPERAND_ADDRESS macro. */ -void -score7_print_operand_address (FILE *file, rtx x) -{ - struct score7_address_info addr; - enum rtx_code code = GET_CODE (x); - enum machine_mode mode = GET_MODE (x); - - if (code == MEM) - x = XEXP (x, 0); - - if (score7_classify_address (&addr, mode, x, true)) - { - switch (addr.type) - { - case SCORE7_ADD_REG: - { - switch (addr.code) - { - case PRE_DEC: - fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)], - INTVAL (addr.offset)); - break; - case POST_DEC: - fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)], - INTVAL (addr.offset)); - break; - case PRE_INC: - fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)], - INTVAL (addr.offset)); - break; - case POST_INC: - fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)], - INTVAL (addr.offset)); - break; - default: - if (INTVAL(addr.offset) == 0) - fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]); - else - fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)], - INTVAL(addr.offset)); - break; - } - } - return; - case SCORE7_ADD_CONST_INT: - case SCORE7_ADD_SYMBOLIC: - output_addr_const (file, x); - return; - } - } - print_rtl (stderr, x); - gcc_unreachable (); -} - -/* Implement SELECT_CC_MODE macro. */ -enum machine_mode -score7_select_cc_mode (enum rtx_code op, rtx x, rtx y) -{ - if ((op == EQ || op == NE || op == LT || op == GE) - && y == const0_rtx - && GET_MODE (x) == SImode) - { - switch (GET_CODE (x)) - { - case PLUS: - case MINUS: - case NEG: - case AND: - case IOR: - case XOR: - case NOT: - case ASHIFT: - case LSHIFTRT: - case ASHIFTRT: - return CC_NZmode; - - case SIGN_EXTEND: - case ZERO_EXTEND: - case ROTATE: - case ROTATERT: - return (op == LT || op == GE) ? CC_Nmode : CCmode; - - default: - return CCmode; - } - } - - if ((op == EQ || op == NE) - && (GET_CODE (y) == NEG) - && register_operand (XEXP (y, 0), SImode) - && register_operand (x, SImode)) - { - return CC_NZmode; - } - - return CCmode; -} - -/* Generate the prologue instructions for entry into a S+core function. */ -void -score7_prologue (void) -{ -#define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1 - - struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ()); - HOST_WIDE_INT size; - int regno; - - size = f->total_size - f->gp_reg_size; - - if (flag_pic) - emit_insn (gen_cpload_score7 ()); - - for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--) - { - if (BITSET_P (f->mask, regno - GP_REG_FIRST)) - { - rtx mem = gen_rtx_MEM (SImode, - gen_rtx_PRE_DEC (SImode, stack_pointer_rtx)); - rtx reg = gen_rtx_REG (SImode, regno); - if (!crtl->calls_eh_return) - MEM_READONLY_P (mem) = 1; - EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg))); - } - } - - if (size > 0) - { - rtx insn; - - if (size >= -32768 && size <= 32767) - EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (-size)))); - else - { - EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE7_PROLOGUE_TEMP_REGNUM), - GEN_INT (size))); - EMIT_PL (emit_insn - (gen_sub3_insn (stack_pointer_rtx, - stack_pointer_rtx, - gen_rtx_REG (Pmode, - SCORE7_PROLOGUE_TEMP_REGNUM)))); - } - insn = get_last_insn (); - REG_NOTES (insn) = - alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, stack_pointer_rtx, - plus_constant (stack_pointer_rtx, - -size)), - REG_NOTES (insn)); - } - - if (frame_pointer_needed) - EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); - - if (flag_pic && f->cprestore_size) - { - if (frame_pointer_needed) - emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size))); - else - emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size))); - } - -#undef EMIT_PL -} - -/* Generate the epilogue instructions in a S+core function. */ -void -score7_epilogue (int sibcall_p) -{ - struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ()); - HOST_WIDE_INT size; - int regno; - rtx base; - - size = f->total_size - f->gp_reg_size; - - if (!frame_pointer_needed) - base = stack_pointer_rtx; - else - base = hard_frame_pointer_rtx; - - if (size) - { - if (size >= -32768 && size <= 32767) - emit_insn (gen_add3_insn (base, base, GEN_INT (size))); - else - { - emit_move_insn (gen_rtx_REG (Pmode, SCORE7_EPILOGUE_TEMP_REGNUM), - GEN_INT (size)); - emit_insn (gen_add3_insn (base, base, - gen_rtx_REG (Pmode, - SCORE7_EPILOGUE_TEMP_REGNUM))); - } - } - - if (base != stack_pointer_rtx) - emit_move_insn (stack_pointer_rtx, base); - - if (crtl->calls_eh_return) - emit_insn (gen_add3_insn (stack_pointer_rtx, - stack_pointer_rtx, - EH_RETURN_STACKADJ_RTX)); - - for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++) - { - if (BITSET_P (f->mask, regno - GP_REG_FIRST)) - { - rtx mem = gen_rtx_MEM (SImode, - gen_rtx_POST_INC (SImode, stack_pointer_rtx)); - rtx reg = gen_rtx_REG (SImode, regno); - - if (!crtl->calls_eh_return) - MEM_READONLY_P (mem) = 1; - - emit_insn (gen_popsi_score7 (reg, mem)); - } - } - - if (!sibcall_p) - emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM))); -} - -/* Return true if X is a symbolic constant that can be calculated in - the same way as a bare symbol. If it is, store the type of the - symbol in *SYMBOL_TYPE. */ -int -score7_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type) -{ - HOST_WIDE_INT offset; - - score7_split_const (x, &x, &offset); - if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) - *symbol_type = score7_classify_symbol (x); - else - return 0; - - if (offset == 0) - return 1; - - /* if offset > 15bit, must reload */ - if (!IMM_IN_RANGE (offset, 15, 1)) - return 0; - - switch (*symbol_type) - { - case SYMBOL_GENERAL: - return 1; - case SYMBOL_SMALL_DATA: - return score7_offset_within_object_p (x, offset); - } - gcc_unreachable (); -} - -void -score7_movsicc (rtx *ops) -{ - enum machine_mode mode; - - mode = score7_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]); - emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM), - gen_rtx_COMPARE (mode, XEXP (ops[1], 0), - XEXP (ops[1], 1)))); -} - -/* Call and sibcall pattern all need call this function. */ -void -score7_call (rtx *ops, bool sib) -{ - rtx addr = XEXP (ops[0], 0); - if (!call_insn_operand (addr, VOIDmode)) - { - rtx oaddr = addr; - addr = gen_reg_rtx (Pmode); - gen_move_insn (addr, oaddr); - } - - if (sib) - emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1])); - else - emit_call_insn (gen_call_internal_score7 (addr, ops[1])); -} - -/* Call value and sibcall value pattern all need call this function. */ -void -score7_call_value (rtx *ops, bool sib) -{ - rtx result = ops[0]; - rtx addr = XEXP (ops[1], 0); - rtx arg = ops[2]; - - if (!call_insn_operand (addr, VOIDmode)) - { - rtx oaddr = addr; - addr = gen_reg_rtx (Pmode); - gen_move_insn (addr, oaddr); - } - - if (sib) - emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg)); - else - emit_call_insn (gen_call_value_internal_score7 (result, addr, arg)); -} - -/* Machine Split */ -void -score7_movdi (rtx *ops) -{ - rtx dst = ops[0]; - rtx src = ops[1]; - rtx dst0 = score7_subw (dst, 0); - rtx dst1 = score7_subw (dst, 1); - rtx src0 = score7_subw (src, 0); - rtx src1 = score7_subw (src, 1); - - if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src)) - { - emit_move_insn (dst1, src1); - emit_move_insn (dst0, src0); - } - else - { - emit_move_insn (dst0, src0); - emit_move_insn (dst1, src1); - } -} - -void -score7_zero_extract_andi (rtx *ops) -{ - if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode)) - emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2])); - else - { - unsigned HOST_WIDE_INT mask; - mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U)); - mask = mask << INTVAL (ops[2]); - emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0], - gen_int_mode (mask, SImode))); - } -} - -/* Check addr could be present as PRE/POST mode. */ -static bool -score7_pindex_mem (rtx addr) -{ - if (GET_CODE (addr) == MEM) - { - switch (GET_CODE (XEXP (addr, 0))) - { - case PRE_DEC: - case POST_DEC: - case PRE_INC: - case POST_INC: - return true; - default: - break; - } - } - return false; -} - -/* Output asm code for ld/sw insn. */ -static int -score7_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit) -{ - struct score7_address_info ai; - - gcc_assert (GET_CODE (ops[idata]) == REG); - gcc_assert (score7_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true)); - - if (!score7_pindex_mem (ops[iaddr]) - && ai.type == SCORE7_ADD_REG - && GET_CODE (ai.offset) == CONST_INT - && G16_REG_P (REGNO (ops[idata])) - && G16_REG_P (REGNO (ai.reg))) - { - if (INTVAL (ai.offset) == 0) - { - ops[iaddr] = ai.reg; - return snprintf (ip, INS_BUF_SZ, - "!\t%%%d, [%%%d]", idata, iaddr); - } - if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM) - { - HOST_WIDE_INT offset = INTVAL (ai.offset); - if (SCORE_ALIGN_UNIT (offset, unit) - && (((offset >> unit) >= 0) && ((offset >> unit) <= 31))) - { - ops[iaddr] = ai.offset; - return snprintf (ip, INS_BUF_SZ, - "p!\t%%%d, %%c%d", idata, iaddr); - } - } - } - return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr); -} - -/* Output asm insn for load. */ -const char * -score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign) -{ - const char *pre_ins[] = - {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"}; - char *ip; - - strcpy (score7_ins, pre_ins[(sign ? 4 : 0) + unit]); - ip = score7_ins + strlen (score7_ins); - - if ((!sign && unit != SCORE_HWORD) - || (sign && unit != SCORE_BYTE)) - score7_pr_addr_post (ops, 0, 1, ip, unit); - else - snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1"); - - return score7_ins; -} - -/* Output asm insn for store. */ -const char * -score7_sinsn (rtx *ops, enum score_mem_unit unit) -{ - const char *pre_ins[] = {"sb", "sh", "sw"}; - char *ip; - - strcpy (score7_ins, pre_ins[unit]); - ip = score7_ins + strlen (score7_ins); - score7_pr_addr_post (ops, 1, 0, ip, unit); - return score7_ins; -} - -/* Output asm insn for load immediate. */ -const char * -score7_limm (rtx *ops) -{ - HOST_WIDE_INT v; - - gcc_assert (GET_CODE (ops[0]) == REG); - gcc_assert (GET_CODE (ops[1]) == CONST_INT); - - v = INTVAL (ops[1]); - if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0)) - return "ldiu!\t%0, %c1"; - else if (IMM_IN_RANGE (v, 16, 1)) - return "ldi\t%0, %c1"; - else if ((v & 0xffff) == 0) - return "ldis\t%0, %U1"; - else - return "li\t%0, %c1"; -} - -/* Output asm insn for move. */ -const char * -score7_move (rtx *ops) -{ - gcc_assert (GET_CODE (ops[0]) == REG); - gcc_assert (GET_CODE (ops[1]) == REG); - - if (G16_REG_P (REGNO (ops[0]))) - { - if (G16_REG_P (REGNO (ops[1]))) - return "mv!\t%0, %1"; - else - return "mlfh!\t%0, %1"; - } - else if (G16_REG_P (REGNO (ops[1]))) - return "mhfl!\t%0, %1"; - else - return "mv\t%0, %1"; -} - -/* Generate add insn. */ -const char * -score7_select_add_imm (rtx *ops, bool set_cc) -{ - HOST_WIDE_INT v = INTVAL (ops[2]); - - gcc_assert (GET_CODE (ops[2]) == CONST_INT); - gcc_assert (REGNO (ops[0]) == REGNO (ops[1])); - - if (set_cc && G16_REG_P (REGNO (ops[0]))) - { - if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15)) - { - ops[2] = GEN_INT (ffs (v) - 1); - return "addei!\t%0, %c2"; - } - - if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15)) - { - ops[2] = GEN_INT (ffs (-v) - 1); - return "subei!\t%0, %c2"; - } - } - - if (set_cc) - return "addi.c\t%0, %c2"; - else - return "addi\t%0, %c2"; -} - -/* Output arith insn. */ -const char * -score7_select (rtx *ops, const char *inst_pre, - bool commu, const char *letter, bool set_cc) -{ - gcc_assert (GET_CODE (ops[0]) == REG); - gcc_assert (GET_CODE (ops[1]) == REG); - - if (set_cc && G16_REG_P (REGNO (ops[0])) - && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1) - && REGNO (ops[0]) == REGNO (ops[1])) - { - snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter); - return score7_ins; - } - - if (commu && set_cc && G16_REG_P (REGNO (ops[0])) - && G16_REG_P (REGNO (ops[1])) - && REGNO (ops[0]) == REGNO (ops[2])) - { - gcc_assert (GET_CODE (ops[2]) == REG); - snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter); - return score7_ins; - } - - if (set_cc) - snprintf (score7_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter); - else - snprintf (score7_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter); - return score7_ins; -} - diff --git a/gcc/config/score/score7.h b/gcc/config/score/score7.h deleted file mode 100644 index 71654aae133..00000000000 --- a/gcc/config/score/score7.h +++ /dev/null @@ -1,158 +0,0 @@ -/* score7.h for Sunplus S+CORE processor - Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. - Contributed by Sunnorth - - 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/>. */ - -#ifndef GCC_SCORE7_H -#define GCC_SCORE7_H - -enum score7_address_type -{ - SCORE7_ADD_REG, - SCORE7_ADD_CONST_INT, - SCORE7_ADD_SYMBOLIC -}; - -struct score7_frame_info -{ - HOST_WIDE_INT total_size; /* bytes that the entire frame takes up */ - HOST_WIDE_INT var_size; /* bytes that variables take up */ - HOST_WIDE_INT args_size; /* bytes that outgoing arguments take up */ - HOST_WIDE_INT gp_reg_size; /* bytes needed to store gp regs */ - HOST_WIDE_INT gp_sp_offset; /* offset from new sp to store gp registers */ - HOST_WIDE_INT cprestore_size; /* # bytes that the .cprestore slot takes up */ - unsigned int mask; /* mask of saved gp registers */ - int num_gp; /* number of gp registers saved */ -}; - -struct score7_arg_info -{ - unsigned int num_bytes; /* The argument's size in bytes */ - unsigned int reg_words; /* The number of words passed in registers */ - unsigned int reg_offset; /* The offset of the first register from */ - /* GP_ARG_FIRST or FP_ARG_FIRST etc */ - unsigned int stack_words; /* The number of words that must be passed */ - /* on the stack */ - unsigned int stack_offset; /* The offset from the start of the stack */ - /* overflow area */ -}; - -#ifdef RTX_CODE -struct score7_address_info -{ - enum score7_address_type type; - rtx reg; - rtx offset; - enum rtx_code code; - enum score_symbol_type symbol_type; -}; -#endif - -#define SCORE7_SDATA_MAX score7_sdata_max -#define SCORE7_STACK_ALIGN(LOC) (((LOC) + 3) & ~3) -#define SCORE7_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8) -#define SCORE7_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8) -#define SCORE7_DEFAULT_SDATA_MAX 8 - -extern int score7_symbolic_constant_p (rtx x, - enum score_symbol_type *symbol_type); -extern bool score7_return_in_memory (const_tree type, - const_tree fndecl ATTRIBUTE_UNUSED); -extern void score7_output_mi_thunk (FILE *file, - tree thunk_fndecl ATTRIBUTE_UNUSED, - HOST_WIDE_INT delta, - HOST_WIDE_INT vcall_offset, - tree function); -extern rtx score7_legitimize_address (rtx x); -extern void -score7_function_prologue (FILE *file, - HOST_WIDE_INT size ATTRIBUTE_UNUSED); -extern void -score7_function_epilogue (FILE *file, - HOST_WIDE_INT size ATTRIBUTE_UNUSED); -extern section *score7_select_rtx_section (enum machine_mode mode, rtx x, - unsigned HOST_WIDE_INT align); -extern bool score7_in_small_data_p (const_tree decl); -extern void score7_asm_file_start (void); -extern void score7_asm_file_end (void); -extern void score7_option_override (void); -extern int score7_reg_class (int regno); -extern enum reg_class score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, - enum reg_class rclass); -extern enum -reg_class score7_secondary_reload_class (enum reg_class rclass, - enum machine_mode mode ATTRIBUTE_UNUSED, - rtx x); -extern int score7_const_ok_for_letter_p (HOST_WIDE_INT value, char c); -extern int score7_extra_constraint (rtx op, char c); -extern int score7_hard_regno_mode_ok (unsigned int regno, - enum machine_mode mode); -extern HOST_WIDE_INT -score7_initial_elimination_offset (int from, - int to ATTRIBUTE_UNUSED); -extern void score7_function_arg_advance (CUMULATIVE_ARGS *cum, - enum machine_mode mode, - const_tree type, - bool named); -extern int score7_arg_partial_bytes (CUMULATIVE_ARGS *cum, - enum machine_mode mode, - tree type, - bool named); -extern rtx score7_function_arg (const CUMULATIVE_ARGS *cum, - enum machine_mode mode, - const_tree type, - bool named); -extern rtx score7_function_value (const_tree valtype, - const_tree func ATTRIBUTE_UNUSED, - enum machine_mode mode); -extern void score7_asm_trampoline_template (FILE *); -extern void score7_trampoline_init (rtx, tree, rtx); -extern int score7_regno_mode_ok_for_base_p (int regno, int strict); -extern bool score7_legitimate_address_p (enum machine_mode mode, rtx x, - bool strict); -extern int score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, - enum reg_class from, - enum reg_class to); -extern bool score7_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed); -extern int score7_address_cost (rtx addr); -extern int score7_output_external (FILE *file ATTRIBUTE_UNUSED, - tree decl, - const char *name); -extern rtx score7_return_addr (int count, rtx frame ATTRIBUTE_UNUSED); -extern void score7_print_operand (FILE *file, rtx op, int c); -extern void score7_print_operand_address (FILE *file, rtx x); -extern enum machine_mode score7_select_cc_mode (enum rtx_code op, - rtx x, - rtx y); -extern void score7_prologue (void); -extern void score7_epilogue (int sibcall_p); -extern void score7_call (rtx *ops, bool sib); -extern void score7_call_value (rtx *ops, bool sib); -extern void score7_movsicc (rtx *ops); -extern void score7_movdi (rtx *ops); -extern void score7_zero_extract_andi (rtx *ops); -extern const char * score7_select_add_imm (rtx *ops, bool set_cc); -extern const char * score7_select (rtx *ops, const char *inst_pre, bool commu, - const char *letter, bool set_cc); -extern const char * score7_move (rtx *ops); -extern const char * score7_limm (rtx *ops); -extern const char * -score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign); -extern const char * -score7_sinsn (rtx *ops, enum score_mem_unit unit); -#endif diff --git a/gcc/config/score/t-score-elf b/gcc/config/score/t-score-elf index f02c482f51d..fd080c1b1fe 100644 --- a/gcc/config/score/t-score-elf +++ b/gcc/config/score/t-score-elf @@ -16,13 +16,6 @@ # along with GCC; see the file COPYING3. If not see # <http://www.gnu.org/licenses/>. -# Additional Backend Files -score7.o: $(srcdir)/config/score/score7.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(RTL_H) output.h flags.h $(TREE_H) \ - expr.h toplev.h $(TM_P_H) - $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ - $(srcdir)/config/score/score7.c - # Assemble startup files. $(T)crti.o: $(srcdir)/config/score/crti.asm $(GCC_PASSES) $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e95e7c8f082..6ffebf1b0fe 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,55 @@ +2011-07-01 Jonathan Wakely <jwakely.gcc@gmail.com> + + PR c++/49605 + * init.c (build_delete): Only warn for sfk_deleting_destructor. + +2011-07-01 Jakub Jelinek <jakub@redhat.com> + + * Make-lang.in (cp/decl.o): Depend on pointer-set.h. + (cp/class.o): Likewise. + (cp/error.o): Likewise. + (cp/name-lookup.o): Likewise. + (cp/decl2.o): Likewise. Don't depend on $(POINTER_SET_H). + +2011-07-01 Jason Merrill <jason@redhat.com> + + PR c++/48261 + * pt.c (lookup_template_function): Handle non-function. + + PR c++/48593 + * pt.c (tsubst_qualified_id): Check PTRMEM_OK_P. + * tree.c (build_qualified_name): Set PTRMEM_OK_P. + * semantics.c (finish_parenthesized_expr): Clear PTRMEM_OK_P on + SCOPE_REF, too. + * cp-tree.h (PTRMEM_OK_P): Apply to SCOPE_REF, too. + (QUALIFIED_NAME_IS_TEMPLATE): Switch to lang flag 1. + + PR c++/48883 + PR c++/49609 + * pt.c (resolve_nondeduced_context): Call mark_used. + + PR c++/49085 + * semantics.c (finish_offsetof): Complain about incomplete type. + +2011-06-30 Jason Merrill <jason@redhat.com> + + PR c++/49387 + * rtti.c (get_tinfo_decl): Call complete_type. + + PR c++/49569 + * method.c (implicitly_declare_fn): Set DECL_PARM_LEVEL and + DECL_PARM_INDEX on rhs parm. + + * pt.c (iterative_hash_template_arg): Use cp_tree_operand_length. + + PR c++/49355 + * tree.c (stabilize_init): Handle aggregate initialization. + + PR c++/48481 + * name-lookup.c (struct arg_lookup): Add fn_set. + (add_function): Check it. + (lookup_arg_dependent_1): Initialize it. + 2011-06-29 Jason Merrill <jason@redhat.com> PR c++/49216 diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index c47132280bf..1b53b3875dd 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -266,11 +266,11 @@ cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \ output.h toplev.h $(HASHTAB_H) $(RTL_H) \ cp/operators.def $(TM_P_H) $(TREE_INLINE_H) $(DIAGNOSTIC_H) $(C_PRAGMA_H) \ debug.h gt-cp-decl.h $(TIMEVAR_H) $(TARGET_H) $(PLUGIN_H) \ - intl.h tree-iterator.h $(SPLAY_TREE_H) \ + intl.h tree-iterator.h pointer-set.h $(SPLAY_TREE_H) \ c-family/c-objc.h cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \ output.h toplev.h $(C_COMMON_H) gt-cp-decl2.h $(CGRAPH_H) \ - $(C_PRAGMA_H) $(TREE_DUMP_H) intl.h $(TARGET_H) $(GIMPLE_H) $(POINTER_SET_H) \ + $(C_PRAGMA_H) $(TREE_DUMP_H) intl.h $(TARGET_H) $(GIMPLE_H) pointer-set.h \ $(SPLAY_TREE_H) c-family/c-ada-spec.h \ c-family/c-objc.h cp/cp-objcp-common.o : cp/cp-objcp-common.c $(CONFIG_H) $(SYSTEM_H) \ @@ -284,7 +284,7 @@ cp/typeck.o: cp/typeck.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \ output.h c-family/c-objc.h cp/class.o: cp/class.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) toplev.h \ $(TARGET_H) convert.h $(CGRAPH_H) $(TREE_DUMP_H) gt-cp-class.h \ - $(SPLAY_TREE_H) + $(SPLAY_TREE_H) pointer-set.h cp/call.o: cp/call.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) toplev.h \ $(DIAGNOSTIC_CORE_H) intl.h gt-cp-call.h convert.h $(TARGET_H) langhooks.h \ $(TIMEVAR_H) c-family/c-objc.h @@ -312,7 +312,7 @@ cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h cp/cp-objcp-common.h \ c-family/c-objc.h cp/error.o: cp/error.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_H) \ $(FLAGS_H) $(REAL_H) $(LANGHOOKS_DEF_H) $(CXX_PRETTY_PRINT_H) \ - tree-diagnostic.h tree-pretty-print.h c-family/c-objc.h + tree-diagnostic.h tree-pretty-print.h pointer-set.h c-family/c-objc.h cp/repo.o: cp/repo.c $(CXX_TREE_H) $(TM_H) toplev.h $(DIAGNOSTIC_CORE_H) \ gt-cp-repo.h cp/semantics.o: cp/semantics.c $(CXX_TREE_H) $(TM_H) toplev.h \ @@ -333,7 +333,7 @@ cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \ cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h \ - $(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h + $(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h pointer-set.h cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) \ $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H) tree-pretty-print.h diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ef25c97aafb..357295c8401 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -53,7 +53,7 @@ c-common.h, not after. TREE_INDIRECT_USING (in NAMESPACE_DECL). CLEANUP_P (in TRY_BLOCK) AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR) - PTRMEM_OK_P (in ADDR_EXPR, OFFSET_REF) + PTRMEM_OK_P (in ADDR_EXPR, OFFSET_REF, SCOPE_REF) PAREN_STRING_LITERAL (in STRING_CST) DECL_PRETTY_FUNCTION_P (in VAR_DECL) KOENIG_LOOKUP_P (in CALL_EXPR) @@ -62,7 +62,6 @@ c-common.h, not after. STMT_EXPR_NO_SCOPE (in STMT_EXPR) BIND_EXPR_TRY_BLOCK (in BIND_EXPR) TYPENAME_IS_ENUM_P (in TYPENAME_TYPE) - QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF) OMP_FOR_GIMPLIFYING_P (in OMP_FOR) BASELINK_QUALIFIED_P (in BASELINK) TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR) @@ -86,6 +85,7 @@ c-common.h, not after. LAMBDA_EXPR_MUTABLE_P (in LAMBDA_EXPR) DECLTYPE_FOR_LAMBDA_RETURN (in DECLTYPE_TYPE) DECL_FINAL_P (in FUNCTION_DECL) + QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF) 2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE) ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) @@ -3354,7 +3354,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* Indicates when overload resolution may resolve to a pointer to member function. [expr.unary.op]/3 */ #define PTRMEM_OK_P(NODE) \ - TREE_LANG_FLAG_0 (TREE_CHECK2 ((NODE), ADDR_EXPR, OFFSET_REF)) + TREE_LANG_FLAG_0 (TREE_CHECK3 ((NODE), ADDR_EXPR, OFFSET_REF, SCOPE_REF)) /* Get the POINTER_TYPE to the METHOD_TYPE associated with this pointer to member function. TYPE_PTRMEMFUNC_P _must_ be true, @@ -3801,7 +3801,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* True for a SCOPE_REF iff the "template" keyword was used to indicate that the qualified name denotes a template. */ #define QUALIFIED_NAME_IS_TEMPLATE(NODE) \ - (TREE_LANG_FLAG_0 (SCOPE_REF_CHECK (NODE))) + (TREE_LANG_FLAG_1 (SCOPE_REF_CHECK (NODE))) /* True for an OMP_ATOMIC that has dependent parameters. These are stored as an expr in operand 1, and integer_zero_node in operand 0. */ diff --git a/gcc/cp/init.c b/gcc/cp/init.c index f80c475f7ac..7970b9ac476 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3467,8 +3467,9 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, } complete_p = false; } - else if (warn_delnonvdtor && MAYBE_CLASS_TYPE_P (type) - && !CLASSTYPE_FINAL (type) && TYPE_POLYMORPHIC_P (type)) + else if (auto_delete == sfk_deleting_destructor && warn_delnonvdtor + && MAYBE_CLASS_TYPE_P (type) && !CLASSTYPE_FINAL (type) + && TYPE_POLYMORPHIC_P (type)) { tree dtor; dtor = CLASSTYPE_DESTRUCTORS (type); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index f10e846d0ea..9b9eb9a9df9 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1528,8 +1528,11 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) /* Note that this parameter is *not* marked DECL_ARTIFICIAL; we want its type to be included in the mangled function name. */ - DECL_ARGUMENTS (fn) = cp_build_parm_decl (NULL_TREE, rhs_parm_type); - TREE_READONLY (DECL_ARGUMENTS (fn)) = 1; + tree decl = cp_build_parm_decl (NULL_TREE, rhs_parm_type); + TREE_READONLY (decl) = 1; + retrofit_lang_decl (decl); + DECL_PARM_INDEX (decl) = DECL_PARM_LEVEL (decl) = 1; + DECL_ARGUMENTS (fn) = decl; } /* Add the "this" parameter. */ this_parm = build_this_parm (fn_type, TYPE_UNQUALIFIED); diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 8bf5f5fde66..615e177e1f1 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "debug.h" #include "c-family/c-pragma.h" #include "params.h" +#include "pointer-set.h" /* The bindings for a particular name in a particular scope. */ @@ -4864,6 +4865,7 @@ struct arg_lookup VEC(tree,gc) *namespaces; VEC(tree,gc) *classes; tree functions; + struct pointer_set_t *fn_set; }; static bool arg_assoc (struct arg_lookup*, tree); @@ -4883,16 +4885,11 @@ static bool arg_assoc_template_arg (struct arg_lookup*, tree); static bool add_function (struct arg_lookup *k, tree fn) { - /* We used to check here to see if the function was already in the list, - but that's O(n^2), which is just too expensive for function lookup. - Now we deal with the occasional duplicate in joust. In doing this, we - assume that the number of duplicates will be small compared to the - total number of functions being compared, which should usually be the - case. */ - if (!is_overloaded_fn (fn)) /* All names except those of (possibly overloaded) functions and function templates are ignored. */; + else if (k->fn_set && pointer_set_insert (k->fn_set, fn)) + /* It's already in the list. */; else if (!k->functions) k->functions = fn; else if (fn == k->functions) @@ -5346,6 +5343,23 @@ lookup_arg_dependent_1 (tree name, tree fns, VEC(tree,gc) *args, picking up later definitions) in the second stage. */ k.namespaces = make_tree_vector (); + /* We used to allow duplicates and let joust discard them, but + since the above change for DR 164 we end up with duplicates of + all the functions found by unqualified lookup. So keep track + of which ones we've seen. */ + if (fns) + { + tree ovl; + /* We shouldn't be here if lookup found something other than + namespace-scope functions. */ + gcc_assert (DECL_NAMESPACE_SCOPE_P (OVL_CURRENT (fns))); + k.fn_set = pointer_set_create (); + for (ovl = fns; ovl; ovl = OVL_NEXT (ovl)) + pointer_set_insert (k.fn_set, OVL_CURRENT (ovl)); + } + else + k.fn_set = NULL; + if (include_std) arg_assoc_namespace (&k, std_node); arg_assoc_args_vec (&k, args); @@ -5363,6 +5377,8 @@ lookup_arg_dependent_1 (tree name, tree fns, VEC(tree,gc) *args, release_tree_vector (k.classes); release_tree_vector (k.namespaces); + if (k.fn_set) + pointer_set_destroy (k.fn_set); return fns; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index dc6cd5086d5..7236e7e5168 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1609,7 +1609,7 @@ iterative_hash_template_arg (tree arg, hashval_t val) default: gcc_assert (IS_EXPR_CODE_CLASS (tclass)); { - unsigned n = TREE_OPERAND_LENGTH (arg); + unsigned n = cp_tree_operand_length (arg); for (i = 0; i < n; ++i) val = iterative_hash_template_arg (TREE_OPERAND (arg, i), val); return val; @@ -6622,8 +6622,12 @@ lookup_template_function (tree fns, tree arglist) return error_mark_node; gcc_assert (!arglist || TREE_CODE (arglist) == TREE_VEC); - gcc_assert (fns && (is_overloaded_fn (fns) - || TREE_CODE (fns) == IDENTIFIER_NODE)); + + if (!is_overloaded_fn (fns) && TREE_CODE (fns) != IDENTIFIER_NODE) + { + error ("%q#D is not a function template", fns); + return error_mark_node; + } if (BASELINK_P (fns)) { @@ -11344,7 +11348,7 @@ tsubst_qualified_id (tree qualified_id, tree args, expr = (adjust_result_of_qualified_name_lookup (expr, scope, current_class_type)); expr = (finish_qualified_id_expr - (scope, expr, done, address_p, + (scope, expr, done, address_p && PTRMEM_OK_P (qualified_id), QUALIFIED_NAME_IS_TEMPLATE (qualified_id), /*template_arg_p=*/false)); } @@ -14679,6 +14683,7 @@ resolve_nondeduced_context (tree orig_expr) } if (good == 1) { + mark_used (goodfn); expr = goodfn; if (baselink) expr = build_baselink (BASELINK_BINFO (baselink), diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 0feaf07f851..53404b4a62d 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -406,6 +406,8 @@ get_tinfo_decl (tree type) type = build_function_type (TREE_TYPE (type), TREE_CHAIN (TYPE_ARG_TYPES (type))); + type = complete_type (type); + /* For a class type, the variable is cached in the type node itself. */ if (CLASS_TYPE_P (type)) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index ad68a012d17..e29705c5782 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1504,7 +1504,8 @@ finish_parenthesized_expr (tree expr) /* This inhibits warnings in c_common_truthvalue_conversion. */ TREE_NO_WARNING (expr) = 1; - if (TREE_CODE (expr) == OFFSET_REF) + if (TREE_CODE (expr) == OFFSET_REF + || TREE_CODE (expr) == SCOPE_REF) /* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be enclosed in parentheses. */ PTRMEM_OK_P (expr) = 0; @@ -3422,6 +3423,12 @@ finish_offsetof (tree expr) } if (REFERENCE_REF_P (expr)) expr = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) == COMPONENT_REF) + { + tree object = TREE_OPERAND (expr, 0); + if (!complete_type_or_else (TREE_TYPE (object), object)) + return error_mark_node; + } return fold_offsetof (expr, NULL_TREE); } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c50751f7ebb..dcd85e40c98 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1411,6 +1411,7 @@ build_qualified_name (tree type, tree scope, tree name, bool template_p) return error_mark_node; t = build2 (SCOPE_REF, type, scope, name); QUALIFIED_NAME_IS_TEMPLATE (t) = template_p; + PTRMEM_OK_P (t) = true; if (type) t = convert_from_reference (t); return t; @@ -3291,10 +3292,18 @@ stabilize_init (tree init, tree *initp) t = TARGET_EXPR_INITIAL (t); if (TREE_CODE (t) == COMPOUND_EXPR) t = expr_last (t); - if (TREE_CODE (t) == CONSTRUCTOR - && EMPTY_CONSTRUCTOR_P (t)) - /* Default-initialization. */ - return true; + if (TREE_CODE (t) == CONSTRUCTOR) + { + /* Aggregate initialization: stabilize each of the field + initializers. */ + unsigned i; + tree value; + bool good = true; + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), i, value) + if (!stabilize_init (value, initp)) + good = false; + return good; + } /* If the initializer is a COND_EXPR, we can't preevaluate anything. */ diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index a4a1b04519c..49aac95e617 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -3105,10 +3105,12 @@ Systems using processors that implement the DEC Alpha architecture and are running the DEC/Compaq/HP Unix (DEC OSF/1, Digital UNIX, or Compaq/HP Tru64 UNIX) operating system, for example the DEC Alpha AXP systems. -As of GCC 3.2, versions before @code{alpha*-dec-osf4} are no longer -supported. (These are the versions which identify themselves as DEC -OSF/1.) As of GCC 4.6, support for Tru64 UNIX V4.0 and V5.0 has been -removed. +Support for Tru64 UNIX V5.1 has been obsoleted in GCC 4.7, but can still +be enabled by configuring with @option{--enable-obsolete}. Support will +be removed in GCC 4.8. As of GCC 4.6, support for Tru64 UNIX V4.0 and +V5.0 has been removed. As of GCC 3.2, versions before +@code{alpha*-dec-osf4} are no longer supported. (These are the versions +which identify themselves as DEC OSF/1.) On Tru64 UNIX, virtual memory exhausted bootstrap failures may be fixed by reconfiguring Kernel Virtual Memory and Swap parameters @@ -3887,11 +3889,13 @@ Support for IRIX 5 has been removed in GCC 4.6. @end html @heading @anchor{mips-sgi-irix6}mips-sgi-irix6 -Support for IRIX 6 releases before 6.5 has been removed in GCC 4.6, as -well as support for -the O32 ABI. It is @emph{strongly} recommended to upgrade to at least -IRIX 6.5.18. This release introduced full ISO C99 support, though for -the N32 and N64 ABIs only. +Support for IRIX 6.5 has been obsoleted in GCC 4.7, but can still be +enabled by configuring with @option{--enable-obsolete}. Support will be +removed in GCC 4.8. Support for IRIX 6 releases before 6.5 has been +removed in GCC 4.6, as well as support for the O32 ABI. It is +@emph{strongly} recommended to upgrade to at least IRIX 6.5.18. This +release introduced full ISO C99 support, though for the N32 and N64 ABIs +only. To build and use GCC on IRIX 6.5, you need the IRIX Development Foundation (IDF) and IRIX Development Libraries (IDL). They are included with the diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index d2cc4ea3ead..3d41c0d029e 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -1760,6 +1760,9 @@ Target uses GNU @command{as}. @item gc_sections Target supports @option{--gc-sections}. +@item gld +Target uses GNU @command{ld}. + @item keeps_null_pointer_checks Target keeps null pointer checks, either due to the use of @option{-fno-delete-null-pointer-checks} or hardwired into the target. diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 0b5a68a1517..a0714c45d26 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -1732,17 +1732,56 @@ struct GTY(()) queued_reg_save { static GTY(()) struct queued_reg_save *queued_reg_saves; /* The caller's ORIG_REG is saved in SAVED_IN_REG. */ -struct GTY(()) reg_saved_in_data { +typedef struct GTY(()) reg_saved_in_data { rtx orig_reg; rtx saved_in_reg; -}; +} reg_saved_in_data; + +DEF_VEC_O (reg_saved_in_data); +DEF_VEC_ALLOC_O (reg_saved_in_data, gc); + +/* A set of registers saved in other registers. This is implemented as + a flat array because it normally contains zero or 1 entry, depending + on the target. IA-64 is the big spender here, using a maximum of + 5 entries. */ +static GTY(()) VEC(reg_saved_in_data, gc) *regs_saved_in_regs; + +/* Compare X and Y for equivalence. The inputs may be REGs or PC_RTX. */ + +static bool +compare_reg_or_pc (rtx x, rtx y) +{ + if (REG_P (x) && REG_P (y)) + return REGNO (x) == REGNO (y); + return x == y; +} + +/* Record SRC as being saved in DEST. DEST may be null to delete an + existing entry. SRC may be a register or PC_RTX. */ + +static void +record_reg_saved_in_reg (rtx dest, rtx src) +{ + reg_saved_in_data *elt; + size_t i; + + FOR_EACH_VEC_ELT (reg_saved_in_data, regs_saved_in_regs, i, elt) + if (compare_reg_or_pc (elt->orig_reg, src)) + { + if (dest == NULL) + VEC_unordered_remove(reg_saved_in_data, regs_saved_in_regs, i); + else + elt->saved_in_reg = dest; + return; + } -/* A list of registers saved in other registers. - The list intentionally has a small maximum capacity of 4; if your - port needs more than that, you might consider implementing a - more efficient data structure. */ -static GTY(()) struct reg_saved_in_data regs_saved_in_regs[4]; -static GTY(()) size_t num_regs_saved_in_regs; + if (dest == NULL) + return; + + elt = VEC_safe_push(reg_saved_in_data, gc, regs_saved_in_regs, NULL); + elt->orig_reg = src; + elt->saved_in_reg = dest; +} static const char *last_reg_save_label; @@ -1784,22 +1823,9 @@ dwarf2out_flush_queued_reg_saves (void) for (q = queued_reg_saves; q; q = q->next) { - size_t i; unsigned int reg, sreg; - for (i = 0; i < num_regs_saved_in_regs; i++) - if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg)) - break; - if (q->saved_reg && i == num_regs_saved_in_regs) - { - gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs)); - num_regs_saved_in_regs++; - } - if (i != num_regs_saved_in_regs) - { - regs_saved_in_regs[i].orig_reg = q->reg; - regs_saved_in_regs[i].saved_in_reg = q->saved_reg; - } + record_reg_saved_in_reg (q->saved_reg, q->reg); reg = DWARF_FRAME_REGNUM (REGNO (q->reg)); if (q->saved_reg) @@ -1826,11 +1852,14 @@ clobbers_queued_reg_save (const_rtx insn) for (q = queued_reg_saves; q; q = q->next) { size_t i; + reg_saved_in_data *rir; + if (modified_in_p (q->reg, insn)) return true; - for (i = 0; i < num_regs_saved_in_regs; i++) - if (REGNO (q->reg) == REGNO (regs_saved_in_regs[i].orig_reg) - && modified_in_p (regs_saved_in_regs[i].saved_in_reg, insn)) + + FOR_EACH_VEC_ELT (reg_saved_in_data, regs_saved_in_regs, i, rir) + if (compare_reg_or_pc (q->reg, rir->orig_reg) + && modified_in_p (rir->saved_in_reg, insn)) return true; } @@ -1842,19 +1871,9 @@ clobbers_queued_reg_save (const_rtx insn) void dwarf2out_reg_save_reg (const char *label, rtx reg, rtx sreg) { - size_t i; unsigned int regno, sregno; - for (i = 0; i < num_regs_saved_in_regs; i++) - if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (reg)) - break; - if (i == num_regs_saved_in_regs) - { - gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs)); - num_regs_saved_in_regs++; - } - regs_saved_in_regs[i].orig_reg = reg; - regs_saved_in_regs[i].saved_in_reg = sreg; + record_reg_saved_in_reg (sreg, reg); regno = DWARF_FRAME_REGNUM (REGNO (reg)); sregno = DWARF_FRAME_REGNUM (REGNO (sreg)); @@ -1867,17 +1886,17 @@ static rtx reg_saved_in (rtx reg) { unsigned int regn = REGNO (reg); - size_t i; struct queued_reg_save *q; + reg_saved_in_data *rir; + size_t i; for (q = queued_reg_saves; q; q = q->next) if (q->saved_reg && regn == REGNO (q->saved_reg)) return q->reg; - for (i = 0; i < num_regs_saved_in_regs; i++) - if (regs_saved_in_regs[i].saved_in_reg - && regn == REGNO (regs_saved_in_regs[i].saved_in_reg)) - return regs_saved_in_regs[i].orig_reg; + FOR_EACH_VEC_ELT (reg_saved_in_data, regs_saved_in_regs, i, rir) + if (regn == REGNO (rir->saved_in_reg)) + return rir->orig_reg; return NULL_RTX; } @@ -1963,6 +1982,7 @@ dwarf2out_frame_debug_cfa_offset (rtx set, const char *label) { HOST_WIDE_INT offset; rtx src, addr, span; + unsigned int sregno; src = XEXP (set, 1); addr = XEXP (set, 0); @@ -1984,12 +2004,21 @@ dwarf2out_frame_debug_cfa_offset (rtx set, const char *label) gcc_unreachable (); } - span = targetm.dwarf_register_span (src); + if (src == pc_rtx) + { + span = NULL; + sregno = DWARF_FRAME_RETURN_COLUMN; + } + else + { + span = targetm.dwarf_register_span (src); + sregno = DWARF_FRAME_REGNUM (REGNO (src)); + } /* ??? We'd like to use queue_reg_save, but we need to come up with a different flushing heuristic for epilogues. */ if (!span) - reg_save (label, DWARF_FRAME_REGNUM (REGNO (src)), INVALID_REGNUM, offset); + reg_save (label, sregno, INVALID_REGNUM, offset); else { /* We have a PARALLEL describing where the contents of SRC live. @@ -2005,8 +2034,8 @@ dwarf2out_frame_debug_cfa_offset (rtx set, const char *label) { rtx elem = XVECEXP (span, 0, par_index); - reg_save (label, DWARF_FRAME_REGNUM (REGNO (elem)), - INVALID_REGNUM, span_offset); + sregno = DWARF_FRAME_REGNUM (REGNO (src)); + reg_save (label, sregno, INVALID_REGNUM, span_offset); span_offset += GET_MODE_SIZE (GET_MODE (elem)); } } @@ -2026,7 +2055,10 @@ dwarf2out_frame_debug_cfa_register (rtx set, const char *label) if (src == pc_rtx) sregno = DWARF_FRAME_RETURN_COLUMN; else - sregno = DWARF_FRAME_REGNUM (REGNO (src)); + { + record_reg_saved_in_reg (dest, src); + sregno = DWARF_FRAME_REGNUM (REGNO (src)); + } dregno = DWARF_FRAME_REGNUM (REGNO (dest)); @@ -2800,6 +2832,7 @@ dwarf2out_frame_debug (rtx insn, bool after_p) const char *label; rtx note, n; bool handled_one = false; + bool need_flush = false; if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn)) dwarf2out_flush_queued_reg_saves (); @@ -2822,7 +2855,7 @@ dwarf2out_frame_debug (rtx insn, bool after_p) { case REG_FRAME_RELATED_EXPR: insn = XEXP (note, 0); - goto found; + goto do_frame_expr; case REG_CFA_DEF_CFA: dwarf2out_frame_debug_def_cfa (XEXP (note, 0), label); @@ -2902,24 +2935,36 @@ dwarf2out_frame_debug (rtx insn, bool after_p) handled_one = true; break; + case REG_CFA_FLUSH_QUEUE: + /* The actual flush happens below. */ + need_flush = true; + handled_one = true; + break; + default: break; } + if (handled_one) { - if (any_cfis_emitted) - dwarf2out_flush_queued_reg_saves (); - return; + /* Minimize the number of advances by emitting the entire queue + once anything is emitted. */ + need_flush |= any_cfis_emitted; } + else + { + insn = PATTERN (insn); + do_frame_expr: + dwarf2out_frame_debug_expr (insn, label); - insn = PATTERN (insn); - found: - dwarf2out_frame_debug_expr (insn, label); + /* Check again. A parallel can save and update the same register. + We could probably check just once, here, but this is safer than + removing the check at the start of the function. */ + if (any_cfis_emitted || clobbers_queued_reg_save (insn)) + need_flush = true; + } - /* Check again. A parallel can save and update the same register. - We could probably check just once, here, but this is safer than - removing the check above. */ - if (any_cfis_emitted || clobbers_queued_reg_save (insn)) + if (need_flush) dwarf2out_flush_queued_reg_saves (); } @@ -2928,8 +2973,6 @@ dwarf2out_frame_debug (rtx insn, bool after_p) void dwarf2out_frame_debug_init (void) { - size_t i; - /* Flush any queued register saves. */ dwarf2out_flush_queued_reg_saves (); @@ -2943,12 +2986,7 @@ dwarf2out_frame_debug_init (void) cfa_temp.reg = -1; cfa_temp.offset = 0; - for (i = 0; i < num_regs_saved_in_regs; i++) - { - regs_saved_in_regs[i].orig_reg = NULL_RTX; - regs_saved_in_regs[i].saved_in_reg = NULL_RTX; - } - num_regs_saved_in_regs = 0; + regs_saved_in_regs = NULL; if (barrier_args_size) { @@ -13151,6 +13189,8 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, name = DECL_NAME (name); add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name)); add_gnat_descriptive_type_attribute (mod_type_die, type, context_die); + if (TYPE_ARTIFICIAL (type)) + add_AT_flag (mod_type_die, DW_AT_artificial, 1); } /* This probably indicates a bug. */ else if (mod_type_die && mod_type_die->die_tag == DW_TAG_base_type) @@ -19406,6 +19446,8 @@ gen_array_type_die (tree type, dw_die_ref context_die) array_die = new_die (DW_TAG_array_type, scope_die, type); add_name_attribute (array_die, type_tag (type)); add_gnat_descriptive_type_attribute (array_die, type, context_die); + if (TYPE_ARTIFICIAL (type)) + add_AT_flag (array_die, DW_AT_artificial, 1); equate_type_number_to_die (type, array_die); if (TREE_CODE (type) == VECTOR_TYPE) @@ -19709,6 +19751,8 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die) equate_type_number_to_die (type, type_die); add_name_attribute (type_die, type_tag (type)); add_gnat_descriptive_type_attribute (type_die, type, context_die); + if (TYPE_ARTIFICIAL (type)) + add_AT_flag (type_die, DW_AT_artificial, 1); if (dwarf_version >= 4 || !dwarf_strict) { if (ENUM_IS_SCOPED (type)) @@ -21566,6 +21610,8 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die, { add_name_attribute (type_die, type_tag (type)); add_gnat_descriptive_type_attribute (type_die, type, context_die); + if (TYPE_ARTIFICIAL (type)) + add_AT_flag (type_die, DW_AT_artificial, 1); } } else diff --git a/gcc/explow.c b/gcc/explow.c index c7d81838033..a042273ec94 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -1102,7 +1102,9 @@ update_nonlocal_goto_save_area (void) first one is used for the frame pointer save; the rest are sized by STACK_SAVEAREA_MODE. Create a reference to array index 1, the first of the stack save area slots. */ - t_save = build4 (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area, + t_save = build4 (ARRAY_REF, + TREE_TYPE (TREE_TYPE (cfun->nonlocal_goto_save_area)), + cfun->nonlocal_goto_save_area, integer_one_node, NULL_TREE, NULL_TREE); r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE); diff --git a/gcc/final.c b/gcc/final.c index cb4a83d08ee..c0c1fc850ec 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -2683,7 +2683,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, current_output_insn = debug_insn = insn; - if (CALL_P (insn) && dwarf2out_do_frame ()) + if (dwarf2out_do_frame () + && (CALL_P (insn) + || find_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL))) dwarf2out_frame_debug (insn, false); /* Find the proper template for this insn. */ diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 055c15d29e1..e2d5d124dac 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,8 @@ +2011-07-02 Janus Weil <janus@gcc.gnu.org> + + PR fortran/49562 + * expr.c (gfc_check_vardef_context): Handle type-bound procedures. + 2011-06-30 Jakub Jelinek <jakub@redhat.com> PR fortran/49540 diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index 4a7a951b6d6..6dcfda1e53a 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -4394,8 +4394,8 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj, sym = e->value.function.esym ? e->value.function.esym : e->symtree->n.sym; } - if (!pointer && e->expr_type == EXPR_FUNCTION - && sym->result->attr.pointer) + attr = gfc_expr_attr (e); + if (!pointer && e->expr_type == EXPR_FUNCTION && attr.pointer) { if (!(gfc_option.allow_std & GFC_STD_F2008)) { @@ -4432,7 +4432,6 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj, /* Find out whether the expr is a pointer; this also means following component references to the last one. */ - attr = gfc_expr_attr (e); is_pointer = (attr.pointer || attr.proc_pointer); if (pointer && !is_pointer) { diff --git a/gcc/function.c b/gcc/function.c index 5be018afde7..0b2f5aa5c37 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -4782,11 +4782,12 @@ expand_function_start (tree subr) if (!DECL_RTL_SET_P (var)) expand_decl (var); - t_save = build4 (ARRAY_REF, ptr_type_node, + t_save = build4 (ARRAY_REF, + TREE_TYPE (TREE_TYPE (cfun->nonlocal_goto_save_area)), cfun->nonlocal_goto_save_area, integer_zero_node, NULL_TREE, NULL_TREE); r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE); - r_save = convert_memory_address (Pmode, r_save); + gcc_assert (GET_MODE (r_save) == Pmode); emit_move_insn (r_save, targetm.builtin_setjmp_frame_value ()); update_nonlocal_goto_save_area (); diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c index 25ccb24a105..7a4f7225bdc 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -1563,7 +1563,10 @@ unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr) else bp_unpack_value (bp, 1); TREE_ASM_WRITTEN (expr) = (unsigned) bp_unpack_value (bp, 1); - TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1); + if (TYPE_P (expr)) + TYPE_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1); + else + TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_USED (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_NOTHROW (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_STATIC (expr) = (unsigned) bp_unpack_value (bp, 1); diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index 19b0ae8bb1e..6345d83d2c9 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -340,7 +340,10 @@ pack_ts_base_value_fields (struct bitpack_d *bp, tree expr) bp_pack_value (bp, 0, 1); /* We write debug info two times, do not confuse the second one. */ bp_pack_value (bp, TYPE_P (expr) ? 0 : TREE_ASM_WRITTEN (expr), 1); - bp_pack_value (bp, TREE_NO_WARNING (expr), 1); + if (TYPE_P (expr)) + bp_pack_value (bp, TYPE_ARTIFICIAL (expr), 1); + else + bp_pack_value (bp, TREE_NO_WARNING (expr), 1); bp_pack_value (bp, TREE_USED (expr), 1); bp_pack_value (bp, TREE_NOTHROW (expr), 1); bp_pack_value (bp, TREE_STATIC (expr), 1); diff --git a/gcc/reg-notes.def b/gcc/reg-notes.def index 9924355f772..eccac9e9d70 100644 --- a/gcc/reg-notes.def +++ b/gcc/reg-notes.def @@ -155,16 +155,23 @@ REG_NOTE (CFA_EXPRESSION) first pattern is the register to be restored. */ REG_NOTE (CFA_RESTORE) -/* Attached to insn that is RTX_FRAME_RELATED_P, marks insn that sets +/* Attached to insns that are RTX_FRAME_RELATED_P, marks insn that sets vDRAP from DRAP. If vDRAP is a register, vdrap_reg is initalized to the argument, if it is a MEM, it is ignored. */ REG_NOTE (CFA_SET_VDRAP) -/* Attached to insn that are RTX_FRAME_RELATED_P, indicating a window +/* Attached to insns that are RTX_FRAME_RELATED_P, indicating a window save operation, i.e. will result in a DW_CFA_GNU_window_save. The argument is ignored. */ REG_NOTE (CFA_WINDOW_SAVE) +/* Attached to insns that are RTX_FRAME_RELATED_P, marks the insn as + requiring that all queued information should be flushed *before* insn, + regardless of what is visible in the rtl. The argument is ignored. + This is normally used for a call instruction which is not exposed to + the rest of the compiler as a CALL_INSN. */ +REG_NOTE (CFA_FLUSH_QUEUE) + /* Indicates that REG holds the exception context for the function. This context is shared by inline functions, so the code to acquire the real exception context is delayed until after inlining. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ce9314187dd..326ba5f8770 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,69 @@ +2011-07-03 Ira Rosen <ira.rosen@linaro.org> + + PR tree-optimization/49610 + * gcc.dg/vect/pr49610.c: New test. + +2011-07-02 Eric Botcazou <ebotcazou@adacore.com> + + * gnat.dg/specs/debug1.ads: New test. + +2011-07-02 Janus Weil <janus@gcc.gnu.org> + + PR fortran/49562 + * gfortran.dg/typebound_proc_23.f90: New. + +2011-07-01 Jonathan Wakely <jwakely.gcc@gmail.com> + + PR c++/49605 + * g++.dg/warn/delete-non-virtual-dtor.C: Adjust. + +2011-07-01 Jason Merrill <jason@redhat.com> + + PR c++/48261 + * g++.dg/template/template-id-3.C: New. + + PR c++/48593 + * g++.dg/template/qualified-id4.C: New. + + PR c++/48883 + * g++.dg/template/explicit-args4.C: New. + + PR c++/49085 + * g++.dg/template/offsetof2.C: New. + +2011-07-01 Kai Tietz <ktietz@redhat.com> + + * gcc.dg/tree-ssa/bitwise-sink.c: New test. + +2011-07-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + PR libmudflap/49549 + * lib/target-supports.exp (check_effective_target_gld): New proc. + +2011-07-01 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/49603 + * gcc.dg/torture/pr49603.c: New testcase. + +2011-06-30 Jason Merrill <jason@redhat.com> + + PR c++/49387 + * g++.dg/rtti/template1.C: New. + + PR c++/49569 + * g++.dg/cpp0x/regress/ctor1.C: New. + + PR c++/49355 + * g++.dg/cpp0x/initlist54.C: New. + +2011-06-30 Martin Jambor <mjambor@suse.cz> + + * gcc.dg/tree-ssa/sra-12.c: New test. + +2011-06-29 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp0x/named.C: Test subobject of xvalue. + 2011-06-30 Richard Guenther <rguenther@suse.de> PR tree-optimization/46787 @@ -453,7 +519,7 @@ 2011-06-18 Janne Blomqvist <jb@gcc.gnu.org> - PR libfortran/48296 + PR libfortran/49296 * gfortran.dg/read_list_eof_1.f90: New test. 2011-06-18 Jakub Jelinek <jakub@redhat.com> diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist54.C b/gcc/testsuite/g++.dg/cpp0x/initlist54.C new file mode 100644 index 00000000000..cdb296133f8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist54.C @@ -0,0 +1,13 @@ +// PR c++/49355 +// { dg-options -std=c++0x } + +#include <string> + +struct T { + std::string foobar; +}; + +int main() +{ + T* x = new T({""}); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/named.C b/gcc/testsuite/g++.dg/cpp0x/named.C index ef1a2fb6f7d..2dff24ca475 100644 --- a/gcc/testsuite/g++.dg/cpp0x/named.C +++ b/gcc/testsuite/g++.dg/cpp0x/named.C @@ -13,6 +13,7 @@ struct T S && get() { return movel(s); } operator S&&() { return movel(s); } S && s; + S s2; }; void named(S const &) {} @@ -33,6 +34,7 @@ void f(S && p) unnamed(t.get()); // function return unnamed(t); // implicit conversion unnamed(static_cast<S&&>(s)); // cast to rvalue + unnamed(static_cast<T&&>(t).s2); // cast to rvalue } int main() diff --git a/gcc/testsuite/g++.dg/cpp0x/regress/ctor1.C b/gcc/testsuite/g++.dg/cpp0x/regress/ctor1.C new file mode 100644 index 00000000000..c35d6011f3b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/regress/ctor1.C @@ -0,0 +1,21 @@ +// PR c++/49569 +// { dg-options -std=c++0x } + +struct A +{ + virtual void f() = 0; +}; + +struct B: A +{ + int i; + virtual void f() { } +}; + +struct C +{ + B b; + C(): b() { } + C(const B& b): b(b) { } +}; + diff --git a/gcc/testsuite/g++.dg/rtti/template1.C b/gcc/testsuite/g++.dg/rtti/template1.C new file mode 100644 index 00000000000..e2a03766fbb --- /dev/null +++ b/gcc/testsuite/g++.dg/rtti/template1.C @@ -0,0 +1,23 @@ +// PR c++/49387 + +#include <typeinfo> + +struct ResourceMonitorClient { }; + +template <typename T> struct ResourcePool : public ResourceMonitorClient { + virtual ~ResourcePool() { } +}; + +template <typename T> struct BaseWriter { + + BaseWriter() { + typeid(ResourcePool<int>*); + } + + virtual void run() { + ResourcePool<int> pool; + } + +}; + +BaseWriter<void> b; diff --git a/gcc/testsuite/g++.dg/template/crash37.C b/gcc/testsuite/g++.dg/template/crash37.C index 60724231eab..d5167c8d2dc 100644 --- a/gcc/testsuite/g++.dg/template/crash37.C +++ b/gcc/testsuite/g++.dg/template/crash37.C @@ -11,7 +11,7 @@ struct coperator_stack struct helper {}; template<class F> -void bla(F f) // { dg-message "bla|no known conversion" } +void bla(F f) { } @@ -20,8 +20,7 @@ struct definition { definition() { - bla(coperator_stack::push3<helper>); // { dg-error "matching" } - // { dg-message "candidate" "candidate note" { target *-*-* } 23 } + bla(coperator_stack::push3<helper>); // { dg-error "pointer to member" } } }; diff --git a/gcc/testsuite/g++.dg/template/explicit-args4.C b/gcc/testsuite/g++.dg/template/explicit-args4.C new file mode 100644 index 00000000000..c64a085edb6 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/explicit-args4.C @@ -0,0 +1,14 @@ +// PR c++/48883 +// { dg-do link } + +template<typename T> +T myMax(T a, T b) { + if(a < b) return a; + return b; +} + +int main() { + bool even = true; + int (*fp)(int, int); + fp = even ? myMax<int> : myMax<int>; /* yields link error */ +} diff --git a/gcc/testsuite/g++.dg/template/offsetof2.C b/gcc/testsuite/g++.dg/template/offsetof2.C new file mode 100644 index 00000000000..da888f7a59e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/offsetof2.C @@ -0,0 +1,10 @@ +// PR c++/49085 + +template <class T> +struct A // { dg-error "declaration" } +{ + int i, j; + int ar[__builtin_offsetof(A,j)]; // { dg-error "incomplete type" } +}; + +A<int> a; diff --git a/gcc/testsuite/g++.dg/template/ptrmem4.C b/gcc/testsuite/g++.dg/template/ptrmem4.C index 62262c4b8e9..14f36d4e386 100644 --- a/gcc/testsuite/g++.dg/template/ptrmem4.C +++ b/gcc/testsuite/g++.dg/template/ptrmem4.C @@ -16,6 +16,5 @@ struct SpyExample void SpyExample::ready() { - queryAliases(inputs); // { dg-error "matching" } - // { dg-message "candidate" "candidate note" { target *-*-* } 19 } + queryAliases(inputs); // { dg-error "matching|unresolved" } } diff --git a/gcc/testsuite/g++.dg/template/qualified-id4.C b/gcc/testsuite/g++.dg/template/qualified-id4.C new file mode 100644 index 00000000000..0d97cb868cb --- /dev/null +++ b/gcc/testsuite/g++.dg/template/qualified-id4.C @@ -0,0 +1,20 @@ +// PR c++/48593 + +template <typename T> struct foo +{ + T data; +}; + +template<typename T> struct bar: public foo<T> +{ + void some_func() + { + T* ptr = &(foo<T>::data); + } +}; + +int main() +{ + bar<int>().some_func(); +} + diff --git a/gcc/testsuite/g++.dg/template/template-id-3.C b/gcc/testsuite/g++.dg/template/template-id-3.C new file mode 100644 index 00000000000..e0753abd9e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/template-id-3.C @@ -0,0 +1,22 @@ +// PR c++/48261 + +typedef double (*gaddType)(double,double); +struct Foo2 +{ + static gaddType add; +}; + +template<typename T> +struct Something +{ + void work() + { + double x=T::template add<double>(5.0,6.0); // { dg-error "add" } + } +}; + +int main() +{ + Something<Foo2> s2; + s2.work(); +} diff --git a/gcc/testsuite/g++.dg/warn/delete-non-virtual-dtor.C b/gcc/testsuite/g++.dg/warn/delete-non-virtual-dtor.C index 9849b1edfa8..c4acbde26a1 100644 --- a/gcc/testsuite/g++.dg/warn/delete-non-virtual-dtor.C +++ b/gcc/testsuite/g++.dg/warn/delete-non-virtual-dtor.C @@ -5,6 +5,7 @@ struct polyBase { virtual void f(); }; void f(polyBase* p, polyBase* arr) { + polyBase pb; delete p; // { dg-warning "non-virtual destructor might" } delete [] arr; } @@ -13,6 +14,7 @@ struct polyDerived : polyBase { }; void f(polyDerived* p, polyDerived* arr) { + polyDerived pd; delete p; // { dg-warning "non-virtual destructor might" } delete [] arr; } @@ -29,6 +31,7 @@ struct finalDerived final : polyBase { }; void f(finalDerived* p, finalDerived* arr) { + finalDerived fd; delete p; // no error for final classes delete [] arr; } @@ -38,7 +41,26 @@ struct safeDerived : safeBase { virtual void f(); }; void f(safeDerived* p, safeDerived* arr) { + safeDerived sd; delete p; // no error because base has virtual dtor delete [] arr; } +struct polyBaseNonTrivial { ~polyBaseNonTrivial(); virtual void f(); }; + +void f(polyBaseNonTrivial* p, polyBaseNonTrivial* arr) +{ + polyBaseNonTrivial pbnt; + delete p; // { dg-warning "non-virtual destructor might" } + delete [] arr; +} + +struct polyDerivedNT : polyBaseNonTrivial { ~polyDerivedNT(); }; + +void f(polyDerivedNT* p, polyDerivedNT* arr) +{ + polyDerivedNT pdnt; + delete p; // { dg-warning "non-virtual destructor might" } + delete [] arr; +} + diff --git a/gcc/testsuite/g++.old-deja/g++.other/pmf3.C b/gcc/testsuite/g++.old-deja/g++.other/pmf3.C index 11e648ed86e..448d7914571 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/pmf3.C +++ b/gcc/testsuite/g++.old-deja/g++.other/pmf3.C @@ -3,7 +3,7 @@ // Bug: g++ was crashing after giving errors. template<class T> - void connect_to_method( // { dg-message "connect_to_method|no known conversion" } + void connect_to_method( T *receiver, void (T::*method)()) {} @@ -20,7 +20,6 @@ public: Gtk_Base::Gtk_Base() { - connect_to_method(this,&show); // { dg-error "no match" } invalid pmf expression - // { dg-message "candidate" "candidate note" { target *-*-* } 23 } + connect_to_method(this,&show); // { dg-error "pointer to member" } invalid pmf expression connect_to_method(this,&expose); // { dg-error "pointer to member" } invalid pmf expression } diff --git a/gcc/testsuite/gcc.dg/torture/pr49603.c b/gcc/testsuite/gcc.dg/torture/pr49603.c new file mode 100644 index 00000000000..90f51e5059c --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr49603.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ + +struct gl_visual { + float AlphaScale; +}; +struct gl_context { + struct gl_visual *Visual; +}; +void quickdraw_rgb( struct gl_context * ctx, + int width, int height) +{ + int i, j; + unsigned char alpha[1600]; + for (j=0; j<width; j++) + alpha[j] = (int) ctx->Visual->AlphaScale; + for (i=0; i<height; i++) + foo( alpha); +} + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bitwise-sink.c b/gcc/testsuite/gcc.dg/tree-ssa/bitwise-sink.c new file mode 100644 index 00000000000..f44529995b7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/bitwise-sink.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +int +foo (_Bool x) +{ + return (x ^ 1); +} + +/* { dg-final { scan-tree-dump-times "x\[^ \]* \\^ 1" 1 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/sra-12.c b/gcc/testsuite/gcc.dg/tree-ssa/sra-12.c new file mode 100644 index 00000000000..988caecd4ae --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/sra-12.c @@ -0,0 +1,25 @@ +/* Verify that SRA total scalarization will not be confused by padding. */ + +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-release_ssa" } */ + +struct S +{ + int i; + unsigned short f1; + char f2; + unsigned short f3, f4; +}; + + +int foo (struct S *p) +{ + struct S l; + + l = *p; + l.i++; + *p = l; +} + +/* { dg-final { scan-tree-dump-times "l;" 0 "release_ssa"} } */ +/* { dg-final { cleanup-tree-dump "release_ssa" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr49610.c b/gcc/testsuite/gcc.dg/vect/pr49610.c new file mode 100644 index 00000000000..87ac5b50343 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr49610.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ + +extern int g_7; +void func_13(int p_17) { + int i; + for (i=0; i < 16; i = (signed char)(i+1)) { + g_7 &= p_17; + g_7 &= (p_17 > 1); + } +} + +/* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gfortran.dg/typebound_proc_23.f90 b/gcc/testsuite/gfortran.dg/typebound_proc_23.f90 new file mode 100644 index 00000000000..ff682a41b36 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/typebound_proc_23.f90 @@ -0,0 +1,32 @@ +! { dg-do run } +! +! PR 49562: [4.6/4.7 Regression] [OOP] assigning value to type-bound function +! +! Contributed by Hans-Werner Boschmann <boschmann@tp1.physik.uni-siegen.de> + +module ice + type::ice_type + contains + procedure::ice_func + end type + integer, target :: it = 0 +contains + function ice_func(this) + integer, pointer :: ice_func + class(ice_type)::this + ice_func => it + end function ice_func + subroutine ice_sub(a) + class(ice_type)::a + a%ice_func() = 1 + end subroutine ice_sub +end module + +use ice +type(ice_type) :: t +if (it/=0) call abort() +call ice_sub(t) +if (it/=1) call abort() +end + +! { dg-final { cleanup-modules "ice" } } diff --git a/gcc/testsuite/gnat.dg/specs/debug1.ads b/gcc/testsuite/gnat.dg/specs/debug1.ads new file mode 100644 index 00000000000..30ccf2891c0 --- /dev/null +++ b/gcc/testsuite/gnat.dg/specs/debug1.ads @@ -0,0 +1,14 @@ +-- { dg-do compile { target *-*-linux* } } +-- { dg-options "-gdwarf-2 -cargs -dA" } + +package Debug1 is + + function N return Integer; + pragma Import (Ada, N); + + type Arr is array (-N .. N) of Boolean; + A : Arr; + +end Debug1; + +-- { dg-final { scan-assembler-times "byte\t0x1\t# DW_AT_artificial" 4 } } diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 393c3ade82e..4e56e48412f 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -3843,6 +3843,26 @@ proc check_effective_target_gas { } { return $use_gas_saved } +# Return 1 if GNU ld is used. + +proc check_effective_target_gld { } { + global use_gld_saved + global tool + + if {![info exists use_gld_saved]} { + # Check if the ld used by gcc is GNU ld. + set gcc_ld [lindex [${tool}_target_compile "-print-prog-name=ld" "" "none" ""] 0] + set status [remote_exec host "$gcc_ld" "--version"] + set ld_output [lindex $status 1] + if { [ string first "GNU" $ld_output ] >= 0 } { + set use_gld_saved 1 + } else { + set use_gld_saved 0 + } + } + return $use_gld_saved +} + # Return 1 if the compiler has been configure with link-time optimization # (LTO) support. diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 674f72e9031..b85c9730f1d 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -1,5 +1,5 @@ /* __builtin_object_size (ptr, object_size_type) computation - Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Jakub Jelinek <jakub@redhat.com> @@ -464,6 +464,7 @@ pass_through_call (const_gimple call) case BUILT_IN_STRNCPY_CHK: case BUILT_IN_STRCAT_CHK: case BUILT_IN_STRNCAT_CHK: + case BUILT_IN_ASSUME_ALIGNED: if (gimple_call_num_args (call) >= 1) return gimple_call_arg (call, 0); break; diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 2102aaa37f3..2a938b72a09 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1,6 +1,6 @@ /* Pretty formatting of GENERIC trees in C syntax. - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011 Free Software Foundation, Inc. Adapted from c-pretty-print.c by Diego Novillo <dnovillo@redhat.com> This file is part of GCC. @@ -1250,19 +1250,58 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, { unsigned HOST_WIDE_INT ix; tree field, val; - bool is_struct_init = FALSE; + bool is_struct_init = false; + bool is_array_init = false; + double_int curidx = double_int_zero; pp_character (buffer, '{'); if (TREE_CODE (TREE_TYPE (node)) == RECORD_TYPE || TREE_CODE (TREE_TYPE (node)) == UNION_TYPE) - is_struct_init = TRUE; + is_struct_init = true; + else if (TREE_CODE (TREE_TYPE (node)) == ARRAY_TYPE + && TYPE_DOMAIN (TREE_TYPE (node)) + && TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (node))) + && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (node)))) + == INTEGER_CST) + { + tree minv = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (node))); + is_array_init = true; + curidx = tree_to_double_int (minv); + } FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (node), ix, field, val) { - if (field && is_struct_init) + if (field) { - pp_character (buffer, '.'); - dump_generic_node (buffer, field, spc, flags, false); - pp_string (buffer, "="); + if (is_struct_init) + { + pp_character (buffer, '.'); + dump_generic_node (buffer, field, spc, flags, false); + pp_character (buffer, '='); + } + else if (is_array_init + && (TREE_CODE (field) != INTEGER_CST + || !double_int_equal_p (tree_to_double_int (field), + curidx))) + { + pp_character (buffer, '['); + if (TREE_CODE (field) == RANGE_EXPR) + { + dump_generic_node (buffer, TREE_OPERAND (field, 0), spc, + flags, false); + pp_string (buffer, " ... "); + dump_generic_node (buffer, TREE_OPERAND (field, 1), spc, + flags, false); + if (TREE_CODE (TREE_OPERAND (field, 1)) == INTEGER_CST) + curidx = tree_to_double_int (TREE_OPERAND (field, 1)); + } + else + dump_generic_node (buffer, field, spc, flags, false); + if (TREE_CODE (field) == INTEGER_CST) + curidx = tree_to_double_int (field); + pp_string (buffer, "]="); + } } + if (is_array_init) + curidx = double_int_add (curidx, double_int_one); if (val && TREE_CODE (val) == ADDR_EXPR) if (TREE_CODE (TREE_OPERAND (val, 0)) == FUNCTION_DECL) val = TREE_OPERAND (val, 0); diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index e45ff8a0272..ca9f316f712 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -170,10 +170,6 @@ struct access /* Is this particular access write access? */ unsigned write : 1; - /* Is this access an artificial one created to scalarize some record - entirely? */ - unsigned total_scalarization : 1; - /* Is this access an access to a non-addressable field? */ unsigned non_addressable : 1; @@ -204,6 +200,10 @@ struct access is not propagated in the access tree in any direction. */ unsigned grp_scalar_write : 1; + /* Is this access an artificial one created to scalarize some record + entirely? */ + unsigned grp_total_scalarization : 1; + /* Other passes of the analysis use this bit to make function analyze_access_subtree create scalar replacements for this group if possible. */ @@ -377,26 +377,26 @@ dump_access (FILE *f, struct access *access, bool grp) fprintf (f, ", type = "); print_generic_expr (f, access->type, 0); if (grp) - fprintf (f, ", total_scalarization = %d, grp_read = %d, grp_write = %d, " - "grp_assignment_read = %d, grp_assignment_write = %d, " - "grp_scalar_read = %d, grp_scalar_write = %d, " + fprintf (f, ", grp_read = %d, grp_write = %d, grp_assignment_read = %d, " + "grp_assignment_write = %d, grp_scalar_read = %d, " + "grp_scalar_write = %d, grp_total_scalarization = %d, " "grp_hint = %d, grp_covered = %d, " "grp_unscalarizable_region = %d, grp_unscalarized_data = %d, " "grp_partial_lhs = %d, grp_to_be_replaced = %d, " "grp_maybe_modified = %d, " "grp_not_necessarilly_dereferenced = %d\n", - access->total_scalarization, access->grp_read, access->grp_write, - access->grp_assignment_read, access->grp_assignment_write, - access->grp_scalar_read, access->grp_scalar_write, + access->grp_read, access->grp_write, access->grp_assignment_read, + access->grp_assignment_write, access->grp_scalar_read, + access->grp_scalar_write, access->grp_total_scalarization, access->grp_hint, access->grp_covered, access->grp_unscalarizable_region, access->grp_unscalarized_data, access->grp_partial_lhs, access->grp_to_be_replaced, access->grp_maybe_modified, access->grp_not_necessarilly_dereferenced); else - fprintf (f, ", write = %d, total_scalarization = %d, " + fprintf (f, ", write = %d, grp_total_scalarization = %d, " "grp_partial_lhs = %d\n", - access->write, access->total_scalarization, + access->write, access->grp_total_scalarization, access->grp_partial_lhs); } @@ -924,7 +924,7 @@ completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset, access = create_access_1 (base, pos, size); access->expr = nref; access->type = ft; - access->total_scalarization = 1; + access->grp_total_scalarization = 1; /* Accesses for intraprocedural SRA can have their stmt NULL. */ } else @@ -932,6 +932,23 @@ completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset, } } +/* Create total_scalarization accesses for all scalar type fields in VAR and + for VAR a a whole. VAR must be of a RECORD_TYPE conforming to + type_consists_of_records_p. */ + +static void +completely_scalarize_var (tree var) +{ + HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (var), 1); + struct access *access; + + access = create_access_1 (var, 0, size); + access->expr = var; + access->type = TREE_TYPE (var); + access->grp_total_scalarization = 1; + + completely_scalarize_record (var, var, 0, var); +} /* Search the given tree for a declaration by skipping handled components and exclude it from the candidates. */ @@ -1059,6 +1076,7 @@ tree_non_mode_aligned_mem_p (tree exp) unsigned int align; if (TREE_CODE (exp) == SSA_NAME + || TREE_CODE (exp) == MEM_REF || mode == BLKmode || !STRICT_ALIGNMENT) return false; @@ -1714,7 +1732,7 @@ sort_and_splice_var_accesses (tree var) bool grp_assignment_read = access->grp_assignment_read; bool grp_assignment_write = access->grp_assignment_write; bool multiple_scalar_reads = false; - bool total_scalarization = access->total_scalarization; + bool total_scalarization = access->grp_total_scalarization; bool grp_partial_lhs = access->grp_partial_lhs; bool first_scalar = is_gimple_reg_type (access->type); bool unscalarizable_region = access->grp_unscalarizable_region; @@ -1758,7 +1776,7 @@ sort_and_splice_var_accesses (tree var) grp_assignment_write |= ac2->grp_assignment_write; grp_partial_lhs |= ac2->grp_partial_lhs; unscalarizable_region |= ac2->grp_unscalarizable_region; - total_scalarization |= ac2->total_scalarization; + total_scalarization |= ac2->grp_total_scalarization; relink_to_new_repr (access, ac2); /* If there are both aggregate-type and scalar-type accesses with @@ -1779,6 +1797,7 @@ sort_and_splice_var_accesses (tree var) access->grp_assignment_read = grp_assignment_read; access->grp_assignment_write = grp_assignment_write; access->grp_hint = multiple_scalar_reads || total_scalarization; + access->grp_total_scalarization = total_scalarization; access->grp_partial_lhs = grp_partial_lhs; access->grp_unscalarizable_region = unscalarizable_region; if (access->first_link) @@ -2024,6 +2043,8 @@ analyze_access_subtree (struct access *root, struct access *parent, root->grp_write = 1; if (parent->grp_assignment_write) root->grp_assignment_write = 1; + if (parent->grp_total_scalarization) + root->grp_total_scalarization = 1; } if (root->grp_unscalarizable_region) @@ -2034,16 +2055,16 @@ analyze_access_subtree (struct access *root, struct access *parent, for (child = root->first_child; child; child = child->next_sibling) { - if (!hole && child->offset < covered_to) - hole = true; - else - covered_to += child->size; - + hole |= covered_to < child->offset; sth_created |= analyze_access_subtree (child, root, allow_replacements && !scalar); root->grp_unscalarized_data |= child->grp_unscalarized_data; - hole |= !child->grp_covered; + root->grp_total_scalarization &= child->grp_total_scalarization; + if (child->grp_covered) + covered_to += child->size; + else + hole = true; } if (allow_replacements && scalar && !root->first_child @@ -2064,10 +2085,16 @@ analyze_access_subtree (struct access *root, struct access *parent, sth_created = true; hole = false; } - else if (covered_to < limit) - hole = true; + else + { + if (covered_to < limit) + hole = true; + if (scalar) + root->grp_total_scalarization = 0; + } - if (sth_created && !hole) + if (sth_created + && (!hole || root->grp_total_scalarization)) { root->grp_covered = 1; return true; @@ -2289,7 +2316,7 @@ analyze_all_variable_accesses (void) <= max_total_scalarization_size) && type_consists_of_records_p (TREE_TYPE (var))) { - completely_scalarize_record (var, var, 0, var); + completely_scalarize_var (var); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Will attempt to totally scalarize "); diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index bbfe0bc8338..7a00c8ad937 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -208,13 +208,11 @@ initialize_hash_element (gimple stmt, tree lhs, { enum tree_code subcode = gimple_assign_rhs_code (stmt); - expr->type = NULL_TREE; - switch (get_gimple_rhs_class (subcode)) { case GIMPLE_SINGLE_RHS: expr->kind = EXPR_SINGLE; - expr->type = TREE_TYPE (gimple_assign_lhs (stmt)); + expr->type = TREE_TYPE (gimple_assign_rhs1 (stmt)); expr->ops.single.rhs = gimple_assign_rhs1 (stmt); break; case GIMPLE_UNARY_RHS: diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index e93acdfc081..893f17b47a4 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -1675,7 +1675,7 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi) /* Try to fold (type) X op CST -> (type) (X op ((type-x) CST)). */ if (TREE_CODE (arg2) == INTEGER_CST && CONVERT_EXPR_CODE_P (def1_code) - && INTEGRAL_TYPE_P (def1_arg1) + && INTEGRAL_TYPE_P (TREE_TYPE (def1_arg1)) && int_fits_type_p (arg2, TREE_TYPE (def1_arg1))) { gimple newop; diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 0352607732b..63b346979af 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -1823,6 +1823,7 @@ vect_is_slp_reduction (loop_vec_info loop_info, gimple phi, gimple first_stmt) ("vect_internal_def"), or it's an induction (defined by a loop-header phi-node). */ if (def_stmt + && gimple_bb (def_stmt) && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)) && (is_gimple_assign (def_stmt) || is_gimple_call (def_stmt) @@ -1852,6 +1853,7 @@ vect_is_slp_reduction (loop_vec_info loop_info, gimple phi, gimple first_stmt) ("vect_internal_def"), or it's an induction (defined by a loop-header phi-node). */ if (def_stmt + && gimple_bb (def_stmt) && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)) && (is_gimple_assign (def_stmt) || is_gimple_call (def_stmt) diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 0d7d3dbe41d..9a384c5cfa3 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -4574,19 +4574,14 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, /* 4. Handle invariant-load. */ if (inv_p && !bb_vinfo) { + tree vec_inv; + gimple_stmt_iterator gsi2 = *gsi; gcc_assert (!strided_load); - if (j == 0) - { - tree vec_inv; - gimple_stmt_iterator gsi2 = *gsi; - gsi_next (&gsi2); - vec_inv = build_vector_from_val (vectype, scalar_dest); - new_temp = vect_init_vector (stmt, vec_inv, - vectype, &gsi2); - new_stmt = SSA_NAME_DEF_STMT (new_temp); - } - else - gcc_unreachable (); /* FORNOW. */ + gsi_next (&gsi2); + vec_inv = build_vector_from_val (vectype, scalar_dest); + new_temp = vect_init_vector (stmt, vec_inv, + vectype, &gsi2); + new_stmt = SSA_NAME_DEF_STMT (new_temp); } if (negative) diff --git a/gcc/tree.h b/gcc/tree.h index 20ba295a219..ab0b6cc66c6 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -699,6 +699,9 @@ struct GTY(()) tree_common { all expressions all decls + TYPE_ARTIFICIAL in + all types + default_def_flag: TYPE_VECTOR_OPAQUE in @@ -1243,6 +1246,9 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, emitted. */ #define TREE_NO_WARNING(NODE) ((NODE)->base.nowarning_flag) +/* Used to indicate that this TYPE represents a compiler-generated entity. */ +#define TYPE_ARTIFICIAL(NODE) (TYPE_CHECK (NODE)->base.nowarning_flag) + /* In an IDENTIFIER_NODE, this means that assemble_name was called with this string as an argument. */ #define TREE_SYMBOL_REFERENCED(NODE) \ |