lsnes/include/library/assembler.hpp
Ilari Liusvaara b9e3a36588 Optimize generic controllers using dynamically generated code
The serialization is not quite on par with the static code,
deserialization is quite a bit faster.
2013-10-23 18:06:33 +03:00

201 lines
4.8 KiB
C++

#ifndef _library__assembler__hpp__included__
#define _library__assembler__hpp__included__
#include <cstring>
#include "serialization.hpp"
#include <cstdint>
#include <stdexcept>
#include <functional>
#include <map>
#include <vector>
#include <list>
namespace assembler
{
typedef size_t addr_t;
class label
{
public:
label()
{
kind = L_LOCAL_U;
}
label(void* global)
{
kind = L_GLOBAL;
addr = (addr_t)global;
}
label(const label& _base, int off)
{
switch(_base.kind) {
case L_LOCAL_U:
base = &_base;
offset = off;
kind = L_RELATIVE;
break;
case L_LOCAL_R:
offset = _base.offset + off;
kind = L_LOCAL_R;
break;
case L_GLOBAL:
addr = _base.addr + off;
kind = L_GLOBAL;
break;
case L_RELATIVE:
base = _base.base;
offset = _base.offset + off;
kind = L_RELATIVE;
break;
}
}
void set(int off)
{
if(kind != L_LOCAL_U)
throw std::runtime_error("Not undefined local label");
offset = off;
kind = L_LOCAL_R;
}
addr_t resolve(addr_t localbase) const
{
switch(kind) {
case L_LOCAL_U: throw std::runtime_error("Unresolved label");
case L_LOCAL_R: return localbase + offset;
case L_GLOBAL: return addr;
case L_RELATIVE: return base->resolve(localbase) + offset;
}
}
private:
enum _kind { L_LOCAL_U, L_LOCAL_R, L_GLOBAL, L_RELATIVE } kind;
const struct label* base;
addr_t addr;
int offset;
};
void i386_reloc_rel8(uint8_t* location, size_t target, size_t source);
void i386_reloc_rel16(uint8_t* location, size_t target, size_t source);
void i386_reloc_rel32(uint8_t* location, size_t target, size_t source);
void i386_reloc_abs32(uint8_t* location, size_t target, size_t source);
void i386_reloc_abs64(uint8_t* location, size_t target, size_t source);
uint8_t i386_modrm(uint8_t reg, uint8_t mod, uint8_t rm);
uint8_t i386_sib(uint8_t base, uint8_t index, uint8_t scale);
struct pad_tag
{
pad_tag(size_t _amount) : amount(_amount) {}
size_t amount;
};
struct label_tag
{
label_tag(label& _l) : l(_l) {}
label& l;
};
struct relocation_tag
{
relocation_tag(std::function<void(uint8_t* location, size_t target, size_t source)> _promise,
const label& _target) : promise(_promise), target(_target) {}
std::function<void(uint8_t* location, size_t target, size_t source)> promise;
const label& target;
};
struct byteseq_tag
{
byteseq_tag(const uint8_t* ss, size_t _sl) { st.resize(_sl); memcpy(&st[0], ss, _sl); }
std::vector<uint8_t> st;
};
template<typename T> struct unsigned_of {};
template<> struct unsigned_of<int8_t> { typedef uint8_t t; };
template<> struct unsigned_of<uint8_t> { typedef uint8_t t; };
template<> struct unsigned_of<int16_t> { typedef uint16_t t; };
template<> struct unsigned_of<uint16_t> { typedef uint16_t t; };
template<> struct unsigned_of<int32_t> { typedef uint32_t t; };
template<> struct unsigned_of<uint32_t> { typedef uint32_t t; };
template<> struct unsigned_of<int64_t> { typedef uint64_t t; };
template<> struct unsigned_of<uint64_t> { typedef uint64_t t; };
template<typename T> byteseq_tag vle(T v)
{
uint8_t b[sizeof(T)];
_write_common<T,typename unsigned_of<T>::t, sizeof(T), false>(b, v);
return byteseq_tag(b, sizeof(T));
}
template<typename T> byteseq_tag vbe(T v)
{
uint8_t b[sizeof(T)];
_write_common<T,typename unsigned_of<T>::t, sizeof(T), true>(b, v);
return byteseq_tag(b, sizeof(T));
}
struct assembler
{
assembler();
template<typename... T> void operator()(uint8_t b, T... args)
{
byte(b);
(*this)(args...);
}
template<typename... T> void operator()(pad_tag p, T... args)
{
pad(p.amount);
(*this)(args...);
}
template<typename... T> void operator()(label_tag l, T... args)
{
label(l.l);
(*this)(args...);
}
template<typename... T> void operator()(relocation_tag r, T... args)
{
relocation(r.promise, r.target);
(*this)(args...);
}
template<typename... T> void operator()(byteseq_tag b, T... args)
{
size_t o = size();
pad(b.st.size());
memcpy(&data[o], &b.st[0], b.st.size());
(*this)(args...);
}
void operator()() {}
void _label(label& l);
void _label(label& l, const std::string& globalname);
void byte(uint8_t b);
void byte(std::initializer_list<uint8_t> b);
void byte(const uint8_t* b, size_t l);
void relocation(std::function<void(uint8_t* location, size_t target, size_t source)> promise,
const label& target);
void align(size_t multiple);
void pad(size_t amount);
size_t size();
std::map<std::string, void*> flush(void* base);
private:
struct reloc
{
std::function<void(uint8_t* location, size_t target, size_t source)> promise;
const label* target;
size_t source;
};
std::vector<uint8_t> data;
std::list<reloc> relocs;
std::map<std::string, const label*> globals;
};
class dynamic_code
{
public:
dynamic_code(size_t size);
~dynamic_code();
void commit();
uint8_t* pointer() throw();
private:
void* base;
size_t asize;
};
}
#endif