Slide Set 2 for ENCM 369 Winter 2014 Lecture Section 01 Steve Norman, PhD, PEng Electrical & Computer Engineering Schulich School of Engineering University of Calgary Winter Term, 2014 ENCM 369 W14 Section 01 Slide Set 2 slide 2/49 Contents ENCM 369 W14 Section 01 Slide Set 2 slide 3/49 ENCM 369 W14 Section 01 Slide Set 2 slide 4/49 (This continues material from Slide Set 1.) Pseudo are lines of A.L. that look like, but do not correspond exactly to real machine. Examples from the previous slide set include blt and la. Another example: move $t1, $t0 # copy $t0 value into $t1 The assembler will read this and generate a real machine instruction, something like this: add $t1, $zero, $t0 ENCM 369 W14 Section 01 Slide Set 2 slide 5/49 Pseudo that have real-instruction mnemonics This is one of the more confusing aspects of the MIPS assembly language. Here are a few examples... A.L. code add $t0,$t0,1 addi $s1,$s0,0x12345 lw $t9, label Remarks A true add has 3 GPR operands. Assembler generates an addi instruction. Constant too big to fit in 16 bits. Assembler generates a 3-instruction sequence. Assembler generates a 2-instruction sequence; 2nd instruction is lw with address built from GPR and offset. ENCM 369 W14 Section 01 Slide Set 2 slide 6/49 Avoid using pseudo in ENCM 369 labs Every now and then using a pseudoinstruction can save you a small amount of typing, but doing so slows down learning of the real MIPS instruction set. Exception: Use la GPR, label whenever you like. There is no convenient way to get the same effect with real. Pseudo are briefly described in Section 6.7.2 of the textbook. The Help facility built into MARS provides separate lists of all the real and pseudo supported by MARS.
ENCM 369 W14 Section 01 Slide Set 2 slide 7/49 ENCM 369 W14 Section 01 Slide Set 2 slide 8/49 Procedure is the A.L. term for a thing like a C function (sometimes called a subroutine or method in other high-level languages). This is a complex topic, and will require several lectures. We ll study rules that allow coding of A.L. programs with hundreds or thousands of procedures and procedure calls! (But lab programs will usually only have 2, 3, or 4 procedures.) ENCM 369 W14 Section 01 Slide Set 2 slide 9/49 Procedures: The first few subtopics ENCM 369 W14 Section 01 Slide Set 2 slide 10/49 Procedures: Subtopics we ll get to later Flow of instruction execution, MIPS jal and jr. Passing arguments in GPRs $a0 $a3, returning a value in GPR $v0. Definitions for the terms leaf and nonleaf. Problems with conflicts over GPRs. (How can many procedures cooperate to share the same small set of GPRs?) Programming the stack in A.L. Using the stack to help with register conflicts. Using the stack to allocate local variables in memory. (Remember, some variables are in GPRs and others are in memory.) ENCM 369 W14 Section 01 Slide Set 2 slide 11/49 Flow of instruction execution, call and return operations In machine language, a procedure is just a sequence of. Suppose a program has two procedures: main and foo. Suppose main calls foo. When foo is done there is a return to main. "CALL" "RETURN" memory of main of foo lower addresses higher addresses ENCM 369 W14 Section 01 Slide Set 2 slide 12/49 Call and return operations in MIPS: jal and jr CALL: A jal (jump and link) instruction in main causes a jump to the first instruction of foo. RETURN: The last instruction in foo is a jr (jump to address in register) instruction. This causes a jump back to the instruction just after the jal instruction in main. "CALL" "RETURN" memory of main of foo lower addresses higher addresses
ENCM 369 W14 Section 01 Slide Set 2 slide 13/49 The concept of a return address, and the MIPS $ra register ENCM 369 W14 Section 01 Slide Set 2 slide 14/49 Differences between j, jal, and jr For the return operation in the given example program to work correctly, information had to be recorded about where to resume execution in main when foo was done. GPR 31 in MIPS, called $ra, is used for this purpose. To see how $ra is used, let s sketch out assembly language code for main and foo. j uses a label to identify the jump target. j does not touch $ra. jal uses a label, too. But jal also updates $ra to note where to come back to when the called procedure has finished. jr does not use a label instead it looks in a GPR to find the jump target address. ENCM 369 W14 Section 01 Slide Set 2 slide 15/49 Remarks about jal and jr ENCM 369 W14 Section 01 Slide Set 2 slide 16/49 Useful terms: caller and callee The word link in jump and link means remember how to come back. (But jarhtcb would be too long as an instruction mnemonic!) jr is most often used with $ra for procedure return, but can be used with other GPRs for other purposes. The r in jr stands for register, not return. A procedure call involves two procedures: the caller, and the callee. The caller makes the call to the callee. When the callee is done there is a return back to the caller. In the earlier example, main was the caller and foo was the callee. ENCM 369 W14 Section 01 Slide Set 2 slide 17/49 Arguments and return values ENCM 369 W14 Section 01 Slide Set 2 slide 18/49 Example procedure with arguments and a return value The caller sometimes needs to send argument values ( args ) to the callee. The callee sometimes needs to send a return value ( r.v. ) back to the caller. In MIPS certain GPRS are reserved for arguments and return values. Which GPRs are they and what rules govern their use? What would be correct MIPS A.L. for the following C function? int quux(int a, int b, int c) return a - b + c;
ENCM 369 W14 Section 01 Slide Set 2 slide 19/49 Limits to the uses of GPRs for arguments and return values ENCM 369 W14 Section 01 Slide Set 2 slide 20/49 Very important terms: leaf and nonleaf The rules we ve just learned work well, if the number of arguments is 4 and all arguments and return values are ints or pointers. What if there are > 4 arguments? What if an arg or r.v. is of type double? Or of a C struct type? Those won t fit in GPRs. We ll ignore all these issues for now, but more complicated rules do exist to handle these cases. It s very important to know what these terms mean, because they will be used a lot in upcoming discussion of how to make procedures work correctly. Let s carefully write down the definitions. Is quux (our most recent example) leaf or nonleaf? ENCM 369 W14 Section 01 Slide Set 2 slide 21/49 Examples of nonleaf procedures in C ENCM 369 W14 Section 01 Slide Set 2 slide 22/49 void f() g(); int func1(int x) if (x < 0) x = func2(x); return x + 17; int factorial(int n) if (n == 0) return 1; else return n * factorial(n - 1); Let s make some notes about each of these procedures. ENCM 369 W14 Section 01 Slide Set 2 slide 23/49 Introduction to register conflict problems ENCM 369 W14 Section 01 Slide Set 2 slide 24/49 First example of register conflict: Use of $ra Consider a program with hundreds of procedures. In MIPS there are only 32 GPRs. (ARM and x86-64 have only 16, and x86 has only 8!) It s very likely that at many times during a run of the program, two or more different procedures might simultaneously want to use a single GPR for two or more different purposes. This kind of situation is called a register conflict. For the C code on the left, a programmer proposes the A.L. on the right as a translation of f2... int f1(void); int f2(void) return 16 * f1(); # This will NOT WORK! f2: jal f1 sll $v0,$v0,4 # f2 rv = 16 * f1 rv jr $ra Let s assume that f1 is coded correctly, and that f2 is called by main. What happens when f2 runs?
ENCM 369 W14 Section 01 Slide Set 2 slide 25/49 How many return addresses have to be maintained at the same time? Suppose main calls alpha, alpha calls beta, beta calls gamma, and gamma calls delta. When delta is running, how many different return addresses must the program remember? ENCM 369 W14 Section 01 Slide Set 2 slide 26/49 Solution to $ra conflict problem Every nonleaf procedure needs to make a backup copy of the $ra contents before it makes any procedure calls that way, return address information will not be lost. The best place for these backup copies is a region of memory called the stack. It does not make sense to use a lot of different GPRs for different return addresses, one GPR per address that would use too many GPRs, and put a limit on how long a chain of procedure calls could be. ENCM 369 W14 Section 01 Slide Set 2 slide 27/49 The stack, and other regions in memory address space ENCM 369 W14 Section 01 Slide Set 2 slide 28/49 How the stack works in MIPS The stack is one of three main regions of memory address space used by a program. The other two are... The text segment: Where are located. (The word text is confusing are not sequences of character codes!) The data segment: Used for statically allocated data. May also be used for dynamically allocated chunks of data obtained with malloc in C or new in C++. The stack is an array of words with addresses from 0x7fff_fffc down to whatever address is in the stack pointer register $sp, which is GPR 29. How can the stack be made to grow by N words? How can it be made to shrink by N words? The bottom boundary of the stack, as shown on the handout, moves up and down as $sp is updated. ENCM 369 W14 Section 01 Slide Set 2 slide 29/49 Fixing a defect ENCM 369 W14 Section 01 Slide Set 2 slide 30/49 Which Way Is Up? Here is C code and a proposed MIPS A.L. translation from a few slides back... int f1(void); int f2(void) return 16 * f1(); # This will NOT WORK! f2: jal f1 sll $v0,$v0,4 # f2 rv = 16 * f1 rv jr $ra How can we use the stack to help in writing correct A.L. code for f2? In textbooks and manuals related to computer organization, there are many diagrams (or maps ) of memory. Some diagrams show higher addresses nearer the top of a page or screen, and others show higher addresses nearer the bottom. Lectures in this course have already done both! When reading diagrams, take time to figure out Which Way Is Up. When drawing diagrams, indicate clearly Which Way Is Up.
ENCM 369 W14 Section 01 Slide Set 2 slide 31/49 ENCM 369 W14 Section 01 Slide Set 2 slide 32/49 int alpha(void) // Plan: use $s0 // for b, $s1 for c. int b, c; b = beta(); c = gamma(); return c + b * 8; What if alpha s caller is also using $s0 or $s1? Or alpha s caller s caller, or alpha s caller s caller s caller? And so on... In a program with hundreds of procedures, you do NOT want to check them ALL for conflicting uses of $s0 and $s1! ENCM 369 W14 Section 01 Slide Set 2 slide 33/49 Sketch of solution to s-register conflict problem ENCM 369 W14 Section 01 Slide Set 2 slide 34/49 MIPS A.L. code for alpha Before alpha starts using $s0 or $s1, alpha should use the stack to save copies of $s0 and $s1 in case alpha s caller (or caller s caller, caller s caller s caller, etc.) is also using $s0 or $s1. After alpha has finished using $s0 and $s1, and just before alpha returns, alpha should read the old values of $s0 and $s1 back from the stack into $s0 and $s1. int alpha(void) // Plan: use $s0 // for b, $s1 for c. int b, c; b = beta(); c = gamma(); return c + b * 8; Let s write a complete A.L. implementation of alpha, then study how it will behave. ENCM 369 W14 Section 01 Slide Set 2 slide 35/49 Saving s-registers on the stack: General remarks ENCM 369 W14 Section 01 Slide Set 2 slide 36/49 Saving s-registers on the stack: General remarks The rule is: All s-registers used by a procedure should have their values saved on the stack near the beginning of that procedure, and restored from the stack near the end. The rule is really good for big programs. In a program with hundreds of procedures, every procedure can use up to eight s-registers without any worry about overwriting variables of other procedures. A possible objection: Sometimes a procedure could save and restore, for example, $s4, even though none of the caller, caller s caller, etc. were using $s4. Wouldn t this be a waste of time and stack space? Answer: Yes, that would be very slightly wasteful, but the waste is acceptable as a tradeoff for the simplicity of being able to use s-registers in any one procedure without checking s-register use in all the other procedures.
ENCM 369 W14 Section 01 Slide Set 2 slide 37/49 What about t-registers? ENCM 369 W14 Section 01 Slide Set 2 slide 38/49 // a, b, c are ints // in $s0, $s1, $s2. // f returns an int. c = a + b + f(7); # This might or # might not work! add $t0, $s0, $s1 # $t0 = a + b addi $a0, $zero, 7 # $a0 = 7 jal f add $s2, $t0, $v0 # c = $t0 + f rv What is dangerous about the A.L. code? How could the A.L. code be reorganized to avoid this risk? What if the C code were c = f(a) + f(b);? ENCM 369 W14 Section 01 Slide Set 2 slide 39/49 ENCM 369 W14 Section 01 Slide Set 2 slide 40/49 More useful procedure-related terms: prologue, body, epilogue A nonleaf procedure gets argument values from its caller in some or all of $a0-$a3, but may need some or all of $a0-$a3 to send argument values to its callees. Solution: Near the beginning of a procedure, incoming arguments should be copied from a-registers to other locations. After that is done, the a-registers are available for outgoing arguments. (We ve already seen a few pieces of terminology: caller, callee, leaf, nonleaf.) The prologue, body, and epilogue are all parts of procedures. Let s write down what each of these parts do. ENCM 369 W14 Section 01 Slide Set 2 slide 41/49 What are the other locations to which incoming args should be copied? ENCM 369 W14 Section 01 Slide Set 2 slide 42/49 Let s look at the A.L. code for fred for strategy (1) page 2 of the handout Two strategies can be used: (1) Copy the incoming args to s-registers in the prologue. (2) Copy the incoming args to the stack in the prologue. Pages 2 and 3 of the Jan 24/27/29 handout provide examples of both strategies. What is fred using $s0, $s1, and $s2 for? What does the stack frame of fred look like? Is the order of the in the prologue of fred important? (Could the add be done before the sw?) bob only takes one argument, in $a0. Why is it necessary for the prologue of fred to make copies of both $a0 and $a1?
ENCM 369 W14 Section 01 Slide Set 2 slide 43/49 Let s look at the A.L. code for fred for strategy (2) page 3 of the handout ENCM 369 W14 Section 01 Slide Set 2 slide 44/49 Which strategy is better for managing a-register conflicts? In strategy (2) the other locations for the arguments are stack slots words reserved within a procedure s stack frame. In the procedure body, access to the incoming arguments is done with lw and sw. Let s draw a diagram for the stack frame of fred, and make a few remarks about how this implementation of fred will work. copying incoming args to s-registers faster access to incoming args in body of procedure copying incoming args to stack slots prologue and epilogue are shorter reduced danger of running out of s-registers when there are a lot of incoming args and local variables So each strategy has an advantage relative to the other. ENCM 369 W14 Section 01 Slide Set 2 slide 45/49 ENCM 369 W14 Section 01 Slide Set 2 slide 46/49 Usually, local variables of nonleaf procedures can go in s-registers. Usually, local variables of leaf procedures can go in t-registers. But what if a local variable is an array? Or what if a local variable occupies a single word, but needs to have an address? In both cases, memory allocation is needed. Remember, registers do not have addresses! ENCM 369 W14 Section 01 Slide Set 2 slide 47/49 Example of local variables on the stack page 4 of Jan 24/27/29 handout The C function test_negatives has 3 local variables: count, sum, and x. count and sum need to have addresses, because &count and &sum are used in the call to negatives. So count and sum must be in memory. x is an array, so it too must be in memory. Solution: make space within the stack frame of test_negatives for count, sum, and x. Let s sketch a stack frame for test_negatives and write down a few remarks about it. ENCM 369 W14 Section 01 Slide Set 2 slide 48/49 A note about the test_negatives example The A.L. code for test_negatives did not use any s-registers, because all of the local variables of test_negatives had to be in memory. A more typical procedure might use s-registers for some local variables, and stack slots for other local variables.
ENCM 369 W14 Section 01 Slide Set 2 slide 49/49 Moving on... Lectures material on procedures and procedure calling conventions is now mostly finished. Pay attention to Lab 3 and Lab 4 exercises designed to help you learn this material.