CPSC 355: Tutorial 9

Arrays, Multidimensional Arrays

PhD Student

Fall 2017

Outline

  • Assignment 2
  • Linear arrays (with this, you should be able to finish assignment 3)
  • Multidimensional Arrays

Assignment 2

#include <stdio.h>

int main() 
{
	int multiplier, multiplicand, result_high, result_low, i, negative;
	long int result, temp1, temp2;

	multiplicand = -8192;
	multiplier = 99;

	result_high = 0;

	printf("multiplier = 0x%08x (%d) multiplicand = 0x%09x (%d) \n\n",
		multiplier, multiplier, multiplicand, multiplicand);

	negative = multiplier < 0 ? 1 : 0;

	for(i = 0; i < 32; i++) {
		if(multiplier & 1) {
			result_high = result_high + multiplicand;
		}

		multiplier = multiplier >> 1;

		if(result_high & 1) {
			multiplier = multiplier | 0x80000000;
		} else {
			multiplier = multiplier & 0x7FFFFFFF;
		}
		result_high = result_high >> 1;
	}

	if(negative) {
		result_high = result_high - multiplicand;
	}

	printf("result_high = 0x%08x, result_low = 0x0%08x\n", result_high, result_low);

	temp1 = (long int) result_high;
	temp1 = temp1 << 32;
	temp2 = (long int) multiplier & 0xFFFFFFFF;
	result = temp1 + temp2;

	printf("64-bit result: 0x%016lx (%ld)\n", result, result);
}

Assignment 2

#include <stdio.h>

int main() 
{
	int multiplier, multiplicand, result_high, result_low, i, negative;
	long int result, temp1, temp2;

	multiplicand = -8192;
	multiplier = 99;

	result_high = 0;

	printf("multiplier = 0x%08x (%d) multiplicand = 0x%09x (%d) \n\n",
		multiplier, multiplier, multiplicand, multiplicand);

        // Didn't do this...
	// negative = multiplier < 0 ? 1 : 0;

	for(i = 0; i < 32; i++) {
		if(multiplier & 1) {
			result_high = result_high + multiplicand;
		}
		multiplier = multiplier >> 1;
		if(result_high & 1) {
			multiplier = multiplier | 0x80000000;
		} else {
			multiplier = multiplier & 0x7FFFFFFF;
		}
		result_high = result_high >> 1;
	}
        // Did it here instead
	if(multiplier < 0) {
		result_high = result_high - multiplicand;
	}

	printf("result_high = 0x%08x, result_low = 0x0%08x\n", result_high, result_low);

	temp1 = (long int) result_high;
	temp1 = temp1 << 32;
	temp2 = (long int) multiplier & 0xFFFFFFFF;
	result = temp1 + temp2;

	printf("64-bit result: 0x%016lx (%ld)\n", result, result);
}

Assignment 2

Why is this incorrect?

The value of multiplier changes throughout the loop.

See tutorial 6 for a less complicated version of the code.

Linear Arrays

#include <stdio.h>
  
#define ARRAY_SIZE 10

int  main(int argc, char *argv[]) {
    unsigned long sum = 0;
    unsigned int i = 0;
    unsigned int array[ARRAY_SIZE];

    for(i = 0; i < ARRAY_SIZE; i++) {
        array[i] = rand();
    }

    for(i = 0; i < ARRAY_SIZE; i++) {
        sum = array[i] + sum;
        printf("array[%i] = %i (sum = %li)\n", i, array[i], sum);
    }
    return 0;
}

An array is really just a contiguous sequence of variables.

Let's start off with an example

Linear Arrays

Let's think about how our stack should look (each cell is 8 bytes)





Free memory




 
old stack

 $sp

Free memory
x29 (old $fp)
x30 (old $lr)
sum variable
i variable, array[0]
array[1], array[2]
...
array[9], ???
old stack

 $sp

Linear Arrays

Free memory
x29 ($fp)
x30 ($lr)
sum variable
i variable, array[0]
array[1], array[2]
...
array[9],  ???
old stack

 $sp

