@@ -113,6 +113,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);
@@ -21416,6 +21416,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. */
@@ -10539,11 +10539,7 @@ (define_insn "*call_indirect_nonlocal_sysv<mode>"
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"
@@ -10629,11 +10625,7 @@ (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
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"
@@ -10764,21 +10756,16 @@ (define_insn "*call_indirect_aix<mode>"
(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 "" "")
@@ -10787,22 +10774,16 @@ (define_insn "*call_value_indirect_aix<mode>"
(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
@@ -10813,21 +10794,16 @@ (define_insn "*call_indirect_elfv2<mode>"
(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 "" "")
@@ -10835,22 +10811,16 @@ (define_insn "*call_value_indirect_elfv2<mode>"
(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"
@@ -11019,13 +10989,7 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
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, "");
}