September 15, 2002

Walter wrote:
> "Robert W. Cunningham" <FlyPG@users.sourceforge.net> wrote in message
> news:3D7FD186.4480CC4A@users.sourceforge.net...
> 
>>Presently, not only does D not allow you to prevent enregistration, it
>>does not allow you to atomically bypass the CPU cache.  Both are needed
>>tigether in order to obtain true "volatile" behavior.
> 
> 
> I've got the "volatile" statement now implemented, as in:
> 
>     volatile a = *p;
> 
> It will prevent any caching of values into and out of the volatile
> statement.

Uh...

    struct Registers
    {
        struct Data
        {
            int a;
        }

        Data data;

        int a () { return volatile data.a; }
        void a (int value) { data.a = value; }
    }

Would that work, or would the get property have to be:

    int a ()
    {
        int value;
        volatile value = data.a;
        return value;
    }

If so, that's pretty heavy stuff for what will be the most common usage.  I'd rather have a function that's turned intrinsic in semantic0, as it retains the "easy to parse dumbly" rule and doesn't have bad worst cases for syntax.

September 15, 2002
"Sean L. Palmer" <seanpalmer@earthlink.net> wrote in message news:alqi86$1pla$1@digitaldaemon.com...
> So there's nothing preventing you from writing code like this?
>
> void BreakStuff(char* c)
> {
>     *c = 2;
> }
>
> int main()
> {
>     const char s = 1;
>     BreakStuff(&s);
>     printf("now it's %d\n",s); // prints 2.
> }
>
> Yeah that const storage class really does a lot of good.
>
> You say const pointers never once saved you from a bug.  Congratulations. They certainly help me out, if only as sanity checks.  If I can get the compiler to verify any part of the correctness of my code, that's great.

I agree const as a type modifier does have some utility, I argue that it is minor compared with the cost of it.

Some other points:

o D does not allow taking the address of a const. Storage is not necessarilly even allocated for a const.

o While D allows one to pass pointers around, it is almost never necessary to do so. Use out and inout parameters, which should give an error when used with const variables.

o In D, if you do wind up using a pointer, it is for either interfacing with C or for doing something unusual that presumptively you're careful with. You can do anything with pointers in D - they're meant as a way around the typing system.

o C doesn't help much there anyway, nothing stops casting away const'ness and modifying it.

o The example will still print 1, not 2, because the implementation assumes that s is 1 and will substitute in the 1 in the printf. This is unlike C, since because const isn't guaranteed to be immutable, the compiler cannot make such an assumption.




September 15, 2002
"Burton Radons" <loth@users.sourceforge.net> wrote in message news:3D842697.6080208@users.sourceforge.net...
>      struct Registers
>      {
>          struct Data
>          {
>              int a;
>          }
>
>          Data data;
>
>          int a () { return volatile data.a; }
>          void a (int value) { data.a = value; }
>      }
>
> Would that work, or would the get property have to be:
>
>      int a ()
>      {
>          int value;
>          volatile value = data.a;
>          return value;
>      }
>
> If so, that's pretty heavy stuff for what will be the most common usage.
>   I'd rather have a function that's turned intrinsic in semantic0, as it
> retains the "easy to parse dumbly" rule and doesn't have bad worst cases
> for syntax.

volatile return data.a;

should work fine.


September 15, 2002
Walter wrote:

> "Robert W. Cunningham" <FlyPG@users.sourceforge.net> wrote in message news:3D7FD186.4480CC4A@users.sourceforge.net...
> > Presently, not only does D not allow you to prevent enregistration, it does not allow you to atomically bypass the CPU cache.  Both are needed tigether in order to obtain true "volatile" behavior.
>
> I've got the "volatile" statement now implemented, as in:
>
>     volatile a = *p;
>
> It will prevent any caching of values into and out of the volatile statement.

Hmmm... That's very different from what I'm used to.

I'd prefer to be able to say "when taking the value of this thing, treat it as volatile, no matter how it is dereferenced, or when, or where".

