Функция ARM THUMB2 для сравнения с рядом значений

Я новичок в ARM и хочу сравнить значение в регистре с набором известных шестнадцатеричных значений. На данный момент я делаю это, используя отдельные инструкции CMP, поэтому код выглядит так:

;stuff

CMP r2, #0x41

CMP r2, #0x45

CMP r2, #0x49

etc...

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

Извиняюсь за вопрос новичка, заранее спасибо за помощь.


person Craw86    schedule 05.01.2017    source источник
comment
Имейте значения, которые вы хотите сравнить, в массиве и перебирайте их   -  person Colin    schedule 05.01.2017
comment
Вы можете сделать дерево сравнений, похожее на двоичный поиск.   -  person EOF    schedule 05.01.2017
comment
это своего рода природа языка ассемблера, у них нет инструкции сравнения одного регистра со многими вещами одновременно, конечно, не для RISC, может быть, CISC, но я сомневаюсь в этом (говоря, что это может привести к тому, что кто-то покажет исключение). вы, возможно, можете уменьшить количество сравнений, но у большого пальца нет инструкции сравнения одного со многими.   -  person old_timer    schedule 11.01.2017


Ответы (1)


Как правило, вы смотрите на допустимый диапазон значений.

  1. Убедитесь, что значение находится в диапазоне.
  2. Вычтите наименьшее значение из регистра.
  3. Использовать измененное значение в качестве индекса массива; Массив может иметь ключ значения или просто быть да/нет.

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

  # Range check (step 1)
  cmp r2, #hi_val
  bhi out_of_range
  cmp r2, #low_val         ; optimized version is subs r2, r2, #low_val
  blo out_of_range

  # Adjust value (step 2)
  sub r2, r2, #low_val     ; removed in optimized version.

  # Get check from array (step 3)
  adr r0, key_array
  ldrb r0, [r0, r2]  ; base of array + adjusted value.
  bx   lr            ; return w. result in r0.

# Handle not in range.
out_of_range:
  mov  r0, #-1
  bx   lr            ; use 0xffffffff for out of range.

# This is a constant array included with the code.
key_array:
  .byte 1, 1, 0, 1, 1, 1, 0, 0, 1, 1 # etc.

Очевидно, что ваш key_array должен быть изменен, чтобы соответствовать вашему варианту использования. Коды условий немного изменятся для значений со знаком и без знака.

Если key_array - это все единицы для двоичного случая, то шаги два и три - это просто return 1;. Если low_val равно нулю, вам не нужно вычитать (или выполнять проверку низкого диапазона). Размер key_array должен быть hi_val - low_val + 1, иначе логика проверки диапазона может измениться.

Этот механизм используется для многих функций «ctype», таких как ispunct, но вы можете хранить до восьми значений в байте и использовать битовую маску, чтобы получить то, что вас интересует. Его также легко реализовать на «C» и используйте компилятор. Можно использовать только один регистр (R0 является функцией, совместимой с EABI), но тогда обработка ошибок также будет смешанной и менее понятной.

person artless noise    schedule 06.01.2017