Почему объявление переменных как volatile ускоряет выполнение кода? - PullRequest
0 голосов
/ 29 сентября 2011

Есть идеи? Я использую кросс-компилятор GCC для PPC750. Выполните простую операцию умножения двух чисел с плавающей запятой в цикле и синхронизируйте ее. Я объявил переменные переменными, чтобы убедиться, что ничего важного не было оптимизировано, и код ускорился!

Я проверил инструкции по сборке для обоих случаев и, конечно же, компилятор сгенерировал еще много инструкций для выполнения той же основной работы в энергонезависимом случае. Время выполнения для 10 000 000 итераций сократилось с 800 до 300 мс!

сборка для летучего корпуса:

0x10eeec  stwu  r1,-32(r1)
0x10eef0  lis   r9,0x1d # 29
0x10eef4  lis   r11,0x4080 # 16512
0x10eef8  lfs   fr0,-18944(r9)
0x10eefc  li    r0,0x0 # 0
0x10ef00  lis   r9,0x98 # 152
0x10ef04  stfs  fr0,8(r1)
0x10ef08  mtspr CTR,r9
0x10ef0c  stw   r11,12(r1)
0x10ef10  stw   r0,16(r1)
0x10ef14  ori   r9,r9,0x9680
0x10ef18  mtspr CTR,r9
0x10ef1c  lfs   fr0,8(r1)
0x10ef20  lfs   fr13,12(r1)
0x10ef24  fmuls fr0,fr0,fr13
0x10ef28  stfs  fr0,16(r1)
0x10ef2c  bc    0x10,0, 0x10ef1c # 0x0010ef1c
0x10ef30  addi  r1,r1,0x20 # 32

сборка для энергонезависимого корпуса:

0x10ef04  stwu        r1,-48(r1)
0x10ef08  stw         r31,44(r1)
0x10ef0c  or          r31,r1,r1
0x10ef10  lis         r9,0x1d # 29
0x10ef14  lfs         fr0,-18832(r9)
0x10ef18  stfs        fr0,12(r31)
0x10ef1c  lis         r0,0x4080 # 16512
0x10ef20  stw         r0,16(r31)
0x10ef24  li          r0,0x0 # 0
0x10ef28  stw         r0,20(r31)
0x10ef2c  li          r0,0x0 # 0
0x10ef30  stw         r0,8(r31)
0x10ef34  lwz         r0,8(r31)
0x10ef38  lis         r9,0x98 # 152
0x10ef3c  ori         r9,r9,0x967f
0x10ef40  cmpl        crf0,0,r0,r9
0x10ef44  bc          0x4,1, 0x10ef4c # 0x0010ef4c
0x10ef48  b           0x10ef6c # 0x0010ef6c
0x10ef4c  lfs         fr0,12(r31)
0x10ef50  lfs         fr13,16(r31)
0x10ef54  fmuls       fr0,fr0,fr13
0x10ef58  stfs        fr0,20(r31)
0x10ef5c  lwz         r9,8(r31)
0x10ef60  addi        r0,r9,0x1 # 1
0x10ef64  stw         r0,8(r31)
0x10ef68  b           0x10ef34 # 0x0010ef34
0x10ef6c  lwz         r11,0(r1)
0x10ef70  lwz         r31,-4(r11)
0x10ef74  or          r1,r11,r11
0x10ef78  blr

Если я правильно прочитал, он загружает значения из памяти во время каждой итерации в обоих случаях , но, похоже, генерирует гораздо больше инструкций для этого в энергонезависимом случае.

Вот источник:

void floatTest()
{
    unsigned long i;
    volatile double d1 = 500.234, d2 = 4.000001, d3=0;
    for(i=0; i<10000000; i++)
        d3 = d1*d2;
}

1 Ответ

2 голосов
/ 30 сентября 2011

Вы уверены, что также не меняли настройки оптимизации?

Оригинал выглядит неоптимизированным - вот часть цикла:

0x10ef34  lwz         r0,8(r31)       //Put 'i' in r0.
0x10ef38  lis         r9,0x98 # 152   //Put MSB of 10000000 in r9
0x10ef3c  ori         r9,r9,0x967f    //Put LSB of 10000000 in r9
0x10ef40  cmpl        crf0,0,r0,r9    //compare r0 to r9

0x10ef44  bc          0x4,1, 0x10ef4c //branch to loop if r0<r9
0x10ef48  b           0x10ef6c        //else branch to end

0x10ef4c  lfs         fr0,12(r31)     //load d1
0x10ef50  lfs         fr13,16(r31)    //load d2
0x10ef54  fmuls       fr0,fr0,fr13    //multiply
0x10ef58  stfs        fr0,20(r31)     //save d3

0x10ef5c  lwz         r9,8(r31)       //load i into r9
0x10ef60  addi        r0,r9,0x1       //add 1
0x10ef64  stw         r0,8(r31)       //save i

0x10ef68  b           0x10ef34        //go back to top, must reload r9

Изменчивая версия выглядит довольно оптимизированной - она ​​перераспределяет инструкции и использует регистр счетчика специального назначения вместо хранения i в стеке:

0x10ef00  lis   r9,0x98 # 152      //MSB of 10M
//.. 4 initialization instructions here ..
0x10ef14  ori   r9,r9,0x9680       //LSB of 10,000000
0x10ef18  mtspr CTR,r9             // store r9 in Special Purpose CTR register
0x10ef1c  lfs   fr0,8(r1)          // load d1
0x10ef20  lfs   fr13,12(r1)        // load d2
0x10ef24  fmuls fr0,fr0,fr13       // multiply
0x10ef28  stfs  fr0,16(r1)         // store result
0x10ef2c  bc    0x10,0, 0x10ef1c   // decrement counter and branch if not 0.

Оптимизация CTR сокращает цикл до 5 инструкций вместо 14 в исходном коде. Я не вижу причин, по которым «volatile» сама по себе могла бы позволить эту оптимизацию.

...