VC++ 과 GCC 에서 동작 확인함
using u32 = unsigned int;
#if _MSC_VER
#include <intrin.h>
inline auto __builtin_ctz( const u32 bits )
{
u32 bit = 0;
_BitScanReverse( (unsigned long*)&bit, bits );
return bit;
}
// BSF 와 BSR 어셈블리 명령을 모르는 사람은 검색해 보시라.
// C++ 에서도 BSF 와 BSR 을 쓸 수 있다! ( 인라인 어셈으로 원래 하던 짓이지만 )
#endif
inline auto where_zero_byte( const __m128i* s )
{
const __m128i zero = _mm_set1_epi8( 0 );
// 8bit char 값 0를 128비트 레지스터 ( 16개 ) 에 채움
return _mm_movemask_epi8( _mm_cmpeq_epi8( _mm_loadu_si128( s ), zero ) );
// 128비트 포인터의 값을 불러와( 16바이트로 정렬되지 않아도 됨 ),
// 각 바이트 == 0 ? 0xFF : 0x00 로 채우고
// 인자의 MSB ( 부호비트 ) 를 LSB 부터 차례로 16비트에 채운뒤 남는 앞 16비트는 0으로 채움.
// 한 마디로 MSB 만 차곡차곡 모아서 16비트를 만듦.
}
auto strlen( const char* s )
{
auto* p = (const __m128i*)s;
u32 finder;
while( !( finder = where_zero_byte( p++ ) ) );
return (const char*)p - s - sizeof *p + __builtin_ctz( finder );
}
성능은?
대신 이러면 다른 컴파일러에선 못 씀.
재미 삼아 만들어 보았다.
그만 알아보자.
u16을 사용하지 않는건 왜 그런가요?
ascii 확장 문자열 비교니깐유?
아 저 카운터? 원래 BSF BSR 이 16비트 32비트를 지원하긴 하는데 32비트 연산에선 16비트가 오히려 느려.
그리고 BitScanReverse 라는 VC++ 빌트인 함수가 long* 를 받음요.
기본이 32비트란 소리.
ㅇㅎ 저도 방금 찾아봤는데 _BitScanReverse 이게 32비트군요 기본이
_BitScanReverse64가 64비트용이고
워 64도 있었군.
__builtin_ctzl <- 이게 리눅스용 64비트 함수군유~
어셈에 직접접근하는게 신기하네영
아 직접까지는 아닌가 함수형태니까 암튼 ㄷㄷ
메모리접근횟수가 아무래도 다를듯? 내부적으로
C로 했을땐 이미 불러놨던 메모리라 바로 불러온다지만 이렇게하면 한번 불러놓고 한번에 작업가능하니
그런데 현업에서 이런코드 쓸까요?? 뭔가 혼자서 썻다가 혼날꺼 같은뎅
ㅋㅋ 인라인 어셈으로도 다 되는걸.
아 windows 랑 linux 에서만 쓸꺼면 괜춘.
intel 계열은 거의 다 되긴 할꺼여~
크흠 경험이 부죡행
BSF 랑 BSR 이 워낙 강력해서 이거 인트린직 있음 좋겠다 했더니 정말 있었고. ㅋㅋ 왜 여태 찡찡대며 인라인어셈으로만 썼었지...
솔까말 이것만 있어도 어셈블리 부러울게 반은 사라짐.
나머지 반은요?
ㅋㅋㅋ
XCHG 계열이지 덤으로 ROR, ROL 같은것들.
딴 애들은 레지스터 거쳐야하고 자잘히 몇 클럭 벌어주는 정도라 크진 않은데 BSF 랑 BSR 은 몇 십 클럭 벌어주는거라 쨉이 안되긴 함.
이게 무슨소리야...
저기 작성한 코드가 GCC 의 strlen 함수보다 다섯배 빠르단 이야기야.