Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

BLOCK construct

Nick_M_3
New Contributor I
2,209 Views

This does not appear to be supported.

PROGRAM Main
    INTEGER :: x
    BLOCK
        VOLATILE :: x
        x = 0
    END BLOCK
END PROGRAM Main

gerbil.f90(3): error #5082: Syntax error, found END-OF-STATEMENT when expecting one of: DATA
    BLOCK
---------^
etc.

0 Kudos
21 Replies
Steven_L_Intel1
Employee
1,910 Views

Compiler version 14 doesn't support BLOCK. Version 15 (due out later this month) does. However, that version does not support adding the VOLATILE or ASYNCHRONOUS attribute to a variable using BLOCK - that will come later.

0 Kudos
Nick_M_3
New Contributor I
1,910 Views

Thanks.  I was actually just investigating yet more deficiencies in the standard, to do with circumstances in which the use of coarrays is forbidden but objects with coarray components is not.  I am pretty certain that most of those are oversights.

My personal view is that anyone who plays games with VOLATILE will get what they so richly deserve!  But you know that ....

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,910 Views

>>My personal view is that anyone who plays games with VOLATILE will get what they so richly deserve!

Volatile has its purpose. Don't shy away from matches just because you got burned once.

Jim Dempsey

0 Kudos
Nick_M_3
New Contributor I
1,910 Views

You should read what I post more carefully.  Aliasing volatile and non-volatile variables is asking for trouble, in any language, because the latter can be optimised aggressively enough to break the semantics of the former.

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,910 Views

In the case of your first post you have omitted IMPLICIT NONE. Nothing inherently wrong with that per-se.

However, the code example also includes a BLOCK, containing "VOLATILE :: X".

This now creates an ambiguity (possibly resolved in the specification), as to if the statement instantiates a new (implicit) variable X or uses the outer scoped X with a (possibly) different attribute. Steve may be able to comment on this.

Regardless, if you are permitted to change the attribute, then you do not have aliases. You simply changed the methodology rules for how to reference the variable. On the other hand, if this instantiates a new X, then again you do not have an alias situation as you have two different storage locations.

So where is the alias?

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,910 Views

Nick knows exactly what he was doing in his example. Fortran 2008 allows you to "append" the ASYNCHRONOUS or VOLATILE attribute to a variable for the scope of a BLOCK construct in this manner. Otherwise, any declaration of a variable in BLOCK creates a new, locally-scoped variable. 

I'm well aware of Nick's opinion of VOLATILE - from his perspective as an academic, it means that the compiler has no idea what is going on with the variable and many assumptions that are normally made are out the window. I think we'd all agree that in certain applications, especially those that interact with non-Fortran code, VOLATILE is sometimes a necessary evil.

0 Kudos
Nick_M_3
New Contributor I
1,910 Views

Well, actually, it's from my perspective as someone who tries to help users with code failures they don't understand, often ones that are not repeatable!  I have many times been in a position of explaining to a user that their C code exposes an inconsistency in the C standard, and that the vendor's claim that it is a user error and the user's claim that it is a compiler error are equally justifiable.  Fortran is better, but there is a nasty ambiguity/inconsistency that I would like to close.  Also, the same issue applies to atomic and non-atomic accesses.

Simple code like that doesn't show the problem, but consider accessing a variable by both its volatile and non-volatile aliases.  What does that imply?  Other than the user is asking for trouble, of course :-)

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,910 Views

The use of VOLATILE as new attribute for variable within block is not creating an alias (multiple variables referencing same/overlapping storage). What it is doing, is changing the access rules for X. I suppose in some sense you could say there is an alias between the register copy and the memory copy... but that alias was there all along. It was not created by the VOLATILE.

What is not known to me, as I haven't dug in to the specification, nor tested compliance, is what the compiler does, or is required to do, with any registered copy of X (alias of X) it has prior to entry to the block. IOW forget it if same or write it if different, unspecified, or worse specified as undefined?

In the case of: not specified in specification and/or don't know, and/or compiler writer's situation is "didn't take this into consideration". Then I would expect first reference of X as read within the block to obtain the memory storage value of X and not use the compiler known copy of X, and in the event where the copy of X is modified, this then exposes a compiler error. Conversely, when the memory storage of X is modified externally to the compiler context, not reading the memory copy would introduce an error as well. Note, this case is not a case of a problem with VOLATILE, it would be a bug in the compiler (or lack in specification as to what to do in this circumstance), or a bug in the user program by not using VOLATILE when it was expressly required.

VOLATILE is not an evil -- it is a tool.

0 Kudos
Nick_M_3
New Contributor I
1,910 Views

Look, this was a simplified example, specifically to show up a compiler issue.  Think use, host or argument association, all of which can be used the same way.  Even with BLOCK, you can do this:

    INTEGER, TARGET :: x

    INTEGER, POINTER :: p

    INTEGER, POINTER, VOLATILE :: q

    p => x

    BLOCK

        VOLATILE ::x

        q => x

You now have two names p and q that refer to the same object, one with VOLATILE and one without.   Now pass those to an external subroutine, and consider code like:

    a = p    ! No VOLATILE, remember?

    b = q

    c = p

