RFC: REG_LABEL not sufficient, cbranchM4 causes ambiguity

Hans-Peter Nilsson hans-peter.nilsson@axis.com
Mon Dec 12 08:50:00 GMT 2005


For once, the documentation seems to be most accurate; more
accurate than random comments in the code, of which some
contradicts other code:

@item REG_LABEL
This insn uses @var{op}, a @code{code_label} or a @code{note} of type
@code{NOTE_INSN_DELETED_LABEL}, but is not a
@code{jump_insn}, or it is a @code{jump_insn} that required the label to
be held in a register.  The presence of this note allows jump
optimization to be aware that @var{op} is, in fact, being used, and flow
optimization to build an accurate flow graph.

However, for a cbranchsi4, the pattern can look like this:

(define_insn_and_split "cbranch<mode>4"
  [(set (pc)
        (if_then_else
         (match_operator
          0 "comparison_operator"
          [(match_operand:BWDQ 1 "nonimmediate_operand" "<cmpop0constraints>")
           (match_operand:BWDQ 2 "general_operand" "<cmpop1constraints>")])
         (label_ref (match_operand 3 "" ""))
         (pc)))]
  ...)

Causing for example in (from gfortran.dg/g77/pr9258.f and with
local CRIS-cc0-removal-changes):

(jump_insn 54 53 56 6 (set (pc)
        (if_then_else (eq (reg/v/f:SI 25 [ m.1 ])
                (label_ref:SI 0))
            (label_ref 33)
            (pc))) 1 {cbranchsi4} (nil)
    (expr_list:REG_BR_PROB (const_int 1900 [0x76c])
        (nil)))

Note *two* labels.  One is a jump target, the other is an
operand.  So, a JUMP_P can have multiple label references *some
of which are not jump targets*.  This causes ambiguity with the
documented (and mostly real) use of REG_LABEL, and of course the
code assumes there are no non-jump-target REG_LABELs in JUMP_P:s.

I could of course "fix" this by disallowing REG_LABELs in
operand 2 in the pattern above, but that'd be like cheating,
giving in to a lame restriction in GCC and proving a
cbranchM4-representation to be lacking by definition with better
expressibility with cc0.  Can't do that.

I propose (and will try to) solve this by splitting REG_LABELs
into two types, REG_LABEL_TARGET and REG_LABEL_OPERAND:

Only JUMP_P:s will have REG_LABEL_TARGET notes; those notes
marks its jump targets (perhaps can be only one).  As a special
case, the JUMP_LABEL field in a JUMP_P is a short-cut and will
be handled as a first REG_LABEL_TARGET note.  It is invalid to
have both JUMP_TARGET being NULL and REG_LABEL_TARGET notes in a
(JUMP_P) insn.  A tablejump/casesi will have its JUMP_LABEL set
to the corresponding ADDR_VEC (there can be another
label-ref-target there, in case you think there'll only ever be
the JUMP_TARGET field and no REG_LABEL_TARGET notes).

A JUMP_P using a register for ordinary branches (like on sh64)
will have its JUMP_LABEL pointing to the label loaded in that
register (if it can be identified; it seems it usually can).  To
make this work, REG_LABEL_TARGET notes (and the JUMP_LABEL) are
sticky; not removed before each jump pass if the JUMP_P no
longer refer to the label in its body.

Any insn can have REG_LABEL_OPERAND, which marks non-target use,
e.g. &&label operands and branch-target register loads in
non-jumps and the non-jump cbranchM4 (label-ref:SI 0) operand
above.  (IIRC the 0 is actually due to the failure I saw.)
REG_LABEL_OPERANDs are regenerated for each jump pass.

A JUMP_P can have REG_LABEL_OPERANDs only for stuff in a
if_then_else condition; everything else is considered a
jump-target.

Or at least that's the definition I currently think (and hope)
will work.

Thoughts?

brgds, H-P



More information about the Gcc mailing list