Segher Boessenkool <seg...@kernel.crashing.org> writes: > Hi! > > On Wed, Nov 20, 2019 at 09:42:46AM +0000, Richard Sandiford wrote: >> Segher Boessenkool <seg...@kernel.crashing.org> writes: >> >> Before I resubmit, why is the simplify-rtx.c part all wrong? >> > >> > It was nice and simple, and it isn't anymore. 8 4 2 1 for the four of >> > lt gt eq un are hardly worth documenting or making symbolic constants >> > for, because a) they are familiar to all powerpc users anyway (the >> > assembler has those as predefined constants!), admittedly this isn't a >> > strong argument for most people; >> >> Ah, OK. I was totally unaware of the connection. > > Yeah, I should have documented it. Time pressure was high the last N > weeks, with everyone else putting stuff in before end of stage 1 things > broke left and right for me. Normally I would just not update trunk the > last two months or so of stage 1 (for development -- for testing you > always need current trunk of course), but I needed some stuff from it. > Oh well, I finally dug myself out. > >> > but also b) they were only used in two short and obvious routines. >> > After your patch the routines are no longer short or obvious. >> > >> > A comparison result is exactly one of four things: lt, gt, eq, or un. >> > So we can express testing for any subset of those with just an OR of >> > the masks for the individual conditions. Whether a comparison is >> > floating point, floating point no-nans, signed, or unsigned, is just >> > a property of the comparison, not of the result, in this representation. >> >> Yeah, this works for OR because we never lose the unorderdness. > > It works for everything, including things with a NOT. > > If the mode does not allow unordered, you mask that away all the way at > the end, and nothing else needs to be done. This doesn't have to be done > for IOR because you can never end up with unordered in the mask if you > didn't start out with some code that allows unordered. > > You also can encode NE as not allowing unordered, if you have a mode > where that does not exist, but that is purely cosmetic. > > 8421 "full" "no-nan" > 0000 false false > 1000 lt lt > 0100 gt gt > 1100 ltgt ne > 0010 eq eq > 1010 le le > 0110 ge ge > 1110 ordered true > 0001 unordered > 1001 unlt > 0101 ungt > 1101 ne > 0011 uneq > 1011 unle > 0111 unge > 1111 true > > So for !HONOR_NANS modes we need to output LTGT as NE, and ORDERED as > true, and that is all. > >> There were two aspects to my patch. One was adding AND, and had: >> >> /* We only handle AND if we can ignore unordered cases. */ >> bool honor_nans_p = HONOR_NANS (GET_MODE (op0)); >> if (code != IOR && (code != AND || honor_nans_p)) >> return 0; >> >> This is needed because e.g. UNLT & ORDERED -> LT is only conditionally >> valid. It doesn't sound like you're objecting to that bit, is that right? >> Or was this what you had in mind with the reference to no-nans? > > UNLT & ORDERED is always LT. When would it not be true?
LT traps on quiet NaNs for -ftrapping-math, UNLT and ORDERED don't. >> As mentioned in the covering note, I punted for this because handling >> trapping FP comparisons correctly for AND would need its own set of >> testcases. > > This isn't trapping arithmetic. Unordered is a perfectly normal result. > As IEEE 754 says: > Four mutually exclusive relations are possible: less than, equal, > greater than, and unordered. > This same is true when !HONOR_NANS, for signed integer comparisons, and > for unsigned integer comparisons: just UNORDERED never happens. > >> > If you do not mix signed and unsigned comparisons (they make not much >> > sense mixed anyway(*)), you need no changes at all: just translate >> > ltu/gtu/leu/geu to/from lt/gt/le/ge on the way in and out of this >> > function (there already are helper functions for that, signed_condition >> > and unsigned_condition). >> >> So this all seems to come down to whether unsigned comparisons are handled >> as separate mask bits or whether they're dealt with by removing the >> unsignedness and then adding it back. ISTM both are legitimate ways >> of doing it. I don't think one of them is "all wrong". > > It violates the whole design of the thing left and right. I never > documented that well (or at all), of course :-/ > >> I was very belatedly getting around to dealing with Joseph's comment >> when you sent your patch and had it approved. Since that patch seemed >> to be more favourably received in general, I was trying to work within >> the existing style of your version. And without the powerpc background, >> I just assumed that the mask values were "documented" by the first block >> of case statements: >> >> case LT: >> return 8; >> case GT: >> return 4; >> case EQ: >> return 2; >> case UNORDERED: >> return 1; > > Yeah, but it may not be obvious that exactly one of those is true for > any comparison, and you can combine them to a mask and do any logical > operations on it. > >> Adding two more cases here didn't seem to make things any more unclear. >> But maybe it is more jarring if you've memorised the powerpc mapping. > > It's also that 2**4 is small, but 2**6 is not. The 2**4 cases all have > separate RTL codes for it, too. > >> I'd actually considered converting to signed and back instead of adding >> extra cases, but I thought that would be rejected as too inefficient. >> (That was a concern with my patch above.) It seemed like one of the selling >> points of doing it your way was that everything was handled by one switch >> statement "in" and one switch statement "out", and I was trying to >> preserve that. >> >> signed_condition and unsigned_condition assert on unordered comparisons, >> so if we're going to go that route, we either need to filter them out >> first or add maybe_* versions of the routines that return UNKNOWN. > > Yeah. rs6000 has > > (define_predicate "unsigned_comparison_operator" > (match_code "ltu,gtu,leu,geu")) > (define_predicate "signed_comparison_operator" > (match_code "lt,gt,le,ge")) > > Maybe we should have those be for every target? > > bool is_signed = (signed_comparison_operator (code0) > || signed_comparison_operator (code1)); > bool is_unsigned = (unsigned_comparison_operator (code0) > || unsigned_comparison_operator (code1)); > > /* Don't allow mixing signed and unsigned comparisons. */ > if (is_signed && is_unsigned) > return 0; > > (this takes care of your EQ/NE concern automatically, btw) > > if (unsigned_comparison_operator (code0)) > code0 = signed_condition (code0); > if (unsigned_comparison_operator (code1)) > code1 = signed_condition (code1); > > and at the end > > if (is_unsigned && signed_comparison_operator (code)) > code = unsigned_condition (code); OK, thanks, I'll do it this way. Richard