|  | 
| 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" | 
|  | 25 | +#include "llvm/Transforms/InstCombine/InstCombiner.h" | 
| 24 | 26 | 
 | 
| 25 | 27 | #include "EVM.h" | 
| 26 | 28 | 
 | 
| 27 | 29 | using namespace llvm; | 
|  | 30 | +using namespace llvm::PatternMatch; | 
| 28 | 31 | 
 | 
| 29 | 32 | #define DEBUG_TYPE "evm-codegen-prepare" | 
| 30 | 33 | 
 | 
| @@ -102,14 +105,47 @@ void EVMCodegenPrepare::processMemTransfer(MemTransferInst *M) { | 
| 102 | 105 |   M->setCalledFunction(Intrinsic::getDeclaration(M->getModule(), IntrID)); | 
| 103 | 106 | } | 
| 104 | 107 | 
 | 
|  | 108 | +static bool optimizeAShrInst(Instruction *I) { | 
|  | 109 | +  auto *Ty = I->getType(); | 
|  | 110 | +  unsigned BitWidth = Ty->getIntegerBitWidth(); | 
|  | 111 | +  if (BitWidth != 256) | 
|  | 112 | +    return false; | 
|  | 113 | + | 
|  | 114 | +  // Fold ashr(shl(x, c), c) -> signextend(((256 - c) / 8) - 1, x) | 
|  | 115 | +  // where c is a constant and divisible by 8. | 
|  | 116 | +  Value *X = nullptr; | 
|  | 117 | +  ConstantInt *ShiftAmt = nullptr; | 
|  | 118 | +  if (match(I->getOperand(0), | 
|  | 119 | +            m_OneUse(m_Shl(m_Value(X), m_ConstantInt(ShiftAmt)))) && | 
|  | 120 | +      match(I->getOperand(1), m_Specific(ShiftAmt)) && | 
|  | 121 | +      ShiftAmt->getZExtValue() % 8 == 0) { | 
|  | 122 | +    IRBuilder<> Builder(I); | 
|  | 123 | +    unsigned ByteIdx = ((BitWidth - ShiftAmt->getZExtValue()) / 8) - 1; | 
|  | 124 | +    auto *B = ConstantInt::get(Ty, ByteIdx); | 
|  | 125 | +    auto *SignExtend = | 
|  | 126 | +        Builder.CreateIntrinsic(Ty, Intrinsic::evm_signextend, {B, X}); | 
|  | 127 | +    SignExtend->takeName(I); | 
|  | 128 | +    I->replaceAllUsesWith(SignExtend); | 
|  | 129 | + | 
|  | 130 | +    // Remove shl after ashr. If to do otherwise, assert will be triggered. | 
|  | 131 | +    auto *ToRemove = cast<Instruction>(I->getOperand(0)); | 
|  | 132 | +    I->eraseFromParent(); | 
|  | 133 | +    ToRemove->eraseFromParent(); | 
|  | 134 | +    return true; | 
|  | 135 | +  } | 
|  | 136 | +  return false; | 
|  | 137 | +} | 
|  | 138 | + | 
| 105 | 139 | bool EVMCodegenPrepare::runOnFunction(Function &F) { | 
| 106 | 140 |   bool Changed = false; | 
| 107 | 141 |   for (auto &BB : F) { | 
| 108 |  | -    for (auto &I : BB) { | 
|  | 142 | +    for (auto &I : make_early_inc_range(BB)) { | 
| 109 | 143 |       if (auto *M = dyn_cast<MemTransferInst>(&I)) { | 
| 110 | 144 |         processMemTransfer(M); | 
| 111 | 145 |         Changed = true; | 
| 112 | 146 |       } | 
|  | 147 | +      if (I.getOpcode() == Instruction::AShr) | 
|  | 148 | +        Changed |= optimizeAShrInst(&I); | 
| 113 | 149 |     } | 
| 114 | 150 |   } | 
| 115 | 151 | 
 | 
|  | 
0 commit comments