There's an access within glibc wherein we've forced an important global
variable into the .sdata section (so that accesses to its members can use
16-bit relocations), but an array access gets constant-folded such that we
produce an offset well well outside of a 16-bit range.
A test case that must be visually inspected looks like the following. I'm not
certain how to turn this into a portable link-time test. But considering that
other ports also handle SYMBOL_REF_SMALL_DATA, it does seem like something
portable would be nice. Ideas? Or should I just drop this in as an alpha
specific test?
extern int x[10] __attribute__((visibility("hidden"), section(".sdata")));
int foo(int y)
{
return x[y-100000];
}
Committed the patch itself to mainline and 4.7 branch.
r~
diff --git a/gcc/config/alpha/predicates.md b/gcc/config/alpha/predicates.md
index 598742f..0a1885b 100644
--- a/gcc/config/alpha/predicates.md
+++ b/gcc/config/alpha/predicates.md
@@ -328,26 +328,50 @@
(define_predicate "small_symbolic_operand"
(match_code "const,symbol_ref")
{
+ HOST_WIDE_INT ofs = 0, max_ofs = 0;
+
if (! TARGET_SMALL_DATA)
- return 0;
+ return false;
if (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == PLUS
&& CONST_INT_P (XEXP (XEXP (op, 0), 1)))
- op = XEXP (XEXP (op, 0), 0);
+ {
+ ofs = INTVAL (XEXP (XEXP (op, 0), 1));
+ op = XEXP (XEXP (op, 0), 0);
+ }
if (GET_CODE (op) != SYMBOL_REF)
- return 0;
+ return false;
/* ??? There's no encode_section_info equivalent for the rtl
constant pool, so SYMBOL_FLAG_SMALL never gets set. */
if (CONSTANT_POOL_ADDRESS_P (op))
- return GET_MODE_SIZE (get_pool_mode (op)) <= g_switch_value;
+ {
+ max_ofs = GET_MODE_SIZE (get_pool_mode (op));
+ if (max_ofs > g_switch_value)
+ return false;
+ }
+ else if (SYMBOL_REF_LOCAL_P (op)
+ && SYMBOL_REF_SMALL_P (op)
+ && !SYMBOL_REF_WEAK (op)
+ && !SYMBOL_REF_TLS_MODEL (op))
+ {
+ if (SYMBOL_REF_DECL (op))
+ max_ofs = tree_low_cst (DECL_SIZE_UNIT (SYMBOL_REF_DECL (op)), 1);
+ }
+ else
+ return false;
- return (SYMBOL_REF_LOCAL_P (op)
- && SYMBOL_REF_SMALL_P (op)
- && !SYMBOL_REF_WEAK (op)
- && !SYMBOL_REF_TLS_MODEL (op));
+ /* Given that we know that the GP is always 8 byte aligned, we can
+ always adjust by 7 without overflowing. */
+ if (max_ofs < 8)
+ max_ofs = 8;
+
+ /* Since we know this is an object in a small data section, we know the
+ entire section is addressable via GP. We don't know where the section
+ boundaries are, but we know the entire object is within. */
+ return IN_RANGE (ofs, 0, max_ofs - 1);
})
;; Return true if OP is a SYMBOL_REF or CONST referencing a variable