http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47707
Summary: Loss of step type precision leads to bad scalar evolution Product: gcc Version: 4.6.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization AssignedTo: unassig...@gcc.gnu.org ReportedBy: xinlian...@gmail.com Compiling the following program with O2 and -fno-tree-vrp, the program aborts at runtime #include <assert.h> struct CH { unsigned char ch : 3; } ch; __attribute__((noinline)) void MakeCheckOp (unsigned int *v1, unsigned int *v2) { assert (*v1 == *v2); } int main (void) { int len; for (len = 4; len >= 1; len--) { unsigned v1, v2; ch.ch = len; v1 = ch.ch; v2 = len; MakeCheckOp (&v1, &v2); } } The following is the ir dump before ivopt: int main() () { unsigned int ivtmp.12; int pretmp.11; unsigned int pretmp.10; <unnamed-unsigned:3> pretmp.9; unsigned char pretmp.8; <unnamed-unsigned:3> pretmp.7; unsigned char pretmp.6; unsigned int v2; unsigned int v1; int len; unsigned int len.1; unsigned int v1.0; <unnamed-unsigned:3> D.2142; unsigned char D.2141; <bb 2>: <bb 3>: Invalid sum of incoming frequencies 8400, should be 8000 # len_17 = PHI <len_9(4), 4(2)> # ivtmp.12_21 = PHI <ivtmp.12_20(4), 4(2)> D.2141_4 = (unsigned char) len_17; D.2142_5 = (<unnamed-unsigned:3>) D.2141_4; ch.ch = D.2142_5; v1.0_7 = (unsigned int) D.2142_5; v1 = v1.0_7; len.1_8 = (unsigned int) len_17; v2 = len.1_8; MakeCheckOp (&v1, &v2); len_9 = len_17 - 1; ivtmp.12_20 = ivtmp.12_21 - 1; if (ivtmp.12_20 != 0) goto <bb 4>; else goto <bb 5>; <bb 4>: goto <bb 3>; <bb 5>: Invalid sum of incoming frequencies 1600, should be 2000 return 0; } The scalar evolution for D.2142 is (analyze_scalar_evolution (loop_nb = 1) (scalar = D.2142_5) (get_scalar_evolution (scalar = D.2142_5) (scalar_evolution = {4, +, 7}_1)) (set_scalar_evolution instantiated_below = 2 (scalar = D.2142_5) (scalar_evolution = {4, +, 7}_1)) ) Which is correct, because precision of D.2142's type is 3 bits, so the sequence will wrap: {4,3,2,1} However for v1.0_7 v1.0_7 = (unsigned int) D.2142_5; The scev is wrong: (analyze_scalar_evolution (loop_nb = 1) (scalar = v1.0_7) (get_scalar_evolution (scalar = v1.0_7) (scalar_evolution = {4, +, 7}_1)) (set_scalar_evolution instantiated_below = 2 (scalar = v1.0_7) (scalar_evolution = {4, +, 7}_1)) ) Which will be {4,11,18,....} as there is no wrapping. The proposed fixed is : Index: tree-chrec.c =================================================================== --- tree-chrec.c (revision 170058) +++ tree-chrec.c (working copy) @@ -1238,8 +1238,13 @@ convert_affine_scev (struct loop *loop, performed by default when CT is signed. */ new_step = *step; if (TYPE_PRECISION (step_type) > TYPE_PRECISION (ct) && TYPE_UNSIGNED (ct)) - new_step = chrec_convert_1 (signed_type_for (ct), new_step, at_stmt, - use_overflow_semantics); + { + tree signed_ct = signed_type_for (ct); + if (TYPE_PRECISION (signed_ct) != TYPE_PRECISION (ct)) + signed_ct = build_nonstandard_integer_type (TYPE_PRECISION (ct), 0); + new_step = chrec_convert_1 (signed_ct, new_step, at_stmt, + use_overflow_semantics); + } new_step = chrec_convert_1 (step_type, new_step, at_stmt, use_overflow_semantics); if (automatically_generated_chrec_p (new_base) @@ -1579,4 +1584,3 @@ evolution_function_right_is_integer_cst return false; } } David