나는 특별한 유스 케이스를 염두에두고 있지 않다. 나는 이것이 인텔의 intrinsics에서의 설계상의 결함/한계인지 아니면 내가 뭔가를 놓치고 있는지 묻고있다.상위 요소를 초기화하는 명령을 낭비하는 컴파일러없이 스칼라를 벡터에 병합하는 방법은 무엇입니까? 인텔 내장 함수의 디자인 제한?
기존 벡터와 스칼라 플로트를 결합하려는 경우 인텔 고유 내장 함수를 사용하여 높은 요소를 0으로 설정하거나 벡터에 스칼라를 브로드 캐스팅하지 않는 방법이없는 것 같습니다. 나는 GNU C 기본 벡터 확장과 관련된 내장 함수를 조사하지 않았다.
여분의 내장 기능이 최적화되어 있지만 gcc (5.4 또는 6.2)를 사용하지 않는 경우 너무 좋지 않습니다. 관련된 내장 함수가 벡터 args만을 취하는 것과 관련하여 pmovzx
또는 insertps
을로드하는 좋은 방법은 없습니다. (그리고 GCC는 ASM 명령에 scalar-> 벡터 적재 접하지 않는다.)
__m128 replace_lower_two_elements(__m128 v, float x) {
__m128 xv = _mm_set_ss(x); // WANTED: something else for this step, some compilers actually compile this to a separate insn
return _mm_shuffle_ps(v, xv, 0); // lower 2 elements are both x, and the garbage is gone
}
GCC 5.3 -march = 할렘 -03 출력, 즉 인텔 CPU 용 SSE4.1하고 조정할 수 있도록 (그건 SSE4.1 없이는 더욱 악화되고, 상위 요소를 0으로 만드는 여러 명령어).
insertps xmm1, xmm1, 0xe # pointless zeroing of upper elements. shufps only reads the low element of xmm1
shufps xmm0, xmm1, 0 # The function *should* just compile to this.
ret
TL은 : DR : 당신이 실제로 효율적으로이 작업을 수행 할 수있는 경우에이 질문의 나머지는 그냥 물어되고, 그렇지 않으면 왜 안.
그 소리의 셔플 최적화 프로그램은이 권리를 취득, 높은 요소 (_mm_set_ss(x)
를) 영점 조정, 또는 그 (_mm_set1_ps(x)
)에 스칼라를 복제에 대한 지침을 낭비하지 않습니다. 컴파일러가 최적화해야하는 무언가를 작성하는 대신 C에서 "효율적으로"작성하는 방법이 있을까요? 최근의 gcc 조차도을 최적화하지 않기 때문에 실제 (그러나 사소한) 문제입니다. __m256 _mm256_castps128_ps256 (__m128 a)
의 scalar-> 128B 당량이 있다면
이 가능하다. 즉, 상위 요소에 정의되지 않은 가비지가있는
__m128
을 생성하고, 하위 요소의 부동 소수점을 생성하고, 스칼라 float/double이 이미 xmm 레지스터에있는 경우 asm 명령어를 0으로 컴파일합니다.
다음 내장 함수는 없지만이어야합니다.
- 위에서 설명한대로
_mm256_castps128_ps256
의 스칼라 -> __ m128 등가물입니다. 스칼라 - 이미 - 인 - 레지스터 경우에 대한 가장 일반적인 해결책. __m128 _mm_move_ss_scalar (__m128 a, float s)
: 벡터a
의 하위 요소를 스칼라s
으로 바꿉니다. 범용 스칼라 -> __ m128 (이전 글 머리 기호)이있는 경우 실제로는 필요하지 않습니다. (movss
의 reg-reg 양식은 0 인로드 양식과 달리 병합되며 두 경우 모두 상위 요소를 0으로 만드는movd
과 다릅니다. 거짓 종속성이없는 스칼라 부동을 포함하는 레지스터를 복사하려면movaps
을 사용하십시오. 불편한 안전한 방법으로 인해 gcc가 최적화되지 않으므로__m128i _mm_loadzxbd (const uint8_t *four_bytes)
및 기타 크기 PMOVZX/PMOVSX : AFAICT, there's no good safe way to use the PMOVZX intrinsics as a load이 있습니다.__m128 _mm_insertload_ps (__m128 a, float *s, const int imm8)
.INSERTPS은로드와 다르게 동작합니다. imm8의 상위 2 비트는 무시되며 항상 메모리의 벡터에서 요소 대신 실효 주소에서 스칼라를 취합니다. 이렇게하면 매핑되지 않은 페이지 바로 앞에float
이있는 경우 16B로 정렬되지 않은 주소와 함께 작동하고 오류가 없어도 작동합니다.PMOVZX와 마찬가지로 gcc는 INSERT에 대한 메모리 피연산자로
_mm_load_ss()
상위 요소를 폴드하지 못합니다. (imm8의 상위 2 비트가 모두 0이 아니면 으로_mm_insert_ps(xmm0, _mm_load_ss(), imm8)
을 컴파일 할 수 있으며, src 요소가 실제로 MOVSS에 의해 메모리에서 생성 된 0 인 경우 다른 imm8이 vec에 포함됩니다. 실제로
__m128 float_to_vec(float a){ something(a); }
과 같은 인라인 래퍼 함수 뒤에 넣을 수 있습니다.
인텔이 내장 함수를 도입하지 않은 이유가 있습니까? _mm256_castps128_ps256
을 추가하는 것과 동시에 정의되지 않은 상위 요소가있는 float -> __ m128을 추가 할 수있었습니다. 이것은 컴파일러 내부의 문제로 구현하기가 어렵습니까? 특히 ICC 내부? - 64에
주요 호출 규칙 (시스템 V 또는 MS __vectorcall
)는 XMM0에 ARG 제 FP를 가지고 상부 정의 요소, FP XMM0 스칼라 인자들을 반환한다. ABI 문서의 경우 x86 태그 위키를 참조하십시오. 즉, 컴파일러가 알 수없는 상위 요소가있는 레지스터에 스칼라 float/double을 갖는 것은 일반적이지 않습니다. 벡터화 된 내부 루프에서는이 작업이 거의 수행되지 않으므로 이러한 쓸모없는 지시를 피하는 것이 대부분 코드 크기를 약간 줄이는 것이라고 생각합니다.
pmovzx의 경우가 더 심각합니다. 내부 루프에서 사용할 수있는 경우입니다 (예 : VPERMD 셔플 마스크의 LUT의 경우, 캐시 풋 프린트에 4를 저장하는 대신 메모리에 32 비트를 채운 각 인덱스를 저장하는 경우).).
pmovzx로서의 부하 문제는 잠시 동안 지금 날 귀찮게하고 있으며, the original version of this question이 날은 XMM 레지스터에 스칼라 부동 소수점을 사용하는 관련 문제에 대해 생각하고 있어요. 아마도 pmovzx에 대한 유스 케이스가 스칼라 -> __ m128보다 많이 사용됩니다.
:
는한 예 :에
__m128 float_to_vec(float x){ return _mm_set_ss(x); }
은 컴파일합니다. '_mm_load_ * '또는'_mm_set_ *'내장 함수를 사용할 때마다 정말 위조 된 코드를 생성합니다. 여기에있는 질문에 주어진 예제의 경우, 4 가지 이상의 명령 (!)을 얻을 수 있습니다 :'movaps xmm2, xmm1; xorps xmm3, xmm3; movss xmm3, xmm2; shufps xmm0, xmm3, 0'. 나는 기본적으로 그냥 포기했습니다. 기억에 넘치지 않는 어셈블리를 생성 할 수있는 한, 그것을 승리라고 부릅니다. –