473,800 Members | 2,523 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Defeating Optimisation for memcmp()

Please consider the following code fragment. Assume UINT32 is a typedef
suitable for defining variables of 32 bits, and that ui32 is initialised.

UINT32 ui32;
/* ... */
/* assume ui32 now is holding a value in uc's range */
unsigned char uc = (unsigned char) ui32; /* tell Lint you know target
type is smaller */
cmos->uc = uc;

/* Check the CMOS write was successful */
/* NOTE: I know third arg evals to 1, but sizeof is used for readability
*/
if (memcmp(cmos->uc, &uc, sizeof(unsigned char)) != 0)
/* CMOS write failed */

I would expect a decent compiler to optimize away the memcmp(). Would you
agree that this change will ensure the memcmp is not optimized away?:

UINT32 ui32;
/* ... */
/* assume ui32 now is holding a value in uc's range */
volatile unsigned char uc = (unsigned char) ui32; /* tell Lint you know
target type is smaller */
cmos->uc = uc;
/* Check the CMOS write was successful */
if (memcmp(cmos->uc, &uc, sizeof(unsigned char)) != 0)
/* CMOS write failed */

Is a call to a library function (memcmp) less likely to be optimised away
than use of relational operators (a) when one of the operands is volatile,
and (b) when neither are volatile?

For example,

if ( cmos->uc != uc )
/* CMOS write failed */

compared to

if (memcmp(cmos->uc, &uc, sizeof(unsigned char)) != 0)
/* CMOS write failed */

Thank-you in advance.

--
Martin

Nov 10 '07 #1
39 3937

"Ben Bacarisse" wrote:
Presumably you mean '&cmos->uc'? The same typo appears several times
so I am not sure.
It's my mistake Ben - I did miss the ampersand for memcmp()'s first
argument. It should of course be as you say.

--
Martin

Nov 10 '07 #2
Martin wrote:
[...]
Is a call to a library function (memcmp) less likely to be optimised away
than use of relational operators (a) when one of the operands is volatile,
and (b) when neither are volatile?
The call has undefined behavior if *either* operand is
volatile. 6.7.3p5:

[...] If an attempt is made to refer to an object
defined with a volatile-qualified type through use of
an lvalue with non-volatile-qualified type, the
behavior is undefined.

There's a quibble: If memcmp is not implemented in C, it does
not use C lvalues to access anything at all and thus might
skirt the prohibition. But then there's 7.1.4p1:

If an argument to a function has an invalid value (such
as a value outside the domain of the function, or a
pointer outside the address space of the program, or a
null pointer, or a pointer to non-modifiable storage when
the corresponding parameter is not const-qualified) [...]
the behavior is undefined.

True, volatile is not mentioned. However, the list of ways in
which an argument can be invalid is prefaced by "such as," a
construct suggestive of a non-exhaustive list.

Finally, there's 6.3.2.3p2:

For any qualifier q, a pointer to a non-q-qualified type
may be converted to a pointer to the q-qualified version
of the type [...]

The point is that the conversion in the other direction is not
described as legal: You can add qualifiers in a conversion, but
you cannot subtract them. If you hand a pointer-to-volatile to
memcmp (which expects a pointer-to-const), I think the compiler
is required to issue a diagnostic -- and if it then accepts and
runs the program anyhow, all bets are off.

The solution to your problem is to qualify the "CMOS" thing
as volatile, and use an ordinary comparison:

struct {
...
volatile unsigned char uc;
...
} *cmos = ...;

cmos->uc = uc;
if (cmos->uc == uc) ...

The compiler is not permitted to optimize away any of the accesses
to cmos->uc, because the volatile qualifier declares that those
accesses have side-effects, just like calls to putchar(). The
compiler cannot "just know" that the comparison will turn out
true; it must actually perform it. That's what volatile does.

--
Eric Sosman
es*****@ieee-dot-org.invalid
Nov 10 '07 #3
Eric Sosman <es*****@ieee-dot-org.invalidwrit es:
Martin wrote:
>[...]
Is a call to a library function (memcmp) less likely to be optimised
away than use of relational operators (a) when one of the operands
is volatile, and (b) when neither are volatile?

The call has undefined behavior if *either* operand is
volatile. 6.7.3p5:
<snip>
The point is that the conversion in the other direction is not
described as legal: You can add qualifiers in a conversion, but
you cannot subtract them.
I stand (implicitly) corrected. I should have seen this. This is why
c.l.c is so worth reading To the OP: ignore (most of) what I wrote!

