xref: /llvm-project/cross-project-tests/debuginfo-tests/dexter-tests/optnone-loops.cpp (revision 45a40c163932d12b72b33bd1d8a84519392b5d39)
11364750dSJames Henderson // Purpose:
21364750dSJames Henderson // Verifies that the debugging experience of loops marked optnone is as expected.
31364750dSJames Henderson 
41364750dSJames Henderson // REQUIRES: lldb
51364750dSJames Henderson // UNSUPPORTED: system-windows
61364750dSJames Henderson // UNSUPPORTED: system-darwin
71364750dSJames Henderson 
8*45a40c16SStephen Tozer // RUN: %clang -std=gnu++11 -O2 -g %s -o %t
91364750dSJames Henderson // RUN: %dexter --fail-lt 1.0 -w \
10*45a40c16SStephen Tozer // RUN:     --binary %t --debugger 'lldb' -- %s
111364750dSJames Henderson 
121364750dSJames Henderson // A simple loop of assignments.
131364750dSJames Henderson // With optimization level > 0 the compiler reorders basic blocks
141364750dSJames Henderson // based on the basic block frequency analysis information.
151364750dSJames Henderson // This also happens with optnone and it shouldn't.
161364750dSJames Henderson // This is not affecting debug info so it is a minor limitation.
171364750dSJames Henderson // Basic block placement based on the block frequency analysis
181364750dSJames Henderson // is normally done to improve i-Cache performances.
simple_memcpy_loop(int * dest,const int * src,unsigned nelems)191364750dSJames Henderson __attribute__((optnone)) void simple_memcpy_loop(int *dest, const int *src,
201364750dSJames Henderson                                                  unsigned nelems) {
211364750dSJames Henderson   for (unsigned i = 0; i != nelems; ++i)
221364750dSJames Henderson     dest[i] = src[i]; // DexLabel('target_simple_memcpy_loop')
231364750dSJames Henderson }
241364750dSJames Henderson 
251364750dSJames Henderson // DexLimitSteps('i', 0, 4, 8, on_line=ref('target_simple_memcpy_loop'))
261364750dSJames Henderson // DexExpectWatchValue('nelems', '16', on_line=ref('target_simple_memcpy_loop'))
271364750dSJames Henderson // DexExpectWatchValue('src[i]', '3', '7', '1', on_line=ref('target_simple_memcpy_loop'))
281364750dSJames Henderson 
291364750dSJames Henderson 
301364750dSJames Henderson // A trivial loop that could be optimized into a builtin memcpy
311364750dSJames Henderson // which is either expanded into a optimal sequence of mov
321364750dSJames Henderson // instructions or directly into a call to memset@plt
trivial_memcpy_loop(int * dest,const int * src)331364750dSJames Henderson __attribute__((optnone)) void trivial_memcpy_loop(int *dest, const int *src) {
341364750dSJames Henderson   for (unsigned i = 0; i != 16; ++i)
351364750dSJames Henderson     dest[i] = src[i]; // DexLabel('target_trivial_memcpy_loop')
361364750dSJames Henderson }
371364750dSJames Henderson 
381364750dSJames Henderson // DexLimitSteps('i', 3, 7, 9, 14, 15, on_line=ref('target_trivial_memcpy_loop'))
391364750dSJames Henderson // DexExpectWatchValue('i', 3, 7, 9, 14, 15, on_line=ref('target_trivial_memcpy_loop'))
401364750dSJames Henderson // DexExpectWatchValue('dest[i-1] == src[i-1]', 'true', on_line=ref('target_trivial_memcpy_loop'))
411364750dSJames Henderson 
421364750dSJames Henderson 
foo(int a)431364750dSJames Henderson __attribute__((always_inline)) int foo(int a) { return a + 5; }
441364750dSJames Henderson 
451364750dSJames Henderson // A trivial loop of calls to a 'always_inline' function.
nonleaf_function_with_loop(int * dest,const int * src)461364750dSJames Henderson __attribute__((optnone)) void nonleaf_function_with_loop(int *dest,
471364750dSJames Henderson                                                          const int *src) {
481364750dSJames Henderson   for (unsigned i = 0; i != 16; ++i)
491364750dSJames Henderson     dest[i] = foo(src[i]); // DexLabel('target_nonleaf_function_with_loop')
501364750dSJames Henderson }
511364750dSJames Henderson 
521364750dSJames Henderson // DexLimitSteps('i', 1, on_line=ref('target_nonleaf_function_with_loop'))
531364750dSJames Henderson // DexExpectWatchValue('dest[0]', '8', on_line=ref('target_nonleaf_function_with_loop'))
541364750dSJames Henderson // DexExpectWatchValue('dest[1]', '4', on_line=ref('target_nonleaf_function_with_loop'))
551364750dSJames Henderson // DexExpectWatchValue('dest[2]', '5', on_line=ref('target_nonleaf_function_with_loop'))
561364750dSJames Henderson // DexExpectWatchValue('src[0]', '8', on_line=ref('target_nonleaf_function_with_loop'))
571364750dSJames Henderson // DexExpectWatchValue('src[1]', '4', on_line=ref('target_nonleaf_function_with_loop'))
581364750dSJames Henderson // DexExpectWatchValue('src[2]', '5', on_line=ref('target_nonleaf_function_with_loop'))
591364750dSJames Henderson 
601364750dSJames Henderson // DexExpectWatchValue('src[1] == dest[1]', 'true', on_line=ref('target_nonleaf_function_with_loop'))
611364750dSJames Henderson // DexExpectWatchValue('src[2] == dest[2]', 'true', on_line=ref('target_nonleaf_function_with_loop'))
621364750dSJames Henderson 
631364750dSJames Henderson 
641364750dSJames Henderson // This entire function could be optimized into a
651364750dSJames Henderson // simple movl %esi, %eax.
661364750dSJames Henderson // That is because we can compute the loop trip count
671364750dSJames Henderson // knowing that ind-var 'i' can never be negative.
counting_loop(unsigned values)681364750dSJames Henderson __attribute__((optnone)) int counting_loop(unsigned values) {
691364750dSJames Henderson   unsigned i = 0;
701364750dSJames Henderson   while (values--) // DexLabel('target_counting_loop')
711364750dSJames Henderson     i++;
721364750dSJames Henderson   return i;
731364750dSJames Henderson }
741364750dSJames Henderson 
751364750dSJames Henderson // DexLimitSteps('i', 8, 16, on_line=ref('target_counting_loop'))
761364750dSJames Henderson // DexExpectWatchValue('i', 8, 16, on_line=ref('target_counting_loop'))
771364750dSJames Henderson 
781364750dSJames Henderson 
791364750dSJames Henderson // This loop could be rotated.
801364750dSJames Henderson // while(cond){
811364750dSJames Henderson //   ..
821364750dSJames Henderson //   cond--;
831364750dSJames Henderson // }
841364750dSJames Henderson //
851364750dSJames Henderson //  -->
861364750dSJames Henderson // if(cond) {
871364750dSJames Henderson //   do {
881364750dSJames Henderson //     ...
891364750dSJames Henderson //     cond--;
901364750dSJames Henderson //   } while(cond);
911364750dSJames Henderson // }
921364750dSJames Henderson //
931364750dSJames Henderson // the compiler will not try to optimize this function.
941364750dSJames Henderson // However the Machine BB Placement Pass will try
951364750dSJames Henderson // to reorder the basic block that computes the
961364750dSJames Henderson // expression 'count' in order to simplify the control
971364750dSJames Henderson // flow.
loop_rotate_test(int * src,unsigned count)981364750dSJames Henderson __attribute__((optnone)) int loop_rotate_test(int *src, unsigned count) {
991364750dSJames Henderson   int result = 0;
1001364750dSJames Henderson 
1011364750dSJames Henderson   while (count) {
1021364750dSJames Henderson     result += src[count - 1]; // DexLabel('target_loop_rotate_test')
1031364750dSJames Henderson     count--;
1041364750dSJames Henderson   }
1051364750dSJames Henderson   return result; // DexLabel('target_loop_rotate_test_ret')
1061364750dSJames Henderson }
1071364750dSJames Henderson 
1081364750dSJames Henderson // DexLimitSteps('result', 13, on_line=ref('target_loop_rotate_test'))
1091364750dSJames Henderson // DexExpectWatchValue('src[count]', 13, on_line=ref('target_loop_rotate_test'))
1101364750dSJames Henderson // DexLimitSteps('result', 158, on_line=ref('target_loop_rotate_test_ret'))
1111364750dSJames Henderson // DexExpectWatchValue('result', 158, on_line=ref('target_loop_rotate_test_ret'))
1121364750dSJames Henderson 
1131364750dSJames Henderson 
1141364750dSJames Henderson typedef int *intptr __attribute__((aligned(16)));
1151364750dSJames Henderson 
1161364750dSJames Henderson // This loop can be vectorized if we enable
1171364750dSJames Henderson // the loop vectorizer.
loop_vectorize_test(intptr dest,intptr src)1181364750dSJames Henderson __attribute__((optnone)) void loop_vectorize_test(intptr dest, intptr src) {
1191364750dSJames Henderson   unsigned count = 0;
1201364750dSJames Henderson 
1211364750dSJames Henderson   int tempArray[16];
1221364750dSJames Henderson 
1231364750dSJames Henderson   while(count != 16) { // DexLabel('target_loop_vectorize_test')
1241364750dSJames Henderson     tempArray[count] = src[count];
1251364750dSJames Henderson     tempArray[count+1] = src[count+1]; // DexLabel('target_loop_vectorize_test_2')
1261364750dSJames Henderson     tempArray[count+2] = src[count+2]; // DexLabel('target_loop_vectorize_test_3')
1271364750dSJames Henderson     tempArray[count+3] = src[count+3]; // DexLabel('target_loop_vectorize_test_4')
1281364750dSJames Henderson     dest[count] = tempArray[count]; // DexLabel('target_loop_vectorize_test_5')
1291364750dSJames Henderson     dest[count+1] = tempArray[count+1]; // DexLabel('target_loop_vectorize_test_6')
1301364750dSJames Henderson     dest[count+2] = tempArray[count+2]; // DexLabel('target_loop_vectorize_test_7')
1311364750dSJames Henderson     dest[count+3] = tempArray[count+3]; // DexLabel('target_loop_vectorize_test_8')
1321364750dSJames Henderson     count += 4; // DexLabel('target_loop_vectorize_test_9')
1331364750dSJames Henderson   }
1341364750dSJames Henderson }
1351364750dSJames Henderson 
1361364750dSJames Henderson // DexLimitSteps('count', 4, 8, 12, 16, from_line=ref('target_loop_vectorize_test'), to_line=ref('target_loop_vectorize_test_9'))
1371364750dSJames Henderson // DexExpectWatchValue('tempArray[count] == src[count]', 'true', on_line=ref('target_loop_vectorize_test_2'))
1381364750dSJames Henderson // DexExpectWatchValue('tempArray[count+1] == src[count+1]', 'true', on_line=ref('target_loop_vectorize_test_3'))
1391364750dSJames Henderson // DexExpectWatchValue('tempArray[count+2] == src[count+2]', 'true', on_line=ref('target_loop_vectorize_test_4'))
1401364750dSJames Henderson // DexExpectWatchValue('tempArray[count+3] == src[count+3]', 'true', on_line=ref('target_loop_vectorize_test_5'))
1411364750dSJames Henderson // DexExpectWatchValue('dest[count] == tempArray[count]', 'true', on_line=ref('target_loop_vectorize_test_6'))
1421364750dSJames Henderson // DexExpectWatchValue('dest[count+1] == tempArray[count+1]', 'true', on_line=ref('target_loop_vectorize_test_7'))
1431364750dSJames Henderson // DexExpectWatchValue('dest[count+2] == tempArray[count+2]', 'true', on_line=ref('target_loop_vectorize_test_8'))
1441364750dSJames Henderson // DexExpectWatchValue('dest[count+3] == tempArray[count+3]', 'true', on_line=ref('target_loop_vectorize_test_9'))
1451364750dSJames Henderson 
1461364750dSJames Henderson 
main()1471364750dSJames Henderson int main() {
1481364750dSJames Henderson   int A[] = {3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
1491364750dSJames Henderson   int B[] = {13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
1501364750dSJames Henderson   int C[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1511364750dSJames Henderson 
1521364750dSJames Henderson   simple_memcpy_loop(C, A, 16);
1531364750dSJames Henderson   trivial_memcpy_loop(B, C);
1541364750dSJames Henderson   nonleaf_function_with_loop(B, B);
1551364750dSJames Henderson   int count = counting_loop(16);
1561364750dSJames Henderson   count += loop_rotate_test(B, 16);
1571364750dSJames Henderson   loop_vectorize_test(A, B);
1581364750dSJames Henderson 
1591364750dSJames Henderson   return A[0] + count;
1601364750dSJames Henderson }
1611364750dSJames Henderson 
162