Several--well 4--people have asked me off-list how the assembly-time 
construction of the table of one-bit counts can be automated.  Its manual 
construction by inspection is possible, though not I think advisable, for a 
table of the one-bit element counts for 0(1)255, which contains only 256 
values.  For a table of these counts for 0(1)65535, which contains 65536 
values, something else is required.  I have stripped a macro definition of 
bullet proofing, optimization, and the like with the result
 
         macro
         ONEBITSK &loGBLAid=,     --identifier, low input value                 
        *
               &hiGBLAid=,               --identifier, high input value         
               *
               &bkGBLAaid=             --identifier, one-bits count GBLAa
.*
.*
.*  counts the number of bits in each of the twos-complement binary
.*  fullword values &(&loGBLAid), &(&loGBLAid)+1, . . . , &(&hiGBLAid)
.*  and sets the successive elements of the array &(&bkGBLAaid)(1)
.*  equal to these count values.  For example, for 
.*
.*  |&idlo   setc  '__low__bound'    --low-bound identifier 
.*  |          gbla  &(&idlo)          --declare low-bound global
.*  |&(&idlo)  seta  0                 --initialize it
.*  |&idhi   setc  '__high_bound'    --high-bound identifier  
.*  |          gbla  &(&idhi)          --declare high-bound global
.*  |&(&idhi)  seta  7                 --initialize it
.*  |&o1aid  setc  '__out_n1bits'    --identifier, output array
.*  |           gbla  &(&o1aid)(1)      --declare output array
.*  |           ONEBITSK  loGBLAid=&idlo,hiGBLAid=&idhi,                        
  *
.*  |                   bkGBLAaid=&o1aid
.*  
.*  it sets
.*
.*   &(&olaid)(1) equal to 0 because '0000' contains 0 one bits
.*   &(&olaid)(2) equal to 1 because '0001' contains 1 one bit
.*   &(&olaid)(3) equal to 1 because '0010' contains 1 one bit 
.*   &(&olaid)(4) equal to 2 because '0011' contains 2 one bits 
.*   &(&olaid)(5) equal to 1 because '0100' contains 1 one bit
.*   &(&olaid)(6) equal to 2 because '0101' contains 2 one bits
.*   &(&olaid)(7) equal to 2 because '0110' contains 2 one bits
.*   &(&olaid)(8) equal to 3 because '0111' contains 3 one bits
.*
         gbla  &(&loGBLAid)       --low-bound global
         gbla  &(&hiGBLAid)       --high-bound global
         gbla  &(&bkGBLAaid)(1)   --bit-counts global array
&subscript_bias seta &(&loGBLAid)-1   --one-origin subscript bias
&i       seta  &(&loGBLAid)       --initialize element_loop subscript
.element_loop  anop ,             --top of element_loop
&i       seta  &i+1                    --increment element_loop index
&eoi    setb  (&i gt &(&hiGBLAid))    --end of interval reached?
           aif   (&eoi).element_lend   --if so, leave element_loop
&bitchars setc A2B(&i)            --BIF gets c/s representation of bits
&one_bit_counter seta 0         --initialize one-bits counter 
&j       seta  0                        --initialize bits_loop index
.bits_loop anop ,                    --top of bits_loop
&j       seta  &j+1                   --increment bits_loop index
&eos   setb  (&j gt 32)            --bit characters exhausted?
           aif   (&eos).bits_lend   --if so, leave bits_loop
&one_bit setb ('&bitchars'(&j,1) eq '1')   --is it a one bit?
&one_bit_counter seta &one_bit_counter+&one_bit   --increment by 0|1
          ago   .bits_loop            --next bit position da capo
.bits_lend anop ,                    --bottom of bits_loop
&k      seta   &i-&subscript_bias    --one-origin output-array subscript
&(&bkGBLAaid)(&k) seta &one_bit_counter  --stow one-bits count
         ago   .element_loop      --next element da capo
.element_lend anop  ,            --bottom of element_loop 
         mexit  ,                        --macro-expanded exit
         mend

This macro is "very inefficient", but notional compile-time inefficiency is a 
small price to pay for ensuring that a generated execution-time table is 
correct.  Readers who are unfamiliar with created set symbols will find it 
opaque but not unintelligible.  It is also an illustration of macro of the sort 
that mathematicians call a lemma: it is of no independent interest, and it does 
not itself generate code.  Its function is instead to facilitate and simplify 
the work of another macro or macros that do generate code. 

John Gilmore Ashland, MA 01721-1817 USA




                                          

Reply via email to