📄 rs6000.c
字号:
/* Subroutines used for code generation on IBM RS/6000. Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */#include "config.h"#include "system.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-attr.h"#include "flags.h"#include "recog.h"#include "obstack.h"#include "tree.h"#include "expr.h"#include "optabs.h"#include "except.h"#include "function.h"#include "output.h"#include "basic-block.h"#include "integrate.h"#include "toplev.h"#include "ggc.h"#include "hashtab.h"#include "tm_p.h"#include "target.h"#include "target-def.h"#include "langhooks.h"#include "reload.h"#ifndef TARGET_NO_PROTOTYPE#define TARGET_NO_PROTOTYPE 0#endif#define min(A,B) ((A) < (B) ? (A) : (B))#define max(A,B) ((A) > (B) ? (A) : (B))/* Target cpu type */enum processor_type rs6000_cpu;struct rs6000_cpu_select rs6000_select[3] ={ /* switch name, tune arch */ { (const char *)0, "--with-cpu=", 1, 1 }, { (const char *)0, "-mcpu=", 1, 1 }, { (const char *)0, "-mtune=", 1, 0 },};/* Size of long double */const char *rs6000_long_double_size_string;int rs6000_long_double_type_size;/* Whether -mabi=altivec has appeared */int rs6000_altivec_abi;/* Whether VRSAVE instructions should be generated. */int rs6000_altivec_vrsave;/* String from -mvrsave= option. */const char *rs6000_altivec_vrsave_string;/* Nonzero if we want SPE ABI extensions. */int rs6000_spe_abi;/* Whether isel instructions should be generated. */int rs6000_isel;/* Nonzero if we have FPRs. */int rs6000_fprs = 1;/* String from -misel=. */const char *rs6000_isel_string;/* Set to nonzero once AIX common-mode calls have been defined. */static int common_mode_defined;/* Private copy of original value of flag_pic for ABI_AIX. */static int rs6000_flag_pic;/* Save information from a "cmpxx" operation until the branch or scc is emitted. */rtx rs6000_compare_op0, rs6000_compare_op1;int rs6000_compare_fp_p;/* Label number of label created for -mrelocatable, to call to so we can get the address of the GOT section */int rs6000_pic_labelno;#ifdef USING_ELFOS_H/* Which abi to adhere to */const char *rs6000_abi_name = RS6000_ABI_NAME;/* Semantics of the small data area */enum rs6000_sdata_type rs6000_sdata = SDATA_DATA;/* Which small data model to use */const char *rs6000_sdata_name = (char *)0;/* Counter for labels which are to be placed in .fixup. */int fixuplabelno = 0;#endif/* ABI enumeration available for subtarget to use. */enum rs6000_abi rs6000_current_abi;/* ABI string from -mabi= option. */const char *rs6000_abi_string;/* Debug flags */const char *rs6000_debug_name;int rs6000_debug_stack; /* debug stack applications */int rs6000_debug_arg; /* debug argument handling */const char *rs6000_traceback_name;static enum { traceback_default = 0, traceback_none, traceback_part, traceback_full} rs6000_traceback;/* Flag to say the TOC is initialized */int toc_initialized;char toc_label_name[10];/* Alias set for saves and restores from the rs6000 stack. */static int rs6000_sr_alias_set;/* Call distance, overridden by -mlongcall and #pragma longcall(1). The only place that looks at this is rs6000_set_default_type_attributes; everywhere else should rely on the presence or absence of a longcall attribute on the function declaration. Exception: init_cumulative_args looks at it too, for libcalls. */int rs6000_default_long_calls;const char *rs6000_longcall_switch;struct builtin_description{ /* mask is not const because we're going to alter it below. This nonsense will go away when we rewrite the -march infrastructure to give us more target flag bits. */ unsigned int mask; const enum insn_code icode; const char *const name; const enum rs6000_builtins code;};static void rs6000_add_gc_roots PARAMS ((void));static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT));static void validate_condition_mode PARAMS ((enum rtx_code, enum machine_mode));static rtx rs6000_generate_compare PARAMS ((enum rtx_code));static void rs6000_maybe_dead PARAMS ((rtx));static void rs6000_emit_stack_tie PARAMS ((void));static void rs6000_frame_related PARAMS ((rtx, rtx, HOST_WIDE_INT, rtx, rtx));static void emit_frame_save PARAMS ((rtx, rtx, enum machine_mode, unsigned int, int, int));static rtx gen_frame_mem_offset PARAMS ((enum machine_mode, rtx, int));static void rs6000_emit_allocate_stack PARAMS ((HOST_WIDE_INT, int));static unsigned rs6000_hash_constant PARAMS ((rtx));static unsigned toc_hash_function PARAMS ((const void *));static int toc_hash_eq PARAMS ((const void *, const void *));static int toc_hash_mark_entry PARAMS ((void **, void *));static void toc_hash_mark_table PARAMS ((void *));static int constant_pool_expr_1 PARAMS ((rtx, int *, int *));static struct machine_function * rs6000_init_machine_status PARAMS ((void));static bool rs6000_assemble_integer PARAMS ((rtx, unsigned int, int));#ifdef HAVE_GAS_HIDDENstatic void rs6000_assemble_visibility PARAMS ((tree, int));#endifstatic int rs6000_ra_ever_killed PARAMS ((void));static tree rs6000_handle_longcall_attribute PARAMS ((tree *, tree, tree, int, bool *));const struct attribute_spec rs6000_attribute_table[];static void rs6000_set_default_type_attributes PARAMS ((tree));static void rs6000_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void rs6000_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static void rs6000_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree));static rtx rs6000_emit_set_long_const PARAMS ((rtx, HOST_WIDE_INT, HOST_WIDE_INT));#if TARGET_ELFstatic unsigned int rs6000_elf_section_type_flags PARAMS ((tree, const char *, int));static void rs6000_elf_asm_out_constructor PARAMS ((rtx, int));static void rs6000_elf_asm_out_destructor PARAMS ((rtx, int));static void rs6000_elf_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT));static void rs6000_elf_unique_section PARAMS ((tree, int));static void rs6000_elf_select_rtx_section PARAMS ((enum machine_mode, rtx, unsigned HOST_WIDE_INT));static void rs6000_elf_encode_section_info PARAMS ((tree, int)) ATTRIBUTE_UNUSED;static const char *rs6000_elf_strip_name_encoding PARAMS ((const char *));static bool rs6000_elf_in_small_data_p PARAMS ((tree));#endif#if TARGET_XCOFFstatic void rs6000_xcoff_asm_globalize_label PARAMS ((FILE *, const char *));static void rs6000_xcoff_asm_named_section PARAMS ((const char *, unsigned int));static void rs6000_xcoff_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT));static void rs6000_xcoff_unique_section PARAMS ((tree, int));static void rs6000_xcoff_select_rtx_section PARAMS ((enum machine_mode, rtx, unsigned HOST_WIDE_INT));static const char * rs6000_xcoff_strip_name_encoding PARAMS ((const char *));static unsigned int rs6000_xcoff_section_type_flags PARAMS ((tree, const char *, int));#endifstatic void rs6000_xcoff_encode_section_info PARAMS ((tree, int)) ATTRIBUTE_UNUSED;static bool rs6000_binds_local_p PARAMS ((tree));static int rs6000_adjust_cost PARAMS ((rtx, rtx, rtx, int));static int rs6000_adjust_priority PARAMS ((rtx, int));static int rs6000_issue_rate PARAMS ((void));static void rs6000_init_builtins PARAMS ((void));static rtx rs6000_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx));static rtx rs6000_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx));static rtx rs6000_expand_ternop_builtin PARAMS ((enum insn_code, tree, rtx));static rtx rs6000_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));static void altivec_init_builtins PARAMS ((void));static void rs6000_common_init_builtins PARAMS ((void));static void enable_mask_for_builtins PARAMS ((struct builtin_description *, int, enum rs6000_builtins, enum rs6000_builtins));static void spe_init_builtins PARAMS ((void));static rtx spe_expand_builtin PARAMS ((tree, rtx, bool *));static rtx spe_expand_predicate_builtin PARAMS ((enum insn_code, tree, rtx));static rtx spe_expand_evsel_builtin PARAMS ((enum insn_code, tree, rtx));static int rs6000_emit_int_cmove PARAMS ((rtx, rtx, rtx, rtx));static rtx altivec_expand_builtin PARAMS ((tree, rtx, bool *));static rtx altivec_expand_ld_builtin PARAMS ((tree, rtx, bool *));static rtx altivec_expand_st_builtin PARAMS ((tree, rtx, bool *));static rtx altivec_expand_dst_builtin PARAMS ((tree, rtx, bool *));static rtx altivec_expand_abs_builtin PARAMS ((enum insn_code, tree, rtx));static rtx altivec_expand_predicate_builtin PARAMS ((enum insn_code, const char *, tree, rtx));static rtx altivec_expand_stv_builtin PARAMS ((enum insn_code, tree));static void rs6000_parse_abi_options PARAMS ((void));static void rs6000_parse_vrsave_option PARAMS ((void));static void rs6000_parse_isel_option PARAMS ((void));static int first_altivec_reg_to_save PARAMS ((void));static unsigned int compute_vrsave_mask PARAMS ((void));static void is_altivec_return_reg PARAMS ((rtx, void *));static rtx generate_set_vrsave PARAMS ((rtx, rs6000_stack_t *, int));static void altivec_frame_fixup PARAMS ((rtx, rtx, HOST_WIDE_INT));static int easy_vector_constant PARAMS ((rtx));/* Default register names. */char rs6000_reg_names[][8] ={ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "mq", "lr", "ctr","ap", "0", "1", "2", "3", "4", "5", "6", "7", "xer", /* AltiVec registers. */ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "vrsave", "vscr", /* SPE registers. */ "spe_acc", "spefscr"};#ifdef TARGET_REGNAMESstatic const char alt_reg_names[][8] ={ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23", "%r24", "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31", "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31", "mq", "lr", "ctr", "ap", "%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7", "xer", /* AltiVec registers. */ "%v0", "%v1", "%v2", "%v3", "%v4", "%v5", "%v6", "%v7", "%v8", "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15", "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31", "vrsave", "vscr", /* SPE registers. */ "spe_acc", "spefscr"};#endif#ifndef MASK_STRICT_ALIGN#define MASK_STRICT_ALIGN 0#endif/* The VRSAVE bitmask puts bit %v0 as the most significant bit. */#define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))/* Initialize the GCC target structure. */#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rs6000_set_default_type_attributes#undef TARGET_ASM_ALIGNED_DI_OP#define TARGET_ASM_ALIGNED_DI_OP DOUBLE_INT_ASM_OP/* Default unaligned ops are only provided for ELF. Find the ops needed for non-ELF systems. */#ifndef OBJECT_FORMAT_ELF#if TARGET_XCOFF/* For XCOFF. rs6000_assemble_integer will handle unaligned DIs on 64-bit targets. */#undef TARGET_ASM_UNALIGNED_HI_OP#define TARGET_ASM_UNALIGNED_HI_OP "\t.vbyte\t2,"#undef TARGET_ASM_UNALIGNED_SI_OP#define TARGET_ASM_UNALIGNED_SI_OP "\t.vbyte\t4,"#undef TARGET_ASM_UNALIGNED_DI_OP#define TARGET_ASM_UNALIGNED_DI_OP "\t.vbyte\t8,"#else/* For Darwin. */#undef TARGET_ASM_UNALIGNED_HI_OP#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"#undef TARGET_ASM_UNALIGNED_SI_OP#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"#endif#endif/* This hook deals with fixups for relocatable code and DI-mode objects in 64-bit code. */#undef TARGET_ASM_INTEGER#define TARGET_ASM_INTEGER rs6000_assemble_integer#ifdef HAVE_GAS_HIDDEN#undef TARGET_ASM_ASSEMBLE_VISIBILITY#define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility#endif#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue#undef TARGET_SCHED_ISSUE_RATE#define TARGET_SCHED_ISSUE_RATE rs6000_issue_rate#undef TARGET_SCHED_ADJUST_COST#define TARGET_SCHED_ADJUST_COST rs6000_adjust_cost#undef TARGET_SCHED_ADJUST_PRIORITY#define TARGET_SCHED_ADJUST_PRIORITY rs6000_adjust_priority#undef TARGET_INIT_BUILTINS#define TARGET_INIT_BUILTINS rs6000_init_builtins#undef TARGET_EXPAND_BUILTIN#define TARGET_EXPAND_BUILTIN rs6000_expand_builtin#undef TARGET_BINDS_LOCAL_P#define TARGET_BINDS_LOCAL_P rs6000_binds_local_p#undef TARGET_ASM_OUTPUT_MI_THUNK#define TARGET_ASM_OUTPUT_MI_THUNK rs6000_output_mi_thunk/* ??? Should work everywhere, but ask dje@watson.ibm.com before enabling for AIX. */#if TARGET_OBJECT_FORMAT != OBJECT_XCOFF#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall#endifstruct gcc_target targetm = TARGET_INITIALIZER;/* Override command line options. Mostly we process the processor type and sometimes adjust other TARGET_ options. */voidrs6000_override_options (default_cpu) const char *default_cpu;{ size_t i, j; struct rs6000_cpu_select *ptr; /* Simplify the entries below by making a mask for any POWER variant and any PowerPC variant. */#define POWER_MASKS (MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING)#define POWERPC_MASKS (MASK_POWERPC | MASK_PPC_GPOPT \ | MASK_PPC_GFXOPT | MASK_POWERPC64)#define POWERPC_OPT_MASKS (MASK_PPC_GPOPT | MASK_PPC_GFXOPT) static struct ptt { const char *const name; /* Canonical processor name. */ const enum processor_type processor; /* Processor type enum value. */ const int target_enable; /* Target flags to enable. */ const int target_disable; /* Target flags to disable. */ } const processor_target_table[] = {{"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_MASKS}, {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING, MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, {"power2", PROCESSOR_POWER, MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING, POWERPC_MASKS | MASK_NEW_MNEMONICS}, {"power3", PROCESSOR_PPC630, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT}, {"power4", PROCESSOR_POWER4, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT}, {"powerpc", PROCESSOR_POWERPC, MASK_POWERPC | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, {"powerpc64", PROCESSOR_POWERPC64, MASK_POWERPC | MASK_POWERPC64 | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS}, {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING, MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING, MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING, MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, {"rsc1", PROCESSOR_PPC601,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -