no-op function pointer

B

bluejack

Ahoy... before I go off scouring particular platforms for specialized
answers, I thought I would see if there is a portable C answer to this
question:

I want a function pointer that, when called, can be a genuine no-op.

Consider:

typedef int(*polymorphic_func)(int param);

struct various_funcs {
polymorphic_func func_a;
polymorphic_func func_b;
};

int really_does_something(int param) { return ++param; }
int really_a_noop(int param) { (void)param; return 0; }

struct various_funcs does_stuff = { really_does_something,
really_does_something };
struct various_funcs noop_funcs = { reall_a_noop, really_a_noop };

int main (int argc, char** argv) {
int x = 10;
int y = does_stuff.func_a(x);
int z = noop_funcs.func_b(x);
return z;
}

----------------------------------

A lot of typing for the very obvious; but does the reference to
noop_funcs.func_b(x) actually make a function call? Or would the
compiler simply assign 0 to z? Is there any C way to ensure a noop? Or
is it going to be all about which compiler / which platform?

Or does it seem unlikely that a compiler could optimize that down to a
noop?

Naturally, I'm really thinking about scenarios in which a variable
contains a function pointer that can only be known as a noop at
runtime, which actually makes this MORE of a language problem in my
mind than a compiler problem. If the NULL function pointer were a noop,
this would be very convenient. But of course, the NULL function pointer
is not a noop, it's a null pointer, and dereferencing it is a segfault.
So is there language support for a function pointer that does nothing?

Ideas? Redirection?
 
M

mailursubbu

I assume your function pointer will be null when it is noop. Before
you call the function verify whether thats NULL or not. If it is NULL
then make noop( ; ) or else call the function.
 
B

bluejack

Checking for NULL and calling if not NULL is, erm, less of a noop than
I was hoping for, but conversations with some guys over at the gcc
newsgroup suggest that's about the best I can hope for.
 
J

Jack Klein

Checking for NULL and calling if not NULL is, erm, less of a noop than
I was hoping for, but conversations with some guys over at the gcc
newsgroup suggest that's about the best I can hope for.

Put your no-op function in a different source file and compile it
separately.

In the function where you assign its address to a pointer, only have
an external definition.

That should make sure the function is called.
 
W

Walter Roberson

in comp.lang.c:
Put your no-op function in a different source file and compile it
separately.
That should make sure the function is called.

The OP was hoping for the opposite: some way of assigning a
value to a function pointer such that when that value was present,
no call would be made. This is, I would gather, a micro-optimization
to avoid the overhead of subroutine linkage for a routine that is
just going to return.

I would suggest to the OP that in a compiler capable of
automatic inlining, that a routine
const void no_op(const TYPE param) { }
would be a good candidate for inlining. The OP had something like
void no_op(TYPE param) { (void)param; return 0; }
but that implies some work on param: it's value has to be accessed
before it is (void) so if param is a trap representation for its
type, then (void) param is potentially going to trap, whereas
simply not using param would not. Also, returning 0 to a void
function is a type mismatch.

Automatic inlining is, to be sure, not promised by C89.
(Does C90 have inline functions?)


A question for the OP: since you show a parameter being
passed in, if the calculation of that parameter would involve
"work" or potential side effects, then what do you want done?
A "real" no_op in such a case would not even evaluate the
parameter(s), at least in the case of what -I- would think of
as "no op". These two are not equivilent:

void no_op(void *param) { }
/* ... */ fptr = no_op;
/* ... */ (*fptr)(param);
vs
#define CALL_MAYBE_NOOP(fptr,param) (fptr? (*fptr)(param) : (void)0)
/* ... */ fptr = NULL;
/* ... */ CALL_MAYBE_NOOP(fptr,param);

A closer match would be:

#define CALL_MAYBE_NOOP(fptr,param) (fptr? (*fptr)(param) : (void)(param))
/* ... */ fptr = NULL;
/* ... */ CALL_MAYBE_NOOP(fptr,param);

(My first iterations used 'if' and {}, but that wasn't quite equivilent
against the possibility that (*fptr)(param) was in a location that
expected an expression rather than a statement.)
 
W

Walter Roberson

void function_that_does_nothing( void )
{
asm( " nop" );
return;
}

Well, that would certainly do nothing on the compilers I use --
it would fail to link, as none of the libraries define
an asm() function.
 
J

Jordan Abel

but that implies some work on param: it's value has to be accessed
before it is (void) so if param is a trap representation for its
type, then (void) param is potentially going to trap, whereas
simply not using param would not.

Except if it can inline it can optimize the statement out too. if not,
passing the parameter traps anyway
 
K

Keith Thompson

Richard Crowley said:
void function_that_does_nothing( void )
{
asm( " nop" );
return;
}

The asm() statement, apart from being non-portable, is superfluous.
So is the return, for matter.
 
B

bluejack

The OP was hoping for the opposite: some way of assigning a
value to a function pointer such that when that value was present,
no call would be made. This is, I would gather, a micro-optimization
to avoid the overhead of subroutine linkage for a routine that is
just going to return.

Exactly so! I'm glad you understood! The other points on this thread
were interesting, but not to my case.
A question for the OP: since you show a parameter being
passed in, if the calculation of that parameter would involve
"work" or potential side effects, then what do you want done?
A "real" no_op in such a case would not even evaluate the
parameter(s), at least in the case of what -I- would think of
as "no op".

The goal is a polymorphic call such that, in instances of objects that
require the call,
the call will be made and will do real work. However, for instances
that do not require the call, the call will not be made. To achieve
that polymorphism, however, the function must have the same parameters
and return signature.

Even this:
#define CALL_MAYBE_NOOP(fptr,param) (fptr? (*fptr)(param) : (void)(param))
/* ... */ fptr = NULL;
/* ... */ CALL_MAYBE_NOOP(fptr,param);

.... carries the overhead of "fptr?"

I did some benchmarking to confirm that yes, testing and not calling is
far more lightweight than calling something that does nothing. It's
still not as lightweight as a genuine no-op, and has the drawback of
making the non-noop case more expensive, although in most applications
that still amortizes to better performance overall than calling the
noop. Since the noop is the common scenario, and there is real work
associated with the non-noop call, the relative cost of the test is
low.

As for inlining, as I understand inlining, it is not possible to inline
a run-time-determined function pointer.

Against accusations of premature optimization, I will say this: I am
designing a multi-purpose, low-level library. The capability of the
language, in this matter, determines library design for me. If there
*were* a way to make acting on a function pointer a genuine noop, I
would use the facility within the library calls, and it would be a good
thing. Since C does not appear to offer this facility in any portable
way (discussions over at the gcc newsgroup devolved quickly into
assembly language and on-the-fly code-rewriting. I am not going to
prematurely optimize to that degree!) ... instead I will design the
library around this limitation in the language. There are other ways to
achieve my objectives, although not quite as elegant.

Thanks for the discussion! I love this stuff.

-bluejack
 
K

Kenneth Brody

bluejack wrote:
[...]
Even this:


... carries the overhead of "fptr?"

I did some benchmarking to confirm that yes, testing and not calling is
far more lightweight than calling something that does nothing. It's
still not as lightweight as a genuine no-op, and has the drawback of
making the non-noop case more expensive, although in most applications
that still amortizes to better performance overall than calling the
noop. Since the noop is the common scenario, and there is real work
associated with the non-noop call, the relative cost of the test is
low.

As for inlining, as I understand inlining, it is not possible to inline
a run-time-determined function pointer.

Against accusations of premature optimization, I will say this: I am
designing a multi-purpose, low-level library. The capability of the
language, in this matter, determines library design for me. If there
*were* a way to make acting on a function pointer a genuine noop, I
would use the facility within the library calls, and it would be a good
thing. Since C does not appear to offer this facility in any portable
way (discussions over at the gcc newsgroup devolved quickly into
assembly language and on-the-fly code-rewriting. I am not going to
prematurely optimize to that degree!) ... instead I will design the
library around this limitation in the language. There are other ways to
achieve my objectives, although not quite as elegant.
[...]

It's not a limitation of C, but a limitation of the computers themselves.
Unless the CPU itself were to have some "magic address" which, when used
as the target of a CALL (or equivalent to that CPU), would be treated by
the CPU as a no-op instead, it is not possible to design a true no-op in
an indirect call.

