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]

Patch to model i386 direction flag.



Hi
This patch models i386's direction flag as extra register.
This makes possible to avoid redundant cld instructions emited
by gcc.

It also makes proper scheduling and size calculation of CLD instruction.
I've also added the STR type for movs? instructions I want to use
in momentarity.

This patch is based on my older string ops rewrite. I would like to settle
down all my patches adding new registers before I restart work on INDREG
stuff.

San Jan  9 05:08:14 CET 2000  Jan Hubicka  <jh@suse.cz>
	* i386.c (ix86_attr_length_default): Handle TYPE_STR and TYPE_CLD.
	* i386.md (FIRST_PSEUDO_REGISTER): Set to 20.
	(FIXED_REGISTERS): Set dirflag as fixed.
	(CALL_USED_REGISTERS): Set dirflag as used.
	(REG_ALLOC_ORDER): Set dirflag as last one.
	(DIRFLAG_REG): New macro.
	(MD_ASM_CLOBBERS): Asm clobber dirflag for backward compatibility.
	(HI_REGISTER_NAMES): Add dirflag.
	(DEBUF_PRINT_REG): Handle dirflag.
	* i386.md (type attribute): New cld and str types.
	(length_opcode attribute): Set cld and str to 1.
	(memory attribute): Set str to unknown - it is not clear from the
	patterns.
	(pent_np function unit): Prefixed string operations takes 12 cycles
	minimally; cld takes 2 cycles.
	(ppro_uops attribute): Str is "many" and cld is "few".
	(ppro_p0 unit): Handle cld here.
	(k6_alux unit): Handle cld and str types.
	(k6_load unit): It is ocupied by str opcodes.
	(k6_store unit): It is ocupied by str opcodes.
	(athlon_decode): Str is vector decoded.
	(athlon_ieu): Handle str and cld.
	(cld pattern): New.
	(movstrsi, clrstr, cmpstr, strlen expander): Emit cld instruction
	(movstrsi_1, clrstrsi_1, cmpstrsi_1, strlensi_1,
	cmpstrsi_nz_1 insn): Do not output cld instruction

*** ../i386.old/i386.c	Sun Jan  9 03:14:53 2000
--- i386.c	Sun Jan  9 03:36:05 2000
*************** ix86_attr_length_default (insn)
*** 5443,5448 ****
--- 5444,5452 ----
      case TYPE_FCMOV:
      case TYPE_IBR:
        break;
+     case TYPE_STR:
+     case TYPE_CLD:
+       len = 0;
  
      case TYPE_ALU1:
      case TYPE_NEGNOT:
*** ../i386.old/i386.h	Sun Jan  9 03:14:53 2000
--- i386.h	Sun Jan  9 03:35:21 2000
*************** extern int ix86_arch;
*** 610,616 ****
     eliminated during reloading in favor of either the stack or frame
     pointer. */
  
! #define FIRST_PSEUDO_REGISTER 19
  
  /* Number of hardware registers that go into the DWARF-2 unwind info.
     If not defined, equals FIRST_PSEUDO_REGISTER.  */
--- 611,617 ----
     eliminated during reloading in favor of either the stack or frame
     pointer. */
  
! #define FIRST_PSEUDO_REGISTER 20
  
  /* Number of hardware registers that go into the DWARF-2 unwind info.
     If not defined, equals FIRST_PSEUDO_REGISTER.  */
*************** extern int ix86_arch;
*** 621,628 ****
     and are not available for the register allocator.
     On the 80386, the stack pointer is such, as is the arg pointer. */
  #define FIXED_REGISTERS \
! /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,flags,fpsr*/ \
! {  0, 0, 0, 0, 0, 0, 0, 1, 0,  0,  0,  0,  0,  0,  0,  0,  1,    0,   0 }
  
  /* 1 for registers not available across function calls.
     These must include the FIXED_REGISTERS and also any
--- 622,629 ----
     and are not available for the register allocator.
     On the 80386, the stack pointer is such, as is the arg pointer. */
  #define FIXED_REGISTERS \
