I've been experimenting with devirtualizing method calls, and sometimes a construct like this can pay dividends:
/* Fetch vtable entry into D.914, then... */ if (D.914 != bar) { /* Make virtual call. */ D.915 = D.914 (this.7, p.6); iftmp.8 = D.915; } else { /* Make direct call. */ D.916 = bar (this.7, p.6); iftmp.8 = D.916; } but this is only useful if the call to bar() gets inlined. On its own this optimization isn't very interesting, but it exposes more optimization opportunities. So, I suppose that what I need to do is make a pass over the trees after inlining to convert this back into a simple virtual call. However, once I do this the CFG is no longer correct, because there's no longer an edge to bar(). Another possibility is to have the inliner convert virtual calls into something like the above. Maybe the real solution to all of is is to have a representation for virtual calls in the IL, but... So, what I'm thinking of doing is writing a post-inlining pass that rewrites the trees and then tidies up the CFG. Is this the right approach? Thanks, Andrew.