CS5031 Exercises 5: Compiled ARM Code

Most of this code has been generated by a real C compiler available for the ARM. I don't expect you to get code as optimised as this (particularly the LSL operands). The compiler calls a routine (rt_sdiv) to do division.

1. Oh dear, how stupid to use a1 to a4 as variable names! I will rename them as x1 to x4, and keep a1 to a4 for the registers.

	b=v2, c=v1, j=v6, k=v5,	d=[fp,#&c], i=[fp,#&10]

	ADD	a1,v2,v2,LSL #2	;	b*5 [4+1]
	ADD	v3,v1,a1,LSL #1	;x1=b*10+c
	RSB	a1,v1,v1,LSL #4	;	c*15 [16-1]
	ADD	v4,a1,v2	;x2=b+c*15
	ADD	a1,v2,v1	;	b+c
	LDR	a3,[fp,#&c]	;	d
	MUL	a2,a3,a1	;a2=	(b+c)*d
	MUL	a1,v5,v6	;	j*k
	LDR	a4,[fp,#&10]	;	i
	ADD	a1,a1,a4	;a1=	i+j*k
	BL	 __rt_sdiv	;a1=a2/a1
	STR	a1,[sp,#4]	;x3=

	SUB	a2,v1,v2	;	c-b
	STR	a2,[sp,#0]	;x4=

	so x1=v3, x2=v4, x3=[sp,#4], x4=[sp,#0]

2.

	SUB	sp,sp,#&f0		;array size = 3*4*5*(4 bytes per int)
	. . .
	MOV	ip,#6
	ADD	a1,a4,a4,LSL #2		;a4 is i	*(4+1)*(4*4)
	ADD	a1,sp,a1,LSL #4		;sp is array origin
	ADD	lr,a2,a2,LSL #2		;a2 is j	*(4+1)*4
	ADD	a1,a1,lr,LSL #2
	STR	ip,[a1,a3,LSL #2]	;a3 is k	*4

3.

	MOV	a3,a1		;a3=a1=a
do	[body]
	CMP	a3,a2		;a2=b
	BLT	do

	MOV	a4,#0		;a4=i
again	CMP	a4,#&64		;i<100
	BLT	body
	B	end
body	[body]
	ADD	a4,a4,#1
	B	again
end

4. Here is a 4-byte wide picture of memory, with increasing addresses going down (which is probably the wrong way up compared to the lectures - sorry). cc, unladen_weight and gross_weight are all integers, which require a 4-byte word each. Everything else can fit into bytes (10 for make, and 7 for regno). A wasted byte is indicated by "- - -" but if we were smart and daring enough, we might save some space by moving "colour" to immediately follow "make". We have to be careful because users sometimes need the fields of the structure to stay in the same order, and not be moved around like this (i.e. because they are doing something silly).

	make0	make1	make2	make3
	make4	make5	make6	make7
	make8	make9	- - -	- - -
	. . . . . . . cc . . . . . . 
	taxed	regno0	regno1	regno2
	regno3	regno4	regno5	regno6
	colour	- - -	- - -	- - -
	. . . . unladen_weight . . . .
	. . . . gross_weight . . . . .

5. There are no parameters, and the local variables are all held in registers, but these registers have to be stacked on entry & restored on exit, so the stack frame just consists of the link, including the saved registers. I don't know exactly what the first 3 instructions do - you just need to stack the registers and make space for the variables.

test	MOV	ip,sp
	STMDB	sp!,{v1-v6,fp,ip,lr,pc}
	SUB	fp,ip,#4

	MOV	a1,#1
	MOV	v5,a1		;v5=m
	MOV	v3,a1		;v3=k
	MOV	v1,a1		;v1=j

	MOV	v2,#&64		;v2=i
for	CMP	v2,#&5a
	BGE	while
	B	end_for

while	CMP	v1,#&64		;v1=j
	BGE	dec

	TEQ	v3,#1		;if k==1
	BNE	end_if

	TEQ	v5,#2		;if m==2
	BNE	else
	ADD	v1,v1,#1
	B	end_if
else	ADD	v1,v1,#&a
end_if	B	while
dec	SUB	v2,v2,#1
	B	for

end_for	MOV	v4,#1		;x=1

	MOV	a2,v3		;	k
	MOV	a1,#&a		;	10
	BL	__rt_sdiv	;	/
	ADD	a1,a1,v1	;	j+k/10
	MLA	v6,v4,a1,v2	;	*x+i

	MOV	a1,#0		; return 0
	LDMDB	fp,{v1-v6,fp,sp,pc}