Even if the C language were to have some "treat this function pointer
dereference as a no-op" feature, how would it implement it? It would be
implemented, most likely, by comparing the pointer to a "magic value",
and then the call ignored if it matches.

How is this different than the above CALL_MAYBE_NOOP() macro, aside from
the macro being explicit? The generated machine code would most likely
be identical.

And, of course, the function must have a void return type.

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
K

Keith Thompson

bluejack said:
Against accusations of premature optimization, I will say this: I am
designing a multi-purpose, low-level library. The capability of the
language, in this matter, determines library design for me. If there
*were* a way to make acting on a function pointer a genuine noop, I
would use the facility within the library calls, and it would be a good
thing. Since C does not appear to offer this facility in any portable
way (discussions over at the gcc newsgroup devolved quickly into
assembly language and on-the-fly code-rewriting. I am not going to
prematurely optimize to that degree!) ... instead I will design the
library around this limitation in the language. There are other ways to
achieve my objectives, although not quite as elegant.

I think what you've been looking for is some kind of shortcut for the
if statement in:

typedef void (void_func)(void);

void call(void_func *p)
{
if (p) p();
}

As you've discovered, there's no such thing (at least in standard C).
And if you think about it, there's not much reason that there should
be. It's just a particular form of an if statement (or a conditional
branch). If the CPU provided an instruction that did the same thing
in hardware or microcode, it would probably have to do the same thing
that the explicit if statement does. I doubt that this kind of thing
is common enough to justify dedicating hardware to it, any more than

int *ptr;
...
if (ptr) ptr ++;
 
B

bluejack

It's not a limitation of C, but a limitation of the computers themselves.
Unless the CPU itself were to have some "magic address" which, when used
as the target of a CALL (or equivalent to that CPU), would be treated by
the CPU as a no-op instead, it is not possible to design a true no-op in
an indirect call.

Well, yes and no.

If C required the functionality, it could be translated in different
ways. Eg, instead
of simply putting in a "call addy" assembly for every function pointer,
the function
pointer could "translate" to a snippet of assembly code. For a genuine
function
call that code might be "call addy", whilst for a noop (with a return
value) it might
be a "mov 0x00 (addy)" code. What the C programmer calls a function
pointer,
would actually be a couple of assembly commands, executed at runtime
rather
than inserted at compile time.

Of course, I don't actually program any assembly language (as is
probably obvious),
so perhaps this isn't as possible as it seems.

Anyhoo.... it's clear that my "elegant little solution" isn't going to
happen, and plenty of thousands of programmers have gotten by without
it in the past, so I'll just take a different design approach.

-b
 
B

bluejack

Keith Thompson wrote
Please provide attributions for quoted material. The paragraph
starting with "It's not a limitation" was written by Kenneth Brody.

yeah, sorry 'bout that. It's this lousy google groups interface,
totally hopeless as a usenet client. Haven't reinstalled a proper
usenet client yet...

-b
 
S

slebetman

bluejack said:
If C required the functionality, it could be translated in different
ways. Eg, instead of simply putting in a "call addy" assembly for every
function pointer, the function pointer could "translate" to a snippet of
assembly code. For a genuine function call that code might be "call addy",
whilst for a noop (with a return value) it might be a "mov 0x00 (addy)" code.

