Сравните две 64-битные переменные на 32-битном микроконтроллере - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть следующая проблема: у меня есть две 64-битные переменные, и их нужно сравнивать как можно быстрее, мой микроконтроллер только 32-битный.

Я думаю, что необходимо разделить 64-битную переменнуюна две 32-битные переменные, такие как

uint64_t var = 0xAAFFFFFFABCDELL;
hiPart = (uint32_t)((var & 0xFFFFFFFF00000000LL) >> 32);
loPart = (uint32_t)(var & 0xFFFFFFFFLL);

, а затем сравнить hiParts и loParts, но я уверен, что этот подход медленный и существует гораздо лучшее решение

Ответы [ 4 ]

0 голосов
/ 21 сентября 2018

Если вы работаете с профсоюзом, вы можете сравнить Hi и Lo Part без каких-либо дополнительных вычислений:

typedef union
{
    struct
    {    
        uint32_t   loPart;
        uint32_t   hiPart;
    };
    uint64_t       complete;
}uint64T;

uint64T var.complete = 0xAAFFFFFFABCDEULL;
0 голосов
/ 21 сентября 2018

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

uint64_t var = …, other_var = …;
if (var == other_var) …

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

load 32 bits from &var into r0
load 32 bits from &other_var into r1
if r0 != r1: goto different
load 32 bits from &var + 4 into r2
load 32 bits from &other_var + 4 into r3
if r2 != r3: goto different
// code for if-equal
different:
// code for if-not-equal

Вот некоторые вещи, которые компилятор знает лучше, чем вы:

  • Какие регистры использовать в зависимости от потребностей окружающегоcode.
  • Использовать ли повторно одни и те же регистры для сравнения верхней и нижней частей или использовать разные регистры.
  • Обрабатывать ли одну часть, а затем другую (как указано выше), илизагрузить одну переменную, а затем другую.Лучший порядок зависит от нагрузки на регистры, а также от времени доступа к памяти и конвейеризации конкретной модели процессора.
0 голосов
/ 21 сентября 2018

Первое правило должно быть: Напишите вашу программу, чтобы она была читабельна человеку .

Если вы сомневаетесь, ничего не предполагайте, а измеряйте.Давайте посмотрим, что нам дает Годболт .

#include <stdint.h>
#include <stdbool.h>

bool foo(uint64_t a, uint64_t b) {
    return a == b;
}

bool foo2(uint64_t a, uint64_t b) {

    uint32_t ahiPart = (uint32_t)((a & 0xFFFFFFFF00000000ULL) >> 32);
    uint32_t aloPart = (uint32_t)(a & 0xFFFFFFFFULL);
    uint32_t bhiPart = (uint32_t)((b & 0xFFFFFFFF00000000ULL) >> 32);
    uint32_t bloPart = (uint32_t)(b & 0xFFFFFFFFULL);

    return ahiPart == bhiPart && aloPart == bloPart;
}

foo:
        eor     r1, r1, r3
        eor     r0, r0, r2
        orr     r0, r0, r1
        rsbs    r1, r0, #0
        adc     r0, r0, r1
        bx      lr

foo2:
        eor     r1, r1, r3
        eor     r0, r0, r2
        orr     r0, r0, r1
        rsbs    r1, r0, #0
        adc     r0, r0, r1
        bx      lr

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

0 голосов
/ 21 сентября 2018

Было время, когда несколько лет назад вам приходилось делать трюки, чтобы быть умнее компилятора.Но на 99,999% компилятор будет умнее вас.

А ваши переменные без знака.Поэтому используйте ULL вместо LL.

...