Download presentation
Presentation is loading. Please wait.
Published byHoward Poole Modified over 9 years ago
1
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
2
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.
3
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.
4
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
5
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
7
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
8
save decreases cwp by 1, restore increases it by 1
9
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.
10
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.
11
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.
12
Subroutine Linkage Calling a subroutine – jmpl jmpl%src_register [+ constant/register] (points address), %dest_register (for saving address of jmpl). jmpl %o0, %o7 – call calllabel 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
13
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
14
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
16
Return Values Subroutines with return values - functions value returned in register %o0 structure, the pointer can be passed on %sp+64
17
/** 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); }
18
/** struct complex { int re, im; }; **/ !structure fields re_offset = 0 im_offset = 4 size_str = 8 ! space for 3 structures used in main str1_offset = -size_str str2_offset = str1_offset - size_str str3_offset = str2_offset - size_str
19
/** struct complex complex_set(int re, int im) { struct complex c; c.re = re; c.im = im; return c; } **/.global complex_set complex_set: save %sp, -96, %sp ld [%fp + 64], %l0 st %i0, [%l0 + re_offset] st %i1, [%l0 + im_offset] ret restore
20
/** 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_add complex_add: save %sp, -96, %sp ld [%fp + 64], %l0 !add and store real part ld [%i0 + re_offset], %o0 ld [%i1 + re_offset], %o1 add %o0, %o1, %o0 st %o0, [%l0 + re_offset] !add and store im part ld [%i0 + im_offset], %o0 ld [%i1 + im_offset], %o1 add %o0, %o1, %o0 st %o0, [%l0 + im_offset] ret restore
21
.global main main: save %sp, (-92+str3_offset)&-8, %sp !initialize the first structure add %fp, str1_offset, %l0 st %l0, [%sp+64] mov 1, %o0 mov 2, %o1 call complex_set nop !initialize the second structure add %fp, str2_offset, %l1 st %l1, [%sp+64] mov 2, %o0 mov 3, %o1 call complex_set nop !add the complex numbers stored in the two structures add %fp, str3_offset, %l2 st %l2, [%sp+64] mov %l0, %o0 mov %l1, %o1 call complex_add nop mov 1, %g1 ta 0 /** main() { struct complex c, c1, c2; c1 = complex_set(1,2); c2 = complex_set(2,3); c = complex_add(&c1, &c2); } **/
22
Subroutines with more than 6 arguments arg7_offset = 92 arg8_offset = arg7_offset + 4 stack_size = arg8_offset + 4.global main main: save %sp, (-stack_size)&-8, %sp … mov 70, %l0 st %l0, [%sp + arg7_offset] mov 20, %l0 call foo st %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 foo foo: save %sp, -96, %sp … !load 7th and 8th arguments ld [%fp+arg7_offset], %l0 add %l0, %i0, %i0 ld [%fp+arg8_offset], %l0 add %l0, %i0, %i0 ret restore May be stored in stack The calling subroutine must make enough space for the extra arguments
23
Leaf Subroutines.global foo foo: !does not need save !save %sp, -96, %sp … !load 7th and 8th arguments ld [%sp+arg7_offset], %o1 add %o1, %o0, %o0 ld [%fp+arg8_offset], %o1 !add %o1, %o0, %o0 retl add %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
24
Pointers as arguments a_offset = -4; b_offset = -8;.global main main: save %sp, (-92+b_offset)&-8, %sp mov 5, %o0 st %o0, [%fp + a_offset]; mov 7, %o1 st %o1, [%fp + b_offset]; add %fp, a_offset, %o0 call swap add %fp, b_offset, %o1 mov 1, %g1 ta 0.global swap swap: ld [%o0], %o2 ld [%o1], %o3 st %o3, [%o0] retl st %o2, [%o1] swap(int *a, int *b) { int temp ; temp = *a; *a = *b; *b = temp; }
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.