From 93dc87e3c96848a0cfa6b416c432b24edabd61ef Mon Sep 17 00:00:00 2001 From: Chung-Ju Wu Date: Tue, 22 Jul 2014 16:41:19 +0800 Subject: [PATCH 07/18] (PATCH 07) Consider varargs situation when creating stack operation assembly code: -- In fact, we only need to take care of 'push.s' situation, because we have to push all the nameless arguments into stack. -- But we do not have to use 'pop.s' to restore them back to registers, because we can just adjust stack pointer to set frame location. This operation should be done in epilogue expanding. -- Because 'pop25' instruction also performs return operation, we will not use v3push/v3pop on isr and vararg functions. Therefore, their instruction length should be 4 bytes. --- gcc/config/nds32/nds32-md-auxiliary.c | 61 +++++++++++++++++++++++++++-------- gcc/config/nds32/nds32-protos.h | 4 +-- gcc/config/nds32/nds32.md | 12 ++++--- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/gcc/config/nds32/nds32-md-auxiliary.c b/gcc/config/nds32/nds32-md-auxiliary.c index 047417c..85a3a30 100644 --- a/gcc/config/nds32/nds32-md-auxiliary.c +++ b/gcc/config/nds32/nds32-md-auxiliary.c @@ -563,17 +563,44 @@ nds32_output_32bit_load_s (rtx *operands, int byte) /* Function to output stack push operation. We need to deal with normal stack push multiple or stack v3push. */ const char * -nds32_output_stack_push (void) +nds32_output_stack_push (rtx par_rtx) { /* A string pattern for output_asm_insn(). */ char pattern[100]; /* The operands array which will be used in output_asm_insn(). */ rtx operands[3]; + /* Pick up varargs first regno and last regno for further use. */ + int rb_va_args = cfun->machine->va_args_first_regno; + int re_va_args = cfun->machine->va_args_last_regno; + int last_argument_regno = NDS32_FIRST_GPR_REGNUM + + NDS32_MAX_GPR_REGS_FOR_ARGS + - 1; /* Pick up callee-saved first regno and last regno for further use. */ - int rb_regno = cfun->machine->callee_saved_regs_first_regno; - int re_regno = cfun->machine->callee_saved_regs_last_regno; + int rb_callee_saved = cfun->machine->callee_saved_regs_first_regno; + int re_callee_saved = cfun->machine->callee_saved_regs_last_regno; - if (TARGET_V3PUSH) + /* First we need to check if we are pushing argument registers not used + for the named arguments. If so, we have to create 'smw.adm' (push.s) + instruction. */ + if (reg_mentioned_p (gen_rtx_REG (SImode, last_argument_regno), par_rtx)) + { + /* Set operands[0] and operands[1]. */ + operands[0] = gen_rtx_REG (SImode, rb_va_args); + operands[1] = gen_rtx_REG (SImode, re_va_args); + /* Create assembly code pattern: "Rb, Re, { }". */ + snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }"); + /* We use output_asm_insn() to output assembly code by ourself. */ + output_asm_insn (pattern, operands); + return ""; + } + + /* If we step here, we are going to do v3push or multiple push operation. */ + + /* The v3push/v3pop instruction should only be applied on + none-isr and none-variadic function. */ + if (TARGET_V3PUSH + && !nds32_isr_function_p (current_function_decl) + && (cfun->machine->va_args_size == 0)) { /* For stack v3push: operands[0]: Re @@ -583,7 +610,7 @@ nds32_output_stack_push (void) int sp_adjust; /* Set operands[0]. */ - operands[0] = gen_rtx_REG (SImode, re_regno); + operands[0] = gen_rtx_REG (SImode, re_callee_saved); /* Check if we can generate 'push25 Re,imm8u', otherwise, generate 'push25 Re,0'. */ @@ -611,8 +638,8 @@ nds32_output_stack_push (void) int push_en4_only_p = 0; /* Set operands[0] and operands[1]. */ - operands[0] = gen_rtx_REG (SImode, rb_regno); - operands[1] = gen_rtx_REG (SImode, re_regno); + operands[0] = gen_rtx_REG (SImode, rb_callee_saved); + operands[1] = gen_rtx_REG (SImode, re_callee_saved); /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */ if (!cfun->machine->fp_size @@ -650,17 +677,23 @@ nds32_output_stack_push (void) /* Function to output stack pop operation. We need to deal with normal stack pop multiple or stack v3pop. */ const char * -nds32_output_stack_pop (void) +nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED) { /* A string pattern for output_asm_insn(). */ char pattern[100]; /* The operands array which will be used in output_asm_insn(). */ rtx operands[3]; /* Pick up callee-saved first regno and last regno for further use. */ - int rb_regno = cfun->machine->callee_saved_regs_first_regno; - int re_regno = cfun->machine->callee_saved_regs_last_regno; + int rb_callee_saved = cfun->machine->callee_saved_regs_first_regno; + int re_callee_saved = cfun->machine->callee_saved_regs_last_regno; + + /* If we step here, we are going to do v3pop or multiple pop operation. */ - if (TARGET_V3PUSH) + /* The v3push/v3pop instruction should only be applied on + none-isr and none-variadic function. */ + if (TARGET_V3PUSH + && !nds32_isr_function_p (current_function_decl) + && (cfun->machine->va_args_size == 0)) { /* For stack v3pop: operands[0]: Re @@ -670,7 +703,7 @@ nds32_output_stack_pop (void) int sp_adjust; /* Set operands[0]. */ - operands[0] = gen_rtx_REG (SImode, re_regno); + operands[0] = gen_rtx_REG (SImode, re_callee_saved); /* Check if we can generate 'pop25 Re,imm8u', otherwise, generate 'pop25 Re,0'. @@ -704,8 +737,8 @@ nds32_output_stack_pop (void) int pop_en4_only_p = 0; /* Set operands[0] and operands[1]. */ - operands[0] = gen_rtx_REG (SImode, rb_regno); - operands[1] = gen_rtx_REG (SImode, re_regno); + operands[0] = gen_rtx_REG (SImode, rb_callee_saved); + operands[1] = gen_rtx_REG (SImode, re_callee_saved); /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */ if (!cfun->machine->fp_size diff --git a/gcc/config/nds32/nds32-protos.h b/gcc/config/nds32/nds32-protos.h index e57674a..8984ea7 100644 --- a/gcc/config/nds32/nds32-protos.h +++ b/gcc/config/nds32/nds32-protos.h @@ -117,8 +117,8 @@ extern const char *nds32_output_32bit_load_s (rtx *, int); /* Auxiliary functions to output stack push/pop instruction. */ -extern const char *nds32_output_stack_push (void); -extern const char *nds32_output_stack_pop (void); +extern const char *nds32_output_stack_push (rtx); +extern const char *nds32_output_stack_pop (rtx); /* Auxiliary functions to decide output alignment or not. */ diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md index da3a97a..ccf33d9 100644 --- a/gcc/config/nds32/nds32.md +++ b/gcc/config/nds32/nds32.md @@ -2025,12 +2025,14 @@ create_template: ])] "" { - return nds32_output_stack_push (); + return nds32_output_stack_push (operands[0]); } [(set_attr "type" "misc") (set_attr "enabled" "1") (set (attr "length") - (if_then_else (match_test "TARGET_V3PUSH") + (if_then_else (match_test "TARGET_V3PUSH + && !nds32_isr_function_p (cfun->decl) + && (cfun->machine->va_args_size == 0)") (const_int 2) (const_int 4)))]) @@ -2045,12 +2047,14 @@ create_template: ])] "" { - return nds32_output_stack_pop (); + return nds32_output_stack_pop (operands[0]); } [(set_attr "type" "misc") (set_attr "enabled" "1") (set (attr "length") - (if_then_else (match_test "TARGET_V3PUSH") + (if_then_else (match_test "TARGET_V3PUSH + && !nds32_isr_function_p (cfun->decl) + && (cfun->machine->va_args_size == 0)") (const_int 2) (const_int 4)))]) -- 1.9.0