Re: patch to fix constant math -5th patch, rtl
On Wed, Apr 24, 2013 at 5:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 09:36 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. Yes, that's what I understand. But consider you get a CONST_INT that is _not_ a valid QImode value. Current code simply trusts that it is, given the context from ... And the fact that it we have to trust but cannot verify is a severe problem at the rtl level that is not going to go away.what i have been strongly objecting to is your idea that just because we cannot verify it, we can thus go change it in some completely different way (i.e. the infinite precision nonsense that you keep hitting us with) and it will all be ok. Appearantly it is all ok because that's exactly what we have today (and had for the last 25 years). CONST_INT encodes infinite precision signed values (with the complication that a QImode 0x80 isn't valid, thus all modes are signed as well it seems). I think this is the fundamental disagreement. Your last step doesn't follow. RTL integer modes are neither signed nor unsigned. They are just a collection of N bits. The fact that CONST_INTs represent smaller-than-HWI integers in sign-extended form is purely a represential detail. There are no semantics attached to it. We could just as easily have decided to extend with zeros or ones instead of sign bits. Although the decision was made before my time, I'm pretty sure the point of having a canonical representation (which happened to be sign extension) was to make sure that any given rtl constant has only a single representation. It would be too confusing if a QImode 0x80 could be represented as either (const_int 128) or (const_int -128) (would (const_int 384) then also be OK?). No, not as value for a QImode as it doesn't fit there. And that's the problem with using an infinite-precision wide_int. If you directly convert a CONST_INT representation of 0x80 into a wide_int, you will always get infinite-precision -128, thanks to the CONST_INT canonicalisation rule. But if you arrive at 0x80 though arithmetic, you might get infinite-precision 128 instead. These two values would not compare equal. That's true. Note that I am not objecting to the canonicalization choice for the RTL object. On trees we do have -128 and 128 QImode integers as tree constants have a sign. So we clearly cannot have wide_int make that choice, but those that create either a tree object or a RTL object have to do additional canonicalization (or truncation to not allow a QImode 384). Yes, I'm again arguing that making choices for wide_int shouldn't be done because it seems right for RTL or right for how a CPU operates. But we are mixing two things in this series of patches - introduction of an additional RTX object kind CONST_WIDE_INT together with deciding on its encoding of constant values, and introduction of a wide_int class as a vehicle to do arithmetic on the host for larger than HOST_WIDE_INT values. The latter could be separated by dropping CONST_DOUBLE in favor of CONST_WIDE_INT everywhere and simply providing a CONST_WIDE_INT - double-int interface (both ways, so you'd actually never generate a CONST_WIDE_INT that doesn't fit a double-int). CONST_DOUBLE encodes infinite precision signed values as well. Just the infinite is limited by the size of the encoding, one and two HOST_WIDE_INTs. It encodes an N-bit integer. It's just that (assuming non-power-of-2 modes) several N-bit integers (with varying N) can be encoded using the same CONST_DOUBLE representation. That might be what you meant, sorry, and so might seem pedantic, but I wasn't sure. Yes, that's what I meant. Being able to share the same RTX object for constants with the same representation but a different mode is nice and looks appealing (of course works only when the actual mode stored in the RTX object is then sth like VOIDmode ...). That we have gazillions of NULL pointer constants on trees (for each pointer type) isn't. Richard. Richard
Re: patch to fix constant math -5th patch, rtl
On Wed, Apr 24, 2013 at 5:55 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. I disagree. All rtl objects have a precision. REGs, MEMs, SYMBOL_REFs, LABEL_REFs and CONSTs all have precisions, and the last three are run-time constants. Why should CONST_INT and CONST_DOUBLE be different? Well - they _are_ different. They don't even have a mode at the moment. If you want to change that be my guest (or well, it's unfortunate to lose the sharing then) - but Kenny always repeats that this is impossible to fix. Having CONST_INT and CONST_DOUBLE without a precision but CONST_WIDE_INT with a precision would be at least odd. See e.g. the hoops that cselib has to jump through: /* We need to pass down the mode of constants through the hash table functions. For that purpose, wrap them in a CONST of the appropriate mode. */ static rtx wrap_constant (enum machine_mode mode, rtx x) { if ((!CONST_SCALAR_INT_P (x)) GET_CODE (x) != CONST_FIXED) return x; gcc_assert (mode != VOIDmode); return gen_rtx_CONST (mode, x); } That is, cselib locally converts (const_int X) into (const:M (const_int X)), purely so that it doesn't lose track of the CONST_INT's mode. (const:M (const_int ...)) is invalid rtl elsewhere, but a necessary hack here all the same. Indeed ugly. But I wonder why cselib needs to store constants in hashtables at all ... they should be VALUEs themselves. So the fix for the above might not necessarily be to assign the CONST_INT a mode (not that CONST_WIDE_INT would fix the above). What RTL currently has looks better to me - operations have explicitely specified precisions. But that isn't enough to determine the precision of all operands. A classic case is ZERO_EXTEND. Something like: (zero_extend:DI (reg:SI X)) is unambiguous. But if you substitute (reg:SI X) with a CONST_INT, the result becomes ambiguous. E.g. we could end up with: (zero_extend:DI (const_int -1)) The ZERO_EXTEND operand still has SImode, but that fact is not explicit in the rtl, and is certainly not explicit in the ZERO_EXTEND operation. So if we just see the result above, we no longer know whether the result should be (const_int 0xff), (const_int 0x), or what. The same goes for: That situation only occurs when you have unfolded RTX. You should have never generated the above (and hopefully the RTL verifier doesn't allow it), but instead called sth like simplify_gen_zero_extend (DImode, SImode, x); with x being the constant substituted for X. It's probably unfortunate that parts of the RTL machinery work like (if I remember correctly) for_each_rtx (x, replace-interesting-stuff); simplify (x); (zero_extend:DI (const_int 256)) where (const_int 0) and (const_int 256) are both potential results. It's not just ZERO_EXTEND. E.g.: (zero_extract:SI ...) tells you that an SImode value is being extracted, but it doesn't tell you what precision you're extracting from. So for:
Re: patch to fix constant math -5th patch, rtl
On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 11:13 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Bienerrichard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. Associating one with it to give a precision to an arithmetic operation looks wrong to me and are a source of mismatches. What RTL currently has looks better to me - operations have explicitely specified precisions. I have tried very hard to make wide-int work very efficiently with both tree and rtl without biasing the rep towards either representation. Both rtl and trees constants have a precision. In tree, constants are done better than in rtl because the tree really does have a field that is filled in that points to a type. However, that does not mean that rtl constants do not have a precision: currently you have to look around at the context to find the mode of a constant that is in your hand, but it is in fact always there. At the rtl level, you can see the entire patch - we always find an appropriate mode. Appearantly you cannot. See Richard S. examples. As of better, the tree has the issue that we have so many unshared constants because they only differ in type but not in their representation. That's the nice part of RTL constants all having VOIDmode ... Richard.
Re: patch to fix constant math -5th patch, rtl
On 05/03/2013 07:34 AM, Richard Biener wrote: On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 11:13 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Bienerrichard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. Associating one with it to give a precision to an arithmetic operation looks wrong to me and are a source of mismatches. What RTL currently has looks better to me - operations have explicitely specified precisions. I have tried very hard to make wide-int work very efficiently with both tree and rtl without biasing the rep towards either representation. Both rtl and trees constants have a precision. In tree, constants are done better than in rtl because the tree really does have a field that is filled in that points to a type. However, that does not mean that rtl constants do not have a precision: currently you have to look around at the context to find the mode of a constant that is in your hand, but it is in fact always there. At the rtl level, you can see the entire patch - we always find an appropriate mode. Appearantly you cannot. See Richard S. examples. As of better, the tree has the issue that we have so many unshared constants because they only differ in type but not in their representation. That's the nice part of RTL constants all having VOIDmode ... Richard. I said we could always find a mode, i did not say that in order to find the mode we did not have to stand on our head, juggle chainsaws and say mother may i. The decision to leave the mode as void in rtl integer constants was made to save space, but comes with an otherwise very high cost and in today's world of cheap memory seems fairly dated. It is a decision that i and others would love to change and the truth is wide int is one step in that direction (in that it gets rid of the pun of using double-int for both integers and floats where the discriminator is voidmode for ints.) But for now we have to live with that poor decision.
Re: patch to fix constant math -5th patch, rtl
On Fri, May 3, 2013 at 1:49 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 05/03/2013 07:34 AM, Richard Biener wrote: On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 11:13 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Bienerrichard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. Associating one with it to give a precision to an arithmetic operation looks wrong to me and are a source of mismatches. What RTL currently has looks better to me - operations have explicitely specified precisions. I have tried very hard to make wide-int work very efficiently with both tree and rtl without biasing the rep towards either representation. Both rtl and trees constants have a precision. In tree, constants are done better than in rtl because the tree really does have a field that is filled in that points to a type. However, that does not mean that rtl constants do not have a precision: currently you have to look around at the context to find the mode of a constant that is in your hand, but it is in fact always there. At the rtl level, you can see the entire patch - we always find an appropriate mode. Appearantly you cannot. See Richard S. examples. As of better, the tree has the issue that we have so many unshared constants because they only differ in type but not in their representation. That's the nice part of RTL constants all having VOIDmode ... Richard. I said we could always find a mode, i did not say that in order to find the mode we did not have to stand on our head, juggle chainsaws and say mother may i. The decision to leave the mode as void in rtl integer constants was made to save space, but comes with an otherwise very high cost and in today's world of cheap memory seems fairly dated. It is a decision that i and others would love to change and the truth is wide int is one step in that direction (in that it gets rid of the pun of using double-int for both integers and floats where the discriminator is voidmode for ints.) But for now we have to live with that poor decision. As far as I have read your wide-int patches the CONST_WIDE_INT RTX object does not include a mode. So I don't see it as a step forward in any way (other than that it makes it explicit that you _do_ need a mode to do any operation on a constant). Richard.
Re: patch to fix constant math -5th patch, rtl
On 05/03/2013 08:12 AM, Richard Biener wrote: On Fri, May 3, 2013 at 1:49 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 05/03/2013 07:34 AM, Richard Biener wrote: On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 11:13 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Bienerrichard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. Associating one with it to give a precision to an arithmetic operation looks wrong to me and are a source of mismatches. What RTL currently has looks better to me - operations have explicitely specified precisions. I have tried very hard to make wide-int work very efficiently with both tree and rtl without biasing the rep towards either representation. Both rtl and trees constants have a precision. In tree, constants are done better than in rtl because the tree really does have a field that is filled in that points to a type. However, that does not mean that rtl constants do not have a precision: currently you have to look around at the context to find the mode of a constant that is in your hand, but it is in fact always there. At the rtl level, you can see the entire patch - we always find an appropriate mode. Appearantly you cannot. See Richard S. examples. As of better, the tree has the issue that we have so many unshared constants because they only differ in type but not in their representation. That's the nice part of RTL constants all having VOIDmode ... Richard. I said we could always find a mode, i did not say that in order to find the mode we did not have to stand on our head, juggle chainsaws and say mother may i. The decision to leave the mode as void in rtl integer constants was made to save space, but comes with an otherwise very high cost and in today's world of cheap memory seems fairly dated. It is a decision that i and others would love to change and the truth is wide int is one step in that direction (in that it gets rid of the pun of using double-int for both integers and floats where the discriminator is voidmode for ints.) But for now we have to live with that poor decision. As far as I have read your wide-int patches the CONST_WIDE_INT RTX object does not include a mode. So I don't see it as a step forward in any way (other than that it makes it explicit that you _do_ need a mode to do any operation on a constant). Richard. There are several problems with just dropping a mode into the already existing mode field of an rtx constant. 1) There may be places where the a back end is testing equality to see if constants of different modes are in fact the same value. 2) Most of the places what build int constants use GEN_INT which does not take a mode, even though about 95% of those places have a mode right there and the rest just take a little work.There are constructor that do take a mode, but in the end they just throw the mode on the floor. 3) The canonical test to see if a CONST_DOUBLE contains an int or float is to test if the mode is VOIDmode. Any port that is converted to have TARGET_SUPPORTS_WIDE_INT has no more of problem (3). I admit that rooting out (1) is
Re: patch to fix constant math -5th patch, rtl
Richard Biener richard.guent...@gmail.com writes: See e.g. the hoops that cselib has to jump through: /* We need to pass down the mode of constants through the hash table functions. For that purpose, wrap them in a CONST of the appropriate mode. */ static rtx wrap_constant (enum machine_mode mode, rtx x) { if ((!CONST_SCALAR_INT_P (x)) GET_CODE (x) != CONST_FIXED) return x; gcc_assert (mode != VOIDmode); return gen_rtx_CONST (mode, x); } That is, cselib locally converts (const_int X) into (const:M (const_int X)), purely so that it doesn't lose track of the CONST_INT's mode. (const:M (const_int ...)) is invalid rtl elsewhere, but a necessary hack here all the same. Indeed ugly. But I wonder why cselib needs to store constants in hashtables at all ... they should be VALUEs themselves. So the fix for the above might not necessarily be to assign the CONST_INT a mode (not that CONST_WIDE_INT would fix the above). I don't understand. Do you mean that cselib values ought to have a field to say whether the value is constant or not, and if so, what constant that is? That feels like just the same kind of hack as the above. The current idea of chaining all known equivalent rtxes in a list seems more natural than having a list of all known equivalent rtxes except CONST_INT and CONST_DOUBLE, which have to be stored separately instead. (Again, we have runtime constants like SYMBOL_REF, which store modes, and which would presumably still be in the normal rtx list.) CONST_WIDE_INT was never supposed to solve this problem. I'm just giving it as an example to back up the argument that rtx constants do in fact have modes (although those modes are not stored in the rtx). The code above is there to make sure that equivalence stays transitive. Without it we could have bogus equivalences like: (A) (reg:DI X) == (const_int Y) == (reg:SI Z) even though it cannot be the case that: (B) (reg:DI X) == (reg:SI Z) My point is that, semantically, (A) did not come from X and Z being equivalent to the same constant. X was equivalent to (const_int:DI Y) and Z was equivalent to (const_int:SI Y). (A) only came about because we happen to use the same rtx object to represent those two semantically- distinct constants. The idea isn't to make CONST_WIDE_INT get rid of the code above. The idea is to make sure that wide_int has a precision and so doesn't require code like the above to be written when dealing with wide_ints. In other words, I got the impression your argument was the fact that CONST_INT and CONST_DOUBLE don't store a mode shows that wide_int shouldn't store a precision. But the fact that CONST_INT and CONST_DOUBLE don't store a mode doesn't mean they don't _have_ a mode. You just have to keep track of that mode separately. And the same would apply to wide_int if we did the same thing there. What I was trying to argue was that storing the mode/precision separately is not always easy. It's also much less robust, because getting the wrong mode or precision will only show up for certain values. If the precision is stored in the wide_int, mismatches can be asserted for based on precision alone, regardless of the value. Ok, so please then make all CONST_INTs and CONST_DOUBLEs have a mode! I'm saying that CONST_INT and CONST_DOUBLE already have a mode, but that mode is not stored in the rtx. So if you're saying make all CONST_INTs and CONST_DOUBLEs _store_ a mode, then yeah, I'd like to :-) But I see Kenny's patch as a prerequisite for that, because it consolidates the CONST_INT and CONST_DOUBLE code so that the choice of rtx code is less special. Lots more work is needed after that. Although TBH, the huge pushback that Kenny has got from this patch puts me off ever trying that change. But storing the mode in the rtx is orthogonal to what Kenny is doing. The mode of each rtx constant is already available in the places that Kenny is changing, because we already do the work to keep track of the mode separately. Being able to get the mode directly from the rtx would be simpler and IMO better, but the semantics are the same either way. Kenny's patch is not designed to fix the CONST_INT representation (although the patch does make it easier to fix the representation in future). Kenny's patch is about representing and handling constants that we can't at the moment. The argument isn't whether CONST_WIDE_INT repeats mistakes made for CONST_INT and CONST_DOUBLE; I hope we agree that CONST_WIDE_INT should behave like the other two, whatever that is. The argument is about whether we copy the mistake into the wide_int class. Storing a precision in wide_int in no way requires CONST_WIDE_INT to store a mode. They are separate choices. The solution is not to have a CONST_WIDE_INT (again with VOIDmode and no precision in the RTX object(!)) and only have wide_int have a precision. Why is having a VOIDmode CONST_WIDE_INT any worse than having a VOIDmode CONST_INT or
Re: patch to fix constant math -5th patch, rtl
On Fri, May 3, 2013 at 2:31 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 05/03/2013 08:12 AM, Richard Biener wrote: On Fri, May 3, 2013 at 1:49 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 05/03/2013 07:34 AM, Richard Biener wrote: On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 11:13 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Bienerrichard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. Associating one with it to give a precision to an arithmetic operation looks wrong to me and are a source of mismatches. What RTL currently has looks better to me - operations have explicitely specified precisions. I have tried very hard to make wide-int work very efficiently with both tree and rtl without biasing the rep towards either representation. Both rtl and trees constants have a precision. In tree, constants are done better than in rtl because the tree really does have a field that is filled in that points to a type. However, that does not mean that rtl constants do not have a precision: currently you have to look around at the context to find the mode of a constant that is in your hand, but it is in fact always there. At the rtl level, you can see the entire patch - we always find an appropriate mode. Appearantly you cannot. See Richard S. examples. As of better, the tree has the issue that we have so many unshared constants because they only differ in type but not in their representation. That's the nice part of RTL constants all having VOIDmode ... Richard. I said we could always find a mode, i did not say that in order to find the mode we did not have to stand on our head, juggle chainsaws and say mother may i. The decision to leave the mode as void in rtl integer constants was made to save space, but comes with an otherwise very high cost and in today's world of cheap memory seems fairly dated. It is a decision that i and others would love to change and the truth is wide int is one step in that direction (in that it gets rid of the pun of using double-int for both integers and floats where the discriminator is voidmode for ints.) But for now we have to live with that poor decision. As far as I have read your wide-int patches the CONST_WIDE_INT RTX object does not include a mode. So I don't see it as a step forward in any way (other than that it makes it explicit that you _do_ need a mode to do any operation on a constant). Richard. There are several problems with just dropping a mode into the already existing mode field of an rtx constant. 1) There may be places where the a back end is testing equality to see if constants of different modes are in fact the same value. That supposedly only happens in places where both RTX objects are know to be constants. Which makes me guess that it's in 99% of the cases a comparison against one of the static RTX objects like const0_rtx - thus easily greppable for (and easily converted similar to the tree case where we have predicates for such tests like integer_zerop ()).
Re: patch to fix constant math -5th patch, rtl
On 05/03/2013 07:19 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 5:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 09:36 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. Yes, that's what I understand. But consider you get a CONST_INT that is _not_ a valid QImode value. Current code simply trusts that it is, given the context from ... And the fact that it we have to trust but cannot verify is a severe problem at the rtl level that is not going to go away.what i have been strongly objecting to is your idea that just because we cannot verify it, we can thus go change it in some completely different way (i.e. the infinite precision nonsense that you keep hitting us with) and it will all be ok. Appearantly it is all ok because that's exactly what we have today (and had for the last 25 years). CONST_INT encodes infinite precision signed values (with the complication that a QImode 0x80 isn't valid, thus all modes are signed as well it seems). I think this is the fundamental disagreement. Your last step doesn't follow. RTL integer modes are neither signed nor unsigned. They are just a collection of N bits. The fact that CONST_INTs represent smaller-than-HWI integers in sign-extended form is purely a represential detail. There are no semantics attached to it. We could just as easily have decided to extend with zeros or ones instead of sign bits. Although the decision was made before my time, I'm pretty sure the point of having a canonical representation (which happened to be sign extension) was to make sure that any given rtl constant has only a single representation. It would be too confusing if a QImode 0x80 could be represented as either (const_int 128) or (const_int -128) (would (const_int 384) then also be OK?). No, not as value for a QImode as it doesn't fit there. And that's the problem with using an infinite-precision wide_int. If you directly convert a CONST_INT representation of 0x80 into a wide_int, you will always get infinite-precision -128, thanks to the CONST_INT canonicalisation rule. But if you arrive at 0x80 though arithmetic, you might get infinite-precision 128 instead. These two values would not compare equal. That's true. Note that I am not objecting to the canonicalization choice for the RTL object. On trees we do have -128 and 128 QImode integers as tree constants have a sign. So we clearly cannot have wide_int make that choice, but those that create either a tree object or a RTL object have to do additional canonicalization (or truncation to not allow a QImode 384). Yes, I'm again arguing that making choices for wide_int shouldn't be done because it seems right for RTL or right for how a CPU operates. But we are mixing two things in this series of patches - introduction of an additional RTX object kind CONST_WIDE_INT together with deciding on its encoding of constant values, and introduction of a wide_int class as a vehicle to do arithmetic on the host for larger than HOST_WIDE_INT values. The latter could be separated by dropping CONST_DOUBLE in favor of CONST_WIDE_INT everywhere and simply providing a CONST_WIDE_INT - double-int interface (both ways, so you'd actually never generate a CONST_WIDE_INT that doesn't fit a double-int). Given the tree world, i am surprised that you would push in this direction. While i do see some benefit for having two reps for ints at the rtl level, I understand the argument that is one too many. The target_supports_wide_int is a transitional trick. The idea is to move the ports away from using CONST_DOUBLE at all for ints. Not only is this a step towards putting a mode in an rtl int const, but it also would allow the floating point world to move beyond the limits that sharing the rep with integers imposes. One of the big goals of this cleanup is to get rid of the three path implementation for integer math: constant fits in HWI - good implementation. constant fits in 2 HWIs - spotty implementation. constant needs more than 2 HWIs - ice or get wrong answer. Doing a trick like this just makes it harder to unify everything into the good implementation category. CONST_DOUBLE encodes infinite precision signed values as well. Just the infinite is limited by the size of the encoding, one and two HOST_WIDE_INTs.
Re: patch to fix constant math -5th patch, rtl
Kenneth Zadeck zad...@naturalbridge.com writes: There are several problems with just dropping a mode into the already existing mode field of an rtx constant. 1) There may be places where the a back end is testing equality to see if constants of different modes are in fact the same value. 2) Most of the places what build int constants use GEN_INT which does not take a mode, even though about 95% of those places have a mode right there and the rest just take a little work.There are constructor that do take a mode, but in the end they just throw the mode on the floor. 3) The canonical test to see if a CONST_DOUBLE contains an int or float is to test if the mode is VOIDmode. Any port that is converted to have TARGET_SUPPORTS_WIDE_INT has no more of problem (3). I admit that rooting out (1) is likely to be the worst of the problems. But we were careful to at least make this work move us in the correct direction. I agree with that, and FWIW, there are others. Two off the top of my head: 4) Many places use const0_rtx instead of CONST0_RTX (mode) (correctly, according to current representation) 5) All const_ints in the .md files would need to be given a mode (except for those places where const_int actually represents a C++ constant, such as in attributes). I realise your list wasn't supposed to be exhaustive, and neither's mine :-) Richard
Re: patch to fix constant math -5th patch, rtl
On Fri, May 3, 2013 at 2:37 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: See e.g. the hoops that cselib has to jump through: /* We need to pass down the mode of constants through the hash table functions. For that purpose, wrap them in a CONST of the appropriate mode. */ static rtx wrap_constant (enum machine_mode mode, rtx x) { if ((!CONST_SCALAR_INT_P (x)) GET_CODE (x) != CONST_FIXED) return x; gcc_assert (mode != VOIDmode); return gen_rtx_CONST (mode, x); } That is, cselib locally converts (const_int X) into (const:M (const_int X)), purely so that it doesn't lose track of the CONST_INT's mode. (const:M (const_int ...)) is invalid rtl elsewhere, but a necessary hack here all the same. Indeed ugly. But I wonder why cselib needs to store constants in hashtables at all ... they should be VALUEs themselves. So the fix for the above might not necessarily be to assign the CONST_INT a mode (not that CONST_WIDE_INT would fix the above). I don't understand. Do you mean that cselib values ought to have a field to say whether the value is constant or not, and if so, what constant that is? That feels like just the same kind of hack as the above. The current idea of chaining all known equivalent rtxes in a list seems more natural than having a list of all known equivalent rtxes except CONST_INT and CONST_DOUBLE, which have to be stored separately instead. (Again, we have runtime constants like SYMBOL_REF, which store modes, and which would presumably still be in the normal rtx list.) CONST_WIDE_INT was never supposed to solve this problem. I'm just giving it as an example to back up the argument that rtx constants do in fact have modes (although those modes are not stored in the rtx). The code above is there to make sure that equivalence stays transitive. Without it we could have bogus equivalences like: (A) (reg:DI X) == (const_int Y) == (reg:SI Z) even though it cannot be the case that: (B) (reg:DI X) == (reg:SI Z) My point is that, semantically, (A) did not come from X and Z being equivalent to the same constant. X was equivalent to (const_int:DI Y) and Z was equivalent to (const_int:SI Y). (A) only came about because we happen to use the same rtx object to represent those two semantically- distinct constants. The idea isn't to make CONST_WIDE_INT get rid of the code above. The idea is to make sure that wide_int has a precision and so doesn't require code like the above to be written when dealing with wide_ints. In other words, I got the impression your argument was the fact that CONST_INT and CONST_DOUBLE don't store a mode shows that wide_int shouldn't store a precision. But the fact that CONST_INT and CONST_DOUBLE don't store a mode doesn't mean they don't _have_ a mode. You just have to keep track of that mode separately. And the same would apply to wide_int if we did the same thing there. What I was trying to argue was that storing the mode/precision separately is not always easy. It's also much less robust, because getting the wrong mode or precision will only show up for certain values. If the precision is stored in the wide_int, mismatches can be asserted for based on precision alone, regardless of the value. I was just arguing that pointing out facts in the RTL land doesn't necessarily influence wide-int which is purely separate. So if you argue that having a mode in RTL constants would be soo nice and thus that is why you want a precision in wide-int then I don't follow that argument. If you want a mode in RTL constants then get a mode in RTL constants! This would make it immediately obvious where to get the precision for wide-ints - something you do not address at all (and as you don't I sort of cannot believe the 'it would be so nice to have a mode on RTL constants'). That said, if modes on RTL constants were so useful then why not have them on CONST_WIDE_INT at least? Please. Only sticking them to wide-int in form of a precision is completely backward to me (and I still think the core wide-int shouldn't have a precision, and if you really want a wide-int-with-precision simply derive from wide-int). Ok, so please then make all CONST_INTs and CONST_DOUBLEs have a mode! I'm saying that CONST_INT and CONST_DOUBLE already have a mode, but that mode is not stored in the rtx. So if you're saying make all CONST_INTs and CONST_DOUBLEs _store_ a mode, then yeah, I'd like to :-) But I see Kenny's patch as a prerequisite for that, because it consolidates the CONST_INT and CONST_DOUBLE code so that the choice of rtx code is less special. Lots more work is needed after that. If there were a separate patch consolidating the paths I'd be all for doing that. I don't see a reason that this cannot be done even with the current code using double-ints. Although TBH, the huge pushback that Kenny has got from this patch puts me off ever
Re: patch to fix constant math -5th patch, rtl
On Fri, May 3, 2013 at 2:45 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 05/03/2013 07:19 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 5:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 09:36 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. Yes, that's what I understand. But consider you get a CONST_INT that is _not_ a valid QImode value. Current code simply trusts that it is, given the context from ... And the fact that it we have to trust but cannot verify is a severe problem at the rtl level that is not going to go away.what i have been strongly objecting to is your idea that just because we cannot verify it, we can thus go change it in some completely different way (i.e. the infinite precision nonsense that you keep hitting us with) and it will all be ok. Appearantly it is all ok because that's exactly what we have today (and had for the last 25 years). CONST_INT encodes infinite precision signed values (with the complication that a QImode 0x80 isn't valid, thus all modes are signed as well it seems). I think this is the fundamental disagreement. Your last step doesn't follow. RTL integer modes are neither signed nor unsigned. They are just a collection of N bits. The fact that CONST_INTs represent smaller-than-HWI integers in sign-extended form is purely a represential detail. There are no semantics attached to it. We could just as easily have decided to extend with zeros or ones instead of sign bits. Although the decision was made before my time, I'm pretty sure the point of having a canonical representation (which happened to be sign extension) was to make sure that any given rtl constant has only a single representation. It would be too confusing if a QImode 0x80 could be represented as either (const_int 128) or (const_int -128) (would (const_int 384) then also be OK?). No, not as value for a QImode as it doesn't fit there. And that's the problem with using an infinite-precision wide_int. If you directly convert a CONST_INT representation of 0x80 into a wide_int, you will always get infinite-precision -128, thanks to the CONST_INT canonicalisation rule. But if you arrive at 0x80 though arithmetic, you might get infinite-precision 128 instead. These two values would not compare equal. That's true. Note that I am not objecting to the canonicalization choice for the RTL object. On trees we do have -128 and 128 QImode integers as tree constants have a sign. So we clearly cannot have wide_int make that choice, but those that create either a tree object or a RTL object have to do additional canonicalization (or truncation to not allow a QImode 384). Yes, I'm again arguing that making choices for wide_int shouldn't be done because it seems right for RTL or right for how a CPU operates. But we are mixing two things in this series of patches - introduction of an additional RTX object kind CONST_WIDE_INT together with deciding on its encoding of constant values, and introduction of a wide_int class as a vehicle to do arithmetic on the host for larger than HOST_WIDE_INT values. The latter could be separated by dropping CONST_DOUBLE in favor of CONST_WIDE_INT everywhere and simply providing a CONST_WIDE_INT - double-int interface (both ways, so you'd actually never generate a CONST_WIDE_INT that doesn't fit a double-int). Given the tree world, i am surprised that you would push in this direction. While i do see some benefit for having two reps for ints at the rtl level, I understand the argument that is one too many. The target_supports_wide_int is a transitional trick. The idea is to move the ports away from using CONST_DOUBLE at all for ints. Not only is this a step towards putting a mode in an rtl int const, but it also would allow the floating point world to move beyond the limits that sharing the rep with integers imposes. One of the big goals of this cleanup is to get rid of the three path implementation for integer math: constant fits in HWI - good implementation. constant fits in 2 HWIs - spotty implementation. constant needs more than 2 HWIs - ice or get wrong answer. Doing a trick like this just makes it harder to unify everything into the good implementation category.
Re: patch to fix constant math -5th patch, rtl
On Fri, May 3, 2013 at 2:48 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Kenneth Zadeck zad...@naturalbridge.com writes: There are several problems with just dropping a mode into the already existing mode field of an rtx constant. 1) There may be places where the a back end is testing equality to see if constants of different modes are in fact the same value. 2) Most of the places what build int constants use GEN_INT which does not take a mode, even though about 95% of those places have a mode right there and the rest just take a little work.There are constructor that do take a mode, but in the end they just throw the mode on the floor. 3) The canonical test to see if a CONST_DOUBLE contains an int or float is to test if the mode is VOIDmode. Any port that is converted to have TARGET_SUPPORTS_WIDE_INT has no more of problem (3). I admit that rooting out (1) is likely to be the worst of the problems. But we were careful to at least make this work move us in the correct direction. I agree with that, and FWIW, there are others. Two off the top of my head: 4) Many places use const0_rtx instead of CONST0_RTX (mode) (correctly, according to current representation) As it's easy from the context to get at a mode just drop const0_rtx and fix the fallout? (and complicate the CONST0_RTX macro to dispatch to const_int_rtx for integer modes) 5) All const_ints in the .md files would need to be given a mode (except for those places where const_int actually represents a C++ constant, such as in attributes). I realise your list wasn't supposed to be exhaustive, and neither's mine :-) Now, do you think it is a good idea to assign integer constants a mode or not? Richard. Richard
Re: patch to fix constant math -5th patch, rtl
Richard Biener richard.guent...@gmail.com writes: 5) All const_ints in the .md files would need to be given a mode (except for those places where const_int actually represents a C++ constant, such as in attributes). I realise your list wasn't supposed to be exhaustive, and neither's mine :-) Now, do you think it is a good idea to assign integer constants a mode or not? I think the answer was obvious: good idea. But it's an aspiration. The huge amount of work involved means that it's out of scope unless someone has several spare months on their hands. The equivalent choice for wide_ints is not an aspiration. The choice is in ours hands. So why force the class to use the old, problematic model that rtl followed when (a) there are no compatiblity reasons to do so and (b) Kenny has already written an implementation that does it the better way? The main reason we share the same CONST_INT and CONST_DOUBLE representation for distinct constants is to save memory. Even that's not an advantage for wide_int, since wide_ints are supposed to be short-lived stack objects. Richard
Re: patch to fix constant math -5th patch, rtl
Richard Biener richard.guent...@gmail.com writes: But storing the mode in the rtx is orthogonal to what Kenny is doing. The mode of each rtx constant is already available in the places that Kenny is changing, because we already do the work to keep track of the mode separately. Being able to get the mode directly from the rtx would be simpler and IMO better, but the semantics are the same either way. Well, you showed examples where it is impossible to get at the mode. No, I showed examples where the mode is not inherent in the rtl. That's a very different thing. I wrote that in respnose to: Richard Biener richard.guent...@gmail.com writes: Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. Associating one with it to give a precision to an arithmetic operation looks wrong to me and are a source of mismatches. What RTL currently has looks better to me - operations have explicitely specified precisions. That is, you seemed to be arguing that constants don't need a precision because, whenever you do anything with them, the operator tells you what precision the constant has. And you seemed to be citing rtl as proof of that. What I was trying to show is that the operator _doesn't_ tell you the precision in all cases. Instead, the operands always have their own precision, and there are rules about which combinations of operand and operator precision are allowed. For most binary operations the three precisions have to be the same. For things like popcount there's no real restriction: the precision of the thing being counted and the precision of the result can be arbitrarily different. For things like zero_extend the operator precision must be greater than the operand precision. Etc. The onus is then on the rtl code to keep track of both the operator and operand precisions where necessary. _And the current rtl code already tries to do that_[*]. The cselib example I gave is one place where we take special measures. See also things like: /* Now recursively process each operand of this operation. We need to handle ZERO_EXTEND specially so that we don't lose track of the inner mode. */ if (GET_CODE (x) == ZERO_EXTEND) { new_rtx = make_compound_operation (XEXP (x, 0), next_code); tem = simplify_const_unary_operation (ZERO_EXTEND, GET_MODE (x), new_rtx, GET_MODE (XEXP (x, 0))); if (tem) return tem; SUBST (XEXP (x, 0), new_rtx); return x; } in combine.c, which is there specifically because this code still knows the mode of both the operand and operator. So all this was trying to dispel the idea that: (a) rtl constants don't have a mode (b) the mode of an operator tells you the mode of the operands Neither is really true. Instead, every rtl constant has a precision/mode. Every tree constant likewise has a precision. The main purpose of wide_int is to handle compile-time arithmetic on rtl constants and tree constants, and if both of those have a precision, it seems strange that wide_int shouldn't. It just pushes the onus of tracking the precision onto the callers, like the current rtl representation does. And the examples I've been giving were supposed to show what a hassle that can be. [*] Highlighted because that's why storing a mode in a CONST_INT or CONST_DOUBLE isn't a prerequisite for Kenny's patch. The mode is already to hand where it needs to be. Thanks, Richard
Re: patch to fix constant math -5th patch, rtl
On 05/03/2013 08:40 AM, Richard Biener wrote: On Fri, May 3, 2013 at 2:31 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 05/03/2013 08:12 AM, Richard Biener wrote: On Fri, May 3, 2013 at 1:49 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 05/03/2013 07:34 AM, Richard Biener wrote: On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 11:13 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Bienerrichard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. Associating one with it to give a precision to an arithmetic operation looks wrong to me and are a source of mismatches. What RTL currently has looks better to me - operations have explicitely specified precisions. I have tried very hard to make wide-int work very efficiently with both tree and rtl without biasing the rep towards either representation. Both rtl and trees constants have a precision. In tree, constants are done better than in rtl because the tree really does have a field that is filled in that points to a type. However, that does not mean that rtl constants do not have a precision: currently you have to look around at the context to find the mode of a constant that is in your hand, but it is in fact always there. At the rtl level, you can see the entire patch - we always find an appropriate mode. Appearantly you cannot. See Richard S. examples. As of better, the tree has the issue that we have so many unshared constants because they only differ in type but not in their representation. That's the nice part of RTL constants all having VOIDmode ... Richard. I said we could always find a mode, i did not say that in order to find the mode we did not have to stand on our head, juggle chainsaws and say mother may i. The decision to leave the mode as void in rtl integer constants was made to save space, but comes with an otherwise very high cost and in today's world of cheap memory seems fairly dated. It is a decision that i and others would love to change and the truth is wide int is one step in that direction (in that it gets rid of the pun of using double-int for both integers and floats where the discriminator is voidmode for ints.) But for now we have to live with that poor decision. As far as I have read your wide-int patches the CONST_WIDE_INT RTX object does not include a mode. So I don't see it as a step forward in any way (other than that it makes it explicit that you _do_ need a mode to do any operation on a constant). Richard. There are several problems with just dropping a mode into the already existing mode field of an rtx constant. 1) There may be places where the a back end is testing equality to see if constants of different modes are in fact the same value. That supposedly only happens in places where both RTX objects are know to be constants. Which makes me guess that it's in 99% of the cases a comparison against one of the static RTX objects like const0_rtx - thus easily greppable for (and easily converted similar to the tree case where we have predicates for such tests like integer_zerop ()). The remaining cases would be missed optimizations at
Re: patch to fix constant math -5th patch, rtl
On 05/03/2013 08:53 AM, Richard Biener wrote: On Fri, May 3, 2013 at 2:37 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: See e.g. the hoops that cselib has to jump through: /* We need to pass down the mode of constants through the hash table functions. For that purpose, wrap them in a CONST of the appropriate mode. */ static rtx wrap_constant (enum machine_mode mode, rtx x) { if ((!CONST_SCALAR_INT_P (x)) GET_CODE (x) != CONST_FIXED) return x; gcc_assert (mode != VOIDmode); return gen_rtx_CONST (mode, x); } That is, cselib locally converts (const_int X) into (const:M (const_int X)), purely so that it doesn't lose track of the CONST_INT's mode. (const:M (const_int ...)) is invalid rtl elsewhere, but a necessary hack here all the same. Indeed ugly. But I wonder why cselib needs to store constants in hashtables at all ... they should be VALUEs themselves. So the fix for the above might not necessarily be to assign the CONST_INT a mode (not that CONST_WIDE_INT would fix the above). I don't understand. Do you mean that cselib values ought to have a field to say whether the value is constant or not, and if so, what constant that is? That feels like just the same kind of hack as the above. The current idea of chaining all known equivalent rtxes in a list seems more natural than having a list of all known equivalent rtxes except CONST_INT and CONST_DOUBLE, which have to be stored separately instead. (Again, we have runtime constants like SYMBOL_REF, which store modes, and which would presumably still be in the normal rtx list.) CONST_WIDE_INT was never supposed to solve this problem. I'm just giving it as an example to back up the argument that rtx constants do in fact have modes (although those modes are not stored in the rtx). The code above is there to make sure that equivalence stays transitive. Without it we could have bogus equivalences like: (A) (reg:DI X) == (const_int Y) == (reg:SI Z) even though it cannot be the case that: (B) (reg:DI X) == (reg:SI Z) My point is that, semantically, (A) did not come from X and Z being equivalent to the same constant. X was equivalent to (const_int:DI Y) and Z was equivalent to (const_int:SI Y). (A) only came about because we happen to use the same rtx object to represent those two semantically- distinct constants. The idea isn't to make CONST_WIDE_INT get rid of the code above. The idea is to make sure that wide_int has a precision and so doesn't require code like the above to be written when dealing with wide_ints. In other words, I got the impression your argument was the fact that CONST_INT and CONST_DOUBLE don't store a mode shows that wide_int shouldn't store a precision. But the fact that CONST_INT and CONST_DOUBLE don't store a mode doesn't mean they don't _have_ a mode. You just have to keep track of that mode separately. And the same would apply to wide_int if we did the same thing there. What I was trying to argue was that storing the mode/precision separately is not always easy. It's also much less robust, because getting the wrong mode or precision will only show up for certain values. If the precision is stored in the wide_int, mismatches can be asserted for based on precision alone, regardless of the value. I was just arguing that pointing out facts in the RTL land doesn't necessarily influence wide-int which is purely separate. So if you argue that having a mode in RTL constants would be soo nice and thus that is why you want a precision in wide-int then I don't follow that argument. If you want a mode in RTL constants then get a mode in RTL constants! This would make it immediately obvious where to get the precision for wide-ints - something you do not address at all (and as you don't I sort of cannot believe the 'it would be so nice to have a mode on RTL constants'). That said, if modes on RTL constants were so useful then why not have them on CONST_WIDE_INT at least? Please. Only sticking them to wide-int in form of a precision is completely backward to me (and I still think the core wide-int shouldn't have a precision, and if you really want a wide-int-with-precision simply derive from wide-int). Ok, so please then make all CONST_INTs and CONST_DOUBLEs have a mode! I'm saying that CONST_INT and CONST_DOUBLE already have a mode, but that mode is not stored in the rtx. So if you're saying make all CONST_INTs and CONST_DOUBLEs _store_ a mode, then yeah, I'd like to :-) But I see Kenny's patch as a prerequisite for that, because it consolidates the CONST_INT and CONST_DOUBLE code so that the choice of rtx code is less special. Lots more work is needed after that. If there were a separate patch consolidating the paths I'd be all for doing that. I don't see a reason that this cannot be done even with the current code using double-ints. Although TBH, the huge pushback that Kenny has got from this patch puts me off ever trying
Re: patch to fix constant math -5th patch, rtl
On 05/03/2013 09:02 AM, Richard Biener wrote: On Fri, May 3, 2013 at 2:45 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 05/03/2013 07:19 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 5:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 09:36 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. Yes, that's what I understand. But consider you get a CONST_INT that is _not_ a valid QImode value. Current code simply trusts that it is, given the context from ... And the fact that it we have to trust but cannot verify is a severe problem at the rtl level that is not going to go away.what i have been strongly objecting to is your idea that just because we cannot verify it, we can thus go change it in some completely different way (i.e. the infinite precision nonsense that you keep hitting us with) and it will all be ok. Appearantly it is all ok because that's exactly what we have today (and had for the last 25 years). CONST_INT encodes infinite precision signed values (with the complication that a QImode 0x80 isn't valid, thus all modes are signed as well it seems). I think this is the fundamental disagreement. Your last step doesn't follow. RTL integer modes are neither signed nor unsigned. They are just a collection of N bits. The fact that CONST_INTs represent smaller-than-HWI integers in sign-extended form is purely a represential detail. There are no semantics attached to it. We could just as easily have decided to extend with zeros or ones instead of sign bits. Although the decision was made before my time, I'm pretty sure the point of having a canonical representation (which happened to be sign extension) was to make sure that any given rtl constant has only a single representation. It would be too confusing if a QImode 0x80 could be represented as either (const_int 128) or (const_int -128) (would (const_int 384) then also be OK?). No, not as value for a QImode as it doesn't fit there. And that's the problem with using an infinite-precision wide_int. If you directly convert a CONST_INT representation of 0x80 into a wide_int, you will always get infinite-precision -128, thanks to the CONST_INT canonicalisation rule. But if you arrive at 0x80 though arithmetic, you might get infinite-precision 128 instead. These two values would not compare equal. That's true. Note that I am not objecting to the canonicalization choice for the RTL object. On trees we do have -128 and 128 QImode integers as tree constants have a sign. So we clearly cannot have wide_int make that choice, but those that create either a tree object or a RTL object have to do additional canonicalization (or truncation to not allow a QImode 384). Yes, I'm again arguing that making choices for wide_int shouldn't be done because it seems right for RTL or right for how a CPU operates. But we are mixing two things in this series of patches - introduction of an additional RTX object kind CONST_WIDE_INT together with deciding on its encoding of constant values, and introduction of a wide_int class as a vehicle to do arithmetic on the host for larger than HOST_WIDE_INT values. The latter could be separated by dropping CONST_DOUBLE in favor of CONST_WIDE_INT everywhere and simply providing a CONST_WIDE_INT - double-int interface (both ways, so you'd actually never generate a CONST_WIDE_INT that doesn't fit a double-int). Given the tree world, i am surprised that you would push in this direction. While i do see some benefit for having two reps for ints at the rtl level, I understand the argument that is one too many. The target_supports_wide_int is a transitional trick. The idea is to move the ports away from using CONST_DOUBLE at all for ints. Not only is this a step towards putting a mode in an rtl int const, but it also would allow the floating point world to move beyond the limits that sharing the rep with integers imposes. One of the big goals of this cleanup is to get rid of the three path implementation for integer math: constant fits in HWI - good implementation. constant fits in 2 HWIs - spotty implementation. constant needs more than 2 HWIs - ice or get wrong answer. Doing a trick like this just makes it harder to unify everything into the good implementation category. CONST_DOUBLE encodes infinite
Re: patch to fix constant math -5th patch, rtl
Richi, I also think that it is a digression to have this discussion about rtl.The root problem is really that Mike, Richard, and myself do not believe that infinite precision math is the proper way to do math for the majority of the compiler. Most of the compiler, at both the rtl and tree level just does the math inline. There are 314 places at the tree level where we ask if the value fits in a hwi and then we do the hwi inline math. The rtl level is even more skewed towards this style of programming. While you view replacing double-int as my primary goal, it accounts for the minority of the places in the code where wide-int needs to be used. Furthermore to call what is done in double-int infinite precision is really pushing it. Because it certainly is not infinite if you happen to have a TImode variable. What i did when i designed wide-int was to come up with a mechanism where i could preserve the performance of that inline math while generalizing it so that it worked correctly for any width. That is why the precision is there. It allows me to avoid the hard work 99% of the time, with an inline test of the precision and then a branch free calculation of the answer. For instance there is no loop checking for carries and propagating them. I also feel strongly that it is our responsibility to preserve, to the extent possible, the notion that optimization never changes the output of a program, except of course for timing. We, in the optimization community, do not always so do so well here, but at the very least, we should always try. Having said that, there are optimizations like VRP that really do need to do math larger than precision defined in the type. I get this, and always have. I understand that if you truncate multiplies, add or subtracts, in VRP then the resulting range is not simple and becomes too difficult to reasonably represent.I have no intention of giving up anything in VRP. My plan for that is to look at the types used in function being compiled and take the largest type, double the precision, and do all of the math within VRP at that expanded fixed precision. We can always guarantee that we can do this in wide-int since the size of the buffer is computed by looking at the target's modes and taking the largest one those times a comfortable multipler. Since you cannot have a type without a corresponding mode, this will always work. This scheme preserves the behavior of VRP while making it work with any sized integer. The alternative is to use a true infinite precision package for VRP but i think that is overkill. Kenny
Re: patch to fix constant math - builtins.c - the first of the tree level patches for wide-int
The only changes here were account for the changes to the wide-int api. On 04/16/2013 04:24 PM, Kenneth Zadeck wrote: Richard, this is the first of the tree level patches so that you can see how the wide-int changes will effect the tree level. This patch converts builtins.c so that it does not in any way assume that tree-cst holds two HWIs. The patch divides all math into two categories: Things that are always so small that we can easily assume that the math can be done using a single HWI and everything else. The things that it assumes can easily be done with a HWI are guarded with assertions. The everything else is done with wide-int. Everything else in this patch is additional abi to support this. The idea is that each pass will be converted, 1 pass per patch in this way.Once everything does not depend on the internals of tree-cst as they do now, then tree-cst will be converted to have an array inside of it rather than just two hwis. Kenny diff --git a/gcc/builtins.c b/gcc/builtins.c index 0c587d1..181784b 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -339,8 +339,8 @@ get_object_alignment_2 (tree exp, unsigned int *alignp, if (TREE_CODE (addr) == BIT_AND_EXPR TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST) { - align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)) - -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))); + align = (tree_to_hwi (TREE_OPERAND (addr, 1)) + -tree_to_hwi (TREE_OPERAND (addr, 1))); align *= BITS_PER_UNIT; addr = TREE_OPERAND (addr, 0); } @@ -357,7 +357,7 @@ get_object_alignment_2 (tree exp, unsigned int *alignp, { unsigned HOST_WIDE_INT step = 1; if (TMR_STEP (exp)) - step = TREE_INT_CST_LOW (TMR_STEP (exp)); + step = tree_to_hwi (TMR_STEP (exp)); align = MIN (align, (step -step) * BITS_PER_UNIT); } if (TMR_INDEX2 (exp)) @@ -379,7 +379,8 @@ get_object_alignment_2 (tree exp, unsigned int *alignp, bitpos += ptr_bitpos; if (TREE_CODE (exp) == MEM_REF || TREE_CODE (exp) == TARGET_MEM_REF) - bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT; + bitpos += wide_int::from_tree (TREE_OPERAND (exp, 1)) + .to_shwi () * BITS_PER_UNIT; } } else if (TREE_CODE (exp) == STRING_CST) @@ -408,23 +409,23 @@ get_object_alignment_2 (tree exp, unsigned int *alignp, } else next_offset = NULL; - if (host_integerp (offset, 1)) + if (tree_fits_uhwi_p (offset)) { /* Any overflow in calculating offset_bits won't change the alignment. */ unsigned offset_bits - = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT); + = ((unsigned) tree_to_hwi (offset) * BITS_PER_UNIT); if (offset_bits) inner = MIN (inner, (offset_bits -offset_bits)); } else if (TREE_CODE (offset) == MULT_EXPR - host_integerp (TREE_OPERAND (offset, 1), 1)) + tree_fits_uhwi_p (TREE_OPERAND (offset, 1))) { /* Any overflow in calculating offset_factor won't change the alignment. */ unsigned offset_factor - = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1) + = ((unsigned) tree_to_hwi (TREE_OPERAND (offset, 1)) * BITS_PER_UNIT); if (offset_factor) @@ -515,7 +516,7 @@ get_pointer_alignment_1 (tree exp, unsigned int *alignp, else if (TREE_CODE (exp) == INTEGER_CST) { *alignp = BIGGEST_ALIGNMENT; - *bitposp = ((TREE_INT_CST_LOW (exp) * BITS_PER_UNIT) + *bitposp = ((tree_to_hwi (exp) * BITS_PER_UNIT) (BIGGEST_ALIGNMENT - 1)); return true; } @@ -624,10 +625,10 @@ c_strlen (tree src, int only_value) a null character if we can represent it as a single HOST_WIDE_INT. */ if (offset_node == 0) offset = 0; - else if (! host_integerp (offset_node, 0)) + else if (!tree_fits_shwi_p (offset_node)) offset = -1; else -offset = tree_low_cst (offset_node, 0); +offset = tree_to_hwi (offset_node); /* If the offset is known to be out of bounds, warn, and call strlen at runtime. */ @@ -665,11 +666,11 @@ c_getstr (tree src) if (offset_node == 0) return TREE_STRING_POINTER (src); - else if (!host_integerp (offset_node, 1) + else if (!tree_fits_uhwi_p (offset_node) || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) 0) return 0; - return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1); + return TREE_STRING_POINTER (src) + tree_to_uhwi (offset_node); } /* Return a constant integer corresponding to target reading @@ -723,7 +724,9 @@ target_char_cast (tree cst, char *p) || CHAR_TYPE_SIZE HOST_BITS_PER_WIDE_INT) return 1; - val = TREE_INT_CST_LOW (cst); + /* Do not care if it fits or not right here. */ + val = tree_to_hwi (cst); + if (CHAR_TYPE_SIZE HOST_BITS_PER_WIDE_INT) val = (((unsigned HOST_WIDE_INT) 1) CHAR_TYPE_SIZE) - 1; @@ -3168,7 +3171,7 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len, return
Re: patch to fix constant math -5th patch, rtl
Richard Biener richard.guent...@gmail.com writes: I suppose the above should use immed_double_int_const (v, mode), too, In practice it doesn't matter, because... which oddly only ever truncates to mode for modes = HOST_BITS_PER_WIDE_INT via gen_int_mode. ...right. That's because there's not really any proper support for non-power-of-2 modes. Partial modes like PDI are specified by things like: PARTIAL_INT_MODE (DI); which is glaringly absent of any bit width. So if the constant is big enough to need 2 HWIs, it in practice must be exactly 2 HWIs wide. One of the advantages of wide_int is that it allows us to relax this restriction: we can have both (a) mode widths greater than HOST_BITS_PER_WIDE_INT*2 and (b) mode widths that are greater than HOST_BITS_PER_WIDE_INT while not being a multiple of it. In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Richard
Re: patch to fix constant math -5th patch, rtl
On 04/24/2013 09:36 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. Yes, that's what I understand. But consider you get a CONST_INT that is _not_ a valid QImode value. Current code simply trusts that it is, given the context from ... And the fact that it we have to trust but cannot verify is a severe problem at the rtl level that is not going to go away.what i have been strongly objecting to is your idea that just because we cannot verify it, we can thus go change it in some completely different way (i.e. the infinite precision nonsense that you keep hitting us with) and it will all be ok. I have three problems with this. 1) Even if we could do this, it gives us answers that are not what the programmer expects!! Understand this!!! Programmers expect the code to behave the same way if they optimize it or not. If you do infinite precision arithmetic you get different answers than the machine may give you. While the C and C++ standards allow this, it is NOT desirable. While there are some optimizations that must make visible changes to be effective, this is certainly not the case with infinite precision mathMaking the change to infinite precision math only because you think is pretty is NOT best practices and will only give GCC a bad reputation in the community. Each programming language defines what it means to do constant arithmetic and by and large, our front ends do this the way they say. But once you go beyond that, you are squarely in the realm where an optimizer is expected to try to make the program run fast without changing the results. Infinite precision math in the optimizations is visible in that A * B / C may get different answers between an infinite precision evaluation and one that is finite precision as specified by the types. And all of this without any possible upside to the programmer. Why would we want to drive people to use llvm? This is my primary objection.If you ever gave any reason for infinite precision aside from that you consider it pretty, then i would consider it.BUT THIS IS NOT WHAT PROGRAMMERS WANT 2) The rtl level of GCC does not follow best practices by today's standards.It is quite fragile. At this point, the best that can be said is that it generally seems to work. What you are asking is for us to make the assumption that the code is in fact in better shape than it is.I understand that in your mind, you are objecting to letting the back ends hold back something that you believe the middle ends should do, but the truth is that this is a bad idea for the middle ends. 3) If i am on a 32 bit machine and i say GEN_INT (0x), i get a 32 bit word with 32 1s in it. There is no other information. In particular there is no information that tells me was that a -1 or was that the largest positive integer. We do not have GEN_INTS and a GEN_INTU, we just have GEN_INT. Your desire is that we can take those 32 bits and apply the lt_p function, not the ltu_p or lts_p function, but an lu_p function and use that to compare those 32 bits to something. At the rtl level there is simply not enough information there to sign extend this value. This will never work without a major rewrite of the back ends.
Re: patch to fix constant math -5th patch, rtl
On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: I suppose the above should use immed_double_int_const (v, mode), too, In practice it doesn't matter, because... which oddly only ever truncates to mode for modes = HOST_BITS_PER_WIDE_INT via gen_int_mode. ...right. That's because there's not really any proper support for non-power-of-2 modes. Partial modes like PDI are specified by things like: PARTIAL_INT_MODE (DI); which is glaringly absent of any bit width. So if the constant is big enough to need 2 HWIs, it in practice must be exactly 2 HWIs wide. Ah, of course. One of the advantages of wide_int is that it allows us to relax this restriction: we can have both (a) mode widths greater than HOST_BITS_PER_WIDE_INT*2 and (b) mode widths that are greater than HOST_BITS_PER_WIDE_INT while not being a multiple of it. In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). Richard. Richard
Re: patch to fix constant math -5th patch, rtl
On 04/24/2013 10:42 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: I suppose the above should use immed_double_int_const (v, mode), too, In practice it doesn't matter, because... which oddly only ever truncates to mode for modes = HOST_BITS_PER_WIDE_INT via gen_int_mode. ...right. That's because there's not really any proper support for non-power-of-2 modes. Partial modes like PDI are specified by things like: PARTIAL_INT_MODE (DI); which is glaringly absent of any bit width. So if the constant is big enough to need 2 HWIs, it in practice must be exactly 2 HWIs wide. Ah, of course. One of the advantages of wide_int is that it allows us to relax this restriction: we can have both (a) mode widths greater than HOST_BITS_PER_WIDE_INT*2 and (b) mode widths that are greater than HOST_BITS_PER_WIDE_INT while not being a multiple of it. In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). Richard. yes but you still have the problem with partial ints having no length.Our plan was to be very careful and make sure that at no point were we doing anything that makes it harder to put modes in const_ints, but that is different from going thru everything and doing it. Partially because of this discussion and some issues that you brought up with patch 4, i am removing the trick of being able to say 'wi + rtl' because there is no mode for the rtl. i am leaving the 'wi + tree' because there is enough to info in the treecst to make this work. but you are going to have to say something wi::add (mode, rtl) see, i am willing to do things that work better in the tree world than in the rtl world. kenny Richard
Re: patch to fix constant math -5th patch, rtl
Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. If your point is that an arbitrary-precision wide_int could be used by other (non-rtl, and probably non-tree) clients, then I don't really see the need. We already have mpz_t for that. What we don't have, and what we IMO need, is something that performs N-bit arithmetic for runtime N. It seems better to have a single class that does that for us (wide_int), rather than scatter N-bit emulation throughout the codebase, which is what we do now. Richard
Re: patch to fix constant math -5th patch, rtl
On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 09:36 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. Yes, that's what I understand. But consider you get a CONST_INT that is _not_ a valid QImode value. Current code simply trusts that it is, given the context from ... And the fact that it we have to trust but cannot verify is a severe problem at the rtl level that is not going to go away.what i have been strongly objecting to is your idea that just because we cannot verify it, we can thus go change it in some completely different way (i.e. the infinite precision nonsense that you keep hitting us with) and it will all be ok. Appearantly it is all ok because that's exactly what we have today (and had for the last 25 years). CONST_INT encodes infinite precision signed values (with the complication that a QImode 0x80 isn't valid, thus all modes are signed as well it seems). CONST_DOUBLE encodes infinite precision signed values as well. Just the infinite is limited by the size of the encoding, one and two HOST_WIDE_INTs. The interpretation of those infinite precision constants is based on the context (the operation mode of the operation we apply to a CONST_INT or CONST_DOUBLE). Thus CONST_INT and CONST_DOUBLE do not have a mode or precision but VOIDmode so different mode 1 can be shared (which is probably the original reason of that design decision). I have three problems with this. 1) Even if we could do this, it gives us answers that are not what the programmer expects!! Understand this!!! Programmers expect the code to behave the same way if they optimize it or not. If you do infinite precision arithmetic you get different answers than the machine may give you. While the C and C++ standards allow this, it is NOT desirable. While there are some optimizations that must make visible changes to be effective, this is certainly not the case with infinite precision mathMaking the change to infinite precision math only because you think is pretty is NOT best practices and will only give GCC a bad reputation in the community. Note that as I tried to explain above this isn't a change. _You_ are proposing a change here! Namely to associate a precision with a _constant_. What precision does a '1' have? What precision does a '12374' have? It doesn't have any. With this proposed change we will have the possibility to explicitely program mismatches like simplify_binary_operation (PLUS_EXPR, HImode, wide_int_rtx (SImode, 27), wide_int_rtx (QImode, 1)) even if _only_ the desired mode of the result matters! Because given the invariant that a wide-int is valid (it doesn't have bits outside of its precision) it's precision does no longer matter! Each programming language defines what it means to do constant arithmetic and by and large, our front ends do this the way they say. But once you go beyond that, you are squarely in the realm where an optimizer is expected to try to make the program run fast without changing the results. Infinite precision math in the optimizations is visible in that A * B / C may get different answers between an infinite precision evaluation and one that is finite precision as specified by the types. And all of this without any possible upside to the programmer. Why would we want to drive people to use llvm? This is my primary objection.If you ever gave any reason for infinite precision aside from that you consider it pretty, then i would consider it.BUT THIS IS NOT WHAT PROGRAMMERS WANT Programming languages or prettiness is not in any way a reason to do infinite precision math. All-caps or pretty punctuation does not change that. Infinite precision math is what we do now. What I ask for is to make separate changes separately. You want larger and host independent integer constants. Fine - do that. You want to change how we do arithmetic? Fine - do that. But please separate the two. (well, I'm likely still going to object to the latter) 2) The rtl level of GCC does not follow best practices by today's standards. It is quite fragile. It works quite well. At this point, the best that can be said is that it generally seems to work. What you are asking is for us to make the assumption that the code is in fact in better shape than it is.I understand
Re: patch to fix constant math -5th patch, rtl
On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. Associating one with it to give a precision to an arithmetic operation looks wrong to me and are a source of mismatches. What RTL currently has looks better to me - operations have explicitely specified precisions. If your point is that an arbitrary-precision wide_int could be used by other (non-rtl, and probably non-tree) clients, then I don't really see the need. We already have mpz_t for that. What we don't have, and what we IMO need, is something that performs N-bit arithmetic for runtime N. It seems better to have a single class that does that for us (wide_int), rather than scatter N-bit emulation throughout the codebase, which is what we do now. mpz_t is not suitable here - it's way too expensive. double-int was the suitable bit for now, but given it's host dependency and inability to handle larger ints (VRP ...) the ability to use wide-ints for this looks appealing. Richard. Richard
Re: patch to fix constant math -5th patch, rtl
Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/24/2013 09:36 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. Yes, that's what I understand. But consider you get a CONST_INT that is _not_ a valid QImode value. Current code simply trusts that it is, given the context from ... And the fact that it we have to trust but cannot verify is a severe problem at the rtl level that is not going to go away.what i have been strongly objecting to is your idea that just because we cannot verify it, we can thus go change it in some completely different way (i.e. the infinite precision nonsense that you keep hitting us with) and it will all be ok. Appearantly it is all ok because that's exactly what we have today (and had for the last 25 years). CONST_INT encodes infinite precision signed values (with the complication that a QImode 0x80 isn't valid, thus all modes are signed as well it seems). I think this is the fundamental disagreement. Your last step doesn't follow. RTL integer modes are neither signed nor unsigned. They are just a collection of N bits. The fact that CONST_INTs represent smaller-than-HWI integers in sign-extended form is purely a represential detail. There are no semantics attached to it. We could just as easily have decided to extend with zeros or ones instead of sign bits. Although the decision was made before my time, I'm pretty sure the point of having a canonical representation (which happened to be sign extension) was to make sure that any given rtl constant has only a single representation. It would be too confusing if a QImode 0x80 could be represented as either (const_int 128) or (const_int -128) (would (const_int 384) then also be OK?). And that's the problem with using an infinite-precision wide_int. If you directly convert a CONST_INT representation of 0x80 into a wide_int, you will always get infinite-precision -128, thanks to the CONST_INT canonicalisation rule. But if you arrive at 0x80 though arithmetic, you might get infinite-precision 128 instead. These two values would not compare equal. CONST_DOUBLE encodes infinite precision signed values as well. Just the infinite is limited by the size of the encoding, one and two HOST_WIDE_INTs. It encodes an N-bit integer. It's just that (assuming non-power-of-2 modes) several N-bit integers (with varying N) can be encoded using the same CONST_DOUBLE representation. That might be what you meant, sorry, and so might seem pedantic, but I wasn't sure. Richard
Re: patch to fix constant math -5th patch, rtl
Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. I disagree. All rtl objects have a precision. REGs, MEMs, SYMBOL_REFs, LABEL_REFs and CONSTs all have precisions, and the last three are run-time constants. Why should CONST_INT and CONST_DOUBLE be different? See e.g. the hoops that cselib has to jump through: /* We need to pass down the mode of constants through the hash table functions. For that purpose, wrap them in a CONST of the appropriate mode. */ static rtx wrap_constant (enum machine_mode mode, rtx x) { if ((!CONST_SCALAR_INT_P (x)) GET_CODE (x) != CONST_FIXED) return x; gcc_assert (mode != VOIDmode); return gen_rtx_CONST (mode, x); } That is, cselib locally converts (const_int X) into (const:M (const_int X)), purely so that it doesn't lose track of the CONST_INT's mode. (const:M (const_int ...)) is invalid rtl elsewhere, but a necessary hack here all the same. What RTL currently has looks better to me - operations have explicitely specified precisions. But that isn't enough to determine the precision of all operands. A classic case is ZERO_EXTEND. Something like: (zero_extend:DI (reg:SI X)) is unambiguous. But if you substitute (reg:SI X) with a CONST_INT, the result becomes ambiguous. E.g. we could end up with: (zero_extend:DI (const_int -1)) The ZERO_EXTEND operand still has SImode, but that fact is not explicit in the rtl, and is certainly not explicit in the ZERO_EXTEND operation. So if we just see the result above, we no longer know whether the result should be (const_int 0xff), (const_int 0x), or what. The same goes for: (zero_extend:DI (const_int 256)) where (const_int 0) and (const_int 256) are both potential results. It's not just ZERO_EXTEND. E.g.: (zero_extract:SI ...) tells you that an SImode value is being extracted, but it doesn't tell you what precision you're extracting from. So for: (zero_extract:SI (const_int -1) (const_int X) (const_int 3)) how many 1 bits should be the result have? Because of the sign-extension canonicalisation, the answer depends on the precision of the (const_int -1), which has now been lost. If instead CONST_INTs were stored in zero-extended form, the same ambiguity would apply to SIGN_EXTRACT. This sort of thing has been a constant headache in rtl. I can't stress how much I feel it is _not_ better than recording the precision of the constant :-) Richard
Re: patch to fix constant math -5th patch, rtl
On 04/24/2013 11:13 AM, Richard Biener wrote: On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Bienerrichard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford rdsandif...@googlemail.com wrote: In other words, one of the reasons wide_int can't be exactly 1:1 in practice is because it is clearing out these mistakes (GEN_INT rather than gen_int_mode) and missing features (non-power-of-2 widths). Note that the argument should be about CONST_WIDE_INT here, not wide-int. Indeed CONST_WIDE_INT has the desired feature and can be properly truncated/extended according to mode at the time we build it via immed_wide_int_cst (w, mode). I don't see the requirement that wide-int itself is automagically providing that truncation/extension (though it is a possibility, one that does not match existing behavior of HWI for CONST_INT or double-int for CONST_DOUBLE). I agree it doesn't match the existing behaviour of HWI for CONST_INT or double-int for CONST_DOUBLE, but I think that's very much a good thing. The model for HWIs at the moment is that you have to truncate results to the canonical form after every operation where it matters. As you proved in your earlier message about the plus_constant bug, that's easily forgotten. I don't think the rtl code is doing all CONST_INT arithmetic on full HWIs because it wants to: it's doing it because that's the way C/C++ arithmetic on primitive types works. In other words, the current CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N) using a single primitive integer type. wide_int gives us N-bit arithmetic directly; no emulation is needed. Ok, so what wide-int provides is integer values encoded in 'len' HWI words that fit in 'precision' or more bits (and often in less). wide-int also provides N-bit arithmetic operations. IMHO both are tied too closely together. A give constant doesn't really have a precision. Associating one with it to give a precision to an arithmetic operation looks wrong to me and are a source of mismatches. What RTL currently has looks better to me - operations have explicitely specified precisions. I have tried very hard to make wide-int work very efficiently with both tree and rtl without biasing the rep towards either representation. Both rtl and trees constants have a precision. In tree, constants are done better than in rtl because the tree really does have a field that is filled in that points to a type. However, that does not mean that rtl constants do not have a precision: currently you have to look around at the context to find the mode of a constant that is in your hand, but it is in fact always there. At the rtl level, you can see the entire patch - we always find an appropriate mode. In the future, this may change. Wide-int moves one step closer in that ports that support it will not expect that double-ints never have a mode. But that is a long way from having the mode attached. What is not stored with the constant is a indication of the signedness. Unlike a desire to add modes to rtl constants, there is no one even thinking about the sign. The sign is implicit in the operator, just as it is at the tree level. So when i designed wide-int, i assumed that i could get precisions from the variables or at least close to them. As far as the question of infinite precision, 99% of the uses of double-int today are get in, do a single operation and get out. If this is all that we plan to do, then it does not really matter if it is infinite precision or not, because at both the rtl and tree level, we truncate on the way out. However, the use of double-int accounts for only a small percentage of the math done in the compiler. My wide-int port converts a substantial portion of the math from inline code that is guarded by checks to the precision against HOST_WIDE_BITS_PER_INT or calls to host_integerp. The conversion of this code has substantial potential to expose the differences between the fixed precision and infinite precision representations. The only justification that you have ever given for wanting to use infinite precision is that it is cleaner. You have never directly addressed my point that it gives surprising answers except to say that the user would have to put in explicit intermediate truncations.It is hard for me to imaging buggering up something as bad as having to put in explicit intermediate truncations. When i write a * b / c, it should really look something like the expression. If your point is that an arbitrary-precision wide_int could be used by other (non-rtl, and probably non-tree) clients, then I don't really see the need. We already have mpz_t for that. What we don't have, and what we IMO need, is something that performs N-bit arithmetic for runtime N. It seems better to have a single class that does that for us (wide_int), rather than scatter N-bit
Re: patch to fix constant math -5th patch, rtl
On Tue, Apr 16, 2013 at 10:17 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is a refreshed version of the rtl changes for wide-int. the only change from the previous versions is that the wide-int binary operations have been simplified to use the new wide-int binary templates. Looking for from_rtx calls (to see where we get the mode/precision from) I see for example - o = rtx_to_double_int (outer); - i = rtx_to_double_int (inner); - - m = double_int::mask (width); - i = m; - m = m.llshift (offset, HOST_BITS_PER_DOUBLE_INT); - i = i.llshift (offset, HOST_BITS_PER_DOUBLE_INT); - o = o.and_not (m) | i; - + + o = (wide_int::from_rtx (outer, GET_MODE (SET_DEST (temp))) + .insert (wide_int::from_rtx (inner, GET_MODE (dest)), + offset, width)); where I'd rather have the original code preserved as much as possible and not introduce a new primitive wide_int::insert for this. The conversion and review process will be much more error-prone if we do multiple things at once (and it might keep the wide_int initial interface leaner). Btw, the wide_int::insert implementation doesn't assert anything about the inputs precision. Instead it reads + if (start + width = precision) +width = precision - start; + + mask = shifted_mask (start, width, false, precision); + tmp = op0.lshift (start, 0, precision, NONE); + result = tmp mask; + + tmp = and_not (mask); + result = result | tmp; which eventually ends up performing everything in target precision. So we don't really care about the mode or precision of inner. Then I see diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h index ad03a34..531a7c1 100644 @@ -180,6 +182,7 @@ typedef struct GTY(()) dw_val_struct { HOST_WIDE_INT GTY ((default)) val_int; unsigned HOST_WIDE_INT GTY ((tag (dw_val_class_unsigned_const))) val_unsigned; double_int GTY ((tag (dw_val_class_const_double))) val_double; + wide_int GTY ((tag (dw_val_class_wide_int))) val_wide; dw_vec_const GTY ((tag (dw_val_class_vec))) val_vec; struct dw_val_die_union { ick. That makes dw_val_struct really large ... (and thus dw_attr_struct). You need to make this a pointer to a wide_int at least. -/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading +/* Return a constant integer corresponding to target reading GET_MODE_BITSIZE (MODE) bits from string constant STR. */ static rtx c_readstr (const char *str, enum machine_mode mode) { - HOST_WIDE_INT c[2]; + wide_int c; ... - return immed_double_const (c[0], c[1], mode); + + c = wide_int::from_array (tmp, len, mode); + return immed_wide_int_const (c, mode); } err - what's this good for? It doesn't look necessary as part of the initial wide-int conversion at least. (please audit your patches for such cases) @@ -4994,12 +4999,12 @@ expand_builtin_signbit (tree exp, rtx target) if (bitpos GET_MODE_BITSIZE (rmode)) { - double_int mask = double_int_zero.set_bit (bitpos); + wide_int mask = wide_int::set_bit_in_zero (bitpos, rmode); if (GET_MODE_SIZE (imode) GET_MODE_SIZE (rmode)) temp = gen_lowpart (rmode, temp); temp = expand_binop (rmode, and_optab, temp, - immed_double_int_const (mask, rmode), + immed_wide_int_const (mask, rmode), NULL_RTX, 1, OPTAB_LIB_WIDEN); } else Likewise. I suppose you remove immed_double_int_const but I see no reason to do that. It just makes your patch larger than necessary. [what was the reason again to have TARGET_SUPPORTS_WIDE_INT at all? It's supposed to be a no-op conversion, right?] @@ -95,38 +95,9 @@ plus_constant (enum machine_mode mode, rtx x, HOST_WIDE_INT c) switch (code) { -case CONST_INT: - if (GET_MODE_BITSIZE (mode) HOST_BITS_PER_WIDE_INT) - { - double_int di_x = double_int::from_shwi (INTVAL (x)); - double_int di_c = double_int::from_shwi (c); - - bool overflow; - double_int v = di_x.add_with_sign (di_c, false, overflow); - if (overflow) - gcc_unreachable (); - - return immed_double_int_const (v, VOIDmode); - } - - return GEN_INT (INTVAL (x) + c); - -case CONST_DOUBLE: - { - double_int di_x = double_int::from_pair (CONST_DOUBLE_HIGH (x), -CONST_DOUBLE_LOW (x)); - double_int di_c = double_int::from_shwi (c); - - bool overflow; - double_int v = di_x.add_with_sign (di_c, false, overflow); - if (overflow) - /* Sorry, we have no way to represent overflows this wide. -To fix, add constant support wider than CONST_DOUBLE. */ - gcc_assert (GET_MODE_BITSIZE (mode) = HOST_BITS_PER_DOUBLE_INT); - - return immed_double_int_const (v, VOIDmode); - } - +CASE_CONST_SCALAR_INT: + return
Re: patch to fix constant math -5th patch, rtl
Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. What does wide-int do with VOIDmode mode inputs? It seems to ICE on them for from_rtx and use garbage (0) for from_shwi. Ugh. ICEing is right. As mentioned before, every rtx constant has a mode, whether it's stored in the rtx or not. Callers must keep track of what that mode is. Btw, plus_constant asserts that mode is either VOIDmode (I suppose semantically do arbitrary precision) No, not arbitrary precision. It's always the precision specified by the mode parameter. The assert is: gcc_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode); This is because GET_MODE always returns VOIDmode for CONST_INT and CONST_DOUBLE integers. The mode parameter is needed to tell us what precision those CONST_INTs and CONST_DOUBLEs actually have, because the rtx itself doesn't tell us. The mode parameter serves no purpose beyond that. So if the rtx does specify a mode (everything except CONST_INT and CONST_DOUBLE), the assert is making sure that the caller has correctly tracked the rtx's mode and provided the right mode parameter. The caller must do that for all rtxes, it's just that we can't assert for it in the CONST_INT and CONST_DOUBLE case, because the rtx has no mode to check against. If CONST_INT and CONST_DOUBLE did have a mode to check against, there would be no need for the mode parameter at all. Likewise there would be no need for wide_int::from_rtx to have a mode parameter. Richard
Re: patch to fix constant math -5th patch, rtl
On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. Yes, that's what I understand. But consider you get a CONST_INT that is _not_ a valid QImode value. Current code simply trusts that it is, given the context from ... What does wide-int do with VOIDmode mode inputs? It seems to ICE on them for from_rtx and use garbage (0) for from_shwi. Ugh. ICEing is right. As mentioned before, every rtx constant has a mode, whether it's stored in the rtx or not. Callers must keep track of what that mode is. ... here. So I see that both CONST_INT and CONST_DOUBLE get their mode (or in wide-int speak precision) from the context. Effectively a CONST_INT and CONST_DOUBLE is valid in multiple modes and thus arbitrary precision with a limit set by the limit of the encoding. Btw, plus_constant asserts that mode is either VOIDmode (I suppose semantically do arbitrary precision) No, not arbitrary precision. It's always the precision specified by the mode parameter. The assert is: gcc_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode); This is because GET_MODE always returns VOIDmode for CONST_INT and CONST_DOUBLE integers. The mode parameter is needed to tell us what precision those CONST_INTs and CONST_DOUBLEs actually have, because the rtx itself doesn't tell us. The mode parameter serves no purpose beyond that. That doesn't make sense. The only thing we could then do with the mode is assert that the CONST_INT/CONST_DOUBLE is valid for mode. mode does not constrain the result in any way, thus it happily produces a CONST_INT (128) from QImode CONST_INT (127) + 1. So, does the caller of plus_constant have to verify the result is actually valid in the mode it expects? And what should it do if the result is not valid? Given that we do not verify the input values and do not care for mode for producing the output value the current behavior of plus_constant is to compute in arbitrary precision. wide-int changes the above to produce a different result (CONST_INT (-128)). I'd rather not have this patch-set introduce such subtle differences. I'd like to see the following: 1) strip away 'precision' from wide-int, make the sign/zero-extend operations that are now implicitely done explicit in the same way as done currently, thus, ... 2) do a more-or-less 1:1 conversion of existing double-int code. double-int code already has all sign/zero-extensions that are required for correctness. and after merging in wide-int 3) see what common code can be factored out (wide_int::insert and friends) 4) if seems fit, introduce a wide_int_with_precision class that provides a wrapper around wide_int and carries out operations in a fixed precision, doing sign-/zero-extends after each operation (I suppose not much code will be simplified by that) before merging converting all targets is necessary - this isn't a part of the infrastructure that can stand a partial conversion. I suspect that conversion of all targets is much easier after 2), especially if most of the double-int interfaces are not removed but their implementation changed to work on wide-ints (just as I mentioned for the immed_double_int_const case, but likely not restricted to that - CONST_DOUBLE_LOW/HIGH can be converted to code that asserts the encoding is sufficiently small for example). Thus, 5) piecewise remove legacy code dealing with CONST_DOUBLE Btw, on 64bit hosts the rtx_def struct has 32bits padding before the rtunion. I think 32bit hosts are legacy now, so using that 32bits padding by storing 'len' there will make space-efficient conversion of CONST_INT possible. Well, and avoids wasting another 32bits of padding for CONST_WIDE on 64bit hosts. So if the rtx does specify a mode (everything except CONST_INT and CONST_DOUBLE), the assert is making sure that the caller has correctly tracked the rtx's mode and provided the right mode parameter. The caller must do that for all rtxes, it's just that we can't assert for it in the CONST_INT and CONST_DOUBLE case, because the rtx has no mode to check against. If CONST_INT and CONST_DOUBLE did have a mode to check against, there would be no need for the mode parameter at all. Likewise there would be no need for wide_int::from_rtx to have a mode parameter. constants do not have an intrinsic mode or precision. They either do or do not fit into a specific mode or precision. If an operation is to be carried out in a specific mode
Re: patch to fix constant math -5th patch, rtl
Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. Yes, that's what I understand. But consider you get a CONST_INT that is _not_ a valid QImode value. But that's invalid :-) It is not valid to call: plus_constant (QImode, GEN_INT (128), 1) The point is that, even though it's invalid, we can't assert for it. plus_constant is not for arbitrary precision arithmetic. It's for arithmetic in a given non-VOIDmode mode. Effectively a CONST_INT and CONST_DOUBLE is valid in multiple modes and thus arbitrary precision with a limit set by the limit of the encoding. The same CONST_INT and CONST_DOUBLE can be shared for several constants in different modes, yes, which is presumably what motivated making them VOIDmode in the first place. E.g. zero is const0_rtx for every integer mode. But in any given context, including plus_constant, the CONST_INT or CONST_DOUBLE has a specific mode. Btw, plus_constant asserts that mode is either VOIDmode (I suppose semantically do arbitrary precision) No, not arbitrary precision. It's always the precision specified by the mode parameter. The assert is: gcc_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode); This is because GET_MODE always returns VOIDmode for CONST_INT and CONST_DOUBLE integers. The mode parameter is needed to tell us what precision those CONST_INTs and CONST_DOUBLEs actually have, because the rtx itself doesn't tell us. The mode parameter serves no purpose beyond that. That doesn't make sense. The only thing we could then do with the mode is assert that the CONST_INT/CONST_DOUBLE is valid for mode. No, we have to generate a correct CONST_INT or CONST_DOUBLE result. If we are adding 1 to a QImode (const_int 127), we must return (const_int -128). If we are adding 1 to HImode (const_int 127), we must return (const_int 128). However... mode does not constrain the result in any way, thus it happily produces a CONST_INT (128) from QImode CONST_INT (127) + 1. So, does the caller of plus_constant have to verify the result is actually valid in the mode it expects? And what should it do if the result is not valid? ...good spot. That's a bug. It should be: return gen_int_mode (INTVAL (x) + c, mode); rather than: return GEN_INT (INTVAL (x) + c); It's a long-standing bug, because in the old days we didn't have the mode to hand. It was missed when the mode was added. But the mode is also used in: if (GET_MODE_BITSIZE (mode) HOST_BITS_PER_WIDE_INT) { double_int di_x = double_int::from_shwi (INTVAL (x)); double_int di_c = double_int::from_shwi (c); bool overflow; double_int v = di_x.add_with_sign (di_c, false, overflow); if (overflow) gcc_unreachable (); return immed_double_int_const (v, VOIDmode); } which is deciding whether the result should be kept as a HWI even in cases where the addition overflows. It isn't arbitrary precision. Richard
Re: patch to fix constant math -5th patch, rtl
On Wed, Apr 24, 2013 at 4:03 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: Can we in such cases please to a preparatory patch and change the CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to mode precision first? I'm not sure what you mean here. CONST_INT HWIs are already sign-extended from mode precision to HWI precision. The 8-bit value 0xb1000 must be represented as (const_int -128); nothing else is allowed. E.g. (const_int 128) is not a valid QImode value on BITS_PER_UNIT==8 targets. Yes, that's what I understand. But consider you get a CONST_INT that is _not_ a valid QImode value. But that's invalid :-) It is not valid to call: plus_constant (QImode, GEN_INT (128), 1) The point is that, even though it's invalid, we can't assert for it. Why can't we assert for it? plus_constant is not for arbitrary precision arithmetic. It's for arithmetic in a given non-VOIDmode mode. Effectively a CONST_INT and CONST_DOUBLE is valid in multiple modes and thus arbitrary precision with a limit set by the limit of the encoding. The same CONST_INT and CONST_DOUBLE can be shared for several constants in different modes, yes, which is presumably what motivated making them VOIDmode in the first place. E.g. zero is const0_rtx for every integer mode. But in any given context, including plus_constant, the CONST_INT or CONST_DOUBLE has a specific mode. Btw, plus_constant asserts that mode is either VOIDmode (I suppose semantically do arbitrary precision) No, not arbitrary precision. It's always the precision specified by the mode parameter. The assert is: gcc_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode); This is because GET_MODE always returns VOIDmode for CONST_INT and CONST_DOUBLE integers. The mode parameter is needed to tell us what precision those CONST_INTs and CONST_DOUBLEs actually have, because the rtx itself doesn't tell us. The mode parameter serves no purpose beyond that. That doesn't make sense. The only thing we could then do with the mode is assert that the CONST_INT/CONST_DOUBLE is valid for mode. No, we have to generate a correct CONST_INT or CONST_DOUBLE result. If we are adding 1 to a QImode (const_int 127), we must return (const_int -128). If we are adding 1 to HImode (const_int 127), we must return (const_int 128). However... mode does not constrain the result in any way, thus it happily produces a CONST_INT (128) from QImode CONST_INT (127) + 1. So, does the caller of plus_constant have to verify the result is actually valid in the mode it expects? And what should it do if the result is not valid? ...good spot. That's a bug. It should be: return gen_int_mode (INTVAL (x) + c, mode); rather than: return GEN_INT (INTVAL (x) + c); It's a long-standing bug, because in the old days we didn't have the mode to hand. It was missed when the mode was added. But the mode is also used in: if (GET_MODE_BITSIZE (mode) HOST_BITS_PER_WIDE_INT) { double_int di_x = double_int::from_shwi (INTVAL (x)); double_int di_c = double_int::from_shwi (c); bool overflow; double_int v = di_x.add_with_sign (di_c, false, overflow); if (overflow) gcc_unreachable (); return immed_double_int_const (v, VOIDmode); } which is deciding whether the result should be kept as a HWI even in cases where the addition overflows. It isn't arbitrary precision. The above is wrong for SImode HOST_WIDE_INT and 0x7fff + 1 in the same way as the QImode case above. It will produce 0x8000. The ICEing on overflow is odd as well as I'd have expected twos-complement behavior which double-int, when overflowing its 2 * HWI precision, provides. I suppose the above should use immed_double_int_const (v, mode), too, which oddly only ever truncates to mode for modes = HOST_BITS_PER_WIDE_INT via gen_int_mode. Same of course for the code for CONST_DOUBLE. Richard. Richard
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On Sun, Apr 21, 2013 at 10:54 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Richard, i pulled these two frags out of your comments because i wanted to get some input from you on it while i addressed the other issues you raised. + enum SignOp { +/* Many of the math functions produce different results depending + on if they are SIGNED or UNSIGNED. In general, there are two + different functions, whose names are prefixed with an 'S and + or an 'U'. However, for some math functions there is also a + routine that does not have the prefix and takes an SignOp + parameter of SIGNED or UNSIGNED. */ +SIGNED, +UNSIGNED + }; You seem to insist on that. It should propagate to the various parts of the compiler that have settled for the 'uns' integer argument. Having one piece behave different is just weird. I suppose I will find code like wi.ext (prec, uns ? UNSIGNED : SIGNED) there is a lot more flexibility on my part than you perceive with respect to this point. My primary issue is that i do not want to have is an interface that has 0 and 1 as a programmer visible part. Beyond that i am open to suggestion. The poster child of my hate are the host_integer_p and the tree_low_cst interfaces. I did not want the wide int stuff to look like these. I see several problems with these: 1) of the 314 places where tree_low_cst is called in the gcc directory (not the subdirectories where the front ends live), NONE of the calls have a variable second parameter. There are a handful of places, as one expects, in the front ends that do, but NONE in the middle end. 2) there are a small number of the places where host_integer_p is called with one parameter and then it is followed by a call to tree_low_cst that has the value with the other sex. I am sure these are mistakes, but having the 0s and 1s flying around does not make it easy to spot them. 3) tree_low_cst implies that the tree cst has only two hwis in it. While i do not want to propagate an interface with 0 and 1 into wide-int, i can understand your dislike of having a wide-int only solution for this. I will point out that for your particular example, uns is almost always set by a call to TYPE_UNSIGNED. There could easily be a different type accessor that converts this part of the type to the right thing to pass in here. I think that there is certainly some place for there to be a unified SYMBOLIC api that controls the signedness everywhere in the compiler. I would like to move toward this direction, but you have been so negative to the places where i have made it convenient to directly convert from tree or rtl into or out of wide-int that i have hesitated to do something that directly links trees and wide-int. So i would like to ask you what would like? Ideally I'd like the wide-int introduction to _not_ be the introduction of a unified symbolic way that controls signedness. We do have two kinds of interfaces currently - one that uses different API entries, like build_int_cstu vs. build_int_cst or double_int::from_shwi vs. from_uhwi, and one that uses the aforementioned integer flag 'uns' with 0 being signed and 1 being unsigned. I think the _uhwi vs. _shwi and _cstu variants are perfectly fine (but only for compile-time constant uses as you say), and the wide-int interface makes use of this kind, too. Proposing a better API for the 'uns' flag separately from wide-int would be a better way to get anybody else than me chime in (I have the feeling that the wide-int series seems to scare off every other reviewer besides me...). I can live with the SIGNED/UNSIGNED enum, but existing APIs should be changed to use that. For wide-int I suggest to go the route you don't want to go. Stick to existing practice and use the integer 'uns' flag. It's as good as SIGNED/UNSIGNED for _variable_ cases (and yes, a lot less descriptive for constant cases). For wide-int, always add a static interface if there is a variable one and convert variable uses to the proper static interface. That said, a lot of my pushback is because I feel a little lonesome in this wide-int review and don't want to lone-some decide about that (generic) interface part as well. + template typename T +inline bool gt_p (T c, SignOp sgn) const; + template typename T +inline bool gts_p (T c) const; + template typename T +inline bool gtu_p (T c) const; it's bad that we can't use the sign information we have available in almost all cases ... (where precision is not an exact multiple of HOST_BITS_PER_WIDE_INT and len == precision / HOST_BITS_PER_WIDE_INT). It isn't hard to encode a sign - you just have to possibly waste a word of zeroes for positive values where at the moment precision is an exact multiple of HOST_BIST_PER_WIDE_INT and len == precision / HOST_BITS_PER_WIDE_INT. Which of course means that the encoding can be one word larger than maximally
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On 04/19/2013 09:31 AM, Richard Biener wrote: + number of elements of the vector that are in use. When LEN * + HOST_BITS_PER_WIDE_INT the precision, the value has been + compressed. The values of the elements of the vector greater than + LEN - 1. are all equal to the highest order bit of LEN. equal to the highest order bit of element LEN - 1. ? Fixed, you are correct. I have gone thru the entire wide-int patch to clean this up. The bottom line is that if the precision is not a multiple of the size of a HWI then everything above that precision is assumed to be identical to the sign bit. Especially _not_ equal to the precision - 1 bit of the value, correct? I do not understand your question here, because in the case talked about above, the bit at precision - 1 would not have been explicitly represented. Anyway, i went thru this top part carefully and made many things clearer. + The representation does not contain any information inherant about + signedness of the represented value, so it can be used to represent + both signed and unsigned numbers. For operations where the results + depend on signedness (division, comparisons), the signedness must + be specified separately. For operations where the signness + matters, one of the operands to the operation specifies either + wide_int::SIGNED or wide_int::UNSIGNED. The last sentence is somehow duplicated. fixed + The numbers are stored as sign entended numbers as a means of + compression. Leading HOST_WIDE_INTS that contain strings of either + -1 or 0 are removed as long as they can be reconstructed from the + top bit that is being represented. I'd put this paragraph before the one that talks about signedness, next to the one that already talks about encoding. done + All constructors for wide_int take either a precision, an enum + machine_mode or tree_type. */ That's probably no longer true (I'll now check). yes you are correct +class wide_int { + /* Internal representation. */ + + /* VAL is set to a size that is capable of computing a full + multiplication on the largest mode that is represented on the + target. The full multiplication is use by tree-vrp. tree-vpn + currently does a 2x largest mode by 2x largest mode yielding a 4x + largest mode result. If operations are added that require larger + buffers, then VAL needs to be changed. */ + HOST_WIDE_INT val[WIDE_INT_MAX_ELTS]; + unsigned short len; + unsigned int precision; I wonder if there is a technical reason to stick to HOST_WIDE_INTs? I'd say for efficiency HOST_WIDEST_FAST_INT would be more appropriate (to get a 32bit value on 32bit x86 for example). I of course see that conversion to/from HOST_WIDE_INT is an important operation that would get slightly more complicated. Maybe just quickly checking the code generated on 32bit x86 for HOST_WIDE_INT vs. HOST_WIDEST_FAST_INT tells us whether it's worth considering (it would be bad if each add/multiply would end up calling to libgcc for example - I know that doesn't happen for x86, but maybe it would happen for an arm hosted gcc targeting x86_64?) This is an interesting point. my guess is that it is unlikely to be worth the work. consider add:most machines have add with carry and well written 32 bit ports would have used an add with carry sequence rather than making the libcall. If i rewrite wide-int in terms of host_fastest_int, then i have to do some messy code to compute the carry which is unlikely to translate into the proper carry instructions. Not to mention the cost overhead of converting to and from HFI given that gcc is written almost entirely using HWIs. I thought about the possible idea of just converting the mul and div functions. This would be easy because i already reblock them into HOST_WIDE_HALF_INTs to do the math.I could just do a different reblocking. However, i think that it is unlikely that doing this would ever show up on anyone's performance counts. Either way you do the same number of multiply instructions, it is just the subroutine wrapper that could possibly go away. + enum ShiftOp { +NONE, +/* There are two uses for the wide-int shifting functions. The + first use is as an emulation of the target hardware. The + second use is as service routines for other optimizations. The + first case needs to be identified by passing TRUNC as the value + of ShiftOp so that shift amount is properly handled according to the + SHIFT_COUNT_TRUNCATED flag. For the second case, the shift + amount is always truncated by the bytesize of the mode of + THIS. */ +TRUNC + }; double-int simply honors SHIFT_COUNT_TRUNCATED. Why differ from that (and thus change behavior in existing code - not sure if you do that with introducing wide-int)? I believe that GCC is supposed to be a little schizophrenic here, at least according to the doc.when it is doing
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
Richard Biener richard.guent...@gmail.com writes: At the rtl level your idea does not work. rtl constants do not have a mode or type. Which is not true and does not matter. I tell you why. Quote: It _is_ true, as long as you read rtl constants as rtl integer constants :-) +#if TARGET_SUPPORTS_WIDE_INT + +/* Match CONST_*s that can represent compile-time constant integers. */ +#define CASE_CONST_SCALAR_INT \ + case CONST_INT: \ + case CONST_WIDE_INT which means you are only replacing CONST_DOUBLE with wide-int. And _all_ CONST_DOUBLE have a mode. Otherwise you'd have no way of creating the wide-int in the first place. No, integer CONST_DOUBLEs have VOIDmode, just like CONST_INT. Only floating-point CONST_DOUBLEs have a real mode. I understand that this makes me vulnerable to the argument that we should not let the rtl level ever dictate anything about the tree level, but the truth is that a variable len rep is almost always used for big integers. In our code, most constants of large types are small numbers. (Remember i got into this because the tree constant prop thinks that left shifting any number by anything greater than 128 is always 0 and discovered that that was just the tip of the iceberg.) But mostly i support the decision to canonize numbers to the smallest number of HWIs because most of the algorithms to do the math can be short circuited.I admit that if i had to effectively unpack most numbers to do the math, that the canonization would be a waste. However, this is not really relevant to this conversation. Yes, you could get rid of the len, but this such a small part of picture. Getting rid of 'len' in the RTX storage was only a question of whether it is an efficient way to go forward. And with considering to unify CONST_INTs and CONST_WIDE_INTs it is not. And even for CONST_WIDE_INTs (which most of the time would be 2 HWI storage, as otherwise you'd use a CONST_INT) it would be an improvement. FWIW, I don't really see any advantage in unifying CONST_INT and CONST_WIDE_INT, for the reasons Kenny has already given. CONST_INT can represent a large majority of the integers and it is already a fairly efficient representation. It's more important that we don't pick a design that forces one choice or the other. And I think Kenny's patch achieves that goal, because the choice is hidden behind macros and behind the wide_int interface. Thanks, Richard
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: At the rtl level your idea does not work. rtl constants do not have a mode or type. Which is not true and does not matter. I tell you why. Quote: It _is_ true, as long as you read rtl constants as rtl integer constants :-) +#if TARGET_SUPPORTS_WIDE_INT + +/* Match CONST_*s that can represent compile-time constant integers. */ +#define CASE_CONST_SCALAR_INT \ + case CONST_INT: \ + case CONST_WIDE_INT which means you are only replacing CONST_DOUBLE with wide-int. And _all_ CONST_DOUBLE have a mode. Otherwise you'd have no way of creating the wide-int in the first place. No, integer CONST_DOUBLEs have VOIDmode, just like CONST_INT. Only floating-point CONST_DOUBLEs have a real mode. I stand corrected. Now that's one more argument for infinite precision constants, as the mode is then certainly provided by the operations similar to the sign. That is, the mode (or size, or precision) of 1 certainly does not matter. I understand that this makes me vulnerable to the argument that we should not let the rtl level ever dictate anything about the tree level, but the truth is that a variable len rep is almost always used for big integers. In our code, most constants of large types are small numbers. (Remember i got into this because the tree constant prop thinks that left shifting any number by anything greater than 128 is always 0 and discovered that that was just the tip of the iceberg.) But mostly i support the decision to canonize numbers to the smallest number of HWIs because most of the algorithms to do the math can be short circuited.I admit that if i had to effectively unpack most numbers to do the math, that the canonization would be a waste. However, this is not really relevant to this conversation. Yes, you could get rid of the len, but this such a small part of picture. Getting rid of 'len' in the RTX storage was only a question of whether it is an efficient way to go forward. And with considering to unify CONST_INTs and CONST_WIDE_INTs it is not. And even for CONST_WIDE_INTs (which most of the time would be 2 HWI storage, as otherwise you'd use a CONST_INT) it would be an improvement. FWIW, I don't really see any advantage in unifying CONST_INT and CONST_WIDE_INT, for the reasons Kenny has already given. CONST_INT can represent a large majority of the integers and it is already a fairly efficient representation. It's more important that we don't pick a design that forces one choice or the other. And I think Kenny's patch achieves that goal, because the choice is hidden behind macros and behind the wide_int interface. Not unifying const-int and double-int in the end would be odd. Richard. Thanks, Richard
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
Richard Biener richard.guent...@gmail.com writes: Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: At the rtl level your idea does not work. rtl constants do not have a mode or type. Which is not true and does not matter. I tell you why. Quote: It _is_ true, as long as you read rtl constants as rtl integer constants :-) +#if TARGET_SUPPORTS_WIDE_INT + +/* Match CONST_*s that can represent compile-time constant integers. */ +#define CASE_CONST_SCALAR_INT \ + case CONST_INT: \ + case CONST_WIDE_INT which means you are only replacing CONST_DOUBLE with wide-int. And _all_ CONST_DOUBLE have a mode. Otherwise you'd have no way of creating the wide-int in the first place. No, integer CONST_DOUBLEs have VOIDmode, just like CONST_INT. Only floating-point CONST_DOUBLEs have a real mode. I stand corrected. Now that's one more argument for infinite precision constants, as the mode is then certainly provided by the operations similar to the sign. That is, the mode (or size, or precision) of 1 certainly does not matter. I disagree. Although CONST_INT and CONST_DOUBLE don't _store_ a mode, they are always interpreted according to a particular mode. It's just that that mode has to be specified separately. That's why so many rtl functions have (enum machine_mode, rtx) pairs. Infinite precision seems very alien to rtl, where everything is interpreted according to a particular mode (whether that mode is stored in the rtx or not). For one thing, I don't see how infinite precision could work in an environment where signedness often isn't defined. E.g. if you optimise an addition of two rtl constants, you don't know (and aren't supposed to know) whether the values involved are signed or unsigned. With fixed-precision arithmetic it doesn't matter, because both operands must have the same precision, and because bits outside the precision are not significant. With infinite precision arithmetic, the choice carries over to the next operation. E.g., to take a 4-bit example, you don't know when constructing a wide_int from an rtx whether 0b1000 represents 8 or -8. But if you have no precision to say how many bits are significant, you have to pick one. Which do you choose? And why should we have to make a choice at all? (Note that this is a different question to whether the internal wide_int representation is sign-extending or not, which is purely an implementation detail. The same implementation principle applies to CONST_INTs: the HWI in a CONST_INT is always sign-extended from the msb of the represented value, although of course the CONST_INT itself doesn't tell you which bit the msb is; that has to be determined separately.) A particular wide_int isn't, and IMO shouldn't be, inherently signed or unsigned. The rtl model is that signedness is a question of interpretation rather than representation. I realise trees are different, because signedness is a property of the type rather than operations on the type, but I still think fixed precision works with both tree and rtl whereas infinite precision doesn't work with rtl. I also fear there are going to be lots of bugs where we forget to truncate the result of an N-bit operation from infinite precision to N bits before using it in the next operation (as per Kenny's ring explanation). With finite precision, and with all-important asserts that the operands have consistent precisions, we shouldn't have any hidden bugs like that. If there are parts of gcc that really want to do infinite-precision arithmetic, mpz_t ought to be as good as anything. Thanks, Richard
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On 04/22/2013 08:20 AM, Richard Biener wrote: That said, a lot of my pushback is because I feel a little lonesome in this wide-int review and don't want to lone-some decide about that (generic) interface part as well. yeh, now sandiford is back from vacation so there are two of us to beat on you about your how bad it would be to do infinite precision!!! be careful what you wish for. kenny
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
Richard, i pulled these two frags out of your comments because i wanted to get some input from you on it while i addressed the other issues you raised. + enum SignOp { +/* Many of the math functions produce different results depending + on if they are SIGNED or UNSIGNED. In general, there are two + different functions, whose names are prefixed with an 'S and + or an 'U'. However, for some math functions there is also a + routine that does not have the prefix and takes an SignOp + parameter of SIGNED or UNSIGNED. */ +SIGNED, +UNSIGNED + }; You seem to insist on that. It should propagate to the various parts of the compiler that have settled for the 'uns' integer argument. Having one piece behave different is just weird. I suppose I will find code like wi.ext (prec, uns ? UNSIGNED : SIGNED) there is a lot more flexibility on my part than you perceive with respect to this point. My primary issue is that i do not want to have is an interface that has 0 and 1 as a programmer visible part. Beyond that i am open to suggestion. The poster child of my hate are the host_integer_p and the tree_low_cst interfaces. I did not want the wide int stuff to look like these. I see several problems with these: 1) of the 314 places where tree_low_cst is called in the gcc directory (not the subdirectories where the front ends live), NONE of the calls have a variable second parameter. There are a handful of places, as one expects, in the front ends that do, but NONE in the middle end. 2) there are a small number of the places where host_integer_p is called with one parameter and then it is followed by a call to tree_low_cst that has the value with the other sex. I am sure these are mistakes, but having the 0s and 1s flying around does not make it easy to spot them. 3) tree_low_cst implies that the tree cst has only two hwis in it. While i do not want to propagate an interface with 0 and 1 into wide-int, i can understand your dislike of having a wide-int only solution for this. I will point out that for your particular example, uns is almost always set by a call to TYPE_UNSIGNED. There could easily be a different type accessor that converts this part of the type to the right thing to pass in here. I think that there is certainly some place for there to be a unified SYMBOLIC api that controls the signedness everywhere in the compiler. I would like to move toward this direction, but you have been so negative to the places where i have made it convenient to directly convert from tree or rtl into or out of wide-int that i have hesitated to do something that directly links trees and wide-int. So i would like to ask you what would like? + template typename T +inline bool gt_p (T c, SignOp sgn) const; + template typename T +inline bool gts_p (T c) const; + template typename T +inline bool gtu_p (T c) const; it's bad that we can't use the sign information we have available in almost all cases ... (where precision is not an exact multiple of HOST_BITS_PER_WIDE_INT and len == precision / HOST_BITS_PER_WIDE_INT). It isn't hard to encode a sign - you just have to possibly waste a word of zeroes for positive values where at the moment precision is an exact multiple of HOST_BIST_PER_WIDE_INT and len == precision / HOST_BITS_PER_WIDE_INT. Which of course means that the encoding can be one word larger than maximally required by 'precision'. Going back to point 1 above, the front ends structure the middle end code where (generally) the sign that is used is encoded in the operator that one is looking at.So the majority of uses in the middle end this fall into the second or third templates and the first template is there as a convenience routine for the middle ends. The front ends certainly use the first template. This is how the rtl level has survived so long without a sign bit in the modes, the operators tell the whole story. The truth is that in the middle end, the story is the same - it is the operators (most of the time) that drive the calls being made. There is an assumption that you are making that i certainly do not believe is true in the backends and i kind of doubt is true in the middle ends. That is that the sign of the compare ALWAYS matches the sign of the operands. Given that i have never seen any code that verifies this in the middle end, i am going to assume that it is not true, because it is always true in gcc that anything that we do not explicitly verify generally turns out to only be generally true and you can spend your life tracking down the end cases. This is a needless complication. At the rtl level, this is completely doomed by the GEN_INT which neither takes a mode or an indication of sign. To assume that there is any meaningful sign information there is a horror story waiting to be written (sure what could go wrong if we go into the old house? whats that
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On Tue, Apr 16, 2013 at 10:07 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Richard, I made major changes to wide-int along the lines you suggested. Each of the binary operations is now a template. There are 5 possible implementations of those operations, one for each of HWI, unsigned HWI, wide-int, rtl, and tree. Note that this is not exactly as you suggested, but it is along the same lines. The HWI template sign extends the value to the precision of the first operand, the unsigned HWI is the same except that it is an unsigned extension. The wide-int version is used as before, but is in truth rarely used. The rtl and tree logically convert the value to a wide-int but in practice do something more efficient than converting to the wide-int. What they do is look inside the rtl or the tree and pass a pointer to the data and a length to the binary operation. This is perfectly safe in the position of a second operand to the binary operation because the lifetime is guaranteed to be very short. The wide-int implementation was also modified to do the same pointer trick allowing all 5 templates to share the same use of the data. Note that currently the tree code is more crufty than one would like. This will clean up nicely when the tree-cst is changed to represent the value with an array and a length field. So now, at least for the second operand of binary operations, the storage is never copied.I do not believe that there is a good similar trick for the first operand. i did not consider something like wide_int::add (a, b) to be a viable option; it seems to mis the point of using an object oriented language. So I think that you really have to copy the data into an instance of a wide int. However, while all of this avoids ever having to pass a precision into the second operand, this patch does preserve the finite math implementation of wide-int.Finite math is really what people expect an optimizer to do, because it seamlessly matches what the machine is going to do. I hope at this point, i can get a comprehensive review on these patches. I believe that I have done what is required. There are two other patches that will be submitted in the next few minutes. The first one is an updated version of the rtl level patch. The only changes from what you have seen before are that the binary operations now use the templated binary operations. The second one is the first of the tree level patches. It converts builtins.c to use both use wide-int and it removes all assumptions that tree-csts are built with two HWIs. Once builtins.c is accepted, i will convert the rest of the middle end patches. They will all be converted in a similar way. + number of elements of the vector that are in use. When LEN * + HOST_BITS_PER_WIDE_INT the precision, the value has been + compressed. The values of the elements of the vector greater than + LEN - 1. are all equal to the highest order bit of LEN. equal to the highest order bit of element LEN - 1. ? Especially _not_ equal to the precision - 1 bit of the value, correct? + The representation does not contain any information inherant about + signedness of the represented value, so it can be used to represent + both signed and unsigned numbers. For operations where the results + depend on signedness (division, comparisons), the signedness must + be specified separately. For operations where the signness + matters, one of the operands to the operation specifies either + wide_int::SIGNED or wide_int::UNSIGNED. The last sentence is somehow duplicated. + The numbers are stored as sign entended numbers as a means of + compression. Leading HOST_WIDE_INTS that contain strings of either + -1 or 0 are removed as long as they can be reconstructed from the + top bit that is being represented. I'd put this paragraph before the one that talks about signedness, next to the one that already talks about encoding. + All constructors for wide_int take either a precision, an enum + machine_mode or tree_type. */ That's probably no longer true (I'll now check). +class wide_int { + /* Internal representation. */ + + /* VAL is set to a size that is capable of computing a full + multiplication on the largest mode that is represented on the + target. The full multiplication is use by tree-vrp. tree-vpn + currently does a 2x largest mode by 2x largest mode yielding a 4x + largest mode result. If operations are added that require larger + buffers, then VAL needs to be changed. */ + HOST_WIDE_INT val[WIDE_INT_MAX_ELTS]; + unsigned short len; + unsigned int precision; I wonder if there is a technical reason to stick to HOST_WIDE_INTs? I'd say for efficiency HOST_WIDEST_FAST_INT would be more appropriate (to get a 32bit value on 32bit x86 for example). I of course see that conversion to/from HOST_WIDE_INT is an important operation that would get slightly more
Re: patch to fix constant math - builtins.c - the first of the tree level patches for wide-int
Richard, this is the first of the tree level patches so that you can see how the wide-int changes will effect the tree level. This patch converts builtins.c so that it does not in any way assume that tree-cst holds two HWIs. The patch divides all math into two categories: Things that are always so small that we can easily assume that the math can be done using a single HWI and everything else. The things that it assumes can easily be done with a HWI are guarded with assertions. The everything else is done with wide-int. Everything else in this patch is additional abi to support this. The idea is that each pass will be converted, 1 pass per patch in this way.Once everything does not depend on the internals of tree-cst as they do now, then tree-cst will be converted to have an array inside of it rather than just two hwis. Kenny 2012-04-16 Kenneth Zadeck zad...@naturalbridge.com * builtins.c (get_object_alignment_2, get_pointer_alignment_1, c_strlen, c_getstr, target_char_cast, expand_builtin_mempcpy_args, expand_builtin_strncpy, expand_builtin_memset_args, expand_builtin_strncpy, expand_builtin_memset_args, expand_builtin_frame_address, expand_builtin_alloca, expand_builtin_atomic_compare_exchange, fold_builtin_powi, fold_builtin_memset, fold_builtin_memory_op, fold_builtin_memchr, fold_builtin_memcmp, fold_builtin_strncmp, fold_builtin_load_exponent, fold_builtin_snprintf, expand_builtin_object_size, expand_builtin_memory_chk, maybe_emit_chk_warning, maybe_emit_sprintf_chk_warning, fold_builtin_object_size, fold_builtin_memory_chk, fold_builtin_stxcpy_chk, fold_builtin_strcat_chk, fold_builtin_sprintf_chk_1, fold_builtin_snprintf_chk_1, do_mpfr_bessel_n): Convert to api that does not assume that tree_cst is two HWIs. (fold_builtin_int_roundingfn, fold_builtin_bitop, fold_builtin_bswap, fold_builtin_memory_op, expand_builtin_object_size): Use wide-int rather than double-int api. * dfp.c (decimal_real_to_integer): Add wide-int version. * real.c (real_to_integer): Ditto. * tree.h (tree_fits_uhwi_p, tree_fits_shwi_p, tree_fits_hwi_p, tree_to_shwi, tree_to_hwi, tree_to_uhwi): New functions. diff --git a/gcc/builtins.c b/gcc/builtins.c index ed5a6b3..5ba2297 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -339,8 +339,8 @@ get_object_alignment_2 (tree exp, unsigned int *alignp, if (TREE_CODE (addr) == BIT_AND_EXPR TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST) { - align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)) - -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))); + align = (tree_to_hwi (TREE_OPERAND (addr, 1)) + -tree_to_hwi (TREE_OPERAND (addr, 1))); align *= BITS_PER_UNIT; addr = TREE_OPERAND (addr, 0); } @@ -357,7 +357,7 @@ get_object_alignment_2 (tree exp, unsigned int *alignp, { unsigned HOST_WIDE_INT step = 1; if (TMR_STEP (exp)) - step = TREE_INT_CST_LOW (TMR_STEP (exp)); + step = tree_to_hwi (TMR_STEP (exp)); align = MIN (align, (step -step) * BITS_PER_UNIT); } if (TMR_INDEX2 (exp)) @@ -379,7 +379,8 @@ get_object_alignment_2 (tree exp, unsigned int *alignp, bitpos += ptr_bitpos; if (TREE_CODE (exp) == MEM_REF || TREE_CODE (exp) == TARGET_MEM_REF) - bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT; + bitpos += wide_int::from_tree (TREE_OPERAND (exp, 1)) + .to_shwi () * BITS_PER_UNIT; } } else if (TREE_CODE (exp) == STRING_CST) @@ -408,23 +409,23 @@ get_object_alignment_2 (tree exp, unsigned int *alignp, } else next_offset = NULL; - if (host_integerp (offset, 1)) + if (tree_fits_uhwi_p (offset)) { /* Any overflow in calculating offset_bits won't change the alignment. */ unsigned offset_bits - = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT); + = ((unsigned) tree_to_hwi (offset) * BITS_PER_UNIT); if (offset_bits) inner = MIN (inner, (offset_bits -offset_bits)); } else if (TREE_CODE (offset) == MULT_EXPR - host_integerp (TREE_OPERAND (offset, 1), 1)) + tree_fits_uhwi_p (TREE_OPERAND (offset, 1))) { /* Any overflow in calculating offset_factor won't change the alignment. */ unsigned offset_factor - = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1) + = ((unsigned) tree_to_hwi (TREE_OPERAND (offset, 1)) * BITS_PER_UNIT); if (offset_factor) @@ -515,7 +516,7 @@ get_pointer_alignment_1 (tree exp, unsigned int *alignp, else if (TREE_CODE (exp) == INTEGER_CST) { *alignp = BIGGEST_ALIGNMENT; - *bitposp = ((TREE_INT_CST_LOW (exp) * BITS_PER_UNIT) + *bitposp = ((tree_to_hwi (exp) * BITS_PER_UNIT) (BIGGEST_ALIGNMENT - 1)); return true; } @@ -624,10 +625,10 @@ c_strlen (tree src, int
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On Fri, Apr 5, 2013 at 2:34 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Richard, There has been something that has bothered me about you proposal for the storage manager and i think i can now characterize that problem. Say i want to compute the expression (a + b) / c converting from tree values, using wide-int as the engine and then storing the result in a tree. (A very common operation for the various simplifiers in gcc.) in my version of wide-int where there is only the stack allocated fix size allocation for the data, the compiler arranges for 6 instances of wide-int that are statically allocated on the stack when the function is entered. There would be 3 copies of the precision and data to get things started and one allocation variable sized object at the end when the INT_CST is built and one copy to put it back. As i have argued, these copies are of negligible size. In your world, to get things started, you would do 3 pointer copies to get the values out of the tree to set the expression leaves but then you will call the allocator 3 times to get space to hold the intermediate nodes before you get to pointer copy the result back into the result cst which still needs an allocation to build it. I am assuming that we can play the same game at the tree level that we do at the rtl level where we do 1 variable sized allocation to get the entire INT_CST rather than doing 1 fixed sized allocation and 1 variable sized one. even if we take the simpler example of a + b, you still loose. The cost of the extra allocation and it's subsequent recovery is more than my copies. In fact, even in the simplest case of someone going from a HWI thru wide_int into tree, you have 2 allocations vs my 1. Just to clarify, my code wouldn't handle tree a, b, c; tree res = (a + b) / c; transparently. The most complex form of the above that I think would be reasonable to handle would be tree a, b, c; wide_int wires = (wi (a) + b) / c; tree res = build_int_cst (TREE_TYPE (a), wires); and the code as posted would even require you to specify the return type of operator+ and operator/ explicitely like wide_int wires = (wi (a).operator+wi_embed_var (b)).operator/wi_embed_var (c); but as I said I just didn't bother to decide that the return type is always of wide_int variable-len-storage kind. Now, the only real allocation that happens is done by build_int_cst. There is one wide_int on the stack to hold the a + b result and one separate wide_int to hold wires (it's literally written in the code). There are no pointer copies involved in the end - the result from converting a tree to a wide_inttree-storage is the original 'tree' pointer itself, thus a register. I just do not see the cost savings and if there are no cost savings, you certainly cannot say that having these templates is simpler than not having the templates. I think you are missing the point - by abstracting away the storage you don't necessarily need to add the templates. But you open up a very easy route for doing so and you make the operations _trivially_ work on the tree / RTL storage with no overhead in generated code and minimal overhead in the amount of code in GCC itself. In my prototype the overhead of adding 'tree' support is to place class wi_tree_int_cst { tree cst; public: void construct (tree c) { cst = c; } const HOST_WIDE_INT *storage() const { return reinterpret_cast HOST_WIDE_INT *(TREE_INT_CST (cst)); } unsigned len() const { return 2; } }; template class wi_traits tree { public: typedef wide_int wi_tree_int_cst wi_t; wi_traits(tree t) { wi_tree_int_cst ws; ws.construct (t); w.construct (ws); } wi_t* operator-() { return w; } private: wi_t w; }; into tree.h. Richard. Kenny On 04/02/2013 11:04 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: This patch contains a large number of the changes requested by Richi. It does not contain any of the changes that he requested to abstract the storage layer. That suggestion appears to be quite unworkable. I of course took this claim as a challenge ... with the following result. It is of course quite workable ;) The attached patch implements the core wide-int class and three storage models (fixed size for things like plain HWI and double-int, variable size similar to how your wide-int works and an adaptor for the double-int as contained in trees). With that you can now do HOST_WIDE_INT wi_test (tree x) { // template argument deduction doesn't do the magic we want it to do // to make this kind of implicit conversions work // overload resolution considers this kind of conversions so we // need some magic that combines both ... but seeding the overload // set with some instantiations doesn't seem to be possible :/ // wide_int w = x + 1; wide_int w; w += x; w += 1; // template argument
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
Richard, There has been something that has bothered me about you proposal for the storage manager and i think i can now characterize that problem. Say i want to compute the expression (a + b) / c converting from tree values, using wide-int as the engine and then storing the result in a tree. (A very common operation for the various simplifiers in gcc.) in my version of wide-int where there is only the stack allocated fix size allocation for the data, the compiler arranges for 6 instances of wide-int that are statically allocated on the stack when the function is entered.There would be 3 copies of the precision and data to get things started and one allocation variable sized object at the end when the INT_CST is built and one copy to put it back. As i have argued, these copies are of negligible size. In your world, to get things started, you would do 3 pointer copies to get the values out of the tree to set the expression leaves but then you will call the allocator 3 times to get space to hold the intermediate nodes before you get to pointer copy the result back into the result cst which still needs an allocation to build it. I am assuming that we can play the same game at the tree level that we do at the rtl level where we do 1 variable sized allocation to get the entire INT_CST rather than doing 1 fixed sized allocation and 1 variable sized one. even if we take the simpler example of a + b, you still loose. The cost of the extra allocation and it's subsequent recovery is more than my copies. In fact, even in the simplest case of someone going from a HWI thru wide_int into tree, you have 2 allocations vs my 1. I just do not see the cost savings and if there are no cost savings, you certainly cannot say that having these templates is simpler than not having the templates. Kenny On 04/02/2013 11:04 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: This patch contains a large number of the changes requested by Richi. It does not contain any of the changes that he requested to abstract the storage layer. That suggestion appears to be quite unworkable. I of course took this claim as a challenge ... with the following result. It is of course quite workable ;) The attached patch implements the core wide-int class and three storage models (fixed size for things like plain HWI and double-int, variable size similar to how your wide-int works and an adaptor for the double-int as contained in trees). With that you can now do HOST_WIDE_INT wi_test (tree x) { // template argument deduction doesn't do the magic we want it to do // to make this kind of implicit conversions work // overload resolution considers this kind of conversions so we // need some magic that combines both ... but seeding the overload // set with some instantiations doesn't seem to be possible :/ // wide_int w = x + 1; wide_int w; w += x; w += 1; // template argument deduction doesn't deduce the return value type, // not considering the template default argument either ... // w = wi (x) + 1; // we could support this by providing rvalue-to-lvalue promotion // via a traits class? // otoh it would lead to sub-optimal code anyway so we should // make the result available as reference parameter and only support // wide_int res; add (res, x, 1); ? w = wi (x).operator+wide_int (1); wide_int::add(w, x, 1); return w.to_hwi (); } we are somewhat limited with C++ unless we want to get really fancy. Eventually providing operator+ just doesn't make much sense for generic wide-int combinations (though then the issue is its operands are no longer commutative which I think is the case with your wide-int or double-int as well - they don't suport 1 + wide_int for obvious reasons). So there are implementation design choices left undecided. Oh, and the operation implementations are crap (they compute nonsense). But you should get the idea. Richard.
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On Wed, Apr 3, 2013 at 6:16 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/03/2013 09:53 AM, Richard Biener wrote: On Wed, Apr 3, 2013 at 2:05 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/03/2013 05:17 AM, Richard Biener wrote: In the end you will have a variable-size storage in TREE_INT_CST thus you will have at least to emit _code_ copying over meta-data and data from the tree representation to the wide-int (similar for RTX CONST_DOUBLE/INT). I'm objecting to the amount of code you emit and agree that the runtime cost is copying the meta-data (hopefully optimizable via CSE / SRA) and in most cases one (or two) iterations of the loop copying the data (not optimizable). i did get rid of the bitsize in the wide-int patch so at this point the meta data is the precision and the len. not really a lot here. As usual we pay a high price in gcc for not pushing the tree rep down into the rtl level, then it would have been acceptable to have the tree type bleed into the wide-int code. 2) You present this as if the implementor actually should care about the implementation and you give 3 alternatives: the double_int, the current one, and HWI. We have tried to make it so that the client should not care. Certainly in my experience here, I have not found a place to care. Well, similar as for the copying overhead for tree your approach requires overloading operations for HOST_WIDE_INT operands to be able to say wi + 1 (which is certainly desirable), or the overhead of using wide_int_one (). In my opinion double_int needs to go away. That is the main thrust of my patches. There is no place in a compiler for an abi that depends on constants fitting into 2 two words whose size is defined by the host. That's true. I'm not arguing to preserve double-int - I'm arguing to preserve a way to ask for an integer type on the host with (at least) N bits. Almost all double-int users really ask for an integer type on the host that has at least as many bits as the pointer representation (or word_mode) on the target (we do have HOST_WIDEST_INT == 32bits for 64bit pointer targets). No double-int user specifically wants 2 * HOST_WIDE_INT precision - that is just what happens to be there. Thus I am providing a way to say get me a host integer with at least N bits (VRP asks for this, for example). What I was asking for is that whatever can provide the above should share the functional interface with wide-int (or the othert way around). And I was claiming that wide-int is too fat, because current users of double-int eventually store double-ints permanently. The problem is that, in truth, double int is too fat. 99.something% of all constants fit in 1 hwi and that is likely to be true forever (i understand that tree vpn may need some thought here). The rtl level, which has, for as long as i have known it, had 2 reps for integer constants. So it was relatively easy to slide the CONST_WIDE_INT in. It seems like the right trickery here rather than adding a storage model for wide-ints might be a way to use the c++ to invisibly support several (and by several i really mean 2) classes of TREE_CSTs. The truth is that _now_ TREE_INT_CSTs use double-ints and we have CONST_INT and CONST_DOUBLE. What I (and you) propose would get us to use variable-size storage for both, allowing to just use a single HOST_WIDE_INT in the majority of cases. In my view the constant length of the variable-size storage for TREE_INT_CSTs is determined by its type (thus, it doesn't have optimized variable-size storage but unoptimized fixed-size storage based on the maximum storage requirement for the type). Similar for RTX CONST_INT which would have fixed-size storage based on the mode-size of the constant. Using optimized space (thus using the encoding properties) requires you to fit the 'short len' somewhere which possibly will not pay off in the end (for tree we do have that storage available, so we could go with optimized storage for it, not sure with RTL, I don't see available space there). There are two questions here: one is the fact that you object to the fact that we represent small constants efficiently Huh? Where do I object to that? I question that for the storage in tree and RTX the encoding trick pays off if you need another HWI-aligned word to store the len. But see below. and the second is that we take advantage of the fact that fixed size stack allocation is effectively free for short lived objects like wide-ints (as i use them). I don't question that and I am not asking you to change that. As part of what I ask for a more optimal (smaller) stack allocation would be _possible_ (but not required). At the rtl level your idea does not work. rtl constants do not have a mode or type.So if you do not compress, how are you going to determine how many words you need for the constant 1. I would love to
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On Tue, Apr 2, 2013 at 7:35 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Yes, I agree that you win the challenge that it can be done.What you have always failed to address is why anyone would want to do this. Or how this would at all be desirable.But I completely agree that from a purely abstract point of view you can add a storage model. Now here is why we REALLY do not want to go down this road: 1) The following comment from your earlier mail is completely wrong +#ifdef NEW_REP_FOR_INT_CST + /* This is the code once the tree level is converted. */ + wide_int result; + int i; + + tree type = TREE_TYPE (tcst); + + result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type)); + result.precision = TYPE_PRECISION (type); + result.len = TREE_INT_CST_LEN (tcst); + for (i = 0; i result.len; i++) +result.val[i] = TREE_INT_CST_ELT (tcst, i); + + return result; +#else this also shows the main reason I was asking for storage abstraction. The initialization from tree is way too expensive. In almost all cases, constants will fit in a single HWI. Thus, the only thing that you are copying is the length and a single HWI. So you are dragging in a lot of machinery just to save these two copies? Certainly there has to be more to it than that. In the end you will have a variable-size storage in TREE_INT_CST thus you will have at least to emit _code_ copying over meta-data and data from the tree representation to the wide-int (similar for RTX CONST_DOUBLE/INT). I'm objecting to the amount of code you emit and agree that the runtime cost is copying the meta-data (hopefully optimizable via CSE / SRA) and in most cases one (or two) iterations of the loop copying the data (not optimizable). 2) You present this as if the implementor actually should care about the implementation and you give 3 alternatives: the double_int, the current one, and HWI. We have tried to make it so that the client should not care. Certainly in my experience here, I have not found a place to care. Well, similar as for the copying overhead for tree your approach requires overloading operations for HOST_WIDE_INT operands to be able to say wi + 1 (which is certainly desirable), or the overhead of using wide_int_one (). In my opinion double_int needs to go away. That is the main thrust of my patches. There is no place in a compiler for an abi that depends on constants fitting into 2 two words whose size is defined by the host. That's true. I'm not arguing to preserve double-int - I'm arguing to preserve a way to ask for an integer type on the host with (at least) N bits. Almost all double-int users really ask for an integer type on the host that has at least as many bits as the pointer representation (or word_mode) on the target (we do have HOST_WIDEST_INT == 32bits for 64bit pointer targets). No double-int user specifically wants 2 * HOST_WIDE_INT precision - that is just what happens to be there. Thus I am providing a way to say get me a host integer with at least N bits (VRP asks for this, for example). What I was asking for is that whatever can provide the above should share the functional interface with wide-int (or the othert way around). And I was claiming that wide-int is too fat, because current users of double-int eventually store double-ints permanently. This is not a beauty contest argument, we have public ports are beginning to use modes that are larger than two x86-64 HWIs and i have a private port that has such modes and it is my experience that any pass that uses this interface has one of three behaviors: it silently gets the wrong answer, it ices, or it fails to do the transformation. If we leave double_int as an available option, then any use of it potentially will have one of these three behaviors. And so one of my strong objections to this direction is that i do not want to fight this kind of bug for the rest of my life. Having a single storage model that just always works is in my opinion a highly desirable option. What you have never answered in a concrete manner is, if we decide to provide this generality, what it would be used for. There is no place in a portable compiler where the right answer for every target is two HOST wide integers. However, i will admit that the HWI option has some merits. We try to address this in our implementation by dividing what is done inline in wide-int.h to the cases that fit in an HWI and then only drop into the heavy code in wide-int.c if mode is larger (which it rarely will be). However, a case could be made that for certain kinds of things like string lengths and such, we could use another interface or as you argue, a different storage model with the same interface. I just do not see that the cost of the conversion code is really going to show up on anyone's radar. What's the issue with abstracting away the model so a fixed-size 'len' is possible? (let away the argument that
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
On Tue, Apr 2, 2013 at 9:08 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: this time for sure. Almost ... diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..92d54a3 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,35 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING #ifdef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); + Ok with that change. (maybe catch one random use of the pattern in code and use the helpers - that would have catched this issue) Thanks, Richard. kenny On 04/02/2013 10:54 AM, Richard Biener wrote: On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Richard, did everything that you asked here. bootstrapped and regtested on x86-64. ok to commit? diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..7e5b85c 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) this should go to hwint.h, and without the masking of prec. while ... diff --git a/gcc/hwint.h b/gcc/hwint.h index da62fad..9dddf05 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT); +/* Sign extend SRC starting from PREC. */ + +#ifdef ENABLE_CHECKING +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); +#else +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); this should go to hwint.c (also without masking prec). Richard. kenny On 04/02/2013 05:38 AM, Richard Biener wrote: On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: richard, I was able to add everything except for the checking asserts.While I think that this is a reasonable idea, it is difficult to add that to a function that is defined in hwint.h because of circular includes. I could move this another file (though this appears to be the logical correct place for it), or we can do without the asserts. The context is that [sz]ext_hwi is that are used are over the compiler but are generally written out long. The wide-int class uses them also, but wide-int did not see like the right place for them to live and i believe that you suggested that i move them. ok to commit, or do you have a suggested resolution to the assert issue? Yes, do #ifdef ENABLE_CHECKING extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); #else +/* Sign extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ int shift = HOST_BITS_PER_WIDE_INT - prec; + return (src shift) shift; +} +} #endif and for ENABLE_CHECKING only provide an out-of-line implementation in hwint.c. That's how we did it with abs_hwi (well, we just do not provide an inline variant there - that's another possibility). Note that hwint.h is always included after config.h so the ENABLE_CHECKING definition should be available. Richard. kenny On 03/27/2013 10:13 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The patch misses context of uses, so I'm not sure what the above functions are intended to do. Richard. On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on hosts not supporting %hd (MinGW?), and
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
yes, i had caught that when i merged it in with the patches that used it, is it ok aside from that? kenny On 04/03/2013 05:32 AM, Richard Biener wrote: On Tue, Apr 2, 2013 at 9:08 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: this time for sure. Almost ... diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..92d54a3 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,35 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING #ifdef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); + Ok with that change. (maybe catch one random use of the pattern in code and use the helpers - that would have catched this issue) Thanks, Richard. kenny On 04/02/2013 10:54 AM, Richard Biener wrote: On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Richard, did everything that you asked here. bootstrapped and regtested on x86-64. ok to commit? diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..7e5b85c 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) this should go to hwint.h, and without the masking of prec. while ... diff --git a/gcc/hwint.h b/gcc/hwint.h index da62fad..9dddf05 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT); +/* Sign extend SRC starting from PREC. */ + +#ifdef ENABLE_CHECKING +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); +#else +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); this should go to hwint.c (also without masking prec). Richard. kenny On 04/02/2013 05:38 AM, Richard Biener wrote: On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: richard, I was able to add everything except for the checking asserts.While I think that this is a reasonable idea, it is difficult to add that to a function that is defined in hwint.h because of circular includes. I could move this another file (though this appears to be the logical correct place for it), or we can do without the asserts. The context is that [sz]ext_hwi is that are used are over the compiler but are generally written out long. The wide-int class uses them also, but wide-int did not see like the right place for them to live and i believe that you suggested that i move them. ok to commit, or do you have a suggested resolution to the assert issue? Yes, do #ifdef ENABLE_CHECKING extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); #else +/* Sign extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ int shift = HOST_BITS_PER_WIDE_INT - prec; + return (src shift) shift; +} +} #endif and for ENABLE_CHECKING only provide an out-of-line implementation in hwint.c. That's how we did it with abs_hwi (well, we just do not provide an inline variant there - that's another possibility). Note that hwint.h is always included after config.h so the ENABLE_CHECKING definition should be available. Richard. kenny On 03/27/2013 10:13 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The patch misses context of uses, so I'm not sure what the above functions are intended to do. Richard. On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On 04/03/2013 05:17 AM, Richard Biener wrote: In the end you will have a variable-size storage in TREE_INT_CST thus you will have at least to emit _code_ copying over meta-data and data from the tree representation to the wide-int (similar for RTX CONST_DOUBLE/INT). I'm objecting to the amount of code you emit and agree that the runtime cost is copying the meta-data (hopefully optimizable via CSE / SRA) and in most cases one (or two) iterations of the loop copying the data (not optimizable). i did get rid of the bitsize in the wide-int patch so at this point the meta data is the precision and the len. not really a lot here. As usual we pay a high price in gcc for not pushing the tree rep down into the rtl level, then it would have been acceptable to have the tree type bleed into the wide-int code. 2) You present this as if the implementor actually should care about the implementation and you give 3 alternatives: the double_int, the current one, and HWI. We have tried to make it so that the client should not care. Certainly in my experience here, I have not found a place to care. Well, similar as for the copying overhead for tree your approach requires overloading operations for HOST_WIDE_INT operands to be able to say wi + 1 (which is certainly desirable), or the overhead of using wide_int_one (). In my opinion double_int needs to go away. That is the main thrust of my patches. There is no place in a compiler for an abi that depends on constants fitting into 2 two words whose size is defined by the host. That's true. I'm not arguing to preserve double-int - I'm arguing to preserve a way to ask for an integer type on the host with (at least) N bits. Almost all double-int users really ask for an integer type on the host that has at least as many bits as the pointer representation (or word_mode) on the target (we do have HOST_WIDEST_INT == 32bits for 64bit pointer targets). No double-int user specifically wants 2 * HOST_WIDE_INT precision - that is just what happens to be there. Thus I am providing a way to say get me a host integer with at least N bits (VRP asks for this, for example). What I was asking for is that whatever can provide the above should share the functional interface with wide-int (or the othert way around). And I was claiming that wide-int is too fat, because current users of double-int eventually store double-ints permanently. The problem is that, in truth, double int is too fat. 99.something% of all constants fit in 1 hwi and that is likely to be true forever (i understand that tree vpn may need some thought here). The rtl level, which has, for as long as i have known it, had 2 reps for integer constants. So it was relatively easy to slide the CONST_WIDE_INT in. It seems like the right trickery here rather than adding a storage model for wide-ints might be a way to use the c++ to invisibly support several (and by several i really mean 2) classes of TREE_CSTs. This is not a beauty contest argument, we have public ports are beginning to use modes that are larger than two x86-64 HWIs and i have a private port that has such modes and it is my experience that any pass that uses this interface has one of three behaviors: it silently gets the wrong answer, it ices, or it fails to do the transformation. If we leave double_int as an available option, then any use of it potentially will have one of these three behaviors. And so one of my strong objections to this direction is that i do not want to fight this kind of bug for the rest of my life. Having a single storage model that just always works is in my opinion a highly desirable option. What you have never answered in a concrete manner is, if we decide to provide this generality, what it would be used for. There is no place in a portable compiler where the right answer for every target is two HOST wide integers. However, i will admit that the HWI option has some merits. We try to address this in our implementation by dividing what is done inline in wide-int.h to the cases that fit in an HWI and then only drop into the heavy code in wide-int.c if mode is larger (which it rarely will be). However, a case could be made that for certain kinds of things like string lengths and such, we could use another interface or as you argue, a different storage model with the same interface. I just do not see that the cost of the conversion code is really going to show up on anyone's radar. What's the issue with abstracting away the model so a fixed-size 'len' is possible? (let away the argument that this would easily allow an adaptor to tree) I have a particularly pessimistic perspective because i have already written most of this patch. It is not that i do not want to change that code, it is that i have seen a certain set of mistakes that were made and i do not want to fix them more than once. At the rtl level you can see the transition from only supporting 32 bit ints to supporting 64 bit
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
On Wed, Apr 3, 2013 at 12:47 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: yes, i had caught that when i merged it in with the patches that used it, is it ok aside from that? Yes. Thanks, Richard. kenny On 04/03/2013 05:32 AM, Richard Biener wrote: On Tue, Apr 2, 2013 at 9:08 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: this time for sure. Almost ... diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..92d54a3 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,35 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING #ifdef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); + Ok with that change. (maybe catch one random use of the pattern in code and use the helpers - that would have catched this issue) Thanks, Richard. kenny On 04/02/2013 10:54 AM, Richard Biener wrote: On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Richard, did everything that you asked here. bootstrapped and regtested on x86-64. ok to commit? diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..7e5b85c 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) this should go to hwint.h, and without the masking of prec. while ... diff --git a/gcc/hwint.h b/gcc/hwint.h index da62fad..9dddf05 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT); +/* Sign extend SRC starting from PREC. */ + +#ifdef ENABLE_CHECKING +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); +#else +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); this should go to hwint.c (also without masking prec). Richard. kenny On 04/02/2013 05:38 AM, Richard Biener wrote: On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: richard, I was able to add everything except for the checking asserts. While I think that this is a reasonable idea, it is difficult to add that to a function that is defined in hwint.h because of circular includes. I could move this another file (though this appears to be the logical correct place for it), or we can do without the asserts. The context is that [sz]ext_hwi is that are used are over the compiler but are generally written out long. The wide-int class uses them also, but wide-int did not see like the right place for them to live and i believe that you suggested that i move them. ok to commit, or do you have a suggested resolution to the assert issue? Yes, do #ifdef ENABLE_CHECKING extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); #else +/* Sign extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ int shift = HOST_BITS_PER_WIDE_INT - prec; + return (src shift) shift; +} +} #endif and for ENABLE_CHECKING only provide an out-of-line implementation in hwint.c. That's how we did it with abs_hwi (well, we just do not provide an inline variant there - that's another possibility). Note that hwint.h is always included after config.h so the ENABLE_CHECKING definition should be available. Richard. kenny On 03/27/2013 10:13 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On Wed, Apr 3, 2013 at 2:05 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/03/2013 05:17 AM, Richard Biener wrote: In the end you will have a variable-size storage in TREE_INT_CST thus you will have at least to emit _code_ copying over meta-data and data from the tree representation to the wide-int (similar for RTX CONST_DOUBLE/INT). I'm objecting to the amount of code you emit and agree that the runtime cost is copying the meta-data (hopefully optimizable via CSE / SRA) and in most cases one (or two) iterations of the loop copying the data (not optimizable). i did get rid of the bitsize in the wide-int patch so at this point the meta data is the precision and the len. not really a lot here. As usual we pay a high price in gcc for not pushing the tree rep down into the rtl level, then it would have been acceptable to have the tree type bleed into the wide-int code. 2) You present this as if the implementor actually should care about the implementation and you give 3 alternatives: the double_int, the current one, and HWI. We have tried to make it so that the client should not care. Certainly in my experience here, I have not found a place to care. Well, similar as for the copying overhead for tree your approach requires overloading operations for HOST_WIDE_INT operands to be able to say wi + 1 (which is certainly desirable), or the overhead of using wide_int_one (). In my opinion double_int needs to go away. That is the main thrust of my patches. There is no place in a compiler for an abi that depends on constants fitting into 2 two words whose size is defined by the host. That's true. I'm not arguing to preserve double-int - I'm arguing to preserve a way to ask for an integer type on the host with (at least) N bits. Almost all double-int users really ask for an integer type on the host that has at least as many bits as the pointer representation (or word_mode) on the target (we do have HOST_WIDEST_INT == 32bits for 64bit pointer targets). No double-int user specifically wants 2 * HOST_WIDE_INT precision - that is just what happens to be there. Thus I am providing a way to say get me a host integer with at least N bits (VRP asks for this, for example). What I was asking for is that whatever can provide the above should share the functional interface with wide-int (or the othert way around). And I was claiming that wide-int is too fat, because current users of double-int eventually store double-ints permanently. The problem is that, in truth, double int is too fat. 99.something% of all constants fit in 1 hwi and that is likely to be true forever (i understand that tree vpn may need some thought here). The rtl level, which has, for as long as i have known it, had 2 reps for integer constants. So it was relatively easy to slide the CONST_WIDE_INT in. It seems like the right trickery here rather than adding a storage model for wide-ints might be a way to use the c++ to invisibly support several (and by several i really mean 2) classes of TREE_CSTs. The truth is that _now_ TREE_INT_CSTs use double-ints and we have CONST_INT and CONST_DOUBLE. What I (and you) propose would get us to use variable-size storage for both, allowing to just use a single HOST_WIDE_INT in the majority of cases. In my view the constant length of the variable-size storage for TREE_INT_CSTs is determined by its type (thus, it doesn't have optimized variable-size storage but unoptimized fixed-size storage based on the maximum storage requirement for the type). Similar for RTX CONST_INT which would have fixed-size storage based on the mode-size of the constant. Using optimized space (thus using the encoding properties) requires you to fit the 'short len' somewhere which possibly will not pay off in the end (for tree we do have that storage available, so we could go with optimized storage for it, not sure with RTL, I don't see available space there). This is not a beauty contest argument, we have public ports are beginning to use modes that are larger than two x86-64 HWIs and i have a private port that has such modes and it is my experience that any pass that uses this interface has one of three behaviors: it silently gets the wrong answer, it ices, or it fails to do the transformation. If we leave double_int as an available option, then any use of it potentially will have one of these three behaviors. And so one of my strong objections to this direction is that i do not want to fight this kind of bug for the rest of my life. Having a single storage model that just always works is in my opinion a highly desirable option. What you have never answered in a concrete manner is, if we decide to provide this generality, what it would be used for. There is no place in a portable compiler where the right answer for every target is two HOST wide integers. However, i will admit that the HWI option has some merits. We try to address this
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On 04/03/2013 09:53 AM, Richard Biener wrote: On Wed, Apr 3, 2013 at 2:05 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 04/03/2013 05:17 AM, Richard Biener wrote: In the end you will have a variable-size storage in TREE_INT_CST thus you will have at least to emit _code_ copying over meta-data and data from the tree representation to the wide-int (similar for RTX CONST_DOUBLE/INT). I'm objecting to the amount of code you emit and agree that the runtime cost is copying the meta-data (hopefully optimizable via CSE / SRA) and in most cases one (or two) iterations of the loop copying the data (not optimizable). i did get rid of the bitsize in the wide-int patch so at this point the meta data is the precision and the len. not really a lot here. As usual we pay a high price in gcc for not pushing the tree rep down into the rtl level, then it would have been acceptable to have the tree type bleed into the wide-int code. 2) You present this as if the implementor actually should care about the implementation and you give 3 alternatives: the double_int, the current one, and HWI. We have tried to make it so that the client should not care. Certainly in my experience here, I have not found a place to care. Well, similar as for the copying overhead for tree your approach requires overloading operations for HOST_WIDE_INT operands to be able to say wi + 1 (which is certainly desirable), or the overhead of using wide_int_one (). In my opinion double_int needs to go away. That is the main thrust of my patches. There is no place in a compiler for an abi that depends on constants fitting into 2 two words whose size is defined by the host. That's true. I'm not arguing to preserve double-int - I'm arguing to preserve a way to ask for an integer type on the host with (at least) N bits. Almost all double-int users really ask for an integer type on the host that has at least as many bits as the pointer representation (or word_mode) on the target (we do have HOST_WIDEST_INT == 32bits for 64bit pointer targets). No double-int user specifically wants 2 * HOST_WIDE_INT precision - that is just what happens to be there. Thus I am providing a way to say get me a host integer with at least N bits (VRP asks for this, for example). What I was asking for is that whatever can provide the above should share the functional interface with wide-int (or the othert way around). And I was claiming that wide-int is too fat, because current users of double-int eventually store double-ints permanently. The problem is that, in truth, double int is too fat. 99.something% of all constants fit in 1 hwi and that is likely to be true forever (i understand that tree vpn may need some thought here). The rtl level, which has, for as long as i have known it, had 2 reps for integer constants. So it was relatively easy to slide the CONST_WIDE_INT in. It seems like the right trickery here rather than adding a storage model for wide-ints might be a way to use the c++ to invisibly support several (and by several i really mean 2) classes of TREE_CSTs. The truth is that _now_ TREE_INT_CSTs use double-ints and we have CONST_INT and CONST_DOUBLE. What I (and you) propose would get us to use variable-size storage for both, allowing to just use a single HOST_WIDE_INT in the majority of cases. In my view the constant length of the variable-size storage for TREE_INT_CSTs is determined by its type (thus, it doesn't have optimized variable-size storage but unoptimized fixed-size storage based on the maximum storage requirement for the type). Similar for RTX CONST_INT which would have fixed-size storage based on the mode-size of the constant. Using optimized space (thus using the encoding properties) requires you to fit the 'short len' somewhere which possibly will not pay off in the end (for tree we do have that storage available, so we could go with optimized storage for it, not sure with RTL, I don't see available space there). There are two questions here: one is the fact that you object to the fact that we represent small constants efficiently and the second is that we take advantage of the fact that fixed size stack allocation is effectively free for short lived objects like wide-ints (as i use them). At the rtl level your idea does not work. rtl constants do not have a mode or type.So if you do not compress, how are you going to determine how many words you need for the constant 1. I would love to have a rep that had the mode in it.But it is a huge change that requires a lot of hacking to every port. I understand that this makes me vulnerable to the argument that we should not let the rtl level ever dictate anything about the tree level, but the truth is that a variable len rep is almost always used for big integers. In our code, most constants of large types are small numbers. (Remember i got into this because the tree constant prop thinks that left shifting any number by anything
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
committed as revision 197456 kenny On 04/03/2013 08:05 AM, Richard Biener wrote: On Wed, Apr 3, 2013 at 12:47 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: yes, i had caught that when i merged it in with the patches that used it, is it ok aside from that? Yes. Thanks, Richard. kenny On 04/03/2013 05:32 AM, Richard Biener wrote: On Tue, Apr 2, 2013 at 9:08 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: this time for sure. Almost ... diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..92d54a3 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,35 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING #ifdef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); + Ok with that change. (maybe catch one random use of the pattern in code and use the helpers - that would have catched this issue) Thanks, Richard. kenny On 04/02/2013 10:54 AM, Richard Biener wrote: On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Richard, did everything that you asked here. bootstrapped and regtested on x86-64. ok to commit? diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..7e5b85c 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) this should go to hwint.h, and without the masking of prec. while ... diff --git a/gcc/hwint.h b/gcc/hwint.h index da62fad..9dddf05 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT); +/* Sign extend SRC starting from PREC. */ + +#ifdef ENABLE_CHECKING +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); +#else +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); this should go to hwint.c (also without masking prec). Richard. kenny On 04/02/2013 05:38 AM, Richard Biener wrote: On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: richard, I was able to add everything except for the checking asserts. While I think that this is a reasonable idea, it is difficult to add that to a function that is defined in hwint.h because of circular includes. I could move this another file (though this appears to be the logical correct place for it), or we can do without the asserts. The context is that [sz]ext_hwi is that are used are over the compiler but are generally written out long. The wide-int class uses them also, but wide-int did not see like the right place for them to live and i believe that you suggested that i move them. ok to commit, or do you have a suggested resolution to the assert issue? Yes, do #ifdef ENABLE_CHECKING extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); #else +/* Sign extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ int shift = HOST_BITS_PER_WIDE_INT - prec; + return (src shift) shift; +} +} #endif and for ENABLE_CHECKING only provide an out-of-line implementation in hwint.c. That's how we did it with abs_hwi (well, we just do not provide an inline variant there - that's another possibility). Note that hwint.h is always included after config.h so the ENABLE_CHECKING definition should be available. Richard. kenny On 03/27/2013 10:13 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The patch misses context of uses, so I'm not sure what the above
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: richard, I was able to add everything except for the checking asserts.While I think that this is a reasonable idea, it is difficult to add that to a function that is defined in hwint.h because of circular includes. I could move this another file (though this appears to be the logical correct place for it), or we can do without the asserts. The context is that [sz]ext_hwi is that are used are over the compiler but are generally written out long. The wide-int class uses them also, but wide-int did not see like the right place for them to live and i believe that you suggested that i move them. ok to commit, or do you have a suggested resolution to the assert issue? Yes, do #ifdef ENABLE_CHECKING extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); #else +/* Sign extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ int shift = HOST_BITS_PER_WIDE_INT - prec; + return (src shift) shift; +} +} #endif and for ENABLE_CHECKING only provide an out-of-line implementation in hwint.c. That's how we did it with abs_hwi (well, we just do not provide an inline variant there - that's another possibility). Note that hwint.h is always included after config.h so the ENABLE_CHECKING definition should be available. Richard. kenny On 03/27/2013 10:13 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The patch misses context of uses, so I'm not sure what the above functions are intended to do. Richard. On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on hosts not supporting %hd (MinGW?), and there's no real need for using h here given the promotion of short to int; you can just use (rather than e.g. needing special handling in xm-mingw32.h like is done for HOST_LONG_LONG_FORMAT).
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
Richard, did everything that you asked here. bootstrapped and regtested on x86-64. ok to commit? kenny On 04/02/2013 05:38 AM, Richard Biener wrote: On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: richard, I was able to add everything except for the checking asserts.While I think that this is a reasonable idea, it is difficult to add that to a function that is defined in hwint.h because of circular includes. I could move this another file (though this appears to be the logical correct place for it), or we can do without the asserts. The context is that [sz]ext_hwi is that are used are over the compiler but are generally written out long. The wide-int class uses them also, but wide-int did not see like the right place for them to live and i believe that you suggested that i move them. ok to commit, or do you have a suggested resolution to the assert issue? Yes, do #ifdef ENABLE_CHECKING extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); #else +/* Sign extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ int shift = HOST_BITS_PER_WIDE_INT - prec; + return (src shift) shift; +} +} #endif and for ENABLE_CHECKING only provide an out-of-line implementation in hwint.c. That's how we did it with abs_hwi (well, we just do not provide an inline variant there - that's another possibility). Note that hwint.h is always included after config.h so the ENABLE_CHECKING definition should be available. Richard. kenny On 03/27/2013 10:13 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The patch misses context of uses, so I'm not sure what the above functions are intended to do. Richard. On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on hosts not supporting %hd (MinGW?), and there's no real need for using h here given the promotion of short to int; you can just use (rather than e.g. needing special handling in xm-mingw32.h like is done for HOST_LONG_LONG_FORMAT). 2013-4-02 Kenneth Zadeck zad...@naturalbridge.com * hwint.c (sext_hwi, zext_hwi): New functions. * hwint.h (HOST_BITS_PER_HALF_WIDE_INT, HOST_HALF_WIDE_INT, HOST_HALF_WIDE_INT_PRINT, HOST_HALF_WIDE_INT_PRINT_C, HOST_HALF_WIDE_INT_PRINT_DEC, HOST_HALF_WIDE_INT_PRINT_DEC_C, HOST_HALF_WIDE_INT_PRINT_UNSIGNED, HOST_HALF_WIDE_INT_PRINT_HEX, HOST_HALF_WIDE_INT_PRINT_HEX_PURE): New symbols. (sext_hwi, zext_hwi): New functions. diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..7e5b85c 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ + int shift = HOST_BITS_PER_WIDE_INT - + (prec (HOST_BITS_PER_WIDE_INT - 1)); + return (src shift) shift; +} +} + +/* Zero extend SRC starting from PREC. */ + +unsigned HOST_WIDE_INT +zext_hwi (unsigned HOST_WIDE_INT src, unsigned int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} + +#endif diff --git a/gcc/hwint.h b/gcc/hwint.h index da62fad..9dddf05 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -76,6 +76,40 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1]; # endif #endif +/* Print support for half a host wide int. */ +#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2) +#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG +# define HOST_HALF_WIDE_INT long +# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT +# define HOST_HALF_WIDE_INT_PRINT_C L +# define HOST_HALF_WIDE_INT_PRINT_DEC %
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Richard, did everything that you asked here. bootstrapped and regtested on x86-64. ok to commit? diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..7e5b85c 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) this should go to hwint.h, and without the masking of prec. while ... diff --git a/gcc/hwint.h b/gcc/hwint.h index da62fad..9dddf05 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT); +/* Sign extend SRC starting from PREC. */ + +#ifdef ENABLE_CHECKING +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); +#else +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); this should go to hwint.c (also without masking prec). Richard. kenny On 04/02/2013 05:38 AM, Richard Biener wrote: On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: richard, I was able to add everything except for the checking asserts.While I think that this is a reasonable idea, it is difficult to add that to a function that is defined in hwint.h because of circular includes. I could move this another file (though this appears to be the logical correct place for it), or we can do without the asserts. The context is that [sz]ext_hwi is that are used are over the compiler but are generally written out long. The wide-int class uses them also, but wide-int did not see like the right place for them to live and i believe that you suggested that i move them. ok to commit, or do you have a suggested resolution to the assert issue? Yes, do #ifdef ENABLE_CHECKING extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); #else +/* Sign extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ int shift = HOST_BITS_PER_WIDE_INT - prec; + return (src shift) shift; +} +} #endif and for ENABLE_CHECKING only provide an out-of-line implementation in hwint.c. That's how we did it with abs_hwi (well, we just do not provide an inline variant there - that's another possibility). Note that hwint.h is always included after config.h so the ENABLE_CHECKING definition should be available. Richard. kenny On 03/27/2013 10:13 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The patch misses context of uses, so I'm not sure what the above functions are intended to do. Richard. On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on hosts not supporting %hd (MinGW?), and there's no real need for using h here given the promotion of short to int; you can just use (rather than e.g. needing special handling in xm-mingw32.h like is done for HOST_LONG_LONG_FORMAT).
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: This patch contains a large number of the changes requested by Richi. It does not contain any of the changes that he requested to abstract the storage layer. That suggestion appears to be quite unworkable. I of course took this claim as a challenge ... with the following result. It is of course quite workable ;) The attached patch implements the core wide-int class and three storage models (fixed size for things like plain HWI and double-int, variable size similar to how your wide-int works and an adaptor for the double-int as contained in trees). With that you can now do HOST_WIDE_INT wi_test (tree x) { // template argument deduction doesn't do the magic we want it to do // to make this kind of implicit conversions work // overload resolution considers this kind of conversions so we // need some magic that combines both ... but seeding the overload // set with some instantiations doesn't seem to be possible :/ // wide_int w = x + 1; wide_int w; w += x; w += 1; // template argument deduction doesn't deduce the return value type, // not considering the template default argument either ... // w = wi (x) + 1; // we could support this by providing rvalue-to-lvalue promotion // via a traits class? // otoh it would lead to sub-optimal code anyway so we should // make the result available as reference parameter and only support // wide_int res; add (res, x, 1); ? w = wi (x).operator+wide_int (1); wide_int::add(w, x, 1); return w.to_hwi (); } we are somewhat limited with C++ unless we want to get really fancy. Eventually providing operator+ just doesn't make much sense for generic wide-int combinations (though then the issue is its operands are no longer commutative which I think is the case with your wide-int or double-int as well - they don't suport 1 + wide_int for obvious reasons). So there are implementation design choices left undecided. Oh, and the operation implementations are crap (they compute nonsense). But you should get the idea. Richard. #include config.h #include system.h #include coretypes.h #include hwint.h #include tree.h /* ??? wide-int should probably use HOST_WIDEST_FAST_INT as storage, not HOST_WIDE_INT. Yeah, we could even template on that ... */ /* Fixed-length embedded storage. wi_embed2 is double-int, wi_embed1 is a plain HOST_WIDE_INT. Can be used for small fixed-(minimum)-size calculations on hosts that have no suitable integer type. */ template unsigned sz class wi_embed { private: HOST_WIDE_INT s[sz]; public: void construct () {} HOST_WIDE_INT* storage() { return s; } const HOST_WIDE_INT* storage() const { return s; } unsigned len() const { return sz; } void set_len(unsigned l) { gcc_checking_assert (l = sz); } }; /* Fixed maximum-length embedded storage but variable dynamic size. */ //#define MAXSZ (4 * (MAX_MODE_INT_SIZE / HOST_BITS_PER_WIDE_INT)) #define MAXSZ 8 template unsigned max_sz class wi_embed_var { private: unsigned len_; HOST_WIDE_INT s[max_sz]; public: void construct () { len_ = 0; } HOST_WIDE_INT* storage() { return s; } const HOST_WIDE_INT* storage() const { return s; } unsigned len() const { return len_; } void set_len(unsigned l) { len_ = l; } }; /* The wide-int class. Defaults to variable-length storage (alternatively use a typedef to avoid the need to use wide_int ). */ template class S = wi_embed_varMAXSZ class wide_int; /* Avoid constructors / destructors to make sure this is a C++04 POD. */ /* Basic wide_int class. The storage model allows for rvalue storage abstraction avoiding copying from for example tree or RTX and to avoid the need of explicit construction for integral arguments of up to HWI size. A storage model needs to provide the following methods: - construct (), default-initialize the storage - unsigned len () const, the size of the storage in HWI quantities - const HOST_WIDE_INT *storage () const, return a pointer to read-only HOST_WIDE_INT storage of size len (). - HOST_WIDE_INT *storage (), return a pointer to writable HOST_WIDE_INT storage of size len (). This method is optional. - void set_len (unsigned l), adjust the size of the storage to at least l HWI words. Conversions of wide_int _to_ tree or RTX or HWI are explicit. Conversions to wide_int happen with overloads to the global function template wi () or via wide_int_traits specializations. */ /* ??? With mixed length operations there are encoding issues for signed vs. unsigned numbers. The easiest encoding is to say wide-ints are always signed which means that -1U needs the MSB of the wide-int storage as zero which means an extra word with zeros. The sign-bit of a wide-int is then always storage()[len() (1 (HOST_BITS_PER_WIDE_INT - 1))]. */ template class S class wide_int : private S { /* Allow
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
Yes, I agree that you win the challenge that it can be done.What you have always failed to address is why anyone would want to do this. Or how this would at all be desirable.But I completely agree that from a purely abstract point of view you can add a storage model. Now here is why we REALLY do not want to go down this road: 1) The following comment from your earlier mail is completely wrong +#ifdef NEW_REP_FOR_INT_CST + /* This is the code once the tree level is converted. */ + wide_int result; + int i; + + tree type = TREE_TYPE (tcst); + + result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type)); + result.precision = TYPE_PRECISION (type); + result.len = TREE_INT_CST_LEN (tcst); + for (i = 0; i result.len; i++) +result.val[i] = TREE_INT_CST_ELT (tcst, i); + + return result; +#else this also shows the main reason I was asking for storage abstraction. The initialization from tree is way too expensive. In almost all cases, constants will fit in a single HWI. Thus, the only thing that you are copying is the length and a single HWI. So you are dragging in a lot of machinery just to save these two copies? Certainly there has to be more to it than that. 2) You present this as if the implementor actually should care about the implementation and you give 3 alternatives: the double_int, the current one, and HWI. We have tried to make it so that the client should not care. Certainly in my experience here, I have not found a place to care. In my opinion double_int needs to go away. That is the main thrust of my patches. There is no place in a compiler for an abi that depends on constants fitting into 2 two words whose size is defined by the host. This is not a beauty contest argument, we have public ports are beginning to use modes that are larger than two x86-64 HWIs and i have a private port that has such modes and it is my experience that any pass that uses this interface has one of three behaviors: it silently gets the wrong answer, it ices, or it fails to do the transformation. If we leave double_int as an available option, then any use of it potentially will have one of these three behaviors. And so one of my strong objections to this direction is that i do not want to fight this kind of bug for the rest of my life.Having a single storage model that just always works is in my opinion a highly desirable option. What you have never answered in a concrete manner is, if we decide to provide this generality, what it would be used for.There is no place in a portable compiler where the right answer for every target is two HOST wide integers. However, i will admit that the HWI option has some merits. We try to address this in our implementation by dividing what is done inline in wide-int.h to the cases that fit in an HWI and then only drop into the heavy code in wide-int.c if mode is larger (which it rarely will be). However, a case could be made that for certain kinds of things like string lengths and such, we could use another interface or as you argue, a different storage model with the same interface. I just do not see that the cost of the conversion code is really going to show up on anyone's radar. 3) your trick will work at the tree level, but not at the rtl level. The wide-int code cannot share storage with the CONST_INTs.We tried this, and there are a million bugs that would have to be fixed to make it work.It could have worked if CONST_INTs had carried a mode around, but since they do not, you end up with the same CONST_INT sharing the rep for several different types and that just did not work unless you are willing to do substantial cleanups. On 04/02/2013 11:04 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: This patch contains a large number of the changes requested by Richi. It does not contain any of the changes that he requested to abstract the storage layer. That suggestion appears to be quite unworkable. I of course took this claim as a challenge ... with the following result. It is of course quite workable ;) The attached patch implements the core wide-int class and three storage models (fixed size for things like plain HWI and double-int, variable size similar to how your wide-int works and an adaptor for the double-int as contained in trees). With that you can now do HOST_WIDE_INT wi_test (tree x) { // template argument deduction doesn't do the magic we want it to do // to make this kind of implicit conversions work // overload resolution considers this kind of conversions so we // need some magic that combines both ... but seeding the overload // set with some instantiations doesn't seem to be possible :/ // wide_int w = x + 1; wide_int w; w += x; w += 1; // template argument deduction doesn't deduce the return value type, // not considering the template default argument
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
this time for sure. kenny On 04/02/2013 10:54 AM, Richard Biener wrote: On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: Richard, did everything that you asked here. bootstrapped and regtested on x86-64. ok to commit? diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..7e5b85c 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) this should go to hwint.h, and without the masking of prec. while ... diff --git a/gcc/hwint.h b/gcc/hwint.h index da62fad..9dddf05 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT); +/* Sign extend SRC starting from PREC. */ + +#ifdef ENABLE_CHECKING +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); +#else +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); this should go to hwint.c (also without masking prec). Richard. kenny On 04/02/2013 05:38 AM, Richard Biener wrote: On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: richard, I was able to add everything except for the checking asserts.While I think that this is a reasonable idea, it is difficult to add that to a function that is defined in hwint.h because of circular includes. I could move this another file (though this appears to be the logical correct place for it), or we can do without the asserts. The context is that [sz]ext_hwi is that are used are over the compiler but are generally written out long. The wide-int class uses them also, but wide-int did not see like the right place for them to live and i believe that you suggested that i move them. ok to commit, or do you have a suggested resolution to the assert issue? Yes, do #ifdef ENABLE_CHECKING extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int); #else +/* Sign extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ int shift = HOST_BITS_PER_WIDE_INT - prec; + return (src shift) shift; +} +} #endif and for ENABLE_CHECKING only provide an out-of-line implementation in hwint.c. That's how we did it with abs_hwi (well, we just do not provide an inline variant there - that's another possibility). Note that hwint.h is always included after config.h so the ENABLE_CHECKING definition should be available. Richard. kenny On 03/27/2013 10:13 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The patch misses context of uses, so I'm not sure what the above functions are intended to do. Richard. On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on hosts not supporting %hd (MinGW?), and there's no real need for using h here given the promotion of short to int; you can just use (rather than e.g. needing special handling in xm-mingw32.h like is done for HOST_LONG_LONG_FORMAT). diff --git a/gcc/hwint.c b/gcc/hwint.c index 330b42c..92d54a3 100644 --- a/gcc/hwint.c +++ b/gcc/hwint.c @@ -204,3 +204,35 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b) { return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b)); } + +#ifndef ENABLE_CHECKING +/* Sign extend SRC starting from PREC. */ + +HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, unsigned int prec) +{ + gcc_checking_assert (prec = HOST_BITS_PER_WIDE_INT); + + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ + int shift = HOST_BITS_PER_WIDE_INT - prec; + return (src shift) shift; +} +} + +/* Zero extend SRC starting
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
richard, I was able to add everything except for the checking asserts.While I think that this is a reasonable idea, it is difficult to add that to a function that is defined in hwint.h because of circular includes. I could move this another file (though this appears to be the logical correct place for it), or we can do without the asserts. The context is that [sz]ext_hwi is that are used are over the compiler but are generally written out long. The wide-int class uses them also, but wide-int did not see like the right place for them to live and i believe that you suggested that i move them. ok to commit, or do you have a suggested resolution to the assert issue? kenny On 03/27/2013 10:13 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The patch misses context of uses, so I'm not sure what the above functions are intended to do. Richard. On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on hosts not supporting %hd (MinGW?), and there's no real need for using h here given the promotion of short to int; you can just use (rather than e.g. needing special handling in xm-mingw32.h like is done for HOST_LONG_LONG_FORMAT). diff --git a/gcc/hwint.h b/gcc/hwint.h index da62fad..b086af0 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -76,6 +76,40 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1]; # endif #endif +/* Print support for half a host wide int. */ +#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2) +#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG +# define HOST_HALF_WIDE_INT long +# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT +# define HOST_HALF_WIDE_INT_PRINT_C L +# define HOST_HALF_WIDE_INT_PRINT_DEC % HOST_HALF_WIDE_INT_PRINT d +# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED % HOST_HALF_WIDE_INT_PRINT u +# define HOST_HALF_WIDE_INT_PRINT_HEX %# HOST_HALF_WIDE_INT_PRINT x +# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE % HOST_HALF_WIDE_INT_PRINT x +#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT +# define HOST_HALF_WIDE_INT int +# define HOST_HALF_WIDE_INT_PRINT +# define HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_DEC % HOST_HALF_WIDE_INT_PRINT d +# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED % HOST_HALF_WIDE_INT_PRINT u +# define HOST_HALF_WIDE_INT_PRINT_HEX %# HOST_HALF_WIDE_INT_PRINT x +# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE % HOST_HALF_WIDE_INT_PRINT x +#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_SHORT +# define HOST_HALF_WIDE_INT short +# define HOST_HALF_WIDE_INT_PRINT +# define HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_DEC % HOST_HALF_WIDE_INT_PRINT d +# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED % HOST_HALF_WIDE_INT_PRINT u +# define HOST_HALF_WIDE_INT_PRINT_HEX %# HOST_HALF_WIDE_INT_PRINT x +# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE % HOST_HALF_WIDE_INT_PRINT x +#else +#error Please add support for HOST_HALF_WIDE_INT +#endif + + #define HOST_WIDE_INT_1 HOST_WIDE_INT_C(1) /* This is a magic identifier which allows GCC to figure out the type @@ -93,9 +127,13 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__; # if HOST_BITS_PER_WIDE_INT == 64 # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \ 0x% HOST_LONG_FORMAT x%016 HOST_LONG_FORMAT x +# define HOST_WIDE_INT_PRINT_PADDED_HEX \ + %016 HOST_LONG_FORMAT x # else # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \ 0x% HOST_LONG_FORMAT x%08 HOST_LONG_FORMAT x +# define HOST_WIDE_INT_PRINT_PADDED_HEX \ + %08 HOST_LONG_FORMAT x # endif #else # define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT @@ -103,6 +141,8 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__; /* We can assume that 'long long' is at least 64 bits. */ # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \ 0x% HOST_LONG_LONG_FORMAT x%016
Re: patch to fix constant math - third patch - what is left for next stage 1
committed as revision 197198 kenny On 03/27/2013 10:19 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:37 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: the original patch 3 was accepted and committed. These were subsequent comments. This could likely be just checked in the next stage 1 without approval. Ok. Thanks, Richard.
Re: patch to fix constant math - second small patch -patch ping for next stage 1
committed as revision 197200. kenny On 03/27/2013 11:07 AM, Richard Biener wrote: On Wed, Mar 27, 2013 at 3:23 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 03/27/2013 10:18 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:27 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the second of my wide int patches with the patch rot removed. I would like to get these pre approved for the next stage 1. On 10/05/2012 06:48 PM, Kenneth Zadeck wrote: This patch adds machinery to genmodes.c so that largest possible sizes of various data structures can be determined at gcc build time. These functions create 3 symbols that are available in insn-modes.h: MAX_BITSIZE_MODE_INT - the bitsize of the largest int. MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int. MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int. I remember we have discussed about the need to special-case/handle partial integer modes. Do further patches use the _INT and _PARTIAL_INT sizes at all? I'm fine with providing MAX_BITSIZE_MODE_ANY_INT. i do not believe that in the end, those two ended up getting used.i can remove them if you want. Yes please. Ok with that change. Richard. kenny Richard.
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
richard, adding the gcc_checking_assert is going to require that i include system.h in hwint.h which seems to cause a loop. while in principle, i agree with the assert, this is going to be a mess. kenny On 03/27/2013 10:13 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The patch misses context of uses, so I'm not sure what the above functions are intended to do. Richard. On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on hosts not supporting %hd (MinGW?), and there's no real need for using h here given the promotion of short to int; you can just use (rather than e.g. needing special handling in xm-mingw32.h like is done for HOST_LONG_LONG_FORMAT).
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); I think this should gcc_checking_assert that prec is not out of range (any reason why prec is signed int and not unsigned int?) rather than ignore bits in prec. +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} likewise. Also I'm not sure I agree about the signedness of the result / src. zext_hwi (-1, HOST_BITS_PER_WIDE_INT) 0 is true which is odd. The patch misses context of uses, so I'm not sure what the above functions are intended to do. Richard. On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on hosts not supporting %hd (MinGW?), and there's no real need for using h here given the promotion of short to int; you can just use (rather than e.g. needing special handling in xm-mingw32.h like is done for HOST_LONG_LONG_FORMAT).
Re: patch to fix constant math - second small patch -patch ping for next stage 1
On Wed, Feb 27, 2013 at 1:27 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the second of my wide int patches with the patch rot removed. I would like to get these pre approved for the next stage 1. On 10/05/2012 06:48 PM, Kenneth Zadeck wrote: This patch adds machinery to genmodes.c so that largest possible sizes of various data structures can be determined at gcc build time. These functions create 3 symbols that are available in insn-modes.h: MAX_BITSIZE_MODE_INT - the bitsize of the largest int. MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int. MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int. I remember we have discussed about the need to special-case/handle partial integer modes. Do further patches use the _INT and _PARTIAL_INT sizes at all? I'm fine with providing MAX_BITSIZE_MODE_ANY_INT. Richard.
Re: patch to fix constant math - third patch - what is left for next stage 1
On Wed, Feb 27, 2013 at 1:37 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: the original patch 3 was accepted and committed. These were subsequent comments. This could likely be just checked in the next stage 1 without approval. Ok. Thanks, Richard.
Re: patch to fix constant math - second small patch -patch ping for next stage 1
On 03/27/2013 10:18 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:27 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the second of my wide int patches with the patch rot removed. I would like to get these pre approved for the next stage 1. On 10/05/2012 06:48 PM, Kenneth Zadeck wrote: This patch adds machinery to genmodes.c so that largest possible sizes of various data structures can be determined at gcc build time. These functions create 3 symbols that are available in insn-modes.h: MAX_BITSIZE_MODE_INT - the bitsize of the largest int. MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int. MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int. I remember we have discussed about the need to special-case/handle partial integer modes. Do further patches use the _INT and _PARTIAL_INT sizes at all? I'm fine with providing MAX_BITSIZE_MODE_ANY_INT. i do not believe that in the end, those two ended up getting used.i can remove them if you want. kenny Richard.
Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: This patch contains a large number of the changes requested by Richi. It does not contain any of the changes that he requested to abstract the storage layer. That suggestion appears to be quite unworkable. I believe that the wide-int class addresses the needs of gcc for performing math on any size integer irregardless of the platform that hosts the compiler. The interface is admittedly large, but it is large for a reason: these are the operations that are commonly performed by the client optimizations in the compiler. I would like to get this patch preapproved for the next stage 1. Please clean from dead code like +// using wide_int::; and +#ifdef DEBUG_WIDE_INT + if (dump_file) +debug_wh (wide_int::from_shwi %s HOST_WIDE_INT_PRINT_HEX )\n, + result, op0); +#endif and +#ifdef NEW_REP_FOR_INT_CST + /* This is the code once the tree level is converted. */ + wide_int result; + int i; + + tree type = TREE_TYPE (tcst); + + result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type)); + result.precision = TYPE_PRECISION (type); + result.len = TREE_INT_CST_LEN (tcst); + for (i = 0; i result.len; i++) +result.val[i] = TREE_INT_CST_ELT (tcst, i); + + return result; +#else this also shows the main reason I was asking for storage abstraction. The initialization from tree is way too expensive. +/* Convert a integer cst into a wide int expanded to BITSIZE and + PRECISION. This call is used by tree passes like vrp that expect + that the math is done in an infinite precision style. BITSIZE and + PRECISION are generally determined to be twice the largest type + seen in the function. */ + +wide_int +wide_int::from_tree_as_infinite_precision (const_tree tcst, + unsigned int bitsize, + unsigned int precision) +{ I know you have converted everything, but to make this patch reviewable I'd like you to strip the initial wide_int down to a bare minimum. Only then people will have a reasonable chance to play with interface changes (such as providing a storage abstraction). +/* Check the upper HOST_WIDE_INTs of src to see if the length can be + shortened. An upper HOST_WIDE_INT is unnecessary if it is all ones + or zeros and the top bit of the next lower word matches. + + This function may change the representation of THIS, but does not + change the value that THIS represents. It does not sign extend in + the case that the size of the mode is less than + HOST_BITS_PER_WIDE_INT. */ + +void +wide_int::canonize () this shouldn't be necessary - it's an optimization - and due to value semantics (yes - I know you have a weird mix of value semantics and modify-in-place in wide_int) the new length should be computed transparently when creating a new value. Well. Leaving wide-int.c for now. +class wide_int { + /* Internal representation. */ + + /* VAL is set to a size that is capable of computing a full + multiplication on the largest mode that is represented on the + target. The full multiplication is use by tree-vrp. tree-vpn + currently does a 2x largest mode by 2x largest mode yielding a 4x + largest mode result. If operations are added that require larger + buffers, then VAL needs to be changed. */ + HOST_WIDE_INT val[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; as you conver partial int modes in MAX_BITSIZE_MODE_ANY_INT the above may come too short. Please properly round up. + unsigned short len; + unsigned int bitsize; + unsigned int precision; I see we didn't get away with this mix of bitsize and precision. I'm probably going to try revisit the past discussions - but can you point me to a single place in the RTL conversion where they make a difference? Bits beyond precision are either undefined or properly zero-/sign-extended. Implicit extension beyond len val members should then provide in valid bits up to bitsize (if anyone cares). That's how double-ints work on tree INTGER_CSTs which only care for precision, even with partial integer mode types (ok, I never came along one of these beasts - testcase / target?). [abstraction possibility - have both wide_ints with actual mode and wide_ints with arbitrary bitsize/precision] + enum ShiftOp { +NONE, +/* There are two uses for the wide-int shifting functions. The + first use is as an emulation of the target hardware. The + second use is as service routines for other optimizations. The + first case needs to be identified by passing TRUNC as the value + of ShiftOp so that shift amount is properly handled according to the + SHIFT_COUNT_TRUNCATED flag. For the second case, the shift + amount is always truncated by the bytesize of the mode of + THIS. */ +TRUNC + }; I think I have expressed my opinion on this. (and SHIFT_COUNT_TRUNCATED
Re: patch to fix constant math - second small patch -patch ping for next stage 1
On Wed, Mar 27, 2013 at 3:23 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 03/27/2013 10:18 AM, Richard Biener wrote: On Wed, Feb 27, 2013 at 1:27 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: Here is the second of my wide int patches with the patch rot removed. I would like to get these pre approved for the next stage 1. On 10/05/2012 06:48 PM, Kenneth Zadeck wrote: This patch adds machinery to genmodes.c so that largest possible sizes of various data structures can be determined at gcc build time. These functions create 3 symbols that are available in insn-modes.h: MAX_BITSIZE_MODE_INT - the bitsize of the largest int. MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int. MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int. I remember we have discussed about the need to special-case/handle partial integer modes. Do further patches use the _INT and _PARTIAL_INT sizes at all? I'm fine with providing MAX_BITSIZE_MODE_ANY_INT. i do not believe that in the end, those two ended up getting used.i can remove them if you want. Yes please. Ok with that change. Richard. kenny Richard.
Re: patch to fix constant math - first small patch - patch ping for the next stage 1
Here is the first of my wide int patches with joseph's comments and the patch rot removed. I would like to get these pre approved for the next stage 1. On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on hosts not supporting %hd (MinGW?), and there's no real need for using h here given the promotion of short to int; you can just use (rather than e.g. needing special handling in xm-mingw32.h like is done for HOST_LONG_LONG_FORMAT). 2013-2-26 Kenneth Zadeck zad...@naturalbridge.com * hwint.h (HOST_BITS_PER_HALF_WIDE_INT, HOST_HALF_WIDE_INT, HOST_HALF_WIDE_INT_PRINT, HOST_HALF_WIDE_INT_PRINT_C, HOST_HALF_WIDE_INT_PRINT_DEC, HOST_HALF_WIDE_INT_PRINT_DEC_C, HOST_HALF_WIDE_INT_PRINT_UNSIGNED, HOST_HALF_WIDE_INT_PRINT_HEX, HOST_HALF_WIDE_INT_PRINT_HEX_PURE): New symbols. (sext_hwi, zext_hwi): New functions. diff --git a/gcc/hwint.h b/gcc/hwint.h index da62fad..aaa66ed 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -76,6 +76,40 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1]; # endif #endif +/* Print support for half a host wide int. */ +#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2) +#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG +# define HOST_HALF_WIDE_INT long +# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT +# define HOST_HALF_WIDE_INT_PRINT_C L +# define HOST_HALF_WIDE_INT_PRINT_DEC % HOST_HALF_WIDE_INT_PRINT d +# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED % HOST_HALF_WIDE_INT_PRINT u +# define HOST_HALF_WIDE_INT_PRINT_HEX %# HOST_HALF_WIDE_INT_PRINT x +# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE % HOST_HALF_WIDE_INT_PRINT x +#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT +# define HOST_HALF_WIDE_INT int +# define HOST_HALF_WIDE_INT_PRINT +# define HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_DEC % HOST_HALF_WIDE_INT_PRINT d +# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED % HOST_HALF_WIDE_INT_PRINT u +# define HOST_HALF_WIDE_INT_PRINT_HEX %# HOST_HALF_WIDE_INT_PRINT x +# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE % HOST_HALF_WIDE_INT_PRINT x +#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_SHORT +# define HOST_HALF_WIDE_INT short +# define HOST_HALF_WIDE_INT_PRINT +# define HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_DEC % HOST_HALF_WIDE_INT_PRINT d +# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED % HOST_HALF_WIDE_INT_PRINT u +# define HOST_HALF_WIDE_INT_PRINT_HEX %# HOST_HALF_WIDE_INT_PRINT x +# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE % HOST_HALF_WIDE_INT_PRINT x +#else +#error Please add support for HOST_HALF_WIDE_INT +#endif + + #define HOST_WIDE_INT_1 HOST_WIDE_INT_C(1) /* This is a magic identifier which allows GCC to figure out the type @@ -93,9 +127,13 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__; # if HOST_BITS_PER_WIDE_INT == 64 # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \ 0x% HOST_LONG_FORMAT x%016 HOST_LONG_FORMAT x +# define HOST_WIDE_INT_PRINT_PADDED_HEX \ + %016 HOST_LONG_FORMAT x # else # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \ 0x% HOST_LONG_FORMAT x%08 HOST_LONG_FORMAT x +# define HOST_WIDE_INT_PRINT_PADDED_HEX \ + %08 HOST_LONG_FORMAT x # endif #else # define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT @@ -103,6 +141,8 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__; /* We can assume that 'long long' is at least 64 bits. */ # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \ 0x% HOST_LONG_LONG_FORMAT x%016 HOST_LONG_LONG_FORMAT x +# define HOST_WIDE_INT_PRINT_PADDED_HEX \ +%016 HOST_LONG_LONG_FORMAT x #endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */ #define HOST_WIDE_INT_PRINT_DEC % HOST_WIDE_INT_PRINT d @@ -276,4 +316,32 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT); +/* Sign extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); + return (src shift) shift; +} +} + +/* Zero extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} + + + #endif /* ! GCC_HWINT_H */
Re: patch to fix constant math - second small patch -patch ping for next stage 1
Here is the second of my wide int patches with the patch rot removed. I would like to get these pre approved for the next stage 1. On 10/05/2012 06:48 PM, Kenneth Zadeck wrote: This patch adds machinery to genmodes.c so that largest possible sizes of various data structures can be determined at gcc build time. These functions create 3 symbols that are available in insn-modes.h: MAX_BITSIZE_MODE_INT - the bitsize of the largest int. MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int. MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int. 2013-2-26 Kenneth Zadeck zad...@naturalbridge.com * genmodes.c (emit_max_int): New function. (emit_insn_modes_h): Added call to emit_max_function. * doc/rtl.texi (MAX_BITSIZE_MODE_INT, MAX_BITSIZE_MODE_PARTIAL_INT, MAX_BITSIZE_MODE_ANY_INT, MAX_BITSIZE_MODE_ANY_MODE): Added doc. * machmode.def: Fixed comment. diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index b0b0723..095a642 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -1456,6 +1456,28 @@ Returns the number of units contained in a mode, i.e., Returns the narrowest mode in mode class @var{c}. @end table +The following 4 variables are defined on every target. They can be +used to allocate buffers that are guaranteed to be large enough to +hold any value that can be represented on the target. + +@table @code +@findex MAX_BITSIZE_MODE_INT +@item MAX_BITSIZE_MODE_INT +The bitsize of the largest integer mode defined on the target. + +@findex MAX_BITSIZE_MODE_PARTIAL_INT +@item MAX_BITSIZE_MODE_PARTIAL_INT +The bitsize of the largest partial integer mode defined on the target. + +@findex MAX_BITSIZE_MODE_ANY_INT +@item MAX_BITSIZE_MODE_ANY_INT +The maximum of MAX_BITSIZE_MODE_INT and MAX_BITSIZE_MODE_PARTIAL_INT. + +@findex MAX_BITSIZE_MODE_ANY_MODE +@item MAX_BITSIZE_MODE_ANY_MODE +The bitsize of the largest mode on the target. +@end table + @findex byte_mode @findex word_mode The global variables @code{byte_mode} and @code{word_mode} contain modes diff --git a/gcc/genmodes.c b/gcc/genmodes.c index 9907d69..f822dcd 100644 --- a/gcc/genmodes.c +++ b/gcc/genmodes.c @@ -848,6 +848,38 @@ calc_wider_mode (void) #define print_closer() puts (};) +/* Compute the max bitsize of some of the classes of integers. It may + be that there are needs for the other integer classes, and this + code is easy to extend. */ +static void +emit_max_int (void) +{ + unsigned int max, mmax; + struct mode_data *i; + int j; + + puts (); + for (max = 1, i = modes[MODE_INT]; i; i = i-next) +if (max i-bytesize) + max = i-bytesize; + printf (#define MAX_BITSIZE_MODE_INT %d*BITS_PER_UNIT\n, max); + mmax = max; + for (max = 1, i = modes[MODE_PARTIAL_INT]; i; i = i-next) +if (max i-bytesize) + max = i-bytesize; + printf (#define MAX_BITSIZE_MODE_PARTIAL_INT %d*BITS_PER_UNIT\n, max); + if (max mmax) +mmax = max; + printf (#define MAX_BITSIZE_MODE_ANY_INT %d*BITS_PER_UNIT\n, mmax); + + mmax = 0; + for (j = 0; j MAX_MODE_CLASS; j++) +for (i = modes[j]; i; i = i-next) + if (mmax i-bytesize) + mmax = i-bytesize; + printf (#define MAX_BITSIZE_MODE_ANY_MODE %d*BITS_PER_UNIT\n, mmax); +} + static void emit_insn_modes_h (void) { @@ -912,6 +944,7 @@ enum machine_mode\n{); #endif printf (#define CONST_MODE_IBIT%s\n, adj_ibit ? : const); printf (#define CONST_MODE_FBIT%s\n, adj_fbit ? : const); + emit_max_int (); puts (\ \n\ #endif /* insn-modes.h */); diff --git a/gcc/machmode.def b/gcc/machmode.def index 4b58150..1062f18 100644 --- a/gcc/machmode.def +++ b/gcc/machmode.def @@ -179,8 +179,11 @@ RANDOM_MODE (BLK); FRACTIONAL_INT_MODE (BI, 1, 1); /* Basic integer modes. We go up to TI in generic code (128 bits). - The name OI is reserved for a 256-bit type (needed by some back ends). - FIXME TI shouldn't be generically available either. */ + TImode is needed here because the some front ends now genericly + support __int128. If the front ends decide to generically support + larger types, then corresponding modes must be added here. The + name OI is reserved for a 256-bit type (needed by some back ends). +*/ INT_MODE (QI, 1); INT_MODE (HI, 2); INT_MODE (SI, 4);
Re: patch to fix constant math - second small patch
On Thu, Nov 8, 2012 at 7:13 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: I have added the proper doc. OK to commit? Ok. Thanks, Richard. Kenny On 10/08/2012 05:06 AM, Richard Guenther wrote: On Sat, Oct 6, 2012 at 12:48 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: This patch adds machinery to genmodes.c so that largest possible sizes of various data structures can be determined at gcc build time. These functions create 3 symbols that are available in insn-modes.h: MAX_BITSIZE_MODE_INT - the bitsize of the largest int. MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int. MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int. Ok. Please document these macros in rtl.texi. Richard.
Re: patch to fix constant math - third small patch
This patch is an updated version of my patch 3 with all of richard sandiford's comments resolved. Richi had approved it before he went on vacation. Committed as revision 193360. Kenny On 10/08/2012 03:42 PM, Richard Sandiford wrote: Kenneth Zadeck zad...@naturalbridge.com writes: diff --git a/gcc/combine.c b/gcc/combine.c index 4e0a579..b531305 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -2617,16 +2617,19 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p, constant. */ if (i1 == 0 (temp = single_set (i2)) != 0 - (CONST_INT_P (SET_SRC (temp)) - || CONST_DOUBLE_AS_INT_P (SET_SRC (temp))) + CONST_SCALAR_INT_P (SET_SRC (temp)) GET_CODE (PATTERN (i3)) == SET - (CONST_INT_P (SET_SRC (PATTERN (i3))) - || CONST_DOUBLE_AS_INT_P (SET_SRC (PATTERN (i3 + CONST_SCALAR_INT_P (SET_SRC (PATTERN (i3))) reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp))) { rtx dest = SET_DEST (PATTERN (i3)); int offset = -1; int width = 0; + + /* There are not explicit tests to make sure that this is not a +float, but there is code here that would not be correct if it +was. */ + gcc_assert (GET_MODE_CLASS (GET_MODE (SET_SRC (temp))) != MODE_FLOAT); No need for this assert: CONST_SCALAR_INT_P (SET_SRC (temp)) should cover it. @@ -1009,9 +1007,7 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode) static rtx wrap_constant (enum machine_mode mode, rtx x) { - if (!CONST_INT_P (x) - GET_CODE (x) != CONST_FIXED - !CONST_DOUBLE_AS_INT_P (x)) + if ((!CONST_SCALAR_INT_P (x)) GET_CODE (x) != CONST_FIXED) Redundant brackets. Looks good to me otherwise, thanks. Richard 2012-11-09 Kenneth Zadeck zad...@naturalbridge.com * rtl.h (CONST_SCALAR_INT_P): New macro. * cfgexpand.c (expand_debug_locations): Changed to use CONST_SCALAR_INT_P macro. * combine.c (try_combine, subst, make_extraction, gen_lowpart_for_combine): Ditto. * cselib.c (entry_and_rtx_equal_p, rtx_equal_for_cselib_1): Ditto. * dwarf2out.c (loc_descriptor): Ditto. * emit-rtl.c (gen_lowpart_common): Ditto. * ira-costs.c (record_reg_classes, record_address_regs): Ditto. * ira-lives.c (single_reg_class): Ditto. * recog.c (simplify_while_replacing, asm_operand_ok, constrain_operands): Ditto. * reload.c (find_reloads): Ditto. * simplify-rtx.c (simplify_unary_operation_1, simplify_const_unary_operation, simplify_binary_operation_1, simplify_const_binary_operation, simplify_relational_operation_1, simplify_subreg): Ditto. diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index e501b4b..0bd9d1d 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -3647,9 +3647,8 @@ expand_debug_locations (void) gcc_assert (mode == GET_MODE (val) || (GET_MODE (val) == VOIDmode - (CONST_INT_P (val) + (CONST_SCALAR_INT_P (val) || GET_CODE (val) == CONST_FIXED -|| CONST_DOUBLE_AS_INT_P (val) || GET_CODE (val) == LABEL_REF))); } diff --git a/gcc/combine.c b/gcc/combine.c index 00719a7..5e85f77 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -2619,17 +2619,15 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p, constant. */ if (i1 == 0 (temp = single_set (i2)) != 0 - (CONST_INT_P (SET_SRC (temp)) - || CONST_DOUBLE_AS_INT_P (SET_SRC (temp))) + CONST_SCALAR_INT_P (SET_SRC (temp)) GET_CODE (PATTERN (i3)) == SET - (CONST_INT_P (SET_SRC (PATTERN (i3))) - || CONST_DOUBLE_AS_INT_P (SET_SRC (PATTERN (i3 + CONST_SCALAR_INT_P (SET_SRC (PATTERN (i3))) reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp))) { rtx dest = SET_DEST (PATTERN (i3)); int offset = -1; int width = 0; - + if (GET_CODE (dest) == ZERO_EXTRACT) { if (CONST_INT_P (XEXP (dest, 1)) @@ -5104,8 +5102,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy) if (GET_CODE (new_rtx) == CLOBBER XEXP (new_rtx, 0) == const0_rtx) return new_rtx; - if (GET_CODE (x) == SUBREG - (CONST_INT_P (new_rtx) || CONST_DOUBLE_AS_INT_P (new_rtx))) + if (GET_CODE (x) == SUBREG CONST_SCALAR_INT_P (new_rtx)) { enum machine_mode mode = GET_MODE (x); @@ -7134,7 +7131,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos, if (mode == tmode) return new_rtx; - if (CONST_INT_P (new_rtx) || CONST_DOUBLE_AS_INT_P (new_rtx)) + if (CONST_SCALAR_INT_P (new_rtx)) return simplify_unary_operation (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, new_rtx, tmode); @@ -10658,8 +10655,7 @@ gen_lowpart_for_combine (enum machine_mode omode, rtx x) /* We can only support MODE being wider than a word if X is a constant integer or has a mode the same size.
Re: patch to fix constant math - first small patch
Joseph, Here is a revised patch with the change you asked for. There have been no other comments. May I commit it? Kenny On 10/05/2012 08:14 PM, Joseph S. Myers wrote: On Fri, 5 Oct 2012, Kenneth Zadeck wrote: +# define HOST_HALF_WIDE_INT_PRINT h This may cause problems on hosts not supporting %hd (MinGW?), and there's no real need for using h here given the promotion of short to int; you can just use (rather than e.g. needing special handling in xm-mingw32.h like is done for HOST_LONG_LONG_FORMAT). diff --git a/gcc/hwint.h b/gcc/hwint.h index ca47148..87371b5 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -77,6 +77,40 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1]; # endif #endif +/* Print support for half a host wide int. */ +#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2) +#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG +# define HOST_HALF_WIDE_INT long +# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT +# define HOST_HALF_WIDE_INT_PRINT_C L +# define HOST_HALF_WIDE_INT_PRINT_DEC % HOST_HALF_WIDE_INT_PRINT d +# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED % HOST_HALF_WIDE_INT_PRINT u +# define HOST_HALF_WIDE_INT_PRINT_HEX %# HOST_HALF_WIDE_INT_PRINT x +# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE % HOST_HALF_WIDE_INT_PRINT x +#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT +# define HOST_HALF_WIDE_INT int +# define HOST_HALF_WIDE_INT_PRINT +# define HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_DEC % HOST_HALF_WIDE_INT_PRINT d +# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED % HOST_HALF_WIDE_INT_PRINT u +# define HOST_HALF_WIDE_INT_PRINT_HEX %# HOST_HALF_WIDE_INT_PRINT x +# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE % HOST_HALF_WIDE_INT_PRINT x +#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_SHORT +# define HOST_HALF_WIDE_INT short +# define HOST_HALF_WIDE_INT_PRINT +# define HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_DEC % HOST_HALF_WIDE_INT_PRINT d +# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C +# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED % HOST_HALF_WIDE_INT_PRINT u +# define HOST_HALF_WIDE_INT_PRINT_HEX %# HOST_HALF_WIDE_INT_PRINT x +# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE % HOST_HALF_WIDE_INT_PRINT x +#else +#error Please add support for HOST_HALF_WIDE_INT +#endif + + #define HOST_WIDE_INT_1 HOST_WIDE_INT_C(1) /* This is a magic identifier which allows GCC to figure out the type @@ -94,9 +128,13 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__; # if HOST_BITS_PER_WIDE_INT == 64 # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \ 0x% HOST_LONG_FORMAT x%016 HOST_LONG_FORMAT x +# define HOST_WIDE_INT_PRINT_PADDED_HEX \ + %016 HOST_LONG_FORMAT x # else # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \ 0x% HOST_LONG_FORMAT x%08 HOST_LONG_FORMAT x +# define HOST_WIDE_INT_PRINT_PADDED_HEX \ + %08 HOST_LONG_FORMAT x # endif #else # define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT @@ -104,6 +142,8 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__; /* We can assume that 'long long' is at least 64 bits. */ # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \ 0x% HOST_LONG_LONG_FORMAT x%016 HOST_LONG_LONG_FORMAT x +# define HOST_WIDE_INT_PRINT_PADDED_HEX \ +%016 HOST_LONG_LONG_FORMAT x #endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */ #define HOST_WIDE_INT_PRINT_DEC % HOST_WIDE_INT_PRINT d @@ -277,4 +317,32 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT); +/* Sign extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +sext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +{ + int shift = HOST_BITS_PER_WIDE_INT - (prec (HOST_BITS_PER_WIDE_INT - 1)); + return (src shift) shift; +} +} + +/* Zero extend SRC starting from PREC. */ + +static inline HOST_WIDE_INT +zext_hwi (HOST_WIDE_INT src, int prec) +{ + if (prec == HOST_BITS_PER_WIDE_INT) +return src; + else +return src (((HOST_WIDE_INT)1 + (prec (HOST_BITS_PER_WIDE_INT - 1))) - 1); +} + + + #endif /* ! GCC_HWINT_H */ 2012-10-5 Kenneth Zadeck zad...@naturalbridge.com * hwint.h (HOST_BITS_PER_HALF_WIDE_INT, HOST_HALF_WIDE_INT, HOST_HALF_WIDE_INT_PRINT, HOST_HALF_WIDE_INT_PRINT_C, HOST_HALF_WIDE_INT_PRINT_DEC, HOST_HALF_WIDE_INT_PRINT_DEC_C, HOST_HALF_WIDE_INT_PRINT_UNSIGNED, HOST_HALF_WIDE_INT_PRINT_HEX, HOST_HALF_WIDE_INT_PRINT_HEX_PURE): New symbols. (sext_hwi, zext_hwi): New functions.
Re: patch to fix constant math - second small patch
I have added the proper doc. OK to commit? Kenny On 10/08/2012 05:06 AM, Richard Guenther wrote: On Sat, Oct 6, 2012 at 12:48 AM, Kenneth Zadeck zad...@naturalbridge.com wrote: This patch adds machinery to genmodes.c so that largest possible sizes of various data structures can be determined at gcc build time. These functions create 3 symbols that are available in insn-modes.h: MAX_BITSIZE_MODE_INT - the bitsize of the largest int. MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int. MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int. Ok. Please document these macros in rtl.texi. Richard. 2012-11-8 Kenneth Zadeck zad...@naturalbridge.com * genmodes.c (emit_max_int): New function. (emit_insn_modes_h): Added call to emit_max_function. * doc/rtl.texi (MAX_BITSIZE_MODE_INT, MAX_BITSIZE_MODE_PARTIAL_INT, MAX_BITSIZE_MODE_ANY_INT, MAX_BITSIZE_MODE_ANY_MODE): Added doc. diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 07c480d..6842cb8 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -1458,6 +1458,28 @@ Returns the number of units contained in a mode, i.e., Returns the narrowest mode in mode class @var{c}. @end table +The following 4 variables are defined on every target. They can be +used to allocate buffers that are guaranteed to be large enough to +hold any value that can be represented on the target. + +@table @code +@findex MAX_BITSIZE_MODE_INT +@item MAX_BITSIZE_MODE_INT +The bitsize of the largest integer mode defined on the target. + +@findex MAX_BITSIZE_MODE_PARTIAL_INT +@item MAX_BITSIZE_MODE_PARTIAL_INT +The bitsize of the largest partial integer mode defined on the target. + +@findex MAX_BITSIZE_MODE_ANY_INT +@item MAX_BITSIZE_MODE_ANY_INT +The maximum of MAX_BITSIZE_MODE_INT and MAX_BITSIZE_MODE_PARTIAL_INT. + +@findex MAX_BITSIZE_MODE_ANY_MODE +@item MAX_BITSIZE_MODE_ANY_MODE +The bitsize of the largest mode on the target. +@end table + @findex byte_mode @findex word_mode The global variables @code{byte_mode} and @code{word_mode} contain modes diff --git a/gcc/genmodes.c b/gcc/genmodes.c index d0095c3..3e63cc7 100644 --- a/gcc/genmodes.c +++ b/gcc/genmodes.c @@ -849,6 +849,38 @@ calc_wider_mode (void) #define print_closer() puts (};) +/* Compute the max bitsize of some of the classes of integers. It may + be that there are needs for the other integer classes, and this + code is easy to extend. */ +static void +emit_max_int (void) +{ + unsigned int max, mmax; + struct mode_data *i; + int j; + + puts (); + for (max = 1, i = modes[MODE_INT]; i; i = i-next) +if (max i-bytesize) + max = i-bytesize; + printf (#define MAX_BITSIZE_MODE_INT %d*BITS_PER_UNIT\n, max); + mmax = max; + for (max = 1, i = modes[MODE_PARTIAL_INT]; i; i = i-next) +if (max i-bytesize) + max = i-bytesize; + printf (#define MAX_BITSIZE_MODE_PARTIAL_INT %d*BITS_PER_UNIT\n, max); + if (max mmax) +mmax = max; + printf (#define MAX_BITSIZE_MODE_ANY_INT %d*BITS_PER_UNIT\n, mmax); + + mmax = 0; + for (j = 0; j MAX_MODE_CLASS; j++) +for (i = modes[j]; i; i = i-next) + if (mmax i-bytesize) + mmax = i-bytesize; + printf (#define MAX_BITSIZE_MODE_ANY_MODE %d*BITS_PER_UNIT\n, mmax); +} + static void emit_insn_modes_h (void) { @@ -913,6 +945,7 @@ enum machine_mode\n{); #endif printf (#define CONST_MODE_IBIT%s\n, adj_ibit ? : const); printf (#define CONST_MODE_FBIT%s\n, adj_fbit ? : const); + emit_max_int (); puts (\ \n\ #endif /* insn-modes.h */); diff --git a/gcc/machmode.def b/gcc/machmode.def index 631015f..7186cb4 100644 --- a/gcc/machmode.def +++ b/gcc/machmode.def @@ -180,8 +180,11 @@ RANDOM_MODE (BLK); FRACTIONAL_INT_MODE (BI, 1, 1); /* Basic integer modes. We go up to TI in generic code (128 bits). - The name OI is reserved for a 256-bit type (needed by some back ends). - FIXME TI shouldn't be generically available either. */ + TImode is needed here because the some front ends now genericly + support __int128. If the front ends decide to generically support + larger types, then corresponding modes must be added here. The + name OI is reserved for a 256-bit type (needed by some back ends). +*/ INT_MODE (QI, 1); INT_MODE (HI, 2); INT_MODE (SI, 4);
Re: patch to fix constant math - 8th patch - tree-vrp.c
On Thu, 1 Nov 2012, Kenneth Zadeck wrote: This patch converts tree-vpn to use wide-int. In doing so it gets rid of all restrictions that this pass currently has on the target or source word size. The pass's reliance on a finite infinite precision representation has been preserved. It first scans the function being compiled to determine the largest type that needs to be represented within that function and then it uses some multiple of that size as it's definition of infinite. I am currently using 4 for this value. However marc glisse claims that this may be due to a bug and that the value should be 2. This is something that has to be investigated further. This could easily be my mistake or some other issue that has crept into the pass. The value of 2 or 4 is easily changed in largest_initialize.The only truly non mechanical transformation is in the code that multiplies two ranges. This code uses the wide-int multiply full functions rather than using pairs of double-ints. (I didn't look at the patch (yet)) Er, no, I didn't claim that using 4 was wrong, I think it is good because it makes things easier. I only claimed that the current implementation jumps through enough hoops to make do with 2. -- Marc Glisse
Re: patch to fix constant math - 4th patch - wide-int.[ch] refresh
This patch refreshes wide-int.[ch]. Most of the changes are bug fixes that were fixed for tree-vrp.c in patch 8. There are two significant differences: 1) There are now constructors to override the precision and bitsize that are normally taken from the type. These are used to perform the finite infinite precision that is required by the tree-vrp.c pass. The bitsize and precision passed in are the ones necessary to compile the current function. 2) The signed and unsigned extension functions have changed a lot. The ones with the name ext do an extension but the result always has the bitsize and precision of this. the functions that are named force_to_size, now return results based on the precision and bitsize passed in after doing the proper extension. The second change is in line with comments made by richi and others. kenny
Re: patch to fix constant math - 8th patch - tree-vrp.c
either way, this needs to be investigated. it could just be my bad. On 11/01/2012 06:28 PM, Marc Glisse wrote: On Thu, 1 Nov 2012, Kenneth Zadeck wrote: This patch converts tree-vpn to use wide-int. In doing so it gets rid of all restrictions that this pass currently has on the target or source word size. The pass's reliance on a finite infinite precision representation has been preserved. It first scans the function being compiled to determine the largest type that needs to be represented within that function and then it uses some multiple of that size as it's definition of infinite. I am currently using 4 for this value. However marc glisse claims that this may be due to a bug and that the value should be 2. This is something that has to be investigated further. This could easily be my mistake or some other issue that has crept into the pass. The value of 2 or 4 is easily changed in largest_initialize.The only truly non mechanical transformation is in the code that multiplies two ranges. This code uses the wide-int multiply full functions rather than using pairs of double-ints. (I didn't look at the patch (yet)) Er, no, I didn't claim that using 4 was wrong, I think it is good because it makes things easier. I only claimed that the current implementation jumps through enough hoops to make do with 2.
Re: patch to fix constant math - 4th patch - the wide-int class.
Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting that you gave this example, since before you were complaining about too many fused ops. Clearly this one could be removed in favour of separate and() and not() operations, but why not provide a fused one if there are clients who'll make use of it? I think Kenny's API is just taking that to its logical conclusion. There doesn't seem to be anything sacrosanct about the current choice of what's fused and what isn't. The speed problem we had using trees
Re: patch to fix constant math - 4th patch - the wide-int class.
On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting that you gave this example, since before you were complaining about too many fused ops. Clearly this one could be removed in favour of separate and() and not() operations, but why not provide a fused one if there are clients who'll make use of it? I was more concerned about fused operations that use precision or bitsize as input. That is for example + bool
Re: patch to fix constant math - 4th patch - the wide-int class.
Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting that you gave this example, since before you were complaining about too many fused ops. Clearly this one could be removed in favour of separate and() and not() operations, but why not provide a fused one if there are clients who'll make use of it? I was more concerned about fused operations that use
Re: patch to fix constant math - 4th patch - the wide-int class.
On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting that you gave this example, since before you were complaining about too many fused ops. Clearly this one could be removed in favour of separate and() and not() operations, but why not provide a fused one if
Re: patch to fix constant math - 4th patch - the wide-int class.
Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting that you gave this example, since before you were complaining about too many fused ops. Clearly this one could be removed in favour of separate and()
Re: patch to fix constant math - 4th patch - the wide-int class.
On Wed, Oct 31, 2012 at 1:22 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting that you gave this example, since before you were
Re: patch to fix constant math - 4th patch - the wide-int class.
Richard Biener richard.guent...@gmail.com writes: But that means that wide_int has to model a P-bit operation as a normal len*HOST_WIDE_INT operation and then fix up the result after the fact, which seems unnecessarily convoluted. It does that right now. The operations are carried out in a loop over len HOST_WIDE_INT parts, the last HWI is then special-treated to account for precision/size. (yes, 'len' is also used as optimization - the fact that len ends up being mutable is another thing I dislike about wide-int. If wide-ints are cheap then all ops should be non-mutating (at least to 'len')). But the point of having a mutating len is that things like zero and -1 are common even for OImode values. So if you're doing someting potentially expensive like OImode multiplication, why do it to the number of HOST_WIDE_INTs needed for an OImode value when the value we're processing has only one significant HOST_WIDE_INT? I still don't see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision X*HOST_WIDE_INT operation for any X) has any special meaning. Well, the same reason as a HOST_WIDE_INT variable has a meaning. We use it to constrain what we (efficiently) want to work on. For example CCP might iterate up to 2 * HOST_BITS_PER_WIDE_INT times when doing bit-constant-propagation in loops (for TImode integers on a x86_64 host). But what about targets with modes wider than TImode? Would double_int still be appropriate then? If not, why does CCP have to use a templated type with a fixed number of HWIs (and all arithmetic done to a fixed number of HWIs) rather than one that can adapt to the runtime values, like wide_int can? Oh, and I don't necessary see a use of double_int in its current form but for an integer representation on the host that is efficient to manipulate integer constants of a target dependent size. For example the target detail that we have partial integer modes with bitsize precision and that the bits precision appearantly have a meaning when looking at the bit-representation of a constant should not be part of the base class of wide-int (I doubt it belongs to wide-int at all, but I guess you know more about the reason we track bitsize in addition to precision - I think it's abstraction at the wrong level, the tree level does fine without knowing about bitsize). TBH I'm uneasy about the bitsize thing too. I think bitsize is only tracked for shift truncation, and if so, I agree it makes sense to do that separately. But anyway, this whole discussion seems to have reached a stalemate. Or I suppose a de-facto rejection, since you're the only person in a position to approve the thing :-) Richard
Re: patch to fix constant math - 4th patch - the wide-int class.
On 10/31/2012 08:11 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting that you gave this example, since before you were complaining about too many fused ops. Clearly this one could be removed in favour of separate and() and not() operations, but why not provide a fused one if there are clients who'll make use of it? I was more
Re: patch to fix constant math - 4th patch - the wide-int class.
On Wed, Oct 31, 2012 at 2:30 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: But that means that wide_int has to model a P-bit operation as a normal len*HOST_WIDE_INT operation and then fix up the result after the fact, which seems unnecessarily convoluted. It does that right now. The operations are carried out in a loop over len HOST_WIDE_INT parts, the last HWI is then special-treated to account for precision/size. (yes, 'len' is also used as optimization - the fact that len ends up being mutable is another thing I dislike about wide-int. If wide-ints are cheap then all ops should be non-mutating (at least to 'len')). But the point of having a mutating len is that things like zero and -1 are common even for OImode values. So if you're doing someting potentially expensive like OImode multiplication, why do it to the number of HOST_WIDE_INTs needed for an OImode value when the value we're processing has only one significant HOST_WIDE_INT? I don't propose doing that. I propose that no wide-int member function may _change_ it's len (to something larger). Only that way you can avoid allocating wasted space for zero and -1. That way also the artificial limit on 2 * largest-int-mode-hwis goes. I still don't see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision X*HOST_WIDE_INT operation for any X) has any special meaning. Well, the same reason as a HOST_WIDE_INT variable has a meaning. We use it to constrain what we (efficiently) want to work on. For example CCP might iterate up to 2 * HOST_BITS_PER_WIDE_INT times when doing bit-constant-propagation in loops (for TImode integers on a x86_64 host). But what about targets with modes wider than TImode? Would double_int still be appropriate then? If not, why does CCP have to use a templated type with a fixed number of HWIs (and all arithmetic done to a fixed number of HWIs) rather than one that can adapt to the runtime values, like wide_int can? Because nobody cares about accurate bit-tracking for modes larger than TImode. And because no convenient abstraction was available ;) Oh, and I don't necessary see a use of double_int in its current form but for an integer representation on the host that is efficient to manipulate integer constants of a target dependent size. For example the target detail that we have partial integer modes with bitsize precision and that the bits precision appearantly have a meaning when looking at the bit-representation of a constant should not be part of the base class of wide-int (I doubt it belongs to wide-int at all, but I guess you know more about the reason we track bitsize in addition to precision - I think it's abstraction at the wrong level, the tree level does fine without knowing about bitsize). TBH I'm uneasy about the bitsize thing too. I think bitsize is only tracked for shift truncation, and if so, I agree it makes sense to do that separately. So, can we please remove all traces of bitsize from wide-int then? But anyway, this whole discussion seems to have reached a stalemate. Or I suppose a de-facto rejection, since you're the only person in a position to approve the thing :-) There are many (silent) people that are able to approve the thing. But the point is I have too many issues with the current patch that I'm unable to point at a specific thing I want Kenny to change after which the patch would be fine. So I rely on some guesswork from Kenny giving my advices leaner API, less fused ops, get rid of bitsize, think of abstracting the core HWI[len] operation, there should be no tree or RTL dependencies in the wide-int API to produce an updated variant. Which of course takes time, which of course crosses my vacation, which in the end means it isn't going to make 4.8 (I _do_ like the idea of not having a dependence on host properties for integer constant representation). Btw, a good hint at what a minimal wide-int API would look like is if you _just_ replace double-int users with it. Then you obviously have to implement only the double-int interface and conversion from/to double-int. Richard. Richard
Re: patch to fix constant math - 4th patch - the wide-int class.
On Wed, Oct 31, 2012 at 2:54 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/31/2012 08:11 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting that you gave this example, since before you were
Re: patch to fix constant math - 4th patch - the wide-int class.
On 10/31/2012 10:05 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 2:54 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/31/2012 08:11 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting that you gave this example, since before you were complaining about too many fused ops. Clearly this one could be removed in favour
Re: patch to fix constant math - 4th patch - the wide-int class.
On Wed, Oct 31, 2012 at 3:18 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/31/2012 10:05 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 2:54 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/31/2012 08:11 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK,
Re: patch to fix constant math - 4th patch - the wide-int class.
On 10/31/2012 09:54 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 2:30 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: But that means that wide_int has to model a P-bit operation as a normal len*HOST_WIDE_INT operation and then fix up the result after the fact, which seems unnecessarily convoluted. It does that right now. The operations are carried out in a loop over len HOST_WIDE_INT parts, the last HWI is then special-treated to account for precision/size. (yes, 'len' is also used as optimization - the fact that len ends up being mutable is another thing I dislike about wide-int. If wide-ints are cheap then all ops should be non-mutating (at least to 'len')). But the point of having a mutating len is that things like zero and -1 are common even for OImode values. So if you're doing someting potentially expensive like OImode multiplication, why do it to the number of HOST_WIDE_INTs needed for an OImode value when the value we're processing has only one significant HOST_WIDE_INT? I don't propose doing that. I propose that no wide-int member function may _change_ it's len (to something larger). Only that way you can avoid allocating wasted space for zero and -1. That way also the artificial limit on 2 * largest-int-mode-hwis goes. it is now 4x not 2x to accomodate the extra bit in tree-vrp. remember that the space burden is minimal.wide-ints are not persistent and there are never more than a handful at a time. I still don't see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision X*HOST_WIDE_INT operation for any X) has any special meaning. Well, the same reason as a HOST_WIDE_INT variable has a meaning. We use it to constrain what we (efficiently) want to work on. For example CCP might iterate up to 2 * HOST_BITS_PER_WIDE_INT times when doing bit-constant-propagation in loops (for TImode integers on a x86_64 host). But what about targets with modes wider than TImode? Would double_int still be appropriate then? If not, why does CCP have to use a templated type with a fixed number of HWIs (and all arithmetic done to a fixed number of HWIs) rather than one that can adapt to the runtime values, like wide_int can? Because nobody cares about accurate bit-tracking for modes larger than TImode. And because no convenient abstraction was available ;) yes, but tree-vrp does not even work for timode. and there are not tests to scale it back when it does see ti-mode. I understand that these can be added, but they so far have not been. I would also point out that i was corrected on this point by (i believe) lawrence. He points out that tree-vrp is still important for converting signed to unsigned for larger modes. Oh, and I don't necessary see a use of double_int in its current form but for an integer representation on the host that is efficient to manipulate integer constants of a target dependent size. For example the target detail that we have partial integer modes with bitsize precision and that the bits precision appearantly have a meaning when looking at the bit-representation of a constant should not be part of the base class of wide-int (I doubt it belongs to wide-int at all, but I guess you know more about the reason we track bitsize in addition to precision - I think it's abstraction at the wrong level, the tree level does fine without knowing about bitsize). TBH I'm uneasy about the bitsize thing too. I think bitsize is only tracked for shift truncation, and if so, I agree it makes sense to do that separately. So, can we please remove all traces of bitsize from wide-int then? But anyway, this whole discussion seems to have reached a stalemate. Or I suppose a de-facto rejection, since you're the only person in a position to approve the thing :-) There are many (silent) people that are able to approve the thing. But the point is I have too many issues with the current patch that I'm unable to point at a specific thing I want Kenny to change after which the patch would be fine. So I rely on some guesswork from Kenny giving my advices leaner API, less fused ops, get rid of bitsize, think of abstracting the core HWI[len] operation, there should be no tree or RTL dependencies in the wide-int API to produce an updated variant. Which of course takes time, which of course crosses my vacation, which in the end means it isn't going to make 4.8 (I _do_ like the idea of not having a dependence on host properties for integer constant representation). Btw, a good hint at what a minimal wide-int API would look like is if you _just_ replace double-int users with it. Then you obviously have to implement only the double-int interface and conversion from/to double-int. Richard. Richard
Re: patch to fix constant math - 4th patch - the wide-int class.
On 10/31/2012 10:24 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 3:18 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/31/2012 10:05 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 2:54 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/31/2012 08:11 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting
Re: patch to fix constant math - 4th patch - the wide-int class.
On 10/31/2012 08:44 AM, Richard Biener wrote: On Wed, Oct 31, 2012 at 1:22 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford rdsandif...@googlemail.com wrote: Richard Biener richard.guent...@gmail.com writes: On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/25/2012 06:42 AM, Richard Biener wrote: On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it. I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard. i do not know why you believe this about the speed. double int always does synthetic math since you do everything at 128 bit precision. the thing about wide int, is that since it does math to the precision's size, it almost never does uses synthetic operations since the sizes for almost every instance can be done using the native math on the machine. almost every call has a check to see if the operation can be done natively. I seriously doubt that you are going to do TI mode math much faster than i do it and if you do who cares. the number of calls does not effect the performance in any negative way and it fact is more efficient since common things that require more than one operation in double in are typically done in a single operation. Simple double-int operations like inline double_int double_int::and_not (double_int b) const { double_int result; result.low = low ~b.low; result.high = high ~b.high; return result; } are always going to be faster than conditionally executing only one operation (but inside an offline function). OK, this is really in reply to the 4.8 thing, but it felt more appropriate here. It's interesting that you gave this example, since before you were complaining about too many fused ops. Clearly this one could be removed in
Re: patch to fix constant math - 4th patch - the wide-int class.
On 10/31/2012 09:30 AM, Richard Sandiford wrote: Richard Biener richard.guent...@gmail.com writes: But that means that wide_int has to model a P-bit operation as a normal len*HOST_WIDE_INT operation and then fix up the result after the fact, which seems unnecessarily convoluted. It does that right now. The operations are carried out in a loop over len HOST_WIDE_INT parts, the last HWI is then special-treated to account for precision/size. (yes, 'len' is also used as optimization - the fact that len ends up being mutable is another thing I dislike about wide-int. If wide-ints are cheap then all ops should be non-mutating (at least to 'len')). But the point of having a mutating len is that things like zero and -1 are common even for OImode values. So if you're doing someting potentially expensive like OImode multiplication, why do it to the number of HOST_WIDE_INTs needed for an OImode value when the value we're processing has only one significant HOST_WIDE_INT? I think with a little thought i can add some special constructors and get rid of the mutating aspects of the interface. I still don't see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision X*HOST_WIDE_INT operation for any X) has any special meaning. Well, the same reason as a HOST_WIDE_INT variable has a meaning. We use it to constrain what we (efficiently) want to work on. For example CCP might iterate up to 2 * HOST_BITS_PER_WIDE_INT times when doing bit-constant-propagation in loops (for TImode integers on a x86_64 host). But what about targets with modes wider than TImode? Would double_int still be appropriate then? If not, why does CCP have to use a templated type with a fixed number of HWIs (and all arithmetic done to a fixed number of HWIs) rather than one that can adapt to the runtime values, like wide_int can? Oh, and I don't necessary see a use of double_int in its current form but for an integer representation on the host that is efficient to manipulate integer constants of a target dependent size. For example the target detail that we have partial integer modes with bitsize precision and that the bits precision appearantly have a meaning when looking at the bit-representation of a constant should not be part of the base class of wide-int (I doubt it belongs to wide-int at all, but I guess you know more about the reason we track bitsize in addition to precision - I think it's abstraction at the wrong level, the tree level does fine without knowing about bitsize). TBH I'm uneasy about the bitsize thing too. I think bitsize is only tracked for shift truncation, and if so, I agree it makes sense to do that separately. But anyway, this whole discussion seems to have reached a stalemate. Or I suppose a de-facto rejection, since you're the only person in a position to approve the thing :-) Richard
Re: patch to fix constant math - 4th patch - the wide-int class.
On Oct 31, 2012, at 5:44 AM, Richard Biener richard.guent...@gmail.com wrote: the fact that len ends up being mutable is another thing I dislike about wide-int. We expose len for construction only, it is non-mutating. During construction, there is no previous value. If wide-ints are cheap then all ops should be non-mutating (at least to 'len')). It is. Construction modifies the object as construction must be defined as initializing the state of the data. Before construction, there is no data, so, we are constructing the data, not mutating the data. Surely you don't object to construction?
Re: patch to fix constant math - 4th patch - the wide-int class.
On Oct 31, 2012, at 6:54 AM, Richard Biener richard.guent...@gmail.com wrote: I propose that no wide-int member function may _change_ it's len (to something larger). We never do that, so, we already do as you wish. We construct wide ints, and we have member functions to construct values. We need to construct values as some parts of the compiler want to create values. The construction of values can be removed when the rest of the compiler no longer wishes to construct values. LTO is an example of a client that wanted to construct a value. I'll let the LTO people chime in if they wish to no loner construct values.
Re: patch to fix constant math - 4th patch - the wide-int class.
On Oct 31, 2012, at 7:05 AM, Richard Biener richard.guent...@gmail.com wrote: You have an artificial limit on what 'len' can be. No. There is no limit, and nothing artificial. We take the maximum of the needs of the target, the maximum of the front-ends and the maximum of the mid-end and the back-end. We can drop a category, if that category no longer wishes to be our client. Any client is free to stop using wide-int, any time they want. For example, vrp could use gmp, if they wanted to, and the need to serve them drops. You have imagined the cost is high to do this, the reality is all long lived objects are small, and all short lived objects are so transitory that we are talking about maybe 5 live at a time. And you do not accomodate users that do not want to pay the storage penalty for that arbitrary upper limit choice. This is also wrong. First, there is no arbitrary upper limit. Second, all long lived objects are small. We accommodated them by having all long lived objects be small. The transitory objects are big, but there are only 5 of them alive at a time. That's all because 'len' may grow (mutate). This is also wrong.
Re: patch to fix constant math - 4th patch - the wide-int class.
On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump mikest...@comcast.net wrote: On Oct 24, 2012, at 2:43 AM, Richard Biener richard.guent...@gmail.com wrote: On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck zad...@naturalbridge.com wrote: On 10/23/2012 10:12 AM, Richard Biener wrote: + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT]; are we sure this rounds properly? Consider a port with max byte mode size 4 on a 64bit host. I do not believe that this can happen. The core compiler includes all modes up to TI mode, so by default we already up to 128 bits. And mode bitsizes are always power-of-two? I suppose so. Actually, no, they are not. Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size. Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT should do it. I still would like to have the ability to provide specializations of wide_int for small sizes, thus ideally wide_int would be a template templated on the number of HWIs in val. Interface-wise wide_int2 should be identical to double_int, thus we should be able to do typedef wide_int2 double_int; If you want to go down this path after the patches get in, go for it.I see no use at all for this. This was not meant to be a plug in replacement for double int. This goal of this patch is to get the compiler to do the constant math the way that the target does it. Any such instantiation is by definition placing some predefined limit that some target may not want. Well, what I don't really like is that we now have two implementations of functions that perform integer math on two-HWI sized integers. What I also don't like too much is that we have two different interfaces to operate on them! Can't you see how I come to not liking this? Especially the latter … double_int is logically dead. Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler. All the necessary semantics and code of double-int _has_ been refactored into wide-int already. Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed. The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that. double_int, compared to wide_int, is fast and lean. I doubt we will get rid of it - you will make compile-time math a _lot_ slower. Just profile when you for example change get_inner_reference to use wide_ints. To be able to remove double_int in favor of wide_int requires _at least_ templating wide_int on 'len' and providing specializations for 1 and 2. It might be a non-issue for math that operates on trees or RTXen due to the allocation overhead we pay, but in recent years we transitioned important paths away from using tree math to using double_ints _for speed reasons_. Richard.