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				&regno, &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, &regno, &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, &regno, &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