This is Peizhao here, a graduate student from UC Irvine. My recent work involves studying the performance of a dependence preserving compiler for C/C++11. The motivation of doing this comes from Boehm and Demsky’s paper about outlawing OOTA behaviors for the C/C++11 memory model (http://plrg.eecs.uci.edu/publications/mspc14.pdf).
Basically I am trying to preserve a syntactic dependence of the original program, and the way I am achieving this goal is to modify/disable IR->IR passes and backend optimization passes too. For example, for the instruction “%Y = mul i32 %X, 0”, typically the IR pass “instcombine” would optimize out this instruction and replace Y’s usage with the value 0. Our change to this pass would simply disable those dependence breaking optimizations. Note that we also need to preserve the control dependence, so we have also modified optimizations such as “simplifycfg”, etc.
So far, I have finished modifying a select set of front-end passes (IR->IR) and can generate a mostly optimized IR that preserves dependence. Our next step is to modify the X86 backend optimizations. My current strategy for the X86 backend is similar to that of the IR->IR passes, which is to pay attention to those peephole optimizations and those that would break the control dependence of a given IR.
Finally, I am wondering if you guys have comments on our approach to a dependence-preserving backend. Or, is there anything you guys think I should pay attention to in terms of dependence breaking (such as specific passes)? From my understanding, but correct me if I am wrong, once you generate the SelectionDAG, the X86 backend doesn’t do too much to break the control flow, so I could mostly focus on peephole optimizations within basic blocks? Thanks, folks!