📄 pa.c
字号:
rtx const_part = NULL; /* Argh. The assembler and linker can't handle arithmetic involving plabels. We'll have to split up operand1 here if it's a function label involved in an arithmetic expression. Luckily, this only happens with addition of constants to plabels, which simplifies the test. We add the constant back in just before returning to our caller. */ if (GET_CODE (operand1) == CONST && GET_CODE (XEXP (operand1, 0)) == PLUS && function_label_operand (XEXP (XEXP (operand1, 0), 0), Pmode)) { /* Save away the constant part of the expression. */ const_part = XEXP (XEXP (operand1, 0), 1); if (GET_CODE (const_part) != CONST_INT) abort (); /* Set operand1 to just the SYMBOL_REF. */ operand1 = XEXP (XEXP (operand1, 0), 0); } if (flag_pic) { rtx temp; if (reload_in_progress || reload_completed) temp = scratch_reg ? scratch_reg : operand0; else temp = gen_reg_rtx (Pmode); /* If operand1 is a function label, then we've got to force it to memory, then load op0 from memory. */ if (function_label_operand (operand1, mode)) { operands[1] = force_const_mem (mode, operand1); emit_move_sequence (operands, mode, temp); } /* Likewise for (const (plus (symbol) (const_int)) when generating pic code during or after reload and const_int will not fit in 14 bits. */ else if (GET_CODE (operand1) == CONST && GET_CODE (XEXP (operand1, 0)) == PLUS && GET_CODE (XEXP (XEXP (operand1, 0), 1)) == CONST_INT && !INT_14_BITS (XEXP (XEXP (operand1, 0), 1)) && (reload_completed || reload_in_progress) && flag_pic) { operands[1] = force_const_mem (mode, operand1); operands[1] = legitimize_pic_address (XEXP (operands[1], 0), mode, temp); emit_move_sequence (operands, mode, temp); } else { operands[1] = legitimize_pic_address (operand1, mode, temp); emit_insn (gen_rtx (SET, VOIDmode, operand0, operands[1])); } } /* On the HPPA, references to data space are supposed to use dp, register 27, but showing it in the RTL inhibits various cse and loop optimizations. */ else { rtx temp, set; if (reload_in_progress || reload_completed) temp = scratch_reg ? scratch_reg : operand0; else temp = gen_reg_rtx (mode); if (ishighonly) set = gen_rtx (SET, mode, operand0, temp); else set = gen_rtx (SET, VOIDmode, operand0, gen_rtx (LO_SUM, mode, temp, operand1)); emit_insn (gen_rtx (SET, VOIDmode, temp, gen_rtx (HIGH, mode, operand1))); emit_insn (set); } /* Add back in the constant part if needed. */ if (const_part != NULL) expand_inc (operand0, const_part); return 1; } else if (GET_CODE (operand1) != CONST_INT || ! cint_ok_for_move (INTVAL (operand1))) { rtx temp; if (reload_in_progress || reload_completed) temp = operand0; else temp = gen_reg_rtx (mode); emit_insn (gen_rtx (SET, VOIDmode, temp, gen_rtx (HIGH, mode, operand1))); operands[1] = gen_rtx (LO_SUM, mode, temp, operand1); } } /* Now have insn-emit do whatever it normally does. */ return 0;}/* Does operand (which is a symbolic_operand) live in text space? If so SYMBOL_REF_FLAG, which is set by ENCODE_SECTION_INFO, will be true. */intread_only_operand (operand) rtx operand;{ if (GET_CODE (operand) == CONST) operand = XEXP (XEXP (operand, 0), 0); if (flag_pic) { if (GET_CODE (operand) == SYMBOL_REF) return SYMBOL_REF_FLAG (operand) && !CONSTANT_POOL_ADDRESS_P (operand); } else { if (GET_CODE (operand) == SYMBOL_REF) return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand); } return 1;}/* Return the best assembler insn template for moving operands[1] into operands[0] as a fullword. */char *singlemove_string (operands) rtx *operands;{ HOST_WIDE_INT intval; if (GET_CODE (operands[0]) == MEM) return "stw %r1,%0"; if (GET_CODE (operands[1]) == MEM) return "ldw %1,%0"; if (GET_CODE (operands[1]) == CONST_DOUBLE) { long i; REAL_VALUE_TYPE d; if (GET_MODE (operands[1]) != SFmode) abort (); /* Translate the CONST_DOUBLE to a CONST_INT with the same target bit pattern. */ REAL_VALUE_FROM_CONST_DOUBLE (d, operands[1]); REAL_VALUE_TO_TARGET_SINGLE (d, i); operands[1] = GEN_INT (i); /* Fall through to CONST_INT case. */ } if (GET_CODE (operands[1]) == CONST_INT) { intval = INTVAL (operands[1]); if (VAL_14_BITS_P (intval)) return "ldi %1,%0"; else if ((intval & 0x7ff) == 0) return "ldil L'%1,%0"; else if (zdepi_cint_p (intval)) return "zdepi %Z1,%0"; else return "ldil L'%1,%0\n\tldo R'%1(%0),%0"; } return "copy %1,%0";}/* Compute position (in OP[1]) and width (in OP[2]) useful for copying IMM to a register using the zdepi instructions. Store the immediate value to insert in OP[0]. */voidcompute_zdepi_operands (imm, op) unsigned HOST_WIDE_INT imm; unsigned *op;{ int lsb, len; /* Find the least significant set bit in IMM. */ for (lsb = 0; lsb < 32; lsb++) { if ((imm & 1) != 0) break; imm >>= 1; } /* Choose variants based on *sign* of the 5-bit field. */ if ((imm & 0x10) == 0) len = (lsb <= 28) ? 4 : 32 - lsb; else { /* Find the width of the bitstring in IMM. */ for (len = 5; len < 32; len++) { if ((imm & (1 << len)) == 0) break; } /* Sign extend IMM as a 5-bit value. */ imm = (imm & 0xf) - 0x10; } op[0] = imm; op[1] = 31 - lsb; op[2] = len;}/* Output assembler code to perform a doubleword move insn with operands OPERANDS. */char *output_move_double (operands) rtx *operands;{ enum { REGOP, OFFSOP, MEMOP, CNSTOP, RNDOP } optype0, optype1; rtx latehalf[2]; rtx addreg0 = 0, addreg1 = 0; /* First classify both operands. */ if (REG_P (operands[0])) optype0 = REGOP; else if (offsettable_memref_p (operands[0])) optype0 = OFFSOP; else if (GET_CODE (operands[0]) == MEM) optype0 = MEMOP; else optype0 = RNDOP; if (REG_P (operands[1])) optype1 = REGOP; else if (CONSTANT_P (operands[1])) optype1 = CNSTOP; else if (offsettable_memref_p (operands[1])) optype1 = OFFSOP; else if (GET_CODE (operands[1]) == MEM) optype1 = MEMOP; else optype1 = RNDOP; /* Check for the cases that the operand constraints are not supposed to allow to happen. Abort if we get one, because generating code for these cases is painful. */ if (optype0 != REGOP && optype1 != REGOP) abort (); /* Handle auto decrementing and incrementing loads and stores specifically, since the structure of the function doesn't work for them without major modification. Do it better when we learn this port about the general inc/dec addressing of PA. (This was written by tege. Chide him if it doesn't work.) */ if (optype0 == MEMOP) { /* We have to output the address syntax ourselves, since print_operand doesn't deal with the addresses we want to use. Fix this later. */ rtx addr = XEXP (operands[0], 0); if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC) { rtx high_reg = gen_rtx (SUBREG, SImode, operands[1], 0); operands[0] = XEXP (addr, 0); if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG) abort (); if (!reg_overlap_mentioned_p (high_reg, addr)) { /* No overlap between high target register and address register. (We do this in a non-obvious way to save a register file writeback) */ if (GET_CODE (addr) == POST_INC) return "stws,ma %1,8(0,%0)\n\tstw %R1,-4(0,%0)"; return "stws,ma %1,-8(0,%0)\n\tstw %R1,12(0,%0)"; } else abort(); } else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC) { rtx high_reg = gen_rtx (SUBREG, SImode, operands[1], 0); operands[0] = XEXP (addr, 0); if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG) abort (); if (!reg_overlap_mentioned_p (high_reg, addr)) { /* No overlap between high target register and address register. (We do this in a non-obvious way to save a register file writeback) */ if (GET_CODE (addr) == PRE_INC) return "stws,mb %1,8(0,%0)\n\tstw %R1,4(0,%0)"; return "stws,mb %1,-8(0,%0)\n\tstw %R1,4(0,%0)"; } else abort(); } } if (optype1 == MEMOP) { /* We have to output the address syntax ourselves, since print_operand doesn't deal with the addresses we want to use. Fix this later. */ rtx addr = XEXP (operands[1], 0); if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC) { rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], 0); operands[1] = XEXP (addr, 0); if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG) abort (); if (!reg_overlap_mentioned_p (high_reg, addr)) { /* No overlap between high target register and address register. (We do this in a non-obvious way to save a register file writeback) */ if (GET_CODE (addr) == POST_INC) return "ldws,ma 8(0,%1),%0\n\tldw -4(0,%1),%R0"; return "ldws,ma -8(0,%1),%0\n\tldw 12(0,%1),%R0"; } else { /* This is an undefined situation. We should load into the address register *and* update that register. Probably we don't need to handle this at all. */ if (GET_CODE (addr) == POST_INC) return "ldw 4(0,%1),%R0\n\tldws,ma 8(0,%1),%0"; return "ldw 4(0,%1),%R0\n\tldws,ma -8(0,%1),%0"; } } else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC) { rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], 0); operands[1] = XEXP (addr, 0); if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG) abort (); if (!reg_overlap_mentioned_p (high_reg, addr)) { /* No overlap between high target register and address register. (We do this in a non-obvious way to save a register file writeback) */ if (GET_CODE (addr) == PRE_INC) return "ldws,mb 8(0,%1),%0\n\tldw 4(0,%1),%R0"; return "ldws,mb -8(0,%1),%0\n\tldw 4(0,%1),%R0"; } else { /* This is an undefined situation. We should load into the address register *and* update that register. Probably we don't need to handle this at all. */ if (GET_CODE (addr) == PRE_INC) return "ldw 12(0,%1),%R0\n\tldws,mb 8(0,%1),%0"; return "ldw -4(0,%1),%R0\n\tldws,mb -8(0,%1),%0"; } } } /* If an operand is an unoffsettable memory ref, find a register we can increment temporarily to make it refer to the second word. */ if (optype0 == MEMOP) addreg0 = find_addr_reg (XEXP (operands[0], 0)); if (optype1 == MEMOP) addreg1 = find_addr_reg (XEXP (operands[1], 0)); /* Ok, we can do one word at a time. Normally we do the low-numbered word first. In either case, set up in LATEHALF the operands to use for the high-numbered word and in some cases alter the operands in OPERANDS to be suitable for the low-numbered word. */ if (optype0 == REGOP) latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); else if (optype0 == OFFSOP) latehalf[0] = adj_offsettable_operand (operands[0], 4); else latehalf[0] = operands[0]; if (optype1 == REGOP) latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); else if (optype1 == OFFSOP) latehalf[1] = adj_offsettable_operand (operands[1], 4); else if (optype1 == CNSTOP) split_double (operands[1], &operands[1], &latehalf[1]); else latehalf[1] = operands[1]; /* If the first move would clobber the source of the second one, do them in the other order. RMS says "This happens only for registers; such overlap can't happen in memory unless the user explicitly sets it up, and that is an undefined circumstance." but it happens on the HP-PA when loading parameter registers, so I am going to define that circumstance, and make it work as expected. */ if (optype0 == REGOP && (optype1 == MEMOP || optype1 == OFFSOP) && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0))) { /* XXX THIS PROBABLY DOESN'T WORK. */ /* Do the late half first. */ if (addreg1) output_asm_insn ("ldo 4(%0),%0", &addreg1); output_asm_insn (singlemove_string (latehalf), latehalf); if (addreg1) output_asm_insn ("ldo -4(%0),%0", &addreg1); /* Then clobber. */ return singlemove_string (operands); } if (optype0 == REGOP && optype1 == REGOP && REGNO (operands[0]) == REGNO (operands[1]) + 1) { output_asm_insn (singlemove_string (latehalf), latehalf); return singlemove_string (operands); } /* Normal case: do the two words, low-numbered first. */ output_asm_insn (singlemove_string (operands), operands); /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) output_asm_insn ("ldo 4(%0),%0", &addreg0); if (addreg1) output_asm_insn ("ldo 4(%0),%0", &addreg1); /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); /* Undo the adds we just did. */ if (addreg0) output_asm_insn ("ldo -4(%0),%0", &addreg0); if (addreg1) output_asm_insn ("ldo -4(%0),%0", &addreg1); return "";}char *output_fp_move_double (operands) rtx *operands;{ if (FP_REG_P (operands[0])) { if (FP_REG_P (operands[1]) || operands[1] == CONST0_RTX (GET_MODE (operands[0]))) output_asm_insn ("fcpy,dbl %r1,%0", operands); else output_asm_insn ("fldds%F1 %1,%0", operands);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -