September 11, 2002
"Joe Battelle" <Joe_member@pathlink.com> wrote in message news:alnutu$i46$1@digitaldaemon.com...
> >Ok, but in the particular example here it cannot be hoisted anyway
because
> >the assignment to the array log[] invalidates all pointer references.
> OK.  I guess my point is that it doesn't have to.  I mean, I think without
the
> volatile specifier, it would be natural for an optimizer to deref p.data
once
> above the loop and put it in a register.  I don't see how assigning the
deref'd
> value to an array element would keep the deref (not the assignment) from
being
> hoisted in all D implementations.

The optimizer has to be painfully conservative. In this case, there's no way the optimizer can verify that the array log[] does not overlap whatever p points to. Do people write code like that? Often enough - and the people that do are usually the ones unable to figure out why their code breaks when optimized and they blame the compiler. It's the famed C 'aliasing' problem.

> >That's probably a better solution. The trouble with volatile as a type modifier is its ripple effects throughout the typing system.
> Understood.  And I think it's very reasonable to do things differently
than in
> C++ if it keeps the complexity of the compiler down.

Yes. Glad you understand! It's important for me, in designing a language, to:

1) understand what the problem is, not just implement a solution

If I understand the problem correctly, I have a chance at implementing a better solution.

2) recognize the scope of the problem

If the scope of the problem is fairly small, it can justify a more targetted solution. For example, volatile permeates partial specialization rules in C++ templates - but why on earth would you be using such to access hardware registers? But you can't get away from it because volatile is a type modifier, so everything that uses types must account for it. It's using a sledgehammer to squash a flea.


September 11, 2002
"Sean L. Palmer" <seanpalmer@earthlink.net> wrote in message news:alnu26$e30$1@digitaldaemon.com...
> You can have pointers to constants too.  How do you deal with that?

D doesn't have pointers to constants as a type. I eventually abandoned all use of const pointers in my C++ code, having discovered:

1) It never once saved me from a bug.
2) There was a significant nuisance involved in getting it all
const-correct.
3) The optimizer can't make use of const info, since one can legitimately
cast away const-ness.
4) I write compilers, and I still have a hard time remembering if the const
goes to the left of the * or the right, or exactly where it goes in more
complex type declarations.

While const as a storage class makes sense, and is implemented in D, const as a type does not.

> I'm sorry... I don't have a problem with C++ type modifiers.  In fact I'd rather have more modifiers, even user-defined ones.

Ok <g>.



September 12, 2002
Russell Lewis wrote:

> What about defining a class with gettors and settors?  You would still have to do some of the hard work, but it would allow you to have something like a struct with volatile members...

That's still a function call, which amount to nothing more than a PEEK or POKE.

Plus, whatever you do within the gettor/settor could still get cached!

You really need to be able to "drill-down" to the physical environment. That is, if I want a bus cycle to occur (read or write), then by God it must occur when and how I want it to!

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.


-BobC


September 12, 2002
Walter wrote:

> "Sean L. Palmer" <seanpalmer@earthlink.net> wrote in message news:alnu26$e30$1@digitaldaemon.com...
> > You can have pointers to constants too.  How do you deal with that?
>
> D doesn't have pointers to constants as a type. I eventually abandoned all use of const pointers in my C++ code, having discovered:
>
> 1) It never once saved me from a bug.
> 2) There was a significant nuisance involved in getting it all
> const-correct.
> 3) The optimizer can't make use of const info, since one can legitimately
> cast away const-ness.
> 4) I write compilers, and I still have a hard time remembering if the const
> goes to the left of the * or the right, or exactly where it goes in more
> complex type declarations.
>
> While const as a storage class makes sense, and is implemented in D, const as a type does not.
>
> > I'm sorry... I don't have a problem with C++ type modifiers.  In fact I'd rather have more modifiers, even user-defined ones.
>
> Ok <g>.

I agree!  Let's replace "const" with "ROM", just to make the difference perfectly clear.  The implementation should simply disallow write cycles to that location.  This can be supported in the compiler, but it can be absolutely guaranteed by placing consts in a separate memory area/page and setting the appropriate MMU bits!

Similarly, the compiler can support "volatile", but volatile items should be assigned MMU protection flags that force cache invalidation upon access (which is how hardware does volatile).

When there is no MMU, forcing "read-thru" on a cache can be a bit harder, but most embedded CPUs allow you to enable cache for only a specified memory range.  Anything outside that range (no matter if it is RAM, ROM or hardware) cannot and will not be cached.  Just be sure the hardware designers keep all the cacheable stuff contiguous within the memory map, and all will be well.

