chapter 7: subroutines lecture notes to accompany the text book sparc architecture, assembly...

24
Chapter 7: Subroutines Lecture notes to accompany the text book SPARC Architecture, Assembly Language Programming, and C, by Richard P. Paul, 2 nd edition, 2000 Abinashi Dhungel

Upload: howard-poole

Post on 18-Dec-2015

216 views

Category:

Documents


3 download

TRANSCRIPT

Chapter 7: Subroutines

Lecture notes to accompany the text book SPARC Architecture, Assembly Language Programming, and C, by Richard P. Paul, 2nd

edition, 2000

Abinashi Dhungel

Introduction• Subroutines

– makes it possible to repeat computation or repeat computation with different arguments.

• Open Subroutine : – handled by text editor / macro preprocessor – The code is inserted whenever required in the program– Efficient with no wasted instructions– Results in long code

• Closed Subroutine:– appears only once in the program, – a jump to the code is executed whenever it is needed and – return is made after the subroutine has been executed to the

location after the jump instruction.

Introduction

• Subroutines– allows to debug code once and then to be sure

that all future instantiations of the code will be correct.

– provides for control of errors– basis for structured programming– specialized instruction• Should not change state of machine (except condition

codes)• Should restore all the registers temporarily used.

Register Saving

• Historically, required pushing all registers to stack and popping out at the end of subroutine execution.

• register save mask to indicate the registers to save. • SPARC provides register file with mapping registers

which indicate active registers– Typically, 128 registers available– Programmer can access 32 at a time (8 global and 24

mapped registers)– save changes mapping to provide new set of registers and

restore, restores mapping on subroutine return

Register Saving• 32 registers are divided into four groups : in, local, out and

global. • global %g0 - %g7 are not mapped and are global to all

subroutines• in registers %i0 - %i7 are used to pass arguments • local registers %l0 - %l7 are for subroutine’s local variables • out registers %o0 - %o7 are used to pass arguments to

subroutine that are called by current subroutine. • with save instruction out registers become in registers and

a new set of local and out registers is provided.• Mapping pointer is changed by 16 registers

Register Saving

• Current register set is indicated by the current window pointer, “CWP” (bits 0-4 inside PSR).

• Last free register set is marked by the window invalid mask register, “WIM”

• Each register set has 16 registers.• Number of register sets is implementation

dependent

save decreases cwp by 1, restore increases it by 1

• after further five subroutine calls without return• an additional subroutine call (causes window_overflow) moves the 16

registers from window set 7 to the stack where the %sp of register window set 6 is pointing.

Register saving

• After save instruction %o6 (%sp) becomes %i6(%fp). • save %sp, -96, %sp – subtracts 96 from the current stack pointer but saves the

result in the new stack pointer, leaving the old stack pointer unchanged.

– The old stack pointer becomes the new frame pointer• restore instruction restores the register window set. – window_underflow occurs if cwp is moved to wim. – restores the registers from the stack.– restore is also an add instruction.

Subroutine Linkage

• To branch to a subroutine a ba instruction might be used. However, there is no way to return to the point where the subroutine was called.

• In SPARC ,two instructions for linking to subroutine which save the address of calling instruction in %o7.

• return is to the address pointed by %o7 + 8. • inside the subroutine, since o7 is mapped to i7,

the return is made to %i7+8.

Subroutine Linkage• Calling a subroutine– jmpl

• jmpl %src_register [+ constant/register] (points address), %dest_register (for saving address of jmpl).

• jmpl %o0, %o7– call

• call label or %register (points address)• Transfers control to that address, and stores the address of call

into %o7.• call %o0 is expanded as jmpl %o0, %o7

• Return from subroutine– jmpl %i7 + 8, %g0– ret is expanded as jmpl %i7+8, %g0

call subr

nop

subr: save %sp, … %sp

ret

restore

Arguments

• Placing arguments in stack,– time consuming since each argument must be stored before

calling subroutine and should be moved back to register for any computation

– flexible since any number of arguments can be passed, supports recursive calls

• In, SPARC first 6 arguments can be placed in the out registers.

• Only 6 out registers are available since %o6 is stack pointer and %o7 is used for storing calling address.

• After save instruction the arguments will be available to subroutine in %i0-%i5

Arguments– 64 bytes for saving 16 registers starting at %sp– 4 bytes for structure return pointer at %sp + 64, – 24 bytes for 6 arguments starting at %sp + 68.

• (saving convention when window_overflow)

• additional arguments may be placed on stack starting at %sp + 92 and can be accessed by the called subroutine at %fp + 92

