Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there the possibility of having one version of machine code for all template arguments of a templated function?

Some people here told it's not possible and some people here told it might be possible to have one version of machine code for all different template arguments of a templated function, so I thought it would be profitable to open a thread regarding this specific matter, if there is not such possibility that's it, if there is, in what situations can we count on this? An example that was specifically considered in both mentioned threads is below:

template<size_t num>    
struct Elements{
 public:
  SomeType elements[num];
};

template<size_t num>
void print(const Elements<num> & elements,size_t size){
 //all instances do exactly same thing and with regard to Size that determines the size of object
}

and of course there's pass by value version also:

template<size_t num>
void print(const Elements<num> elements,size_t size){
 //all instances do exactly same thing and with regard to Size that determines the size of object
}
like image 935
Pooria Avatar asked Nov 20 '10 08:11

Pooria


1 Answers

A smart linker can recognize when two different function bodies are identical and combine them together into one symbol. This is called "COMDAT folding" in MSVC and "duplicate stripping" most other places. For example, the following two functions might compile identically on PPC, although they take different types, because the types are the same size and behave identically in the given situation.

template<typename T>
GetLowBit( T foo ) { return T & 1; }

GetLowBit<unsigned long>(ulong x); // compiles to "li r4, 1 ; and r3, r3, r4 ; blr "
GetLowBit<signed long>(long x); // also compiles to "li r4, 1 ; and r3, r3, r4 ; blr "

and so the linker can make both of their "names" point to the same place, as it were, so that a call to GetLowBit<unsigned long> goes to the same address as a call to GetLowBit<signed long>. So, in general, it's possible to fold together different template instantiations of functions that all operate on identical type sizes in identical ways. (In particular, containers that store pointers or enums tend to get folded together.)

This doesn't just happen for template functions. Some linkers can notice when any two functions have identical bodies, and merge them. In particular I see that MSVC tends to collapse every virtual function that does nothing but return into one uber-function, eg for

class A
{ 
  virtual void nothing() {};
}

class B
{
   virtual void empty() {};
}

I often see (in the disassembler while debugging something else) that the vtable entries for nothing and empty both point to the same function body, which in turn is just a ret.

Can you count on this? No. This is a feature that a smart linker might provide for functions when it notices them. Your linker might be stupid — there's a lot of lousy compilers out there. It might only happen if you supply certain command arguments. It may happen for some functions but not others for reasons known only to the linker. It may even differ from build to build depending on what else is in the program.

So in general, yes this can happen, and when it does, it can be a nice savings in executable size. But you can't count on it happening unless you are very familiar with your linker and all its features.

like image 104
Crashworks Avatar answered Sep 24 '22 21:09

Crashworks