Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Computer Organization and Design Addressing Modes Montek Singh Mon, Jan 31, 2011 Lecture 4 Operands and Addressing Modes • • • • Where is the data? Addresses as data Names and Values Indirection Reading: Ch. 2.3 Just enough C For our purposes C is almost identical to JAVA except: C has “functions”, JAVA has “methods”. function == method without “class” i.e., a global method C has “pointers” explicitly JAVA has them but hides them under the covers. C pointers int i; int a[10]; int *p; // simple integer variable // array of integers // pointer to integer(s) *(expression) is content at memory address computed by expression a[k] == *(a+k) a is a constant of type “int *” a[k] = a[k+1] EQUIV *(a+k) = *(a+k+1) Legal uses of C Pointers int i; int a[10]; int *p; // simple integer variable // array of integers // pointer to integer(s) p = &i; p = a; p = &a[5]; *p *p = 1; *(p+1) = 1; p[1] = 1; p++; // // // // // // // // & means address of no need for & on a address of 6th element of a value of location pointed by p change value of that location change value of next location exactly the same as above step pointer to the next element Legal uses of Pointers int i; // simple integer variable int a[10]; // array of integers int *p; // pointer to integer(s) So what happens when p = &i; What is value of p[0]? What is value of p[1]? C Pointers vs. object size Does “p++” really add 1 to the pointer? NO! It adds 4. Why 4? char *q; ... q++; // really does add 1 Clear123 void clear1(int array[], int size) { for(int i=0; i<size; i++) array[i] = 0; } void clear2(int *array, int size) { for(int *p = &array[0]; p < &array[size]; p++) *p = 0; } void clear3(int *array, int size) { int *arrayend = array + size; while(array < arrayend) *array++ = 0; } Pointer summary In the “C” world and in the “machine” world: a pointer is just the address of an object in memory size of pointer is fixed regardless of size of object to get to the next object: in machine code: increment pointer by the object’s size in bytes in C: increment pointer by 1 to get the ith object: in machine code: add i*sizeof(object) to pointer in C: add i to pointer Examples: int R[5] R is int* constant address; 20 bytes storage R[i] *(R+i) int *p = &R[3] p = (R+3) (p points 12 bytes after start of R) Last Time - “Machine” Language 32-bit (4-byte) ADD instruction: 00000000100000100001100000100000 op = R-type Rs Means, to MIPS, Rt Rd func = add Reg[3] = Reg[4] + Reg[2] But, most of us would prefer to write add $3, $4, $2 (ASSEMBLER) or, better yet, a = b+c; (C) Revisiting Operands Operands – the variables needed to perform an instruction’s operation Three types in the MIPS ISA: Register: add $2, $3, $4 # operands are the “contents” of a register Immediate: addi $2,$2,1 # 2nd source operand is part of the instruction Register-Indirect: lw $2, 12($28) # source operand is in memory sw $2, 12($28) # destination operand is memory Simple enough, but is it enough? Common “Addressing Modes” MIPS can do these with appropriate choices for Ra and const Absolute (Direct): lw $8, 0x1000($0) – Value = Mem[constant] – Use: accessing static data Indirect: lw $8, 0($9) – Value = Mem[Reg[x]] – Use: pointer accesses Displacement: lw $8, 16($9) – Value = Mem[Reg[x] + constant] – Use: access to local variables Indexed: Memory indirect: – Value = Mem[Mem[Reg[x]]] – Use: access thru pointer in mem Autoincrement: – Value = Mem[Reg[x]]; Reg[x]++ – Use: sequential pointer accesses Autodecrement: – Value = Reg[X]--; Mem[Reg[x]] – Use: stack operations Scaled: – Value = Mem[Reg[x] + Reg[y]] – Use: array accesses (base+index) – Value = Mem[Reg[x] + c + d*Reg[y]] – Use: array accesses (base+index) Is the complexity worth the cost? Need a cost/benefit analysis! From Hennessy & Patterson Memory Operands: Usage Usage of different memory operand modes Absolute (Direct) Addressing What we want: The contents of a specific memory location Examples: “C” int x = 10; main() { x = x + 1; } “MIPS Assembly” Allocates space for a single integer (4bytes) and initializes its value to 10 .data .global x x: .word 10 .text .global main main: lw $2,x($0) addi $2,$2,1 sw $2,x($0) Caveats In practice $gp is used instead of $0 Can only address the first and last 32K of memory this way Sometimes generates a two instruction sequence: lui lw $1,xhighbits $2,xlowbits($1) Indirect Addressing What we want: The contents at a memory address held in a register Examples: “C” int x = 10; main() { int *y = &x; *y = 2; } “la” is not a real instruction, It’s a convenient pseudoinstruction that constructs a constant via either a 1 instruction or 2 instruction sequence “MIPS Assembly” .data .global x x: .word 10 ori $2,$0,x lui ori $2,xhighbits $2,$2,xlowbits .text .global main main: la $2,x addi $3,$0,2 sw $3,0($2) Caveats You must make sure that the register contains a valid address (double, word, or short aligned as required) Displacement Addressing What we want: The contents of a memory location relative to a register Examples: “C” int a[5]; main() { int i = 3; a[i] = 2; } “MIPS Assembly” .data .global a a: .space 20 Allocates space for a 5 uninitialized integers (20bytes) .text .global main main: addi $2,$0,3 addi $3,$0,2 sll $1,$2,2 sw $3,a($1) Caveats Must multiply (shift) the “index” to be properly aligned Displacement Addressing: Once More What we want: The contents of a memory location relative to a register Examples: “C” struct p { int x, y; } main() { p.x = 3; p.y = 2; } “MIPS Assembly” .data .global p p: .space 8 .text .global main main: la $1,p addi $2,$0,3 sw $2,0($1) addi $2,$0,2 sw $2,4($1) Allocates space for 2 uninitialized integers (8-bytes) Caveats Constants offset to the various fields of the structure Structures larger than 32K use a different approach Conditionals C code: if (expr) { STUFF } MIPS assembly: (compute expr in $rx) beq $rx, $0, Lendif (compile STUFF) Lendif: C code: if (expr) { STUFF1 } else { STUFF2 } MIPS assembly: (compute expr in $rx) beq $rx, $0, Lelse (compile STUFF1) beq $0, $0, Lendif Lelse: (compile STUFF2) Lendif: There are little tricks that come into play when compiling conditional code blocks. For instance, the statement: if (y > 32) { x = x + 1; } compiles to: lw $24, y ori $15, $0, 32 slt $1, $15, $24 beq $1, $0, Lendif lw $24, x addi $24, $24, 1 sw $24, x Lendif: Loops MIPS assembly: while (expr) Lwhile: C code: { STUFF } (compute expr in $rx) beq $rX,$0,Lendw (compile STUFF) beq $0,$0,Lwhile Lendw: Alternate MIPS assembly: beq $0,$0,Ltest Lwhile: (compile STUFF) Ltest: (compute expr in $rx) bne $rX,$0,Lwhile Lendw: Compilers spend a lot of time optimizing in and around loops - moving all possible computations outside of loops - unrolling loops to reduce branching overhead - simplifying expressions that depend on “loop variables” For Loops Most high-level languages provide loop constructs that establish and update an iteration variable, which is used to control the loop’s behavior C code: int sum = 0; int data[10] = {1,2,3,4,5,6,7,8,9,10}; int i; for (i=0; i<10; i++) { sum += data[i] } MIPS assembly: sum: .word 0x0 data: .word 0x1, 0x2, 0x3, 0x4, 0x5 .word 0x6, 0x7, 0x8, 0x9, 0xa add $30,$0,$0 Lfor: lw $24,sum($0) sll $15,$30,2 lw $15,data($15) addu $24,$24,$15 sw $24,sum add $30,$30,1 slt $24,$30,10 bne $24,$0,Lfor Lendfor: Next Time We’ll write some real assembly code Play with a simulator Bring your Laptops!