http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35305
--- Comment #4 from davidxl <xinliangli at gmail dot com> 2012-10-30 18:57:18 UTC --- The suggested transformation can be useful in some cases, but won't be general enough. The listed example is an extreme case. For instance, the second a+b instance does not have to be in the hot trace but still still hot enough to be PREed. Or there is no one dominating traces available -- the expression is available in all incoming paths except for one rare path. switch (a) { case 1: g[1] = a + b; break; case 2: g[2] = a + b; break; case 3: g[3] = a + b; ... default: g[0] = 0; } switch (b) { case 1: ... a + b; // partially redundant case 2: ... a + b; // redundant default: // does nothing break; } Regarding handling dereferences, the availability and down-safety analysis needs to be extended to to recognize safe speculation candidates. Example 1: dereference of same pointer fully available -- int g1, g2; struct A { int a; int b; }; void foo(struct A* ap, int k,int m) { if (__builtin_expect (k, 1)) g1 = ap->b; else g2 = ap->a; if (__builtin_expect (m, 1)) { g2 = ap->b; // Good safe speculative PRE candidate } } Example 2: deference of ap fully anticipated int g1, g2; struct A { int a; int b; }; void foo(struct A* ap, int k,int m) { if (__builtin_expect (k, 1)) g1 = ap->b; if (__builtin_expect (m, 1)) g2 = ap->b; // Safe to speculatively hoist across the branch into the else of the previous branch else g1 = ap->a; } David (In reply to comment #3) > Wouldn't this be a candidate for forming a superblock from hot traces of > a function? Thus in the testcase > > if (k && m) > { > g1 = a + b; > g2 = a + b; > } > else > { > ... old code > } > > which would also handle the case where we cannot speculatively move code > (like dereferences)?