|
41 | 41 |
|
42 | 42 | mutable struct TapedTask{Tdynamic_scope,Tfargs,Tmc<:MistyClosure}
|
43 | 43 | dynamic_scope::Tdynamic_scope
|
44 |
| - fargs::Tfargs |
| 44 | + const fargs::Tfargs |
45 | 45 | const mc::Tmc
|
46 | 46 | const position::Base.RefValue{Int32}
|
47 | 47 | end
|
@@ -369,7 +369,7 @@ function derive_copyable_task_ir(ir::BBCode)::Tuple{BBCode,Tuple}
|
369 | 369 | end
|
370 | 370 | end
|
371 | 371 |
|
372 |
| - # For each existing basic block, produce a sequence of `NamedTuple`s which |
| 372 | + # For each existing basic block, create a sequence of `NamedTuple`s which |
373 | 373 | # define the manner in which it must be split.
|
374 | 374 | # A block will in general be split as follows:
|
375 | 375 | # 1 - %1 = φ(...)
|
@@ -666,6 +666,16 @@ function derive_copyable_task_ir(ir::BBCode)::Tuple{BBCode,Tuple}
|
666 | 666 | end
|
667 | 667 | push!(new_blocks, BBlock(splits_ids[n], inst_pairs))
|
668 | 668 | elseif is_produce_stmt(stmt)
|
| 669 | + # This is a statement of the form |
| 670 | + # %n = produce(arg) |
| 671 | + # |
| 672 | + # We transform this into |
| 673 | + # Libtask.set_resume_block!(refs_id, id_of_next_block) |
| 674 | + # return ProducedValue(arg) |
| 675 | + # |
| 676 | + # The point is to ensure that, next time that this `TapedTask` is called, |
| 677 | + # computation is resumed from the statement _after_ this produce statement, |
| 678 | + # and to return whatever this produce statement returns. |
669 | 679 |
|
670 | 680 | # When this TapedTask is next called, we should resume from the first
|
671 | 681 | # statement of the next split.
|
@@ -699,7 +709,29 @@ function derive_copyable_task_ir(ir::BBCode)::Tuple{BBCode,Tuple}
|
699 | 709 | push!(new_blocks, BBlock(splits_ids[n], inst_pairs))
|
700 | 710 | else
|
701 | 711 | # The final statement is one which might produce, but is not itself a
|
702 |
| - # `produce` statement. |
| 712 | + # `produce` statement. For example |
| 713 | + # y = f(x) |
| 714 | + # |
| 715 | + # becomes (morally speaking) |
| 716 | + # y = f(x) |
| 717 | + # if y isa ProducedValue |
| 718 | + # set_resume_block!(refs_id, id_of_current_block) |
| 719 | + # return y |
| 720 | + # end |
| 721 | + # |
| 722 | + # The point is to ensure that, if `f` "produces" (as indicated by `y` being |
| 723 | + # a `ProducedValue`) then the next time that this TapedTask is called, we |
| 724 | + # must resume from the call to `f`, as subsequent runs might also produce. |
| 725 | + # On the other hand, if anything other than a `ProducedValue` is returned, |
| 726 | + # we know that `f` has nothing else to produce, and execution can safely |
| 727 | + # continue to the next split. |
| 728 | + # In addition to the above, we must do the usual thing and ensure that any |
| 729 | + # ssas are read from storage, and write the result of this computation to |
| 730 | + # storage before continuing to the next instruction. |
| 731 | + # |
| 732 | + # You should look at the IR generated by a simple example in the test suite |
| 733 | + # which involves calls that might produce, in order to get a sense of what |
| 734 | + # the resulting code looks like prior to digging into the code below. |
703 | 735 |
|
704 | 736 | # Create a new basic block from the existing statements, since all new
|
705 | 737 | # statement need to live in their own basic blocks.
|
|
0 commit comments