blob: c39a37477cfd86c7497159936e9e4a2c9e3c0fbe [file] [log] [blame]
Geoffrey Martin-Noble552d3f82021-05-25 17:56:09 -07001// Copyright 2019 The IREE Authors
powderluv2e2fc9c2019-10-23 10:09:44 -07002//
Geoffrey Martin-Noble552d3f82021-05-25 17:56:09 -07003// Licensed under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
powderluv2e2fc9c2019-10-23 10:09:44 -07006
Stella Laurenzo3b44a0a2022-04-18 19:57:57 -07007#include "./vm.h"
powderluv2e2fc9c2019-10-23 10:09:44 -07008
Stella Laurenzo3b44a0a2022-04-18 19:57:57 -07009#include "./status_utils.h"
Stella Laurenzodc513de2019-12-19 10:19:57 -080010#include "iree/base/api.h"
Stella Laurenzo7b066572022-07-31 18:38:15 -070011// TODO: We shouldn't need the HAL API but it is used for direct printing
12// summaries of HAL objects in lists. We should have a better way of doing this
13// dynamically vs hard depending on a type switch here.
Ben Vanik6ada2932021-06-21 09:09:32 -070014#include "iree/modules/hal/module.h"
Eugene Zhulenev6f81ceb2023-05-16 19:23:26 -070015#include "iree/tooling/modules/resolver.h"
Ben Vanikc3a13e62020-11-16 01:54:22 -080016#include "iree/vm/api.h"
Stella Laurenzoaeaaad62021-05-03 13:44:52 -070017#include "pybind11/numpy.h"
powderluv2e2fc9c2019-10-23 10:09:44 -070018
19namespace iree {
20namespace python {
21
Stella Laurenzoedc8a982019-12-20 09:22:37 -080022namespace {
23
Stella Laurenzoaeaaad62021-05-03 13:44:52 -070024// RAII wrapper for a Py_buffer which calls PyBuffer_Release when it goes
25// out of scope.
26class PyBufferReleaser {
27 public:
28 PyBufferReleaser(Py_buffer& b) : b_(b) {}
29 ~PyBufferReleaser() { PyBuffer_Release(&b_); }
30
31 private:
32 Py_buffer& b_;
33};
34
35py::dict GetFunctionReflectionDict(iree_vm_function_t& f) {
36 py::dict attrs;
Ben Vanik1d60c182022-06-28 12:37:40 -070037 for (iree_host_size_t i = 0;; ++i) {
38 iree_string_pair_t attr;
39 auto status = iree_vm_function_get_attr(f, i, &attr);
40 if (iree_status_is_out_of_range(status)) {
Stella Laurenzoaeaaad62021-05-03 13:44:52 -070041 iree_status_ignore(status);
42 break;
43 }
44 CheckApiStatus(status, "Error getting reflection attr");
Ben Vanik1d60c182022-06-28 12:37:40 -070045 py::str key_str(attr.key.data, attr.key.size);
46 py::str value_str(attr.value.data, attr.value.size);
Stella Laurenzoaeaaad62021-05-03 13:44:52 -070047 attrs[std::move(key_str)] = std::move(value_str);
48 }
49 return attrs;
50}
51
Stella Laurenzoedc8a982019-12-20 09:22:37 -080052} // namespace
53
Stella Laurenzodc513de2019-12-19 10:19:57 -080054//------------------------------------------------------------------------------
55// VmInstance
56//------------------------------------------------------------------------------
57
58VmInstance VmInstance::Create() {
Ben Vanikcc436802023-06-10 08:53:52 -070059 IREE_TRACE_SCOPE_NAMED("VmInstance::Create");
Ben Vanik9aa83ed2022-08-06 12:55:34 -070060
61 iree_vm_instance_t* instance = NULL;
Ben Vanik09630d62023-04-13 14:21:40 -070062 auto status = iree_vm_instance_create(IREE_VM_TYPE_CAPACITY_DEFAULT,
63 iree_allocator_system(), &instance);
Stella Laurenzodc513de2019-12-19 10:19:57 -080064 CheckApiStatus(status, "Error creating instance");
Ben Vanik9aa83ed2022-08-06 12:55:34 -070065
66 // The python bindings assume the HAL is always available for use.
67 // We register the types here so modules can be loaded using the HAL types
68 // in any order.
69 CheckApiStatus(iree_hal_module_register_all_types(instance),
70 "registering HAL types");
71
Stella Laurenzo65690a12022-01-31 12:43:00 -080072 return VmInstance::StealFromRawPtr(instance);
Stella Laurenzodc513de2019-12-19 10:19:57 -080073}
74
75//------------------------------------------------------------------------------
76// VmContext
77//------------------------------------------------------------------------------
78
79VmContext VmContext::Create(VmInstance* instance,
Ben Vanikdf89eb02021-06-20 18:01:16 -070080 std::optional<std::vector<VmModule*>> modules) {
Ben Vanikcc436802023-06-10 08:53:52 -070081 IREE_TRACE_SCOPE_NAMED("VmContext::Create");
Stella Laurenzodc513de2019-12-19 10:19:57 -080082 iree_vm_context_t* context;
83 if (!modules) {
84 // Simple create with open allowed modules.
Ben Vanik89e95302021-10-05 17:05:39 -070085 auto status =
86 iree_vm_context_create(instance->raw_ptr(), IREE_VM_CONTEXT_FLAG_NONE,
87 iree_allocator_system(), &context);
Stella Laurenzodc513de2019-12-19 10:19:57 -080088 CheckApiStatus(status, "Error creating vm context");
89 } else {
90 // Closed set of modules.
Ben Vanikb9b794b2021-06-19 20:11:08 -070091 std::vector<iree_vm_module_t*> module_handles;
Stella Laurenzodc513de2019-12-19 10:19:57 -080092 module_handles.resize(modules->size());
93 for (size_t i = 0, e = module_handles.size(); i < e; ++i) {
94 module_handles[i] = (*modules)[i]->raw_ptr();
95 }
96 auto status = iree_vm_context_create_with_modules(
Ben Vanik70c2bb02022-06-09 12:42:54 -070097 instance->raw_ptr(), IREE_VM_CONTEXT_FLAG_NONE, module_handles.size(),
98 module_handles.data(), iree_allocator_system(), &context);
Stella Laurenzodc513de2019-12-19 10:19:57 -080099 CheckApiStatus(status, "Error creating vm context with modules");
100 }
101
Ben Vanik91c75fb2022-06-23 19:08:12 -0700102 IREE_ASSERT(context);
Stella Laurenzo65690a12022-01-31 12:43:00 -0800103 return VmContext::StealFromRawPtr(context);
Stella Laurenzodc513de2019-12-19 10:19:57 -0800104}
105
106void VmContext::RegisterModules(std::vector<VmModule*> modules) {
Ben Vanikb9b794b2021-06-19 20:11:08 -0700107 std::vector<iree_vm_module_t*> module_handles;
Stella Laurenzodc513de2019-12-19 10:19:57 -0800108 module_handles.resize(modules.size());
109 for (size_t i = 0, e = module_handles.size(); i < e; ++i) {
110 module_handles[i] = modules[i]->raw_ptr();
111 }
Ben Vanik70c2bb02022-06-09 12:42:54 -0700112 auto status = iree_vm_context_register_modules(
113 raw_ptr(), module_handles.size(), &module_handles[0]);
Stella Laurenzodc513de2019-12-19 10:19:57 -0800114 CheckApiStatus(status, "Error registering modules");
115}
116
Stella Laurenzod5efc482019-12-21 04:59:36 -0800117void VmContext::Invoke(iree_vm_function_t f, VmVariantList& inputs,
118 VmVariantList& outputs) {
Stella Laurenzod2009dc2022-03-08 17:59:40 -0800119 iree_status_t status;
120 {
121 py::gil_scoped_release release;
122 status = iree_vm_invoke(raw_ptr(), f, IREE_VM_INVOCATION_FLAG_NONE, nullptr,
123 inputs.raw_ptr(), outputs.raw_ptr(),
124 iree_allocator_system());
125 }
126 CheckApiStatus(status, "Error invoking function");
Stella Laurenzod5efc482019-12-21 04:59:36 -0800127}
128
Stella Laurenzodc513de2019-12-19 10:19:57 -0800129//------------------------------------------------------------------------------
130// VmModule
131//------------------------------------------------------------------------------
132
Eugene Zhulenev6f81ceb2023-05-16 19:23:26 -0700133VmModule VmModule::ResolveModuleDependency(VmInstance* instance,
134 const std::string& name,
135 uint32_t minimum_version) {
Ben Vanikcc436802023-06-10 08:53:52 -0700136 IREE_TRACE_SCOPE_NAMED("VmModule::ResolveModuleDependency");
Eugene Zhulenev6f81ceb2023-05-16 19:23:26 -0700137 iree_vm_module_t* module = nullptr;
138
139 iree_vm_module_dependency_t dependency = {
140 iree_make_cstring_view(name.c_str()), minimum_version,
141 IREE_VM_MODULE_DEPENDENCY_FLAG_REQUIRED};
142
143 auto status = iree_tooling_resolve_module_dependency(
144 instance->raw_ptr(), &dependency, iree_allocator_system(), &module);
145
146 assert(module != nullptr);
147
148 CheckApiStatus(status, "Error resolving module dependency");
149 auto py_module = VmModule::StealFromRawPtr(module);
150 return py_module;
151}
152
Stella Laurenzo3345b762023-06-15 00:22:24 -0700153VmModule VmModule::MMap(VmInstance* instance, std::string filepath) {
154 IREE_TRACE_SCOPE_NAMED("VmModule::MMap");
155 auto mmap_module = py::module::import("mmap");
156 auto open_func = py::module::import("io").attr("open");
157 auto file_obj = open_func(filepath, "r+b");
158 auto flags = py::cast<int64_t>(mmap_module.attr("MAP_SHARED"));
159 // MAP_POPULATE isn't available on all versions/platforms.
160 if (py::hasattr(mmap_module, "MAP_POPULATE")) {
161 flags |= py::cast<int64_t>(mmap_module.attr("MAP_POPULATE"));
162 }
163 auto prot = py::cast<int64_t>(mmap_module.attr("PROT_READ"));
164 auto mapped_file =
165 mmap_module.attr("mmap")(file_obj.attr("fileno")(), 0, flags, prot);
166 mapped_file.attr("madvise")(mmap_module.attr("MADV_RANDOM"));
167 return FromFlatbufferBlob(instance, mapped_file);
168}
169
Ben Vanik9aa83ed2022-08-06 12:55:34 -0700170VmModule VmModule::FromFlatbufferBlob(VmInstance* instance,
171 py::object flatbuffer_blob_object) {
Ben Vanikcc436802023-06-10 08:53:52 -0700172 IREE_TRACE_SCOPE_NAMED("VmModule::FromFlatbufferBlob");
Stella Laurenzo73045212021-06-25 16:18:57 -0700173 auto flatbuffer_blob = py::cast<py::buffer>(flatbuffer_blob_object);
Stella Laurenzoe2b0d7f2020-01-06 13:14:40 -0800174 auto buffer_info = flatbuffer_blob.request();
Ben Vanik9aa83ed2022-08-06 12:55:34 -0700175 iree_vm_module_t* module = nullptr;
Stella Laurenzoe2b0d7f2020-01-06 13:14:40 -0800176
177 // Bridge to the C-based deallocator API.
Kojo Acquahc1d499e2023-05-25 07:01:25 -0700178 PyObject* pyobject_ptr = flatbuffer_blob_object.ptr();
Ben Vanik5ca3e182021-07-12 07:46:23 -0700179 auto ctl_fn = +([](void* self, iree_allocator_command_t command,
180 const void* params, void** inout_ptr) {
181 assert(command == IREE_ALLOCATOR_COMMAND_FREE);
Kojo Acquahc1d499e2023-05-25 07:01:25 -0700182 PyObject* pyobject_ptr = static_cast<PyObject*>(self);
183 Py_XDECREF(pyobject_ptr);
Ben Vanik5ca3e182021-07-12 07:46:23 -0700184 return iree_ok_status();
Stella Laurenzoe2b0d7f2020-01-06 13:14:40 -0800185 });
Kojo Acquahc1d499e2023-05-25 07:01:25 -0700186 Py_XINCREF(pyobject_ptr);
187 iree_allocator_t deallocator{/*self=*/pyobject_ptr, /*ctl=*/ctl_fn};
Stella Laurenzoe2b0d7f2020-01-06 13:14:40 -0800188
Stella Laurenzodc513de2019-12-19 10:19:57 -0800189 auto status = iree_vm_bytecode_module_create(
Ben Vanik9aa83ed2022-08-06 12:55:34 -0700190 instance->raw_ptr(),
Stella Laurenzoe2b0d7f2020-01-06 13:14:40 -0800191 {static_cast<const uint8_t*>(buffer_info.ptr),
192 static_cast<iree_host_size_t>(buffer_info.size)},
Ben Vanikf5bd6fd2020-08-05 21:14:57 -0700193 deallocator, iree_allocator_system(), &module);
Ben Vanikaf5401f2020-08-06 21:31:15 -0700194 if (!iree_status_is_ok(status)) {
Kojo Acquahc1d499e2023-05-25 07:01:25 -0700195 Py_XDECREF(pyobject_ptr);
Stella Laurenzodc513de2019-12-19 10:19:57 -0800196 }
197
Ben Vanik9a50ab12022-05-26 14:20:59 -0700198 CheckApiStatus(status, "Error creating vm module from FlatBuffer");
Stella Laurenzo65690a12022-01-31 12:43:00 -0800199 auto py_module = VmModule::StealFromRawPtr(module);
Stella Laurenzo73045212021-06-25 16:18:57 -0700200 py_module.stashed_flatbuffer_blob = flatbuffer_blob_object;
201 return py_module;
Stella Laurenzodc513de2019-12-19 10:19:57 -0800202}
203
Ben Vanikdf89eb02021-06-20 18:01:16 -0700204std::optional<iree_vm_function_t> VmModule::LookupFunction(
Stella Laurenzodc513de2019-12-19 10:19:57 -0800205 const std::string& name, iree_vm_function_linkage_t linkage) {
206 iree_vm_function_t f;
Ben Vanikfcd368b2019-12-20 10:55:37 -0800207 auto status = iree_vm_module_lookup_function_by_name(
Scott Todd60b07642023-06-15 09:41:01 -0700208 raw_ptr(), linkage,
209 {name.data(), static_cast<iree_host_size_t>(name.size())}, &f);
Ben Vanikaf5401f2020-08-06 21:31:15 -0700210 if (iree_status_is_not_found(status)) {
211 iree_status_ignore(status);
Ben Vanikdf89eb02021-06-20 18:01:16 -0700212 return std::nullopt;
Stella Laurenzodc513de2019-12-19 10:19:57 -0800213 }
214 CheckApiStatus(status, "Error looking up function");
215 return f;
216}
217
Stella Laurenzo480e6ef2019-12-23 10:07:52 -0800218//------------------------------------------------------------------------------
Stella Laurenzo95dff502022-07-31 14:16:12 -0700219// VmRef
220//------------------------------------------------------------------------------
221
222const char* const VmRef::kRefAttr = "__iree_vm_ref__";
223const char* const VmRef::kCastAttr = "__iree_vm_cast__";
Ben Vanik09630d62023-04-13 14:21:40 -0700224const char* const VmRef::kTypeAttr = "__iree_vm_type__";
Stella Laurenzo95dff502022-07-31 14:16:12 -0700225
Stella Laurenzo7b066572022-07-31 18:38:15 -0700226py::object VmRef::Deref(py::object ref_object_class, bool optional) {
227 py::object casted = ref_object_class.attr(kCastAttr)(*this);
228 if (!optional && casted.is_none()) {
229 throw py::type_error("Cannot dereference to specific type");
230 }
231 return casted;
Stella Laurenzo95dff502022-07-31 14:16:12 -0700232}
233
234bool VmRef::IsInstance(py::object ref_object_class) {
Ben Vanik09630d62023-04-13 14:21:40 -0700235 auto type = py::cast<iree_vm_ref_type_t>(ref_object_class.attr(kTypeAttr)());
236 return type == ref_.type;
Stella Laurenzo95dff502022-07-31 14:16:12 -0700237}
238
239std::string VmRef::ToString() {
240 if (!ref_.ptr) {
241 return "<VmRef NULL>";
242 }
243 iree_string_view_t type_name = iree_vm_ref_type_name(ref_.type);
244 std::stringstream ss;
245 ss << "<VmRef ";
246 ss.write(type_name.data, type_name.size);
247 ss << " at " << std::hex << "0x" << reinterpret_cast<uintptr_t>(ref_.ptr)
248 << ">";
249 return ss.str();
250}
251
252//------------------------------------------------------------------------------
Stella Laurenzo480e6ef2019-12-23 10:07:52 -0800253// VmVariantList
254//------------------------------------------------------------------------------
255
Stella Laurenzo99956042021-05-14 10:32:38 -0700256void VmVariantList::PushFloat(double fvalue) {
257 // Note that Python floats are f64.
258 iree_vm_value_t value = iree_vm_value_make_f64(fvalue);
259 CheckApiStatus(iree_vm_list_push_value(raw_ptr(), &value),
260 "Could not push float");
261}
262
263void VmVariantList::PushInt(int64_t ivalue) {
264 // Note that Python ints are unbounded, so just use the largest type we
265 // have.
266 iree_vm_value_t value = iree_vm_value_make_i64(ivalue);
267 CheckApiStatus(iree_vm_list_push_value(raw_ptr(), &value),
268 "Could not push int");
269}
270
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700271void VmVariantList::PushList(VmVariantList& other) {
272 iree_vm_ref_t retained = iree_vm_list_retain_ref(other.raw_ptr());
273 iree_vm_list_push_ref_move(raw_ptr(), &retained);
274}
275
Stella Laurenzo7b066572022-07-31 18:38:15 -0700276void VmVariantList::PushRef(py::handle ref_or_object) {
277 py::object py_ref = ref_or_object.attr(VmRef::kRefAttr);
278 VmRef& ref = py::cast<VmRef&>(py_ref);
279 CheckApiStatus(iree_vm_list_push_ref_retain(raw_ptr(), &ref.ref()),
280 "Failed to push ref");
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700281}
282
Stella Laurenzo99956042021-05-14 10:32:38 -0700283py::object VmVariantList::GetAsList(int index) {
Stella Laurenzo5ba8a7a2021-05-11 21:29:23 -0700284 iree_vm_ref_t ref = {0};
285 CheckApiStatus(iree_vm_list_get_ref_assign(raw_ptr(), index, &ref),
286 "Could not access list element");
287 iree_vm_list_t* sub_list = NULL;
288 CheckApiStatus(iree_vm_list_check_deref(ref, &sub_list),
289 "Could not deref list (wrong type?)");
290 iree_vm_list_retain(sub_list);
Stella Laurenzo95dff502022-07-31 14:16:12 -0700291 return py::cast(VmVariantList::StealFromRawPtr(sub_list));
Stella Laurenzo99956042021-05-14 10:32:38 -0700292}
293
294py::object VmVariantList::GetVariant(int index) {
295 iree_vm_variant_t v = iree_vm_variant_empty();
Ben Vanik78fc0e32023-03-06 16:20:08 -0800296 CheckApiStatus(iree_vm_list_get_variant_assign(raw_ptr(), index, &v),
Stella Laurenzo99956042021-05-14 10:32:38 -0700297 "Could not access list element");
Ben Vanik09630d62023-04-13 14:21:40 -0700298 if (iree_vm_variant_is_empty(v)) {
299 return py::none();
300 } else if (iree_vm_variant_is_value(v)) {
Stella Laurenzo99956042021-05-14 10:32:38 -0700301 // Convert a value type.
Ben Vanik09630d62023-04-13 14:21:40 -0700302 switch (iree_vm_type_def_as_value(v.type)) {
Stella Laurenzo99956042021-05-14 10:32:38 -0700303 case IREE_VM_VALUE_TYPE_I8:
304 return py::cast(v.i8);
305 case IREE_VM_VALUE_TYPE_I16:
306 return py::cast(v.i16);
307 case IREE_VM_VALUE_TYPE_I32:
308 return py::cast(v.i32);
309 case IREE_VM_VALUE_TYPE_I64:
310 return py::cast(v.i64);
311 case IREE_VM_VALUE_TYPE_F32:
312 return py::cast(v.f32);
313 case IREE_VM_VALUE_TYPE_F64:
314 return py::cast(v.f64);
315 default:
316 throw RaiseValueError("Unsupported VM value type conversion");
317 }
Stella Laurenzo7b066572022-07-31 18:38:15 -0700318 } else if (iree_vm_variant_is_ref(v)) {
319 VmRef ref;
320 iree_vm_ref_retain(&v.ref, &ref.ref());
321 return py::cast(ref, py::return_value_policy::move);
Stella Laurenzo99956042021-05-14 10:32:38 -0700322 }
323
324 throw RaiseValueError("Unsupported VM to Python Type Conversion");
Stella Laurenzo5ba8a7a2021-05-11 21:29:23 -0700325}
326
Stella Laurenzo73045212021-06-25 16:18:57 -0700327py::object VmVariantList::GetAsSerializedTraceValue(int index) {
328 iree_vm_variant_t v = iree_vm_variant_empty();
Ben Vanik78fc0e32023-03-06 16:20:08 -0800329 CheckApiStatus(iree_vm_list_get_variant_assign(raw_ptr(), index, &v),
Stella Laurenzo73045212021-06-25 16:18:57 -0700330 "Could not access list element");
Ben Vanik09630d62023-04-13 14:21:40 -0700331 if (iree_vm_variant_is_empty(v)) {
332 py::dict record;
333 record["type"] = "null";
334 return std::move(record);
335 } else if (iree_vm_variant_is_value(v)) {
Stella Laurenzo73045212021-06-25 16:18:57 -0700336 // Convert a value type.
337 py::dict record;
Ben Vanik09630d62023-04-13 14:21:40 -0700338 switch (iree_vm_type_def_as_value(v.type)) {
Stella Laurenzo73045212021-06-25 16:18:57 -0700339 case IREE_VM_VALUE_TYPE_I8:
340 record["i8"] = py::cast(v.i8);
341 break;
342 case IREE_VM_VALUE_TYPE_I16:
343 record["i16"] = py::cast(v.i16);
344 break;
345 case IREE_VM_VALUE_TYPE_I32:
346 record["i32"] = py::cast(v.i32);
347 break;
348 case IREE_VM_VALUE_TYPE_I64:
349 record["i64"] = py::cast(v.i64);
350 break;
351 case IREE_VM_VALUE_TYPE_F32:
352 record["f32"] = py::cast(v.f32);
353 break;
354 case IREE_VM_VALUE_TYPE_F64:
355 record["f64"] = py::cast(v.f64);
356 break;
357 default:
358 throw RaiseValueError("Unsupported VM value type conversion");
359 }
360 record["type"] = py::cast("value");
361 return std::move(record);
Ben Vanik09630d62023-04-13 14:21:40 -0700362 } else if (iree_vm_variant_is_ref(v)) {
Stella Laurenzo73045212021-06-25 16:18:57 -0700363 // Convert reference type.
364 if (iree_vm_list_isa(v.ref)) {
365 py::dict record;
Ben Vanikabe6c762021-06-27 21:57:07 -0700366 record["type"] = "vm.list";
Stella Laurenzo73045212021-06-25 16:18:57 -0700367 py::list items;
368 iree_vm_list_t* sub_list = NULL;
369 CheckApiStatus(iree_vm_list_check_deref(v.ref, &sub_list),
370 "Could not deref list (wrong type?)");
371 iree_vm_list_retain(sub_list);
Stella Laurenzo95dff502022-07-31 14:16:12 -0700372 VmVariantList sub_list_object = VmVariantList::StealFromRawPtr(sub_list);
Stella Laurenzo73045212021-06-25 16:18:57 -0700373 for (int i = 0, e = sub_list_object.size(); i < e; ++i) {
374 items.append(sub_list_object.GetAsSerializedTraceValue(i));
375 }
376 record["items"] = std::move(items);
377 return std::move(record);
378 } else if (iree_hal_buffer_view_isa(v.ref)) {
379 py::dict record;
Ben Vanikabe6c762021-06-27 21:57:07 -0700380 record["type"] = "hal.buffer_view";
Stella Laurenzo73045212021-06-25 16:18:57 -0700381 iree_hal_buffer_view_t* buffer_view = iree_hal_buffer_view_deref(v.ref);
382 if (!buffer_view) {
383 throw RaiseValueError(
384 "Could not deref result buffer view (wrong type?)");
385 }
386 iree_hal_buffer_t* raw_buffer = iree_hal_buffer_view_buffer(buffer_view);
387 if (!raw_buffer) {
388 throw RaiseValueError("Could not deref result buffer (wrong type?)");
389 }
390
391 // Extract dims from the buffer view.
Scott Todd60b07642023-06-15 09:41:01 -0700392 iree_host_size_t rank = 0;
Ben Vanik49fee302022-05-16 21:18:59 -0700393 std::vector<iree_hal_dim_t> dims(6);
Stella Laurenzo73045212021-06-25 16:18:57 -0700394 iree_status_t status = iree_hal_buffer_view_shape(
395 buffer_view, dims.capacity(), dims.data(), &rank);
396 if (iree_status_is_out_of_range(status)) {
397 dims.resize(rank);
398 status = iree_hal_buffer_view_shape(buffer_view, dims.capacity(),
399 dims.data(), &rank);
400 }
401 CheckApiStatus(status, "Error extracting shape");
402 dims.resize(rank);
403 record["shape"] = py::cast(std::move(dims));
404
405 // Element type.
406 iree_hal_element_type_t element_type =
407 iree_hal_buffer_view_element_type(buffer_view);
Ben Vanik40876b92023-03-06 11:26:53 -0800408 char element_type_str[64] = {0};
409 iree_host_size_t element_type_length = 0;
410 CheckApiStatus(
411 iree_hal_format_element_type(element_type, sizeof(element_type_str),
412 element_type_str, &element_type_length),
413 "Formatting element type");
414 record["element_type"] =
415 std::string(element_type_str, element_type_length);
Stella Laurenzo73045212021-06-25 16:18:57 -0700416
417 // Map memory.
418 iree_device_size_t byte_length = iree_hal_buffer_byte_length(raw_buffer);
Ben Vanikeff1bb52021-12-16 11:04:21 -0800419 iree_hal_buffer_mapping_t mapped_memory = {{0}};
Stella Laurenzo73045212021-06-25 16:18:57 -0700420 CheckApiStatus(iree_hal_buffer_map_range(
Ben Vanikb036c632021-12-14 14:21:16 -0800421 raw_buffer, IREE_HAL_MAPPING_MODE_SCOPED,
422 IREE_HAL_MEMORY_ACCESS_READ, 0 /* element_offset */,
423 byte_length, &mapped_memory),
Stella Laurenzo73045212021-06-25 16:18:57 -0700424 "Could not map memory");
425 record["contents"] =
426 py::bytes(reinterpret_cast<const char*>(mapped_memory.contents.data),
427 mapped_memory.contents.data_length);
428 iree_hal_buffer_unmap_range(&mapped_memory);
429
430 return std::move(record);
431 }
432 }
433
434 throw RaiseValueError("Unsupported VM to Python Type Conversion");
435}
436
Stella Laurenzo7b066572022-07-31 18:38:15 -0700437py::object VmVariantList::GetAsRef(int index) {
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700438 iree_vm_variant_t v = iree_vm_variant_empty();
Ben Vanik78fc0e32023-03-06 16:20:08 -0800439 CheckApiStatus(iree_vm_list_get_variant_assign(raw_ptr(), index, &v),
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700440 "Could not access list element");
Stella Laurenzo7b066572022-07-31 18:38:15 -0700441 if (!iree_vm_variant_is_ref(v)) {
442 throw std::invalid_argument("list element is not a ref");
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700443 }
Stella Laurenzo7b066572022-07-31 18:38:15 -0700444 VmRef ref;
445 iree_vm_ref_retain(&v.ref, &ref.ref());
446 return py::cast(ref, py::return_value_policy::move);
447}
448
449py::object VmVariantList::GetAsObject(int index, py::object clazz) {
450 return clazz.attr(VmRef::kCastAttr)(GetAsRef(index));
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700451}
452
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700453namespace {
454
Ben Vanikb9b794b2021-06-19 20:11:08 -0700455static std::string ToHexString(const uint8_t* data, size_t length) {
456 static constexpr char kHexChars[] = {'0', '1', '2', '3', '4', '5', '6', '7',
457 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
458 std::string s(length * 2, ' ');
459 for (size_t i = 0; i < length; ++i) {
460 s[2 * i + 0] = kHexChars[(data[i] & 0xF0) >> 4];
461 s[2 * i + 1] = kHexChars[(data[i] & 0x0F) >> 0];
462 }
463 return s;
464}
465static std::string ToHexString(uint32_t value) {
466 return ToHexString((const uint8_t*)&value, sizeof(value));
467}
468
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700469void AppendListContents(std::string& out, iree_vm_list_t* list,
470 std::unordered_set<iree_vm_list_t*>& visited) {
471 for (iree_host_size_t i = 0, e = iree_vm_list_size(list); i < e; ++i) {
472 iree_vm_variant_t variant = iree_vm_variant_empty();
Ben Vanik78fc0e32023-03-06 16:20:08 -0800473 iree_status_t status = iree_vm_list_get_variant_assign(list, i, &variant);
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700474 if (!iree_status_is_ok(status)) {
475 iree_status_ignore(status);
476 out.append("Error");
477 continue;
478 }
479 if (i > 0) out.append(", ");
480
481 if (iree_vm_variant_is_value(variant)) {
Sean Silvabef60b42021-09-09 20:51:05 -0700482 // Convert a value type to a string.
Ben Vanik09630d62023-04-13 14:21:40 -0700483 switch (iree_vm_type_def_as_value(variant.type)) {
Sean Silvabef60b42021-09-09 20:51:05 -0700484 case IREE_VM_VALUE_TYPE_I8: {
485 out += std::to_string(variant.i8);
486 break;
487 }
488 case IREE_VM_VALUE_TYPE_I16: {
489 out += std::to_string(variant.i16);
490 break;
491 }
492 case IREE_VM_VALUE_TYPE_I32: {
493 out += std::to_string(variant.i32);
494 break;
495 }
496 case IREE_VM_VALUE_TYPE_I64: {
497 out += std::to_string(variant.i64);
498 break;
499 }
500 case IREE_VM_VALUE_TYPE_F32: {
501 out += std::to_string(variant.f32);
502 break;
503 }
504 case IREE_VM_VALUE_TYPE_F64: {
505 out += std::to_string(variant.f64);
506 break;
507 }
508 default:
509 throw RaiseValueError("Unsupported VM value type to string");
510 }
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700511 } else if (iree_vm_variant_is_ref(variant)) {
512 // Pretty print a subset of ABI impacting known types.
513 if (iree_hal_buffer_isa(variant.ref)) {
514 auto* hal_buffer = iree_hal_buffer_deref(variant.ref);
515 assert(hal_buffer);
Ben Vanikb9b794b2021-06-19 20:11:08 -0700516 out += std::string("HalBuffer(") +
517 std::to_string(iree_hal_buffer_byte_length(hal_buffer)) + ")";
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700518 } else if (iree_hal_buffer_view_isa(variant.ref)) {
519 auto hal_bv = iree_hal_buffer_view_deref(variant.ref);
Ben Vanikb9b794b2021-06-19 20:11:08 -0700520 out += "HalBufferView(";
Ben Vanik49fee302022-05-16 21:18:59 -0700521 std::vector<iree_hal_dim_t> shape(
522 iree_hal_buffer_view_shape_rank(hal_bv));
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700523 iree_hal_buffer_view_shape(hal_bv, shape.size(), shape.data(), nullptr);
Ben Vanikb9b794b2021-06-19 20:11:08 -0700524 for (size_t i = 0; i < shape.size(); ++i) {
525 if (i > 0) out += 'x';
526 out += std::to_string(shape[i]);
527 }
528 out += ":0x" +
529 ToHexString(static_cast<uint32_t>(
530 iree_hal_buffer_view_element_type(hal_bv))) +
531 ")";
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700532 } else if (iree_vm_list_isa(variant.ref)) {
533 out.append("List[");
534 iree_vm_list_t* sub_list = iree_vm_list_deref(variant.ref);
535 if (visited.insert(sub_list).second) {
536 AppendListContents(out, sub_list, visited);
537 } else {
538 out.append("...circular...");
539 }
540 out.append("]");
541 } else {
Ben Vanik09630d62023-04-13 14:21:40 -0700542 out += "Unknown(" +
543 std::to_string(iree_vm_type_def_as_ref(variant.type)) + ")";
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700544 }
545 } else {
546 out.append("None");
547 }
548 }
549}
550
551} // namespace
552
Stella Laurenzo480e6ef2019-12-23 10:07:52 -0800553std::string VmVariantList::DebugString() const {
554 // The variant list API requires mutability, so we const cast to it internally
555 // so we can maintain a const DebugString() for callers.
556 auto mutable_this = const_cast<VmVariantList*>(this);
Ben Vanikb9b794b2021-06-19 20:11:08 -0700557 std::string s =
558 std::string("<VmVariantList(") + std::to_string(size()) + "): [";
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700559 iree_vm_list_t* list = mutable_this->raw_ptr();
560 std::unordered_set<iree_vm_list_t*> visited;
561 visited.insert(list);
562 AppendListContents(s, list, visited);
563 s.append("]>");
Stella Laurenzo480e6ef2019-12-23 10:07:52 -0800564 return s;
565}
566
powderluv2e2fc9c2019-10-23 10:09:44 -0700567void SetupVmBindings(pybind11::module m) {
Ben Vanik4c0a53e2020-06-16 10:33:19 -0700568 py::enum_<enum iree_vm_function_linkage_e>(m, "Linkage")
Stella Laurenzodc513de2019-12-19 10:19:57 -0800569 .value("INTERNAL", IREE_VM_FUNCTION_LINKAGE_INTERNAL)
570 .value("IMPORT", IREE_VM_FUNCTION_LINKAGE_IMPORT)
Ben Vanik79495f42022-04-18 10:49:21 -0700571 .value("IMPORT_OPTIONAL", IREE_VM_FUNCTION_LINKAGE_IMPORT_OPTIONAL)
Stella Laurenzodc513de2019-12-19 10:19:57 -0800572 .value("EXPORT", IREE_VM_FUNCTION_LINKAGE_EXPORT)
573 .export_values();
574
Stella Laurenzo7b066572022-07-31 18:38:15 -0700575 auto vm_buffer = py::class_<VmBuffer>(m, "VmBuffer", py::buffer_protocol());
Ben Vanik09630d62023-04-13 14:21:40 -0700576 VmRef::BindRefProtocol(vm_buffer, iree_vm_buffer_type,
Stella Laurenzo7b066572022-07-31 18:38:15 -0700577 iree_vm_buffer_retain_ref, iree_vm_buffer_deref,
578 iree_vm_buffer_isa);
579 vm_buffer
Ben Vanik3e6130e2023-03-04 12:41:21 -0800580 .def(py::init([](iree_host_size_t length, iree_host_size_t alignment,
581 bool is_mutable) {
Stella Laurenzo7b066572022-07-31 18:38:15 -0700582 iree_vm_buffer_access_t access = 0;
583 if (is_mutable) {
584 access |= IREE_VM_BUFFER_ACCESS_MUTABLE;
585 }
586 iree_vm_buffer_t* raw_buffer;
587 CheckApiStatus(
Ben Vanik3e6130e2023-03-04 12:41:21 -0800588 iree_vm_buffer_create(access, length, alignment,
589 iree_allocator_system(), &raw_buffer),
Stella Laurenzo7b066572022-07-31 18:38:15 -0700590 "Error creating buffer");
591 return VmBuffer::StealFromRawPtr(raw_buffer);
592 }),
Ben Vanik3e6130e2023-03-04 12:41:21 -0800593 py::arg("length"), py::arg("alignment") = 0,
594 py::arg("mutable") = true)
Stella Laurenzo7b066572022-07-31 18:38:15 -0700595 .def_buffer([](VmBuffer& self) -> py::buffer_info {
596 return py::buffer_info(
597 /*ptr=*/self.raw_ptr()->data.data,
598 /*itemsize=*/sizeof(uint8_t),
599 /*format=*/py::format_descriptor<uint8_t>::format(),
600 /*ndim=*/1,
601 /*shape=*/{self.raw_ptr()->data.data_length},
602 /*strides=*/{1},
603 /*readonly=*/
604 !(self.raw_ptr()->access & IREE_VM_BUFFER_ACCESS_MUTABLE));
605 })
606 .def("__repr__", [](VmBuffer& self) {
607 std::stringstream ss;
608 ss << "<VmBuffer size " << self.raw_ptr()->data.data_length << " at 0x"
609 << std::hex << reinterpret_cast<uintptr_t>(self.raw_ptr()->data.data)
610 << ">";
611 return ss.str();
612 });
613
Stella Laurenzodc513de2019-12-19 10:19:57 -0800614 // Mutation and inspection of the variant list is mostly opaque to python.
Stella Laurenzo95dff502022-07-31 14:16:12 -0700615 auto vm_list = py::class_<VmVariantList>(m, "VmVariantList");
Ben Vanik09630d62023-04-13 14:21:40 -0700616 VmRef::BindRefProtocol(vm_list, iree_vm_list_type, iree_vm_list_retain_ref,
Stella Laurenzo7b066572022-07-31 18:38:15 -0700617 iree_vm_list_deref, iree_vm_list_isa);
Stella Laurenzo95dff502022-07-31 14:16:12 -0700618 vm_list
619 // User Methods.
Stella Laurenzodc513de2019-12-19 10:19:57 -0800620 .def(py::init(&VmVariantList::Create))
Stella Laurenzo480e6ef2019-12-23 10:07:52 -0800621 .def_property_readonly("size", &VmVariantList::size)
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700622 .def("__len__", &VmVariantList::size)
Stella Laurenzo7b066572022-07-31 18:38:15 -0700623 .def("get_as_ref", &VmVariantList::GetAsRef)
624 .def("get_as_object", &VmVariantList::GetAsObject)
Stella Laurenzo5ba8a7a2021-05-11 21:29:23 -0700625 .def("get_as_list", &VmVariantList::GetAsList)
Stella Laurenzo99956042021-05-14 10:32:38 -0700626 .def("get_variant", &VmVariantList::GetVariant)
Stella Laurenzo73045212021-06-25 16:18:57 -0700627 .def("get_serialized_trace_value",
628 &VmVariantList::GetAsSerializedTraceValue)
Stella Laurenzo99956042021-05-14 10:32:38 -0700629 .def("push_float", &VmVariantList::PushFloat)
630 .def("push_int", &VmVariantList::PushInt)
Stella Laurenzo397c4fc2021-05-08 00:19:22 -0700631 .def("push_list", &VmVariantList::PushList)
Stella Laurenzo7b066572022-07-31 18:38:15 -0700632 .def("push_ref", &VmVariantList::PushRef)
Stella Laurenzo480e6ef2019-12-23 10:07:52 -0800633 .def("__repr__", &VmVariantList::DebugString);
Stella Laurenzodc513de2019-12-19 10:19:57 -0800634
635 py::class_<iree_vm_function_t>(m, "VmFunction")
Stella Laurenzod5efc482019-12-21 04:59:36 -0800636 .def_readonly("linkage", &iree_vm_function_t::linkage)
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700637 .def_readonly("ordinal", &iree_vm_function_t::ordinal)
Stella Laurenzo73045212021-06-25 16:18:57 -0700638 .def_property_readonly("name",
639 [](iree_vm_function_t& self) {
640 iree_string_view_t name =
641 iree_vm_function_name(&self);
642 return py::str(name.data, name.size);
643 })
644 .def_property_readonly("module_name",
645 [](iree_vm_function_t& self) {
646 iree_string_view_t name =
647 iree_vm_module_name(self.module);
648 return py::str(name.data, name.size);
649 })
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700650 .def_property_readonly("reflection",
651 [](iree_vm_function_t& self) {
652 return GetFunctionReflectionDict(self);
653 })
654 .def("__repr__", [](iree_vm_function_t& self) {
655 iree_string_view_t name = iree_vm_function_name(&self);
656 std::string repr("<VmFunction ");
657 repr.append(name.data, name.size);
658
659 iree_vm_function_signature_t sig = iree_vm_function_signature(&self);
660 repr.append("(");
661 repr.append(sig.calling_convention.data, sig.calling_convention.size);
662 repr.append("), reflection = ");
663 py::dict reflection = GetFunctionReflectionDict(self);
664 repr.append(py::cast<std::string>(py::repr(reflection)));
665 repr.append(">");
666 return repr;
667 });
Stella Laurenzodc513de2019-12-19 10:19:57 -0800668
669 py::class_<VmInstance>(m, "VmInstance").def(py::init(&VmInstance::Create));
670
671 py::class_<VmContext>(m, "VmContext")
672 .def(py::init(&VmContext::Create), py::arg("instance"),
Ben Vanikdf89eb02021-06-20 18:01:16 -0700673 py::arg("modules") = std::optional<std::vector<VmModule*>>())
Stella Laurenzodc513de2019-12-19 10:19:57 -0800674 .def("register_modules", &VmContext::RegisterModules)
Stella Laurenzod5efc482019-12-21 04:59:36 -0800675 .def_property_readonly("context_id", &VmContext::context_id)
Stella Laurenzod5efc482019-12-21 04:59:36 -0800676 .def("invoke", &VmContext::Invoke);
Stella Laurenzodc513de2019-12-19 10:19:57 -0800677
678 py::class_<VmModule>(m, "VmModule")
Eugene Zhulenev6f81ceb2023-05-16 19:23:26 -0700679 .def_static("resolve_module_dependency",
680 &VmModule::ResolveModuleDependency)
Stella Laurenzodc513de2019-12-19 10:19:57 -0800681 .def_static("from_flatbuffer", &VmModule::FromFlatbufferBlob)
Stella Laurenzo3345b762023-06-15 00:22:24 -0700682 .def_static("mmap", &VmModule::MMap)
Stella Laurenzo449e7e52019-12-23 14:24:38 -0800683 .def_property_readonly("name", &VmModule::name)
Ben Vanik6b8387c2022-08-08 12:26:17 -0700684 .def_property_readonly("version",
685 [](VmModule& self) {
686 iree_vm_module_signature_t sig =
687 iree_vm_module_signature(self.raw_ptr());
688 return sig.version;
689 })
Stella Laurenzodc513de2019-12-19 10:19:57 -0800690 .def("lookup_function", &VmModule::LookupFunction, py::arg("name"),
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700691 py::arg("linkage") = IREE_VM_FUNCTION_LINKAGE_EXPORT)
Stella Laurenzo73045212021-06-25 16:18:57 -0700692 .def_property_readonly(
693 "stashed_flatbuffer_blob",
694 [](VmModule& self) { return self.get_stashed_flatbuffer_blob(); })
Stella Laurenzoc4598082021-10-05 12:46:52 -0700695 .def_property_readonly(
696 "function_names",
697 [](VmModule& self) {
698 py::list names;
699 iree_vm_module_signature_t sig =
700 iree_vm_module_signature(self.raw_ptr());
701 for (size_t ordinal = 0; ordinal < sig.export_function_count;
702 ++ordinal) {
703 iree_vm_function_t f;
Stella Laurenzoc4598082021-10-05 12:46:52 -0700704 auto status = iree_vm_module_lookup_function_by_ordinal(
Ben Vanik71904de2021-10-05 15:57:07 -0700705 self.raw_ptr(), IREE_VM_FUNCTION_LINKAGE_EXPORT, ordinal, &f);
Stella Laurenzoc4598082021-10-05 12:46:52 -0700706 if (iree_status_is_not_found(status)) {
707 iree_status_ignore(status);
708 break;
709 }
710 CheckApiStatus(status, "Error enumerating module");
711 iree_string_view_t fname = iree_vm_function_name(&f);
712 py::str name(fname.data, fname.size);
713 names.append(name);
714 }
715 return names;
716 })
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700717 .def("__repr__", [](VmModule& self) {
718 std::string repr("<VmModule ");
719 iree_string_view_t name = iree_vm_module_name(self.raw_ptr());
720 repr.append(name.data, name.size);
721
722 iree_vm_module_signature_t sig =
723 iree_vm_module_signature(self.raw_ptr());
724 repr.append(" : [");
725 for (size_t ordinal = 0; ordinal < sig.export_function_count;
726 ++ordinal) {
727 iree_vm_function_t f;
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700728 auto status = iree_vm_module_lookup_function_by_ordinal(
Ben Vanik6c4dd5b2021-10-05 15:29:23 -0700729 self.raw_ptr(), IREE_VM_FUNCTION_LINKAGE_EXPORT, ordinal, &f);
Stella Laurenzoaeaaad62021-05-03 13:44:52 -0700730 if (iree_status_is_not_found(status)) {
731 iree_status_ignore(status);
732 break;
733 }
734 CheckApiStatus(status, "Error enumerating module");
735 iree_string_view_t fname = iree_vm_function_name(&f);
736 if (ordinal > 0) {
737 repr.append(", ");
738 }
739 repr.append(fname.data, fname.size);
740 }
741 repr.append("]");
742 repr.append(">");
743 return repr;
744 });
Stella Laurenzo95dff502022-07-31 14:16:12 -0700745
746 py::class_<VmRef>(m, "VmRef")
747 .def("isinstance", &VmRef::IsInstance)
Stella Laurenzo7b066572022-07-31 18:38:15 -0700748 .def("deref", &VmRef::Deref, py::arg("value"),
749 py::arg("optional") = false)
Stella Laurenzo95dff502022-07-31 14:16:12 -0700750 .def("__repr__", &VmRef::ToString)
Stella Laurenzo7b066572022-07-31 18:38:15 -0700751 .def_property_readonly(VmRef::kRefAttr,
752 [](py::object self) { return self; })
Stella Laurenzo95dff502022-07-31 14:16:12 -0700753 .def("__eq__",
754 [](VmRef& self, VmRef& other) {
755 return self.ref().ptr == other.ref().ptr;
756 })
757 .def("__eq__", [](VmRef& self, py::object& other) { return false; });
powderluv2e2fc9c2019-10-23 10:09:44 -0700758}
759
760} // namespace python
761} // namespace iree