Add FactoredSwitchCompiler - great space gain

This commit is contained in:
Théophile Bastian 2018-06-25 16:32:52 +02:00
parent b9b66b9244
commit a34bbd928a
8 changed files with 178 additions and 5 deletions

View file

@ -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);
} }

View 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";
}
}

View 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
};

View file

@ -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

View file

@ -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--;
} }

View file

@ -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 {

View file

@ -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;

View file

@ -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;
} }