|
7 | 7 | #include "llvm/IR/Module.h" |
8 | 8 | #include "llvm/Linker/Linker.h" |
9 | 9 | #include "quadrants/analysis/offline_cache_util.h" |
| 10 | +#include "quadrants/ir/analysis.h" |
| 11 | +#include "quadrants/ir/snode.h" |
10 | 12 | #include "quadrants/ir/statements.h" |
11 | 13 | #include "quadrants/ir/transforms.h" |
12 | 14 | #include "quadrants/program/extension.h" |
@@ -1975,6 +1977,39 @@ void TaskCodeGenLLVM::finalize_offloaded_task_function() { |
1975 | 1977 | current_task->ad_stack.allocas = ad_stack_allocas_info_; |
1976 | 1978 | current_task->ad_stack.size_exprs = ad_stack_size_exprs_; |
1977 | 1979 | current_task->ad_stack.bound_expr = ad_stack_static_bound_expr_; |
| 1980 | + // Snodes the task body mutates. Persisted on `OffloadedTask::snode_writes` so the LLVM |
| 1981 | + // launcher can invalidate the per-task adstack metadata cache when a kernel that runs in |
| 1982 | + // between mutated a SNode an enclosing `size_expr::FieldLoad` reads. Mirrors the SPIR-V |
| 1983 | + // analogue in `spirv_codegen.cpp`. Sorted + deduplicated for stable serialisation. |
| 1984 | + if (current_offload != nullptr) { |
| 1985 | + auto snode_rw = irpass::analysis::gather_snode_read_writes(current_offload); |
| 1986 | + current_task->snode_writes.reserve(snode_rw.second.size()); |
| 1987 | + for (auto *s : snode_rw.second) { |
| 1988 | + if (s != nullptr) { |
| 1989 | + current_task->snode_writes.push_back(s->id); |
| 1990 | + } |
| 1991 | + } |
| 1992 | + std::sort(current_task->snode_writes.begin(), current_task->snode_writes.end()); |
| 1993 | + current_task->snode_writes.erase( |
| 1994 | + std::unique(current_task->snode_writes.begin(), current_task->snode_writes.end()), |
| 1995 | + current_task->snode_writes.end()); |
| 1996 | + // Ndarray args this task writes to. Same role as `snode_writes` but for ndarray data; |
| 1997 | + // covers `size_expr::ExternalTensorRead` invalidation. The first element of each |
| 1998 | + // `arg_id_path` key is the kernel-arg slot, which is what `Program::ndarray_data_gen_` |
| 1999 | + // is keyed by (via the bound DeviceAllocation). |
| 2000 | + auto arr_access = irpass::detect_external_ptr_access_in_task(current_offload); |
| 2001 | + for (const auto &kv : arr_access) { |
| 2002 | + if ((static_cast<uint32_t>(kv.second) & static_cast<uint32_t>(irpass::ExternalPtrAccess::WRITE)) == 0) { |
| 2003 | + continue; |
| 2004 | + } |
| 2005 | + if (!kv.first.empty()) { |
| 2006 | + current_task->arr_writes.push_back(kv.first.front()); |
| 2007 | + } |
| 2008 | + } |
| 2009 | + std::sort(current_task->arr_writes.begin(), current_task->arr_writes.end()); |
| 2010 | + current_task->arr_writes.erase(std::unique(current_task->arr_writes.begin(), current_task->arr_writes.end()), |
| 2011 | + current_task->arr_writes.end()); |
| 2012 | + } |
1978 | 2013 | } |
1979 | 2014 |
|
1980 | 2015 | // entry_block should jump to the body after all allocas are inserted |
|
0 commit comments