Suppse I have a global pointer to a hardware register (say, a 32-bit real-time clock/counter).  Adding "volatile" to each and every use will be a nightmare.  Missing just one could ruin an entire application, and be next to impossible to detect and debug.

Which means all my volatile items would probably need to be single-reference, and thus need to be wrapped within a function call or an object.  I'd need an explicit "inline" statement to ensure I can access the dereferenced pointer value in "real-time".

Unless I have misunderstood the meaning and use, this interpretation of "volatile" looks like a non-starter to me.


-BobC


September 15, 2002
Walter wrote:
> "Burton Radons" <loth@users.sourceforge.net> wrote in message
> news:3D842697.6080208@users.sourceforge.net...
> 
>>     struct Registers
>>     {
>>         struct Data
>>         {
>>             int a;
>>         }
>>
>>         Data data;
>>
>>         int a () { return volatile data.a; }
>>         void a (int value) { data.a = value; }
>>     }
>>
>>Would that work, or would the get property have to be:
>>
>>     int a ()
>>     {
>>         int value;
>>         volatile value = data.a;
>>         return value;
>>     }
>>
>>If so, that's pretty heavy stuff for what will be the most common usage.
>>  I'd rather have a function that's turned intrinsic in semantic0, as it
>>retains the "easy to parse dumbly" rule and doesn't have bad worst cases
>>for syntax.
> 
> 
> volatile return data.a;
> 
> should work fine.

Oh... kay.  So what's the advantage over a function?  Why does it earn its additional parsing complexity?  This also requires the compiler to have knowledge of every statement and expression and how to make it non-caching; the function-based method is just a guaranteed dereference.

The property-based read is going to be the most common - I'd even predict that using stuff like "volatile for..." will be consigned to the criminally insane, as leaving it to the caller to manage volatile is a bad idea (but as a property it's fine).  So supporting it doesn't look to have much particular extra value.

September 15, 2002
"Burton Radons" <loth@users.sourceforge.net> wrote in message news:3D8466B4.3080008@users.sourceforge.net...
> > volatile return data.a;
> >
> > should work fine.
>
> Oh... kay.  So what's the advantage over a function?

It's more convenient. No dummy functions.

> Why does it earn
> its additional parsing complexity?

Not sure what you mean. A volatile statement is almost no code to implement.

>  This also requires the compiler to
> have knowledge of every statement and expression and how to make it
> non-caching; the function-based method is just a guaranteed dereference.

No, it's pretty trivial to implement. It requires no knowledge of the statements being processed. Each statement gets processed into a sequence of basic blocks. The compiler just marks those blocks as being conceptually like asm blocks - already taken care of within the optimizer.

> The property-based read is going to be the most common - I'd even predict that using stuff like "volatile for..." will be consigned to the criminally insane, as leaving it to the caller to manage volatile is a bad idea (but as a property it's fine).  So supporting it doesn't look to have much particular extra value.

I was thinking it would be good for things like:

    for (int i = 0; i < 1000; i++)
        volatile sum += *p;



September 15, 2002
"Robert W. Cunningham" <FlyPG@users.sourceforge.net> wrote in message news:3D84342E.948C934@users.sourceforge.net...
> Walter wrote:
> > "Robert W. Cunningham" <FlyPG@users.sourceforge.net> wrote in message news:3D7FD186.4480CC4A@users.sourceforge.net...
> > > Presently, not only does D not allow you to prevent enregistration, it does not allow you to atomically bypass the CPU cache.  Both are
needed
> > > tigether in order to obtain true "volatile" behavior.
> > I've got the "volatile" statement now implemented, as in:
> >     volatile a = *p;
> > It will prevent any caching of values into and out of the volatile
> > statement.
> Hmmm... That's very different from what I'm used to.

It is a different way of looking at the issue, but I think it does address your concerns.

> I'd prefer to be able to say "when taking the value of this thing, treat
it
> as volatile, no matter how it is dereferenced, or when, or where".

