Firstly, m1, m2, m3 could be written in binary form as: 01010101..., 00110011...., 0000111100001111.... In fact ,we could add more m according to the same rules.
This part of code
(z & m1) + ((z >> 1) & m1)
could be break into three steps:
store all digits with odd index(right to left), for example, (1011 & m1) will get (0001),
similarly, store all digits with even index((1011 >> 1) & m1) will get (0101)
add them together: (0001 + 0101 = 0110). Divide 0110 into : (01 10) and change them into decimal: (1 2)
We could regard (z & m1) + ((z >> 1) & m1) as a "folding" function. Regard the original digit as an array of 1-digit, binary numbers: [1, 0, 0, 1] , the folder will change the original array into 2-digit, binary numbers: [01(1), 10(2)].
Similarly, folder functions also use m2, m3.... By applying the folder function simutaniously, the array will become 4-digit, 8-digit...until reach any sufficiently large number of digit (sorry for my english but hope you could understand). Finally it will be folded into an array with only one element, which is the result of Hamming distance.