Nvcc 是一种可简化 CUDA 代码编译过程的编译器驱动程序:它提供了简单、熟悉的命令行选项,通过调用实现不同编译阶段的工具集合来执行它们。
Nvcc 的基本工作流在于将设备代码与主机代码分离开来,并将设备代码编译为二进制形式或 cubin 对象。所生成的主机代码将作为需要使用其他工具编译的 C 代码输出,或通过在最后一个编译阶段中调用主机编译器直接作为对象代码输出。
应用程序可忽略所生成的主机代码,使用 CUDA 驱动程序 API在设备上加载并执行 cubin 对象,也可链接到所生成的主机代码,其中包含 cubin 对象,其形式为全局初始化数据数组,包含将第 4.2.3 节所述执行配置语法转换为必要的 CUDA 运行启动代码的转换,目的在于加载和启动编译后的各内核(参见第 4.5.2 节)。
编译器的前端根据 C++ 语法规则处理 CUDA 源文件。主机代码支持完整的 C++ 语法。但设备代码仅支持 C++ 的 C 子集,类、继承、基本块内的变量声明等 C++ 特殊特性不受支持。由于使用了 C++ 语法规则,因此若未经过强制类型转换,无法将空指针(例如 malloc() 所返回的空指针)指派给非空指针。
关于 nvcc 工作流和命令选项的详细说明将在其他文档中提供。
Nvcc 引入了两个编译器指令,下面几节将加以介绍。
4.2.5.1 noinline
默认情况下,device 函数总是内嵌的。noinline 函数限定符可用于指示编译器尽可能不要内嵌该函数。函数体必须位于所调用的同一个文件内。
如果函数具有指针参数或者具有较大的参数列表,则编译器不会遵从 noinline 限定符。
4.2.5.2 #pragma unroll
默认情况下,编译器将展开具有已知行程计数的小循环。#pragma unroll 指令可用于控制任何给定循环的展开操作。它必须紧接于循环之前,而且仅应用于该循环。可选择在其后接一个数字,指定必须展开多少次循环。
例如,在下面的代码示例中:
#pragma unroll 5
for (int i = 0; i < n; ++i)
循环将展开 5 次。程序员需要负责确保展开操作不会影响程序的正确性(在上面的示例中,如果 n 小于 5,则程序的正确性将受到影响)。
#pragma unroll 1 将阻止编译器展开一个循环。
如果在 #pragma unroll 后未指定任何数据,如果其行程计数为常数,则该循环将完全展开,否则将不会展开。