subreg rtl documentation

Ulrich Weigand uweigand@de.ibm.com
Fri Apr 11 20:18:00 GMT 2008


Kenneth Zadeck wrote:

> ulrich,
> 
> I was wondering if you had been following this discussion on subregs of 
> mem and could at least answer the question with respect to the s390?

sorry, I've been out of office for a couple of days ...


The use of explicit SUBREG in s390.md insn pattern generally falls
into the following two categories:
- match patterns generated by combine
- handle register pair architecture requirements

1.) Match patterns generated by combine

In several cases, combine generates RTX containing paradoxical
subregs as "canonical" to represent "extend-with-don't-care-bits"
operations.  For example, we have an instruction to zero-extend a
31-bit value in memory to 64 bits in register.  This should be
employed e.g. to implement the following:

long test (int *x)
{
  return (long)*x & 0x7fffffffL;
}

as:

test:
       llgt    %r2,0(%r2)  # 26    *llgt_sidi   [length = 6]
       br      %r14        # 29    *return      [length = 2]


Before combine, we see

(insn 7 4 8 2 (set (reg:DI 46)
        (sign_extend:DI (mem:SI (reg/v/f:DI 44 [ x ]) [2 S4 A32]))) 123 {*extendsidi2} (insn_list:REG_DEP_TRUE 3 (
nil))
    (expr_list:REG_DEAD (reg/v/f:DI 44 [ x ])
        (nil)))

(insn 8 7 14 2 (parallel [
            (set (reg:DI 45)
                (and:DI (reg:DI 46)
                    (const_int 2147483647 [0x7fffffff])))
            (clobber (reg:CC 33 %cc))
        ]) 297 {*anddi3} (insn_list:REG_DEP_TRUE 7 (nil))
    (expr_list:REG_DEAD (reg:DI 46)
        (expr_list:REG_UNUSED (reg:CC 33 %cc)
            (nil))))


Now, when combine inserts the definition of reg 46 into its use
in insn 12, the resulting expression is canonicalized to use a
paradoxical subreg instead of the sign_extend (this happens 
initially in expand_compound_operation, and remains present
throughout further simplification).  In order to match the
combined expression, the s390.md backend provides a pattern
using an explicit subreg:

(define_insn "*llgt_sidi"
  [(set (match_operand:DI 0 "register_operand" "=d")
        (and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "m") 0)
                (const_int 2147483647)))]
  "TARGET_64BIT"
  "llgt\t%0,%1"
  [(set_attr "op_type"  "RXE")])


If combine were to canonicalize this to a ZERO_EXTEND
(or SIGN_EXTEND) instead, we could certainly change the
s390 backend accordingly.

This type of explicit subreg occurs in the following patterns; note
that those are all paradoxical subregs:

(define_insn "*llgt_sidi"
  [(set (match_operand:DI 0 "register_operand" "=d")
        (and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "m") 0)
                (const_int 2147483647)))]

(define_insn_and_split "*llgt_sidi_split"
  [(set (match_operand:DI 0 "register_operand" "=d")
        (and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "m") 0)
                (const_int 2147483647)))
   (clobber (reg:CC CC_REGNUM))]

