문제

SSE/SSE2 지침으로 코드를 최적화하는 것이 처음이며 지금까지 나는 멀지 않았습니다. 내 아는 바와 같이 일반적인 SSE- 최적화 된 기능은 다음과 같습니다.

void sse_func(const float* const ptr, int len){
    if( ptr is aligned )
    {
        for( ... ){
            // unroll loop by 4 or 2 elements
        }
        for( ....){
            // handle the rest
            // (non-optimized code)
        }
    } else {
        for( ....){
            // regular C code to handle non-aligned memory
        }
    }
}

그러나 메모리가 ptr 포인트는 16 바이트에 의해 정렬됩니까? 이 기능에 전달 된 모든 메모리가 정렬 될 수 없으므로 정렬되지 않은 메모리에 대한 일반 C 코드 경로를 포함해야한다고 생각합니다. 그리고 정렬되지 않은 메모리에서 SSE 레지스터에 데이터를로드하기 위해 고입재를 사용하는 것은 끔찍한 느린 것 같습니다 (일반 C 코드보다 느리게).

미리 감사드립니다 ...

도움이 되었습니까?

해결책

편집 : 캐스팅 long 오늘날 INT와 포인터가 다른 크기 일 가능성에 맞지 않도록 자신을 보호하는 저렴한 방법입니다.

아래 의견에서 지적했듯이 헤더를 기꺼이 포함하려는 경우 더 나은 솔루션이 있습니다 ...

포인터 p 16 바이트 경계 IFF에 정렬됩니다 ((unsigned long)p & 15) == 0.

다른 팁

#define is_aligned(POINTER, BYTE_COUNT) \
    (((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0)

캐스트 void * (또는 동등성, char *) 표준은 반전 전환 만 보장하기 때문에 필요합니다. uintptr_t ~을 위한 void *.

유형 안전을 원한다면 인라인 함수 사용을 고려하십시오.

static inline _Bool is_aligned(const void *restrict pointer, size_t byte_count)
{ return (uintptr_t)pointer % byte_count == 0; }

컴파일러 최적화를 희망합니다 byte_count 컴파일 타임 상수입니다.

왜 우리가 변환해야합니까? void * ?

C 언어는 다른 포인터 유형에 대해 다른 표현을 허용합니다. 예를 들어 64 비트를 가질 수 있습니다. void * 입력 (전체 주소 공간) 및 32 비트 foo * 입력 (세그먼트).

변환 foo * -> void * 예를 들어 오프셋을 추가하는 실제 계산이 포함될 수 있습니다. 또한 표준은 또한 (임의의) 포인터를 정수로 변환 할 때 발생하는 일에도 구현에 이르지만 종종 누프로 구현 된 것으로 생각됩니다.

그러한 구현을 위해 foo * -> uintptr_t -> foo * 효과가 있지만 foo * -> uintptr_t -> void * 그리고 void * -> uintptr_t -> foo * 그렇지 않을 것입니다. 세그먼트 오프셋과 관련하여 정렬 만 확인하기 때문에 정렬 계산도 안정적으로 작동하지 않습니다.

결론적으로 : 항상 사용하십시오 void * 구현 독립적 행동을 얻기 위해.

다른 답변은 낮은 비트 세트로 AN 및 작동을 제안하고 0과 비교합니다.

그러나보다 간단한 테스트는 원하는 정렬 값을 가진 모드를 수행하고 0과 비교하는 것입니다.

#define ALIGNMENT_VALUE     16u

if (((uintptr_t)ptr % ALIGNMENT_VALUE) == 0)
{
    // ptr is aligned
}

기능 템플릿과 같은

#include <type_traits>

template< typename T >
bool is_aligned(T* p){
    return !(reinterpret_cast<uintptr_t>(p) % std::alignment_of<T>::value);
}

다음과 같은 것을 호출하여 런타임시 정렬을 확인할 수 있습니다.

struct foo_type{ int bar; }foo;
assert(is_aligned(&foo)); // passes

잘못된 정렬이 실패하는 것을 확인하려면

// would almost certainly fail
assert(is_aligned((foo_type*)(1 + (uintptr_t)(&foo)));

이것은 기본적으로 내가 사용하는 것입니다. 정수를 템플릿으로 만들면 컴파일 시간이 확장되어 있으므로 내가 무엇을하든 느린 모듈로 작동으로 끝나지 않습니다.

나는 항상 내 입력을 확인하는 것을 좋아하므로 컴파일 타임 어설 션이 있습니다. 정렬 값이 잘못되면 잘 컴파일하지 않습니다 ...

template <unsigned int alignment>
struct IsAligned
{
    static_assert((alignment & (alignment - 1)) == 0, "Alignment must be a power of 2");

    static inline bool Value(const void * ptr)
    {
        return (((uintptr_t)ptr) & (alignment - 1)) == 0;
    }
};

무슨 일이 일어나고 있는지 확인하려면 다음을 사용할 수 있습니다.

// 1 of them is aligned...
int* ptr = new int[8];
for (int i = 0; i < 8; ++i)
    std::cout << IsAligned<32>::Value(ptr + i) << std::endl;

// Should give '1'
int* ptr2 = (int*)_aligned_malloc(32, 32);
std::cout << IsAligned<32>::Value(ptr2) << std::endl;

당신은 단지 '와'0x03 (4S에 정렬), 0x07 (8 초에 정렬) 또는 0x0F (16S에 정렬)를 가진 PTR을 설정하여 가장 낮은 비트가 설정되어 있는지 확인할 수 있습니까?

전문가에게 맡기십시오.

https://www.boost.org/doc/libs/1_65_1/doc/html/align/reference.html#align.reference.functions.is_aligned

bool is_aligned(const void* ptr, std::size_t alignment) noexcept; 

예시:

        char D[1];
        assert( boost::alignment::is_aligned(&D[0], alignof(double)) ); //  might fail, sometimes

어때요 :

void *mem = malloc(1024+15); 
void *ptr =( (*(char*)mem) - (*(char *)mem % 16) );
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top