s390.c
来自「gcc3.2.1源代码」· C语言 代码 · 共 2,465 行 · 第 1/5 页
C
2,465 行
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 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_pic_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; /* 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_pic_move. */ if (flag_pic) return 1; /* Even in the non-PIC case, we can accept immediate LARL operands here. */ if (TARGET_64BIT) return larl_operand (op, VOIDmode); /* All remaining non-PIC symbolic constants are forced into the literal pool. */ return 0;}/* 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; /* If reload is completed, and we do not already have a literal pool, and OP must be forced to the literal pool, then something must have gone wrong earlier. We *cannot* force the constant any more, because the prolog generation already decided we don't need to set up the base register. */ if (reload_completed && !regs_ever_live[BASE_REGISTER]) abort (); /* 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. For constants we *could* handle directly, it might still be preferable to put them in the pool and use a memory-to-memory instruction. However, try to avoid needlessly allocating a literal pool in a routine that wouldn't otherwise need any. Heuristically, we assume that 64-bit leaf functions typically don't need a literal pool, all others do. */ case CONST_DOUBLE: case CONST_INT: if (!legitimate_reload_constant_p (op)) return NO_REGS; if (TARGET_64BIT && current_function_is_leaf) return class; 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 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_in) register rtx target; register rtx src; register rtx scratch_in;{ rtx sum1, sum2, scratch; /* ??? reload apparently does not ensure that the scratch register and the target do not overlap. We absolutely require this to be the case, however. Therefore the reload_in[sd]i patterns ask for a double-sized scratch register, and if one part happens to be equal to the target, we use the other one. */ scratch = gen_rtx_REG (Pmode, REGNO (scratch_in)); if (rtx_equal_p (scratch, target)) scratch = gen_rtx_REG (Pmode, REGNO (scratch_in) + 1); /* 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)); /* If one of the two operands is equal to the target, make it the first one. If one is a constant, make it the second one. */ if (rtx_equal_p (target, sum2) || GET_CODE (sum1) == CONST_INT) { rtx tem = sum2; sum2 = sum1; sum1 = tem; } /* If the first operand is not an address register, we reload it into the target. */ if (true_regnum (sum1) < 1 || true_regnum (sum1) > 15) { emit_move_insn (target, sum1); sum1 = target; } /* Likewise for the second operand. However, take care not to clobber the target if we already used it for the first operand. Use the scratch instead. Also, allow an immediate offset if it is in range. */ if ((true_regnum (sum2) < 1 || true_regnum (sum2) > 15) && !(GET_CODE (sum2) == CONST_INT && INTVAL (sum2) >= 0 && INTVAL (sum2) < 4096)) { if (!rtx_equal_p (target, sum1)) { emit_move_insn (target, sum2); sum2 = target; } else { emit_move_insn (scratch, sum2); sum2 = scratch; } } /* 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. */ src = gen_rtx_PLUS (Pmode, sum1, sum2); src = legitimize_la_operand (src); emit_insn (gen_rtx_SET (VOIDmode, target, src));}/* Decompose a RTL expression ADDR for a memory address into its components, returned in OUT. The boolean STRICT specifies whether strict register checking applies. 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, strict) register rtx addr; struct s390_address *out; int strict;{ 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 */ /* 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 ((strict && ! REG_OK_FOR_BASE_STRICT_P (base)) || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base))) 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) || (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 ((strict && ! REG_OK_FOR_BASE_STRICT_P (indx)) || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (indx))) 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) || (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 (INTVAL (disp) < 0 || INTVAL (disp) >= 4096) return FALSE; } /* In the small-PIC case, the linker converts @GOT12 offsets to possible displacements. */ else if (GET_CODE (disp) == CONST && GET_CODE (XEXP (disp, 0)) == UNSPEC && XINT (XEXP (disp, 0), 1) == 110) { 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; /* In 64-bit PIC mode we cannot accept symbolic constants in the constant pool. */ if (TARGET_64BIT && flag_pic && SYMBOLIC_CONST (get_pool_constant (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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?