В качестве упражнения и побочного проекта я начал писать библиотеку SIMD времени выполнения на C++, которая охватывает встроенные функции и строит дерево выражений. Каждый возможный узел в дереве должен содержать метод eval(), который возвращает результат указанного узла. Например, для узла AddOp он суммирует обе стороны, для simd_vec он загружает данные в регистр AVX.
Поскольку я использую FMV для генерации различных путей кода и диспетчера во время выполнения, у меня есть один тип возвращаемого значения, который может включать в себя результат для AVX-512, AVX2, а также скаляр. отступать. Моей первой мыслью было сделать что-то вроде этого
Идея заключается в том, что simd_t не владеет данными и не приводит к ненужной загрузке и сохраняется на каждом этапе дерева рекурсивных выражений.
Теперь у меня есть проблема с этим: он компилируется правильно только тогда, когда передаются флаги -mavx2 и -mavx512f.
/>Другая идея, которая у меня возникла, заключалась в том, чтобы иметь в стеке облегченную оболочку, подобную этой:
Код: Выделить всё
template
struct simd_register {
// In a more robust version the largest compiled in vector size would be in a context singleton
alignas(64) T[64 / sizeof(T)];
}
Основная проблема, с которой я столкнулся при этом подходе, заключается в том, что теперь на каждом этапе eval() выполняются операции загрузки и сохранения из стека и в него. Мне известно о правиле «как если бы», которое было введено в C++11, но я не знаю точно, насколько оно сильное и надежное, и поэтому не уверен, могу ли я с уверенностью ожидать, что оно избавится от ненужных действий из стека туда и обратно.
Подробнее здесь:
https://stackoverflow.com/questions/797 ... -rule-in-c