This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: i386.md splits (hope final version)



Hi
Here is an updated patch for extendsidi case. I've added flow2_completed
variale and rewrote splits into C statements. It is now handled by
three splits. Two splits are neccesary because reg->reg case should be
split before flow analysis and the third one is needed to handle
reg_dead note, because split can't look for it.

I've also found problems in Jeff's version of handling clobbers.
Following code:

char pole[];
main(int a)
{
  *((long long *)(pole+a))=a;
}

Resulted in code that first store firt half to correct address, then shifted
eax and stored result to incorrect address, because it was originally adressed
using eax. So I've changed clobber to use &r1 constraint to say reload to
get temporary register not conflicting with adress of destination.
I've later changed it to two alternatived &r, &1 because reload then
always choose &1 case, moved source register for me and thus increased
flow dependencies.

This is probably the only important change I've done. Resulting code
is now quite good IMO. For example following code:

int a;
long long b;
 long main()
{
b=a;
return (a);
}

Generated:

	pushl %esi
	movl a,%ecx
	pushl %ebx
	movl %ecx,%ebx
	movl %ebx,%esi
	sarl $31,%esi
	movl %ebx,%eax
	movl %esi,%edx
	popl %ebx
	movl %eax,b
	movl %edx,b+4
	popl %esi
	movl %ecx,%eax
	ret

And now does:

	movl a,%eax
	cltd
	movl %eax,b
	movl %edx,b+4
	ret

(so egcs now tunnels the result trought extended value :)
Honza

Thu Nov  5 15:56:42 MET 1998  Jeffrey A Law (law@cygnus.com), Jan Hubicka (hubicka@freesoft.cz)
	* recog.c: (flow2_completed) new global variable
	* rtl.h: (flow2_completed) declare
	* toplev.c: (flow2_completed) set variable
	* i386.md: (extendsidi3) use # and handle by splits

*** gcc/rtl.h.old	Thu Nov  5 15:51:32 1998
--- gcc/rtl.h	Thu Nov  5 15:52:15 1998
*************** extern union tree_node *make_tree	PROTO(
*** 1191,1196 ****
--- 1191,1201 ----
  
  extern int reload_completed;
  
+ /* Nonzero after end of second dataflow pass.
+    Set to 1 or 0 by toplev.c.  */
+ 
+ extern int flow2_completed;
+ 
  /* Set to 1 while reload_as_needed is operating.
     Required by some machines to handle any generated moves differently.  */
  
*** gcc/toplev.c.old	Thu Nov  5 15:52:23 1998
--- gcc/toplev.c	Thu Nov  5 15:54:12 1998
*************** rest_of_compilation (decl)
*** 3803,3808 ****
--- 3803,3810 ----
  	 life_analysis (insns, max_reg_num (), rtl_dump_file);
         });
  
+   flow2_completed = 1;
+ 
    /* On some machines, the prologue and epilogue code, or parts thereof,
       can be represented as RTL.  Doing so lets us schedule insns between
       it and the rest of the code and also allows delayed branch
*************** rest_of_compilation (decl)
*** 3972,3977 ****
--- 3974,3980 ----
      }
  
    reload_completed = 0;
+   flow2_completed = 0;
  
    TIMEVAR (final_time,
  	   {
*** gcc/recog.c.old	Thu Nov  5 16:07:30 1998
--- gcc/recog.c	Thu Nov  5 16:07:12 1998
*************** int which_alternative;
*** 106,111 ****
--- 106,116 ----
  
  int reload_completed;
  
+ /* nonzero after end of second dataflow pass.
+    set to 1 or 0 by toplev.c. */
+ 
+ int flow2_completed;
+ 
  /* Initialize data used by the function `recog'.
     This must be called once in the compilation of a function
     before any insn recognition may be done in the function.  */
