1fd4e5da5Sopenharmony_ci// Copyright (c) 2015-2016 The Khronos Group Inc. 2fd4e5da5Sopenharmony_ci// 3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License. 5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at 6fd4e5da5Sopenharmony_ci// 7fd4e5da5Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8fd4e5da5Sopenharmony_ci// 9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and 13fd4e5da5Sopenharmony_ci// limitations under the License. 14fd4e5da5Sopenharmony_ci 15fd4e5da5Sopenharmony_ci// Assembler tests for instructions in the "Control Flow" section of the 16fd4e5da5Sopenharmony_ci// SPIR-V spec. 17fd4e5da5Sopenharmony_ci 18fd4e5da5Sopenharmony_ci#include <sstream> 19fd4e5da5Sopenharmony_ci#include <string> 20fd4e5da5Sopenharmony_ci#include <tuple> 21fd4e5da5Sopenharmony_ci#include <vector> 22fd4e5da5Sopenharmony_ci 23fd4e5da5Sopenharmony_ci#include "gmock/gmock.h" 24fd4e5da5Sopenharmony_ci#include "test/test_fixture.h" 25fd4e5da5Sopenharmony_ci#include "test/unit_spirv.h" 26fd4e5da5Sopenharmony_ci 27fd4e5da5Sopenharmony_cinamespace spvtools { 28fd4e5da5Sopenharmony_cinamespace { 29fd4e5da5Sopenharmony_ci 30fd4e5da5Sopenharmony_ciusing spvtest::Concatenate; 31fd4e5da5Sopenharmony_ciusing spvtest::EnumCase; 32fd4e5da5Sopenharmony_ciusing spvtest::MakeInstruction; 33fd4e5da5Sopenharmony_ciusing spvtest::TextToBinaryTest; 34fd4e5da5Sopenharmony_ciusing ::testing::Combine; 35fd4e5da5Sopenharmony_ciusing ::testing::Eq; 36fd4e5da5Sopenharmony_ciusing ::testing::TestWithParam; 37fd4e5da5Sopenharmony_ciusing ::testing::Values; 38fd4e5da5Sopenharmony_ciusing ::testing::ValuesIn; 39fd4e5da5Sopenharmony_ci 40fd4e5da5Sopenharmony_ci// Test OpSelectionMerge 41fd4e5da5Sopenharmony_ci 42fd4e5da5Sopenharmony_ciusing OpSelectionMergeTest = spvtest::TextToBinaryTestBase< 43fd4e5da5Sopenharmony_ci TestWithParam<EnumCase<spv::SelectionControlMask>>>; 44fd4e5da5Sopenharmony_ci 45fd4e5da5Sopenharmony_ciTEST_P(OpSelectionMergeTest, AnySingleSelectionControlMask) { 46fd4e5da5Sopenharmony_ci const std::string input = "OpSelectionMerge %1 " + GetParam().name(); 47fd4e5da5Sopenharmony_ci EXPECT_THAT(CompiledInstructions(input), 48fd4e5da5Sopenharmony_ci Eq(MakeInstruction(spv::Op::OpSelectionMerge, 49fd4e5da5Sopenharmony_ci {1, uint32_t(GetParam().value())}))); 50fd4e5da5Sopenharmony_ci} 51fd4e5da5Sopenharmony_ci 52fd4e5da5Sopenharmony_ci// clang-format off 53fd4e5da5Sopenharmony_ci#define CASE(VALUE,NAME) { spv::SelectionControlMask::VALUE, NAME} 54fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(TextToBinarySelectionMerge, OpSelectionMergeTest, 55fd4e5da5Sopenharmony_ci ValuesIn(std::vector<EnumCase<spv::SelectionControlMask>>{ 56fd4e5da5Sopenharmony_ci CASE(MaskNone, "None"), 57fd4e5da5Sopenharmony_ci CASE(Flatten, "Flatten"), 58fd4e5da5Sopenharmony_ci CASE(DontFlatten, "DontFlatten"), 59fd4e5da5Sopenharmony_ci })); 60fd4e5da5Sopenharmony_ci#undef CASE 61fd4e5da5Sopenharmony_ci// clang-format on 62fd4e5da5Sopenharmony_ci 63fd4e5da5Sopenharmony_ciTEST_F(OpSelectionMergeTest, CombinedSelectionControlMask) { 64fd4e5da5Sopenharmony_ci const std::string input = "OpSelectionMerge %1 Flatten|DontFlatten"; 65fd4e5da5Sopenharmony_ci const uint32_t expected_mask = 66fd4e5da5Sopenharmony_ci uint32_t(spv::SelectionControlMask::Flatten | 67fd4e5da5Sopenharmony_ci spv::SelectionControlMask::DontFlatten); 68fd4e5da5Sopenharmony_ci EXPECT_THAT( 69fd4e5da5Sopenharmony_ci CompiledInstructions(input), 70fd4e5da5Sopenharmony_ci Eq(MakeInstruction(spv::Op::OpSelectionMerge, {1, expected_mask}))); 71fd4e5da5Sopenharmony_ci} 72fd4e5da5Sopenharmony_ci 73fd4e5da5Sopenharmony_ciTEST_F(OpSelectionMergeTest, WrongSelectionControl) { 74fd4e5da5Sopenharmony_ci // Case sensitive: "flatten" != "Flatten" and thus wrong. 75fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure("OpSelectionMerge %1 flatten|DontFlatten"), 76fd4e5da5Sopenharmony_ci Eq("Invalid selection control operand 'flatten|DontFlatten'.")); 77fd4e5da5Sopenharmony_ci} 78fd4e5da5Sopenharmony_ci 79fd4e5da5Sopenharmony_ci// Test OpLoopMerge 80fd4e5da5Sopenharmony_ci 81fd4e5da5Sopenharmony_ciusing OpLoopMergeTest = spvtest::TextToBinaryTestBase< 82fd4e5da5Sopenharmony_ci TestWithParam<std::tuple<spv_target_env, EnumCase<int>>>>; 83fd4e5da5Sopenharmony_ci 84fd4e5da5Sopenharmony_ciTEST_P(OpLoopMergeTest, AnySingleLoopControlMask) { 85fd4e5da5Sopenharmony_ci const auto ctrl = std::get<1>(GetParam()); 86fd4e5da5Sopenharmony_ci std::ostringstream input; 87fd4e5da5Sopenharmony_ci input << "OpLoopMerge %merge %continue " << ctrl.name(); 88fd4e5da5Sopenharmony_ci for (auto num : ctrl.operands()) input << " " << num; 89fd4e5da5Sopenharmony_ci EXPECT_THAT(CompiledInstructions(input.str(), std::get<0>(GetParam())), 90fd4e5da5Sopenharmony_ci Eq(MakeInstruction(spv::Op::OpLoopMerge, {1, 2, ctrl.value()}, 91fd4e5da5Sopenharmony_ci ctrl.operands()))); 92fd4e5da5Sopenharmony_ci} 93fd4e5da5Sopenharmony_ci 94fd4e5da5Sopenharmony_ci#define CASE(VALUE, NAME) \ 95fd4e5da5Sopenharmony_ci { int32_t(spv::LoopControlMask::VALUE), NAME } 96fd4e5da5Sopenharmony_ci#define CASE1(VALUE, NAME, PARM) \ 97fd4e5da5Sopenharmony_ci { \ 98fd4e5da5Sopenharmony_ci int32_t(spv::LoopControlMask::VALUE), NAME, { PARM } \ 99fd4e5da5Sopenharmony_ci } 100fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P( 101fd4e5da5Sopenharmony_ci TextToBinaryLoopMerge, OpLoopMergeTest, 102fd4e5da5Sopenharmony_ci Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), 103fd4e5da5Sopenharmony_ci ValuesIn(std::vector<EnumCase<int>>{ 104fd4e5da5Sopenharmony_ci // clang-format off 105fd4e5da5Sopenharmony_ci CASE(MaskNone, "None"), 106fd4e5da5Sopenharmony_ci CASE(Unroll, "Unroll"), 107fd4e5da5Sopenharmony_ci CASE(DontUnroll, "DontUnroll"), 108fd4e5da5Sopenharmony_ci // clang-format on 109fd4e5da5Sopenharmony_ci }))); 110fd4e5da5Sopenharmony_ci 111fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P( 112fd4e5da5Sopenharmony_ci TextToBinaryLoopMergeV11, OpLoopMergeTest, 113fd4e5da5Sopenharmony_ci Combine(Values(SPV_ENV_UNIVERSAL_1_1), 114fd4e5da5Sopenharmony_ci ValuesIn(std::vector<EnumCase<int>>{ 115fd4e5da5Sopenharmony_ci // clang-format off 116fd4e5da5Sopenharmony_ci CASE(DependencyInfinite, "DependencyInfinite"), 117fd4e5da5Sopenharmony_ci CASE1(DependencyLength, "DependencyLength", 234), 118fd4e5da5Sopenharmony_ci {int32_t(spv::LoopControlMask::Unroll|spv::LoopControlMask::DependencyLength), 119fd4e5da5Sopenharmony_ci "DependencyLength|Unroll", {33}}, 120fd4e5da5Sopenharmony_ci // clang-format on 121fd4e5da5Sopenharmony_ci }))); 122fd4e5da5Sopenharmony_ci#undef CASE 123fd4e5da5Sopenharmony_ci#undef CASE1 124fd4e5da5Sopenharmony_ci 125fd4e5da5Sopenharmony_ciTEST_F(OpLoopMergeTest, CombinedLoopControlMask) { 126fd4e5da5Sopenharmony_ci const std::string input = "OpLoopMerge %merge %continue Unroll|DontUnroll"; 127fd4e5da5Sopenharmony_ci const uint32_t expected_mask = 128fd4e5da5Sopenharmony_ci uint32_t(spv::LoopControlMask::Unroll | spv::LoopControlMask::DontUnroll); 129fd4e5da5Sopenharmony_ci EXPECT_THAT(CompiledInstructions(input), 130fd4e5da5Sopenharmony_ci Eq(MakeInstruction(spv::Op::OpLoopMerge, {1, 2, expected_mask}))); 131fd4e5da5Sopenharmony_ci} 132fd4e5da5Sopenharmony_ci 133fd4e5da5Sopenharmony_ciTEST_F(OpLoopMergeTest, WrongLoopControl) { 134fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure("OpLoopMerge %m %c none"), 135fd4e5da5Sopenharmony_ci Eq("Invalid loop control operand 'none'.")); 136fd4e5da5Sopenharmony_ci} 137fd4e5da5Sopenharmony_ci 138fd4e5da5Sopenharmony_ci// Test OpSwitch 139fd4e5da5Sopenharmony_ci 140fd4e5da5Sopenharmony_ciTEST_F(TextToBinaryTest, SwitchGoodZeroTargets) { 141fd4e5da5Sopenharmony_ci EXPECT_THAT(CompiledInstructions("OpSwitch %selector %default"), 142fd4e5da5Sopenharmony_ci Eq(MakeInstruction(spv::Op::OpSwitch, {1, 2}))); 143fd4e5da5Sopenharmony_ci} 144fd4e5da5Sopenharmony_ci 145fd4e5da5Sopenharmony_ciTEST_F(TextToBinaryTest, SwitchGoodOneTarget) { 146fd4e5da5Sopenharmony_ci EXPECT_THAT( 147fd4e5da5Sopenharmony_ci CompiledInstructions("%1 = OpTypeInt 32 0\n" 148fd4e5da5Sopenharmony_ci "%2 = OpConstant %1 52\n" 149fd4e5da5Sopenharmony_ci "OpSwitch %2 %default 12 %target0"), 150fd4e5da5Sopenharmony_ci Eq(Concatenate({MakeInstruction(spv::Op::OpTypeInt, {1, 32, 0}), 151fd4e5da5Sopenharmony_ci MakeInstruction(spv::Op::OpConstant, {1, 2, 52}), 152fd4e5da5Sopenharmony_ci MakeInstruction(spv::Op::OpSwitch, {2, 3, 12, 4})}))); 153fd4e5da5Sopenharmony_ci} 154fd4e5da5Sopenharmony_ci 155fd4e5da5Sopenharmony_ciTEST_F(TextToBinaryTest, SwitchGoodTwoTargets) { 156fd4e5da5Sopenharmony_ci EXPECT_THAT( 157fd4e5da5Sopenharmony_ci CompiledInstructions("%1 = OpTypeInt 32 0\n" 158fd4e5da5Sopenharmony_ci "%2 = OpConstant %1 52\n" 159fd4e5da5Sopenharmony_ci "OpSwitch %2 %default 12 %target0 42 %target1"), 160fd4e5da5Sopenharmony_ci Eq(Concatenate({ 161fd4e5da5Sopenharmony_ci MakeInstruction(spv::Op::OpTypeInt, {1, 32, 0}), 162fd4e5da5Sopenharmony_ci MakeInstruction(spv::Op::OpConstant, {1, 2, 52}), 163fd4e5da5Sopenharmony_ci MakeInstruction(spv::Op::OpSwitch, {2, 3, 12, 4, 42, 5}), 164fd4e5da5Sopenharmony_ci }))); 165fd4e5da5Sopenharmony_ci} 166fd4e5da5Sopenharmony_ci 167fd4e5da5Sopenharmony_ciTEST_F(TextToBinaryTest, SwitchBadMissingSelector) { 168fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure("OpSwitch"), 169fd4e5da5Sopenharmony_ci Eq("Expected operand for OpSwitch instruction, but found the end " 170fd4e5da5Sopenharmony_ci "of the stream.")); 171fd4e5da5Sopenharmony_ci} 172fd4e5da5Sopenharmony_ci 173fd4e5da5Sopenharmony_ciTEST_F(TextToBinaryTest, SwitchBadInvalidSelector) { 174fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure("OpSwitch 12"), 175fd4e5da5Sopenharmony_ci Eq("Expected id to start with %.")); 176fd4e5da5Sopenharmony_ci} 177fd4e5da5Sopenharmony_ci 178fd4e5da5Sopenharmony_ciTEST_F(TextToBinaryTest, SwitchBadMissingDefault) { 179fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure("OpSwitch %selector"), 180fd4e5da5Sopenharmony_ci Eq("Expected operand for OpSwitch instruction, but found the end " 181fd4e5da5Sopenharmony_ci "of the stream.")); 182fd4e5da5Sopenharmony_ci} 183fd4e5da5Sopenharmony_ci 184fd4e5da5Sopenharmony_ciTEST_F(TextToBinaryTest, SwitchBadInvalidDefault) { 185fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure("OpSwitch %selector 12"), 186fd4e5da5Sopenharmony_ci Eq("Expected id to start with %.")); 187fd4e5da5Sopenharmony_ci} 188fd4e5da5Sopenharmony_ci 189fd4e5da5Sopenharmony_ciTEST_F(TextToBinaryTest, SwitchBadInvalidLiteral) { 190fd4e5da5Sopenharmony_ci // The assembler recognizes "OpSwitch %selector %default" as a complete 191fd4e5da5Sopenharmony_ci // instruction. Then it tries to parse "%abc" as the start of a new 192fd4e5da5Sopenharmony_ci // instruction, but can't since it hits the end of stream. 193fd4e5da5Sopenharmony_ci const auto input = R"(%i32 = OpTypeInt 32 0 194fd4e5da5Sopenharmony_ci %selector = OpConstant %i32 42 195fd4e5da5Sopenharmony_ci OpSwitch %selector %default %abc)"; 196fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure(input), Eq("Expected '=', found end of stream.")); 197fd4e5da5Sopenharmony_ci} 198fd4e5da5Sopenharmony_ci 199fd4e5da5Sopenharmony_ciTEST_F(TextToBinaryTest, SwitchBadMissingTarget) { 200fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure("%1 = OpTypeInt 32 0\n" 201fd4e5da5Sopenharmony_ci "%2 = OpConstant %1 52\n" 202fd4e5da5Sopenharmony_ci "OpSwitch %2 %default 12"), 203fd4e5da5Sopenharmony_ci Eq("Expected operand for OpSwitch instruction, but found the end " 204fd4e5da5Sopenharmony_ci "of the stream.")); 205fd4e5da5Sopenharmony_ci} 206fd4e5da5Sopenharmony_ci 207fd4e5da5Sopenharmony_ci// A test case for an OpSwitch. 208fd4e5da5Sopenharmony_ci// It is also parameterized to test encodings OpConstant 209fd4e5da5Sopenharmony_ci// integer literals. This can capture both single and multi-word 210fd4e5da5Sopenharmony_ci// integer literal tests. 211fd4e5da5Sopenharmony_cistruct SwitchTestCase { 212fd4e5da5Sopenharmony_ci std::string constant_type_args; 213fd4e5da5Sopenharmony_ci std::string constant_value_arg; 214fd4e5da5Sopenharmony_ci std::string case_value_arg; 215fd4e5da5Sopenharmony_ci std::vector<uint32_t> expected_instructions; 216fd4e5da5Sopenharmony_ci}; 217fd4e5da5Sopenharmony_ci 218fd4e5da5Sopenharmony_ciusing OpSwitchValidTest = 219fd4e5da5Sopenharmony_ci spvtest::TextToBinaryTestBase<TestWithParam<SwitchTestCase>>; 220fd4e5da5Sopenharmony_ci 221fd4e5da5Sopenharmony_ci// Tests the encoding of OpConstant literal values, and also 222fd4e5da5Sopenharmony_ci// the literal integer cases in an OpSwitch. This can 223fd4e5da5Sopenharmony_ci// test both single and multi-word integer literal encodings. 224fd4e5da5Sopenharmony_ciTEST_P(OpSwitchValidTest, ValidTypes) { 225fd4e5da5Sopenharmony_ci const std::string input = "%1 = OpTypeInt " + GetParam().constant_type_args + 226fd4e5da5Sopenharmony_ci "\n" 227fd4e5da5Sopenharmony_ci "%2 = OpConstant %1 " + 228fd4e5da5Sopenharmony_ci GetParam().constant_value_arg + 229fd4e5da5Sopenharmony_ci "\n" 230fd4e5da5Sopenharmony_ci "OpSwitch %2 %default " + 231fd4e5da5Sopenharmony_ci GetParam().case_value_arg + " %4\n"; 232fd4e5da5Sopenharmony_ci std::vector<uint32_t> instructions; 233fd4e5da5Sopenharmony_ci EXPECT_THAT(CompiledInstructions(input), 234fd4e5da5Sopenharmony_ci Eq(GetParam().expected_instructions)); 235fd4e5da5Sopenharmony_ci} 236fd4e5da5Sopenharmony_ci 237fd4e5da5Sopenharmony_ci// Constructs a SwitchTestCase from the given integer_width, signedness, 238fd4e5da5Sopenharmony_ci// constant value string, and expected encoded constant. 239fd4e5da5Sopenharmony_ciSwitchTestCase MakeSwitchTestCase(uint32_t integer_width, 240fd4e5da5Sopenharmony_ci uint32_t integer_signedness, 241fd4e5da5Sopenharmony_ci std::string constant_str, 242fd4e5da5Sopenharmony_ci std::vector<uint32_t> encoded_constant, 243fd4e5da5Sopenharmony_ci std::string case_value_str, 244fd4e5da5Sopenharmony_ci std::vector<uint32_t> encoded_case_value) { 245fd4e5da5Sopenharmony_ci std::stringstream ss; 246fd4e5da5Sopenharmony_ci ss << integer_width << " " << integer_signedness; 247fd4e5da5Sopenharmony_ci return SwitchTestCase{ 248fd4e5da5Sopenharmony_ci ss.str(), 249fd4e5da5Sopenharmony_ci constant_str, 250fd4e5da5Sopenharmony_ci case_value_str, 251fd4e5da5Sopenharmony_ci {Concatenate( 252fd4e5da5Sopenharmony_ci {MakeInstruction(spv::Op::OpTypeInt, 253fd4e5da5Sopenharmony_ci {1, integer_width, integer_signedness}), 254fd4e5da5Sopenharmony_ci MakeInstruction(spv::Op::OpConstant, 255fd4e5da5Sopenharmony_ci Concatenate({{1, 2}, encoded_constant})), 256fd4e5da5Sopenharmony_ci MakeInstruction(spv::Op::OpSwitch, 257fd4e5da5Sopenharmony_ci Concatenate({{2, 3}, encoded_case_value, {4}}))})}}; 258fd4e5da5Sopenharmony_ci} 259fd4e5da5Sopenharmony_ci 260fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P( 261fd4e5da5Sopenharmony_ci TextToBinaryOpSwitchValid1Word, OpSwitchValidTest, 262fd4e5da5Sopenharmony_ci ValuesIn(std::vector<SwitchTestCase>({ 263fd4e5da5Sopenharmony_ci MakeSwitchTestCase(32, 0, "42", {42}, "100", {100}), 264fd4e5da5Sopenharmony_ci MakeSwitchTestCase(32, 1, "-1", {0xffffffff}, "100", {100}), 265fd4e5da5Sopenharmony_ci // SPIR-V 1.0 Rev 1 clarified that for an integer narrower than 32-bits, 266fd4e5da5Sopenharmony_ci // its bits will appear in the lower order bits of the 32-bit word, and 267fd4e5da5Sopenharmony_ci // a signed integer is sign-extended. 268fd4e5da5Sopenharmony_ci MakeSwitchTestCase(7, 0, "127", {127}, "100", {100}), 269fd4e5da5Sopenharmony_ci MakeSwitchTestCase(14, 0, "99", {99}, "100", {100}), 270fd4e5da5Sopenharmony_ci MakeSwitchTestCase(16, 0, "65535", {65535}, "100", {100}), 271fd4e5da5Sopenharmony_ci MakeSwitchTestCase(16, 1, "101", {101}, "100", {100}), 272fd4e5da5Sopenharmony_ci // Demonstrate sign extension 273fd4e5da5Sopenharmony_ci MakeSwitchTestCase(16, 1, "-2", {0xfffffffe}, "100", {100}), 274fd4e5da5Sopenharmony_ci // Hex cases 275fd4e5da5Sopenharmony_ci MakeSwitchTestCase(16, 1, "0x7ffe", {0x7ffe}, "0x1234", {0x1234}), 276fd4e5da5Sopenharmony_ci MakeSwitchTestCase(16, 1, "0x8000", {0xffff8000}, "0x8100", 277fd4e5da5Sopenharmony_ci {0xffff8100}), 278fd4e5da5Sopenharmony_ci MakeSwitchTestCase(16, 0, "0x8000", {0x00008000}, "0x8100", {0x8100}), 279fd4e5da5Sopenharmony_ci }))); 280fd4e5da5Sopenharmony_ci 281fd4e5da5Sopenharmony_ci// NB: The words LOW ORDER bits show up first. 282fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P( 283fd4e5da5Sopenharmony_ci TextToBinaryOpSwitchValid2Words, OpSwitchValidTest, 284fd4e5da5Sopenharmony_ci ValuesIn(std::vector<SwitchTestCase>({ 285fd4e5da5Sopenharmony_ci MakeSwitchTestCase(33, 0, "101", {101, 0}, "500", {500, 0}), 286fd4e5da5Sopenharmony_ci MakeSwitchTestCase(48, 1, "-1", {0xffffffff, 0xffffffff}, "900", 287fd4e5da5Sopenharmony_ci {900, 0}), 288fd4e5da5Sopenharmony_ci MakeSwitchTestCase(64, 1, "-2", {0xfffffffe, 0xffffffff}, "-5", 289fd4e5da5Sopenharmony_ci {0xfffffffb, uint32_t(-1)}), 290fd4e5da5Sopenharmony_ci // Hex cases 291fd4e5da5Sopenharmony_ci MakeSwitchTestCase(48, 1, "0x7fffffffffff", {0xffffffff, 0x00007fff}, 292fd4e5da5Sopenharmony_ci "100", {100, 0}), 293fd4e5da5Sopenharmony_ci MakeSwitchTestCase(48, 1, "0x800000000000", {0x00000000, 0xffff8000}, 294fd4e5da5Sopenharmony_ci "0x800000000000", {0x00000000, 0xffff8000}), 295fd4e5da5Sopenharmony_ci MakeSwitchTestCase(48, 0, "0x800000000000", {0x00000000, 0x00008000}, 296fd4e5da5Sopenharmony_ci "0x800000000000", {0x00000000, 0x00008000}), 297fd4e5da5Sopenharmony_ci MakeSwitchTestCase(63, 0, "0x500000000", {0, 5}, "12", {12, 0}), 298fd4e5da5Sopenharmony_ci MakeSwitchTestCase(64, 0, "0x600000000", {0, 6}, "12", {12, 0}), 299fd4e5da5Sopenharmony_ci MakeSwitchTestCase(64, 1, "0x700000123", {0x123, 7}, "12", {12, 0}), 300fd4e5da5Sopenharmony_ci }))); 301fd4e5da5Sopenharmony_ci 302fd4e5da5Sopenharmony_ciusing ControlFlowRoundTripTest = RoundTripTest; 303fd4e5da5Sopenharmony_ci 304fd4e5da5Sopenharmony_ciTEST_P(ControlFlowRoundTripTest, DisassemblyEqualsAssemblyInput) { 305fd4e5da5Sopenharmony_ci const std::string assembly = GetParam(); 306fd4e5da5Sopenharmony_ci EXPECT_THAT(EncodeAndDecodeSuccessfully(assembly), Eq(assembly)) << assembly; 307fd4e5da5Sopenharmony_ci} 308fd4e5da5Sopenharmony_ci 309fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P( 310fd4e5da5Sopenharmony_ci OpSwitchRoundTripUnsignedIntegers, ControlFlowRoundTripTest, 311fd4e5da5Sopenharmony_ci ValuesIn(std::vector<std::string>({ 312fd4e5da5Sopenharmony_ci // Unsigned 16-bit. 313fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 16 0\n%2 = OpConstant %1 65535\nOpSwitch %2 %3\n", 314fd4e5da5Sopenharmony_ci // Unsigned 32-bit, three non-default cases. 315fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 32 0\n%2 = OpConstant %1 123456\n" 316fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 100 %4 102 %5 1000000 %6\n", 317fd4e5da5Sopenharmony_ci // Unsigned 48-bit, three non-default cases. 318fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 48 0\n%2 = OpConstant %1 5000000000\n" 319fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 100 %4 102 %5 6000000000 %6\n", 320fd4e5da5Sopenharmony_ci // Unsigned 64-bit, three non-default cases. 321fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 64 0\n%2 = OpConstant %1 9223372036854775807\n" 322fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 100 %4 102 %5 9000000000000000000 %6\n", 323fd4e5da5Sopenharmony_ci }))); 324fd4e5da5Sopenharmony_ci 325fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P( 326fd4e5da5Sopenharmony_ci OpSwitchRoundTripSignedIntegers, ControlFlowRoundTripTest, 327fd4e5da5Sopenharmony_ci ValuesIn(std::vector<std::string>{ 328fd4e5da5Sopenharmony_ci // Signed 16-bit, with two non-default cases 329fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 16 1\n%2 = OpConstant %1 32767\n" 330fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 99 %4 -102 %5\n", 331fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 16 1\n%2 = OpConstant %1 -32768\n" 332fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 99 %4 -102 %5\n", 333fd4e5da5Sopenharmony_ci // Signed 32-bit, two non-default cases. 334fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 32 1\n%2 = OpConstant %1 -123456\n" 335fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 100 %4 -123456 %5\n", 336fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 32 1\n%2 = OpConstant %1 123456\n" 337fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 100 %4 123456 %5\n", 338fd4e5da5Sopenharmony_ci // Signed 48-bit, three non-default cases. 339fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 48 1\n%2 = OpConstant %1 5000000000\n" 340fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 100 %4 -7000000000 %5 6000000000 %6\n", 341fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 48 1\n%2 = OpConstant %1 -5000000000\n" 342fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 100 %4 -7000000000 %5 6000000000 %6\n", 343fd4e5da5Sopenharmony_ci // Signed 64-bit, three non-default cases. 344fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 64 1\n%2 = OpConstant %1 9223372036854775807\n" 345fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 100 %4 7000000000 %5 -1000000000000000000 %6\n", 346fd4e5da5Sopenharmony_ci "%1 = OpTypeInt 64 1\n%2 = OpConstant %1 -9223372036854775808\n" 347fd4e5da5Sopenharmony_ci "OpSwitch %2 %3 100 %4 7000000000 %5 -1000000000000000000 %6\n", 348fd4e5da5Sopenharmony_ci })); 349fd4e5da5Sopenharmony_ci 350fd4e5da5Sopenharmony_ciusing OpSwitchInvalidTypeTestCase = 351fd4e5da5Sopenharmony_ci spvtest::TextToBinaryTestBase<TestWithParam<std::string>>; 352fd4e5da5Sopenharmony_ci 353fd4e5da5Sopenharmony_ciTEST_P(OpSwitchInvalidTypeTestCase, InvalidTypes) { 354fd4e5da5Sopenharmony_ci const std::string input = 355fd4e5da5Sopenharmony_ci "%1 = " + GetParam() + 356fd4e5da5Sopenharmony_ci "\n" 357fd4e5da5Sopenharmony_ci "%3 = OpCopyObject %1 %2\n" // We only care the type of the expression 358fd4e5da5Sopenharmony_ci " OpSwitch %3 %default 32 %c\n"; 359fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure(input), 360fd4e5da5Sopenharmony_ci Eq("The selector operand for OpSwitch must be the result of an " 361fd4e5da5Sopenharmony_ci "instruction that generates an integer scalar")); 362fd4e5da5Sopenharmony_ci} 363fd4e5da5Sopenharmony_ci 364fd4e5da5Sopenharmony_ci// clang-format off 365fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P( 366fd4e5da5Sopenharmony_ci TextToBinaryOpSwitchInvalidTests, OpSwitchInvalidTypeTestCase, 367fd4e5da5Sopenharmony_ci ValuesIn(std::vector<std::string>{ 368fd4e5da5Sopenharmony_ci {"OpTypeVoid", 369fd4e5da5Sopenharmony_ci "OpTypeBool", 370fd4e5da5Sopenharmony_ci "OpTypeFloat 32", 371fd4e5da5Sopenharmony_ci "OpTypeVector %a 32", 372fd4e5da5Sopenharmony_ci "OpTypeMatrix %a 32", 373fd4e5da5Sopenharmony_ci "OpTypeImage %a 1D 0 0 0 0 Unknown", 374fd4e5da5Sopenharmony_ci "OpTypeSampler", 375fd4e5da5Sopenharmony_ci "OpTypeSampledImage %a", 376fd4e5da5Sopenharmony_ci "OpTypeArray %a %b", 377fd4e5da5Sopenharmony_ci "OpTypeRuntimeArray %a", 378fd4e5da5Sopenharmony_ci "OpTypeStruct %a", 379fd4e5da5Sopenharmony_ci "OpTypeOpaque \"Foo\"", 380fd4e5da5Sopenharmony_ci "OpTypePointer UniformConstant %a", 381fd4e5da5Sopenharmony_ci "OpTypeFunction %a %b", 382fd4e5da5Sopenharmony_ci "OpTypeEvent", 383fd4e5da5Sopenharmony_ci "OpTypeDeviceEvent", 384fd4e5da5Sopenharmony_ci "OpTypeReserveId", 385fd4e5da5Sopenharmony_ci "OpTypeQueue", 386fd4e5da5Sopenharmony_ci "OpTypePipe ReadOnly", 387fd4e5da5Sopenharmony_ci 388fd4e5da5Sopenharmony_ci // Skip OpTypeForwardPointer because it doesn't even produce a result 389fd4e5da5Sopenharmony_ci // ID. 390fd4e5da5Sopenharmony_ci 391fd4e5da5Sopenharmony_ci // At least one thing that isn't a type at all 392fd4e5da5Sopenharmony_ci "OpNot %a %b" 393fd4e5da5Sopenharmony_ci }, 394fd4e5da5Sopenharmony_ci })); 395fd4e5da5Sopenharmony_ci// clang-format on 396fd4e5da5Sopenharmony_ci 397fd4e5da5Sopenharmony_ciusing OpKillTest = spvtest::TextToBinaryTest; 398fd4e5da5Sopenharmony_ci 399fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(OpKillTest, ControlFlowRoundTripTest, 400fd4e5da5Sopenharmony_ci Values("OpKill\n")); 401fd4e5da5Sopenharmony_ci 402fd4e5da5Sopenharmony_ciTEST_F(OpKillTest, ExtraArgsAssemblyError) { 403fd4e5da5Sopenharmony_ci const std::string input = "OpKill 1"; 404fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure(input), 405fd4e5da5Sopenharmony_ci Eq("Expected <opcode> or <result-id> at the beginning of an " 406fd4e5da5Sopenharmony_ci "instruction, found '1'.")); 407fd4e5da5Sopenharmony_ci} 408fd4e5da5Sopenharmony_ci 409fd4e5da5Sopenharmony_ciusing OpTerminateInvocationTest = spvtest::TextToBinaryTest; 410fd4e5da5Sopenharmony_ci 411fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(OpTerminateInvocationTest, ControlFlowRoundTripTest, 412fd4e5da5Sopenharmony_ci Values("OpTerminateInvocation\n")); 413fd4e5da5Sopenharmony_ci 414fd4e5da5Sopenharmony_ciTEST_F(OpTerminateInvocationTest, ExtraArgsAssemblyError) { 415fd4e5da5Sopenharmony_ci const std::string input = "OpTerminateInvocation 1"; 416fd4e5da5Sopenharmony_ci EXPECT_THAT(CompileFailure(input), 417fd4e5da5Sopenharmony_ci Eq("Expected <opcode> or <result-id> at the beginning of an " 418fd4e5da5Sopenharmony_ci "instruction, found '1'.")); 419fd4e5da5Sopenharmony_ci} 420fd4e5da5Sopenharmony_ci 421fd4e5da5Sopenharmony_ci// TODO(dneto): OpPhi 422fd4e5da5Sopenharmony_ci// TODO(dneto): OpLoopMerge 423fd4e5da5Sopenharmony_ci// TODO(dneto): OpLabel 424fd4e5da5Sopenharmony_ci// TODO(dneto): OpBranch 425fd4e5da5Sopenharmony_ci// TODO(dneto): OpSwitch 426fd4e5da5Sopenharmony_ci// TODO(dneto): OpReturn 427fd4e5da5Sopenharmony_ci// TODO(dneto): OpReturnValue 428fd4e5da5Sopenharmony_ci// TODO(dneto): OpUnreachable 429fd4e5da5Sopenharmony_ci// TODO(dneto): OpLifetimeStart 430fd4e5da5Sopenharmony_ci// TODO(dneto): OpLifetimeStop 431fd4e5da5Sopenharmony_ci 432fd4e5da5Sopenharmony_ci} // namespace 433fd4e5da5Sopenharmony_ci} // namespace spvtools 434