Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <cstring> | |
| 6 #include <functional> | |
| 7 #include <iostream> | |
| 8 #include <memory> | |
| 9 | |
| 5 #include "src/v8.h" | 10 #include "src/v8.h" |
| 6 | 11 |
| 12 #include "src/asmjs/asm-typer.h" | |
| 13 #include "src/asmjs/asm-types.h" | |
| 7 #include "src/asmjs/typing-asm.h" | 14 #include "src/asmjs/typing-asm.h" |
| 8 #include "src/ast/ast-expression-visitor.h" | 15 #include "src/ast/ast-expression-visitor.h" |
| 16 #include "src/ast/ast-value-factory.h" | |
| 9 #include "src/ast/ast.h" | 17 #include "src/ast/ast.h" |
| 10 #include "src/ast/scopes.h" | 18 #include "src/ast/scopes.h" |
| 19 #include "src/base/platform/platform.h" | |
| 11 #include "src/parsing/parser.h" | 20 #include "src/parsing/parser.h" |
| 12 #include "src/parsing/rewriter.h" | 21 #include "src/parsing/rewriter.h" |
| 13 #include "src/type-cache.h" | 22 #include "src/type-cache.h" |
| 14 #include "test/cctest/cctest.h" | 23 #include "test/cctest/cctest.h" |
| 15 #include "test/cctest/expression-type-collector-macros.h" | 24 #include "test/cctest/expression-type-collector-macros.h" |
| 16 #include "test/cctest/expression-type-collector.h" | 25 #include "test/cctest/expression-type-collector.h" |
| 17 | 26 |
| 18 // Macros for function types. | 27 // Macros for function types. |
| 19 #define FUNC_FOREIGN_TYPE Bounds(Type::Function(Type::Any(), zone)) | 28 #define FUNC_FOREIGN_TYPE Bounds(Type::Function(Type::Any(), zone)) |
| 20 #define FUNC_V_TYPE Bounds(Type::Function(Type::Undefined(), zone)) | 29 #define FUNC_V_TYPE Bounds(Type::Function(Type::Undefined(), zone)) |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 39 #define FUNC_N2N_TYPE \ | 48 #define FUNC_N2N_TYPE \ |
| 40 Bounds(Type::Function(Type::Number(), Type::Number(), zone)) | 49 Bounds(Type::Function(Type::Number(), Type::Number(), zone)) |
| 41 | 50 |
| 42 // Macros for array types. | 51 // Macros for array types. |
| 43 #define FLOAT64_ARRAY_TYPE Bounds(Type::Array(cache.kAsmDouble, zone)) | 52 #define FLOAT64_ARRAY_TYPE Bounds(Type::Array(cache.kAsmDouble, zone)) |
| 44 #define FUNC_I2I_ARRAY_TYPE \ | 53 #define FUNC_I2I_ARRAY_TYPE \ |
| 45 Bounds(Type::Array(Type::Function(cache.kAsmSigned, cache.kAsmInt, zone), \ | 54 Bounds(Type::Array(Type::Function(cache.kAsmSigned, cache.kAsmInt, zone), \ |
| 46 zone)) | 55 zone)) |
| 47 | 56 |
| 48 using namespace v8::internal; | 57 using namespace v8::internal; |
| 58 namespace iw = i::wasm; | |
| 49 | 59 |
| 50 namespace { | 60 namespace { |
| 51 | 61 |
| 52 std::string Validate(Zone* zone, const char* source, | 62 std::string Validate(Zone* zone, const char* source, |
| 53 ZoneVector<ExpressionTypeEntry>* types) { | 63 ZoneVector<ExpressionTypeEntry>* types) { |
| 54 i::Isolate* isolate = CcTest::i_isolate(); | 64 i::Isolate* isolate = CcTest::i_isolate(); |
| 55 i::Factory* factory = isolate->factory(); | 65 i::Factory* factory = isolate->factory(); |
| 56 | 66 |
| 57 i::Handle<i::String> source_code = | 67 i::Handle<i::String> source_code = |
| 58 factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked(); | 68 factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked(); |
| (...skipping 2488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2547 CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmDouble)) { | 2557 CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmDouble)) { |
| 2548 CHECK_VAR(x, Bounds(cache.kAsmDouble)); | 2558 CHECK_VAR(x, Bounds(cache.kAsmDouble)); |
| 2549 CHECK_EXPR(Literal, Bounds(cache.kAsmDouble)); | 2559 CHECK_EXPR(Literal, Bounds(cache.kAsmDouble)); |
| 2550 } | 2560 } |
| 2551 } | 2561 } |
| 2552 } | 2562 } |
| 2553 CHECK_SKIP(); | 2563 CHECK_SKIP(); |
| 2554 } | 2564 } |
| 2555 CHECK_FUNC_TYPES_END | 2565 CHECK_FUNC_TYPES_END |
| 2556 } | 2566 } |
| 2567 | |
| 2568 // ----------------------------------------------------------------------------- | |
| 2569 // asm.js typer v2. | |
| 2570 | |
| 2571 namespace v8 { | |
| 2572 namespace internal { | |
| 2573 namespace wasm { | |
| 2574 | |
| 2575 enum ValidationType { | |
| 2576 ValidateModule, | |
|
bradn
2016/07/11 17:55:34
Any reason not to put these in an anonymous namesp
John
2016/07/12 21:13:15
yes: AsmTyper has a friendship relationship with A
| |
| 2577 ValidateGlobals, | |
| 2578 ValidateFunctionTables, | |
| 2579 ValidateExport, | |
| 2580 ValidateFunction, | |
| 2581 ValidateStatement, | |
| 2582 ValidateExpression, | |
| 2583 }; | |
| 2584 | |
| 2585 class AsmTyperHarnessBuilder { | |
| 2586 public: | |
| 2587 AsmTyperHarnessBuilder(const char* source, ValidationType type) | |
| 2588 : source_(source), | |
| 2589 validation_type_(type), | |
| 2590 handles_(), | |
| 2591 zone_(handles_.main_zone()), | |
| 2592 isolate_(CcTest::i_isolate()), | |
| 2593 ast_value_factory_(zone_, isolate_->heap()->HashSeed()), | |
| 2594 factory_(isolate_->factory()), | |
| 2595 source_code_( | |
| 2596 factory_->NewStringFromUtf8(CStrVector(source)).ToHandleChecked()), | |
| 2597 script_(factory_->NewScript(source_code_)) { | |
| 2598 ParseInfo info(zone_, script_); | |
| 2599 info.set_global(); | |
| 2600 info.set_lazy(false); | |
| 2601 info.set_allow_lazy_parsing(false); | |
| 2602 info.set_toplevel(true); | |
| 2603 info.set_ast_value_factory(&ast_value_factory_); | |
| 2604 info.set_ast_value_factory_owned(false); | |
| 2605 Parser parser(&info); | |
| 2606 | |
| 2607 if (!Compiler::ParseAndAnalyze(&info)) { | |
| 2608 std::cerr << "Failed to parse:\n" << source_ << "\n"; | |
| 2609 CHECK(false); | |
| 2610 } | |
| 2611 | |
| 2612 outer_scope_ = info.script_scope(); | |
| 2613 module_ = | |
| 2614 info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun(); | |
| 2615 typer_.reset(new AsmTyper(isolate_, zone_, *script_, module_)); | |
| 2616 | |
| 2617 if (validation_type_ == ValidateStatement || | |
| 2618 validation_type_ == ValidateExpression) { | |
| 2619 fun_scope_.reset(new AsmTyper::FunctionScope(typer_.get())); | |
| 2620 | |
| 2621 auto* decls = module_->scope()->declarations(); | |
| 2622 for (int ii = 0; ii < decls->length(); ++ii) { | |
| 2623 Declaration* decl = decls->at(ii); | |
| 2624 if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) { | |
| 2625 fun_decl_ = fun_decl; | |
|
bradn
2016/07/11 17:55:33
CHECK that something's found?
John
2016/07/12 21:13:15
Done.
| |
| 2626 break; | |
| 2627 } | |
| 2628 } | |
| 2629 } | |
| 2630 } | |
| 2631 | |
| 2632 struct VariableName { | |
| 2633 VariableName(const char* name, VariableMode mode) | |
| 2634 : name_(name), mode_(mode) {} | |
| 2635 VariableName(const VariableName&) = default; | |
| 2636 VariableName& operator=(const VariableName&) = default; | |
| 2637 | |
| 2638 const char* name_; | |
| 2639 const VariableMode mode_; | |
| 2640 }; | |
| 2641 | |
| 2642 AsmTyperHarnessBuilder* WithLocal(VariableName var_name, AsmType* type) { | |
| 2643 CHECK(validation_type_ == ValidateStatement || | |
| 2644 validation_type_ == ValidateExpression); | |
| 2645 auto* var = DeclareVariable(var_name); | |
| 2646 auto* var_info = new (zone_) AsmTyper::VariableInfo(type); | |
| 2647 var_info->set_mutability(AsmTyper::VariableInfo::kLocal); | |
| 2648 CHECK(typer_->AddLocal(var, var_info)); | |
| 2649 return this; | |
| 2650 } | |
| 2651 | |
| 2652 AsmTyperHarnessBuilder* WithGlobal(VariableName var_name, AsmType* type) { | |
| 2653 auto* var = DeclareVariable(var_name); | |
| 2654 auto* var_info = new (zone_) AsmTyper::VariableInfo(type); | |
| 2655 var_info->set_mutability(AsmTyper::VariableInfo::kMutableGlobal); | |
| 2656 CHECK(typer_->AddGlobal(var, var_info)); | |
| 2657 return this; | |
| 2658 } | |
| 2659 | |
| 2660 AsmTyperHarnessBuilder* WithGlobal( | |
| 2661 VariableName var_name, std::function<AsmType*(Zone*)> type_creator) { | |
| 2662 return WithGlobal(var_name, type_creator(zone_)); | |
| 2663 } | |
| 2664 | |
| 2665 AsmTyperHarnessBuilder* WithUndefinedGlobal( | |
| 2666 VariableName var_name, std::function<AsmType*(Zone*)> type_creator) { | |
| 2667 auto* type = type_creator(zone_); | |
| 2668 CHECK(type->AsFunctionType() != nullptr || | |
| 2669 type->AsFunctionTableType() != nullptr); | |
| 2670 WithGlobal(var_name, type); | |
| 2671 auto* var_info = typer_->Lookup(DeclareVariable(var_name)); | |
| 2672 CHECK(var_info); | |
| 2673 var_info->FirstForwardUseIs(nullptr); | |
| 2674 return this; | |
| 2675 } | |
| 2676 | |
| 2677 AsmTyperHarnessBuilder* WithImport(VariableName var_name, | |
| 2678 AsmTyper::StandardMember standard_member) { | |
| 2679 auto* var = DeclareVariable(var_name); | |
| 2680 AsmTyper::VariableInfo* var_info = nullptr; | |
| 2681 auto* stdlib_map = &typer_->stdlib_math_types_; | |
| 2682 switch (standard_member) { | |
| 2683 case AsmTyper::kHeap: | |
| 2684 case AsmTyper::kStdlib: | |
| 2685 case AsmTyper::kModule: | |
| 2686 case AsmTyper::kNone: | |
| 2687 CHECK(false); | |
| 2688 case AsmTyper::kFFI: | |
| 2689 stdlib_map = nullptr; | |
| 2690 var_info = new (zone_) AsmTyper::VariableInfo(AsmType::FFIType(zone_)); | |
| 2691 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal); | |
| 2692 break; | |
| 2693 case AsmTyper::kInfinity: | |
| 2694 case AsmTyper::kNaN: | |
| 2695 stdlib_map = &typer_->stdlib_types_; | |
| 2696 default: | |
| 2697 break; | |
| 2698 } | |
| 2699 | |
| 2700 if (var_info == nullptr) { | |
| 2701 for (auto iter : *stdlib_map) { | |
| 2702 if (iter.second->standard_member() == standard_member) { | |
| 2703 var_info = iter.second; | |
| 2704 break; | |
| 2705 } | |
| 2706 } | |
| 2707 | |
| 2708 CHECK(var_info != nullptr); | |
| 2709 var_info = var_info->Clone(zone_); | |
| 2710 } | |
| 2711 | |
| 2712 CHECK(typer_->AddGlobal(var, var_info)); | |
| 2713 return this; | |
| 2714 } | |
| 2715 | |
| 2716 AsmTyperHarnessBuilder* WithReturnType(AsmType* type) { | |
| 2717 CHECK(type->IsReturnType()); | |
| 2718 CHECK(typer_->return_type_ == AsmType::None()); | |
| 2719 typer_->return_type_ = type; | |
| 2720 return this; | |
| 2721 } | |
| 2722 | |
| 2723 AsmTyperHarnessBuilder* WithStdlib(VariableName var_name) { | |
| 2724 auto* var = DeclareVariable(var_name); | |
| 2725 auto* var_info = new (zone_) AsmTyper::VariableInfo(); | |
| 2726 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal); | |
| 2727 var_info->set_standard_member(AsmTyper::kStdlib); | |
| 2728 CHECK(typer_->AddGlobal(var, var_info)); | |
| 2729 return this; | |
| 2730 } | |
| 2731 | |
| 2732 AsmTyperHarnessBuilder* WithHeap(VariableName var_name) { | |
| 2733 auto* var = DeclareVariable(var_name); | |
| 2734 auto* var_info = new (zone_) AsmTyper::VariableInfo(); | |
| 2735 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal); | |
| 2736 var_info->set_standard_member(AsmTyper::kHeap); | |
| 2737 CHECK(typer_->AddGlobal(var, var_info)); | |
| 2738 return this; | |
| 2739 } | |
| 2740 | |
| 2741 AsmTyperHarnessBuilder* WithFFI(VariableName var_name) { | |
| 2742 auto* var = DeclareVariable(var_name); | |
| 2743 auto* var_info = | |
| 2744 new (zone_) AsmTyper::VariableInfo(AsmType::FFIType(zone_)); | |
| 2745 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal); | |
| 2746 var_info->set_standard_member(AsmTyper::kFFI); | |
| 2747 CHECK(typer_->AddGlobal(var, var_info)); | |
| 2748 return this; | |
| 2749 } | |
| 2750 | |
| 2751 bool Succeeds() { | |
| 2752 CHECK(validation_type_ == ValidateModule || | |
| 2753 validation_type_ == ValidateGlobals || | |
| 2754 validation_type_ == ValidateFunctionTables || | |
| 2755 validation_type_ == ValidateExport || | |
| 2756 validation_type_ == ValidateFunction || | |
| 2757 validation_type_ == ValidateStatement); | |
| 2758 | |
| 2759 if (validation_type_ == ValidateStatement) { | |
| 2760 CHECK(typer_->return_type_ != AsmType::None()); | |
| 2761 if (ValidateAllStatements(fun_decl_)) { | |
| 2762 return true; | |
| 2763 } | |
| 2764 } else if (typer_->Validate()) { | |
| 2765 return true; | |
| 2766 } | |
| 2767 | |
| 2768 std::cerr << "Asm validation failed: " << typer_->error_message() << "\n"; | |
| 2769 return false; | |
| 2770 } | |
| 2771 | |
| 2772 bool SucceedsWithExactType(AsmType* type) { | |
| 2773 CHECK(validation_type_ == ValidateExpression); | |
| 2774 auto* validated_as = ValidateExpressionStatment(fun_decl_); | |
| 2775 if (validated_as == AsmType::None()) { | |
| 2776 std::cerr << "Validation failure: " << typer_->error_message() << "\n"; | |
| 2777 return false; | |
| 2778 } else if (validated_as != type) { | |
| 2779 std::cerr << "Validation succeeded with wrong type " | |
| 2780 << validated_as->Name() << " (vs. " << type->Name() << ").\n"; | |
| 2781 return false; | |
| 2782 } | |
| 2783 | |
| 2784 return true; | |
| 2785 } | |
| 2786 | |
| 2787 bool FailsWithMessage(const char* error_message) { | |
| 2788 CHECK(validation_type_ == ValidateModule || | |
| 2789 validation_type_ == ValidateGlobals || | |
| 2790 validation_type_ == ValidateFunctionTables || | |
| 2791 validation_type_ == ValidateExport || | |
| 2792 validation_type_ == ValidateFunction || | |
| 2793 validation_type_ == ValidateStatement || | |
| 2794 validation_type_ == ValidateExpression); | |
| 2795 | |
| 2796 bool success; | |
| 2797 if (validation_type_ == ValidateStatement) { | |
| 2798 CHECK(typer_->return_type_ != AsmType::None()); | |
| 2799 success = ValidateAllStatements(fun_decl_); | |
| 2800 } else if (validation_type_ == ValidateExpression) { | |
| 2801 success = ValidateExpressionStatment(fun_decl_) != AsmType::None(); | |
| 2802 } else { | |
| 2803 success = typer_->Validate(); | |
| 2804 } | |
| 2805 | |
| 2806 if (success) { | |
| 2807 std::cerr << "Asm validation succeeded\n"; | |
| 2808 return false; | |
| 2809 } | |
| 2810 | |
| 2811 if (std::strstr(typer_->error_message(), error_message) == nullptr) { | |
| 2812 std::cerr << "Asm validation failed with the wrong error message:\n" | |
| 2813 "Expected to contain '" | |
| 2814 << error_message << "'\n" | |
| 2815 " Actually is '" | |
| 2816 << typer_->error_message() << "'\n"; | |
| 2817 return false; | |
| 2818 } | |
| 2819 | |
| 2820 return true; | |
| 2821 } | |
| 2822 | |
| 2823 private: | |
| 2824 Variable* DeclareVariable(VariableName var_name) { | |
| 2825 auto* name_ast_string = ast_value_factory_.GetOneByteString(var_name.name_); | |
| 2826 return var_name.mode_ == DYNAMIC_GLOBAL | |
| 2827 ? outer_scope_->DeclareDynamicGlobal(name_ast_string) | |
| 2828 : module_->scope()->DeclareLocal(name_ast_string, VAR, | |
| 2829 kCreatedInitialized, | |
| 2830 Variable::NORMAL); | |
| 2831 } | |
| 2832 | |
| 2833 bool ValidateAllStatements(FunctionDeclaration* fun_decl) { | |
| 2834 AsmTyper::FlattenedStatements iter(zone_, fun_decl->fun()->body()); | |
| 2835 while (auto* curr = iter.Next()) { | |
| 2836 if (typer_->ValidateStatement(curr) == AsmType::None()) { | |
| 2837 return false; | |
| 2838 } | |
| 2839 } | |
| 2840 return true; | |
| 2841 } | |
| 2842 | |
| 2843 AsmType* ValidateExpressionStatment(FunctionDeclaration* fun_decl) { | |
| 2844 AsmTyper::FlattenedStatements iter(zone_, fun_decl->fun()->body()); | |
| 2845 AsmType* ret = AsmType::None(); | |
| 2846 bool last_was_expression_statement = false; | |
| 2847 while (auto* curr = iter.Next()) { | |
| 2848 if (auto* expr_stmt = curr->AsExpressionStatement()) { | |
| 2849 last_was_expression_statement = true; | |
| 2850 if ((ret = typer_->ValidateExpression(expr_stmt->expression())) == | |
| 2851 AsmType::None()) { | |
| 2852 break; | |
| 2853 } | |
| 2854 } else { | |
| 2855 ret = AsmType::None(); | |
| 2856 last_was_expression_statement = true; | |
| 2857 if (typer_->ValidateStatement(curr) == AsmType::None()) { | |
| 2858 break; | |
| 2859 } | |
| 2860 } | |
| 2861 } | |
| 2862 CHECK(last_was_expression_statement || ret == AsmType::None()); | |
| 2863 return ret; | |
| 2864 } | |
| 2865 | |
| 2866 std::string source_; | |
| 2867 ValidationType validation_type_; | |
| 2868 HandleAndZoneScope handles_; | |
| 2869 Zone* zone_; | |
| 2870 Isolate* isolate_; | |
| 2871 AstValueFactory ast_value_factory_; | |
| 2872 Factory* factory_; | |
| 2873 Handle<String> source_code_; | |
| 2874 Handle<Script> script_; | |
| 2875 | |
| 2876 Scope* outer_scope_; | |
| 2877 FunctionLiteral* module_; | |
| 2878 FunctionDeclaration* fun_decl_; | |
| 2879 std::unique_ptr<AsmTyper> typer_; | |
| 2880 std::unique_ptr<AsmTyper::FunctionScope> fun_scope_; | |
| 2881 }; | |
| 2882 | |
| 2883 } // namespace wasm | |
| 2884 } // namespace internal | |
| 2885 } // namespace v8 | |
| 2886 | |
| 2887 namespace { | |
| 2888 | |
| 2889 struct ValidationInput { | |
| 2890 ValidationInput(const std::string& source, iw::ValidationType type) | |
| 2891 : source_(source), type_(type) {} | |
| 2892 | |
| 2893 const std::string source_; | |
| 2894 const iw::ValidationType type_; | |
| 2895 }; | |
| 2896 | |
| 2897 std::unique_ptr<iw::AsmTyperHarnessBuilder> ValidationOf( | |
| 2898 ValidationInput input) { | |
| 2899 return std::unique_ptr<iw::AsmTyperHarnessBuilder>( | |
| 2900 new iw::AsmTyperHarnessBuilder(input.source_.c_str(), input.type_)); | |
| 2901 } | |
| 2902 | |
| 2903 ValidationInput Module(const char* source) { | |
| 2904 return ValidationInput(source, iw::ValidateModule); | |
| 2905 } | |
| 2906 | |
| 2907 std::string WrapInFunction(const char* source, bool needs_use_asm) { | |
| 2908 if (needs_use_asm) { | |
| 2909 return std::string( | |
| 2910 "function foo() {\n" | |
| 2911 " 'use asm';\n" | |
| 2912 " ") + | |
| 2913 source + | |
| 2914 "\n" | |
| 2915 "}"; | |
| 2916 } | |
| 2917 | |
| 2918 return std::string( | |
| 2919 "function bar() {\n" | |
| 2920 " ") + | |
| 2921 source + | |
| 2922 "\n" | |
| 2923 "}\n" | |
| 2924 "return {b: bar};\n"; | |
| 2925 } | |
| 2926 | |
| 2927 ValidationInput Globals(const char* source) { | |
| 2928 static const bool kNeedsUseAsm = true; | |
| 2929 return ValidationInput(WrapInFunction(source, kNeedsUseAsm), | |
| 2930 iw::ValidateGlobals); | |
| 2931 } | |
| 2932 | |
| 2933 ValidationInput FunctionTables(const char* source) { | |
| 2934 static const bool kNeedsUseAsm = true; | |
| 2935 return ValidationInput(WrapInFunction(source, kNeedsUseAsm), | |
| 2936 iw::ValidateFunctionTables); | |
| 2937 } | |
| 2938 | |
| 2939 ValidationInput Export(const char* source) { | |
| 2940 static const bool kNeedsUseAsm = true; | |
| 2941 return ValidationInput(WrapInFunction(source, kNeedsUseAsm), | |
| 2942 iw::ValidateExport); | |
| 2943 } | |
| 2944 | |
| 2945 ValidationInput Function(const char* source) { | |
| 2946 static const bool kNeedsUseAsm = true; | |
| 2947 return ValidationInput(WrapInFunction(source, kNeedsUseAsm), | |
| 2948 iw::ValidateFunction); | |
| 2949 } | |
| 2950 | |
| 2951 ValidationInput Statement(const char* source) { | |
| 2952 static const bool kDoesNotNeedUseAsm = false; | |
| 2953 static const bool kNeedsUseAsm = true; | |
| 2954 return ValidationInput( | |
| 2955 WrapInFunction(WrapInFunction(source, kDoesNotNeedUseAsm).c_str(), | |
| 2956 kNeedsUseAsm), | |
| 2957 iw::ValidateStatement); | |
| 2958 } | |
| 2959 | |
| 2960 ValidationInput Expression(const char* source) { | |
| 2961 static const bool kDoesNotNeedUseAsm = false; | |
| 2962 static const bool kNeedsUseAsm = true; | |
| 2963 return ValidationInput( | |
| 2964 WrapInFunction(WrapInFunction(source, kDoesNotNeedUseAsm).c_str(), | |
| 2965 kNeedsUseAsm), | |
| 2966 iw::ValidateExpression); | |
| 2967 } | |
| 2968 | |
| 2969 iw::AsmTyperHarnessBuilder::VariableName Var(const char* name) { | |
| 2970 return iw::AsmTyperHarnessBuilder::VariableName(name, VAR); | |
| 2971 } | |
| 2972 | |
| 2973 iw::AsmTyperHarnessBuilder::VariableName DynamicGlobal(const char* name) { | |
| 2974 return iw::AsmTyperHarnessBuilder::VariableName(name, DYNAMIC_GLOBAL); | |
| 2975 } | |
| 2976 | |
| 2977 TEST(MissingUseAsmDirective) { | |
| 2978 v8::V8::Initialize(); | |
| 2979 | |
| 2980 // We can't test the empty input ("") because the AsmTyperHarnessBuilder will | |
| 2981 // CHECK if there's no function in the top-level scope. | |
| 2982 const char* kTests[] = {"function module(){}", | |
| 2983 "function module(){ use_asm; }", | |
| 2984 "function module(){ \"use asm \"; }", | |
| 2985 "function module(){ \" use asm \"; }", | |
| 2986 "function module(){ \"use Asm\"; }"}; | |
| 2987 | |
| 2988 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 2989 const char* module = kTests[ii]; | |
| 2990 if (!ValidationOf(Module(module)) | |
| 2991 ->FailsWithMessage("Missing \"use asm\"")) { | |
| 2992 std::cerr << "Test:\n" << module; | |
| 2993 CHECK(false); | |
| 2994 } | |
| 2995 } | |
| 2996 } | |
| 2997 | |
| 2998 TEST(InvalidModuleSignature) { | |
| 2999 v8::V8::Initialize(); | |
| 3000 | |
| 3001 const struct { | |
| 3002 const char* module; | |
| 3003 const char* error_message; | |
| 3004 } kTests[] = { | |
| 3005 {"function eval(){ \"use asm\"; }", | |
| 3006 "Invalid asm.js identifier in module name"}, | |
| 3007 {"function arguments(){ \"use asm\"; }", | |
| 3008 "Invalid asm.js identifier in module name"}, | |
| 3009 {"function module(eval){ \"use asm\"; }", | |
| 3010 "Invalid asm.js identifier in module parameter"}, | |
| 3011 {"function module(arguments){ \"use asm\"; }", | |
| 3012 "Invalid asm.js identifier in module parameter"}, | |
| 3013 {"function module(stdlib, eval){ \"use asm\"; }", | |
| 3014 "Invalid asm.js identifier in module parameter"}, | |
| 3015 {"function module(stdlib, arguments){ \"use asm\"; }", | |
| 3016 "Invalid asm.js identifier in module parameter"}, | |
| 3017 {"function module(stdlib, foreign, eval){ \"use asm\"; }", | |
| 3018 "Invalid asm.js identifier in module parameter"}, | |
| 3019 {"function module(stdlib, foreign, arguments){ \"use asm\"; }", | |
| 3020 "Invalid asm.js identifier in module parameter"}, | |
| 3021 {"function module(stdlib, foreign, heap, eval){ \"use asm\"; }", | |
| 3022 "asm.js modules may not have more than three parameters"}, | |
| 3023 {"function module(stdlib, foreign, heap, arguments){ \"use asm\"; }", | |
| 3024 "asm.js modules may not have more than three parameters"}, | |
| 3025 {"function module(module){ \"use asm\"; }", | |
| 3026 "Redeclared identifier in module parameter"}, | |
| 3027 {"function module(stdlib, module){ \"use asm\"; }", | |
| 3028 "Redeclared identifier in module parameter"}, | |
| 3029 {"function module(stdlib, stdlib){ \"use asm\"; }", | |
| 3030 "Redeclared identifier in module parameter"}, | |
| 3031 {"function module(stdlib, foreign, module){ \"use asm\"; }", | |
| 3032 "Redeclared identifier in module parameter"}, | |
| 3033 {"function module(stdlib, foreign, stdlib){ \"use asm\"; }", | |
| 3034 "Redeclared identifier in module parameter"}, | |
| 3035 {"function module(stdlib, foreign, foreign){ \"use asm\"; }", | |
| 3036 "Redeclared identifier in module parameter"}, | |
| 3037 }; | |
| 3038 | |
| 3039 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3040 const auto* test = kTests + ii; | |
| 3041 if (!ValidationOf(Module(test->module)) | |
| 3042 ->FailsWithMessage(test->error_message)) { | |
| 3043 std::cerr << "Test:\n" << test->module; | |
| 3044 CHECK(false); | |
| 3045 } | |
| 3046 } | |
| 3047 } | |
| 3048 | |
| 3049 TEST(ErrorsInGlobalVariableDefinition) { | |
| 3050 const struct { | |
| 3051 const char* decl; | |
| 3052 const char* error_message; | |
| 3053 } kTests[] = { | |
| 3054 {"var v;", "Global variable missing initializer"}, | |
| 3055 {"var v = uninitialized;", "Invalid global variable initializer"}, | |
| 3056 {"var v = 'use asm';", "type annotation - forbidden literal"}, | |
| 3057 {"var v = 4294967296;", " - forbidden literal"}, | |
| 3058 {"var v = not_fround;", "Invalid global variable initializer"}, | |
| 3059 {"var v = not_fround(1);", "expected call fround(literal)"}, | |
| 3060 {"var v = __fround__(1.0);", "expected call fround(literal)"}, | |
| 3061 {"var v = fround(1.0, 1.0);", "expected call fround(literal)"}, | |
| 3062 {"var v = fround(not_fround);", "literal argument for call to fround"}, | |
| 3063 {"var v = fround(1);", "literal argument to be a floating point"}, | |
| 3064 {"var v = stdlib.nan", "Invalid import"}, | |
| 3065 {"var v = stdlib.Math.nan", "Invalid import"}, | |
| 3066 {"var v = stdlib.Mathh.E", "Invalid import"}, | |
| 3067 {"var v = stdlib.Math", "Invalid import"}, | |
| 3068 {"var v = Stdlib.Math.E", "Invalid import"}, | |
| 3069 {"var v = stdlib.Math.E[0]", "Invalid import"}, | |
| 3070 {"var v = stdlibb.NaN", "Invalid import"}, | |
| 3071 {"var v = ffi.NaN[0]", "Invalid import"}, | |
| 3072 {"var v = heap.NaN[0]", "Invalid import"}, | |
| 3073 {"var v = ffi.foo * 2.0;", "unrecognized annotation"}, | |
| 3074 {"var v = ffi.foo|1;", "unrecognized annotation"}, | |
| 3075 {"var v = ffi()|0;", "must import member"}, | |
| 3076 {"var v = +ffi();", "must import member"}, | |
| 3077 {"var v = ffi().a|0;", "object lookup failed"}, | |
| 3078 {"var v = +ffi().a;", "object lookup failed"}, | |
| 3079 {"var v = sstdlib.a|0;", "object lookup failed"}, | |
| 3080 {"var v = +sstdlib.a;", "object lookup failed"}, | |
| 3081 {"var v = stdlib.NaN|0;", "object is not the ffi"}, | |
| 3082 {"var v = +stdlib.NaN;", "object is not the ffi"}, | |
| 3083 {"var v = new f()", "Invalid type after new"}, | |
| 3084 {"var v = new stdli.Uint8Array(heap)", "Unknown stdlib member in heap"}, | |
| 3085 {"var v = new stdlib.dd(heap)", "Unknown stdlib member in heap"}, | |
| 3086 {"var v = new stdlib.Math.fround(heap)", "Type is not a heap view type"}, | |
| 3087 {"var v = new stdlib.Uint8Array(a, b)", "Invalid number of arguments"}, | |
| 3088 {"var v = new stdlib.Uint8Array(heap())", "should be the module's heap"}, | |
| 3089 {"var v = new stdlib.Uint8Array(heap_)", "instead of heap parameter"}, | |
| 3090 {"var v = new stdlib.Uint8Array(ffi)", "should be the module's heap"}, | |
| 3091 {"var eval = 0;", "in global variable"}, | |
| 3092 {"var eval = 0.0;", "in global variable"}, | |
| 3093 {"var eval = fround(0.0);", "in global variable"}, | |
| 3094 {"var eval = +ffi.a;", "in global variable"}, | |
| 3095 {"var eval = ffi.a|0;", "in global variable"}, | |
| 3096 {"var eval = ffi.a;", "in global variable"}, | |
| 3097 {"var eval = new stdlib.Uint8Array(heap);", "in global variable"}, | |
|
bradn
2016/07/11 17:55:34
kind of an odd error message?
John
2016/07/12 21:13:15
These are only snippets of the actual error messag
| |
| 3098 {"var arguments = 0;", "in global variable"}, | |
| 3099 {"var arguments = 0.0;", "in global variable"}, | |
| 3100 {"var arguments = fround(0.0);", "in global variable"}, | |
| 3101 {"var arguments = +ffi.a;", "in global variable"}, | |
| 3102 {"var arguments = ffi.a|0;", "in global variable"}, | |
| 3103 {"var arguments = ffi.a;", "in global variable"}, | |
| 3104 {"var arguments = new stdlib.Uint8Array(heap);", "in global variable"}, | |
| 3105 {"var a = 0, a = 0.0;", "Redefined global variable"}, | |
| 3106 {"var a = 0; var a = 0;", "Redefined global variable"}, | |
| 3107 {"var a = 0, b = 0; var a = 0;", "Redefined global variable"}, | |
| 3108 {"var a = 0, b = 0; var b = 0, a = 0.0;", "Redefined global variable"}, | |
| 3109 }; | |
| 3110 | |
| 3111 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3112 const auto* test = kTests + ii; | |
| 3113 if (!ValidationOf(Globals(test->decl)) | |
| 3114 ->WithStdlib(DynamicGlobal("stdlib")) | |
| 3115 ->WithFFI(DynamicGlobal("ffi")) | |
| 3116 ->WithHeap(DynamicGlobal("heap")) | |
| 3117 ->WithGlobal(DynamicGlobal("not_fround"), iw::AsmType::Int()) | |
| 3118 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
| 3119 ->FailsWithMessage(test->error_message)) { | |
| 3120 std::cerr << "Test:\n" << test->decl; | |
| 3121 CHECK(false); | |
| 3122 } | |
| 3123 } | |
| 3124 } | |
| 3125 | |
| 3126 TEST(ErrorsInFunctionTableDefinition) { | |
| 3127 const struct { | |
| 3128 const char* tables; | |
| 3129 const char* error_message; | |
| 3130 } kTests[] = { | |
| 3131 {"var a = [a, a, a];", "Invalid length for function pointer table"}, | |
| 3132 {"var a = [d2s0()];", "must be a function name"}, | |
| 3133 {"var a = [d2s44];", "Undefined identifier in function pointer"}, | |
| 3134 {"var a = [fround];", "not be a member of the standard library"}, | |
| 3135 {"var a = [imul];", "not be a member of the standard library"}, | |
| 3136 {"var a = [ffi_import];", "must be an asm.js function"}, | |
| 3137 {"var a = [dI];", "must be an asm.js function"}, | |
| 3138 {"var a = [d2s0, d2s1, d2s0, f2s0];", "mismatch in function pointer"}, | |
| 3139 {"var eval = [d2s0, d2s1];", "asm.js identifier in function table name"}, | |
| 3140 {"var arguments = [d2s0, d2s1];", "asm.js identifier in function table"}, | |
| 3141 {"var foo = [d2s0, d2s1];", | |
| 3142 "Identifier redefined as function pointer table"}, | |
| 3143 {"var I = [d2s0, d2s1];", | |
| 3144 "Identifier redefined as function pointer table"}, | |
| 3145 {"var d2s = [d2f0, d2f1];", "redefined as function pointer table"}, | |
| 3146 {"var d2s_t = [d2s0];", "Function table size mismatch"}, | |
| 3147 {"var d2s_t = [d2f0, d2f1];", "initializer does not match previous"}, | |
| 3148 }; | |
| 3149 | |
| 3150 auto d2s = [](Zone* zone) -> iw::AsmType* { | |
| 3151 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
| 3152 ret->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
| 3153 return ret; | |
| 3154 }; | |
| 3155 | |
| 3156 auto d2s_tbl = [](Zone* zone) -> iw::AsmType* { | |
| 3157 auto* d2s = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
| 3158 d2s->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
| 3159 | |
| 3160 auto* ret = iw::AsmType::FunctionTableType(zone, 2, d2s); | |
| 3161 return ret; | |
| 3162 }; | |
| 3163 | |
| 3164 auto f2s = [](Zone* zone) -> iw::AsmType* { | |
| 3165 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
| 3166 ret->AsFunctionType()->AddArgument(iw::AsmType::Float()); | |
| 3167 return ret; | |
| 3168 }; | |
| 3169 | |
| 3170 auto d2f = [](Zone* zone) -> iw::AsmType* { | |
| 3171 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Float()); | |
| 3172 ret->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
| 3173 return ret; | |
| 3174 }; | |
| 3175 | |
| 3176 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3177 const auto* test = kTests + ii; | |
| 3178 if (!ValidationOf(FunctionTables(test->tables)) | |
| 3179 ->WithImport(DynamicGlobal("ffi_import"), iw::AsmTyper::kFFI) | |
| 3180 ->WithImport(DynamicGlobal("imul"), iw::AsmTyper::kMathImul) | |
| 3181 ->WithImport(DynamicGlobal("E"), iw::AsmTyper::kMathE) | |
| 3182 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
| 3183 ->WithImport(DynamicGlobal("floor"), iw::AsmTyper::kMathFround) | |
| 3184 ->WithGlobal(DynamicGlobal("d2s0"), d2s) | |
| 3185 ->WithGlobal(DynamicGlobal("d2s1"), d2s) | |
| 3186 ->WithGlobal(DynamicGlobal("f2s0"), f2s) | |
| 3187 ->WithGlobal(DynamicGlobal("f2s1"), f2s) | |
| 3188 ->WithGlobal(DynamicGlobal("d2f0"), d2f) | |
| 3189 ->WithGlobal(DynamicGlobal("d2f1"), d2f) | |
| 3190 ->WithGlobal(DynamicGlobal("dI"), iw::AsmType::Int()) | |
| 3191 ->WithGlobal(Var("I"), iw::AsmType::Int()) | |
| 3192 ->WithUndefinedGlobal(Var("d2s"), d2s) | |
| 3193 ->WithUndefinedGlobal(Var("d2s_t"), d2s_tbl) | |
| 3194 ->FailsWithMessage(test->error_message)) { | |
| 3195 std::cerr << "Test:\n" << test->tables; | |
| 3196 CHECK(false); | |
| 3197 } | |
| 3198 } | |
| 3199 } | |
| 3200 | |
| 3201 TEST(ErrorsInModuleExport) { | |
| 3202 const struct { | |
| 3203 const char* module_export; | |
| 3204 const char* error_message; | |
| 3205 } kTests[] = { | |
| 3206 {"", "Missing asm.js module export"}, | |
| 3207 {"return;", "Unrecognized expression in asm.js module export expression"}, | |
| 3208 {"return f;", "Undefined identifier in asm.js module export"}, | |
| 3209 {"return f();", "Unrecognized expression in asm.js module export"}, | |
| 3210 {"return d2s_tbl;", "cannot export function tables"}, | |
| 3211 {"return min;", "cannot export standard library functions"}, | |
| 3212 {"return ffi;", "cannot export foreign functions"}, | |
| 3213 {"return I;", "is not an asm.js function"}, | |
| 3214 {"return {\'a\': d2s_tbl}", "cannot export function tables"}, | |
|
bradn
2016/07/11 17:55:33
Why \' ?
John
2016/07/12 21:13:15
Because. Done.
| |
| 3215 {"return {\'a\': min}", "cannot export standard library functions"}, | |
| 3216 {"return {\'a\': ffi}", "cannot export foreign functions"}, | |
| 3217 {"return {\'a\': f()}", "must be an asm.js function name"}, | |
| 3218 {"return {\'a\': f}", "Undefined identifier in asm.js module export"}, | |
| 3219 {"function v() { a(); } return {b: d2s}", "Missing definition for forw"}, | |
| 3220 {"return {b: d2s, \'a\': d2s_tbl}", "cannot export function tables"}, | |
| 3221 {"return {b: d2s, \'a\': min}", "cannot export standard library"}, | |
| 3222 {"return {b: d2s, \'a\': ffi}", "cannot export foreign functions"}, | |
| 3223 {"return {b: d2s, \'a\': f()}", "must be an asm.js function name"}, | |
| 3224 {"return {b: d2s, \'a\': f}", "Undefined identifier in asm.js module"}, | |
| 3225 }; | |
| 3226 | |
| 3227 auto d2s_tbl = [](Zone* zone) -> iw::AsmType* { | |
| 3228 auto* d2s = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
| 3229 d2s->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
| 3230 | |
| 3231 auto* ret = iw::AsmType::FunctionTableType(zone, 2, d2s); | |
| 3232 return ret; | |
| 3233 }; | |
| 3234 | |
| 3235 auto d2s = [](Zone* zone) -> iw::AsmType* { | |
| 3236 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
| 3237 ret->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
| 3238 return ret; | |
| 3239 }; | |
| 3240 | |
| 3241 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3242 const auto* test = kTests + ii; | |
| 3243 if (!ValidationOf(Export(test->module_export)) | |
| 3244 ->WithGlobal(DynamicGlobal("d2s_tbl"), d2s_tbl) | |
| 3245 ->WithGlobal(DynamicGlobal("d2s"), d2s) | |
| 3246 ->WithImport(DynamicGlobal("min"), iw::AsmTyper::kMathMin) | |
| 3247 ->WithImport(DynamicGlobal("ffi"), iw::AsmTyper::kFFI) | |
| 3248 ->WithGlobal(DynamicGlobal("I"), iw::AsmType::Int()) | |
| 3249 ->FailsWithMessage(test->error_message)) { | |
| 3250 std::cerr << "Test:\n" << test->module_export; | |
| 3251 CHECK(false); | |
| 3252 } | |
| 3253 } | |
| 3254 } | |
| 3255 | |
| 3256 TEST(ErrorsInFunction) { | |
| 3257 auto d2s = [](Zone* zone) -> iw::AsmType* { | |
| 3258 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
| 3259 ret->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
| 3260 return ret; | |
| 3261 }; | |
| 3262 | |
| 3263 const struct { | |
| 3264 const char* function; | |
| 3265 const char* error_message; | |
| 3266 } kTests[] = { | |
| 3267 {"function f(eval) {" | |
| 3268 " eval = eval|0;" | |
| 3269 "}\n", | |
| 3270 "Invalid asm.js identifier in parameter name"}, | |
| 3271 {"function f(arguments) {" | |
| 3272 " arguments = arguments|0;" | |
| 3273 "}\n", | |
| 3274 "Invalid asm.js identifier in parameter name"}, | |
| 3275 // The following error should actually be a "redeclared local," but the | |
| 3276 // AST "hides" the first parameter from us, so the parameter type checking | |
| 3277 // will fail because the validator will think that the a = a|0 is | |
| 3278 // annotating the second parameter. | |
| 3279 {"function f(a, a) {\n" | |
| 3280 " a = a|0;\n" | |
| 3281 " a = +a;\n" | |
| 3282 "}\n", | |
| 3283 "Incorrect parameter type annotations"}, | |
| 3284 {"function f(b, a) {\n" | |
| 3285 " if (0) return;\n" | |
| 3286 " b = +b;\n" | |
| 3287 " a = a|0;\n" | |
| 3288 "}\n", | |
| 3289 "Incorrect parameter type annotations"}, | |
| 3290 {"function f(b, a) {\n" | |
| 3291 " f();\n" | |
| 3292 " b = +b;\n" | |
| 3293 " a = a|0;\n" | |
| 3294 "}\n", | |
| 3295 "Incorrect parameter type annotations"}, | |
| 3296 {"function f(b, a) {\n" | |
| 3297 " f.a = 0;\n" | |
| 3298 " b = +b;\n" | |
| 3299 " a = a|0;\n" | |
| 3300 "}\n", | |
| 3301 "Incorrect parameter type annotations"}, | |
| 3302 {"function f(b, a) {\n" | |
| 3303 " a = a|0;\n" | |
| 3304 " b = +b;\n" | |
| 3305 "}\n", | |
| 3306 "Incorrect parameter type annotations"}, | |
| 3307 {"function f(b, a) {\n" | |
| 3308 " b = +b;\n" | |
| 3309 " a = a|0;\n" | |
| 3310 " var eval = 0;\n" | |
| 3311 "}\n", | |
| 3312 "Invalid asm.js identifier in local variable"}, | |
| 3313 {"function f(b, a) {\n" | |
| 3314 " b = +b;\n" | |
| 3315 " a = a|0;\n" | |
| 3316 " var b = 0;\n" | |
| 3317 "}\n", | |
| 3318 "Redeclared local"}, | |
| 3319 {"function f(b, a) {\n" | |
| 3320 " b = +b;\n" | |
| 3321 " a = a|0;\n" | |
| 3322 " var c = 0, c = 1.0;\n" | |
| 3323 "}\n", | |
| 3324 "Redeclared local"}, | |
| 3325 {"function f(b, a) {\n" | |
| 3326 " b = +b;\n" | |
| 3327 " a = a|0;\n" | |
| 3328 " var c = 0; var c = 1.0;\n" | |
| 3329 "}\n", | |
| 3330 "Redeclared local"}, | |
| 3331 {"function f(b, a) {\n" | |
| 3332 " b = +b;\n" | |
| 3333 " a = a|0;\n" | |
| 3334 " f();\n" | |
| 3335 " var c = 0;\n" | |
| 3336 "}\n", | |
| 3337 "Local variable missing initializer in asm.js module"}, | |
| 3338 {"function f() {\n" | |
| 3339 " function ff() {}\n" | |
| 3340 "}\n", | |
| 3341 "Functions may only define inner variables"}, | |
| 3342 {"function f() {\n" | |
| 3343 " return a+1;\n" | |
| 3344 "}\n", | |
| 3345 "Invalid return type annotation"}, | |
| 3346 {"function f() {\n" | |
| 3347 " return ~~x;\n" | |
| 3348 "}\n", | |
| 3349 "Invalid return type annotation"}, | |
| 3350 {"function f() {\n" | |
| 3351 " return d();\n" | |
| 3352 "}\n", | |
| 3353 "Invalid function call in return statement"}, | |
| 3354 {"function f() {\n" | |
| 3355 " return 'use asm';\n" | |
| 3356 "}\n", | |
| 3357 "Invalid literal in return statement"}, | |
| 3358 {"function f() {\n" | |
| 3359 " return 2147483648;\n" | |
| 3360 "}\n", | |
| 3361 "Invalid literal in return statement"}, | |
| 3362 {"function f() {\n" | |
| 3363 " return stdlib.Math.E;" | |
| 3364 "}\n", | |
| 3365 "Invalid return type expression"}, | |
| 3366 {"function f() {\n" | |
| 3367 " return E[0];" | |
| 3368 "}\n", | |
| 3369 "Invalid return type expression"}, | |
| 3370 {"function I() {}\n", "Identifier redefined as function"}, | |
| 3371 {"function foo() {}\n", "Identifier redefined as function"}, | |
| 3372 {"function d2s() {}\n", "Identifier redefined (function name)"}, | |
| 3373 {"function d2s(x) {\n" | |
| 3374 " x = x|0;\n" | |
| 3375 " return -1;\n" | |
| 3376 "}\n", | |
| 3377 "Identifier redefined (function name)"}, | |
| 3378 {"function d2s(x) {\n" | |
| 3379 " x = +x;\n" | |
| 3380 " return -1.0;\n" | |
| 3381 "}\n", | |
| 3382 "Identifier redefined (function name)"}, | |
| 3383 }; | |
| 3384 | |
| 3385 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3386 const auto* test = kTests + ii; | |
| 3387 if (!ValidationOf(Function(test->function)) | |
| 3388 ->WithGlobal(Var("I"), iw::AsmType::Int()) | |
| 3389 ->WithGlobal(Var("d2s"), d2s) | |
| 3390 ->FailsWithMessage(test->error_message)) { | |
| 3391 std::cerr << "Test:\n" << test->function; | |
| 3392 CHECK(false); | |
| 3393 } | |
| 3394 } | |
| 3395 } | |
| 3396 | |
| 3397 TEST(ErrorsInStatement) { | |
| 3398 const struct { | |
| 3399 const char* statement; | |
| 3400 const char* error_message; | |
| 3401 } kTests[] = { | |
| 3402 {"if (fround(1));", "If condition must be type int"}, | |
| 3403 {"return;", "Type mismatch in return statement"}, | |
| 3404 {"return +1.0;", "Type mismatch in return statement"}, | |
| 3405 {"return +d()", "Type mismatch in return statement"}, | |
| 3406 {"while (fround(1));", "While condition must be type int"}, | |
| 3407 {"do {} while (fround(1));", "Do {} While condition must be type int"}, | |
| 3408 {"for (;fround(1););", "For condition must be type int"}, | |
| 3409 {"switch(flocal){ case 0: return 0; }", "Switch tag must be signed"}, | |
| 3410 {"switch(slocal){ case 1: case 1: return 0; }", "Duplicated case label"}, | |
| 3411 {"switch(slocal){ case 1: case 0: break; case 1: return 0; }", | |
| 3412 "Duplicated case label"}, | |
| 3413 {"switch(slocal){ case 1.0: return 0; }", | |
| 3414 "Case label must be a 32-bit signed integer"}, | |
| 3415 {"switch(slocal){ case 1.0: return 0; }", | |
| 3416 "Case label must be a 32-bit signed integer"}, | |
| 3417 {"switch(slocal){ case -100000: case 2147483647: return 0; }", | |
| 3418 "Out-of-bounds case"}, | |
| 3419 {"switch(slocal){ case 2147483648: return 0; }", | |
| 3420 "Case label must be a 32-bit signed"}, | |
| 3421 }; | |
| 3422 | |
| 3423 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3424 const auto* test = kTests + ii; | |
| 3425 if (!ValidationOf(Statement(test->statement)) | |
| 3426 ->WithReturnType(iw::AsmType::Signed()) | |
| 3427 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
| 3428 ->WithLocal(DynamicGlobal("flocal"), iw::AsmType::Float()) | |
| 3429 ->WithLocal(DynamicGlobal("slocal"), iw::AsmType::Signed()) | |
| 3430 ->FailsWithMessage(test->error_message)) { | |
| 3431 std::cerr << "Test:\n" << test->statement; | |
| 3432 CHECK(false); | |
| 3433 } | |
| 3434 } | |
| 3435 } | |
| 3436 | |
| 3437 TEST(ErrorsInExpression) { | |
| 3438 auto d2d = [](Zone* zone) -> iw::AsmType* { | |
| 3439 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Double()); | |
| 3440 ret->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
| 3441 return ret; | |
| 3442 }; | |
| 3443 | |
| 3444 auto d2s_tbl = [](Zone* zone) -> iw::AsmType* { | |
| 3445 auto* d2s = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
| 3446 d2s->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
| 3447 | |
| 3448 auto* ret = iw::AsmType::FunctionTableType(zone, 2, d2s); | |
| 3449 return ret; | |
| 3450 }; | |
| 3451 | |
| 3452 const struct { | |
| 3453 const char* expression; | |
| 3454 const char* error_message; | |
| 3455 } kTests[] = { | |
| 3456 {"noy_a_function();", "Unanotated call to a function must be a call to"}, | |
| 3457 {"a = 0;", "Undeclared identifier"}, | |
| 3458 {"ilocal = +1.0", "Type mismatch in assignment"}, | |
| 3459 {"!dlocal", "Invalid type for !"}, | |
| 3460 {"2 * dlocal", "Invalid types for intish *"}, | |
| 3461 {"dlocal * 2", "Invalid types for intish *"}, | |
| 3462 {"1048577 * ilocal", "Invalid operands for *"}, | |
| 3463 {"1048577 / ilocal", "Invalid operands for /"}, | |
| 3464 {"1048577 % dlocal", "Invalid operands for %"}, | |
| 3465 {"1048577 * dlocal", "Invalid operands for *"}, | |
| 3466 {"1048577 / dlocal", "Invalid operands for /"}, | |
| 3467 {"1048577 % ilocal", "Invalid operands for %"}, | |
| 3468 {"ilocal * dlocal", "Invalid operands for *"}, | |
| 3469 {"ilocal / dlocal", "Invalid operands for /"}, | |
| 3470 {"ilocal % dlocal", "Invalid operands for %"}, | |
| 3471 {"1048577 + dlocal", "Invalid operands for additive expression"}, | |
| 3472 {"1048577 - dlocal", "Invalid operands for additive expression"}, | |
| 3473 {"ilocal + dlocal", "Invalid operands for additive expression"}, | |
| 3474 {"ilocal - dlocal", "Invalid operands for additive expression"}, | |
| 3475 {"1048577 << dlocal", "Invalid operands for <<"}, | |
| 3476 {"1048577 >> dlocal", "Invalid operands for >>"}, | |
| 3477 {"1048577 >>> dlocal", "Invalid operands for >>"}, | |
| 3478 {"ilocal << dlocal", "Invalid operands for <<"}, | |
| 3479 {"ilocal >> dlocal", "Invalid operands for >>"}, | |
| 3480 {"ilocal >>> dlocal", "Invalid operands for >>>"}, | |
| 3481 {"1048577 < dlocal", "Invalid operands for <"}, | |
| 3482 {"ilocal < dlocal", "Invalid operands for <"}, | |
| 3483 {"1048577 > dlocal", "Invalid operands for >"}, | |
| 3484 {"ilocal > dlocal", "Invalid operands for >"}, | |
| 3485 {"1048577 <= dlocal", "Invalid operands for <="}, | |
| 3486 {"ilocal <= dlocal", "Invalid operands for <="}, | |
| 3487 {"1048577 >= dlocal", "Invalid operands for >="}, | |
| 3488 {"ilocal >= dlocal", "Invalid operands for >="}, | |
| 3489 {"1048577 == dlocal", "Invalid operands for =="}, | |
| 3490 {"ilocal == dlocal", "Invalid operands for =="}, | |
| 3491 /* NOTE: the parser converts a == b to !(a == b). */ | |
| 3492 {"1048577 != dlocal", "Invalid operands for =="}, | |
| 3493 {"ilocal != dlocal", "Invalid operands for =="}, | |
| 3494 {"dlocal & dlocal", "Invalid operands for &"}, | |
| 3495 {"1048577 & dlocal", "Invalid operands for &"}, | |
| 3496 {"ilocal & dlocal", "Invalid operands for &"}, | |
| 3497 {"dlocal | dlocal2", "Invalid operands for |"}, | |
| 3498 {"1048577 | dlocal", "Invalid operands for |"}, | |
| 3499 {"ilocal | dlocal", "Invalid operands for |"}, | |
| 3500 {"dlocal ^ dlocal2", "Invalid operands for ^"}, | |
| 3501 {"1048577 ^ dlocal", "Invalid operands for ^"}, | |
| 3502 {"ilocal ^ dlocal", "Invalid operands for ^"}, | |
| 3503 {"dlocal ? 0 : 1", "Ternary operation condition should be int"}, | |
| 3504 {"ilocal ? dlocal : 1", "Type mismatch for ternary operation result"}, | |
| 3505 {"ilocal ? 1 : dlocal", "Type mismatch for ternary operation result"}, | |
| 3506 {"eval(10)|0", "Invalid asm.js identifier in (forward) function"}, | |
| 3507 {"arguments(10)|0", "Invalid asm.js identifier in (forward) function"}, | |
| 3508 {"not_a_function(10)|0", "Calling something that's not a function"}, | |
| 3509 {"fround(FFI())", "Foreign functions can't return float"}, | |
| 3510 {"FFI(fround(0))|0", "Function invocation does not match function type"}, | |
| 3511 {"FFI(2147483648)|0", "Function invocation does not match function type"}, | |
| 3512 {"d2d(2.0)|0", "Function invocation does not match function type"}, | |
| 3513 {"+d2d(2)", "Function invocation does not match function type"}, | |
| 3514 {"eval[ilocal & 3]()|0", "Invalid asm.js identifier in (forward)"}, | |
| 3515 {"arguments[ilocal & 3]()|0", "Invalid asm.js identifier in (forward)"}, | |
| 3516 {"not_a_function[ilocal & 3]()|0", "Identifier does not name a function"}, | |
| 3517 {"d2s_tbl[ilocal & 3](0.0)|0", "Function table size does not match"}, | |
| 3518 {"+d2s_tbl[ilocal & 1](0.0)", "does not match previous signature"}, | |
| 3519 {"d2s_tbl[ilocal & 1](0)|0", "does not match previous signature"}, | |
| 3520 {"a.b()|0", "Indirect call index must be in the expr & mask form"}, | |
| 3521 {"HEAP32[0][0] = 0", "Invalid heap access"}, | |
| 3522 {"heap32[0] = 0", "Undeclared identifier in heap access"}, | |
| 3523 {"not_a_function[0] = 0", "Identifier does not represent a heap view"}, | |
| 3524 {"HEAP32[0.0] = 0", "Heap access index must be intish"}, | |
| 3525 {"HEAP32[-1] = 0", "Heap access index must be a 32-bit unsigned integer"}, | |
| 3526 {"HEAP32[ilocal >> 1] = 0", "Invalid heap access index"}, | |
| 3527 // *VIOLATION* the following is invalid, but because of desugaring it is | |
| 3528 // accepted. | |
| 3529 // {"HEAP32[0 >> 1] = 0", "Invalid heap access index"}, | |
| 3530 {"HEAP8[fround(0.0)] = 0", "Invalid heap access index for byte array"}, | |
| 3531 }; | |
| 3532 | |
| 3533 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3534 const auto* test = kTests + ii; | |
| 3535 if (!ValidationOf(Expression(test->expression)) | |
| 3536 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int()) | |
| 3537 ->WithLocal(DynamicGlobal("dlocal"), iw::AsmType::Double()) | |
| 3538 ->WithLocal(DynamicGlobal("dlocal2"), iw::AsmType::Double()) | |
| 3539 ->WithLocal(DynamicGlobal("not_a_function"), iw::AsmType::Int()) | |
| 3540 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
| 3541 ->WithImport(DynamicGlobal("FFI"), iw::AsmTyper::kFFI) | |
| 3542 ->WithGlobal(DynamicGlobal("d2d"), d2d) | |
| 3543 ->WithGlobal(DynamicGlobal("d2s_tbl"), d2s_tbl) | |
| 3544 ->WithGlobal(DynamicGlobal("HEAP32"), iw::AsmType::Int32Array()) | |
| 3545 ->WithGlobal(DynamicGlobal("HEAP8"), iw::AsmType::Int8Array()) | |
| 3546 ->FailsWithMessage(test->error_message)) { | |
| 3547 std::cerr << "Test:\n" << test->expression; | |
| 3548 CHECK(false); | |
| 3549 } | |
| 3550 } | |
| 3551 } | |
| 3552 | |
| 3553 TEST(ValidateNumericLiteral) { | |
| 3554 const struct { | |
| 3555 const char* expression; | |
| 3556 iw::AsmType* expected_type; | |
| 3557 } kTests[] = { | |
| 3558 {"0", iw::AsmType::FixNum()}, | |
| 3559 {"-1", iw::AsmType::Signed()}, | |
| 3560 {"2147483648", iw::AsmType::Unsigned()}, | |
| 3561 {"0.0", iw::AsmType::Double()}, | |
| 3562 }; | |
| 3563 | |
| 3564 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3565 const auto* test = kTests + ii; | |
| 3566 if (!ValidationOf(Expression(test->expression)) | |
| 3567 ->SucceedsWithExactType(test->expected_type)) { | |
| 3568 std::cerr << "Test:\n" << test->expression; | |
| 3569 CHECK(false); | |
| 3570 } | |
| 3571 } | |
| 3572 } | |
| 3573 | |
| 3574 TEST(ValidateIdentifier) { | |
| 3575 const struct { | |
| 3576 const char* expression; | |
| 3577 iw::AsmType* expected_type; | |
| 3578 } kTests[] = {{"afixnum", iw::AsmType::FixNum()}, | |
| 3579 {"adouble", iw::AsmType::Double()}, | |
| 3580 {"afloat", iw::AsmType::Float()}, | |
| 3581 {"anextern", iw::AsmType::Extern()}, | |
| 3582 {"avoid", iw::AsmType::Void()}}; | |
| 3583 | |
| 3584 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3585 const auto* test = kTests + ii; | |
| 3586 if (!ValidationOf(Expression(test->expression)) | |
| 3587 ->WithLocal(DynamicGlobal(test->expression), test->expected_type) | |
| 3588 ->WithGlobal(DynamicGlobal(test->expression), | |
| 3589 iw::AsmType::Floatish()) | |
| 3590 ->SucceedsWithExactType(test->expected_type)) { | |
| 3591 std::cerr << "Test (local identifiers):\n" << test->expression; | |
| 3592 CHECK(false); | |
| 3593 } | |
| 3594 } | |
| 3595 | |
| 3596 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3597 const auto* test = kTests + ii; | |
| 3598 if (!ValidationOf(Expression(test->expression)) | |
| 3599 ->WithGlobal(DynamicGlobal(test->expression), test->expected_type) | |
| 3600 ->SucceedsWithExactType(test->expected_type)) { | |
| 3601 std::cerr << "Test (global identifiers):\n" << test->expression; | |
| 3602 CHECK(false); | |
| 3603 } | |
| 3604 } | |
| 3605 } | |
| 3606 | |
| 3607 TEST(ValidateCallExpression) { | |
| 3608 auto v2f = [](Zone* zone) -> iw::AsmType* { | |
| 3609 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Float()); | |
| 3610 return ret; | |
| 3611 }; | |
| 3612 | |
| 3613 const struct { | |
| 3614 const char* expression; | |
| 3615 } kTests[] = { | |
| 3616 {"a_float_function()"}, | |
| 3617 {"fround(0)"}, | |
| 3618 {"slocal"}, | |
| 3619 {"ulocal"}, | |
| 3620 {"dqlocal"}, | |
| 3621 {"fishlocal"}, | |
| 3622 }; | |
| 3623 | |
| 3624 char full_test[200]; | |
| 3625 static const size_t kFullTestSize = arraysize(full_test); | |
| 3626 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3627 const auto* test = kTests + ii; | |
| 3628 CHECK(v8::base::OS::SNPrintF(full_test, kFullTestSize, "fround(%s)", | |
| 3629 test->expression) < kFullTestSize); | |
| 3630 if (!ValidationOf(Expression(full_test)) | |
| 3631 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
| 3632 ->WithGlobal(DynamicGlobal("a_float_function"), v2f) | |
| 3633 ->WithLocal(DynamicGlobal("slocal"), iw::AsmType::Signed()) | |
| 3634 ->WithLocal(DynamicGlobal("ulocal"), iw::AsmType::Unsigned()) | |
| 3635 ->WithLocal(DynamicGlobal("dqlocal"), iw::AsmType::DoubleQ()) | |
| 3636 ->WithLocal(DynamicGlobal("fishlocal"), iw::AsmType::Floatish()) | |
| 3637 ->SucceedsWithExactType(iw::AsmType::Float())) { | |
| 3638 std::cerr << "Test:\n" << full_test; | |
| 3639 CHECK(false); | |
| 3640 } | |
| 3641 } | |
| 3642 | |
| 3643 const struct { | |
| 3644 const char* expression; | |
| 3645 const char* error_message; | |
| 3646 } kFailureTests[] = { | |
| 3647 {"vlocal", "Invalid argument type to fround"}, | |
| 3648 {"ilocal", "Invalid argument type to fround"}, | |
| 3649 {"a_double_function()", "Function invocation does not match"}, | |
| 3650 }; | |
| 3651 | |
| 3652 auto v2d = [](Zone* zone) -> iw::AsmType* { | |
| 3653 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Double()); | |
| 3654 return ret; | |
| 3655 }; | |
| 3656 | |
| 3657 for (size_t ii = 0; ii < arraysize(kFailureTests); ++ii) { | |
| 3658 const auto* test = kFailureTests + ii; | |
| 3659 CHECK(v8::base::OS::SNPrintF(full_test, kFullTestSize, "fround(%s)", | |
| 3660 test->expression) < kFullTestSize); | |
| 3661 if (!ValidationOf(Expression(full_test)) | |
| 3662 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
| 3663 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int()) | |
| 3664 ->WithLocal(DynamicGlobal("vlocal"), iw::AsmType::Void()) | |
| 3665 ->WithGlobal(DynamicGlobal("a_double_function"), v2d) | |
| 3666 ->FailsWithMessage(test->error_message)) { | |
| 3667 std::cerr << "Test:\n" << full_test; | |
| 3668 CHECK(false); | |
| 3669 } | |
| 3670 } | |
| 3671 } | |
| 3672 | |
| 3673 TEST(ValidateMemberExpression) { | |
| 3674 const struct { | |
| 3675 const char* expression; | |
| 3676 iw::AsmType* load_type; | |
| 3677 } kTests[] = { | |
| 3678 {"I8[iish]", iw::AsmType::Intish()}, // leniency. | |
|
bradn
2016/07/11 17:55:33
Not clear what you mean?
John
2016/07/12 21:13:15
Done.
| |
| 3679 {"I8[iish >> 0]", iw::AsmType::Intish()}, | |
| 3680 {"I8[0]", iw::AsmType::Intish()}, | |
| 3681 {"I8[2147483648]", iw::AsmType::Intish()}, | |
| 3682 {"U8[iish >> 0]", iw::AsmType::Intish()}, | |
| 3683 {"U8[0]", iw::AsmType::Intish()}, | |
| 3684 {"U8[2147483648]", iw::AsmType::Intish()}, | |
| 3685 {"I16[iish >> 1]", iw::AsmType::Intish()}, | |
| 3686 {"I16[0]", iw::AsmType::Intish()}, | |
| 3687 {"I16[2147483648]", iw::AsmType::Intish()}, // bug: must be "shifted." | |
|
bradn
2016/07/11 17:55:33
??
John
2016/07/12 21:13:15
Done.
| |
| 3688 {"U16[iish >> 1]", iw::AsmType::Intish()}, | |
| 3689 {"U16[0]", iw::AsmType::Intish()}, | |
| 3690 {"U16[2147483648]", iw::AsmType::Intish()}, // bug: must be "shifted." | |
| 3691 {"I32[iish >> 2]", iw::AsmType::Intish()}, | |
| 3692 {"I32[0]", iw::AsmType::Intish()}, | |
| 3693 {"I32[2147483648]", iw::AsmType::Intish()}, // bug: must be "shifted." | |
| 3694 {"U32[iish >> 2]", iw::AsmType::Intish()}, | |
| 3695 {"U32[0]", iw::AsmType::Intish()}, | |
| 3696 {"U32[2147483648]", iw::AsmType::Intish()}, // bug: must be "shifted." | |
| 3697 {"F32[iish >> 2]", iw::AsmType::FloatQ()}, | |
| 3698 {"F32[0]", iw::AsmType::FloatQ()}, | |
| 3699 {"F32[2147483648]", iw::AsmType::FloatQ()}, // bug: must be "shifted." | |
| 3700 {"F64[iish >> 3]", iw::AsmType::DoubleQ()}, | |
| 3701 {"F64[0]", iw::AsmType::DoubleQ()}, | |
| 3702 {"F64[2147483648]", iw::AsmType::DoubleQ()}, // bug: must be "shifted." | |
| 3703 }; | |
| 3704 | |
| 3705 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3706 const auto* test = kTests + ii; | |
| 3707 if (!ValidationOf(Expression(test->expression)) | |
| 3708 ->WithGlobal(DynamicGlobal("I8"), iw::AsmType::Int8Array()) | |
| 3709 ->WithGlobal(DynamicGlobal("U8"), iw::AsmType::Uint8Array()) | |
| 3710 ->WithGlobal(DynamicGlobal("I16"), iw::AsmType::Int16Array()) | |
| 3711 ->WithGlobal(DynamicGlobal("U16"), iw::AsmType::Uint16Array()) | |
| 3712 ->WithGlobal(DynamicGlobal("I32"), iw::AsmType::Int32Array()) | |
| 3713 ->WithGlobal(DynamicGlobal("U32"), iw::AsmType::Uint32Array()) | |
| 3714 ->WithGlobal(DynamicGlobal("F32"), iw::AsmType::Float32Array()) | |
| 3715 ->WithGlobal(DynamicGlobal("F64"), iw::AsmType::Float64Array()) | |
| 3716 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish()) | |
| 3717 ->SucceedsWithExactType(test->load_type)) { | |
| 3718 std::cerr << "Test:\n" << test->expression; | |
| 3719 CHECK(false); | |
| 3720 } | |
| 3721 } | |
| 3722 } | |
| 3723 | |
| 3724 TEST(ValidateAssignmentExpression) { | |
| 3725 const struct { | |
| 3726 const char* expression; | |
| 3727 iw::AsmType* load_type; | |
| 3728 } kTests[] = { | |
| 3729 // ----------------------------------------------------------------------- | |
| 3730 // Array assignments. | |
| 3731 // Storing signed to int heap view. | |
| 3732 {"I8[1024] = -1024", iw::AsmType::Signed()}, // leniency. | |
| 3733 {"I8[1024 >> 0] = -1024", iw::AsmType::Signed()}, | |
| 3734 {"I8[0] = -1024", iw::AsmType::Signed()}, | |
| 3735 {"I8[2147483648] = -1024", iw::AsmType::Signed()}, | |
| 3736 {"U8[1024 >> 0] = -1024", iw::AsmType::Signed()}, | |
| 3737 {"U8[0] = -1024", iw::AsmType::Signed()}, | |
| 3738 {"U8[2147483648] = -1024", iw::AsmType::Signed()}, | |
| 3739 {"I16[1024 >> 1] = -1024", iw::AsmType::Signed()}, | |
| 3740 {"I16[0] = -1024", iw::AsmType::Signed()}, | |
| 3741 {"I16[2147483648] = -1024", iw::AsmType::Signed()}, // bug: !"shifted." | |
| 3742 {"U16[1024 >> 1] = -1024", iw::AsmType::Signed()}, | |
| 3743 {"U16[0] = -1024", iw::AsmType::Signed()}, | |
| 3744 {"U16[2147483648] = -1024", iw::AsmType::Signed()}, // bug: !"shifted." | |
| 3745 {"I32[1024 >> 2] = -1024", iw::AsmType::Signed()}, | |
| 3746 {"I32[0] = -1024", iw::AsmType::Signed()}, | |
| 3747 {"I32[2147483648] = -1024", iw::AsmType::Signed()}, // bug: !"shifted." | |
| 3748 {"U32[1024 >> 2] = -1024", iw::AsmType::Signed()}, | |
| 3749 {"U32[0] = -1024", iw::AsmType::Signed()}, | |
| 3750 {"U32[2147483648] = -1024", iw::AsmType::Signed()}, // bug: !"shifted." | |
| 3751 // Sroting fixnum to int heap view. | |
| 3752 {"I8[1024] = 1024", iw::AsmType::FixNum()}, // leniency. | |
| 3753 {"I8[1024 >> 0] = 1024", iw::AsmType::FixNum()}, | |
| 3754 {"I8[0] = 1024", iw::AsmType::FixNum()}, | |
| 3755 {"I8[2147483648] = 1024", iw::AsmType::FixNum()}, | |
| 3756 {"U8[1024 >> 0] = 1024", iw::AsmType::FixNum()}, | |
| 3757 {"U8[0] = 1024", iw::AsmType::FixNum()}, | |
| 3758 {"U8[2147483648] = 1024", iw::AsmType::FixNum()}, | |
| 3759 {"I16[1024 >> 1] = 1024", iw::AsmType::FixNum()}, | |
| 3760 {"I16[0] = 1024", iw::AsmType::FixNum()}, | |
| 3761 {"I16[2147483648] = 1024", iw::AsmType::FixNum()}, // bug: not "shifted." | |
| 3762 {"U16[1024 >> 1] = 1024", iw::AsmType::FixNum()}, | |
| 3763 {"U16[0] = 1024", iw::AsmType::FixNum()}, | |
| 3764 {"U16[2147483648] = 1024", iw::AsmType::FixNum()}, // bug: not "shifted." | |
| 3765 {"I32[1024 >> 2] = 1024", iw::AsmType::FixNum()}, | |
| 3766 {"I32[0] = 1024", iw::AsmType::FixNum()}, | |
| 3767 {"I32[2147483648] = 1024", iw::AsmType::FixNum()}, // bug: not "shifted." | |
| 3768 {"U32[1024 >> 2] = 1024", iw::AsmType::FixNum()}, | |
| 3769 {"U32[0] = 1024", iw::AsmType::FixNum()}, | |
| 3770 {"U32[2147483648] = 1024", iw::AsmType::FixNum()}, // bug: not "shifted." | |
| 3771 // Storing int to int heap view. | |
| 3772 {"I8[ilocal] = ilocal", iw::AsmType::Int()}, // leniency. | |
| 3773 {"I8[ilocal >> 0] = ilocal", iw::AsmType::Int()}, | |
| 3774 {"I8[0] = ilocal", iw::AsmType::Int()}, | |
| 3775 {"I8[2147483648] = ilocal", iw::AsmType::Int()}, | |
| 3776 {"U8[ilocal >> 0] = ilocal", iw::AsmType::Int()}, | |
| 3777 {"U8[0] = ilocal", iw::AsmType::Int()}, | |
| 3778 {"U8[2147483648] = ilocal", iw::AsmType::Int()}, | |
| 3779 {"I16[ilocal >> 1] = ilocal", iw::AsmType::Int()}, | |
| 3780 {"I16[0] = ilocal", iw::AsmType::Int()}, | |
| 3781 {"I16[2147483648] = ilocal", iw::AsmType::Int()}, // bug: not "shifted." | |
| 3782 {"U16[ilocal >> 1] = ilocal", iw::AsmType::Int()}, | |
| 3783 {"U16[0] = ilocal", iw::AsmType::Int()}, | |
| 3784 {"U16[2147483648] = ilocal", iw::AsmType::Int()}, // bug: not "shifted." | |
| 3785 {"I32[ilocal >> 2] = ilocal", iw::AsmType::Int()}, | |
| 3786 {"I32[0] = ilocal", iw::AsmType::Int()}, | |
| 3787 {"I32[2147483648] = ilocal", iw::AsmType::Int()}, // bug: not "shifted." | |
| 3788 {"U32[ilocal >> 2] = ilocal", iw::AsmType::Int()}, | |
| 3789 {"U32[0] = ilocal", iw::AsmType::Int()}, | |
| 3790 {"U32[2147483648] = ilocal", iw::AsmType::Int()}, // bug: not "shifted." | |
| 3791 // Storing intish to int heap view. | |
| 3792 {"I8[iish] = iish", iw::AsmType::Intish()}, // leniency. | |
| 3793 {"I8[iish >> 0] = iish", iw::AsmType::Intish()}, | |
| 3794 {"I8[0] = iish", iw::AsmType::Intish()}, | |
| 3795 {"I8[2147483648] = iish", iw::AsmType::Intish()}, | |
| 3796 {"U8[iish >> 0] = iish", iw::AsmType::Intish()}, | |
| 3797 {"U8[0] = iish", iw::AsmType::Intish()}, | |
| 3798 {"U8[2147483648] = iish", iw::AsmType::Intish()}, | |
| 3799 {"I16[iish >> 1] = iish", iw::AsmType::Intish()}, | |
| 3800 {"I16[0] = iish", iw::AsmType::Intish()}, | |
| 3801 {"I16[2147483648] = iish", iw::AsmType::Intish()}, // bug: not "shifted." | |
| 3802 {"U16[iish >> 1] = iish", iw::AsmType::Intish()}, | |
| 3803 {"U16[0] = iish", iw::AsmType::Intish()}, | |
| 3804 {"U16[2147483648] = iish", iw::AsmType::Intish()}, // bug: not "shifted." | |
| 3805 {"I32[iish >> 2] = iish", iw::AsmType::Intish()}, | |
| 3806 {"I32[0] = iish", iw::AsmType::Intish()}, | |
| 3807 {"I32[2147483648] = iish", iw::AsmType::Intish()}, // bug: not "shifted." | |
| 3808 {"U32[iish >> 2] = iish", iw::AsmType::Intish()}, | |
| 3809 {"U32[0] = iish", iw::AsmType::Intish()}, | |
| 3810 {"U32[2147483648] = iish", iw::AsmType::Intish()}, // bug: not "shifted." | |
| 3811 // Storing floatish to f32 heap view. | |
| 3812 {"F32[iish >> 2] = fish", iw::AsmType::Floatish()}, | |
| 3813 {"F32[0] = fish", iw::AsmType::Floatish()}, | |
| 3814 {"F32[2147483648] = fish ", iw::AsmType::Floatish()}, // bug: !"shifted." | |
| 3815 // Storing double? to f32 heap view. | |
| 3816 {"F32[iish >> 2] = dq", iw::AsmType::DoubleQ()}, | |
| 3817 {"F32[0] = dq", iw::AsmType::DoubleQ()}, | |
| 3818 {"F32[2147483648] = dq", iw::AsmType::DoubleQ()}, // bug: not "shifted." | |
| 3819 // Storing float? to f64 heap view. | |
| 3820 {"F64[iish >> 3] = fq", iw::AsmType::FloatQ()}, | |
| 3821 {"F64[0] = fq", iw::AsmType::FloatQ()}, | |
| 3822 {"F64[2147483648] = fq", iw::AsmType::FloatQ()}, // bug: not "shifted." | |
| 3823 // Storing double? to f64 heap view. | |
| 3824 {"F64[iish >> 3] = dq", iw::AsmType::DoubleQ()}, | |
| 3825 {"F64[0] = dq", iw::AsmType::DoubleQ()}, | |
| 3826 {"F64[2147483648] = dq", iw::AsmType::DoubleQ()}, // bug: not "shifted." | |
| 3827 // ----------------------------------------------------------------------- | |
| 3828 // Scalar assignments. | |
| 3829 {"ilocal = 1024", iw::AsmType::FixNum()}, | |
| 3830 {"ilocal = -1024", iw::AsmType::Signed()}, | |
| 3831 {"ilocal = 2147483648", iw::AsmType::Unsigned()}, | |
| 3832 {"ilocal = iglobal", iw::AsmType::Int()}, | |
| 3833 {"iglobal = 1024", iw::AsmType::FixNum()}, | |
| 3834 {"iglobal = -1024", iw::AsmType::Signed()}, | |
| 3835 {"iglobal = 2147483648", iw::AsmType::Unsigned()}, | |
| 3836 {"iglobal = ilocal", iw::AsmType::Int()}, | |
| 3837 {"dlocal = 0.0", iw::AsmType::Double()}, | |
| 3838 {"dlocal = +make_double()", iw::AsmType::Double()}, | |
| 3839 {"dglobal = 0.0", iw::AsmType::Double()}, | |
| 3840 {"dglobal = +make_double()", iw::AsmType::Double()}, | |
| 3841 {"flocal = fround(0)", iw::AsmType::Float()}, | |
| 3842 {"flocal = fround(make_float())", iw::AsmType::Float()}, | |
| 3843 {"fglobal = fround(0)", iw::AsmType::Float()}, | |
| 3844 {"fglobal = fround(make_float())", iw::AsmType::Float()}, | |
| 3845 }; | |
| 3846 | |
| 3847 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3848 const auto* test = kTests + ii; | |
| 3849 if (!ValidationOf(Expression(test->expression)) | |
| 3850 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
| 3851 ->WithLocal(DynamicGlobal("fq"), iw::AsmType::FloatQ()) | |
| 3852 ->WithLocal(DynamicGlobal("dq"), iw::AsmType::DoubleQ()) | |
| 3853 ->WithLocal(DynamicGlobal("fish"), iw::AsmType::Floatish()) | |
| 3854 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish()) | |
| 3855 ->WithGlobal(DynamicGlobal("iglobal"), iw::AsmType::Int()) | |
| 3856 ->WithGlobal(DynamicGlobal("dglobal"), iw::AsmType::Double()) | |
| 3857 ->WithGlobal(DynamicGlobal("fglobal"), iw::AsmType::Float()) | |
| 3858 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int()) | |
| 3859 ->WithLocal(DynamicGlobal("dlocal"), iw::AsmType::Double()) | |
| 3860 ->WithLocal(DynamicGlobal("flocal"), iw::AsmType::Float()) | |
| 3861 ->WithGlobal(DynamicGlobal("I8"), iw::AsmType::Int8Array()) | |
| 3862 ->WithGlobal(DynamicGlobal("U8"), iw::AsmType::Uint8Array()) | |
| 3863 ->WithGlobal(DynamicGlobal("I16"), iw::AsmType::Int16Array()) | |
| 3864 ->WithGlobal(DynamicGlobal("U16"), iw::AsmType::Uint16Array()) | |
| 3865 ->WithGlobal(DynamicGlobal("I32"), iw::AsmType::Int32Array()) | |
| 3866 ->WithGlobal(DynamicGlobal("U32"), iw::AsmType::Uint32Array()) | |
| 3867 ->WithGlobal(DynamicGlobal("F32"), iw::AsmType::Float32Array()) | |
| 3868 ->WithGlobal(DynamicGlobal("F64"), iw::AsmType::Float64Array()) | |
| 3869 ->SucceedsWithExactType(test->load_type)) { | |
| 3870 std::cerr << "Test:\n" << test->expression; | |
| 3871 CHECK(false); | |
| 3872 } | |
| 3873 } | |
| 3874 } | |
| 3875 | |
| 3876 TEST(ValidateUnaryExpression) { | |
| 3877 auto v2d = [](Zone* zone) -> iw::AsmType* { | |
| 3878 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Double()); | |
| 3879 return ret; | |
| 3880 }; | |
| 3881 | |
| 3882 const struct { | |
| 3883 const char* expression; | |
| 3884 iw::AsmType* load_type; | |
| 3885 } kTests[] = { | |
| 3886 {"-2147483648", iw::AsmType::Signed()}, | |
| 3887 {"-1024", iw::AsmType::Signed()}, | |
| 3888 {"-1", iw::AsmType::Signed()}, | |
| 3889 {"-2147483648.0", iw::AsmType::Double()}, | |
| 3890 {"+make_double()", iw::AsmType::Double()}, | |
| 3891 {"+dbl()", iw::AsmType::Double()}, | |
| 3892 {"make_double() * 1.0", iw::AsmType::Double()}, // Violation. | |
| 3893 {"~~fq", iw::AsmType::Signed()}, | |
| 3894 {"~~dglobal", iw::AsmType::Signed()}, | |
| 3895 {"+slocal", iw::AsmType::Double()}, | |
| 3896 {"slocal * 1.0", iw::AsmType::Double()}, // Violation. | |
| 3897 {"+ulocal", iw::AsmType::Double()}, | |
| 3898 {"ulocal * 1.0", iw::AsmType::Double()}, // Violation. | |
| 3899 {"+dq", iw::AsmType::Double()}, | |
| 3900 {"dq * 1.0", iw::AsmType::Double()}, // Violation. | |
| 3901 {"+fq", iw::AsmType::Double()}, | |
| 3902 {"fq * 1.0", iw::AsmType::Double()}, // Violation. | |
| 3903 {"-ilocal", iw::AsmType::Intish()}, | |
| 3904 {"ilocal * -1", iw::AsmType::Intish()}, // Violation. | |
| 3905 {"-dq", iw::AsmType::Double()}, | |
| 3906 {"dq * -1", iw::AsmType::Double()}, // Violation. | |
| 3907 {"-fq", iw::AsmType::Floatish()}, | |
| 3908 {"fq * -1", iw::AsmType::Floatish()}, // Violation. | |
| 3909 {"~iish", iw::AsmType::Signed()}, | |
| 3910 {"iish ^ -1", iw::AsmType::Signed()}, // Violation, but OK. | |
| 3911 {"!ilocal", iw::AsmType::Int()}, | |
| 3912 }; | |
| 3913 | |
| 3914 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3915 const auto* test = kTests + ii; | |
| 3916 if (!ValidationOf(Expression(test->expression)) | |
| 3917 ->WithLocal(DynamicGlobal("fq"), iw::AsmType::FloatQ()) | |
| 3918 ->WithLocal(DynamicGlobal("dq"), iw::AsmType::DoubleQ()) | |
| 3919 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish()) | |
| 3920 ->WithLocal(DynamicGlobal("slocal"), iw::AsmType::Signed()) | |
| 3921 ->WithLocal(DynamicGlobal("ulocal"), iw::AsmType::Unsigned()) | |
| 3922 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int()) | |
| 3923 ->WithGlobal(DynamicGlobal("dglobal"), iw::AsmType::Double()) | |
| 3924 ->WithGlobal(DynamicGlobal("dbl"), v2d) | |
| 3925 ->SucceedsWithExactType(test->load_type)) { | |
| 3926 std::cerr << "Test:\n" << test->expression; | |
| 3927 CHECK(false); | |
| 3928 } | |
| 3929 } | |
| 3930 } | |
| 3931 | |
| 3932 TEST(ValidateMultiplicativeExpression) { | |
| 3933 const struct { | |
| 3934 const char* expression; | |
| 3935 iw::AsmType* load_type; | |
| 3936 } kTests[] = { | |
| 3937 {"dq * dq", iw::AsmType::Double()}, | |
| 3938 {"fq * fq", iw::AsmType::Floatish()}, | |
| 3939 {"slocal / slocal", iw::AsmType::Intish()}, | |
| 3940 {"ulocal / ulocal", iw::AsmType::Intish()}, | |
| 3941 {"dq / dq", iw::AsmType::Double()}, | |
| 3942 {"fq / fq", iw::AsmType::Floatish()}, | |
| 3943 {"slocal % slocal", iw::AsmType::Intish()}, | |
| 3944 {"ulocal % ulocal", iw::AsmType::Intish()}, | |
| 3945 {"dq % dq", iw::AsmType::Double()}, | |
| 3946 {"-1048575 * ilocal", iw::AsmType::Intish()}, | |
| 3947 {"ilocal * -1048575", iw::AsmType::Intish()}, | |
| 3948 {"1048575 * ilocal", iw::AsmType::Intish()}, | |
| 3949 {"ilocal * 1048575", iw::AsmType::Intish()}, | |
| 3950 }; | |
| 3951 | |
| 3952 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3953 const auto* test = kTests + ii; | |
| 3954 if (!ValidationOf(Expression(test->expression)) | |
| 3955 ->WithLocal(DynamicGlobal("fq"), iw::AsmType::FloatQ()) | |
| 3956 ->WithLocal(DynamicGlobal("dq"), iw::AsmType::DoubleQ()) | |
| 3957 ->WithLocal(DynamicGlobal("slocal"), iw::AsmType::Signed()) | |
| 3958 ->WithLocal(DynamicGlobal("ulocal"), iw::AsmType::Unsigned()) | |
| 3959 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int()) | |
| 3960 ->WithGlobal(DynamicGlobal("dglobal"), iw::AsmType::Double()) | |
| 3961 ->SucceedsWithExactType(test->load_type)) { | |
| 3962 std::cerr << "Test:\n" << test->expression; | |
| 3963 CHECK(false); | |
| 3964 } | |
| 3965 } | |
| 3966 } | |
| 3967 | |
| 3968 TEST(ValidateAdditiveExpression) { | |
| 3969 const struct { | |
| 3970 const char* expression; | |
| 3971 iw::AsmType* load_type; | |
| 3972 } kTests[] = { | |
| 3973 {"dlocal + dlocal", iw::AsmType::Double()}, | |
| 3974 {"fq + fq", iw::AsmType::Floatish()}, | |
| 3975 {"dq - dq", iw::AsmType::Double()}, | |
| 3976 {"fq - fq", iw::AsmType::Floatish()}, | |
| 3977 {"ilocal + 1", iw::AsmType::Intish()}, | |
| 3978 {"ilocal - 1", iw::AsmType::Intish()}, | |
| 3979 {"slocal + ilocal + 1", iw::AsmType::Intish()}, | |
| 3980 {"slocal - ilocal + 1", iw::AsmType::Intish()}, | |
| 3981 {"ulocal + ilocal + 1", iw::AsmType::Intish()}, | |
| 3982 {"ulocal - ilocal + 1", iw::AsmType::Intish()}, | |
| 3983 {"ulocal + slocal + ilocal + 1", iw::AsmType::Intish()}, | |
| 3984 {"ulocal + slocal - ilocal + 1", iw::AsmType::Intish()}, | |
| 3985 {"ulocal - slocal + ilocal + 1", iw::AsmType::Intish()}, | |
| 3986 {"ulocal - slocal - ilocal + 1", iw::AsmType::Intish()}, | |
| 3987 {"1 + 1", iw::AsmType::FixNum()}, // Violation: intish. | |
| 3988 }; | |
| 3989 | |
| 3990 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 3991 const auto* test = kTests + ii; | |
| 3992 if (!ValidationOf(Expression(test->expression)) | |
| 3993 ->WithLocal(DynamicGlobal("fq"), iw::AsmType::FloatQ()) | |
| 3994 ->WithLocal(DynamicGlobal("dq"), iw::AsmType::DoubleQ()) | |
| 3995 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish()) | |
| 3996 ->WithLocal(DynamicGlobal("dlocal"), iw::AsmType::Double()) | |
| 3997 ->WithLocal(DynamicGlobal("slocal"), iw::AsmType::Signed()) | |
| 3998 ->WithLocal(DynamicGlobal("ulocal"), iw::AsmType::Unsigned()) | |
| 3999 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int()) | |
| 4000 ->SucceedsWithExactType(test->load_type)) { | |
| 4001 std::cerr << "Test:\n" << test->expression; | |
| 4002 CHECK(false); | |
| 4003 } | |
| 4004 } | |
| 4005 } | |
| 4006 | |
| 4007 TEST(ValidateShiftExpression) { | |
| 4008 const struct { | |
| 4009 const char* expression; | |
| 4010 iw::AsmType* load_type; | |
| 4011 } kTests[] = { | |
| 4012 {"iish << iish", iw::AsmType::Signed()}, | |
| 4013 {"iish >> iish", iw::AsmType::Signed()}, | |
| 4014 {"iish >>> iish", iw::AsmType::Unsigned()}, | |
| 4015 {"1 << 0", iw::AsmType::FixNum()}, // Violation: signed. | |
| 4016 {"1 >> 0", iw::AsmType::FixNum()}, // Violation: signed. | |
| 4017 {"4294967295 >>> 0", iw::AsmType::Unsigned()}, | |
| 4018 {"-1 >>> 0", iw::AsmType::Unsigned()}, | |
| 4019 {"2147483647 >>> 0", iw::AsmType::FixNum()}, // Violation: unsigned. | |
| 4020 }; | |
| 4021 | |
| 4022 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 4023 const auto* test = kTests + ii; | |
| 4024 if (!ValidationOf(Expression(test->expression)) | |
| 4025 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish()) | |
| 4026 ->SucceedsWithExactType(test->load_type)) { | |
| 4027 std::cerr << "Test:\n" << test->expression; | |
| 4028 CHECK(false); | |
| 4029 } | |
| 4030 } | |
| 4031 } | |
| 4032 | |
| 4033 TEST(ValidateComparisonExpression) { | |
| 4034 const struct { | |
| 4035 const char* expression; | |
| 4036 iw::AsmType* load_type; | |
| 4037 } kTests[] = { | |
| 4038 // ----------------------------------------------------------------------- | |
| 4039 // Non const <op> Non const | |
| 4040 {"s0 == s1", iw::AsmType::Int()}, | |
| 4041 {"u0 == u1", iw::AsmType::Int()}, | |
| 4042 {"f0 == f1", iw::AsmType::Int()}, | |
| 4043 {"d0 == d1", iw::AsmType::Int()}, | |
| 4044 {"s0 != s1", iw::AsmType::Int()}, | |
| 4045 {"u0 != u1", iw::AsmType::Int()}, | |
| 4046 {"f0 != f1", iw::AsmType::Int()}, | |
| 4047 {"d0 != d1", iw::AsmType::Int()}, | |
| 4048 {"s0 < s1", iw::AsmType::Int()}, | |
| 4049 {"u0 < u1", iw::AsmType::Int()}, | |
| 4050 {"f0 < f1", iw::AsmType::Int()}, | |
| 4051 {"d0 < d1", iw::AsmType::Int()}, | |
| 4052 {"s0 <= s1", iw::AsmType::Int()}, | |
| 4053 {"u0 <= u1", iw::AsmType::Int()}, | |
| 4054 {"f0 <= f1", iw::AsmType::Int()}, | |
| 4055 {"d0 <= d1", iw::AsmType::Int()}, | |
| 4056 {"s0 > s1", iw::AsmType::Int()}, | |
| 4057 {"u0 > u1", iw::AsmType::Int()}, | |
| 4058 {"f0 > f1", iw::AsmType::Int()}, | |
| 4059 {"d0 > d1", iw::AsmType::Int()}, | |
| 4060 {"s0 >= s1", iw::AsmType::Int()}, | |
| 4061 {"u0 >= u1", iw::AsmType::Int()}, | |
| 4062 {"f0 >= f1", iw::AsmType::Int()}, | |
| 4063 {"d0 >= d1", iw::AsmType::Int()}, | |
| 4064 // ----------------------------------------------------------------------- | |
| 4065 // Non const <op> Const | |
| 4066 {"s0 == -1025", iw::AsmType::Int()}, | |
| 4067 {"u0 == 123456789", iw::AsmType::Int()}, | |
| 4068 {"f0 == fround(123456.78)", iw::AsmType::Int()}, | |
| 4069 {"d0 == 9876543.201", iw::AsmType::Int()}, | |
| 4070 {"s0 != -1025", iw::AsmType::Int()}, | |
| 4071 {"u0 != 123456789", iw::AsmType::Int()}, | |
| 4072 {"f0 != fround(123456.78)", iw::AsmType::Int()}, | |
| 4073 {"d0 != 9876543.201", iw::AsmType::Int()}, | |
| 4074 {"s0 < -1025", iw::AsmType::Int()}, | |
| 4075 {"u0 < 123456789", iw::AsmType::Int()}, | |
| 4076 {"f0 < fround(123456.78)", iw::AsmType::Int()}, | |
| 4077 {"d0 < 9876543.201", iw::AsmType::Int()}, | |
| 4078 {"s0 <= -1025", iw::AsmType::Int()}, | |
| 4079 {"u0 <= 123456789", iw::AsmType::Int()}, | |
| 4080 {"f0 <= fround(123456.78)", iw::AsmType::Int()}, | |
| 4081 {"d0 <= 9876543.201", iw::AsmType::Int()}, | |
| 4082 {"s0 > -1025", iw::AsmType::Int()}, | |
| 4083 {"u0 > 123456789", iw::AsmType::Int()}, | |
| 4084 {"f0 > fround(123456.78)", iw::AsmType::Int()}, | |
| 4085 {"d0 > 9876543.201", iw::AsmType::Int()}, | |
| 4086 {"s0 >= -1025", iw::AsmType::Int()}, | |
| 4087 {"u0 >= 123456789", iw::AsmType::Int()}, | |
| 4088 {"f0 >= fround(123456.78)", iw::AsmType::Int()}, | |
| 4089 {"d0 >= 9876543.201", iw::AsmType::Int()}, | |
| 4090 // ----------------------------------------------------------------------- | |
| 4091 // Const <op> Non const | |
| 4092 {"-1025 == s0", iw::AsmType::Int()}, | |
| 4093 {"123456789 == u0", iw::AsmType::Int()}, | |
| 4094 {"fround(123456.78) == f0", iw::AsmType::Int()}, | |
| 4095 {"9876543.201 == d0", iw::AsmType::Int()}, | |
| 4096 {"-1025 != s0", iw::AsmType::Int()}, | |
| 4097 {"123456789 != u0", iw::AsmType::Int()}, | |
| 4098 {"fround(123456.78) != f0", iw::AsmType::Int()}, | |
| 4099 {"9876543.201 != d0", iw::AsmType::Int()}, | |
| 4100 {"-1025 < s0", iw::AsmType::Int()}, | |
| 4101 {"123456789 < u0", iw::AsmType::Int()}, | |
| 4102 {"fround(123456.78) < f0", iw::AsmType::Int()}, | |
| 4103 {"9876543.201 < d0", iw::AsmType::Int()}, | |
| 4104 {"-1025 <= s0", iw::AsmType::Int()}, | |
| 4105 {"123456789 <= u0", iw::AsmType::Int()}, | |
| 4106 {"fround(123456.78) <= f0", iw::AsmType::Int()}, | |
| 4107 {"9876543.201 <= d0", iw::AsmType::Int()}, | |
| 4108 {"-1025 > s0", iw::AsmType::Int()}, | |
| 4109 {"123456789 > u0", iw::AsmType::Int()}, | |
| 4110 {"fround(123456.78) > f0", iw::AsmType::Int()}, | |
| 4111 {"9876543.201 > d0", iw::AsmType::Int()}, | |
| 4112 {"-1025 >= s0", iw::AsmType::Int()}, | |
| 4113 {"123456789 >= u0", iw::AsmType::Int()}, | |
| 4114 {"fround(123456.78) >= f0", iw::AsmType::Int()}, | |
| 4115 {"9876543.201 >= d0", iw::AsmType::Int()}, | |
| 4116 // TODO(jpp): maybe add Const <op> Const. | |
| 4117 }; | |
| 4118 | |
| 4119 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 4120 const auto* test = kTests + ii; | |
| 4121 if (!ValidationOf(Expression(test->expression)) | |
| 4122 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
| 4123 ->WithLocal(DynamicGlobal("u0"), iw::AsmType::Unsigned()) | |
| 4124 ->WithLocal(DynamicGlobal("u1"), iw::AsmType::Unsigned()) | |
| 4125 ->WithLocal(DynamicGlobal("s0"), iw::AsmType::Signed()) | |
| 4126 ->WithLocal(DynamicGlobal("s1"), iw::AsmType::Signed()) | |
| 4127 ->WithLocal(DynamicGlobal("f0"), iw::AsmType::Float()) | |
| 4128 ->WithLocal(DynamicGlobal("f1"), iw::AsmType::Float()) | |
| 4129 ->WithLocal(DynamicGlobal("d0"), iw::AsmType::Double()) | |
| 4130 ->WithLocal(DynamicGlobal("d1"), iw::AsmType::Double()) | |
| 4131 ->SucceedsWithExactType(test->load_type)) { | |
| 4132 std::cerr << "Test:\n" << test->expression; | |
| 4133 CHECK(false); | |
| 4134 } | |
| 4135 } | |
| 4136 } | |
| 4137 | |
| 4138 TEST(ValidateBitwiseExpression) { | |
| 4139 auto v2s = [](Zone* zone) -> iw::AsmType* { | |
| 4140 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
| 4141 return ret; | |
| 4142 }; | |
| 4143 | |
| 4144 const struct { | |
| 4145 const char* expression; | |
| 4146 iw::AsmType* load_type; | |
| 4147 } kTests[] = { | |
| 4148 {"iish0 & iish1", iw::AsmType::Signed()}, | |
| 4149 {"iish0 | iish1", iw::AsmType::Signed()}, | |
| 4150 {"iish0 ^ iish1", iw::AsmType::Signed()}, | |
| 4151 {"iish0 & -1", iw::AsmType::Signed()}, | |
| 4152 {"iish0 | -1", iw::AsmType::Signed()}, | |
| 4153 {"iish0 ^ -1", iw::AsmType::Signed()}, | |
| 4154 {"2147483648 & iish1", iw::AsmType::Signed()}, | |
| 4155 {"2147483648 | iish1", iw::AsmType::Signed()}, | |
| 4156 {"2147483648 ^ iish1", iw::AsmType::Signed()}, | |
| 4157 {"2147483648 & 0", iw::AsmType::FixNum()}, // Violation: signed. | |
| 4158 {"2147483648 | 0", iw::AsmType::Signed()}, | |
| 4159 {"2147483648 ^ 0", iw::AsmType::Signed()}, | |
| 4160 {"2134651 & 123", iw::AsmType::FixNum()}, // Violation: signed. | |
| 4161 {"2134651 | 123", iw::AsmType::FixNum()}, // Violation: signed. | |
| 4162 {"2134651 ^ 123", iw::AsmType::FixNum()}, // Violation: signed. | |
| 4163 {"make_signed()|0", iw::AsmType::Signed()}, | |
| 4164 {"signed()|0", iw::AsmType::Signed()}, | |
| 4165 }; | |
| 4166 | |
| 4167 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 4168 const auto* test = kTests + ii; | |
| 4169 if (!ValidationOf(Expression(test->expression)) | |
| 4170 ->WithLocal(DynamicGlobal("iish1"), iw::AsmType::Intish()) | |
| 4171 ->WithLocal(DynamicGlobal("iish0"), iw::AsmType::Intish()) | |
| 4172 ->WithGlobal(DynamicGlobal("signed"), v2s) | |
| 4173 ->SucceedsWithExactType(test->load_type)) { | |
| 4174 std::cerr << "Test:\n" << test->expression; | |
| 4175 CHECK(false); | |
| 4176 } | |
| 4177 } | |
| 4178 } | |
| 4179 | |
| 4180 TEST(ValidateConditionalExpression) { | |
| 4181 const struct { | |
| 4182 const char* expression; | |
| 4183 iw::AsmType* load_type; | |
| 4184 } kTests[] = { | |
| 4185 {"i0 ? i0 : i1", iw::AsmType::Int()}, | |
| 4186 {"i0 ? f0 : f1", iw::AsmType::Float()}, | |
| 4187 {"i0 ? d0 : d1", iw::AsmType::Double()}, | |
| 4188 {"0 ? -1 : 2147483648", iw::AsmType::Int()}, | |
| 4189 }; | |
| 4190 | |
| 4191 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 4192 const auto* test = kTests + ii; | |
| 4193 if (!ValidationOf(Expression(test->expression)) | |
| 4194 ->WithLocal(DynamicGlobal("i0"), iw::AsmType::Int()) | |
| 4195 ->WithLocal(DynamicGlobal("i1"), iw::AsmType::Int()) | |
| 4196 ->WithLocal(DynamicGlobal("f0"), iw::AsmType::Float()) | |
| 4197 ->WithLocal(DynamicGlobal("f1"), iw::AsmType::Float()) | |
| 4198 ->WithLocal(DynamicGlobal("d0"), iw::AsmType::Double()) | |
| 4199 ->WithLocal(DynamicGlobal("d1"), iw::AsmType::Double()) | |
| 4200 ->SucceedsWithExactType(test->load_type)) { | |
| 4201 std::cerr << "Test:\n" << test->expression; | |
| 4202 CHECK(false); | |
| 4203 } | |
| 4204 } | |
| 4205 } | |
| 4206 | |
| 4207 TEST(ValidateCall) { | |
| 4208 auto v2f = [](Zone* zone) -> iw::AsmType* { | |
| 4209 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Float()); | |
| 4210 return ret; | |
| 4211 }; | |
| 4212 | |
| 4213 // ifd2_ is a helper function that returns a lambda for creating a function | |
| 4214 // type that accepts an int, a float, and a double. ret_type_factory is a | |
| 4215 // pointer to an AsmType*() function, and (*ret_type_factory)() returns the | |
| 4216 // desired return type. For example, | |
| 4217 // | |
| 4218 // ifd2_(&iw::AsmType::Float) | |
| 4219 // | |
| 4220 // returns an AsmType representing an asm.j function with the following | |
| 4221 // signature: | |
| 4222 // | |
| 4223 // float(int, float, double) | |
| 4224 auto ifd2_ = [](iw::AsmType* ( | |
| 4225 *ret_type_factory)()) -> std::function<iw::AsmType*(Zone*)> { | |
| 4226 return [ret_type_factory](Zone* zone) -> iw::AsmType* { | |
| 4227 auto* ret = iw::AsmType::Function(zone, (*ret_type_factory)()); | |
| 4228 ret->AsFunctionType()->AddArgument(iw::AsmType::Int()); | |
| 4229 ret->AsFunctionType()->AddArgument(iw::AsmType::Float()); | |
| 4230 ret->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
| 4231 return ret; | |
| 4232 }; | |
| 4233 }; | |
| 4234 auto ifd2f = ifd2_(&iw::AsmType::Float); | |
| 4235 auto ifd2d = ifd2_(&iw::AsmType::Double); | |
| 4236 auto ifd2i = ifd2_(&iw::AsmType::Signed); | |
| 4237 | |
| 4238 // Just like ifd2_, but this one returns a type representing a function table. | |
| 4239 auto tbl_ifd2_ = [](size_t tbl_size, iw::AsmType* (*ret_type_factory)()) | |
| 4240 -> std::function<iw::AsmType*(Zone*)> { | |
| 4241 return [tbl_size, ret_type_factory](Zone* zone) -> iw::AsmType* { | |
| 4242 auto* signature = iw::AsmType::Function(zone, (*ret_type_factory)()); | |
| 4243 signature->AsFunctionType()->AddArgument(iw::AsmType::Int()); | |
| 4244 signature->AsFunctionType()->AddArgument(iw::AsmType::Float()); | |
| 4245 signature->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
| 4246 | |
| 4247 auto* ret = iw::AsmType::FunctionTableType(zone, tbl_size, signature); | |
| 4248 return ret; | |
| 4249 }; | |
| 4250 }; | |
| 4251 auto ifd2f_tbl = tbl_ifd2_(32, &iw::AsmType::Float); | |
| 4252 auto ifd2d_tbl = tbl_ifd2_(64, &iw::AsmType::Double); | |
| 4253 auto ifd2i_tbl = tbl_ifd2_(4096, &iw::AsmType::Signed); | |
| 4254 | |
| 4255 const struct { | |
| 4256 const char* expression; | |
| 4257 iw::AsmType* load_type; | |
| 4258 } kTests[] = { | |
| 4259 // ----------------------------------------------------------------------- | |
| 4260 // Functions. | |
| 4261 {"fround(v2f())", iw::AsmType::Float()}, | |
| 4262 {"fround(fish)", iw::AsmType::Float()}, | |
| 4263 {"fround(dq)", iw::AsmType::Float()}, | |
| 4264 {"fround(s)", iw::AsmType::Float()}, | |
| 4265 {"fround(u)", iw::AsmType::Float()}, | |
| 4266 {"ffi()|0", iw::AsmType::Signed()}, | |
| 4267 {"ffi(1.0)|0", iw::AsmType::Signed()}, | |
| 4268 {"ffi(1.0, 2.0)|0", iw::AsmType::Signed()}, | |
| 4269 {"ffi(1.0, 2.0, 3)|0", iw::AsmType::Signed()}, | |
| 4270 {"ffi(1.0, 2.0, 3, 4)|0", iw::AsmType::Signed()}, | |
| 4271 {"+ffi()", iw::AsmType::Double()}, | |
| 4272 {"+ffi(1.0)", iw::AsmType::Double()}, | |
| 4273 {"+ffi(1.0, 2.0)", iw::AsmType::Double()}, | |
| 4274 {"+ffi(1.0, 2.0, 3)", iw::AsmType::Double()}, | |
| 4275 {"+ffi(1.0, 2.0, 3, 4)", iw::AsmType::Double()}, | |
| 4276 {"fround(ifd2f(1, fround(1), 1.0))", iw::AsmType::Float()}, | |
| 4277 {"+ifd2d(1, fround(1), 1.0)", iw::AsmType::Double()}, | |
| 4278 {"ifd2i(1, fround(1), 1.0)|0", iw::AsmType::Signed()}, | |
| 4279 // ----------------------------------------------------------------------- | |
| 4280 // Function tables. | |
| 4281 {"fround(ifd2f_tbl[iish & 31](1, fround(1), 1.0))", iw::AsmType::Float()}, | |
| 4282 {"+ifd2d_tbl[iish & 63](1, fround(1), 1.0)", iw::AsmType::Double()}, | |
| 4283 {"ifd2i_tbl[iish & 4095](1, fround(1), 1.0)|0", iw::AsmType::Signed()}, | |
| 4284 }; | |
| 4285 | |
| 4286 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
| 4287 const auto* test = kTests + ii; | |
| 4288 if (!ValidationOf(Expression(test->expression)) | |
| 4289 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
| 4290 ->WithImport(DynamicGlobal("ffi"), iw::AsmTyper::kFFI) | |
| 4291 ->WithLocal(DynamicGlobal("fish"), iw::AsmType::Floatish()) | |
| 4292 ->WithLocal(DynamicGlobal("dq"), iw::AsmType::DoubleQ()) | |
| 4293 ->WithLocal(DynamicGlobal("s"), iw::AsmType::Signed()) | |
| 4294 ->WithLocal(DynamicGlobal("u"), iw::AsmType::Unsigned()) | |
| 4295 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish()) | |
| 4296 ->WithGlobal(DynamicGlobal("v2f"), v2f) | |
| 4297 ->WithGlobal(DynamicGlobal("ifd2f_tbl"), ifd2f_tbl) | |
| 4298 ->WithGlobal(DynamicGlobal("ifd2d_tbl"), ifd2d_tbl) | |
| 4299 ->WithGlobal(DynamicGlobal("ifd2i_tbl"), ifd2i_tbl) | |
| 4300 ->SucceedsWithExactType(test->load_type)) { | |
| 4301 std::cerr << "Test:\n" << test->expression; | |
| 4302 CHECK(false); | |
| 4303 } | |
| 4304 } | |
| 4305 } | |
| 4306 | |
| 4307 } // namespace | |
| OLD | NEW |