+2018-04-04 Chung-Ju Wu <jasonwucj@gmail.com>
+ Kito Cheng <kito.cheng@gmail.com>
+
+ * config/nds32/nds32-md-auxiliary.c (nds32_long_call_p): New function.
+ * config/nds32/nds32-protos.h (nds32_long_call_p): Declare.
+ * config/nds32/nds32.c (nds32_function_ok_for_sibcall): New function.
+ (TARGET_FUNCTION_OK_FOR_SIBCALL): Define.
+ * config/nds32/nds32.md (sibcall_internal): New.
+ (sibcall_register): Remove.
+ (sibcall_immediate): Remove.
+ (sibcall_value_internal): New.
+ (sibcall_value_register): Remove.
+ (sibcall_value_immediate): Remove.
+ * config/nds32/predicates.md (nds32_general_register_operand): New.
+ (nds32_call_address_operand): New.
+
2018-04-03 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/85167
}
}
}
+
+/* Return true X is need use long call. */
+bool
+nds32_long_call_p (rtx symbol)
+{
+ return TARGET_CMODEL_LARGE;
+}
extern const char *nds32_output_casesi_pc_relative (rtx *);
extern const char *nds32_output_casesi (rtx *);
+/* Auxiliary functions to identify long-call symbol. */
+extern bool nds32_long_call_p (rtx);
+
/* Auxiliary functions to identify 16 bit addresing mode. */
extern enum nds32_16bit_address_type nds32_mem_format (rtx);
/* -- Permitting tail calls. */
+/* Return true if it is ok to do sibling call optimization. */
+static bool
+nds32_function_ok_for_sibcall (tree decl,
+ tree exp ATTRIBUTE_UNUSED)
+{
+ /* The DECL is NULL if it is an indirect call. */
+
+ /* 1. Do not apply sibling call if -mv3push is enabled,
+ because pop25 instruction also represents return behavior.
+ 2. If this function is a variadic function, do not apply sibling call
+ because the stack layout may be a mess.
+ 3. We don't want to apply sibling call optimization for indirect
+ sibcall because the pop behavior in epilogue may pollute the
+ content of caller-saved regsiter when the register is used for
+ indirect sibcall. */
+ return (!TARGET_V3PUSH
+ && (cfun->machine->va_args_size == 0)
+ && decl);
+}
+
/* Determine whether we need to enable warning for function return check. */
static bool
nds32_warn_func_return (tree decl)
/* -- Permitting tail calls. */
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL nds32_function_ok_for_sibcall
+
#undef TARGET_WARN_FUNC_RETURN
#define TARGET_WARN_FUNC_RETURN nds32_warn_func_return
;; The sibcall patterns.
;; sibcall
-;; sibcall_register
-;; sibcall_immediate
+;; sibcall_internal
(define_expand "sibcall"
[(parallel [(call (match_operand 0 "memory_operand" "")
(const_int 0))
(clobber (reg:SI TA_REGNUM))
(return)])]
- ""
- ""
-)
-
-(define_insn "*sibcall_register"
- [(parallel [(call (mem (match_operand:SI 0 "register_operand" "r, r"))
- (match_operand 1))
- (clobber (reg:SI TA_REGNUM))
- (return)])]
- ""
- "@
- jr5\t%0
- jr\t%0"
- [(set_attr "type" "branch,branch")
- (set_attr "length" " 2, 4")])
+ "")
-(define_insn "*sibcall_immediate"
- [(parallel [(call (mem (match_operand:SI 0 "immediate_operand" "i"))
+(define_insn "sibcall_internal"
+ [(parallel [(call (mem (match_operand:SI 0 "nds32_call_address_operand" "r, i"))
(match_operand 1))
(clobber (reg:SI TA_REGNUM))
(return)])]
""
{
- if (TARGET_CMODEL_LARGE)
- return "b\t%0";
- else
- return "j\t%0";
+ switch (which_alternative)
+ {
+ case 0:
+ if (TARGET_16_BIT)
+ return "jr5\t%0";
+ else
+ return "jr\t%0";
+ case 1:
+ if (nds32_long_call_p (operands[0]))
+ return "b\t%0";
+ else
+ return "j\t%0";
+ 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" "1")
+ (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))
+ ])]
+)
;; sibcall_value
-;; sibcall_value_register
+;; sibcall_value_internal
;; sibcall_value_immediate
(define_expand "sibcall_value"
(const_int 0)))
(clobber (reg:SI TA_REGNUM))
(return)])]
- ""
- ""
-)
-
-(define_insn "*sibcall_value_register"
- [(parallel [(set (match_operand 0)
- (call (mem (match_operand:SI 1 "register_operand" "r, r"))
- (match_operand 2)))
- (clobber (reg:SI TA_REGNUM))
- (return)])]
- ""
- "@
- jr5\t%1
- jr\t%1"
- [(set_attr "type" "branch,branch")
- (set_attr "length" " 2, 4")])
+ "")
-(define_insn "*sibcall_value_immediate"
+(define_insn "sibcall_value_internal"
[(parallel [(set (match_operand 0)
- (call (mem (match_operand:SI 1 "immediate_operand" "i"))
+ (call (mem (match_operand:SI 1 "nds32_call_address_operand" "r, i"))
(match_operand 2)))
(clobber (reg:SI TA_REGNUM))
(return)])]
""
{
- if (TARGET_CMODEL_LARGE)
- return "b\t%1";
- else
- return "j\t%1";
+ switch (which_alternative)
+ {
+ case 0:
+ if (TARGET_16_BIT)
+ return "jr5\t%1";
+ else
+ return "jr\t%1";
+ case 1:
+ if (nds32_long_call_p (operands[1]))
+ return "b\t%1";
+ else
+ return "j\t%1";
+ 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" "1")
+ (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))
+ ])]
+)
;; ----------------------------------------------------------------------------
return true;
})
+(define_predicate "nds32_general_register_operand"
+ (match_code "reg,subreg")
+{
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ return (REG_P (op)
+ && (REGNO (op) >= FIRST_PSEUDO_REGISTER
+ || REGNO (op) <= NDS32_LAST_GPR_REGNUM));
+})
+
+(define_predicate "nds32_call_address_operand"
+ (ior (match_operand 0 "nds32_symbolic_operand")
+ (match_operand 0 "nds32_general_register_operand")))
+
(define_predicate "nds32_lmw_smw_base_operand"
(and (match_code "mem")
(match_test "nds32_valid_smw_lwm_base_p (op)")))