Can I hint the optimizer by giving the range of an integer?

后端 未结 4 974
一生所求
一生所求 2020-12-02 04:15

I am using an int type to store a value. By the semantics of the program, the value always varies in a very small range (0 - 36), and int (not a

4条回答
  •  半阙折子戏
    2020-12-02 04:33

    Yes, it is possible. For example, for gcc you can use __builtin_unreachable to tell the compiler about impossible conditions, like so:

    if (value < 0 || value > 36) __builtin_unreachable();
    

    We can wrap the condition above in a macro:

    #define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
    

    And use it like so:

    assume(x >= 0 && x <= 10);
    

    As you can see, gcc performs optimizations based on this information:

    #define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
    
    int func(int x){
        assume(x >=0 && x <= 10);
    
        if (x > 11){
            return 2;
        }
        else{
            return 17;
        }
    }
    

    Produces:

    func(int):
        mov     eax, 17
        ret
    

    One downside, however, that if your code ever breaks such assumptions, you get undefined behavior.

    It doesn't notify you when this happens, even in debug builds. To debug/test/catch bugs with assumptions more easily, you can use a hybrid assume/assert macro (credits to @David Z), like this one:

    #if defined(NDEBUG)
    #define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
    #else
    #include 
    #define assume(cond) assert(cond)
    #endif
    

    In debug builds (with NDEBUG not defined), it works like an ordinary assert, printing error message and abort'ing program, and in release builds it makes use of an assumption, producing optimized code.

    Note, however, that it is not a substitute for regular assert - cond remains in release builds, so you should not do something like assume(VeryExpensiveComputation()).

提交回复
热议问题