0% found this document useful (0 votes)
2 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)
2 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
You are on page 1/ 53

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