diff --git a/src/compiler/evm_frontend/evm_mir_compiler.cpp b/src/compiler/evm_frontend/evm_mir_compiler.cpp index 40f1e4ffb..a99b55a4d 100644 --- a/src/compiler/evm_frontend/evm_mir_compiler.cpp +++ b/src/compiler/evm_frontend/evm_mir_compiler.cpp @@ -4,11 +4,14 @@ #include "compiler/evm_frontend/evm_mir_compiler.h" #include "action/evm_bytecode_visitor.h" #include "compiler/evm_frontend/evm_imported.h" +#include "compiler/mir/constants.h" #include "compiler/mir/module.h" #include "evm/gas_storage_cost.h" #include "runtime/evm_instance.h" #include "utils/hash_utils.h" +#include "llvm/Support/Casting.h" #include +#include #ifdef ZEN_ENABLE_EVM_GAS_REGISTER #include "compiler/llvm-prebuild/Target/X86/X86Subtarget.h" @@ -1876,6 +1879,18 @@ EVMMirBuilder::handleClz(const Operand &ValueOp) { RuntimeFunctions.GetClz, ValueOp); } +namespace { +// Extract constant shift amount from MInstruction if it is a constant. +std::optional getConstShiftAmount(MInstruction *Inst) { + if (auto *CI = llvm::dyn_cast(Inst)) { + if (auto *IntConst = llvm::dyn_cast(&CI->getConstant())) { + return IntConst->getValue().getZExtValue(); + } + } + return std::nullopt; +} +} // namespace + EVMMirBuilder::U256Inst EVMMirBuilder::handleLeftShift(const U256Inst &Value, MInstruction *ShiftAmount, MInstruction *IsLargeShift) { @@ -1884,6 +1899,41 @@ EVMMirBuilder::handleLeftShift(const U256Inst &Value, MInstruction *ShiftAmount, U256Inst Result = {}; MInstruction *Zero = createIntConstInstruction(MirI64Type, 0); + + // Fast path: constant shift amount — direct limb logic, no Select/cmp loops. + if (auto ShiftOpt = getConstShiftAmount(ShiftAmount)) { + uint64_t Shift = *ShiftOpt; + if (Shift >= 256) { + for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) + Result[I] = Zero; + return Result; + } + uint64_t CompShift = Shift / 64; + uint64_t ShiftMod = Shift % 64; + uint64_t RemainingBits = (ShiftMod == 0) ? 0 : (64 - ShiftMod); + for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) { + MInstruction *R = Zero; + if (I >= CompShift) { + size_t SrcIdx = I - CompShift; + MInstruction *SrcVal = Value[SrcIdx]; + MInstruction *Shifted = createInstruction( + false, OP_shl, MirI64Type, SrcVal, + createIntConstInstruction(MirI64Type, ShiftMod)); + if (SrcIdx > 0 && RemainingBits > 0) { + MInstruction *Carry = createInstruction( + false, OP_ushr, MirI64Type, Value[SrcIdx - 1], + createIntConstInstruction(MirI64Type, RemainingBits)); + R = createInstruction(false, OP_or, MirI64Type, + Shifted, Carry); + } else { + R = Shifted; + } + } + Result[I] = protectUnsafeValue(R, MirI64Type); + } + return Result; + } + MInstruction *One = createIntConstInstruction(MirI64Type, 1); MInstruction *Const64 = createIntConstInstruction(MirI64Type, 64); @@ -2019,6 +2069,41 @@ EVMMirBuilder::handleLogicalRightShift(const U256Inst &Value, U256Inst Result = {}; MInstruction *Zero = createIntConstInstruction(MirI64Type, 0); + + // Fast path: constant shift amount — direct limb logic, no Select/cmp loops. + if (auto ShiftOpt = getConstShiftAmount(ShiftAmount)) { + uint64_t Shift = *ShiftOpt; + if (Shift >= 256) { + for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) + Result[I] = Zero; + return Result; + } + uint64_t CompShift = Shift / 64; + uint64_t ShiftMod = Shift % 64; + uint64_t CarryShift = (ShiftMod == 0) ? 0 : (64 - ShiftMod); + for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) { + MInstruction *R = Zero; + if (I + CompShift < EVM_ELEMENTS_COUNT) { + size_t SrcIdx = I + CompShift; + MInstruction *SrcVal = Value[SrcIdx]; + MInstruction *Shifted = createInstruction( + false, OP_ushr, MirI64Type, SrcVal, + createIntConstInstruction(MirI64Type, ShiftMod)); + if (SrcIdx + 1 < EVM_ELEMENTS_COUNT && CarryShift > 0) { + MInstruction *Carry = createInstruction( + false, OP_shl, MirI64Type, Value[SrcIdx + 1], + createIntConstInstruction(MirI64Type, CarryShift)); + R = createInstruction(false, OP_or, MirI64Type, + Shifted, Carry); + } else { + R = Shifted; + } + } + Result[I] = protectUnsafeValue(R, MirI64Type); + } + return Result; + } + MInstruction *One = createIntConstInstruction(MirI64Type, 1); MInstruction *Const64 = createIntConstInstruction(MirI64Type, 64); @@ -2146,25 +2231,56 @@ EVMMirBuilder::handleArithmeticRightShift(const U256Inst &Value, EVMFrontendContext::getMIRTypeFromEVMType(EVMType::UINT64); U256Inst Result = {}; - // Arithmetic right shift: sign-extend when shift >= 256 MInstruction *Zero = createIntConstInstruction(MirI64Type, 0); MInstruction *AllOnes = createIntConstInstruction(MirI64Type, ~0ULL); - // Check sign bit (bit 63 of highest component) + // Check sign bit (bit 63 of highest component) for large-shift result MInstruction *HighComponent = Value[EVM_ELEMENTS_COUNT - 1]; MInstruction *Const63 = createIntConstInstruction(MirI64Type, 63); MInstruction *SignBit = createInstruction( false, OP_ushr, MirI64Type, HighComponent, Const63); - - // Sign bit is 1 if negative MInstruction *One = createIntConstInstruction(MirI64Type, 1); MInstruction *IsNegative = createInstruction( false, CmpInstruction::Predicate::ICMP_EQ, &Ctx.I64Type, SignBit, One); - - // Large shift result: all 1s if negative, all 0s if positive MInstruction *LargeShiftResult = createInstruction( false, MirI64Type, IsNegative, AllOnes, Zero); + // Fast path: constant shift amount — direct limb logic, no Select/cmp loops. + if (auto ShiftOpt = getConstShiftAmount(ShiftAmount)) { + uint64_t Shift = *ShiftOpt; + if (Shift >= 256) { + for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) + Result[I] = LargeShiftResult; + return Result; + } + uint64_t CompShift = Shift / 64; + uint64_t ShiftMod = Shift % 64; + uint64_t CarryShift = (ShiftMod == 0) ? 0 : (64 - ShiftMod); + for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) { + MInstruction *R = LargeShiftResult; + if (I + CompShift < EVM_ELEMENTS_COUNT) { + size_t SrcIdx = I + CompShift; + MInstruction *SrcVal = Value[SrcIdx]; + // Use arithmetic shift for the high component (contains sign bit) + bool UseArithShift = (SrcIdx == EVM_ELEMENTS_COUNT - 1); + MInstruction *Shifted = createInstruction( + false, UseArithShift ? OP_sshr : OP_ushr, MirI64Type, SrcVal, + createIntConstInstruction(MirI64Type, ShiftMod)); + if (SrcIdx + 1 < EVM_ELEMENTS_COUNT && CarryShift > 0) { + MInstruction *Carry = createInstruction( + false, OP_shl, MirI64Type, Value[SrcIdx + 1], + createIntConstInstruction(MirI64Type, CarryShift)); + R = createInstruction(false, OP_or, MirI64Type, + Shifted, Carry); + } else { + R = Shifted; + } + } + Result[I] = protectUnsafeValue(R, MirI64Type); + } + return Result; + } + // intra-component shifts = shift % 64 // shift_comp = shift / 64 (which component index shift from) MInstruction *Const64 = createIntConstInstruction(MirI64Type, 64);