-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
[AOT] Support LLVM backend with C++ runtime #10753
Conversation
b98da99
to
111efec
Compare
It has been a while since this PR was updated, please leave a review or address the outstanding comments. @areusch if this PR is still a work in progress, please convert it to a draft until it is ready for review. |
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.
I did a pass @areusch .
Few comments for docs / cleanup.
* \param num the number to convert | ||
* \return PrimExpr representing num | ||
*/ | ||
inline PrimExpr ConstInt32(int32_t num) { |
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.
Maybe not needed for this PR, but should we move this as tir::make_const_int32 ?
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.
changed to use tir::make_const
, which i think handles it
return tir::Evaluate(tir::Call(DataType::Int(32), tvm::tir::builtin::call_extern(), | ||
{tvm::tir::StringImm(device_hook), context})); | ||
} | ||
} // namespace |
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.
Why this empty namespace ?
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.
to make this a "static" function aka it cannot be linked against from elsewhere
tir::Stmt body = tir::SeqStmt::Flatten(prep_stmts_, call_stmts); | ||
|
||
for (auto bind : let_binds_) { | ||
body = tir::LetStmt(bind.first, bind.second, body); |
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.
Why do we need a Let binding here? Cant we just arg bind w/o introducing a let node here ?
tvm/src/tir/transforms/arg_binder.h
Lines 74 to 75 in 95df0eb
void Bind(const PrimExpr& arg, const PrimExpr& value, const std::string& arg_name, | |
bool with_let = false); |
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.
yeah sorry, this part is cruft and should get deleted.
} | ||
} // namespace | ||
|
||
class AOTCallGenerator { |
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.
docs : we need docs for this but I think this part is still WIP as I did not see who uses this
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.
good point--this is cruft from the old approach, before I started relying on LegalizePackedCalls/LowerTVMBuiltin, so can remove it now :)
src/target/llvm/codegen_cpu.cc
Outdated
PackedCall pc; | ||
std::string func_name = args[0].as<StringImmNode>()->value; | ||
llvm::Value* handle = GetPackedFuncHandle(func_name); | ||
llvm::Value* handle = nullptr; | ||
if (use_string_lookup) { |
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.
I think we dont need to introduce handle just yet.
Shall we just merged to a single if/else down ? -- so its clear what happens when string-based function lookup is not used.
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.
done!
src/target/llvm/codegen_llvm.cc
Outdated
if (auto* ptr_op = op->op.as<OpNode>()) { | ||
auto call_op = GetRef<Op>(ptr_op); | ||
if (op->op.same_as(builtin_call_extern_) || op->op.same_as(builtin_call_pure_extern_)) { | ||
if (op->op.same_as(builtin_lookup_param_)) { | ||
// return llvm::ConstantInt::get(t_void_p_, 0); |
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.
remove
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.
done
@@ -389,6 +406,16 @@ class CodeGenLLVM : public ExprFunctor<llvm::Value*(const PrimExpr&)>, | |||
unsigned int shared_address_space, int alignment, | |||
llvm::GlobalValue::LinkageTypes linkage); | |||
|
|||
llvm::Argument* GetArg(const llvm::Function* function, int i) const { |
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.
Should we add docs for this ?
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.
done
src/target/llvm/llvm_module.cc
Outdated
// std::string tmp; | ||
// llvm::raw_string_ostream stream(tmp); | ||
// mod->print(stream, nullptr); | ||
// LOG(INFO) << "LLVM metadata IR: " << stream.str(); |
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.
remove
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.
done
src/target/metadata_module.cc
Outdated
@@ -144,6 +144,12 @@ static runtime::Module CreateCppMetadataModule( | |||
auto metadata_module = CreateCSourceCppMetadataModule(runtime_metadata); | |||
metadata_module->Import(target_module); | |||
target_module = metadata_module; | |||
#ifdef TVM_LLVM_VERSION |
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.
Why this Ifdef ?
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.
indicates USE_LLVM is ON. added a comment.
* \file tvm/target/metadata_utils.cc | ||
* \brief Defines utility functions and classes for emitting metadata. | ||
*/ | ||
#include "metadata_utils.h" |
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.
Please add docs for all the functions introduced here.
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.
done (let me know if more are needed)
* this is necessary to allow CodeGenCPU to emit calls that include resource_handle.
* previously I believe we required interface_api == "c", but this really means to generate C API bindings, and we are generating "packed" bindings. * I think "c" was chosen here because the distinction between interface-api and use-unpacked-api is confusing. "c" interface-api means to generate an entrypoint API for microcontrollers that accepts bare data buffers. "packed" interface-api means to generate a TVMBackendPackedCFunc entrypoint. use-unpacked-api forms the same determination for the operator functions. * A further confusion here is that there are two ways to call "packed" operator functions: tir.tvm_builtin_call_packed and tir.tvm_builtin_call_cpacked. This distinction describes whether or not to late-bind calls via TVMBackendGetFuncFromEnv. Right now, AOT only ever requires call_cpacked because target_host == target, and for all suitable target_host, we expect a single DSO-exportable runtime.Module. When we move away from this by introducing heterogeneous target support to AOT, we can use this as a condition to help us choose between call_cpacked and call_packed (and possibly add a compile-time option to assert it is call_cpacked, for situations where we really don't want call_packed).
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.
@manupa-arm thanks for the review! i'm still working on fixing up the unit tests (the test_tir_usmp_transform_convert_pool_allocations_to_offsets needs updating but I don't quite understand how to do this with preflattened_buffer_map--will confer with @Lunderberg tomorrow).
would appreciate a second round of comments when you get a minute!
* \param num the number to convert | ||
* \return PrimExpr representing num | ||
*/ | ||
inline PrimExpr ConstInt32(int32_t num) { |
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.
changed to use tir::make_const
, which i think handles it
return tir::Evaluate(tir::Call(DataType::Int(32), tvm::tir::builtin::call_extern(), | ||
{tvm::tir::StringImm(device_hook), context})); | ||
} | ||
} // namespace |
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.
to make this a "static" function aka it cannot be linked against from elsewhere
} | ||
} // namespace | ||
|
||
class AOTCallGenerator { |
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.
good point--this is cruft from the old approach, before I started relying on LegalizePackedCalls/LowerTVMBuiltin, so can remove it now :)
tir::Stmt body = tir::SeqStmt::Flatten(prep_stmts_, call_stmts); | ||
|
||
for (auto bind : let_binds_) { | ||
body = tir::LetStmt(bind.first, bind.second, body); |
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.
yeah sorry, this part is cruft and should get deleted.
src/target/llvm/codegen_cpu.cc
Outdated
PackedCall pc; | ||
std::string func_name = args[0].as<StringImmNode>()->value; | ||
llvm::Value* handle = GetPackedFuncHandle(func_name); | ||
llvm::Value* handle = nullptr; | ||
if (use_string_lookup) { |
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.
done!
src/target/llvm/codegen_llvm.cc
Outdated
if (auto* ptr_op = op->op.as<OpNode>()) { | ||
auto call_op = GetRef<Op>(ptr_op); | ||
if (op->op.same_as(builtin_call_extern_) || op->op.same_as(builtin_call_pure_extern_)) { | ||
if (op->op.same_as(builtin_lookup_param_)) { | ||
// return llvm::ConstantInt::get(t_void_p_, 0); |
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.
done
@@ -389,6 +406,16 @@ class CodeGenLLVM : public ExprFunctor<llvm::Value*(const PrimExpr&)>, | |||
unsigned int shared_address_space, int alignment, | |||
llvm::GlobalValue::LinkageTypes linkage); | |||
|
|||
llvm::Argument* GetArg(const llvm::Function* function, int i) const { |
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.
done
src/target/llvm/llvm_module.cc
Outdated
// std::string tmp; | ||
// llvm::raw_string_ostream stream(tmp); | ||
// mod->print(stream, nullptr); | ||
// LOG(INFO) << "LLVM metadata IR: " << stream.str(); |
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.
done
src/target/metadata_module.cc
Outdated
@@ -144,6 +144,12 @@ static runtime::Module CreateCppMetadataModule( | |||
auto metadata_module = CreateCSourceCppMetadataModule(runtime_metadata); | |||
metadata_module->Import(target_module); | |||
target_module = metadata_module; | |||
#ifdef TVM_LLVM_VERSION |
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.
indicates USE_LLVM is ON. added a comment.
* \file tvm/target/metadata_utils.cc | ||
* \brief Defines utility functions and classes for emitting metadata. | ||
*/ | ||
#include "metadata_utils.h" |
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.
done (let me know if more are needed)
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.
Hi @areusch,
I had a quick look over this, I've mostly identified areas where it'd be good to add some additional tests (especially the TIR script bit) - though I've avoided areas which aren't as well setup for testing. Other than that, it looks fine move forwards given the other reviews caught everything else 😸
const char* get_c_struct_name() const final; | ||
|
||
std::string get_element_c_struct_name() const { | ||
CHECK(kind == MetadataKind::kMetadata) |
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.
Can you add an ASSERT_THROWS
test for this?
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.
done
src/target/llvm/codegen_llvm.h
Outdated
auto a = VisitExpr(e); | ||
return a; |
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.
Either be explicit with the type or directly return the value from VisitExpr
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.
oops, leftover from logging. fixed!
if data is None: | ||
data = self.context.func_buffer_map[param].data | ||
|
||
buffer_name: str = f"{postflattened.name}_preflatten" | ||
if align != -1: | ||
if isinstance(align, IntImm): | ||
align = align.value | ||
else: | ||
assert isinstance(align, int), f"align: want int or IntImm, got {align!r}" | ||
|
||
if offset_factor != 0: | ||
if isinstance(offset_factor, IntImm): | ||
offset_factor = offset_factor.value | ||
else: | ||
assert isinstance( | ||
offset_factor, int | ||
), f"offset_factor: want int or IntImm, got {offset_factor!r}" | ||
|
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.
Could we add some unit tests for these cases?
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.
done
src/target/metadata_utils.cc
Outdated
|
||
DiscoverArraysVisitor::DiscoverArraysVisitor(std::vector<DiscoveredArray>* queue) : queue_{queue} {} | ||
|
||
std::string address_from_parts(const std::vector<std::string>& parts) { |
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.
Should this be AddressFromParts
to match the coding conventions?
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.
Also, should this be in the middle of the DiscoverArraysVisitor
definitions?
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.
good catch, fixed both
src/target/metadata_utils.cc
Outdated
void DiscoverArraysVisitor::Visit(const char* key, ObjectRef* value) { | ||
address_parts_.push_back(key); | ||
if (value->as<runtime::metadata::MetadataBaseNode>() != nullptr) { | ||
auto metadata = Downcast<runtime::metadata::MetadataBase>(*value); | ||
const runtime::metadata::MetadataArrayNode* arr = | ||
value->as<runtime::metadata::MetadataArrayNode>(); | ||
if (arr != nullptr) { | ||
for (unsigned int i = 0; i < arr->array.size(); i++) { | ||
ObjectRef o = arr->array[i]; | ||
if (o.as<runtime::metadata::MetadataBaseNode>() != nullptr) { | ||
std::stringstream ss; | ||
ss << i; | ||
address_parts_.push_back(ss.str()); | ||
runtime::metadata::MetadataBase metadata = Downcast<runtime::metadata::MetadataBase>(o); | ||
ReflectionVTable::Global()->VisitAttrs(metadata.operator->(), this); | ||
address_parts_.pop_back(); | ||
} | ||
} | ||
|
||
queue_->push_back(std::make_tuple(address_from_parts(address_parts_), | ||
Downcast<runtime::metadata::MetadataArray>(metadata))); | ||
} else { | ||
ReflectionVTable::Global()->VisitAttrs(metadata.operator->(), this); | ||
} | ||
} | ||
address_parts_.pop_back(); | ||
} |
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.
Is it possible to add some testing for these visitors (DiscoverComplexTypesVisitor
and DiscoverArraysVisitor
) whilst we're creating this file afresh?
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.
done
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.
thanks for the round of comments @Mousius! would appreciate another look here
const char* get_c_struct_name() const final; | ||
|
||
std::string get_element_c_struct_name() const { | ||
CHECK(kind == MetadataKind::kMetadata) |
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.
done
src/target/metadata_utils.cc
Outdated
void DiscoverArraysVisitor::Visit(const char* key, ObjectRef* value) { | ||
address_parts_.push_back(key); | ||
if (value->as<runtime::metadata::MetadataBaseNode>() != nullptr) { | ||
auto metadata = Downcast<runtime::metadata::MetadataBase>(*value); | ||
const runtime::metadata::MetadataArrayNode* arr = | ||
value->as<runtime::metadata::MetadataArrayNode>(); | ||
if (arr != nullptr) { | ||
for (unsigned int i = 0; i < arr->array.size(); i++) { | ||
ObjectRef o = arr->array[i]; | ||
if (o.as<runtime::metadata::MetadataBaseNode>() != nullptr) { | ||
std::stringstream ss; | ||
ss << i; | ||
address_parts_.push_back(ss.str()); | ||
runtime::metadata::MetadataBase metadata = Downcast<runtime::metadata::MetadataBase>(o); | ||
ReflectionVTable::Global()->VisitAttrs(metadata.operator->(), this); | ||
address_parts_.pop_back(); | ||
} | ||
} | ||
|
||
queue_->push_back(std::make_tuple(address_from_parts(address_parts_), | ||
Downcast<runtime::metadata::MetadataArray>(metadata))); | ||
} else { | ||
ReflectionVTable::Global()->VisitAttrs(metadata.operator->(), this); | ||
} | ||
} | ||
address_parts_.pop_back(); | ||
} |
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.
done
if data is None: | ||
data = self.context.func_buffer_map[param].data | ||
|
||
buffer_name: str = f"{postflattened.name}_preflatten" | ||
if align != -1: | ||
if isinstance(align, IntImm): | ||
align = align.value | ||
else: | ||
assert isinstance(align, int), f"align: want int or IntImm, got {align!r}" | ||
|
||
if offset_factor != 0: | ||
if isinstance(offset_factor, IntImm): | ||
offset_factor = offset_factor.value | ||
else: | ||
assert isinstance( | ||
offset_factor, int | ||
), f"offset_factor: want int or IntImm, got {offset_factor!r}" | ||
|
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.
done
src/target/llvm/codegen_llvm.h
Outdated
auto a = VisitExpr(e); | ||
return a; |
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.
oops, leftover from logging. fixed!
src/target/metadata_utils.cc
Outdated
|
||
DiscoverArraysVisitor::DiscoverArraysVisitor(std::vector<DiscoveredArray>* queue) : queue_{queue} {} | ||
|
||
std::string address_from_parts(const std::vector<std::string>& parts) { |
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.
good catch, fixed both
oops, it seems we ran into some kind of CI bug :( i don't think PR will start testing til it's merged, unfortunately will need a review on #11007 before we can retest this one. Nevertheless, it's ready for another look. |
also, did push this #11007 on top of this PR to exercise the fix, you can see it here: https://ci.tlcpack.ai/blue/organizations/jenkins/tvm/detail/areusch-test-jenkinsfile-merge-fix/3/pipeline/ |
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.
LGTM once CI passes 😸
src/target/llvm/codegen_llvm.h
Outdated
@@ -481,6 +518,8 @@ void CodeGenLLVM::AddFunctionsOrdered(IterType begin, IterType end, ConvType pfu | |||
return name_a < name_b; | |||
}); | |||
for (auto& f : funcs) { | |||
auto global_symbol = f->GetAttr<String>(tvm::attr::kGlobalSymbol); | |||
LOG(INFO) << "Adding " << static_cast<std::string>(global_symbol.value()); |
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.
Please remove this diff, I see codegen_llvm.h:522: Adding ...
all over the place in the log https://ci.tlcpack.ai/blue/organizations/jenkins/tvm/detail/PR-10753/19/pipeline
Sorry I remember I added this one
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.
done!
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.
sorry can you also remove auto global_symbol = f->GetAttr<String>(tvm::attr::kGlobalSymbol);
change since global_symbol
is not used
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.
We can address this in a follow-up
* add get_c_struct_name() method to Metadata to distinguish struct type name in llvm * add metadata serialization support to llvm codegen * Organize MetadataQueuer into a separate file. * Add DiscoverArraysVisitor to metadata_utils * Fill DLTensor metadata in LegalizePackedCalls. * Improve error message from Call asserts * Pass non-String device_context down to codegen. * this is necessary to allow CodeGenCPU to emit calls that include resource_handle. * Scope usage of lvalue refs in LowerTVMBuiltin to avoid corrupt memory. * test fixes * Also fill preflattened_buffer_map (TODO, maybe don't do this) * Fix C codegen. * Set USMP elem_offset to 0. * Clarify calculation of byte_offset from elem_offset. * fix tests * Fix arm compile warning * Fix hexagon test. * previously I believe we required interface_api == "c", but this really means to generate C API bindings, and we are generating "packed" bindings. * I think "c" was chosen here because the distinction between interface-api and use-unpacked-api is confusing. "c" interface-api means to generate an entrypoint API for microcontrollers that accepts bare data buffers. "packed" interface-api means to generate a TVMBackendPackedCFunc entrypoint. use-unpacked-api forms the same determination for the operator functions. * A further confusion here is that there are two ways to call "packed" operator functions: tir.tvm_builtin_call_packed and tir.tvm_builtin_call_cpacked. This distinction describes whether or not to late-bind calls via TVMBackendGetFuncFromEnv. Right now, AOT only ever requires call_cpacked because target_host == target, and for all suitable target_host, we expect a single DSO-exportable runtime.Module. When we move away from this by introducing heterogeneous target support to AOT, we can use this as a condition to help us choose between call_cpacked and call_packed (and possibly add a compile-time option to assert it is call_cpacked, for situations where we really don't want call_packed). * Document T.preflattened_buffer * Fix test_aot_legalize_packed_calls * Address manupa comments * Fix convert_pool_allocations_to_offsets test. * lint * Fix T.preflattened_buffer * Add preflattened_buffer_map to TIRTextPrinter * Fix tests * Fix BYOC * Fix invoking C device API. * remove comments * Address Mousius comments * lint * lint * Fix GMock linking on new CMake * address masahi comment Co-authored-by: Masahiro Masuda <masahi129@gmail.com>
* add get_c_struct_name() method to Metadata to distinguish struct type name in llvm * add metadata serialization support to llvm codegen * Organize MetadataQueuer into a separate file. * Add DiscoverArraysVisitor to metadata_utils * Fill DLTensor metadata in LegalizePackedCalls. * Improve error message from Call asserts * Pass non-String device_context down to codegen. * this is necessary to allow CodeGenCPU to emit calls that include resource_handle. * Scope usage of lvalue refs in LowerTVMBuiltin to avoid corrupt memory. * test fixes * Also fill preflattened_buffer_map (TODO, maybe don't do this) * Fix C codegen. * Set USMP elem_offset to 0. * Clarify calculation of byte_offset from elem_offset. * fix tests * Fix arm compile warning * Fix hexagon test. * previously I believe we required interface_api == "c", but this really means to generate C API bindings, and we are generating "packed" bindings. * I think "c" was chosen here because the distinction between interface-api and use-unpacked-api is confusing. "c" interface-api means to generate an entrypoint API for microcontrollers that accepts bare data buffers. "packed" interface-api means to generate a TVMBackendPackedCFunc entrypoint. use-unpacked-api forms the same determination for the operator functions. * A further confusion here is that there are two ways to call "packed" operator functions: tir.tvm_builtin_call_packed and tir.tvm_builtin_call_cpacked. This distinction describes whether or not to late-bind calls via TVMBackendGetFuncFromEnv. Right now, AOT only ever requires call_cpacked because target_host == target, and for all suitable target_host, we expect a single DSO-exportable runtime.Module. When we move away from this by introducing heterogeneous target support to AOT, we can use this as a condition to help us choose between call_cpacked and call_packed (and possibly add a compile-time option to assert it is call_cpacked, for situations where we really don't want call_packed). * Document T.preflattened_buffer * Fix test_aot_legalize_packed_calls * Address manupa comments * Fix convert_pool_allocations_to_offsets test. * lint * Fix T.preflattened_buffer * Add preflattened_buffer_map to TIRTextPrinter * Fix tests * Fix BYOC * Fix invoking C device API. * remove comments * Address Mousius comments * lint * lint * Fix GMock linking on new CMake * address masahi comment Co-authored-by: Masahiro Masuda <masahi129@gmail.com>
This PR adds support for using the LLVM backend under the C++ runtime. Additional work is needed to support LLVM under the C runtime for microTVM uses.
#10280