Быстрое деление на GCC / ARM

Насколько я знаю, большинство компиляторов будут выполнять быстрое деление путем умножения, а затем сдвига битов вправо. Например, если вы проверитеэто так нить он говорит, что когда вы просите компилятор Microsoft выполнить деление на 10, он умножит дивиденд на 0x1999999A (что составляет 2 ^ 32/10), а затем разделит результат на 2 ^ 32 (используя 32 сдвига вправо).

Все идет нормально.

Как только я протестировал то же самое деление на 10 на ARM с использованием GCC, компилятор сделал что-то немного другое. Сначала он умножил дивиденд на 0x66666667 (2 ^ 34/10), затем разделил результат на 2 ^ 34. Пока что он такой же, как Microsoft, за исключением использования более высокого множителя. После этого, однако, он вычел (дивиденд / 2 ^ 31) из результата.

Мой вопрос: почему в версии ARM есть такое дополнительное вычитание? Можете ли вы привести числовой пример, где без этого вычитания результат будет неправильным?

Если вы хотите проверить сгенерированный код, он ниже (с моими комментариями):

        ldr     r2, [r7, #4] @--this loads the dividend from memory into r2
        movw    r3, #:lower16:1717986919 @--moves the lower 16 bits of the constant 
        movt    r3, #:upper16:1717986919 @--moves the upper 16 bits of the constant
        smull   r1, r3, r3, r2 @--multiply long, put lower 32 bits in r1, higher 32 in r3
        asr     r1, r3, #2 @--r3>>2, then store in r1 (effectively >>34, since r3 was higher 32 bits of multiplication)
        asr     r3, r2, #31 @--dividend>>31, then store in r3
        rsb     r3, r3, r1 @--r1 - r3, store in r3
        str     r3, [r7, #0] @--this stores the result in memory (from r3) 

Ответы на вопрос(2)

Ваш ответ на вопрос