--
Ben.
Nov 10 '07 #4

"Eric Sosman" wrote:
The solution to your problem is to qualify the "CMOS" thing
as volatile, and use an ordinary comparison:

struct {
...
volatile unsigned char uc;
...
} *cmos = ...;

cmos->uc = uc;
if (cmos->uc == uc) ...

The compiler is not permitted to optimize away any of the accesses
to cmos->uc, because the volatile qualifier declares that those
accesses have side-effects, just like calls to putchar(). The
compiler cannot "just know" that the comparison will turn out
true; it must actually perform it. That's what volatile does.

Thanks for your comments. I don't think making the cmos variable volatile is
an option.

Why can't I make uc volatile?

volatile unsigned char uc = (unsigned char) ui32;
/* ... init uc ... */
cmos->uc = uc;
if ( cmos->uc != uc )
/* error writing to CMOS */

--
Martin

Nov 11 '07 #5
"Martin" <martin.o_brien @[no-spam]which.netwrites :
"Eric Sosman" wrote:
> The solution to your problem is to qualify the "CMOS" thing
as volatile, and use an ordinary comparison:

struct {
...
volatile unsigned char uc;
...
} *cmos = ...;

cmos->uc = uc;
if (cmos->uc == uc) ...

The compiler is not permitted to optimize away any of the accesses
to cmos->uc, because the volatile qualifier declares that those
accesses have side-effects, just like calls to putchar(). The
compiler cannot "just know" that the comparison will turn out
true; it must actually perform it. That's what volatile does.


Thanks for your comments. I don't think making the cmos variable volatile is
an option.

Why can't I make uc volatile?

volatile unsigned char uc = (unsigned char) ui32;
/* ... init uc ... */
cmos->uc = uc;
if ( cmos->uc != uc )
/* error writing to CMOS */
Eric Sosman's comment was about using memcmp -- specifically that
passing memcmp a pointer to a volatile object is not permitted. You
can use a != test but...

Making uc volatile won't work. The compiler may assume that cmos->uc
is set as per the assignment (it need not access the object again). I
can't see a way round this other than making the object that is
actually volatile, volatile. Forcing the compiler to re-access uc to
compare it against the value that it may have squirreled away as the
assumed contents of cmos->uc will not help you.

--
Ben.
Nov 11 '07 #6
Eric Sosman wrote:
>
.... snip ...
>
The compiler is not permitted to optimize away any of the accesses
to cmos->uc, because the volatile qualifier declares that those
accesses have side-effects, just like calls to putchar(). The
compiler cannot "just know" that the comparison will turn out
true; it must actually perform it. That's what volatile does.
Not side-effects. The variable may 'spontaneously' change between
reads. There is no reason to insist on a write between reads.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home .att.net>
Try the download section.

--
Posted via a free Usenet account from http://www.teranews.com

Nov 11 '07 #7
>"Eric Sosman" wrote:
>> The solution to your problem is to qualify the "CMOS" thing
as volatile, and use an ordinary comparison:

struct {
...
volatile unsigned char uc;
...
} *cmos = ...;
(Or, as I tend to prefer, make the structure type's elements
ordinary, non-"volatile"-qualified, but use a volatile qualifier
on the pointer itself:

struct whatever { ... unsigned char uc; ... };
volatile struct whatever *cmos = ...;

This allows one to copy the entire data structure into ordinary
RAM, then manipulate it there without defeating optimization.)
>>cmos->uc = uc;
if (cmos->uc == uc) ...

The compiler is not permitted to optimize away any of the accesses
to cmos->uc, because the volatile qualifier declares that those
accesses have side-effects ...
(Or rather, that they "may" have side effects, and the compiler
should assume the worst.)
>"Martin" <martin.o_brien @[no-spam]which.netwrites :
>Thanks for your comments. I don't think making the cmos variable
volatile is an option.
Why not? (Neither Eric Sosman's method nor mine generally requires
much in the way of code changes.)
>Why can't I make uc volatile?
You can; it just is silly, and may well not work. (In fact, it is
only likely to work if the code happens to work with no "volatile"
qualifiers anyway. That is, adding the volatile qualifier in the
wrong place is extremely unlikely to help.)

[I am going to make a name change below, so that "uc" unambiguously
refers to cmos->uc, and use "temp_v" for the local variable.]
> volatile unsigned char temp_v = (unsigned char) ui32;
cmos->uc = temp_v;
if ( cmos->uc != temp_v )
/* error writing to CMOS */
In article <87************ @bsb.me.uk>
Ben Bacarisse <be********@bsb .me.ukwrote:
>Making temp_v volatile won't work.
Well, it *might* work, all depending on details about the
compiler's internal workings.
>The compiler may assume that cmos->uc is set as per the assignment
(it need not access the object again).
Right -- for instance, it might generate code of the form:

ldw cmos_, a3 # so that register a3 = cmos
ldb -12(sp), d1 # so that register d1 = temp_v
stb d1, 48(a3) /* cmos->uc = temp_v; */

ldb -12(sp), d2 # so that register d2 = temp_v
cmp d1, d2 /* see if cmos->uc == temp_v */
...

Note that temp_v was loaded twice, in case it changed; but the
compiler could see that 48(a3), which refers to cmos->uc, was set
from register d1, and -- since it is "ordinary RAM" (even though
it is not!) it must not have changed, so there was no need to load
*that* again.
>I can't see a way round this other than making the object that is
actually volatile, volatile.
Indeed.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 11 '07 #8
My apologies - I had meant to submit a thank-you message to all your
responses before now.

So, thanks for the helpful advice.

I have two related questions. According to K&R2:

"Except that it should diagnose explicit attempts to change 'const'
objects, a compiler may ignore these qualifiers."

"These qualifiers" are 'const' and 'volatile'. It seems that this could be
an issue. I can carefully implement Eric Sosman's suggestion regarding using
a volatile pointer to the structure, but it seems an ANSI/ISO conformant
compiler is free to ignore it, and the compiler then could optimise away the
following memcmp(). Could someone clarify this for me?

Also, along those lines of making a pointer volatile, I would like some
clarification. Consider this code abstract:

volatile char arr[10];
char arr2[10]
/* ... code that initialises both arrays ... */
if ( memcmp(&arr[3], &arr2[3], 1) ... )
/* etc. */

Does the deferencing of the first argument, arr, mean that memcmp is being
handed a non-volatile type (which is, I believe, the principle behind Chris
Torek's suggestion)?

--
Martin

Nov 20 '07 #9
"Martin" <martin.o_brien @[no-spam]which.netwrites :
I have two related questions. According to K&R2:

"Except that it should diagnose explicit attempts to change 'const'
objects, a compiler may ignore these qualifiers."
This statement is given in the context of qualifiers on types,
not qualifiers on pointers. I think that this is intended to
mean that the compiler is not obligated to store const objects in
read-only memory, and that it is not obligated to put volatile
objects in a special section of memory either.
--
Ben Pfaff
http://benpfaff.org
Nov 20 '07 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

16
4561
by: rajkumar | last post by:
I have a struct like struct MyStruct { int a; int b; int c: bool d; bool e; }
4
6438
by: blueblueblue2005 | last post by:
hi, I am reading the description of memcmp and strcmp, it seems there is no big difference between these two functions. except that memcmp takes void pointer parameters. so why string.h has these two functions doing the same thing?
6
3938
by: Sidney Cadot | last post by:
Hi all, Just browsing through my newly-acquired C99 spec, I was reading on the memcmp() function (7.21.4.1). It has a rather peculiar wording: int memcmp(const void *s1, const void *s2, size_t n); 1. The memcmp function compares the first n characters of the object pointed to by s1 to the first n characters of the object pointed to by s2.
2
8115
by: Mads Jacobsen | last post by:
Hi, Does anyone know the c#-function of c++'s memcmp()? Regards, Mads
7
12769
by: Alex Stark | last post by:
Hi, I'm new to c# an missing functions like memcmp and memcpy from C. Is there something similar ? cu Alex
4
14381
by: Preets | last post by:
Hi, Can anybody please tell me the difference between memcmp() and strncmp() functions ?
4
14334
by: system55 | last post by:
which of the 2 commands are applicable in comparing an array of unsigned chars? if(strcmp(aAbsCylNumHigh, bAbsCylNumHigh)<=0 && strcmp(aAbsCylNumLow,bAbsCylNumLow)<=0 && strcmp(aSecNum,.bSecNum)<0 ) or if(memcmp(aAbsCylNumHigh, bAbsCylNumHigh,2)<=0 && memcmp(aAbsCylNumLow,bAbsCylNumLow,2)<=0 && memcmp(aSecNum,.bSecNum,2)<0 )
0
9690
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10501
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
10250
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10032
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9085
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5469
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5603
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3764
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2944
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.