Browse Source

Pinhole optimise working fairly well...

cl-refactor
Gav Wood 11 years ago
parent
commit
143e370bbf
  1. 7
      alethzero/MainWin.cpp
  2. 80
      liblll/Assembly.cpp
  3. 1
      liblll/Assembly.h
  4. 7
      liblll/CodeFragment.h
  5. 14
      liblll/Compiler.cpp
  6. 4
      liblll/Compiler.h
  7. 7
      lllc/main.cpp
  8. 4
      test/vm.cpp

7
alethzero/MainWin.cpp

@ -840,12 +840,13 @@ void Main::on_data_textChanged()
if (isCreation()) if (isCreation())
{ {
vector<string> errors; vector<string> errors;
auto asmcode = eth::compileLLLToAsm(ui->data->toPlainText().toStdString()); auto asmcode = eth::compileLLLToAsm(ui->data->toPlainText().toStdString(), false);
m_data = compileLLL(ui->data->toPlainText().toStdString(), &errors); auto asmcodeopt = eth::compileLLLToAsm(ui->data->toPlainText().toStdString(), true);
m_data = compileLLL(ui->data->toPlainText().toStdString(), true, &errors);
for (auto const& i: errors) for (auto const& i: errors)
cwarn << i; cwarn << i;
ui->code->setHtml("<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped() + "<p/><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre>"); ui->code->setHtml("<h4>Opt</h4><pre>" + QString::fromStdString(asmcodeopt).toHtmlEscaped() + "</pre><h4>Pre</h4><pre>" + QString::fromStdString(asmcode).toHtmlEscaped() + "</pre><h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped());
ui->gas->setMinimum((qint64)state().createGas(m_data.size(), 0)); ui->gas->setMinimum((qint64)state().createGas(m_data.size(), 0));
if (!ui->gas->isEnabled()) if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas); ui->gas->setValue(m_backupGas);

80
liblll/Assembly.cpp

@ -186,6 +186,9 @@ inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b)
return true; return true;
} }
struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; };
#define copt eth::LogOutputStream<OptimiserChannel, true>()
void Assembly::optimise() void Assembly::optimise()
{ {
map<Instruction, function<u256(u256, u256)>> c_simple = map<Instruction, function<u256(u256, u256)>> c_simple =
@ -210,7 +213,7 @@ void Assembly::optimise()
std::vector<pair<AssemblyItems, function<AssemblyItems(AssemblyItemsConstRef)>>> rules = std::vector<pair<AssemblyItems, function<AssemblyItems(AssemblyItemsConstRef)>>> rules =
{ {
{ { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
{ { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { return m[0].data() ? AssemblyItems({ m[1], Instruction::JUMP }) : AssemblyItems(); } }, { { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data()) return { m[1], Instruction::JUMP }; else return {}; } },
}; };
for (auto const& i: c_simple) for (auto const& i: c_simple)
@ -219,19 +222,16 @@ void Assembly::optimise()
{ {
rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } }); rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } });
rules.push_back({ { Push, i.first, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[2].data(), m[0].data()), i.first }; } }); rules.push_back({ { Push, i.first, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[2].data(), m[0].data()), i.first }; } });
rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {}; else return m.toVector(); }});
{
if (m[0].m_data == m[2].m_data)
return {};
else
return m.toVector();
}});
} }
copt << *this;
unsigned total = 0; unsigned total = 0;
for (unsigned count = 1; count > 0; total += count) for (unsigned count = 1; count > 0; total += count)
{ {
count = 0; count = 0;
map<u256, unsigned> tags;
for (unsigned i = 0; i < m_items.size(); ++i) for (unsigned i = 0; i < m_items.size(); ++i)
{ {
for (auto const& r: rules) for (auto const& r: rules)
@ -242,23 +242,64 @@ void Assembly::optimise()
auto rw = r.second(vr); auto rw = r.second(vr);
if (rw.size() < vr.size()) if (rw.size() < vr.size())
{ {
cnote << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes..."; copt << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes...";
for (unsigned j = 0; j < vr.size(); ++j) for (unsigned j = 0; j < vr.size(); ++j)
if (j < rw.size()) if (j < rw.size())
m_items[i + j] = rw[j]; m_items[i + j] = rw[j];
else else
m_items.erase(m_items.begin() + i + rw.size()); m_items.erase(m_items.begin() + i + rw.size());
cnote << AssemblyItemsConstRef(&rw); copt << AssemblyItemsConstRef(&rw);
count++; count++;
copt << "Now:\n" << m_items;
} }
} }
} }
if (m_items[i].type() == Operation && m_items[i].data() == (byte)Instruction::JUMP)
{
bool o = false;
while (m_items.size() > i + 1 && m_items[i + 1].type() != Tag)
{
m_items.erase(m_items.begin() + i + 1);
o = true;
}
if (o)
{
copt << "Jump with no tag. Now:\n" << m_items;
++count;
}
}
} }
}
// TODO: find all unused tags, for all those that have an unconditional jump immediately before, remove code between the tag and the next used tag (removing unused tags from the todo along the way). for (unsigned i = 0; i < m_items.size(); ++i)
if (m_items[i].type() == Tag)
tags.insert(make_pair(m_items[i].data(), i));
for (auto const& i: m_items)
if (i.type() == PushTag)
tags.erase(i.data());
cnote << total << " optimisations done."; if (tags.size())
{
auto t = *tags.begin();
unsigned i = t.second;
if (i && m_items[i - 1].type() == Operation && m_items[i - 1].data() == (byte)Instruction::JUMP)
while (i < m_items.size() && (m_items[i].type() != Tag || tags.count(m_items[i].data())))
{
if (m_items[i].type() == Tag && tags.count(m_items[i].data()))
tags.erase(m_items[i].data());
m_items.erase(m_items.begin() + i);
}
else
{
m_items.erase(m_items.begin() + i);
tags.erase(t.first);
}
copt << "Unused tag. Now:\n" << m_items;
++count;
}
}
copt << total << " optimisations done.";
} }
bytes Assembly::assemble() const bytes Assembly::assemble() const
@ -333,13 +374,16 @@ bytes Assembly::assemble() const
for (auto const& i: m_data) for (auto const& i: m_data)
{ {
auto its = dataRef.equal_range(i.first); auto its = dataRef.equal_range(i.first);
for (auto it = its.first; it != its.second; ++it) if (its.first != its.second)
{ {
bytesRef r(ret.data() + it->second, bytesPerTag); for (auto it = its.first; it != its.second; ++it)
toBigEndian(ret.size(), r); {
bytesRef r(ret.data() + it->second, bytesPerTag);
toBigEndian(ret.size(), r);
}
for (auto b: i.second)
ret.push_back(b);
} }
for (auto b: i.second)
ret.push_back(b);
} }
} }
return ret; return ret;