That's the type modifier approach.

> Suppse I have a global pointer to a hardware register (say, a 32-bit
> real-time clock/counter).
> Adding "volatile" to each and every use will be a
> nightmare.  Missing just one could ruin an entire application, and be next
> to impossible to detect and debug.

The compiler isn't that good at caching values. <g> Caching is nearly always very localized, and is flushed anyway when any assignments through a pointer are done. The only time this can be an issue is if two reads are done with no intervening indirect assignments of any sort. That includes assigning to any globals/statics, assigning to arrays, or calling functions.

> Which means all my volatile items would probably need to be single-reference, and thus need to be wrapped within a function call or an object.

You could do it that way - and is a common oo technique with property gettors and settors. The gettors and settors get inline expanded, so there's no performance penalty for using them.

> I'd need an explicit "inline" statement to ensure I can access the dereferenced pointer value in "real-time".

I think that would be unnecessary. Even the most basic inlining capability will inline a function that consists of nothing but return *p;

> Unless I have misunderstood the meaning and use, this interpretation of "volatile" looks like a non-starter to me.

Can you post a bit of code that would cause particular grief?



September 16, 2002
Walter wrote:

> "Robert W. Cunningham" <FlyPG@users.sourceforge.net> wrote in message news:3D84342E.948C934@users.sourceforge.net...
> > Suppse I have a global pointer to a hardware register (say, a 32-bit
> > real-time clock/counter).
> > Adding "volatile" to each and every use will be a
> > nightmare.  Missing just one could ruin an entire application, and be next
> > to impossible to detect and debug.
>
> The compiler isn't that good at caching values. <g> Caching is nearly always very localized, and is flushed anyway when any assignments through a pointer are done. The only time this can be an issue is if two reads are done with no intervening indirect assignments of any sort. That includes assigning to any globals/statics, assigning to arrays, or calling functions.

It seems you may have a biased view of the vast array of caching strategies used by the wide variety of processors out there!  Generally, read and write (and instruction fetch) caching are handled by separate, independent hardware subsystems.  Whatever caching the compiler may or may not do is secondary to whatever hardware caching may be going on.

I don't really care all that much about assignment (write) caching (for the
hardware, I configure it when the processor boots and can generally forget
about it).  I do care very much about access (read) caching (since the hardware
read cache is always enabled, and I want to bypass it when I need to).

So, I do agree that compiler caching isn't much of an issue.  But that is only a small part of what "volatile" must handle.


> > Which means all my volatile items would probably need to be single-reference, and thus need to be wrapped within a function call or an object.
>
> You could do it that way - and is a common oo technique with property gettors and settors. The gettors and settors get inline expanded, so there's no performance penalty for using them.

Other than they are MUCH heavier than simply having a *p wherever I need to access a volatile value.

A typical snippet, say for a timer:

if (*p > last_time) { ... }

I do this all the time in C.  It is especially handy when many items need to be tested very quickly.  Such as an array of 8000 IPC mailboxes.

If any access were to fetch a prior value from a hardware cache or a CPU register, the program would not be getting the data it needs (which is a true read cycle to the hardware).


> > I'd need an explicit "inline" statement to ensure I can access the dereferenced pointer value in "real-time".
>
> I think that would be unnecessary. Even the most basic inlining capability will inline a function that consists of nothing but return *p;

It just seems like extra window dressing (baggage) and ahssle for D to do something that is so easy in C.

It's like training a dog:  If I say "fetch" and the dog doesn't fetch, the dog will be disciplined.  Well, OK, it's not exactly like training a dog:  If I say "fetch" and my compiler doesn't do a true "fetch", the compiler will be taken out and shot.


-BobC


September 16, 2002
"Robert W. Cunningham" <FlyPG@users.sourceforge.net> wrote in message news:3D8571DA.5BAE5977@users.sourceforge.net...
> So, I do agree that compiler caching isn't much of an issue.  But that is
only
> a small part of what "volatile" must handle.

How should code be generated differently?

