没有显式内部函数的CUDA半浮点运算

没有显式内部函数的CUDA半浮点运算,cuda,intrinsics,nvcc,fma,half-precision-float,Cuda,Intrinsics,Nvcc,Fma,Half Precision Float,我使用的是CUDA 11.2,我使用\u half类型对16位浮点值进行操作 我很惊讶nvcc编译器在我执行以下操作时不会正确调用融合乘法加法指令: __half a,b,c; ... __half x = a * b + c; 它不发出融合的乘法加法,而是发出单独的mul和add指令 mul.f16 %rs164,%rs1,%rs306; add.f16 %rs167,%rs164,%rs65; 请注意,尽管使用了--fmad=true编译器选项,但仍然存在这种情况 而显式hfma(a、b

我使用的是CUDA 11.2,我使用
\u half
类型对16位浮点值进行操作

我很惊讶nvcc编译器在我执行以下操作时不会正确调用融合乘法加法指令:

__half a,b,c;
...
__half x = a * b + c;
它不发出融合的乘法加法,而是发出单独的mul和add指令

mul.f16 %rs164,%rs1,%rs306;
add.f16 %rs167,%rs164,%rs65;
请注意,尽管使用了
--fmad=true
编译器选项,但仍然存在这种情况

而显式hfma(a、b、c)将发出:

fma.rn.f16 %rs164,%rs1,%rs300,%rs65;

利用16位浮点乘法加法使用显式内部函数的唯一方法是什么?

GPU实际执行的指令是SASS,而不是PTX。PTX是一种中间格式,将PTX转换为SASS的工具是一个优化编译器

当我按照您的建议执行操作并研究SASS时,我看到生成了一条融合乘法加法指令:

$ cat t111.cu
#include <cuda_fp16.h>
__global__ void k(__half *x, __half a, __half b, __half c){
        *x = a*b+c;
}
$ nvcc -arch=sm_75 -c t111.cu
$ cuobjdump -ptx t111.o

Fatbin elf code:
================
arch = sm_75
code version = [1,7]
producer = <unknown>
host = linux
compile_size = 64bit

Fatbin ptx code:
================
arch = sm_75
code version = [7,1]
producer = <unknown>
host = linux
compile_size = 64bit
compressed

.version 7.1
.target sm_75
.address_size 64



.visible .entry _Z1kP6__halfS_S_S_(
.param .u64 _Z1kP6__halfS_S_S__param_0,
.param .align 2 .b8 _Z1kP6__halfS_S_S__param_1[2],
.param .align 2 .b8 _Z1kP6__halfS_S_S__param_2[2],
.param .align 2 .b8 _Z1kP6__halfS_S_S__param_3[2]
)
{
.reg .b16 %rs<7>;
.reg .b64 %rd<3>;


ld.param.u64 %rd1, [_Z1kP6__halfS_S_S__param_0];
ld.param.u16 %rs2, [_Z1kP6__halfS_S_S__param_1];
ld.param.u16 %rs3, [_Z1kP6__halfS_S_S__param_2];
ld.param.u16 %rs6, [_Z1kP6__halfS_S_S__param_3];
cvta.to.global.u64 %rd2, %rd1;

        {mul.f16 %rs1,%rs2,%rs3;
}


        {add.f16 %rs4,%rs1,%rs6;
}

        st.global.u16 [%rd2], %rs4;
ret;
}


$ cuobjdump -sass t111.o

Fatbin elf code:
================
arch = sm_75
code version = [1,7]
producer = <unknown>
host = linux
compile_size = 64bit

        code for sm_75
                Function : _Z1kP6__halfS_S_S_
        .headerflags    @"EF_CUDA_SM75 EF_CUDA_PTX_SM(EF_CUDA_SM75)"
        /*0000*/                   MOV R1, c[0x0][0x28] ;                                /* 0x00000a0000017a02 */
                                                                                         /* 0x000fd00000000f00 */
        /*0010*/                   LDC.U16 R0, c[0x0][0x168] ;                           /* 0x00005a00ff007b82 */
                                                                                         /* 0x000e220000000400 */
        /*0020*/                   ULDC.64 UR4, c[0x0][0x160] ;                          /* 0x0000580000047ab9 */
                                                                                         /* 0x000fce0000000a00 */
        /*0030*/                   LDC.U16 R3, c[0x0][0x16a] ;                           /* 0x00005a80ff037b82 */
                                                                                         /* 0x000e240000000400 */
        /*0040*/                   HFMA2 R0, R0.H0_H0, R3.H0_H0, c[0x0] [0x16c].H0_H0 ;  /* 0x20005b0000007631 */
                                                                                         /* 0x001fd00000040803 */
        /*0050*/                   STG.E.U16.SYS [UR4], R0 ;                             /* 0x00000000ff007986 */
                                                                                         /* 0x000fe2000c10e504 */
        /*0060*/                   EXIT ;                                                /* 0x000000000000794d */
                                                                                         /* 0x000fea0003800000 */
        /*0070*/                   BRA 0x70;                                             /* 0xfffffff000007947 */
                                                                                         /* 0x000fc0000383ffff */
                ..........



Fatbin ptx code:
================
arch = sm_75
code version = [7,1]
producer = <unknown>
host = linux
compile_size = 64bit
compressed
$
$cat t111.cu
#包括
__全局无效k(uuu-half*x,uu-half-a,uu-half-b,uu-half-c){
*x=a*b+c;
}
$nvcc-arch=sm_75-c t111.cu
$cuobjdump-ptx t111.o
Fatbin elf代码:
================
arch=sm_75
代码版本=[1,7]
制作人=
主机=linux
编译大小=64位
Fatbin ptx代码:
================
arch=sm_75
代码版本=[7,1]
制作人=
主机=linux
编译大小=64位
压缩的
.7.1版
.目标sm_75
.地址大小64
.可见。条目_Z1kP6__半S_S__(
.param.u64 Z1kP6 uuu半S u S uu参数0,
.param.align 2.b8 Z1kP6_uuhalf S_us_us_u参数1[2],
.param.align 2.b8 Z1kP6_uuhalf S_us_us_u参数2[2],
.param.align 2.b8_Z1kP6_uuhalf S_S_us_u参数3[2]
)
{
.reg.b16%rs;
.reg.b64%rd;
ld.param.u64%rd1,[\u Z1kP6\u一半S\u S\u参数0];
ld.param.u16%rs2,[\u Z1kP6\u一半S\u S\u参数1];
ld.param.u16%rs3,[\u Z1kP6\u一半S\u S\u参数2];
ld.param.u16%rs6,[\u Z1kP6\u一半S\u S\u参数3];
cvta.to.global.u64%rd2,%rd1;
{mul.f16%rs1,%rs2,%rs3;
}
{add.f16%rs4,%rs1,%rs6;
}
st.global.u16[%rd2],%rs4;
ret;
}
$cuobjdump-sass t111.o
Fatbin elf代码:
================
arch=sm_75
代码版本=[1,7]
制作人=
主机=linux
编译大小=64位
sm_75的代码
功能:Z1kP6_uuuhalfs_us_us_
.headerflags@“EF_CUDA_SM75 EF_CUDA_PTX_SM(EF_CUDA_SM75)”
/*0000*/MOV R1,c[0x0][0x28];/*0x00000a0000017a02*/
/*0x000fd00000000f00*/
/*0010*/LDC.U16 R0,c[0x0][0x168];/*0x00005a00ff007b82*/
/*0x000E2200000400*/
/*0020*/ULDC.64 UR4,c[0x0][0x160];/*0x00005800047AB9*/
/*0x000fce0000000a00*/
/*0030*/LDC.U16 R3,c[0x0][0x16a];/*0x00005a80ff037b82*/
/*0x000e240000000400*/
/*0040*/HFMA2 R0,R0.H0_H0,R3.H0_H0,c[0x0][0x16c].H0_H0;/*0x200000000007631*/
/*0x001fd00000040803*/
/*0050*/STG.E.U16.SYS[UR4],R0;/*0x00000000ff007986*/
/*0x000fe2000c10e504*/
/*0060*/退出;/*0x000000000000794d*/
/*0x000fea0003800000*/
/*0070*/BRA 0x70;/*0xFFFFF000007947*/
/*0x000fc0000383ffff*/
..........
Fatbin ptx代码:
================
arch=sm_75
代码版本=[7,1]
制作人=
主机=linux
编译大小=64位
压缩的
$
(CUDA 11.1)


我不建议用PTX分析来回答这样的问题。

GPU实际执行的指令是SASS,而不是PTX。PTX是一种中间格式,将PTX转换为SASS的工具是一个优化编译器

当我按照您的建议执行操作并研究SASS时,我看到生成了一条融合乘法加法指令:

$ cat t111.cu
#include <cuda_fp16.h>
__global__ void k(__half *x, __half a, __half b, __half c){
        *x = a*b+c;
}
$ nvcc -arch=sm_75 -c t111.cu
$ cuobjdump -ptx t111.o

Fatbin elf code:
================
arch = sm_75
code version = [1,7]
producer = <unknown>
host = linux
compile_size = 64bit

Fatbin ptx code:
================
arch = sm_75
code version = [7,1]
producer = <unknown>
host = linux
compile_size = 64bit
compressed

.version 7.1
.target sm_75
.address_size 64



.visible .entry _Z1kP6__halfS_S_S_(
.param .u64 _Z1kP6__halfS_S_S__param_0,
.param .align 2 .b8 _Z1kP6__halfS_S_S__param_1[2],
.param .align 2 .b8 _Z1kP6__halfS_S_S__param_2[2],
.param .align 2 .b8 _Z1kP6__halfS_S_S__param_3[2]
)
{
.reg .b16 %rs<7>;
.reg .b64 %rd<3>;


ld.param.u64 %rd1, [_Z1kP6__halfS_S_S__param_0];
ld.param.u16 %rs2, [_Z1kP6__halfS_S_S__param_1];
ld.param.u16 %rs3, [_Z1kP6__halfS_S_S__param_2];
ld.param.u16 %rs6, [_Z1kP6__halfS_S_S__param_3];
cvta.to.global.u64 %rd2, %rd1;

        {mul.f16 %rs1,%rs2,%rs3;
}


        {add.f16 %rs4,%rs1,%rs6;
}

        st.global.u16 [%rd2], %rs4;
ret;
}


$ cuobjdump -sass t111.o

Fatbin elf code:
================
arch = sm_75
code version = [1,7]
producer = <unknown>
host = linux
compile_size = 64bit

        code for sm_75
                Function : _Z1kP6__halfS_S_S_
        .headerflags    @"EF_CUDA_SM75 EF_CUDA_PTX_SM(EF_CUDA_SM75)"
        /*0000*/                   MOV R1, c[0x0][0x28] ;                                /* 0x00000a0000017a02 */
                                                                                         /* 0x000fd00000000f00 */
        /*0010*/                   LDC.U16 R0, c[0x0][0x168] ;                           /* 0x00005a00ff007b82 */
                                                                                         /* 0x000e220000000400 */
        /*0020*/                   ULDC.64 UR4, c[0x0][0x160] ;                          /* 0x0000580000047ab9 */
                                                                                         /* 0x000fce0000000a00 */
        /*0030*/                   LDC.U16 R3, c[0x0][0x16a] ;                           /* 0x00005a80ff037b82 */
                                                                                         /* 0x000e240000000400 */
        /*0040*/                   HFMA2 R0, R0.H0_H0, R3.H0_H0, c[0x0] [0x16c].H0_H0 ;  /* 0x20005b0000007631 */
                                                                                         /* 0x001fd00000040803 */
        /*0050*/                   STG.E.U16.SYS [UR4], R0 ;                             /* 0x00000000ff007986 */
                                                                                         /* 0x000fe2000c10e504 */
        /*0060*/                   EXIT ;                                                /* 0x000000000000794d */
                                                                                         /* 0x000fea0003800000 */
        /*0070*/                   BRA 0x70;                                             /* 0xfffffff000007947 */
                                                                                         /* 0x000fc0000383ffff */
                ..........



Fatbin ptx code:
================
arch = sm_75
code version = [7,1]
producer = <unknown>
host = linux
compile_size = 64bit
compressed
$
$cat t111.cu
#包括
__全局无效k(uuu-half*x,uu-half-a,uu-half-b,uu-half-c){
*x=a*b+c;
}
$nvcc-arch=sm_75-c t111.cu
$cuobjdump-ptx t111.o
Fatbin elf代码:
================
arch=sm_75
代码版本=[1,7]
制作人=
主机=linux
编译大小=64位
Fatbin ptx代码:
================
arch=sm_75
代码版本=[7,1]
制作人=
主机=linux
编译大小=64位
压缩的
.7.1版
.目标sm_75
.地址大小64
.可见。条目_Z1kP6__半S_S__(
.param.u64 Z1kP6 uuu半S u S uu参数0,
.param.align 2.b8 Z1kP6_uuhalf S_us_us_u参数1[2],
.param.align 2.b8 Z1kP6_uuhalf S_us_us_u参数2[2],
.param.align 2.b8_Z1kP6_uuhalf S_S_us_u参数3[2]
)
{
.reg.b16%rs;
.reg.b64%rd;
ld.param.u64%rd1,[\u Z1kP6\u一半S\u S\u参数0];
ld.param.u16%rs2,[\u Z1kP6\u一半S\u S\u参数1];
ld.param.u16%rs3,[\u Z1kP6\u一半S\u S\u参数2];
ld.param.u16%rs6,[\u Z1kP6\u一半S\u S\u参数3];
cvta.to.global.u64%rd2,%rd1;
{mul.f16%rs1,%rs2,%rs3;
}
{add.f16%rs4,%rs1,%rs6;
}
st.global.u16[%rd2],%rs4;
ret;
}
$cuobjdump-sass t111.o
Fatbin elf代码:
================
arch=sm_75
代码版本=[1,7]
制作人=
主机=linux
编译大小=64位
sm_75的代码
功能:Z1kP6_uuuhalfs_us_us_
.headerflags@“EF_CUDA_SM75 EF_CUDA_PTX_SM(EF_CUDA_SM75)”
/*0000*/