diff mbox

PATCH [1/n] addr32: Properly use Pmode and word_mode

Message ID CAMe9rOqTg9MJr+8M0NGSC6TRzQ0avvAc=ucvbs-L5TEBLQLCmw@mail.gmail.com
State New
Headers show

Commit Message

H.J. Lu March 6, 2012, 3:37 p.m. UTC
On Mon, Mar 5, 2012 at 9:11 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Sun, Mar 4, 2012 at 11:47 PM, Uros Bizjak <ubizjak@gmail.com> wrote:
>> On Mon, Mar 5, 2012 at 4:53 AM, H.J. Lu <hjl.tools@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.
diff mbox

Patch

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]);"