-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move parallel/async lowering from LLVM codegen to a standard Halide IR lowering pass. #6195
Merged
Merged
Changes from 78 commits
Commits
Show all changes
85 commits
Select commit
Hold shift + click to select a range
0b7bd25
First cut at factoring parallel task compilation, including closure
e3a14b0
Fix formating that got munged by emacs somehow.
e06a2a8
Merge branch 'master' into factor_parallel_codegen
7e90c97
Checkpoint progress.
c9ab059
Small fixes.
a6d9f1d
Checkpoint progress.
a2a92a4
Checkpoint preogress.
8375961
Checkpoint progress.
fbb05ab
Checkpoint progress. Debugging code will be removed.
f8de53e
Try a fix for make_typed_struct in C++ codegen.
c5d902e
Another attempt to fix C++ codegen.
b1f8c6c
Another C codegen fix.
5eef291
Checkpoint progress.
3391b6d
Merge branch 'master' into factor_parallel_codegen
ade53a2
Use make_typed_struct rather than make_struct to construct
980c447
Checkpoint.
7071d40
Uniqueify closure names because LLVM was doing that to function names.
9b5c399
Small formatting cleanups.
ffb2887
Get generated C++ to compile via a combination of fixing types and
91d7130
Typo fix to a typo fix.
6785903
Merge branch 'master' into factor_parallel_codegen
c711bb1
Restore inadvertently deleted code.
d6ac3e9
Rename make_struct_type to declare_struct_type.
f157165
Add new file to CMake.
3c33517
Add fixes for Hexagon offload and any passes that might add additional
c4f517b
Add comment with a bit of info for the future..
69db2ad
Typo fix.
b5fd7f9
Don't duplicate the closure call to test the error return.
2e3660d
Use _ucon in C++ code to get rid of constness casting ugliness.
b8272fc
Merge branch 'master' into factor_parallel_codegen
4f345e0
Change resolve_function_name intrinsic to use a Call node to designate
ea9fa9a
Small C++ backend output formating change.
9cdb347
Add halide_semaphore_acquire_t as a well known type for use inside co…
147f381
Add handling for halide_semaphore_t allocation.
a71ecf1
Fix type for halide_semaphore_t.
d68ca8c
Reapply C++ backend formatting fix.
f00a4e5
Merge branch 'master' into factor_parallel_codegen
c0526eb
Add support for calling legacy halide_do_par_for runtime routine in
739a358
Formatting fixes.
dd0f8ed
Format and tidy fixes.
1fe603b
Attempt to pass formatting check.
e8f87ac
Merge branch 'master' into factor_parallel_codegen
71e5612
Merge branch 'master' into factor_parallel_codegen
2f24967
Fix last set of test failures.
430cab2
Formatting whitespace fixes.
d37a16c
Update comments.
6cefab2
Merge branch 'master' into factor_parallel_codegen
9a3d926
Attempt to fix pointer cast error with some versions of LLVM.
1aac285
Another attempt at fixing bool compatibility casting.
e8e296b
Another iteration.
2da926b
Merge branch 'master' into factor_parallel_codegen
3946ccd
Remove likely useless extern argument check logic.
687b71b
Merge branch 'master' into factor_parallel_codegen
c87399c
Merge branch 'master' into factor_parallel_codegen
00a0715
Add hacky fix for losing global variables.
dsharletg 5d93f1e
Comment typo fixes.
f49f800
Merge branch 'master' into factor_parallel_codegen
5733306
Merge branch 'master' into factor_parallel_codegen
steven-johnson 114d209
Merge branch 'master' into factor_parallel_codegen
steven-johnson df247f9
Remove no-longer-used Closure code from Codegen_Internal
steven-johnson b9ac7d6
Remove unused MayBlock visitor class
steven-johnson 6528ba6
clang-tidy
steven-johnson 2fd4c9f
Attempt to fix parallel offloads for HVX
steven-johnson e71bb81
Merge branch 'factor_parallel_codegen' of https://github.com/halide/H…
steven-johnson e64651b
Merge branch 'master' into factor_parallel_codegen
steven-johnson 7d2c2c6
Update parallel_nested_1.cpp
steven-johnson e02571b
Augment Closure debugging
steven-johnson 7eb9f5f
Add some std::move usage
steven-johnson f02b1e9
Merge branch 'master' into factor_parallel_codegen
steven-johnson 0faca07
Fix hvx lock/unlock semantics for PR #6457 (#6462)
steven-johnson d180598
Merge branch 'master' into factor_parallel_codegen
steven-johnson 9af64ae
Sort IntrinsicOp and corresponding names
steven-johnson 25b7b77
Remove unused `is_const_pointer()` function
steven-johnson 387c58f
Minor hygiene in LowerParallelTasks
steven-johnson 24a6eb2
Merge branch 'master' into factor_parallel_codegen
steven-johnson a1d267e
use Closure::include
steven-johnson c21e701
Switch to PureIntrinsics per review feedback.
b6ba514
Minor cleanup of parallel refactor intrinsics (#6465)
steven-johnson 2923246
Update CodeGen_C.cpp
steven-johnson 5764d12
Merge branch 'master' into factor_parallel_codegen
steven-johnson 64db40f
Remove 'foo.buffer' from Closure entirely
steven-johnson bdd7857
Update LowerParallelTasks.cpp
steven-johnson 5cf15ea
Keep track of task_parent inside LowerParallelTasks; remove no-longer…
steven-johnson 57412df
Fix potential issue with additional LoweredFuncs (#6490)
steven-johnson c70badd
factor parallel codegen with fewer intrinsics (#6487)
abadams File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1820,7 +1820,7 @@ void CodeGen_C::compile(const LoweredFunc &f, const std::map<std::string, std::s | |
set_name_mangling_mode(name_mangling); | ||
|
||
std::vector<std::string> namespaces; | ||
std::string simple_name = extract_namespaces(f.name, namespaces); | ||
std::string simple_name = c_print_name(extract_namespaces(f.name, namespaces), false); | ||
if (!is_c_plus_plus_interface()) { | ||
user_assert(namespaces.empty()) << "Namespace qualifiers not allowed on function name if not compiling with Target::CPlusPlusNameMangling.\n"; | ||
} | ||
|
@@ -2369,12 +2369,19 @@ void CodeGen_C::visit(const Call *op) { | |
} else if (op->is_intrinsic(Call::alloca)) { | ||
internal_assert(op->args.size() == 1); | ||
internal_assert(op->type.is_handle()); | ||
const int64_t *sz = as_const_int(op->args[0]); | ||
if (op->type == type_of<struct halide_buffer_t *>() && | ||
Call::as_intrinsic(op->args[0], {Call::size_of_halide_buffer_t})) { | ||
stream << get_indent(); | ||
string buf_name = unique_name('b'); | ||
stream << "halide_buffer_t " << buf_name << ";\n"; | ||
rhs << "&" << buf_name; | ||
} else if (op->type == type_of<struct halide_semaphore_t *>() && | ||
sz && *sz == 16) { | ||
stream << get_indent(); | ||
string semaphore_name = unique_name("sema"); | ||
stream << "halide_semaphore_t " << semaphore_name << ";\n"; | ||
rhs << "&" << semaphore_name; | ||
} else { | ||
// Make a stack of uint64_ts | ||
string size = print_expr(simplify((op->args[0] + 7) / 8)); | ||
|
@@ -2460,6 +2467,141 @@ void CodeGen_C::visit(const Call *op) { | |
} | ||
rhs << "(&" << struct_name << ")"; | ||
} | ||
} else if (op->is_intrinsic(Call::define_typed_struct)) { | ||
// Emit a declaration like: | ||
// | ||
// struct {const int f_0, const char f_1, const int f_2} foo; | ||
// | ||
// rhs is set to a nullptr of the new type. | ||
|
||
// Declares a struct type. Returns a null pointer of the new type. | ||
const size_t args_size = op->args.size(); | ||
internal_assert(args_size >= 1); | ||
|
||
const StringImm *str_imm = op->args[0].as<StringImm>(); | ||
internal_assert(str_imm != nullptr); | ||
std::string name = c_print_name(str_imm->value, false); | ||
|
||
stream << get_indent() << "struct " << name; | ||
stream << " {\n"; | ||
// List the types. | ||
indent++; | ||
for (size_t i = 1; i < args_size; i++) { | ||
stream << get_indent() << print_type(op->args[i].type(), AppendSpace) << "f_" << i - 1 << ";\n"; | ||
} | ||
indent--; | ||
stream << get_indent() << "};\n"; | ||
rhs << "((" << name << " *)nullptr)"; | ||
} else if (op->is_intrinsic(Call::forward_declare_typed_struct)) { | ||
// Emit a declaration like: | ||
// | ||
// struct foo; | ||
// | ||
// rhs is set to a nullptr of the given type. | ||
internal_assert(op->args.size() == 1); | ||
|
||
const StringImm *str_imm = op->args[0].as<StringImm>(); | ||
internal_assert(str_imm != nullptr); | ||
std::string name = c_print_name(str_imm->value, false); | ||
|
||
if (!starts_with(name, "halide_")) { | ||
// Types beginning with halide_ don't need forward declaration (e.g. halide_buffer_t). | ||
stream << get_indent() << "struct " << name << ";\n"; | ||
} | ||
rhs << "((" << name << " *)nullptr)"; | ||
} else if (op->is_intrinsic(Call::make_typed_struct)) { | ||
steven-johnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
internal_assert(op->args.size() >= 2); | ||
|
||
string type_carrier = print_expr(op->args[0]); | ||
const int64_t *count_ptr = as_const_int(op->args[1]); | ||
internal_assert(count_ptr != nullptr); | ||
int64_t count = *count_ptr; | ||
|
||
// Get the args | ||
vector<string> values; | ||
for (size_t i = 2; i < op->args.size(); i++) { | ||
values.push_back(print_expr(op->args[i])); | ||
} | ||
string struct_name = unique_name('s'); | ||
string array_specifier; | ||
if (count > 0) { | ||
array_specifier = "[]"; | ||
} | ||
stream << get_indent() << "std::remove_pointer<decltype(" << type_carrier << ")>::type " << struct_name << array_specifier << " = {\n"; | ||
// List the values. | ||
indent++; | ||
int item = 0; | ||
size_t initializer_count = values.size() / count; | ||
internal_assert((values.size() % count) == 0); | ||
do { | ||
if (count > 0) { | ||
stream << get_indent() << "{\n"; | ||
indent++; | ||
} | ||
for (size_t i = 0; i < initializer_count; i++) { | ||
stream << get_indent() << values[i + item * initializer_count]; | ||
if (i < op->args.size() - 1) { | ||
stream << ","; | ||
} | ||
stream << "\n"; | ||
} | ||
if (count > 0) { | ||
indent--; | ||
stream << get_indent() << "},\n"; | ||
} | ||
item += 1; | ||
} while (item < count); | ||
indent--; | ||
stream << get_indent() << "};\n"; | ||
// Return a pointer to it of the appropriate type | ||
|
||
// TODO: This is dubious type-punning. We really need to | ||
// find a better way to do this. We dodge the problem for | ||
// the specific case of buffer shapes in the case above. | ||
if (op->type.handle_type) { | ||
rhs << "(" << print_type(op->type) << ")"; | ||
} | ||
rhs << "(&" << struct_name << ((count > 0) ? "[0])" : ")"); | ||
} else if (op->is_intrinsic(Call::load_typed_struct_member)) { | ||
// Given an instance of a typed_struct, a definition of a typed_struct, | ||
// and the index of a slot, load the value of that slot. | ||
// | ||
// An instance of a typed_struct is an Expr of Handle() type that has been | ||
// created by a call to make_typed_struct. | ||
// | ||
// A definiton of a typed_struct is an Expr of Handle() type that has been | ||
// created by a call to define_typed_struct. | ||
// | ||
// Note that both the instance and definition are needed because the instance | ||
// is often a void* by the time it is -- it will have been been passed through | ||
// an API that takes an opaque pointer as a void*, and needs explicit casting | ||
// back to the correct type for safe field access. | ||
// | ||
// It is assumed that the slot index is valid for the given typed_struct. | ||
// | ||
// TODO: this comment is replicated in CodeGen_LLVM and should be updated there too. | ||
// TODO: https://github.com/halide/Halide/issues/6468 | ||
|
||
internal_assert(op->args.size() == 3); | ||
std::string typed_struct_instance = print_expr(op->args[0]); | ||
std::string typed_struct_definition = print_expr(op->args[1]); | ||
const uint64_t *index = as_const_uint(op->args[2]); | ||
internal_assert(index != nullptr); | ||
rhs << "((decltype(" << typed_struct_definition << "))" << typed_struct_instance << ")->" | ||
<< "f_" << *index; | ||
} else if (op->is_intrinsic(Call::resolve_function_name)) { | ||
internal_assert(op->args.size() == 1); | ||
const Call *decl_call = op->args[0].as<Call>(); | ||
internal_assert(decl_call != nullptr); | ||
std::string c_name = c_print_name(decl_call->name, false); | ||
rhs << "(&" << c_name << ")"; | ||
} else if (op->is_intrinsic(Call::get_user_context)) { | ||
internal_assert(op->args.empty()); | ||
rhs << "_ucon"; | ||
} else if (op->is_intrinsic(Call::get_pointer_symbol_or_null)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The LLVM implementation of this symbol attempts a symbol lookup, but this just returns null unconditionally, which is mighty puzzling. Is it a bug, or do I just misunderstand the usage? (Documentation somewhere would be helpful) |
||
internal_assert(op->args.size() == 2); | ||
// TODO(zalman|abadams): Figure out how to get rid of the maybe foo.buffer exists, maybe it doesn't thing in closures. | ||
rhs << "(nullptr)"; | ||
} else if (op->is_intrinsic(Call::stringify)) { | ||
// Rewrite to an snprintf | ||
vector<string> printf_args; | ||
|
@@ -2490,7 +2632,6 @@ void CodeGen_C::visit(const Call *op) { | |
stream << get_indent() << "char " << buf_name << "[1024];\n"; | ||
stream << get_indent() << "snprintf(" << buf_name << ", 1024, \"" << format_string << "\", " << with_commas(printf_args) << ");\n"; | ||
rhs << buf_name; | ||
|
||
} else if (op->is_intrinsic(Call::register_destructor)) { | ||
internal_assert(op->args.size() == 2); | ||
const StringImm *fn = op->args[0].as<StringImm>(); | ||
|
@@ -2560,6 +2701,21 @@ void CodeGen_C::visit(const Call *op) { | |
stream << get_indent() << rhs.str() << ";\n"; | ||
// Make an innocuous assignment value for our caller (probably an Evaluate node) to ignore. | ||
print_assignment(op->type, "0"); | ||
} else if (op->is_intrinsic(Call::define_typed_struct) || | ||
op->is_intrinsic(Call::make_typed_struct) || | ||
op->is_intrinsic(Call::load_typed_struct_member) || | ||
op->is_intrinsic(Call::resolve_function_name)) { | ||
// print_assigment will get the type info wrong for this case. | ||
std::string rhs_str = rhs.str(); | ||
auto cached = cache.find(rhs_str); | ||
if (cached == cache.end()) { | ||
id = unique_name('_'); | ||
stream << get_indent() << "auto " << id << " = " << rhs_str << ";\n"; | ||
} else { | ||
id = cached->second; | ||
} | ||
// Avoid unused variable warnings. | ||
stream << get_indent() << "halide_unused(" << id << ");\n"; | ||
} else { | ||
print_assignment(op->type, rhs.str()); | ||
} | ||
|
@@ -2710,9 +2866,10 @@ void CodeGen_C::visit(const Let *op) { | |
if (op->value.type().is_handle()) { | ||
// The body might contain a Load that references this directly | ||
// by name, so we can't rewrite the name. | ||
stream << get_indent() << print_type(op->value.type()) | ||
<< " " << print_name(op->name) | ||
<< " = " << id_value << ";\n"; | ||
std::string name = print_name(op->name); | ||
stream << get_indent() << "auto " | ||
<< name << " = " << id_value << ";\n"; | ||
stream << get_indent() << "halide_unused(" << name << ");\n"; | ||
} else { | ||
Expr new_var = Variable::make(op->value.type(), id_value); | ||
body = substitute(op->name, new_var, body); | ||
|
@@ -2800,12 +2957,14 @@ void CodeGen_C::visit(const VectorReduce *op) { | |
void CodeGen_C::visit(const LetStmt *op) { | ||
string id_value = print_expr(op->value); | ||
Stmt body = op->body; | ||
|
||
if (op->value.type().is_handle()) { | ||
// The body might contain a Load or Store that references this | ||
// directly by name, so we can't rewrite the name. | ||
stream << get_indent() << print_type(op->value.type()) | ||
<< " " << print_name(op->name) | ||
<< " = " << id_value << ";\n"; | ||
std::string name = print_name(op->name); | ||
stream << get_indent() << "auto " | ||
<< name << " = " << id_value << ";\n"; | ||
stream << get_indent() << "halide_unused(" << name << ");\n"; | ||
} else { | ||
Expr new_var = Variable::make(op->value.type(), id_value); | ||
body = substitute(op->name, new_var, body); | ||
|
@@ -3222,7 +3381,8 @@ HALIDE_FUNCTION_ATTRS | |
int test1(struct halide_buffer_t *_buf_buffer, float _alpha, int32_t _beta, void const *__user_context) { | ||
void * const _ucon = const_cast<void *>(__user_context); | ||
void *_0 = _halide_buffer_get_host(_buf_buffer); | ||
void * _buf = _0; | ||
auto _buf = _0; | ||
halide_unused(_buf); | ||
{ | ||
int64_t _1 = 43; | ||
int64_t _2 = _1 * _beta; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be:
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, my bad, will fix