This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

28xx code: efficient method of determining if a 64-bit signed integer fits into a 32-bit signed integer

I'm looking for a way to determine if a 64-bit signed integer (long long) fits into a 32-bit signed integer. There must be an easy way to do this... yes?

  • I tried this:

    typedef long int32_t;
    typedef long long int64_t;

    bool canBeRepresentedAsInt32(int64_t z64)
    {
        int32_t z32 = (int32_t)z64;
        return (z64-z32) == 0;
    }

    and this is the cruddy job the compiler does (note the call to LL$$CMP when there's a perfectly good CMP64 instruction):

    _canBeRepresentedAsInt32__FL:
        .dwcfi    cfa_offset, -2
        .dwcfi    save_reg_to_mem, 26, 0
        .dwcfi    save_reg_to_reg, 78, 26
            ADDB      SP,#4
        .dwcfi    cfa_offset, -6
    ;* AR5   assigned to _z64
    $C$DW$5    .dwtag  DW_TAG_variable, DW_AT_name("z64")
        .dwattr $C$DW$5, DW_AT_TI_symbol_name("_z64")
        .dwattr $C$DW$5, DW_AT_type(*$C$DW$T$25)
        .dwattr $C$DW$5, DW_AT_location[DW_OP_reg14]
            MOVL      XAR6,P                ; |5|
            MOVL      XAR5,ACC              ; |5|
        .dwpsn    file "test64.cpp",line 7,column 2,is_stmt
            MOVL      ACC,XAR6              ; |7|
            MOVB      XAR4,#0
            ASR64     ACC:P,16              ; |7|
            ASR64     ACC:P,16              ; |7|
            MOVL      *-SP[4],P             ; |7|
            MOVL      *-SP[2],ACC           ; |7|
            MOVL      P,XAR6                ; |7|
            MOVL      ACC,XAR5              ; |7|
    $C$DW$6    .dwtag  DW_TAG_TI_branch
        .dwattr $C$DW$6, DW_AT_low_pc(0x00)
        .dwattr $C$DW$6, DW_AT_name("LL$$CMP")
        .dwattr $C$DW$6, DW_AT_TI_call
            FFC       XAR7,#LL$$CMP         ; |7|
            ; call occurs [#LL$$CMP] ; |7|
            CMPB      AL,#0                 ; |7|
            MOVB      XAR4,#1,EQ            ; |7|
            MOV       AL,AR4                ; |7|
        .dwpsn    file "test64.cpp",line 8,column 1,is_stmt
            SUBB      SP,#4
        .dwcfi    cfa_offset, -2
    $C$DW$7    .dwtag  DW_TAG_TI_branch
        .dwattr $C$DW$7, DW_AT_low_pc(0x00)
        .dwattr $C$DW$7, DW_AT_TI_return
            LRETR
            ; return occurs
        .dwattr $C$DW$1, DW_AT_TI_end_file("test64.cpp")
        .dwattr $C$DW$1, DW_AT_TI_end_line(0x08)
        .dwattr $C$DW$1, DW_AT_TI_end_column(0x01)
        .dwendentry
        .dwendtag $C$DW$1

     

    There should be a way to do it in 4 instructions (assembly pseudocode below):


        MOVL      ACC, [lower 32 bits]  ; P register can contain garbage
        ASR64     ACC:P,16  
        ASR64     ACC:P,16    ; right shift by 32
        CMPL      ACC, [upper 32 bits]

    which gives you the appropriate status flags for a conditional test.      

    But this isn't C-callable without adding the huge overhead of a function call, and intrinsics are no help here.

  • Here is one solution to consider ...

    #define HI(v64) ((uint32_t) (v64 >> 32))  // uint32_t defined in <stdint.h>
    #define FITS_IN_32(v64) ((HI(v64) == 0) | (~HI(v64) == 0))

    This uses the fact that, if the value fits in 32-bits, the upper half is all 0 or all 1's.  It is not as slick as your 4 instruction sequence, but it's an improvement.

    Hope this helps ...

    -George

  • Georgem said:
    This uses the fact that, if the value fits in 32-bits, the upper half is all 0 or all 1's.

    That's necessary but not sufficient, as it covers a range of 2^33 numbers, not 2^32. I need to exclude numbers smaller than -2^31 and larger than (2^31 - 1).

  • Could you please request a __cmp64() intrinsic to go along with the CMP64 instruction?

     

    Also, I continue to repeat my mantra that the compiler needs to have some way of allowing users to write their own short inline assembly sequences in a way that efficiently interfaces with C/C++. Inline assembly is rarely useful because there's no way to interface with local C/C++ variables. Intrinsics are poorly supported and not expandable. And writing C-callable assembly functions incurs the overhead of a function call, which is poor performance for a sequence of <10 assembly instructions. (viz. my other post http://e2e.ti.com/support/development_tools/compiler/f/343/t/31645.aspx )