Bitwise Multiplication with Shifts and Adds

I’ve been learning some x86 assembly over the past week.

Something that assembly language does really well (even better than a higher level language such as C) is bit manipulation. For example, here is a way to multiply two 32 bit unsigned integers using only shifts and adds. This is an interesting exercise because shifts and adds are among the most low-level operations a CPU can perform, and it seems likely that the MUL instruction is in practice implemented using some combination of shifts and adds.

To see how this is possible, we first realise that any number can be written as a sum of powers of 2:

E.g. 42 = 32 + 8 + 2 = 2^5 + 2^3 + 2^1 = \text{0001 0101b}

Due to the distributive property of multiplication, when we multiply a number, we can multiply by the powers of two and sum:

20 \times 42 = 20 \times (32 + 8 + 2) = 20 \times (2^5 + 2^3 + 2^1)

And in binary, multiplying by a power of two is simply a bit-shift to the left:

20 \times 2^1 = \text{0000 0010 1000b}
20 \times 2^3 = \text{0000 1010 0000b}
20 \times 2^5 = \text{0010 1000 0000b}

So for each power of two of 42, we can multiply by shifting 20 by the required number of bits and accumulating the result:

20 \times 42 = \text{0011 0100 1000b}

Here is the listing in MASM. The actual multiplication loop is just 5 lines of code.

; Binary Multiplication
.code
main PROC
	mov		eax,42
	mov		ebx,20
	call	bitmul
						; EAX = 840
	exit
main ENDP


; Multiplies an unsigned 32 bit integer in EAX by EBX
; Receives: EAX = uint32, EBX = uint32
; Returns: EAX
bitmul PROC
	push	edx			; save used registers
	push	ecx
	mov		edx, eax	; store original multiplicand into EDX
	mov		ecx, 32		; loop for 32 bits
	mov		eax, 0		; eax will accumulate the result

BeginLoop:
	shr		edx, 1		; shift lowest bit into carry flag
	jnc		DontAdd		; jump if carry flag not set
	add		eax, ebx
DontAdd:
	shl		ebx, 1		; shifting multiplies EBX by 2
	loop	BeginLoop

	pop		ecx			; restore used registers
	pop		edx
	ret
bitmul ENDP

END main