Date post: | 15-Mar-2016 |
Category: |
Documents |
Upload: | abbot-floyd |
View: | 49 times |
Download: | 2 times |
Machine-Level Programming 5Structured Data
TopicsTopics Arrays
– 2 – CMSC 313, F’09
Basic Data Types
IntegralIntegral Stored & operated on in general registers Signed vs. unsigned depends on instructions used
Intel GAS Bytes Cbyte b 1 [unsigned] charword w 2 [unsigned] shortdouble word l 4 [unsigned] int
Floating PointFloating Point Stored & operated on in floating point registers
Intel GAS Bytes CSingle s 4 floatDouble l 8 doubleExtended t 10/12/16 long double
– 3 – CMSC 313, F’09
Array AllocationBasic PrincipleBasic Principle
T A[L]; Array of data type T and length L Contiguously allocated region of L * sizeof(T) bytes
char string[12];
x x + 12int val[5];
x x + 4 x + 8 x + 12 x + 16 x + 20double a[4];
x + 32x + 24x x + 8 x + 16
char *p[3];
x x + 4 x + 8 x + 12
– 4 – CMSC 313, F’09
Array AccessBasic PrincipleBasic 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*
ReferenceReference TypeType ValueValueval[4]valval+1&val[2]val[5]*(val+1)val + i
1 5 2 1 3int val[5];
x x + 4 x + 8 x + 12 x + 16 x + 20
int 3int * xint * x + 4int * x + 8int ????int 5int * x + 4i
– 5 – CMSC 313, F’09
Array Example
NotesNotes Declaration “zip_dig umbc” equivalent to “int umbc[5]” Example arrays were allocated in successive 20 byte blocks
Not guaranteed to happen in general
typedef int zip_dig[5];
zip_dig cmu = { 1, 5, 2, 1, 3 };zip_dig mit = { 0, 2, 1, 3, 9 };zip_dig umbc = { 2, 1, 2, 5, 0 };
zip_dig cmu; 1 5 2 1 3
16 20 24 28 32 36zip_dig mit; 0 2 1 3 9
36 40 44 48 52 56zip_dig umbc; 2 1 2 5 0
56 60 64 68 72 76
– 6 – CMSC 313, F’09
Array Accessing Example
IA32 Memory Reference CodeIA32 Memory Reference Code
int get_digit (zip_dig z, int dig){ return z[dig];}
# %edx = z# %eax = digmovl (%edx,%eax,4),%eax # z[dig]
ComputationComputation Register %edx contains starting
address of array Register %eax contains array
index Desired digit at 4*%eax + %edx Use memory reference (%edx,%eax,4)
– 7 – CMSC 313, F’09
Referencing Examples
Code Does Not Do Any Bounds Checking!Code Does Not Do Any Bounds Checking!
ReferenceReference AddressAddress ValueValue Guaranteed?Guaranteed?mit[3]mit[5]mit[-1]cmu[15]
zip_dig cmu; 1 5 2 1 3
16 20 24 28 32 36zip_dig mit; 0 2 1 3 9
36 40 44 48 52 56zip_dig umbc; 2 1 2 5 0
56 60 64 68 72 76
YesYesNoNoNoNoNoNo
Out of range behavior implementation-dependentNo guaranteed relative allocation of different
arrays
3336 + 4*3 = 4836 + 4*5 = 5636 + 4*(-1) = 3216 + 4*15 = 76
2233????
– 8 – CMSC 313, F’09
int zd2int(zip_dig z){ int i; int zi = 0; for (i = 0; i < 5; i++) { zi = 10 * zi + z[i]; } return zi;}
Array Loop Example
Original SourceOriginal Source
int zd2int(zip_dig z){ int zi = 0; int *zend = z + 4; do { zi = 10 * zi + *z; z++; } while (z <= zend); return zi;}
Transformed VersionTransformed Version As generated by GCC Eliminate loop variable i Convert array code to
pointer code Express in do-while form
No need to test at entrance
– 9 – CMSC 313, F’09
# %ecx = zxorl %eax,%eax # zi = 0leal 16(%ecx),%ebx # zend = z+4
.L59:leal (%eax,%eax,4),%edx # 5*zimovl (%ecx),%eax # *zaddl $4,%ecx # z++leal (%eax,%edx,2),%eax # zi = *z + 2*(5*zi)cmpl %ebx,%ecx # z : zendjle .L59 # if <= goto loop
Array Loop Implementation (IA32)RegistersRegisters
%ecx z%eax zi%ebx zend
ComputationsComputations 10*zi + *z implemented as *z + 2*(zi+4*zi)
z++ increments by 4
int zd2int(zip_dig z){ int zi = 0; int *zend = z + 4; do { zi = 10 * zi + *z; z++; } while(z <= zend); return zi;}
# %ecx = zxorl %eax,%eax # zi = 0leal 16(%ecx),%ebx # zend = z+4
.L59:leal (%eax,%eax,4),%edx # 5*zimovl (%ecx),%eax # *zaddl $4,%ecx # z++leal (%eax,%edx,2),%eax # zi = *z + 2*(5*zi)cmpl %ebx,%ecx # z : zendjle .L59 # if <= goto loop
int zd2int(zip_dig z){ int zi = 0; int *zend = z + 4; do { zi = 10 * zi + *z; z++; } while(z <= zend); return zi;}
# %ecx = zxorl %eax,%eax # zi = 0leal 16(%ecx),%ebx # zend = z+4
.L59:leal (%eax,%eax,4),%edx # 5*zimovl (%ecx),%eax # *zaddl $4,%ecx # z++leal (%eax,%edx,2),%eax # zi = *z + 2*(5*zi)cmpl %ebx,%ecx # z : zendjle .L59 # if <= goto loop
int zd2int(zip_dig z){ int zi = 0; int *zend = z + 4; do { zi = 10 * zi + *z; z++; } while(z <= zend); return zi;}
# %ecx = zxorl %eax,%eax # zi = 0leal 16(%ecx),%ebx # zend = z+4
.L59:leal (%eax,%eax,4),%edx # 5*zimovl (%ecx),%eax # *zaddl $4,%ecx # z++leal (%eax,%edx,2),%eax # zi = *z + 2*(5*zi)cmpl %ebx,%ecx # z : zendjle .L59 # if <= goto loop
int zd2int(zip_dig z){ int zi = 0; int *zend = z + 4; do { zi = 10 * zi + *z; z++; } while(z <= zend); return zi;}
# %ecx = zxorl %eax,%eax # zi = 0leal 16(%ecx),%ebx # zend = z+4
.L59:movl (%ecx),%eax # *zleal (%eax,%eax,4),%edx # 5*zileal (%eax,%edx,2),%eax # zi = *z + 2*(5*zi)addl $4,%ecx # z++cmpl %ebx,%ecx # z : zendjle .L59 # if <= goto loop
int zd2int(zip_dig z){ int zi = 0; int *zend = z + 4; do { zi = 10 * zi + *z; z++; } while(z <= zend); return zi;}
– 10 – CMSC 313, F’09
Array Code Exampleint main ( ){ int i, sum, array[4];
for (i = 0; i < 4; i++ ) array[i] = i << 2;
sum = sumArray( array );
printf( "Array sum = %d\n", sum); return 0;}
int sumArray( int a[ ] ){ return a[1] + a[3];}
– 11 – CMSC 313, F’09
sumArray
int sumArray( int a[ ] )int sumArray( int a[ ] )
{{
return a[ 1 ] + a[ 3 ];return a[ 1 ] + a[ 3 ];
}}
08048390 <sumArray>: 8048390: 55 push %ebp # setup 8048391: 89 e5 mov %esp,%ebp # setup 8048393: 8b 55 08 mov 0x8(%ebp),%edx # edx = a 8048396: 5d pop %ebp # finish up 8048397: 8b 42 0c mov 0xc(%edx),%eax # a[ 3 ] 804839a: 8b 4a 04 mov 0x4(%edx),%ecx # a[ 1 ] 804839d: 01 c8 add %ecx,%eax # return sum 804839f: c3 ret
– 12 – CMSC 313, F’09
mainint main ( ){ int i, sum, aa[4];
for (i = 0; i < 4; i++ ) aa[i] = i << 2; // aa[i] = i * 4
sum = sumArray( aa );
printf( "Array sum = %d\n", sum);
return 0;}
– 13 – CMSC 313, F’09
main080483a0 <main>: 80483a0: 31 d2 xor %edx,%edx # i = 0# missing setup code 80483b0: 83 ec 24 sub $0x24,%esp # big stack 80483b3: 8d 4d ec lea 0xffffffec(%ebp),%ecx # aa at ebp - 0x14 80483b6: 8d 76 00 lea 0x0(%esi),%esi # filler 80483b9: 8d bc 27 00 00 00 00 lea 0x0(%edi),%edi # fillerL1: # word boundary 80483c0: 8d 04 95 00 00 00 00 lea 0x0(,%edx,4),%eax # i * 4 80483c7: 89 04 91 mov %eax,(%ecx,%edx,4) # a[ i ] 80483ca: 42 inc %edx # i++ 80483cb: 83 fa 04 cmp $0x4,%edx # compare i : 4 80483ce: 75 f0 jne 80483c0 <main+0x20> # loop L1 ?? 80483d0: 89 0c 24 mov %ecx,(%esp) # “push” param 80483d3: e8 b8 ff ff ff call 8048390 <sumArray> # 80483d8: c7 04 24 d8 84 04 08 movl $0x80484d8,(%esp) # for printf 80483df: 89 44 24 04 mov %eax,0x4(%esp) # for printf 80483e3: e8 d4 fe ff ff call 80482bc <printf@plt> # 80483e8: 83 c4 24 add $0x24,%esp # resest esp 80483eb: 31 c0 xor %eax,%eax # return 0# missing finish code 80483ed: C3 ret
– 14 – CMSC 313, F’09
Nested Array Example
Declaration “zip_dig md[4]” equivalent to “int md[4][5]” Variable md denotes array of 4 elements
» Allocated contiguously Each element is an array of 5 int’s
» Allocated contiguously “Row-Major” ordering of all elements guaranteed
#define PCOUNT 4zip_dig md[PCOUNT] = {{2, 1, 1, 6, 2}, {2, 1, 2, 2, 8 }, {2, 1, 0, 4, 2 }, {2, 1, 2, 1, 0 }};
zip_digmd[4];
76 96 116 136 156
2 1 1 6 2 2 1 2 2 8 2 1 0 4 2 2 1 2 1 0
– 15 – CMSC 313, F’09
Viewing as Multidimensional ArrayDeclarationDeclaration
T A[R][C]; 2D array of data type T R rows, C columns Type T element requires K bytes
Array SizeArray Size R * C * K bytes
ArrangementArrangement Row-Major Ordering
A[0][0] A[0][C-1]
A[R-1][0]
• • •
• • •A[R-1][C-1]
•••
•••
int A[R][C];
A[0][0]
A[0][C-1]
• • •A
[1][0]
A[1][C-1]
• • •A
[R-1][0]
A[R-1][C-1]
• • •• • •
4*R*C Bytes
– 16 – CMSC 313, F’09
• • •
Nested Array Row Access
Row VectorsRow Vectors A[i] is array of C elements Each element of type T requires K bytes Starting address A + i * (C * K)
A[i][0]
A[i][C-1]
• • •
A[i]
A[R-1][0]
A[R-1][C-1]
• • •
A[R-1]
• • •
A
A[0][0]
A[0]
[C-1]• • •
A[0]
int A[R][C];
A+i*C*4 A+(R-1)*C*4
– 17 – CMSC 313, F’09
Nested Array Row Access Code
Row VectorRow Vector md is a 2-d array of ints, 5 ints per row md[index] is array of 5 ints Starting address of md[index] is md + 20*index
IA32 CodeIA32 Code Computes and returns address Compute as md + 4*(index + 4*index)
int *get_md_zip(int index){ return md[index];}
# %eax = indexleal (%eax,%eax,4),%eax # 5 * indexleal md(,%eax,4),%eax # md + (20 * index)
– 18 – CMSC 313, F’09
• • •
Nested Array Element Access
Array Elements Array Elements A[i][j] is element of type T Address A + i * (C * K) + j * K
= A + (i * C + j)* K
• • •A
[i][j]
A[i][j]
• • •
A[i]
A[R-1][0]
A[R-1][C-1]
• • •
A[R-1]
• • •
A
A[0][0]
A[0]
[C-1]• • •
A[0]
int A[R][C];
A+i*C*4 A+(R-1)*C*4A+(i*C+j)*4
– 19 – CMSC 313, F’09
Nested Array Element Access CodeArray Elements Array Elements
md[index][dig] is int Address:
md + 20*index + 4*dig
IA32 CodeIA32 Code Computes address
md + 4*dig + 4*(index+4*index) movl performs memory reference
int get_md_digit (int index, int dig){ return md[index][dig];}
# %ecx = dig# %eax = indexleal 0(,%ecx,4),%edx # 4*digleal (%eax,%eax,4),%eax # 5*indexmovl md(%edx,%eax,4),%eax # *(md + 4*dig + 20*index)
– 20 – CMSC 313, F’09
Strange Referencing Examples
ReferenceReference AddressAddress ValueValue Guaranteed?Guaranteed?md[3][3] 76+20*3+4*3 = 148 1md[2][5] 76+20*2+4*5 = 136 2md[2][-1] 76+20*2+4*-1 = 112 8md[4][-1] 76+20*4+4*-1 = 152 0md[0][19] 76+20*0+4*19 = 152 0 md[0][-1] 76+20*0+4*-1 = 72 ?? Code does not do any bounds checking Ordering of elements within array guaranteed
YesYesYesYesYesYesYesYesYesYesNoNo
zip_digmd[4];
76 96 116 136 156
2 1 1 6 2 2 1 2 2 8 2 1 0 4 2 2 1 2 1 0
– 21 – CMSC 313, F’09
Multi-Level Array Example Variable univ
denotes array of 3 elements
Each element is a pointer
4 bytes Each pointer points
to array of int’s
zip_dig cmu = { 1, 5, 2, 1, 3 };zip_dig mit = { 0, 2, 1, 3, 9 };zip_dig umbc = { 2, 1, 2, 5, 0 };
#define UCOUNT 3int *univ[UCOUNT] = {mit, cmu, umbc};
36160
1656
164
168
univ
cmu1 5 2 1 3
16 20 24 28 32 36mit0 2 1 3 9
36 40 44 48 52 56umbc9 4 7 2 0
56 60 64 68 72 76
– 22 – CMSC 313, F’09
Element Access in Multi-Level Array
Computation (IA32)Computation (IA32) Element access Mem[Mem[univ + 4*index] + 4*dig] Must do two memory reads
First get pointer to row arrayThen access element within array
# %ecx = index# %eax = digleal 0(,%ecx,4),%edx # 4*indexmovl univ(%edx),%edx # Mem[univ + 4*index]movl (%edx,%eax,4),%eax # Mem[... + 4*dig]
int get_univ_digit (int index, int dig){ return univ[index][dig];}
– 23 – CMSC 313, F’09
Array Element Accesses Similar C references
Nested ArrayNested Array
Element atMem[md+20*index+4*dig]
Different address computation
Multi-Level ArrayMulti-Level Array
Element atMem[Mem[univ+4*index]+4*dig]
int get_md_digit (int index, int dig){ return md[index][dig];}
int get_univ_digit (int index, int dig){ return univ[index][dig];}
76 96 116 136 156
1 5 2 0 6 1 5 2 1 3 1 5 2 1 7 1 5 2 2 1
76 96 116 136 156
1 5 2 0 6 1 5 2 1 3 1 5 2 1 7 1 5 2 2 11 5 2 0 61 5 2 0 6 1 5 2 1 31 5 2 1 3 1 5 2 1 71 5 2 1 7 1 5 2 2 12 1 2 5 0 36160
1656
164
168
univ
cmu1 5 2 1 3
16 20 24 28 32 36mit0 2 1 3 9
36 40 44 48 52 56ucb9 4 7 2 0
56 60 64 68 72 76
36160
1656
164
168
univ36160
1656
164
168
univ
cmu1 5 2 1 3
16 20 24 28 32 36
1 5 2 1 31 5 2 1 3
16 20 24 28 32 36mit0 2 1 3 9
36 40 44 48 52 56
0 2 1 3 90 2 1 3 9
36 40 44 48 52 56umbc9 4 7 2 0
56 60 64 68 72 76
9 4 7 2 029 1 2 5 0
56 60 64 68 72 76
– 24 – CMSC 313, F’09
Strange Referencing Examples
ReferenceReference AddressAddress ValueValue Guaranteed?Guaranteed?univ[2][3] 56+4*3 = 68 2univ[1][5] 16+4*5 = 36 0univ[2][-1] 56+4*-1 = 52 9univ[3][-1] ?? ??univ[1][12] 16+4*12 = 64 7 Code does not do any bounds checking Ordering of elements in different arrays not guaranteed
36160
1656
164
168
univ
cmu1 5 2 1 3
16 20 24 28 32 36mit0 2 1 3 9
36 40 44 48 52 56umbc9 4 7 2 0
56 60 64 68 72 76
YesYesNoNoNoNoNoNoNoNo
– 25 – CMSC 313, F’09
Using Nested Arrays
StrengthsStrengths C compiler handles
doubly subscripted arrays Generates very efficient
codeAvoids multiply in index
computation
LimitationLimitation Only works if have fixed
array size
#define N 16typedef int fix_matrix[N][N];
/* Compute element i,k of fixed matrix product */int fix_prod_ele(fix_matrix a, fix_matrix b, int i, int k){ int j; int result = 0; for (j = 0; j < N; j++) result += a[i][j]*b[j][k]; return result;}
A
(i,*)
B
(*,k)
Column-wise
Row-wise
– 26 – CMSC 313, F’09
Dynamic Nested ArraysStrengthStrength
Can create matrix of arbitrary size
ProgrammingProgramming Must do index
computation explicitly
PerformancePerformance Accessing single element
costly Must do multiplication
int * new_var_matrix(int n){ return (int *) calloc(sizeof(int), n*n);}
int var_ele (int *a, int i,int j, int n){ return a[i*n + j];}
movl 12(%ebp),%eax # imovl 8(%ebp),%edx # aimull 20(%ebp),%eax # n*iaddl 16(%ebp),%eax # n*i+jmovl (%edx,%eax,4),%eax # Mem[a+4*(i*n+j)]
– 27 – CMSC 313, F’09
Dynamic Array MultiplicationWithout OptimizationsWithout Optimizations
Multiplies 2 for subscripts 1 for data
Adds 2 for array indexing 1 for loop index 1 for data
/* Compute element i,k of variable matrix product */int var_prod_ele (int *a, int *b, int i, int k, int n){ int j; int result = 0; for (j = 0; j < n; j++) result += a[i*n+j] * b[j*n+k]; return result;}
A
(i,*)
B
(*,k)
Column-wise
Row-wise
– 28 – CMSC 313, F’09
Optimizing Dynamic Array Mult.
OptimizationsOptimizations Performed when set
optimization level to -O2
Code MotionCode Motion Expression i*n can be
computed outside loop
Strength ReductionStrength Reduction Incrementing j has effect of
incrementing j*n+k by n
PerformancePerformance Compiler can optimize
regular access patterns
{ int j; int result = 0; for (j = 0; j < n; j++) result += a[i*n+j] * b[j*n+k]; return result;}{ int j; int result = 0; int iTn = i*n; int jTnPk = k; for (j = 0; j < n; j++) { result += a[iTn+j] * b[jTnPk]; jTnPk += n; } return result;}
– 29 – CMSC 313, F’09
SummaryArrays in CArrays in C
Contiguous allocation of memory Pointer to first element No bounds checking
2-D Arrays in C2-D Arrays in C “nested” -- int grades[ 4 ][ 6 ];
Nr rows, columns fixed Dynamic -- int *grades[ 6 ];
Nr rows dynamic, nr columns fixed Double subscripts work in both cases
Compiler generates different code