> Other than they are MUCH heavier than simply having a *p wherever I need
to
> access a volatile value.
> A typical snippet, say for a timer:
>
> if (*p > last_time) { ... }
>
> I do this all the time in C.  It is especially handy when many items need
to be
> tested very quickly.  Such as an array of 8000 IPC mailboxes.
> If any access were to fetch a prior value from a hardware cache or a CPU
> register, the program would not be getting the data it needs (which is a
true
> read cycle to the hardware).

p.get() is only 5 characters more, and no extra code is actually generated.

> It just seems like extra window dressing (baggage) and ahssle for D to do something that is so easy in C.

The trouble is how it percolates through the typing system, affecting everything from function overloading to template partial ordering to template argument deduction to template partial specialization. It just winds up adding a great deal of complexity.


September 18, 2002
Walter wrote:

> "Robert W. Cunningham" <FlyPG@users.sourceforge.net> wrote in message news:3D8571DA.5BAE5977@users.sourceforge.net...
> > So, I do agree that compiler caching isn't much of an issue.  But that is
> only
> > a small part of what "volatile" must handle.
>
> How should code be generated differently?

I don't keep this stuff in my head!  Back in the day, I'd go to the processor manual and look it up.  And I haven't used an x86 processor on an embedded project since the 8086.  But I do know that "volatile" works just fine on an x86!

I don't have to look at CPU manuals any more:  These days, GCC does "volatile" well on all platforms I use it on.  Which probably means that GCC-D will likely have a "proper" volatile, since GCC itself already has the code to handle it on all platforms.

That's good enough for me!


> > Other than they are MUCH heavier than simply having a *p wherever I need
> to
> > access a volatile value.
> > A typical snippet, say for a timer:
> >
> > if (*p > last_time) { ... }
> >
> > I do this all the time in C.  It is especially handy when many items need
> to be
> > tested very quickly.  Such as an array of 8000 IPC mailboxes.
> > If any access were to fetch a prior value from a hardware cache or a CPU
> > register, the program would not be getting the data it needs (which is a
> true
> > read cycle to the hardware).
>
> p.get() is only 5 characters more, and no extra code is actually generated.

But how much more code is generated?  More importantly, how many times longer does it take to execute that code compared to "*p"?

If there is absolutely zero difference (it is one or two instructions), then you and I are describing identical functionality, only from different perspectives.

But if there is any difference, then your version of volatile will be both "big" and "slow", and not all that useful for systems programming.


> > It just seems like extra window dressing (baggage) and ahssle for D to do something that is so easy in C.
>
> The trouble is how it percolates through the typing system, affecting everything from function overloading to template partial ordering to template argument deduction to template partial specialization. It just winds up adding a great deal of complexity.

Then simply outlaw "volatile" for ALL those uses!  I want a fast, simple, clean volatile.  Not a new type (sub)system.

I only need "volatile" for specific pointers that, when dereferenced, will ALWAYS drill through the cache and read the hardware directly.

It need not be elegant or general:  "Possible" and "fast" will suffice.


Hmmm... If the implementation of your proposed volatile syntax is both light and fast, I suppose I could make your initial proposal meet my needs, but I'd need to add a notational layer that would need to be handled by a preprocessor.  If that will work, I'm fine with it.

For example, I'd place my "volatile" declarations in encoded comments, use an initial preprocessor pass to extract the list of variable names that are "volatile", then use a final preprocessor pass to wrap all references with your notation.  So long as I don't have to do it manually, it will probably work for me.

I've written several such systems that used encoded comments.  The key is to do so in a way that keeps debugging sane enough to use the original source file (instead of the post-processed file).  I don't see that being a problem here.

But I'd much prefer a solution that didn't demand preprocessing for it to be both general and robust.

Preprocessing would kill one of D's special characteristics.  But it would be OK if it enabled the use of D for direct hardware-level programming.


Hmmmm....  I could do that same transformation if I had access to your parse tree.  Which means your compiler should be able to do it just as easily.


-BobC