On Mon, Mar 5, 2012 at 9:11 AM, H.J. Lu <[email protected]> wrote:
> On Sun, Mar 4, 2012 at 11:47 PM, Uros Bizjak <[email protected]> wrote:
>> On Mon, Mar 5, 2012 at 4:53 AM, H.J. Lu <[email protected]> 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]);"