Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/action/evm_bytecode_visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1618,14 +1618,23 @@ template <typename IRBuilder> class EVMByteCodeVisitor {
RequiredSize <= Plan.MaxRequiredSize;
}

void maybePrepareLinearBlockMemoryPrecheck(evmc_opcode Opcode,
Operand Stride) {
if (!CurBlockLinearPrecheckPlan.Eligible ||
CurBlockLinearPrecheckPlan.CoveredOpcode != Opcode) {
return;
}
Builder.prepareLinearBlockMemoryPrecheck(Stride);
}

void maybePrepareLinearBlockMemoryPrecheck(evmc_opcode Opcode) {
if (!CurBlockLinearPrecheckPlan.Eligible ||
CurBlockLinearPrecheckPlan.CoveredOpcode != Opcode ||
Stack.getSize() <= CurBlockLinearPrecheckPlan.StrideStackIndex) {
return;
}
Builder.prepareLinearBlockMemoryPrecheck(
Stack.peek(CurBlockLinearPrecheckPlan.StrideStackIndex));
maybePrepareLinearBlockMemoryPrecheck(
Opcode, Stack.peek(CurBlockLinearPrecheckPlan.StrideStackIndex));
}

LargeStaticWorkspaceVerifierResult
Expand Down Expand Up @@ -3085,7 +3094,7 @@ template <typename IRBuilder> class EVMByteCodeVisitor {
Operand Current = Stack.peek(0);
Operand Stride = Stack.peek(1);
Builder.noteMemoryOpcodeInBlock(OP_MSTORE, MStorePC);
maybePrepareLinearBlockMemoryPrecheck(OP_MSTORE);
maybePrepareLinearBlockMemoryPrecheck(OP_MSTORE, Stride);
Builder.handleMStore(Current, Current);
Operand Next =
Builder.template handleBinaryArithmetic<BinaryOperator::BO_ADD>(Current,
Expand Down
56 changes: 54 additions & 2 deletions src/tests/evm_jit_frontend_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1554,7 +1554,7 @@ class MockEVMBuilder {
MOCK_OPERAND_STUB(handleBlobHash);
MOCK_OPERAND_STUB(handleBlockHash);
MOCK_OPERAND_STUB(handleByte);
MOCK_OPERAND_STUB(handleCallDataLoad);
Operand handleCallDataLoad(Operand) { return Operand(CallDataLoadResult); }
MOCK_OPERAND_STUB(handleCallDataSize);
MOCK_OPERAND_STUB(handleCallValue);
MOCK_OPERAND_STUB(handleCaller);
Expand Down Expand Up @@ -1690,8 +1690,9 @@ class MockEVMBuilder {
LargeStaticWorkspaceRejectHelperByteExactRisk += RejectHelperByteExactRisk;
LargeStaticWorkspaceRejectTooFewOps += RejectTooFewOps;
}
void prepareLinearBlockMemoryPrecheck(Operand) {
void prepareLinearBlockMemoryPrecheck(Operand Stride) {
LinearPrecheckPrepareCount++;
LastLinearPrecheckStride = Stride.resolvedValue()[0];
}
void noteMemoryOpcodeInBlock(evmc_opcode, uint64_t) {}
void noteHelperOpcodeInBlock(evmc_opcode, uint64_t) {}
Expand Down Expand Up @@ -1796,6 +1797,10 @@ class MockEVMBuilder {
return LinearPrecheckPrepareCount;
}

void setCallDataLoadResult(uint64_t Value) { CallDataLoadResult = Value; }

uint64_t lastLinearPrecheckStride() const { return LastLinearPrecheckStride; }

bool Trapped = false;
bool Undefined = false;
uint64_t LargeStaticWorkspaceCandidates = 0;
Expand Down Expand Up @@ -1850,6 +1855,8 @@ class MockEVMBuilder {
uint64_t LastLinearPrecheckCoveredDirectOps = 0;
bool LastLinearPrecheckValueEqualsFirstAddr = false;
uint32_t LinearPrecheckPrepareCount = 0;
uint64_t LastLinearPrecheckStride = 0;
uint64_t CallDataLoadResult = 0;

#undef MOCK_OPERAND_STUB
#undef MOCK_VOID_STUB
Expand Down Expand Up @@ -3053,6 +3060,49 @@ TEST(EVMJITFrontendVisitorTest, FusesLinearMStoreNextMotifIntoMeteredRange) {
EXPECT_EQ(Builder.topStackValue()[0], 0x60U);
}

TEST(EVMJITFrontendVisitorTest,
PlansFusedLinearMStoreMemoryPrecheckWithDynamicStride) {
const std::vector<uint8_t> Bytecode = {
0x5f, // PUSH0 calldata offset for stride
0x35, // CALLDATALOAD
0x5f, // PUSH0 current
0x80, // DUP1
0x80, // DUP1
0x52, // MSTORE
0x81, // DUP2
0x01, // ADD
0x80, // DUP1
0x80, // DUP1
0x52, // MSTORE
0x81, // DUP2
0x01, // ADD
0x00 // STOP
};

COMPILER::EVMFrontendContext Ctx;
Ctx.setRevision(EVMC_CANCUN);
Ctx.setBytecode(reinterpret_cast<const zen::common::Byte *>(Bytecode.data()),
Bytecode.size());

MockEVMBuilder Builder;
Builder.setCallDataLoadResult(7);
COMPILER::EVMByteCodeVisitor<MockEVMBuilder> Visitor(Builder, &Ctx);
EXPECT_TRUE(Visitor.compile());
EXPECT_FALSE(Builder.Trapped);
EXPECT_FALSE(Builder.Undefined);

EXPECT_EQ(Builder.linearPrecheckPlanCount(), 1U);
EXPECT_EQ(Builder.lastLinearPrecheckAccessWidth(), 32U);
EXPECT_EQ(Builder.lastLinearPrecheckCoveredDirectOps(), 2U);
EXPECT_TRUE(Builder.lastLinearPrecheckValueEqualsFirstAddr());
EXPECT_EQ(Builder.linearPrecheckPrepareCount(), 2U);
EXPECT_EQ(Builder.lastLinearPrecheckStride(), 7U);
EXPECT_EQ(Builder.meteredOpcodeCount(OP_MSTORE), 2U);
EXPECT_EQ(Builder.mstoreCount(), 2U);
EXPECT_EQ(Builder.runtimeStackDepth(), 2U);
EXPECT_EQ(Builder.topStackValue()[0], 14U);
}

TEST(EVMJITFrontendVisitorTest, PlansLinearMStore8NextMotifMemoryPrecheck) {
const std::vector<uint8_t> Bytecode = {
0x5f, // PUSH0 calldata offset for stride
Expand All @@ -3077,6 +3127,7 @@ TEST(EVMJITFrontendVisitorTest, PlansLinearMStore8NextMotifMemoryPrecheck) {
Bytecode.size());

MockEVMBuilder Builder;
Builder.setCallDataLoadResult(11);
COMPILER::EVMByteCodeVisitor<MockEVMBuilder> Visitor(Builder, &Ctx);
EXPECT_TRUE(Visitor.compile());
EXPECT_FALSE(Builder.Trapped);
Expand All @@ -3087,6 +3138,7 @@ TEST(EVMJITFrontendVisitorTest, PlansLinearMStore8NextMotifMemoryPrecheck) {
EXPECT_EQ(Builder.lastLinearPrecheckCoveredDirectOps(), 2U);
EXPECT_FALSE(Builder.lastLinearPrecheckValueEqualsFirstAddr());
EXPECT_EQ(Builder.linearPrecheckPrepareCount(), 2U);
EXPECT_EQ(Builder.lastLinearPrecheckStride(), 11U);
EXPECT_EQ(Builder.meteredOpcodeCount(OP_MSTORE8), 2U);
EXPECT_EQ(Builder.runtimeStackDepth(), 2U);
}
Expand Down
Loading