Skip to content

Commit 98c272f

Browse files
[EVM] Transform icmp ult (add x, CAdd), CCmp -> icmp eq (evm.signextend(b, x)), x
Signed-off-by: Vladimir Radosavljevic <[email protected]>
1 parent 19eef91 commit 98c272f

File tree

1 file changed

+49
-1
lines changed

1 file changed

+49
-1
lines changed

llvm/lib/Target/EVM/EVMCodegenPrepare.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
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

2728
using namespace llvm;
29+
using namespace llvm::PatternMatch;
2830

2931
#define DEBUG_TYPE "evm-codegen-prepare"
3032

@@ -102,14 +104,60 @@ 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+
105151
bool EVMCodegenPrepare::runOnFunction(Function &F) {
106152
bool Changed = false;
107153
for (auto &BB : F) {
108-
for (auto &I : BB) {
154+
for (auto &I : make_early_inc_range(BB)) {
109155
if (auto *M = dyn_cast<MemTransferInst>(&I)) {
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

Comments
 (0)