Я думаю, вы неправильно поняли, что делает _m_pmulhw
. На самом деле это очень четко задокументировано в Intel Intrinsics Guide: https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text = _ m_pmulhw & expand = 4340 . Соответствующая инструкция - pmulhw
, которая также четко документирована, например, в руководстве по инструкциям x86 Феликса Клотье: https://www.felixcloutier.com/x86/pmulhw
Она умножает четыре пары 16-битных целых чисел которые упакованы внутри двух операндов, а затем выдают верхнюю половину всех четырех умножений (High Packed Packed Multiply High-Word). Это означает, что для входов 0x12345678abcdef01, 0x9876543210fedcba он умножит 0x1234 * 0x9876
, 0x5678 * 0x5432
, 0xabcd * 0x10fe
, 0xef01 * 0xdcba
и упакует старшие 16 бит каждого результата в вывод.
Для вашего Например, вы умножаете 0xffff * 0xffff
четыре раза, получая 32-битный результат 0x00000001
(-1 * -1
, поскольку это 16-битное умножение со знаком), и, следовательно, получаете 0x0000000000000000
в старшей половине и 0x0001000100010001
в нижней половине - это именно то, что вы видите в выводе bitset
.
Если вы ищете 128-битное умножение, на самом деле нет встроенного c для этого (кроме _mulx_u64
, но при этом используется новая инструкция mulx
, которая не так широко распространена). Microsoft имеет нестандартный _mul128
intrinsi c, но на других платформах вы можете просто использовать тип __int128
(или локальный эквивалент), чтобы получить 64x64 => 128-битное умножение.
Также Я бы настоятельно рекомендовал использовать набор инструкций SSE, а не старый набор MMX; Инструкции SSE в большинстве случаев быстрее и позволяют работать с гораздо более широкими векторными типами (теперь 256-битный стандарт, теперь доступен AVX512), что может обеспечить значительное повышение скорости.