jim@bnr-rsc.UUCP (Jim Somerville) (07/13/88)
I have a question on how compilers should handle shifting. Consider the following: unsigned int x; /* ints are 32 bits */ unsigned int y; y = x>>32; /* the 32 could also be the value of another variable */ What should be the value of y after the shifting is complete? a) x b) 0 c) none of the above Do I have a valid complaint if the compiler I am using gives x? -- Jim Somerville (bnr-vpa!bnr-rsc!jim) Phone: (613) 763-4497 Bell-Northern Research Usenet:utgpu!bnr-vpa!bnr-rsc!jim P.O. Box 3511, Station C, Ottawa, Ontario, Canada, K1Y 4H7
mahar@weitek.UUCP (Mike Mahar) (07/16/88)
The question (x>>32) has come up. K&R and ANSI-C say the result is undefined. The 68000 shift instruction will give you a 0. The 80286 shift instruction will give you a 0. The 80386 shift instruction will give you x. The Weitek XL shift instruction will give you x. I don't know what MIPS Co. 88000 or 29000 return but I suspect the C compiler does what the instruction does. The result stems from whether the machine truncates the shift amount to 5 bits before doing the shift. It is easy to see why the C standards punt on the issue. -- Mike Mahar UUCP: {turtlevax, cae780}!weitek!mahar
alanf%smile@Sun.COM (Alan Fargusson) (07/16/88)
In article <705@bnr-rsc.UUCP>, jim@bnr-rsc.UUCP (Jim Somerville) writes: > I have a question on how compilers should handle shifting. > What should be the value of y after the shifting is complete? > a) x > b) 0 > c) none of the above D: All of the above. It is implemetation dependent. > Do I have a valid complaint if the compiler I am using gives x? No. Since different hardware will implements the shift in different ways it would be rather difficult to define this. - - - - - - - - - - - - - - - - - - - - - Alan Fargusson Sun Microsystems alanf@sun.com ..!sun!alanf
davidsen@steinmetz.ge.com (William E. Davidsen Jr) (07/18/88)
In article <705@bnr-rsc.UUCP> jim@bnr-rsc.UUCP (Jim Somerville) writes: | What should be the value of y after the shifting is complete? | a) x | b) 0 | c) none of the above | | Do I have a valid complaint if the compiler I am using gives x? I would certainly think so. The action of a shift on an unsigned is pretty well defined, and the compiler you mention is not doing it. x>>32 should work the same on any machine, 8, 16, 32, or 64 bits. Also, the action of doing: x >>= 16; x>>= 16; better be the same as: x = x>>32; If your compiler isn't correcting for hardware characteristics I say it's broken. The idea of a C standard is that you don't have to build in a bunch of hardware checks at the source level. People will try to tell you that's the way the hardware shift works... there is no justification for that, you are talking about the C source, and it should work correctly. What is needed is compiler code to check for a constant shift of 31+ and load zero (no runtime penalty) and generated code for variable shifts which does (pseudocode): cmp shftreg,32 jnc lbl1 mov datareg,0 jmp lbl2 lbl1: shiftr datareg,shftreg lbl2: Of course the logic could be improved in a machine dependent way... in my opinion reliable operation is more important than speed. I have no objection to a compiler switch which allows "unsafe optimization," and use that feature in some places myself. "it doesn't matter how fast you get the wrong answer" -me -- bill davidsen (wedu@ge-crd.arpa) {uunet | philabs | seismo}!steinmetz!crdos1!davidsen "Stupidity, like virtue, is its own reward" -me
rogerk@mips.COM (Roger B.A. Klorese) (07/19/88)
In article <392@attila.weitek.UUCP> mahar@attila.UUCP (Mike Mahar) writes: >The question (x>>32) has come up. K&R and ANSI-C say the result is undefined. >I don't know what MIPS Co. 88000 or 29000 return but I suspect the C compiler >does what the instruction does. The M/1000 (MIPS R2000-based) gives x. -- Roger B.A. Klorese MIPS Computer Systems, Inc. {ames,decwrl,prls,pyramid}!mips!rogerk 25 Burlington Mall Rd, Suite 300 rogerk@mips.COM Burlington, MA 01803 I don't think we're in toto any more, Kansas... +1 617 270-0613
guy@gorodish.Sun.COM (Guy Harris) (07/19/88)
> I would certainly think so. The action of a shift on an unsigned is > pretty well defined, Yes, but the action of a shift *whose magnitude is equal to the number of bits in the operand* is not well defined by either K&R or by the January 11, 1988 ANSI C draft. K&R: 7.5 Shift operators ... The result is undefined if the right operand is negative, or greater than or equal to the length of the object in bits. ANSI C: 3.3.7 Bitwise shift operators ...If the value of the right operand is negative or is greater than or equal to the width in bits of the promoted left operand, the behavior is undefined. > x>>32 should work the same on any machine, 8, 16, 32, or 64 bits. Also, the > action of doing: > x >>= 16; x>>= 16; > better be the same as: > x = x>>32; Perhaps they *should*; however, neither the K&R nor the January 11 ANSI C draft specifications for the language require this. If you think that they should, I suggest you lobby the ANSI C committee.
baum@Apple.COM (Allen J. Baum) (07/19/88)
[] >In article <60137@sun.uucp> alanf%smile@Sun.COM (Alan Fargusson) writes: >In article <705@bnr-rsc.UUCP>, jim@bnr-rsc.UUCP (Jim Somerville) writes: >> I have a question on how compilers should handle shifting. > >> What should be the value of y after the shifting is complete? >> a) x >> b) 0 >> c) none of the above > >D: All of the above. It is implemetation dependent. > >> Do I have a valid complaint if the compiler I am using gives x? > >No. Since different hardware will implements the shift in different ways it >would be rather difficult to define this. Our Cray will give x!=0, since an int is 64 bits.... -- {decwrl,hplabs,ihnp4}!nsc!apple!baum (408)973-3385
earl@mips.COM (Earl Killian) (07/19/88)
In article <11556@steinmetz.ge.com> davidsen@steinmetz.ge.com (William E. Davidsen Jr) writes:
From: davidsen@steinmetz.ge.com (William E. Davidsen Jr)
Date: 18 Jul 88 15:19:38 GMT
I would certainly think so. The action of a shift on an unsigned is
pretty well defined, and the compiler you mention is not doing it. x>>32
should work the same on any machine, 8, 16, 32, or 64 bits. Also, the
action of doing:
x >>= 16; x>>= 16;
better be the same as:
x = x>>32;
By extension
x >>= 16; x >>= 16; x >>= 16; x >>= 16;
x >>= 16; x >>= 16; x >>= 16; x >>= 16;
x >>= 16; x >>= 16; x >>= 16; x >>= 16;
x >>= 16; x >>= 16; x >>= 16; x >>= 16;
should give the same answer as
x >>= 256;
but I doubt very many C implementations do this. Most architectures
look at 5, 6, 7, or 8 bits of the shift count. It always seemed
inconsistent to me to look are more than 5 (i.e. log2(bitsperword))
without looking at all of them.
--
UUCP: {ames,decwrl,prls,pyramid}!mips!earl
USPS: MIPS Computer Systems, 930 Arques Ave, Sunnyvale CA, 94086
rick@pcrat.UUCP (Rick Richardson) (07/19/88)
In article <392@attila.weitek.UUCP> mahar@attila.UUCP (Mike Mahar) writes: >The question (x>>32) has come up. K&R and ANSI-C say the result is undefined. >The 68000 shift instruction will give you a 0. >The 80286 shift instruction will give you a 0. This depends upon your 80286 compiler, whether x is an int or a long, and whether you try shift 16 or 32 bits. The AT&T 80286 compiler (GET THIS!) actually detects: some_long >> 32 some_int >> 32 and explicity generates code to give the result as "some_long" or "some_int"! At first, I thought this implementation choice was for consistency with the case where the shift count is a variable. But alas, if x is "32": some_long >> x gives result "0" some_int >> x gives result "some_int" So this compiler isn't even consistent in its treatment of this problem. -- Rick Richardson, PC Research, Inc. (201) 542-3734 (voice, nights) OR (201) 389-8963 (voice, days) uunet!pcrat!rick (UUCP) rick%pcrat.uucp@uunet.uu.net (INTERNET)
davidsen@steinmetz.ge.com (William E. Davidsen Jr) (07/19/88)
In article <2620@wright.mips.COM> earl@mips.COM (Earl Killian) writes: | In article <11556@steinmetz.ge.com> davidsen@steinmetz.ge.com (William E. Davidsen Jr) writes: | | ... stuff I wrote ... | By extension | x >>= 16; x >>= 16; x >>= 16; x >>= 16; | x >>= 16; x >>= 16; x >>= 16; x >>= 16; | x >>= 16; x >>= 16; x >>= 16; x >>= 16; | x >>= 16; x >>= 16; x >>= 16; x >>= 16; | should give the same answer as | x >>= 256; | but I doubt very many C implementations do this. Most architectures | look at 5, 6, 7, or 8 bits of the shift count. It always seemed | inconsistent to me to look are more than 5 (i.e. log2(bitsperword)) | without looking at all of them. I consider this to be a major botch in an implementation, *particularly* on fixed shifts where the problem can be detected at compile time. There is *no* portable way to put in a check for shift out of range, unless you check the range at runtime, which is possible but messy. Guess it's a quality of implementation issue. I'm actually trying to see what various C compilers do with this. Perhpas the only portable way to do it is with a loop, one bit at a time. I think you were agreeing with me... -- bill davidsen (wedu@ge-crd.arpa) {uunet | philabs | seismo}!steinmetz!crdos1!davidsen "Stupidity, like virtue, is its own reward" -me
henry@utzoo.uucp (Henry Spencer) (07/20/88)
In article <11556@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes: > ... The action of a shift on an unsigned is pretty well defined... Not if it's shifting the full number of bits, it's not. Different machines handle this case differently. > If your compiler isn't correcting for hardware characteristics I say >it's broken. The idea of a C standard is that you don't have to build in >a bunch of hardware checks at the source level. Not quite. The idea of a C standard is to be a treaty between the user and the implementor. It tells the user what he can expect from the compiler, and -- just as important -- what he CAN'T expect from the compiler. One thing he cannot expect, in C, is for the compiler to try to cover up the underlying hardware. That is not the way C works. > What is needed is compiler code to check for a constant shift of 31+ >and load zero (no runtime penalty)... What if the shift count is a runtime quantity? Any such shift has to pay the penalty of bounds checking, even if the programmer knows full well that it's never more than (say) 3 bits. Please don't tell me that the penalty is only a few instructions; those few instructions can add up (especially if they include branches, which pipelined machines really hate). X3J11 has tried to avoid, on principle, any features that would require run-time checks on orthodox machines. Assigning specific semantics to overflow behavior -- which is what shifting all the bits out amounts to -- is such a feature in most cases. >...in my opinion reliable operation is more important than speed... Reliable operation means operation which obeys the rules of the language. If the language rules say -- as X3J11 does -- that the effect of such a shift is implementation-defined, then there is no reliability issue involved, except insofar as the programmer has to *understand* the language he is using in order to produce working programs. This is not Fortran or Pascal; C has always given people more than enough rope to hang themselves, for the sake of fast execution of programs written by those who *do* know what they're doing. Nobody ever said it was suitable for beginners. -- Anyone who buys Wisconsin cheese is| Henry Spencer at U of Toronto Zoology a traitor to mankind. --Pournelle |uunet!mnetor!utzoo! henry @zoo.toronto.edu
jlg@beta.lanl.gov (Jim Giles) (07/21/88)
In article <2620@wright.mips.COM>, earl@mips.COM (Earl Killian) writes: > [...] It always seemed > inconsistent to me to look are more than 5 (i.e. log2(bitsperword)) > without looking at all of them. But log2(bitsperword) is 6! 32 bits is only a half a word on a 'real' machine :-) J. Giles Los Alamos
guy@gorodish.Sun.COM (Guy Harris) (07/21/88)
> Contrary to the other two follow-ups I've seen (when will > people learn not to react without thinking), yes you do have a > valid complaint. The C language (both K+R and X3J11) > guarantees that X >> n is a logical shift, with 0 padding on > the left, when X is an unsigned quantity, as it is in this > case. It is only when X is not unsigned, that a right shift is > implementation dependant. I don't know which follow-ups *you* saw; none of the ones *I* saw said *anything* about smearing the sign bit. All the ones I saw pointed out, quite correctly, that he did *not* have a valid complaint, because the result of shifting a signed *or* unsigned 32-bit quantity right by 32 bits is undefined. It might arguably be more correct to say that complaining that his compiler wasn't "doing the right thing" according to some language specification wasn't valid. He could, I suppose, complain that the language specification should say what happens when you shift by more than the size of the LHS, in bytes, or that the hardware shouldn't take the shift count modulo 32, or that the compiler should "do the right thing" even though it's not required by the language specification; these might or might not be considered valid complaints depending on your point of view.
davidsen@steinmetz.ge.com (William E. Davidsen Jr) (07/21/88)
In article <1988Jul19.173807.6604@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: | Reliable operation means operation which obeys the rules of the language. | If the language rules say -- as X3J11 does -- that the effect of such a | shift is implementation-defined, then there is no reliability issue | involved, except insofar as the programmer has to *understand* the language | he is using in order to produce working programs. This is not Fortran or | Pascal; C has always given people more than enough rope to hang themselves, | for the sake of fast execution of programs written by those who *do* know | what they're doing. Nobody ever said it was suitable for beginners. The rules may say anything is undefined, but that doesn't make it a good idea. At one time early in standards process, the question of having sizes known to the preprocessor was discussed. At that time my recollection is that sizeof was not to be allowed in a preprocessor constant expression, although reading the standard certainly seems to say it is at this time. Then the user could use conditional code as: #include <limits.h> #define UNSIGN_BIT (CHAR_BIT)*sizeof(unsigned)) #if UNSIGN_BIT < MAX_SHIFT /* brain damaged stuff, user runtime checks */ if (shift >= UNSIGN_BIT) valu = 0; else valu >>= shift; #else /* reasonable machine */ valu >>= shift; #endif My reason for saying the sizeof now seems legal is: section 3.8 p83 l15: #if takes a constant expression section 3.8.1 p84 l19-27: definition of const expr section 3.3.3.4 p43 l22: action of sizeof operator section 2.2.4.2 p13 l30-34: CHAR_BIT in limits.h The only thing disallowed in 3.8.1 is casts, and footnote 74 disallows keywords. However sizeof is an operator as defined in 3.3.3.4. If sizeof is NOT legal in preprocessor directives, then the standard should be clarified, and there is simply no way (known to me) to determine the size of int in bits at preprocessor time. It can be found, of course, at runtime, but that precludes use of conditional code to avoid checks where they are not needed. Yes, I've been programming C for awhile (since it was spelled B and ran on the GE600) and I can program around stuff like this. I'm sure Henry can, too. If C is ever going to be a portable general purpose language rather than a toy for hackers, programmers should not have to guess that two shifts of 10 don't give the same result as one shift of 20 (or whatever the sizes may be), or any of the other non-intuitive things which happen in the name of speed. Getting speed should be an "unsafe optimization," like dropping stack checking, ignoring alias problems, etc. It has a definite place and I don't deny that I would use it. The default should be to have the source code work as written. -- bill davidsen (wedu@ge-crd.arpa) {uunet | philabs | seismo}!steinmetz!crdos1!davidsen "Stupidity, like virtue, is its own reward" -me
henry@utzoo.uucp (Henry Spencer) (07/22/88)
In article <440@softway.oz> stephenf@softway.UUCP (Stephen Frede) writes: >Contrary to the other two follow-ups I've seen (when will >people learn not to react without thinking), yes you do have a >valid complaint. The C language (both K+R and X3J11) >guarantees that X >> n is a logical shift, with 0 padding on >the left, when X is an unsigned quantity, as it is in this >case. It is only when X is not unsigned, that a right shift is >implementation dependant. Sorry, Stephen, but in this case you're the one who's reacting without thinking. The first paragraph of the Semantics subsection of section 3.3.7 of the second-public-comment draft states: If the value of the right operand... is greater than or equal to the width in bits of the... left operand, the behavior is undefined. This applies to *all shifts*, not just signed ones. Somewhat further down we find another statement to the effect that right shifts of negative signed numbers give implementation-defined values. Note that these two statements don't say quite the same thing, either: right shift of a negative signed number yields an implementation-defined value, that is, a well-defined value that depends on the implementation in a way that the implementation is required to document, while shift-all-bits yields undefined behavior, that is, it can do anything it pleases. -- Anyone who buys Wisconsin cheese is| Henry Spencer at U of Toronto Zoology a traitor to mankind. --Pournelle |uunet!mnetor!utzoo! henry @zoo.toronto.edu
chris@mimsy.UUCP (Chris Torek) (07/22/88)
In article <440@softway.oz> stephenf@softway.oz (Stephen Frede) writes: >Contrary to the other two follow-ups I've seen .... The C language >(both K+R and X3J11) guarantees that X >> n is a logical shift, with >0 padding on the left, when X is an unsigned quantity, as it is in this >case. It is only when X is not unsigned, that a right shift is >implementation dependant. This is correct. The amount of the shift, however, must not be negative, or greater than or equal to the length of the object in bits (K&R, p. 189). Since this was `x >> 32' and x was a 32 bit (or smaller) object, the amount of the shift was too large, and the result is thus undefined, before we ever get to the question as to whether the result is implementation defined. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
chris@mimsy.UUCP (Chris Torek) (07/22/88)
In article <11606@steinmetz.ge.com> davidsen@steinmetz.ge.com (William E. Davidsen Jr) writes: >reading the [draft proposed X3J11 C] standard certainly seems to >say [that sizeof is allowed in preprocessor expressions] at this time. >... If sizeof is NOT legal in preprocessor directives, then the standard >should be clarified, ... It is explicitly disallowed in one tiny clause in the second most recent draft. (I have not yet had time to look at the most recent draft.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
henry@utzoo.uucp (Henry Spencer) (07/24/88)
In article <11606@steinmetz.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes: > The rules may say anything is undefined, but that doesn't make it a >good idea. At one time early in standards process, the question of >having sizes known to the preprocessor was discussed. At that time my >recollection is that sizeof was not to be allowed in a preprocessor >constant expression, although reading the standard certainly seems to >say it is at this time. You have an out-of-date draft, I believe. The second-public-comment draft (I haven't seen the third yet) explicitly forbids sizeof in this context. >... If C is ever going to be a portable general purpose >language rather than a toy for hackers, programmers should not have to >guess that two shifts of 10 don't give the same result as one shift of >20 (or whatever the sizes may be), or any of the other non-intuitive >things which happen in the name of speed. To slightly misquote DMR: "if you want Pascal, you know where to find it". C is already a portable general purpose language, one which specializes in speed rather than in coddling novice C programmers. Consider an analogy. Effective and safe use of a fully-equipped vertical milling machine requires learning and practicing page after page of procedures and precautions; it is *not* something you can learn in five minutes, and the machine can -- literally -- kill you if you get sloppy. Building it out of soft plastic would make it much safer. However, for a real machining job, I want the metal one, despite its complex procedures and the very real dangers incurred in the name of rapid and precise machining. >... The default should be to have the source code work as written. It already does. When you write >> in a C program, that is the C >> operator you are writing, not some abstract mathematical version with different properties. -- Anyone who buys Wisconsin cheese is| Henry Spencer at U of Toronto Zoology a traitor to mankind. --Pournelle |uunet!mnetor!utzoo! henry @zoo.toronto.edu
stephenf@softway.oz (Stephen Frede) (07/25/88)
In article <440@softway.oz> stephenf@softway.oz (Stephen Frede (me)) writes: >Contrary to the other two follow-ups I've seen .... [silliness] I had hoped the cancel message would spread quick enough to save me too much embarassment. Unfortunately not, but I deserve it all. The followups to my article are of course correct. The other followups to the original article hadn't reached here when I originally posted. - Stephen
davidsen@steinmetz.ge.com (William E. Davidsen Jr) (07/25/88)
henry@utzoo.uucp (Henry Spencer) writes: | You have an out-of-date draft, I believe. The second-public-comment draft | (I haven't seen the third yet) explicitly forbids sizeof in this context. I believe what I have is current. I got it a week ago and it's marked as THIRD public review. The many references were all based on that draft. Another note, from the sizeof (3.3.3.4) section, line 23. Constraints =========== The _sizeof_ operator shall not be applied to an expression function type or an incomplete type, to the parenthesized name of such a type, or to an lvalue that designates a bitfield object. Chris Tokek said that there was a obscure phrase which disallowed use of sizeof in the preprocessor, but 3.8.1 on the #if says that the 2nd argument is a constant expression, and 3.4 (constant expressions) says: Constraints =========== Constant expression shall not contain assignment, increment, decrement, function call, or comma operators, except when they when they are contained within the operand of a sizeof operator. This is the only reference to constant expression in the index. If the semantics of the #if say that the first field is a constant expression, and the definition of constant expression specifically includes sizeof, either sizeof is legal in the expression of #if, or perhaps the phrase is a bit too obscure. I didn't think this was legal, but after some time checking the standard I thank that the standard *seems* to say that it is. Since this discussion has gotten split between comp.std.c, comp.lang.c and comp.arch, I have directed followup to comp.std.c, since the question has changed to a standards issue. -- bill davidsen (wedu@ge-crd.arpa) {uunet | philabs | seismo}!steinmetz!crdos1!davidsen "Stupidity, like virtue, is its own reward" -me
davidsen@steinmetz.ge.com (William E. Davidsen Jr) (07/26/88)
In article <12638@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: | In article <11606@steinmetz.ge.com> davidsen@steinmetz.ge.com | (William E. Davidsen Jr) writes: | >reading the [draft proposed X3J11 C] standard certainly seems to | >say [that sizeof is allowed in preprocessor expressions] at this time. | >... If sizeof is NOT legal in preprocessor directives, then the standard | >should be clarified, ... | | It is explicitly disallowed in one tiny clause in the second most recent | draft. (I have not yet had time to look at the most recent draft.) Actually I believe that the clause you mention was deleted. Here is a message and my reply: ================================================================ From: dmr@research.att.com Date: Tue, 26 Jul 88 01:15:16 EDT To: wedu@ge-crd.arpa Subject: #if sizeof p. 87, line 24-25 of the Jan draft (the constraint in 3.8.1) say "Additional restrictions apply.... The expression ... shall not contain a sizeof operator...." Dennis Ritchie ==== Subject: Re: #if sizeof Date: 26 Jul 88 08:36:16 EDT (Tue) From: davidsen@crdos1.UUCP (Wm E. Davidsen) Thanks for the reference from the January draft. The v3 draft in 3.8.1 constraints says: The expression that controls conditional inclusion shall be an integral constant expression except that: it shall not contain a cast; identifiers (including those lexically identical to keywords) are interpreted as described below{74}; and it may contain unary operator expressions of the form: defined identifier or defined ( identifier ) which evaluate to 1 if the identifier is currently defined as a macro name (that is, if it is predefined or if it has been the subject of a #define preprocessing directive without an intervening #undef directive with the same subject identifier), 0 if not. Each preprocessing token which remains after all macro replacements have occured shall be in the lexical form of a token. ---------------------------------------------------------------- 74 Because the controlling constant expression is evaluated during translation phase 4, all identifiers either are or are not macro names - there simply are no keywords, enumeration constants, and so on. Whatever was in the January draft seems to be removed. ================================================================ I can believe that this is a typo, although I would rather believe that sizeof is now allowed. -- bill davidsen (wedu@ge-crd.arpa) {uunet | philabs | seismo}!steinmetz!crdos1!davidsen "Stupidity, like virtue, is its own reward" -me