2013-12-13 3 views
0

Я пытаюсь узнать больше об ARM-сборке и понять, что именно происходит за кулисами с NEON intrinsics. Я использую последний компилятор Xcode LLVM. Я нахожу, что часто сборка, созданная из встроенных функций, на самом деле медленнее, чем даже простой наивный код C.Сборка, созданная с помощью NEON intrinsics [LLVM - Xcode]

Например, этот код:

void ArmTest::runTest() 
{ 

    const float vector[4] = {1,2,3,4}; 
    float result[4]; 
    float32x4_t vA = vld1q_f32(vector); 

    asm("#Begin Test"); 

    vA = vmulq_f32(vA, vA); 

    asm("#End Test"); 

    vst1q_f32(result, vA); 
} 

Производит этот вывод:

#Begin Test 

ldr q0, [sp, #16] 
stp q0, q0, [fp, #-48] 
ldur q1, [fp, #-32] 
fmul.4s v0, v1, v0 
str q0, [sp, #16] 

#End Test 

То, что я не понимаю, почему все грузы/магазины ударяя память здесь? Я должен упустить что-то очевидное, не так ли? Кроме того, как бы написать это в встроенной сборке, чтобы она была оптимальной? Я бы ожидал только одной инструкции, но результат был другим.

Пожалуйста, помогите мне разобраться.

Спасибо!

+0

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

+0

Вы также должны знать, что доступ к одной и той же области памяти с ARM и NEON отнимает много циклов при «переключении». Поэтому, если вы пишете тестовые функции, вы должны позволить им обрабатывать большой фрагмент данных с помощью нескольких итераций. В вашем примере вектор, вероятно, инициализируется ARM в стеке и считывается и вычисляется NEON - очень медленно. –

+0

void square (float * pDst, float * pSrc, unsigned int size); <== например. –

ответ

2

Вам нужен лучший тест. Ваш тест не использует результаты вашего расчета ни за что, поэтому компилятор просто движется, чтобы сделать вас счастливыми. Похоже, что вы компилируете с -O0, что создаст кучу ненужных загрузок и хранилищ для целей отладки. Если вы скомпилированы с -O3, весь ваш код будет удален. Я переписал тест, чтобы сохранить результаты и скомпилирован с -O3 и вот результаты:

$ cat neon.c 
#include <arm_neon.h> 

void runTest(const float vector[], float result[]) 
{ 
    float32x4_t vA = vld1q_f32(vector); 
    vA = vmulq_f32(vA, vA); 
    vst1q_f32(result, vA); 
} 

$ xcrun -sdk iphoneos clang -arch arm64 -S neon.c -O3 
$ cat neon.s 
    .section __TEXT,__text,regular,pure_instructions 
    .globl _runTest 
    .align 2 
_runTest:        ; @runTest 
; BB#0: 
    ldr q0, [x0] 
    fmul.4s v0, v0, v0 
    str q0, [x1] 
    ret lr 

Этот код выглядит оптимальные

+0

Спасибо! Я знал, что я пропустил что-то простое. Результат у вас есть именно то, что я ожидал, и ваше предположение было правильным, я не собирал флагов O3 – bitwise

Смежные вопросы