Commit 695deddc authored by phlo's avatar phlo

fixed removing FENCE instructions

parent 0d72d8df
......@@ -8,7 +8,7 @@
//==============================================================================
// Model<T>
//
// * Instruction::Concept implementation
// Instruction::Concept implementation
//==============================================================================
template <class T>
......@@ -24,43 +24,60 @@ struct Model : Instruction::Concept
Model (const T & p) : pod(p) {}
// Model (const T && pod) : obj(move(pod)) {}
virtual std::unique_ptr<Concept> clone () const
std::unique_ptr<Concept> clone () const
{
return std::make_unique<Model<T>>(pod);
}
virtual bool is_nullary () const { return std::is_base_of<Nullary, T>(); }
virtual bool is_unary () const { return std::is_base_of<Unary, T>(); }
virtual bool is_memory () const { return std::is_base_of<Memory, T>(); }
virtual bool is_jump () const { return pod.type & Instruction::Type::jump; }
bool is_nullary () const { return std::is_base_of<Nullary, T>::value; }
bool is_unary () const { return std::is_base_of<Unary, T>::value; }
bool is_memory () const { return std::is_base_of<Memory, T>::value; }
bool is_jump () const { return pod.type & Instruction::Type::jump; }
virtual bool requires_flush () const
bool requires_flush () const
{
return pod.type & (Type::write | Type::barrier);
}
virtual const std::string & symbol () const { return pod.symbol; }
const std::string & symbol () const { return pod.symbol; }
virtual uint8_t type () const { return pod.type; }
virtual void type (uint8_t type) { pod.type = type; }
uint8_t type () const { return pod.type; }
void type (const uint8_t type) { pod.type = type; }
virtual word_t arg () const { const Unary & u = *this; return u.arg; }
virtual bool indirect () const { const Memory & m = *this; return m.indirect; }
word_t arg () const
{
if constexpr(std::is_base_of<Unary, T>::value)
return pod.arg;
else
{ assert(false); return 0; }
}
virtual void execute (Thread & t) const { t.execute(pod); }
virtual std::string encode (Encoder & e) const { return e.encode(pod); }
void arg (const word_t a [[maybe_unused]])
{
if constexpr(std::is_base_of<Unary, T>::value)
pod.arg = a;
else
assert(false);
}
virtual operator const Unary & () const
bool indirect () const
{
assert(is_unary());
return reinterpret_cast<const Unary &>(pod);
if constexpr(std::is_base_of<Memory, T>::value)
return pod.indirect;
else
{ assert(false); return false; }
}
virtual operator const Memory & () const
void indirect (const bool i [[maybe_unused]])
{
assert(is_memory());
return reinterpret_cast<const Memory &>(pod);
if constexpr(std::is_base_of<Memory, T>::value)
pod.indirect = i;
else
assert(false);
}
void execute (Thread & t) const { t.execute(pod); }
std::string encode (Encoder & e) const { return e.encode(pod); }
};
//==============================================================================
......@@ -203,7 +220,10 @@ uint8_t Instruction::type () const { return model->type(); }
void Instruction::type (uint8_t t) { model->type(t); }
word_t Instruction::arg () const { return model->arg(); }
void Instruction::arg (const word_t a) { model->arg(a); }
bool Instruction::indirect () const { return model->indirect(); }
void Instruction::indirect (const bool i) { model->indirect(i); }
void Instruction::execute (Thread & t) const { model->execute(t); }
std::string Instruction::encode (Encoder & e) const { return model->encode(e); }
......@@ -220,11 +240,6 @@ Instruction & Instruction::operator = (const Instruction & other)
return *this;
}
// conversion ------------------------------------------------------------------
//
Instruction::operator const Unary & () const { return *model; }
Instruction::operator const Memory & () const { return *model; }
//==============================================================================
// non-member operators
//==============================================================================
......@@ -233,24 +248,17 @@ Instruction::operator const Memory & () const { return *model; }
//
bool operator == (const Instruction & a, const Instruction & b)
{
if (a.symbol() != b.symbol())
if (&a.symbol() != &b.symbol())
return false;
if (a.type() != b.type())
return false;
if (a.is_memory() && b.is_memory())
{
const Instruction::Memory & ma = a, mb = b;
return ma.arg == mb.arg && ma.indirect == mb.indirect;
}
else if (a.is_unary() && b.is_unary())
{
const Instruction::Unary & ua = a, ub = b;
return a.arg() == b.arg() && a.indirect() == b.indirect();
return ua.arg == ub.arg;
}
if (a.is_unary() && b.is_unary())
return a.arg() == b.arg();
return true;
}
......
......@@ -100,10 +100,10 @@ struct Instruction
// 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, word_t arg);
static Instruction create (const std::string & symbol,
const word_t arg,
const bool indirect);
word_t arg,
bool indirect);
//----------------------------------------------------------------------------
// member types
......@@ -128,8 +128,8 @@ struct Instruction
// instruction PODs ----------------------------------------------------------
//
struct Nullary { uint8_t type = Type::none; };
struct Unary : Nullary { const word_t arg; };
struct Memory : Unary { const bool indirect = false; };
struct Unary : Nullary { word_t arg; };
struct Memory : Unary { bool indirect = false; };
DECLARE_MEMORY (Load, Memory, "LOAD", accu | read)
DECLARE_MEMORY (Store, Memory, "STORE", write)
......@@ -178,13 +178,13 @@ struct Instruction
virtual void type (uint8_t type) = 0;
virtual word_t arg () const = 0;
virtual void arg (word_t arg) = 0;
virtual bool indirect () const = 0;
virtual void indirect (bool indirect) = 0;
virtual void execute (Thread & t) const = 0;
virtual std::string encode (Encoder & e) const = 0;
virtual operator const Instruction::Unary & () const = 0;
virtual operator const Instruction::Memory & () const = 0;
};
//----------------------------------------------------------------------------
......@@ -233,7 +233,10 @@ struct Instruction
void type (uint8_t type);
word_t arg () const;
void arg (word_t arg);
bool indirect () const;
void indirect (bool indirect);
void execute (Thread & t) const;
std::string encode (Encoder & e) const;
......@@ -253,11 +256,6 @@ struct Instruction
// * required due to user-declared copy constructor / assignment operator
//
Instruction & operator = (Instruction && other) = default;
// conversion into an abstract instruction POD
//
operator const Unary & () const;
operator const Memory & () const;
};
//==============================================================================
......
......@@ -21,11 +21,15 @@
// constructors
//------------------------------------------------------------------------------
Program::Program () : std::vector<Instruction>(), set_memory_barrier(false) {}
Program::Program () :
set_fence(false),
num_removed(0)
{}
Program::Program(std::istream & f, const std::string & p) :
path(p),
set_memory_barrier(false)
set_fence(false),
num_removed(0)
{
std::string token;
......@@ -174,16 +178,16 @@ Program::Program(std::istream & f, const std::string & p) :
if (op.is_jump())
{
const Instruction::Unary & j = op;
const word_t target = op.arg();
if (j.arg >= size())
if (target >= size())
throw std::runtime_error(
path + ": illegal jump [" + std::to_string(pc) + "]");
if (op.symbol() != Instruction::Jmp::symbol || j.arg == pc + 1)
if (op.symbol() != Instruction::Jmp::symbol || target == pc + 1)
predecessors[pc + 1].insert(pc);
predecessors[j.arg].insert(pc);
predecessors[target].insert(pc);
}
else if (pc < last)
{
......@@ -217,19 +221,22 @@ void Program::push_back (Instruction && op)
// define the following instruction as memory barrier
if (&op.symbol() == &Instruction::Fence::symbol)
{
set_memory_barrier = true;
set_fence = true;
num_removed++;
return;
}
// define instruction as checkpoint or memory barrier
if (set_memory_barrier)
// define instruction as memory barrier
if (set_fence)
{
op.type(op.type() | Instruction::Type::barrier);
set_memory_barrier = false;
set_fence = false;
}
// adjust jump targets after removing FENCEs
if (op.is_jump() && num_removed)
op.arg(op.arg() - num_removed);
// append instruction
std::vector<Instruction>::push_back(op);
}
......@@ -305,12 +312,10 @@ std::string Program::print (const bool include_pc, const word_t pc) const
}
else if (op.is_memory())
{
const Instruction::Memory & m = op;
if (m.indirect)
ss << "[" << m.arg << "]";
if (op.indirect())
ss << "[" << op.arg() << "]";
else
ss << m.arg;
ss << op.arg();
}
else
{
......
......@@ -69,7 +69,11 @@ struct Program : public std::vector<Instruction>
// define next instruction as memory barrier
//
bool set_memory_barrier;
bool set_fence;
// adjust jump targets after removing FENCEs
//
word_t num_removed;
//----------------------------------------------------------------------------
// constructors
......
......@@ -585,9 +585,7 @@ std::string Schedule::print () const
if (op.is_unary())
{
const Instruction::Unary u = op;
arg = std::to_string(u.arg);
arg = std::to_string(op.arg());
if (op.is_memory())
{
......@@ -597,7 +595,7 @@ std::string Schedule::print () const
else if (op.is_jump())
try
{
arg = program.get_label(u.arg);
arg = program.get_label(op.arg());
}
catch (...) {}
}
......@@ -725,18 +723,18 @@ const std::optional<Schedule::Heap> Schedule::iterator::next_heap_state ()
if (op.type() & Instruction::Type::atomic)
{
const Instruction::Memory & atomic = op;
word_t address = atomic.indirect
? schedule->heap_updates.at(atomic.arg).rend()->second
: atomic.arg;
word_t address =
op.indirect()
? schedule->heap_updates.at(op.arg()).rend()->second
: op.arg();
auto & cell = heap.at(address);
// mind subsequent writes of an equal value to the same address
word_t value = cell.cur->first == step
? cell.cur++->second
: (--cell.cur)++->second;
word_t value =
cell.cur->first == step
? cell.cur++->second
: (--cell.cur)++->second;
return {{address, value}};
}
......
......@@ -179,14 +179,14 @@
; statement activation variables - stmt_<thread>_<pc>
106 init 1 19 5
107 and 1 19 -45 0:0:STORE:0
108 next 1 19 107 stmt_0_0
109 init 1 20 4
110 and 1 20 -46 0:1:CHECK:0
111 ite 1 19 45 110 0:0:STORE:0
112 ne 1 9 6
113 and 1 51 112
114 ite 1 25 113 111 0:6:JNZ:1
108 ne 1 9 6
109 and 1 51 108
110 ite 1 25 109 107 0:6:JNZ:0
111 next 1 19 110 stmt_0_0
112 init 1 20 4
113 and 1 20 -46 0:1:CHECK:0
114 ite 1 19 45 113 0:0:STORE:0
115 next 1 20 114 stmt_0_1
116 init 1 21 4
......@@ -210,14 +210,14 @@
131 next 1 24 130 stmt_0_5
132 init 1 25 4
133 and 1 25 -51 0:6:JNZ:1
133 and 1 25 -51 0:6:JNZ:0
134 ite 1 24 50 133 0:5:CHECK:1
135 next 1 25 134 stmt_0_6
136 init 1 26 4
137 and 1 26 -52 0:7:EXIT:1
138 and 1 51 -112
139 ite 1 25 138 137 0:6:JNZ:1
138 and 1 51 -108
139 ite 1 25 138 137 0:6:JNZ:0
140 next 1 26 139 stmt_0_7
141 init 1 27 5
......
This diff is collapsed.
......@@ -92,11 +92,13 @@ TEST_F(Program, parse)
ASSERT_EQ(6, program.size());
ASSERT_EQ(1, program.checkpoints.size());
ASSERT_EQ(1, program.checkpoints[0][0]);
ASSERT_EQ(1, program.labels.size());
ASSERT_EQ(1, program.pc_to_label.size());
ASSERT_EQ("LOOP", *program.pc_to_label[2]);
ASSERT_EQ(1, program.label_to_pc.size());
ASSERT_EQ(2, program.label_to_pc[program.pc_to_label[2]]);
ASSERT_EQ(1, program.num_removed);
ASSERT_EQ("0\tSTORE\t0", program.print(true, 0));
ASSERT_EQ("1\tCHECK\t0", program.print(true, 1));
......@@ -105,6 +107,8 @@ TEST_F(Program, parse)
ASSERT_EQ("4\tCAS\t0", program.print(true, 4));
ASSERT_EQ("5\tJMP\tLOOP", program.print(true, 5));
ASSERT_TRUE(program[1].type() & Instruction::Type::barrier);
// indirect addressing
program = create_from_file<::Program>("data/indirect.addressing.asm");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment