Line data Source code
1 : // Copyright 2014 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
6 : #define V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
7 :
8 : #include <memory>
9 :
10 : #include "src/compiler/backend/instruction.h"
11 : #include "src/register-configuration.h"
12 : #include "test/unittests/test-utils.h"
13 : #include "testing/gmock/include/gmock/gmock.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 : namespace compiler {
18 :
19 104 : class InstructionSequenceTest : public TestWithIsolateAndZone {
20 : public:
21 : static constexpr int kNoValue = kMinInt;
22 : static constexpr MachineRepresentation kNoRep = MachineRepresentation::kNone;
23 : static constexpr MachineRepresentation kFloat32 =
24 : MachineRepresentation::kFloat32;
25 : static constexpr MachineRepresentation kFloat64 =
26 : MachineRepresentation::kFloat64;
27 : static constexpr MachineRepresentation kSimd128 =
28 : MachineRepresentation::kSimd128;
29 :
30 : typedef RpoNumber Rpo;
31 :
32 : struct VReg {
33 785 : VReg() : value_(kNoValue) {}
34 2 : VReg(PhiInstruction* phi) : value_(phi->virtual_register()) {} // NOLINT
35 : explicit VReg(int value, MachineRepresentation rep = kNoRep)
36 : : value_(value), rep_(rep) {}
37 : int value_;
38 : MachineRepresentation rep_ = kNoRep;
39 : };
40 :
41 : typedef std::pair<VReg, VReg> VRegPair;
42 :
43 : enum TestOperandType {
44 : kInvalid,
45 : kSameAsFirst,
46 : kRegister,
47 : kFixedRegister,
48 : kSlot,
49 : kFixedSlot,
50 : kExplicit,
51 : kImmediate,
52 : kNone,
53 : kConstant,
54 : kUnique,
55 : kUniqueRegister
56 : };
57 :
58 : struct TestOperand {
59 552 : TestOperand() : type_(kInvalid), vreg_(), value_(kNoValue), rep_(kNoRep) {}
60 : explicit TestOperand(TestOperandType type)
61 10 : : type_(type), vreg_(), value_(kNoValue), rep_(kNoRep) {}
62 : // For tests that do register allocation.
63 : TestOperand(TestOperandType type, VReg vreg, int value = kNoValue)
64 257 : : type_(type), vreg_(vreg), value_(value), rep_(vreg.rep_) {}
65 : // For immediates, constants, and tests that don't do register allocation.
66 : TestOperand(TestOperandType type, int value,
67 : MachineRepresentation rep = kNoRep)
68 282 : : type_(type), vreg_(), value_(value), rep_(rep) {}
69 :
70 : TestOperandType type_;
71 : VReg vreg_;
72 : int value_;
73 : MachineRepresentation rep_;
74 : };
75 :
76 : static TestOperand Same() { return TestOperand(kSameAsFirst); }
77 :
78 : static TestOperand ExplicitReg(int index) {
79 : TestOperandType type = kExplicit;
80 : return TestOperand(type, index);
81 : }
82 :
83 : static TestOperand ExplicitFPReg(int index,
84 : MachineRepresentation rep = kFloat64) {
85 : TestOperandType type = kExplicit;
86 : return TestOperand(type, index, rep);
87 : }
88 :
89 : static TestOperand Reg(VReg vreg, int index = kNoValue) {
90 88 : TestOperandType type = (index == kNoValue) ? kRegister : kFixedRegister;
91 : return TestOperand(type, vreg, index);
92 : }
93 :
94 : static TestOperand Reg(int index = kNoValue,
95 : MachineRepresentation rep = kNoRep) {
96 : return Reg(VReg(kNoValue, rep), index);
97 : }
98 :
99 : static TestOperand FPReg(int index = kNoValue,
100 : MachineRepresentation rep = kFloat64) {
101 : return Reg(index, rep);
102 : }
103 :
104 : static TestOperand Slot(VReg vreg, int index = kNoValue) {
105 48 : TestOperandType type = (index == kNoValue) ? kSlot : kFixedSlot;
106 : return TestOperand(type, vreg, index);
107 : }
108 :
109 : static TestOperand Slot(int index = kNoValue,
110 : MachineRepresentation rep = kNoRep) {
111 : return Slot(VReg(kNoValue, rep), index);
112 : }
113 :
114 : static TestOperand Const(int index) {
115 : CHECK_NE(kNoValue, index);
116 : return TestOperand(kConstant, index);
117 : }
118 :
119 : static TestOperand Use(VReg vreg) { return TestOperand(kNone, vreg); }
120 :
121 : static TestOperand Use() { return Use(VReg()); }
122 :
123 : static TestOperand Unique(VReg vreg) { return TestOperand(kUnique, vreg); }
124 :
125 : static TestOperand UniqueReg(VReg vreg) {
126 : return TestOperand(kUniqueRegister, vreg);
127 : }
128 :
129 : enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump };
130 :
131 : struct BlockCompletion {
132 : BlockCompletionType type_;
133 : TestOperand op_;
134 : int offset_0_;
135 : int offset_1_;
136 : };
137 :
138 : static BlockCompletion FallThrough() {
139 29 : BlockCompletion completion = {kFallThrough, TestOperand(), 1, kNoValue};
140 : return completion;
141 : }
142 :
143 : static BlockCompletion Jump(int offset) {
144 65 : BlockCompletion completion = {kJump, TestOperand(), offset, kNoValue};
145 : return completion;
146 : }
147 :
148 : static BlockCompletion Branch(TestOperand op, int left_offset,
149 : int right_offset) {
150 22 : BlockCompletion completion = {kBranch, op, left_offset, right_offset};
151 : return completion;
152 : }
153 :
154 : static BlockCompletion Last() {
155 38 : BlockCompletion completion = {kBlockEnd, TestOperand(), kNoValue, kNoValue};
156 : return completion;
157 : }
158 :
159 : InstructionSequenceTest();
160 :
161 : void SetNumRegs(int num_general_registers, int num_double_registers);
162 : int GetNumRegs(MachineRepresentation rep);
163 : int GetAllocatableCode(int index, MachineRepresentation rep = kNoRep);
164 : const RegisterConfiguration* config();
165 : InstructionSequence* sequence();
166 :
167 : void StartLoop(int loop_blocks);
168 : void EndLoop();
169 : void StartBlock(bool deferred = false);
170 : Instruction* EndBlock(BlockCompletion completion = FallThrough());
171 :
172 : TestOperand Imm(int32_t imm = 0);
173 : VReg Define(TestOperand output_op);
174 61 : VReg Parameter(TestOperand output_op = Reg()) { return Define(output_op); }
175 6 : VReg FPParameter(MachineRepresentation rep = kFloat64) {
176 6 : return Parameter(FPReg(kNoValue, rep));
177 : }
178 :
179 : MachineRepresentation GetCanonicalRep(TestOperand op) {
180 : return IsFloatingPoint(op.rep_) ? op.rep_
181 290 : : sequence()->DefaultRepresentation();
182 : }
183 :
184 : Instruction* Return(TestOperand input_op_0);
185 8 : Instruction* Return(VReg vreg) { return Return(Reg(vreg, 0)); }
186 :
187 : PhiInstruction* Phi(VReg incoming_vreg_0 = VReg(),
188 : VReg incoming_vreg_1 = VReg(),
189 : VReg incoming_vreg_2 = VReg(),
190 : VReg incoming_vreg_3 = VReg());
191 : PhiInstruction* Phi(VReg incoming_vreg_0, size_t input_count);
192 : void SetInput(PhiInstruction* phi, size_t input, VReg vreg);
193 :
194 : VReg DefineConstant(int32_t imm = 0);
195 : Instruction* EmitNop();
196 : Instruction* EmitI(size_t input_size, TestOperand* inputs);
197 : Instruction* EmitI(TestOperand input_op_0 = TestOperand(),
198 : TestOperand input_op_1 = TestOperand(),
199 : TestOperand input_op_2 = TestOperand(),
200 : TestOperand input_op_3 = TestOperand());
201 : VReg EmitOI(TestOperand output_op, size_t input_size, TestOperand* inputs);
202 : VReg EmitOI(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
203 : TestOperand input_op_1 = TestOperand(),
204 : TestOperand input_op_2 = TestOperand(),
205 : TestOperand input_op_3 = TestOperand());
206 : VRegPair EmitOOI(TestOperand output_op_0, TestOperand output_op_1,
207 : size_t input_size, TestOperand* inputs);
208 : VRegPair EmitOOI(TestOperand output_op_0, TestOperand output_op_1,
209 : TestOperand input_op_0 = TestOperand(),
210 : TestOperand input_op_1 = TestOperand(),
211 : TestOperand input_op_2 = TestOperand(),
212 : TestOperand input_op_3 = TestOperand());
213 : VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs);
214 : VReg EmitCall(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
215 : TestOperand input_op_1 = TestOperand(),
216 : TestOperand input_op_2 = TestOperand(),
217 : TestOperand input_op_3 = TestOperand());
218 :
219 : InstructionBlock* current_block() const { return current_block_; }
220 :
221 : // Called after all instructions have been inserted.
222 : void WireBlocks();
223 :
224 : private:
225 197 : virtual bool DoesRegisterAllocation() const { return true; }
226 :
227 346 : VReg NewReg(TestOperand op = TestOperand()) {
228 346 : int vreg = sequence()->NextVirtualRegister();
229 346 : if (IsFloatingPoint(op.rep_))
230 8 : sequence()->MarkAsRepresentation(op.rep_, vreg);
231 346 : return VReg(vreg, op.rep_);
232 : }
233 :
234 : static TestOperand Invalid() { return TestOperand(kInvalid); }
235 :
236 : Instruction* EmitBranch(TestOperand input_op);
237 : Instruction* EmitFallThrough();
238 : Instruction* EmitJump();
239 : Instruction* NewInstruction(InstructionCode code, size_t outputs_size,
240 : InstructionOperand* outputs,
241 : size_t inputs_size = 0,
242 : InstructionOperand* inputs = nullptr,
243 : size_t temps_size = 0,
244 : InstructionOperand* temps = nullptr);
245 : InstructionOperand Unallocated(TestOperand op,
246 : UnallocatedOperand::ExtendedPolicy policy);
247 : InstructionOperand Unallocated(TestOperand op,
248 : UnallocatedOperand::ExtendedPolicy policy,
249 : UnallocatedOperand::Lifetime lifetime);
250 : InstructionOperand Unallocated(TestOperand op,
251 : UnallocatedOperand::ExtendedPolicy policy,
252 : int index);
253 : InstructionOperand Unallocated(TestOperand op,
254 : UnallocatedOperand::BasicPolicy policy,
255 : int index);
256 : InstructionOperand* ConvertInputs(size_t input_size, TestOperand* inputs);
257 : InstructionOperand ConvertInputOp(TestOperand op);
258 : InstructionOperand ConvertOutputOp(VReg vreg, TestOperand op);
259 : InstructionBlock* NewBlock(bool deferred = false);
260 : void WireBlock(size_t block_offset, int jump_offset);
261 :
262 : Instruction* Emit(InstructionCode code, size_t outputs_size = 0,
263 : InstructionOperand* outputs = nullptr,
264 : size_t inputs_size = 0,
265 : InstructionOperand* inputs = nullptr, size_t temps_size = 0,
266 : InstructionOperand* temps = nullptr, bool is_call = false);
267 :
268 : Instruction* AddInstruction(Instruction* instruction);
269 :
270 : struct LoopData {
271 : Rpo loop_header_;
272 : int expected_blocks_;
273 : };
274 :
275 : typedef std::vector<LoopData> LoopBlocks;
276 : typedef std::map<int, const Instruction*> Instructions;
277 : typedef std::vector<BlockCompletion> Completions;
278 :
279 : std::unique_ptr<RegisterConfiguration> config_;
280 : InstructionSequence* sequence_;
281 : int num_general_registers_;
282 : int num_double_registers_;
283 :
284 : // Block building state.
285 : InstructionBlocks instruction_blocks_;
286 : Instructions instructions_;
287 : Completions completions_;
288 : LoopBlocks loop_blocks_;
289 : InstructionBlock* current_block_;
290 : bool block_returns_;
291 :
292 : DISALLOW_COPY_AND_ASSIGN(InstructionSequenceTest);
293 : };
294 :
295 : } // namespace compiler
296 : } // namespace internal
297 : } // namespace v8
298 :
299 : #endif // V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
|