! /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,flags,fpsr, dir*/ \
! {  0, 0, 0, 0, 0, 0, 0, 1, 0,  0,  0,  0,  0,  0,  0,  0,  1,    0,   0,   0 }
  
  /* 1 for registers not available across function calls.
     These must include the FIXED_REGISTERS and also any
*************** extern int ix86_arch;
*** 632,639 ****
     Aside from that, you can include as many other registers as you like.  */
  
  #define CALL_USED_REGISTERS \
! /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,flags,fpsr*/ \
! {  1, 1, 1, 0, 0, 0, 0, 1, 1,  1,  1,  1,  1,  1,  1,  1,  1,    1,   1 }
  
  /* Order in which to allocate registers.  Each register must be
     listed once, even those in FIXED_REGISTERS.  List frame pointer
--- 633,640 ----
     Aside from that, you can include as many other registers as you like.  */
  
  #define CALL_USED_REGISTERS \
! /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,flags,fpsr, dir*/ \
! {  1, 1, 1, 0, 0, 0, 0, 1, 1,  1,  1,  1,  1,  1,  1,  1,  1,    1,   1,   1 }
  
  /* Order in which to allocate registers.  Each register must be
     listed once, even those in FIXED_REGISTERS.  List frame pointer
*************** extern int ix86_arch;
*** 655,662 ****
     generated by allocating edx first, so restore the 'natural' order of things. */
  
  #define REG_ALLOC_ORDER \
! /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,cc,fpsr*/ \
! {  0, 1, 2, 3, 4, 5, 6, 7, 8,  9, 10, 11, 12, 13, 14, 15, 16,17,  18 }
  
  /* A C statement (sans semicolon) to choose the order in which to
     allocate hard registers for pseudo-registers local to a basic
--- 656,663 ----
     generated by allocating edx first, so restore the 'natural' order of things. */
  
  #define REG_ALLOC_ORDER \
! /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,cc,fpsr, dir*/ \
! {  0, 1, 2, 3, 4, 5, 6, 7, 8,  9, 10, 11, 12, 13, 14, 15, 16,17,  18,  19 }
  
  /* A C statement (sans semicolon) to choose the order in which to
     allocate hard registers for pseudo-registers local to a basic
*************** extern int ix86_arch;
*** 764,769 ****
--- 765,771 ----
  
  #define FLAGS_REG 17
  #define FPSR_REG 18
+ #define DIRFLAG_REG 19
  
  /* Value should be nonzero if functions must have frame pointers.
     Zero means the frame pointer need not be set up (and parms
*************** enum reg_class
*** 1067,1072 ****
--- 1069,1075 ----
    do {									      \
      (CLOBBERS) = tree_cons (NULL_TREE, build_string (5, "flags"), (CLOBBERS));\
      (CLOBBERS) = tree_cons (NULL_TREE, build_string (4, "fpsr"), (CLOBBERS)); \
+     (CLOBBERS) = tree_cons (NULL_TREE, build_string (7, "dirflag"), (CLOBBERS)); \
    } while (0)
  
  /* Stack layout; function entry, exit and calling.  */
*************** while (0)
*** 2170,2176 ****
  #define HI_REGISTER_NAMES						\
  {"ax","dx","cx","bx","si","di","bp","sp",				\
   "st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)","",	\
!  "flags","fpsr" }
  
  #define REGISTER_NAMES HI_REGISTER_NAMES
  
--- 2173,2179 ----
  #define HI_REGISTER_NAMES						\
  {"ax","dx","cx","bx","si","di","bp","sp",				\
   "st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)","",	\
!  "flags","fpsr", "dirflag" }
  
  #define REGISTER_NAMES HI_REGISTER_NAMES
  
