You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@stdcxx.apache.org by Scott Zhong <Sc...@roguewave.com> on 2008/03/04 21:40:24 UTC

RE: [PATCH] STDCXX-423


> -----Original Message-----
> From: Martin Sebor [mailto:sebor@roguewave.com]
> Sent: Wednesday, February 20, 2008 12:26 PM
> To: dev@stdcxx.apache.org
> Subject: Re: [PATCH] STDCXX-423
> 
> Scott Zhong wrote:
> [...]
> >>> As I write this, I realize that the my function,
> > compute_byte_size(),
> >>> can be optimized to shift one bit to the next byte boundary.
> >> I don't think we need to (or should) worry about optimizing config
> >> tests. What we might want to do is use the template parameter in
> >> the signature of the function for non-conforming compilers that
> >> have trouble with these types of things.
> >
> > Sorry I meant to say that its more of a code fix than optimization.
> > Sizeof() returns the number of bytes so the function should check
each
> > byte instead of each bit.
> 
> But not all bits of every byte need to contribute to the value
> representation of the object. IIUC, there can be 4 byte ints
> (i.e., sizeof(int) == 4) with 29 bits for the value, 1 bit for
> the sign, and 2 bits of padding.
> 

I had overlooked that fact, thank you for reminding me.

> >
> >>> template <class T>
> >>> unsigned compute_byte_size()
> >>> {
> >>>     T max = T (one);
> >>>     unsigned byte = 0;
> >>>     for (; T (max * 128) > max; max *= 128) {
> >> FWIW, for signed T the expression T(max * 128) > max has undefined
> >> behavior in the presence of overflow. We've seen at least two (if
> >> not three) compilers exploit this presumably in some aggressive
> >> optimizations (see, for example, STDCXX-482). Since most (all?)
> >> hardware simply wraps around in the presence of overflow we just
> >> need to prevent the compiler optimization here.
> >
> > Would the volatile keyword in front of "max" be sufficient here?
> 
> It might help, but I'm not sure it's guaranteed to. All it usually
> does is make the compiler generate code that reloads the value of
> the object from memory into a register on each access. The stage
> I'm concerned with takes place before code generation based on what
> the compiler can prove about the program. For all signed x, the
> compiler is free to assume that in (x * N) > x, the subexpression
> (x * N) doesn't overflow and thus (x * N) is always guaranteed to
> be greater than x (for N > 0). To prevent it from making such an
> assumption we need to rewrite the expression like so: (x * N) > y
> while initializing x and y to the same value in such a way that
> the compiler cannot prove that (x == y) holds.
> 

Would this suffice?

template <class T>
unsigned compute_byte_size()
{
    T max = T (one);
    T current = T (one);
    unsigned byte = 0;
    for (int I = 1; T (current * 2) > max; current *= 2, max *= 2, i++)
{
        if (i > 8 ) {byte++; i = 1; }
    }
    return byte;
}


> Martin


Re: [PATCH] STDCXX-423

Posted by Martin Sebor <se...@roguewave.com>.
Scott Zhong wrote:
>> -----Original Message-----
>> From: Martin Sebor [mailto:sebor@roguewave.com]
>> Sent: Thursday, March 13, 2008 12:32 PM
>> To: dev@stdcxx.apache.org
>> Subject: RE: [PATCH] STDCXX-423
>>
>>
>> Okay, so this function seems to correctly compute the number of bytes
>> in the value representation of the object. Remind me, where do we need
>> it in the rest of LIMITS.cpp again? I.e., what does the patch look
>> like?
>>
>> Thanks
>> Martin
>>
> 
> The patch looks like the following; it replaces SIZEOF macro on int
> types with CALC_SIZEOF macro. The CALC_SIZEOF macro expends to
> compute_byte_size function.

That's what I thought. I'm afraid I don't think this is correct.
The value of a sizeof expression must be the size of the operand
expressed as (n X CHAR_BIT), and that's what the test computes.

The problem noted in the issue is not with the sizeof operator or
the _RWSTD_XXX_SIZE macros but rather with the exact-width integer
types such as int32_t, and the assumption made in the test that
integer types for which sizeof returns 1, 2, 4, or 8, respectively,
have no padding bits.

For example, the code here:
http://fisheye6.cenqua.com/browse/stdcxx/trunk/etc/config/src/LIMITS.cpp?r=611451#l531

531    if (32 == char_bits * sizeof (int) && !(bits & 4)) {
532        bits |= 4;
533        printf ("#define _RWSTD_INT32_T  int\n");
534 	   printf ("#define _RWSTD_UINT32_T unsigned int\n");
535    }

will incorrectly define int32_t to int when sizeof(int) == 4 holds even
when int has 1 or more padding bits.

I assume you're familiar with the C99 spec for exact-width integer types
but just for reference:

   7.18.1.1  Exact-width integer types
   -1- The typedef name intN_t designates a signed integer type with
       width N, no padding bits, and a two’s complement representation.
       Thus, int8_t denotes a signed integer type with a width of
       exactly 8 bits.
   -2- The typedef name uintN_t designates an unsigned integer type
       with width N. Thus, uint24_t denotes an unsigned integer type
       with a width of exactly 24 bits.
   -3- These types are optional. However, if an implementation provides
       integer types with widths of 8, 16, 32, or 64 bits, it shall
       define the corresponding typedef names.

What we need to do to solve the exceedingly hypothetical problem noted
in STDCXX-423 is compute the number of bits in the value representation
of integer types with widths of 8, 16, 32, and 64 bits, compare the
results with number of bits in their object representation and only
if the two match define the corresponding exact-width typedefs.

Martin

> 
> --- LIMITS.cpp  (revision 624452)
> +++ LIMITS.cpp  (working copy)
> @@ -223,13 +223,27 @@
>      return bits;
>  }
>  
> +template <class T>
> +unsigned compute_byte_size()
> +{
> +    T max = T (one);
> +    T current = T(one);
> +    unsigned byte = 1;
> +    for (int i = 1; T (current * 2) > max; current *=2, max *= 2, i++)
> {
> +        if (i > 8) { byte++; i=1; }
> +    }
> +    return byte;
> +}
> 
> + 
>  // used to compute the size of a pointer to a member function  struct
> EmptyStruct { };
>  
>  
>  // to silence printf() format comaptibility warnings
>  #define SIZEOF(T)   unsigned (sizeof (T))
> + 
> +// to not include possible bit padding
> +#define CALC_SIZEOF(T)  compute_byte_size<T>()
>  
>  
>  int main ()
> @@ -243,17 +257,17 @@
>  
>  #ifndef _RWSTD_NO_BOOL
>      printf ("#define _RWSTD_BOOL_SIZE   %2u /* sizeof (bool) */\n",
> -            SIZEOF (bool));
> +            CALC_SIZEOF (bool));
>  #endif   // _RWSTD_NO_BOOL
>  
>      printf ("#define _RWSTD_CHAR_SIZE   %2u /* sizeof (char) */\n",
> -            SIZEOF (char));
> +            CALC_SIZEOF (char));
>      printf ("#define _RWSTD_SHRT_SIZE   %2u /* sizeof (short) */\n",
> -            SIZEOF (short));
> +            CALC_SIZEOF (short));
>      printf ("#define _RWSTD_INT_SIZE    %2u /* sizeof (int) */\n",
> -            SIZEOF (int));
> +            CALC_SIZEOF (int));
>      printf ("#define _RWSTD_LONG_SIZE   %2u /* sizeof (long) */\n",
> -            SIZEOF (long));
> +            CALC_SIZEOF (long));
>  
>      printf ("#define _RWSTD_FLT_SIZE    %2u /* sizeof (float) */\n",
>              SIZEOF (float));
> @@ -319,7 +333,7 @@
>  
>  #    define LLong long long
>  
> -    printf ("#define _RWSTD_LLONG_SIZE  %2u\n", SIZEOF (LLong));
> +    printf ("#define _RWSTD_LLONG_SIZE  %2u\n", CALC_SIZEOF (LLong));
>  
>      const char llong_name[] = "long long";
>  
> @@ -332,7 +346,7 @@
>  
>  #    define LLong __int64
>  
> -    printf ("#define _RWSTD_LLONG_SIZE  %2u\n", SIZEOF (LLong));
> +    printf ("#define _RWSTD_LLONG_SIZE  %2u\n", CALC_SIZEOF (LLong));
>  
>      const char llong_name[] = "__int64";
>  
> @@ -352,7 +366,7 @@
>  #ifndef _RWSTD_NO_WCHAR_T
>  
>      printf ("#define _RWSTD_WCHAR_SIZE  %2u /* sizeof (wchar_t) */\n",
> -            SIZEOF (wchar_t));
> +            CALC_SIZEOF (wchar_t));
>  
>      const char *suffix = "U";
>      if ((wchar_t)~0 < (wchar_t)0)
> 
> 
> 


