This patch is a major revision of the patch I originally proposed here: https://gcc.gnu.org/pipermail/gcc-patches/2022-July/598040.html The primary motivation of this patch is to avoid incorrect optimization of MODE_CC comparisons in simplify_const_relational_operation when/if a backend represents the (known) contents of a MODE_CC register using a CONST_INT. In such cases, the RTL optimizers don't know the semantics of this integer value, so shouldn't change anything (i.e. should return NULL_RTX from simplify_const_relational_operation). The secondary motivation is that by introducing a new target hook, called simplify_modecc_const, the backend can (optionally) encode and interpret a target dependent encoding of MODE_CC registers. The worked example provided with this patch is to allow the i386 backend to explicitly model the carry flag (MODE_CCC) using 1 to indicate that the carry flag is set, and 0 to indicate the carry flag is clear. This allows the instructions stc (set carry flag), clc (clear carry flag) and cmc (complement carry flag) to be represented in RTL. However an even better example would be the rs6000 backend, where this patch/target hook would allow improved modelling of the condition register CR. The powerpc's comparison instructions set fields/bits in the CR register [where bit 0 indicates less than, bit 1 greater than, bit 2 equal to and bit3 overflow] analogous to x86's flags register [containing bits for carry, zero, overflow, parity etc.]. These fields can be manipulated directly using crset (aka creqv) and crclr (aka crxor) instructions and even transferred from general purpose registers using mtcr. However, without a patch like this, it's impossible to safely model/represent these instructions in rs6000.md. This patch has been tested on x86_64-pc-linux-gnu with make bootstrap and make -k check, both with and without --target_board=unix{-m32}, and both with and without a patch to add stc, clc and cmc support to the x86 backend. I'll resubmit the x86 target pieces again with that follow-up backend patch, so for now I'm only looking for approval of the middle-end infrastructure pieces. The x86 hunks below are provided as context/documentation for how this hook could/should be used (but I wouldn't object to pre-approval of those bits by Uros). Ok for mainline? 2022-07-26 Roger Sayle gcc/ChangeLog * target.def (simplify_modecc_const): New target hook. * doc/tm.texi (TARGET_SIMPLIFY_MODECC_CONST): Document here. * doc/tm.texi.in (TARGET_SIMPLIFY_MODECC_CONST): Locate @hook here. * hooks.cc (hook_rtx_mode_int_rtx_null): Define default hook here. * hooks.h (hook_rtx_mode_int_rtx_null): Prototype here. * simplify-rtx.c (simplify_const_relational_operation): Avoid mis-optimizing MODE_CC comparisons by calling new target hook. * config/i386.cc (ix86_simplify_modecc_const): Implement new target hook, supporting interpreting MODE_CCC values as the x86 carry flag. (TARGET_SIMPLIFY_MODECC_CONST): Define as ix86_simplify_modecc_const. Thanks in advance, Roger -- > -----Original Message----- > From: Segher Boessenkool > Sent: 07 July 2022 23:39 > To: Roger Sayle > Cc: gcc-patches@gcc.gnu.org > Subject: Re: [PATCH] Be careful with MODE_CC in > simplify_const_relational_operation. > > Hi! > > On Thu, Jul 07, 2022 at 10:08:04PM +0100, Roger Sayle wrote: > > I think it's fair to describe RTL's representation of condition flags > > using MODE_CC as a little counter-intuitive. > > "A little challenging", and you should see that as a good thing, as a puzzle to > crack :-) > > > For example, the i386 > > backend represents the carry flag (in adc instructions) using RTL of > > the form "(ltu:SI (reg:CCC) (const_int 0))", where great care needs to > > be taken not to treat this like a normal RTX expression, after all LTU > > (less-than-unsigned) against const0_rtx would normally always be > > false. > > A comparison of a MODE_CC thing against 0 means the result of a > *previous* comparison (or other cc setter) is looked at. Usually it simply looks > at some condition bits in a flags register. It does not do any actual comparison: > that has been done before (if at all even). > > > Hence, MODE_CC comparisons need to be treated with caution, and > > simplify_const_relational_operation returns early (to avoid > > problems) when GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC. > > Not just to avoid problems: there simply isn't enough information to do a > correct job. > > > However, consider the (currently) hypothetical situation, where the > > RTL optimizers determine that a previous instruction unconditionally > > sets or clears the carry flag, and this gets propagated by combine > > into the above expression, we'd end up with something that looks like > > (ltu:SI (const_int 1) (const_int 0)), which doesn't mean what it says. > > Fortunately, simplify_const_relational_operation is passed the > > original mode of the comparison (cmp_mode, the original mode of op0) > > which can be checked for MODE_CC, even when op0 is now VOIDmode > > (const_int) after the substitution. Defending against this is clearly > > the right thing to do. > > > > More controversially, rather than just abort > > simplification/optimization in this case, we can use the comparison > > operator to infer/select the semantics of the CC_MODE flag. > > Hopefully, whenever a backend uses LTU, it represents the (set) carry > > flag (and behaves like i386.md), in which case the result of the simplified > expression is the first operand. > > [If there's no standardization of semantics across backends, then we > > should always just return 0; but then miss potential optimizations]. > > On PowerPC, ltu means the result of an unsigned comparison (we have > instructions for that, cmpl[wd][i] mainly) was "smaller than". It does not mean > anything is unsigned smaller than zero. It also has nothing to do with carries, > which are done via a different register (the XER). > > > + /* Handle MODE_CC comparisons that have been simplified to > > + constants. */ > > + if (GET_MODE_CLASS (mode) == MODE_CC > > + && op1 == const0_rtx > > + && CONST_INT_P (op0)) > > + { > > + /* LTU represents the carry flag. */ > > + if (code == LTU) > > + return op0 == const0_rtx ? const0_rtx : const_true_rtx; > > + return 0; > > + } > > + > > /* We can't simplify MODE_CC values since we don't know what the > > actual comparison is. */ > > ^^^ > This comment is 100% true. We cannot simplify any MODE_CC comparison > without having more context. The combiner does have that context when it > tries to combine the CC setter with the CC consumer, for example. > > Do you have some piece of motivating example code? > > > Segher