I noticed that the switch code on PowerPC little endian systems (with medium
code mode) did not follow the ABI in terms of page 69:

        Table 2.36. Position-Independent Switch Code for Small/Medium Models
        (preferred, with TOC-relative addressing)

The code we currently generate is:

        .section        ".toc","aw"
        .align 3
.LC0:
        .quad   .L4
        .section        ".text"

        # ...

        addis 10,2,.LC0@toc@ha
        ld 10,.LC0@toc@l(10)
        sldi 3,3,2
        add 9,10,3
        lwa 9,0(9)
        add 9,9,10
        mtctr 9
        bctr
.L4:
        .long .L2-.L4
        .long .L12-.L4
        .long .L11-.L4
        .long .L10-.L4
        .long .L9-.L4
        .long .L8-.L4
        .long .L7-.L4
        .long .L6-.L4
        .long .L5-.L4
        .long .L3-.L4

While the suggested code would be something like:

        addis 10,2,.L4@toc@ha
        addi 10,10,.L4@toc@l
        sldi 3,3,2
        lwax 9,10,3
        add 9,9,10
        mtctr 9
        bctr
        .p2align 2
        .align 2
.L4:
        .long .L2-.L4
        .long .L12-.L4
        .long .L11-.L4
        .long .L10-.L4
        .long .L9-.L4
        .long .L8-.L4
        .long .L7-.L4
        .long .L6-.L4
        .long .L5-.L4
        .long .L3-.L4

This patch adds an insn to load a LABEL_REF into a GPR.  This is needed so the
FWPROP1 pass can convert the load the of the label address from the TOC to a
direct load to a GPR.

While working on the patch, I discovered that the LWA instruction did not
support indexed loads.  This was due to it using the 'Y' constraint, which
accepts DS-form offsettable addresses, but not X-form indexed addresses.  I
added the Z constraint so that the indexed form is accepted.

I am in the middle of doing spec 2006 runs on both power8 and power9 systems
with this change.  So far after 2 runs out 3, I'm seeing several minor wins on
power9 (1-2%, perlbench, gcc, sjeng, sphinx3) and no regressions.  On power8 I
see 3 minor wins (1-3%, perlbench, sjeng, omnetpp) and 1 minor regression (1%,
povray).

I have done bootstrap builds with/without the change and there were no
regressions in the test suite.  Can I check this change into the trunk?  It is
a simple enough change for back ports, if desired.

Note, I will be on vacation for 11 days starting this Saturday.  I will not be
actively checking my mail in that time period.  If I get the approval early
enough, I can check it in.  Otherwise, somebody else can check it in if they
monitor for failure, or we can wait until I get around August 14th to check it
in.

2018-07-31  Michael Meissner  <meiss...@linux.ibm.com>

        * config/rs6000/predicates.md (label_ref_operand): New predicate
        to recognize LABEL_REF.
        * config/rs6000/rs6000.c (rs6000_output_addr_const_extra): Allow
        LABEL_REF's inside of UNSPEC_TOCREL's.
        * config/rs6000/rs6000.md (extendsi<mode>2): Allow reg+reg indexed
        addressing.
        (labelref): New insn to optimize loading a label address into
        registers on a medium code system.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meiss...@linux.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/predicates.md
===================================================================
--- gcc/config/rs6000/predicates.md     (revision 263040)
+++ gcc/config/rs6000/predicates.md     (working copy)
@@ -1662,6 +1662,10 @@ (define_predicate "small_toc_ref"
   return GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_TOCREL;
 })
 
+;; Match a LABEL_REF operand
+(define_predicate "label_ref_operand"
+  (match_code "label_ref"))
+
 ;; Match the first insn (addis) in fusing the combination of addis and loads to
 ;; GPR registers on power8.
 (define_predicate "fusion_gpr_addis"
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 263040)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -20807,7 +20807,8 @@ rs6000_output_addr_const_extra (FILE *fi
     switch (XINT (x, 1))
       {
       case UNSPEC_TOCREL:
-       gcc_checking_assert (GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF
+       gcc_checking_assert ((GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF
+                             || GET_CODE (XVECEXP (x, 0, 0)) == LABEL_REF)
                             && REG_P (XVECEXP (x, 0, 1))
                             && REGNO (XVECEXP (x, 0, 1)) == TOC_REGISTER);
        output_addr_const (file, XVECEXP (x, 0, 0));
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md (revision 263040)
+++ gcc/config/rs6000/rs6000.md (working copy)
@@ -998,7 +998,7 @@ (define_insn "extendsi<mode>2"
                     "=r, r,   wl,    wu,    wj,    wK,     wH,    wr")
 
        (sign_extend:EXTSI (match_operand:SI 1 "lwa_operand"
-                    "Y,  r,   Z,     Z,     r,     wK,     wH,    ?wIwH")))]
+                    "YZ, r,   Z,     Z,     r,     wK,     wH,    ?wIwH")))]
   ""
   "@
    lwa%U1%X1 %0,%1
@@ -10246,6 +10246,21 @@ (define_insn_and_split "*tocref<mode>"
   [(set (match_dup 0) (high:P (match_dup 1)))
    (set (match_dup 0) (lo_sum:P (match_dup 0) (match_dup 1)))])
 
+;; This pattern exists to allow fwprop to convert the load of the LABEL_REF
+;; address for switches into using ADDIS/ADDI if we can use the TOC
+;; to get the address.
+(define_insn_and_split "*labelref"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=b*r")
+       (match_operand:DI 1 "label_ref_operand"))]
+  "TARGET_POWERPC64 && TARGET_ELF && TARGET_CMODEL == CMODEL_MEDIUM"
+  "#"
+  "&& 1"
+  [(set (match_dup 0)
+       (match_dup 2))]
+{
+  operands[2] = create_TOC_reference (operands[1], NULL_RTX);
+})
+
 ;; Elf specific ways of loading addresses for non-PIC code.
 ;; The output of this could be r0, but we make a very strong
 ;; preference for a base register because it will usually

Reply via email to