Sign in to follow this  
Norman Barrows

comdat folding

Recommended Posts

Just for fun, i kicked the warning level up from 4 to all on the caveman project. it did catch a few explicit conversions i missed.

 

after suppressing the "#ifdef symbol is undefined" and "padding data structure" warnings in the windows and directx headers, and the "inlining" and "not inlining" warnings from the linker, i set linker output to verbose. then i tried all the different verbose setttings. when i tried - show comdat folding, this is what i got:

 

1>------ Rebuild All started: Project: caveman, Configuration: Release Win32 ------
1>cl : Command line warning D9025: overriding '/sdl-' with '/GS-'
1>  modeler.cpp
1>  Z3D.cpp
1>  Zaudio.cpp
1>  caveman.cpp
1>  Generating code
1>  Finished generating code
1>  
1>      Selected symbol:
1>          "public: __thiscall Zdrawinfo::Zdrawinfo(void)" (??0Zdrawinfo@@QAE@XZ) from modeler.obj
1>      Replaced symbol(s):
1>          "public: __thiscall drawrec::drawrec(void)" (??0drawrec@@QAE@XZ) from Z3D.obj
1>          "public: __thiscall ttyperec::ttyperec(void)" (??0ttyperec@@QAE@XZ) from Z3D.obj
1>          "public: __thiscall objtyperec::objtyperec(void)" (??0objtyperec@@QAE@XZ) from caveman.obj
1>          "public: __thiscall plantrec::plantrec(void)" (??0plantrec@@QAE@XZ) from caveman.obj
1>          "public: __thiscall chunk2::chunk2(void)" (??0chunk2@@QAE@XZ) from caveman.obj
1>  
1>      Selected symbol:
1>          "void __fastcall remove_stuff_near_cave(int,int,int)" (?remove_stuff_near_cave@@YIXHHH@Z) from caveman.obj
1>      Replaced symbol(s):
1>          "void __fastcall remove_stuff_near_rockshelter(int,int,int)" (?remove_stuff_near_rockshelter@@YIXHHH@Z) from caveman.obj
1>  
1>      Selected symbol:
1>          "void __fastcall runstate_cornered(int)" (?runstate_cornered@@YIXH@Z) from caveman.obj
1>      Replaced symbol(s):
1>          "void __fastcall run_defend_location_attack(int)" (?run_defend_location_attack@@YIXH@Z) from caveman.obj
1>  
1>      Selected symbol:
1>          "void __fastcall generate_CB2(int,int,int,int)" (?generate_CB2@@YIXHHHH@Z) from caveman.obj
1>      Replaced symbol(s):
1>          "void __fastcall generate_non_tropical_savanna_tree(int,int,int,int)" (?generate_non_tropical_savanna_tree@@YIXHHHH@Z) from caveman.obj
1>  
1>      ICF total savings: 774 bytes
1>  
1>  caveman.vcxproj -> C:\Rockland\caveman\Release\caveman.exe
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
 

 

 

 

 

so this means that, for example, remove_stuff_near_rockshelter and remove_stuff_near_cave are identical at the object code and/or machine code level?

 

i understand the concept of how this could be, just want to confirm i'm reading this output correctly.

 

 

and:

1>      Selected symbol:
1>          "public: __thiscall Zdrawinfo::Zdrawinfo(void)" (??0Zdrawinfo@@QAE@XZ) from modeler.obj
1>      Replaced symbol(s):
1>          "public: __thiscall drawrec::drawrec(void)" (??0drawrec@@QAE@XZ) from Z3D.obj
 

means that internally the compiler is creating code that returns a pointer to a struct, and is using the same code for all? (all the symbols listed in this case are POD structs).

 

is it folding them because the structs just happen to be the same size, perhaps?

 

 

 

 

 

 

 

 

 

Share this post


Link to post
Share on other sites

The structs don't necessarily need to be the same size. __thiscall functions take the object argument by pointer. However, both functions are doing the same things to the same offsets into the pointer.

Share this post


Link to post
Share on other sites

However, both functions are doing the same things to the same offsets into the pointer.


In other words, the actual machine code for the two functions are identical.

You can see this when debugging sometimes - especially with small getter functions - where you'll set a breakpoint on `Foo::getX()` but then the debugger breaks in some seemingly unrelated `Bar::getY()`. If you examine the assembly it'll turn out that they're running the exact same set of instructions. The CPU don't care none 'bout y'all OOPy semantics. tongue.png

