0% found this document useful (0 votes)
12 views53 pages

EL3011 - 12 Data Structure

This document is a module on Data Structures, specifically focusing on arrays, their allocation, access, and alignment. It covers one-dimensional, multi-dimensional, and multi-level arrays, providing examples and code snippets for better understanding. The content is adapted from a course at Carnegie Mellon University and serves as a resource for students in computer architecture at Institut Teknologi Bandung.

Uploaded by

creojr88
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views53 pages

EL3011 - 12 Data Structure

This document is a module on Data Structures, specifically focusing on arrays, their allocation, access, and alignment. It covers one-dimensional, multi-dimensional, and multi-level arrays, providing examples and code snippets for better understanding. The content is adapted from a course at Carnegie Mellon University and serves as a resource for students in computer architecture at Institut Teknologi Bandung.

Uploaded by

creojr88
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

1

Modul 12
Data Structure
EL3011 Arsitektur Sistem Komputer

STEI - Institut Teknologi Bandung


2

Contents
1. Arrays
• One-dimensional
• Multi-dimensional (nested)
• Multi-level
2. Structure
• Allocation
• Access
• Alignment

This module adopted from 15-213 Introduction to Computer Systems Lecture, Carnegie Mellon
University, 2020
3

Modul 12. Data Structure

12.2. Arrays

EL3011 Arsitektur Sistem Komputer

STEI - Institut Teknologi Bandung


4
Array Allocation
• Basic Principle
T A[L];
• Array of data type T and length L
• Contiguously allocated region of L * sizeof(T) bytes in
memory

char string[12];

x x + 12

int val[5];

x x+4 x+8 x + 12 x + 16 x + 20

double a[3];

x x+8 x + 16 x + 24

char *p[3];

x x+8 x + 16 x + 24
5

Array Access
• Basic Principle
T A[L];
• Array of data type T and length L
• Identifier A can be used as a pointer to array element 0:
Type T*
int val[5]; 1 5 2 1 3

x x + 4 x + 8 x + 12 x + 16 x + 20

• Reference Type Value


val[4] int
val int *
val+1 int *
&val[2] int *
val[5] int
*(val+1) int
val + i int *
6

Array Access
• Basic Principle
T A[L];
• Array of data type T and length L
• Identifier A can be used as a pointer to array element 0:
Type T*
int val[5]; 1 5 2 1 3

x x + 4 x + 8 x + 12 x + 16 x + 20

• Reference Type Value


val[4] int 3
val int *
val+1 int *
&val[2] int *
val[5] int
*(val+1) int
val + i int *
7

Array Access
• Basic Principle
T A[L];
• Array of data type T and length L
• Identifier A can be used as a pointer to array element 0:
Type T*
int val[5]; 1 5 2 1 3

x x + 4 x + 8 x + 12 x + 16 x + 20

• Reference Type Value


val[4] int 3
val int * x
val+1 int * x + 4
&val[2] int * x + 8
val[5] int ??
*(val+1) int 5 //val[1]
val + i int * x + 4 * i //&val[i]
8

Array Example
#define ZLEN 5
typedef int zip_dig[ZLEN];

zip_dig cmu = { 1, 5, 2, 1, 3 };
zip_dig mit = { 0, 2, 1, 3, 9 };
zip_dig ucb = { 9, 4, 7, 2, 0 };

zip_dig cmu; 1 5 2 1 3
16 20 24 28 32 36
zip_dig mit; 0 2 1 3 9
36 40 44 48 52 56
zip_dig ucb; 9 4 7 2 0

56 60 64 68 72 76
• Declaration “zip_dig cmu” equivalent to “int cmu[5]”
• Example arrays were allocated in successive 20 byte blocks
• Not guaranteed to happen in general
9

Array Accessing Example


zip_dig cmu; 1 5 2 1 3
16 20 24 28 32 36

int get_digit
(zip_dig z, int digit)
{
return z[digit]; n Register %rdi contains
} starting address of array
n Register %rsi contains
x86-64 array index
# %rdi = z n Desired digit at
# %rsi = digit %rdi + 4*%rsi
movl (%rdi,%rsi,4), %eax # z[digit] n Use memory reference
(%rdi,%rsi,4)
10

Array Loop Example


void zincr(zip_dig z) {
size_t i;
for (i = 0; i < ZLEN; i++)
z[i]++;
}

# %rdi = z
movl $0, %eax # i = 0
jmp .L3 # goto middle
.L4: # loop:
addl $1, (%rdi,%rax,4) # z[i]++
addq $1, %rax # i++
.L3: # middle
cmpq $4, %rax # i:4
jbe .L4 # if <=, goto loop
rep; ret
11

Array Loop Example


void zincr(zip_dig z) {
size_t i;
for (i = 0; i < ZLEN; i++)
z[i]++;
}

# %rdi = z
movl $0, %eax # i = 0
jmp .L3 # goto middle
.L4: # loop:
addl $1, (%rdi,%rax,4) # z[i]++
addq $1, %rax # i++
.L3: # middle
cmpq $4, %rax # i:4
jbe .L4 # if <=, goto loop
rep; ret
12

Understanding Pointers & Arrays #1


Decl A1 , A2 *A1 , *A2
Comp Bad Size Comp Bad Size
int A1[3]
int *A2

• Comp: Compiles (Y/N)


• Bad: Possible bad pointer reference (Y/N)
• Size: Value returned by sizeof
13

Understanding Pointers & Arrays #1


Decl A1 , A2 *A1 , *A2
Comp Bad Size Comp Bad Size
int A1[3]
int *A2

A1 Allocated pointer
Unallocated pointer
A2
Allocated int
Unallocated int

• Comp: Compiles (Y/N)


• Bad: Possible bad pointer reference (Y/N)
• Size: Value returned by sizeof
14

Understanding Pointers & Arrays #1


Decl A1 , A2 *A1 , *A2
Comp Bad Size Comp Bad Size
int A1[3] Y N 12 Y N 4
int *A2 Y N 8 Y Y 4

A1 Allocated pointer
Unallocated pointer
A2
Allocated int
Unallocated int

• Comp: Compiles (Y/N)


• Bad: Possible bad pointer reference (Y/N)
• Size: Value returned by sizeof
15

Understanding Pointers & Arrays #2


Decl An *An **An
Cmp Bad Size Cmp Bad Size Cmp Bad Size
int A1[3]
int *A2[3]
int
(*A3)[3]

Allocated pointer
Unallocated pointer
Allocated int
Unallocated int
16

Understanding Pointers & Arrays #2


Decl An *An **An
Cmp Bad Size Cmp Bad Size Cmp Bad Size
int A1[3]
int *A2[3]
int
(*A3)[3]

A1

A2

A3
Allocated pointer
Unallocated pointer
Allocated int
Unallocated int
17

Understanding Pointers & Arrays #2


Decl An *An **An
Cmp Bad Size Cmp Bad Size Cmp Bad Size
int A1[3] Y N 12 Y N 4 N - -
int *A2[3] Y N 24 Y N 8 Y Y 4
int Y N 8 Y Y 12 Y Y 4
(*A3)[3]

A1

A2

A3
Allocated pointer
Unallocated pointer
Allocated int
Unallocated int
18

Multidimensional (Nested) Arrays


• Declaration A[0][0] • • • A[0][C-1]
T A[R][C];
• 2D array of data type T • •
• •
• R rows, C columns • •
• Array Size A[R-1][0] • • • A[R-1][C-1]
• R * C * sizeof(T) bytes
• Arrangement
• Row-Major Ordering

int A[R][C];
A A A A A A
[0] • • • [0] [1] • • • [1] • • • [R-1] • • • [R-1]
[0] [C-1] [0] [C-1] [0] [C-1]

4*R*C Bytes
19

Nested Array Example


#define PCOUNT 4
typedef int zip_dig[5];

zip_dig pgh[PCOUNT] =
{{1, 5, 2, 0, 6},
{1, 5, 2, 1, 3 },
{1, 5, 2, 1, 7 },
{1, 5, 2, 2, 1 }};

zip_dig
1 5 2 0 6 1 5 2 1 3 1 5 2 1 7 1 5 2 2 1
pgh[4];

76 96 116 136 156

• “zip_dig pgh[4]” equivalent to “int


pgh[4][5]”
• Variable pgh: array of 4 elements, allocated contiguously
• Each element is an array of 5 int’s, allocated contiguously
• “Row-Major” ordering of all elements in memory
20

Nested Array Row Access


• Row Vectors
• A[i] is array of C elements of type T
• Starting address A + i * (C * sizeof(T))

int A[R][C];

A[0] A[i] A[R-1]

A A A A A A
[0] ••• [0] • • • [i] ••• [i] • • • [R-1] ••• [R-1]
[0] [C-1] [0] [C-1] [0] [C-1]

A A+(i*C*4) A+((R-1)*C*4)
21

Nested Array Row Access Code


1 5 2 0 6 1 5 2 1 3 1 5 2 1 7 1 5 2 2 1

pgh pgh[2] int *get_pgh_zip(int index)


{
return pgh[index];
}
# %rdi = index
leaq (%rdi,%rdi,4),%rax # 5 * index
leaq pgh(,%rax,4),%rax # pgh + (20 * index)

• Row Vector
• pgh[index] is array of 5 int’s
• Starting address pgh+20*index
• Machine Code
• Computes and returns address
• Compute as pgh + 4*(index+4*index)
22

Nested Array Element Access


• Array Elements
• A[i][j] is element of type T, which requires K bytes
• Address A + i * (C * K) + j * K
= A + (i * C + j) * K

int A[R][C];

A[0] A[i] A[R-1]

A A A A A
[0] ••• [0] • • • ••• [i] ••• • • • [R-1] ••• [R-1]
[0] [C-1] [j] [0] [C-1]

A A+(i*C*4) A+((R-1)*C*4)
A+(i*C*4)+(j*4)
23

Nested Array Element Access Code


1 5 2 0 6 1 5 2 1 3 1 5 2 1 7 1 5 2 2 1

pgh pgh[1][1] int get_pgh_digit(int index, int dig)


{
return pgh[index][dig];
}

leaq (%rdi,%rdi,4), %rax # 5*index


addl %rax, %rsi # 5*index+dig
movl pgh(,%rsi,4), %eax # M[pgh + 4*(5*index+dig)]

• Array Elements
• pgh[index][dig] is int
• Address: pgh + 20*index + 4*dig
= pgh + 4*(5*index + dig)
24

Multi-Level Array Example


zip_dig cmu = { 1, 5, 2, 1, 3 }; • Variable univ denotes array
zip_dig mit = { 0, 2, 1, 3, 9 }; of 3 elements
zip_dig ucb = { 9, 4, 7, 2, 0 }; • Each element is a pointer
#define UCOUNT 3 • 8 bytes
int *univ[UCOUNT] = {mit, cmu, ucb}; • Each pointer points to array
of int’s

cmu
1 5 2 1 3
univ
16 20 24 28 32 36
160 36 mit
0 2 1 3 9
168 16
176 56 ucb 36 40 44 48 52 56
9 4 7 2 0

56 60 64 68 72 76
25

Element Access in Multi-Level Array


int get_univ_digit
(size_t index, size_t digit)
{
return univ[index][digit];
}

salq $2, %rsi # 4*digit


addq univ(,%rdi,8), %rsi # p = univ[index] + 4*digit
movl (%rsi), %eax # return *p
ret

• Computation
• Element access Mem[Mem[univ+8*index]+4*digit]
• Must do two memory reads
• First get pointer to row array
• Then access element within array
26

Array Element Accesses


Nested array Multi-level array
int get_pgh_digit int get_univ_digit
(size_t index, size_t digit) (size_t index, size_t digit)
{ {
return pgh[index][digit]; return univ[index][digit];
} }