For example, on my embedded multiprocessor projects, I often intentionally place part of the RAM outside the cache.  It may then be used as mailboxes and semaphores by all processors, with the guarantee the all processors have the same view of that memory at all times.  (And all embedded processors I'm aware of support an atomic read-modify-write cycle, so again hardware helps.)  The central OS has to enforce the "guarantee" for processes residing in common memory that is cached.  All RTOS's I've used do this quite well.


-BobC


September 12, 2002
"Robert W. Cunningham" <FlyPG@users.sourceforge.net> wrote in message news:3D7FD42F.DA459077@users.sourceforge.net...
> I agree!  Let's replace "const" with "ROM", just to make the difference perfectly clear.  The implementation should simply disallow write cycles
to
> that location.  This can be supported in the compiler, but it can be absolutely guaranteed by placing consts in a separate memory area/page and setting the appropriate MMU bits!

That's how const works as a storage class now - but it is up to the implementation if it wants to place them in ROM or not.

> Similarly, the compiler can support "volatile", but volatile items should
be
> assigned MMU protection flags that force cache invalidation upon access
(which
> is how hardware does volatile).
>
> When there is no MMU, forcing "read-thru" on a cache can be a bit harder,
but
> most embedded CPUs allow you to enable cache for only a specified memory range.  Anything outside that range (no matter if it is RAM, ROM or
hardware)
> cannot and will not be cached.  Just be sure the hardware designers keep
all
> the cacheable stuff contiguous within the memory map, and all will be
well.
>
> For example, on my embedded multiprocessor projects, I often intentionally place part of the RAM outside the cache.  It may then be used as mailboxes
and
> semaphores by all processors, with the guarantee the all processors have
the
> same view of that memory at all times.  (And all embedded processors I'm
aware
> of support an atomic read-modify-write cycle, so again hardware helps.)
The
> central OS has to enforce the "guarantee" for processes residing in common memory that is cached.  All RTOS's I've used do this quite well.

Do you see a "volatile" segment in the executable, analogously to a "rom" segment?


September 12, 2002
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.

Sean

"Walter" <walter@digitalmars.com> wrote in message news:alo3rr$1ab1$1@digitaldaemon.com...
>
> "Sean L. Palmer" <seanpalmer@earthlink.net> wrote in message news:alnu26$e30$1@digitaldaemon.com...
> > You can have pointers to constants too.  How do you deal with that?
>
> D doesn't have pointers to constants as a type. I eventually abandoned all use of const pointers in my C++ code, having discovered:
>
> 1) It never once saved me from a bug.
> 2) There was a significant nuisance involved in getting it all
> const-correct.
> 3) The optimizer can't make use of const info, since one can legitimately
> cast away const-ness.
> 4) I write compilers, and I still have a hard time remembering if the
const
> goes to the left of the * or the right, or exactly where it goes in more complex type declarations.
>
> While const as a storage class makes sense, and is implemented in D, const as a type does not.
>
> > I'm sorry... I don't have a problem with C++ type modifiers.  In fact
I'd
> > rather have more modifiers, even user-defined ones.
>
> Ok <g>.
>
>
>


September 12, 2002
Sean L. Palmer wrote:

> 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.
> }

You cannot write such code in D. You simply can't take address of
a constant, because constants don't have addresses - they are
just values, inserted in-place where constant is used.

There is no such C++ nonsense as "constant variable" in D. Constant is a constant. Variable is a variable. You cannot use variables where constants are expected (in case-block, for example). Nor can you use constants where variables (and lvalues in general) are required - as out arguments etc

September 13, 2002
So it's not possible to force the compiler to pass a large constant by reference?

It's often tricky to initialize something using initializer syntax.  How will you build complex constants?  Do constants then always have to be known at compile time?

If what you're saying is true I'd expect not to be able to build any kind of structure out of constants such as a static const linked list.  Can't take addresses, can't have lists.  Or graphs.

I suppose if nobody modifies a thing, and nobody externally can modify a thing (not public) then for all intents and purposes it is const, but it's sure nice to be able to keep people from modifying stuff without the no-address restriction.  Is there a way to get around this?  People will abuse it (witness mutable in C++, a way to declare a something as constant to everyone but me.  Not constant so much as read-only;. at least to you.)

I guess there are two different things people use const for... real constants (forever unchanging values) and read-only access protection.  D only supports the former.

Sean

"Pavel Minayev" <evilone@omen.ru> wrote in message news:alqlrj$26ks$1@digitaldaemon.com...
> Sean L. Palmer wrote:
>
> > 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.
> > }
>
> You cannot write such code in D. You simply can't take address of a constant, because constants don't have addresses - they are just values, inserted in-place where constant is used.
>
> There is no such C++ nonsense as "constant variable" in D. Constant is a constant. Variable is a variable. You cannot use variables where constants are expected (in case-block, for example). Nor can you use constants where variables (and lvalues in general) are required - as out arguments etc



September 14, 2002
Walter wrote:

> Do you see a "volatile" segment in the executable, analogously to a "rom" segment?

Yup!  But only if there was no other way to obtain it.  Since a compiler has to be targeted for its platform (CPU + OS), that targeting would have to provide the most logical implementation of volatile for that platform.

Some CPU instruction sets have instruction prefixes that flag the associated data access(es) as "read-thru".  For such CPUs, D could handle the entire issue itself, with no need for a volatile segment in the executable or OS support.

The problem with volatile segments is that many of the standard executable formats don't allow for it, so it can't be presented to the loader. Fortunately, most platforms where this might be needed have implemented suitable extensions to the executable format.  Extensions which, unfortunately, tend to be proprietary.

Most platforms provide an OS call to map any memory segment as desired, so the needed logic can generally be added to the program startup code (the venerable cstart.a on C systems, which I've hacked many a time).


-BobC


September 14, 2002
"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.