sparc.c revision 119256
150397Sobrien/* Subroutines for insn-output.c for Sun SPARC. 272562Sobrien Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3117395Skan 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 450397Sobrien Contributed by Michael Tiemann (tiemann@cygnus.com) 550397Sobrien 64 bit SPARC V9 support by Michael Tiemann, Jim Wilson, and Doug Evans, 650397Sobrien at Cygnus Support. 750397Sobrien 850397SobrienThis file is part of GNU CC. 950397Sobrien 1050397SobrienGNU CC is free software; you can redistribute it and/or modify 1150397Sobrienit under the terms of the GNU General Public License as published by 1250397Sobrienthe Free Software Foundation; either version 2, or (at your option) 1350397Sobrienany later version. 1450397Sobrien 1550397SobrienGNU CC is distributed in the hope that it will be useful, 1650397Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1750397SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1850397SobrienGNU General Public License for more details. 1950397Sobrien 2050397SobrienYou should have received a copy of the GNU General Public License 2150397Sobrienalong with GNU CC; see the file COPYING. If not, write to 2250397Sobrienthe Free Software Foundation, 59 Temple Place - Suite 330, 2350397SobrienBoston, MA 02111-1307, USA. */ 2450397Sobrien 2550397Sobrien#include "config.h" 2650397Sobrien#include "system.h" 2750397Sobrien#include "tree.h" 2850397Sobrien#include "rtl.h" 2950397Sobrien#include "regs.h" 3050397Sobrien#include "hard-reg-set.h" 3150397Sobrien#include "real.h" 3250397Sobrien#include "insn-config.h" 3350397Sobrien#include "conditions.h" 3450397Sobrien#include "output.h" 3550397Sobrien#include "insn-attr.h" 3650397Sobrien#include "flags.h" 3790075Sobrien#include "function.h" 3850397Sobrien#include "expr.h" 3990075Sobrien#include "optabs.h" 4090075Sobrien#include "libfuncs.h" 4150397Sobrien#include "recog.h" 4250397Sobrien#include "toplev.h" 4390075Sobrien#include "ggc.h" 4490075Sobrien#include "tm_p.h" 4590075Sobrien#include "debug.h" 4690075Sobrien#include "target.h" 4790075Sobrien#include "target-def.h" 4850397Sobrien 4950397Sobrien/* 1 if the caller has placed an "unimp" insn immediately after the call. 5050397Sobrien This is used in v8 code when calling a function that returns a structure. 5150397Sobrien v9 doesn't have this. Be careful to have this test be the same as that 5250397Sobrien used on the call. */ 5350397Sobrien 5450397Sobrien#define SKIP_CALLERS_UNIMP_P \ 5550397Sobrien(!TARGET_ARCH64 && current_function_returns_struct \ 5650397Sobrien && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))) \ 5750397Sobrien && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl))) \ 5850397Sobrien == INTEGER_CST)) 5950397Sobrien 6050397Sobrien/* Global variables for machine-dependent things. */ 6150397Sobrien 6250397Sobrien/* Size of frame. Need to know this to emit return insns from leaf procedures. 6350397Sobrien ACTUAL_FSIZE is set by compute_frame_size() which is called during the 6450397Sobrien reload pass. This is important as the value is later used in insn 6550397Sobrien scheduling (to see what can go in a delay slot). 6650397Sobrien APPARENT_FSIZE is the size of the stack less the register save area and less 6750397Sobrien the outgoing argument area. It is used when saving call preserved regs. */ 6850397Sobrienstatic int apparent_fsize; 6950397Sobrienstatic int actual_fsize; 7050397Sobrien 7196263Sobrien/* Number of live general or floating point registers needed to be 7296263Sobrien saved (as 4-byte quantities). */ 7390075Sobrienstatic int num_gfregs; 7490075Sobrien 7550397Sobrien/* Save the operands last given to a compare for use when we 7650397Sobrien generate a scc or bcc insn. */ 7750397Sobrienrtx sparc_compare_op0, sparc_compare_op1; 7850397Sobrien 7996263Sobrien/* Coordinate with the md file wrt special insns created by 8096263Sobrien sparc_nonflat_function_epilogue. */ 8196263Sobrienbool sparc_emitting_epilogue; 8250397Sobrien 8396263Sobrien/* Vector to say how input registers are mapped to output registers. 8496263Sobrien HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to 8596263Sobrien eliminate it. You must use -fomit-frame-pointer to get that. */ 8696263Sobrienchar leaf_reg_remap[] = 8750397Sobrien{ 0, 1, 2, 3, 4, 5, 6, 7, 8850397Sobrien -1, -1, -1, -1, -1, -1, 14, -1, 8950397Sobrien -1, -1, -1, -1, -1, -1, -1, -1, 9050397Sobrien 8, 9, 10, 11, 12, 13, -1, 15, 9150397Sobrien 9250397Sobrien 32, 33, 34, 35, 36, 37, 38, 39, 9350397Sobrien 40, 41, 42, 43, 44, 45, 46, 47, 9450397Sobrien 48, 49, 50, 51, 52, 53, 54, 55, 9550397Sobrien 56, 57, 58, 59, 60, 61, 62, 63, 9650397Sobrien 64, 65, 66, 67, 68, 69, 70, 71, 9750397Sobrien 72, 73, 74, 75, 76, 77, 78, 79, 9850397Sobrien 80, 81, 82, 83, 84, 85, 86, 87, 9950397Sobrien 88, 89, 90, 91, 92, 93, 94, 95, 10050397Sobrien 96, 97, 98, 99, 100}; 10150397Sobrien 10290075Sobrien/* Vector, indexed by hard register number, which contains 1 10390075Sobrien for a register that is allowable in a candidate for leaf 10490075Sobrien function treatment. */ 10590075Sobrienchar sparc_leaf_regs[] = 10690075Sobrien{ 1, 1, 1, 1, 1, 1, 1, 1, 10790075Sobrien 0, 0, 0, 0, 0, 0, 1, 0, 10890075Sobrien 0, 0, 0, 0, 0, 0, 0, 0, 10990075Sobrien 1, 1, 1, 1, 1, 1, 0, 1, 11090075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 11190075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 11290075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 11390075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 11490075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 11590075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 11690075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 11790075Sobrien 1, 1, 1, 1, 1, 1, 1, 1, 11890075Sobrien 1, 1, 1, 1, 1}; 11990075Sobrien 12050397Sobrien/* Name of where we pretend to think the frame pointer points. 12150397Sobrien Normally, this is "%fp", but if we are in a leaf procedure, 12250397Sobrien this is "%sp+something". We record "something" separately as it may be 12350397Sobrien too big for reg+constant addressing. */ 12450397Sobrien 12552284Sobrienstatic const char *frame_base_name; 12650397Sobrienstatic int frame_base_offset; 12750397Sobrien 12890075Sobrienstatic void sparc_init_modes PARAMS ((void)); 12990075Sobrienstatic int save_regs PARAMS ((FILE *, int, int, const char *, 13050397Sobrien int, int, int)); 13190075Sobrienstatic int restore_regs PARAMS ((FILE *, int, int, const char *, int, int)); 13290075Sobrienstatic void build_big_number PARAMS ((FILE *, int, const char *)); 13390075Sobrienstatic int function_arg_slotno PARAMS ((const CUMULATIVE_ARGS *, 13450397Sobrien enum machine_mode, tree, int, int, 13550397Sobrien int *, int *)); 13650397Sobrien 13790075Sobrienstatic int supersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int)); 13890075Sobrienstatic int hypersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int)); 13952284Sobrien 14090075Sobrienstatic void sparc_output_addr_vec PARAMS ((rtx)); 14190075Sobrienstatic void sparc_output_addr_diff_vec PARAMS ((rtx)); 14290075Sobrienstatic void sparc_output_deferred_case_vectors PARAMS ((void)); 14390075Sobrienstatic int check_return_regs PARAMS ((rtx)); 14490075Sobrienstatic int epilogue_renumber PARAMS ((rtx *, int)); 14590075Sobrienstatic bool sparc_assemble_integer PARAMS ((rtx, unsigned int, int)); 14690075Sobrienstatic int set_extends PARAMS ((rtx)); 14790075Sobrienstatic void output_restore_regs PARAMS ((FILE *, int)); 14890075Sobrienstatic void sparc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); 14990075Sobrienstatic void sparc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); 15090075Sobrienstatic void sparc_flat_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); 15190075Sobrienstatic void sparc_flat_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); 15290075Sobrienstatic void sparc_nonflat_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT, 15390075Sobrien int)); 15490075Sobrienstatic void sparc_nonflat_function_prologue PARAMS ((FILE *, HOST_WIDE_INT, 15590075Sobrien int)); 15690075Sobrien#ifdef OBJECT_FORMAT_ELF 15790075Sobrienstatic void sparc_elf_asm_named_section PARAMS ((const char *, unsigned int)); 15890075Sobrien#endif 159117395Skanstatic void sparc_aout_select_section PARAMS ((tree, int, 160117395Skan unsigned HOST_WIDE_INT)) 161117395Skan ATTRIBUTE_UNUSED; 162117395Skanstatic void sparc_aout_select_rtx_section PARAMS ((enum machine_mode, rtx, 163117395Skan unsigned HOST_WIDE_INT)) 164117395Skan ATTRIBUTE_UNUSED; 16552284Sobrien 16690075Sobrienstatic int sparc_adjust_cost PARAMS ((rtx, rtx, rtx, int)); 16790075Sobrienstatic int sparc_issue_rate PARAMS ((void)); 16890075Sobrienstatic void sparc_sched_init PARAMS ((FILE *, int, int)); 169117395Skanstatic int sparc_use_dfa_pipeline_interface PARAMS ((void)); 170117395Skanstatic int sparc_use_sched_lookahead PARAMS ((void)); 17196263Sobrien 17296263Sobrienstatic void emit_soft_tfmode_libcall PARAMS ((const char *, int, rtx *)); 17396263Sobrienstatic void emit_soft_tfmode_binop PARAMS ((enum rtx_code, rtx *)); 17496263Sobrienstatic void emit_soft_tfmode_unop PARAMS ((enum rtx_code, rtx *)); 17596263Sobrienstatic void emit_soft_tfmode_cvt PARAMS ((enum rtx_code, rtx *)); 17696263Sobrienstatic void emit_hard_tfmode_operation PARAMS ((enum rtx_code, rtx *)); 177117395Skan 178117395Skanstatic void sparc_encode_section_info PARAMS ((tree, int)); 179117395Skanstatic void sparc_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, 180117395Skan HOST_WIDE_INT, tree)); 18150397Sobrien 18250397Sobrien/* Option handling. */ 18350397Sobrien 18450397Sobrien/* Code model option as passed by user. */ 18552284Sobrienconst char *sparc_cmodel_string; 18650397Sobrien/* Parsed value. */ 18750397Sobrienenum cmodel sparc_cmodel; 18850397Sobrien 18990075Sobrienchar sparc_hard_reg_printed[8]; 19050397Sobrien 19150397Sobrienstruct sparc_cpu_select sparc_select[] = 19250397Sobrien{ 19350397Sobrien /* switch name, tune arch */ 19450397Sobrien { (char *)0, "default", 1, 1 }, 19550397Sobrien { (char *)0, "-mcpu=", 1, 1 }, 19650397Sobrien { (char *)0, "-mtune=", 1, 0 }, 19750397Sobrien { 0, 0, 0, 0 } 19850397Sobrien}; 19950397Sobrien 20050397Sobrien/* CPU type. This is set from TARGET_CPU_DEFAULT and -m{cpu,tune}=xxx. */ 20150397Sobrienenum processor_type sparc_cpu; 20290075Sobrien 20390075Sobrien/* Initialize the GCC target structure. */ 20450397Sobrien 20590075Sobrien/* The sparc default is to use .half rather than .short for aligned 20690075Sobrien HI objects. Use .word instead of .long on non-ELF systems. */ 20790075Sobrien#undef TARGET_ASM_ALIGNED_HI_OP 20890075Sobrien#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" 20990075Sobrien#ifndef OBJECT_FORMAT_ELF 21090075Sobrien#undef TARGET_ASM_ALIGNED_SI_OP 21190075Sobrien#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" 21290075Sobrien#endif 21390075Sobrien 21490075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP 21590075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\t.uahalf\t" 21690075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP 21790075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\t.uaword\t" 21890075Sobrien#undef TARGET_ASM_UNALIGNED_DI_OP 21990075Sobrien#define TARGET_ASM_UNALIGNED_DI_OP "\t.uaxword\t" 22090075Sobrien 22190075Sobrien/* The target hook has to handle DI-mode values. */ 22290075Sobrien#undef TARGET_ASM_INTEGER 22390075Sobrien#define TARGET_ASM_INTEGER sparc_assemble_integer 22490075Sobrien 22590075Sobrien#undef TARGET_ASM_FUNCTION_PROLOGUE 22690075Sobrien#define TARGET_ASM_FUNCTION_PROLOGUE sparc_output_function_prologue 22790075Sobrien#undef TARGET_ASM_FUNCTION_EPILOGUE 22890075Sobrien#define TARGET_ASM_FUNCTION_EPILOGUE sparc_output_function_epilogue 22990075Sobrien 23090075Sobrien#undef TARGET_SCHED_ADJUST_COST 23190075Sobrien#define TARGET_SCHED_ADJUST_COST sparc_adjust_cost 23290075Sobrien#undef TARGET_SCHED_ISSUE_RATE 23390075Sobrien#define TARGET_SCHED_ISSUE_RATE sparc_issue_rate 23490075Sobrien#undef TARGET_SCHED_INIT 23590075Sobrien#define TARGET_SCHED_INIT sparc_sched_init 236117395Skan#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE 237117395Skan#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE sparc_use_dfa_pipeline_interface 238117395Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD 239117395Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead 24090075Sobrien 241117395Skan#undef TARGET_ENCODE_SECTION_INFO 242117395Skan#define TARGET_ENCODE_SECTION_INFO sparc_encode_section_info 243117395Skan 244117395Skan#undef TARGET_ASM_OUTPUT_MI_THUNK 245117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk 246117395Skan#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK 247117395Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall 248117395Skan 24990075Sobrienstruct gcc_target targetm = TARGET_INITIALIZER; 25090075Sobrien 25150397Sobrien/* Validate and override various options, and do some machine dependent 25250397Sobrien initialization. */ 25350397Sobrien 25450397Sobrienvoid 25550397Sobriensparc_override_options () 25650397Sobrien{ 25750397Sobrien static struct code_model { 25890075Sobrien const char *const name; 25990075Sobrien const int value; 26090075Sobrien } const cmodels[] = { 26150397Sobrien { "32", CM_32 }, 26250397Sobrien { "medlow", CM_MEDLOW }, 26350397Sobrien { "medmid", CM_MEDMID }, 26450397Sobrien { "medany", CM_MEDANY }, 26550397Sobrien { "embmedany", CM_EMBMEDANY }, 26650397Sobrien { 0, 0 } 26750397Sobrien }; 26890075Sobrien const struct code_model *cmodel; 26950397Sobrien /* Map TARGET_CPU_DEFAULT to value for -m{arch,tune}=. */ 27050397Sobrien static struct cpu_default { 27190075Sobrien const int cpu; 27290075Sobrien const char *const name; 27390075Sobrien } const cpu_default[] = { 27450397Sobrien /* There must be one entry here for each TARGET_CPU value. */ 27550397Sobrien { TARGET_CPU_sparc, "cypress" }, 27650397Sobrien { TARGET_CPU_sparclet, "tsc701" }, 27750397Sobrien { TARGET_CPU_sparclite, "f930" }, 27850397Sobrien { TARGET_CPU_v8, "v8" }, 27952284Sobrien { TARGET_CPU_hypersparc, "hypersparc" }, 28052284Sobrien { TARGET_CPU_sparclite86x, "sparclite86x" }, 28150397Sobrien { TARGET_CPU_supersparc, "supersparc" }, 28250397Sobrien { TARGET_CPU_v9, "v9" }, 28350397Sobrien { TARGET_CPU_ultrasparc, "ultrasparc" }, 284117395Skan { TARGET_CPU_ultrasparc3, "ultrasparc3" }, 28550397Sobrien { 0, 0 } 28650397Sobrien }; 28790075Sobrien const struct cpu_default *def; 28850397Sobrien /* Table of values for -m{cpu,tune}=. */ 28950397Sobrien static struct cpu_table { 29090075Sobrien const char *const name; 29190075Sobrien const enum processor_type processor; 29290075Sobrien const int disable; 29390075Sobrien const int enable; 29490075Sobrien } const cpu_table[] = { 29550397Sobrien { "v7", PROCESSOR_V7, MASK_ISA, 0 }, 29650397Sobrien { "cypress", PROCESSOR_CYPRESS, MASK_ISA, 0 }, 29750397Sobrien { "v8", PROCESSOR_V8, MASK_ISA, MASK_V8 }, 29850397Sobrien /* TI TMS390Z55 supersparc */ 29950397Sobrien { "supersparc", PROCESSOR_SUPERSPARC, MASK_ISA, MASK_V8 }, 30050397Sobrien { "sparclite", PROCESSOR_SPARCLITE, MASK_ISA, MASK_SPARCLITE }, 30150397Sobrien /* The Fujitsu MB86930 is the original sparclite chip, with no fpu. 30250397Sobrien The Fujitsu MB86934 is the recent sparclite chip, with an fpu. */ 30350397Sobrien { "f930", PROCESSOR_F930, MASK_ISA|MASK_FPU, MASK_SPARCLITE }, 30450397Sobrien { "f934", PROCESSOR_F934, MASK_ISA, MASK_SPARCLITE|MASK_FPU }, 30552284Sobrien { "hypersparc", PROCESSOR_HYPERSPARC, MASK_ISA, MASK_V8|MASK_FPU }, 30690075Sobrien { "sparclite86x", PROCESSOR_SPARCLITE86X, MASK_ISA|MASK_FPU, 30790075Sobrien MASK_SPARCLITE }, 30850397Sobrien { "sparclet", PROCESSOR_SPARCLET, MASK_ISA, MASK_SPARCLET }, 30950397Sobrien /* TEMIC sparclet */ 31050397Sobrien { "tsc701", PROCESSOR_TSC701, MASK_ISA, MASK_SPARCLET }, 31150397Sobrien { "v9", PROCESSOR_V9, MASK_ISA, MASK_V9 }, 31290075Sobrien /* TI ultrasparc I, II, IIi */ 31390075Sobrien { "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, MASK_V9 31490075Sobrien /* Although insns using %y are deprecated, it is a clear win on current 31590075Sobrien ultrasparcs. */ 31690075Sobrien |MASK_DEPRECATED_V8_INSNS}, 317117395Skan /* TI ultrasparc III */ 318117395Skan /* ??? Check if %y issue still holds true in ultra3. */ 319117395Skan { "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS}, 32050397Sobrien { 0, 0, 0, 0 } 32150397Sobrien }; 32290075Sobrien const struct cpu_table *cpu; 32390075Sobrien const struct sparc_cpu_select *sel; 32450397Sobrien int fpu; 32552284Sobrien 32650397Sobrien#ifndef SPARC_BI_ARCH 32750397Sobrien /* Check for unsupported architecture size. */ 32850397Sobrien if (! TARGET_64BIT != DEFAULT_ARCH32_P) 32990075Sobrien error ("%s is not supported by this configuration", 33090075Sobrien DEFAULT_ARCH32_P ? "-m64" : "-m32"); 33150397Sobrien#endif 33250397Sobrien 33390075Sobrien /* We force all 64bit archs to use 128 bit long double */ 33490075Sobrien if (TARGET_64BIT && ! TARGET_LONG_DOUBLE_128) 33552284Sobrien { 33690075Sobrien error ("-mlong-double-64 not allowed with -m64"); 33790075Sobrien target_flags |= MASK_LONG_DOUBLE_128; 33852284Sobrien } 33952284Sobrien 34050397Sobrien /* Code model selection. */ 34150397Sobrien sparc_cmodel = SPARC_DEFAULT_CMODEL; 34252284Sobrien 34352284Sobrien#ifdef SPARC_BI_ARCH 34452284Sobrien if (TARGET_ARCH32) 34552284Sobrien sparc_cmodel = CM_32; 34652284Sobrien#endif 34752284Sobrien 34850397Sobrien if (sparc_cmodel_string != NULL) 34950397Sobrien { 35050397Sobrien if (TARGET_ARCH64) 35150397Sobrien { 35250397Sobrien for (cmodel = &cmodels[0]; cmodel->name; cmodel++) 35350397Sobrien if (strcmp (sparc_cmodel_string, cmodel->name) == 0) 35450397Sobrien break; 35550397Sobrien if (cmodel->name == NULL) 35650397Sobrien error ("bad value (%s) for -mcmodel= switch", sparc_cmodel_string); 35750397Sobrien else 35850397Sobrien sparc_cmodel = cmodel->value; 35950397Sobrien } 36050397Sobrien else 36150397Sobrien error ("-mcmodel= is not supported on 32 bit systems"); 36250397Sobrien } 36350397Sobrien 36450397Sobrien fpu = TARGET_FPU; /* save current -mfpu status */ 36550397Sobrien 36650397Sobrien /* Set the default CPU. */ 36750397Sobrien for (def = &cpu_default[0]; def->name; ++def) 36850397Sobrien if (def->cpu == TARGET_CPU_DEFAULT) 36950397Sobrien break; 37050397Sobrien if (! def->name) 37150397Sobrien abort (); 37250397Sobrien sparc_select[0].string = def->name; 37350397Sobrien 37450397Sobrien for (sel = &sparc_select[0]; sel->name; ++sel) 37550397Sobrien { 37650397Sobrien if (sel->string) 37750397Sobrien { 37850397Sobrien for (cpu = &cpu_table[0]; cpu->name; ++cpu) 37950397Sobrien if (! strcmp (sel->string, cpu->name)) 38050397Sobrien { 38150397Sobrien if (sel->set_tune_p) 38250397Sobrien sparc_cpu = cpu->processor; 38350397Sobrien 38450397Sobrien if (sel->set_arch_p) 38550397Sobrien { 38650397Sobrien target_flags &= ~cpu->disable; 38750397Sobrien target_flags |= cpu->enable; 38850397Sobrien } 38950397Sobrien break; 39050397Sobrien } 39150397Sobrien 39250397Sobrien if (! cpu->name) 39350397Sobrien error ("bad value (%s) for %s switch", sel->string, sel->name); 39450397Sobrien } 39550397Sobrien } 39650397Sobrien 39750397Sobrien /* If -mfpu or -mno-fpu was explicitly used, don't override with 39890075Sobrien the processor default. Clear MASK_FPU_SET to avoid confusing 39990075Sobrien the reverse mapping from switch values to names. */ 40050397Sobrien if (TARGET_FPU_SET) 40190075Sobrien { 40290075Sobrien target_flags = (target_flags & ~MASK_FPU) | fpu; 40390075Sobrien target_flags &= ~MASK_FPU_SET; 40490075Sobrien } 40550397Sobrien 40690075Sobrien /* Don't allow -mvis if FPU is disabled. */ 40790075Sobrien if (! TARGET_FPU) 40890075Sobrien target_flags &= ~MASK_VIS; 40990075Sobrien 41090075Sobrien /* -mvis assumes UltraSPARC+, so we are sure v9 instructions 41190075Sobrien are available. 41290075Sobrien -m64 also implies v9. */ 41390075Sobrien if (TARGET_VIS || TARGET_ARCH64) 41490075Sobrien { 41590075Sobrien target_flags |= MASK_V9; 41690075Sobrien target_flags &= ~(MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE); 41790075Sobrien } 41890075Sobrien 41950397Sobrien /* Use the deprecated v8 insns for sparc64 in 32 bit mode. */ 42050397Sobrien if (TARGET_V9 && TARGET_ARCH32) 42150397Sobrien target_flags |= MASK_DEPRECATED_V8_INSNS; 42250397Sobrien 42352284Sobrien /* V8PLUS requires V9, makes no sense in 64 bit mode. */ 42452284Sobrien if (! TARGET_V9 || TARGET_ARCH64) 42550397Sobrien target_flags &= ~MASK_V8PLUS; 42650397Sobrien 42750397Sobrien /* Don't use stack biasing in 32 bit mode. */ 42850397Sobrien if (TARGET_ARCH32) 42950397Sobrien target_flags &= ~MASK_STACK_BIAS; 43052284Sobrien 43190075Sobrien /* Supply a default value for align_functions. */ 432117395Skan if (align_functions == 0 433117395Skan && (sparc_cpu == PROCESSOR_ULTRASPARC 434117395Skan || sparc_cpu == PROCESSOR_ULTRASPARC3)) 43590075Sobrien align_functions = 32; 43650397Sobrien 43750397Sobrien /* Validate PCC_STRUCT_RETURN. */ 43850397Sobrien if (flag_pcc_struct_return == DEFAULT_PCC_STRUCT_RETURN) 43950397Sobrien flag_pcc_struct_return = (TARGET_ARCH64 ? 0 : 1); 44050397Sobrien 44190075Sobrien /* Only use .uaxword when compiling for a 64-bit target. */ 44290075Sobrien if (!TARGET_ARCH64) 44390075Sobrien targetm.asm_out.unaligned_op.di = NULL; 44490075Sobrien 44550397Sobrien /* Do various machine dependent initializations. */ 44650397Sobrien sparc_init_modes (); 44750397Sobrien} 44850397Sobrien 44950397Sobrien/* Miscellaneous utilities. */ 45050397Sobrien 45150397Sobrien/* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move 45250397Sobrien or branch on register contents instructions. */ 45350397Sobrien 45450397Sobrienint 45550397Sobrienv9_regcmp_p (code) 45650397Sobrien enum rtx_code code; 45750397Sobrien{ 45850397Sobrien return (code == EQ || code == NE || code == GE || code == LT 45950397Sobrien || code == LE || code == GT); 46050397Sobrien} 46150397Sobrien 46250397Sobrien 46350397Sobrien/* Operand constraints. */ 46450397Sobrien 465117395Skan/* Return nonzero only if OP is a register of mode MODE, 46690075Sobrien or const0_rtx. */ 46750397Sobrien 46850397Sobrienint 46950397Sobrienreg_or_0_operand (op, mode) 47050397Sobrien rtx op; 47150397Sobrien enum machine_mode mode; 47250397Sobrien{ 47350397Sobrien if (register_operand (op, mode)) 47450397Sobrien return 1; 47550397Sobrien if (op == const0_rtx) 47650397Sobrien return 1; 47750397Sobrien if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE 47850397Sobrien && CONST_DOUBLE_HIGH (op) == 0 47950397Sobrien && CONST_DOUBLE_LOW (op) == 0) 48050397Sobrien return 1; 48190075Sobrien if (fp_zero_operand (op, mode)) 48250397Sobrien return 1; 48350397Sobrien return 0; 48450397Sobrien} 48550397Sobrien 486117395Skan/* Return nonzero only if OP is const1_rtx. */ 487117395Skan 488117395Skanint 489117395Skanconst1_operand (op, mode) 490117395Skan rtx op; 491117395Skan enum machine_mode mode ATTRIBUTE_UNUSED; 492117395Skan{ 493117395Skan return op == const1_rtx; 494117395Skan} 495117395Skan 49650397Sobrien/* Nonzero if OP is a floating point value with value 0.0. */ 49750397Sobrien 49850397Sobrienint 49990075Sobrienfp_zero_operand (op, mode) 50050397Sobrien rtx op; 50190075Sobrien enum machine_mode mode; 50250397Sobrien{ 50390075Sobrien if (GET_MODE_CLASS (GET_MODE (op)) != MODE_FLOAT) 50490075Sobrien return 0; 50590075Sobrien return op == CONST0_RTX (mode); 50690075Sobrien} 50750397Sobrien 50896263Sobrien/* Nonzero if OP is a register operand in floating point register. */ 50996263Sobrien 51096263Sobrienint 51196263Sobrienfp_register_operand (op, mode) 51296263Sobrien rtx op; 51396263Sobrien enum machine_mode mode; 51496263Sobrien{ 51596263Sobrien if (! register_operand (op, mode)) 51696263Sobrien return 0; 51796263Sobrien if (GET_CODE (op) == SUBREG) 51896263Sobrien op = SUBREG_REG (op); 51996263Sobrien return GET_CODE (op) == REG && SPARC_FP_REG_P (REGNO (op)); 52096263Sobrien} 52196263Sobrien 52290075Sobrien/* Nonzero if OP is a floating point constant which can 52390075Sobrien be loaded into an integer register using a single 52490075Sobrien sethi instruction. */ 52590075Sobrien 52690075Sobrienint 52790075Sobrienfp_sethi_p (op) 52890075Sobrien rtx op; 52990075Sobrien{ 53090075Sobrien if (GET_CODE (op) == CONST_DOUBLE) 53190075Sobrien { 53290075Sobrien REAL_VALUE_TYPE r; 53390075Sobrien long i; 53490075Sobrien 53590075Sobrien REAL_VALUE_FROM_CONST_DOUBLE (r, op); 53690075Sobrien if (REAL_VALUES_EQUAL (r, dconst0) && 53790075Sobrien ! REAL_VALUE_MINUS_ZERO (r)) 53890075Sobrien return 0; 53990075Sobrien REAL_VALUE_TO_TARGET_SINGLE (r, i); 54090075Sobrien if (SPARC_SETHI_P (i)) 54190075Sobrien return 1; 54290075Sobrien } 54390075Sobrien 54490075Sobrien return 0; 54550397Sobrien} 54650397Sobrien 54790075Sobrien/* Nonzero if OP is a floating point constant which can 54890075Sobrien be loaded into an integer register using a single 54990075Sobrien mov instruction. */ 55090075Sobrien 55190075Sobrienint 55290075Sobrienfp_mov_p (op) 55390075Sobrien rtx op; 55490075Sobrien{ 55590075Sobrien if (GET_CODE (op) == CONST_DOUBLE) 55690075Sobrien { 55790075Sobrien REAL_VALUE_TYPE r; 55890075Sobrien long i; 55990075Sobrien 56090075Sobrien REAL_VALUE_FROM_CONST_DOUBLE (r, op); 56190075Sobrien if (REAL_VALUES_EQUAL (r, dconst0) && 56290075Sobrien ! REAL_VALUE_MINUS_ZERO (r)) 56390075Sobrien return 0; 56490075Sobrien REAL_VALUE_TO_TARGET_SINGLE (r, i); 56590075Sobrien if (SPARC_SIMM13_P (i)) 56690075Sobrien return 1; 56790075Sobrien } 56890075Sobrien 56990075Sobrien return 0; 57090075Sobrien} 57190075Sobrien 57290075Sobrien/* Nonzero if OP is a floating point constant which can 57390075Sobrien be loaded into an integer register using a high/losum 57490075Sobrien instruction sequence. */ 57590075Sobrien 57690075Sobrienint 57790075Sobrienfp_high_losum_p (op) 57890075Sobrien rtx op; 57990075Sobrien{ 58090075Sobrien /* The constraints calling this should only be in 58190075Sobrien SFmode move insns, so any constant which cannot 58290075Sobrien be moved using a single insn will do. */ 58390075Sobrien if (GET_CODE (op) == CONST_DOUBLE) 58490075Sobrien { 58590075Sobrien REAL_VALUE_TYPE r; 58690075Sobrien long i; 58790075Sobrien 58890075Sobrien REAL_VALUE_FROM_CONST_DOUBLE (r, op); 58990075Sobrien if (REAL_VALUES_EQUAL (r, dconst0) && 59090075Sobrien ! REAL_VALUE_MINUS_ZERO (r)) 59190075Sobrien return 0; 59290075Sobrien REAL_VALUE_TO_TARGET_SINGLE (r, i); 59390075Sobrien if (! SPARC_SETHI_P (i) 59490075Sobrien && ! SPARC_SIMM13_P (i)) 59590075Sobrien return 1; 59690075Sobrien } 59790075Sobrien 59890075Sobrien return 0; 59990075Sobrien} 60090075Sobrien 60150397Sobrien/* Nonzero if OP is an integer register. */ 60250397Sobrien 60350397Sobrienint 60450397Sobrienintreg_operand (op, mode) 60550397Sobrien rtx op; 60650397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 60750397Sobrien{ 60850397Sobrien return (register_operand (op, SImode) 60950397Sobrien || (TARGET_ARCH64 && register_operand (op, DImode))); 61050397Sobrien} 61150397Sobrien 61250397Sobrien/* Nonzero if OP is a floating point condition code register. */ 61350397Sobrien 61450397Sobrienint 61550397Sobrienfcc_reg_operand (op, mode) 61650397Sobrien rtx op; 61750397Sobrien enum machine_mode mode; 61850397Sobrien{ 61950397Sobrien /* This can happen when recog is called from combine. Op may be a MEM. 62050397Sobrien Fail instead of calling abort in this case. */ 62150397Sobrien if (GET_CODE (op) != REG) 62250397Sobrien return 0; 62350397Sobrien 62450397Sobrien if (mode != VOIDmode && mode != GET_MODE (op)) 62550397Sobrien return 0; 62650397Sobrien if (mode == VOIDmode 62750397Sobrien && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode)) 62850397Sobrien return 0; 62950397Sobrien 63050397Sobrien#if 0 /* ??? ==> 1 when %fcc0-3 are pseudos first. See gen_compare_reg(). */ 63150397Sobrien if (reg_renumber == 0) 63250397Sobrien return REGNO (op) >= FIRST_PSEUDO_REGISTER; 63350397Sobrien return REGNO_OK_FOR_CCFP_P (REGNO (op)); 63450397Sobrien#else 63550397Sobrien return (unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG < 4; 63650397Sobrien#endif 63750397Sobrien} 63850397Sobrien 63996263Sobrien/* Nonzero if OP is a floating point condition code fcc0 register. */ 64096263Sobrien 64196263Sobrienint 64296263Sobrienfcc0_reg_operand (op, mode) 64396263Sobrien rtx op; 64496263Sobrien enum machine_mode mode; 64596263Sobrien{ 64696263Sobrien /* This can happen when recog is called from combine. Op may be a MEM. 64796263Sobrien Fail instead of calling abort in this case. */ 64896263Sobrien if (GET_CODE (op) != REG) 64996263Sobrien return 0; 65096263Sobrien 65196263Sobrien if (mode != VOIDmode && mode != GET_MODE (op)) 65296263Sobrien return 0; 65396263Sobrien if (mode == VOIDmode 65496263Sobrien && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode)) 65596263Sobrien return 0; 65696263Sobrien 65796263Sobrien return REGNO (op) == SPARC_FCC_REG; 65896263Sobrien} 65996263Sobrien 66050397Sobrien/* Nonzero if OP is an integer or floating point condition code register. */ 66150397Sobrien 66250397Sobrienint 66350397Sobrienicc_or_fcc_reg_operand (op, mode) 66450397Sobrien rtx op; 66550397Sobrien enum machine_mode mode; 66650397Sobrien{ 66750397Sobrien if (GET_CODE (op) == REG && REGNO (op) == SPARC_ICC_REG) 66850397Sobrien { 66950397Sobrien if (mode != VOIDmode && mode != GET_MODE (op)) 67050397Sobrien return 0; 67150397Sobrien if (mode == VOIDmode 67250397Sobrien && GET_MODE (op) != CCmode && GET_MODE (op) != CCXmode) 67350397Sobrien return 0; 67450397Sobrien return 1; 67550397Sobrien } 67650397Sobrien 67750397Sobrien return fcc_reg_operand (op, mode); 67850397Sobrien} 67950397Sobrien 68050397Sobrien/* Nonzero if OP can appear as the dest of a RESTORE insn. */ 68150397Sobrienint 68250397Sobrienrestore_operand (op, mode) 68350397Sobrien rtx op; 68450397Sobrien enum machine_mode mode; 68550397Sobrien{ 68650397Sobrien return (GET_CODE (op) == REG && GET_MODE (op) == mode 68750397Sobrien && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32))); 68850397Sobrien} 68950397Sobrien 69050397Sobrien/* Call insn on SPARC can take a PC-relative constant address, or any regular 69150397Sobrien memory address. */ 69250397Sobrien 69350397Sobrienint 69450397Sobriencall_operand (op, mode) 69550397Sobrien rtx op; 69650397Sobrien enum machine_mode mode; 69750397Sobrien{ 69850397Sobrien if (GET_CODE (op) != MEM) 69950397Sobrien abort (); 70050397Sobrien op = XEXP (op, 0); 70150397Sobrien return (symbolic_operand (op, mode) || memory_address_p (Pmode, op)); 70250397Sobrien} 70350397Sobrien 70450397Sobrienint 70550397Sobriencall_operand_address (op, mode) 70650397Sobrien rtx op; 70750397Sobrien enum machine_mode mode; 70850397Sobrien{ 70950397Sobrien return (symbolic_operand (op, mode) || memory_address_p (Pmode, op)); 71050397Sobrien} 71150397Sobrien 71250397Sobrien/* Returns 1 if OP is either a symbol reference or a sum of a symbol 71350397Sobrien reference and a constant. */ 71450397Sobrien 71550397Sobrienint 71650397Sobriensymbolic_operand (op, mode) 71750397Sobrien register rtx op; 71850397Sobrien enum machine_mode mode; 71950397Sobrien{ 72090075Sobrien enum machine_mode omode = GET_MODE (op); 72190075Sobrien 72290075Sobrien if (omode != mode && omode != VOIDmode && mode != VOIDmode) 72390075Sobrien return 0; 72490075Sobrien 72550397Sobrien switch (GET_CODE (op)) 72650397Sobrien { 72750397Sobrien case SYMBOL_REF: 72850397Sobrien case LABEL_REF: 72950397Sobrien return 1; 73050397Sobrien 73150397Sobrien case CONST: 73250397Sobrien op = XEXP (op, 0); 73350397Sobrien return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF 73450397Sobrien || GET_CODE (XEXP (op, 0)) == LABEL_REF) 73550397Sobrien && GET_CODE (XEXP (op, 1)) == CONST_INT); 73650397Sobrien 73750397Sobrien default: 73850397Sobrien return 0; 73950397Sobrien } 74050397Sobrien} 74150397Sobrien 74250397Sobrien/* Return truth value of statement that OP is a symbolic memory 74350397Sobrien operand of mode MODE. */ 74450397Sobrien 74550397Sobrienint 74650397Sobriensymbolic_memory_operand (op, mode) 74750397Sobrien rtx op; 74850397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 74950397Sobrien{ 75050397Sobrien if (GET_CODE (op) == SUBREG) 75150397Sobrien op = SUBREG_REG (op); 75250397Sobrien if (GET_CODE (op) != MEM) 75350397Sobrien return 0; 75450397Sobrien op = XEXP (op, 0); 75550397Sobrien return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST 75650397Sobrien || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF); 75750397Sobrien} 75850397Sobrien 75950397Sobrien/* Return truth value of statement that OP is a LABEL_REF of mode MODE. */ 76050397Sobrien 76150397Sobrienint 76250397Sobrienlabel_ref_operand (op, mode) 76350397Sobrien rtx op; 76450397Sobrien enum machine_mode mode; 76550397Sobrien{ 76650397Sobrien if (GET_CODE (op) != LABEL_REF) 76750397Sobrien return 0; 76850397Sobrien if (GET_MODE (op) != mode) 76950397Sobrien return 0; 77050397Sobrien return 1; 77150397Sobrien} 77250397Sobrien 77350397Sobrien/* Return 1 if the operand is an argument used in generating pic references 77450397Sobrien in either the medium/low or medium/anywhere code models of sparc64. */ 77550397Sobrien 77650397Sobrienint 77750397Sobriensp64_medium_pic_operand (op, mode) 77850397Sobrien rtx op; 77950397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 78050397Sobrien{ 78150397Sobrien /* Check for (const (minus (symbol_ref:GOT) 78250397Sobrien (const (minus (label) (pc))))). */ 78350397Sobrien if (GET_CODE (op) != CONST) 78450397Sobrien return 0; 78550397Sobrien op = XEXP (op, 0); 78650397Sobrien if (GET_CODE (op) != MINUS) 78750397Sobrien return 0; 78850397Sobrien if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF) 78950397Sobrien return 0; 79050397Sobrien /* ??? Ensure symbol is GOT. */ 79150397Sobrien if (GET_CODE (XEXP (op, 1)) != CONST) 79250397Sobrien return 0; 79350397Sobrien if (GET_CODE (XEXP (XEXP (op, 1), 0)) != MINUS) 79450397Sobrien return 0; 79550397Sobrien return 1; 79650397Sobrien} 79750397Sobrien 79850397Sobrien/* Return 1 if the operand is a data segment reference. This includes 79950397Sobrien the readonly data segment, or in other words anything but the text segment. 80050397Sobrien This is needed in the medium/anywhere code model on v9. These values 80150397Sobrien are accessed with EMBMEDANY_BASE_REG. */ 80250397Sobrien 80350397Sobrienint 80450397Sobriendata_segment_operand (op, mode) 80550397Sobrien rtx op; 80650397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 80750397Sobrien{ 80850397Sobrien switch (GET_CODE (op)) 80950397Sobrien { 81050397Sobrien case SYMBOL_REF : 81150397Sobrien return ! SYMBOL_REF_FLAG (op); 81250397Sobrien case PLUS : 81350397Sobrien /* Assume canonical format of symbol + constant. 81450397Sobrien Fall through. */ 81550397Sobrien case CONST : 81690075Sobrien return data_segment_operand (XEXP (op, 0), VOIDmode); 81750397Sobrien default : 81850397Sobrien return 0; 81950397Sobrien } 82050397Sobrien} 82150397Sobrien 82250397Sobrien/* Return 1 if the operand is a text segment reference. 82350397Sobrien This is needed in the medium/anywhere code model on v9. */ 82450397Sobrien 82550397Sobrienint 82650397Sobrientext_segment_operand (op, mode) 82750397Sobrien rtx op; 82850397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 82950397Sobrien{ 83050397Sobrien switch (GET_CODE (op)) 83150397Sobrien { 83250397Sobrien case LABEL_REF : 83350397Sobrien return 1; 83450397Sobrien case SYMBOL_REF : 83550397Sobrien return SYMBOL_REF_FLAG (op); 83650397Sobrien case PLUS : 83750397Sobrien /* Assume canonical format of symbol + constant. 83850397Sobrien Fall through. */ 83950397Sobrien case CONST : 84090075Sobrien return text_segment_operand (XEXP (op, 0), VOIDmode); 84150397Sobrien default : 84250397Sobrien return 0; 84350397Sobrien } 84450397Sobrien} 84550397Sobrien 84650397Sobrien/* Return 1 if the operand is either a register or a memory operand that is 84750397Sobrien not symbolic. */ 84850397Sobrien 84950397Sobrienint 85050397Sobrienreg_or_nonsymb_mem_operand (op, mode) 85150397Sobrien register rtx op; 85250397Sobrien enum machine_mode mode; 85350397Sobrien{ 85450397Sobrien if (register_operand (op, mode)) 85550397Sobrien return 1; 85650397Sobrien 85750397Sobrien if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode)) 85850397Sobrien return 1; 85950397Sobrien 86050397Sobrien return 0; 86150397Sobrien} 86250397Sobrien 86350397Sobrienint 86450397Sobriensplittable_symbolic_memory_operand (op, mode) 86550397Sobrien rtx op; 86650397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 86750397Sobrien{ 86850397Sobrien if (GET_CODE (op) != MEM) 86950397Sobrien return 0; 87050397Sobrien if (! symbolic_operand (XEXP (op, 0), Pmode)) 87150397Sobrien return 0; 87250397Sobrien return 1; 87350397Sobrien} 87450397Sobrien 87550397Sobrienint 87650397Sobriensplittable_immediate_memory_operand (op, mode) 87750397Sobrien rtx op; 87850397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 87950397Sobrien{ 88050397Sobrien if (GET_CODE (op) != MEM) 88150397Sobrien return 0; 88250397Sobrien if (! immediate_operand (XEXP (op, 0), Pmode)) 88350397Sobrien return 0; 88450397Sobrien return 1; 88550397Sobrien} 88650397Sobrien 88750397Sobrien/* Return truth value of whether OP is EQ or NE. */ 88850397Sobrien 88950397Sobrienint 89050397Sobrieneq_or_neq (op, mode) 89150397Sobrien rtx op; 89250397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 89350397Sobrien{ 89450397Sobrien return (GET_CODE (op) == EQ || GET_CODE (op) == NE); 89550397Sobrien} 89650397Sobrien 89750397Sobrien/* Return 1 if this is a comparison operator, but not an EQ, NE, GEU, 89850397Sobrien or LTU for non-floating-point. We handle those specially. */ 89950397Sobrien 90050397Sobrienint 90150397Sobriennormal_comp_operator (op, mode) 90250397Sobrien rtx op; 90350397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 90450397Sobrien{ 90550397Sobrien enum rtx_code code = GET_CODE (op); 90650397Sobrien 90750397Sobrien if (GET_RTX_CLASS (code) != '<') 90850397Sobrien return 0; 90950397Sobrien 91050397Sobrien if (GET_MODE (XEXP (op, 0)) == CCFPmode 91150397Sobrien || GET_MODE (XEXP (op, 0)) == CCFPEmode) 91250397Sobrien return 1; 91350397Sobrien 91450397Sobrien return (code != NE && code != EQ && code != GEU && code != LTU); 91550397Sobrien} 91650397Sobrien 91750397Sobrien/* Return 1 if this is a comparison operator. This allows the use of 91850397Sobrien MATCH_OPERATOR to recognize all the branch insns. */ 91950397Sobrien 92050397Sobrienint 92150397Sobriennoov_compare_op (op, mode) 92250397Sobrien register rtx op; 92350397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 92450397Sobrien{ 92550397Sobrien enum rtx_code code = GET_CODE (op); 92650397Sobrien 92750397Sobrien if (GET_RTX_CLASS (code) != '<') 92850397Sobrien return 0; 92950397Sobrien 93096263Sobrien if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode 93196263Sobrien || GET_MODE (XEXP (op, 0)) == CCX_NOOVmode) 93250397Sobrien /* These are the only branches which work with CC_NOOVmode. */ 93350397Sobrien return (code == EQ || code == NE || code == GE || code == LT); 93450397Sobrien return 1; 93550397Sobrien} 93650397Sobrien 93796263Sobrien/* Return 1 if this is a 64-bit comparison operator. This allows the use of 93896263Sobrien MATCH_OPERATOR to recognize all the branch insns. */ 93996263Sobrien 94096263Sobrienint 94196263Sobriennoov_compare64_op (op, mode) 94296263Sobrien register rtx op; 94396263Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 94496263Sobrien{ 94596263Sobrien enum rtx_code code = GET_CODE (op); 94696263Sobrien 94796263Sobrien if (! TARGET_V9) 94896263Sobrien return 0; 94996263Sobrien 95096263Sobrien if (GET_RTX_CLASS (code) != '<') 95196263Sobrien return 0; 95296263Sobrien 95396263Sobrien if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode) 95496263Sobrien /* These are the only branches which work with CCX_NOOVmode. */ 95596263Sobrien return (code == EQ || code == NE || code == GE || code == LT); 95696263Sobrien return (GET_MODE (XEXP (op, 0)) == CCXmode); 95796263Sobrien} 95896263Sobrien 95950397Sobrien/* Nonzero if OP is a comparison operator suitable for use in v9 96050397Sobrien conditional move or branch on register contents instructions. */ 96150397Sobrien 96250397Sobrienint 96350397Sobrienv9_regcmp_op (op, mode) 96450397Sobrien register rtx op; 96550397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 96650397Sobrien{ 96750397Sobrien enum rtx_code code = GET_CODE (op); 96850397Sobrien 96950397Sobrien if (GET_RTX_CLASS (code) != '<') 97050397Sobrien return 0; 97150397Sobrien 97250397Sobrien return v9_regcmp_p (code); 97350397Sobrien} 97450397Sobrien 97550397Sobrien/* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation. */ 97650397Sobrien 97750397Sobrienint 97850397Sobrienextend_op (op, mode) 97950397Sobrien rtx op; 98050397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 98150397Sobrien{ 98250397Sobrien return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND; 98350397Sobrien} 98450397Sobrien 98550397Sobrien/* Return nonzero if OP is an operator of mode MODE which can set 98650397Sobrien the condition codes explicitly. We do not include PLUS and MINUS 98750397Sobrien because these require CC_NOOVmode, which we handle explicitly. */ 98850397Sobrien 98950397Sobrienint 99050397Sobriencc_arithop (op, mode) 99150397Sobrien rtx op; 99250397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 99350397Sobrien{ 99450397Sobrien if (GET_CODE (op) == AND 99550397Sobrien || GET_CODE (op) == IOR 99650397Sobrien || GET_CODE (op) == XOR) 99750397Sobrien return 1; 99850397Sobrien 99950397Sobrien return 0; 100050397Sobrien} 100150397Sobrien 100250397Sobrien/* Return nonzero if OP is an operator of mode MODE which can bitwise 100350397Sobrien complement its second operand and set the condition codes explicitly. */ 100450397Sobrien 100550397Sobrienint 100650397Sobriencc_arithopn (op, mode) 100750397Sobrien rtx op; 100850397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 100950397Sobrien{ 101050397Sobrien /* XOR is not here because combine canonicalizes (xor (not ...) ...) 101190075Sobrien and (xor ... (not ...)) to (not (xor ...)). */ 101250397Sobrien return (GET_CODE (op) == AND 101350397Sobrien || GET_CODE (op) == IOR); 101450397Sobrien} 101550397Sobrien 101650397Sobrien/* Return true if OP is a register, or is a CONST_INT that can fit in a 101750397Sobrien signed 13 bit immediate field. This is an acceptable SImode operand for 101850397Sobrien most 3 address instructions. */ 101950397Sobrien 102050397Sobrienint 102150397Sobrienarith_operand (op, mode) 102250397Sobrien rtx op; 102350397Sobrien enum machine_mode mode; 102450397Sobrien{ 102552284Sobrien if (register_operand (op, mode)) 102650397Sobrien return 1; 102750397Sobrien if (GET_CODE (op) != CONST_INT) 102850397Sobrien return 0; 102996263Sobrien return SMALL_INT32 (op); 103050397Sobrien} 103150397Sobrien 103252284Sobrien/* Return true if OP is a constant 4096 */ 103352284Sobrien 103452284Sobrienint 103552284Sobrienarith_4096_operand (op, mode) 103652284Sobrien rtx op; 103752284Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 103852284Sobrien{ 103952284Sobrien if (GET_CODE (op) != CONST_INT) 104052284Sobrien return 0; 104196263Sobrien else 104296263Sobrien return INTVAL (op) == 4096; 104352284Sobrien} 104452284Sobrien 104552284Sobrien/* Return true if OP is suitable as second operand for add/sub */ 104652284Sobrien 104752284Sobrienint 104852284Sobrienarith_add_operand (op, mode) 104952284Sobrien rtx op; 105052284Sobrien enum machine_mode mode; 105152284Sobrien{ 105252284Sobrien return arith_operand (op, mode) || arith_4096_operand (op, mode); 105352284Sobrien} 105452284Sobrien 105552284Sobrien/* Return true if OP is a CONST_INT or a CONST_DOUBLE which can fit in the 105652284Sobrien immediate field of OR and XOR instructions. Used for 64-bit 105752284Sobrien constant formation patterns. */ 105852284Sobrienint 105952284Sobrienconst64_operand (op, mode) 106052284Sobrien rtx op; 106152284Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 106252284Sobrien{ 106352284Sobrien return ((GET_CODE (op) == CONST_INT 106452284Sobrien && SPARC_SIMM13_P (INTVAL (op))) 106552284Sobrien#if HOST_BITS_PER_WIDE_INT != 64 106652284Sobrien || (GET_CODE (op) == CONST_DOUBLE 106752284Sobrien && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)) 106852284Sobrien && (CONST_DOUBLE_HIGH (op) == 106952284Sobrien ((CONST_DOUBLE_LOW (op) & 0x80000000) != 0 ? 107096263Sobrien (HOST_WIDE_INT)-1 : 0))) 107152284Sobrien#endif 107252284Sobrien ); 107352284Sobrien} 107452284Sobrien 107552284Sobrien/* The same, but only for sethi instructions. */ 107652284Sobrienint 107752284Sobrienconst64_high_operand (op, mode) 107852284Sobrien rtx op; 107996263Sobrien enum machine_mode mode; 108052284Sobrien{ 108152284Sobrien return ((GET_CODE (op) == CONST_INT 108296263Sobrien && (INTVAL (op) & ~(HOST_WIDE_INT)0x3ff) != 0 108396263Sobrien && SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode)) 108452284Sobrien ) 108552284Sobrien || (GET_CODE (op) == CONST_DOUBLE 108652284Sobrien && CONST_DOUBLE_HIGH (op) == 0 108796263Sobrien && (CONST_DOUBLE_LOW (op) & ~(HOST_WIDE_INT)0x3ff) != 0 108852284Sobrien && SPARC_SETHI_P (CONST_DOUBLE_LOW (op)))); 108952284Sobrien} 109052284Sobrien 109150397Sobrien/* Return true if OP is a register, or is a CONST_INT that can fit in a 109250397Sobrien signed 11 bit immediate field. This is an acceptable SImode operand for 109350397Sobrien the movcc instructions. */ 109450397Sobrien 109550397Sobrienint 109650397Sobrienarith11_operand (op, mode) 109750397Sobrien rtx op; 109850397Sobrien enum machine_mode mode; 109950397Sobrien{ 110050397Sobrien return (register_operand (op, mode) 110150397Sobrien || (GET_CODE (op) == CONST_INT && SPARC_SIMM11_P (INTVAL (op)))); 110250397Sobrien} 110350397Sobrien 110450397Sobrien/* Return true if OP is a register, or is a CONST_INT that can fit in a 110550397Sobrien signed 10 bit immediate field. This is an acceptable SImode operand for 110650397Sobrien the movrcc instructions. */ 110750397Sobrien 110850397Sobrienint 110950397Sobrienarith10_operand (op, mode) 111050397Sobrien rtx op; 111150397Sobrien enum machine_mode mode; 111250397Sobrien{ 111350397Sobrien return (register_operand (op, mode) 111450397Sobrien || (GET_CODE (op) == CONST_INT && SPARC_SIMM10_P (INTVAL (op)))); 111550397Sobrien} 111650397Sobrien 111750397Sobrien/* Return true if OP is a register, is a CONST_INT that fits in a 13 bit 111850397Sobrien immediate field, or is a CONST_DOUBLE whose both parts fit in a 13 bit 111950397Sobrien immediate field. 112050397Sobrien v9: Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that 112150397Sobrien can fit in a 13 bit immediate field. This is an acceptable DImode operand 112250397Sobrien for most 3 address instructions. */ 112350397Sobrien 112450397Sobrienint 112550397Sobrienarith_double_operand (op, mode) 112650397Sobrien rtx op; 112750397Sobrien enum machine_mode mode; 112850397Sobrien{ 112950397Sobrien return (register_operand (op, mode) 113050397Sobrien || (GET_CODE (op) == CONST_INT && SMALL_INT (op)) 113150397Sobrien || (! TARGET_ARCH64 113250397Sobrien && GET_CODE (op) == CONST_DOUBLE 113350397Sobrien && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000 113450397Sobrien && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_HIGH (op) + 0x1000) < 0x2000) 113550397Sobrien || (TARGET_ARCH64 113650397Sobrien && GET_CODE (op) == CONST_DOUBLE 113750397Sobrien && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000 113850397Sobrien && ((CONST_DOUBLE_HIGH (op) == -1 113950397Sobrien && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000) 114050397Sobrien || (CONST_DOUBLE_HIGH (op) == 0 114150397Sobrien && (CONST_DOUBLE_LOW (op) & 0x1000) == 0)))); 114250397Sobrien} 114350397Sobrien 114452284Sobrien/* Return true if OP is a constant 4096 for DImode on ARCH64 */ 114552284Sobrien 114652284Sobrienint 114752284Sobrienarith_double_4096_operand (op, mode) 114852284Sobrien rtx op; 114952284Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 115052284Sobrien{ 115152284Sobrien return (TARGET_ARCH64 && 115252284Sobrien ((GET_CODE (op) == CONST_INT && INTVAL (op) == 4096) || 115352284Sobrien (GET_CODE (op) == CONST_DOUBLE && 115452284Sobrien CONST_DOUBLE_LOW (op) == 4096 && 115552284Sobrien CONST_DOUBLE_HIGH (op) == 0))); 115652284Sobrien} 115752284Sobrien 115852284Sobrien/* Return true if OP is suitable as second operand for add/sub in DImode */ 115952284Sobrien 116052284Sobrienint 116152284Sobrienarith_double_add_operand (op, mode) 116252284Sobrien rtx op; 116352284Sobrien enum machine_mode mode; 116452284Sobrien{ 116552284Sobrien return arith_double_operand (op, mode) || arith_double_4096_operand (op, mode); 116652284Sobrien} 116752284Sobrien 116850397Sobrien/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that 116950397Sobrien can fit in an 11 bit immediate field. This is an acceptable DImode 117050397Sobrien operand for the movcc instructions. */ 117150397Sobrien/* ??? Replace with arith11_operand? */ 117250397Sobrien 117350397Sobrienint 117450397Sobrienarith11_double_operand (op, mode) 117550397Sobrien rtx op; 117650397Sobrien enum machine_mode mode; 117750397Sobrien{ 117850397Sobrien return (register_operand (op, mode) 117950397Sobrien || (GET_CODE (op) == CONST_DOUBLE 118050397Sobrien && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) 118150397Sobrien && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x400) < 0x800 118250397Sobrien && ((CONST_DOUBLE_HIGH (op) == -1 118350397Sobrien && (CONST_DOUBLE_LOW (op) & 0x400) == 0x400) 118450397Sobrien || (CONST_DOUBLE_HIGH (op) == 0 118550397Sobrien && (CONST_DOUBLE_LOW (op) & 0x400) == 0))) 118650397Sobrien || (GET_CODE (op) == CONST_INT 118750397Sobrien && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) 118850397Sobrien && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x400) < 0x800)); 118950397Sobrien} 119050397Sobrien 119150397Sobrien/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that 119250397Sobrien can fit in an 10 bit immediate field. This is an acceptable DImode 119350397Sobrien operand for the movrcc instructions. */ 119450397Sobrien/* ??? Replace with arith10_operand? */ 119550397Sobrien 119650397Sobrienint 119750397Sobrienarith10_double_operand (op, mode) 119850397Sobrien rtx op; 119950397Sobrien enum machine_mode mode; 120050397Sobrien{ 120150397Sobrien return (register_operand (op, mode) 120250397Sobrien || (GET_CODE (op) == CONST_DOUBLE 120350397Sobrien && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) 120450397Sobrien && (unsigned) (CONST_DOUBLE_LOW (op) + 0x200) < 0x400 120550397Sobrien && ((CONST_DOUBLE_HIGH (op) == -1 120650397Sobrien && (CONST_DOUBLE_LOW (op) & 0x200) == 0x200) 120750397Sobrien || (CONST_DOUBLE_HIGH (op) == 0 120850397Sobrien && (CONST_DOUBLE_LOW (op) & 0x200) == 0))) 120950397Sobrien || (GET_CODE (op) == CONST_INT 121050397Sobrien && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) 121150397Sobrien && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x200) < 0x400)); 121250397Sobrien} 121350397Sobrien 121490075Sobrien/* Return truth value of whether OP is an integer which fits the 121550397Sobrien range constraining immediate operands in most three-address insns, 121650397Sobrien which have a 13 bit immediate field. */ 121750397Sobrien 121850397Sobrienint 121950397Sobriensmall_int (op, mode) 122050397Sobrien rtx op; 122150397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 122250397Sobrien{ 122352284Sobrien return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); 122452284Sobrien} 122552284Sobrien 122652284Sobrienint 122752284Sobriensmall_int_or_double (op, mode) 122852284Sobrien rtx op; 122952284Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 123052284Sobrien{ 123150397Sobrien return ((GET_CODE (op) == CONST_INT && SMALL_INT (op)) 123252284Sobrien || (GET_CODE (op) == CONST_DOUBLE 123352284Sobrien && CONST_DOUBLE_HIGH (op) == 0 123452284Sobrien && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)))); 123550397Sobrien} 123650397Sobrien 123750397Sobrien/* Recognize operand values for the umul instruction. That instruction sign 123850397Sobrien extends immediate values just like all other sparc instructions, but 123950397Sobrien interprets the extended result as an unsigned number. */ 124050397Sobrien 124150397Sobrienint 124250397Sobrienuns_small_int (op, mode) 124350397Sobrien rtx op; 124450397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 124550397Sobrien{ 124650397Sobrien#if HOST_BITS_PER_WIDE_INT > 32 124750397Sobrien /* All allowed constants will fit a CONST_INT. */ 124852284Sobrien return (GET_CODE (op) == CONST_INT 124952284Sobrien && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000) 125052284Sobrien || (INTVAL (op) >= 0xFFFFF000 125190075Sobrien && INTVAL (op) <= 0xFFFFFFFF))); 125250397Sobrien#else 125352284Sobrien return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000) 125452284Sobrien || (GET_CODE (op) == CONST_DOUBLE 125552284Sobrien && CONST_DOUBLE_HIGH (op) == 0 125652284Sobrien && (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000)); 125750397Sobrien#endif 125850397Sobrien} 125950397Sobrien 126050397Sobrienint 126150397Sobrienuns_arith_operand (op, mode) 126250397Sobrien rtx op; 126350397Sobrien enum machine_mode mode; 126450397Sobrien{ 126550397Sobrien return register_operand (op, mode) || uns_small_int (op, mode); 126650397Sobrien} 126750397Sobrien 126850397Sobrien/* Return truth value of statement that OP is a call-clobbered register. */ 126950397Sobrienint 127050397Sobrienclobbered_register (op, mode) 127150397Sobrien rtx op; 127250397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 127350397Sobrien{ 127450397Sobrien return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]); 127550397Sobrien} 127652284Sobrien 127752284Sobrien/* Return 1 if OP is a valid operand for the source of a move insn. */ 127852284Sobrien 127952284Sobrienint 128052284Sobrieninput_operand (op, mode) 128152284Sobrien rtx op; 128252284Sobrien enum machine_mode mode; 128352284Sobrien{ 128452284Sobrien /* If both modes are non-void they must be the same. */ 128552284Sobrien if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) 128652284Sobrien return 0; 128752284Sobrien 128852284Sobrien /* Only a tiny bit of handling for CONSTANT_P_RTX is necessary. */ 128952284Sobrien if (GET_CODE (op) == CONST && GET_CODE (XEXP (op, 0)) == CONSTANT_P_RTX) 129052284Sobrien return 1; 129152284Sobrien 129252284Sobrien /* Allow any one instruction integer constant, and all CONST_INT 129352284Sobrien variants when we are working in DImode and !arch64. */ 129452284Sobrien if (GET_MODE_CLASS (mode) == MODE_INT 129552284Sobrien && ((GET_CODE (op) == CONST_INT 129696263Sobrien && (SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode)) 129752284Sobrien || SPARC_SIMM13_P (INTVAL (op)) 129852284Sobrien || (mode == DImode 129952284Sobrien && ! TARGET_ARCH64))) 130052284Sobrien || (TARGET_ARCH64 130152284Sobrien && GET_CODE (op) == CONST_DOUBLE 130252284Sobrien && ((CONST_DOUBLE_HIGH (op) == 0 130352284Sobrien && SPARC_SETHI_P (CONST_DOUBLE_LOW (op))) 130452284Sobrien || 130552284Sobrien#if HOST_BITS_PER_WIDE_INT == 64 130652284Sobrien (CONST_DOUBLE_HIGH (op) == 0 130752284Sobrien && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))) 130852284Sobrien#else 130952284Sobrien (SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)) 131052284Sobrien && (((CONST_DOUBLE_LOW (op) & 0x80000000) == 0 131152284Sobrien && CONST_DOUBLE_HIGH (op) == 0) 131290075Sobrien || (CONST_DOUBLE_HIGH (op) == -1 131390075Sobrien && CONST_DOUBLE_LOW (op) & 0x80000000) != 0)) 131452284Sobrien#endif 131552284Sobrien )))) 131652284Sobrien return 1; 131752284Sobrien 131852284Sobrien /* If !arch64 and this is a DImode const, allow it so that 131952284Sobrien the splits can be generated. */ 132052284Sobrien if (! TARGET_ARCH64 132152284Sobrien && mode == DImode 132252284Sobrien && GET_CODE (op) == CONST_DOUBLE) 132352284Sobrien return 1; 132452284Sobrien 132552284Sobrien if (register_operand (op, mode)) 132652284Sobrien return 1; 132752284Sobrien 132890075Sobrien if (GET_MODE_CLASS (mode) == MODE_FLOAT 132990075Sobrien && GET_CODE (op) == CONST_DOUBLE) 133090075Sobrien return 1; 133190075Sobrien 133252284Sobrien /* If this is a SUBREG, look inside so that we handle 133352284Sobrien paradoxical ones. */ 133452284Sobrien if (GET_CODE (op) == SUBREG) 133552284Sobrien op = SUBREG_REG (op); 133652284Sobrien 133752284Sobrien /* Check for valid MEM forms. */ 133852284Sobrien if (GET_CODE (op) == MEM) 133952284Sobrien { 134052284Sobrien rtx inside = XEXP (op, 0); 134152284Sobrien 134252284Sobrien if (GET_CODE (inside) == LO_SUM) 134352284Sobrien { 134452284Sobrien /* We can't allow these because all of the splits 134552284Sobrien (eventually as they trickle down into DFmode 134652284Sobrien splits) require offsettable memory references. */ 134752284Sobrien if (! TARGET_V9 134852284Sobrien && GET_MODE (op) == TFmode) 134952284Sobrien return 0; 135052284Sobrien 135152284Sobrien return (register_operand (XEXP (inside, 0), Pmode) 135252284Sobrien && CONSTANT_P (XEXP (inside, 1))); 135352284Sobrien } 135452284Sobrien return memory_address_p (mode, inside); 135552284Sobrien } 135652284Sobrien 135752284Sobrien return 0; 135852284Sobrien} 135952284Sobrien 136050397Sobrien 136152284Sobrien/* We know it can't be done in one insn when we get here, 136252284Sobrien the movsi expander guarentees this. */ 136352284Sobrienvoid 136452284Sobriensparc_emit_set_const32 (op0, op1) 136552284Sobrien rtx op0; 136652284Sobrien rtx op1; 136752284Sobrien{ 136852284Sobrien enum machine_mode mode = GET_MODE (op0); 136952284Sobrien rtx temp; 137052284Sobrien 137152284Sobrien if (GET_CODE (op1) == CONST_INT) 137252284Sobrien { 137352284Sobrien HOST_WIDE_INT value = INTVAL (op1); 137452284Sobrien 137596263Sobrien if (SPARC_SETHI_P (value & GET_MODE_MASK (mode)) 137652284Sobrien || SPARC_SIMM13_P (value)) 137752284Sobrien abort (); 137852284Sobrien } 137952284Sobrien 138052284Sobrien /* Full 2-insn decomposition is needed. */ 138152284Sobrien if (reload_in_progress || reload_completed) 138252284Sobrien temp = op0; 138352284Sobrien else 138452284Sobrien temp = gen_reg_rtx (mode); 138552284Sobrien 138652284Sobrien if (GET_CODE (op1) == CONST_INT) 138752284Sobrien { 138852284Sobrien /* Emit them as real moves instead of a HIGH/LO_SUM, 138952284Sobrien this way CSE can see everything and reuse intermediate 139052284Sobrien values if it wants. */ 139152284Sobrien if (TARGET_ARCH64 139252284Sobrien && HOST_BITS_PER_WIDE_INT != 64 139352284Sobrien && (INTVAL (op1) & 0x80000000) != 0) 139490075Sobrien emit_insn (gen_rtx_SET 139590075Sobrien (VOIDmode, temp, 1396117395Skan immed_double_const (INTVAL (op1) & ~(HOST_WIDE_INT)0x3ff, 1397117395Skan 0, DImode))); 139852284Sobrien else 139990075Sobrien emit_insn (gen_rtx_SET (VOIDmode, temp, 140096263Sobrien GEN_INT (INTVAL (op1) 140196263Sobrien & ~(HOST_WIDE_INT)0x3ff))); 140290075Sobrien 140352284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 140452284Sobrien op0, 140590075Sobrien gen_rtx_IOR (mode, temp, 140652284Sobrien GEN_INT (INTVAL (op1) & 0x3ff)))); 140752284Sobrien } 140852284Sobrien else 140952284Sobrien { 141052284Sobrien /* A symbol, emit in the traditional way. */ 141190075Sobrien emit_insn (gen_rtx_SET (VOIDmode, temp, 141290075Sobrien gen_rtx_HIGH (mode, op1))); 141352284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 141490075Sobrien op0, gen_rtx_LO_SUM (mode, temp, op1))); 141552284Sobrien 141652284Sobrien } 141752284Sobrien} 141852284Sobrien 141952284Sobrien 1420117395Skan/* SPARC-v9 code-model support. */ 142152284Sobrienvoid 142252284Sobriensparc_emit_set_symbolic_const64 (op0, op1, temp1) 142352284Sobrien rtx op0; 142452284Sobrien rtx op1; 142552284Sobrien rtx temp1; 142652284Sobrien{ 142796263Sobrien rtx ti_temp1 = 0; 142896263Sobrien 142996263Sobrien if (temp1 && GET_MODE (temp1) == TImode) 143096263Sobrien { 143196263Sobrien ti_temp1 = temp1; 143296263Sobrien temp1 = gen_rtx_REG (DImode, REGNO (temp1)); 143396263Sobrien } 143496263Sobrien 143552284Sobrien switch (sparc_cmodel) 143652284Sobrien { 143752284Sobrien case CM_MEDLOW: 143852284Sobrien /* The range spanned by all instructions in the object is less 143952284Sobrien than 2^31 bytes (2GB) and the distance from any instruction 144052284Sobrien to the location of the label _GLOBAL_OFFSET_TABLE_ is less 144152284Sobrien than 2^31 bytes (2GB). 144252284Sobrien 144352284Sobrien The executable must be in the low 4TB of the virtual address 144452284Sobrien space. 144552284Sobrien 144652284Sobrien sethi %hi(symbol), %temp 144752284Sobrien or %temp, %lo(symbol), %reg */ 144852284Sobrien emit_insn (gen_rtx_SET (VOIDmode, temp1, gen_rtx_HIGH (DImode, op1))); 144952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, gen_rtx_LO_SUM (DImode, temp1, op1))); 145052284Sobrien break; 145152284Sobrien 145252284Sobrien case CM_MEDMID: 145352284Sobrien /* The range spanned by all instructions in the object is less 145452284Sobrien than 2^31 bytes (2GB) and the distance from any instruction 145552284Sobrien to the location of the label _GLOBAL_OFFSET_TABLE_ is less 145652284Sobrien than 2^31 bytes (2GB). 145752284Sobrien 145852284Sobrien The executable must be in the low 16TB of the virtual address 145952284Sobrien space. 146052284Sobrien 146152284Sobrien sethi %h44(symbol), %temp1 146252284Sobrien or %temp1, %m44(symbol), %temp2 146352284Sobrien sllx %temp2, 12, %temp3 146452284Sobrien or %temp3, %l44(symbol), %reg */ 146552284Sobrien emit_insn (gen_seth44 (op0, op1)); 146652284Sobrien emit_insn (gen_setm44 (op0, op0, op1)); 146752284Sobrien emit_insn (gen_rtx_SET (VOIDmode, temp1, 146852284Sobrien gen_rtx_ASHIFT (DImode, op0, GEN_INT (12)))); 146952284Sobrien emit_insn (gen_setl44 (op0, temp1, op1)); 147052284Sobrien break; 147152284Sobrien 147252284Sobrien case CM_MEDANY: 147352284Sobrien /* The range spanned by all instructions in the object is less 147452284Sobrien than 2^31 bytes (2GB) and the distance from any instruction 147552284Sobrien to the location of the label _GLOBAL_OFFSET_TABLE_ is less 147652284Sobrien than 2^31 bytes (2GB). 147752284Sobrien 147852284Sobrien The executable can be placed anywhere in the virtual address 147952284Sobrien space. 148052284Sobrien 148152284Sobrien sethi %hh(symbol), %temp1 148252284Sobrien sethi %lm(symbol), %temp2 148352284Sobrien or %temp1, %hm(symbol), %temp3 148452284Sobrien or %temp2, %lo(symbol), %temp4 148552284Sobrien sllx %temp3, 32, %temp5 148652284Sobrien or %temp4, %temp5, %reg */ 148752284Sobrien 148896263Sobrien /* It is possible that one of the registers we got for operands[2] 148996263Sobrien might coincide with that of operands[0] (which is why we made 149096263Sobrien it TImode). Pick the other one to use as our scratch. */ 149190075Sobrien if (rtx_equal_p (temp1, op0)) 149296263Sobrien { 149396263Sobrien if (ti_temp1) 149496263Sobrien temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1); 149596263Sobrien else 149696263Sobrien abort(); 149796263Sobrien } 149852284Sobrien 149952284Sobrien emit_insn (gen_sethh (op0, op1)); 150052284Sobrien emit_insn (gen_setlm (temp1, op1)); 150152284Sobrien emit_insn (gen_sethm (op0, op0, op1)); 150252284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 150352284Sobrien gen_rtx_ASHIFT (DImode, op0, GEN_INT (32)))); 150452284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 150552284Sobrien gen_rtx_PLUS (DImode, op0, temp1))); 150652284Sobrien emit_insn (gen_setlo (op0, op0, op1)); 150752284Sobrien break; 150852284Sobrien 150952284Sobrien case CM_EMBMEDANY: 151052284Sobrien /* Old old old backwards compatibility kruft here. 151152284Sobrien Essentially it is MEDLOW with a fixed 64-bit 151252284Sobrien virtual base added to all data segment addresses. 151352284Sobrien Text-segment stuff is computed like MEDANY, we can't 151452284Sobrien reuse the code above because the relocation knobs 151552284Sobrien look different. 151652284Sobrien 151752284Sobrien Data segment: sethi %hi(symbol), %temp1 151852284Sobrien or %temp1, %lo(symbol), %temp2 151952284Sobrien add %temp2, EMBMEDANY_BASE_REG, %reg 152052284Sobrien 152152284Sobrien Text segment: sethi %uhi(symbol), %temp1 152252284Sobrien sethi %hi(symbol), %temp2 152352284Sobrien or %temp1, %ulo(symbol), %temp3 152452284Sobrien or %temp2, %lo(symbol), %temp4 152552284Sobrien sllx %temp3, 32, %temp5 152652284Sobrien or %temp4, %temp5, %reg */ 152752284Sobrien if (data_segment_operand (op1, GET_MODE (op1))) 152852284Sobrien { 152952284Sobrien emit_insn (gen_embmedany_sethi (temp1, op1)); 153052284Sobrien emit_insn (gen_embmedany_brsum (op0, temp1)); 153152284Sobrien emit_insn (gen_embmedany_losum (op0, op0, op1)); 153252284Sobrien } 153352284Sobrien else 153452284Sobrien { 153596263Sobrien /* It is possible that one of the registers we got for operands[2] 153696263Sobrien might coincide with that of operands[0] (which is why we made 153796263Sobrien it TImode). Pick the other one to use as our scratch. */ 153896263Sobrien if (rtx_equal_p (temp1, op0)) 153996263Sobrien { 154096263Sobrien if (ti_temp1) 154196263Sobrien temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1); 154296263Sobrien else 154396263Sobrien abort(); 154496263Sobrien } 154552284Sobrien 154652284Sobrien emit_insn (gen_embmedany_textuhi (op0, op1)); 154752284Sobrien emit_insn (gen_embmedany_texthi (temp1, op1)); 154852284Sobrien emit_insn (gen_embmedany_textulo (op0, op0, op1)); 154952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 155052284Sobrien gen_rtx_ASHIFT (DImode, op0, GEN_INT (32)))); 155152284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 155252284Sobrien gen_rtx_PLUS (DImode, op0, temp1))); 155352284Sobrien emit_insn (gen_embmedany_textlo (op0, op0, op1)); 155452284Sobrien } 155552284Sobrien break; 155652284Sobrien 155752284Sobrien default: 155852284Sobrien abort(); 155952284Sobrien } 156052284Sobrien} 156152284Sobrien 156252284Sobrien/* These avoid problems when cross compiling. If we do not 156352284Sobrien go through all this hair then the optimizer will see 156452284Sobrien invalid REG_EQUAL notes or in some cases none at all. */ 156590075Sobrienstatic void sparc_emit_set_safe_HIGH64 PARAMS ((rtx, HOST_WIDE_INT)); 156690075Sobrienstatic rtx gen_safe_SET64 PARAMS ((rtx, HOST_WIDE_INT)); 156790075Sobrienstatic rtx gen_safe_OR64 PARAMS ((rtx, HOST_WIDE_INT)); 156890075Sobrienstatic rtx gen_safe_XOR64 PARAMS ((rtx, HOST_WIDE_INT)); 156952284Sobrien 157052284Sobrien#if HOST_BITS_PER_WIDE_INT == 64 157196263Sobrien#define GEN_HIGHINT64(__x) GEN_INT ((__x) & ~(HOST_WIDE_INT)0x3ff) 157252284Sobrien#define GEN_INT64(__x) GEN_INT (__x) 157352284Sobrien#else 157452284Sobrien#define GEN_HIGHINT64(__x) \ 1575117395Skan immed_double_const ((__x) & ~(HOST_WIDE_INT)0x3ff, 0, DImode) 157652284Sobrien#define GEN_INT64(__x) \ 1577117395Skan immed_double_const ((__x) & 0xffffffff, \ 1578117395Skan ((__x) & 0x80000000 ? -1 : 0), DImode) 157952284Sobrien#endif 158052284Sobrien 158152284Sobrien/* The optimizer is not to assume anything about exactly 158252284Sobrien which bits are set for a HIGH, they are unspecified. 158352284Sobrien Unfortunately this leads to many missed optimizations 158452284Sobrien during CSE. We mask out the non-HIGH bits, and matches 158552284Sobrien a plain movdi, to alleviate this problem. */ 158652284Sobrienstatic void 158752284Sobriensparc_emit_set_safe_HIGH64 (dest, val) 158852284Sobrien rtx dest; 158952284Sobrien HOST_WIDE_INT val; 159052284Sobrien{ 159152284Sobrien emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_HIGHINT64 (val))); 159252284Sobrien} 159352284Sobrien 159452284Sobrienstatic rtx 159552284Sobriengen_safe_SET64 (dest, val) 159652284Sobrien rtx dest; 159752284Sobrien HOST_WIDE_INT val; 159852284Sobrien{ 159952284Sobrien return gen_rtx_SET (VOIDmode, dest, GEN_INT64 (val)); 160052284Sobrien} 160152284Sobrien 160252284Sobrienstatic rtx 160352284Sobriengen_safe_OR64 (src, val) 160452284Sobrien rtx src; 160552284Sobrien HOST_WIDE_INT val; 160652284Sobrien{ 160752284Sobrien return gen_rtx_IOR (DImode, src, GEN_INT64 (val)); 160852284Sobrien} 160952284Sobrien 161052284Sobrienstatic rtx 161152284Sobriengen_safe_XOR64 (src, val) 161252284Sobrien rtx src; 161352284Sobrien HOST_WIDE_INT val; 161452284Sobrien{ 161552284Sobrien return gen_rtx_XOR (DImode, src, GEN_INT64 (val)); 161652284Sobrien} 161752284Sobrien 161852284Sobrien/* Worker routines for 64-bit constant formation on arch64. 161952284Sobrien One of the key things to be doing in these emissions is 162052284Sobrien to create as many temp REGs as possible. This makes it 162152284Sobrien possible for half-built constants to be used later when 162252284Sobrien such values are similar to something required later on. 162352284Sobrien Without doing this, the optimizer cannot see such 162452284Sobrien opportunities. */ 162552284Sobrien 162652284Sobrienstatic void sparc_emit_set_const64_quick1 162790075Sobrien PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT, int)); 162852284Sobrien 162952284Sobrienstatic void 163052284Sobriensparc_emit_set_const64_quick1 (op0, temp, low_bits, is_neg) 163152284Sobrien rtx op0; 163252284Sobrien rtx temp; 163352284Sobrien unsigned HOST_WIDE_INT low_bits; 163452284Sobrien int is_neg; 163552284Sobrien{ 163652284Sobrien unsigned HOST_WIDE_INT high_bits; 163752284Sobrien 163852284Sobrien if (is_neg) 163952284Sobrien high_bits = (~low_bits) & 0xffffffff; 164052284Sobrien else 164152284Sobrien high_bits = low_bits; 164252284Sobrien 164352284Sobrien sparc_emit_set_safe_HIGH64 (temp, high_bits); 164452284Sobrien if (!is_neg) 164552284Sobrien { 164652284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 164752284Sobrien gen_safe_OR64 (temp, (high_bits & 0x3ff)))); 164852284Sobrien } 164952284Sobrien else 165052284Sobrien { 165152284Sobrien /* If we are XOR'ing with -1, then we should emit a one's complement 165252284Sobrien instead. This way the combiner will notice logical operations 165352284Sobrien such as ANDN later on and substitute. */ 165452284Sobrien if ((low_bits & 0x3ff) == 0x3ff) 165552284Sobrien { 165652284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 165752284Sobrien gen_rtx_NOT (DImode, temp))); 165852284Sobrien } 165952284Sobrien else 166052284Sobrien { 166152284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 166252284Sobrien gen_safe_XOR64 (temp, 166396263Sobrien (-(HOST_WIDE_INT)0x400 166496263Sobrien | (low_bits & 0x3ff))))); 166552284Sobrien } 166652284Sobrien } 166752284Sobrien} 166852284Sobrien 166952284Sobrienstatic void sparc_emit_set_const64_quick2 167090075Sobrien PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT, 167152284Sobrien unsigned HOST_WIDE_INT, int)); 167252284Sobrien 167352284Sobrienstatic void 167452284Sobriensparc_emit_set_const64_quick2 (op0, temp, high_bits, low_immediate, shift_count) 167552284Sobrien rtx op0; 167652284Sobrien rtx temp; 167752284Sobrien unsigned HOST_WIDE_INT high_bits; 167852284Sobrien unsigned HOST_WIDE_INT low_immediate; 167952284Sobrien int shift_count; 168052284Sobrien{ 168152284Sobrien rtx temp2 = op0; 168252284Sobrien 168352284Sobrien if ((high_bits & 0xfffffc00) != 0) 168452284Sobrien { 168552284Sobrien sparc_emit_set_safe_HIGH64 (temp, high_bits); 168652284Sobrien if ((high_bits & ~0xfffffc00) != 0) 168752284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 168852284Sobrien gen_safe_OR64 (temp, (high_bits & 0x3ff)))); 168952284Sobrien else 169052284Sobrien temp2 = temp; 169152284Sobrien } 169252284Sobrien else 169352284Sobrien { 169452284Sobrien emit_insn (gen_safe_SET64 (temp, high_bits)); 169552284Sobrien temp2 = temp; 169652284Sobrien } 169752284Sobrien 169890075Sobrien /* Now shift it up into place. */ 169952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 170052284Sobrien gen_rtx_ASHIFT (DImode, temp2, 170152284Sobrien GEN_INT (shift_count)))); 170252284Sobrien 170352284Sobrien /* If there is a low immediate part piece, finish up by 170452284Sobrien putting that in as well. */ 170552284Sobrien if (low_immediate != 0) 170652284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 170752284Sobrien gen_safe_OR64 (op0, low_immediate))); 170852284Sobrien} 170952284Sobrien 171052284Sobrienstatic void sparc_emit_set_const64_longway 171190075Sobrien PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT)); 171252284Sobrien 171352284Sobrien/* Full 64-bit constant decomposition. Even though this is the 171452284Sobrien 'worst' case, we still optimize a few things away. */ 171552284Sobrienstatic void 171652284Sobriensparc_emit_set_const64_longway (op0, temp, high_bits, low_bits) 171752284Sobrien rtx op0; 171852284Sobrien rtx temp; 171952284Sobrien unsigned HOST_WIDE_INT high_bits; 172052284Sobrien unsigned HOST_WIDE_INT low_bits; 172152284Sobrien{ 172252284Sobrien rtx sub_temp; 172352284Sobrien 172452284Sobrien if (reload_in_progress || reload_completed) 172552284Sobrien sub_temp = op0; 172652284Sobrien else 172752284Sobrien sub_temp = gen_reg_rtx (DImode); 172852284Sobrien 172952284Sobrien if ((high_bits & 0xfffffc00) != 0) 173052284Sobrien { 173152284Sobrien sparc_emit_set_safe_HIGH64 (temp, high_bits); 173252284Sobrien if ((high_bits & ~0xfffffc00) != 0) 173352284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 173452284Sobrien sub_temp, 173552284Sobrien gen_safe_OR64 (temp, (high_bits & 0x3ff)))); 173652284Sobrien else 173752284Sobrien sub_temp = temp; 173852284Sobrien } 173952284Sobrien else 174052284Sobrien { 174152284Sobrien emit_insn (gen_safe_SET64 (temp, high_bits)); 174252284Sobrien sub_temp = temp; 174352284Sobrien } 174452284Sobrien 174552284Sobrien if (!reload_in_progress && !reload_completed) 174652284Sobrien { 174752284Sobrien rtx temp2 = gen_reg_rtx (DImode); 174852284Sobrien rtx temp3 = gen_reg_rtx (DImode); 174952284Sobrien rtx temp4 = gen_reg_rtx (DImode); 175052284Sobrien 175152284Sobrien emit_insn (gen_rtx_SET (VOIDmode, temp4, 175252284Sobrien gen_rtx_ASHIFT (DImode, sub_temp, 175352284Sobrien GEN_INT (32)))); 175452284Sobrien 175552284Sobrien sparc_emit_set_safe_HIGH64 (temp2, low_bits); 175652284Sobrien if ((low_bits & ~0xfffffc00) != 0) 175752284Sobrien { 175852284Sobrien emit_insn (gen_rtx_SET (VOIDmode, temp3, 175952284Sobrien gen_safe_OR64 (temp2, (low_bits & 0x3ff)))); 176052284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 176152284Sobrien gen_rtx_PLUS (DImode, temp4, temp3))); 176252284Sobrien } 176352284Sobrien else 176452284Sobrien { 176552284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 176652284Sobrien gen_rtx_PLUS (DImode, temp4, temp2))); 176752284Sobrien } 176852284Sobrien } 176952284Sobrien else 177052284Sobrien { 177152284Sobrien rtx low1 = GEN_INT ((low_bits >> (32 - 12)) & 0xfff); 177252284Sobrien rtx low2 = GEN_INT ((low_bits >> (32 - 12 - 12)) & 0xfff); 177352284Sobrien rtx low3 = GEN_INT ((low_bits >> (32 - 12 - 12 - 8)) & 0x0ff); 177452284Sobrien int to_shift = 12; 177552284Sobrien 177652284Sobrien /* We are in the middle of reload, so this is really 177752284Sobrien painful. However we do still make an attempt to 177852284Sobrien avoid emitting truly stupid code. */ 177952284Sobrien if (low1 != const0_rtx) 178052284Sobrien { 178152284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 178252284Sobrien gen_rtx_ASHIFT (DImode, sub_temp, 178352284Sobrien GEN_INT (to_shift)))); 178452284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 178552284Sobrien gen_rtx_IOR (DImode, op0, low1))); 178652284Sobrien sub_temp = op0; 178752284Sobrien to_shift = 12; 178852284Sobrien } 178952284Sobrien else 179052284Sobrien { 179152284Sobrien to_shift += 12; 179252284Sobrien } 179352284Sobrien if (low2 != const0_rtx) 179452284Sobrien { 179552284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 179652284Sobrien gen_rtx_ASHIFT (DImode, sub_temp, 179752284Sobrien GEN_INT (to_shift)))); 179852284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 179952284Sobrien gen_rtx_IOR (DImode, op0, low2))); 180052284Sobrien sub_temp = op0; 180152284Sobrien to_shift = 8; 180252284Sobrien } 180352284Sobrien else 180452284Sobrien { 180552284Sobrien to_shift += 8; 180652284Sobrien } 180752284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 180852284Sobrien gen_rtx_ASHIFT (DImode, sub_temp, 180952284Sobrien GEN_INT (to_shift)))); 181052284Sobrien if (low3 != const0_rtx) 181152284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 181252284Sobrien gen_rtx_IOR (DImode, op0, low3))); 181390075Sobrien /* phew... */ 181452284Sobrien } 181552284Sobrien} 181652284Sobrien 181790075Sobrien/* Analyze a 64-bit constant for certain properties. */ 181852284Sobrienstatic void analyze_64bit_constant 181990075Sobrien PARAMS ((unsigned HOST_WIDE_INT, 182052284Sobrien unsigned HOST_WIDE_INT, 182152284Sobrien int *, int *, int *)); 182252284Sobrien 182352284Sobrienstatic void 182452284Sobrienanalyze_64bit_constant (high_bits, low_bits, hbsp, lbsp, abbasp) 182552284Sobrien unsigned HOST_WIDE_INT high_bits, low_bits; 182652284Sobrien int *hbsp, *lbsp, *abbasp; 182752284Sobrien{ 182852284Sobrien int lowest_bit_set, highest_bit_set, all_bits_between_are_set; 182952284Sobrien int i; 183052284Sobrien 183152284Sobrien lowest_bit_set = highest_bit_set = -1; 183252284Sobrien i = 0; 183352284Sobrien do 183452284Sobrien { 183552284Sobrien if ((lowest_bit_set == -1) 183652284Sobrien && ((low_bits >> i) & 1)) 183752284Sobrien lowest_bit_set = i; 183852284Sobrien if ((highest_bit_set == -1) 183952284Sobrien && ((high_bits >> (32 - i - 1)) & 1)) 184052284Sobrien highest_bit_set = (64 - i - 1); 184152284Sobrien } 184252284Sobrien while (++i < 32 184352284Sobrien && ((highest_bit_set == -1) 184452284Sobrien || (lowest_bit_set == -1))); 184552284Sobrien if (i == 32) 184652284Sobrien { 184752284Sobrien i = 0; 184852284Sobrien do 184952284Sobrien { 185052284Sobrien if ((lowest_bit_set == -1) 185152284Sobrien && ((high_bits >> i) & 1)) 185252284Sobrien lowest_bit_set = i + 32; 185352284Sobrien if ((highest_bit_set == -1) 185452284Sobrien && ((low_bits >> (32 - i - 1)) & 1)) 185552284Sobrien highest_bit_set = 32 - i - 1; 185652284Sobrien } 185752284Sobrien while (++i < 32 185852284Sobrien && ((highest_bit_set == -1) 185952284Sobrien || (lowest_bit_set == -1))); 186052284Sobrien } 186152284Sobrien /* If there are no bits set this should have gone out 186252284Sobrien as one instruction! */ 186352284Sobrien if (lowest_bit_set == -1 186452284Sobrien || highest_bit_set == -1) 186552284Sobrien abort (); 186652284Sobrien all_bits_between_are_set = 1; 186752284Sobrien for (i = lowest_bit_set; i <= highest_bit_set; i++) 186852284Sobrien { 186952284Sobrien if (i < 32) 187052284Sobrien { 187152284Sobrien if ((low_bits & (1 << i)) != 0) 187252284Sobrien continue; 187352284Sobrien } 187452284Sobrien else 187552284Sobrien { 187652284Sobrien if ((high_bits & (1 << (i - 32))) != 0) 187752284Sobrien continue; 187852284Sobrien } 187952284Sobrien all_bits_between_are_set = 0; 188052284Sobrien break; 188152284Sobrien } 188252284Sobrien *hbsp = highest_bit_set; 188352284Sobrien *lbsp = lowest_bit_set; 188452284Sobrien *abbasp = all_bits_between_are_set; 188552284Sobrien} 188652284Sobrien 188752284Sobrienstatic int const64_is_2insns 188890075Sobrien PARAMS ((unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT)); 188952284Sobrien 189052284Sobrienstatic int 189152284Sobrienconst64_is_2insns (high_bits, low_bits) 189252284Sobrien unsigned HOST_WIDE_INT high_bits, low_bits; 189352284Sobrien{ 189452284Sobrien int highest_bit_set, lowest_bit_set, all_bits_between_are_set; 189552284Sobrien 189652284Sobrien if (high_bits == 0 189752284Sobrien || high_bits == 0xffffffff) 189852284Sobrien return 1; 189952284Sobrien 190052284Sobrien analyze_64bit_constant (high_bits, low_bits, 190152284Sobrien &highest_bit_set, &lowest_bit_set, 190252284Sobrien &all_bits_between_are_set); 190352284Sobrien 190452284Sobrien if ((highest_bit_set == 63 190552284Sobrien || lowest_bit_set == 0) 190652284Sobrien && all_bits_between_are_set != 0) 190752284Sobrien return 1; 190852284Sobrien 190952284Sobrien if ((highest_bit_set - lowest_bit_set) < 21) 191052284Sobrien return 1; 191152284Sobrien 191252284Sobrien return 0; 191352284Sobrien} 191452284Sobrien 191552284Sobrienstatic unsigned HOST_WIDE_INT create_simple_focus_bits 191690075Sobrien PARAMS ((unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, 191752284Sobrien int, int)); 191852284Sobrien 191952284Sobrienstatic unsigned HOST_WIDE_INT 192052284Sobriencreate_simple_focus_bits (high_bits, low_bits, lowest_bit_set, shift) 192152284Sobrien unsigned HOST_WIDE_INT high_bits, low_bits; 192252284Sobrien int lowest_bit_set, shift; 192352284Sobrien{ 192452284Sobrien HOST_WIDE_INT hi, lo; 192552284Sobrien 192652284Sobrien if (lowest_bit_set < 32) 192752284Sobrien { 192852284Sobrien lo = (low_bits >> lowest_bit_set) << shift; 192952284Sobrien hi = ((high_bits << (32 - lowest_bit_set)) << shift); 193052284Sobrien } 193152284Sobrien else 193252284Sobrien { 193352284Sobrien lo = 0; 193452284Sobrien hi = ((high_bits >> (lowest_bit_set - 32)) << shift); 193552284Sobrien } 193652284Sobrien if (hi & lo) 193752284Sobrien abort (); 193852284Sobrien return (hi | lo); 193952284Sobrien} 194052284Sobrien 194152284Sobrien/* Here we are sure to be arch64 and this is an integer constant 194252284Sobrien being loaded into a register. Emit the most efficient 194352284Sobrien insn sequence possible. Detection of all the 1-insn cases 194452284Sobrien has been done already. */ 194552284Sobrienvoid 194652284Sobriensparc_emit_set_const64 (op0, op1) 194752284Sobrien rtx op0; 194852284Sobrien rtx op1; 194952284Sobrien{ 195052284Sobrien unsigned HOST_WIDE_INT high_bits, low_bits; 195152284Sobrien int lowest_bit_set, highest_bit_set; 195252284Sobrien int all_bits_between_are_set; 195352284Sobrien rtx temp; 195452284Sobrien 195552284Sobrien /* Sanity check that we know what we are working with. */ 195690075Sobrien if (! TARGET_ARCH64) 195752284Sobrien abort (); 195852284Sobrien 195990075Sobrien if (GET_CODE (op0) != SUBREG) 196090075Sobrien { 196190075Sobrien if (GET_CODE (op0) != REG 196290075Sobrien || (REGNO (op0) >= SPARC_FIRST_FP_REG 196390075Sobrien && REGNO (op0) <= SPARC_LAST_V9_FP_REG)) 196490075Sobrien abort (); 196590075Sobrien } 196690075Sobrien 196752284Sobrien if (reload_in_progress || reload_completed) 196852284Sobrien temp = op0; 196952284Sobrien else 197052284Sobrien temp = gen_reg_rtx (DImode); 197152284Sobrien 197252284Sobrien if (GET_CODE (op1) != CONST_DOUBLE 197352284Sobrien && GET_CODE (op1) != CONST_INT) 197452284Sobrien { 197552284Sobrien sparc_emit_set_symbolic_const64 (op0, op1, temp); 197652284Sobrien return; 197752284Sobrien } 197852284Sobrien 197952284Sobrien if (GET_CODE (op1) == CONST_DOUBLE) 198052284Sobrien { 198152284Sobrien#if HOST_BITS_PER_WIDE_INT == 64 198252284Sobrien high_bits = (CONST_DOUBLE_LOW (op1) >> 32) & 0xffffffff; 198352284Sobrien low_bits = CONST_DOUBLE_LOW (op1) & 0xffffffff; 198452284Sobrien#else 198552284Sobrien high_bits = CONST_DOUBLE_HIGH (op1); 198652284Sobrien low_bits = CONST_DOUBLE_LOW (op1); 198752284Sobrien#endif 198852284Sobrien } 198952284Sobrien else 199052284Sobrien { 199152284Sobrien#if HOST_BITS_PER_WIDE_INT == 64 199252284Sobrien high_bits = ((INTVAL (op1) >> 32) & 0xffffffff); 199352284Sobrien low_bits = (INTVAL (op1) & 0xffffffff); 199452284Sobrien#else 199552284Sobrien high_bits = ((INTVAL (op1) < 0) ? 199652284Sobrien 0xffffffff : 199752284Sobrien 0x00000000); 199852284Sobrien low_bits = INTVAL (op1); 199952284Sobrien#endif 200052284Sobrien } 200152284Sobrien 200252284Sobrien /* low_bits bits 0 --> 31 200352284Sobrien high_bits bits 32 --> 63 */ 200452284Sobrien 200552284Sobrien analyze_64bit_constant (high_bits, low_bits, 200652284Sobrien &highest_bit_set, &lowest_bit_set, 200752284Sobrien &all_bits_between_are_set); 200852284Sobrien 200952284Sobrien /* First try for a 2-insn sequence. */ 201052284Sobrien 201152284Sobrien /* These situations are preferred because the optimizer can 201252284Sobrien * do more things with them: 201352284Sobrien * 1) mov -1, %reg 201452284Sobrien * sllx %reg, shift, %reg 201552284Sobrien * 2) mov -1, %reg 201652284Sobrien * srlx %reg, shift, %reg 201752284Sobrien * 3) mov some_small_const, %reg 201852284Sobrien * sllx %reg, shift, %reg 201952284Sobrien */ 202052284Sobrien if (((highest_bit_set == 63 202152284Sobrien || lowest_bit_set == 0) 202252284Sobrien && all_bits_between_are_set != 0) 202352284Sobrien || ((highest_bit_set - lowest_bit_set) < 12)) 202452284Sobrien { 202552284Sobrien HOST_WIDE_INT the_const = -1; 202652284Sobrien int shift = lowest_bit_set; 202752284Sobrien 202852284Sobrien if ((highest_bit_set != 63 202952284Sobrien && lowest_bit_set != 0) 203052284Sobrien || all_bits_between_are_set == 0) 203152284Sobrien { 203252284Sobrien the_const = 203352284Sobrien create_simple_focus_bits (high_bits, low_bits, 203452284Sobrien lowest_bit_set, 0); 203552284Sobrien } 203652284Sobrien else if (lowest_bit_set == 0) 203752284Sobrien shift = -(63 - highest_bit_set); 203852284Sobrien 203952284Sobrien if (! SPARC_SIMM13_P (the_const)) 204052284Sobrien abort (); 204152284Sobrien 204252284Sobrien emit_insn (gen_safe_SET64 (temp, the_const)); 204352284Sobrien if (shift > 0) 204452284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 204552284Sobrien op0, 204652284Sobrien gen_rtx_ASHIFT (DImode, 204752284Sobrien temp, 204852284Sobrien GEN_INT (shift)))); 204952284Sobrien else if (shift < 0) 205052284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 205152284Sobrien op0, 205252284Sobrien gen_rtx_LSHIFTRT (DImode, 205352284Sobrien temp, 205452284Sobrien GEN_INT (-shift)))); 205552284Sobrien else 205652284Sobrien abort (); 205752284Sobrien return; 205852284Sobrien } 205952284Sobrien 206052284Sobrien /* Now a range of 22 or less bits set somewhere. 206152284Sobrien * 1) sethi %hi(focus_bits), %reg 206252284Sobrien * sllx %reg, shift, %reg 206352284Sobrien * 2) sethi %hi(focus_bits), %reg 206452284Sobrien * srlx %reg, shift, %reg 206552284Sobrien */ 206652284Sobrien if ((highest_bit_set - lowest_bit_set) < 21) 206752284Sobrien { 206852284Sobrien unsigned HOST_WIDE_INT focus_bits = 206952284Sobrien create_simple_focus_bits (high_bits, low_bits, 207052284Sobrien lowest_bit_set, 10); 207152284Sobrien 207252284Sobrien if (! SPARC_SETHI_P (focus_bits)) 207352284Sobrien abort (); 207452284Sobrien 207552284Sobrien sparc_emit_set_safe_HIGH64 (temp, focus_bits); 207652284Sobrien 207752284Sobrien /* If lowest_bit_set == 10 then a sethi alone could have done it. */ 207852284Sobrien if (lowest_bit_set < 10) 207952284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 208052284Sobrien op0, 208152284Sobrien gen_rtx_LSHIFTRT (DImode, temp, 208252284Sobrien GEN_INT (10 - lowest_bit_set)))); 208352284Sobrien else if (lowest_bit_set > 10) 208452284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 208552284Sobrien op0, 208652284Sobrien gen_rtx_ASHIFT (DImode, temp, 208752284Sobrien GEN_INT (lowest_bit_set - 10)))); 208852284Sobrien else 208952284Sobrien abort (); 209052284Sobrien return; 209152284Sobrien } 209252284Sobrien 209352284Sobrien /* 1) sethi %hi(low_bits), %reg 209452284Sobrien * or %reg, %lo(low_bits), %reg 209552284Sobrien * 2) sethi %hi(~low_bits), %reg 209652284Sobrien * xor %reg, %lo(-0x400 | (low_bits & 0x3ff)), %reg 209752284Sobrien */ 209852284Sobrien if (high_bits == 0 209952284Sobrien || high_bits == 0xffffffff) 210052284Sobrien { 210152284Sobrien sparc_emit_set_const64_quick1 (op0, temp, low_bits, 210252284Sobrien (high_bits == 0xffffffff)); 210352284Sobrien return; 210452284Sobrien } 210552284Sobrien 210652284Sobrien /* Now, try 3-insn sequences. */ 210752284Sobrien 210852284Sobrien /* 1) sethi %hi(high_bits), %reg 210952284Sobrien * or %reg, %lo(high_bits), %reg 211052284Sobrien * sllx %reg, 32, %reg 211152284Sobrien */ 211252284Sobrien if (low_bits == 0) 211352284Sobrien { 211452284Sobrien sparc_emit_set_const64_quick2 (op0, temp, high_bits, 0, 32); 211552284Sobrien return; 211652284Sobrien } 211752284Sobrien 211852284Sobrien /* We may be able to do something quick 211952284Sobrien when the constant is negated, so try that. */ 212052284Sobrien if (const64_is_2insns ((~high_bits) & 0xffffffff, 212152284Sobrien (~low_bits) & 0xfffffc00)) 212252284Sobrien { 212352284Sobrien /* NOTE: The trailing bits get XOR'd so we need the 212452284Sobrien non-negated bits, not the negated ones. */ 212552284Sobrien unsigned HOST_WIDE_INT trailing_bits = low_bits & 0x3ff; 212652284Sobrien 212752284Sobrien if ((((~high_bits) & 0xffffffff) == 0 212852284Sobrien && ((~low_bits) & 0x80000000) == 0) 212952284Sobrien || (((~high_bits) & 0xffffffff) == 0xffffffff 213052284Sobrien && ((~low_bits) & 0x80000000) != 0)) 213152284Sobrien { 213252284Sobrien int fast_int = (~low_bits & 0xffffffff); 213352284Sobrien 213452284Sobrien if ((SPARC_SETHI_P (fast_int) 213552284Sobrien && (~high_bits & 0xffffffff) == 0) 213652284Sobrien || SPARC_SIMM13_P (fast_int)) 213752284Sobrien emit_insn (gen_safe_SET64 (temp, fast_int)); 213852284Sobrien else 213952284Sobrien sparc_emit_set_const64 (temp, GEN_INT64 (fast_int)); 214052284Sobrien } 214152284Sobrien else 214252284Sobrien { 214352284Sobrien rtx negated_const; 214452284Sobrien#if HOST_BITS_PER_WIDE_INT == 64 214552284Sobrien negated_const = GEN_INT (((~low_bits) & 0xfffffc00) | 214652284Sobrien (((HOST_WIDE_INT)((~high_bits) & 0xffffffff))<<32)); 214752284Sobrien#else 2148117395Skan negated_const = immed_double_const ((~low_bits) & 0xfffffc00, 2149117395Skan (~high_bits) & 0xffffffff, 2150117395Skan DImode); 215152284Sobrien#endif 215252284Sobrien sparc_emit_set_const64 (temp, negated_const); 215352284Sobrien } 215452284Sobrien 215552284Sobrien /* If we are XOR'ing with -1, then we should emit a one's complement 215652284Sobrien instead. This way the combiner will notice logical operations 215752284Sobrien such as ANDN later on and substitute. */ 215852284Sobrien if (trailing_bits == 0x3ff) 215952284Sobrien { 216052284Sobrien emit_insn (gen_rtx_SET (VOIDmode, op0, 216152284Sobrien gen_rtx_NOT (DImode, temp))); 216252284Sobrien } 216352284Sobrien else 216452284Sobrien { 216552284Sobrien emit_insn (gen_rtx_SET (VOIDmode, 216652284Sobrien op0, 216752284Sobrien gen_safe_XOR64 (temp, 216852284Sobrien (-0x400 | trailing_bits)))); 216952284Sobrien } 217052284Sobrien return; 217152284Sobrien } 217252284Sobrien 217352284Sobrien /* 1) sethi %hi(xxx), %reg 217452284Sobrien * or %reg, %lo(xxx), %reg 217552284Sobrien * sllx %reg, yyy, %reg 217652284Sobrien * 217752284Sobrien * ??? This is just a generalized version of the low_bits==0 217852284Sobrien * thing above, FIXME... 217952284Sobrien */ 218052284Sobrien if ((highest_bit_set - lowest_bit_set) < 32) 218152284Sobrien { 218252284Sobrien unsigned HOST_WIDE_INT focus_bits = 218352284Sobrien create_simple_focus_bits (high_bits, low_bits, 218452284Sobrien lowest_bit_set, 0); 218552284Sobrien 218652284Sobrien /* We can't get here in this state. */ 218752284Sobrien if (highest_bit_set < 32 218852284Sobrien || lowest_bit_set >= 32) 218952284Sobrien abort (); 219052284Sobrien 219152284Sobrien /* So what we know is that the set bits straddle the 219252284Sobrien middle of the 64-bit word. */ 219352284Sobrien sparc_emit_set_const64_quick2 (op0, temp, 219452284Sobrien focus_bits, 0, 219552284Sobrien lowest_bit_set); 219652284Sobrien return; 219752284Sobrien } 219852284Sobrien 219952284Sobrien /* 1) sethi %hi(high_bits), %reg 220052284Sobrien * or %reg, %lo(high_bits), %reg 220152284Sobrien * sllx %reg, 32, %reg 220252284Sobrien * or %reg, low_bits, %reg 220352284Sobrien */ 220452284Sobrien if (SPARC_SIMM13_P(low_bits) 220552284Sobrien && ((int)low_bits > 0)) 220652284Sobrien { 220752284Sobrien sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_bits, 32); 220852284Sobrien return; 220952284Sobrien } 221052284Sobrien 221190075Sobrien /* The easiest way when all else fails, is full decomposition. */ 221252284Sobrien#if 0 221352284Sobrien printf ("sparc_emit_set_const64: Hard constant [%08lx%08lx] neg[%08lx%08lx]\n", 221452284Sobrien high_bits, low_bits, ~high_bits, ~low_bits); 221552284Sobrien#endif 221652284Sobrien sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits); 221752284Sobrien} 221852284Sobrien 221990075Sobrien/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, 222090075Sobrien return the mode to be used for the comparison. For floating-point, 222190075Sobrien CCFP[E]mode is used. CC_NOOVmode should be used when the first operand 222290075Sobrien is a PLUS, MINUS, NEG, or ASHIFT. CCmode should be used when no special 222390075Sobrien processing is needed. */ 222490075Sobrien 222590075Sobrienenum machine_mode 222690075Sobrienselect_cc_mode (op, x, y) 222790075Sobrien enum rtx_code op; 222890075Sobrien rtx x; 222990075Sobrien rtx y ATTRIBUTE_UNUSED; 223090075Sobrien{ 223190075Sobrien if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) 223290075Sobrien { 223390075Sobrien switch (op) 223490075Sobrien { 223590075Sobrien case EQ: 223690075Sobrien case NE: 223790075Sobrien case UNORDERED: 223890075Sobrien case ORDERED: 223990075Sobrien case UNLT: 224090075Sobrien case UNLE: 224190075Sobrien case UNGT: 224290075Sobrien case UNGE: 224390075Sobrien case UNEQ: 224490075Sobrien case LTGT: 224590075Sobrien return CCFPmode; 224690075Sobrien 224790075Sobrien case LT: 224890075Sobrien case LE: 224990075Sobrien case GT: 225090075Sobrien case GE: 225190075Sobrien return CCFPEmode; 225290075Sobrien 225390075Sobrien default: 225490075Sobrien abort (); 225590075Sobrien } 225690075Sobrien } 225790075Sobrien else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS 225890075Sobrien || GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT) 225990075Sobrien { 226090075Sobrien if (TARGET_ARCH64 && GET_MODE (x) == DImode) 226190075Sobrien return CCX_NOOVmode; 226290075Sobrien else 226390075Sobrien return CC_NOOVmode; 226490075Sobrien } 226590075Sobrien else 226690075Sobrien { 226790075Sobrien if (TARGET_ARCH64 && GET_MODE (x) == DImode) 226890075Sobrien return CCXmode; 226990075Sobrien else 227090075Sobrien return CCmode; 227190075Sobrien } 227290075Sobrien} 227390075Sobrien 227450397Sobrien/* X and Y are two things to compare using CODE. Emit the compare insn and 227550397Sobrien return the rtx for the cc reg in the proper mode. */ 227650397Sobrien 227750397Sobrienrtx 227850397Sobriengen_compare_reg (code, x, y) 227950397Sobrien enum rtx_code code; 228050397Sobrien rtx x, y; 228150397Sobrien{ 228250397Sobrien enum machine_mode mode = SELECT_CC_MODE (code, x, y); 228350397Sobrien rtx cc_reg; 228450397Sobrien 228550397Sobrien /* ??? We don't have movcc patterns so we cannot generate pseudo regs for the 228650397Sobrien fcc regs (cse can't tell they're really call clobbered regs and will 228750397Sobrien remove a duplicate comparison even if there is an intervening function 228850397Sobrien call - it will then try to reload the cc reg via an int reg which is why 228950397Sobrien we need the movcc patterns). It is possible to provide the movcc 229050397Sobrien patterns by using the ldxfsr/stxfsr v9 insns. I tried it: you need two 229150397Sobrien registers (say %g1,%g5) and it takes about 6 insns. A better fix would be 229250397Sobrien to tell cse that CCFPE mode registers (even pseudos) are call 229350397Sobrien clobbered. */ 229450397Sobrien 229550397Sobrien /* ??? This is an experiment. Rather than making changes to cse which may 229650397Sobrien or may not be easy/clean, we do our own cse. This is possible because 229750397Sobrien we will generate hard registers. Cse knows they're call clobbered (it 229850397Sobrien doesn't know the same thing about pseudos). If we guess wrong, no big 229950397Sobrien deal, but if we win, great! */ 230050397Sobrien 230150397Sobrien if (TARGET_V9 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) 230250397Sobrien#if 1 /* experiment */ 230350397Sobrien { 230450397Sobrien int reg; 230550397Sobrien /* We cycle through the registers to ensure they're all exercised. */ 230650397Sobrien static int next_fcc_reg = 0; 230750397Sobrien /* Previous x,y for each fcc reg. */ 230850397Sobrien static rtx prev_args[4][2]; 230950397Sobrien 231050397Sobrien /* Scan prev_args for x,y. */ 231150397Sobrien for (reg = 0; reg < 4; reg++) 231250397Sobrien if (prev_args[reg][0] == x && prev_args[reg][1] == y) 231350397Sobrien break; 231450397Sobrien if (reg == 4) 231550397Sobrien { 231650397Sobrien reg = next_fcc_reg; 231750397Sobrien prev_args[reg][0] = x; 231850397Sobrien prev_args[reg][1] = y; 231950397Sobrien next_fcc_reg = (next_fcc_reg + 1) & 3; 232050397Sobrien } 232150397Sobrien cc_reg = gen_rtx_REG (mode, reg + SPARC_FIRST_V9_FCC_REG); 232250397Sobrien } 232350397Sobrien#else 232450397Sobrien cc_reg = gen_reg_rtx (mode); 232550397Sobrien#endif /* ! experiment */ 232650397Sobrien else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) 232750397Sobrien cc_reg = gen_rtx_REG (mode, SPARC_FCC_REG); 232850397Sobrien else 232950397Sobrien cc_reg = gen_rtx_REG (mode, SPARC_ICC_REG); 233050397Sobrien 233152284Sobrien emit_insn (gen_rtx_SET (VOIDmode, cc_reg, 233250397Sobrien gen_rtx_COMPARE (mode, x, y))); 233350397Sobrien 233450397Sobrien return cc_reg; 233550397Sobrien} 233650397Sobrien 233750397Sobrien/* This function is used for v9 only. 233850397Sobrien CODE is the code for an Scc's comparison. 233950397Sobrien OPERANDS[0] is the target of the Scc insn. 234050397Sobrien OPERANDS[1] is the value we compare against const0_rtx (which hasn't 234150397Sobrien been generated yet). 234250397Sobrien 234350397Sobrien This function is needed to turn 234450397Sobrien 234550397Sobrien (set (reg:SI 110) 234650397Sobrien (gt (reg:CCX 100 %icc) 234750397Sobrien (const_int 0))) 234850397Sobrien into 234950397Sobrien (set (reg:SI 110) 235050397Sobrien (gt:DI (reg:CCX 100 %icc) 235150397Sobrien (const_int 0))) 235250397Sobrien 235350397Sobrien IE: The instruction recognizer needs to see the mode of the comparison to 235450397Sobrien find the right instruction. We could use "gt:DI" right in the 235550397Sobrien define_expand, but leaving it out allows us to handle DI, SI, etc. 235650397Sobrien 235750397Sobrien We refer to the global sparc compare operands sparc_compare_op0 and 235850397Sobrien sparc_compare_op1. */ 235950397Sobrien 236050397Sobrienint 236150397Sobriengen_v9_scc (compare_code, operands) 236250397Sobrien enum rtx_code compare_code; 236350397Sobrien register rtx *operands; 236450397Sobrien{ 236550397Sobrien rtx temp, op0, op1; 236650397Sobrien 236750397Sobrien if (! TARGET_ARCH64 236850397Sobrien && (GET_MODE (sparc_compare_op0) == DImode 236950397Sobrien || GET_MODE (operands[0]) == DImode)) 237050397Sobrien return 0; 237150397Sobrien 237296263Sobrien op0 = sparc_compare_op0; 237350397Sobrien op1 = sparc_compare_op1; 237450397Sobrien 237550397Sobrien /* Try to use the movrCC insns. */ 237650397Sobrien if (TARGET_ARCH64 237750397Sobrien && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT 237850397Sobrien && op1 == const0_rtx 237950397Sobrien && v9_regcmp_p (compare_code)) 238050397Sobrien { 238150397Sobrien /* Special case for op0 != 0. This can be done with one instruction if 238296263Sobrien operands[0] == sparc_compare_op0. */ 238350397Sobrien 238450397Sobrien if (compare_code == NE 238550397Sobrien && GET_MODE (operands[0]) == DImode 238696263Sobrien && rtx_equal_p (op0, operands[0])) 238750397Sobrien { 238850397Sobrien emit_insn (gen_rtx_SET (VOIDmode, operands[0], 238950397Sobrien gen_rtx_IF_THEN_ELSE (DImode, 239050397Sobrien gen_rtx_fmt_ee (compare_code, DImode, 239150397Sobrien op0, const0_rtx), 239250397Sobrien const1_rtx, 239350397Sobrien operands[0]))); 239450397Sobrien return 1; 239550397Sobrien } 239650397Sobrien 239796263Sobrien if (reg_overlap_mentioned_p (operands[0], op0)) 239896263Sobrien { 239996263Sobrien /* Handle the case where operands[0] == sparc_compare_op0. 240096263Sobrien We "early clobber" the result. */ 240196263Sobrien op0 = gen_reg_rtx (GET_MODE (sparc_compare_op0)); 240296263Sobrien emit_move_insn (op0, sparc_compare_op0); 240396263Sobrien } 240496263Sobrien 240550397Sobrien emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx)); 240650397Sobrien if (GET_MODE (op0) != DImode) 240750397Sobrien { 240850397Sobrien temp = gen_reg_rtx (DImode); 240950397Sobrien convert_move (temp, op0, 0); 241050397Sobrien } 241150397Sobrien else 241250397Sobrien temp = op0; 241350397Sobrien emit_insn (gen_rtx_SET (VOIDmode, operands[0], 241450397Sobrien gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), 241550397Sobrien gen_rtx_fmt_ee (compare_code, DImode, 241650397Sobrien temp, const0_rtx), 241750397Sobrien const1_rtx, 241850397Sobrien operands[0]))); 241950397Sobrien return 1; 242050397Sobrien } 242150397Sobrien else 242250397Sobrien { 242350397Sobrien operands[1] = gen_compare_reg (compare_code, op0, op1); 242450397Sobrien 242550397Sobrien switch (GET_MODE (operands[1])) 242650397Sobrien { 242750397Sobrien case CCmode : 242850397Sobrien case CCXmode : 242950397Sobrien case CCFPEmode : 243050397Sobrien case CCFPmode : 243150397Sobrien break; 243250397Sobrien default : 243350397Sobrien abort (); 243450397Sobrien } 243550397Sobrien emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx)); 243650397Sobrien emit_insn (gen_rtx_SET (VOIDmode, operands[0], 243750397Sobrien gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), 243850397Sobrien gen_rtx_fmt_ee (compare_code, 243950397Sobrien GET_MODE (operands[1]), 244050397Sobrien operands[1], const0_rtx), 244150397Sobrien const1_rtx, operands[0]))); 244250397Sobrien return 1; 244350397Sobrien } 244450397Sobrien} 244550397Sobrien 244650397Sobrien/* Emit a conditional jump insn for the v9 architecture using comparison code 244750397Sobrien CODE and jump target LABEL. 244850397Sobrien This function exists to take advantage of the v9 brxx insns. */ 244950397Sobrien 245050397Sobrienvoid 245150397Sobrienemit_v9_brxx_insn (code, op0, label) 245250397Sobrien enum rtx_code code; 245350397Sobrien rtx op0, label; 245450397Sobrien{ 245550397Sobrien emit_jump_insn (gen_rtx_SET (VOIDmode, 245650397Sobrien pc_rtx, 245750397Sobrien gen_rtx_IF_THEN_ELSE (VOIDmode, 245850397Sobrien gen_rtx_fmt_ee (code, GET_MODE (op0), 245950397Sobrien op0, const0_rtx), 246050397Sobrien gen_rtx_LABEL_REF (VOIDmode, label), 246150397Sobrien pc_rtx))); 246250397Sobrien} 246390075Sobrien 246490075Sobrien/* Generate a DFmode part of a hard TFmode register. 246590075Sobrien REG is the TFmode hard register, LOW is 1 for the 246690075Sobrien low 64bit of the register and 0 otherwise. 246790075Sobrien */ 246890075Sobrienrtx 246990075Sobriengen_df_reg (reg, low) 247090075Sobrien rtx reg; 247190075Sobrien int low; 247290075Sobrien{ 247390075Sobrien int regno = REGNO (reg); 247490075Sobrien 247590075Sobrien if ((WORDS_BIG_ENDIAN == 0) ^ (low != 0)) 247690075Sobrien regno += (TARGET_ARCH64 && regno < 32) ? 1 : 2; 247790075Sobrien return gen_rtx_REG (DFmode, regno); 247890075Sobrien} 247950397Sobrien 248096263Sobrien/* Generate a call to FUNC with OPERANDS. Operand 0 is the return value. 248196263Sobrien Unlike normal calls, TFmode operands are passed by reference. It is 248296263Sobrien assumed that no more than 3 operands are required. */ 248396263Sobrien 248496263Sobrienstatic void 248596263Sobrienemit_soft_tfmode_libcall (func_name, nargs, operands) 248696263Sobrien const char *func_name; 248796263Sobrien int nargs; 248896263Sobrien rtx *operands; 248996263Sobrien{ 249096263Sobrien rtx ret_slot = NULL, arg[3], func_sym; 249196263Sobrien int i; 249296263Sobrien 249396263Sobrien /* We only expect to be called for conversions, unary, and binary ops. */ 249496263Sobrien if (nargs < 2 || nargs > 3) 249596263Sobrien abort (); 249696263Sobrien 249796263Sobrien for (i = 0; i < nargs; ++i) 249896263Sobrien { 249996263Sobrien rtx this_arg = operands[i]; 250096263Sobrien rtx this_slot; 250196263Sobrien 250296263Sobrien /* TFmode arguments and return values are passed by reference. */ 250396263Sobrien if (GET_MODE (this_arg) == TFmode) 250496263Sobrien { 2505102780Skan int force_stack_temp; 2506102780Skan 2507102780Skan force_stack_temp = 0; 2508102780Skan if (TARGET_BUGGY_QP_LIB && i == 0) 2509102780Skan force_stack_temp = 1; 2510102780Skan 2511102780Skan if (GET_CODE (this_arg) == MEM 2512102780Skan && ! force_stack_temp) 251396263Sobrien this_arg = XEXP (this_arg, 0); 2514102780Skan else if (CONSTANT_P (this_arg) 2515102780Skan && ! force_stack_temp) 251696263Sobrien { 251796263Sobrien this_slot = force_const_mem (TFmode, this_arg); 251896263Sobrien this_arg = XEXP (this_slot, 0); 251996263Sobrien } 252096263Sobrien else 252196263Sobrien { 252296263Sobrien this_slot = assign_stack_temp (TFmode, GET_MODE_SIZE (TFmode), 0); 252396263Sobrien 252496263Sobrien /* Operand 0 is the return value. We'll copy it out later. */ 252596263Sobrien if (i > 0) 252696263Sobrien emit_move_insn (this_slot, this_arg); 252796263Sobrien else 252896263Sobrien ret_slot = this_slot; 252996263Sobrien 253096263Sobrien this_arg = XEXP (this_slot, 0); 253196263Sobrien } 253296263Sobrien } 253396263Sobrien 253496263Sobrien arg[i] = this_arg; 253596263Sobrien } 253696263Sobrien 253796263Sobrien func_sym = gen_rtx_SYMBOL_REF (Pmode, func_name); 253896263Sobrien 253996263Sobrien if (GET_MODE (operands[0]) == TFmode) 254096263Sobrien { 254196263Sobrien if (nargs == 2) 254296263Sobrien emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 2, 254396263Sobrien arg[0], GET_MODE (arg[0]), 254496263Sobrien arg[1], GET_MODE (arg[1])); 254596263Sobrien else 254696263Sobrien emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 3, 254796263Sobrien arg[0], GET_MODE (arg[0]), 254896263Sobrien arg[1], GET_MODE (arg[1]), 254996263Sobrien arg[2], GET_MODE (arg[2])); 255096263Sobrien 255196263Sobrien if (ret_slot) 255296263Sobrien emit_move_insn (operands[0], ret_slot); 255396263Sobrien } 255496263Sobrien else 255596263Sobrien { 255696263Sobrien rtx ret; 255796263Sobrien 255896263Sobrien if (nargs != 2) 255996263Sobrien abort (); 256096263Sobrien 256196263Sobrien ret = emit_library_call_value (func_sym, operands[0], LCT_NORMAL, 256296263Sobrien GET_MODE (operands[0]), 1, 256396263Sobrien arg[1], GET_MODE (arg[1])); 256496263Sobrien 256596263Sobrien if (ret != operands[0]) 256696263Sobrien emit_move_insn (operands[0], ret); 256796263Sobrien } 256896263Sobrien} 256996263Sobrien 257096263Sobrien/* Expand soft-float TFmode calls to sparc abi routines. */ 257196263Sobrien 257296263Sobrienstatic void 257396263Sobrienemit_soft_tfmode_binop (code, operands) 257496263Sobrien enum rtx_code code; 257596263Sobrien rtx *operands; 257696263Sobrien{ 257796263Sobrien const char *func; 257896263Sobrien 257996263Sobrien switch (code) 258096263Sobrien { 258196263Sobrien case PLUS: 258296263Sobrien func = "_Qp_add"; 258396263Sobrien break; 258496263Sobrien case MINUS: 258596263Sobrien func = "_Qp_sub"; 258696263Sobrien break; 258796263Sobrien case MULT: 258896263Sobrien func = "_Qp_mul"; 258996263Sobrien break; 259096263Sobrien case DIV: 259196263Sobrien func = "_Qp_div"; 259296263Sobrien break; 259396263Sobrien default: 259496263Sobrien abort (); 259596263Sobrien } 259696263Sobrien 259796263Sobrien emit_soft_tfmode_libcall (func, 3, operands); 259896263Sobrien} 259996263Sobrien 260096263Sobrienstatic void 260196263Sobrienemit_soft_tfmode_unop (code, operands) 260296263Sobrien enum rtx_code code; 260396263Sobrien rtx *operands; 260496263Sobrien{ 260596263Sobrien const char *func; 260696263Sobrien 260796263Sobrien switch (code) 260896263Sobrien { 260996263Sobrien case SQRT: 261096263Sobrien func = "_Qp_sqrt"; 261196263Sobrien break; 261296263Sobrien default: 261396263Sobrien abort (); 261496263Sobrien } 261596263Sobrien 261696263Sobrien emit_soft_tfmode_libcall (func, 2, operands); 261796263Sobrien} 261896263Sobrien 261996263Sobrienstatic void 262096263Sobrienemit_soft_tfmode_cvt (code, operands) 262196263Sobrien enum rtx_code code; 262296263Sobrien rtx *operands; 262396263Sobrien{ 262496263Sobrien const char *func; 262596263Sobrien 262696263Sobrien switch (code) 262796263Sobrien { 262896263Sobrien case FLOAT_EXTEND: 262996263Sobrien switch (GET_MODE (operands[1])) 263096263Sobrien { 263196263Sobrien case SFmode: 263296263Sobrien func = "_Qp_stoq"; 263396263Sobrien break; 263496263Sobrien case DFmode: 263596263Sobrien func = "_Qp_dtoq"; 263696263Sobrien break; 263796263Sobrien default: 263896263Sobrien abort (); 263996263Sobrien } 264096263Sobrien break; 264196263Sobrien 264296263Sobrien case FLOAT_TRUNCATE: 264396263Sobrien switch (GET_MODE (operands[0])) 264496263Sobrien { 264596263Sobrien case SFmode: 264696263Sobrien func = "_Qp_qtos"; 264796263Sobrien break; 264896263Sobrien case DFmode: 264996263Sobrien func = "_Qp_qtod"; 265096263Sobrien break; 265196263Sobrien default: 265296263Sobrien abort (); 265396263Sobrien } 265496263Sobrien break; 265596263Sobrien 265696263Sobrien case FLOAT: 265796263Sobrien switch (GET_MODE (operands[1])) 265896263Sobrien { 265996263Sobrien case SImode: 266096263Sobrien func = "_Qp_itoq"; 266196263Sobrien break; 266296263Sobrien case DImode: 266396263Sobrien func = "_Qp_xtoq"; 266496263Sobrien break; 266596263Sobrien default: 266696263Sobrien abort (); 266796263Sobrien } 266896263Sobrien break; 266996263Sobrien 267096263Sobrien case UNSIGNED_FLOAT: 267196263Sobrien switch (GET_MODE (operands[1])) 267296263Sobrien { 267396263Sobrien case SImode: 267496263Sobrien func = "_Qp_uitoq"; 267596263Sobrien break; 267696263Sobrien case DImode: 267796263Sobrien func = "_Qp_uxtoq"; 267896263Sobrien break; 267996263Sobrien default: 268096263Sobrien abort (); 268196263Sobrien } 268296263Sobrien break; 268396263Sobrien 268496263Sobrien case FIX: 268596263Sobrien switch (GET_MODE (operands[0])) 268696263Sobrien { 268796263Sobrien case SImode: 268896263Sobrien func = "_Qp_qtoi"; 268996263Sobrien break; 269096263Sobrien case DImode: 269196263Sobrien func = "_Qp_qtox"; 269296263Sobrien break; 269396263Sobrien default: 269496263Sobrien abort (); 269596263Sobrien } 269696263Sobrien break; 269796263Sobrien 269896263Sobrien case UNSIGNED_FIX: 269996263Sobrien switch (GET_MODE (operands[0])) 270096263Sobrien { 270196263Sobrien case SImode: 270296263Sobrien func = "_Qp_qtoui"; 270396263Sobrien break; 270496263Sobrien case DImode: 270596263Sobrien func = "_Qp_qtoux"; 270696263Sobrien break; 270796263Sobrien default: 270896263Sobrien abort (); 270996263Sobrien } 271096263Sobrien break; 271196263Sobrien 271296263Sobrien default: 271396263Sobrien abort (); 271496263Sobrien } 271596263Sobrien 271696263Sobrien emit_soft_tfmode_libcall (func, 2, operands); 271796263Sobrien} 271896263Sobrien 271996263Sobrien/* Expand a hard-float tfmode operation. All arguments must be in 272096263Sobrien registers. */ 272196263Sobrien 272296263Sobrienstatic void 272396263Sobrienemit_hard_tfmode_operation (code, operands) 272496263Sobrien enum rtx_code code; 272596263Sobrien rtx *operands; 272696263Sobrien{ 272796263Sobrien rtx op, dest; 272896263Sobrien 272996263Sobrien if (GET_RTX_CLASS (code) == '1') 273096263Sobrien { 273196263Sobrien operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); 273296263Sobrien op = gen_rtx_fmt_e (code, GET_MODE (operands[0]), operands[1]); 273396263Sobrien } 273496263Sobrien else 273596263Sobrien { 273696263Sobrien operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); 273796263Sobrien operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); 273896263Sobrien op = gen_rtx_fmt_ee (code, GET_MODE (operands[0]), 273996263Sobrien operands[1], operands[2]); 274096263Sobrien } 274196263Sobrien 274296263Sobrien if (register_operand (operands[0], VOIDmode)) 274396263Sobrien dest = operands[0]; 274496263Sobrien else 274596263Sobrien dest = gen_reg_rtx (GET_MODE (operands[0])); 274696263Sobrien 274796263Sobrien emit_insn (gen_rtx_SET (VOIDmode, dest, op)); 274896263Sobrien 274996263Sobrien if (dest != operands[0]) 275096263Sobrien emit_move_insn (operands[0], dest); 275196263Sobrien} 275296263Sobrien 275396263Sobrienvoid 275496263Sobrienemit_tfmode_binop (code, operands) 275596263Sobrien enum rtx_code code; 275696263Sobrien rtx *operands; 275796263Sobrien{ 275896263Sobrien if (TARGET_HARD_QUAD) 275996263Sobrien emit_hard_tfmode_operation (code, operands); 276096263Sobrien else 276196263Sobrien emit_soft_tfmode_binop (code, operands); 276296263Sobrien} 276396263Sobrien 276496263Sobrienvoid 276596263Sobrienemit_tfmode_unop (code, operands) 276696263Sobrien enum rtx_code code; 276796263Sobrien rtx *operands; 276896263Sobrien{ 276996263Sobrien if (TARGET_HARD_QUAD) 277096263Sobrien emit_hard_tfmode_operation (code, operands); 277196263Sobrien else 277296263Sobrien emit_soft_tfmode_unop (code, operands); 277396263Sobrien} 277496263Sobrien 277596263Sobrienvoid 277696263Sobrienemit_tfmode_cvt (code, operands) 277796263Sobrien enum rtx_code code; 277896263Sobrien rtx *operands; 277996263Sobrien{ 278096263Sobrien if (TARGET_HARD_QUAD) 278196263Sobrien emit_hard_tfmode_operation (code, operands); 278296263Sobrien else 278396263Sobrien emit_soft_tfmode_cvt (code, operands); 278496263Sobrien} 278596263Sobrien 278650397Sobrien/* Return nonzero if a return peephole merging return with 278750397Sobrien setting of output register is ok. */ 278850397Sobrienint 278950397Sobrienleaf_return_peephole_ok () 279050397Sobrien{ 279150397Sobrien return (actual_fsize == 0); 279250397Sobrien} 279350397Sobrien 279496263Sobrien/* Return nonzero if a branch/jump/call instruction will be emitting 279596263Sobrien nop into its delay slot. */ 279696263Sobrien 279796263Sobrienint 279896263Sobrienempty_delay_slot (insn) 279996263Sobrien rtx insn; 280096263Sobrien{ 280196263Sobrien rtx seq; 280296263Sobrien 280396263Sobrien /* If no previous instruction (should not happen), return true. */ 280496263Sobrien if (PREV_INSN (insn) == NULL) 280596263Sobrien return 1; 280696263Sobrien 280796263Sobrien seq = NEXT_INSN (PREV_INSN (insn)); 280896263Sobrien if (GET_CODE (PATTERN (seq)) == SEQUENCE) 280996263Sobrien return 0; 281096263Sobrien 281196263Sobrien return 1; 281296263Sobrien} 281396263Sobrien 281450397Sobrien/* Return nonzero if TRIAL can go into the function epilogue's 281550397Sobrien delay slot. SLOT is the slot we are trying to fill. */ 281650397Sobrien 281750397Sobrienint 281850397Sobrieneligible_for_epilogue_delay (trial, slot) 281950397Sobrien rtx trial; 282050397Sobrien int slot; 282150397Sobrien{ 282250397Sobrien rtx pat, src; 282350397Sobrien 282450397Sobrien if (slot >= 1) 282550397Sobrien return 0; 282650397Sobrien 282750397Sobrien if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET) 282850397Sobrien return 0; 282950397Sobrien 283050397Sobrien if (get_attr_length (trial) != 1) 283150397Sobrien return 0; 283250397Sobrien 283390075Sobrien /* If there are any call-saved registers, we should scan TRIAL if it 283490075Sobrien does not reference them. For now just make it easy. */ 283590075Sobrien if (num_gfregs) 283650397Sobrien return 0; 283750397Sobrien 283890075Sobrien /* If the function uses __builtin_eh_return, the eh_return machinery 283990075Sobrien occupies the delay slot. */ 284090075Sobrien if (current_function_calls_eh_return) 284190075Sobrien return 0; 284290075Sobrien 284350397Sobrien /* In the case of a true leaf function, anything can go into the delay slot. 284450397Sobrien A delay slot only exists however if the frame size is zero, otherwise 284550397Sobrien we will put an insn to adjust the stack after the return. */ 284652284Sobrien if (current_function_uses_only_leaf_regs) 284750397Sobrien { 284850397Sobrien if (leaf_return_peephole_ok ()) 284950397Sobrien return ((get_attr_in_uncond_branch_delay (trial) 285050397Sobrien == IN_BRANCH_DELAY_TRUE)); 285150397Sobrien return 0; 285250397Sobrien } 285350397Sobrien 285450397Sobrien pat = PATTERN (trial); 285550397Sobrien 285650397Sobrien /* Otherwise, only operations which can be done in tandem with 285790075Sobrien a `restore' or `return' insn can go into the delay slot. */ 285850397Sobrien if (GET_CODE (SET_DEST (pat)) != REG 285950397Sobrien || REGNO (SET_DEST (pat)) < 24) 286050397Sobrien return 0; 286150397Sobrien 286290075Sobrien /* If this instruction sets up floating point register and we have a return 286390075Sobrien instruction, it can probably go in. But restore will not work 286490075Sobrien with FP_REGS. */ 286590075Sobrien if (REGNO (SET_DEST (pat)) >= 32) 286690075Sobrien { 286790075Sobrien if (TARGET_V9 && ! epilogue_renumber (&pat, 1) 286890075Sobrien && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE)) 286990075Sobrien return 1; 287090075Sobrien return 0; 287190075Sobrien } 287290075Sobrien 287350397Sobrien /* The set of insns matched here must agree precisely with the set of 287450397Sobrien patterns paired with a RETURN in sparc.md. */ 287550397Sobrien 287650397Sobrien src = SET_SRC (pat); 287750397Sobrien 287852284Sobrien /* This matches "*return_[qhs]i" or even "*return_di" on TARGET_ARCH64. */ 287990075Sobrien if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT 288090075Sobrien && arith_operand (src, GET_MODE (src))) 288152284Sobrien { 288252284Sobrien if (TARGET_ARCH64) 288352284Sobrien return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); 288452284Sobrien else 288552284Sobrien return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode); 288652284Sobrien } 288790075Sobrien 288850397Sobrien /* This matches "*return_di". */ 288990075Sobrien else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT 289090075Sobrien && arith_double_operand (src, GET_MODE (src))) 289150397Sobrien return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); 289250397Sobrien 289350397Sobrien /* This matches "*return_sf_no_fpu". */ 289450397Sobrien else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode) 289550397Sobrien && register_operand (src, SFmode)) 289650397Sobrien return 1; 289750397Sobrien 289890075Sobrien /* If we have return instruction, anything that does not use 289990075Sobrien local or output registers and can go into a delay slot wins. */ 290090075Sobrien else if (TARGET_V9 && ! epilogue_renumber (&pat, 1) 290190075Sobrien && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE)) 290290075Sobrien return 1; 290390075Sobrien 290450397Sobrien /* This matches "*return_addsi". */ 290550397Sobrien else if (GET_CODE (src) == PLUS 290650397Sobrien && arith_operand (XEXP (src, 0), SImode) 290750397Sobrien && arith_operand (XEXP (src, 1), SImode) 290850397Sobrien && (register_operand (XEXP (src, 0), SImode) 290950397Sobrien || register_operand (XEXP (src, 1), SImode))) 291050397Sobrien return 1; 291150397Sobrien 291250397Sobrien /* This matches "*return_adddi". */ 291350397Sobrien else if (GET_CODE (src) == PLUS 291450397Sobrien && arith_double_operand (XEXP (src, 0), DImode) 291550397Sobrien && arith_double_operand (XEXP (src, 1), DImode) 291650397Sobrien && (register_operand (XEXP (src, 0), DImode) 291750397Sobrien || register_operand (XEXP (src, 1), DImode))) 291850397Sobrien return 1; 291950397Sobrien 292090075Sobrien /* This can match "*return_losum_[sd]i". 292190075Sobrien Catch only some cases, so that return_losum* don't have 292290075Sobrien to be too big. */ 292390075Sobrien else if (GET_CODE (src) == LO_SUM 292490075Sobrien && ! TARGET_CM_MEDMID 292590075Sobrien && ((register_operand (XEXP (src, 0), SImode) 292690075Sobrien && immediate_operand (XEXP (src, 1), SImode)) 292790075Sobrien || (TARGET_ARCH64 292890075Sobrien && register_operand (XEXP (src, 0), DImode) 292990075Sobrien && immediate_operand (XEXP (src, 1), DImode)))) 293090075Sobrien return 1; 293190075Sobrien 293290075Sobrien /* sll{,x} reg,1,reg2 is add reg,reg,reg2 as well. */ 293390075Sobrien else if (GET_CODE (src) == ASHIFT 293490075Sobrien && (register_operand (XEXP (src, 0), SImode) 293590075Sobrien || register_operand (XEXP (src, 0), DImode)) 293690075Sobrien && XEXP (src, 1) == const1_rtx) 293790075Sobrien return 1; 293890075Sobrien 293950397Sobrien return 0; 294050397Sobrien} 294150397Sobrien 294290075Sobrien/* Return nonzero if TRIAL can go into the sibling call 294390075Sobrien delay slot. */ 294490075Sobrien 294590075Sobrienint 294690075Sobrieneligible_for_sibcall_delay (trial) 294790075Sobrien rtx trial; 294890075Sobrien{ 294990075Sobrien rtx pat, src; 295090075Sobrien 295190075Sobrien if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET) 295290075Sobrien return 0; 295390075Sobrien 295490075Sobrien if (get_attr_length (trial) != 1) 295590075Sobrien return 0; 295690075Sobrien 295790075Sobrien pat = PATTERN (trial); 295890075Sobrien 295990075Sobrien if (current_function_uses_only_leaf_regs) 296090075Sobrien { 296190075Sobrien /* If the tail call is done using the call instruction, 296290075Sobrien we have to restore %o7 in the delay slot. */ 296390075Sobrien if ((TARGET_ARCH64 && ! TARGET_CM_MEDLOW) || flag_pic) 296490075Sobrien return 0; 296590075Sobrien 296690075Sobrien /* %g1 is used to build the function address */ 296790075Sobrien if (reg_mentioned_p (gen_rtx_REG (Pmode, 1), pat)) 296890075Sobrien return 0; 296990075Sobrien 297090075Sobrien return 1; 297190075Sobrien } 297290075Sobrien 297390075Sobrien /* Otherwise, only operations which can be done in tandem with 297490075Sobrien a `restore' insn can go into the delay slot. */ 297590075Sobrien if (GET_CODE (SET_DEST (pat)) != REG 297690075Sobrien || REGNO (SET_DEST (pat)) < 24 297790075Sobrien || REGNO (SET_DEST (pat)) >= 32) 297890075Sobrien return 0; 297990075Sobrien 298090075Sobrien /* If it mentions %o7, it can't go in, because sibcall will clobber it 298190075Sobrien in most cases. */ 298290075Sobrien if (reg_mentioned_p (gen_rtx_REG (Pmode, 15), pat)) 298390075Sobrien return 0; 298490075Sobrien 298590075Sobrien src = SET_SRC (pat); 298690075Sobrien 298790075Sobrien if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT 298890075Sobrien && arith_operand (src, GET_MODE (src))) 298990075Sobrien { 299090075Sobrien if (TARGET_ARCH64) 299190075Sobrien return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); 299290075Sobrien else 299390075Sobrien return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode); 299490075Sobrien } 299590075Sobrien 299690075Sobrien else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT 299790075Sobrien && arith_double_operand (src, GET_MODE (src))) 299890075Sobrien return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); 299990075Sobrien 300090075Sobrien else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode) 300190075Sobrien && register_operand (src, SFmode)) 300290075Sobrien return 1; 300390075Sobrien 300490075Sobrien else if (GET_CODE (src) == PLUS 300590075Sobrien && arith_operand (XEXP (src, 0), SImode) 300690075Sobrien && arith_operand (XEXP (src, 1), SImode) 300790075Sobrien && (register_operand (XEXP (src, 0), SImode) 300890075Sobrien || register_operand (XEXP (src, 1), SImode))) 300990075Sobrien return 1; 301090075Sobrien 301190075Sobrien else if (GET_CODE (src) == PLUS 301290075Sobrien && arith_double_operand (XEXP (src, 0), DImode) 301390075Sobrien && arith_double_operand (XEXP (src, 1), DImode) 301490075Sobrien && (register_operand (XEXP (src, 0), DImode) 301590075Sobrien || register_operand (XEXP (src, 1), DImode))) 301690075Sobrien return 1; 301790075Sobrien 301890075Sobrien else if (GET_CODE (src) == LO_SUM 301990075Sobrien && ! TARGET_CM_MEDMID 302090075Sobrien && ((register_operand (XEXP (src, 0), SImode) 302190075Sobrien && immediate_operand (XEXP (src, 1), SImode)) 302290075Sobrien || (TARGET_ARCH64 302390075Sobrien && register_operand (XEXP (src, 0), DImode) 302490075Sobrien && immediate_operand (XEXP (src, 1), DImode)))) 302590075Sobrien return 1; 302690075Sobrien 302790075Sobrien else if (GET_CODE (src) == ASHIFT 302890075Sobrien && (register_operand (XEXP (src, 0), SImode) 302990075Sobrien || register_operand (XEXP (src, 0), DImode)) 303090075Sobrien && XEXP (src, 1) == const1_rtx) 303190075Sobrien return 1; 303290075Sobrien 303390075Sobrien return 0; 303490075Sobrien} 303590075Sobrien 303650397Sobrienstatic int 303750397Sobriencheck_return_regs (x) 303850397Sobrien rtx x; 303950397Sobrien{ 304050397Sobrien switch (GET_CODE (x)) 304150397Sobrien { 304250397Sobrien case REG: 304350397Sobrien return IN_OR_GLOBAL_P (x); 304450397Sobrien 304550397Sobrien case CONST_INT: 304650397Sobrien case CONST_DOUBLE: 304750397Sobrien case CONST: 304850397Sobrien case SYMBOL_REF: 304950397Sobrien case LABEL_REF: 305050397Sobrien return 1; 305150397Sobrien 305250397Sobrien case SET: 305350397Sobrien case IOR: 305450397Sobrien case AND: 305550397Sobrien case XOR: 305650397Sobrien case PLUS: 305750397Sobrien case MINUS: 305850397Sobrien if (check_return_regs (XEXP (x, 1)) == 0) 305950397Sobrien return 0; 306050397Sobrien case NOT: 306150397Sobrien case NEG: 306250397Sobrien case MEM: 306350397Sobrien return check_return_regs (XEXP (x, 0)); 306450397Sobrien 306550397Sobrien default: 306650397Sobrien return 0; 306750397Sobrien } 306850397Sobrien 306950397Sobrien} 307050397Sobrien 307150397Sobrienint 307250397Sobrienshort_branch (uid1, uid2) 307350397Sobrien int uid1, uid2; 307450397Sobrien{ 307590075Sobrien int delta = INSN_ADDRESSES (uid1) - INSN_ADDRESSES (uid2); 307690075Sobrien 307790075Sobrien /* Leave a few words of "slop". */ 307890075Sobrien if (delta >= -1023 && delta <= 1022) 307950397Sobrien return 1; 308090075Sobrien 308150397Sobrien return 0; 308250397Sobrien} 308350397Sobrien 3084117395Skan/* Return nonzero if REG is not used after INSN. 308550397Sobrien We assume REG is a reload reg, and therefore does 308650397Sobrien not live past labels or calls or jumps. */ 308750397Sobrienint 308850397Sobrienreg_unused_after (reg, insn) 308950397Sobrien rtx reg; 309050397Sobrien rtx insn; 309150397Sobrien{ 309250397Sobrien enum rtx_code code, prev_code = UNKNOWN; 309350397Sobrien 309450397Sobrien while ((insn = NEXT_INSN (insn))) 309550397Sobrien { 309650397Sobrien if (prev_code == CALL_INSN && call_used_regs[REGNO (reg)]) 309750397Sobrien return 1; 309850397Sobrien 309950397Sobrien code = GET_CODE (insn); 310050397Sobrien if (GET_CODE (insn) == CODE_LABEL) 310150397Sobrien return 1; 310250397Sobrien 310350397Sobrien if (GET_RTX_CLASS (code) == 'i') 310450397Sobrien { 310550397Sobrien rtx set = single_set (insn); 310650397Sobrien int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set)); 310750397Sobrien if (set && in_src) 310850397Sobrien return 0; 310950397Sobrien if (set && reg_overlap_mentioned_p (reg, SET_DEST (set))) 311050397Sobrien return 1; 311150397Sobrien if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn))) 311250397Sobrien return 0; 311350397Sobrien } 311450397Sobrien prev_code = code; 311550397Sobrien } 311650397Sobrien return 1; 311750397Sobrien} 311850397Sobrien 311950397Sobrien/* The table we use to reference PIC data. */ 3120117395Skanstatic GTY(()) rtx global_offset_table; 312150397Sobrien 312250397Sobrien/* The function we use to get at it. */ 3123117395Skanstatic GTY(()) rtx get_pc_symbol; 312450397Sobrienstatic char get_pc_symbol_name[256]; 312550397Sobrien 312650397Sobrien/* Ensure that we are not using patterns that are not OK with PIC. */ 312750397Sobrien 312850397Sobrienint 312950397Sobriencheck_pic (i) 313050397Sobrien int i; 313150397Sobrien{ 313250397Sobrien switch (flag_pic) 313350397Sobrien { 313450397Sobrien case 1: 313590075Sobrien if (GET_CODE (recog_data.operand[i]) == SYMBOL_REF 313690075Sobrien || (GET_CODE (recog_data.operand[i]) == CONST 313790075Sobrien && ! (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS 313890075Sobrien && (XEXP (XEXP (recog_data.operand[i], 0), 0) 313950397Sobrien == global_offset_table) 314090075Sobrien && (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1)) 314150397Sobrien == CONST)))) 314250397Sobrien abort (); 314350397Sobrien case 2: 314450397Sobrien default: 314550397Sobrien return 1; 314650397Sobrien } 314750397Sobrien} 314850397Sobrien 314950397Sobrien/* Return true if X is an address which needs a temporary register when 315050397Sobrien reloaded while generating PIC code. */ 315150397Sobrien 315250397Sobrienint 315350397Sobrienpic_address_needs_scratch (x) 315450397Sobrien rtx x; 315550397Sobrien{ 315650397Sobrien /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ 315750397Sobrien if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS 315850397Sobrien && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF 315950397Sobrien && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT 316050397Sobrien && ! SMALL_INT (XEXP (XEXP (x, 0), 1))) 316150397Sobrien return 1; 316250397Sobrien 316350397Sobrien return 0; 316450397Sobrien} 316550397Sobrien 316650397Sobrien/* Legitimize PIC addresses. If the address is already position-independent, 316750397Sobrien we return ORIG. Newly generated position-independent addresses go into a 3168117395Skan reg. This is REG if nonzero, otherwise we allocate register(s) as 316950397Sobrien necessary. */ 317050397Sobrien 317150397Sobrienrtx 317250397Sobrienlegitimize_pic_address (orig, mode, reg) 317350397Sobrien rtx orig; 317450397Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 317550397Sobrien rtx reg; 317650397Sobrien{ 317752284Sobrien if (GET_CODE (orig) == SYMBOL_REF) 317850397Sobrien { 317950397Sobrien rtx pic_ref, address; 318050397Sobrien rtx insn; 318150397Sobrien 318250397Sobrien if (reg == 0) 318350397Sobrien { 318450397Sobrien if (reload_in_progress || reload_completed) 318550397Sobrien abort (); 318650397Sobrien else 318750397Sobrien reg = gen_reg_rtx (Pmode); 318850397Sobrien } 318950397Sobrien 319050397Sobrien if (flag_pic == 2) 319150397Sobrien { 319250397Sobrien /* If not during reload, allocate another temp reg here for loading 319350397Sobrien in the address, so that these instructions can be optimized 319450397Sobrien properly. */ 319550397Sobrien rtx temp_reg = ((reload_in_progress || reload_completed) 319650397Sobrien ? reg : gen_reg_rtx (Pmode)); 319750397Sobrien 319850397Sobrien /* Must put the SYMBOL_REF inside an UNSPEC here so that cse 319950397Sobrien won't get confused into thinking that these two instructions 320050397Sobrien are loading in the true address of the symbol. If in the 320150397Sobrien future a PIC rtx exists, that should be used instead. */ 320252284Sobrien if (Pmode == SImode) 320352284Sobrien { 320452284Sobrien emit_insn (gen_movsi_high_pic (temp_reg, orig)); 320552284Sobrien emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig)); 320652284Sobrien } 320752284Sobrien else 320852284Sobrien { 320952284Sobrien emit_insn (gen_movdi_high_pic (temp_reg, orig)); 321052284Sobrien emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig)); 321152284Sobrien } 321250397Sobrien address = temp_reg; 321350397Sobrien } 321450397Sobrien else 321550397Sobrien address = orig; 321650397Sobrien 321750397Sobrien pic_ref = gen_rtx_MEM (Pmode, 321890075Sobrien gen_rtx_PLUS (Pmode, 321990075Sobrien pic_offset_table_rtx, address)); 322050397Sobrien current_function_uses_pic_offset_table = 1; 322150397Sobrien RTX_UNCHANGING_P (pic_ref) = 1; 322250397Sobrien insn = emit_move_insn (reg, pic_ref); 322350397Sobrien /* Put a REG_EQUAL note on this insn, so that it can be optimized 322450397Sobrien by loop. */ 322550397Sobrien REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, 322650397Sobrien REG_NOTES (insn)); 322750397Sobrien return reg; 322850397Sobrien } 322950397Sobrien else if (GET_CODE (orig) == CONST) 323050397Sobrien { 323150397Sobrien rtx base, offset; 323250397Sobrien 323350397Sobrien if (GET_CODE (XEXP (orig, 0)) == PLUS 323450397Sobrien && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) 323550397Sobrien return orig; 323650397Sobrien 323750397Sobrien if (reg == 0) 323850397Sobrien { 323950397Sobrien if (reload_in_progress || reload_completed) 324050397Sobrien abort (); 324150397Sobrien else 324250397Sobrien reg = gen_reg_rtx (Pmode); 324350397Sobrien } 324450397Sobrien 324550397Sobrien if (GET_CODE (XEXP (orig, 0)) == PLUS) 324650397Sobrien { 324750397Sobrien base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); 324850397Sobrien offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, 324950397Sobrien base == reg ? 0 : reg); 325050397Sobrien } 325150397Sobrien else 325250397Sobrien abort (); 325350397Sobrien 325450397Sobrien if (GET_CODE (offset) == CONST_INT) 325550397Sobrien { 325650397Sobrien if (SMALL_INT (offset)) 325790075Sobrien return plus_constant (base, INTVAL (offset)); 325850397Sobrien else if (! reload_in_progress && ! reload_completed) 325950397Sobrien offset = force_reg (Pmode, offset); 326050397Sobrien else 326150397Sobrien /* If we reach here, then something is seriously wrong. */ 326250397Sobrien abort (); 326350397Sobrien } 326450397Sobrien return gen_rtx_PLUS (Pmode, base, offset); 326550397Sobrien } 326652284Sobrien else if (GET_CODE (orig) == LABEL_REF) 326752284Sobrien /* ??? Why do we do this? */ 326852284Sobrien /* Now movsi_pic_label_ref uses it, but we ought to be checking that 326952284Sobrien the register is live instead, in case it is eliminated. */ 327052284Sobrien current_function_uses_pic_offset_table = 1; 327150397Sobrien 327250397Sobrien return orig; 327350397Sobrien} 327450397Sobrien 327590075Sobrien/* Emit special PIC prologues. */ 327650397Sobrien 327750397Sobrienvoid 327890075Sobrienload_pic_register () 327950397Sobrien{ 328050397Sobrien /* Labels to get the PC in the prologue of this function. */ 328150397Sobrien int orig_flag_pic = flag_pic; 328250397Sobrien 328350397Sobrien if (! flag_pic) 328450397Sobrien abort (); 328550397Sobrien 328690075Sobrien /* If we haven't emitted the special get_pc helper function, do so now. */ 328750397Sobrien if (get_pc_symbol_name[0] == 0) 328850397Sobrien { 328952284Sobrien int align; 329052284Sobrien 329150397Sobrien ASM_GENERATE_INTERNAL_LABEL (get_pc_symbol_name, "LGETPC", 0); 329252284Sobrien text_section (); 329350397Sobrien 329452284Sobrien align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); 329552284Sobrien if (align > 0) 329652284Sobrien ASM_OUTPUT_ALIGN (asm_out_file, align); 329750397Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LGETPC", 0); 329890075Sobrien fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file); 329950397Sobrien } 330050397Sobrien 330150397Sobrien /* Initialize every time through, since we can't easily 330250397Sobrien know this to be permanent. */ 330350397Sobrien global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); 330450397Sobrien get_pc_symbol = gen_rtx_SYMBOL_REF (Pmode, get_pc_symbol_name); 330550397Sobrien flag_pic = 0; 330650397Sobrien 330790075Sobrien emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table, 330890075Sobrien get_pc_symbol)); 330950397Sobrien 331050397Sobrien flag_pic = orig_flag_pic; 331150397Sobrien 331250397Sobrien /* Need to emit this whether or not we obey regdecls, 331350397Sobrien since setjmp/longjmp can cause life info to screw up. 331450397Sobrien ??? In the case where we don't obey regdecls, this is not sufficient 331550397Sobrien since we may not fall out the bottom. */ 331650397Sobrien emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx)); 331750397Sobrien} 331850397Sobrien 331952284Sobrien/* Return 1 if RTX is a MEM which is known to be aligned to at 332096263Sobrien least a DESIRED byte boundary. */ 332150397Sobrien 332250397Sobrienint 332352284Sobrienmem_min_alignment (mem, desired) 332452284Sobrien rtx mem; 332552284Sobrien int desired; 332650397Sobrien{ 332752284Sobrien rtx addr, base, offset; 332850397Sobrien 332952284Sobrien /* If it's not a MEM we can't accept it. */ 333050397Sobrien if (GET_CODE (mem) != MEM) 333152284Sobrien return 0; 333250397Sobrien 333350397Sobrien addr = XEXP (mem, 0); 333452284Sobrien base = offset = NULL_RTX; 333550397Sobrien if (GET_CODE (addr) == PLUS) 333650397Sobrien { 333752284Sobrien if (GET_CODE (XEXP (addr, 0)) == REG) 333850397Sobrien { 333950397Sobrien base = XEXP (addr, 0); 334052284Sobrien 334152284Sobrien /* What we are saying here is that if the base 334252284Sobrien REG is aligned properly, the compiler will make 334352284Sobrien sure any REG based index upon it will be so 334452284Sobrien as well. */ 334552284Sobrien if (GET_CODE (XEXP (addr, 1)) == CONST_INT) 334652284Sobrien offset = XEXP (addr, 1); 334752284Sobrien else 334852284Sobrien offset = const0_rtx; 334950397Sobrien } 335050397Sobrien } 335150397Sobrien else if (GET_CODE (addr) == REG) 335250397Sobrien { 335350397Sobrien base = addr; 335450397Sobrien offset = const0_rtx; 335550397Sobrien } 335650397Sobrien 335752284Sobrien if (base != NULL_RTX) 335850397Sobrien { 335952284Sobrien int regno = REGNO (base); 336050397Sobrien 336196263Sobrien if (regno != HARD_FRAME_POINTER_REGNUM && regno != STACK_POINTER_REGNUM) 336250397Sobrien { 336352284Sobrien /* Check if the compiler has recorded some information 336452284Sobrien about the alignment of the base REG. If reload has 336590075Sobrien completed, we already matched with proper alignments. 336690075Sobrien If not running global_alloc, reload might give us 336790075Sobrien unaligned pointer to local stack though. */ 336890075Sobrien if (((cfun != 0 336990075Sobrien && REGNO_POINTER_ALIGN (regno) >= desired * BITS_PER_UNIT) 337090075Sobrien || (optimize && reload_completed)) 337190075Sobrien && (INTVAL (offset) & (desired - 1)) == 0) 337252284Sobrien return 1; 337350397Sobrien } 337450397Sobrien else 337550397Sobrien { 337652284Sobrien if (((INTVAL (offset) - SPARC_STACK_BIAS) & (desired - 1)) == 0) 337752284Sobrien return 1; 337850397Sobrien } 337950397Sobrien } 338052284Sobrien else if (! TARGET_UNALIGNED_DOUBLES 338152284Sobrien || CONSTANT_P (addr) 338252284Sobrien || GET_CODE (addr) == LO_SUM) 338350397Sobrien { 338452284Sobrien /* Anything else we know is properly aligned unless TARGET_UNALIGNED_DOUBLES 338552284Sobrien is true, in which case we can only assume that an access is aligned if 338652284Sobrien it is to a constant address, or the address involves a LO_SUM. */ 338752284Sobrien return 1; 338850397Sobrien } 338950397Sobrien 339052284Sobrien /* An obviously unaligned address. */ 339152284Sobrien return 0; 339250397Sobrien} 339350397Sobrien 339450397Sobrien 339550397Sobrien/* Vectors to keep interesting information about registers where it can easily 3396117395Skan be got. We used to use the actual mode value as the bit number, but there 339750397Sobrien are more than 32 modes now. Instead we use two tables: one indexed by 339850397Sobrien hard register number, and one indexed by mode. */ 339950397Sobrien 340050397Sobrien/* The purpose of sparc_mode_class is to shrink the range of modes so that 340150397Sobrien they all fit (as bit numbers) in a 32 bit word (again). Each real mode is 340250397Sobrien mapped into one sparc_mode_class mode. */ 340350397Sobrien 340450397Sobrienenum sparc_mode_class { 340550397Sobrien S_MODE, D_MODE, T_MODE, O_MODE, 340650397Sobrien SF_MODE, DF_MODE, TF_MODE, OF_MODE, 340750397Sobrien CC_MODE, CCFP_MODE 340850397Sobrien}; 340950397Sobrien 341050397Sobrien/* Modes for single-word and smaller quantities. */ 341150397Sobrien#define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE)) 341250397Sobrien 341350397Sobrien/* Modes for double-word and smaller quantities. */ 341450397Sobrien#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE)) 341550397Sobrien 341650397Sobrien/* Modes for quad-word and smaller quantities. */ 341750397Sobrien#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE)) 341850397Sobrien 341990075Sobrien/* Modes for 8-word and smaller quantities. */ 342090075Sobrien#define O_MODES (T_MODES | (1 << (int) O_MODE) | (1 << (int) OF_MODE)) 342190075Sobrien 342250397Sobrien/* Modes for single-float quantities. We must allow any single word or 342350397Sobrien smaller quantity. This is because the fix/float conversion instructions 342450397Sobrien take integer inputs/outputs from the float registers. */ 342550397Sobrien#define SF_MODES (S_MODES) 342650397Sobrien 342750397Sobrien/* Modes for double-float and smaller quantities. */ 342850397Sobrien#define DF_MODES (S_MODES | D_MODES) 342950397Sobrien 343050397Sobrien/* Modes for double-float only quantities. */ 343190075Sobrien#define DF_MODES_NO_S ((1 << (int) D_MODE) | (1 << (int) DF_MODE)) 343250397Sobrien 343350397Sobrien/* Modes for quad-float only quantities. */ 343450397Sobrien#define TF_ONLY_MODES (1 << (int) TF_MODE) 343550397Sobrien 343650397Sobrien/* Modes for quad-float and smaller quantities. */ 343750397Sobrien#define TF_MODES (DF_MODES | TF_ONLY_MODES) 343850397Sobrien 343990075Sobrien/* Modes for quad-float and double-float quantities. */ 344090075Sobrien#define TF_MODES_NO_S (DF_MODES_NO_S | TF_ONLY_MODES) 344150397Sobrien 344290075Sobrien/* Modes for quad-float pair only quantities. */ 344390075Sobrien#define OF_ONLY_MODES (1 << (int) OF_MODE) 344490075Sobrien 344590075Sobrien/* Modes for quad-float pairs and smaller quantities. */ 344690075Sobrien#define OF_MODES (TF_MODES | OF_ONLY_MODES) 344790075Sobrien 344890075Sobrien#define OF_MODES_NO_S (TF_MODES_NO_S | OF_ONLY_MODES) 344990075Sobrien 345050397Sobrien/* Modes for condition codes. */ 345150397Sobrien#define CC_MODES (1 << (int) CC_MODE) 345250397Sobrien#define CCFP_MODES (1 << (int) CCFP_MODE) 345350397Sobrien 345450397Sobrien/* Value is 1 if register/mode pair is acceptable on sparc. 345550397Sobrien The funny mixture of D and T modes is because integer operations 345650397Sobrien do not specially operate on tetra quantities, so non-quad-aligned 345750397Sobrien registers can hold quadword quantities (except %o4 and %i4 because 345850397Sobrien they cross fixed registers). */ 345950397Sobrien 346050397Sobrien/* This points to either the 32 bit or the 64 bit version. */ 346190075Sobrienconst int *hard_regno_mode_classes; 346250397Sobrien 346390075Sobrienstatic const int hard_32bit_mode_classes[] = { 346450397Sobrien S_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, 346550397Sobrien T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES, 346650397Sobrien T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, 346750397Sobrien T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES, 346850397Sobrien 346990075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 347090075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 347190075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 347290075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES, 347350397Sobrien 347450397Sobrien /* FP regs f32 to f63. Only the even numbered registers actually exist, 347550397Sobrien and none can hold SFmode/SImode values. */ 347690075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 347790075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 347890075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 347990075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 348050397Sobrien 348150397Sobrien /* %fcc[0123] */ 348250397Sobrien CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES, 348350397Sobrien 348450397Sobrien /* %icc */ 348550397Sobrien CC_MODES 348650397Sobrien}; 348750397Sobrien 348890075Sobrienstatic const int hard_64bit_mode_classes[] = { 348950397Sobrien D_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, 349090075Sobrien O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, 349150397Sobrien T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, 349290075Sobrien O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, 349350397Sobrien 349490075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 349590075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 349690075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES, 349790075Sobrien OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES, 349850397Sobrien 349950397Sobrien /* FP regs f32 to f63. Only the even numbered registers actually exist, 350050397Sobrien and none can hold SFmode/SImode values. */ 350190075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 350290075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 350390075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 350490075Sobrien OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0, 350550397Sobrien 350650397Sobrien /* %fcc[0123] */ 350750397Sobrien CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES, 350850397Sobrien 350950397Sobrien /* %icc */ 351050397Sobrien CC_MODES 351150397Sobrien}; 351250397Sobrien 351350397Sobrienint sparc_mode_class [NUM_MACHINE_MODES]; 351450397Sobrien 351550397Sobrienenum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER]; 351650397Sobrien 351750397Sobrienstatic void 351850397Sobriensparc_init_modes () 351950397Sobrien{ 352050397Sobrien int i; 352150397Sobrien 352250397Sobrien for (i = 0; i < NUM_MACHINE_MODES; i++) 352350397Sobrien { 352450397Sobrien switch (GET_MODE_CLASS (i)) 352550397Sobrien { 352650397Sobrien case MODE_INT: 352750397Sobrien case MODE_PARTIAL_INT: 352850397Sobrien case MODE_COMPLEX_INT: 352950397Sobrien if (GET_MODE_SIZE (i) <= 4) 353050397Sobrien sparc_mode_class[i] = 1 << (int) S_MODE; 353150397Sobrien else if (GET_MODE_SIZE (i) == 8) 353250397Sobrien sparc_mode_class[i] = 1 << (int) D_MODE; 353350397Sobrien else if (GET_MODE_SIZE (i) == 16) 353450397Sobrien sparc_mode_class[i] = 1 << (int) T_MODE; 353550397Sobrien else if (GET_MODE_SIZE (i) == 32) 353650397Sobrien sparc_mode_class[i] = 1 << (int) O_MODE; 353750397Sobrien else 353850397Sobrien sparc_mode_class[i] = 0; 353950397Sobrien break; 354050397Sobrien case MODE_FLOAT: 354150397Sobrien case MODE_COMPLEX_FLOAT: 354250397Sobrien if (GET_MODE_SIZE (i) <= 4) 354350397Sobrien sparc_mode_class[i] = 1 << (int) SF_MODE; 354450397Sobrien else if (GET_MODE_SIZE (i) == 8) 354550397Sobrien sparc_mode_class[i] = 1 << (int) DF_MODE; 354650397Sobrien else if (GET_MODE_SIZE (i) == 16) 354750397Sobrien sparc_mode_class[i] = 1 << (int) TF_MODE; 354850397Sobrien else if (GET_MODE_SIZE (i) == 32) 354950397Sobrien sparc_mode_class[i] = 1 << (int) OF_MODE; 355050397Sobrien else 355150397Sobrien sparc_mode_class[i] = 0; 355250397Sobrien break; 355350397Sobrien case MODE_CC: 355450397Sobrien default: 355550397Sobrien /* mode_class hasn't been initialized yet for EXTRA_CC_MODES, so 355650397Sobrien we must explicitly check for them here. */ 355750397Sobrien if (i == (int) CCFPmode || i == (int) CCFPEmode) 355850397Sobrien sparc_mode_class[i] = 1 << (int) CCFP_MODE; 355950397Sobrien else if (i == (int) CCmode || i == (int) CC_NOOVmode 356050397Sobrien || i == (int) CCXmode || i == (int) CCX_NOOVmode) 356150397Sobrien sparc_mode_class[i] = 1 << (int) CC_MODE; 356250397Sobrien else 356350397Sobrien sparc_mode_class[i] = 0; 356450397Sobrien break; 356550397Sobrien } 356650397Sobrien } 356750397Sobrien 356850397Sobrien if (TARGET_ARCH64) 356950397Sobrien hard_regno_mode_classes = hard_64bit_mode_classes; 357050397Sobrien else 357150397Sobrien hard_regno_mode_classes = hard_32bit_mode_classes; 357250397Sobrien 357350397Sobrien /* Initialize the array used by REGNO_REG_CLASS. */ 357450397Sobrien for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 357550397Sobrien { 357650397Sobrien if (i < 16 && TARGET_V8PLUS) 357750397Sobrien sparc_regno_reg_class[i] = I64_REGS; 357896263Sobrien else if (i < 32 || i == FRAME_POINTER_REGNUM) 357950397Sobrien sparc_regno_reg_class[i] = GENERAL_REGS; 358050397Sobrien else if (i < 64) 358150397Sobrien sparc_regno_reg_class[i] = FP_REGS; 358250397Sobrien else if (i < 96) 358350397Sobrien sparc_regno_reg_class[i] = EXTRA_FP_REGS; 358450397Sobrien else if (i < 100) 358550397Sobrien sparc_regno_reg_class[i] = FPCC_REGS; 358650397Sobrien else 358750397Sobrien sparc_regno_reg_class[i] = NO_REGS; 358850397Sobrien } 358950397Sobrien} 359050397Sobrien 359150397Sobrien/* Save non call used registers from LOW to HIGH at BASE+OFFSET. 359250397Sobrien N_REGS is the number of 4-byte regs saved thus far. This applies even to 359350397Sobrien v9 int regs as it simplifies the code. */ 359450397Sobrien 359550397Sobrienstatic int 359650397Sobriensave_regs (file, low, high, base, offset, n_regs, real_offset) 359750397Sobrien FILE *file; 359850397Sobrien int low, high; 359952284Sobrien const char *base; 360050397Sobrien int offset; 360150397Sobrien int n_regs; 360250397Sobrien int real_offset; 360350397Sobrien{ 360450397Sobrien int i; 360550397Sobrien 360650397Sobrien if (TARGET_ARCH64 && high <= 32) 360750397Sobrien { 360850397Sobrien for (i = low; i < high; i++) 360950397Sobrien { 361050397Sobrien if (regs_ever_live[i] && ! call_used_regs[i]) 361150397Sobrien { 361252284Sobrien fprintf (file, "\tstx\t%s, [%s+%d]\n", 361350397Sobrien reg_names[i], base, offset + 4 * n_regs); 361450397Sobrien if (dwarf2out_do_frame ()) 361550397Sobrien dwarf2out_reg_save ("", i, real_offset + 4 * n_regs); 361650397Sobrien n_regs += 2; 361750397Sobrien } 361850397Sobrien } 361950397Sobrien } 362050397Sobrien else 362150397Sobrien { 362250397Sobrien for (i = low; i < high; i += 2) 362350397Sobrien { 362450397Sobrien if (regs_ever_live[i] && ! call_used_regs[i]) 362550397Sobrien { 362650397Sobrien if (regs_ever_live[i+1] && ! call_used_regs[i+1]) 362750397Sobrien { 362852284Sobrien fprintf (file, "\tstd\t%s, [%s+%d]\n", 362950397Sobrien reg_names[i], base, offset + 4 * n_regs); 363050397Sobrien if (dwarf2out_do_frame ()) 363150397Sobrien { 363250397Sobrien char *l = dwarf2out_cfi_label (); 363350397Sobrien dwarf2out_reg_save (l, i, real_offset + 4 * n_regs); 363450397Sobrien dwarf2out_reg_save (l, i+1, real_offset + 4 * n_regs + 4); 363550397Sobrien } 363650397Sobrien n_regs += 2; 363750397Sobrien } 363850397Sobrien else 363950397Sobrien { 364052284Sobrien fprintf (file, "\tst\t%s, [%s+%d]\n", 364150397Sobrien reg_names[i], base, offset + 4 * n_regs); 364250397Sobrien if (dwarf2out_do_frame ()) 364350397Sobrien dwarf2out_reg_save ("", i, real_offset + 4 * n_regs); 364450397Sobrien n_regs += 2; 364550397Sobrien } 364650397Sobrien } 364750397Sobrien else 364850397Sobrien { 364950397Sobrien if (regs_ever_live[i+1] && ! call_used_regs[i+1]) 365050397Sobrien { 365152284Sobrien fprintf (file, "\tst\t%s, [%s+%d]\n", 365250397Sobrien reg_names[i+1], base, offset + 4 * n_regs + 4); 365350397Sobrien if (dwarf2out_do_frame ()) 365450397Sobrien dwarf2out_reg_save ("", i + 1, real_offset + 4 * n_regs + 4); 365550397Sobrien n_regs += 2; 365650397Sobrien } 365750397Sobrien } 365850397Sobrien } 365950397Sobrien } 366050397Sobrien return n_regs; 366150397Sobrien} 366250397Sobrien 366350397Sobrien/* Restore non call used registers from LOW to HIGH at BASE+OFFSET. 366450397Sobrien 366550397Sobrien N_REGS is the number of 4-byte regs saved thus far. This applies even to 366650397Sobrien v9 int regs as it simplifies the code. */ 366750397Sobrien 366850397Sobrienstatic int 366950397Sobrienrestore_regs (file, low, high, base, offset, n_regs) 367050397Sobrien FILE *file; 367150397Sobrien int low, high; 367252284Sobrien const char *base; 367350397Sobrien int offset; 367450397Sobrien int n_regs; 367550397Sobrien{ 367650397Sobrien int i; 367750397Sobrien 367850397Sobrien if (TARGET_ARCH64 && high <= 32) 367950397Sobrien { 368050397Sobrien for (i = low; i < high; i++) 368150397Sobrien { 368250397Sobrien if (regs_ever_live[i] && ! call_used_regs[i]) 368352284Sobrien fprintf (file, "\tldx\t[%s+%d], %s\n", 368450397Sobrien base, offset + 4 * n_regs, reg_names[i]), 368550397Sobrien n_regs += 2; 368650397Sobrien } 368750397Sobrien } 368850397Sobrien else 368950397Sobrien { 369050397Sobrien for (i = low; i < high; i += 2) 369150397Sobrien { 369250397Sobrien if (regs_ever_live[i] && ! call_used_regs[i]) 369350397Sobrien if (regs_ever_live[i+1] && ! call_used_regs[i+1]) 369452284Sobrien fprintf (file, "\tldd\t[%s+%d], %s\n", 369550397Sobrien base, offset + 4 * n_regs, reg_names[i]), 369650397Sobrien n_regs += 2; 369750397Sobrien else 369890075Sobrien fprintf (file, "\tld\t[%s+%d], %s\n", 369950397Sobrien base, offset + 4 * n_regs, reg_names[i]), 370050397Sobrien n_regs += 2; 370150397Sobrien else if (regs_ever_live[i+1] && ! call_used_regs[i+1]) 370290075Sobrien fprintf (file, "\tld\t[%s+%d], %s\n", 370350397Sobrien base, offset + 4 * n_regs + 4, reg_names[i+1]), 370450397Sobrien n_regs += 2; 370550397Sobrien } 370650397Sobrien } 370750397Sobrien return n_regs; 370850397Sobrien} 370950397Sobrien 371050397Sobrien/* Compute the frame size required by the function. This function is called 371150397Sobrien during the reload pass and also by output_function_prologue(). */ 371250397Sobrien 371350397Sobrienint 371450397Sobriencompute_frame_size (size, leaf_function) 371550397Sobrien int size; 371650397Sobrien int leaf_function; 371750397Sobrien{ 371850397Sobrien int n_regs = 0, i; 371950397Sobrien int outgoing_args_size = (current_function_outgoing_args_size 372050397Sobrien + REG_PARM_STACK_SPACE (current_function_decl)); 372150397Sobrien 372296263Sobrien /* N_REGS is the number of 4-byte regs saved thus far. This applies 372396263Sobrien even to v9 int regs to be consistent with save_regs/restore_regs. */ 372496263Sobrien 372596263Sobrien if (TARGET_ARCH64) 372650397Sobrien { 372796263Sobrien for (i = 0; i < 8; i++) 372896263Sobrien if (regs_ever_live[i] && ! call_used_regs[i]) 372996263Sobrien n_regs += 2; 373096263Sobrien } 373196263Sobrien else 373296263Sobrien { 373396263Sobrien for (i = 0; i < 8; i += 2) 373450397Sobrien if ((regs_ever_live[i] && ! call_used_regs[i]) 373550397Sobrien || (regs_ever_live[i+1] && ! call_used_regs[i+1])) 373650397Sobrien n_regs += 2; 373750397Sobrien } 373850397Sobrien 373996263Sobrien for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2) 374096263Sobrien if ((regs_ever_live[i] && ! call_used_regs[i]) 374196263Sobrien || (regs_ever_live[i+1] && ! call_used_regs[i+1])) 374296263Sobrien n_regs += 2; 374396263Sobrien 374450397Sobrien /* Set up values for use in `function_epilogue'. */ 374550397Sobrien num_gfregs = n_regs; 374650397Sobrien 374750397Sobrien if (leaf_function && n_regs == 0 374850397Sobrien && size == 0 && current_function_outgoing_args_size == 0) 374950397Sobrien { 375050397Sobrien actual_fsize = apparent_fsize = 0; 375150397Sobrien } 375250397Sobrien else 375350397Sobrien { 375496263Sobrien /* We subtract STARTING_FRAME_OFFSET, remember it's negative. */ 375596263Sobrien apparent_fsize = (size - STARTING_FRAME_OFFSET + 7) & -8; 375650397Sobrien apparent_fsize += n_regs * 4; 375750397Sobrien actual_fsize = apparent_fsize + ((outgoing_args_size + 7) & -8); 375850397Sobrien } 375950397Sobrien 376050397Sobrien /* Make sure nothing can clobber our register windows. 376150397Sobrien If a SAVE must be done, or there is a stack-local variable, 376250397Sobrien the register window area must be allocated. 376350397Sobrien ??? For v8 we apparently need an additional 8 bytes of reserved space. */ 376450397Sobrien if (leaf_function == 0 || size > 0) 376550397Sobrien actual_fsize += (16 * UNITS_PER_WORD) + (TARGET_ARCH64 ? 0 : 8); 376650397Sobrien 376750397Sobrien return SPARC_STACK_ALIGN (actual_fsize); 376850397Sobrien} 376950397Sobrien 377050397Sobrien/* Build a (32 bit) big number in a register. */ 377150397Sobrien/* ??? We may be able to use the set macro here too. */ 377250397Sobrien 377350397Sobrienstatic void 377450397Sobrienbuild_big_number (file, num, reg) 377550397Sobrien FILE *file; 377650397Sobrien int num; 377752284Sobrien const char *reg; 377850397Sobrien{ 377950397Sobrien if (num >= 0 || ! TARGET_ARCH64) 378050397Sobrien { 378152284Sobrien fprintf (file, "\tsethi\t%%hi(%d), %s\n", num, reg); 378250397Sobrien if ((num & 0x3ff) != 0) 378352284Sobrien fprintf (file, "\tor\t%s, %%lo(%d), %s\n", reg, num, reg); 378450397Sobrien } 378550397Sobrien else /* num < 0 && TARGET_ARCH64 */ 378650397Sobrien { 378750397Sobrien /* Sethi does not sign extend, so we must use a little trickery 378850397Sobrien to use it for negative numbers. Invert the constant before 378950397Sobrien loading it in, then use xor immediate to invert the loaded bits 379050397Sobrien (along with the upper 32 bits) to the desired constant. This 379150397Sobrien works because the sethi and immediate fields overlap. */ 379250397Sobrien int asize = num; 379350397Sobrien int inv = ~asize; 379450397Sobrien int low = -0x400 + (asize & 0x3FF); 379550397Sobrien 379652284Sobrien fprintf (file, "\tsethi\t%%hi(%d), %s\n\txor\t%s, %d, %s\n", 379750397Sobrien inv, reg, reg, low, reg); 379850397Sobrien } 379950397Sobrien} 380050397Sobrien 380190075Sobrien/* Output any necessary .register pseudo-ops. */ 380290075Sobrienvoid 380390075Sobriensparc_output_scratch_registers (file) 380490075Sobrien FILE *file ATTRIBUTE_UNUSED; 380590075Sobrien{ 380690075Sobrien#ifdef HAVE_AS_REGISTER_PSEUDO_OP 380790075Sobrien int i; 380890075Sobrien 380990075Sobrien if (TARGET_ARCH32) 381090075Sobrien return; 381190075Sobrien 381290075Sobrien /* Check if %g[2367] were used without 381390075Sobrien .register being printed for them already. */ 381490075Sobrien for (i = 2; i < 8; i++) 381590075Sobrien { 381690075Sobrien if (regs_ever_live [i] 381790075Sobrien && ! sparc_hard_reg_printed [i]) 381890075Sobrien { 381990075Sobrien sparc_hard_reg_printed [i] = 1; 382090075Sobrien fprintf (file, "\t.register\t%%g%d, #scratch\n", i); 382190075Sobrien } 382290075Sobrien if (i == 3) i = 5; 382390075Sobrien } 382490075Sobrien#endif 382590075Sobrien} 382690075Sobrien 382790075Sobrien/* This function generates the assembly code for function entry. 382890075Sobrien FILE is a stdio stream to output the code to. 382990075Sobrien SIZE is an int: how many units of temporary storage to allocate. 383090075Sobrien Refer to the array `regs_ever_live' to determine which registers 383190075Sobrien to save; `regs_ever_live[I]' is nonzero if register number I 383290075Sobrien is ever used in the function. This macro is responsible for 383390075Sobrien knowing which registers should not be saved even if used. */ 383490075Sobrien 383590075Sobrien/* On SPARC, move-double insns between fpu and cpu need an 8-byte block 383690075Sobrien of memory. If any fpu reg is used in the function, we allocate 383790075Sobrien such a block here, at the bottom of the frame, just in case it's needed. 383890075Sobrien 383990075Sobrien If this function is a leaf procedure, then we may choose not 384090075Sobrien to do a "save" insn. The decision about whether or not 384190075Sobrien to do this is made in regclass.c. */ 384290075Sobrien 384390075Sobrienstatic void 384490075Sobriensparc_output_function_prologue (file, size) 384590075Sobrien FILE *file; 384690075Sobrien HOST_WIDE_INT size; 384790075Sobrien{ 384890075Sobrien if (TARGET_FLAT) 384990075Sobrien sparc_flat_function_prologue (file, size); 385090075Sobrien else 385190075Sobrien sparc_nonflat_function_prologue (file, size, 385290075Sobrien current_function_uses_only_leaf_regs); 385390075Sobrien} 385490075Sobrien 385550397Sobrien/* Output code for the function prologue. */ 385650397Sobrien 385790075Sobrienstatic void 385890075Sobriensparc_nonflat_function_prologue (file, size, leaf_function) 385950397Sobrien FILE *file; 386090075Sobrien HOST_WIDE_INT size; 386150397Sobrien int leaf_function; 386250397Sobrien{ 386390075Sobrien sparc_output_scratch_registers (file); 386490075Sobrien 386550397Sobrien /* Need to use actual_fsize, since we are also allocating 386650397Sobrien space for our callee (and our own register save area). */ 386750397Sobrien actual_fsize = compute_frame_size (size, leaf_function); 386850397Sobrien 386950397Sobrien if (leaf_function) 387050397Sobrien { 387150397Sobrien frame_base_name = "%sp"; 387250397Sobrien frame_base_offset = actual_fsize + SPARC_STACK_BIAS; 387350397Sobrien } 387450397Sobrien else 387550397Sobrien { 387650397Sobrien frame_base_name = "%fp"; 387750397Sobrien frame_base_offset = SPARC_STACK_BIAS; 387850397Sobrien } 387950397Sobrien 388050397Sobrien /* This is only for the human reader. */ 388150397Sobrien fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START); 388250397Sobrien 388350397Sobrien if (actual_fsize == 0) 388450397Sobrien /* do nothing. */ ; 388590075Sobrien else if (! leaf_function) 388650397Sobrien { 388750397Sobrien if (actual_fsize <= 4096) 388852284Sobrien fprintf (file, "\tsave\t%%sp, -%d, %%sp\n", actual_fsize); 388950397Sobrien else if (actual_fsize <= 8192) 389050397Sobrien { 389152284Sobrien fprintf (file, "\tsave\t%%sp, -4096, %%sp\n"); 389252284Sobrien fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize - 4096); 389350397Sobrien } 389450397Sobrien else 389550397Sobrien { 389650397Sobrien build_big_number (file, -actual_fsize, "%g1"); 389752284Sobrien fprintf (file, "\tsave\t%%sp, %%g1, %%sp\n"); 389850397Sobrien } 389950397Sobrien } 390050397Sobrien else /* leaf function */ 390150397Sobrien { 390250397Sobrien if (actual_fsize <= 4096) 390352284Sobrien fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize); 390450397Sobrien else if (actual_fsize <= 8192) 390550397Sobrien { 390652284Sobrien fprintf (file, "\tadd\t%%sp, -4096, %%sp\n"); 390752284Sobrien fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize - 4096); 390850397Sobrien } 390950397Sobrien else 391050397Sobrien { 391150397Sobrien build_big_number (file, -actual_fsize, "%g1"); 391252284Sobrien fprintf (file, "\tadd\t%%sp, %%g1, %%sp\n"); 391350397Sobrien } 391450397Sobrien } 391550397Sobrien 391650397Sobrien if (dwarf2out_do_frame () && actual_fsize) 391750397Sobrien { 391850397Sobrien char *label = dwarf2out_cfi_label (); 391950397Sobrien 392050397Sobrien /* The canonical frame address refers to the top of the frame. */ 392150397Sobrien dwarf2out_def_cfa (label, (leaf_function ? STACK_POINTER_REGNUM 392296263Sobrien : HARD_FRAME_POINTER_REGNUM), 392350397Sobrien frame_base_offset); 392450397Sobrien 392550397Sobrien if (! leaf_function) 392650397Sobrien { 392750397Sobrien /* Note the register window save. This tells the unwinder that 392850397Sobrien it needs to restore the window registers from the previous 392950397Sobrien frame's window save area at 0(cfa). */ 393050397Sobrien dwarf2out_window_save (label); 393150397Sobrien 393250397Sobrien /* The return address (-8) is now in %i7. */ 393350397Sobrien dwarf2out_return_reg (label, 31); 393450397Sobrien } 393550397Sobrien } 393650397Sobrien 393750397Sobrien /* If doing anything with PIC, do it now. */ 393850397Sobrien if (! flag_pic) 393950397Sobrien fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START); 394050397Sobrien 394150397Sobrien /* Call saved registers are saved just above the outgoing argument area. */ 394250397Sobrien if (num_gfregs) 394350397Sobrien { 394450397Sobrien int offset, real_offset, n_regs; 394552284Sobrien const char *base; 394650397Sobrien 394750397Sobrien real_offset = -apparent_fsize; 394850397Sobrien offset = -apparent_fsize + frame_base_offset; 394950397Sobrien if (offset < -4096 || offset + num_gfregs * 4 > 4096) 395050397Sobrien { 395150397Sobrien /* ??? This might be optimized a little as %g1 might already have a 395250397Sobrien value close enough that a single add insn will do. */ 395350397Sobrien /* ??? Although, all of this is probably only a temporary fix 395450397Sobrien because if %g1 can hold a function result, then 395550397Sobrien output_function_epilogue will lose (the result will get 395650397Sobrien clobbered). */ 395750397Sobrien build_big_number (file, offset, "%g1"); 395852284Sobrien fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name); 395950397Sobrien base = "%g1"; 396050397Sobrien offset = 0; 396150397Sobrien } 396250397Sobrien else 396350397Sobrien { 396450397Sobrien base = frame_base_name; 396550397Sobrien } 396650397Sobrien 396796263Sobrien n_regs = save_regs (file, 0, 8, base, offset, 0, real_offset); 396896263Sobrien save_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs, 396996263Sobrien real_offset); 397050397Sobrien } 397150397Sobrien} 397250397Sobrien 397390075Sobrien/* Output code to restore any call saved registers. */ 397490075Sobrien 397590075Sobrienstatic void 397690075Sobrienoutput_restore_regs (file, leaf_function) 397790075Sobrien FILE *file; 397896263Sobrien int leaf_function ATTRIBUTE_UNUSED; 397990075Sobrien{ 398090075Sobrien int offset, n_regs; 398190075Sobrien const char *base; 398290075Sobrien 398390075Sobrien offset = -apparent_fsize + frame_base_offset; 398490075Sobrien if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/) 398590075Sobrien { 398690075Sobrien build_big_number (file, offset, "%g1"); 398790075Sobrien fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name); 398890075Sobrien base = "%g1"; 398990075Sobrien offset = 0; 399090075Sobrien } 399190075Sobrien else 399290075Sobrien { 399390075Sobrien base = frame_base_name; 399490075Sobrien } 399590075Sobrien 399696263Sobrien n_regs = restore_regs (file, 0, 8, base, offset, 0); 399796263Sobrien restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs); 399890075Sobrien} 399990075Sobrien 400090075Sobrien/* This function generates the assembly code for function exit, 400190075Sobrien on machines that need it. 400290075Sobrien 400390075Sobrien The function epilogue should not depend on the current stack pointer! 400490075Sobrien It should use the frame pointer only. This is mandatory because 400590075Sobrien of alloca; we also take advantage of it to omit stack adjustments 400690075Sobrien before returning. */ 400790075Sobrien 400890075Sobrienstatic void 400990075Sobriensparc_output_function_epilogue (file, size) 401090075Sobrien FILE *file; 401190075Sobrien HOST_WIDE_INT size; 401290075Sobrien{ 401390075Sobrien if (TARGET_FLAT) 401490075Sobrien sparc_flat_function_epilogue (file, size); 401590075Sobrien else 401690075Sobrien sparc_nonflat_function_epilogue (file, size, 401790075Sobrien current_function_uses_only_leaf_regs); 401890075Sobrien} 401990075Sobrien 402050397Sobrien/* Output code for the function epilogue. */ 402150397Sobrien 402290075Sobrienstatic void 402390075Sobriensparc_nonflat_function_epilogue (file, size, leaf_function) 402450397Sobrien FILE *file; 402590075Sobrien HOST_WIDE_INT size ATTRIBUTE_UNUSED; 402650397Sobrien int leaf_function; 402750397Sobrien{ 402852284Sobrien const char *ret; 402950397Sobrien 403090075Sobrien if (current_function_epilogue_delay_list == 0) 403150397Sobrien { 403252284Sobrien /* If code does not drop into the epilogue, we need 403396263Sobrien do nothing except output pending case vectors. 403496263Sobrien 403596263Sobrien We have to still output a dummy nop for the sake of 403696263Sobrien sane backtraces. Otherwise, if the last two instructions 403796263Sobrien of a function were call foo; dslot; this can make the return 403896263Sobrien PC of foo (ie. address of call instruction plus 8) point to 403996263Sobrien the first instruction in the next function. */ 4040119256Skan rtx insn, last_real_insn; 404196263Sobrien 4042119256Skan insn = get_last_insn (); 404396263Sobrien 4044119256Skan last_real_insn = prev_real_insn (insn); 4045119256Skan if (last_real_insn 4046119256Skan && GET_CODE (last_real_insn) == INSN 4047119256Skan && GET_CODE (PATTERN (last_real_insn)) == SEQUENCE) 4048119256Skan last_real_insn = XVECEXP (PATTERN (last_real_insn), 0, 0); 4049119256Skan 4050119256Skan if (last_real_insn && GET_CODE (last_real_insn) == CALL_INSN) 4051119256Skan fputs("\tnop\n", file); 4052119256Skan 405396263Sobrien if (GET_CODE (insn) == NOTE) 405496263Sobrien insn = prev_nonnote_insn (insn); 405596263Sobrien if (insn && GET_CODE (insn) == BARRIER) 405696263Sobrien goto output_vectors; 405750397Sobrien } 405850397Sobrien 405950397Sobrien if (num_gfregs) 406090075Sobrien output_restore_regs (file, leaf_function); 406150397Sobrien 406250397Sobrien /* Work out how to skip the caller's unimp instruction if required. */ 406350397Sobrien if (leaf_function) 406452284Sobrien ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%o7+12" : "retl"); 406550397Sobrien else 406652284Sobrien ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%i7+12" : "ret"); 406750397Sobrien 406896263Sobrien if (! leaf_function) 406950397Sobrien { 407096263Sobrien if (current_function_calls_eh_return) 407196263Sobrien { 407296263Sobrien if (current_function_epilogue_delay_list) 407396263Sobrien abort (); 407496263Sobrien if (SKIP_CALLERS_UNIMP_P) 407596263Sobrien abort (); 407650397Sobrien 407796263Sobrien fputs ("\trestore\n\tretl\n\tadd\t%sp, %g1, %sp\n", file); 407896263Sobrien } 407996263Sobrien /* If we wound up with things in our delay slot, flush them here. */ 408096263Sobrien else if (current_function_epilogue_delay_list) 408150397Sobrien { 408296263Sobrien rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0)); 408396263Sobrien 408496263Sobrien if (TARGET_V9 && ! epilogue_renumber (&delay, 1)) 408590075Sobrien { 408696263Sobrien epilogue_renumber (&delay, 0); 408796263Sobrien fputs (SKIP_CALLERS_UNIMP_P 408896263Sobrien ? "\treturn\t%i7+12\n" 408996263Sobrien : "\treturn\t%i7+8\n", file); 409096263Sobrien final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), 409196263Sobrien file, 1, 0, 0); 409290075Sobrien } 409396263Sobrien else 409450397Sobrien { 409596263Sobrien rtx insn, src; 409690075Sobrien 409796263Sobrien if (GET_CODE (delay) != SET) 409896263Sobrien abort(); 409996263Sobrien 410096263Sobrien src = SET_SRC (delay); 410196263Sobrien if (GET_CODE (src) == ASHIFT) 410290075Sobrien { 410396263Sobrien if (XEXP (src, 1) != const1_rtx) 410496263Sobrien abort(); 410596263Sobrien SET_SRC (delay) 410696263Sobrien = gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0), 410796263Sobrien XEXP (src, 0)); 410890075Sobrien } 410990075Sobrien 411096263Sobrien insn = gen_rtx_PARALLEL (VOIDmode, 411196263Sobrien gen_rtvec (2, delay, 411296263Sobrien gen_rtx_RETURN (VOIDmode))); 411396263Sobrien insn = emit_jump_insn (insn); 411490075Sobrien 411596263Sobrien sparc_emitting_epilogue = true; 411696263Sobrien final_scan_insn (insn, file, 1, 0, 1); 411796263Sobrien sparc_emitting_epilogue = false; 411850397Sobrien } 411950397Sobrien } 412096263Sobrien else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P) 412196263Sobrien fputs ("\treturn\t%i7+8\n\tnop\n", file); 412296263Sobrien else 412396263Sobrien fprintf (file, "\t%s\n\trestore\n", ret); 412496263Sobrien } 412596263Sobrien /* All of the following cases are for leaf functions. */ 412696263Sobrien else if (current_function_calls_eh_return) 412796263Sobrien abort (); 412896263Sobrien else if (current_function_epilogue_delay_list) 412996263Sobrien { 413096263Sobrien /* eligible_for_epilogue_delay_slot ensures that if this is a 413196263Sobrien leaf function, then we will only have insn in the delay slot 413296263Sobrien if the frame size is zero, thus no adjust for the stack is 413396263Sobrien needed here. */ 413496263Sobrien if (actual_fsize != 0) 413590075Sobrien abort (); 413696263Sobrien fprintf (file, "\t%s\n", ret); 413796263Sobrien final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), 413896263Sobrien file, 1, 0, 1); 413996263Sobrien } 414096263Sobrien /* Output 'nop' instead of 'sub %sp,-0,%sp' when no frame, so as to 414150397Sobrien avoid generating confusing assembly language output. */ 414296263Sobrien else if (actual_fsize == 0) 414396263Sobrien fprintf (file, "\t%s\n\tnop\n", ret); 414496263Sobrien else if (actual_fsize <= 4096) 414596263Sobrien fprintf (file, "\t%s\n\tsub\t%%sp, -%d, %%sp\n", ret, actual_fsize); 414696263Sobrien else if (actual_fsize <= 8192) 414796263Sobrien fprintf (file, "\tsub\t%%sp, -4096, %%sp\n\t%s\n\tsub\t%%sp, -%d, %%sp\n", 414896263Sobrien ret, actual_fsize - 4096); 414996263Sobrien else if ((actual_fsize & 0x3ff) == 0) 415096263Sobrien fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n", 415196263Sobrien actual_fsize, ret); 415296263Sobrien else 415396263Sobrien fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n", 415496263Sobrien actual_fsize, actual_fsize, ret); 415552284Sobrien 415652284Sobrien output_vectors: 415752284Sobrien sparc_output_deferred_case_vectors (); 415850397Sobrien} 415990075Sobrien 416090075Sobrien/* Output a sibling call. */ 416190075Sobrien 416290075Sobrienconst char * 416390075Sobrienoutput_sibcall (insn, call_operand) 416490075Sobrien rtx insn, call_operand; 416590075Sobrien{ 416690075Sobrien int leaf_regs = current_function_uses_only_leaf_regs; 416790075Sobrien rtx operands[3]; 416890075Sobrien int delay_slot = dbr_sequence_length () > 0; 416990075Sobrien 417090075Sobrien if (num_gfregs) 417190075Sobrien { 417290075Sobrien /* Call to restore global regs might clobber 417390075Sobrien the delay slot. Instead of checking for this 417490075Sobrien output the delay slot now. */ 417590075Sobrien if (delay_slot) 417690075Sobrien { 417790075Sobrien rtx delay = NEXT_INSN (insn); 417890075Sobrien 417990075Sobrien if (! delay) 418090075Sobrien abort (); 418190075Sobrien 418290075Sobrien final_scan_insn (delay, asm_out_file, 1, 0, 1); 418390075Sobrien PATTERN (delay) = gen_blockage (); 418490075Sobrien INSN_CODE (delay) = -1; 418590075Sobrien delay_slot = 0; 418690075Sobrien } 418790075Sobrien output_restore_regs (asm_out_file, leaf_regs); 418890075Sobrien } 418990075Sobrien 419090075Sobrien operands[0] = call_operand; 419190075Sobrien 419290075Sobrien if (leaf_regs) 419390075Sobrien { 419490075Sobrien#ifdef HAVE_AS_RELAX_OPTION 419590075Sobrien /* If as and ld are relaxing tail call insns into branch always, 419690075Sobrien use or %o7,%g0,X; call Y; or X,%g0,%o7 always, so that it can 419790075Sobrien be optimized. With sethi/jmpl as nor ld has no easy way how to 419890075Sobrien find out if somebody does not branch between the sethi and jmpl. */ 419990075Sobrien int spare_slot = 0; 420090075Sobrien#else 420190075Sobrien int spare_slot = ((TARGET_ARCH32 || TARGET_CM_MEDLOW) && ! flag_pic); 420290075Sobrien#endif 420390075Sobrien int size = 0; 420490075Sobrien 420590075Sobrien if ((actual_fsize || ! spare_slot) && delay_slot) 420690075Sobrien { 420790075Sobrien rtx delay = NEXT_INSN (insn); 420890075Sobrien 420990075Sobrien if (! delay) 421090075Sobrien abort (); 421190075Sobrien 421290075Sobrien final_scan_insn (delay, asm_out_file, 1, 0, 1); 421390075Sobrien PATTERN (delay) = gen_blockage (); 421490075Sobrien INSN_CODE (delay) = -1; 421590075Sobrien delay_slot = 0; 421690075Sobrien } 421790075Sobrien if (actual_fsize) 421890075Sobrien { 421990075Sobrien if (actual_fsize <= 4096) 422090075Sobrien size = actual_fsize; 422190075Sobrien else if (actual_fsize <= 8192) 422290075Sobrien { 422390075Sobrien fputs ("\tsub\t%sp, -4096, %sp\n", asm_out_file); 422490075Sobrien size = actual_fsize - 4096; 422590075Sobrien } 422690075Sobrien else if ((actual_fsize & 0x3ff) == 0) 422790075Sobrien fprintf (asm_out_file, 422890075Sobrien "\tsethi\t%%hi(%d), %%g1\n\tadd\t%%sp, %%g1, %%sp\n", 422990075Sobrien actual_fsize); 423090075Sobrien else 423190075Sobrien { 423290075Sobrien fprintf (asm_out_file, 423390075Sobrien "\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n", 423490075Sobrien actual_fsize, actual_fsize); 423590075Sobrien fputs ("\tadd\t%%sp, %%g1, %%sp\n", asm_out_file); 423690075Sobrien } 423790075Sobrien } 423890075Sobrien if (spare_slot) 423990075Sobrien { 424090075Sobrien output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands); 424190075Sobrien output_asm_insn ("jmpl\t%%g1 + %%lo(%a0), %%g0", operands); 424290075Sobrien if (size) 424390075Sobrien fprintf (asm_out_file, "\t sub\t%%sp, -%d, %%sp\n", size); 424490075Sobrien else if (! delay_slot) 424590075Sobrien fputs ("\t nop\n", asm_out_file); 424690075Sobrien } 424790075Sobrien else 424890075Sobrien { 424990075Sobrien if (size) 425090075Sobrien fprintf (asm_out_file, "\tsub\t%%sp, -%d, %%sp\n", size); 425190075Sobrien /* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize 425290075Sobrien it into branch if possible. */ 425390075Sobrien output_asm_insn ("or\t%%o7, %%g0, %%g1", operands); 425490075Sobrien output_asm_insn ("call\t%a0, 0", operands); 425590075Sobrien output_asm_insn (" or\t%%g1, %%g0, %%o7", operands); 425690075Sobrien } 425790075Sobrien return ""; 425890075Sobrien } 425990075Sobrien 426090075Sobrien output_asm_insn ("call\t%a0, 0", operands); 426190075Sobrien if (delay_slot) 426290075Sobrien { 426390075Sobrien rtx delay = NEXT_INSN (insn), pat; 426490075Sobrien 426590075Sobrien if (! delay) 426690075Sobrien abort (); 426790075Sobrien 426890075Sobrien pat = PATTERN (delay); 426990075Sobrien if (GET_CODE (pat) != SET) 427090075Sobrien abort (); 427190075Sobrien 427290075Sobrien operands[0] = SET_DEST (pat); 427390075Sobrien pat = SET_SRC (pat); 427490075Sobrien switch (GET_CODE (pat)) 427590075Sobrien { 427690075Sobrien case PLUS: 427790075Sobrien operands[1] = XEXP (pat, 0); 427890075Sobrien operands[2] = XEXP (pat, 1); 427990075Sobrien output_asm_insn (" restore %r1, %2, %Y0", operands); 428090075Sobrien break; 428190075Sobrien case LO_SUM: 428290075Sobrien operands[1] = XEXP (pat, 0); 428390075Sobrien operands[2] = XEXP (pat, 1); 428490075Sobrien output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands); 428590075Sobrien break; 428690075Sobrien case ASHIFT: 428790075Sobrien operands[1] = XEXP (pat, 0); 428890075Sobrien output_asm_insn (" restore %r1, %r1, %Y0", operands); 428990075Sobrien break; 429090075Sobrien default: 429190075Sobrien operands[1] = pat; 429290075Sobrien output_asm_insn (" restore %%g0, %1, %Y0", operands); 429390075Sobrien break; 429490075Sobrien } 429590075Sobrien PATTERN (delay) = gen_blockage (); 429690075Sobrien INSN_CODE (delay) = -1; 429790075Sobrien } 429890075Sobrien else 429990075Sobrien fputs ("\t restore\n", asm_out_file); 430090075Sobrien return ""; 430190075Sobrien} 430250397Sobrien 430350397Sobrien/* Functions for handling argument passing. 430450397Sobrien 430550397Sobrien For v8 the first six args are normally in registers and the rest are 430650397Sobrien pushed. Any arg that starts within the first 6 words is at least 430750397Sobrien partially passed in a register unless its data type forbids. 430850397Sobrien 430950397Sobrien For v9, the argument registers are laid out as an array of 16 elements 431050397Sobrien and arguments are added sequentially. The first 6 int args and up to the 431150397Sobrien first 16 fp args (depending on size) are passed in regs. 431250397Sobrien 431350397Sobrien Slot Stack Integral Float Float in structure Double Long Double 431450397Sobrien ---- ----- -------- ----- ------------------ ------ ----------- 431550397Sobrien 15 [SP+248] %f31 %f30,%f31 %d30 431650397Sobrien 14 [SP+240] %f29 %f28,%f29 %d28 %q28 431750397Sobrien 13 [SP+232] %f27 %f26,%f27 %d26 431850397Sobrien 12 [SP+224] %f25 %f24,%f25 %d24 %q24 431950397Sobrien 11 [SP+216] %f23 %f22,%f23 %d22 432050397Sobrien 10 [SP+208] %f21 %f20,%f21 %d20 %q20 432150397Sobrien 9 [SP+200] %f19 %f18,%f19 %d18 432250397Sobrien 8 [SP+192] %f17 %f16,%f17 %d16 %q16 432350397Sobrien 7 [SP+184] %f15 %f14,%f15 %d14 432450397Sobrien 6 [SP+176] %f13 %f12,%f13 %d12 %q12 432550397Sobrien 5 [SP+168] %o5 %f11 %f10,%f11 %d10 432650397Sobrien 4 [SP+160] %o4 %f9 %f8,%f9 %d8 %q8 432750397Sobrien 3 [SP+152] %o3 %f7 %f6,%f7 %d6 432850397Sobrien 2 [SP+144] %o2 %f5 %f4,%f5 %d4 %q4 432950397Sobrien 1 [SP+136] %o1 %f3 %f2,%f3 %d2 433050397Sobrien 0 [SP+128] %o0 %f1 %f0,%f1 %d0 %q0 433150397Sobrien 433250397Sobrien Here SP = %sp if -mno-stack-bias or %sp+stack_bias otherwise. 433350397Sobrien 433450397Sobrien Integral arguments are always passed as 64 bit quantities appropriately 433550397Sobrien extended. 433650397Sobrien 433750397Sobrien Passing of floating point values is handled as follows. 433850397Sobrien If a prototype is in scope: 433950397Sobrien If the value is in a named argument (i.e. not a stdarg function or a 434050397Sobrien value not part of the `...') then the value is passed in the appropriate 434150397Sobrien fp reg. 434250397Sobrien If the value is part of the `...' and is passed in one of the first 6 434350397Sobrien slots then the value is passed in the appropriate int reg. 434450397Sobrien If the value is part of the `...' and is not passed in one of the first 6 434550397Sobrien slots then the value is passed in memory. 434650397Sobrien If a prototype is not in scope: 434750397Sobrien If the value is one of the first 6 arguments the value is passed in the 434850397Sobrien appropriate integer reg and the appropriate fp reg. 434950397Sobrien If the value is not one of the first 6 arguments the value is passed in 435050397Sobrien the appropriate fp reg and in memory. 435150397Sobrien */ 435250397Sobrien 435350397Sobrien/* Maximum number of int regs for args. */ 435450397Sobrien#define SPARC_INT_ARG_MAX 6 435550397Sobrien/* Maximum number of fp regs for args. */ 435650397Sobrien#define SPARC_FP_ARG_MAX 16 435750397Sobrien 435850397Sobrien#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) 435950397Sobrien 436050397Sobrien/* Handle the INIT_CUMULATIVE_ARGS macro. 436150397Sobrien Initialize a variable CUM of type CUMULATIVE_ARGS 436250397Sobrien for a call to a function whose data type is FNTYPE. 436350397Sobrien For a library call, FNTYPE is 0. */ 436450397Sobrien 436550397Sobrienvoid 436650397Sobrieninit_cumulative_args (cum, fntype, libname, indirect) 436750397Sobrien CUMULATIVE_ARGS *cum; 436850397Sobrien tree fntype; 436990075Sobrien rtx libname ATTRIBUTE_UNUSED; 437050397Sobrien int indirect ATTRIBUTE_UNUSED; 437150397Sobrien{ 437250397Sobrien cum->words = 0; 437350397Sobrien cum->prototype_p = fntype && TYPE_ARG_TYPES (fntype); 437450397Sobrien cum->libcall_p = fntype == 0; 437550397Sobrien} 437650397Sobrien 437750397Sobrien/* Compute the slot number to pass an argument in. 437850397Sobrien Returns the slot number or -1 if passing on the stack. 437950397Sobrien 438050397Sobrien CUM is a variable of type CUMULATIVE_ARGS which gives info about 438150397Sobrien the preceding args and about the function being called. 438250397Sobrien MODE is the argument's machine mode. 438350397Sobrien TYPE is the data type of the argument (as a tree). 438450397Sobrien This is null for libcalls where that information may 438550397Sobrien not be available. 438650397Sobrien NAMED is nonzero if this argument is a named parameter 438750397Sobrien (otherwise it is an extra parameter matching an ellipsis). 438850397Sobrien INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG. 438950397Sobrien *PREGNO records the register number to use if scalar type. 439050397Sobrien *PPADDING records the amount of padding needed in words. */ 439150397Sobrien 439250397Sobrienstatic int 439350397Sobrienfunction_arg_slotno (cum, mode, type, named, incoming_p, pregno, ppadding) 439450397Sobrien const CUMULATIVE_ARGS *cum; 439550397Sobrien enum machine_mode mode; 439650397Sobrien tree type; 439750397Sobrien int named; 439850397Sobrien int incoming_p; 439950397Sobrien int *pregno; 440050397Sobrien int *ppadding; 440150397Sobrien{ 440250397Sobrien int regbase = (incoming_p 440350397Sobrien ? SPARC_INCOMING_INT_ARG_FIRST 440450397Sobrien : SPARC_OUTGOING_INT_ARG_FIRST); 440550397Sobrien int slotno = cum->words; 440650397Sobrien int regno; 440750397Sobrien 440850397Sobrien *ppadding = 0; 440950397Sobrien 441050397Sobrien if (type != 0 && TREE_ADDRESSABLE (type)) 441150397Sobrien return -1; 441250397Sobrien if (TARGET_ARCH32 441350397Sobrien && type != 0 && mode == BLKmode 441450397Sobrien && TYPE_ALIGN (type) % PARM_BOUNDARY != 0) 441550397Sobrien return -1; 441650397Sobrien 441750397Sobrien switch (mode) 441850397Sobrien { 441950397Sobrien case VOIDmode : 442050397Sobrien /* MODE is VOIDmode when generating the actual call. 442150397Sobrien See emit_call_1. */ 442250397Sobrien return -1; 442350397Sobrien 442450397Sobrien case QImode : case CQImode : 442550397Sobrien case HImode : case CHImode : 442650397Sobrien case SImode : case CSImode : 442750397Sobrien case DImode : case CDImode : 442890075Sobrien case TImode : case CTImode : 442950397Sobrien if (slotno >= SPARC_INT_ARG_MAX) 443050397Sobrien return -1; 443150397Sobrien regno = regbase + slotno; 443250397Sobrien break; 443350397Sobrien 443450397Sobrien case SFmode : case SCmode : 443550397Sobrien case DFmode : case DCmode : 443650397Sobrien case TFmode : case TCmode : 443750397Sobrien if (TARGET_ARCH32) 443850397Sobrien { 443950397Sobrien if (slotno >= SPARC_INT_ARG_MAX) 444050397Sobrien return -1; 444150397Sobrien regno = regbase + slotno; 444250397Sobrien } 444350397Sobrien else 444450397Sobrien { 444550397Sobrien if ((mode == TFmode || mode == TCmode) 444650397Sobrien && (slotno & 1) != 0) 444750397Sobrien slotno++, *ppadding = 1; 444850397Sobrien if (TARGET_FPU && named) 444950397Sobrien { 445050397Sobrien if (slotno >= SPARC_FP_ARG_MAX) 445150397Sobrien return -1; 445250397Sobrien regno = SPARC_FP_ARG_FIRST + slotno * 2; 445350397Sobrien if (mode == SFmode) 445450397Sobrien regno++; 445550397Sobrien } 445650397Sobrien else 445750397Sobrien { 445850397Sobrien if (slotno >= SPARC_INT_ARG_MAX) 445950397Sobrien return -1; 446050397Sobrien regno = regbase + slotno; 446150397Sobrien } 446250397Sobrien } 446350397Sobrien break; 446450397Sobrien 446550397Sobrien case BLKmode : 446650397Sobrien /* For sparc64, objects requiring 16 byte alignment get it. */ 446750397Sobrien if (TARGET_ARCH64) 446850397Sobrien { 446950397Sobrien if (type && TYPE_ALIGN (type) == 128 && (slotno & 1) != 0) 447050397Sobrien slotno++, *ppadding = 1; 447150397Sobrien } 447250397Sobrien 447350397Sobrien if (TARGET_ARCH32 447450397Sobrien || (type && TREE_CODE (type) == UNION_TYPE)) 447550397Sobrien { 447650397Sobrien if (slotno >= SPARC_INT_ARG_MAX) 447750397Sobrien return -1; 447850397Sobrien regno = regbase + slotno; 447950397Sobrien } 448050397Sobrien else 448150397Sobrien { 448250397Sobrien tree field; 448350397Sobrien int intregs_p = 0, fpregs_p = 0; 448450397Sobrien /* The ABI obviously doesn't specify how packed 448550397Sobrien structures are passed. These are defined to be passed 448650397Sobrien in int regs if possible, otherwise memory. */ 448750397Sobrien int packed_p = 0; 448850397Sobrien 448950397Sobrien /* First see what kinds of registers we need. */ 449050397Sobrien for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 449150397Sobrien { 449250397Sobrien if (TREE_CODE (field) == FIELD_DECL) 449350397Sobrien { 449450397Sobrien if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE 449550397Sobrien && TARGET_FPU) 449650397Sobrien fpregs_p = 1; 449750397Sobrien else 449850397Sobrien intregs_p = 1; 449950397Sobrien if (DECL_PACKED (field)) 450050397Sobrien packed_p = 1; 450150397Sobrien } 450250397Sobrien } 450350397Sobrien if (packed_p || !named) 450450397Sobrien fpregs_p = 0, intregs_p = 1; 450550397Sobrien 450650397Sobrien /* If all arg slots are filled, then must pass on stack. */ 450750397Sobrien if (fpregs_p && slotno >= SPARC_FP_ARG_MAX) 450850397Sobrien return -1; 450950397Sobrien /* If there are only int args and all int arg slots are filled, 451050397Sobrien then must pass on stack. */ 451150397Sobrien if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX) 451250397Sobrien return -1; 451350397Sobrien /* Note that even if all int arg slots are filled, fp members may 451450397Sobrien still be passed in regs if such regs are available. 451550397Sobrien *PREGNO isn't set because there may be more than one, it's up 451650397Sobrien to the caller to compute them. */ 451750397Sobrien return slotno; 451850397Sobrien } 451950397Sobrien break; 452050397Sobrien 452150397Sobrien default : 452250397Sobrien abort (); 452350397Sobrien } 452450397Sobrien 452550397Sobrien *pregno = regno; 452650397Sobrien return slotno; 452750397Sobrien} 452850397Sobrien 452950397Sobrien/* Handle recursive register counting for structure field layout. */ 453050397Sobrien 453150397Sobrienstruct function_arg_record_value_parms 453250397Sobrien{ 4533117395Skan rtx ret; /* return expression being built. */ 4534117395Skan int slotno; /* slot number of the argument. */ 4535117395Skan int named; /* whether the argument is named. */ 4536117395Skan int regbase; /* regno of the base register. */ 4537117395Skan int stack; /* 1 if part of the argument is on the stack. */ 4538117395Skan int intoffset; /* offset of the pending integer field. */ 4539117395Skan unsigned int nregs; /* number of words passed in registers. */ 454050397Sobrien}; 454150397Sobrien 454252284Sobrienstatic void function_arg_record_value_3 454390075Sobrien PARAMS ((HOST_WIDE_INT, struct function_arg_record_value_parms *)); 454452284Sobrienstatic void function_arg_record_value_2 454590075Sobrien PARAMS ((tree, HOST_WIDE_INT, 454690075Sobrien struct function_arg_record_value_parms *)); 454790075Sobrienstatic void function_arg_record_value_1 454890075Sobrien PARAMS ((tree, HOST_WIDE_INT, 454990075Sobrien struct function_arg_record_value_parms *)); 455052284Sobrienstatic rtx function_arg_record_value 455190075Sobrien PARAMS ((tree, enum machine_mode, int, int, int)); 455252284Sobrien 455390075Sobrien/* A subroutine of function_arg_record_value. Traverse the structure 455490075Sobrien recusively and determine how many registers will be required. */ 455590075Sobrien 455650397Sobrienstatic void 455750397Sobrienfunction_arg_record_value_1 (type, startbitpos, parms) 455850397Sobrien tree type; 455990075Sobrien HOST_WIDE_INT startbitpos; 456050397Sobrien struct function_arg_record_value_parms *parms; 456150397Sobrien{ 456250397Sobrien tree field; 456350397Sobrien 456450397Sobrien /* The ABI obviously doesn't specify how packed structures are 456550397Sobrien passed. These are defined to be passed in int regs if possible, 456650397Sobrien otherwise memory. */ 456750397Sobrien int packed_p = 0; 456850397Sobrien 456950397Sobrien /* We need to compute how many registers are needed so we can 457050397Sobrien allocate the PARALLEL but before we can do that we need to know 457150397Sobrien whether there are any packed fields. If there are, int regs are 457250397Sobrien used regardless of whether there are fp values present. */ 457350397Sobrien for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 457450397Sobrien { 457550397Sobrien if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field)) 457650397Sobrien { 457750397Sobrien packed_p = 1; 457850397Sobrien break; 457950397Sobrien } 458050397Sobrien } 458150397Sobrien 458250397Sobrien /* Compute how many registers we need. */ 458350397Sobrien for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 458450397Sobrien { 458550397Sobrien if (TREE_CODE (field) == FIELD_DECL) 458650397Sobrien { 458790075Sobrien HOST_WIDE_INT bitpos = startbitpos; 458890075Sobrien 458990075Sobrien if (DECL_SIZE (field) != 0 459090075Sobrien && host_integerp (bit_position (field), 1)) 459190075Sobrien bitpos += int_bit_position (field); 459290075Sobrien 459350397Sobrien /* ??? FIXME: else assume zero offset. */ 459450397Sobrien 459550397Sobrien if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) 459690075Sobrien function_arg_record_value_1 (TREE_TYPE (field), bitpos, parms); 459796263Sobrien else if ((TREE_CODE (TREE_TYPE (field)) == REAL_TYPE 459896263Sobrien || (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE 459996263Sobrien && (TREE_CODE (TREE_TYPE (TREE_TYPE (field))) 460096263Sobrien == REAL_TYPE))) 460150397Sobrien && TARGET_FPU 460250397Sobrien && ! packed_p 460350397Sobrien && parms->named) 460450397Sobrien { 460550397Sobrien if (parms->intoffset != -1) 460650397Sobrien { 460750397Sobrien int intslots, this_slotno; 460850397Sobrien 460950397Sobrien intslots = (bitpos - parms->intoffset + BITS_PER_WORD - 1) 461050397Sobrien / BITS_PER_WORD; 461150397Sobrien this_slotno = parms->slotno + parms->intoffset 461250397Sobrien / BITS_PER_WORD; 461350397Sobrien 4614117395Skan if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno) 4615117395Skan { 4616117395Skan intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno); 4617117395Skan /* We need to pass this field on the stack. */ 4618117395Skan parms->stack = 1; 4619117395Skan } 4620117395Skan 462150397Sobrien parms->nregs += intslots; 462250397Sobrien parms->intoffset = -1; 462350397Sobrien } 462450397Sobrien 462550397Sobrien /* There's no need to check this_slotno < SPARC_FP_ARG MAX. 462650397Sobrien If it wasn't true we wouldn't be here. */ 462750397Sobrien parms->nregs += 1; 462896263Sobrien if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE) 462996263Sobrien parms->nregs += 1; 463050397Sobrien } 463150397Sobrien else 463250397Sobrien { 463350397Sobrien if (parms->intoffset == -1) 463450397Sobrien parms->intoffset = bitpos; 463550397Sobrien } 463650397Sobrien } 463750397Sobrien } 463850397Sobrien} 463950397Sobrien 464090075Sobrien/* A subroutine of function_arg_record_value. Assign the bits of the 464190075Sobrien structure between parms->intoffset and bitpos to integer registers. */ 464250397Sobrien 464350397Sobrienstatic void 464450397Sobrienfunction_arg_record_value_3 (bitpos, parms) 464590075Sobrien HOST_WIDE_INT bitpos; 464650397Sobrien struct function_arg_record_value_parms *parms; 464750397Sobrien{ 464850397Sobrien enum machine_mode mode; 464990075Sobrien unsigned int regno; 465090075Sobrien unsigned int startbit, endbit; 465190075Sobrien int this_slotno, intslots, intoffset; 465250397Sobrien rtx reg; 465350397Sobrien 465450397Sobrien if (parms->intoffset == -1) 465550397Sobrien return; 465690075Sobrien 465750397Sobrien intoffset = parms->intoffset; 465850397Sobrien parms->intoffset = -1; 465950397Sobrien 466090075Sobrien startbit = intoffset & -BITS_PER_WORD; 466190075Sobrien endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD; 466290075Sobrien intslots = (endbit - startbit) / BITS_PER_WORD; 466350397Sobrien this_slotno = parms->slotno + intoffset / BITS_PER_WORD; 466450397Sobrien 466550397Sobrien intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno); 466650397Sobrien if (intslots <= 0) 466750397Sobrien return; 466850397Sobrien 466950397Sobrien /* If this is the trailing part of a word, only load that much into 467050397Sobrien the register. Otherwise load the whole register. Note that in 467150397Sobrien the latter case we may pick up unwanted bits. It's not a problem 467250397Sobrien at the moment but may wish to revisit. */ 467350397Sobrien 467450397Sobrien if (intoffset % BITS_PER_WORD != 0) 467590075Sobrien mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD, 467690075Sobrien MODE_INT, 0); 467750397Sobrien else 467850397Sobrien mode = word_mode; 467950397Sobrien 468050397Sobrien intoffset /= BITS_PER_UNIT; 468150397Sobrien do 468250397Sobrien { 468350397Sobrien regno = parms->regbase + this_slotno; 468450397Sobrien reg = gen_rtx_REG (mode, regno); 4685117395Skan XVECEXP (parms->ret, 0, parms->stack + parms->nregs) 468650397Sobrien = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset)); 468750397Sobrien 468850397Sobrien this_slotno += 1; 468950397Sobrien intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1; 469050397Sobrien parms->nregs += 1; 469150397Sobrien intslots -= 1; 469250397Sobrien } 469350397Sobrien while (intslots > 0); 469450397Sobrien} 469550397Sobrien 469690075Sobrien/* A subroutine of function_arg_record_value. Traverse the structure 469790075Sobrien recursively and assign bits to floating point registers. Track which 469890075Sobrien bits in between need integer registers; invoke function_arg_record_value_3 469990075Sobrien to make that happen. */ 470090075Sobrien 470150397Sobrienstatic void 470250397Sobrienfunction_arg_record_value_2 (type, startbitpos, parms) 470350397Sobrien tree type; 470490075Sobrien HOST_WIDE_INT startbitpos; 470550397Sobrien struct function_arg_record_value_parms *parms; 470650397Sobrien{ 470750397Sobrien tree field; 470850397Sobrien int packed_p = 0; 470950397Sobrien 471050397Sobrien for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 471150397Sobrien { 471250397Sobrien if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field)) 471350397Sobrien { 471450397Sobrien packed_p = 1; 471550397Sobrien break; 471650397Sobrien } 471750397Sobrien } 471850397Sobrien 471950397Sobrien for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) 472050397Sobrien { 472150397Sobrien if (TREE_CODE (field) == FIELD_DECL) 472250397Sobrien { 472390075Sobrien HOST_WIDE_INT bitpos = startbitpos; 472490075Sobrien 472590075Sobrien if (DECL_SIZE (field) != 0 472690075Sobrien && host_integerp (bit_position (field), 1)) 472790075Sobrien bitpos += int_bit_position (field); 472890075Sobrien 472950397Sobrien /* ??? FIXME: else assume zero offset. */ 473050397Sobrien 473150397Sobrien if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE) 473290075Sobrien function_arg_record_value_2 (TREE_TYPE (field), bitpos, parms); 473396263Sobrien else if ((TREE_CODE (TREE_TYPE (field)) == REAL_TYPE 473496263Sobrien || (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE 473596263Sobrien && (TREE_CODE (TREE_TYPE (TREE_TYPE (field))) 473696263Sobrien == REAL_TYPE))) 473750397Sobrien && TARGET_FPU 473850397Sobrien && ! packed_p 473950397Sobrien && parms->named) 474050397Sobrien { 474150397Sobrien int this_slotno = parms->slotno + bitpos / BITS_PER_WORD; 474296263Sobrien int regno; 474396263Sobrien enum machine_mode mode = DECL_MODE (field); 474450397Sobrien rtx reg; 474550397Sobrien 474650397Sobrien function_arg_record_value_3 (bitpos, parms); 474796263Sobrien regno = SPARC_FP_ARG_FIRST + this_slotno * 2 474896263Sobrien + ((mode == SFmode || mode == SCmode) 474996263Sobrien && (bitpos & 32) != 0); 475096263Sobrien switch (mode) 475196263Sobrien { 475296263Sobrien case SCmode: mode = SFmode; break; 475396263Sobrien case DCmode: mode = DFmode; break; 475496263Sobrien case TCmode: mode = TFmode; break; 475596263Sobrien default: break; 475696263Sobrien } 475796263Sobrien reg = gen_rtx_REG (mode, regno); 4758117395Skan XVECEXP (parms->ret, 0, parms->stack + parms->nregs) 475950397Sobrien = gen_rtx_EXPR_LIST (VOIDmode, reg, 476050397Sobrien GEN_INT (bitpos / BITS_PER_UNIT)); 476150397Sobrien parms->nregs += 1; 476296263Sobrien if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE) 476396263Sobrien { 476496263Sobrien regno += GET_MODE_SIZE (mode) / 4; 476596263Sobrien reg = gen_rtx_REG (mode, regno); 4766117395Skan XVECEXP (parms->ret, 0, parms->stack + parms->nregs) 476796263Sobrien = gen_rtx_EXPR_LIST (VOIDmode, reg, 476896263Sobrien GEN_INT ((bitpos + GET_MODE_BITSIZE (mode)) 476996263Sobrien / BITS_PER_UNIT)); 477096263Sobrien parms->nregs += 1; 477196263Sobrien } 477250397Sobrien } 477350397Sobrien else 477450397Sobrien { 477550397Sobrien if (parms->intoffset == -1) 477650397Sobrien parms->intoffset = bitpos; 477750397Sobrien } 477850397Sobrien } 477950397Sobrien } 478050397Sobrien} 478150397Sobrien 478290075Sobrien/* Used by function_arg and function_value to implement the complex 4783117395Skan conventions of the 64-bit ABI for passing and returning structures. 4784117395Skan Return an expression valid as a return value for the two macros 4785117395Skan FUNCTION_ARG and FUNCTION_VALUE. 478690075Sobrien 4787117395Skan TYPE is the data type of the argument (as a tree). 4788117395Skan This is null for libcalls where that information may 4789117395Skan not be available. 4790117395Skan MODE is the argument's machine mode. 4791117395Skan SLOTNO is the index number of the argument's slot in the parameter array. 4792117395Skan NAMED is nonzero if this argument is a named parameter 4793117395Skan (otherwise it is an extra parameter matching an ellipsis). 4794117395Skan REGBASE is the regno of the base register for the parameter array. */ 4795117395Skan 479650397Sobrienstatic rtx 479750397Sobrienfunction_arg_record_value (type, mode, slotno, named, regbase) 479850397Sobrien tree type; 479950397Sobrien enum machine_mode mode; 480050397Sobrien int slotno, named, regbase; 480150397Sobrien{ 480250397Sobrien HOST_WIDE_INT typesize = int_size_in_bytes (type); 480350397Sobrien struct function_arg_record_value_parms parms; 480490075Sobrien unsigned int nregs; 480550397Sobrien 480650397Sobrien parms.ret = NULL_RTX; 480750397Sobrien parms.slotno = slotno; 480850397Sobrien parms.named = named; 480950397Sobrien parms.regbase = regbase; 4810117395Skan parms.stack = 0; 481150397Sobrien 481250397Sobrien /* Compute how many registers we need. */ 481350397Sobrien parms.nregs = 0; 481450397Sobrien parms.intoffset = 0; 481550397Sobrien function_arg_record_value_1 (type, 0, &parms); 481650397Sobrien 481750397Sobrien if (parms.intoffset != -1) 481850397Sobrien { 481990075Sobrien unsigned int startbit, endbit; 482050397Sobrien int intslots, this_slotno; 482150397Sobrien 482290075Sobrien startbit = parms.intoffset & -BITS_PER_WORD; 482390075Sobrien endbit = (typesize*BITS_PER_UNIT + BITS_PER_WORD - 1) & -BITS_PER_WORD; 482490075Sobrien intslots = (endbit - startbit) / BITS_PER_WORD; 482550397Sobrien this_slotno = slotno + parms.intoffset / BITS_PER_WORD; 482650397Sobrien 4827117395Skan if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno) 4828117395Skan { 4829117395Skan intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno); 4830117395Skan /* We need to pass this field on the stack. */ 4831117395Skan parms.stack = 1; 4832117395Skan } 483350397Sobrien 483450397Sobrien parms.nregs += intslots; 483550397Sobrien } 483650397Sobrien nregs = parms.nregs; 483750397Sobrien 483850397Sobrien /* Allocate the vector and handle some annoying special cases. */ 483950397Sobrien if (nregs == 0) 484050397Sobrien { 484150397Sobrien /* ??? Empty structure has no value? Duh? */ 484250397Sobrien if (typesize <= 0) 484350397Sobrien { 484450397Sobrien /* Though there's nothing really to store, return a word register 484550397Sobrien anyway so the rest of gcc doesn't go nuts. Returning a PARALLEL 484650397Sobrien leads to breakage due to the fact that there are zero bytes to 484750397Sobrien load. */ 484850397Sobrien return gen_rtx_REG (mode, regbase); 484950397Sobrien } 485050397Sobrien else 485150397Sobrien { 485250397Sobrien /* ??? C++ has structures with no fields, and yet a size. Give up 485350397Sobrien for now and pass everything back in integer registers. */ 485450397Sobrien nregs = (typesize + UNITS_PER_WORD - 1) / UNITS_PER_WORD; 485550397Sobrien } 485650397Sobrien if (nregs + slotno > SPARC_INT_ARG_MAX) 485750397Sobrien nregs = SPARC_INT_ARG_MAX - slotno; 485850397Sobrien } 485950397Sobrien if (nregs == 0) 486052284Sobrien abort (); 486150397Sobrien 4862117395Skan parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (parms.stack + nregs)); 486350397Sobrien 4864117395Skan /* If at least one field must be passed on the stack, generate 4865117395Skan (parallel [(expr_list (nil) ...) ...]) so that all fields will 4866117395Skan also be passed on the stack. We can't do much better because the 4867117395Skan semantics of FUNCTION_ARG_PARTIAL_NREGS doesn't handle the case 4868117395Skan of structures for which the fields passed exclusively in registers 4869117395Skan are not at the beginning of the structure. */ 4870117395Skan if (parms.stack) 4871117395Skan XVECEXP (parms.ret, 0, 0) 4872117395Skan = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx); 4873117395Skan 487450397Sobrien /* Fill in the entries. */ 487550397Sobrien parms.nregs = 0; 487650397Sobrien parms.intoffset = 0; 487750397Sobrien function_arg_record_value_2 (type, 0, &parms); 487850397Sobrien function_arg_record_value_3 (typesize * BITS_PER_UNIT, &parms); 487950397Sobrien 488050397Sobrien if (parms.nregs != nregs) 488150397Sobrien abort (); 488250397Sobrien 488350397Sobrien return parms.ret; 488450397Sobrien} 488550397Sobrien 488650397Sobrien/* Handle the FUNCTION_ARG macro. 488750397Sobrien Determine where to put an argument to a function. 488850397Sobrien Value is zero to push the argument on the stack, 488950397Sobrien or a hard register in which to store the argument. 489050397Sobrien 489150397Sobrien CUM is a variable of type CUMULATIVE_ARGS which gives info about 489250397Sobrien the preceding args and about the function being called. 489350397Sobrien MODE is the argument's machine mode. 489450397Sobrien TYPE is the data type of the argument (as a tree). 489550397Sobrien This is null for libcalls where that information may 489650397Sobrien not be available. 489750397Sobrien NAMED is nonzero if this argument is a named parameter 489850397Sobrien (otherwise it is an extra parameter matching an ellipsis). 489950397Sobrien INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG. */ 490050397Sobrien 490150397Sobrienrtx 490250397Sobrienfunction_arg (cum, mode, type, named, incoming_p) 490350397Sobrien const CUMULATIVE_ARGS *cum; 490450397Sobrien enum machine_mode mode; 490550397Sobrien tree type; 490650397Sobrien int named; 490750397Sobrien int incoming_p; 490850397Sobrien{ 490950397Sobrien int regbase = (incoming_p 491050397Sobrien ? SPARC_INCOMING_INT_ARG_FIRST 491150397Sobrien : SPARC_OUTGOING_INT_ARG_FIRST); 491250397Sobrien int slotno, regno, padding; 491350397Sobrien rtx reg; 491450397Sobrien 491550397Sobrien slotno = function_arg_slotno (cum, mode, type, named, incoming_p, 491650397Sobrien ®no, &padding); 491750397Sobrien 491850397Sobrien if (slotno == -1) 491950397Sobrien return 0; 492050397Sobrien 492150397Sobrien if (TARGET_ARCH32) 492250397Sobrien { 492350397Sobrien reg = gen_rtx_REG (mode, regno); 492450397Sobrien return reg; 492550397Sobrien } 492650397Sobrien 492750397Sobrien /* v9 fp args in reg slots beyond the int reg slots get passed in regs 492850397Sobrien but also have the slot allocated for them. 492950397Sobrien If no prototype is in scope fp values in register slots get passed 493050397Sobrien in two places, either fp regs and int regs or fp regs and memory. */ 493150397Sobrien if ((GET_MODE_CLASS (mode) == MODE_FLOAT 493250397Sobrien || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) 493350397Sobrien && SPARC_FP_REG_P (regno)) 493450397Sobrien { 493550397Sobrien reg = gen_rtx_REG (mode, regno); 493650397Sobrien if (cum->prototype_p || cum->libcall_p) 493750397Sobrien { 493850397Sobrien /* "* 2" because fp reg numbers are recorded in 4 byte 493950397Sobrien quantities. */ 494050397Sobrien#if 0 494150397Sobrien /* ??? This will cause the value to be passed in the fp reg and 494250397Sobrien in the stack. When a prototype exists we want to pass the 494350397Sobrien value in the reg but reserve space on the stack. That's an 494450397Sobrien optimization, and is deferred [for a bit]. */ 494550397Sobrien if ((regno - SPARC_FP_ARG_FIRST) >= SPARC_INT_ARG_MAX * 2) 494650397Sobrien return gen_rtx_PARALLEL (mode, 494750397Sobrien gen_rtvec (2, 494850397Sobrien gen_rtx_EXPR_LIST (VOIDmode, 494950397Sobrien NULL_RTX, const0_rtx), 495050397Sobrien gen_rtx_EXPR_LIST (VOIDmode, 495150397Sobrien reg, const0_rtx))); 495250397Sobrien else 495350397Sobrien#else 495450397Sobrien /* ??? It seems that passing back a register even when past 495550397Sobrien the area declared by REG_PARM_STACK_SPACE will allocate 495650397Sobrien space appropriately, and will not copy the data onto the 495750397Sobrien stack, exactly as we desire. 495850397Sobrien 495950397Sobrien This is due to locate_and_pad_parm being called in 496050397Sobrien expand_call whenever reg_parm_stack_space > 0, which 496150397Sobrien while benefical to our example here, would seem to be 496250397Sobrien in error from what had been intended. Ho hum... -- r~ */ 496350397Sobrien#endif 496450397Sobrien return reg; 496550397Sobrien } 496650397Sobrien else 496750397Sobrien { 496850397Sobrien rtx v0, v1; 496950397Sobrien 497050397Sobrien if ((regno - SPARC_FP_ARG_FIRST) < SPARC_INT_ARG_MAX * 2) 497150397Sobrien { 497250397Sobrien int intreg; 497350397Sobrien 497450397Sobrien /* On incoming, we don't need to know that the value 497550397Sobrien is passed in %f0 and %i0, and it confuses other parts 497650397Sobrien causing needless spillage even on the simplest cases. */ 497750397Sobrien if (incoming_p) 497850397Sobrien return reg; 497950397Sobrien 498050397Sobrien intreg = (SPARC_OUTGOING_INT_ARG_FIRST 498150397Sobrien + (regno - SPARC_FP_ARG_FIRST) / 2); 498250397Sobrien 498350397Sobrien v0 = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx); 498450397Sobrien v1 = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (mode, intreg), 498550397Sobrien const0_rtx); 498650397Sobrien return gen_rtx_PARALLEL (mode, gen_rtvec (2, v0, v1)); 498750397Sobrien } 498850397Sobrien else 498950397Sobrien { 499050397Sobrien v0 = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx); 499150397Sobrien v1 = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx); 499250397Sobrien return gen_rtx_PARALLEL (mode, gen_rtvec (2, v0, v1)); 499350397Sobrien } 499450397Sobrien } 499550397Sobrien } 499650397Sobrien else if (type && TREE_CODE (type) == RECORD_TYPE) 499750397Sobrien { 499850397Sobrien /* Structures up to 16 bytes in size are passed in arg slots on the 499950397Sobrien stack and are promoted to registers where possible. */ 500050397Sobrien 500150397Sobrien if (int_size_in_bytes (type) > 16) 500250397Sobrien abort (); /* shouldn't get here */ 500350397Sobrien 500450397Sobrien return function_arg_record_value (type, mode, slotno, named, regbase); 500550397Sobrien } 500650397Sobrien else if (type && TREE_CODE (type) == UNION_TYPE) 500750397Sobrien { 500850397Sobrien enum machine_mode mode; 500950397Sobrien int bytes = int_size_in_bytes (type); 501050397Sobrien 501150397Sobrien if (bytes > 16) 501250397Sobrien abort (); 501350397Sobrien 501450397Sobrien mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0); 501550397Sobrien reg = gen_rtx_REG (mode, regno); 501650397Sobrien } 501750397Sobrien else 501850397Sobrien { 501950397Sobrien /* Scalar or complex int. */ 502050397Sobrien reg = gen_rtx_REG (mode, regno); 502150397Sobrien } 502250397Sobrien 502350397Sobrien return reg; 502450397Sobrien} 502550397Sobrien 502650397Sobrien/* Handle the FUNCTION_ARG_PARTIAL_NREGS macro. 502750397Sobrien For an arg passed partly in registers and partly in memory, 502850397Sobrien this is the number of registers used. 502950397Sobrien For args passed entirely in registers or entirely in memory, zero. 503050397Sobrien 503150397Sobrien Any arg that starts in the first 6 regs but won't entirely fit in them 503250397Sobrien needs partial registers on v8. On v9, structures with integer 503350397Sobrien values in arg slots 5,6 will be passed in %o5 and SP+176, and complex fp 503450397Sobrien values that begin in the last fp reg [where "last fp reg" varies with the 503550397Sobrien mode] will be split between that reg and memory. */ 503650397Sobrien 503750397Sobrienint 503850397Sobrienfunction_arg_partial_nregs (cum, mode, type, named) 503950397Sobrien const CUMULATIVE_ARGS *cum; 504050397Sobrien enum machine_mode mode; 504150397Sobrien tree type; 504250397Sobrien int named; 504350397Sobrien{ 504450397Sobrien int slotno, regno, padding; 504550397Sobrien 504650397Sobrien /* We pass 0 for incoming_p here, it doesn't matter. */ 504750397Sobrien slotno = function_arg_slotno (cum, mode, type, named, 0, ®no, &padding); 504850397Sobrien 504950397Sobrien if (slotno == -1) 505050397Sobrien return 0; 505150397Sobrien 505250397Sobrien if (TARGET_ARCH32) 505350397Sobrien { 505450397Sobrien if ((slotno + (mode == BLKmode 505550397Sobrien ? ROUND_ADVANCE (int_size_in_bytes (type)) 505650397Sobrien : ROUND_ADVANCE (GET_MODE_SIZE (mode)))) 505750397Sobrien > NPARM_REGS (SImode)) 505850397Sobrien return NPARM_REGS (SImode) - slotno; 505950397Sobrien return 0; 506050397Sobrien } 506150397Sobrien else 506250397Sobrien { 506350397Sobrien if (type && AGGREGATE_TYPE_P (type)) 506450397Sobrien { 506550397Sobrien int size = int_size_in_bytes (type); 506650397Sobrien int align = TYPE_ALIGN (type); 506750397Sobrien 506850397Sobrien if (align == 16) 506950397Sobrien slotno += slotno & 1; 507050397Sobrien if (size > 8 && size <= 16 507150397Sobrien && slotno == SPARC_INT_ARG_MAX - 1) 507250397Sobrien return 1; 507350397Sobrien } 507450397Sobrien else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT 507550397Sobrien || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT 507650397Sobrien && ! TARGET_FPU)) 507750397Sobrien { 507850397Sobrien if (GET_MODE_ALIGNMENT (mode) == 128) 507950397Sobrien { 508050397Sobrien slotno += slotno & 1; 508150397Sobrien if (slotno == SPARC_INT_ARG_MAX - 2) 508250397Sobrien return 1; 508350397Sobrien } 508450397Sobrien else 508550397Sobrien { 508650397Sobrien if (slotno == SPARC_INT_ARG_MAX - 1) 508750397Sobrien return 1; 508850397Sobrien } 508950397Sobrien } 509050397Sobrien else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) 509150397Sobrien { 509250397Sobrien if (GET_MODE_ALIGNMENT (mode) == 128) 509350397Sobrien slotno += slotno & 1; 509450397Sobrien if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD) 509550397Sobrien > SPARC_FP_ARG_MAX) 509650397Sobrien return 1; 509750397Sobrien } 509850397Sobrien return 0; 509950397Sobrien } 510050397Sobrien} 510150397Sobrien 510250397Sobrien/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro. 510350397Sobrien !v9: The SPARC ABI stipulates passing struct arguments (of any size) and 510450397Sobrien quad-precision floats by invisible reference. 510550397Sobrien v9: Aggregates greater than 16 bytes are passed by reference. 510650397Sobrien For Pascal, also pass arrays by reference. */ 510750397Sobrien 510850397Sobrienint 510950397Sobrienfunction_arg_pass_by_reference (cum, mode, type, named) 511050397Sobrien const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED; 511150397Sobrien enum machine_mode mode; 511250397Sobrien tree type; 511350397Sobrien int named ATTRIBUTE_UNUSED; 511450397Sobrien{ 511550397Sobrien if (TARGET_ARCH32) 511650397Sobrien { 511750397Sobrien return ((type && AGGREGATE_TYPE_P (type)) 511850397Sobrien || mode == TFmode || mode == TCmode); 511950397Sobrien } 512050397Sobrien else 512150397Sobrien { 512250397Sobrien return ((type && TREE_CODE (type) == ARRAY_TYPE) 512390075Sobrien /* Consider complex values as aggregates, so care for TCmode. */ 512450397Sobrien || GET_MODE_SIZE (mode) > 16 512596263Sobrien || (type 512696263Sobrien && AGGREGATE_TYPE_P (type) 512796263Sobrien && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)); 512850397Sobrien } 512950397Sobrien} 513050397Sobrien 513150397Sobrien/* Handle the FUNCTION_ARG_ADVANCE macro. 513250397Sobrien Update the data in CUM to advance over an argument 513350397Sobrien of mode MODE and data type TYPE. 513450397Sobrien TYPE is null for libcalls where that information may not be available. */ 513550397Sobrien 513650397Sobrienvoid 513750397Sobrienfunction_arg_advance (cum, mode, type, named) 513850397Sobrien CUMULATIVE_ARGS *cum; 513950397Sobrien enum machine_mode mode; 514050397Sobrien tree type; 514150397Sobrien int named; 514250397Sobrien{ 514350397Sobrien int slotno, regno, padding; 514450397Sobrien 514550397Sobrien /* We pass 0 for incoming_p here, it doesn't matter. */ 514650397Sobrien slotno = function_arg_slotno (cum, mode, type, named, 0, ®no, &padding); 514750397Sobrien 514850397Sobrien /* If register required leading padding, add it. */ 514950397Sobrien if (slotno != -1) 515050397Sobrien cum->words += padding; 515150397Sobrien 515250397Sobrien if (TARGET_ARCH32) 515350397Sobrien { 515450397Sobrien cum->words += (mode != BLKmode 515550397Sobrien ? ROUND_ADVANCE (GET_MODE_SIZE (mode)) 515650397Sobrien : ROUND_ADVANCE (int_size_in_bytes (type))); 515750397Sobrien } 515850397Sobrien else 515950397Sobrien { 516050397Sobrien if (type && AGGREGATE_TYPE_P (type)) 516150397Sobrien { 516250397Sobrien int size = int_size_in_bytes (type); 516350397Sobrien 516450397Sobrien if (size <= 8) 516550397Sobrien ++cum->words; 516650397Sobrien else if (size <= 16) 516750397Sobrien cum->words += 2; 516850397Sobrien else /* passed by reference */ 516950397Sobrien ++cum->words; 517050397Sobrien } 517150397Sobrien else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT) 517250397Sobrien { 517350397Sobrien cum->words += 2; 517450397Sobrien } 517550397Sobrien else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) 517650397Sobrien { 517750397Sobrien cum->words += GET_MODE_SIZE (mode) / UNITS_PER_WORD; 517850397Sobrien } 517950397Sobrien else 518050397Sobrien { 518150397Sobrien cum->words += (mode != BLKmode 518250397Sobrien ? ROUND_ADVANCE (GET_MODE_SIZE (mode)) 518350397Sobrien : ROUND_ADVANCE (int_size_in_bytes (type))); 518450397Sobrien } 518550397Sobrien } 518650397Sobrien} 518750397Sobrien 518850397Sobrien/* Handle the FUNCTION_ARG_PADDING macro. 518950397Sobrien For the 64 bit ABI structs are always stored left shifted in their 519050397Sobrien argument slot. */ 519150397Sobrien 519250397Sobrienenum direction 519350397Sobrienfunction_arg_padding (mode, type) 519450397Sobrien enum machine_mode mode; 519550397Sobrien tree type; 519650397Sobrien{ 519750397Sobrien if (TARGET_ARCH64 && type != 0 && AGGREGATE_TYPE_P (type)) 519850397Sobrien return upward; 519950397Sobrien 520050397Sobrien /* This is the default definition. */ 520150397Sobrien return (! BYTES_BIG_ENDIAN 520250397Sobrien ? upward 520350397Sobrien : ((mode == BLKmode 520450397Sobrien ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST 520550397Sobrien && int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT)) 520650397Sobrien : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) 520750397Sobrien ? downward : upward)); 520850397Sobrien} 520950397Sobrien 521050397Sobrien/* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE macros. 521150397Sobrien For v9, function return values are subject to the same rules as arguments, 521250397Sobrien except that up to 32-bytes may be returned in registers. */ 521350397Sobrien 521450397Sobrienrtx 521550397Sobrienfunction_value (type, mode, incoming_p) 521650397Sobrien tree type; 521750397Sobrien enum machine_mode mode; 521850397Sobrien int incoming_p; 521950397Sobrien{ 522050397Sobrien int regno; 522150397Sobrien int regbase = (incoming_p 522250397Sobrien ? SPARC_OUTGOING_INT_ARG_FIRST 522350397Sobrien : SPARC_INCOMING_INT_ARG_FIRST); 522450397Sobrien 522550397Sobrien if (TARGET_ARCH64 && type) 522650397Sobrien { 522750397Sobrien if (TREE_CODE (type) == RECORD_TYPE) 522850397Sobrien { 522950397Sobrien /* Structures up to 32 bytes in size are passed in registers, 523050397Sobrien promoted to fp registers where possible. */ 523150397Sobrien 523250397Sobrien if (int_size_in_bytes (type) > 32) 523350397Sobrien abort (); /* shouldn't get here */ 523450397Sobrien 523550397Sobrien return function_arg_record_value (type, mode, 0, 1, regbase); 523650397Sobrien } 523790075Sobrien else if (AGGREGATE_TYPE_P (type)) 523850397Sobrien { 523990075Sobrien /* All other aggregate types are passed in an integer register 524090075Sobrien in a mode corresponding to the size of the type. */ 524190075Sobrien HOST_WIDE_INT bytes = int_size_in_bytes (type); 524250397Sobrien 524350397Sobrien if (bytes > 32) 524450397Sobrien abort (); 524550397Sobrien 524650397Sobrien mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0); 524750397Sobrien } 524850397Sobrien } 524952284Sobrien 525052284Sobrien if (TARGET_ARCH64 525152284Sobrien && GET_MODE_CLASS (mode) == MODE_INT 525252284Sobrien && GET_MODE_SIZE (mode) < UNITS_PER_WORD 525390075Sobrien && type && ! AGGREGATE_TYPE_P (type)) 525452284Sobrien mode = DImode; 525550397Sobrien 525650397Sobrien if (incoming_p) 525750397Sobrien regno = BASE_RETURN_VALUE_REG (mode); 525850397Sobrien else 525950397Sobrien regno = BASE_OUTGOING_VALUE_REG (mode); 526050397Sobrien 526150397Sobrien return gen_rtx_REG (mode, regno); 526250397Sobrien} 526350397Sobrien 526490075Sobrien/* Do what is necessary for `va_start'. We look at the current function 526590075Sobrien to determine if stdarg or varargs is used and return the address of 526690075Sobrien the first unnamed parameter. */ 526750397Sobrien 526850397Sobrienrtx 526990075Sobriensparc_builtin_saveregs () 527050397Sobrien{ 527150397Sobrien int first_reg = current_function_args_info.words; 527250397Sobrien rtx address; 527350397Sobrien int regno; 527450397Sobrien 527550397Sobrien for (regno = first_reg; regno < NPARM_REGS (word_mode); regno++) 527650397Sobrien emit_move_insn (gen_rtx_MEM (word_mode, 527790075Sobrien gen_rtx_PLUS (Pmode, 527890075Sobrien frame_pointer_rtx, 527996263Sobrien GEN_INT (FIRST_PARM_OFFSET (0) 528090075Sobrien + (UNITS_PER_WORD 528190075Sobrien * regno)))), 528250397Sobrien gen_rtx_REG (word_mode, 528390075Sobrien BASE_INCOMING_ARG_REG (word_mode) + regno)); 528450397Sobrien 528550397Sobrien address = gen_rtx_PLUS (Pmode, 528690075Sobrien frame_pointer_rtx, 528796263Sobrien GEN_INT (FIRST_PARM_OFFSET (0) 528890075Sobrien + UNITS_PER_WORD * first_reg)); 528950397Sobrien 529050397Sobrien return address; 529150397Sobrien} 529290075Sobrien 529390075Sobrien/* Implement `va_start' for varargs and stdarg. */ 529490075Sobrien 529590075Sobrienvoid 5296117395Skansparc_va_start (valist, nextarg) 529790075Sobrien tree valist; 529890075Sobrien rtx nextarg; 529990075Sobrien{ 530090075Sobrien nextarg = expand_builtin_saveregs (); 5301117395Skan std_expand_builtin_va_start (valist, nextarg); 530290075Sobrien} 530390075Sobrien 530490075Sobrien/* Implement `va_arg'. */ 530590075Sobrien 530690075Sobrienrtx 530790075Sobriensparc_va_arg (valist, type) 530890075Sobrien tree valist, type; 530990075Sobrien{ 531090075Sobrien HOST_WIDE_INT size, rsize, align; 531190075Sobrien tree addr, incr; 531290075Sobrien rtx addr_rtx; 531390075Sobrien int indirect = 0; 531490075Sobrien 531590075Sobrien /* Round up sizeof(type) to a word. */ 531690075Sobrien size = int_size_in_bytes (type); 531790075Sobrien rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD; 531890075Sobrien align = 0; 531990075Sobrien 532090075Sobrien if (TARGET_ARCH64) 532190075Sobrien { 532290075Sobrien if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD) 532390075Sobrien align = 2 * UNITS_PER_WORD; 532490075Sobrien 532590075Sobrien if (AGGREGATE_TYPE_P (type)) 532690075Sobrien { 532796263Sobrien if ((unsigned HOST_WIDE_INT) size > 16) 532890075Sobrien { 532990075Sobrien indirect = 1; 533090075Sobrien size = rsize = UNITS_PER_WORD; 533190075Sobrien } 533296263Sobrien /* SPARC v9 ABI states that structures up to 8 bytes in size are 533396263Sobrien given one 8 byte slot. */ 533496263Sobrien else if (size == 0) 533596263Sobrien size = rsize = UNITS_PER_WORD; 533690075Sobrien else 533790075Sobrien size = rsize; 533890075Sobrien } 533990075Sobrien } 534090075Sobrien else 534190075Sobrien { 534290075Sobrien if (AGGREGATE_TYPE_P (type) 534390075Sobrien || TYPE_MODE (type) == TFmode 534490075Sobrien || TYPE_MODE (type) == TCmode) 534590075Sobrien { 534690075Sobrien indirect = 1; 534790075Sobrien size = rsize = UNITS_PER_WORD; 534890075Sobrien } 534990075Sobrien } 535090075Sobrien 535190075Sobrien incr = valist; 535290075Sobrien if (align) 535390075Sobrien { 535490075Sobrien incr = fold (build (PLUS_EXPR, ptr_type_node, incr, 535590075Sobrien build_int_2 (align - 1, 0))); 535690075Sobrien incr = fold (build (BIT_AND_EXPR, ptr_type_node, incr, 535790075Sobrien build_int_2 (-align, -1))); 535890075Sobrien } 535990075Sobrien 536090075Sobrien addr = incr = save_expr (incr); 536190075Sobrien if (BYTES_BIG_ENDIAN && size < rsize) 536290075Sobrien { 536390075Sobrien addr = fold (build (PLUS_EXPR, ptr_type_node, incr, 536490075Sobrien build_int_2 (rsize - size, 0))); 536590075Sobrien } 536690075Sobrien incr = fold (build (PLUS_EXPR, ptr_type_node, incr, 536790075Sobrien build_int_2 (rsize, 0))); 536890075Sobrien 536990075Sobrien incr = build (MODIFY_EXPR, ptr_type_node, valist, incr); 537090075Sobrien TREE_SIDE_EFFECTS (incr) = 1; 537190075Sobrien expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL); 537290075Sobrien 537390075Sobrien addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL); 537490075Sobrien 537590075Sobrien /* If the address isn't aligned properly for the type, 537690075Sobrien we may need to copy to a temporary. 537790075Sobrien FIXME: This is inefficient. Usually we can do this 537890075Sobrien in registers. */ 537990075Sobrien if (align == 0 538090075Sobrien && TYPE_ALIGN (type) > BITS_PER_WORD 538190075Sobrien && !indirect) 538290075Sobrien { 538390075Sobrien /* FIXME: We really need to specify that the temporary is live 538490075Sobrien for the whole function because expand_builtin_va_arg wants 538590075Sobrien the alias set to be get_varargs_alias_set (), but in this 538690075Sobrien case the alias set is that for TYPE and if the memory gets 538790075Sobrien reused it will be reused with alias set TYPE. */ 538890075Sobrien rtx tmp = assign_temp (type, 0, 1, 0); 538990075Sobrien rtx dest_addr; 539090075Sobrien 539190075Sobrien addr_rtx = force_reg (Pmode, addr_rtx); 539290075Sobrien addr_rtx = gen_rtx_MEM (BLKmode, addr_rtx); 539390075Sobrien set_mem_alias_set (addr_rtx, get_varargs_alias_set ()); 539490075Sobrien set_mem_align (addr_rtx, BITS_PER_WORD); 539590075Sobrien tmp = shallow_copy_rtx (tmp); 539690075Sobrien PUT_MODE (tmp, BLKmode); 539790075Sobrien set_mem_alias_set (tmp, 0); 539890075Sobrien 5399117395Skan dest_addr = emit_block_move (tmp, addr_rtx, GEN_INT (rsize), 5400117395Skan BLOCK_OP_NORMAL); 540190075Sobrien if (dest_addr != NULL_RTX) 540290075Sobrien addr_rtx = dest_addr; 540390075Sobrien else 540490075Sobrien addr_rtx = XCEXP (tmp, 0, MEM); 540590075Sobrien } 540690075Sobrien 540790075Sobrien if (indirect) 540890075Sobrien { 540990075Sobrien addr_rtx = force_reg (Pmode, addr_rtx); 541090075Sobrien addr_rtx = gen_rtx_MEM (Pmode, addr_rtx); 541190075Sobrien set_mem_alias_set (addr_rtx, get_varargs_alias_set ()); 541290075Sobrien } 541390075Sobrien 541490075Sobrien return addr_rtx; 541590075Sobrien} 541650397Sobrien 541750397Sobrien/* Return the string to output a conditional branch to LABEL, which is 541850397Sobrien the operand number of the label. OP is the conditional expression. 541950397Sobrien XEXP (OP, 0) is assumed to be a condition code register (integer or 542050397Sobrien floating point) and its mode specifies what kind of comparison we made. 542150397Sobrien 5422117395Skan REVERSED is nonzero if we should reverse the sense of the comparison. 542350397Sobrien 5424117395Skan ANNUL is nonzero if we should generate an annulling branch. 542550397Sobrien 5426117395Skan NOOP is nonzero if we have to follow this branch by a noop. 542750397Sobrien 542850397Sobrien INSN, if set, is the insn. */ 542950397Sobrien 543050397Sobrienchar * 543196263Sobrienoutput_cbranch (op, dest, label, reversed, annul, noop, insn) 543296263Sobrien rtx op, dest; 543350397Sobrien int label; 543450397Sobrien int reversed, annul, noop; 543550397Sobrien rtx insn; 543650397Sobrien{ 543796263Sobrien static char string[50]; 543850397Sobrien enum rtx_code code = GET_CODE (op); 543950397Sobrien rtx cc_reg = XEXP (op, 0); 544050397Sobrien enum machine_mode mode = GET_MODE (cc_reg); 544196263Sobrien const char *labelno, *branch; 544296263Sobrien int spaces = 8, far; 544396263Sobrien char *p; 544450397Sobrien 544596263Sobrien /* v9 branches are limited to +-1MB. If it is too far away, 544696263Sobrien change 544796263Sobrien 544896263Sobrien bne,pt %xcc, .LC30 544996263Sobrien 545096263Sobrien to 545196263Sobrien 545296263Sobrien be,pn %xcc, .+12 545396263Sobrien nop 545496263Sobrien ba .LC30 545596263Sobrien 545696263Sobrien and 545796263Sobrien 545896263Sobrien fbne,a,pn %fcc2, .LC29 545996263Sobrien 546096263Sobrien to 546196263Sobrien 546296263Sobrien fbe,pt %fcc2, .+16 546396263Sobrien nop 546496263Sobrien ba .LC29 */ 546596263Sobrien 546696263Sobrien far = get_attr_length (insn) >= 3; 546796263Sobrien if (reversed ^ far) 546850397Sobrien { 546990075Sobrien /* Reversal of FP compares takes care -- an ordered compare 547090075Sobrien becomes an unordered compare and vice versa. */ 547150397Sobrien if (mode == CCFPmode || mode == CCFPEmode) 547290075Sobrien code = reverse_condition_maybe_unordered (code); 547350397Sobrien else 547490075Sobrien code = reverse_condition (code); 547590075Sobrien } 547650397Sobrien 547790075Sobrien /* Start by writing the branch condition. */ 547890075Sobrien if (mode == CCFPmode || mode == CCFPEmode) 547990075Sobrien { 548090075Sobrien switch (code) 548152284Sobrien { 548290075Sobrien case NE: 548390075Sobrien branch = "fbne"; 548490075Sobrien break; 548590075Sobrien case EQ: 548690075Sobrien branch = "fbe"; 548790075Sobrien break; 548890075Sobrien case GE: 548990075Sobrien branch = "fbge"; 549090075Sobrien break; 549190075Sobrien case GT: 549290075Sobrien branch = "fbg"; 549390075Sobrien break; 549490075Sobrien case LE: 549590075Sobrien branch = "fble"; 549690075Sobrien break; 549790075Sobrien case LT: 549890075Sobrien branch = "fbl"; 549990075Sobrien break; 550090075Sobrien case UNORDERED: 550190075Sobrien branch = "fbu"; 550290075Sobrien break; 550390075Sobrien case ORDERED: 550490075Sobrien branch = "fbo"; 550590075Sobrien break; 550690075Sobrien case UNGT: 550790075Sobrien branch = "fbug"; 550890075Sobrien break; 550990075Sobrien case UNLT: 551090075Sobrien branch = "fbul"; 551190075Sobrien break; 551290075Sobrien case UNEQ: 551390075Sobrien branch = "fbue"; 551490075Sobrien break; 551590075Sobrien case UNGE: 551690075Sobrien branch = "fbuge"; 551790075Sobrien break; 551890075Sobrien case UNLE: 551990075Sobrien branch = "fbule"; 552090075Sobrien break; 552190075Sobrien case LTGT: 552290075Sobrien branch = "fblg"; 552390075Sobrien break; 552450397Sobrien 552590075Sobrien default: 552690075Sobrien abort (); 552750397Sobrien } 552850397Sobrien 552990075Sobrien /* ??? !v9: FP branches cannot be preceded by another floating point 553090075Sobrien insn. Because there is currently no concept of pre-delay slots, 553190075Sobrien we can fix this only by always emitting a nop before a floating 553290075Sobrien point branch. */ 553350397Sobrien 553490075Sobrien string[0] = '\0'; 553590075Sobrien if (! TARGET_V9) 553690075Sobrien strcpy (string, "nop\n\t"); 553790075Sobrien strcat (string, branch); 553890075Sobrien } 553990075Sobrien else 554090075Sobrien { 554190075Sobrien switch (code) 554250397Sobrien { 554390075Sobrien case NE: 554490075Sobrien branch = "bne"; 554590075Sobrien break; 554690075Sobrien case EQ: 554790075Sobrien branch = "be"; 554890075Sobrien break; 554990075Sobrien case GE: 555096263Sobrien if (mode == CC_NOOVmode || mode == CCX_NOOVmode) 555190075Sobrien branch = "bpos"; 555250397Sobrien else 555390075Sobrien branch = "bge"; 555490075Sobrien break; 555590075Sobrien case GT: 555690075Sobrien branch = "bg"; 555790075Sobrien break; 555890075Sobrien case LE: 555990075Sobrien branch = "ble"; 556090075Sobrien break; 556190075Sobrien case LT: 556296263Sobrien if (mode == CC_NOOVmode || mode == CCX_NOOVmode) 556390075Sobrien branch = "bneg"; 556490075Sobrien else 556590075Sobrien branch = "bl"; 556690075Sobrien break; 556790075Sobrien case GEU: 556890075Sobrien branch = "bgeu"; 556990075Sobrien break; 557090075Sobrien case GTU: 557190075Sobrien branch = "bgu"; 557290075Sobrien break; 557390075Sobrien case LEU: 557490075Sobrien branch = "bleu"; 557590075Sobrien break; 557690075Sobrien case LTU: 557790075Sobrien branch = "blu"; 557890075Sobrien break; 557950397Sobrien 558090075Sobrien default: 558190075Sobrien abort (); 558250397Sobrien } 558390075Sobrien strcpy (string, branch); 558450397Sobrien } 558590075Sobrien spaces -= strlen (branch); 558696263Sobrien p = strchr (string, '\0'); 558750397Sobrien 558850397Sobrien /* Now add the annulling, the label, and a possible noop. */ 558996263Sobrien if (annul && ! far) 559052284Sobrien { 559196263Sobrien strcpy (p, ",a"); 559296263Sobrien p += 2; 559352284Sobrien spaces -= 2; 559452284Sobrien } 559550397Sobrien 559650397Sobrien if (! TARGET_V9) 559796263Sobrien labelno = ""; 559850397Sobrien else 559950397Sobrien { 560050397Sobrien rtx note; 560196263Sobrien int v8 = 0; 560250397Sobrien 560396263Sobrien if (! far && insn && INSN_ADDRESSES_SET_P ()) 560452284Sobrien { 560596263Sobrien int delta = (INSN_ADDRESSES (INSN_UID (dest)) 560696263Sobrien - INSN_ADDRESSES (INSN_UID (insn))); 560796263Sobrien /* Leave some instructions for "slop". */ 560896263Sobrien if (delta < -260000 || delta >= 260000) 560996263Sobrien v8 = 1; 561052284Sobrien } 561150397Sobrien 561250397Sobrien if (mode == CCFPmode || mode == CCFPEmode) 561350397Sobrien { 561496263Sobrien static char v9_fcc_labelno[] = "%%fccX, "; 561596263Sobrien /* Set the char indicating the number of the fcc reg to use. */ 561696263Sobrien v9_fcc_labelno[5] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0'; 561750397Sobrien labelno = v9_fcc_labelno; 561896263Sobrien if (v8) 561996263Sobrien { 562096263Sobrien if (REGNO (cc_reg) == SPARC_FCC_REG) 562196263Sobrien labelno = ""; 562296263Sobrien else 562396263Sobrien abort (); 562496263Sobrien } 562550397Sobrien } 562650397Sobrien else if (mode == CCXmode || mode == CCX_NOOVmode) 562796263Sobrien { 562896263Sobrien labelno = "%%xcc, "; 562996263Sobrien if (v8) 563096263Sobrien abort (); 563196263Sobrien } 563250397Sobrien else 563396263Sobrien { 563496263Sobrien labelno = "%%icc, "; 563596263Sobrien if (v8) 563696263Sobrien labelno = ""; 563796263Sobrien } 563896263Sobrien 563996263Sobrien if (*labelno && insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX))) 564096263Sobrien { 564196263Sobrien strcpy (p, 564296263Sobrien ((INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ^ far) 564396263Sobrien ? ",pt" : ",pn"); 564496263Sobrien p += 3; 564596263Sobrien spaces -= 3; 564696263Sobrien } 564750397Sobrien } 564896263Sobrien if (spaces > 0) 564996263Sobrien *p++ = '\t'; 565096263Sobrien else 565196263Sobrien *p++ = ' '; 565296263Sobrien strcpy (p, labelno); 565396263Sobrien p = strchr (p, '\0'); 565496263Sobrien if (far) 565596263Sobrien { 565696263Sobrien strcpy (p, ".+12\n\tnop\n\tb\t"); 565796263Sobrien if (annul || noop) 565896263Sobrien p[3] = '6'; 565996263Sobrien p += 13; 566096263Sobrien } 566196263Sobrien *p++ = '%'; 566296263Sobrien *p++ = 'l'; 566350397Sobrien /* Set the char indicating the number of the operand containing the 566450397Sobrien label_ref. */ 566596263Sobrien *p++ = label + '0'; 566696263Sobrien *p = '\0'; 566750397Sobrien if (noop) 566896263Sobrien strcpy (p, "\n\tnop"); 566950397Sobrien 567050397Sobrien return string; 567150397Sobrien} 567250397Sobrien 567390075Sobrien/* Emit a library call comparison between floating point X and Y. 567490075Sobrien COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). 567590075Sobrien TARGET_ARCH64 uses _Qp_* functions, which use pointers to TFmode 567690075Sobrien values as arguments instead of the TFmode registers themselves, 567790075Sobrien that's why we cannot call emit_float_lib_cmp. */ 567890075Sobrienvoid 567990075Sobriensparc_emit_float_lib_cmp (x, y, comparison) 568090075Sobrien rtx x, y; 568190075Sobrien enum rtx_code comparison; 568290075Sobrien{ 568390075Sobrien const char *qpfunc; 568490075Sobrien rtx slot0, slot1, result, tem, tem2; 568590075Sobrien enum machine_mode mode; 568690075Sobrien 568790075Sobrien switch (comparison) 568890075Sobrien { 568990075Sobrien case EQ: 569090075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_feq" : "_Q_feq"; 569190075Sobrien break; 569290075Sobrien 569390075Sobrien case NE: 569490075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_fne" : "_Q_fne"; 569590075Sobrien break; 569690075Sobrien 569790075Sobrien case GT: 569890075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_fgt" : "_Q_fgt"; 569990075Sobrien break; 570090075Sobrien 570190075Sobrien case GE: 570290075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_fge" : "_Q_fge"; 570390075Sobrien break; 570490075Sobrien 570590075Sobrien case LT: 570690075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_flt" : "_Q_flt"; 570790075Sobrien break; 570890075Sobrien 570990075Sobrien case LE: 571090075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_fle" : "_Q_fle"; 571190075Sobrien break; 571290075Sobrien 571390075Sobrien case ORDERED: 571490075Sobrien case UNORDERED: 571590075Sobrien case UNGT: 571690075Sobrien case UNLT: 571790075Sobrien case UNEQ: 571890075Sobrien case UNGE: 571990075Sobrien case UNLE: 572090075Sobrien case LTGT: 572190075Sobrien qpfunc = (TARGET_ARCH64) ? "_Qp_cmp" : "_Q_cmp"; 572290075Sobrien break; 572390075Sobrien 572490075Sobrien default: 572590075Sobrien abort(); 572690075Sobrien break; 572790075Sobrien } 572890075Sobrien 572990075Sobrien if (TARGET_ARCH64) 573090075Sobrien { 573190075Sobrien if (GET_CODE (x) != MEM) 573290075Sobrien { 573390075Sobrien slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0); 573490075Sobrien emit_insn (gen_rtx_SET (VOIDmode, slot0, x)); 573590075Sobrien } 573690075Sobrien else 573790075Sobrien slot0 = x; 573890075Sobrien 573990075Sobrien if (GET_CODE (y) != MEM) 574090075Sobrien { 574190075Sobrien slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0); 574290075Sobrien emit_insn (gen_rtx_SET (VOIDmode, slot1, y)); 574390075Sobrien } 574490075Sobrien else 574590075Sobrien slot1 = y; 574690075Sobrien 574796263Sobrien emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL, 574890075Sobrien DImode, 2, 574990075Sobrien XEXP (slot0, 0), Pmode, 575090075Sobrien XEXP (slot1, 0), Pmode); 575190075Sobrien 575290075Sobrien mode = DImode; 575390075Sobrien } 575490075Sobrien else 575590075Sobrien { 575696263Sobrien emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL, 575790075Sobrien SImode, 2, 575890075Sobrien x, TFmode, y, TFmode); 575990075Sobrien 576090075Sobrien mode = SImode; 576190075Sobrien } 576290075Sobrien 576390075Sobrien 576490075Sobrien /* Immediately move the result of the libcall into a pseudo 576590075Sobrien register so reload doesn't clobber the value if it needs 576690075Sobrien the return register for a spill reg. */ 576790075Sobrien result = gen_reg_rtx (mode); 576890075Sobrien emit_move_insn (result, hard_libcall_value (mode)); 576990075Sobrien 577090075Sobrien switch (comparison) 577190075Sobrien { 577290075Sobrien default: 577390075Sobrien emit_cmp_insn (result, const0_rtx, NE, NULL_RTX, mode, 0); 577490075Sobrien break; 577590075Sobrien case ORDERED: 577690075Sobrien case UNORDERED: 577790075Sobrien emit_cmp_insn (result, GEN_INT(3), comparison == UNORDERED ? EQ : NE, 577890075Sobrien NULL_RTX, mode, 0); 577990075Sobrien break; 578090075Sobrien case UNGT: 578190075Sobrien case UNGE: 578290075Sobrien emit_cmp_insn (result, const1_rtx, 578390075Sobrien comparison == UNGT ? GT : NE, NULL_RTX, mode, 0); 578490075Sobrien break; 578590075Sobrien case UNLE: 578690075Sobrien emit_cmp_insn (result, const2_rtx, NE, NULL_RTX, mode, 0); 578790075Sobrien break; 578890075Sobrien case UNLT: 578990075Sobrien tem = gen_reg_rtx (mode); 579090075Sobrien if (TARGET_ARCH32) 579190075Sobrien emit_insn (gen_andsi3 (tem, result, const1_rtx)); 579290075Sobrien else 579390075Sobrien emit_insn (gen_anddi3 (tem, result, const1_rtx)); 579490075Sobrien emit_cmp_insn (tem, const0_rtx, NE, NULL_RTX, mode, 0); 579590075Sobrien break; 579690075Sobrien case UNEQ: 579790075Sobrien case LTGT: 579890075Sobrien tem = gen_reg_rtx (mode); 579990075Sobrien if (TARGET_ARCH32) 580090075Sobrien emit_insn (gen_addsi3 (tem, result, const1_rtx)); 580190075Sobrien else 580290075Sobrien emit_insn (gen_adddi3 (tem, result, const1_rtx)); 580390075Sobrien tem2 = gen_reg_rtx (mode); 580490075Sobrien if (TARGET_ARCH32) 580590075Sobrien emit_insn (gen_andsi3 (tem2, tem, const2_rtx)); 580690075Sobrien else 580790075Sobrien emit_insn (gen_anddi3 (tem2, tem, const2_rtx)); 580890075Sobrien emit_cmp_insn (tem2, const0_rtx, comparison == UNEQ ? EQ : NE, 580990075Sobrien NULL_RTX, mode, 0); 581090075Sobrien break; 581190075Sobrien } 581290075Sobrien} 581390075Sobrien 581496263Sobrien/* Generate an unsigned DImode to FP conversion. This is the same code 581596263Sobrien optabs would emit if we didn't have TFmode patterns. */ 581696263Sobrien 581796263Sobrienvoid 581896263Sobriensparc_emit_floatunsdi (operands) 581996263Sobrien rtx operands[2]; 582096263Sobrien{ 582196263Sobrien rtx neglab, donelab, i0, i1, f0, in, out; 582296263Sobrien enum machine_mode mode; 582396263Sobrien 582496263Sobrien out = operands[0]; 582596263Sobrien in = force_reg (DImode, operands[1]); 582696263Sobrien mode = GET_MODE (out); 582796263Sobrien neglab = gen_label_rtx (); 582896263Sobrien donelab = gen_label_rtx (); 582996263Sobrien i0 = gen_reg_rtx (DImode); 583096263Sobrien i1 = gen_reg_rtx (DImode); 583196263Sobrien f0 = gen_reg_rtx (mode); 583296263Sobrien 583396263Sobrien emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab); 583496263Sobrien 583596263Sobrien emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in))); 583696263Sobrien emit_jump_insn (gen_jump (donelab)); 583796263Sobrien emit_barrier (); 583896263Sobrien 583996263Sobrien emit_label (neglab); 584096263Sobrien 584196263Sobrien emit_insn (gen_lshrdi3 (i0, in, const1_rtx)); 584296263Sobrien emit_insn (gen_anddi3 (i1, in, const1_rtx)); 584396263Sobrien emit_insn (gen_iordi3 (i0, i0, i1)); 584496263Sobrien emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0))); 584596263Sobrien emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0))); 584696263Sobrien 584796263Sobrien emit_label (donelab); 584896263Sobrien} 584996263Sobrien 585050397Sobrien/* Return the string to output a conditional branch to LABEL, testing 585150397Sobrien register REG. LABEL is the operand number of the label; REG is the 585250397Sobrien operand number of the reg. OP is the conditional expression. The mode 585350397Sobrien of REG says what kind of comparison we made. 585450397Sobrien 5855117395Skan REVERSED is nonzero if we should reverse the sense of the comparison. 585650397Sobrien 5857117395Skan ANNUL is nonzero if we should generate an annulling branch. 585850397Sobrien 5859117395Skan NOOP is nonzero if we have to follow this branch by a noop. */ 586050397Sobrien 586150397Sobrienchar * 586296263Sobrienoutput_v9branch (op, dest, reg, label, reversed, annul, noop, insn) 586396263Sobrien rtx op, dest; 586450397Sobrien int reg, label; 586550397Sobrien int reversed, annul, noop; 586652284Sobrien rtx insn; 586750397Sobrien{ 586896263Sobrien static char string[50]; 586950397Sobrien enum rtx_code code = GET_CODE (op); 587050397Sobrien enum machine_mode mode = GET_MODE (XEXP (op, 0)); 587152284Sobrien rtx note; 587296263Sobrien int far; 587396263Sobrien char *p; 587450397Sobrien 587596263Sobrien /* branch on register are limited to +-128KB. If it is too far away, 587696263Sobrien change 587796263Sobrien 587896263Sobrien brnz,pt %g1, .LC30 587996263Sobrien 588096263Sobrien to 588196263Sobrien 588296263Sobrien brz,pn %g1, .+12 588396263Sobrien nop 588496263Sobrien ba,pt %xcc, .LC30 588596263Sobrien 588696263Sobrien and 588796263Sobrien 588896263Sobrien brgez,a,pn %o1, .LC29 588996263Sobrien 589096263Sobrien to 589196263Sobrien 589296263Sobrien brlz,pt %o1, .+16 589396263Sobrien nop 589496263Sobrien ba,pt %xcc, .LC29 */ 589596263Sobrien 589696263Sobrien far = get_attr_length (insn) >= 3; 589796263Sobrien 589850397Sobrien /* If not floating-point or if EQ or NE, we can just reverse the code. */ 589996263Sobrien if (reversed ^ far) 590096263Sobrien code = reverse_condition (code); 590150397Sobrien 590250397Sobrien /* Only 64 bit versions of these instructions exist. */ 590350397Sobrien if (mode != DImode) 590450397Sobrien abort (); 590550397Sobrien 590650397Sobrien /* Start by writing the branch condition. */ 590750397Sobrien 590850397Sobrien switch (code) 590950397Sobrien { 591050397Sobrien case NE: 591150397Sobrien strcpy (string, "brnz"); 591250397Sobrien break; 591350397Sobrien 591450397Sobrien case EQ: 591550397Sobrien strcpy (string, "brz"); 591650397Sobrien break; 591750397Sobrien 591850397Sobrien case GE: 591950397Sobrien strcpy (string, "brgez"); 592050397Sobrien break; 592150397Sobrien 592250397Sobrien case LT: 592350397Sobrien strcpy (string, "brlz"); 592450397Sobrien break; 592550397Sobrien 592650397Sobrien case LE: 592750397Sobrien strcpy (string, "brlez"); 592850397Sobrien break; 592950397Sobrien 593050397Sobrien case GT: 593150397Sobrien strcpy (string, "brgz"); 593250397Sobrien break; 593350397Sobrien 593450397Sobrien default: 593550397Sobrien abort (); 593650397Sobrien } 593750397Sobrien 593896263Sobrien p = strchr (string, '\0'); 593996263Sobrien 594050397Sobrien /* Now add the annulling, reg, label, and nop. */ 594196263Sobrien if (annul && ! far) 594252284Sobrien { 594396263Sobrien strcpy (p, ",a"); 594496263Sobrien p += 2; 594552284Sobrien } 594650397Sobrien 594796263Sobrien if (insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX))) 594852284Sobrien { 594996263Sobrien strcpy (p, 595096263Sobrien ((INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ^ far) 595196263Sobrien ? ",pt" : ",pn"); 595296263Sobrien p += 3; 595352284Sobrien } 595450397Sobrien 595596263Sobrien *p = p < string + 8 ? '\t' : ' '; 595696263Sobrien p++; 595796263Sobrien *p++ = '%'; 595896263Sobrien *p++ = '0' + reg; 595996263Sobrien *p++ = ','; 596096263Sobrien *p++ = ' '; 596196263Sobrien if (far) 596296263Sobrien { 596396263Sobrien int veryfar = 1, delta; 596450397Sobrien 596596263Sobrien if (INSN_ADDRESSES_SET_P ()) 596696263Sobrien { 596796263Sobrien delta = (INSN_ADDRESSES (INSN_UID (dest)) 596896263Sobrien - INSN_ADDRESSES (INSN_UID (insn))); 596996263Sobrien /* Leave some instructions for "slop". */ 597096263Sobrien if (delta >= -260000 && delta < 260000) 597196263Sobrien veryfar = 0; 597296263Sobrien } 597396263Sobrien 597496263Sobrien strcpy (p, ".+12\n\tnop\n\t"); 597596263Sobrien if (annul || noop) 597696263Sobrien p[3] = '6'; 597796263Sobrien p += 11; 597896263Sobrien if (veryfar) 597996263Sobrien { 598096263Sobrien strcpy (p, "b\t"); 598196263Sobrien p += 2; 598296263Sobrien } 598396263Sobrien else 598496263Sobrien { 598596263Sobrien strcpy (p, "ba,pt\t%%xcc, "); 598696263Sobrien p += 13; 598796263Sobrien } 598896263Sobrien } 598996263Sobrien *p++ = '%'; 599096263Sobrien *p++ = 'l'; 599196263Sobrien *p++ = '0' + label; 599296263Sobrien *p = '\0'; 599396263Sobrien 599450397Sobrien if (noop) 599596263Sobrien strcpy (p, "\n\tnop"); 599650397Sobrien 599750397Sobrien return string; 599850397Sobrien} 599950397Sobrien 600090075Sobrien/* Return 1, if any of the registers of the instruction are %l[0-7] or %o[0-7]. 600190075Sobrien Such instructions cannot be used in the delay slot of return insn on v9. 600290075Sobrien If TEST is 0, also rename all %i[0-7] registers to their %o[0-7] counterparts. 600390075Sobrien */ 600450397Sobrien 600590075Sobrienstatic int 600690075Sobrienepilogue_renumber (where, test) 600790075Sobrien register rtx *where; 600890075Sobrien int test; 600950397Sobrien{ 601090075Sobrien register const char *fmt; 601190075Sobrien register int i; 601290075Sobrien register enum rtx_code code; 601350397Sobrien 601490075Sobrien if (*where == 0) 601590075Sobrien return 0; 601690075Sobrien 601790075Sobrien code = GET_CODE (*where); 601890075Sobrien 601950397Sobrien switch (code) 602050397Sobrien { 602150397Sobrien case REG: 602290075Sobrien if (REGNO (*where) >= 8 && REGNO (*where) < 24) /* oX or lX */ 602390075Sobrien return 1; 602490075Sobrien if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32) 602590075Sobrien *where = gen_rtx (REG, GET_MODE (*where), OUTGOING_REGNO (REGNO(*where))); 602690075Sobrien case SCRATCH: 602790075Sobrien case CC0: 602890075Sobrien case PC: 602950397Sobrien case CONST_INT: 603050397Sobrien case CONST_DOUBLE: 603190075Sobrien return 0; 603250397Sobrien 603390075Sobrien /* Do not replace the frame pointer with the stack pointer because 603490075Sobrien it can cause the delayed instruction to load below the stack. 603590075Sobrien This occurs when instructions like: 603690075Sobrien 603790075Sobrien (set (reg/i:SI 24 %i0) 603890075Sobrien (mem/f:SI (plus:SI (reg/f:SI 30 %fp) 603990075Sobrien (const_int -20 [0xffffffec])) 0)) 604090075Sobrien 604190075Sobrien are in the return delayed slot. */ 604250397Sobrien case PLUS: 604390075Sobrien if (GET_CODE (XEXP (*where, 0)) == REG 604496263Sobrien && REGNO (XEXP (*where, 0)) == HARD_FRAME_POINTER_REGNUM 604590075Sobrien && (GET_CODE (XEXP (*where, 1)) != CONST_INT 604690075Sobrien || INTVAL (XEXP (*where, 1)) < SPARC_STACK_BIAS)) 604790075Sobrien return 1; 604890075Sobrien break; 604950397Sobrien 605090075Sobrien case MEM: 605190075Sobrien if (SPARC_STACK_BIAS 605290075Sobrien && GET_CODE (XEXP (*where, 0)) == REG 605396263Sobrien && REGNO (XEXP (*where, 0)) == HARD_FRAME_POINTER_REGNUM) 605490075Sobrien return 1; 605590075Sobrien break; 605690075Sobrien 605750397Sobrien default: 605890075Sobrien break; 605950397Sobrien } 606090075Sobrien 606190075Sobrien fmt = GET_RTX_FORMAT (code); 606290075Sobrien 606390075Sobrien for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) 606490075Sobrien { 606590075Sobrien if (fmt[i] == 'E') 606690075Sobrien { 606790075Sobrien register int j; 606890075Sobrien for (j = XVECLEN (*where, i) - 1; j >= 0; j--) 606990075Sobrien if (epilogue_renumber (&(XVECEXP (*where, i, j)), test)) 607090075Sobrien return 1; 607190075Sobrien } 607290075Sobrien else if (fmt[i] == 'e' 607390075Sobrien && epilogue_renumber (&(XEXP (*where, i)), test)) 607490075Sobrien return 1; 607590075Sobrien } 607690075Sobrien return 0; 607750397Sobrien} 607850397Sobrien 607950397Sobrien/* Leaf functions and non-leaf functions have different needs. */ 608050397Sobrien 608190075Sobrienstatic const int 608250397Sobrienreg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER; 608350397Sobrien 608490075Sobrienstatic const int 608550397Sobrienreg_nonleaf_alloc_order[] = REG_ALLOC_ORDER; 608650397Sobrien 608790075Sobrienstatic const int *const reg_alloc_orders[] = { 608850397Sobrien reg_leaf_alloc_order, 608950397Sobrien reg_nonleaf_alloc_order}; 609050397Sobrien 609150397Sobrienvoid 609250397Sobrienorder_regs_for_local_alloc () 609350397Sobrien{ 609450397Sobrien static int last_order_nonleaf = 1; 609550397Sobrien 609650397Sobrien if (regs_ever_live[15] != last_order_nonleaf) 609750397Sobrien { 609850397Sobrien last_order_nonleaf = !last_order_nonleaf; 609990075Sobrien memcpy ((char *) reg_alloc_order, 610090075Sobrien (const char *) reg_alloc_orders[last_order_nonleaf], 610190075Sobrien FIRST_PSEUDO_REGISTER * sizeof (int)); 610250397Sobrien } 610350397Sobrien} 610450397Sobrien 610552284Sobrien/* Return 1 if REG and MEM are legitimate enough to allow the various 610652284Sobrien mem<-->reg splits to be run. */ 610752284Sobrien 610852284Sobrienint 610952284Sobriensparc_splitdi_legitimate (reg, mem) 611052284Sobrien rtx reg; 611152284Sobrien rtx mem; 611252284Sobrien{ 611352284Sobrien /* Punt if we are here by mistake. */ 611452284Sobrien if (! reload_completed) 611552284Sobrien abort (); 611652284Sobrien 611752284Sobrien /* We must have an offsettable memory reference. */ 611852284Sobrien if (! offsettable_memref_p (mem)) 611952284Sobrien return 0; 612052284Sobrien 612152284Sobrien /* If we have legitimate args for ldd/std, we do not want 612252284Sobrien the split to happen. */ 612352284Sobrien if ((REGNO (reg) % 2) == 0 612452284Sobrien && mem_min_alignment (mem, 8)) 612552284Sobrien return 0; 612652284Sobrien 612752284Sobrien /* Success. */ 612852284Sobrien return 1; 612952284Sobrien} 613052284Sobrien 613152284Sobrien/* Return 1 if x and y are some kind of REG and they refer to 613252284Sobrien different hard registers. This test is guarenteed to be 613352284Sobrien run after reload. */ 613452284Sobrien 613552284Sobrienint 613652284Sobriensparc_absnegfloat_split_legitimate (x, y) 613752284Sobrien rtx x, y; 613852284Sobrien{ 613952284Sobrien if (GET_CODE (x) != REG) 614052284Sobrien return 0; 614152284Sobrien if (GET_CODE (y) != REG) 614252284Sobrien return 0; 614352284Sobrien if (REGNO (x) == REGNO (y)) 614452284Sobrien return 0; 614552284Sobrien return 1; 614652284Sobrien} 614752284Sobrien 614850397Sobrien/* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1. 614950397Sobrien This makes them candidates for using ldd and std insns. 615050397Sobrien 615150397Sobrien Note reg1 and reg2 *must* be hard registers. */ 615250397Sobrien 615350397Sobrienint 615450397Sobrienregisters_ok_for_ldd_peep (reg1, reg2) 615550397Sobrien rtx reg1, reg2; 615650397Sobrien{ 615750397Sobrien /* We might have been passed a SUBREG. */ 615850397Sobrien if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG) 615950397Sobrien return 0; 616050397Sobrien 616150397Sobrien if (REGNO (reg1) % 2 != 0) 616250397Sobrien return 0; 616350397Sobrien 616450397Sobrien /* Integer ldd is deprecated in SPARC V9 */ 616550397Sobrien if (TARGET_V9 && REGNO (reg1) < 32) 616650397Sobrien return 0; 616750397Sobrien 616850397Sobrien return (REGNO (reg1) == REGNO (reg2) - 1); 616950397Sobrien} 617050397Sobrien 617190075Sobrien/* Return 1 if the addresses in mem1 and mem2 are suitable for use in 617290075Sobrien an ldd or std insn. 617390075Sobrien 617490075Sobrien This can only happen when addr1 and addr2, the addresses in mem1 617590075Sobrien and mem2, are consecutive memory locations (addr1 + 4 == addr2). 617690075Sobrien addr1 must also be aligned on a 64-bit boundary. 617750397Sobrien 617890075Sobrien Also iff dependent_reg_rtx is not null it should not be used to 617990075Sobrien compute the address for mem1, i.e. we cannot optimize a sequence 618090075Sobrien like: 618190075Sobrien ld [%o0], %o0 618290075Sobrien ld [%o0 + 4], %o1 618390075Sobrien to 618490075Sobrien ldd [%o0], %o0 618596263Sobrien nor: 618696263Sobrien ld [%g3 + 4], %g3 618796263Sobrien ld [%g3], %g2 618896263Sobrien to 618996263Sobrien ldd [%g3], %g2 619096263Sobrien 619196263Sobrien But, note that the transformation from: 619296263Sobrien ld [%g2 + 4], %g3 619396263Sobrien ld [%g2], %g2 619496263Sobrien to 619596263Sobrien ldd [%g2], %g2 619696263Sobrien is perfectly fine. Thus, the peephole2 patterns always pass us 619796263Sobrien the destination register of the first load, never the second one. 619896263Sobrien 619990075Sobrien For stores we don't have a similar problem, so dependent_reg_rtx is 620090075Sobrien NULL_RTX. */ 620150397Sobrien 620250397Sobrienint 620390075Sobrienmems_ok_for_ldd_peep (mem1, mem2, dependent_reg_rtx) 620490075Sobrien rtx mem1, mem2, dependent_reg_rtx; 620550397Sobrien{ 620690075Sobrien rtx addr1, addr2; 620790075Sobrien unsigned int reg1; 620890075Sobrien int offset1; 620950397Sobrien 621090075Sobrien /* The mems cannot be volatile. */ 621190075Sobrien if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2)) 621290075Sobrien return 0; 621390075Sobrien 621490075Sobrien /* MEM1 should be aligned on a 64-bit boundary. */ 621590075Sobrien if (MEM_ALIGN (mem1) < 64) 621690075Sobrien return 0; 621790075Sobrien 621890075Sobrien addr1 = XEXP (mem1, 0); 621990075Sobrien addr2 = XEXP (mem2, 0); 622090075Sobrien 622150397Sobrien /* Extract a register number and offset (if used) from the first addr. */ 622250397Sobrien if (GET_CODE (addr1) == PLUS) 622350397Sobrien { 622450397Sobrien /* If not a REG, return zero. */ 622550397Sobrien if (GET_CODE (XEXP (addr1, 0)) != REG) 622650397Sobrien return 0; 622750397Sobrien else 622850397Sobrien { 622950397Sobrien reg1 = REGNO (XEXP (addr1, 0)); 623050397Sobrien /* The offset must be constant! */ 623150397Sobrien if (GET_CODE (XEXP (addr1, 1)) != CONST_INT) 623250397Sobrien return 0; 623350397Sobrien offset1 = INTVAL (XEXP (addr1, 1)); 623450397Sobrien } 623550397Sobrien } 623650397Sobrien else if (GET_CODE (addr1) != REG) 623750397Sobrien return 0; 623850397Sobrien else 623950397Sobrien { 624050397Sobrien reg1 = REGNO (addr1); 624150397Sobrien /* This was a simple (mem (reg)) expression. Offset is 0. */ 624250397Sobrien offset1 = 0; 624350397Sobrien } 624450397Sobrien 624550397Sobrien /* Make sure the second address is a (mem (plus (reg) (const_int). */ 624650397Sobrien if (GET_CODE (addr2) != PLUS) 624750397Sobrien return 0; 624850397Sobrien 624950397Sobrien if (GET_CODE (XEXP (addr2, 0)) != REG 625050397Sobrien || GET_CODE (XEXP (addr2, 1)) != CONST_INT) 625150397Sobrien return 0; 625250397Sobrien 625390075Sobrien if (reg1 != REGNO (XEXP (addr2, 0))) 625450397Sobrien return 0; 625550397Sobrien 625690075Sobrien if (dependent_reg_rtx != NULL_RTX && reg1 == REGNO (dependent_reg_rtx)) 625750397Sobrien return 0; 625890075Sobrien 625950397Sobrien /* The first offset must be evenly divisible by 8 to ensure the 626050397Sobrien address is 64 bit aligned. */ 626150397Sobrien if (offset1 % 8 != 0) 626250397Sobrien return 0; 626350397Sobrien 626450397Sobrien /* The offset for the second addr must be 4 more than the first addr. */ 626550397Sobrien if (INTVAL (XEXP (addr2, 1)) != offset1 + 4) 626650397Sobrien return 0; 626750397Sobrien 626850397Sobrien /* All the tests passed. addr1 and addr2 are valid for ldd and std 626950397Sobrien instructions. */ 627050397Sobrien return 1; 627150397Sobrien} 627250397Sobrien 627350397Sobrien/* Return 1 if reg is a pseudo, or is the first register in 627450397Sobrien a hard register pair. This makes it a candidate for use in 627550397Sobrien ldd and std insns. */ 627650397Sobrien 627750397Sobrienint 627850397Sobrienregister_ok_for_ldd (reg) 627950397Sobrien rtx reg; 628050397Sobrien{ 628150397Sobrien /* We might have been passed a SUBREG. */ 628250397Sobrien if (GET_CODE (reg) != REG) 628350397Sobrien return 0; 628450397Sobrien 628550397Sobrien if (REGNO (reg) < FIRST_PSEUDO_REGISTER) 628650397Sobrien return (REGNO (reg) % 2 == 0); 628750397Sobrien else 628850397Sobrien return 1; 628950397Sobrien} 629050397Sobrien 629150397Sobrien/* Print operand X (an rtx) in assembler syntax to file FILE. 629250397Sobrien CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. 629350397Sobrien For `%' followed by punctuation, CODE is the punctuation and X is null. */ 629450397Sobrien 629550397Sobrienvoid 629650397Sobrienprint_operand (file, x, code) 629750397Sobrien FILE *file; 629850397Sobrien rtx x; 629950397Sobrien int code; 630050397Sobrien{ 630150397Sobrien switch (code) 630250397Sobrien { 630350397Sobrien case '#': 630450397Sobrien /* Output a 'nop' if there's nothing for the delay slot. */ 630550397Sobrien if (dbr_sequence_length () == 0) 630652284Sobrien fputs ("\n\t nop", file); 630750397Sobrien return; 630850397Sobrien case '*': 630950397Sobrien /* Output an annul flag if there's nothing for the delay slot and we 631050397Sobrien are optimizing. This is always used with '(' below. */ 631150397Sobrien /* Sun OS 4.1.1 dbx can't handle an annulled unconditional branch; 631250397Sobrien this is a dbx bug. So, we only do this when optimizing. */ 631350397Sobrien /* On UltraSPARC, a branch in a delay slot causes a pipeline flush. 631450397Sobrien Always emit a nop in case the next instruction is a branch. */ 631550397Sobrien if (dbr_sequence_length () == 0 631650397Sobrien && (optimize && (int)sparc_cpu < PROCESSOR_V9)) 631750397Sobrien fputs (",a", file); 631850397Sobrien return; 631950397Sobrien case '(': 632050397Sobrien /* Output a 'nop' if there's nothing for the delay slot and we are 632150397Sobrien not optimizing. This is always used with '*' above. */ 632250397Sobrien if (dbr_sequence_length () == 0 632350397Sobrien && ! (optimize && (int)sparc_cpu < PROCESSOR_V9)) 632452284Sobrien fputs ("\n\t nop", file); 632550397Sobrien return; 632650397Sobrien case '_': 632750397Sobrien /* Output the Embedded Medium/Anywhere code model base register. */ 632850397Sobrien fputs (EMBMEDANY_BASE_REG, file); 632950397Sobrien return; 633050397Sobrien case '@': 633150397Sobrien /* Print out what we are using as the frame pointer. This might 633250397Sobrien be %fp, or might be %sp+offset. */ 633350397Sobrien /* ??? What if offset is too big? Perhaps the caller knows it isn't? */ 633450397Sobrien fprintf (file, "%s+%d", frame_base_name, frame_base_offset); 633550397Sobrien return; 633650397Sobrien case 'Y': 633750397Sobrien /* Adjust the operand to take into account a RESTORE operation. */ 633850397Sobrien if (GET_CODE (x) == CONST_INT) 633950397Sobrien break; 634050397Sobrien else if (GET_CODE (x) != REG) 634190075Sobrien output_operand_lossage ("invalid %%Y operand"); 634250397Sobrien else if (REGNO (x) < 8) 634350397Sobrien fputs (reg_names[REGNO (x)], file); 634450397Sobrien else if (REGNO (x) >= 24 && REGNO (x) < 32) 634550397Sobrien fputs (reg_names[REGNO (x)-16], file); 634650397Sobrien else 634790075Sobrien output_operand_lossage ("invalid %%Y operand"); 634850397Sobrien return; 634950397Sobrien case 'L': 635050397Sobrien /* Print out the low order register name of a register pair. */ 635150397Sobrien if (WORDS_BIG_ENDIAN) 635250397Sobrien fputs (reg_names[REGNO (x)+1], file); 635350397Sobrien else 635450397Sobrien fputs (reg_names[REGNO (x)], file); 635550397Sobrien return; 635650397Sobrien case 'H': 635750397Sobrien /* Print out the high order register name of a register pair. */ 635850397Sobrien if (WORDS_BIG_ENDIAN) 635950397Sobrien fputs (reg_names[REGNO (x)], file); 636050397Sobrien else 636150397Sobrien fputs (reg_names[REGNO (x)+1], file); 636250397Sobrien return; 636350397Sobrien case 'R': 636450397Sobrien /* Print out the second register name of a register pair or quad. 636550397Sobrien I.e., R (%o0) => %o1. */ 636650397Sobrien fputs (reg_names[REGNO (x)+1], file); 636750397Sobrien return; 636850397Sobrien case 'S': 636950397Sobrien /* Print out the third register name of a register quad. 637050397Sobrien I.e., S (%o0) => %o2. */ 637150397Sobrien fputs (reg_names[REGNO (x)+2], file); 637250397Sobrien return; 637350397Sobrien case 'T': 637450397Sobrien /* Print out the fourth register name of a register quad. 637550397Sobrien I.e., T (%o0) => %o3. */ 637650397Sobrien fputs (reg_names[REGNO (x)+3], file); 637750397Sobrien return; 637850397Sobrien case 'x': 637950397Sobrien /* Print a condition code register. */ 638050397Sobrien if (REGNO (x) == SPARC_ICC_REG) 638150397Sobrien { 638250397Sobrien /* We don't handle CC[X]_NOOVmode because they're not supposed 638350397Sobrien to occur here. */ 638450397Sobrien if (GET_MODE (x) == CCmode) 638550397Sobrien fputs ("%icc", file); 638650397Sobrien else if (GET_MODE (x) == CCXmode) 638750397Sobrien fputs ("%xcc", file); 638850397Sobrien else 638950397Sobrien abort (); 639050397Sobrien } 639150397Sobrien else 639250397Sobrien /* %fccN register */ 639350397Sobrien fputs (reg_names[REGNO (x)], file); 639450397Sobrien return; 639550397Sobrien case 'm': 639650397Sobrien /* Print the operand's address only. */ 639750397Sobrien output_address (XEXP (x, 0)); 639850397Sobrien return; 639950397Sobrien case 'r': 640050397Sobrien /* In this case we need a register. Use %g0 if the 640150397Sobrien operand is const0_rtx. */ 640250397Sobrien if (x == const0_rtx 640350397Sobrien || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x)))) 640450397Sobrien { 640550397Sobrien fputs ("%g0", file); 640650397Sobrien return; 640750397Sobrien } 640850397Sobrien else 640950397Sobrien break; 641050397Sobrien 641150397Sobrien case 'A': 641250397Sobrien switch (GET_CODE (x)) 641350397Sobrien { 641450397Sobrien case IOR: fputs ("or", file); break; 641550397Sobrien case AND: fputs ("and", file); break; 641650397Sobrien case XOR: fputs ("xor", file); break; 641790075Sobrien default: output_operand_lossage ("invalid %%A operand"); 641850397Sobrien } 641950397Sobrien return; 642050397Sobrien 642150397Sobrien case 'B': 642250397Sobrien switch (GET_CODE (x)) 642350397Sobrien { 642450397Sobrien case IOR: fputs ("orn", file); break; 642550397Sobrien case AND: fputs ("andn", file); break; 642650397Sobrien case XOR: fputs ("xnor", file); break; 642790075Sobrien default: output_operand_lossage ("invalid %%B operand"); 642850397Sobrien } 642950397Sobrien return; 643050397Sobrien 643150397Sobrien /* These are used by the conditional move instructions. */ 643250397Sobrien case 'c' : 643350397Sobrien case 'C': 643450397Sobrien { 643590075Sobrien enum rtx_code rc = GET_CODE (x); 643690075Sobrien 643790075Sobrien if (code == 'c') 643890075Sobrien { 643990075Sobrien enum machine_mode mode = GET_MODE (XEXP (x, 0)); 644090075Sobrien if (mode == CCFPmode || mode == CCFPEmode) 644190075Sobrien rc = reverse_condition_maybe_unordered (GET_CODE (x)); 644290075Sobrien else 644390075Sobrien rc = reverse_condition (GET_CODE (x)); 644490075Sobrien } 644550397Sobrien switch (rc) 644650397Sobrien { 644750397Sobrien case NE: fputs ("ne", file); break; 644850397Sobrien case EQ: fputs ("e", file); break; 644950397Sobrien case GE: fputs ("ge", file); break; 645050397Sobrien case GT: fputs ("g", file); break; 645150397Sobrien case LE: fputs ("le", file); break; 645250397Sobrien case LT: fputs ("l", file); break; 645350397Sobrien case GEU: fputs ("geu", file); break; 645450397Sobrien case GTU: fputs ("gu", file); break; 645550397Sobrien case LEU: fputs ("leu", file); break; 645650397Sobrien case LTU: fputs ("lu", file); break; 645790075Sobrien case LTGT: fputs ("lg", file); break; 645890075Sobrien case UNORDERED: fputs ("u", file); break; 645990075Sobrien case ORDERED: fputs ("o", file); break; 646090075Sobrien case UNLT: fputs ("ul", file); break; 646190075Sobrien case UNLE: fputs ("ule", file); break; 646290075Sobrien case UNGT: fputs ("ug", file); break; 646390075Sobrien case UNGE: fputs ("uge", file); break; 646490075Sobrien case UNEQ: fputs ("ue", file); break; 646550397Sobrien default: output_operand_lossage (code == 'c' 646690075Sobrien ? "invalid %%c operand" 646790075Sobrien : "invalid %%C operand"); 646850397Sobrien } 646950397Sobrien return; 647050397Sobrien } 647150397Sobrien 647250397Sobrien /* These are used by the movr instruction pattern. */ 647350397Sobrien case 'd': 647450397Sobrien case 'D': 647550397Sobrien { 647650397Sobrien enum rtx_code rc = (code == 'd' 647750397Sobrien ? reverse_condition (GET_CODE (x)) 647850397Sobrien : GET_CODE (x)); 647950397Sobrien switch (rc) 648050397Sobrien { 648150397Sobrien case NE: fputs ("ne", file); break; 648250397Sobrien case EQ: fputs ("e", file); break; 648350397Sobrien case GE: fputs ("gez", file); break; 648450397Sobrien case LT: fputs ("lz", file); break; 648550397Sobrien case LE: fputs ("lez", file); break; 648650397Sobrien case GT: fputs ("gz", file); break; 648750397Sobrien default: output_operand_lossage (code == 'd' 648890075Sobrien ? "invalid %%d operand" 648990075Sobrien : "invalid %%D operand"); 649050397Sobrien } 649150397Sobrien return; 649250397Sobrien } 649350397Sobrien 649450397Sobrien case 'b': 649550397Sobrien { 649650397Sobrien /* Print a sign-extended character. */ 649796263Sobrien int i = trunc_int_for_mode (INTVAL (x), QImode); 649850397Sobrien fprintf (file, "%d", i); 649950397Sobrien return; 650050397Sobrien } 650150397Sobrien 650250397Sobrien case 'f': 650350397Sobrien /* Operand must be a MEM; write its address. */ 650450397Sobrien if (GET_CODE (x) != MEM) 650590075Sobrien output_operand_lossage ("invalid %%f operand"); 650650397Sobrien output_address (XEXP (x, 0)); 650750397Sobrien return; 650850397Sobrien 6509117395Skan case 's': 6510117395Skan { 6511117395Skan /* Print a sign-extended 32-bit value. */ 6512117395Skan HOST_WIDE_INT i; 6513117395Skan if (GET_CODE(x) == CONST_INT) 6514117395Skan i = INTVAL (x); 6515117395Skan else if (GET_CODE(x) == CONST_DOUBLE) 6516117395Skan i = CONST_DOUBLE_LOW (x); 6517117395Skan else 6518117395Skan { 6519117395Skan output_operand_lossage ("invalid %%s operand"); 6520117395Skan return; 6521117395Skan } 6522117395Skan i = trunc_int_for_mode (i, SImode); 6523117395Skan fprintf (file, HOST_WIDE_INT_PRINT_DEC, i); 6524117395Skan return; 6525117395Skan } 6526117395Skan 652750397Sobrien case 0: 652850397Sobrien /* Do nothing special. */ 652950397Sobrien break; 653050397Sobrien 653150397Sobrien default: 653250397Sobrien /* Undocumented flag. */ 653350397Sobrien output_operand_lossage ("invalid operand output code"); 653450397Sobrien } 653550397Sobrien 653650397Sobrien if (GET_CODE (x) == REG) 653750397Sobrien fputs (reg_names[REGNO (x)], file); 653850397Sobrien else if (GET_CODE (x) == MEM) 653950397Sobrien { 654050397Sobrien fputc ('[', file); 654150397Sobrien /* Poor Sun assembler doesn't understand absolute addressing. */ 654290075Sobrien if (CONSTANT_P (XEXP (x, 0))) 654350397Sobrien fputs ("%g0+", file); 654450397Sobrien output_address (XEXP (x, 0)); 654550397Sobrien fputc (']', file); 654650397Sobrien } 654750397Sobrien else if (GET_CODE (x) == HIGH) 654850397Sobrien { 654950397Sobrien fputs ("%hi(", file); 655050397Sobrien output_addr_const (file, XEXP (x, 0)); 655150397Sobrien fputc (')', file); 655250397Sobrien } 655350397Sobrien else if (GET_CODE (x) == LO_SUM) 655450397Sobrien { 655550397Sobrien print_operand (file, XEXP (x, 0), 0); 655652284Sobrien if (TARGET_CM_MEDMID) 655752284Sobrien fputs ("+%l44(", file); 655852284Sobrien else 655952284Sobrien fputs ("+%lo(", file); 656050397Sobrien output_addr_const (file, XEXP (x, 1)); 656150397Sobrien fputc (')', file); 656250397Sobrien } 656350397Sobrien else if (GET_CODE (x) == CONST_DOUBLE 656450397Sobrien && (GET_MODE (x) == VOIDmode 656550397Sobrien || GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)) 656650397Sobrien { 656750397Sobrien if (CONST_DOUBLE_HIGH (x) == 0) 656890075Sobrien fprintf (file, "%u", (unsigned int) CONST_DOUBLE_LOW (x)); 656950397Sobrien else if (CONST_DOUBLE_HIGH (x) == -1 657050397Sobrien && CONST_DOUBLE_LOW (x) < 0) 657190075Sobrien fprintf (file, "%d", (int) CONST_DOUBLE_LOW (x)); 657250397Sobrien else 657350397Sobrien output_operand_lossage ("long long constant not a valid immediate operand"); 657450397Sobrien } 657550397Sobrien else if (GET_CODE (x) == CONST_DOUBLE) 657650397Sobrien output_operand_lossage ("floating point constant not a valid immediate operand"); 657750397Sobrien else { output_addr_const (file, x); } 657850397Sobrien} 657950397Sobrien 658090075Sobrien/* Target hook for assembling integer objects. The sparc version has 658190075Sobrien special handling for aligned DI-mode objects. */ 658250397Sobrien 658390075Sobrienstatic bool 658490075Sobriensparc_assemble_integer (x, size, aligned_p) 658590075Sobrien rtx x; 658690075Sobrien unsigned int size; 658790075Sobrien int aligned_p; 658850397Sobrien{ 658990075Sobrien /* ??? We only output .xword's for symbols and only then in environments 659090075Sobrien where the assembler can handle them. */ 659190075Sobrien if (aligned_p && size == 8 659290075Sobrien && (GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE)) 659350397Sobrien { 659490075Sobrien if (TARGET_V9) 659550397Sobrien { 659690075Sobrien assemble_integer_with_op ("\t.xword\t", x); 659790075Sobrien return true; 659850397Sobrien } 659950397Sobrien else 660050397Sobrien { 660190075Sobrien assemble_aligned_integer (4, const0_rtx); 660290075Sobrien assemble_aligned_integer (4, x); 660390075Sobrien return true; 660450397Sobrien } 660550397Sobrien } 660690075Sobrien return default_assemble_integer (x, size, aligned_p); 660750397Sobrien} 660850397Sobrien 660950397Sobrien/* Return the value of a code used in the .proc pseudo-op that says 661050397Sobrien what kind of result this function returns. For non-C types, we pick 661150397Sobrien the closest C type. */ 661250397Sobrien 661350397Sobrien#ifndef SHORT_TYPE_SIZE 661450397Sobrien#define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2) 661550397Sobrien#endif 661650397Sobrien 661750397Sobrien#ifndef INT_TYPE_SIZE 661850397Sobrien#define INT_TYPE_SIZE BITS_PER_WORD 661950397Sobrien#endif 662050397Sobrien 662150397Sobrien#ifndef LONG_TYPE_SIZE 662250397Sobrien#define LONG_TYPE_SIZE BITS_PER_WORD 662350397Sobrien#endif 662450397Sobrien 662550397Sobrien#ifndef LONG_LONG_TYPE_SIZE 662650397Sobrien#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2) 662750397Sobrien#endif 662850397Sobrien 662950397Sobrien#ifndef FLOAT_TYPE_SIZE 663050397Sobrien#define FLOAT_TYPE_SIZE BITS_PER_WORD 663150397Sobrien#endif 663250397Sobrien 663350397Sobrien#ifndef DOUBLE_TYPE_SIZE 663450397Sobrien#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) 663550397Sobrien#endif 663650397Sobrien 663750397Sobrien#ifndef LONG_DOUBLE_TYPE_SIZE 663850397Sobrien#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2) 663950397Sobrien#endif 664050397Sobrien 664150397Sobrienunsigned long 664250397Sobriensparc_type_code (type) 664350397Sobrien register tree type; 664450397Sobrien{ 664550397Sobrien register unsigned long qualifiers = 0; 664650397Sobrien register unsigned shift; 664750397Sobrien 664850397Sobrien /* Only the first 30 bits of the qualifier are valid. We must refrain from 664950397Sobrien setting more, since some assemblers will give an error for this. Also, 665050397Sobrien we must be careful to avoid shifts of 32 bits or more to avoid getting 665150397Sobrien unpredictable results. */ 665250397Sobrien 665350397Sobrien for (shift = 6; shift < 30; shift += 2, type = TREE_TYPE (type)) 665450397Sobrien { 665550397Sobrien switch (TREE_CODE (type)) 665650397Sobrien { 665750397Sobrien case ERROR_MARK: 665850397Sobrien return qualifiers; 665950397Sobrien 666050397Sobrien case ARRAY_TYPE: 666150397Sobrien qualifiers |= (3 << shift); 666250397Sobrien break; 666350397Sobrien 666450397Sobrien case FUNCTION_TYPE: 666550397Sobrien case METHOD_TYPE: 666650397Sobrien qualifiers |= (2 << shift); 666750397Sobrien break; 666850397Sobrien 666950397Sobrien case POINTER_TYPE: 667050397Sobrien case REFERENCE_TYPE: 667150397Sobrien case OFFSET_TYPE: 667250397Sobrien qualifiers |= (1 << shift); 667350397Sobrien break; 667450397Sobrien 667550397Sobrien case RECORD_TYPE: 667650397Sobrien return (qualifiers | 8); 667750397Sobrien 667850397Sobrien case UNION_TYPE: 667950397Sobrien case QUAL_UNION_TYPE: 668050397Sobrien return (qualifiers | 9); 668150397Sobrien 668250397Sobrien case ENUMERAL_TYPE: 668350397Sobrien return (qualifiers | 10); 668450397Sobrien 668550397Sobrien case VOID_TYPE: 668650397Sobrien return (qualifiers | 16); 668750397Sobrien 668850397Sobrien case INTEGER_TYPE: 668950397Sobrien /* If this is a range type, consider it to be the underlying 669050397Sobrien type. */ 669150397Sobrien if (TREE_TYPE (type) != 0) 669250397Sobrien break; 669350397Sobrien 669450397Sobrien /* Carefully distinguish all the standard types of C, 669550397Sobrien without messing up if the language is not C. We do this by 669650397Sobrien testing TYPE_PRECISION and TREE_UNSIGNED. The old code used to 669750397Sobrien look at both the names and the above fields, but that's redundant. 669850397Sobrien Any type whose size is between two C types will be considered 669950397Sobrien to be the wider of the two types. Also, we do not have a 670050397Sobrien special code to use for "long long", so anything wider than 670150397Sobrien long is treated the same. Note that we can't distinguish 670250397Sobrien between "int" and "long" in this code if they are the same 670350397Sobrien size, but that's fine, since neither can the assembler. */ 670450397Sobrien 670550397Sobrien if (TYPE_PRECISION (type) <= CHAR_TYPE_SIZE) 670650397Sobrien return (qualifiers | (TREE_UNSIGNED (type) ? 12 : 2)); 670750397Sobrien 670850397Sobrien else if (TYPE_PRECISION (type) <= SHORT_TYPE_SIZE) 670950397Sobrien return (qualifiers | (TREE_UNSIGNED (type) ? 13 : 3)); 671050397Sobrien 671150397Sobrien else if (TYPE_PRECISION (type) <= INT_TYPE_SIZE) 671250397Sobrien return (qualifiers | (TREE_UNSIGNED (type) ? 14 : 4)); 671350397Sobrien 671450397Sobrien else 671550397Sobrien return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5)); 671650397Sobrien 671750397Sobrien case REAL_TYPE: 671850397Sobrien /* If this is a range type, consider it to be the underlying 671950397Sobrien type. */ 672050397Sobrien if (TREE_TYPE (type) != 0) 672150397Sobrien break; 672250397Sobrien 672350397Sobrien /* Carefully distinguish all the standard types of C, 672450397Sobrien without messing up if the language is not C. */ 672550397Sobrien 672650397Sobrien if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE) 672750397Sobrien return (qualifiers | 6); 672850397Sobrien 672950397Sobrien else 673050397Sobrien return (qualifiers | 7); 673150397Sobrien 673250397Sobrien case COMPLEX_TYPE: /* GNU Fortran COMPLEX type. */ 673350397Sobrien /* ??? We need to distinguish between double and float complex types, 673450397Sobrien but I don't know how yet because I can't reach this code from 673550397Sobrien existing front-ends. */ 673650397Sobrien return (qualifiers | 7); /* Who knows? */ 673750397Sobrien 673850397Sobrien case CHAR_TYPE: /* GNU Pascal CHAR type. Not used in C. */ 673950397Sobrien case BOOLEAN_TYPE: /* GNU Fortran BOOLEAN type. */ 674050397Sobrien case FILE_TYPE: /* GNU Pascal FILE type. */ 674150397Sobrien case SET_TYPE: /* GNU Pascal SET type. */ 674250397Sobrien case LANG_TYPE: /* ? */ 674350397Sobrien return qualifiers; 674450397Sobrien 674550397Sobrien default: 674650397Sobrien abort (); /* Not a type! */ 674750397Sobrien } 674850397Sobrien } 674950397Sobrien 675050397Sobrien return qualifiers; 675150397Sobrien} 675250397Sobrien 675350397Sobrien/* Nested function support. */ 675450397Sobrien 675550397Sobrien/* Emit RTL insns to initialize the variable parts of a trampoline. 675650397Sobrien FNADDR is an RTX for the address of the function's pure code. 675750397Sobrien CXT is an RTX for the static chain value for the function. 675850397Sobrien 675950397Sobrien This takes 16 insns: 2 shifts & 2 ands (to split up addresses), 4 sethi 676050397Sobrien (to load in opcodes), 4 iors (to merge address and opcodes), and 4 writes 676150397Sobrien (to store insns). This is a bit excessive. Perhaps a different 676250397Sobrien mechanism would be better here. 676350397Sobrien 676450397Sobrien Emit enough FLUSH insns to synchronize the data and instruction caches. */ 676550397Sobrien 676650397Sobrienvoid 676750397Sobriensparc_initialize_trampoline (tramp, fnaddr, cxt) 676850397Sobrien rtx tramp, fnaddr, cxt; 676950397Sobrien{ 677050397Sobrien /* SPARC 32 bit trampoline: 677150397Sobrien 677252284Sobrien sethi %hi(fn), %g1 677352284Sobrien sethi %hi(static), %g2 677452284Sobrien jmp %g1+%lo(fn) 677552284Sobrien or %g2, %lo(static), %g2 677650397Sobrien 677750397Sobrien SETHI i,r = 00rr rrr1 00ii iiii iiii iiii iiii iiii 677850397Sobrien JMPL r+i,d = 10dd ddd1 1100 0rrr rr1i iiii iiii iiii 677950397Sobrien */ 678052284Sobrien#ifdef TRANSFER_FROM_TRAMPOLINE 678152284Sobrien emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"), 678296263Sobrien LCT_NORMAL, VOIDmode, 1, tramp, Pmode); 678352284Sobrien#endif 678450397Sobrien 678596263Sobrien emit_move_insn 678696263Sobrien (gen_rtx_MEM (SImode, plus_constant (tramp, 0)), 678796263Sobrien expand_binop (SImode, ior_optab, 678896263Sobrien expand_shift (RSHIFT_EXPR, SImode, fnaddr, 678996263Sobrien size_int (10), 0, 1), 679096263Sobrien GEN_INT (trunc_int_for_mode (0x03000000, SImode)), 679196263Sobrien NULL_RTX, 1, OPTAB_DIRECT)); 679250397Sobrien 679396263Sobrien emit_move_insn 679496263Sobrien (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), 679596263Sobrien expand_binop (SImode, ior_optab, 679696263Sobrien expand_shift (RSHIFT_EXPR, SImode, cxt, 679796263Sobrien size_int (10), 0, 1), 679896263Sobrien GEN_INT (trunc_int_for_mode (0x05000000, SImode)), 679996263Sobrien NULL_RTX, 1, OPTAB_DIRECT)); 680050397Sobrien 680196263Sobrien emit_move_insn 680296263Sobrien (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), 680396263Sobrien expand_binop (SImode, ior_optab, 680496263Sobrien expand_and (SImode, fnaddr, GEN_INT (0x3ff), NULL_RTX), 680596263Sobrien GEN_INT (trunc_int_for_mode (0x81c06000, SImode)), 680696263Sobrien NULL_RTX, 1, OPTAB_DIRECT)); 680750397Sobrien 680896263Sobrien emit_move_insn 680996263Sobrien (gen_rtx_MEM (SImode, plus_constant (tramp, 12)), 681096263Sobrien expand_binop (SImode, ior_optab, 681196263Sobrien expand_and (SImode, cxt, GEN_INT (0x3ff), NULL_RTX), 681296263Sobrien GEN_INT (trunc_int_for_mode (0x8410a000, SImode)), 681396263Sobrien NULL_RTX, 1, OPTAB_DIRECT)); 681450397Sobrien 681550397Sobrien /* On UltraSPARC a flush flushes an entire cache line. The trampoline is 681650397Sobrien aligned on a 16 byte boundary so one flush clears it all. */ 681796263Sobrien emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp)))); 6818117395Skan if (sparc_cpu != PROCESSOR_ULTRASPARC 6819117395Skan && sparc_cpu != PROCESSOR_ULTRASPARC3) 682050397Sobrien emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, 682150397Sobrien plus_constant (tramp, 8))))); 682250397Sobrien} 682350397Sobrien 682450397Sobrien/* The 64 bit version is simpler because it makes more sense to load the 682550397Sobrien values as "immediate" data out of the trampoline. It's also easier since 682650397Sobrien we can read the PC without clobbering a register. */ 682750397Sobrien 682850397Sobrienvoid 682950397Sobriensparc64_initialize_trampoline (tramp, fnaddr, cxt) 683050397Sobrien rtx tramp, fnaddr, cxt; 683150397Sobrien{ 683252284Sobrien#ifdef TRANSFER_FROM_TRAMPOLINE 683352284Sobrien emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"), 683496263Sobrien LCT_NORMAL, VOIDmode, 1, tramp, Pmode); 683552284Sobrien#endif 683652284Sobrien 683750397Sobrien /* 683852284Sobrien rd %pc, %g1 683952284Sobrien ldx [%g1+24], %g5 684052284Sobrien jmp %g5 684152284Sobrien ldx [%g1+16], %g5 684250397Sobrien +16 bytes data 684350397Sobrien */ 684450397Sobrien 684550397Sobrien emit_move_insn (gen_rtx_MEM (SImode, tramp), 684696263Sobrien GEN_INT (trunc_int_for_mode (0x83414000, SImode))); 684750397Sobrien emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), 684896263Sobrien GEN_INT (trunc_int_for_mode (0xca586018, SImode))); 684950397Sobrien emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), 685096263Sobrien GEN_INT (trunc_int_for_mode (0x81c14000, SImode))); 685150397Sobrien emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)), 685296263Sobrien GEN_INT (trunc_int_for_mode (0xca586010, SImode))); 685350397Sobrien emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt); 685452284Sobrien emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr); 685590075Sobrien emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp)))); 685652284Sobrien 6857117395Skan if (sparc_cpu != PROCESSOR_ULTRASPARC 6858117395Skan && sparc_cpu != PROCESSOR_ULTRASPARC3) 685990075Sobrien emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8))))); 686050397Sobrien} 686150397Sobrien 686250397Sobrien/* Subroutines to support a flat (single) register window calling 686350397Sobrien convention. */ 686450397Sobrien 686550397Sobrien/* Single-register window sparc stack frames look like: 686650397Sobrien 686750397Sobrien Before call After call 686850397Sobrien +-----------------------+ +-----------------------+ 686950397Sobrien high | | | | 687050397Sobrien mem | caller's temps. | | caller's temps. | 687150397Sobrien | | | | 687250397Sobrien +-----------------------+ +-----------------------+ 687350397Sobrien | | | | 687450397Sobrien | arguments on stack. | | arguments on stack. | 687550397Sobrien | | | | 687650397Sobrien +-----------------------+FP+92->+-----------------------+ 687750397Sobrien | 6 words to save | | 6 words to save | 687850397Sobrien | arguments passed | | arguments passed | 687950397Sobrien | in registers, even | | in registers, even | 688050397Sobrien | if not passed. | | if not passed. | 688150397Sobrien SP+68->+-----------------------+FP+68->+-----------------------+ 688250397Sobrien | 1 word struct addr | | 1 word struct addr | 688350397Sobrien +-----------------------+FP+64->+-----------------------+ 688450397Sobrien | | | | 688550397Sobrien | 16 word reg save area | | 16 word reg save area | 688650397Sobrien | | | | 688750397Sobrien SP->+-----------------------+ FP->+-----------------------+ 688850397Sobrien | 4 word area for | 688950397Sobrien | fp/alu reg moves | 689050397Sobrien FP-16->+-----------------------+ 689150397Sobrien | | 689250397Sobrien | local variables | 689350397Sobrien | | 689450397Sobrien +-----------------------+ 689550397Sobrien | | 689650397Sobrien | fp register save | 689750397Sobrien | | 689850397Sobrien +-----------------------+ 689950397Sobrien | | 690050397Sobrien | gp register save | 690150397Sobrien | | 690250397Sobrien +-----------------------+ 690350397Sobrien | | 690450397Sobrien | alloca allocations | 690550397Sobrien | | 690650397Sobrien +-----------------------+ 690750397Sobrien | | 690850397Sobrien | arguments on stack | 690950397Sobrien | | 691050397Sobrien SP+92->+-----------------------+ 691150397Sobrien | 6 words to save | 691250397Sobrien | arguments passed | 691350397Sobrien | in registers, even | 691450397Sobrien low | if not passed. | 691550397Sobrien memory SP+68->+-----------------------+ 691650397Sobrien | 1 word struct addr | 691750397Sobrien SP+64->+-----------------------+ 691850397Sobrien | | 691950397Sobrien I 16 word reg save area | 692050397Sobrien | | 692150397Sobrien SP->+-----------------------+ */ 692250397Sobrien 692350397Sobrien/* Structure to be filled in by sparc_flat_compute_frame_size with register 692450397Sobrien save masks, and offsets for the current function. */ 692550397Sobrien 692650397Sobrienstruct sparc_frame_info 692750397Sobrien{ 692850397Sobrien unsigned long total_size; /* # bytes that the entire frame takes up. */ 692950397Sobrien unsigned long var_size; /* # bytes that variables take up. */ 693050397Sobrien unsigned long args_size; /* # bytes that outgoing arguments take up. */ 693150397Sobrien unsigned long extra_size; /* # bytes of extra gunk. */ 693250397Sobrien unsigned int gp_reg_size; /* # bytes needed to store gp regs. */ 693350397Sobrien unsigned int fp_reg_size; /* # bytes needed to store fp regs. */ 693450397Sobrien unsigned long gmask; /* Mask of saved gp registers. */ 693550397Sobrien unsigned long fmask; /* Mask of saved fp registers. */ 693650397Sobrien unsigned long reg_offset; /* Offset from new sp to store regs. */ 693750397Sobrien int initialized; /* Nonzero if frame size already calculated. */ 693850397Sobrien}; 693950397Sobrien 694050397Sobrien/* Current frame information calculated by sparc_flat_compute_frame_size. */ 694150397Sobrienstruct sparc_frame_info current_frame_info; 694250397Sobrien 694350397Sobrien/* Zero structure to initialize current_frame_info. */ 694450397Sobrienstruct sparc_frame_info zero_frame_info; 694550397Sobrien 694650397Sobrien/* Tell prologue and epilogue if register REGNO should be saved / restored. */ 694750397Sobrien 694850397Sobrien#define RETURN_ADDR_REGNUM 15 694996263Sobrien#define HARD_FRAME_POINTER_MASK (1 << (HARD_FRAME_POINTER_REGNUM)) 695050397Sobrien#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM)) 695150397Sobrien 695250397Sobrien#define MUST_SAVE_REGISTER(regno) \ 695396263Sobrien ((regs_ever_live[regno] && !call_used_regs[regno]) \ 695496263Sobrien || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \ 695550397Sobrien || (regno == RETURN_ADDR_REGNUM && regs_ever_live[RETURN_ADDR_REGNUM])) 695650397Sobrien 695750397Sobrien/* Return the bytes needed to compute the frame pointer from the current 695850397Sobrien stack pointer. */ 695950397Sobrien 696050397Sobrienunsigned long 696150397Sobriensparc_flat_compute_frame_size (size) 696250397Sobrien int size; /* # of var. bytes allocated. */ 696350397Sobrien{ 696450397Sobrien int regno; 696550397Sobrien unsigned long total_size; /* # bytes that the entire frame takes up. */ 696650397Sobrien unsigned long var_size; /* # bytes that variables take up. */ 696750397Sobrien unsigned long args_size; /* # bytes that outgoing arguments take up. */ 696850397Sobrien unsigned long extra_size; /* # extra bytes. */ 696950397Sobrien unsigned int gp_reg_size; /* # bytes needed to store gp regs. */ 697050397Sobrien unsigned int fp_reg_size; /* # bytes needed to store fp regs. */ 697150397Sobrien unsigned long gmask; /* Mask of saved gp registers. */ 697250397Sobrien unsigned long fmask; /* Mask of saved fp registers. */ 697350397Sobrien unsigned long reg_offset; /* Offset to register save area. */ 697450397Sobrien int need_aligned_p; /* 1 if need the save area 8 byte aligned. */ 697550397Sobrien 697650397Sobrien /* This is the size of the 16 word reg save area, 1 word struct addr 697750397Sobrien area, and 4 word fp/alu register copy area. */ 697852284Sobrien extra_size = -STARTING_FRAME_OFFSET + FIRST_PARM_OFFSET(0); 697952284Sobrien var_size = size; 698052284Sobrien gp_reg_size = 0; 698152284Sobrien fp_reg_size = 0; 698252284Sobrien gmask = 0; 698352284Sobrien fmask = 0; 698452284Sobrien reg_offset = 0; 698550397Sobrien need_aligned_p = 0; 698650397Sobrien 698752284Sobrien args_size = 0; 698852284Sobrien if (!leaf_function_p ()) 698952284Sobrien { 699052284Sobrien /* Also include the size needed for the 6 parameter registers. */ 699152284Sobrien args_size = current_function_outgoing_args_size + 24; 699252284Sobrien } 699352284Sobrien total_size = var_size + args_size; 699452284Sobrien 699550397Sobrien /* Calculate space needed for gp registers. */ 699650397Sobrien for (regno = 1; regno <= 31; regno++) 699750397Sobrien { 699850397Sobrien if (MUST_SAVE_REGISTER (regno)) 699950397Sobrien { 700050397Sobrien /* If we need to save two regs in a row, ensure there's room to bump 700150397Sobrien up the address to align it to a doubleword boundary. */ 700250397Sobrien if ((regno & 0x1) == 0 && MUST_SAVE_REGISTER (regno+1)) 700350397Sobrien { 700450397Sobrien if (gp_reg_size % 8 != 0) 700550397Sobrien gp_reg_size += 4; 700650397Sobrien gp_reg_size += 2 * UNITS_PER_WORD; 700750397Sobrien gmask |= 3 << regno; 700850397Sobrien regno++; 700950397Sobrien need_aligned_p = 1; 701050397Sobrien } 701150397Sobrien else 701250397Sobrien { 701350397Sobrien gp_reg_size += UNITS_PER_WORD; 701450397Sobrien gmask |= 1 << regno; 701550397Sobrien } 701650397Sobrien } 701750397Sobrien } 701850397Sobrien 701950397Sobrien /* Calculate space needed for fp registers. */ 702050397Sobrien for (regno = 32; regno <= 63; regno++) 702150397Sobrien { 702250397Sobrien if (regs_ever_live[regno] && !call_used_regs[regno]) 702350397Sobrien { 702450397Sobrien fp_reg_size += UNITS_PER_WORD; 702550397Sobrien fmask |= 1 << (regno - 32); 702650397Sobrien } 702750397Sobrien } 702850397Sobrien 702950397Sobrien if (gmask || fmask) 703050397Sobrien { 703150397Sobrien int n; 703250397Sobrien reg_offset = FIRST_PARM_OFFSET(0) + args_size; 703350397Sobrien /* Ensure save area is 8 byte aligned if we need it. */ 703450397Sobrien n = reg_offset % 8; 703550397Sobrien if (need_aligned_p && n != 0) 703650397Sobrien { 703750397Sobrien total_size += 8 - n; 703850397Sobrien reg_offset += 8 - n; 703950397Sobrien } 704050397Sobrien total_size += gp_reg_size + fp_reg_size; 704150397Sobrien } 704250397Sobrien 704352284Sobrien /* If we must allocate a stack frame at all, we must also allocate 704452284Sobrien room for register window spillage, so as to be binary compatible 704552284Sobrien with libraries and operating systems that do not use -mflat. */ 704652284Sobrien if (total_size > 0) 704752284Sobrien total_size += extra_size; 704852284Sobrien else 704952284Sobrien extra_size = 0; 705050397Sobrien 705150397Sobrien total_size = SPARC_STACK_ALIGN (total_size); 705250397Sobrien 705350397Sobrien /* Save other computed information. */ 705450397Sobrien current_frame_info.total_size = total_size; 705550397Sobrien current_frame_info.var_size = var_size; 705650397Sobrien current_frame_info.args_size = args_size; 705750397Sobrien current_frame_info.extra_size = extra_size; 705850397Sobrien current_frame_info.gp_reg_size = gp_reg_size; 705950397Sobrien current_frame_info.fp_reg_size = fp_reg_size; 706050397Sobrien current_frame_info.gmask = gmask; 706150397Sobrien current_frame_info.fmask = fmask; 706250397Sobrien current_frame_info.reg_offset = reg_offset; 706350397Sobrien current_frame_info.initialized = reload_completed; 706450397Sobrien 706550397Sobrien /* Ok, we're done. */ 706650397Sobrien return total_size; 706750397Sobrien} 706850397Sobrien 706950397Sobrien/* Save/restore registers in GMASK and FMASK at register BASE_REG plus offset 707050397Sobrien OFFSET. 707150397Sobrien 707250397Sobrien BASE_REG must be 8 byte aligned. This allows us to test OFFSET for 707350397Sobrien appropriate alignment and use DOUBLEWORD_OP when we can. We assume 707450397Sobrien [BASE_REG+OFFSET] will always be a valid address. 707550397Sobrien 707650397Sobrien WORD_OP is either "st" for save, "ld" for restore. 707750397Sobrien DOUBLEWORD_OP is either "std" for save, "ldd" for restore. */ 707850397Sobrien 707950397Sobrienvoid 708050397Sobriensparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op, 708150397Sobrien doubleword_op, base_offset) 708250397Sobrien FILE *file; 708390075Sobrien const char *base_reg; 708450397Sobrien unsigned int offset; 708550397Sobrien unsigned long gmask; 708650397Sobrien unsigned long fmask; 708790075Sobrien const char *word_op; 708890075Sobrien const char *doubleword_op; 708950397Sobrien unsigned long base_offset; 709050397Sobrien{ 709150397Sobrien int regno; 709250397Sobrien 709350397Sobrien if (gmask == 0 && fmask == 0) 709450397Sobrien return; 709550397Sobrien 709650397Sobrien /* Save registers starting from high to low. We've already saved the 709750397Sobrien previous frame pointer and previous return address for the debugger's 709850397Sobrien sake. The debugger allows us to not need a nop in the epilog if at least 709950397Sobrien one register is reloaded in addition to return address. */ 710050397Sobrien 710150397Sobrien if (gmask) 710250397Sobrien { 710350397Sobrien for (regno = 1; regno <= 31; regno++) 710450397Sobrien { 710550397Sobrien if ((gmask & (1L << regno)) != 0) 710650397Sobrien { 710750397Sobrien if ((regno & 0x1) == 0 && ((gmask & (1L << (regno+1))) != 0)) 710850397Sobrien { 710950397Sobrien /* We can save two registers in a row. If we're not at a 711050397Sobrien double word boundary, move to one. 711150397Sobrien sparc_flat_compute_frame_size ensures there's room to do 711250397Sobrien this. */ 711350397Sobrien if (offset % 8 != 0) 711450397Sobrien offset += UNITS_PER_WORD; 711550397Sobrien 711650397Sobrien if (word_op[0] == 's') 711750397Sobrien { 711852284Sobrien fprintf (file, "\t%s\t%s, [%s+%d]\n", 711950397Sobrien doubleword_op, reg_names[regno], 712050397Sobrien base_reg, offset); 712150397Sobrien if (dwarf2out_do_frame ()) 712250397Sobrien { 712350397Sobrien char *l = dwarf2out_cfi_label (); 712450397Sobrien dwarf2out_reg_save (l, regno, offset + base_offset); 712550397Sobrien dwarf2out_reg_save 712650397Sobrien (l, regno+1, offset+base_offset + UNITS_PER_WORD); 712750397Sobrien } 712850397Sobrien } 712950397Sobrien else 713052284Sobrien fprintf (file, "\t%s\t[%s+%d], %s\n", 713150397Sobrien doubleword_op, base_reg, offset, 713250397Sobrien reg_names[regno]); 713350397Sobrien 713450397Sobrien offset += 2 * UNITS_PER_WORD; 713550397Sobrien regno++; 713650397Sobrien } 713750397Sobrien else 713850397Sobrien { 713950397Sobrien if (word_op[0] == 's') 714050397Sobrien { 714152284Sobrien fprintf (file, "\t%s\t%s, [%s+%d]\n", 714250397Sobrien word_op, reg_names[regno], 714350397Sobrien base_reg, offset); 714450397Sobrien if (dwarf2out_do_frame ()) 714550397Sobrien dwarf2out_reg_save ("", regno, offset + base_offset); 714650397Sobrien } 714750397Sobrien else 714852284Sobrien fprintf (file, "\t%s\t[%s+%d], %s\n", 714950397Sobrien word_op, base_reg, offset, reg_names[regno]); 715050397Sobrien 715150397Sobrien offset += UNITS_PER_WORD; 715250397Sobrien } 715350397Sobrien } 715450397Sobrien } 715550397Sobrien } 715650397Sobrien 715750397Sobrien if (fmask) 715850397Sobrien { 715950397Sobrien for (regno = 32; regno <= 63; regno++) 716050397Sobrien { 716150397Sobrien if ((fmask & (1L << (regno - 32))) != 0) 716250397Sobrien { 716350397Sobrien if (word_op[0] == 's') 716450397Sobrien { 716552284Sobrien fprintf (file, "\t%s\t%s, [%s+%d]\n", 716650397Sobrien word_op, reg_names[regno], 716750397Sobrien base_reg, offset); 716850397Sobrien if (dwarf2out_do_frame ()) 716950397Sobrien dwarf2out_reg_save ("", regno, offset + base_offset); 717050397Sobrien } 717150397Sobrien else 717252284Sobrien fprintf (file, "\t%s\t[%s+%d], %s\n", 717350397Sobrien word_op, base_reg, offset, reg_names[regno]); 717450397Sobrien 717550397Sobrien offset += UNITS_PER_WORD; 717650397Sobrien } 717750397Sobrien } 717850397Sobrien } 717950397Sobrien} 718050397Sobrien 718150397Sobrien/* Set up the stack and frame (if desired) for the function. */ 718250397Sobrien 718390075Sobrienstatic void 718490075Sobriensparc_flat_function_prologue (file, size) 718550397Sobrien FILE *file; 718690075Sobrien HOST_WIDE_INT size; 718750397Sobrien{ 718890075Sobrien const char *sp_str = reg_names[STACK_POINTER_REGNUM]; 718950397Sobrien unsigned long gmask = current_frame_info.gmask; 719050397Sobrien 719190075Sobrien sparc_output_scratch_registers (file); 719290075Sobrien 719350397Sobrien /* This is only for the human reader. */ 719450397Sobrien fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START); 719550397Sobrien fprintf (file, "\t%s# vars= %ld, regs= %d/%d, args= %d, extra= %ld\n", 719650397Sobrien ASM_COMMENT_START, 719750397Sobrien current_frame_info.var_size, 719850397Sobrien current_frame_info.gp_reg_size / 4, 719950397Sobrien current_frame_info.fp_reg_size / 4, 720050397Sobrien current_function_outgoing_args_size, 720150397Sobrien current_frame_info.extra_size); 720250397Sobrien 720350397Sobrien size = SPARC_STACK_ALIGN (size); 720450397Sobrien size = (! current_frame_info.initialized 720550397Sobrien ? sparc_flat_compute_frame_size (size) 720650397Sobrien : current_frame_info.total_size); 720750397Sobrien 720850397Sobrien /* These cases shouldn't happen. Catch them now. */ 720950397Sobrien if (size == 0 && (gmask || current_frame_info.fmask)) 721050397Sobrien abort (); 721150397Sobrien 721250397Sobrien /* Allocate our stack frame by decrementing %sp. 721350397Sobrien At present, the only algorithm gdb can use to determine if this is a 721450397Sobrien flat frame is if we always set %i7 if we set %sp. This can be optimized 721550397Sobrien in the future by putting in some sort of debugging information that says 721650397Sobrien this is a `flat' function. However, there is still the case of debugging 721750397Sobrien code without such debugging information (including cases where most fns 721850397Sobrien have such info, but there is one that doesn't). So, always do this now 721950397Sobrien so we don't get a lot of code out there that gdb can't handle. 722050397Sobrien If the frame pointer isn't needn't then that's ok - gdb won't be able to 722150397Sobrien distinguish us from a non-flat function but there won't (and shouldn't) 722250397Sobrien be any differences anyway. The return pc is saved (if necessary) right 722350397Sobrien after %i7 so gdb won't have to look too far to find it. */ 722450397Sobrien if (size > 0) 722550397Sobrien { 722650397Sobrien unsigned int reg_offset = current_frame_info.reg_offset; 722796263Sobrien const char *const fp_str = reg_names[HARD_FRAME_POINTER_REGNUM]; 722890075Sobrien static const char *const t1_str = "%g1"; 722950397Sobrien 723050397Sobrien /* Things get a little tricky if local variables take up more than ~4096 723150397Sobrien bytes and outgoing arguments take up more than ~4096 bytes. When that 723250397Sobrien happens, the register save area can't be accessed from either end of 723350397Sobrien the frame. Handle this by decrementing %sp to the start of the gp 723450397Sobrien register save area, save the regs, update %i7, and then set %sp to its 723550397Sobrien final value. Given that we only have one scratch register to play 723650397Sobrien with it is the cheapest solution, and it helps gdb out as it won't 723750397Sobrien slow down recognition of flat functions. 723850397Sobrien Don't change the order of insns emitted here without checking with 723950397Sobrien the gdb folk first. */ 724050397Sobrien 724150397Sobrien /* Is the entire register save area offsettable from %sp? */ 724290075Sobrien if (reg_offset < 4096 - 64 * (unsigned) UNITS_PER_WORD) 724350397Sobrien { 724450397Sobrien if (size <= 4096) 724550397Sobrien { 724652284Sobrien fprintf (file, "\tadd\t%s, %d, %s\n", 724790075Sobrien sp_str, (int) -size, sp_str); 724896263Sobrien if (gmask & HARD_FRAME_POINTER_MASK) 724950397Sobrien { 725052284Sobrien fprintf (file, "\tst\t%s, [%s+%d]\n", 725150397Sobrien fp_str, sp_str, reg_offset); 725252284Sobrien fprintf (file, "\tsub\t%s, %d, %s\t%s# set up frame pointer\n", 725390075Sobrien sp_str, (int) -size, fp_str, ASM_COMMENT_START); 725450397Sobrien reg_offset += 4; 725550397Sobrien } 725650397Sobrien } 725750397Sobrien else 725850397Sobrien { 725990075Sobrien fprintf (file, "\tset\t"); 726090075Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, size); 726190075Sobrien fprintf (file, ", %s\n\tsub\t%s, %s, %s\n", 726290075Sobrien t1_str, sp_str, t1_str, sp_str); 726396263Sobrien if (gmask & HARD_FRAME_POINTER_MASK) 726450397Sobrien { 726552284Sobrien fprintf (file, "\tst\t%s, [%s+%d]\n", 726650397Sobrien fp_str, sp_str, reg_offset); 726752284Sobrien fprintf (file, "\tadd\t%s, %s, %s\t%s# set up frame pointer\n", 726850397Sobrien sp_str, t1_str, fp_str, ASM_COMMENT_START); 726950397Sobrien reg_offset += 4; 727050397Sobrien } 727150397Sobrien } 727250397Sobrien if (dwarf2out_do_frame ()) 727350397Sobrien { 727450397Sobrien char *l = dwarf2out_cfi_label (); 727596263Sobrien if (gmask & HARD_FRAME_POINTER_MASK) 727650397Sobrien { 727796263Sobrien dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM, 727850397Sobrien reg_offset - 4 - size); 727996263Sobrien dwarf2out_def_cfa (l, HARD_FRAME_POINTER_REGNUM, 0); 728050397Sobrien } 728150397Sobrien else 728250397Sobrien dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size); 728350397Sobrien } 728450397Sobrien if (gmask & RETURN_ADDR_MASK) 728550397Sobrien { 728652284Sobrien fprintf (file, "\tst\t%s, [%s+%d]\n", 728750397Sobrien reg_names[RETURN_ADDR_REGNUM], sp_str, reg_offset); 728850397Sobrien if (dwarf2out_do_frame ()) 728950397Sobrien dwarf2out_return_save ("", reg_offset - size); 729050397Sobrien reg_offset += 4; 729150397Sobrien } 729250397Sobrien sparc_flat_save_restore (file, sp_str, reg_offset, 729396263Sobrien gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK), 729450397Sobrien current_frame_info.fmask, 729550397Sobrien "st", "std", -size); 729650397Sobrien } 729750397Sobrien else 729850397Sobrien { 729950397Sobrien /* Subtract %sp in two steps, but make sure there is always a 730050397Sobrien 64 byte register save area, and %sp is properly aligned. */ 730150397Sobrien /* Amount to decrement %sp by, the first time. */ 730290075Sobrien unsigned HOST_WIDE_INT size1 = ((size - reg_offset + 64) + 15) & -16; 730350397Sobrien /* Offset to register save area from %sp. */ 730490075Sobrien unsigned HOST_WIDE_INT offset = size1 - (size - reg_offset); 730550397Sobrien 730650397Sobrien if (size1 <= 4096) 730750397Sobrien { 730852284Sobrien fprintf (file, "\tadd\t%s, %d, %s\n", 730990075Sobrien sp_str, (int) -size1, sp_str); 731096263Sobrien if (gmask & HARD_FRAME_POINTER_MASK) 731150397Sobrien { 731252284Sobrien fprintf (file, "\tst\t%s, [%s+%d]\n\tsub\t%s, %d, %s\t%s# set up frame pointer\n", 731390075Sobrien fp_str, sp_str, (int) offset, sp_str, (int) -size1, 731490075Sobrien fp_str, ASM_COMMENT_START); 731550397Sobrien offset += 4; 731650397Sobrien } 731750397Sobrien } 731850397Sobrien else 731950397Sobrien { 732090075Sobrien fprintf (file, "\tset\t"); 732190075Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, size1); 732290075Sobrien fprintf (file, ", %s\n\tsub\t%s, %s, %s\n", 732390075Sobrien t1_str, sp_str, t1_str, sp_str); 732496263Sobrien if (gmask & HARD_FRAME_POINTER_MASK) 732550397Sobrien { 732652284Sobrien fprintf (file, "\tst\t%s, [%s+%d]\n\tadd\t%s, %s, %s\t%s# set up frame pointer\n", 732790075Sobrien fp_str, sp_str, (int) offset, sp_str, t1_str, 732890075Sobrien fp_str, ASM_COMMENT_START); 732950397Sobrien offset += 4; 733050397Sobrien } 733150397Sobrien } 733250397Sobrien if (dwarf2out_do_frame ()) 733350397Sobrien { 733450397Sobrien char *l = dwarf2out_cfi_label (); 733596263Sobrien if (gmask & HARD_FRAME_POINTER_MASK) 733650397Sobrien { 733796263Sobrien dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM, 733850397Sobrien offset - 4 - size1); 733996263Sobrien dwarf2out_def_cfa (l, HARD_FRAME_POINTER_REGNUM, 0); 734050397Sobrien } 734150397Sobrien else 734250397Sobrien dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size1); 734350397Sobrien } 734450397Sobrien if (gmask & RETURN_ADDR_MASK) 734550397Sobrien { 734652284Sobrien fprintf (file, "\tst\t%s, [%s+%d]\n", 734790075Sobrien reg_names[RETURN_ADDR_REGNUM], sp_str, (int) offset); 734850397Sobrien if (dwarf2out_do_frame ()) 734950397Sobrien /* offset - size1 == reg_offset - size 735050397Sobrien if reg_offset were updated above like offset. */ 735150397Sobrien dwarf2out_return_save ("", offset - size1); 735250397Sobrien offset += 4; 735350397Sobrien } 735450397Sobrien sparc_flat_save_restore (file, sp_str, offset, 735596263Sobrien gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK), 735650397Sobrien current_frame_info.fmask, 735750397Sobrien "st", "std", -size1); 735890075Sobrien fprintf (file, "\tset\t"); 735990075Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, size - size1); 736090075Sobrien fprintf (file, ", %s\n\tsub\t%s, %s, %s\n", 736190075Sobrien t1_str, sp_str, t1_str, sp_str); 736250397Sobrien if (dwarf2out_do_frame ()) 736396263Sobrien if (! (gmask & HARD_FRAME_POINTER_MASK)) 736450397Sobrien dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, size); 736550397Sobrien } 736650397Sobrien } 736750397Sobrien 736850397Sobrien fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START); 736950397Sobrien} 737050397Sobrien 737150397Sobrien/* Do any necessary cleanup after a function to restore stack, frame, 737290075Sobrien and regs. */ 737350397Sobrien 737490075Sobrienstatic void 737590075Sobriensparc_flat_function_epilogue (file, size) 737650397Sobrien FILE *file; 737790075Sobrien HOST_WIDE_INT size; 737850397Sobrien{ 737950397Sobrien rtx epilogue_delay = current_function_epilogue_delay_list; 738050397Sobrien int noepilogue = FALSE; 738150397Sobrien 738250397Sobrien /* This is only for the human reader. */ 738350397Sobrien fprintf (file, "\t%s#EPILOGUE#\n", ASM_COMMENT_START); 738450397Sobrien 738550397Sobrien /* The epilogue does not depend on any registers, but the stack 738650397Sobrien registers, so we assume that if we have 1 pending nop, it can be 738750397Sobrien ignored, and 2 it must be filled (2 nops occur for integer 738850397Sobrien multiply and divide). */ 738950397Sobrien 739050397Sobrien size = SPARC_STACK_ALIGN (size); 739150397Sobrien size = (!current_frame_info.initialized 739250397Sobrien ? sparc_flat_compute_frame_size (size) 739350397Sobrien : current_frame_info.total_size); 739450397Sobrien 739550397Sobrien if (size == 0 && epilogue_delay == 0) 739650397Sobrien { 739750397Sobrien rtx insn = get_last_insn (); 739850397Sobrien 739950397Sobrien /* If the last insn was a BARRIER, we don't have to write any code 740050397Sobrien because a jump (aka return) was put there. */ 740150397Sobrien if (GET_CODE (insn) == NOTE) 740250397Sobrien insn = prev_nonnote_insn (insn); 740350397Sobrien if (insn && GET_CODE (insn) == BARRIER) 740450397Sobrien noepilogue = TRUE; 740550397Sobrien } 740650397Sobrien 740750397Sobrien if (!noepilogue) 740850397Sobrien { 740990075Sobrien unsigned HOST_WIDE_INT reg_offset = current_frame_info.reg_offset; 741090075Sobrien unsigned HOST_WIDE_INT size1; 741190075Sobrien const char *const sp_str = reg_names[STACK_POINTER_REGNUM]; 741296263Sobrien const char *const fp_str = reg_names[HARD_FRAME_POINTER_REGNUM]; 741390075Sobrien static const char *const t1_str = "%g1"; 741450397Sobrien 741550397Sobrien /* In the reload sequence, we don't need to fill the load delay 741650397Sobrien slots for most of the loads, also see if we can fill the final 741750397Sobrien delay slot if not otherwise filled by the reload sequence. */ 741850397Sobrien 741950397Sobrien if (size > 4095) 742090075Sobrien { 742190075Sobrien fprintf (file, "\tset\t"); 742290075Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, size); 742390075Sobrien fprintf (file, ", %s\n", t1_str); 742490075Sobrien } 742550397Sobrien 742650397Sobrien if (frame_pointer_needed) 742750397Sobrien { 742850397Sobrien if (size > 4095) 742952284Sobrien fprintf (file,"\tsub\t%s, %s, %s\t\t%s# sp not trusted here\n", 743050397Sobrien fp_str, t1_str, sp_str, ASM_COMMENT_START); 743150397Sobrien else 743252284Sobrien fprintf (file,"\tsub\t%s, %d, %s\t\t%s# sp not trusted here\n", 743390075Sobrien fp_str, (int) size, sp_str, ASM_COMMENT_START); 743450397Sobrien } 743550397Sobrien 743650397Sobrien /* Is the entire register save area offsettable from %sp? */ 743790075Sobrien if (reg_offset < 4096 - 64 * (unsigned) UNITS_PER_WORD) 743850397Sobrien { 743950397Sobrien size1 = 0; 744050397Sobrien } 744150397Sobrien else 744250397Sobrien { 744350397Sobrien /* Restore %sp in two steps, but make sure there is always a 744450397Sobrien 64 byte register save area, and %sp is properly aligned. */ 744550397Sobrien /* Amount to increment %sp by, the first time. */ 744650397Sobrien size1 = ((reg_offset - 64 - 16) + 15) & -16; 744750397Sobrien /* Offset to register save area from %sp. */ 744850397Sobrien reg_offset = size1 - reg_offset; 744950397Sobrien 745090075Sobrien fprintf (file, "\tset\t"); 745190075Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, size1); 745290075Sobrien fprintf (file, ", %s\n\tadd\t%s, %s, %s\n", 745390075Sobrien t1_str, sp_str, t1_str, sp_str); 745450397Sobrien } 745550397Sobrien 745650397Sobrien /* We must restore the frame pointer and return address reg first 745750397Sobrien because they are treated specially by the prologue output code. */ 745896263Sobrien if (current_frame_info.gmask & HARD_FRAME_POINTER_MASK) 745950397Sobrien { 746052284Sobrien fprintf (file, "\tld\t[%s+%d], %s\n", 746190075Sobrien sp_str, (int) reg_offset, fp_str); 746250397Sobrien reg_offset += 4; 746350397Sobrien } 746450397Sobrien if (current_frame_info.gmask & RETURN_ADDR_MASK) 746550397Sobrien { 746652284Sobrien fprintf (file, "\tld\t[%s+%d], %s\n", 746790075Sobrien sp_str, (int) reg_offset, reg_names[RETURN_ADDR_REGNUM]); 746850397Sobrien reg_offset += 4; 746950397Sobrien } 747050397Sobrien 747150397Sobrien /* Restore any remaining saved registers. */ 747250397Sobrien sparc_flat_save_restore (file, sp_str, reg_offset, 747396263Sobrien current_frame_info.gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK), 747450397Sobrien current_frame_info.fmask, 747550397Sobrien "ld", "ldd", 0); 747650397Sobrien 747750397Sobrien /* If we had to increment %sp in two steps, record it so the second 747850397Sobrien restoration in the epilogue finishes up. */ 747950397Sobrien if (size1 > 0) 748050397Sobrien { 748150397Sobrien size -= size1; 748250397Sobrien if (size > 4095) 748390075Sobrien { 748490075Sobrien fprintf (file, "\tset\t"); 748590075Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, size); 748690075Sobrien fprintf (file, ", %s\n", t1_str); 748790075Sobrien } 748850397Sobrien } 748950397Sobrien 749050397Sobrien if (current_function_returns_struct) 749152284Sobrien fprintf (file, "\tjmp\t%%o7+12\n"); 749250397Sobrien else 749350397Sobrien fprintf (file, "\tretl\n"); 749450397Sobrien 749550397Sobrien /* If the only register saved is the return address, we need a 749650397Sobrien nop, unless we have an instruction to put into it. Otherwise 749750397Sobrien we don't since reloading multiple registers doesn't reference 749850397Sobrien the register being loaded. */ 749950397Sobrien 750050397Sobrien if (epilogue_delay) 750150397Sobrien { 750250397Sobrien if (size) 750350397Sobrien abort (); 750450397Sobrien final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1); 750550397Sobrien } 750650397Sobrien 750750397Sobrien else if (size > 4095) 750852284Sobrien fprintf (file, "\tadd\t%s, %s, %s\n", sp_str, t1_str, sp_str); 750950397Sobrien 751050397Sobrien else if (size > 0) 751190075Sobrien fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, (int) size, sp_str); 751250397Sobrien 751350397Sobrien else 751450397Sobrien fprintf (file, "\tnop\n"); 751550397Sobrien } 751650397Sobrien 751750397Sobrien /* Reset state info for each function. */ 751850397Sobrien current_frame_info = zero_frame_info; 751952284Sobrien 752052284Sobrien sparc_output_deferred_case_vectors (); 752150397Sobrien} 752250397Sobrien 752350397Sobrien/* Define the number of delay slots needed for the function epilogue. 752450397Sobrien 752550397Sobrien On the sparc, we need a slot if either no stack has been allocated, 752650397Sobrien or the only register saved is the return register. */ 752750397Sobrien 752850397Sobrienint 752950397Sobriensparc_flat_epilogue_delay_slots () 753050397Sobrien{ 753150397Sobrien if (!current_frame_info.initialized) 753250397Sobrien (void) sparc_flat_compute_frame_size (get_frame_size ()); 753350397Sobrien 753450397Sobrien if (current_frame_info.total_size == 0) 753550397Sobrien return 1; 753650397Sobrien 753750397Sobrien return 0; 753850397Sobrien} 753950397Sobrien 754090075Sobrien/* Return true if TRIAL is a valid insn for the epilogue delay slot. 754150397Sobrien Any single length instruction which doesn't reference the stack or frame 754250397Sobrien pointer is OK. */ 754350397Sobrien 754450397Sobrienint 754550397Sobriensparc_flat_eligible_for_epilogue_delay (trial, slot) 754650397Sobrien rtx trial; 754750397Sobrien int slot ATTRIBUTE_UNUSED; 754850397Sobrien{ 754950397Sobrien rtx pat = PATTERN (trial); 755050397Sobrien 755150397Sobrien if (get_attr_length (trial) != 1) 755250397Sobrien return 0; 755350397Sobrien 755450397Sobrien if (! reg_mentioned_p (stack_pointer_rtx, pat) 755550397Sobrien && ! reg_mentioned_p (frame_pointer_rtx, pat)) 755650397Sobrien return 1; 755750397Sobrien 755850397Sobrien return 0; 755950397Sobrien} 756050397Sobrien 756150397Sobrien/* Adjust the cost of a scheduling dependency. Return the new cost of 756250397Sobrien a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ 756350397Sobrien 756452284Sobrienstatic int 756550397Sobriensupersparc_adjust_cost (insn, link, dep_insn, cost) 756650397Sobrien rtx insn; 756750397Sobrien rtx link; 756850397Sobrien rtx dep_insn; 756950397Sobrien int cost; 757050397Sobrien{ 757150397Sobrien enum attr_type insn_type; 757250397Sobrien 757350397Sobrien if (! recog_memoized (insn)) 757450397Sobrien return 0; 757550397Sobrien 757650397Sobrien insn_type = get_attr_type (insn); 757750397Sobrien 757850397Sobrien if (REG_NOTE_KIND (link) == 0) 757950397Sobrien { 758050397Sobrien /* Data dependency; DEP_INSN writes a register that INSN reads some 758150397Sobrien cycles later. */ 758250397Sobrien 758350397Sobrien /* if a load, then the dependence must be on the memory address; 758452284Sobrien add an extra "cycle". Note that the cost could be two cycles 758552284Sobrien if the reg was written late in an instruction group; we ca not tell 758650397Sobrien here. */ 758750397Sobrien if (insn_type == TYPE_LOAD || insn_type == TYPE_FPLOAD) 758850397Sobrien return cost + 3; 758950397Sobrien 759050397Sobrien /* Get the delay only if the address of the store is the dependence. */ 759150397Sobrien if (insn_type == TYPE_STORE || insn_type == TYPE_FPSTORE) 759250397Sobrien { 759350397Sobrien rtx pat = PATTERN(insn); 759450397Sobrien rtx dep_pat = PATTERN (dep_insn); 759550397Sobrien 759650397Sobrien if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET) 759752284Sobrien return cost; /* This should not happen! */ 759850397Sobrien 759950397Sobrien /* The dependency between the two instructions was on the data that 760050397Sobrien is being stored. Assume that this implies that the address of the 760150397Sobrien store is not dependent. */ 760250397Sobrien if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat))) 760350397Sobrien return cost; 760450397Sobrien 760550397Sobrien return cost + 3; /* An approximation. */ 760650397Sobrien } 760750397Sobrien 760850397Sobrien /* A shift instruction cannot receive its data from an instruction 760950397Sobrien in the same cycle; add a one cycle penalty. */ 761050397Sobrien if (insn_type == TYPE_SHIFT) 761150397Sobrien return cost + 3; /* Split before cascade into shift. */ 761250397Sobrien } 761350397Sobrien else 761450397Sobrien { 761550397Sobrien /* Anti- or output- dependency; DEP_INSN reads/writes a register that 761650397Sobrien INSN writes some cycles later. */ 761750397Sobrien 761850397Sobrien /* These are only significant for the fpu unit; writing a fp reg before 761950397Sobrien the fpu has finished with it stalls the processor. */ 762050397Sobrien 762150397Sobrien /* Reusing an integer register causes no problems. */ 762250397Sobrien if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT) 762350397Sobrien return 0; 762450397Sobrien } 762550397Sobrien 762650397Sobrien return cost; 762750397Sobrien} 762850397Sobrien 762952284Sobrienstatic int 763052284Sobrienhypersparc_adjust_cost (insn, link, dep_insn, cost) 763152284Sobrien rtx insn; 763252284Sobrien rtx link; 763352284Sobrien rtx dep_insn; 763452284Sobrien int cost; 763552284Sobrien{ 763652284Sobrien enum attr_type insn_type, dep_type; 763752284Sobrien rtx pat = PATTERN(insn); 763852284Sobrien rtx dep_pat = PATTERN (dep_insn); 763952284Sobrien 764052284Sobrien if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0) 764152284Sobrien return cost; 764252284Sobrien 764352284Sobrien insn_type = get_attr_type (insn); 764452284Sobrien dep_type = get_attr_type (dep_insn); 764552284Sobrien 764652284Sobrien switch (REG_NOTE_KIND (link)) 764752284Sobrien { 764852284Sobrien case 0: 764952284Sobrien /* Data dependency; DEP_INSN writes a register that INSN reads some 765052284Sobrien cycles later. */ 765152284Sobrien 765252284Sobrien switch (insn_type) 765352284Sobrien { 765452284Sobrien case TYPE_STORE: 765552284Sobrien case TYPE_FPSTORE: 765690075Sobrien /* Get the delay iff the address of the store is the dependence. */ 765752284Sobrien if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET) 765852284Sobrien return cost; 765952284Sobrien 766052284Sobrien if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat))) 766152284Sobrien return cost; 766252284Sobrien return cost + 3; 766352284Sobrien 766452284Sobrien case TYPE_LOAD: 766552284Sobrien case TYPE_SLOAD: 766652284Sobrien case TYPE_FPLOAD: 766752284Sobrien /* If a load, then the dependence must be on the memory address. If 766852284Sobrien the addresses aren't equal, then it might be a false dependency */ 766952284Sobrien if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE) 767052284Sobrien { 767152284Sobrien if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET 767252284Sobrien || GET_CODE (SET_DEST (dep_pat)) != MEM 767352284Sobrien || GET_CODE (SET_SRC (pat)) != MEM 767452284Sobrien || ! rtx_equal_p (XEXP (SET_DEST (dep_pat), 0), 767552284Sobrien XEXP (SET_SRC (pat), 0))) 767652284Sobrien return cost + 2; 767752284Sobrien 767852284Sobrien return cost + 8; 767952284Sobrien } 768052284Sobrien break; 768152284Sobrien 768252284Sobrien case TYPE_BRANCH: 768352284Sobrien /* Compare to branch latency is 0. There is no benefit from 768452284Sobrien separating compare and branch. */ 768552284Sobrien if (dep_type == TYPE_COMPARE) 768652284Sobrien return 0; 768752284Sobrien /* Floating point compare to branch latency is less than 768852284Sobrien compare to conditional move. */ 768952284Sobrien if (dep_type == TYPE_FPCMP) 769052284Sobrien return cost - 1; 769152284Sobrien break; 769252284Sobrien default: 769352284Sobrien break; 769452284Sobrien } 769552284Sobrien break; 769652284Sobrien 769752284Sobrien case REG_DEP_ANTI: 769890075Sobrien /* Anti-dependencies only penalize the fpu unit. */ 769952284Sobrien if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT) 770052284Sobrien return 0; 770152284Sobrien break; 770252284Sobrien 770352284Sobrien default: 770452284Sobrien break; 770552284Sobrien } 770652284Sobrien 770752284Sobrien return cost; 770852284Sobrien} 770952284Sobrien 771052284Sobrienstatic int 771152284Sobriensparc_adjust_cost(insn, link, dep, cost) 771252284Sobrien rtx insn; 771352284Sobrien rtx link; 771452284Sobrien rtx dep; 771552284Sobrien int cost; 771652284Sobrien{ 771752284Sobrien switch (sparc_cpu) 771852284Sobrien { 771952284Sobrien case PROCESSOR_SUPERSPARC: 772052284Sobrien cost = supersparc_adjust_cost (insn, link, dep, cost); 772152284Sobrien break; 772252284Sobrien case PROCESSOR_HYPERSPARC: 772352284Sobrien case PROCESSOR_SPARCLITE86X: 772452284Sobrien cost = hypersparc_adjust_cost (insn, link, dep, cost); 772552284Sobrien break; 772652284Sobrien default: 772752284Sobrien break; 772852284Sobrien } 772952284Sobrien return cost; 773052284Sobrien} 773152284Sobrien 773252284Sobrienstatic void 773390075Sobriensparc_sched_init (dump, sched_verbose, max_ready) 773490075Sobrien FILE *dump ATTRIBUTE_UNUSED; 773590075Sobrien int sched_verbose ATTRIBUTE_UNUSED; 773690075Sobrien int max_ready ATTRIBUTE_UNUSED; 773790075Sobrien{ 773890075Sobrien} 773990075Sobrien 774090075Sobrienstatic int 7741117395Skansparc_use_dfa_pipeline_interface () 774252284Sobrien{ 7743117395Skan if ((1 << sparc_cpu) & 7744117395Skan ((1 << PROCESSOR_ULTRASPARC) | (1 << PROCESSOR_CYPRESS) | 7745117395Skan (1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) | 7746117395Skan (1 << PROCESSOR_SPARCLITE86X) | (1 << PROCESSOR_TSC701) | 7747117395Skan (1 << PROCESSOR_ULTRASPARC3))) 7748117395Skan return 1; 7749117395Skan return 0; 775052284Sobrien} 775152284Sobrien 775290075Sobrienstatic int 7753117395Skansparc_use_sched_lookahead () 775490075Sobrien{ 7755117395Skan if (sparc_cpu == PROCESSOR_ULTRASPARC 7756117395Skan || sparc_cpu == PROCESSOR_ULTRASPARC3) 7757117395Skan return 4; 7758117395Skan if ((1 << sparc_cpu) & 7759117395Skan ((1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) | 7760117395Skan (1 << PROCESSOR_SPARCLITE86X))) 7761117395Skan return 3; 7762117395Skan return 0; 776390075Sobrien} 776490075Sobrien 776590075Sobrienstatic int 776650397Sobriensparc_issue_rate () 776750397Sobrien{ 776850397Sobrien switch (sparc_cpu) 776950397Sobrien { 7770117395Skan default: 7771117395Skan return 1; 7772117395Skan case PROCESSOR_V9: 777350397Sobrien /* Assume V9 processors are capable of at least dual-issue. */ 777450397Sobrien return 2; 7775117395Skan case PROCESSOR_SUPERSPARC: 7776117395Skan return 3; 777752284Sobrien case PROCESSOR_HYPERSPARC: 777852284Sobrien case PROCESSOR_SPARCLITE86X: 777952284Sobrien return 2; 7780117395Skan case PROCESSOR_ULTRASPARC: 7781117395Skan case PROCESSOR_ULTRASPARC3: 7782117395Skan return 4; 778350397Sobrien } 778450397Sobrien} 778550397Sobrien 778650397Sobrienstatic int 778790075Sobrienset_extends (insn) 778890075Sobrien rtx insn; 778950397Sobrien{ 779050397Sobrien register rtx pat = PATTERN (insn); 779150397Sobrien 779250397Sobrien switch (GET_CODE (SET_SRC (pat))) 779350397Sobrien { 779490075Sobrien /* Load and some shift instructions zero extend. */ 779550397Sobrien case MEM: 779650397Sobrien case ZERO_EXTEND: 779750397Sobrien /* sethi clears the high bits */ 779850397Sobrien case HIGH: 779950397Sobrien /* LO_SUM is used with sethi. sethi cleared the high 780050397Sobrien bits and the values used with lo_sum are positive */ 780150397Sobrien case LO_SUM: 780250397Sobrien /* Store flag stores 0 or 1 */ 780350397Sobrien case LT: case LTU: 780450397Sobrien case GT: case GTU: 780550397Sobrien case LE: case LEU: 780650397Sobrien case GE: case GEU: 780750397Sobrien case EQ: 780850397Sobrien case NE: 780950397Sobrien return 1; 781050397Sobrien case AND: 781150397Sobrien { 781290075Sobrien rtx op0 = XEXP (SET_SRC (pat), 0); 781350397Sobrien rtx op1 = XEXP (SET_SRC (pat), 1); 781450397Sobrien if (GET_CODE (op1) == CONST_INT) 781550397Sobrien return INTVAL (op1) >= 0; 781690075Sobrien if (GET_CODE (op0) != REG) 781790075Sobrien return 0; 781890075Sobrien if (sparc_check_64 (op0, insn) == 1) 781950397Sobrien return 1; 782090075Sobrien return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1); 782150397Sobrien } 782290075Sobrien case IOR: 782390075Sobrien case XOR: 782490075Sobrien { 782590075Sobrien rtx op0 = XEXP (SET_SRC (pat), 0); 782690075Sobrien rtx op1 = XEXP (SET_SRC (pat), 1); 782790075Sobrien if (GET_CODE (op0) != REG || sparc_check_64 (op0, insn) <= 0) 782890075Sobrien return 0; 782990075Sobrien if (GET_CODE (op1) == CONST_INT) 783090075Sobrien return INTVAL (op1) >= 0; 783190075Sobrien return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1); 783290075Sobrien } 783350397Sobrien case LSHIFTRT: 783450397Sobrien return GET_MODE (SET_SRC (pat)) == SImode; 783590075Sobrien /* Positive integers leave the high bits zero. */ 783650397Sobrien case CONST_DOUBLE: 783790075Sobrien return ! (CONST_DOUBLE_LOW (SET_SRC (pat)) & 0x80000000); 783850397Sobrien case CONST_INT: 783990075Sobrien return ! (INTVAL (SET_SRC (pat)) & 0x80000000); 784050397Sobrien case ASHIFTRT: 784150397Sobrien case SIGN_EXTEND: 784250397Sobrien return - (GET_MODE (SET_SRC (pat)) == SImode); 784390075Sobrien case REG: 784490075Sobrien return sparc_check_64 (SET_SRC (pat), insn); 784550397Sobrien default: 784650397Sobrien return 0; 784750397Sobrien } 784850397Sobrien} 784950397Sobrien 785090075Sobrien/* We _ought_ to have only one kind per function, but... */ 7851117395Skanstatic GTY(()) rtx sparc_addr_diff_list; 7852117395Skanstatic GTY(()) rtx sparc_addr_list; 785352284Sobrien 785452284Sobrienvoid 785552284Sobriensparc_defer_case_vector (lab, vec, diff) 785652284Sobrien rtx lab, vec; 785752284Sobrien int diff; 785852284Sobrien{ 785952284Sobrien vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec); 786052284Sobrien if (diff) 786152284Sobrien sparc_addr_diff_list 786252284Sobrien = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_diff_list); 786352284Sobrien else 786452284Sobrien sparc_addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_list); 786552284Sobrien} 786652284Sobrien 786752284Sobrienstatic void 786852284Sobriensparc_output_addr_vec (vec) 786952284Sobrien rtx vec; 787052284Sobrien{ 787152284Sobrien rtx lab = XEXP (vec, 0), body = XEXP (vec, 1); 787252284Sobrien int idx, vlen = XVECLEN (body, 0); 787352284Sobrien 787452284Sobrien#ifdef ASM_OUTPUT_ADDR_VEC_START 787552284Sobrien ASM_OUTPUT_ADDR_VEC_START (asm_out_file); 787652284Sobrien#endif 787752284Sobrien 787852284Sobrien#ifdef ASM_OUTPUT_CASE_LABEL 787952284Sobrien ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab), 788052284Sobrien NEXT_INSN (lab)); 788152284Sobrien#else 788252284Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab)); 788352284Sobrien#endif 788452284Sobrien 788552284Sobrien for (idx = 0; idx < vlen; idx++) 788652284Sobrien { 788752284Sobrien ASM_OUTPUT_ADDR_VEC_ELT 788852284Sobrien (asm_out_file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); 788952284Sobrien } 789052284Sobrien 789152284Sobrien#ifdef ASM_OUTPUT_ADDR_VEC_END 789252284Sobrien ASM_OUTPUT_ADDR_VEC_END (asm_out_file); 789352284Sobrien#endif 789452284Sobrien} 789552284Sobrien 789652284Sobrienstatic void 789752284Sobriensparc_output_addr_diff_vec (vec) 789852284Sobrien rtx vec; 789952284Sobrien{ 790052284Sobrien rtx lab = XEXP (vec, 0), body = XEXP (vec, 1); 790152284Sobrien rtx base = XEXP (XEXP (body, 0), 0); 790252284Sobrien int idx, vlen = XVECLEN (body, 1); 790352284Sobrien 790452284Sobrien#ifdef ASM_OUTPUT_ADDR_VEC_START 790552284Sobrien ASM_OUTPUT_ADDR_VEC_START (asm_out_file); 790652284Sobrien#endif 790752284Sobrien 790852284Sobrien#ifdef ASM_OUTPUT_CASE_LABEL 790952284Sobrien ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab), 791052284Sobrien NEXT_INSN (lab)); 791152284Sobrien#else 791252284Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab)); 791352284Sobrien#endif 791452284Sobrien 791552284Sobrien for (idx = 0; idx < vlen; idx++) 791652284Sobrien { 791752284Sobrien ASM_OUTPUT_ADDR_DIFF_ELT 791852284Sobrien (asm_out_file, 791952284Sobrien body, 792052284Sobrien CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), 792152284Sobrien CODE_LABEL_NUMBER (base)); 792252284Sobrien } 792352284Sobrien 792452284Sobrien#ifdef ASM_OUTPUT_ADDR_VEC_END 792552284Sobrien ASM_OUTPUT_ADDR_VEC_END (asm_out_file); 792652284Sobrien#endif 792752284Sobrien} 792852284Sobrien 792952284Sobrienstatic void 793052284Sobriensparc_output_deferred_case_vectors () 793152284Sobrien{ 793252284Sobrien rtx t; 793352284Sobrien int align; 793452284Sobrien 793552284Sobrien if (sparc_addr_list == NULL_RTX 793652284Sobrien && sparc_addr_diff_list == NULL_RTX) 793752284Sobrien return; 793852284Sobrien 793952284Sobrien /* Align to cache line in the function's code section. */ 794052284Sobrien function_section (current_function_decl); 794152284Sobrien 794252284Sobrien align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); 794352284Sobrien if (align > 0) 794452284Sobrien ASM_OUTPUT_ALIGN (asm_out_file, align); 794552284Sobrien 794652284Sobrien for (t = sparc_addr_list; t ; t = XEXP (t, 1)) 794752284Sobrien sparc_output_addr_vec (XEXP (t, 0)); 794852284Sobrien for (t = sparc_addr_diff_list; t ; t = XEXP (t, 1)) 794952284Sobrien sparc_output_addr_diff_vec (XEXP (t, 0)); 795052284Sobrien 795152284Sobrien sparc_addr_list = sparc_addr_diff_list = NULL_RTX; 795252284Sobrien} 795352284Sobrien 795450397Sobrien/* Return 0 if the high 32 bits of X (the low word of X, if DImode) are 795550397Sobrien unknown. Return 1 if the high bits are zero, -1 if the register is 795650397Sobrien sign extended. */ 795750397Sobrienint 795850397Sobriensparc_check_64 (x, insn) 795950397Sobrien rtx x, insn; 796050397Sobrien{ 796150397Sobrien /* If a register is set only once it is safe to ignore insns this 796250397Sobrien code does not know how to handle. The loop will either recognize 796350397Sobrien the single set and return the correct value or fail to recognize 796450397Sobrien it and return 0. */ 796550397Sobrien int set_once = 0; 796690075Sobrien rtx y = x; 796750397Sobrien 796890075Sobrien if (GET_CODE (x) != REG) 796990075Sobrien abort (); 797090075Sobrien 797190075Sobrien if (GET_MODE (x) == DImode) 797290075Sobrien y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN); 797390075Sobrien 797490075Sobrien if (flag_expensive_optimizations 797590075Sobrien && REG_N_SETS (REGNO (y)) == 1) 797650397Sobrien set_once = 1; 797750397Sobrien 797850397Sobrien if (insn == 0) 797950397Sobrien { 798050397Sobrien if (set_once) 798150397Sobrien insn = get_last_insn_anywhere (); 798250397Sobrien else 798350397Sobrien return 0; 798450397Sobrien } 798550397Sobrien 798650397Sobrien while ((insn = PREV_INSN (insn))) 798750397Sobrien { 798850397Sobrien switch (GET_CODE (insn)) 798950397Sobrien { 799050397Sobrien case JUMP_INSN: 799150397Sobrien case NOTE: 799250397Sobrien break; 799350397Sobrien case CODE_LABEL: 799450397Sobrien case CALL_INSN: 799550397Sobrien default: 799650397Sobrien if (! set_once) 799750397Sobrien return 0; 799850397Sobrien break; 799950397Sobrien case INSN: 800050397Sobrien { 800150397Sobrien rtx pat = PATTERN (insn); 800250397Sobrien if (GET_CODE (pat) != SET) 800350397Sobrien return 0; 800450397Sobrien if (rtx_equal_p (x, SET_DEST (pat))) 800590075Sobrien return set_extends (insn); 800690075Sobrien if (y && rtx_equal_p (y, SET_DEST (pat))) 800790075Sobrien return set_extends (insn); 800890075Sobrien if (reg_overlap_mentioned_p (SET_DEST (pat), y)) 800950397Sobrien return 0; 801050397Sobrien } 801150397Sobrien } 801250397Sobrien } 801350397Sobrien return 0; 801450397Sobrien} 801550397Sobrien 8016117395Skan/* Returns assembly code to perform a DImode shift using 8017117395Skan a 64-bit global or out register on SPARC-V8+. */ 801850397Sobrienchar * 801950397Sobriensparc_v8plus_shift (operands, insn, opcode) 802050397Sobrien rtx *operands; 802150397Sobrien rtx insn; 802290075Sobrien const char *opcode; 802350397Sobrien{ 802450397Sobrien static char asm_code[60]; 802550397Sobrien 8026117395Skan /* The scratch register is only required when the destination 8027117395Skan register is not a 64-bit global or out register. */ 8028117395Skan if (which_alternative != 2) 802950397Sobrien operands[3] = operands[0]; 8030117395Skan 803150397Sobrien if (GET_CODE (operands[1]) == CONST_INT) 803250397Sobrien { 803390075Sobrien output_asm_insn ("mov\t%1, %3", operands); 803450397Sobrien } 803550397Sobrien else 803650397Sobrien { 803790075Sobrien output_asm_insn ("sllx\t%H1, 32, %3", operands); 803850397Sobrien if (sparc_check_64 (operands[1], insn) <= 0) 803990075Sobrien output_asm_insn ("srl\t%L1, 0, %L1", operands); 804090075Sobrien output_asm_insn ("or\t%L1, %3, %3", operands); 804150397Sobrien } 804250397Sobrien 804350397Sobrien strcpy(asm_code, opcode); 8044117395Skan 804550397Sobrien if (which_alternative != 2) 804690075Sobrien return strcat (asm_code, "\t%0, %2, %L0\n\tsrlx\t%L0, 32, %H0"); 804750397Sobrien else 804890075Sobrien return strcat (asm_code, "\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0"); 804950397Sobrien} 805052284Sobrien 805196263Sobrien/* Output rtl to increment the profiler label LABELNO 805296263Sobrien for profiling a function entry. */ 805352284Sobrien 805452284Sobrienvoid 805596263Sobriensparc_profile_hook (labelno) 805652284Sobrien int labelno; 805752284Sobrien{ 805852284Sobrien char buf[32]; 805996263Sobrien rtx lab, fun; 806096263Sobrien 806152284Sobrien ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno); 806296263Sobrien lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); 806396263Sobrien fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_FUNCTION); 806452284Sobrien 806596263Sobrien emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode); 806652284Sobrien} 806796263Sobrien 806890075Sobrien#ifdef OBJECT_FORMAT_ELF 806990075Sobrienstatic void 807090075Sobriensparc_elf_asm_named_section (name, flags) 807190075Sobrien const char *name; 807290075Sobrien unsigned int flags; 807352284Sobrien{ 807490075Sobrien if (flags & SECTION_MERGE) 807552284Sobrien { 807690075Sobrien /* entsize cannot be expressed in this section attributes 807790075Sobrien encoding style. */ 807890075Sobrien default_elf_asm_named_section (name, flags); 807990075Sobrien return; 808052284Sobrien } 808152284Sobrien 808290075Sobrien fprintf (asm_out_file, "\t.section\t\"%s\"", name); 808352284Sobrien 808490075Sobrien if (!(flags & SECTION_DEBUG)) 808590075Sobrien fputs (",#alloc", asm_out_file); 808690075Sobrien if (flags & SECTION_WRITE) 808790075Sobrien fputs (",#write", asm_out_file); 808890075Sobrien if (flags & SECTION_CODE) 808990075Sobrien fputs (",#execinstr", asm_out_file); 809052284Sobrien 809190075Sobrien /* ??? Handle SECTION_BSS. */ 809252284Sobrien 809390075Sobrien fputc ('\n', asm_out_file); 809452284Sobrien} 809590075Sobrien#endif /* OBJECT_FORMAT_ELF */ 809696263Sobrien 8097117395Skan/* ??? Similar to the standard section selection, but force reloc-y-ness 8098117395Skan if SUNOS4_SHARED_LIBRARIES. Unclear why this helps (as opposed to 8099117395Skan pretending PIC always on), but that's what the old code did. */ 8100117395Skan 8101117395Skanstatic void 8102117395Skansparc_aout_select_section (t, reloc, align) 8103117395Skan tree t; 8104117395Skan int reloc; 8105117395Skan unsigned HOST_WIDE_INT align; 8106117395Skan{ 8107117395Skan default_select_section (t, reloc | SUNOS4_SHARED_LIBRARIES, align); 8108117395Skan} 8109117395Skan 8110117395Skan/* Use text section for a constant unless we need more alignment than 8111117395Skan that offers. */ 8112117395Skan 8113117395Skanstatic void 8114117395Skansparc_aout_select_rtx_section (mode, x, align) 8115117395Skan enum machine_mode mode; 8116117395Skan rtx x; 8117117395Skan unsigned HOST_WIDE_INT align; 8118117395Skan{ 8119117395Skan if (align <= MAX_TEXT_ALIGN 8120117395Skan && ! (flag_pic && (symbolic_operand (x, mode) 8121117395Skan || SUNOS4_SHARED_LIBRARIES))) 8122117395Skan readonly_data_section (); 8123117395Skan else 8124117395Skan data_section (); 8125117395Skan} 8126117395Skan 812796263Sobrienint 812896263Sobriensparc_extra_constraint_check (op, c, strict) 812996263Sobrien rtx op; 813096263Sobrien int c; 813196263Sobrien int strict; 813296263Sobrien{ 813396263Sobrien int reload_ok_mem; 813496263Sobrien 813596263Sobrien if (TARGET_ARCH64 813696263Sobrien && (c == 'T' || c == 'U')) 813796263Sobrien return 0; 813896263Sobrien 813996263Sobrien switch (c) 814096263Sobrien { 814196263Sobrien case 'Q': 814296263Sobrien return fp_sethi_p (op); 814396263Sobrien 814496263Sobrien case 'R': 814596263Sobrien return fp_mov_p (op); 814696263Sobrien 814796263Sobrien case 'S': 814896263Sobrien return fp_high_losum_p (op); 814996263Sobrien 815096263Sobrien case 'U': 815196263Sobrien if (! strict 815296263Sobrien || (GET_CODE (op) == REG 815396263Sobrien && (REGNO (op) < FIRST_PSEUDO_REGISTER 815496263Sobrien || reg_renumber[REGNO (op)] >= 0))) 815596263Sobrien return register_ok_for_ldd (op); 815696263Sobrien 815796263Sobrien return 0; 815896263Sobrien 815996263Sobrien case 'W': 816096263Sobrien case 'T': 816196263Sobrien break; 816296263Sobrien 816396263Sobrien default: 816496263Sobrien return 0; 816596263Sobrien } 816696263Sobrien 816796263Sobrien /* Our memory extra constraints have to emulate the 816896263Sobrien behavior of 'm' and 'o' in order for reload to work 816996263Sobrien correctly. */ 817096263Sobrien if (GET_CODE (op) == MEM) 817196263Sobrien { 817296263Sobrien reload_ok_mem = 0; 817396263Sobrien if ((TARGET_ARCH64 || mem_min_alignment (op, 8)) 817496263Sobrien && (! strict 817596263Sobrien || strict_memory_address_p (Pmode, XEXP (op, 0)))) 817696263Sobrien reload_ok_mem = 1; 817796263Sobrien } 817896263Sobrien else 817996263Sobrien { 818096263Sobrien reload_ok_mem = (reload_in_progress 818196263Sobrien && GET_CODE (op) == REG 818296263Sobrien && REGNO (op) >= FIRST_PSEUDO_REGISTER 818396263Sobrien && reg_renumber [REGNO (op)] < 0); 818496263Sobrien } 818596263Sobrien 818696263Sobrien return reload_ok_mem; 818796263Sobrien} 8188102780Skan 8189117395Skan/* ??? This duplicates information provided to the compiler by the 8190117395Skan ??? scheduler description. Some day, teach genautomata to output 8191117395Skan ??? the latencies and then CSE will just use that. */ 8192117395Skan 8193117395Skanint 8194117395Skansparc_rtx_costs (x, code, outer_code) 8195117395Skan rtx x; 8196117395Skan enum rtx_code code, outer_code; 8197117395Skan{ 8198117395Skan switch (code) 8199117395Skan { 8200117395Skan case PLUS: case MINUS: case ABS: case NEG: 8201117395Skan case FLOAT: case UNSIGNED_FLOAT: 8202117395Skan case FIX: case UNSIGNED_FIX: 8203117395Skan case FLOAT_EXTEND: case FLOAT_TRUNCATE: 8204117395Skan if (FLOAT_MODE_P (GET_MODE (x))) 8205117395Skan { 8206117395Skan switch (sparc_cpu) 8207117395Skan { 8208117395Skan case PROCESSOR_ULTRASPARC: 8209117395Skan case PROCESSOR_ULTRASPARC3: 8210117395Skan return COSTS_N_INSNS (4); 8211117395Skan 8212117395Skan case PROCESSOR_SUPERSPARC: 8213117395Skan return COSTS_N_INSNS (3); 8214117395Skan 8215117395Skan case PROCESSOR_CYPRESS: 8216117395Skan return COSTS_N_INSNS (5); 8217117395Skan 8218117395Skan case PROCESSOR_HYPERSPARC: 8219117395Skan case PROCESSOR_SPARCLITE86X: 8220117395Skan default: 8221117395Skan return COSTS_N_INSNS (1); 8222117395Skan } 8223117395Skan } 8224117395Skan 8225117395Skan return COSTS_N_INSNS (1); 8226117395Skan 8227117395Skan case SQRT: 8228117395Skan switch (sparc_cpu) 8229117395Skan { 8230117395Skan case PROCESSOR_ULTRASPARC: 8231117395Skan if (GET_MODE (x) == SFmode) 8232117395Skan return COSTS_N_INSNS (13); 8233117395Skan else 8234117395Skan return COSTS_N_INSNS (23); 8235117395Skan 8236117395Skan case PROCESSOR_ULTRASPARC3: 8237117395Skan if (GET_MODE (x) == SFmode) 8238117395Skan return COSTS_N_INSNS (20); 8239117395Skan else 8240117395Skan return COSTS_N_INSNS (29); 8241117395Skan 8242117395Skan case PROCESSOR_SUPERSPARC: 8243117395Skan return COSTS_N_INSNS (12); 8244117395Skan 8245117395Skan case PROCESSOR_CYPRESS: 8246117395Skan return COSTS_N_INSNS (63); 8247117395Skan 8248117395Skan case PROCESSOR_HYPERSPARC: 8249117395Skan case PROCESSOR_SPARCLITE86X: 8250117395Skan return COSTS_N_INSNS (17); 8251117395Skan 8252117395Skan default: 8253117395Skan return COSTS_N_INSNS (30); 8254117395Skan } 8255117395Skan 8256117395Skan case COMPARE: 8257117395Skan if (FLOAT_MODE_P (GET_MODE (x))) 8258117395Skan { 8259117395Skan switch (sparc_cpu) 8260117395Skan { 8261117395Skan case PROCESSOR_ULTRASPARC: 8262117395Skan case PROCESSOR_ULTRASPARC3: 8263117395Skan return COSTS_N_INSNS (1); 8264117395Skan 8265117395Skan case PROCESSOR_SUPERSPARC: 8266117395Skan return COSTS_N_INSNS (3); 8267117395Skan 8268117395Skan case PROCESSOR_CYPRESS: 8269117395Skan return COSTS_N_INSNS (5); 8270117395Skan 8271117395Skan case PROCESSOR_HYPERSPARC: 8272117395Skan case PROCESSOR_SPARCLITE86X: 8273117395Skan default: 8274117395Skan return COSTS_N_INSNS (1); 8275117395Skan } 8276117395Skan } 8277117395Skan 8278117395Skan /* ??? Maybe mark integer compares as zero cost on 8279117395Skan ??? all UltraSPARC processors because the result 8280117395Skan ??? can be bypassed to a branch in the same group. */ 8281117395Skan 8282117395Skan return COSTS_N_INSNS (1); 8283117395Skan 8284117395Skan case MULT: 8285117395Skan if (FLOAT_MODE_P (GET_MODE (x))) 8286117395Skan { 8287117395Skan switch (sparc_cpu) 8288117395Skan { 8289117395Skan case PROCESSOR_ULTRASPARC: 8290117395Skan case PROCESSOR_ULTRASPARC3: 8291117395Skan return COSTS_N_INSNS (4); 8292117395Skan 8293117395Skan case PROCESSOR_SUPERSPARC: 8294117395Skan return COSTS_N_INSNS (3); 8295117395Skan 8296117395Skan case PROCESSOR_CYPRESS: 8297117395Skan return COSTS_N_INSNS (7); 8298117395Skan 8299117395Skan case PROCESSOR_HYPERSPARC: 8300117395Skan case PROCESSOR_SPARCLITE86X: 8301117395Skan return COSTS_N_INSNS (1); 8302117395Skan 8303117395Skan default: 8304117395Skan return COSTS_N_INSNS (5); 8305117395Skan } 8306117395Skan } 8307117395Skan 8308117395Skan /* The latency is actually variable for Ultra-I/II 8309117395Skan And if one of the inputs have a known constant 8310117395Skan value, we could calculate this precisely. 8311117395Skan 8312117395Skan However, for that to be useful we would need to 8313117395Skan add some machine description changes which would 8314117395Skan make sure small constants ended up in rs1 of the 8315117395Skan multiply instruction. This is because the multiply 8316117395Skan latency is determined by the number of clear (or 8317117395Skan set if the value is negative) bits starting from 8318117395Skan the most significant bit of the first input. 8319117395Skan 8320117395Skan The algorithm for computing num_cycles of a multiply 8321117395Skan on Ultra-I/II is: 8322117395Skan 8323117395Skan if (rs1 < 0) 8324117395Skan highest_bit = highest_clear_bit(rs1); 8325117395Skan else 8326117395Skan highest_bit = highest_set_bit(rs1); 8327117395Skan if (num_bits < 3) 8328117395Skan highest_bit = 3; 8329117395Skan num_cycles = 4 + ((highest_bit - 3) / 2); 8330117395Skan 8331117395Skan If we did that we would have to also consider register 8332117395Skan allocation issues that would result from forcing such 8333117395Skan a value into a register. 8334117395Skan 8335117395Skan There are other similar tricks we could play if we 8336117395Skan knew, for example, that one input was an array index. 8337117395Skan 8338117395Skan Since we do not play any such tricks currently the 8339117395Skan safest thing to do is report the worst case latency. */ 8340117395Skan if (sparc_cpu == PROCESSOR_ULTRASPARC) 8341117395Skan return (GET_MODE (x) == DImode ? 8342117395Skan COSTS_N_INSNS (34) : COSTS_N_INSNS (19)); 8343117395Skan 8344117395Skan /* Multiply latency on Ultra-III, fortunately, is constant. */ 8345117395Skan if (sparc_cpu == PROCESSOR_ULTRASPARC3) 8346117395Skan return COSTS_N_INSNS (6); 8347117395Skan 8348117395Skan if (sparc_cpu == PROCESSOR_HYPERSPARC 8349117395Skan || sparc_cpu == PROCESSOR_SPARCLITE86X) 8350117395Skan return COSTS_N_INSNS (17); 8351117395Skan 8352117395Skan return (TARGET_HARD_MUL 8353117395Skan ? COSTS_N_INSNS (5) 8354117395Skan : COSTS_N_INSNS (25)); 8355117395Skan 8356117395Skan case DIV: 8357117395Skan case UDIV: 8358117395Skan case MOD: 8359117395Skan case UMOD: 8360117395Skan if (FLOAT_MODE_P (GET_MODE (x))) 8361117395Skan { 8362117395Skan switch (sparc_cpu) 8363117395Skan { 8364117395Skan case PROCESSOR_ULTRASPARC: 8365117395Skan if (GET_MODE (x) == SFmode) 8366117395Skan return COSTS_N_INSNS (13); 8367117395Skan else 8368117395Skan return COSTS_N_INSNS (23); 8369117395Skan 8370117395Skan case PROCESSOR_ULTRASPARC3: 8371117395Skan if (GET_MODE (x) == SFmode) 8372117395Skan return COSTS_N_INSNS (17); 8373117395Skan else 8374117395Skan return COSTS_N_INSNS (20); 8375117395Skan 8376117395Skan case PROCESSOR_SUPERSPARC: 8377117395Skan if (GET_MODE (x) == SFmode) 8378117395Skan return COSTS_N_INSNS (6); 8379117395Skan else 8380117395Skan return COSTS_N_INSNS (9); 8381117395Skan 8382117395Skan case PROCESSOR_HYPERSPARC: 8383117395Skan case PROCESSOR_SPARCLITE86X: 8384117395Skan if (GET_MODE (x) == SFmode) 8385117395Skan return COSTS_N_INSNS (8); 8386117395Skan else 8387117395Skan return COSTS_N_INSNS (12); 8388117395Skan 8389117395Skan default: 8390117395Skan return COSTS_N_INSNS (7); 8391117395Skan } 8392117395Skan } 8393117395Skan 8394117395Skan if (sparc_cpu == PROCESSOR_ULTRASPARC) 8395117395Skan return (GET_MODE (x) == DImode ? 8396117395Skan COSTS_N_INSNS (68) : COSTS_N_INSNS (37)); 8397117395Skan if (sparc_cpu == PROCESSOR_ULTRASPARC3) 8398117395Skan return (GET_MODE (x) == DImode ? 8399117395Skan COSTS_N_INSNS (71) : COSTS_N_INSNS (40)); 8400117395Skan return COSTS_N_INSNS (25); 8401117395Skan 8402117395Skan case IF_THEN_ELSE: 8403117395Skan /* Conditional moves. */ 8404117395Skan switch (sparc_cpu) 8405117395Skan { 8406117395Skan case PROCESSOR_ULTRASPARC: 8407117395Skan return COSTS_N_INSNS (2); 8408117395Skan 8409117395Skan case PROCESSOR_ULTRASPARC3: 8410117395Skan if (FLOAT_MODE_P (GET_MODE (x))) 8411117395Skan return COSTS_N_INSNS (3); 8412117395Skan else 8413117395Skan return COSTS_N_INSNS (2); 8414117395Skan 8415117395Skan default: 8416117395Skan return COSTS_N_INSNS (1); 8417117395Skan } 8418117395Skan 8419117395Skan case MEM: 8420117395Skan /* If outer-code is SIGN/ZERO extension we have to subtract 8421117395Skan out COSTS_N_INSNS (1) from whatever we return in determining 8422117395Skan the cost. */ 8423117395Skan switch (sparc_cpu) 8424117395Skan { 8425117395Skan case PROCESSOR_ULTRASPARC: 8426117395Skan if (outer_code == ZERO_EXTEND) 8427117395Skan return COSTS_N_INSNS (1); 8428117395Skan else 8429117395Skan return COSTS_N_INSNS (2); 8430117395Skan 8431117395Skan case PROCESSOR_ULTRASPARC3: 8432117395Skan if (outer_code == ZERO_EXTEND) 8433117395Skan { 8434117395Skan if (GET_MODE (x) == QImode 8435117395Skan || GET_MODE (x) == HImode 8436117395Skan || outer_code == SIGN_EXTEND) 8437117395Skan return COSTS_N_INSNS (2); 8438117395Skan else 8439117395Skan return COSTS_N_INSNS (1); 8440117395Skan } 8441117395Skan else 8442117395Skan { 8443117395Skan /* This handles sign extension (3 cycles) 8444117395Skan and everything else (2 cycles). */ 8445117395Skan return COSTS_N_INSNS (2); 8446117395Skan } 8447117395Skan 8448117395Skan case PROCESSOR_SUPERSPARC: 8449117395Skan if (FLOAT_MODE_P (GET_MODE (x)) 8450117395Skan || outer_code == ZERO_EXTEND 8451117395Skan || outer_code == SIGN_EXTEND) 8452117395Skan return COSTS_N_INSNS (0); 8453117395Skan else 8454117395Skan return COSTS_N_INSNS (1); 8455117395Skan 8456117395Skan case PROCESSOR_TSC701: 8457117395Skan if (outer_code == ZERO_EXTEND 8458117395Skan || outer_code == SIGN_EXTEND) 8459117395Skan return COSTS_N_INSNS (2); 8460117395Skan else 8461117395Skan return COSTS_N_INSNS (3); 8462117395Skan 8463117395Skan case PROCESSOR_CYPRESS: 8464117395Skan if (outer_code == ZERO_EXTEND 8465117395Skan || outer_code == SIGN_EXTEND) 8466117395Skan return COSTS_N_INSNS (1); 8467117395Skan else 8468117395Skan return COSTS_N_INSNS (2); 8469117395Skan 8470117395Skan case PROCESSOR_HYPERSPARC: 8471117395Skan case PROCESSOR_SPARCLITE86X: 8472117395Skan default: 8473117395Skan if (outer_code == ZERO_EXTEND 8474117395Skan || outer_code == SIGN_EXTEND) 8475117395Skan return COSTS_N_INSNS (0); 8476117395Skan else 8477117395Skan return COSTS_N_INSNS (1); 8478117395Skan } 8479117395Skan 8480117395Skan case CONST_INT: 8481117395Skan if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000) 8482117395Skan return 0; 8483117395Skan 8484117395Skan /* fallthru */ 8485117395Skan case HIGH: 8486117395Skan return 2; 8487117395Skan 8488117395Skan case CONST: 8489117395Skan case LABEL_REF: 8490117395Skan case SYMBOL_REF: 8491117395Skan return 4; 8492117395Skan 8493117395Skan case CONST_DOUBLE: 8494117395Skan if (GET_MODE (x) == DImode) 8495117395Skan if ((XINT (x, 3) == 0 8496117395Skan && (unsigned) XINT (x, 2) < 0x1000) 8497117395Skan || (XINT (x, 3) == -1 8498117395Skan && XINT (x, 2) < 0 8499117395Skan && XINT (x, 2) >= -0x1000)) 8500117395Skan return 0; 8501117395Skan return 8; 8502117395Skan 8503117395Skan default: 8504117395Skan abort(); 8505117395Skan }; 8506117395Skan} 8507117395Skan 8508117395Skan/* If we are referencing a function make the SYMBOL_REF special. In 8509117395Skan the Embedded Medium/Anywhere code model, %g4 points to the data 8510117395Skan segment so we must not add it to function addresses. */ 8511117395Skan 8512117395Skanstatic void 8513117395Skansparc_encode_section_info (decl, first) 8514117395Skan tree decl; 8515117395Skan int first ATTRIBUTE_UNUSED; 8516117395Skan{ 8517117395Skan if (TARGET_CM_EMBMEDANY && TREE_CODE (decl) == FUNCTION_DECL) 8518117395Skan SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1; 8519117395Skan} 8520117395Skan 8521102780Skan/* Output code to add DELTA to the first argument, and then jump to FUNCTION. 8522102780Skan Used for C++ multiple inheritance. */ 8523102780Skan 8524117395Skanstatic void 8525117395Skansparc_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function) 8526102780Skan FILE *file; 8527102780Skan tree thunk_fndecl ATTRIBUTE_UNUSED; 8528102780Skan HOST_WIDE_INT delta; 8529117395Skan HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED; 8530102780Skan tree function; 8531102780Skan{ 8532102780Skan rtx this, insn, funexp, delta_rtx, tmp; 8533102780Skan 8534102780Skan reload_completed = 1; 8535102780Skan no_new_pseudos = 1; 8536102780Skan current_function_uses_only_leaf_regs = 1; 8537102780Skan 8538102780Skan emit_note (NULL, NOTE_INSN_PROLOGUE_END); 8539102780Skan 8540102780Skan /* Find the "this" pointer. Normally in %o0, but in ARCH64 if the function 8541102780Skan returns a structure, the structure return pointer is there instead. */ 8542102780Skan if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) 8543102780Skan this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST + 1); 8544102780Skan else 8545102780Skan this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST); 8546102780Skan 8547102780Skan /* Add DELTA. When possible use a plain add, otherwise load it into 8548102780Skan a register first. */ 8549102780Skan delta_rtx = GEN_INT (delta); 8550102780Skan if (!SPARC_SIMM13_P (delta)) 8551102780Skan { 8552102780Skan rtx scratch = gen_rtx_REG (Pmode, 1); 8553102780Skan if (TARGET_ARCH64) 8554102780Skan sparc_emit_set_const64 (scratch, delta_rtx); 8555102780Skan else 8556102780Skan sparc_emit_set_const32 (scratch, delta_rtx); 8557102780Skan delta_rtx = scratch; 8558102780Skan } 8559102780Skan 8560102780Skan tmp = gen_rtx_PLUS (Pmode, this, delta_rtx); 8561102780Skan emit_insn (gen_rtx_SET (VOIDmode, this, tmp)); 8562102780Skan 8563102780Skan /* Generate a tail call to the target function. */ 8564102780Skan if (! TREE_USED (function)) 8565102780Skan { 8566102780Skan assemble_external (function); 8567102780Skan TREE_USED (function) = 1; 8568102780Skan } 8569102780Skan funexp = XEXP (DECL_RTL (function), 0); 8570102780Skan funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); 8571102780Skan insn = emit_call_insn (gen_sibcall (funexp)); 8572102780Skan SIBLING_CALL_P (insn) = 1; 8573102780Skan emit_barrier (); 8574102780Skan 8575102780Skan /* Run just enough of rest_of_compilation to get the insns emitted. 8576102780Skan There's not really enough bulk here to make other passes such as 8577102780Skan instruction scheduling worth while. Note that use_thunk calls 8578102780Skan assemble_start_function and assemble_end_function. */ 8579102780Skan insn = get_insns (); 8580102780Skan shorten_branches (insn); 8581102780Skan final_start_function (insn, file, 1); 8582102780Skan final (insn, file, 1, 0); 8583102780Skan final_end_function (); 8584102780Skan 8585102780Skan reload_completed = 0; 8586102780Skan no_new_pseudos = 0; 8587102780Skan} 8588117395Skan 8589117395Skan#include "gt-sparc.h" 8590