Index: gcc/config/rs6000/predicates.md =================================================================== --- gcc/config/rs6000/predicates.md (revision 263965) +++ 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 263965) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -20994,7 +20994,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 263965) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -10219,6 +10219,21 @@ (define_insn_and_split "*tocref" [(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 Index: gcc/testsuite/gcc.target/powerpc/switch-01.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/switch-01.c (nonexistent) +++ gcc/testsuite/gcc.target/powerpc/switch-01.c (working copy) @@ -0,0 +1,29 @@ +/* { dg-do compile { target { powerpc64le*-*-* } } } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */ +/* { dg-options "-O2 -mcmodel=medium -mcpu=power8" } */ + +/* Test that we don't load the label address when creating a switch table on + PowerPC LE systems using the medium code model. */ + +unsigned long test (unsigned long a, unsigned long b, unsigned long c) +{ + switch (a) + { + default: return a+b; + case 10: return a-b; + case 11: return a*b; + case 12: return a/b; + case 13: return a<>b; + case 15: return a | b; + case 16: return a & b; + case 17: return a ^ b; + case 18: return a & ~b; + case 19: return a | ~b; + case 20: return a ^ ~b; + } +} + +/* { dg-final { scan-assembler-not {\mld\M} } } */ +/* { dg-final { scan-assembler {\maddis .*@toc@ha\M} } } */ +/* { dg-final { scan-assembler {\maddi .*@toc@l\M} } } */