2016-01-29 57 views
4

我想對齊指針p以便p = a (modulo b)。大多數情況下,SIMD對齊時a = 0和b = 32或64,但當我想微調我的算法以獲得緩存關聯性時,我可能也希望a = 64和b = 128。對齊指針

  • std::align不接受任何2的權力爲alignement。這將是固定在C++ 17,但它是無用的,現在
  • __mm_malloc/__free是不那麼容易移植,因爲我想

我最好的解決方案迄今指針轉換爲std::uintptr_t和使用模運算整數來移動指針。不幸的是,它不是可移植的,因爲投擲指針std::uintptr_t不是「允許」的。但它適用於迄今爲止我嘗試過的所有平臺。

這樣的代碼會破壞什麼樣的平臺?

+0

的std ::對齊還不接受2.任何權力它將工作在C++ 17:http://en.cppreference.com/w/cpp/memory/align – InsideLoop

回答

2

可能是你尋找的是這樣的:

inline size_t AlignHi(size_t size, size_t align) 
{ 
    return (size + align - 1) & ~(align - 1); 
} 

inline void * Allocate(size_t size, size_t align) 
{ 
#if defined(_MSC_VER) 
    return _aligned_malloc(size, align); 
#elif defined(__GNUC__) 
    align = AlignHi(align, sizeof(void*)); 
    size = AlignHi(size, align); 
    void * ptr; 
    int result = ::posix_memalign(&ptr, align, size); 
    return result ? NULL : ptr; 
#else 
    return malloc(size); 
#endif 
} 

inline void Free(void * p) 
{ 
#if defined(_MSC_VER) 
    _aligned_free(p); 
#else 
    free(p); 
#endif 
} 
+0

我一直在尋找更「普遍」的東西。但它似乎是目前唯一正確的做法。 – InsideLoop

+0

我從跨平臺SIMD庫中獲取了這些功能。 – Maxim

0

的std ::對齊不接受任意2電源alignement。我將在C++ 17中修復,但現在沒用了。

讓我們來看看標準(草案)所說的。

[ptr.align]

2要求:

(2.1) - 取向應是基本對準值或通過在此上下文中實現支持擴展的取向值。

因此,任何基本的對齊值都是允許的,如果實現允許,也可能有其他值。讓我們看看基本的一致是什麼。

[basic.align]

2甲基本對準由對準小於或等於由在所有上下文中執行,這是等於alignof(支持的最大的對準錶示std :: max_align_t)...

好的。然後對所有路線都有限制。

4對齊被表示爲類型std :: size_t的值。有效對齊僅包括由基本類型的alignof表達式返回的那些值,以及可能爲空的額外的實現定義的值集合。 每個對齊值應該是一個非負整數冪的兩個

所以,不僅是允許2個比對權力,但實際上只 2個比對權力允許的。與C++ 17的不同之處在於,在此之前,只允許小於或等於alignof(std::max_align_t)(即基本對齊)的對齊。支持更大的隊列取決於實施。

TL; DR您的前提是錯誤的。但是否std::align工作,直到C++ 17仍然實現定義。

+0

感謝您的詳細解釋。但是在許多平臺上,alignof(std :: max_align_t)是16。它低於SIMD尺寸:32或64. – InsideLoop

+0

@InsideLoop不夠公平。我猜在C++ 17之前沒有標準的方法來獲得32或64字節的對齊。如果你不介意,我會留下完整的答案。 – user2079303

0

下面的C++代碼要求alignment是分配機智malloc_aligned 2.內存的功率必須free_aligned發佈:

void * 
malloc_aligned(std::size_t alignment, std::size_t size) 
{ 
    alignment = std::max(alignment, alignof(void *)); 
    size  += alignment; 

    void *ptr = std::malloc(size); 
    void *ptr2 = (void *)(((uintptr_t)ptr + alignment) & ~(alignment-1)); 
    void **vp = (void**) ptr2 - 1; 
    *vp  = ptr; 
    return ptr2; 
} 

void 
free_aligned(void *ptr) 
{ 
    std::free(*((void**)ptr-1)); 
}