-
Notifications
You must be signed in to change notification settings - Fork 497
/
flow.h
613 lines (523 loc) · 20 KB
/
flow.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
// Copyright (C) 2022-2024 Exaloop Inc. <https://exaloop.io>
#pragma once
#include <list>
#include <vector>
#include "codon/cir/base.h"
#include "codon/cir/transform/parallel/schedule.h"
#include "codon/cir/value.h"
#include "codon/cir/var.h"
namespace codon {
namespace ir {
/// Base for flows, which represent control flow.
class Flow : public AcceptorExtend<Flow, Value> {
public:
static const char NodeId;
using AcceptorExtend::AcceptorExtend;
protected:
types::Type *doGetType() const final;
};
/// Flow that contains a series of flows or instructions.
class SeriesFlow : public AcceptorExtend<SeriesFlow, Flow> {
private:
std::list<Value *> series;
public:
static const char NodeId;
using AcceptorExtend::AcceptorExtend;
/// @return an iterator to the first instruction/flow
auto begin() { return series.begin(); }
/// @return an iterator beyond the last instruction/flow
auto end() { return series.end(); }
/// @return an iterator to the first instruction/flow
auto begin() const { return series.begin(); }
/// @return an iterator beyond the last instruction/flow
auto end() const { return series.end(); }
/// @return a pointer to the first instruction/flow
Value *front() { return series.front(); }
/// @return a pointer to the last instruction/flow
Value *back() { return series.back(); }
/// @return a pointer to the first instruction/flow
const Value *front() const { return series.front(); }
/// @return a pointer to the last instruction/flow
const Value *back() const { return series.back(); }
/// Inserts an instruction/flow at the given position.
/// @param pos the position
/// @param v the flow or instruction
/// @return an iterator to the newly added instruction/flow
template <typename It> auto insert(It pos, Value *v) { return series.insert(pos, v); }
/// Appends an instruction/flow.
/// @param f the flow or instruction
void push_back(Value *f) { series.push_back(f); }
/// Erases the item at the supplied position.
/// @param pos the position
/// @return the iterator beyond the removed flow or instruction
template <typename It> auto erase(It pos) { return series.erase(pos); }
protected:
std::vector<Value *> doGetUsedValues() const override {
return std::vector<Value *>(series.begin(), series.end());
}
int doReplaceUsedValue(id_t id, Value *newValue) override;
};
/// Flow representing a while loop.
class WhileFlow : public AcceptorExtend<WhileFlow, Flow> {
private:
/// the condition
Value *cond;
/// the body
Value *body;
public:
static const char NodeId;
/// Constructs a while loop.
/// @param cond the condition
/// @param body the body
/// @param name the flow's name
WhileFlow(Value *cond, Flow *body, std::string name = "")
: AcceptorExtend(std::move(name)), cond(cond), body(body) {}
/// @return the condition
Value *getCond() { return cond; }
/// @return the condition
const Value *getCond() const { return cond; }
/// Sets the condition.
/// @param c the new condition
void setCond(Value *c) { cond = c; }
/// @return the body
Flow *getBody() { return cast<Flow>(body); }
/// @return the body
const Flow *getBody() const { return cast<Flow>(body); }
/// Sets the body.
/// @param f the new value
void setBody(Flow *f) { body = f; }
protected:
std::vector<Value *> doGetUsedValues() const override { return {cond, body}; }
int doReplaceUsedValue(id_t id, Value *newValue) override;
};
/// Flow representing a for loop.
class ForFlow : public AcceptorExtend<ForFlow, Flow> {
private:
/// the iterator
Value *iter;
/// the body
Value *body;
/// the variable
Var *var;
/// parallel loop schedule, or null if none
std::unique_ptr<transform::parallel::OMPSched> schedule;
public:
static const char NodeId;
/// Constructs a for loop.
/// @param iter the iterator
/// @param body the body
/// @param var the variable
/// @param name the flow's name
ForFlow(Value *iter, Flow *body, Var *var,
std::unique_ptr<transform::parallel::OMPSched> schedule = {},
std::string name = "")
: AcceptorExtend(std::move(name)), iter(iter), body(body), var(var),
schedule(std::move(schedule)) {}
/// @return the iter
Value *getIter() { return iter; }
/// @return the iter
const Value *getIter() const { return iter; }
/// Sets the iter.
/// @param f the new iter
void setIter(Value *f) { iter = f; }
/// @return the body
Flow *getBody() { return cast<Flow>(body); }
/// @return the body
const Flow *getBody() const { return cast<Flow>(body); }
/// Sets the body.
/// @param f the new body
void setBody(Flow *f) { body = f; }
/// @return the var
Var *getVar() { return var; }
/// @return the var
const Var *getVar() const { return var; }
/// Sets the var.
/// @param c the new var
void setVar(Var *c) { var = c; }
/// @return true if parallel
bool isParallel() const { return bool(schedule); }
/// Sets parallel status.
/// @param a true if parallel
void setParallel(bool a = true) {
if (a)
schedule = std::make_unique<transform::parallel::OMPSched>();
else
schedule = std::unique_ptr<transform::parallel::OMPSched>();
}
/// @return the parallel loop schedule, or null if none
transform::parallel::OMPSched *getSchedule() { return schedule.get(); }
/// @return the parallel loop schedule, or null if none
const transform::parallel::OMPSched *getSchedule() const { return schedule.get(); }
/// Sets the parallel loop schedule
/// @param s the schedule string (e.g. OpenMP pragma)
void setSchedule(std::unique_ptr<transform::parallel::OMPSched> s) {
schedule = std::move(s);
}
protected:
std::vector<Value *> doGetUsedValues() const override;
int doReplaceUsedValue(id_t id, Value *newValue) override;
std::vector<Var *> doGetUsedVariables() const override { return {var}; }
int doReplaceUsedVariable(id_t id, Var *newVar) override;
};
/// Flow representing an imperative for loop.
class ImperativeForFlow : public AcceptorExtend<ImperativeForFlow, Flow> {
private:
/// the initial value
Value *start;
/// the step value
int64_t step;
/// the end value
Value *end;
/// the body
Value *body;
/// the variable, must be integer type
Var *var;
/// parallel loop schedule, or null if none
std::unique_ptr<transform::parallel::OMPSched> schedule;
public:
static const char NodeId;
/// Constructs an imperative for loop.
/// @param body the body
/// @param start the start value
/// @param step the step value
/// @param end the end value
/// @param var the end variable, must be integer
/// @param name the flow's name
ImperativeForFlow(Value *start, int64_t step, Value *end, Flow *body, Var *var,
std::unique_ptr<transform::parallel::OMPSched> schedule = {},
std::string name = "")
: AcceptorExtend(std::move(name)), start(start), step(step), end(end), body(body),
var(var), schedule(std::move(schedule)) {}
/// @return the start value
Value *getStart() const { return start; }
/// Sets the start value.
/// @param v the new value
void setStart(Value *val) { start = val; }
/// @return the step value
int64_t getStep() const { return step; }
/// Sets the step value.
/// @param v the new value
void setStep(int64_t val) { step = val; }
/// @return the end value
Value *getEnd() const { return end; }
/// Sets the end value.
/// @param v the new value
void setEnd(Value *val) { end = val; }
/// @return the body
Flow *getBody() { return cast<Flow>(body); }
/// @return the body
const Flow *getBody() const { return cast<Flow>(body); }
/// Sets the body.
/// @param f the new body
void setBody(Flow *f) { body = f; }
/// @return the var
Var *getVar() { return var; }
/// @return the var
const Var *getVar() const { return var; }
/// Sets the var.
/// @param c the new var
void setVar(Var *c) { var = c; }
/// @return true if parallel
bool isParallel() const { return bool(schedule); }
/// Sets parallel status.
/// @param a true if parallel
void setParallel(bool a = true) {
if (a)
schedule = std::make_unique<transform::parallel::OMPSched>();
else
schedule = std::unique_ptr<transform::parallel::OMPSched>();
}
/// @return the parallel loop schedule, or null if none
transform::parallel::OMPSched *getSchedule() { return schedule.get(); }
/// @return the parallel loop schedule, or null if none
const transform::parallel::OMPSched *getSchedule() const { return schedule.get(); }
/// Sets the parallel loop schedule
/// @param s the schedule string (e.g. OpenMP pragma)
void setSchedule(std::unique_ptr<transform::parallel::OMPSched> s) {
schedule = std::move(s);
}
protected:
std::vector<Value *> doGetUsedValues() const override;
int doReplaceUsedValue(id_t id, Value *newValue) override;
std::vector<Var *> doGetUsedVariables() const override { return {var}; }
int doReplaceUsedVariable(id_t id, Var *newVar) override;
};
/// Flow representing an if statement.
class IfFlow : public AcceptorExtend<IfFlow, Flow> {
private:
/// the condition
Value *cond;
/// the true branch
Value *trueBranch;
/// the false branch
Value *falseBranch;
public:
static const char NodeId;
/// Constructs an if.
/// @param cond the condition
/// @param trueBranch the true branch
/// @param falseBranch the false branch
/// @param name the flow's name
IfFlow(Value *cond, Flow *trueBranch, Flow *falseBranch = nullptr,
std::string name = "")
: AcceptorExtend(std::move(name)), cond(cond), trueBranch(trueBranch),
falseBranch(falseBranch) {}
/// @return the true branch
Flow *getTrueBranch() { return cast<Flow>(trueBranch); }
/// @return the true branch
const Flow *getTrueBranch() const { return cast<Flow>(trueBranch); }
/// Sets the true branch.
/// @param f the new true branch
void setTrueBranch(Flow *f) { trueBranch = f; }
/// @return the false branch
Flow *getFalseBranch() { return cast<Flow>(falseBranch); }
/// @return the false branch
const Flow *getFalseBranch() const { return cast<Flow>(falseBranch); }
/// Sets the false.
/// @param f the new false
void setFalseBranch(Flow *f) { falseBranch = f; }
/// @return the condition
Value *getCond() { return cond; }
/// @return the condition
const Value *getCond() const { return cond; }
/// Sets the condition.
/// @param c the new condition
void setCond(Value *c) { cond = c; }
protected:
std::vector<Value *> doGetUsedValues() const override;
int doReplaceUsedValue(id_t id, Value *newValue) override;
};
/// Flow representing a try-catch statement.
class TryCatchFlow : public AcceptorExtend<TryCatchFlow, Flow> {
public:
/// Class representing a catch clause.
class Catch {
private:
/// the handler
Value *handler;
/// the catch type, may be nullptr
types::Type *type;
/// the catch variable, may be nullptr
Var *catchVar;
public:
explicit Catch(Flow *handler, types::Type *type = nullptr, Var *catchVar = nullptr)
: handler(handler), type(type), catchVar(catchVar) {}
/// @return the handler
Flow *getHandler() { return cast<Flow>(handler); }
/// @return the handler
const Flow *getHandler() const { return cast<Flow>(handler); }
/// Sets the handler.
/// @param h the new value
void setHandler(Flow *h) { handler = h; }
/// @return the catch type, may be nullptr
types::Type *getType() const { return type; }
/// Sets the catch type.
/// @param t the new type, nullptr for catch all
void setType(types::Type *t) { type = t; }
/// @return the variable, may be nullptr
Var *getVar() { return catchVar; }
/// @return the variable, may be nullptr
const Var *getVar() const { return catchVar; }
/// Sets the variable.
/// @param v the new value, may be nullptr
void setVar(Var *v) { catchVar = v; }
};
private:
/// the catch clauses
std::list<Catch> catches;
/// the body
Value *body;
/// the finally, may be nullptr
Value *finally;
public:
static const char NodeId;
/// Constructs an try-catch.
/// @param name the's name
/// @param body the body
/// @param finally the finally
explicit TryCatchFlow(Flow *body, Flow *finally = nullptr, std::string name = "")
: AcceptorExtend(std::move(name)), body(body), finally(finally) {}
/// @return the body
Flow *getBody() { return cast<Flow>(body); }
/// @return the body
const Flow *getBody() const { return cast<Flow>(body); }
/// Sets the body.
/// @param f the new
void setBody(Flow *f) { body = f; }
/// @return the finally
Flow *getFinally() { return cast<Flow>(finally); }
/// @return the finally
const Flow *getFinally() const { return cast<Flow>(finally); }
/// Sets the finally.
/// @param f the new
void setFinally(Flow *f) { finally = f; }
/// @return an iterator to the first catch
auto begin() { return catches.begin(); }
/// @return an iterator beyond the last catch
auto end() { return catches.end(); }
/// @return an iterator to the first catch
auto begin() const { return catches.begin(); }
/// @return an iterator beyond the last catch
auto end() const { return catches.end(); }
/// @return a reference to the first catch
auto &front() { return catches.front(); }
/// @return a reference to the last catch
auto &back() { return catches.back(); }
/// @return a reference to the first catch
auto &front() const { return catches.front(); }
/// @return a reference to the last catch
auto &back() const { return catches.back(); }
/// Inserts a catch at the given position.
/// @param pos the position
/// @param v the catch
/// @return an iterator to the newly added catch
template <typename It> auto insert(It pos, Catch v) { return catches.insert(pos, v); }
/// Appends a catch.
/// @param v the catch
void push_back(Catch v) { catches.push_back(v); }
/// Emplaces a catch.
/// @tparam Args the catch constructor args
template <typename... Args> void emplace_back(Args &&...args) {
catches.emplace_back(std::forward<Args>(args)...);
}
/// Erases a catch at the given position.
/// @param pos the position
/// @return the iterator beyond the erased catch
template <typename It> auto erase(It pos) { return catches.erase(pos); }
protected:
std::vector<Value *> doGetUsedValues() const override;
int doReplaceUsedValue(id_t id, Value *newValue) override;
std::vector<types::Type *> doGetUsedTypes() const override;
int doReplaceUsedType(const std::string &name, types::Type *newType) override;
std::vector<Var *> doGetUsedVariables() const override;
int doReplaceUsedVariable(id_t id, Var *newVar) override;
};
/// Flow that represents a pipeline. Pipelines with only function
/// stages are expressions and have a concrete type. Pipelines with
/// generator stages are not expressions and have no type. This
/// representation allows for stages that output generators but do
/// not get explicitly iterated in the pipeline, since generator
/// stages are denoted by a separate flag.
class PipelineFlow : public AcceptorExtend<PipelineFlow, Flow> {
public:
/// Represents a single stage in a pipeline.
class Stage {
private:
/// the function being (partially) called in this stage
Value *callee;
/// the function arguments, where null represents where
/// previous pipeline output should go
std::vector<Value *> args;
/// true if this stage is a generator
bool generator;
/// true if this stage is marked parallel
bool parallel;
public:
/// Constructs a pipeline stage.
/// @param callee the function being called
/// @param args call arguments, with exactly one null entry
/// @param generator whether this stage is a generator stage
/// @param parallel whether this stage is parallel
Stage(Value *callee, std::vector<Value *> args, bool generator, bool parallel)
: callee(callee), args(std::move(args)), generator(generator),
parallel(parallel) {}
/// @return an iterator to the first argument
auto begin() { return args.begin(); }
/// @return an iterator beyond the last argument
auto end() { return args.end(); }
/// @return an iterator to the first argument
auto begin() const { return args.begin(); }
/// @return an iterator beyond the last argument
auto end() const { return args.end(); }
/// @return a pointer to the first argument
Value *front() { return args.front(); }
/// @return a pointer to the last argument
Value *back() { return args.back(); }
/// @return a pointer to the first argument
const Value *front() const { return args.front(); }
/// @return a pointer to the last argument
const Value *back() const { return args.back(); }
/// Inserts an argument.
/// @param pos the position
/// @param v the argument
/// @return an iterator to the newly added argument
template <typename It> auto insert(It pos, Value *v) { return args.insert(pos, v); }
/// Appends an argument.
/// @param v the argument
void push_back(Value *v) { args.push_back(v); }
/// Erases the item at the supplied position.
/// @param pos the position
/// @return the iterator beyond the removed argument
template <typename It> auto erase(It pos) { return args.erase(pos); }
/// Sets the called function.
/// @param c the callee
void setCallee(Value *c) { callee = c; }
/// @return the called function
Value *getCallee() { return callee; }
/// @return the called function
const Value *getCallee() const { return callee; }
/// Sets the stage's generator flag.
/// @param v the new value
void setGenerator(bool v = true) { generator = v; }
/// @return whether this stage is a generator stage
bool isGenerator() const { return generator; }
/// Sets the stage's parallel flag.
/// @param v the new value
void setParallel(bool v = true) { parallel = v; }
/// @return whether this stage is parallel
bool isParallel() const { return parallel; }
/// @return the output type of this stage
types::Type *getOutputType() const;
/// @return the output element type of this stage
types::Type *getOutputElementType() const;
friend class PipelineFlow;
};
private:
/// pipeline stages
std::list<Stage> stages;
public:
static const char NodeId;
/// Constructs a pipeline flow.
/// @param stages vector of pipeline stages
/// @param name the name
explicit PipelineFlow(std::vector<Stage> stages = {}, std::string name = "")
: AcceptorExtend(std::move(name)), stages(stages.begin(), stages.end()) {}
/// @return an iterator to the first stage
auto begin() { return stages.begin(); }
/// @return an iterator beyond the last stage
auto end() { return stages.end(); }
/// @return an iterator to the first stage
auto begin() const { return stages.begin(); }
/// @return an iterator beyond the last stage
auto end() const { return stages.end(); }
/// @return a pointer to the first stage
Stage &front() { return stages.front(); }
/// @return a pointer to the last stage
Stage &back() { return stages.back(); }
/// @return a pointer to the first stage
const Stage &front() const { return stages.front(); }
/// @return a pointer to the last stage
const Stage &back() const { return stages.back(); }
/// Inserts a stage
/// @param pos the position
/// @param v the stage
/// @return an iterator to the newly added stage
template <typename It> auto insert(It pos, Stage v) { return stages.insert(pos, v); }
/// Appends an stage.
/// @param v the stage
void push_back(Stage v) { stages.push_back(std::move(v)); }
/// Erases the item at the supplied position.
/// @param pos the position
/// @return the iterator beyond the removed stage
template <typename It> auto erase(It pos) { return stages.erase(pos); }
/// Emplaces a stage.
/// @param args the args
template <typename... Args> void emplace_back(Args &&...args) {
stages.emplace_back(std::forward<Args>(args)...);
}
protected:
std::vector<Value *> doGetUsedValues() const override;
int doReplaceUsedValue(id_t id, Value *newValue) override;
};
} // namespace ir
} // namespace codon