📄 s390.c
字号:
s390_const_double_ok_for_constraint_p (rtx value, int c, const char * str){ gcc_assert (c == str[0]); switch (str[0]) { case 'G': /* The floating point zero constant. */ return (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT && value == CONST0_RTX (GET_MODE (value))); default: return 0; }}/* 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; gcc_assert (c == str[0]); 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 'Q': part_mode = QImode; break; case 'H': part_mode = HImode; break; case 'S': part_mode = SImode; 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; case 'O': if (!TARGET_EXTIMM) return 0; switch (str[1]) { case 's': return trunc_int_for_mode (value, SImode) == value; case 'p': return value == 0 || s390_single_part (GEN_INT (value), DImode, SImode, 0) == 1; case 'n': return value == -1 || s390_single_part (GEN_INT (value), DImode, SImode, -1) == 1; default: gcc_unreachable (); } break; case 'P': return legitimate_reload_constant_p (GEN_INT (value)); 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){ switch (code) { case CONST: case CONST_INT: case LABEL_REF: case SYMBOL_REF: case CONST_DOUBLE: case MEM: *total = 0; return true; case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATE: case ROTATERT: case AND: case IOR: case XOR: case NEG: case NOT: *total = COSTS_N_INSNS (1); return false; case PLUS: case MINUS: /* Check for multiply and add. */ if ((GET_MODE (x) == DFmode || GET_MODE (x) == SFmode) && GET_CODE (XEXP (x, 0)) == MULT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD) { /* This is the multiply and add case. */ if (GET_MODE (x) == DFmode) *total = s390_cost->madbr; else *total = s390_cost->maebr; *total += rtx_cost (XEXP (XEXP (x, 0), 0), MULT) + rtx_cost (XEXP (XEXP (x, 0), 1), MULT) + rtx_cost (XEXP (x, 1), code); return true; /* Do not do an additional recursive descent. */ } *total = COSTS_N_INSNS (1); return false; case MULT: switch (GET_MODE (x)) { case SImode: { rtx left = XEXP (x, 0); rtx right = XEXP (x, 1); if (GET_CODE (right) == CONST_INT && CONST_OK_FOR_K (INTVAL (right))) *total = s390_cost->mhi; else if (GET_CODE (left) == SIGN_EXTEND) *total = s390_cost->mh; else *total = s390_cost->ms; /* msr, ms, msy */ break; } case DImode: { rtx left = XEXP (x, 0); rtx right = XEXP (x, 1); if (TARGET_64BIT) { if (GET_CODE (right) == CONST_INT && CONST_OK_FOR_K (INTVAL (right))) *total = s390_cost->mghi; else if (GET_CODE (left) == SIGN_EXTEND) *total = s390_cost->msgf; else *total = s390_cost->msg; /* msgr, msg */ } else /* TARGET_31BIT */ { if (GET_CODE (left) == SIGN_EXTEND && GET_CODE (right) == SIGN_EXTEND) /* mulsidi case: mr, m */ *total = s390_cost->m; else if (GET_CODE (left) == ZERO_EXTEND && GET_CODE (right) == ZERO_EXTEND && TARGET_CPU_ZARCH) /* umulsidi case: ml, mlr */ *total = s390_cost->ml; else /* Complex calculation is required. */ *total = COSTS_N_INSNS (40); } break; } case SFmode: case DFmode: *total = s390_cost->mult_df; break; case TFmode: *total = s390_cost->mxbr; break; default: return false; } return false; case UDIV: case UMOD: if (GET_MODE (x) == TImode) /* 128 bit division */ *total = s390_cost->dlgr; else if (GET_MODE (x) == DImode) { rtx right = XEXP (x, 1); if (GET_CODE (right) == ZERO_EXTEND) /* 64 by 32 bit division */ *total = s390_cost->dlr; else /* 64 by 64 bit division */ *total = s390_cost->dlgr; } else if (GET_MODE (x) == SImode) /* 32 bit division */ *total = s390_cost->dlr; return false; case DIV: case MOD: if (GET_MODE (x) == DImode) { rtx right = XEXP (x, 1); if (GET_CODE (right) == ZERO_EXTEND) /* 64 by 32 bit division */ if (TARGET_64BIT) *total = s390_cost->dsgfr; else *total = s390_cost->dr; else /* 64 by 64 bit division */ *total = s390_cost->dsgr; } else if (GET_MODE (x) == SImode) /* 32 bit division */ *total = s390_cost->dlr; else if (GET_MODE (x) == SFmode) { if (TARGET_IEEE_FLOAT) *total = s390_cost->debr; else /* TARGET_IBM_FLOAT */ *total = s390_cost->der; } else if (GET_MODE (x) == DFmode) { if (TARGET_IEEE_FLOAT) *total = s390_cost->ddbr; else /* TARGET_IBM_FLOAT */ *total = s390_cost->ddr; } else if (GET_MODE (x) == TFmode) { if (TARGET_IEEE_FLOAT) *total = s390_cost->dxbr; else /* TARGET_IBM_FLOAT */ *total = s390_cost->dxr; } return false; case SQRT: if (GET_MODE (x) == SFmode) *total = s390_cost->sqebr; else if (GET_MODE (x) == DFmode) *total = s390_cost->sqdbr; else /* TFmode */ *total = s390_cost->sqxbr; return false; case SIGN_EXTEND: case ZERO_EXTEND: if (outer_code == MULT || outer_code == DIV || outer_code == MOD || outer_code == PLUS || outer_code == MINUS || outer_code == COMPARE) *total = 0; return false; case COMPARE: *total = COSTS_N_INSNS (1); if (GET_CODE (XEXP (x, 0)) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) { rtx op0 = XEXP (XEXP (x, 0), 0); rtx op1 = XEXP (XEXP (x, 0), 1); rtx op2 = XEXP (x, 1); if (memory_operand (op0, GET_MODE (op0)) && s390_tm_ccmode (op1, op2, 0) != VOIDmode) return true; if (register_operand (op0, GET_MODE (op0)) && s390_tm_ccmode (op1, op2, 1) != VOIDmode) return true; } return false; default: return false; }}/* Return the cost of an address rtx ADDR. */static ints390_address_cost (rtx addr){ struct s390_address ad; if (!s390_decompose_address (addr, &ad)) return 1000; return ad.indx? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (1);}/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode, otherwise return 0. */inttls_symbolic_operand (rtx op){ if (GET_CODE (op) != SYMBOL_REF) return 0; return SYMBOL_REF_TLS_MODEL (op);}/* Split DImode access register reference REG (on 64-bit) into its constituent low and high parts, and store them into LO and HI. Note that gen_lowpart/ gen_highpart cannot be used as they assume all registers are word-sized, while our access registers have only half that size. */voids390_split_access_reg (rtx reg, rtx *lo, rtx *hi){ gcc_assert (TARGET_64BIT); gcc_assert (ACCESS_REG_P (reg)); gcc_assert (GET_MODE (reg) == DImode); gcc_assert (!(REGNO (reg) & 1)); *lo = gen_rtx_REG (SImode, REGNO (reg) + 1); *hi = gen_rtx_REG (SImode, REGNO (reg));}/* Return true if OP contains a symbol reference */boolsymbolic_reference_mentioned_p (rtx op){ const char *fmt; int i; if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) return 1; fmt = GET_RTX_FORMAT (GET_CODE (op)); for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) { if (fmt[i] == 'E') { int j; for (j = XVECLEN (op, i) - 1; j >= 0; j--) if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) return 1; } else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) return 1; } return 0;}/* Return true if OP contains a reference to a thread-local symbol. */booltls_symbolic_reference_mentioned_p (rtx op){ const char *fmt; int i; if (GET_CODE (op) == SYMBOL_REF) return tls_symbolic_operand (op); fmt = GET_RTX_FORMAT (GET_CODE (op)); for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) { if (fmt[i] == 'E') { int j; for (j = XVECLEN (op, i) - 1; j >= 0; j--) if (tls_symbolic_reference_mentioned_p (XVECEXP (op, i, j))) return true; } else if (fmt[i] == 'e' && tls_symbolic_reference_mentioned_p (XEXP (op, i))) return true; } return false;}/* Return true if OP is a legitimate general operand when generating PIC code. It is given that flag_pic is on and that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */intlegitimate_pic_operand_p (rtx op){ /* Accept all non-symbolic constants. */ if (!SYMBOLIC_CONST (op)) return 1; /* Reject everything else; must be handled via emit_symbolic_move. */ return 0;}/* Returns true if the constant value OP is a legitimate general operand. It is given that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */intlegitimate_constant_p (rtx op){ /* Accept all non-symbolic constants. */ if (!SYMBOLIC_CONST (op)) return 1; /* Accept immediate LARL operands. */ if (TARGET_CPU_ZARCH && larl_operand (op, VOIDmode)) return 1; /* Thread-local symbols are never legal constants. This is so that emit_call knows that computing such addresses might require a function call. */ if (TLS_SYMBOLIC_CONST (op)) return 0; /* In the PIC case, symbolic constants must *not* be forced into the literal pool. We accept them here, so that they will be handled by emit_symbolic_move. */ if (flag_pic) return 1; /* All remaining non-PIC symbolic constants are forced into the literal pool. */ return 0;}/* Determine if it's legal to put X into the constant pool. This is not possible if X contains the address of a symbol that is not constant (TLS) or not known at final link time (PIC). */static bools390_cannot_force_const_mem (rtx x){ switch (GET_CODE (x)) { case CONST_INT: case CONST_DOUBLE: /* Acce
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -