📄 rs6000.c
字号:
/* Subroutines used for code generation on IBM RS/6000. Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 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;/* Set to non-zero once AIX common-mode calls have been defined. */static int common_mode_defined;/* 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 *//* 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;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 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 void rs6000_free_machine_status PARAMS ((struct function *));static void rs6000_init_machine_status PARAMS ((struct function *));static bool rs6000_assemble_integer PARAMS ((rtx, unsigned int, int));static 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_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void rs6000_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));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));#endif#ifdef OBJECT_FORMAT_COFFstatic void xcoff_asm_named_section PARAMS ((const char *, unsigned int));#endifstatic 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 void altivec_init_builtins PARAMS ((void));static rtx rs6000_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));static rtx altivec_expand_builtin PARAMS ((tree, rtx));static rtx altivec_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx));static rtx altivec_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx));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_ternop_builtin PARAMS ((enum insn_code, tree, rtx));static rtx altivec_expand_stv_builtin PARAMS ((enum insn_code, tree));static void rs6000_parse_abi_options 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 *));int vrsave_operation PARAMS ((rtx, enum machine_mode));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"};#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"};#endif#ifndef MASK_STRICT_ALIGN#define MASK_STRICT_ALIGN 0#endif/* Initialize the GCC target structure. */#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table#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#ifdef OBJECT_FORMAT_COFF/* 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#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#if TARGET_ELF#undef TARGET_SECTION_TYPE_FLAGS#define TARGET_SECTION_TYPE_FLAGS rs6000_elf_section_type_flags#endif#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/* The VRSAVE bitmask puts bit %v0 as the most significant bit. */#define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))struct 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}, {"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, MASK_POWER | MASK_MULTIPLE | MASK_STRING, MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, {"rios2", PROCESSOR_RIOS2, MASK_POWER | MASK_MULTIPLE | MASK_STRING | MASK_POWER2, POWERPC_MASKS | MASK_NEW_MNEMONICS}, {"rs64a", PROCESSOR_RS64A, MASK_POWERPC | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS}, {"401", PROCESSOR_PPC403, MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, {"403", PROCESSOR_PPC403, MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS | MASK_STRICT_ALIGN, POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, {"405", PROCESSOR_PPC405, MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, {"505", PROCESSOR_MPCCORE, MASK_POWERPC | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, {"601", PROCESSOR_PPC601, MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_MULTIPLE | MASK_STRING, MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64}, {"602", PROCESSOR_PPC603, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, {"603", PROCESSOR_PPC603, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, {"603e", PROCESSOR_PPC603, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, {"ec603e", PROCESSOR_PPC603, MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, {"604", PROCESSOR_PPC604, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, {"604e", PROCESSOR_PPC604e, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, {"620", PROCESSOR_PPC620, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT}, {"630", PROCESSOR_PPC630, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT}, {"740", PROCESSOR_PPC750, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, {"750", PROCESSOR_PPC750, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, {"7400", PROCESSOR_PPC7400, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, {"7450", PROCESSOR_PPC7450, MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, {"801", PROCESSOR_MPCCORE, MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, {"821", PROCESSOR_MPCCORE, MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, {"823", PROCESSOR_MPCCORE, MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, {"860", PROCESSOR_MPCCORE, MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}}; size_t ptt_size = sizeof (processor_target_table) / sizeof (struct ptt); /* Save current -mmultiple/-mno-multiple status. */ int multiple = TARGET_MULTIPLE; /* Save current -mstring/-mno-string status. */ int string = TARGET_STRING; /* Identify the processor type. */ rs6000_select[0].string = default_cpu; rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT; for (i = 0; i < ARRAY_SIZE (rs6000_select); i++) { ptr = &rs6000_select[i]; if (ptr->string != (char *)0 && ptr->string[0] != '\0') { for (j = 0; j < ptt_size; j++) if (! strcmp (ptr->string, processor_target_table[j].name)) { if (ptr->set_tune_p) rs6000_cpu = processor_target_table[j].processor; if (ptr->set_arch_p) { target_flags |= processor_target_table[j].target_enable; target_flags &= ~processor_target_table[j].target_disable; } break; } if (j == ptt_size) error ("bad value (%s) for %s switch", ptr->string, ptr->name); } } /* If we are optimizing big endian systems for space, use the store multiple instructions. */ if (BYTES_BIG_ENDIAN && optimize_size) target_flags |= MASK_MULTIPLE; /* If -mmultiple or -mno-multiple was explicitly used, don't override with the processor default */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -