1 // Purpose:
2 // Verifies that the debugging experience of loops marked optnone is as expected.
3
4 // REQUIRES: lldb
5 // UNSUPPORTED: system-windows
6 // UNSUPPORTED: system-darwin
7
8 // RUN: %dexter --fail-lt 1.0 -w \
9 // RUN: --builder 'clang' --debugger 'lldb' \
10 // RUN: --cflags "-O2 -g" -- %s
11
12 // A simple loop of assignments.
13 // With optimization level > 0 the compiler reorders basic blocks
14 // based on the basic block frequency analysis information.
15 // This also happens with optnone and it shouldn't.
16 // This is not affecting debug info so it is a minor limitation.
17 // Basic block placement based on the block frequency analysis
18 // is normally done to improve i-Cache performances.
simple_memcpy_loop(int * dest,const int * src,unsigned nelems)19 __attribute__((optnone)) void simple_memcpy_loop(int *dest, const int *src,
20 unsigned nelems) {
21 for (unsigned i = 0; i != nelems; ++i)
22 dest[i] = src[i]; // DexLabel('target_simple_memcpy_loop')
23 }
24
25 // DexLimitSteps('i', 0, 4, 8, on_line='target_simple_memcpy_loop')
26 // DexExpectWatchValue('nelems', '16', on_line='target_simple_memcpy_loop')
27 // DexExpectWatchValue('src[i]', '3', '7', '1', on_line='target_simple_memcpy_loop')
28
29
30 // A trivial loop that could be optimized into a builtin memcpy
31 // which is either expanded into a optimal sequence of mov
32 // instructions or directly into a call to memset@plt
trivial_memcpy_loop(int * dest,const int * src)33 __attribute__((optnone)) void trivial_memcpy_loop(int *dest, const int *src) {
34 for (unsigned i = 0; i != 16; ++i)
35 dest[i] = src[i]; // DexLabel('target_trivial_memcpy_loop')
36 }
37
38 // DexLimitSteps('i', 3, 7, 9, 14, 15, on_line='target_trivial_memcpy_loop')
39 // DexExpectWatchValue('i', 3, 7, 9, 14, 15, on_line='target_trivial_memcpy_loop')
40 // DexExpectWatchValue('dest[i-1] == src[i-1]', 'true', on_line='target_trivial_memcpy_loop')
41
42
foo(int a)43 __attribute__((always_inline)) int foo(int a) { return a + 5; }
44
45 // A trivial loop of calls to a 'always_inline' function.
nonleaf_function_with_loop(int * dest,const int * src)46 __attribute__((optnone)) void nonleaf_function_with_loop(int *dest,
47 const int *src) {
48 for (unsigned i = 0; i != 16; ++i)
49 dest[i] = foo(src[i]); // DexLabel('target_nonleaf_function_with_loop')
50 }
51
52 // DexLimitSteps('i', 1, on_line='target_nonleaf_function_with_loop')
53 // DexExpectWatchValue('dest[0]', '8', on_line='target_nonleaf_function_with_loop')
54 // DexExpectWatchValue('dest[1]', '4', on_line='target_nonleaf_function_with_loop')
55 // DexExpectWatchValue('dest[2]', '5', on_line='target_nonleaf_function_with_loop')
56 // DexExpectWatchValue('src[0]', '8', on_line='target_nonleaf_function_with_loop')
57 // DexExpectWatchValue('src[1]', '4', on_line='target_nonleaf_function_with_loop')
58 // DexExpectWatchValue('src[2]', '5', on_line='target_nonleaf_function_with_loop')
59
60 // DexExpectWatchValue('src[1] == dest[1]', 'true', on_line='target_nonleaf_function_with_loop')
61 // DexExpectWatchValue('src[2] == dest[2]', 'true', on_line='target_nonleaf_function_with_loop')
62
63
64 // This entire function could be optimized into a
65 // simple movl %esi, %eax.
66 // That is because we can compute the loop trip count
67 // knowing that ind-var 'i' can never be negative.
counting_loop(unsigned values)68 __attribute__((optnone)) int counting_loop(unsigned values) {
69 unsigned i = 0;
70 while (values--) // DexLabel('target_counting_loop')
71 i++;
72 return i;
73 }
74
75 // DexLimitSteps('i', 8, 16, on_line='target_counting_loop')
76 // DexExpectWatchValue('i', 8, 16, on_line='target_counting_loop')
77
78
79 // This loop could be rotated.
80 // while(cond){
81 // ..
82 // cond--;
83 // }
84 //
85 // -->
86 // if(cond) {
87 // do {
88 // ...
89 // cond--;
90 // } while(cond);
91 // }
92 //
93 // the compiler will not try to optimize this function.
94 // However the Machine BB Placement Pass will try
95 // to reorder the basic block that computes the
96 // expression 'count' in order to simplify the control
97 // flow.
loop_rotate_test(int * src,unsigned count)98 __attribute__((optnone)) int loop_rotate_test(int *src, unsigned count) {
99 int result = 0;
100
101 while (count) {
102 result += src[count - 1]; // DexLabel('target_loop_rotate_test')
103 count--;
104 }
105 return result; // DexLabel('target_loop_rotate_test_ret')
106 }
107
108 // DexLimitSteps('result', 13, on_line='target_loop_rotate_test')
109 // DexExpectWatchValue('src[count]', 13, on_line='target_loop_rotate_test')
110 // DexLimitSteps('result', 158, on_line='target_loop_rotate_test_ret')
111 // DexExpectWatchValue('result', 158, on_line='target_loop_rotate_test_ret')
112
113
114 typedef int *intptr __attribute__((aligned(16)));
115
116 // This loop can be vectorized if we enable
117 // the loop vectorizer.
loop_vectorize_test(intptr dest,intptr src)118 __attribute__((optnone)) void loop_vectorize_test(intptr dest, intptr src) {
119 unsigned count = 0;
120
121 int tempArray[16];
122
123 while(count != 16) { // DexLabel('target_loop_vectorize_test')
124 tempArray[count] = src[count];
125 tempArray[count+1] = src[count+1]; // DexLabel('target_loop_vectorize_test_2')
126 tempArray[count+2] = src[count+2]; // DexLabel('target_loop_vectorize_test_3')
127 tempArray[count+3] = src[count+3]; // DexLabel('target_loop_vectorize_test_4')
128 dest[count] = tempArray[count]; // DexLabel('target_loop_vectorize_test_5')
129 dest[count+1] = tempArray[count+1]; // DexLabel('target_loop_vectorize_test_6')
130 dest[count+2] = tempArray[count+2]; // DexLabel('target_loop_vectorize_test_7')
131 dest[count+3] = tempArray[count+3]; // DexLabel('target_loop_vectorize_test_8')
132 count += 4; // DexLabel('target_loop_vectorize_test_9')
133 }
134 }
135
136 // DexLimitSteps('count', 4, 8, 12, 16, from_line='target_loop_vectorize_test', to_line='target_loop_vectorize_test_9')
137 // DexExpectWatchValue('tempArray[count] == src[count]', 'true', on_line='target_loop_vectorize_test_2')
138 // DexExpectWatchValue('tempArray[count+1] == src[count+1]', 'true', on_line='target_loop_vectorize_test_3')
139 // DexExpectWatchValue('tempArray[count+2] == src[count+2]', 'true', on_line='target_loop_vectorize_test_4')
140 // DexExpectWatchValue('tempArray[count+3] == src[count+3]', 'true', on_line='target_loop_vectorize_test_5')
141 // DexExpectWatchValue('dest[count] == tempArray[count]', 'true', on_line='target_loop_vectorize_test_6')
142 // DexExpectWatchValue('dest[count+1] == tempArray[count+1]', 'true', on_line='target_loop_vectorize_test_7')
143 // DexExpectWatchValue('dest[count+2] == tempArray[count+2]', 'true', on_line='target_loop_vectorize_test_8')
144 // DexExpectWatchValue('dest[count+3] == tempArray[count+3]', 'true', on_line='target_loop_vectorize_test_9')
145
146
main()147 int main() {
148 int A[] = {3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
149 int B[] = {13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
150 int C[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
151
152 simple_memcpy_loop(C, A, 16);
153 trivial_memcpy_loop(B, C);
154 nonleaf_function_with_loop(B, B);
155 int count = counting_loop(16);
156 count += loop_rotate_test(B, 16);
157 loop_vectorize_test(A, B);
158
159 return A[0] + count;
160 }
161
162