chris@mimsy.UUCP (Chris Torek) (12/16/87)
>>In article <9770@mimsy.UUCP> I wrote >>... why not just use `register'? ... [because] you cannot take the >>address of a register. To which, in article <6833@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn) replies: >That's not the answer! Sure it is. Watch: >The "noalias" type qualifier promises that the object can only be >modified by a single handle.... So does `register'. The key difference between `register' and `noalias' is that with `register' variables, the compiler refuses to allow you even to begin to provide a second handle for an object (by taking its address). >...thereby permitting the optimizer to do things that are not >safe otherwise.... f() { register int r; ... r = 1; g(); if (r == 1) ... Does the `if' succeed? Yes, because there is no way for g() to alter `r'. f() { register int r; ... r = 1; g(&r); if (r == 1) ... Oops, this is illegal. f() { noalias int r; ... r = 1; g(&r); if (r == 1) ... Is this true? Depends on the exact definition of noalias. Change it a bit: f1() { /* noalias */ int r; ... g(&r); r = 1; z(); if (r == 1) ... Is it? Without the `noalias', not necessarily; with `noalias', yes. So now we can discard the `register' keyword, since noalias is just a stronger form of it. (N.B.: `can' != `should'.) All I have been saying all along is that `register' and `noalias' really mean the same thing to a compiler that does not automatically put `register' vairables in machine registers. The real difference between the two keywords is that `noalias' says `even if I appear to be aliasing a variable, I am not', while `register' says `I promise not to alias this variable and you should stop me if I appear to do so'. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
gwyn@brl-smoke.ARPA (Doug Gwyn ) (12/16/87)
In article <9796@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >>>In article <9770@mimsy.UUCP> I wrote >>>... why not just use `register'? ... [because] you cannot take the >>>address of a register. >To which, in article <6833@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA >(Doug Gwyn) replies: >>That's not the answer! > f() { > register int r; > ... > r = 1; > g(); > if (r == 1) ... >Does the `if' succeed? Yes, because there is no way for g() to >alter `r'. That is true for any auto; "register" has nothing to do with it! If you mean that there is no way to form a pointer to r, that is of course correct, but a red herring. >All I have been saying all along is that `register' and `noalias' >really mean the same thing to a compiler that does not automatically >put `register' vairables in machine registers. No! No! No! "register" acts as a storage class while "noalias" is a type qualifier. This distinction shows up clearly when one compares register thing *p; /* p is possibly in a register */ and noalias thing *p; /* (*p), not p, is unaliased */ Consider adding to your choice of the above the following code: *p = 1; { /* should be a function, shown in-line for simplicity */ thing *q = (thing *)p; /* cast necessary if noalias */ *q = 0; } if ( *p ) ; /* noalias is allowed to get here */ else ; /* register always gets here */ See the difference? (I actually oversimplified the example. Don't take it too literally.) Another way to see that there is a difference is to realize that all the pointer parameters in the standard C library can be qualified noalias, except for memmove(). One would not say this of "register". Consideration of what is special about memmove() should provide a clue.
barmar@think.COM (Barry Margolin) (12/16/87)
In article <9796@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >>>In article <9770@mimsy.UUCP> I wrote >>>... why not just use `register'? ... [because] you cannot take the >>>address of a register. > >To which, in article <6833@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA >(Doug Gwyn) replies: >>That's not the answer! > >Sure it is. Watch: [followed by a number of good examples.] How about: noalias int r[5]; r[1] = 1; foo(r); if (r[1] == 1) ... Are arrays allowed to be declared "register"? --- Barry Margolin Thinking Machines Corp. barmar@think.com seismo!think!barmar
chris@mimsy.UUCP (Chris Torek) (12/16/87)
>>... `register' and `noalias' [can] really mean the same thing [me] >[but] "register" acts as a storage class while "noalias" is >a type qualifier. [Doug] Sure---but this is artificial; one could change this as easily as add `noalias'. (Well, `int register *p' *would* look a bit odd.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
chris@mimsy.UUCP (Chris Torek) (12/16/87)
(Just a correction!... more typos)
>... `int register *p'
I meant to type `int *register p'. (Arrh. That makes three errors
in three news articles within two days! I need to work on my editing.)
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
gwyn@brl-smoke.ARPA (Doug Gwyn ) (12/17/87)
In article <9807@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >>>... `register' and `noalias' [can] really mean the same thing [me] >>[but] "register" acts as a storage class while "noalias" is >>a type qualifier. [Doug] >Sure---but this is artificial; one could change this as easily as >add `noalias'. (Well, `int register *p' *would* look a bit odd.) You're missing what is really going on here. "register" was an aid to optimizer technology of the 70s; "noalias" is an aid to optimizer technology of the 80s. The type of optimizations these are supposed to help with have entirely different natures. "noalias" is intended to allow data loaded into temporary registers to continue to be used without having to reload it when some unrelated pointer-dereference storage occurs; also, it permits vectorization of operations on function array parameters, because of the non-overlapping guarantee. "register" attempts something much simpler, namely to help allocate limited fast storage to specified variables. That is why it is appropriate for "register" to be a storage class. The constraint against & applied to a register variable simply reflects the reality of common machine architecture (fast storage not necessarily being addressable). "noalias" is by no means just "register" with the &-constraint removed. It is a totally different concept with different semantic content and (possibly, if the optimizer takes advantage of it) different run-time effects on code behavior. I don't know what the next C standard (after the 198x one) will do to accommodate the optimizer technology of the 90s. Personally, I have not had much luck with optimizers and was glad that they aren't allowed to muck around much with the code that I write unless I deliberate instruct them to (by using appropriate keywords).
marty1@houdi.UUCP (M.BRILLIANT) (12/17/87)
In article <9817@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: > (Just a correction!... more typos) >>... `int register *p' > > I meant to type `int *register p'. (Arrh. That makes three errors > in three news articles within two days! I need to work on my editing.) Maybe C should have less abstruse type declarations. How about: type (pointer to register int) p; vs. type (register pointer to int) p; Wouldn't errors in such a format be harder to make and easier to find? Incidentally, I also find it easier to understand. M. B. Brilliant Marty AT&T-BL HO 3D-520 (201)-949-1858 Holmdel, NJ 07733 ihnp4!houdi!marty1
devine@cookie.dec.com (Bob Devine) (12/17/87)
In article <6833@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: > >The "noalias" type qualifier promises that the object can only be >modified by a single handle (as I said), thereby permitting the >optimizer to do things that are not safe otherwise [...] I dislike this creation. I can see that some time/space savings is possible *if it is used correctly* but I doubt it. I simply don't see it as worth the bother. Most folks would drop into assembly or otherwise recode if they are that concerned with optimization. I see problems with someone later recoding parts of a program and gets bitten by 'noalias' -- there are too many programmer (bad) habits. A better way, in hindsight, would have been to have a 'alias' keyword that designates those cases where multiple handles are used; all other cases could then be assumed to be optimizable. Too late. Finally, if the committee wants to provide the negative-name for attributes perhaps they should use 'noregister' instead of 'volatile'. Bob Devine ...!decwrl!cookie.dec.com!devine
ok@quintus.UUCP (Richard A. O'Keefe) (12/17/87)
In article <6845@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes: > register thing *p; /* p is possibly in a register */ > and > noalias thing *p; /* (*p), not p, is unaliased */ > Consider adding to your choice of the above the following code: > *p = 1; > { /* should be a function, shown in-line for simplicity */ > thing *q = (thing *)p; /* cast necessary if noalias */ > *q = 0; > } > if ( *p ) > ; /* noalias is allowed to get here */ > else > ; /* register always gets here */ > See the difference? > (I actually oversimplified the example. Don't take it too literally.) > I don't understand this. In Doug Gwyn's example, *p HAS AN ALIAS! That is, there are two ways (*p and *q) of getting at the same location. If this isn't illegal, what is the point of 'noalias'? This is definitely the wrong time to put 'noalias' in. The Committee have apparently rejected a number of otherwise sensible things on the grounds of "no prior art". This one they should reject because there IS prior art, and it turned out to be a bad idea. Remember PL/I? That was an incredibly complicated language that IBM used to sell. I believe some museum pieces still run it. You used to be able to say things like DECLARE FRED ENTRY(BINARY FLOAT) RETURNS(BINARY FLOAT) REDUCIBLE; DECLARE JIM BINARY FIXED PRECISION(15,0) ABNORMAL; What the first of these declarations meant was that if the compiler saw FRED(X) + FRED(X) it was entitled to compile it as FRED(X)*2.0, whereas if you said DECLARE FRED .... IRREDUCIBLE; it was obliged to produce two procedure calls. What the second of these declarations meant was that the compiler was entitled to assume that nobody would change JIM behind its back, so that if for example it saw JIM+JIM it was entitled to compile it as JIM*2. The PL/I manual I just checked explicitly says "If B is ABNORMAL, the expression B+B is not necessarily equivalent to the expression 2*B." One problem with this is that if a variable can change behind the compiler's back, it isn't just the compiler that gets confused. If B is ABNORMAL, what *is* the expression B+B equivalent to? But the main trouble with it was that you could lie to the compiler, quite inadvertently. It was an explicit feature of PL/I that it wasn't supposed to protect the programmer from himself, and my word, that was one feature you you could be sure of. Please, if something like 'noalias' is added to C, define it so that it is provably easy for a simple compiler to determine when the program is inconsistent with the declaration. Anyway, why are the Committee only doing half a job? What's the point of introducing NORMAL (the default being ABNORMAL) without introducing REDUCIBLE (the default being IRREDUCIBLE)? Having the C compiler recognise that sin(x) or strlen(s) only needs to be evaluated more than once in some complicated expression would be more useful to me than making promises about pointers that the compiler isn't apparently expected to check, and the 'noalias' attribute on the arguments is not enough to allow that optimisation.
jejones@mcrware.UUCP (James Jones) (12/17/87)
In article <9796@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes: > f() { > register int r; > ... > r = 1; > g(); > if (r == 1) ... > > Does the `if' succeed? Yes, because there is no way for g() to > alter `r'. Ah, but g() need not be the culprit. In the presence of setjmp()/longjmp(), an arbitrary stretch of code in f() could have been executed. (The particular case you show looks safe, but in general, one could have r = 1; if (setjmp(jbuf) != 0) { /* code not involving r */ } if (r == 1) { /* Shouldn't this always be true? Not necessarily... */ } r = 2; woof(); and somewhere in woof() or further down, longjmp() is called.) James Jones
mcdonald@uxe.cso.uiuc.edu (12/17/87)
>> f() { >> register int r; >> ... >> r = 1; >> g(); >> if (r == 1) ... >>Does the `if' succeed? Yes, because there is no way for g() to >>alter `r'. >That is true for any auto; "register" has nothing to do with it! >If you mean that there is no way to form a pointer to r, that is >of course correct, but a red herring. Really? int *xxxx; f() { int r; xxxx = &r; r = 1; g(); printf("%d",r); } g(){ *xxxx += 5 ;} What would happen if I had said " noalias int r" ? From what has been said, I have no earthly idea. ( Is it an error? If the compiler could recognize it as an error, why have it?) Doug McDonald
gwyn@brl-smoke.ARPA (Doug Gwyn ) (12/18/87)
In article <8712170057.AA17035@decwrl.dec.com> devine@cookie.dec.com (Bob Devine) writes: >In article <6833@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: > A better way, in hindsight, would have been to have a 'alias' keyword >that designates those cases where multiple handles are used; all other >cases could then be assumed to be optimizable. Too late. It was always too late for that! Existing practice (e.g. K&R C) requires that unqualified declarations behave as though pointer aliasing might be occurring (because it might). The default has to be "safe" behavior to agree with current C.
gwyn@brl-smoke.ARPA (Doug Gwyn ) (12/18/87)
In article <475@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes: >I don't understand this. In Doug Gwyn's example, *p HAS AN ALIAS! >That is, there are two ways (*p and *q) of getting at the same >location. If this isn't illegal, what is the point of 'noalias'? The point of my example was to show that the existence of an alias can affect the code behavior, assuming a highly-optimizing compiler takes the "noalias" qualifier seriously. Proper use of this would normally be not to do things like my example, but mostly to flag arguments to functions that are promised not to point to overlapping storage (although there are several other uses for "noalias"). "noalias" is sufficiently general that it is not feasible for all cases of run-time aliasing to be detected at compile time. And such aliasing would not be tested for at run time either, because the point is to permit otherwise "unsafe" optimizations, given that the programmer has (by using "noalias") promised that the code will only be used in ways that do not involve unsafe aliasing. The burden is on the programmer who specifies something as "noalias" to get it right, not on the compiler to check that he did. There are many things in C this way.. >Having the C compiler recognise that sin(x) or strlen(s) only needs to >be evaluated more than once in some complicated expression would >be more useful to me than making promises about pointers that >the compiler isn't apparently expected to check, and the 'noalias' >attribute on the arguments is not enough to allow that optimisation. True, "noalias" does not promise that a function has no side effects. It is rather rare that one encounters C code that could benefit from some such facility for flagging functions like that, but there is a lot of code that can take advantage of the new opportunity for optimization.
gwyn@brl-smoke.ARPA (Doug Gwyn ) (12/19/87)
In article <47000026@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes: > int *xxxx; > int r; > xxxx = &r; >What would happen if I had said " noalias int r" ? From what has been said, >I have no earthly idea. ( Is it an error? If the compiler could recognize it >as an error, why have it?) About the only error concerning "noalias" you would ever be likely to get would be an attempt to assign a pointer to noalias object into a pointer to plain object without using an explicit cast. (This may manifest itself as a function parameter type mismatch also.) The other direction is legal and safe. You can always take the address of a noalias object with &, obtaining a pointer to noalias object thereby; it would be the attempt to assign the pointer to a pointer to plain object that would generate the error.
jsb@dasys1.UUCP (Jim Baumbach) (12/20/87)
In article <6858@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: -In article <8712170057.AA17035@decwrl.dec.com> devine@cookie.dec.com (Bob Devine) writes: ->In article <6833@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: -> A better way, in hindsight, would have been to have a 'alias' keyword ->that designates those cases where multiple handles are used; all other ->cases could then be assumed to be optimizable. Too late. - -It was always too late for that! -The default has to be "safe" behavior to agree with current C. Sort of true, but the opposite decision was made vis a vis 'volatile'. Before the invention of volatile, all variables were potentially volatile and optimizers which treated them otherwise were WRONG. I had to use a work around to get my routine which checked for the ready bit to be set on my disc controller not to have the check removed by the optimizing compiler. In actuality, few cases of troublesome aliasing occur but a lot fewer cases of 'volatile' occur so it was safe to break one but not the other. -jim -- Jim Baumbach {uunet}!mstan\ Big Electric Cat Public Unix {bellcore,cmcl2}!cucard!dasys1!jsb New York, NY, USA {sun}!hoptoad/ or uunet!actnyc!fred!jsb
gwyn@brl-smoke.ARPA (Doug Gwyn ) (12/21/87)
In article <2270@dasys1.UUCP> jsb@dasys1.UUCP (Jim Baumbach) writes: >Before the invention of volatile, all variables were potentially volatile >and optimizers which treated them otherwise were WRONG. No, there was simply no guarantee one way or the other. Some flavors of PCC had a special hack that detected a probable reference to a Unibus device register and disabled optimizations for the expression containing it, much as "volatile" now does. The original (Ritchie) PDP-11 C compiler didn't do enough optimization for this to ever be an issue. (Of course, it didn't need to; the PDP-11 instruction set and C were a close match.)