blob: 727d67e2be60d7c843ec766d01cbc22a2ac1b80f [file] [edit]
// REQUIRES: any-device
// RUN: %clangxx -fsycl %s -o %t.out
// RUN: %t.out
#include <sycl/sycl.hpp>
#include <cassert>
#include <cstddef>
#include <iostream>
#include <tuple>
using namespace sycl;
constexpr size_t Align = 256;
struct alignas(Align) Aligned {
int x;
};
int main() {
queue q;
context ctx = q.get_context();
device d = q.get_device();
auto check = [&q](size_t Alignment, auto AllocFn, int Line = __builtin_LINE(),
int Case = 0) {
// First allocation might naturally be over-aligned. Do several of them to
// do the verification;
decltype(AllocFn()) Arr[10];
for (auto *&Elem : Arr)
Elem = AllocFn();
for (auto *Ptr : Arr) {
auto v = reinterpret_cast<uintptr_t>(Ptr);
if ((v & (Alignment - 1)) != 0) {
std::cout << "Failed at line " << Line << ", case " << Case
<< std::endl;
assert(false && "Not properly aligned!");
break; // To be used with commented out assert above.
}
}
for (auto *Ptr : Arr)
free(Ptr, q);
};
// The strictest (largest) fundamental alignment of any type is the alignment
// of max_align_t. This is, however, smaller than the minimal alignment
// returned by the underlying runtime as of now.
constexpr size_t FAlign = alignof(std::max_align_t);
auto CheckAll = [&](size_t Expected, auto Funcs,
int Line = __builtin_LINE()) {
std::apply(
[&](auto... Fs) {
int Case = 0;
(void)std::initializer_list<int>{
(check(Expected, Fs, Line, Case++), 0)...};
},
Funcs);
};
auto MDevice = [&](auto... args) {
return malloc_device(sizeof(std::max_align_t), args...);
};
CheckAll(FAlign,
std::tuple{[&]() { return MDevice(q); },
[&]() { return MDevice(d, ctx); },
[&]() { return MDevice(q, property_list{}); },
[&]() { return MDevice(d, ctx, property_list{}); }});
auto ADevice = [&](auto... args) {
return aligned_alloc_device(Align, 1024, args...);
};
CheckAll(Align, std::tuple{
[&]() { return ADevice(q); },
[&]() { return ADevice(d, ctx); },
[&]() { return ADevice(q, property_list{}); },
[&]() { return ADevice(d, ctx, property_list{}); },
});
auto MHost = [&](auto... args) {
return malloc_host(sizeof(std::max_align_t), args...);
};
CheckAll(FAlign,
std::tuple{[&]() { return MHost(q); }, [&]() { return MHost(ctx); },
[&]() { return MHost(q, property_list{}); },
[&]() { return MHost(ctx, property_list{}); }});
auto AHost = [&](auto... args) {
return aligned_alloc_host(Align, 1024, args...);
};
CheckAll(Align, std::tuple{
[&]() { return AHost(q); },
[&]() { return AHost(ctx); },
[&]() { return AHost(q, property_list{}); },
[&]() { return AHost(ctx, property_list{}); },
});
if (d.has(aspect::usm_shared_allocations)) {
auto MShared = [&](auto... args) {
return malloc_shared(sizeof(std::max_align_t), args...);
};
CheckAll(FAlign,
std::tuple{[&]() { return MShared(q); },
[&]() { return MShared(d, ctx); },
[&]() { return MShared(q, property_list{}); },
[&]() { return MShared(d, ctx, property_list{}); }});
auto AShared = [&](auto... args) {
return aligned_alloc_shared(Align, 1024, args...);
};
CheckAll(Align, std::tuple{
[&]() { return AShared(q); },
[&]() { return AShared(d, ctx); },
[&]() { return AShared(q, property_list{}); },
[&]() { return AShared(d, ctx, property_list{}); },
});
}
auto TDevice = [&](auto... args) {
return malloc_device<Aligned>(1, args...);
};
CheckAll(Align, std::tuple{[&]() { return TDevice(q); },
[&]() { return TDevice(d, ctx); }});
auto TADevice = [&](auto... args) {
return aligned_alloc_device<Aligned>(Align, 1, args...);
};
CheckAll(Align, std::tuple{[&]() { return TADevice(q); },
[&]() { return TADevice(d, ctx); }});
auto THost = [&](auto... args) { return malloc_host<Aligned>(1, args...); };
CheckAll(Align, std::tuple{[&]() { return THost(q); },
[&]() { return THost(ctx); }});
auto TAHost = [&](auto... args) {
return aligned_alloc_host<Aligned>(Align, 1, args...);
};
CheckAll(Align, std::tuple{[&]() { return TAHost(q); },
[&]() { return TAHost(ctx); }});
if (d.has(aspect::usm_shared_allocations)) {
auto TShared = [&](auto... args) {
return malloc_shared<Aligned>(1, args...);
};
CheckAll(Align, std::tuple{[&]() { return TShared(q); },
[&]() { return TShared(d, ctx); }});
auto TAShared = [&](auto... args) {
return aligned_alloc_shared<Aligned>(Align, 1, args...);
};
CheckAll(Align, std::tuple{[&]() { return TAShared(q); },
[&]() { return TAShared(d, ctx); }});
}
auto Malloc = [&](auto... args) {
return malloc(sizeof(std::max_align_t), args...);
};
CheckAll(
FAlign,
std::tuple{
[&]() { return Malloc(q, usm::alloc::host); },
[&]() { return Malloc(d, ctx, usm::alloc::host); },
[&]() { return Malloc(q, usm::alloc::host, property_list{}); },
[&]() { return Malloc(d, ctx, usm::alloc::host, property_list{}); }});
auto AMalloc = [&](auto... args) {
return aligned_alloc(Align, 1024, args...);
};
CheckAll(
Align,
std::tuple{
[&]() { return AMalloc(q, usm::alloc::host); },
[&]() { return AMalloc(d, ctx, usm::alloc::host); },
[&]() { return AMalloc(q, usm::alloc::host, property_list{}); },
[&]() { return AMalloc(d, ctx, usm::alloc::host, property_list{}); },
});
auto TMalloc = [&](auto... args) { return malloc<Aligned>(1, args...); };
CheckAll(Align,
std::tuple{[&]() { return TMalloc(q, usm::alloc::host); },
[&]() { return TMalloc(d, ctx, usm::alloc::host); }});
auto TAMalloc = [&](auto... args) {
return aligned_alloc<Aligned>(Align, 1, args...);
};
CheckAll(Align,
std::tuple{[&]() { return TAMalloc(q, usm::alloc::host); },
[&]() { return TAMalloc(d, ctx, usm::alloc::host); }});
// Testing invalid arguments for alignment
assert(aligned_alloc_device(3, 1024, q) == nullptr);
assert(aligned_alloc_host(3, 1024, q) == nullptr);
assert(aligned_alloc_shared(3, 1024, q) == nullptr);
// A requested alignment of 0 means "no specific alignment" and must
// succeed, routing through the plain (non-aligned) allocation path.
void *ZeroAlignPtr = aligned_alloc_device(0, 1024, q);
assert(ZeroAlignPtr != nullptr);
free(ZeroAlignPtr, q);
ZeroAlignPtr = aligned_alloc_host(0, 1024, q);
assert(ZeroAlignPtr != nullptr);
free(ZeroAlignPtr, q);
ZeroAlignPtr = aligned_alloc_shared(0, 1024, q);
assert(ZeroAlignPtr != nullptr);
free(ZeroAlignPtr, q);
return 0;
}