*************** do { long l;						\
*** 2383,2388 ****
--- 2386,2393 ----
         fprintf (FILE, "%d ", REGNO (X));		\
         if (REGNO (X) == FLAGS_REG)			\
  	 { fputs ("flags", FILE); break; }		\
+        if (REGNO (X) == DIRFLAG_REG)			\
+ 	 { fputs ("dirflag", FILE); break; }		\
         if (REGNO (X) == FPSR_REG)			\
  	 { fputs ("fpsr", FILE); break; }		\
         if (REGNO (X) == ARG_POINTER_REGNUM)		\
*** ../i386.old/i386.md	Sun Jan  9 03:14:53 2000
--- i386.md	Sun Jan  9 05:11:24 2000
***************
*** 83,89 ****
  ;; A basic instruction type.  Refinements due to arguments to be
  ;; provided in other attributes.
  (define_attr "type"
!   "other,multi,alu1,negnot,alu,icmp,imov,imovx,lea,incdec,ishift,imul,idiv,ibr,setcc,push,pop,call,callv,icmov,fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch"
    (const_string "other"))
  
  ;; The (bounding maximum) length of an instruction in bytes.
--- 83,89 ----
  ;; A basic instruction type.  Refinements due to arguments to be
  ;; provided in other attributes.
  (define_attr "type"
!   "other,multi,alu1,negnot,alu,icmp,imov,imovx,lea,incdec,ishift,imul,idiv,ibr,setcc,push,pop,call,callv,icmov,fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,str,cld"
    (const_string "other"))
  
  ;; The (bounding maximum) length of an instruction in bytes.
***************
*** 105,110 ****
--- 105,112 ----
  (define_attr "length_opcode" ""
    (cond [(eq_attr "type" "imovx,setcc,icmov")
  	   (const_int 3)
+ 	 (eq_attr "type" "str,cld")
+ 	   (const_int 1)
           (and (eq_attr "type" "incdec")
  	      (ior (match_operand:SI 1 "register_operand" "")
  		   (match_operand:HI 1 "register_operand" "")))
***************
*** 127,135 ****
  ;; if the instruction is complex.
  
  (define_attr "memory" "none,load,store,both,unknown"
!   (cond [(eq_attr "type" "other,multi")
  	   (const_string "unknown")
! 	 (eq_attr "type" "lea,fcmov,fpspc")
  	   (const_string "none")
  	 (eq_attr "type" "push")
  	   (if_then_else (match_operand 1 "memory_operand" "")
--- 129,137 ----
  ;; if the instruction is complex.
  
  (define_attr "memory" "none,load,store,both,unknown"
!   (cond [(eq_attr "type" "other,multi,str")
  	   (const_string "unknown")
! 	 (eq_attr "type" "lea,fcmov,fpspc,cld")
  	   (const_string "none")
  	 (eq_attr "type" "push")
  	   (if_then_else (match_operand 1 "memory_operand" "")
***************
*** 260,265 ****
--- 262,273 ----
         (eq_attr "type" "imul"))
    11 11)
  
+ ;; Rep movs takes minimally 12 cycles.
+ (define_function_unit "pent_np" 1 0
+   (and (eq_attr "cpu" "pentium")
+        (eq_attr "type" "str"))
+   12 12)
+ 
  ; ??? IDIV for SI takes 46 cycles, for HI 30, for QI 22
  (define_function_unit "pent_np" 1 0
    (and (eq_attr "cpu" "pentium")
***************
*** 304,309 ****
--- 312,322 ----
  	         (eq_attr "memory" "store"))))
    2 2)
  
+ (define_function_unit "pent_np" 1 0
+   (and (eq_attr "cpu" "pentium")
+        (eq_attr "type" "cld"))
+   2 2)
+ 
  (define_function_unit "fpu" 1 0
    (and (eq_attr "cpu" "pentium")
         (and (eq_attr "type" "fmov")
***************
*** 469,477 ****
  ;;	     cycles to decode in decoder 0.
  
  (define_attr "ppro_uops" "one,few,many"
!   (cond [(eq_attr "type" "other,multi,call,callv,fpspc")
  	   (const_string "many")
! 	 (eq_attr "type" "icmov,fcmov")
  	   (const_string "few")
  	 (eq_attr "type" "imov")
  	   (if_then_else (eq_attr "memory" "store,both")
--- 482,490 ----
  ;;	     cycles to decode in decoder 0.
  
  (define_attr "ppro_uops" "one,few,many"
!   (cond [(eq_attr "type" "other,multi,call,callv,fpspc,str")
  	   (const_string "many")
! 	 (eq_attr "type" "icmov,fcmov,str,cld")
  	   (const_string "few")
  	 (eq_attr "type" "imov")
  	   (if_then_else (eq_attr "memory" "store,both")
***************
*** 496,502 ****
  
  (define_function_unit "ppro_p0" 1 0
    (and (eq_attr "cpu" "pentiumpro")
!        (eq_attr "type" "ishift,lea,ibr"))
    1 1)
  
  (define_function_unit "ppro_p0" 1 0
--- 509,515 ----
  
  (define_function_unit "ppro_p0" 1 0
    (and (eq_attr "cpu" "pentiumpro")
!        (eq_attr "type" "ishift,lea,ibr,cld"))
    1 1)
  
  (define_function_unit "ppro_p0" 1 0
***************
*** 611,617 ****
  ;; Shift instructions and certain arithmetic are issued only to X pipe.
  (define_function_unit "k6_alux" 1 0
    (and (eq_attr "cpu" "k6")
!        (eq_attr "type" "ishift,alu1,negnot"))
    1 1)
  
  ;; The QI mode arithmetic is issued to X pipe only.
--- 624,630 ----
  ;; Shift instructions and certain arithmetic are issued only to X pipe.
  (define_function_unit "k6_alux" 1 0
    (and (eq_attr "cpu" "k6")
!        (eq_attr "type" "ishift,alu1,negnot,cld"))
    1 1)
  
  ;; The QI mode arithmetic is issued to X pipe only.
***************
*** 644,649 ****
--- 657,668 ----
  	    (eq_attr "memory" "load,both")))
    1 1)
  
+ (define_function_unit "k6_load" 1 0
+   (and (eq_attr "cpu" "k6")
+        (and (eq_attr "type" "str")
+ 	    (eq_attr "memory" "load,both")))
+   10 10)
+ 
  ;; Lea have two instructions, so latency is probably 2
  (define_function_unit "k6_store" 1 0
    (and (eq_attr "cpu" "k6")
***************
*** 652,657 ****
--- 671,681 ----
  
  (define_function_unit "k6_store" 1 0
    (and (eq_attr "cpu" "k6")
+        (eq_attr "type" "str"))
+   10 10)
+ 
+ (define_function_unit "k6_store" 1 0
+   (and (eq_attr "cpu" "k6")
         (ior (eq_attr "type" "push")
  	    (eq_attr "memory" "store,both")))
    1 1)
***************
*** 713,719 ****
  ;; communicates with all the execution units seperately instead.
  
  (define_attr "athlon_decode" "direct,vector"
!   (cond [(eq_attr "type" "call,imul,idiv,other,multi,fcmov,fpspc")
  	   (const_string "vector")
           (and (eq_attr "type" "push")
                (match_operand 1 "memory_operand" ""))
--- 737,743 ----
  ;; communicates with all the execution units seperately instead.
  
  (define_attr "athlon_decode" "direct,vector"
!   (cond [(eq_attr "type" "call,imul,idiv,other,multi,fcmov,fpspc,str")
  	   (const_string "vector")
           (and (eq_attr "type" "push")
                (match_operand 1 "memory_operand" ""))
***************
*** 741,751 ****
  
  (define_function_unit "athlon_ieu" 3 0
    (and (eq_attr "cpu" "athlon")
!        (eq_attr "type" "alu1,negnot,alu,icmp,imov,imovx,lea,incdec,ishift,imul,idiv,ibr,setcc,push,pop,call,callv,icmov"))
    1 1)
  
  (define_function_unit "athlon_ieu" 3 0
    (and (eq_attr "cpu" "athlon")
         (eq_attr "type" "imul"))
    4 0)
  
--- 765,780 ----
  
  (define_function_unit "athlon_ieu" 3 0
    (and (eq_attr "cpu" "athlon")
!        (eq_attr "type" "alu1,negnot,alu,icmp,imov,imovx,lea,incdec,ishift,imul,idiv,ibr,setcc,push,pop,call,callv,icmov,str,cld"))
    1 1)
  
  (define_function_unit "athlon_ieu" 3 0
    (and (eq_attr "cpu" "athlon")
+        (eq_attr "type" "str"))
+   15 15)
+ 
+ (define_function_unit "athlon_ieu" 3 0
+   (and (eq_attr "cpu" "athlon")
         (eq_attr "type" "imul"))
    4 0)
  
***************
*** 7786,7796 ****
--- 7815,7832 ----
  
  ;; Block operation instructions
  
+ (define_insn "cld"
+  [(set (reg:SI 19) (const_int 0))]
+  ""
+  "cld"
+   [(set_attr "type" "cld")])
+ 
  (define_expand "movstrsi"
    [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
  		   (match_operand:BLK 1 "memory_operand" ""))
  	      (use (match_operand:SI 2 "const_int_operand" ""))
  	      (use (match_operand:SI 3 "const_int_operand" ""))
+ 	      (use (reg:SI 19))
  	      (clobber (match_scratch:SI 4 ""))
  	      (clobber (match_dup 5))
  	      (clobber (match_dup 6))])]
***************
*** 7810,7815 ****
--- 7846,7852 ----
  
    operands[0] = change_address (operands[0], VOIDmode, addr0);
    operands[1] = change_address (operands[1], VOIDmode, addr1);
+   emit_insn (gen_cld ());
  }")
  
  ;; It might seem that operands 0 & 1 could use predicate register_operand.
***************
*** 7821,7826 ****
--- 7858,7864 ----
  	(mem:BLK (match_operand:SI 1 "address_operand" "S")))
     (use (match_operand:SI 2 "const_int_operand" "n"))
     (use (match_operand:SI 3 "immediate_operand" "i"))
+    (use (reg:SI 19))
     (clobber (match_scratch:SI 4 "=&c"))
     (clobber (match_dup 0))
     (clobber (match_dup 1))]
***************
*** 7829,7835 ****
  {
    rtx xops[2];
  
-   output_asm_insn (\"cld\", operands);
    if (GET_CODE (operands[2]) == CONST_INT)
      {
        if (INTVAL (operands[2]) & ~0x03)
--- 7867,7872 ----
***************
*** 7852,7863 ****
    [(set_attr "type" "multi")])
  
  (define_expand "clrstrsi"
!   [(set (match_dup 3) (const_int 0))
     (parallel [(set (match_operand:BLK 0 "memory_operand" "")
  		   (const_int 0))
  	      (use (match_operand:SI 1 "const_int_operand" ""))
  	      (use (match_operand:SI 2 "const_int_operand" ""))
  	      (use (match_dup 3))
  	      (clobber (match_scratch:SI 4 ""))
  	      (clobber (match_dup 5))])]
    ""
--- 7889,7902 ----
    [(set_attr "type" "multi")])
  
  (define_expand "clrstrsi"
!   [(set (reg:SI 19) (const_int 0))
!    (set (match_dup 3) (const_int 0))
     (parallel [(set (match_operand:BLK 0 "memory_operand" "")
  		   (const_int 0))
  	      (use (match_operand:SI 1 "const_int_operand" ""))
  	      (use (match_operand:SI 2 "const_int_operand" ""))
  	      (use (match_dup 3))
+ 	      (use (reg:SI 19))
  	      (clobber (match_scratch:SI 4 ""))
  	      (clobber (match_dup 5))])]
    ""
***************
*** 7874,7879 ****
--- 7913,7920 ----
    operands[5] = addr0;
  
    operands[0] = gen_rtx_MEM (BLKmode, addr0);
+ 
+   emit_insn (gen_cld ());
  }")
  
  ;; It might seem that operand 0 could use predicate register_operand.
***************
*** 7886,7891 ****
--- 7927,7933 ----
     (use (match_operand:SI 1 "const_int_operand" "n"))
     (use (match_operand:SI 2 "immediate_operand" "i"))
     (use (match_operand:SI 3 "register_operand" "a"))
+    (use (reg:SI 19))
     (clobber (match_scratch:SI 4 "=&c"))
     (clobber (match_dup 0))]
    ""
***************
*** 7893,7899 ****
  {
    rtx xops[2];
  
-   output_asm_insn (\"cld\", operands);
    if (GET_CODE (operands[1]) == CONST_INT)
      {
        unsigned int count = INTVAL (operands[1]) & 0xffffffff;
--- 7935,7940 ----
***************
*** 7955,7960 ****
--- 7996,8002 ----
       once cc0 is dead.  */
    align = operands[4];
  
+   emit_insn (gen_cld ());
    if (GET_CODE (count) == CONST_INT)
      {
        if (INTVAL (count) == 0)
***************
*** 8005,8015 ****
  		    (mem:BLK (match_operand:SI 1 "address_operand" "D"))))
     (use (match_operand:SI 2 "register_operand" "c"))
     (use (match_operand:SI 3 "immediate_operand" "i"))
     (clobber (match_dup 0))
     (clobber (match_dup 1))
     (clobber (match_dup 2))]
    ""
!   "cld\;repz{\;| }cmpsb"
    [(set_attr "type" "multi")
     (set_attr "length" "3")])
  
--- 8047,8058 ----
  		    (mem:BLK (match_operand:SI 1 "address_operand" "D"))))
     (use (match_operand:SI 2 "register_operand" "c"))
     (use (match_operand:SI 3 "immediate_operand" "i"))
+    (use (reg:SI 19))
     (clobber (match_dup 0))
     (clobber (match_dup 1))
     (clobber (match_dup 2))]
    ""
!   "repz{\;| }cmpsb"
    [(set_attr "type" "multi")
     (set_attr "length" "3")])
  
***************
*** 8023,8034 ****
  		      (mem:BLK (match_operand:SI 1 "address_operand" "D")))
  	  (const_int 0)))
     (use (match_operand:SI 3 "immediate_operand" "i"))
     (clobber (match_dup 0))
     (clobber (match_dup 1))
     (clobber (match_dup 2))]
    ""
    ;; The initial compare sets the zero flag.
!   "cmp{l}\\t%2, %2\;cld\;repz{\;| }cmpsb"
    [(set_attr "type" "multi")
     (set_attr "length" "5")])
  
--- 8066,8078 ----
  		      (mem:BLK (match_operand:SI 1 "address_operand" "D")))
  	  (const_int 0)))
     (use (match_operand:SI 3 "immediate_operand" "i"))
+    (use (reg:SI 19))
     (clobber (match_dup 0))
     (clobber (match_dup 1))
     (clobber (match_dup 2))]
    ""
    ;; The initial compare sets the zero flag.
!   "cmp{l}\\t%2, %2\;repz{\;| }cmpsb"
    [(set_attr "type" "multi")
     (set_attr "length" "5")])
  
***************
*** 8076,8081 ****
--- 8120,8126 ----
  
        emit_move_insn (scratch3, addr);
  
+       emit_insn (gen_cld ());
        emit_insn (gen_strlensi_1 (scratch1, scratch3, eoschar,
  				 align, constm1_rtx));
        emit_insn (gen_one_cmplsi2 (scratch2, scratch1));
***************
*** 8094,8103 ****
  		    (match_operand:QI 2 "general_operand" "a")
  		    (match_operand:SI 3 "immediate_operand" "i")
  		    (match_operand:SI 4 "immediate_operand" "0")] 0))
     (clobber (match_dup 1))
     (clobber (reg:CC 17))]
    ""
!   "cld\;repnz{\;| }scasb"
    [(set_attr "type" "multi")
     (set_attr "length" "3")])
  
--- 8139,8149 ----
  		    (match_operand:QI 2 "general_operand" "a")
  		    (match_operand:SI 3 "immediate_operand" "i")
  		    (match_operand:SI 4 "immediate_operand" "0")] 0))
+    (use (reg:SI 19))
     (clobber (match_dup 1))
     (clobber (reg:CC 17))]
    ""
!   "repnz{\;| }scasb"
    [(set_attr "type" "multi")
     (set_attr "length" "3")])
  

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