CUDA4.0 inline PTX汇编程序开发( 0 )

内联PTX汇编具有如下形式:

asm(“instop”:”type_symbolic”(or):”type_symbolic”(ir),..);

asm(“instop”::”type_symbolic”(r));

第二种形式是无输出操作格式,需要使用”::”指示符

其中instop是指令操作

type_symbolic是类型指示符(可选如下),分别对应与PTX中的数据类型:

“h” .s16, .u16

“r” .s32, .u32

“l” .s64, .u64

“f” .f32

“d” .f64

 

例如:

//c=a+b

float a=…

float b=…;

float c;

asm( “add.f32 %0, %1, %2;” : “=f”(c):”f”(a),”f”(b));

 

%0, %1, %2,是匹配符,在分开写的“asm()”段中,不通指令序列中的%匹配符不具有相关项,它们的作用只是根据“:”后面的匹配格式按照顺序进行匹配,所以统一规格程序中的两段“asm()“中的相同的%numberic不一定指向统一规格实际的物理寄存器,例如:

 

__global__

void cuk_lerp( float* z, const float* x, const float* y, float alpha )

{

    float u=x[ threadIdx.x ];

    float v=y[ threadIdx.x ];

    float a, b;

    asm( "sub.f32 %0, 0f3f800000, %1;" : "=f"(a) : "f"(alpha) );  //a=1.f-alpha

    asm( "mul.f32 %0, %0, %1;" : "+f"(u) : "f"(a) );                // u*=a

    asm( "fma.rn.f32 %0, %1, %2, %3;" : "=f"(b) : "f"(alpha), "f"(v), "f"(u) ); // b=alpha*v+u

    z[ threadIdx.x ]=b;

}

 

来看下这段代码,首先看第一段“asm(),在前面的指令序列中可以直接使用数字,但有些限制,0f3f800000对应的十进制浮点数是1.f,但不能直接使用1.f,否则编译器会报错,因为f属于类型匹配符中的关键字”;也不能使用1,或者1.0,这样编译器也会报错,前者认为是整数,类型不匹配;后者则认为是双精度浮点数,类型的尺寸不匹配。

再看第二段asm(),+f(u)表示即读友写操作,并以一定对应“+=”操作,也可是任何CUDA编译器支持的“op=操作,比如:+=, -=, *=, &=, op匹配哪种操作则有前面的指令决定。

   也可在内联汇编里声明局部变量:

asm( “reg.u32 a;/n/t”

“shl.u32 %0, 1, a;”

: “=r”(mask) : “r”(a) );

注意,这段代码,当指令操作位于匹配格式序列之前也就是最后一段指令操作学列时,不需要再使用“/n/t”换行符。

匹配格式也支持如果没有输入的操作:

asm( “mov.s32 %0, 7;” : “=r”(x) );

 

通常存储器写操作是作为输出操作,但有时会存在同步隐患,或者想避免编译器对存储操作的优化,这时可以使用”memory”指示字:

   

 

总体来说inline PTX现在还比较初级,有些功能还不能使用,比如指令操作数只能是标量,不支持矢量,举个例子:

asm( "ld.shared.v2.f32 { %0, %1 },[ %2+16 ];":"=f"(a),"=f"(b): “r”(ptr) );

这样虽然编译可以通过,但是内核执行却会发生错误,而应该使用如下代码代替:

asm( "ld.shared.f32 { %0 },[ %1+0 ];":"=f"(a): “r”(ptr) );

asm( "ld.shared.f32 { %0 },[ %1+8 ];":"=f"(b): “r”(ptr) );

 

   关于使用inline ptx的更多细节可以参考CUDAtookit4.0中的using inline PTX assembly in CUDA.pdf(当然,这里所说的一些细节手册并未提到).

好了,写的比较仓促,且耐心不足,疏漏之处在所难免,欢迎指正。以后会补上更详细晚上的PTX内联汇编编程文档。

欢迎大家来和我讨论交流。

下面提上完整的测试程序:

内核代码正式上面的cuk_lerp,但注意:测试时须将cuk_lerp放入extern C {}中。

另外设置编译选项时,输出不能设置为-ptx,只有-cubin或者-fatbin选项才支持内联ptx.

host code:

#include

#include

#pragma comment( lib, "cuda.lib" )

 

int main()

{

    CUdevice    device;

    CUcontext   context;

    CUmodule    module;

    CUfunction  kernel;

    CUdeviceptr dptr[ 3 ];

 

    cuInit( 0 );

    cuDeviceGet( &device, 0 );

    cuCtxCreate( &context, CU_CTX_SCHED_AUTO, device );

    cuModuleLoad( &module, "kernel.cubin" );

    cuModuleGetFunction( &kernel, module, "cuk_lerp" );

 

#define n_threads 128

    size_t size=n_threads*sizeof( float );

    cuMemAlloc( &dptr[ 0 ], size );

    cuMemAlloc( &dptr[ 1 ], size );

    cuMemAlloc( &dptr[ 2 ], size );

 

    float a[ 128 ];

    float b[ 128 ];

    for( int i=0; i<n_threads; ++i )

    {

          a[ i ]=1.f;

        b[ i ]=2.f;

    }

 

    cuMemcpyHtoD( dptr[ 1 ], a, size );

    cuMemcpyHtoD( dptr[ 2 ], b, size );

 

    float alpha=0.5f;

    void* params[]={ &dptr[ 0 ], &dptr[ 1 ], &dptr[ 2 ], &alpha };

    cuLaunchKernel( kernel, 1, 1, 1, 128, 1, 1, 0, NULL, params, 0 );

    cuCtxSynchronize();

 

    cuMemcpyDtoH( a, dptr[ 0 ], size );

 

    for( int i=0; i<128; ++i ){

        printf( "%f/n", a[ i ] );

    }

 

    cuMemFree( dptr[ 0 ] );

    cuMemFree( dptr[ 1 ] );

    cuMemFree( dptr[ 2 ] );

    cuModuleUnload( module );

    cuCtxDestroy( context );

 

    return 0;

}

    asm volatile ( “mov.u32 %0, %%laneid.x;” : “=r”(out) :: “memory” );

你可能感兴趣的:(GPU编程)