Evgeny Karpov <evgeny.kar...@microsoft.com> writes:
> This patch allows using an offset of up to 16MB in "symbol + offset",
> instead of 1MB limit that was used previously.
>
> gcc/ChangeLog:
>
>       * config/aarch64/aarch64.cc (aarch64_load_symref_appropriately):
>       Update.
> ---
>  gcc/config/aarch64/aarch64.cc | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 62a154e5083..d66591899f8 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -2971,6 +2971,25 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm,
>         tmp_reg = gen_reg_rtx (mode);
>  
>       emit_move_insn (tmp_reg, gen_rtx_HIGH (mode, copy_rtx (imm)));
> +
> +     if (TARGET_PECOFF)
> +       {
> +         poly_int64 offset;
> +         HOST_WIDE_INT const_offset;
> +         strip_offset (imm, &offset);
> +
> +         if (offset.is_constant (&const_offset)
> +             && abs_hwi (const_offset) >= 1 << 20)
> +           {
> +             rtx const_int = imm;
> +             const_int = XEXP (const_int, 0);
> +             XEXP (const_int, 1) = GEN_INT (const_offset % (1 << 20));
> +
> +             emit_set_insn (tmp_reg, plus_constant (mode, tmp_reg,
> +                            const_offset & ~0xfffff));
> +           }
> +       }
> +
>       emit_insn (gen_add_losym (dest, tmp_reg, imm));
>       return;
>        }

Could you try the following alternative:

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 00bcf18ae97..b82ebf19cd6 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -3002,7 +3002,22 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm,
        if (can_create_pseudo_p ())
          tmp_reg = gen_reg_rtx (mode);
 
+       HOST_WIDE_INT mid_const = 0;
+       if (TARGET_PECOFF)
+         {
+           poly_int64 offset;
+           strip_offset (imm, &offset);
+
+           HOST_WIDE_INT const_offset;
+           if (offset.is_constant (&const_offset))
+             /* Written this way for the sake of negative offsets.  */
+             mid_const = const_offset / (1 << 20) * (1 << 20);
+         }
+       imm = plus_constant (mode, imm, -mid_const);
+
        emit_move_insn (tmp_reg, gen_rtx_HIGH (mode, copy_rtx (imm)));
+       if (mid_const)
+         emit_set_insn (tmp_reg, plus_constant (mode, tmp_reg, mid_const));
        emit_insn (gen_add_losym (dest, tmp_reg, imm));
        return;
       }

(completely untested!)  The reasons for preferring this are:

(1) It means that the HIGH and LO_SUM agree on what the immediate is.
    In other words, we adjust both the HIGH and the LO_SUM, rather than
    just the LO_SUM.

(2) We avoid having to alter existing rtxes using XEXP.

(3) It looks like it should cope better with negative offsets (which are
    possible in some cases).

OK like that if it works.

Thanks,
Richard

Reply via email to