[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
This commit is contained in:
parent
75a0b80599
commit
ce83eeda06
|
@ -1,3 +1,19 @@
|
||||||
|
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>
|
2018-11-29 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
* config/rs6000/rs6000-protos.h (rs6000_call_template): Declare.
|
* config/rs6000/rs6000-protos.h (rs6000_call_template): Declare.
|
||||||
|
|
|
@ -107,6 +107,8 @@ extern void print_operand (FILE *, rtx, int);
|
||||||
extern void print_operand_address (FILE *, rtx);
|
extern void print_operand_address (FILE *, rtx);
|
||||||
extern const char *rs6000_call_template (rtx *, unsigned int, const char *);
|
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_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,
|
extern enum rtx_code rs6000_reverse_condition (machine_mode,
|
||||||
enum rtx_code);
|
enum rtx_code);
|
||||||
extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
|
extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
|
||||||
|
|
|
@ -21411,6 +21411,83 @@ rs6000_sibcall_template (rtx *operands, unsigned int funop, const char *arg)
|
||||||
return rs6000_call_template_1 (operands, funop, true, 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
|
#if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
|
||||||
/* Emit an assembler directive to set symbol visibility for DECL to
|
/* Emit an assembler directive to set symbol visibility for DECL to
|
||||||
VISIBILITY_TYPE. */
|
VISIBILITY_TYPE. */
|
||||||
|
|
|
@ -10525,11 +10525,7 @@
|
||||||
else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
|
else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
|
||||||
output_asm_insn ("creqv 6,6,6", operands);
|
output_asm_insn ("creqv 6,6,6", operands);
|
||||||
|
|
||||||
if (rs6000_speculate_indirect_jumps
|
return rs6000_indirect_call_template (operands, 0);
|
||||||
|| which_alternative == 1 || which_alternative == 3)
|
|
||||||
return "b%T0l";
|
|
||||||
else
|
|
||||||
return "crset 2\;beq%T0l-";
|
|
||||||
}
|
}
|
||||||
[(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
|
[(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
|
||||||
(set_attr_alternative "length"
|
(set_attr_alternative "length"
|
||||||
|
@ -10615,11 +10611,7 @@
|
||||||
else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
|
else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
|
||||||
output_asm_insn ("creqv 6,6,6", operands);
|
output_asm_insn ("creqv 6,6,6", operands);
|
||||||
|
|
||||||
if (rs6000_speculate_indirect_jumps
|
return rs6000_indirect_call_template (operands, 1);
|
||||||
|| which_alternative == 1 || which_alternative == 3)
|
|
||||||
return "b%T1l";
|
|
||||||
else
|
|
||||||
return "crset 2\;beq%T1l-";
|
|
||||||
}
|
}
|
||||||
[(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
|
[(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
|
||||||
(set_attr_alternative "length"
|
(set_attr_alternative "length"
|
||||||
|
@ -10750,21 +10742,16 @@
|
||||||
(use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
|
(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))
|
(set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
|
||||||
(clobber (reg:P LR_REGNO))]
|
(clobber (reg:P LR_REGNO))]
|
||||||
"DEFAULT_ABI == ABI_AIX && rs6000_speculate_indirect_jumps"
|
"DEFAULT_ABI == ABI_AIX"
|
||||||
"<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3(1)"
|
{
|
||||||
|
return rs6000_indirect_call_template (operands, 0);
|
||||||
|
}
|
||||||
[(set_attr "type" "jmpreg")
|
[(set_attr "type" "jmpreg")
|
||||||
(set_attr "length" "12")])
|
(set (attr "length")
|
||||||
|
(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
|
||||||
(define_insn "*call_indirect_aix<mode>_nospec"
|
(match_test "which_alternative != 1"))
|
||||||
[(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
|
(const_string "16")
|
||||||
(match_operand 1 "" "g,g"))
|
(const_string "12")))])
|
||||||
(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)"
|
|
||||||
[(set_attr "type" "jmpreg")
|
|
||||||
(set_attr "length" "16")])
|
|
||||||
|
|
||||||
(define_insn "*call_value_indirect_aix<mode>"
|
(define_insn "*call_value_indirect_aix<mode>"
|
||||||
[(set (match_operand 0 "" "")
|
[(set (match_operand 0 "" "")
|
||||||
|
@ -10773,22 +10760,16 @@
|
||||||
(use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
|
(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))
|
(set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
|
||||||
(clobber (reg:P LR_REGNO))]
|
(clobber (reg:P LR_REGNO))]
|
||||||
"DEFAULT_ABI == ABI_AIX && rs6000_speculate_indirect_jumps"
|
"DEFAULT_ABI == ABI_AIX"
|
||||||
"<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4(1)"
|
{
|
||||||
|
return rs6000_indirect_call_template (operands, 1);
|
||||||
|
}
|
||||||
[(set_attr "type" "jmpreg")
|
[(set_attr "type" "jmpreg")
|
||||||
(set_attr "length" "12")])
|
(set (attr "length")
|
||||||
|
(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
|
||||||
(define_insn "*call_value_indirect_aix<mode>_nospec"
|
(match_test "which_alternative != 1"))
|
||||||
[(set (match_operand 0 "" "")
|
(const_string "16")
|
||||||
(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
|
(const_string "12")))])
|
||||||
(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)"
|
|
||||||
[(set_attr "type" "jmpreg")
|
|
||||||
(set_attr "length" "16")])
|
|
||||||
|
|
||||||
;; Call to indirect functions with the ELFv2 ABI.
|
;; Call to indirect functions with the ELFv2 ABI.
|
||||||
;; Operand0 is the addresss of the function to call
|
;; Operand0 is the addresss of the function to call
|
||||||
|
@ -10799,21 +10780,16 @@
|
||||||
(match_operand 1 "" "g,g"))
|
(match_operand 1 "" "g,g"))
|
||||||
(set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
|
(set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
|
||||||
(clobber (reg:P LR_REGNO))]
|
(clobber (reg:P LR_REGNO))]
|
||||||
"DEFAULT_ABI == ABI_ELFv2 && rs6000_speculate_indirect_jumps"
|
"DEFAULT_ABI == ABI_ELFv2"
|
||||||
"b%T0l\;<ptrload> 2,%2(1)"
|
{
|
||||||
|
return rs6000_indirect_call_template (operands, 0);
|
||||||
|
}
|
||||||
[(set_attr "type" "jmpreg")
|
[(set_attr "type" "jmpreg")
|
||||||
(set_attr "length" "8")])
|
(set (attr "length")
|
||||||
|
(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
|
||||||
;; Variant with deliberate misprediction.
|
(match_test "which_alternative != 1"))
|
||||||
(define_insn "*call_indirect_elfv2<mode>_nospec"
|
(const_string "12")
|
||||||
[(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
|
(const_string "8")))])
|
||||||
(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)"
|
|
||||||
[(set_attr "type" "jmpreg")
|
|
||||||
(set_attr "length" "12")])
|
|
||||||
|
|
||||||
(define_insn "*call_value_indirect_elfv2<mode>"
|
(define_insn "*call_value_indirect_elfv2<mode>"
|
||||||
[(set (match_operand 0 "" "")
|
[(set (match_operand 0 "" "")
|
||||||
|
@ -10821,22 +10797,16 @@
|
||||||
(match_operand 2 "" "g,g")))
|
(match_operand 2 "" "g,g")))
|
||||||
(set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
|
(set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
|
||||||
(clobber (reg:P LR_REGNO))]
|
(clobber (reg:P LR_REGNO))]
|
||||||
"DEFAULT_ABI == ABI_ELFv2 && rs6000_speculate_indirect_jumps"
|
"DEFAULT_ABI == ABI_ELFv2"
|
||||||
"b%T1l\;<ptrload> 2,%3(1)"
|
{
|
||||||
|
return rs6000_indirect_call_template (operands, 1);
|
||||||
|
}
|
||||||
[(set_attr "type" "jmpreg")
|
[(set_attr "type" "jmpreg")
|
||||||
(set_attr "length" "8")])
|
(set (attr "length")
|
||||||
|
(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
|
||||||
; Variant with deliberate misprediction.
|
(match_test "which_alternative != 1"))
|
||||||
(define_insn "*call_value_indirect_elfv2<mode>_nospec"
|
(const_string "12")
|
||||||
[(set (match_operand 0 "" "")
|
(const_string "8")))])
|
||||||
(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)"
|
|
||||||
[(set_attr "type" "jmpreg")
|
|
||||||
(set_attr "length" "12")])
|
|
||||||
|
|
||||||
;; Call subroutine returning any type.
|
;; Call subroutine returning any type.
|
||||||
(define_expand "untyped_call"
|
(define_expand "untyped_call"
|
||||||
|
@ -11005,13 +10975,7 @@
|
||||||
output_asm_insn ("creqv 6,6,6", operands);
|
output_asm_insn ("creqv 6,6,6", operands);
|
||||||
|
|
||||||
if (which_alternative >= 2)
|
if (which_alternative >= 2)
|
||||||
{
|
return rs6000_indirect_sibcall_template (operands, 0);
|
||||||
if (rs6000_speculate_indirect_jumps)
|
|
||||||
return "b%T0";
|
|
||||||
else
|
|
||||||
/* Can use CR0 since it is volatile across sibcalls. */
|
|
||||||
return "crset 2\;beq%T0-\;b $";
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return rs6000_sibcall_template (operands, 0, "");
|
return rs6000_sibcall_template (operands, 0, "");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue