kernels_aux = r""" // The types of these two will be replaced during compilation by the Spiral code generator. // It matches on `using default_int = ` and `;` with the inner part being replaced so the form should be kept as is. // The two statements need to begin at the start of a line. using default_int = int; using default_uint = unsigned int; #ifndef __NVRTC__ // NVRTC has these includes by default so they need to be left out if it is used as the compiler. #include #include #include #endif // For error checking on the host. #define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); } template inline __device__ void destroy(T& obj) { obj.~T(); } inline void gpuAssert(cudaError error, const char *file, int line, bool abort=true) { if (error != cudaSuccess) { fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(error), file, line); if (abort) exit(error); } } template struct sptr // Shared pointer for the Spiral datatypes. They have to have the refc field inside them to work. { el* base; __device__ sptr() : base(nullptr) {} __device__ sptr(el* ptr) : base(ptr) { this->base->refc++; } __device__ ~sptr() { if (this->base != nullptr && --this->base->refc == 0) { delete this->base; this->base = nullptr; } } __device__ sptr(sptr& x) { this->base = x.base; this->base->refc++; } __device__ sptr(sptr&& x) { this->base = x.base; x.base = nullptr; } __device__ sptr& operator=(sptr& x) { if (this->base != x.base) { delete this->base; this->base = x.base; this->base->refc++; } return *this; } __device__ sptr& operator=(sptr&& x) { if (this->base != x.base) { delete this->base; this->base = x.base; x.base = nullptr; } return *this; } }; template struct csptr : public sptr { // Shared pointer for closures specifically. using sptr::sptr; template __device__ auto operator()(Args... args) -> decltype(this->base->operator()(args...)) { return this->base->operator()(args...); } }; template struct static_array { el ptr[max_length]; __device__ el& operator[](default_int i) { assert("The index has to be in range." && 0 <= i && i < max_length); return this->ptr[i]; } }; template struct static_array_list { default_int length{ 0 }; el ptr[max_length]; __device__ el& operator[](default_int i) { assert("The index has to be in range." && 0 <= i && i < this->length); return this->ptr[i]; } __device__ void push(el& x) { ptr[this->length++] = x; assert("The array after pushing should not be greater than max length." && this->length <= max_length); } __device__ void push(el&& x) { ptr[this->length++] = std::move(x); assert("The array after pushing should not be greater than max length." && this->length <= max_length); } __device__ el pop() { assert("The array before popping should be greater than 0." && 0 < this->length); auto x = ptr[--this->length]; ptr[this->length].~el(); new (&ptr[this->length]) el(); return x; } // Should be used only during initialization. __device__ void unsafe_set_length(default_int i) { assert("The new length should be in range." && 0 <= i && i <= max_length); this->length = i; } }; template struct dynamic_array_base { int refc{ 0 }; el* ptr; __device__ dynamic_array_base() : ptr(new el[max_length]) {} __device__ ~dynamic_array_base() { delete[] this->ptr; } __device__ el& operator[](default_int i) { assert("The index has to be in range." && 0 <= i && i < this->length); return this->ptr[i]; } }; template struct dynamic_array { sptr> ptr; __device__ dynamic_array() = default; __device__ dynamic_array(bool t) : ptr(new dynamic_array_base()) {} __device__ el& operator[](default_int i) { return this->ptr.base->operator[](i); } }; template struct dynamic_array_list_base { int refc{ 0 }; default_int length{ 0 }; el* ptr; __device__ dynamic_array_list_base() : ptr(new el[max_length]) {} __device__ dynamic_array_list_base(default_int l) : ptr(new el[max_length]) { this->unsafe_set_length(l); } __device__ ~dynamic_array_list_base() { delete[] this->ptr; } __device__ el& operator[](default_int i) { assert("The index has to be in range." && 0 <= i && i < this->length); return this->ptr[i]; } __device__ void push(el& x) { ptr[this->length++] = x; assert("The array after pushing should not be greater than max length." && this->length <= max_length); } __device__ void push(el&& x) { ptr[this->length++] = std::move(x); assert("The array after pushing should not be greater than max length." && this->length <= max_length); } __device__ el pop() { assert("The array before popping should be greater than 0." && 0 < this->length); auto x = ptr[--this->length]; ptr[this->length].~el(); new (&ptr[this->length]) el(); return x; } // Should be used only during initialization. __device__ void unsafe_set_length(default_int i) { assert("The new length should be in range." && 0 <= i && i <= max_length); this->length = i; } }; template struct dynamic_array_list { sptr> ptr; __device__ dynamic_array_list() = default; __device__ dynamic_array_list(default_int l) : ptr(new dynamic_array_list_base(l)) {} __device__ el& operator[](default_int i) { return this->ptr.base->operator[](i); } __device__ void push(el& x) { this->ptr.base->push(x); } __device__ void push(el&& x) { this->ptr.base->push(std::move(x)); } __device__ el pop() { return this->ptr.base->pop(); } // Should be used only during initialization. __device__ void unsafe_set_length(default_int i) { this->ptr.base->unsafe_set_length(i); } __device__ default_int length_() { return this->ptr.base->length; } }; """ class static_array(): def __init__(self, length): self.ptr = [] for _ in range(length): self.ptr.append(None) def __getitem__(self, index): assert 0 <= index < len(self.ptr), "The get index needs to be in range." return self.ptr[index] def __setitem__(self, index, value): assert 0 <= index < len(self.ptr), "The set index needs to be in range." self.ptr[index] = value class static_array_list(static_array): def __init__(self, length): super().__init__(length) self.length = 0 def __getitem__(self, index): assert 0 <= index < self.length, "The get index needs to be in range." return self.ptr[index] def __setitem__(self, index, value): assert 0 <= index < self.length, "The set index needs to be in range." self.ptr[index] = value def push(self,value): assert (self.length < len(self.ptr)), "The length before pushing has to be less than the maximum length of the array." self.ptr[self.length] = value self.length += 1 def pop(self): assert (0 < self.length), "The length before popping has to be greater than 0." self.length -= 1 return self.ptr[self.length] def unsafe_set_length(self,i): assert 0 <= i <= len(self.ptr), "The new length has to be in range." self.length = i class dynamic_array(static_array): pass class dynamic_array_list(static_array_list): def length_(self): return self.length