|  | // Copyright 2019 The IREE Authors | 
|  | // | 
|  | // Licensed under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  |  | 
|  | // Loads a VM module from the provided file and outputs the requested | 
|  | // information. | 
|  | // | 
|  | // $ iree-dump-module [--output=...] module.vmfb | 
|  | //   --output=metadata: module metadata and size breakdown. | 
|  | //   --output=flatbuffer-binary: module flatbuffer in binary format. | 
|  | //   --output=flatbuffer-json: module flatbuffer in JSON format. | 
|  |  | 
|  | #include <ctype.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include "iree/base/api.h" | 
|  | #include "iree/base/internal/file_io.h" | 
|  | #include "iree/base/internal/flags.h" | 
|  | #include "iree/vm/bytecode/archive.h" | 
|  | #include "iree/vm/bytecode/module.h" | 
|  |  | 
|  | // NOTE: include order matters: | 
|  | #include "iree/base/internal/flatcc/parsing.h" | 
|  | #include "iree/schemas/bytecode_module_def_json_printer.h" | 
|  | #include "iree/schemas/bytecode_module_def_reader.h" | 
|  | #include "iree/schemas/bytecode_module_def_verifier.h" | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // IO utilities | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #if defined(IREE_PLATFORM_WINDOWS) | 
|  | #include <fcntl.h> | 
|  | #include <io.h> | 
|  | #define IREE_SET_BINARY_MODE(handle) _setmode(_fileno(handle), O_BINARY) | 
|  | #else | 
|  | #define IREE_SET_BINARY_MODE(handle) ((void)0) | 
|  | #endif  // IREE_PLATFORM_WINDOWS | 
|  |  | 
|  | static void iree_tooling_print_indent(int indent) { | 
|  | fprintf(stdout, "%*s", indent, ""); | 
|  | } | 
|  |  | 
|  | static void iree_tooling_printf_section_header(const char* format, ...) { | 
|  | fprintf(stdout, | 
|  | "//" | 
|  | "===-----------------------------------------------------------------" | 
|  | "---------------------------------------------===//\n"); | 
|  | fprintf(stdout, "// "); | 
|  | va_list args; | 
|  | va_start(args, format); | 
|  | vfprintf(stdout, format, args); | 
|  | va_end(args); | 
|  | fprintf(stdout, "\n"); | 
|  | fprintf(stdout, | 
|  | "//" | 
|  | "===-----------------------------------------------------------------" | 
|  | "---------------------------------------------===//\n"); | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // --output=metadata | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | static size_t iree_tooling_print_feature_bits(iree_vm_FeatureBits_enum_t bits) { | 
|  | size_t length = 0; | 
|  | if (bits & iree_vm_FeatureBits_EXT_F32) { | 
|  | if (length) fprintf(stdout, " | "); | 
|  | fprintf(stdout, "EXT_F32"); | 
|  | length += strlen("EXT_F32"); | 
|  | bits = bits & ~iree_vm_FeatureBits_EXT_F32; | 
|  | } | 
|  | if (bits & iree_vm_FeatureBits_EXT_F64) { | 
|  | if (length) fprintf(stdout, " | "); | 
|  | fprintf(stdout, "EXT_F64"); | 
|  | length += strlen("EXT_F64"); | 
|  | bits = bits & ~iree_vm_FeatureBits_EXT_F64; | 
|  | } | 
|  | if (bits) { | 
|  | if (length) fprintf(stdout, " | "); | 
|  | fprintf(stdout, "%08X", bits); | 
|  | length += 8; | 
|  | } | 
|  | return length; | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_attr_def(iree_vm_AttrDef_table_t attr_def) { | 
|  | fprintf(stdout, "%s: %s", iree_vm_AttrDef_key(attr_def), | 
|  | iree_vm_AttrDef_value(attr_def)); | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_attr_defs(iree_vm_AttrDef_vec_t attr_defs, | 
|  | int indent) { | 
|  | for (size_t i = 0; i < iree_vm_AttrDef_vec_len(attr_defs); ++i) { | 
|  | iree_tooling_print_indent(indent); | 
|  | iree_tooling_print_attr_def(iree_vm_AttrDef_vec_at(attr_defs, i)); | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_type_def(iree_vm_TypeDef_table_t type_def) { | 
|  | fprintf(stdout, "%s", iree_vm_TypeDef_full_name(type_def)); | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_type_defs(iree_vm_TypeDef_vec_t type_defs, | 
|  | int indent) { | 
|  | for (size_t i = 0; i < iree_vm_TypeDef_vec_len(type_defs); ++i) { | 
|  | iree_tooling_print_indent(indent); | 
|  | fprintf(stdout, "[%3zu] ", i); | 
|  | iree_tooling_print_type_def(iree_vm_TypeDef_vec_at(type_defs, i)); | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_module_dependency_def( | 
|  | iree_vm_ModuleDependencyDef_table_t dependency_def) { | 
|  | fprintf(stdout, "%s, version >= %d, ", | 
|  | iree_vm_ModuleDependencyDef_name(dependency_def), | 
|  | iree_vm_ModuleDependencyDef_minimum_version(dependency_def)); | 
|  | if (iree_vm_ModuleDependencyDef_flags(dependency_def) & | 
|  | iree_vm_ModuleDependencyFlagBits_OPTIONAL) { | 
|  | fprintf(stdout, "optional"); | 
|  | } else { | 
|  | fprintf(stdout, "required"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_module_dependency_defs( | 
|  | iree_vm_ModuleDependencyDef_vec_t dependency_defs, int indent) { | 
|  | for (size_t i = 0; i < iree_vm_ModuleDependencyDef_vec_len(dependency_defs); | 
|  | ++i) { | 
|  | iree_tooling_print_indent(indent); | 
|  | iree_tooling_print_module_dependency_def( | 
|  | iree_vm_ModuleDependencyDef_vec_at(dependency_defs, i)); | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static iree_status_t iree_tooling_print_cconv_fragment( | 
|  | iree_string_view_t cconv_fragment) { | 
|  | for (iree_host_size_t i = 0; i < cconv_fragment.size; ++i) { | 
|  | if (i > 0) fprintf(stdout, ", "); | 
|  | switch (cconv_fragment.data[i]) { | 
|  | case IREE_VM_CCONV_TYPE_VOID: | 
|  | break; | 
|  | case IREE_VM_CCONV_TYPE_I32: | 
|  | fprintf(stdout, "i32"); | 
|  | break; | 
|  | case IREE_VM_CCONV_TYPE_F32: | 
|  | fprintf(stdout, "f32"); | 
|  | break; | 
|  | case IREE_VM_CCONV_TYPE_I64: | 
|  | fprintf(stdout, "i64"); | 
|  | break; | 
|  | case IREE_VM_CCONV_TYPE_F64: | 
|  | fprintf(stdout, "f64"); | 
|  | break; | 
|  | case IREE_VM_CCONV_TYPE_REF: | 
|  | fprintf(stdout, "!vm.ref<?>"); | 
|  | break; | 
|  | case IREE_VM_CCONV_TYPE_SPAN_START: { | 
|  | iree_host_size_t end_pos = iree_string_view_find_char( | 
|  | cconv_fragment, IREE_VM_CCONV_TYPE_SPAN_END, i + 1); | 
|  | if (end_pos == IREE_STRING_VIEW_NPOS) { | 
|  | return iree_make_status(IREE_STATUS_FAILED_PRECONDITION, | 
|  | "unterminated cconv span"); | 
|  | } | 
|  | fprintf(stdout, "tuple<"); | 
|  | IREE_RETURN_IF_ERROR(iree_tooling_print_cconv_fragment( | 
|  | iree_string_view_substr(cconv_fragment, i + 1, end_pos - i - 1))); | 
|  | fprintf(stdout, ">..."); | 
|  | i = end_pos;  // +1 from the for-loop | 
|  | } break; | 
|  | default: | 
|  | return iree_make_status(IREE_STATUS_UNIMPLEMENTED, | 
|  | "unsupported cconv type '%c'", | 
|  | cconv_fragment.data[i]); | 
|  | } | 
|  | } | 
|  | return iree_ok_status(); | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_function_cconv(flatbuffers_string_t cconv) { | 
|  | iree_vm_function_signature_t signature = { | 
|  | .calling_convention = iree_make_cstring_view(cconv), | 
|  | }; | 
|  | iree_string_view_t arguments, results; | 
|  | IREE_CHECK_OK(iree_vm_function_call_get_cconv_fragments( | 
|  | &signature, &arguments, &results)); | 
|  | fprintf(stdout, "("); | 
|  | IREE_CHECK_OK(iree_tooling_print_cconv_fragment(arguments)); | 
|  | fprintf(stdout, ") -> ("); | 
|  | IREE_CHECK_OK(iree_tooling_print_cconv_fragment(results)); | 
|  | fprintf(stdout, ")"); | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_imported_function_def( | 
|  | iree_vm_ImportFunctionDef_table_t function_def, int indent) { | 
|  | if (iree_vm_ImportFunctionDef_flags(function_def) & | 
|  | iree_vm_ImportFlagBits_OPTIONAL) { | 
|  | fprintf(stdout, "?"); | 
|  | } | 
|  | fprintf(stdout, "%s", iree_vm_ImportFunctionDef_full_name(function_def)); | 
|  | iree_vm_FunctionSignatureDef_table_t signature_def = | 
|  | iree_vm_ImportFunctionDef_signature(function_def); | 
|  | if (iree_vm_FunctionSignatureDef_calling_convention_is_present( | 
|  | signature_def)) { | 
|  | iree_tooling_print_function_cconv( | 
|  | iree_vm_FunctionSignatureDef_calling_convention(signature_def)); | 
|  | } | 
|  | fprintf(stdout, "\n"); | 
|  | if (iree_vm_FunctionSignatureDef_attrs_is_present(signature_def)) { | 
|  | iree_tooling_print_attr_defs( | 
|  | iree_vm_FunctionSignatureDef_attrs(signature_def), indent); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_imported_function_defs( | 
|  | iree_vm_ImportFunctionDef_vec_t function_defs, int indent) { | 
|  | for (size_t i = 0; i < iree_vm_ImportFunctionDef_vec_len(function_defs); | 
|  | ++i) { | 
|  | iree_tooling_print_indent(indent); | 
|  | fprintf(stdout, "[%3zu] ", i); | 
|  | iree_tooling_print_imported_function_def( | 
|  | iree_vm_ImportFunctionDef_vec_at(function_defs, i), indent + 6); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_exported_function_def( | 
|  | iree_vm_ExportFunctionDef_table_t function_def, | 
|  | iree_vm_FunctionSignatureDef_vec_t function_signature_defs) { | 
|  | fprintf(stdout, "%s", iree_vm_ExportFunctionDef_local_name(function_def)); | 
|  | iree_vm_FunctionSignatureDef_table_t signature_def = | 
|  | iree_vm_FunctionSignatureDef_vec_at( | 
|  | function_signature_defs, | 
|  | iree_vm_ExportFunctionDef_internal_ordinal(function_def)); | 
|  | if (iree_vm_FunctionSignatureDef_calling_convention_is_present( | 
|  | signature_def)) { | 
|  | iree_tooling_print_function_cconv( | 
|  | iree_vm_FunctionSignatureDef_calling_convention(signature_def)); | 
|  | } | 
|  | fprintf(stdout, "\n"); | 
|  | if (iree_vm_FunctionSignatureDef_attrs_is_present(signature_def)) { | 
|  | iree_tooling_print_attr_defs( | 
|  | iree_vm_FunctionSignatureDef_attrs(signature_def), 8); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_exported_function_defs( | 
|  | iree_vm_ExportFunctionDef_vec_t function_defs, | 
|  | iree_vm_FunctionSignatureDef_vec_t function_signature_defs, int indent) { | 
|  | for (size_t i = 0; i < iree_vm_ExportFunctionDef_vec_len(function_defs); | 
|  | ++i) { | 
|  | iree_tooling_print_indent(indent); | 
|  | fprintf(stdout, "[%3zu] ", i); | 
|  | iree_tooling_print_exported_function_def( | 
|  | iree_vm_ExportFunctionDef_vec_at(function_defs, i), | 
|  | function_signature_defs); | 
|  | } | 
|  | } | 
|  |  | 
|  | static size_t iree_tooling_calculate_external_rodata_size( | 
|  | iree_vm_RodataSegmentDef_vec_t segment_defs) { | 
|  | size_t total_size = 0; | 
|  | for (size_t i = 0; i < iree_vm_RodataSegmentDef_vec_len(segment_defs); ++i) { | 
|  | iree_vm_RodataSegmentDef_table_t segment_def = | 
|  | iree_vm_RodataSegmentDef_vec_at(segment_defs, i); | 
|  | if (!iree_vm_RodataSegmentDef_embedded_data_is_present(segment_def)) { | 
|  | total_size += iree_vm_RodataSegmentDef_external_data_length(segment_def); | 
|  | } | 
|  | } | 
|  | return total_size; | 
|  | } | 
|  |  | 
|  | // Returns true if |data| is likely a string. The string may not have a NUL | 
|  | // terminator and the length is returned in |out_length|. Note that string | 
|  | // tables may have NUL terminators and this will only return the first string. | 
|  | static bool iree_tooling_data_is_string(flatbuffers_uint8_vec_t data, | 
|  | size_t* out_length) { | 
|  | *out_length = 0; | 
|  | size_t length = flatbuffers_uint8_vec_scan(data, 0); | 
|  | if (length == flatbuffers_not_found) { | 
|  | length = flatbuffers_uint8_vec_len(data); | 
|  | } | 
|  | for (size_t i = 0; i < length; ++i) { | 
|  | char c = flatbuffers_uint8_vec_at(data, i); | 
|  | if (!isprint(c)) return false; | 
|  | } | 
|  | *out_length = length; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_rodata_segment_defs( | 
|  | iree_vm_RodataSegmentDef_vec_t segment_defs, int indent) { | 
|  | for (size_t i = 0; i < iree_vm_RodataSegmentDef_vec_len(segment_defs); ++i) { | 
|  | iree_tooling_print_indent(indent); | 
|  | iree_vm_RodataSegmentDef_table_t segment_def = | 
|  | iree_vm_RodataSegmentDef_vec_at(segment_defs, i); | 
|  | fprintf(stdout, ".rodata[%3zu] ", i); | 
|  | switch (iree_vm_RodataSegmentDef_compression_type_type(segment_def)) { | 
|  | case iree_vm_CompressionTypeDef_UncompressedDataDef: | 
|  | fprintf(stdout, "uncompressed "); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | if (iree_vm_RodataSegmentDef_embedded_data_is_present(segment_def)) { | 
|  | flatbuffers_uint8_vec_t data = | 
|  | iree_vm_RodataSegmentDef_embedded_data(segment_def); | 
|  | fprintf(stdout, "embedded %8zu bytes", flatbuffers_uint8_vec_len(data)); | 
|  | size_t string_length = 0; | 
|  | if (iree_tooling_data_is_string(data, &string_length)) { | 
|  | static const size_t MAX_LENGTH = 32; | 
|  | fprintf(stdout, " `%.*s`", (int)iree_min(MAX_LENGTH, string_length), | 
|  | (const char*)data); | 
|  | if (string_length >= MAX_LENGTH) fprintf(stdout, "..."); | 
|  | } | 
|  | } else { | 
|  | fprintf(stdout, | 
|  | "external %8" PRIu64 " bytes (offset %" PRIu64 " / %" PRIX64 | 
|  | "h to %" PRIX64 "h)", | 
|  | iree_vm_RodataSegmentDef_external_data_length(segment_def), | 
|  | iree_vm_RodataSegmentDef_external_data_offset(segment_def), | 
|  | iree_vm_RodataSegmentDef_external_data_offset(segment_def), | 
|  | iree_vm_RodataSegmentDef_external_data_offset(segment_def) + | 
|  | iree_vm_RodataSegmentDef_external_data_length(segment_def)); | 
|  | } | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_rwdata_segment_defs( | 
|  | iree_vm_RwdataSegmentDef_vec_t segment_defs, int indent) { | 
|  | for (size_t i = 0; i < iree_vm_RwdataSegmentDef_vec_len(segment_defs); ++i) { | 
|  | iree_tooling_print_indent(indent); | 
|  | iree_vm_RwdataSegmentDef_table_t segment_def = | 
|  | iree_vm_RwdataSegmentDef_vec_at(segment_defs, i); | 
|  | fprintf(stdout, ".rwdata[%3zu] %d bytes\n", i, | 
|  | iree_vm_RwdataSegmentDef_byte_size(segment_def)); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void iree_tooling_print_function_descriptors( | 
|  | iree_vm_FunctionDescriptor_vec_t descriptors, | 
|  | iree_vm_ExportFunctionDef_vec_t export_defs) { | 
|  | fprintf(stdout, | 
|  | "  # | Offset   |   Length | Blocks | i32 # | ref # | Requirements | " | 
|  | "Aliases\n"); | 
|  | fprintf(stdout, | 
|  | "----+----------+----------+--------+-------+-------+--------------+-" | 
|  | "----------------------------------------------------\n"); | 
|  | for (size_t i = 0; i < iree_vm_FunctionDescriptor_vec_len(descriptors); ++i) { | 
|  | iree_vm_FunctionDescriptor_struct_t descriptor = | 
|  | iree_vm_FunctionDescriptor_vec_at(descriptors, i); | 
|  | fprintf(stdout, "%3zu | %08X | %8d | %6d | %5d | %5d | ", i, | 
|  | iree_vm_FunctionDescriptor_bytecode_offset(descriptor), | 
|  | iree_vm_FunctionDescriptor_bytecode_length(descriptor), | 
|  | iree_vm_FunctionDescriptor_block_count(descriptor), | 
|  | iree_vm_FunctionDescriptor_i32_register_count(descriptor), | 
|  | iree_vm_FunctionDescriptor_ref_register_count(descriptor)); | 
|  | size_t pos = iree_tooling_print_feature_bits( | 
|  | iree_vm_FunctionDescriptor_requirements(descriptor)); | 
|  | if (pos < 12) iree_tooling_print_indent(12 - pos); | 
|  | fprintf(stdout, " | "); | 
|  | bool any_aliases = false; | 
|  | for (size_t j = 0; j < iree_vm_ExportFunctionDef_vec_len(export_defs); | 
|  | ++j) { | 
|  | iree_vm_ExportFunctionDef_table_t export_def = | 
|  | iree_vm_ExportFunctionDef_vec_at(export_defs, j); | 
|  | if (iree_vm_ExportFunctionDef_internal_ordinal(export_def) == i) { | 
|  | if (any_aliases) fprintf(stdout, ", "); | 
|  | fprintf(stdout, "%s", iree_vm_ExportFunctionDef_local_name(export_def)); | 
|  | any_aliases = true; | 
|  | } | 
|  | } | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static iree_status_t iree_tooling_dump_module_metadata( | 
|  | iree_const_byte_span_t flatbuffer_contents, | 
|  | iree_const_byte_span_t rodata_contents) { | 
|  | iree_vm_BytecodeModuleDef_table_t module_def = | 
|  | iree_vm_BytecodeModuleDef_as_root(flatbuffer_contents.data); | 
|  |  | 
|  | iree_tooling_printf_section_header( | 
|  | "@%s : version %d", iree_vm_BytecodeModuleDef_name(module_def), | 
|  | iree_vm_BytecodeModuleDef_version(module_def)); | 
|  | fprintf(stdout, "\n"); | 
|  |  | 
|  | if (iree_vm_BytecodeModuleDef_requirements_is_present(module_def)) { | 
|  | fprintf(stdout, "Requirements: "); | 
|  | iree_tooling_print_feature_bits( | 
|  | iree_vm_BytecodeModuleDef_requirements(module_def)); | 
|  | fprintf(stdout, "\n\n"); | 
|  | } | 
|  |  | 
|  | if (iree_vm_BytecodeModuleDef_attrs_is_present(module_def)) { | 
|  | fprintf(stdout, "Attributes:\n"); | 
|  | iree_tooling_print_attr_defs(iree_vm_BytecodeModuleDef_attrs(module_def), | 
|  | 2); | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  |  | 
|  | if (iree_vm_BytecodeModuleDef_types_is_present(module_def)) { | 
|  | fprintf(stdout, "Required Types:\n"); | 
|  | iree_tooling_print_type_defs(iree_vm_BytecodeModuleDef_types(module_def), | 
|  | 2); | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  |  | 
|  | if (iree_vm_BytecodeModuleDef_dependencies_is_present(module_def)) { | 
|  | fprintf(stdout, "Module Dependencies:\n"); | 
|  | iree_tooling_print_module_dependency_defs( | 
|  | iree_vm_BytecodeModuleDef_dependencies(module_def), 2); | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  |  | 
|  | if (iree_vm_BytecodeModuleDef_imported_functions_is_present(module_def)) { | 
|  | fprintf(stdout, "Imported Functions:\n"); | 
|  | iree_tooling_print_imported_function_defs( | 
|  | iree_vm_BytecodeModuleDef_imported_functions(module_def), 2); | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  |  | 
|  | if (iree_vm_BytecodeModuleDef_exported_functions_is_present(module_def)) { | 
|  | fprintf(stdout, "Exported Functions:\n"); | 
|  | iree_tooling_print_exported_function_defs( | 
|  | iree_vm_BytecodeModuleDef_exported_functions(module_def), | 
|  | iree_vm_BytecodeModuleDef_function_signatures(module_def), 2); | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  |  | 
|  | iree_tooling_printf_section_header("Sections"); | 
|  | fprintf(stdout, "\n"); | 
|  |  | 
|  | if (iree_vm_BytecodeModuleDef_module_state_is_present(module_def)) { | 
|  | iree_vm_ModuleStateDef_table_t module_state_def = | 
|  | iree_vm_BytecodeModuleDef_module_state(module_def); | 
|  | fprintf(stdout, "Module State:\n"); | 
|  | fprintf(stdout, "  %d bytes, %d refs, ~%zu bytes total\n", | 
|  | iree_vm_ModuleStateDef_global_bytes_capacity(module_state_def), | 
|  | iree_vm_ModuleStateDef_global_ref_count(module_state_def), | 
|  | iree_vm_ModuleStateDef_global_bytes_capacity(module_state_def) + | 
|  | sizeof(iree_vm_ref_t) * | 
|  | iree_vm_ModuleStateDef_global_ref_count(module_state_def)); | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  |  | 
|  | fprintf(stdout, "FlatBuffer: %" PRIhsz " bytes\n", | 
|  | flatbuffer_contents.data_length); | 
|  | if (iree_vm_BytecodeModuleDef_bytecode_data_is_present(module_def)) { | 
|  | flatbuffers_uint8_vec_t bytecode_data = | 
|  | iree_vm_BytecodeModuleDef_bytecode_data(module_def); | 
|  | fprintf(stdout, "  Bytecode: %zu bytes\n", | 
|  | flatbuffers_uint8_vec_len(bytecode_data)); | 
|  | } | 
|  | if (iree_vm_BytecodeModuleDef_rodata_segments_is_present(module_def)) { | 
|  | iree_tooling_print_rodata_segment_defs( | 
|  | iree_vm_BytecodeModuleDef_rodata_segments(module_def), 2); | 
|  | } | 
|  | if (iree_vm_BytecodeModuleDef_rwdata_segments_is_present(module_def)) { | 
|  | iree_tooling_print_rwdata_segment_defs( | 
|  | iree_vm_BytecodeModuleDef_rwdata_segments(module_def), 2); | 
|  | } | 
|  | fprintf(stdout, "\n"); | 
|  | size_t external_size = iree_tooling_calculate_external_rodata_size( | 
|  | iree_vm_BytecodeModuleDef_rodata_segments(module_def)); | 
|  | if (external_size > 0) { | 
|  | fprintf(stdout, "External .rodata: ~%zu bytes\n\n", external_size); | 
|  | } | 
|  |  | 
|  | iree_tooling_printf_section_header( | 
|  | "Bytecode : version %d", iree_vm_BytecodeModuleDef_version(module_def)); | 
|  | fprintf(stdout, "\n"); | 
|  |  | 
|  | if (iree_vm_BytecodeModuleDef_function_descriptors_is_present(module_def)) { | 
|  | iree_tooling_print_function_descriptors( | 
|  | iree_vm_BytecodeModuleDef_function_descriptors(module_def), | 
|  | iree_vm_BytecodeModuleDef_exported_functions(module_def)); | 
|  | } | 
|  |  | 
|  | fprintf(stdout, "\n"); | 
|  |  | 
|  | if (iree_vm_BytecodeModuleDef_debug_database_is_present(module_def)) { | 
|  | iree_tooling_printf_section_header("Debug Information"); | 
|  | iree_vm_DebugDatabaseDef_table_t database_def = | 
|  | iree_vm_BytecodeModuleDef_debug_database(module_def); | 
|  | fprintf(stdout, | 
|  | "// NOTE: debug databases are large and should be stripped in " | 
|  | "deployed artifacts.\n"); | 
|  | fprintf(stdout, "\n"); | 
|  |  | 
|  | // TODO(benvanik): some kind of informative output; for now just counts to | 
|  | // indicate how much is present (would be nice to calculate full sizing). | 
|  | fprintf(stdout, "Locations: %zu\n", | 
|  | flatbuffers_generic_vec_len( | 
|  | iree_vm_DebugDatabaseDef_location_table(database_def))); | 
|  |  | 
|  | fprintf(stdout, "\n"); | 
|  | } | 
|  |  | 
|  | return iree_ok_status(); | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // --output=flatbuffer-binary | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | static iree_status_t iree_tooling_dump_module_flatbuffer_binary( | 
|  | iree_const_byte_span_t flatbuffer_contents) { | 
|  | IREE_SET_BINARY_MODE(stdout);  // ensure binary output mode | 
|  | fwrite(flatbuffer_contents.data, 1, flatbuffer_contents.data_length, stdout); | 
|  | return iree_ok_status(); | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // --output=flatbuffer-json | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | IREE_FLAG(bool, flatbuffer_pretty, false, "Pretty print flatbuffer JSON."); | 
|  |  | 
|  | static iree_status_t iree_tooling_dump_module_flatbuffer_json( | 
|  | iree_const_byte_span_t flatbuffer_contents) { | 
|  | flatcc_json_printer_t printer; | 
|  | flatcc_json_printer_init(&printer, NULL); | 
|  | if (FLAG_flatbuffer_pretty) { | 
|  | flatcc_json_printer_set_flags(&printer, flatcc_json_printer_f_pretty); | 
|  | } | 
|  | flatcc_json_printer_set_skip_default(&printer, true); | 
|  | bytecode_module_def_print_json(&printer, | 
|  | (const char*)flatbuffer_contents.data, | 
|  | flatbuffer_contents.data_length); | 
|  | flatcc_json_printer_flush(&printer); | 
|  | flatcc_json_printer_clear(&printer); | 
|  | return iree_ok_status(); | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // main | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | IREE_FLAG(string, output, "metadata", | 
|  | "Output mode:\n" | 
|  | "  'metadata': module metadata and size breakdown.\n" | 
|  | "  'flatbuffer-binary': module flatbuffer in binary format.\n" | 
|  | "  'flatbuffer-json': module flatbuffer in JSON format.\n"); | 
|  |  | 
|  | int main(int argc, char** argv) { | 
|  | IREE_TRACE_APP_ENTER(); | 
|  |  | 
|  | iree_allocator_t host_allocator = iree_allocator_system(); | 
|  | int exit_code = EXIT_SUCCESS; | 
|  |  | 
|  | // Parse command line flags. | 
|  | iree_flags_set_usage("iree-dump-module", | 
|  | "Dumps IREE VM module details to stdout.\n" | 
|  | "$ iree-dump-module [--output=...] module.vmfb\n"); | 
|  | iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_DEFAULT, &argc, &argv); | 
|  |  | 
|  | if (argc < 2) { | 
|  | fprintf(stderr, "Syntax: iree-dump-module [--output=...] module.vmfb\n"); | 
|  | IREE_TRACE_APP_EXIT(EXIT_FAILURE); | 
|  | return EXIT_FAILURE; | 
|  | } | 
|  |  | 
|  | iree_file_contents_t* file_contents = NULL; | 
|  | iree_status_t status = iree_file_read_contents( | 
|  | argv[1], IREE_FILE_READ_FLAG_DEFAULT, host_allocator, &file_contents); | 
|  |  | 
|  | iree_const_byte_span_t flatbuffer_contents = iree_const_byte_span_empty(); | 
|  | iree_const_byte_span_t rodata_contents = iree_const_byte_span_empty(); | 
|  | if (iree_status_is_ok(status)) { | 
|  | iree_host_size_t rodata_offset = 0; | 
|  | status = iree_vm_bytecode_archive_parse_header( | 
|  | file_contents->const_buffer, &flatbuffer_contents, &rodata_offset); | 
|  | rodata_contents = iree_make_const_byte_span( | 
|  | file_contents->const_buffer.data + rodata_offset, | 
|  | file_contents->const_buffer.data_length - rodata_offset); | 
|  | } | 
|  | if (iree_status_is_ok(status)) { | 
|  | int verify_ret = iree_vm_BytecodeModuleDef_verify_as_root( | 
|  | flatbuffer_contents.data, flatbuffer_contents.data_length); | 
|  | if (verify_ret != flatcc_verify_ok) { | 
|  | status = iree_make_status(IREE_STATUS_INVALID_ARGUMENT, | 
|  | "FlatBuffer verification failed: %s", | 
|  | flatcc_verify_error_string(verify_ret)); | 
|  | } | 
|  | } | 
|  | if (iree_status_is_ok(status)) { | 
|  | if (strcmp(FLAG_output, "metadata") == 0) { | 
|  | status = iree_tooling_dump_module_metadata(flatbuffer_contents, | 
|  | rodata_contents); | 
|  | } else if (strcmp(FLAG_output, "flatbuffer-binary") == 0) { | 
|  | status = iree_tooling_dump_module_flatbuffer_binary(flatbuffer_contents); | 
|  | } else if (strcmp(FLAG_output, "flatbuffer-json") == 0) { | 
|  | status = iree_tooling_dump_module_flatbuffer_json(flatbuffer_contents); | 
|  | } else { | 
|  | status = iree_make_status(IREE_STATUS_INVALID_ARGUMENT, | 
|  | "unrecognized --output= flag value '%s'", | 
|  | FLAG_output); | 
|  | } | 
|  | } | 
|  |  | 
|  | iree_file_contents_free(file_contents); | 
|  |  | 
|  | fflush(stdout); | 
|  | if (!iree_status_is_ok(status)) { | 
|  | iree_status_fprint(stderr, status); | 
|  | iree_status_free(status); | 
|  | exit_code = EXIT_FAILURE; | 
|  | } | 
|  | fflush(stderr); | 
|  | IREE_TRACE_APP_EXIT(exit_code); | 
|  | return exit_code; | 
|  | } |