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 |
| 484 if (false) { |
| 485 // constant mode. |
| 486 Handle<Code> wrapper = Handle<Code>::null(); |
| 487 { |
| 488 // Wrap the above code with a callable function that passes constants. |
| 489 Zone zone; |
| 490 Graph graph(&zone); |
| 491 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); |
| 492 RawMachineAssembler raw(isolate, &graph, cdesc); |
| 493 Unique<HeapObject> unique = |
| 494 Unique<HeapObject>::CreateUninitialized(inner); |
| 495 Node* target = raw.HeapConstant(unique); |
| 496 Node** args = zone.NewArray<Node*>(kMaxParamCount); |
| 497 for (int i = 0; i < num_params; i++) { |
| 498 args[i] = raw.Int32Constant(0x100 + i); |
| 499 } |
| 500 |
| 501 Node* call = raw.CallN(desc, target, args); |
| 502 raw.Return(call); |
| 503 wrapper = CompileGraph("Compute-wrapper", cdesc, &graph, raw.Export()); |
| 504 } |
| 505 |
| 506 CodeRunner<int32_t> runnable(isolate, wrapper, &csig); |
| 507 |
| 508 // Run the code, checking it against the reference. |
| 509 for (int j = 0; j < kMaxParamCount; j++) { |
| 510 input[j] = 0x100 + j; |
| 511 } |
| 512 int32_t expected = compute(desc, input); |
| 513 int32_t result = runnable.Call(); |
| 514 |
| 515 CHECK_EQ(expected, result); |
| 516 } |
| 517 |
| 518 { |
| 519 // buffer mode. |
| 520 Handle<Code> wrapper = Handle<Code>::null(); |
| 521 { |
| 522 // Wrap the above code with a callable function that loads from {input}. |
| 523 Zone zone; |
| 524 Graph graph(&zone); |
| 525 CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); |
| 526 RawMachineAssembler raw(isolate, &graph, cdesc); |
| 527 Node* base = raw.PointerConstant(input); |
| 528 Unique<HeapObject> unique = |
| 529 Unique<HeapObject>::CreateUninitialized(inner); |
| 530 Node* target = raw.HeapConstant(unique); |
| 531 Node** args = zone.NewArray<Node*>(kMaxParamCount); |
| 532 for (int i = 0; i < num_params; i++) { |
| 533 Node* offset = raw.Int32Constant(i * sizeof(int32_t)); |
| 534 args[i] = raw.Load(kMachInt32, base, offset); |
| 535 } |
| 536 |
| 537 Node* call = raw.CallN(desc, target, args); |
| 538 raw.Return(call); |
| 539 wrapper = CompileGraph("Compute-wrapper", cdesc, &graph, raw.Export()); |
| 540 } |
| 541 |
| 542 CodeRunner<int32_t> runnable(isolate, wrapper, &csig); |
| 543 |
| 544 // Run the code, checking it against the reference. |
| 545 for (int i = 0; i < 5; i++) { |
| 546 // Use pseudo-random values for each run, but the first run gets args |
| 547 // 100, 101, 102, 103... for easier diagnosis. |
| 548 uint32_t base = 1111111111u * i * seed; |
| 549 for (int j = 0; j < kMaxParamCount; j++) { |
| 550 input[j] = static_cast<int32_t>(100 + base + j); |
| 551 } |
| 552 int32_t expected = compute(desc, input); |
| 553 int32_t result = runnable.Call(); |
| 554 |
| 555 CHECK_EQ(expected, result); |
| 556 } |
| 557 } |
| 558 } |
| 559 |
| 560 |
| 561 static uint32_t coeff[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, |
| 562 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, |
| 563 79, 83, 89, 97, 101, 103, 107, 109, 113}; |
| 564 |
| 565 |
| 566 static void Build_Int32_WeightedSum(CallDescriptor* desc, |
| 567 RawMachineAssembler& raw) { |
| 568 Node* result = raw.Int32Constant(0); |
| 569 for (int i = 0; i < ParamCount(desc); i++) { |
| 570 Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i])); |
| 571 result = raw.Int32Add(result, term); |
| 572 } |
| 573 raw.Return(result); |
| 574 } |
| 575 |
| 576 |
| 577 static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) { |
| 578 uint32_t result = 0; |
| 579 for (int i = 0; i < ParamCount(desc); i++) { |
| 580 result += static_cast<uint32_t>(input[i]) * coeff[i]; |
| 581 } |
| 582 return static_cast<int32_t>(result); |
| 583 } |
| 584 |
| 585 |
| 586 static void Test_Int32_WeightedSum_of_size(int count) { |
| 587 Int32Signature sig(count); |
| 588 for (int p0 = 0; p0 < Register::kMaxNumAllocatableRegisters; p0++) { |
| 589 Zone zone; |
| 590 |
| 591 int parray[] = {p0}; |
| 592 int rarray[] = {0}; |
| 593 Allocator params(parray, 1, nullptr, 0); |
| 594 Allocator rets(rarray, 1, nullptr, 0); |
| 595 RegisterConfig config(params, rets); |
| 596 CallDescriptor* desc = config.Create(&zone, &sig); |
| 597 Run_Int32_Computation(desc, Build_Int32_WeightedSum, |
| 598 Compute_Int32_WeightedSum, 257 + count); |
| 599 } |
| 600 } |
| 601 |
| 602 |
| 603 // Separate tests for parallelization. |
| 604 #define TEST_INT32_WEIGHTEDSUM(x) \ |
| 605 TEST(Run_Int32_WeightedSum_##x) { Test_Int32_WeightedSum_of_size(x); } |
| 606 |
| 607 |
| 608 TEST_INT32_WEIGHTEDSUM(1) |
| 609 TEST_INT32_WEIGHTEDSUM(2) |
| 610 TEST_INT32_WEIGHTEDSUM(3) |
| 611 TEST_INT32_WEIGHTEDSUM(4) |
| 612 TEST_INT32_WEIGHTEDSUM(5) |
| 613 TEST_INT32_WEIGHTEDSUM(7) |
| 614 TEST_INT32_WEIGHTEDSUM(9) |
| 615 TEST_INT32_WEIGHTEDSUM(11) |
| 616 TEST_INT32_WEIGHTEDSUM(17) |
| 617 TEST_INT32_WEIGHTEDSUM(19) |
| 618 |
| 619 |
| 620 template <int which> |
| 621 static void Build_Int32_Select(CallDescriptor* desc, RawMachineAssembler& raw) { |
| 622 raw.Return(raw.Parameter(which)); |
| 623 } |
| 624 |
| 625 |
| 626 template <int which> |
| 627 static int32_t Compute_Int32_Select(CallDescriptor* desc, int32_t* inputs) { |
| 628 return inputs[which]; |
| 629 } |
| 630 |
| 631 |
| 632 template <int which> |
| 633 void Test_Int32_Select() { |
| 634 int parray[] = {0}; |
| 635 int rarray[] = {0}; |
| 636 Allocator params(parray, 1, nullptr, 0); |
| 637 Allocator rets(rarray, 1, nullptr, 0); |
| 638 RegisterConfig config(params, rets); |
| 639 |
| 640 Zone zone; |
| 641 |
| 642 for (int i = which + 1; i <= 64; i++) { |
| 643 Int32Signature sig(i); |
| 644 CallDescriptor* desc = config.Create(&zone, &sig); |
| 645 Run_Int32_Computation(desc, Build_Int32_Select<which>, |
| 646 Compute_Int32_Select<which>, 1025 + which); |
| 647 } |
| 648 } |
| 649 |
| 650 |
| 651 // Separate tests for parallelization. |
| 652 #define TEST_INT32_SELECT(x) \ |
| 653 TEST(Run_Int32_Select_##x) { Test_Int32_Select<x>(); } |
| 654 |
| 655 |
| 656 TEST_INT32_SELECT(0) |
| 657 TEST_INT32_SELECT(1) |
| 658 TEST_INT32_SELECT(2) |
| 659 TEST_INT32_SELECT(3) |
| 660 TEST_INT32_SELECT(4) |
| 661 TEST_INT32_SELECT(5) |
| 662 TEST_INT32_SELECT(6) |
| 663 TEST_INT32_SELECT(11) |
| 664 TEST_INT32_SELECT(15) |
| 665 TEST_INT32_SELECT(19) |
| 666 TEST_INT32_SELECT(45) |
| 667 TEST_INT32_SELECT(62) |
| 668 TEST_INT32_SELECT(63) |
| 669 #endif // NATIVE_STACK_PARAMS_OK |
| 670 |
| 671 |
| 672 TEST(TheLastTestForLint) { |
| 673 // Yes, thank you. |
| 674 } |
OLD | NEW |