If x changes, are a and c allowed to be the same, but b different?  THAT is the sort of thing that causes trouble!  And that is why I say that aliasing volatile and non-volatile variables is asking for trouble.

> VOLATILE is not an evil -- it is a tool.

So is a chainsaw with no guard or dead man's switch.

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,910 Views

The root of the problem is you are passing in aliases to the subroutine and expecting (requiring) them to be separate entities.

The subroutine will not follow the VOLATILE rules, unless of course the dummies of that subroutine are also attributed as volatile. Now then, with both dummies marked volatile the fact that in the called subroutine you modify one of the dummies (representing the variable reference by the other), and it is observed by referencing the other variable, is expressly what you expect to happen through use of VOLATILE, assuming you really intended to pass aliases and not rely of the compiler to accidentally cache one or both of these in register(s). Now if this is not what you want to happen, then do not pass aliases, or pass as one, a value (at time of call).

The fact that VOLATILE (assuming placed in called subroutine on both args) exposes the problem does not make VOLATILE the problem. The problem is the aliasing (and expecting/requiring they be not).

Note, it is highly likely that under your above circumstance, and the expectation of the code behavior you describe, that running that code without the volatiles in Debug build would "fail" in the same manner as release with volatiles. Note "fail", as on the flip-side you were lucky you got the answer you wanted. IOW programming by chance.

The fact that you create aliases requires that you know what you are doing with the aliases, and know your responsibilities.

>>aliasing volatile and non-volatile variables is asking for trouble

Aliasing without knowing what you are doing is asking for trouble. The same subroutine called without volatiles but with aliases has the same issues. The behavior in release and debug builds will differ (in a similar way that you observed with volatile).

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,910 Views

RE: So is a chainsaw with no guard or dead man's switch.

The above is a perfect metaphor to describe a "political correctness" position against VOLATILE.

People who do not know how to operate a chain saw, are not aware that the chain guard is used to protect the chain from damage during storage and transport. It does have a side effect of protecting a klutz from injuring self or others while the saw in non-operational.

In addition to a chain guard, you can additionally add a kick guard bar tip to help prevent kickbacks. However, use of this hobbles full operational capability of the chain saw: a) diameter of wood you can cut is reduced by more than 1/2, and b) it inhibits plunge cuts (lesser used technique used by experienced operators).

Jim Dempsey

0 Kudos
Izaak_Beekman
New Contributor II
1,910 Views

Nick M. wrote:

Also, the same issue applies to atomic and non-atomic accesses.

Hi Nick,

Could you please elaborate on the issues surrounding atomic and non-atomic access? Is this statement made in regard to F2008’s atomic_ref(), atomic_define() and atomic_int_kind? Under what sort of circumstances can one get into trouble here? 

I have started using atomics to coordinate communication between coarray images, and want to make sure I don’t get in over my head. Right now I ensure that remote images always use atomic_ref() to query the state of an atomic variable, and the local image is the only one that is allowed to change its state with an atomic_define(). 

Thanks for any insight you may provide

0 Kudos
Nick_M_3
New Contributor I
1,910 Views

Izaak Beekman wrote:

Could you please elaborate on the issues surrounding atomic and non-atomic access? Is this statement made in regard to F2008’s atomic_ref(), atomic_define() and atomic_int_kind? Under what sort of circumstances can one get into trouble here? 

Yes.  Well, there are several ways, all of which I am hoping to get closed in the standard.

One is that you can pass an array of atomic variables as non-coarrays past a copy-in/copy-out call, synchronise, and update atomically (properly synchronised) on another image.  Provided that you don't access the array (but merely associate it) on the first image, that's not currently forbidden by the existing wording, but it won't work because the copy-out will restore the old value.

There are more subtle aspects on some systems (including older Intel CPUs and hybrid MIC/ordinary systems) where you need to generate special code in order to ensure that atomics behave 'properly', because they are partially exempt from the image ordering rules.  The current wording in the standard punts on the semantics, so all of x86, SPARC and POWER consistency rules are allowed.  The first is causally consistent, but does cause some algorithms to fail, but the last uses a weaker model.  And, once you access a single variable using both ordinary accesses and atomic ones (even when legal), all bets are off on all systems - the compiler can do anything.

There are lots of variations on both of these, some much harder to explain, but the summary is that having a single variable associated or accessed as a non-coarray or by ordinary coarray operations at the same time it is associated or accessed by an atomic subroutine is Bad News.  Most of these are currently locked out for ordinary variables, though not all, but atomics introduce several new ways to cause confusion.

Izaak Beekman wrote:

I have started using atomics to coordinate communication between coarray images, and want to make sure I don’t get in over my head. Right now I ensure that remote images always use atomic_ref() to query the state of an atomic variable, and the local image is the only one that is allowed to change its state with an atomic_define(). 

That's the right way to do it.  Basically, if you don't play games, you are FAIRLY safe.  What you mustn't do is to use an atomic variable as an ordinary variable or coarray - EVER - unless you know for certain what code is likely to be generated.  Just as for volatile.  But there's no guarantees in the standard, and the effect is that both have system-dependent semantics.

