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]

possible problem with C implied intermediate variable sizerequirements -> rtl mapping ?


(Summary: GCC's C's front-end doesn't seem to be placing requirements
 on it's back-end to generate intermediate temporaries which may be
 required to be wider than it's operands, to comply with C's semantics;
 which is particularly a problem on smaller than int sized machines.)

Based on the machine description documentation, it appears that the
semantics of rtl instruction template mode size designators specify
the size of operation's result, where for example:

(OPERATION :MODE ....)

Defines that OPERATION produces a MODE size result, which is then
correspondingly used by the back-end in conjunction with other
rtl instruction definitions to synthesize a matching pattern to
that which the front-end specified as being required to satisfy
the code it parsed in compliance with language's evaluation rules.

However it appears that GCC's C isn't complying with C's semantics
for operations who's operands are smaller than int, when its result
is used as an intermediate operand in subsequent operations prior to
final assignment to a logical variable?

It appears that the GCC C front-end may be assuming operation modes
specify the size of it's operands, not the size mode of the result of
an operation on it's operands, thereby loosing the ability to specify
to the code generator the requirements for an intermediate operation
result which may be larger than it's operands, as typically the case
in C when intermediate operations are assumed to preserve at least
a logical int size of precision, although typically not practically
required to be greater than the size of the target assignment?

For example, if a hypothetical target machine were defined as having
the following operand mode size mappings:

QI :: signed char
HI :: signed int

With the following partial rtl description fragment describing
three different instructions a hypothetical machine is capable of:

; QI size sum of two QI size operands.
(define_insn "qi_plus_qiqi"
  [(set (match_operand:QI 0 "register_operand" "")
        (plus:QI (match_operand:QI 1 "register_operand" "")
                 (match_operand:QI 2 "register_operand" "")))
  ""
  %0:qi = plus %1:qi %2:qi"
  "")

; HI size sum of two QI size operands.
(define_insn "hi_plus_qiqi"
  [(set (match_operand:HI 0 "register_operand" "")
        (plus:HI (match_operand:QI 1 "register_operand" "")
                 (match_operand:QI 2 "register_operand" "")))]
  ""
  "%0:hi = %1:qi %2:qi"
  "")

; QI size sum of one QI size and one HI size operand.
(define_insn "qi_plus_qihi"
  [(set (match_operand:QI 0 "register_operand" "")
        (plus:QI (match_operand:QI 1 "register_operand" "")
                 (match_operand:HI 2 "register_operand" "")))]
  ""
  "%0:qi = plus %1:hi %2:qi"
  "")

Given the C code fragment (assuming it's not optimized away):

    volatile signed char x, y ;

    x = y + y ;
    x = y + y + y ;
    
Assuming x == r0:qi, y == r1:qi, and if a temporary allocation is
hypothetically required then temp == r2:MODE, then expecting the
following to be logically generated satisfying C's semantics:

x = y + y generating an rtl equivalent expression like:

 (set (reg:QI 0)
      (plus:QI (reg:QI 1)
               (reg:QI 1)))

Which satisfies C as it's target only requires QI precision, yielding:

 r0:qi = plus r1:qi r1:qi ; which is fine, and then


x = y + y + y generating an rtl equivalent with an widened intermediate:

 (set (reg:QI 0)
      (plus:QI (reg:QI 1)
                 (plus:HI (reg:QI 1)
                        (reg:QI 1))))

Ideally yielding, and satisfying C's semantics for intermediate operations:

 r2:hi = plus r1:qi r1:qi ; where r2:hi is an widened intermediate temporary
 r0:qi = plus r1:qi r2:hi ; as required to guarantee intermediate precision.

Which it doesn't seem to do as required to satisfy C's semantics that
operations are performed to maintain at least the logical precision of the
greater of an int or it's largest ranking operand, it appears to generate:

 (set (reg:QI 0)
      (plus:QI (reg:QI 1)
                 (plus:QI (reg:QI 1)
                        (reg:QI 1))))

Incorrectly yielding:

 r2:qi = plus r1:qi r1:qi ; where r2:qi = char loosing the required
 r0:qi = plus r2:qi r1:qi ; intermediate precision specified by C ?
 
????

Thanks, if I'm misinterpreting things, any insight would be appreciated,

-paul- 



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