RE: [PATCH] STDCXX-423

Posted by Scott Zhong <Sc...@roguewave.com>.
> -----Original Message-----
> From: Martin Sebor [mailto:sebor@roguewave.com]
> Sent: Thursday, March 13, 2008 12:32 PM
> To: dev@stdcxx.apache.org
> Subject: RE: [PATCH] STDCXX-423
> 
> 
> Okay, so this function seems to correctly compute the number of bytes
> in the value representation of the object. Remind me, where do we need
> it in the rest of LIMITS.cpp again? I.e., what does the patch look
> like?
> 
> Thanks
> Martin
> 

The patch looks like the following; it replaces SIZEOF macro on int
types with CALC_SIZEOF macro. The CALC_SIZEOF macro expends to
compute_byte_size function.

--- LIMITS.cpp  (revision 624452)
+++ LIMITS.cpp  (working copy)
@@ -223,13 +223,27 @@
     return bits;
 }
 
+template <class T>
+unsigned compute_byte_size()
+{
+    T max = T (one);
+    T current = T(one);
+    unsigned byte = 1;
+    for (int i = 1; T (current * 2) > max; current *=2, max *= 2, i++)
{
+        if (i > 8) { byte++; i=1; }
+    }
+    return byte;
+}

+ 
 // used to compute the size of a pointer to a member function  struct
