📄 s390.c
字号:
else s390_cost = &z900_cost; if (TARGET_BACKCHAIN && TARGET_PACKED_STACK && TARGET_HARD_FLOAT) error ("-mbackchain -mpacked-stack -mhard-float are not supported " "in combination."); if (s390_warn_framesize_string) { if (sscanf (s390_warn_framesize_string, HOST_WIDE_INT_PRINT_DEC, &s390_warn_framesize) != 1) error ("invalid value for -mwarn-framesize"); } if (s390_warn_dynamicstack_string) s390_warn_dynamicstack_p = 1; if (s390_stack_size_string) { if (sscanf (s390_stack_size_string, HOST_WIDE_INT_PRINT_DEC, &s390_stack_size) != 1) error ("invalid value for -mstack-size"); if (exact_log2 (s390_stack_size) == -1) error ("stack size must be an exact power of 2"); if (s390_stack_guard_string) { if (sscanf (s390_stack_guard_string, HOST_WIDE_INT_PRINT_DEC, &s390_stack_guard) != 1) error ("invalid value for -mstack-guard"); if (s390_stack_guard >= s390_stack_size) error ("stack size must be greater than the stack guard value"); if (exact_log2 (s390_stack_guard) == -1) error ("stack guard value must be an exact power of 2"); } else error ("-mstack-size implies use of -mstack-guard"); } if (s390_stack_guard_string && !s390_stack_size_string) error ("-mstack-guard implies use of -mstack-size"); }/* Map for smallest class containing reg regno. */const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] ={ GENERAL_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, ADDR_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, FP_REGS, ADDR_REGS, CC_REGS, ADDR_REGS, ADDR_REGS, ACCESS_REGS, ACCESS_REGS};/* Return attribute type of insn. */static enum attr_types390_safe_attr_type (rtx insn){ if (recog_memoized (insn) >= 0) return get_attr_type (insn); else return TYPE_NONE;}/* Return true if OP a (const_int 0) operand. OP is the current operation. MODE is the current operation mode. */intconst0_operand (register rtx op, enum machine_mode mode){ return op == CONST0_RTX (mode);}/* Return true if OP is constant. OP is the current operation. MODE is the current operation mode. */intconsttable_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return CONSTANT_P (op);}/* Return true if the mode of operand OP matches MODE. If MODE is set to VOIDmode, set it to the mode of OP. */static intcheck_mode (register rtx op, enum machine_mode *mode){ if (*mode == VOIDmode) *mode = GET_MODE (op); else { if (GET_MODE (op) != VOIDmode && GET_MODE (op) != *mode) return 0; } return 1;}/* Return true if OP a valid operand for the LARL instruction. OP is the current operation. MODE is the current operation mode. */intlarl_operand (register rtx op, enum machine_mode mode){ if (! check_mode (op, &mode)) return 0; /* Allow labels and local symbols. */ if (GET_CODE (op) == LABEL_REF) return 1; if (GET_CODE (op) == SYMBOL_REF) return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0 && SYMBOL_REF_TLS_MODEL (op) == 0 && (!flag_pic || SYMBOL_REF_LOCAL_P (op))); /* Everything else must have a CONST, so strip it. */ if (GET_CODE (op) != CONST) return 0; op = XEXP (op, 0); /* Allow adding *even* in-range constants. */ if (GET_CODE (op) == PLUS) { if (GET_CODE (XEXP (op, 1)) != CONST_INT || (INTVAL (XEXP (op, 1)) & 1) != 0) return 0;#if HOST_BITS_PER_WIDE_INT > 32 if (INTVAL (XEXP (op, 1)) >= (HOST_WIDE_INT)1 << 32 || INTVAL (XEXP (op, 1)) < -((HOST_WIDE_INT)1 << 32)) return 0;#endif op = XEXP (op, 0); } /* Labels and local symbols allowed here as well. */ if (GET_CODE (op) == LABEL_REF) return 1; if (GET_CODE (op) == SYMBOL_REF) return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0 && SYMBOL_REF_TLS_MODEL (op) == 0 && (!flag_pic || SYMBOL_REF_LOCAL_P (op))); /* Now we must have a @GOTENT offset or @PLT stub or an @INDNTPOFF TLS offset. */ if (GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_GOTENT) return 1; if (GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_PLT) return 1; if (GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_INDNTPOFF) return 1; return 0;}/* Return true if OP is a valid S-type operand. OP is the current operation. MODE is the current operation mode. */ints_operand (rtx op, enum machine_mode mode){ struct s390_address addr; /* Call general_operand first, so that we don't have to check for many special cases. */ if (!general_operand (op, mode)) return 0; /* Just like memory_operand, allow (subreg (mem ...)) after reload. */ if (reload_completed && GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == MEM) op = SUBREG_REG (op); if (GET_CODE (op) != MEM) return 0; if (!s390_decompose_address (XEXP (op, 0), &addr)) return 0; if (addr.indx) return 0; return 1;}/* Return true if OP a valid shift count operand. OP is the current operation. MODE is the current operation mode. */intshift_count_operand (rtx op, enum machine_mode mode){ HOST_WIDE_INT offset = 0; if (! check_mode (op, &mode)) return 0; /* We can have an integer constant, an address register, or a sum of the two. Note that reload already checks that any register present is an address register, so we just check for any register here. */ if (GET_CODE (op) == CONST_INT) { offset = INTVAL (op); op = NULL_RTX; } if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT) { offset = INTVAL (XEXP (op, 1)); op = XEXP (op, 0); } while (op && GET_CODE (op) == SUBREG) op = SUBREG_REG (op); if (op && GET_CODE (op) != REG) return 0; /* Unfortunately we have to reject constants that are invalid for an address, or else reload will get confused. */ if (!DISP_IN_RANGE (offset)) return 0; return 1;}/* Return true if DISP is a valid short displacement. */static ints390_short_displacement (rtx disp){ /* No displacement is OK. */ if (!disp) return 1; /* Integer displacement in range. */ if (GET_CODE (disp) == CONST_INT) return INTVAL (disp) >= 0 && INTVAL (disp) < 4096; /* GOT offset is not OK, the GOT can be large. */ if (GET_CODE (disp) == CONST && GET_CODE (XEXP (disp, 0)) == UNSPEC && (XINT (XEXP (disp, 0), 1) == UNSPEC_GOT || XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF)) return 0; /* All other symbolic constants are literal pool references, which are OK as the literal pool must be small. */ if (GET_CODE (disp) == CONST) return 1; return 0;}/* Return true if OP is a valid operand for a C constraint. */ints390_extra_constraint_str (rtx op, int c, const char * str){ struct s390_address addr; if (c != str[0]) abort (); /* Check for offsettable variants of memory constraints. */ if (c == 'A') { /* Only accept non-volatile MEMs. */ if (!MEM_P (op) || MEM_VOLATILE_P (op)) return 0; if ((reload_completed || reload_in_progress) ? !offsettable_memref_p (op) : !offsettable_nonstrict_memref_p (op)) return 0; c = str[1]; } /* Check for non-literal-pool variants of memory constraints. */ else if (c == 'B') { if (GET_CODE (op) != MEM) return 0; if (!s390_decompose_address (XEXP (op, 0), &addr)) return 0; if (addr.base && REG_P (addr.base) && REGNO (addr.base) == BASE_REGNUM) return 0; if (addr.indx && REG_P (addr.indx) && REGNO (addr.indx) == BASE_REGNUM) return 0; c = str[1]; } switch (c) { case 'Q': if (GET_CODE (op) != MEM) return 0; if (!s390_decompose_address (XEXP (op, 0), &addr)) return 0; if (addr.indx) return 0; if (TARGET_LONG_DISPLACEMENT) { if (!s390_short_displacement (addr.disp)) return 0; } break; case 'R': if (GET_CODE (op) != MEM) return 0; if (TARGET_LONG_DISPLACEMENT) { if (!s390_decompose_address (XEXP (op, 0), &addr)) return 0; if (!s390_short_displacement (addr.disp)) return 0; } break; case 'S': if (!TARGET_LONG_DISPLACEMENT) return 0; if (GET_CODE (op) != MEM) return 0; if (!s390_decompose_address (XEXP (op, 0), &addr)) return 0; if (addr.indx) return 0; if (s390_short_displacement (addr.disp)) return 0; break; case 'T': if (!TARGET_LONG_DISPLACEMENT) return 0; if (GET_CODE (op) != MEM) return 0; /* Any invalid address here will be fixed up by reload, so accept it for the most generic constraint. */ if (s390_decompose_address (XEXP (op, 0), &addr) && s390_short_displacement (addr.disp)) return 0; break; case 'U': if (TARGET_LONG_DISPLACEMENT) { if (!s390_decompose_address (op, &addr)) return 0; if (!s390_short_displacement (addr.disp)) return 0; } break; case 'W': if (!TARGET_LONG_DISPLACEMENT) return 0; /* Any invalid address here will be fixed up by reload, so accept it for the most generic constraint. */ if (s390_decompose_address (op, &addr) && s390_short_displacement (addr.disp)) return 0; break; case 'Y': return shift_count_operand (op, VOIDmode); default: return 0; } return 1;}/* Return true if VALUE matches the constraint STR. */ints390_const_ok_for_constraint_p (HOST_WIDE_INT value, int c, const char * str){ enum machine_mode mode, part_mode; int def; int part, part_goal; if (c != str[0]) abort (); switch (str[0]) { case 'I': return (unsigned int)value < 256; case 'J': return (unsigned int)value < 4096; case 'K': return value >= -32768 && value < 32768; case 'L': return (TARGET_LONG_DISPLACEMENT ? (value >= -524288 && value <= 524287) : (value >= 0 && value <= 4095)); case 'M': return value == 2147483647; case 'N': if (str[1] == 'x') part_goal = -1; else part_goal = str[1] - '0'; switch (str[2]) { case 'H': part_mode = HImode; break; case 'Q': part_mode = QImode; break; default: return 0; } switch (str[3]) { case 'H': mode = HImode; break; case 'S': mode = SImode; break; case 'D': mode = DImode; break; default: return 0; } switch (str[4]) { case '0': def = 0; break; case 'F': def = -1; break; default: return 0; } if (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (part_mode)) return 0; part = s390_single_part (GEN_INT (value), mode, part_mode, def); if (part < 0) return 0; if (part_goal != -1 && part_goal != part) return 0; break; default: return 0; } return 1;}/* Compute a (partial) cost for rtx X. Return true if the complete cost has been computed, and false if subexpressions should be scanned. In either case, *TOTAL contains the cost result. CODE contains GET_CODE (x), OUTER_CODE contains the code of the superexpression of x. */static bools390_rtx_costs (rtx x, int code, int outer_code, int *total){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -