This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[RS6000] powerpc64 -mcmodel=medium large symbol offsets
- From: Alan Modra <amodra at gmail dot com>
- To: David Edelsohn <dje dot gcc at gmail dot com>, gcc-patches at gcc dot gnu dot org
- Date: Fri, 6 Sep 2013 16:43:29 +0930
- Subject: [RS6000] powerpc64 -mcmodel=medium large symbol offsets
- Authentication-results: sourceware.org; auth=none
The following testcase taken from the linux kernel is miscompiled on
powerpc64-linux.
/* -m64 -mcmodel=medium -O -S -fno-section-anchors */
static int x;
unsigned long
foo (void)
{
return ((unsigned long) &x) - 0xc000000000000000;
}
generates
addis 3,2,x+4611686018427387904@toc@ha
addi 3,3,x+4611686018427387904@toc@l
blr
losing the top 32 bits of the offset. Sadly, the assembler and linker
do not complain, which is a hole in the ABI. (@ha and _HA relocs as
per the ABI won't complain about overflow since they might be used in
a @highesta, @highera sequence loading a 64-bit value.)
This patch stops combine merging large offsets into a symbol addend
by copying code from reg_or_add_cint_operand to a new predicate,
add_cint_operand, and using that to restrict the range of offsets.
Bootstrapped and regression tested powerpc64-linux. OK to apply?
* config/rs6000/predicates.md (add_cint_operand): New.
* config/rs6000/rs6000.md (largetoc_high_plus): Restrict offset
using add_cint_operand.
(largetoc_high_plus_aix): Likewise.
Index: gcc/config/rs6000/predicates.md
===================================================================
--- gcc/config/rs6000/predicates.md (revision 202264)
+++ gcc/config/rs6000/predicates.md (working copy)
@@ -376,6 +376,12 @@
(ior (match_code "const_int")
(match_operand 0 "gpc_reg_operand")))
+;; Return 1 if op is a constant integer valid for addition with addis, addi.
+(define_predicate "add_cint_operand"
+ (and (match_code "const_int")
+ (match_test "(unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80008000)
+ < (unsigned HOST_WIDE_INT) 0x100000000ll")))
+
;; Return 1 if op is a constant integer valid for addition
;; or non-special register.
(define_predicate "reg_or_add_cint_operand"
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md (revision 202264)
+++ gcc/config/rs6000/rs6000.md (working copy)
@@ -12207,7 +12209,7 @@
(unspec [(match_operand:DI 1 "" "")
(match_operand:DI 2 "gpc_reg_operand" "b")]
UNSPEC_TOCREL)
- (match_operand 3 "const_int_operand" "n"))))]
+ (match_operand 3 "add_cint_operand" "n"))))]
"TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL"
"addis %0,%2,%1+%3@toc@ha")
@@ -12218,7 +12220,7 @@
(unspec [(match_operand:P 1 "" "")
(match_operand:P 2 "gpc_reg_operand" "b")]
UNSPEC_TOCREL)
- (match_operand 3 "const_int_operand" "n"))))]
+ (match_operand 3 "add_cint_operand" "n"))))]
"TARGET_XCOFF && TARGET_CMODEL != CMODEL_SMALL"
"addis %0,%1+%3@u(%2)")
--
Alan Modra
Australia Development Lab, IBM