Commit 0d72d8df authored by phlo's avatar phlo

removed Instruction::Set

parent 94a1cb96
This diff is collapsed.
#ifndef INSTRUCTION_HH_
#define INSTRUCTION_HH_
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
......@@ -12,35 +13,26 @@
//==============================================================================
// simplify declaration of instruction PODs ------------------------------------
//
#define DECLARE_NULLARY(classname, baseclass, _symbol, _type) \
struct classname : public baseclass \
struct classname : baseclass \
{ \
inline static const std::string & symbol = \
Set::add_nullary<classname>(_symbol); \
\
classname () : baseclass(_type) {} \
classname (uint8_t t) : baseclass(t) {} \
add_nullary<classname>(_symbol, _type); \
}; \
#define DECLARE_UNARY(classname, baseclass, _symbol, _type) \
struct classname : public baseclass \
struct classname : baseclass \
{ \
inline static const std::string & symbol = \
Set::add_unary<classname>(_symbol); \
\
classname (word_t a) : baseclass(_type, a) {} \
classname (uint8_t t, word_t a) : baseclass(t, a) {} \
add_unary<classname>(_symbol, _type); \
}; \
#define DECLARE_MEMORY(classname, baseclass, _symbol, _type) \
struct classname : public baseclass \
struct classname : baseclass \
{ \
inline static const std::string & symbol = \
Set::add_memory<classname>(_symbol); \
\
classname (word_t a, bool i = false) : baseclass(_type, a, i) {} \
classname (uint8_t t, word_t a, bool i = false) : baseclass(t, a, i) {} \
add_memory<classname>(_symbol, _type); \
}; \
//==============================================================================
......@@ -59,71 +51,66 @@ struct Encoder;
struct Instruction
{
//----------------------------------------------------------------------------
// member types
// static members
//----------------------------------------------------------------------------
// object factories to simplify parsing --------------------------------------
// map containing pointers to nullary instruction object factories
//
using nullary_factory_map =
std::unordered_map<
std::string,
std::function<Instruction()>>;
struct Set
{
virtual ~Set () = 0; // for a purely static class
//------------------------------------------------------------------------
// static members
//------------------------------------------------------------------------
// map containing pointers to nullary instruction object factories
//
using nullary_t =
std::unordered_map<
std::string,
Instruction (*) ()>;
static std::unique_ptr<nullary_t> nullary;
// map containing pointers to unary instruction object factories
//
using unary_t =
std::unordered_map<
std::string,
Instruction (*) (word_t)>;
static std::unique_ptr<unary_t> unary;
// map containing pointers to memory instruction object factories
//
using memory_t =
std::unordered_map<
std::string,
Instruction (*) (word_t, bool)>;
static std::unique_ptr<memory_t> memory;
//------------------------------------------------------------------------
// static member functions
//------------------------------------------------------------------------
// NOTE: really needed?
static bool contains (const std::string & symbol);
template <class POD>
static const std::string & add_nullary (const std::string && symbol);
template <class POD>
static const std::string & add_unary (const std::string && symbol);
template <class POD>
static const std::string & add_memory (const std::string && symbol);
// copy elision
//
static Instruction create (const std::string & symbol);
static Instruction create (const std::string & symbol, const word_t arg);
static Instruction create (const std::string & symbol,
const word_t arg,
const bool indirect);
};
static std::unique_ptr<nullary_factory_map> nullary_factory;
// instruction types ---------------------------------------------------------
// map containing pointers to unary instruction object factories
//
using unary_factory_map =
std::unordered_map<
std::string,
std::function<Instruction(word_t)>>;
static std::unique_ptr<unary_factory_map> unary_factory;
// map containing pointers to memory instruction object factories
//
using memory_factory_map =
std::unordered_map<
std::string,
std::function<Instruction(word_t, bool)>>;
static std::unique_ptr<memory_factory_map> memory_factory;
//----------------------------------------------------------------------------
// static member functions
//----------------------------------------------------------------------------
static bool contains (const std::string & symbol);
template <class POD>
static const std::string & add_nullary (const std::string & symbol,
uint8_t type);
template <class POD>
static const std::string & add_unary (const std::string & symbol,
uint8_t type);
template <class POD>
static const std::string & add_memory (const std::string & symbol,
uint8_t type);
// copy elision
//
static Instruction create (const std::string & symbol);
static Instruction create (const std::string & symbol, const word_t arg);
static Instruction create (const std::string & symbol,
const word_t arg,
const bool indirect);
//----------------------------------------------------------------------------
// member types
//----------------------------------------------------------------------------
// instruction types ---------------------------------------------------------
//
enum Type : uint8_t
{
none = 0,
......@@ -138,32 +125,11 @@ struct Instruction
jump = 1 << 7 // jump instruction
};
// abstract base classes for instruction PODs --------------------------------
struct Nullary
{
uint8_t type;
Nullary (uint8_t t) : type(t) {}
virtual ~Nullary () = default; // some virtual required by dynamic_cast
};
struct Unary : public Nullary
{
const word_t arg;
Unary (uint8_t t, word_t a) : Nullary(t), arg(a) {}
};
struct Memory : public Unary
{
const bool indirect;
Memory (uint8_t t, word_t a, bool i) : Unary(t, a), indirect(i) {}
};
// concrete instruction PODs -------------------------------------------------
// instruction PODs ----------------------------------------------------------
//
struct Nullary { uint8_t type = Type::none; };
struct Unary : Nullary { const word_t arg; };
struct Memory : Unary { const bool indirect = false; };
DECLARE_MEMORY (Load, Memory, "LOAD", accu | read)
DECLARE_MEMORY (Store, Memory, "STORE", write)
......@@ -194,12 +160,10 @@ struct Instruction
DECLARE_UNARY (Exit, Unary, "EXIT", control)
// abstract interface (types erasure concept) --------------------------------
//
struct Concept
{
using pointer = std::unique_ptr<Concept>;
virtual pointer clone () const = 0;
virtual std::unique_ptr<Concept> clone () const = 0;
virtual bool is_nullary () const = 0;
virtual bool is_unary () const = 0;
......@@ -227,7 +191,7 @@ struct Instruction
// members
//----------------------------------------------------------------------------
Concept::pointer model;
std::unique_ptr<Concept> model;
//----------------------------------------------------------------------------
// constructors
......@@ -237,8 +201,8 @@ struct Instruction
// construct embedding a given POD
//
template <class T>
Instruction (const T & pod);
template <class POD>
Instruction (const POD & pod);
// copy constructor
//
......
......@@ -21,6 +21,8 @@
// constructors
//------------------------------------------------------------------------------
Program::Program () : std::vector<Instruction>(), set_memory_barrier(false) {}
Program::Program(std::istream & f, const std::string & p) :
path(p),
set_memory_barrier(false)
......@@ -70,7 +72,7 @@ Program::Program(std::istream & f, const std::string & p) :
// parse instruction
if (line.eof())
{
try { cmd = Instruction::Set::create(symbol.c_str()); }
try { cmd = Instruction::create(symbol); }
catch (...) { UNKNOWN_INSTRUCTION_ERROR(); }
}
else
......@@ -80,7 +82,7 @@ Program::Program(std::istream & f, const std::string & p) :
// try to parse the argument
if (line >> arg)
{
try { cmd = Instruction::Set::create(symbol.c_str(), arg); }
try { cmd = Instruction::create(symbol, arg); }
catch (...) { UNKNOWN_INSTRUCTION_ERROR(); }
}
// label or indirect addressing
......@@ -108,12 +110,12 @@ Program::Program(std::istream & f, const std::string & p) :
"indirect addressing does not support labels");
}
try { cmd = Instruction::Set::create(symbol.c_str(), arg); }
try { cmd = Instruction::create(symbol, arg); }
catch (...) { UNKNOWN_INSTRUCTION_ERROR(); }
// check if the instruction supports indirect addresses
if (cmd.is_memory())
cmd = Instruction::Set::create(symbol.c_str(), arg, true);
cmd = Instruction::create(symbol, arg, true);
else
INSTRUCTION_ERROR("does not support indirect addressing");
}
......@@ -122,7 +124,7 @@ Program::Program(std::istream & f, const std::string & p) :
{
// create dummy Instruction which will be replaced by the
// actual one when all labels are known
try { cmd = Instruction::Set::create(symbol.c_str(), word_max); }
try { cmd = Instruction::create(symbol, word_max); }
catch (...) { UNKNOWN_INSTRUCTION_ERROR(); }
// check if the instruction supports labels (is a jmp)
......@@ -157,7 +159,7 @@ Program::Program(std::istream & f, const std::string & p) :
{
// check if label exists and replace dummy
(*this)[pc] =
Instruction::Set::create(sym.c_str(), label_to_pc.at(label));
Instruction::create(sym, label_to_pc.at(label));
}
catch (...)
{
......@@ -324,7 +326,7 @@ std::string Program::print (const bool include_pc, const word_t pc) const
//==============================================================================
// equality --------------------------------------------------------------------
//
bool operator == (const Program & a, const Program & b)
{
if (a.size() != b.size())
......
......@@ -77,6 +77,10 @@ struct Program : public std::vector<Instruction>
using std::vector<Instruction>::vector; // inherit constructors
// default constructor
//
Program ();
// construct from file
//
Program (std::istream & file, const std::string & path);
......
......@@ -139,7 +139,7 @@ Schedule::Schedule(std::istream & file, const std::string & path) :
bool flush = symbol == "FLUSH";
if (!flush && !Instruction::Set::contains(symbol.c_str()))
if (!flush && !Instruction::contains(symbol))
parser_error(path, line_num, "unknown instruction [" + symbol + "]");
// parse instruction argument
......
......@@ -8,6 +8,8 @@ namespace test::encoder {
template <class E, class Impl = E>
struct Encoder: public ::testing::Test
{
using Type = Instruction::Type;
Program::List programs;
std::unique_ptr<E> encoder = create_encoder();
......
......@@ -337,7 +337,7 @@ TEST_F(btor2_Encoder, declare_constants)
for (size_t thread = 0; thread < 3; thread++)
for (size_t pc = 0; pc < 3; pc++)
programs[thread].push_back(
Instruction::Set::create("ADDI", thread + pc + 1));
Instruction::create("ADDI", thread + pc + 1));
reset_encoder();
......@@ -3184,7 +3184,7 @@ TEST_F(btor2_Encoder, LOAD)
word_t address = 0;
Instruction::Load load (address);
Instruction::Load load {Type::none, address};
ASSERT_EQ(
encoder->nids_load[encoder->thread][address],
......@@ -3202,7 +3202,7 @@ TEST_F(btor2_Encoder, LOAD_indirect)
word_t address = 0;
Instruction::Load load (address, true);
Instruction::Load load {Type::none, address, true};
ASSERT_EQ(
encoder->nids_load_indirect[encoder->thread][address],
......@@ -3218,7 +3218,7 @@ TEST_F(btor2_Encoder, STORE)
word_t address = 0;
Instruction::Store store (address);
Instruction::Store store {Type::none, address};
encoder->update = ::Encoder::State::sb_adr;
ASSERT_EQ(encoder->nids_const[address], encoder->encode(store));
......@@ -3237,7 +3237,7 @@ TEST_F(btor2_Encoder, STORE_indirect)
word_t address = 0;
Instruction::Store store (address, true);
Instruction::Store store {Type::none, address, true};
encoder->update = ::Encoder::State::sb_adr;
ASSERT_EQ(
......@@ -3259,7 +3259,7 @@ TEST_F(btor2_Encoder, ADD)
word_t address = 0;
Instruction::Add add (address);
Instruction::Add add {Type::none, address};
std::string nid_add = encoder->encode(add);
......@@ -3291,7 +3291,7 @@ TEST_F(btor2_Encoder, ADD_indirect)
word_t address = 0;
Instruction::Add add (address, true);
Instruction::Add add {Type::none, address, true};
std::string nid_add = encoder->encode(add);
......@@ -3323,7 +3323,7 @@ TEST_F(btor2_Encoder, ADDI)
word_t value = 0;
Instruction::Addi addi (value);
Instruction::Addi addi {Type::none, value};
std::string nid_addi = encoder->encode(addi);
......@@ -3354,7 +3354,7 @@ TEST_F(btor2_Encoder, SUB)
word_t address = 0;
Instruction::Sub sub (address);
Instruction::Sub sub {Type::none, address};
std::string nid_sub = encoder->encode(sub);
......@@ -3386,7 +3386,7 @@ TEST_F(btor2_Encoder, SUB_indirect)
word_t address = 0;
Instruction::Sub sub (address, true);
Instruction::Sub sub {Type::none, address, true};
std::string nid_sub = encoder->encode(sub);
......@@ -3418,7 +3418,7 @@ TEST_F(btor2_Encoder, SUBI)
word_t value = 0;
Instruction::Subi subi (value);
Instruction::Subi subi {Type::none, value};
std::string nid_subi = encoder->encode(subi);
......@@ -3449,7 +3449,7 @@ TEST_F(btor2_Encoder, MUL)
word_t address = 0;
Instruction::Mul mul (address);
Instruction::Mul mul {Type::none, address};
std::string nid_mul = encoder->encode(mul);
......@@ -3481,7 +3481,7 @@ TEST_F(btor2_Encoder, MUL_indirect)
word_t address = 0;
Instruction::Mul mul (address, true);
Instruction::Mul mul {Type::none, address, true};
std::string nid_mul = encoder->encode(mul);
......@@ -3513,7 +3513,7 @@ TEST_F(btor2_Encoder, MULI)
word_t value = 0;
Instruction::Muli muli (value);
Instruction::Muli muli {Type::none, value};
std::string nid_muli = encoder->encode(muli);
......@@ -3544,7 +3544,7 @@ TEST_F(btor2_Encoder, CMP)
word_t address = 0;
Instruction::Cmp cmp (address);
Instruction::Cmp cmp {Type::none, address};
std::string nid_cmp = encoder->encode(cmp);
......@@ -3576,7 +3576,7 @@ TEST_F(btor2_Encoder, CMP_indirect)
word_t address = 0;
Instruction::Cmp cmp (address, true);
Instruction::Cmp cmp {Type::none, address, true};
std::string nid_cmp = encoder->encode(cmp);
......@@ -3600,7 +3600,7 @@ TEST_F(btor2_Encoder, CMP_indirect)
TEST_F(btor2_Encoder, JMP)
{
Instruction::Jmp jmp (0);
Instruction::Jmp jmp {Type::none, 0};
ASSERT_EQ("", encoder->encode(jmp));
ASSERT_EQ("", encoder->str());
......@@ -3614,7 +3614,7 @@ TEST_F(btor2_Encoder, JZ)
btor2::nid_t nid = encoder->node;
Instruction::Jz jz (0);
Instruction::Jz jz {Type::none, 0};
std::string nid_jz = encoder->encode(jz);
......@@ -3643,7 +3643,7 @@ TEST_F(btor2_Encoder, JNZ)
btor2::nid_t nid = encoder->node;
Instruction::Jnz jnz (0);
Instruction::Jnz jnz {Type::none, 0};
std::string nid_jnz = encoder->encode(jnz);
......@@ -3672,7 +3672,7 @@ TEST_F(btor2_Encoder, JS)
btor2::nid_t nid = encoder->node;
Instruction::Js js (0);
Instruction::Js js {Type::none, 0};
std::string nid_js = encoder->encode(js);
......@@ -3702,7 +3702,7 @@ TEST_F(btor2_Encoder, JNS)
btor2::nid_t nid = encoder->node;
Instruction::Jns jns (0);
Instruction::Jns jns {Type::none, 0};
std::string nid_jns = encoder->encode(jns);
......@@ -3732,7 +3732,7 @@ TEST_F(btor2_Encoder, JNZNS)
btor2::nid_t nid = encoder->node;
Instruction::Jnzns jnzns (0);
Instruction::Jnzns jnzns {Type::none, 0};
std::string nid_jnzns = encoder->encode(jnzns);
......@@ -3778,7 +3778,7 @@ TEST_F(btor2_Encoder, MEM)
word_t address = 0;
Instruction::Mem mem (address);
Instruction::Mem mem {Type::none, address};
ASSERT_EQ(
encoder->nids_load[encoder->thread][address],
......@@ -3796,7 +3796,7 @@ TEST_F(btor2_Encoder, MEM_indirect)
word_t address = 0;
Instruction::Mem mem (address, true);
Instruction::Mem mem {Type::none, address, true};
ASSERT_EQ(
encoder->nids_load_indirect[encoder->thread][address],
......@@ -3814,7 +3814,7 @@ TEST_F(btor2_Encoder, CAS)
word_t address = 0;
Instruction::Cas cas (address);
Instruction::Cas cas {Type::none, address};
std::string nid_cas;
......@@ -3884,7 +3884,7 @@ TEST_F(btor2_Encoder, CAS_indirect)
word_t address = 0;
Instruction::Cas cas (address, true);
Instruction::Cas cas {Type::none, address, true};
std::string nid_cas;
......@@ -3946,7 +3946,7 @@ TEST_F(btor2_Encoder, CAS_indirect)
TEST_F(btor2_Encoder, CHECK)
{
Instruction::Check check (1);
Instruction::Check check {Type::none, 1};
ASSERT_EQ("", encoder->encode(check));
ASSERT_EQ("", encoder->str());
......@@ -3954,7 +3954,7 @@ TEST_F(btor2_Encoder, CHECK)
TEST_F(btor2_Encoder, EXIT)
{
Instruction::Exit exit (1);
Instruction::Exit exit {Type::none, 1};
ASSERT_EQ(encoder->nids_const[1], encoder->encode(exit));
ASSERT_EQ("", encoder->str());
......
......@@ -1531,21 +1531,21 @@ TEST_F(smtlib_Encoder, define_checkpoint_contraints_empty)
TEST_F(smtlib_Encoder, LOAD)
{
Instruction::Load load (1);
Instruction::Load load {Type::none, 1};
ASSERT_EQ(encoder->load(load.arg), encoder->encode(load));
}
TEST_F(smtlib_Encoder, LOAD_indirect)
{
Instruction::Load load (1, true);
Instruction::Load load {Type::none, 1, true};
ASSERT_EQ(encoder->load(load.arg, load.indirect), encoder->encode(load));
}
TEST_F(smtlib_Encoder, STORE)
{
Instruction::Store store (1);
Instruction::Store store {Type::none, 1};
encoder->update = ::Encoder::State::sb_adr;
ASSERT_EQ("#x0001", encoder->encode(store));
......@@ -1556,7 +1556,7 @@ TEST_F(smtlib_Encoder, STORE)
TEST_F(smtlib_Encoder, STORE_indirect)
{
Instruction::Store store (1, true);
Instruction::Store store {Type::none, 1, true};
encoder->update = ::Encoder::State::sb_adr;
ASSERT_EQ(encoder->load(store.arg), encoder->encode(store));
......@@ -1567,7 +1567,7 @@ TEST_F(smtlib_Encoder, STORE_indirect)
TEST_F(smtlib_Encoder, ADD)
{
Instruction::Add add (1);
Instruction::Add add {Type::none, 1};
ASSERT_EQ(
"(bvadd accu_0_0 " + encoder->load(add.arg) + ")",
......@@ -1576,7 +1576,7 @@ TEST_F(smtlib_Encoder, ADD)
TEST_F(smtlib_Encoder, ADD_indirect)
{
Instruction::Add add (1, true);
Instruction::Add add {Type::none, 1, true};
ASSERT_EQ(
"(bvadd accu_0_0 " + encoder->load(add.arg, add.indirect) + ")",
......@@ -1585,14 +1585,14 @@ TEST_F(smtlib_Encoder, ADD_indirect)
TEST_F(smtlib_Encoder, ADDI)
{
Instruction::Addi addi (1);
Instruction::Addi addi {Type::none, 1};
ASSERT_EQ("(bvadd accu_0_0 #x0001)", encoder->encode(addi));
}
TEST_F(smtlib_Encoder, SUB)
{
Instruction::Sub sub (1);
Instruction::Sub sub {Type::none, 1};
ASSERT_EQ(
"(bvsub accu_0_0 " + encoder->load(sub.arg) + ")",
......@@ -1601,7 +1601,7 @@ TEST_F(smtlib_Encoder, SUB)
TEST_F(smtlib_Encoder, SUB_indirect)
{
Instruction::Sub sub (1, true);
Instruction::Sub sub {Type::none, 1, true};
ASSERT_EQ(
"(bvsub accu_0_0 " + encoder->load(sub.arg, sub.indirect) + ")",
......@@ -1610,14 +1610,14 @@ TEST_F(smtlib_Encoder, SUB_indirect)
TEST_F(smtlib_Encoder, SUBI)
{
Instruction::Subi subi (1);
Instruction::Subi subi {Type::none, 1};
ASSERT_EQ("(bvsub accu_0_0 #x0001)", encoder->encode(subi));
}
TEST_F(smtlib_Encoder, MUL)
{
Instruction::Mul mul (1);
Instruction::Mul mul {Type::none, 1};
ASSERT_EQ(
"(bvmul accu_0_0 " + encoder->load(mul.arg) + ")",
......@@ -1626,7 +1626,7 @@ TEST_F(smtlib_Encoder, MUL)
TEST_F(smtlib_Encoder, MUL_indirect)
{
Instruction::Mul mul (1, true);
Instruction::Mul mul {Type::none, 1, true};
ASSERT_EQ(
"(bvmul accu_0_0 " + encoder->load(mul.arg, mul.indirect) + ")",
......@@ -1635,14 +1635,14 @@ TEST_F(smtlib_Encoder, MUL_indirect)
TEST_F(smtlib_Encoder, MULI)
{
Instruction::Muli muli (1);
Instruction::Muli muli {Type::none, 1};
ASSERT_EQ("(bvmul accu_0_0 #x0001)", encoder->encode(muli));
}
TEST_F(smtlib_Encoder, CMP)
{
Instruction::Cmp cmp (1);
Instruction::Cmp cmp {Type::none, 1};
ASSERT_EQ(
"(bvsub accu_0_0 " + encoder->load(cmp.arg) + ")",
......@@ -1651,7 +1651,7 @@ TEST_F(smtlib_Encoder, CMP)
TEST_F(smtlib_Encoder, CMP_indirect)
{
Instruction::Cmp cmp (1, true);
Instruction::Cmp cmp {Type::none, 1, true};
ASSERT_EQ(
"(bvsub accu_0_0 " + encoder->load(cmp.arg, cmp.indirect) + ")",
......@@ -1660,28 +1660,28 @@ TEST_F(smtlib_Encoder, CMP_indirect)
TEST_F(smtlib_Encoder, JMP)
{
Instruction::Jmp jmp (1);
Instruction::Jmp jmp {Type::none, 1};
ASSERT_TRUE(encoder->encode(jmp).empty());
}
TEST_F(smtlib_Encoder, JZ)
{
Instruction::Jz jz (1);
Instruction::Jz jz {Type::none, 1};
ASSERT_EQ("(= accu_0_0 #x0000)", encoder->encode(jz));
}
TEST_F(smtlib_Encoder, JNZ)
{
Instruction::Jnz jnz (1);
Instruction::Jnz jnz {Type::none, 1};
ASSERT_EQ("(not (= accu_0_0 #x0000))", encoder->encode(jnz));
}
TEST_F(smtlib_Encoder, JS)
{
Instruction::Js js (1);