It's been years since I've mucked with it but I'd imagine that with GCC's "partial inlining" it could be even more confusing. smile.png

Share this post


Link to post
Share on other sites


and:
1>      Selected symbol:
1>          "public: __thiscall Zdrawinfo::Zdrawinfo(void)" (??0Zdrawinfo@@QAE@XZ) from modeler.obj
1>      Replaced symbol(s):
1>          "public: __thiscall drawrec::drawrec(void)" (??0drawrec@@QAE@XZ) from Z3D.obj
 
means that internally the compiler is creating code that returns a pointer to a struct, and is using the same code for all? (all the symbols listed in this case are POD structs).

 

Why do your POD structs have constructors? A real POD struct would not need any constructor - all of its members would be left uninitialized.

Share this post


Link to post
Share on other sites


Why do your POD structs have constructors? A real POD struct would not need any constructor - all of its members would be left uninitialized.

 

i thought these were weird too.

 

here's zdrawinfo:

 

struct Zdrawinfo
{
int type,         // 0=mesh, 1=model, 2=2d billboard, 3=3d billboard
meshID,       // for models: modelID 
texID,        // for models: aniID 
alphatest,cull,clamp,materialID,rad,cliprng,data[5];
float sx,sy,sz,x,y,z,rx,ry,rz,range;       // range is rng to camera. not currently used.
D3DXMATRIX mWorld;
};
 
its used as a parameters list for drawing calls.
 
and drawrec:
 
// drawlist record
struct drawrec
{
int meshID,texID,alphatest,cull,clamp,materialID;
D3DXMATRIX mWorld;
float range;
};
 
this is an actual entry in the render queue.
 
to draw, you fill in the info in a zdrawinfo struct, then call  a drawing method:
Zdraw - adds mesh to render queue, creates world mat from eulers in the zdrawinfo struct
Zdraw2 - adds mesh to render queue, uses world mat from the zdrawinfo struct
Zdraw_immediate  - draw_indexed_primitive mesh, creates world mat from eulers in the zdrawinfo struct
Zdraw_immediate2 - draw_indexed_primitive mesh,  uses world mat from the zdrawinfo struct
Zd - adds item to render queue, based on type specified in the zdrawinfo struct (mesh, model, 2d billboard, 3d billboard)
 
when an item is added to the render queue, the info in the zdrawinfo is used to fill in the info in the drawrec. the render queue is an unordered static array of drawrecs, and uses a 2d bucket sorted index for drawing. as drawing calls are made, they are added to the queue and to the index.
 
and the two structs are not identical....   most strange.
 
"Indeed, most curious", as Spock would say...

Share this post


Link to post
Share on other sites


and the two structs are not identical....   most strange.
 
"Indeed, most curious", as Spock would say...

 

They both have D3DXMATRIX, which is not a POD type because it has a constructor. Its constructor doesn't actually happen to do anything, though. So, your two classes are not technically POD types either, and they get default compiled constructors.

 

I took a stab at building a project on debug, with comdat folding, with this set of structs (the names lie, none of them are close to "Big"):

 

struct BigTestStruct1
{
    BigTestStruct1();
 
    int a, b, c, d, e;
};
struct BigTestStruct2
{
    BigTestStruct2();
 
    int a, b, c, d, e, f, g;
};
struct BigTestStruct3
{
    int a, b, c, d, e;
};
struct BigTestStruct4
{
    int a, b, c, d, e, f, g;
};

 

I put the constructors in their own .cpp files. Anyway, I got this output:

 

1>      Selected symbol:
1>          "public: __thiscall std::allocator<char>::allocator<char>(void)" (??0?$allocator@D@std@@QAE@XZ) from ConsoleRandomTest.obj
1>      Replaced symbol(s):
1>          "public: __thiscall std::allocator<struct std::_Container_proxy>::allocator<struct std::_Container_proxy>(void)" (??0?$allocator@U_Container_proxy@std@@@std@@QAE@XZ) from ConsoleRandomTest.obj
1>          "public: __thiscall BigTestStruct1::BigTestStruct1(void)" (??0BigTestStruct1@@QAE@XZ) from BTS1.obj
1>          "public: __thiscall BigTestStruct2::BigTestStruct2(void)" (??0BigTestStruct2@@QAE@XZ) from BTS2.obj

 

3 and 4 weren't in the comdat folding log or the map file.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this