|
63 | 63 | #include "llvm/IR/Instruction.h" |
64 | 64 | #include "llvm/IR/Instructions.h" |
65 | 65 | #include "llvm/IR/IntrinsicInst.h" |
| 66 | +// EVM local begin |
| 67 | +#include "llvm/IR/IntrinsicsEVM.h" |
| 68 | +// EVM local begin |
66 | 69 | #include "llvm/IR/Module.h" |
67 | 70 | #include "llvm/IR/PassManager.h" |
68 | 71 | #include "llvm/IR/PatternMatch.h" |
|
73 | 76 | #include "llvm/Support/DebugCounter.h" |
74 | 77 | #include "llvm/Support/ErrorHandling.h" |
75 | 78 | #include "llvm/Support/raw_ostream.h" |
| 79 | +// EVM local begin |
| 80 | +#include "llvm/TargetParser/Triple.h" |
| 81 | +// EVM local end |
76 | 82 | #include "llvm/Transforms/Utils/AssumeBundleBuilder.h" |
77 | 83 | #include "llvm/Transforms/Utils/BuildLibCalls.h" |
78 | 84 | #include "llvm/Transforms/Utils/Local.h" |
@@ -1801,6 +1807,29 @@ struct DSEState { |
1801 | 1807 | return false; |
1802 | 1808 | } |
1803 | 1809 |
|
| 1810 | + /// Verify whether there is a path from the block containing the store to a |
| 1811 | + /// return block, i.e., a block that does not end with 'unreachable'. |
| 1812 | + bool isOnPathToFunctionReturn(const MemoryDef *MaybeDeadDef) { |
| 1813 | + const BasicBlock *BB = MaybeDeadDef->getBlock(); |
| 1814 | + // Handle the trivial case where the store resides in a block that ends |
| 1815 | + // with 'unreachable'. |
| 1816 | + if (isa<UnreachableInst>(BB->getTerminator())) |
| 1817 | + return false; |
| 1818 | + |
| 1819 | + // Handle the general case by performing a depth-first traversal on the |
| 1820 | + // inverse control flow graph (CFG), starting from a return block and |
| 1821 | + // continuing until the block containing the store is reached. |
| 1822 | + for (const BasicBlock *R : PDT.roots()) { |
| 1823 | + if (isa<UnreachableInst>(R->getTerminator())) |
| 1824 | + continue; |
| 1825 | + |
| 1826 | + for (auto I = idf_begin(R), E = idf_end(R); I != E; ++I) |
| 1827 | + if (*I == BB) |
| 1828 | + return true; |
| 1829 | + } |
| 1830 | + return false; |
| 1831 | + } |
| 1832 | + |
1804 | 1833 | /// Eliminate writes to objects that are not visible in the caller and are not |
1805 | 1834 | /// accessed before returning from the function. |
1806 | 1835 | bool eliminateDeadWritesAtEndOfFunction() { |
@@ -1828,8 +1857,23 @@ struct DSEState { |
1828 | 1857 | // underlying objects is very uncommon. If it turns out to be important, |
1829 | 1858 | // we can use getUnderlyingObjects here instead. |
1830 | 1859 | const Value *UO = getUnderlyingObject(DefLoc->Ptr); |
1831 | | - if (!isInvisibleToCallerAfterRet(UO)) |
1832 | | - continue; |
| 1860 | + if (!isInvisibleToCallerAfterRet(UO)) { |
| 1861 | + // EVM local begin |
| 1862 | + // For EVM verify that all paths originating from the basic block |
| 1863 | + // containing the store eventually lead to blocks that terminate with |
| 1864 | + // an 'unreachable' instruction. If, in addition, the store is not |
| 1865 | + // read before the function returns (as determined by |
| 1866 | + // isWriteAtEndOfFunction), then the store can be safely eliminated. |
| 1867 | + // TODO: Evaluate this transformation across all targets |
| 1868 | + // (i.e., without limiting it to EVM) to assess whether it could be |
| 1869 | + // upstreamed. At first glance, this appears to be EVM-specific, |
| 1870 | + // since in the general case it is not guaranteed that memory side |
| 1871 | + // effects preceding an unreachable can be safely ignored. |
| 1872 | + Triple TT(DefI->getFunction()->getParent()->getTargetTriple()); |
| 1873 | + if (!TT.isEVM() || isOnPathToFunctionReturn(Def)) |
| 1874 | + continue; |
| 1875 | + // EVM local end |
| 1876 | + } |
1833 | 1877 |
|
1834 | 1878 | if (isWriteAtEndOfFunction(Def, *DefLoc)) { |
1835 | 1879 | // See through pointer-to-pointer bitcasts |
|
0 commit comments