(define_insn "*tstdi_sign"
  [(set (reg CC_REGNUM)
        (compare (ashiftrt:DI (ashift:DI (subreg:DI (match_operand:SI 0 "register_operand" "d") 0)
                                         (const_int 32)) (const_int 32))
                 (match_operand:DI 1 "const0_operand" "")))
   (set (match_operand:DI 2 "register_operand" "=d")
        (sign_extend:DI (match_dup 0)))]

(define_insn_and_split "*cmpint_sign_cc"
  [(set (reg CC_REGNUM)
        (compare (ashiftrt:DI (ashift:DI (subreg:DI
                   (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
                              UNSPEC_CCU_TO_INT) 0)
                   (const_int 32)) (const_int 32))
                 (const_int 0)))
   (set (match_operand:DI 0 "register_operand" "=d")
        (sign_extend:DI (unspec:SI [(match_dup 1)] UNSPEC_CCU_TO_INT)))]

(define_insn "*negdi2_sign_cc"
  [(set (reg CC_REGNUM)
        (compare (neg:DI (ashiftrt:DI (ashift:DI (subreg:DI
                           (match_operand:SI 1 "register_operand" "d") 0)
                           (const_int 32)) (const_int 32)))
                 (const_int 0)))
   (set (match_operand:DI 0 "register_operand" "=d")
        (neg:DI (sign_extend:DI (match_dup 1))))]

(define_insn "*absdi2_sign_cc"
  [(set (reg CC_REGNUM)
        (compare (abs:DI (ashiftrt:DI (ashift:DI (subreg:DI
                           (match_operand:SI 1 "register_operand" "d") 0)
                           (const_int 32)) (const_int 32)))
                 (const_int 0)))
   (set (match_operand:DI 0 "register_operand" "=d")
        (abs:DI (sign_extend:DI (match_dup 1))))]

(define_insn "*negabsdi2_sign_cc"
  [(set (reg CC_REGNUM)
        (compare (neg:DI (abs:DI (ashiftrt:DI (ashift:DI (subreg:DI
                           (match_operand:SI 1 "register_operand" "d") 0)
                           (const_int 32)) (const_int 32))))
                 (const_int 0)))
   (set (match_operand:DI 0 "register_operand" "=d")
        (neg:DI (abs:DI (sign_extend:DI (match_dup 1)))))]


2.) Register pair architecture requirements

Some instructions in the S/390 instruction set have two logically
separate inputs that need to be provided in a pair of registers
(with even / odd numbers).

To implement this, those patterns would typically require an operand
of double-wordsize mode, and use subregs of that operand to describe
the two inputs.  As double-wordsize modes are only allowed into hard
registers with even register number, this provides an even/odd pair.

For example, the "mvcle" instruction implements a memory-to-memory
copy, and requires the address and length of the source in one such
register pair, and the address and length of the destination in a
second register pair.  (If the destination is longer than the source,
the remainder will be padded with a value provided in another register.)

We use this to implement the "movmem" pattern; the expander will
allocate double-word wide registers, and generate RTX to be matched
by the following pattern:

(define_insn "*movmem_long"
  [(clobber (match_operand:<DBL> 0 "register_operand" "=d"))
   (clobber (match_operand:<DBL> 1 "register_operand" "=d"))
   (set (mem:BLK (subreg:P (match_operand:<DBL> 2 "register_operand" "0") 0))
        (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "1") 0)))
   (use (match_dup 2))
   (use (match_dup 3))
   (clobber (reg:CC CC_REGNUM))]
  ""
  "mvcle\t%0,%1,0\;jo\t.-4"
  [(set_attr "length" "8")
   (set_attr "type" "vs")])

(Note that the "length" components do not actually show up in the RTX,
they are implicit in the movmem pattern.  That is the reason for the
extra USE statements to avoid dataflow from considering the insns to
set of the length as dead.)

This type of subreg is used in the following register patterns; note
that those are all non-paradoxical subregs of registers:

(define_insn "*movmem_long"
  [(clobber (match_operand:<DBL> 0 "register_operand" "=d"))
   (clobber (match_operand:<DBL> 1 "register_operand" "=d"))
   (set (mem:BLK (subreg:P (match_operand:<DBL> 2 "register_operand" "0") 0))
        (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "1") 0)))
   (use (match_dup 2))
   (use (match_dup 3))
   (clobber (reg:CC CC_REGNUM))]

(define_insn "*setmem_long"
  [(clobber (match_operand:<DBL> 0 "register_operand" "=d"))
   (set (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "0") 0))
        (match_operand 2 "shift_count_or_setmem_operand" "Y"))
   (use (match_dup 3))
   (use (match_operand:<DBL> 1 "register_operand" "d"))
   (clobber (reg:CC CC_REGNUM))]

(define_insn "*setmem_long_and"
  [(clobber (match_operand:<DBL> 0 "register_operand" "=d"))
   (set (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "0") 0))
        (and (match_operand 2 "shift_count_or_setmem_operand" "Y")
             (match_operand 4 "const_int_operand"             "n")))
   (use (match_dup 3))
   (use (match_operand:<DBL> 1 "register_operand" "d"))
   (clobber (reg:CC CC_REGNUM))]

(define_insn "*cmpmem_long"
  [(clobber (match_operand:<DBL> 0 "register_operand" "=d"))
   (clobber (match_operand:<DBL> 1 "register_operand" "=d"))
   (set (reg:CCU CC_REGNUM)
        (compare:CCU (mem:BLK (subreg:P (match_operand:<DBL> 2 "register_operand" "0") 0))
                     (mem:BLK (subreg:P (match_operand:<DBL> 3 "register_operand" "1") 0))))
   (use (match_dup 2))
   (use (match_dup 3))]


3.) Bogus uses

There is one additional use of an explicit subreg, which looks bogus
to me and could simply be eliminated by back-end changes alone:

(define_insn "clztidi2"
  [(set (match_operand:TI 0 "register_operand" "=d")
        (ior:TI
          (ashift:TI
            (zero_extend:TI
              (xor:DI (match_operand:DI 1 "register_operand" "d")
                      (lshiftrt (match_operand:DI 2 "const_int_operand" "")
                                (subreg:SI (clz:DI (match_dup 1)) 4))))

            (const_int 64))
          (zero_extend:TI (clz:DI (match_dup 1)))))
   (clobber (reg:CC CC_REGNUM))]


Bye,
Ulrich


-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com



More information about the Gcc-patches mailing list