CUDA内联汇编和PTX ISA入门指南

本文是一篇关于CUDA内联汇编和PTX ISA的入门指南,介绍了内联汇编的基本用法,包括引用、约束和修饰符。同时,详细讲解了PTX ISA的概述、变量声明、指令集以及谓词逻辑执行分支。通过实例展示了如何使用mul和mad指令,并解释了如何将PTX代码转换为类似C的语言形式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Example

首先给出一个具体例子,下文根据该例讲述基本用法

        asm("{\n\t"
                ".reg .s32 b;\n\t"
                ".reg .pred p;\n\t"
                "add.cc.u32 %1, %1, %2;\n\t"
                "addc.s32 b, 0, 0;\n\t"
                "sub.cc.u32 %0, %0, %2;\n\t"
                "subc.cc.u32 %1, %1, 0;\n\t"
                "subc.s32 b, b, 0;\n\t"
                "setp.eq.s32 p, b, 1;\n\t"
                "@p add.cc.u32 %0, %0, 0xffffffff;\n\t"
                "@p addc.u32 %1, %1, 0;\n\t"
                "}"
                : "+r"(x[0]), "+r"(x[1])
                : "r"(x[2]));

内联汇编(inline assembly)

官方参考:https://docs.nvidia.com/cuda/inline-ptx-assembly/index.html

CUDA内联汇编语法和C/C++相同(除不允许设置clobbered registers)

       asm ( "assembler template string" 
           : "constraint"(output operands)                  /* optional */
           : "constraint"(input operands)                   /* optional */
           );

引用

"assembler template string"指PTX汇编指令代码,其中可以用%n引用操作数,n为从0开始的整数。编号顺序和在出现在输出操作数、输入操作数中的先后顺序一致(例如Example中,操作数出现顺序为x[0],x[1],x[2]分别对应汇编代码中的引用%0,%1,%2

constriant

规定使用相应的PTX寄存器类型

"h" = .u16 reg	// u表示无符号 16表示位数
"r" = .u32 reg
"l" = .u64 reg
"f" = .f32 reg  // f表示浮点寄存器
"d" = .f64 reg

补充(modifier)

由于官方参考关于操作数(operand)的修饰符描述较少,这里稍作简略描述(参考OpenXL C/C++ inline asemmbly):

  • =:表示该操作数只写(write-only),之前的值会被弃用,被这一新的输出数据取而代之
  • +:表示该操作数既可读又可写

输出操作数必须带上修饰符=+,输入操作数由于官方文档并未说明可直接认为修饰符可选(或没有)

PTX ISA

概述

PTX:Parallel Thread Execution
ISA:Instruction Set Architecture(指令集)

PTX ISA比CUDA C++更底层,但编程模型完全相同,仅在一些称谓上有所区别,例如

CTA(Cooperative Thread Array):等同于CUDA线程模型中的Block(PS:Grid这一概念依然保持不变)

变量声明

Example第2、3行均为变量声明语句,单独来看

.reg .s32 b;
.reg .pred p;

由三部分组成:State Space + Type + Identifier

State Space

规定存储位置,带有.前缀,区别标识符

名称 描述
.reg 寄存器,访存快
.sreg 特殊寄存器。只读;预定义;平台有关
.const 共享内存(Shared memory),只读
.global 全局内存(Global memory),全部线程共享
.local 本地内存(Local memory),每个线程私有
.param Kernel parameter
.shared 可按地址访问的共享内存,一个CTA内共享

具体特性参见官方文档State Spaces

Type
基本类型 对应符号
有符号整数 .s8, .s16, .s32, .s64
无符号整数 .u8, .u16, .u32, .u64
浮点数 .f16, .f16x2, .f32, .f64
位串(无类型) .b8, .b16, .b32, .b64
谓词 .pred
Identifier

标识符基本和所有语言规定相同,细微区别参见官方文档Identifier


回到例子

.reg .s32 b;	// 有符号32位整数变量b,使用寄存器存放
.reg .pred p;	// 谓词变量p(用于存放谓词逻辑结果,布尔值),使用寄存器存放

关于谓词的使用方法下文会有详细描述

指令集

指令格式
@p opcode;
@p opcode a;
@p opcode d, a;
@p opcode d, a, b;
@p opcode d, a, b, c;
  • 注意指令的操作数个数,以及操作数的含义(源、目的等等)
  • 最左边的@p是可选的guard predicate,即根据对应谓词结果选择是否执行该条指令
指令类型信息

多类型指令必须带上类型及大小描述符,例如Example中第4行add.cc.u32 %1, %1, %2;.u32表示进行无符号32位整数的加法。

扩展精度的整数运算

主要用于处理进位,例如Example中的4、5行:

add.cc.u32 %1, %1, %2;
addc.s32 b, 0, 0;

add.cc表示该条指令会改写条件码(Condition Code,简称CC)寄存器中的进位标志位(Carry Flag,简称CF);addc表示执行带进位的加法,也就是说除了源操作数外还会加上CC.CF

其它扩展运算指令参考官方文档Extended-Precision Integer Arithmetic Instructions

谓词逻辑执行分支

谓词寄存器本质上是虚拟的寄存器,用于处理PTX中的分支(类比其他ISA的条件跳转指令beq等)

  1. 声明谓词寄存器

    如Example中第3行.reg .pred p,声明谓词变量p

  2. step指令给谓词变量绑定具体谓词逻辑

    如Example中第9行setp.eq.s32 p, b, 1setp指set predicate register

    基本语法格式:setp.CmpOp.type p, a, b

    • type:规定源操作数a,b的类型
    • CmpOp:比较运算符
    • p必须是.pred类型变量

    关于step指令的详细用法参见官方文档Comparison and Selection Instructions: setp

  3. 设置条件分支

    如Example中10、11行

    @p add.cc.u32 %0, %0, 0xffffffff;
    @p addc.u32 %1, %1, 0;
    

    @p表示当p=True时,执行该条指令;而@!p则表示p=False时执行。

翻译为C-like language

// 函数功能:X mod p
// p = 0xFFFFFFFF00000001
// x = {x[0], x[1], x[2]}
// x[0]: LSW(least significant word) word=32-bit
void _uint96_modP(uint32 *x) {
	x[1] += x[2];
    b = /*上条指令发生溢出*/ ? 1 : 0;
    x[0] -= x[2];
    x[1] -= /*上条指令发生溢出*/ ? 1 : 0;
    if (b == 1) {
        x[0] += 0xFFFFFFFF; // x[0] += UINT_MAX
        x[1] += /*上条指令发生溢出*/ ? 1 : 0;
    }
}

(以下内容为分析函数功能,考虑到文章完整性才添加,和主旨无关)
X = x 0 + x 1 ⋅ 2 32 + x 2 ⋅ 2 64 m o d    ( P = 2 64 − 2 32 + 1 ) = x 0 + x 1 ⋅ 2 32 + x 2 ⋅ 2 64 − x 2 P m o d    P = ( x 0 − x 2 ) + ( x 1 + x 2 ) ⋅ 2 32 m o d    P \begin{aligned} X&=x_0+x_1\cdot 2^{32}+x_2\cdot 2^{64} \mod {(P=2^{64}-2^{32}+1)}\\ &=x_0+x_1\cdot 2^{32}+x_2\cdot 2^{64}-x_2P \mod P\\ &=(x_0-x_2)+(x_1+x_2)\cdot 2^{32} \mod P \end{aligned} X=x0+x1232+x2264mod(P=264232+1)=x0+x1232+x2264x2PmodP=(x0

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值