But in YOUR case, this won't work because the information is run-time
(you stated in earlier posts that macros won't work for you). So the
compiler MUST ALWAYS make a call and do a return. So, for the noop
function you wanted you'll be facint call and return overhead. Like you
said earlier, checking for NULL is much more lightweight and much
faster (compiles to a single instruction on a lot of platforms).
Anyhoo.... it's clear that my "elegant little solution" isn't going to
happen, and plenty of thousands of programmers have gotten by without
it in the past, so I'll just take a different design approach.

Due to the fundamentals of CPU design. Though I have seen CPUs where
returning from a subroutine is free by using a return bit in the
instruction instead of a dedicated return instruction, so all
instructions can return (think of the assembly that looks something
like: noop,return). But even so, checking for NULL is still faster
since it avoids the call overhead (calling itself is usually a single
instruction but parameter passing, especially if you have more than one
parameter, can take up lots of instructions).
 
T

tedu

bluejack said:
If C required the functionality, it could be translated in different
ways. Eg, instead
of simply putting in a "call addy" assembly for every function pointer,
the function
pointer could "translate" to a snippet of assembly code. For a genuine
function
call that code might be "call addy", whilst for a noop (with a return
value) it might
be a "mov 0x00 (addy)" code. What the C programmer calls a function
pointer,
would actually be a couple of assembly commands, executed at runtime
rather
than inserted at compile time.

if the compiler is capable of deciding to insert "call" or "mov" at
compile time, that means you should be capable as well. which means
you can just delete the noop call entirely.
 
W

Walter Roberson

But in YOUR case, this won't work because the information is run-time
(you stated in earlier posts that macros won't work for you). So the
compiler MUST ALWAYS make a call and do a return. So, for the noop
function you wanted you'll be facint call and return overhead. Like you
said earlier, checking for NULL is much more lightweight and much
faster (compiles to a single instruction on a lot of platforms).

I think you missed bluejack's idea.

The usual implementation semantics for a function pointer is:

- set up any register preservation needed
- set up the parameters
- unconditionally perform a subroutine call to the address indicated
by the function pointer -- historically if not to the actual instruction
location whose value is stored in the pointer, then to an instruction
location determined by taking the pointer value to be an offset from
some register or some segment pointer
- save any expected return parameters
- undo any necessary register preservation

with this all handled inline.

A potential replacement semantics for a function pointer would be something
like this:

- construct a pointer to a block of code that would set up the
parameters, and another pointer to a block of code that would
retreive return parameters to the proper locatons, and put the address
of the structure containing both into a register reserved for this
purpose... or push the structure contents onto the stack
- unconditionally perform a lightweight call to the address indicated
by the function pointer, either as a direct value or as an offset
as per the above. A lightweight call would just record the return
address and then do the branch
- deallocate the above structure / pop the values from the stack

The process of building a function pointer would then involve writing
into memory one of two things:

- if the pointer is NULL, just write a lightweight jump back to the
return location, without having called the setup or teardown routine
- otherwise, write a sequence to retrieve the address of the
setup routine and to perform a lightweight call to it, followed by
a sequence to perform the subroutine call the the actual code
location, followed by a sequence to retrieve the address of the
teardown routine and to perform a lightweight call to it.

The compiler would, in this semantics, pre-compile the setup and
teardown routines according the current context of what registers were
used and where the arguments were to be retrieved from, so the
'construct a pointer' bit would simply be a matter of saving two
values known in advance to the compiler. The address saved in the
function pointer variable would still be dynamic, but only a light
dynamic call would be used, rather than a full "preserve all the registers,
save all the masks, change contexts. The code that was branched
-to- would do nothing, gracefully, for the no-op (NULL) case,
but for the non-NULL case, at the time the pointer was created the
compiler stored the code to deal with the parameters and perform the
"real" subroutine call.


There are three major differences between the above and the current
semantics.

The first is that I have created a new definition, that deliberately
taking the function pointer of NULL results in a something that is a no-op
rather than a crash-the-program-op.

The second is that I have -defined- this NULL case as not
even evaluating the arguments at all -- but that part of it is easily
redefined if you want to evaluate the arguments anyhow (in case of
side-effects.)

The third difference is that with the current traditional semantics,
*all* code is always in fixed memory and precompiled, so all aspects
of code itself can be stored in read-only (execute-only) memory, whereas
in the revised semantics, I have framed it in terms of the
function-pointer operation writing RAM that contains code that will
later be executed, thus needing a section that is writable and
executable, and (in a naive implementation) quite extendable
since one could potentially loop taking pointers to functions.

As C semantics do not allow for user creation of routines on the
fly, then an optimization of what I have described would be possible:
it would be possible for the program to take note of all routines
whose pointer is ever taken, and pre-write the code for calling
those, and write just those handlers to read-only (execute only)
memory, at locations that it knows about.

Indeed, this could be taken further as follows:

Instead of having the current semantics of inline parameter
setup and so on, followed by unconditional branch, pre-compile
the code that would be needed to do the parameter handling,
and do a lightweight branch to the address designated by the
stored function pointer. At compile time, the compiler is
able to detect a function pointer to NULL, and can return as
the pointer a block of code that does nothing gracefully and returns
with a light return; for all other calls, the address would be to the
be function code block, which would call the setup block, call
the real code just below, then call the teardown block, then do a
light return. All of this involves only precompiled entities and so
can go into read-only (execute-only) memory.

This should, I believe, work no matter what -legal- function pointer
manipulations were undertaken. It isn't possible to construct a
new function pointer such as by doing pointer arithmetic on an
existing one, and it isn't possible to construct a new NULL pointer
by subtracting a function pointer from itself. Therefore, no matter
how many levels one goes through, every operation on a
function pointer amounts to either passing a compile-(well, link-)
time constant around, storing such a constant, or taking the
address of a memory location that contains such a constant and working
with that. One should thus be able to implement this with just the minor
change to C semantics of permitting a no-op function pointer constructor,
which one might or might not choose to be accompanied by the semantics
of not evaluating the parameters.


Now, I don't imagine for a moment that anyone would bother to go
through the trouble to actually implement this, since clearly it
is only an optimization and the C standards stay well away from
matters of efficency. All I'm saying is that bluejack's proposal
is not "impossible" and could be made to work. But it'd only
-matter- for architectures and APIs on which there is a lightweight
call/return mechanism that is much less costly than the API's
full-call requirements.

Note: I cannot at the moment think of any implementation of the
idea that does not involve at least -one- call/return: to go
below that, one would need self-modifying code... or code that
just tests for NULL and branches around the call, which is of course
what the CALL_MAYBE_NOOP macro does...

(Yes, we've looped back to where we started, but now we know that
the idea wasn't impossible, but that the CALL_MAYBE_NOOP implementation
is probably much more efficient anyhow...)
 
C

Chris Torek

[enormous snippage]
Now, I don't imagine for a moment that anyone would bother to go
through the trouble to actually implement this, since clearly it
is only an optimization and the C standards stay well away from
matters of efficency. All I'm saying is that bluejack's proposal
is not "impossible" and could be made to work. But it'd only
-matter- for architectures and APIs on which there is a lightweight
call/return mechanism that is much less costly than the API's
full-call requirements.

Quite so. In fact, on many modern systems, calling a no-op
subroutine is just as fast as any other branch. Hence:

if (fp) (*fp)(arg);

might compile to:

brz fp_reg, 1f # if "fp" is zero, skip the call
nop # nothing to do in delay slot

jal fp_reg # otherwise execute subroutine call
mov arg, a0 # (and put argument in argument-zero register)
1:

which would never be any faster, and maybe *slower* (by about one
CPU cycle, whenever the register is nonzero), than:

jal fp_reg # jump and link (i.e., call subroutine)
mov arg, a0 # with argument in "a0" register

with the no-op subroutine being compiled to:

jmp ret_reg # return from subroutine
nop # nothing to do in delay slot

(the above is not intended to be either SPARC or MIPS assembly,
but rather something more or less the same as both).
Note: I cannot at the moment think of any implementation of the
idea that does not involve at least -one- call/return: to go
below that, one would need self-modifying code... or code that
just tests for NULL and branches around the call, which is of course
what the CALL_MAYBE_NOOP macro does...

Some architectures can achieve this without self-modifying code
using an "execute" instruction that executes an instruction stored
in a register. In this case, we would do something like:

ld t0, instruction # which is either "call t1" or "nop"
ld t1, target # which is either the function to call, or irrelevant
exc t0 # execute instruction in register t0
(Yes, we've looped back to where we started, but now we know that
the idea wasn't impossible, but that the CALL_MAYBE_NOOP implementation
is probably much more efficient anyhow...)

Or at least, completely portable C, and likely not significantly
slower. (The one-cycle slowdown above means that on a 1 GHz CPU,
it costs about one extra nanosecond when calling "real work"
functions. I say "about" because the 8 bytes for the brz+nop, or
4 bytes if we find an instruction for the delay slot, takes cache
space and could bump something out. On the other hand, perhaps
the instruction we move into the delay slot would have been in its
own CPU cycle anyway, and with a two-instructions-per-cycle CPU,
the branch-on-register-zero instruction could turn out to be entirely
"free" after all.)
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top