2020#include " llvm/IR/IntrinsicInst.h"
2121#include " llvm/IR/Intrinsics.h"
2222#include " llvm/IR/IntrinsicsEVM.h"
23+ #include " llvm/IR/PatternMatch.h"
2324#include " llvm/Pass.h"
2425
2526#include " EVM.h"
2627
2728using namespace llvm ;
29+ using namespace llvm ::PatternMatch;
2830
2931#define DEBUG_TYPE " evm-codegen-prepare"
3032
@@ -102,6 +104,50 @@ void EVMCodegenPrepare::processMemTransfer(MemTransferInst *M) {
102104 M->setCalledFunction (Intrinsic::getDeclaration (M->getModule (), IntrID));
103105}
104106
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+
105151bool EVMCodegenPrepare::runOnFunction (Function &F) {
106152 bool Changed = false ;
107153 for (auto &BB : F) {
@@ -110,6 +156,8 @@ bool EVMCodegenPrepare::runOnFunction(Function &F) {
110156 processMemTransfer (M);
111157 Changed = true ;
112158 }
159+ if (I.getOpcode () == Instruction::ICmp)
160+ Changed |= optimizeICmp (cast<ICmpInst>(&I));
113161 }
114162 }
115163
0 commit comments