use Inline C; use strict; use warnings; # Assembly code via Inline::C to return the # 1. number of leading zeros of the input integer # 2. a number with only bit set where the MSSB is located # # by bliako # for https://perlmonks.org/?node_id=11158279 # 21/03/2024 my $z = 17; my $res = mssb($z); print "Leading zeros for $z : ".$res->[0]."\n"; print "MSSB for $z : ".sprintf("%032b\n", $res->[1])."\n"; # result: # Leading zeros for 17 : 27 # MSSB for 17 : 00000000000000000000000000010000 __END__ __C__ #include AV * mssb(int input){ int num_leading_zeros; int mssb; asm volatile( /* note: lzcnt inp, out mov src, dst add what, dst # set bit of value in dst at zero-based bitposition: btsl bitposition, dst (it modifies dst) */ "lzcnt %[input], %[num_leading_zeros] \n\t\ mov $32, %%eax \n\t\ sub %[num_leading_zeros], %%eax \n\t\ sub $1, %%eax \n\t\ xor %[mssb], %[mssb] \n\t\ bts %%eax, %[mssb] \n\t\ " /* outputs */ : [num_leading_zeros] "=r" (num_leading_zeros) , [mssb] "=r" (mssb) /* inputs */ : [input] "mr" (input) /* clobbers: we are messing with these registers */ : "eax" ); // return an arrayref of the two outputs AV* ret = newAV(); sv_2mortal((SV*)ret); av_push(ret, newSViv(num_leading_zeros)); av_push(ret, newSViv(mssb)); return ret; }