mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Implement Yul IR generation for abi.encode*
This commit is contained in:
parent
d0b82fe854
commit
a0e291bd06
@ -781,6 +781,94 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case FunctionType::Kind::ABIEncode:
|
||||||
|
case FunctionType::Kind::ABIEncodePacked:
|
||||||
|
case FunctionType::Kind::ABIEncodeWithSelector:
|
||||||
|
case FunctionType::Kind::ABIEncodeWithSignature:
|
||||||
|
{
|
||||||
|
bool const isPacked = functionType->kind() == FunctionType::Kind::ABIEncodePacked;
|
||||||
|
solAssert(functionType->padArguments() != isPacked, "");
|
||||||
|
bool const hasSelectorOrSignature =
|
||||||
|
functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector ||
|
||||||
|
functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature;
|
||||||
|
|
||||||
|
TypePointers argumentTypes;
|
||||||
|
TypePointers targetTypes;
|
||||||
|
vector<string> argumentVars;
|
||||||
|
for (size_t i = 0; i < arguments.size(); ++i)
|
||||||
|
{
|
||||||
|
// ignore selector
|
||||||
|
if (hasSelectorOrSignature && i == 0)
|
||||||
|
continue;
|
||||||
|
argumentTypes.emplace_back(&type(*arguments[i]));
|
||||||
|
targetTypes.emplace_back(type(*arguments[i]).fullEncodingType(false, true, isPacked));
|
||||||
|
argumentVars += IRVariable(*arguments[i]).stackSlots();
|
||||||
|
}
|
||||||
|
|
||||||
|
string selector;
|
||||||
|
if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature)
|
||||||
|
{
|
||||||
|
// hash the signature
|
||||||
|
Type const& selectorType = type(*arguments.front());
|
||||||
|
if (auto const* stringType = dynamic_cast<StringLiteralType const*>(&selectorType))
|
||||||
|
{
|
||||||
|
FixedHash<4> hash(keccak256(stringType->value()));
|
||||||
|
selector = formatNumber(u256(FixedHash<4>::Arith(hash)) << (256 - 32));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Used to reset the free memory pointer later.
|
||||||
|
string freeMemoryPre = m_context.newYulVariable();
|
||||||
|
m_code << "let " << freeMemoryPre << " := " << freeMemory() << "\n";
|
||||||
|
IRVariable array = convert(*arguments[0], *TypeProvider::bytesMemory());
|
||||||
|
IRVariable hashVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(32));
|
||||||
|
|
||||||
|
define(hashVariable) <<
|
||||||
|
"keccak256(" <<
|
||||||
|
m_utils.arrayDataAreaFunction(*TypeProvider::bytesMemory()) <<
|
||||||
|
"(" <<
|
||||||
|
array.commaSeparatedList() <<
|
||||||
|
"), " <<
|
||||||
|
m_utils.arrayLengthFunction(*TypeProvider::bytesMemory()) <<
|
||||||
|
"(" <<
|
||||||
|
array.commaSeparatedList() <<
|
||||||
|
"))\n";
|
||||||
|
IRVariable selectorVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(4));
|
||||||
|
define(selectorVariable, hashVariable);
|
||||||
|
m_code << "mstore(" << to_string(CompilerUtils::freeMemoryPointer) << ", " << freeMemoryPre << ")\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector)
|
||||||
|
selector = convert(*arguments.front(), *TypeProvider::fixedBytes(4)).name();
|
||||||
|
|
||||||
|
Whiskers templ(R"(
|
||||||
|
let <data> := <allocateTemporary>()
|
||||||
|
let <mpos> := add(<data>, 0x20)
|
||||||
|
<?+selector>
|
||||||
|
mstore(<mpos>, <selector>)
|
||||||
|
<mpos> := add(<mpos>, 4)
|
||||||
|
</+selector>
|
||||||
|
let <mend> := <encode>(<mpos><arguments>)
|
||||||
|
mstore(<data>, sub(<mend>, add(<data>, 0x20)))
|
||||||
|
mstore(<freeMemPtr>, <roundUp>(<mend>))
|
||||||
|
)");
|
||||||
|
templ("data", IRVariable(_functionCall).part("mpos").name());
|
||||||
|
templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction());
|
||||||
|
templ("mpos", m_context.newYulVariable());
|
||||||
|
templ("mend", m_context.newYulVariable());
|
||||||
|
templ("selector", selector);
|
||||||
|
templ("encode",
|
||||||
|
isPacked ?
|
||||||
|
m_context.abiFunctions().tupleEncoderPacked(argumentTypes, targetTypes) :
|
||||||
|
m_context.abiFunctions().tupleEncoder(argumentTypes, targetTypes, false)
|
||||||
|
);
|
||||||
|
templ("arguments", joinHumanReadablePrefixed(argumentVars));
|
||||||
|
templ("freeMemPtr", to_string(CompilerUtils::freeMemoryPointer));
|
||||||
|
templ("roundUp", m_utils.roundUpFunction());
|
||||||
|
|
||||||
|
m_code << templ.render();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case FunctionType::Kind::Revert:
|
case FunctionType::Kind::Revert:
|
||||||
{
|
{
|
||||||
solAssert(arguments.size() == parameterTypes.size(), "");
|
solAssert(arguments.size() == parameterTypes.size(), "");
|
||||||
@ -843,6 +931,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
solAssert(arguments.size() == 1, "");
|
solAssert(arguments.size() == 1, "");
|
||||||
|
|
||||||
ArrayType const* arrayType = TypeProvider::bytesMemory();
|
ArrayType const* arrayType = TypeProvider::bytesMemory();
|
||||||
|
|
||||||
auto array = convert(*arguments[0], *arrayType);
|
auto array = convert(*arguments[0], *arrayType);
|
||||||
|
|
||||||
define(_functionCall) <<
|
define(_functionCall) <<
|
||||||
|
@ -89,7 +89,7 @@ string IRVariable::name() const
|
|||||||
{
|
{
|
||||||
solAssert(m_type.sizeOnStack() == 1, "");
|
solAssert(m_type.sizeOnStack() == 1, "");
|
||||||
auto const& [itemName, type] = m_type.stackItems().front();
|
auto const& [itemName, type] = m_type.stackItems().front();
|
||||||
solAssert(!type, "");
|
solAssert(!type, "Expected null type for name " + itemName);
|
||||||
return suffixedName(itemName);
|
return suffixedName(itemName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,8 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f0() -> 0x20, 0x0
|
// f0() -> 0x20, 0x0
|
||||||
// f1() -> 0x20, 0x40, 0x1, 0x2
|
// f1() -> 0x20, 0x40, 0x1, 0x2
|
||||||
|
@ -5,5 +5,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f() -> 0x20, 0x40, 0x1, -2
|
// f() -> 0x20, 0x40, 0x1, -2
|
||||||
|
@ -9,5 +9,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f() -> 0x40, 0xa0, 0x40, 0x20, 0x0, 0x0
|
// f() -> 0x40, 0xa0, 0x40, 0x20, 0x0, 0x0
|
||||||
|
@ -8,5 +8,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f() -> 0x20, 0x40, 0x1, -2
|
// f() -> 0x20, 0x40, 0x1, -2
|
||||||
|
@ -21,6 +21,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// f(uint256[]): 32, 3, 23, 42, 87 -> 32, 160, 32, 3, 23, 42, 87
|
// f(uint256[]): 32, 3, 23, 42, 87 -> 32, 160, 32, 3, 23, 42, 87
|
||||||
|
@ -21,6 +21,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// f(uint256[]): 32, 3, 42, 23, 87 -> 32, 160, 32, 3, 42, 23, 87
|
// f(uint256[]): 32, 3, 42, 23, 87 -> 32, 160, 32, 3, 42, 23, 87
|
||||||
|
@ -21,6 +21,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// f(uint256[][]): 0x20, 2, 0x40, 0xC0, 3, 13, 17, 23, 4, 27, 31, 37, 41 -> 32, 416, 32, 2, 64, 192, 3, 13, 17, 23, 4, 27, 31, 37, 41
|
// f(uint256[][]): 0x20, 2, 0x40, 0xC0, 3, 13, 17, 23, 4, 27, 31, 37, 41 -> 32, 416, 32, 2, 64, 192, 3, 13, 17, 23, 4, 27, 31, 37, 41
|
||||||
|
@ -15,6 +15,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87
|
// f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87
|
||||||
|
@ -15,6 +15,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87
|
// f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87
|
||||||
|
@ -10,6 +10,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// f((uint256[])[]): 32, 1, 32, 32, 3, 17, 42, 23 -> 32, 256, 32, 1, 32, 32, 3, 17, 42, 23
|
// f((uint256[])[]): 32, 1, 32, 32, 3, 17, 42, 23 -> 32, 256, 32, 1, 32, 32, 3, 17, 42, 23
|
||||||
|
@ -12,6 +12,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// f(uint256[],uint256[],bool): 0x60, 0xE0, true, 3, 23, 42, 87, 2, 51, 72 -> 32, 160, 0x20, 3, 23, 42, 87
|
// f(uint256[],uint256[],bool): 0x60, 0xE0, true, 3, 23, 42, 87, 2, 51, 72 -> 32, 160, 0x20, 3, 23, 42, 87
|
||||||
|
@ -12,6 +12,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// f(uint256[3],uint256[2],bool): 23, 42, 87, 51, 72, true -> 32, 96, 23, 42, 87
|
// f(uint256[3],uint256[2],bool): 23, 42, 87, 51, 72, true -> 32, 96, 23, 42, 87
|
||||||
|
@ -12,6 +12,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// f((uint256[])): 0x20, 0x20, 3, 42, 23, 17 -> 32, 192, 0x20, 0x20, 3, 42, 23, 17
|
// f((uint256[])): 0x20, 0x20, 3, 42, 23, 17 -> 32, 192, 0x20, 0x20, 3, 42, 23, 17
|
||||||
|
@ -12,6 +12,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// f((uint256)): 3 -> 32, 32, 3
|
// f((uint256)): 3 -> 32, 32, 3
|
||||||
|
@ -22,5 +22,7 @@ contract Main {
|
|||||||
return map[a];
|
return map[a];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1
|
// f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1
|
||||||
|
@ -3,5 +3,7 @@ contract c {
|
|||||||
d = keccak256(abi.encodePacked(a, b, c));
|
d = keccak256(abi.encodePacked(a, b, c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// foo(uint256,uint256,uint256): 0xa, 0xc, 0xd -> 0xbc740a98aae5923e8f04c9aa798c9ee82f69e319997699f2782c40828db9fd81
|
// foo(uint256,uint256,uint256): 0xa, 0xc, 0xd -> 0xbc740a98aae5923e8f04c9aa798c9ee82f69e319997699f2782c40828db9fd81
|
||||||
|
@ -3,5 +3,7 @@ contract c {
|
|||||||
d = keccak256(abi.encodePacked(a, b, uint8(145)));
|
d = keccak256(abi.encodePacked(a, b, uint8(145)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// foo(uint256,uint16): 0xa, 0xc -> 0x88acd45f75907e7c560318bc1a5249850a0999c4896717b1167d05d116e6dbad
|
// foo(uint256,uint16): 0xa, 0xc -> 0x88acd45f75907e7c560318bc1a5249850a0999c4896717b1167d05d116e6dbad
|
||||||
|
@ -7,6 +7,8 @@ contract c {
|
|||||||
d = keccak256(abi.encodePacked(a, b, uint8(145), "foo"));
|
d = keccak256(abi.encodePacked(a, b, uint8(145), "foo"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// foo() -> 0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d
|
// foo() -> 0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d
|
||||||
// bar(uint256,uint16): 0xa, 0xc -> 0x6990f36476dc412b1c4baa48e2d9f4aa4bb313f61fda367c8fdbbb2232dc6146
|
// bar(uint256,uint16): 0xa, 0xc -> 0x6990f36476dc412b1c4baa48e2d9f4aa4bb313f61fda367c8fdbbb2232dc6146
|
||||||
|
@ -149,6 +149,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
// EVMVersion: >=byzantium
|
// EVMVersion: >=byzantium
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f1() -> 2
|
// f1() -> 2
|
||||||
// f1a() -> 2
|
// f1a() -> 2
|
||||||
|
Loading…
Reference in New Issue
Block a user