• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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