EmptyStruct { };
 
 
 // to silence printf() format comaptibility warnings
 #define SIZEOF(T)   unsigned (sizeof (T))
+ 
+// to not include possible bit padding
+#define CALC_SIZEOF(T)  compute_byte_size<T>()
 
 
 int main ()
@@ -243,17 +257,17 @@
 
 #ifndef _RWSTD_NO_BOOL
     printf ("#define _RWSTD_BOOL_SIZE   %2u /* sizeof (bool) */\n",
-            SIZEOF (bool));
+            CALC_SIZEOF (bool));
 #endif   // _RWSTD_NO_BOOL
 
     printf ("#define _RWSTD_CHAR_SIZE   %2u /* sizeof (char) */\n",
-            SIZEOF (char));
+            CALC_SIZEOF (char));
     printf ("#define _RWSTD_SHRT_SIZE   %2u /* sizeof (short) */\n",
-            SIZEOF (short));
+            CALC_SIZEOF (short));
     printf ("#define _RWSTD_INT_SIZE    %2u /* sizeof (int) */\n",
-            SIZEOF (int));
+            CALC_SIZEOF (int));
     printf ("#define _RWSTD_LONG_SIZE   %2u /* sizeof (long) */\n",
-            SIZEOF (long));
+            CALC_SIZEOF (long));
 
     printf ("#define _RWSTD_FLT_SIZE    %2u /* sizeof (float) */\n",
             SIZEOF (float));
@@ -319,7 +333,7 @@
 
 #    define LLong long long
 
-    printf ("#define _RWSTD_LLONG_SIZE  %2u\n", SIZEOF (LLong));
+    printf ("#define _RWSTD_LLONG_SIZE  %2u\n", CALC_SIZEOF (LLong));
 
     const char llong_name[] = "long long";
 
@@ -332,7 +346,7 @@
 
 #    define LLong __int64
 
-    printf ("#define _RWSTD_LLONG_SIZE  %2u\n", SIZEOF (LLong));
+    printf ("#define _RWSTD_LLONG_SIZE  %2u\n", CALC_SIZEOF (LLong));
 
     const char llong_name[] = "__int64";
 
@@ -352,7 +366,7 @@
 #ifndef _RWSTD_NO_WCHAR_T
 
     printf ("#define _RWSTD_WCHAR_SIZE  %2u /* sizeof (wchar_t) */\n",
-            SIZEOF (wchar_t));
+            CALC_SIZEOF (wchar_t));
 
     const char *suffix = "U";
     if ((wchar_t)~0 < (wchar_t)0)



RE: [PATCH] STDCXX-423

Posted by Martin Sebor <se...@roguewave.com>.
Okay, so this function seems to correctly compute the number of bytes
in the value representation of the object. Remind me, where do we need
it in the rest of LIMITS.cpp again? I.e., what does the patch look
like?

Thanks
Martin


