Add an experimental static library web demo using Emscripten. (#8171)
This is a proof of concept for deploying to the web using IREE. See the README for more details.
Rough structure:
* `build_static_emscripten_demo.sh` compiles an MNIST sample model targeting WebAssembly (`--iree-hal-target-backends=llvm --iree-llvm-target-triple=wasm32-unknown-unknown -iree-llvm-link-static`), compiles the runtime using Emscripten, then starts a local webserver for the provided index.html
* Parts of this could be folded into the CMakeLists.txt, but I think this split is easier to follow
* `index.html` has the web demo code (`<canvas>` for drawing, javascript for interfacing between the UI and the Wasm module)
* `main.c` has the native demo code (using IREE's high level `runtime/` API)
* `device_sync.c` and `device_multithreaded.c` implement CPU devices using the static library output
Future work _not_ finished here:
* Finish multithreading setup. I'm still debugging something in our use of threading/synchronization primitives and Emscripten's pthreads implementation (an infinite timeout instead always returns immediately, breaking our implementation)
* Support for non-static deployment by implementing an emscripten loader (similar to dlopen)
* Building/testing on our CI. We have an Emscripten build in https://github.com/google/iree/blob/main/build_tools/buildkite/cmake/build_configurations.yml that could be extended to cover this though
The resulting web page looks like this: 
(again - proof of concept, the demo program is not very accurate and the preprocessing logic may be wrong :D)
diff --git a/experimental/sample_web_static/device_sync.c b/experimental/sample_web_static/device_sync.c
new file mode 100644
index 0000000..82e291d
--- /dev/null
+++ b/experimental/sample_web_static/device_sync.c
@@ -0,0 +1,45 @@
+// Copyright 2022 The IREE Authors
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "iree/hal/local/loaders/static_library_loader.h"
+#include "iree/hal/local/sync_device.h"
+#include "mnist_static.h"
+
+iree_status_t create_device_with_static_loader(iree_allocator_t host_allocator,
+ iree_hal_device_t** out_device) {
+ iree_hal_sync_device_params_t params;
+ iree_hal_sync_device_params_initialize(¶ms);
+
+ // Load the statically embedded library.
+ const iree_hal_executable_library_header_t** static_library =
+ mnist_linked_llvm_library_query(
+ IREE_HAL_EXECUTABLE_LIBRARY_LATEST_VERSION,
+ /*reserved=*/NULL);
+ const iree_hal_executable_library_header_t** libraries[1] = {static_library};
+
+ iree_hal_executable_loader_t* library_loader = NULL;
+ iree_status_t status = iree_hal_static_library_loader_create(
+ IREE_ARRAYSIZE(libraries), libraries,
+ iree_hal_executable_import_provider_null(), host_allocator,
+ &library_loader);
+
+ iree_string_view_t identifier = iree_make_cstring_view("sync");
+ iree_hal_allocator_t* device_allocator = NULL;
+ if (iree_status_is_ok(status)) {
+ status = iree_hal_allocator_create_heap(identifier, host_allocator,
+ host_allocator, &device_allocator);
+ }
+
+ if (iree_status_is_ok(status)) {
+ status = iree_hal_sync_device_create(
+ identifier, ¶ms, /*loader_count=*/1, &library_loader,
+ device_allocator, host_allocator, out_device);
+ }
+
+ iree_hal_allocator_release(device_allocator);
+ iree_hal_executable_loader_release(library_loader);
+ return status;
+}