Accesses looks similar in C, but address computations very different:

Mem[pgh+20*index+4*digit] Mem[Mem[univ+8*index]+4*digit]
27
N X N Matrix #define N 16

Code typedef int fix_matrix[N][N];


/* Get element A[i][j] */
int fix_ele(fix_matrix A,
• Fixed dimensions size_t i, size_t j)
• Know value of N at {
compile time return A[i][j];
}
#define IDX(n, i, j) ((i)*(n)+(j))
• Variable dimensions, /* Get element A[i][j] */
explicit indexing int vec_ele(size_t n, int *A,
size_t i, size_t j)
• Traditional way to {
implement dynamic return A[IDX(n,i,j)];
arrays }

/* Get element A[i][j] */


int var_ele(size_t n, int A[n][n],
• Variable dimensions, size_t i, size_t j) {
implicit indexing return A[i][j];
• Now supported by gcc }
28

16 X 16 Matrix Access
¢ Array Elements
§ int A[16][16];
§ Address A + i * (C * K) + j * K
§ C = 16, K = 4
/* Get element A[i][j] */
int fix_ele(fix_matrix A, size_t i, size_t j) {
return A[i][j];
}

# A in %rdi, i in %rsi, j in %rdx


salq $6, %rsi # 64*i
addq %rsi, %rdi # A + 64*i
movl (%rdi,%rdx,4), %eax # Mem[A + 64*i + 4*j]
ret
29

n X n Matrix Access
¢ Array Elements
§ size_t n;
§ int A[n][n];
§ Address A + i * (C * K) + j * K
§ C = n, K = 4
§ Must perform integer multiplication
/* Get element A[i][j] */
int var_ele(size_t n, int A[n][n], size_t i, size_t j)
{
return A[i][j];
}

# n in %rdi, A in %rsi, i in %rdx, j in %rcx


imulq %rdx, %rdi # n*i
leaq (%rsi,%rdi,4), %rax # A + 4*n*i
movl (%rax,%rcx,4), %eax # A + 4*n*i + 4*j
ret
30

Example: Array Access


#include <stdio.h>
#define ZLEN 5
#define PCOUNT 4
typedef int zip_dig[ZLEN];

int main(int argc, char** argv) {


zip_dig pgh[PCOUNT] =
{{1, 5, 2, 0, 6},
{1, 5, 2, 1, 3 },
{1, 5, 2, 1, 7 }, linux> ./array
{1, 5, 2, 2, 1 }};
int *linear_zip = (int *) pgh;
int *zip2 = (int *) pgh[2];
int result =
pgh[0][0] +
linear_zip[7] +
*(linear_zip + 8) +
zip2[1];
printf("result: %d\n", result);
return 0;
}
31

Example: Array Access


#include <stdio.h>
#define ZLEN 5
#define PCOUNT 4
typedef int zip_dig[ZLEN];

int main(int argc, char** argv) {


zip_dig pgh[PCOUNT] =
{{1, 5, 2, 0, 6},
{1, 5, 2, 1, 3 },
{1, 5, 2, 1, 7 }, linux> ./array
{1, 5, 2, 2, 1 }};
result: 9
int *linear_zip = (int *) pgh;
int *zip2 = (int *) pgh[2];
int result =
pgh[0][0] +
linear_zip[7] +
*(linear_zip + 8) +
zip2[1];
printf("result: %d\n", result);
return 0;
}
32

Understanding Pointers & Arrays #3


Decl An *An **An
Cmp Bad Size Cmp Bad Size Cmp Bad Size
int A1[3][5]
int *A2[3][5]
int (*A3)[3][5]
int *(A4[3][5])
int (*A5[3])[5]

Decl ***An
• Cmp: Compiles (Y/N)
• Bad: Possible bad pointer Cmp Bad Size
reference (Y/N) int A1[3][5]
• Size: Value returned by int *A2[3][5]
sizeof int (*A3)[3][5]
int *(A4[3][5])
int (*A5[3])[5]
33

Allocated pointer Declaration


Allocated pointer to unallocated int
int A1[3][5]
Unallocated pointer
Allocated int int *A2[3][5]
Unallocated int int (*A3)[3][5]
int *(A4[3][5])
int (*A5[3])[5]
34

Allocated pointer Declaration


Allocated pointer to unallocated int
int A1[3][5]
Unallocated pointer
Allocated int int *A2[3][5]
Unallocated int int (*A3)[3][5]
int *(A4[3][5])
A1 int (*A5[3])[5]

A2/A4

A3

A5
35

Understanding Pointers & Arrays #3


Decl An *An **An
Cmp Bad Size Cmp Bad Size Cmp Bad Size
int A1[3][5] Y N 60 Y N 20 Y N 4
int *A2[3][5] Y N 120 Y N 40 Y N 8
int (*A3)[3][5] Y N 8 Y Y 60 Y Y 20
int *(A4[3][5]) Y N 120 Y N 40 Y N 8
int (*A5[3])[5] Y N 24 Y N 8 Y Y 20
Decl ***An
• Cmp: Compiles (Y/N)
• Bad: Possible bad pointer Cmp Bad Size
reference (Y/N) int A1[3][5] N - -
• Size: Value returned by int *A2[3][5] Y Y 4
sizeof int (*A3)[3][5] Y Y 4
int *(A4[3][5]) Y Y 4
int (*A5[3])[5] Y Y 4
36

Modul 12. Data Structure

12.2. Structures

EL3011 Arsitektur Sistem Komputer

STEI - Institut Teknologi Bandung


37

Structure Representation
r
struct rec {
int a[4];
size_t i; a i next
struct rec *next;
0 16 24 32
};

• Structure represented as block of memory


• Big enough to hold all of the fields
• Fields ordered according to declaration
• Even if another ordering could yield a more compact
representation
• Compiler determines overall size + positions of fields
• Machine-level program has no understanding of the
structures in the source code
38

Generating Pointer to Structure Member


r r+4*idx
struct rec {
int a[4];
size_t i; a i next
struct rec *next;
0 16 24 32
};

• Generating Pointer to int *get_ap


(struct rec *r, size_t idx)
Array Element {
• Offset of each structure return &r->a[idx];
}
member determined at
compile time
# r in %rdi, idx in %rsi
• Compute as r + leaq (%rdi,%rsi,4), %rax
4*idx ret
39
struct rec {

Following Linked List #1 int a[4];


size_t i;
struct rec *next;
• C Code };
r
long length(struct rec*r) {
long len = 0L;
while (r) { a i next
len ++;
r = r->next; 0 16 24 32
}
return len; Register Value
} %rdi r

• Loop assembly code %rax len

.L11: # loop:
addq $1, %rax # len ++
movq 24(%rdi), %rdi # r = Mem[r+24]
testq %rdi, %rdi # Test r
jne .L11 # If != 0, goto loop
40
struct rec {

Following Linked List #2 int a[4];


size_t i;
struct rec *next;
• C Code };
r
void set_val
(struct rec *r, int val)
{ a i next
while (r) {
size_t i = r->i; 0 16 24 32
// No bounds check Element i
r->a[i] = val;
r = r->next; Register Value
} %rdi r
}
%rsi val

.L11: # loop:
movq 16(%rdi), %rax # i = Mem[r+16]
movl %esi, (%rdi,%rax,4) # Mem[r+4*i] = val
movq 24(%rdi), %rdi # r = Mem[r+24]
testq %rdi, %rdi # Test r
jne .L11 # if !=0 goto loop
41

Structures & Alignment


• Unaligned Data struct S1 {
char c;
c i[0] i[1] v
int i[2];
p p+1 p+5 p+9 p+17 double v;
} *p;

• Aligned Data
• Primitive data type requires B bytes implies
Address must be multiple of B
c 3 bytes i[0] i[1] 4 bytes v
p+0 p+4 p+8 p+16 p+24

Multiple of 4 Multiple of 8

Multiple of 8 Multiple of 8
42

