Re: [000/nnn] poly_int: representation of runtime offsets and sizes
On Wed, Nov 8, 2017 at 10:39 AM, Richard Sandifordwrote: > Richard Biener writes: >> On Wed, Oct 25, 2017 at 1:26 PM, Richard Sandiford >> wrote: >>> Richard Biener writes: On Tue, Oct 24, 2017 at 3:24 PM, Richard Sandiford wrote: > Richard Biener writes: >> On Tue, Oct 24, 2017 at 2:48 PM, Richard Sandiford >> wrote: >>> Richard Biener writes: On Tue, Oct 24, 2017 at 1:23 PM, Richard Sandiford wrote: > Eric Botcazou writes: >>> Yeah. E.g. for ==, the two options would be: >>> >>> a) must_eq (a, b) -> a == b >>>must_ne (a, b) -> a != b >>> >>>which has the weird property that (a == b) != (!(a != b)) >>> >>> b) must_eq (a, b) -> a == b >>>may_ne (a, b)-> a != b >>> >>>which has the weird property that a can be equal to b when a != b >> >> Yes, a) was the one I had in mind, i.e. the traditional operators are >> the must >> variants and you use an outer ! in order to express the may. Of >> course this >> would require a bit of discipline but, on the other hand, if most of >> the cases >> fall in the must category, that could be less ugly. > > I just think that discipline is going to be hard to maintain in > practice, > since it's so natural to assume (a == b || a != b) == true. With the > may/must approach, static type checking forces the issue. > >>> Sorry about that. It's the best I could come up with without losing >>> the may/must distinction. >> >> Which variant is known_zero though? Must or may? > > must. maybe_nonzero is the may version. Can you rename known_zero to must_be_zero then? >>> >>> That'd be OK with me. >>> >>> Another alternative I wondered about was must_eq_0 / may_ne_0. >>> What's wrong with must_eq (X, 0) / may_eq (X, 0) btw? >>> >>> must_eq (X, 0) generated a warning if X is unsigned, so sometimes you'd >>> need must_eq (X, 0) and sometimes must_eq (X, 0U). >> >> Is that because they are templates? Maybe providing a partial >> specialization >> would help? > > I don't think it's templates specifically. We end up with something like: > > int f (unsigned int x, const int y) > { > return x != y; > } > > int g (unsigned int x) { return f (x, 0); } > > which generates a warning too. > >> I'd be fine with must_eq_p and may_eq_0. > > OK, I'll switch to that if there are no objections. Hum. But then we still warn for must_eq_p (x, 1), no? >>> >>> Yeah. The patch also had a known_one and known_all_ones for >>> those two (fairly) common cases. For other values the patches >>> just add "U" where necessary. >>> >>> If you think it would be better to use U consistently and not >>> have the helpers, then I'm happy to do that instead. >>> So why does int f (unsigned int x) { return x != 0; } not warn? Probably because of promotion of the arg. >>> >>> [Jakub's already answered this part.] >>> Shouldn't we then simply never have a may/must_*_p (T1, T2) with T1 and T2 being not compatible? That is, force promotion rules on them with template magic? >>> >>> This was what I meant by: >>> >>> Or we could suppress warnings by forcibly converting the input. >>> Sometimes the warnings are useful though. >>> >>> We already do this kind of conversion for arithmetic, to ensure >>> that poly_uint16 + poly_uint16 -> poly_int64 promotes before the >>> addition rather than after it. But it defeats the point of the >>> comparison warning, which is that you're potentially redefining >>> the sign bit. >>> >>> I think the warning's just as valuable for may/must comparison of >>> non-literals as it is for normal comparison operators. It's just >>> unfortunate that we no longer get the special handling of literals. >> >> Ok, I see. >> >> I think I have a slight preference for using 0U consistently but I haven't >> looked at too many patches yet to see how common/ugly that would be. > > OK. FWIW, that's also how we had it until very recently. I added the > known/maybe stuff in a late and probably misguided attempt to make > things prettier. > > I've pulled that part out and switched back to using U. I'll post the > new 001 patch in a sec. Should I repost all the other patches that > changed as well, or isn't it worth it for a change like that? Not worth re-posting IMHO.
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
Richard Bienerwrites: > On Wed, Oct 25, 2017 at 1:26 PM, Richard Sandiford > wrote: >> Richard Biener writes: >>> On Tue, Oct 24, 2017 at 3:24 PM, Richard Sandiford >>> wrote: Richard Biener writes: > On Tue, Oct 24, 2017 at 2:48 PM, Richard Sandiford > wrote: >> Richard Biener writes: >>> On Tue, Oct 24, 2017 at 1:23 PM, Richard Sandiford >>> wrote: Eric Botcazou writes: >> Yeah. E.g. for ==, the two options would be: >> >> a) must_eq (a, b) -> a == b >>must_ne (a, b) -> a != b >> >>which has the weird property that (a == b) != (!(a != b)) >> >> b) must_eq (a, b) -> a == b >>may_ne (a, b)-> a != b >> >>which has the weird property that a can be equal to b when a != b > > Yes, a) was the one I had in mind, i.e. the traditional operators are > the must > variants and you use an outer ! in order to express the may. Of > course this > would require a bit of discipline but, on the other hand, if most of > the cases > fall in the must category, that could be less ugly. I just think that discipline is going to be hard to maintain in practice, since it's so natural to assume (a == b || a != b) == true. With the may/must approach, static type checking forces the issue. >> Sorry about that. It's the best I could come up with without losing >> the may/must distinction. > > Which variant is known_zero though? Must or may? must. maybe_nonzero is the may version. >>> >>> Can you rename known_zero to must_be_zero then? >> >> That'd be OK with me. >> >> Another alternative I wondered about was must_eq_0 / may_ne_0. >> >>> What's wrong with must_eq (X, 0) / may_eq (X, 0) btw? >> >> must_eq (X, 0) generated a warning if X is unsigned, so sometimes you'd >> need must_eq (X, 0) and sometimes must_eq (X, 0U). > > Is that because they are templates? Maybe providing a partial > specialization > would help? I don't think it's templates specifically. We end up with something like: int f (unsigned int x, const int y) { return x != y; } int g (unsigned int x) { return f (x, 0); } which generates a warning too. > I'd be fine with must_eq_p and may_eq_0. OK, I'll switch to that if there are no objections. >>> >>> Hum. But then we still warn for must_eq_p (x, 1), no? >> >> Yeah. The patch also had a known_one and known_all_ones for >> those two (fairly) common cases. For other values the patches >> just add "U" where necessary. >> >> If you think it would be better to use U consistently and not >> have the helpers, then I'm happy to do that instead. >> >>> So why does >>> >>> int f (unsigned int x) >>> { >>> return x != 0; >>> } >>> >>> not warn? Probably because of promotion of the arg. >> >> [Jakub's already answered this part.] >> >>> Shouldn't we then simply never have a may/must_*_p (T1, T2) >>> with T1 and T2 being not compatible? That is, force promotion >>> rules on them with template magic? >> >> This was what I meant by: >> >> Or we could suppress warnings by forcibly converting the input. >> Sometimes the warnings are useful though. >> >> We already do this kind of conversion for arithmetic, to ensure >> that poly_uint16 + poly_uint16 -> poly_int64 promotes before the >> addition rather than after it. But it defeats the point of the >> comparison warning, which is that you're potentially redefining >> the sign bit. >> >> I think the warning's just as valuable for may/must comparison of >> non-literals as it is for normal comparison operators. It's just >> unfortunate that we no longer get the special handling of literals. > > Ok, I see. > > I think I have a slight preference for using 0U consistently but I haven't > looked at too many patches yet to see how common/ugly that would be. OK. FWIW, that's also how we had it until very recently. I added the known/maybe stuff in a late and probably misguided attempt to make things prettier. I've pulled that part out and switched back to using U. I'll post the new 001 patch in a sec. Should I repost all the other patches that changed as well, or isn't it worth it for a change like that? Thanks, Richard
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
On Wed, Oct 25, 2017 at 1:26 PM, Richard Sandifordwrote: > Richard Biener writes: >> On Tue, Oct 24, 2017 at 3:24 PM, Richard Sandiford >> wrote: >>> Richard Biener writes: On Tue, Oct 24, 2017 at 2:48 PM, Richard Sandiford wrote: > Richard Biener writes: >> On Tue, Oct 24, 2017 at 1:23 PM, Richard Sandiford >> wrote: >>> Eric Botcazou writes: > Yeah. E.g. for ==, the two options would be: > > a) must_eq (a, b) -> a == b >must_ne (a, b) -> a != b > >which has the weird property that (a == b) != (!(a != b)) > > b) must_eq (a, b) -> a == b >may_ne (a, b)-> a != b > >which has the weird property that a can be equal to b when a != b Yes, a) was the one I had in mind, i.e. the traditional operators are the must variants and you use an outer ! in order to express the may. Of course this would require a bit of discipline but, on the other hand, if most of the cases fall in the must category, that could be less ugly. >>> >>> I just think that discipline is going to be hard to maintain in >>> practice, >>> since it's so natural to assume (a == b || a != b) == true. With the >>> may/must approach, static type checking forces the issue. >>> > Sorry about that. It's the best I could come up with without losing > the may/must distinction. Which variant is known_zero though? Must or may? >>> >>> must. maybe_nonzero is the may version. >> >> Can you rename known_zero to must_be_zero then? > > That'd be OK with me. > > Another alternative I wondered about was must_eq_0 / may_ne_0. > >> What's wrong with must_eq (X, 0) / may_eq (X, 0) btw? > > must_eq (X, 0) generated a warning if X is unsigned, so sometimes you'd > need must_eq (X, 0) and sometimes must_eq (X, 0U). Is that because they are templates? Maybe providing a partial specialization would help? >>> >>> I don't think it's templates specifically. We end up with something like: >>> >>> int f (unsigned int x, const int y) >>> { >>> return x != y; >>> } >>> >>> int g (unsigned int x) { return f (x, 0); } >>> >>> which generates a warning too. >>> I'd be fine with must_eq_p and may_eq_0. >>> >>> OK, I'll switch to that if there are no objections. >> >> Hum. But then we still warn for must_eq_p (x, 1), no? > > Yeah. The patch also had a known_one and known_all_ones for > those two (fairly) common cases. For other values the patches > just add "U" where necessary. > > If you think it would be better to use U consistently and not > have the helpers, then I'm happy to do that instead. > >> So why does >> >> int f (unsigned int x) >> { >> return x != 0; >> } >> >> not warn? Probably because of promotion of the arg. > > [Jakub's already answered this part.] > >> Shouldn't we then simply never have a may/must_*_p (T1, T2) >> with T1 and T2 being not compatible? That is, force promotion >> rules on them with template magic? > > This was what I meant by: > > Or we could suppress warnings by forcibly converting the input. > Sometimes the warnings are useful though. > > We already do this kind of conversion for arithmetic, to ensure > that poly_uint16 + poly_uint16 -> poly_int64 promotes before the > addition rather than after it. But it defeats the point of the > comparison warning, which is that you're potentially redefining > the sign bit. > > I think the warning's just as valuable for may/must comparison of > non-literals as it is for normal comparison operators. It's just > unfortunate that we no longer get the special handling of literals. Ok, I see. I think I have a slight preference for using 0U consistently but I haven't looked at too many patches yet to see how common/ugly that would be. Richard. > Thanks, > Richard
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
Richard Bienerwrites: > On Tue, Oct 24, 2017 at 3:24 PM, Richard Sandiford > wrote: >> Richard Biener writes: >>> On Tue, Oct 24, 2017 at 2:48 PM, Richard Sandiford >>> wrote: Richard Biener writes: > On Tue, Oct 24, 2017 at 1:23 PM, Richard Sandiford > wrote: >> Eric Botcazou writes: Yeah. E.g. for ==, the two options would be: a) must_eq (a, b) -> a == b must_ne (a, b) -> a != b which has the weird property that (a == b) != (!(a != b)) b) must_eq (a, b) -> a == b may_ne (a, b)-> a != b which has the weird property that a can be equal to b when a != b >>> >>> Yes, a) was the one I had in mind, i.e. the traditional operators are >>> the must >>> variants and you use an outer ! in order to express the may. Of >>> course this >>> would require a bit of discipline but, on the other hand, if most of >>> the cases >>> fall in the must category, that could be less ugly. >> >> I just think that discipline is going to be hard to maintain in practice, >> since it's so natural to assume (a == b || a != b) == true. With the >> may/must approach, static type checking forces the issue. >> Sorry about that. It's the best I could come up with without losing the may/must distinction. >>> >>> Which variant is known_zero though? Must or may? >> >> must. maybe_nonzero is the may version. > > Can you rename known_zero to must_be_zero then? That'd be OK with me. Another alternative I wondered about was must_eq_0 / may_ne_0. > What's wrong with must_eq (X, 0) / may_eq (X, 0) btw? must_eq (X, 0) generated a warning if X is unsigned, so sometimes you'd need must_eq (X, 0) and sometimes must_eq (X, 0U). >>> >>> Is that because they are templates? Maybe providing a partial >>> specialization >>> would help? >> >> I don't think it's templates specifically. We end up with something like: >> >> int f (unsigned int x, const int y) >> { >> return x != y; >> } >> >> int g (unsigned int x) { return f (x, 0); } >> >> which generates a warning too. >> >>> I'd be fine with must_eq_p and may_eq_0. >> >> OK, I'll switch to that if there are no objections. > > Hum. But then we still warn for must_eq_p (x, 1), no? Yeah. The patch also had a known_one and known_all_ones for those two (fairly) common cases. For other values the patches just add "U" where necessary. If you think it would be better to use U consistently and not have the helpers, then I'm happy to do that instead. > So why does > > int f (unsigned int x) > { > return x != 0; > } > > not warn? Probably because of promotion of the arg. [Jakub's already answered this part.] > Shouldn't we then simply never have a may/must_*_p (T1, T2) > with T1 and T2 being not compatible? That is, force promotion > rules on them with template magic? This was what I meant by: Or we could suppress warnings by forcibly converting the input. Sometimes the warnings are useful though. We already do this kind of conversion for arithmetic, to ensure that poly_uint16 + poly_uint16 -> poly_int64 promotes before the addition rather than after it. But it defeats the point of the comparison warning, which is that you're potentially redefining the sign bit. I think the warning's just as valuable for may/must comparison of non-literals as it is for normal comparison operators. It's just unfortunate that we no longer get the special handling of literals. Thanks, Richard
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
On Wed, Oct 25, 2017 at 12:19:37PM +0200, Richard Biener wrote: > Hum. But then we still warn for must_eq_p (x, 1), no? > > So why does > > int f (unsigned int x) > { > return x != 0; > } > > not warn? Probably because of promotion of the arg. Because then one comparison operand is positive constant smaller than the signed maximum. We warn when both comparison operands are variable and one is signed and the other is unsigned. Jakub
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
On Tue, Oct 24, 2017 at 3:24 PM, Richard Sandifordwrote: > Richard Biener writes: >> On Tue, Oct 24, 2017 at 2:48 PM, Richard Sandiford >> wrote: >>> Richard Biener writes: On Tue, Oct 24, 2017 at 1:23 PM, Richard Sandiford wrote: > Eric Botcazou writes: >>> Yeah. E.g. for ==, the two options would be: >>> >>> a) must_eq (a, b) -> a == b >>>must_ne (a, b) -> a != b >>> >>>which has the weird property that (a == b) != (!(a != b)) >>> >>> b) must_eq (a, b) -> a == b >>>may_ne (a, b)-> a != b >>> >>>which has the weird property that a can be equal to b when a != b >> >> Yes, a) was the one I had in mind, i.e. the traditional operators are >> the must >> variants and you use an outer ! in order to express the may. Of >> course this >> would require a bit of discipline but, on the other hand, if most of >> the cases >> fall in the must category, that could be less ugly. > > I just think that discipline is going to be hard to maintain in practice, > since it's so natural to assume (a == b || a != b) == true. With the > may/must approach, static type checking forces the issue. > >>> Sorry about that. It's the best I could come up with without losing >>> the may/must distinction. >> >> Which variant is known_zero though? Must or may? > > must. maybe_nonzero is the may version. Can you rename known_zero to must_be_zero then? >>> >>> That'd be OK with me. >>> >>> Another alternative I wondered about was must_eq_0 / may_ne_0. >>> What's wrong with must_eq (X, 0) / may_eq (X, 0) btw? >>> >>> must_eq (X, 0) generated a warning if X is unsigned, so sometimes you'd >>> need must_eq (X, 0) and sometimes must_eq (X, 0U). >> >> Is that because they are templates? Maybe providing a partial specialization >> would help? > > I don't think it's templates specifically. We end up with something like: > > int f (unsigned int x, const int y) > { > return x != y; > } > > int g (unsigned int x) { return f (x, 0); } > > which generates a warning too. > >> I'd be fine with must_eq_p and may_eq_0. > > OK, I'll switch to that if there are no objections. Hum. But then we still warn for must_eq_p (x, 1), no? So why does int f (unsigned int x) { return x != 0; } not warn? Probably because of promotion of the arg. Shouldn't we then simply never have a may/must_*_p (T1, T2) with T1 and T2 being not compatible? That is, force promotion rules on them with template magic? Richard. > Thanks, > Richard
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
Richard Bienerwrites: > On Tue, Oct 24, 2017 at 2:48 PM, Richard Sandiford > wrote: >> Richard Biener writes: >>> On Tue, Oct 24, 2017 at 1:23 PM, Richard Sandiford >>> wrote: Eric Botcazou writes: >> Yeah. E.g. for ==, the two options would be: >> >> a) must_eq (a, b) -> a == b >>must_ne (a, b) -> a != b >> >>which has the weird property that (a == b) != (!(a != b)) >> >> b) must_eq (a, b) -> a == b >>may_ne (a, b)-> a != b >> >>which has the weird property that a can be equal to b when a != b > > Yes, a) was the one I had in mind, i.e. the traditional operators are > the must > variants and you use an outer ! in order to express the may. Of > course this > would require a bit of discipline but, on the other hand, if most of > the cases > fall in the must category, that could be less ugly. I just think that discipline is going to be hard to maintain in practice, since it's so natural to assume (a == b || a != b) == true. With the may/must approach, static type checking forces the issue. >> Sorry about that. It's the best I could come up with without losing >> the may/must distinction. > > Which variant is known_zero though? Must or may? must. maybe_nonzero is the may version. >>> >>> Can you rename known_zero to must_be_zero then? >> >> That'd be OK with me. >> >> Another alternative I wondered about was must_eq_0 / may_ne_0. >> >>> What's wrong with must_eq (X, 0) / may_eq (X, 0) btw? >> >> must_eq (X, 0) generated a warning if X is unsigned, so sometimes you'd >> need must_eq (X, 0) and sometimes must_eq (X, 0U). > > Is that because they are templates? Maybe providing a partial specialization > would help? I don't think it's templates specifically. We end up with something like: int f (unsigned int x, const int y) { return x != y; } int g (unsigned int x) { return f (x, 0); } which generates a warning too. > I'd be fine with must_eq_p and may_eq_0. OK, I'll switch to that if there are no objections. Thanks, Richard
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
On Tue, Oct 24, 2017 at 2:48 PM, Richard Sandifordwrote: > Richard Biener writes: >> On Tue, Oct 24, 2017 at 1:23 PM, Richard Sandiford >> wrote: >>> Eric Botcazou writes: > Yeah. E.g. for ==, the two options would be: > > a) must_eq (a, b) -> a == b >must_ne (a, b) -> a != b > >which has the weird property that (a == b) != (!(a != b)) > > b) must_eq (a, b) -> a == b >may_ne (a, b)-> a != b > >which has the weird property that a can be equal to b when a != b Yes, a) was the one I had in mind, i.e. the traditional operators are the must variants and you use an outer ! in order to express the may. Of course this would require a bit of discipline but, on the other hand, if most of the cases fall in the must category, that could be less ugly. >>> >>> I just think that discipline is going to be hard to maintain in practice, >>> since it's so natural to assume (a == b || a != b) == true. With the >>> may/must approach, static type checking forces the issue. >>> > Sorry about that. It's the best I could come up with without losing > the may/must distinction. Which variant is known_zero though? Must or may? >>> >>> must. maybe_nonzero is the may version. >> >> Can you rename known_zero to must_be_zero then? > > That'd be OK with me. > > Another alternative I wondered about was must_eq_0 / may_ne_0. > >> What's wrong with must_eq (X, 0) / may_eq (X, 0) btw? > > must_eq (X, 0) generated a warning if X is unsigned, so sometimes you'd > need must_eq (X, 0) and sometimes must_eq (X, 0U). Is that because they are templates? Maybe providing a partial specialization would help? I'd be fine with must_eq_p and may_eq_0. Richard. > Having a specific > function seemed cleaner, especially in routines that were polymorphic > in X. > > Or we could suppress warnings by forcibly converting the input. > Sometimes the warnings are useful though. > > Thanks, > Richard
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
Richard Bienerwrites: > On Tue, Oct 24, 2017 at 1:23 PM, Richard Sandiford > wrote: >> Eric Botcazou writes: Yeah. E.g. for ==, the two options would be: a) must_eq (a, b) -> a == b must_ne (a, b) -> a != b which has the weird property that (a == b) != (!(a != b)) b) must_eq (a, b) -> a == b may_ne (a, b)-> a != b which has the weird property that a can be equal to b when a != b >>> >>> Yes, a) was the one I had in mind, i.e. the traditional operators are >>> the must >>> variants and you use an outer ! in order to express the may. Of course this >>> would require a bit of discipline but, on the other hand, if most of >>> the cases >>> fall in the must category, that could be less ugly. >> >> I just think that discipline is going to be hard to maintain in practice, >> since it's so natural to assume (a == b || a != b) == true. With the >> may/must approach, static type checking forces the issue. >> Sorry about that. It's the best I could come up with without losing the may/must distinction. >>> >>> Which variant is known_zero though? Must or may? >> >> must. maybe_nonzero is the may version. > > Can you rename known_zero to must_be_zero then? That'd be OK with me. Another alternative I wondered about was must_eq_0 / may_ne_0. > What's wrong with must_eq (X, 0) / may_eq (X, 0) btw? must_eq (X, 0) generated a warning if X is unsigned, so sometimes you'd need must_eq (X, 0) and sometimes must_eq (X, 0U). Having a specific function seemed cleaner, especially in routines that were polymorphic in X. Or we could suppress warnings by forcibly converting the input. Sometimes the warnings are useful though. Thanks, Richard
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
On Tue, Oct 24, 2017 at 1:23 PM, Richard Sandifordwrote: > Eric Botcazou writes: >>> Yeah. E.g. for ==, the two options would be: >>> >>> a) must_eq (a, b) -> a == b >>>must_ne (a, b) -> a != b >>> >>>which has the weird property that (a == b) != (!(a != b)) >>> >>> b) must_eq (a, b) -> a == b >>>may_ne (a, b)-> a != b >>> >>>which has the weird property that a can be equal to b when a != b >> >> Yes, a) was the one I had in mind, i.e. the traditional operators are the >> must >> variants and you use an outer ! in order to express the may. Of course this >> would require a bit of discipline but, on the other hand, if most of the >> cases >> fall in the must category, that could be less ugly. > > I just think that discipline is going to be hard to maintain in practice, > since it's so natural to assume (a == b || a != b) == true. With the > may/must approach, static type checking forces the issue. > >>> Sorry about that. It's the best I could come up with without losing >>> the may/must distinction. >> >> Which variant is known_zero though? Must or may? > > must. maybe_nonzero is the may version. Can you rename known_zero to must_be_zero then? What's wrong with must_eq (X, 0) / may_eq (X, 0) btw? Richard. > Thanks, > Richard
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
Eric Botcazouwrites: >> Yeah. E.g. for ==, the two options would be: >> >> a) must_eq (a, b) -> a == b >>must_ne (a, b) -> a != b >> >>which has the weird property that (a == b) != (!(a != b)) >> >> b) must_eq (a, b) -> a == b >>may_ne (a, b)-> a != b >> >>which has the weird property that a can be equal to b when a != b > > Yes, a) was the one I had in mind, i.e. the traditional operators are the > must > variants and you use an outer ! in order to express the may. Of course this > would require a bit of discipline but, on the other hand, if most of the > cases > fall in the must category, that could be less ugly. I just think that discipline is going to be hard to maintain in practice, since it's so natural to assume (a == b || a != b) == true. With the may/must approach, static type checking forces the issue. >> Sorry about that. It's the best I could come up with without losing >> the may/must distinction. > > Which variant is known_zero though? Must or may? must. maybe_nonzero is the may version. Thanks, Richard
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
> Yeah. E.g. for ==, the two options would be: > > a) must_eq (a, b) -> a == b >must_ne (a, b) -> a != b > >which has the weird property that (a == b) != (!(a != b)) > > b) must_eq (a, b) -> a == b >may_ne (a, b)-> a != b > >which has the weird property that a can be equal to b when a != b Yes, a) was the one I had in mind, i.e. the traditional operators are the must variants and you use an outer ! in order to express the may. Of course this would require a bit of discipline but, on the other hand, if most of the cases fall in the must category, that could be less ugly. > Sorry about that. It's the best I could come up with without losing > the may/must distinction. Which variant is known_zero though? Must or may? -- Eric Botcazou
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
Eric Botcazouwrites: >> The patch that adds poly_int has detailed documentation, but the main >> points are: >> >> * there's no total ordering between poly_ints, so the best we can do >> when comparing them is to ask whether two values *might* or *must* >> be related in a particular way. E.g. if mode A has size 2 + 2X >> and mode B has size 4, the condition: >> >> GET_MODE_SIZE (A) <= GET_MODE_SIZE (B) >> >> is true for X<=1 and false for X>=2. This translates to: >> >> may_le (GET_MODE_SIZE (A), GET_MODE_SIZE (B)) == true >> must_le (GET_MODE_SIZE (A), GET_MODE_SIZE (B)) == false >> >> Of course, the may/must distinction already exists in things like >> alias analysis. > > I presume that you considered using traditional operators instead of awkward > names, despite the lack of total ordering, and rejected it? Yeah. E.g. for ==, the two options would be: a) must_eq (a, b) -> a == b must_ne (a, b) -> a != b which has the weird property that (a == b) != (!(a != b)) b) must_eq (a, b) -> a == b may_ne (a, b)-> a != b which has the weird property that a can be equal to b when a != b may/must matters in a similar way as it does for alias analysis: "may" usually selects conservatively-correct, just-in-case behaviour while "must" selects something that would be wrong if the condition didn't hold. > Because: > > - && (bitpos == 0 || MEM_P (target))) > + && (known_zero (bitpos) || MEM_P (target))) > > - && bitsize == TYPE_PRECISION (type)) > + && must_eq (bitsize, TYPE_PRECISION (type))) > > - if (need_to_clear && size > 0) > + if (need_to_clear && may_gt (size, 0)) > > is really ugly... Sorry about that. It's the best I could come up with without losing the may/must distinction. Thanks, Richard
Re: [000/nnn] poly_int: representation of runtime offsets and sizes
> The patch that adds poly_int has detailed documentation, but the main > points are: > > * there's no total ordering between poly_ints, so the best we can do > when comparing them is to ask whether two values *might* or *must* > be related in a particular way. E.g. if mode A has size 2 + 2X > and mode B has size 4, the condition: > > GET_MODE_SIZE (A) <= GET_MODE_SIZE (B) > > is true for X<=1 and false for X>=2. This translates to: > > may_le (GET_MODE_SIZE (A), GET_MODE_SIZE (B)) == true > must_le (GET_MODE_SIZE (A), GET_MODE_SIZE (B)) == false > > Of course, the may/must distinction already exists in things like > alias analysis. I presume that you considered using traditional operators instead of awkward names, despite the lack of total ordering, and rejected it? Because: - && (bitpos == 0 || MEM_P (target))) + && (known_zero (bitpos) || MEM_P (target))) - && bitsize == TYPE_PRECISION (type)) + && must_eq (bitsize, TYPE_PRECISION (type))) - if (need_to_clear && size > 0) + if (need_to_clear && may_gt (size, 0)) is really ugly... -- Eric Botcazou