Thread: volatile Qualifier on Function

  1. #1
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587

    volatile Qualifier on Function

    I had a discussion with someone recently about avoiding unwanted optimization-caused ommition of function calls. I suggested volatile, knowing of its meaning for (normal) variables. But I was told that, for example in:
    Code:
    volatile void func(void){}
    volatile refers to the void, or whatever the return type is, of the function, instead of telling the compiler the function is volatile, ie that calls to it can't be messed with (which is what I would assumed it would mean).

    As it turns out, the specification (6.7.3.2) says volatile (and all other qualifiers) is only valid for lvalues. I know the returned value of a function is an rval. But is the function symbol and lval? I can't assign to it. Even with -Wall, neither GCC or Clang give a warning for using it that way. 6.7.3.6 speaks about "unknown side effects", but it could be referring only to memory mapped registers and the like. Nowhere does it mention volative being used with function.

    I tested it, and volatile didn't stop clang from optimizing away a loop from 10 to 0, with each iteration calling an empty function. All it did was clear the variable (xorl %eax, %eax).

    So what I'd like to know, is: Is there any way to definitely tell a compiler a function call can't be omitted? (That is, without turning off optimizations. :P)

  2. #2
    Registered User
    Join Date
    Apr 2013
    Posts
    1,646
    Quote Originally Posted by User Name: View Post
    Is there any way to definitely tell a compiler a function call can't be omitted?
    Not that I'm aware of. You need to set the variables that the function is testing and/or modifying to volatile to prevent this.

  3. #3
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,980
    Why are you concerned about this? What is the real implementation/problem that you are trying to solve?

    gg

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,907
    I'd like to second Codeplug's question, what is your real aim? Do you have a real-world need for this, or is this some purely theoretical discussion? If the behavior is the same whether or not the function is optimized out, then why worry about it?

    > So what I'd like to know, is: Is there any way to definitely tell a compiler a function call can't be omitted? (That is, without turning off optimizations. :P)
    Not a standard way within the C language. It would depend on what compiler you are using (some old/basic ones may never optimize away a function call). You would have to look at all the documentation for the compiler(s) in question to find out what optimizations they support and if/how to disable them for certain cases. If any compiler supported this, I would expect it to be controlled via command line flags or maybe #pragma directives.

    As a side note:
    volatile often gets misused. I think you have a good idea of what it does, but to clarify, it is used to tell the compiler that the variable marked volatile may change in ways the compiler/implementation can't know or predict (e.g. external devices, sensors, memory-mapped IO). The fact that it disables/prohibits some optimizations is a side-effect of what it is, not it's purpose.

  5. #5
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Assuming you do not enable IPA, interprocedural analysis, or IPO, interprocedural optimizations, at link time: If you compile the target function in a separate compilation unit, the compiler cannot optimize away the function calls, even if the function was declared void and takes no parameters.

    I do a lot of math-related stuff, and end up having to benchmark all sorts of functions, with various optimization flags. In complex cases inlining and data reuse tends to affect timings quite a bit, but full programs tend to be difficult to fully test and benchmark. So, using these microbenchmarks in different conditions let me make pretty good estimates how each implementation works in different situations, without doing the actual, full tests.

    I usually have one dummy function that takes the exact same parameters, but does nothing in the function body, i.e.
    Code:
    void compute_dummy(double *const out, const double *const in, const size_t size);
    void compute_candidate1(double *const out, const double *const in, const size_t size);
    void compute_candidate2(double *const out, const double *const in, const size_t size);
    so that I can estimate the function call overhead. (On x86-64, it's typically 66-67 clock cycles as reported by rdtsc, with optimizations enabled. It does vary a bit if there are many or complex function arguments.)

    The test functions and the main benchmark are compiled separately, to separate object files, and only linked together -- being careful not to enable IPA or IPO -- to get the actual executable.

    When benchmarking, things like cache hotness (whether data is already in cache or not) affects the timing results a lot, but measuring the runtime of e.g. 1000 or 10000 calls, and looking at the timing distribution (via rdtsc on x86 and x86-64, or clock_gettime(CLOCK_THREAD_CPUTIME_ID, &timespec) in general case) is quite informative. I'm personally very careful to not just look at the minimum timings; the median or mode is much more reliable. You can always expect a few surprisingly long measurements, due to kernel/processor scheduling.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,600
    > So what I'd like to know, is: Is there any way to definitely tell a compiler a function call can't be omitted? (That is, without turning off optimizations. :P)
    A couple of suggestions.

    1. Put func() into another source file, so the current source file sees only extern void func(void);. This will prevent the compiler from seeing that func() does nothing, and hence the loop does nothing. A very smart linker might still do something (examples anywhere?)

    2. Make a volatile function pointer to func, and call the function via the function pointer. volatile void (*fn)(void) = func; .... fn();
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    AFAICT, there is use. The theoretical question stemed from a Clang "error" reported to the mailing list of LLVM. Apparently LLVM inlines functions that obviously have no side effects (like functions that do nothing). I was aware that putting it in another source file would force it, assuming LTO is turned off or LTO isn't smart enough to notice it does nothing.

    But that still leaves me wondering what the heck volatile really means when used with a function. Is it just that 2/3 of the major compilers (haven't tested icc) are allowing nonsensical function declarations?

  8. #8
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    The function returns a volatile object. It would have to be stored or used in a volatile context. I don't think using a function call to get a volatile variable is too different from modifying it any other way.

  9. #9
    Registered User
    Join Date
    Apr 2013
    Posts
    1,646
    Quote Originally Posted by Salem View Post
    Make a volatile function pointer to func, and call the function via the function pointer. volatile void (*fn)(void) = func; .... fn();
    Shouldn't that be void (* volatile fn)(void) = func; ? I'm not sure how you can declare a function to be volatile, only a pointer to a function, the same as any variable type (as opposed to a function).
    Last edited by rcgldr; 06-05-2013 at 02:43 AM.

  10. #10
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by rcgldr View Post
    Shouldn't that be void (* volatile fn)(void) = func; ? I'm not sure how you can declare a function to be volatile, only a pointer to a function, the same as any variable type (as opposed to a function).
    Not necessarily:

    cdecl: C gibberish ↔ English

  11. #11
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Strictly speaking, a function cannot return volatile void. However, some older compilers used that as a trick to tell the compiler that the function does not return. For example, a function that always calls exit() might be declared as "volatile void". Using that for a function in a loop might - with those compilers - give unpleasant surprises.

    gcc supports an option -fno-inline. Also, compiling without optimisation (e.g. for debugging) turns off inlining - with most compilers.

    Most compilers will also not inline a function if the definition is not visible (i.e. the caller and callee are in separate source files). That doesn't prevent inlining from occurring at link time (or even at run time!), but such optimisations after compiling are uncommon - but not non-existant.

    If you want absolute guarantees that inlining a function will not occur, you need to read documentation for your build process, as well as the host system.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  12. #12
    Registered User
    Join Date
    Apr 2013
    Posts
    1,646
    Quote Originally Posted by rcgldr View Post
    Shouldn't that be void (* volatile fn)(void) = func; ?
    Quote Originally Posted by whiteflags View Post
    That C gibberish example is for a pointer to function that returns a volatile void, as opposed to my example of a volatile pointer to function which returns a void.

  13. #13
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Which would be the point: Apparently there is no problem with how Salem originally wrote the pointer declaration.

  14. #14
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,980
    I believe Salem's intention was to call the function using a function pointer which is volatile - with the idea that the compiler must call it because it's a volatile access. If that's the case then it would be "void (*volatile fn)(void)".

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Const qualifier
    By karthik537 in forum C Programming
    Replies: 3
    Last Post: 02-17-2011, 12:24 AM
  2. ROM Qualifier (Part 2)
    By Syndacate in forum C Programming
    Replies: 7
    Last Post: 02-06-2011, 04:21 PM
  3. ROM Qualifier vs Const?
    By Syndacate in forum C Programming
    Replies: 20
    Last Post: 01-20-2011, 01:42 PM
  4. specifier-qualifier-list
    By Raman in forum C Programming
    Replies: 2
    Last Post: 11-04-2008, 08:12 AM
  5. const qualifier used on a function argument
    By hzmonte in forum C Programming
    Replies: 27
    Last Post: 04-18-2006, 11:08 PM