2016-04-12 7 views
1

Скажем, у меня есть указатель на память в rsi, и я хотел бы загрузить значение 12-байтного , указанное в нижние 96 бит xmm0. Меня не волнует, что происходит с высокими 32 битами. Каков эффективный способ сделать это?Как загрузить 96 бит из памяти в регистр XMM?

(сторона вопрос: лучшее, что я придумал вовлекает movlpd «Move Low Упакованных двойная точность с плавающей точкой Значения» инструкция Есть ли способ в , которые это инструкция специфична для значений с плавающей точкой. ? Я не понять, что это документировано таким образом,., конечно, он должен работать для целых тоже)

ответ

2

Если нагрузка 16byte не будет переходить на другую страницу и неисправности, а затем использовать movups. Высокие 4 байта будут там, где есть мусор. Причиной промаха в кеше для 4B, о котором вы не заботитесь, может быть проблема, так же как и кэш-линия.

В противном случае используйте movq/pinsrd (SSE4.1) или какой-либо другой способ сделать две нагрузки + перетасовку. movq + pinsrd будет иметь 3 процессора с интегрированным доменом на процессорах Intel SnB, потому что pinsrd не может быть микро-предохранителем. (И для его ALU uop требуется порт для перетасовки (p5)).


Другая возможность: AVX VMASKMOVPS xmm1, xmm2, m128.

Условно двигается упакованные элементы данных из второго операнда источника в соответствующий элемент данных операнда назначения, в зависимости от маски бит, связанных с каждым элементом данных (MSB 1-го операнда SRC).

... Ошибки не будут происходить за счетом ссылки любой ячейки памяти, если соответствующий бит маски для этой ячейки памяти составляет 0.

Intel Haswell: 3 микрооперации слита-домена (один нагрузка и два перетасовки (P5)). 4c, одна на 2 c пропускную способность.

Это, вероятно, не очень хорошее сравнение, особенно. если окружающий код должен перетасоваться.


Ваш очень-редко принимается условный переход, который использует movups в любое время он гарантированно не по вине также 3 слит-домен микрооперации на быстрой дорожке, и один из них может работать на port6 ​​(не конкурирующего с векторных ALU вообще). LEA также не находится на критическом пути.


movlpd безопасен в использовании при любых данных. Он никогда не будет ошибочным или медленным с данными, которые представляют собой NaN с плавающей точкой или что-то в этом роде. Вам нужно только беспокоиться об этом с инструкциями, которые перечислены в руководстве insn ref с непустым «Исключением с плавающей запятой SIMD». например addps может генерировать исключения «Overflow, Underflow, Invalid, Precision, Denormal», но shufps говорит «None».

+0

К сожалению, я не контролирую положение или размеры входного , поэтому я не могу разобраться. «movq» и «pinsrd» - это то, что я тоже придумал; спасибо за подтверждение. – jacobsa

+0

Спасибо также за примечание о 'movlpd'. Но тогда мой вопрос: почему он документирован как применимый к значениям с плавающей запятой, в частности? – jacobsa

+0

@jacobsa: Если вы знаете, что есть читаемая память * до * 12B, которую вы хотите, вы можете загрузить с '[addr-4]', а затем сдвинуть ('psrldq'). Или вы можете даже замаскировать адрес, чтобы получить указатель с 16-кратным выравниванием, который покрывает некоторые нужные вам данные (и по-прежнему не может быть неисправным). –

1

ответ Питер Кордес помог, сделав меня думать о страницах, и я завелся просто проверить, есть ли какой-то шанс, мы бы вина:

// We'd like to perform only a single load from memory, but there's no 96-bit 
// load instruction and it's not necessarily safe to load the full 128 bits 
// since this may read beyond the end of the buffer. 
// 
// However, observe that memory protection applies with granularity of at 
// most 4 KiB (the smallest page size). If the full 16 bytes lies within a 
// single 4 KiB page, then we're fine. If the 12 bytes we are to read 
// straddles a page boundary, then we're also fine (because the next four 
// bytes must lie in the second page, which we're already reading). The only 
// time we're not guaranteed to be okay to read 16 bytes is if the 12 bytes 
// we want to read lie near the end of one page, and some or all of the 
// following four bytes lie within the next page. 
// 
// In other words, the only time there's a risk is when the pointer mod 4096 
// is in the range [4081, 4085). This is <0.1% of addresses. Check for this 
// and handle it specially. 
// 
// We perform the check by adding 15 and then checking for the range [0, 3). 
lea rax, [rsi+15] 
test eax, 0xffc 
jz slow_read 

// Hooray, we can load from memory just once. 
movdqu xmm0, XMMWORD PTR [rsi] 

done_reading: 
[...] 

slow_read: 
movq xmm1, QWORD PTR [rsi] 
pinsrd xmm1, DWORD PTR [rsi+8], 2 
jmp done_reading 
+0

быстрее: 'lea eax, [rsi + 15]'/'test eax, 0xffc' /' jz'. Поскольку вас интересуют только низкие байты, вам не нужны 64-битные регистры, которые сохраняют байты в префиксах REX. Я использовал eax, потому что есть специальная кодировка 'test eax, imm32'. Вы * можете * изменить это, чтобы использовать 'slow_read' для расщеплений в кеш-строке тоже, но вы, вероятно, потеряете гораздо худшее значение в случае неверных прогнозов в отрасли, чем вы бы выиграли. Вы должны проверить это безоговорочно, используя 'movq' /' pinsrd', чтобы убедиться, что это лучше. 'lea' /' fused test-and-branch'/'movups' - 3 uops, то же самое, что' movq'/'pinsrd', но более короткий критический путь. –

+0

Хорошая старая 'lea', как я ее забыл? Благодарю. Мой бенчмарк недостаточно чувствителен, чтобы сказать разницу здесь (или это не узкое место), но ваш патч приятнее. Готово. – jacobsa

+0

'lea EAX, [rsi + 15]' сохраняет еще один байт в кодировке. Размер адреса по умолчанию составляет 64 бит, но размер операнда по умолчанию составляет 32 бит, даже для LEA. Кроме того, странно, что 'movdqu' загружается в другой регистр, чем' movq'/'pinsrd'. (Кроме того, вы можете сохранить байт с помощью «movups». Нет недостатка в использовании загрузок/хранилищ FP, и clang на самом деле делает это иногда. Используйте правильный тип insn для данных для reg-reg-ходов, хотя, поскольку некоторые урче заботиться об этом.) –

 Смежные вопросы

  • Нет связанных вопросов^_^