📄 s390.c
字号:
case 114: case UNSPEC_TLSGD: case UNSPEC_TLSLDM: case UNSPEC_NTPOFF: case UNSPEC_DTPOFF: case UNSPEC_GOTNTPOFF: case UNSPEC_INDNTPOFF: return false; default: return true; } break; default: abort (); }}/* Returns true if the constant value OP is a legitimate general operand during and after reload. The difference to legitimate_constant_p is that this function will not accept a constant that would need to be forced to the literal pool before it can be used as operand. */intlegitimate_reload_constant_p (op) register rtx op;{ /* Accept l(g)hi operands. */ if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (op), 'K')) return 1; /* Accept lliXX operands. */ if (TARGET_64BIT && s390_single_hi (op, DImode, 0) >= 0) return 1; /* Accept larl operands. */ if (TARGET_64BIT && larl_operand (op, VOIDmode)) return 1; /* Everything else cannot be handled without reload. */ return 0;}/* Given an rtx OP being reloaded into a reg required to be in class CLASS, return the class of reg to actually use. */enum reg_classs390_preferred_reload_class (op, class) rtx op; enum reg_class class;{ /* This can happen if a floating point constant is being reloaded into an integer register. Leave well alone. */ if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT && class != FP_REGS) return class; switch (GET_CODE (op)) { /* Constants we cannot reload must be forced into the literal pool. */ case CONST_DOUBLE: case CONST_INT: if (legitimate_reload_constant_p (op)) return class; else return NO_REGS; /* If a symbolic constant or a PLUS is reloaded, it is most likely being used as an address, so prefer ADDR_REGS. If 'class' is not a superset of ADDR_REGS, e.g. FP_REGS, reject this reload. */ case PLUS: case LABEL_REF: case SYMBOL_REF: case CONST: if (reg_class_subset_p (ADDR_REGS, class)) return ADDR_REGS; else return NO_REGS; default: break; } return class;}/* Return the register class of a scratch register needed to load IN into a register of class CLASS in MODE. We need a temporary when loading a PLUS expression which is not a legitimate operand of the LOAD ADDRESS instruction. */enum reg_classs390_secondary_input_reload_class (class, mode, in) enum reg_class class ATTRIBUTE_UNUSED; enum machine_mode mode; rtx in;{ if (s390_plus_operand (in, mode)) return ADDR_REGS; return NO_REGS;}/* Return the register class of a scratch register needed to store a register of class CLASS in MODE into OUT: We need a temporary when storing a double-word to a non-offsettable memory address. */enum reg_classs390_secondary_output_reload_class (class, mode, out) enum reg_class class; enum machine_mode mode; rtx out;{ if ((TARGET_64BIT ? mode == TImode : (mode == DImode || mode == DFmode)) && reg_classes_intersect_p (GENERAL_REGS, class) && GET_CODE (out) == MEM && !offsettable_memref_p (out) && !s_operand (out, VOIDmode)) return ADDR_REGS; return NO_REGS;}/* Return true if OP is a PLUS that is not a legitimate operand for the LA instruction. OP is the current operation. MODE is the current operation mode. */ints390_plus_operand (op, mode) register rtx op; enum machine_mode mode;{ if (!check_mode (op, &mode) || mode != Pmode) return FALSE; if (GET_CODE (op) != PLUS) return FALSE; if (legitimate_la_operand_p (op)) return FALSE; return TRUE;}/* Generate code to load SRC, which is PLUS that is not a legitimate operand for the LA instruction, into TARGET. SCRATCH may be used as scratch register. */voids390_expand_plus_operand (target, src, scratch) register rtx target; register rtx src; register rtx scratch;{ rtx sum1, sum2; struct s390_address ad; /* src must be a PLUS; get its two operands. */ if (GET_CODE (src) != PLUS || GET_MODE (src) != Pmode) abort (); /* Check if any of the two operands is already scheduled for replacement by reload. This can happen e.g. when float registers occur in an address. */ sum1 = find_replacement (&XEXP (src, 0)); sum2 = find_replacement (&XEXP (src, 1)); src = gen_rtx_PLUS (Pmode, sum1, sum2); /* If the address is already strictly valid, there's nothing to do. */ if (!s390_decompose_address (src, &ad) || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base)) || (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx))) { /* Otherwise, one of the operands cannot be an address register; we reload its value into the scratch register. */ if (true_regnum (sum1) < 1 || true_regnum (sum1) > 15) { emit_move_insn (scratch, sum1); sum1 = scratch; } if (true_regnum (sum2) < 1 || true_regnum (sum2) > 15) { emit_move_insn (scratch, sum2); sum2 = scratch; } /* According to the way these invalid addresses are generated in reload.c, it should never happen (at least on s390) that *neither* of the PLUS components, after find_replacements was applied, is an address register. */ if (sum1 == scratch && sum2 == scratch) { debug_rtx (src); abort (); } src = gen_rtx_PLUS (Pmode, sum1, sum2); } /* Emit the LOAD ADDRESS pattern. Note that reload of PLUS is only ever performed on addresses, so we can mark the sum as legitimate for LA in any case. */ s390_load_address (target, src);}/* Decompose a RTL expression ADDR for a memory address into its components, returned in OUT. Returns 0 if ADDR is not a valid memory address, nonzero otherwise. If OUT is NULL, don't return the components, but check for validity only. Note: Only addresses in canonical form are recognized. LEGITIMIZE_ADDRESS should convert non-canonical forms to the canonical form so that they will be recognized. */static ints390_decompose_address (addr, out) register rtx addr; struct s390_address *out;{ rtx base = NULL_RTX; rtx indx = NULL_RTX; rtx disp = NULL_RTX; int pointer = FALSE; /* Decompose address into base + index + displacement. */ if (GET_CODE (addr) == REG || GET_CODE (addr) == UNSPEC) base = addr; else if (GET_CODE (addr) == PLUS) { rtx op0 = XEXP (addr, 0); rtx op1 = XEXP (addr, 1); enum rtx_code code0 = GET_CODE (op0); enum rtx_code code1 = GET_CODE (op1); if (code0 == REG || code0 == UNSPEC) { if (code1 == REG || code1 == UNSPEC) { indx = op0; /* index + base */ base = op1; } else { base = op0; /* base + displacement */ disp = op1; } } else if (code0 == PLUS) { indx = XEXP (op0, 0); /* index + base + disp */ base = XEXP (op0, 1); disp = op1; } else { return FALSE; } } else disp = addr; /* displacement */ /* Prefer to use pointer as base, not index. */ if (base && indx) { int base_ptr = GET_CODE (base) == UNSPEC || (REG_P (base) && REG_POINTER (base)); int indx_ptr = GET_CODE (indx) == UNSPEC || (REG_P (indx) && REG_POINTER (indx)); if (!base_ptr && indx_ptr) { rtx tmp = base; base = indx; indx = tmp; } } /* Validate base register. */ if (base) { if (GET_CODE (base) == UNSPEC) { if (XVECLEN (base, 0) != 1 || XINT (base, 1) != 101) return FALSE; base = XVECEXP (base, 0, 0); pointer = TRUE; } if (GET_CODE (base) != REG || GET_MODE (base) != Pmode) return FALSE; if (REGNO (base) == BASE_REGISTER || REGNO (base) == STACK_POINTER_REGNUM || REGNO (base) == FRAME_POINTER_REGNUM || ((reload_completed || reload_in_progress) && frame_pointer_needed && REGNO (base) == HARD_FRAME_POINTER_REGNUM) || REGNO (base) == ARG_POINTER_REGNUM || (REGNO (base) >= FIRST_VIRTUAL_REGISTER && REGNO (base) <= LAST_VIRTUAL_REGISTER) || (flag_pic && REGNO (base) == PIC_OFFSET_TABLE_REGNUM)) pointer = TRUE; } /* Validate index register. */ if (indx) { if (GET_CODE (indx) == UNSPEC) { if (XVECLEN (indx, 0) != 1 || XINT (indx, 1) != 101) return FALSE; indx = XVECEXP (indx, 0, 0); pointer = TRUE; } if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode) return FALSE; if (REGNO (indx) == BASE_REGISTER || REGNO (indx) == STACK_POINTER_REGNUM || REGNO (indx) == FRAME_POINTER_REGNUM || ((reload_completed || reload_in_progress) && frame_pointer_needed && REGNO (indx) == HARD_FRAME_POINTER_REGNUM) || REGNO (indx) == ARG_POINTER_REGNUM || (REGNO (indx) >= FIRST_VIRTUAL_REGISTER && REGNO (indx) <= LAST_VIRTUAL_REGISTER) || (flag_pic && REGNO (indx) == PIC_OFFSET_TABLE_REGNUM)) pointer = TRUE; } /* Validate displacement. */ if (disp) { /* Allow integer constant in range. */ if (GET_CODE (disp) == CONST_INT) { /* If the argument pointer is involved, the displacement will change later anyway as the argument pointer gets eliminated. This could make a valid displacement invalid, but it is more likely to make an invalid displacement valid, because we sometimes access the register save area via negative offsets to the arg pointer. Thus we don't check the displacement for validity here. If after elimination the displacement turns out to be invalid after all, this is fixed up by reload in any case. */ if (base != arg_pointer_rtx && indx != arg_pointer_rtx) { if (INTVAL (disp) < 0 || INTVAL (disp) >= 4096) return FALSE; } } /* In the small-PIC case, the linker converts @GOT12 and @GOTNTPOFF offsets to possible displacements. */ else if (GET_CODE (disp) == CONST && GET_CODE (XEXP (disp, 0)) == UNSPEC && (XINT (XEXP (disp, 0), 1) == 110 || XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF)) { if (flag_pic != 1) return FALSE; pointer = TRUE; } /* Accept chunkfied literal pool symbol references. */ else if (GET_CODE (disp) == CONST && GET_CODE (XEXP (disp, 0)) == MINUS && GET_CODE (XEXP (XEXP (disp, 0), 0)) == LABEL_REF && GET_CODE (XEXP (XEXP (disp, 0), 1)) == LABEL_REF) { pointer = TRUE; } /* Likewise if a constant offset is present. */ else if (GET_CODE (disp) == CONST && GET_CODE (XEXP (disp, 0)) == PLUS && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT && GET_CODE (XEXP (XEXP (disp, 0), 0)) == MINUS && GET_CODE (XEXP (XEXP (XEXP (disp, 0), 0), 0)) == LABEL_REF && GET_CODE (XEXP (XEXP (XEXP (disp, 0), 0), 1)) == LABEL_REF) { pointer = TRUE; } /* We can convert literal pool addresses to displacements by basing them off the base register. */ else { /* In some cases, we can accept an additional small constant offset. Split these off here. */ unsigned int offset = 0; if (GET_CODE (disp) == CONST && GET_CODE (XEXP (disp, 0)) == PLUS && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT) { offset = INTVAL (XEXP (XEXP (disp, 0), 1)); disp = XEXP (XEXP (disp, 0), 0); } /* Now we must have a literal pool address. */ if (GET_CODE (disp) != SYMBOL_REF || !CONSTANT_POOL_ADDRESS_P (disp)) return FALSE; /* If we have an offset, make sure it does not exceed the size of the constant pool entry. */ if (offset && offset >= GET_MODE_SIZE (get_pool_mode (disp))) return FALSE; /* Either base or index must be free to hold the base register. */ if (base && indx) return FALSE; /* Convert the address. */ if (base) indx = gen_rtx_REG (Pmode, BASE_REGISTER); else base = gen_rtx_REG (Pmode, BASE_REGISTER); disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp), 100); disp = gen_rtx_CONST (Pmode, disp); if (offset) disp = plus_constant (disp, offset); pointer = TRUE; } } if (!base && !indx) pointer = TRUE; if (out) { out->base = base; out->indx = indx; out->disp = disp; out->pointer = pointer; } return TRUE;}/* Return nonzero if ADDR is a valid memory address. STRICT specifies whether strict register checking applies. */intlegitimate_address_p (mode, addr, strict) enum machine_mode mode ATTRIBUTE_UNUSED; register rtx addr; int strict;{ struct s390_address ad; if (!s390_decompose_address (addr, &ad)) return FALSE; if (strict) { if (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -