Obviously, -G6 means favor the Pentium Pro.
Notice that most of the switches have no effect on how C2 or LINK are started (although the EXE size changes so that we know the option is making itself known!). Since most switches have no effect, we must assume they are being acted on within VB6.EXE itself (as it seems to contain the compiler's first pass). Or perhaps the mystery files shown earlier (VB603389GL, VB603389SY, VB603389EX, VB603389IN, and VB603389DB) have some way of influencing the code generator, thus sidestepping our efforts to understand how the process is being controlled.
Table 7-4 The Compiler Effect
Optimization Option | C2.EXE Effect | LINK.EXE Effect |
Optimize For Small Code | None | None |
Optimize For Fast Code | None | None |
Favor Pentium Pro | /G6 (from G5) | None |
Create Symbolic Debug Info | /Zi | /DEBUG |
/DEBUGTYPE:CV | ||
Assume No Aliasing | None | None |
Remove Array Bounds Checks | None | None |
Remove Integer Overflow Checks | None | None |
Remove Floating Point Error Checks | None | None |
Allow Unrounded Floating Point Operations | None | None |
Remove Safe Pentium(tm)FDIV Checks | /QIfdiv Removed | None |
Advanced Optimizations
Microsoft generally encourages you to play around with what they call the safe compiler options. Naturally, these are options that aren't situated beneath the Advanced Optimizations button. For those options Microsoft usually provides a disclaimer: "These might crash your program." Let's see what these Advanced Optimizations are about and why this warning is given. (See Table 7-5)
Table 7-5 Advanced Optimizations Options
Option | Description |
Allow Unrounded Floating Point Operations | Allows the compiler to compare floating-point expressions without first rounding to the correct precision. Floating-point calculations are normally rounded off to the correct degree of precision (Single or Double) before comparisons are made. Selecting this option allows the compiler to do floating-point comparisons before rounding, when it can do so more efficiently. This improves the speed of some floating-point operations; however, this may result in calculations being maintained to a higher precision than expected, and two floating-point values not comparing equal when they might be expected to. |
Assume No Aliasing | Tells the compiler that your program does not use aliasing (that your program does not refer to the same memory location by more than one name, which occurs when using ByRef arguments that refer to the same variable in two ways). Checking this option allows the compiler to apply optimization such as storing variables in registers and performing loop optimizations. |
Remove Array Bounds Checks | Disables Visual Basic array bounds checking. By default, Visual Basic makes a check on every access to an array to determine if the index is within the range of the array. If the index is outside the bounds of the array, an error is returned. Selecting this option will turn off this error checking, which can speed up array manipulation significantly. However, if your program accesses an array with an index that is out of bounds, invalid memory locations might be accessed without warning. This can cause unexpected behavior or program crashes. |
Remove Floating Point Error Checks |
Disables Visual Basic floating-point error checking and turns off error checking for valid floating-point operations and numeric values assigned to floating-point variables. By default in Visual Basic, a check is made on every calculation to a variable with floating-point data types (Single and Double) to be sure that the resulting value is within the range of that data type. If the value is of the wrong magnitude, an error will occur.
Error checking is also performed to determine if division by zero or other invalid operations are attempted. Selecting this option turns off this error checking, which can speed up floating-point calculations. If data type capacities are overflowed, however, no error will be returned and incorrect results might occur. |
Remove Integer Overflow Checks | Disables Visual Basic integer overflow checking. By default in Visual Basic, a check is made on every calculation to a variable with an integer data type (Byte, Integer, Long, and Currency) to be sure that the resulting value is within range of that data type. If the value is of the wrong magnitude, an error will occur. Selecting this option will turn off this error checking, which can speed up integer calculations. If data type capacities are overflowed, however, no error will be returned and incorrect results might occur. |
Remove Safe Pentium FDIV Checks | Disables checking for safe Pentium floating-point division and turns off the generation of special code for Pentium processors with the FDIV bug. The native code compiler automatically adds extra code for floating-point operations to make these operations safe when run on Pentium processors that have the FDIV bug. Selecting this option produces code that is smaller and faster, but which might in rare cases produce slightly incorrect results on Pentium processors with the FDIV bug. |
Integer Overflow
Dim n As Integer n = 100 * 200 * 300
Disassembly (without Integer Overflow check)
' Do the multiplication - ax = 300 mov ax,offset Form::Proc+4Ch ' Signed integer multiplication. 300 * 20000 ' The 20000 is stored in Form::Proc+51h and was ' created by the compiler from the constant exp. ' 100 * 200 and held as 'immediate data' imul ax,ax,offset Form::Proc+51h n = Result mov word ptr [n],ax
Disassembly (with Integer Overflow check)
' Do the multiplication - ax = 100 mov ax,offset Form::Proc+4Ch imul ax,ax,offset Form::Proc+51h ' Jump to error handler if the overflow flag set jo ___vbaErrorOverflow Else, n = Result mov word ptr [n],ax
Array Bounds
Dim n1 As Integer Dim n(100) As Integer n1 = n(101)
Disassembly (without Array Bounds check)
' Sizeof(Integer) = 2, put in eax push 2 pop eax ' Integer multiplication. 2 * 101 (&H65) = result in eax. imul eax,eax,65h ' Get array base address in to ecx. mov ecx,dword ptr [ebp-20h] n(101) (base plus offset) is in ax mov ax,word ptr [ecx+eax] n1 = n(101) mov word ptr [n1],ax
Disassembly (with Array Bounds check)
' Address pointed to by v1 = 101, the offset we want mov dword ptr [unnamed_var1],65h ' Compare value thus assigned with the known size of array + 1 cmp dword ptr [unnamed_var1],65h ' Jump above or equal to 'Call ___vbaGenerateBoundsError' jae Form1::Proc+6Dh ' Zero the flags and a memory location. and dword ptr [ebp-48h],0 ' Jump to 'mov eax,dword ptr [unnamed_var1]' jmp Form1::Proc+75h ' Raise the VB error here call ___vbaGenerateBoundsError ' Store element number we want to access mov dword ptr [ebp-48h],eax ' Get the element we wanted to access into eax mov eax,dword ptr [unnamed_var1] ' Get array base address in to ecx. mov ecx,dword ptr [ebp-20h] ' n(101) is in ax (* 2 because sizeof(Integer) = 2 mov ax,word ptr [ecx+eax*2] ' n1 = n(101) mov word ptr [n1],ax Floating Point Error Dim s As Single s = s * s
Disassembly (without Floating Point Error check)
' Pushes the specified operand onto the FP stack fld dword ptr [s] ' Multiplies the source by the destination and returns ' the product in the destination fmul dword ptr [s] ' Stores the value in the floating point store (ST?) ' to the specified memory location fstp dword ptr [s]
Disassembly (with Floating Point Error check)
fld dword ptr [s] fmul dword ptr [s] fstp dword ptr [s] ' Store the floating point flags in AX (no wait) fnstsw ax ' Test for floating point error flag set test al,0Dh ' Jump if zero flag not set jne ___vbaFPException
You should now have more of a feel for why these options are left partially obscured like they are, and for the warning given by Microsoft. Without a native code debugger it's really hard to see just how your code's being affected. Even with a debugger like the one that comes with Visual Studio it's not a straightforward task to read through the assembly-language dumps and state that your code is cool and that the optimizations you've chosen are safe!