📄 s390.c
字号:
if (GET_CODE (op) == SYMBOL_REF && XSTR (op, 0)[0] != '@' && !tls_symbolic_operand (op) && (!flag_pic || SYMBOL_REF_FLAG (op) || CONSTANT_POOL_ADDRESS_P (op))) return 1; /* Everything else must have a CONST, so strip it. */ if (GET_CODE (op) != CONST) return 0; op = XEXP (op, 0); /* Allow adding *even* constants. */ if (GET_CODE (op) == PLUS) { if (GET_CODE (XEXP (op, 1)) != CONST_INT || (INTVAL (XEXP (op, 1)) & 1) != 0) return 0; 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 && XSTR (op, 0)[0] != '@' && !tls_symbolic_operand (op) && (!flag_pic || SYMBOL_REF_FLAG (op) || CONSTANT_POOL_ADDRESS_P (op))) return 1; /* Now we must have a @GOTENT offset or @PLT stub or an @INDNTPOFF TLS offset. */ if (GET_CODE (op) == UNSPEC && XINT (op, 1) == 111) return 1; if (GET_CODE (op) == UNSPEC && XINT (op, 1) == 113) return 1; if (GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_INDNTPOFF) return 1; return 0;}/* Helper routine to implement s_operand and s_imm_operand. OP is the current operation. MODE is the current operation mode. ALLOW_IMMEDIATE specifies whether immediate operands should be accepted or not. */static intgeneral_s_operand (op, mode, allow_immediate) register rtx op; enum machine_mode mode; int allow_immediate;{ 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); switch (GET_CODE (op)) { /* Constants that we are sure will be forced to the literal pool in reload are OK as s-operand. Note that we cannot call s390_preferred_reload_class here because it might not be known yet at this point whether the current function is a leaf or not. */ case CONST_INT: case CONST_DOUBLE: if (!allow_immediate || reload_completed) break; if (!legitimate_reload_constant_p (op)) return 1; if (!TARGET_64BIT) return 1; break; /* Memory operands are OK unless they already use an index register. */ case MEM: if (GET_CODE (XEXP (op, 0)) == ADDRESSOF) return 1; if (s390_decompose_address (XEXP (op, 0), &addr) && !addr.indx) return 1; break; default: break; } 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 (op, mode) register rtx op; enum machine_mode mode;{ return general_s_operand (op, mode, 0);}/* Return true if OP is a valid S-type operand or an immediate operand that can be addressed as S-type operand by forcing it into the literal pool. OP is the current operation. MODE is the current operation mode. */ints_imm_operand (op, mode) register rtx op; enum machine_mode mode;{ return general_s_operand (op, mode, 1);}/* Return true if OP is a valid operand for a 'Q' constraint. This differs from s_operand in that only memory operands without index register are accepted, nothing else. */intq_constraint (op) register rtx op;{ struct s390_address addr; 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 the cost of an address rtx ADDR. */ints390_address_cost (addr) 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 (op, mode) 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) == 113) 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 (op) register rtx op;{ const char *symbol_str; if (GET_CODE (op) != SYMBOL_REF) return 0; symbol_str = XSTR (op, 0); if (symbol_str[0] != '%') return 0; return strchr (tls_model_chars, symbol_str[1]) - tls_model_chars;}/* 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 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ 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); /* 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; if (src_addr == frame_pointer_rtx || src_addr == arg_pointer_rtx) 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)) != Pmode || REGNO (SET_DEST (elt)) != dest_regno + i || GET_CODE (SET_SRC (elt)) != MEM || GET_MODE (SET_SRC (elt)) != Pmode || 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 * UNITS_PER_WORD) 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 (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ 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); /* 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; if (dest_addr == frame_pointer_rtx || dest_addr == arg_pointer_rtx) 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)) != Pmode || REGNO (SET_SRC (elt)) != src_regno + i || GET_CODE (SET_DEST (elt)) != MEM || GET_MODE (SET_DEST (elt)) != Pmode || 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 * UNITS_PER_WORD) return 0; } return 1;}/* Return true if OP contains a symbol reference */intsymbolic_reference_mentioned_p (op) 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 (op) 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 (op) 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 (op) register rtx op;{ /* Accept all non-symbolic constants. */ if (!SYMBOLIC_CONST (op)) return 1; /* Accept immediate LARL operands. */ if (TARGET_64BIT && 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 (x) rtx x;{ switch (GET_CODE (x)) { case CONST_INT: case CONST_DOUBLE: /* Accept all non-symbolic constants. */ return false; case LABEL_REF: /* Labels are OK iff we are non-PIC. */ return flag_pic != 0; case SYMBOL_REF: /* 'Naked' TLS symbol references are never OK, non-TLS symbols are OK iff we are non-PIC. */ if (tls_symbolic_operand (x)) return true; else return flag_pic != 0; case CONST: return s390_cannot_force_const_mem (XEXP (x, 0)); case PLUS: case MINUS: return s390_cannot_force_const_mem (XEXP (x, 0)) || s390_cannot_force_const_mem (XEXP (x, 1)); case UNSPEC: switch (XINT (x, 1)) { /* Only lt-relative or GOT-relative UNSPECs are OK. */ case 100: case 104: case 112:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -