From 34f64dab4829227378994f1a7f8d60d13eb33652 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Fri, 9 Apr 2021 16:34:40 +0200 Subject: gcc: fix sparc toolchain, patch from buildroot --- toolchain/gcc/patches/10.3.0/revert-sparc.patch | 23628 ++++++++++++++++++++++ 1 file changed, 23628 insertions(+) create mode 100644 toolchain/gcc/patches/10.3.0/revert-sparc.patch (limited to 'toolchain/gcc') diff --git a/toolchain/gcc/patches/10.3.0/revert-sparc.patch b/toolchain/gcc/patches/10.3.0/revert-sparc.patch new file mode 100644 index 000000000..5df11ce40 --- /dev/null +++ b/toolchain/gcc/patches/10.3.0/revert-sparc.patch @@ -0,0 +1,23628 @@ +diff -Nur gcc-10.3.0.orig/gcc/config/sparc/sparc.c gcc-10.3.0/gcc/config/sparc/sparc.c +--- gcc-10.3.0.orig/gcc/config/sparc/sparc.c 2021-04-08 13:56:28.201742273 +0200 ++++ gcc-10.3.0/gcc/config/sparc/sparc.c 2021-04-09 07:51:37.884501308 +0200 +@@ -4157,6 +4157,13 @@ + static bool + sparc_cannot_force_const_mem (machine_mode mode, rtx x) + { ++ /* After IRA has run in PIC mode, it is too late to put anything into the ++ constant pool if the PIC register hasn't already been initialized. */ ++ if ((lra_in_progress || reload_in_progress) ++ && flag_pic ++ && !crtl->uses_pic_offset_table) ++ return true; ++ + switch (GET_CODE (x)) + { + case CONST_INT: +@@ -4192,11 +4199,9 @@ + } + + /* Global Offset Table support. */ +-static GTY(()) rtx got_symbol_rtx = NULL_RTX; +-static GTY(()) rtx got_register_rtx = NULL_RTX; + static GTY(()) rtx got_helper_rtx = NULL_RTX; +- +-static GTY(()) bool got_helper_needed = false; ++static GTY(()) rtx got_register_rtx = NULL_RTX; ++static GTY(()) rtx got_symbol_rtx = NULL_RTX; + + /* Return the SYMBOL_REF for the Global Offset Table. */ + +@@ -4209,6 +4214,27 @@ + return got_symbol_rtx; + } + ++#ifdef HAVE_GAS_HIDDEN ++# define USE_HIDDEN_LINKONCE 1 ++#else ++# define USE_HIDDEN_LINKONCE 0 ++#endif ++ ++static void ++get_pc_thunk_name (char name[32], unsigned int regno) ++{ ++ const char *reg_name = reg_names[regno]; ++ ++ /* Skip the leading '%' as that cannot be used in a ++ symbol name. */ ++ reg_name += 1; ++ ++ if (USE_HIDDEN_LINKONCE) ++ sprintf (name, "__sparc_get_pc_thunk.%s", reg_name); ++ else ++ ASM_GENERATE_INTERNAL_LABEL (name, "LADDPC", regno); ++} ++ + /* Wrapper around the load_pcrel_sym{si,di} patterns. */ + + static rtx +@@ -4228,78 +4254,30 @@ + return insn; + } + +-/* Output the load_pcrel_sym{si,di} patterns. */ +- +-const char * +-output_load_pcrel_sym (rtx *operands) +-{ +- if (flag_delayed_branch) +- { +- output_asm_insn ("sethi\t%%hi(%a1-4), %0", operands); +- output_asm_insn ("call\t%a2", operands); +- output_asm_insn (" add\t%0, %%lo(%a1+4), %0", operands); +- } +- else +- { +- output_asm_insn ("sethi\t%%hi(%a1-8), %0", operands); +- output_asm_insn ("add\t%0, %%lo(%a1-4), %0", operands); +- output_asm_insn ("call\t%a2", operands); +- output_asm_insn (" nop", NULL); +- } +- +- if (operands[2] == got_helper_rtx) +- got_helper_needed = true; +- +- return ""; +-} +- +-#ifdef HAVE_GAS_HIDDEN +-# define USE_HIDDEN_LINKONCE 1 +-#else +-# define USE_HIDDEN_LINKONCE 0 +-#endif +- + /* Emit code to load the GOT register. */ + + void + load_got_register (void) + { +- rtx insn; ++ if (!got_register_rtx) ++ got_register_rtx = gen_rtx_REG (Pmode, GLOBAL_OFFSET_TABLE_REGNUM); + + if (TARGET_VXWORKS_RTP) +- { +- if (!got_register_rtx) +- got_register_rtx = pic_offset_table_rtx; +- +- insn = gen_vxworks_load_got (); +- } ++ emit_insn (gen_vxworks_load_got ()); + else + { +- if (!got_register_rtx) +- got_register_rtx = gen_rtx_REG (Pmode, GLOBAL_OFFSET_TABLE_REGNUM); +- + /* The GOT symbol is subject to a PC-relative relocation so we need a + helper function to add the PC value and thus get the final value. */ + if (!got_helper_rtx) + { + char name[32]; +- +- /* Skip the leading '%' as that cannot be used in a symbol name. */ +- if (USE_HIDDEN_LINKONCE) +- sprintf (name, "__sparc_get_pc_thunk.%s", +- reg_names[REGNO (got_register_rtx)] + 1); +- else +- ASM_GENERATE_INTERNAL_LABEL (name, "LADDPC", +- REGNO (got_register_rtx)); +- ++ get_pc_thunk_name (name, GLOBAL_OFFSET_TABLE_REGNUM); + got_helper_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); + } + +- insn +- = gen_load_pcrel_sym (got_register_rtx, sparc_got (), got_helper_rtx); ++ emit_insn (gen_load_pcrel_sym (got_register_rtx, sparc_got (), ++ got_helper_rtx)); + } +- +- emit_insn (insn); + } + + /* Ensure that we are not using patterns that are not OK with PIC. */ +@@ -5464,7 +5442,7 @@ + return true; + + /* GOT register (%l7) if needed. */ +- if (got_register_rtx && regno == REGNO (got_register_rtx)) ++ if (regno == GLOBAL_OFFSET_TABLE_REGNUM && got_register_rtx) + return true; + + /* If the function accesses prior frames, the frame pointer and the return +@@ -12507,9 +12485,10 @@ + sparc_file_end (void) + { + /* If we need to emit the special GOT helper function, do so now. */ +- if (got_helper_needed) ++ if (got_helper_rtx) + { + const char *name = XSTR (got_helper_rtx, 0); ++ const char *reg_name = reg_names[GLOBAL_OFFSET_TABLE_REGNUM]; + #ifdef DWARF2_UNWIND_INFO + bool do_cfi; + #endif +@@ -12546,22 +12525,17 @@ + #ifdef DWARF2_UNWIND_INFO + do_cfi = dwarf2out_do_cfi_asm (); + if (do_cfi) +- output_asm_insn (".cfi_startproc", NULL); ++ fprintf (asm_out_file, "\t.cfi_startproc\n"); + #endif + if (flag_delayed_branch) +- { +- output_asm_insn ("jmp\t%%o7+8", NULL); +- output_asm_insn (" add\t%%o7, %0, %0", &got_register_rtx); +- } ++ fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n", ++ reg_name, reg_name); + else +- { +- output_asm_insn ("add\t%%o7, %0, %0", &got_register_rtx); +- output_asm_insn ("jmp\t%%o7+8", NULL); +- output_asm_insn (" nop", NULL); +- } ++ fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n", ++ reg_name, reg_name); + #ifdef DWARF2_UNWIND_INFO + if (do_cfi) +- output_asm_insn (".cfi_endproc", NULL); ++ fprintf (asm_out_file, "\t.cfi_endproc\n"); + #endif + } + +@@ -13056,10 +13030,7 @@ + edge entry_edge; + rtx_insn *seq; + +- /* In PIC mode, we need to always initialize the PIC register if optimization +- is enabled, because we are called from IRA and LRA may later force things +- to the constant pool for optimization purposes. */ +- if (!flag_pic || (!crtl->uses_pic_offset_table && !optimize)) ++ if (!crtl->uses_pic_offset_table) + return; + + start_sequence (); +diff -Nur gcc-10.3.0.orig/gcc/config/sparc/sparc.c.orig gcc-10.3.0/gcc/config/sparc/sparc.c.orig +--- gcc-10.3.0.orig/gcc/config/sparc/sparc.c.orig 1970-01-01 01:00:00.000000000 +0100 ++++ gcc-10.3.0/gcc/config/sparc/sparc.c.orig 2021-04-08 13:56:28.201742273 +0200 +@@ -0,0 +1,13813 @@ ++/* Subroutines for insn-output.c for SPARC. ++ Copyright (C) 1987-2020 Free Software Foundation, Inc. ++ Contributed by Michael Tiemann (tiemann@cygnus.com) ++ 64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans, ++ at Cygnus Support. ++ ++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 ++. */ ++ ++#define IN_TARGET_CODE 1 ++ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "backend.h" ++#include "target.h" ++#include "rtl.h" ++#include "tree.h" ++#include "memmodel.h" ++#include "gimple.h" ++#include "df.h" ++#include "tm_p.h" ++#include "stringpool.h" ++#include "attribs.h" ++#include "expmed.h" ++#include "optabs.h" ++#include "regs.h" ++#include "emit-rtl.h" ++#include "recog.h" ++#include "diagnostic-core.h" ++#include "alias.h" ++#include "fold-const.h" ++#include "stor-layout.h" ++#include "calls.h" ++#include "varasm.h" ++#include "output.h" ++#include "insn-attr.h" ++#include "explow.h" ++#include "expr.h" ++#include "debug.h" ++#include "cfgrtl.h" ++#include "common/common-target.h" ++#include "gimplify.h" ++#include "langhooks.h" ++#include "reload.h" ++#include "tree-pass.h" ++#include "context.h" ++#include "builtins.h" ++#include "tree-vector-builder.h" ++#include "opts.h" ++ ++/* This file should be included last. */ ++#include "target-def.h" ++ ++/* Processor costs */ ++ ++struct processor_costs { ++ /* Integer load */ ++ const int int_load; ++ ++ /* Integer signed load */ ++ const int int_sload; ++ ++ /* Integer zeroed load */ ++ const int int_zload; ++ ++ /* Float load */ ++ const int float_load; ++ ++ /* fmov, fneg, fabs */ ++ const int float_move; ++ ++ /* fadd, fsub */ ++ const int float_plusminus; ++ ++ /* fcmp */ ++ const int float_cmp; ++ ++ /* fmov, fmovr */ ++ const int float_cmove; ++ ++ /* fmul */ ++ const int float_mul; ++ ++ /* fdivs */ ++ const int float_div_sf; ++ ++ /* fdivd */ ++ const int float_div_df; ++ ++ /* fsqrts */ ++ const int float_sqrt_sf; ++ ++ /* fsqrtd */ ++ const int float_sqrt_df; ++ ++ /* umul/smul */ ++ const int int_mul; ++ ++ /* mulX */ ++ const int int_mulX; ++ ++ /* integer multiply cost for each bit set past the most ++ significant 3, so the formula for multiply cost becomes: ++ ++ if (rs1 < 0) ++ highest_bit = highest_clear_bit(rs1); ++ else ++ highest_bit = highest_set_bit(rs1); ++ if (highest_bit < 3) ++ highest_bit = 3; ++ cost = int_mul{,X} + ((highest_bit - 3) / int_mul_bit_factor); ++ ++ A value of zero indicates that the multiply costs is fixed, ++ and not variable. */ ++ const int int_mul_bit_factor; ++ ++ /* udiv/sdiv */ ++ const int int_div; ++ ++ /* divX */ ++ const int int_divX; ++ ++ /* movcc, movr */ ++ const int int_cmove; ++ ++ /* penalty for shifts, due to scheduling rules etc. */ ++ const int shift_penalty; ++ ++ /* cost of a (predictable) branch. */ ++ const int branch_cost; ++}; ++ ++static const ++struct processor_costs cypress_costs = { ++ COSTS_N_INSNS (2), /* int load */ ++ COSTS_N_INSNS (2), /* int signed load */ ++ COSTS_N_INSNS (2), /* int zeroed load */ ++ COSTS_N_INSNS (2), /* float load */ ++ COSTS_N_INSNS (5), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (5), /* fadd, fsub */ ++ COSTS_N_INSNS (1), /* fcmp */ ++ COSTS_N_INSNS (1), /* fmov, fmovr */ ++ COSTS_N_INSNS (7), /* fmul */ ++ COSTS_N_INSNS (37), /* fdivs */ ++ COSTS_N_INSNS (37), /* fdivd */ ++ COSTS_N_INSNS (63), /* fsqrts */ ++ COSTS_N_INSNS (63), /* fsqrtd */ ++ COSTS_N_INSNS (1), /* imul */ ++ COSTS_N_INSNS (1), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (1), /* idiv */ ++ COSTS_N_INSNS (1), /* idivX */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 3 /* branch cost */ ++}; ++ ++static const ++struct processor_costs supersparc_costs = { ++ COSTS_N_INSNS (1), /* int load */ ++ COSTS_N_INSNS (1), /* int signed load */ ++ COSTS_N_INSNS (1), /* int zeroed load */ ++ COSTS_N_INSNS (0), /* float load */ ++ COSTS_N_INSNS (3), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (3), /* fadd, fsub */ ++ COSTS_N_INSNS (3), /* fcmp */ ++ COSTS_N_INSNS (1), /* fmov, fmovr */ ++ COSTS_N_INSNS (3), /* fmul */ ++ COSTS_N_INSNS (6), /* fdivs */ ++ COSTS_N_INSNS (9), /* fdivd */ ++ COSTS_N_INSNS (12), /* fsqrts */ ++ COSTS_N_INSNS (12), /* fsqrtd */ ++ COSTS_N_INSNS (4), /* imul */ ++ COSTS_N_INSNS (4), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (4), /* idiv */ ++ COSTS_N_INSNS (4), /* idivX */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 1, /* shift penalty */ ++ 3 /* branch cost */ ++}; ++ ++static const ++struct processor_costs hypersparc_costs = { ++ COSTS_N_INSNS (1), /* int load */ ++ COSTS_N_INSNS (1), /* int signed load */ ++ COSTS_N_INSNS (1), /* int zeroed load */ ++ COSTS_N_INSNS (1), /* float load */ ++ COSTS_N_INSNS (1), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (1), /* fadd, fsub */ ++ COSTS_N_INSNS (1), /* fcmp */ ++ COSTS_N_INSNS (1), /* fmov, fmovr */ ++ COSTS_N_INSNS (1), /* fmul */ ++ COSTS_N_INSNS (8), /* fdivs */ ++ COSTS_N_INSNS (12), /* fdivd */ ++ COSTS_N_INSNS (17), /* fsqrts */ ++ COSTS_N_INSNS (17), /* fsqrtd */ ++ COSTS_N_INSNS (17), /* imul */ ++ COSTS_N_INSNS (17), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (17), /* idiv */ ++ COSTS_N_INSNS (17), /* idivX */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 3 /* branch cost */ ++}; ++ ++static const ++struct processor_costs leon_costs = { ++ COSTS_N_INSNS (1), /* int load */ ++ COSTS_N_INSNS (1), /* int signed load */ ++ COSTS_N_INSNS (1), /* int zeroed load */ ++ COSTS_N_INSNS (1), /* float load */ ++ COSTS_N_INSNS (1), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (1), /* fadd, fsub */ ++ COSTS_N_INSNS (1), /* fcmp */ ++ COSTS_N_INSNS (1), /* fmov, fmovr */ ++ COSTS_N_INSNS (1), /* fmul */ ++ COSTS_N_INSNS (15), /* fdivs */ ++ COSTS_N_INSNS (15), /* fdivd */ ++ COSTS_N_INSNS (23), /* fsqrts */ ++ COSTS_N_INSNS (23), /* fsqrtd */ ++ COSTS_N_INSNS (5), /* imul */ ++ COSTS_N_INSNS (5), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (5), /* idiv */ ++ COSTS_N_INSNS (5), /* idivX */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 3 /* branch cost */ ++}; ++ ++static const ++struct processor_costs leon3_costs = { ++ COSTS_N_INSNS (1), /* int load */ ++ COSTS_N_INSNS (1), /* int signed load */ ++ COSTS_N_INSNS (1), /* int zeroed load */ ++ COSTS_N_INSNS (1), /* float load */ ++ COSTS_N_INSNS (1), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (1), /* fadd, fsub */ ++ COSTS_N_INSNS (1), /* fcmp */ ++ COSTS_N_INSNS (1), /* fmov, fmovr */ ++ COSTS_N_INSNS (1), /* fmul */ ++ COSTS_N_INSNS (14), /* fdivs */ ++ COSTS_N_INSNS (15), /* fdivd */ ++ COSTS_N_INSNS (22), /* fsqrts */ ++ COSTS_N_INSNS (23), /* fsqrtd */ ++ COSTS_N_INSNS (5), /* imul */ ++ COSTS_N_INSNS (5), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (35), /* idiv */ ++ COSTS_N_INSNS (35), /* idivX */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 3 /* branch cost */ ++}; ++ ++static const ++struct processor_costs sparclet_costs = { ++ COSTS_N_INSNS (3), /* int load */ ++ COSTS_N_INSNS (3), /* int signed load */ ++ COSTS_N_INSNS (1), /* int zeroed load */ ++ COSTS_N_INSNS (1), /* float load */ ++ COSTS_N_INSNS (1), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (1), /* fadd, fsub */ ++ COSTS_N_INSNS (1), /* fcmp */ ++ COSTS_N_INSNS (1), /* fmov, fmovr */ ++ COSTS_N_INSNS (1), /* fmul */ ++ COSTS_N_INSNS (1), /* fdivs */ ++ COSTS_N_INSNS (1), /* fdivd */ ++ COSTS_N_INSNS (1), /* fsqrts */ ++ COSTS_N_INSNS (1), /* fsqrtd */ ++ COSTS_N_INSNS (5), /* imul */ ++ COSTS_N_INSNS (5), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (5), /* idiv */ ++ COSTS_N_INSNS (5), /* idivX */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 3 /* branch cost */ ++}; ++ ++static const ++struct processor_costs ultrasparc_costs = { ++ COSTS_N_INSNS (2), /* int load */ ++ COSTS_N_INSNS (3), /* int signed load */ ++ COSTS_N_INSNS (2), /* int zeroed load */ ++ COSTS_N_INSNS (2), /* float load */ ++ COSTS_N_INSNS (1), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (4), /* fadd, fsub */ ++ COSTS_N_INSNS (1), /* fcmp */ ++ COSTS_N_INSNS (2), /* fmov, fmovr */ ++ COSTS_N_INSNS (4), /* fmul */ ++ COSTS_N_INSNS (13), /* fdivs */ ++ COSTS_N_INSNS (23), /* fdivd */ ++ COSTS_N_INSNS (13), /* fsqrts */ ++ COSTS_N_INSNS (23), /* fsqrtd */ ++ COSTS_N_INSNS (4), /* imul */ ++ COSTS_N_INSNS (4), /* imulX */ ++ 2, /* imul bit factor */ ++ COSTS_N_INSNS (37), /* idiv */ ++ COSTS_N_INSNS (68), /* idivX */ ++ COSTS_N_INSNS (2), /* movcc/movr */ ++ 2, /* shift penalty */ ++ 2 /* branch cost */ ++}; ++ ++static const ++struct processor_costs ultrasparc3_costs = { ++ COSTS_N_INSNS (2), /* int load */ ++ COSTS_N_INSNS (3), /* int signed load */ ++ COSTS_N_INSNS (3), /* int zeroed load */ ++ COSTS_N_INSNS (2), /* float load */ ++ COSTS_N_INSNS (3), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (4), /* fadd, fsub */ ++ COSTS_N_INSNS (5), /* fcmp */ ++ COSTS_N_INSNS (3), /* fmov, fmovr */ ++ COSTS_N_INSNS (4), /* fmul */ ++ COSTS_N_INSNS (17), /* fdivs */ ++ COSTS_N_INSNS (20), /* fdivd */ ++ COSTS_N_INSNS (20), /* fsqrts */ ++ COSTS_N_INSNS (29), /* fsqrtd */ ++ COSTS_N_INSNS (6), /* imul */ ++ COSTS_N_INSNS (6), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (40), /* idiv */ ++ COSTS_N_INSNS (71), /* idivX */ ++ COSTS_N_INSNS (2), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 2 /* branch cost */ ++}; ++ ++static const ++struct processor_costs niagara_costs = { ++ COSTS_N_INSNS (3), /* int load */ ++ COSTS_N_INSNS (3), /* int signed load */ ++ COSTS_N_INSNS (3), /* int zeroed load */ ++ COSTS_N_INSNS (9), /* float load */ ++ COSTS_N_INSNS (8), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (8), /* fadd, fsub */ ++ COSTS_N_INSNS (26), /* fcmp */ ++ COSTS_N_INSNS (8), /* fmov, fmovr */ ++ COSTS_N_INSNS (29), /* fmul */ ++ COSTS_N_INSNS (54), /* fdivs */ ++ COSTS_N_INSNS (83), /* fdivd */ ++ COSTS_N_INSNS (100), /* fsqrts - not implemented in hardware */ ++ COSTS_N_INSNS (100), /* fsqrtd - not implemented in hardware */ ++ COSTS_N_INSNS (11), /* imul */ ++ COSTS_N_INSNS (11), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (72), /* idiv */ ++ COSTS_N_INSNS (72), /* idivX */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 4 /* branch cost */ ++}; ++ ++static const ++struct processor_costs niagara2_costs = { ++ COSTS_N_INSNS (3), /* int load */ ++ COSTS_N_INSNS (3), /* int signed load */ ++ COSTS_N_INSNS (3), /* int zeroed load */ ++ COSTS_N_INSNS (3), /* float load */ ++ COSTS_N_INSNS (6), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (6), /* fadd, fsub */ ++ COSTS_N_INSNS (6), /* fcmp */ ++ COSTS_N_INSNS (6), /* fmov, fmovr */ ++ COSTS_N_INSNS (6), /* fmul */ ++ COSTS_N_INSNS (19), /* fdivs */ ++ COSTS_N_INSNS (33), /* fdivd */ ++ COSTS_N_INSNS (19), /* fsqrts */ ++ COSTS_N_INSNS (33), /* fsqrtd */ ++ COSTS_N_INSNS (5), /* imul */ ++ COSTS_N_INSNS (5), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (26), /* idiv, average of 12 - 41 cycle range */ ++ COSTS_N_INSNS (26), /* idivX, average of 12 - 41 cycle range */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 5 /* branch cost */ ++}; ++ ++static const ++struct processor_costs niagara3_costs = { ++ COSTS_N_INSNS (3), /* int load */ ++ COSTS_N_INSNS (3), /* int signed load */ ++ COSTS_N_INSNS (3), /* int zeroed load */ ++ COSTS_N_INSNS (3), /* float load */ ++ COSTS_N_INSNS (9), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (9), /* fadd, fsub */ ++ COSTS_N_INSNS (9), /* fcmp */ ++ COSTS_N_INSNS (9), /* fmov, fmovr */ ++ COSTS_N_INSNS (9), /* fmul */ ++ COSTS_N_INSNS (23), /* fdivs */ ++ COSTS_N_INSNS (37), /* fdivd */ ++ COSTS_N_INSNS (23), /* fsqrts */ ++ COSTS_N_INSNS (37), /* fsqrtd */ ++ COSTS_N_INSNS (9), /* imul */ ++ COSTS_N_INSNS (9), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (31), /* idiv, average of 17 - 45 cycle range */ ++ COSTS_N_INSNS (30), /* idivX, average of 16 - 44 cycle range */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 5 /* branch cost */ ++}; ++ ++static const ++struct processor_costs niagara4_costs = { ++ COSTS_N_INSNS (5), /* int load */ ++ COSTS_N_INSNS (5), /* int signed load */ ++ COSTS_N_INSNS (5), /* int zeroed load */ ++ COSTS_N_INSNS (5), /* float load */ ++ COSTS_N_INSNS (11), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (11), /* fadd, fsub */ ++ COSTS_N_INSNS (11), /* fcmp */ ++ COSTS_N_INSNS (11), /* fmov, fmovr */ ++ COSTS_N_INSNS (11), /* fmul */ ++ COSTS_N_INSNS (24), /* fdivs */ ++ COSTS_N_INSNS (37), /* fdivd */ ++ COSTS_N_INSNS (24), /* fsqrts */ ++ COSTS_N_INSNS (37), /* fsqrtd */ ++ COSTS_N_INSNS (12), /* imul */ ++ COSTS_N_INSNS (12), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (50), /* idiv, average of 41 - 60 cycle range */ ++ COSTS_N_INSNS (35), /* idivX, average of 26 - 44 cycle range */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 2 /* branch cost */ ++}; ++ ++static const ++struct processor_costs niagara7_costs = { ++ COSTS_N_INSNS (5), /* int load */ ++ COSTS_N_INSNS (5), /* int signed load */ ++ COSTS_N_INSNS (5), /* int zeroed load */ ++ COSTS_N_INSNS (5), /* float load */ ++ COSTS_N_INSNS (11), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (11), /* fadd, fsub */ ++ COSTS_N_INSNS (11), /* fcmp */ ++ COSTS_N_INSNS (11), /* fmov, fmovr */ ++ COSTS_N_INSNS (11), /* fmul */ ++ COSTS_N_INSNS (24), /* fdivs */ ++ COSTS_N_INSNS (37), /* fdivd */ ++ COSTS_N_INSNS (24), /* fsqrts */ ++ COSTS_N_INSNS (37), /* fsqrtd */ ++ COSTS_N_INSNS (12), /* imul */ ++ COSTS_N_INSNS (12), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (51), /* idiv, average of 42 - 61 cycle range */ ++ COSTS_N_INSNS (35), /* idivX, average of 26 - 44 cycle range */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 1 /* branch cost */ ++}; ++ ++static const ++struct processor_costs m8_costs = { ++ COSTS_N_INSNS (3), /* int load */ ++ COSTS_N_INSNS (3), /* int signed load */ ++ COSTS_N_INSNS (3), /* int zeroed load */ ++ COSTS_N_INSNS (3), /* float load */ ++ COSTS_N_INSNS (9), /* fmov, fneg, fabs */ ++ COSTS_N_INSNS (9), /* fadd, fsub */ ++ COSTS_N_INSNS (9), /* fcmp */ ++ COSTS_N_INSNS (9), /* fmov, fmovr */ ++ COSTS_N_INSNS (9), /* fmul */ ++ COSTS_N_INSNS (26), /* fdivs */ ++ COSTS_N_INSNS (30), /* fdivd */ ++ COSTS_N_INSNS (33), /* fsqrts */ ++ COSTS_N_INSNS (41), /* fsqrtd */ ++ COSTS_N_INSNS (12), /* imul */ ++ COSTS_N_INSNS (10), /* imulX */ ++ 0, /* imul bit factor */ ++ COSTS_N_INSNS (57), /* udiv/sdiv */ ++ COSTS_N_INSNS (30), /* udivx/sdivx */ ++ COSTS_N_INSNS (1), /* movcc/movr */ ++ 0, /* shift penalty */ ++ 1 /* branch cost */ ++}; ++ ++static const struct processor_costs *sparc_costs = &cypress_costs; ++ ++#ifdef HAVE_AS_RELAX_OPTION ++/* If 'as' and 'ld' are relaxing tail call insns into branch always, use ++ "or %o7,%g0,X; call Y; or X,%g0,%o7" always, so that it can be optimized. ++ With sethi/jmp, neither 'as' nor 'ld' has an easy way how to find out if ++ somebody does not branch between the sethi and jmp. */ ++#define LEAF_SIBCALL_SLOT_RESERVED_P 1 ++#else ++#define LEAF_SIBCALL_SLOT_RESERVED_P \ ++ ((TARGET_ARCH64 && !TARGET_CM_MEDLOW) || flag_pic) ++#endif ++ ++/* Vector to say how input registers are mapped to output registers. ++ HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to ++ eliminate it. You must use -fomit-frame-pointer to get that. */ ++char leaf_reg_remap[] = ++{ 0, 1, 2, 3, 4, 5, 6, 7, ++ -1, -1, -1, -1, -1, -1, 14, -1, ++ -1, -1, -1, -1, -1, -1, -1, -1, ++ 8, 9, 10, 11, 12, 13, -1, 15, ++ ++ 32, 33, 34, 35, 36, 37, 38, 39, ++ 40, 41, 42, 43, 44, 45, 46, 47, ++ 48, 49, 50, 51, 52, 53, 54, 55, ++ 56, 57, 58, 59, 60, 61, 62, 63, ++ 64, 65, 66, 67, 68, 69, 70, 71, ++ 72, 73, 74, 75, 76, 77, 78, 79, ++ 80, 81, 82, 83, 84, 85, 86, 87, ++ 88, 89, 90, 91, 92, 93, 94, 95, ++ 96, 97, 98, 99, 100, 101, 102}; ++ ++/* Vector, indexed by hard register number, which contains 1 ++ for a register that is allowable in a candidate for leaf ++ function treatment. */ ++char sparc_leaf_regs[] = ++{ 1, 1, 1, 1, 1, 1, 1, 1, ++ 0, 0, 0, 0, 0, 0, 1, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ 1, 1, 1, 1, 1, 1, 0, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1}; ++ ++struct GTY(()) machine_function ++{ ++ /* Size of the frame of the function. */ ++ HOST_WIDE_INT frame_size; ++ ++ /* Size of the frame of the function minus the register window save area ++ and the outgoing argument area. */ ++ HOST_WIDE_INT apparent_frame_size; ++ ++ /* Register we pretend the frame pointer is allocated to. Normally, this ++ is %fp, but if we are in a leaf procedure, this is (%sp + offset). We ++ record "offset" separately as it may be too big for (reg + disp). */ ++ rtx frame_base_reg; ++ HOST_WIDE_INT frame_base_offset; ++ ++ /* Number of global or FP registers to be saved (as 4-byte quantities). */ ++ int n_global_fp_regs; ++ ++ /* True if the current function is leaf and uses only leaf regs, ++ so that the SPARC leaf function optimization can be applied. ++ Private version of crtl->uses_only_leaf_regs, see ++ sparc_expand_prologue for the rationale. */ ++ int leaf_function_p; ++ ++ /* True if the prologue saves local or in registers. */ ++ bool save_local_in_regs_p; ++ ++ /* True if the data calculated by sparc_expand_prologue are valid. */ ++ bool prologue_data_valid_p; ++}; ++ ++#define sparc_frame_size cfun->machine->frame_size ++#define sparc_apparent_frame_size cfun->machine->apparent_frame_size ++#define sparc_frame_base_reg cfun->machine->frame_base_reg ++#define sparc_frame_base_offset cfun->machine->frame_base_offset ++#define sparc_n_global_fp_regs cfun->machine->n_global_fp_regs ++#define sparc_leaf_function_p cfun->machine->leaf_function_p ++#define sparc_save_local_in_regs_p cfun->machine->save_local_in_regs_p ++#define sparc_prologue_data_valid_p cfun->machine->prologue_data_valid_p ++ ++/* 1 if the next opcode is to be specially indented. */ ++int sparc_indent_opcode = 0; ++ ++static void sparc_option_override (void); ++static void sparc_init_modes (void); ++static int function_arg_slotno (const CUMULATIVE_ARGS *, machine_mode, ++ const_tree, bool, bool, int *, int *); ++ ++static int supersparc_adjust_cost (rtx_insn *, int, rtx_insn *, int); ++static int hypersparc_adjust_cost (rtx_insn *, int, rtx_insn *, int); ++ ++static void sparc_emit_set_const32 (rtx, rtx); ++static void sparc_emit_set_const64 (rtx, rtx); ++static void sparc_output_addr_vec (rtx); ++static void sparc_output_addr_diff_vec (rtx); ++static void sparc_output_deferred_case_vectors (void); ++static bool sparc_legitimate_address_p (machine_mode, rtx, bool); ++static bool sparc_legitimate_constant_p (machine_mode, rtx); ++static rtx sparc_builtin_saveregs (void); ++static int epilogue_renumber (rtx *, int); ++static bool sparc_assemble_integer (rtx, unsigned int, int); ++static int set_extends (rtx_insn *); ++static void sparc_asm_function_prologue (FILE *); ++static void sparc_asm_function_epilogue (FILE *); ++#ifdef TARGET_SOLARIS ++static void sparc_solaris_elf_asm_named_section (const char *, unsigned int, ++ tree) ATTRIBUTE_UNUSED; ++#endif ++static int sparc_adjust_cost (rtx_insn *, int, rtx_insn *, int, unsigned int); ++static int sparc_issue_rate (void); ++static void sparc_sched_init (FILE *, int, int); ++static int sparc_use_sched_lookahead (void); ++ ++static void emit_soft_tfmode_libcall (const char *, int, rtx *); ++static void emit_soft_tfmode_binop (enum rtx_code, rtx *); ++static void emit_soft_tfmode_unop (enum rtx_code, rtx *); ++static void emit_soft_tfmode_cvt (enum rtx_code, rtx *); ++static void emit_hard_tfmode_operation (enum rtx_code, rtx *); ++ ++static bool sparc_function_ok_for_sibcall (tree, tree); ++static void sparc_init_libfuncs (void); ++static void sparc_init_builtins (void); ++static void sparc_fpu_init_builtins (void); ++static void sparc_vis_init_builtins (void); ++static tree sparc_builtin_decl (unsigned, bool); ++static rtx sparc_expand_builtin (tree, rtx, rtx, machine_mode, int); ++static tree sparc_fold_builtin (tree, int, tree *, bool); ++static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, ++ HOST_WIDE_INT, tree); ++static bool sparc_can_output_mi_thunk (const_tree, HOST_WIDE_INT, ++ HOST_WIDE_INT, const_tree); ++static struct machine_function * sparc_init_machine_status (void); ++static bool sparc_cannot_force_const_mem (machine_mode, rtx); ++static rtx sparc_tls_get_addr (void); ++static rtx sparc_tls_got (void); ++static int sparc_register_move_cost (machine_mode, ++ reg_class_t, reg_class_t); ++static bool sparc_rtx_costs (rtx, machine_mode, int, int, int *, bool); ++static machine_mode sparc_promote_function_mode (const_tree, machine_mode, ++ int *, const_tree, int); ++static bool sparc_strict_argument_naming (cumulative_args_t); ++static void sparc_va_start (tree, rtx); ++static tree sparc_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *); ++static bool sparc_vector_mode_supported_p (machine_mode); ++static bool sparc_tls_referenced_p (rtx); ++static rtx sparc_legitimize_tls_address (rtx); ++static rtx sparc_legitimize_pic_address (rtx, rtx); ++static rtx sparc_legitimize_address (rtx, rtx, machine_mode); ++static rtx sparc_delegitimize_address (rtx); ++static bool sparc_mode_dependent_address_p (const_rtx, addr_space_t); ++static bool sparc_pass_by_reference (cumulative_args_t, ++ const function_arg_info &); ++static void sparc_function_arg_advance (cumulative_args_t, ++ const function_arg_info &); ++static rtx sparc_function_arg (cumulative_args_t, const function_arg_info &); ++static rtx sparc_function_incoming_arg (cumulative_args_t, ++ const function_arg_info &); ++static pad_direction sparc_function_arg_padding (machine_mode, const_tree); ++static unsigned int sparc_function_arg_boundary (machine_mode, ++ const_tree); ++static int sparc_arg_partial_bytes (cumulative_args_t, ++ const function_arg_info &); ++static bool sparc_return_in_memory (const_tree, const_tree); ++static rtx sparc_struct_value_rtx (tree, int); ++static rtx sparc_function_value (const_tree, const_tree, bool); ++static rtx sparc_libcall_value (machine_mode, const_rtx); ++static bool sparc_function_value_regno_p (const unsigned int); ++static unsigned HOST_WIDE_INT sparc_asan_shadow_offset (void); ++static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED; ++static void sparc_file_end (void); ++static bool sparc_frame_pointer_required (void); ++static bool sparc_can_eliminate (const int, const int); ++static void sparc_conditional_register_usage (void); ++static bool sparc_use_pseudo_pic_reg (void); ++static void sparc_init_pic_reg (void); ++#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING ++static const char *sparc_mangle_type (const_tree); ++#endif ++static void sparc_trampoline_init (rtx, tree, rtx); ++static machine_mode sparc_preferred_simd_mode (scalar_mode); ++static reg_class_t sparc_preferred_reload_class (rtx x, reg_class_t rclass); ++static bool sparc_lra_p (void); ++static bool sparc_print_operand_punct_valid_p (unsigned char); ++static void sparc_print_operand (FILE *, rtx, int); ++static void sparc_print_operand_address (FILE *, machine_mode, rtx); ++static reg_class_t sparc_secondary_reload (bool, rtx, reg_class_t, ++ machine_mode, ++ secondary_reload_info *); ++static bool sparc_secondary_memory_needed (machine_mode, reg_class_t, ++ reg_class_t); ++static machine_mode sparc_secondary_memory_needed_mode (machine_mode); ++static scalar_int_mode sparc_cstore_mode (enum insn_code icode); ++static void sparc_atomic_assign_expand_fenv (tree *, tree *, tree *); ++static bool sparc_fixed_condition_code_regs (unsigned int *, unsigned int *); ++static unsigned int sparc_min_arithmetic_precision (void); ++static unsigned int sparc_hard_regno_nregs (unsigned int, machine_mode); ++static bool sparc_hard_regno_mode_ok (unsigned int, machine_mode); ++static bool sparc_modes_tieable_p (machine_mode, machine_mode); ++static bool sparc_can_change_mode_class (machine_mode, machine_mode, ++ reg_class_t); ++static HOST_WIDE_INT sparc_constant_alignment (const_tree, HOST_WIDE_INT); ++static bool sparc_vectorize_vec_perm_const (machine_mode, rtx, rtx, rtx, ++ const vec_perm_indices &); ++static bool sparc_can_follow_jump (const rtx_insn *, const rtx_insn *); ++ ++#ifdef SUBTARGET_ATTRIBUTE_TABLE ++/* Table of valid machine attributes. */ ++static const struct attribute_spec sparc_attribute_table[] = ++{ ++ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, ++ do_diagnostic, handler, exclude } */ ++ SUBTARGET_ATTRIBUTE_TABLE, ++ { NULL, 0, 0, false, false, false, false, NULL, NULL } ++}; ++#endif ++ ++char sparc_hard_reg_printed[8]; ++ ++/* Initialize the GCC target structure. */ ++ ++/* The default is to use .half rather than .short for aligned HI objects. */ ++#undef TARGET_ASM_ALIGNED_HI_OP ++#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" ++ ++#undef TARGET_ASM_UNALIGNED_HI_OP ++#define TARGET_ASM_UNALIGNED_HI_OP "\t.uahalf\t" ++#undef TARGET_ASM_UNALIGNED_SI_OP ++#define TARGET_ASM_UNALIGNED_SI_OP "\t.uaword\t" ++#undef TARGET_ASM_UNALIGNED_DI_OP ++#define TARGET_ASM_UNALIGNED_DI_OP "\t.uaxword\t" ++ ++/* The target hook has to handle DI-mode values. */ ++#undef TARGET_ASM_INTEGER ++#define TARGET_ASM_INTEGER sparc_assemble_integer ++ ++#undef TARGET_ASM_FUNCTION_PROLOGUE ++#define TARGET_ASM_FUNCTION_PROLOGUE sparc_asm_function_prologue ++#undef TARGET_ASM_FUNCTION_EPILOGUE ++#define TARGET_ASM_FUNCTION_EPILOGUE sparc_asm_function_epilogue ++ ++#undef TARGET_SCHED_ADJUST_COST ++#define TARGET_SCHED_ADJUST_COST sparc_adjust_cost ++#undef TARGET_SCHED_ISSUE_RATE ++#define TARGET_SCHED_ISSUE_RATE sparc_issue_rate ++#undef TARGET_SCHED_INIT ++#define TARGET_SCHED_INIT sparc_sched_init ++#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD ++#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead ++ ++#undef TARGET_FUNCTION_OK_FOR_SIBCALL ++#define TARGET_FUNCTION_OK_FOR_SIBCALL sparc_function_ok_for_sibcall ++ ++#undef TARGET_INIT_LIBFUNCS ++#define TARGET_INIT_LIBFUNCS sparc_init_libfuncs ++ ++#undef TARGET_LEGITIMIZE_ADDRESS ++#define TARGET_LEGITIMIZE_ADDRESS sparc_legitimize_address ++#undef TARGET_DELEGITIMIZE_ADDRESS ++#define TARGET_DELEGITIMIZE_ADDRESS sparc_delegitimize_address ++#undef TARGET_MODE_DEPENDENT_ADDRESS_P ++#define TARGET_MODE_DEPENDENT_ADDRESS_P sparc_mode_dependent_address_p ++ ++#undef TARGET_INIT_BUILTINS ++#define TARGET_INIT_BUILTINS sparc_init_builtins ++#undef TARGET_BUILTIN_DECL ++#define TARGET_BUILTIN_DECL sparc_builtin_decl ++#undef TARGET_EXPAND_BUILTIN ++#define TARGET_EXPAND_BUILTIN sparc_expand_builtin ++#undef TARGET_FOLD_BUILTIN ++#define TARGET_FOLD_BUILTIN sparc_fold_builtin ++ ++#if TARGET_TLS ++#undef TARGET_HAVE_TLS ++#define TARGET_HAVE_TLS true ++#endif ++ ++#undef TARGET_CANNOT_FORCE_CONST_MEM ++#define TARGET_CANNOT_FORCE_CONST_MEM sparc_cannot_force_const_mem ++ ++#undef TARGET_ASM_OUTPUT_MI_THUNK ++#define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk ++#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK ++#define TARGET_ASM_CAN_OUTPUT_MI_THUNK sparc_can_output_mi_thunk ++ ++#undef TARGET_RTX_COSTS ++#define TARGET_RTX_COSTS sparc_rtx_costs ++#undef TARGET_ADDRESS_COST ++#define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0 ++#undef TARGET_REGISTER_MOVE_COST ++#define TARGET_REGISTER_MOVE_COST sparc_register_move_cost ++ ++#undef TARGET_PROMOTE_FUNCTION_MODE ++#define TARGET_PROMOTE_FUNCTION_MODE sparc_promote_function_mode ++#undef TARGET_STRICT_ARGUMENT_NAMING ++#define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming ++ ++#undef TARGET_MUST_PASS_IN_STACK ++#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size ++#undef TARGET_PASS_BY_REFERENCE ++#define TARGET_PASS_BY_REFERENCE sparc_pass_by_reference ++#undef TARGET_ARG_PARTIAL_BYTES ++#define TARGET_ARG_PARTIAL_BYTES sparc_arg_partial_bytes ++#undef TARGET_FUNCTION_ARG_ADVANCE ++#define TARGET_FUNCTION_ARG_ADVANCE sparc_function_arg_advance ++#undef TARGET_FUNCTION_ARG ++#define TARGET_FUNCTION_ARG sparc_function_arg ++#undef TARGET_FUNCTION_INCOMING_ARG ++#define TARGET_FUNCTION_INCOMING_ARG sparc_function_incoming_arg ++#undef TARGET_FUNCTION_ARG_PADDING ++#define TARGET_FUNCTION_ARG_PADDING sparc_function_arg_padding ++#undef TARGET_FUNCTION_ARG_BOUNDARY ++#define TARGET_FUNCTION_ARG_BOUNDARY sparc_function_arg_boundary ++ ++#undef TARGET_RETURN_IN_MEMORY ++#define TARGET_RETURN_IN_MEMORY sparc_return_in_memory ++#undef TARGET_STRUCT_VALUE_RTX ++#define TARGET_STRUCT_VALUE_RTX sparc_struct_value_rtx ++#undef TARGET_FUNCTION_VALUE ++#define TARGET_FUNCTION_VALUE sparc_function_value ++#undef TARGET_LIBCALL_VALUE ++#define TARGET_LIBCALL_VALUE sparc_libcall_value ++#undef TARGET_FUNCTION_VALUE_REGNO_P ++#define TARGET_FUNCTION_VALUE_REGNO_P sparc_function_value_regno_p ++ ++#undef TARGET_EXPAND_BUILTIN_SAVEREGS ++#define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs ++ ++#undef TARGET_ASAN_SHADOW_OFFSET ++#define TARGET_ASAN_SHADOW_OFFSET sparc_asan_shadow_offset ++ ++#undef TARGET_EXPAND_BUILTIN_VA_START ++#define TARGET_EXPAND_BUILTIN_VA_START sparc_va_start ++#undef TARGET_GIMPLIFY_VA_ARG_EXPR ++#define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg ++ ++#undef TARGET_VECTOR_MODE_SUPPORTED_P ++#define TARGET_VECTOR_MODE_SUPPORTED_P sparc_vector_mode_supported_p ++ ++#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE ++#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE sparc_preferred_simd_mode ++ ++#ifdef SUBTARGET_INSERT_ATTRIBUTES ++#undef TARGET_INSERT_ATTRIBUTES ++#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES ++#endif ++ ++#ifdef SUBTARGET_ATTRIBUTE_TABLE ++#undef TARGET_ATTRIBUTE_TABLE ++#define TARGET_ATTRIBUTE_TABLE sparc_attribute_table ++#endif ++ ++#undef TARGET_OPTION_OVERRIDE ++#define TARGET_OPTION_OVERRIDE sparc_option_override ++ ++#ifdef TARGET_THREAD_SSP_OFFSET ++#undef TARGET_STACK_PROTECT_GUARD ++#define TARGET_STACK_PROTECT_GUARD hook_tree_void_null ++#endif ++ ++#if TARGET_GNU_TLS && defined(HAVE_AS_SPARC_UA_PCREL) ++#undef TARGET_ASM_OUTPUT_DWARF_DTPREL ++#define TARGET_ASM_OUTPUT_DWARF_DTPREL sparc_output_dwarf_dtprel ++#endif ++ ++#undef TARGET_ASM_FILE_END ++#define TARGET_ASM_FILE_END sparc_file_end ++ ++#undef TARGET_FRAME_POINTER_REQUIRED ++#define TARGET_FRAME_POINTER_REQUIRED sparc_frame_pointer_required ++ ++#undef TARGET_CAN_ELIMINATE ++#define TARGET_CAN_ELIMINATE sparc_can_eliminate ++ ++#undef TARGET_PREFERRED_RELOAD_CLASS ++#define TARGET_PREFERRED_RELOAD_CLASS sparc_preferred_reload_class ++ ++#undef TARGET_SECONDARY_RELOAD ++#define TARGET_SECONDARY_RELOAD sparc_secondary_reload ++#undef TARGET_SECONDARY_MEMORY_NEEDED ++#define TARGET_SECONDARY_MEMORY_NEEDED sparc_secondary_memory_needed ++#undef TARGET_SECONDARY_MEMORY_NEEDED_MODE ++#define TARGET_SECONDARY_MEMORY_NEEDED_MODE sparc_secondary_memory_needed_mode ++ ++#undef TARGET_CONDITIONAL_REGISTER_USAGE ++#define TARGET_CONDITIONAL_REGISTER_USAGE sparc_conditional_register_usage ++ ++#undef TARGET_INIT_PIC_REG ++#define TARGET_INIT_PIC_REG sparc_init_pic_reg ++ ++#undef TARGET_USE_PSEUDO_PIC_REG ++#define TARGET_USE_PSEUDO_PIC_REG sparc_use_pseudo_pic_reg ++ ++#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING ++#undef TARGET_MANGLE_TYPE ++#define TARGET_MANGLE_TYPE sparc_mangle_type ++#endif ++ ++#undef TARGET_LRA_P ++#define TARGET_LRA_P sparc_lra_p ++ ++#undef TARGET_LEGITIMATE_ADDRESS_P ++#define TARGET_LEGITIMATE_ADDRESS_P sparc_legitimate_address_p ++ ++#undef TARGET_LEGITIMATE_CONSTANT_P ++#define TARGET_LEGITIMATE_CONSTANT_P sparc_legitimate_constant_p ++ ++#undef TARGET_TRAMPOLINE_INIT ++#define TARGET_TRAMPOLINE_INIT sparc_trampoline_init ++ ++#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P ++#define TARGET_PRINT_OPERAND_PUNCT_VALID_P sparc_print_operand_punct_valid_p ++#undef TARGET_PRINT_OPERAND ++#define TARGET_PRINT_OPERAND sparc_print_operand ++#undef TARGET_PRINT_OPERAND_ADDRESS ++#define TARGET_PRINT_OPERAND_ADDRESS sparc_print_operand_address ++ ++/* The value stored by LDSTUB. */ ++#undef TARGET_ATOMIC_TEST_AND_SET_TRUEVAL ++#define TARGET_ATOMIC_TEST_AND_SET_TRUEVAL 0xff ++ ++#undef TARGET_CSTORE_MODE ++#define TARGET_CSTORE_MODE sparc_cstore_mode ++ ++#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV ++#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV sparc_atomic_assign_expand_fenv ++ ++#undef TARGET_FIXED_CONDITION_CODE_REGS ++#define TARGET_FIXED_CONDITION_CODE_REGS sparc_fixed_condition_code_regs ++ ++#undef TARGET_MIN_ARITHMETIC_PRECISION ++#define TARGET_MIN_ARITHMETIC_PRECISION sparc_min_arithmetic_precision ++ ++#undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS ++#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1 ++ ++#undef TARGET_HARD_REGNO_NREGS ++#define TARGET_HARD_REGNO_NREGS sparc_hard_regno_nregs ++#undef TARGET_HARD_REGNO_MODE_OK ++#define TARGET_HARD_REGNO_MODE_OK sparc_hard_regno_mode_ok ++ ++#undef TARGET_MODES_TIEABLE_P ++#define TARGET_MODES_TIEABLE_P sparc_modes_tieable_p ++ ++#undef TARGET_CAN_CHANGE_MODE_CLASS ++#define TARGET_CAN_CHANGE_MODE_CLASS sparc_can_change_mode_class ++ ++#undef TARGET_CONSTANT_ALIGNMENT ++#define TARGET_CONSTANT_ALIGNMENT sparc_constant_alignment ++ ++#undef TARGET_VECTORIZE_VEC_PERM_CONST ++#define TARGET_VECTORIZE_VEC_PERM_CONST sparc_vectorize_vec_perm_const ++ ++#undef TARGET_CAN_FOLLOW_JUMP ++#define TARGET_CAN_FOLLOW_JUMP sparc_can_follow_jump ++ ++struct gcc_target targetm = TARGET_INITIALIZER; ++ ++/* Return the memory reference contained in X if any, zero otherwise. */ ++ ++static rtx ++mem_ref (rtx x) ++{ ++ if (GET_CODE (x) == SIGN_EXTEND || GET_CODE (x) == ZERO_EXTEND) ++ x = XEXP (x, 0); ++ ++ if (MEM_P (x)) ++ return x; ++ ++ return NULL_RTX; ++} ++ ++/* True if any of INSN's source register(s) is REG. */ ++ ++static bool ++insn_uses_reg_p (rtx_insn *insn, unsigned int reg) ++{ ++ extract_insn (insn); ++ return ((REG_P (recog_data.operand[1]) ++ && REGNO (recog_data.operand[1]) == reg) ++ || (recog_data.n_operands == 3 ++ && REG_P (recog_data.operand[2]) ++ && REGNO (recog_data.operand[2]) == reg)); ++} ++ ++/* True if INSN is a floating-point division or square-root. */ ++ ++static bool ++div_sqrt_insn_p (rtx_insn *insn) ++{ ++ if (GET_CODE (PATTERN (insn)) != SET) ++ return false; ++ ++ switch (get_attr_type (insn)) ++ { ++ case TYPE_FPDIVS: ++ case TYPE_FPSQRTS: ++ case TYPE_FPDIVD: ++ case TYPE_FPSQRTD: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++/* True if INSN is a floating-point instruction. */ ++ ++static bool ++fpop_insn_p (rtx_insn *insn) ++{ ++ if (GET_CODE (PATTERN (insn)) != SET) ++ return false; ++ ++ switch (get_attr_type (insn)) ++ { ++ case TYPE_FPMOVE: ++ case TYPE_FPCMOVE: ++ case TYPE_FP: ++ case TYPE_FPCMP: ++ case TYPE_FPMUL: ++ case TYPE_FPDIVS: ++ case TYPE_FPSQRTS: ++ case TYPE_FPDIVD: ++ case TYPE_FPSQRTD: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++/* True if INSN is an atomic instruction. */ ++ ++static bool ++atomic_insn_for_leon3_p (rtx_insn *insn) ++{ ++ switch (INSN_CODE (insn)) ++ { ++ case CODE_FOR_swapsi: ++ case CODE_FOR_ldstub: ++ case CODE_FOR_atomic_compare_and_swap_leon3_1: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++/* We use a machine specific pass to enable workarounds for errata. ++ ++ We need to have the (essentially) final form of the insn stream in order ++ to properly detect the various hazards. Therefore, this machine specific ++ pass runs as late as possible. */ ++ ++/* True if INSN is a md pattern or asm statement. */ ++#define USEFUL_INSN_P(INSN) \ ++ (NONDEBUG_INSN_P (INSN) \ ++ && GET_CODE (PATTERN (INSN)) != USE \ ++ && GET_CODE (PATTERN (INSN)) != CLOBBER) ++ ++static unsigned int ++sparc_do_work_around_errata (void) ++{ ++ rtx_insn *insn, *next; ++ ++ /* Force all instructions to be split into their final form. */ ++ split_all_insns_noflow (); ++ ++ /* Now look for specific patterns in the insn stream. */ ++ for (insn = get_insns (); insn; insn = next) ++ { ++ bool insert_nop = false; ++ rtx set; ++ rtx_insn *jump; ++ rtx_sequence *seq; ++ ++ /* Look into the instruction in a delay slot. */ ++ if (NONJUMP_INSN_P (insn) ++ && (seq = dyn_cast (PATTERN (insn)))) ++ { ++ jump = seq->insn (0); ++ insn = seq->insn (1); ++ } ++ else if (JUMP_P (insn)) ++ jump = insn; ++ else ++ jump = NULL; ++ ++ /* Place a NOP at the branch target of an integer branch if it is a ++ floating-point operation or a floating-point branch. */ ++ if (sparc_fix_gr712rc ++ && jump ++ && jump_to_label_p (jump) ++ && get_attr_branch_type (jump) == BRANCH_TYPE_ICC) ++ { ++ rtx_insn *target = next_active_insn (JUMP_LABEL_AS_INSN (jump)); ++ if (target ++ && (fpop_insn_p (target) ++ || (JUMP_P (target) ++ && get_attr_branch_type (target) == BRANCH_TYPE_FCC))) ++ emit_insn_before (gen_nop (), target); ++ } ++ ++ /* Insert a NOP between load instruction and atomic instruction. Insert ++ a NOP at branch target if there is a load in delay slot and an atomic ++ instruction at branch target. */ ++ if (sparc_fix_ut700 ++ && NONJUMP_INSN_P (insn) ++ && (set = single_set (insn)) != NULL_RTX ++ && mem_ref (SET_SRC (set)) ++ && REG_P (SET_DEST (set))) ++ { ++ if (jump && jump_to_label_p (jump)) ++ { ++ rtx_insn *target = next_active_insn (JUMP_LABEL_AS_INSN (jump)); ++ if (target && atomic_insn_for_leon3_p (target)) ++ emit_insn_before (gen_nop (), target); ++ } ++ ++ next = next_active_insn (insn); ++ if (!next) ++ break; ++ ++ if (atomic_insn_for_leon3_p (next)) ++ insert_nop = true; ++ } ++ ++ /* Look for a sequence that starts with a fdiv or fsqrt instruction and ++ ends with another fdiv or fsqrt instruction with no dependencies on ++ the former, along with an appropriate pattern in between. */ ++ if (sparc_fix_lost_divsqrt ++ && NONJUMP_INSN_P (insn) ++ && div_sqrt_insn_p (insn)) ++ { ++ int i; ++ int fp_found = 0; ++ rtx_insn *after; ++ ++ const unsigned int dest_reg = REGNO (SET_DEST (single_set (insn))); ++ ++ next = next_active_insn (insn); ++ if (!next) ++ break; ++ ++ for (after = next, i = 0; i < 4; i++) ++ { ++ /* Count floating-point operations. */ ++ if (i != 3 && fpop_insn_p (after)) ++ { ++ /* If the insn uses the destination register of ++ the div/sqrt, then it cannot be problematic. */ ++ if (insn_uses_reg_p (after, dest_reg)) ++ break; ++ fp_found++; ++ } ++ ++ /* Count floating-point loads. */ ++ if (i != 3 ++ && (set = single_set (after)) != NULL_RTX ++ && REG_P (SET_DEST (set)) ++ && REGNO (SET_DEST (set)) > 31) ++ { ++ /* If the insn uses the destination register of ++ the div/sqrt, then it cannot be problematic. */ ++ if (REGNO (SET_DEST (set)) == dest_reg) ++ break; ++ fp_found++; ++ } ++ ++ /* Check if this is a problematic sequence. */ ++ if (i > 1 ++ && fp_found >= 2 ++ && div_sqrt_insn_p (after)) ++ { ++ /* If this is the short version of the problematic ++ sequence we add two NOPs in a row to also prevent ++ the long version. */ ++ if (i == 2) ++ emit_insn_before (gen_nop (), next); ++ insert_nop = true; ++ break; ++ } ++ ++ /* No need to scan past a second div/sqrt. */ ++ if (div_sqrt_insn_p (after)) ++ break; ++ ++ /* Insert NOP before branch. */ ++ if (i < 3 ++ && (!NONJUMP_INSN_P (after) ++ || GET_CODE (PATTERN (after)) == SEQUENCE)) ++ { ++ insert_nop = true; ++ break; ++ } ++ ++ after = next_active_insn (after); ++ if (!after) ++ break; ++ } ++ } ++ ++ /* Look for either of these two sequences: ++ ++ Sequence A: ++ 1. store of word size or less (e.g. st / stb / sth / stf) ++ 2. any single instruction that is not a load or store ++ 3. any store instruction (e.g. st / stb / sth / stf / std / stdf) ++ ++ Sequence B: ++ 1. store of double word size (e.g. std / stdf) ++ 2. any store instruction (e.g. st / stb / sth / stf / std / stdf) */ ++ if (sparc_fix_b2bst ++ && NONJUMP_INSN_P (insn) ++ && (set = single_set (insn)) != NULL_RTX ++ && MEM_P (SET_DEST (set))) ++ { ++ /* Sequence B begins with a double-word store. */ ++ bool seq_b = GET_MODE_SIZE (GET_MODE (SET_DEST (set))) == 8; ++ rtx_insn *after; ++ int i; ++ ++ next = next_active_insn (insn); ++ if (!next) ++ break; ++ ++ for (after = next, i = 0; i < 2; i++) ++ { ++ /* Skip empty assembly statements. */ ++ if ((GET_CODE (PATTERN (after)) == UNSPEC_VOLATILE) ++ || (USEFUL_INSN_P (after) ++ && (asm_noperands (PATTERN (after))>=0) ++ && !strcmp (decode_asm_operands (PATTERN (after), ++ NULL, NULL, NULL, ++ NULL, NULL), ""))) ++ after = next_active_insn (after); ++ if (!after) ++ break; ++ ++ /* If the insn is a branch, then it cannot be problematic. */ ++ if (!NONJUMP_INSN_P (after) ++ || GET_CODE (PATTERN (after)) == SEQUENCE) ++ break; ++ ++ /* Sequence B is only two instructions long. */ ++ if (seq_b) ++ { ++ /* Add NOP if followed by a store. */ ++ if ((set = single_set (after)) != NULL_RTX ++ && MEM_P (SET_DEST (set))) ++ insert_nop = true; ++ ++ /* Otherwise it is ok. */ ++ break; ++ } ++ ++ /* If the second instruction is a load or a store, ++ then the sequence cannot be problematic. */ ++ if (i == 0) ++ { ++ if ((set = single_set (after)) != NULL_RTX ++ && (MEM_P (SET_DEST (set)) || mem_ref (SET_SRC (set)))) ++ break; ++ ++ after = next_active_insn (after); ++ if (!after) ++ break; ++ } ++ ++ /* Add NOP if third instruction is a store. */ ++ if (i == 1 ++ && (set = single_set (after)) != NULL_RTX ++ && MEM_P (SET_DEST (set))) ++ insert_nop = true; ++ } ++ } ++ ++ /* Look for a single-word load into an odd-numbered FP register. */ ++ else if (sparc_fix_at697f ++ && NONJUMP_INSN_P (insn) ++ && (set = single_set (insn)) != NULL_RTX ++ && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4 ++ && mem_ref (SET_SRC (set)) ++ && REG_P (SET_DEST (set)) ++ && REGNO (SET_DEST (set)) > 31 ++ && REGNO (SET_DEST (set)) % 2 != 0) ++ { ++ /* The wrong dependency is on the enclosing double register. */ ++ const unsigned int x = REGNO (SET_DEST (set)) - 1; ++ unsigned int src1, src2, dest; ++ int code; ++ ++ next = next_active_insn (insn); ++ if (!next) ++ break; ++ /* If the insn is a branch, then it cannot be problematic. */ ++ if (!NONJUMP_INSN_P (next) || GET_CODE (PATTERN (next)) == SEQUENCE) ++ continue; ++ ++ extract_insn (next); ++ code = INSN_CODE (next); ++ ++ switch (code) ++ { ++ case CODE_FOR_adddf3: ++ case CODE_FOR_subdf3: ++ case CODE_FOR_muldf3: ++ case CODE_FOR_divdf3: ++ dest = REGNO (recog_data.operand[0]); ++ src1 = REGNO (recog_data.operand[1]); ++ src2 = REGNO (recog_data.operand[2]); ++ if (src1 != src2) ++ { ++ /* Case [1-4]: ++ ld [address], %fx+1 ++ FPOPd %f{x,y}, %f{y,x}, %f{x,y} */ ++ if ((src1 == x || src2 == x) ++ && (dest == src1 || dest == src2)) ++ insert_nop = true; ++ } ++ else ++ { ++ /* Case 5: ++ ld [address], %fx+1 ++ FPOPd %fx, %fx, %fx */ ++ if (src1 == x ++ && dest == src1 ++ && (code == CODE_FOR_adddf3 || code == CODE_FOR_muldf3)) ++ insert_nop = true; ++ } ++ break; ++ ++ case CODE_FOR_sqrtdf2: ++ dest = REGNO (recog_data.operand[0]); ++ src1 = REGNO (recog_data.operand[1]); ++ /* Case 6: ++ ld [address], %fx+1 ++ fsqrtd %fx, %fx */ ++ if (src1 == x && dest == src1) ++ insert_nop = true; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ /* Look for a single-word load into an integer register. */ ++ else if (sparc_fix_ut699 ++ && NONJUMP_INSN_P (insn) ++ && (set = single_set (insn)) != NULL_RTX ++ && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) <= 4 ++ && (mem_ref (SET_SRC (set)) != NULL_RTX ++ || INSN_CODE (insn) == CODE_FOR_movsi_pic_gotdata_op) ++ && REG_P (SET_DEST (set)) ++ && REGNO (SET_DEST (set)) < 32) ++ { ++ /* There is no problem if the second memory access has a data ++ dependency on the first single-cycle load. */ ++ rtx x = SET_DEST (set); ++ ++ next = next_active_insn (insn); ++ if (!next) ++ break; ++ /* If the insn is a branch, then it cannot be problematic. */ ++ if (!NONJUMP_INSN_P (next) || GET_CODE (PATTERN (next)) == SEQUENCE) ++ continue; ++ ++ /* Look for a second memory access to/from an integer register. */ ++ if ((set = single_set (next)) != NULL_RTX) ++ { ++ rtx src = SET_SRC (set); ++ rtx dest = SET_DEST (set); ++ rtx mem; ++ ++ /* LDD is affected. */ ++ if ((mem = mem_ref (src)) != NULL_RTX ++ && REG_P (dest) ++ && REGNO (dest) < 32 ++ && !reg_mentioned_p (x, XEXP (mem, 0))) ++ insert_nop = true; ++ ++ /* STD is *not* affected. */ ++ else if (MEM_P (dest) ++ && GET_MODE_SIZE (GET_MODE (dest)) <= 4 ++ && (src == CONST0_RTX (GET_MODE (dest)) ++ || (REG_P (src) ++ && REGNO (src) < 32 ++ && REGNO (src) != REGNO (x))) ++ && !reg_mentioned_p (x, XEXP (dest, 0))) ++ insert_nop = true; ++ ++ /* GOT accesses uses LD. */ ++ else if (INSN_CODE (next) == CODE_FOR_movsi_pic_gotdata_op ++ && !reg_mentioned_p (x, XEXP (XEXP (src, 0), 1))) ++ insert_nop = true; ++ } ++ } ++ ++ /* Look for a single-word load/operation into an FP register. */ ++ else if (sparc_fix_ut699 ++ && NONJUMP_INSN_P (insn) ++ && (set = single_set (insn)) != NULL_RTX ++ && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4 ++ && REG_P (SET_DEST (set)) ++ && REGNO (SET_DEST (set)) > 31) ++ { ++ /* Number of instructions in the problematic window. */ ++ const int n_insns = 4; ++ /* The problematic combination is with the sibling FP register. */ ++ const unsigned int x = REGNO (SET_DEST (set)); ++ const unsigned int y = x ^ 1; ++ rtx_insn *after; ++ int i; ++ ++ next = next_active_insn (insn); ++ if (!next) ++ break; ++ /* If the insn is a branch, then it cannot be problematic. */ ++ if (!NONJUMP_INSN_P (next) || GET_CODE (PATTERN (next)) == SEQUENCE) ++ continue; ++ ++ /* Look for a second load/operation into the sibling FP register. */ ++ if (!((set = single_set (next)) != NULL_RTX ++ && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4 ++ && REG_P (SET_DEST (set)) ++ && REGNO (SET_DEST (set)) == y)) ++ continue; ++ ++ /* Look for a (possible) store from the FP register in the next N ++ instructions, but bail out if it is again modified or if there ++ is a store from the sibling FP register before this store. */ ++ for (after = next, i = 0; i < n_insns; i++) ++ { ++ bool branch_p; ++ ++ after = next_active_insn (after); ++ if (!after) ++ break; ++ ++ /* This is a branch with an empty delay slot. */ ++ if (!NONJUMP_INSN_P (after)) ++ { ++ if (++i == n_insns) ++ break; ++ branch_p = true; ++ after = NULL; ++ } ++ /* This is a branch with a filled delay slot. */ ++ else if (rtx_sequence *seq = ++ dyn_cast (PATTERN (after))) ++ { ++ if (++i == n_insns) ++ break; ++ branch_p = true; ++ after = seq->insn (1); ++ } ++ /* This is a regular instruction. */ ++ else ++ branch_p = false; ++ ++ if (after && (set = single_set (after)) != NULL_RTX) ++ { ++ const rtx src = SET_SRC (set); ++ const rtx dest = SET_DEST (set); ++ const unsigned int size = GET_MODE_SIZE (GET_MODE (dest)); ++ ++ /* If the FP register is again modified before the store, ++ then the store isn't affected. */ ++ if (REG_P (dest) ++ && (REGNO (dest) == x ++ || (REGNO (dest) == y && size == 8))) ++ break; ++ ++ if (MEM_P (dest) && REG_P (src)) ++ { ++ /* If there is a store from the sibling FP register ++ before the store, then the store is not affected. */ ++ if (REGNO (src) == y || (REGNO (src) == x && size == 8)) ++ break; ++ ++ /* Otherwise, the store is affected. */ ++ if (REGNO (src) == x && size == 4) ++ { ++ insert_nop = true; ++ break; ++ } ++ } ++ } ++ ++ /* If we have a branch in the first M instructions, then we ++ cannot see the (M+2)th instruction so we play safe. */ ++ if (branch_p && i <= (n_insns - 2)) ++ { ++ insert_nop = true; ++ break; ++ } ++ } ++ } ++ ++ else ++ next = NEXT_INSN (insn); ++ ++ if (insert_nop) ++ emit_insn_before (gen_nop (), next); ++ } ++ ++ return 0; ++} ++ ++namespace { ++ ++const pass_data pass_data_work_around_errata = ++{ ++ RTL_PASS, /* type */ ++ "errata", /* name */ ++ OPTGROUP_NONE, /* optinfo_flags */ ++ TV_MACH_DEP, /* tv_id */ ++ 0, /* properties_required */ ++ 0, /* properties_provided */ ++ 0, /* properties_destroyed */ ++ 0, /* todo_flags_start */ ++ 0, /* todo_flags_finish */ ++}; ++ ++class pass_work_around_errata : public rtl_opt_pass ++{ ++public: ++ pass_work_around_errata(gcc::context *ctxt) ++ : rtl_opt_pass(pass_data_work_around_errata, ctxt) ++ {} ++ ++ /* opt_pass methods: */ ++ virtual bool gate (function *) ++ { ++ return sparc_fix_at697f ++ || sparc_fix_ut699 || sparc_fix_ut700 || sparc_fix_gr712rc ++ || sparc_fix_b2bst || sparc_fix_lost_divsqrt; ++ } ++ ++ virtual unsigned int execute (function *) ++ { ++ return sparc_do_work_around_errata (); ++ } ++ ++}; // class pass_work_around_errata ++ ++} // anon namespace ++ ++rtl_opt_pass * ++make_pass_work_around_errata (gcc::context *ctxt) ++{ ++ return new pass_work_around_errata (ctxt); ++} ++ ++/* Helpers for TARGET_DEBUG_OPTIONS. */ ++static void ++dump_target_flag_bits (const int flags) ++{ ++ if (flags & MASK_64BIT) ++ fprintf (stderr, "64BIT "); ++ if (flags & MASK_APP_REGS) ++ fprintf (stderr, "APP_REGS "); ++ if (flags & MASK_FASTER_STRUCTS) ++ fprintf (stderr, "FASTER_STRUCTS "); ++ if (flags & MASK_FLAT) ++ fprintf (stderr, "FLAT "); ++ if (flags & MASK_FMAF) ++ fprintf (stderr, "FMAF "); ++ if (flags & MASK_FSMULD) ++ fprintf (stderr, "FSMULD "); ++ if (flags & MASK_FPU) ++ fprintf (stderr, "FPU "); ++ if (flags & MASK_HARD_QUAD) ++ fprintf (stderr, "HARD_QUAD "); ++ if (flags & MASK_POPC) ++ fprintf (stderr, "POPC "); ++ if (flags & MASK_PTR64) ++ fprintf (stderr, "PTR64 "); ++ if (flags & MASK_STACK_BIAS) ++ fprintf (stderr, "STACK_BIAS "); ++ if (flags & MASK_UNALIGNED_DOUBLES) ++ fprintf (stderr, "UNALIGNED_DOUBLES "); ++ if (flags & MASK_V8PLUS) ++ fprintf (stderr, "V8PLUS "); ++ if (flags & MASK_VIS) ++ fprintf (stderr, "VIS "); ++ if (flags & MASK_VIS2) ++ fprintf (stderr, "VIS2 "); ++ if (flags & MASK_VIS3) ++ fprintf (stderr, "VIS3 "); ++ if (flags & MASK_VIS4) ++ fprintf (stderr, "VIS4 "); ++ if (flags & MASK_VIS4B) ++ fprintf (stderr, "VIS4B "); ++ if (flags & MASK_CBCOND) ++ fprintf (stderr, "CBCOND "); ++ if (flags & MASK_DEPRECATED_V8_INSNS) ++ fprintf (stderr, "DEPRECATED_V8_INSNS "); ++ if (flags & MASK_SPARCLET) ++ fprintf (stderr, "SPARCLET "); ++ if (flags & MASK_SPARCLITE) ++ fprintf (stderr, "SPARCLITE "); ++ if (flags & MASK_V8) ++ fprintf (stderr, "V8 "); ++ if (flags & MASK_V9) ++ fprintf (stderr, "V9 "); ++} ++ ++static void ++dump_target_flags (const char *prefix, const int flags) ++{ ++ fprintf (stderr, "%s: (%08x) [ ", prefix, flags); ++ dump_target_flag_bits (flags); ++ fprintf(stderr, "]\n"); ++} ++ ++/* Validate and override various options, and do some machine dependent ++ initialization. */ ++ ++static void ++sparc_option_override (void) ++{ ++ /* Map TARGET_CPU_DEFAULT to value for -m{cpu,tune}=. */ ++ static struct cpu_default { ++ const int cpu; ++ const enum sparc_processor_type processor; ++ } const cpu_default[] = { ++ /* There must be one entry here for each TARGET_CPU value. */ ++ { TARGET_CPU_sparc, PROCESSOR_CYPRESS }, ++ { TARGET_CPU_v8, PROCESSOR_V8 }, ++ { TARGET_CPU_supersparc, PROCESSOR_SUPERSPARC }, ++ { TARGET_CPU_hypersparc, PROCESSOR_HYPERSPARC }, ++ { TARGET_CPU_leon, PROCESSOR_LEON }, ++ { TARGET_CPU_leon3, PROCESSOR_LEON3 }, ++ { TARGET_CPU_leon3v7, PROCESSOR_LEON3V7 }, ++ { TARGET_CPU_sparclite, PROCESSOR_F930 }, ++ { TARGET_CPU_sparclite86x, PROCESSOR_SPARCLITE86X }, ++ { TARGET_CPU_sparclet, PROCESSOR_TSC701 }, ++ { TARGET_CPU_v9, PROCESSOR_V9 }, ++ { TARGET_CPU_ultrasparc, PROCESSOR_ULTRASPARC }, ++ { TARGET_CPU_ultrasparc3, PROCESSOR_ULTRASPARC3 }, ++ { TARGET_CPU_niagara, PROCESSOR_NIAGARA }, ++ { TARGET_CPU_niagara2, PROCESSOR_NIAGARA2 }, ++ { TARGET_CPU_niagara3, PROCESSOR_NIAGARA3 }, ++ { TARGET_CPU_niagara4, PROCESSOR_NIAGARA4 }, ++ { TARGET_CPU_niagara7, PROCESSOR_NIAGARA7 }, ++ { TARGET_CPU_m8, PROCESSOR_M8 }, ++ { -1, PROCESSOR_V7 } ++ }; ++ const struct cpu_default *def; ++ /* Table of values for -m{cpu,tune}=. This must match the order of ++ the enum processor_type in sparc-opts.h. */ ++ static struct cpu_table { ++ const char *const name; ++ const int disable; ++ const int enable; ++ } const cpu_table[] = { ++ { "v7", MASK_ISA, 0 }, ++ { "cypress", MASK_ISA, 0 }, ++ { "v8", MASK_ISA, MASK_V8 }, ++ /* TI TMS390Z55 supersparc */ ++ { "supersparc", MASK_ISA, MASK_V8 }, ++ { "hypersparc", MASK_ISA, MASK_V8 }, ++ { "leon", MASK_ISA|MASK_FSMULD, MASK_V8|MASK_LEON }, ++ { "leon3", MASK_ISA, MASK_V8|MASK_LEON3 }, ++ { "leon3v7", MASK_ISA, MASK_LEON3 }, ++ { "sparclite", MASK_ISA, MASK_SPARCLITE }, ++ /* The Fujitsu MB86930 is the original sparclite chip, with no FPU. */ ++ { "f930", MASK_ISA|MASK_FPU, MASK_SPARCLITE }, ++ /* The Fujitsu MB86934 is the recent sparclite chip, with an FPU. */ ++ { "f934", MASK_ISA, MASK_SPARCLITE }, ++ { "sparclite86x", MASK_ISA|MASK_FPU, MASK_SPARCLITE }, ++ { "sparclet", MASK_ISA, MASK_SPARCLET }, ++ /* TEMIC sparclet */ ++ { "tsc701", MASK_ISA, MASK_SPARCLET }, ++ { "v9", MASK_ISA, MASK_V9 }, ++ /* UltraSPARC I, II, IIi */ ++ { "ultrasparc", MASK_ISA, ++ /* Although insns using %y are deprecated, it is a clear win. */ ++ MASK_V9|MASK_DEPRECATED_V8_INSNS }, ++ /* UltraSPARC III */ ++ /* ??? Check if %y issue still holds true. */ ++ { "ultrasparc3", MASK_ISA, ++ MASK_V9|MASK_DEPRECATED_V8_INSNS|MASK_VIS2 }, ++ /* UltraSPARC T1 */ ++ { "niagara", MASK_ISA, ++ MASK_V9|MASK_DEPRECATED_V8_INSNS }, ++ /* UltraSPARC T2 */ ++ { "niagara2", MASK_ISA, ++ MASK_V9|MASK_POPC|MASK_VIS2 }, ++ /* UltraSPARC T3 */ ++ { "niagara3", MASK_ISA, ++ MASK_V9|MASK_POPC|MASK_VIS3|MASK_FMAF }, ++ /* UltraSPARC T4 */ ++ { "niagara4", MASK_ISA, ++ MASK_V9|MASK_POPC|MASK_VIS3|MASK_FMAF|MASK_CBCOND }, ++ /* UltraSPARC M7 */ ++ { "niagara7", MASK_ISA, ++ MASK_V9|MASK_POPC|MASK_VIS4|MASK_FMAF|MASK_CBCOND|MASK_SUBXC }, ++ /* UltraSPARC M8 */ ++ { "m8", MASK_ISA, ++ MASK_V9|MASK_POPC|MASK_VIS4B|MASK_FMAF|MASK_CBCOND|MASK_SUBXC } ++ }; ++ const struct cpu_table *cpu; ++ unsigned int i; ++ ++ if (sparc_debug_string != NULL) ++ { ++ const char *q; ++ char *p; ++ ++ p = ASTRDUP (sparc_debug_string); ++ while ((q = strtok (p, ",")) != NULL) ++ { ++ bool invert; ++ int mask; ++ ++ p = NULL; ++ if (*q == '!') ++ { ++ invert = true; ++ q++; ++ } ++ else ++ invert = false; ++ ++ if (! strcmp (q, "all")) ++ mask = MASK_DEBUG_ALL; ++ else if (! strcmp (q, "options")) ++ mask = MASK_DEBUG_OPTIONS; ++ else ++ error ("unknown %<-mdebug-%s%> switch", q); ++ ++ if (invert) ++ sparc_debug &= ~mask; ++ else ++ sparc_debug |= mask; ++ } ++ } ++ ++ /* Enable the FsMULd instruction by default if not explicitly specified by ++ the user. It may be later disabled by the CPU (explicitly or not). */ ++ if (TARGET_FPU && !(target_flags_explicit & MASK_FSMULD)) ++ target_flags |= MASK_FSMULD; ++ ++ if (TARGET_DEBUG_OPTIONS) ++ { ++ dump_target_flags("Initial target_flags", target_flags); ++ dump_target_flags("target_flags_explicit", target_flags_explicit); +