Observable behavior and instruction reordering

D

DaKoadMunky

<CODE>

#include <iostream>
using namespace std;

int Foo(int x,int y)
{
int result = x;
result*=y;
result+=y;
return result;
}

int main()
{
cout<<Foo(2,4)<<endl; // I expect this to output 12 --LINE 1

cout<<Foo(4,2)<<endl; //I expect this to output 10 --LINE 2

return 0;
}

</CODE>

Are my expectations concerning the output of this program reasonable?

My concern stems from a lack of understanding of instruction reordering as it
relates to observable behavior.

Specifically I wonder if the expressions result*=y and result+=y in function
Foo could be swapped. That of course would change the meaning of Foo.
However, the following quote from the Draft Ansi C++ Standard makes me think
that the meaning of Foo is not observable behavior...

"The observable behavior of the abstract machine is its sequence of reads and
writes to volatile data and calls to library I/O functions."

Based on this quote the only behavior I would expect is that LINE 1 will
execute before LINE 2.

When a compiler reorders instructions that don't involve R/W to volatile data
and calls to library I/O functions how does it know that it is not changing the
meaning of a program?

Any insights as to what I am not grokking would be appreciated.
 
J

John Harrison

DaKoadMunky said:
<CODE>

#include <iostream>
using namespace std;

int Foo(int x,int y)
{
int result = x;
result*=y;
result+=y;
return result;
}

int main()
{
cout<<Foo(2,4)<<endl; // I expect this to output 12 --LINE 1

cout<<Foo(4,2)<<endl; //I expect this to output 10 --LINE 2

return 0;
}

</CODE>

Are my expectations concerning the output of this program reasonable?

My concern stems from a lack of understanding of instruction reordering as it
relates to observable behavior.

Specifically I wonder if the expressions result*=y and result+=y in function
Foo could be swapped. That of course would change the meaning of Foo.
However, the following quote from the Draft Ansi C++ Standard makes me think
that the meaning of Foo is not observable behavior...

"The observable behavior of the abstract machine is its sequence of reads and
writes to volatile data and calls to library I/O functions."

Based on this quote the only behavior I would expect is that LINE 1 will
execute before LINE 2.

When a compiler reorders instructions that don't involve R/W to volatile data
and calls to library I/O functions how does it know that it is not changing the
meaning of a program?

Any insights as to what I am not grokking would be appreciated.

If the instructions were reordered in the way you suggest then you would not
see cout << 12 followed by cout << 10 (you would see cout << 24 followed by
cout << 12), therefore the observable behaviour would have changed because
the values of the arguments used in a standard library call would have
changed, and therefore the compiler would not be allowed to do that
reordering.

John
 
B

bartek

(e-mail address removed) (DaKoadMunky) wrote in
<CODE>

#include <iostream>
using namespace std;

int Foo(int x,int y)
{
int result = x;
result*=y;
result+=y;
return result;
}

int main()
{
cout<<Foo(2,4)<<endl; // I expect this to output 12 --LINE 1

cout<<Foo(4,2)<<endl; //I expect this to output 10 --LINE 2

return 0;
}

</CODE>

Are my expectations concerning the output of this program reasonable?

My concern stems from a lack of understanding of instruction
reordering as it relates to observable behavior.

Specifically I wonder if the expressions result*=y and result+=y in
function Foo could be swapped. That of course would change the
meaning of Foo. However, the following quote from the Draft Ansi C++
Standard makes me think that the meaning of Foo is not observable
behavior...

"The observable behavior of the abstract machine is its sequence of
reads and writes to volatile data and calls to library I/O functions."

Based on this quote the only behavior I would expect is that LINE 1
will execute before LINE 2.

When a compiler reorders instructions that don't involve R/W to
volatile data and calls to library I/O functions how does it know that
it is not changing the meaning of a program?

Because the people who created it, told it to only reorder those things
that won't break the meaning of the program. Observable behaviour is not
the only criteria when dealing with instruction reordering, obviously.

Cheers.
 
T

tom_usenet

<CODE>

#include <iostream>
using namespace std;

int Foo(int x,int y)
{
int result = x;
result*=y;
result+=y;
return result;
}

int main()
{
cout<<Foo(2,4)<<endl; // I expect this to output 12 --LINE 1

cout<<Foo(4,2)<<endl; //I expect this to output 10 --LINE 2

return 0;
}

</CODE>

Are my expectations concerning the output of this program reasonable?

Yes, any standards conforming compiler should produce a program that
outputs:
12
10
My concern stems from a lack of understanding of instruction reordering as it
relates to observable behavior.

Specifically I wonder if the expressions result*=y and result+=y in function
Foo could be swapped. That of course would change the meaning of Foo.
However, the following quote from the Draft Ansi C++ Standard makes me think
that the meaning of Foo is not observable behavior...

"The observable behavior of the abstract machine is its sequence of reads and
writes to volatile data and calls to library I/O functions."

Based on this quote the only behavior I would expect is that LINE 1 will
execute before LINE 2.

"calls to library I/O functions" includes what is passed to those
functions! i.e. any reorderings that the compiler does must not change
the appearance of the output of a conforming program in any way.
When a compiler reorders instructions that don't involve R/W to volatile data
and calls to library I/O functions how does it know that it is not changing the
meaning of a program?

If it can't determine that it won't make a difference to observable
behaviour, it won't reorder (since it is forbidden by the standard).

Tom
 
T

Thomas Matthews

DaKoadMunky said:
<CODE>

#include <iostream>
using namespace std;

int Foo(int x,int y)
{
int result = x;
result*=y;
result+=y;
return result;
}

int main()
{
cout<<Foo(2,4)<<endl; // I expect this to output 12 --LINE 1

cout<<Foo(4,2)<<endl; //I expect this to output 10 --LINE 2

return 0;
}

</CODE>

Are my expectations concerning the output of this program reasonable?

My concern stems from a lack of understanding of instruction reordering as it
relates to observable behavior.

Specifically I wonder if the expressions result*=y and result+=y in function
Foo could be swapped. That of course would change the meaning of Foo.
However, the following quote from the Draft Ansi C++ Standard makes me think
that the meaning of Foo is not observable behavior...

"The observable behavior of the abstract machine is its sequence of reads and
writes to volatile data and calls to library I/O functions."

Based on this quote the only behavior I would expect is that LINE 1 will
execute before LINE 2.

When a compiler reorders instructions that don't involve R/W to volatile data
and calls to library I/O functions how does it know that it is not changing the
meaning of a program?

Any insights as to what I am not grokking would be appreciated.

A translator is allowed to set the ordering of the instructions as long
as the functionality remains the same.

In your example, changing the order of the mathematical assignments
will change the meaning. However, there is nothing stopping a
translator changing the order of the assignment operation.

Your function evaluates the expression: f(x,y) = x * y + y;
The actually assignment of the value to result could be postponed
or not even occur at all (since the value is returned and not
stored in any static memory location). For example, your function
could be translated as:
int Foo(int x, int y)
{
return x * y + y;
}
The above function provides the same functionality, but has
no assignment operations.

There are no libraries calls, no I/O and no volatile or static
variables.

However, changing the order of the operations will change the
functionality.

The rules allow for compilers to optimize code. The qualifiers
"static", "volatile" and "mutable" are used to control the
optimization. During debugging, I may declare a variable
in a function as "static" so that the variable isn't "optimized
away". I use "volatile" when accessing hardware values so that
the compiler doesn't "optimize away" a variable that is read
only once.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.comeaucomputing.com/learn/faq/
Other sites:
http://www.josuttis.com -- C++ STL Library book
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top