Внимание гуру сборки ARM!
У меня есть код, который неожиданно завершается неудачей при оптимизации. Я выделил его в простом модульном тесте на моем встроенном устройстве. Код построен для встроенной среды ARM A7 с использованием gcc-arm-8.3-2019.03-x86_64-arm-eabi.
Код представляет собой базовый поиск двоичного дерева как часть шаблона:
map_node_s<KEY, VALUE> * _getMutableNode(
const KEY & key,
OUT map_node_s<KEY, VALUE> *** ptrToChildLink,
OUT map_node_s<KEY, VALUE> ** ptrToParent
)
{
map_node_s<KEY, VALUE> * parent = NULL;
map_node_s<KEY, VALUE> ** linkToChild = &_root;
map_node_s<KEY, VALUE> * current = *linkToChild;
while (current)
{
if (current->key == key)
{
break;
}
parent = current;
if (key < current->key)
{
linkToChild = &parent->left;
current = parent->left;
}
else
{
linkToChild = &parent->right;
current = parent->right;
}
}
*ptrToParent = parent;
*ptrToChildLink = linkToChild;
return current;
}
Это вызывается методом _getStoredKey
, а KEY и VALUE имеют значения int.
Оптимизатор (O2) выдает следующее, что выглядит правильно:
map_node_s<KEY, VALUE> * _getStoredKey(const KEY & key)
63174910: e92d 43f7 stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, lr}
63174914: 4604 mov r4, r0
map_node_s<KEY, VALUE> * current = *linkToChild;
63174916: 6843 ldr r3, [r0, #4]
map_node_s<KEY, VALUE> * _getStoredKey(const KEY & key)
63174918: 4689 mov r9, r1
map_node_s<KEY, VALUE> ** linkToChild = &_root;
6317491a: 1d07 adds r7, r0, #4
map_node_s<KEY, VALUE> * parent = NULL;
6317491c: f04f 0800 mov.w r8, #0
while (current)
63174920: b17b cbz r3, 63174942 <_ZNSt3mapImSt4pairImSt6vectorIhN3csd9allocatorIhEEEEE13_getStoredKeyERKm+0x32>
if (current->key == key)
63174922: 6819 ldr r1, [r3, #0]
63174924: f8d9 2000 ldr.w r2, [r9]
63174928: 4291 cmp r1, r2
6317492a: d00a beq.n 63174942 <_ZNSt3mapImSt4pairImSt6vectorIhN3csd9allocatorIhEEEEE13_getStoredKeyERKm+0x32>
current = parent->right;
6317492c: e9d3 2106 ldrd r2, r1, [r3, #24]
linkToChild = &parent->left;
63174930: bf8e itee hi
63174932: f103 0718 addhi.w r7, r3, #24
linkToChild = &parent->right;
63174936: f103 071c addls.w r7, r3, #28
current = parent->right;
6317493a: 460a movls r2, r1
6317493c: 4698 mov r8, r3
6317493e: 4613 mov r3, r2
63174940: e7ee b.n 63174920 <_ZNSt3mapImSt4pairImSt6vectorIhN3csd9allocatorIhEEEEE13_getStoredKeyERKm+0x10>
current = _getMutableNode(key, &linkToChild, &parent);
63174942: 9301 str r3, [sp, #4]
Но при запуске получается неправильная сортировка, если я не отключаю оптимизацию для метода !! Неоптимизированная сборка выглядит совершенно иначе.
Код также будет работать, если я добавлю точку останова. Я не знаю, как это влияет на конвейер команд, или I-кеш, или что-то еще.
Кроме того, если я сделаю небольшую корректировку, код будет работать:
if (key < current->key)
{
linkToChild = &parent->left;
}
else
{
linkToChild = &parent->right;
}
current = *linkToChild;
который испускает
6317ff34: b168 cbz r0, 6317ff52 <_ZNSt3mapIiiE15_getMutableNodeERKiPPPSt10map_node_sIiiES6_+0x28>
if (current->key == key)
6317ff36: 680b ldr r3, [r1, #0]
6317ff38: 6806 ldr r6, [r0, #0]
6317ff3a: 429e cmp r6, r3
6317ff3c: d009 beq.n 6317ff52 <_ZNSt3mapIiiE15_getMutableNodeERKiPPPSt10map_node_sIiiES6_+0x28>
linkToChild = &parent->left;
6317ff3e: bfc7 ittee gt
6317ff40: 68c6 ldrgt r6, [r0, #12]
6317ff42: f100 040c addgt.w r4, r0, #12
linkToChild = &parent->right;
6317ff46: 6906 ldrle r6, [r0, #16]
6317ff48: f100 0410 addle.w r4, r0, #16
map_node_s<KEY, VALUE> * _getMutableNode(
6317ff4c: 4605 mov r5, r0
6317ff4e: 4630 mov r0, r6
6317ff50: e7f0 b.n 6317ff34 <_ZNSt3mapIiiE15_getMutableNodeERKiPPPSt10map_node_sIiiES6_+0xa>
Что-то не так с созданной компилятором сборкой?
Есть ли дополнительные директивы asm, которые я могу вставить, чтобы попытаться проверить наличие проблем с выполнением?