1132718Skan/* Subroutines for insn-output.c for SPARC. 272562Sobrien Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3169689Skan 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 4169689Skan Free Software Foundation, Inc. 550397Sobrien Contributed by Michael Tiemann (tiemann@cygnus.com) 6132718Skan 64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans, 750397Sobrien at Cygnus Support. 850397Sobrien 9132718SkanThis file is part of GCC. 1050397Sobrien 11132718SkanGCC is free software; you can redistribute it and/or modify 1250397Sobrienit under the terms of the GNU General Public License as published by 1350397Sobrienthe Free Software Foundation; either version 2, or (at your option) 1450397Sobrienany later version. 1550397Sobrien 16132718SkanGCC is distributed in the hope that it will be useful, 1750397Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1850397SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1950397SobrienGNU General Public License for more details. 2050397Sobrien 2150397SobrienYou should have received a copy of the GNU General Public License 22132718Skanalong with GCC; see the file COPYING. If not, write to 23169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor, 24169689SkanBoston, MA 02110-1301, USA. */ 2550397Sobrien 2650397Sobrien#include "config.h" 2750397Sobrien#include "system.h" 28132718Skan#include "coretypes.h" 29132718Skan#include "tm.h" 3050397Sobrien#include "tree.h" 3150397Sobrien#include "rtl.h" 3250397Sobrien#include "regs.h" 3350397Sobrien#include "hard-reg-set.h" 3450397Sobrien#include "real.h" 3550397Sobrien#include "insn-config.h" 36169689Skan#include "insn-codes.h" 3750397Sobrien#include "conditions.h" 3850397Sobrien#include "output.h" 3950397Sobrien#include "insn-attr.h" 4050397Sobrien#include "flags.h" 4190075Sobrien#include "function.h" 4250397Sobrien#include "expr.h" 4390075Sobrien#include "optabs.h" 4450397Sobrien#include "recog.h" 4550397Sobrien#include "toplev.h" 4690075Sobrien#include "ggc.h" 4790075Sobrien#include "tm_p.h" 4890075Sobrien#include "debug.h" 4990075Sobrien#include "target.h" 5090075Sobrien#include "target-def.h" 51132718Skan#include "cfglayout.h" 52169689Skan#include "tree-gimple.h" 53169689Skan#include "langhooks.h" 5450397Sobrien 55169689Skan/* Processor costs */ 56169689Skanstatic const 57169689Skanstruct processor_costs cypress_costs = { 58169689Skan COSTS_N_INSNS (2), /* int load */ 59169689Skan COSTS_N_INSNS (2), /* int signed load */ 60169689Skan COSTS_N_INSNS (2), /* int zeroed load */ 61169689Skan COSTS_N_INSNS (2), /* float load */ 62169689Skan COSTS_N_INSNS (5), /* fmov, fneg, fabs */ 63169689Skan COSTS_N_INSNS (5), /* fadd, fsub */ 64169689Skan COSTS_N_INSNS (1), /* fcmp */ 65169689Skan COSTS_N_INSNS (1), /* fmov, fmovr */ 66169689Skan COSTS_N_INSNS (7), /* fmul */ 67169689Skan COSTS_N_INSNS (37), /* fdivs */ 68169689Skan COSTS_N_INSNS (37), /* fdivd */ 69169689Skan COSTS_N_INSNS (63), /* fsqrts */ 70169689Skan COSTS_N_INSNS (63), /* fsqrtd */ 71169689Skan COSTS_N_INSNS (1), /* imul */ 72169689Skan COSTS_N_INSNS (1), /* imulX */ 73169689Skan 0, /* imul bit factor */ 74169689Skan COSTS_N_INSNS (1), /* idiv */ 75169689Skan COSTS_N_INSNS (1), /* idivX */ 76169689Skan COSTS_N_INSNS (1), /* movcc/movr */ 77169689Skan 0, /* shift penalty */ 78169689Skan}; 7950397Sobrien 80169689Skanstatic const 81169689Skanstruct processor_costs supersparc_costs = { 82169689Skan COSTS_N_INSNS (1), /* int load */ 83169689Skan COSTS_N_INSNS (1), /* int signed load */ 84169689Skan COSTS_N_INSNS (1), /* int zeroed load */ 85169689Skan COSTS_N_INSNS (0), /* float load */ 86169689Skan COSTS_N_INSNS (3), /* fmov, fneg, fabs */ 87169689Skan COSTS_N_INSNS (3), /* fadd, fsub */ 88169689Skan COSTS_N_INSNS (3), /* fcmp */ 89169689Skan COSTS_N_INSNS (1), /* fmov, fmovr */ 90169689Skan COSTS_N_INSNS (3), /* fmul */ 91169689Skan COSTS_N_INSNS (6), /* fdivs */ 92169689Skan COSTS_N_INSNS (9), /* fdivd */ 93169689Skan COSTS_N_INSNS (12), /* fsqrts */ 94169689Skan COSTS_N_INSNS (12), /* fsqrtd */ 95169689Skan COSTS_N_INSNS (4), /* imul */ 96169689Skan COSTS_N_INSNS (4), /* imulX */ 97169689Skan 0, /* imul bit factor */ 98169689Skan COSTS_N_INSNS (4), /* idiv */ 99169689Skan COSTS_N_INSNS (4), /* idivX */ 100169689Skan COSTS_N_INSNS (1), /* movcc/movr */ 101169689Skan 1, /* shift penalty */ 102169689Skan}; 10350397Sobrien 104169689Skanstatic const 105169689Skanstruct processor_costs hypersparc_costs = { 106169689Skan COSTS_N_INSNS (1), /* int load */ 107169689Skan COSTS_N_INSNS (1), /* int signed load */ 108169689Skan COSTS_N_INSNS (1), /* int zeroed load */ 109169689Skan COSTS_N_INSNS (1), /* float load */ 110169689Skan COSTS_N_INSNS (1), /* fmov, fneg, fabs */ 111169689Skan COSTS_N_INSNS (1), /* fadd, fsub */ 112169689Skan COSTS_N_INSNS (1), /* fcmp */ 113169689Skan COSTS_N_INSNS (1), /* fmov, fmovr */ 114169689Skan COSTS_N_INSNS (1), /* fmul */ 115169689Skan COSTS_N_INSNS (8), /* fdivs */ 116169689Skan COSTS_N_INSNS (12), /* fdivd */ 117169689Skan COSTS_N_INSNS (17), /* fsqrts */ 118169689Skan COSTS_N_INSNS (17), /* fsqrtd */ 119169689Skan COSTS_N_INSNS (17), /* imul */ 120169689Skan COSTS_N_INSNS (17), /* imulX */ 121169689Skan 0, /* imul bit factor */ 122169689Skan COSTS_N_INSNS (17), /* idiv */ 123169689Skan COSTS_N_INSNS (17), /* idivX */ 124169689Skan COSTS_N_INSNS (1), /* movcc/movr */ 125169689Skan 0, /* shift penalty */ 126169689Skan}; 127169689Skan 128169689Skanstatic const 129169689Skanstruct processor_costs sparclet_costs = { 130169689Skan COSTS_N_INSNS (3), /* int load */ 131169689Skan COSTS_N_INSNS (3), /* int signed load */ 132169689Skan COSTS_N_INSNS (1), /* int zeroed load */ 133169689Skan COSTS_N_INSNS (1), /* float load */ 134169689Skan COSTS_N_INSNS (1), /* fmov, fneg, fabs */ 135169689Skan COSTS_N_INSNS (1), /* fadd, fsub */ 136169689Skan COSTS_N_INSNS (1), /* fcmp */ 137169689Skan COSTS_N_INSNS (1), /* fmov, fmovr */ 138169689Skan COSTS_N_INSNS (1), /* fmul */ 139169689Skan COSTS_N_INSNS (1), /* fdivs */ 140169689Skan COSTS_N_INSNS (1), /* fdivd */ 141169689Skan COSTS_N_INSNS (1), /* fsqrts */ 142169689Skan COSTS_N_INSNS (1), /* fsqrtd */ 143169689Skan COSTS_N_INSNS (5), /* imul */ 144169689Skan COSTS_N_INSNS (5), /* imulX */ 145169689Skan 0, /* imul bit factor */ 146169689Skan COSTS_N_INSNS (5), /* idiv */ 147169689Skan COSTS_N_INSNS (5), /* idivX */ 148169689Skan COSTS_N_INSNS (1), /* movcc/movr */ 149169689Skan 0, /* shift penalty */ 150169689Skan}; 151169689Skan 152169689Skanstatic const 153169689Skanstruct processor_costs ultrasparc_costs = { 154169689Skan COSTS_N_INSNS (2), /* int load */ 155169689Skan COSTS_N_INSNS (3), /* int signed load */ 156169689Skan COSTS_N_INSNS (2), /* int zeroed load */ 157169689Skan COSTS_N_INSNS (2), /* float load */ 158169689Skan COSTS_N_INSNS (1), /* fmov, fneg, fabs */ 159169689Skan COSTS_N_INSNS (4), /* fadd, fsub */ 160169689Skan COSTS_N_INSNS (1), /* fcmp */ 161169689Skan COSTS_N_INSNS (2), /* fmov, fmovr */ 162169689Skan COSTS_N_INSNS (4), /* fmul */ 163169689Skan COSTS_N_INSNS (13), /* fdivs */ 164169689Skan COSTS_N_INSNS (23), /* fdivd */ 165169689Skan COSTS_N_INSNS (13), /* fsqrts */ 166169689Skan COSTS_N_INSNS (23), /* fsqrtd */ 167169689Skan COSTS_N_INSNS (4), /* imul */ 168169689Skan COSTS_N_INSNS (4), /* imulX */ 169169689Skan 2, /* imul bit factor */ 170169689Skan COSTS_N_INSNS (37), /* idiv */ 171169689Skan COSTS_N_INSNS (68), /* idivX */ 172169689Skan COSTS_N_INSNS (2), /* movcc/movr */ 173169689Skan 2, /* shift penalty */ 174169689Skan}; 175169689Skan 176169689Skanstatic const 177169689Skanstruct processor_costs ultrasparc3_costs = { 178169689Skan COSTS_N_INSNS (2), /* int load */ 179169689Skan COSTS_N_INSNS (3), /* int signed load */ 180169689Skan COSTS_N_INSNS (3), /* int zeroed load */ 181169689Skan COSTS_N_INSNS (2), /* float load */ 182169689Skan COSTS_N_INSNS (3), /* fmov, fneg, fabs */ 183169689Skan COSTS_N_INSNS (4), /* fadd, fsub */ 184169689Skan COSTS_N_INSNS (5), /* fcmp */ 185169689Skan COSTS_N_INSNS (3), /* fmov, fmovr */ 186169689Skan COSTS_N_INSNS (4), /* fmul */ 187169689Skan COSTS_N_INSNS (17), /* fdivs */ 188169689Skan COSTS_N_INSNS (20), /* fdivd */ 189169689Skan COSTS_N_INSNS (20), /* fsqrts */ 190169689Skan COSTS_N_INSNS (29), /* fsqrtd */ 191169689Skan COSTS_N_INSNS (6), /* imul */ 192169689Skan COSTS_N_INSNS (6), /* imulX */ 193169689Skan 0, /* imul bit factor */ 194169689Skan COSTS_N_INSNS (40), /* idiv */ 195169689Skan COSTS_N_INSNS (71), /* idivX */ 196169689Skan COSTS_N_INSNS (2), /* movcc/movr */ 197169689Skan 0, /* shift penalty */ 198169689Skan}; 199169689Skan 200169689Skanstatic const 201169689Skanstruct processor_costs niagara_costs = { 202169689Skan COSTS_N_INSNS (3), /* int load */ 203169689Skan COSTS_N_INSNS (3), /* int signed load */ 204169689Skan COSTS_N_INSNS (3), /* int zeroed load */ 205169689Skan COSTS_N_INSNS (9), /* float load */ 206169689Skan COSTS_N_INSNS (8), /* fmov, fneg, fabs */ 207169689Skan COSTS_N_INSNS (8), /* fadd, fsub */ 208169689Skan COSTS_N_INSNS (26), /* fcmp */ 209169689Skan COSTS_N_INSNS (8), /* fmov, fmovr */ 210169689Skan COSTS_N_INSNS (29), /* fmul */ 211169689Skan COSTS_N_INSNS (54), /* fdivs */ 212169689Skan COSTS_N_INSNS (83), /* fdivd */ 213169689Skan COSTS_N_INSNS (100), /* fsqrts - not implemented in hardware */ 214169689Skan COSTS_N_INSNS (100), /* fsqrtd - not implemented in hardware */ 215169689Skan COSTS_N_INSNS (11), /* imul */ 216169689Skan COSTS_N_INSNS (11), /* imulX */ 217169689Skan 0, /* imul bit factor */ 218169689Skan COSTS_N_INSNS (72), /* idiv */ 219169689Skan COSTS_N_INSNS (72), /* idivX */ 220169689Skan COSTS_N_INSNS (1), /* movcc/movr */ 221169689Skan 0, /* shift penalty */ 222169689Skan}; 223169689Skan 224169689Skanconst struct processor_costs *sparc_costs = &cypress_costs; 225169689Skan 226169689Skan#ifdef HAVE_AS_RELAX_OPTION 227169689Skan/* If 'as' and 'ld' are relaxing tail call insns into branch always, use 228169689Skan "or %o7,%g0,X; call Y; or X,%g0,%o7" always, so that it can be optimized. 229169689Skan With sethi/jmp, neither 'as' nor 'ld' has an easy way how to find out if 230169689Skan somebody does not branch between the sethi and jmp. */ 231169689Skan#define LEAF_SIBCALL_SLOT_RESERVED_P 1 232169689Skan#else 233169689Skan#define LEAF_SIBCALL_SLOT_RESERVED_P \ 234169689Skan ((TARGET_ARCH64 && !TARGET_CM_MEDLOW) || flag_pic) 235169689Skan#endif 236169689Skan 23750397Sobrien/* Global variables for machine-dependent things. */ 23850397Sobrien 23950397Sobrien/* Size of frame. Need to know this to emit return insns from leaf procedures. 240169689Skan ACTUAL_FSIZE is set by sparc_compute_frame_size() which is called during the 241169689Skan reload pass. This is important as the value is later used for scheduling 242169689Skan (to see what can go in a delay slot). 24350397Sobrien APPARENT_FSIZE is the size of the stack less the register save area and less 24450397Sobrien the outgoing argument area. It is used when saving call preserved regs. */ 245132718Skanstatic HOST_WIDE_INT apparent_fsize; 246132718Skanstatic HOST_WIDE_INT actual_fsize; 24750397Sobrien 24896263Sobrien/* Number of live general or floating point registers needed to be 24996263Sobrien saved (as 4-byte quantities). */ 25090075Sobrienstatic int num_gfregs; 25190075Sobrien 252169689Skan/* The alias set for prologue/epilogue register save/restore. */ 253169689Skanstatic GTY(()) int sparc_sr_alias_set; 254169689Skan 255169689Skan/* The alias set for the structure return value. */ 256169689Skanstatic GTY(()) int struct_value_alias_set; 257169689Skan 25850397Sobrien/* Save the operands last given to a compare for use when we 25950397Sobrien generate a scc or bcc insn. */ 260169689Skanrtx sparc_compare_op0, sparc_compare_op1, sparc_compare_emitted; 26150397Sobrien 26296263Sobrien/* Vector to say how input registers are mapped to output registers. 26396263Sobrien HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to 26496263Sobrien eliminate it. You must use -fomit-frame-pointer to get that. */ 26596263Sobrienchar leaf_reg_remap[] = 26650397Sobrien{ 0, 1, 2, 3, 4, 5, 6, 7, 26750397Sobrien -1, -1, -1, -1, -1, -1, 14, -1, 26850397Sobrien -1, -1, -1, -1, -1, -1, -1, -1, 26950397Sobrien 8, 9, 10, 11, 12, 13, -1, 15, 27050397Sobrien 27150397Sobrien 32, 33, 34, 35, 36, 37, 38, 39, 27250397Sobrien 40, 41, 42, 43, 44, 45, 46, 47, 27350397Sobrien 48, 49, 50, 51, 52, 53, 54, 55, 27450397Sobrien 56, 57, 58, 59, 60, 61, 62, 63, 27550397Sobrien 64, 65, 66, 67, 68, 69, 70, 71, 27650397Sobrien 72, 73, 74, 75, 76, 77, 78, 79, 27750397Sobrien 80, 81, 82, 83, 84, 85, 86, 87, 27850397Sobrien 88, 89, 90, 91, 92, 93, 94, 95, 27950397Sobrien 96, 97, 98, 99, 100}; 28050397Sobrien 28190075Sobrien/* Vector, indexed by hard register number, which contains 1 28290075Sobrien for a register that is allowable in a candidate for leaf 28390075Sobrien function treatment. */ 28490075Sobrienchar sparc_leaf_regs[] = 28590075Sobrien{ 1, 1, 1, 1, 1, 1, 1, 1, 28690075Sobrien 0, 0, 0, 0, 0, 0, 1, 0, 28790075Sobrien 0, 0, 0, 0, 0, 0, 0, 0, 28890075Sobrien 1, 1, 1, 1, 1, 1, 0, 1, 28990075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 29090075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 29190075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 29290075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 29390075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 29490075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 29590075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 29690075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 29790075Sobrien 1, 1, 1, 1, 1}; 29890075Sobrien 299132718Skanstruct machine_function GTY(()) 300132718Skan{ 301132718Skan /* Some local-dynamic TLS symbol name. */ 302132718Skan const char *some_ld_name; 303169689Skan 304169689Skan /* True if the current function is leaf and uses only leaf regs, 305169689Skan so that the SPARC leaf function optimization can be applied. 306169689Skan Private version of current_function_uses_only_leaf_regs, see 307169689Skan sparc_expand_prologue for the rationale. */ 308169689Skan int leaf_function_p; 309169689Skan 310169689Skan /* True if the data calculated by sparc_expand_prologue are valid. */ 311169689Skan bool prologue_data_valid_p; 312132718Skan}; 313132718Skan 314169689Skan#define sparc_leaf_function_p cfun->machine->leaf_function_p 315169689Skan#define sparc_prologue_data_valid_p cfun->machine->prologue_data_valid_p 31650397Sobrien 317169689Skan/* Register we pretend to think the frame pointer is allocated to. 318169689Skan Normally, this is %fp, but if we are in a leaf procedure, this 319169689Skan is %sp+"something". We record "something" separately as it may 320169689Skan be too big for reg+constant addressing. */ 321169689Skanstatic rtx frame_base_reg; 322132718Skanstatic HOST_WIDE_INT frame_base_offset; 32350397Sobrien 324169689Skan/* 1 if the next opcode is to be specially indented. */ 325169689Skanint sparc_indent_opcode = 0; 326169689Skan 327169689Skanstatic bool sparc_handle_option (size_t, const char *, int); 328132718Skanstatic void sparc_init_modes (void); 329132718Skanstatic void scan_record_type (tree, int *, int *, int *); 330132718Skanstatic int function_arg_slotno (const CUMULATIVE_ARGS *, enum machine_mode, 331132718Skan tree, int, int, int *, int *); 33250397Sobrien 333132718Skanstatic int supersparc_adjust_cost (rtx, rtx, rtx, int); 334132718Skanstatic int hypersparc_adjust_cost (rtx, rtx, rtx, int); 33552284Sobrien 336132718Skanstatic void sparc_output_addr_vec (rtx); 337132718Skanstatic void sparc_output_addr_diff_vec (rtx); 338132718Skanstatic void sparc_output_deferred_case_vectors (void); 339169689Skanstatic rtx sparc_builtin_saveregs (void); 340132718Skanstatic int epilogue_renumber (rtx *, int); 341132718Skanstatic bool sparc_assemble_integer (rtx, unsigned int, int); 342132718Skanstatic int set_extends (rtx); 343169689Skanstatic void emit_pic_helper (void); 344169689Skanstatic void load_pic_register (bool); 345169689Skanstatic int save_or_restore_regs (int, int, rtx, int, int); 346169689Skanstatic void emit_save_or_restore_regs (int); 347169689Skanstatic void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT); 348169689Skanstatic void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT); 34990075Sobrien#ifdef OBJECT_FORMAT_ELF 350169689Skanstatic void sparc_elf_asm_named_section (const char *, unsigned int, tree); 35190075Sobrien#endif 35252284Sobrien 353132718Skanstatic int sparc_adjust_cost (rtx, rtx, rtx, int); 354132718Skanstatic int sparc_issue_rate (void); 355132718Skanstatic void sparc_sched_init (FILE *, int, int); 356132718Skanstatic int sparc_use_sched_lookahead (void); 35796263Sobrien 358132718Skanstatic void emit_soft_tfmode_libcall (const char *, int, rtx *); 359132718Skanstatic void emit_soft_tfmode_binop (enum rtx_code, rtx *); 360132718Skanstatic void emit_soft_tfmode_unop (enum rtx_code, rtx *); 361132718Skanstatic void emit_soft_tfmode_cvt (enum rtx_code, rtx *); 362132718Skanstatic void emit_hard_tfmode_operation (enum rtx_code, rtx *); 363117395Skan 364132718Skanstatic bool sparc_function_ok_for_sibcall (tree, tree); 365132718Skanstatic void sparc_init_libfuncs (void); 366169689Skanstatic void sparc_init_builtins (void); 367169689Skanstatic void sparc_vis_init_builtins (void); 368169689Skanstatic rtx sparc_expand_builtin (tree, rtx, rtx, enum machine_mode, int); 369169689Skanstatic tree sparc_fold_builtin (tree, tree, bool); 370169689Skanstatic int sparc_vis_mul8x16 (int, int); 371169689Skanstatic tree sparc_handle_vis_mul8x16 (int, tree, tree, tree); 372132718Skanstatic void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, 373132718Skan HOST_WIDE_INT, tree); 374146895Skanstatic bool sparc_can_output_mi_thunk (tree, HOST_WIDE_INT, 375146895Skan HOST_WIDE_INT, tree); 376132718Skanstatic struct machine_function * sparc_init_machine_status (void); 377132718Skanstatic bool sparc_cannot_force_const_mem (rtx); 378132718Skanstatic rtx sparc_tls_get_addr (void); 379132718Skanstatic rtx sparc_tls_got (void); 380132718Skanstatic const char *get_some_local_dynamic_name (void); 381132718Skanstatic int get_some_local_dynamic_name_1 (rtx *, void *); 382132718Skanstatic bool sparc_rtx_costs (rtx, int, int, int *); 383169689Skanstatic bool sparc_promote_prototypes (tree); 384169689Skanstatic rtx sparc_struct_value_rtx (tree, int); 385169689Skanstatic bool sparc_return_in_memory (tree, tree); 386169689Skanstatic bool sparc_strict_argument_naming (CUMULATIVE_ARGS *); 387169689Skanstatic tree sparc_gimplify_va_arg (tree, tree, tree *, tree *); 388169689Skanstatic bool sparc_vector_mode_supported_p (enum machine_mode); 389169689Skanstatic bool sparc_pass_by_reference (CUMULATIVE_ARGS *, 390169689Skan enum machine_mode, tree, bool); 391169689Skanstatic int sparc_arg_partial_bytes (CUMULATIVE_ARGS *, 392169689Skan enum machine_mode, tree, bool); 393169689Skanstatic void sparc_dwarf_handle_frame_unspec (const char *, rtx, int); 394169689Skanstatic void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED; 395169689Skanstatic void sparc_file_end (void); 396169689Skan#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING 397169689Skanstatic const char *sparc_mangle_fundamental_type (tree); 398169689Skan#endif 399169689Skan#ifdef SUBTARGET_ATTRIBUTE_TABLE 400169689Skanconst struct attribute_spec sparc_attribute_table[]; 401169689Skan#endif 40250397Sobrien 40350397Sobrien/* Option handling. */ 40450397Sobrien 40550397Sobrien/* Parsed value. */ 40650397Sobrienenum cmodel sparc_cmodel; 40750397Sobrien 40890075Sobrienchar sparc_hard_reg_printed[8]; 40950397Sobrien 41050397Sobrienstruct sparc_cpu_select sparc_select[] = 41150397Sobrien{ 41250397Sobrien /* switch name, tune arch */ 41350397Sobrien { (char *)0, "default", 1, 1 }, 41450397Sobrien { (char *)0, "-mcpu=", 1, 1 }, 41550397Sobrien { (char *)0, "-mtune=", 1, 0 }, 41650397Sobrien { 0, 0, 0, 0 } 41750397Sobrien}; 41850397Sobrien 41950397Sobrien/* CPU type. This is set from TARGET_CPU_DEFAULT and -m{cpu,tune}=xxx. */ 42050397Sobrienenum processor_type sparc_cpu; 421169689Skan 422169689Skan/* Whetheran FPU option was specified. */ 423169689Skanstatic bool fpu_option_set = false; 424169689Skan 42590075Sobrien/* Initialize the GCC target structure. */ 42650397Sobrien 42790075Sobrien/* The sparc default is to use .half rather than .short for aligned 42890075Sobrien HI objects. Use .word instead of .long on non-ELF systems. */ 42990075Sobrien#undef TARGET_ASM_ALIGNED_HI_OP 43090075Sobrien#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" 43190075Sobrien#ifndef OBJECT_FORMAT_ELF 43290075Sobrien#undef TARGET_ASM_ALIGNED_SI_OP 43390075Sobrien#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" 43490075Sobrien#endif 43590075Sobrien 43690075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP 43790075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\t.uahalf\t" 43890075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP 43990075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\t.uaword\t" 44090075Sobrien#undef TARGET_ASM_UNALIGNED_DI_OP 44190075Sobrien#define TARGET_ASM_UNALIGNED_DI_OP "\t.uaxword\t" 44290075Sobrien 44390075Sobrien/* The target hook has to handle DI-mode values. */ 44490075Sobrien#undef TARGET_ASM_INTEGER 44590075Sobrien#define TARGET_ASM_INTEGER sparc_assemble_integer 44690075Sobrien 44790075Sobrien#undef TARGET_ASM_FUNCTION_PROLOGUE 448169689Skan#define TARGET_ASM_FUNCTION_PROLOGUE sparc_asm_function_prologue 44990075Sobrien#undef TARGET_ASM_FUNCTION_EPILOGUE 450169689Skan#define TARGET_ASM_FUNCTION_EPILOGUE sparc_asm_function_epilogue 45190075Sobrien 45290075Sobrien#undef TARGET_SCHED_ADJUST_COST 45390075Sobrien#define TARGET_SCHED_ADJUST_COST sparc_adjust_cost 45490075Sobrien#undef TARGET_SCHED_ISSUE_RATE 45590075Sobrien#define TARGET_SCHED_ISSUE_RATE sparc_issue_rate 45690075Sobrien#undef TARGET_SCHED_INIT 45790075Sobrien#define TARGET_SCHED_INIT sparc_sched_init 458117395Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD 459117395Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead 46090075Sobrien 461132718Skan#undef TARGET_FUNCTION_OK_FOR_SIBCALL 462132718Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL sparc_function_ok_for_sibcall 463117395Skan 464132718Skan#undef TARGET_INIT_LIBFUNCS 465132718Skan#define TARGET_INIT_LIBFUNCS sparc_init_libfuncs 466169689Skan#undef TARGET_INIT_BUILTINS 467169689Skan#define TARGET_INIT_BUILTINS sparc_init_builtins 468132718Skan 469169689Skan#undef TARGET_EXPAND_BUILTIN 470169689Skan#define TARGET_EXPAND_BUILTIN sparc_expand_builtin 471169689Skan#undef TARGET_FOLD_BUILTIN 472169689Skan#define TARGET_FOLD_BUILTIN sparc_fold_builtin 473169689Skan 474169689Skan#if TARGET_TLS 475132718Skan#undef TARGET_HAVE_TLS 476132718Skan#define TARGET_HAVE_TLS true 477132718Skan#endif 478169689Skan 479132718Skan#undef TARGET_CANNOT_FORCE_CONST_MEM 480132718Skan#define TARGET_CANNOT_FORCE_CONST_MEM sparc_cannot_force_const_mem 481132718Skan 482117395Skan#undef TARGET_ASM_OUTPUT_MI_THUNK 483117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk 484117395Skan#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK 485146895Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK sparc_can_output_mi_thunk 486117395Skan 487132718Skan#undef TARGET_RTX_COSTS 488132718Skan#define TARGET_RTX_COSTS sparc_rtx_costs 489132718Skan#undef TARGET_ADDRESS_COST 490132718Skan#define TARGET_ADDRESS_COST hook_int_rtx_0 491132718Skan 492169689Skan/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a 493169689Skan no-op for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime 494169689Skan test for this value. */ 495169689Skan#undef TARGET_PROMOTE_FUNCTION_ARGS 496169689Skan#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true 497169689Skan 498169689Skan/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a 499169689Skan no-op for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime 500169689Skan test for this value. */ 501169689Skan#undef TARGET_PROMOTE_FUNCTION_RETURN 502169689Skan#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true 503169689Skan 504169689Skan#undef TARGET_PROMOTE_PROTOTYPES 505169689Skan#define TARGET_PROMOTE_PROTOTYPES sparc_promote_prototypes 506169689Skan 507169689Skan#undef TARGET_STRUCT_VALUE_RTX 508169689Skan#define TARGET_STRUCT_VALUE_RTX sparc_struct_value_rtx 509169689Skan#undef TARGET_RETURN_IN_MEMORY 510169689Skan#define TARGET_RETURN_IN_MEMORY sparc_return_in_memory 511169689Skan#undef TARGET_MUST_PASS_IN_STACK 512169689Skan#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size 513169689Skan#undef TARGET_PASS_BY_REFERENCE 514169689Skan#define TARGET_PASS_BY_REFERENCE sparc_pass_by_reference 515169689Skan#undef TARGET_ARG_PARTIAL_BYTES 516169689Skan#define TARGET_ARG_PARTIAL_BYTES sparc_arg_partial_bytes 517169689Skan 518169689Skan#undef TARGET_EXPAND_BUILTIN_SAVEREGS 519169689Skan#define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs 520169689Skan#undef TARGET_STRICT_ARGUMENT_NAMING 521169689Skan#define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming 522169689Skan 523169689Skan#undef TARGET_GIMPLIFY_VA_ARG_EXPR 524169689Skan#define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg 525169689Skan 526169689Skan#undef TARGET_VECTOR_MODE_SUPPORTED_P 527169689Skan#define TARGET_VECTOR_MODE_SUPPORTED_P sparc_vector_mode_supported_p 528169689Skan 529169689Skan#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC 530169689Skan#define TARGET_DWARF_HANDLE_FRAME_UNSPEC sparc_dwarf_handle_frame_unspec 531169689Skan 532169689Skan#ifdef SUBTARGET_INSERT_ATTRIBUTES 533169689Skan#undef TARGET_INSERT_ATTRIBUTES 534169689Skan#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES 535169689Skan#endif 536169689Skan 537169689Skan#ifdef SUBTARGET_ATTRIBUTE_TABLE 538169689Skan#undef TARGET_ATTRIBUTE_TABLE 539169689Skan#define TARGET_ATTRIBUTE_TABLE sparc_attribute_table 540169689Skan#endif 541169689Skan 542169689Skan#undef TARGET_RELAXED_ORDERING 543169689Skan#define TARGET_RELAXED_ORDERING SPARC_RELAXED_ORDERING 544169689Skan 545169689Skan#undef TARGET_DEFAULT_TARGET_FLAGS 546169689Skan#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT 547169689Skan#undef TARGET_HANDLE_OPTION 548169689Skan#define TARGET_HANDLE_OPTION sparc_handle_option 549169689Skan 550169689Skan#if TARGET_GNU_TLS 551169689Skan#undef TARGET_ASM_OUTPUT_DWARF_DTPREL 552169689Skan#define TARGET_ASM_OUTPUT_DWARF_DTPREL sparc_output_dwarf_dtprel 553169689Skan#endif 554169689Skan 555169689Skan#undef TARGET_ASM_FILE_END 556169689Skan#define TARGET_ASM_FILE_END sparc_file_end 557169689Skan 558169689Skan#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING 559169689Skan#undef TARGET_MANGLE_FUNDAMENTAL_TYPE 560169689Skan#define TARGET_MANGLE_FUNDAMENTAL_TYPE sparc_mangle_fundamental_type 561169689Skan#endif 562169689Skan 56390075Sobrienstruct gcc_target targetm = TARGET_INITIALIZER; 564169689Skan 565169689Skan/* Implement TARGET_HANDLE_OPTION. */ 566169689Skan 567169689Skanstatic bool 568169689Skansparc_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED) 569169689Skan{ 570169689Skan switch (code) 571169689Skan { 572169689Skan case OPT_mfpu: 573169689Skan case OPT_mhard_float: 574169689Skan case OPT_msoft_float: 575169689Skan fpu_option_set = true; 576169689Skan break; 577169689Skan 578169689Skan case OPT_mcpu_: 579169689Skan sparc_select[1].string = arg; 580169689Skan break; 581169689Skan 582169689Skan case OPT_mtune_: 583169689Skan sparc_select[2].string = arg; 584169689Skan break; 585169689Skan } 586169689Skan 587169689Skan return true; 588169689Skan} 589169689Skan 59050397Sobrien/* Validate and override various options, and do some machine dependent 59150397Sobrien initialization. */ 59250397Sobrien 59350397Sobrienvoid 594132718Skansparc_override_options (void) 59550397Sobrien{ 59650397Sobrien static struct code_model { 59790075Sobrien const char *const name; 59890075Sobrien const int value; 59990075Sobrien } const cmodels[] = { 60050397Sobrien { "32", CM_32 }, 60150397Sobrien { "medlow", CM_MEDLOW }, 60250397Sobrien { "medmid", CM_MEDMID }, 60350397Sobrien { "medany", CM_MEDANY }, 60450397Sobrien { "embmedany", CM_EMBMEDANY }, 60550397Sobrien { 0, 0 } 60650397Sobrien }; 60790075Sobrien const struct code_model *cmodel; 60850397Sobrien /* Map TARGET_CPU_DEFAULT to value for -m{arch,tune}=. */ 60950397Sobrien static struct cpu_default { 61090075Sobrien const int cpu; 61190075Sobrien const char *const name; 61290075Sobrien } const cpu_default[] = { 61350397Sobrien /* There must be one entry here for each TARGET_CPU value. */ 61450397Sobrien { TARGET_CPU_sparc, "cypress" }, 61550397Sobrien { TARGET_CPU_sparclet, "tsc701" }, 61650397Sobrien { TARGET_CPU_sparclite, "f930" }, 61750397Sobrien { TARGET_CPU_v8, "v8" }, 61852284Sobrien { TARGET_CPU_hypersparc, "hypersparc" }, 61952284Sobrien { TARGET_CPU_sparclite86x, "sparclite86x" }, 62050397Sobrien { TARGET_CPU_supersparc, "supersparc" }, 62150397Sobrien { TARGET_CPU_v9, "v9" }, 62250397Sobrien { TARGET_CPU_ultrasparc, "ultrasparc" }, 623117395Skan { TARGET_CPU_ultrasparc3, "ultrasparc3" }, 624169689Skan { TARGET_CPU_niagara, "niagara" }, 62550397Sobrien { 0, 0 } 62650397Sobrien }; 62790075Sobrien const struct cpu_default *def; 62850397Sobrien /* Table of values for -m{cpu,tune}=. */ 62950397Sobrien static struct cpu_table { 63090075Sobrien const char *const name; 63190075Sobrien const enum processor_type processor; 63290075Sobrien const int disable; 63390075Sobrien const int enable; 63490075Sobrien } const cpu_table[] = { 63550397Sobrien { "v7", PROCESSOR_V7, MASK_ISA, 0 }, 63650397Sobrien { "cypress", PROCESSOR_CYPRESS, MASK_ISA, 0 }, 63750397Sobrien { "v8", PROCESSOR_V8, MASK_ISA, MASK_V8 }, 63850397Sobrien /* TI TMS390Z55 supersparc */ 63950397Sobrien { "supersparc", PROCESSOR_SUPERSPARC, MASK_ISA, MASK_V8 }, 64050397Sobrien { "sparclite", PROCESSOR_SPARCLITE, MASK_ISA, MASK_SPARCLITE }, 64150397Sobrien /* The Fujitsu MB86930 is the original sparclite chip, with no fpu. 64250397Sobrien The Fujitsu MB86934 is the recent sparclite chip, with an fpu. */ 64350397Sobrien { "f930", PROCESSOR_F930, MASK_ISA|MASK_FPU, MASK_SPARCLITE }, 64450397Sobrien { "f934", PROCESSOR_F934, MASK_ISA, MASK_SPARCLITE|MASK_FPU }, 64552284Sobrien { "hypersparc", PROCESSOR_HYPERSPARC, MASK_ISA, MASK_V8|MASK_FPU }, 64690075Sobrien { "sparclite86x", PROCESSOR_SPARCLITE86X, MASK_ISA|MASK_FPU, 64790075Sobrien MASK_SPARCLITE }, 64850397Sobrien { "sparclet", PROCESSOR_SPARCLET, MASK_ISA, MASK_SPARCLET }, 64950397Sobrien /* TEMIC sparclet */ 65050397Sobrien { "tsc701", PROCESSOR_TSC701, MASK_ISA, MASK_SPARCLET }, 65150397Sobrien { "v9", PROCESSOR_V9, MASK_ISA, MASK_V9 }, 65290075Sobrien /* TI ultrasparc I, II, IIi */ 65390075Sobrien { "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, MASK_V9 65490075Sobrien /* Although insns using %y are deprecated, it is a clear win on current 65590075Sobrien ultrasparcs. */ 65690075Sobrien |MASK_DEPRECATED_V8_INSNS}, 657117395Skan /* TI ultrasparc III */ 658117395Skan /* ??? Check if %y issue still holds true in ultra3. */ 659117395Skan { "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS}, 660169689Skan /* UltraSPARC T1 */ 661169689Skan { "niagara", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS}, 66250397Sobrien { 0, 0, 0, 0 } 66350397Sobrien }; 66490075Sobrien const struct cpu_table *cpu; 66590075Sobrien const struct sparc_cpu_select *sel; 66650397Sobrien int fpu; 66752284Sobrien 66850397Sobrien#ifndef SPARC_BI_ARCH 66950397Sobrien /* Check for unsupported architecture size. */ 67050397Sobrien if (! TARGET_64BIT != DEFAULT_ARCH32_P) 67190075Sobrien error ("%s is not supported by this configuration", 67290075Sobrien DEFAULT_ARCH32_P ? "-m64" : "-m32"); 67350397Sobrien#endif 67450397Sobrien 67590075Sobrien /* We force all 64bit archs to use 128 bit long double */ 67690075Sobrien if (TARGET_64BIT && ! TARGET_LONG_DOUBLE_128) 67752284Sobrien { 67890075Sobrien error ("-mlong-double-64 not allowed with -m64"); 67990075Sobrien target_flags |= MASK_LONG_DOUBLE_128; 68052284Sobrien } 68152284Sobrien 68250397Sobrien /* Code model selection. */ 68350397Sobrien sparc_cmodel = SPARC_DEFAULT_CMODEL; 68452284Sobrien 68552284Sobrien#ifdef SPARC_BI_ARCH 68652284Sobrien if (TARGET_ARCH32) 68752284Sobrien sparc_cmodel = CM_32; 68852284Sobrien#endif 68952284Sobrien 69050397Sobrien if (sparc_cmodel_string != NULL) 69150397Sobrien { 69250397Sobrien if (TARGET_ARCH64) 69350397Sobrien { 69450397Sobrien for (cmodel = &cmodels[0]; cmodel->name; cmodel++) 69550397Sobrien if (strcmp (sparc_cmodel_string, cmodel->name) == 0) 69650397Sobrien break; 69750397Sobrien if (cmodel->name == NULL) 69850397Sobrien error ("bad value (%s) for -mcmodel= switch", sparc_cmodel_string); 69950397Sobrien else 70050397Sobrien sparc_cmodel = cmodel->value; 70150397Sobrien } 70250397Sobrien else 70350397Sobrien error ("-mcmodel= is not supported on 32 bit systems"); 70450397Sobrien } 70550397Sobrien 706171825Skan fpu = target_flags & MASK_FPU; /* save current -mfpu status */ 70750397Sobrien 70850397Sobrien /* Set the default CPU. */ 70950397Sobrien for (def = &cpu_default[0]; def->name; ++def) 71050397Sobrien if (def->cpu == TARGET_CPU_DEFAULT) 71150397Sobrien break; 712169689Skan gcc_assert (def->name); 71350397Sobrien sparc_select[0].string = def->name; 71450397Sobrien 71550397Sobrien for (sel = &sparc_select[0]; sel->name; ++sel) 71650397Sobrien { 71750397Sobrien if (sel->string) 71850397Sobrien { 71950397Sobrien for (cpu = &cpu_table[0]; cpu->name; ++cpu) 72050397Sobrien if (! strcmp (sel->string, cpu->name)) 72150397Sobrien { 72250397Sobrien if (sel->set_tune_p) 72350397Sobrien sparc_cpu = cpu->processor; 72450397Sobrien 72550397Sobrien if (sel->set_arch_p) 72650397Sobrien { 72750397Sobrien target_flags &= ~cpu->disable; 72850397Sobrien target_flags |= cpu->enable; 72950397Sobrien } 73050397Sobrien break; 73150397Sobrien } 73250397Sobrien 73350397Sobrien if (! cpu->name) 73450397Sobrien error ("bad value (%s) for %s switch", sel->string, sel->name); 73550397Sobrien } 73650397Sobrien } 73750397Sobrien 73850397Sobrien /* If -mfpu or -mno-fpu was explicitly used, don't override with 739169689Skan the processor default. */ 740169689Skan if (fpu_option_set) 741169689Skan target_flags = (target_flags & ~MASK_FPU) | fpu; 74250397Sobrien 74390075Sobrien /* Don't allow -mvis if FPU is disabled. */ 74490075Sobrien if (! TARGET_FPU) 74590075Sobrien target_flags &= ~MASK_VIS; 74690075Sobrien 74790075Sobrien /* -mvis assumes UltraSPARC+, so we are sure v9 instructions 74890075Sobrien are available. 74990075Sobrien -m64 also implies v9. */ 75090075Sobrien if (TARGET_VIS || TARGET_ARCH64) 75190075Sobrien { 75290075Sobrien target_flags |= MASK_V9; 75390075Sobrien target_flags &= ~(MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE); 75490075Sobrien } 75590075Sobrien 75650397Sobrien /* Use the deprecated v8 insns for sparc64 in 32 bit mode. */ 75750397Sobrien if (TARGET_V9 && TARGET_ARCH32) 75850397Sobrien target_flags |= MASK_DEPRECATED_V8_INSNS; 75950397Sobrien 76052284Sobrien /* V8PLUS requires V9, makes no sense in 64 bit mode. */ 76152284Sobrien if (! TARGET_V9 || TARGET_ARCH64) 76250397Sobrien target_flags &= ~MASK_V8PLUS; 76350397Sobrien 76450397Sobrien /* Don't use stack biasing in 32 bit mode. */ 76550397Sobrien if (TARGET_ARCH32) 76650397Sobrien target_flags &= ~MASK_STACK_BIAS; 76752284Sobrien 76890075Sobrien /* Supply a default value for align_functions. */ 769117395Skan if (align_functions == 0 770117395Skan && (sparc_cpu == PROCESSOR_ULTRASPARC 771169689Skan || sparc_cpu == PROCESSOR_ULTRASPARC3 772169689Skan || sparc_cpu == PROCESSOR_NIAGARA)) 77390075Sobrien align_functions = 32; 77450397Sobrien 77550397Sobrien /* Validate PCC_STRUCT_RETURN. */ 77650397Sobrien if (flag_pcc_struct_return == DEFAULT_PCC_STRUCT_RETURN) 77750397Sobrien flag_pcc_struct_return = (TARGET_ARCH64 ? 0 : 1); 77850397Sobrien 77990075Sobrien /* Only use .uaxword when compiling for a 64-bit target. */ 78090075Sobrien if (!TARGET_ARCH64) 78190075Sobrien targetm.asm_out.unaligned_op.di = NULL; 78290075Sobrien 78350397Sobrien /* Do various machine dependent initializations. */ 78450397Sobrien sparc_init_modes (); 785132718Skan 786169689Skan /* Acquire unique alias sets for our private stuff. */ 787169689Skan sparc_sr_alias_set = new_alias_set (); 788169689Skan struct_value_alias_set = new_alias_set (); 789169689Skan 790132718Skan /* Set up function hooks. */ 791132718Skan init_machine_status = sparc_init_machine_status; 792169689Skan 793169689Skan switch (sparc_cpu) 794169689Skan { 795169689Skan case PROCESSOR_V7: 796169689Skan case PROCESSOR_CYPRESS: 797169689Skan sparc_costs = &cypress_costs; 798169689Skan break; 799169689Skan case PROCESSOR_V8: 800169689Skan case PROCESSOR_SPARCLITE: 801169689Skan case PROCESSOR_SUPERSPARC: 802169689Skan sparc_costs = &supersparc_costs; 803169689Skan break; 804169689Skan case PROCESSOR_F930: 805169689Skan case PROCESSOR_F934: 806169689Skan case PROCESSOR_HYPERSPARC: 807169689Skan case PROCESSOR_SPARCLITE86X: 808169689Skan sparc_costs = &hypersparc_costs; 809169689Skan break; 810169689Skan case PROCESSOR_SPARCLET: 811169689Skan case PROCESSOR_TSC701: 812169689Skan sparc_costs = &sparclet_costs; 813169689Skan break; 814169689Skan case PROCESSOR_V9: 815169689Skan case PROCESSOR_ULTRASPARC: 816169689Skan sparc_costs = &ultrasparc_costs; 817169689Skan break; 818169689Skan case PROCESSOR_ULTRASPARC3: 819169689Skan sparc_costs = &ultrasparc3_costs; 820169689Skan break; 821169689Skan case PROCESSOR_NIAGARA: 822169689Skan sparc_costs = &niagara_costs; 823169689Skan break; 824169689Skan }; 825169689Skan 826169689Skan#ifdef TARGET_DEFAULT_LONG_DOUBLE_128 827169689Skan if (!(target_flags_explicit & MASK_LONG_DOUBLE_128)) 828169689Skan target_flags |= MASK_LONG_DOUBLE_128; 829169689Skan#endif 83050397Sobrien} 83150397Sobrien 832169689Skan#ifdef SUBTARGET_ATTRIBUTE_TABLE 833169689Skan/* Table of valid machine attributes. */ 834169689Skanconst struct attribute_spec sparc_attribute_table[] = 835169689Skan{ 836169689Skan /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ 837169689Skan SUBTARGET_ATTRIBUTE_TABLE, 838169689Skan { NULL, 0, 0, false, false, false, NULL } 839169689Skan}; 840169689Skan#endif 841169689Skan 84250397Sobrien/* Miscellaneous utilities. */ 84350397Sobrien 84450397Sobrien/* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move 84550397Sobrien or branch on register contents instructions. */ 84650397Sobrien 84750397Sobrienint 848132718Skanv9_regcmp_p (enum rtx_code code) 84950397Sobrien{ 85050397Sobrien return (code == EQ || code == NE || code == GE || code == LT 85150397Sobrien || code == LE || code == GT); 85250397Sobrien} 85350397Sobrien 85490075Sobrien/* Nonzero if OP is a floating point constant which can 85590075Sobrien be loaded into an integer register using a single 85690075Sobrien sethi instruction. */ 85790075Sobrien 85890075Sobrienint 859132718Skanfp_sethi_p (rtx op) 86090075Sobrien{ 86190075Sobrien if (GET_CODE (op) == CONST_DOUBLE) 86290075Sobrien { 86390075Sobrien REAL_VALUE_TYPE r; 86490075Sobrien long i; 86590075Sobrien 86690075Sobrien REAL_VALUE_FROM_CONST_DOUBLE (r, op); 86790075Sobrien REAL_VALUE_TO_TARGET_SINGLE (r, i); 868169689Skan return !SPARC_SIMM13_P (i) && SPARC_SETHI_P (i); 86990075Sobrien } 87090075Sobrien 87190075Sobrien return 0; 87250397Sobrien} 87350397Sobrien 87490075Sobrien/* Nonzero if OP is a floating point constant which can 87590075Sobrien be loaded into an integer register using a single 87690075Sobrien mov instruction. */ 87790075Sobrien 87890075Sobrienint 879132718Skanfp_mov_p (rtx op) 88090075Sobrien{ 88190075Sobrien if (GET_CODE (op) == CONST_DOUBLE) 88290075Sobrien { 88390075Sobrien REAL_VALUE_TYPE r; 88490075Sobrien long i; 88590075Sobrien 88690075Sobrien REAL_VALUE_FROM_CONST_DOUBLE (r, op); 88790075Sobrien REAL_VALUE_TO_TARGET_SINGLE (r, i); 888169689Skan return SPARC_SIMM13_P (i); 88990075Sobrien } 89090075Sobrien 89190075Sobrien return 0; 89290075Sobrien} 89390075Sobrien 89490075Sobrien/* Nonzero if OP is a floating point constant which can 89590075Sobrien be loaded into an integer register using a high/losum 89690075Sobrien instruction sequence. */ 89790075Sobrien 89890075Sobrienint 899132718Skanfp_high_losum_p (rtx op) 90090075Sobrien{ 90190075Sobrien /* The constraints calling this should only be in 90290075Sobrien SFmode move insns, so any constant which cannot 90390075Sobrien be moved using a single insn will do. */ 90490075Sobrien if (GET_CODE (op) == CONST_DOUBLE) 90590075Sobrien { 90690075Sobrien REAL_VALUE_TYPE r; 90790075Sobrien long i; 90890075Sobrien 90990075Sobrien REAL_VALUE_FROM_CONST_DOUBLE (r, op); 91090075Sobrien REAL_VALUE_TO_TARGET_SINGLE (r, i); 911169689Skan return !SPARC_SIMM13_P (i) && !SPARC_SETHI_P (i); 91290075Sobrien } 91390075Sobrien 91490075Sobrien return 0; 91590075Sobrien} 91690075Sobrien 917169689Skan/* Expand a move instruction. Return true if all work is done. */ 91850397Sobrien 919169689Skanbool 920169689Skansparc_expand_move (enum machine_mode mode, rtx *operands) 92150397Sobrien{ 922169689Skan /* Handle sets of MEM first. */ 923169689Skan if (GET_CODE (operands[0]) == MEM) 924169689Skan { 925169689Skan /* 0 is a register (or a pair of registers) on SPARC. */ 926169689Skan if (register_or_zero_operand (operands[1], mode)) 927169689Skan return false; 92850397Sobrien 929169689Skan if (!reload_in_progress) 930169689Skan { 931169689Skan operands[0] = validize_mem (operands[0]); 932169689Skan operands[1] = force_reg (mode, operands[1]); 933169689Skan } 934169689Skan } 93550397Sobrien 936169689Skan /* Fixup TLS cases. */ 937169689Skan if (TARGET_HAVE_TLS 938169689Skan && CONSTANT_P (operands[1]) 939169689Skan && GET_CODE (operands[1]) != HIGH 940169689Skan && sparc_tls_referenced_p (operands [1])) 941169689Skan { 942169689Skan rtx sym = operands[1]; 943169689Skan rtx addend = NULL; 94450397Sobrien 945169689Skan if (GET_CODE (sym) == CONST && GET_CODE (XEXP (sym, 0)) == PLUS) 946169689Skan { 947169689Skan addend = XEXP (XEXP (sym, 0), 1); 948169689Skan sym = XEXP (XEXP (sym, 0), 0); 949169689Skan } 95050397Sobrien 951169689Skan gcc_assert (SPARC_SYMBOL_REF_TLS_P (sym)); 95250397Sobrien 953169689Skan sym = legitimize_tls_address (sym); 954169689Skan if (addend) 955169689Skan { 956169689Skan sym = gen_rtx_PLUS (mode, sym, addend); 957169689Skan sym = force_operand (sym, operands[0]); 958169689Skan } 959169689Skan operands[1] = sym; 960169689Skan } 961169689Skan 962169689Skan /* Fixup PIC cases. */ 963169689Skan if (flag_pic && CONSTANT_P (operands[1])) 964169689Skan { 965169689Skan if (pic_address_needs_scratch (operands[1])) 966169689Skan operands[1] = legitimize_pic_address (operands[1], mode, 0); 96796263Sobrien 968169689Skan if (GET_CODE (operands[1]) == LABEL_REF && mode == SImode) 969169689Skan { 970169689Skan emit_insn (gen_movsi_pic_label_ref (operands[0], operands[1])); 971169689Skan return true; 972169689Skan } 97396263Sobrien 974169689Skan if (GET_CODE (operands[1]) == LABEL_REF && mode == DImode) 975169689Skan { 976169689Skan gcc_assert (TARGET_ARCH64); 977169689Skan emit_insn (gen_movdi_pic_label_ref (operands[0], operands[1])); 978169689Skan return true; 979169689Skan } 98096263Sobrien 981169689Skan if (symbolic_operand (operands[1], mode)) 982169689Skan { 983169689Skan operands[1] = legitimize_pic_address (operands[1], 984169689Skan mode, 985169689Skan (reload_in_progress ? 986169689Skan operands[0] : 987169689Skan NULL_RTX)); 988169689Skan return false; 989169689Skan } 99050397Sobrien } 99150397Sobrien 992169689Skan /* If we are trying to toss an integer constant into FP registers, 993169689Skan or loading a FP or vector constant, force it into memory. */ 994169689Skan if (CONSTANT_P (operands[1]) 995169689Skan && REG_P (operands[0]) 996169689Skan && (SPARC_FP_REG_P (REGNO (operands[0])) 997169689Skan || SCALAR_FLOAT_MODE_P (mode) 998169689Skan || VECTOR_MODE_P (mode))) 99950397Sobrien { 1000169689Skan /* emit_group_store will send such bogosity to us when it is 1001169689Skan not storing directly into memory. So fix this up to avoid 1002169689Skan crashes in output_constant_pool. */ 1003169689Skan if (operands [1] == const0_rtx) 1004169689Skan operands[1] = CONST0_RTX (mode); 1005132718Skan 1006169689Skan /* We can clear FP registers if TARGET_VIS, and always other regs. */ 1007169689Skan if ((TARGET_VIS || REGNO (operands[0]) < SPARC_FIRST_FP_REG) 1008169689Skan && const_zero_operand (operands[1], mode)) 1009169689Skan return false; 101050397Sobrien 1011169689Skan if (REGNO (operands[0]) < SPARC_FIRST_FP_REG 1012169689Skan /* We are able to build any SF constant in integer registers 1013169689Skan with at most 2 instructions. */ 1014169689Skan && (mode == SFmode 1015169689Skan /* And any DF constant in integer registers. */ 1016169689Skan || (mode == DFmode 1017169689Skan && (reload_completed || reload_in_progress)))) 1018169689Skan return false; 101950397Sobrien 1020169689Skan operands[1] = force_const_mem (mode, operands[1]); 1021169689Skan if (!reload_in_progress) 1022169689Skan operands[1] = validize_mem (operands[1]); 1023169689Skan return false; 102450397Sobrien } 102550397Sobrien 1026169689Skan /* Accept non-constants and valid constants unmodified. */ 1027169689Skan if (!CONSTANT_P (operands[1]) 1028169689Skan || GET_CODE (operands[1]) == HIGH 1029169689Skan || input_operand (operands[1], mode)) 1030169689Skan return false; 103150397Sobrien 1032169689Skan switch (mode) 103350397Sobrien { 1034169689Skan case QImode: 1035169689Skan /* All QImode constants require only one insn, so proceed. */ 1036169689Skan break; 103750397Sobrien 1038169689Skan case HImode: 1039169689Skan case SImode: 1040169689Skan sparc_emit_set_const32 (operands[0], operands[1]); 1041169689Skan return true; 104250397Sobrien 1043169689Skan case DImode: 1044169689Skan /* input_operand should have filtered out 32-bit mode. */ 1045169689Skan sparc_emit_set_const64 (operands[0], operands[1]); 1046169689Skan return true; 1047169689Skan 1048169689Skan default: 1049169689Skan gcc_unreachable (); 105050397Sobrien } 105150397Sobrien 1052169689Skan return false; 105350397Sobrien} 105450397Sobrien 1055169689Skan/* Load OP1, a 32-bit constant, into OP0, a register. 1056169689Skan We know it can't be done in one insn when we get 1057169689Skan here, the move expander guarantees this. */ 105850397Sobrien 105952284Sobrienvoid 1060132718Skansparc_emit_set_const32 (rtx op0, rtx op1) 106152284Sobrien{ 106252284Sobrien enum machine_mode mode = GET_MODE (op0); 106352284Sobrien rtx temp; 106452284Sobrien 106552284Sobrien if (reload_in_progress || reload_completed) 106652284Sobrien temp = op0; 106752284Sobrien else 106852284Sobrien temp = gen_reg_rtx (mode); 106952284Sobrien 107052284Sobrien if (GET_CODE (op1) == CONST_INT) 107152284Sobrien { 1072169689Skan gcc_assert (!small_int_operand (op1, mode) 1073169689Skan && !const_high_operand (op1, mode)); 1074169689Skan 107552284Sobrien /* Emit them as real moves instead of a HIGH/LO_SUM, 107652284Sobrien this way CSE can see everything and reuse intermediate 107752284Sobrien values if it wants. */ 1078169689Skan emit_insn (gen_rtx_SET (VOIDmode, temp, 1079169689Skan GEN_INT (INTVAL (op1) 1080169689Skan & ~(HOST_WIDE_INT)0x3ff))); 108190075Sobrien 108252284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 108352284Sobrien op0, 108490075Sobrien gen_rtx_IOR (mode, temp, 108552284Sobrien GEN_INT (INTVAL (op1) & 0x3ff)))); 108652284Sobrien } 108752284Sobrien else 108852284Sobrien { 108952284Sobrien /* A symbol, emit in the traditional way. */ 109090075Sobrien emit_insn (gen_rtx_SET (VOIDmode, temp, 109190075Sobrien gen_rtx_HIGH (mode, op1))); 109252284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 109390075Sobrien op0, gen_rtx_LO_SUM (mode, temp, op1))); 109452284Sobrien } 109552284Sobrien} 109652284Sobrien 1097132718Skan/* Load OP1, a symbolic 64-bit constant, into OP0, a DImode register. 1098169689Skan If TEMP is nonzero, we are forbidden to use any other scratch 1099132718Skan registers. Otherwise, we are allowed to generate them as needed. 1100132718Skan 1101132718Skan Note that TEMP may have TImode if the code model is TARGET_CM_MEDANY 1102132718Skan or TARGET_CM_EMBMEDANY (see the reload_indi and reload_outdi patterns). */ 1103169689Skan 110452284Sobrienvoid 1105132718Skansparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp) 110652284Sobrien{ 1107132718Skan rtx temp1, temp2, temp3, temp4, temp5; 1108132718Skan rtx ti_temp = 0; 110996263Sobrien 1110132718Skan if (temp && GET_MODE (temp) == TImode) 111196263Sobrien { 1112132718Skan ti_temp = temp; 1113132718Skan temp = gen_rtx_REG (DImode, REGNO (temp)); 111496263Sobrien } 111596263Sobrien 1116132718Skan /* SPARC-V9 code-model support. */ 111752284Sobrien switch (sparc_cmodel) 111852284Sobrien { 111952284Sobrien case CM_MEDLOW: 112052284Sobrien /* The range spanned by all instructions in the object is less 112152284Sobrien than 2^31 bytes (2GB) and the distance from any instruction 112252284Sobrien to the location of the label _GLOBAL_OFFSET_TABLE_ is less 112352284Sobrien than 2^31 bytes (2GB). 112452284Sobrien 112552284Sobrien The executable must be in the low 4TB of the virtual address 112652284Sobrien space. 112752284Sobrien 1128132718Skan sethi %hi(symbol), %temp1 1129132718Skan or %temp1, %lo(symbol), %reg */ 1130132718Skan if (temp) 1131132718Skan temp1 = temp; /* op0 is allowed. */ 1132132718Skan else 1133132718Skan temp1 = gen_reg_rtx (DImode); 1134132718Skan 113552284Sobrien emit_insn (gen_rtx_SET (VOIDmode, temp1, gen_rtx_HIGH (DImode, op1))); 113652284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, gen_rtx_LO_SUM (DImode, temp1, op1))); 113752284Sobrien break; 113852284Sobrien 113952284Sobrien case CM_MEDMID: 114052284Sobrien /* The range spanned by all instructions in the object is less 114152284Sobrien than 2^31 bytes (2GB) and the distance from any instruction 114252284Sobrien to the location of the label _GLOBAL_OFFSET_TABLE_ is less 114352284Sobrien than 2^31 bytes (2GB). 114452284Sobrien 114552284Sobrien The executable must be in the low 16TB of the virtual address 114652284Sobrien space. 114752284Sobrien 114852284Sobrien sethi %h44(symbol), %temp1 114952284Sobrien or %temp1, %m44(symbol), %temp2 115052284Sobrien sllx %temp2, 12, %temp3 115152284Sobrien or %temp3, %l44(symbol), %reg */ 1152132718Skan if (temp) 1153132718Skan { 1154132718Skan temp1 = op0; 1155132718Skan temp2 = op0; 1156132718Skan temp3 = temp; /* op0 is allowed. */ 1157132718Skan } 1158132718Skan else 1159132718Skan { 1160132718Skan temp1 = gen_reg_rtx (DImode); 1161132718Skan temp2 = gen_reg_rtx (DImode); 1162132718Skan temp3 = gen_reg_rtx (DImode); 1163132718Skan } 1164132718Skan 1165132718Skan emit_insn (gen_seth44 (temp1, op1)); 1166132718Skan emit_insn (gen_setm44 (temp2, temp1, op1)); 1167132718Skan emit_insn (gen_rtx_SET (VOIDmode, temp3, 1168132718Skan gen_rtx_ASHIFT (DImode, temp2, GEN_INT (12)))); 1169132718Skan emit_insn (gen_setl44 (op0, temp3, op1)); 117052284Sobrien break; 117152284Sobrien 117252284Sobrien case CM_MEDANY: 117352284Sobrien /* The range spanned by all instructions in the object is less 117452284Sobrien than 2^31 bytes (2GB) and the distance from any instruction 117552284Sobrien to the location of the label _GLOBAL_OFFSET_TABLE_ is less 117652284Sobrien than 2^31 bytes (2GB). 117752284Sobrien 117852284Sobrien The executable can be placed anywhere in the virtual address 117952284Sobrien space. 118052284Sobrien 118152284Sobrien sethi %hh(symbol), %temp1 118252284Sobrien sethi %lm(symbol), %temp2 118352284Sobrien or %temp1, %hm(symbol), %temp3 1184132718Skan sllx %temp3, 32, %temp4 1185132718Skan or %temp4, %temp2, %temp5 1186132718Skan or %temp5, %lo(symbol), %reg */ 1187132718Skan if (temp) 118896263Sobrien { 1189132718Skan /* It is possible that one of the registers we got for operands[2] 1190132718Skan might coincide with that of operands[0] (which is why we made 1191132718Skan it TImode). Pick the other one to use as our scratch. */ 1192132718Skan if (rtx_equal_p (temp, op0)) 1193132718Skan { 1194169689Skan gcc_assert (ti_temp); 1195169689Skan temp = gen_rtx_REG (DImode, REGNO (temp) + 1); 1196132718Skan } 1197132718Skan temp1 = op0; 1198132718Skan temp2 = temp; /* op0 is _not_ allowed, see above. */ 1199132718Skan temp3 = op0; 1200132718Skan temp4 = op0; 1201132718Skan temp5 = op0; 120296263Sobrien } 1203132718Skan else 1204132718Skan { 1205132718Skan temp1 = gen_reg_rtx (DImode); 1206132718Skan temp2 = gen_reg_rtx (DImode); 1207132718Skan temp3 = gen_reg_rtx (DImode); 1208132718Skan temp4 = gen_reg_rtx (DImode); 1209132718Skan temp5 = gen_reg_rtx (DImode); 1210132718Skan } 121152284Sobrien 1212132718Skan emit_insn (gen_sethh (temp1, op1)); 1213132718Skan emit_insn (gen_setlm (temp2, op1)); 1214132718Skan emit_insn (gen_sethm (temp3, temp1, op1)); 1215132718Skan emit_insn (gen_rtx_SET (VOIDmode, temp4, 1216132718Skan gen_rtx_ASHIFT (DImode, temp3, GEN_INT (32)))); 1217132718Skan emit_insn (gen_rtx_SET (VOIDmode, temp5, 1218132718Skan gen_rtx_PLUS (DImode, temp4, temp2))); 1219132718Skan emit_insn (gen_setlo (op0, temp5, op1)); 122052284Sobrien break; 122152284Sobrien 122252284Sobrien case CM_EMBMEDANY: 122352284Sobrien /* Old old old backwards compatibility kruft here. 122452284Sobrien Essentially it is MEDLOW with a fixed 64-bit 122552284Sobrien virtual base added to all data segment addresses. 122652284Sobrien Text-segment stuff is computed like MEDANY, we can't 122752284Sobrien reuse the code above because the relocation knobs 122852284Sobrien look different. 122952284Sobrien 123052284Sobrien Data segment: sethi %hi(symbol), %temp1 1231132718Skan add %temp1, EMBMEDANY_BASE_REG, %temp2 1232132718Skan or %temp2, %lo(symbol), %reg */ 123352284Sobrien if (data_segment_operand (op1, GET_MODE (op1))) 123452284Sobrien { 1235132718Skan if (temp) 1236132718Skan { 1237132718Skan temp1 = temp; /* op0 is allowed. */ 1238132718Skan temp2 = op0; 1239132718Skan } 1240132718Skan else 1241132718Skan { 1242132718Skan temp1 = gen_reg_rtx (DImode); 1243132718Skan temp2 = gen_reg_rtx (DImode); 1244132718Skan } 1245132718Skan 124652284Sobrien emit_insn (gen_embmedany_sethi (temp1, op1)); 1247132718Skan emit_insn (gen_embmedany_brsum (temp2, temp1)); 1248132718Skan emit_insn (gen_embmedany_losum (op0, temp2, op1)); 124952284Sobrien } 1250132718Skan 1251132718Skan /* Text segment: sethi %uhi(symbol), %temp1 1252132718Skan sethi %hi(symbol), %temp2 1253132718Skan or %temp1, %ulo(symbol), %temp3 1254132718Skan sllx %temp3, 32, %temp4 1255132718Skan or %temp4, %temp2, %temp5 1256132718Skan or %temp5, %lo(symbol), %reg */ 125752284Sobrien else 125852284Sobrien { 1259132718Skan if (temp) 126096263Sobrien { 1261132718Skan /* It is possible that one of the registers we got for operands[2] 1262132718Skan might coincide with that of operands[0] (which is why we made 1263132718Skan it TImode). Pick the other one to use as our scratch. */ 1264132718Skan if (rtx_equal_p (temp, op0)) 1265132718Skan { 1266169689Skan gcc_assert (ti_temp); 1267169689Skan temp = gen_rtx_REG (DImode, REGNO (temp) + 1); 1268132718Skan } 1269132718Skan temp1 = op0; 1270132718Skan temp2 = temp; /* op0 is _not_ allowed, see above. */ 1271132718Skan temp3 = op0; 1272132718Skan temp4 = op0; 1273132718Skan temp5 = op0; 127496263Sobrien } 1275132718Skan else 1276132718Skan { 1277132718Skan temp1 = gen_reg_rtx (DImode); 1278132718Skan temp2 = gen_reg_rtx (DImode); 1279132718Skan temp3 = gen_reg_rtx (DImode); 1280132718Skan temp4 = gen_reg_rtx (DImode); 1281132718Skan temp5 = gen_reg_rtx (DImode); 1282132718Skan } 128352284Sobrien 1284132718Skan emit_insn (gen_embmedany_textuhi (temp1, op1)); 1285132718Skan emit_insn (gen_embmedany_texthi (temp2, op1)); 1286132718Skan emit_insn (gen_embmedany_textulo (temp3, temp1, op1)); 1287132718Skan emit_insn (gen_rtx_SET (VOIDmode, temp4, 1288132718Skan gen_rtx_ASHIFT (DImode, temp3, GEN_INT (32)))); 1289132718Skan emit_insn (gen_rtx_SET (VOIDmode, temp5, 1290132718Skan gen_rtx_PLUS (DImode, temp4, temp2))); 1291132718Skan emit_insn (gen_embmedany_textlo (op0, temp5, op1)); 129252284Sobrien } 129352284Sobrien break; 129452284Sobrien 129552284Sobrien default: 1296169689Skan gcc_unreachable (); 129752284Sobrien } 129852284Sobrien} 129952284Sobrien 1300169689Skan#if HOST_BITS_PER_WIDE_INT == 32 1301169689Skanvoid 1302169689Skansparc_emit_set_const64 (rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED) 1303169689Skan{ 1304169689Skan gcc_unreachable (); 1305169689Skan} 1306169689Skan#else 130752284Sobrien/* These avoid problems when cross compiling. If we do not 130852284Sobrien go through all this hair then the optimizer will see 130952284Sobrien invalid REG_EQUAL notes or in some cases none at all. */ 1310169689Skanstatic rtx gen_safe_HIGH64 (rtx, HOST_WIDE_INT); 1311132718Skanstatic rtx gen_safe_SET64 (rtx, HOST_WIDE_INT); 1312132718Skanstatic rtx gen_safe_OR64 (rtx, HOST_WIDE_INT); 1313132718Skanstatic rtx gen_safe_XOR64 (rtx, HOST_WIDE_INT); 131452284Sobrien 131552284Sobrien/* The optimizer is not to assume anything about exactly 131652284Sobrien which bits are set for a HIGH, they are unspecified. 131752284Sobrien Unfortunately this leads to many missed optimizations 131852284Sobrien during CSE. We mask out the non-HIGH bits, and matches 131952284Sobrien a plain movdi, to alleviate this problem. */ 1320169689Skanstatic rtx 1321169689Skangen_safe_HIGH64 (rtx dest, HOST_WIDE_INT val) 132252284Sobrien{ 1323169689Skan return gen_rtx_SET (VOIDmode, dest, GEN_INT (val & ~(HOST_WIDE_INT)0x3ff)); 132452284Sobrien} 132552284Sobrien 132652284Sobrienstatic rtx 1327132718Skangen_safe_SET64 (rtx dest, HOST_WIDE_INT val) 132852284Sobrien{ 1329169689Skan return gen_rtx_SET (VOIDmode, dest, GEN_INT (val)); 133052284Sobrien} 133152284Sobrien 133252284Sobrienstatic rtx 1333132718Skangen_safe_OR64 (rtx src, HOST_WIDE_INT val) 133452284Sobrien{ 1335169689Skan return gen_rtx_IOR (DImode, src, GEN_INT (val)); 133652284Sobrien} 133752284Sobrien 133852284Sobrienstatic rtx 1339132718Skangen_safe_XOR64 (rtx src, HOST_WIDE_INT val) 134052284Sobrien{ 1341169689Skan return gen_rtx_XOR (DImode, src, GEN_INT (val)); 134252284Sobrien} 134352284Sobrien 134452284Sobrien/* Worker routines for 64-bit constant formation on arch64. 134552284Sobrien One of the key things to be doing in these emissions is 134652284Sobrien to create as many temp REGs as possible. This makes it 134752284Sobrien possible for half-built constants to be used later when 134852284Sobrien such values are similar to something required later on. 134952284Sobrien Without doing this, the optimizer cannot see such 135052284Sobrien opportunities. */ 135152284Sobrien 1352132718Skanstatic void sparc_emit_set_const64_quick1 (rtx, rtx, 1353132718Skan unsigned HOST_WIDE_INT, int); 135452284Sobrien 135552284Sobrienstatic void 1356132718Skansparc_emit_set_const64_quick1 (rtx op0, rtx temp, 1357132718Skan unsigned HOST_WIDE_INT low_bits, int is_neg) 135852284Sobrien{ 135952284Sobrien unsigned HOST_WIDE_INT high_bits; 136052284Sobrien 136152284Sobrien if (is_neg) 136252284Sobrien high_bits = (~low_bits) & 0xffffffff; 136352284Sobrien else 136452284Sobrien high_bits = low_bits; 136552284Sobrien 1366169689Skan emit_insn (gen_safe_HIGH64 (temp, high_bits)); 136752284Sobrien if (!is_neg) 136852284Sobrien { 136952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 137052284Sobrien gen_safe_OR64 (temp, (high_bits & 0x3ff)))); 137152284Sobrien } 137252284Sobrien else 137352284Sobrien { 137452284Sobrien /* If we are XOR'ing with -1, then we should emit a one's complement 137552284Sobrien instead. This way the combiner will notice logical operations 137652284Sobrien such as ANDN later on and substitute. */ 137752284Sobrien if ((low_bits & 0x3ff) == 0x3ff) 137852284Sobrien { 137952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 138052284Sobrien gen_rtx_NOT (DImode, temp))); 138152284Sobrien } 138252284Sobrien else 138352284Sobrien { 138452284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 138552284Sobrien gen_safe_XOR64 (temp, 138696263Sobrien (-(HOST_WIDE_INT)0x400 138796263Sobrien | (low_bits & 0x3ff))))); 138852284Sobrien } 138952284Sobrien } 139052284Sobrien} 139152284Sobrien 1392132718Skanstatic void sparc_emit_set_const64_quick2 (rtx, rtx, unsigned HOST_WIDE_INT, 1393132718Skan unsigned HOST_WIDE_INT, int); 139452284Sobrien 139552284Sobrienstatic void 1396132718Skansparc_emit_set_const64_quick2 (rtx op0, rtx temp, 1397132718Skan unsigned HOST_WIDE_INT high_bits, 1398132718Skan unsigned HOST_WIDE_INT low_immediate, 1399132718Skan int shift_count) 140052284Sobrien{ 140152284Sobrien rtx temp2 = op0; 140252284Sobrien 140352284Sobrien if ((high_bits & 0xfffffc00) != 0) 140452284Sobrien { 1405169689Skan emit_insn (gen_safe_HIGH64 (temp, high_bits)); 140652284Sobrien if ((high_bits & ~0xfffffc00) != 0) 140752284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 140852284Sobrien gen_safe_OR64 (temp, (high_bits & 0x3ff)))); 140952284Sobrien else 141052284Sobrien temp2 = temp; 141152284Sobrien } 141252284Sobrien else 141352284Sobrien { 141452284Sobrien emit_insn (gen_safe_SET64 (temp, high_bits)); 141552284Sobrien temp2 = temp; 141652284Sobrien } 141752284Sobrien 141890075Sobrien /* Now shift it up into place. */ 141952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 142052284Sobrien gen_rtx_ASHIFT (DImode, temp2, 142152284Sobrien GEN_INT (shift_count)))); 142252284Sobrien 142352284Sobrien /* If there is a low immediate part piece, finish up by 142452284Sobrien putting that in as well. */ 142552284Sobrien if (low_immediate != 0) 142652284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 142752284Sobrien gen_safe_OR64 (op0, low_immediate))); 142852284Sobrien} 142952284Sobrien 1430132718Skanstatic void sparc_emit_set_const64_longway (rtx, rtx, unsigned HOST_WIDE_INT, 1431132718Skan unsigned HOST_WIDE_INT); 143252284Sobrien 143352284Sobrien/* Full 64-bit constant decomposition. Even though this is the 143452284Sobrien 'worst' case, we still optimize a few things away. */ 143552284Sobrienstatic void 1436132718Skansparc_emit_set_const64_longway (rtx op0, rtx temp, 1437132718Skan unsigned HOST_WIDE_INT high_bits, 1438132718Skan unsigned HOST_WIDE_INT low_bits) 143952284Sobrien{ 144052284Sobrien rtx sub_temp; 144152284Sobrien 144252284Sobrien if (reload_in_progress || reload_completed) 144352284Sobrien sub_temp = op0; 144452284Sobrien else 144552284Sobrien sub_temp = gen_reg_rtx (DImode); 144652284Sobrien 144752284Sobrien if ((high_bits & 0xfffffc00) != 0) 144852284Sobrien { 1449169689Skan emit_insn (gen_safe_HIGH64 (temp, high_bits)); 145052284Sobrien if ((high_bits & ~0xfffffc00) != 0) 145152284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 145252284Sobrien sub_temp, 145352284Sobrien gen_safe_OR64 (temp, (high_bits & 0x3ff)))); 145452284Sobrien else 145552284Sobrien sub_temp = temp; 145652284Sobrien } 145752284Sobrien else 145852284Sobrien { 145952284Sobrien emit_insn (gen_safe_SET64 (temp, high_bits)); 146052284Sobrien sub_temp = temp; 146152284Sobrien } 146252284Sobrien 146352284Sobrien if (!reload_in_progress && !reload_completed) 146452284Sobrien { 146552284Sobrien rtx temp2 = gen_reg_rtx (DImode); 146652284Sobrien rtx temp3 = gen_reg_rtx (DImode); 146752284Sobrien rtx temp4 = gen_reg_rtx (DImode); 146852284Sobrien 146952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, temp4, 147052284Sobrien gen_rtx_ASHIFT (DImode, sub_temp, 147152284Sobrien GEN_INT (32)))); 147252284Sobrien 1473169689Skan emit_insn (gen_safe_HIGH64 (temp2, low_bits)); 147452284Sobrien if ((low_bits & ~0xfffffc00) != 0) 147552284Sobrien { 147652284Sobrien emit_insn (gen_rtx_SET (VOIDmode, temp3, 147752284Sobrien gen_safe_OR64 (temp2, (low_bits & 0x3ff)))); 147852284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 147952284Sobrien gen_rtx_PLUS (DImode, temp4, temp3))); 148052284Sobrien } 148152284Sobrien else 148252284Sobrien { 148352284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 148452284Sobrien gen_rtx_PLUS (DImode, temp4, temp2))); 148552284Sobrien } 148652284Sobrien } 148752284Sobrien else 148852284Sobrien { 148952284Sobrien rtx low1 = GEN_INT ((low_bits >> (32 - 12)) & 0xfff); 149052284Sobrien rtx low2 = GEN_INT ((low_bits >> (32 - 12 - 12)) & 0xfff); 149152284Sobrien rtx low3 = GEN_INT ((low_bits >> (32 - 12 - 12 - 8)) & 0x0ff); 149252284Sobrien int to_shift = 12; 149352284Sobrien 149452284Sobrien /* We are in the middle of reload, so this is really 149552284Sobrien painful. However we do still make an attempt to 149652284Sobrien avoid emitting truly stupid code. */ 149752284Sobrien if (low1 != const0_rtx) 149852284Sobrien { 149952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 150052284Sobrien gen_rtx_ASHIFT (DImode, sub_temp, 150152284Sobrien GEN_INT (to_shift)))); 150252284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 150352284Sobrien gen_rtx_IOR (DImode, op0, low1))); 150452284Sobrien sub_temp = op0; 150552284Sobrien to_shift = 12; 150652284Sobrien } 150752284Sobrien else 150852284Sobrien { 150952284Sobrien to_shift += 12; 151052284Sobrien } 151152284Sobrien if (low2 != const0_rtx) 151252284Sobrien { 151352284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 151452284Sobrien gen_rtx_ASHIFT (DImode, sub_temp, 151552284Sobrien GEN_INT (to_shift)))); 151652284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 151752284Sobrien gen_rtx_IOR (DImode, op0, low2))); 151852284Sobrien sub_temp = op0; 151952284Sobrien to_shift = 8; 152052284Sobrien } 152152284Sobrien else 152252284Sobrien { 152352284Sobrien to_shift += 8; 152452284Sobrien } 152552284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 152652284Sobrien gen_rtx_ASHIFT (DImode, sub_temp, 152752284Sobrien GEN_INT (to_shift)))); 152852284Sobrien if (low3 != const0_rtx) 152952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 153052284Sobrien gen_rtx_IOR (DImode, op0, low3))); 153190075Sobrien /* phew... */ 153252284Sobrien } 153352284Sobrien} 153452284Sobrien 153590075Sobrien/* Analyze a 64-bit constant for certain properties. */ 1536132718Skanstatic void analyze_64bit_constant (unsigned HOST_WIDE_INT, 1537132718Skan unsigned HOST_WIDE_INT, 1538132718Skan int *, int *, int *); 153952284Sobrien 154052284Sobrienstatic void 1541132718Skananalyze_64bit_constant (unsigned HOST_WIDE_INT high_bits, 1542132718Skan unsigned HOST_WIDE_INT low_bits, 1543132718Skan int *hbsp, int *lbsp, int *abbasp) 154452284Sobrien{ 154552284Sobrien int lowest_bit_set, highest_bit_set, all_bits_between_are_set; 154652284Sobrien int i; 154752284Sobrien 154852284Sobrien lowest_bit_set = highest_bit_set = -1; 154952284Sobrien i = 0; 155052284Sobrien do 155152284Sobrien { 155252284Sobrien if ((lowest_bit_set == -1) 155352284Sobrien && ((low_bits >> i) & 1)) 155452284Sobrien lowest_bit_set = i; 155552284Sobrien if ((highest_bit_set == -1) 155652284Sobrien && ((high_bits >> (32 - i - 1)) & 1)) 155752284Sobrien highest_bit_set = (64 - i - 1); 155852284Sobrien } 155952284Sobrien while (++i < 32 156052284Sobrien && ((highest_bit_set == -1) 156152284Sobrien || (lowest_bit_set == -1))); 156252284Sobrien if (i == 32) 156352284Sobrien { 156452284Sobrien i = 0; 156552284Sobrien do 156652284Sobrien { 156752284Sobrien if ((lowest_bit_set == -1) 156852284Sobrien && ((high_bits >> i) & 1)) 156952284Sobrien lowest_bit_set = i + 32; 157052284Sobrien if ((highest_bit_set == -1) 157152284Sobrien && ((low_bits >> (32 - i - 1)) & 1)) 157252284Sobrien highest_bit_set = 32 - i - 1; 157352284Sobrien } 157452284Sobrien while (++i < 32 157552284Sobrien && ((highest_bit_set == -1) 157652284Sobrien || (lowest_bit_set == -1))); 157752284Sobrien } 157852284Sobrien /* If there are no bits set this should have gone out 157952284Sobrien as one instruction! */ 1580169689Skan gcc_assert (lowest_bit_set != -1 && highest_bit_set != -1); 158152284Sobrien all_bits_between_are_set = 1; 158252284Sobrien for (i = lowest_bit_set; i <= highest_bit_set; i++) 158352284Sobrien { 158452284Sobrien if (i < 32) 158552284Sobrien { 158652284Sobrien if ((low_bits & (1 << i)) != 0) 158752284Sobrien continue; 158852284Sobrien } 158952284Sobrien else 159052284Sobrien { 159152284Sobrien if ((high_bits & (1 << (i - 32))) != 0) 159252284Sobrien continue; 159352284Sobrien } 159452284Sobrien all_bits_between_are_set = 0; 159552284Sobrien break; 159652284Sobrien } 159752284Sobrien *hbsp = highest_bit_set; 159852284Sobrien *lbsp = lowest_bit_set; 159952284Sobrien *abbasp = all_bits_between_are_set; 160052284Sobrien} 160152284Sobrien 1602132718Skanstatic int const64_is_2insns (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT); 160352284Sobrien 160452284Sobrienstatic int 1605132718Skanconst64_is_2insns (unsigned HOST_WIDE_INT high_bits, 1606132718Skan unsigned HOST_WIDE_INT low_bits) 160752284Sobrien{ 160852284Sobrien int highest_bit_set, lowest_bit_set, all_bits_between_are_set; 160952284Sobrien 161052284Sobrien if (high_bits == 0 161152284Sobrien || high_bits == 0xffffffff) 161252284Sobrien return 1; 161352284Sobrien 161452284Sobrien analyze_64bit_constant (high_bits, low_bits, 161552284Sobrien &highest_bit_set, &lowest_bit_set, 161652284Sobrien &all_bits_between_are_set); 161752284Sobrien 161852284Sobrien if ((highest_bit_set == 63 161952284Sobrien || lowest_bit_set == 0) 162052284Sobrien && all_bits_between_are_set != 0) 162152284Sobrien return 1; 162252284Sobrien 162352284Sobrien if ((highest_bit_set - lowest_bit_set) < 21) 162452284Sobrien return 1; 162552284Sobrien 162652284Sobrien return 0; 162752284Sobrien} 162852284Sobrien 1629132718Skanstatic unsigned HOST_WIDE_INT create_simple_focus_bits (unsigned HOST_WIDE_INT, 1630132718Skan unsigned HOST_WIDE_INT, 1631132718Skan int, int); 163252284Sobrien 163352284Sobrienstatic unsigned HOST_WIDE_INT 1634132718Skancreate_simple_focus_bits (unsigned HOST_WIDE_INT high_bits, 1635132718Skan unsigned HOST_WIDE_INT low_bits, 1636132718Skan int lowest_bit_set, int shift) 163752284Sobrien{ 163852284Sobrien HOST_WIDE_INT hi, lo; 163952284Sobrien 164052284Sobrien if (lowest_bit_set < 32) 164152284Sobrien { 164252284Sobrien lo = (low_bits >> lowest_bit_set) << shift; 164352284Sobrien hi = ((high_bits << (32 - lowest_bit_set)) << shift); 164452284Sobrien } 164552284Sobrien else 164652284Sobrien { 164752284Sobrien lo = 0; 164852284Sobrien hi = ((high_bits >> (lowest_bit_set - 32)) << shift); 164952284Sobrien } 1650169689Skan gcc_assert (! (hi & lo)); 165152284Sobrien return (hi | lo); 165252284Sobrien} 165352284Sobrien 165452284Sobrien/* Here we are sure to be arch64 and this is an integer constant 165552284Sobrien being loaded into a register. Emit the most efficient 165652284Sobrien insn sequence possible. Detection of all the 1-insn cases 165752284Sobrien has been done already. */ 165852284Sobrienvoid 1659132718Skansparc_emit_set_const64 (rtx op0, rtx op1) 166052284Sobrien{ 166152284Sobrien unsigned HOST_WIDE_INT high_bits, low_bits; 166252284Sobrien int lowest_bit_set, highest_bit_set; 166352284Sobrien int all_bits_between_are_set; 1664132718Skan rtx temp = 0; 166552284Sobrien 166652284Sobrien /* Sanity check that we know what we are working with. */ 1667169689Skan gcc_assert (TARGET_ARCH64 1668169689Skan && (GET_CODE (op0) == SUBREG 1669169689Skan || (REG_P (op0) && ! SPARC_FP_REG_P (REGNO (op0))))); 167052284Sobrien 167152284Sobrien if (reload_in_progress || reload_completed) 167252284Sobrien temp = op0; 167352284Sobrien 1674169689Skan if (GET_CODE (op1) != CONST_INT) 167552284Sobrien { 167652284Sobrien sparc_emit_set_symbolic_const64 (op0, op1, temp); 167752284Sobrien return; 167852284Sobrien } 167952284Sobrien 1680132718Skan if (! temp) 1681132718Skan temp = gen_reg_rtx (DImode); 1682132718Skan 1683169689Skan high_bits = ((INTVAL (op1) >> 32) & 0xffffffff); 1684169689Skan low_bits = (INTVAL (op1) & 0xffffffff); 168552284Sobrien 168652284Sobrien /* low_bits bits 0 --> 31 168752284Sobrien high_bits bits 32 --> 63 */ 168852284Sobrien 168952284Sobrien analyze_64bit_constant (high_bits, low_bits, 169052284Sobrien &highest_bit_set, &lowest_bit_set, 169152284Sobrien &all_bits_between_are_set); 169252284Sobrien 169352284Sobrien /* First try for a 2-insn sequence. */ 169452284Sobrien 169552284Sobrien /* These situations are preferred because the optimizer can 169652284Sobrien * do more things with them: 169752284Sobrien * 1) mov -1, %reg 169852284Sobrien * sllx %reg, shift, %reg 169952284Sobrien * 2) mov -1, %reg 170052284Sobrien * srlx %reg, shift, %reg 170152284Sobrien * 3) mov some_small_const, %reg 170252284Sobrien * sllx %reg, shift, %reg 170352284Sobrien */ 170452284Sobrien if (((highest_bit_set == 63 170552284Sobrien || lowest_bit_set == 0) 170652284Sobrien && all_bits_between_are_set != 0) 170752284Sobrien || ((highest_bit_set - lowest_bit_set) < 12)) 170852284Sobrien { 170952284Sobrien HOST_WIDE_INT the_const = -1; 171052284Sobrien int shift = lowest_bit_set; 171152284Sobrien 171252284Sobrien if ((highest_bit_set != 63 171352284Sobrien && lowest_bit_set != 0) 171452284Sobrien || all_bits_between_are_set == 0) 171552284Sobrien { 171652284Sobrien the_const = 171752284Sobrien create_simple_focus_bits (high_bits, low_bits, 171852284Sobrien lowest_bit_set, 0); 171952284Sobrien } 172052284Sobrien else if (lowest_bit_set == 0) 172152284Sobrien shift = -(63 - highest_bit_set); 172252284Sobrien 1723169689Skan gcc_assert (SPARC_SIMM13_P (the_const)); 1724169689Skan gcc_assert (shift != 0); 172552284Sobrien 172652284Sobrien emit_insn (gen_safe_SET64 (temp, the_const)); 172752284Sobrien if (shift > 0) 172852284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 172952284Sobrien op0, 173052284Sobrien gen_rtx_ASHIFT (DImode, 173152284Sobrien temp, 173252284Sobrien GEN_INT (shift)))); 173352284Sobrien else if (shift < 0) 173452284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 173552284Sobrien op0, 173652284Sobrien gen_rtx_LSHIFTRT (DImode, 173752284Sobrien temp, 173852284Sobrien GEN_INT (-shift)))); 173952284Sobrien return; 174052284Sobrien } 174152284Sobrien 174252284Sobrien /* Now a range of 22 or less bits set somewhere. 174352284Sobrien * 1) sethi %hi(focus_bits), %reg 174452284Sobrien * sllx %reg, shift, %reg 174552284Sobrien * 2) sethi %hi(focus_bits), %reg 174652284Sobrien * srlx %reg, shift, %reg 174752284Sobrien */ 174852284Sobrien if ((highest_bit_set - lowest_bit_set) < 21) 174952284Sobrien { 175052284Sobrien unsigned HOST_WIDE_INT focus_bits = 175152284Sobrien create_simple_focus_bits (high_bits, low_bits, 175252284Sobrien lowest_bit_set, 10); 175352284Sobrien 1754169689Skan gcc_assert (SPARC_SETHI_P (focus_bits)); 1755169689Skan gcc_assert (lowest_bit_set != 10); 175652284Sobrien 1757169689Skan emit_insn (gen_safe_HIGH64 (temp, focus_bits)); 175852284Sobrien 175952284Sobrien /* If lowest_bit_set == 10 then a sethi alone could have done it. */ 176052284Sobrien if (lowest_bit_set < 10) 176152284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 176252284Sobrien op0, 176352284Sobrien gen_rtx_LSHIFTRT (DImode, temp, 176452284Sobrien GEN_INT (10 - lowest_bit_set)))); 176552284Sobrien else if (lowest_bit_set > 10) 176652284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 176752284Sobrien op0, 176852284Sobrien gen_rtx_ASHIFT (DImode, temp, 176952284Sobrien GEN_INT (lowest_bit_set - 10)))); 177052284Sobrien return; 177152284Sobrien } 177252284Sobrien 177352284Sobrien /* 1) sethi %hi(low_bits), %reg 177452284Sobrien * or %reg, %lo(low_bits), %reg 177552284Sobrien * 2) sethi %hi(~low_bits), %reg 177652284Sobrien * xor %reg, %lo(-0x400 | (low_bits & 0x3ff)), %reg 177752284Sobrien */ 177852284Sobrien if (high_bits == 0 177952284Sobrien || high_bits == 0xffffffff) 178052284Sobrien { 178152284Sobrien sparc_emit_set_const64_quick1 (op0, temp, low_bits, 178252284Sobrien (high_bits == 0xffffffff)); 178352284Sobrien return; 178452284Sobrien } 178552284Sobrien 178652284Sobrien /* Now, try 3-insn sequences. */ 178752284Sobrien 178852284Sobrien /* 1) sethi %hi(high_bits), %reg 178952284Sobrien * or %reg, %lo(high_bits), %reg 179052284Sobrien * sllx %reg, 32, %reg 179152284Sobrien */ 179252284Sobrien if (low_bits == 0) 179352284Sobrien { 179452284Sobrien sparc_emit_set_const64_quick2 (op0, temp, high_bits, 0, 32); 179552284Sobrien return; 179652284Sobrien } 179752284Sobrien 179852284Sobrien /* We may be able to do something quick 179952284Sobrien when the constant is negated, so try that. */ 180052284Sobrien if (const64_is_2insns ((~high_bits) & 0xffffffff, 180152284Sobrien (~low_bits) & 0xfffffc00)) 180252284Sobrien { 180352284Sobrien /* NOTE: The trailing bits get XOR'd so we need the 180452284Sobrien non-negated bits, not the negated ones. */ 180552284Sobrien unsigned HOST_WIDE_INT trailing_bits = low_bits & 0x3ff; 180652284Sobrien 180752284Sobrien if ((((~high_bits) & 0xffffffff) == 0 180852284Sobrien && ((~low_bits) & 0x80000000) == 0) 180952284Sobrien || (((~high_bits) & 0xffffffff) == 0xffffffff 181052284Sobrien && ((~low_bits) & 0x80000000) != 0)) 181152284Sobrien { 1812169689Skan unsigned HOST_WIDE_INT fast_int = (~low_bits & 0xffffffff); 181352284Sobrien 181452284Sobrien if ((SPARC_SETHI_P (fast_int) 181552284Sobrien && (~high_bits & 0xffffffff) == 0) 181652284Sobrien || SPARC_SIMM13_P (fast_int)) 181752284Sobrien emit_insn (gen_safe_SET64 (temp, fast_int)); 181852284Sobrien else 1819169689Skan sparc_emit_set_const64 (temp, GEN_INT (fast_int)); 182052284Sobrien } 182152284Sobrien else 182252284Sobrien { 182352284Sobrien rtx negated_const; 182452284Sobrien negated_const = GEN_INT (((~low_bits) & 0xfffffc00) | 182552284Sobrien (((HOST_WIDE_INT)((~high_bits) & 0xffffffff))<<32)); 182652284Sobrien sparc_emit_set_const64 (temp, negated_const); 182752284Sobrien } 182852284Sobrien 182952284Sobrien /* If we are XOR'ing with -1, then we should emit a one's complement 183052284Sobrien instead. This way the combiner will notice logical operations 183152284Sobrien such as ANDN later on and substitute. */ 183252284Sobrien if (trailing_bits == 0x3ff) 183352284Sobrien { 183452284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 183552284Sobrien gen_rtx_NOT (DImode, temp))); 183652284Sobrien } 183752284Sobrien else 183852284Sobrien { 183952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 184052284Sobrien op0, 184152284Sobrien gen_safe_XOR64 (temp, 184252284Sobrien (-0x400 | trailing_bits)))); 184352284Sobrien } 184452284Sobrien return; 184552284Sobrien } 184652284Sobrien 184752284Sobrien /* 1) sethi %hi(xxx), %reg 184852284Sobrien * or %reg, %lo(xxx), %reg 184952284Sobrien * sllx %reg, yyy, %reg 185052284Sobrien * 185152284Sobrien * ??? This is just a generalized version of the low_bits==0 185252284Sobrien * thing above, FIXME... 185352284Sobrien */ 185452284Sobrien if ((highest_bit_set - lowest_bit_set) < 32) 185552284Sobrien { 185652284Sobrien unsigned HOST_WIDE_INT focus_bits = 185752284Sobrien create_simple_focus_bits (high_bits, low_bits, 185852284Sobrien lowest_bit_set, 0); 185952284Sobrien 186052284Sobrien /* We can't get here in this state. */ 1861169689Skan gcc_assert (highest_bit_set >= 32 && lowest_bit_set < 32); 186252284Sobrien 186352284Sobrien /* So what we know is that the set bits straddle the 186452284Sobrien middle of the 64-bit word. */ 186552284Sobrien sparc_emit_set_const64_quick2 (op0, temp, 186652284Sobrien focus_bits, 0, 186752284Sobrien lowest_bit_set); 186852284Sobrien return; 186952284Sobrien } 187052284Sobrien 187152284Sobrien /* 1) sethi %hi(high_bits), %reg 187252284Sobrien * or %reg, %lo(high_bits), %reg 187352284Sobrien * sllx %reg, 32, %reg 187452284Sobrien * or %reg, low_bits, %reg 187552284Sobrien */ 187652284Sobrien if (SPARC_SIMM13_P(low_bits) 187752284Sobrien && ((int)low_bits > 0)) 187852284Sobrien { 187952284Sobrien sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_bits, 32); 188052284Sobrien return; 188152284Sobrien } 188252284Sobrien 188390075Sobrien /* The easiest way when all else fails, is full decomposition. */ 188452284Sobrien#if 0 188552284Sobrien printf ("sparc_emit_set_const64: Hard constant [%08lx%08lx] neg[%08lx%08lx]\n", 188652284Sobrien high_bits, low_bits, ~high_bits, ~low_bits); 188752284Sobrien#endif 188852284Sobrien sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits); 188952284Sobrien} 1890169689Skan#endif /* HOST_BITS_PER_WIDE_INT == 32 */ 189152284Sobrien 189290075Sobrien/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, 189390075Sobrien return the mode to be used for the comparison. For floating-point, 189490075Sobrien CCFP[E]mode is used. CC_NOOVmode should be used when the first operand 189590075Sobrien is a PLUS, MINUS, NEG, or ASHIFT. CCmode should be used when no special 189690075Sobrien processing is needed. */ 189790075Sobrien 189890075Sobrienenum machine_mode 1899132718Skanselect_cc_mode (enum rtx_code op, rtx x, rtx y ATTRIBUTE_UNUSED) 190090075Sobrien{ 190190075Sobrien if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) 190290075Sobrien { 190390075Sobrien switch (op) 190490075Sobrien { 190590075Sobrien case EQ: 190690075Sobrien case NE: 190790075Sobrien case UNORDERED: 190890075Sobrien case ORDERED: 190990075Sobrien case UNLT: 191090075Sobrien case UNLE: 191190075Sobrien case UNGT: 191290075Sobrien case UNGE: 191390075Sobrien case UNEQ: 191490075Sobrien case LTGT: 191590075Sobrien return CCFPmode; 191690075Sobrien 191790075Sobrien case LT: 191890075Sobrien case LE: 191990075Sobrien case GT: 192090075Sobrien case GE: 192190075Sobrien return CCFPEmode; 192290075Sobrien 192390075Sobrien default: 1924169689Skan gcc_unreachable (); 192590075Sobrien } 192690075Sobrien } 192790075Sobrien else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS 192890075Sobrien || GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT) 192990075Sobrien { 193090075Sobrien if (TARGET_ARCH64 && GET_MODE (x) == DImode) 193190075Sobrien return CCX_NOOVmode; 193290075Sobrien else 193390075Sobrien return CC_NOOVmode; 193490075Sobrien } 193590075Sobrien else 193690075Sobrien { 193790075Sobrien if (TARGET_ARCH64 && GET_MODE (x) == DImode) 193890075Sobrien return CCXmode; 193990075Sobrien else 194090075Sobrien return CCmode; 194190075Sobrien } 194290075Sobrien} 194390075Sobrien 194450397Sobrien/* X and Y are two things to compare using CODE. Emit the compare insn and 194550397Sobrien return the rtx for the cc reg in the proper mode. */ 194650397Sobrien 194750397Sobrienrtx 1948169689Skangen_compare_reg (enum rtx_code code) 194950397Sobrien{ 1950169689Skan rtx x = sparc_compare_op0; 1951169689Skan rtx y = sparc_compare_op1; 195250397Sobrien enum machine_mode mode = SELECT_CC_MODE (code, x, y); 195350397Sobrien rtx cc_reg; 195450397Sobrien 1955169689Skan if (sparc_compare_emitted != NULL_RTX) 1956169689Skan { 1957169689Skan cc_reg = sparc_compare_emitted; 1958169689Skan sparc_compare_emitted = NULL_RTX; 1959169689Skan return cc_reg; 1960169689Skan } 1961169689Skan 196250397Sobrien /* ??? We don't have movcc patterns so we cannot generate pseudo regs for the 196350397Sobrien fcc regs (cse can't tell they're really call clobbered regs and will 196450397Sobrien remove a duplicate comparison even if there is an intervening function 196550397Sobrien call - it will then try to reload the cc reg via an int reg which is why 196650397Sobrien we need the movcc patterns). It is possible to provide the movcc 196750397Sobrien patterns by using the ldxfsr/stxfsr v9 insns. I tried it: you need two 196850397Sobrien registers (say %g1,%g5) and it takes about 6 insns. A better fix would be 196950397Sobrien to tell cse that CCFPE mode registers (even pseudos) are call 197050397Sobrien clobbered. */ 197150397Sobrien 197250397Sobrien /* ??? This is an experiment. Rather than making changes to cse which may 197350397Sobrien or may not be easy/clean, we do our own cse. This is possible because 197450397Sobrien we will generate hard registers. Cse knows they're call clobbered (it 197550397Sobrien doesn't know the same thing about pseudos). If we guess wrong, no big 197650397Sobrien deal, but if we win, great! */ 197750397Sobrien 197850397Sobrien if (TARGET_V9 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) 197950397Sobrien#if 1 /* experiment */ 198050397Sobrien { 198150397Sobrien int reg; 198250397Sobrien /* We cycle through the registers to ensure they're all exercised. */ 198350397Sobrien static int next_fcc_reg = 0; 198450397Sobrien /* Previous x,y for each fcc reg. */ 198550397Sobrien static rtx prev_args[4][2]; 198650397Sobrien 198750397Sobrien /* Scan prev_args for x,y. */ 198850397Sobrien for (reg = 0; reg < 4; reg++) 198950397Sobrien if (prev_args[reg][0] == x && prev_args[reg][1] == y) 199050397Sobrien break; 199150397Sobrien if (reg == 4) 199250397Sobrien { 199350397Sobrien reg = next_fcc_reg; 199450397Sobrien prev_args[reg][0] = x; 199550397Sobrien prev_args[reg][1] = y; 199650397Sobrien next_fcc_reg = (next_fcc_reg + 1) & 3; 199750397Sobrien } 199850397Sobrien cc_reg = gen_rtx_REG (mode, reg + SPARC_FIRST_V9_FCC_REG); 199950397Sobrien } 200050397Sobrien#else 200150397Sobrien cc_reg = gen_reg_rtx (mode); 200250397Sobrien#endif /* ! experiment */ 200350397Sobrien else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) 200450397Sobrien cc_reg = gen_rtx_REG (mode, SPARC_FCC_REG); 200550397Sobrien else 200650397Sobrien cc_reg = gen_rtx_REG (mode, SPARC_ICC_REG); 200750397Sobrien 200852284Sobrien emit_insn (gen_rtx_SET (VOIDmode, cc_reg, 200950397Sobrien gen_rtx_COMPARE (mode, x, y))); 201050397Sobrien 201150397Sobrien return cc_reg; 201250397Sobrien} 201350397Sobrien 201450397Sobrien/* This function is used for v9 only. 201550397Sobrien CODE is the code for an Scc's comparison. 201650397Sobrien OPERANDS[0] is the target of the Scc insn. 201750397Sobrien OPERANDS[1] is the value we compare against const0_rtx (which hasn't 201850397Sobrien been generated yet). 201950397Sobrien 202050397Sobrien This function is needed to turn 202150397Sobrien 202250397Sobrien (set (reg:SI 110) 202350397Sobrien (gt (reg:CCX 100 %icc) 202450397Sobrien (const_int 0))) 202550397Sobrien into 202650397Sobrien (set (reg:SI 110) 202750397Sobrien (gt:DI (reg:CCX 100 %icc) 202850397Sobrien (const_int 0))) 202950397Sobrien 203050397Sobrien IE: The instruction recognizer needs to see the mode of the comparison to 203150397Sobrien find the right instruction. We could use "gt:DI" right in the 203250397Sobrien define_expand, but leaving it out allows us to handle DI, SI, etc. 203350397Sobrien 203450397Sobrien We refer to the global sparc compare operands sparc_compare_op0 and 203550397Sobrien sparc_compare_op1. */ 203650397Sobrien 203750397Sobrienint 2038132718Skangen_v9_scc (enum rtx_code compare_code, register rtx *operands) 203950397Sobrien{ 204050397Sobrien if (! TARGET_ARCH64 204150397Sobrien && (GET_MODE (sparc_compare_op0) == DImode 204250397Sobrien || GET_MODE (operands[0]) == DImode)) 204350397Sobrien return 0; 204450397Sobrien 204550397Sobrien /* Try to use the movrCC insns. */ 204650397Sobrien if (TARGET_ARCH64 2047169689Skan && GET_MODE_CLASS (GET_MODE (sparc_compare_op0)) == MODE_INT 2048169689Skan && sparc_compare_op1 == const0_rtx 204950397Sobrien && v9_regcmp_p (compare_code)) 205050397Sobrien { 2051169689Skan rtx op0 = sparc_compare_op0; 2052169689Skan rtx temp; 2053169689Skan 205450397Sobrien /* Special case for op0 != 0. This can be done with one instruction if 205596263Sobrien operands[0] == sparc_compare_op0. */ 205650397Sobrien 205750397Sobrien if (compare_code == NE 205850397Sobrien && GET_MODE (operands[0]) == DImode 205996263Sobrien && rtx_equal_p (op0, operands[0])) 206050397Sobrien { 206150397Sobrien emit_insn (gen_rtx_SET (VOIDmode, operands[0], 206250397Sobrien gen_rtx_IF_THEN_ELSE (DImode, 206350397Sobrien gen_rtx_fmt_ee (compare_code, DImode, 206450397Sobrien op0, const0_rtx), 206550397Sobrien const1_rtx, 206650397Sobrien operands[0]))); 206750397Sobrien return 1; 206850397Sobrien } 206950397Sobrien 207096263Sobrien if (reg_overlap_mentioned_p (operands[0], op0)) 207196263Sobrien { 207296263Sobrien /* Handle the case where operands[0] == sparc_compare_op0. 207396263Sobrien We "early clobber" the result. */ 207496263Sobrien op0 = gen_reg_rtx (GET_MODE (sparc_compare_op0)); 207596263Sobrien emit_move_insn (op0, sparc_compare_op0); 207696263Sobrien } 207796263Sobrien 207850397Sobrien emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx)); 207950397Sobrien if (GET_MODE (op0) != DImode) 208050397Sobrien { 208150397Sobrien temp = gen_reg_rtx (DImode); 208250397Sobrien convert_move (temp, op0, 0); 208350397Sobrien } 208450397Sobrien else 208550397Sobrien temp = op0; 208650397Sobrien emit_insn (gen_rtx_SET (VOIDmode, operands[0], 208750397Sobrien gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), 208850397Sobrien gen_rtx_fmt_ee (compare_code, DImode, 208950397Sobrien temp, const0_rtx), 209050397Sobrien const1_rtx, 209150397Sobrien operands[0]))); 209250397Sobrien return 1; 209350397Sobrien } 209450397Sobrien else 209550397Sobrien { 2096169689Skan operands[1] = gen_compare_reg (compare_code); 209750397Sobrien 209850397Sobrien switch (GET_MODE (operands[1])) 209950397Sobrien { 210050397Sobrien case CCmode : 210150397Sobrien case CCXmode : 210250397Sobrien case CCFPEmode : 210350397Sobrien case CCFPmode : 210450397Sobrien break; 210550397Sobrien default : 2106169689Skan gcc_unreachable (); 210750397Sobrien } 210850397Sobrien emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx)); 210950397Sobrien emit_insn (gen_rtx_SET (VOIDmode, operands[0], 211050397Sobrien gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), 211150397Sobrien gen_rtx_fmt_ee (compare_code, 211250397Sobrien GET_MODE (operands[1]), 211350397Sobrien operands[1], const0_rtx), 211450397Sobrien const1_rtx, operands[0]))); 211550397Sobrien return 1; 211650397Sobrien } 211750397Sobrien} 211850397Sobrien 211950397Sobrien/* Emit a conditional jump insn for the v9 architecture using comparison code 212050397Sobrien CODE and jump target LABEL. 212150397Sobrien This function exists to take advantage of the v9 brxx insns. */ 212250397Sobrien 212350397Sobrienvoid 2124132718Skanemit_v9_brxx_insn (enum rtx_code code, rtx op0, rtx label) 212550397Sobrien{ 2126169689Skan gcc_assert (sparc_compare_emitted == NULL_RTX); 212750397Sobrien emit_jump_insn (gen_rtx_SET (VOIDmode, 212850397Sobrien pc_rtx, 212950397Sobrien gen_rtx_IF_THEN_ELSE (VOIDmode, 213050397Sobrien gen_rtx_fmt_ee (code, GET_MODE (op0), 213150397Sobrien op0, const0_rtx), 213250397Sobrien gen_rtx_LABEL_REF (VOIDmode, label), 213350397Sobrien pc_rtx))); 213450397Sobrien} 213590075Sobrien 213690075Sobrien/* Generate a DFmode part of a hard TFmode register. 213790075Sobrien REG is the TFmode hard register, LOW is 1 for the 213890075Sobrien low 64bit of the register and 0 otherwise. 213990075Sobrien */ 214090075Sobrienrtx 2141132718Skangen_df_reg (rtx reg, int low) 214290075Sobrien{ 214390075Sobrien int regno = REGNO (reg); 214490075Sobrien 214590075Sobrien if ((WORDS_BIG_ENDIAN == 0) ^ (low != 0)) 214690075Sobrien regno += (TARGET_ARCH64 && regno < 32) ? 1 : 2; 214790075Sobrien return gen_rtx_REG (DFmode, regno); 214890075Sobrien} 214950397Sobrien 215096263Sobrien/* Generate a call to FUNC with OPERANDS. Operand 0 is the return value. 215196263Sobrien Unlike normal calls, TFmode operands are passed by reference. It is 215296263Sobrien assumed that no more than 3 operands are required. */ 215396263Sobrien 215496263Sobrienstatic void 2155132718Skanemit_soft_tfmode_libcall (const char *func_name, int nargs, rtx *operands) 215696263Sobrien{ 215796263Sobrien rtx ret_slot = NULL, arg[3], func_sym; 215896263Sobrien int i; 215996263Sobrien 216096263Sobrien /* We only expect to be called for conversions, unary, and binary ops. */ 2161169689Skan gcc_assert (nargs == 2 || nargs == 3); 216296263Sobrien 216396263Sobrien for (i = 0; i < nargs; ++i) 216496263Sobrien { 216596263Sobrien rtx this_arg = operands[i]; 216696263Sobrien rtx this_slot; 216796263Sobrien 216896263Sobrien /* TFmode arguments and return values are passed by reference. */ 216996263Sobrien if (GET_MODE (this_arg) == TFmode) 217096263Sobrien { 2171102780Skan int force_stack_temp; 2172102780Skan 2173102780Skan force_stack_temp = 0; 2174102780Skan if (TARGET_BUGGY_QP_LIB && i == 0) 2175102780Skan force_stack_temp = 1; 2176102780Skan 2177102780Skan if (GET_CODE (this_arg) == MEM 2178102780Skan && ! force_stack_temp) 217996263Sobrien this_arg = XEXP (this_arg, 0); 2180102780Skan else if (CONSTANT_P (this_arg) 2181102780Skan && ! force_stack_temp) 218296263Sobrien { 218396263Sobrien this_slot = force_const_mem (TFmode, this_arg); 218496263Sobrien this_arg = XEXP (this_slot, 0); 218596263Sobrien } 218696263Sobrien else 218796263Sobrien { 218896263Sobrien this_slot = assign_stack_temp (TFmode, GET_MODE_SIZE (TFmode), 0); 218996263Sobrien 219096263Sobrien /* Operand 0 is the return value. We'll copy it out later. */ 219196263Sobrien if (i > 0) 219296263Sobrien emit_move_insn (this_slot, this_arg); 219396263Sobrien else 219496263Sobrien ret_slot = this_slot; 219596263Sobrien 219696263Sobrien this_arg = XEXP (this_slot, 0); 219796263Sobrien } 219896263Sobrien } 219996263Sobrien 220096263Sobrien arg[i] = this_arg; 220196263Sobrien } 220296263Sobrien 220396263Sobrien func_sym = gen_rtx_SYMBOL_REF (Pmode, func_name); 220496263Sobrien 220596263Sobrien if (GET_MODE (operands[0]) == TFmode) 220696263Sobrien { 220796263Sobrien if (nargs == 2) 220896263Sobrien emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 2, 220996263Sobrien arg[0], GET_MODE (arg[0]), 221096263Sobrien arg[1], GET_MODE (arg[1])); 221196263Sobrien else 221296263Sobrien emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 3, 221396263Sobrien arg[0], GET_MODE (arg[0]), 221496263Sobrien arg[1], GET_MODE (arg[1]), 221596263Sobrien arg[2], GET_MODE (arg[2])); 221696263Sobrien 221796263Sobrien if (ret_slot) 221896263Sobrien emit_move_insn (operands[0], ret_slot); 221996263Sobrien } 222096263Sobrien else 222196263Sobrien { 222296263Sobrien rtx ret; 222396263Sobrien 2224169689Skan gcc_assert (nargs == 2); 222596263Sobrien 222696263Sobrien ret = emit_library_call_value (func_sym, operands[0], LCT_NORMAL, 222796263Sobrien GET_MODE (operands[0]), 1, 222896263Sobrien arg[1], GET_MODE (arg[1])); 222996263Sobrien 223096263Sobrien if (ret != operands[0]) 223196263Sobrien emit_move_insn (operands[0], ret); 223296263Sobrien } 223396263Sobrien} 223496263Sobrien 223596263Sobrien/* Expand soft-float TFmode calls to sparc abi routines. */ 223696263Sobrien 223796263Sobrienstatic void 2238132718Skanemit_soft_tfmode_binop (enum rtx_code code, rtx *operands) 223996263Sobrien{ 224096263Sobrien const char *func; 224196263Sobrien 224296263Sobrien switch (code) 224396263Sobrien { 224496263Sobrien case PLUS: 224596263Sobrien func = "_Qp_add"; 224696263Sobrien break; 224796263Sobrien case MINUS: 224896263Sobrien func = "_Qp_sub"; 224996263Sobrien break; 225096263Sobrien case MULT: 225196263Sobrien func = "_Qp_mul"; 225296263Sobrien break; 225396263Sobrien case DIV: 225496263Sobrien func = "_Qp_div"; 225596263Sobrien break; 225696263Sobrien default: 2257169689Skan gcc_unreachable (); 225896263Sobrien } 225996263Sobrien 226096263Sobrien emit_soft_tfmode_libcall (func, 3, operands); 226196263Sobrien} 226296263Sobrien 226396263Sobrienstatic void 2264132718Skanemit_soft_tfmode_unop (enum rtx_code code, rtx *operands) 226596263Sobrien{ 226696263Sobrien const char *func; 226796263Sobrien 2268169689Skan gcc_assert (code == SQRT); 2269169689Skan func = "_Qp_sqrt"; 227096263Sobrien 227196263Sobrien emit_soft_tfmode_libcall (func, 2, operands); 227296263Sobrien} 227396263Sobrien 227496263Sobrienstatic void 2275132718Skanemit_soft_tfmode_cvt (enum rtx_code code, rtx *operands) 227696263Sobrien{ 227796263Sobrien const char *func; 227896263Sobrien 227996263Sobrien switch (code) 228096263Sobrien { 228196263Sobrien case FLOAT_EXTEND: 228296263Sobrien switch (GET_MODE (operands[1])) 228396263Sobrien { 228496263Sobrien case SFmode: 228596263Sobrien func = "_Qp_stoq"; 228696263Sobrien break; 228796263Sobrien case DFmode: 228896263Sobrien func = "_Qp_dtoq"; 228996263Sobrien break; 229096263Sobrien default: 2291169689Skan gcc_unreachable (); 229296263Sobrien } 229396263Sobrien break; 229496263Sobrien 229596263Sobrien case FLOAT_TRUNCATE: 229696263Sobrien switch (GET_MODE (operands[0])) 229796263Sobrien { 229896263Sobrien case SFmode: 229996263Sobrien func = "_Qp_qtos"; 230096263Sobrien break; 230196263Sobrien case DFmode: 230296263Sobrien func = "_Qp_qtod"; 230396263Sobrien break; 230496263Sobrien default: 2305169689Skan gcc_unreachable (); 230696263Sobrien } 230796263Sobrien break; 230896263Sobrien 230996263Sobrien case FLOAT: 231096263Sobrien switch (GET_MODE (operands[1])) 231196263Sobrien { 231296263Sobrien case SImode: 231396263Sobrien func = "_Qp_itoq"; 231496263Sobrien break; 231596263Sobrien case DImode: 231696263Sobrien func = "_Qp_xtoq"; 231796263Sobrien break; 231896263Sobrien default: 2319169689Skan gcc_unreachable (); 232096263Sobrien } 232196263Sobrien break; 232296263Sobrien 232396263Sobrien case UNSIGNED_FLOAT: 232496263Sobrien switch (GET_MODE (operands[1])) 232596263Sobrien { 232696263Sobrien case SImode: 232796263Sobrien func = "_Qp_uitoq"; 232896263Sobrien break; 232996263Sobrien case DImode: 233096263Sobrien func = "_Qp_uxtoq"; 233196263Sobrien break; 233296263Sobrien default: 2333169689Skan gcc_unreachable (); 233496263Sobrien } 233596263Sobrien break; 233696263Sobrien 233796263Sobrien case FIX: 233896263Sobrien switch (GET_MODE (operands[0])) 233996263Sobrien { 234096263Sobrien case SImode: 234196263Sobrien func = "_Qp_qtoi"; 234296263Sobrien break; 234396263Sobrien case DImode: 234496263Sobrien func = "_Qp_qtox"; 234596263Sobrien break; 234696263Sobrien default: 2347169689Skan gcc_unreachable (); 234896263Sobrien } 234996263Sobrien break; 235096263Sobrien 235196263Sobrien case UNSIGNED_FIX: 235296263Sobrien switch (GET_MODE (operands[0])) 235396263Sobrien { 235496263Sobrien case SImode: 235596263Sobrien func = "_Qp_qtoui"; 235696263Sobrien break; 235796263Sobrien case DImode: 235896263Sobrien func = "_Qp_qtoux"; 235996263Sobrien break; 236096263Sobrien default: 2361169689Skan gcc_unreachable (); 236296263Sobrien } 236396263Sobrien break; 236496263Sobrien 236596263Sobrien default: 2366169689Skan gcc_unreachable (); 236796263Sobrien } 236896263Sobrien 236996263Sobrien emit_soft_tfmode_libcall (func, 2, operands); 237096263Sobrien} 237196263Sobrien 237296263Sobrien/* Expand a hard-float tfmode operation. All arguments must be in 237396263Sobrien registers. */ 237496263Sobrien 237596263Sobrienstatic void 2376132718Skanemit_hard_tfmode_operation (enum rtx_code code, rtx *operands) 237796263Sobrien{ 237896263Sobrien rtx op, dest; 237996263Sobrien 2380169689Skan if (GET_RTX_CLASS (code) == RTX_UNARY) 238196263Sobrien { 238296263Sobrien operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); 238396263Sobrien op = gen_rtx_fmt_e (code, GET_MODE (operands[0]), operands[1]); 238496263Sobrien } 238596263Sobrien else 238696263Sobrien { 238796263Sobrien operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); 238896263Sobrien operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); 238996263Sobrien op = gen_rtx_fmt_ee (code, GET_MODE (operands[0]), 239096263Sobrien operands[1], operands[2]); 239196263Sobrien } 239296263Sobrien 239396263Sobrien if (register_operand (operands[0], VOIDmode)) 239496263Sobrien dest = operands[0]; 239596263Sobrien else 239696263Sobrien dest = gen_reg_rtx (GET_MODE (operands[0])); 239796263Sobrien 239896263Sobrien emit_insn (gen_rtx_SET (VOIDmode, dest, op)); 239996263Sobrien 240096263Sobrien if (dest != operands[0]) 240196263Sobrien emit_move_insn (operands[0], dest); 240296263Sobrien} 240396263Sobrien 240496263Sobrienvoid 2405132718Skanemit_tfmode_binop (enum rtx_code code, rtx *operands) 240696263Sobrien{ 240796263Sobrien if (TARGET_HARD_QUAD) 240896263Sobrien emit_hard_tfmode_operation (code, operands); 240996263Sobrien else 241096263Sobrien emit_soft_tfmode_binop (code, operands); 241196263Sobrien} 241296263Sobrien 241396263Sobrienvoid 2414132718Skanemit_tfmode_unop (enum rtx_code code, rtx *operands) 241596263Sobrien{ 241696263Sobrien if (TARGET_HARD_QUAD) 241796263Sobrien emit_hard_tfmode_operation (code, operands); 241896263Sobrien else 241996263Sobrien emit_soft_tfmode_unop (code, operands); 242096263Sobrien} 242196263Sobrien 242296263Sobrienvoid 2423132718Skanemit_tfmode_cvt (enum rtx_code code, rtx *operands) 242496263Sobrien{ 242596263Sobrien if (TARGET_HARD_QUAD) 242696263Sobrien emit_hard_tfmode_operation (code, operands); 242796263Sobrien else 242896263Sobrien emit_soft_tfmode_cvt (code, operands); 242996263Sobrien} 243096263Sobrien 243196263Sobrien/* Return nonzero if a branch/jump/call instruction will be emitting 243296263Sobrien nop into its delay slot. */ 243396263Sobrien 243496263Sobrienint 2435132718Skanempty_delay_slot (rtx insn) 243696263Sobrien{ 243796263Sobrien rtx seq; 243896263Sobrien 243996263Sobrien /* If no previous instruction (should not happen), return true. */ 244096263Sobrien if (PREV_INSN (insn) == NULL) 244196263Sobrien return 1; 244296263Sobrien 244396263Sobrien seq = NEXT_INSN (PREV_INSN (insn)); 244496263Sobrien if (GET_CODE (PATTERN (seq)) == SEQUENCE) 244596263Sobrien return 0; 244696263Sobrien 244796263Sobrien return 1; 244896263Sobrien} 244996263Sobrien 2450169689Skan/* Return nonzero if TRIAL can go into the call delay slot. */ 245150397Sobrien 245250397Sobrienint 2453169689Skantls_call_delay (rtx trial) 245450397Sobrien{ 2455169689Skan rtx pat; 245650397Sobrien 2457169689Skan /* Binutils allows 2458169689Skan call __tls_get_addr, %tgd_call (foo) 2459169689Skan add %l7, %o0, %o0, %tgd_add (foo) 2460169689Skan while Sun as/ld does not. */ 2461169689Skan if (TARGET_GNU_TLS || !TARGET_TLS) 2462169689Skan return 1; 246350397Sobrien 2464169689Skan pat = PATTERN (trial); 246550397Sobrien 2466169689Skan /* We must reject tgd_add{32|64}, i.e. 2467169689Skan (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSGD))) 2468169689Skan and tldm_add{32|64}, i.e. 2469169689Skan (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSLDM))) 2470169689Skan for Sun as/ld. */ 2471169689Skan if (GET_CODE (pat) == SET 2472169689Skan && GET_CODE (SET_SRC (pat)) == PLUS) 2473169689Skan { 2474169689Skan rtx unspec = XEXP (SET_SRC (pat), 1); 247550397Sobrien 2476169689Skan if (GET_CODE (unspec) == UNSPEC 2477169689Skan && (XINT (unspec, 1) == UNSPEC_TLSGD 2478169689Skan || XINT (unspec, 1) == UNSPEC_TLSLDM)) 2479169689Skan return 0; 248050397Sobrien } 248150397Sobrien 2482169689Skan return 1; 2483169689Skan} 248450397Sobrien 2485169689Skan/* Return nonzero if TRIAL, an insn, can be combined with a 'restore' 2486169689Skan instruction. RETURN_P is true if the v9 variant 'return' is to be 2487169689Skan considered in the test too. 248850397Sobrien 2489169689Skan TRIAL must be a SET whose destination is a REG appropriate for the 2490169689Skan 'restore' instruction or, if RETURN_P is true, for the 'return' 2491169689Skan instruction. */ 249290075Sobrien 2493169689Skanstatic int 2494169689Skaneligible_for_restore_insn (rtx trial, bool return_p) 2495169689Skan{ 2496169689Skan rtx pat = PATTERN (trial); 2497169689Skan rtx src = SET_SRC (pat); 249850397Sobrien 2499169689Skan /* The 'restore src,%g0,dest' pattern for word mode and below. */ 250090075Sobrien if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT 250190075Sobrien && arith_operand (src, GET_MODE (src))) 250252284Sobrien { 250352284Sobrien if (TARGET_ARCH64) 250452284Sobrien return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); 250552284Sobrien else 250652284Sobrien return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode); 250752284Sobrien } 250890075Sobrien 2509169689Skan /* The 'restore src,%g0,dest' pattern for double-word mode. */ 251090075Sobrien else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT 251190075Sobrien && arith_double_operand (src, GET_MODE (src))) 251250397Sobrien return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); 251350397Sobrien 2514169689Skan /* The 'restore src,%g0,dest' pattern for float if no FPU. */ 2515169689Skan else if (! TARGET_FPU && register_operand (src, SFmode)) 251650397Sobrien return 1; 251750397Sobrien 2518169689Skan /* The 'restore src,%g0,dest' pattern for double if no FPU. */ 2519169689Skan else if (! TARGET_FPU && TARGET_ARCH64 && register_operand (src, DFmode)) 2520169689Skan return 1; 2521169689Skan 2522169689Skan /* If we have the 'return' instruction, anything that does not use 252390075Sobrien local or output registers and can go into a delay slot wins. */ 2524169689Skan else if (return_p && TARGET_V9 && ! epilogue_renumber (&pat, 1) 2525169689Skan && (get_attr_in_uncond_branch_delay (trial) 2526169689Skan == IN_UNCOND_BRANCH_DELAY_TRUE)) 252790075Sobrien return 1; 252890075Sobrien 2529169689Skan /* The 'restore src1,src2,dest' pattern for SImode. */ 253050397Sobrien else if (GET_CODE (src) == PLUS 2531169689Skan && register_operand (XEXP (src, 0), SImode) 2532169689Skan && arith_operand (XEXP (src, 1), SImode)) 253350397Sobrien return 1; 253450397Sobrien 2535169689Skan /* The 'restore src1,src2,dest' pattern for DImode. */ 253650397Sobrien else if (GET_CODE (src) == PLUS 2537169689Skan && register_operand (XEXP (src, 0), DImode) 2538169689Skan && arith_double_operand (XEXP (src, 1), DImode)) 253950397Sobrien return 1; 254050397Sobrien 2541169689Skan /* The 'restore src1,%lo(src2),dest' pattern. */ 254290075Sobrien else if (GET_CODE (src) == LO_SUM 254390075Sobrien && ! TARGET_CM_MEDMID 254490075Sobrien && ((register_operand (XEXP (src, 0), SImode) 254590075Sobrien && immediate_operand (XEXP (src, 1), SImode)) 254690075Sobrien || (TARGET_ARCH64 254790075Sobrien && register_operand (XEXP (src, 0), DImode) 254890075Sobrien && immediate_operand (XEXP (src, 1), DImode)))) 254990075Sobrien return 1; 255090075Sobrien 2551169689Skan /* The 'restore src,src,dest' pattern. */ 255290075Sobrien else if (GET_CODE (src) == ASHIFT 255390075Sobrien && (register_operand (XEXP (src, 0), SImode) 255490075Sobrien || register_operand (XEXP (src, 0), DImode)) 255590075Sobrien && XEXP (src, 1) == const1_rtx) 255690075Sobrien return 1; 255790075Sobrien 255850397Sobrien return 0; 255950397Sobrien} 256050397Sobrien 2561169689Skan/* Return nonzero if TRIAL can go into the function return's 2562169689Skan delay slot. */ 2563169689Skan 2564132718Skanint 2565169689Skaneligible_for_return_delay (rtx trial) 2566132718Skan{ 2567161651Skan rtx pat; 2568132718Skan 2569169689Skan if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET) 2570169689Skan return 0; 2571132718Skan 2572169689Skan if (get_attr_length (trial) != 1) 2573169689Skan return 0; 2574169689Skan 2575169689Skan /* If there are any call-saved registers, we should scan TRIAL if it 2576169689Skan does not reference them. For now just make it easy. */ 2577169689Skan if (num_gfregs) 2578169689Skan return 0; 2579169689Skan 2580169689Skan /* If the function uses __builtin_eh_return, the eh_return machinery 2581169689Skan occupies the delay slot. */ 2582169689Skan if (current_function_calls_eh_return) 2583169689Skan return 0; 2584169689Skan 2585169689Skan /* In the case of a true leaf function, anything can go into the slot. */ 2586169689Skan if (sparc_leaf_function_p) 2587169689Skan return get_attr_in_uncond_branch_delay (trial) 2588169689Skan == IN_UNCOND_BRANCH_DELAY_TRUE; 2589169689Skan 2590132718Skan pat = PATTERN (trial); 2591132718Skan 2592169689Skan /* Otherwise, only operations which can be done in tandem with 2593169689Skan a `restore' or `return' insn can go into the delay slot. */ 2594169689Skan if (GET_CODE (SET_DEST (pat)) != REG 2595169689Skan || (REGNO (SET_DEST (pat)) >= 8 && REGNO (SET_DEST (pat)) < 24)) 2596169689Skan return 0; 2597132718Skan 2598169689Skan /* If this instruction sets up floating point register and we have a return 2599169689Skan instruction, it can probably go in. But restore will not work 2600169689Skan with FP_REGS. */ 2601169689Skan if (REGNO (SET_DEST (pat)) >= 32) 2602169689Skan return (TARGET_V9 2603169689Skan && ! epilogue_renumber (&pat, 1) 2604169689Skan && (get_attr_in_uncond_branch_delay (trial) 2605169689Skan == IN_UNCOND_BRANCH_DELAY_TRUE)); 2606161651Skan 2607169689Skan return eligible_for_restore_insn (trial, true); 2608132718Skan} 2609132718Skan 2610169689Skan/* Return nonzero if TRIAL can go into the sibling call's 261190075Sobrien delay slot. */ 261290075Sobrien 261390075Sobrienint 2614132718Skaneligible_for_sibcall_delay (rtx trial) 261590075Sobrien{ 2616169689Skan rtx pat; 261790075Sobrien 261890075Sobrien if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET) 261990075Sobrien return 0; 262090075Sobrien 262190075Sobrien if (get_attr_length (trial) != 1) 262290075Sobrien return 0; 262390075Sobrien 262490075Sobrien pat = PATTERN (trial); 262590075Sobrien 2626169689Skan if (sparc_leaf_function_p) 262790075Sobrien { 262890075Sobrien /* If the tail call is done using the call instruction, 262990075Sobrien we have to restore %o7 in the delay slot. */ 2630169689Skan if (LEAF_SIBCALL_SLOT_RESERVED_P) 263190075Sobrien return 0; 263290075Sobrien 263390075Sobrien /* %g1 is used to build the function address */ 263490075Sobrien if (reg_mentioned_p (gen_rtx_REG (Pmode, 1), pat)) 263590075Sobrien return 0; 263690075Sobrien 263790075Sobrien return 1; 263890075Sobrien } 263990075Sobrien 264090075Sobrien /* Otherwise, only operations which can be done in tandem with 264190075Sobrien a `restore' insn can go into the delay slot. */ 264290075Sobrien if (GET_CODE (SET_DEST (pat)) != REG 2643169689Skan || (REGNO (SET_DEST (pat)) >= 8 && REGNO (SET_DEST (pat)) < 24) 264490075Sobrien || REGNO (SET_DEST (pat)) >= 32) 264590075Sobrien return 0; 264690075Sobrien 264790075Sobrien /* If it mentions %o7, it can't go in, because sibcall will clobber it 264890075Sobrien in most cases. */ 264990075Sobrien if (reg_mentioned_p (gen_rtx_REG (Pmode, 15), pat)) 265090075Sobrien return 0; 265190075Sobrien 2652169689Skan return eligible_for_restore_insn (trial, false); 265390075Sobrien} 265490075Sobrien 265550397Sobrienint 2656132718Skanshort_branch (int uid1, int uid2) 265750397Sobrien{ 265890075Sobrien int delta = INSN_ADDRESSES (uid1) - INSN_ADDRESSES (uid2); 265990075Sobrien 266090075Sobrien /* Leave a few words of "slop". */ 266190075Sobrien if (delta >= -1023 && delta <= 1022) 266250397Sobrien return 1; 266390075Sobrien 266450397Sobrien return 0; 266550397Sobrien} 266650397Sobrien 2667117395Skan/* Return nonzero if REG is not used after INSN. 266850397Sobrien We assume REG is a reload reg, and therefore does 266950397Sobrien not live past labels or calls or jumps. */ 267050397Sobrienint 2671132718Skanreg_unused_after (rtx reg, rtx insn) 267250397Sobrien{ 267350397Sobrien enum rtx_code code, prev_code = UNKNOWN; 267450397Sobrien 267550397Sobrien while ((insn = NEXT_INSN (insn))) 267650397Sobrien { 267750397Sobrien if (prev_code == CALL_INSN && call_used_regs[REGNO (reg)]) 267850397Sobrien return 1; 267950397Sobrien 268050397Sobrien code = GET_CODE (insn); 268150397Sobrien if (GET_CODE (insn) == CODE_LABEL) 268250397Sobrien return 1; 268350397Sobrien 2684169689Skan if (INSN_P (insn)) 268550397Sobrien { 268650397Sobrien rtx set = single_set (insn); 268750397Sobrien int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set)); 268850397Sobrien if (set && in_src) 268950397Sobrien return 0; 269050397Sobrien if (set && reg_overlap_mentioned_p (reg, SET_DEST (set))) 269150397Sobrien return 1; 269250397Sobrien if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn))) 269350397Sobrien return 0; 269450397Sobrien } 269550397Sobrien prev_code = code; 269650397Sobrien } 269750397Sobrien return 1; 269850397Sobrien} 269950397Sobrien 2700132718Skan/* Determine if it's legal to put X into the constant pool. This 2701132718Skan is not possible if X contains the address of a symbol that is 2702132718Skan not constant (TLS) or not known at final link time (PIC). */ 2703132718Skan 2704132718Skanstatic bool 2705132718Skansparc_cannot_force_const_mem (rtx x) 2706132718Skan{ 2707132718Skan switch (GET_CODE (x)) 2708132718Skan { 2709132718Skan case CONST_INT: 2710132718Skan case CONST_DOUBLE: 2711169689Skan case CONST_VECTOR: 2712132718Skan /* Accept all non-symbolic constants. */ 2713132718Skan return false; 2714132718Skan 2715132718Skan case LABEL_REF: 2716132718Skan /* Labels are OK iff we are non-PIC. */ 2717132718Skan return flag_pic != 0; 2718132718Skan 2719132718Skan case SYMBOL_REF: 2720132718Skan /* 'Naked' TLS symbol references are never OK, 2721132718Skan non-TLS symbols are OK iff we are non-PIC. */ 2722132718Skan if (SYMBOL_REF_TLS_MODEL (x)) 2723132718Skan return true; 2724132718Skan else 2725132718Skan return flag_pic != 0; 2726132718Skan 2727132718Skan case CONST: 2728132718Skan return sparc_cannot_force_const_mem (XEXP (x, 0)); 2729132718Skan case PLUS: 2730132718Skan case MINUS: 2731132718Skan return sparc_cannot_force_const_mem (XEXP (x, 0)) 2732132718Skan || sparc_cannot_force_const_mem (XEXP (x, 1)); 2733132718Skan case UNSPEC: 2734132718Skan return true; 2735132718Skan default: 2736169689Skan gcc_unreachable (); 2737132718Skan } 2738132718Skan} 2739132718Skan 2740169689Skan/* PIC support. */ 2741169689Skanstatic GTY(()) char pic_helper_symbol_name[256]; 2742169689Skanstatic GTY(()) rtx pic_helper_symbol; 2743169689Skanstatic GTY(()) bool pic_helper_emitted_p = false; 2744117395Skanstatic GTY(()) rtx global_offset_table; 274550397Sobrien 274650397Sobrien/* Ensure that we are not using patterns that are not OK with PIC. */ 274750397Sobrien 274850397Sobrienint 2749132718Skancheck_pic (int i) 275050397Sobrien{ 275150397Sobrien switch (flag_pic) 275250397Sobrien { 275350397Sobrien case 1: 2754169689Skan gcc_assert (GET_CODE (recog_data.operand[i]) != SYMBOL_REF 2755169689Skan && (GET_CODE (recog_data.operand[i]) != CONST 2756169689Skan || (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS 2757169689Skan && (XEXP (XEXP (recog_data.operand[i], 0), 0) 2758169689Skan == global_offset_table) 2759169689Skan && (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1)) 2760169689Skan == CONST)))); 276150397Sobrien case 2: 276250397Sobrien default: 276350397Sobrien return 1; 276450397Sobrien } 276550397Sobrien} 276650397Sobrien 276750397Sobrien/* Return true if X is an address which needs a temporary register when 276850397Sobrien reloaded while generating PIC code. */ 276950397Sobrien 277050397Sobrienint 2771132718Skanpic_address_needs_scratch (rtx x) 277250397Sobrien{ 277350397Sobrien /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ 277450397Sobrien if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS 277550397Sobrien && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF 277650397Sobrien && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT 277750397Sobrien && ! SMALL_INT (XEXP (XEXP (x, 0), 1))) 277850397Sobrien return 1; 277950397Sobrien 278050397Sobrien return 0; 278150397Sobrien} 278250397Sobrien 2783132718Skan/* Determine if a given RTX is a valid constant. We already know this 2784132718Skan satisfies CONSTANT_P. */ 2785132718Skan 2786132718Skanbool 2787132718Skanlegitimate_constant_p (rtx x) 2788132718Skan{ 2789132718Skan rtx inner; 2790132718Skan 2791132718Skan switch (GET_CODE (x)) 2792132718Skan { 2793132718Skan case SYMBOL_REF: 2794132718Skan /* TLS symbols are not constant. */ 2795132718Skan if (SYMBOL_REF_TLS_MODEL (x)) 2796132718Skan return false; 2797132718Skan break; 2798132718Skan 2799132718Skan case CONST: 2800132718Skan inner = XEXP (x, 0); 2801132718Skan 2802132718Skan /* Offsets of TLS symbols are never valid. 2803132718Skan Discourage CSE from creating them. */ 2804132718Skan if (GET_CODE (inner) == PLUS 2805169689Skan && SPARC_SYMBOL_REF_TLS_P (XEXP (inner, 0))) 2806132718Skan return false; 2807132718Skan break; 2808132718Skan 2809132718Skan case CONST_DOUBLE: 2810132718Skan if (GET_MODE (x) == VOIDmode) 2811132718Skan return true; 2812132718Skan 2813132718Skan /* Floating point constants are generally not ok. 2814132718Skan The only exception is 0.0 in VIS. */ 2815132718Skan if (TARGET_VIS 2816169689Skan && SCALAR_FLOAT_MODE_P (GET_MODE (x)) 2817169689Skan && const_zero_operand (x, GET_MODE (x))) 2818132718Skan return true; 2819132718Skan 2820132718Skan return false; 2821132718Skan 2822169689Skan case CONST_VECTOR: 2823169689Skan /* Vector constants are generally not ok. 2824169689Skan The only exception is 0 in VIS. */ 2825169689Skan if (TARGET_VIS 2826169689Skan && const_zero_operand (x, GET_MODE (x))) 2827169689Skan return true; 2828169689Skan 2829169689Skan return false; 2830169689Skan 2831132718Skan default: 2832132718Skan break; 2833132718Skan } 2834132718Skan 2835132718Skan return true; 2836132718Skan} 2837132718Skan 2838132718Skan/* Determine if a given RTX is a valid constant address. */ 2839132718Skan 2840132718Skanbool 2841132718Skanconstant_address_p (rtx x) 2842132718Skan{ 2843132718Skan switch (GET_CODE (x)) 2844132718Skan { 2845132718Skan case LABEL_REF: 2846132718Skan case CONST_INT: 2847132718Skan case HIGH: 2848132718Skan return true; 2849132718Skan 2850132718Skan case CONST: 2851132718Skan if (flag_pic && pic_address_needs_scratch (x)) 2852132718Skan return false; 2853132718Skan return legitimate_constant_p (x); 2854132718Skan 2855132718Skan case SYMBOL_REF: 2856132718Skan return !flag_pic && legitimate_constant_p (x); 2857132718Skan 2858132718Skan default: 2859132718Skan return false; 2860132718Skan } 2861132718Skan} 2862132718Skan 2863132718Skan/* Nonzero if the constant value X is a legitimate general operand 2864132718Skan when generating PIC code. It is given that flag_pic is on and 2865132718Skan that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ 2866132718Skan 2867132718Skanbool 2868132718Skanlegitimate_pic_operand_p (rtx x) 2869132718Skan{ 2870132718Skan if (pic_address_needs_scratch (x)) 2871132718Skan return false; 2872169689Skan if (SPARC_SYMBOL_REF_TLS_P (x) 2873132718Skan || (GET_CODE (x) == CONST 2874132718Skan && GET_CODE (XEXP (x, 0)) == PLUS 2875169689Skan && SPARC_SYMBOL_REF_TLS_P (XEXP (XEXP (x, 0), 0)))) 2876132718Skan return false; 2877132718Skan return true; 2878132718Skan} 2879132718Skan 2880132718Skan/* Return nonzero if ADDR is a valid memory address. 2881132718Skan STRICT specifies whether strict register checking applies. */ 2882132718Skan 2883132718Skanint 2884132718Skanlegitimate_address_p (enum machine_mode mode, rtx addr, int strict) 2885132718Skan{ 2886146895Skan rtx rs1 = NULL, rs2 = NULL, imm1 = NULL; 2887132718Skan 2888132718Skan if (REG_P (addr) || GET_CODE (addr) == SUBREG) 2889132718Skan rs1 = addr; 2890132718Skan else if (GET_CODE (addr) == PLUS) 2891132718Skan { 2892132718Skan rs1 = XEXP (addr, 0); 2893132718Skan rs2 = XEXP (addr, 1); 2894132718Skan 2895132718Skan /* Canonicalize. REG comes first, if there are no regs, 2896132718Skan LO_SUM comes first. */ 2897132718Skan if (!REG_P (rs1) 2898132718Skan && GET_CODE (rs1) != SUBREG 2899132718Skan && (REG_P (rs2) 2900132718Skan || GET_CODE (rs2) == SUBREG 2901132718Skan || (GET_CODE (rs2) == LO_SUM && GET_CODE (rs1) != LO_SUM))) 2902132718Skan { 2903132718Skan rs1 = XEXP (addr, 1); 2904132718Skan rs2 = XEXP (addr, 0); 2905132718Skan } 2906132718Skan 2907132718Skan if ((flag_pic == 1 2908132718Skan && rs1 == pic_offset_table_rtx 2909132718Skan && !REG_P (rs2) 2910132718Skan && GET_CODE (rs2) != SUBREG 2911132718Skan && GET_CODE (rs2) != LO_SUM 2912132718Skan && GET_CODE (rs2) != MEM 2913169689Skan && ! SPARC_SYMBOL_REF_TLS_P (rs2) 2914132718Skan && (! symbolic_operand (rs2, VOIDmode) || mode == Pmode) 2915132718Skan && (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2))) 2916132718Skan || ((REG_P (rs1) 2917132718Skan || GET_CODE (rs1) == SUBREG) 2918132718Skan && RTX_OK_FOR_OFFSET_P (rs2))) 2919132718Skan { 2920132718Skan imm1 = rs2; 2921132718Skan rs2 = NULL; 2922132718Skan } 2923132718Skan else if ((REG_P (rs1) || GET_CODE (rs1) == SUBREG) 2924132718Skan && (REG_P (rs2) || GET_CODE (rs2) == SUBREG)) 2925132718Skan { 2926146895Skan /* We prohibit REG + REG for TFmode when there are no quad move insns 2927146895Skan and we consequently need to split. We do this because REG+REG 2928146895Skan is not an offsettable address. If we get the situation in reload 2929132718Skan where source and destination of a movtf pattern are both MEMs with 2930132718Skan REG+REG address, then only one of them gets converted to an 2931146895Skan offsettable address. */ 2932132718Skan if (mode == TFmode 2933146895Skan && ! (TARGET_FPU && TARGET_ARCH64 && TARGET_HARD_QUAD)) 2934132718Skan return 0; 2935132718Skan 2936132718Skan /* We prohibit REG + REG on ARCH32 if not optimizing for 2937132718Skan DFmode/DImode because then mem_min_alignment is likely to be zero 2938132718Skan after reload and the forced split would lack a matching splitter 2939132718Skan pattern. */ 2940132718Skan if (TARGET_ARCH32 && !optimize 2941132718Skan && (mode == DFmode || mode == DImode)) 2942132718Skan return 0; 2943132718Skan } 2944132718Skan else if (USE_AS_OFFSETABLE_LO10 2945132718Skan && GET_CODE (rs1) == LO_SUM 2946132718Skan && TARGET_ARCH64 2947132718Skan && ! TARGET_CM_MEDMID 2948132718Skan && RTX_OK_FOR_OLO10_P (rs2)) 2949132718Skan { 2950132718Skan rs2 = NULL; 2951132718Skan imm1 = XEXP (rs1, 1); 2952132718Skan rs1 = XEXP (rs1, 0); 2953169689Skan if (! CONSTANT_P (imm1) || SPARC_SYMBOL_REF_TLS_P (rs1)) 2954132718Skan return 0; 2955132718Skan } 2956132718Skan } 2957132718Skan else if (GET_CODE (addr) == LO_SUM) 2958132718Skan { 2959132718Skan rs1 = XEXP (addr, 0); 2960132718Skan imm1 = XEXP (addr, 1); 2961132718Skan 2962169689Skan if (! CONSTANT_P (imm1) || SPARC_SYMBOL_REF_TLS_P (rs1)) 2963132718Skan return 0; 2964132718Skan 2965146895Skan /* We can't allow TFmode in 32-bit mode, because an offset greater 2966146895Skan than the alignment (8) may cause the LO_SUM to overflow. */ 2967146895Skan if (mode == TFmode && TARGET_ARCH32) 2968132718Skan return 0; 2969132718Skan } 2970132718Skan else if (GET_CODE (addr) == CONST_INT && SMALL_INT (addr)) 2971132718Skan return 1; 2972132718Skan else 2973132718Skan return 0; 2974132718Skan 2975132718Skan if (GET_CODE (rs1) == SUBREG) 2976132718Skan rs1 = SUBREG_REG (rs1); 2977132718Skan if (!REG_P (rs1)) 2978132718Skan return 0; 2979132718Skan 2980132718Skan if (rs2) 2981132718Skan { 2982132718Skan if (GET_CODE (rs2) == SUBREG) 2983132718Skan rs2 = SUBREG_REG (rs2); 2984132718Skan if (!REG_P (rs2)) 2985132718Skan return 0; 2986132718Skan } 2987132718Skan 2988132718Skan if (strict) 2989132718Skan { 2990132718Skan if (!REGNO_OK_FOR_BASE_P (REGNO (rs1)) 2991132718Skan || (rs2 && !REGNO_OK_FOR_BASE_P (REGNO (rs2)))) 2992132718Skan return 0; 2993132718Skan } 2994132718Skan else 2995132718Skan { 2996132718Skan if ((REGNO (rs1) >= 32 2997132718Skan && REGNO (rs1) != FRAME_POINTER_REGNUM 2998132718Skan && REGNO (rs1) < FIRST_PSEUDO_REGISTER) 2999132718Skan || (rs2 3000132718Skan && (REGNO (rs2) >= 32 3001132718Skan && REGNO (rs2) != FRAME_POINTER_REGNUM 3002132718Skan && REGNO (rs2) < FIRST_PSEUDO_REGISTER))) 3003132718Skan return 0; 3004132718Skan } 3005132718Skan return 1; 3006132718Skan} 3007132718Skan 3008132718Skan/* Construct the SYMBOL_REF for the tls_get_offset function. */ 3009132718Skan 3010132718Skanstatic GTY(()) rtx sparc_tls_symbol; 3011169689Skan 3012132718Skanstatic rtx 3013132718Skansparc_tls_get_addr (void) 3014132718Skan{ 3015132718Skan if (!sparc_tls_symbol) 3016132718Skan sparc_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_addr"); 3017132718Skan 3018132718Skan return sparc_tls_symbol; 3019132718Skan} 3020132718Skan 3021132718Skanstatic rtx 3022132718Skansparc_tls_got (void) 3023132718Skan{ 3024132718Skan rtx temp; 3025132718Skan if (flag_pic) 3026132718Skan { 3027132718Skan current_function_uses_pic_offset_table = 1; 3028132718Skan return pic_offset_table_rtx; 3029132718Skan } 3030132718Skan 3031132718Skan if (!global_offset_table) 3032132718Skan global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); 3033132718Skan temp = gen_reg_rtx (Pmode); 3034132718Skan emit_move_insn (temp, global_offset_table); 3035132718Skan return temp; 3036132718Skan} 3037132718Skan 3038169689Skan/* Return 1 if *X is a thread-local symbol. */ 3039132718Skan 3040169689Skanstatic int 3041169689Skansparc_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED) 3042169689Skan{ 3043169689Skan return SPARC_SYMBOL_REF_TLS_P (*x); 3044169689Skan} 3045169689Skan 3046169689Skan/* Return 1 if X contains a thread-local symbol. */ 3047169689Skan 3048169689Skanbool 3049169689Skansparc_tls_referenced_p (rtx x) 3050169689Skan{ 3051169689Skan if (!TARGET_HAVE_TLS) 3052169689Skan return false; 3053169689Skan 3054169689Skan return for_each_rtx (&x, &sparc_tls_symbol_ref_1, 0); 3055169689Skan} 3056169689Skan 3057132718Skan/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute 3058132718Skan this (thread-local) address. */ 3059132718Skan 3060132718Skanrtx 3061132718Skanlegitimize_tls_address (rtx addr) 3062132718Skan{ 3063132718Skan rtx temp1, temp2, temp3, ret, o0, got, insn; 3064132718Skan 3065169689Skan gcc_assert (! no_new_pseudos); 3066132718Skan 3067132718Skan if (GET_CODE (addr) == SYMBOL_REF) 3068132718Skan switch (SYMBOL_REF_TLS_MODEL (addr)) 3069132718Skan { 3070132718Skan case TLS_MODEL_GLOBAL_DYNAMIC: 3071132718Skan start_sequence (); 3072132718Skan temp1 = gen_reg_rtx (SImode); 3073132718Skan temp2 = gen_reg_rtx (SImode); 3074132718Skan ret = gen_reg_rtx (Pmode); 3075132718Skan o0 = gen_rtx_REG (Pmode, 8); 3076132718Skan got = sparc_tls_got (); 3077132718Skan emit_insn (gen_tgd_hi22 (temp1, addr)); 3078132718Skan emit_insn (gen_tgd_lo10 (temp2, temp1, addr)); 3079132718Skan if (TARGET_ARCH32) 3080132718Skan { 3081132718Skan emit_insn (gen_tgd_add32 (o0, got, temp2, addr)); 3082132718Skan insn = emit_call_insn (gen_tgd_call32 (o0, sparc_tls_get_addr (), 3083132718Skan addr, const1_rtx)); 3084132718Skan } 3085132718Skan else 3086132718Skan { 3087132718Skan emit_insn (gen_tgd_add64 (o0, got, temp2, addr)); 3088132718Skan insn = emit_call_insn (gen_tgd_call64 (o0, sparc_tls_get_addr (), 3089132718Skan addr, const1_rtx)); 3090132718Skan } 3091132718Skan CALL_INSN_FUNCTION_USAGE (insn) 3092132718Skan = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, o0), 3093132718Skan CALL_INSN_FUNCTION_USAGE (insn)); 3094132718Skan insn = get_insns (); 3095132718Skan end_sequence (); 3096132718Skan emit_libcall_block (insn, ret, o0, addr); 3097132718Skan break; 3098132718Skan 3099132718Skan case TLS_MODEL_LOCAL_DYNAMIC: 3100132718Skan start_sequence (); 3101132718Skan temp1 = gen_reg_rtx (SImode); 3102132718Skan temp2 = gen_reg_rtx (SImode); 3103132718Skan temp3 = gen_reg_rtx (Pmode); 3104132718Skan ret = gen_reg_rtx (Pmode); 3105132718Skan o0 = gen_rtx_REG (Pmode, 8); 3106132718Skan got = sparc_tls_got (); 3107132718Skan emit_insn (gen_tldm_hi22 (temp1)); 3108132718Skan emit_insn (gen_tldm_lo10 (temp2, temp1)); 3109132718Skan if (TARGET_ARCH32) 3110132718Skan { 3111132718Skan emit_insn (gen_tldm_add32 (o0, got, temp2)); 3112132718Skan insn = emit_call_insn (gen_tldm_call32 (o0, sparc_tls_get_addr (), 3113132718Skan const1_rtx)); 3114132718Skan } 3115132718Skan else 3116132718Skan { 3117132718Skan emit_insn (gen_tldm_add64 (o0, got, temp2)); 3118132718Skan insn = emit_call_insn (gen_tldm_call64 (o0, sparc_tls_get_addr (), 3119132718Skan const1_rtx)); 3120132718Skan } 3121132718Skan CALL_INSN_FUNCTION_USAGE (insn) 3122132718Skan = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, o0), 3123132718Skan CALL_INSN_FUNCTION_USAGE (insn)); 3124132718Skan insn = get_insns (); 3125132718Skan end_sequence (); 3126132718Skan emit_libcall_block (insn, temp3, o0, 3127132718Skan gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), 3128132718Skan UNSPEC_TLSLD_BASE)); 3129132718Skan temp1 = gen_reg_rtx (SImode); 3130132718Skan temp2 = gen_reg_rtx (SImode); 3131132718Skan emit_insn (gen_tldo_hix22 (temp1, addr)); 3132132718Skan emit_insn (gen_tldo_lox10 (temp2, temp1, addr)); 3133132718Skan if (TARGET_ARCH32) 3134132718Skan emit_insn (gen_tldo_add32 (ret, temp3, temp2, addr)); 3135132718Skan else 3136132718Skan emit_insn (gen_tldo_add64 (ret, temp3, temp2, addr)); 3137132718Skan break; 3138132718Skan 3139132718Skan case TLS_MODEL_INITIAL_EXEC: 3140132718Skan temp1 = gen_reg_rtx (SImode); 3141132718Skan temp2 = gen_reg_rtx (SImode); 3142132718Skan temp3 = gen_reg_rtx (Pmode); 3143132718Skan got = sparc_tls_got (); 3144132718Skan emit_insn (gen_tie_hi22 (temp1, addr)); 3145132718Skan emit_insn (gen_tie_lo10 (temp2, temp1, addr)); 3146132718Skan if (TARGET_ARCH32) 3147132718Skan emit_insn (gen_tie_ld32 (temp3, got, temp2, addr)); 3148132718Skan else 3149132718Skan emit_insn (gen_tie_ld64 (temp3, got, temp2, addr)); 3150132718Skan if (TARGET_SUN_TLS) 3151132718Skan { 3152132718Skan ret = gen_reg_rtx (Pmode); 3153132718Skan if (TARGET_ARCH32) 3154132718Skan emit_insn (gen_tie_add32 (ret, gen_rtx_REG (Pmode, 7), 3155132718Skan temp3, addr)); 3156132718Skan else 3157132718Skan emit_insn (gen_tie_add64 (ret, gen_rtx_REG (Pmode, 7), 3158132718Skan temp3, addr)); 3159132718Skan } 3160132718Skan else 3161132718Skan ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 7), temp3); 3162132718Skan break; 3163132718Skan 3164132718Skan case TLS_MODEL_LOCAL_EXEC: 3165132718Skan temp1 = gen_reg_rtx (Pmode); 3166132718Skan temp2 = gen_reg_rtx (Pmode); 3167132718Skan if (TARGET_ARCH32) 3168132718Skan { 3169132718Skan emit_insn (gen_tle_hix22_sp32 (temp1, addr)); 3170132718Skan emit_insn (gen_tle_lox10_sp32 (temp2, temp1, addr)); 3171132718Skan } 3172132718Skan else 3173132718Skan { 3174132718Skan emit_insn (gen_tle_hix22_sp64 (temp1, addr)); 3175132718Skan emit_insn (gen_tle_lox10_sp64 (temp2, temp1, addr)); 3176132718Skan } 3177132718Skan ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 7), temp2); 3178132718Skan break; 3179132718Skan 3180132718Skan default: 3181169689Skan gcc_unreachable (); 3182132718Skan } 3183132718Skan 3184132718Skan else 3185169689Skan gcc_unreachable (); /* for now ... */ 3186132718Skan 3187132718Skan return ret; 3188132718Skan} 3189132718Skan 3190132718Skan 319150397Sobrien/* Legitimize PIC addresses. If the address is already position-independent, 319250397Sobrien we return ORIG. Newly generated position-independent addresses go into a 3193117395Skan reg. This is REG if nonzero, otherwise we allocate register(s) as 319450397Sobrien necessary. */ 319550397Sobrien 319650397Sobrienrtx 3197132718Skanlegitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, 3198132718Skan rtx reg) 319950397Sobrien{ 320052284Sobrien if (GET_CODE (orig) == SYMBOL_REF) 320150397Sobrien { 320250397Sobrien rtx pic_ref, address; 320350397Sobrien rtx insn; 320450397Sobrien 320550397Sobrien if (reg == 0) 320650397Sobrien { 3207169689Skan gcc_assert (! reload_in_progress && ! reload_completed); 3208169689Skan reg = gen_reg_rtx (Pmode); 320950397Sobrien } 321050397Sobrien 321150397Sobrien if (flag_pic == 2) 321250397Sobrien { 321350397Sobrien /* If not during reload, allocate another temp reg here for loading 321450397Sobrien in the address, so that these instructions can be optimized 321550397Sobrien properly. */ 321650397Sobrien rtx temp_reg = ((reload_in_progress || reload_completed) 321750397Sobrien ? reg : gen_reg_rtx (Pmode)); 321850397Sobrien 321950397Sobrien /* Must put the SYMBOL_REF inside an UNSPEC here so that cse 322050397Sobrien won't get confused into thinking that these two instructions 322150397Sobrien are loading in the true address of the symbol. If in the 322250397Sobrien future a PIC rtx exists, that should be used instead. */ 3223169689Skan if (TARGET_ARCH64) 322452284Sobrien { 3225169689Skan emit_insn (gen_movdi_high_pic (temp_reg, orig)); 3226169689Skan emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig)); 322752284Sobrien } 322852284Sobrien else 322952284Sobrien { 3230169689Skan emit_insn (gen_movsi_high_pic (temp_reg, orig)); 3231169689Skan emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig)); 323252284Sobrien } 323350397Sobrien address = temp_reg; 323450397Sobrien } 323550397Sobrien else 323650397Sobrien address = orig; 323750397Sobrien 3238169689Skan pic_ref = gen_const_mem (Pmode, 3239169689Skan gen_rtx_PLUS (Pmode, 3240169689Skan pic_offset_table_rtx, address)); 324150397Sobrien current_function_uses_pic_offset_table = 1; 324250397Sobrien insn = emit_move_insn (reg, pic_ref); 324350397Sobrien /* Put a REG_EQUAL note on this insn, so that it can be optimized 324450397Sobrien by loop. */ 324550397Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, 324650397Sobrien REG_NOTES (insn)); 324750397Sobrien return reg; 324850397Sobrien } 324950397Sobrien else if (GET_CODE (orig) == CONST) 325050397Sobrien { 325150397Sobrien rtx base, offset; 325250397Sobrien 325350397Sobrien if (GET_CODE (XEXP (orig, 0)) == PLUS 325450397Sobrien && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) 325550397Sobrien return orig; 325650397Sobrien 325750397Sobrien if (reg == 0) 325850397Sobrien { 3259169689Skan gcc_assert (! reload_in_progress && ! reload_completed); 3260169689Skan reg = gen_reg_rtx (Pmode); 326150397Sobrien } 326250397Sobrien 3263169689Skan gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS); 3264169689Skan base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); 3265169689Skan offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, 3266169689Skan base == reg ? 0 : reg); 326750397Sobrien 326850397Sobrien if (GET_CODE (offset) == CONST_INT) 326950397Sobrien { 327050397Sobrien if (SMALL_INT (offset)) 327190075Sobrien return plus_constant (base, INTVAL (offset)); 327250397Sobrien else if (! reload_in_progress && ! reload_completed) 327350397Sobrien offset = force_reg (Pmode, offset); 327450397Sobrien else 327550397Sobrien /* If we reach here, then something is seriously wrong. */ 3276169689Skan gcc_unreachable (); 327750397Sobrien } 327850397Sobrien return gen_rtx_PLUS (Pmode, base, offset); 327950397Sobrien } 328052284Sobrien else if (GET_CODE (orig) == LABEL_REF) 328152284Sobrien /* ??? Why do we do this? */ 328252284Sobrien /* Now movsi_pic_label_ref uses it, but we ought to be checking that 328352284Sobrien the register is live instead, in case it is eliminated. */ 328452284Sobrien current_function_uses_pic_offset_table = 1; 328550397Sobrien 328650397Sobrien return orig; 328750397Sobrien} 328850397Sobrien 3289132718Skan/* Try machine-dependent ways of modifying an illegitimate address X 3290132718Skan to be legitimate. If we find one, return the new, valid address. 3291132718Skan 3292132718Skan OLDX is the address as it was before break_out_memory_refs was called. 3293132718Skan In some cases it is useful to look at this to decide what needs to be done. 3294132718Skan 3295132718Skan MODE is the mode of the operand pointed to by X. */ 3296132718Skan 3297132718Skanrtx 3298132718Skanlegitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode) 3299132718Skan{ 3300132718Skan rtx orig_x = x; 3301132718Skan 3302132718Skan if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT) 3303132718Skan x = gen_rtx_PLUS (Pmode, XEXP (x, 1), 3304132718Skan force_operand (XEXP (x, 0), NULL_RTX)); 3305132718Skan if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == MULT) 3306132718Skan x = gen_rtx_PLUS (Pmode, XEXP (x, 0), 3307132718Skan force_operand (XEXP (x, 1), NULL_RTX)); 3308132718Skan if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS) 3309132718Skan x = gen_rtx_PLUS (Pmode, force_operand (XEXP (x, 0), NULL_RTX), 3310132718Skan XEXP (x, 1)); 3311132718Skan if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == PLUS) 3312132718Skan x = gen_rtx_PLUS (Pmode, XEXP (x, 0), 3313132718Skan force_operand (XEXP (x, 1), NULL_RTX)); 3314132718Skan 3315132718Skan if (x != orig_x && legitimate_address_p (mode, x, FALSE)) 3316132718Skan return x; 3317132718Skan 3318169689Skan if (SPARC_SYMBOL_REF_TLS_P (x)) 3319132718Skan x = legitimize_tls_address (x); 3320132718Skan else if (flag_pic) 3321132718Skan x = legitimize_pic_address (x, mode, 0); 3322132718Skan else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 1))) 3323132718Skan x = gen_rtx_PLUS (Pmode, XEXP (x, 0), 3324132718Skan copy_to_mode_reg (Pmode, XEXP (x, 1))); 3325132718Skan else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 0))) 3326132718Skan x = gen_rtx_PLUS (Pmode, XEXP (x, 1), 3327132718Skan copy_to_mode_reg (Pmode, XEXP (x, 0))); 3328132718Skan else if (GET_CODE (x) == SYMBOL_REF 3329132718Skan || GET_CODE (x) == CONST 3330132718Skan || GET_CODE (x) == LABEL_REF) 3331132718Skan x = copy_to_suggested_reg (x, NULL_RTX, Pmode); 3332132718Skan return x; 3333132718Skan} 3334132718Skan 3335169689Skan/* Emit the special PIC helper function. */ 333650397Sobrien 3337169689Skanstatic void 3338169689Skanemit_pic_helper (void) 333950397Sobrien{ 3340169689Skan const char *pic_name = reg_names[REGNO (pic_offset_table_rtx)]; 3341169689Skan int align; 334250397Sobrien 3343169689Skan switch_to_section (text_section); 334450397Sobrien 3345169689Skan align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); 3346169689Skan if (align > 0) 3347169689Skan ASM_OUTPUT_ALIGN (asm_out_file, align); 3348169689Skan ASM_OUTPUT_LABEL (asm_out_file, pic_helper_symbol_name); 3349169689Skan if (flag_delayed_branch) 3350169689Skan fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n", 3351169689Skan pic_name, pic_name); 3352169689Skan else 3353169689Skan fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n", 3354169689Skan pic_name, pic_name); 335552284Sobrien 3356169689Skan pic_helper_emitted_p = true; 3357169689Skan} 335850397Sobrien 3359169689Skan/* Emit code to load the PIC register. */ 3360169689Skan 3361169689Skanstatic void 3362169689Skanload_pic_register (bool delay_pic_helper) 3363169689Skan{ 3364169689Skan int orig_flag_pic = flag_pic; 3365169689Skan 3366169689Skan /* If we haven't initialized the special PIC symbols, do so now. */ 3367169689Skan if (!pic_helper_symbol_name[0]) 3368169689Skan { 3369169689Skan ASM_GENERATE_INTERNAL_LABEL (pic_helper_symbol_name, "LADDPC", 0); 3370169689Skan pic_helper_symbol = gen_rtx_SYMBOL_REF (Pmode, pic_helper_symbol_name); 3371169689Skan global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); 337250397Sobrien } 337350397Sobrien 3374169689Skan /* If we haven't emitted the special PIC helper function, do so now unless 3375169689Skan we are requested to delay it. */ 3376169689Skan if (!delay_pic_helper && !pic_helper_emitted_p) 3377169689Skan emit_pic_helper (); 3378169689Skan 337950397Sobrien flag_pic = 0; 3380169689Skan if (TARGET_ARCH64) 3381169689Skan emit_insn (gen_load_pcrel_symdi (pic_offset_table_rtx, global_offset_table, 3382169689Skan pic_helper_symbol)); 3383169689Skan else 3384169689Skan emit_insn (gen_load_pcrel_symsi (pic_offset_table_rtx, global_offset_table, 3385169689Skan pic_helper_symbol)); 338650397Sobrien flag_pic = orig_flag_pic; 338750397Sobrien 338850397Sobrien /* Need to emit this whether or not we obey regdecls, 338950397Sobrien since setjmp/longjmp can cause life info to screw up. 339050397Sobrien ??? In the case where we don't obey regdecls, this is not sufficient 339150397Sobrien since we may not fall out the bottom. */ 339250397Sobrien emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx)); 339350397Sobrien} 339450397Sobrien 339552284Sobrien/* Return 1 if RTX is a MEM which is known to be aligned to at 339696263Sobrien least a DESIRED byte boundary. */ 339750397Sobrien 339850397Sobrienint 3399132718Skanmem_min_alignment (rtx mem, int desired) 340050397Sobrien{ 340152284Sobrien rtx addr, base, offset; 340250397Sobrien 340352284Sobrien /* If it's not a MEM we can't accept it. */ 340450397Sobrien if (GET_CODE (mem) != MEM) 340552284Sobrien return 0; 340650397Sobrien 3407169689Skan /* Obviously... */ 3408169689Skan if (!TARGET_UNALIGNED_DOUBLES 3409169689Skan && MEM_ALIGN (mem) / BITS_PER_UNIT >= (unsigned)desired) 3410169689Skan return 1; 3411169689Skan 3412169689Skan /* ??? The rest of the function predates MEM_ALIGN so 3413169689Skan there is probably a bit of redundancy. */ 341450397Sobrien addr = XEXP (mem, 0); 341552284Sobrien base = offset = NULL_RTX; 341650397Sobrien if (GET_CODE (addr) == PLUS) 341750397Sobrien { 341852284Sobrien if (GET_CODE (XEXP (addr, 0)) == REG) 341950397Sobrien { 342050397Sobrien base = XEXP (addr, 0); 342152284Sobrien 342252284Sobrien /* What we are saying here is that if the base 342352284Sobrien REG is aligned properly, the compiler will make 342452284Sobrien sure any REG based index upon it will be so 342552284Sobrien as well. */ 342652284Sobrien if (GET_CODE (XEXP (addr, 1)) == CONST_INT) 342752284Sobrien offset = XEXP (addr, 1); 342852284Sobrien else 342952284Sobrien offset = const0_rtx; 343050397Sobrien } 343150397Sobrien } 343250397Sobrien else if (GET_CODE (addr) == REG) 343350397Sobrien { 343450397Sobrien base = addr; 343550397Sobrien offset = const0_rtx; 343650397Sobrien } 343750397Sobrien 343852284Sobrien if (base != NULL_RTX) 343950397Sobrien { 344052284Sobrien int regno = REGNO (base); 344150397Sobrien 344296263Sobrien if (regno != HARD_FRAME_POINTER_REGNUM && regno != STACK_POINTER_REGNUM) 344350397Sobrien { 344452284Sobrien /* Check if the compiler has recorded some information 344552284Sobrien about the alignment of the base REG. If reload has 344690075Sobrien completed, we already matched with proper alignments. 344790075Sobrien If not running global_alloc, reload might give us 344890075Sobrien unaligned pointer to local stack though. */ 344990075Sobrien if (((cfun != 0 345090075Sobrien && REGNO_POINTER_ALIGN (regno) >= desired * BITS_PER_UNIT) 345190075Sobrien || (optimize && reload_completed)) 345290075Sobrien && (INTVAL (offset) & (desired - 1)) == 0) 345352284Sobrien return 1; 345450397Sobrien } 345550397Sobrien else 345650397Sobrien { 345752284Sobrien if (((INTVAL (offset) - SPARC_STACK_BIAS) & (desired - 1)) == 0) 345852284Sobrien return 1; 345950397Sobrien } 346050397Sobrien } 346152284Sobrien else if (! TARGET_UNALIGNED_DOUBLES 346252284Sobrien || CONSTANT_P (addr) 346352284Sobrien || GET_CODE (addr) == LO_SUM) 346450397Sobrien { 346552284Sobrien /* Anything else we know is properly aligned unless TARGET_UNALIGNED_DOUBLES 346652284Sobrien is true, in which case we can only assume that an access is aligned if 346752284Sobrien it is to a constant address, or the address involves a LO_SUM. */ 346852284Sobrien return 1; 346950397Sobrien } 347050397Sobrien 347152284Sobrien /* An obviously unaligned address. */ 347252284Sobrien return 0; 347350397Sobrien} 347450397Sobrien 347550397Sobrien 347650397Sobrien/* Vectors to keep interesting information about registers where it can easily 3477117395Skan be got. We used to use the actual mode value as the bit number, but there 347850397Sobrien are more than 32 modes now. Instead we use two tables: one indexed by 347950397Sobrien hard register number, and one indexed by mode. */ 348050397Sobrien 348150397Sobrien/* The purpose of sparc_mode_class is to shrink the range of modes so that 348250397Sobrien they all fit (as bit numbers) in a 32 bit word (again). Each real mode is 348350397Sobrien mapped into one sparc_mode_class mode. */ 348450397Sobrien 348550397Sobrienenum sparc_mode_class { 348650397Sobrien S_MODE, D_MODE, T_MODE, O_MODE, 348750397Sobrien SF_MODE, DF_MODE, TF_MODE, OF_MODE, 348850397Sobrien CC_MODE, CCFP_MODE 348950397Sobrien}; 349050397Sobrien 349150397Sobrien/* Modes for single-word and smaller quantities. */ 349250397Sobrien#define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE)) 349350397Sobrien 349450397Sobrien/* Modes for double-word and smaller quantities. */ 349550397Sobrien#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE)) 349650397Sobrien 349750397Sobrien/* Modes for quad-word and smaller quantities. */ 349850397Sobrien#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE)) 349950397Sobrien 350090075Sobrien/* Modes for 8-word and smaller quantities. */ 350190075Sobrien#define O_MODES (T_MODES | (1 << (int) O_MODE) | (1 << (int) OF_MODE)) 350290075Sobrien 350350397Sobrien/* Modes for single-float quantities. We must allow any single word or 350450397Sobrien smaller quantity. This is because the fix/float conversion instructions 350550397Sobrien take integer inputs/outputs from the float registers. */ 350650397Sobrien#define SF_MODES (S_MODES) 350750397Sobrien 350850397Sobrien/* Modes for double-float and smaller quantities. */ 350950397Sobrien#define DF_MODES (S_MODES | D_MODES) 351050397Sobrien 351150397Sobrien/* Modes for double-float only quantities. */ 351290075Sobrien#define DF_MODES_NO_S ((1 << (int) D_MODE) | (1 << (int) DF_MODE)) 351350397Sobrien 351450397Sobrien/* Modes for quad-float only quantities. */ 351550397Sobrien#define TF_ONLY_MODES (1 << (int) TF_MODE) 351650397Sobrien 351750397Sobrien/* Modes for quad-float and smaller quantities. */ 351850397Sobrien#define TF_MODES (DF_MODES | TF_ONLY_MODES) 351950397Sobrien 352090075Sobrien/* Modes for quad-float and double-float quantities. */ 352190075Sobrien#define TF_MODES_NO_S (DF_MODES_NO_S | TF_ONLY_MODES) 352250397Sobrien 352390075Sobrien/* Modes for quad-float pair only quantities. */ 352490075Sobrien#define OF_ONLY_MODES (1 << (int) OF_MODE) 352590075Sobrien 352690075Sobrien/* Modes for quad-float pairs and smaller quantities. */ 352790075Sobrien#define OF_MODES (TF_MODES | OF_ONLY_MODES) 352890075Sobrien 352990075Sobrien#define OF_MODES_NO_S (TF_MODES_NO_S | OF_ONLY_MODES) 353090075Sobrien 353150397Sobrien/* Modes for condition codes. */ 353250397Sobrien#define CC_MODES (1 << (int) CC_MODE) 353350397Sobrien#define CCFP_MODES (1 << (int) CCFP_MODE) 353450397Sobrien 353550397Sobrien/* Value is 1 if register/mode pair is acceptable on sparc. 353650397Sobrien The funny mixture of D and T modes is because integer operations 353750397Sobrien do not specially operate on tetra quantities, so non-quad-aligned 353850397Sobrien registers can hold quadword quantities (except %o4 and %i4 because 353950397Sobrien they cross fixed registers). */ 354050397Sobrien 354150397Sobrien/* This points to either the 32 bit or the 64 bit version. */ 354290075Sobrienconst int *hard_regno_mode_classes; 354350397Sobrien 354490075Sobrienstatic const int hard_32bit_mode_classes[] = { 354550397Sobrien S_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, 354650397Sobrien T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES, 354750397Sobrien T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, 354850397Sobrien T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES, 354950397Sobrien 355090075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 355190075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 355290075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 355390075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES, 355450397Sobrien 355550397Sobrien /* FP regs f32 to f63. Only the even numbered registers actually exist, 355650397Sobrien and none can hold SFmode/SImode values. */ 355790075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 355890075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 355990075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 356090075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 356150397Sobrien 356250397Sobrien /* %fcc[0123] */ 356350397Sobrien CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES, 356450397Sobrien 356550397Sobrien /* %icc */ 356650397Sobrien CC_MODES 356750397Sobrien}; 356850397Sobrien 356990075Sobrienstatic const int hard_64bit_mode_classes[] = { 357050397Sobrien D_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, 357190075Sobrien O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, 357250397Sobrien T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, 357390075Sobrien O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, 357450397Sobrien 357590075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 357690075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 357790075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 357890075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES, 357950397Sobrien 358050397Sobrien /* FP regs f32 to f63. Only the even numbered registers actually exist, 358150397Sobrien and none can hold SFmode/SImode values. */ 358290075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 358390075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 358490075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 358590075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 358650397Sobrien 358750397Sobrien /* %fcc[0123] */ 358850397Sobrien CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES, 358950397Sobrien 359050397Sobrien /* %icc */ 359150397Sobrien CC_MODES 359250397Sobrien}; 359350397Sobrien 359450397Sobrienint sparc_mode_class [NUM_MACHINE_MODES]; 359550397Sobrien 359650397Sobrienenum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER]; 359750397Sobrien 359850397Sobrienstatic void 3599132718Skansparc_init_modes (void) 360050397Sobrien{ 360150397Sobrien int i; 360250397Sobrien 360350397Sobrien for (i = 0; i < NUM_MACHINE_MODES; i++) 360450397Sobrien { 360550397Sobrien switch (GET_MODE_CLASS (i)) 360650397Sobrien { 360750397Sobrien case MODE_INT: 360850397Sobrien case MODE_PARTIAL_INT: 360950397Sobrien case MODE_COMPLEX_INT: 361050397Sobrien if (GET_MODE_SIZE (i) <= 4) 361150397Sobrien sparc_mode_class[i] = 1 << (int) S_MODE; 361250397Sobrien else if (GET_MODE_SIZE (i) == 8) 361350397Sobrien sparc_mode_class[i] = 1 << (int) D_MODE; 361450397Sobrien else if (GET_MODE_SIZE (i) == 16) 361550397Sobrien sparc_mode_class[i] = 1 << (int) T_MODE; 361650397Sobrien else if (GET_MODE_SIZE (i) == 32) 361750397Sobrien sparc_mode_class[i] = 1 << (int) O_MODE; 361850397Sobrien else 361950397Sobrien sparc_mode_class[i] = 0; 362050397Sobrien break; 3621169689Skan case MODE_VECTOR_INT: 3622169689Skan if (GET_MODE_SIZE (i) <= 4) 3623169689Skan sparc_mode_class[i] = 1 << (int)SF_MODE; 3624169689Skan else if (GET_MODE_SIZE (i) == 8) 3625169689Skan sparc_mode_class[i] = 1 << (int)DF_MODE; 3626169689Skan break; 362750397Sobrien case MODE_FLOAT: 362850397Sobrien case MODE_COMPLEX_FLOAT: 362950397Sobrien if (GET_MODE_SIZE (i) <= 4) 363050397Sobrien sparc_mode_class[i] = 1 << (int) SF_MODE; 363150397Sobrien else if (GET_MODE_SIZE (i) == 8) 363250397Sobrien sparc_mode_class[i] = 1 << (int) DF_MODE; 363350397Sobrien else if (GET_MODE_SIZE (i) == 16) 363450397Sobrien sparc_mode_class[i] = 1 << (int) TF_MODE; 363550397Sobrien else if (GET_MODE_SIZE (i) == 32) 363650397Sobrien sparc_mode_class[i] = 1 << (int) OF_MODE; 363750397Sobrien else 363850397Sobrien sparc_mode_class[i] = 0; 363950397Sobrien break; 364050397Sobrien case MODE_CC: 364150397Sobrien if (i == (int) CCFPmode || i == (int) CCFPEmode) 364250397Sobrien sparc_mode_class[i] = 1 << (int) CCFP_MODE; 3643132718Skan else 364450397Sobrien sparc_mode_class[i] = 1 << (int) CC_MODE; 364550397Sobrien break; 3646132718Skan default: 3647132718Skan sparc_mode_class[i] = 0; 3648132718Skan break; 364950397Sobrien } 365050397Sobrien } 365150397Sobrien 365250397Sobrien if (TARGET_ARCH64) 365350397Sobrien hard_regno_mode_classes = hard_64bit_mode_classes; 365450397Sobrien else 365550397Sobrien hard_regno_mode_classes = hard_32bit_mode_classes; 365650397Sobrien 365750397Sobrien /* Initialize the array used by REGNO_REG_CLASS. */ 365850397Sobrien for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 365950397Sobrien { 366050397Sobrien if (i < 16 && TARGET_V8PLUS) 366150397Sobrien sparc_regno_reg_class[i] = I64_REGS; 366296263Sobrien else if (i < 32 || i == FRAME_POINTER_REGNUM) 366350397Sobrien sparc_regno_reg_class[i] = GENERAL_REGS; 366450397Sobrien else if (i < 64) 366550397Sobrien sparc_regno_reg_class[i] = FP_REGS; 366650397Sobrien else if (i < 96) 366750397Sobrien sparc_regno_reg_class[i] = EXTRA_FP_REGS; 366850397Sobrien else if (i < 100) 366950397Sobrien sparc_regno_reg_class[i] = FPCC_REGS; 367050397Sobrien else 367150397Sobrien sparc_regno_reg_class[i] = NO_REGS; 367250397Sobrien } 367350397Sobrien} 367450397Sobrien 367550397Sobrien/* Compute the frame size required by the function. This function is called 3676169689Skan during the reload pass and also by sparc_expand_prologue. */ 367750397Sobrien 3678132718SkanHOST_WIDE_INT 3679169689Skansparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p) 368050397Sobrien{ 368150397Sobrien int outgoing_args_size = (current_function_outgoing_args_size 368250397Sobrien + REG_PARM_STACK_SPACE (current_function_decl)); 3683169689Skan int n_regs = 0; /* N_REGS is the number of 4-byte regs saved thus far. */ 3684169689Skan int i; 368550397Sobrien 368696263Sobrien if (TARGET_ARCH64) 368750397Sobrien { 368896263Sobrien for (i = 0; i < 8; i++) 368996263Sobrien if (regs_ever_live[i] && ! call_used_regs[i]) 369096263Sobrien n_regs += 2; 369196263Sobrien } 369296263Sobrien else 369396263Sobrien { 369496263Sobrien for (i = 0; i < 8; i += 2) 369550397Sobrien if ((regs_ever_live[i] && ! call_used_regs[i]) 369650397Sobrien || (regs_ever_live[i+1] && ! call_used_regs[i+1])) 369750397Sobrien n_regs += 2; 369850397Sobrien } 369950397Sobrien 370096263Sobrien for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2) 370196263Sobrien if ((regs_ever_live[i] && ! call_used_regs[i]) 370296263Sobrien || (regs_ever_live[i+1] && ! call_used_regs[i+1])) 370396263Sobrien n_regs += 2; 370496263Sobrien 3705169689Skan /* Set up values for use in prologue and epilogue. */ 370650397Sobrien num_gfregs = n_regs; 370750397Sobrien 3708169689Skan if (leaf_function_p 3709169689Skan && n_regs == 0 3710169689Skan && size == 0 3711169689Skan && current_function_outgoing_args_size == 0) 3712169689Skan actual_fsize = apparent_fsize = 0; 371350397Sobrien else 371450397Sobrien { 371596263Sobrien /* We subtract STARTING_FRAME_OFFSET, remember it's negative. */ 371696263Sobrien apparent_fsize = (size - STARTING_FRAME_OFFSET + 7) & -8; 371750397Sobrien apparent_fsize += n_regs * 4; 371850397Sobrien actual_fsize = apparent_fsize + ((outgoing_args_size + 7) & -8); 371950397Sobrien } 372050397Sobrien 372150397Sobrien /* Make sure nothing can clobber our register windows. 372250397Sobrien If a SAVE must be done, or there is a stack-local variable, 3723169689Skan the register window area must be allocated. */ 3724169689Skan if (! leaf_function_p || size > 0) 3725169689Skan actual_fsize += FIRST_PARM_OFFSET (current_function_decl); 372650397Sobrien 372750397Sobrien return SPARC_STACK_ALIGN (actual_fsize); 372850397Sobrien} 372950397Sobrien 3730169689Skan/* Output any necessary .register pseudo-ops. */ 373150397Sobrien 373290075Sobrienvoid 3733132718Skansparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED) 373490075Sobrien{ 373590075Sobrien#ifdef HAVE_AS_REGISTER_PSEUDO_OP 373690075Sobrien int i; 373790075Sobrien 373890075Sobrien if (TARGET_ARCH32) 373990075Sobrien return; 374090075Sobrien 374190075Sobrien /* Check if %g[2367] were used without 374290075Sobrien .register being printed for them already. */ 374390075Sobrien for (i = 2; i < 8; i++) 374490075Sobrien { 374590075Sobrien if (regs_ever_live [i] 374690075Sobrien && ! sparc_hard_reg_printed [i]) 374790075Sobrien { 374890075Sobrien sparc_hard_reg_printed [i] = 1; 3749169689Skan /* %g7 is used as TLS base register, use #ignore 3750169689Skan for it instead of #scratch. */ 3751169689Skan fprintf (file, "\t.register\t%%g%d, #%s\n", i, 3752169689Skan i == 7 ? "ignore" : "scratch"); 375390075Sobrien } 375490075Sobrien if (i == 3) i = 5; 375590075Sobrien } 375690075Sobrien#endif 375790075Sobrien} 375890075Sobrien 3759169689Skan/* Save/restore call-saved registers from LOW to HIGH at BASE+OFFSET 3760169689Skan as needed. LOW should be double-word aligned for 32-bit registers. 3761169689Skan Return the new OFFSET. */ 376290075Sobrien 3763169689Skan#define SORR_SAVE 0 3764169689Skan#define SORR_RESTORE 1 376590075Sobrien 3766169689Skanstatic int 3767169689Skansave_or_restore_regs (int low, int high, rtx base, int offset, int action) 3768169689Skan{ 3769169689Skan rtx mem, insn; 3770169689Skan int i; 377190075Sobrien 3772169689Skan if (TARGET_ARCH64 && high <= 32) 3773169689Skan { 3774169689Skan for (i = low; i < high; i++) 3775169689Skan { 3776169689Skan if (regs_ever_live[i] && ! call_used_regs[i]) 3777169689Skan { 3778169689Skan mem = gen_rtx_MEM (DImode, plus_constant (base, offset)); 3779169689Skan set_mem_alias_set (mem, sparc_sr_alias_set); 3780169689Skan if (action == SORR_SAVE) 3781169689Skan { 3782169689Skan insn = emit_move_insn (mem, gen_rtx_REG (DImode, i)); 3783169689Skan RTX_FRAME_RELATED_P (insn) = 1; 3784169689Skan } 3785169689Skan else /* action == SORR_RESTORE */ 3786169689Skan emit_move_insn (gen_rtx_REG (DImode, i), mem); 3787169689Skan offset += 8; 3788169689Skan } 3789169689Skan } 3790169689Skan } 3791169689Skan else 3792169689Skan { 3793169689Skan for (i = low; i < high; i += 2) 3794169689Skan { 3795169689Skan bool reg0 = regs_ever_live[i] && ! call_used_regs[i]; 3796169689Skan bool reg1 = regs_ever_live[i+1] && ! call_used_regs[i+1]; 3797169689Skan enum machine_mode mode; 3798169689Skan int regno; 3799169689Skan 3800169689Skan if (reg0 && reg1) 3801169689Skan { 3802169689Skan mode = i < 32 ? DImode : DFmode; 3803169689Skan regno = i; 3804169689Skan } 3805169689Skan else if (reg0) 3806169689Skan { 3807169689Skan mode = i < 32 ? SImode : SFmode; 3808169689Skan regno = i; 3809169689Skan } 3810169689Skan else if (reg1) 3811169689Skan { 3812169689Skan mode = i < 32 ? SImode : SFmode; 3813169689Skan regno = i + 1; 3814169689Skan offset += 4; 3815169689Skan } 3816169689Skan else 3817169689Skan continue; 3818169689Skan 3819169689Skan mem = gen_rtx_MEM (mode, plus_constant (base, offset)); 3820169689Skan set_mem_alias_set (mem, sparc_sr_alias_set); 3821169689Skan if (action == SORR_SAVE) 3822169689Skan { 3823169689Skan insn = emit_move_insn (mem, gen_rtx_REG (mode, regno)); 3824169689Skan RTX_FRAME_RELATED_P (insn) = 1; 3825169689Skan } 3826169689Skan else /* action == SORR_RESTORE */ 3827169689Skan emit_move_insn (gen_rtx_REG (mode, regno), mem); 3828169689Skan 3829169689Skan /* Always preserve double-word alignment. */ 3830169689Skan offset = (offset + 7) & -8; 3831169689Skan } 3832169689Skan } 3833169689Skan 3834169689Skan return offset; 3835169689Skan} 3836169689Skan 3837169689Skan/* Emit code to save call-saved registers. */ 3838169689Skan 383990075Sobrienstatic void 3840169689Skanemit_save_or_restore_regs (int action) 384190075Sobrien{ 3842169689Skan HOST_WIDE_INT offset; 3843169689Skan rtx base; 3844169689Skan 3845169689Skan offset = frame_base_offset - apparent_fsize; 3846169689Skan 3847169689Skan if (offset < -4096 || offset + num_gfregs * 4 > 4095) 3848169689Skan { 3849169689Skan /* ??? This might be optimized a little as %g1 might already have a 3850169689Skan value close enough that a single add insn will do. */ 3851169689Skan /* ??? Although, all of this is probably only a temporary fix 3852169689Skan because if %g1 can hold a function result, then 3853169689Skan sparc_expand_epilogue will lose (the result will be 3854169689Skan clobbered). */ 3855169689Skan base = gen_rtx_REG (Pmode, 1); 3856169689Skan emit_move_insn (base, GEN_INT (offset)); 3857169689Skan emit_insn (gen_rtx_SET (VOIDmode, 3858169689Skan base, 3859169689Skan gen_rtx_PLUS (Pmode, frame_base_reg, base))); 3860169689Skan offset = 0; 3861169689Skan } 386290075Sobrien else 3863169689Skan base = frame_base_reg; 3864169689Skan 3865169689Skan offset = save_or_restore_regs (0, 8, base, offset, action); 3866169689Skan save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, action); 386790075Sobrien} 386890075Sobrien 3869169689Skan/* Generate a save_register_window insn. */ 387050397Sobrien 3871169689Skanstatic rtx 3872169689Skangen_save_register_window (rtx increment) 387350397Sobrien{ 3874169689Skan if (TARGET_ARCH64) 3875169689Skan return gen_save_register_windowdi (increment); 3876169689Skan else 3877169689Skan return gen_save_register_windowsi (increment); 3878169689Skan} 387990075Sobrien 3880169689Skan/* Generate an increment for the stack pointer. */ 3881169689Skan 3882169689Skanstatic rtx 3883169689Skangen_stack_pointer_inc (rtx increment) 3884169689Skan{ 3885169689Skan return gen_rtx_SET (VOIDmode, 3886169689Skan stack_pointer_rtx, 3887169689Skan gen_rtx_PLUS (Pmode, 3888169689Skan stack_pointer_rtx, 3889169689Skan increment)); 3890169689Skan} 3891169689Skan 3892169689Skan/* Generate a decrement for the stack pointer. */ 3893169689Skan 3894169689Skanstatic rtx 3895169689Skangen_stack_pointer_dec (rtx decrement) 3896169689Skan{ 3897169689Skan return gen_rtx_SET (VOIDmode, 3898169689Skan stack_pointer_rtx, 3899169689Skan gen_rtx_MINUS (Pmode, 3900169689Skan stack_pointer_rtx, 3901169689Skan decrement)); 3902169689Skan} 3903169689Skan 3904169689Skan/* Expand the function prologue. The prologue is responsible for reserving 3905169689Skan storage for the frame, saving the call-saved registers and loading the 3906169689Skan PIC register if needed. */ 3907169689Skan 3908169689Skanvoid 3909169689Skansparc_expand_prologue (void) 3910169689Skan{ 3911169689Skan rtx insn; 3912169689Skan int i; 3913169689Skan 3914169689Skan /* Compute a snapshot of current_function_uses_only_leaf_regs. Relying 3915169689Skan on the final value of the flag means deferring the prologue/epilogue 3916169689Skan expansion until just before the second scheduling pass, which is too 3917169689Skan late to emit multiple epilogues or return insns. 3918169689Skan 3919169689Skan Of course we are making the assumption that the value of the flag 3920169689Skan will not change between now and its final value. Of the three parts 3921169689Skan of the formula, only the last one can reasonably vary. Let's take a 3922169689Skan closer look, after assuming that the first two ones are set to true 3923169689Skan (otherwise the last value is effectively silenced). 3924169689Skan 3925169689Skan If only_leaf_regs_used returns false, the global predicate will also 3926169689Skan be false so the actual frame size calculated below will be positive. 3927169689Skan As a consequence, the save_register_window insn will be emitted in 3928169689Skan the instruction stream; now this insn explicitly references %fp 3929169689Skan which is not a leaf register so only_leaf_regs_used will always 3930169689Skan return false subsequently. 3931169689Skan 3932169689Skan If only_leaf_regs_used returns true, we hope that the subsequent 3933169689Skan optimization passes won't cause non-leaf registers to pop up. For 3934169689Skan example, the regrename pass has special provisions to not rename to 3935169689Skan non-leaf registers in a leaf function. */ 3936169689Skan sparc_leaf_function_p 3937169689Skan = optimize > 0 && leaf_function_p () && only_leaf_regs_used (); 3938169689Skan 393950397Sobrien /* Need to use actual_fsize, since we are also allocating 394050397Sobrien space for our callee (and our own register save area). */ 3941169689Skan actual_fsize 3942169689Skan = sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p); 394350397Sobrien 3944169689Skan /* Advertise that the data calculated just above are now valid. */ 3945169689Skan sparc_prologue_data_valid_p = true; 3946169689Skan 3947169689Skan if (sparc_leaf_function_p) 394850397Sobrien { 3949169689Skan frame_base_reg = stack_pointer_rtx; 395050397Sobrien frame_base_offset = actual_fsize + SPARC_STACK_BIAS; 395150397Sobrien } 395250397Sobrien else 395350397Sobrien { 3954169689Skan frame_base_reg = hard_frame_pointer_rtx; 395550397Sobrien frame_base_offset = SPARC_STACK_BIAS; 395650397Sobrien } 395750397Sobrien 395850397Sobrien if (actual_fsize == 0) 395950397Sobrien /* do nothing. */ ; 3960169689Skan else if (sparc_leaf_function_p) 396150397Sobrien { 396250397Sobrien if (actual_fsize <= 4096) 3963169689Skan insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-actual_fsize))); 396450397Sobrien else if (actual_fsize <= 8192) 396550397Sobrien { 3966169689Skan insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096))); 3967169689Skan /* %sp is still the CFA register. */ 3968169689Skan RTX_FRAME_RELATED_P (insn) = 1; 3969169689Skan insn 3970169689Skan = emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize))); 397150397Sobrien } 397250397Sobrien else 397350397Sobrien { 3974169689Skan rtx reg = gen_rtx_REG (Pmode, 1); 3975169689Skan emit_move_insn (reg, GEN_INT (-actual_fsize)); 3976169689Skan insn = emit_insn (gen_stack_pointer_inc (reg)); 3977169689Skan REG_NOTES (insn) = 3978169689Skan gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, 3979169689Skan gen_stack_pointer_inc (GEN_INT (-actual_fsize)), 3980169689Skan REG_NOTES (insn)); 398150397Sobrien } 3982169689Skan 3983169689Skan RTX_FRAME_RELATED_P (insn) = 1; 398450397Sobrien } 3985169689Skan else 398650397Sobrien { 398750397Sobrien if (actual_fsize <= 4096) 3988169689Skan insn = emit_insn (gen_save_register_window (GEN_INT (-actual_fsize))); 398950397Sobrien else if (actual_fsize <= 8192) 399050397Sobrien { 3991169689Skan insn = emit_insn (gen_save_register_window (GEN_INT (-4096))); 3992169689Skan /* %sp is not the CFA register anymore. */ 3993169689Skan emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize))); 399450397Sobrien } 399550397Sobrien else 399650397Sobrien { 3997169689Skan rtx reg = gen_rtx_REG (Pmode, 1); 3998169689Skan emit_move_insn (reg, GEN_INT (-actual_fsize)); 3999169689Skan insn = emit_insn (gen_save_register_window (reg)); 400050397Sobrien } 4001169689Skan 4002169689Skan RTX_FRAME_RELATED_P (insn) = 1; 4003169689Skan for (i=0; i < XVECLEN (PATTERN (insn), 0); i++) 4004169689Skan RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1; 400550397Sobrien } 400650397Sobrien 4007169689Skan if (num_gfregs) 4008169689Skan emit_save_or_restore_regs (SORR_SAVE); 400950397Sobrien 4010169689Skan /* Load the PIC register if needed. */ 4011169689Skan if (flag_pic && current_function_uses_pic_offset_table) 4012169689Skan load_pic_register (false); 4013169689Skan} 4014169689Skan 4015169689Skan/* This function generates the assembly code for function entry, which boils 4016169689Skan down to emitting the necessary .register directives. */ 401750397Sobrien 4018169689Skanstatic void 4019169689Skansparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) 4020169689Skan{ 4021169689Skan /* Check that the assumption we made in sparc_expand_prologue is valid. */ 4022169689Skan gcc_assert (sparc_leaf_function_p == current_function_uses_only_leaf_regs); 402350397Sobrien 4024169689Skan sparc_output_scratch_registers (file); 4025169689Skan} 402650397Sobrien 4027169689Skan/* Expand the function epilogue, either normal or part of a sibcall. 4028169689Skan We emit all the instructions except the return or the call. */ 402950397Sobrien 4030169689Skanvoid 4031169689Skansparc_expand_epilogue (void) 4032169689Skan{ 403350397Sobrien if (num_gfregs) 4034169689Skan emit_save_or_restore_regs (SORR_RESTORE); 4035169689Skan 4036169689Skan if (actual_fsize == 0) 4037169689Skan /* do nothing. */ ; 4038169689Skan else if (sparc_leaf_function_p) 403950397Sobrien { 4040169689Skan if (actual_fsize <= 4096) 4041169689Skan emit_insn (gen_stack_pointer_dec (GEN_INT (- actual_fsize))); 4042169689Skan else if (actual_fsize <= 8192) 404350397Sobrien { 4044169689Skan emit_insn (gen_stack_pointer_dec (GEN_INT (-4096))); 4045169689Skan emit_insn (gen_stack_pointer_dec (GEN_INT (4096 - actual_fsize))); 404650397Sobrien } 404750397Sobrien else 404850397Sobrien { 4049169689Skan rtx reg = gen_rtx_REG (Pmode, 1); 4050169689Skan emit_move_insn (reg, GEN_INT (-actual_fsize)); 4051169689Skan emit_insn (gen_stack_pointer_dec (reg)); 405250397Sobrien } 405350397Sobrien } 405450397Sobrien} 405550397Sobrien 4056169689Skan/* Return true if it is appropriate to emit `return' instructions in the 4057169689Skan body of a function. */ 405890075Sobrien 4059169689Skanbool 4060169689Skansparc_can_use_return_insn_p (void) 4061169689Skan{ 4062169689Skan return sparc_prologue_data_valid_p 4063169689Skan && (actual_fsize == 0 || !sparc_leaf_function_p); 4064169689Skan} 4065169689Skan 4066169689Skan/* This function generates the assembly code for function exit. */ 4067169689Skan 406890075Sobrienstatic void 4069169689Skansparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) 407090075Sobrien{ 4071169689Skan /* If code does not drop into the epilogue, we have to still output 4072169689Skan a dummy nop for the sake of sane backtraces. Otherwise, if the 4073169689Skan last two instructions of a function were "call foo; dslot;" this 4074169689Skan can make the return PC of foo (i.e. address of call instruction 4075169689Skan plus 8) point to the first instruction in the next function. */ 407690075Sobrien 4077169689Skan rtx insn, last_real_insn; 407890075Sobrien 4079169689Skan insn = get_last_insn (); 408090075Sobrien 4081169689Skan last_real_insn = prev_real_insn (insn); 4082169689Skan if (last_real_insn 4083169689Skan && GET_CODE (last_real_insn) == INSN 4084169689Skan && GET_CODE (PATTERN (last_real_insn)) == SEQUENCE) 4085169689Skan last_real_insn = XVECEXP (PATTERN (last_real_insn), 0, 0); 408690075Sobrien 4087169689Skan if (last_real_insn && GET_CODE (last_real_insn) == CALL_INSN) 4088169689Skan fputs("\tnop\n", file); 408990075Sobrien 4090169689Skan sparc_output_deferred_case_vectors (); 409190075Sobrien} 4092169689Skan 4093169689Skan/* Output a 'restore' instruction. */ 4094169689Skan 409590075Sobrienstatic void 4096169689Skanoutput_restore (rtx pat) 409750397Sobrien{ 4098169689Skan rtx operands[3]; 409950397Sobrien 4100169689Skan if (! pat) 410150397Sobrien { 4102169689Skan fputs ("\t restore\n", asm_out_file); 4103169689Skan return; 4104169689Skan } 410596263Sobrien 4106169689Skan gcc_assert (GET_CODE (pat) == SET); 410796263Sobrien 4108169689Skan operands[0] = SET_DEST (pat); 4109169689Skan pat = SET_SRC (pat); 411096263Sobrien 4111169689Skan switch (GET_CODE (pat)) 4112169689Skan { 4113169689Skan case PLUS: 4114169689Skan operands[1] = XEXP (pat, 0); 4115169689Skan operands[2] = XEXP (pat, 1); 4116169689Skan output_asm_insn (" restore %r1, %2, %Y0", operands); 4117169689Skan break; 4118169689Skan case LO_SUM: 4119169689Skan operands[1] = XEXP (pat, 0); 4120169689Skan operands[2] = XEXP (pat, 1); 4121169689Skan output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands); 4122169689Skan break; 4123169689Skan case ASHIFT: 4124169689Skan operands[1] = XEXP (pat, 0); 4125169689Skan gcc_assert (XEXP (pat, 1) == const1_rtx); 4126169689Skan output_asm_insn (" restore %r1, %r1, %Y0", operands); 4127169689Skan break; 4128169689Skan default: 4129169689Skan operands[1] = pat; 4130169689Skan output_asm_insn (" restore %%g0, %1, %Y0", operands); 4131169689Skan break; 4132169689Skan } 4133169689Skan} 4134169689Skan 4135169689Skan/* Output a return. */ 4136119256Skan 4137169689Skanconst char * 4138169689Skanoutput_return (rtx insn) 4139169689Skan{ 4140169689Skan if (sparc_leaf_function_p) 4141169689Skan { 4142169689Skan /* This is a leaf function so we don't have to bother restoring the 4143169689Skan register window, which frees us from dealing with the convoluted 4144169689Skan semantics of restore/return. We simply output the jump to the 4145169689Skan return address and the insn in the delay slot (if any). */ 4146119256Skan 4147169689Skan gcc_assert (! current_function_calls_eh_return); 4148169689Skan 4149169689Skan return "jmp\t%%o7+%)%#"; 415050397Sobrien } 415150397Sobrien else 4152169689Skan { 4153169689Skan /* This is a regular function so we have to restore the register window. 4154169689Skan We may have a pending insn for the delay slot, which will be either 4155169689Skan combined with the 'restore' instruction or put in the delay slot of 4156169689Skan the 'return' instruction. */ 415750397Sobrien 415896263Sobrien if (current_function_calls_eh_return) 415996263Sobrien { 4160169689Skan /* If the function uses __builtin_eh_return, the eh_return 4161169689Skan machinery occupies the delay slot. */ 4162169689Skan gcc_assert (! final_sequence); 416350397Sobrien 4164169689Skan if (! flag_delayed_branch) 4165169689Skan fputs ("\tadd\t%fp, %g1, %fp\n", asm_out_file); 4166169689Skan 4167169689Skan if (TARGET_V9) 4168169689Skan fputs ("\treturn\t%i7+8\n", asm_out_file); 4169169689Skan else 4170169689Skan fputs ("\trestore\n\tjmp\t%o7+8\n", asm_out_file); 4171169689Skan 4172169689Skan if (flag_delayed_branch) 4173169689Skan fputs ("\t add\t%sp, %g1, %sp\n", asm_out_file); 4174169689Skan else 4175169689Skan fputs ("\t nop\n", asm_out_file); 417696263Sobrien } 4177169689Skan else if (final_sequence) 417850397Sobrien { 4179169689Skan rtx delay, pat; 418096263Sobrien 4181169689Skan delay = NEXT_INSN (insn); 4182169689Skan gcc_assert (delay); 4183169689Skan 4184169689Skan pat = PATTERN (delay); 4185169689Skan 4186169689Skan if (TARGET_V9 && ! epilogue_renumber (&pat, 1)) 418790075Sobrien { 4188169689Skan epilogue_renumber (&pat, 0); 4189169689Skan return "return\t%%i7+%)%#"; 419090075Sobrien } 419196263Sobrien else 419250397Sobrien { 4193169689Skan output_asm_insn ("jmp\t%%i7+%)", NULL); 4194169689Skan output_restore (pat); 4195169689Skan PATTERN (delay) = gen_blockage (); 4196169689Skan INSN_CODE (delay) = -1; 419750397Sobrien } 419850397Sobrien } 419996263Sobrien else 4200169689Skan { 4201169689Skan /* The delay slot is empty. */ 4202169689Skan if (TARGET_V9) 4203169689Skan return "return\t%%i7+%)\n\t nop"; 4204169689Skan else if (flag_delayed_branch) 4205169689Skan return "jmp\t%%i7+%)\n\t restore"; 4206169689Skan else 4207169689Skan return "restore\n\tjmp\t%%o7+%)\n\t nop"; 4208169689Skan } 420996263Sobrien } 421052284Sobrien 4211169689Skan return ""; 421250397Sobrien} 421390075Sobrien 421490075Sobrien/* Output a sibling call. */ 421590075Sobrien 421690075Sobrienconst char * 4217132718Skanoutput_sibcall (rtx insn, rtx call_operand) 421890075Sobrien{ 4219169689Skan rtx operands[1]; 422090075Sobrien 4221169689Skan gcc_assert (flag_delayed_branch); 4222169689Skan 4223169689Skan operands[0] = call_operand; 4224169689Skan 4225169689Skan if (sparc_leaf_function_p) 422690075Sobrien { 4227169689Skan /* This is a leaf function so we don't have to bother restoring the 4228169689Skan register window. We simply output the jump to the function and 4229169689Skan the insn in the delay slot (if any). */ 423090075Sobrien 4231169689Skan gcc_assert (!(LEAF_SIBCALL_SLOT_RESERVED_P && final_sequence)); 423290075Sobrien 4233169689Skan if (final_sequence) 4234169689Skan output_asm_insn ("sethi\t%%hi(%a0), %%g1\n\tjmp\t%%g1 + %%lo(%a0)%#", 4235169689Skan operands); 4236169689Skan else 4237169689Skan /* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize 4238169689Skan it into branch if possible. */ 4239169689Skan output_asm_insn ("or\t%%o7, %%g0, %%g1\n\tcall\t%a0, 0\n\t or\t%%g1, %%g0, %%o7", 4240169689Skan operands); 424190075Sobrien } 4242169689Skan else 4243169689Skan { 4244169689Skan /* This is a regular function so we have to restore the register window. 4245169689Skan We may have a pending insn for the delay slot, which will be combined 4246169689Skan with the 'restore' instruction. */ 424790075Sobrien 4248169689Skan output_asm_insn ("call\t%a0, 0", operands); 424990075Sobrien 4250169689Skan if (final_sequence) 425190075Sobrien { 425290075Sobrien rtx delay = NEXT_INSN (insn); 4253169689Skan gcc_assert (delay); 425490075Sobrien 4255169689Skan output_restore (PATTERN (delay)); 425690075Sobrien 425790075Sobrien PATTERN (delay) = gen_blockage (); 425890075Sobrien INSN_CODE (delay) = -1; 425990075Sobrien } 426090075Sobrien else 4261169689Skan output_restore (NULL_RTX); 426290075Sobrien } 426390075Sobrien 426490075Sobrien return ""; 426590075Sobrien} 426650397Sobrien 426750397Sobrien/* Functions for handling argument passing. 426850397Sobrien 4269169689Skan For 32-bit, the first 6 args are normally in registers and the rest are 427050397Sobrien pushed. Any arg that starts within the first 6 words is at least 427150397Sobrien partially passed in a register unless its data type forbids. 427250397Sobrien 4273169689Skan For 64-bit, the argument registers are laid out as an array of 16 elements 427450397Sobrien and arguments are added sequentially. The first 6 int args and up to the 427550397Sobrien first 16 fp args (depending on size) are passed in regs. 427650397Sobrien 427750397Sobrien Slot Stack Integral Float Float in structure Double Long Double 427850397Sobrien ---- ----- -------- ----- ------------------ ------ ----------- 427950397Sobrien 15 [SP+248] %f31 %f30,%f31 %d30 428050397Sobrien 14 [SP+240] %f29 %f28,%f29 %d28 %q28 428150397Sobrien 13 [SP+232] %f27 %f26,%f27 %d26 428250397Sobrien 12 [SP+224] %f25 %f24,%f25 %d24 %q24 428350397Sobrien 11 [SP+216] %f23 %f22,%f23 %d22 428450397Sobrien 10 [SP+208] %f21 %f20,%f21 %d20 %q20 428550397Sobrien 9 [SP+200] %f19 %f18,%f19 %d18 428650397Sobrien 8 [SP+192] %f17 %f16,%f17 %d16 %q16 428750397Sobrien 7 [SP+184] %f15 %f14,%f15 %d14 428850397Sobrien 6 [SP+176] %f13 %f12,%f13 %d12 %q12 428950397Sobrien 5 [SP+168] %o5 %f11 %f10,%f11 %d10 429050397Sobrien 4 [SP+160] %o4 %f9 %f8,%f9 %d8 %q8 429150397Sobrien 3 [SP+152] %o3 %f7 %f6,%f7 %d6 429250397Sobrien 2 [SP+144] %o2 %f5 %f4,%f5 %d4 %q4 429350397Sobrien 1 [SP+136] %o1 %f3 %f2,%f3 %d2 429450397Sobrien 0 [SP+128] %o0 %f1 %f0,%f1 %d0 %q0 429550397Sobrien 429650397Sobrien Here SP = %sp if -mno-stack-bias or %sp+stack_bias otherwise. 429750397Sobrien 4298169689Skan Integral arguments are always passed as 64-bit quantities appropriately 429950397Sobrien extended. 430050397Sobrien 430150397Sobrien Passing of floating point values is handled as follows. 430250397Sobrien If a prototype is in scope: 430350397Sobrien If the value is in a named argument (i.e. not a stdarg function or a 430450397Sobrien value not part of the `...') then the value is passed in the appropriate 430550397Sobrien fp reg. 430650397Sobrien If the value is part of the `...' and is passed in one of the first 6 430750397Sobrien slots then the value is passed in the appropriate int reg. 430850397Sobrien If the value is part of the `...' and is not passed in one of the first 6 430950397Sobrien slots then the value is passed in memory. 431050397Sobrien If a prototype is not in scope: 431150397Sobrien If the value is one of the first 6 arguments the value is passed in the 431250397Sobrien appropriate integer reg and the appropriate fp reg. 431350397Sobrien If the value is not one of the first 6 arguments the value is passed in 431450397Sobrien the appropriate fp reg and in memory. 431550397Sobrien 4316169689Skan 4317169689Skan Summary of the calling conventions implemented by GCC on SPARC: 4318169689Skan 4319169689Skan 32-bit ABI: 4320169689Skan size argument return value 4321169689Skan 4322169689Skan small integer <4 int. reg. int. reg. 4323169689Skan word 4 int. reg. int. reg. 4324169689Skan double word 8 int. reg. int. reg. 4325169689Skan 4326169689Skan _Complex small integer <8 int. reg. int. reg. 4327169689Skan _Complex word 8 int. reg. int. reg. 4328169689Skan _Complex double word 16 memory int. reg. 4329169689Skan 4330169689Skan vector integer <=8 int. reg. FP reg. 4331169689Skan vector integer >8 memory memory 4332169689Skan 4333169689Skan float 4 int. reg. FP reg. 4334169689Skan double 8 int. reg. FP reg. 4335169689Skan long double 16 memory memory 4336169689Skan 4337169689Skan _Complex float 8 memory FP reg. 4338169689Skan _Complex double 16 memory FP reg. 4339169689Skan _Complex long double 32 memory FP reg. 4340169689Skan 4341169689Skan vector float any memory memory 4342169689Skan 4343169689Skan aggregate any memory memory 4344169689Skan 4345169689Skan 4346169689Skan 4347169689Skan 64-bit ABI: 4348169689Skan size argument return value 4349169689Skan 4350169689Skan small integer <8 int. reg. int. reg. 4351169689Skan word 8 int. reg. int. reg. 4352169689Skan double word 16 int. reg. int. reg. 4353169689Skan 4354169689Skan _Complex small integer <16 int. reg. int. reg. 4355169689Skan _Complex word 16 int. reg. int. reg. 4356169689Skan _Complex double word 32 memory int. reg. 4357169689Skan 4358169689Skan vector integer <=16 FP reg. FP reg. 4359169689Skan vector integer 16<s<=32 memory FP reg. 4360169689Skan vector integer >32 memory memory 4361169689Skan 4362169689Skan float 4 FP reg. FP reg. 4363169689Skan double 8 FP reg. FP reg. 4364169689Skan long double 16 FP reg. FP reg. 4365169689Skan 4366169689Skan _Complex float 8 FP reg. FP reg. 4367169689Skan _Complex double 16 FP reg. FP reg. 4368169689Skan _Complex long double 32 memory FP reg. 4369169689Skan 4370169689Skan vector float <=16 FP reg. FP reg. 4371169689Skan vector float 16<s<=32 memory FP reg. 4372169689Skan vector float >32 memory memory 4373169689Skan 4374169689Skan aggregate <=16 reg. reg. 4375169689Skan aggregate 16<s<=32 memory reg. 4376169689Skan aggregate >32 memory memory 4377169689Skan 4378169689Skan 4379169689Skan 4380169689SkanNote #1: complex floating-point types follow the extended SPARC ABIs as 4381169689Skanimplemented by the Sun compiler. 4382169689Skan 4383169689SkanNote #2: integral vector types follow the scalar floating-point types 4384169689Skanconventions to match what is implemented by the Sun VIS SDK. 4385169689Skan 4386169689SkanNote #3: floating-point vector types follow the aggregate types 4387169689Skanconventions. */ 4388169689Skan 4389169689Skan 439050397Sobrien/* Maximum number of int regs for args. */ 439150397Sobrien#define SPARC_INT_ARG_MAX 6 439250397Sobrien/* Maximum number of fp regs for args. */ 439350397Sobrien#define SPARC_FP_ARG_MAX 16 439450397Sobrien 439550397Sobrien#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) 439650397Sobrien 439750397Sobrien/* Handle the INIT_CUMULATIVE_ARGS macro. 439850397Sobrien Initialize a variable CUM of type CUMULATIVE_ARGS 439950397Sobrien for a call to a function whose data type is FNTYPE. 440050397Sobrien For a library call, FNTYPE is 0. */ 440150397Sobrien 440250397Sobrienvoid 4403132718Skaninit_cumulative_args (struct sparc_args *cum, tree fntype, 4404132718Skan rtx libname ATTRIBUTE_UNUSED, 4405132718Skan tree fndecl ATTRIBUTE_UNUSED) 440650397Sobrien{ 440750397Sobrien cum->words = 0; 440850397Sobrien cum->prototype_p = fntype && TYPE_ARG_TYPES (fntype); 440950397Sobrien cum->libcall_p = fntype == 0; 441050397Sobrien} 441150397Sobrien 4412169689Skan/* Handle the TARGET_PROMOTE_PROTOTYPES target hook. 4413169689Skan When a prototype says `char' or `short', really pass an `int'. */ 4414169689Skan 4415169689Skanstatic bool 4416169689Skansparc_promote_prototypes (tree fntype ATTRIBUTE_UNUSED) 4417169689Skan{ 4418169689Skan return TARGET_ARCH32 ? true : false; 4419169689Skan} 4420169689Skan 4421169689Skan/* Handle the TARGET_STRICT_ARGUMENT_NAMING target hook. */ 4422169689Skan 4423169689Skanstatic bool 4424169689Skansparc_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED) 4425169689Skan{ 4426169689Skan return TARGET_ARCH64 ? true : false; 4427169689Skan} 4428169689Skan 4429132718Skan/* Scan the record type TYPE and return the following predicates: 4430132718Skan - INTREGS_P: the record contains at least one field or sub-field 4431132718Skan that is eligible for promotion in integer registers. 4432132718Skan - FP_REGS_P: the record contains at least one field or sub-field 4433132718Skan that is eligible for promotion in floating-point registers. 4434132718Skan - PACKED_P: the record contains at least one field that is packed. 4435132718Skan 4436132718Skan Sub-fields are not taken into account for the PACKED_P predicate. */ 4437132718Skan 4438132718Skanstatic void 4439132718Skanscan_record_type (tree type, int *intregs_p, int *fpregs_p, int *packed_p) 4440132718Skan{ 4441132718Skan tree field; 4442132718Skan 4443132718Skan for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 4444132718Skan { 4445132718Skan if (TREE_CODE (field) == FIELD_DECL) 4446132718Skan { 4447132718Skan if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) 4448132718Skan scan_record_type (TREE_TYPE (field), intregs_p, fpregs_p, 0); 4449169689Skan else if ((FLOAT_TYPE_P (TREE_TYPE (field)) 4450169689Skan || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE) 4451169689Skan && TARGET_FPU) 4452132718Skan *fpregs_p = 1; 4453132718Skan else 4454132718Skan *intregs_p = 1; 4455132718Skan 4456132718Skan if (packed_p && DECL_PACKED (field)) 4457132718Skan *packed_p = 1; 4458132718Skan } 4459132718Skan } 4460132718Skan} 4461132718Skan 446250397Sobrien/* Compute the slot number to pass an argument in. 4463132718Skan Return the slot number or -1 if passing on the stack. 446450397Sobrien 446550397Sobrien CUM is a variable of type CUMULATIVE_ARGS which gives info about 446650397Sobrien the preceding args and about the function being called. 446750397Sobrien MODE is the argument's machine mode. 446850397Sobrien TYPE is the data type of the argument (as a tree). 446950397Sobrien This is null for libcalls where that information may 447050397Sobrien not be available. 447150397Sobrien NAMED is nonzero if this argument is a named parameter 447250397Sobrien (otherwise it is an extra parameter matching an ellipsis). 447350397Sobrien INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG. 447450397Sobrien *PREGNO records the register number to use if scalar type. 447550397Sobrien *PPADDING records the amount of padding needed in words. */ 447650397Sobrien 447750397Sobrienstatic int 4478132718Skanfunction_arg_slotno (const struct sparc_args *cum, enum machine_mode mode, 4479132718Skan tree type, int named, int incoming_p, 4480132718Skan int *pregno, int *ppadding) 448150397Sobrien{ 448250397Sobrien int regbase = (incoming_p 448350397Sobrien ? SPARC_INCOMING_INT_ARG_FIRST 448450397Sobrien : SPARC_OUTGOING_INT_ARG_FIRST); 448550397Sobrien int slotno = cum->words; 4486169689Skan enum mode_class mclass; 448750397Sobrien int regno; 448850397Sobrien 448950397Sobrien *ppadding = 0; 449050397Sobrien 4491169689Skan if (type && TREE_ADDRESSABLE (type)) 449250397Sobrien return -1; 4493169689Skan 449450397Sobrien if (TARGET_ARCH32 4495169689Skan && mode == BLKmode 4496169689Skan && type 449750397Sobrien && TYPE_ALIGN (type) % PARM_BOUNDARY != 0) 449850397Sobrien return -1; 449950397Sobrien 4500169689Skan /* For SPARC64, objects requiring 16-byte alignment get it. */ 4501169689Skan if (TARGET_ARCH64 4502169689Skan && (type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode)) >= 128 4503169689Skan && (slotno & 1) != 0) 4504169689Skan slotno++, *ppadding = 1; 4505169689Skan 4506169689Skan mclass = GET_MODE_CLASS (mode); 4507169689Skan if (type && TREE_CODE (type) == VECTOR_TYPE) 450850397Sobrien { 4509169689Skan /* Vector types deserve special treatment because they are 4510169689Skan polymorphic wrt their mode, depending upon whether VIS 4511169689Skan instructions are enabled. */ 4512169689Skan if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE) 4513169689Skan { 4514169689Skan /* The SPARC port defines no floating-point vector modes. */ 4515169689Skan gcc_assert (mode == BLKmode); 4516169689Skan } 4517169689Skan else 4518169689Skan { 4519169689Skan /* Integral vector types should either have a vector 4520169689Skan mode or an integral mode, because we are guaranteed 4521169689Skan by pass_by_reference that their size is not greater 4522169689Skan than 16 bytes and TImode is 16-byte wide. */ 4523169689Skan gcc_assert (mode != BLKmode); 452450397Sobrien 4525169689Skan /* Vector integers are handled like floats according to 4526169689Skan the Sun VIS SDK. */ 4527169689Skan mclass = MODE_FLOAT; 4528169689Skan } 4529169689Skan } 4530169689Skan 4531169689Skan switch (mclass) 4532169689Skan { 4533169689Skan case MODE_FLOAT: 4534169689Skan case MODE_COMPLEX_FLOAT: 4535169689Skan if (TARGET_ARCH64 && TARGET_FPU && named) 4536169689Skan { 4537169689Skan if (slotno >= SPARC_FP_ARG_MAX) 4538169689Skan return -1; 4539169689Skan regno = SPARC_FP_ARG_FIRST + slotno * 2; 4540169689Skan /* Arguments filling only one single FP register are 4541169689Skan right-justified in the outer double FP register. */ 4542169689Skan if (GET_MODE_SIZE (mode) <= 4) 4543169689Skan regno++; 4544169689Skan break; 4545169689Skan } 4546132718Skan /* fallthrough */ 4547132718Skan 4548169689Skan case MODE_INT: 4549169689Skan case MODE_COMPLEX_INT: 455050397Sobrien if (slotno >= SPARC_INT_ARG_MAX) 455150397Sobrien return -1; 455250397Sobrien regno = regbase + slotno; 455350397Sobrien break; 455450397Sobrien 4555169689Skan case MODE_RANDOM: 4556169689Skan if (mode == VOIDmode) 4557169689Skan /* MODE is VOIDmode when generating the actual call. */ 4558169689Skan return -1; 4559132718Skan 4560169689Skan gcc_assert (mode == BLKmode); 456150397Sobrien 456250397Sobrien if (TARGET_ARCH32 4563169689Skan || !type 4564169689Skan || (TREE_CODE (type) != VECTOR_TYPE 4565169689Skan && TREE_CODE (type) != RECORD_TYPE)) 456650397Sobrien { 456750397Sobrien if (slotno >= SPARC_INT_ARG_MAX) 456850397Sobrien return -1; 456950397Sobrien regno = regbase + slotno; 457050397Sobrien } 4571169689Skan else /* TARGET_ARCH64 && type */ 457250397Sobrien { 4573132718Skan int intregs_p = 0, fpregs_p = 0, packed_p = 0; 457450397Sobrien 4575132718Skan /* First see what kinds of registers we would need. */ 4576169689Skan if (TREE_CODE (type) == VECTOR_TYPE) 4577169689Skan fpregs_p = 1; 4578169689Skan else 4579169689Skan scan_record_type (type, &intregs_p, &fpregs_p, &packed_p); 4580132718Skan 4581132718Skan /* The ABI obviously doesn't specify how packed structures 4582132718Skan are passed. These are defined to be passed in int regs 4583132718Skan if possible, otherwise memory. */ 458450397Sobrien if (packed_p || !named) 458550397Sobrien fpregs_p = 0, intregs_p = 1; 458650397Sobrien 458750397Sobrien /* If all arg slots are filled, then must pass on stack. */ 458850397Sobrien if (fpregs_p && slotno >= SPARC_FP_ARG_MAX) 458950397Sobrien return -1; 4590169689Skan 459150397Sobrien /* If there are only int args and all int arg slots are filled, 459250397Sobrien then must pass on stack. */ 459350397Sobrien if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX) 459450397Sobrien return -1; 4595169689Skan 459650397Sobrien /* Note that even if all int arg slots are filled, fp members may 459750397Sobrien still be passed in regs if such regs are available. 459850397Sobrien *PREGNO isn't set because there may be more than one, it's up 459950397Sobrien to the caller to compute them. */ 460050397Sobrien return slotno; 460150397Sobrien } 460250397Sobrien break; 460350397Sobrien 460450397Sobrien default : 4605169689Skan gcc_unreachable (); 460650397Sobrien } 460750397Sobrien 460850397Sobrien *pregno = regno; 460950397Sobrien return slotno; 461050397Sobrien} 461150397Sobrien 461250397Sobrien/* Handle recursive register counting for structure field layout. */ 461350397Sobrien 461450397Sobrienstruct function_arg_record_value_parms 461550397Sobrien{ 4616117395Skan rtx ret; /* return expression being built. */ 4617117395Skan int slotno; /* slot number of the argument. */ 4618117395Skan int named; /* whether the argument is named. */ 4619117395Skan int regbase; /* regno of the base register. */ 4620117395Skan int stack; /* 1 if part of the argument is on the stack. */ 4621132718Skan int intoffset; /* offset of the first pending integer field. */ 4622117395Skan unsigned int nregs; /* number of words passed in registers. */ 462350397Sobrien}; 462450397Sobrien 462552284Sobrienstatic void function_arg_record_value_3 4626132718Skan (HOST_WIDE_INT, struct function_arg_record_value_parms *); 462752284Sobrienstatic void function_arg_record_value_2 4628132718Skan (tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool); 462990075Sobrienstatic void function_arg_record_value_1 4630132718Skan (tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool); 4631132718Skanstatic rtx function_arg_record_value (tree, enum machine_mode, int, int, int); 4632146895Skanstatic rtx function_arg_union_value (int, enum machine_mode, int, int); 463352284Sobrien 463490075Sobrien/* A subroutine of function_arg_record_value. Traverse the structure 4635132718Skan recursively and determine how many registers will be required. */ 463690075Sobrien 463750397Sobrienstatic void 4638132718Skanfunction_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos, 4639132718Skan struct function_arg_record_value_parms *parms, 4640132718Skan bool packed_p) 464150397Sobrien{ 464250397Sobrien tree field; 464350397Sobrien 464450397Sobrien /* We need to compute how many registers are needed so we can 464550397Sobrien allocate the PARALLEL but before we can do that we need to know 4646132718Skan whether there are any packed fields. The ABI obviously doesn't 4647132718Skan specify how structures are passed in this case, so they are 4648132718Skan defined to be passed in int regs if possible, otherwise memory, 4649132718Skan regardless of whether there are fp values present. */ 465050397Sobrien 4651132718Skan if (! packed_p) 4652132718Skan for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 4653132718Skan { 4654132718Skan if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field)) 4655132718Skan { 4656132718Skan packed_p = true; 4657132718Skan break; 4658132718Skan } 4659132718Skan } 4660132718Skan 466150397Sobrien /* Compute how many registers we need. */ 466250397Sobrien for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 466350397Sobrien { 466450397Sobrien if (TREE_CODE (field) == FIELD_DECL) 466550397Sobrien { 466690075Sobrien HOST_WIDE_INT bitpos = startbitpos; 466790075Sobrien 4668169689Skan if (DECL_SIZE (field) != 0) 4669169689Skan { 4670169689Skan if (integer_zerop (DECL_SIZE (field))) 4671169689Skan continue; 467290075Sobrien 4673169689Skan if (host_integerp (bit_position (field), 1)) 4674169689Skan bitpos += int_bit_position (field); 4675169689Skan } 4676169689Skan 467750397Sobrien /* ??? FIXME: else assume zero offset. */ 467850397Sobrien 467950397Sobrien if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) 4680132718Skan function_arg_record_value_1 (TREE_TYPE (field), 4681132718Skan bitpos, 4682132718Skan parms, 4683132718Skan packed_p); 4684169689Skan else if ((FLOAT_TYPE_P (TREE_TYPE (field)) 4685169689Skan || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE) 4686132718Skan && TARGET_FPU 4687132718Skan && parms->named 4688132718Skan && ! packed_p) 468950397Sobrien { 469050397Sobrien if (parms->intoffset != -1) 469150397Sobrien { 4692132718Skan unsigned int startbit, endbit; 469350397Sobrien int intslots, this_slotno; 469450397Sobrien 4695132718Skan startbit = parms->intoffset & -BITS_PER_WORD; 4696132718Skan endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD; 4697132718Skan 4698132718Skan intslots = (endbit - startbit) / BITS_PER_WORD; 469950397Sobrien this_slotno = parms->slotno + parms->intoffset 470050397Sobrien / BITS_PER_WORD; 470150397Sobrien 4702117395Skan if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno) 4703117395Skan { 4704117395Skan intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno); 4705117395Skan /* We need to pass this field on the stack. */ 4706117395Skan parms->stack = 1; 4707117395Skan } 4708117395Skan 470950397Sobrien parms->nregs += intslots; 471050397Sobrien parms->intoffset = -1; 471150397Sobrien } 471250397Sobrien 471350397Sobrien /* There's no need to check this_slotno < SPARC_FP_ARG MAX. 471450397Sobrien If it wasn't true we wouldn't be here. */ 4715169689Skan if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE 4716169689Skan && DECL_MODE (field) == BLKmode) 4717169689Skan parms->nregs += TYPE_VECTOR_SUBPARTS (TREE_TYPE (field)); 4718169689Skan else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE) 4719169689Skan parms->nregs += 2; 4720169689Skan else 472196263Sobrien parms->nregs += 1; 472250397Sobrien } 472350397Sobrien else 472450397Sobrien { 472550397Sobrien if (parms->intoffset == -1) 472650397Sobrien parms->intoffset = bitpos; 472750397Sobrien } 472850397Sobrien } 472950397Sobrien } 473050397Sobrien} 473150397Sobrien 473290075Sobrien/* A subroutine of function_arg_record_value. Assign the bits of the 473390075Sobrien structure between parms->intoffset and bitpos to integer registers. */ 473450397Sobrien 473550397Sobrienstatic void 4736132718Skanfunction_arg_record_value_3 (HOST_WIDE_INT bitpos, 4737132718Skan struct function_arg_record_value_parms *parms) 473850397Sobrien{ 473950397Sobrien enum machine_mode mode; 474090075Sobrien unsigned int regno; 474190075Sobrien unsigned int startbit, endbit; 474290075Sobrien int this_slotno, intslots, intoffset; 474350397Sobrien rtx reg; 474450397Sobrien 474550397Sobrien if (parms->intoffset == -1) 474650397Sobrien return; 474790075Sobrien 474850397Sobrien intoffset = parms->intoffset; 474950397Sobrien parms->intoffset = -1; 475050397Sobrien 475190075Sobrien startbit = intoffset & -BITS_PER_WORD; 475290075Sobrien endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD; 475390075Sobrien intslots = (endbit - startbit) / BITS_PER_WORD; 475450397Sobrien this_slotno = parms->slotno + intoffset / BITS_PER_WORD; 475550397Sobrien 475650397Sobrien intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno); 475750397Sobrien if (intslots <= 0) 475850397Sobrien return; 475950397Sobrien 476050397Sobrien /* If this is the trailing part of a word, only load that much into 476150397Sobrien the register. Otherwise load the whole register. Note that in 476250397Sobrien the latter case we may pick up unwanted bits. It's not a problem 476350397Sobrien at the moment but may wish to revisit. */ 476450397Sobrien 476550397Sobrien if (intoffset % BITS_PER_WORD != 0) 4766169689Skan mode = smallest_mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD, 4767169689Skan MODE_INT); 476850397Sobrien else 476950397Sobrien mode = word_mode; 477050397Sobrien 477150397Sobrien intoffset /= BITS_PER_UNIT; 477250397Sobrien do 477350397Sobrien { 477450397Sobrien regno = parms->regbase + this_slotno; 477550397Sobrien reg = gen_rtx_REG (mode, regno); 4776117395Skan XVECEXP (parms->ret, 0, parms->stack + parms->nregs) 477750397Sobrien = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset)); 477850397Sobrien 477950397Sobrien this_slotno += 1; 478050397Sobrien intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1; 4781132718Skan mode = word_mode; 478250397Sobrien parms->nregs += 1; 478350397Sobrien intslots -= 1; 478450397Sobrien } 478550397Sobrien while (intslots > 0); 478650397Sobrien} 478750397Sobrien 478890075Sobrien/* A subroutine of function_arg_record_value. Traverse the structure 478990075Sobrien recursively and assign bits to floating point registers. Track which 479090075Sobrien bits in between need integer registers; invoke function_arg_record_value_3 479190075Sobrien to make that happen. */ 479290075Sobrien 479350397Sobrienstatic void 4794132718Skanfunction_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos, 4795132718Skan struct function_arg_record_value_parms *parms, 4796132718Skan bool packed_p) 479750397Sobrien{ 479850397Sobrien tree field; 479950397Sobrien 4800132718Skan if (! packed_p) 4801132718Skan for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 4802132718Skan { 4803132718Skan if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field)) 4804132718Skan { 4805132718Skan packed_p = true; 4806132718Skan break; 4807132718Skan } 4808132718Skan } 480950397Sobrien 481050397Sobrien for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 481150397Sobrien { 481250397Sobrien if (TREE_CODE (field) == FIELD_DECL) 481350397Sobrien { 481490075Sobrien HOST_WIDE_INT bitpos = startbitpos; 481590075Sobrien 4816169689Skan if (DECL_SIZE (field) != 0) 4817169689Skan { 4818169689Skan if (integer_zerop (DECL_SIZE (field))) 4819169689Skan continue; 482090075Sobrien 4821169689Skan if (host_integerp (bit_position (field), 1)) 4822169689Skan bitpos += int_bit_position (field); 4823169689Skan } 4824169689Skan 482550397Sobrien /* ??? FIXME: else assume zero offset. */ 482650397Sobrien 482750397Sobrien if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) 4828132718Skan function_arg_record_value_2 (TREE_TYPE (field), 4829132718Skan bitpos, 4830132718Skan parms, 4831132718Skan packed_p); 4832169689Skan else if ((FLOAT_TYPE_P (TREE_TYPE (field)) 4833169689Skan || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE) 4834132718Skan && TARGET_FPU 4835132718Skan && parms->named 4836132718Skan && ! packed_p) 483750397Sobrien { 483850397Sobrien int this_slotno = parms->slotno + bitpos / BITS_PER_WORD; 4839169689Skan int regno, nregs, pos; 484096263Sobrien enum machine_mode mode = DECL_MODE (field); 484150397Sobrien rtx reg; 484250397Sobrien 484350397Sobrien function_arg_record_value_3 (bitpos, parms); 4844169689Skan 4845169689Skan if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE 4846169689Skan && mode == BLKmode) 4847169689Skan { 4848169689Skan mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field))); 4849169689Skan nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field)); 485096263Sobrien } 4851169689Skan else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE) 4852169689Skan { 4853169689Skan mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field))); 4854169689Skan nregs = 2; 4855169689Skan } 4856169689Skan else 4857169689Skan nregs = 1; 4858169689Skan 4859169689Skan regno = SPARC_FP_ARG_FIRST + this_slotno * 2; 4860169689Skan if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0) 4861169689Skan regno++; 486296263Sobrien reg = gen_rtx_REG (mode, regno); 4863169689Skan pos = bitpos / BITS_PER_UNIT; 4864117395Skan XVECEXP (parms->ret, 0, parms->stack + parms->nregs) 4865169689Skan = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos)); 486650397Sobrien parms->nregs += 1; 4867169689Skan while (--nregs > 0) 486896263Sobrien { 486996263Sobrien regno += GET_MODE_SIZE (mode) / 4; 487096263Sobrien reg = gen_rtx_REG (mode, regno); 4871169689Skan pos += GET_MODE_SIZE (mode); 4872117395Skan XVECEXP (parms->ret, 0, parms->stack + parms->nregs) 4873169689Skan = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos)); 487496263Sobrien parms->nregs += 1; 487596263Sobrien } 487650397Sobrien } 487750397Sobrien else 487850397Sobrien { 487950397Sobrien if (parms->intoffset == -1) 488050397Sobrien parms->intoffset = bitpos; 488150397Sobrien } 488250397Sobrien } 488350397Sobrien } 488450397Sobrien} 488550397Sobrien 488690075Sobrien/* Used by function_arg and function_value to implement the complex 4887117395Skan conventions of the 64-bit ABI for passing and returning structures. 4888117395Skan Return an expression valid as a return value for the two macros 4889117395Skan FUNCTION_ARG and FUNCTION_VALUE. 489090075Sobrien 4891117395Skan TYPE is the data type of the argument (as a tree). 4892117395Skan This is null for libcalls where that information may 4893117395Skan not be available. 4894117395Skan MODE is the argument's machine mode. 4895117395Skan SLOTNO is the index number of the argument's slot in the parameter array. 4896117395Skan NAMED is nonzero if this argument is a named parameter 4897117395Skan (otherwise it is an extra parameter matching an ellipsis). 4898117395Skan REGBASE is the regno of the base register for the parameter array. */ 4899117395Skan 490050397Sobrienstatic rtx 4901132718Skanfunction_arg_record_value (tree type, enum machine_mode mode, 4902132718Skan int slotno, int named, int regbase) 490350397Sobrien{ 490450397Sobrien HOST_WIDE_INT typesize = int_size_in_bytes (type); 490550397Sobrien struct function_arg_record_value_parms parms; 490690075Sobrien unsigned int nregs; 490750397Sobrien 490850397Sobrien parms.ret = NULL_RTX; 490950397Sobrien parms.slotno = slotno; 491050397Sobrien parms.named = named; 491150397Sobrien parms.regbase = regbase; 4912117395Skan parms.stack = 0; 491350397Sobrien 491450397Sobrien /* Compute how many registers we need. */ 491550397Sobrien parms.nregs = 0; 491650397Sobrien parms.intoffset = 0; 4917132718Skan function_arg_record_value_1 (type, 0, &parms, false); 491850397Sobrien 4919132718Skan /* Take into account pending integer fields. */ 492050397Sobrien if (parms.intoffset != -1) 492150397Sobrien { 492290075Sobrien unsigned int startbit, endbit; 492350397Sobrien int intslots, this_slotno; 492450397Sobrien 492590075Sobrien startbit = parms.intoffset & -BITS_PER_WORD; 492690075Sobrien endbit = (typesize*BITS_PER_UNIT + BITS_PER_WORD - 1) & -BITS_PER_WORD; 492790075Sobrien intslots = (endbit - startbit) / BITS_PER_WORD; 492850397Sobrien this_slotno = slotno + parms.intoffset / BITS_PER_WORD; 492950397Sobrien 4930117395Skan if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno) 4931117395Skan { 4932117395Skan intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno); 4933117395Skan /* We need to pass this field on the stack. */ 4934117395Skan parms.stack = 1; 4935117395Skan } 493650397Sobrien 493750397Sobrien parms.nregs += intslots; 493850397Sobrien } 493950397Sobrien nregs = parms.nregs; 494050397Sobrien 494150397Sobrien /* Allocate the vector and handle some annoying special cases. */ 494250397Sobrien if (nregs == 0) 494350397Sobrien { 494450397Sobrien /* ??? Empty structure has no value? Duh? */ 494550397Sobrien if (typesize <= 0) 494650397Sobrien { 494750397Sobrien /* Though there's nothing really to store, return a word register 494850397Sobrien anyway so the rest of gcc doesn't go nuts. Returning a PARALLEL 494950397Sobrien leads to breakage due to the fact that there are zero bytes to 495050397Sobrien load. */ 495150397Sobrien return gen_rtx_REG (mode, regbase); 495250397Sobrien } 495350397Sobrien else 495450397Sobrien { 495550397Sobrien /* ??? C++ has structures with no fields, and yet a size. Give up 495650397Sobrien for now and pass everything back in integer registers. */ 495750397Sobrien nregs = (typesize + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 495850397Sobrien } 495950397Sobrien if (nregs + slotno > SPARC_INT_ARG_MAX) 496050397Sobrien nregs = SPARC_INT_ARG_MAX - slotno; 496150397Sobrien } 4962169689Skan gcc_assert (nregs != 0); 496350397Sobrien 4964117395Skan parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (parms.stack + nregs)); 496550397Sobrien 4966117395Skan /* If at least one field must be passed on the stack, generate 4967117395Skan (parallel [(expr_list (nil) ...) ...]) so that all fields will 4968117395Skan also be passed on the stack. We can't do much better because the 4969169689Skan semantics of TARGET_ARG_PARTIAL_BYTES doesn't handle the case 4970117395Skan of structures for which the fields passed exclusively in registers 4971117395Skan are not at the beginning of the structure. */ 4972117395Skan if (parms.stack) 4973117395Skan XVECEXP (parms.ret, 0, 0) 4974117395Skan = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx); 4975117395Skan 497650397Sobrien /* Fill in the entries. */ 497750397Sobrien parms.nregs = 0; 497850397Sobrien parms.intoffset = 0; 4979132718Skan function_arg_record_value_2 (type, 0, &parms, false); 498050397Sobrien function_arg_record_value_3 (typesize * BITS_PER_UNIT, &parms); 498150397Sobrien 4982169689Skan gcc_assert (parms.nregs == nregs); 498350397Sobrien 498450397Sobrien return parms.ret; 498550397Sobrien} 498650397Sobrien 4987132718Skan/* Used by function_arg and function_value to implement the conventions 4988132718Skan of the 64-bit ABI for passing and returning unions. 4989132718Skan Return an expression valid as a return value for the two macros 4990132718Skan FUNCTION_ARG and FUNCTION_VALUE. 4991132718Skan 4992132718Skan SIZE is the size in bytes of the union. 4993132718Skan MODE is the argument's machine mode. 4994132718Skan REGNO is the hard register the union will be passed in. */ 4995132718Skan 4996132718Skanstatic rtx 4997146895Skanfunction_arg_union_value (int size, enum machine_mode mode, int slotno, 4998146895Skan int regno) 4999132718Skan{ 5000132718Skan int nwords = ROUND_ADVANCE (size), i; 5001132718Skan rtx regs; 5002132718Skan 5003146895Skan /* See comment in previous function for empty structures. */ 5004146895Skan if (nwords == 0) 5005146895Skan return gen_rtx_REG (mode, regno); 5006146895Skan 5007146895Skan if (slotno == SPARC_INT_ARG_MAX - 1) 5008146895Skan nwords = 1; 5009146895Skan 5010132718Skan regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords)); 5011132718Skan 5012132718Skan for (i = 0; i < nwords; i++) 5013169689Skan { 5014169689Skan /* Unions are passed left-justified. */ 5015169689Skan XVECEXP (regs, 0, i) 5016169689Skan = gen_rtx_EXPR_LIST (VOIDmode, 5017169689Skan gen_rtx_REG (word_mode, regno), 5018169689Skan GEN_INT (UNITS_PER_WORD * i)); 5019169689Skan regno++; 5020169689Skan } 5021132718Skan 5022132718Skan return regs; 5023132718Skan} 5024132718Skan 5025169689Skan/* Used by function_arg and function_value to implement the conventions 5026169689Skan for passing and returning large (BLKmode) vectors. 5027169689Skan Return an expression valid as a return value for the two macros 5028169689Skan FUNCTION_ARG and FUNCTION_VALUE. 5029169689Skan 5030169689Skan SIZE is the size in bytes of the vector. 5031169689Skan BASE_MODE is the argument's base machine mode. 5032169689Skan REGNO is the FP hard register the vector will be passed in. */ 5033169689Skan 5034169689Skanstatic rtx 5035169689Skanfunction_arg_vector_value (int size, enum machine_mode base_mode, int regno) 5036169689Skan{ 5037169689Skan unsigned short base_mode_size = GET_MODE_SIZE (base_mode); 5038169689Skan int nregs = size / base_mode_size, i; 5039169689Skan rtx regs; 5040169689Skan 5041169689Skan regs = gen_rtx_PARALLEL (BLKmode, rtvec_alloc (nregs)); 5042169689Skan 5043169689Skan for (i = 0; i < nregs; i++) 5044169689Skan { 5045169689Skan XVECEXP (regs, 0, i) 5046169689Skan = gen_rtx_EXPR_LIST (VOIDmode, 5047169689Skan gen_rtx_REG (base_mode, regno), 5048169689Skan GEN_INT (base_mode_size * i)); 5049169689Skan regno += base_mode_size / 4; 5050169689Skan } 5051169689Skan 5052169689Skan return regs; 5053169689Skan} 5054169689Skan 505550397Sobrien/* Handle the FUNCTION_ARG macro. 505650397Sobrien Determine where to put an argument to a function. 505750397Sobrien Value is zero to push the argument on the stack, 505850397Sobrien or a hard register in which to store the argument. 505950397Sobrien 506050397Sobrien CUM is a variable of type CUMULATIVE_ARGS which gives info about 506150397Sobrien the preceding args and about the function being called. 506250397Sobrien MODE is the argument's machine mode. 506350397Sobrien TYPE is the data type of the argument (as a tree). 506450397Sobrien This is null for libcalls where that information may 506550397Sobrien not be available. 506650397Sobrien NAMED is nonzero if this argument is a named parameter 506750397Sobrien (otherwise it is an extra parameter matching an ellipsis). 506850397Sobrien INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG. */ 506950397Sobrien 507050397Sobrienrtx 5071132718Skanfunction_arg (const struct sparc_args *cum, enum machine_mode mode, 5072132718Skan tree type, int named, int incoming_p) 507350397Sobrien{ 507450397Sobrien int regbase = (incoming_p 507550397Sobrien ? SPARC_INCOMING_INT_ARG_FIRST 507650397Sobrien : SPARC_OUTGOING_INT_ARG_FIRST); 507750397Sobrien int slotno, regno, padding; 5078169689Skan enum mode_class mclass = GET_MODE_CLASS (mode); 507950397Sobrien 508050397Sobrien slotno = function_arg_slotno (cum, mode, type, named, incoming_p, 508150397Sobrien ®no, &padding); 508250397Sobrien if (slotno == -1) 508350397Sobrien return 0; 508450397Sobrien 5085169689Skan /* Vector types deserve special treatment because they are polymorphic wrt 5086169689Skan their mode, depending upon whether VIS instructions are enabled. */ 5087169689Skan if (type && TREE_CODE (type) == VECTOR_TYPE) 508850397Sobrien { 5089169689Skan HOST_WIDE_INT size = int_size_in_bytes (type); 5090169689Skan gcc_assert ((TARGET_ARCH32 && size <= 8) 5091169689Skan || (TARGET_ARCH64 && size <= 16)); 5092169689Skan 5093169689Skan if (mode == BLKmode) 5094169689Skan return function_arg_vector_value (size, 5095169689Skan TYPE_MODE (TREE_TYPE (type)), 5096169689Skan SPARC_FP_ARG_FIRST + 2*slotno); 5097169689Skan else 5098169689Skan mclass = MODE_FLOAT; 509950397Sobrien } 5100169689Skan 5101169689Skan if (TARGET_ARCH32) 5102169689Skan return gen_rtx_REG (mode, regno); 5103169689Skan 5104169689Skan /* Structures up to 16 bytes in size are passed in arg slots on the stack 5105169689Skan and are promoted to registers if possible. */ 5106132718Skan if (type && TREE_CODE (type) == RECORD_TYPE) 5107132718Skan { 5108169689Skan HOST_WIDE_INT size = int_size_in_bytes (type); 5109169689Skan gcc_assert (size <= 16); 511050397Sobrien 5111132718Skan return function_arg_record_value (type, mode, slotno, named, regbase); 5112132718Skan } 5113169689Skan 5114169689Skan /* Unions up to 16 bytes in size are passed in integer registers. */ 5115132718Skan else if (type && TREE_CODE (type) == UNION_TYPE) 5116132718Skan { 5117132718Skan HOST_WIDE_INT size = int_size_in_bytes (type); 5118169689Skan gcc_assert (size <= 16); 5119132718Skan 5120146895Skan return function_arg_union_value (size, mode, slotno, regno); 5121132718Skan } 5122169689Skan 512350397Sobrien /* v9 fp args in reg slots beyond the int reg slots get passed in regs 512450397Sobrien but also have the slot allocated for them. 512550397Sobrien If no prototype is in scope fp values in register slots get passed 512650397Sobrien in two places, either fp regs and int regs or fp regs and memory. */ 5127169689Skan else if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) 5128169689Skan && SPARC_FP_REG_P (regno)) 512950397Sobrien { 5130169689Skan rtx reg = gen_rtx_REG (mode, regno); 513150397Sobrien if (cum->prototype_p || cum->libcall_p) 513250397Sobrien { 513350397Sobrien /* "* 2" because fp reg numbers are recorded in 4 byte 513450397Sobrien quantities. */ 513550397Sobrien#if 0 513650397Sobrien /* ??? This will cause the value to be passed in the fp reg and 513750397Sobrien in the stack. When a prototype exists we want to pass the 513850397Sobrien value in the reg but reserve space on the stack. That's an 513950397Sobrien optimization, and is deferred [for a bit]. */ 514050397Sobrien if ((regno - SPARC_FP_ARG_FIRST) >= SPARC_INT_ARG_MAX * 2) 514150397Sobrien return gen_rtx_PARALLEL (mode, 514250397Sobrien gen_rtvec (2, 514350397Sobrien gen_rtx_EXPR_LIST (VOIDmode, 514450397Sobrien NULL_RTX, const0_rtx), 514550397Sobrien gen_rtx_EXPR_LIST (VOIDmode, 514650397Sobrien reg, const0_rtx))); 514750397Sobrien else 514850397Sobrien#else 514950397Sobrien /* ??? It seems that passing back a register even when past 515050397Sobrien the area declared by REG_PARM_STACK_SPACE will allocate 515150397Sobrien space appropriately, and will not copy the data onto the 515250397Sobrien stack, exactly as we desire. 515350397Sobrien 515450397Sobrien This is due to locate_and_pad_parm being called in 515550397Sobrien expand_call whenever reg_parm_stack_space > 0, which 5156132718Skan while beneficial to our example here, would seem to be 515750397Sobrien in error from what had been intended. Ho hum... -- r~ */ 515850397Sobrien#endif 515950397Sobrien return reg; 516050397Sobrien } 516150397Sobrien else 516250397Sobrien { 516350397Sobrien rtx v0, v1; 516450397Sobrien 516550397Sobrien if ((regno - SPARC_FP_ARG_FIRST) < SPARC_INT_ARG_MAX * 2) 516650397Sobrien { 516750397Sobrien int intreg; 516850397Sobrien 516950397Sobrien /* On incoming, we don't need to know that the value 517050397Sobrien is passed in %f0 and %i0, and it confuses other parts 517150397Sobrien causing needless spillage even on the simplest cases. */ 517250397Sobrien if (incoming_p) 517350397Sobrien return reg; 517450397Sobrien 517550397Sobrien intreg = (SPARC_OUTGOING_INT_ARG_FIRST 517650397Sobrien + (regno - SPARC_FP_ARG_FIRST) / 2); 517750397Sobrien 517850397Sobrien v0 = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx); 517950397Sobrien v1 = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (mode, intreg), 518050397Sobrien const0_rtx); 518150397Sobrien return gen_rtx_PARALLEL (mode, gen_rtvec (2, v0, v1)); 518250397Sobrien } 518350397Sobrien else 518450397Sobrien { 518550397Sobrien v0 = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx); 518650397Sobrien v1 = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx); 518750397Sobrien return gen_rtx_PARALLEL (mode, gen_rtvec (2, v0, v1)); 518850397Sobrien } 518950397Sobrien } 519050397Sobrien } 5191169689Skan 5192169689Skan /* All other aggregate types are passed in an integer register in a mode 5193169689Skan corresponding to the size of the type. */ 5194169689Skan else if (type && AGGREGATE_TYPE_P (type)) 519550397Sobrien { 5196169689Skan HOST_WIDE_INT size = int_size_in_bytes (type); 5197169689Skan gcc_assert (size <= 16); 5198169689Skan 5199169689Skan mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0); 520050397Sobrien } 520150397Sobrien 5202169689Skan return gen_rtx_REG (mode, regno); 520350397Sobrien} 520450397Sobrien 5205169689Skan/* For an arg passed partly in registers and partly in memory, 5206169689Skan this is the number of bytes of registers used. 520750397Sobrien For args passed entirely in registers or entirely in memory, zero. 520850397Sobrien 520950397Sobrien Any arg that starts in the first 6 regs but won't entirely fit in them 521050397Sobrien needs partial registers on v8. On v9, structures with integer 521150397Sobrien values in arg slots 5,6 will be passed in %o5 and SP+176, and complex fp 521250397Sobrien values that begin in the last fp reg [where "last fp reg" varies with the 521350397Sobrien mode] will be split between that reg and memory. */ 521450397Sobrien 5215169689Skanstatic int 5216169689Skansparc_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, 5217169689Skan tree type, bool named) 521850397Sobrien{ 521950397Sobrien int slotno, regno, padding; 522050397Sobrien 522150397Sobrien /* We pass 0 for incoming_p here, it doesn't matter. */ 522250397Sobrien slotno = function_arg_slotno (cum, mode, type, named, 0, ®no, &padding); 522350397Sobrien 522450397Sobrien if (slotno == -1) 522550397Sobrien return 0; 522650397Sobrien 522750397Sobrien if (TARGET_ARCH32) 522850397Sobrien { 522950397Sobrien if ((slotno + (mode == BLKmode 523050397Sobrien ? ROUND_ADVANCE (int_size_in_bytes (type)) 523150397Sobrien : ROUND_ADVANCE (GET_MODE_SIZE (mode)))) 5232169689Skan > SPARC_INT_ARG_MAX) 5233169689Skan return (SPARC_INT_ARG_MAX - slotno) * UNITS_PER_WORD; 523450397Sobrien } 523550397Sobrien else 523650397Sobrien { 5237169689Skan /* We are guaranteed by pass_by_reference that the size of the 5238169689Skan argument is not greater than 16 bytes, so we only need to return 5239169689Skan one word if the argument is partially passed in registers. */ 5240169689Skan 524150397Sobrien if (type && AGGREGATE_TYPE_P (type)) 524250397Sobrien { 524350397Sobrien int size = int_size_in_bytes (type); 524450397Sobrien 5245169689Skan if (size > UNITS_PER_WORD 524650397Sobrien && slotno == SPARC_INT_ARG_MAX - 1) 5247169689Skan return UNITS_PER_WORD; 524850397Sobrien } 524950397Sobrien else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT 525050397Sobrien || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT 5251132718Skan && ! (TARGET_FPU && named))) 525250397Sobrien { 5253132718Skan /* The complex types are passed as packed types. */ 5254169689Skan if (GET_MODE_SIZE (mode) > UNITS_PER_WORD 5255169689Skan && slotno == SPARC_INT_ARG_MAX - 1) 5256169689Skan return UNITS_PER_WORD; 525750397Sobrien } 525850397Sobrien else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) 525950397Sobrien { 526050397Sobrien if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD) 526150397Sobrien > SPARC_FP_ARG_MAX) 5262169689Skan return UNITS_PER_WORD; 526350397Sobrien } 526450397Sobrien } 5265169689Skan 5266169689Skan return 0; 526750397Sobrien} 526850397Sobrien 5269169689Skan/* Handle the TARGET_PASS_BY_REFERENCE target hook. 5270169689Skan Specify whether to pass the argument by reference. */ 527150397Sobrien 5272169689Skanstatic bool 5273169689Skansparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, 5274169689Skan enum machine_mode mode, tree type, 5275169689Skan bool named ATTRIBUTE_UNUSED) 527650397Sobrien{ 527750397Sobrien if (TARGET_ARCH32) 5278169689Skan /* Original SPARC 32-bit ABI says that structures and unions, 5279169689Skan and quad-precision floats are passed by reference. For Pascal, 5280169689Skan also pass arrays by reference. All other base types are passed 5281169689Skan in registers. 5282169689Skan 5283169689Skan Extended ABI (as implemented by the Sun compiler) says that all 5284169689Skan complex floats are passed by reference. Pass complex integers 5285169689Skan in registers up to 8 bytes. More generally, enforce the 2-word 5286169689Skan cap for passing arguments in registers. 5287169689Skan 5288169689Skan Vector ABI (as implemented by the Sun VIS SDK) says that vector 5289169689Skan integers are passed like floats of the same size, that is in 5290169689Skan registers up to 8 bytes. Pass all vector floats by reference 5291169689Skan like structure and unions. */ 5292169689Skan return ((type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type))) 5293169689Skan || mode == SCmode 5294169689Skan /* Catch CDImode, TFmode, DCmode and TCmode. */ 5295169689Skan || GET_MODE_SIZE (mode) > 8 5296169689Skan || (type 5297169689Skan && TREE_CODE (type) == VECTOR_TYPE 5298169689Skan && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8)); 529950397Sobrien else 5300169689Skan /* Original SPARC 64-bit ABI says that structures and unions 5301169689Skan smaller than 16 bytes are passed in registers, as well as 5302169689Skan all other base types. 5303169689Skan 5304169689Skan Extended ABI (as implemented by the Sun compiler) says that 5305169689Skan complex floats are passed in registers up to 16 bytes. Pass 5306169689Skan all complex integers in registers up to 16 bytes. More generally, 5307169689Skan enforce the 2-word cap for passing arguments in registers. 5308169689Skan 5309169689Skan Vector ABI (as implemented by the Sun VIS SDK) says that vector 5310169689Skan integers are passed like floats of the same size, that is in 5311169689Skan registers (up to 16 bytes). Pass all vector floats like structure 5312169689Skan and unions. */ 5313169689Skan return ((type 5314169689Skan && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE) 5315169689Skan && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16) 5316169689Skan /* Catch CTImode and TCmode. */ 5317169689Skan || GET_MODE_SIZE (mode) > 16); 531850397Sobrien} 531950397Sobrien 532050397Sobrien/* Handle the FUNCTION_ARG_ADVANCE macro. 532150397Sobrien Update the data in CUM to advance over an argument 532250397Sobrien of mode MODE and data type TYPE. 532350397Sobrien TYPE is null for libcalls where that information may not be available. */ 532450397Sobrien 532550397Sobrienvoid 5326132718Skanfunction_arg_advance (struct sparc_args *cum, enum machine_mode mode, 5327132718Skan tree type, int named) 532850397Sobrien{ 532950397Sobrien int slotno, regno, padding; 533050397Sobrien 533150397Sobrien /* We pass 0 for incoming_p here, it doesn't matter. */ 533250397Sobrien slotno = function_arg_slotno (cum, mode, type, named, 0, ®no, &padding); 533350397Sobrien 533450397Sobrien /* If register required leading padding, add it. */ 533550397Sobrien if (slotno != -1) 533650397Sobrien cum->words += padding; 533750397Sobrien 533850397Sobrien if (TARGET_ARCH32) 533950397Sobrien { 534050397Sobrien cum->words += (mode != BLKmode 534150397Sobrien ? ROUND_ADVANCE (GET_MODE_SIZE (mode)) 534250397Sobrien : ROUND_ADVANCE (int_size_in_bytes (type))); 534350397Sobrien } 534450397Sobrien else 534550397Sobrien { 534650397Sobrien if (type && AGGREGATE_TYPE_P (type)) 534750397Sobrien { 534850397Sobrien int size = int_size_in_bytes (type); 534950397Sobrien 535050397Sobrien if (size <= 8) 535150397Sobrien ++cum->words; 535250397Sobrien else if (size <= 16) 535350397Sobrien cum->words += 2; 535450397Sobrien else /* passed by reference */ 535550397Sobrien ++cum->words; 535650397Sobrien } 535750397Sobrien else 535850397Sobrien { 535950397Sobrien cum->words += (mode != BLKmode 536050397Sobrien ? ROUND_ADVANCE (GET_MODE_SIZE (mode)) 536150397Sobrien : ROUND_ADVANCE (int_size_in_bytes (type))); 536250397Sobrien } 536350397Sobrien } 536450397Sobrien} 536550397Sobrien 536650397Sobrien/* Handle the FUNCTION_ARG_PADDING macro. 536750397Sobrien For the 64 bit ABI structs are always stored left shifted in their 536850397Sobrien argument slot. */ 536950397Sobrien 537050397Sobrienenum direction 5371132718Skanfunction_arg_padding (enum machine_mode mode, tree type) 537250397Sobrien{ 537350397Sobrien if (TARGET_ARCH64 && type != 0 && AGGREGATE_TYPE_P (type)) 537450397Sobrien return upward; 537550397Sobrien 5376132718Skan /* Fall back to the default. */ 5377132718Skan return DEFAULT_FUNCTION_ARG_PADDING (mode, type); 537850397Sobrien} 537950397Sobrien 5380169689Skan/* Handle the TARGET_RETURN_IN_MEMORY target hook. 5381169689Skan Specify whether to return the return value in memory. */ 5382169689Skan 5383169689Skanstatic bool 5384169689Skansparc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED) 5385169689Skan{ 5386169689Skan if (TARGET_ARCH32) 5387169689Skan /* Original SPARC 32-bit ABI says that structures and unions, 5388169689Skan and quad-precision floats are returned in memory. All other 5389169689Skan base types are returned in registers. 5390169689Skan 5391169689Skan Extended ABI (as implemented by the Sun compiler) says that 5392169689Skan all complex floats are returned in registers (8 FP registers 5393169689Skan at most for '_Complex long double'). Return all complex integers 5394169689Skan in registers (4 at most for '_Complex long long'). 5395169689Skan 5396169689Skan Vector ABI (as implemented by the Sun VIS SDK) says that vector 5397169689Skan integers are returned like floats of the same size, that is in 5398169689Skan registers up to 8 bytes and in memory otherwise. Return all 5399169689Skan vector floats in memory like structure and unions; note that 5400169689Skan they always have BLKmode like the latter. */ 5401169689Skan return (TYPE_MODE (type) == BLKmode 5402169689Skan || TYPE_MODE (type) == TFmode 5403169689Skan || (TREE_CODE (type) == VECTOR_TYPE 5404169689Skan && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8)); 5405169689Skan else 5406169689Skan /* Original SPARC 64-bit ABI says that structures and unions 5407169689Skan smaller than 32 bytes are returned in registers, as well as 5408169689Skan all other base types. 5409169689Skan 5410169689Skan Extended ABI (as implemented by the Sun compiler) says that all 5411169689Skan complex floats are returned in registers (8 FP registers at most 5412169689Skan for '_Complex long double'). Return all complex integers in 5413169689Skan registers (4 at most for '_Complex TItype'). 5414169689Skan 5415169689Skan Vector ABI (as implemented by the Sun VIS SDK) says that vector 5416169689Skan integers are returned like floats of the same size, that is in 5417169689Skan registers. Return all vector floats like structure and unions; 5418169689Skan note that they always have BLKmode like the latter. */ 5419169689Skan return ((TYPE_MODE (type) == BLKmode 5420169689Skan && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32)); 5421169689Skan} 5422169689Skan 5423169689Skan/* Handle the TARGET_STRUCT_VALUE target hook. 5424169689Skan Return where to find the structure return value address. */ 5425169689Skan 5426169689Skanstatic rtx 5427169689Skansparc_struct_value_rtx (tree fndecl, int incoming) 5428169689Skan{ 5429169689Skan if (TARGET_ARCH64) 5430169689Skan return 0; 5431169689Skan else 5432169689Skan { 5433169689Skan rtx mem; 5434169689Skan 5435169689Skan if (incoming) 5436169689Skan mem = gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx, 5437169689Skan STRUCT_VALUE_OFFSET)); 5438169689Skan else 5439169689Skan mem = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx, 5440169689Skan STRUCT_VALUE_OFFSET)); 5441169689Skan 5442169689Skan /* Only follow the SPARC ABI for fixed-size structure returns. 5443169689Skan Variable size structure returns are handled per the normal 5444169689Skan procedures in GCC. This is enabled by -mstd-struct-return */ 5445169689Skan if (incoming == 2 5446169689Skan && sparc_std_struct_return 5447169689Skan && TYPE_SIZE_UNIT (TREE_TYPE (fndecl)) 5448169689Skan && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (fndecl))) == INTEGER_CST) 5449169689Skan { 5450169689Skan /* We must check and adjust the return address, as it is 5451169689Skan optional as to whether the return object is really 5452169689Skan provided. */ 5453169689Skan rtx ret_rtx = gen_rtx_REG (Pmode, 31); 5454169689Skan rtx scratch = gen_reg_rtx (SImode); 5455169689Skan rtx endlab = gen_label_rtx (); 5456169689Skan 5457169689Skan /* Calculate the return object size */ 5458169689Skan tree size = TYPE_SIZE_UNIT (TREE_TYPE (fndecl)); 5459169689Skan rtx size_rtx = GEN_INT (TREE_INT_CST_LOW (size) & 0xfff); 5460169689Skan /* Construct a temporary return value */ 5461169689Skan rtx temp_val = assign_stack_local (Pmode, TREE_INT_CST_LOW (size), 0); 5462169689Skan 5463169689Skan /* Implement SPARC 32-bit psABI callee returns struck checking 5464169689Skan requirements: 5465169689Skan 5466169689Skan Fetch the instruction where we will return to and see if 5467169689Skan it's an unimp instruction (the most significant 10 bits 5468169689Skan will be zero). */ 5469169689Skan emit_move_insn (scratch, gen_rtx_MEM (SImode, 5470169689Skan plus_constant (ret_rtx, 8))); 5471169689Skan /* Assume the size is valid and pre-adjust */ 5472169689Skan emit_insn (gen_add3_insn (ret_rtx, ret_rtx, GEN_INT (4))); 5473169689Skan emit_cmp_and_jump_insns (scratch, size_rtx, EQ, const0_rtx, SImode, 0, endlab); 5474169689Skan emit_insn (gen_sub3_insn (ret_rtx, ret_rtx, GEN_INT (4))); 5475169689Skan /* Assign stack temp: 5476169689Skan Write the address of the memory pointed to by temp_val into 5477169689Skan the memory pointed to by mem */ 5478169689Skan emit_move_insn (mem, XEXP (temp_val, 0)); 5479169689Skan emit_label (endlab); 5480169689Skan } 5481169689Skan 5482169689Skan set_mem_alias_set (mem, struct_value_alias_set); 5483169689Skan return mem; 5484169689Skan } 5485169689Skan} 5486169689Skan 548750397Sobrien/* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE macros. 548850397Sobrien For v9, function return values are subject to the same rules as arguments, 5489169689Skan except that up to 32 bytes may be returned in registers. */ 549050397Sobrien 549150397Sobrienrtx 5492132718Skanfunction_value (tree type, enum machine_mode mode, int incoming_p) 549350397Sobrien{ 5494169689Skan /* Beware that the two values are swapped here wrt function_arg. */ 5495169689Skan int regbase = (incoming_p 5496169689Skan ? SPARC_OUTGOING_INT_ARG_FIRST 5497169689Skan : SPARC_INCOMING_INT_ARG_FIRST); 5498169689Skan enum mode_class mclass = GET_MODE_CLASS (mode); 549950397Sobrien int regno; 550050397Sobrien 5501169689Skan /* Vector types deserve special treatment because they are polymorphic wrt 5502169689Skan their mode, depending upon whether VIS instructions are enabled. */ 5503169689Skan if (type && TREE_CODE (type) == VECTOR_TYPE) 5504169689Skan { 5505169689Skan HOST_WIDE_INT size = int_size_in_bytes (type); 5506169689Skan gcc_assert ((TARGET_ARCH32 && size <= 8) 5507169689Skan || (TARGET_ARCH64 && size <= 32)); 5508169689Skan 5509169689Skan if (mode == BLKmode) 5510169689Skan return function_arg_vector_value (size, 5511169689Skan TYPE_MODE (TREE_TYPE (type)), 5512169689Skan SPARC_FP_ARG_FIRST); 5513169689Skan else 5514169689Skan mclass = MODE_FLOAT; 5515169689Skan } 5516169689Skan 551750397Sobrien if (TARGET_ARCH64 && type) 551850397Sobrien { 5519169689Skan /* Structures up to 32 bytes in size are returned in registers. */ 552050397Sobrien if (TREE_CODE (type) == RECORD_TYPE) 552150397Sobrien { 5522169689Skan HOST_WIDE_INT size = int_size_in_bytes (type); 5523169689Skan gcc_assert (size <= 32); 552450397Sobrien 552550397Sobrien return function_arg_record_value (type, mode, 0, 1, regbase); 552650397Sobrien } 5527169689Skan 5528169689Skan /* Unions up to 32 bytes in size are returned in integer registers. */ 5529132718Skan else if (TREE_CODE (type) == UNION_TYPE) 5530132718Skan { 5531132718Skan HOST_WIDE_INT size = int_size_in_bytes (type); 5532169689Skan gcc_assert (size <= 32); 5533132718Skan 5534146895Skan return function_arg_union_value (size, mode, 0, regbase); 5535132718Skan } 5536169689Skan 5537169689Skan /* Objects that require it are returned in FP registers. */ 5538169689Skan else if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) 5539169689Skan ; 5540169689Skan 5541169689Skan /* All other aggregate types are returned in an integer register in a 5542169689Skan mode corresponding to the size of the type. */ 554390075Sobrien else if (AGGREGATE_TYPE_P (type)) 554450397Sobrien { 554590075Sobrien /* All other aggregate types are passed in an integer register 554690075Sobrien in a mode corresponding to the size of the type. */ 5547169689Skan HOST_WIDE_INT size = int_size_in_bytes (type); 5548169689Skan gcc_assert (size <= 32); 554950397Sobrien 5550169689Skan mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0); 555150397Sobrien 5552132718Skan /* ??? We probably should have made the same ABI change in 5553132718Skan 3.4.0 as the one we made for unions. The latter was 5554132718Skan required by the SCD though, while the former is not 5555132718Skan specified, so we favored compatibility and efficiency. 5556132718Skan 5557132718Skan Now we're stuck for aggregates larger than 16 bytes, 5558132718Skan because OImode vanished in the meantime. Let's not 5559132718Skan try to be unduly clever, and simply follow the ABI 5560132718Skan for unions in that case. */ 5561132718Skan if (mode == BLKmode) 5562169689Skan return function_arg_union_value (size, mode, 0, regbase); 5563169689Skan else 5564169689Skan mclass = MODE_INT; 556550397Sobrien } 5566169689Skan 5567169689Skan /* This must match PROMOTE_FUNCTION_MODE. */ 5568169689Skan else if (mclass == MODE_INT && GET_MODE_SIZE (mode) < UNITS_PER_WORD) 5569132718Skan mode = word_mode; 557050397Sobrien } 557150397Sobrien 5572169689Skan if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) && TARGET_FPU) 5573169689Skan regno = SPARC_FP_ARG_FIRST; 557450397Sobrien else 5575169689Skan regno = regbase; 557650397Sobrien 557750397Sobrien return gen_rtx_REG (mode, regno); 557850397Sobrien} 557950397Sobrien 558090075Sobrien/* Do what is necessary for `va_start'. We look at the current function 558190075Sobrien to determine if stdarg or varargs is used and return the address of 558290075Sobrien the first unnamed parameter. */ 558350397Sobrien 5584169689Skanstatic rtx 5585132718Skansparc_builtin_saveregs (void) 558650397Sobrien{ 558750397Sobrien int first_reg = current_function_args_info.words; 558850397Sobrien rtx address; 558950397Sobrien int regno; 559050397Sobrien 5591169689Skan for (regno = first_reg; regno < SPARC_INT_ARG_MAX; regno++) 559250397Sobrien emit_move_insn (gen_rtx_MEM (word_mode, 559390075Sobrien gen_rtx_PLUS (Pmode, 559490075Sobrien frame_pointer_rtx, 559596263Sobrien GEN_INT (FIRST_PARM_OFFSET (0) 559690075Sobrien + (UNITS_PER_WORD 559790075Sobrien * regno)))), 559850397Sobrien gen_rtx_REG (word_mode, 5599169689Skan SPARC_INCOMING_INT_ARG_FIRST + regno)); 560050397Sobrien 560150397Sobrien address = gen_rtx_PLUS (Pmode, 560290075Sobrien frame_pointer_rtx, 560396263Sobrien GEN_INT (FIRST_PARM_OFFSET (0) 560490075Sobrien + UNITS_PER_WORD * first_reg)); 560550397Sobrien 560650397Sobrien return address; 560750397Sobrien} 560890075Sobrien 5609169689Skan/* Implement `va_start' for stdarg. */ 561090075Sobrien 561190075Sobrienvoid 5612132718Skansparc_va_start (tree valist, rtx nextarg) 561390075Sobrien{ 561490075Sobrien nextarg = expand_builtin_saveregs (); 5615117395Skan std_expand_builtin_va_start (valist, nextarg); 561690075Sobrien} 561790075Sobrien 5618169689Skan/* Implement `va_arg' for stdarg. */ 561990075Sobrien 5620169689Skanstatic tree 5621169689Skansparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) 562290075Sobrien{ 562390075Sobrien HOST_WIDE_INT size, rsize, align; 562490075Sobrien tree addr, incr; 5625169689Skan bool indirect; 5626169689Skan tree ptrtype = build_pointer_type (type); 562790075Sobrien 5628169689Skan if (pass_by_reference (NULL, TYPE_MODE (type), type, false)) 562990075Sobrien { 5630169689Skan indirect = true; 5631169689Skan size = rsize = UNITS_PER_WORD; 5632169689Skan align = 0; 563390075Sobrien } 563490075Sobrien else 563590075Sobrien { 5636169689Skan indirect = false; 5637169689Skan size = int_size_in_bytes (type); 5638169689Skan rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD; 5639169689Skan align = 0; 5640169689Skan 5641169689Skan if (TARGET_ARCH64) 564290075Sobrien { 5643169689Skan /* For SPARC64, objects requiring 16-byte alignment get it. */ 5644169689Skan if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD) 5645169689Skan align = 2 * UNITS_PER_WORD; 5646169689Skan 5647169689Skan /* SPARC-V9 ABI states that structures up to 16 bytes in size 5648169689Skan are left-justified in their slots. */ 5649169689Skan if (AGGREGATE_TYPE_P (type)) 5650169689Skan { 5651169689Skan if (size == 0) 5652169689Skan size = rsize = UNITS_PER_WORD; 5653169689Skan else 5654169689Skan size = rsize; 5655169689Skan } 565690075Sobrien } 565790075Sobrien } 565890075Sobrien 565990075Sobrien incr = valist; 566090075Sobrien if (align) 566190075Sobrien { 5662169689Skan incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, 5663169689Skan ssize_int (align - 1))); 5664169689Skan incr = fold (build2 (BIT_AND_EXPR, ptr_type_node, incr, 5665169689Skan ssize_int (-align))); 566690075Sobrien } 566790075Sobrien 5668169689Skan gimplify_expr (&incr, pre_p, post_p, is_gimple_val, fb_rvalue); 5669169689Skan addr = incr; 5670169689Skan 567190075Sobrien if (BYTES_BIG_ENDIAN && size < rsize) 5672169689Skan addr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, 5673169689Skan ssize_int (rsize - size))); 5674169689Skan 5675169689Skan if (indirect) 567690075Sobrien { 5677169689Skan addr = fold_convert (build_pointer_type (ptrtype), addr); 5678169689Skan addr = build_va_arg_indirect_ref (addr); 567990075Sobrien } 568090075Sobrien /* If the address isn't aligned properly for the type, 568190075Sobrien we may need to copy to a temporary. 568290075Sobrien FIXME: This is inefficient. Usually we can do this 568390075Sobrien in registers. */ 5684169689Skan else if (align == 0 5685169689Skan && TYPE_ALIGN (type) > BITS_PER_WORD) 568690075Sobrien { 5687169689Skan tree tmp = create_tmp_var (type, "va_arg_tmp"); 5688169689Skan tree dest_addr = build_fold_addr_expr (tmp); 568990075Sobrien 5690169689Skan tree copy = build_function_call_expr 5691169689Skan (implicit_built_in_decls[BUILT_IN_MEMCPY], 5692169689Skan tree_cons (NULL_TREE, dest_addr, 5693169689Skan tree_cons (NULL_TREE, addr, 5694169689Skan tree_cons (NULL_TREE, size_int (rsize), 5695169689Skan NULL_TREE)))); 569690075Sobrien 5697169689Skan gimplify_and_add (copy, pre_p); 5698169689Skan addr = dest_addr; 569990075Sobrien } 5700169689Skan else 5701169689Skan addr = fold_convert (ptrtype, addr); 570290075Sobrien 5703169689Skan incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, ssize_int (rsize))); 5704169689Skan incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr); 5705169689Skan gimplify_and_add (incr, post_p); 5706169689Skan 5707169689Skan return build_va_arg_indirect_ref (addr); 570890075Sobrien} 570950397Sobrien 5710169689Skan/* Implement the TARGET_VECTOR_MODE_SUPPORTED_P target hook. 5711169689Skan Specify whether the vector mode is supported by the hardware. */ 5712169689Skan 5713169689Skanstatic bool 5714169689Skansparc_vector_mode_supported_p (enum machine_mode mode) 5715169689Skan{ 5716169689Skan return TARGET_VIS && VECTOR_MODE_P (mode) ? true : false; 5717169689Skan} 5718169689Skan 5719132718Skan/* Return the string to output an unconditional branch to LABEL, which is 5720132718Skan the operand number of the label. 5721132718Skan 5722132718Skan DEST is the destination insn (i.e. the label), INSN is the source. */ 5723132718Skan 5724132718Skanconst char * 5725132718Skanoutput_ubranch (rtx dest, int label, rtx insn) 5726132718Skan{ 5727132718Skan static char string[64]; 5728169689Skan bool v9_form = false; 5729132718Skan char *p; 5730132718Skan 5731169689Skan if (TARGET_V9 && INSN_ADDRESSES_SET_P ()) 5732132718Skan { 5733169689Skan int delta = (INSN_ADDRESSES (INSN_UID (dest)) 5734169689Skan - INSN_ADDRESSES (INSN_UID (insn))); 5735169689Skan /* Leave some instructions for "slop". */ 5736169689Skan if (delta >= -260000 && delta < 260000) 5737169689Skan v9_form = true; 5738132718Skan } 5739169689Skan 5740169689Skan if (v9_form) 5741169689Skan strcpy (string, "ba%*,pt\t%%xcc, "); 5742132718Skan else 5743169689Skan strcpy (string, "b%*\t"); 5744132718Skan 5745132718Skan p = strchr (string, '\0'); 5746132718Skan *p++ = '%'; 5747132718Skan *p++ = 'l'; 5748132718Skan *p++ = '0' + label; 5749132718Skan *p++ = '%'; 5750169689Skan *p++ = '('; 5751132718Skan *p = '\0'; 5752132718Skan 5753132718Skan return string; 5754132718Skan} 5755132718Skan 575650397Sobrien/* Return the string to output a conditional branch to LABEL, which is 575750397Sobrien the operand number of the label. OP is the conditional expression. 575850397Sobrien XEXP (OP, 0) is assumed to be a condition code register (integer or 575950397Sobrien floating point) and its mode specifies what kind of comparison we made. 576050397Sobrien 5761132718Skan DEST is the destination insn (i.e. the label), INSN is the source. 5762132718Skan 5763117395Skan REVERSED is nonzero if we should reverse the sense of the comparison. 576450397Sobrien 5765169689Skan ANNUL is nonzero if we should generate an annulling branch. */ 576650397Sobrien 5767169689Skanconst char * 5768132718Skanoutput_cbranch (rtx op, rtx dest, int label, int reversed, int annul, 5769169689Skan rtx insn) 577050397Sobrien{ 5771169689Skan static char string[64]; 577250397Sobrien enum rtx_code code = GET_CODE (op); 577350397Sobrien rtx cc_reg = XEXP (op, 0); 577450397Sobrien enum machine_mode mode = GET_MODE (cc_reg); 577596263Sobrien const char *labelno, *branch; 577696263Sobrien int spaces = 8, far; 577796263Sobrien char *p; 577850397Sobrien 577996263Sobrien /* v9 branches are limited to +-1MB. If it is too far away, 578096263Sobrien change 578196263Sobrien 578296263Sobrien bne,pt %xcc, .LC30 578396263Sobrien 578496263Sobrien to 578596263Sobrien 578696263Sobrien be,pn %xcc, .+12 5787169689Skan nop 578896263Sobrien ba .LC30 578996263Sobrien 579096263Sobrien and 579196263Sobrien 579296263Sobrien fbne,a,pn %fcc2, .LC29 579396263Sobrien 579496263Sobrien to 579596263Sobrien 579696263Sobrien fbe,pt %fcc2, .+16 5797169689Skan nop 579896263Sobrien ba .LC29 */ 579996263Sobrien 5800132718Skan far = TARGET_V9 && (get_attr_length (insn) >= 3); 580196263Sobrien if (reversed ^ far) 580250397Sobrien { 580390075Sobrien /* Reversal of FP compares takes care -- an ordered compare 580490075Sobrien becomes an unordered compare and vice versa. */ 580550397Sobrien if (mode == CCFPmode || mode == CCFPEmode) 580690075Sobrien code = reverse_condition_maybe_unordered (code); 580750397Sobrien else 580890075Sobrien code = reverse_condition (code); 580990075Sobrien } 581050397Sobrien 581190075Sobrien /* Start by writing the branch condition. */ 581290075Sobrien if (mode == CCFPmode || mode == CCFPEmode) 581390075Sobrien { 581490075Sobrien switch (code) 581552284Sobrien { 581690075Sobrien case NE: 581790075Sobrien branch = "fbne"; 581890075Sobrien break; 581990075Sobrien case EQ: 582090075Sobrien branch = "fbe"; 582190075Sobrien break; 582290075Sobrien case GE: 582390075Sobrien branch = "fbge"; 582490075Sobrien break; 582590075Sobrien case GT: 582690075Sobrien branch = "fbg"; 582790075Sobrien break; 582890075Sobrien case LE: 582990075Sobrien branch = "fble"; 583090075Sobrien break; 583190075Sobrien case LT: 583290075Sobrien branch = "fbl"; 583390075Sobrien break; 583490075Sobrien case UNORDERED: 583590075Sobrien branch = "fbu"; 583690075Sobrien break; 583790075Sobrien case ORDERED: 583890075Sobrien branch = "fbo"; 583990075Sobrien break; 584090075Sobrien case UNGT: 584190075Sobrien branch = "fbug"; 584290075Sobrien break; 584390075Sobrien case UNLT: 584490075Sobrien branch = "fbul"; 584590075Sobrien break; 584690075Sobrien case UNEQ: 584790075Sobrien branch = "fbue"; 584890075Sobrien break; 584990075Sobrien case UNGE: 585090075Sobrien branch = "fbuge"; 585190075Sobrien break; 585290075Sobrien case UNLE: 585390075Sobrien branch = "fbule"; 585490075Sobrien break; 585590075Sobrien case LTGT: 585690075Sobrien branch = "fblg"; 585790075Sobrien break; 585850397Sobrien 585990075Sobrien default: 5860169689Skan gcc_unreachable (); 586150397Sobrien } 586250397Sobrien 586390075Sobrien /* ??? !v9: FP branches cannot be preceded by another floating point 586490075Sobrien insn. Because there is currently no concept of pre-delay slots, 586590075Sobrien we can fix this only by always emitting a nop before a floating 586690075Sobrien point branch. */ 586750397Sobrien 586890075Sobrien string[0] = '\0'; 586990075Sobrien if (! TARGET_V9) 587090075Sobrien strcpy (string, "nop\n\t"); 587190075Sobrien strcat (string, branch); 587290075Sobrien } 587390075Sobrien else 587490075Sobrien { 587590075Sobrien switch (code) 587650397Sobrien { 587790075Sobrien case NE: 587890075Sobrien branch = "bne"; 587990075Sobrien break; 588090075Sobrien case EQ: 588190075Sobrien branch = "be"; 588290075Sobrien break; 588390075Sobrien case GE: 588496263Sobrien if (mode == CC_NOOVmode || mode == CCX_NOOVmode) 588590075Sobrien branch = "bpos"; 588650397Sobrien else 588790075Sobrien branch = "bge"; 588890075Sobrien break; 588990075Sobrien case GT: 589090075Sobrien branch = "bg"; 589190075Sobrien break; 589290075Sobrien case LE: 589390075Sobrien branch = "ble"; 589490075Sobrien break; 589590075Sobrien case LT: 589696263Sobrien if (mode == CC_NOOVmode || mode == CCX_NOOVmode) 589790075Sobrien branch = "bneg"; 589890075Sobrien else 589990075Sobrien branch = "bl"; 590090075Sobrien break; 590190075Sobrien case GEU: 590290075Sobrien branch = "bgeu"; 590390075Sobrien break; 590490075Sobrien case GTU: 590590075Sobrien branch = "bgu"; 590690075Sobrien break; 590790075Sobrien case LEU: 590890075Sobrien branch = "bleu"; 590990075Sobrien break; 591090075Sobrien case LTU: 591190075Sobrien branch = "blu"; 591290075Sobrien break; 591350397Sobrien 591490075Sobrien default: 5915169689Skan gcc_unreachable (); 591650397Sobrien } 591790075Sobrien strcpy (string, branch); 591850397Sobrien } 591990075Sobrien spaces -= strlen (branch); 592096263Sobrien p = strchr (string, '\0'); 592150397Sobrien 592250397Sobrien /* Now add the annulling, the label, and a possible noop. */ 592396263Sobrien if (annul && ! far) 592452284Sobrien { 592596263Sobrien strcpy (p, ",a"); 592696263Sobrien p += 2; 592752284Sobrien spaces -= 2; 592852284Sobrien } 592950397Sobrien 5930132718Skan if (TARGET_V9) 593150397Sobrien { 593250397Sobrien rtx note; 593396263Sobrien int v8 = 0; 593450397Sobrien 593596263Sobrien if (! far && insn && INSN_ADDRESSES_SET_P ()) 593652284Sobrien { 593796263Sobrien int delta = (INSN_ADDRESSES (INSN_UID (dest)) 593896263Sobrien - INSN_ADDRESSES (INSN_UID (insn))); 593996263Sobrien /* Leave some instructions for "slop". */ 594096263Sobrien if (delta < -260000 || delta >= 260000) 594196263Sobrien v8 = 1; 594252284Sobrien } 594350397Sobrien 594450397Sobrien if (mode == CCFPmode || mode == CCFPEmode) 594550397Sobrien { 594696263Sobrien static char v9_fcc_labelno[] = "%%fccX, "; 594796263Sobrien /* Set the char indicating the number of the fcc reg to use. */ 594896263Sobrien v9_fcc_labelno[5] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0'; 594950397Sobrien labelno = v9_fcc_labelno; 595096263Sobrien if (v8) 595196263Sobrien { 5952169689Skan gcc_assert (REGNO (cc_reg) == SPARC_FCC_REG); 5953169689Skan labelno = ""; 595496263Sobrien } 595550397Sobrien } 595650397Sobrien else if (mode == CCXmode || mode == CCX_NOOVmode) 595796263Sobrien { 595896263Sobrien labelno = "%%xcc, "; 5959169689Skan gcc_assert (! v8); 596096263Sobrien } 596150397Sobrien else 596296263Sobrien { 596396263Sobrien labelno = "%%icc, "; 596496263Sobrien if (v8) 596596263Sobrien labelno = ""; 596696263Sobrien } 596796263Sobrien 596896263Sobrien if (*labelno && insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX))) 596996263Sobrien { 597096263Sobrien strcpy (p, 597196263Sobrien ((INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ^ far) 597296263Sobrien ? ",pt" : ",pn"); 597396263Sobrien p += 3; 597496263Sobrien spaces -= 3; 597596263Sobrien } 597650397Sobrien } 5977132718Skan else 5978132718Skan labelno = ""; 5979132718Skan 598096263Sobrien if (spaces > 0) 598196263Sobrien *p++ = '\t'; 598296263Sobrien else 598396263Sobrien *p++ = ' '; 598496263Sobrien strcpy (p, labelno); 598596263Sobrien p = strchr (p, '\0'); 598696263Sobrien if (far) 598796263Sobrien { 5988169689Skan strcpy (p, ".+12\n\t nop\n\tb\t"); 5989169689Skan /* Skip the next insn if requested or 5990169689Skan if we know that it will be a nop. */ 5991169689Skan if (annul || ! final_sequence) 599296263Sobrien p[3] = '6'; 5993169689Skan p += 14; 599496263Sobrien } 599596263Sobrien *p++ = '%'; 599696263Sobrien *p++ = 'l'; 599796263Sobrien *p++ = label + '0'; 5998169689Skan *p++ = '%'; 5999169689Skan *p++ = '#'; 600096263Sobrien *p = '\0'; 600150397Sobrien 600250397Sobrien return string; 600350397Sobrien} 600450397Sobrien 600590075Sobrien/* Emit a library call comparison between floating point X and Y. 600690075Sobrien COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). 600790075Sobrien TARGET_ARCH64 uses _Qp_* functions, which use pointers to TFmode 600890075Sobrien values as arguments instead of the TFmode registers themselves, 600990075Sobrien that's why we cannot call emit_float_lib_cmp. */ 601090075Sobrienvoid 6011132718Skansparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison) 601290075Sobrien{ 601390075Sobrien const char *qpfunc; 601490075Sobrien rtx slot0, slot1, result, tem, tem2; 601590075Sobrien enum machine_mode mode; 601690075Sobrien 601790075Sobrien switch (comparison) 601890075Sobrien { 601990075Sobrien case EQ: 602090075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_feq" : "_Q_feq"; 602190075Sobrien break; 602290075Sobrien 602390075Sobrien case NE: 602490075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_fne" : "_Q_fne"; 602590075Sobrien break; 602690075Sobrien 602790075Sobrien case GT: 602890075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_fgt" : "_Q_fgt"; 602990075Sobrien break; 603090075Sobrien 603190075Sobrien case GE: 603290075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_fge" : "_Q_fge"; 603390075Sobrien break; 603490075Sobrien 603590075Sobrien case LT: 603690075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_flt" : "_Q_flt"; 603790075Sobrien break; 603890075Sobrien 603990075Sobrien case LE: 604090075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_fle" : "_Q_fle"; 604190075Sobrien break; 604290075Sobrien 604390075Sobrien case ORDERED: 604490075Sobrien case UNORDERED: 604590075Sobrien case UNGT: 604690075Sobrien case UNLT: 604790075Sobrien case UNEQ: 604890075Sobrien case UNGE: 604990075Sobrien case UNLE: 605090075Sobrien case LTGT: 605190075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_cmp" : "_Q_cmp"; 605290075Sobrien break; 605390075Sobrien 605490075Sobrien default: 6055169689Skan gcc_unreachable (); 605690075Sobrien } 605790075Sobrien 605890075Sobrien if (TARGET_ARCH64) 605990075Sobrien { 606090075Sobrien if (GET_CODE (x) != MEM) 606190075Sobrien { 606290075Sobrien slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0); 6063169689Skan emit_move_insn (slot0, x); 606490075Sobrien } 606590075Sobrien else 606690075Sobrien slot0 = x; 606790075Sobrien 606890075Sobrien if (GET_CODE (y) != MEM) 606990075Sobrien { 607090075Sobrien slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0); 6071169689Skan emit_move_insn (slot1, y); 607290075Sobrien } 607390075Sobrien else 607490075Sobrien slot1 = y; 607590075Sobrien 607696263Sobrien emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL, 607790075Sobrien DImode, 2, 607890075Sobrien XEXP (slot0, 0), Pmode, 607990075Sobrien XEXP (slot1, 0), Pmode); 608090075Sobrien 608190075Sobrien mode = DImode; 608290075Sobrien } 608390075Sobrien else 608490075Sobrien { 608596263Sobrien emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL, 608690075Sobrien SImode, 2, 608790075Sobrien x, TFmode, y, TFmode); 608890075Sobrien 608990075Sobrien mode = SImode; 609090075Sobrien } 609190075Sobrien 609290075Sobrien 609390075Sobrien /* Immediately move the result of the libcall into a pseudo 609490075Sobrien register so reload doesn't clobber the value if it needs 609590075Sobrien the return register for a spill reg. */ 609690075Sobrien result = gen_reg_rtx (mode); 609790075Sobrien emit_move_insn (result, hard_libcall_value (mode)); 609890075Sobrien 609990075Sobrien switch (comparison) 610090075Sobrien { 610190075Sobrien default: 610290075Sobrien emit_cmp_insn (result, const0_rtx, NE, NULL_RTX, mode, 0); 610390075Sobrien break; 610490075Sobrien case ORDERED: 610590075Sobrien case UNORDERED: 610690075Sobrien emit_cmp_insn (result, GEN_INT(3), comparison == UNORDERED ? EQ : NE, 610790075Sobrien NULL_RTX, mode, 0); 610890075Sobrien break; 610990075Sobrien case UNGT: 611090075Sobrien case UNGE: 611190075Sobrien emit_cmp_insn (result, const1_rtx, 611290075Sobrien comparison == UNGT ? GT : NE, NULL_RTX, mode, 0); 611390075Sobrien break; 611490075Sobrien case UNLE: 611590075Sobrien emit_cmp_insn (result, const2_rtx, NE, NULL_RTX, mode, 0); 611690075Sobrien break; 611790075Sobrien case UNLT: 611890075Sobrien tem = gen_reg_rtx (mode); 611990075Sobrien if (TARGET_ARCH32) 612090075Sobrien emit_insn (gen_andsi3 (tem, result, const1_rtx)); 612190075Sobrien else 612290075Sobrien emit_insn (gen_anddi3 (tem, result, const1_rtx)); 612390075Sobrien emit_cmp_insn (tem, const0_rtx, NE, NULL_RTX, mode, 0); 612490075Sobrien break; 612590075Sobrien case UNEQ: 612690075Sobrien case LTGT: 612790075Sobrien tem = gen_reg_rtx (mode); 612890075Sobrien if (TARGET_ARCH32) 612990075Sobrien emit_insn (gen_addsi3 (tem, result, const1_rtx)); 613090075Sobrien else 613190075Sobrien emit_insn (gen_adddi3 (tem, result, const1_rtx)); 613290075Sobrien tem2 = gen_reg_rtx (mode); 613390075Sobrien if (TARGET_ARCH32) 613490075Sobrien emit_insn (gen_andsi3 (tem2, tem, const2_rtx)); 613590075Sobrien else 613690075Sobrien emit_insn (gen_anddi3 (tem2, tem, const2_rtx)); 613790075Sobrien emit_cmp_insn (tem2, const0_rtx, comparison == UNEQ ? EQ : NE, 613890075Sobrien NULL_RTX, mode, 0); 613990075Sobrien break; 614090075Sobrien } 614190075Sobrien} 614290075Sobrien 614396263Sobrien/* Generate an unsigned DImode to FP conversion. This is the same code 614496263Sobrien optabs would emit if we didn't have TFmode patterns. */ 614596263Sobrien 614696263Sobrienvoid 6147169689Skansparc_emit_floatunsdi (rtx *operands, enum machine_mode mode) 614896263Sobrien{ 614996263Sobrien rtx neglab, donelab, i0, i1, f0, in, out; 615096263Sobrien 615196263Sobrien out = operands[0]; 615296263Sobrien in = force_reg (DImode, operands[1]); 615396263Sobrien neglab = gen_label_rtx (); 615496263Sobrien donelab = gen_label_rtx (); 615596263Sobrien i0 = gen_reg_rtx (DImode); 615696263Sobrien i1 = gen_reg_rtx (DImode); 615796263Sobrien f0 = gen_reg_rtx (mode); 615896263Sobrien 615996263Sobrien emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab); 616096263Sobrien 616196263Sobrien emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in))); 616296263Sobrien emit_jump_insn (gen_jump (donelab)); 616396263Sobrien emit_barrier (); 616496263Sobrien 616596263Sobrien emit_label (neglab); 616696263Sobrien 616796263Sobrien emit_insn (gen_lshrdi3 (i0, in, const1_rtx)); 616896263Sobrien emit_insn (gen_anddi3 (i1, in, const1_rtx)); 616996263Sobrien emit_insn (gen_iordi3 (i0, i0, i1)); 617096263Sobrien emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0))); 617196263Sobrien emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0))); 617296263Sobrien 617396263Sobrien emit_label (donelab); 617496263Sobrien} 617596263Sobrien 6176169689Skan/* Generate an FP to unsigned DImode conversion. This is the same code 6177169689Skan optabs would emit if we didn't have TFmode patterns. */ 6178169689Skan 6179169689Skanvoid 6180169689Skansparc_emit_fixunsdi (rtx *operands, enum machine_mode mode) 6181169689Skan{ 6182169689Skan rtx neglab, donelab, i0, i1, f0, in, out, limit; 6183169689Skan 6184169689Skan out = operands[0]; 6185169689Skan in = force_reg (mode, operands[1]); 6186169689Skan neglab = gen_label_rtx (); 6187169689Skan donelab = gen_label_rtx (); 6188169689Skan i0 = gen_reg_rtx (DImode); 6189169689Skan i1 = gen_reg_rtx (DImode); 6190169689Skan limit = gen_reg_rtx (mode); 6191169689Skan f0 = gen_reg_rtx (mode); 6192169689Skan 6193169689Skan emit_move_insn (limit, 6194169689Skan CONST_DOUBLE_FROM_REAL_VALUE ( 6195169689Skan REAL_VALUE_ATOF ("9223372036854775808.0", mode), mode)); 6196169689Skan emit_cmp_and_jump_insns (in, limit, GE, NULL_RTX, mode, 0, neglab); 6197169689Skan 6198169689Skan emit_insn (gen_rtx_SET (VOIDmode, 6199169689Skan out, 6200169689Skan gen_rtx_FIX (DImode, gen_rtx_FIX (mode, in)))); 6201169689Skan emit_jump_insn (gen_jump (donelab)); 6202169689Skan emit_barrier (); 6203169689Skan 6204169689Skan emit_label (neglab); 6205169689Skan 6206169689Skan emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_MINUS (mode, in, limit))); 6207169689Skan emit_insn (gen_rtx_SET (VOIDmode, 6208169689Skan i0, 6209169689Skan gen_rtx_FIX (DImode, gen_rtx_FIX (mode, f0)))); 6210169689Skan emit_insn (gen_movdi (i1, const1_rtx)); 6211169689Skan emit_insn (gen_ashldi3 (i1, i1, GEN_INT (63))); 6212169689Skan emit_insn (gen_xordi3 (out, i0, i1)); 6213169689Skan 6214169689Skan emit_label (donelab); 6215169689Skan} 6216169689Skan 621750397Sobrien/* Return the string to output a conditional branch to LABEL, testing 621850397Sobrien register REG. LABEL is the operand number of the label; REG is the 621950397Sobrien operand number of the reg. OP is the conditional expression. The mode 622050397Sobrien of REG says what kind of comparison we made. 622150397Sobrien 6222132718Skan DEST is the destination insn (i.e. the label), INSN is the source. 6223132718Skan 6224117395Skan REVERSED is nonzero if we should reverse the sense of the comparison. 622550397Sobrien 6226169689Skan ANNUL is nonzero if we should generate an annulling branch. */ 622750397Sobrien 6228169689Skanconst char * 6229132718Skanoutput_v9branch (rtx op, rtx dest, int reg, int label, int reversed, 6230169689Skan int annul, rtx insn) 623150397Sobrien{ 6232169689Skan static char string[64]; 623350397Sobrien enum rtx_code code = GET_CODE (op); 623450397Sobrien enum machine_mode mode = GET_MODE (XEXP (op, 0)); 623552284Sobrien rtx note; 623696263Sobrien int far; 623796263Sobrien char *p; 623850397Sobrien 623996263Sobrien /* branch on register are limited to +-128KB. If it is too far away, 624096263Sobrien change 624196263Sobrien 624296263Sobrien brnz,pt %g1, .LC30 624396263Sobrien 624496263Sobrien to 624596263Sobrien 624696263Sobrien brz,pn %g1, .+12 6247169689Skan nop 624896263Sobrien ba,pt %xcc, .LC30 624996263Sobrien 625096263Sobrien and 625196263Sobrien 625296263Sobrien brgez,a,pn %o1, .LC29 625396263Sobrien 625496263Sobrien to 625596263Sobrien 625696263Sobrien brlz,pt %o1, .+16 6257169689Skan nop 625896263Sobrien ba,pt %xcc, .LC29 */ 625996263Sobrien 626096263Sobrien far = get_attr_length (insn) >= 3; 626196263Sobrien 626250397Sobrien /* If not floating-point or if EQ or NE, we can just reverse the code. */ 626396263Sobrien if (reversed ^ far) 626496263Sobrien code = reverse_condition (code); 626550397Sobrien 626650397Sobrien /* Only 64 bit versions of these instructions exist. */ 6267169689Skan gcc_assert (mode == DImode); 626850397Sobrien 626950397Sobrien /* Start by writing the branch condition. */ 627050397Sobrien 627150397Sobrien switch (code) 627250397Sobrien { 627350397Sobrien case NE: 627450397Sobrien strcpy (string, "brnz"); 627550397Sobrien break; 627650397Sobrien 627750397Sobrien case EQ: 627850397Sobrien strcpy (string, "brz"); 627950397Sobrien break; 628050397Sobrien 628150397Sobrien case GE: 628250397Sobrien strcpy (string, "brgez"); 628350397Sobrien break; 628450397Sobrien 628550397Sobrien case LT: 628650397Sobrien strcpy (string, "brlz"); 628750397Sobrien break; 628850397Sobrien 628950397Sobrien case LE: 629050397Sobrien strcpy (string, "brlez"); 629150397Sobrien break; 629250397Sobrien 629350397Sobrien case GT: 629450397Sobrien strcpy (string, "brgz"); 629550397Sobrien break; 629650397Sobrien 629750397Sobrien default: 6298169689Skan gcc_unreachable (); 629950397Sobrien } 630050397Sobrien 630196263Sobrien p = strchr (string, '\0'); 630296263Sobrien 630350397Sobrien /* Now add the annulling, reg, label, and nop. */ 630496263Sobrien if (annul && ! far) 630552284Sobrien { 630696263Sobrien strcpy (p, ",a"); 630796263Sobrien p += 2; 630852284Sobrien } 630950397Sobrien 631096263Sobrien if (insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX))) 631152284Sobrien { 631296263Sobrien strcpy (p, 631396263Sobrien ((INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ^ far) 631496263Sobrien ? ",pt" : ",pn"); 631596263Sobrien p += 3; 631652284Sobrien } 631750397Sobrien 631896263Sobrien *p = p < string + 8 ? '\t' : ' '; 631996263Sobrien p++; 632096263Sobrien *p++ = '%'; 632196263Sobrien *p++ = '0' + reg; 632296263Sobrien *p++ = ','; 632396263Sobrien *p++ = ' '; 632496263Sobrien if (far) 632596263Sobrien { 632696263Sobrien int veryfar = 1, delta; 632750397Sobrien 632896263Sobrien if (INSN_ADDRESSES_SET_P ()) 632996263Sobrien { 633096263Sobrien delta = (INSN_ADDRESSES (INSN_UID (dest)) 633196263Sobrien - INSN_ADDRESSES (INSN_UID (insn))); 633296263Sobrien /* Leave some instructions for "slop". */ 633396263Sobrien if (delta >= -260000 && delta < 260000) 633496263Sobrien veryfar = 0; 633596263Sobrien } 633696263Sobrien 6337169689Skan strcpy (p, ".+12\n\t nop\n\t"); 6338169689Skan /* Skip the next insn if requested or 6339169689Skan if we know that it will be a nop. */ 6340169689Skan if (annul || ! final_sequence) 634196263Sobrien p[3] = '6'; 6342169689Skan p += 12; 634396263Sobrien if (veryfar) 634496263Sobrien { 634596263Sobrien strcpy (p, "b\t"); 634696263Sobrien p += 2; 634796263Sobrien } 634896263Sobrien else 634996263Sobrien { 635096263Sobrien strcpy (p, "ba,pt\t%%xcc, "); 635196263Sobrien p += 13; 635296263Sobrien } 635396263Sobrien } 635496263Sobrien *p++ = '%'; 635596263Sobrien *p++ = 'l'; 635696263Sobrien *p++ = '0' + label; 6357169689Skan *p++ = '%'; 6358169689Skan *p++ = '#'; 635996263Sobrien *p = '\0'; 636096263Sobrien 636150397Sobrien return string; 636250397Sobrien} 636350397Sobrien 636490075Sobrien/* Return 1, if any of the registers of the instruction are %l[0-7] or %o[0-7]. 636590075Sobrien Such instructions cannot be used in the delay slot of return insn on v9. 636690075Sobrien If TEST is 0, also rename all %i[0-7] registers to their %o[0-7] counterparts. 636790075Sobrien */ 636850397Sobrien 636990075Sobrienstatic int 6370132718Skanepilogue_renumber (register rtx *where, int test) 637150397Sobrien{ 637290075Sobrien register const char *fmt; 637390075Sobrien register int i; 637490075Sobrien register enum rtx_code code; 637550397Sobrien 637690075Sobrien if (*where == 0) 637790075Sobrien return 0; 637890075Sobrien 637990075Sobrien code = GET_CODE (*where); 638090075Sobrien 638150397Sobrien switch (code) 638250397Sobrien { 638350397Sobrien case REG: 638490075Sobrien if (REGNO (*where) >= 8 && REGNO (*where) < 24) /* oX or lX */ 638590075Sobrien return 1; 638690075Sobrien if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32) 6387169689Skan *where = gen_rtx_REG (GET_MODE (*where), OUTGOING_REGNO (REGNO(*where))); 638890075Sobrien case SCRATCH: 638990075Sobrien case CC0: 639090075Sobrien case PC: 639150397Sobrien case CONST_INT: 639250397Sobrien case CONST_DOUBLE: 639390075Sobrien return 0; 639450397Sobrien 639590075Sobrien /* Do not replace the frame pointer with the stack pointer because 639690075Sobrien it can cause the delayed instruction to load below the stack. 639790075Sobrien This occurs when instructions like: 639890075Sobrien 639990075Sobrien (set (reg/i:SI 24 %i0) 640090075Sobrien (mem/f:SI (plus:SI (reg/f:SI 30 %fp) 640190075Sobrien (const_int -20 [0xffffffec])) 0)) 640290075Sobrien 640390075Sobrien are in the return delayed slot. */ 640450397Sobrien case PLUS: 640590075Sobrien if (GET_CODE (XEXP (*where, 0)) == REG 640696263Sobrien && REGNO (XEXP (*where, 0)) == HARD_FRAME_POINTER_REGNUM 640790075Sobrien && (GET_CODE (XEXP (*where, 1)) != CONST_INT 640890075Sobrien || INTVAL (XEXP (*where, 1)) < SPARC_STACK_BIAS)) 640990075Sobrien return 1; 641090075Sobrien break; 641150397Sobrien 641290075Sobrien case MEM: 641390075Sobrien if (SPARC_STACK_BIAS 641490075Sobrien && GET_CODE (XEXP (*where, 0)) == REG 641596263Sobrien && REGNO (XEXP (*where, 0)) == HARD_FRAME_POINTER_REGNUM) 641690075Sobrien return 1; 641790075Sobrien break; 641890075Sobrien 641950397Sobrien default: 642090075Sobrien break; 642150397Sobrien } 642290075Sobrien 642390075Sobrien fmt = GET_RTX_FORMAT (code); 642490075Sobrien 642590075Sobrien for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 642690075Sobrien { 642790075Sobrien if (fmt[i] == 'E') 642890075Sobrien { 642990075Sobrien register int j; 643090075Sobrien for (j = XVECLEN (*where, i) - 1; j >= 0; j--) 643190075Sobrien if (epilogue_renumber (&(XVECEXP (*where, i, j)), test)) 643290075Sobrien return 1; 643390075Sobrien } 643490075Sobrien else if (fmt[i] == 'e' 643590075Sobrien && epilogue_renumber (&(XEXP (*where, i)), test)) 643690075Sobrien return 1; 643790075Sobrien } 643890075Sobrien return 0; 643950397Sobrien} 644050397Sobrien 644150397Sobrien/* Leaf functions and non-leaf functions have different needs. */ 644250397Sobrien 644390075Sobrienstatic const int 644450397Sobrienreg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER; 644550397Sobrien 644690075Sobrienstatic const int 644750397Sobrienreg_nonleaf_alloc_order[] = REG_ALLOC_ORDER; 644850397Sobrien 644990075Sobrienstatic const int *const reg_alloc_orders[] = { 645050397Sobrien reg_leaf_alloc_order, 645150397Sobrien reg_nonleaf_alloc_order}; 645250397Sobrien 645350397Sobrienvoid 6454132718Skanorder_regs_for_local_alloc (void) 645550397Sobrien{ 645650397Sobrien static int last_order_nonleaf = 1; 645750397Sobrien 645850397Sobrien if (regs_ever_live[15] != last_order_nonleaf) 645950397Sobrien { 646050397Sobrien last_order_nonleaf = !last_order_nonleaf; 646190075Sobrien memcpy ((char *) reg_alloc_order, 646290075Sobrien (const char *) reg_alloc_orders[last_order_nonleaf], 646390075Sobrien FIRST_PSEUDO_REGISTER * sizeof (int)); 646450397Sobrien } 646550397Sobrien} 646650397Sobrien 646752284Sobrien/* Return 1 if REG and MEM are legitimate enough to allow the various 646852284Sobrien mem<-->reg splits to be run. */ 646952284Sobrien 647052284Sobrienint 6471132718Skansparc_splitdi_legitimate (rtx reg, rtx mem) 647252284Sobrien{ 647352284Sobrien /* Punt if we are here by mistake. */ 6474169689Skan gcc_assert (reload_completed); 647552284Sobrien 647652284Sobrien /* We must have an offsettable memory reference. */ 647752284Sobrien if (! offsettable_memref_p (mem)) 647852284Sobrien return 0; 647952284Sobrien 648052284Sobrien /* If we have legitimate args for ldd/std, we do not want 648152284Sobrien the split to happen. */ 648252284Sobrien if ((REGNO (reg) % 2) == 0 648352284Sobrien && mem_min_alignment (mem, 8)) 648452284Sobrien return 0; 648552284Sobrien 648652284Sobrien /* Success. */ 648752284Sobrien return 1; 648852284Sobrien} 648952284Sobrien 649052284Sobrien/* Return 1 if x and y are some kind of REG and they refer to 6491132718Skan different hard registers. This test is guaranteed to be 649252284Sobrien run after reload. */ 649352284Sobrien 649452284Sobrienint 6495132718Skansparc_absnegfloat_split_legitimate (rtx x, rtx y) 649652284Sobrien{ 649752284Sobrien if (GET_CODE (x) != REG) 649852284Sobrien return 0; 649952284Sobrien if (GET_CODE (y) != REG) 650052284Sobrien return 0; 650152284Sobrien if (REGNO (x) == REGNO (y)) 650252284Sobrien return 0; 650352284Sobrien return 1; 650452284Sobrien} 650552284Sobrien 650650397Sobrien/* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1. 650750397Sobrien This makes them candidates for using ldd and std insns. 650850397Sobrien 650950397Sobrien Note reg1 and reg2 *must* be hard registers. */ 651050397Sobrien 651150397Sobrienint 6512132718Skanregisters_ok_for_ldd_peep (rtx reg1, rtx reg2) 651350397Sobrien{ 651450397Sobrien /* We might have been passed a SUBREG. */ 651550397Sobrien if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG) 651650397Sobrien return 0; 651750397Sobrien 651850397Sobrien if (REGNO (reg1) % 2 != 0) 651950397Sobrien return 0; 652050397Sobrien 652150397Sobrien /* Integer ldd is deprecated in SPARC V9 */ 652250397Sobrien if (TARGET_V9 && REGNO (reg1) < 32) 652350397Sobrien return 0; 652450397Sobrien 652550397Sobrien return (REGNO (reg1) == REGNO (reg2) - 1); 652650397Sobrien} 652750397Sobrien 652890075Sobrien/* Return 1 if the addresses in mem1 and mem2 are suitable for use in 652990075Sobrien an ldd or std insn. 653090075Sobrien 653190075Sobrien This can only happen when addr1 and addr2, the addresses in mem1 653290075Sobrien and mem2, are consecutive memory locations (addr1 + 4 == addr2). 653390075Sobrien addr1 must also be aligned on a 64-bit boundary. 653450397Sobrien 653590075Sobrien Also iff dependent_reg_rtx is not null it should not be used to 653690075Sobrien compute the address for mem1, i.e. we cannot optimize a sequence 653790075Sobrien like: 653890075Sobrien ld [%o0], %o0 653990075Sobrien ld [%o0 + 4], %o1 654090075Sobrien to 654190075Sobrien ldd [%o0], %o0 654296263Sobrien nor: 654396263Sobrien ld [%g3 + 4], %g3 654496263Sobrien ld [%g3], %g2 654596263Sobrien to 654696263Sobrien ldd [%g3], %g2 654796263Sobrien 654896263Sobrien But, note that the transformation from: 654996263Sobrien ld [%g2 + 4], %g3 655096263Sobrien ld [%g2], %g2 655196263Sobrien to 655296263Sobrien ldd [%g2], %g2 655396263Sobrien is perfectly fine. Thus, the peephole2 patterns always pass us 655496263Sobrien the destination register of the first load, never the second one. 655596263Sobrien 655690075Sobrien For stores we don't have a similar problem, so dependent_reg_rtx is 655790075Sobrien NULL_RTX. */ 655850397Sobrien 655950397Sobrienint 6560132718Skanmems_ok_for_ldd_peep (rtx mem1, rtx mem2, rtx dependent_reg_rtx) 656150397Sobrien{ 656290075Sobrien rtx addr1, addr2; 656390075Sobrien unsigned int reg1; 6564132718Skan HOST_WIDE_INT offset1; 656550397Sobrien 656690075Sobrien /* The mems cannot be volatile. */ 656790075Sobrien if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2)) 656890075Sobrien return 0; 656990075Sobrien 657090075Sobrien /* MEM1 should be aligned on a 64-bit boundary. */ 657190075Sobrien if (MEM_ALIGN (mem1) < 64) 657290075Sobrien return 0; 657390075Sobrien 657490075Sobrien addr1 = XEXP (mem1, 0); 657590075Sobrien addr2 = XEXP (mem2, 0); 657690075Sobrien 657750397Sobrien /* Extract a register number and offset (if used) from the first addr. */ 657850397Sobrien if (GET_CODE (addr1) == PLUS) 657950397Sobrien { 658050397Sobrien /* If not a REG, return zero. */ 658150397Sobrien if (GET_CODE (XEXP (addr1, 0)) != REG) 658250397Sobrien return 0; 658350397Sobrien else 658450397Sobrien { 658550397Sobrien reg1 = REGNO (XEXP (addr1, 0)); 658650397Sobrien /* The offset must be constant! */ 658750397Sobrien if (GET_CODE (XEXP (addr1, 1)) != CONST_INT) 658850397Sobrien return 0; 658950397Sobrien offset1 = INTVAL (XEXP (addr1, 1)); 659050397Sobrien } 659150397Sobrien } 659250397Sobrien else if (GET_CODE (addr1) != REG) 659350397Sobrien return 0; 659450397Sobrien else 659550397Sobrien { 659650397Sobrien reg1 = REGNO (addr1); 659750397Sobrien /* This was a simple (mem (reg)) expression. Offset is 0. */ 659850397Sobrien offset1 = 0; 659950397Sobrien } 660050397Sobrien 660150397Sobrien /* Make sure the second address is a (mem (plus (reg) (const_int). */ 660250397Sobrien if (GET_CODE (addr2) != PLUS) 660350397Sobrien return 0; 660450397Sobrien 660550397Sobrien if (GET_CODE (XEXP (addr2, 0)) != REG 660650397Sobrien || GET_CODE (XEXP (addr2, 1)) != CONST_INT) 660750397Sobrien return 0; 660850397Sobrien 660990075Sobrien if (reg1 != REGNO (XEXP (addr2, 0))) 661050397Sobrien return 0; 661150397Sobrien 661290075Sobrien if (dependent_reg_rtx != NULL_RTX && reg1 == REGNO (dependent_reg_rtx)) 661350397Sobrien return 0; 661490075Sobrien 661550397Sobrien /* The first offset must be evenly divisible by 8 to ensure the 661650397Sobrien address is 64 bit aligned. */ 661750397Sobrien if (offset1 % 8 != 0) 661850397Sobrien return 0; 661950397Sobrien 662050397Sobrien /* The offset for the second addr must be 4 more than the first addr. */ 662150397Sobrien if (INTVAL (XEXP (addr2, 1)) != offset1 + 4) 662250397Sobrien return 0; 662350397Sobrien 662450397Sobrien /* All the tests passed. addr1 and addr2 are valid for ldd and std 662550397Sobrien instructions. */ 662650397Sobrien return 1; 662750397Sobrien} 662850397Sobrien 662950397Sobrien/* Return 1 if reg is a pseudo, or is the first register in 663050397Sobrien a hard register pair. This makes it a candidate for use in 663150397Sobrien ldd and std insns. */ 663250397Sobrien 663350397Sobrienint 6634132718Skanregister_ok_for_ldd (rtx reg) 663550397Sobrien{ 663650397Sobrien /* We might have been passed a SUBREG. */ 663750397Sobrien if (GET_CODE (reg) != REG) 663850397Sobrien return 0; 663950397Sobrien 664050397Sobrien if (REGNO (reg) < FIRST_PSEUDO_REGISTER) 664150397Sobrien return (REGNO (reg) % 2 == 0); 664250397Sobrien else 664350397Sobrien return 1; 664450397Sobrien} 664550397Sobrien 664650397Sobrien/* Print operand X (an rtx) in assembler syntax to file FILE. 664750397Sobrien CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. 664850397Sobrien For `%' followed by punctuation, CODE is the punctuation and X is null. */ 664950397Sobrien 665050397Sobrienvoid 6651132718Skanprint_operand (FILE *file, rtx x, int code) 665250397Sobrien{ 665350397Sobrien switch (code) 665450397Sobrien { 665550397Sobrien case '#': 6656169689Skan /* Output an insn in a delay slot. */ 6657169689Skan if (final_sequence) 6658169689Skan sparc_indent_opcode = 1; 6659169689Skan else 666052284Sobrien fputs ("\n\t nop", file); 666150397Sobrien return; 666250397Sobrien case '*': 666350397Sobrien /* Output an annul flag if there's nothing for the delay slot and we 6664169689Skan are optimizing. This is always used with '(' below. 6665169689Skan Sun OS 4.1.1 dbx can't handle an annulled unconditional branch; 6666169689Skan this is a dbx bug. So, we only do this when optimizing. 6667169689Skan On UltraSPARC, a branch in a delay slot causes a pipeline flush. 666850397Sobrien Always emit a nop in case the next instruction is a branch. */ 6669169689Skan if (! final_sequence && (optimize && (int)sparc_cpu < PROCESSOR_V9)) 667050397Sobrien fputs (",a", file); 667150397Sobrien return; 667250397Sobrien case '(': 667350397Sobrien /* Output a 'nop' if there's nothing for the delay slot and we are 667450397Sobrien not optimizing. This is always used with '*' above. */ 6675169689Skan if (! final_sequence && ! (optimize && (int)sparc_cpu < PROCESSOR_V9)) 667652284Sobrien fputs ("\n\t nop", file); 6677169689Skan else if (final_sequence) 6678169689Skan sparc_indent_opcode = 1; 667950397Sobrien return; 6680169689Skan case ')': 6681169689Skan /* Output the right displacement from the saved PC on function return. 6682169689Skan The caller may have placed an "unimp" insn immediately after the call 6683169689Skan so we have to account for it. This insn is used in the 32-bit ABI 6684169689Skan when calling a function that returns a non zero-sized structure. The 6685169689Skan 64-bit ABI doesn't have it. Be careful to have this test be the same 6686169689Skan as that used on the call. The exception here is that when 6687169689Skan sparc_std_struct_return is enabled, the psABI is followed exactly 6688169689Skan and the adjustment is made by the code in sparc_struct_value_rtx. 6689169689Skan The call emitted is the same when sparc_std_struct_return is 6690169689Skan present. */ 6691169689Skan if (! TARGET_ARCH64 6692169689Skan && current_function_returns_struct 6693169689Skan && ! sparc_std_struct_return 6694169689Skan && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl))) 6695169689Skan == INTEGER_CST) 6696169689Skan && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl)))) 6697169689Skan fputs ("12", file); 6698169689Skan else 6699169689Skan fputc ('8', file); 6700169689Skan return; 670150397Sobrien case '_': 670250397Sobrien /* Output the Embedded Medium/Anywhere code model base register. */ 670350397Sobrien fputs (EMBMEDANY_BASE_REG, file); 670450397Sobrien return; 6705132718Skan case '&': 6706132718Skan /* Print some local dynamic TLS name. */ 6707132718Skan assemble_name (file, get_some_local_dynamic_name ()); 6708132718Skan return; 6709169689Skan 671050397Sobrien case 'Y': 671150397Sobrien /* Adjust the operand to take into account a RESTORE operation. */ 671250397Sobrien if (GET_CODE (x) == CONST_INT) 671350397Sobrien break; 671450397Sobrien else if (GET_CODE (x) != REG) 671590075Sobrien output_operand_lossage ("invalid %%Y operand"); 671650397Sobrien else if (REGNO (x) < 8) 671750397Sobrien fputs (reg_names[REGNO (x)], file); 671850397Sobrien else if (REGNO (x) >= 24 && REGNO (x) < 32) 671950397Sobrien fputs (reg_names[REGNO (x)-16], file); 672050397Sobrien else 672190075Sobrien output_operand_lossage ("invalid %%Y operand"); 672250397Sobrien return; 672350397Sobrien case 'L': 672450397Sobrien /* Print out the low order register name of a register pair. */ 672550397Sobrien if (WORDS_BIG_ENDIAN) 672650397Sobrien fputs (reg_names[REGNO (x)+1], file); 672750397Sobrien else 672850397Sobrien fputs (reg_names[REGNO (x)], file); 672950397Sobrien return; 673050397Sobrien case 'H': 673150397Sobrien /* Print out the high order register name of a register pair. */ 673250397Sobrien if (WORDS_BIG_ENDIAN) 673350397Sobrien fputs (reg_names[REGNO (x)], file); 673450397Sobrien else 673550397Sobrien fputs (reg_names[REGNO (x)+1], file); 673650397Sobrien return; 673750397Sobrien case 'R': 673850397Sobrien /* Print out the second register name of a register pair or quad. 673950397Sobrien I.e., R (%o0) => %o1. */ 674050397Sobrien fputs (reg_names[REGNO (x)+1], file); 674150397Sobrien return; 674250397Sobrien case 'S': 674350397Sobrien /* Print out the third register name of a register quad. 674450397Sobrien I.e., S (%o0) => %o2. */ 674550397Sobrien fputs (reg_names[REGNO (x)+2], file); 674650397Sobrien return; 674750397Sobrien case 'T': 674850397Sobrien /* Print out the fourth register name of a register quad. 674950397Sobrien I.e., T (%o0) => %o3. */ 675050397Sobrien fputs (reg_names[REGNO (x)+3], file); 675150397Sobrien return; 675250397Sobrien case 'x': 675350397Sobrien /* Print a condition code register. */ 675450397Sobrien if (REGNO (x) == SPARC_ICC_REG) 675550397Sobrien { 675650397Sobrien /* We don't handle CC[X]_NOOVmode because they're not supposed 675750397Sobrien to occur here. */ 675850397Sobrien if (GET_MODE (x) == CCmode) 675950397Sobrien fputs ("%icc", file); 676050397Sobrien else if (GET_MODE (x) == CCXmode) 676150397Sobrien fputs ("%xcc", file); 676250397Sobrien else 6763169689Skan gcc_unreachable (); 676450397Sobrien } 676550397Sobrien else 676650397Sobrien /* %fccN register */ 676750397Sobrien fputs (reg_names[REGNO (x)], file); 676850397Sobrien return; 676950397Sobrien case 'm': 677050397Sobrien /* Print the operand's address only. */ 677150397Sobrien output_address (XEXP (x, 0)); 677250397Sobrien return; 677350397Sobrien case 'r': 677450397Sobrien /* In this case we need a register. Use %g0 if the 677550397Sobrien operand is const0_rtx. */ 677650397Sobrien if (x == const0_rtx 677750397Sobrien || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x)))) 677850397Sobrien { 677950397Sobrien fputs ("%g0", file); 678050397Sobrien return; 678150397Sobrien } 678250397Sobrien else 678350397Sobrien break; 678450397Sobrien 678550397Sobrien case 'A': 678650397Sobrien switch (GET_CODE (x)) 678750397Sobrien { 678850397Sobrien case IOR: fputs ("or", file); break; 678950397Sobrien case AND: fputs ("and", file); break; 679050397Sobrien case XOR: fputs ("xor", file); break; 679190075Sobrien default: output_operand_lossage ("invalid %%A operand"); 679250397Sobrien } 679350397Sobrien return; 679450397Sobrien 679550397Sobrien case 'B': 679650397Sobrien switch (GET_CODE (x)) 679750397Sobrien { 679850397Sobrien case IOR: fputs ("orn", file); break; 679950397Sobrien case AND: fputs ("andn", file); break; 680050397Sobrien case XOR: fputs ("xnor", file); break; 680190075Sobrien default: output_operand_lossage ("invalid %%B operand"); 680250397Sobrien } 680350397Sobrien return; 680450397Sobrien 680550397Sobrien /* These are used by the conditional move instructions. */ 680650397Sobrien case 'c' : 680750397Sobrien case 'C': 680850397Sobrien { 680990075Sobrien enum rtx_code rc = GET_CODE (x); 681090075Sobrien 681190075Sobrien if (code == 'c') 681290075Sobrien { 681390075Sobrien enum machine_mode mode = GET_MODE (XEXP (x, 0)); 681490075Sobrien if (mode == CCFPmode || mode == CCFPEmode) 681590075Sobrien rc = reverse_condition_maybe_unordered (GET_CODE (x)); 681690075Sobrien else 681790075Sobrien rc = reverse_condition (GET_CODE (x)); 681890075Sobrien } 681950397Sobrien switch (rc) 682050397Sobrien { 682150397Sobrien case NE: fputs ("ne", file); break; 682250397Sobrien case EQ: fputs ("e", file); break; 682350397Sobrien case GE: fputs ("ge", file); break; 682450397Sobrien case GT: fputs ("g", file); break; 682550397Sobrien case LE: fputs ("le", file); break; 682650397Sobrien case LT: fputs ("l", file); break; 682750397Sobrien case GEU: fputs ("geu", file); break; 682850397Sobrien case GTU: fputs ("gu", file); break; 682950397Sobrien case LEU: fputs ("leu", file); break; 683050397Sobrien case LTU: fputs ("lu", file); break; 683190075Sobrien case LTGT: fputs ("lg", file); break; 683290075Sobrien case UNORDERED: fputs ("u", file); break; 683390075Sobrien case ORDERED: fputs ("o", file); break; 683490075Sobrien case UNLT: fputs ("ul", file); break; 683590075Sobrien case UNLE: fputs ("ule", file); break; 683690075Sobrien case UNGT: fputs ("ug", file); break; 683790075Sobrien case UNGE: fputs ("uge", file); break; 683890075Sobrien case UNEQ: fputs ("ue", file); break; 683950397Sobrien default: output_operand_lossage (code == 'c' 684090075Sobrien ? "invalid %%c operand" 684190075Sobrien : "invalid %%C operand"); 684250397Sobrien } 684350397Sobrien return; 684450397Sobrien } 684550397Sobrien 684650397Sobrien /* These are used by the movr instruction pattern. */ 684750397Sobrien case 'd': 684850397Sobrien case 'D': 684950397Sobrien { 685050397Sobrien enum rtx_code rc = (code == 'd' 685150397Sobrien ? reverse_condition (GET_CODE (x)) 685250397Sobrien : GET_CODE (x)); 685350397Sobrien switch (rc) 685450397Sobrien { 685550397Sobrien case NE: fputs ("ne", file); break; 685650397Sobrien case EQ: fputs ("e", file); break; 685750397Sobrien case GE: fputs ("gez", file); break; 685850397Sobrien case LT: fputs ("lz", file); break; 685950397Sobrien case LE: fputs ("lez", file); break; 686050397Sobrien case GT: fputs ("gz", file); break; 686150397Sobrien default: output_operand_lossage (code == 'd' 686290075Sobrien ? "invalid %%d operand" 686390075Sobrien : "invalid %%D operand"); 686450397Sobrien } 686550397Sobrien return; 686650397Sobrien } 686750397Sobrien 686850397Sobrien case 'b': 686950397Sobrien { 687050397Sobrien /* Print a sign-extended character. */ 687196263Sobrien int i = trunc_int_for_mode (INTVAL (x), QImode); 687250397Sobrien fprintf (file, "%d", i); 687350397Sobrien return; 687450397Sobrien } 687550397Sobrien 687650397Sobrien case 'f': 687750397Sobrien /* Operand must be a MEM; write its address. */ 687850397Sobrien if (GET_CODE (x) != MEM) 687990075Sobrien output_operand_lossage ("invalid %%f operand"); 688050397Sobrien output_address (XEXP (x, 0)); 688150397Sobrien return; 688250397Sobrien 6883117395Skan case 's': 6884117395Skan { 6885117395Skan /* Print a sign-extended 32-bit value. */ 6886117395Skan HOST_WIDE_INT i; 6887117395Skan if (GET_CODE(x) == CONST_INT) 6888117395Skan i = INTVAL (x); 6889117395Skan else if (GET_CODE(x) == CONST_DOUBLE) 6890117395Skan i = CONST_DOUBLE_LOW (x); 6891117395Skan else 6892117395Skan { 6893117395Skan output_operand_lossage ("invalid %%s operand"); 6894117395Skan return; 6895117395Skan } 6896117395Skan i = trunc_int_for_mode (i, SImode); 6897117395Skan fprintf (file, HOST_WIDE_INT_PRINT_DEC, i); 6898117395Skan return; 6899117395Skan } 6900117395Skan 690150397Sobrien case 0: 690250397Sobrien /* Do nothing special. */ 690350397Sobrien break; 690450397Sobrien 690550397Sobrien default: 690650397Sobrien /* Undocumented flag. */ 690750397Sobrien output_operand_lossage ("invalid operand output code"); 690850397Sobrien } 690950397Sobrien 691050397Sobrien if (GET_CODE (x) == REG) 691150397Sobrien fputs (reg_names[REGNO (x)], file); 691250397Sobrien else if (GET_CODE (x) == MEM) 691350397Sobrien { 691450397Sobrien fputc ('[', file); 691550397Sobrien /* Poor Sun assembler doesn't understand absolute addressing. */ 691690075Sobrien if (CONSTANT_P (XEXP (x, 0))) 691750397Sobrien fputs ("%g0+", file); 691850397Sobrien output_address (XEXP (x, 0)); 691950397Sobrien fputc (']', file); 692050397Sobrien } 692150397Sobrien else if (GET_CODE (x) == HIGH) 692250397Sobrien { 692350397Sobrien fputs ("%hi(", file); 692450397Sobrien output_addr_const (file, XEXP (x, 0)); 692550397Sobrien fputc (')', file); 692650397Sobrien } 692750397Sobrien else if (GET_CODE (x) == LO_SUM) 692850397Sobrien { 692950397Sobrien print_operand (file, XEXP (x, 0), 0); 693052284Sobrien if (TARGET_CM_MEDMID) 693152284Sobrien fputs ("+%l44(", file); 693252284Sobrien else 693352284Sobrien fputs ("+%lo(", file); 693450397Sobrien output_addr_const (file, XEXP (x, 1)); 693550397Sobrien fputc (')', file); 693650397Sobrien } 693750397Sobrien else if (GET_CODE (x) == CONST_DOUBLE 693850397Sobrien && (GET_MODE (x) == VOIDmode 693950397Sobrien || GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)) 694050397Sobrien { 694150397Sobrien if (CONST_DOUBLE_HIGH (x) == 0) 694290075Sobrien fprintf (file, "%u", (unsigned int) CONST_DOUBLE_LOW (x)); 694350397Sobrien else if (CONST_DOUBLE_HIGH (x) == -1 694450397Sobrien && CONST_DOUBLE_LOW (x) < 0) 694590075Sobrien fprintf (file, "%d", (int) CONST_DOUBLE_LOW (x)); 694650397Sobrien else 694750397Sobrien output_operand_lossage ("long long constant not a valid immediate operand"); 694850397Sobrien } 694950397Sobrien else if (GET_CODE (x) == CONST_DOUBLE) 695050397Sobrien output_operand_lossage ("floating point constant not a valid immediate operand"); 695150397Sobrien else { output_addr_const (file, x); } 695250397Sobrien} 695350397Sobrien 695490075Sobrien/* Target hook for assembling integer objects. The sparc version has 695590075Sobrien special handling for aligned DI-mode objects. */ 695650397Sobrien 695790075Sobrienstatic bool 6958132718Skansparc_assemble_integer (rtx x, unsigned int size, int aligned_p) 695950397Sobrien{ 696090075Sobrien /* ??? We only output .xword's for symbols and only then in environments 696190075Sobrien where the assembler can handle them. */ 696290075Sobrien if (aligned_p && size == 8 696390075Sobrien && (GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE)) 696450397Sobrien { 696590075Sobrien if (TARGET_V9) 696650397Sobrien { 696790075Sobrien assemble_integer_with_op ("\t.xword\t", x); 696890075Sobrien return true; 696950397Sobrien } 697050397Sobrien else 697150397Sobrien { 697290075Sobrien assemble_aligned_integer (4, const0_rtx); 697390075Sobrien assemble_aligned_integer (4, x); 697490075Sobrien return true; 697550397Sobrien } 697650397Sobrien } 697790075Sobrien return default_assemble_integer (x, size, aligned_p); 697850397Sobrien} 697950397Sobrien 698050397Sobrien/* Return the value of a code used in the .proc pseudo-op that says 698150397Sobrien what kind of result this function returns. For non-C types, we pick 698250397Sobrien the closest C type. */ 698350397Sobrien 698450397Sobrien#ifndef SHORT_TYPE_SIZE 698550397Sobrien#define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2) 698650397Sobrien#endif 698750397Sobrien 698850397Sobrien#ifndef INT_TYPE_SIZE 698950397Sobrien#define INT_TYPE_SIZE BITS_PER_WORD 699050397Sobrien#endif 699150397Sobrien 699250397Sobrien#ifndef LONG_TYPE_SIZE 699350397Sobrien#define LONG_TYPE_SIZE BITS_PER_WORD 699450397Sobrien#endif 699550397Sobrien 699650397Sobrien#ifndef LONG_LONG_TYPE_SIZE 699750397Sobrien#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2) 699850397Sobrien#endif 699950397Sobrien 700050397Sobrien#ifndef FLOAT_TYPE_SIZE 700150397Sobrien#define FLOAT_TYPE_SIZE BITS_PER_WORD 700250397Sobrien#endif 700350397Sobrien 700450397Sobrien#ifndef DOUBLE_TYPE_SIZE 700550397Sobrien#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) 700650397Sobrien#endif 700750397Sobrien 700850397Sobrien#ifndef LONG_DOUBLE_TYPE_SIZE 700950397Sobrien#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) 701050397Sobrien#endif 701150397Sobrien 701250397Sobrienunsigned long 7013132718Skansparc_type_code (register tree type) 701450397Sobrien{ 701550397Sobrien register unsigned long qualifiers = 0; 701650397Sobrien register unsigned shift; 701750397Sobrien 701850397Sobrien /* Only the first 30 bits of the qualifier are valid. We must refrain from 701950397Sobrien setting more, since some assemblers will give an error for this. Also, 702050397Sobrien we must be careful to avoid shifts of 32 bits or more to avoid getting 702150397Sobrien unpredictable results. */ 702250397Sobrien 702350397Sobrien for (shift = 6; shift < 30; shift += 2, type = TREE_TYPE (type)) 702450397Sobrien { 702550397Sobrien switch (TREE_CODE (type)) 702650397Sobrien { 702750397Sobrien case ERROR_MARK: 702850397Sobrien return qualifiers; 702950397Sobrien 703050397Sobrien case ARRAY_TYPE: 703150397Sobrien qualifiers |= (3 << shift); 703250397Sobrien break; 703350397Sobrien 703450397Sobrien case FUNCTION_TYPE: 703550397Sobrien case METHOD_TYPE: 703650397Sobrien qualifiers |= (2 << shift); 703750397Sobrien break; 703850397Sobrien 703950397Sobrien case POINTER_TYPE: 704050397Sobrien case REFERENCE_TYPE: 704150397Sobrien case OFFSET_TYPE: 704250397Sobrien qualifiers |= (1 << shift); 704350397Sobrien break; 704450397Sobrien 704550397Sobrien case RECORD_TYPE: 704650397Sobrien return (qualifiers | 8); 704750397Sobrien 704850397Sobrien case UNION_TYPE: 704950397Sobrien case QUAL_UNION_TYPE: 705050397Sobrien return (qualifiers | 9); 705150397Sobrien 705250397Sobrien case ENUMERAL_TYPE: 705350397Sobrien return (qualifiers | 10); 705450397Sobrien 705550397Sobrien case VOID_TYPE: 705650397Sobrien return (qualifiers | 16); 705750397Sobrien 705850397Sobrien case INTEGER_TYPE: 705950397Sobrien /* If this is a range type, consider it to be the underlying 706050397Sobrien type. */ 706150397Sobrien if (TREE_TYPE (type) != 0) 706250397Sobrien break; 706350397Sobrien 706450397Sobrien /* Carefully distinguish all the standard types of C, 706550397Sobrien without messing up if the language is not C. We do this by 7066169689Skan testing TYPE_PRECISION and TYPE_UNSIGNED. The old code used to 706750397Sobrien look at both the names and the above fields, but that's redundant. 706850397Sobrien Any type whose size is between two C types will be considered 706950397Sobrien to be the wider of the two types. Also, we do not have a 707050397Sobrien special code to use for "long long", so anything wider than 707150397Sobrien long is treated the same. Note that we can't distinguish 707250397Sobrien between "int" and "long" in this code if they are the same 707350397Sobrien size, but that's fine, since neither can the assembler. */ 707450397Sobrien 707550397Sobrien if (TYPE_PRECISION (type) <= CHAR_TYPE_SIZE) 7076169689Skan return (qualifiers | (TYPE_UNSIGNED (type) ? 12 : 2)); 707750397Sobrien 707850397Sobrien else if (TYPE_PRECISION (type) <= SHORT_TYPE_SIZE) 7079169689Skan return (qualifiers | (TYPE_UNSIGNED (type) ? 13 : 3)); 708050397Sobrien 708150397Sobrien else if (TYPE_PRECISION (type) <= INT_TYPE_SIZE) 7082169689Skan return (qualifiers | (TYPE_UNSIGNED (type) ? 14 : 4)); 708350397Sobrien 708450397Sobrien else 7085169689Skan return (qualifiers | (TYPE_UNSIGNED (type) ? 15 : 5)); 708650397Sobrien 708750397Sobrien case REAL_TYPE: 708850397Sobrien /* If this is a range type, consider it to be the underlying 708950397Sobrien type. */ 709050397Sobrien if (TREE_TYPE (type) != 0) 709150397Sobrien break; 709250397Sobrien 709350397Sobrien /* Carefully distinguish all the standard types of C, 709450397Sobrien without messing up if the language is not C. */ 709550397Sobrien 709650397Sobrien if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE) 709750397Sobrien return (qualifiers | 6); 709850397Sobrien 709950397Sobrien else 710050397Sobrien return (qualifiers | 7); 710150397Sobrien 710250397Sobrien case COMPLEX_TYPE: /* GNU Fortran COMPLEX type. */ 710350397Sobrien /* ??? We need to distinguish between double and float complex types, 710450397Sobrien but I don't know how yet because I can't reach this code from 710550397Sobrien existing front-ends. */ 710650397Sobrien return (qualifiers | 7); /* Who knows? */ 710750397Sobrien 7108169689Skan case VECTOR_TYPE: 7109169689Skan case BOOLEAN_TYPE: /* Boolean truth value type. */ 711050397Sobrien case LANG_TYPE: /* ? */ 711150397Sobrien return qualifiers; 711250397Sobrien 711350397Sobrien default: 7114169689Skan gcc_unreachable (); /* Not a type! */ 711550397Sobrien } 711650397Sobrien } 711750397Sobrien 711850397Sobrien return qualifiers; 711950397Sobrien} 712050397Sobrien 712150397Sobrien/* Nested function support. */ 712250397Sobrien 712350397Sobrien/* Emit RTL insns to initialize the variable parts of a trampoline. 712450397Sobrien FNADDR is an RTX for the address of the function's pure code. 712550397Sobrien CXT is an RTX for the static chain value for the function. 712650397Sobrien 712750397Sobrien This takes 16 insns: 2 shifts & 2 ands (to split up addresses), 4 sethi 712850397Sobrien (to load in opcodes), 4 iors (to merge address and opcodes), and 4 writes 712950397Sobrien (to store insns). This is a bit excessive. Perhaps a different 713050397Sobrien mechanism would be better here. 713150397Sobrien 713250397Sobrien Emit enough FLUSH insns to synchronize the data and instruction caches. */ 713350397Sobrien 713450397Sobrienvoid 7135132718Skansparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt) 713650397Sobrien{ 7137132718Skan /* SPARC 32-bit trampoline: 713850397Sobrien 713952284Sobrien sethi %hi(fn), %g1 714052284Sobrien sethi %hi(static), %g2 714152284Sobrien jmp %g1+%lo(fn) 714252284Sobrien or %g2, %lo(static), %g2 714350397Sobrien 714450397Sobrien SETHI i,r = 00rr rrr1 00ii iiii iiii iiii iiii iiii 714550397Sobrien JMPL r+i,d = 10dd ddd1 1100 0rrr rr1i iiii iiii iiii 714650397Sobrien */ 714750397Sobrien 714896263Sobrien emit_move_insn 714996263Sobrien (gen_rtx_MEM (SImode, plus_constant (tramp, 0)), 715096263Sobrien expand_binop (SImode, ior_optab, 715196263Sobrien expand_shift (RSHIFT_EXPR, SImode, fnaddr, 715296263Sobrien size_int (10), 0, 1), 715396263Sobrien GEN_INT (trunc_int_for_mode (0x03000000, SImode)), 715496263Sobrien NULL_RTX, 1, OPTAB_DIRECT)); 715550397Sobrien 715696263Sobrien emit_move_insn 715796263Sobrien (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), 715896263Sobrien expand_binop (SImode, ior_optab, 715996263Sobrien expand_shift (RSHIFT_EXPR, SImode, cxt, 716096263Sobrien size_int (10), 0, 1), 716196263Sobrien GEN_INT (trunc_int_for_mode (0x05000000, SImode)), 716296263Sobrien NULL_RTX, 1, OPTAB_DIRECT)); 716350397Sobrien 716496263Sobrien emit_move_insn 716596263Sobrien (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), 716696263Sobrien expand_binop (SImode, ior_optab, 716796263Sobrien expand_and (SImode, fnaddr, GEN_INT (0x3ff), NULL_RTX), 716896263Sobrien GEN_INT (trunc_int_for_mode (0x81c06000, SImode)), 716996263Sobrien NULL_RTX, 1, OPTAB_DIRECT)); 717050397Sobrien 717196263Sobrien emit_move_insn 717296263Sobrien (gen_rtx_MEM (SImode, plus_constant (tramp, 12)), 717396263Sobrien expand_binop (SImode, ior_optab, 717496263Sobrien expand_and (SImode, cxt, GEN_INT (0x3ff), NULL_RTX), 717596263Sobrien GEN_INT (trunc_int_for_mode (0x8410a000, SImode)), 717696263Sobrien NULL_RTX, 1, OPTAB_DIRECT)); 717750397Sobrien 717850397Sobrien /* On UltraSPARC a flush flushes an entire cache line. The trampoline is 717950397Sobrien aligned on a 16 byte boundary so one flush clears it all. */ 718096263Sobrien emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp)))); 7181117395Skan if (sparc_cpu != PROCESSOR_ULTRASPARC 7182169689Skan && sparc_cpu != PROCESSOR_ULTRASPARC3 7183169689Skan && sparc_cpu != PROCESSOR_NIAGARA) 718450397Sobrien emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, 718550397Sobrien plus_constant (tramp, 8))))); 7186132718Skan 7187132718Skan /* Call __enable_execute_stack after writing onto the stack to make sure 7188132718Skan the stack address is accessible. */ 7189132718Skan#ifdef ENABLE_EXECUTE_STACK 7190169689Skan emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"), 7191132718Skan LCT_NORMAL, VOIDmode, 1, tramp, Pmode); 7192132718Skan#endif 7193132718Skan 719450397Sobrien} 719550397Sobrien 7196132718Skan/* The 64-bit version is simpler because it makes more sense to load the 719750397Sobrien values as "immediate" data out of the trampoline. It's also easier since 719850397Sobrien we can read the PC without clobbering a register. */ 719950397Sobrien 720050397Sobrienvoid 7201132718Skansparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt) 720250397Sobrien{ 7203132718Skan /* SPARC 64-bit trampoline: 720452284Sobrien 720552284Sobrien rd %pc, %g1 720652284Sobrien ldx [%g1+24], %g5 720752284Sobrien jmp %g5 720852284Sobrien ldx [%g1+16], %g5 720950397Sobrien +16 bytes data 721050397Sobrien */ 721150397Sobrien 721250397Sobrien emit_move_insn (gen_rtx_MEM (SImode, tramp), 721396263Sobrien GEN_INT (trunc_int_for_mode (0x83414000, SImode))); 721450397Sobrien emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), 721596263Sobrien GEN_INT (trunc_int_for_mode (0xca586018, SImode))); 721650397Sobrien emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), 721796263Sobrien GEN_INT (trunc_int_for_mode (0x81c14000, SImode))); 721850397Sobrien emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)), 721996263Sobrien GEN_INT (trunc_int_for_mode (0xca586010, SImode))); 722050397Sobrien emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt); 722152284Sobrien emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr); 722290075Sobrien emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp)))); 722352284Sobrien 7224117395Skan if (sparc_cpu != PROCESSOR_ULTRASPARC 7225169689Skan && sparc_cpu != PROCESSOR_ULTRASPARC3 7226169689Skan && sparc_cpu != PROCESSOR_NIAGARA) 722790075Sobrien emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8))))); 7228132718Skan 7229132718Skan /* Call __enable_execute_stack after writing onto the stack to make sure 7230132718Skan the stack address is accessible. */ 7231132718Skan#ifdef ENABLE_EXECUTE_STACK 7232169689Skan emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"), 7233132718Skan LCT_NORMAL, VOIDmode, 1, tramp, Pmode); 7234132718Skan#endif 723550397Sobrien} 723650397Sobrien 723750397Sobrien/* Adjust the cost of a scheduling dependency. Return the new cost of 723850397Sobrien a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ 723950397Sobrien 724052284Sobrienstatic int 7241132718Skansupersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) 724250397Sobrien{ 724350397Sobrien enum attr_type insn_type; 724450397Sobrien 724550397Sobrien if (! recog_memoized (insn)) 724650397Sobrien return 0; 724750397Sobrien 724850397Sobrien insn_type = get_attr_type (insn); 724950397Sobrien 725050397Sobrien if (REG_NOTE_KIND (link) == 0) 725150397Sobrien { 725250397Sobrien /* Data dependency; DEP_INSN writes a register that INSN reads some 725350397Sobrien cycles later. */ 725450397Sobrien 725550397Sobrien /* if a load, then the dependence must be on the memory address; 725652284Sobrien add an extra "cycle". Note that the cost could be two cycles 725752284Sobrien if the reg was written late in an instruction group; we ca not tell 725850397Sobrien here. */ 725950397Sobrien if (insn_type == TYPE_LOAD || insn_type == TYPE_FPLOAD) 726050397Sobrien return cost + 3; 726150397Sobrien 726250397Sobrien /* Get the delay only if the address of the store is the dependence. */ 726350397Sobrien if (insn_type == TYPE_STORE || insn_type == TYPE_FPSTORE) 726450397Sobrien { 726550397Sobrien rtx pat = PATTERN(insn); 726650397Sobrien rtx dep_pat = PATTERN (dep_insn); 726750397Sobrien 726850397Sobrien if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET) 726952284Sobrien return cost; /* This should not happen! */ 727050397Sobrien 727150397Sobrien /* The dependency between the two instructions was on the data that 727250397Sobrien is being stored. Assume that this implies that the address of the 727350397Sobrien store is not dependent. */ 727450397Sobrien if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat))) 727550397Sobrien return cost; 727650397Sobrien 727750397Sobrien return cost + 3; /* An approximation. */ 727850397Sobrien } 727950397Sobrien 728050397Sobrien /* A shift instruction cannot receive its data from an instruction 728150397Sobrien in the same cycle; add a one cycle penalty. */ 728250397Sobrien if (insn_type == TYPE_SHIFT) 728350397Sobrien return cost + 3; /* Split before cascade into shift. */ 728450397Sobrien } 728550397Sobrien else 728650397Sobrien { 728750397Sobrien /* Anti- or output- dependency; DEP_INSN reads/writes a register that 728850397Sobrien INSN writes some cycles later. */ 728950397Sobrien 729050397Sobrien /* These are only significant for the fpu unit; writing a fp reg before 729150397Sobrien the fpu has finished with it stalls the processor. */ 729250397Sobrien 729350397Sobrien /* Reusing an integer register causes no problems. */ 729450397Sobrien if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT) 729550397Sobrien return 0; 729650397Sobrien } 729750397Sobrien 729850397Sobrien return cost; 729950397Sobrien} 730050397Sobrien 730152284Sobrienstatic int 7302132718Skanhypersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) 730352284Sobrien{ 730452284Sobrien enum attr_type insn_type, dep_type; 730552284Sobrien rtx pat = PATTERN(insn); 730652284Sobrien rtx dep_pat = PATTERN (dep_insn); 730752284Sobrien 730852284Sobrien if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0) 730952284Sobrien return cost; 731052284Sobrien 731152284Sobrien insn_type = get_attr_type (insn); 731252284Sobrien dep_type = get_attr_type (dep_insn); 731352284Sobrien 731452284Sobrien switch (REG_NOTE_KIND (link)) 731552284Sobrien { 731652284Sobrien case 0: 731752284Sobrien /* Data dependency; DEP_INSN writes a register that INSN reads some 731852284Sobrien cycles later. */ 731952284Sobrien 732052284Sobrien switch (insn_type) 732152284Sobrien { 732252284Sobrien case TYPE_STORE: 732352284Sobrien case TYPE_FPSTORE: 732490075Sobrien /* Get the delay iff the address of the store is the dependence. */ 732552284Sobrien if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET) 732652284Sobrien return cost; 732752284Sobrien 732852284Sobrien if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat))) 732952284Sobrien return cost; 733052284Sobrien return cost + 3; 733152284Sobrien 733252284Sobrien case TYPE_LOAD: 733352284Sobrien case TYPE_SLOAD: 733452284Sobrien case TYPE_FPLOAD: 733552284Sobrien /* If a load, then the dependence must be on the memory address. If 733652284Sobrien the addresses aren't equal, then it might be a false dependency */ 733752284Sobrien if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE) 733852284Sobrien { 733952284Sobrien if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET 734052284Sobrien || GET_CODE (SET_DEST (dep_pat)) != MEM 734152284Sobrien || GET_CODE (SET_SRC (pat)) != MEM 734252284Sobrien || ! rtx_equal_p (XEXP (SET_DEST (dep_pat), 0), 734352284Sobrien XEXP (SET_SRC (pat), 0))) 734452284Sobrien return cost + 2; 734552284Sobrien 734652284Sobrien return cost + 8; 734752284Sobrien } 734852284Sobrien break; 734952284Sobrien 735052284Sobrien case TYPE_BRANCH: 735152284Sobrien /* Compare to branch latency is 0. There is no benefit from 735252284Sobrien separating compare and branch. */ 735352284Sobrien if (dep_type == TYPE_COMPARE) 735452284Sobrien return 0; 735552284Sobrien /* Floating point compare to branch latency is less than 735652284Sobrien compare to conditional move. */ 735752284Sobrien if (dep_type == TYPE_FPCMP) 735852284Sobrien return cost - 1; 735952284Sobrien break; 736052284Sobrien default: 736152284Sobrien break; 736252284Sobrien } 736352284Sobrien break; 736452284Sobrien 736552284Sobrien case REG_DEP_ANTI: 736690075Sobrien /* Anti-dependencies only penalize the fpu unit. */ 736752284Sobrien if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT) 736852284Sobrien return 0; 736952284Sobrien break; 737052284Sobrien 737152284Sobrien default: 737252284Sobrien break; 737352284Sobrien } 737452284Sobrien 737552284Sobrien return cost; 737652284Sobrien} 737752284Sobrien 737852284Sobrienstatic int 7379132718Skansparc_adjust_cost(rtx insn, rtx link, rtx dep, int cost) 738052284Sobrien{ 738152284Sobrien switch (sparc_cpu) 738252284Sobrien { 738352284Sobrien case PROCESSOR_SUPERSPARC: 738452284Sobrien cost = supersparc_adjust_cost (insn, link, dep, cost); 738552284Sobrien break; 738652284Sobrien case PROCESSOR_HYPERSPARC: 738752284Sobrien case PROCESSOR_SPARCLITE86X: 738852284Sobrien cost = hypersparc_adjust_cost (insn, link, dep, cost); 738952284Sobrien break; 739052284Sobrien default: 739152284Sobrien break; 739252284Sobrien } 739352284Sobrien return cost; 739452284Sobrien} 739552284Sobrien 739652284Sobrienstatic void 7397132718Skansparc_sched_init (FILE *dump ATTRIBUTE_UNUSED, 7398132718Skan int sched_verbose ATTRIBUTE_UNUSED, 7399132718Skan int max_ready ATTRIBUTE_UNUSED) 740090075Sobrien{ 740190075Sobrien} 740290075Sobrien 740390075Sobrienstatic int 7404132718Skansparc_use_sched_lookahead (void) 740590075Sobrien{ 7406169689Skan if (sparc_cpu == PROCESSOR_NIAGARA) 7407169689Skan return 0; 7408117395Skan if (sparc_cpu == PROCESSOR_ULTRASPARC 7409117395Skan || sparc_cpu == PROCESSOR_ULTRASPARC3) 7410117395Skan return 4; 7411117395Skan if ((1 << sparc_cpu) & 7412117395Skan ((1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) | 7413117395Skan (1 << PROCESSOR_SPARCLITE86X))) 7414117395Skan return 3; 7415117395Skan return 0; 741690075Sobrien} 741790075Sobrien 741890075Sobrienstatic int 7419132718Skansparc_issue_rate (void) 742050397Sobrien{ 742150397Sobrien switch (sparc_cpu) 742250397Sobrien { 7423169689Skan case PROCESSOR_NIAGARA: 7424117395Skan default: 7425117395Skan return 1; 7426117395Skan case PROCESSOR_V9: 742750397Sobrien /* Assume V9 processors are capable of at least dual-issue. */ 742850397Sobrien return 2; 7429117395Skan case PROCESSOR_SUPERSPARC: 7430117395Skan return 3; 743152284Sobrien case PROCESSOR_HYPERSPARC: 743252284Sobrien case PROCESSOR_SPARCLITE86X: 743352284Sobrien return 2; 7434117395Skan case PROCESSOR_ULTRASPARC: 7435117395Skan case PROCESSOR_ULTRASPARC3: 7436117395Skan return 4; 743750397Sobrien } 743850397Sobrien} 743950397Sobrien 744050397Sobrienstatic int 7441132718Skanset_extends (rtx insn) 744250397Sobrien{ 744350397Sobrien register rtx pat = PATTERN (insn); 744450397Sobrien 744550397Sobrien switch (GET_CODE (SET_SRC (pat))) 744650397Sobrien { 744790075Sobrien /* Load and some shift instructions zero extend. */ 744850397Sobrien case MEM: 744950397Sobrien case ZERO_EXTEND: 745050397Sobrien /* sethi clears the high bits */ 745150397Sobrien case HIGH: 745250397Sobrien /* LO_SUM is used with sethi. sethi cleared the high 745350397Sobrien bits and the values used with lo_sum are positive */ 745450397Sobrien case LO_SUM: 745550397Sobrien /* Store flag stores 0 or 1 */ 745650397Sobrien case LT: case LTU: 745750397Sobrien case GT: case GTU: 745850397Sobrien case LE: case LEU: 745950397Sobrien case GE: case GEU: 746050397Sobrien case EQ: 746150397Sobrien case NE: 746250397Sobrien return 1; 746350397Sobrien case AND: 746450397Sobrien { 746590075Sobrien rtx op0 = XEXP (SET_SRC (pat), 0); 746650397Sobrien rtx op1 = XEXP (SET_SRC (pat), 1); 746750397Sobrien if (GET_CODE (op1) == CONST_INT) 746850397Sobrien return INTVAL (op1) >= 0; 746990075Sobrien if (GET_CODE (op0) != REG) 747090075Sobrien return 0; 747190075Sobrien if (sparc_check_64 (op0, insn) == 1) 747250397Sobrien return 1; 747390075Sobrien return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1); 747450397Sobrien } 747590075Sobrien case IOR: 747690075Sobrien case XOR: 747790075Sobrien { 747890075Sobrien rtx op0 = XEXP (SET_SRC (pat), 0); 747990075Sobrien rtx op1 = XEXP (SET_SRC (pat), 1); 748090075Sobrien if (GET_CODE (op0) != REG || sparc_check_64 (op0, insn) <= 0) 748190075Sobrien return 0; 748290075Sobrien if (GET_CODE (op1) == CONST_INT) 748390075Sobrien return INTVAL (op1) >= 0; 748490075Sobrien return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1); 748590075Sobrien } 748650397Sobrien case LSHIFTRT: 748750397Sobrien return GET_MODE (SET_SRC (pat)) == SImode; 748890075Sobrien /* Positive integers leave the high bits zero. */ 748950397Sobrien case CONST_DOUBLE: 749090075Sobrien return ! (CONST_DOUBLE_LOW (SET_SRC (pat)) & 0x80000000); 749150397Sobrien case CONST_INT: 749290075Sobrien return ! (INTVAL (SET_SRC (pat)) & 0x80000000); 749350397Sobrien case ASHIFTRT: 749450397Sobrien case SIGN_EXTEND: 749550397Sobrien return - (GET_MODE (SET_SRC (pat)) == SImode); 749690075Sobrien case REG: 749790075Sobrien return sparc_check_64 (SET_SRC (pat), insn); 749850397Sobrien default: 749950397Sobrien return 0; 750050397Sobrien } 750150397Sobrien} 750250397Sobrien 750390075Sobrien/* We _ought_ to have only one kind per function, but... */ 7504117395Skanstatic GTY(()) rtx sparc_addr_diff_list; 7505117395Skanstatic GTY(()) rtx sparc_addr_list; 750652284Sobrien 750752284Sobrienvoid 7508132718Skansparc_defer_case_vector (rtx lab, rtx vec, int diff) 750952284Sobrien{ 751052284Sobrien vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec); 751152284Sobrien if (diff) 751252284Sobrien sparc_addr_diff_list 751352284Sobrien = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_diff_list); 751452284Sobrien else 751552284Sobrien sparc_addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_list); 751652284Sobrien} 751752284Sobrien 751852284Sobrienstatic void 7519132718Skansparc_output_addr_vec (rtx vec) 752052284Sobrien{ 752152284Sobrien rtx lab = XEXP (vec, 0), body = XEXP (vec, 1); 752252284Sobrien int idx, vlen = XVECLEN (body, 0); 752352284Sobrien 752452284Sobrien#ifdef ASM_OUTPUT_ADDR_VEC_START 752552284Sobrien ASM_OUTPUT_ADDR_VEC_START (asm_out_file); 752652284Sobrien#endif 752752284Sobrien 752852284Sobrien#ifdef ASM_OUTPUT_CASE_LABEL 752952284Sobrien ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab), 753052284Sobrien NEXT_INSN (lab)); 753152284Sobrien#else 7532132718Skan (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (lab)); 753352284Sobrien#endif 753452284Sobrien 753552284Sobrien for (idx = 0; idx < vlen; idx++) 753652284Sobrien { 753752284Sobrien ASM_OUTPUT_ADDR_VEC_ELT 753852284Sobrien (asm_out_file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); 753952284Sobrien } 754052284Sobrien 754152284Sobrien#ifdef ASM_OUTPUT_ADDR_VEC_END 754252284Sobrien ASM_OUTPUT_ADDR_VEC_END (asm_out_file); 754352284Sobrien#endif 754452284Sobrien} 754552284Sobrien 754652284Sobrienstatic void 7547132718Skansparc_output_addr_diff_vec (rtx vec) 754852284Sobrien{ 754952284Sobrien rtx lab = XEXP (vec, 0), body = XEXP (vec, 1); 755052284Sobrien rtx base = XEXP (XEXP (body, 0), 0); 755152284Sobrien int idx, vlen = XVECLEN (body, 1); 755252284Sobrien 755352284Sobrien#ifdef ASM_OUTPUT_ADDR_VEC_START 755452284Sobrien ASM_OUTPUT_ADDR_VEC_START (asm_out_file); 755552284Sobrien#endif 755652284Sobrien 755752284Sobrien#ifdef ASM_OUTPUT_CASE_LABEL 755852284Sobrien ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab), 755952284Sobrien NEXT_INSN (lab)); 756052284Sobrien#else 7561132718Skan (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (lab)); 756252284Sobrien#endif 756352284Sobrien 756452284Sobrien for (idx = 0; idx < vlen; idx++) 756552284Sobrien { 756652284Sobrien ASM_OUTPUT_ADDR_DIFF_ELT 756752284Sobrien (asm_out_file, 756852284Sobrien body, 756952284Sobrien CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), 757052284Sobrien CODE_LABEL_NUMBER (base)); 757152284Sobrien } 757252284Sobrien 757352284Sobrien#ifdef ASM_OUTPUT_ADDR_VEC_END 757452284Sobrien ASM_OUTPUT_ADDR_VEC_END (asm_out_file); 757552284Sobrien#endif 757652284Sobrien} 757752284Sobrien 757852284Sobrienstatic void 7579132718Skansparc_output_deferred_case_vectors (void) 758052284Sobrien{ 758152284Sobrien rtx t; 758252284Sobrien int align; 758352284Sobrien 758452284Sobrien if (sparc_addr_list == NULL_RTX 758552284Sobrien && sparc_addr_diff_list == NULL_RTX) 758652284Sobrien return; 758752284Sobrien 758852284Sobrien /* Align to cache line in the function's code section. */ 7589169689Skan switch_to_section (current_function_section ()); 759052284Sobrien 759152284Sobrien align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); 759252284Sobrien if (align > 0) 759352284Sobrien ASM_OUTPUT_ALIGN (asm_out_file, align); 759452284Sobrien 759552284Sobrien for (t = sparc_addr_list; t ; t = XEXP (t, 1)) 759652284Sobrien sparc_output_addr_vec (XEXP (t, 0)); 759752284Sobrien for (t = sparc_addr_diff_list; t ; t = XEXP (t, 1)) 759852284Sobrien sparc_output_addr_diff_vec (XEXP (t, 0)); 759952284Sobrien 760052284Sobrien sparc_addr_list = sparc_addr_diff_list = NULL_RTX; 760152284Sobrien} 760252284Sobrien 760350397Sobrien/* Return 0 if the high 32 bits of X (the low word of X, if DImode) are 760450397Sobrien unknown. Return 1 if the high bits are zero, -1 if the register is 760550397Sobrien sign extended. */ 760650397Sobrienint 7607132718Skansparc_check_64 (rtx x, rtx insn) 760850397Sobrien{ 760950397Sobrien /* If a register is set only once it is safe to ignore insns this 761050397Sobrien code does not know how to handle. The loop will either recognize 761150397Sobrien the single set and return the correct value or fail to recognize 761250397Sobrien it and return 0. */ 761350397Sobrien int set_once = 0; 761490075Sobrien rtx y = x; 761550397Sobrien 7616169689Skan gcc_assert (GET_CODE (x) == REG); 761790075Sobrien 761890075Sobrien if (GET_MODE (x) == DImode) 761990075Sobrien y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN); 762090075Sobrien 762190075Sobrien if (flag_expensive_optimizations 762290075Sobrien && REG_N_SETS (REGNO (y)) == 1) 762350397Sobrien set_once = 1; 762450397Sobrien 762550397Sobrien if (insn == 0) 762650397Sobrien { 762750397Sobrien if (set_once) 762850397Sobrien insn = get_last_insn_anywhere (); 762950397Sobrien else 763050397Sobrien return 0; 763150397Sobrien } 763250397Sobrien 763350397Sobrien while ((insn = PREV_INSN (insn))) 763450397Sobrien { 763550397Sobrien switch (GET_CODE (insn)) 763650397Sobrien { 763750397Sobrien case JUMP_INSN: 763850397Sobrien case NOTE: 763950397Sobrien break; 764050397Sobrien case CODE_LABEL: 764150397Sobrien case CALL_INSN: 764250397Sobrien default: 764350397Sobrien if (! set_once) 764450397Sobrien return 0; 764550397Sobrien break; 764650397Sobrien case INSN: 764750397Sobrien { 764850397Sobrien rtx pat = PATTERN (insn); 764950397Sobrien if (GET_CODE (pat) != SET) 765050397Sobrien return 0; 765150397Sobrien if (rtx_equal_p (x, SET_DEST (pat))) 765290075Sobrien return set_extends (insn); 765390075Sobrien if (y && rtx_equal_p (y, SET_DEST (pat))) 765490075Sobrien return set_extends (insn); 765590075Sobrien if (reg_overlap_mentioned_p (SET_DEST (pat), y)) 765650397Sobrien return 0; 765750397Sobrien } 765850397Sobrien } 765950397Sobrien } 766050397Sobrien return 0; 766150397Sobrien} 766250397Sobrien 7663117395Skan/* Returns assembly code to perform a DImode shift using 7664117395Skan a 64-bit global or out register on SPARC-V8+. */ 7665169689Skanconst char * 7666169689Skanoutput_v8plus_shift (rtx *operands, rtx insn, const char *opcode) 766750397Sobrien{ 766850397Sobrien static char asm_code[60]; 766950397Sobrien 7670117395Skan /* The scratch register is only required when the destination 7671117395Skan register is not a 64-bit global or out register. */ 7672117395Skan if (which_alternative != 2) 767350397Sobrien operands[3] = operands[0]; 7674117395Skan 7675122180Skan /* We can only shift by constants <= 63. */ 7676122180Skan if (GET_CODE (operands[2]) == CONST_INT) 7677122180Skan operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f); 7678122180Skan 767950397Sobrien if (GET_CODE (operands[1]) == CONST_INT) 768050397Sobrien { 768190075Sobrien output_asm_insn ("mov\t%1, %3", operands); 768250397Sobrien } 768350397Sobrien else 768450397Sobrien { 768590075Sobrien output_asm_insn ("sllx\t%H1, 32, %3", operands); 768650397Sobrien if (sparc_check_64 (operands[1], insn) <= 0) 768790075Sobrien output_asm_insn ("srl\t%L1, 0, %L1", operands); 768890075Sobrien output_asm_insn ("or\t%L1, %3, %3", operands); 768950397Sobrien } 769050397Sobrien 769150397Sobrien strcpy(asm_code, opcode); 7692117395Skan 769350397Sobrien if (which_alternative != 2) 769490075Sobrien return strcat (asm_code, "\t%0, %2, %L0\n\tsrlx\t%L0, 32, %H0"); 769550397Sobrien else 769690075Sobrien return strcat (asm_code, "\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0"); 769750397Sobrien} 769852284Sobrien 769996263Sobrien/* Output rtl to increment the profiler label LABELNO 770096263Sobrien for profiling a function entry. */ 770152284Sobrien 770252284Sobrienvoid 7703132718Skansparc_profile_hook (int labelno) 770452284Sobrien{ 770552284Sobrien char buf[32]; 770696263Sobrien rtx lab, fun; 770796263Sobrien 770852284Sobrien ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno); 770996263Sobrien lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); 771096263Sobrien fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_FUNCTION); 771152284Sobrien 771296263Sobrien emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode); 771352284Sobrien} 771496263Sobrien 771590075Sobrien#ifdef OBJECT_FORMAT_ELF 771690075Sobrienstatic void 7717169689Skansparc_elf_asm_named_section (const char *name, unsigned int flags, 7718169689Skan tree decl) 771952284Sobrien{ 772090075Sobrien if (flags & SECTION_MERGE) 772152284Sobrien { 772290075Sobrien /* entsize cannot be expressed in this section attributes 772390075Sobrien encoding style. */ 7724169689Skan default_elf_asm_named_section (name, flags, decl); 772590075Sobrien return; 772652284Sobrien } 772752284Sobrien 772890075Sobrien fprintf (asm_out_file, "\t.section\t\"%s\"", name); 772952284Sobrien 773090075Sobrien if (!(flags & SECTION_DEBUG)) 773190075Sobrien fputs (",#alloc", asm_out_file); 773290075Sobrien if (flags & SECTION_WRITE) 773390075Sobrien fputs (",#write", asm_out_file); 7734132718Skan if (flags & SECTION_TLS) 7735132718Skan fputs (",#tls", asm_out_file); 773690075Sobrien if (flags & SECTION_CODE) 773790075Sobrien fputs (",#execinstr", asm_out_file); 773852284Sobrien 773990075Sobrien /* ??? Handle SECTION_BSS. */ 774052284Sobrien 774190075Sobrien fputc ('\n', asm_out_file); 774252284Sobrien} 774390075Sobrien#endif /* OBJECT_FORMAT_ELF */ 774496263Sobrien 7745169689Skan/* We do not allow indirect calls to be optimized into sibling calls. 7746169689Skan 7747169689Skan We cannot use sibling calls when delayed branches are disabled 7748169689Skan because they will likely require the call delay slot to be filled. 7749169689Skan 7750169689Skan Also, on SPARC 32-bit we cannot emit a sibling call when the 7751132718Skan current function returns a structure. This is because the "unimp 7752132718Skan after call" convention would cause the callee to return to the 7753132718Skan wrong place. The generic code already disallows cases where the 7754132718Skan function being called returns a structure. 7755132718Skan 7756132718Skan It may seem strange how this last case could occur. Usually there 7757132718Skan is code after the call which jumps to epilogue code which dumps the 7758132718Skan return value into the struct return area. That ought to invalidate 7759169689Skan the sibling call right? Well, in the C++ case we can end up passing 7760132718Skan the pointer to the struct return area to a constructor (which returns 7761132718Skan void) and then nothing else happens. Such a sibling call would look 7762132718Skan valid without the added check here. */ 7763132718Skanstatic bool 7764132718Skansparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) 7765132718Skan{ 7766132718Skan return (decl 7767169689Skan && flag_delayed_branch 7768132718Skan && (TARGET_ARCH64 || ! current_function_returns_struct)); 7769132718Skan} 7770132718Skan 7771132718Skan/* libfunc renaming. */ 7772132718Skan#include "config/gofast.h" 7773132718Skan 7774132718Skanstatic void 7775132718Skansparc_init_libfuncs (void) 7776132718Skan{ 7777132718Skan if (TARGET_ARCH32) 7778132718Skan { 7779132718Skan /* Use the subroutines that Sun's library provides for integer 7780132718Skan multiply and divide. The `*' prevents an underscore from 7781132718Skan being prepended by the compiler. .umul is a little faster 7782169689Skan than .mul. */ 7783132718Skan set_optab_libfunc (smul_optab, SImode, "*.umul"); 7784132718Skan set_optab_libfunc (sdiv_optab, SImode, "*.div"); 7785132718Skan set_optab_libfunc (udiv_optab, SImode, "*.udiv"); 7786132718Skan set_optab_libfunc (smod_optab, SImode, "*.rem"); 7787132718Skan set_optab_libfunc (umod_optab, SImode, "*.urem"); 7788132718Skan 7789132718Skan /* TFmode arithmetic. These names are part of the SPARC 32bit ABI. */ 7790132718Skan set_optab_libfunc (add_optab, TFmode, "_Q_add"); 7791132718Skan set_optab_libfunc (sub_optab, TFmode, "_Q_sub"); 7792132718Skan set_optab_libfunc (neg_optab, TFmode, "_Q_neg"); 7793132718Skan set_optab_libfunc (smul_optab, TFmode, "_Q_mul"); 7794132718Skan set_optab_libfunc (sdiv_optab, TFmode, "_Q_div"); 7795132718Skan 7796132718Skan /* We can define the TFmode sqrt optab only if TARGET_FPU. This 7797132718Skan is because with soft-float, the SFmode and DFmode sqrt 7798132718Skan instructions will be absent, and the compiler will notice and 7799132718Skan try to use the TFmode sqrt instruction for calls to the 7800132718Skan builtin function sqrt, but this fails. */ 7801132718Skan if (TARGET_FPU) 7802132718Skan set_optab_libfunc (sqrt_optab, TFmode, "_Q_sqrt"); 7803132718Skan 7804132718Skan set_optab_libfunc (eq_optab, TFmode, "_Q_feq"); 7805132718Skan set_optab_libfunc (ne_optab, TFmode, "_Q_fne"); 7806132718Skan set_optab_libfunc (gt_optab, TFmode, "_Q_fgt"); 7807132718Skan set_optab_libfunc (ge_optab, TFmode, "_Q_fge"); 7808132718Skan set_optab_libfunc (lt_optab, TFmode, "_Q_flt"); 7809132718Skan set_optab_libfunc (le_optab, TFmode, "_Q_fle"); 7810132718Skan 7811132718Skan set_conv_libfunc (sext_optab, TFmode, SFmode, "_Q_stoq"); 7812132718Skan set_conv_libfunc (sext_optab, TFmode, DFmode, "_Q_dtoq"); 7813132718Skan set_conv_libfunc (trunc_optab, SFmode, TFmode, "_Q_qtos"); 7814132718Skan set_conv_libfunc (trunc_optab, DFmode, TFmode, "_Q_qtod"); 7815132718Skan 7816132718Skan set_conv_libfunc (sfix_optab, SImode, TFmode, "_Q_qtoi"); 7817132718Skan set_conv_libfunc (ufix_optab, SImode, TFmode, "_Q_qtou"); 7818132718Skan set_conv_libfunc (sfloat_optab, TFmode, SImode, "_Q_itoq"); 7819169689Skan set_conv_libfunc (ufloat_optab, TFmode, SImode, "_Q_utoq"); 7820132718Skan 7821132718Skan if (DITF_CONVERSION_LIBFUNCS) 7822132718Skan { 7823132718Skan set_conv_libfunc (sfix_optab, DImode, TFmode, "_Q_qtoll"); 7824132718Skan set_conv_libfunc (ufix_optab, DImode, TFmode, "_Q_qtoull"); 7825132718Skan set_conv_libfunc (sfloat_optab, TFmode, DImode, "_Q_lltoq"); 7826169689Skan set_conv_libfunc (ufloat_optab, TFmode, DImode, "_Q_ulltoq"); 7827132718Skan } 7828132718Skan 7829132718Skan if (SUN_CONVERSION_LIBFUNCS) 7830132718Skan { 7831132718Skan set_conv_libfunc (sfix_optab, DImode, SFmode, "__ftoll"); 7832132718Skan set_conv_libfunc (ufix_optab, DImode, SFmode, "__ftoull"); 7833132718Skan set_conv_libfunc (sfix_optab, DImode, DFmode, "__dtoll"); 7834132718Skan set_conv_libfunc (ufix_optab, DImode, DFmode, "__dtoull"); 7835132718Skan } 7836132718Skan } 7837132718Skan if (TARGET_ARCH64) 7838132718Skan { 7839132718Skan /* In the SPARC 64bit ABI, SImode multiply and divide functions 7840132718Skan do not exist in the library. Make sure the compiler does not 7841132718Skan emit calls to them by accident. (It should always use the 7842132718Skan hardware instructions.) */ 7843132718Skan set_optab_libfunc (smul_optab, SImode, 0); 7844132718Skan set_optab_libfunc (sdiv_optab, SImode, 0); 7845132718Skan set_optab_libfunc (udiv_optab, SImode, 0); 7846132718Skan set_optab_libfunc (smod_optab, SImode, 0); 7847132718Skan set_optab_libfunc (umod_optab, SImode, 0); 7848132718Skan 7849132718Skan if (SUN_INTEGER_MULTIPLY_64) 7850132718Skan { 7851132718Skan set_optab_libfunc (smul_optab, DImode, "__mul64"); 7852132718Skan set_optab_libfunc (sdiv_optab, DImode, "__div64"); 7853132718Skan set_optab_libfunc (udiv_optab, DImode, "__udiv64"); 7854132718Skan set_optab_libfunc (smod_optab, DImode, "__rem64"); 7855132718Skan set_optab_libfunc (umod_optab, DImode, "__urem64"); 7856132718Skan } 7857132718Skan 7858132718Skan if (SUN_CONVERSION_LIBFUNCS) 7859132718Skan { 7860132718Skan set_conv_libfunc (sfix_optab, DImode, SFmode, "__ftol"); 7861132718Skan set_conv_libfunc (ufix_optab, DImode, SFmode, "__ftoul"); 7862132718Skan set_conv_libfunc (sfix_optab, DImode, DFmode, "__dtol"); 7863132718Skan set_conv_libfunc (ufix_optab, DImode, DFmode, "__dtoul"); 7864132718Skan } 7865132718Skan } 7866132718Skan 7867132718Skan gofast_maybe_init_libfuncs (); 7868132718Skan} 7869132718Skan 7870169689Skan#define def_builtin(NAME, CODE, TYPE) \ 7871169689Skan lang_hooks.builtin_function((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, \ 7872169689Skan NULL_TREE) 7873117395Skan 7874169689Skan/* Implement the TARGET_INIT_BUILTINS target hook. 7875169689Skan Create builtin functions for special SPARC instructions. */ 7876169689Skan 7877117395Skanstatic void 7878169689Skansparc_init_builtins (void) 7879117395Skan{ 7880169689Skan if (TARGET_VIS) 7881169689Skan sparc_vis_init_builtins (); 7882117395Skan} 7883117395Skan 7884169689Skan/* Create builtin functions for VIS 1.0 instructions. */ 7885117395Skan 7886117395Skanstatic void 7887169689Skansparc_vis_init_builtins (void) 7888117395Skan{ 7889169689Skan tree v4qi = build_vector_type (unsigned_intQI_type_node, 4); 7890169689Skan tree v8qi = build_vector_type (unsigned_intQI_type_node, 8); 7891169689Skan tree v4hi = build_vector_type (intHI_type_node, 4); 7892169689Skan tree v2hi = build_vector_type (intHI_type_node, 2); 7893169689Skan tree v2si = build_vector_type (intSI_type_node, 2); 7894169689Skan 7895169689Skan tree v4qi_ftype_v4hi = build_function_type_list (v4qi, v4hi, 0); 7896169689Skan tree v8qi_ftype_v2si_v8qi = build_function_type_list (v8qi, v2si, v8qi, 0); 7897169689Skan tree v2hi_ftype_v2si = build_function_type_list (v2hi, v2si, 0); 7898169689Skan tree v4hi_ftype_v4qi = build_function_type_list (v4hi, v4qi, 0); 7899169689Skan tree v8qi_ftype_v4qi_v4qi = build_function_type_list (v8qi, v4qi, v4qi, 0); 7900169689Skan tree v4hi_ftype_v4qi_v4hi = build_function_type_list (v4hi, v4qi, v4hi, 0); 7901169689Skan tree v4hi_ftype_v4qi_v2hi = build_function_type_list (v4hi, v4qi, v2hi, 0); 7902169689Skan tree v2si_ftype_v4qi_v2hi = build_function_type_list (v2si, v4qi, v2hi, 0); 7903169689Skan tree v4hi_ftype_v8qi_v4hi = build_function_type_list (v4hi, v8qi, v4hi, 0); 7904169689Skan tree v4hi_ftype_v4hi_v4hi = build_function_type_list (v4hi, v4hi, v4hi, 0); 7905169689Skan tree v2si_ftype_v2si_v2si = build_function_type_list (v2si, v2si, v2si, 0); 7906169689Skan tree v8qi_ftype_v8qi_v8qi = build_function_type_list (v8qi, v8qi, v8qi, 0); 7907169689Skan tree di_ftype_v8qi_v8qi_di = build_function_type_list (intDI_type_node, 7908169689Skan v8qi, v8qi, 7909169689Skan intDI_type_node, 0); 7910169689Skan tree di_ftype_di_di = build_function_type_list (intDI_type_node, 7911169689Skan intDI_type_node, 7912169689Skan intDI_type_node, 0); 7913169689Skan tree ptr_ftype_ptr_si = build_function_type_list (ptr_type_node, 7914169689Skan ptr_type_node, 7915169689Skan intSI_type_node, 0); 7916169689Skan tree ptr_ftype_ptr_di = build_function_type_list (ptr_type_node, 7917169689Skan ptr_type_node, 7918169689Skan intDI_type_node, 0); 7919169689Skan 7920169689Skan /* Packing and expanding vectors. */ 7921169689Skan def_builtin ("__builtin_vis_fpack16", CODE_FOR_fpack16_vis, v4qi_ftype_v4hi); 7922169689Skan def_builtin ("__builtin_vis_fpack32", CODE_FOR_fpack32_vis, 7923169689Skan v8qi_ftype_v2si_v8qi); 7924169689Skan def_builtin ("__builtin_vis_fpackfix", CODE_FOR_fpackfix_vis, 7925169689Skan v2hi_ftype_v2si); 7926169689Skan def_builtin ("__builtin_vis_fexpand", CODE_FOR_fexpand_vis, v4hi_ftype_v4qi); 7927169689Skan def_builtin ("__builtin_vis_fpmerge", CODE_FOR_fpmerge_vis, 7928169689Skan v8qi_ftype_v4qi_v4qi); 7929169689Skan 7930169689Skan /* Multiplications. */ 7931169689Skan def_builtin ("__builtin_vis_fmul8x16", CODE_FOR_fmul8x16_vis, 7932169689Skan v4hi_ftype_v4qi_v4hi); 7933169689Skan def_builtin ("__builtin_vis_fmul8x16au", CODE_FOR_fmul8x16au_vis, 7934169689Skan v4hi_ftype_v4qi_v2hi); 7935169689Skan def_builtin ("__builtin_vis_fmul8x16al", CODE_FOR_fmul8x16al_vis, 7936169689Skan v4hi_ftype_v4qi_v2hi); 7937169689Skan def_builtin ("__builtin_vis_fmul8sux16", CODE_FOR_fmul8sux16_vis, 7938169689Skan v4hi_ftype_v8qi_v4hi); 7939169689Skan def_builtin ("__builtin_vis_fmul8ulx16", CODE_FOR_fmul8ulx16_vis, 7940169689Skan v4hi_ftype_v8qi_v4hi); 7941169689Skan def_builtin ("__builtin_vis_fmuld8sux16", CODE_FOR_fmuld8sux16_vis, 7942169689Skan v2si_ftype_v4qi_v2hi); 7943169689Skan def_builtin ("__builtin_vis_fmuld8ulx16", CODE_FOR_fmuld8ulx16_vis, 7944169689Skan v2si_ftype_v4qi_v2hi); 7945169689Skan 7946169689Skan /* Data aligning. */ 7947169689Skan def_builtin ("__builtin_vis_faligndatav4hi", CODE_FOR_faligndatav4hi_vis, 7948169689Skan v4hi_ftype_v4hi_v4hi); 7949169689Skan def_builtin ("__builtin_vis_faligndatav8qi", CODE_FOR_faligndatav8qi_vis, 7950169689Skan v8qi_ftype_v8qi_v8qi); 7951169689Skan def_builtin ("__builtin_vis_faligndatav2si", CODE_FOR_faligndatav2si_vis, 7952169689Skan v2si_ftype_v2si_v2si); 7953169689Skan def_builtin ("__builtin_vis_faligndatadi", CODE_FOR_faligndatadi_vis, 7954169689Skan di_ftype_di_di); 7955169689Skan if (TARGET_ARCH64) 7956169689Skan def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrdi_vis, 7957169689Skan ptr_ftype_ptr_di); 7958117395Skan else 7959169689Skan def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrsi_vis, 7960169689Skan ptr_ftype_ptr_si); 7961169689Skan 7962169689Skan /* Pixel distance. */ 7963169689Skan def_builtin ("__builtin_vis_pdist", CODE_FOR_pdist_vis, 7964169689Skan di_ftype_v8qi_v8qi_di); 7965117395Skan} 7966117395Skan 7967169689Skan/* Handle TARGET_EXPAND_BUILTIN target hook. 7968169689Skan Expand builtin functions for sparc intrinsics. */ 7969169689Skan 7970169689Skanstatic rtx 7971171825Skansparc_expand_builtin (tree exp, rtx target, 7972171825Skan rtx subtarget ATTRIBUTE_UNUSED, 7973171825Skan enum machine_mode tmode ATTRIBUTE_UNUSED, 7974171825Skan int ignore ATTRIBUTE_UNUSED) 7975169689Skan{ 7976169689Skan tree arglist; 7977169689Skan tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); 7978169689Skan unsigned int icode = DECL_FUNCTION_CODE (fndecl); 7979169689Skan rtx pat, op[4]; 7980169689Skan enum machine_mode mode[4]; 7981169689Skan int arg_count = 0; 7982169689Skan 7983171825Skan mode[0] = insn_data[icode].operand[0].mode; 7984171825Skan if (!target 7985171825Skan || GET_MODE (target) != mode[0] 7986171825Skan || ! (*insn_data[icode].operand[0].predicate) (target, mode[0])) 7987171825Skan op[0] = gen_reg_rtx (mode[0]); 7988169689Skan else 7989171825Skan op[0] = target; 7990169689Skan 7991169689Skan for (arglist = TREE_OPERAND (exp, 1); arglist; 7992169689Skan arglist = TREE_CHAIN (arglist)) 7993169689Skan { 7994169689Skan tree arg = TREE_VALUE (arglist); 7995169689Skan 7996169689Skan arg_count++; 7997169689Skan mode[arg_count] = insn_data[icode].operand[arg_count].mode; 7998169689Skan op[arg_count] = expand_normal (arg); 7999169689Skan 8000169689Skan if (! (*insn_data[icode].operand[arg_count].predicate) (op[arg_count], 8001169689Skan mode[arg_count])) 8002169689Skan op[arg_count] = copy_to_mode_reg (mode[arg_count], op[arg_count]); 8003169689Skan } 8004169689Skan 8005169689Skan switch (arg_count) 8006169689Skan { 8007169689Skan case 1: 8008169689Skan pat = GEN_FCN (icode) (op[0], op[1]); 8009169689Skan break; 8010169689Skan case 2: 8011169689Skan pat = GEN_FCN (icode) (op[0], op[1], op[2]); 8012169689Skan break; 8013169689Skan case 3: 8014169689Skan pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); 8015169689Skan break; 8016169689Skan default: 8017169689Skan gcc_unreachable (); 8018169689Skan } 8019169689Skan 8020169689Skan if (!pat) 8021169689Skan return NULL_RTX; 8022169689Skan 8023169689Skan emit_insn (pat); 8024169689Skan 8025169689Skan return op[0]; 8026169689Skan} 8027169689Skan 8028169689Skanstatic int 8029169689Skansparc_vis_mul8x16 (int e8, int e16) 8030169689Skan{ 8031169689Skan return (e8 * e16 + 128) / 256; 8032169689Skan} 8033169689Skan 8034169689Skan/* Multiply the vector elements in ELTS0 to the elements in ELTS1 as specified 8035169689Skan by FNCODE. All of the elements in ELTS0 and ELTS1 lists must be integer 8036169689Skan constants. A tree list with the results of the multiplications is returned, 8037169689Skan and each element in the list is of INNER_TYPE. */ 8038169689Skan 8039169689Skanstatic tree 8040169689Skansparc_handle_vis_mul8x16 (int fncode, tree inner_type, tree elts0, tree elts1) 8041169689Skan{ 8042169689Skan tree n_elts = NULL_TREE; 8043169689Skan int scale; 8044169689Skan 8045169689Skan switch (fncode) 8046169689Skan { 8047169689Skan case CODE_FOR_fmul8x16_vis: 8048169689Skan for (; elts0 && elts1; 8049169689Skan elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1)) 8050169689Skan { 8051169689Skan int val 8052169689Skan = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)), 8053169689Skan TREE_INT_CST_LOW (TREE_VALUE (elts1))); 8054169689Skan n_elts = tree_cons (NULL_TREE, 8055169689Skan build_int_cst (inner_type, val), 8056169689Skan n_elts); 8057169689Skan } 8058169689Skan break; 8059169689Skan 8060169689Skan case CODE_FOR_fmul8x16au_vis: 8061169689Skan scale = TREE_INT_CST_LOW (TREE_VALUE (elts1)); 8062169689Skan 8063169689Skan for (; elts0; elts0 = TREE_CHAIN (elts0)) 8064169689Skan { 8065169689Skan int val 8066169689Skan = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)), 8067169689Skan scale); 8068169689Skan n_elts = tree_cons (NULL_TREE, 8069169689Skan build_int_cst (inner_type, val), 8070169689Skan n_elts); 8071169689Skan } 8072169689Skan break; 8073169689Skan 8074169689Skan case CODE_FOR_fmul8x16al_vis: 8075169689Skan scale = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (elts1))); 8076169689Skan 8077169689Skan for (; elts0; elts0 = TREE_CHAIN (elts0)) 8078169689Skan { 8079169689Skan int val 8080169689Skan = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)), 8081169689Skan scale); 8082169689Skan n_elts = tree_cons (NULL_TREE, 8083169689Skan build_int_cst (inner_type, val), 8084169689Skan n_elts); 8085169689Skan } 8086169689Skan break; 8087169689Skan 8088169689Skan default: 8089169689Skan gcc_unreachable (); 8090169689Skan } 8091169689Skan 8092169689Skan return nreverse (n_elts); 8093169689Skan 8094169689Skan} 8095169689Skan/* Handle TARGET_FOLD_BUILTIN target hook. 8096169689Skan Fold builtin functions for SPARC intrinsics. If IGNORE is true the 8097169689Skan result of the function call is ignored. NULL_TREE is returned if the 8098169689Skan function could not be folded. */ 8099169689Skan 8100169689Skanstatic tree 8101169689Skansparc_fold_builtin (tree fndecl, tree arglist, bool ignore) 8102169689Skan{ 8103169689Skan tree arg0, arg1, arg2; 8104169689Skan tree rtype = TREE_TYPE (TREE_TYPE (fndecl)); 8105169689Skan 8106171825Skan if (ignore 8107171825Skan && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrsi_vis 8108169689Skan && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrdi_vis) 8109171825Skan return fold_convert (rtype, integer_zero_node); 8110169689Skan 8111169689Skan switch (DECL_FUNCTION_CODE (fndecl)) 8112169689Skan { 8113169689Skan case CODE_FOR_fexpand_vis: 8114169689Skan arg0 = TREE_VALUE (arglist); 8115169689Skan STRIP_NOPS (arg0); 8116169689Skan 8117169689Skan if (TREE_CODE (arg0) == VECTOR_CST) 8118169689Skan { 8119169689Skan tree inner_type = TREE_TYPE (rtype); 8120169689Skan tree elts = TREE_VECTOR_CST_ELTS (arg0); 8121169689Skan tree n_elts = NULL_TREE; 8122169689Skan 8123169689Skan for (; elts; elts = TREE_CHAIN (elts)) 8124169689Skan { 8125169689Skan unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (elts)) << 4; 8126169689Skan n_elts = tree_cons (NULL_TREE, 8127169689Skan build_int_cst (inner_type, val), 8128169689Skan n_elts); 8129169689Skan } 8130169689Skan return build_vector (rtype, nreverse (n_elts)); 8131169689Skan } 8132169689Skan break; 8133169689Skan 8134169689Skan case CODE_FOR_fmul8x16_vis: 8135169689Skan case CODE_FOR_fmul8x16au_vis: 8136169689Skan case CODE_FOR_fmul8x16al_vis: 8137169689Skan arg0 = TREE_VALUE (arglist); 8138169689Skan arg1 = TREE_VALUE (TREE_CHAIN (arglist)); 8139169689Skan STRIP_NOPS (arg0); 8140169689Skan STRIP_NOPS (arg1); 8141169689Skan 8142169689Skan if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST) 8143169689Skan { 8144169689Skan tree inner_type = TREE_TYPE (rtype); 8145169689Skan tree elts0 = TREE_VECTOR_CST_ELTS (arg0); 8146169689Skan tree elts1 = TREE_VECTOR_CST_ELTS (arg1); 8147169689Skan tree n_elts = sparc_handle_vis_mul8x16 (DECL_FUNCTION_CODE (fndecl), 8148169689Skan inner_type, elts0, elts1); 8149169689Skan 8150169689Skan return build_vector (rtype, n_elts); 8151169689Skan } 8152169689Skan break; 8153169689Skan 8154169689Skan case CODE_FOR_fpmerge_vis: 8155169689Skan arg0 = TREE_VALUE (arglist); 8156169689Skan arg1 = TREE_VALUE (TREE_CHAIN (arglist)); 8157169689Skan STRIP_NOPS (arg0); 8158169689Skan STRIP_NOPS (arg1); 8159169689Skan 8160169689Skan if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST) 8161169689Skan { 8162169689Skan tree elts0 = TREE_VECTOR_CST_ELTS (arg0); 8163169689Skan tree elts1 = TREE_VECTOR_CST_ELTS (arg1); 8164169689Skan tree n_elts = NULL_TREE; 8165169689Skan 8166169689Skan for (; elts0 && elts1; 8167169689Skan elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1)) 8168169689Skan { 8169169689Skan n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts0), n_elts); 8170169689Skan n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts1), n_elts); 8171169689Skan } 8172169689Skan 8173169689Skan return build_vector (rtype, nreverse (n_elts)); 8174169689Skan } 8175169689Skan break; 8176169689Skan 8177169689Skan case CODE_FOR_pdist_vis: 8178169689Skan arg0 = TREE_VALUE (arglist); 8179169689Skan arg1 = TREE_VALUE (TREE_CHAIN (arglist)); 8180169689Skan arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); 8181169689Skan STRIP_NOPS (arg0); 8182169689Skan STRIP_NOPS (arg1); 8183169689Skan STRIP_NOPS (arg2); 8184169689Skan 8185169689Skan if (TREE_CODE (arg0) == VECTOR_CST 8186169689Skan && TREE_CODE (arg1) == VECTOR_CST 8187169689Skan && TREE_CODE (arg2) == INTEGER_CST) 8188169689Skan { 8189169689Skan int overflow = 0; 8190169689Skan unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg2); 8191169689Skan HOST_WIDE_INT high = TREE_INT_CST_HIGH (arg2); 8192169689Skan tree elts0 = TREE_VECTOR_CST_ELTS (arg0); 8193169689Skan tree elts1 = TREE_VECTOR_CST_ELTS (arg1); 8194169689Skan 8195169689Skan for (; elts0 && elts1; 8196169689Skan elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1)) 8197169689Skan { 8198169689Skan unsigned HOST_WIDE_INT 8199169689Skan low0 = TREE_INT_CST_LOW (TREE_VALUE (elts0)), 8200169689Skan low1 = TREE_INT_CST_LOW (TREE_VALUE (elts1)); 8201169689Skan HOST_WIDE_INT high0 = TREE_INT_CST_HIGH (TREE_VALUE (elts0)); 8202169689Skan HOST_WIDE_INT high1 = TREE_INT_CST_HIGH (TREE_VALUE (elts1)); 8203169689Skan 8204169689Skan unsigned HOST_WIDE_INT l; 8205169689Skan HOST_WIDE_INT h; 8206169689Skan 8207169689Skan overflow |= neg_double (low1, high1, &l, &h); 8208169689Skan overflow |= add_double (low0, high0, l, h, &l, &h); 8209169689Skan if (h < 0) 8210169689Skan overflow |= neg_double (l, h, &l, &h); 8211169689Skan 8212169689Skan overflow |= add_double (low, high, l, h, &low, &high); 8213169689Skan } 8214169689Skan 8215169689Skan gcc_assert (overflow == 0); 8216169689Skan 8217169689Skan return build_int_cst_wide (rtype, low, high); 8218169689Skan } 8219169689Skan 8220169689Skan default: 8221169689Skan break; 8222169689Skan } 8223171825Skan 8224169689Skan return NULL_TREE; 8225169689Skan} 8226169689Skan 822796263Sobrienint 8228132718Skansparc_extra_constraint_check (rtx op, int c, int strict) 822996263Sobrien{ 823096263Sobrien int reload_ok_mem; 823196263Sobrien 823296263Sobrien if (TARGET_ARCH64 823396263Sobrien && (c == 'T' || c == 'U')) 823496263Sobrien return 0; 823596263Sobrien 823696263Sobrien switch (c) 823796263Sobrien { 823896263Sobrien case 'Q': 823996263Sobrien return fp_sethi_p (op); 824096263Sobrien 824196263Sobrien case 'R': 824296263Sobrien return fp_mov_p (op); 824396263Sobrien 824496263Sobrien case 'S': 824596263Sobrien return fp_high_losum_p (op); 824696263Sobrien 824796263Sobrien case 'U': 824896263Sobrien if (! strict 824996263Sobrien || (GET_CODE (op) == REG 825096263Sobrien && (REGNO (op) < FIRST_PSEUDO_REGISTER 825196263Sobrien || reg_renumber[REGNO (op)] >= 0))) 825296263Sobrien return register_ok_for_ldd (op); 825396263Sobrien 825496263Sobrien return 0; 825596263Sobrien 825696263Sobrien case 'W': 825796263Sobrien case 'T': 825896263Sobrien break; 825996263Sobrien 8260169689Skan case 'Y': 8261169689Skan return const_zero_operand (op, GET_MODE (op)); 8262169689Skan 826396263Sobrien default: 826496263Sobrien return 0; 826596263Sobrien } 826696263Sobrien 826796263Sobrien /* Our memory extra constraints have to emulate the 826896263Sobrien behavior of 'm' and 'o' in order for reload to work 826996263Sobrien correctly. */ 827096263Sobrien if (GET_CODE (op) == MEM) 827196263Sobrien { 827296263Sobrien reload_ok_mem = 0; 827396263Sobrien if ((TARGET_ARCH64 || mem_min_alignment (op, 8)) 827496263Sobrien && (! strict 827596263Sobrien || strict_memory_address_p (Pmode, XEXP (op, 0)))) 827696263Sobrien reload_ok_mem = 1; 827796263Sobrien } 827896263Sobrien else 827996263Sobrien { 828096263Sobrien reload_ok_mem = (reload_in_progress 828196263Sobrien && GET_CODE (op) == REG 828296263Sobrien && REGNO (op) >= FIRST_PSEUDO_REGISTER 828396263Sobrien && reg_renumber [REGNO (op)] < 0); 828496263Sobrien } 828596263Sobrien 828696263Sobrien return reload_ok_mem; 828796263Sobrien} 8288102780Skan 8289117395Skan/* ??? This duplicates information provided to the compiler by the 8290117395Skan ??? scheduler description. Some day, teach genautomata to output 8291117395Skan ??? the latencies and then CSE will just use that. */ 8292117395Skan 8293132718Skanstatic bool 8294132718Skansparc_rtx_costs (rtx x, int code, int outer_code, int *total) 8295117395Skan{ 8296169689Skan enum machine_mode mode = GET_MODE (x); 8297169689Skan bool float_mode_p = FLOAT_MODE_P (mode); 8298169689Skan 8299117395Skan switch (code) 8300117395Skan { 8301169689Skan case CONST_INT: 8302169689Skan if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000) 8303117395Skan { 8304169689Skan *total = 0; 8305169689Skan return true; 8306169689Skan } 8307169689Skan /* FALLTHRU */ 8308117395Skan 8309169689Skan case HIGH: 8310169689Skan *total = 2; 8311169689Skan return true; 8312117395Skan 8313169689Skan case CONST: 8314169689Skan case LABEL_REF: 8315169689Skan case SYMBOL_REF: 8316169689Skan *total = 4; 8317169689Skan return true; 8318117395Skan 8319169689Skan case CONST_DOUBLE: 8320169689Skan if (GET_MODE (x) == VOIDmode 8321169689Skan && ((CONST_DOUBLE_HIGH (x) == 0 8322169689Skan && CONST_DOUBLE_LOW (x) < 0x1000) 8323169689Skan || (CONST_DOUBLE_HIGH (x) == -1 8324169689Skan && CONST_DOUBLE_LOW (x) < 0 8325169689Skan && CONST_DOUBLE_LOW (x) >= -0x1000))) 8326169689Skan *total = 0; 8327169689Skan else 8328169689Skan *total = 8; 8329132718Skan return true; 8330117395Skan 8331169689Skan case MEM: 8332169689Skan /* If outer-code was a sign or zero extension, a cost 8333169689Skan of COSTS_N_INSNS (1) was already added in. This is 8334169689Skan why we are subtracting it back out. */ 8335169689Skan if (outer_code == ZERO_EXTEND) 8336117395Skan { 8337169689Skan *total = sparc_costs->int_zload - COSTS_N_INSNS (1); 8338117395Skan } 8339169689Skan else if (outer_code == SIGN_EXTEND) 8340117395Skan { 8341169689Skan *total = sparc_costs->int_sload - COSTS_N_INSNS (1); 8342117395Skan } 8343169689Skan else if (float_mode_p) 8344169689Skan { 8345169689Skan *total = sparc_costs->float_load; 8346169689Skan } 8347169689Skan else 8348169689Skan { 8349169689Skan *total = sparc_costs->int_load; 8350169689Skan } 8351117395Skan 8352132718Skan return true; 8353117395Skan 8354169689Skan case PLUS: 8355169689Skan case MINUS: 8356169689Skan if (float_mode_p) 8357169689Skan *total = sparc_costs->float_plusminus; 8358169689Skan else 8359169689Skan *total = COSTS_N_INSNS (1); 8360169689Skan return false; 8361169689Skan 8362117395Skan case MULT: 8363169689Skan if (float_mode_p) 8364169689Skan *total = sparc_costs->float_mul; 8365169689Skan else if (! TARGET_HARD_MUL) 8366169689Skan *total = COSTS_N_INSNS (25); 8367169689Skan else 8368117395Skan { 8369169689Skan int bit_cost; 8370169689Skan 8371169689Skan bit_cost = 0; 8372169689Skan if (sparc_costs->int_mul_bit_factor) 8373117395Skan { 8374169689Skan int nbits; 8375117395Skan 8376169689Skan if (GET_CODE (XEXP (x, 1)) == CONST_INT) 8377169689Skan { 8378169689Skan unsigned HOST_WIDE_INT value = INTVAL (XEXP (x, 1)); 8379169689Skan for (nbits = 0; value != 0; value &= value - 1) 8380169689Skan nbits++; 8381169689Skan } 8382169689Skan else if (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE 8383169689Skan && GET_MODE (XEXP (x, 1)) == VOIDmode) 8384169689Skan { 8385169689Skan rtx x1 = XEXP (x, 1); 8386169689Skan unsigned HOST_WIDE_INT value1 = CONST_DOUBLE_LOW (x1); 8387169689Skan unsigned HOST_WIDE_INT value2 = CONST_DOUBLE_HIGH (x1); 8388117395Skan 8389169689Skan for (nbits = 0; value1 != 0; value1 &= value1 - 1) 8390169689Skan nbits++; 8391169689Skan for (; value2 != 0; value2 &= value2 - 1) 8392169689Skan nbits++; 8393169689Skan } 8394169689Skan else 8395169689Skan nbits = 7; 8396117395Skan 8397169689Skan if (nbits < 3) 8398169689Skan nbits = 3; 8399169689Skan bit_cost = (nbits - 3) / sparc_costs->int_mul_bit_factor; 8400169689Skan bit_cost = COSTS_N_INSNS (bit_cost); 8401117395Skan } 8402117395Skan 8403169689Skan if (mode == DImode) 8404169689Skan *total = sparc_costs->int_mulX + bit_cost; 8405169689Skan else 8406169689Skan *total = sparc_costs->int_mul + bit_cost; 8407132718Skan } 8408169689Skan return false; 8409117395Skan 8410169689Skan case ASHIFT: 8411169689Skan case ASHIFTRT: 8412169689Skan case LSHIFTRT: 8413169689Skan *total = COSTS_N_INSNS (1) + sparc_costs->shift_penalty; 8414169689Skan return false; 8415117395Skan 8416117395Skan case DIV: 8417117395Skan case UDIV: 8418117395Skan case MOD: 8419117395Skan case UMOD: 8420169689Skan if (float_mode_p) 8421117395Skan { 8422169689Skan if (mode == DFmode) 8423169689Skan *total = sparc_costs->float_div_df; 8424169689Skan else 8425169689Skan *total = sparc_costs->float_div_sf; 8426117395Skan } 8427132718Skan else 8428117395Skan { 8429169689Skan if (mode == DImode) 8430169689Skan *total = sparc_costs->int_divX; 8431117395Skan else 8432169689Skan *total = sparc_costs->int_div; 8433169689Skan } 8434169689Skan return false; 8435117395Skan 8436169689Skan case NEG: 8437169689Skan if (! float_mode_p) 8438169689Skan { 8439132718Skan *total = COSTS_N_INSNS (1); 8440169689Skan return false; 8441117395Skan } 8442169689Skan /* FALLTHRU */ 8443117395Skan 8444169689Skan case ABS: 8445169689Skan case FLOAT: 8446169689Skan case UNSIGNED_FLOAT: 8447169689Skan case FIX: 8448169689Skan case UNSIGNED_FIX: 8449169689Skan case FLOAT_EXTEND: 8450169689Skan case FLOAT_TRUNCATE: 8451169689Skan *total = sparc_costs->float_move; 8452169689Skan return false; 8453117395Skan 8454169689Skan case SQRT: 8455169689Skan if (mode == DFmode) 8456169689Skan *total = sparc_costs->float_sqrt_df; 8457169689Skan else 8458169689Skan *total = sparc_costs->float_sqrt_sf; 8459169689Skan return false; 8460117395Skan 8461169689Skan case COMPARE: 8462169689Skan if (float_mode_p) 8463169689Skan *total = sparc_costs->float_cmp; 8464169689Skan else 8465169689Skan *total = COSTS_N_INSNS (1); 8466169689Skan return false; 8467117395Skan 8468169689Skan case IF_THEN_ELSE: 8469169689Skan if (float_mode_p) 8470169689Skan *total = sparc_costs->float_cmove; 8471169689Skan else 8472169689Skan *total = sparc_costs->int_cmove; 8473169689Skan return false; 8474117395Skan 8475169689Skan case IOR: 8476169689Skan /* Handle the NAND vector patterns. */ 8477169689Skan if (sparc_vector_mode_supported_p (GET_MODE (x)) 8478169689Skan && GET_CODE (XEXP (x, 0)) == NOT 8479169689Skan && GET_CODE (XEXP (x, 1)) == NOT) 8480132718Skan { 8481169689Skan *total = COSTS_N_INSNS (1); 8482132718Skan return true; 8483132718Skan } 8484132718Skan else 8485169689Skan return false; 8486117395Skan 8487117395Skan default: 8488132718Skan return false; 8489132718Skan } 8490117395Skan} 8491117395Skan 8492169689Skan/* Emit the sequence of insns SEQ while preserving the registers REG and REG2. 8493169689Skan This is achieved by means of a manual dynamic stack space allocation in 8494169689Skan the current frame. We make the assumption that SEQ doesn't contain any 8495169689Skan function calls, with the possible exception of calls to the PIC helper. */ 8496169689Skan 8497169689Skanstatic void 8498169689Skanemit_and_preserve (rtx seq, rtx reg, rtx reg2) 8499169689Skan{ 8500169689Skan /* We must preserve the lowest 16 words for the register save area. */ 8501169689Skan HOST_WIDE_INT offset = 16*UNITS_PER_WORD; 8502169689Skan /* We really need only 2 words of fresh stack space. */ 8503169689Skan HOST_WIDE_INT size = SPARC_STACK_ALIGN (offset + 2*UNITS_PER_WORD); 8504169689Skan 8505169689Skan rtx slot 8506169689Skan = gen_rtx_MEM (word_mode, plus_constant (stack_pointer_rtx, 8507169689Skan SPARC_STACK_BIAS + offset)); 8508169689Skan 8509169689Skan emit_insn (gen_stack_pointer_dec (GEN_INT (size))); 8510169689Skan emit_insn (gen_rtx_SET (VOIDmode, slot, reg)); 8511169689Skan if (reg2) 8512169689Skan emit_insn (gen_rtx_SET (VOIDmode, 8513169689Skan adjust_address (slot, word_mode, UNITS_PER_WORD), 8514169689Skan reg2)); 8515169689Skan emit_insn (seq); 8516169689Skan if (reg2) 8517169689Skan emit_insn (gen_rtx_SET (VOIDmode, 8518169689Skan reg2, 8519169689Skan adjust_address (slot, word_mode, UNITS_PER_WORD))); 8520169689Skan emit_insn (gen_rtx_SET (VOIDmode, reg, slot)); 8521169689Skan emit_insn (gen_stack_pointer_inc (GEN_INT (size))); 8522169689Skan} 8523169689Skan 8524146895Skan/* Output the assembler code for a thunk function. THUNK_DECL is the 8525146895Skan declaration for the thunk function itself, FUNCTION is the decl for 8526146895Skan the target function. DELTA is an immediate constant offset to be 8527146895Skan added to THIS. If VCALL_OFFSET is nonzero, the word at address 8528146895Skan (*THIS + VCALL_OFFSET) should be additionally added to THIS. */ 8529102780Skan 8530117395Skanstatic void 8531132718Skansparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, 8532146895Skan HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, 8533132718Skan tree function) 8534102780Skan{ 8535146895Skan rtx this, insn, funexp; 8536169689Skan unsigned int int_arg_first; 8537102780Skan 8538102780Skan reload_completed = 1; 8539132718Skan epilogue_completed = 1; 8540102780Skan no_new_pseudos = 1; 8541169689Skan reset_block_changes (); 8542102780Skan 8543132718Skan emit_note (NOTE_INSN_PROLOGUE_END); 8544102780Skan 8545169689Skan if (flag_delayed_branch) 8546169689Skan { 8547169689Skan /* We will emit a regular sibcall below, so we need to instruct 8548169689Skan output_sibcall that we are in a leaf function. */ 8549169689Skan sparc_leaf_function_p = current_function_uses_only_leaf_regs = 1; 8550169689Skan 8551169689Skan /* This will cause final.c to invoke leaf_renumber_regs so we 8552169689Skan must behave as if we were in a not-yet-leafified function. */ 8553169689Skan int_arg_first = SPARC_INCOMING_INT_ARG_FIRST; 8554169689Skan } 8555169689Skan else 8556169689Skan { 8557169689Skan /* We will emit the sibcall manually below, so we will need to 8558169689Skan manually spill non-leaf registers. */ 8559169689Skan sparc_leaf_function_p = current_function_uses_only_leaf_regs = 0; 8560169689Skan 8561169689Skan /* We really are in a leaf function. */ 8562169689Skan int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST; 8563169689Skan } 8564169689Skan 8565102780Skan /* Find the "this" pointer. Normally in %o0, but in ARCH64 if the function 8566102780Skan returns a structure, the structure return pointer is there instead. */ 8567132718Skan if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) 8568169689Skan this = gen_rtx_REG (Pmode, int_arg_first + 1); 8569102780Skan else 8570169689Skan this = gen_rtx_REG (Pmode, int_arg_first); 8571102780Skan 8572102780Skan /* Add DELTA. When possible use a plain add, otherwise load it into 8573102780Skan a register first. */ 8574146895Skan if (delta) 8575102780Skan { 8576146895Skan rtx delta_rtx = GEN_INT (delta); 8577146895Skan 8578146895Skan if (! SPARC_SIMM13_P (delta)) 8579146895Skan { 8580146895Skan rtx scratch = gen_rtx_REG (Pmode, 1); 8581146895Skan emit_move_insn (scratch, delta_rtx); 8582146895Skan delta_rtx = scratch; 8583146895Skan } 8584146895Skan 8585146895Skan /* THIS += DELTA. */ 8586146895Skan emit_insn (gen_add2_insn (this, delta_rtx)); 8587146895Skan } 8588146895Skan 8589146895Skan /* Add the word at address (*THIS + VCALL_OFFSET). */ 8590146895Skan if (vcall_offset) 8591146895Skan { 8592146895Skan rtx vcall_offset_rtx = GEN_INT (vcall_offset); 8593102780Skan rtx scratch = gen_rtx_REG (Pmode, 1); 8594132718Skan 8595169689Skan gcc_assert (vcall_offset < 0); 8596146895Skan 8597146895Skan /* SCRATCH = *THIS. */ 8598146895Skan emit_move_insn (scratch, gen_rtx_MEM (Pmode, this)); 8599146895Skan 8600146895Skan /* Prepare for adding VCALL_OFFSET. The difficulty is that we 8601146895Skan may not have any available scratch register at this point. */ 8602146895Skan if (SPARC_SIMM13_P (vcall_offset)) 8603146895Skan ; 8604146895Skan /* This is the case if ARCH64 (unless -ffixed-g5 is passed). */ 8605146895Skan else if (! fixed_regs[5] 8606146895Skan /* The below sequence is made up of at least 2 insns, 8607146895Skan while the default method may need only one. */ 8608146895Skan && vcall_offset < -8192) 8609146895Skan { 8610146895Skan rtx scratch2 = gen_rtx_REG (Pmode, 5); 8611146895Skan emit_move_insn (scratch2, vcall_offset_rtx); 8612146895Skan vcall_offset_rtx = scratch2; 8613146895Skan } 8614102780Skan else 8615132718Skan { 8616146895Skan rtx increment = GEN_INT (-4096); 8617146895Skan 8618146895Skan /* VCALL_OFFSET is a negative number whose typical range can be 8619146895Skan estimated as -32768..0 in 32-bit mode. In almost all cases 8620146895Skan it is therefore cheaper to emit multiple add insns than 8621146895Skan spilling and loading the constant into a register (at least 8622146895Skan 6 insns). */ 8623146895Skan while (! SPARC_SIMM13_P (vcall_offset)) 8624146895Skan { 8625146895Skan emit_insn (gen_add2_insn (scratch, increment)); 8626146895Skan vcall_offset += 4096; 8627146895Skan } 8628146895Skan vcall_offset_rtx = GEN_INT (vcall_offset); /* cannot be 0 */ 8629132718Skan } 8630132718Skan 8631146895Skan /* SCRATCH = *(*THIS + VCALL_OFFSET). */ 8632146895Skan emit_move_insn (scratch, gen_rtx_MEM (Pmode, 8633146895Skan gen_rtx_PLUS (Pmode, 8634146895Skan scratch, 8635146895Skan vcall_offset_rtx))); 8636146895Skan 8637146895Skan /* THIS += *(*THIS + VCALL_OFFSET). */ 8638146895Skan emit_insn (gen_add2_insn (this, scratch)); 8639102780Skan } 8640102780Skan 8641102780Skan /* Generate a tail call to the target function. */ 8642102780Skan if (! TREE_USED (function)) 8643102780Skan { 8644102780Skan assemble_external (function); 8645102780Skan TREE_USED (function) = 1; 8646102780Skan } 8647102780Skan funexp = XEXP (DECL_RTL (function), 0); 8648169689Skan 8649169689Skan if (flag_delayed_branch) 8650169689Skan { 8651169689Skan funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); 8652169689Skan insn = emit_call_insn (gen_sibcall (funexp)); 8653169689Skan SIBLING_CALL_P (insn) = 1; 8654169689Skan } 8655169689Skan else 8656169689Skan { 8657169689Skan /* The hoops we have to jump through in order to generate a sibcall 8658169689Skan without using delay slots... */ 8659169689Skan rtx spill_reg, spill_reg2, seq, scratch = gen_rtx_REG (Pmode, 1); 8660169689Skan 8661169689Skan if (flag_pic) 8662169689Skan { 8663169689Skan spill_reg = gen_rtx_REG (word_mode, 15); /* %o7 */ 8664169689Skan spill_reg2 = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM); 8665169689Skan start_sequence (); 8666169689Skan /* Delay emitting the PIC helper function because it needs to 8667169689Skan change the section and we are emitting assembly code. */ 8668169689Skan load_pic_register (true); /* clobbers %o7 */ 8669169689Skan scratch = legitimize_pic_address (funexp, Pmode, scratch); 8670169689Skan seq = get_insns (); 8671169689Skan end_sequence (); 8672169689Skan emit_and_preserve (seq, spill_reg, spill_reg2); 8673169689Skan } 8674169689Skan else if (TARGET_ARCH32) 8675169689Skan { 8676169689Skan emit_insn (gen_rtx_SET (VOIDmode, 8677169689Skan scratch, 8678169689Skan gen_rtx_HIGH (SImode, funexp))); 8679169689Skan emit_insn (gen_rtx_SET (VOIDmode, 8680169689Skan scratch, 8681169689Skan gen_rtx_LO_SUM (SImode, scratch, funexp))); 8682169689Skan } 8683169689Skan else /* TARGET_ARCH64 */ 8684169689Skan { 8685169689Skan switch (sparc_cmodel) 8686169689Skan { 8687169689Skan case CM_MEDLOW: 8688169689Skan case CM_MEDMID: 8689169689Skan /* The destination can serve as a temporary. */ 8690169689Skan sparc_emit_set_symbolic_const64 (scratch, funexp, scratch); 8691169689Skan break; 8692169689Skan 8693169689Skan case CM_MEDANY: 8694169689Skan case CM_EMBMEDANY: 8695169689Skan /* The destination cannot serve as a temporary. */ 8696169689Skan spill_reg = gen_rtx_REG (DImode, 15); /* %o7 */ 8697169689Skan start_sequence (); 8698169689Skan sparc_emit_set_symbolic_const64 (scratch, funexp, spill_reg); 8699169689Skan seq = get_insns (); 8700169689Skan end_sequence (); 8701169689Skan emit_and_preserve (seq, spill_reg, 0); 8702169689Skan break; 8703169689Skan 8704169689Skan default: 8705169689Skan gcc_unreachable (); 8706169689Skan } 8707169689Skan } 8708169689Skan 8709169689Skan emit_jump_insn (gen_indirect_jump (scratch)); 8710169689Skan } 8711169689Skan 8712102780Skan emit_barrier (); 8713102780Skan 8714102780Skan /* Run just enough of rest_of_compilation to get the insns emitted. 8715102780Skan There's not really enough bulk here to make other passes such as 8716102780Skan instruction scheduling worth while. Note that use_thunk calls 8717102780Skan assemble_start_function and assemble_end_function. */ 8718102780Skan insn = get_insns (); 8719132718Skan insn_locators_initialize (); 8720102780Skan shorten_branches (insn); 8721102780Skan final_start_function (insn, file, 1); 8722169689Skan final (insn, file, 1); 8723102780Skan final_end_function (); 8724102780Skan 8725102780Skan reload_completed = 0; 8726132718Skan epilogue_completed = 0; 8727102780Skan no_new_pseudos = 0; 8728102780Skan} 8729117395Skan 8730146895Skan/* Return true if sparc_output_mi_thunk would be able to output the 8731146895Skan assembler code for the thunk function specified by the arguments 8732146895Skan it is passed, and false otherwise. */ 8733146895Skanstatic bool 8734146895Skansparc_can_output_mi_thunk (tree thunk_fndecl ATTRIBUTE_UNUSED, 8735146895Skan HOST_WIDE_INT delta ATTRIBUTE_UNUSED, 8736146895Skan HOST_WIDE_INT vcall_offset, 8737146895Skan tree function ATTRIBUTE_UNUSED) 8738146895Skan{ 8739146895Skan /* Bound the loop used in the default method above. */ 8740146895Skan return (vcall_offset >= -32768 || ! fixed_regs[5]); 8741146895Skan} 8742146895Skan 8743132718Skan/* How to allocate a 'struct machine_function'. */ 8744132718Skan 8745132718Skanstatic struct machine_function * 8746132718Skansparc_init_machine_status (void) 8747132718Skan{ 8748132718Skan return ggc_alloc_cleared (sizeof (struct machine_function)); 8749132718Skan} 8750132718Skan 8751132718Skan/* Locate some local-dynamic symbol still in use by this function 8752132718Skan so that we can print its name in local-dynamic base patterns. */ 8753132718Skan 8754132718Skanstatic const char * 8755132718Skanget_some_local_dynamic_name (void) 8756132718Skan{ 8757132718Skan rtx insn; 8758132718Skan 8759132718Skan if (cfun->machine->some_ld_name) 8760132718Skan return cfun->machine->some_ld_name; 8761132718Skan 8762132718Skan for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) 8763132718Skan if (INSN_P (insn) 8764132718Skan && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0)) 8765132718Skan return cfun->machine->some_ld_name; 8766132718Skan 8767169689Skan gcc_unreachable (); 8768132718Skan} 8769132718Skan 8770132718Skanstatic int 8771132718Skanget_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED) 8772132718Skan{ 8773132718Skan rtx x = *px; 8774132718Skan 8775132718Skan if (x 8776132718Skan && GET_CODE (x) == SYMBOL_REF 8777132718Skan && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC) 8778132718Skan { 8779132718Skan cfun->machine->some_ld_name = XSTR (x, 0); 8780132718Skan return 1; 8781132718Skan } 8782132718Skan 8783132718Skan return 0; 8784132718Skan} 8785132718Skan 8786169689Skan/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook. 8787169689Skan This is called from dwarf2out.c to emit call frame instructions 8788169689Skan for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */ 8789169689Skanstatic void 8790169689Skansparc_dwarf_handle_frame_unspec (const char *label, 8791169689Skan rtx pattern ATTRIBUTE_UNUSED, 8792169689Skan int index ATTRIBUTE_UNUSED) 8793169689Skan{ 8794169689Skan gcc_assert (index == UNSPECV_SAVEW); 8795169689Skan dwarf2out_window_save (label); 8796169689Skan} 8797169689Skan 8798169689Skan/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL. 8799132718Skan We need to emit DTP-relative relocations. */ 8800132718Skan 8801169689Skanstatic void 8802132718Skansparc_output_dwarf_dtprel (FILE *file, int size, rtx x) 8803132718Skan{ 8804132718Skan switch (size) 8805132718Skan { 8806132718Skan case 4: 8807132718Skan fputs ("\t.word\t%r_tls_dtpoff32(", file); 8808132718Skan break; 8809132718Skan case 8: 8810132718Skan fputs ("\t.xword\t%r_tls_dtpoff64(", file); 8811132718Skan break; 8812132718Skan default: 8813169689Skan gcc_unreachable (); 8814132718Skan } 8815132718Skan output_addr_const (file, x); 8816132718Skan fputs (")", file); 8817132718Skan} 8818132718Skan 8819169689Skan/* Do whatever processing is required at the end of a file. */ 8820169689Skan 8821169689Skanstatic void 8822169689Skansparc_file_end (void) 8823169689Skan{ 8824169689Skan /* If we haven't emitted the special PIC helper function, do so now. */ 8825169689Skan if (pic_helper_symbol_name[0] && !pic_helper_emitted_p) 8826169689Skan emit_pic_helper (); 8827169689Skan 8828169689Skan if (NEED_INDICATE_EXEC_STACK) 8829169689Skan file_end_indicate_exec_stack (); 8830169689Skan} 8831169689Skan 8832169689Skan#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING 8833169689Skan/* Implement TARGET_MANGLE_FUNDAMENTAL_TYPE. */ 8834169689Skan 8835169689Skanstatic const char * 8836169689Skansparc_mangle_fundamental_type (tree type) 8837169689Skan{ 8838169689Skan if (!TARGET_64BIT 8839169689Skan && TYPE_MAIN_VARIANT (type) == long_double_type_node 8840169689Skan && TARGET_LONG_DOUBLE_128) 8841169689Skan return "g"; 8842169689Skan 8843169689Skan /* For all other types, use normal C++ mangling. */ 8844169689Skan return NULL; 8845169689Skan} 8846169689Skan#endif 8847169689Skan 8848169689Skan/* Expand code to perform a 8 or 16-bit compare and swap by doing 32-bit 8849169689Skan compare and swap on the word containing the byte or half-word. */ 8850169689Skan 8851169689Skanvoid 8852169689Skansparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval) 8853169689Skan{ 8854169689Skan rtx addr1 = force_reg (Pmode, XEXP (mem, 0)); 8855169689Skan rtx addr = gen_reg_rtx (Pmode); 8856169689Skan rtx off = gen_reg_rtx (SImode); 8857169689Skan rtx oldv = gen_reg_rtx (SImode); 8858169689Skan rtx newv = gen_reg_rtx (SImode); 8859169689Skan rtx oldvalue = gen_reg_rtx (SImode); 8860169689Skan rtx newvalue = gen_reg_rtx (SImode); 8861169689Skan rtx res = gen_reg_rtx (SImode); 8862169689Skan rtx resv = gen_reg_rtx (SImode); 8863169689Skan rtx memsi, val, mask, end_label, loop_label, cc; 8864169689Skan 8865169689Skan emit_insn (gen_rtx_SET (VOIDmode, addr, 8866169689Skan gen_rtx_AND (Pmode, addr1, GEN_INT (-4)))); 8867169689Skan 8868169689Skan if (Pmode != SImode) 8869169689Skan addr1 = gen_lowpart (SImode, addr1); 8870169689Skan emit_insn (gen_rtx_SET (VOIDmode, off, 8871169689Skan gen_rtx_AND (SImode, addr1, GEN_INT (3)))); 8872169689Skan 8873169689Skan memsi = gen_rtx_MEM (SImode, addr); 8874169689Skan set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER); 8875169689Skan MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem); 8876169689Skan 8877169689Skan val = force_reg (SImode, memsi); 8878169689Skan 8879169689Skan emit_insn (gen_rtx_SET (VOIDmode, off, 8880169689Skan gen_rtx_XOR (SImode, off, 8881169689Skan GEN_INT (GET_MODE (mem) == QImode 8882169689Skan ? 3 : 2)))); 8883169689Skan 8884169689Skan emit_insn (gen_rtx_SET (VOIDmode, off, 8885169689Skan gen_rtx_ASHIFT (SImode, off, GEN_INT (3)))); 8886169689Skan 8887169689Skan if (GET_MODE (mem) == QImode) 8888169689Skan mask = force_reg (SImode, GEN_INT (0xff)); 8889169689Skan else 8890169689Skan mask = force_reg (SImode, GEN_INT (0xffff)); 8891169689Skan 8892169689Skan emit_insn (gen_rtx_SET (VOIDmode, mask, 8893169689Skan gen_rtx_ASHIFT (SImode, mask, off))); 8894169689Skan 8895169689Skan emit_insn (gen_rtx_SET (VOIDmode, val, 8896169689Skan gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask), 8897169689Skan val))); 8898169689Skan 8899169689Skan oldval = gen_lowpart (SImode, oldval); 8900169689Skan emit_insn (gen_rtx_SET (VOIDmode, oldv, 8901169689Skan gen_rtx_ASHIFT (SImode, oldval, off))); 8902169689Skan 8903169689Skan newval = gen_lowpart_common (SImode, newval); 8904169689Skan emit_insn (gen_rtx_SET (VOIDmode, newv, 8905169689Skan gen_rtx_ASHIFT (SImode, newval, off))); 8906169689Skan 8907169689Skan emit_insn (gen_rtx_SET (VOIDmode, oldv, 8908169689Skan gen_rtx_AND (SImode, oldv, mask))); 8909169689Skan 8910169689Skan emit_insn (gen_rtx_SET (VOIDmode, newv, 8911169689Skan gen_rtx_AND (SImode, newv, mask))); 8912169689Skan 8913169689Skan end_label = gen_label_rtx (); 8914169689Skan loop_label = gen_label_rtx (); 8915169689Skan emit_label (loop_label); 8916169689Skan 8917169689Skan emit_insn (gen_rtx_SET (VOIDmode, oldvalue, 8918169689Skan gen_rtx_IOR (SImode, oldv, val))); 8919169689Skan 8920169689Skan emit_insn (gen_rtx_SET (VOIDmode, newvalue, 8921169689Skan gen_rtx_IOR (SImode, newv, val))); 8922169689Skan 8923169689Skan emit_insn (gen_sync_compare_and_swapsi (res, memsi, oldvalue, newvalue)); 8924169689Skan 8925169689Skan emit_cmp_and_jump_insns (res, oldvalue, EQ, NULL, SImode, 0, end_label); 8926169689Skan 8927169689Skan emit_insn (gen_rtx_SET (VOIDmode, resv, 8928169689Skan gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask), 8929169689Skan res))); 8930169689Skan 8931169689Skan sparc_compare_op0 = resv; 8932169689Skan sparc_compare_op1 = val; 8933169689Skan cc = gen_compare_reg (NE); 8934169689Skan 8935169689Skan emit_insn (gen_rtx_SET (VOIDmode, val, resv)); 8936169689Skan 8937169689Skan sparc_compare_emitted = cc; 8938169689Skan emit_jump_insn (gen_bne (loop_label)); 8939169689Skan 8940169689Skan emit_label (end_label); 8941169689Skan 8942169689Skan emit_insn (gen_rtx_SET (VOIDmode, res, 8943169689Skan gen_rtx_AND (SImode, res, mask))); 8944169689Skan 8945169689Skan emit_insn (gen_rtx_SET (VOIDmode, res, 8946169689Skan gen_rtx_LSHIFTRT (SImode, res, off))); 8947169689Skan 8948169689Skan emit_move_insn (result, gen_lowpart (GET_MODE (result), res)); 8949169689Skan} 8950169689Skan 8951117395Skan#include "gt-sparc.h" 8952