subroutine_name:save %sp, -(64 + 4 + 24 + args + local ) & -8, %sp

– where local variables are accessed at %fp – local_var_offset

Return Values

• Subroutines with return values - functions• value returned in register %o0• structure , the pointer can be passed on

%sp+64

/** C program to add two complex numbers **/struct complex {int re, im;};

struct complex complex_set(int re, int im) { struct complex c; c.re = re; c.im = im; return c;}

struct complex complex_add(struct complex* c1, struct complex* c2) { struct complex c; c.re = c1->re + c2->re; c.im = c1->im + c2->im; return c;}

main() {struct complex c, c1, c2;c1 = complex_set(1,2);c2 = complex_set(2,3);

c = complex_add(&c1, &c2); }

/**struct complex {int re, im;};**/

!structure fieldsre_offset = 0im_offset = 4size_str = 8

! space for 3 structures used in mainstr1_offset = -size_strstr2_offset = str1_offset - size_strstr3_offset = str2_offset - size_str

/**struct complex complex_set(int re, int im) { struct complex c; c.re = re; c.im = im; return c;}**/

.global complex_setcomplex_set:save %sp, -96 , %sp

ld [%fp + 64], %l0st %i0, [%l0 + re_offset]st %i1, [%l0 + im_offset]

retrestore

/**struct complex complex_add(struct complex* c1, struct complex* c2) { struct complex c; c.re = c1->re + c2->re; c.im = c1->im + c2->im; return c;}**/

.global complex_addcomplex_add:save %sp, -96, %spld [%fp + 64], %l0

!add and store real partld [%i0 + re_offset], %o0ld [%i1 + re_offset], %o1add %o0, %o1, %o0st %o0, [%l0 + re_offset]

!add and store im partld [%i0 + im_offset], %o0ld [%i1 + im_offset], %o1add %o0, %o1, %o0st %o0, [%l0 + im_offset]

retrestore

.global mainmain:

save %sp, (-92+str3_offset)&-8 , %sp

!initialize the first structureadd %fp, str1_offset, %l0 st %l0, [%sp+64]mov 1, %o0mov 2, %o1call complex_setnop

!initialize the second structureadd %fp, str2_offset, %l1 st %l1, [%sp+64]mov 2, %o0mov 3, %o1call complex_setnop

!add the complex numbers stored in the two structuresadd %fp, str3_offset, %l2st %l2, [%sp+64]mov %l0, %o0mov %l1, %o1call complex_addnop

mov 1, %g1ta 0

/**main() {struct complex c, c1, c2;c1 = complex_set(1,2);c2 = complex_set(2,3);

c = complex_add(&c1, &c2); }**/

Subroutines with more than 6 arguments

arg7_offset = 92arg8_offset = arg7_offset + 4stack_size = arg8_offset + 4

.global mainmain: save %sp, (-stack_size)&-8, %sp… …

mov 70, %l0st %l0, [%sp + arg7_offset]mov 20, %l0call foost %l0, [%sp + arg8_offset]

/** int foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { return a1+a2+a3+a4+a5+a6+a7+a8; } **/

.global foofoo: save %sp, -96, %sp

… …

!load 7th and 8th argumentsld [%fp+arg7_offset], %l0add %l0, %i0, %i0

ld [%fp+arg8_offset], %l0add %l0, %i0, %i0

retrestore

• May be stored in stack• The calling subroutine must make

enough space for the extra arguments

Leaf Subroutines

.global foofoo: !does not need save!save %sp, -96, %sp

… …

!load 7th and 8th argumentsld [%sp+arg7_offset], %o1add %o1, %o0, %o0

ld [%fp+arg8_offset], %o1!add %o1, %o0, %o0

retladd %o1, %o0, %o0

• Subroutines that do not call any other subroutines

• Can be made efficient by working on same register sets of the parent subroutine.• register use should be restricted

to %o0 - %o5, %g0, %g1. • Does not require restore or save• Return to parent is to %o7 + 8

instead of %i7 + 8• retl is expanded as

jmpl %o7 + 8, %g0

Pointers as argumentsa_offset = -4;b_offset = -8;

.global mainmain:save %sp, (-92+b_offset)&-8, %sp

mov 5, %o0st %o0, [%fp + a_offset];mov 7, %o1st %o1, [%fp + b_offset];

add %fp, a_offset, %o0call swapadd %fp, b_offset, %o1

mov 1, %g1ta 0

.global swapswap:ld [%o0], %o2ld [%o1], %o3

st %o3, [%o0]retlst %o2, [%o1]

swap(int *a, int *b) { int temp ; temp = *a; *a = *b; *b = temp;}