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