*** gcc/config/i386/i386.md.orig	Thu Nov  5 16:14:11 1998
--- gcc/config/i386/i386.md	Thu Nov  5 17:12:35 1998
***************
*** 2045,2071 ****
  ;;- sign extension instructions
  
  (define_insn "extendsidi2"
!   [(set (match_operand:DI 0 "register_operand" "=r")
! 	(sign_extend:DI (match_operand:SI 1 "register_operand" "0")))]
    ""
!   "*
! {
!   if (REGNO (operands[0]) == 0)
!     {
!       /* This used to be cwtl, but that extends HI to SI somehow.  */
! #ifdef INTEL_SYNTAX
!       return \"cdq\";
! #else
!       return \"cltd\";
! #endif
!     }
! 
!   operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
!   output_asm_insn (AS2 (mov%L0,%0,%1), operands);
! 
!   operands[0] = GEN_INT (31);
!   return AS2 (sar%L1,%0,%1);
! }")
  
  ;; Note that the i386 programmers' manual says that the opcodes
  ;; are named movsx..., but the assembler on Unix does not accept that.
--- 2045,2117 ----
  ;;- sign extension instructions
  
  (define_insn "extendsidi2"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=A,?r,?Ar,*o,*o")
! 	(sign_extend:DI (match_operand:SI 1 "register_operand" "0,0,r,*r,*r")))
!    (clobber (match_scratch:SI 2 "=X,X,X,&r,&1"))]
    ""
!   "#")
! 
! ;; Extend to memory case when source register does die case
! (define_split 
!   [(set (match_operand:DI 0 "memory_operand" "")
! 	(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
!    (clobber (match_operand:SI 2 "register_operand" ""))]
!   "flow2_completed && dead_or_set_p (insn, operands[1]) && !reg_mentioned_p (operands[1], operands[0])"
!   [(set (match_dup 3) (match_dup 1))
!    (set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31)))
!    (set (match_dup 4) (match_dup 1))]
!   "split_di (&operands[0], 1, &operands[3], &operands[4]);")
! 
! ;; Extend to memory case when source register does not die case
! (define_split 
!   [(set (match_operand:DI 0 "memory_operand" "")
! 	(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
!    (clobber (match_operand:SI 2 "register_operand" ""))]
!   "flow2_completed"
!   [(const_int 0)]
!   "{
!     split_di (&operands[0], 1, &operands[3], &operands[4]);
! 
!     emit_move_insn (operands[3], operands[1]);
!     if (!true_regnum (operands[1]) && true_regnum(operands[2]) == 1
!         && (optimize_size || !TARGET_PENTIUM))
!       {  /*ctld case*/
!          emit_insn (gen_ashrsi3_31 (operands[2], operands[1]));
!       }
!     else
!       {
!          emit_move_insn (operands[2], operands[1]);
!          emit_insn (gen_ashrsi3_31 (operands[2], operands[2]));
!       }
!     emit_move_insn (operands[4], operands[2]);
!     DONE;
!   }")
! 
! ;; Use ctld pattern in case target is eax and we are not optimizing for
! ;; Pentium. Otherwise use move and shift combination. 
! (define_split 
!   [(set (match_operand:DI 0 "register_operand" "")
! 	(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
!    (clobber (match_scratch:SI 2 "X"))]
!   "reload_completed"
!   [(const_int 0)]
!   "split_di (&operands[0], 1, &operands[3], &operands[4]);
! 
!    if (true_regnum (operands[3]) != true_regnum (operands[1]))
!      emit_move_insn (operands[3], operands[1]);
! 
!    /* Emit cltd case */
!    if (!true_regnum (operands[3]) && (optimize_size || !TARGET_PENTIUM))
!      {
!        emit_insn (gen_ashrsi3_31 (operands[4], operands[3]));
!        DONE;
!      }
! 
!    if (true_regnum (operands[4]) != true_regnum (operands[1]))
!      emit_move_insn (operands[4], operands[1]);
! 
!    emit_insn (gen_ashrsi3_31 (operands[4], operands[4]));
!    DONE;")
  
  ;; Note that the i386 programmers' manual says that the opcodes
  ;; are named movsx..., but the assembler on Unix does not accept that.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]