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