📄 s390.c
字号:
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_CONSTRAINT_P (INTVAL (right), 'K', "K")) *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_CONSTRAINT_P (INTVAL (right), 'K', "K")) *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; 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; } return false; case SQRT: if (GET_MODE (x) == SFmode) *total = s390_cost->sqebr; else /* DFmode */ *total = s390_cost->sqdbr; 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);}/* Return true if OP is a valid operand for the BRAS instruction. OP is the current operation. MODE is the current operation mode. */intbras_sym_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ register enum rtx_code code = GET_CODE (op); /* Allow SYMBOL_REFs. */ if (code == SYMBOL_REF) return 1; /* Allow @PLT stubs. */ if (code == CONST && GET_CODE (XEXP (op, 0)) == UNSPEC && XINT (XEXP (op, 0), 1) == UNSPEC_PLT) return 1; return 0;}/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode, otherwise return 0. */inttls_symbolic_operand (register rtx op){ if (GET_CODE (op) != SYMBOL_REF) return 0; return SYMBOL_REF_TLS_MODEL (op);}/* Return true if OP is a load multiple operation. It is known to be a PARALLEL and the first section will be tested. OP is the current operation. MODE is the current operation mode. */intload_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ enum machine_mode elt_mode; int count = XVECLEN (op, 0); unsigned int dest_regno; rtx src_addr; int i, off; /* Perform a quick check so we don't blow up below. */ if (count <= 1 || GET_CODE (XVECEXP (op, 0, 0)) != SET || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM) return 0; dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0))); src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0); elt_mode = GET_MODE (SET_DEST (XVECEXP (op, 0, 0))); /* Check, is base, or base + displacement. */ if (GET_CODE (src_addr) == REG) off = 0; else if (GET_CODE (src_addr) == PLUS && GET_CODE (XEXP (src_addr, 0)) == REG && GET_CODE (XEXP (src_addr, 1)) == CONST_INT) { off = INTVAL (XEXP (src_addr, 1)); src_addr = XEXP (src_addr, 0); } else return 0; for (i = 1; i < count; i++) { rtx elt = XVECEXP (op, 0, i); if (GET_CODE (elt) != SET || GET_CODE (SET_DEST (elt)) != REG || GET_MODE (SET_DEST (elt)) != elt_mode || REGNO (SET_DEST (elt)) != dest_regno + i || GET_CODE (SET_SRC (elt)) != MEM || GET_MODE (SET_SRC (elt)) != elt_mode || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr) || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != off + i * GET_MODE_SIZE (elt_mode)) return 0; } return 1;}/* Return true if OP is a store multiple operation. It is known to be a PARALLEL and the first section will be tested. OP is the current operation. MODE is the current operation mode. */intstore_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ enum machine_mode elt_mode; int count = XVECLEN (op, 0); unsigned int src_regno; rtx dest_addr; int i, off; /* Perform a quick check so we don't blow up below. */ if (count <= 1 || GET_CODE (XVECEXP (op, 0, 0)) != SET || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG) return 0; src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0))); dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0); elt_mode = GET_MODE (SET_SRC (XVECEXP (op, 0, 0))); /* Check, is base, or base + displacement. */ if (GET_CODE (dest_addr) == REG) off = 0; else if (GET_CODE (dest_addr) == PLUS && GET_CODE (XEXP (dest_addr, 0)) == REG && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT) { off = INTVAL (XEXP (dest_addr, 1)); dest_addr = XEXP (dest_addr, 0); } else return 0; for (i = 1; i < count; i++) { rtx elt = XVECEXP (op, 0, i); if (GET_CODE (elt) != SET || GET_CODE (SET_SRC (elt)) != REG || GET_MODE (SET_SRC (elt)) != elt_mode || REGNO (SET_SRC (elt)) != src_regno + i || GET_CODE (SET_DEST (elt)) != MEM || GET_MODE (SET_DEST (elt)) != elt_mode || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr) || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != off + i * GET_MODE_SIZE (elt_mode)) return 0; } return 1;}/* 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 */intsymbolic_reference_mentioned_p (rtx op){ register const char *fmt; register 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') { register 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. */inttls_symbolic_reference_mentioned_p (rtx op){ register const char *fmt; register 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') { register int j; for (j = XVECLEN (op, i) - 1; j >= 0; j--) if (tls_symbolic_reference_mentioned_p (XVECEXP (op, i, j))) return 1; } else if (fmt[i] == 'e' && tls_symbolic_reference_mentioned_p (XEXP (op, i))) return 1; } return 0;}/* 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 (register 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 (register 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 const
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -