@@ -136,6 +136,51 @@ static bool optimizeAShrInst(Instruction *I) {
136136  return  false ;
137137}
138138
139+ static  bool  optimizeICmp (ICmpInst *I) {
140+   auto  *Ty = I->getOperand (0 )->getType ();
141+   unsigned  BitWidth = Ty->getIntegerBitWidth ();
142+   if  (BitWidth != 256 )
143+     return  false ;
144+ 
145+   if  (I->getPredicate () == CmpInst::ICMP_ULT) {
146+     Value *X = nullptr ;
147+     const  APInt *CAdd = nullptr , *CCmp = nullptr ;
148+ 
149+     //  icmp ult (add x, CAdd), CCmp -> icmp eq (evm.signextend(b, x)), x
150+     //  where CCmp is a power of 2 and CAdd is twice smaller than CCmp.
151+     if  (match (I->getOperand (0 ), m_OneUse (m_c_Add (m_Value (X), m_APInt (CAdd)))) &&
152+         match (I->getOperand (1 ), m_APInt (CCmp)) && CCmp->isPowerOf2 () &&
153+         *CAdd == CCmp->lshr (1 )) {
154+       unsigned  CCmpLog2 = CCmp->logBase2 ();
155+ 
156+       //  If CCmpLog2 is not divisible by 8, cannot use signextend.
157+       if  (CCmpLog2 % 8  != 0 )
158+         return  false ;
159+ 
160+       IRBuilder<> Builder (I);
161+       unsigned  ByteIdx = (CCmpLog2 / 8 ) - 1 ;
162+ 
163+       //  ByteIdx should be in [0, 31].
164+       if  (ByteIdx > 31 )
165+         return  false ;
166+ 
167+       auto  *B = ConstantInt::get (Ty, ByteIdx);
168+       auto  *SignExtend =
169+           Builder.CreateIntrinsic (Ty, Intrinsic::evm_signextend, {B, X});
170+       auto  *NewCmp = Builder.CreateICmp (CmpInst::ICMP_EQ, SignExtend, X);
171+       NewCmp->takeName (I);
172+       I->replaceAllUsesWith (NewCmp);
173+ 
174+       //  Remove add after icmp. If to do otherwise, assert will be triggered.
175+       auto  *ToRemove = cast<Instruction>(I->getOperand (0 ));
176+       I->eraseFromParent ();
177+       ToRemove->eraseFromParent ();
178+       return  true ;
179+     }
180+   }
181+   return  false ;
182+ }
183+ 
139184bool  EVMCodegenPrepare::runOnFunction (Function &F) {
140185  bool  Changed = false ;
141186  for  (auto  &BB : F) {
@@ -146,6 +191,8 @@ bool EVMCodegenPrepare::runOnFunction(Function &F) {
146191      }
147192      if  (I.getOpcode () == Instruction::AShr)
148193        Changed |= optimizeAShrInst (&I);
194+       else  if  (I.getOpcode () == Instruction::ICmp)
195+         Changed |= optimizeICmp (cast<ICmpInst>(&I));
149196    }
150197  }
151198
0 commit comments