[NDS32] Refine call and return patterns.
gcc/ * config/nds32/nds32-md-auxiliary.c (nds32_output_return, nds32_output_call, nds32_symbol_binds_local_p): New functions. * config/nds32/nds32-protos.h (nds32_output_call, nds32_output_return): Declare. * config/nds32/nds32.md: Refine all the call and return patterns. Co-Authored-By: Kito Cheng <kito.cheng@gmail.com> From-SVN: r259186
This commit is contained in:
parent
96975b1159
commit
f467067339
4 changed files with 211 additions and 53 deletions
|
@ -1,3 +1,12 @@
|
|||
2018-04-06 Chung-Ju Wu <jasonwucj@gmail.com>
|
||||
Kito Cheng <kito.cheng@gmail.com>
|
||||
|
||||
* config/nds32/nds32-md-auxiliary.c (nds32_output_return,
|
||||
nds32_output_call, nds32_symbol_binds_local_p): New functions.
|
||||
* config/nds32/nds32-protos.h (nds32_output_call,
|
||||
nds32_output_return): Declare.
|
||||
* config/nds32/nds32.md: Refine all the call and return patterns.
|
||||
|
||||
2018-04-06 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR debug/85252
|
||||
|
|
|
@ -1938,6 +1938,48 @@ nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED)
|
|||
return "";
|
||||
}
|
||||
|
||||
/* Function to output return operation. */
|
||||
const char *
|
||||
nds32_output_return (void)
|
||||
{
|
||||
/* A string pattern for output_asm_insn(). */
|
||||
char pattern[100];
|
||||
/* The operands array which will be used in output_asm_insn(). */
|
||||
rtx operands[2];
|
||||
/* For stack v3pop:
|
||||
operands[0]: Re
|
||||
operands[1]: imm8u */
|
||||
int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
|
||||
int sp_adjust;
|
||||
|
||||
/* Set operands[0]. */
|
||||
operands[0] = gen_rtx_REG (SImode, re_callee_saved);
|
||||
|
||||
/* Check if we can generate 'pop25 Re,imm8u',
|
||||
otherwise, generate 'pop25 Re,0'.
|
||||
We have to consider alloca issue as well.
|
||||
If the function does call alloca(), the stack pointer is not fixed.
|
||||
In that case, we cannot use 'pop25 Re,imm8u' directly.
|
||||
We have to caculate stack pointer from frame pointer
|
||||
and then use 'pop25 Re,0'. */
|
||||
sp_adjust = cfun->machine->local_size
|
||||
+ cfun->machine->out_args_size
|
||||
+ cfun->machine->callee_saved_area_gpr_padding_bytes
|
||||
+ cfun->machine->callee_saved_fpr_regs_size;
|
||||
if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
|
||||
&& NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
|
||||
&& !cfun->calls_alloca)
|
||||
operands[1] = GEN_INT (sp_adjust);
|
||||
else
|
||||
operands[1] = GEN_INT (0);
|
||||
|
||||
/* Create assembly code pattern. */
|
||||
snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
|
||||
/* We use output_asm_insn() to output assembly code by ourself. */
|
||||
output_asm_insn (pattern, operands);
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Function to generate PC relative jump table.
|
||||
Refer to nds32.md for more details.
|
||||
|
||||
|
@ -2681,6 +2723,56 @@ nds32_output_cbranchsi4_greater_less_zero (rtx_insn *insn, rtx *operands)
|
|||
return "";
|
||||
}
|
||||
|
||||
/* Return true if SYMBOL_REF X binds locally. */
|
||||
|
||||
static bool
|
||||
nds32_symbol_binds_local_p (const_rtx x)
|
||||
{
|
||||
return (SYMBOL_REF_DECL (x)
|
||||
? targetm.binds_local_p (SYMBOL_REF_DECL (x))
|
||||
: SYMBOL_REF_LOCAL_P (x));
|
||||
}
|
||||
|
||||
const char *
|
||||
nds32_output_call (rtx insn, rtx *operands, rtx symbol, const char *long_call,
|
||||
const char *call, bool align_p)
|
||||
{
|
||||
char pattern[100];
|
||||
bool noreturn_p;
|
||||
|
||||
if (GET_CODE (symbol) == CONST)
|
||||
{
|
||||
symbol= XEXP (symbol, 0);
|
||||
|
||||
if (GET_CODE (symbol) == PLUS)
|
||||
symbol = XEXP (symbol, 0);
|
||||
}
|
||||
|
||||
gcc_assert (GET_CODE (symbol) == SYMBOL_REF
|
||||
|| REG_P (symbol));
|
||||
|
||||
if (nds32_long_call_p (symbol))
|
||||
strcpy (pattern, long_call);
|
||||
else
|
||||
strcpy (pattern, call);
|
||||
|
||||
if (align_p)
|
||||
strcat (pattern, "\n\t.align 2");
|
||||
|
||||
noreturn_p = find_reg_note (insn, REG_NORETURN, NULL_RTX) != NULL_RTX;
|
||||
|
||||
if (noreturn_p)
|
||||
{
|
||||
if (TARGET_16_BIT)
|
||||
strcat (pattern, "\n\tnop16");
|
||||
else
|
||||
strcat (pattern, "\n\tnop");
|
||||
}
|
||||
|
||||
output_asm_insn (pattern, operands);
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Spilt a doubleword instrucion to two single word instructions. */
|
||||
void
|
||||
nds32_spilt_doubleword (rtx *operands, bool load_p)
|
||||
|
|
|
@ -172,11 +172,15 @@ extern const char *nds32_output_cbranchsi4_equality_reg_or_const_int (rtx_insn *
|
|||
rtx *);
|
||||
extern const char *nds32_output_cbranchsi4_greater_less_zero (rtx_insn *, rtx *);
|
||||
|
||||
extern const char *nds32_output_call (rtx, rtx *, rtx,
|
||||
const char *, const char *, bool);
|
||||
|
||||
|
||||
/* Auxiliary functions to output stack push/pop instruction. */
|
||||
|
||||
extern const char *nds32_output_stack_push (rtx);
|
||||
extern const char *nds32_output_stack_pop (rtx);
|
||||
extern const char *nds32_output_return (void);
|
||||
|
||||
/* Auxiliary functions to split double word RTX pattern. */
|
||||
|
||||
|
|
|
@ -1419,36 +1419,41 @@
|
|||
""
|
||||
)
|
||||
|
||||
(define_insn "*call_register"
|
||||
[(parallel [(call (mem (match_operand:SI 0 "register_operand" "r, r"))
|
||||
(match_operand 1))
|
||||
(clobber (reg:SI LP_REGNUM))
|
||||
(clobber (reg:SI TA_REGNUM))])]
|
||||
""
|
||||
"@
|
||||
jral5\t%0
|
||||
jral\t%0"
|
||||
[(set_attr "type" "branch,branch")
|
||||
(set_attr "length" " 2, 4")])
|
||||
|
||||
(define_insn "*call_immediate"
|
||||
[(parallel [(call (mem (match_operand:SI 0 "immediate_operand" "i"))
|
||||
(define_insn "call_internal"
|
||||
[(parallel [(call (mem (match_operand:SI 0 "nds32_call_address_operand" "r, i"))
|
||||
(match_operand 1))
|
||||
(clobber (reg:SI LP_REGNUM))
|
||||
(clobber (reg:SI TA_REGNUM))])]
|
||||
""
|
||||
{
|
||||
if (TARGET_CMODEL_LARGE)
|
||||
return "bal\t%0";
|
||||
else
|
||||
return "jal\t%0";
|
||||
switch (which_alternative)
|
||||
{
|
||||
case 0:
|
||||
if (TARGET_16_BIT)
|
||||
return "jral5\t%0";
|
||||
else
|
||||
return "jral\t%0";
|
||||
case 1:
|
||||
return nds32_output_call (insn, operands, operands[0],
|
||||
"bal\t%0", "jal\t%0", false);
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
[(set_attr "type" "branch")
|
||||
(set (attr "length")
|
||||
(if_then_else (match_test "TARGET_CMODEL_LARGE")
|
||||
(const_int 12)
|
||||
(const_int 4)))])
|
||||
|
||||
[(set_attr "enabled" "yes")
|
||||
(set_attr "type" "branch")
|
||||
(set_attr_alternative "length"
|
||||
[
|
||||
;; Alternative 0
|
||||
(if_then_else (match_test "TARGET_16_BIT")
|
||||
(const_int 2)
|
||||
(const_int 4))
|
||||
;; Alternative 1
|
||||
(if_then_else (match_test "nds32_long_call_p (operands[0])")
|
||||
(const_int 12)
|
||||
(const_int 4))
|
||||
])]
|
||||
)
|
||||
|
||||
;; Subroutine call instruction returning a value.
|
||||
;; operands[0]: It is the hard regiser in which the value is returned.
|
||||
|
@ -1462,42 +1467,71 @@
|
|||
(match_operand 2)))
|
||||
(clobber (reg:SI LP_REGNUM))
|
||||
(clobber (reg:SI TA_REGNUM))])]
|
||||
""
|
||||
""
|
||||
)
|
||||
"")
|
||||
|
||||
(define_insn "*call_value_register"
|
||||
(define_insn "call_value_internal"
|
||||
[(parallel [(set (match_operand 0)
|
||||
(call (mem (match_operand:SI 1 "register_operand" "r, r"))
|
||||
(call (mem (match_operand:SI 1 "nds32_call_address_operand" "r, i"))
|
||||
(match_operand 2)))
|
||||
(clobber (reg:SI LP_REGNUM))
|
||||
(clobber (reg:SI TA_REGNUM))])]
|
||||
""
|
||||
"@
|
||||
jral5\t%1
|
||||
jral\t%1"
|
||||
[(set_attr "type" "branch,branch")
|
||||
(set_attr "length" " 2, 4")])
|
||||
{
|
||||
switch (which_alternative)
|
||||
{
|
||||
case 0:
|
||||
if (TARGET_16_BIT)
|
||||
return "jral5\t%1";
|
||||
else
|
||||
return "jral\t%1";
|
||||
case 1:
|
||||
return nds32_output_call (insn, operands, operands[1],
|
||||
"bal\t%1", "jal\t%1", false);
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
[(set_attr "enabled" "yes")
|
||||
(set_attr "type" "branch")
|
||||
(set_attr_alternative "length"
|
||||
[
|
||||
;; Alternative 0
|
||||
(if_then_else (match_test "TARGET_16_BIT")
|
||||
(const_int 2)
|
||||
(const_int 4))
|
||||
;; Alternative 1
|
||||
(if_then_else (match_test "nds32_long_call_p (operands[1])")
|
||||
(const_int 12)
|
||||
(const_int 4))
|
||||
])]
|
||||
)
|
||||
|
||||
(define_insn "*call_value_immediate"
|
||||
[(parallel [(set (match_operand 0)
|
||||
(call (mem (match_operand:SI 1 "immediate_operand" "i"))
|
||||
(match_operand 2)))
|
||||
(clobber (reg:SI LP_REGNUM))
|
||||
(clobber (reg:SI TA_REGNUM))])]
|
||||
;; Call subroutine returning any type.
|
||||
|
||||
(define_expand "untyped_call"
|
||||
[(parallel [(call (match_operand 0 "" "")
|
||||
(const_int 0))
|
||||
(match_operand 1 "" "")
|
||||
(match_operand 2 "" "")])]
|
||||
""
|
||||
{
|
||||
if (TARGET_CMODEL_LARGE)
|
||||
return "bal\t%1";
|
||||
else
|
||||
return "jal\t%1";
|
||||
}
|
||||
[(set_attr "type" "branch")
|
||||
(set (attr "length")
|
||||
(if_then_else (match_test "TARGET_CMODEL_LARGE")
|
||||
(const_int 12)
|
||||
(const_int 4)))])
|
||||
int i;
|
||||
|
||||
emit_call_insn (gen_call (operands[0], const0_rtx));
|
||||
|
||||
for (i = 0; i < XVECLEN (operands[2], 0); i++)
|
||||
{
|
||||
rtx set = XVECEXP (operands[2], 0, i);
|
||||
emit_move_insn (SET_DEST (set), SET_SRC (set));
|
||||
}
|
||||
|
||||
/* The optimizer does not know that the call sets the function value
|
||||
registers we stored in the result block. We avoid problems by
|
||||
claiming that all hard registers are used and clobbered at this
|
||||
point. */
|
||||
emit_insn (gen_blockage ());
|
||||
DONE;
|
||||
})
|
||||
|
||||
;; ----------------------------------------------------------------------------
|
||||
|
||||
|
@ -1715,10 +1749,18 @@
|
|||
;; Use this pattern to expand a return instruction
|
||||
;; with simple_return rtx if no epilogue is required.
|
||||
(define_expand "return"
|
||||
[(simple_return)]
|
||||
[(parallel [(return)
|
||||
(clobber (reg:SI FP_REGNUM))])]
|
||||
"nds32_can_use_return_insn ()"
|
||||
""
|
||||
)
|
||||
{
|
||||
/* Emit as the simple return. */
|
||||
if (cfun->machine->naked_p
|
||||
&& (cfun->machine->va_args_size == 0))
|
||||
{
|
||||
emit_jump_insn (gen_return_internal ());
|
||||
DONE;
|
||||
}
|
||||
})
|
||||
|
||||
;; This pattern is expanded only by the shrink-wrapping optimization
|
||||
;; on paths where the function prologue has not been executed.
|
||||
|
@ -1728,6 +1770,17 @@
|
|||
""
|
||||
)
|
||||
|
||||
(define_insn "*nds32_return"
|
||||
[(parallel [(return)
|
||||
(clobber (reg:SI FP_REGNUM))])]
|
||||
""
|
||||
{
|
||||
return nds32_output_return ();
|
||||
}
|
||||
[(set_attr "type" "branch")
|
||||
(set_attr "enabled" "yes")
|
||||
(set_attr "length" "4")])
|
||||
|
||||
(define_insn "return_internal"
|
||||
[(simple_return)]
|
||||
""
|
||||
|
|
Loading…
Add table
Reference in a new issue