|
20 | 20 | #include "llvm/IR/IntrinsicInst.h"
|
21 | 21 | #include "llvm/IR/Intrinsics.h"
|
22 | 22 | #include "llvm/IR/IntrinsicsEVM.h"
|
| 23 | +#include "llvm/IR/PatternMatch.h" |
23 | 24 | #include "llvm/Pass.h"
|
24 | 25 |
|
25 | 26 | #include "EVM.h"
|
26 | 27 |
|
27 | 28 | using namespace llvm;
|
| 29 | +using namespace llvm::PatternMatch; |
28 | 30 |
|
29 | 31 | #define DEBUG_TYPE "evm-codegen-prepare"
|
30 | 32 |
|
@@ -102,14 +104,60 @@ void EVMCodegenPrepare::processMemTransfer(MemTransferInst *M) {
|
102 | 104 | M->setCalledFunction(Intrinsic::getDeclaration(M->getModule(), IntrID));
|
103 | 105 | }
|
104 | 106 |
|
| 107 | +static bool optimizeICmp(ICmpInst *I) { |
| 108 | + auto *Ty = I->getOperand(0)->getType(); |
| 109 | + if (!Ty->isIntegerTy(256)) |
| 110 | + return false; |
| 111 | + |
| 112 | + if (I->getPredicate() == CmpInst::ICMP_ULT) { |
| 113 | + Value *X = nullptr; |
| 114 | + const APInt *CAdd = nullptr, *CCmp = nullptr; |
| 115 | + |
| 116 | + // icmp ult (add x, CAdd), CCmp -> icmp eq (evm.signextend(b, x)), x |
| 117 | + // where CCmp is a power of 2 and CAdd is twice smaller than CCmp. |
| 118 | + if (match(I->getOperand(0), m_OneUse(m_c_Add(m_Value(X), m_APInt(CAdd)))) && |
| 119 | + match(I->getOperand(1), m_APInt(CCmp)) && CCmp->isPowerOf2() && |
| 120 | + *CAdd == CCmp->lshr(1)) { |
| 121 | + unsigned CCmpLog2 = CCmp->logBase2(); |
| 122 | + |
| 123 | + // If CCmpLog2 is not divisible by 8, cannot use signextend. |
| 124 | + if (CCmpLog2 % 8 != 0) |
| 125 | + return false; |
| 126 | + |
| 127 | + IRBuilder<> Builder(I); |
| 128 | + unsigned ByteIdx = (CCmpLog2 / 8) - 1; |
| 129 | + |
| 130 | + // ByteIdx should be in [0, 31]. |
| 131 | + if (ByteIdx > 31) |
| 132 | + return false; |
| 133 | + |
| 134 | + auto *B = ConstantInt::get(Ty, ByteIdx); |
| 135 | + auto *SignExtend = |
| 136 | + Builder.CreateIntrinsic(Ty, Intrinsic::evm_signextend, {B, X}); |
| 137 | + auto *NewCmp = Builder.CreateICmp(CmpInst::ICMP_EQ, SignExtend, X); |
| 138 | + NewCmp->takeName(I); |
| 139 | + I->replaceAllUsesWith(NewCmp); |
| 140 | + |
| 141 | + // Remove add after icmp. If to do otherwise, assert will be triggered. |
| 142 | + auto *ToRemove = cast<Instruction>(I->getOperand(0)); |
| 143 | + I->eraseFromParent(); |
| 144 | + ToRemove->eraseFromParent(); |
| 145 | + return true; |
| 146 | + } |
| 147 | + } |
| 148 | + return false; |
| 149 | +} |
| 150 | + |
105 | 151 | bool EVMCodegenPrepare::runOnFunction(Function &F) {
|
106 | 152 | bool Changed = false;
|
107 | 153 | for (auto &BB : F) {
|
108 |
| - for (auto &I : BB) { |
| 154 | + for (auto &I : make_early_inc_range(BB)) { |
109 | 155 | if (auto *M = dyn_cast<MemTransferInst>(&I)) {
|
110 | 156 | processMemTransfer(M);
|
111 | 157 | Changed = true;
|
112 | 158 | }
|
| 159 | + if (I.getOpcode() == Instruction::ICmp) |
| 160 | + Changed |= optimizeICmp(cast<ICmpInst>(&I)); |
113 | 161 | }
|
114 | 162 | }
|
115 | 163 |
|
|
0 commit comments