Skip to content

Commit 90e3deb

Browse files
committed
Add support for hera debugging module.
1 parent 5a8c76f commit 90e3deb

File tree

3 files changed

+87
-33
lines changed

3 files changed

+87
-33
lines changed

libyul/backends/wasm/WasmCodeTransform.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,25 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call)
122122
{
123123
if (BuiltinFunction const* builtin = m_dialect.builtin(_call.functionName.name))
124124
{
125-
if (_call.functionName.name.str().substr(0, 4) == "eth.")
125+
if (_call.functionName.name.str().substr(0, 6) == "debug.")
126+
{
127+
yulAssert(builtin->returns.size() <= 1, "");
128+
// Imported function, use regular call, but mark for import.
129+
if (!m_functionsToImport.count(builtin->name))
130+
{
131+
wasm::FunctionImport imp{
132+
"debug",
133+
builtin->name.str().substr(6),
134+
builtin->name.str(),
135+
{},
136+
builtin->returns.empty() ? nullopt : make_optional<wasm::Type>(translatedType(builtin->returns.front()))
137+
};
138+
for (auto const& param: builtin->parameters)
139+
imp.paramTypes.emplace_back(translatedType(param));
140+
m_functionsToImport[builtin->name] = std::move(imp);
141+
}
142+
}
143+
else if (_call.functionName.name.str().substr(0, 4) == "eth.")
126144
{
127145
yulAssert(builtin->returns.size() <= 1, "");
128146
// Imported function, use regular call, but mark for import.

libyul/backends/wasm/WasmDialect.cpp

Lines changed: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,17 @@
2626
using namespace std;
2727
using namespace solidity::yul;
2828

29+
std::string const WasmDialect::i64{"i64"};
30+
std::string const WasmDialect::i32{"i32"};
31+
std::string const WasmDialect::i32ptr{"i32"}; // Uses "i32" on purpose.
32+
2933
WasmDialect::WasmDialect()
3034
{
31-
YulString i64 = "i64"_yulstring;
32-
YulString i32 = "i32"_yulstring;
33-
defaultType = i64;
34-
boolType = i32;
35-
types = {i64, i32};
35+
YulString i64_type = "i64"_yulstring;
36+
YulString i32_type = "i32"_yulstring;
37+
defaultType = i64_type;
38+
boolType = i32_type;
39+
types = {i64_type, i32_type};
3640

3741
for (auto t: types)
3842
for (auto const& name: {
@@ -67,10 +71,10 @@ WasmDialect::WasmDialect()
6771
// TODO: ge_s
6872
"ge_u"
6973
})
70-
addFunction(t.str() + "." + name, {t, t}, {i32});
74+
addFunction(t.str() + "." + name, {t, t}, {i32_type});
7175

72-
addFunction("i32.eqz", {i32}, {i32});
73-
addFunction("i64.eqz", {i64}, {i32});
76+
addFunction("i32.eqz", {i32_type}, {i32_type});
77+
addFunction("i64.eqz", {i64_type}, {i32_type});
7478

7579
for (auto t: types)
7680
for (auto const& name: {
@@ -80,27 +84,27 @@ WasmDialect::WasmDialect()
8084
})
8185
addFunction(t.str() + "." + name, {t}, {t});
8286

83-
addFunction("i32.wrap_i64", {i64}, {i32});
87+
addFunction("i32.wrap_i64", {i64_type}, {i32_type});
8488

85-
addFunction("i64.extend_i32_u", {i32}, {i64});
89+
addFunction("i64.extend_i32_u", {i32_type}, {i64_type});
8690

87-
addFunction("i32.store", {i32, i32}, {}, false);
91+
addFunction("i32.store", {i32_type, i32_type}, {}, false);
8892
m_functions["i32.store"_yulstring].sideEffects.invalidatesStorage = false;
89-
addFunction("i64.store", {i32, i64}, {}, false);
93+
addFunction("i64.store", {i32_type, i64_type}, {}, false);
9094
m_functions["i64.store"_yulstring].sideEffects.invalidatesStorage = false;
9195
// TODO: add i32.store16, i64.store8, i64.store16, i64.store32
9296

93-
addFunction("i32.store8", {i32, i32}, {}, false);
97+
addFunction("i32.store8", {i32_type, i32_type}, {}, false);
9498
m_functions["i32.store8"_yulstring].sideEffects.invalidatesStorage = false;
95-
addFunction("i64.store8", {i32, i64}, {}, false);
99+
addFunction("i64.store8", {i32_type, i64_type}, {}, false);
96100
m_functions["i64.store8"_yulstring].sideEffects.invalidatesStorage = false;
97101

98-
addFunction("i32.load", {i32}, {i32}, false);
102+
addFunction("i32.load", {i32_type}, {i32_type}, false);
99103
m_functions["i32.load"_yulstring].sideEffects.invalidatesStorage = false;
100104
m_functions["i32.load"_yulstring].sideEffects.invalidatesMemory = false;
101105
m_functions["i32.load"_yulstring].sideEffects.sideEffectFree = true;
102106
m_functions["i32.load"_yulstring].sideEffects.sideEffectFreeIfNoMSize = true;
103-
addFunction("i64.load", {i32}, {i64}, false);
107+
addFunction("i64.load", {i32_type}, {i64_type}, false);
104108
m_functions["i64.load"_yulstring].sideEffects.invalidatesStorage = false;
105109
m_functions["i64.load"_yulstring].sideEffects.invalidatesMemory = false;
106110
m_functions["i64.load"_yulstring].sideEffects.sideEffectFree = true;
@@ -109,8 +113,8 @@ WasmDialect::WasmDialect()
109113

110114
// Drop is actually overloaded for all types, but Yul does not support that.
111115
// Because of that, we introduce "i32.drop" and "i64.drop".
112-
addFunction("i32.drop", {i32}, {});
113-
addFunction("i64.drop", {i64}, {});
116+
addFunction("i32.drop", {i32_type}, {});
117+
addFunction("i64.drop", {i64_type}, {});
114118

115119
addFunction("nop", {}, {});
116120
addFunction("unreachable", {}, {}, false);
@@ -119,10 +123,11 @@ WasmDialect::WasmDialect()
119123
m_functions["unreachable"_yulstring].controlFlowSideEffects.terminates = true;
120124
m_functions["unreachable"_yulstring].controlFlowSideEffects.reverts = true;
121125

122-
addFunction("datasize", {i64}, {i64}, true, {true});
123-
addFunction("dataoffset", {i64}, {i64}, true, {true});
126+
addFunction("datasize", {i64_type}, {i64_type}, true, {true});
127+
addFunction("dataoffset", {i64_type}, {i64_type}, true, {true});
124128

125129
addEthereumExternals();
130+
addDebugExternals();
126131
}
127132

128133
BuiltinFunction const* WasmDialect::builtin(YulString _name) const
@@ -161,18 +166,6 @@ WasmDialect const& WasmDialect::instance()
161166

162167
void WasmDialect::addEthereumExternals()
163168
{
164-
// These are not YulStrings because that would be too complicated with regards
165-
// to the YulStringRepository reset.
166-
static string const i64{"i64"};
167-
static string const i32{"i32"};
168-
static string const i32ptr{"i32"}; // Uses "i32" on purpose.
169-
struct External
170-
{
171-
string name;
172-
vector<string> parameters;
173-
vector<string> returns;
174-
ControlFlowSideEffects controlFlowSideEffects = ControlFlowSideEffects{};
175-
};
176169
static vector<External> externals{
177170
{"getAddress", {i32ptr}, {}},
178171
{"getExternalBalance", {i32ptr, i32ptr}, {}},
@@ -225,6 +218,34 @@ void WasmDialect::addEthereumExternals()
225218
}
226219
}
227220

221+
void WasmDialect::addDebugExternals()
222+
{
223+
static vector<External> debugExternals {
224+
{"print32", {i32}, {}},
225+
{"print64", {i64}, {}},
226+
{"printMem", {i32, i32}, {}},
227+
{"printMemHex", {i32, i32}, {}},
228+
{"printStorage", {i32}, {}},
229+
{"printStorageHex", {i32}, {}},
230+
};
231+
for (External const& ext: debugExternals)
232+
{
233+
YulString name{"debug." + ext.name};
234+
BuiltinFunction& f = m_functions[name];
235+
f.name = name;
236+
for (string const& p: ext.parameters)
237+
f.parameters.emplace_back(YulString(p));
238+
for (string const& p: ext.returns)
239+
f.returns.emplace_back(YulString(p));
240+
// TODO some of them are side effect free.
241+
f.sideEffects = SideEffects::worst();
242+
f.controlFlowSideEffects = ext.controlFlowSideEffects;
243+
f.isMSize = false;
244+
f.sideEffects.invalidatesStorage = false;
245+
f.literalArguments.reset();
246+
}
247+
}
248+
228249
void WasmDialect::addFunction(
229250
string _name,
230251
vector<YulString> _params,

libyul/backends/wasm/WasmDialect.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct WasmDialect: public Dialect
5656

5757
private:
5858
void addEthereumExternals();
59+
void addDebugExternals();
5960

6061
void addFunction(
6162
std::string _name,
@@ -66,6 +67,20 @@ struct WasmDialect: public Dialect
6667
);
6768

6869
std::map<YulString, BuiltinFunction> m_functions;
70+
71+
// These are not YulStrings because that would be too complicated with regards
72+
// to the YulStringRepository reset.
73+
static std::string const i64;
74+
static std::string const i32;
75+
static std::string const i32ptr;
76+
77+
struct External
78+
{
79+
std::string name;
80+
std::vector<std::string> parameters;
81+
std::vector<std::string> returns;
82+
ControlFlowSideEffects controlFlowSideEffects = ControlFlowSideEffects{};
83+
};
6984
};
7085

7186
}

0 commit comments

Comments
 (0)