We need 16 bytes for fp and lr, 16 for sum and i (although we'll only use 12 of those) and 10 * 4 bytes for the array.

We need 72 bytes in total -- or 80 bytes when rounded up to the 16 byte stack boundary

stp  fp, lr, [sp, -80 & -16]!
mov  fp, sp

 $fp

Linear Arrays

// File: tut8ex1.asm
// Description: Sums a random list of numbers

    // Define the size of the array
    array_count = 10

    // Define the sizes of the variables on the stack
    array_size = array_count * 4    // 4 bytes for an integer
    i_size     = 4                  // 4 bytes int
    sum_size   = 8                  // 8 bytes for a long

    // Define the offsets from the frame pointer
    sum_so     = 16
    i_so       = sum_so + sum_size
    array_so   = i_so + i_size

    // Sum up all the sizes
    var_size   = array_size + i_size + sum_size
    
    alloc      = -(16 + var_size) & -16
    dealloc    = -alloc

fp             .req   x29
lr             .req   x30

fmt1:    .string  "array[%i] = %i (sum = %li)\n"

	.balign 4
	.global main
main: 
        stp  fp, lr, [sp, alloc]!
        mov  fp, sp

        // more code...

        mov w0, 0                // setup 0 return code
        ldp  fp, lr, [sp], dealloc
        ret
Free memory
x29 ($fp)
x30 ($lr)
sum variable
i variable, array[0]
array[1], array[2]
...
array[9],  ???
old stack

 $fp

Linear Arrays

#include <stdio.h>
  
#define ARRAY_SIZE 10

int  main(int argc, char *argv[]) {
    unsigned long sum = 0;
    unsigned int i = 0;
    unsigned int array[ARRAY_SIZE];

    for(i = 0; i < ARRAY_SIZE; i++) {
        array[i] = rand();
    }

    for(i = 0; i < ARRAY_SIZE; i++) {
        sum = array[i] + sum;
        printf("array[%i] = %i (sum = %li)\n", i, array[i], sum);
    }
    return 0;
}

Linear Arrays



main: 
        stp  fp, lr, [sp, alloc]!  // Allocate stack vars, save fp lr
        mov  fp, sp                // save stack frame

        str  wzr, [fp, i_so]       // set i = 0
        str  xzr, [fp, sum_so]     // set sum = 0

loop_1_top:
        bl   rand                  // Generate a random number, put it in w0
        
        ldr  w1, [fp, i_so]        // load i into w1
        add  x2, fp, array_so      // set x2 to the address of the first element of the array

        str  w0, [x2, w1, SXTW 2]  // store w0 (random number) into address x2 + signext(w1) << 2 
                                   // remember x2 = fp + array_os, and w1 << 2 = i * 4
                                   // thus this is equivalent to "store x0 in the i'th
                                   // element of the array".

        ldr w1, [fp, i_so]         // load i
        add w1, w1, 1              // increment i
        str w1, [fp, i_so]         // store i
        cmp w1, array_count        // if i < array count
        b.lt loop_1_top             
      
        // second loop in next slide

        mov w0, 0                // setup 0 return code
        ldp  fp, lr, [sp], dealloc
        ret
        

Linear Arrays

#include <stdio.h>
  
#define ARRAY_SIZE 10

int  main(int argc, char *argv[]) {
    unsigned long sum = 0;
    unsigned int i = 0;
    unsigned int array[ARRAY_SIZE];

    for(i = 0; i < ARRAY_SIZE; i++) {
        array[i] = rand();
    }

    for(i = 0; i < ARRAY_SIZE; i++) {
        sum = array[i] + sum;
        printf("array[%i] = %i (sum = %li)\n", i, array[i], sum);
    }
    return 0;
}

Linear Arrays

// ....
        b.lt loop_1_top             

        str wzr, [fp, i_so]        // set i var to 0 

loop_2_top:               
        ldr  w1, [fp, i_so]        // load i into w1
        add  x2, fp, array_so      // set x2 to the address of the first element of the array

        ldr  w3, [x2, w1, SXTW 2]     // load from address x2 + signext(w1) << 2 
                                      // remember x2 = fp + array_os, and w1 << 2 = i * 4
                                      // thus this is equivalent to "the i'th
                                      // element of the array".

        ldr  x4, [fp, sum_so]         // load the sum variable
        add  x4, x4, x3               // Don't sign extend w3, just take its wider reg x3
        str  x4, [fp, sum_so]         // place x4 back in the sum var

        // printf as usual
        ldr  x0, =fmt1
        ldr  w1, [fp, i_so]       // first arg = i
        ldr  w2, [x2, w1, SXTW 2] // second arg = array[i]
        ldr  x3, [fp, sum_so]     // third arg = sum
        bl printf

        ldr w1, [fp, i_so]         // load i
        add w1, w1, 1              // increment i
        str w1, [fp, i_so]         // store i
        cmp w1, array_count        // if i <= array count
        b.lt loop_2_top             

        mov w0, 0                // setup 0 return code
        ldp  fp, lr, [sp], dealloc
        ret
        

Multidimensional Arrays

This isn't as scary as it sounds, for example here's a 2D array

We want to store values to cells in this array

x=1

y=2

42

If a value represents, say, shade...

Multidimensional Arrays

This isn't as scary as it sounds, for example here's a 2D array

Then you just have (a black and white, and uncompressed) image

Multidimensional Arrays

Let's just turn this into a linear array

x

y

0 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 32 33 34
45 46 47 48 49 50 51
52 53 54 55 56 57 58
0
1
2
3
...
58

2D

Linear

Multidimensional Arrays

How do I index the linear array given (x,y) pairs?

x

y

0 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 32 33 34
45 46 47 48 49 50 51
52 53 54 55 56 57 58
0
1
2
3
...
58

(2, 0) = cell 2

Multidimensional Arrays

How do I index the linear array given (x,y) pairs?

x

y

0 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 32 33 34
45 46 47 48 49 50 51
52 53 54 55 56 57 58
0
...
8
9
...
58

(2, 1) = cell 7 + 2 = cell 9

Multidimensional Arrays

How do I index the linear array given (x,y) pairs?

x

y

0 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 32 33 34
45 46 47 48 49 50 51
52 53 54 55 56 57 58
0
...
15
16
...
58

(2, 2) = cell 14 + 2 = cell 16

Multidimensional Arrays

How do I index the linear array given (x,y) pairs?

x

y

0 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 32 33 34
45 46 47 48 49 50 51
52 53 54 55 56 57 58
0
...
15
16
...
58

(x, y) = cell y*7 + x 

Multidimensional Arrays

For a grid with a known grid_width

x

y

(x, y) = y*grid_width + x 

Multidimensional Arrays

#include<stdio.h>
  
#define WIDTH  7
#define HEIGHT 7

int linear_index(int x, int y) {
    return y * WIDTH + x;
}

int main(int argc, char *argv) {
    char arr[WIDTH * HEIGHT];
    // clear out the array
    for(int j = 0; j < HEIGHT; j++)
        for(int i = 0; i < WIDTH; i++)
            arr[linear_index(i,j)] = ' ';

    // left right eye
    arr[linear_index(2,1)] = '|';
    arr[linear_index(2,2)] = '|';

    arr[linear_index(4,1)] = '|';
    arr[linear_index(4,2)] = '|';

    arr[linear_index(1,4)] = '\\';
    arr[linear_index(2,5)] = '-';
    arr[linear_index(3,5)] = '-';
    arr[linear_index(4,5)] = '-';
    arr[linear_index(5,4)] = '/';

    // print array
    for(int j = 0; j < HEIGHT; j++){
        for(int i = 0; i < WIDTH; i++){
            putchar(arr[linear_index(i,j)]);
        }
        putchar('\n');
    }
    return 0;
}

Multidimensional Arrays

This technique works up to n-dimensions

element\_index = \displaystyle\sum^{n-1}_{i=1} \left(dim\_index_i\times \prod^{n}_{j=i+1} dim_j \right) + dim\_index_n
element_index=i=1n1(dim_indexi×j=i+1ndimj)+dim_indexnelement\_index = \displaystyle\sum^{n-1}_{i=1} \left(dim\_index_i\times \prod^{n}_{j=i+1} dim_j \right) + dim\_index_n

For example, if we have a 4 by 5 by 6 grid, and we want to find the linear index of (1,2,3)

element\_index = (1 \times 5 \times 6) + (2 \times 6) + 3
element_index=(1×5×6)+(2×6)+3element\_index = (1 \times 5 \times 6) + (2 \times 6) + 3

Next Day

Work day, bring your questions!

CPSC 355: Tutorial 9

By Joshua Horacsek

CPSC 355: Tutorial 9

  • 1,823