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;
|
||||
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);
|
||||
}
|
||||
|
|
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++
|
||||
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
|
||||
|
||||
TARGET=dwarf-assembly
|
||||
|
@ -14,6 +15,7 @@ OBJS=\
|
|||
ConseqEquivFilter.o \
|
||||
SwitchStatement.o \
|
||||
NativeSwitchCompiler.o \
|
||||
FactoredSwitchCompiler.o \
|
||||
settings.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
|
||||
<< dec << ":\n";
|
||||
indent_count++;
|
||||
os << indent_str(cur_case.code);
|
||||
os << indent_str(cur_case.content.code);
|
||||
indent_count--;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/** Compiles a SwitchStatement to a native C switch */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SwitchStatement.hpp"
|
||||
|
||||
class NativeSwitchCompiler: public AbstractSwitchCompiler {
|
||||
|
|
|
@ -9,9 +9,19 @@
|
|||
#include <memory>
|
||||
|
||||
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 {
|
||||
uintptr_t low_bound, high_bound;
|
||||
std::string code;
|
||||
SwitchCaseContent content;
|
||||
};
|
||||
|
||||
std::string switch_var;
|
||||
|
|
18
src/main.cpp
18
src/main.cpp
|
@ -9,6 +9,7 @@
|
|||
#include "CodeGenerator.hpp"
|
||||
#include "SwitchStatement.hpp"
|
||||
#include "NativeSwitchCompiler.hpp"
|
||||
#include "FactoredSwitchCompiler.hpp"
|
||||
#include "PcHoleFiller.hpp"
|
||||
#include "ConseqEquivFilter.hpp"
|
||||
|
||||
|
@ -101,6 +102,7 @@ int main(int argc, char** argv) {
|
|||
ConseqEquivFilter()(
|
||||
parsed_dwarf));
|
||||
|
||||
FactoredSwitchCompiler* sw_compiler = new FactoredSwitchCompiler(1);
|
||||
CodeGenerator code_gen(
|
||||
filtered_dwarf,
|
||||
cout,
|
||||
|
@ -109,8 +111,22 @@ int main(int argc, char** argv) {
|
|||
ss << "_fde_" << fde.beg_ip;
|
||||
return ss.str();
|
||||
},
|
||||
new NativeSwitchCompiler());
|
||||
//new NativeSwitchCompiler()
|
||||
sw_compiler
|
||||
);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue