Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5203503

Browse files
committed
Allow for per-parameter literalValues builtin functions
1 parent 582c754 commit 5203503

12 files changed

+75
-52
lines changed

libyul/AsmAnalysis.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,14 +255,14 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
255255
yulAssert(!_funCall.functionName.name.empty(), "");
256256
vector<YulString> const* parameterTypes = nullptr;
257257
vector<YulString> const* returnTypes = nullptr;
258-
bool needsLiteralArguments = false;
258+
vector<bool> const* needsLiteralArguments = nullptr;
259259

260260
if (BuiltinFunction const* f = m_dialect.builtin(_funCall.functionName.name))
261261
{
262262
parameterTypes = &f->parameters;
263263
returnTypes = &f->returns;
264264
if (f->literalArguments)
265-
needsLiteralArguments = true;
265+
needsLiteralArguments = &f->literalArguments.value();
266266
}
267267
else if (!m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
268268
[&](Scope::Variable const&)
@@ -293,11 +293,13 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
293293
);
294294

295295
vector<YulString> argTypes;
296-
for (auto const& arg: _funCall.arguments | boost::adaptors::reversed)
296+
for (size_t i = _funCall.arguments.size(); i > 0; i--)
297297
{
298+
Expression const& arg = _funCall.arguments[i - 1];
299+
298300
argTypes.emplace_back(expectExpression(arg));
299301

300-
if (needsLiteralArguments)
302+
if (needsLiteralArguments && (*needsLiteralArguments)[i - 1])
301303
{
302304
if (!holds_alternative<Literal>(arg))
303305
typeError(

libyul/Dialect.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <vector>
3030
#include <set>
31+
#include <optional>
3132

3233
namespace solidity::yul
3334
{
@@ -46,8 +47,8 @@ struct BuiltinFunction
4647
ControlFlowSideEffects controlFlowSideEffects;
4748
/// If true, this is the msize instruction.
4849
bool isMSize = false;
49-
/// If true, can only accept literals as arguments and they cannot be moved to variables.
50-
bool literalArguments = false;
50+
/// If set, same length as the arguments, if true at index i, the i'th argument has to be a literal which means it can't be moved to variables.
51+
std::optional<std::vector<bool>> literalArguments;
5152
};
5253

5354
struct Dialect: boost::noncopyable

libyul/backends/evm/EVMDialect.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
5555
f.controlFlowSideEffects.terminates = evmasm::SemanticInformation::terminatesControlFlow(_instruction);
5656
f.controlFlowSideEffects.reverts = evmasm::SemanticInformation::reverts(_instruction);
5757
f.isMSize = _instruction == evmasm::Instruction::MSIZE;
58-
f.literalArguments = false;
58+
f.literalArguments.reset();
5959
f.instruction = _instruction;
6060
f.generateCode = [_instruction](
6161
FunctionCall const&,
@@ -75,17 +75,22 @@ pair<YulString, BuiltinFunctionForEVM> createFunction(
7575
size_t _params,
7676
size_t _returns,
7777
SideEffects _sideEffects,
78-
bool _literalArguments,
78+
vector<bool> _literalArguments,
7979
std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&, std::function<void()>)> _generateCode
8080
)
8181
{
82+
solAssert(_literalArguments.size() == _params || _literalArguments.empty(), "");
83+
8284
YulString name{std::move(_name)};
8385
BuiltinFunctionForEVM f;
8486
f.name = name;
8587
f.parameters.resize(_params);
8688
f.returns.resize(_returns);
8789
f.sideEffects = std::move(_sideEffects);
88-
f.literalArguments = _literalArguments;
90+
if (!_literalArguments.empty())
91+
f.literalArguments = std::move(_literalArguments);
92+
else
93+
f.literalArguments.reset();
8994
f.isMSize = false;
9095
f.instruction = {};
9196
f.generateCode = std::move(_generateCode);
@@ -107,7 +112,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
107112

108113
if (_objectAccess)
109114
{
110-
builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, true, [](
115+
builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {true}, [](
111116
FunctionCall const& _call,
112117
AbstractAssembly& _assembly,
113118
BuiltinContext& _context,
@@ -128,7 +133,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
128133
_assembly.appendDataSize(_context.subIDs.at(dataName));
129134
}
130135
}));
131-
builtins.emplace(createFunction("dataoffset", 1, 1, SideEffects{}, true, [](
136+
builtins.emplace(createFunction("dataoffset", 1, 1, SideEffects{}, {true}, [](
132137
FunctionCall const& _call,
133138
AbstractAssembly& _assembly,
134139
BuiltinContext& _context,
@@ -154,7 +159,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
154159
3,
155160
0,
156161
SideEffects{false, false, false, false, true},
157-
false,
162+
{},
158163
[](
159164
FunctionCall const&,
160165
AbstractAssembly& _assembly,
@@ -262,7 +267,7 @@ EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectA
262267
m_functions["popbool"_yulstring] = m_functions["pop"_yulstring];
263268
m_functions["popbool"_yulstring].name = "popbool"_yulstring;
264269
m_functions["popbool"_yulstring].parameters = {"bool"_yulstring};
265-
m_functions.insert(createFunction("bool_to_u256", 1, 1, {}, false, [](
270+
m_functions.insert(createFunction("bool_to_u256", 1, 1, {}, {}, [](
266271
FunctionCall const&,
267272
AbstractAssembly&,
268273
BuiltinContext&,
@@ -272,7 +277,7 @@ EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectA
272277
}));
273278
m_functions["bool_to_u256"_yulstring].parameters = {"bool"_yulstring};
274279
m_functions["bool_to_u256"_yulstring].returns = {"u256"_yulstring};
275-
m_functions.insert(createFunction("u256_to_bool", 1, 1, {}, false, [](
280+
m_functions.insert(createFunction("u256_to_bool", 1, 1, {}, {}, [](
276281
FunctionCall const&,
277282
AbstractAssembly& _assembly,
278283
BuiltinContext&,

libyul/backends/evm/EVMDialect.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ struct BuiltinContext
4545
std::map<YulString, AbstractAssembly::SubID> subIDs;
4646
};
4747

48-
struct BuiltinFunctionForEVM: BuiltinFunction
48+
struct BuiltinFunctionForEVM: public BuiltinFunction
4949
{
5050
std::optional<evmasm::Instruction> instruction;
5151
/// Function to generate code for the given function call and append it to the abstract

libyul/backends/wasm/WasmCodeTransform.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,15 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
136136
}
137137
typeConversionNeeded = true;
138138
}
139-
else if (builtin->literalArguments)
139+
else if (builtin->literalArguments && contains(builtin->literalArguments.value(), true))
140140
{
141141
vector<wasm::Expression> literals;
142-
for (auto const& arg: _call.arguments)
143-
literals.emplace_back(wasm::StringLiteral{std::get<Literal>(arg).value.str()});
142+
for (size_t i = 0; i < _call.arguments.size(); i++)
143+
if (builtin->literalArguments.value()[i])
144+
literals.emplace_back(wasm::StringLiteral{std::get<Literal>(_call.arguments[i]).value.str()});
145+
else
146+
literals.emplace_back(visitReturnByValue(_call.arguments[i]));
147+
144148
return wasm::BuiltinCall{_call.functionName.name.str(), std::move(literals)};
145149
}
146150
else

libyul/backends/wasm/WasmDialect.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ WasmDialect::WasmDialect()
102102
m_functions["unreachable"_yulstring].controlFlowSideEffects.terminates = true;
103103
m_functions["unreachable"_yulstring].controlFlowSideEffects.reverts = true;
104104

105-
addFunction("datasize", {i64}, {i64}, true, true);
106-
addFunction("dataoffset", {i64}, {i64}, true, true);
105+
addFunction("datasize", {i64}, {i64}, true, {true});
106+
addFunction("dataoffset", {i64}, {i64}, true, {true});
107107

108108
addEthereumExternals();
109109
}
@@ -204,7 +204,7 @@ void WasmDialect::addEthereumExternals()
204204
f.controlFlowSideEffects = ext.controlFlowSideEffects;
205205
f.isMSize = false;
206206
f.sideEffects.invalidatesStorage = (ext.name == "storageStore");
207-
f.literalArguments = false;
207+
f.literalArguments.reset();
208208
}
209209
}
210210

@@ -213,7 +213,7 @@ void WasmDialect::addFunction(
213213
vector<YulString> _params,
214214
vector<YulString> _returns,
215215
bool _movable,
216-
bool _literalArguments
216+
std::vector<bool> _literalArguments
217217
)
218218
{
219219
YulString name{move(_name)};
@@ -224,5 +224,8 @@ void WasmDialect::addFunction(
224224
f.returns = std::move(_returns);
225225
f.sideEffects = _movable ? SideEffects{} : SideEffects::worst();
226226
f.isMSize = false;
227-
f.literalArguments = _literalArguments;
227+
if (!_literalArguments.empty())
228+
f.literalArguments = std::move(_literalArguments);
229+
else
230+
f.literalArguments.reset();
228231
}

libyul/backends/wasm/WasmDialect.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ struct WasmDialect: public Dialect
6161
std::vector<YulString> _params,
6262
std::vector<YulString> _returns,
6363
bool _movable = true,
64-
bool _literalArguments = false
64+
std::vector<bool> _literalArguments = std::vector<bool>{}
6565
);
6666

6767
std::map<YulString, BuiltinFunction> m_functions;

libyul/backends/wasm/WordSizeTransform.cpp

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,24 @@ void WordSizeTransform::operator()(FunctionDefinition& _fd)
4141

4242
void WordSizeTransform::operator()(FunctionCall& _fc)
4343
{
44+
vector<bool> const* literalArguments = nullptr;
45+
4446
if (BuiltinFunction const* fun = m_inputDialect.builtin(_fc.functionName.name))
4547
if (fun->literalArguments)
48+
literalArguments = &fun->literalArguments.value();
49+
50+
vector<Expression> newArgs;
51+
52+
for (size_t i = 0; i < _fc.arguments.size(); i++)
53+
if (!literalArguments || !(*literalArguments)[i])
54+
newArgs += expandValueToVector(_fc.arguments[i]);
55+
else
4656
{
47-
for (Expression& arg: _fc.arguments)
48-
get<Literal>(arg).type = m_targetDialect.defaultType;
49-
return;
57+
get<Literal>(_fc.arguments[i]).type = m_targetDialect.defaultType;
58+
newArgs.emplace_back(std::move(_fc.arguments[i]));
5059
}
5160

52-
rewriteFunctionCallArguments(_fc.arguments);
61+
_fc.arguments = std::move(newArgs);
5362
}
5463

5564
void WordSizeTransform::operator()(If& _if)
@@ -97,9 +106,9 @@ void WordSizeTransform::operator()(Block& _block)
97106

98107
// Special handling for datasize and dataoffset - they will only need one variable.
99108
if (BuiltinFunction const* f = m_inputDialect.builtin(std::get<FunctionCall>(*varDecl.value).functionName.name))
100-
if (f->literalArguments)
109+
if (f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring)
101110
{
102-
yulAssert(f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring, "");
111+
yulAssert(f->literalArguments && f->literalArguments.value()[0], "");
103112
yulAssert(varDecl.variables.size() == 1, "");
104113
auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name);
105114
vector<Statement> ret;
@@ -158,9 +167,9 @@ void WordSizeTransform::operator()(Block& _block)
158167

159168
// Special handling for datasize and dataoffset - they will only need one variable.
160169
if (BuiltinFunction const* f = m_inputDialect.builtin(std::get<FunctionCall>(*assignment.value).functionName.name))
161-
if (f->literalArguments)
170+
if (f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring)
162171
{
163-
yulAssert(f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring, "");
172+
yulAssert(f->literalArguments && f->literalArguments.value()[0], "");
164173
yulAssert(assignment.variableNames.size() == 1, "");
165174
auto newLhs = generateU64IdentifierNames(assignment.variableNames[0].name);
166175
vector<Statement> ret;
@@ -268,17 +277,6 @@ void WordSizeTransform::rewriteIdentifierList(vector<Identifier>& _ids)
268277
);
269278
}
270279

271-
void WordSizeTransform::rewriteFunctionCallArguments(vector<Expression>& _args)
272-
{
273-
iterateReplacing(
274-
_args,
275-
[&](Expression& _e) -> std::optional<vector<Expression>>
276-
{
277-
return expandValueToVector(_e);
278-
}
279-
);
280-
}
281-
282280
vector<Statement> WordSizeTransform::handleSwitchInternal(
283281
langutil::SourceLocation const& _location,
284282
vector<YulString> const& _splitExpressions,

libyul/backends/wasm/WordSizeTransform.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ class WordSizeTransform: public ASTModifier
8383

8484
void rewriteVarDeclList(std::vector<TypedName>&);
8585
void rewriteIdentifierList(std::vector<Identifier>&);
86-
void rewriteFunctionCallArguments(std::vector<Expression>&);
8786

8887
std::vector<Statement> handleSwitch(Switch& _switch);
8988
std::vector<Statement> handleSwitchInternal(

libyul/optimiser/CommonSubexpressionEliminator.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,21 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
5858
// If this is a function call to a function that requires literal arguments,
5959
// do not try to simplify there.
6060
if (holds_alternative<FunctionCall>(_e))
61-
if (BuiltinFunction const* builtin = m_dialect.builtin(std::get<FunctionCall>(_e).functionName.name))
62-
if (builtin->literalArguments)
61+
{
62+
FunctionCall& funCall = std::get<FunctionCall>(_e);
63+
64+
if (BuiltinFunction const* builtin = m_dialect.builtin(funCall.functionName.name))
65+
{
66+
for (size_t i = funCall.arguments.size(); i > 0; i--)
6367
// We should not modify function arguments that have to be literals
6468
// Note that replacing the function call entirely is fine,
6569
// if the function call is movable.
66-
descend = false;
70+
if (!builtin->literalArguments || !builtin->literalArguments.value()[i - 1])
71+
visit(funCall.arguments[i - 1]);
72+
73+
descend = false;
74+
}
75+
}
6776

6877
// We visit the inner expression first to first simplify inner expressions,
6978
// which hopefully allows more matches.

0 commit comments

Comments
 (0)