This is the mail archive of the gcc@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]
Other format: [Raw text]

RFC on potential operand/operator processing simplification.


As GCC's does not presently enable the specification of sign-ness constrains
in it's rtl machine descriptions; it seems to force the front-end to promote
asymmetrically sized operands to a common type and size prior to attempting
to match parsed expression trees against target machine rtl definitions.

Therefore, although the target machine may be able to directly utilize
operands in their originally specified non-promoted form, the front-end
effectively masks the opportunity to do so; thereby creating an unnecessary
inefficiency, typically most evident on smaller than int wide machines.

If the semantics of rtl expressions were extended to enable the
specification of an integer's sign-ness as well as size constraint, then the
front-end need only specify the precision of the operation required to
comply with C's the languages semantics, but not need to apriority cast it's
operands, as the target machines rlt specification could then specify their
most efficient treatment.

Which overall seems like a win-win. Simpler front-end processing, and more
efficient and flexible machine rtl code specification.

Does this make sense? What are the downsides I may be missing?

------ Forwarded Earlier Message -------
Was: request for opinion on alternative operand/
     operator classification/promotion approach

Please consider this a request for opinion on the possible benefits of
simplifying GCC's present front-end's operand and operation type/precision
determination logic in favor of leveraging the back-end's present rtl tree
matching/covering ability to more optimally identify and apply operand cast
promotions only if and as required by the target machine's instruction set
definition to enable more efficient target machine instruction specification
and code generation, by adopting a few reasonably simple conventions.

More specifically, as most operations need only be performed at the
precision defined by the lesser of it's target's need or greatest source
operand precision, and does not require the physical promotion of it's
operands if the target's instruction set is capable of performing the
required logical/arithmetic operation utilizing the operand's native
specified form; the front-end need typically only ascertain an operand's
specified type and required operation precision, and pass it to the back-end
after higher level optimizations prior for code generation; then simply
allow the back-end constrained by it's target's machine specification to
sign or zero extend it's operands only as required, rather than attempting
to apriority do so less optimally.

This simplification seems achievable in a backward compatible way by adding
unsigned integer size type specifications QU, HU, SU, etc. to the existing
QI, HI, SI, etc. signed integer operand/operator designators, thereby
enabling rtl machine specifications to identify operand types and define
templates as required to sign or zero extend operands as may be required for
the target machine. Additionally, if the semantics of "set" rtl operation
semantics were extended to allow it's use to specify assignments of a
smaller size than it's source operand, and returned value, more efficient
instruction templates can be more easily and concisely specified, without
having to resort to hard coded move code generation, and/or peep hole
optimization to improve the efficiently of intermediate computation
assignments.

Then, where (min/max x-type y-type) is the lesser/greater ranking type, and
(x-type) is an sub expression's outer rank need.

For assignment expressions:

  (x-type)( (y-type)y = (z-type)z )
=> 
  (set:(max x-type y-type z-type) y:(y-type) z:(z-type))


For typical binary expressions (excluding /):

  (x-type)( (y-type)y op (z-type)y )
=> 
  (op:((min x-type (max y-type z-type)) y:(y-type) z:(z-type))
  
  where for (/):
=> 
  (op:(min x-type (max y-type (+1-signed? z-type))) y:(y-type) z:(z-type))


For typical unary expressions:

  (x-type)( op (y-type)y )
=> 
  (op:(max x-type y-type)) y:(y-type))

Then within the target machine's description, cast templates may then be
defines as required to cast sign or zero extend it's operands as may be
required; where on larger machines, were all operands loaded into the
register file, most cast specifications will be nul/void operations, as
operands will have typically been logically type extended into the machine's
native integer size; i.e., for a hypothetical simplified 8-bit target
division instruction template (where X matches either Integer or Unsigned):

(define-insn "qx_div_hihi"
    (set:HI (match_operand:QX 0)
            (div:HI (match_operand:HI 1) (match_operand:HI 2)))
    ""
    "%0:QX = div %1:HI %2:HI"
    "")

A nul/void cast for a machine in which all register operands are HI wide:

(define-insn "hi_cast_qi"
    (set:HI (match_operand:HI 0) (match_operand:QI 1))
    ""
    ""
    "")

A cast for a machine in which some register operands may be QI wide:

(define-insn "hi_cast_qi"
    (set:HI (match_operand:HI 0) (match_operand:QI 1))
    ""
    "%0:HI = sex %1:QI"
    "")

So overall, does this make any sense to consider to both potentially
simplify the present front-end type operand/operation classification &
promotion logic, and improve the compilers ability to simply specify
efficient small machine instruction set definitions; or viewed as likely not
worth the effort?

Thanks, -paul-


------ End of Forwarded Message



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