Tested on hppa-unknown-linux-gnu and hppa64-hp-hpux11.11. Committed to trunk.
Dave --- hppa: Fix various secondary reload issues with LRA While commit 1887cd4b8fd0 fixed some reload issues on hppa, it exposed some new issues. For the most part, these involve the handling of floating-point loads and stores. The first issue was secondary reloads for SImode/SFmode puns were not handled correctly and we got a SIGSEGV for stack growth in a few compilations. I looked at handling these reloads. In the worst case we needed to allocate a stack slot and a scratch register. It takes up to three insns to load the slot address and two insns to copy the value through memory. I decided in the end that it was better to block cross-class type punning for modes that can reside in a single float register. We have to allow large integer/float mode changes on 64-bit HP-UX. It has a software emulated long double. We also need to allow these mode changes after reload as pa_output_move_double uses DImode to SImode type punning. Otherwise, type punning is prohibitted in the general register classes and classes that intersect the FP registers. By preventing cross-class type punning in pa_can_change_mode_class, we were able to remove the code that attempted to handle secondary reloads for type punned modes. All that is left is code to strip SUBREG wrappers on entry. In the process of working on how to fix the cross-class type punning issue, I noticed that the handling of secondary reloads for REG+D addresses could be improved by handling integer and float reloads separately. Now we only need secondary reloads for out-of-range displacements. After this was implemented, we still had issues with symbolic and constant loads for SFmode and DFmode. We don't have support for naked symbolic or constant loads. This was fixed by adding a new block in pa_emit_move_sequence to explicitly split out the address calculation for these loads. It also handles 64-bit PIC loads. The pa_legitimate_constant_p and pa_legitimate_address_p functions were updated to reject naked symbolic and constant pool SFmode/DFmode addresses on 32-bit targets. 2026-10-10 John David Anglin <[email protected]> gcc/ChangeLog: * config/pa/pa.cc (pa_emit_move_sequence): Handle SFmode and DFmode symbolic, constant pool, or CONST memory references on both 32-bit and 64-bit targets by emitting proper PIC, 14-bit HIGH/LO_SUM, or 1.x fallback move sequences using a scratch register. (pa_secondary_reload): Strip SUBREG early. Update hard-float memory displacement checks to account for 5-bit vs 14-bit constraints on PA 1.x vs PA 2.0. Look through MEM wrappers when evaluating symbolic address expressions. For symbolic address expressions under flag_pic or non-readonly conditions, return R1_REGS for SImode and DImode, but explicitly break out for SFmode and DFmode to let them safely fall back to GENERAL_REGS. Return GENERAL_REGS instead of NO_REGS for shifted and coprocessor/SAR reload fallbacks. (pa_can_change_mode_class): Remove equal-size mode change shortcut. Prevent cross-class type punning between integer and floating-point modes within GENERAL_REGS or R1_REGS before reload is completed. (pa_legitimate_constant_p): Reject out-of-range multi-word constants in DImode on 32-bit targets. Reject naked symbolic or constant pool SFmode and DFmode addresses unconditionally on 32-bit targets, while intentionally allowing fully-formed LO_SUM expressions to preserve PA 2.0 optimizations. (pa_legitimate_address_p): Reject naked symbolic, constant pool, or CONST expressions for SFmode and DFmode unconditionally on 32-bit targets to force a proper HIGH/LO_SUM split or reload. diff --git a/gcc/config/pa/pa.cc b/gcc/config/pa/pa.cc index 88a52d7c0ea..86e1ee548de 100644 --- a/gcc/config/pa/pa.cc +++ b/gcc/config/pa/pa.cc @@ -2229,6 +2229,49 @@ pa_emit_move_sequence (rtx *operands, machine_mode mode, rtx scratch_reg) return 1; } + if ((mode == SFmode || mode == DFmode) + && MEM_P (operand1) + && (scratch_reg || can_create_pseudo_p ()) + && (CONSTANT_POOL_ADDRESS_P (XEXP (operand1, 0)) + || GET_CODE (XEXP (operand1, 0)) == SYMBOL_REF + || GET_CODE (XEXP (operand1, 0)) == CONST)) + { + rtx addr = XEXP (operand1, 0); + rtx scratch; + + if (scratch_reg) + { + scratch = scratch_reg; + if (GET_MODE (scratch) != Pmode) + scratch = gen_rtx_REG (Pmode, REGNO (scratch)); + } + else + scratch = gen_reg_rtx (Pmode); + + if (flag_pic) + { + /* Handle PIC compilations. */ + rtx pic_reg = legitimize_pic_address (addr, Pmode, scratch); + operand1 = replace_equiv_address (operand1, pic_reg); + } + else if (INT14_OK_STRICT) + { + /* Non-PIC 32-bit PA 2.0 targets can use the 14-bit + displacement optimization. */ + emit_insn (gen_rtx_SET (scratch, gen_rtx_HIGH (Pmode, addr))); + operand1 = replace_equiv_address (operand1, + gen_rtx_LO_SUM (Pmode, + scratch, + addr)); + } + else + { + /* 32-bit PA 1.x fallback. */ + emit_move_insn (scratch, addr); + operand1 = replace_equiv_address (operand1, scratch); + } + } + /* Handle the most common case: storing into a register. */ if (register_operand (operand0, mode)) { @@ -6378,54 +6421,54 @@ pa_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, /* Strip the SUBREG to find the true underlying register entity. */ if (GET_CODE (x) == SUBREG) + x = SUBREG_REG (x); + + /* Handle the easy stuff first. */ + if ((rclass == GENERAL_REGS || FP_REG_CLASS_P (rclass)) + && reg_plus_base_memory_operand (x, mode)) { - rtx inner = SUBREG_REG (x); - machine_mode inner_mode = GET_MODE (inner); + /* If we are using soft-float, floating point modes live in the + general registers, meaning they follow the standard 14-bit + integer displacement rules. */ + bool hard_float_fp = (!TARGET_SOFT_FLOAT && FP_REG_CLASS_P (rclass)); - /* Check if we are bridging a 32 or 64-bit Float/Integer Type-Pun. */ - if (REG_P (inner) - && ((mode == DImode && inner_mode == DFmode) - || (mode == DFmode && inner_mode == DImode) - || (mode == SImode && inner_mode == SFmode) - || (mode == SFmode && inner_mode == SImode))) + if (hard_float_fp) { - regno = REGNO (inner); + rtx offset = XEXP (XEXP (x, 0), 1); + + /* PA 1.x hard-float instructions only have a 5-bit displacement. + PA 2.0 expands this to a wider 14-bit displacement range. */ + bool legal_fp_disp = TARGET_PA_20 ? INT_14_BITS (offset) + : INT_5_BITS (offset); - /* If the inner register has not been assigned or is bound - to a floating-point class, we may need a general register - scratchpad to handle the secondary reload. */ - if (regno >= FIRST_PSEUDO_REGISTER - || FP_REG_CLASS_P (REGNO_REG_CLASS (regno))) + if (!legal_fp_disp) { - /* If we need to load/store into an FP register block - but our current instruction class is floating, force - a general register scratchpad. */ - if (FP_REG_CLASS_P (rclass)) - { - sri->icode = (in_p - ? direct_optab_handler (reload_in_optab, mode) - : direct_optab_handler (reload_out_optab, mode)); - return GENERAL_REGS; - } + /* An out-of-range displacement for a hard-float register + requires a general purpose register to fix the address. */ + sri->icode = (in_p + ? direct_optab_handler (reload_in_optab, mode) + : direct_optab_handler (reload_out_optab, mode)); + return GENERAL_REGS; } } + else + { + /* For GENERAL_REGS (and soft-float FP targets), check if the + offset fits the standard 14-bit integer load/store range. */ + rtx offset = XEXP (XEXP (x, 0), 1); - /* Let normal processing handle the un-wrapped inner rtx if needed. */ - x = inner; - } + if (!INT_14_BITS (offset) && (mode == SImode || mode == DImode)) + { + sri->icode = (in_p + ? direct_optab_handler (reload_in_optab, mode) + : direct_optab_handler (reload_out_optab, mode)); - /* Handle the easy stuff first. */ - if ((rclass == GENERAL_REGS || FP_REG_CLASS_P (rclass)) - && reg_plus_base_memory_operand (x, mode)) - { - /* Guard this fallback check against narrow modes. This guarantees - QImode/HImode will completely bypass direct_optab_handler loops. */ - if (mode == SImode || mode == DImode) - sri->icode = (in_p - ? direct_optab_handler (reload_in_optab, mode) - : direct_optab_handler (reload_out_optab, mode)); - else - sri->icode = CODE_FOR_nothing; + /* Let expander use its internal clobber */ + return NO_REGS; + } + } + + sri->icode = CODE_FOR_nothing; return NO_REGS; } @@ -6476,33 +6519,40 @@ pa_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, default: gcc_unreachable (); } - return NO_REGS; + return R1_REGS; } - /* Secondary reloads of symbolic expressions require %r1 as a scratch - register when we're generating PIC code or when the operand isn't - readonly. */ - if (pa_symbolic_expression_p (x)) + /* If we are given a MEM wrapper, look through it to extract the true + underlying address entity. */ + rtx addr = MEM_P (x) ? XEXP (x, 0) : x; + + /* Secondary reloads of symbolic address expressions require %r1 as a + scratch register when we're generating PIC code or when the operand + isn't readonly. */ + if (pa_symbolic_expression_p (addr)) { - if (GET_CODE (x) == HIGH) - x = XEXP (x, 0); + if (GET_CODE (addr) == HIGH) + addr = XEXP (addr, 0); - if (flag_pic || !read_only_operand (x, VOIDmode)) + if (flag_pic || !read_only_operand (addr, VOIDmode)) { switch (mode) { case E_SImode: sri->icode = CODE_FOR_reload_insi_r1; - break; + return R1_REGS; case E_DImode: sri->icode = CODE_FOR_reload_indi_r1; + return R1_REGS; + + case E_SFmode: + case E_DFmode: break; default: gcc_unreachable (); } - return NO_REGS; } } @@ -6533,7 +6583,7 @@ pa_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, sri->icode = (in_p ? direct_optab_handler (reload_in_optab, mode) : direct_optab_handler (reload_out_optab, mode)); - return NO_REGS; + return GENERAL_REGS; } /* A SAR<->FP register copy requires an intermediate general register @@ -6553,7 +6603,7 @@ pa_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, sri->icode = (in_p ? direct_optab_handler (reload_in_optab, mode) : direct_optab_handler (reload_out_optab, mode)); - return NO_REGS; + return GENERAL_REGS; } /* Handle FP copy. */ @@ -10572,9 +10622,6 @@ pa_can_change_mode_class (machine_mode from, machine_mode to, if (from == to) return true; - if (GET_MODE_SIZE (from) == GET_MODE_SIZE (to)) - return true; - /* Reject changes to/from modes with zero size. */ if (!GET_MODE_SIZE (from) || !GET_MODE_SIZE (to)) return false; @@ -10584,6 +10631,20 @@ pa_can_change_mode_class (machine_mode from, machine_mode to, || COMPLEX_MODE_P (to) || VECTOR_MODE_P (to)) return false; + /* Prevent cross-class type punning impacting the general registers + before reload completes. If the allocator is forced to use + GENERAL_REGS, disallow the mode change so it forces a proper + instruction breakdown. */ + if ((rclass == GENERAL_REGS || rclass == R1_REGS) + && !reload_completed + && GET_MODE_SIZE (to) <= GET_MODE_SIZE (DFmode) + && GET_MODE_SIZE (from) <= GET_MODE_SIZE (DFmode) + && ((GET_MODE_CLASS (from) == MODE_INT + && GET_MODE_CLASS (to) == MODE_FLOAT) + || (GET_MODE_CLASS (from) == MODE_FLOAT + && GET_MODE_CLASS (to) == MODE_INT))) + return false; + /* There is no way to load QImode or HImode values directly from memory to a FP register. SImode loads to the FP registers are not zero extended. On the 64-bit target, this conflicts with the definition @@ -10937,6 +10998,40 @@ pa_function_section (tree decl, enum node_frequency freq, static bool pa_legitimate_constant_p (machine_mode mode, rtx x) { + /* Fix early multi-word constant leaks on 32-bit targets. */ + if (!TARGET_64BIT + && mode == DImode + && CONST_INT_P (x) + && !INT_14_BITS (x)) + return false; + + /* Reject naked symbolic and constant pool SF and DF mode addresses + unconditionally on 32-bit targets. We intentionally do not unwrap + LO_SUM expressions here, as those are valid address calculations + for 14-bit displacement optimizations on PA 2.0. */ + if (!TARGET_64BIT && (mode == SFmode || mode == DFmode)) + { + rtx base = x; + if (GET_CODE (base) == PLUS) + { + /* Check both components of the addition for symbolic links. */ + rtx op0 = XEXP (base, 0); + rtx op1 = XEXP (base, 1); + if (GET_CODE (op0) == SYMBOL_REF || GET_CODE (op0) == LABEL_REF + || GET_CODE (op0) == CONST || CONSTANT_POOL_ADDRESS_P (op0) + || GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF + || GET_CODE (op1) == CONST || CONSTANT_POOL_ADDRESS_P (op1)) + return false; + } + + if (GET_CODE (base) == SYMBOL_REF + || GET_CODE (base) == LABEL_REF + || GET_CODE (base) == CONST + || CONSTANT_POOL_ADDRESS_P (base)) + return false; + } + + /* All non-zero float constants are illegitimate. */ if (GET_MODE_CLASS (mode) == MODE_FLOAT && x != CONST0_RTX (mode)) return false; @@ -11140,6 +11235,19 @@ pa_legitimate_address_p (machine_mode mode, rtx x, bool strict, code_helper) return false; } + /* Reject symbolic and constant pool SF and DF mode addresses + unconditionally on 32-bit targets. Even when 14-bit displacements + are active (PA 2.0), naked symbolic addresses cannot be loaded + directly into floating-point registers and must be forced through + a HIGH/LO_SUM split or reload. */ + if (!TARGET_64BIT + && (mode == SFmode || mode == DFmode) + && (GET_CODE (x) == SYMBOL_REF + || GET_CODE (x) == LABEL_REF + || GET_CODE (x) == CONST + || CONSTANT_POOL_ADDRESS_P (x))) + return false; + if (GET_CODE (x) == CONST_INT && INT_5_BITS (x)) return true;
signature.asc
Description: PGP signature
