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. 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(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 114 typedef 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 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