Add FactoredSwitchCompiler - great space gain
This commit is contained in:
parent
b9b66b9244
commit
a34bbd928a
8 changed files with 178 additions and 5 deletions
|
@ -86,7 +86,7 @@ void CodeGenerator::switch_append_fde(
|
||||||
|
|
||||||
ostringstream case_oss;
|
ostringstream case_oss;
|
||||||
gen_of_row_content(fde.rows[fde_row_id], case_oss);
|
gen_of_row_content(fde.rows[fde_row_id], case_oss);
|
||||||
sw_case.code = case_oss.str();
|
sw_case.content.code = case_oss.str();
|
||||||
|
|
||||||
sw.cases.push_back(sw_case);
|
sw.cases.push_back(sw_case);
|
||||||
}
|
}
|
||||||
|
|
94
src/FactoredSwitchCompiler.cpp
Normal file
94
src/FactoredSwitchCompiler.cpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#include "FactoredSwitchCompiler.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
FactoredSwitchCompiler::FactoredSwitchCompiler(int indent):
|
||||||
|
AbstractSwitchCompiler(indent), cur_label_id(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FactoredSwitchCompiler::to_stream(
|
||||||
|
std::ostream& os, const SwitchStatement& sw)
|
||||||
|
{
|
||||||
|
JumpPointMap jump_points;
|
||||||
|
|
||||||
|
gen_binsearch_tree(os, jump_points, sw.switch_var,
|
||||||
|
sw.cases.begin(), sw.cases.end());
|
||||||
|
|
||||||
|
os << indent_str(sw.default_case) << "\n"
|
||||||
|
<< indent() << "/* ===== LABELS ============================== */\n\n";
|
||||||
|
|
||||||
|
gen_jump_points_code(os, jump_points);
|
||||||
|
}
|
||||||
|
|
||||||
|
FactoredSwitchCompiler::FactorJumpPoint
|
||||||
|
FactoredSwitchCompiler::get_jump_point(
|
||||||
|
FactoredSwitchCompiler::JumpPointMap& jump_map,
|
||||||
|
const SwitchStatement::SwitchCaseContent& sw_case)
|
||||||
|
{
|
||||||
|
#ifdef STATS
|
||||||
|
stats.refer_count++;
|
||||||
|
#endif//STATS
|
||||||
|
|
||||||
|
auto pregen = jump_map.find(sw_case);
|
||||||
|
if(pregen != jump_map.end()) // Was previously generated
|
||||||
|
return pregen->second;
|
||||||
|
|
||||||
|
#ifdef STATS
|
||||||
|
stats.generated_count++;
|
||||||
|
#endif//STATS
|
||||||
|
|
||||||
|
// Wasn't generated previously -- we'll generate it here
|
||||||
|
size_t label_id = cur_label_id++;
|
||||||
|
ostringstream label_ss;
|
||||||
|
label_ss << "_factor_" << label_id;
|
||||||
|
FactorJumpPoint label_name = label_ss.str();
|
||||||
|
|
||||||
|
jump_map.insert(make_pair(sw_case, label_name));
|
||||||
|
return label_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FactoredSwitchCompiler::gen_jump_points_code(std::ostream& os,
|
||||||
|
const FactoredSwitchCompiler::JumpPointMap& jump_map)
|
||||||
|
{
|
||||||
|
for(const auto& block: jump_map) {
|
||||||
|
os << indent() << block.second << ":\n"
|
||||||
|
<< indent_str(block.first.code) << "\n\n";
|
||||||
|
}
|
||||||
|
os << indent() << "assert(0);\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void FactoredSwitchCompiler::gen_binsearch_tree(
|
||||||
|
std::ostream& os,
|
||||||
|
FactoredSwitchCompiler::JumpPointMap& jump_map,
|
||||||
|
const std::string& sw_var,
|
||||||
|
const FactoredSwitchCompiler::case_iterator_t& begin,
|
||||||
|
const FactoredSwitchCompiler::case_iterator_t& end)
|
||||||
|
{
|
||||||
|
size_t iter_delta = end - begin;
|
||||||
|
if(iter_delta == 0)
|
||||||
|
os << indent() << "assert(0);\n";
|
||||||
|
else if(iter_delta == 1) {
|
||||||
|
FactorJumpPoint jump_point = get_jump_point(
|
||||||
|
jump_map, begin->content);
|
||||||
|
os << indent() << "// IP=0x" << hex << begin->low_bound
|
||||||
|
<< " ... 0x" << begin->high_bound << dec << "\n"
|
||||||
|
<< indent() << "goto " << jump_point << ";\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const case_iterator_t mid = begin + iter_delta / 2;
|
||||||
|
|
||||||
|
os << indent() << "if(" << sw_var << " < 0x"
|
||||||
|
<< hex << mid->low_bound << dec << ") {\n";
|
||||||
|
indent_count++;
|
||||||
|
gen_binsearch_tree(os, jump_map, sw_var, begin, mid);
|
||||||
|
indent_count--;
|
||||||
|
os << indent() << "} else {\n";
|
||||||
|
indent_count++;
|
||||||
|
gen_binsearch_tree(os, jump_map, sw_var, mid, end);
|
||||||
|
indent_count--;
|
||||||
|
os << indent() << "}\n";
|
||||||
|
}
|
||||||
|
}
|
49
src/FactoredSwitchCompiler.hpp
Normal file
49
src/FactoredSwitchCompiler.hpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/** A switch generator that tries to factor out most of the redundancy between
|
||||||
|
* switch blocks, generating manually a switch-like template */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SwitchStatement.hpp"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class FactoredSwitchCompiler: public AbstractSwitchCompiler {
|
||||||
|
public:
|
||||||
|
#ifdef STATS
|
||||||
|
struct Stats {
|
||||||
|
Stats(): generated_count(0), refer_count(0) {}
|
||||||
|
int generated_count, refer_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Stats& get_stats() const { return stats; }
|
||||||
|
#endif
|
||||||
|
FactoredSwitchCompiler(int indent=0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::string FactorJumpPoint;
|
||||||
|
typedef std::map<SwitchStatement::SwitchCaseContent, FactorJumpPoint>
|
||||||
|
JumpPointMap;
|
||||||
|
typedef std::vector<SwitchStatement::SwitchCase>::const_iterator
|
||||||
|
case_iterator_t;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void to_stream(std::ostream& os, const SwitchStatement& sw);
|
||||||
|
|
||||||
|
FactorJumpPoint get_jump_point(JumpPointMap& jump_map,
|
||||||
|
const SwitchStatement::SwitchCaseContent& sw_case);
|
||||||
|
|
||||||
|
void gen_jump_points_code(std::ostream& os,
|
||||||
|
const JumpPointMap& jump_map);
|
||||||
|
|
||||||
|
void gen_binsearch_tree(
|
||||||
|
std::ostream& os,
|
||||||
|
JumpPointMap& jump_map,
|
||||||
|
const std::string& sw_var,
|
||||||
|
const case_iterator_t& begin,
|
||||||
|
const case_iterator_t& end);
|
||||||
|
|
||||||
|
size_t cur_label_id;
|
||||||
|
|
||||||
|
#ifdef STATS
|
||||||
|
Stats stats;
|
||||||
|
#endif//STATS
|
||||||
|
};
|
|
@ -1,6 +1,7 @@
|
||||||
CXX=g++
|
CXX=g++
|
||||||
CXXLOCS?=-L. -I.
|
CXXLOCS?=-L. -I.
|
||||||
CXXFLAGS=$(CXXLOCS) -Wall -Wextra -std=c++14 -O2 -g
|
CXXFL?=
|
||||||
|
CXXFLAGS=$(CXXLOCS) -Wall -Wextra -std=c++14 -O2 -g $(CXXFL)
|
||||||
CXXLIBS=-lelf -ldwarf -ldwarfpp -lsrk31c++ -lc++fileno
|
CXXLIBS=-lelf -ldwarf -ldwarfpp -lsrk31c++ -lc++fileno
|
||||||
|
|
||||||
TARGET=dwarf-assembly
|
TARGET=dwarf-assembly
|
||||||
|
@ -14,6 +15,7 @@ OBJS=\
|
||||||
ConseqEquivFilter.o \
|
ConseqEquivFilter.o \
|
||||||
SwitchStatement.o \
|
SwitchStatement.o \
|
||||||
NativeSwitchCompiler.o \
|
NativeSwitchCompiler.o \
|
||||||
|
FactoredSwitchCompiler.o \
|
||||||
settings.o \
|
settings.o \
|
||||||
main.o
|
main.o
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ void NativeSwitchCompiler::to_stream(ostream& os, const SwitchStatement& sw) {
|
||||||
<< hex << cur_case.low_bound << " ... 0x" << cur_case.high_bound
|
<< hex << cur_case.low_bound << " ... 0x" << cur_case.high_bound
|
||||||
<< dec << ":\n";
|
<< dec << ":\n";
|
||||||
indent_count++;
|
indent_count++;
|
||||||
os << indent_str(cur_case.code);
|
os << indent_str(cur_case.content.code);
|
||||||
indent_count--;
|
indent_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
/** Compiles a SwitchStatement to a native C switch */
|
/** Compiles a SwitchStatement to a native C switch */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include "SwitchStatement.hpp"
|
#include "SwitchStatement.hpp"
|
||||||
|
|
||||||
class NativeSwitchCompiler: public AbstractSwitchCompiler {
|
class NativeSwitchCompiler: public AbstractSwitchCompiler {
|
||||||
|
|
|
@ -9,9 +9,19 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
struct SwitchStatement {
|
struct SwitchStatement {
|
||||||
|
struct SwitchCaseContent {
|
||||||
|
std::string code;
|
||||||
|
|
||||||
|
bool operator==(const SwitchCaseContent& oth) const {
|
||||||
|
return code == oth.code;
|
||||||
|
}
|
||||||
|
bool operator<(const SwitchCaseContent& oth) const {
|
||||||
|
return code < oth.code;
|
||||||
|
}
|
||||||
|
};
|
||||||
struct SwitchCase {
|
struct SwitchCase {
|
||||||
uintptr_t low_bound, high_bound;
|
uintptr_t low_bound, high_bound;
|
||||||
std::string code;
|
SwitchCaseContent content;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string switch_var;
|
std::string switch_var;
|
||||||
|
|
18
src/main.cpp
18
src/main.cpp
|
@ -9,6 +9,7 @@
|
||||||
#include "CodeGenerator.hpp"
|
#include "CodeGenerator.hpp"
|
||||||
#include "SwitchStatement.hpp"
|
#include "SwitchStatement.hpp"
|
||||||
#include "NativeSwitchCompiler.hpp"
|
#include "NativeSwitchCompiler.hpp"
|
||||||
|
#include "FactoredSwitchCompiler.hpp"
|
||||||
#include "PcHoleFiller.hpp"
|
#include "PcHoleFiller.hpp"
|
||||||
#include "ConseqEquivFilter.hpp"
|
#include "ConseqEquivFilter.hpp"
|
||||||
|
|
||||||
|
@ -101,6 +102,7 @@ int main(int argc, char** argv) {
|
||||||
ConseqEquivFilter()(
|
ConseqEquivFilter()(
|
||||||
parsed_dwarf));
|
parsed_dwarf));
|
||||||
|
|
||||||
|
FactoredSwitchCompiler* sw_compiler = new FactoredSwitchCompiler(1);
|
||||||
CodeGenerator code_gen(
|
CodeGenerator code_gen(
|
||||||
filtered_dwarf,
|
filtered_dwarf,
|
||||||
cout,
|
cout,
|
||||||
|
@ -109,8 +111,22 @@ int main(int argc, char** argv) {
|
||||||
ss << "_fde_" << fde.beg_ip;
|
ss << "_fde_" << fde.beg_ip;
|
||||||
return ss.str();
|
return ss.str();
|
||||||
},
|
},
|
||||||
new NativeSwitchCompiler());
|
//new NativeSwitchCompiler()
|
||||||
|
sw_compiler
|
||||||
|
);
|
||||||
|
|
||||||
code_gen.generate();
|
code_gen.generate();
|
||||||
|
|
||||||
|
#ifdef STATS
|
||||||
|
cerr << "Factoring stats:\nRefers: "
|
||||||
|
<< sw_compiler->get_stats().refer_count
|
||||||
|
<< "\nGenerated: "
|
||||||
|
<< sw_compiler->get_stats().generated_count
|
||||||
|
<< "\nAvoided: "
|
||||||
|
<< sw_compiler->get_stats().refer_count
|
||||||
|
- sw_compiler->get_stats().generated_count
|
||||||
|
<< "\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue