1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//! NVPTX 内部函数 (experimental)
//!
//! 这些内部函数构成了 CUDA 编程模型的基础。
//!
//!
//! 引用的是 [CUDA C 编程指南][cuda_c]。
//! 也与 [LLVM NVPTX 后端文档][llvm_docs] 有关。
//!
//! [cuda_c]:
//! http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html
//! [llvm_docs]:
//! https://llvm.org/docs/NVPTXUsage.html

use crate::ffi::c_void;

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.nvvm.barrier0"]
    fn syncthreads() -> ();
    #[link_name = "llvm.nvvm.read.ptx.sreg.ntid.x"]
    fn block_dim_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ntid.y"]
    fn block_dim_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ntid.z"]
    fn block_dim_z() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.x"]
    fn block_idx_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.y"]
    fn block_idx_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.z"]
    fn block_idx_z() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.x"]
    fn grid_dim_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.y"]
    fn grid_dim_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.z"]
    fn grid_dim_z() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.tid.x"]
    fn thread_idx_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.tid.y"]
    fn thread_idx_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.tid.z"]
    fn thread_idx_z() -> i32;
}

/// 同步块中的所有线程。
#[inline]
pub unsafe fn _syncthreads() -> () {
    syncthreads()
}

/// 第 x 个线程块维度。
#[inline]
pub unsafe fn _block_dim_x() -> i32 {
    block_dim_x()
}

/// 第 y 个线程块的维度。
#[inline]
pub unsafe fn _block_dim_y() -> i32 {
    block_dim_y()
}

/// 第 z 个线程块的维度。
#[inline]
pub unsafe fn _block_dim_z() -> i32 {
    block_dim_z()
}

/// 第 x 个线程块索引。
#[inline]
pub unsafe fn _block_idx_x() -> i32 {
    block_idx_x()
}

/// 第 y 个线程块索引。
#[inline]
pub unsafe fn _block_idx_y() -> i32 {
    block_idx_y()
}

/// 第 z 个线程块索引。
#[inline]
pub unsafe fn _block_idx_z() -> i32 {
    block_idx_z()
}

/// 第 x 个块网格尺寸。
#[inline]
pub unsafe fn _grid_dim_x() -> i32 {
    grid_dim_x()
}

/// 第 y 个块网格尺寸。
#[inline]
pub unsafe fn _grid_dim_y() -> i32 {
    grid_dim_y()
}

/// 第 z 个块网格尺寸。
#[inline]
pub unsafe fn _grid_dim_z() -> i32 {
    grid_dim_z()
}

/// 第 x 个线程索引。
#[inline]
pub unsafe fn _thread_idx_x() -> i32 {
    thread_idx_x()
}

/// 第 y 个线程索引。
#[inline]
pub unsafe fn _thread_idx_y() -> i32 {
    thread_idx_y()
}

/// 第 z 个线程索引。
#[inline]
pub unsafe fn _thread_idx_z() -> i32 {
    thread_idx_z()
}

/// 生成陷阱指令 `TRAP`
#[inline]
pub unsafe fn trap() -> ! {
    crate::intrinsics::abort()
}

// 基本的 CUDA syscall 声明。
extern "C" {
    /// 将格式化的输出从内核打印到主机端输出流。
    ///
    /// Syscall 参数:
    /// * `status`: `vprintf` 返回的状态值。
    /// * `format`: 指向格式说明符输入的指针 (使用常见的 `printf` 格式)。
    /// * `valist`: 指向 valist 输入的指针。
    ///
    /// ```
    /// #[repr(C)]
    /// struct PrintArgs(f32, f32, f32, i32);
    ///
    /// vprintf(
    ///     "int(%f + %f) = int(%f) = %d\n".as_ptr(),
    ///     transmute(&PrintArgs(a, b, a + b, (a + b) as i32)),
    /// );
    /// ```
    ///
    /// 资料来源: [编程指南](https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#formatted-output)、[PTX Interoperability](https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability/index.html#system-calls)。
    ///
    ///
    pub fn vprintf(format: *const u8, valist: *const c_void) -> i32;

    /// 从固定大小的堆中动态分配内存。
    ///
    /// CUDA 内核 `malloc()` 函数从设备堆中分配至少 `size` 字节,并返回指向分配的内存的指针; 如果内存不足,无法返回请求,则返回 `NULL`。
    ///
    /// 返回的指针保证与 16 字节边界对齐。
    ///
    /// 给定 CUDA 线程通过 `malloc()` 分配的内存将保持分配给 CUDA 上下文的生命周期,或者直到被调用显式释放到 `free()` 为止。它可以被其他任何 CUDA 线程使用,即使随后的内核启动也可以使用。
    ///
    /// 资料来源: [编程指南](https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#dynamic-global-memory-allocation-and-operations)、[PTX Interoperability](https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability/index.html#system-calls)。
    ///
    ///
    ///
    ///
    ///
    ///
    ///
    // FIXME(denzp): 分配 `malloc` 和 `nothrow` 属性。
    pub fn malloc(size: usize) -> *mut c_void;

    /// 释放以前动态分配的内存。
    ///
    /// CUDA 内核 `free()` 函数将 `ptr` 指向的内存释放,该内存必须由先前的调用返回给 `malloc()`。
    /// 如果 `ptr` 为 NULL,则忽略对 `free()` 的调用。
    ///
    /// 任何 CUDA 线程都可以释放另一个线程分配的内存,但应注意确保同一指针不会被释放超过一次。使用相同的 `ptr` 重复调用 `free()` 具有未定义的行为。
    ///
    /// 资料来源: [编程指南](https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#dynamic-global-memory-allocation-and-operations)、[PTX Interoperability](https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability/index.html#system-calls)。
    ///
    ///
    ///
    ///
    ///
    // FIXME(denzp): 分配 `nothrow` 属性。
    pub fn free(ptr: *mut c_void);

    // syscall 的内部声明。
    // 导出的变体将 `char_size` 参数设置为 `1` (以字节为单位的单个字符大小)。
    fn __assertfail(
        message: *const u8,
        file: *const u8,
        line: u32,
        function: *const u8,
        char_size: usize,
    );
}

/// *assert expression 产生 `false` 值* 时将使用 Syscall。
///
/// Syscall 参数:
/// * `message`: 指向应该输出的字符串的指针。
/// * `file`: 指向与断言关联的文件名字符串的指针。
/// * `line`: 与断言关联的行号。
/// * `function`: 指向与断言关联的函数名称字符串的指针。
///
/// 来源: [PTX 互操作性](https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability/index.html#system-calls)。
///
#[inline]
pub unsafe fn __assert_fail(message: *const u8, file: *const u8, line: u32, function: *const u8) {
    __assertfail(message, file, line, function, 1)
}