diff --git a/debuginfo-tests/dexter-tests/optnone-fastmath.cpp b/debuginfo-tests/dexter-tests/optnone-fastmath.cpp new file mode 100644 --- /dev/null +++ b/debuginfo-tests/dexter-tests/optnone-fastmath.cpp @@ -0,0 +1,104 @@ +// RUN: %dexter --fail-lt 1.0 -w \ +// RUN: --builder 'clang' --debugger 'lldb' \ +// RUN: --cflags "-ffast-math -O2 -g" -- %s +// RUN: %dexter --fail-lt 1.0 -w \ +// RUN: --builder 'clang' --debugger 'lldb' \ +// RUN: --cflags "-ffast-math -O0 -g" -- %s + +// REQUIRES: lldb +// UNSUPPORTED: system-windows + +//// Check that the debugging experience with __attribute__((optnone)) at O2 +//// matches O0. Test scalar floating point arithmetic with -ffast-math. + +//// Example of strength reduction. +//// The division by 10.0f can be rewritten as a multiply by 0.1f. +//// A / 10.f ==> A * 0.1f +//// This is safe with fastmath since we treat the two operations +//// as equally precise. However we don't want this to happen +//// with optnone. +__attribute__((optnone)) +float test_fdiv(float A) { + float result; + result = A / 10.f; // DexLabel('fdiv_assign') + return result; // DexLabel('fdiv_ret') +} +// DexExpectWatchValue('A', 4, on_line='fdiv_assign') +// DexExpectWatchValue('result', '0.400000006', on_line='fdiv_ret') + +//// (A * B) - (A * C) ==> A * (B - C) +__attribute__((optnone)) +float test_distributivity(float A, float B, float C) { + float result; + float op1 = A * B; + float op2 = A * C; // DexLabel('distributivity_op2') + result = op1 - op2; // DexLabel('distributivity_result') + return result; // DexLabel('distributivity_ret') +} +// DexExpectWatchValue('op1', '20', on_line='distributivity_op2') +// DexExpectWatchValue('op2', '24', on_line='distributivity_result') +// DexExpectWatchValue('result', '-4', on_line='distributivity_ret') + +//// (A + B) + C == A + (B + C) +//// therefore, ((A + B) + C) + (A + (B + C))) +//// can be rewritten as +//// 2.0f * ((A + B) + C) +//// Clang is currently unable to spot this optimization +//// opportunity with fastmath. +__attribute__((optnone)) +float test_associativity(float A, float B, float C) { + float result; + float op1 = A + B; + float op2 = B + C; + op1 += C; // DexLabel('associativity_op1') + op2 += A; + result = op1 + op2; // DexLabel('associativity_result') + return result; // DexLabel('associativity_ret') +} +// DexExpectWatchValue('op1', '9', '15', from_line='associativity_op1', to_line='associativity_result') +// DexExpectWatchValue('op2', '11', '15', from_line='associativity_op1', to_line='associativity_result') +// DexExpectWatchValue('result', '30', on_line='associativity_ret') + +//// With fastmath, the ordering of instructions doesn't matter +//// since we work under the assumption that there is no loss +//// in precision. This simplifies things for the optimizer which +//// can then decide to reorder instructions and fold +//// redundant operations like this: +//// A += 5.0f +//// A -= 5.0f +//// --> +//// A +//// This function can be simplified to a return A + B. +__attribute__((optnone)) +float test_simplify_fp_operations(float A, float B) { + float result = A + 10.0f; // DexLabel('fp_operations_result') + result += B; // DexLabel('fp_operations_add') + result -= 10.0f; + return result; // DexLabel('fp_operations_ret') +} +// DexExpectWatchValue('A', '8.25', on_line='fp_operations_result') +// DexExpectWatchValue('B', '26.3999996', on_line='fp_operations_result') +// DexExpectWatchValue('result', '18.25', '44.6500015', '34.6500015', from_line='fp_operations_add', to_line='fp_operations_ret') + +//// Again, this is a simple return A + B. +//// Clang is unable to spot the opportunity to fold the code sequence. +__attribute__((optnone)) +float test_simplify_fp_operations_2(float A, float B, float C) { + float result = A + C; // DexLabel('fp_operations_2_result') + result += B; + result -= C; // DexLabel('fp_operations_2_subtract') + return result; // DexLabel('fp_operations_2_ret') +} +// DexExpectWatchValue('A', '9.11999988', on_line='fp_operations_2_result') +// DexExpectWatchValue('B', '61.050003', on_line='fp_operations_2_result') +// DexExpectWatchValue('C', '1002.11102', on_line='fp_operations_2_result') +// DexExpectWatchValue('result', '1072.28101', '70.1699829', from_line='fp_operations_2_subtract', to_line='fp_operations_2_ret') + +int main() { + float result = test_fdiv(4.0f); + result += test_distributivity(4.0f, 5.0f, 6.0f); + result += test_associativity(4.0f, 5.0f, 6.0f); + result += test_simplify_fp_operations(8.25, result); + result += test_simplify_fp_operations_2(9.12, result, 1002.111); + return static_cast(result); +} diff --git a/debuginfo-tests/dexter-tests/optnone-simple-functions.cpp b/debuginfo-tests/dexter-tests/optnone-simple-functions.cpp new file mode 100644 --- /dev/null +++ b/debuginfo-tests/dexter-tests/optnone-simple-functions.cpp @@ -0,0 +1,104 @@ +// RUN: %dexter --fail-lt 1.0 -w \ +// RUN: --builder 'clang' --debugger 'lldb' \ +// RUN: --cflags "-O2 -g" -- %s +// RUN: %dexter --fail-lt 1.0 -w \ +// RUN: --builder 'clang' --debugger 'lldb' \ +// RUN: --cflags "-O0 -g" -- %s + +// REQUIRES: lldb +// UNSUPPORTED: system-windows + +//// Check that the debugging experience with __attribute__((optnone)) at O2 +//// matches O0. Test simple functions performing simple arithmetic +//// operations and small loops. + +__attribute__((optnone)) +int test1(int test1_a, int test1_b) { + int test1_result = 0; + // DexLabel('test1_start') + test1_result = test1_a + test1_b; // DexExpectStepOrder(1) + return test1_result; // DexExpectStepOrder(2) + // DexLabel('test1_end') +} +// DexExpectWatchValue('test1_a', 3, from_line='test1_start', to_line='test1_end') +// DexExpectWatchValue('test1_b', 4, from_line='test1_start', to_line='test1_end') +// DexExpectWatchValue('test1_result', 0, 7, from_line='test1_start', to_line='test1_end') + +__attribute__((optnone)) +int test2(int test2_a, int test2_b) { + int test2_result = test2_a + test2_a + test2_a + test2_a; // DexExpectStepOrder(3) + // DexLabel('test2_start') + return test2_a << 2; // DexExpectStepOrder(4) + // DexLabel('test2_end') +} +// DexExpectWatchValue('test2_a', 1, from_line='test2_start', to_line='test2_end') +// DexExpectWatchValue('test2_b', 2, from_line='test2_start', to_line='test2_end') +// DexExpectWatchValue('test2_result', 4, from_line='test2_start', to_line='test2_end') + +__attribute__((optnone)) +int test3(int test3_a, int test3_b) { + int test3_temp1 = 0, test3_temp2 = 0; + // DexLabel('test3_start') + test3_temp1 = test3_a + 5; // DexExpectStepOrder(5) + test3_temp2 = test3_b + 5; // DexExpectStepOrder(6) + if (test3_temp1 > test3_temp2) { // DexExpectStepOrder(7) + test3_temp1 *= test3_temp2; // DexUnreachable() + } + return test3_temp1; // DexExpectStepOrder(8) + // DexLabel('test3_end') +} +// DexExpectWatchValue('test3_a', 5, from_line='test3_start', to_line='test3_end') +// DexExpectWatchValue('test3_b', 6, from_line='test3_start', to_line='test3_end') +// DexExpectWatchValue('test3_temp1', 0, 10, from_line='test3_start', to_line='test3_end') +// DexExpectWatchValue('test3_temp2', 0, 11, from_line='test3_start', to_line='test3_end') + +unsigned num_iterations = 4; + +__attribute__((optnone)) +int test4(int test4_a, int test4_b) { + int val1 = 0, val2 = 0; + // DexLabel('test4_start') + + val1 = (test4_a > test4_b) ? test4_a : test4_b; // DexExpectStepOrder(9) + val2 = val1; + val2 += val1; // DexExpectStepOrder(10) + + for (unsigned i=0; i != num_iterations; ++i) { // DexExpectStepOrder(11, 13, 15, 17, 19) + val1--; + val2 += i; + if (val2 % 2 == 0) // DexExpectStepOrder(12, 14, 16, 18) + val2 /= 2; + } + + return (val1 > val2) ? val2 : val1; // DexExpectStepOrder(20) + // DexLabel('test4_end') +} +// DexExpectWatchValue('test4_a', 1, from_line='test4_start', to_line='test4_end') +// DexExpectWatchValue('test4_b', 9, from_line='test4_start', to_line='test4_end') +// DexExpectWatchValue('val1', 0, 9, 8, 7, 6, 5, from_line='test4_start', to_line='test4_end') +// DexExpectWatchValue('val2', 0, 9, 18, 9, 10, 5, 7, 10, 5, 9, from_line='test4_start', to_line='test4_end') + +__attribute__((optnone)) +int test5(int test5_val) { + int c = 1; // DexExpectStepOrder(21) + // DexLabel('test5_start') + if (test5_val) // DexExpectStepOrder(22) + c = 5; // DexExpectStepOrder(23) + return c ? test5_val : test5_val; // DexExpectStepOrder(24) + // DexLabel('test5_end') +} +// DexExpectWatchValue('test5_val', 7, from_line='test5_start', to_line='test5_end') +// DexExpectWatchValue('c', 1, 5, from_line='test5_start', to_line='test5_end') + +int main() { + int main_result = 0; + // DexLabel('main_start') + main_result = test1(3,4); + main_result += test2(1,2); + main_result += test3(5,6); + main_result += test4(1,9); + main_result += test5(7); + return main_result; + // DexLabel('main_end') +} +// DexExpectWatchValue('main_result', 0, 7, 11, 21, 26, 33, from_line='main_start', to_line='main_end') diff --git a/debuginfo-tests/dexter-tests/optnone-struct-and-methods.cpp b/debuginfo-tests/dexter-tests/optnone-struct-and-methods.cpp new file mode 100644 --- /dev/null +++ b/debuginfo-tests/dexter-tests/optnone-struct-and-methods.cpp @@ -0,0 +1,105 @@ +// RUN: %dexter --fail-lt 1.0 -w \ +// RUN: --builder 'clang' --debugger 'lldb' \ +// RUN: --cflags "-g -O2" -v -- %s +// RUN: %dexter --fail-lt 1.0 -w \ +// RUN: --builder 'clang' --debugger 'lldb' \ +// RUN: --cflags "-g -O0" -- %s + +// REQUIRES: lldb +// UNSUPPORTED: system-windows + +//// Check that the debugging experience with __attribute__((optnone)) at O2 +//// matches O0. Test simple structs and methods. + +long a_global_ptr[] = { 0xCAFEBABEL, 0xFEEDBEEFL }; + +namespace { + +struct A { + int a; + float b; + + enum B { + A_VALUE = 0x1, + B_VALUE = 0x2 + }; + + struct some_data { + enum B other_b; + enum B other_other_b; + }; + + struct other_data { + union { + void *raw_ptr; + long *long_ptr; + float *float_ptr; + } a; + struct some_data b; + struct some_data c; + }; +private: + struct other_data _data; + +public: + struct other_data *getOtherData() { return &_data; } + + __attribute__((always_inline,nodebug)) + void setSomeData1(A::B value, A::B other_value) { + struct other_data *data = getOtherData(); + data->b.other_b = value; + data->b.other_other_b = other_value; + } + + __attribute__((always_inline)) + void setSomeData2(A::B value, A::B other_value) { + struct other_data *data = getOtherData(); + data->c.other_b = value; + data->c.other_other_b = other_value; + } + + void setOtherData() { + setSomeData2(A_VALUE, B_VALUE); + getOtherData()->a.long_ptr = &a_global_ptr[0]; + } + + __attribute__((optnone)) + A() { + __builtin_memset(this, 0xFF, sizeof(*this)); + } //DexLabel('break_0') + // DexExpectWatchValue('a', '-1', on_line='break_0') + //// Check b is NaN by comparing it to itself. + // DexExpectWatchValue('this->b == this->b', 'false', on_line='break_0') + // DexExpectWatchValue('_data.a.raw_ptr == -1', 'true', on_line='break_0') + // DexExpectWatchValue('_data.a.float_ptr == -1', 'true', on_line='break_0') + // DexExpectWatchValue('_data.a.float_ptr == -1', 'true', on_line='break_0') + // DexExpectWatchValue('a_global_ptr[0]', 0xcafebabe, on_line='break_0') + // DexExpectWatchValue('a_global_ptr[1]', 0xfeedbeef, on_line='break_0') + + __attribute__((optnone)) + ~A() { + *getOtherData()->a.long_ptr = 0xADDF00DL; + } //DexLabel('break_1') + // DexExpectWatchValue('_data.a.raw_ptr == a_global_ptr', 'true', on_line='break_1') + // DexExpectWatchValue('a_global_ptr[0]', 0xaddf00d, on_line='break_1') + + __attribute__((optnone)) + long getData() { + setSomeData1(B_VALUE, A_VALUE); + setOtherData(); + return getOtherData()->a.long_ptr[1]; //DexLabel('break_2') + } + // DexExpectWatchValue('_data.b.other_b', 'B_VALUE', on_line='break_2') + // DexExpectWatchValue('_data.b.other_other_b', 'A_VALUE', on_line='break_2') +}; + +} // anonymous namespace + +int main() { + int result = 0; + { + A a; + result = a.getData(); + } + return result; +} diff --git a/debuginfo-tests/dexter-tests/optnone-vectors-and-functions.cpp b/debuginfo-tests/dexter-tests/optnone-vectors-and-functions.cpp new file mode 100644 --- /dev/null +++ b/debuginfo-tests/dexter-tests/optnone-vectors-and-functions.cpp @@ -0,0 +1,135 @@ +// RUN: %dexter --fail-lt 1.0 -w \ +// RUN: --builder 'clang' --debugger 'lldb' \ +// RUN: --cflags "-g -O2" -v -- %s +// RUN: %dexter --fail-lt 1.0 -w \ +// RUN: --builder 'clang' --debugger 'lldb' \ +// RUN: --cflags "-g -O0" -- %s + +// REQUIRES: lldb +// UNSUPPORTED: system-windows + +//// Check that the debugging experience with __attribute__((optnone)) at O2 +//// matches O0. Test simple template functions performing simple arithmetic +//// vector operations and trivial loops. + +typedef int int4 __attribute__((ext_vector_type(4))); +template struct TypeTraits {}; + +template<> +struct TypeTraits { + static const unsigned NumElements = 4; + static const unsigned UnusedField = 0xDEADBEEFU; + static unsigned MysteryNumber; +}; +unsigned TypeTraits::MysteryNumber = 3U; + +template +__attribute__((optnone)) +T test1(T x, T y) { + T tmp = x + y; // DexLabel('break_0') + T tmp2 = tmp + y; + return tmp; // DexLabel('break_1') +} +// DexLimitSteps('1', '1', from_line='break_0', to_line='break_1') +//// FIXME: gdb can print this but lldb cannot. Perhaps PR42920? +// \DexExpectWatchValue('TypeTraits::NumElements', 4, on_line='break_0') +// \DexExpectWatchValue('TypeTraits::UnusedField', 0xdeadbeef, on_line='break_0') +// DexExpectWatchValue('x[0]', 1, on_line='break_0') +// DexExpectWatchValue('x[1]', 2, on_line='break_0') +// DexExpectWatchValue('x[2]', 3, on_line='break_0') +// DexExpectWatchValue('x[3]', 4, on_line='break_0') +// DexExpectWatchValue('y[0]', 5, on_line='break_0') +// DexExpectWatchValue('y[1]', 6, on_line='break_0') +// DexExpectWatchValue('y[2]', 7, on_line='break_0') +// DexExpectWatchValue('y[3]', 8, on_line='break_0') +// DexExpectWatchValue('tmp[0]', 6, on_line='break_1') +// DexExpectWatchValue('tmp[1]', 8, on_line='break_1') +// DexExpectWatchValue('tmp[2]', 10, on_line='break_1') +// DexExpectWatchValue('tmp[3]', 12, on_line='break_1') +// DexExpectWatchValue('tmp2[0]', 11, on_line='break_1') +// DexExpectWatchValue('tmp2[1]', 14, on_line='break_1') +// DexExpectWatchValue('tmp2[2]', 17, on_line='break_1') +// DexExpectWatchValue('tmp2[3]', 20, on_line='break_1') + +template +__attribute__((optnone)) +T test2(T x, T y) { + T tmp = x; + int break_2 = 0; // DexLabel('break_2') + for (unsigned i = 0; i != TypeTraits::NumElements; ++i) { + tmp <<= 1; // DexLabel('break_3') + tmp |= y; + } + + tmp[0] >>= TypeTraits::MysteryNumber; + return tmp; // DexLabel('break_5') +} +// DexLimitSteps('1', '1', on_line='break_2') +// DexExpectWatchValue('x[0]', 6, on_line='break_2') +// DexExpectWatchValue('x[1]', 8, on_line='break_2') +// DexExpectWatchValue('x[2]', 10, on_line='break_2') +// DexExpectWatchValue('x[3]', 12, on_line='break_2') +// DexExpectWatchValue('y[0]', 5, on_line='break_2') +// DexExpectWatchValue('y[1]', 6, on_line='break_2') +// DexExpectWatchValue('y[2]', 7, on_line='break_2') +// DexExpectWatchValue('y[3]', 8, on_line='break_2') +// DexExpectWatchValue('tmp[0]', 6, on_line='break_2') +// DexExpectWatchValue('tmp[1]', 8, on_line='break_2') +// DexExpectWatchValue('tmp[2]', 10, on_line='break_2') +// DexExpectWatchValue('tmp[3]', 12, on_line='break_2') +// DexLimitSteps('i', 3, on_line='break_3') +// DexExpectWatchValue('tmp[0]', 63, on_line='break_3') +// DexExpectWatchValue('tmp[1]', 94, on_line='break_3') +// DexExpectWatchValue('tmp[2]', 95, on_line='break_3') +// DexExpectWatchValue('tmp[3]', 120, on_line='break_3') +// DexLimitSteps('i', 3, on_line='break_5') +// DexExpectWatchValue('tmp[0]', 15, on_line='break_5') + +template +__attribute__((optnone)) +T test3(T InVec) { + T result; + for (unsigned i=0; i != TypeTraits::NumElements; ++i) + result[i] = InVec[i]; // DexLabel('break_6') + return result; // DexLabel('break_7') +} +// DexLimitSteps('i', '3', from_line='break_6', to_line='break_7') +// DexExpectWatchValue('InVec[0]', 15, from_line='break_6', to_line='break_7') +// DexExpectWatchValue('InVec[1]', 190, from_line='break_6', to_line='break_7') +// DexExpectWatchValue('InVec[2]', 191, from_line='break_6', to_line='break_7') +// DexExpectWatchValue('InVec[3]', 248, from_line='break_6', to_line='break_7') +// DexExpectWatchValue('result[0]', 15, from_line='break_6', to_line='break_7') +// DexExpectWatchValue('result[1]', 190, from_line='break_6', to_line='break_7') +// DexExpectWatchValue('result[2]', 191, from_line='break_6', to_line='break_7') +// DexExpectWatchValue('result[3]', 248, on_line='break_7') + +template +__attribute__((optnone)) +T test4(T x, T y) { + for (unsigned i=0; i != TypeTraits::NumElements; ++i) + x[i] = (x[i] > y[i])? x[i] : y[i] + TypeTraits::MysteryNumber; // DexLabel('break_11') + return x; // DexLabel('break_12') +} +// DexLimitSteps('1', '1', from_line='break_11', to_line='break_12') +//// FIXME: lldb won't print this but gdb unexpectedly says it's optimized out, even at O0. +// \DexExpectWatchValue('TypeTraits::MysteryNumber', 3, on_line='break_11') +// DexExpectWatchValue('i', 0, 1, 2, 3, on_line='break_11') +// DexExpectWatchValue('x[0]', 1, 8, from_line='break_11', to_line='break_12') +// DexExpectWatchValue('x[1]', 2, 9, from_line='break_11', to_line='break_12') +// DexExpectWatchValue('x[2]', 3, 10, from_line='break_11', to_line='break_12') +// DexExpectWatchValue('x[3]', 4, 11, from_line='break_11', to_line='break_12') +// DexExpectWatchValue('y[0]', 5, from_line='break_11', to_line='break_12') +// DexExpectWatchValue('y[1]', 6, from_line='break_11', to_line='break_12') +// DexExpectWatchValue('y[2]', 7, from_line='break_11', to_line='break_12') +// DexExpectWatchValue('y[3]', 8, from_line='break_11', to_line='break_12') + +int main() { + int4 a = (int4){1,2,3,4}; + int4 b = (int4){5,6,7,8}; + + int4 tmp = test1(a,b); + tmp = test2(tmp,b); + tmp = test3(tmp); + tmp += test4(a,b); + return tmp[0]; +}