summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Blake Kongslie2022-06-25 10:16:12 -0700
committerJulian Blake Kongslie2022-06-25 10:16:12 -0700
commitd80e0dbd20bb8597afe92f770e39d20440557d1f (patch)
tree3a2a89d3e8b0a7dd8f9a26f166825cef7c62795d
parentMove get-git-tag to a tools subdirectory. (diff)
downloadissim-d80e0dbd20bb8597afe92f770e39d20440557d1f.tar.xz
Demo for a coroutine-based step evaluator.
Diffstat (limited to '')
-rw-r--r--aisa/aisa.cpp5
-rw-r--r--aisa/aisa.h73
-rw-r--r--aisa/coroutine.h120
-rw-r--r--main.cpp52
4 files changed, 243 insertions, 7 deletions
diff --git a/aisa/aisa.cpp b/aisa/aisa.cpp
index 0c806de..97a3b17 100644
--- a/aisa/aisa.cpp
+++ b/aisa/aisa.cpp
@@ -4,9 +4,4 @@
4 4
5namespace aisa { 5namespace aisa {
6 6
7 void do_something()
8 {
9 std::cout << "Hello, world!\n";
10 }
11
12} 7}
diff --git a/aisa/aisa.h b/aisa/aisa.h
index b570d6b..8cb302e 100644
--- a/aisa/aisa.h
+++ b/aisa/aisa.h
@@ -1,7 +1,78 @@
1#pragma once 1#pragma once
2 2
3#include <coroutine>
4#include <cstdint>
5#include <iostream>
6#include <optional>
7#include <utility>
8#include <vector>
9
10#include "aisa/coroutine.h"
11
3namespace aisa { 12namespace aisa {
4 13
5 void do_something(); 14 using regnum_t = std::uint_fast64_t;
15 using regval_t = std::uint64_t;
16
17 template<typename CRTP> struct EvalState {
18 CRTP & crtp() noexcept { return static_cast<CRTP &>(*this); }
19 task<regval_t> async_load_reg(regnum_t rn)
20 {
21 while (true) {
22 if (auto rv = crtp().load_reg(rn); rv.has_value())
23 co_return *rv;
24 co_await suspend();
25 }
26 }
27 };
28
29 struct Step {
30 const std::optional<std::pair<regnum_t, regval_t>> predicate;
31 const std::vector<regnum_t> source_regs;
32 const std::vector<regnum_t> destination_regs;
33
34 std::optional<regnum_t> predicate_reg() const
35 {
36 if (predicate.has_value())
37 return predicate->first;
38 return {};
39 }
40
41 std::optional<regnum_t> expected_predicate_val() const
42 {
43 if (predicate.has_value())
44 return predicate->second;
45 return {};
46 }
47
48 template<typename State> task<void> evaluate(State &state) const
49 {
50 if (predicate.has_value()) {
51 std::cout << "checking predicate...\n";
52 std::cout << "\texpect " << predicate->second << "\n";
53 regval_t pval = co_await state.async_load_reg(predicate->first);
54 std::cout << "\tgot " << pval << "\n";
55 if (pval != predicate->second) {
56 std::cout << "\tpredicate skipped\n";
57 co_return;
58 } else {
59 std::cout << "\tpredicate not skipped\n";
60 }
61 }
62 std::cout << "reading sources...\n";
63 std::vector<regval_t> source_vals;
64 source_vals.reserve(source_regs.size());
65 for (unsigned int i = 0; i < source_regs.size(); ++i) {
66 std::cout << "\tgetting source " << i << "...\n";
67 source_vals.emplace_back(co_await state.async_load_reg(source_regs[i]));
68 std::cout << "\t\tgot " << source_vals.back() << "\n";
69 }
70 std::cout << "sources:";
71 for (unsigned int i = 0; i < source_regs.size(); ++i)
72 std::cout << " " << source_regs[i] << "=" << source_vals[i];
73 std::cout << "\n";
74 std::cout << "done with evaluate\n";
75 }
76 };
6 77
7} 78}
diff --git a/aisa/coroutine.h b/aisa/coroutine.h
new file mode 100644
index 0000000..40a6982
--- /dev/null
+++ b/aisa/coroutine.h
@@ -0,0 +1,120 @@
1#pragma once
2
3#include <coroutine>
4
5namespace aisa {
6
7 inline auto suspend() noexcept { return std::suspend_always{}; }
8
9 template<typename result_t> struct promise;
10
11 template<typename result_t> struct task : public std::coroutine_handle<promise<result_t>> {
12 using handle = std::coroutine_handle<struct promise<result_t>>;
13 using promise_type = struct promise<result_t>;
14 bool await_ready() const noexcept { return handle::done(); }
15 result_t await_resume() const noexcept;
16 template<typename other_t> void await_suspend(std::coroutine_handle<struct promise<other_t>> h) const noexcept;
17 std::optional<result_t> operator()() noexcept;
18 };
19
20 template<> struct task<void> : public std::coroutine_handle<promise<void>> {
21 using handle = std::coroutine_handle<struct promise<void>>;
22 using promise_type = struct promise<void>;
23 bool await_ready() const noexcept { return handle::done(); }
24 void await_resume() const noexcept;
25 template<typename other_t> void await_suspend(std::coroutine_handle<struct promise<other_t>> h) const noexcept;
26 bool operator()() noexcept;
27 };
28
29 template<typename result_t> struct promise {
30 std::coroutine_handle<> precursor;
31 std::optional<result_t> result;
32 promise() = default;
33 promise(const promise &) = delete;
34 task<result_t> get_return_object() noexcept { return task<result_t>{std::coroutine_handle<promise<result_t>>::from_promise(*this)}; }
35 std::suspend_never initial_suspend() const noexcept { return {}; }
36 std::suspend_always final_suspend() const noexcept { return {}; }
37 void unhandled_exception() { }
38 void return_value(result_t x) noexcept { result = std::move(x); }
39 };
40
41 template<> struct promise<void> {
42 std::coroutine_handle<> precursor;
43 promise() = default;
44 promise(const promise &) = delete;
45 task<void> get_return_object() noexcept { return task<void>{std::coroutine_handle<promise<void>>::from_promise(*this)}; }
46 std::suspend_never initial_suspend() const noexcept { return {}; }
47 std::suspend_always final_suspend() const noexcept { return {}; }
48 void unhandled_exception() { }
49 void return_void() noexcept { }
50 };
51
52 template<typename result_t> result_t task<result_t>::await_resume() const noexcept
53 {
54 auto x = std::move(handle::promise().result.value());
55 handle::destroy();
56 return std::move(x);
57 }
58
59 template<typename result_t> template<typename other_t> void task<result_t>::await_suspend(std::coroutine_handle<struct promise<other_t>> h) const noexcept
60 {
61 h.promise().precursor = *this;
62 }
63
64 template<typename result_t> std::optional<result_t> task<result_t>::operator()() noexcept
65 {
66 if (!handle::operator bool())
67 return {};
68 if (!handle::done()) {
69 auto &precursor = handle::promise().precursor;
70 if (precursor) {
71 if (!precursor.done())
72 precursor.resume();
73 if (precursor.done())
74 precursor = nullptr;
75 }
76 if (!precursor)
77 handle::resume();
78 }
79 if (handle::done()) {
80 auto x = await_resume();
81 handle::operator=(nullptr);
82 return std::move(x);
83 }
84 return {};
85 }
86
87 inline void task<void>::await_resume() const noexcept
88 {
89 handle::destroy();
90 }
91
92 template<typename other_t> void task<void>::await_suspend(std::coroutine_handle<struct promise<other_t>> h) const noexcept
93 {
94 h.promise().precursor = *this;
95 }
96
97 inline bool task<void>::operator()() noexcept
98 {
99 if (!handle::operator bool())
100 return true;
101 if (!handle::done()) {
102 auto &precursor = handle::promise().precursor;
103 if (precursor) {
104 if (!precursor.done())
105 precursor.resume();
106 if (precursor.done())
107 precursor = nullptr;
108 }
109 if (!precursor)
110 handle::resume();
111 }
112 if (handle::done()) {
113 await_resume();
114 handle::operator=(nullptr);
115 return true;
116 }
117 return false;
118 }
119
120}
diff --git a/main.cpp b/main.cpp
index 6b7b0f4..0240bb5 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,4 +1,6 @@
1#include <iostream> 1#include <iostream>
2#include <map>
3#include <optional>
2 4
3#include "aisa/aisa.h" 5#include "aisa/aisa.h"
4#include "git-tag.h" 6#include "git-tag.h"
@@ -6,6 +8,54 @@
6int main(int argc, const char *argv[]) 8int main(int argc, const char *argv[])
7{ 9{
8 std::cout << "Version " << GIT_TAG << "\n"; 10 std::cout << "Version " << GIT_TAG << "\n";
9 aisa::do_something(); 11
12 aisa::Step step;
13 const_cast<std::optional<std::pair<aisa::regnum_t, aisa::regval_t>> &>(step.predicate) = std::optional(std::make_pair(123, 456));
14 const_cast<std::vector<aisa::regnum_t> &>(step.source_regs).emplace_back(12);
15 const_cast<std::vector<aisa::regnum_t> &>(step.source_regs).emplace_back(34);
16 const_cast<std::vector<aisa::regnum_t> &>(step.source_regs).emplace_back(56);
17
18 struct State : public aisa::EvalState<State> {
19 std::map<aisa::regnum_t, aisa::regval_t> regs;
20
21 std::optional<aisa::regval_t> load_reg(aisa::regnum_t rn)
22 {
23 std::cout << "state.load_reg(" << rn << ") = ";
24 if (auto x = regs.find(rn); x != regs.end()) {
25 std::cout << x->second << "\n";
26 return x->second;
27 }
28 std::cout << "(not available)\n";
29 return {};
30 }
31 } state;
32
33 auto t = state.async_load_reg(999);
34 t();
35 t();
36 t();
37 std::cout << "set regs[999] = 54321\n"; state.regs[999] = 54321;
38 std::optional<aisa::regval_t> result;
39 while (!result.has_value())
40 result = t();
41 std::cout << "result = " << *result << "\n";
42
43 std::cout << "\n\n\n";
44
45 auto w = step.evaluate(state);
46 w();
47 w();
48 w();
49 std::cout << "set predicate (valid)\n"; state.regs[step.predicate->first] = step.predicate->second;
50 w();
51 w();
52 w();
53 std::cout << "set regs (all)\n";
54 for (int i = 10; i < 100; ++i)
55 state.regs[i] = 1000 + i;
56 for (bool done = false; !done; done = w())
57 ;
58 std::cout << "huzzah!\n";
59
10 return 0; 60 return 0;
11} 61}