Изменчивая внутренняя сборка рычага вызвала ошибку результата вычисления в лязге с асаном - PullRequest
0 голосов
/ 22 февраля 2019

Мой вопрос заключается в том, что я получаю неправильный результат, когда переменные nn не имеют изменяемых идентификаторов, но когда я добавляю изменяемый идентификатор к nn, тогда я получаю правильный результат.Что происходит, когда я добавляю летучий?Мой неправильный код ниже:

            int size = outw * outh;
            (volatile)int nn = size >> 2;
            int remain = size & 3;

            float32x4_t _bias0 = bias ? vld1q_f32(&bias[p]) : vdupq_n_f32(0.0f);
            int chanel_offset=in_channel_offset*4;
            int kernel_offset=inch*4;

            if (nn > 0)
            {
                // fprintf(stderr, "%s %d\n", __FILE__, __LINE__);
                asm volatile(
                    "add        r0, %[kernel0], %[kernel_offset]            \n"
                    "vld1.f32   {d0-d3},  [%[kernel0]]                      \n"
                    "vld1.f32   {d4-d7},  [r0]                              \n"
                    "add        r0, r0, %[kernel_offset]                    \n"
                    "vld1.f32   {d8-d11},  [r0]                             \n"
                    "add        r0, r0, %[kernel_offset]                    \n"
                    "vld1.f32   {d12-d15},  [r0]                            \n"

                    "add        r1, %[r0], %[channel_offset]                \n"
                    "pld        [%[r0], #128]                               \n"
                    "vld1.f32   {q13}, [%[r0] :128]!                        \n" // q13 = r0

                    "pld        [r1, #128]                  \n"
                    "vld1.f32   {q14}, [r1 :128]            \n" // q14 = r1

                    "pld        [%[outptr0], #128]          \n"
                    "vdup.32    q9, %e[_bias0][0]           \n"
                    "pld        [%[outptr1], #128]          \n"
                    "vdup.32    q10, %e[_bias0][1]          \n"

                    "0:                                     \n"
                    "vmla.f32   q9, q13, d0[0]              \n"
                    "vmla.f32   q10, q13, d4[0]             \n"
                    "add        r1, r1, %[channel_offset]   \n"
                    "pld        [%[outptr2], #128]          \n"
                    "vdup.32    q11, %f[_bias0][0]          \n"

                    "vmla.f32   q9, q14, d0[1]              \n"
                    "vmla.f32   q10, q14, d4[1]             \n"

                    "pld        [%[outptr3], #128]          \n"
                    "vdup.32    q12, %f[_bias0][1]          \n"

                    "vmla.f32   q11, q13, d8[0]             \n"
                    "vmla.f32   q11, q14, d8[1]             \n"

                    "pld        [r1, #128]                  \n"
                    "vld1.f32   {q15}, [r1 :128]            \n" // q15 = r2

                    "vmla.f32   q12, q13, d12[0]            \n"
                    "vmla.f32   q12, q14, d12[1]            \n"

                    "add        r1, r1, %[channel_offset]   \n"

                    "vmla.f32   q9, q15, d1[0]              \n"
                    "vmla.f32   q10, q15, d5[0]             \n"

                    "pld        [r1, #128]                  \n"
                    "vld1.f32   {q13}, [r1 :128]            \n" // q13 = r3

                    "vmla.f32   q11, q15, d9[0]             \n"
                    "vmla.f32   q12, q15, d13[0]            \n"

                    "add        r1, r1, %[channel_offset]   \n"

                    "vmla.f32   q9, q13, d1[1]              \n"
                    "vmla.f32   q10, q13, d5[1]             \n"

                    "pld        [r1, #128]                  \n"
                    "vld1.f32   {q14}, [r1 :128]            \n" // q14 = r4

                    "vmla.f32   q11, q13, d9[1]             \n"
                    "add        r1, r1, %[channel_offset]   \n"
                    "vmla.f32   q12, q13, d13[1]            \n"

                    "pld        [r1, #128]                  \n"
                    "vld1.f32   {q15}, [r1 :128]            \n" // q15 = r5

                    "vmla.f32   q9, q14, d2[0]              \n"
                    "vmla.f32   q10, q14, d6[0]             \n"

                    "add        r1, r1, %[channel_offset]   \n"

                    "pld        [%[r0], #128]               \n"
                    "vld1.f32   {q13}, [%[r0] :128]         \n" // q13 = r0

                    "vmla.f32   q11, q14, d10[0]            \n"
                    "vmla.f32   q12, q14, d14[0]            \n"

                    "pld        [r1, #128]                  \n"
                    "vld1.f32   {q14}, [r1 :128]            \n" // q14 = r6

                    "vmla.f32   q9, q15, d2[1]              \n"
                    "vmla.f32   q10, q15, d6[1]             \n"

                    "add        r1, r1, %[channel_offset]   \n"

                    "vmla.f32   q11, q15, d10[1]            \n"
                    "vmla.f32   q12, q15, d14[1]            \n"

                    "pld        [r1, #128]                  \n"
                    "vld1.f32   {q15}, [r1 :128]            \n" // q15 = r7

                    "vmla.f32   q9, q14, d3[0]              \n"
                    "vmla.f32   q10, q14, d7[0]             \n"

                    "add        r1, %[r0], %[channel_offset]\n"

                    "vmla.f32   q11, q14, d11[0]            \n"
                    "vmla.f32   q12, q14, d15[0]            \n"

                    "add        %[r0], %[r0], #16           \n"

                    "vmla.f32   q9, q15, d3[1]              \n"
                    "vmla.f32   q10, q15, d7[1]             \n"

                    "pld        [r1, #128]                  \n"
                    "vld1.f32   {q14}, [r1 :128]            \n" // q14 = r1

                    "vst1.f32   {q9}, [%[outptr0] :128]!    \n"
                    "vst1.f32   {q10}, [%[outptr1] :128]!   \n"

                    "vmla.f32   q11, q15, d11[1]            \n"
                    "vmla.f32   q12, q15, d15[1]            \n"

                    "subs       %[nn], #1                   \n"

                    "pld        [%[outptr0], #128]          \n"
                    //"vld1.f32   {q9}, [%0 :128]       \n" // q9 = outptr0
                    "vdup.32    q9, %e[_bias0][0]           \n"

                    "pld        [%[outptr1], #128]           \n"
                    //"vld1.f32   {q10}, [%1 :128]       \n" // q10 = outptr1
                    "vdup.32    q10, %e[_bias0][1]          \n"

                    "vst1.f32   {q11}, [%[outptr2] :128]!   \n"
                    "vst1.f32   {q12}, [%[outptr3] :128]!   \n"

                    "bne        0b                          \n"

                    "sub        %[r0], #16                  \n"

                    : [outptr0] "+r"(outptr0), 
                      [outptr1] "+r"(outptr1), 
                      [outptr2] "+r"(outptr2),
                      [outptr3] "+r"(outptr3), 
                      [r0] "+r"(r0),                          
                      [channel_offset] "+r"(chanel_offset)    

                    : [nn] "r"(nn),                          
                      [kernel0] "r" (kernel0),             
                      [kernel_offset] "r" (kernel_offset),   
                      [_bias0] "w" (_bias0)                 
                    : "cc", "memory", "r0", "r1", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
                      "q9", "q10", "q11", "q12", "q13", "q14", "q15");
            }