The trouble is that only people with extensive experience on multiple architectures and compilers are likely to know what you can get away with.  Their semantics is not precisely defined, and so different readers of the standard (e.g. multiple compiler vendors, users etc.) read the wording differently.  I am hoping to get this improved in the next standard.

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,910 Views

Steve,

Can you explain why the ATOMIC_xxx has not been "extended" to include ATOM's that are non-coarray/non-coindex?

Although you can use !$OMP ATOMIC... this does then require builds with OpenMP enabled as opposed to use with other threading techniques (POSIX, ...).

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,910 Views

ATOMIC and CRITICAL are all part of the coarray feature. There has never been an attempt to make these operate outside of coarrays and Fortran does not have "threading" per se. One needs mechanisms to synchronize images and these are among those methods.

0 Kudos
Izaak_Beekman
New Contributor II
1,910 Views

Nick M. wrote:

One is that you can pass an array of atomic variables as non-coarrays past a copy-in/copy-out call, synchronise, and update atomically (properly synchronised) on another image.  Provided that you don't access the array (but merely associate it) on the first image, that's not currently forbidden by the existing wording, but it won't work because the copy-out will restore the old value.

I think I follow you here. In general I find one has to be *EXTREMELY* careful with coarrays and image control statements in the context of procedures and argument association; it is all to easy to think you are achieving the desired effect, while actually effecting something else.

[qoute=Nick M.]

There are more subtle aspects on some systems (including older Intel CPUs and hybrid MIC/ordinary systems) where you need to generate special code in order to ensure that atomics behave 'properly', because they are partially exempt from the image ordering rules.  The current wording in the standard punts on the semantics, so all of x86, SPARC and POWER consistency rules are allowed.  The first is causally consistent, but does cause some algorithms to fail, but the last uses a weaker model.  And, once you access a single variable using both ordinary accesses and atomic ones (even when legal), all bets are off on all systems - the compiler can do anything.

I don’t know much about hardware, but does this mean that if one *only* ever defines (using atomic_define) an atomic variable on this_image() it must always be referenced with atomic_ref() on this image? Obviously referencing it from a different image would require an atomic_ref() but I thought it would be safe to reference it on the RHS of this_image() in expressions, without the use of atomic_ref. Am I mistaken?

Nick M. wrote:

There are lots of variations on both of these, some much harder to explain, but the summary is that having a single variable associated or accessed as a non-coarray or by ordinary coarray operations at the same time it is associated or accessed by an atomic subroutine is Bad News.  Most of these are currently locked out for ordinary variables, though not all, but atomics introduce several new ways to cause confusion.

Quote:

Izaak Beekman wrote:

I have started using atomics to coordinate communication between coarray images, and want to make sure I don’t get in over my head. Right now I ensure that remote images always use atomic_ref() to query the state of an atomic variable, and the local image is the only one that is allowed to change its state with an atomic_define(). 

 

That's the right way to do it.  Basically, if you don't play games, you are FAIRLY safe.  What you mustn't do is to use an atomic variable as an ordinary variable or coarray - EVER - unless you know for certain what code is likely to be generated.  Just as for volatile.  But there's no guarantees in the standard, and the effect is that both have system-dependent semantics.

So to elaborate on my original description of my usage of atomics, and rephrase my question above; If an atomic variable is only ever defined through atomic_define() and always from this_image() can it safely appear in expressions on this_image() or must it also be referenced using atomic_ref() from this_image()?

0 Kudos
Nick_M_3
New Contributor I
1,910 Views

I am not making myself clear - sorry :-(

What I was meaning was that you should use only ATOMIC_DEFINE and ATOMIC_REF to set and extract the value from any image, and never use that variable in ordinary assignments, expressions, procedure arguments etc.  That can be done, but you need very VERY careful to get it right, so I recommend not doing it.  Ever.  And don't trust ANY interaction with any other facility except image control statements (and most especially not VOLATILE!)  That rule is simple to describe and simple to follow.

The bigger problem, which is the one you refer to, is that the consistency and 'progress' of atomic variables is not specified.  Those are infernally hard to describe, unfortunately.  Steve probably knows what the Intel compiler guarantees, but I don't, and I can tell you that each compiler will be different (and future versions of the Intel ones probably will be, too).  Your method of using it is one of the safer ones, but that's the most that I can guarantee.  For a relatively comprehensible description, look at (say);

    http://en.wikipedia.org/wiki/Consistency_model

0 Kudos
Izaak_Beekman
New Contributor II
1,910 Views

Thank you so much for your response, Nick. I will replace any references to the atomic variable with atomic_ref()s, even if I know that it is only ever defined (by atomic_define) from this_image(). Off to read up about memory consistency models.

0 Kudos
Izaak_Beekman
New Contributor II
1,910 Views

Is block construct supported in Version 15.0.0.077 Build 20140716? If so I am getting compiler errors saying it’s not.

0 Kudos
Steven_L_Intel1
Employee
1,731 Views

Yes, it is. Please show us a source that demonstrates the problem.

0 Kudos
Reply