0
struct GCTX {
uint64_t _ip, _fp;
};
// used in the caller
class Generator : public NoCopyNoMove {
;
GCTX _ctxuint64_t _val;
public:
template<typename F, typename...Ts>
__attribute__((always_inline))
(F&& f, Ts&&...xs) {
Generatorauto fp = __builtin_frame_address(0);
= f((GCTX*)fp, std::forward<Ts>(xs)...);
_val register uint64_t callee_ip asm("rdx");
register uint64_t callee_fp asm("rsi");
asm volatile ("" : "=r"(callee_ip), "=r"(callee_fp) : :
"rbx", "rcx", "rsp", "r8", "r9", "r10", "r11",
"r12", "r13", "r14", "r15" );
= {callee_ip, callee_fp};
_ctx }
__attribute__((always_inline))
void resume() {
register uint64_t& _ip asm("rdx") = _ctx._ip;
register uint64_t& _fp asm("rsi") = _ctx._fp;
register uint64_t retval asm("rax");
__asm__ volatile (R"(
lea 1f(%%rip), %%rdi
xchg %%rbp, %0
jmp *%1
1:
)" : "+r"(_fp), "+r"(_ip), "=r"(retval) : :
"rbx", "rcx", "rsp", "rdi", "r8", "r9",
"r10", "r11", "r12", "r13", "r14", "r15");
= retval;
_val }
uint64_t value() { return _val; }
operator bool() { return _ctx._ip; }
~Generator() { while(unlikely(*this)) resume(); }
};
// the promise object of the generator, should be first
// constructed on entry, and gets destructed last on exit
class GPromise : public NoCopyNoMove {
;
GCTX _ctxpublic:
(GCTX* fp) {
GPromise._ip = (uint64_t)__builtin_return_address(0);
_ctx._fp = (uint64_t)fp;
_ctx}
__attribute__((always_inline))
void yield(uint64_t x) {
register uint64_t& retval asm("rax") = x;
register uint64_t& _caller_ip asm("rdi") = _ctx._ip;
register uint64_t& _caller_fp asm("rsi") = _ctx._fp;
__asm__ volatile (R"(
lea 1f(%%rip), %%rdx
xchg %%rbp, %1
jmp *%0
1:
)" : "+r"(_caller_ip), "+r"(_caller_fp), "+r"(retval) :
: "rbx", "rcx", "rdx", "rsp", "r8", "r9",
"r10", "r11", "r12", "r13", "r14", "r15");
}
~GPromise() {
auto frame = (uint64_t*)__builtin_frame_address(0);
[1] = _ctx._ip;
frameregister uint64_t _callee_ip asm("rdx");
__asm__ volatile ("xor %0, %0" : "=r"(_callee_ip));
}
};
__attribute__((noinline))
uint64_t seq_gen(GCTX* fp, uint64_t c) {
// create promise obj on entry, destructed on exit
(fp);
GPromise gwhile(c)
.yield(c--);
greturn 0;
}
__attribute__((noinline))
uint64_t sum_seq(uint64_t c) {
uint64_t sum = 0;
for (Generator g(&seq_gen, c); g; g.resume())
+= g.value();
sum return sum;
}
__attribute__((noinline))
void _Hanoi(GPromise& g, char n, char f, char t, char a) {
if (n == 0) return;
(g, n-1, f, a, t);
_Hanoi.yield(n + (f << 8) + (t << 16));
g(g, n-1, a, t, f);
_Hanoi}
__attribute__((noinline))
uint64_t Hanoi(GCTX* fp, char n) {
(fp);
GPromise g(g, n, 'a', 'b', 'c');
_Hanoireturn 0;
}
__attribute__((noinline))
uint64_t test_hanoi(uint64_t c) {
uint64_t sum = 0;
for (Generator g(&Hanoi, (char)c); g; g.resume()) {
auto n = g.value() % 256;
auto f = g.value() / 256 % 256;
auto t = g.value() / 256 / 256;
// printf("move disk %d from '%c' to '%c'\n", n, f, t);
++;
sum}
return sum;
}
__attribute__((noinline))
void wait_for_ready() { proton::thread_yield(); }
__attribute__((noinline))
ssize_t write_some(void *buf, size_t count) {
();
wait_for_ready// auto some = std::min((size_t)(1 + rand() % 16), count);
auto some = 800;
+= some;
total return some;
}
__attribute__((noinline))
ssize_t write_fully(void *buf, size_t count) {
size_t size = 0;
while (count) {
ssize_t s = write_some(buf, count);
if (s < 0) return s;
else if (s == 0) return size;
assert(s <= count);
-= s;
count += s;
size (char*&)buf += s;
}
return size;
}