From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- third_party/wasm2c/src/c-writer.cc | 5295 ++++++++++++++++++++++++++++++++++++ 1 file changed, 5295 insertions(+) create mode 100644 third_party/wasm2c/src/c-writer.cc (limited to 'third_party/wasm2c/src/c-writer.cc') diff --git a/third_party/wasm2c/src/c-writer.cc b/third_party/wasm2c/src/c-writer.cc new file mode 100644 index 0000000000..2405c170ae --- /dev/null +++ b/third_party/wasm2c/src/c-writer.cc @@ -0,0 +1,5295 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * 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 + * + * http://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 "wabt/c-writer.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wabt/cast.h" +#include "wabt/common.h" +#include "wabt/ir.h" +#include "wabt/literal.h" +#include "wabt/sha256.h" +#include "wabt/stream.h" +#include "wabt/string-util.h" + +#define INDENT_SIZE 2 + +#define UNIMPLEMENTED(x) printf("unimplemented: %s\n", (x)), abort() + +// code to be inserted into the generated output +extern const char* s_header_top; +extern const char* s_header_bottom; +extern const char* s_source_includes; +extern const char* s_source_declarations; +extern const char* s_simd_source_declarations; + +namespace wabt { + +namespace { + +struct Label { + Label(LabelType label_type, + const std::string& name, + const TypeVector& sig, + size_t type_stack_size, + size_t try_catch_stack_size, + bool used = false) + : label_type(label_type), + name(name), + sig(sig), + type_stack_size(type_stack_size), + try_catch_stack_size(try_catch_stack_size), + used(used) {} + + bool HasValue() const { return !sig.empty(); } + + LabelType label_type; + const std::string& name; + const TypeVector& sig; + size_t type_stack_size; + size_t try_catch_stack_size; + bool used = false; +}; + +struct LocalName { + explicit LocalName(const std::string& name) : name(name) {} + const std::string& name; +}; + +struct ParamName : LocalName { + using LocalName::LocalName; + ParamName(const Var& var) : LocalName(var.name()) {} +}; + +struct LabelName : LocalName { + using LocalName::LocalName; +}; + +struct GlobalName { + GlobalName(ModuleFieldType type, const std::string& name) + : type(type), name(name) {} + ModuleFieldType type; + const std::string& name; +}; + +struct ExternalPtr : GlobalName { + using GlobalName::GlobalName; +}; + +struct ExternalRef : GlobalName { + using GlobalName::GlobalName; +}; + +struct ExternalInstancePtr : GlobalName { + using GlobalName::GlobalName; +}; + +struct ExternalInstanceRef : GlobalName { + using GlobalName::GlobalName; +}; + +struct GotoLabel { + explicit GotoLabel(const Var& var) : var(var) {} + const Var& var; +}; + +struct LabelDecl { + explicit LabelDecl(const std::string& name) : name(name) {} + std::string name; +}; + +struct GlobalInstanceVar { + explicit GlobalInstanceVar(const Var& var) : var(var) {} + const Var& var; +}; + +struct StackVar { + explicit StackVar(Index index, Type type = Type::Any) + : index(index), type(type) {} + Index index; + Type type; +}; + +struct TypeEnum { + explicit TypeEnum(Type type) : type(type) {} + Type type; +}; + +struct SignedType { + explicit SignedType(Type type) : type(type) {} + Type type; +}; + +struct ResultType { + explicit ResultType(const TypeVector& types) : types(types) {} + const TypeVector& types; +}; + +struct TryCatchLabel { + TryCatchLabel(const std::string& name, size_t try_catch_stack_size) + : name(name), try_catch_stack_size(try_catch_stack_size), used(false) {} + std::string name; + size_t try_catch_stack_size; + bool used; +}; + +struct FuncTypeExpr { + const FuncType* func_type; + FuncTypeExpr(const FuncType* f) : func_type(f) {} +}; + +struct Newline {}; +struct OpenBrace {}; +struct CloseBrace {}; + +int GetShiftMask(Type type) { + // clang-format off + switch (type) { + case Type::I32: return 31; + case Type::I64: return 63; + default: WABT_UNREACHABLE; return 0; + } + // clang-format on +} + +/* + * This function is the default behavior for name_to_output_file_index_. For + * single .c output, this function returns a vector filled with 0. For multiple + * .c outputs, this function sorts all non-imported functions in the module by + * their names, and then divides all non-imported functions into equal-sized + * buckets (# of non-imported functions / # of .c outputs) based on the sorting. + */ +static std::vector default_name_to_output_file_index( + std::vector::const_iterator func_begin, + std::vector::const_iterator func_end, + size_t num_imports, + size_t num_streams) { + std::vector result; + result.resize(std::distance(func_begin, func_end)); + if (num_streams == 1) { + return result; + } + + std::map sorted_functions; + size_t non_imported_funcs = result.size() - num_imports; + size_t bucket_size = non_imported_funcs / num_streams + + (non_imported_funcs % num_streams ? 1 : 0); + Index func_index = 0; + for (auto func = func_begin; func != func_end; func++) { + sorted_functions.insert({(*func)->name, func_index}); + ++func_index; + } + Index sorted_func_index = 0; + for (const auto& [func_name, index] : sorted_functions) { + bool is_import = index < num_imports; + if (!is_import) { + result.at(index) = sorted_func_index / bucket_size; + ++sorted_func_index; + } + } + return result; +} + +class CWriter { + public: + CWriter(std::vector&& c_streams, + Stream* h_stream, + Stream* h_impl_stream, + const char* header_name, + const char* header_impl_name, + const WriteCOptions& options) + : options_(options), + c_streams_(std::move(c_streams)), + h_stream_(h_stream), + h_impl_stream_(h_impl_stream), + header_name_(header_name), + header_impl_name_(header_impl_name) { + module_prefix_ = MangleModuleName(options_.module_name); + if (c_streams_.size() != 1 && options.name_to_output_file_index) { + name_to_output_file_index_ = options.name_to_output_file_index; + } else { + name_to_output_file_index_ = default_name_to_output_file_index; + } + } + + Result WriteModule(const Module&); + + private: + using SymbolSet = std::set; + using SymbolMap = std::map; + using StackTypePair = std::pair; + using StackVarSymbolMap = std::map; + + void WriteCHeader(); + void WriteCSource(); + + size_t MarkTypeStack() const; + void ResetTypeStack(size_t mark); + Type StackType(Index) const; + void PushType(Type); + void PushTypes(const TypeVector&); + void DropTypes(size_t count); + + void PushLabel(LabelType, + const std::string& name, + const FuncSignature&, + bool used = false); + const Label* FindLabel(const Var& var, bool mark_used = true); + bool IsTopLabelUsed() const; + void PopLabel(); + + static constexpr char MangleType(Type); + static constexpr char MangleField(ModuleFieldType); + static std::string MangleMultivalueTypes(const TypeVector&); + static std::string MangleTagTypes(const TypeVector&); + static std::string Mangle(std::string_view name, bool double_underscores); + static std::string MangleName(std::string_view); + static std::string MangleModuleName(std::string_view); + std::string ExportName(std::string_view module_name, + std::string_view export_name); + std::string ExportName(std::string_view export_name); + std::string ModuleInstanceTypeName() const; + static std::string ModuleInstanceTypeName(std::string_view module_name); + void ClaimName(SymbolSet& set, + SymbolMap& map, + char type_suffix, + std::string_view wasm_name, + const std::string& c_name); + std::string FindUniqueName(SymbolSet& set, std::string_view proposed_name); + std::string ClaimUniqueName(SymbolSet& set, + SymbolMap& map, + char type_suffix, + std::string_view wasm_name, + const std::string& proposed_c_name); + void DefineImportName(const Import* import, + std::string_view module_name, + std::string_view field_name); + void ReserveExportNames(); + void ReserveExportName(std::string_view); + std::string DefineImportedModuleInstanceName(std::string_view name); + std::string DefineInstanceMemberName(ModuleFieldType, std::string_view); + std::string DefineGlobalScopeName(ModuleFieldType, std::string_view); + std::string DefineLocalScopeName(std::string_view name, bool is_label); + std::string DefineParamName(std::string_view); + std::string DefineLabelName(std::string_view); + std::string DefineStackVarName(Index, Type, std::string_view); + + static void SerializeFuncType(const FuncType&, std::string&); + + std::string GetGlobalName(ModuleFieldType, const std::string&) const; + std::string GetLocalName(const std::string&, bool is_label) const; + + void Indent(int size = INDENT_SIZE); + void Dedent(int size = INDENT_SIZE); + void WriteIndent(); + void WriteData(const char* src, size_t size); + void Writef(const char* format, ...); + + template + void Write(T&& t, U&& u, Args&&... args) { + Write(std::forward(t)); + Write(std::forward(u)); + Write(std::forward(args)...); + } + + static const char* GetReferenceTypeName(const Type& type); + static const char* GetReferenceNullValue(const Type& type); + static const char* GetCTypeName(const Type& type); + + const char* InternalSymbolScope() const; + + enum class CWriterPhase { + Declarations, + Definitions, + }; + + void Write() {} + void Write(Newline); + void Write(OpenBrace); + void Write(CloseBrace); + void Write(uint64_t); + void Write(std::string_view); + void Write(const ParamName&); + void Write(const LabelName&); + void Write(const GlobalName&); + void Write(const ExternalPtr&); + void Write(const ExternalRef&); + void Write(const ExternalInstancePtr&); + void Write(const ExternalInstanceRef&); + void Write(Type); + void Write(SignedType); + void Write(TypeEnum); + void Write(const GotoLabel&); + void Write(const LabelDecl&); + void Write(const GlobalInstanceVar&); + void Write(const StackVar&); + void Write(const ResultType&); + void Write(const Const&); + void WriteInitExpr(const ExprList&); + void WriteInitExprTerminal(const Expr*); + std::string GenerateHeaderGuard() const; + void WriteSourceTop(); + void WriteMultiCTop(); + void WriteMultiCTopEmpty(); + void WriteMultivalueTypes(); + void WriteTagTypes(); + void WriteFuncTypeDecls(); + void WriteFuncTypes(); + void Write(const FuncTypeExpr&); + void WriteTagDecls(); + void WriteTags(); + void ComputeUniqueImports(); + void BeginInstance(); + void WriteImports(); + void WriteFuncDeclarations(); + void WriteFuncDeclaration(const FuncDeclaration&, const std::string&); + void WriteImportFuncDeclaration(const FuncDeclaration&, + const std::string& module_name, + const std::string&); + void WriteCallIndirectFuncDeclaration(const FuncDeclaration&, + const std::string&); + void ComputeSimdScope(); + void WriteHeaderIncludes(); + void WriteV128Decl(); + void WriteModuleInstance(); + void WriteGlobals(); + void WriteGlobal(const Global&, const std::string&); + void WriteGlobalPtr(const Global&, const std::string&); + void WriteMemories(); + void WriteMemory(const std::string&); + void WriteMemoryPtr(const std::string&); + void WriteTables(); + void WriteTable(const std::string&, const wabt::Type&); + void WriteTablePtr(const std::string&, const Table&); + void WriteTableType(const wabt::Type&); + void WriteDataInstances(); + void WriteElemInstances(); + void WriteGlobalInitializers(); + void WriteDataInitializerDecls(); + void WriteDataInitializers(); + void WriteElemInitializerDecls(); + void WriteElemInitializers(); + void WriteElemTableInit(bool, const ElemSegment*, const Table*); + void WriteExports(CWriterPhase); + void WriteInitDecl(); + void WriteFreeDecl(); + void WriteGetFuncTypeDecl(); + void WriteInit(); + void WriteFree(); + void WriteGetFuncType(); + void WriteInitInstanceImport(); + void WriteImportProperties(CWriterPhase); + void WriteFuncs(); + void Write(const Func&); + void WriteParamsAndLocals(); + void WriteParams(const std::vector& index_to_name); + void WriteParamSymbols(const std::vector& index_to_name); + void WriteParamTypes(const FuncDeclaration& decl); + void WriteLocals(const std::vector& index_to_name); + void WriteStackVarDeclarations(); + void Write(const ExprList&); + + enum class AssignOp { + Disallowed, + Allowed, + }; + + void WriteSimpleUnaryExpr(Opcode, const char* op); + void WriteInfixBinaryExpr(Opcode, + const char* op, + AssignOp = AssignOp::Allowed); + void WritePrefixBinaryExpr(Opcode, const char* op); + void WriteSignedBinaryExpr(Opcode, const char* op); + void Write(const BinaryExpr&); + void Write(const CompareExpr&); + void Write(const ConvertExpr&); + void Write(const LoadExpr&); + void Write(const StoreExpr&); + void Write(const UnaryExpr&); + void Write(const TernaryExpr&); + void Write(const SimdLaneOpExpr&); + void Write(const SimdLoadLaneExpr&); + void Write(const SimdStoreLaneExpr&); + void Write(const SimdShuffleOpExpr&); + void Write(const LoadSplatExpr&); + void Write(const LoadZeroExpr&); + void Write(const Block&); + + size_t BeginTry(const TryExpr& tryexpr); + void WriteTryCatch(const TryExpr& tryexpr); + void WriteTryDelegate(const TryExpr& tryexpr); + void Write(const Catch& c); + void WriteThrow(); + + void PushTryCatch(const std::string& name); + void PopTryCatch(); + + void PushFuncSection(std::string_view include_condition = ""); + + const WriteCOptions& options_; + const Module* module_ = nullptr; + const Func* func_ = nullptr; + Stream* stream_ = nullptr; + std::vector c_streams_; + Stream* h_stream_ = nullptr; + Stream* h_impl_stream_ = nullptr; + std::string header_name_; + std::string header_impl_name_; + Result result_ = Result::Ok; + int indent_ = 0; + bool should_write_indent_next_ = false; + int consecutive_newline_count_ = 0; + + SymbolMap global_sym_map_; + SymbolMap local_sym_map_; + SymbolMap import_module_sym_map_; + StackVarSymbolMap stack_var_sym_map_; + SymbolSet global_syms_; + SymbolSet local_syms_; + SymbolSet import_syms_; + TypeVector type_stack_; + std::vector