Refactoring the iree::vm on top of iree::rt. The dedupes the interfaces that were factored out previously and moves a bit more common code for printing/disassembling to keep feature parity with the old interface. PiperOrigin-RevId: 274841300
diff --git a/iree/hal/interpreter/BUILD b/iree/hal/interpreter/BUILD index 97235f6..204eb0a 100644 --- a/iree/hal/interpreter/BUILD +++ b/iree/hal/interpreter/BUILD
@@ -18,6 +18,7 @@ "//iree/hal:executable", "//iree/hal:executable_cache", "//iree/hal:executable_format", + "//iree/rt", ], ) @@ -38,13 +39,13 @@ "//iree/hal:allocator", "//iree/hal:buffer_view", "//iree/hal:heap_buffer", + "//iree/rt", "//iree/schemas/bytecode:interpreter_bytecode_v0", + "//iree/vm:bytecode_module", "//iree/vm:bytecode_reader", "//iree/vm:bytecode_tables_interpreter", "//iree/vm:bytecode_util", - "//iree/vm:function", "//iree/vm:opcode_info", - "//iree/vm:stack", "//iree/vm:type", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:inlined_vector", @@ -57,16 +58,13 @@ srcs = ["bytecode_executable.cc"], hdrs = ["bytecode_executable.h"], deps = [ - ":interpreter_context", + ":interpreter_module", "//iree/base:status", "//iree/hal:allocator", "//iree/hal:executable", "//iree/hal:executable_spec", + "//iree/rt", "//iree/vm:bytecode_tables_interpreter", - "//iree/vm:bytecode_validator", - "//iree/vm:context", - "//iree/vm:module", - "//iree/vm:module_printer", "@com_google_absl//absl/types:span", ], ) @@ -116,30 +114,13 @@ "//iree/base:tracing", "//iree/hal:buffer_view", "//iree/hal/host:host_local_command_processor", + "//iree/rt", "@com_google_absl//absl/container:inlined_vector", "@com_google_absl//absl/types:span", ], ) cc_library( - name = "interpreter_context", - srcs = ["interpreter_context.cc"], - hdrs = ["interpreter_context.h"], - deps = [ - ":bytecode_dispatch", - ":bytecode_kernels", - "//iree/base:flatbuffer_util", - "//iree/base:status", - "//iree/hal:allocator", - "//iree/hal:buffer_view", - "//iree/vm:context", - "//iree/vm:function", - "//iree/vm:stack", - "@com_google_absl//absl/types:span", - ], -) - -cc_library( name = "interpreter_device", srcs = ["interpreter_device.cc"], hdrs = ["interpreter_device.h"], @@ -159,6 +140,7 @@ "//iree/hal/host:host_local_allocator", "//iree/hal/host:host_submission_queue", "//iree/hal/host:inproc_command_buffer", + "//iree/rt", "@com_google_absl//absl/container:inlined_vector", "@com_google_absl//absl/memory", "@com_google_absl//absl/types:span", @@ -187,3 +169,22 @@ ], alwayslink = 1, ) + +cc_library( + name = "interpreter_module", + srcs = ["interpreter_module.cc"], + hdrs = ["interpreter_module.h"], + deps = [ + ":bytecode_dispatch", + ":bytecode_kernels", + "//iree/base:flatbuffer_util", + "//iree/base:status", + "//iree/base:tracing", + "//iree/hal:allocator", + "//iree/hal:buffer_view", + "//iree/rt", + "//iree/vm:bytecode_module", + "//iree/vm:bytecode_tables_interpreter", + "@com_google_absl//absl/types:span", + ], +)
diff --git a/iree/hal/interpreter/CMakeLists.txt b/iree/hal/interpreter/CMakeLists.txt index 5031688..5295105 100644 --- a/iree/hal/interpreter/CMakeLists.txt +++ b/iree/hal/interpreter/CMakeLists.txt
@@ -75,7 +75,7 @@ iree::hal::allocator iree::hal::executable iree::hal::executable_spec - iree::hal::interpreter::interpreter_context + iree::hal::interpreter::interpreter_module iree::vm::bytecode_tables_interpreter iree::vm::bytecode_validator iree::vm::context @@ -138,27 +138,6 @@ iree_cc_library( NAME - interpreter_context - HDRS - "interpreter_context.h" - SRCS - "interpreter_context.cc" - DEPS - absl::span - iree::base::flatbuffer_util - iree::base::status - iree::hal::allocator - iree::hal::buffer_view - iree::hal::interpreter::bytecode_dispatch - iree::hal::interpreter::bytecode_kernels - iree::vm::context - iree::vm::function - iree::vm::stack - PUBLIC -) - -iree_cc_library( - NAME interpreter_device HDRS "interpreter_device.h" @@ -212,3 +191,24 @@ iree::hal::interpreter::interpreter_driver PUBLIC ) + +iree_cc_library( + NAME + interpreter_module + HDRS + "interpreter_module.h" + SRCS + "interpreter_module.cc" + DEPS + absl::span + iree::base::flatbuffer_util + iree::base::status + iree::hal::allocator + iree::hal::buffer_view + iree::hal::interpreter::bytecode_dispatch + iree::hal::interpreter::bytecode_kernels + iree::vm::context + iree::vm::function + iree::vm::stack + PUBLIC +)
diff --git a/iree/hal/interpreter/bytecode_cache.cc b/iree/hal/interpreter/bytecode_cache.cc index de7d8f2..b42db5a 100644 --- a/iree/hal/interpreter/bytecode_cache.cc +++ b/iree/hal/interpreter/bytecode_cache.cc
@@ -23,8 +23,9 @@ namespace iree { namespace hal { -BytecodeCache::BytecodeCache(hal::Allocator* allocator) - : allocator_(allocator) {} +BytecodeCache::BytecodeCache(ref_ptr<rt::Instance> instance, + hal::Allocator* allocator) + : instance_(std::move(instance)), allocator_(allocator) {} BytecodeCache::~BytecodeCache() = default; @@ -43,9 +44,9 @@ // Wrap the data (or copy it). bool allow_aliasing_data = AllBitsSet(mode, ExecutableCachingMode::kAliasProvidedData); - ASSIGN_OR_RETURN( - auto executable, - BytecodeExecutable::Load(allocator_, spec, !allow_aliasing_data)); + ASSIGN_OR_RETURN(auto executable, + BytecodeExecutable::Load(add_ref(instance_), allocator_, + spec, !allow_aliasing_data)); return executable; }
diff --git a/iree/hal/interpreter/bytecode_cache.h b/iree/hal/interpreter/bytecode_cache.h index fd955c5..4da59ec 100644 --- a/iree/hal/interpreter/bytecode_cache.h +++ b/iree/hal/interpreter/bytecode_cache.h
@@ -18,13 +18,14 @@ #include "iree/hal/allocator.h" #include "iree/hal/executable.h" #include "iree/hal/executable_cache.h" +#include "iree/rt/instance.h" namespace iree { namespace hal { class BytecodeCache final : public ExecutableCache { public: - explicit BytecodeCache(hal::Allocator* allocator); + BytecodeCache(ref_ptr<rt::Instance> instance, hal::Allocator* allocator); ~BytecodeCache() override; bool CanPrepareFormat(ExecutableFormat format) const override; @@ -33,6 +34,7 @@ ExecutableCachingModeBitfield mode, const ExecutableSpec& spec) override; private: + ref_ptr<rt::Instance> instance_; hal::Allocator* allocator_; };
diff --git a/iree/hal/interpreter/bytecode_dispatch.cc b/iree/hal/interpreter/bytecode_dispatch.cc index b89fb44..f0e7040 100644 --- a/iree/hal/interpreter/bytecode_dispatch.cc +++ b/iree/hal/interpreter/bytecode_dispatch.cc
@@ -33,11 +33,12 @@ #include "iree/hal/interpreter/bytecode_dispatch_conversion.h" #include "iree/hal/interpreter/bytecode_dispatch_util.h" #include "iree/hal/interpreter/bytecode_kernels.h" +#include "iree/rt/function.h" #include "iree/schemas/bytecode/interpreter_bytecode_v0.h" +#include "iree/vm/bytecode_module.h" #include "iree/vm/bytecode_reader.h" #include "iree/vm/bytecode_tables_interpreter.h" #include "iree/vm/bytecode_util.h" -#include "iree/vm/function.h" #include "iree/vm/opcode_info.h" namespace iree { @@ -45,11 +46,9 @@ namespace { +using ::iree::rt::Stack; +using ::iree::rt::StackFrame; using ::iree::vm::BytecodeReader; -using ::iree::vm::ImportFunction; -using ::iree::vm::NativeFunction; -using ::iree::vm::Stack; -using ::iree::vm::StackFrame; } // namespace @@ -111,38 +110,23 @@ DISPATCH_CORE_OPCODE(kCall, { auto* old_stack_frame = stack->current_frame(); ASSIGN_OR_RETURN(const auto& target_function, reader.ReadFunction()); + // TODO(benvanik): rework register storage interface. + ASSIGN_OR_RETURN( + const auto* function_def, + static_cast<const vm::BytecodeModule*>(target_function.module()) + ->GetFunctionDef(target_function.linkage(), + target_function.ordinal())); ASSIGN_OR_RETURN(auto* new_stack_frame, stack->PushFrame(target_function)); + new_stack_frame->mutable_registers()->buffer_views.resize( + function_def->bytecode()->local_count()); RETURN_IF_ERROR( reader.CopyInputsAndSwitchStackFrame(old_stack_frame, new_stack_frame)); DVLOG(1) << "Call; stack now: " << stack->DebugString(); }); DISPATCH_CORE_OPCODE(kCallImport, { - auto* old_stack_frame = stack->current_frame(); - ASSIGN_OR_RETURN(const auto* target_function, reader.ReadImportFunction()); - switch (target_function->link_type()) { - case ImportFunction::LinkType::kModule: { - ASSIGN_OR_RETURN(auto* new_stack_frame, - stack->PushFrame(target_function->linked_function())); - RETURN_IF_ERROR(reader.CopyInputsAndSwitchStackFrame(old_stack_frame, - new_stack_frame)); - DVLOG(1) << "Call module import; stack now: " << stack->DebugString(); - break; - } - case ImportFunction::LinkType::kNativeFunction: { - ASSIGN_OR_RETURN(auto* new_stack_frame, - stack->PushFrame(*target_function)); - RETURN_IF_ERROR(reader.CopyInputsAndSwitchStackFrame(old_stack_frame, - new_stack_frame)); - DVLOG(1) << "Call native import; stack now: " << stack->DebugString(); - RETURN_IF_ERROR(CallNativeFunction(stack, *target_function)); - RETURN_IF_ERROR(reader.CopyResultsAndSwitchStackFrame(old_stack_frame, - new_stack_frame)); - RETURN_IF_ERROR(stack->PopFrame()); - DVLOG(1) << "Return from native; stack now: " << stack->DebugString(); - break; - } - } + return UnimplementedErrorBuilder(IREE_LOC) + << "Non-module imports not supported"; }); DISPATCH_CORE_OPCODE(kCallIndirect, { @@ -156,8 +140,9 @@ // Returning from entry function. Marshal results from the return stmt. ASSIGN_OR_RETURN(int32_t src_count, reader.ReadCount()); for (int i = 0; i < src_count; ++i) { - ASSIGN_OR_RETURN(auto* src_local, - reader.ReadLocal(old_stack_frame->mutable_locals())); + ASSIGN_OR_RETURN( + auto* src_local, + reader.ReadLocal(old_stack_frame->mutable_registers())); entry_results[i] = std::move(*src_local); } DVLOG(1) << "Returning to entry";
diff --git a/iree/hal/interpreter/bytecode_dispatch.h b/iree/hal/interpreter/bytecode_dispatch.h index 1d4b7d1..edd92d2 100644 --- a/iree/hal/interpreter/bytecode_dispatch.h +++ b/iree/hal/interpreter/bytecode_dispatch.h
@@ -18,15 +18,15 @@ #include "iree/base/status.h" #include "iree/hal/allocator.h" #include "iree/hal/interpreter/bytecode_kernels.h" -#include "iree/vm/stack.h" -#include "iree/vm/stack_frame.h" +#include "iree/rt/stack.h" +#include "iree/rt/stack_frame.h" namespace iree { namespace hal { Status Dispatch(hal::Allocator* allocator, - kernels::RuntimeState* kernel_runtime_state, vm::Stack* stack, - vm::StackFrame* entry_stack_frame, + kernels::RuntimeState* kernel_runtime_state, rt::Stack* stack, + rt::StackFrame* entry_stack_frame, absl::Span<BufferView> entry_results); } // namespace hal
diff --git a/iree/hal/interpreter/bytecode_dispatch_util.cc b/iree/hal/interpreter/bytecode_dispatch_util.cc index 0e59bd8..40937e1 100644 --- a/iree/hal/interpreter/bytecode_dispatch_util.cc +++ b/iree/hal/interpreter/bytecode_dispatch_util.cc
@@ -34,18 +34,6 @@ return false; } -Status CallNativeFunction(vm::Stack* stack, - const vm::ImportFunction& function) { - auto* stack_frame = stack->current_frame(); - - // Marshal inputs and outputs. - auto args = stack_frame->mutable_locals().subspan(0, function.input_count()); - auto results = stack_frame->mutable_locals().subspan(args.size()); - - const auto& fn = function.native_function(); - return fn(stack, args, results); -} - Status ValidateElementwiseUnaryOp(BufferView* src_local, BufferView* dst_local) { // TODO(benvanik): validate shapes.
diff --git a/iree/hal/interpreter/bytecode_dispatch_util.h b/iree/hal/interpreter/bytecode_dispatch_util.h index b8f40e1..cb8d7d9 100644 --- a/iree/hal/interpreter/bytecode_dispatch_util.h +++ b/iree/hal/interpreter/bytecode_dispatch_util.h
@@ -24,10 +24,10 @@ #include "iree/hal/buffer_view.h" #include "iree/hal/heap_buffer.h" #include "iree/hal/interpreter/bytecode_kernels.h" +#include "iree/rt/function.h" +#include "iree/rt/stack.h" #include "iree/schemas/bytecode/interpreter_bytecode_v0.h" #include "iree/vm/bytecode_reader.h" -#include "iree/vm/function.h" -#include "iree/vm/stack.h" #include "iree/vm/type.h" // TODO(benvanik): move to dedicated config file/build flags. @@ -42,8 +42,6 @@ // bitwise zero. bool BufferViewIsTrue(const BufferView& buffer_view); -Status CallNativeFunction(vm::Stack* stack, const vm::ImportFunction& function); - Status ValidateElementwiseUnaryOp(BufferView* src_local, BufferView* dst_local); Status ValidateElementwiseBinaryOp(BufferView* lhs_local, BufferView* rhs_local, BufferView* dst_local);
diff --git a/iree/hal/interpreter/bytecode_executable.cc b/iree/hal/interpreter/bytecode_executable.cc index 130eb77..c528263 100644 --- a/iree/hal/interpreter/bytecode_executable.cc +++ b/iree/hal/interpreter/bytecode_executable.cc
@@ -16,63 +16,40 @@ #include <iostream> -#include "iree/vm/bytecode_tables_interpreter.h" -#include "iree/vm/bytecode_validator.h" -#include "iree/vm/module.h" -#include "iree/vm/module_printer.h" +#include "iree/hal/interpreter/interpreter_module.h" +#include "iree/rt/policy.h" namespace iree { namespace hal { -namespace { -// TODO(benvanik): remove when debugger is wired up to the HAL. -const bool kEnableExecutablePrinting = false; -} // namespace - // static StatusOr<ref_ptr<BytecodeExecutable>> BytecodeExecutable::Load( - hal::Allocator* allocator, ExecutableSpec spec, bool allow_aliasing_data) { + ref_ptr<rt::Instance> instance, hal::Allocator* allocator, + ExecutableSpec spec, bool allow_aliasing_data) { // Allocate the executable now. // We do this here so that if we need to clone the data we are passing that // to the VM loader instead of the data we may not have access to later. - auto executable = - make_ref<BytecodeExecutable>(allocator, spec, allow_aliasing_data); - auto* context = executable->mutable_context(); + auto executable = make_ref<BytecodeExecutable>(std::move(instance), allocator, + spec, allow_aliasing_data); // Create the executable module. auto module_def = ::flatbuffers::GetRoot<ModuleDef>(executable->executable_data().data()); - ASSIGN_OR_RETURN(auto module, vm::Module::FromDef(*module_def)); - executable->module_ = module.get(); - RETURN_IF_ERROR(context->RegisterModule(std::move(module))); - - // Validate bytecode to ensure it will be usable for execution. - // We do this here so that we get a good stack immediately when the bytecode - // is provided instead of when we go to run it. This more closely mirrors how - // a backend that performed compilation (such as SPIR-V) would fail. - for (auto* function_def : - *executable->module().function_table().def().functions()) { - RETURN_IF_ERROR(vm::BytecodeValidator::Validate( - *context, executable->module(), *function_def->bytecode())); - } - - // Print the bytecode. - // TODO(benvanik): remove when debugger is wired up to the HAL. - if (kEnableExecutablePrinting) { - vm::PrintModuleFlagBitfield print_flags = vm::PrintModuleFlag::kNone; - for (const auto& module : context->modules()) { - RETURN_IF_ERROR(vm::PrintModuleToStream( - vm::interpreter_opcode_table(), *module, print_flags, &std::cout)); - } - } + ASSIGN_OR_RETURN(auto module, + InterpreterModule::FromDef(allocator, *module_def)); + executable->module_ = add_ref(module); + RETURN_IF_ERROR(executable->context()->RegisterModule(std::move(module))); return executable; } -BytecodeExecutable::BytecodeExecutable(hal::Allocator* allocator, +BytecodeExecutable::BytecodeExecutable(ref_ptr<rt::Instance> instance, + hal::Allocator* allocator, ExecutableSpec spec, bool allow_aliasing_data) - : spec_(spec), context_(allocator) { + : spec_(spec), + context_( + make_ref<rt::Context>(std::move(instance), make_ref<rt::Policy>())) { if (!allow_aliasing_data) { // Clone data. cloned_executable_data_ = {spec.executable_data.begin(),
diff --git a/iree/hal/interpreter/bytecode_executable.h b/iree/hal/interpreter/bytecode_executable.h index 1fae48f..6cd47de 100644 --- a/iree/hal/interpreter/bytecode_executable.h +++ b/iree/hal/interpreter/bytecode_executable.h
@@ -22,20 +22,21 @@ #include "iree/hal/allocator.h" #include "iree/hal/executable.h" #include "iree/hal/executable_spec.h" -#include "iree/hal/interpreter/interpreter_context.h" -#include "iree/vm/context.h" +#include "iree/rt/context.h" +#include "iree/rt/instance.h" +#include "iree/rt/module.h" namespace iree { namespace hal { class BytecodeExecutable final : public Executable { public: - static StatusOr<ref_ptr<BytecodeExecutable>> Load(hal::Allocator* allocator, - ExecutableSpec spec, - bool allow_aliasing_data); + static StatusOr<ref_ptr<BytecodeExecutable>> Load( + ref_ptr<rt::Instance> instance, hal::Allocator* allocator, + ExecutableSpec spec, bool allow_aliasing_data); - BytecodeExecutable(hal::Allocator* allocator, ExecutableSpec spec, - bool allow_aliasing_data); + BytecodeExecutable(ref_ptr<rt::Instance> instance, hal::Allocator* allocator, + ExecutableSpec spec, bool allow_aliasing_data); ~BytecodeExecutable() override; bool supports_debugging() const override { return false; } @@ -46,20 +47,19 @@ } // VM context with the executable registered. - const InterpreterContext& context() const { return context_; } - InterpreterContext* mutable_context() { return &context_; } + const ref_ptr<rt::Context>& context() const { return context_; } // VM module representing the executable. // Note that there may be more than one module in the Context and only this // module can be used to lookup executable exports. - const vm::Module& module() const { return *module_; } + const ref_ptr<rt::Module>& module() const { return module_; } private: ExecutableSpec spec_; std::vector<uint8_t> cloned_executable_data_; - InterpreterContext context_; - vm::Module* module_ = nullptr; + ref_ptr<rt::Context> context_; + ref_ptr<rt::Module> module_; }; } // namespace hal
diff --git a/iree/hal/interpreter/interpreter_command_processor.cc b/iree/hal/interpreter/interpreter_command_processor.cc index a79b10e..783809d 100644 --- a/iree/hal/interpreter/interpreter_command_processor.cc +++ b/iree/hal/interpreter/interpreter_command_processor.cc
@@ -21,6 +21,7 @@ #include "iree/base/tracing.h" #include "iree/hal/buffer_view.h" #include "iree/hal/interpreter/bytecode_executable.h" +#include "iree/rt/stack.h" namespace iree { namespace hal { @@ -40,26 +41,23 @@ auto* executable = static_cast<BytecodeExecutable*>(dispatch_request.executable); const auto& module = executable->module(); - ASSIGN_OR_RETURN(auto entry_function, module.function_table().LookupExport( + ASSIGN_OR_RETURN(auto entry_function, module->LookupFunctionByOrdinal( + rt::Function::Linkage::kExport, dispatch_request.entry_point)); - vm::Stack stack; + rt::Stack stack(executable->context().get()); // TODO(benvanik): avoid this by directly referencing the bindings. - absl::InlinedVector<BufferView, 8> args; - args.reserve(dispatch_request.bindings.size()); + absl::InlinedVector<BufferView, 8> arguments; + arguments.reserve(dispatch_request.bindings.size()); for (auto& binding : dispatch_request.bindings) { - args.push_back(BufferView{add_ref(binding.buffer), binding.shape, - binding.element_size}); + arguments.push_back(BufferView{add_ref(binding.buffer), binding.shape, + binding.element_size}); } absl::InlinedVector<BufferView, 8> results; - if (entry_function.result_count() > 0) { - return UnimplementedErrorBuilder(IREE_LOC) - << "Executable export results are not yet implemented"; - } - RETURN_IF_ERROR(executable->context().Invoke( - &stack, entry_function, absl::MakeSpan(args), absl::MakeSpan(results))); + RETURN_IF_ERROR(executable->module()->Execute( + &stack, entry_function, std::move(arguments), &results)); return OkStatus(); }
diff --git a/iree/hal/interpreter/interpreter_context.cc b/iree/hal/interpreter/interpreter_context.cc deleted file mode 100644 index e30aa96..0000000 --- a/iree/hal/interpreter/interpreter_context.cc +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/hal/interpreter/interpreter_context.h" - -#include "iree/base/flatbuffer_util.h" -#include "iree/base/status.h" -#include "iree/hal/interpreter/bytecode_dispatch.h" - -namespace iree { -namespace hal { - -namespace { - -using ::iree::vm::Function; - -} // namespace - -Status InterpreterContext::Invoke(vm::Stack* stack, Function function, - absl::Span<BufferView> args, - absl::Span<BufferView> results) const { - // Verify arg/result counts. - if (args.size() != function.input_count()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Function " << function.name() << " requires " - << function.input_count() << " inputs but only " << args.size() - << " provided"; - } - if (results.size() != function.result_count()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Function " << function.name() << " requires " - << function.result_count() << " outputs but only " << results.size() - << " provided"; - } - - // Push stack frame for the function we are calling. - ASSIGN_OR_RETURN(auto* callee_stack_frame, stack->PushFrame(function)); - - // Marshal input arguments. - for (int i = 0; i < args.size(); ++i) { - *callee_stack_frame->mutable_local(i) = std::move(args[i]); - } - - // Run main dispatch loop until it exits (or errors). - RETURN_IF_ERROR(Dispatch(allocator_, &kernel_runtime_state_, stack, - callee_stack_frame, results)); - - // Pop the callee frame to balance out the stack. - RETURN_IF_ERROR(stack->PopFrame()); - - return OkStatus(); -} - -} // namespace hal -} // namespace iree
diff --git a/iree/hal/interpreter/interpreter_context.h b/iree/hal/interpreter/interpreter_context.h deleted file mode 100644 index 2808c14..0000000 --- a/iree/hal/interpreter/interpreter_context.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_HAL_INTERPRETER_INTERPRETER_CONTEXT_H_ -#define IREE_HAL_INTERPRETER_INTERPRETER_CONTEXT_H_ - -#include <memory> - -#include "absl/types/span.h" -#include "iree/base/status.h" -#include "iree/hal/allocator.h" -#include "iree/hal/buffer_view.h" -#include "iree/hal/interpreter/bytecode_kernels.h" -#include "iree/vm/context.h" -#include "iree/vm/function.h" -#include "iree/vm/stack.h" - -namespace iree { -namespace hal { - -class InterpreterContext final : public vm::Context { - public: - explicit InterpreterContext(hal::Allocator* allocator) - : allocator_(allocator) {} - - // TODO(benvanik): helpers to make passing args easier - Status Invoke(vm::Stack* stack, vm::Function function, - absl::Span<BufferView> args, - absl::Span<BufferView> results) const; - - private: - hal::Allocator* allocator_; - mutable kernels::RuntimeState kernel_runtime_state_; -}; - -} // namespace hal -} // namespace iree - -#endif // IREE_HAL_INTERPRETER_INTERPRETER_CONTEXT_H_
diff --git a/iree/hal/interpreter/interpreter_device.cc b/iree/hal/interpreter/interpreter_device.cc index 239084e..7a61cc3 100644 --- a/iree/hal/interpreter/interpreter_device.cc +++ b/iree/hal/interpreter/interpreter_device.cc
@@ -97,11 +97,12 @@ } // namespace InterpreterDevice::InterpreterDevice(DeviceInfo device_info) - : Device(std::move(device_info)) { + : Device(std::move(device_info)), instance_(make_ref<rt::Instance>()) { // We currently only expose a single command queue. auto command_queue = absl::make_unique<UnsynchronizedCommandQueue>( &allocator_, "cpu0", CommandCategory::kTransfer | CommandCategory::kDispatch); + // TODO(benvanik): allow injection of the wrapper type to support // SyncCommandQueue without always linking in both. auto async_command_queue = @@ -112,7 +113,7 @@ InterpreterDevice::~InterpreterDevice() = default; std::shared_ptr<ExecutableCache> InterpreterDevice::CreateExecutableCache() { - return std::make_shared<BytecodeCache>(&allocator_); + return std::make_shared<BytecodeCache>(add_ref(instance_), &allocator_); } StatusOr<ref_ptr<CommandBuffer>> InterpreterDevice::CreateCommandBuffer(
diff --git a/iree/hal/interpreter/interpreter_device.h b/iree/hal/interpreter/interpreter_device.h index 9afdaac..5987ab9 100644 --- a/iree/hal/interpreter/interpreter_device.h +++ b/iree/hal/interpreter/interpreter_device.h
@@ -21,6 +21,7 @@ #include "iree/hal/device.h" #include "iree/hal/host/host_local_allocator.h" #include "iree/hal/interpreter/bytecode_kernels.h" +#include "iree/rt/instance.h" namespace iree { namespace hal { @@ -66,6 +67,7 @@ Status WaitIdle(absl::Time deadline) override; private: + ref_ptr<rt::Instance> instance_; kernels::RuntimeState kernel_runtime_state_; mutable HostLocalAllocator allocator_; mutable absl::InlinedVector<std::unique_ptr<CommandQueue>, 1> command_queues_;
diff --git a/iree/hal/interpreter/interpreter_module.cc b/iree/hal/interpreter/interpreter_module.cc new file mode 100644 index 0000000..c569fea --- /dev/null +++ b/iree/hal/interpreter/interpreter_module.cc
@@ -0,0 +1,80 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "iree/hal/interpreter/interpreter_module.h" + +#include "iree/base/flatbuffer_util.h" +#include "iree/base/status.h" +#include "iree/base/tracing.h" +#include "iree/hal/interpreter/bytecode_dispatch.h" +#include "iree/vm/bytecode_tables_interpreter.h" + +namespace iree { +namespace hal { + +// static +StatusOr<ref_ptr<rt::Module>> InterpreterModule::FromDef( + hal::Allocator* allocator, const ModuleDef& module_def) { + ASSIGN_OR_RETURN(auto module_file, + vm::ModuleFile::Create(&module_def, []() {})); + if (module_file->root() == nullptr) { + return InvalidArgumentErrorBuilder(IREE_LOC) << "No root ModuleDef present"; + } + + auto module = + assign_ref(new InterpreterModule(allocator, std::move(module_file))); + + // TODO(benvanik): validate internals here? or make explicit? + + return {std::move(module)}; +} + +InterpreterModule::InterpreterModule( + hal::Allocator* allocator, std::unique_ptr<vm::ModuleFile> module_file) + : vm::BytecodeModule(std::move(module_file), + vm::interpreter_opcode_table()), + allocator_(allocator) {} + +Status InterpreterModule::Execute( + rt::Stack* stack, const rt::Function function, + absl::InlinedVector<hal::BufferView, 8> arguments, + absl::InlinedVector<hal::BufferView, 8>* results) const { + IREE_TRACE_SCOPE0("InterperterModule::Execute"); + + // Push stack frame for the function we are calling. + ASSIGN_OR_RETURN(auto* callee_stack_frame, stack->PushFrame(function)); + + // TODO(benvanik): rework register storage interface. + ASSIGN_OR_RETURN(const auto* function_def, + GetFunctionDef(function.linkage(), function.ordinal())); + auto* registers = callee_stack_frame->mutable_registers(); + registers->buffer_views.resize(function_def->bytecode()->local_count()); + + // Marshal input arguments. + for (int i = 0; i < arguments.size(); ++i) { + registers->buffer_views[i] = std::move(arguments[i]); + } + + // Run main dispatch loop until it exits (or errors). + RETURN_IF_ERROR(Dispatch(allocator_, &kernel_runtime_state_, stack, + callee_stack_frame, results)); + + // Pop the callee frame to balance out the stack. + RETURN_IF_ERROR(stack->PopFrame()); + + return OkStatus(); +} + +} // namespace hal +} // namespace iree
diff --git a/iree/hal/interpreter/interpreter_module.h b/iree/hal/interpreter/interpreter_module.h new file mode 100644 index 0000000..d7d98e3 --- /dev/null +++ b/iree/hal/interpreter/interpreter_module.h
@@ -0,0 +1,55 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef IREE_HAL_INTERPRETER_INTERPRETER_MODULE_H_ +#define IREE_HAL_INTERPRETER_INTERPRETER_MODULE_H_ + +#include <memory> + +#include "absl/types/span.h" +#include "iree/base/status.h" +#include "iree/hal/allocator.h" +#include "iree/hal/buffer_view.h" +#include "iree/hal/interpreter/bytecode_kernels.h" +#include "iree/rt/function.h" +#include "iree/rt/module.h" +#include "iree/rt/stack.h" +#include "iree/vm/bytecode_module.h" +#include "iree/vm/bytecode_tables_interpreter.h" + +namespace iree { +namespace hal { + +class InterpreterModule final : public vm::BytecodeModule { + public: + static StatusOr<ref_ptr<rt::Module>> FromDef(hal::Allocator* allocator, + const ModuleDef& module_def); + + Status Execute( + rt::Stack* stack, const rt::Function function, + absl::InlinedVector<hal::BufferView, 8> arguments, + absl::InlinedVector<hal::BufferView, 8>* results) const override; + + private: + InterpreterModule(hal::Allocator* allocator, + std::unique_ptr<vm::ModuleFile> module_file); + + hal::Allocator* allocator_; + mutable kernels::RuntimeState kernel_runtime_state_; +}; + +} // namespace hal +} // namespace iree + +#endif // IREE_HAL_INTERPRETER_INTERPRETER_MODULE_H_
diff --git a/iree/rt/BUILD b/iree/rt/BUILD index 8fc7242..65e956b 100644 --- a/iree/rt/BUILD +++ b/iree/rt/BUILD
@@ -39,25 +39,31 @@ "function.cc", "instance.cc", "invocation.cc", + "module_printer.cc", "source_location.cc", + "stack.cc", "stack_frame.cc", "stack_trace.cc", ], hdrs = [ "context.h", + "disassembler.h", "function.h", "function_signature.h", "instance.h", "invocation.h", "module.h", + "module_printer.h", "module_signature.h", "policy.h", "source_location.h", "source_resolver.h", + "stack.h", "stack_frame.h", "stack_trace.h", ], deps = [ + "//iree/base:bitfield", "//iree/base:intrusive_list", "//iree/base:ref_ptr", "//iree/base:status",
diff --git a/iree/rt/CMakeLists.txt b/iree/rt/CMakeLists.txt index 8cf7786..61b14a3 100644 --- a/iree/rt/CMakeLists.txt +++ b/iree/rt/CMakeLists.txt
@@ -40,20 +40,25 @@ "function.cc" "instance.cc" "invocation.cc" + "module_printer.cc" "source_location.cc" + "stack.cc" "stack_frame.cc" "stack_trace.cc" HDRS "context.h" + "disassembler.h" "function.h" "function_signature.h" "instance.h" "invocation.h" "module.h" + "module_printer.h" "module_signature.h" "policy.h" "source_location.h" "source_resolver.h" + "stack.h" "stack_frame.h" "stack_trace.h" DEPS @@ -64,6 +69,7 @@ absl::time absl::optional absl::span + iree::base::bitfield iree::base::intrusive_list iree::base::ref_ptr iree::base::status
diff --git a/iree/rt/api.cc b/iree/rt/api.cc index 6e1e5c5..db43358 100644 --- a/iree/rt/api.cc +++ b/iree/rt/api.cc
@@ -108,6 +108,8 @@ SourceResolver* source_resolver() const override { return nullptr; } + Disassembler* disassembler() const override { return nullptr; } + std::string DebugStringShort() const override { return std::string(name()); } StatusOr<const Function> LookupFunctionByOrdinal( @@ -165,7 +167,7 @@ } Status Execute( - const Function function, + Stack* stack, const Function function, absl::InlinedVector<hal::BufferView, 8> arguments, absl::InlinedVector<hal::BufferView, 8>* results) const override { // TODO(benvanik): fn ptr callback to external code. Waiting on fibers.
diff --git a/iree/rt/context.cc b/iree/rt/context.cc index ba49cc4..6320325 100644 --- a/iree/rt/context.cc +++ b/iree/rt/context.cc
@@ -123,6 +123,24 @@ function_name); } +StatusOr<const Function> Context::ResolveImport(const Module* module, + int32_t ordinal) const { + for (const auto& import_table_ref : module_import_tables_) { + if (import_table_ref.first == module) { + const auto& import_table = import_table_ref.second; + if (ordinal >= import_table.size()) { + return NotFoundErrorBuilder(IREE_LOC) + << "Import ordinal " << ordinal + << " out of bounds of import table (" << import_table.size() + << ")"; + } + return import_table[ordinal]; + } + } + return NotFoundErrorBuilder(IREE_LOC) + << "Import ordinal " << ordinal << " not found"; +} + void Context::RegisterInvocation(Invocation* invocation) { { absl::MutexLock lock(&invocations_mutex_);
diff --git a/iree/rt/context.h b/iree/rt/context.h index 83b7ee4..d67b79a 100644 --- a/iree/rt/context.h +++ b/iree/rt/context.h
@@ -80,6 +80,11 @@ // reference is valid for the lifetime of the context. StatusOr<const Function> ResolveFunction(absl::string_view full_name) const; + // Resolves an imported function by import ordinal. The function reference is + // valid for the lifetime of the context. + StatusOr<const Function> ResolveImport(const Module* module, + int32_t ordinal) const; + private: // Resolves imports for the given module. StatusOr<ModuleImportTable> ResolveImports(Module* module);
diff --git a/iree/rt/disassembler.h b/iree/rt/disassembler.h new file mode 100644 index 0000000..52d91ee --- /dev/null +++ b/iree/rt/disassembler.h
@@ -0,0 +1,64 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef IREE_RT_DISASSEMBLER_H_ +#define IREE_RT_DISASSEMBLER_H_ + +#include <cstdint> +#include <ostream> +#include <vector> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "iree/base/status.h" +#include "iree/rt/function.h" +#include "iree/rt/source_location.h" + +namespace iree { +namespace rt { + +// A single disassembled instruction. +struct Instruction { + // Offset of the instruction within the function. + // The meaning of this is backend-dependent. + SourceOffset offset; + + // The first line of |long_text|. + absl::string_view short_text; + + // Human-readable text of the instruction. May contain multiple lines. + std::string long_text; +}; + +// Disassembles functions into instructions. +// +// Thread-safe. +class Disassembler { + public: + virtual ~Disassembler() = default; + + // Disassembles one or more instructions within the given function based on + // source offsets. + virtual StatusOr<std::vector<Instruction>> DisassembleInstructions( + const Function& function, SourceOffset offset, + int32_t instruction_count = INT32_MAX) const = 0; + + protected: + Disassembler() = default; +}; + +} // namespace rt +} // namespace iree + +#endif // IREE_RT_DISASSEMBLER_H_
diff --git a/iree/rt/instance.h b/iree/rt/instance.h index f5e3bc8..61fd544 100644 --- a/iree/rt/instance.h +++ b/iree/rt/instance.h
@@ -21,14 +21,7 @@ #include "iree/base/ref_ptr.h" #include "iree/hal/device_manager.h" #include "iree/rt/context.h" - -namespace iree { -namespace rt { -namespace debug { -class DebugServer; -} // namespace debug -} // namespace rt -} // namespace iree +#include "iree/rt/debug/debug_server.h" namespace iree { namespace rt { @@ -46,7 +39,8 @@ class Instance final : public RefObject<Instance> { public: // Creates an instance with an optional attached |debug_server|. - explicit Instance(std::unique_ptr<debug::DebugServer> debug_server = nullptr); + Instance() : Instance(nullptr) {} + explicit Instance(std::unique_ptr<debug::DebugServer> debug_server); ~Instance(); Instance(const Instance&) = delete; Instance& operator=(const Instance&) = delete;
diff --git a/iree/rt/invocation.cc b/iree/rt/invocation.cc index f35671e..0abe667 100644 --- a/iree/rt/invocation.cc +++ b/iree/rt/invocation.cc
@@ -72,7 +72,7 @@ // TODO(benvanik): fiber scheduling and such. auto execute_status = function.module()->Execute( - function, std::move(arguments), &results_value); + &invocation->stack_, function, std::move(arguments), &results_value); if (execute_status.ok()) { invocation->CompleteSuccess(std::move(results_value)); } else { @@ -82,12 +82,33 @@ return invocation; } +// static +StatusOr<ref_ptr<Invocation>> Invocation::Create( + ref_ptr<Context> context, const Function function, ref_ptr<Policy> policy, + absl::Span<const ref_ptr<Invocation>> dependencies, + absl::Span<const hal::BufferView> arguments) { + absl::InlinedVector<ref_ptr<Invocation>, 4> dependency_list; + dependency_list.reserve(dependencies.size()); + for (auto& dependency : dependencies) { + dependency_list.push_back(add_ref(dependency)); + } + absl::InlinedVector<hal::BufferView, 8> argument_list; + argument_list.reserve(arguments.size()); + for (auto& buffer_view : arguments) { + argument_list.push_back(buffer_view); + } + return Invocation::Create(std::move(context), function, std::move(policy), + std::move(dependency_list), + std::move(argument_list)); +} + Invocation::Invocation(ref_ptr<Context> context, const Function function, ref_ptr<Policy> policy) : id_(NextUniqueInvocationId()), context_(std::move(context)), function_(function), - policy_(std::move(policy)) { + policy_(std::move(policy)), + stack_(context_.get()) { IREE_TRACE_SCOPE0("Invocation::ctor"); context_->RegisterInvocation(this); }
diff --git a/iree/rt/invocation.h b/iree/rt/invocation.h index b2e79a5..600fd8a 100644 --- a/iree/rt/invocation.h +++ b/iree/rt/invocation.h
@@ -27,6 +27,7 @@ #include "iree/hal/buffer_view.h" #include "iree/rt/function.h" #include "iree/rt/policy.h" +#include "iree/rt/stack.h" #include "iree/rt/stack_trace.h" namespace iree { @@ -63,6 +64,10 @@ absl::InlinedVector<hal::BufferView, 8> arguments, absl::optional<absl::InlinedVector<hal::BufferView, 8>> results = absl::nullopt); + static StatusOr<ref_ptr<Invocation>> Create( + ref_ptr<Context> context, const Function function, ref_ptr<Policy> policy, + absl::Span<const ref_ptr<Invocation>> dependencies, + absl::Span<const hal::BufferView> arguments); ~Invocation(); @@ -126,6 +131,8 @@ const Function function_; ref_ptr<Policy> policy_; + Stack stack_; + absl::Mutex status_mutex_; Status completion_status_ ABSL_GUARDED_BY(status_mutex_) = UnavailableErrorBuilder(IREE_LOC);
diff --git a/iree/rt/module.h b/iree/rt/module.h index d81572e..1878d9d 100644 --- a/iree/rt/module.h +++ b/iree/rt/module.h
@@ -27,7 +27,9 @@ namespace iree { namespace rt { +class Disassembler; class SourceResolver; +class Stack; // Abstract compiled module interface for resolving functions. // @@ -50,6 +52,11 @@ // May be nullptr if debugging info has been stripped. virtual SourceResolver* source_resolver() const = 0; + // Returns a disassembler that can be used to disassemble functions in the + // module. May be nullptr if debugging info has been stripped or disassembly + // has been disabled as a compile option. + virtual Disassembler* disassembler() const = 0; + // A short human-readable string that matches the compiler formatting. virtual std::string DebugStringShort() const = 0; @@ -82,7 +89,7 @@ // Temporary until scheduler is built. virtual Status Execute( - const Function function, + Stack* stack, const Function function, absl::InlinedVector<hal::BufferView, 8> arguments, absl::InlinedVector<hal::BufferView, 8>* results) const = 0;
diff --git a/iree/rt/module_printer.cc b/iree/rt/module_printer.cc new file mode 100644 index 0000000..dd0267e --- /dev/null +++ b/iree/rt/module_printer.cc
@@ -0,0 +1,65 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "iree/rt/module_printer.h" + +#include <iomanip> + +#include "iree/rt/disassembler.h" +#include "iree/rt/source_resolver.h" + +namespace iree { +namespace rt { + +Status PrintModuleToStream(const Module& module, PrintModuleFlagBitfield flags, + std::ostream* stream) { + *stream << "Imports:\n"; + for (int i = 0; i < module.signature().import_function_count(); ++i) { + ASSIGN_OR_RETURN(auto function, module.LookupFunctionByOrdinal( + Function::Linkage::kImport, i)); + *stream << " " << i << ": " << function << "\n"; + } + *stream << "Exports:\n"; + for (int i = 0; i < module.signature().export_function_count(); ++i) { + ASSIGN_OR_RETURN(auto function, module.LookupFunctionByOrdinal( + Function::Linkage::kExport, i)); + *stream << " " << i << ": " << function << "\n"; + } + if (module.signature().internal_function_count()) { + *stream << "Internal:\n"; + auto* disassembler = module.disassembler(); + for (int i = 0; i < module.signature().internal_function_count(); ++i) { + ASSIGN_OR_RETURN(auto function, module.LookupFunctionByOrdinal( + Function::Linkage::kInternal, i)); + *stream << " " << i << ": " << function << "\n"; + if (disassembler && AllBitsSet(flags, PrintModuleFlag::kDisassemble)) { + auto instructions_or = + disassembler->DisassembleInstructions(function, 0); + if (IsUnavailable(instructions_or.status())) continue; + for (const auto& instruction : instructions_or.ValueOrDie()) { + *stream << " " << std::setw(6) << instruction.offset << ": " + << instruction.long_text << "\n"; + } + } + } + } + return OkStatus(); +} + +Status PrintModuleToStream(const Module& module, std::ostream* stream) { + return PrintModuleToStream(module, PrintModuleFlag::kNone, stream); +} + +} // namespace rt +} // namespace iree
diff --git a/iree/vm/module_printer.h b/iree/rt/module_printer.h similarity index 67% rename from iree/vm/module_printer.h rename to iree/rt/module_printer.h index ee35fb3..945dbbd 100644 --- a/iree/vm/module_printer.h +++ b/iree/rt/module_printer.h
@@ -12,33 +12,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef IREE_VM_MODULE_PRINTER_H_ -#define IREE_VM_MODULE_PRINTER_H_ +#ifndef IREE_RT_MODULE_PRINTER_H_ +#define IREE_RT_MODULE_PRINTER_H_ #include <ostream> #include "iree/base/bitfield.h" #include "iree/base/status.h" -#include "iree/vm/module.h" -#include "iree/vm/opcode_info.h" +#include "iree/rt/module.h" namespace iree { -namespace vm { +namespace rt { enum class PrintModuleFlag { kNone = 0, - kIncludeSourceMapping = 1, + kDisassemble = 1 << 0, }; IREE_BITFIELD(PrintModuleFlag); using PrintModuleFlagBitfield = PrintModuleFlag; // Prints all functions within the module to the given |stream|. -Status PrintModuleToStream(OpcodeTable opcode_table, const Module& module, +Status PrintModuleToStream(const Module& module, std::ostream* stream); +Status PrintModuleToStream(const Module& module, PrintModuleFlagBitfield flags, std::ostream* stream); -Status PrintModuleToStream(OpcodeTable opcode_table, const Module& module, - PrintModuleFlagBitfield flags, std::ostream* stream); -} // namespace vm +} // namespace rt } // namespace iree -#endif // IREE_VM_MODULE_PRINTER_H_ +#endif // IREE_RT_MODULE_PRINTER_H_
diff --git a/iree/rt/source_location.cc b/iree/rt/source_location.cc index c61645f..835905b 100644 --- a/iree/rt/source_location.cc +++ b/iree/rt/source_location.cc
@@ -14,14 +14,18 @@ #include "iree/rt/source_location.h" +#include <sstream> + #include "iree/rt/source_resolver.h" namespace iree { namespace rt { std::string SourceLocation::DebugStringShort() const { - // TODO(benvanik): ask source resolver. - return "<source>"; + if (is_unknown()) return "(unknown)"; + std::ostringstream stream; + resolver_->PrintSourceLocation(resolver_args_, &stream); + return stream.str(); } } // namespace rt
diff --git a/iree/rt/source_location.h b/iree/rt/source_location.h index 9939e15..7db98ec 100644 --- a/iree/rt/source_location.h +++ b/iree/rt/source_location.h
@@ -15,6 +15,7 @@ #ifndef IREE_RT_SOURCE_LOCATION_H_ #define IREE_RT_SOURCE_LOCATION_H_ +#include <array> #include <cstdint> #include <cstring> #include <ostream> @@ -31,6 +32,10 @@ // hash table. using SourceOffset = int64_t; +// Implementation-defined opaque args stored within source locations that can be +// used by a SourceResolver to map back to its internal storage. +using SourceResolverArgs = std::array<uint64_t, 2>; + // A location within a source file. // Only valid for the lifetime of the SourceResolver that returned it. class SourceLocation final { @@ -40,15 +45,12 @@ // Returns true if the two source locations reference the same target. inline static bool Equal(const SourceLocation& a, const SourceLocation& b) { - return a.resolver_ == b.resolver_ && - std::memcmp(a.resolver_args_, b.resolver_args_, - sizeof(a.resolver_args_)) == 0; + return a.resolver_ == b.resolver_ && a.resolver_args_ == b.resolver_args_; } SourceLocation() = default; - SourceLocation(SourceResolver* resolver, uintptr_t resolver_args[2]) - : resolver_(resolver), - resolver_args_{resolver_args[0], resolver_args[1]} {} + SourceLocation(SourceResolver* resolver, SourceResolverArgs resolver_args) + : resolver_(resolver), resolver_args_(resolver_args) {} // A short one-line human readable string (such as file/line number). std::string DebugStringShort() const; @@ -63,7 +65,7 @@ private: SourceResolver* resolver_ = nullptr; - uintptr_t resolver_args_[2] = {0, 0}; + SourceResolverArgs resolver_args_ = {0, 0}; }; inline bool operator==(const SourceLocation& a, const SourceLocation& b) {
diff --git a/iree/rt/source_resolver.h b/iree/rt/source_resolver.h index fd677a2..3ceb1b9 100644 --- a/iree/rt/source_resolver.h +++ b/iree/rt/source_resolver.h
@@ -15,14 +15,21 @@ #ifndef IREE_RT_SOURCE_RESOLVER_H_ #define IREE_RT_SOURCE_RESOLVER_H_ +#include <cstdint> +#include <ostream> +#include <vector> + +#include "absl/strings/string_view.h" #include "absl/types/optional.h" +#include "iree/base/status.h" #include "iree/rt/function.h" #include "iree/rt/source_location.h" namespace iree { namespace rt { -// Resolves offsets within functions to SourceLocations. +// Resolves offsets within functions to SourceLocations and provides source +// language services. // // Thread-safe. class SourceResolver { @@ -34,6 +41,11 @@ virtual absl::optional<SourceLocation> ResolveFunctionOffset( const Function& function, SourceOffset offset) = 0; + // Converts a source location to a human-readable string, commonly in a single + // line denoting an original source file location (such as path:line:col). + virtual void PrintSourceLocation(SourceResolverArgs resolver_args, + std::ostream* stream) const = 0; + // TODO(benvanik): query local variable names. // TODO(benvanik): step target calculation (relative mapping).
diff --git a/iree/rt/stack.cc b/iree/rt/stack.cc new file mode 100644 index 0000000..f4f300f --- /dev/null +++ b/iree/rt/stack.cc
@@ -0,0 +1,60 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "iree/rt/stack.h" + +#include <iterator> + +#include "absl/strings/str_join.h" +#include "iree/base/status.h" + +namespace iree { +namespace rt { + +constexpr int Stack::kMaxStackDepth; + +Stack::Stack(Context* context) : context_(context) {} + +Stack::~Stack() = default; + +StatusOr<StackFrame*> Stack::PushFrame(Function function) { + if (stack_depth_ + 1 > kMaxStackDepth) { + return InternalErrorBuilder(IREE_LOC) + << "Max stack depth of " << kMaxStackDepth << " exceeded"; + } + frames_[stack_depth_++] = StackFrame(function); + + // TODO(benvanik): WTF scope enter. + + return current_frame(); +} + +Status Stack::PopFrame() { + if (stack_depth_ == 0) { + return InternalErrorBuilder(IREE_LOC) << "Unbalanced stack pop"; + } + + // TODO(benvanik): WTF scope leave. + + --stack_depth_; + frames_[stack_depth_] = {}; + return OkStatus(); +} + +std::string Stack::DebugString() const { + return absl::StrJoin(frames(), "\n", StackFrameFormatter()); +} + +} // namespace rt +} // namespace iree
diff --git a/iree/rt/stack.h b/iree/rt/stack.h new file mode 100644 index 0000000..a9547fe --- /dev/null +++ b/iree/rt/stack.h
@@ -0,0 +1,85 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef IREE_RT_STACK_H_ +#define IREE_RT_STACK_H_ + +#include <functional> + +#include "absl/types/span.h" +#include "iree/base/status.h" +#include "iree/rt/stack_frame.h" + +namespace iree { +namespace rt { + +class Context; + +// A runtime call stack for managing stack frames. +// The frames within a stack may be from different backends and may provide +// varying levels of information based on capabilities. +// +// Thread-compatible. Do not attempt to investigate a stack while another thread +// may be mutating it! +class Stack final { + public: + static constexpr int kMaxStackDepth = 32; + + explicit Stack(Context* context); + Stack(const Stack&) = delete; + Stack& operator=(const Stack&) = delete; + ~Stack(); + + // Context defining the module and global workspaces. + Context* context() const { return context_; } + + // All stack frames within the stack. + absl::Span<StackFrame> frames() { + return absl::MakeSpan(frames_).subspan(0, stack_depth_); + } + absl::Span<const StackFrame> frames() const { + return absl::MakeConstSpan(frames_).subspan(0, stack_depth_); + } + + // The current stack frame. + StackFrame* current_frame() { + return stack_depth_ > 0 ? &frames_[stack_depth_ - 1] : nullptr; + } + + // The stack frame of the caller of the current function. + StackFrame* caller_frame() { + return stack_depth_ > 1 ? &frames_[stack_depth_ - 2] : nullptr; + } + + StatusOr<StackFrame*> PushFrame(Function function); + Status PopFrame(); + + // Returns a full stack frame listing in human-readable form. + std::string DebugString() const; + + private: + Context* context_ = nullptr; + std::array<StackFrame, kMaxStackDepth> frames_; + int stack_depth_ = 0; +}; + +inline std::ostream& operator<<(std::ostream& stream, const Stack& stack) { + stream << stack.DebugString(); + return stream; +} + +} // namespace rt +} // namespace iree + +#endif // IREE_RT_STACK_H_
diff --git a/iree/rt/stack_frame.h b/iree/rt/stack_frame.h index 573e48e..bb77ef4 100644 --- a/iree/rt/stack_frame.h +++ b/iree/rt/stack_frame.h
@@ -17,6 +17,7 @@ #include <ostream> +#include "absl/types/span.h" #include "iree/rt/function.h" #include "iree/rt/module.h" #include "iree/rt/source_location.h" @@ -24,6 +25,12 @@ namespace iree { namespace rt { +// TODO(benvanik): allocate in-place from an arena. +// Register table used within a stack frame. +struct Registers { + std::vector<hal::BufferView> buffer_views; +}; + // A single frame on the call stack containing current execution state and // register values. // @@ -35,12 +42,15 @@ // but instead just routing to the real storage via indirection. If the debugger // is not attached and no errors are hit then no additional bookkeeping is done. // -// Thread-compatible, as is the owning StackTrace. +// Thread-compatible, as is the owning Stack/StackTrace. class StackFrame final { public: StackFrame() = default; - explicit StackFrame(Function function, SourceOffset offset) - : function_(function), offset_(offset) {} + explicit StackFrame(Function function) : function_(function) {} + StackFrame(Function function, SourceOffset offset, Registers registers) + : function_(function), + offset_(offset), + registers_(std::move(registers)) {} StackFrame(const StackFrame&) = delete; StackFrame& operator=(const StackFrame&) = delete; StackFrame(StackFrame&&) = default; @@ -57,15 +67,17 @@ // treat them as opaque and must use the SourceResolver to compute new // offsets (such as 'next offset'). SourceOffset offset() const { return offset_; } + SourceOffset* mutable_offset() { return &offset_; } // Returns a source location, if available, for the current offset within the // target function. absl::optional<SourceLocation> source_location() const; - // TODO(benvanik): register access: - // query total register layout for stack frame - // get register in stack frame - // set register in stack frame + // Registers used within the stack frame. + // Storage is implementation-defined and is valid only for the lifetime of the + // frame. + const Registers& registers() const { return registers_; } + Registers* mutable_registers() { return ®isters_; } // A short human-readable string for the frame; a single line. std::string DebugStringShort() const; @@ -73,6 +85,13 @@ private: Function function_; SourceOffset offset_ = 0; + Registers registers_; +}; + +struct StackFrameFormatter { + void operator()(std::string* out, const StackFrame& stack_frame) const { + out->append(stack_frame.DebugStringShort()); + } }; inline std::ostream& operator<<(std::ostream& stream,
diff --git a/iree/rt/stack_trace.cc b/iree/rt/stack_trace.cc index a5fdf33..ace8803 100644 --- a/iree/rt/stack_trace.cc +++ b/iree/rt/stack_trace.cc
@@ -20,14 +20,6 @@ namespace iree { namespace rt { -namespace { -struct StackFrameFormatter { - void operator()(std::string* out, const StackFrame& stack_frame) const { - out->append(stack_frame.DebugStringShort()); - } -}; -} // namespace - std::string StackTrace::DebugString() const { return absl::StrJoin(frames_, "\n", StackFrameFormatter()); }
diff --git a/iree/rt/stack_trace.h b/iree/rt/stack_trace.h index 0c0612b..beca466 100644 --- a/iree/rt/stack_trace.h +++ b/iree/rt/stack_trace.h
@@ -25,12 +25,13 @@ namespace iree { namespace rt { -// A snapshot of the runtime callstack providing access to stack frames. +// A snapshot of a stack at a point in time. // The frames within a stack may be from different backends and may provide // varying levels of information based on capabilities. // -// Thread-compatible. Execution on one thread and stack manipulation on another -// must be externally synchronized by the caller. +// Depending on the capture options the trace may contain references to register +// values (such as buffers) from the time of capture. If the buffers were +// modified after the capture was taken those results will be reflected! class StackTrace final { public: StackTrace() = default; @@ -45,16 +46,6 @@ return absl::MakeConstSpan(frames_); } - // The current stack frame. - const StackFrame* current_frame() const { - return !frames_.empty() ? &frames_[frames_.size() - 1] : nullptr; - } - - // The stack frame of the caller of the current function. - const StackFrame* caller_frame() const { - return frames_.size() > 1 ? &frames_[frames_.size() - 2] : nullptr; - } - // Returns a full stack frame listing in human-readable form. std::string DebugString() const;
diff --git a/iree/samples/CMakeLists.txt b/iree/samples/CMakeLists.txt index 48bf62c..ae75ec9 100644 --- a/iree/samples/CMakeLists.txt +++ b/iree/samples/CMakeLists.txt
@@ -13,4 +13,4 @@ # limitations under the License. add_subdirectory(hal) -add_subdirectory(vm) +add_subdirectory(rt)
diff --git a/iree/samples/hal/BUILD b/iree/samples/hal/BUILD index f29844b..8fa22bf 100644 --- a/iree/samples/hal/BUILD +++ b/iree/samples/hal/BUILD
@@ -2,14 +2,14 @@ # These do not rely on higher layers of the system (such as the VM or runtime). load("//iree:build_defs.bzl", "PLATFORM_VULKAN_TEST_DEPS") -load("//iree/tools:compilation.bzl", "iree_module") +load("//iree/tools:compilation.bzl", "iree_bytecode_module") package( default_visibility = ["//visibility:public"], licenses = ["notice"], # Apache 2.0 ) -iree_module( +iree_bytecode_module( name = "simple_compute_test_module", srcs = ["simple_compute_test.mlir"], cc_namespace = "iree::hal::samples",
diff --git a/iree/samples/hal/simple_compute_test.cc b/iree/samples/hal/simple_compute_test.cc index ac2986b..43f0c48 100644 --- a/iree/samples/hal/simple_compute_test.cc +++ b/iree/samples/hal/simple_compute_test.cc
@@ -21,8 +21,8 @@ // imports requiring runtime support, uses floats exclusively (as that's assumed // available everywhere), etc. // -// The `iree_module` build rule is used to translate the MLIR to the module -// flatbuffer. Additional target support can be defined there. +// The `iree_bytecode_module` build rule is used to translate the MLIR to the +// module flatbuffer. Additional target support can be defined there. #include "gmock/gmock.h" #include "gtest/gtest.h"
diff --git a/iree/samples/vm/BUILD b/iree/samples/rt/BUILD similarity index 69% rename from iree/samples/vm/BUILD rename to iree/samples/rt/BUILD index 2a1a94c..2712b07 100644 --- a/iree/samples/vm/BUILD +++ b/iree/samples/rt/BUILD
@@ -1,21 +1,21 @@ -# Samples demonstrating use of the VM API. +# Samples demonstrating use of the RT API. -load("//iree/tools:compilation.bzl", "iree_module") +load("//iree/tools:compilation.bzl", "iree_bytecode_module") package( default_visibility = ["//visibility:public"], licenses = ["notice"], # Apache 2.0 ) -iree_module( - name = "simple_module_test_module", +iree_bytecode_module( + name = "simple_module_test_bytecode_module", srcs = ["simple_module_test.mlir"], - cc_namespace = "iree::vm::samples", + cc_namespace = "iree::rt::samples", ) cc_test( - name = "simple_module_test", - srcs = ["simple_module_test.cc"], + name = "bytecode_module_test", + srcs = ["bytecode_module_test.cc"], data = [ # When building with --config=asan you must specify the following # envvar when using Vulkan + a local Nvidia GPU: @@ -23,20 +23,18 @@ "//iree/tools:sanitizer_suppressions.txt", ], deps = [ - ":simple_module_test_module_cc", + ":simple_module_test_bytecode_module_cc", "@com_google_googletest//:gtest_main", "@com_google_absl//absl/strings", "//iree/base:flatbuffer_util", + "//iree/base:status", "//iree/base:status_matchers", "//iree/hal:buffer_view", - "//iree/hal:command_buffer", - "//iree/hal:command_queue", "//iree/hal:driver_registry", + "//iree/rt", "//iree/schemas", - "//iree/base:status", - "//iree/vm:fiber_state", - "//iree/vm:instance", - "//iree/vm:sequencer_context", + "//iree/vm:bytecode_module", + "//iree/vm:sequencer_module", # These are the drivers we support running with and can produce # executables for from the source MLIR.
diff --git a/iree/samples/vm/CMakeLists.txt b/iree/samples/rt/CMakeLists.txt similarity index 82% rename from iree/samples/vm/CMakeLists.txt rename to iree/samples/rt/CMakeLists.txt index 1c36407..ec6ee74 100644 --- a/iree/samples/vm/CMakeLists.txt +++ b/iree/samples/rt/CMakeLists.txt
@@ -14,9 +14,9 @@ iree_cc_test( NAME - simple_module_test + bytecode_module_test SRCS - "simple_module_test.cc" + "bytecode_module_test.cc" DEPS absl::strings gtest_main @@ -24,13 +24,10 @@ iree::base::status iree::base::status_matchers iree::hal::buffer_view - iree::hal::command_buffer - iree::hal::command_queue iree::hal::driver_registry iree::schemas - iree::vm::fiber_state - iree::vm::instance - iree::vm::sequencer_context + iree::rt + iree::vm::bytecode_module # Enabled drivers: iree::hal::interpreter::interpreter_driver_module iree::hal::vulkan::vulkan_driver_module
diff --git a/iree/samples/vm/simple_module_test.cc b/iree/samples/rt/bytecode_module_test.cc similarity index 79% rename from iree/samples/vm/simple_module_test.cc rename to iree/samples/rt/bytecode_module_test.cc index 8db859e..2fdc7cf 100644 --- a/iree/samples/vm/simple_module_test.cc +++ b/iree/samples/rt/bytecode_module_test.cc
@@ -25,6 +25,8 @@ // The `iree_module` build rule is used to translate the MLIR to the module // flatbuffer. Additional HAL backend target support can be defined there. +#include "iree/vm/bytecode_module.h" + #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/strings/str_replace.h" @@ -32,23 +34,20 @@ #include "iree/base/status.h" #include "iree/base/status_matchers.h" #include "iree/hal/buffer_view.h" -#include "iree/hal/command_buffer.h" -#include "iree/hal/command_queue.h" #include "iree/hal/driver_registry.h" -#include "iree/samples/vm/simple_module_test_module.h" +#include "iree/rt/context.h" +#include "iree/rt/instance.h" +#include "iree/samples/rt/simple_module_test_bytecode_module.h" #include "iree/schemas/module_def_generated.h" -#include "iree/vm/fiber_state.h" -#include "iree/vm/instance.h" -#include "iree/vm/sequencer_context.h" +#include "iree/vm/sequencer_module.h" namespace iree { -namespace vm { +namespace rt { namespace samples { namespace { -using iree::hal::BufferView; - -using ModuleFile = FlatBufferFile<ModuleDef>; +using ::iree::hal::BufferView; +using ::iree::vm::ModuleFile; struct TestParams { // HAL driver to use for the test. @@ -77,7 +76,7 @@ }; TEST_P(SimpleModuleTest, RunOnce) { - auto instance = std::make_shared<Instance>(); + auto instance = make_ref<Instance>(); // Create driver for this test (based on params) and then get a default // device. @@ -105,22 +104,20 @@ // Make a new context and load the precompiled module file (from // simple_module_test.mlir) into it. LOG(INFO) << "Loading simple_module_test.mlir..."; - SequencerContext context(instance); - const auto* module_file_toc = simple_module_test_module_create(); - ASSERT_OK_AND_ASSIGN( - auto module_file, - ModuleFile::WrapBuffer(ModuleDefIdentifier(), - absl::MakeSpan(reinterpret_cast<const uint8_t*>( - module_file_toc->data), - module_file_toc->size))); + auto policy = make_ref<Policy>(); + Context context(add_ref(instance), add_ref(policy)); + const auto* module_file_toc = simple_module_test_bytecode_module_create(); + ASSERT_OK_AND_ASSIGN(auto module_file, + vm::ModuleFile::WrapBuffer( + ModuleDefIdentifier(), + absl::MakeSpan(reinterpret_cast<const uint8_t*>( + module_file_toc->data), + module_file_toc->size))); ASSERT_OK_AND_ASSIGN(auto main_module, - Module::FromFile(std::move(module_file))); + vm::SequencerModule::FromFile(std::move(module_file))); ASSERT_OK(context.RegisterModule(std::move(main_module))); LOG(INFO) << "Module loaded and context is ready for use"; - // In this sample we just have a single fiber. - FiberState fiber_state(instance); - // Allocate buffers that can be mapped on the CPU and that can also be used // on the device. Not all devices support this, but the ones we have now do. LOG(INFO) << "Creating I/O buffers..."; @@ -140,14 +137,17 @@ // Call into the @simple_mul function. LOG(INFO) << "Calling @simple_mul..."; - std::vector<BufferView> args{ + absl::InlinedVector<BufferView, 8> args{ BufferView{add_ref(arg0_buffer), {kElementCount}, sizeof(float)}, BufferView{add_ref(arg1_buffer), {kElementCount}, sizeof(float)}, }; - std::vector<BufferView> results{1}; - ASSERT_OK_AND_ASSIGN(auto simple_mul, context.LookupExport("simple_mul")); - ASSERT_OK(context.Invoke(&fiber_state, simple_mul, absl::MakeSpan(args), - absl::MakeSpan(results))); + ASSERT_OK_AND_ASSIGN(auto simple_mul, + context.ResolveFunction("module.simple_mul")); + ASSERT_OK_AND_ASSIGN(auto invocation, + Invocation::Create(add_ref(&context), simple_mul, + nullptr, {}, std::move(args))); + ASSERT_OK(invocation->Await(absl::InfiniteFuture())); + ASSERT_OK_AND_ASSIGN(auto results, invocation->ConsumeResults()); // Read back the results and ensure we got the right values. LOG(INFO) << "Reading back results..."; @@ -166,5 +166,5 @@ } // namespace } // namespace samples -} // namespace vm +} // namespace rt } // namespace iree
diff --git a/iree/samples/vm/simple_module_test.mlir b/iree/samples/rt/simple_module_test.mlir similarity index 100% rename from iree/samples/vm/simple_module_test.mlir rename to iree/samples/rt/simple_module_test.mlir
diff --git a/iree/tools/BUILD b/iree/tools/BUILD index 6d15ade..3fa849c 100644 --- a/iree/tools/BUILD +++ b/iree/tools/BUILD
@@ -37,6 +37,8 @@ "@com_google_absl//absl/flags:flag", "@com_google_absl//absl/strings", "//iree/base:source_location", + "//iree/rt", + "//iree/vm:sequencer_module", "@llvm//:support", "@local_config_mlir//:IR", "@local_config_mlir//:Parser", @@ -48,19 +50,14 @@ "//iree/compiler/Translation/SPIRV", "//iree/hal:buffer_view_string_util", "//iree/hal:driver_registry", + "//iree/schemas", + "//iree/rt/debug:debug_server_flags", + ] + PLATFORM_VULKAN_DEPS + [ "//iree/hal/interpreter:interpreter_driver_module", - "//iree/hal/vulkan:vulkan_driver_module", # TODO(b/142004903): enable when Dawn HAL implementation is functional # "//iree/hal/dawn:dawn_driver_module", - "//iree/schemas", - "//iree/vm:bytecode_tables_sequencer", - "//iree/vm:fiber_state", - "//iree/vm:instance", - "//iree/vm:module", - "//iree/vm:module_printer", - "//iree/vm:sequencer_context", - "//iree/rt/debug:debug_server_flags", - ] + PLATFORM_VULKAN_DEPS, + "//iree/hal/vulkan:vulkan_driver_module", + ], ) cc_binary( @@ -94,16 +91,10 @@ "//iree/hal:buffer_view_string_util", "//iree/hal:driver_registry", "//iree/hal/interpreter:interpreter_driver_module", + "//iree/rt", "//iree/rt/debug:debug_server_flags", "//iree/schemas", - "//iree/vm:bytecode_printer", - "//iree/vm:bytecode_tables_sequencer", - "//iree/vm:fiber_state", - "//iree/vm:function", - "//iree/vm:instance", - "//iree/vm:module", - "//iree/vm:module_printer", - "//iree/vm:sequencer_context", + "//iree/vm:sequencer_module", "@com_google_absl//absl/flags:flag", "@com_google_absl//absl/strings", ],
diff --git a/iree/tools/compilation.bzl b/iree/tools/compilation.bzl index 5d1ffe5..b232099 100644 --- a/iree/tools/compilation.bzl +++ b/iree/tools/compilation.bzl
@@ -3,7 +3,7 @@ load("//build_tools/embed_data:build_defs.bzl", "cc_embed_data") # TODO(benvanik): port to a full starlark rule, document, etc. -def iree_module( +def iree_bytecode_module( name, srcs, cc_namespace = None,
diff --git a/iree/tools/debugger/BUILD b/iree/tools/debugger/BUILD index b1f432b..e3b90a4 100644 --- a/iree/tools/debugger/BUILD +++ b/iree/tools/debugger/BUILD
@@ -7,7 +7,8 @@ # By default the IREE runtime does not compile in debug support. To link it in # pass --define=IREE_DEBUG=1 to bazel builds of the runtime. -load("//third_party/emscripten:split_transition_defs.bzl", "auto_wasm_binary") +# TODO(benvanik): re-enable debugger after refactoring. +# load("//third_party/emscripten:split_transition_defs.bzl", "auto_wasm_binary") package( default_visibility = ["//visibility:public"], @@ -41,10 +42,6 @@ # "//iree/base:status", # "//iree/rt/debug:debug_client", # "//iree/schemas", -# "//iree/vm:bytecode_printer", -# "//iree/vm:bytecode_tables_sequencer", -# "//iree/vm:module", -# "//iree/vm:source_map", # ], # ) #
diff --git a/iree/tools/debugger/debug_app.cc b/iree/tools/debugger/debug_app.cc index 793f4a1..303979e 100644 --- a/iree/tools/debugger/debug_app.cc +++ b/iree/tools/debugger/debug_app.cc
@@ -31,10 +31,8 @@ #include "iree/base/status.h" #include "iree/rt/debug/debug_client.h" #include "iree/schemas/debug_service_generated.h" -#include "iree/vm/bytecode_printer.h" +#include "iree/vm/bytecode_module.h" #include "iree/vm/bytecode_tables_sequencer.h" -#include "iree/vm/module.h" -#include "iree/vm/source_map.h" namespace iree { namespace rt { @@ -1311,21 +1309,7 @@ auto* remote_module = document->function->module(); auto* remote_function = document->function; - ASSIGN_OR_RETURN(auto module, vm::Module::FromDef(remote_module->def())); - - // TODO(benvanik): source map support. - // Want line count including source lines, IR lines, and bytecode lines. - // May want lower level (JIT/etc) lines too. - - // TODO(benvanik): bytecode iterator for richer display. - auto source_map_resolver = vm::SourceMapResolver::FromFunction( - module->def(), remote_function->ordinal()); - vm::BytecodePrinter printer(vm::sequencer_opcode_table(), - module->function_table(), - module->executable_table(), source_map_resolver); - ASSIGN_OR_RETURN(std::string full_string, - printer.Print(*remote_function->bytecode())); - document->bytecode_info.lines = absl::StrSplit(full_string, '\n'); + document->bytecode_info.lines = remote_function->name(); return OkStatus(); }
diff --git a/iree/tools/run_mlir_main.cc b/iree/tools/run_mlir_main.cc index 360745e..dfa3486 100644 --- a/iree/tools/run_mlir_main.cc +++ b/iree/tools/run_mlir_main.cc
@@ -47,14 +47,14 @@ #include "iree/compiler/Translation/Sequencer/SequencerModuleTranslation.h" #include "iree/hal/buffer_view_string_util.h" #include "iree/hal/driver_registry.h" +#include "iree/rt/context.h" #include "iree/rt/debug/debug_server_flags.h" +#include "iree/rt/instance.h" +#include "iree/rt/invocation.h" +#include "iree/rt/module.h" +#include "iree/rt/module_printer.h" #include "iree/schemas/module_def_generated.h" -#include "iree/vm/bytecode_tables_sequencer.h" -#include "iree/vm/fiber_state.h" -#include "iree/vm/instance.h" -#include "iree/vm/module.h" -#include "iree/vm/module_printer.h" -#include "iree/vm/sequencer_context.h" +#include "iree/vm/sequencer_module.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/SourceMgr.h" #include "mlir/IR/Attributes.h" @@ -92,9 +92,8 @@ namespace { using ::iree::hal::BufferView; -using ::iree::vm::Function; -using ::iree::vm::Module; -using ::iree::vm::ModuleFile; +using ::iree::rt::Function; +using ::iree::rt::Module; // Returns a driver name capable of handling input from the given backend. std::string BackendToDriverName(std::string backend) { @@ -107,7 +106,7 @@ } // Prepares a module for evaluation by running MLIR import and IREE translation. -StatusOr<std::unique_ptr<Module>> PrepareModule( +StatusOr<ref_ptr<Module>> PrepareModule( std::string target_backend, std::unique_ptr<llvm::MemoryBuffer> file_buffer) { mlir::MLIRContext context; @@ -142,9 +141,9 @@ // Wrap module in a file handle. ASSIGN_OR_RETURN(auto iree_module_file, - ModuleFile::FromBuffer(ModuleDefIdentifier(), - std::move(iree_module_bytes))); - return Module::FromFile(std::move(iree_module_file)); + vm::ModuleFile::FromBuffer(ModuleDefIdentifier(), + std::move(iree_module_bytes))); + return vm::SequencerModule::FromFile(std::move(iree_module_file)); } // Parses a list of input shapes and values from a string of newline-separated @@ -196,25 +195,22 @@ } // Evaluates a single function in its own fiber, printing the results to stdout. -Status EvaluateFunction(std::shared_ptr<vm::Instance> instance, - vm::SequencerContext* context, +Status EvaluateFunction(const ref_ptr<rt::Context>& context, hal::Allocator* allocator, const Function& function) { - // Setup our dummy fiber we will run with. - vm::FiberState fiber_state(instance); - std::cout << "EXEC @" << function.name() << std::endl; - // Marshal inputs. - ASSIGN_OR_RETURN(std::vector<BufferView> args, - ParseInputsFromFlags(allocator)); - std::vector<BufferView> results; - results.resize(function.result_count()); + // Create invocation that will perform the execution. + ASSIGN_OR_RETURN(auto arguments, ParseInputsFromFlags(allocator)); + ASSIGN_OR_RETURN( + auto invocation, + rt::Invocation::Create(add_ref(context), function, make_ref<rt::Policy>(), + {}, absl::MakeConstSpan(arguments))); - // Call into the main function. - RETURN_IF_ERROR(context->Invoke(&fiber_state, function, absl::MakeSpan(args), - absl::MakeSpan(results))); + // Wait until invocation completes. + RETURN_IF_ERROR(invocation->Await(absl::InfiniteFuture())); // Print outputs. + ASSIGN_OR_RETURN(auto results, invocation->ConsumeResults()); RETURN_IF_ERROR(OutputFunctionResults(function, absl::MakeSpan(results))); return OkStatus(); @@ -222,35 +218,33 @@ // Evaluates all exported functions within given module. Status EvaluateFunctions(absl::string_view target_backend, - std::unique_ptr<Module> module) { + ref_ptr<Module> module) { // Create the context we'll use for this (ensuring that we can't interfere // with other running evaluations, such as when in a multithreaded test // runner). ASSIGN_OR_RETURN(auto debug_server, rt::debug::CreateDebugServerFromFlags()); - auto instance = std::make_shared<vm::Instance>(); + auto instance = make_ref<rt::Instance>(std::move(debug_server)); ASSIGN_OR_RETURN(auto driver, hal::DriverRegistry::shared_registry()->Create( target_backend)); ASSIGN_OR_RETURN(auto device, driver->CreateDefaultDevice()); RETURN_IF_ERROR(instance->device_manager()->RegisterDevice(device)); - vm::SequencerContext context(instance); if (absl::GetFlag(FLAGS_print_bytecode)) { - vm::PrintModuleFlagBitfield print_flags = vm::PrintModuleFlag::kNone; - RETURN_IF_ERROR(vm::PrintModuleToStream(vm::sequencer_opcode_table(), - *module, print_flags, &std::cout)); + RETURN_IF_ERROR(rt::PrintModuleToStream( + *module, rt::PrintModuleFlag::kDisassemble, &std::cout)); } - // Register module with the context. - RETURN_IF_ERROR(context.RegisterModule(std::move(module))); - // Evaluate all exported functions. - for (auto& module : context.modules()) { - for (int function_ordinal : *module->def().function_table()->exports()) { - ASSIGN_OR_RETURN(auto function, module->function_table().LookupFunction( - function_ordinal)); - RETURN_IF_ERROR( - EvaluateFunction(instance, &context, device->allocator(), function)); - } + auto policy = make_ref<rt::Policy>(); + for (int i = 0; i < module->signature().export_function_count(); ++i) { + // Setup a new context for this invocation. + auto context = make_ref<rt::Context>(add_ref(instance), add_ref(policy)); + RETURN_IF_ERROR(context->RegisterModule(add_ref(module))); + + // Invoke the function and print results. + ASSIGN_OR_RETURN(auto function, module->LookupFunctionByOrdinal( + rt::Function::Linkage::kExport, i)); + RETURN_IF_ERROR(EvaluateFunction(context, device->allocator(), function)); } RETURN_IF_ERROR(instance->device_manager()->UnregisterDevice(device.get()));
diff --git a/iree/tools/run_module_main.cc b/iree/tools/run_module_main.cc index 5fefbfc..be634ee 100644 --- a/iree/tools/run_module_main.cc +++ b/iree/tools/run_module_main.cc
@@ -27,23 +27,19 @@ #include "iree/base/status.h" #include "iree/hal/buffer_view_string_util.h" #include "iree/hal/driver_registry.h" +#include "iree/rt/context.h" #include "iree/rt/debug/debug_server_flags.h" +#include "iree/rt/instance.h" +#include "iree/rt/module_printer.h" #include "iree/schemas/module_def_generated.h" -#include "iree/vm/bytecode_printer.h" -#include "iree/vm/bytecode_tables_sequencer.h" -#include "iree/vm/fiber_state.h" -#include "iree/vm/function.h" -#include "iree/vm/instance.h" -#include "iree/vm/module.h" -#include "iree/vm/module_printer.h" -#include "iree/vm/sequencer_context.h" +#include "iree/vm/sequencer_module.h" ABSL_FLAG(std::string, main_module, "", "Main module with entry point."); ABSL_FLAG(std::string, main_function, "", "Function within the main module to execute."); -ABSL_FLAG(bool, print_source_info, false, - "Prints source map information in bytecode output."); +ABSL_FLAG(bool, print_disassembly, true, + "Prints bytecode disassembly for the module."); ABSL_FLAG(std::string, input_values, "", "Input shapes and optional values."); ABSL_FLAG(std::string, input_file, "", @@ -54,18 +50,15 @@ "binary/signed int/unsigned int/float)."); namespace iree { -namespace vm { namespace { -using ::iree::hal::BufferView; - // Parses a list of input shapes and values from a string of newline-separated // inputs. Expects the contents to have one value per line with each value // listed as // [shape]xtype=[value] // Example: // 4x4xi8=0,1,2,3 -StatusOr<std::vector<BufferView>> ParseInputsFromFlags( +StatusOr<std::vector<hal::BufferView>> ParseInputsFromFlags( hal::Allocator* allocator) { std::string file_contents; if (!absl::GetFlag(FLAGS_input_values).empty()) { @@ -75,7 +68,7 @@ ASSIGN_OR_RETURN(file_contents, file_io::GetFileContents(absl::GetFlag(FLAGS_input_file))); } - std::vector<BufferView> inputs; + std::vector<hal::BufferView> inputs; for (const auto& line : absl::StrSplit(file_contents, '\n', absl::SkipWhitespace())) { ASSIGN_OR_RETURN(auto input, @@ -89,81 +82,67 @@ Status Run() { ASSIGN_OR_RETURN(auto debug_server, rt::debug::CreateDebugServerFromFlags()); - auto instance = std::make_shared<Instance>(); + auto instance = make_ref<rt::Instance>(std::move(debug_server)); ASSIGN_OR_RETURN(auto driver, hal::DriverRegistry::shared_registry()->Create( "interpreter")); ASSIGN_OR_RETURN(auto device, driver->CreateDefaultDevice()); RETURN_IF_ERROR(instance->device_manager()->RegisterDevice(device)); - SequencerContext context(instance); + auto policy = make_ref<rt::Policy>(); + auto context = make_ref<rt::Context>(add_ref(instance), std::move(policy)); // Load main module. ASSIGN_OR_RETURN( auto main_module_file, - ModuleFile::LoadFile(ModuleDefIdentifier(), - absl::GetFlag(FLAGS_main_module)), + vm::ModuleFile::LoadFile(ModuleDefIdentifier(), + absl::GetFlag(FLAGS_main_module)), _ << "while loading module file " << absl::GetFlag(FLAGS_main_module)); ASSIGN_OR_RETURN(auto main_module, - Module::FromFile(std::move(main_module_file))); - - // Add native functions for use by the module. - RETURN_IF_ERROR(context.RegisterNativeFunction( - "fabsf", - [](Stack* stack, absl::Span<const BufferView> args, - absl::Span<BufferView> results) -> Status { - // TODO(benvanik): example native functions. - LOG(INFO) << "fabsf"; - return OkStatus(); - })); + vm::SequencerModule::FromFile(std::move(main_module_file))); // Register the main module with the context. // We could add additional modules (specializations, shared libraries, etc). // ModuleFioles are stateless so we could have the same module_file used by // multiple contexts simultaneously. - auto* main_module_ptr = main_module.get(); - RETURN_IF_ERROR(context.RegisterModule(std::move(main_module))); + RETURN_IF_ERROR(context->RegisterModule(add_ref(main_module))); // Dump the registered modules. - PrintModuleFlagBitfield print_flags = PrintModuleFlag::kNone; - if (absl::GetFlag(FLAGS_print_source_info)) { - print_flags |= PrintModuleFlag::kIncludeSourceMapping; + rt::PrintModuleFlagBitfield print_flags = rt::PrintModuleFlag::kNone; + if (absl::GetFlag(FLAGS_print_disassembly)) { + print_flags |= rt::PrintModuleFlag::kDisassemble; } - for (const auto& module : context.modules()) { - RETURN_IF_ERROR(PrintModuleToStream(sequencer_opcode_table(), *module, - print_flags, &std::cout)); + for (const auto& module : context->modules()) { + RETURN_IF_ERROR(PrintModuleToStream(*module, print_flags, &std::cout)); } - // Setup a new fiber. - FiberState fiber_state(instance); - - // Setup arguments and storage for results. - Function main_function; + rt::Function main_function; if (!absl::GetFlag(FLAGS_main_function).empty()) { // User-specified main function. - ASSIGN_OR_RETURN(main_function, - context.LookupExport(absl::GetFlag(FLAGS_main_function))); + ASSIGN_OR_RETURN(main_function, main_module->LookupFunctionByName( + rt::Function::Linkage::kExport, + absl::GetFlag(FLAGS_main_function))); } else { // No main function specified; to prevent non-deterministic behavior we // require one unless there's exactly one exported function in the module. - auto* exports = main_module_ptr->function_table().def().exports(); - if (exports && exports->size() == 1) { - ASSIGN_OR_RETURN( - main_function, - main_module_ptr->function_table().LookupFunction(exports->Get(0))); + if (main_module->signature().export_function_count() == 1) { + ASSIGN_OR_RETURN(main_function, main_module->LookupFunctionByOrdinal( + rt::Function::Linkage::kExport, 0)); } else { return InvalidArgumentErrorBuilder(IREE_LOC) << "--main_function= must be specified to disambiguate the " "function to run"; } } - ASSIGN_OR_RETURN(std::vector<BufferView> args, - ParseInputsFromFlags(device->allocator())); - std::vector<BufferView> results; - results.resize(main_function.result_count()); // Call into the main function. - RETURN_IF_ERROR(context.Invoke(&fiber_state, main_function, - absl::MakeSpan(args), - absl::MakeSpan(results))); + ASSIGN_OR_RETURN(auto arguments, ParseInputsFromFlags(device->allocator())); + ASSIGN_OR_RETURN(auto invocation, + rt::Invocation::Create(add_ref(context), main_function, + make_ref<rt::Policy>(), {}, + absl::MakeConstSpan(arguments))); + + // Wait until invocation completes. + RETURN_IF_ERROR(invocation->Await(absl::InfiniteFuture())); + ASSIGN_OR_RETURN(auto results, invocation->ConsumeResults()); // Dump all results to stdout. std::vector<std::string> output_types = @@ -201,5 +180,4 @@ return 0; } -} // namespace vm } // namespace iree
diff --git a/iree/tools/web/BUILD b/iree/tools/web/BUILD index 3737e05..f55ef9d 100644 --- a/iree/tools/web/BUILD +++ b/iree/tools/web/BUILD
@@ -1,12 +1,12 @@ # IREE web tools. +load("//third_party/emscripten:split_transition_defs.bzl", "auto_wasm_binary") + package( default_visibility = ["//visibility:public"], licenses = ["notice"], # Apache 2.0 ) -load("//third_party/emscripten:split_transition_defs.bzl", "auto_wasm_binary") - EMSCRIPTEN_LINKOPTS_COMMON = [ # Error at compile time on unresolved symbols. "-s ERROR_ON_UNDEFINED_SYMBOLS=1", @@ -58,9 +58,8 @@ "//iree/hal:buffer_view_string_util", "//iree/hal:driver_registry", "//iree/hal/interpreter:interpreter_driver_module", - "//iree/vm:bytecode_tables_sequencer", - "//iree/vm:instance", - "//iree/vm:sequencer_context", + "//iree/rt", + "//iree/vm:sequencer_module", "//third_party/emscripten:embind", ], )
diff --git a/iree/tools/web/run_module_emscripten.cc b/iree/tools/web/run_module_emscripten.cc index f713807..49d88a7 100644 --- a/iree/tools/web/run_module_emscripten.cc +++ b/iree/tools/web/run_module_emscripten.cc
@@ -26,14 +26,10 @@ #include "iree/hal/buffer_view.h" #include "iree/hal/buffer_view_string_util.h" #include "iree/hal/driver_registry.h" +#include "iree/rt/context.h" +#include "iree/rt/instance.h" #include "iree/schemas/module_def_generated.h" -#include "iree/vm/bytecode_tables_sequencer.h" -#include "iree/vm/fiber_state.h" -#include "iree/vm/function.h" -#include "iree/vm/instance.h" -#include "iree/vm/module.h" -#include "iree/vm/module_printer.h" -#include "iree/vm/sequencer_context.h" +#include "iree/vm/sequencer_module.h" namespace iree { @@ -59,52 +55,49 @@ // Runs an IREE module with the provided inputs and returns its outputs. StatusOr<std::string> RunIreeModule(std::string module_file_data, absl::string_view inputs_string) { - auto instance = std::make_shared<vm::Instance>(); + auto instance = make_ref<rt::Instance>(); // Create driver and device. ASSIGN_OR_RETURN(auto driver, hal::DriverRegistry::shared_registry()->Create( "interpreter")); ASSIGN_OR_RETURN(auto device, driver->CreateDefaultDevice()); RETURN_IF_ERROR(instance->device_manager()->RegisterDevice(device)); - vm::SequencerContext context(instance); + + auto policy = make_ref<rt::Policy>(); + auto context = make_ref<rt::Context>(add_ref(instance), std::move(policy)); // Load main module FlatBuffer. ASSIGN_OR_RETURN(auto main_module_file, FlatBufferFile<ModuleDef>::FromString(ModuleDefIdentifier(), module_file_data)); ASSIGN_OR_RETURN(auto main_module, - vm::Module::FromFile(std::move(main_module_file))); + vm::SequencerModule::FromFile(std::move(main_module_file))); // Register the main module with the context. - RETURN_IF_ERROR(context.RegisterModule(std::move(main_module))); - - // Dump the registered modules. - vm::PrintModuleFlagBitfield print_flags = - vm::PrintModuleFlag::kIncludeSourceMapping; - for (const auto& module : context.modules()) { - RETURN_IF_ERROR(vm::PrintModuleToStream(vm::sequencer_opcode_table(), - *module, print_flags, &std::cout)); - } - - // Setup a new fiber. - vm::FiberState fiber_state(instance); + RETURN_IF_ERROR(context->RegisterModule(add_ref(main_module))); // Setup arguments and storage for results. - // TODO(scotttodd): Receive main function name from JS - ASSIGN_OR_RETURN(vm::Function main_function, context.LookupExport("main")); + // TODO(scotttodd): Receive main function name from JS. + ASSIGN_OR_RETURN(auto main_function, + main_module->LookupFunctionByName( + rt::Function::Linkage::kExport, "main")); - ASSIGN_OR_RETURN(std::vector<hal::BufferView> args, + ASSIGN_OR_RETURN(auto arguments, ParseInputs(inputs_string, device->allocator())); - std::vector<hal::BufferView> results; - results.resize(main_function.result_count()); // Call into the main function. - RETURN_IF_ERROR(context.Invoke(&fiber_state, main_function, - absl::MakeSpan(args), - absl::MakeSpan(results))); + ASSIGN_OR_RETURN(auto invocation, + rt::Invocation::Create(add_ref(context), main_function, + make_ref<rt::Policy>(), {}, + absl::MakeConstSpan(arguments))); + + // Wait until invocation completes. + // TODO(scotttodd): make this an async callback. + RETURN_IF_ERROR(invocation->Await(absl::InfiniteFuture())); + ASSIGN_OR_RETURN(auto results, invocation->ConsumeResults()); // Dump all results to stdout. - // TODO(scotttodd): Receive output types / print mode from JS + // TODO(scotttodd): Receive output types / print mode from JS. // TODO(scotttodd): Return list of outputs instead of just the first (proto?) for (int i = 0; i < results.size(); ++i) { const auto& result = results[i];
diff --git a/iree/vm/BUILD b/iree/vm/BUILD index d65e151..9da6c77 100644 --- a/iree/vm/BUILD +++ b/iree/vm/BUILD
@@ -6,22 +6,30 @@ ) cc_library( - name = "bytecode_printer", - srcs = ["bytecode_printer.cc"], - hdrs = ["bytecode_printer.h"], + name = "bytecode_module", + srcs = [ + "bytecode_disassembler.cc", + "bytecode_module.cc", + ], + hdrs = [ + "bytecode_disassembler.h", + "bytecode_module.h", + ], deps = [ ":bytecode_util", - ":executable_table", - ":function_table", - ":module", ":opcode_info", - ":source_map", + ":source_map_resolver", ":type", + "//iree/base:flatbuffer_util", "//iree/base:status", + "//iree/base:tracing", + "//iree/hal:buffer_view", + "//iree/rt", "//iree/schemas", "//iree/schemas/bytecode:bytecode_v0", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:inlined_vector", + "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", "@com_google_absl//absl/types:span", ], @@ -32,13 +40,13 @@ srcs = ["bytecode_reader.cc"], hdrs = ["bytecode_reader.h"], deps = [ - ":function", - ":stack", + ":bytecode_module", ":type", "//iree/base:shape", "//iree/base:status", "//iree/hal:buffer_view", "//iree/hal:heap_buffer", + "//iree/rt", "//iree/schemas/bytecode:bytecode_v0", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:inlined_vector", @@ -80,122 +88,13 @@ srcs = ["bytecode_validator.cc"], hdrs = ["bytecode_validator.h"], deps = [ - ":context", - ":module", + ":bytecode_module", "//iree/base:status", "//iree/schemas", ], ) cc_library( - name = "context", - srcs = ["context.cc"], - hdrs = ["context.h"], - deps = [ - ":function", - ":module", - "//iree/base:flatbuffer_util", - "//iree/base:status", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", - ], -) - -cc_library( - name = "executable_table", - srcs = ["executable_table.cc"], - hdrs = ["executable_table.h"], - deps = [ - "//iree/base:flatbuffer_util", - "//iree/base:source_location", - "//iree/base:status", - "//iree/schemas", - ], -) - -cc_library( - name = "fiber_state", - srcs = ["fiber_state.cc"], - hdrs = ["fiber_state.h"], - deps = [ - ":instance", - ":stack", - "//iree/base:status", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", - ], -) - -cc_library( - name = "function", - srcs = ["function.cc"], - hdrs = ["function.h"], - deps = [ - "//iree/base:flatbuffer_util", - "//iree/base:status", - "//iree/hal:buffer_view", - "//iree/schemas", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", - ], -) - -cc_library( - name = "function_table", - srcs = ["function_table.cc"], - hdrs = ["function_table.h"], - deps = [ - ":function", - "//iree/base:flatbuffer_util", - "//iree/base:status", - "//iree/schemas", - "@com_google_absl//absl/container:flat_hash_map", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", - ], -) - -cc_library( - name = "instance", - srcs = ["instance.cc"], - hdrs = ["instance.h"], - deps = [ - "//iree/base:source_location", - "//iree/base:status", - "//iree/hal:device_manager", - "@com_google_absl//absl/memory", - ], -) - -cc_library( - name = "module", - srcs = ["module.cc"], - hdrs = ["module.h"], - deps = [ - ":executable_table", - ":function_table", - "//iree/base:flatbuffer_util", - "//iree/base:status", - "//iree/schemas", - "@com_google_absl//absl/memory", - ], -) - -cc_library( - name = "module_printer", - srcs = ["module_printer.cc"], - hdrs = ["module_printer.h"], - deps = [ - ":bytecode_printer", - ":module", - ":opcode_info", - ":source_map", - "//iree/base:bitfield", - "//iree/base:status", - ], -) - -cc_library( name = "opcode_info", hdrs = ["opcode_info.h"], deps = [ @@ -207,35 +106,15 @@ ) cc_library( - name = "sequencer_context", - srcs = ["sequencer_context.cc"], - hdrs = ["sequencer_context.h"], - deps = [ - ":context", - ":fiber_state", - ":function", - ":instance", - ":module", - ":sequencer_dispatch", - "//iree/base:flatbuffer_util", - "//iree/base:status", - "//iree/hal:buffer_view", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", - ], -) - -cc_library( name = "sequencer_dispatch", srcs = ["sequencer_dispatch.cc"], hdrs = ["sequencer_dispatch.h"], deps = [ + ":bytecode_module", ":bytecode_reader", ":bytecode_tables_sequencer", ":bytecode_util", - ":function", ":opcode_info", - ":stack", "//iree/base:logging", "//iree/base:memory", "//iree/base:status", @@ -244,6 +123,7 @@ "//iree/hal:device", "//iree/hal:device_placement", "//iree/hal:heap_buffer", + "//iree/rt", "//iree/schemas/bytecode:sequencer_bytecode_v0", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:inlined_vector", @@ -254,35 +134,32 @@ ) cc_library( - name = "source_map", - srcs = ["source_map.cc"], - hdrs = ["source_map.h"], + name = "sequencer_module", + srcs = ["sequencer_module.cc"], + hdrs = ["sequencer_module.h"], deps = [ - "//iree/base:flatbuffer_util", + ":bytecode_module", + ":bytecode_tables_sequencer", + ":sequencer_dispatch", "//iree/base:status", - "//iree/schemas", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:optional", + "//iree/base:tracing", + "//iree/hal:buffer_view", + "//iree/rt", + "@com_google_absl//absl/memory", ], ) cc_library( - name = "stack", - srcs = [ - "stack.cc", - "stack_frame.cc", - ], - hdrs = [ - "stack.h", - "stack_frame.h", - ], + name = "source_map_resolver", + srcs = ["source_map_resolver.cc"], + hdrs = ["source_map_resolver.h"], deps = [ - ":function", - ":module", + "//iree/base:flatbuffer_util", "//iree/base:status", - "//iree/hal:buffer_view", + "//iree/rt", + "//iree/schemas", "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", + "@com_google_absl//absl/types:optional", ], )
diff --git a/iree/vm/CMakeLists.txt b/iree/vm/CMakeLists.txt index 4a357f3..ab8c873 100644 --- a/iree/vm/CMakeLists.txt +++ b/iree/vm/CMakeLists.txt
@@ -12,14 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. - iree_cc_library( NAME - bytecode_printer + bytecode_disassembler SRCS - "bytecode_printer.cc" + "bytecode_disassembler.cc" HDRS - "bytecode_printer.h" + "bytecode_disassembler.h" DEPS absl::core_headers absl::inlined_vector @@ -28,18 +27,34 @@ iree::base::status iree::schemas iree::schemas::bytecode::bytecode_v0 + iree::rt iree::vm::bytecode_util - iree::vm::executable_table - iree::vm::function_table - iree::vm::module iree::vm::opcode_info - iree::vm::source_map + iree::vm::source_map_resolver iree::vm::type PUBLIC ) iree_cc_library( NAME + bytecode_module + SRCS + "bytecode_module.cc" + HDRS + "bytecode_module.h" + DEPS + absl::memory + iree::base::flatbuffer_util + iree::base::status + iree::rt + iree::schemas + iree::vm::bytecode_disassembler + iree::vm::source_map_resolver + PUBLIC +) + +iree_cc_library( + NAME bytecode_reader SRCS "bytecode_reader.cc" @@ -52,9 +67,9 @@ iree::base::status iree::hal::buffer_view iree::hal::heap_buffer + iree::rt iree::schemas::bytecode::bytecode_v0 - iree::vm::function - iree::vm::stack + iree::vm::bytecode_module iree::vm::type PUBLIC ) @@ -115,137 +130,6 @@ iree_cc_library( NAME - context - SRCS - "context.cc" - HDRS - "context.h" - DEPS - absl::strings - absl::span - iree::base::flatbuffer_util - iree::base::status - iree::vm::function - iree::vm::module - PUBLIC -) - -iree_cc_library( - NAME - executable_table - SRCS - "executable_table.cc" - HDRS - "executable_table.h" - DEPS - iree::base::flatbuffer_util - iree::base::status - iree::schemas - PUBLIC -) - -iree_cc_library( - NAME - fiber_state - SRCS - "fiber_state.cc" - HDRS - "fiber_state.h" - DEPS - absl::strings - absl::span - iree::base::status - iree::vm::instance - iree::vm::stack - PUBLIC -) - -iree_cc_library( - NAME - function - SRCS - "function.cc" - HDRS - "function.h" - DEPS - absl::strings - absl::span - iree::base::flatbuffer_util - iree::base::status - iree::hal::buffer_view - iree::schemas - PUBLIC -) - -iree_cc_library( - NAME - function_table - SRCS - "function_table.cc" - HDRS - "function_table.h" - DEPS - absl::flat_hash_map - absl::strings - absl::span - iree::base::flatbuffer_util - iree::base::status - iree::schemas - iree::vm::function - PUBLIC -) - -iree_cc_library( - NAME - instance - SRCS - "instance.cc" - HDRS - "instance.h" - DEPS - absl::memory - iree::base::source_location - iree::base::status - iree::hal::device_manager - PUBLIC -) - -iree_cc_library( - NAME - module - SRCS - "module.cc" - HDRS - "module.h" - DEPS - absl::memory - iree::base::flatbuffer_util - iree::base::status - iree::schemas - iree::vm::executable_table - iree::vm::function_table - PUBLIC -) - -iree_cc_library( - NAME - module_printer - SRCS - "module_printer.cc" - HDRS - "module_printer.h" - DEPS - iree::base::bitfield - iree::base::status - iree::vm::bytecode_printer - iree::vm::module - iree::vm::opcode_info - iree::vm::source_map - PUBLIC -) - -iree_cc_library( - NAME opcode_info HDRS "opcode_info.h" @@ -259,28 +143,6 @@ iree_cc_library( NAME - sequencer_context - SRCS - "sequencer_context.cc" - HDRS - "sequencer_context.h" - DEPS - absl::strings - absl::span - iree::base::flatbuffer_util - iree::base::status - iree::hal::buffer_view - iree::vm::context - iree::vm::fiber_state - iree::vm::function - iree::vm::instance - iree::vm::module - iree::vm::sequencer_dispatch - PUBLIC -) - -iree_cc_library( - NAME sequencer_dispatch SRCS "sequencer_dispatch.cc" @@ -300,53 +162,53 @@ iree::hal::device iree::hal::device_placement iree::hal::heap_buffer + iree::rt iree::schemas::bytecode::sequencer_bytecode_v0 + iree::vm::bytecode_module iree::vm::bytecode_reader iree::vm::bytecode_tables_sequencer iree::vm::bytecode_util - iree::vm::function iree::vm::opcode_info - iree::vm::stack PUBLIC ) iree_cc_library( NAME - source_map + sequencer_module SRCS - "source_map.cc" + "sequencer_module.cc" HDRS - "source_map.h" + "sequencer_module.h" + DEPS + absl::core_headers + iree::base::status + iree::hal::buffer_view + iree::rt + iree::schemas::bytecode::sequencer_bytecode_v0 + iree::vm::bytecode_module + iree::vm::sequencer_dispatch + PUBLIC +) + +iree_cc_library( + NAME + source_map_resolver + SRCS + "source_map_resolver.cc" + HDRS + "source_map_resolver.h" DEPS absl::strings absl::optional iree::base::flatbuffer_util iree::base::status + iree::rt iree::schemas PUBLIC ) iree_cc_library( NAME - stack - SRCS - "stack.cc" - "stack_frame.cc" - HDRS - "stack.h" - "stack_frame.h" - DEPS - absl::strings - absl::span - iree::base::status - iree::hal::buffer_view - iree::vm::function - iree::vm::module - PUBLIC -) - -iree_cc_library( - NAME type SRCS "type.cc"
diff --git a/iree/vm/bytecode_printer.cc b/iree/vm/bytecode_disassembler.cc similarity index 73% rename from iree/vm/bytecode_printer.cc rename to iree/vm/bytecode_disassembler.cc index 136d257..4868792 100644 --- a/iree/vm/bytecode_printer.cc +++ b/iree/vm/bytecode_disassembler.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "iree/vm/bytecode_printer.h" +#include "iree/vm/bytecode_disassembler.h" #include <iomanip> #include <sstream> @@ -25,8 +25,8 @@ #include "iree/base/status.h" #include "iree/schemas/bytecode/bytecode_v0.h" #include "iree/schemas/source_map_def_generated.h" +#include "iree/vm/bytecode_module.h" #include "iree/vm/bytecode_util.h" -#include "iree/vm/module.h" #include "iree/vm/type.h" namespace iree { @@ -34,8 +34,10 @@ namespace { +using ::iree::rt::SourceOffset; + template <typename T> -StatusOr<T> ReadValue(absl::Span<const uint8_t> data, int* offset) { +StatusOr<T> ReadValue(absl::Span<const uint8_t> data, SourceOffset* offset) { if (*offset + sizeof(T) > data.size()) { return OutOfRangeErrorBuilder(IREE_LOC) << "Bytecode data underrun"; } @@ -44,16 +46,19 @@ return value; } -StatusOr<const Type> ReadType(absl::Span<const uint8_t> data, int* offset) { +StatusOr<const Type> ReadType(absl::Span<const uint8_t> data, + SourceOffset* offset) { ASSIGN_OR_RETURN(uint8_t type_index, ReadValue<uint8_t>(data, offset)); return Type::FromTypeIndex(type_index); } -StatusOr<uint8_t> ReadCount(absl::Span<const uint8_t> data, int* offset) { +StatusOr<uint8_t> ReadCount(absl::Span<const uint8_t> data, + SourceOffset* offset) { return ReadValue<uint8_t>(data, offset); } -StatusOr<uint16_t> ReadValueSlot(absl::Span<const uint8_t> data, int* offset) { +StatusOr<uint16_t> ReadValueSlot(absl::Span<const uint8_t> data, + SourceOffset* offset) { return ReadValue<uint16_t>(data, offset); } @@ -103,55 +108,30 @@ } // namespace -// static -std::string BytecodePrinter::ToString( - OpcodeTable opcode_table, const FunctionTable& function_table, - const ExecutableTable& executable_table, - const SourceMapResolver& source_map_resolver, - const BytecodeDef& bytecode_def) { - BytecodePrinter printer(opcode_table, function_table, executable_table, - source_map_resolver); - auto result = printer.Print(bytecode_def); - if (!result.ok()) { - return result.status().ToString(); - } - return result.ValueOrDie(); -} +StatusOr<std::vector<rt::Instruction>> +BytecodeDisassembler::DisassembleInstructions(const rt::Function& function, + SourceOffset offset, + int32_t instruction_count) const { + std::vector<rt::Instruction> instructions; -StatusOr<std::string> BytecodePrinter::Print( - const BytecodeDef& bytecode_def) const { - std::ostringstream stream; - RETURN_IF_ERROR(PrintToStream(bytecode_def, &stream)) << stream.str(); - return stream.str(); -} - -Status BytecodePrinter::PrintToStream(const BytecodeDef& bytecode_def, - std::ostream* stream) const { - if (!bytecode_def.contents()) { - return OkStatus(); + ASSIGN_OR_RETURN( + auto* function_def, + static_cast<const BytecodeModule*>(function.module()) + ->GetFunctionDef(function.linkage(), function.ordinal())); + auto* bytecode_def = function_def->bytecode(); + if (!bytecode_def) { + return UnavailableErrorBuilder(IREE_LOC) << "Function contains no body"; } auto data = absl::MakeSpan( - reinterpret_cast<const uint8_t*>(bytecode_def.contents()->data()), - bytecode_def.contents()->size()); - return PrintToStream(data, stream); -} + reinterpret_cast<const uint8_t*>(bytecode_def->contents()->data()), + bytecode_def->contents()->size()); -Status BytecodePrinter::PrintToStream(absl::Span<const uint8_t> data, - std::ostream* stream) const { // TODO(benvanik): scan and find all branch offsets to insert labels - int offset = 0; - absl::optional<SourceLocation> previous_location; - while (offset < data.length()) { - auto source_location = source_map_resolver_.ResolveBytecodeOffset(offset); - if (source_location.has_value()) { - if (previous_location != source_location) { - *stream << std::setw(10) << "; " << source_location.value() << "\n"; - } - previous_location = source_location; - } - - *stream << std::setw(6) << offset << ": "; + while (offset < data.length() && instructions.size() < instruction_count) { + instructions.push_back({}); + auto& instruction = instructions.back(); + instruction.offset = offset; uint8_t opcode = data[offset++]; const auto& opcode_info = GetOpcodeInfo(opcode_table_, opcode); @@ -161,6 +141,8 @@ } int payload_offset = offset; + std::ostringstream stream; + // Print out return values, if any. int base_result_index = 0; int printed_result_count = 0; @@ -168,7 +150,7 @@ ++i) { if (opcode_info.operands[i] == OperandEncoding::kNone) break; if (printed_result_count > 0) { - *stream << ", "; + stream << ", "; } switch (opcode_info.operands[i]) { default: @@ -193,20 +175,20 @@ case OperandEncoding::kResultSlot: { ++printed_result_count; ASSIGN_OR_RETURN(uint16_t slot_ordinal, ReadValueSlot(data, &offset)); - *stream << "%" << slot_ordinal; + stream << "%" << slot_ordinal; break; } case OperandEncoding::kVariadicResultSlots: { ++printed_result_count; - *stream << "["; + stream << "["; ASSIGN_OR_RETURN(int count, ReadCount(data, &offset)); for (int j = 0; j < count; ++j) { ASSIGN_OR_RETURN(uint16_t slot_ordinal, ReadValueSlot(data, &offset)); - if (j > 0) *stream << ", "; - *stream << "%" << slot_ordinal; + if (j > 0) stream << ", "; + stream << "%" << slot_ordinal; } - *stream << "]"; + stream << "]"; break; } case OperandEncoding::kVariadicTransferSlots: { @@ -268,11 +250,11 @@ } } if (printed_result_count > 0) { - *stream << " = "; + stream << " = "; } offset = payload_offset; - *stream << opcode_info.mnemonic; + stream << opcode_info.mnemonic; // Print out operands. int base_operand_index = 0; @@ -283,9 +265,9 @@ if (opcode_info.operands[i] != OperandEncoding::kResultSlot && opcode_info.operands[i] != OperandEncoding::kVariadicResultSlots) { if (i == base_operand_index) { - *stream << " "; + stream << " "; } else if (printed_operand_count > 0) { - *stream << ", "; + stream << ", "; } } switch (opcode_info.operands[i]) { @@ -298,41 +280,41 @@ case OperandEncoding::kInputSlot: { ++printed_operand_count; ASSIGN_OR_RETURN(uint16_t slot_ordinal, ReadValueSlot(data, &offset)); - *stream << "%" << slot_ordinal; + stream << "%" << slot_ordinal; break; } case OperandEncoding::kVariadicInputSlots: { ++printed_operand_count; - *stream << "["; + stream << "["; ASSIGN_OR_RETURN(int count, ReadCount(data, &offset)); for (int j = 0; j < count; ++j) { ASSIGN_OR_RETURN(uint16_t slot_ordinal, ReadValueSlot(data, &offset)); - if (j > 0) *stream << ", "; - *stream << "%" << slot_ordinal; + if (j > 0) stream << ", "; + stream << "%" << slot_ordinal; } - *stream << "]"; + stream << "]"; break; } case OperandEncoding::kOutputSlot: { ++printed_operand_count; ASSIGN_OR_RETURN(uint16_t slot_ordinal, ReadValueSlot(data, &offset)); - *stream << "&" - << "%" << slot_ordinal; + stream << "&" + << "%" << slot_ordinal; break; } case OperandEncoding::kVariadicOutputSlots: { ++printed_operand_count; - *stream << "["; + stream << "["; ASSIGN_OR_RETURN(int count, ReadCount(data, &offset)); for (int j = 0; j < count; ++j) { ASSIGN_OR_RETURN(uint16_t slot_ordinal, ReadValueSlot(data, &offset)); - if (j > 0) *stream << ", "; - *stream << "&" - << "%" << slot_ordinal; + if (j > 0) stream << ", "; + stream << "&" + << "%" << slot_ordinal; } - *stream << "]"; + stream << "]"; break; } case OperandEncoding::kResultSlot: { @@ -348,17 +330,17 @@ } case OperandEncoding::kVariadicTransferSlots: { ++printed_operand_count; - *stream << "["; + stream << "["; ASSIGN_OR_RETURN(int count, ReadCount(data, &offset)); for (int j = 0; j < count; ++j) { ASSIGN_OR_RETURN(uint16_t src_slot_ordinal, ReadValueSlot(data, &offset)); ASSIGN_OR_RETURN(uint16_t dst_slot_ordinal, ReadValueSlot(data, &offset)); - if (j > 0) *stream << ", "; - *stream << "%" << src_slot_ordinal << "=>%" << dst_slot_ordinal; + if (j > 0) stream << ", "; + stream << "%" << src_slot_ordinal << "=>%" << dst_slot_ordinal; } - *stream << "]"; + stream << "]"; break; } case OperandEncoding::kConstant: { @@ -374,7 +356,7 @@ } ASSIGN_OR_RETURN(auto encoding, ReadValue<ConstantEncoding>(data, &offset)); - *stream << ConstantEncodingToString(encoding); + stream << ConstantEncodingToString(encoding); int serialized_element_count = 1; switch (encoding) { case ConstantEncoding::kDense: @@ -388,27 +370,29 @@ << "Unimplemented constant encoding " << static_cast<int>(encoding); } - *stream << " buffer_view<"; + stream << " buffer_view<"; if (!shape.empty()) { - *stream << absl::StrJoin(shape, "x") << "x"; + stream << absl::StrJoin(shape, "x") << "x"; } - *stream << type << ">{"; + stream << type << ">{"; size_t element_size = type.element_size(); auto bytes = data.subspan( offset, std::min(serialized_element_count, 1024) * element_size); - *stream << ConstantToString(type, bytes); - if (serialized_element_count > 1024) *stream << "..."; + stream << ConstantToString(type, bytes); + if (serialized_element_count > 1024) stream << "..."; offset += serialized_element_count * element_size; - *stream << "}"; + stream << "}"; break; } case OperandEncoding::kFunctionOrdinal: { ++printed_operand_count; ASSIGN_OR_RETURN(auto function_ordinal, ReadValue<uint32_t>(data, &offset)); - ASSIGN_OR_RETURN(auto function, - function_table_.LookupFunction(function_ordinal)); - *stream << "@" << function_ordinal << " " << function.name(); + ASSIGN_OR_RETURN( + auto target_function, + function.module()->LookupFunctionByOrdinal( + rt::Function::Linkage::kInternal, function_ordinal)); + stream << "@" << function_ordinal << " " << target_function.name(); break; } case OperandEncoding::kDispatchOrdinal: { @@ -418,88 +402,80 @@ ASSIGN_OR_RETURN(auto export_ordinal, ReadValue<uint16_t>(data, &offset)); // TODO(benvanik): lookup in executable table. - *stream << "@" << dispatch_ordinal << ":" << export_ordinal; + stream << "@" << dispatch_ordinal << ":" << export_ordinal; break; } case OperandEncoding::kImportOrdinal: { ++printed_operand_count; ASSIGN_OR_RETURN(auto import_ordinal, ReadValue<uint32_t>(data, &offset)); - ASSIGN_OR_RETURN(auto* function, - function_table_.LookupImport(import_ordinal)); - *stream << "@i" << import_ordinal << " "; - switch (function->link_type()) { - default: - *stream << "??"; - break; - case ImportFunction::LinkType::kNativeFunction: - *stream << "<native>"; - break; - case ImportFunction::LinkType::kModule: - *stream << function->linked_function().module().name() << ":" - << function->linked_function().name(); - break; - } + ASSIGN_OR_RETURN(auto target_function, + function.module()->LookupFunctionByOrdinal( + rt::Function::Linkage::kImport, import_ordinal)); + stream << "@i" << import_ordinal << " " << target_function.name(); break; } case OperandEncoding::kBlockOffset: { ++printed_operand_count; ASSIGN_OR_RETURN(uint32_t block_offset, ReadValue<uint32_t>(data, &offset)); - *stream << ":" << block_offset; + stream << ":" << block_offset; break; } case OperandEncoding::kTypeIndex: { ++printed_operand_count; ASSIGN_OR_RETURN(auto type, ReadType(data, &offset)); - *stream << type; + stream << type; break; } case OperandEncoding::kIndex: { ++printed_operand_count; ASSIGN_OR_RETURN(auto index, ReadValue<int32_t>(data, &offset)); - *stream << "#" << index; + stream << "#" << index; break; } case OperandEncoding::kIndexList: { ++printed_operand_count; - *stream << "{"; + stream << "{"; ASSIGN_OR_RETURN(int count, ReadCount(data, &offset)); for (int j = 0; j < count; ++j) { ASSIGN_OR_RETURN(auto dim, ReadValue<int32_t>(data, &offset)); - if (j > 0) *stream << ","; - *stream << dim; + if (j > 0) stream << ","; + stream << dim; } - *stream << "}"; + stream << "}"; break; } case OperandEncoding::kCmpIPredicate: { ++printed_operand_count; ASSIGN_OR_RETURN(auto predicate_value, ReadValue<uint8_t>(data, &offset)); - *stream << "<" - << PredicateToString( - static_cast<CmpIPredicate>(predicate_value)) - << ">"; + stream << "<" + << PredicateToString( + static_cast<CmpIPredicate>(predicate_value)) + << ">"; break; } case OperandEncoding::kCmpFPredicate: { ++printed_operand_count; ASSIGN_OR_RETURN(auto predicate_value, ReadValue<uint8_t>(data, &offset)); - *stream << "<" - << PredicateToString( - static_cast<CmpFPredicate>(predicate_value)) - << ">"; + stream << "<" + << PredicateToString( + static_cast<CmpFPredicate>(predicate_value)) + << ">"; break; } } } - *stream << "\n"; + stream << "\n"; + + instruction.long_text = stream.str(); + instruction.short_text = instruction.long_text; } - return OkStatus(); + return instructions; } } // namespace vm
diff --git a/iree/vm/bytecode_disassembler.h b/iree/vm/bytecode_disassembler.h new file mode 100644 index 0000000..633e290 --- /dev/null +++ b/iree/vm/bytecode_disassembler.h
@@ -0,0 +1,46 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef IREE_VM_BYTECODE_DISASSEMBLER_H_ +#define IREE_VM_BYTECODE_DISASSEMBLER_H_ + +#include <ostream> + +#include "iree/base/status.h" +#include "iree/rt/disassembler.h" +#include "iree/schemas/bytecode_def_generated.h" +#include "iree/schemas/source_map_def_generated.h" +#include "iree/vm/opcode_info.h" + +namespace iree { +namespace vm { + +// Disassembles bytecode with a specific op set to text. +class BytecodeDisassembler final : public rt::Disassembler { + public: + explicit BytecodeDisassembler(OpcodeTable opcode_table) + : opcode_table_(opcode_table) {} + + StatusOr<std::vector<rt::Instruction>> DisassembleInstructions( + const rt::Function& function, rt::SourceOffset offset, + int32_t instruction_count) const override; + + private: + OpcodeTable opcode_table_; +}; + +} // namespace vm +} // namespace iree + +#endif // IREE_VM_BYTECODE_DISASSEMBLER_H_
diff --git a/iree/vm/bytecode_module.cc b/iree/vm/bytecode_module.cc new file mode 100644 index 0000000..7812cb6 --- /dev/null +++ b/iree/vm/bytecode_module.cc
@@ -0,0 +1,310 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "iree/vm/bytecode_module.h" + +#include "absl/memory/memory.h" +#include "iree/base/status.h" +#include "iree/base/tracing.h" +#include "iree/hal/buffer_view.h" +#include "iree/vm/bytecode_disassembler.h" + +namespace iree { +namespace vm { + +namespace { + +using ::iree::hal::BufferView; +using ::iree::rt::Function; +using ::iree::rt::FunctionSignature; +using ::iree::rt::Module; +using ::iree::rt::ModuleSignature; + +Status ValidateElementSize(int element_bit_width, + const ElementTypeDef& expected_element_type) { + switch (expected_element_type.type_union_type()) { + case ElementTypeDefUnion::FloatTypeDef: { + auto expected_bit_width = + expected_element_type.type_union_as_FloatTypeDef()->width(); + if (element_bit_width != expected_bit_width) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Has element bit width " << element_bit_width + << " but expected " << expected_bit_width; + } + return OkStatus(); + } + case ElementTypeDefUnion::IntegerTypeDef: { + auto expected_bit_width = + expected_element_type.type_union_as_IntegerTypeDef()->width(); + if (element_bit_width != expected_bit_width) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Has element bit width " << element_bit_width + << " but expected " << expected_bit_width; + } + return OkStatus(); + } + case ElementTypeDefUnion::UnknownTypeDef: + case ElementTypeDefUnion::NONE: { + } + } + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Defined type has unsupported element type " + << EnumNameElementTypeDefUnion( + expected_element_type.type_union_type()); +} + +Status ValidateTypeStructure(const FunctionTypeDef& type_def) { + // Ensure all fields are populated. + return OkStatus(); +} + +Status ValidateFunctionTableStructure( + const FunctionTableDef& function_table_def) { + if (!function_table_def.functions()) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Function table is missing the function listing"; + } + + // All functions must contain a valid type. + const auto& functions = *function_table_def.functions(); + for (int i = 0; i < functions.size(); ++i) { + const auto* function = functions[i]; + if (!function) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Function ordinal " << i << " is missing its contents"; + } + if (!function->type()) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Function ordinal " << i << " is missing its type"; + } + RETURN_IF_ERROR(ValidateTypeStructure(*function->type())); + } + + // Imports must also have a name (that we can use to resolve it). + if (function_table_def.imports()) { + const auto& imports = *function_table_def.imports(); + for (int i = 0; i < imports.size(); ++i) { + int function_index = imports[i]; + if (!functions[function_index]->name()) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Import ordinal " << i << " is missing its contents"; + } + } + } + + // Exports must also have a name (that others will use to look it up). + if (function_table_def.exports()) { + const auto& exports = *function_table_def.exports(); + for (int i = 0; i < exports.size(); ++i) { + int function_index = exports[i]; + if (!functions[function_index]->name()) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Export ordinal " << i << " is missing its contents"; + } + } + } + + return OkStatus(); +} + +Status ValidateExecutableTableStructure( + const ExecutableTableDef& executable_table_def) { + if (!executable_table_def.multi_arch_executables()) { + // May have sequencer only fns. Fine to not have dispatchable executables. + return OkStatus(); + } + + // All fat executables need at least one device-specific executable. + const auto& multi_arch_executables = + *executable_table_def.multi_arch_executables(); + for (int i = 0; i < multi_arch_executables.size(); ++i) { + const auto* multi_arch_executable = multi_arch_executables[i]; + if (!multi_arch_executable || !multi_arch_executable->executables() || + multi_arch_executable->executables()->size() == 0) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Multi-arch executable ordinal " << i + << " is missing its contents"; + } + } + + return OkStatus(); +} + +} // namespace + +// static +Status BytecodeModule::ValidateStructure(const ModuleDef& module_def) { + IREE_TRACE_SCOPE0("BytecodeModule::ValidateStructure"); + + // Must have a function table. + if (module_def.function_table()) { + RETURN_IF_ERROR( + ValidateFunctionTableStructure(*module_def.function_table())); + } else { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "ModuleDef is missing a function table"; + } + + // Must have an executable table. + if (module_def.executable_table()) { + RETURN_IF_ERROR( + ValidateExecutableTableStructure(*module_def.executable_table())); + } else { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "ModuleDef is missing an executable table"; + } + + return OkStatus(); +} + +BytecodeModule::BytecodeModule(std::unique_ptr<ModuleFile> module_file, + OpcodeTable opcode_table) + : module_file_(std::move(module_file)), + module_def_(*module_file_->root()), + source_resolver_(SourceMapResolver::FromModule(module_def_)), + disassembler_(absl::make_unique<BytecodeDisassembler>(opcode_table)) {} + +BytecodeModule::~BytecodeModule() = default; + +const ModuleSignature BytecodeModule::signature() const { + return ModuleSignature(function_table_def().imports()->size(), + function_table_def().exports()->size(), + function_table_def().functions()->size(), 0); +} + +std::string BytecodeModule::DebugStringShort() const { + return std::string(name()); +} + +StatusOr<int32_t> BytecodeModule::MapFunctionOrdinal(Function::Linkage linkage, + int32_t ordinal) const { + const auto& function_table = function_table_def(); + switch (linkage) { + case Function::Linkage::kImport: + if (ordinal < 0 || ordinal >= function_table.imports()->size()) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Import ordinal " << ordinal + << " is outside the valid range [0, " + << function_table.imports()->size() << ")"; + } + ordinal = function_table.imports()->Get(ordinal); + break; + case Function::Linkage::kExport: + if (ordinal < 0 || ordinal >= function_table.exports()->size()) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Export ordinal " << ordinal + << " is outside the valid range [0, " + << function_table.exports()->size() << ")"; + } + ordinal = function_table.exports()->Get(ordinal); + break; + default: + break; + } + if (ordinal < 0 || ordinal >= function_table.functions()->size()) { + return OutOfRangeErrorBuilder(IREE_LOC) + << "Function ordinal " << ordinal + << " is outside the valid range [0, " + << function_table.functions()->size() << ")"; + } + return ordinal; +} + +StatusOr<const Function> BytecodeModule::LookupFunctionByOrdinal( + Function::Linkage linkage, int32_t ordinal) const { + ASSIGN_OR_RETURN(ordinal, MapFunctionOrdinal(linkage, ordinal)); + return Function(this, Function::Linkage::kInternal, ordinal); +} + +StatusOr<const Function> BytecodeModule::LookupFunctionByName( + Function::Linkage linkage, absl::string_view name) const { + const auto& functions = *function_table_def().functions(); + for (int i = 0; i < functions.size(); ++i) { + const auto* function_def = functions.Get(i); + if (WrapString(function_def->name()) == name) { + return LookupFunctionByOrdinal(Function::Linkage::kInternal, i); + } + } + return NotFoundErrorBuilder(IREE_LOC) + << "Function '" << name + << "' not found in function table (or names have been stripped)"; +} + +StatusOr<absl::string_view> BytecodeModule::GetFunctionName( + Function::Linkage linkage, int32_t ordinal) const { + ASSIGN_OR_RETURN(ordinal, MapFunctionOrdinal(linkage, ordinal)); + const auto* function_def = function_table_def().functions()->Get(ordinal); + return WrapString(function_def->name()); +} + +StatusOr<const FunctionSignature> BytecodeModule::GetFunctionSignature( + Function::Linkage linkage, int32_t ordinal) const { + ASSIGN_OR_RETURN(ordinal, MapFunctionOrdinal(linkage, ordinal)); + const auto* function_def = function_table_def().functions()->Get(ordinal); + const auto* type_def = function_def->type(); + return FunctionSignature( + type_def->inputs() ? type_def->inputs()->size() : 0, + type_def->results() ? type_def->results()->size() : 0); +} + +StatusOr<const FunctionDef*> BytecodeModule::GetFunctionDef( + rt::Function::Linkage linkage, int32_t ordinal) const { + ASSIGN_OR_RETURN(ordinal, MapFunctionOrdinal(linkage, ordinal)); + const auto& function_defs = *function_table_def().functions(); + if (ordinal >= function_defs.size()) { + return OutOfRangeErrorBuilder(IREE_LOC) + << "Internal function ordinal " << ordinal + << " out of range of table (" << function_defs.size() << ")"; + } + return function_defs.Get(ordinal); +} + +StatusOr<const MultiArchExecutableDef*> +BytecodeModule::LookupMultiArchExecutable(int executable_ordinal) const { + if (executable_ordinal < 0 || + executable_ordinal >= + executable_table_def().multi_arch_executables()->size()) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Invalid multi-arch executable ordinal " << executable_ordinal; + } + return executable_table_def().multi_arch_executables()->Get( + executable_ordinal); +} + +// static +Status BytecodeModule::ValidateArgType(const BufferView& arg, + const MemRefTypeDef& expected_type) { + RETURN_IF_ERROR( + ValidateElementSize(arg.element_size * 8, *expected_type.element_type())); + + auto expected_shape = expected_type.shape(); + if (arg.shape.size() != expected_shape->size()) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Argument should have rank " << expected_shape->size() + << " but has rank " << arg.shape.size(); + } + for (int i = 0; i < expected_shape->size(); ++i) { + auto dim_size = arg.shape[i]; + auto expected_dim_size = expected_shape->Get(i); + if (dim_size != expected_dim_size) { + return InvalidArgumentErrorBuilder(IREE_LOC) + << "Argument dimension " << i << " should have size " + << expected_dim_size << " but has size " << dim_size; + } + } + return OkStatus(); +} + +} // namespace vm +} // namespace iree
diff --git a/iree/vm/bytecode_module.h b/iree/vm/bytecode_module.h new file mode 100644 index 0000000..36d034e --- /dev/null +++ b/iree/vm/bytecode_module.h
@@ -0,0 +1,103 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef IREE_VM_BYTECODE_MODULE_H_ +#define IREE_VM_BYTECODE_MODULE_H_ + +#include <memory> + +#include "iree/base/flatbuffer_util.h" +#include "iree/rt/function.h" +#include "iree/rt/module.h" +#include "iree/schemas/executable_table_def_generated.h" +#include "iree/schemas/function_table_def_generated.h" +#include "iree/schemas/module_def_generated.h" +#include "iree/vm/opcode_info.h" +#include "iree/vm/source_map_resolver.h" + +namespace iree { +namespace vm { + +using ModuleFile = FlatBufferFile<ModuleDef>; + +// A loaded bytecode module backed by a FlatBuffer. +class BytecodeModule : public rt::Module { + public: + static Status ValidateStructure(const ModuleDef& module_def); + + ~BytecodeModule() override; + + const ModuleDef& def() const { return module_def_; } + const FunctionTableDef& function_table_def() const { + return *module_def_.function_table(); + } + const ExecutableTableDef& executable_table_def() const { + return *module_def_.executable_table(); + } + + absl::string_view name() const override { + return WrapString(module_def_.name()); + } + + const rt::ModuleSignature signature() const override; + + rt::SourceResolver* source_resolver() const override { + return &source_resolver_; + } + + rt::Disassembler* disassembler() const override { + return disassembler_.get(); + } + + std::string DebugStringShort() const override; + + StatusOr<const rt::Function> LookupFunctionByOrdinal( + rt::Function::Linkage linkage, int32_t ordinal) const override; + + StatusOr<const rt::Function> LookupFunctionByName( + rt::Function::Linkage linkage, absl::string_view name) const override; + + StatusOr<absl::string_view> GetFunctionName(rt::Function::Linkage linkage, + int32_t ordinal) const override; + + StatusOr<const rt::FunctionSignature> GetFunctionSignature( + rt::Function::Linkage linkage, int32_t ordinal) const override; + + StatusOr<const FunctionDef*> GetFunctionDef(rt::Function::Linkage linkage, + int32_t ordinal) const; + + StatusOr<const MultiArchExecutableDef*> LookupMultiArchExecutable( + int executable_ordinal) const; + + protected: + BytecodeModule(std::unique_ptr<ModuleFile> module_file, + OpcodeTable opcode_table); + + static Status ValidateArgType(const hal::BufferView& arg, + const MemRefTypeDef& expected_type); + + private: + StatusOr<int32_t> MapFunctionOrdinal(rt::Function::Linkage linkage, + int32_t ordinal) const; + + std::unique_ptr<ModuleFile> module_file_; + const ModuleDef& module_def_; + mutable SourceMapResolver source_resolver_; + mutable std::unique_ptr<rt::Disassembler> disassembler_; +}; + +} // namespace vm +} // namespace iree + +#endif // IREE_VM_BYTECODE_MODULE_H_
diff --git a/iree/vm/bytecode_printer.h b/iree/vm/bytecode_printer.h deleted file mode 100644 index 2f2cd5b..0000000 --- a/iree/vm/bytecode_printer.h +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_BYTECODE_PRINTER_H_ -#define IREE_VM_BYTECODE_PRINTER_H_ - -#include <ostream> - -#include "iree/base/status.h" -#include "iree/schemas/bytecode_def_generated.h" -#include "iree/schemas/source_map_def_generated.h" -#include "iree/vm/executable_table.h" -#include "iree/vm/function_table.h" -#include "iree/vm/opcode_info.h" -#include "iree/vm/source_map.h" - -namespace iree { -namespace vm { - -// Prints bytecode in a text format to enable human-inspection. -// Optionally can interleave original source location information if a SourceMap -// is available. -class BytecodePrinter { - public: - static std::string ToString(OpcodeTable opcode_table, - const FunctionTable& function_table, - const ExecutableTable& executable_table, - const SourceMapResolver& source_map_resolver, - const BytecodeDef& bytecode_def); - - explicit BytecodePrinter(OpcodeTable opcode_table, - const FunctionTable& function_table, - const ExecutableTable& executable_table, - const SourceMapResolver& source_map_resolver) - : opcode_table_(opcode_table), - function_table_(function_table), - executable_table_(executable_table), - source_map_resolver_(source_map_resolver) {} - - StatusOr<std::string> Print(const BytecodeDef& bytecode_def) const; - - Status PrintToStream(const BytecodeDef& bytecode_def, - std::ostream* stream) const; - Status PrintToStream(absl::Span<const uint8_t> data, - std::ostream* stream) const; - - private: - OpcodeTable opcode_table_; - const FunctionTable& function_table_; - const ExecutableTable& executable_table_; - const SourceMapResolver& source_map_resolver_; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_BYTECODE_PRINTER_H_
diff --git a/iree/vm/bytecode_reader.cc b/iree/vm/bytecode_reader.cc index cd1e0bf..65e69f3 100644 --- a/iree/vm/bytecode_reader.cc +++ b/iree/vm/bytecode_reader.cc
@@ -17,12 +17,16 @@ #include "iree/base/shape.h" #include "iree/base/status.h" #include "iree/hal/heap_buffer.h" +#include "iree/vm/bytecode_module.h" namespace iree { namespace vm { namespace { + using ::iree::hal::BufferView; +using ::iree::rt::StackFrame; + } // namespace StatusOr<const uint8_t*> BytecodeReader::AdvanceOffset() { @@ -30,18 +34,10 @@ // TODO(benvanik): make a flag and/or remove. DVLOG(1) << "dispatch(" << stack_frame_->function().name() << "@" << offset() << "): " << int(*bytecode_pc_); - for (int i = 0; i < locals_.size(); ++i) { - DVLOG(1) << "local[" << i << "] " << locals_[i].DebugStringShort(); + for (int i = 0; i < registers_->buffer_views.size(); ++i) { + DVLOG(1) << "local[" << i << "] " + << registers_->buffer_views[i].DebugStringShort(); } - - if (breakpoint_table_) { - auto it = breakpoint_table_->find(offset()); - if (it != breakpoint_table_->end()) { - // Breakpoint hit! - RETURN_IF_ERROR(it->second(*stack_)); - } - } - return bytecode_pc_++; } @@ -128,29 +124,26 @@ // Setup state pointers for faster dereferencing. const auto& function = new_stack_frame->function(); - const auto& bytecode = *function.def().bytecode(); + ASSIGN_OR_RETURN( + const auto* function_def, + static_cast<const BytecodeModule*>(function.module()) + ->GetFunctionDef(function.linkage(), function.ordinal())); + const auto& bytecode = *function_def->bytecode(); bytecode_base_ = bytecode.contents()->Data(); bytecode_limit_ = bytecode_base_ + bytecode.contents()->size(); bytecode_pc_ = bytecode_base_ + new_stack_frame->offset(); - locals_ = new_stack_frame->mutable_locals(); - // TODO(benvanik): reimplement breakpoints as bytecode rewriting. - int function_ordinal = function.module() - .function_table() - .LookupFunctionOrdinal(function) - .ValueOrDie(); - breakpoint_table_ = - function.module().function_table().GetFunctionBreakpointTable( - function_ordinal); + registers_ = new_stack_frame->mutable_registers(); return OkStatus(); } Status BytecodeReader::CopyInputsAndSwitchStackFrame( StackFrame* src_stack_frame, StackFrame* dst_stack_frame) { - ASSIGN_OR_RETURN(int32_t src_count, ReadCount()); - for (int i = 0; i < src_count; ++i) { + ASSIGN_OR_RETURN(size_t src_count, ReadCount()); + auto& dst_buffer_views = dst_stack_frame->mutable_registers()->buffer_views; + for (int i = 0; i < std::min(src_count, dst_buffer_views.size()); ++i) { ASSIGN_OR_RETURN(auto* src_local, - ReadLocal(src_stack_frame->mutable_locals())); - *dst_stack_frame->mutable_local(i) = *src_local; + ReadLocal(src_stack_frame->mutable_registers())); + dst_buffer_views[i] = *src_local; } return SwitchStackFrame(dst_stack_frame); } @@ -162,7 +155,7 @@ absl::InlinedVector<BufferView*, 8> src_locals(src_count); for (int i = 0; i < src_count; ++i) { ASSIGN_OR_RETURN(src_locals[i], - ReadLocal(src_stack_frame->mutable_locals())); + ReadLocal(src_stack_frame->mutable_registers())); } RETURN_IF_ERROR(SwitchStackFrame(dst_stack_frame)); ASSIGN_OR_RETURN(int32_t dst_count, ReadCount()); @@ -173,7 +166,7 @@ } for (int i = 0; i < dst_count; ++i) { ASSIGN_OR_RETURN(auto* dst_local, - ReadLocal(dst_stack_frame->mutable_locals())); + ReadLocal(dst_stack_frame->mutable_registers())); *dst_local = *src_locals[i]; } return OkStatus(); @@ -183,9 +176,9 @@ ASSIGN_OR_RETURN(int32_t count, ReadCount()); for (int i = 0; i < count; ++i) { ASSIGN_OR_RETURN(auto* src_local, - ReadLocal(stack_frame_->mutable_locals())); + ReadLocal(stack_frame_->mutable_registers())); ASSIGN_OR_RETURN(auto* dst_local, - ReadLocal(stack_frame_->mutable_locals())); + ReadLocal(stack_frame_->mutable_registers())); *dst_local = *src_local; } return OkStatus();
diff --git a/iree/vm/bytecode_reader.h b/iree/vm/bytecode_reader.h index 6ba8227..f2b85fd 100644 --- a/iree/vm/bytecode_reader.h +++ b/iree/vm/bytecode_reader.h
@@ -19,10 +19,10 @@ #include "absl/container/inlined_vector.h" #include "iree/base/status.h" #include "iree/hal/buffer_view.h" +#include "iree/rt/context.h" +#include "iree/rt/stack.h" +#include "iree/rt/stack_frame.h" #include "iree/schemas/bytecode/bytecode_v0.h" -#include "iree/vm/function.h" -#include "iree/vm/stack.h" -#include "iree/vm/stack_frame.h" #include "iree/vm/type.h" namespace iree { @@ -30,19 +30,19 @@ class BytecodeReader { public: - explicit BytecodeReader(Stack* stack) : stack_(stack) {} + explicit BytecodeReader(rt::Stack* stack) : stack_(stack) {} int offset() const { return static_cast<int>(bytecode_pc_ - bytecode_base_); } StatusOr<const uint8_t*> AdvanceOffset(); - Status SwitchStackFrame(StackFrame* new_stack_frame); + Status SwitchStackFrame(rt::StackFrame* new_stack_frame); Status BranchToOffset(int32_t offset); - Status CopyInputsAndSwitchStackFrame(StackFrame* src_stack_frame, - StackFrame* dst_stack_frame); - Status CopyResultsAndSwitchStackFrame(StackFrame* src_stack_frame, - StackFrame* dst_stack_frame); + Status CopyInputsAndSwitchStackFrame(rt::StackFrame* src_stack_frame, + rt::StackFrame* dst_stack_frame); + Status CopyResultsAndSwitchStackFrame(rt::StackFrame* src_stack_frame, + rt::StackFrame* dst_stack_frame); Status CopySlots(); StatusOr<hal::BufferView> ReadConstant(); @@ -56,32 +56,33 @@ return Type::FromTypeIndex(type_index); } - ABSL_ATTRIBUTE_ALWAYS_INLINE StatusOr<const Function> ReadFunction() { + ABSL_ATTRIBUTE_ALWAYS_INLINE StatusOr<const rt::Function> ReadFunction() { ASSIGN_OR_RETURN(auto value, ReadValue<uint32_t>()); const auto& module = stack_frame_->module(); - return module.function_table().LookupFunction(value); + return module.LookupFunctionByOrdinal(rt::Function::Linkage::kInternal, + value); } - ABSL_ATTRIBUTE_ALWAYS_INLINE StatusOr<const ImportFunction*> + ABSL_ATTRIBUTE_ALWAYS_INLINE StatusOr<const rt::Function> ReadImportFunction() { ASSIGN_OR_RETURN(auto value, ReadValue<uint32_t>()); const auto& module = stack_frame_->module(); - return module.function_table().LookupImport(value); + return stack_->context()->ResolveImport(&module, value); } ABSL_ATTRIBUTE_ALWAYS_INLINE StatusOr<hal::BufferView*> ReadLocal( - absl::Span<hal::BufferView> locals) { + rt::Registers* registers) { ASSIGN_OR_RETURN(auto value, ReadValue<uint16_t>()); - if (value > locals.size()) { + if (value > registers->buffer_views.size()) { return OutOfRangeErrorBuilder(IREE_LOC) << "Out of bounds local access " << value << " of " - << locals.size(); + << registers->buffer_views.size(); } - return &locals[value]; + return ®isters->buffer_views[value]; } ABSL_ATTRIBUTE_ALWAYS_INLINE StatusOr<hal::BufferView*> ReadLocal() { - return ReadLocal(locals_); + return ReadLocal(registers_); } Status SkipLocals(int count); @@ -105,7 +106,7 @@ template <typename T, size_t N = 8> ABSL_ATTRIBUTE_ALWAYS_INLINE StatusOr<absl::InlinedVector<T, N>> ReadSlotElements() { - ASSIGN_OR_RETURN(auto* local, ReadLocal(locals_)); + ASSIGN_OR_RETURN(auto* local, ReadLocal(registers_)); absl::InlinedVector<T, N> result(local->shape.element_count()); if (sizeof(T) == local->element_size) { // Fast(ish) path: requested element size matches the actual element size. @@ -154,13 +155,12 @@ return value; } - Stack* stack_ = nullptr; - StackFrame* stack_frame_ = nullptr; + rt::Stack* stack_ = nullptr; + rt::StackFrame* stack_frame_ = nullptr; const uint8_t* bytecode_base_ = nullptr; const uint8_t* bytecode_limit_ = nullptr; const uint8_t* bytecode_pc_ = nullptr; - absl::Span<hal::BufferView> locals_; - FunctionTable::BreakpointTable* breakpoint_table_ = nullptr; + rt::Registers* registers_ = nullptr; }; } // namespace vm
diff --git a/iree/vm/bytecode_validator.cc b/iree/vm/bytecode_validator.cc index c8a3bbd..968b193 100644 --- a/iree/vm/bytecode_validator.cc +++ b/iree/vm/bytecode_validator.cc
@@ -18,7 +18,7 @@ namespace vm { // static -Status BytecodeValidator::Validate(const Context& context, const Module& module, +Status BytecodeValidator::Validate(const BytecodeModule& module, const BytecodeDef& bytecode_def) { // TODO(benvanik): validate bytecode. return OkStatus();
diff --git a/iree/vm/bytecode_validator.h b/iree/vm/bytecode_validator.h index bf435dc..429c754 100644 --- a/iree/vm/bytecode_validator.h +++ b/iree/vm/bytecode_validator.h
@@ -17,8 +17,7 @@ #include "iree/base/status.h" #include "iree/schemas/bytecode_def_generated.h" -#include "iree/vm/context.h" -#include "iree/vm/module.h" +#include "iree/vm/bytecode_module.h" namespace iree { namespace vm { @@ -28,7 +27,7 @@ // be resolved with matching signatures. class BytecodeValidator { public: - static Status Validate(const Context& context, const Module& module, + static Status Validate(const BytecodeModule& module, const BytecodeDef& bytecode_def); };
diff --git a/iree/vm/context.cc b/iree/vm/context.cc deleted file mode 100644 index bae330a..0000000 --- a/iree/vm/context.cc +++ /dev/null
@@ -1,111 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/context.h" - -#include "iree/base/flatbuffer_util.h" -#include "iree/base/status.h" - -namespace iree { -namespace vm { - -namespace { - -int NextUniqueId() { - static int next_id = 0; - return ++next_id; -} - -} // namespace - -Context::Context() : id_(NextUniqueId()) {} - -Context::~Context() = default; - -Status Context::RegisterNativeFunction(std::string name, - NativeFunction native_function) { - native_functions_.emplace_back(std::move(name), std::move(native_function)); - return OkStatus(); -} - -Status Context::RegisterModule(std::unique_ptr<Module> module) { - // Attempt to link the module. - RETURN_IF_ERROR(module->mutable_function_table()->ResolveImports( - [&](const Module& importing_module, - const FunctionDef& import_function_def) -> StatusOr<ImportFunction> { - absl::string_view export_name = WrapString(import_function_def.name()); - - // Try to find a native function (we prefer these). - for (const auto& native_function : native_functions_) { - if (native_function.first == export_name) { - LOG(INFO) << "Resolved import '" << export_name - << "' to native function"; - return ImportFunction(importing_module, import_function_def, - native_function.second); - } - } - - // Try to find an export in an existing module. - // We prefer the more recently registered modules. - // NOTE: slow O(n*m) search through all modules * exports. - for (auto it = modules_.rbegin(); it != modules_.rend(); ++it) { - const auto& module = *it; - auto export_or = module->function_table().LookupExport(export_name); - if (export_or.ok()) { - LOG(INFO) << "Resolved import '" << export_name << "' to module " - << module->name(); - return ImportFunction(importing_module, import_function_def, - export_or.ValueOrDie()); - } - } - - return NotFoundErrorBuilder(IREE_LOC) - << "Import '" << export_name << "' could not be resolved"; - })); - - modules_.push_back(std::move(module)); - return OkStatus(); -} - -StatusOr<const Module*> Context::LookupModule( - absl::string_view module_name) const { - return const_cast<Context*>(this)->LookupModule(module_name); -} - -StatusOr<Module*> Context::LookupModule(absl::string_view module_name) { - for (const auto& module : modules_) { - if (module->name() == module_name) { - return module.get(); - } - } - return NotFoundErrorBuilder(IREE_LOC) - << "No module with the name '" << module_name - << "' has been registered"; -} - -StatusOr<const Function> Context::LookupExport( - absl::string_view export_name) const { - for (const auto& module : modules_) { - auto export_or = module->function_table().LookupExport(export_name); - if (export_or.ok()) { - return export_or.ValueOrDie(); - } - } - return NotFoundErrorBuilder(IREE_LOC) - << "No export with the name '" << export_name - << "' is present in the context"; -} - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/context.h b/iree/vm/context.h deleted file mode 100644 index 6c3682b..0000000 --- a/iree/vm/context.h +++ /dev/null
@@ -1,91 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_CONTEXT_H_ -#define IREE_VM_CONTEXT_H_ - -#include <memory> -#include <vector> - -#include "absl/strings/string_view.h" -#include "absl/types/span.h" -#include "iree/base/status.h" -#include "iree/vm/function.h" -#include "iree/vm/module.h" - -namespace iree { -namespace vm { - -// An isolated execution context. -// Effectively a sandbox where modules can be loaded and run with restricted -// visibility. Each context may have its own set of imports that modules can -// access and its own resource constraints. -// -// The function namespace is shared within a context, meaning that an import of -// function 'a' from a module will resolve to an export of function 'a' from -// another. Functions internal to a module are not resolved through the -// namespace and may share names (or have no names at all). -// -// Modules have imports resolved automatically when loaded by searching existing -// modules. This means that load order is important to ensure overrides are -// respected. For example, target-specific modules should be loaded prior to -// generic modules that may import functions defined there and if a function is -// not available in the target-specific modules the fallback provided by the -// generic module will be used. -// -// TODO(benvanik): evaluate if worth making thread-safe (epochs/generational). -// Contexts are thread-compatible; const methods may be called concurrently from -// any thread (including Invoke), however no threads must be using a shared -// Context while new native functions or modules are registered. -class Context { - public: - Context(); - Context(const Context&) = delete; - Context& operator=(const Context&) = delete; - Context(Context&&) = default; - Context& operator=(Context&&) = default; - virtual ~Context(); - - // A process-unique ID for the context. - int id() const { return id_; } - - // TODO(benvanik): make immutable by moving to a static Create fn. - virtual Status RegisterNativeFunction(std::string name, - NativeFunction native_function); - - virtual Status RegisterModule(std::unique_ptr<Module> module); - - const std::vector<std::pair<std::string, NativeFunction>>& native_functions() - const { - return native_functions_; - } - - const std::vector<std::unique_ptr<Module>>& modules() const { - return modules_; - } - - StatusOr<const Module*> LookupModule(absl::string_view module_name) const; - StatusOr<Module*> LookupModule(absl::string_view module_name); - StatusOr<const Function> LookupExport(absl::string_view export_name) const; - - private: - int id_; - std::vector<std::pair<std::string, NativeFunction>> native_functions_; - std::vector<std::unique_ptr<Module>> modules_; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_CONTEXT_H_
diff --git a/iree/vm/executable_table.cc b/iree/vm/executable_table.cc deleted file mode 100644 index 0752fa3..0000000 --- a/iree/vm/executable_table.cc +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/executable_table.h" - -#include "iree/base/flatbuffer_util.h" -#include "iree/base/status.h" - -namespace iree { -namespace vm { - -// static -Status ExecutableTable::ValidateStructure( - const ExecutableTableDef& executable_table_def) { - if (!executable_table_def.multi_arch_executables()) { - // May have sequencer only fns. Fine to not have dispatchable executables. - return OkStatus(); - } - - // All fat executables need at least one device-specific executable. - const auto& multi_arch_executables = - *executable_table_def.multi_arch_executables(); - for (int i = 0; i < multi_arch_executables.size(); ++i) { - const auto* multi_arch_executable = multi_arch_executables[i]; - if (!multi_arch_executable || !multi_arch_executable->executables() || - multi_arch_executable->executables()->size() == 0) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Multi-arch executable ordinal " << i - << " is missing its contents"; - } - } - - return OkStatus(); -} - -ExecutableTable::ExecutableTable(const ExecutableTableDef& executable_table_def) - : executable_table_def_(executable_table_def) {} - -ExecutableTable::~ExecutableTable() = default; - -StatusOr<const MultiArchExecutableDef*> -ExecutableTable::LookupMultiArchExecutable(int executable_ordinal) const { - if (executable_ordinal < 0 || - executable_ordinal >= - executable_table_def_.multi_arch_executables()->size()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Invalid multi-arch executable ordinal " << executable_ordinal; - } - return executable_table_def_.multi_arch_executables()->Get( - executable_ordinal); -} - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/executable_table.h b/iree/vm/executable_table.h deleted file mode 100644 index e26918d..0000000 --- a/iree/vm/executable_table.h +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_EXECUTABLE_TABLE_H_ -#define IREE_VM_EXECUTABLE_TABLE_H_ - -#include "iree/base/status.h" -#include "iree/schemas/executable_table_def_generated.h" - -namespace iree { -namespace vm { - -// A table of executables present within a module. -// Manages lookup and selection of executables based on target devices. -// -// Thread-safe. -class ExecutableTable { - public: - static Status ValidateStructure( - const ExecutableTableDef& executable_table_def); - - explicit ExecutableTable(const ExecutableTableDef& executable_table_def); - ExecutableTable(const ExecutableTable&) = delete; - ExecutableTable& operator=(const ExecutableTable&) = delete; - ~ExecutableTable(); - - const ExecutableTableDef& def() const { return executable_table_def_; } - - StatusOr<const MultiArchExecutableDef*> LookupMultiArchExecutable( - int executable_ordinal) const; - - // TODO(benvanik): resolve executable by ID+format+features (ExecutableDef). - - // TODO(benvanik): insert/get HAL executables (thread-safe!). - - private: - const ExecutableTableDef& executable_table_def_; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_EXECUTABLE_TABLE_H_
diff --git a/iree/vm/fiber_state.cc b/iree/vm/fiber_state.cc deleted file mode 100644 index 90d9fd4..0000000 --- a/iree/vm/fiber_state.cc +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/fiber_state.h" - -#include <iterator> - -#include "absl/strings/str_join.h" -#include "iree/base/status.h" - -namespace iree { -namespace vm { - -FiberState::FiberState(std::shared_ptr<Instance> instance) - : instance_(std::move(instance)), id_(Instance::NextUniqueId()) { -} - -FiberState::~FiberState() { -} - -bool FiberState::is_suspended() { - // TODO(benvanik): implement. - return false; -} - -Status FiberState::Suspend(SuspendCallback suspend_callback) { - DVLOG(1) << "Suspending fiber " << id(); - return OkStatus(); -} - -Status FiberState::Resume() { - DVLOG(1) << "Resuming fiber " << id(); - return OkStatus(); -} - -Status FiberState::Step(StepTarget step_target, - SuspendCallback suspend_callback) { - return UnimplementedErrorBuilder(IREE_LOC) << "Step not yet implemented"; -} - -namespace { -struct StackFrameFormatter { - void operator()(std::string* out, const StackFrame& stack_frame) const { - out->append(absl::StrCat(stack_frame.module().name(), ":", - stack_frame.function().name(), "@", - stack_frame.offset())); - } -}; -} // namespace - -std::string FiberState::DebugString() const { - auto frames = stack_.frames(); - return absl::StrJoin(frames.begin(), frames.end(), "\n", - StackFrameFormatter()); -} - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/fiber_state.h b/iree/vm/fiber_state.h deleted file mode 100644 index 5799831..0000000 --- a/iree/vm/fiber_state.h +++ /dev/null
@@ -1,113 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_FIBER_STATE_H_ -#define IREE_VM_FIBER_STATE_H_ - -#include <functional> - -#include "absl/types/span.h" -#include "iree/base/status.h" -#include "iree/vm/instance.h" -#include "iree/vm/stack.h" - -namespace iree { -namespace vm { - -// Fiber call stack and state machine model. -// Fibers may not line up with host application threads and execution may move -// across threads. -// -// Fibers are thread-compatible. Certain methods, such as Suspend and Resume -// (and others that explicitly call them) may be called from other threads, -// however members and other methods should be assumed safe to use only from -// the owning thread or when is_suspended returns true. -class FiberState { - public: - // Called when a fiber completes suspending (in response to a Suspend or Step - // request). The |suspend_status| will indicate if the suspension was - // successful. - using SuspendCallback = std::function<void(Status suspend_status)>; - - struct StepTarget { - // TODO(benvanik): step target info (matching RPC message). - // module / function / offset - // relative to current: once, out, return, etc - }; - - explicit FiberState(std::shared_ptr<Instance> instance); - FiberState(const FiberState&) = delete; - FiberState& operator=(const FiberState&) = delete; - ~FiberState(); - - // A process-unique ID for the fiber. - int id() const { return id_; } - - const std::shared_ptr<Instance>& instance() const { return instance_; } - - // VM call stack. - // NOTE: only valid while suspended. - const Stack& stack() const { return stack_; } - Stack* mutable_stack() { return &stack_; } - - // Returns true if the fiber is suspended. - // This only returns true if the fiber has been requested to suspend with - // Suspend and the runtime has acked the suspend. Once suspended (and until - // resumed) fiber state will not change and may be observed from any thread. - // - // Safe to call from any thread. - bool is_suspended(); - - // Suspends the fiber at the next possible chance. - // - // Fibers have a suspension depth and each call to Suspend must be matched - // with a call to Resume. Fibers will only resume excution when all prior - // Suspend calls have their matching Resume called. - // - // Optionally callers may provide a |suspend_callback| that will be called - // from a random thread when the fiber is suspended (or fails to suspend). - // - // Safe to call from any thread. - Status Suspend(SuspendCallback suspend_callback = nullptr); - - // Resumes the fiber if it is suspended (or cancels a pending suspend). - // This may wake threads if they are currently waiting on the fiber to - // execute. - // - // Safe to call from any thread. - Status Resume(); - - // Steps fiber execution. - // This will attempt to resume the fiber and will complete asynchronously. - // Upon returning the fiber should be assumed resumed and callers must query - // is_suspended to wait until the fiber suspends again. Optionally callers may - // provide a |suspend_callback| that will be called from a random thread when - // the fiber is suspended (or fails to suspend). - // - // Safe to call from any thread while the fiber is suspended. - Status Step(StepTarget step_target, - SuspendCallback suspend_callback = nullptr); - - std::string DebugString() const; - - private: - std::shared_ptr<Instance> instance_; - int id_; - Stack stack_; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_FIBER_STATE_H_
diff --git a/iree/vm/function.cc b/iree/vm/function.cc deleted file mode 100644 index 1e92c28..0000000 --- a/iree/vm/function.cc +++ /dev/null
@@ -1,121 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/function.h" - -#include "absl/strings/str_cat.h" -#include "absl/strings/str_join.h" -#include "iree/base/flatbuffer_util.h" -#include "iree/schemas/type_def_generated.h" - -namespace iree { -namespace vm { - -namespace { - -struct TypeFormatter { - void operator()(std::string* out, const TypeDef* type_def) const { - switch (type_def->type_union_type()) { - case TypeDefUnion::MemRefTypeDef: - (*this)(out, type_def->type_union_as_MemRefTypeDef()); - return; - case TypeDefUnion::DeviceTypeDef: - out->append("device"); - return; - case TypeDefUnion::CommandBufferTypeDef: - out->append("command_buffer"); - return; - case TypeDefUnion::EventTypeDef: - out->append("event"); - return; - case TypeDefUnion::SemaphoreTypeDef: - out->append("semaphore"); - return; - case TypeDefUnion::FenceTypeDef: - out->append("fence"); - return; - default: - out->append("<invalid>"); - return; - } - } - - void operator()(std::string* out, - const MemRefTypeDef* mem_ref_type_def) const { - out->append("memref<"); - if (mem_ref_type_def->shape()) { - for (int dim : *mem_ref_type_def->shape()) { - out->append(std::to_string(dim)); - out->append("x"); - } - } else { - out->append("?x"); - } - (*this)(out, mem_ref_type_def->element_type()); - out->append(">"); - } - - void operator()(std::string* out, const ElementTypeDef* type_def) const { - switch (type_def->type_union_type()) { - case ElementTypeDefUnion::FloatTypeDef: { - const auto* float_type_def = type_def->type_union_as_FloatTypeDef(); - out->append("f"); - out->append(std::to_string(float_type_def->width())); - break; - } - case ElementTypeDefUnion::IntegerTypeDef: { - const auto* int_type_def = type_def->type_union_as_IntegerTypeDef(); - out->append("i"); - out->append(std::to_string(int_type_def->width())); - break; - } - case ElementTypeDefUnion::UnknownTypeDef: { - const auto* unknown_type_def = type_def->type_union_as_UnknownTypeDef(); - out->append("unknown<"); - auto dialect_str = WrapString(unknown_type_def->dialect()); - out->append(dialect_str.data(), dialect_str.size()); - auto type_data_str = WrapString(unknown_type_def->type_data()); - out->append(type_data_str.data(), type_data_str.size()); - out->append(">"); - break; - } - default: - out->append("<invalid>"); - return; - } - } -}; - -} // namespace - -std::string Function::DebugStringShort() const { - return absl::StrCat( - name(), "(", - type_def().inputs() - ? absl::StrJoin(*type_def().inputs(), ", ", TypeFormatter()) - : "", - ") -> (", - type_def().results() - ? absl::StrJoin(*type_def().results(), ", ", TypeFormatter()) - : "", - ")"); -} - -std::string ImportFunction::DebugStringShort() const { - // TODO(benvanik): import function strings. - return "(IMPORT)"; -} - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/function.h b/iree/vm/function.h deleted file mode 100644 index 7f590a0..0000000 --- a/iree/vm/function.h +++ /dev/null
@@ -1,124 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_FUNCTION_H_ -#define IREE_VM_FUNCTION_H_ - -#include <functional> - -#include "absl/strings/string_view.h" -#include "absl/types/span.h" -#include "iree/base/flatbuffer_util.h" -#include "iree/base/status.h" -#include "iree/hal/buffer_view.h" -#include "iree/schemas/function_def_generated.h" -#include "iree/schemas/type_def_generated.h" - -namespace iree { -namespace vm { - -class Stack; -class Module; - -// TODO(benvanik): reorganize this; I don't like it. maybe ImportFunction -// shouldn't derive from Function at all? - -// A function defined within a Module. -// Imported functions may be of the ImportFunction type and contain additional -// runtime linkage information. -class Function { - public: - Function() = default; - Function(const Module& module, const FunctionDef& function_def) - : module_(&module), function_def_(&function_def) {} - - absl::string_view name() const { return WrapString(function_def_->name()); } - - const Module& module() const { return *module_; } - const FunctionDef& def() const { return *function_def_; } - const FunctionTypeDef& type_def() const { return *def().type(); } - - int input_count() const { - return type_def().inputs() ? type_def().inputs()->size() : 0; - } - int result_count() const { - return type_def().results() ? type_def().results()->size() : 0; - } - - std::string DebugStringShort() const; - - private: - const Module* module_ = nullptr; - const FunctionDef* function_def_ = nullptr; -}; - -inline std::ostream& operator<<(std::ostream& stream, - const Function& function) { - stream << function.DebugStringShort(); - return stream; -} - -// TODO(benvanik): make an interface as well. -// TODO(benvanik): pass through additional attributes. -using NativeFunction = - std::function<Status(Stack* stack, absl::Span<hal::BufferView> args, - absl::Span<hal::BufferView> results)>; - -// A function imported into a Module from either a native function or other -// module. -class ImportFunction : public Function { - public: - enum class LinkType { - kNativeFunction, - kModule, - }; - - ImportFunction() = default; - ImportFunction(const Module& module, const FunctionDef& function_def, - NativeFunction native_function) - : Function(module, function_def), - link_type_(LinkType::kNativeFunction), - native_function_(std::move(native_function)) {} - ImportFunction(const Module& module, const FunctionDef& function_def, - Function linked_function) - : Function(module, function_def), - link_type_(LinkType::kModule), - linked_function_(std::move(linked_function)) {} - ImportFunction(const ImportFunction&) = delete; - ImportFunction& operator=(const ImportFunction&) = delete; - ImportFunction(ImportFunction&&) = default; - ImportFunction& operator=(ImportFunction&&) = default; - - LinkType link_type() const { return link_type_; } - const NativeFunction& native_function() const { return native_function_; } - const Function& linked_function() const { return linked_function_; } - - std::string DebugStringShort() const; - - private: - LinkType link_type_; - NativeFunction native_function_; - Function linked_function_; -}; - -inline std::ostream& operator<<(std::ostream& stream, - const ImportFunction& function) { - stream << function.DebugStringShort(); - return stream; -} - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_FUNCTION_H_
diff --git a/iree/vm/function_table.cc b/iree/vm/function_table.cc deleted file mode 100644 index 1e629bd..0000000 --- a/iree/vm/function_table.cc +++ /dev/null
@@ -1,261 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/function_table.h" - -#include "absl/container/flat_hash_map.h" -#include "iree/base/flatbuffer_util.h" -#include "iree/base/status.h" - -namespace iree { -namespace vm { - -namespace { - -Status ValidateType(const FunctionTypeDef& type_def) { - // Ensure all fields are populated. - return OkStatus(); -} - -} // namespace - -// static -Status FunctionTable::ValidateStructure( - const FunctionTableDef& function_table_def) { - if (!function_table_def.functions()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Function table is missing the function listing"; - } - - // All functions must contain a valid type. - const auto& functions = *function_table_def.functions(); - for (int i = 0; i < functions.size(); ++i) { - const auto* function = functions[i]; - if (!function) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Function ordinal " << i << " is missing its contents"; - } - if (!function->type()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Function ordinal " << i << " is missing its type"; - } - RETURN_IF_ERROR(ValidateType(*function->type())); - } - - // Imports must also have a name (that we can use to resolve it). - if (function_table_def.imports()) { - const auto& imports = *function_table_def.imports(); - for (int i = 0; i < imports.size(); ++i) { - int function_index = imports[i]; - if (!functions[function_index]->name()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Import ordinal " << i << " is missing its contents"; - } - } - } - - // Exports must also have a name (that others will use to look it up). - if (function_table_def.exports()) { - const auto& exports = *function_table_def.exports(); - for (int i = 0; i < exports.size(); ++i) { - int function_index = exports[i]; - if (!functions[function_index]->name()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Export ordinal " << i << " is missing its contents"; - } - } - } - - return OkStatus(); -} - -FunctionTable::FunctionTable(const Module& module, - const FunctionTableDef& function_table_def) - : module_(module), function_table_def_(function_table_def) {} - -FunctionTable::~FunctionTable() = default; - -Status FunctionTable::ResolveImports(ImportResolver import_resolver) { - if (!function_table_def_.imports()) { - // No imports to resolve. - return OkStatus(); - } - - const auto& imports = *function_table_def_.imports(); - const auto& functions = *function_table_def_.functions(); - for (int i = 0; i < imports.size(); ++i) { - const auto* function_def = functions[imports[i]]; - ASSIGN_OR_RETURN(auto import_function, - import_resolver(module_, *function_def)); - import_functions_.push_back(std::move(import_function)); - } - - return OkStatus(); -} - -StatusOr<int> FunctionTable::LookupImportOrdinal( - absl::string_view import_name) const { - if (function_table_def_.imports()) { - const auto& imports = *function_table_def_.imports(); - const auto& functions = *function_table_def_.functions(); - for (int i = 0; i < imports.size(); ++i) { - if (WrapString(functions[imports[i]]->name()) == import_name) { - return i; - } - } - } - return NotFoundErrorBuilder(IREE_LOC) - << "Import with the name '" << import_name << "' not found in module"; -} - -StatusOr<const ImportFunction*> FunctionTable::LookupImport( - absl::string_view import_name) const { - ASSIGN_OR_RETURN(int import_ordinal, LookupImportOrdinal(import_name)); - return LookupImport(import_ordinal); -} - -StatusOr<const ImportFunction*> FunctionTable::LookupImport( - int import_ordinal) const { - if (import_ordinal < 0 || import_ordinal >= import_functions_.size()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Import ordinal " << import_ordinal - << " is outside the valid range [0, " << import_functions_.size() - << ")"; - } - return {&import_functions_[import_ordinal]}; -} - -StatusOr<int> FunctionTable::LookupExportFunctionOrdinal( - absl::string_view export_name) const { - // NOTE: this is a linear scan of the export table, but since export count - // is usually small and the only time this lookup should happen is on module - // load it's (probably) fine. - if (function_table_def_.exports()) { - const auto& exports = *function_table_def_.exports(); - for (int i = 0; i < exports.size(); ++i) { - int export_ordinal = exports.Get(i); - const auto& function_def = - *function_table_def_.functions()->Get(export_ordinal); - if (WrapString(function_def.name()) == export_name) { - return export_ordinal; - } - } - } - return NotFoundErrorBuilder(IREE_LOC) - << "Export with the name '" << export_name << "' not found in module"; -} - -StatusOr<const Function> FunctionTable::LookupExport( - absl::string_view export_name) const { - ASSIGN_OR_RETURN(int export_ordinal, - LookupExportFunctionOrdinal(export_name)); - return LookupFunction(export_ordinal); -} - -StatusOr<const Function> FunctionTable::LookupExport(int export_ordinal) const { - if (!function_table_def_.exports() || export_ordinal < 0 || - export_ordinal >= function_table_def_.exports()->size()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Export ordinal " << export_ordinal - << " is outside the valid range [0, " - << function_table_def_.exports()->size() << ")"; - } - const auto& exports = *function_table_def_.exports(); - int function_ordinal = exports.Get(export_ordinal); - return LookupFunction(function_ordinal); -} - -StatusOr<const Function> FunctionTable::LookupFunction(int ordinal) const { - if (ordinal < 0 || ordinal >= function_table_def_.functions()->size()) { - return OutOfRangeErrorBuilder(IREE_LOC) - << "Function ordinal " << ordinal - << " is outside the valid range [0, " - << function_table_def_.functions()->size() << ")"; - } - const auto* function_def = function_table_def_.functions()->Get(ordinal); - return Function(module_, *function_def); -} - -StatusOr<int> FunctionTable::LookupFunctionOrdinal( - const Function& function) const { - const auto& functions = *function_table_def_.functions(); - for (int i = 0; i < functions.size(); ++i) { - if (&function.def() == functions.Get(i)) { - return i; - } - } - return NotFoundErrorBuilder(IREE_LOC) << "Function not a member of module"; -} - -StatusOr<int> FunctionTable::LookupFunctionOrdinalByName( - absl::string_view name) const { - for (int i = 0; i < function_table_def_.functions()->size(); ++i) { - const auto* function_def = function_table_def_.functions()->Get(i); - if (WrapString(function_def->name()) == name) { - return i; - } - } - return NotFoundErrorBuilder(IREE_LOC) - << "Function '" << name - << "' not found in function table (or names have been stripped)"; -} - -Status FunctionTable::RegisterBreakpoint(int function_ordinal, int offset, - BreakpointCallback callback) { - if (breakpoint_tables_.empty()) { - breakpoint_tables_.resize(function_table_def_.functions()->size()); - } - if (function_ordinal < 0 || function_ordinal > breakpoint_tables_.size()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Function ordinal " << function_ordinal << " out of bounds"; - } - if (!breakpoint_tables_[function_ordinal]) { - breakpoint_tables_[function_ordinal] = - absl::make_unique<absl::flat_hash_map<int, BreakpointCallback>>(); - } - auto& function_table = *breakpoint_tables_[function_ordinal]; - function_table[offset] = std::move(callback); - return OkStatus(); -} - -Status FunctionTable::UnregisterBreakpoint(int function_ordinal, int offset) { - if (function_ordinal < 0 || function_ordinal > breakpoint_tables_.size()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Function ordinal " << function_ordinal << " out of bounds"; - } - auto* function_table = breakpoint_tables_[function_ordinal].get(); - if (function_table) { - auto it = function_table->find(offset); - if (it != function_table->end()) { - function_table->erase(it); - } - } - return OkStatus(); -} - -Status FunctionTable::UnregisterAllBreakpoints() { - breakpoint_tables_.clear(); - return OkStatus(); -} - -FunctionTable::BreakpointTable* FunctionTable::GetFunctionBreakpointTable( - int function_ordinal) const { - if (function_ordinal < 0 || function_ordinal >= breakpoint_tables_.size()) { - return nullptr; - } - return breakpoint_tables_[function_ordinal].get(); -} - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/function_table.h b/iree/vm/function_table.h deleted file mode 100644 index e7a1034..0000000 --- a/iree/vm/function_table.h +++ /dev/null
@@ -1,125 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_FUNCTION_TABLE_H_ -#define IREE_VM_FUNCTION_TABLE_H_ - -#include <functional> -#include <vector> - -#include "absl/container/flat_hash_map.h" -#include "absl/strings/string_view.h" -#include "absl/types/span.h" -#include "iree/base/status.h" -#include "iree/schemas/function_table_def_generated.h" -#include "iree/vm/function.h" - -namespace iree { -namespace vm { - -class Stack; -class Module; - -// A table of functions present within a module. -// Manages the import table, local function resolution, and breakpoints. -// -// Function tables are normally thread-compatible. Debugging-specific methods -// like RegisterBreakpoint must only be called when the debugger has suspended -// all fibers that could be executing functions from the table. -class FunctionTable { - public: - static Status ValidateStructure(const FunctionTableDef& function_table_def); - - FunctionTable(const Module& module, - const FunctionTableDef& function_table_def); - FunctionTable(const FunctionTable&) = delete; - FunctionTable& operator=(const FunctionTable&) = delete; - ~FunctionTable(); - - const FunctionTableDef& def() const { return function_table_def_; } - - using ImportResolver = std::function<StatusOr<ImportFunction>( - const Module& importing_module, const FunctionDef& import_function_def)>; - Status ResolveImports(ImportResolver import_resolver); - - StatusOr<const ImportFunction*> LookupImport( - absl::string_view import_name) const; - StatusOr<const ImportFunction*> LookupImport(int import_ordinal) const; - - StatusOr<const Function> LookupExport(absl::string_view export_name) const; - StatusOr<const Function> LookupExport(int export_ordinal) const; - - StatusOr<const Function> LookupFunction(int ordinal) const; - - StatusOr<int> LookupFunctionOrdinal(const Function& function) const; - StatusOr<int> LookupFunctionOrdinalByName(absl::string_view name) const; - - // Handles breakpoints that are encountered during execution. - // The current function and offset within the function will be provided. - // The fiber is set as suspended prior to issuing the callback and resumed - // if the callback returns ok. - // - // Implementations can use the return status to indicate intended program - // flow: - // - return ok to resume the fiber and continue execution - // - return abort to terminate the fiber - // - return an error to propagate via normal error handling logic - using BreakpointCallback = std::function<Status(const Stack& stack)>; - - // Registers a breakpoint for an operation offset within a function. - // The provided callback will be issued when the breakpoint is hit. If a - // breakpoint already exists for the given offset it will be replaced. - // - // The global debug lock must be held and all fibers must be suspended. - Status RegisterBreakpoint(int function_ordinal, int offset, - BreakpointCallback callback); - - // Unregisters a breakpoint, if one has been registered. - // - // The global debug lock must be held and all fibers must be suspended. - Status UnregisterBreakpoint(int function_ordinal, int offset); - - // Unregisters all breakpoints in the function table. - // - // The global debug lock must be held and all fibers must be suspended. - Status UnregisterAllBreakpoints(); - - using BreakpointTable = absl::flat_hash_map<int, BreakpointCallback>; - - // Returns the breakpoint table mapping offset to breakpoint callback. - // Returns nullptr if the given function does not have a breakpoint table. - // - // This table is not synchronized and while the debug lock is held it must not - // be accessed by any other threads. Reading is otherwise safe. - BreakpointTable* GetFunctionBreakpointTable(int function_ordinal) const; - - private: - StatusOr<int> LookupImportOrdinal(absl::string_view import_name) const; - StatusOr<int> LookupExportFunctionOrdinal( - absl::string_view export_name) const; - - const Module& module_; - const FunctionTableDef& function_table_def_; - std::vector<ImportFunction> import_functions_; - - // One slot per function in the function table. The hash map contains the - // breakpoints for that particular function mapped by offset within the - // function. - std::vector<std::unique_ptr<BreakpointTable>> breakpoint_tables_; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_FUNCTION_TABLE_H_
diff --git a/iree/vm/instance.cc b/iree/vm/instance.cc deleted file mode 100644 index 7668d73..0000000 --- a/iree/vm/instance.cc +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/instance.h" - -#include "absl/memory/memory.h" -#include "iree/base/source_location.h" -#include "iree/base/status.h" - -namespace iree { -namespace vm { - -// static -int Instance::NextUniqueId() { - static int next_id = 0; - return ++next_id; -} - -Instance::Instance() - : device_manager_(absl::make_unique<hal::DeviceManager>()) {} - -Instance::~Instance() = default; - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/instance.h b/iree/vm/instance.h deleted file mode 100644 index 68c4524..0000000 --- a/iree/vm/instance.h +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_INSTANCE_H_ -#define IREE_VM_INSTANCE_H_ - -#include <memory> - -#include "iree/hal/device_manager.h" - -namespace iree { -namespace vm { - -// Shared runtime instance responsible for routing Context events, enumerating -// and creating hardware device interfaces, and managing thread pools. -// -// A single runtime instance can service multiple contexts and hosting -// applications should try to reuse a runtime as much as possible. This ensures -// that resource allocation across contexts is handled and extraneous device -// interaction is avoided. -class Instance { - public: - // Allocates a global unique ID. - static int NextUniqueId(); - - Instance(); - ~Instance(); - Instance(const Instance&) = delete; - Instance& operator=(const Instance&) = delete; - - hal::DeviceManager* device_manager() const { return device_manager_.get(); } - - private: - std::unique_ptr<hal::DeviceManager> device_manager_; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_INSTANCE_H_
diff --git a/iree/vm/module.cc b/iree/vm/module.cc deleted file mode 100644 index 4aaa634..0000000 --- a/iree/vm/module.cc +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/module.h" - -#include "absl/memory/memory.h" -#include "iree/base/status.h" - -namespace iree { -namespace vm { - -// static -Status Module::ValidateStructure(const ModuleDef& module_def) { - // Must have a function table. - if (module_def.function_table()) { - RETURN_IF_ERROR( - FunctionTable::ValidateStructure(*module_def.function_table())); - } else { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "ModuleDef is missing a function table"; - } - - // May optionally have an executable table. - if (module_def.executable_table()) { - RETURN_IF_ERROR( - ExecutableTable::ValidateStructure(*module_def.executable_table())); - } - - return OkStatus(); -} - -// static -StatusOr<std::unique_ptr<Module>> Module::FromDef(const ModuleDef& module_def) { - ASSIGN_OR_RETURN(auto module_file, ModuleFile::Create(&module_def, []() {})); - return FromFile(std::move(module_file)); -} - -// static -StatusOr<std::unique_ptr<Module>> Module::FromFile( - std::unique_ptr<ModuleFile> module_file) { - if (module_file->root() == nullptr) { - return InvalidArgumentErrorBuilder(IREE_LOC) << "No root ModuleDef present"; - } - const auto& module_def = *module_file->root(); - - // Validates the structure of the module (but not bytecode). - // This ensures we don't have flatbuffer vectors will null entries, etc. - RETURN_IF_ERROR(Module::ValidateStructure(module_def)); - - auto module = absl::WrapUnique(new Module(std::move(module_file))); - - // TODO(benvanik): validate internals here? or make explicit? - - return {std::move(module)}; -} - -Module::Module(std::unique_ptr<ModuleFile> module_file) - : module_file_(std::move(module_file)), - module_def_(*module_file_->root()), - function_table_(*this, *module_def_.function_table()), - executable_table_(*module_def_.executable_table()) {} - -Module::~Module() = default; - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/module.h b/iree/vm/module.h deleted file mode 100644 index 01cfc0d..0000000 --- a/iree/vm/module.h +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_MODULE_H_ -#define IREE_VM_MODULE_H_ - -#include <memory> - -#include "iree/base/flatbuffer_util.h" -#include "iree/schemas/module_def_generated.h" -#include "iree/vm/executable_table.h" -#include "iree/vm/function_table.h" - -namespace iree { -namespace vm { - -using ModuleFile = FlatBufferFile<ModuleDef>; - -// A loaded bytecode module. -class Module { - public: - static Status ValidateStructure(const ModuleDef& module_def); - - static StatusOr<std::unique_ptr<Module>> FromDef(const ModuleDef& module_def); - static StatusOr<std::unique_ptr<Module>> FromFile( - std::unique_ptr<ModuleFile> module_file); - - Module(const Module&) = delete; - Module& operator=(const Module&) = delete; - ~Module(); - - absl::string_view name() const { return WrapString(module_def_.name()); } - - const ModuleDef& def() const { return module_def_; } - const FunctionTable& function_table() const { return function_table_; } - FunctionTable* mutable_function_table() { return &function_table_; } - const ExecutableTable& executable_table() const { return executable_table_; } - ExecutableTable* mutable_executable_table() { return &executable_table_; } - - private: - explicit Module(std::unique_ptr<ModuleFile> module_file); - - std::unique_ptr<ModuleFile> module_file_; - const ModuleDef& module_def_; - FunctionTable function_table_; - ExecutableTable executable_table_; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_MODULE_H_
diff --git a/iree/vm/module_printer.cc b/iree/vm/module_printer.cc deleted file mode 100644 index 2304d33..0000000 --- a/iree/vm/module_printer.cc +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/module_printer.h" - -#include "iree/vm/bytecode_printer.h" -#include "iree/vm/source_map.h" - -namespace iree { -namespace vm { - -Status PrintModuleToStream(OpcodeTable opcode_table, const Module& module, - PrintModuleFlagBitfield flags, - std::ostream* stream) { - // TODO(benvanik): custom FunctionTable Function iterator. - for (int i = 0; i < module.function_table().def().functions()->size(); ++i) { - ASSIGN_OR_RETURN(const auto& function, - module.function_table().LookupFunction(i)); - if (function.def().bytecode()) { - auto source_map_resolver = - AllBitsSet(flags, PrintModuleFlag::kIncludeSourceMapping) - ? SourceMapResolver::FromFunction(module.def(), i) - : SourceMapResolver(); - BytecodePrinter printer(opcode_table, module.function_table(), - module.executable_table(), source_map_resolver); - *stream << "Function " << i << ": " << function << "\n"; - RETURN_IF_ERROR( - printer.PrintToStream(*function.def().bytecode(), stream)); - *stream << "\n"; - } else { - *stream << "Function " << i << ": " << function.name() << " (import)\n"; - } - } - return OkStatus(); -} - -Status PrintModuleToStream(OpcodeTable opcode_table, const Module& module, - std::ostream* stream) { - return PrintModuleToStream(opcode_table, module, PrintModuleFlag::kNone, - stream); -} - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/sequencer_context.cc b/iree/vm/sequencer_context.cc deleted file mode 100644 index a8bda41..0000000 --- a/iree/vm/sequencer_context.cc +++ /dev/null
@@ -1,154 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/sequencer_context.h" - -#include "iree/base/flatbuffer_util.h" -#include "iree/base/status.h" -#include "iree/hal/buffer_view.h" -#include "iree/vm/fiber_state.h" -#include "iree/vm/sequencer_dispatch.h" - -namespace iree { -namespace vm { - -namespace { - -using ::iree::hal::BufferView; - -Status ValidateElementSize(int element_bit_width, - const ElementTypeDef& expected_element_type) { - switch (expected_element_type.type_union_type()) { - case ElementTypeDefUnion::FloatTypeDef: { - auto expected_bit_width = - expected_element_type.type_union_as_FloatTypeDef()->width(); - if (element_bit_width != expected_bit_width) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Has element bit width " << element_bit_width - << " but expected " << expected_bit_width; - } - return OkStatus(); - } - case ElementTypeDefUnion::IntegerTypeDef: { - auto expected_bit_width = - expected_element_type.type_union_as_IntegerTypeDef()->width(); - if (element_bit_width != expected_bit_width) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Has element bit width " << element_bit_width - << " but expected " << expected_bit_width; - } - return OkStatus(); - } - case ElementTypeDefUnion::UnknownTypeDef: - case ElementTypeDefUnion::NONE: { - } - } - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Defined type has unsupported element type " - << EnumNameElementTypeDefUnion( - expected_element_type.type_union_type()); -} - -Status ValidateArgType(const BufferView& arg, - const MemRefTypeDef& expected_type) { - RETURN_IF_ERROR( - ValidateElementSize(arg.element_size * 8, *expected_type.element_type())); - - auto expected_shape = expected_type.shape(); - if (arg.shape.size() != expected_shape->size()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Argument should have rank " << expected_shape->size() - << " but has rank " << arg.shape.size(); - } - for (int i = 0; i < expected_shape->size(); ++i) { - auto dim_size = arg.shape[i]; - auto expected_dim_size = expected_shape->Get(i); - if (dim_size != expected_dim_size) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Argument dimension " << i << " should have size " - << expected_dim_size << " but has size " << dim_size; - } - } - return OkStatus(); -} - -} // namespace - -SequencerContext::SequencerContext(std::shared_ptr<Instance> instance) - : instance_(std::move(instance)) {} - -SequencerContext::~SequencerContext() = default; - -Status SequencerContext::RegisterNativeFunction( - std::string name, NativeFunction native_function) { - // TODO(benvanik): provide to debugger. - return Context::RegisterNativeFunction(std::move(name), - std::move(native_function)); -} - -Status SequencerContext::RegisterModule(std::unique_ptr<Module> module) { - RETURN_IF_ERROR(Context::RegisterModule(std::move(module))); - return OkStatus(); -} - -Status SequencerContext::Invoke(FiberState* fiber_state, Function function, - absl::Span<BufferView> args, - absl::Span<BufferView> results) const { - // Verify arg/result counts. - if (args.size() != function.input_count()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Function " << function.name() << " requires " - << function.input_count() << " inputs but " << args.size() - << " provided"; - } - if (results.size() != function.result_count()) { - return InvalidArgumentErrorBuilder(IREE_LOC) - << "Function " << function.name() << " requires " - << function.result_count() << " outputs but " << results.size() - << " provided"; - } - - // Push stack frame for the function we are calling. - auto* stack = fiber_state->mutable_stack(); - ASSIGN_OR_RETURN(auto* callee_stack_frame, stack->PushFrame(function)); - - // Marshal input arguments. - for (int i = 0; i < args.size(); ++i) { - auto arg = args[i]; - auto expected_arg_type = function.type_def().inputs()->Get(i); - RETURN_IF_ERROR( - ValidateArgType(arg, *expected_arg_type->type_union_as_MemRefTypeDef())) - << "Function " << function.name() << " argument " << i; - *callee_stack_frame->mutable_local(i) = std::move(arg); - } - - // TODO(benvanik): change to: - // get command queue (any command queue) - // make command buffer - // record dispatch - // submit - // wait on fence - ASSIGN_OR_RETURN(auto placement, - instance_->device_manager()->ResolvePlacement({})); - RETURN_IF_ERROR( - DispatchSequence(placement, stack, callee_stack_frame, results)); - - // Pop the callee frame to balance out the stack. - RETURN_IF_ERROR(stack->PopFrame()); - - return OkStatus(); -} - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/sequencer_context.h b/iree/vm/sequencer_context.h deleted file mode 100644 index dbc4bc9..0000000 --- a/iree/vm/sequencer_context.h +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_SEQUENCER_CONTEXT_H_ -#define IREE_VM_SEQUENCER_CONTEXT_H_ - -#include <memory> -#include <vector> - -#include "absl/strings/string_view.h" -#include "absl/types/span.h" -#include "iree/base/status.h" -#include "iree/hal/buffer_view.h" -#include "iree/vm/context.h" -#include "iree/vm/fiber_state.h" -#include "iree/vm/function.h" -#include "iree/vm/instance.h" -#include "iree/vm/module.h" - -namespace iree { -namespace vm { - -class SequencerContext final : public Context { - public: - explicit SequencerContext(std::shared_ptr<Instance> instance); - ~SequencerContext() override; - - Status RegisterNativeFunction(std::string name, - NativeFunction native_function) override; - - Status RegisterModule(std::unique_ptr<Module> module) override; - - // TODO(benvanik): helpers to make passing args easier - Status Invoke(FiberState* fiber_state, vm::Function function, - absl::Span<hal::BufferView> args, - absl::Span<hal::BufferView> results) const; - - private: - std::shared_ptr<Instance> instance_; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_CONTEXT_H_
diff --git a/iree/vm/sequencer_dispatch.cc b/iree/vm/sequencer_dispatch.cc index 90065b9..ce5a408 100644 --- a/iree/vm/sequencer_dispatch.cc +++ b/iree/vm/sequencer_dispatch.cc
@@ -32,10 +32,10 @@ #include "iree/hal/device.h" #include "iree/hal/heap_buffer.h" #include "iree/schemas/bytecode/sequencer_bytecode_v0.h" +#include "iree/vm/bytecode_module.h" #include "iree/vm/bytecode_reader.h" #include "iree/vm/bytecode_tables_sequencer.h" #include "iree/vm/bytecode_util.h" -#include "iree/vm/function.h" #include "iree/vm/opcode_info.h" namespace iree { @@ -65,15 +65,17 @@ } // TODO(benvanik): insert fence callbacks and wait on fence. -Status CallNativeFunction(Stack* stack, const ImportFunction& function) { - auto* stack_frame = stack->current_frame(); - +Status CallExternalFunction(rt::Stack* stack, const rt::Function& function) { // Marshal inputs and outputs. - auto args = stack_frame->mutable_locals().subspan(0, function.input_count()); - auto results = stack_frame->mutable_locals().subspan(args.size()); - - const auto& fn = function.native_function(); - return fn(stack, args, results); + const auto* stack_frame = stack->current_frame(); + auto buffer_views = absl::MakeSpan(stack_frame->registers().buffer_views); + absl::InlinedVector<hal::BufferView, 8> arguments( + buffer_views.begin(), + buffer_views.begin() + function.signature().argument_count()); + absl::InlinedVector<hal::BufferView, 8> results( + buffer_views.begin() + arguments.size(), buffer_views.end()); + return function.module()->Execute(stack, function, std::move(arguments), + &results); } // Pretty prints an array, e.g. [1, 2, 3, 4] @@ -109,8 +111,8 @@ } // namespace -Status DispatchSequence(const hal::DevicePlacement& placement, Stack* stack, - StackFrame* entry_stack_frame, +Status DispatchSequence(const hal::DevicePlacement& placement, rt::Stack* stack, + rt::StackFrame* entry_stack_frame, absl::Span<BufferView> entry_results) { // Dispatch table mapping 1:1 with bytecode ops. // Each entry is a label within this function that can be used for computed @@ -164,7 +166,15 @@ DISPATCH_CORE_OPCODE(kCall, { auto* old_stack_frame = stack->current_frame(); ASSIGN_OR_RETURN(const auto& target_function, reader.ReadFunction()); + // TODO(benvanik): rework register storage interface. + ASSIGN_OR_RETURN( + const auto* function_def, + static_cast<const BytecodeModule*>(target_function.module()) + ->GetFunctionDef(target_function.linkage(), + target_function.ordinal())); ASSIGN_OR_RETURN(auto* new_stack_frame, stack->PushFrame(target_function)); + new_stack_frame->mutable_registers()->buffer_views.resize( + function_def->bytecode()->local_count()); RETURN_IF_ERROR( reader.CopyInputsAndSwitchStackFrame(old_stack_frame, new_stack_frame)); DVLOG(1) << "Call; stack now: " << stack->DebugString(); @@ -172,30 +182,20 @@ DISPATCH_CORE_OPCODE(kCallImport, { auto* old_stack_frame = stack->current_frame(); - ASSIGN_OR_RETURN(const auto* target_function, reader.ReadImportFunction()); - switch (target_function->link_type()) { - case ImportFunction::LinkType::kModule: { - ASSIGN_OR_RETURN(auto* new_stack_frame, - stack->PushFrame(target_function->linked_function())); - RETURN_IF_ERROR(reader.CopyInputsAndSwitchStackFrame(old_stack_frame, - new_stack_frame)); - DVLOG(1) << "Call module import; stack now: " << stack->DebugString(); - break; - } - case ImportFunction::LinkType::kNativeFunction: { - ASSIGN_OR_RETURN(auto* new_stack_frame, - stack->PushFrame(*target_function)); - RETURN_IF_ERROR(reader.CopyInputsAndSwitchStackFrame(old_stack_frame, - new_stack_frame)); - DVLOG(1) << "Call native import; stack now: " << stack->DebugString(); - RETURN_IF_ERROR(CallNativeFunction(stack, *target_function)); - RETURN_IF_ERROR(reader.CopyResultsAndSwitchStackFrame(old_stack_frame, - new_stack_frame)); - RETURN_IF_ERROR(stack->PopFrame()); - DVLOG(1) << "Return from native; stack now: " << stack->DebugString(); - break; - } - } + ASSIGN_OR_RETURN(const auto& target_function, reader.ReadImportFunction()); + ASSIGN_OR_RETURN(auto* new_stack_frame, stack->PushFrame(target_function)); + // TODO(benvanik): rework register storage interface. + const auto& signature = target_function.signature(); + new_stack_frame->mutable_registers()->buffer_views.resize( + signature.argument_count() + signature.result_count()); + RETURN_IF_ERROR( + reader.CopyInputsAndSwitchStackFrame(old_stack_frame, new_stack_frame)); + DVLOG(1) << "Call native import; stack now: " << stack->DebugString(); + RETURN_IF_ERROR(CallExternalFunction(stack, target_function)); + RETURN_IF_ERROR(reader.CopyResultsAndSwitchStackFrame(old_stack_frame, + new_stack_frame)); + RETURN_IF_ERROR(stack->PopFrame()); + DVLOG(1) << "Return from native; stack now: " << stack->DebugString(); }); DISPATCH_CORE_OPCODE(kCallIndirect, { @@ -209,8 +209,9 @@ // Returning from entry function. Marshal results from the return stmt. ASSIGN_OR_RETURN(int32_t src_count, reader.ReadCount()); for (int i = 0; i < src_count; ++i) { - ASSIGN_OR_RETURN(auto* src_local, - reader.ReadLocal(old_stack_frame->mutable_locals())); + ASSIGN_OR_RETURN( + auto* src_local, + reader.ReadLocal(old_stack_frame->mutable_registers())); entry_results[i] = std::move(*src_local); } DVLOG(1) << "Returning to entry"; @@ -259,11 +260,10 @@ // TODO(benvanik): the real sequencer :) ASSIGN_OR_RETURN(auto dispatch_ordinal, reader.ReadInt32()); ASSIGN_OR_RETURN(auto export_ordinal, reader.ReadUint16_t()); - auto& executable_table = - stack->current_frame()->module().executable_table(); ASSIGN_OR_RETURN( - auto* multi_arch_executable_def, - executable_table.LookupMultiArchExecutable(dispatch_ordinal)); + const auto* multi_arch_executable_def, + static_cast<const BytecodeModule&>(stack->current_frame()->module()) + .LookupMultiArchExecutable(dispatch_ordinal)); if (export_ordinal >= multi_arch_executable_def->entry_point_count()) { return InvalidArgumentErrorBuilder(IREE_LOC) << "Invalid executable export ordinal " << export_ordinal;
diff --git a/iree/vm/sequencer_dispatch.h b/iree/vm/sequencer_dispatch.h index fc664db..0251c17 100644 --- a/iree/vm/sequencer_dispatch.h +++ b/iree/vm/sequencer_dispatch.h
@@ -18,15 +18,15 @@ #include "iree/base/status.h" #include "iree/hal/buffer_view.h" #include "iree/hal/device_placement.h" -#include "iree/vm/stack.h" -#include "iree/vm/stack_frame.h" +#include "iree/rt/stack.h" +#include "iree/rt/stack_frame.h" namespace iree { namespace vm { // TODO(benvanik): API that supports yielding. -Status DispatchSequence(const hal::DevicePlacement& placement, Stack* stack, - StackFrame* entry_stack_frame, +Status DispatchSequence(const hal::DevicePlacement& placement, rt::Stack* stack, + rt::StackFrame* entry_stack_frame, absl::Span<hal::BufferView> entry_results); } // namespace vm
diff --git a/iree/vm/sequencer_module.cc b/iree/vm/sequencer_module.cc new file mode 100644 index 0000000..1906ef6 --- /dev/null +++ b/iree/vm/sequencer_module.cc
@@ -0,0 +1,112 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "iree/vm/sequencer_module.h" + +#include "absl/memory/memory.h" +#include "iree/base/status.h" +#include "iree/base/tracing.h" +#include "iree/hal/buffer_view.h" +#include "iree/rt/context.h" +#include "iree/rt/instance.h" +#include "iree/vm/bytecode_tables_sequencer.h" +#include "iree/vm/sequencer_dispatch.h" + +namespace iree { +namespace vm { + +namespace { + +using ::iree::hal::BufferView; +using ::iree::rt::Function; +using ::iree::rt::Module; + +} // namespace + +// static +StatusOr<ref_ptr<rt::Module>> SequencerModule::FromDef( + const ModuleDef& module_def) { + ASSIGN_OR_RETURN(auto module_file, ModuleFile::Create(&module_def, []() {})); + return FromFile(std::move(module_file)); +} + +// static +StatusOr<ref_ptr<rt::Module>> SequencerModule::FromFile( + std::unique_ptr<ModuleFile> module_file) { + if (module_file->root() == nullptr) { + return InvalidArgumentErrorBuilder(IREE_LOC) << "No root ModuleDef present"; + } + const auto& module_def = *module_file->root(); + + // Validates the structure of the module (but not bytecode). + // This ensures we don't have flatbuffer vectors will null entries, etc. + RETURN_IF_ERROR(BytecodeModule::ValidateStructure(module_def)); + + auto module = assign_ref(new SequencerModule(std::move(module_file))); + + // TODO(benvanik): validate internals here? or make explicit? + + return {std::move(module)}; +} + +SequencerModule::SequencerModule(std::unique_ptr<ModuleFile> module_file) + : BytecodeModule(std::move(module_file), sequencer_opcode_table()) {} + +SequencerModule::~SequencerModule() = default; + +Status SequencerModule::Execute( + rt::Stack* stack, const Function function, + absl::InlinedVector<hal::BufferView, 8> arguments, + absl::InlinedVector<hal::BufferView, 8>* results) const { + IREE_TRACE_SCOPE0("SequencerModule::Execute"); + + // Push stack frame for the function we are calling. + ASSIGN_OR_RETURN(auto* callee_stack_frame, stack->PushFrame(function)); + + // TODO(benvanik): rework register storage interface. + ASSIGN_OR_RETURN(const auto* function_def, + GetFunctionDef(function.linkage(), function.ordinal())); + auto* registers = callee_stack_frame->mutable_registers(); + registers->buffer_views.resize(function_def->bytecode()->local_count()); + + // Marshal input arguments. + for (int i = 0; i < arguments.size(); ++i) { + auto arg = arguments[i]; + auto expected_arg_type = function_def->type()->inputs()->Get(i); + RETURN_IF_ERROR(BytecodeModule::ValidateArgType( + arg, *expected_arg_type->type_union_as_MemRefTypeDef())) + << "Function " << function.name() << " argument " << i; + registers->buffer_views[i] = std::move(arg); + } + + // TODO(benvanik): change to: + // get command queue (any command queue) + // make command buffer + // record dispatch + // submit + // wait on fence + ASSIGN_OR_RETURN( + auto placement, + stack->context()->instance()->device_manager()->ResolvePlacement({})); + RETURN_IF_ERROR( + DispatchSequence(placement, stack, callee_stack_frame, results)); + + // Pop the callee frame to balance out the stack. + RETURN_IF_ERROR(stack->PopFrame()); + + return OkStatus(); +} + +} // namespace vm +} // namespace iree
diff --git a/iree/vm/sequencer_module.h b/iree/vm/sequencer_module.h new file mode 100644 index 0000000..b9bb176 --- /dev/null +++ b/iree/vm/sequencer_module.h
@@ -0,0 +1,46 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef IREE_VM_SEQUENCER_MODULE_H_ +#define IREE_VM_SEQUENCER_MODULE_H_ + +#include <memory> + +#include "iree/vm/bytecode_module.h" + +namespace iree { +namespace vm { + +// A module using the sequencer bytecode ops. +class SequencerModule final : public BytecodeModule { + public: + static StatusOr<ref_ptr<rt::Module>> FromDef(const ModuleDef& module_def); + static StatusOr<ref_ptr<rt::Module>> FromFile( + std::unique_ptr<ModuleFile> module_file); + + ~SequencerModule() override; + + Status Execute( + rt::Stack* stack, const rt::Function function, + absl::InlinedVector<hal::BufferView, 8> arguments, + absl::InlinedVector<hal::BufferView, 8>* results) const override; + + private: + explicit SequencerModule(std::unique_ptr<ModuleFile> module_file); +}; + +} // namespace vm +} // namespace iree + +#endif // IREE_VM_SEQUENCER_MODULE_H_
diff --git a/iree/vm/source_map.h b/iree/vm/source_map.h deleted file mode 100644 index 32cd41e..0000000 --- a/iree/vm/source_map.h +++ /dev/null
@@ -1,104 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_SOURCE_MAP_H_ -#define IREE_VM_SOURCE_MAP_H_ - -#include "absl/strings/string_view.h" -#include "absl/types/optional.h" -#include "iree/base/status.h" -#include "iree/schemas/module_def_generated.h" -#include "iree/schemas/source_map_def_generated.h" - -namespace iree { -namespace vm { - -class SourceLocation { - public: - static bool Equal(const SourceLocation& a, const SourceLocation& b); - - SourceLocation() = default; - SourceLocation(const SourceMapDef& source_map_def, - const FunctionSourceMapDef& function_source_map, - int location_ordinal) - : source_map_def_(&source_map_def), - function_source_map_(&function_source_map), - location_ordinal_(location_ordinal) {} - - std::string DebugStringShort() const; - - bool empty() const { return source_map_def_ == nullptr; } - - private: - const SourceMapDef* source_map_def_ = nullptr; - const FunctionSourceMapDef* function_source_map_ = nullptr; - int location_ordinal_ = 0; -}; - -inline bool operator==(const SourceLocation& a, const SourceLocation& b) { - return SourceLocation::Equal(a, b); -} - -inline bool operator!=(const SourceLocation& a, const SourceLocation& b) { - return !(a == b); -} - -class SourceMap { - public: - static SourceMap FromModule(const ModuleDef& module_def); - - SourceMap() = default; - explicit SourceMap(const SourceMapDef& source_map_def) - : source_map_def_(&source_map_def) {} - - bool empty() const { return source_map_def_ == nullptr; } - const SourceMapDef* def() const { return source_map_def_; } - - StatusOr<absl::string_view> GetUniqueString(int string_index) const; - - StatusOr<const FunctionSourceMapDef*> GetFunctionSourceMap( - int function_ordinal) const; - - private: - const SourceMapDef* source_map_def_ = nullptr; -}; -inline std::ostream& operator<<(std::ostream& stream, - const SourceLocation& location) { - stream << location.DebugStringShort(); - return stream; -} - -class SourceMapResolver { - public: - static SourceMapResolver FromFunction(const ModuleDef& module_def, - int function_ordinal); - - SourceMapResolver() = default; - - absl::optional<SourceLocation> ResolveBytecodeOffset(int offset) const; - - private: - SourceMapResolver(SourceMap source_map, - const FunctionSourceMapDef& function_source_map) - : source_map_(std::move(source_map)), - function_source_map_(&function_source_map) {} - - SourceMap source_map_; - const FunctionSourceMapDef* function_source_map_ = nullptr; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_SOURCE_MAP_H_
diff --git a/iree/vm/source_map.cc b/iree/vm/source_map_resolver.cc similarity index 72% rename from iree/vm/source_map.cc rename to iree/vm/source_map_resolver.cc index 4b8467f..96025e4 100644 --- a/iree/vm/source_map.cc +++ b/iree/vm/source_map_resolver.cc
@@ -12,23 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "iree/vm/source_map.h" - -#include <sstream> +#include "iree/vm/source_map_resolver.h" #include "iree/base/flatbuffer_util.h" #include "iree/base/status.h" +#include "iree/schemas/source_map_def_generated.h" namespace iree { namespace vm { namespace { -Status PrintLocation(const SourceMap& source_map, +Status PrintLocation(const SourceMapResolver& source_map, const FunctionSourceMapDef& function_source_map, const LocationDef& location, std::ostream* stream); -Status PrintFileLocation(const SourceMap& source_map, +Status PrintFileLocation(const SourceMapResolver& source_map, const FunctionSourceMapDef& function_source_map, const FileLocationDef& location, std::ostream* stream) { @@ -38,7 +37,7 @@ return OkStatus(); } -Status PrintNameLocation(const SourceMap& source_map, +Status PrintNameLocation(const SourceMapResolver& source_map, const FunctionSourceMapDef& function_source_map, const NameLocationDef& location, std::ostream* stream) { @@ -47,7 +46,7 @@ return OkStatus(); } -Status PrintCallSiteLocation(const SourceMap& source_map, +Status PrintCallSiteLocation(const SourceMapResolver& source_map, const FunctionSourceMapDef& function_source_map, const CallSiteLocationDef& location, std::ostream* stream) { @@ -55,7 +54,7 @@ return OkStatus(); } -Status PrintFusedLocation(const SourceMap& source_map, +Status PrintFusedLocation(const SourceMapResolver& source_map, const FunctionSourceMapDef& function_source_map, const FusedLocationDef& location, std::ostream* stream) { @@ -74,7 +73,7 @@ return OkStatus(); } -Status PrintLocation(const SourceMap& source_map, +Status PrintLocation(const SourceMapResolver& source_map, const FunctionSourceMapDef& function_source_map, const LocationDef& location, std::ostream* stream) { switch (location.location_union_type()) { @@ -104,36 +103,15 @@ } // namespace // static -bool SourceLocation::Equal(const SourceLocation& a, const SourceLocation& b) { - return a.source_map_def_ == b.source_map_def_ && - a.function_source_map_ == b.function_source_map_ && - a.location_ordinal_ == b.location_ordinal_; -} - -std::string SourceLocation::DebugStringShort() const { - if (empty()) { - return "<unknown>"; - } - std::ostringstream stream; - const auto& location = - *function_source_map_->location_table()->Get(location_ordinal_); - auto status = PrintLocation(SourceMap(*source_map_def_), - *function_source_map_, location, &stream); - if (!status.ok()) { - stream << status; - } - return stream.str(); -} - -// static -SourceMap SourceMap::FromModule(const ModuleDef& module_def) { +SourceMapResolver SourceMapResolver::FromModule(const ModuleDef& module_def) { if (module_def.source_map()) { - return SourceMap{*module_def.source_map()}; + return SourceMapResolver{*module_def.source_map()}; } return {}; } -StatusOr<absl::string_view> SourceMap::GetUniqueString(int string_index) const { +StatusOr<absl::string_view> SourceMapResolver::GetUniqueString( + int string_index) const { if (empty()) { return NotFoundErrorBuilder(IREE_LOC) << "No source map present"; } @@ -145,7 +123,7 @@ << "String index " << string_index << " not present in string table"; } -StatusOr<const FunctionSourceMapDef*> SourceMap::GetFunctionSourceMap( +StatusOr<const FunctionSourceMapDef*> SourceMapResolver::GetFunctionSourceMap( int function_ordinal) const { if (empty()) { return NotFoundErrorBuilder(IREE_LOC) << "No source map present"; @@ -163,28 +141,16 @@ << " source map not present in function table"; } -// static -SourceMapResolver SourceMapResolver::FromFunction(const ModuleDef& module_def, - int function_ordinal) { - auto source_map = SourceMap::FromModule(module_def); - if (source_map.empty()) { - return {}; - } - auto function_source_map_or = - source_map.GetFunctionSourceMap(function_ordinal); +absl::optional<rt::SourceLocation> SourceMapResolver::ResolveFunctionOffset( + const rt::Function& function, rt::SourceOffset offset) { + if (empty()) return absl::nullopt; + auto function_source_map_or = GetFunctionSourceMap(function.ordinal()); if (!function_source_map_or.ok()) { - return {}; + return absl::nullopt; } - return SourceMapResolver(source_map, *function_source_map_or.ValueOrDie()); -} - -absl::optional<SourceLocation> SourceMapResolver::ResolveBytecodeOffset( - int offset) const { - if (!function_source_map_) { - return {}; - } - - const auto* bytecode_map = function_source_map_->bytecode_map(); + const auto* function_source_map = function_source_map_or.ValueOrDie(); + const auto* bytecode_map = function_source_map->bytecode_map(); + if (!bytecode_map) return absl::nullopt; // TODO(benvanik): allow fuzzy offset matching/table sparsity. int location_ordinal = -1; @@ -195,11 +161,33 @@ } } if (location_ordinal == -1) { - return {}; + return absl::nullopt; } - return SourceLocation(*source_map_.def(), *function_source_map_, - location_ordinal); + return rt::SourceLocation(this, + { + reinterpret_cast<uint64_t>(function_source_map), + static_cast<uint64_t>(location_ordinal), + }); +} + +void SourceMapResolver::PrintSourceLocation( + rt::SourceResolverArgs resolver_args, std::ostream* stream) const { + if (empty()) { + *stream << "<unknown>"; + return; + } + + auto* function_source_map = + reinterpret_cast<FunctionSourceMapDef*>(resolver_args[0]); + int location_ordinal = static_cast<int>(resolver_args[1]); + + const auto& location = + *function_source_map->location_table()->Get(location_ordinal); + auto status = PrintLocation(*this, *function_source_map, location, stream); + if (!status.ok()) { + *stream << status; + } } } // namespace vm
diff --git a/iree/vm/source_map_resolver.h b/iree/vm/source_map_resolver.h new file mode 100644 index 0000000..5c8f7c2 --- /dev/null +++ b/iree/vm/source_map_resolver.h
@@ -0,0 +1,57 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef IREE_VM_SOURCE_MAP_RESOLVER_H_ +#define IREE_VM_SOURCE_MAP_RESOLVER_H_ + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "iree/base/status.h" +#include "iree/rt/source_resolver.h" +#include "iree/schemas/module_def_generated.h" +#include "iree/schemas/source_map_def_generated.h" + +namespace iree { +namespace vm { + +class SourceMapResolver final : public rt::SourceResolver { + public: + static SourceMapResolver FromModule(const ModuleDef& module_def); + + SourceMapResolver() = default; + explicit SourceMapResolver(const SourceMapDef& source_map_def) + : source_map_def_(&source_map_def) {} + + bool empty() const { return source_map_def_ == nullptr; } + const SourceMapDef* def() const { return source_map_def_; } + + StatusOr<absl::string_view> GetUniqueString(int string_index) const; + + StatusOr<const FunctionSourceMapDef*> GetFunctionSourceMap( + int function_ordinal) const; + + absl::optional<rt::SourceLocation> ResolveFunctionOffset( + const rt::Function& function, rt::SourceOffset offset) override; + + void PrintSourceLocation(rt::SourceResolverArgs resolver_args, + std::ostream* stream) const override; + + private: + const SourceMapDef* source_map_def_ = nullptr; +}; + +} // namespace vm +} // namespace iree + +#endif // IREE_VM_SOURCE_MAP_RESOLVER_H_
diff --git a/iree/vm/stack.cc b/iree/vm/stack.cc deleted file mode 100644 index 5912173..0000000 --- a/iree/vm/stack.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/stack.h" - -#include <iterator> - -#include "absl/strings/str_join.h" -#include "iree/base/status.h" - -namespace iree { -namespace vm { - -constexpr int Stack::kMaxStackDepth; - -Stack::Stack() = default; - -Stack::~Stack() = default; - -StatusOr<StackFrame*> Stack::PushFrame(Function function) { - if (stack_depth_ + 1 > kMaxStackDepth) { - return InternalErrorBuilder(IREE_LOC) - << "Max stack depth of " << kMaxStackDepth << " exceeded"; - } - stack_[stack_depth_++] = StackFrame(function); - - // TODO(benvanik): WTF scope enter. - - return current_frame(); -} - -StatusOr<StackFrame*> Stack::PushFrame(const ImportFunction& function) { - if (stack_depth_ + 1 > kMaxStackDepth) { - return InternalErrorBuilder(IREE_LOC) - << "Max stack depth of " << kMaxStackDepth << " exceeded"; - } - stack_[stack_depth_++] = StackFrame(function); - - // TODO(benvanik): WTF scope enter. - - return current_frame(); -} - -Status Stack::PopFrame() { - if (stack_depth_ == 0) { - return InternalErrorBuilder(IREE_LOC) << "Unbalanced stack pop"; - } - - // TODO(benvanik): WTF scope leave. - - --stack_depth_; - return OkStatus(); -} - -namespace { -struct StackFrameFormatter { - void operator()(std::string* out, const StackFrame& stack_frame) const { - out->append(absl::StrCat(stack_frame.module().name(), ":", - stack_frame.function().name(), "@", - stack_frame.offset())); - } -}; -} // namespace - -std::string Stack::DebugString() const { - return absl::StrJoin(std::begin(stack_), std::begin(stack_) + stack_depth_, - "\n", StackFrameFormatter()); -} - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/stack.h b/iree/vm/stack.h deleted file mode 100644 index 7228742..0000000 --- a/iree/vm/stack.h +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_STACK_H_ -#define IREE_VM_STACK_H_ - -#include <functional> - -#include "absl/types/span.h" -#include "iree/base/status.h" -#include "iree/vm/stack_frame.h" - -namespace iree { -namespace vm { - -// VM call stack. -// -// Stacks are thread-compatible. -class Stack { - public: - static constexpr int kMaxStackDepth = 32; - - Stack(); - Stack(const Stack&) = delete; - Stack& operator=(const Stack&) = delete; - ~Stack(); - - absl::Span<const StackFrame> frames() const { - return absl::MakeConstSpan(stack_, stack_depth_); - } - absl::Span<StackFrame> mutable_frames() { - return absl::MakeSpan(stack_, stack_depth_); - } - - StackFrame* current_frame() { - return stack_depth_ > 0 ? &stack_[stack_depth_ - 1] : nullptr; - } - const StackFrame* current_frame() const { - return stack_depth_ > 0 ? &stack_[stack_depth_ - 1] : nullptr; - } - StackFrame* caller_frame() { - return stack_depth_ > 1 ? &stack_[stack_depth_ - 2] : nullptr; - } - const StackFrame* caller_frame() const { - return stack_depth_ > 1 ? &stack_[stack_depth_ - 2] : nullptr; - } - - StatusOr<StackFrame*> PushFrame(Function function); - StatusOr<StackFrame*> PushFrame(const ImportFunction& function); - Status PopFrame(); - - std::string DebugString() const; - - private: - StackFrame stack_[kMaxStackDepth]; - int stack_depth_ = 0; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_STACK_H_
diff --git a/iree/vm/stack_frame.cc b/iree/vm/stack_frame.cc deleted file mode 100644 index 3974470..0000000 --- a/iree/vm/stack_frame.cc +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "iree/vm/stack_frame.h" - -#include "iree/base/status.h" - -namespace iree { -namespace vm { - -StackFrame::StackFrame(Function function) : function_(function) { - const auto* bytecode_def = function_.def().bytecode(); - if (bytecode_def) { - offset_limit_ = bytecode_def->contents()->Length(); - locals_.resize(bytecode_def->local_count()); - } else { - locals_.resize(function_.input_count() + function_.result_count()); - } -} - -StackFrame::StackFrame(const ImportFunction& function) - : function_(function), import_function_(&function) {} - -Status StackFrame::set_offset(int offset) { - if (offset < 0 || offset > offset_limit_) { - return OutOfRangeErrorBuilder(IREE_LOC) - << "Offset " << offset - << " is outside of the bytecode body limit of " << offset_limit_; - } - offset_ = offset; - return OkStatus(); -} - -} // namespace vm -} // namespace iree
diff --git a/iree/vm/stack_frame.h b/iree/vm/stack_frame.h deleted file mode 100644 index a39c789..0000000 --- a/iree/vm/stack_frame.h +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IREE_VM_STACK_FRAME_H_ -#define IREE_VM_STACK_FRAME_H_ - -#include <vector> - -#include "absl/types/span.h" -#include "iree/hal/buffer_view.h" -#include "iree/vm/function.h" -#include "iree/vm/module.h" - -namespace iree { -namespace vm { - -// A single frame on the call stack containing current execution state and -// local values. -// -// StackFrames are designed to be serialized so that suspend and resume is -// possible. This means that most state is stored either entirely within the -// frame or references to non-pointer values (such as other function indices). -// BufferViews require special care to allow rendezvous and liveness tracking. -class StackFrame { - public: - StackFrame() = default; - explicit StackFrame(Function function); - explicit StackFrame(const ImportFunction& function); - StackFrame(const StackFrame&) = delete; - StackFrame& operator=(const StackFrame&) = delete; - StackFrame(StackFrame&&) = default; - StackFrame& operator=(StackFrame&&) = default; - - const Module& module() const { return function_.module(); } - const Function& function() const { return function_; } - - inline int offset() const { return offset_; } - Status set_offset(int offset); - inline int* mutable_offset() { return &offset_; } - - inline const hal::BufferView& local(int ordinal) { return locals_[ordinal]; } - inline hal::BufferView* mutable_local(int ordinal) { - return &locals_[ordinal]; - } - - inline absl::Span<const hal::BufferView> locals() const { - return absl::MakeConstSpan(locals_); - } - inline absl::Span<hal::BufferView> mutable_locals() { - return absl::MakeSpan(locals_); - } - - private: - Function function_; - const ImportFunction* import_function_; - int offset_ = 0; - int offset_limit_ = 0; - - // TODO(benvanik): replace with a placed allocation. - std::vector<hal::BufferView> locals_; -}; - -} // namespace vm -} // namespace iree - -#endif // IREE_VM_STACK_FRAME_H_