On Mon, Mar 5, 2012 at 9:11 AM, H.J. Lu <hjl.to...@gmail.com> wrote: > On Sun, Mar 4, 2012 at 11:47 PM, Uros Bizjak <ubiz...@gmail.com> wrote: >> On Mon, Mar 5, 2012 at 4:53 AM, H.J. Lu <hjl.to...@gmail.com> wrote: >> >>> and compiler does generate the same output. i386.c also has >>> >>> xasm = "jmp\t%A0"; >>> xasm = "call\t%A0"; >>> >>> for calls. There are no separate indirect call patterns. For x32, >>> only indirect register calls have to be in DImode. The direct call >>> should be in Pmode (SImode). >> >> Direct call just expects label to some abolute address that is assumed >> to fit in 32 bits (see constant_call_address_operand_p). >> >> call and jmp insn expect word_mode operands, so please change >> ix86_expand_call and call patterns in the same way as jump >> instructions above. >> >>> Since x86-64 hardware always zero-extends upper 32bits of 64bit >>> registers when loading its lower 32bits, it is safe and easier to just >>> to output 64bit registers for %A than zero-extend it by hand for all >>> jump/call patterns. >> >> No, the instruction expects word_mode operands, so we have to extend >> values to expected mode. I don't think that patching at insn output >> time is acceptable. > > You are right. I found a testcase to show problem: > > struct foo > { > void (*f) (void); > int i; > }; > > void > __attribute__ ((noinline)) > bar (struct foo x) > { > x.f (); > } > > "x" is passed in RDI and the uppper 32bits of RDI is "int i". >
Operand 1 of calls must be in Pmode for SYMOL_REF and word_mode for register. When I removed :P like @@ -11423,7 +11428,7 @@ (define_insn "*call_value" [(set (match_operand 0 "" "") - (call (mem:QI (match_operand:P 1 "call_insn_operand" "<c>zw")) + (call (mem:QI (match_operand 1 "call_insn_operand" "<c>zw")) (match_operand 2 "" "")))] "!SIBLING_CALL_P (insn)" "* return ix86_output_call_insn (insn, operands[1]);" I got In file included from /net/gnu-6/export/gnu/import/git/gcc-addr32/libgcc/unwind-dw2.c:1633:0: /net/gnu-6/export/gnu/import/git/gcc-addr32/libgcc/unwind.inc: In function \u2018_Unwind_ForcedUnwind_Phase2\u2019: /net/gnu-6/export/gnu/import/git/gcc-addr32/libgcc/unwind.inc:189:1: error: unable to find a register to spill in class \u2018CREG\u2019 /net/gnu-6/export/gnu/import/git/gcc-addr32/libgcc/unwind.inc:189:1: error: this is the insn: (call_insn 62 60 63 9 (set (reg:SI 0 ax) (call (mem:QI (reg/f:DI 0 ax [orig:88 D.9044 ] [88]) [0 *D.9044_25 S1 A8]) (const_int 0 [0]))) /net/gnu-6/export/gnu/import/git/gcc-addr32/libgcc/unwind.inc:175 629 {*call_value} (expr_list:REG_DEAD (reg/f:DI 0 ax [orig:88 D.9044 ] [88]) (expr_list:REG_DEAD (reg:DI 37 r8) (expr_list:REG_DEAD (reg:SI 5 di) (expr_list:REG_DEAD (reg:SI 4 si) (expr_list:REG_DEAD (reg:DI 2 cx) (expr_list:REG_DEAD (reg:DI 1 dx) (nil))))))) (expr_list:REG_BR_PRED (use (reg:SI 5 di)) (expr_list:REG_BR_PRED (use (reg:SI 4 si)) (expr_list:REG_FRAME_RELATED_EXPR (use (reg:DI 1 dx)) (expr_list:REG_BR_PRED (use (reg:DI 2 cx)) (expr_list:REG_BR_PRED (use (reg:DI 37 r8)) (nil))))))) /net/gnu-6/export/gnu/import/git/gcc-addr32/libgcc/unwind.inc:189:1: internal compiler error: in spill_failure, at reload1.c:2120 Please submit a full bug report, with preprocessed source if appropriate. See <http://gcc.gnu.org/bugs.html> for instructions. Here is a patch to duplicate function symbol to change it from Pmode to word_mode. It seems to work. But I am not sure if it is the right approach. Any suggestions? Thanks. -- H.J. --- diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 1828cf6..26e23c7 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -22976,6 +22975,19 @@ construct_plt_address (rtx symbol) return tmp; } +static rtx +duplicate_function_symbol_ref (enum machine_mode mode, rtx fnaddr) +{ + rtx dup_symbol_ref; + gcc_assert (!SYMBOL_REF_HAS_BLOCK_INFO_P (fnaddr)); + dup_symbol_ref = gen_rtx_SYMBOL_REF (mode, XSTR (fnaddr, 0)); + SYMBOL_REF_USED (dup_symbol_ref) = SYMBOL_REF_USED (fnaddr); + SYMBOL_REF_WEAK (dup_symbol_ref) = SYMBOL_REF_WEAK (fnaddr); + SET_SYMBOL_REF_DECL (dup_symbol_ref, SYMBOL_REF_DECL (fnaddr)); + SYMBOL_REF_FLAGS (dup_symbol_ref) = SYMBOL_REF_FLAGS (fnaddr); + return dup_symbol_ref; +} + rtx ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx callarg2, @@ -23026,13 +23038,22 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, && !local_symbolic_operand (XEXP (fnaddr, 0), VOIDmode)) fnaddr = gen_rtx_MEM (QImode, construct_plt_address (XEXP (fnaddr, 0))); else if (sibcall - ? !sibcall_insn_operand (XEXP (fnaddr, 0), Pmode) - : !call_insn_operand (XEXP (fnaddr, 0), Pmode)) + ? !sibcall_insn_operand (XEXP (fnaddr, 0), word_mode) + : !call_insn_operand (XEXP (fnaddr, 0), word_mode)) { fnaddr = XEXP (fnaddr, 0); - if (GET_MODE (fnaddr) != Pmode) - fnaddr = convert_to_mode (Pmode, fnaddr, 1); - fnaddr = gen_rtx_MEM (QImode, copy_to_mode_reg (Pmode, fnaddr)); + if (TARGET_X32 && GET_CODE (fnaddr) == SYMBOL_REF) + { + fnaddr = duplicate_function_symbol_ref (word_mode, fnaddr); + fnaddr = gen_rtx_MEM (QImode, fnaddr); + } + else + { + if (GET_MODE (fnaddr) != word_mode) + fnaddr = convert_to_mode (word_mode, fnaddr, 1); + fnaddr = gen_rtx_MEM (QImode, + copy_to_mode_reg (word_mode, fnaddr)); + } } vec_len = 0; @@ -23122,7 +23143,7 @@ ix86_split_call_vzeroupper (rtx insn, rtx vzeroupper) const char * ix86_output_call_insn (rtx insn, rtx call_op) { - bool direct_p = constant_call_address_operand (call_op, Pmode); + bool direct_p = constant_call_address_operand (call_op, word_mode); bool seh_nop_p = false; const char *xasm; @@ -32211,6 +32232,16 @@ x86_output_mi_thunk (FILE *file, emit_jump_insn (gen_indirect_jump (fnaddr)); else { + if (GET_MODE (fnaddr) != word_mode) + { + if (TARGET_X32 && GET_CODE (fnaddr) == SYMBOL_REF) + fnaddr = duplicate_function_symbol_ref (word_mode, fnaddr); + else + { + fnaddr = convert_to_mode (word_mode, fnaddr, 1); + fnaddr = copy_to_mode_reg (word_mode, fnaddr); + } + } tmp = gen_rtx_MEM (QImode, fnaddr); tmp = gen_rtx_CALL (VOIDmode, tmp, const0_rtx); tmp = emit_call_insn (tmp); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 715e7ea..3f7f4f1 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -11100,10 +11100,15 @@ (set_attr "modrm" "0")]) (define_expand "indirect_jump" - [(set (pc) (match_operand 0 "indirect_branch_operand" ""))]) + [(set (pc) (match_operand 0 "indirect_branch_operand" ""))] + "" +{ + if (TARGET_X32) + operands[0] = convert_memory_address (word_mode, operands[0]); +}) (define_insn "*indirect_jump" - [(set (pc) (match_operand:P 0 "indirect_branch_operand" "rw"))] + [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw"))] "" "jmp\t%A0" [(set_attr "type" "ibr") @@ -11145,12 +11150,12 @@ operands[0] = expand_simple_binop (Pmode, code, op0, op1, NULL_RTX, 0, OPTAB_DIRECT); } - else if (TARGET_X32) - operands[0] = convert_memory_address (Pmode, operands[0]); + if (TARGET_X32) + operands[0] = convert_memory_address (word_mode, operands[0]); }) (define_insn "*tablejump_1" - [(set (pc) (match_operand:P 0 "indirect_branch_operand" "rw")) + [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rw")) (use (label_ref (match_operand 1 "" "")))] "" "jmp\t%A0" @@ -11237,7 +11242,7 @@ }) (define_insn_and_split "*call_vzeroupper" - [(call (mem:QI (match_operand:P 0 "call_insn_operand" "<c>zw")) + [(call (mem:QI (match_operand:W 0 "call_insn_operand" "<c>zw")) (match_operand 1 "" "")) (unspec [(match_operand 2 "const_int_operand" "")] UNSPEC_CALL_NEEDS_VZEROUPPER)] @@ -11249,7 +11254,7 @@ [(set_attr "type" "call")]) (define_insn "*call" - [(call (mem:QI (match_operand:P 0 "call_insn_operand" "<c>zw")) + [(call (mem:QI (match_operand:W 0 "call_insn_operand" "<c>zw")) (match_operand 1 "" ""))] "!SIBLING_CALL_P (insn)" "* return ix86_output_call_insn (insn, operands[0]);" @@ -11301,7 +11306,7 @@ [(set_attr "type" "call")]) (define_insn_and_split "*sibcall_vzeroupper" - [(call (mem:QI (match_operand:P 0 "sibcall_insn_operand" "Uz")) + [(call (mem:QI (match_operand:W 0 "sibcall_insn_operand" "Uz")) (match_operand 1 "" "")) (unspec [(match_operand 2 "const_int_operand" "")] UNSPEC_CALL_NEEDS_VZEROUPPER)] @@ -11313,7 +11318,7 @@ [(set_attr "type" "call")]) (define_insn "*sibcall" - [(call (mem:QI (match_operand:P 0 "sibcall_insn_operand" "Uz")) + [(call (mem:QI (match_operand:W 0 "sibcall_insn_operand" "Uz")) (match_operand 1 "" ""))] "SIBLING_CALL_P (insn)" "* return ix86_output_call_insn (insn, operands[0]);" @@ -11410,7 +11415,7 @@ (define_insn_and_split "*call_value_vzeroupper" [(set (match_operand 0 "" "") - (call (mem:QI (match_operand:P 1 "call_insn_operand" "<c>zw")) + (call (mem:QI (match_operand:W 1 "call_insn_operand" "<c>zw")) (match_operand 2 "" ""))) (unspec [(match_operand 3 "const_int_operand" "")] UNSPEC_CALL_NEEDS_VZEROUPPER)] @@ -11423,7 +11428,7 @@ (define_insn "*call_value" [(set (match_operand 0 "" "") - (call (mem:QI (match_operand:P 1 "call_insn_operand" "<c>zw")) + (call (mem:QI (match_operand:W 1 "call_insn_operand" "<c>zw")) (match_operand 2 "" "")))] "!SIBLING_CALL_P (insn)" "* return ix86_output_call_insn (insn, operands[1]);" @@ -11431,7 +11436,7 @@ (define_insn_and_split "*sibcall_value_vzeroupper" [(set (match_operand 0 "" "") - (call (mem:QI (match_operand:P 1 "sibcall_insn_operand" "Uz")) + (call (mem:QI (match_operand:W 1 "sibcall_insn_operand" "Uz")) (match_operand 2 "" ""))) (unspec [(match_operand 3 "const_int_operand" "")] UNSPEC_CALL_NEEDS_VZEROUPPER)] @@ -11444,7 +11449,7 @@ (define_insn "*sibcall_value" [(set (match_operand 0 "" "") - (call (mem:QI (match_operand:P 1 "sibcall_insn_operand" "Uz")) + (call (mem:QI (match_operand:W 1 "sibcall_insn_operand" "Uz")) (match_operand 2 "" "")))] "SIBLING_CALL_P (insn)" "* return ix86_output_call_insn (insn, operands[1]);"