Skip to content

Commit ce7d1cf

Browse files
committed
evmmax: Implement EVMMAX instruction support in yul
1 parent 9ff6d26 commit ce7d1cf

File tree

15 files changed

+514
-5
lines changed

15 files changed

+514
-5
lines changed

libevmasm/Assembly.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,10 @@ LinkerObject const& Assembly::assembleEOF() const
15581558
item.instruction() != Instruction::RJUMPI &&
15591559
item.instruction() != Instruction::CALLF &&
15601560
item.instruction() != Instruction::JUMPF &&
1561-
item.instruction() != Instruction::RETF
1561+
item.instruction() != Instruction::RETF &&
1562+
item.instruction() != Instruction::ADDMODX &&
1563+
item.instruction() != Instruction::SUBMODX &&
1564+
item.instruction() != Instruction::MULMODX
15621565
);
15631566
solAssert(!(item.instruction() >= Instruction::PUSH0 && item.instruction() <= Instruction::PUSH32));
15641567
ret.bytecode += assembleOperation(item);
@@ -1636,6 +1639,12 @@ LinkerObject const& Assembly::assembleEOF() const
16361639
case RetF:
16371640
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::RETF));
16381641
break;
1642+
case EVMMAXArithmeticInstruction:
1643+
{
1644+
ret.bytecode.push_back(static_cast<uint8_t>(item.instruction()));
1645+
appendBigEndian(ret.bytecode, 7, item.data());
1646+
break;
1647+
}
16391648
default:
16401649
solAssert(false, "Unexpected opcode while assembling.");
16411650
}

libevmasm/Assembly.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,70 @@ class Assembly
145145
/// Appends @a _data literally to the very end of the bytecode.
146146
void appendToAuxiliaryData(bytes const& _data) { m_auxiliaryData += _data; }
147147

148+
AssemblyItem appendSetModX() { return append(Instruction::SETMODX); }
149+
AssemblyItem appendLoadX() { return append(Instruction::LOADX); }
150+
AssemblyItem appendStoreX() { return append(Instruction::SETMODX); }
151+
AssemblyItem appendAddModX(
152+
uint8_t _dstValueIndex,
153+
uint8_t _dstStride,
154+
uint8_t _xValueIndex,
155+
uint8_t _xStride,
156+
uint8_t _yValueIndex,
157+
uint8_t _yStride,
158+
uint8_t _count
159+
)
160+
{
161+
return append(AssemblyItem::modularOperation(
162+
Instruction::ADDMODX,
163+
_dstValueIndex,
164+
_dstStride,
165+
_xValueIndex,
166+
_xStride,
167+
_yValueIndex,
168+
_yStride,
169+
_count));
170+
}
171+
AssemblyItem appendSubModX(
172+
uint8_t _dstValueIndex,
173+
uint8_t _dstStride,
174+
uint8_t _xValueIndex,
175+
uint8_t _xStride,
176+
uint8_t _yValueIndex,
177+
uint8_t _yStride,
178+
uint8_t _count
179+
)
180+
{
181+
return append(AssemblyItem::modularOperation(
182+
Instruction::SUBMODX,
183+
_dstValueIndex,
184+
_dstStride,
185+
_xValueIndex,
186+
_xStride,
187+
_yValueIndex,
188+
_yStride,
189+
_count));
190+
}
191+
AssemblyItem appendMulModX(
192+
uint8_t _dstValueIndex,
193+
uint8_t _dstStride,
194+
uint8_t _xValueIndex,
195+
uint8_t _xStride,
196+
uint8_t _yValueIndex,
197+
uint8_t _yStride,
198+
uint8_t _count
199+
)
200+
{
201+
return append(AssemblyItem::modularOperation(
202+
Instruction::MULMODX,
203+
_dstValueIndex,
204+
_dstStride,
205+
_xValueIndex,
206+
_xStride,
207+
_yValueIndex,
208+
_yStride,
209+
_count));
210+
}
211+
148212
int deposit() const { return m_deposit; }
149213
void adjustDeposit(int _adjustment) { m_deposit += _adjustment; solAssert(m_deposit >= 0); }
150214
void setDeposit(int _deposit) { m_deposit = _deposit; solAssert(m_deposit >= 0); }

libevmasm/AssemblyItem.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ std::pair<std::string, std::string> AssemblyItem::nameAndData(langutil::EVMVersi
119119
return {"VERBATIM", util::toHex(verbatimData())};
120120
case AuxDataLoadN:
121121
return {"AUXDATALOADN", util::toString(data())};
122+
case EVMMAXArithmeticInstruction:
123+
return {instructionInfo(instruction(), _evmVersion).name, toStringInHex(data())};
122124
case UndefinedItem:
123125
solAssert(false);
124126
}
@@ -192,6 +194,8 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength, langutil::EVMVersion _
192194
return 2;
193195
case ReturnContract:
194196
return 2;
197+
case EVMMAXArithmeticInstruction:
198+
return 1 + 7;
195199
case UndefinedItem:
196200
solAssert(false);
197201
}
@@ -242,6 +246,7 @@ size_t AssemblyItem::returnValues() const
242246
case PushDeployTimeAddress:
243247
return 1;
244248
case Tag:
249+
case EVMMAXArithmeticInstruction:
245250
return 0;
246251
case VerbatimBytecode:
247252
return std::get<1>(*m_verbatimBytecode);
@@ -284,6 +289,7 @@ bool AssemblyItem::canBeFunctional() const
284289
case AuxDataLoadN:
285290
return true;
286291
case Tag:
292+
case EVMMAXArithmeticInstruction:
287293
return false;
288294
case AssignImmutable:
289295
case VerbatimBytecode:
@@ -410,6 +416,10 @@ std::string AssemblyItem::toAssemblyText(Assembly const& _assembly) const
410416
case RetF:
411417
text = "retf";
412418
break;
419+
case EVMMAXArithmeticInstruction:
420+
text = util::toLower(instructionInfo(instruction(), _assembly.evmVersion()).name) +
421+
"{" + util::toHex(toCompactBigEndian(data(), 1)) + "}";
422+
break;
413423
}
414424
if (m_jumpType == JumpType::IntoFunction || m_jumpType == JumpType::OutOfFunction)
415425
{
@@ -487,6 +497,10 @@ std::ostream& solidity::evmasm::operator<<(std::ostream& _out, AssemblyItem cons
487497
case AuxDataLoadN:
488498
_out << " AuxDataLoadN " << util::toString(_item.data());
489499
break;
500+
case EVMMAXArithmeticInstruction:
501+
_out << " " << instructionInfo(_item.instruction(), EVMVersion()).name <<
502+
" " << util::toHex(toCompactBigEndian(_item.data(), 1));
503+
break;
490504
case UndefinedItem:
491505
_out << " ???";
492506
break;

libevmasm/AssemblyItem.h

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ enum AssemblyItemType
6262
CallF, ///< Jumps to a returning EOF function, adding a new frame to the return stack.
6363
JumpF, ///< Jumps to a returning or non-returning EOF function without changing the return stack.
6464
RetF, ///< Returns from an EOF function, removing a frame from the return stack.
65-
VerbatimBytecode ///< Contains data that is inserted into the bytecode code section without modification.
65+
VerbatimBytecode, ///< Contains data that is inserted into the bytecode code section without modification.
66+
EVMMAXArithmeticInstruction ///< One of three possible modular arithmetic instructions of EVMMAX
6667
};
6768

6869
enum class Precision { Precise , Approximate };
@@ -148,6 +149,35 @@ class AssemblyItem
148149
return AssemblyItem(ConditionalRelativeJump, Instruction::RJUMPI, _tag.data(), _debugData);
149150
}
150151

152+
static AssemblyItem modularOperation(
153+
Instruction _instruction,
154+
uint8_t _dstValueIndex,
155+
uint8_t _dstStride,
156+
uint8_t _xValueIndex,
157+
uint8_t _xStride,
158+
uint8_t _yValueIndex,
159+
uint8_t _yStride,
160+
uint8_t _count,
161+
langutil::DebugData::ConstPtr _debugData = langutil::DebugData::create())
162+
{
163+
solAssert(
164+
_instruction == Instruction::ADDMODX ||
165+
_instruction == Instruction::SUBMODX ||
166+
_instruction == Instruction::MULMODX
167+
);
168+
169+
u256 data =
170+
u256(_dstValueIndex) << 8 * 6 |
171+
u256(_dstStride) << 8 * 5 |
172+
u256(_xValueIndex) << 8 * 4 |
173+
u256(_xStride) << 8 * 3 |
174+
u256(_yValueIndex) << 8 * 2 |
175+
u256(_yStride) << 8 * 1 |
176+
u256(_count);
177+
178+
return AssemblyItem(EVMMAXArithmeticInstruction, _instruction, data, std::move(_debugData));
179+
}
180+
151181
AssemblyItem(AssemblyItem const&) = default;
152182
AssemblyItem(AssemblyItem&&) = default;
153183
AssemblyItem& operator=(AssemblyItem const&) = default;
@@ -191,7 +221,8 @@ class AssemblyItem
191221
m_type == ConditionalRelativeJump ||
192222
m_type == CallF ||
193223
m_type == JumpF ||
194-
m_type == RetF;
224+
m_type == RetF ||
225+
m_type == EVMMAXArithmeticInstruction;
195226
}
196227
/// @returns the instruction of this item (only valid if hasInstruction returns true)
197228
Instruction instruction() const

libevmasm/Instruction.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,13 @@ std::map<std::string, Instruction> const solidity::evmasm::c_instructions =
188188
{ "CREATE2", Instruction::CREATE2 },
189189
{ "REVERT", Instruction::REVERT },
190190
{ "INVALID", Instruction::INVALID },
191-
{ "SELFDESTRUCT", Instruction::SELFDESTRUCT }
191+
{ "SELFDESTRUCT", Instruction::SELFDESTRUCT },
192+
{ "SETMODX", Instruction::SETMODX },
193+
{ "LOADX", Instruction::LOADX },
194+
{ "STOREX", Instruction::STOREX },
195+
{ "ADDMODX", Instruction::ADDMODX },
196+
{ "SUBMODX", Instruction::SUBMODX },
197+
{ "MULMODX", Instruction::MULMODX },
192198
};
193199

194200
/// @note InstructionInfo is assumed to be the same across all EVM versions except for the instruction name.
@@ -353,7 +359,13 @@ static std::map<Instruction, InstructionInfo> const c_instructionInfo =
353359
{Instruction::CREATE2, {"CREATE2", 0, 4, 1, true, Tier::Special}},
354360
{Instruction::REVERT, {"REVERT", 0, 2, 0, true, Tier::Zero}},
355361
{Instruction::INVALID, {"INVALID", 0, 0, 0, true, Tier::Zero}},
356-
{Instruction::SELFDESTRUCT, {"SELFDESTRUCT", 0, 1, 0, true, Tier::Special}}
362+
{Instruction::SELFDESTRUCT, {"SELFDESTRUCT", 0, 1, 0, true, Tier::Special}},
363+
{Instruction::SETMODX, {"SETMODX", 0, 3, 0, true, Tier::Special}},
364+
{Instruction::LOADX, {"LOADX", 0, 3, 0, true, Tier::Special}},
365+
{Instruction::STOREX, {"STOREX", 0, 3, 0, true, Tier::Special}},
366+
{Instruction::ADDMODX, {"ADDMODX", 7, 0, 0, true, Tier::Special}},
367+
{Instruction::SUBMODX, {"SUBMODX", 7, 0, 0, true, Tier::Special}},
368+
{Instruction::MULMODX, {"MULMODX", 7, 0, 0, true, Tier::Special}}
357369
};
358370

359371
InstructionInfo solidity::evmasm::instructionInfo(Instruction _inst, langutil::EVMVersion _evmVersion)

libevmasm/Instruction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,13 @@ enum class Instruction: uint8_t
183183
LOG3, ///< Makes a log entry; 3 topics.
184184
LOG4, ///< Makes a log entry; 4 topics.
185185

186+
SETMODX = 0xc0, ///< Setup modulus context of EVMMAX
187+
LOADX = 0xc1, ///< Load values from EVMMAX context to EVM memory
188+
STOREX = 0xc2, ///< Store values in EVMMAX context from EVM memory
189+
ADDMODX = 0xc3, ///< Compute modular addition in EVMMAX
190+
SUBMODX = 0xc4, ///< Compute modular subtraction in EVMMAX
191+
MULMODX = 0xc5, ///< Compute modular multiplication in EVMMAX
192+
186193
DATALOADN = 0xd1, ///< load data from EOF data section
187194

188195
RJUMP = 0xe0, ///< relative jump

liblangutil/EVMVersion.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ bool EVMVersion::hasOpcode(Instruction _opcode, std::optional<uint8_t> _eofVersi
8888
case Instruction::EXTCALL:
8989
case Instruction::EXTSTATICCALL:
9090
case Instruction::EXTDELEGATECALL:
91+
case Instruction::SETMODX:
92+
case Instruction::LOADX:
93+
case Instruction::STOREX:
9194
return _eofVersion.has_value();
9295
default:
9396
return true;

libyul/backends/evm/AbstractAssembly.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,44 @@ class AbstractAssembly
149149
/// EOF auxiliary data in data section and the auxiliary data are different things.
150150
virtual void appendToAuxiliaryData(bytes const& _data) = 0;
151151

152+
/// EVMMAX specific assembly items appending
153+
/// Appends EVMMAX modulus context initializing instruction
154+
virtual void appendSetModX() = 0;
155+
/// Appends EVMMAX values loading instruction
156+
virtual void appendLoadX() = 0;
157+
/// Appends EVMMAX values storing instruction
158+
virtual void appendStoreX() = 0;
159+
/// Appends EVMMAX modular arithmetic instructions accordingly to their names.
160+
/// The instructions take x, y values indexes lists defined as start index, stride and count.
161+
/// Perform modular arithmetic computations and return values to destination values list.
162+
virtual void appendAddModX(
163+
uint8_t _dstValueIndex,
164+
uint8_t _dstStride,
165+
uint8_t _xValueIndex,
166+
uint8_t _xStride,
167+
uint8_t _yValueIndex,
168+
uint8_t _yStride,
169+
uint8_t _count
170+
) = 0;
171+
virtual void appendSubModX(
172+
uint8_t _dstValueIndex,
173+
uint8_t _dstStride,
174+
uint8_t _xValueIndex,
175+
uint8_t _xStride,
176+
uint8_t _yValueIndex,
177+
uint8_t _yStride,
178+
uint8_t _count
179+
) = 0;
180+
virtual void appendMulModX(
181+
uint8_t _dstValueIndex,
182+
uint8_t _dstStride,
183+
uint8_t _xValueIndex,
184+
uint8_t _xStride,
185+
uint8_t _yValueIndex,
186+
uint8_t _yStride,
187+
uint8_t _count
188+
) = 0;
189+
152190
/// Mark this assembly as invalid. Any attempt to request bytecode from it should throw.
153191
virtual void markAsInvalid() = 0;
154192

0 commit comments

Comments
 (0)