Jump to content

Introspector/gcc/rtl/peephole/i386.md

From Wikibooks, open books for an open world

rtl.def:

/* Definition of an RTL peephole operation.
   Follows the same arguments as define_split.  */
DEF_RTL_EXPR(DEFINE_PEEPHOLE2, "define_peephole2", "EsES", 'x')
/* Definition of a split operation.
   1st operand: insn pattern to match
   2nd operand: C expression that must be true
   3rd operand: vector of insn patterns to place into a SEQUENCE
   4th operand: optionally, some C code to execute before generating the
	insns.  This might, for example, create some RTX's and store them in
	elements of `recog_data.operand' for use by the vector of
	insn-patterns.
	(`operands' is an alias here for `recog_data.operand').  */
DEF_RTL_EXPR(DEFINE_SPLIT, "define_split", "EsES", 'x')


file :config/i386/i386.md:

;; Peephole optimizations to clean up after cmpstr*.  This should be
;; handled in combine, but it is not currently up to the task.
;; When used for their truth value, the cmpstr* expanders generate
;; code like this:
;;
;;   repz cmpsb
;;   seta 	%al
;;   setb 	%dl
;;   cmpb 	%al, %dl
;;   jcc	label
;;
;; The intermediate three instructions are unnecessary.

;; This one handles cmpstr*_nz_1...
(define_peephole2
  [(parallel[
     (set (reg:CC 17)
	  (compare:CC (mem:BLK (match_operand 4 "register_operand" ""))
		      (mem:BLK (match_operand 5 "register_operand" ""))))
     (use (match_operand 6 "register_operand" ""))
     (use (match_operand:SI 3 "immediate_operand" ""))
     (use (reg:SI 19))
     (clobber (match_operand 0 "register_operand" ""))
     (clobber (match_operand 1 "register_operand" ""))
     (clobber (match_operand 2 "register_operand" ""))])
   (set (match_operand:QI 7 "register_operand" "")
	(gtu:QI (reg:CC 17) (const_int 0)))
   (set (match_operand:QI 8 "register_operand" "")
	(ltu:QI (reg:CC 17) (const_int 0)))
   (set (reg 17)
	(compare (match_dup 7) (match_dup 8)))
  ]
  "peep2_reg_dead_p (4, operands[7]) && peep2_reg_dead_p (4, operands[8])"
  [(parallel[
     (set (reg:CC 17)
	  (compare:CC (mem:BLK (match_dup 4))
		      (mem:BLK (match_dup 5))))
     (use (match_dup 6))
     (use (match_dup 3))
     (use (reg:SI 19))
     (clobber (match_dup 0))
     (clobber (match_dup 1))
     (clobber (match_dup 2))])]
  "")

;; ...and this one handles cmpstr*_1.
(define_peephole2
  [(parallel[
     (set (reg:CC 17)
	  (if_then_else:CC (ne (match_operand 6 "register_operand" "")
			       (const_int 0))
	    (compare:CC (mem:BLK (match_operand 4 "register_operand" ""))
		        (mem:BLK (match_operand 5 "register_operand" "")))
	    (const_int 0)))
     (use (match_operand:SI 3 "immediate_operand" ""))
     (use (reg:CC 17))
     (use (reg:SI 19))
     (clobber (match_operand 0 "register_operand" ""))
     (clobber (match_operand 1 "register_operand" ""))
     (clobber (match_operand 2 "register_operand" ""))])
   (set (match_operand:QI 7 "register_operand" "")
	(gtu:QI (reg:CC 17) (const_int 0)))
   (set (match_operand:QI 8 "register_operand" "")
	(ltu:QI (reg:CC 17) (const_int 0)))
   (set (reg 17)
	(compare (match_dup 7) (match_dup 8)))
  ]
  "peep2_reg_dead_p (4, operands[7]) && peep2_reg_dead_p (4, operands[8])"
  [(parallel[
     (set (reg:CC 17)
	  (if_then_else:CC (ne (match_dup 6)
			       (const_int 0))
	    (compare:CC (mem:BLK (match_dup 4))
			(mem:BLK (match_dup 5)))
	    (const_int 0)))
     (use (match_dup 3))
     (use (reg:CC 17))
     (use (reg:SI 19))
     (clobber (match_dup 0))
     (clobber (match_dup 1))
     (clobber (match_dup 2))])]
  "")


taken from : http://www.cs.cmu.edu/cgi-bin/info2www?(gccint.info)define_peephole2

RTL to RTL Peephole Optimizers
------------------------------

   The `define_peephole2' definition tells the compiler how to
substitute one sequence of instructions for another sequence, what
additional scratch registers may be needed and what their lifetimes
must be.

     (define_peephole2
       [INSN-PATTERN-1
        INSN-PATTERN-2
        ...]
       "CONDITION"
       [NEW-INSN-PATTERN-1
        NEW-INSN-PATTERN-2
        ...]
       "PREPARATION-STATEMENTS")

   The definition is almost identical to `define_split' (Note: Insn
Splitting) except that the pattern to match is not a single
instruction, but a sequence of instructions.

   It is possible to request additional scratch registers for use in the
output template.  If appropriate registers are not free, the pattern
will simply not match.

   Scratch registers are requested with a `match_scratch' pattern at
the top level of the input pattern.  The allocated register (initially)
will be dead at the point requested within the original sequence.  If
the scratch is used at more than a single point, a `match_dup' pattern
at the top level of the input pattern marks the last position in the
input sequence at which the register must be available.

   Here is an example from the IA-32 machine description:

     (define_peephole2
       [(match_scratch:SI 2 "r")
        (parallel [(set (match_operand:SI 0 "register_operand" "")
                        (match_operator:SI 3 "arith_or_logical_operator"
                          [(match_dup 0)
                           (match_operand:SI 1 "memory_operand" "")]))
                   (clobber (reg:CC 17))])]
       "! optimize_size && ! TARGET_READ_MODIFY"
       [(set (match_dup 2) (match_dup 1))
        (parallel [(set (match_dup 0)
                        (match_op_dup 3 [(match_dup 0) (match_dup 2)]))
                   (clobber (reg:CC 17))])]
       "")

This pattern tries to split a load from its use in the hopes that we'll
be able to schedule around the memory load latency.  It allocates a
single `SImode' register of class `GENERAL_REGS' (`"r"') that needs to
be live only at the point just before the arithmetic.

   A real example requiring extended scratch lifetimes is harder to
come by, so here's a silly made-up example:

     (define_peephole2
       [(match_scratch:SI 4 "r")
        (set (match_operand:SI 0 "" "") (match_operand:SI 1 "" ""))
        (set (match_operand:SI 2 "" "") (match_dup 1))
        (match_dup 4)
        (set (match_operand:SI 3 "" "") (match_dup 1))]
       "/* determine 1 does not overlap 0 and 2 */"
       [(set (match_dup 4) (match_dup 1))
        (set (match_dup 0) (match_dup 4))
        (set (match_dup 2) (match_dup 4))]
        (set (match_dup 3) (match_dup 4))]
       "")

If we had not added the `(match_dup 4)' in the middle of the input
sequence, it might have been the case that the register we chose at the
beginning of the sequence is killed by the first or second `set'.