diff options
author | Alan Modra <amodra@gmail.com> | 2018-11-29 15:13:21 +1030 |
---|---|---|
committer | Alan Modra <amodra@gcc.gnu.org> | 2018-11-29 15:13:21 +1030 |
commit | ce83eeda066824074e56fbecdfcc5dd23fac6486 (patch) | |
tree | 8707ec139df15a2a40d15143b861c4d580e5109d | |
parent | 75a0b80599ca4326da8a203e042cb9db6c27ab08 (diff) | |
download | gcc-ce83eeda066824074e56fbecdfcc5dd23fac6486.zip gcc-ce83eeda066824074e56fbecdfcc5dd23fac6486.tar.gz gcc-ce83eeda066824074e56fbecdfcc5dd23fac6486.tar.bz2 |
[RS6000] rs6000_indirect_call_template
Like the last patch for external calls, now handle most assembly code
for indirect calls in one place. The patch also merges some insns,
correcting some !rs6000_speculate_indirect_jumps cases branching to
LR, which don't require a speculation barrier.
* config/rs6000/rs6000-protos.h (rs6000_indirect_call_template),
(rs6000_indirect_sibcall_template): Declare.
* config/rs6000/rs6000.c (rs6000_indirect_call_template_1),
(rs6000_indirect_call_template, rs6000_indirect_sibcall_template):
New functions.
* config/rs6000/rs6000.md (call_indirect_nonlocal_sysv),
(call_value_indirect_nonlocal_sysv, sibcall_nonlocal_sysv),
(call_indirect_aix, call_value_indirect_aix): Use
rs6000_indirect_call_template and rs6000_indirect_sibcall_template.
call_indirect_elfv2, call_value_indirect_elfv2): Likewise, and
handle both speculation and non-speculation cases.
(call_indirect_aix_nospec, call_value_indirect_aix_nospec): Delete.
(call_indirect_elfv2_nospec, call_value_indirect_elfv2_nospec): Delete.
From-SVN: r266601
-rw-r--r-- | gcc/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 77 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 114 |
4 files changed, 134 insertions, 75 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0186a40..85ae1d9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,21 @@ 2018-11-29 Alan Modra <amodra@gmail.com> + * config/rs6000/rs6000-protos.h (rs6000_indirect_call_template), + (rs6000_indirect_sibcall_template): Declare. + * config/rs6000/rs6000.c (rs6000_indirect_call_template_1), + (rs6000_indirect_call_template, rs6000_indirect_sibcall_template): + New functions. + * config/rs6000/rs6000.md (call_indirect_nonlocal_sysv), + (call_value_indirect_nonlocal_sysv, sibcall_nonlocal_sysv), + (call_indirect_aix, call_value_indirect_aix): Use + rs6000_indirect_call_template and rs6000_indirect_sibcall_template. + call_indirect_elfv2, call_value_indirect_elfv2): Likewise, and + handle both speculation and non-speculation cases. + (call_indirect_aix_nospec, call_value_indirect_aix_nospec): Delete. + (call_indirect_elfv2_nospec, call_value_indirect_elfv2_nospec): Delete. + +2018-11-29 Alan Modra <amodra@gmail.com> + * config/rs6000/rs6000-protos.h (rs6000_call_template): Declare. (rs6000_sibcall_template): Declare. (macho_call_template): Rename from output_call. diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index bdb2a59..f1a294a 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -107,6 +107,8 @@ extern void print_operand (FILE *, rtx, int); extern void print_operand_address (FILE *, rtx); extern const char *rs6000_call_template (rtx *, unsigned int, const char *); extern const char *rs6000_sibcall_template (rtx *, unsigned int, const char *); +extern const char *rs6000_indirect_call_template (rtx *, unsigned int); +extern const char *rs6000_indirect_sibcall_template (rtx *, unsigned int); extern enum rtx_code rs6000_reverse_condition (machine_mode, enum rtx_code); extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 7c7117c..497a157 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -21411,6 +21411,83 @@ rs6000_sibcall_template (rtx *operands, unsigned int funop, const char *arg) return rs6000_call_template_1 (operands, funop, true, arg); } +/* As above, for indirect calls. */ + +static const char * +rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop, + bool sibcall) +{ + /* -Wformat-overflow workaround, without which gcc thinks that %u + might produce 10 digits. */ + gcc_assert (funop <= MAX_RECOG_OPERANDS); + + static char str[144]; + const char *ptrload = TARGET_64BIT ? "d" : "wz"; + + /* We don't need the extra code to stop indirect call speculation if + calling via LR. */ + bool speculate = (TARGET_MACHO + || rs6000_speculate_indirect_jumps + || (REG_P (operands[funop]) + && REGNO (operands[funop]) == LR_REGNO)); + + if (DEFAULT_ABI == ABI_AIX) + { + if (speculate) + sprintf (str, + "l%s 2,%%%u\n\t" + "b%%T%ul\n\t" + "l%s 2,%%%u(1)", + ptrload, funop + 2, funop, ptrload, funop + 3); + else + sprintf (str, + "crset 2\n\t" + "l%s 2,%%%u\n\t" + "beq%%T%ul-\n\t" + "l%s 2,%%%u(1)", + ptrload, funop + 2, funop, ptrload, funop + 3); + } + else if (DEFAULT_ABI == ABI_ELFv2) + { + if (speculate) + sprintf (str, + "b%%T%ul\n\t" + "l%s 2,%%%u(1)", + funop, ptrload, funop + 2); + else + sprintf (str, + "crset 2\n\t" + "beq%%T%ul-\n\t" + "l%s 2,%%%u(1)", + funop, ptrload, funop + 2); + } + else + { + if (speculate) + sprintf (str, + "b%%T%u%s", + funop, sibcall ? "" : "l"); + else + sprintf (str, + "crset 2\n\t" + "beq%%T%u%s-%s", + funop, sibcall ? "" : "l", sibcall ? "\n\tb $" : ""); + } + return str; +} + +const char * +rs6000_indirect_call_template (rtx *operands, unsigned int funop) +{ + return rs6000_indirect_call_template_1 (operands, funop, false); +} + +const char * +rs6000_indirect_sibcall_template (rtx *operands, unsigned int funop) +{ + return rs6000_indirect_call_template_1 (operands, funop, true); +} + #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO /* Emit an assembler directive to set symbol visibility for DECL to VISIBILITY_TYPE. */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index fd0ae58..c918b04 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -10525,11 +10525,7 @@ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) output_asm_insn ("creqv 6,6,6", operands); - if (rs6000_speculate_indirect_jumps - || which_alternative == 1 || which_alternative == 3) - return "b%T0l"; - else - return "crset 2\;beq%T0l-"; + return rs6000_indirect_call_template (operands, 0); } [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg") (set_attr_alternative "length" @@ -10615,11 +10611,7 @@ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) output_asm_insn ("creqv 6,6,6", operands); - if (rs6000_speculate_indirect_jumps - || which_alternative == 1 || which_alternative == 3) - return "b%T1l"; - else - return "crset 2\;beq%T1l-"; + return rs6000_indirect_call_template (operands, 1); } [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg") (set_attr_alternative "length" @@ -10750,21 +10742,16 @@ (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>")) (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_AIX && rs6000_speculate_indirect_jumps" - "<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3(1)" - [(set_attr "type" "jmpreg") - (set_attr "length" "12")]) - -(define_insn "*call_indirect_aix<mode>_nospec" - [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l")) - (match_operand 1 "" "g,g")) - (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>")) - (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) - (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_AIX && !rs6000_speculate_indirect_jumps" - "crset 2\;<ptrload> 2,%2\;beq%T0l-\;<ptrload> 2,%3(1)" + "DEFAULT_ABI == ABI_AIX" +{ + return rs6000_indirect_call_template (operands, 0); +} [(set_attr "type" "jmpreg") - (set_attr "length" "16")]) + (set (attr "length") + (if_then_else (and (match_test "!rs6000_speculate_indirect_jumps") + (match_test "which_alternative != 1")) + (const_string "16") + (const_string "12")))]) (define_insn "*call_value_indirect_aix<mode>" [(set (match_operand 0 "" "") @@ -10773,22 +10760,16 @@ (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>")) (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_AIX && rs6000_speculate_indirect_jumps" - "<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4(1)" - [(set_attr "type" "jmpreg") - (set_attr "length" "12")]) - -(define_insn "*call_value_indirect_aix<mode>_nospec" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) - (match_operand 2 "" "g,g"))) - (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>")) - (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) - (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_AIX && !rs6000_speculate_indirect_jumps" - "crset 2\;<ptrload> 2,%3\;beq%T1l-\;<ptrload> 2,%4(1)" + "DEFAULT_ABI == ABI_AIX" +{ + return rs6000_indirect_call_template (operands, 1); +} [(set_attr "type" "jmpreg") - (set_attr "length" "16")]) + (set (attr "length") + (if_then_else (and (match_test "!rs6000_speculate_indirect_jumps") + (match_test "which_alternative != 1")) + (const_string "16") + (const_string "12")))]) ;; Call to indirect functions with the ELFv2 ABI. ;; Operand0 is the addresss of the function to call @@ -10799,21 +10780,16 @@ (match_operand 1 "" "g,g")) (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_ELFv2 && rs6000_speculate_indirect_jumps" - "b%T0l\;<ptrload> 2,%2(1)" - [(set_attr "type" "jmpreg") - (set_attr "length" "8")]) - -;; Variant with deliberate misprediction. -(define_insn "*call_indirect_elfv2<mode>_nospec" - [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l")) - (match_operand 1 "" "g,g")) - (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) - (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_ELFv2 && !rs6000_speculate_indirect_jumps" - "crset 2\;beq%T0l-\;<ptrload> 2,%2(1)" + "DEFAULT_ABI == ABI_ELFv2" +{ + return rs6000_indirect_call_template (operands, 0); +} [(set_attr "type" "jmpreg") - (set_attr "length" "12")]) + (set (attr "length") + (if_then_else (and (match_test "!rs6000_speculate_indirect_jumps") + (match_test "which_alternative != 1")) + (const_string "12") + (const_string "8")))]) (define_insn "*call_value_indirect_elfv2<mode>" [(set (match_operand 0 "" "") @@ -10821,22 +10797,16 @@ (match_operand 2 "" "g,g"))) (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_ELFv2 && rs6000_speculate_indirect_jumps" - "b%T1l\;<ptrload> 2,%3(1)" - [(set_attr "type" "jmpreg") - (set_attr "length" "8")]) - -; Variant with deliberate misprediction. -(define_insn "*call_value_indirect_elfv2<mode>_nospec" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) - (match_operand 2 "" "g,g"))) - (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) - (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_ELFv2 && !rs6000_speculate_indirect_jumps" - "crset 2\;beq%T1l-\;<ptrload> 2,%3(1)" + "DEFAULT_ABI == ABI_ELFv2" +{ + return rs6000_indirect_call_template (operands, 1); +} [(set_attr "type" "jmpreg") - (set_attr "length" "12")]) + (set (attr "length") + (if_then_else (and (match_test "!rs6000_speculate_indirect_jumps") + (match_test "which_alternative != 1")) + (const_string "12") + (const_string "8")))]) ;; Call subroutine returning any type. (define_expand "untyped_call" @@ -11005,13 +10975,7 @@ output_asm_insn ("creqv 6,6,6", operands); if (which_alternative >= 2) - { - if (rs6000_speculate_indirect_jumps) - return "b%T0"; - else - /* Can use CR0 since it is volatile across sibcalls. */ - return "crset 2\;beq%T0-\;b $"; - } + return rs6000_indirect_sibcall_template (operands, 0); else return rs6000_sibcall_template (operands, 0, ""); } |