📄 s390.c
字号:
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;{ return s390_decompose_address (addr, NULL, strict);}/* Return 1 if OP is a valid operand for the LA instruction. In 31-bit, we need to prove that the result is used as an address, as LA performs only a 31-bit addition. */intlegitimate_la_operand_p (op) register rtx op;{ struct s390_address addr; if (!s390_decompose_address (op, &addr, FALSE)) return FALSE; if (TARGET_64BIT || addr.pointer) return TRUE; return FALSE;}/* Return a modified variant of OP that is guaranteed to be accepted by legitimate_la_operand_p. */rtxlegitimize_la_operand (op) register rtx op;{ struct s390_address addr; if (!s390_decompose_address (op, &addr, FALSE)) abort (); if (TARGET_64BIT || addr.pointer) return op; if (!addr.base) abort (); op = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr.base), 101); if (addr.indx) op = gen_rtx_PLUS (Pmode, op, addr.indx); if (addr.disp) op = gen_rtx_PLUS (Pmode, op, addr.disp); return op; }/* Return a legitimate reference for ORIG (an address) using the register REG. If REG is 0, a new pseudo is generated. There are two types of references that must be handled: 1. Global data references must load the address from the GOT, via the PIC reg. An insn is emitted to do this load, and the reg is returned. 2. Static data references, constant pool addresses, and code labels compute the address as an offset from the GOT, whose base is in the PIC reg. Static data objects have SYMBOL_REF_FLAG set to differentiate them from global data objects. The returned address is the PIC reg + an unspec constant. GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC reg also appears in the address. */rtxlegitimize_pic_address (orig, reg) rtx orig; rtx reg;{ rtx addr = orig; rtx new = orig; rtx base; if (GET_CODE (addr) == LABEL_REF || (GET_CODE (addr) == SYMBOL_REF && (SYMBOL_REF_FLAG (addr) || CONSTANT_POOL_ADDRESS_P (addr)))) { /* This is a local symbol. */ if (TARGET_64BIT) { /* Access local symbols PC-relative via LARL. This is the same as in the non-PIC case, so it is handled automatically ... */ } else { /* Access local symbols relative to the literal pool. */ rtx temp = reg? reg : gen_reg_rtx (Pmode); addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, addr), 100); addr = gen_rtx_CONST (SImode, addr); addr = force_const_mem (SImode, addr); emit_move_insn (temp, addr); base = gen_rtx_REG (Pmode, BASE_REGISTER); base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101); new = gen_rtx_PLUS (Pmode, base, temp); if (reg != 0) { emit_move_insn (reg, new); new = reg; } } } else if (GET_CODE (addr) == SYMBOL_REF) { if (reg == 0) reg = gen_reg_rtx (Pmode); if (flag_pic == 1) { /* Assume GOT offset < 4k. This is handled the same way in both 31- and 64-bit code (@GOT12). */ current_function_uses_pic_offset_table = 1; new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 110); new = gen_rtx_CONST (Pmode, new); new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); new = gen_rtx_MEM (Pmode, new); RTX_UNCHANGING_P (new) = 1; emit_move_insn (reg, new); new = reg; } else if (TARGET_64BIT) { /* If the GOT offset might be >= 4k, we determine the position of the GOT entry via a PC-relative LARL (@GOTENT). */ rtx temp = gen_reg_rtx (Pmode); new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 111); new = gen_rtx_CONST (Pmode, new); emit_move_insn (temp, new); new = gen_rtx_MEM (Pmode, temp); RTX_UNCHANGING_P (new) = 1; emit_move_insn (reg, new); new = reg; } else { /* If the GOT offset might be >= 4k, we have to load it from the literal pool (@GOT). */ rtx temp = gen_reg_rtx (Pmode); current_function_uses_pic_offset_table = 1; addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, addr), 112); addr = gen_rtx_CONST (SImode, addr); addr = force_const_mem (SImode, addr); emit_move_insn (temp, addr); new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp); new = gen_rtx_MEM (Pmode, new); RTX_UNCHANGING_P (new) = 1; emit_move_insn (reg, new); new = reg; } } else { if (GET_CODE (addr) == CONST) { addr = XEXP (addr, 0); if (GET_CODE (addr) == UNSPEC) { if (XVECLEN (addr, 0) != 1) abort (); switch (XINT (addr, 1)) { /* If someone moved an @GOT or lt-relative UNSPEC out of the literal pool, force them back in. */ case 100: case 112: case 114: new = force_const_mem (SImode, orig); break; /* @GOTENT is OK as is. */ case 111: break; /* @PLT is OK as is on 64-bit, must be converted to lt-relative PLT on 31-bit. */ case 113: if (!TARGET_64BIT) { rtx temp = reg? reg : gen_reg_rtx (Pmode); addr = XVECEXP (addr, 0, 0); addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, addr), 114); addr = gen_rtx_CONST (SImode, addr); addr = force_const_mem (SImode, addr); emit_move_insn (temp, addr); base = gen_rtx_REG (Pmode, BASE_REGISTER); base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101); new = gen_rtx_PLUS (Pmode, base, temp); if (reg != 0) { emit_move_insn (reg, new); new = reg; } } break; /* Everything else cannot happen. */ default: abort (); } } else if (GET_CODE (addr) != PLUS) abort (); } if (GET_CODE (addr) == PLUS) { rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1); /* Check first to see if this is a constant offset from a local symbol reference. */ if ((GET_CODE (op0) == LABEL_REF || (GET_CODE (op0) == SYMBOL_REF && (SYMBOL_REF_FLAG (op0) || CONSTANT_POOL_ADDRESS_P (op0)))) && GET_CODE (op1) == CONST_INT) { if (TARGET_64BIT) { if (INTVAL (op1) & 1) { /* LARL can't handle odd offsets, so emit a pair of LARL and LA. */ rtx temp = reg? reg : gen_reg_rtx (Pmode); if (INTVAL (op1) < 0 || INTVAL (op1) >= 4096) { int even = INTVAL (op1) - 1; op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even)); op0 = gen_rtx_CONST (Pmode, op0); op1 = GEN_INT (1); } emit_move_insn (temp, op0); new = gen_rtx_PLUS (Pmode, temp, op1); if (reg != 0) { emit_move_insn (reg, new); new = reg; } } else { /* If the offset is even, we can just use LARL. This will happen automatically. */ } } else { /* Access local symbols relative to the literal pool. */ rtx temp = reg? reg : gen_reg_rtx (Pmode); addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, op0), 100); addr = gen_rtx_PLUS (SImode, addr, op1); addr = gen_rtx_CONST (SImode, addr); addr = force_const_mem (SImode, addr); emit_move_insn (temp, addr); base = gen_rtx_REG (Pmode, BASE_REGISTER); base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), 101); new = gen_rtx_PLUS (Pmode, base, temp); if (reg != 0) { emit_move_insn (reg, new); new = reg; } } } /* Now, check whether it is an LT-relative symbol plus offset that was pulled out of the literal pool. Force it back in. */ else if (GET_CODE (op0) == UNSPEC && GET_CODE (op1) == CONST_INT) { if (XVECLEN (op0, 0) != 1) abort (); if (XINT (op0, 1) != 100) abort (); new = force_const_mem (SImode, orig); } /* Otherwise, compute the sum. */ else { base = legitimize_pic_address (XEXP (addr, 0), reg); new = legitimize_pic_address (XEXP (addr, 1), base == reg ? NULL_RTX : reg); if (GET_CODE (new) == CONST_INT) new = plus_constant (base, INTVAL (new)); else { if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1))) { base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0)); new = XEXP (new, 1); } new = gen_rtx_PLUS (Pmode, base, new); } if (GET_CODE (new) == CONST) new = XEXP (new, 0); new = force_operand (new, 0); } } } return new;}/* Emit insns to move operands[1] into operands[0]. */voidemit_pic_move (operands, mode) rtx *operands; enum machine_mode mode ATTRIBUTE_UNUSED;{ rtx temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1])) operands[1] = force_reg (Pmode, operands[1]); else operands[1] = legitimize_pic_address (operands[1], temp);}/* Try machine-dependent ways of modifying an illegitimate address X to be legitimate. If we find one, return the new, valid address. OLDX is the address as it was before break_out_memory_refs was called. In some cases it is useful to look at this to decide what needs to be done. MODE is the mode of the operand pointed to by X. When -fpic is used, special handling is needed for symbolic references. See comments by legitimize_pic_address for details. */rtxlegitimize_address (x, oldx, mode) register rtx x; register rtx oldx ATTRIBUTE_UNUSED; enum machine_mode mode ATTRIBUTE_UNUSED;{ rtx constant_term = const0_rtx; if (flag_pic) { if (SYMBOLIC_CONST (x) || (GET_CODE (x) == PLUS && (SYMBOLIC_CONST (XEXP (x, 0)) || SYMBOLIC_CONST (XEXP (x, 1))))) x = legitimize_pic_address (x, 0); if (legitimate_address_p (mode, x, FALSE)) return x; } x = eliminate_constant_term (x, &constant_term); if (GET_CODE (x) == PLUS) { if (GET_CODE (XEXP (x, 0)) == REG) { register rtx temp = gen_reg_rtx (Pmode); register rtx val = force_operand (XEXP (x, 1), temp); if (val != temp) emit_move_insn (temp, val); x = gen_rtx_PLUS (Pmode, XEXP (x, 0), temp); } else if (GET_CODE (XEXP (x, 1)) == REG) { register rtx temp = gen_reg_rtx (Pmode); register rtx val = force_operand (XEXP (x, 0), temp); if (val != temp) emit_move_insn (temp, val); x = gen_rtx_PLUS (Pmode, temp, XEXP (x, 1)); } } if (constant_term != const0_rtx) x = gen_rtx_PLUS (Pmode, x, constant_term); return x;}/* In the name of slightly smaller debug output, and to cater to general assembler losage, recognize various UNSPEC sequences and turn them back into a direct symbol reference. */rtxs390_simplify_dwarf_addr (orig_x) rtx orig_x;{ rtx x = orig_x, y; if (GET_CODE (x) != MEM) return orig_x; x = XEXP (x, 0); if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST && GET_CODE (XEXP (x, 0)) == REG && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM) { y = XEXP (XEXP (x, 1), 0); if (GET_CODE (y) == UNSPEC && XINT (y, 1) == 110) return XVECEXP (y, 0, 0); return orig_x; } if (GET_CODE (x) == CONST) { y = XEXP (x, 0); if (GET_CODE (y) == UNSPEC && XINT (y, 1) == 111) return XVECEXP (y, 0, 0); return orig_x; } return orig_x; }/* Output symbolic constant X in assembler syntax to stdio stream FILE. */voids390_output_symbolic_const (file, x) FILE *file; rtx x;{ switch (GET_CODE (x)) { case CONST: case ZERO_EXTEND: case SIGN_EXTEND: s390_output_symbolic_const (file, XEXP (x, 0)); break; case PLUS: s390_output_symbolic_const (file, XEXP (x, 0)); fprintf (file, "+"); s390_output_symbolic_const (file, XEXP (x, 1)); break; case MINUS: s390_output_symbolic_const (file, XEXP (x, 0)); fprintf (file, "-"); s390_output_symbolic_const (file, XEXP (x, 1)); break; case CONST_INT: case LABEL_REF:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -