CUDA 二进制工具

cuobjdump、nvdisasm、cu++filt 和 nvprune 的应用说明。

1. 概述

本文档介绍了 cuobjdumpnvdisasmcu++filtnvprune,这四个 CUDA 二进制工具,适用于 Linux (x86、ARM 和 P9)、Windows、Mac OS 和 Android。

1.1. 什么是 CUDA 二进制文件?

CUDA 二进制文件(也称为 cubin)文件是一种 ELF 格式的文件,它由 CUDA 可执行代码段以及包含符号、重定位器、调试信息等的其他段组成。默认情况下,CUDA 编译器驱动程序 nvcc 将 cubin 文件嵌入到主机可执行文件中。但是,也可以使用 nvcc 的 “-cubin” 选项单独生成它们。cubin 文件在运行时由 CUDA 驱动程序 API 加载。

注意

有关 cubin 文件或 CUDA 编译轨迹的更多详细信息,请参阅 NVIDIA CUDA 编译器驱动程序 NVCC

1.2. cuobjdumpnvdisasm 之间的区别

CUDA 提供了两个二进制实用程序,用于检查和反汇编 cubin 文件和主机可执行文件:cuobjdumpnvdisasm。基本上,cuobjdump 接受 cubin 文件和主机二进制文件,而 nvdisasm 仅接受 cubin 文件;但 nvdisasm 提供了更丰富的输出选项。

以下是这两个工具的快速比较

表 1. cuobjdumpnvdisasm 的比较

cuobjdump

nvdisasm

反汇编 cubin

从以下输入文件中提取 ptx 并提取和反汇编 cubin

  • 主机二进制文件

    • 可执行文件

    • 目标文件

    • 静态库

  • 外部 fatbinary 文件

控制流分析和输出

高级显示选项

1.3. 命令选项类型和表示法

本文档的本节提供了有关以下工具的命令行选项的常用详细信息

每个命令行选项都有一个长名称和一个短名称,它们可以互换使用。这两种变体通过必须放在选项名称前面的连字符的数量来区分,即长名称必须以两个连字符开头,而短名称必须以单个连字符开头。例如,-I--include-path 的短名称。长选项旨在用于构建脚本,其中选项的大小不如描述性值重要,而短选项旨在用于交互式使用。

上述工具识别三种类型的命令选项:布尔选项、单值选项和列表选项。

布尔选项没有参数,它们要么在命令行上指定,要么不指定。单值选项最多只能指定一次,列表选项可以重复。每种选项类型的示例如下:

Boolean option : nvdisams --print-raw <file>
Single value   : nvdisasm --binary SM70 <file>
List options   : cuobjdump --function "foo,bar,foobar" <file>

单值选项和列表选项必须具有参数,这些参数必须在选项名称后跟一个或多个空格或等号字符。当使用诸如 -I-l-L 之类的单字符短名称时,选项的值也可以紧跟在选项本身之后,而无需用空格或等号字符分隔。列表选项的各个值可以用逗号在选项的单个实例中分隔,或者可以重复该选项,或者可以是这两种情况的任意组合。

因此,对于上述可能取值的两个示例选项,以下表示法是合法的:

-o file
-o=file
-Idir1,dir2 -I=dir3 -I dir4,dir5

对于采用单值的选项,如果多次指定,则命令行中最右边的值将被视为该选项。在下面的示例中,将反汇编 test.bin 二进制文件,并假定架构为 SM75

nvdisasm.exe -b SM70 -b SM75 test.bin
nvdisasm warning : incompatible redefinition for option 'binary', the last value of this option was used

对于采用值列表的选项,如果多次指定,则这些值将附加到列表中。如果指定了重复的值,则会忽略它们。在下面的示例中,函数 foobar 被视为选项 --function 的有效值,并且重复值 foo 被忽略。

cuobjdump --function "foo" --function "bar" --function "foo" -sass  test.cubin

2. cuobjdump

cuobjdump 从 CUDA 二进制文件(独立的和嵌入在主机二进制文件中的)中提取信息,并以人类可读的格式呈现它们。cuobjdump 的输出包括每个内核的 CUDA 汇编代码、CUDA ELF 节头、字符串表、重定位器和其他 CUDA 特定节。它还从主机二进制文件中提取嵌入的 ptx 文本。

有关每个 GPU 架构的 CUDA 汇编指令集列表,请参阅 指令集参考

2.1. 用法

cuobjdump 每次运行时接受单个输入文件。基本用法如下:

cuobjdump [options] <file>

要反汇编独立的 cubin 或嵌入在主机可执行文件中的 cubin,并显示内核的 CUDA 汇编代码,请使用以下命令:

cuobjdump -sass <input file>

要以人类可读的格式从 cubin 文件中转储 cuda elf 节,请使用以下命令:

cuobjdump -elf <cubin file>

要从主机二进制文件中提取 ptx 文本,请使用以下命令:

cuobjdump -ptx <host binary>

以下是 cuobjdump 的示例输出:

$ cuobjdump a.out -sass -ptx
Fatbin elf code:
================
arch = sm_70
code version = [1,7]
producer = cuda
host = linux
compile_size = 64bit
identifier = add.cu

code for sm_70
        Function : _Z3addPiS_S_
.headerflags    @"EF_CUDA_SM70 EF_CUDA_PTX_SM(EF_CUDA_SM70)"
/*0000*/      IMAD.MOV.U32 R1, RZ, RZ, c[0x0][0x28] ;  /* 0x00000a00ff017624 */
                                                       /* 0x000fd000078e00ff */
/*0010*/ @!PT SHFL.IDX PT, RZ, RZ, RZ, RZ ;            /* 0x000000fffffff389 */
                                                       /* 0x000fe200000e00ff */
/*0020*/      IMAD.MOV.U32 R2, RZ, RZ, c[0x0][0x160] ; /* 0x00005800ff027624 */
                                                       /* 0x000fe200078e00ff */
/*0030*/      MOV R3, c[0x0][0x164] ;                  /* 0x0000590000037a02 */
                                                       /* 0x000fe20000000f00 */
/*0040*/      IMAD.MOV.U32 R4, RZ, RZ, c[0x0][0x168] ; /* 0x00005a00ff047624 */
                                                       /* 0x000fe200078e00ff */
/*0050*/      MOV R5, c[0x0][0x16c] ;                  /* 0x00005b0000057a02 */
                                                       /* 0x000fcc0000000f00 */
/*0060*/      LDG.E.SYS R2, [R2] ;                     /* 0x0000000002027381 */
                                                       /* 0x000ea800001ee900 */
/*0070*/      LDG.E.SYS R5, [R4] ;                     /* 0x0000000004057381 */
                                                       /* 0x000ea200001ee900 */
/*0080*/      IMAD.MOV.U32 R6, RZ, RZ, c[0x0][0x170] ; /* 0x00005c00ff067624 */
                                                       /* 0x000fe200078e00ff */
/*0090*/      MOV R7, c[0x0][0x174] ;                  /* 0x00005d0000077a02 */
                                                       /* 0x000fe40000000f00 */
/*00a0*/      IADD3 R9, R2, R5, RZ ;                   /* 0x0000000502097210 */
                                                       /* 0x004fd00007ffe0ff */
/*00b0*/      STG.E.SYS [R6], R9 ;                     /* 0x0000000906007386 */
                                                       /* 0x000fe2000010e900 */
/*00c0*/      EXIT ;                                   /* 0x000000000000794d */
                                                       /* 0x000fea0003800000 */
/*00d0*/      BRA 0xd0;                                /* 0xfffffff000007947 */
                                                       /* 0x000fc0000383ffff */
/*00e0*/      NOP;                                     /* 0x0000000000007918 */
                                                       /* 0x000fc00000000000 */
/*00f0*/      NOP;                                     /* 0x0000000000007918 */
                                                       /* 0x000fc00000000000 */
        .......................
Fatbin ptx code:
================
arch = sm_70
code version = [7,0]
producer = cuda
host = linux
compile_size = 64bit
compressed
identifier = add.cu

.version 7.0
.target sm_70
.address_size 64

.visible .entry _Z3addPiS_S_(
.param .u64 _Z3addPiS_S__param_0,
.param .u64 _Z3addPiS_S__param_1,
.param .u64 _Z3addPiS_S__param_2
)
{
.reg .s32 %r<4>;
.reg .s64 %rd<7>;

ld.param.u64 %rd1, [_Z3addPiS_S__param_0];
ld.param.u64 %rd2, [_Z3addPiS_S__param_1];
ld.param.u64 %rd3, [_Z3addPiS_S__param_2];
cvta.to.global.u64 %rd4, %rd3;
cvta.to.global.u64 %rd5, %rd2;
cvta.to.global.u64 %rd6, %rd1;
ld.global.u32 %r1, [%rd6];
ld.global.u32 %r2, [%rd5];
add.s32 %r3, %r2, %r1;
st.global.u32 [%rd4], %r3;
ret;
}

如输出所示,a.out 主机二进制文件包含用于 sm_70 的 cubin 和 ptx 代码。

要列出主机二进制文件中的 cubin 文件,请使用 -lelf 选项:

$ cuobjdump a.out -lelf
ELF file    1: add_new.sm_70.cubin
ELF file    2: add_new.sm_75.cubin
ELF file    3: add_old.sm_70.cubin
ELF file    4: add_old.sm_75.cubin

要从主机二进制文件中提取所有 cubin 作为文件,请使用 -xelf all 选项:

$ cuobjdump a.out -xelf all
Extracting ELF file    1: add_new.sm_70.cubin
Extracting ELF file    2: add_new.sm_75.cubin
Extracting ELF file    3: add_old.sm_70.cubin
Extracting ELF file    4: add_old.sm_75.cubin

要提取名为 add_new.sm_70.cubin 的 cubin:

$ cuobjdump a.out -xelf add_new.sm_70.cubin
Extracting ELF file    1: add_new.sm_70.cubin

要仅提取名称中包含 _old 的 cubin:

$ cuobjdump a.out -xelf _old
Extracting ELF file    1: add_old.sm_70.cubin
Extracting ELF file    2: add_old.sm_75.cubin

您可以将任何子字符串传递给 -xelf-xptx 选项。只有名称中包含该子字符串的文件才会从输入二进制文件中提取。

要转储通用和每个函数的资源使用信息:

$ cuobjdump test.cubin -res-usage

Resource usage:
 Common:
  GLOBAL:56 CONSTANT[3]:28
 Function calculate:
  REG:24 STACK:8 SHARED:0 LOCAL:0 CONSTANT[0]:472 CONSTANT[2]:24 TEXTURE:0 SURFACE:0 SAMPLER:0
 Function mysurf_func:
  REG:38 STACK:8 SHARED:4 LOCAL:0 CONSTANT[0]:532 TEXTURE:8 SURFACE:7 SAMPLER:0
 Function mytexsampler_func:
  REG:42 STACK:0 SHARED:0 LOCAL:0 CONSTANT[0]:472 TEXTURE:4 SURFACE:0 SAMPLER:1

请注意,REG、TEXTURE、SURFACE 和 SAMPLER 的值表示计数,而其他资源的值表示使用的字节数。

2.2. 命令行选项

表 2 包含 cuobjdump 的受支持命令行选项,以及每个选项的功能描述。每个选项都有一个长名称和一个短名称,可以互换使用。

表 2. cuobjdump 命令行选项

选项(长)

选项(短)

描述

--all-fatbin

-all

转储所有 fatbin 节。默认情况下,仅转储可执行 fatbin 的内容(如果存在),否则如果不存在可执行 fatbin,则转储可重定位 fatbin。

--dump-elf

-elf

转储 ELF 对象节。

--dump-elf-symbols

-symbols

转储 ELF 符号名称。

--dump-ptx

-ptx

转储所有列出的设备函数的 PTX。

--dump-sass

-sass

转储单个 cubin 文件或嵌入在二进制文件中的所有 cubin 文件的 CUDA 汇编代码。

--dump-resource-usage

-res-usage

转储每个 ELF 的资源使用情况。有助于在一个位置获取所有资源使用信息。

--extract-elf <部分文件名>,...

-xelf

提取包含 <部分文件名> 的 ELF 文件,并另存为文件。使用 all 提取所有文件。要获取 ELF 文件列表,请使用 -lelf 选项。适用于主机可执行文件/对象/库和外部 fatbin。所有 dumplist 选项都将使用此选项忽略。

--extract-ptx <部分文件名>,...

-xptx

提取包含 <部分文件名> 的 PTX 文件,并另存为文件。使用 all 提取所有文件。要获取 PTX 文件列表,请使用 -lptx 选项。适用于主机可执行文件/对象/库和外部 fatbin。所有 dumplist 选项都将使用此选项忽略。

--extract-text <部分文件名>,...

-xtext

提取包含 <部分文件名> 的文本二进制编码文件,并另存为文件。使用“all”提取所有文件。要获取文本二进制编码的列表,请使用 -ltext 选项。所有“dump”和“list”选项都将使用此选项忽略。

--function <函数名>,...

-fun

指定必须转储其 fat binary 结构的设备函数的名称。

--function-index <函数索引>,...

-findex

指定必须转储其 fat binary 结构的函数的符号表索引。

--gpu-architecture <GPU 架构名称>

-arch

指定应转储信息的 GPU 架构。此选项的允许值为:sm_50, sm_52, sm_53, sm_60, sm_61, sm_62, sm_70, sm_72, sm_75, sm_80, sm_86, sm_87, sm_89, sm_90, sm_90a, sm_100, sm_100a, sm_120, sm_120a

--help

-h

打印有关此工具的帮助信息。

--list-elf

-lelf

列出 fatbin 中所有可用的 ELF 文件。适用于主机可执行文件/对象/库和外部 fatbin。所有其他选项都将使用此标志忽略。这可以用于稍后使用 -xelf 选项选择特定的 ELF。

--list-ptx

-lptx

列出 fatbin 中所有可用的 PTX 文件。适用于主机可执行文件/对象/库和外部 fatbin。所有其他选项都将使用此标志忽略。这可以用于稍后使用 -xptx 选项选择特定的 PTX。

--list-text

-ltext

列出 fatbin 中所有可用的文本二进制函数名称。所有其他选项都将使用此标志忽略。这可以用于稍后使用 -xtext 选项选择特定的函数。

--options-file <文件>,...

-optf

从指定的文件中包含命令行选项。

--sort-functions

-sort

转储 sass 时对函数进行排序。

--version

-V

打印有关此工具的版本信息。

3. nvdisasm

nvdisasm 从独立的 cubin 文件中提取信息,并以人类可读的格式呈现它们。nvdisasm 的输出包括每个内核的 CUDA 汇编代码、ELF 数据节的列表和其他 CUDA 特定节。输出样式和选项通过 nvdisasm 命令行选项控制。nvdisasm 还执行控制流分析以注释跳转/分支目标,并使输出更易于阅读。

注意

nvdisasm 需要完整的重定位信息才能执行控制流分析。如果 CUDA 二进制文件中缺少此信息,请使用 nvdisasm 选项 -ndf 关闭控制流分析,或使用 ptxasnvlink 选项 -preserve-relocs 重新生成 cubin 文件。

有关每个 GPU 架构的 CUDA 汇编指令集列表,请参阅 指令集参考

3.1. 用法

nvdisasm 每次运行时接受单个输入文件。基本用法如下:

nvdisasm [options] <input cubin file>

以下是 nvdisasm 的示例输出:

    .headerflags    @"EF_CUDA_TEXMODE_UNIFIED EF_CUDA_64BIT_ADDRESS EF_CUDA_SM70
                      EF_CUDA_VIRTUAL_SM(EF_CUDA_SM70)"
    .elftype        @"ET_EXEC"

//--------------------- .nv.info                  --------------------------
    .section        .nv.info,"",@"SHT_CUDA_INFO"
    .align  4

......

//--------------------- .text._Z9acos_main10acosParams --------------------------
    .section    .text._Z9acos_main10acosParams,"ax",@progbits
    .sectioninfo    @"SHI_REGISTERS=14"
    .align    128
        .global     _Z9acos_main10acosParams
        .type       _Z9acos_main10acosParams,@function
        .size       _Z9acos_main10acosParams,(.L_21 - _Z9acos_main10acosParams)
        .other      _Z9acos_main10acosParams,@"STO_CUDA_ENTRY STV_DEFAULT"
_Z9acos_main10acosParams:
.text._Z9acos_main10acosParams:
        /*0000*/               MOV R1, c[0x0][0x28] ;
        /*0010*/               NOP;
        /*0020*/               S2R R0, SR_CTAID.X ;
        /*0030*/               S2R R3, SR_TID.X ;
        /*0040*/               IMAD R0, R0, c[0x0][0x0], R3 ;
        /*0050*/               ISETP.GE.AND P0, PT, R0, c[0x0][0x170], PT ;
        /*0060*/           @P0 EXIT ;
.L_1:
        /*0070*/               MOV R11, 0x4 ;
        /*0080*/               IMAD.WIDE R2, R0, R11, c[0x0][0x160] ;
        /*0090*/               LDG.E.SYS R2, [R2] ;
        /*00a0*/               MOV R7, 0x3d53f941 ;
        /*00b0*/               FADD.FTZ R4, |R2|.reuse, -RZ ;
        /*00c0*/               FSETP.GT.FTZ.AND P0, PT, |R2|.reuse, 0.5699, PT ;
        /*00d0*/               FSETP.GEU.FTZ.AND P1, PT, R2, RZ, PT ;
        /*00e0*/               FADD.FTZ R5, -R4, 1 ;
        /*00f0*/               IMAD.WIDE R2, R0, R11, c[0x0][0x168] ;
        /*0100*/               FMUL.FTZ R5, R5, 0.5 ;
        /*0110*/           @P0 MUFU.SQRT R4, R5 ;
        /*0120*/               MOV R5, c[0x0][0x0] ;
        /*0130*/               IMAD R0, R5, c[0x0][0xc], R0 ;
        /*0140*/               FMUL.FTZ R6, R4, R4 ;
        /*0150*/               FFMA.FTZ R7, R6, R7, 0.018166976049542427063 ;
        /*0160*/               FFMA.FTZ R7, R6, R7, 0.046756859868764877319 ;
        /*0170*/               FFMA.FTZ R7, R6, R7, 0.074846573173999786377 ;
        /*0180*/               FFMA.FTZ R7, R6, R7, 0.16667014360427856445 ;
        /*0190*/               FMUL.FTZ R7, R6, R7 ;
        /*01a0*/               FFMA.FTZ R7, R4, R7, R4 ;
        /*01b0*/               FADD.FTZ R9, R7, R7 ;
        /*01c0*/          @!P0 FADD.FTZ R9, -R7, 1.5707963705062866211 ;
        /*01d0*/               ISETP.GE.AND P0, PT, R0, c[0x0][0x170], PT ;
        /*01e0*/          @!P1 FADD.FTZ R9, -R9, 3.1415927410125732422 ;
        /*01f0*/               STG.E.SYS [R2], R9 ;
        /*0200*/          @!P0 BRA `(.L_1) ;
        /*0210*/               EXIT ;
.L_2:
        /*0220*/               BRA `(.L_2);
.L_21:

要获取内核的控制流图,请使用以下命令:

nvdisasm -cfg <input cubin file>

nvdisasm 能够以 DOT 图形描述语言的格式生成 CUDA 汇编的控制流。nvdisasm 的控制流输出可以直接导入到 DOT 图形可视化工具(如 Graphviz)中。

以下是如何使用 nvdisasm 和 Graphviz 生成上述 cubin (a.cubin) 的控制流 PNG 图像 (cfg.png):

nvdisasm -cfg a.cubin | dot -ocfg.png -Tpng

以下是生成的图形:

Control Flow Graph

控制流图

要使用 nvdisasm 和 Graphviz 生成上述 cubin (a.cubin) 的基本块控制流 PNG 图像 (bbcfg.png):

nvdisasm -bbcfg a.cubin | dot -obbcfg.png -Tpng

以下是生成的图形:

Basic Block Control Flow Graph

基本块控制流图

nvdisasm 能够显示寄存器(通用和谓词)的生命周期范围信息。对于 CUDA 汇编的每一行,nvdisasm 显示给定的设备寄存器是否已分配、访问、处于活动状态或重新分配。它还显示了使用的寄存器总数。如果用户对任何特定寄存器的生命周期范围或一般寄存器使用情况感兴趣,这将非常有用。

以下是示例输出(为简洁起见,输出已修剪):

                                                      // +-----------------+------+
                                                      // |      GPR        | PRED |
                                                      // |                 |      |
                                                      // |                 |      |
                                                      // |    000000000011 |      |
                                                      // |  # 012345678901 | # 01 |
                                                      // +-----------------+------+
    .global acos                                      // |                 |      |
    .type   acos,@function                            // |                 |      |
    .size   acos,(.L_21 - acos)                       // |                 |      |
    .other  acos,@"STO_CUDA_ENTRY STV_DEFAULT"        // |                 |      |
acos:                                                 // |                 |      |
.text.acos:                                           // |                 |      |
    MOV R1, c[0x0][0x28] ;                            // |  1  ^           |      |
    NOP;                                              // |  1  ^           |      |
    S2R R0, SR_CTAID.X ;                              // |  2 ^:           |      |
    S2R R3, SR_TID.X ;                                // |  3 :: ^         |      |
    IMAD R0, R0, c[0x0][0x0], R3 ;                    // |  3 x: v         |      |
    ISETP.GE.AND P0, PT, R0, c[0x0][0x170], PT ;      // |  2 v:           | 1 ^  |
@P0 EXIT ;                                            // |  2 ::           | 1 v  |
.L_1:                                                 // |  2 ::           |      |
     MOV R11, 0x4 ;                                   // |  3 ::         ^ |      |
     IMAD.WIDE R2, R0, R11, c[0x0][0x160] ;           // |  5 v:^^       v |      |
     LDG.E.SYS R2, [R2] ;                             // |  4 ::^        : |      |
     MOV R7, 0x3d53f941 ;                             // |  5 :::    ^   : |      |
     FADD.FTZ R4, |R2|.reuse, -RZ ;                   // |  6 ::v ^  :   : |      |
     FSETP.GT.FTZ.AND P0, PT, |R2|.reuse, 0.5699, PT; // |  6 ::v :  :   : | 1 ^  |
     FSETP.GEU.FTZ.AND P1, PT, R2, RZ, PT ;           // |  6 ::v :  :   : | 2 :^ |
     FADD.FTZ R5, -R4, 1 ;                            // |  6 ::  v^ :   : | 2 :: |
     IMAD.WIDE R2, R0, R11, c[0x0][0x168] ;           // |  8 v:^^:: :   v | 2 :: |
     FMUL.FTZ R5, R5, 0.5 ;                           // |  5 ::  :x :     | 2 :: |
 @P0 MUFU.SQRT R4, R5 ;                               // |  5 ::  ^v :     | 2 v: |
     MOV R5, c[0x0][0x0] ;                            // |  5 ::  :^ :     | 2 :: |
     IMAD R0, R5, c[0x0][0xc], R0 ;                   // |  5 x:  :v :     | 2 :: |
     FMUL.FTZ R6, R4, R4 ;                            // |  5 ::  v ^:     | 2 :: |
     FFMA.FTZ R7, R6, R7, 0.018166976049542427063 ;   // |  5 ::  : vx     | 2 :: |
     FFMA.FTZ R7, R6, R7, 0.046756859868764877319 ;   // |  5 ::  : vx     | 2 :: |
     FFMA.FTZ R7, R6, R7, 0.074846573173999786377 ;   // |  5 ::  : vx     | 2 :: |
     FFMA.FTZ R7, R6, R7, 0.16667014360427856445 ;    // |  5 ::  : vx     | 2 :: |
     FMUL.FTZ R7, R6, R7 ;                            // |  5 ::  : vx     | 2 :: |
     FFMA.FTZ R7, R4, R7, R4 ;                        // |  4 ::  v  x     | 2 :: |
     FADD.FTZ R9, R7, R7 ;                            // |  4 ::     v ^   | 2 :: |
@!P0 FADD.FTZ R9, -R7, 1.5707963705062866211 ;        // |  4 ::     v ^   | 2 v: |
     ISETP.GE.AND P0, PT, R0, c[0x0][0x170], PT ;     // |  3 v:       :   | 2 ^: |
@!P1 FADD.FTZ R9, -R9, 3.1415927410125732422 ;        // |  3 ::       x   | 2 :v |
     STG.E.SYS [R2], R9 ;                             // |  3 ::       v   | 1 :  |
@!P0 BRA `(.L_1) ;                                    // |  2 ::           | 1 v  |
     EXIT ;                                           // |  1  :           |      |
.L_2:                                                 // +.................+......+
     BRA `(.L_2);                                     // |                 |      |
.L_21:                                                // +-----------------+------+
                                                      // Legend:
                                                      //     ^       : Register assignment
                                                      //     v       : Register usage
                                                      //     x       : Register usage and reassignment
                                                      //     :       : Register in use
                                                      //     <space> : Register not in use
                                                      //     #       : Number of occupied registers

nvdisasm 能够显示 CUDA 源文件的行号信息,这对于调试非常有用。

要获取内核的行信息,请使用以下命令:

nvdisasm -g <input cubin file>

以下是使用 nvdisasm -g 命令的内核的示例输出:

//--------------------- .text._Z6kernali          --------------------------
        .section        .text._Z6kernali,"ax",@progbits
        .sectioninfo    @"SHI_REGISTERS=24"
        .align  128
        .global         _Z6kernali
        .type           _Z6kernali,@function
        .size           _Z6kernali,(.L_4 - _Z6kernali)
        .other          _Z6kernali,@"STO_CUDA_ENTRY STV_DEFAULT"
_Z6kernali:
.text._Z6kernali:
        /*0000*/                   MOV R1, c[0x0][0x28] ;
        /*0010*/                   NOP;
    //## File "/home/user/cuda/sample/sample.cu", line 25
        /*0020*/                   MOV R0, 0x160 ;
        /*0030*/                   LDC R0, c[0x0][R0] ;
        /*0040*/                   MOV R0, R0 ;
        /*0050*/                   MOV R2, R0 ;
    //## File "/home/user/cuda/sample/sample.cu", line 26
        /*0060*/                   MOV R4, R2 ;
        /*0070*/                   MOV R20, 32@lo((_Z6kernali + .L_1@srel)) ;
        /*0080*/                   MOV R21, 32@hi((_Z6kernali + .L_1@srel)) ;
        /*0090*/                   CALL.ABS.NOINC `(_Z3fooi) ;
.L_1:
        /*00a0*/                   MOV R0, R4 ;
        /*00b0*/                   MOV R4, R2 ;
        /*00c0*/                   MOV R2, R0 ;
        /*00d0*/                   MOV R20, 32@lo((_Z6kernali + .L_2@srel)) ;
        /*00e0*/                   MOV R21, 32@hi((_Z6kernali + .L_2@srel)) ;
        /*00f0*/                   CALL.ABS.NOINC `(_Z3bari) ;
.L_2:
        /*0100*/                   MOV R4, R4 ;
        /*0110*/                   IADD3 R4, R2, R4, RZ ;
        /*0120*/                   MOV R2, 32@lo(arr) ;
        /*0130*/                   MOV R3, 32@hi(arr) ;
        /*0140*/                   MOV R2, R2 ;
        /*0150*/                   MOV R3, R3 ;
        /*0160*/                   ST.E.SYS [R2], R4 ;
    //## File "/home/user/cuda/sample/sample.cu", line 27
        /*0170*/                   ERRBAR ;
        /*0180*/                   EXIT ;
.L_3:
        /*0190*/                   BRA `(.L_3);
.L_4:

nvdisasm 能够显示带有附加函数内联信息的行号信息(如果有)。在没有任何函数内联的情况下,输出与使用 nvdisasm -g 命令的输出相同。

以下是使用 nvdisasm -gi 命令的内核的示例输出:

//--------------------- .text._Z6kernali          --------------------------
    .section    .text._Z6kernali,"ax",@progbits
    .sectioninfo    @"SHI_REGISTERS=16"
    .align    128
        .global         _Z6kernali
        .type           _Z6kernali,@function
        .size           _Z6kernali,(.L_18 - _Z6kernali)
        .other          _Z6kernali,@"STO_CUDA_ENTRY STV_DEFAULT"
_Z6kernali:
.text._Z6kernali:
        /*0000*/                   IMAD.MOV.U32 R1, RZ, RZ, c[0x0][0x28] ;
    //## File "/home/user/cuda/inline.cu", line 17 inlined at "/home/user/cuda/inline.cu", line 23
    //## File "/home/user/cuda/inline.cu", line 23
        /*0010*/                   UMOV UR4, 32@lo(arr) ;
        /*0020*/                   UMOV UR5, 32@hi(arr) ;
        /*0030*/                   IMAD.U32 R2, RZ, RZ, UR4 ;
        /*0040*/                   MOV R3, UR5 ;
        /*0050*/                   ULDC.64 UR4, c[0x0][0x118] ;
    //## File "/home/user/cuda/inline.cu", line 10 inlined at "/home/user/cuda/inline.cu", line 17
    //## File "/home/user/cuda/inline.cu", line 17 inlined at "/home/user/cuda/inline.cu", line 23
    //## File "/home/user/cuda/inline.cu", line 23
        /*0060*/                   LDG.E R4, [R2.64] ;
        /*0070*/                   LDG.E R5, [R2.64+0x4] ;
    //## File "/home/user/cuda/inline.cu", line 17 inlined at "/home/user/cuda/inline.cu", line 23
    //## File "/home/user/cuda/inline.cu", line 23
        /*0080*/                   LDG.E R0, [R2.64+0x8] ;
    //## File "/home/user/cuda/inline.cu", line 23
        /*0090*/                   UMOV UR6, 32@lo(ans) ;
        /*00a0*/                   UMOV UR7, 32@hi(ans) ;
    //## File "/home/user/cuda/inline.cu", line 10 inlined at "/home/user/cuda/inline.cu", line 17
    //## File "/home/user/cuda/inline.cu", line 17 inlined at "/home/user/cuda/inline.cu", line 23
    //## File "/home/user/cuda/inline.cu", line 23
        /*00b0*/                   IADD3 R7, R4, c[0x0][0x160], RZ ;
    //## File "/home/user/cuda/inline.cu", line 23
        /*00c0*/                   IMAD.U32 R4, RZ, RZ, UR6 ;
    //## File "/home/user/cuda/inline.cu", line 10 inlined at "/home/user/cuda/inline.cu", line 17
    //## File "/home/user/cuda/inline.cu", line 17 inlined at "/home/user/cuda/inline.cu", line 23
    //## File "/home/user/cuda/inline.cu", line 23
        /*00d0*/                   IADD3 R9, R5, c[0x0][0x160], RZ ;
    //## File "/home/user/cuda/inline.cu", line 23
        /*00e0*/                   MOV R5, UR7 ;
    //## File "/home/user/cuda/inline.cu", line 10 inlined at "/home/user/cuda/inline.cu", line 17
    //## File "/home/user/cuda/inline.cu", line 17 inlined at "/home/user/cuda/inline.cu", line 23
    //## File "/home/user/cuda/inline.cu", line 23
        /*00f0*/                   IADD3 R11, R0.reuse, c[0x0][0x160], RZ ;
    //## File "/home/user/cuda/inline.cu", line 17 inlined at "/home/user/cuda/inline.cu", line 23
    //## File "/home/user/cuda/inline.cu", line 23
        /*0100*/                   IMAD.IADD R13, R0, 0x1, R7 ;
    //## File "/home/user/cuda/inline.cu", line 10 inlined at "/home/user/cuda/inline.cu", line 17
    //## File "/home/user/cuda/inline.cu", line 17 inlined at "/home/user/cuda/inline.cu", line 23
    //## File "/home/user/cuda/inline.cu", line 23
        /*0110*/                   STG.E [R2.64+0x4], R9 ;
        /*0120*/                   STG.E [R2.64], R7 ;
        /*0130*/                   STG.E [R2.64+0x8], R11 ;
    //## File "/home/user/cuda/inline.cu", line 23
        /*0140*/                   STG.E [R4.64], R13 ;
    //## File "/home/user/cuda/inline.cu", line 24
        /*0150*/                   EXIT ;
.L_3:
        /*0160*/                   BRA (.L_3);
.L_18:

nvdisasm 可以生成 JSON 格式的反汇编。

有关 JSON 格式的详细信息,请参阅附录

要获取 JSON 格式的反汇编,请使用以下命令:

nvdisasm -json <input cubin file>

nvdisasm -json 的输出将采用最小化格式。下面的示例是美化后的示例:

[
    {
        "ELF": {
            "layout-id": 4,
            "ei_osabi": 51,
            "ei_abiversion": 7
        },
        "SM": {
            "version": {
                "major": 9,
                "minor": 0
            }
        },
        "SchemaVersion": {
            "major": 12,
            "minor": 8,
            "revision": 0
        },
        "Producer": "nvdisasm V12.8.14 Build r570_00.r12.8/compiler.35033008_0",
        "Description": ""
    },
    [
        {
            "function-name": "foo",
            "start": 0,
            "length": 96,
            "other-attributes": [],
            "sass-instructions": [
                {
                    "opcode": "LDC",
                    "operands": "R1,c[0x0][0x28]"
                },
                {
                    "opcode": "MOV",
                    "operands": "R6,0x60"
                },
                {
                    "opcode": "ISETP.NE.U32.AND",
                    "operands": "P0,PT,R1,0x1,PT"
                },
                {
                    "opcode": "CALL.REL.NOINC",
                    "operands": "`(bar)",
                    "other-attributes": {
                        "control-flow": "True"
                    }
                },
                {
                    "opcode": "MOV",
                    "operands": "R8,R7"
                },
                {
                    "opcode": "EXIT",
                    "other-attributes": {
                        "control-flow": "True"
                    }
                }
            ]
        },
        {
            "function-name": "bar",
            "start": 96,
            "length": 32,
            "other-attributes": [],
            "sass-instructions": [
                {
                    "opcode": "STS.128",
                    "operands": "[UR5+0x400],RZ"
                },
                {
                    "opcode": "RET.REL.NODEC",
                    "operands": "R18,`(foo)",
                    "other-attributes": {
                        "control-flow": "True"
                    }
                }
            ]
        }
    ]
]

3.2. 命令行选项

表 3 包含 nvdisasm 的受支持命令行选项,以及每个选项的功能描述。每个选项都有一个长名称和一个短名称,可以互换使用。

表 3. nvdisasm 命令行选项

选项(长)

选项(短)

描述

--base-address <值>

-base

指定要反汇编的映像的逻辑基地址。此选项仅在反汇编原始指令二进制文件时有效(请参阅选项 --binary),并且在反汇编 Elf 文件时将被忽略。默认值:0。

--binary <SMxy>

-b

指定此选项后,假定输入文件包含原始指令二进制文件,即指令内存中出现的二进制指令编码序列。此选项的值必须是原始二进制文件的断言架构。此选项的允许值为:SM50, SM52, SM53, SM60, SM61, SM62, SM70, SM72, SM75, SM80, SM86, SM87, SM89, SM90, SM90a, SM100, SM100a, SM100, SM100a, SM120, SM120a

--cuda-function-index <符号索引>,...

-fun

将输出限制为由具有给定索引的符号表示的 CUDA 函数。给定符号的 CUDA 函数是封闭节。这仅限制可执行节;所有其他节仍将被打印。

--emit-json

-json

以 JSON 格式打印反汇编。这可以与选项 --binary <SMxy>--cuda-function-index <符号索引>,... 一起使用。有关 JSON 格式的详细信息,请参阅附录。但是,这与选项 --print-life-ranges--life-range-mode--output-control-flow-graph--output-control-flow-graph-with-basic-blocks 不兼容。

--help

-h

打印有关此工具的帮助信息。

--life-range-mode

-lrm

此选项隐含选项 --print-life-ranges,并确定应如何打印寄存器生命周期范围信息。count:完全不打印,仅保留 # 列(活动寄存器的数量);wide:列间隔开以提高可读性(默认);narrow:每个寄存器一个字符列,节省表格宽度。此选项的允许值为:countnarrowwide

--no-dataflow

-ndf

禁用反汇编后的数据流分析。通常启用数据流分析以执行分支堆栈分析,并使用推断的分支目标标签注释所有通过 GPU 分支堆栈跳转的指令。但是,当不满足输入 nvelf/cubin 的某些限制时,它有时可能会失败。

--no-vliw

-novliw

常规模式;以正常语法而不是 VLIW 语法反汇编配对的指令。

--options-file <文件>,...

-optf

从指定的文件中包含命令行选项。

--output-control-flow-graph

-cfg

指定时,输出控制流图,其中每个节点都是一个超块,格式可供 graphviz 工具(如 dot)使用。

--output-control-flow-graph-with-basic-blocks

-bbcfg

指定时,输出控制流图,其中每个节点都是一个基本块,格式可供 graphviz 工具(如 dot)使用。

--print-code

-c

仅打印代码节。

--print-instr-offsets-cfg

-poff

指定时,在控制流图中打印指令偏移量。这应与选项 --output-control-flow-graph--output-control-flow-graph-with-basic-blocks 一起使用。

--print-instruction-encoding

-hex

指定时,在每个反汇编操作后打印编码字节。

--print-life-ranges

-plr

在生成的反汇编的尾随列中打印寄存器生命周期范围信息。

--print-line-info

-g

如果存在,则使用从 .debug_line 节获取的源行信息注释反汇编。

--print-line-info-inline

-gi

如果存在,则使用从 .debug_line 节获取的源行信息以及函数内联信息注释反汇编。

--print-line-info-ptx

-gp

如果存在,则使用从 .nv_debug_line_sass 节获取的源行信息注释反汇编。

--print-raw

-raw

打印反汇编,而不尝试美化它。

--separate-functions

-sf

用一些换行符分隔与函数符号对应的代码,以使其在打印的反汇编中突出显示。

--version

-V

打印有关此工具的版本信息。

4. 指令集参考

本节包含 NVIDIA® GPU 架构的指令集参考。

4.1. Maxwell 和 Pascal 指令集

Maxwell(计算能力 5.x)和 Pascal(计算能力 6.x)架构具有以下指令集格式:

(instruction) (destination) (source1), (source2) ...

有效的目标和源位置包括:

  • RX 用于寄存器

  • SRX 用于特殊系统控制寄存器

  • PX 用于条件寄存器

  • c[X][Y] 用于常量内存

表 4 列出了 Maxwell 和 Pascal GPU 的有效指令。

表 4. Maxwell 和 Pascal 指令集

操作码

描述

浮点指令

FADD

FP32 加法

FCHK

单精度 FP 除法范围检查

FCMP

FP32 与零比较并选择源

FFMA

FP32 融合乘加

FMNMX

FP32 最小值/最大值

FMUL

FP32 乘法

FSET

FP32 比较和设置

FSETP

FP32 比较和设置谓词

FSWZADD

用于 FSWZ 仿真的 FP32 加法

MUFU

多功能操作

RRO

范围缩减运算符 FP

DADD

FP64 加法

DFMA

FP64 融合乘加

DMNMX

FP64 最小值/最大值

DMUL

FP64 乘法

DSET

FP64 比较和设置

DSETP

FP64 比较和设置谓词

HADD2

FP16 加法

HFMA2

FP16 融合乘加

HMUL2

FP16 乘法

HSET2

FP16 比较和设置

HSETP2

FP16 比较和设置谓词

整数指令

BFE

位字段提取

BFI

位字段插入

FLO

查找前导 1

IADD

整数加法

IADD3

3 输入整数加法

ICMP

整数与零比较并选择源

IMAD

整数乘加

IMADSP

提取的整数乘加。

IMNMX

整数最小值/最大值

IMUL

整数乘法

ISCADD

缩放整数加法

ISET

整数比较和设置

ISETP

整数比较和设置谓词

LEA

计算有效地址

LOP

逻辑运算

LOP3

3 输入逻辑运算

POPC

人口计数

SHF

漏斗移位

SHL

左移

SHR

右移

XMAD

整数短乘加

转换指令

F2F

浮点到浮点转换

F2I

浮点到整数转换

I2F

整数到浮点转换

I2I

整数到整数转换

移动指令

MOV

移动

PRMT

置换寄存器对

SEL

使用谓词选择源

SHFL

Warp 宽度寄存器 Shuffle

谓词/CC 指令

CSET

测试条件代码和设置

CSETP

测试条件代码和设置谓词

PSET

组合谓词和设置

PSETP

组合谓词和设置谓词

P2R

将谓词寄存器移动到寄存器

R2P

将寄存器移动到谓词/CC寄存器

纹理指令

TEX

纹理Fetch

TLD

纹理加载

TLD4

纹理加载 4

TXQ

纹理查询

TEXS

纹理Fetch,带标量/非vec4源/目标

TLD4S

纹理加载 4,带标量/非vec4源/目标

TLDS

纹理加载,带标量/非vec4源/目标

计算加载/存储指令

LD

从通用内存加载

LDC

加载常量

LDG

从全局内存加载

LDL

在本地内存窗口内加载

LDS

本地共享内存窗口内

ST

存储到通用内存

STG

存储到全局内存

STL

存储到本地内存

STS

存储到共享内存

ATOM

通用内存上的原子操作

ATOMS

共享内存上的原子操作

RED

通用内存上的归约操作

CCTL

缓存控制

CCTLL

缓存控制

MEMBAR

内存屏障

CCTLT

纹理缓存控制

表面内存指令

SUATOM

表面内存上的原子操作

SULD

表面加载

SURED

表面内存上的归约操作

SUST

表面存储

控制指令

BRA

相对分支

BRX

相对分支间接

JMP

绝对跳转

JMX

绝对跳转间接

SSY

设置同步点

SYNC

条件分支后收敛线程

CAL

相对调用

JCAL

绝对调用

PRET

从子程序预返回

RET

从子程序返回

BRK

中断

PBK

预中断

CONT

继续

PCNT

预继续

EXIT

退出程序

PEXIT

预退出

BPT

断点/陷阱

杂项指令

NOP

空操作

CS2R

将特殊寄存器移动到寄存器

S2R

将特殊寄存器移动到寄存器

B2R

将屏障移动到寄存器

BAR

屏障同步

R2B

将寄存器移动到屏障

VOTE

跨SIMD线程组投票

4.2. Volta 指令集

Volta 架构(计算能力 7.0 和 7.2)具有以下指令集格式

(instruction) (destination) (source1), (source2) ...

有效的目标和源位置包括:

  • RX 用于寄存器

  • SRX 用于特殊系统控制寄存器

  • 用于谓词寄存器的 PX

  • c[X][Y] 用于常量内存

表 5 列出了 Volta GPU 的有效指令。

表 5. Volta 指令集

操作码

描述

浮点指令

FADD

FP32 加法

FADD32I

FP32 加法

FCHK

浮点范围检查

FFMA32I

FP32 融合乘加

FFMA

FP32 融合乘加

FMNMX

FP32 最小值/最大值

FMUL

FP32 乘法

FMUL32I

FP32 乘法

FSEL

浮点选择

FSET

FP32 比较和设置

FSETP

FP32 比较和设置谓词

FSWZADD

FP32 混洗加法

MUFU

FP32 多功能操作

HADD2

FP16 加法

HADD2_32I

FP16 加法

HFMA2

FP16 融合乘加

HFMA2_32I

FP16 融合乘加

HMMA

矩阵乘法和累加

HMUL2

FP16 乘法

HMUL2_32I

FP16 乘法

HSET2

FP16 比较和设置

HSETP2

FP16 比较和设置谓词

DADD

FP64 加法

DFMA

FP64 融合乘加

DMUL

FP64 乘法

DSETP

FP64 比较和设置谓词

整数指令

BMSK

位域掩码

BREV

位反转

FLO

查找前导 1

IABS

整数绝对值

IADD

整数加法

IADD3

3 输入整数加法

IADD32I

整数加法

IDP

整数点积和累加

IDP4A

整数点积和累加

IMAD

整数乘加

IMMA

整数矩阵乘法和累加

IMNMX

整数最小值/最大值

IMUL

整数乘法

IMUL32I

整数乘法

ISCADD

缩放整数加法

ISCADD32I

缩放整数加法

ISETP

整数比较和设置谓词

LEA

加载有效地址

LOP

逻辑运算

LOP3

逻辑运算

LOP32I

逻辑运算

POPC

人口计数

SHF

漏斗移位

SHL

左移

SHR

右移

VABSDIFF

绝对差

VABSDIFF4

绝对差

转换指令

F2F

浮点到浮点转换

F2I

浮点到整数转换

I2F

整数到浮点转换

I2I

整数到整数转换

I2IP

整数到整数转换和打包

FRND

舍入为整数

移动指令

MOV

移动

MOV32I

移动

PRMT

置换寄存器对

SEL

使用谓词选择源

SGXT

符号扩展

SHFL

Warp 宽度寄存器 Shuffle

谓词指令

PLOP3

谓词逻辑运算

PSETP

组合谓词和设置谓词

P2R

将谓词寄存器移动到寄存器

R2P

将寄存器移动到谓词寄存器

加载/存储指令

LD

从通用内存加载

LDC

加载常量

LDG

从全局内存加载

LDL

在本地内存窗口内加载

LDS

在共享内存窗口内加载

ST

存储到通用内存

STG

存储到全局内存

STL

存储到本地内存

STS

存储到共享内存

MATCH

跨线程组匹配寄存器值

QSPC

查询空间

ATOM

通用内存上的原子操作

ATOMS

共享内存上的原子操作

ATOMG

全局内存上的原子操作

RED

通用内存上的归约操作

CCTL

缓存控制

CCTLL

缓存控制

ERRBAR

错误屏障

MEMBAR

内存屏障

CCTLT

纹理缓存控制

纹理指令

TEX

纹理Fetch

TLD

纹理加载

TLD4

纹理加载 4

TMML

纹理mipmap层级

TXD

带导数的纹理Fetch

TXQ

纹理查询

表面指令

SUATOM

表面内存上的原子操作

SULD

表面加载

SURED

表面内存上的归约操作

SUST

表面存储

控制指令

BMOV

移动收敛屏障状态

BPT

断点/陷阱

BRA

相对分支

BREAK

跳出指定的收敛屏障

BRX

相对分支间接

BSSY

屏障设置收敛同步点

BSYNC

在收敛屏障上同步线程

CALL

调用函数

EXIT

退出程序

JMP

绝对跳转

JMX

绝对跳转间接

KILL

终止线程

NANOSLEEP

暂停执行

RET

从子程序返回

RPCMOV

PC 寄存器移动

RTT

从陷阱返回

WARPSYNC

同步 Warp 中的线程

YIELD

Yield 控制

杂项指令

B2R

将屏障移动到寄存器

BAR

屏障同步

CS2R

将特殊寄存器移动到寄存器

DEPBAR

依赖屏障

GETLMEMBASE

获取本地内存基地址

LEPC

加载有效 PC

NOP

空操作

PMTRIG

性能监视器触发器

R2B

将寄存器移动到屏障

S2R

将特殊寄存器移动到寄存器

SETCTAID

设置 CTA ID

SETLMEMBASE

设置本地内存基地址

VOTE

跨SIMD线程组投票

4.3. Turing 指令集

Turing 架构(计算能力 7.5)具有以下指令集格式

(instruction) (destination) (source1), (source2) ...

有效的目标和源位置包括:

  • RX 用于寄存器

  • 用于统一寄存器的 URX

  • SRX 用于特殊系统控制寄存器

  • 用于谓词寄存器的 PX

  • c[X][Y] 用于常量内存

表 6 列出了 Turing GPU 的有效指令。

表 6. Turing 指令集

操作码

描述

浮点指令

FADD

FP32 加法

FADD32I

FP32 加法

FCHK

浮点范围检查

FFMA32I

FP32 融合乘加

FFMA

FP32 融合乘加

FMNMX

FP32 最小值/最大值

FMUL

FP32 乘法

FMUL32I

FP32 乘法

FSEL

浮点选择

FSET

FP32 比较和设置

FSETP

FP32 比较和设置谓词

FSWZADD

FP32 混洗加法

MUFU

FP32 多功能操作

HADD2

FP16 加法

HADD2_32I

FP16 加法

HFMA2

FP16 融合乘加

HFMA2_32I

FP16 融合乘加

HMMA

矩阵乘法和累加

HMUL2

FP16 乘法

HMUL2_32I

FP16 乘法

HSET2

FP16 比较和设置

HSETP2

FP16 比较和设置谓词

DADD

FP64 加法

DFMA

FP64 融合乘加

DMUL

FP64 乘法

DSETP

FP64 比较和设置谓词

整数指令

BMMA

位矩阵乘法和累加

BMSK

位域掩码

BREV

位反转

FLO

查找前导 1

IABS

整数绝对值

IADD

整数加法

IADD3

3 输入整数加法

IADD32I

整数加法

IDP

整数点积和累加

IDP4A

整数点积和累加

IMAD

整数乘加

IMMA

整数矩阵乘法和累加

IMNMX

整数最小值/最大值

IMUL

整数乘法

IMUL32I

整数乘法

ISCADD

缩放整数加法

ISCADD32I

缩放整数加法

ISETP

整数比较和设置谓词

LEA

加载有效地址

LOP

逻辑运算

LOP3

逻辑运算

LOP32I

逻辑运算

POPC

人口计数

SHF

漏斗移位

SHL

左移

SHR

右移

VABSDIFF

绝对差

VABSDIFF4

绝对差

转换指令

F2F

浮点到浮点转换

F2I

浮点到整数转换

I2F

整数到浮点转换

I2I

整数到整数转换

I2IP

整数到整数转换和打包

FRND

舍入为整数

移动指令

MOV

移动

MOV32I

移动

MOVM

带转置或扩展的移动矩阵

PRMT

置换寄存器对

SEL

使用谓词选择源

SGXT

符号扩展

SHFL

Warp 宽度寄存器 Shuffle

谓词指令

PLOP3

谓词逻辑运算

PSETP

组合谓词和设置谓词

P2R

将谓词寄存器移动到寄存器

R2P

将寄存器移动到谓词寄存器

加载/存储指令

LD

从通用内存加载

LDC

加载常量

LDG

从全局内存加载

LDL

在本地内存窗口内加载

LDS

在共享内存窗口内加载

LDSM

从共享内存加载矩阵,带元素大小扩展

ST

存储到通用内存

STG

存储到全局内存

STL

存储到本地内存

STS

存储到共享内存

MATCH

跨线程组匹配寄存器值

QSPC

查询空间

ATOM

通用内存上的原子操作

ATOMS

共享内存上的原子操作

ATOMG

全局内存上的原子操作

RED

通用内存上的归约操作

CCTL

缓存控制

CCTLL

缓存控制

ERRBAR

错误屏障

MEMBAR

内存屏障

CCTLT

纹理缓存控制

统一数据路径指令

R2UR

从向量寄存器移动到统一寄存器

S2UR

将特殊寄存器移动到统一寄存器

UBMSK

统一位域掩码

UBREV

统一位反转

UCLEA

加载常量的有效地址

UFLO

统一查找前导一

UIADD3

统一整数加法

UIADD3.64

统一整数加法

UIMAD

统一整数乘法

UISETP

整数比较和设置统一谓词

ULDC

从常量内存加载到统一寄存器

ULEA

统一加载有效地址

ULOP

逻辑运算

ULOP3

逻辑运算

ULOP32I

逻辑运算

UMOV

统一移动

UP2UR

统一谓词到统一寄存器

UPLOP3

统一谓词逻辑运算

UPOPC

统一人口计数

UPRMT

统一字节置换

UPSETP

统一谓词逻辑运算

UR2UP

统一寄存器到统一谓词

USEL

统一选择

USGXT

统一符号扩展

USHF

统一漏斗移位

USHL

统一左移

USHR

统一右移

VOTEU

跨 SIMD 线程组投票,结果在统一目标中

纹理指令

TEX

纹理Fetch

TLD

纹理加载

TLD4

纹理加载 4

TMML

纹理mipmap层级

TXD

带导数的纹理Fetch

TXQ

纹理查询

表面指令

SUATOM

表面内存上的原子操作

SULD

表面加载

SURED

表面内存上的归约操作

SUST

表面存储

控制指令

BMOV

移动收敛屏障状态

BPT

断点/陷阱

BRA

相对分支

BREAK

跳出指定的收敛屏障

BRX

相对分支间接

BRXU

相对分支,带基于统一寄存器的偏移量

BSSY

屏障设置收敛同步点

BSYNC

在收敛屏障上同步线程

CALL

调用函数

EXIT

退出程序

JMP

绝对跳转

JMX

绝对跳转间接

JMXU

绝对跳转,带基于统一寄存器的偏移量

KILL

终止线程

NANOSLEEP

暂停执行

RET

从子程序返回

RPCMOV

PC 寄存器移动

RTT

从陷阱返回

WARPSYNC

同步 Warp 中的线程

YIELD

Yield 控制

杂项指令

B2R

将屏障移动到寄存器

BAR

屏障同步

CS2R

将特殊寄存器移动到寄存器

DEPBAR

依赖屏障

GETLMEMBASE

获取本地内存基地址

LEPC

加载有效 PC

NOP

空操作

PMTRIG

性能监视器触发器

R2B

将寄存器移动到屏障

S2R

将特殊寄存器移动到寄存器

SETCTAID

设置 CTA ID

SETLMEMBASE

设置本地内存基地址

VOTE

跨SIMD线程组投票

4.4. NVIDIA Ampere GPU 和 Ada 指令集

NVIDIA Ampere GPU 和 Ada 架构(计算能力 8.0 和 8.6)具有以下指令集格式

(instruction) (destination) (source1), (source2) ...

有效的目标和源位置包括:

  • RX 用于寄存器

  • 用于统一寄存器的 URX

  • SRX 用于特殊系统控制寄存器

  • 用于谓词寄存器的 PX

  • 用于统一谓词寄存器的 UPX

  • c[X][Y] 用于常量内存

表 7 列出了 NVIDIA Ampere 架构和 Ada GPU 的有效指令。

表 7. NVIDIA Ampere GPU 和 Ada 指令集

操作码

描述

浮点指令

FADD

FP32 加法

FADD32I

FP32 加法

FCHK

浮点范围检查

FFMA32I

FP32 融合乘加

FFMA

FP32 融合乘加

FMNMX

FP32 最小值/最大值

FMUL

FP32 乘法

FMUL32I

FP32 乘法

FSEL

浮点选择

FSET

FP32 比较和设置

FSETP

FP32 比较和设置谓词

FSWZADD

FP32 混洗加法

MUFU

FP32 多功能操作

HADD2

FP16 加法

HADD2_32I

FP16 加法

HFMA2

FP16 融合乘加

HFMA2_32I

FP16 融合乘加

HMMA

矩阵乘法和累加

HMNMX2

FP16 最小值/最大值

HMUL2

FP16 乘法

HMUL2_32I

FP16 乘法

HSET2

FP16 比较和设置

HSETP2

FP16 比较和设置谓词

DADD

FP64 加法

DFMA

FP64 融合乘加

DMMA

矩阵乘法和累加

DMUL

FP64 乘法

DSETP

FP64 比较和设置谓词

整数指令

BMMA

位矩阵乘法和累加

BMSK

位域掩码

BREV

位反转

FLO

查找前导 1

IABS

整数绝对值

IADD

整数加法

IADD3

3 输入整数加法

IADD32I

整数加法

IDP

整数点积和累加

IDP4A

整数点积和累加

IMAD

整数乘加

IMMA

整数矩阵乘法和累加

IMNMX

整数最小值/最大值

IMUL

整数乘法

IMUL32I

整数乘法

ISCADD

缩放整数加法

ISCADD32I

缩放整数加法

ISETP

整数比较和设置谓词

LEA

加载有效地址

LOP

逻辑运算

LOP3

逻辑运算

LOP32I

逻辑运算

POPC

人口计数

SHF

漏斗移位

SHL

左移

SHR

右移

VABSDIFF

绝对差

VABSDIFF4

绝对差

转换指令

F2F

浮点到浮点转换

F2I

浮点到整数转换

I2F

整数到浮点转换

I2I

整数到整数转换

I2IP

整数到整数转换和打包

I2FP

整数到 FP32 转换和打包

F2IP

FP32 向下转换为整数并打包

FRND

舍入为整数

移动指令

MOV

移动

MOV32I

移动

MOVM

带转置或扩展的移动矩阵

PRMT

置换寄存器对

SEL

使用谓词选择源

SGXT

符号扩展

SHFL

Warp 宽度寄存器 Shuffle

谓词指令

PLOP3

谓词逻辑运算

PSETP

组合谓词和设置谓词

P2R

将谓词寄存器移动到寄存器

R2P

将寄存器移动到谓词寄存器

加载/存储指令

LD

从通用内存加载

LDC

加载常量

LDG

从全局内存加载

LDGDEPBAR

全局加载依赖屏障

LDGSTS

异步全局到共享内存复制

LDL

在本地内存窗口内加载

LDS

在共享内存窗口内加载

LDSM

从共享内存加载矩阵,带元素大小扩展

ST

存储到通用内存

STG

存储到全局内存

STL

存储到本地内存

STS

存储到共享内存

MATCH

跨线程组匹配寄存器值

QSPC

查询空间

ATOM

通用内存上的原子操作

ATOMS

共享内存上的原子操作

ATOMG

全局内存上的原子操作

RED

通用内存上的归约操作

CCTL

缓存控制

CCTLL

缓存控制

ERRBAR

错误屏障

MEMBAR

内存屏障

CCTLT

纹理缓存控制

统一数据路径指令

R2UR

从向量寄存器移动到统一寄存器

REDUX

将向量寄存器归约到统一寄存器

S2UR

将特殊寄存器移动到统一寄存器

UBMSK

统一位域掩码

UBREV

统一位反转

UCLEA

加载常量的有效地址

UF2FP

统一 FP32 向下转换和打包

UFLO

统一查找前导一

UIADD3

统一整数加法

UIADD3.64

统一整数加法

UIMAD

统一整数乘法

UISETP

整数比较和设置统一谓词

ULDC

从常量内存加载到统一寄存器

ULEA

统一加载有效地址

ULOP

逻辑运算

ULOP3

逻辑运算

ULOP32I

逻辑运算

UMOV

统一移动

UP2UR

统一谓词到统一寄存器

UPLOP3

统一谓词逻辑运算

UPOPC

统一人口计数

UPRMT

统一字节置换

UPSETP

统一谓词逻辑运算

UR2UP

统一寄存器到统一谓词

USEL

统一选择

USGXT

统一符号扩展

USHF

统一漏斗移位

USHL

统一左移

USHR

统一右移

VOTEU

跨 SIMD 线程组投票,结果在统一目标中

纹理指令

TEX

纹理Fetch

TLD

纹理加载

TLD4

纹理加载 4

TMML

纹理mipmap层级

TXD

带导数的纹理Fetch

TXQ

纹理查询

表面指令

SUATOM

表面内存上的原子操作

SULD

表面加载

SURED

表面内存上的归约操作

SUST

表面存储

控制指令

BMOV

移动收敛屏障状态

BPT

断点/陷阱

BRA

相对分支

BREAK

跳出指定的收敛屏障

BRX

相对分支间接

BRXU

相对分支,带基于统一寄存器的偏移量

BSSY

屏障设置收敛同步点

BSYNC

在收敛屏障上同步线程

CALL

调用函数

EXIT

退出程序

JMP

绝对跳转

JMX

绝对跳转间接

JMXU

绝对跳转,带基于统一寄存器的偏移量

KILL

终止线程

NANOSLEEP

暂停执行

RET

从子程序返回

RPCMOV

PC 寄存器移动

WARPSYNC

同步 Warp 中的线程

YIELD

Yield 控制

杂项指令

B2R

将屏障移动到寄存器

BAR

屏障同步

CS2R

将特殊寄存器移动到寄存器

DEPBAR

依赖屏障

GETLMEMBASE

获取本地内存基地址

LEPC

加载有效 PC

NOP

空操作

PMTRIG

性能监视器触发器

S2R

将特殊寄存器移动到寄存器

SETCTAID

设置 CTA ID

SETLMEMBASE

设置本地内存基地址

VOTE

跨SIMD线程组投票

4.5. Hopper 指令集

Hopper 架构(计算能力 9.0)具有以下指令集格式

(instruction) (destination) (source1), (source2) ...

有效的目标和源位置包括:

  • RX 用于寄存器

  • 用于统一寄存器的 URX

  • SRX 用于特殊系统控制寄存器

  • 用于谓词寄存器的 PX

  • 用于统一谓词寄存器的 UPX

  • c[X][Y] 用于常量内存

  • 用于内存描述符的 desc[URX][RY]

  • 用于全局内存描述符的 gdesc[URX]

表 8 列出了 Hopper GPU 的有效指令。

表 8. Hopper 指令集

操作码

描述

浮点指令

FADD

FP32 加法

FADD32I

FP32 加法

FCHK

浮点范围检查

FFMA32I

FP32 融合乘加

FFMA

FP32 融合乘加

FMNMX

FP32 最小值/最大值

FMUL

FP32 乘法

FMUL32I

FP32 乘法

FSEL

浮点选择

FSET

FP32 比较和设置

FSETP

FP32 比较和设置谓词

FSWZADD

FP32 混洗加法

MUFU

FP32 多功能操作

HADD2

FP16 加法

HADD2_32I

FP16 加法

HFMA2

FP16 融合乘加

HFMA2_32I

FP16 融合乘加

HMMA

矩阵乘法和累加

HMNMX2

FP16 最小值/最大值

HMUL2

FP16 乘法

HMUL2_32I

FP16 乘法

HSET2

FP16 比较和设置

HSETP2

FP16 比较和设置谓词

DADD

FP64 加法

DFMA

FP64 融合乘加

DMMA

矩阵乘法和累加

DMUL

FP64 乘法

DSETP

FP64 比较和设置谓词

整数指令

BMMA

位矩阵乘法和累加

BMSK

位域掩码

BREV

位反转

FLO

查找前导 1

IABS

整数绝对值

IADD

整数加法

IADD3

3 输入整数加法

IADD32I

整数加法

IDP

整数点积和累加

IDP4A

整数点积和累加

IMAD

整数乘加

IMMA

整数矩阵乘法和累加

IMNMX

整数最小值/最大值

IMUL

整数乘法

IMUL32I

整数乘法

ISCADD

缩放整数加法

ISCADD32I

缩放整数加法

ISETP

整数比较和设置谓词

LEA

加载有效地址

LOP

逻辑运算

LOP3

逻辑运算

LOP32I

逻辑运算

POPC

人口计数

SHF

漏斗移位

SHL

左移

SHR

右移

VABSDIFF

绝对差

VABSDIFF4

绝对差

VHMNMX

SIMD FP16 3 输入最小值/最大值

VIADD

SIMD 整数加法

VIADDMNMX

SIMD 整数加法和融合的最小值/最大值比较

VIMNMX

SIMD 整数最小值/最大值

VIMNMX3

SIMD 整数 3 输入最小值/最大值

转换指令

F2F

浮点到浮点转换

F2I

浮点到整数转换

I2F

整数到浮点转换

I2I

整数到整数转换

I2IP

整数到整数转换和打包

I2FP

整数到 FP32 转换和打包

F2IP

FP32 向下转换为整数并打包

FRND

舍入为整数

移动指令

MOV

移动

MOV32I

移动

MOVM

带转置或扩展的移动矩阵

PRMT

置换寄存器对

SEL

使用谓词选择源

SGXT

符号扩展

SHFL

Warp 宽度寄存器 Shuffle

谓词指令

PLOP3

谓词逻辑运算

PSETP

组合谓词和设置谓词

P2R

将谓词寄存器移动到寄存器

R2P

将寄存器移动到谓词寄存器

加载/存储指令

FENCE

共享或全局内存的内存可见性保证

LD

从通用内存加载

LDC

加载常量

LDG

从全局内存加载

LDGDEPBAR

全局加载依赖屏障

LDGMC

减少加载

LDGSTS

异步全局到共享内存复制

LDL

在本地内存窗口内加载

LDS

在共享内存窗口内加载

LDSM

从共享内存加载矩阵,带元素大小扩展

STSM

将矩阵存储到共享内存

ST

存储到通用内存

STG

存储到全局内存

STL

存储到本地内存

STS

存储到共享内存

STAS

异步存储到分布式共享内存,带显式同步

SYNCS

同步单元

MATCH

跨线程组匹配寄存器值

QSPC

查询空间

ATOM

通用内存上的原子操作

ATOMS

共享内存上的原子操作

ATOMG

全局内存上的原子操作

REDAS

分布式共享内存上的异步归约,带显式同步

REDG

通用内存上的归约操作

CCTL

缓存控制

CCTLL

缓存控制

ERRBAR

错误屏障

MEMBAR

内存屏障

CCTLT

纹理缓存控制

统一数据路径指令

R2UR

从向量寄存器移动到统一寄存器

REDUX

将向量寄存器归约到统一寄存器

S2UR

将特殊寄存器移动到统一寄存器

UBMSK

统一位域掩码

UBREV

统一位反转

UCGABAR_ARV

CGA 屏障同步

UCGABAR_WAIT

CGA 屏障同步

UCLEA

加载常量的有效地址

UF2FP

统一 FP32 向下转换和打包

UFLO

统一查找前导一

UIADD3

统一整数加法

UIADD3.64

统一整数加法

UIMAD

统一整数乘法

UISETP

整数比较和设置统一谓词

ULDC

从常量内存加载到统一寄存器

ULEA

统一加载有效地址

ULEPC

统一加载有效 PC

ULOP

逻辑运算

ULOP3

逻辑运算

ULOP32I

逻辑运算

UMOV

统一移动

UP2UR

统一谓词到统一寄存器

UPLOP3

统一谓词逻辑运算

UPOPC

统一人口计数

UPRMT

统一字节置换

UPSETP

统一谓词逻辑运算

UR2UP

统一寄存器到统一谓词

USEL

统一选择

USETMAXREG

释放、取消分配和分配寄存器

USGXT

统一符号扩展

USHF

统一漏斗移位

USHL

统一左移

USHR

统一右移

VOTEU

跨 SIMD 线程组投票,结果在统一目标中

Warpgroup 指令

BGMMA

跨 Warp 的位矩阵乘法和累加

HGMMA

跨 Warpgroup 的矩阵乘法和累加

IGMMA

跨 Warpgroup 的整数矩阵乘法和累加

QGMMA

跨 Warpgroup 的 FP8 矩阵乘法和累加

WARPGROUP

Warpgroup 同步

WARPGROUPSET

设置 Warpgroup 计数器

张量内存访问指令

UBLKCP

批量数据复制

UBLKPF

批量数据预取

UBLKRED

从共享内存批量数据复制,带归约

UTMACCTL

TMA 缓存控制

UTMACMDFLUSH

TMA 命令刷新

UTMALDG

从全局到共享内存的张量加载

UTMAPF

张量预取

UTMAREDG

从共享到全局内存的张量存储,带归约

UTMASTG

从共享到全局内存的张量存储

纹理指令

TEX

纹理Fetch

TLD

纹理加载

TLD4

纹理加载 4

TMML

纹理mipmap层级

TXD

带导数的纹理Fetch

TXQ

纹理查询

表面指令

SUATOM

表面内存上的原子操作

SULD

表面加载

SURED

表面内存上的归约操作

SUST

表面存储

控制指令

ACQBULK

等待批量释放状态 Warp 状态

BMOV

移动收敛屏障状态

BPT

断点/陷阱

BRA

相对分支

BREAK

跳出指定的收敛屏障

BRX

相对分支间接

BRXU

相对分支,带基于统一寄存器的偏移量

BSSY

屏障设置收敛同步点

BSYNC

在收敛屏障上同步线程

CALL

调用函数

CGAERRBAR

CGA 错误屏障

ELECT

选出一个 Leader 线程

ENDCOLLECTIVE

重置 MCOLLECTIVE 掩码

EXIT

退出程序

JMP

绝对跳转

JMX

绝对跳转间接

JMXU

绝对跳转,带基于统一寄存器的偏移量

KILL

终止线程

NANOSLEEP

暂停执行

PREEXIT

依赖任务启动提示

RET

从子程序返回

RPCMOV

PC 寄存器移动

WARPSYNC

同步 Warp 中的线程

YIELD

Yield 控制

杂项指令

B2R

将屏障移动到寄存器

BAR

屏障同步

CS2R

将特殊寄存器移动到寄存器

DEPBAR

依赖屏障

GETLMEMBASE

获取本地内存基地址

LEPC

加载有效 PC

NOP

空操作

PMTRIG

性能监视器触发器

S2R

将特殊寄存器移动到寄存器

SETCTAID

设置 CTA ID

SETLMEMBASE

设置本地内存基地址

VOTE

跨 SIMT 线程组投票

4.6. Blackwell 指令集

Blackwell 架构(计算能力 10.0 和 12.0)具有以下指令集格式

(instruction) (destination) (source1), (source2) ...

有效的目标和源位置包括:

  • RX 用于寄存器

  • 用于统一寄存器的 URX

  • SRX 用于特殊系统控制寄存器

  • 用于谓词寄存器的 PX

  • 用于统一谓词寄存器的 UPX

  • c[X][Y] 用于常量内存

  • 用于内存描述符的 desc[URX][RY]

  • 用于全局内存描述符的 gdesc[URX]

  • 用于张量内存的 tmem[URX]

表 8 列出了 Blackwell GPU 的有效指令。

表 8. Blackwell 指令集

操作码

描述

浮点指令

FADD

FP32 加法

FADD2

FP32 加法

FADD32I

FP32 加法

FCHK

浮点范围检查

FFMA32I

FP32 融合乘加

FFMA

FP32 融合乘加

FFMA2

FP32 融合乘加

FHADD

FP32 加法

FHFMA

FP32 融合乘加

FMNMX

FP32 最小值/最大值

FMNMX3

3 输入浮点最小值/最大值

FMUL

FP32 乘法

FMUL2

FP32 乘法

FMUL32I

FP32 乘法

FSEL

浮点选择

FSET

FP32 比较和设置

FSETP

FP32 比较和设置谓词

FSWZADD

FP32 混洗加法

MUFU

FP32 多功能操作

HADD2

FP16 加法

HADD2_32I

FP16 加法

HFMA2

FP16 融合乘加

HFMA2_32I

FP16 融合乘加

HMMA

矩阵乘法和累加

HMNMX2

FP16 最小值/最大值

HMUL2

FP16 乘法

HMUL2_32I

FP16 乘法

HSET2

FP16 比较和设置

HSETP2

FP16 比较和设置谓词

DADD

FP64 加法

DFMA

FP64 融合乘加

DMMA

矩阵乘法和累加

DMUL

FP64 乘法

DSETP

FP64 比较和设置谓词

OMMA

跨 Warp 的 FP4 矩阵乘法和累加

QMMA

跨 Warp 的 FP8 矩阵乘法和累加

整数指令

BMSK

位域掩码

BREV

位反转

FLO

查找前导 1

IABS

整数绝对值

IADD

整数加法

IADD3

3 输入整数加法

IADD32I

整数加法

IDP

整数点积和累加

IDP4A

整数点积和累加

IMAD

整数乘加

IMMA

整数矩阵乘法和累加

IMNMX

整数最小值/最大值

IMUL

整数乘法

IMUL32I

整数乘法

ISCADD

缩放整数加法

ISCADD32I

缩放整数加法

ISETP

整数比较和设置谓词

LEA

加载有效地址

LOP

逻辑运算

LOP3

逻辑运算

LOP32I

逻辑运算

POPC

人口计数

SHF

漏斗移位

SHL

左移

SHR

右移

VABSDIFF

绝对差

VABSDIFF4

绝对差

VHMNMX

SIMD FP16 3 输入最小值/最大值

VIADD

SIMD 整数加法

VIADDMNMX

SIMD 整数加法和融合的最小值/最大值比较

VIMNMX

SIMD 整数最小值/最大值

VIMNMX3

SIMD 整数 3 输入最小值/最大值

转换指令

F2F

浮点到浮点转换

F2I

浮点到整数转换

I2F

整数到浮点转换

I2I

整数到整数转换

I2IP

整数到整数转换和打包

I2FP

整数到 FP32 转换和打包

F2IP

FP32 向下转换为整数并打包

FRND

舍入为整数

移动指令

MOV

移动

MOV32I

移动

MOVM

带转置或扩展的移动矩阵

PRMT

置换寄存器对

SEL

使用谓词选择源

SGXT

符号扩展

SHFL

Warp 宽度寄存器 Shuffle

谓词指令

PLOP3

谓词逻辑运算

PSETP

组合谓词和设置谓词

P2R

将谓词寄存器移动到寄存器

R2P

将寄存器移动到谓词寄存器

加载/存储指令

FENCE

共享或全局内存的内存可见性保证

LD

从通用内存加载

LDC

加载常量

LDG

从全局内存加载

LDGDEPBAR

全局加载依赖屏障

LDGMC

减少加载

LDGSTS

异步全局到共享内存复制

LDL

在本地内存窗口内加载

LDS

在共享内存窗口内加载

LDSM

从共享内存加载矩阵,带元素大小扩展

STSM

将矩阵存储到共享内存

ST

存储到通用内存

STG

存储到全局内存

STL

存储到本地内存

STS

存储到共享内存

STAS

异步存储到分布式共享内存,带显式同步

SYNCS

同步单元

MATCH

跨线程组匹配寄存器值

QSPC

查询空间

ATOM

通用内存上的原子操作

ATOMS

共享内存上的原子操作

ATOMG

全局内存上的原子操作

REDAS

分布式共享内存上的异步归约,带显式同步

REDG

通用内存上的归约操作

CCTL

缓存控制

CCTLL

缓存控制

ERRBAR

错误屏障

MEMBAR

内存屏障

CCTLT

纹理缓存控制

统一数据路径指令

CREDUX

耦合的向量寄存器归约到统一寄存器

CS2UR

从常量内存加载值到统一寄存器

LDCU

从常量内存加载值到统一寄存器

R2UR

从向量寄存器移动到统一寄存器

REDUX

将向量寄存器归约到统一寄存器

S2UR

将特殊寄存器移动到统一寄存器

UBMSK

统一位域掩码

UBREV

统一位反转

UCGABAR_ARV

CGA 屏障同步

UCGABAR_WAIT

CGA 屏障同步

UCLEA

加载常量的有效地址

UFADD

统一统一 FP32 加法

UF2F

统一浮点到浮点转换

UF2FP

统一 FP32 向下转换和打包

UF2I

统一浮点到整数转换

UF2IP

统一 FP32 向下转换为整数并打包

UFFMA

统一 FP32 融合乘加

UFLO

统一查找前导一

UFMNMX

统一浮点最小值/最大值

UFMUL

统一 FP32 乘法

UFRND

统一舍入为整数

UFSEL

统一浮点选择

UFSET

统一浮点比较和设置

UFSETP

统一浮点比较和设置谓词

UI2F

统一整数到浮点转换

UI2FP

统一整数到 FP32 转换和打包

UI2I

统一饱和整数到整数转换

UI2IP

统一双饱和整数到整数转换和打包

UIABS

统一整数绝对值

UIMNMX

统一整数最小值/最大值

UIADD3

统一整数加法

UIADD3.64

统一整数加法

UIMAD

统一整数乘法

UISETP

统一整数比较和设置统一谓词

ULEA

统一加载有效地址

ULEPC

统一加载有效 PC

ULOP

统一逻辑运算

ULOP3

统一逻辑运算

ULOP32I

统一逻辑运算

UMOV

统一移动

UP2UR

统一谓词到统一寄存器

UPLOP3

统一谓词逻辑运算

UPOPC

统一人口计数

UPRMT

统一字节置换

UPSETP

统一谓词逻辑运算

UR2UP

统一寄存器到统一谓词

USEL

统一选择

USETMAXREG

释放、取消分配和分配寄存器

USGXT

统一符号扩展

USHF

统一漏斗移位

USHL

统一左移

USHR

统一右移

UGETNEXTWORKID

统一获取下一个工作 ID

UMEMSETS

初始化共享内存

UREDGR

统一全局内存归约,带释放

USTGR

统一存储到全局内存,带释放

UVIADD

统一 SIMD 整数加法

UVIMNMX

统一 SIMD 整数最小值/最大值

UVIRTCOUNT

虚拟资源管理

VOTEU

跨 SIMD 线程组投票,结果在统一目标中

张量内存访问指令

UBLKCP

批量数据复制

UBLKPF

批量数据预取

UBLKRED

从共享内存批量数据复制,带归约

UTMACCTL

TMA 缓存控制

UTMACMDFLUSH

TMA 命令刷新

UTMALDG

从全局到共享内存的张量加载

UTMAPF

张量预取

UTMAREDG

从共享到全局内存的张量存储,带归约

UTMASTG

从共享到全局内存的张量存储

张量核心内存指令

LDT

从张量内存加载矩阵到寄存器文件

LDTM

从张量内存加载矩阵到寄存器文件

STT

从寄存器文件将矩阵存储到张量内存

STTM

从寄存器文件将矩阵存储到张量内存

UTCATOMSWS

在 SW 状态寄存器上执行原子操作

UTCBAR

张量核心屏障

UTCCP

从共享内存到张量内存的异步数据复制

UTCHMMA

统一矩阵乘法和累加

UTCIMMA

统一矩阵乘法和累加

UTCOMMA

统一矩阵乘法和累加

UTCQMMA

统一矩阵乘法和累加

UTCSHIFT

在张量内存中移动元素

纹理指令

TEX

纹理Fetch

TLD

纹理加载

TLD4

纹理加载 4

TMML

纹理mipmap层级

TXD

带导数的纹理Fetch

TXQ

纹理查询

表面指令

SUATOM

表面内存上的原子操作

SULD

表面加载

SURED

表面内存上的归约操作

SUST

表面存储

控制指令

ACQBULK

等待批量释放状态 Warp 状态

ACQSHMINIT

等待共享内存初始化释放状态 Warp 状态

BMOV

移动收敛屏障状态

BPT

断点/陷阱

BRA

相对分支

BREAK

跳出指定的收敛屏障

BRX

相对分支间接

BRXU

相对分支,带基于统一寄存器的偏移量

BSSY

屏障设置收敛同步点

BSYNC

在收敛屏障上同步线程

CALL

调用函数

CGAERRBAR

CGA 错误屏障

ELECT

选出一个 Leader 线程

ENDCOLLECTIVE

重置 MCOLLECTIVE 掩码

EXIT

退出程序

JMP

绝对跳转

JMX

绝对跳转间接

JMXU

绝对跳转,带基于统一寄存器的偏移量

KILL

终止线程

NANOSLEEP

暂停执行

PREEXIT

依赖任务启动提示

RET

从子程序返回

RPCMOV

PC 寄存器移动

WARPSYNC

同步 Warp 中的线程

YIELD

Yield 控制

杂项指令

B2R

将屏障移动到寄存器

BAR

屏障同步

CS2R

将特殊寄存器移动到寄存器

DEPBAR

依赖屏障

GETLMEMBASE

获取本地内存基地址

LEPC

加载有效 PC

NOP

空操作

PMTRIG

性能监视器触发器

S2R

将特殊寄存器移动到寄存器

SETCTAID

设置 CTA ID

SETLMEMBASE

设置本地内存基地址

VOTE

跨 SIMT 线程组投票

5. cu++filt

cu++filt 解码(反混淆)已被 CUDA C++ 混淆的低级标识符,使其成为用户可读的名称。对于每个输入的字母数字单词,cu++filt 的输出要么是反混淆的名称(如果名称解码为 CUDA C++ 名称),要么是原始名称本身。

5.1. 用法

cu++filt 接受一个或多个字母数字单词(由字母、数字、下划线、美元符号或句点组成),并尝试解密它们。基本用法如下

cu++filt [options] <symbol(s)>

要反混淆整个文件(如二进制文件),请将文件内容通过管道传递给 cu++filt,例如在以下命令中

nm <input file> | cu++filt

要在不打印参数类型的情况下反混淆函数名称,请使用以下命令

cu++filt -p <symbol(s)>

要跳过混淆符号的前导下划线,请使用以下命令

cu++filt -_ <symbol(s)>

这是 cu++filt 的示例输出

$ cu++filt _Z1fIiEbl
bool f<int>(long)

如输出所示,符号 _Z1fIiEbl 已成功反混淆。

要剥离函数签名和参数中的所有类型,请使用 -p 选项

$ cu++filt -p _Z1fIiEbl
f<int>

要跳过混淆符号的前导下划线,请使用 -_ 选项

$ cu++filt -_ __Z1fIiEbl
bool f<int>(long)

要反混淆整个文件,请将文件内容通过管道传递给 cu++filt

$ nm test.sm_70.cubin | cu++filt
0000000000000000 t hello(char *)
0000000000000070 t hello(char *)::display()
0000000000000000 T hello(int *)

无法反混淆的符号将按原样打印回 stdout

$ cu++filt _ZD2
_ZD2

可以从命令行反混淆多个符号

$ cu++filt _ZN6Scope15Func1Enez _Z3fooIiPFYneEiEvv _ZD2
Scope1::Func1(__int128, long double, ...)
void foo<int, __int128 (*)(long double), int>()
_ZD2

5.2. 命令行选项

表 9 包含 cu++filt 支持的命令行选项,以及每个选项的功能描述。

表 9. cu++filt 命令行选项

选项

描述

-_

剥离下划线。在某些系统上,CUDA 编译器在每个名称前面都放置一个下划线。此选项删除初始下划线。cu++filt 是否默认删除下划线取决于目标。

-p

在反混淆函数名称时,不显示函数参数的类型。

-h

打印 cu++filt 选项的摘要并退出。

-v

打印此工具的版本信息。

5.3. 库可用性

cu++filt 也可作为静态库 (libcufilt) 使用,可以链接到现有项目。以下接口描述了其用法

char* __cu_demangle(const char *id, char *output_buffer, size_t *length, int *status)

此接口可以在 SDK 中的文件 “nv_decode.h” 中找到。

输入参数

id 输入混淆字符串。

output_buffer 指向将存储反混淆缓冲区的指针。此内存必须使用 malloc 分配。如果 output-buffer 为 NULL,则将 malloc 内存以存储反混淆的名称,并通过函数返回值返回。如果 output-buffer 太小,则使用 realloc 扩展它。

length 如果用户提供预分配的内存,则必须提供输出缓冲区的大小。这是反混淆器在需要重新分配大小时所必需的。如果 length 为非空,则反混淆缓冲区的长度将放置在 length 中。

status *status 设置为以下值之一

  • 0 - 反混淆操作成功

  • -1 - 发生内存分配失败

  • -2 - 不是有效的混淆 id

  • -3 - 发生输入验证失败(一个或多个参数无效)

返回值

指向 NUL 终止的反混淆名称的开头的指针,如果反混淆失败,则为 NULL。调用者负责使用 free 释放此内存。

注意:此函数是线程安全的。

用法示例

#include <stdio.h>
#include <stdlib.h>
#include "nv_decode.h"

int main()
{
  int     status;
  const char *real_mangled_name="_ZN8clstmp01I5cls01E13clstmp01_mf01Ev";
  const char *fake_mangled_name="B@d_iDentiFier";

  char* realname = __cu_demangle(fake_mangled_name, 0, 0, &status);
  printf("fake_mangled_name:\t result => %s\t status => %d\n", realname, status);
  free(realname);

  size_t size = sizeof(char)*1000;
  realname = (char*)malloc(size);
  __cu_demangle(real_mangled_name, realname, &size, &status);
  printf("real_mangled_name:\t result => %s\t status => %d\n", realname, status);
  free(realname);

  return 0;
}

这将打印

fake_mangled_name:   result => (null)     status => -2
real_mangled_name:   result => clstmp01<cls01>::clstmp01_mf01()   status => 0

6. nvprune

nvprune 剪除主机对象文件和库,使其仅包含指定目标的设备代码。

6.1. 用法

nvprune 每次运行时接受单个输入文件,并发出新的输出文件。基本用法如下

nvprune [options] -o <outfile> <infile>

输入文件必须是可重定位的主机对象或静态库(而不是主机可执行文件),输出文件将是相同的格式。

必须使用 –arch 或 –generate-code 选项之一来指定要保留的目标。所有其他设备代码都将从文件中丢弃。目标可以是 sm_NN arch (cubin) 或 compute_NN arch (ptx)。

例如,以下命令将剪除 libcublas_static.a,使其仅包含 sm_70 cubin,而不是通常存在的所有目标

nvprune -arch sm_70 libcublas_static.a -o libcublas_static70.a

请注意,这意味着 libcublas_static70.a 将无法在任何其他架构上运行,因此仅应在为单个架构构建时使用。

6.2. 命令行选项

表 10 包含 nvprune 支持的命令行选项,以及每个选项的功能描述。每个选项都有一个长名称和一个短名称,可以互换使用。

表 10. nvprune 命令行选项

选项(长)

选项(短)

描述

--arch <gpu 架构名称>,...

-arch

指定将保留在对象或库中的 NVIDIA GPU 架构的名称。

--generate-code

-gencode

此选项的格式与 nvcc –generate-code 选项相同,并提供了一种指定应保留在对象或库中的多个架构的方法。只有 ‘code’ 值用作匹配的目标。此选项允许的关键字:‘arch’,‘code’。

--no-relocatable-elf

-no-relocatable-elf

不保留任何可重定位的 ELF。

--output-file

-o

指定输出文件的名称和位置。

--help

-h

打印有关此工具的帮助信息。

--options-file <文件>,...

-optf

从指定的文件中包含命令行选项。

--version

-V

打印有关此工具的版本信息。

7. 附录

7.1. JSON 格式

nvdisasm 的输出是人类可读的文本,未针对机器消费进行格式化。任何使用 nvdisasm 输出的工具都必须解析人类可读的文本,这可能很慢,并且对文本的任何细微更改都可能破坏解析器。

基于 JSON 的格式提供了一种高效且可扩展的方法,用于从 nvdisasm 输出机器可读数据。选项 -json 可用于生成符合以下 JSON 模式定义的 JSON 文档。

{
    "$id": "https://nvidia.com/cuda/cuda-binary-utilities/index.html#json-format",
    "description": "A JSON schema for NVIDIA CUDA disassembler. The $id attribute is not a real URL but a unique identifier for the schema",
    "$schema": "https://json-schema.fullstack.org.cn/draft/2020-12/schema",
    "title": "A JSON schema for NVIDIA CUDA disassembler",
    "version": "12-8-0",
    "type": "array",
    "minItems": 2,
    "prefixItems": [
        {
            "$ref": "#/$defs/metadata"
        },
        {
            "description": "A list of CUDA functions",
            "type": "array",
            "minItems": 1,
            "items": {
                "$ref": "#/$defs/function"
            }
        }
    ],
    "$defs": {
        "metadata": {
            "type": "object",
            "properties": {
                "ELF": {
                    "$ref": "#/$defs/elf-metadata"
                },
                "SM": {
                    "type": "object",
                    "properties": {
                        "version": {
                            "$ref": "#/$defs/sm-version"
                        }
                    },
                    "required": [
                        "version"
                    ]
                },
                "SchemaVersion": {
                    "$ref": "#/$defs/version"
                },
                "Producer": {
                    "type": "string",
                    "description": "Name and version of the CUDA disassembler tool",
                    "maxLength": 1024
                },
                "Description": {
                    "type": "string",
                    "description": "A description that may be empty",
                    "maxLength": 1024
                },
                ".note.nv.tkinfo": {
                    "$ref": "#/$defs/Elf64_NV_TKinfo"
                }
            },
            "required": [
                "ELF",
                "SM",
                "SchemaVersion",
                "Producer",
                "Description"
            ]
        },
        "elf-metadata": {
            "type": "object",
            "properties": {
                "layout-id": {
                    "description": "Indicates the layout of the ELF file, part of the ELF header flags. Undocumented enum",
                    "type": "integer"
                },
                "ei_osabi": {
                    "description": "Operating system/ABI identification",
                    "type": "integer"
                },
                "ei_abiversion": {
                    "description": "ABI version",
                    "type": "integer"
                }
            },
            "required": [
                "layout-id",
                "ei_osabi",
                "ei_abiversion"
            ]
        },
        "sm-version": {
            "type": "object",
            "properties": {
                "major": {
                    "type": "integer"
                },
                "minor": {
                    "type": "integer"
                }
            },
            "required": [
                "major",
                "minor"
            ]
        },
        "version": {
            "type": "object",
            "properties": {
                "major": {
                    "type": "integer"
                },
                "minor": {
                    "type": "integer"
                },
                "revision": {
                    "type": "integer"
                }
            },
            "required": [
                "major",
                "minor",
                "revision"
            ]
        },
        "sass-instruction-attribute": {
            "type": "object",
            "additionalProperties": {
                "type": "string"
            }
        },
        "sass-instruction": {
            "type": "object",
            "properties": {
                "predicate": {
                    "type": "string",
                    "description": "Instruction predicate"
                },
                "opcode": {
                    "type": "string",
                    "description": "The instruction opcode. May be empty to indicate a gap between non-contiguous instructions"
                },
                "operands": {
                    "type": "string",
                    "description": "Instruction operands separated by commas"
                },
                "extra": {
                    "type": "string",
                    "description": "Optional field"
                },
                "other-attributes": {
                    "type": "object",
                    "description": "Additional instruction attributes encoded as a map of string:string key-value pairs. Example: {'control-flow': 'True'}",
                    "items": {
                        "type": "string"
                    }
                },
                "other-flags": {
                    "type": "array",
                    "description": "Aditional instruction attributes encoded as a list strings",
                    "items": {
                        "type": "string"
                    }
                }
            },
            "required": [
                "opcode"
            ]
        },
        "function": {
            "type": "object",
            "properties": {
                "function-name": {
                    "type": "string"
                },
                "start": {
                    "type": "integer",
                    "description": "The function's start virtual address"
                },
                "length": {
                    "type": "integer",
                    "description": "The function's length in bytes"
                },
                "other-attributes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "sass-instructions": {
                    "type": "array",
                    "items": {
                        "$ref": "#/$defs/sass-instruction"
                    }
                }
            },
            "required": [
                "function-name",
                "start",
                "length",
                "sass-instructions"
            ]
        },
        "Elf64_NV_TKinfo": {
            "type": "object",
            "properties": {
                "tki_toolkitVersion": {
                    "type": "integer"
                },
                "tki_objFname": {
                    "type": "string"
                },
                "tki_toolName": {
                    "type": "string"
                },
                "tki_toolVersion": {
                    "type": "string"
                },
                "tki_toolBranch": {
                    "type": "string"
                },
                "tki_toolOptions": {
                    "type": "string"
                }
            },
            "required": [
                "tki_toolkitVersion",
                "tki_objFname",
                "tki_toolName",
                "tki_toolVersion",
                "tki_toolBranch",
                "tki_toolOptions"
            ]
        }
    }
}

关于 sass-instruction 对象的说明

  • other-attributes 可能包含 "control-flow": "True" 键值对,以指示控制流指令。

  • 第 n 个(从 0 开始)SASS 指令的地址可以计算为 start + n * 指令大小。在 Volta 和更高版本的架构上,指令大小为 16 字节,而在之前的架构上为 8 字节。

  • JSON 列表可能包含空指令对象;这些对象计入指令索引,因为它们指示不连续指令之间的间隙。

  • 空指令对象具有单个字段 opcode,其值为空字符串:"opcode": ""

这是 nvdisasm -json 的示例输出

[
    // First element in the list: Metadata
    {
        // ELF Metadata
        "ELF": {
            "layout-id": 4,
            "ei_osabi": 51,
            "ei_abiversion": 7
        },
        // SASS code SM version: SM89 (16 bytes instructions)
        "SM": {
            "version": {
                "major": 8,
                "minor": 9
            }
        },
        "SchemaVersion": {
            "major": 12,
            "minor": 8,
            "revision": 0
        },
        // Release details of nvdisasm
        "Producer": "nvdisasm V12.8.14 Build r570_00.r12.8/compiler.35033008_0",
        "Description": ""
    },
    // Second element in the list: Functions
    [
        {
            "function-name": "_Z10exampleKernelv",
            // Function start address
            "start": 0,
            // Function length in bytes
            "length": 384,
            "other-attributes": [],
            // SASS instructions
            "sass-instructions": [
                {
                    // Instruction at 0x00
                    "opcode": "IMAD.MOV.U32",
                    "operands": "R1,RZ,RZ,c[0x0][0x28]"
                },
                {
                    // Instruction at 0x10 (16 bytes increment)
                    "opcode": "MOV",
                    "operands": "R0,0x0"
                },
                {
                    // Instruction at 0x20
                    "opcode": "IMAD.MOV.U32",
                    "operands": "R4,RZ,RZ,c[0x4][0x8]"
                },
                // [...]
                {
                    "opcode": "CALL.ABS.NOINC",
                    "operands": "R2",
                    // other-attributes is an optional that can indicate control flow instructions
                    "other-attributes": {
                        "control-flow": "True"
                    }
                },
                {
                    "opcode": "EXIT",
                    "other-attributes": {
                        "control-flow": "True"
                    }
                },
                {
                    "opcode": "NOP"
                }
            ]
        }
    ]
]

8. 声明

8.1. 声明

本文档仅供参考,不应被视为对产品的特定功能、状况或质量的保证。NVIDIA Corporation(“NVIDIA”)对本文档中包含的信息的准确性或完整性不作任何明示或暗示的陈述或保证,并且对本文中包含的任何错误不承担任何责任。NVIDIA 对使用此类信息或因使用此类信息而可能导致的侵犯第三方专利或其他权利的后果或用途不承担任何责任。本文档不构成开发、发布或交付任何材料(下文定义)、代码或功能的承诺。

NVIDIA 保留随时对此文档进行更正、修改、增强、改进和任何其他更改的权利,恕不另行通知。

客户应在下订单前获取最新的相关信息,并应验证此类信息是否为最新且完整。

NVIDIA 产品的销售受 NVIDIA 在订单确认时提供的标准销售条款和条件的约束,除非 NVIDIA 和客户的授权代表签署的个别销售协议(“销售条款”)另有约定。NVIDIA 在此明确反对将任何客户通用条款和条件应用于购买本文档中引用的 NVIDIA 产品。本文档未直接或间接形成任何合同义务。

NVIDIA 产品并非设计、授权或保证适用于医疗、军事、航空、航天或生命支持设备,也不适用于 NVIDIA 产品的故障或故障可以合理预期会导致人身伤害、死亡或财产或环境损害的应用。对于在上述设备或应用中包含和/或使用 NVIDIA 产品,NVIDIA 不承担任何责任,因此,此类包含和/或使用由客户自行承担风险。

NVIDIA 不作任何陈述或保证,保证基于本文档的产品将适用于任何特定用途。NVIDIA 不一定会对每种产品的所有参数进行测试。客户全权负责评估和确定本文档中包含的任何信息的适用性,确保产品适用于客户计划的应用并适合该应用,并为该应用执行必要的测试,以避免应用或产品的默认设置。客户产品设计中的缺陷可能会影响 NVIDIA 产品的质量和可靠性,并可能导致超出本文档中包含的附加或不同条件和/或要求。对于可能基于或归因于以下原因的任何默认、损坏、成本或问题,NVIDIA 不承担任何责任:(i)以任何违反本文档的方式使用 NVIDIA 产品,或(ii)客户产品设计。

本文档未授予任何 NVIDIA 专利权、版权或其他 NVIDIA 知识产权下的任何明示或暗示的许可。NVIDIA 发布的关于第三方产品或服务的信息不构成 NVIDIA 授予使用此类产品或服务的许可,也不构成对此类产品或服务的保证或认可。使用此类信息可能需要获得第三方的专利或其他知识产权下的许可,或者获得 NVIDIA 的专利或其他知识产权下的 NVIDIA 许可。

仅在事先获得 NVIDIA 书面批准的情况下,才允许复制本文档中的信息,复制时不得进行更改,并且必须完全符合所有适用的出口法律和法规,并附带所有相关的条件、限制和声明。

本文档和所有 NVIDIA 设计规范、参考板、文件、图纸、诊断程序、列表和其他文档(统称为“材料”)均按“原样”提供。NVIDIA 对材料不作任何明示、暗示、法定或其他形式的保证,并明确声明不承担所有关于不侵权、适销性和特定用途适用性的默示保证。在法律未禁止的范围内,在任何情况下,NVIDIA 均不对因使用本文档而引起的任何损害(包括但不限于任何直接、间接、特殊、附带、惩罚性或后果性损害,无论因何种原因造成且无论责任理论如何)承担责任,即使 NVIDIA 已被告知可能发生此类损害。尽管客户可能因任何原因遭受任何损害,但 NVIDIA 对本文所述产品的客户的累计责任应根据产品的销售条款进行限制。

8.2. OpenCL

OpenCL 是 Apple Inc. 的商标,已获得 Khronos Group Inc. 的许可使用。

8.3. 商标

NVIDIA 和 NVIDIA 徽标是 NVIDIA Corporation 在美国和其他国家/地区的商标或注册商标。其他公司和产品名称可能是与其相关的各自公司的商标。