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: %clang -std=gnu++11 -O2 -g %s -o %t
9// RUN: %dexter --fail-lt 1.0 -w \
10// RUN: --binary %t --debugger 'lldb' -- %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.
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=ref('target_simple_memcpy_loop'))
26// DexExpectWatchValue('nelems', '16', on_line=ref('target_simple_memcpy_loop'))
27// DexExpectWatchValue('src[i]', '3', '7', '1', on_line=ref('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
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=ref('target_trivial_memcpy_loop'))
39// DexExpectWatchValue('i', 3, 7, 9, 14, 15, on_line=ref('target_trivial_memcpy_loop'))
40// DexExpectWatchValue('dest[i-1] == src[i-1]', 'true', on_line=ref('target_trivial_memcpy_loop'))
41
42
43__attribute__((always_inline)) int foo(int a) { return a + 5; }
44
45// A trivial loop of calls to a 'always_inline' function.
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(a: src[i]); // DexLabel('target_nonleaf_function_with_loop')
50}
51
52// DexLimitSteps('i', 1, on_line=ref('target_nonleaf_function_with_loop'))
53// DexExpectWatchValue('dest[0]', '8', on_line=ref('target_nonleaf_function_with_loop'))
54// DexExpectWatchValue('dest[1]', '4', on_line=ref('target_nonleaf_function_with_loop'))
55// DexExpectWatchValue('dest[2]', '5', on_line=ref('target_nonleaf_function_with_loop'))
56// DexExpectWatchValue('src[0]', '8', on_line=ref('target_nonleaf_function_with_loop'))
57// DexExpectWatchValue('src[1]', '4', on_line=ref('target_nonleaf_function_with_loop'))
58// DexExpectWatchValue('src[2]', '5', on_line=ref('target_nonleaf_function_with_loop'))
59
60// DexExpectWatchValue('src[1] == dest[1]', 'true', on_line=ref('target_nonleaf_function_with_loop'))
61// DexExpectWatchValue('src[2] == dest[2]', 'true', on_line=ref('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.
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=ref('target_counting_loop'))
76// DexExpectWatchValue('i', 8, 16, on_line=ref('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.
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=ref('target_loop_rotate_test'))
109// DexExpectWatchValue('src[count]', 13, on_line=ref('target_loop_rotate_test'))
110// DexLimitSteps('result', 158, on_line=ref('target_loop_rotate_test_ret'))
111// DexExpectWatchValue('result', 158, on_line=ref('target_loop_rotate_test_ret'))
112
113
114typedef int *intptr __attribute__((aligned(16)));
115
116// This loop can be vectorized if we enable
117// the loop vectorizer.
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=ref('target_loop_vectorize_test'), to_line=ref('target_loop_vectorize_test_9'))
137// DexExpectWatchValue('tempArray[count] == src[count]', 'true', on_line=ref('target_loop_vectorize_test_2'))
138// DexExpectWatchValue('tempArray[count+1] == src[count+1]', 'true', on_line=ref('target_loop_vectorize_test_3'))
139// DexExpectWatchValue('tempArray[count+2] == src[count+2]', 'true', on_line=ref('target_loop_vectorize_test_4'))
140// DexExpectWatchValue('tempArray[count+3] == src[count+3]', 'true', on_line=ref('target_loop_vectorize_test_5'))
141// DexExpectWatchValue('dest[count] == tempArray[count]', 'true', on_line=ref('target_loop_vectorize_test_6'))
142// DexExpectWatchValue('dest[count+1] == tempArray[count+1]', 'true', on_line=ref('target_loop_vectorize_test_7'))
143// DexExpectWatchValue('dest[count+2] == tempArray[count+2]', 'true', on_line=ref('target_loop_vectorize_test_8'))
144// DexExpectWatchValue('dest[count+3] == tempArray[count+3]', 'true', on_line=ref('target_loop_vectorize_test_9'))
145
146
147int 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(dest: C, src: A, nelems: 16);
153 trivial_memcpy_loop(dest: B, src: C);
154 nonleaf_function_with_loop(dest: B, src: B);
155 int count = counting_loop(values: 16);
156 count += loop_rotate_test(src: B, count: 16);
157 loop_vectorize_test(dest: A, src: B);
158
159 return A[0] + count;
160}
161
162

source code of cross-project-tests/debuginfo-tests/dexter-tests/optnone-loops.cpp