Alignment Principles
• Aligned Data
• Primitive data type requires B bytes
• Address must be multiple of B
• Required on some machines; advised on x86-64
• Motivation for Aligning Data
• Memory accessed by (aligned) chunks of 4 or 8 bytes (system
dependent)
• Inefficient to load or store datum that spans cache lines (64 bytes).
Intel states should avoid crossing 16 byte boundaries.
[Cache lines will be discussed in Lecture 11.]
• Virtual memory trickier when datum spans 2 pages (4 KB pages)
[Virtual memory pages will be discussed in Lecture 17.]
• Compiler
• Inserts gaps in structure to ensure correct alignment of fields
43

Specific Cases of Alignment (x86-64)


• 1 byte: char, …
• no restrictions on address
• 2 bytes: short, …
• lowest 1 bit of address must be 02
• 4 bytes: int, float, …
• lowest 2 bits of address must be 002
• 8 bytes: double, long, char *, …
• lowest 3 bits of address must be 0002
44

Satisfying Alignment with Structures


• Within structure: struct S1 {
char c;
• Must satisfy each element’s alignment requirement int i[2];
• Overall structure placement double v;
} *p;
• Each structure has alignment requirement K
• K = Largest alignment of any element
• Initial address & structure length must be multiples of K
• Example:
• K = 8, due to double element

c 3 bytes i[0] i[1] 4 bytes v


p+0 p+4 p+8 p+16 p+24

Multiple of 4 Multiple of 8

Multiple of 8 Multiple of 8
Internal padding
45

Meeting Overall Alignment Requirement

struct S2 {
double v;
• For largest alignment requirement K int i[2];
char c;
• Overall structure must be multiple of K } *p;

External padding
v i[0] i[1] c 7 bytes
p+0 p+8 p+16 p+24

Multiple of K=8
46

Arrays of Structures struct S2 {


• Overall structure length multiple of K double v;
• Satisfy alignment requirement int i[2];
for every element char c;
} a[10];

a[0] a[1] a[2] • • •


a+0 a+24 a+48 a+72

v i[0] i[1] c 7 bytes


a+24 a+32 a+40 a+48
47

Accessing Array Elements


struct S3 {
short i;
float v;
• Compute array offset 12*idx short j;
• sizeof(S3), including alignment spacers } a[10];

• Element j is at offset 8 within structure


• Assembler gives offset a+8
• Resolved during linking
a[0] • • • a[idx] • • •
a+0 a+12 a+12*idx

i 2 bytes v j 2 bytes
a+12*idx a+12*idx+8

short get_j(int idx)


# %rdi = idx
{
leaq (%rdi,%rdi,2),%rax # 3*idx
return a[idx].j;
movzwl a+8(,%rax,4),%eax
}
48

Saving Space
• Put large data types first
struct S4 { struct S5 {
char c; int i;
int i; char c;
char d; char d;
} *p; } *p;

c 3 bytes i d 3 bytes 12 bytes

• Effect (largest alignment requirement K=4)


i c d 2 bytes 8 bytes
49

Example Struct Exam Question

http://www.cs.cmu.edu/~213/oldexams/exam1-f12.pdf
50

Example Struct Exam Question

a X X X X X X X b b b b b b b b

c c c c d d d X e e e e e e e e

f f f f f f f f|

http://www.cs.cmu.edu/~213/oldexams/exam1-f12.pdf
51

Example Struct Exam Question (Cont’d)

http://www.cs.cmu.edu/~213/oldexams/exam1-f12.pdf
52

Example Struct Exam Question (Cont’d)

a d d d c c c c b b b b b b b b

e e e e e e e e f f f f f f f f|

http://www.cs.cmu.edu/~213/oldexams/exam1-f12.pdf
53

Summary

• Arrays
• Elements packed into contiguous region of memory
• Use index arithmetic to locate individual elements
• Structures
• Elements packed into single region of memory
• Access using offsets determined by compiler
• Possible require internal and external padding to ensure alignment
• Combinations
• Can nest structure and array code arbitrarily

You might also like