Now we have an inline bug. Pelles C 5 inliner has been beefed up to inline more code than v4.5 can. Here is a divider that will use a shift instruction if code elsewhere has determined that the denominator is a power of two. wShift is the >> shift value or 0 if a divide must be used.
// compile with Maximize Speed or Maximize Speed More
#if 0
#define seekdivshift2(x,wShift,wSize) ((wShift)?((x)>>(wShift)):((x)/(wSize)))
#else
inline DWORD seekdivshift2(DWORD x,unsigned uiShift,WORD wSize) {
return uiShift?(x>>uiShift):(x/wSize);
}
#endif
static void sdtest(unsigned uiShift,WORD wSize) {
volatile DWORD x=atoi("12345");
DWORD st=seekdivshift2(x,uiShift,wSize);
printf("%u%s%u = %u\n",x,uiShift?">>":"/",uiShift?uiShift:wSize,st);
}
sdtest(0,3); // this will divide by 3
sdtest(3,0); // this will shift by 3
Volatile was added to get the bug to show. The shift divider always works. The non shift divider is broken. Change seekdivshift2() to non inline, remove the volatile, change to a macro, or change the compile optimization and the bug might go into remission depending on the surrounding code.
mov ebx,dword ptr[uiShift]
//eax=atoi("12345");
mov dword ptr [x],eax // x=ebp-4
test ebx,ebx // uiShift from above
je divide
mov eax,dword ptr [x] // this numerator load is right
// remainder of shift code that works
divide:
mov eax,dword ptr [ebp-8] // this compiler generated location was never set. It is set in the macro version but only for the shift code path. It contains an unknown value for the divide code path.
// divide with an unknown numerator
The volatile was required to get this simple example to show the bug. When this is inlined into normal code where there aren't lots of unused registers available the code looks like this:
mov eax,dword ptr [shift value]
mov [compiler generated location],eax // sloppy register handling created this location
test eax,eax
je divide
mov edx,[numerator] // move this up 1 or more instructions and we have a winner!
mov eax,edx // prepare the numerator
mov ecx,[compiler generated location]
// shift code
divide:
mov eax,edx // prepare the numerator with an unknown value from edx. edx has the value we want in the shift code path.
// divide with random numerator
Looks to me that the load in the shift code is out of place.