Есть ли способ получить не 8-битный множественный тип данных? - PullRequest
0 голосов
/ 16 ноября 2018

Я понимаю, что это своего рода странный вопрос, но у меня есть несколько мыслей по поводу, и это заинтересовало меня.

пример: как я могу получить 31-битный тип данных или что-то в этом роде?)

прямо сейчас я думаю, что ответ на этот вопрос - НЕТ, вы не можете.может я не прав?

1 Ответ

0 голосов
/ 16 ноября 2018

Вы всегда можете реализовать перенос на любую ширину вручную, например a++; a&=0x7fffffff;, чтобы замаскировать результат до 31 бита и реализовать беззнаковый 31-битный тип. Возвращение расширения знака к более широкому типу обходится дороже, обычно смещение влево, а не арифметическое смещение вправо, если ширина источника не поддерживается специально языком и / или оборудованием. (например, ARM имеет команду расширения со знаком битового поля, которая может извлекать и расширять знак произвольного битового поля в регистр полного целого числа).

Есть процессоры со словами и / или байтами, которые не кратны 8 битам, например PDP-10 имеет 36-битные слова. https://en.wikipedia.org/wiki/36-bit. В этой системе естественный размер составляет 36 бит, и 32 бита будут нестандартным типом, требующим дополнительных инструкций.

Могу ли я иметь какие-то структуры данных, которые будут храниться в памяти, например, 31 бит -> 31 бит -> 31 бит, и можно ли заставить процессор работать с ними как 31 бит.

Нет, вы не можете этого сделать. Нет процессоров, о которых мне известно, с битно-адресуемой памятью. Любая загрузка / сохранение должна быть выровнена по крайней мере до границ байтов. (Байт-адресуемая память в наши дни почти универсальна, но некоторые DSP и некоторые старые процессоры, такие как DEC Alpha, имеют / имеют только адресную память).

C с битовыми полями будет эмулировать более узкие типы, но с заполнением; вы не можете избежать того, что сгенерированный компилятором ассемблер коснется отступа.

, например

struct i31 {
    int i:31;   // note *signed* int
    // 1 bit of padding is implicit on targets with 32-bit int
};

struct i31 inc(struct i31 x) {
    x.i++;
    return x;
}

int extend_to_int(struct i31 x) {
    return x.i;
}

компилируется для x86-64 в это (в проводнике компилятора Godbolt) .

Вероятно, я должен был бы использовать gcc -fwrapv, чтобы определить поведение переполнения со знаком в качестве дополнения 2. Я не уверен, что правила C для битовых полей, является ли присвоение подписанного результата подписанному битовому полю все еще вызывает поведение переполнения подписи undefined-поведение в ISO C и C ++.

# gcc8.2 -O3
inc(i31):
    lea     eax, [rdi+1]
    and     edi, -2147483648   # keep the top bit of the input
    and     eax, 2147483647    # keep the low 31 bits of i++
    or      eax, edi           # merge.
          #   IDK why it can't / doesn't just leave the carry-out in the padding
    ret
extend_to_int(i31):
    lea     eax, [rdi+rdi]     # left shift by 1 (and copy)
    sar     eax                # shift arithmetic right (by 1)
    ret

Но ARM аккуратен и имеет лучшие инструкции по битовым полям, чем x86. (Практически все имеют лучшие инструкции битового поля, чем x86).

# ARM gcc7.2 -march=armv8-a -O3
inc(i31):
    add     r3, r0, #1
    bfi     r0, r3, #0, #31    # bitfield insert to preserve the high bit of the struct
    bx      lr
extend_to_int(i31):
    sbfx    r0, r0, #0, #31    # signed bitfield extract
    bx      lr
...