1
liblll/Assembly.h

@ -62,6 +62,7 @@ typedef std::vector<AssemblyItem> AssemblyItems;
typedef vector_ref<AssemblyItem const> AssemblyItemsConstRef; typedef vector_ref<AssemblyItem const> AssemblyItemsConstRef;
std::ostream& operator<<(std::ostream& _out, AssemblyItemsConstRef _i); std::ostream& operator<<(std::ostream& _out, AssemblyItemsConstRef _i);
inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _i) { return operator<<(_out, AssemblyItemsConstRef(&_i)); }
class Assembly class Assembly
{ {

7
liblll/CodeFragment.h

@ -43,10 +43,13 @@ public:
static CodeFragment compile(std::string const& _src, CompilerState& _s); static CodeFragment compile(std::string const& _src, CompilerState& _s);
/// Consolidates data and compiles code. /// Consolidates data and compiles code.
bytes code() { m_asm.optimise(); return m_asm.assemble(); } bytes code() const { return m_asm.assemble(); }
/// Consolidates data and compiles code. /// Consolidates data and compiles code.
std::string assembly() { m_asm.optimise(); return m_asm.out(); } std::string assembly() const { return m_asm.out(); }
/// Optimise the code. Best do this just before calling code() or assembly().
void optimise() { m_asm.optimise(); }
private: private:
template <class T> void error() const { throw T(); } template <class T> void error() const { throw T(); }

14
liblll/Compiler.cpp

@ -27,12 +27,15 @@
using namespace std; using namespace std;
using namespace eth; using namespace eth;
bytes eth::compileLLL(string const& _src, vector<string>* _errors) bytes eth::compileLLL(string const& _src, bool _opt, vector<string>* _errors)
{ {
try try
{ {
CompilerState cs; CompilerState cs;
bytes ret = CodeFragment::compile(_src, cs).code(); auto f = CodeFragment::compile(_src, cs);
if (_opt)
f.optimise();
bytes ret = f.code();
for (auto i: cs.treesToKill) for (auto i: cs.treesToKill)
killBigints(i); killBigints(i);
return ret; return ret;
@ -50,12 +53,15 @@ bytes eth::compileLLL(string const& _src, vector<string>* _errors)
return bytes(); return bytes();
} }
std::string eth::compileLLLToAsm(std::string const& _src, std::vector<std::string>* _errors) std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector<std::string>* _errors)
{ {
try try
{ {
CompilerState cs; CompilerState cs;
string ret = CodeFragment::compile(_src, cs).assembly(); auto f = CodeFragment::compile(_src, cs);
if (_opt)
f.optimise();
string ret = f.assembly();
for (auto i: cs.treesToKill) for (auto i: cs.treesToKill)
killBigints(i); killBigints(i);
return ret; return ret;

4
liblll/Compiler.h

@ -29,8 +29,8 @@ namespace eth
{ {
std::string parseLLL(std::string const& _src); std::string parseLLL(std::string const& _src);
std::string compileLLLToAsm(std::string const& _src, std::vector<std::string>* _errors = nullptr); std::string compileLLLToAsm(std::string const& _src, bool _opt = true, std::vector<std::string>* _errors = nullptr);
bytes compileLLL(std::string const& _src, std::vector<std::string>* _errors = nullptr); bytes compileLLL(std::string const& _src, bool _opt = true, std::vector<std::string>* _errors = nullptr);
} }

7
lllc/main.cpp

@ -55,6 +55,7 @@ enum Mode { Binary, Hex, Assembly, ParseTree };
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
unsigned optimise = 1;
string infile; string infile;
Mode mode = Hex; Mode mode = Hex;
@ -71,6 +72,8 @@ int main(int argc, char** argv)
mode = Assembly; mode = Assembly;
else if (arg == "-t" || arg == "--parse-tree") else if (arg == "-t" || arg == "--parse-tree")
mode = ParseTree; mode = ParseTree;
else if ((arg == "-o" || arg == "--optimise") && argc > i + 1)
optimise = atoi(argv[++i]);
else if (arg == "-V" || arg == "--version") else if (arg == "-V" || arg == "--version")
version(); version();
else else
@ -95,7 +98,7 @@ int main(int argc, char** argv)
cerr << "Empty file." << endl; cerr << "Empty file." << endl;
else if (mode == Binary || mode == Hex) else if (mode == Binary || mode == Hex)
{ {
auto bs = compileLLL(src, &errors); auto bs = compileLLL(src, optimise ? true : false, &errors);
if (mode == Hex) if (mode == Hex)
cout << toHex(bs) << endl; cout << toHex(bs) << endl;
else if (mode == Binary) else if (mode == Binary)
@ -104,7 +107,7 @@ int main(int argc, char** argv)
else if (mode == ParseTree) else if (mode == ParseTree)
cout << parseLLL(src) << endl; cout << parseLLL(src) << endl;
else if (mode == Assembly) else if (mode == Assembly)
cout << compileLLLToAsm(src, &errors) << endl; cout << compileLLLToAsm(src, optimise ? true : false, &errors) << endl;
for (auto const& i: errors) for (auto const& i: errors)
cerr << i << endl; cerr << i << endl;

4
test/vm.cpp

@ -163,7 +163,7 @@ public:
thisTxCode.clear(); thisTxCode.clear();
if (_o["code"].type() == str_type) if (_o["code"].type() == str_type)
thisTxCode = compileLLL(_o["code"].get_str(), nullptr); thisTxCode = compileLLL(_o["code"].get_str());
else else
for (auto const& j: _o["code"].get_array()) for (auto const& j: _o["code"].get_array())
thisTxCode.push_back(toByte(j)); thisTxCode.push_back(toByte(j));
@ -278,7 +278,7 @@ public:
get<2>(a)[adr++] = toInt(k); get<2>(a)[adr++] = toInt(k);
} }
if (o["code"].type() == str_type) if (o["code"].type() == str_type)
get<3>(a) = compileLLL(o["code"].get_str(), nullptr); get<3>(a) = compileLLL(o["code"].get_str());
else else
{ {
get<3>(a).clear(); get<3>(a).clear();

Loading…
Cancel
Save