Приведенный выше код вычисляет результат outprt0, outptr1, outptr2, outptr3 с входным ядром, r0 и смещением (ядро * r0 + смещение).

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

Вы изменяете входной операнд, лежащий в компиляторе .

volatile int nn заставляет компилятор каждый раз перезагружать его из памяти вместо использования значения, которое должно бытьвсе еще в регистрах после вашего оператора asm, который обещал компилятору, что [nn] "r" (nn) был операндом ввода (только для чтения).

Но ваш код имеет "subs %[nn], #1.


Используйте ограничение "+r" для (копии) nn.

int nn_tmp = nn;  // the asm destroys this copy
asm ("..."  : [nn] "+r"(nn_tmp) : ...);

Или используйте фиктивный вывод с совпадающим ограничением, например

int dummy;
asm ("..." : "=r"(dummy)  : [nn] "0" (nn) : ...);

Где "0" - это номер операнда фиктивного вывода.

Вы могли бы сохранить / восстановить %[nn] каким-то образом внутри asm, но это почти неизменно хуже, чем позволить компиляторуПовторно материализуйте nn, если / когда необходимо.


Как правило, вам не нужно asm volatile, если только вы не берете ввод указателя и не используете "memory" Clobber, поэтому некоторые из выходов не являютсяв ограничениях как "=m" или [dummy_in_out] "+m"( *(float (*)[]) my_array), чтобы сказать ему весь массив или произвольный размер доступачерез этот указатель - операнд RMW.

В вашем случае, вероятно, наиболее вероятен клоббер памяти, и, вероятно, нет места для компилятора, развертывающего этот оператор или выполняющего несколько его прогонов с одним и тем же вводом.Или оптимизировать его, если все выходы не используются.

0 голосов
/ 22 февраля 2019

Том прав, что ключевое слово volatile намекает вашему компилятору, что ваши операции не должны быть оптимизированы.В объявлениях переменных volatile говорит компилятору не оптимизировать чтение / запись в эту переменную.

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

Этот фрагмент кода не компилируется, и вы не указали компилятор, поэтому я не буду копать дальше.

Я бы подключил ваш рабочий пример к https://godbolt.org/ и поиграл с тем, что оптимизируется при добавлении и удалении volatile.

...