LINUX.ORG.RU

GCC аппаратный float для arm

 , ,


1

2

Есть вот такая функция для тестирования fpu:

float __attribute__ ((noinline)) testfpu(float a) {
	return __builtin_sqrtf(__builtin_sqrtf(__builtin_sqrtf(a)));
}
Для неё GCC генерирует следующий код:
/ (fcn) sym.testfpu (thumb) 80
|           ; CALL XREF from 0x08001cb6 (sym.testfpu)
|           0x08001c50      b1eec07a       vsqrt.f32 s14, s0
|           0x08001c54      08b5           push {r3, lr}
|           0x08001c56      b4ee477a       vcmp.f32 s14, s14
|           0x08001c5a      f1ee10fa       vmrs apsr_nzcv, fpscr
|       ,=< 0x08001c5e      0ed1           bne 0x8001c7e
|       |   ; JMP XREF from 0x08001c86 (sym.testfpu)
|      .--> 0x08001c60      f1eec77a       vsqrt.f32 s15, s14
|      ||   0x08001c64      f4ee677a       vcmp.f32 s15, s15
|      ||   0x08001c68      f1ee10fa       vmrs apsr_nzcv, fpscr
|     ,===< 0x08001c6c      11d1           bne 0x8001c92
|     |||   ; JMP XREF from 0x08001c9e (sym.testfpu)
|    .----> 0x08001c6e      b1eee70a       vsqrt.f32 s0, s15
|    ||||   0x08001c72      b4ee400a       vcmp.f32 s0, s0
|    ||||   0x08001c76      f1ee10fa       vmrs apsr_nzcv, fpscr
|   ,=====< 0x08001c7a      05d1           bne 0x8001c88
|   |||||   ; JMP XREF from 0x08001c90 (sym.testfpu)
|  .------> 0x08001c7c      08bd           pop {r3, pc}
|  |||||`-> 0x08001c7e      08f067f9       bl sym.sqrtf
|  |||||    0x08001c82      b0ee407a       vmov.f32 s14, s0
|  ||||`==< 0x08001c86      ebe7           b 0x8001c60
|  |`-----> 0x08001c88      b0ee670a       vmov.f32 s0, s15
|  | ||     0x08001c8c      08f060f9       bl sym.sqrtf
|  `======< 0x08001c90      f4e7           b 0x8001c7c
|    |`---> 0x08001c92      b0ee470a       vmov.f32 s0, s14
|    |      0x08001c96      08f05bf9       bl sym.sqrtf
|    |      0x08001c9a      f0ee407a       vmov.f32 s15, s0
\    `====< 0x08001c9e      e6e7           b 0x8001c6e

Настройки компилятора:
-O2 -mfpu=vfpv4-d16 -mfloat-abi=hard
Видно, что gcc успешно использует инструкцию vsqrt для вычисления квадратного корня. Но при этом после каждой инструкции вставляются некрасивые проверки с откатом на программную реализацию в случае возникновения ошибки. Как можно избавиться от этих проверок?

PS: Забавно, что без использования FPU код получается куда проще:

/ (fcn) sym.testfpu (thumb) 18
|           ; CALL XREF from 0x08001b30 (sym.testfpu)
|           0x08001b0c      08b5           push {r3, lr}
|           0x08001b0e      08f0fff8       bl sym.sqrtf
|           0x08001b12      08f0fdf8       bl sym.sqrtf
|           0x08001b16      bde80840       pop.w {r3, lr}
\       ,=< 0x08001b1a      08f0f9b8       b.w sym.sqrtf



Последнее исправление: Selat (всего исправлений: 1)

без использования FPU код получается куда проще:

И тормознее. Потому что остальной код сидит в libm.

devl547 ★★★★★
()
Ответ на: комментарий от devl547

Быстрее в случае извлечения корня из отрицательного число :)

Selat
() автор топика

$ armv7a-unknown-linux-gnueabi-gcc -O2 -ffast-math -mfpu=vfpv4-d16 -mfloat-abi=hard -S a.c

testfpu:
        vabs.f32        s0, s0
        vmov.f32        s1, #1.25e-1
        b       powf
        .size   testfpu, .-te

:)

sf ★★★
()

JMP всегда выполнялся за 1 такт,при текущих гигагерцах на аармах-что ты собрался экономить?

может еще точки с запятой и скобки начнешь считать?

совсем уже?

hxf88097
()

Я наконце-то нагуглил нужную статью: ссылка.

Всё оказалось очень просто: gcc по умолчанию хочет, чтобы sqrt при ошибке писала статус в переменную errno. Проверки приходится добавлять потому, что процессорная инструкция не знает про эту переменную. Отключить проверку математических функцией на ошибки можно с помощью опции -fno-math-errno.

Selat
() автор топика
Ответ на: комментарий от Selat

С включённой опцией код получается куда проще:

/ (fcn) sym.testfpu (thumb) 14
|           ; CALL XREF from 0x080009d6 (sym.testfpu)
|           0x0800093c      b1eec00a       vsqrt.f32 s0, s0
|           0x08000940      f1eec07a       vsqrt.f32 s15, s0
|           0x08000944      b1eee70a       vsqrt.f32 s0, s15
\           0x08000948      7047           bx lr       

Selat
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.