@@ -9351,6 +9351,8 @@ aarch64_classify_symbol (rtx x, rtx offset)
if (aarch64_tls_symbol_p (x))
return aarch64_classify_tls_symbol (x);
+ const_tree decl = SYMBOL_REF_DECL (x);
+
switch (aarch64_cmodel)
{
case AARCH64_CMODEL_TINY:
@@ -9359,25 +9361,45 @@ aarch64_classify_symbol (rtx x, rtx offset)
we have no way of knowing the address of symbol at compile time
so we can't accurately say if the distance between the PC and
symbol + offset is outside the addressible range of +/-1M in the
- TINY code model. So we rely on images not being greater than
- 1M and cap the offset at 1M and anything beyond 1M will have to
- be loaded using an alternative mechanism. Furthermore if the
- symbol is a weak reference to something that isn't known to
- resolve to a symbol in this module, then force to memory. */
+ TINY code model. So we limit the maximum offset to +/-64KB and
+ assume the offset to the symbol is not larger than +/-(1M - 64KB).
+ Furthermore force to memory if the symbol is a weak reference to
+ something that doesn't resolve to a symbol in this module. */
if ((SYMBOL_REF_WEAK (x)
&& !aarch64_symbol_binds_local_p (x))
- || INTVAL (offset) < -1048575 || INTVAL (offset) > 1048575)
+ || !IN_RANGE (INTVAL (offset), -0x10000, 0x10000))
return SYMBOL_FORCE_TO_MEM;
+
+ /* Limit offset to within the size of a declaration if available. */
+ if (decl && DECL_P (decl))
+ {
+ const_tree decl_size = DECL_SIZE (decl);
+
+ if (decl_size
+ && !IN_RANGE (INTVAL (offset), 0, tree_to_shwi (decl_size)))
+ return SYMBOL_FORCE_TO_MEM;
+ }
+
return SYMBOL_TINY_ABSOLUTE;
case AARCH64_CMODEL_SMALL:
/* Same reasoning as the tiny code model, but the offset cap here is
- 4G. */
+ 1G, allowing +/-3G for the offset to the symbol. */
if ((SYMBOL_REF_WEAK (x)
&& !aarch64_symbol_binds_local_p (x))
- || !IN_RANGE (INTVAL (offset), HOST_WIDE_INT_C (-4294967263),
- HOST_WIDE_INT_C (4294967264)))
+ || !IN_RANGE (INTVAL (offset), -0x40000000, 0x40000000))
return SYMBOL_FORCE_TO_MEM;
+
+ /* Limit offset to within the size of a declaration if available. */
+ if (decl && DECL_P (decl))
+ {
+ const_tree decl_size = DECL_SIZE (decl);
+
+ if (decl_size
+ && !IN_RANGE (INTVAL (offset), 0, tree_to_shwi (decl_size)))
+ return SYMBOL_FORCE_TO_MEM;
+ }
+
return SYMBOL_SMALL_ABSOLUTE;
case AARCH64_CMODEL_TINY_PIC:
@@ -1,12 +1,12 @@
-/* { dg-do compile } */
+/* { dg-do link } */
/* { dg-options "-O3 -save-temps -mcmodel=tiny" } */
-int fixed_regs[0x00200000];
+char fixed_regs[0x00200000];
int
-foo()
+main()
{
- return fixed_regs[0x00080000];
+ return fixed_regs[0x000ff000];
}
/* { dg-final { scan-assembler-not "adr\tx\[0-9\]+, fixed_regs\\\+" } } */
@@ -1,12 +1,12 @@
-/* { dg-do compile } */
+/* { dg-do link } */
/* { dg-options "-O3 -save-temps -mcmodel=small" } */
-int fixed_regs[0x200000000ULL];
+char fixed_regs[0x200000000ULL];
int
-foo()
+main()
{
- return fixed_regs[0x100000000ULL];
+ return fixed_regs[0xfffff000ULL];
}
/* { dg-final { scan-assembler-not "adrp\tx\[0-9\]+, fixed_regs\\\+" } } */