OLD | NEW |
| (Empty) |
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 #include "src/assembler.h" | |
6 #include "src/codegen.h" | |
7 #include "src/compiler/linkage.h" | |
8 #include "src/compiler/machine-type.h" | |
9 #include "src/compiler/raw-machine-assembler.h" | |
10 | |
11 #include "test/cctest/cctest.h" | |
12 #include "test/cctest/compiler/codegen-tester.h" | |
13 #include "test/cctest/compiler/graph-builder-tester.h" | |
14 #include "test/cctest/compiler/value-helper.h" | |
15 | |
16 using namespace v8::base; | |
17 using namespace v8::internal; | |
18 using namespace v8::internal::compiler; | |
19 | |
20 typedef RawMachineAssembler::Label MLabel; | |
21 | |
22 #if !V8_TARGET_ARCH_ARM64 | |
23 // TODO(titzer): fix native stack parameters on arm64 | |
24 #define NATIVE_STACK_PARAMS_OK | |
25 #endif | |
26 | |
27 namespace { | |
28 // Picks a representative set of registers from the allocatable set. | |
29 // If there are less than 100 possible pairs, do them all, otherwise try | |
30 // to select a representative set. | |
31 class RegisterPairs { | |
32 public: | |
33 RegisterPairs() | |
34 : max_(std::min(100, Register::kMaxNumAllocatableRegisters * | |
35 Register::kMaxNumAllocatableRegisters)), | |
36 counter_(0) {} | |
37 | |
38 bool More() { return counter_ < max_; } | |
39 | |
40 void Next(int* r0, int* r1, bool same_is_ok) { | |
41 do { | |
42 // Find the next pair. | |
43 if (exhaustive()) { | |
44 *r0 = counter_ % Register::kMaxNumAllocatableRegisters; | |
45 *r1 = counter_ / Register::kMaxNumAllocatableRegisters; | |
46 } else { | |
47 // Try each register at least once for both r0 and r1. | |
48 int index = counter_ / 2; | |
49 if (counter_ & 1) { | |
50 *r0 = index % Register::kMaxNumAllocatableRegisters; | |
51 *r1 = index / Register::kMaxNumAllocatableRegisters; | |
52 } else { | |
53 *r1 = index % Register::kMaxNumAllocatableRegisters; | |
54 *r0 = index / Register::kMaxNumAllocatableRegisters; | |
55 } | |
56 } | |
57 counter_++; | |
58 if (same_is_ok) break; | |
59 if (*r0 == *r1) { | |
60 if (counter_ >= max_) { | |
61 // For the last hurrah, reg#0 with reg#n-1 | |
62 *r0 = 0; | |
63 *r1 = Register::kMaxNumAllocatableRegisters - 1; | |
64 break; | |
65 } | |
66 } | |
67 } while (true); | |
68 | |
69 DCHECK(*r0 >= 0 && *r0 < Register::kMaxNumAllocatableRegisters); | |
70 DCHECK(*r1 >= 0 && *r1 < Register::kMaxNumAllocatableRegisters); | |
71 printf("pair = %d, %d\n", *r0, *r1); | |
72 } | |
73 | |
74 private: | |
75 int max_; | |
76 int counter_; | |
77 bool exhaustive() { | |
78 return max_ == (Register::kMaxNumAllocatableRegisters * | |
79 Register::kMaxNumAllocatableRegisters); | |
80 } | |
81 }; | |
82 | |
83 | |
84 // Helper for allocating either an GP or FP reg, or the next stack slot. | |
85 struct Allocator { | |
86 Allocator(int* gp, int gpc, int* fp, int fpc) | |
87 : gp_count(gpc), | |
88 gp_offset(0), | |
89 gp_regs(gp), | |
90 fp_count(fpc), | |
91 fp_offset(0), | |
92 fp_regs(fp), | |
93 stack_offset(0) {} | |
94 | |
95 int gp_count; | |
96 int gp_offset; | |
97 int* gp_regs; | |
98 | |
99 int fp_count; | |
100 int fp_offset; | |
101 int* fp_regs; | |
102 | |
103 int stack_offset; | |
104 | |
105 LinkageLocation Next(MachineType type) { | |
106 if (IsFloatingPoint(type)) { | |
107 // Allocate a floating point register/stack location. | |
108 if (fp_offset < fp_count) { | |
109 return LinkageLocation::ForRegister(fp_regs[fp_offset++]); | |
110 } else { | |
111 int offset = -1 - stack_offset; | |
112 stack_offset += Words(type); | |
113 return LinkageLocation::ForCallerFrameSlot(offset); | |
114 } | |
115 } else { | |
116 // Allocate a general purpose register/stack location. | |
117 if (gp_offset < gp_count) { | |
118 return LinkageLocation::ForRegister(gp_regs[gp_offset++]); | |
119 } else { | |
120 int offset = -1 - stack_offset; | |
121 stack_offset += Words(type); | |
122 return LinkageLocation::ForCallerFrameSlot(offset); | |
123 } | |
124 } | |
125 } | |
126 bool IsFloatingPoint(MachineType type) { | |
127 return RepresentationOf(type) == kRepFloat32 || | |
128 RepresentationOf(type) == kRepFloat64; | |
129 } | |
130 int Words(MachineType type) { | |
131 int size = ElementSizeOf(type); | |
132 return size <= kPointerSize ? 1 : size / kPointerSize; | |
133 } | |
134 void Reset() { | |
135 fp_offset = 0; | |
136 gp_offset = 0; | |
137 stack_offset = 0; | |
138 } | |
139 }; | |
140 | |
141 | |
142 class RegisterConfig { | |
143 public: | |
144 RegisterConfig(Allocator& p, Allocator& r) : params(p), rets(r) {} | |
145 | |
146 CallDescriptor* Create(Zone* zone, MachineSignature* msig) { | |
147 rets.Reset(); | |
148 params.Reset(); | |
149 | |
150 LocationSignature::Builder locations(zone, msig->return_count(), | |
151 msig->parameter_count()); | |
152 // Add return location(s). | |
153 const int return_count = static_cast<int>(locations.return_count_); | |
154 for (int i = 0; i < return_count; i++) { | |
155 locations.AddReturn(rets.Next(msig->GetReturn(i))); | |
156 } | |
157 | |
158 // Add register and/or stack parameter(s). | |
159 const int parameter_count = static_cast<int>(msig->parameter_count()); | |
160 for (int i = 0; i < parameter_count; i++) { | |
161 locations.AddParam(params.Next(msig->GetParam(i))); | |
162 } | |
163 | |
164 const RegList kCalleeSaveRegisters = 0; | |
165 const RegList kCalleeSaveFPRegisters = 0; | |
166 | |
167 MachineType target_type = compiler::kMachAnyTagged; | |
168 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); | |
169 int stack_param_count = params.stack_offset; | |
170 return new (zone) CallDescriptor( // -- | |
171 CallDescriptor::kCallCodeObject, // kind | |
172 target_type, // target MachineType | |
173 target_loc, // target location | |
174 msig, // machine_sig | |
175 locations.Build(), // location_sig | |
176 stack_param_count, // stack_parameter_count | |
177 compiler::Operator::kNoProperties, // properties | |
178 kCalleeSaveRegisters, // callee-saved registers | |
179 kCalleeSaveFPRegisters, // callee-saved fp regs | |
180 CallDescriptor::kNoFlags, // flags | |
181 "c-call"); | |
182 } | |
183 | |
184 private: | |
185 Allocator& params; | |
186 Allocator& rets; | |
187 }; | |
188 | |
189 const int kMaxParamCount = 64; | |
190 | |
191 MachineType kIntTypes[kMaxParamCount + 1] = { | |
192 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, | |
193 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, | |
194 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, | |
195 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, | |
196 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, | |
197 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, | |
198 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, | |
199 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, | |
200 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, | |
201 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32, | |
202 kMachInt32, kMachInt32, kMachInt32, kMachInt32, kMachInt32}; | |
203 | |
204 | |
205 // For making uniform int32 signatures shorter. | |
206 class Int32Signature : public MachineSignature { | |
207 public: | |
208 explicit Int32Signature(int param_count) | |
209 : MachineSignature(1, param_count, kIntTypes) { | |
210 CHECK(param_count <= kMaxParamCount); | |
211 } | |
212 }; | |
213 | |
214 | |
215 Handle<Code> CompileGraph(const char* name, CallDescriptor* desc, Graph* graph, | |
216 Schedule* schedule = nullptr) { | |
217 Isolate* isolate = CcTest::InitIsolateOnce(); | |
218 Handle<Code> code = | |
219 Pipeline::GenerateCodeForTesting(isolate, desc, graph, schedule); | |
220 CHECK(!code.is_null()); | |
221 #ifdef ENABLE_DISASSEMBLER | |
222 if (FLAG_print_opt_code) { | |
223 OFStream os(stdout); | |
224 code->Disassemble(name, os); | |
225 } | |
226 #endif | |
227 return code; | |
228 } | |
229 | |
230 | |
231 Handle<Code> WrapWithCFunction(Handle<Code> inner, CallDescriptor* desc) { | |
232 Zone zone; | |
233 MachineSignature* msig = | |
234 const_cast<MachineSignature*>(desc->GetMachineSignature()); | |
235 int param_count = static_cast<int>(msig->parameter_count()); | |
236 GraphAndBuilders caller(&zone); | |
237 { | |
238 GraphAndBuilders& b = caller; | |
239 Node* start = b.graph()->NewNode(b.common()->Start(param_count + 3)); | |
240 b.graph()->SetStart(start); | |
241 Unique<HeapObject> unique = Unique<HeapObject>::CreateUninitialized(inner); | |
242 Node* target = b.graph()->NewNode(b.common()->HeapConstant(unique)); | |
243 | |
244 // Add arguments to the call. | |
245 Node** args = zone.NewArray<Node*>(param_count + 3); | |
246 int index = 0; | |
247 args[index++] = target; | |
248 for (int i = 0; i < param_count; i++) { | |
249 args[index] = b.graph()->NewNode(b.common()->Parameter(i), start); | |
250 index++; | |
251 } | |
252 args[index++] = start; // effect. | |
253 args[index++] = start; // control. | |
254 | |
255 // Build the call and return nodes. | |
256 Node* call = | |
257 b.graph()->NewNode(b.common()->Call(desc), param_count + 3, args); | |
258 Node* ret = b.graph()->NewNode(b.common()->Return(), call, call, start); | |
259 b.graph()->SetEnd(ret); | |
260 } | |
261 | |
262 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, msig); | |
263 | |
264 return CompileGraph("wrapper", cdesc, caller.graph()); | |
265 } | |
266 | |
267 | |
268 } // namespace | |
269 | |
270 | |
271 static void TestInt32Sub(CallDescriptor* desc) { | |
272 Isolate* isolate = CcTest::InitIsolateOnce(); | |
273 HandleScope scope(isolate); | |
274 Zone zone; | |
275 GraphAndBuilders inner(&zone); | |
276 { | |
277 // Build the add function. | |
278 GraphAndBuilders& b = inner; | |
279 Node* start = b.graph()->NewNode(b.common()->Start(5)); | |
280 b.graph()->SetStart(start); | |
281 Node* p0 = b.graph()->NewNode(b.common()->Parameter(0), start); | |
282 Node* p1 = b.graph()->NewNode(b.common()->Parameter(1), start); | |
283 Node* add = b.graph()->NewNode(b.machine()->Int32Sub(), p0, p1); | |
284 Node* ret = b.graph()->NewNode(b.common()->Return(), add, start, start); | |
285 b.graph()->SetEnd(ret); | |
286 } | |
287 | |
288 Handle<Code> inner_code = CompileGraph("Int32Sub", desc, inner.graph()); | |
289 Handle<Code> wrapper = WrapWithCFunction(inner_code, desc); | |
290 MachineSignature* msig = | |
291 const_cast<MachineSignature*>(desc->GetMachineSignature()); | |
292 CodeRunner<int32_t> runnable(isolate, wrapper, | |
293 CSignature::FromMachine(&zone, msig)); | |
294 | |
295 FOR_INT32_INPUTS(i) { | |
296 FOR_INT32_INPUTS(j) { | |
297 int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(*i) - | |
298 static_cast<uint32_t>(*j)); | |
299 int32_t result = runnable.Call(*i, *j); | |
300 CHECK_EQ(expected, result); | |
301 } | |
302 } | |
303 } | |
304 | |
305 | |
306 #ifdef NATIVE_STACK_PARAMS_OK | |
307 static void CopyTwentyInt32(CallDescriptor* desc) { | |
308 const int kNumParams = 20; | |
309 int32_t input[kNumParams]; | |
310 int32_t output[kNumParams]; | |
311 Isolate* isolate = CcTest::InitIsolateOnce(); | |
312 HandleScope scope(isolate); | |
313 Handle<Code> inner = Handle<Code>::null(); | |
314 { | |
315 // Writes all parameters into the output buffer. | |
316 Zone zone; | |
317 Graph graph(&zone); | |
318 RawMachineAssembler raw(isolate, &graph, desc); | |
319 Node* base = raw.PointerConstant(output); | |
320 for (int i = 0; i < kNumParams; i++) { | |
321 Node* offset = raw.Int32Constant(i * sizeof(int32_t)); | |
322 raw.Store(kMachInt32, base, offset, raw.Parameter(i)); | |
323 } | |
324 raw.Return(raw.Int32Constant(42)); | |
325 inner = CompileGraph("CopyTwentyInt32", desc, &graph, raw.Export()); | |
326 } | |
327 | |
328 CSignature0<int32_t> csig; | |
329 Handle<Code> wrapper = Handle<Code>::null(); | |
330 { | |
331 // Loads parameters from the input buffer and calls the above code. | |
332 Zone zone; | |
333 Graph graph(&zone); | |
334 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); | |
335 RawMachineAssembler raw(isolate, &graph, cdesc); | |
336 Node* base = raw.PointerConstant(input); | |
337 Unique<HeapObject> unique = Unique<HeapObject>::CreateUninitialized(inner); | |
338 Node* target = raw.HeapConstant(unique); | |
339 Node** args = zone.NewArray<Node*>(kNumParams); | |
340 for (int i = 0; i < kNumParams; i++) { | |
341 Node* offset = raw.Int32Constant(i * sizeof(int32_t)); | |
342 args[i] = raw.Load(kMachInt32, base, offset); | |
343 } | |
344 | |
345 Node* call = raw.CallN(desc, target, args); | |
346 raw.Return(call); | |
347 wrapper = | |
348 CompileGraph("CopyTwentyInt32-wrapper", cdesc, &graph, raw.Export()); | |
349 } | |
350 | |
351 CodeRunner<int32_t> runnable(isolate, wrapper, &csig); | |
352 | |
353 // Run the code, checking it correctly implements the memcpy. | |
354 for (int i = 0; i < 5; i++) { | |
355 uint32_t base = 1111111111u * i; | |
356 for (int j = 0; j < kNumParams; j++) { | |
357 input[j] = static_cast<int32_t>(base + 13 * j); | |
358 } | |
359 | |
360 memset(output, 0, sizeof(output)); | |
361 CHECK_EQ(42, runnable.Call()); | |
362 | |
363 for (int j = 0; j < kNumParams; j++) { | |
364 CHECK_EQ(input[j], output[j]); | |
365 } | |
366 } | |
367 } | |
368 #endif // NATIVE_STACK_PARAMS_OK | |
369 | |
370 | |
371 static void Test_RunInt32SubWithRet(int retreg) { | |
372 Int32Signature sig(2); | |
373 Zone zone; | |
374 RegisterPairs pairs; | |
375 while (pairs.More()) { | |
376 int parray[2]; | |
377 int rarray[] = {retreg}; | |
378 pairs.Next(&parray[0], &parray[1], false); | |
379 Allocator params(parray, 2, nullptr, 0); | |
380 Allocator rets(rarray, 1, nullptr, 0); | |
381 RegisterConfig config(params, rets); | |
382 CallDescriptor* desc = config.Create(&zone, &sig); | |
383 TestInt32Sub(desc); | |
384 } | |
385 } | |
386 | |
387 | |
388 // Separate tests for parallelization. | |
389 #define TEST_INT32_SUB_WITH_RET(x) \ | |
390 TEST(Run_Int32Sub_all_allocatable_pairs_##x) { \ | |
391 if (Register::kMaxNumAllocatableRegisters > x) Test_RunInt32SubWithRet(x); \ | |
392 } | |
393 | |
394 | |
395 TEST_INT32_SUB_WITH_RET(0) | |
396 TEST_INT32_SUB_WITH_RET(1) | |
397 TEST_INT32_SUB_WITH_RET(2) | |
398 TEST_INT32_SUB_WITH_RET(3) | |
399 TEST_INT32_SUB_WITH_RET(4) | |
400 TEST_INT32_SUB_WITH_RET(5) | |
401 TEST_INT32_SUB_WITH_RET(6) | |
402 TEST_INT32_SUB_WITH_RET(7) | |
403 TEST_INT32_SUB_WITH_RET(8) | |
404 TEST_INT32_SUB_WITH_RET(9) | |
405 TEST_INT32_SUB_WITH_RET(10) | |
406 TEST_INT32_SUB_WITH_RET(11) | |
407 TEST_INT32_SUB_WITH_RET(12) | |
408 TEST_INT32_SUB_WITH_RET(13) | |
409 TEST_INT32_SUB_WITH_RET(14) | |
410 TEST_INT32_SUB_WITH_RET(15) | |
411 TEST_INT32_SUB_WITH_RET(16) | |
412 TEST_INT32_SUB_WITH_RET(17) | |
413 TEST_INT32_SUB_WITH_RET(18) | |
414 TEST_INT32_SUB_WITH_RET(19) | |
415 | |
416 | |
417 TEST(Run_Int32Sub_all_allocatable_single) { | |
418 #ifdef NATIVE_STACK_PARAMS_OK | |
419 Int32Signature sig(2); | |
420 RegisterPairs pairs; | |
421 while (pairs.More()) { | |
422 Zone zone; | |
423 int parray[1]; | |
424 int rarray[1]; | |
425 pairs.Next(&rarray[0], &parray[0], true); | |
426 Allocator params(parray, 1, nullptr, 0); | |
427 Allocator rets(rarray, 1, nullptr, 0); | |
428 RegisterConfig config(params, rets); | |
429 CallDescriptor* desc = config.Create(&zone, &sig); | |
430 TestInt32Sub(desc); | |
431 } | |
432 #endif // NATIVE_STACK_PARAMS_OK | |
433 } | |
434 | |
435 | |
436 TEST(Run_CopyTwentyInt32_all_allocatable_pairs) { | |
437 #ifdef NATIVE_STACK_PARAMS_OK | |
438 Int32Signature sig(20); | |
439 RegisterPairs pairs; | |
440 while (pairs.More()) { | |
441 Zone zone; | |
442 int parray[2]; | |
443 int rarray[] = {0}; | |
444 pairs.Next(&parray[0], &parray[1], false); | |
445 Allocator params(parray, 2, nullptr, 0); | |
446 Allocator rets(rarray, 1, nullptr, 0); | |
447 RegisterConfig config(params, rets); | |
448 CallDescriptor* desc = config.Create(&zone, &sig); | |
449 CopyTwentyInt32(desc); | |
450 } | |
451 #endif // NATIVE_STACK_PARAMS_OK | |
452 } | |
453 | |
454 | |
455 #ifdef NATIVE_STACK_PARAMS_OK | |
456 int ParamCount(CallDescriptor* desc) { | |
457 return static_cast<int>(desc->GetMachineSignature()->parameter_count()); | |
458 } | |
459 | |
460 | |
461 // Super mega helper routine to generate a computation with a given | |
462 // call descriptor, compile the code, wrap the code, and pass various inputs, | |
463 // comparing against a reference implementation. | |
464 static void Run_Int32_Computation( | |
465 CallDescriptor* desc, void (*build)(CallDescriptor*, RawMachineAssembler&), | |
466 int32_t (*compute)(CallDescriptor*, int32_t* inputs), int seed = 1) { | |
467 int num_params = ParamCount(desc); | |
468 CHECK_LE(num_params, kMaxParamCount); | |
469 int32_t input[kMaxParamCount]; | |
470 Isolate* isolate = CcTest::InitIsolateOnce(); | |
471 HandleScope scope(isolate); | |
472 Handle<Code> inner = Handle<Code>::null(); | |
473 { | |
474 // Build the graph for the computation. | |
475 Zone zone; | |
476 Graph graph(&zone); | |
477 RawMachineAssembler raw(isolate, &graph, desc); | |
478 build(desc, raw); | |
479 inner = CompileGraph("Compute", desc, &graph, raw.Export()); | |
480 } | |
481 | |
482 CSignature0<int32_t> csig; | |
483 Handle<Code> wrapper = Handle<Code>::null(); | |
484 { | |
485 // Wrap the above code with a callable function that loads from {input}. | |
486 Zone zone; | |
487 Graph graph(&zone); | |
488 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); | |
489 RawMachineAssembler raw(isolate, &graph, cdesc); | |
490 Node* base = raw.PointerConstant(input); | |
491 Unique<HeapObject> unique = Unique<HeapObject>::CreateUninitialized(inner); | |
492 Node* target = raw.HeapConstant(unique); | |
493 Node** args = zone.NewArray<Node*>(kMaxParamCount); | |
494 for (int i = 0; i < num_params; i++) { | |
495 Node* offset = raw.Int32Constant(i * sizeof(int32_t)); | |
496 args[i] = raw.Load(kMachInt32, base, offset); | |
497 } | |
498 | |
499 Node* call = raw.CallN(desc, target, args); | |
500 raw.Return(call); | |
501 wrapper = CompileGraph("Compute-wrapper", cdesc, &graph, raw.Export()); | |
502 } | |
503 | |
504 CodeRunner<int32_t> runnable(isolate, wrapper, &csig); | |
505 | |
506 // Run the code, checking it against the reference. | |
507 for (int i = 0; i < 5; i++) { | |
508 // Use pseudo-random values for each run, but the first run gets args | |
509 // 100, 101, 102, 103... for easier diagnosis. | |
510 uint32_t base = 1111111111u * i * seed; | |
511 for (int j = 0; j < kMaxParamCount; j++) { | |
512 input[j] = static_cast<int32_t>(100 + base + j); | |
513 } | |
514 int32_t expected = compute(desc, input); | |
515 int32_t result = runnable.Call(); | |
516 | |
517 CHECK_EQ(expected, result); | |
518 } | |
519 } | |
520 | |
521 | |
522 static uint32_t coeff[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, | |
523 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, | |
524 79, 83, 89, 97, 101, 103, 107, 109, 113}; | |
525 | |
526 | |
527 static void Build_Int32_WeightedSum(CallDescriptor* desc, | |
528 RawMachineAssembler& raw) { | |
529 Node* result = raw.Int32Constant(0); | |
530 for (int i = 0; i < ParamCount(desc); i++) { | |
531 Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i])); | |
532 result = raw.Int32Add(result, term); | |
533 } | |
534 raw.Return(result); | |
535 } | |
536 | |
537 | |
538 static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) { | |
539 uint32_t result = 0; | |
540 for (int i = 0; i < ParamCount(desc); i++) { | |
541 result += static_cast<uint32_t>(input[i]) * coeff[i]; | |
542 } | |
543 return static_cast<int32_t>(result); | |
544 } | |
545 | |
546 | |
547 static void Test_Int32_WeightedSum_of_size(int count) { | |
548 Int32Signature sig(count); | |
549 for (int p0 = 0; p0 < Register::kMaxNumAllocatableRegisters; p0++) { | |
550 Zone zone; | |
551 | |
552 int parray[] = {p0}; | |
553 int rarray[] = {0}; | |
554 Allocator params(parray, 1, nullptr, 0); | |
555 Allocator rets(rarray, 1, nullptr, 0); | |
556 RegisterConfig config(params, rets); | |
557 CallDescriptor* desc = config.Create(&zone, &sig); | |
558 Run_Int32_Computation(desc, Build_Int32_WeightedSum, | |
559 Compute_Int32_WeightedSum, 257 + count); | |
560 } | |
561 } | |
562 | |
563 | |
564 // Separate tests for parallelization. | |
565 #define TEST_INT32_WEIGHTEDSUM(x) \ | |
566 TEST(Run_Int32_WeightedSum_##x) { Test_Int32_WeightedSum_of_size(x); } | |
567 | |
568 | |
569 TEST_INT32_WEIGHTEDSUM(1) | |
570 TEST_INT32_WEIGHTEDSUM(2) | |
571 TEST_INT32_WEIGHTEDSUM(3) | |
572 TEST_INT32_WEIGHTEDSUM(4) | |
573 TEST_INT32_WEIGHTEDSUM(5) | |
574 TEST_INT32_WEIGHTEDSUM(7) | |
575 TEST_INT32_WEIGHTEDSUM(9) | |
576 TEST_INT32_WEIGHTEDSUM(11) | |
577 TEST_INT32_WEIGHTEDSUM(17) | |
578 TEST_INT32_WEIGHTEDSUM(19) | |
579 | |
580 | |
581 template <int which> | |
582 static void Build_Int32_Select(CallDescriptor* desc, RawMachineAssembler& raw) { | |
583 raw.Return(raw.Parameter(which)); | |
584 } | |
585 | |
586 | |
587 template <int which> | |
588 static int32_t Compute_Int32_Select(CallDescriptor* desc, int32_t* inputs) { | |
589 return inputs[which]; | |
590 } | |
591 | |
592 | |
593 template <int which> | |
594 void Test_Int32_Select() { | |
595 int parray[] = {0}; | |
596 int rarray[] = {0}; | |
597 Allocator params(parray, 1, nullptr, 0); | |
598 Allocator rets(rarray, 1, nullptr, 0); | |
599 RegisterConfig config(params, rets); | |
600 | |
601 Zone zone; | |
602 for (int i = which + 1; i <= 64; i++) { | |
603 Int32Signature sig(i); | |
604 CallDescriptor* desc = config.Create(&zone, &sig); | |
605 Run_Int32_Computation(desc, Build_Int32_Select<which>, | |
606 Compute_Int32_Select<which>, 1025 + which); | |
607 } | |
608 } | |
609 | |
610 | |
611 // Separate tests for parallelization. | |
612 #define TEST_INT32_SELECT(x) \ | |
613 TEST(Run_Int32_Select_##x) { Test_Int32_Select<x>(); } | |
614 | |
615 | |
616 TEST_INT32_SELECT(0) | |
617 TEST_INT32_SELECT(1) | |
618 TEST_INT32_SELECT(2) | |
619 TEST_INT32_SELECT(3) | |
620 TEST_INT32_SELECT(4) | |
621 TEST_INT32_SELECT(5) | |
622 TEST_INT32_SELECT(6) | |
623 TEST_INT32_SELECT(11) | |
624 TEST_INT32_SELECT(15) | |
625 TEST_INT32_SELECT(19) | |
626 TEST_INT32_SELECT(45) | |
627 TEST_INT32_SELECT(62) | |
628 TEST_INT32_SELECT(63) | |
629 #endif // NATIVE_STACK_PARAMS_OK | |
630 | |
631 | |
632 TEST(TheLastTestForLint) { | |
633 // Yes, thank you. | |
634 } | |
OLD | NEW |