summaryrefslogtreecommitdiff
path: root/gcc/calls.c
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2009-02-20 10:13:17 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2009-02-20 10:13:17 +0000
commit4681dd41834c6955207e66cd3b9dc3b45299d63c (patch)
tree9126c53d1ae5105c5fed3f5605c764b6e48fc0bc /gcc/calls.c
parentae0d6a1cdc1fd1914e7960e7ac0b8739129dd62a (diff)
downloadgcc-4681dd41834c6955207e66cd3b9dc3b45299d63c.tar.gz
PR target/39240
* calls.c (expand_call): Clear try_tail_call if caller and callee disagree in promotion of function return value. * gcc.c-torture/execute/pr39240.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@144316 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/calls.c')
-rw-r--r--gcc/calls.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/gcc/calls.c b/gcc/calls.c
index 9dcf66298ca..df7481ab4de 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -2333,6 +2333,37 @@ expand_call (tree exp, rtx target, int ignore)
|| !lang_hooks.decls.ok_for_sibcall (fndecl))
try_tail_call = 0;
+ /* Check if caller and callee disagree in promotion of function
+ return value. */
+ if (try_tail_call)
+ {
+ enum machine_mode caller_mode, caller_promoted_mode;
+ enum machine_mode callee_mode, callee_promoted_mode;
+ int caller_unsignedp, callee_unsignedp;
+ tree caller_res = DECL_RESULT (current_function_decl);
+
+ caller_unsignedp = TYPE_UNSIGNED (TREE_TYPE (caller_res));
+ caller_mode = caller_promoted_mode = DECL_MODE (caller_res);
+ callee_unsignedp = TYPE_UNSIGNED (TREE_TYPE (funtype));
+ callee_mode = callee_promoted_mode = TYPE_MODE (TREE_TYPE (funtype));
+ if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
+ caller_promoted_mode
+ = promote_mode (TREE_TYPE (caller_res), caller_mode,
+ &caller_unsignedp, 1);
+ if (targetm.calls.promote_function_return (funtype))
+ callee_promoted_mode
+ = promote_mode (TREE_TYPE (funtype), callee_mode,
+ &callee_unsignedp, 1);
+ if (caller_mode != VOIDmode
+ && (caller_promoted_mode != callee_promoted_mode
+ || ((caller_mode != caller_promoted_mode
+ || callee_mode != callee_promoted_mode)
+ && (caller_unsignedp != callee_unsignedp
+ || GET_MODE_BITSIZE (caller_mode)
+ < GET_MODE_BITSIZE (callee_mode)))))
+ try_tail_call = 0;
+ }
+
/* Ensure current function's preferred stack boundary is at least
what we need. Stack alignment may also increase preferred stack
boundary. */