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?
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.
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
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).Georgem said:This uses the fact that, if the value fits in 32-bits, the upper half is all 0 or all 1's.
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 )