cs3843 syllabus outline lecture notes programming assignments recitations homework set up Homogeneous Arrays Homogeneous arrays are arrays where each element has the same data type and size. We will discuss One-dimensional arrays o size of array and elements o how to reference an element Two-dimensional arrays o size of elements, rows, and arrays o how to reference an element One-dimensional Array and Element Sizes For one-dimensional arrays in C, the lower bounds of the subscript is always zero. The size of each element is always the same. Some programming languages (e.g., PL/I) allow specification of both the lower bounds and upper bounds for each array dimension. Other languages use 1 as the lower bounds. Example declarations in C: char szString[10]; char *pszString[10]; long lvalM[5]; long *plvalM[5]; double dvalM[5]; double *pdvalM[5]; unsigned short usvalM[8]; How to reference an element in one-dimensional arrays Given array A having an element size of E, how do you find the address of element A[i]? sum the beginning address of A and i * E Using i in the calculation is determining element address Array Name szString pszString lvalM plvalM dvalM pdValM usvalM Element Size (bytes) 1 Total Array Size (bytes) 10 4 20 8 4 2 40 20 16 If β is the starting address of A and E is 4, this shows the address of each element. subscript 0 1 2 3 4 β β+E β+2E β+3E β+4E using a subscript reference. For most one-dimensional arrays of primitive data, what are the element sizes? 1, 2, 4, 8 In IA32 assembly code, is it necessary to multiply i by E? Code for sumArray 4 int sumArray(int iValueM[], int iCnt) 5 { 6 int i; 7 int isum = 0; 8 for (i = 0; i < iCnt; i++) 9 { 10 isum += iValueM[i]; 11 } 12 return isum; 13 } Using pointer advancement Another approach to referencing elements is pointer advancement. Use a register as a cursor pointer which will contain the address of the current array element. That cursor pointer register begins with the beginning address of the array. Advancing to the next element is done by adding the element size, E, to that register. Terminate the loop when the cursor pointer advances past the last element. If there are N elements in the array, terminate when we reach β+E*N. That sumArray using gcc -O0 which used subscript reference 3 .globl sumArray 4 .type 5 sumArray: 6 pushl 7 movl 8 subl 9 movl 10 movl 11 jmp 12 .L3: # # loop body # 13 movl 14 sall 15 addl 16 movl 17 addl 18 addl 19 .L2: # loop test 20 movl 21 cmpl 22 jl # After loop 23 movl 24 leave 25 ret sumArray, @function %ebp %esp, %ebp $16, %esp $0, -8(%ebp) $0, -4(%ebp) .L2 # # # # -4(%ebp), %eax $2, %eax 8(%ebp), %eax (%eax), %eax %eax, -8(%ebp) $1, -4(%ebp) # i -> %eax # i * 4 -> %eax # addr of array + i * 4 # value of element of array -> %eax # add element to isum # i++ -4(%ebp), %eax 12(%ebp), %eax .L3 # i -> %eax # compare i:iCnt # i < iCnt, continue loop -8(%ebp), %eax get 16 bytes on stack 0 -> isum 0 -> i jump to loop test # prepare isum for return 5 sumArray: # Register Usage: # %edx - address just past last element (endPtr) # %eax - work and then isum # %ecx - pointer cursor into array 6 pushl %ebp 7 movl %esp, %ebp # no locals, not calling anything, not modifying callee save registers # so we do not need automatic memory 8 movl 8(%ebp), %ecx # address of array -> %ecx 9 movl 12(%ebp), %eax # icnt -> %eax # determine end pointer 10 leal (%ecx,%eax,4), %edx # array addr + 4*icnt -> %edx 11 movl $0, %eax # 0 -> isum # # see if cursor >= endPtr, if so skip loop # 12 cmpl %edx, %ecx # compare cursor:endPtr 13 jae .L3 # if cursor >= endPtr, skip loop address is our end pointer. Two-dimensional Arrays C stores two-dimensional arrays in row major order. This means the entire first row is in memory followed by the entire second row, and so on. 14 .L6: # # Loop body # 15 addl 16 addl # # if cursor 17 cmpl 18 ja 19 .L3: # Why didn't we 20 popl 21 ret (%ecx), %eax $4, %ecx # Add element to sum # Add element size to pointer < endPtr, loop %ecx, %edx .L6 # compare endPtr:cursor # if endPtr > cursor, loop do a leave? %ebp int A[4][3]; Shown as two-dimensional: Column 0 Column 1 Row 0 0 1 Row 1 10 11 Row 2 20 21 Row 3 30 31 Shown contiguous in memory: 0 1 2 10 11 [0][0] [0][1] first row row 0 [0][2] [1][0] 12 [1][1] [1][2] second row (row 1) Column 2 2 12 22 32 20 21 22 30 [2][0] [2][1] third row (row 2) [2][2] [3][0] 31 32 [3][1] [3][2] fourth row (row 3) How big is a two-dimensional array Assuming an element is size E, the number of rows is R, and the number of columns is C: row size is E*C array size is E*C*R For A in the previous example: E is 4 R is 4 C is 3 Therefore, row size = E*C = 4*3 = 12 array size is E*C*R = 12 * 4 = 48 bytes How to reference an element in two-dimensional arrays Given array A having β as its beginning address element size of E R rows C columns How do you find the address of element A[i][j] using a subscript reference approach? β + rowSize*i + E*j Assume: i is in %eax j is in %ecx β is in %ebx E is 4 Depending on the value of C, what could we do to compute the address of element A[i][j]? Number of Instructions Columns (C) β + C*E*i + E*j β + (C*i + j) * E 2 leal (%ecx, %eax, 2), %edx leal (%ebx, %edx, 4), %edx The multiplication by E uses shifting since E is usually 1, 2, 4 or 8. 3 Depending on the value of C, multiple leal instructions or a imull instruction is used. 4 leal addl sall leal leal (%eax, %eax, 2), %edx %ecx, %edx 2, %edx (%ecx, %eax, 4), %edx (%ebx, %edx, 4), %edx leal addl sall leal sall addl sall (%eax, %eax, 4), %edx %ecx, %edx 2, %edx (%eax, %eax, 4), %edx 1, %edx %ecx, %edx 2, %edx 5 10 C code for function sum2dArray 4 int sum2dArray(int iValueM[][5], int iRowCnt) 5 { 6 int i; 7 int j; 8 int isum = 0; 9 for (i = 0; i < iRowCnt; i++) 10 { 11 for (j = 0; j < 5; j++) 12 { 13 isum += iValueM[i][j]; 14 } 15 } 16 return isum; 17 } sum2dArray using gcc -O0 # Parameters: # i 8(%ebp) iValueM[][5] - address of 2d array with 5 columns # i 12(%ebp) iRowCnt - count of rows in the 2d array # Locals: # -4(%ebp) i - row subscript # -8(%ebp) j - column subscript # -12(%ebp) iSum - sum of the elements 3 .globl sum2dArray 4 .type sum2dArray, @function 5 sum2dArray: 6 pushl %ebp 7 movl %esp, %ebp 8 subl $16, %esp 9 movl $0, -12(%ebp) # 0 -> iSum 10 movl $0, -4(%ebp) # 0 -> i 11 jmp .L2 # Jump to Outer Loop test # Outer Loop Body 12 .L5: 13 movl $0, -8(%ebp) # 0 -> j 14 jmp .L3 # Jump to inner loop test 15 .L4: # Inner Loop Body # Calculate the rowAddress &iValueM + i*20 # 16 movl -4(%ebp), %edx # i -> %edx 17 movl %edx, %eax # i -> %eax 18 sall $2, %eax # i * 4 -> %eax 19 addl %edx, %eax # i * 5 -> %eax 20 sall $2, %eax # i * 20 -> %eax. 20 is row size 21 movl %eax, %edx # i * 20 -> %edx 22 addl 8(%ebp), %edx # add &iValueM to %edx. This is # the rowAddress 23 movl -8(%ebp), %eax # j -> %eax # The next instruction computes the address of the element by # adding j*4 and the row address. It then takes the element's value # and places it in %eax 24 movl (%edx,%eax,4), %eax # value at (j*4 + rowAddress) -> %eax 25 addl %eax, -12(%ebp) # Add element value to iSum 26 addl $1, -8(%ebp) # j++ 27 .L3: # Inner Loop Test 28 cmpl $4, -8(%ebp) # compare j:4 29 jle .L4 # if j <= 4, stay in inner loop # After Inner Loop 30 addl $1, -4(%ebp) # i++ 31 .L2: # Outer loop test 32 movl -4(%ebp), %eax # i -> %eax 33 cmpl 12(%ebp), %eax # compare i:iRowCnt 34 jl .L5 # if i < iRowCnt, loop to .L5 # After Outer loop 35 movl -12(%ebp), %eax # return iSum 36 leave 37 ret How can we make lines 16-25 more efficient? We had: 16 17 18 19 20 21 22 %edx. 23 24 25 movl movl sall addl sall movl addl -4(%ebp), %edx %edx, %eax # $2, %eax # %edx, %eax # $2, %eax # %eax, %edx # 8(%ebp), %edx # # i -> %edx i -> %eax i * 4 -> %eax i * 5 -> %eax i * 20 -> %eax. i * 20 -> %edx add &iValueM to movl movl addl -8(%ebp), %eax # j -> %eax (%edx,%eax,4), %eax # element value %eax, -12(%ebp) # Add element value More efficient for 5 columns, but using subscripts 16 movl -4(%ebp), %eax # i -> %eax 17 leal (%eax,%eax,4), %edx # i*5 -> %edx 18 addl -8(%ebp), %edx # i*5 + j -> %edx 19 movl 8(%ebp), %ecx # &iValueM -> %ecx # next instruction computes the address of the element and moves its # value to %eax 20 movl (%ecx,%edx,4), %eax # element value in %eax 21 addl %eax, -12(%ebp) # Add element value to iSum