diff options
author | Jakub Jelinek <jakub@redhat.com> | 2009-02-20 11:13:17 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2009-02-20 11:13:17 +0100 |
commit | c69cd1f5cd4256bea42452375dbf67c25bd6e4ef (patch) | |
tree | 9126c53d1ae5105c5fed3f5605c764b6e48fc0bc /gcc/calls.c | |
parent | bd967b22bc9acbf5c77a1a75fc6df199637f55e3 (diff) | |
download | gcc-c69cd1f5cd4256bea42452375dbf67c25bd6e4ef.zip gcc-c69cd1f5cd4256bea42452375dbf67c25bd6e4ef.tar.gz gcc-c69cd1f5cd4256bea42452375dbf67c25bd6e4ef.tar.bz2 |
re PR target/39240 (Invalid sibcall optimization with promoted return types and differing signedness)
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.
From-SVN: r144316
Diffstat (limited to 'gcc/calls.c')
-rw-r--r-- | gcc/calls.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/gcc/calls.c b/gcc/calls.c index 9dcf662..df7481a 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. */ |