Hello! Attached patch fixes PR 53811. gcc failed to check if symbol_ref operands fits sibcall_insn_operand predicate. In case of -mcmodel=large, we must emit indirect jump for a sibcall.
2012-07-03 Uros Bizjak <ubiz...@gmail.com> PR target/53811 * config/i386/i386.c (x86_output_mi_thunk): Check if fnaddr satisfies sibcall_insn_operand. Move it to a temporary register if not. testsuite/ChangLog: 2012-07-03 Uros Bizjak <ubiz...@gmail.com> PR target/53811 * g++.dg/other/pr53811.C: New test. Tested on x86_64-pc-linux-gnu, committed to mainline SVN, similar patch will be committed to 4.7 branch. Uros.
Index: config/i386/i386.c =================================================================== --- config/i386/i386.c (revision 189191) +++ config/i386/i386.c (working copy) @@ -32931,7 +32931,19 @@ x86_output_mi_thunk (FILE *file, { rtx this_param = x86_this_parameter (function); rtx this_reg, tmp, fnaddr; + unsigned int tmp_regno; + if (TARGET_64BIT) + tmp_regno = R10_REG; + else + { + unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (function)); + if ((ccvt & (IX86_CALLCVT_FASTCALL | IX86_CALLCVT_THISCALL)) != 0) + tmp_regno = AX_REG; + else + tmp_regno = CX_REG; + } + emit_note (NOTE_INSN_PROLOGUE_END); /* If VCALL_OFFSET, we'll need THIS in a register. Might as well @@ -32957,7 +32969,7 @@ x86_output_mi_thunk (FILE *file, { if (!x86_64_general_operand (delta_rtx, Pmode)) { - tmp = gen_rtx_REG (Pmode, R10_REG); + tmp = gen_rtx_REG (Pmode, tmp_regno); emit_move_insn (tmp, delta_rtx); delta_rtx = tmp; } @@ -32970,18 +32982,7 @@ x86_output_mi_thunk (FILE *file, if (vcall_offset) { rtx vcall_addr, vcall_mem, this_mem; - unsigned int tmp_regno; - if (TARGET_64BIT) - tmp_regno = R10_REG; - else - { - unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (function)); - if ((ccvt & (IX86_CALLCVT_FASTCALL | IX86_CALLCVT_THISCALL)) != 0) - tmp_regno = AX_REG; - else - tmp_regno = CX_REG; - } tmp = gen_rtx_REG (Pmode, tmp_regno); this_mem = gen_rtx_MEM (ptr_mode, this_reg); @@ -33056,6 +33057,15 @@ x86_output_mi_thunk (FILE *file, emit_jump_insn (gen_indirect_jump (fnaddr)); else { + if (!sibcall_insn_operand (fnaddr, word_mode)) + { + tmp = gen_rtx_REG (word_mode, tmp_regno); + if (GET_MODE (fnaddr) != word_mode) + fnaddr = gen_rtx_ZERO_EXTEND (word_mode, fnaddr); + emit_move_insn (tmp, fnaddr); + fnaddr = tmp; + } + tmp = gen_rtx_MEM (QImode, fnaddr); tmp = gen_rtx_CALL (VOIDmode, tmp, const0_rtx); tmp = emit_call_insn (tmp); Index: testsuite/g++.dg/other/pr53811.C =================================================================== --- testsuite/g++.dg/other/pr53811.C (revision 0) +++ testsuite/g++.dg/other/pr53811.C (working copy) @@ -0,0 +1,29 @@ +// { dg-do compile } +// { dg-options "-mcmodel=large" { target { { i?86-*-* x86_64-*-* } && lp64 } } } + +struct ICCStringClass +{ + virtual void * + CreateString (const char *fromText) = 0; +}; + +struct AGSCCDynamicObject +{ + virtual void + Unserialize (int index, const char *serializedData, int dataSize) = 0; +}; + + +struct ScriptString:AGSCCDynamicObject, ICCStringClass +{ + virtual void *CreateString (const char *fromText); +}; + +const char * +CreateNewScriptString (const char *fromText, bool reAllocate = true); + +void * +ScriptString::CreateString (const char *fromText) +{ + return (void *) CreateNewScriptString (fromText); +}