Efficiently dividing unsigned value by a power of two, rounding up - in CUDA

前端 未结 6 1122
被撕碎了的回忆
被撕碎了的回忆 2021-01-21 09:28

I was just reading:

Efficiently dividing unsigned value by a power of two, rounding up

and I was wondering what was the fastest way to do this in CUDA. Of course

6条回答
  •  有刺的猬
    2021-01-21 10:17

    With funnel shifting available, a possible 32 bit strategy is doing a 33bit shift (essentially) preserving the carry of the addition so it be done before the shift, such as this: (not tested)

    unsigned sum = dividend + mask;
    unsigned result = __funnelshift_r(sum, sum < mask, log_2_of_divisor);
    

    Edit by @einpoklum:

    Tested using @RobertCrovella's program, seems to work fine. The test kernel PTX for SM_61 is:

        .reg .pred      %p<2>;
        .reg .b32       %r<12>;
    
    
        ld.param.u32    %r5, [_Z4testjj_param_0];
        ld.param.u32    %r6, [_Z4testjj_param_1];
        neg.s32         %r7, %r6;
        and.b32         %r8, %r6, %r7;
        clz.b32         %r9, %r8;
        mov.u32         %r10, 31;
        sub.s32         %r4, %r10, %r9;
        add.s32         %r11, %r6, -1;
        add.s32         %r2, %r11, %r5;
        setp.lt.u32     %p1, %r2, %r11;
        selp.u32        %r3, 1, 0, %p1;
        // inline asm
        shf.r.wrap.b32 %r1, %r2, %r3, %r4;
        // inline asm
        st.global.u32   [r], %r1;
        ret;
    

    and the SASS is:

    /*0008*/                   MOV R1, c[0x0][0x20];                 /* 0x4c98078000870001 */
    /*0010*/                   MOV R0, c[0x0][0x144];                /* 0x4c98078005170000 */
    /*0018*/                   IADD R2, RZ, -c[0x0][0x144];          /* 0x4c1100000517ff02 */
                                                                     /* 0x001c4c00fe4007f1 */
    /*0028*/                   IADD32I R0, R0, -0x1;                 /* 0x1c0ffffffff70000 */
    /*0030*/                   LOP.AND R2, R2, c[0x0][0x144];        /* 0x4c47000005170202 */
    /*0038*/                   FLO.U32 R2, R2;                       /* 0x5c30000000270002 */
                                                                     /* 0x003fd800fe2007e6 */
    /*0048*/                   IADD R5, R0, c[0x0][0x140];           /* 0x4c10000005070005 */
    /*0050*/                   ISETP.LT.U32.AND P0, PT, R5, R0, PT;  /* 0x5b62038000070507 */
    /*0058*/                   IADD32I R0, -R2, 0x1f;                /* 0x1d00000001f70200 */
                                                                     /* 0x001fc400fe2007f6 */
    /*0068*/                   IADD32I R0, -R0, 0x1f;                /* 0x1d00000001f70000 */
    /*0070*/                   SEL R6, RZ, 0x1, !P0;                 /* 0x38a004000017ff06 */
    /*0078*/                   MOV32I R2, 0x0;                       /* 0x010000000007f002 */
                                                                     /* 0x0003c400fe4007e4 */
    /*0088*/                   MOV32I R3, 0x0;                       /* 0x010000000007f003 */
    /*0090*/                   SHF.R.W R0, R5, R0, R6;               /* 0x5cfc030000070500 */
    /*0098*/                   STG.E [R2], R0;                       /* 0xeedc200000070200 */
                                                                     /* 0x001f8000ffe007ff */
    /*00a8*/                   EXIT;                                 /* 0xe30000000007000f */
    /*00b0*/                   BRA 0xb0;                             /* 0xe2400fffff87000f */
    /*00b8*/                   NOP;                                  /* 0x50b0000000070f00 */
    

提交回复
热议问题