Scott Zhong-2 wrote:
> 
> After going through the logic again:
> 
> iter #	i	byte	structure
> 
> 1		1	0		00000001
> 2		2	0		00000010
> 3		3	0		00000100
> 4		4	0		00001000
> 5		5	0		00010000
> 6		6	0		00100000
> 7		7	0		01000000
> 8		8	0		10000000
> 9		1	1		00000001 00000000
> 10		2	1		00000010 00000000
> 11		3	1		00000100 00000000
> 12		4	1		00001000 00000000
> 13		5	1		00010000 00000000
> 14		6	1		00100000 00000000
> 15		7	1		01000000 00000000
> 16		8	1		10000000 00000000
> 17		1	2		00000001 00000000 00000000
> 
> Byte should be initialized to 1.
> 
> template <class T>
> unsigned compute_byte_size()
> {
>     T max = T (one);
>     T current = T(one);
>     unsigned byte = 1;
>     for (int i = 1; T (current * 2) > max; current *=2, max *= 2, i++) {
>         if (i > 8) { byte++; i=1; }
>     }
>     return byte;
> }
> 
>> -----Original Message-----
>> From: Martin Sebor [mailto:sebor@roguewave.com]
>> Sent: Wednesday, March 05, 2008 5:19 PM
>> To: dev@stdcxx.apache.org
>> Subject: Re: [PATCH] STDCXX-423
>> 
>> Scott Zhong wrote:
>> >
>> >> -----Original Message-----
>> >> From: Martin Sebor [mailto:sebor@roguewave.com]
>> >> Sent: Wednesday, February 20, 2008 12:26 PM
>> >> To: dev@stdcxx.apache.org
>> >> Subject: Re: [PATCH] STDCXX-423
>> >>
>> >> Scott Zhong wrote:
>> >> [...]
>> >>>>> As I write this, I realize that the my function,
>> >>> compute_byte_size(),
>> >>>>> can be optimized to shift one bit to the next byte boundary.
>> >>>> I don't think we need to (or should) worry about optimizing
> config
>> >>>> tests. What we might want to do is use the template parameter in
>> >>>> the signature of the function for non-conforming compilers that
>> >>>> have trouble with these types of things.
>> >>> Sorry I meant to say that its more of a code fix than
> optimization.
>> >>> Sizeof() returns the number of bytes so the function should check
>> > each
>> >>> byte instead of each bit.
>> >> But not all bits of every byte need to contribute to the value
>> >> representation of the object. IIUC, there can be 4 byte ints
>> >> (i.e., sizeof(int) == 4) with 29 bits for the value, 1 bit for
>> >> the sign, and 2 bits of padding.
>> >>
>> >
>> > I had overlooked that fact, thank you for reminding me.
>> >
>> >>>>> template <class T>
>> >>>>> unsigned compute_byte_size()
>> >>>>> {
>> >>>>>     T max = T (one);
>> >>>>>     unsigned byte = 0;
>> >>>>>     for (; T (max * 128) > max; max *= 128) {
>> >>>> FWIW, for signed T the expression T(max * 128) > max has
> undefined
>> >>>> behavior in the presence of overflow. We've seen at least two (if
>> >>>> not three) compilers exploit this presumably in some aggressive
>> >>>> optimizations (see, for example, STDCXX-482). Since most (all?)
>> >>>> hardware simply wraps around in the presence of overflow we just
>> >>>> need to prevent the compiler optimization here.
>> >>> Would the volatile keyword in front of "max" be sufficient here?
>> >> It might help, but I'm not sure it's guaranteed to. All it usually
>> >> does is make the compiler generate code that reloads the value of
>> >> the object from memory into a register on each access. The stage
>> >> I'm concerned with takes place before code generation based on what
>> >> the compiler can prove about the program. For all signed x, the
>> >> compiler is free to assume that in (x * N) > x, the subexpression
>> >> (x * N) doesn't overflow and thus (x * N) is always guaranteed to
>> >> be greater than x (for N > 0). To prevent it from making such an
>> >> assumption we need to rewrite the expression like so: (x * N) > y
>> >> while initializing x and y to the same value in such a way that
>> >> the compiler cannot prove that (x == y) holds.
>> >>
>> >
>> > Would this suffice?
>> 
>> This doesn't seem correct, not just because of the typo but because
>> it returns 3 for T = int (assuming one == 1). Even if it was correct
>> I'm not sure a smart optimizer couldn't make some assumptions about
>> the dependency between current and max (they are both modified using
>> exactly the same expression) that would cause the code to misbehave.
>> 
>> Martin
>> 
>> >
>> > template <class T>
>> > unsigned compute_byte_size()
>> > {
>> >     T max = T (one);
>> >     T current = T (one);
>> >     unsigned byte = 0;
>> >     for (int I = 1; T (current * 2) > max; current *= 2, max *= 2,
> i++)
>> > {
>> >         if (i > 8 ) {byte++; i = 1; }
>> >     }
>> >     return byte;
>> > }
>> >
>> >
>> >> Martin
>> >
> 
> 
> 

-- 
View this message in context: http://www.nabble.com/-PATCH--STDCXX-423-tp15191643p16035049.html
Sent from the stdcxx-dev mailing list archive at Nabble.com.


RE: [PATCH] STDCXX-423

Posted by Scott Zhong <Sc...@roguewave.com>.
After going through the logic again:

iter #	i	byte	structure

1		1	0		00000001
2		2	0		00000010
3		3	0		00000100
4		4	0		00001000
5		5	0		00010000
6		6	0		00100000
7		7	0		01000000
8		8	0		10000000
9		1	1		00000001 00000000
10		2	1		00000010 00000000
11		3	1		00000100 00000000
12		4	1		00001000 00000000
13		5	1		00010000 00000000
14		6	1		00100000 00000000
15		7	1		01000000 00000000
16		8	1		10000000 00000000
17		1	2		00000001 00000000 00000000

Byte should be initialized to 1.

template <class T>
unsigned compute_byte_size()
{
    T max = T (one);
    T current = T(one);
    unsigned byte = 1;
    for (int i = 1; T (current * 2) > max; current *=2, max *= 2, i++) {
        if (i > 8) { byte++; i=1; }
    }
    return byte;
}

> -----Original Message-----
> From: Martin Sebor [mailto:sebor@roguewave.com]
> Sent: Wednesday, March 05, 2008 5:19 PM
> To: dev@stdcxx.apache.org
> Subject: Re: [PATCH] STDCXX-423
> 
> Scott Zhong wrote:
> >
> >> -----Original Message-----
> >> From: Martin Sebor [mailto:sebor@roguewave.com]
> >> Sent: Wednesday, February 20, 2008 12:26 PM
> >> To: dev@stdcxx.apache.org
> >> Subject: Re: [PATCH] STDCXX-423
> >>
> >> Scott Zhong wrote:
> >> [...]
> >>>>> As I write this, I realize that the my function,
> >>> compute_byte_size(),
> >>>>> can be optimized to shift one bit to the next byte boundary.
> >>>> I don't think we need to (or should) worry about optimizing
config
> >>>> tests. What we might want to do is use the template parameter in
> >>>> the signature of the function for non-conforming compilers that
> >>>> have trouble with these types of things.
> >>> Sorry I meant to say that its more of a code fix than
optimization.
> >>> Sizeof() returns the number of bytes so the function should check
> > each
> >>> byte instead of each bit.
> >> But not all bits of every byte need to contribute to the value
> >> representation of the object. IIUC, there can be 4 byte ints
> >> (i.e., sizeof(int) == 4) with 29 bits for the value, 1 bit for
> >> the sign, and 2 bits of padding.
> >>
> >
> > I had overlooked that fact, thank you for reminding me.
> >
> >>>>> template <class T>
> >>>>> unsigned compute_byte_size()
> >>>>> {
> >>>>>     T max = T (one);
> >>>>>     unsigned byte = 0;
> >>>>>     for (; T (max * 128) > max; max *= 128) {
> >>>> FWIW, for signed T the expression T(max * 128) > max has
undefined
> >>>> behavior in the presence of overflow. We've seen at least two (if
> >>>> not three) compilers exploit this presumably in some aggressive
> >>>> optimizations (see, for example, STDCXX-482). Since most (all?)
> >>>> hardware simply wraps around in the presence of overflow we just
> >>>> need to prevent the compiler optimization here.
> >>> Would the volatile keyword in front of "max" be sufficient here?
> >> It might help, but I'm not sure it's guaranteed to. All it usually
> >> does is make the compiler generate code that reloads the value of
> >> the object from memory into a register on each access. The stage
> >> I'm concerned with takes place before code generation based on what
> >> the compiler can prove about the program. For all signed x, the
> >> compiler is free to assume that in (x * N) > x, the subexpression
> >> (x * N) doesn't overflow and thus (x * N) is always guaranteed to
> >> be greater than x (for N > 0). To prevent it from making such an
> >> assumption we need to rewrite the expression like so: (x * N) > y
> >> while initializing x and y to the same value in such a way that
> >> the compiler cannot prove that (x == y) holds.
> >>
> >
> > Would this suffice?
> 
> This doesn't seem correct, not just because of the typo but because
> it returns 3 for T = int (assuming one == 1). Even if it was correct
> I'm not sure a smart optimizer couldn't make some assumptions about
> the dependency between current and max (they are both modified using
> exactly the same expression) that would cause the code to misbehave.
> 
> Martin
> 
> >
> > template <class T>
> > unsigned compute_byte_size()
> > {
> >     T max = T (one);
> >     T current = T (one);
> >     unsigned byte = 0;
> >     for (int I = 1; T (current * 2) > max; current *= 2, max *= 2,
i++)
> > {
> >         if (i > 8 ) {byte++; i = 1; }
> >     }
> >     return byte;
> > }
> >
> >
> >> Martin
> >


Re: [PATCH] STDCXX-423

Posted by Martin Sebor <se...@roguewave.com>.
Scott Zhong wrote:
> 
>> -----Original Message-----
>> From: Martin Sebor [mailto:sebor@roguewave.com]
>> Sent: Wednesday, February 20, 2008 12:26 PM
>> To: dev@stdcxx.apache.org
>> Subject: Re: [PATCH] STDCXX-423
>>
>> Scott Zhong wrote:
>> [...]
>>>>> As I write this, I realize that the my function,
>>> compute_byte_size(),
>>>>> can be optimized to shift one bit to the next byte boundary.
>>>> I don't think we need to (or should) worry about optimizing config
>>>> tests. What we might want to do is use the template parameter in
>>>> the signature of the function for non-conforming compilers that
>>>> have trouble with these types of things.
>>> Sorry I meant to say that its more of a code fix than optimization.
>>> Sizeof() returns the number of bytes so the function should check
> each
>>> byte instead of each bit.
>> But not all bits of every byte need to contribute to the value
>> representation of the object. IIUC, there can be 4 byte ints
>> (i.e., sizeof(int) == 4) with 29 bits for the value, 1 bit for
>> the sign, and 2 bits of padding.
>>
> 
> I had overlooked that fact, thank you for reminding me.
> 
>>>>> template <class T>
>>>>> unsigned compute_byte_size()
>>>>> {
>>>>>     T max = T (one);
>>>>>     unsigned byte = 0;
>>>>>     for (; T (max * 128) > max; max *= 128) {
>>>> FWIW, for signed T the expression T(max * 128) > max has undefined
>>>> behavior in the presence of overflow. We've seen at least two (if
>>>> not three) compilers exploit this presumably in some aggressive
>>>> optimizations (see, for example, STDCXX-482). Since most (all?)
>>>> hardware simply wraps around in the presence of overflow we just
>>>> need to prevent the compiler optimization here.
>>> Would the volatile keyword in front of "max" be sufficient here?
>> It might help, but I'm not sure it's guaranteed to. All it usually
>> does is make the compiler generate code that reloads the value of
>> the object from memory into a register on each access. The stage
>> I'm concerned with takes place before code generation based on what
>> the compiler can prove about the program. For all signed x, the
>> compiler is free to assume that in (x * N) > x, the subexpression
>> (x * N) doesn't overflow and thus (x * N) is always guaranteed to
>> be greater than x (for N > 0). To prevent it from making such an
>> assumption we need to rewrite the expression like so: (x * N) > y
>> while initializing x and y to the same value in such a way that
>> the compiler cannot prove that (x == y) holds.
>>
> 
> Would this suffice?

This doesn't seem correct, not just because of the typo but because
it returns 3 for T = int (assuming one == 1). Even if it was correct
I'm not sure a smart optimizer couldn't make some assumptions about
the dependency between current and max (they are both modified using
exactly the same expression) that would cause the code to misbehave.

Martin

> 
> template <class T>
> unsigned compute_byte_size()
> {
>     T max = T (one);
>     T current = T (one);
>     unsigned byte = 0;
>     for (int I = 1; T (current * 2) > max; current *= 2, max *= 2, i++)
> {
>         if (i > 8 ) {byte++; i = 1; }
>     }
>     return byte;
> }
> 
> 
>> Martin
>