1. 31
    1. 1

      assert() in C is a bit confused: it’s optional, so it can’t be used to guarantee something is always true. But it’s not stating an assumption like SQLite wants to. It’s too late to have it perform as __builtin_assume(), since that will cause all kinds of UB in programs wherever someone intended it as a safety double-check rather than an optimization hint.

      SQLite would probably be better off defining their own assume() macro rather than try to reeducate everyone on their flavor of assert().

      1. 1

        What is __builtin_assume? I only found __assume in MSVC and __builtin_assume_aligned in GCC.

        What is the problem with using assert for optimizations. If the condition is false the statements afterwards are not executed so the assumption of the condition being true can be used. Just like an if-statement branch provides guarantees.

        assert(foo < 42);      // exchange with if (!(foo < 42)) return;
        bar = (foo * 2) < 100 ? "yes" : "no";   // can be optimized to bar = "yes"
        
        1. 2

          it’s if !cond { __builtin_unreachable() }, i.e. tells the compiler that the condition is always true, and invoke UB if it isn’t. It’s different than assert(), because it doesn’t check, it removes all checks of such condition.

          Letting optimizer assume things is dangerous, e.g. there’s a well-known bug:

          char *tmp = &obj->field;
          if (!obj) {
             return;
          }
          

          In the code above the if is completely removed, because obj->field lets the optimizer assume obj cannot possibly be null. If you’re not SQLite and do assert(obj) you may expect to catch a bug when obj is unexpectedly null. If you do assume(obj) you’re guaranteeing the code will misbehave on null.

        2. 1

          It’s a clang extension. It lets the compiler assume that the condition is true. LLVM has some macros that expand to something analogous to assert in debug builds and __builtin_assume in release builds, so that assumptions are checked during testing and then fed into the optimiser for release builds.