1 // Copyright (c) 2016 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "opt/instruction.h"
16
17 #include "gmock/gmock.h"
18
19 #include "spirv-tools/libspirv.h"
20 #include "unit_spirv.h"
21
22 namespace {
23
24 using spvtest::MakeInstruction;
25 using spvtools::ir::Instruction;
26 using spvtools::ir::Operand;
27 using ::testing::Eq;
28
TEST(InstructionTest,CreateTrivial)29 TEST(InstructionTest, CreateTrivial) {
30 Instruction empty;
31 EXPECT_EQ(SpvOpNop, empty.opcode());
32 EXPECT_EQ(0u, empty.type_id());
33 EXPECT_EQ(0u, empty.result_id());
34 EXPECT_EQ(0u, empty.NumOperands());
35 EXPECT_EQ(0u, empty.NumOperandWords());
36 EXPECT_EQ(0u, empty.NumInOperandWords());
37 EXPECT_EQ(empty.cend(), empty.cbegin());
38 EXPECT_EQ(empty.end(), empty.begin());
39 }
40
TEST(InstructionTest,CreateWithOpcodeAndNoOperands)41 TEST(InstructionTest, CreateWithOpcodeAndNoOperands) {
42 Instruction inst(SpvOpReturn);
43 EXPECT_EQ(SpvOpReturn, inst.opcode());
44 EXPECT_EQ(0u, inst.type_id());
45 EXPECT_EQ(0u, inst.result_id());
46 EXPECT_EQ(0u, inst.NumOperands());
47 EXPECT_EQ(0u, inst.NumOperandWords());
48 EXPECT_EQ(0u, inst.NumInOperandWords());
49 EXPECT_EQ(inst.cend(), inst.cbegin());
50 EXPECT_EQ(inst.end(), inst.begin());
51 }
52
53 // The words for an OpTypeInt for 32-bit signed integer resulting in Id 44.
54 uint32_t kSampleInstructionWords[] = {(4 << 16) | uint32_t(SpvOpTypeInt), 44,
55 32, 1};
56 // The operands that would be parsed from kSampleInstructionWords
57 spv_parsed_operand_t kSampleParsedOperands[] = {
58 {1, 1, SPV_OPERAND_TYPE_RESULT_ID, SPV_NUMBER_NONE, 0},
59 {2, 1, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_NUMBER_UNSIGNED_INT, 32},
60 {3, 1, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_NUMBER_UNSIGNED_INT, 1},
61 };
62
63 // A valid parse of kSampleParsedOperands.
64 spv_parsed_instruction_t kSampleParsedInstruction = {kSampleInstructionWords,
65 uint16_t(4),
66 uint16_t(SpvOpTypeInt),
67 SPV_EXT_INST_TYPE_NONE,
68 0, // type id
69 44, // result id
70 kSampleParsedOperands,
71 3};
72
73 // The words for an OpAccessChain instruction.
74 uint32_t kSampleAccessChainInstructionWords[] = {
75 (7 << 16) | uint32_t(SpvOpAccessChain), 100, 101, 102, 103, 104, 105};
76
77 // The operands that would be parsed from kSampleAccessChainInstructionWords.
78 spv_parsed_operand_t kSampleAccessChainOperands[] = {
79 {1, 1, SPV_OPERAND_TYPE_RESULT_ID, SPV_NUMBER_NONE, 0},
80 {2, 1, SPV_OPERAND_TYPE_TYPE_ID, SPV_NUMBER_NONE, 0},
81 {3, 1, SPV_OPERAND_TYPE_ID, SPV_NUMBER_NONE, 0},
82 {4, 1, SPV_OPERAND_TYPE_ID, SPV_NUMBER_NONE, 0},
83 {5, 1, SPV_OPERAND_TYPE_ID, SPV_NUMBER_NONE, 0},
84 {6, 1, SPV_OPERAND_TYPE_ID, SPV_NUMBER_NONE, 0},
85 };
86
87 // A valid parse of kSampleAccessChainInstructionWords
88 spv_parsed_instruction_t kSampleAccessChainInstruction = {
89 kSampleAccessChainInstructionWords,
90 uint16_t(7),
91 uint16_t(SpvOpAccessChain),
92 SPV_EXT_INST_TYPE_NONE,
93 100, // type id
94 101, // result id
95 kSampleAccessChainOperands,
96 6};
97
98 // The words for an OpControlBarrier instruction.
99 uint32_t kSampleControlBarrierInstructionWords[] = {
100 (4 << 16) | uint32_t(SpvOpControlBarrier), 100, 101, 102};
101
102 // The operands that would be parsed from kSampleControlBarrierInstructionWords.
103 spv_parsed_operand_t kSampleControlBarrierOperands[] = {
104 {1, 1, SPV_OPERAND_TYPE_SCOPE_ID, SPV_NUMBER_NONE, 0}, // Execution
105 {2, 1, SPV_OPERAND_TYPE_SCOPE_ID, SPV_NUMBER_NONE, 0}, // Memory
106 {3, 1, SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID, SPV_NUMBER_NONE,
107 0}, // Semantics
108 };
109
110 // A valid parse of kSampleControlBarrierInstructionWords
111 spv_parsed_instruction_t kSampleControlBarrierInstruction = {
112 kSampleControlBarrierInstructionWords,
113 uint16_t(4),
114 uint16_t(SpvOpControlBarrier),
115 SPV_EXT_INST_TYPE_NONE,
116 0, // type id
117 0, // result id
118 kSampleControlBarrierOperands,
119 3};
120
TEST(InstructionTest,CreateWithOpcodeAndOperands)121 TEST(InstructionTest, CreateWithOpcodeAndOperands) {
122 Instruction inst(kSampleParsedInstruction);
123 EXPECT_EQ(SpvOpTypeInt, inst.opcode());
124 EXPECT_EQ(0u, inst.type_id());
125 EXPECT_EQ(44u, inst.result_id());
126 EXPECT_EQ(3u, inst.NumOperands());
127 EXPECT_EQ(3u, inst.NumOperandWords());
128 EXPECT_EQ(2u, inst.NumInOperandWords());
129 }
130
TEST(InstructionTest,GetOperand)131 TEST(InstructionTest, GetOperand) {
132 Instruction inst(kSampleParsedInstruction);
133 EXPECT_THAT(inst.GetOperand(0).words, Eq(std::vector<uint32_t>{44}));
134 EXPECT_THAT(inst.GetOperand(1).words, Eq(std::vector<uint32_t>{32}));
135 EXPECT_THAT(inst.GetOperand(2).words, Eq(std::vector<uint32_t>{1}));
136 }
137
TEST(InstructionTest,GetInOperand)138 TEST(InstructionTest, GetInOperand) {
139 Instruction inst(kSampleParsedInstruction);
140 EXPECT_THAT(inst.GetInOperand(0).words, Eq(std::vector<uint32_t>{32}));
141 EXPECT_THAT(inst.GetInOperand(1).words, Eq(std::vector<uint32_t>{1}));
142 }
143
TEST(InstructionTest,OperandConstIterators)144 TEST(InstructionTest, OperandConstIterators) {
145 Instruction inst(kSampleParsedInstruction);
146 // Spot check iteration across operands.
147 auto cbegin = inst.cbegin();
148 auto cend = inst.cend();
149 EXPECT_NE(cend, inst.cbegin());
150
151 auto citer = inst.cbegin();
152 for (int i = 0; i < 3; ++i, ++citer) {
153 const auto& operand = *citer;
154 EXPECT_THAT(operand.type, Eq(kSampleParsedOperands[i].type));
155 EXPECT_THAT(operand.words,
156 Eq(std::vector<uint32_t>{kSampleInstructionWords[i + 1]}));
157 EXPECT_NE(cend, citer);
158 }
159 EXPECT_EQ(cend, citer);
160
161 // Check that cbegin and cend have not changed.
162 EXPECT_EQ(cbegin, inst.cbegin());
163 EXPECT_EQ(cend, inst.cend());
164
165 // Check arithmetic.
166 const Operand& operand2 = *(inst.cbegin() + 2);
167 EXPECT_EQ(SPV_OPERAND_TYPE_LITERAL_INTEGER, operand2.type);
168 }
169
TEST(InstructionTest,OperandIterators)170 TEST(InstructionTest, OperandIterators) {
171 Instruction inst(kSampleParsedInstruction);
172 // Spot check iteration across operands, with mutable iterators.
173 auto begin = inst.begin();
174 auto end = inst.end();
175 EXPECT_NE(end, inst.begin());
176
177 auto iter = inst.begin();
178 for (int i = 0; i < 3; ++i, ++iter) {
179 const auto& operand = *iter;
180 EXPECT_THAT(operand.type, Eq(kSampleParsedOperands[i].type));
181 EXPECT_THAT(operand.words,
182 Eq(std::vector<uint32_t>{kSampleInstructionWords[i + 1]}));
183 EXPECT_NE(end, iter);
184 }
185 EXPECT_EQ(end, iter);
186
187 // Check that begin and end have not changed.
188 EXPECT_EQ(begin, inst.begin());
189 EXPECT_EQ(end, inst.end());
190
191 // Check arithmetic.
192 Operand& operand2 = *(inst.begin() + 2);
193 EXPECT_EQ(SPV_OPERAND_TYPE_LITERAL_INTEGER, operand2.type);
194
195 // Check mutation through an iterator.
196 operand2.type = SPV_OPERAND_TYPE_TYPE_ID;
197 EXPECT_EQ(SPV_OPERAND_TYPE_TYPE_ID, (*(inst.cbegin() + 2)).type);
198 }
199
TEST(InstructionTest,ForInIdStandardIdTypes)200 TEST(InstructionTest, ForInIdStandardIdTypes) {
201 Instruction inst(kSampleAccessChainInstruction);
202
203 std::vector<uint32_t> ids;
204 inst.ForEachInId([&ids](const uint32_t* idptr) { ids.push_back(*idptr); });
205 EXPECT_THAT(ids, Eq(std::vector<uint32_t>{102, 103, 104, 105}));
206
207 ids.clear();
208 inst.ForEachInId([&ids](uint32_t* idptr) { ids.push_back(*idptr); });
209 EXPECT_THAT(ids, Eq(std::vector<uint32_t>{102, 103, 104, 105}));
210 }
211
TEST(InstructionTest,ForInIdNonstandardIdTypes)212 TEST(InstructionTest, ForInIdNonstandardIdTypes) {
213 Instruction inst(kSampleControlBarrierInstruction);
214
215 std::vector<uint32_t> ids;
216 inst.ForEachInId([&ids](const uint32_t* idptr) { ids.push_back(*idptr); });
217 EXPECT_THAT(ids, Eq(std::vector<uint32_t>{100, 101, 102}));
218
219 ids.clear();
220 inst.ForEachInId([&ids](uint32_t* idptr) { ids.push_back(*idptr); });
221 EXPECT_THAT(ids, Eq(std::vector<uint32_t>{100, 101, 102}));
222 }
223
224 } // anonymous namespace
225