Большинство архитектур поддерживают только 128-битное И через SIMD, и в этом случае они обычно также поддерживают сравнение для равенства в упакованных байтах / int16 / int32. например, x86 pcmpeqb/w/d/q
.
Вы можете И вместе сравнить результаты и проверить в конце (строки кэша или целого массива), что каждый элемент вашего вектора SIMD имеет "true" ", т. е. каждый элемент массива соответствует первому элементу.
Вы можете сделать это на упакованных 2-битных полях, выполнив битовую трансляцию, чтобы дублировать первое 2-битное поле для всех остальных пар. в байтах и в байтовой передаче, что в целом вектор SIMD (например, AVX2 vpbroadcastb
, или в C intrinsics _mm_set1_epi8
). Сравнение на равенство все еще работает в этом случае для упакованных 2-битных или 4-битных полей, хотя для загрузки + pcmpeqb с другим reg + pand может потребоваться пара дополнительных входных мопов на 16-байтовый вектор по сравнению с просто pand
с операндом источника памяти. Тем не менее, разрешение на вдвое более плотном представлении компенсирует это на большинстве процессоров, особенно когда вы рассматриваете возможность сократить объем кэш-памяти в два раза. перенумерация для вас, или упаковка массива перечислений для хранения двух элементов nibble на байт.
Определенно нет текущих компиляторов C; язык (и ABI для языка) слишком сильно определяют ширину типов и макеты данных, и обычно компилятору не стоит тратить время на поиск редких случаев, когда структура данных полностью закрыта для функции и полностью реструктурировать работу типов .
(Более того, компилятору Writers времени обычно не стоит пытаться писать код, который может безопасно / правильно выполнять крупные высокоуровневые преобразования, которые отличают макет данных в памяти от исходного кода говорит, что полная оптимизация массива, безусловно, сделана, но я не видел, как это делают C компиляторы. Изменение типа *)
Но, конечно, это возможно в теории, особенно в отличие от языков C, где enum
не определяет , как вещи нумеруются автоматически. (В C, который четко определен: начинайте с нуля и увеличивайте на 1, если вы не переопределите его, например, enum foo { a = 1<<0, b = 1<<1, ... };
Скомпилированные языки с опережением времени будут нацелены на ABI, который определен для платформы (например, x86-64 System V ABI при компиляции для x86-64 GNU / Linux). Это позволяет коду из разных компиляторов и разных версий / настроек оптимизации одного и того же компилятора вызывать друг друга.
Наличие enum
в качестве функции arg или возвращаемого значения делает его частью ABI, для не static
функций (то есть тех, которые могут быть вызваны из отдельно скомпилированного кода Таким образом, кроме оптимизации во время соединения (и встраивания), компиляторы не имеют выбора в отношении представления данных через границы не встроенных функций. (За исключением иногда с межпроцедурной оптимизацией, иногда включаемой оптимизацией во время соединения через источник файлы.)
Также имейте в виду, что компиляторы C обычно заботятся о том, чтобы быть полезными для низкоуровневого системного программирования, включая int извлечение с помощью аппаратного обеспечения или возможность отображения файлов карты памяти. Если это может произойти, то представления данных становятся видимыми извне. Это причина, почему компиляторы не захотят делать упаковку данных, которая изменяет способ хранения массива. Трудно доказать (кроме локального, чей адрес никогда не выходит за пределы функции), что ничто иное не может заботиться о расположении данных массива.
Атомность / потокобезопасность для изменения смежных элементов массива
C / C ++ гарантирует, что разные потоки могут изменять разные объекты, не мешая друг другу. (поскольку C11 / C ++ 11 представили модель памяти с поддержкой потоков).
Сюда входят смежные элементы char array[]
или enum foo array[]
. Каждый элемент массива является отдельным объектом. (А также является частью всего объекта массива). Модель памяти C ++ и условия гонки на массивах символов и Может ли современное оборудование x86 не хранить в памяти ни одного байта? (может, так может каждый ISA с инструкциями для хранения байтов)
На однопоточном языке или на языке без такой гарантии, да, теоретически у вас может быть реализация, которая упаковывает перечисления в суббайтовые поля.
Интересный факт: в C ++ std::vector<bool>
требуется специализация на упакованном растровом шаблоне ( полезная структура данных, к сожалению, исторический выбор класса для предоставления его через ). Это делает небезопасным одновременное выполнение vbool[1] = false
и vbool[2] = false
различными потоками, в отличие от других std::vector
, где это безопасно.
Если вы хотите эту оптимизацию, вы обычно написать самому в источнике