我是新来使用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 *(或,equivalenty,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 *得到实现,独立的行为

其他的答案提示与操作与设定为低位,并且与零进行比较。

但是,更直接的测试将是做一个MOD与期望的对准值,并比较为零。

#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;

你能只是“和” 0×03与在PTR(4S上对齐),0×07(上787-8对齐)或为0x0F(16S上对齐),以查看是否有任何的最低位被设置?

把这种方式留给专业人员,

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