Divide by zero with VC ++ 2015 cycle optimization

Background:

We just switched our development environment to VC ++ 2015 with VC ++ 2008. Right after that we discovered a problem: the program raised the division by 0, despite the fact that the divider is divided into C ++ code.

Test code:

#include <cstdlib>

int test(int n, int test_for_zero)
{
    int result = 0;
    for (int i = 0; i < n; ++i) {

        if (test_for_zero)
            result += rand() >> ((8 % test_for_zero) * test_for_zero);
    }

    return result;
}

int main()
{
    return test(rand(), rand() & 0x80000000);
}

Compiled VC ++ 2015 Update 3 or VC ++ 2017 with default settings, at startup, it increases the division by zero. Compiled VC 2008 works fine.

Analysis:

; 6    :    for (int i = 0; i < n; ++i) {

    test    edi, edi
    jle SHORT $LN15@main

; 7    : 
; 8    :        if (test_for_zero)
; 9    :            result += rand() >> ((8 % test_for_zero) * test_for_zero);

    mov ecx, DWORD PTR _test_for_zero$1$[ebp]
    mov eax, 8
    cdq
    idiv    ecx  ; <== IT HERE, IDIV BEFORE CHECKING FOR ZERO
    mov eax, edx
    imul    eax, ecx
    mov DWORD PTR tv147[ebp], eax
    test    ecx, ecx
    je  SHORT $LN15@main
$LL11@main:
    call    ebx
    mov ecx, DWORD PTR tv147[ebp]
    sar eax, cl
    add esi, eax
    sub edi, 1
    jne SHORT $LL11@main

The compiler takes the constant part ((8 % test_for_zero) * test_for_zero)from the body of the loop and simply forgets to test test_for_zerobefore dividing. Obviously, it can be easily fixed in place by simply completing the compiler task, but correctly.

, -d2SSAOptimizer- -Oxx, - -Od.

:

  • ? ++ VC 2008, ?
  • : - , -Ob?
+4
1

( Visual Studio!), .

, "Invariant Code Motion". , VS 15.7.

, https://docs.microsoft.com/en-us/cpp/preprocessor/optimize:

    #pragma optimize( "", off )  
    <Function containing code with this loop>
    #pragma optimize( "", on )  

, , (-Od), , .

+1

Source: https://habr.com/ru/post/1689204/


All Articles