Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1 | // Copyright 2015 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/raw-machine-assembler.h" |
| 9 | #include "src/machine-type.h" |
| 10 | #include "src/register-configuration.h" |
| 11 | |
| 12 | #include "test/cctest/cctest.h" |
| 13 | #include "test/cctest/compiler/codegen-tester.h" |
| 14 | #include "test/cctest/compiler/graph-builder-tester.h" |
| 15 | #include "test/cctest/compiler/value-helper.h" |
| 16 | |
| 17 | namespace v8 { |
| 18 | namespace internal { |
| 19 | namespace compiler { |
| 20 | |
| 21 | namespace { |
| 22 | typedef float float32; |
| 23 | typedef double float64; |
| 24 | |
| 25 | // Picks a representative pair of integers from the given range. |
| 26 | // If there are less than {max_pairs} possible pairs, do them all, otherwise try |
| 27 | // to select a representative set. |
| 28 | class Pairs { |
| 29 | public: |
| 30 | Pairs(int max_pairs, int range, const int* codes) |
| 31 | : range_(range), |
| 32 | codes_(codes), |
| 33 | max_pairs_(std::min(max_pairs, range_ * range_)), |
| 34 | counter_(0) {} |
| 35 | |
| 36 | bool More() { return counter_ < max_pairs_; } |
| 37 | |
| 38 | void Next(int* r0, int* r1, bool same_is_ok) { |
| 39 | do { |
| 40 | // Find the next pair. |
| 41 | if (exhaustive()) { |
| 42 | *r0 = codes_[counter_ % range_]; |
| 43 | *r1 = codes_[counter_ / range_]; |
| 44 | } else { |
| 45 | // Try each integer at least once for both r0 and r1. |
| 46 | int index = counter_ / 2; |
| 47 | if (counter_ & 1) { |
| 48 | *r0 = codes_[index % range_]; |
| 49 | *r1 = codes_[index / range_]; |
| 50 | } else { |
| 51 | *r1 = codes_[index % range_]; |
| 52 | *r0 = codes_[index / range_]; |
| 53 | } |
| 54 | } |
| 55 | counter_++; |
| 56 | if ((same_is_ok) || (*r0 != *r1)) break; |
| 57 | if (counter_ == max_pairs_) { |
| 58 | // For the last hurrah, reg#0 with reg#n-1 |
| 59 | *r0 = codes_[0]; |
| 60 | *r1 = codes_[range_ - 1]; |
| 61 | break; |
| 62 | } |
| 63 | } while (true); |
| 64 | } |
| 65 | |
| 66 | private: |
| 67 | int range_; |
| 68 | const int* codes_; |
| 69 | int max_pairs_; |
| 70 | int counter_; |
| 71 | bool exhaustive() { return max_pairs_ == (range_ * range_); } |
| 72 | }; |
| 73 | |
| 74 | |
| 75 | // Pairs of general purpose registers. |
| 76 | class RegisterPairs : public Pairs { |
| 77 | public: |
| 78 | RegisterPairs() |
| 79 | : Pairs( |
| 80 | 100, |
| 81 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 82 | ->num_allocatable_general_registers(), |
| 83 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 84 | ->allocatable_general_codes()) {} |
| 85 | }; |
| 86 | |
| 87 | |
| 88 | // Pairs of double registers. |
| 89 | class Float32RegisterPairs : public Pairs { |
| 90 | public: |
| 91 | Float32RegisterPairs() |
| 92 | : Pairs( |
| 93 | 100, |
| 94 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 95 | ->num_allocatable_aliased_double_registers(), |
| 96 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 97 | ->allocatable_double_codes()) {} |
| 98 | }; |
| 99 | |
| 100 | |
| 101 | // Pairs of double registers. |
| 102 | class Float64RegisterPairs : public Pairs { |
| 103 | public: |
| 104 | Float64RegisterPairs() |
| 105 | : Pairs( |
| 106 | 100, |
| 107 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 108 | ->num_allocatable_aliased_double_registers(), |
| 109 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 110 | ->allocatable_double_codes()) {} |
| 111 | }; |
| 112 | |
| 113 | |
| 114 | // Helper for allocating either an GP or FP reg, or the next stack slot. |
| 115 | struct Allocator { |
| 116 | Allocator(int* gp, int gpc, int* fp, int fpc) |
| 117 | : gp_count(gpc), |
| 118 | gp_offset(0), |
| 119 | gp_regs(gp), |
| 120 | fp_count(fpc), |
| 121 | fp_offset(0), |
| 122 | fp_regs(fp), |
| 123 | stack_offset(0) {} |
| 124 | |
| 125 | int gp_count; |
| 126 | int gp_offset; |
| 127 | int* gp_regs; |
| 128 | |
| 129 | int fp_count; |
| 130 | int fp_offset; |
| 131 | int* fp_regs; |
| 132 | |
| 133 | int stack_offset; |
| 134 | |
| 135 | LinkageLocation Next(MachineType type) { |
| 136 | if (IsFloatingPoint(type.representation())) { |
| 137 | // Allocate a floating point register/stack location. |
| 138 | if (fp_offset < fp_count) { |
| 139 | return LinkageLocation::ForRegister(fp_regs[fp_offset++]); |
| 140 | } else { |
| 141 | int offset = -1 - stack_offset; |
| 142 | stack_offset += StackWords(type); |
| 143 | return LinkageLocation::ForCallerFrameSlot(offset); |
| 144 | } |
| 145 | } else { |
| 146 | // Allocate a general purpose register/stack location. |
| 147 | if (gp_offset < gp_count) { |
| 148 | return LinkageLocation::ForRegister(gp_regs[gp_offset++]); |
| 149 | } else { |
| 150 | int offset = -1 - stack_offset; |
| 151 | stack_offset += StackWords(type); |
| 152 | return LinkageLocation::ForCallerFrameSlot(offset); |
| 153 | } |
| 154 | } |
| 155 | } |
| 156 | int StackWords(MachineType type) { |
| 157 | // TODO(titzer): hack. float32 occupies 8 bytes on stack. |
| 158 | int size = IsFloatingPoint(type.representation()) |
| 159 | ? kDoubleSize |
| 160 | : (1 << ElementSizeLog2Of(type.representation())); |
| 161 | return size <= kPointerSize ? 1 : size / kPointerSize; |
| 162 | } |
| 163 | void Reset() { |
| 164 | fp_offset = 0; |
| 165 | gp_offset = 0; |
| 166 | stack_offset = 0; |
| 167 | } |
| 168 | }; |
| 169 | |
| 170 | |
| 171 | class RegisterConfig { |
| 172 | public: |
| 173 | RegisterConfig(Allocator& p, Allocator& r) : params(p), rets(r) {} |
| 174 | |
| 175 | CallDescriptor* Create(Zone* zone, MachineSignature* msig) { |
| 176 | rets.Reset(); |
| 177 | params.Reset(); |
| 178 | |
| 179 | LocationSignature::Builder locations(zone, msig->return_count(), |
| 180 | msig->parameter_count()); |
| 181 | // Add return location(s). |
| 182 | const int return_count = static_cast<int>(locations.return_count_); |
| 183 | for (int i = 0; i < return_count; i++) { |
| 184 | locations.AddReturn(rets.Next(msig->GetReturn(i))); |
| 185 | } |
| 186 | |
| 187 | // Add register and/or stack parameter(s). |
| 188 | const int parameter_count = static_cast<int>(msig->parameter_count()); |
| 189 | for (int i = 0; i < parameter_count; i++) { |
| 190 | locations.AddParam(params.Next(msig->GetParam(i))); |
| 191 | } |
| 192 | |
| 193 | const RegList kCalleeSaveRegisters = 0; |
| 194 | const RegList kCalleeSaveFPRegisters = 0; |
| 195 | |
| 196 | MachineType target_type = MachineType::AnyTagged(); |
| 197 | LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); |
| 198 | int stack_param_count = params.stack_offset; |
| 199 | return new (zone) CallDescriptor( // -- |
| 200 | CallDescriptor::kCallCodeObject, // kind |
| 201 | target_type, // target MachineType |
| 202 | target_loc, // target location |
| 203 | msig, // machine_sig |
| 204 | locations.Build(), // location_sig |
| 205 | stack_param_count, // stack_parameter_count |
| 206 | compiler::Operator::kNoProperties, // properties |
| 207 | kCalleeSaveRegisters, // callee-saved registers |
| 208 | kCalleeSaveFPRegisters, // callee-saved fp regs |
| 209 | CallDescriptor::kUseNativeStack, // flags |
| 210 | "c-call"); |
| 211 | } |
| 212 | |
| 213 | private: |
| 214 | Allocator& params; |
| 215 | Allocator& rets; |
| 216 | }; |
| 217 | |
| 218 | const int kMaxParamCount = 64; |
| 219 | |
| 220 | MachineType kIntTypes[kMaxParamCount + 1] = { |
| 221 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 222 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 223 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 224 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 225 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 226 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 227 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 228 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 229 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 230 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 231 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 232 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 233 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 234 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 235 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 236 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 237 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 238 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 239 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 240 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 241 | MachineType::Int32(), MachineType::Int32(), MachineType::Int32(), |
| 242 | MachineType::Int32(), MachineType::Int32()}; |
| 243 | |
| 244 | |
| 245 | // For making uniform int32 signatures shorter. |
| 246 | class Int32Signature : public MachineSignature { |
| 247 | public: |
| 248 | explicit Int32Signature(int param_count) |
| 249 | : MachineSignature(1, param_count, kIntTypes) { |
| 250 | CHECK(param_count <= kMaxParamCount); |
| 251 | } |
| 252 | }; |
| 253 | |
| 254 | |
| 255 | Handle<Code> CompileGraph(const char* name, CallDescriptor* desc, Graph* graph, |
| 256 | Schedule* schedule = nullptr) { |
| 257 | Isolate* isolate = CcTest::InitIsolateOnce(); |
| 258 | CompilationInfo info("testing", isolate, graph->zone()); |
| 259 | Handle<Code> code = |
| 260 | Pipeline::GenerateCodeForTesting(&info, desc, graph, schedule); |
| 261 | CHECK(!code.is_null()); |
| 262 | #ifdef ENABLE_DISASSEMBLER |
| 263 | if (FLAG_print_opt_code) { |
| 264 | OFStream os(stdout); |
| 265 | code->Disassemble(name, os); |
| 266 | } |
| 267 | #endif |
| 268 | return code; |
| 269 | } |
| 270 | |
| 271 | |
| 272 | Handle<Code> WrapWithCFunction(Handle<Code> inner, CallDescriptor* desc) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 273 | Zone zone(inner->GetIsolate()->allocator()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 274 | MachineSignature* msig = |
| 275 | const_cast<MachineSignature*>(desc->GetMachineSignature()); |
| 276 | int param_count = static_cast<int>(msig->parameter_count()); |
| 277 | GraphAndBuilders caller(&zone); |
| 278 | { |
| 279 | GraphAndBuilders& b = caller; |
| 280 | Node* start = b.graph()->NewNode(b.common()->Start(param_count + 3)); |
| 281 | b.graph()->SetStart(start); |
| 282 | Node* target = b.graph()->NewNode(b.common()->HeapConstant(inner)); |
| 283 | |
| 284 | // Add arguments to the call. |
| 285 | Node** args = zone.NewArray<Node*>(param_count + 3); |
| 286 | int index = 0; |
| 287 | args[index++] = target; |
| 288 | for (int i = 0; i < param_count; i++) { |
| 289 | args[index] = b.graph()->NewNode(b.common()->Parameter(i), start); |
| 290 | index++; |
| 291 | } |
| 292 | args[index++] = start; // effect. |
| 293 | args[index++] = start; // control. |
| 294 | |
| 295 | // Build the call and return nodes. |
| 296 | Node* call = |
| 297 | b.graph()->NewNode(b.common()->Call(desc), param_count + 3, args); |
| 298 | Node* ret = b.graph()->NewNode(b.common()->Return(), call, call, start); |
| 299 | b.graph()->SetEnd(ret); |
| 300 | } |
| 301 | |
| 302 | CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, msig); |
| 303 | |
| 304 | return CompileGraph("wrapper", cdesc, caller.graph()); |
| 305 | } |
| 306 | |
| 307 | |
| 308 | template <typename CType> |
| 309 | class ArgsBuffer { |
| 310 | public: |
| 311 | static const int kMaxParamCount = 64; |
| 312 | |
| 313 | explicit ArgsBuffer(int count, int seed = 1) : count_(count), seed_(seed) { |
| 314 | // initialize the buffer with "seed 0" |
| 315 | seed_ = 0; |
| 316 | Mutate(); |
| 317 | seed_ = seed; |
| 318 | } |
| 319 | |
| 320 | class Sig : public MachineSignature { |
| 321 | public: |
| 322 | explicit Sig(int param_count) |
| 323 | : MachineSignature(1, param_count, MachTypes()) { |
| 324 | CHECK(param_count <= kMaxParamCount); |
| 325 | } |
| 326 | }; |
| 327 | |
| 328 | static MachineType* MachTypes() { |
| 329 | MachineType t = MachineTypeForC<CType>(); |
| 330 | static MachineType kTypes[kMaxParamCount + 1] = { |
| 331 | t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, |
| 332 | t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, |
| 333 | t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t}; |
| 334 | return kTypes; |
| 335 | } |
| 336 | |
| 337 | Node* MakeConstant(RawMachineAssembler& raw, int32_t value) { |
| 338 | return raw.Int32Constant(value); |
| 339 | } |
| 340 | |
| 341 | Node* MakeConstant(RawMachineAssembler& raw, int64_t value) { |
| 342 | return raw.Int64Constant(value); |
| 343 | } |
| 344 | |
| 345 | Node* MakeConstant(RawMachineAssembler& raw, float32 value) { |
| 346 | return raw.Float32Constant(value); |
| 347 | } |
| 348 | |
| 349 | Node* MakeConstant(RawMachineAssembler& raw, float64 value) { |
| 350 | return raw.Float64Constant(value); |
| 351 | } |
| 352 | |
| 353 | Node* LoadInput(RawMachineAssembler& raw, Node* base, int index) { |
| 354 | Node* offset = raw.Int32Constant(index * sizeof(CType)); |
| 355 | return raw.Load(MachineTypeForC<CType>(), base, offset); |
| 356 | } |
| 357 | |
| 358 | Node* StoreOutput(RawMachineAssembler& raw, Node* value) { |
| 359 | Node* base = raw.PointerConstant(&output); |
| 360 | Node* offset = raw.Int32Constant(0); |
| 361 | return raw.Store(MachineTypeForC<CType>().representation(), base, offset, |
| 362 | value, kNoWriteBarrier); |
| 363 | } |
| 364 | |
| 365 | // Computes the next set of inputs by updating the {input} array. |
| 366 | void Mutate(); |
| 367 | |
| 368 | void Reset() { memset(input, 0, sizeof(input)); } |
| 369 | |
| 370 | int count_; |
| 371 | int seed_; |
| 372 | CType input[kMaxParamCount]; |
| 373 | CType output; |
| 374 | }; |
| 375 | |
| 376 | |
| 377 | template <> |
| 378 | void ArgsBuffer<int32_t>::Mutate() { |
| 379 | uint32_t base = 1111111111u * seed_; |
| 380 | for (int j = 0; j < count_ && j < kMaxParamCount; j++) { |
| 381 | input[j] = static_cast<int32_t>(256 + base + j + seed_ * 13); |
| 382 | } |
| 383 | output = -1; |
| 384 | seed_++; |
| 385 | } |
| 386 | |
| 387 | |
| 388 | template <> |
| 389 | void ArgsBuffer<int64_t>::Mutate() { |
| 390 | uint64_t base = 11111111111111111ull * seed_; |
| 391 | for (int j = 0; j < count_ && j < kMaxParamCount; j++) { |
| 392 | input[j] = static_cast<int64_t>(256 + base + j + seed_ * 13); |
| 393 | } |
| 394 | output = -1; |
| 395 | seed_++; |
| 396 | } |
| 397 | |
| 398 | |
| 399 | template <> |
| 400 | void ArgsBuffer<float32>::Mutate() { |
| 401 | float64 base = -33.25 * seed_; |
| 402 | for (int j = 0; j < count_ && j < kMaxParamCount; j++) { |
| 403 | input[j] = 256 + base + j + seed_ * 13; |
| 404 | } |
| 405 | output = std::numeric_limits<float32>::quiet_NaN(); |
| 406 | seed_++; |
| 407 | } |
| 408 | |
| 409 | |
| 410 | template <> |
| 411 | void ArgsBuffer<float64>::Mutate() { |
| 412 | float64 base = -111.25 * seed_; |
| 413 | for (int j = 0; j < count_ && j < kMaxParamCount; j++) { |
| 414 | input[j] = 256 + base + j + seed_ * 13; |
| 415 | } |
| 416 | output = std::numeric_limits<float64>::quiet_NaN(); |
| 417 | seed_++; |
| 418 | } |
| 419 | |
| 420 | |
| 421 | int ParamCount(CallDescriptor* desc) { |
| 422 | return static_cast<int>(desc->GetMachineSignature()->parameter_count()); |
| 423 | } |
| 424 | |
| 425 | |
| 426 | template <typename CType> |
| 427 | class Computer { |
| 428 | public: |
| 429 | static void Run(CallDescriptor* desc, |
| 430 | void (*build)(CallDescriptor*, RawMachineAssembler&), |
| 431 | CType (*compute)(CallDescriptor*, CType* inputs), |
| 432 | int seed = 1) { |
| 433 | int num_params = ParamCount(desc); |
| 434 | CHECK_LE(num_params, kMaxParamCount); |
| 435 | Isolate* isolate = CcTest::InitIsolateOnce(); |
| 436 | HandleScope scope(isolate); |
| 437 | Handle<Code> inner = Handle<Code>::null(); |
| 438 | { |
| 439 | // Build the graph for the computation. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 440 | Zone zone(isolate->allocator()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 441 | Graph graph(&zone); |
| 442 | RawMachineAssembler raw(isolate, &graph, desc); |
| 443 | build(desc, raw); |
| 444 | inner = CompileGraph("Compute", desc, &graph, raw.Export()); |
| 445 | } |
| 446 | |
| 447 | CSignature0<int32_t> csig; |
| 448 | ArgsBuffer<CType> io(num_params, seed); |
| 449 | |
| 450 | { |
| 451 | // constant mode. |
| 452 | Handle<Code> wrapper = Handle<Code>::null(); |
| 453 | { |
| 454 | // Wrap the above code with a callable function that passes constants. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 455 | Zone zone(isolate->allocator()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 456 | Graph graph(&zone); |
| 457 | CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); |
| 458 | RawMachineAssembler raw(isolate, &graph, cdesc); |
| 459 | Node* target = raw.HeapConstant(inner); |
| 460 | Node** args = zone.NewArray<Node*>(num_params); |
| 461 | for (int i = 0; i < num_params; i++) { |
| 462 | args[i] = io.MakeConstant(raw, io.input[i]); |
| 463 | } |
| 464 | |
| 465 | Node* call = raw.CallN(desc, target, args); |
| 466 | Node* store = io.StoreOutput(raw, call); |
| 467 | USE(store); |
| 468 | raw.Return(raw.Int32Constant(seed)); |
| 469 | wrapper = |
| 470 | CompileGraph("Compute-wrapper-const", cdesc, &graph, raw.Export()); |
| 471 | } |
| 472 | |
| 473 | CodeRunner<int32_t> runnable(isolate, wrapper, &csig); |
| 474 | |
| 475 | // Run the code, checking it against the reference. |
| 476 | CType expected = compute(desc, io.input); |
| 477 | int32_t check_seed = runnable.Call(); |
| 478 | CHECK_EQ(seed, check_seed); |
| 479 | CHECK_EQ(expected, io.output); |
| 480 | } |
| 481 | |
| 482 | { |
| 483 | // buffer mode. |
| 484 | Handle<Code> wrapper = Handle<Code>::null(); |
| 485 | { |
| 486 | // Wrap the above code with a callable function that loads from {input}. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 487 | Zone zone(isolate->allocator()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 488 | Graph graph(&zone); |
| 489 | CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); |
| 490 | RawMachineAssembler raw(isolate, &graph, cdesc); |
| 491 | Node* base = raw.PointerConstant(io.input); |
| 492 | Node* target = raw.HeapConstant(inner); |
| 493 | Node** args = zone.NewArray<Node*>(kMaxParamCount); |
| 494 | for (int i = 0; i < num_params; i++) { |
| 495 | args[i] = io.LoadInput(raw, base, i); |
| 496 | } |
| 497 | |
| 498 | Node* call = raw.CallN(desc, target, args); |
| 499 | Node* store = io.StoreOutput(raw, call); |
| 500 | USE(store); |
| 501 | raw.Return(raw.Int32Constant(seed)); |
| 502 | wrapper = CompileGraph("Compute-wrapper", cdesc, &graph, raw.Export()); |
| 503 | } |
| 504 | |
| 505 | CodeRunner<int32_t> runnable(isolate, wrapper, &csig); |
| 506 | |
| 507 | // Run the code, checking it against the reference. |
| 508 | for (int i = 0; i < 5; i++) { |
| 509 | CType expected = compute(desc, io.input); |
| 510 | int32_t check_seed = runnable.Call(); |
| 511 | CHECK_EQ(seed, check_seed); |
| 512 | CHECK_EQ(expected, io.output); |
| 513 | io.Mutate(); |
| 514 | } |
| 515 | } |
| 516 | } |
| 517 | }; |
| 518 | |
| 519 | } // namespace |
| 520 | |
| 521 | |
| 522 | static void TestInt32Sub(CallDescriptor* desc) { |
| 523 | Isolate* isolate = CcTest::InitIsolateOnce(); |
| 524 | HandleScope scope(isolate); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 525 | Zone zone(isolate->allocator()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 526 | GraphAndBuilders inner(&zone); |
| 527 | { |
| 528 | // Build the add function. |
| 529 | GraphAndBuilders& b = inner; |
| 530 | Node* start = b.graph()->NewNode(b.common()->Start(5)); |
| 531 | b.graph()->SetStart(start); |
| 532 | Node* p0 = b.graph()->NewNode(b.common()->Parameter(0), start); |
| 533 | Node* p1 = b.graph()->NewNode(b.common()->Parameter(1), start); |
| 534 | Node* add = b.graph()->NewNode(b.machine()->Int32Sub(), p0, p1); |
| 535 | Node* ret = b.graph()->NewNode(b.common()->Return(), add, start, start); |
| 536 | b.graph()->SetEnd(ret); |
| 537 | } |
| 538 | |
| 539 | Handle<Code> inner_code = CompileGraph("Int32Sub", desc, inner.graph()); |
| 540 | Handle<Code> wrapper = WrapWithCFunction(inner_code, desc); |
| 541 | MachineSignature* msig = |
| 542 | const_cast<MachineSignature*>(desc->GetMachineSignature()); |
| 543 | CodeRunner<int32_t> runnable(isolate, wrapper, |
| 544 | CSignature::FromMachine(&zone, msig)); |
| 545 | |
| 546 | FOR_INT32_INPUTS(i) { |
| 547 | FOR_INT32_INPUTS(j) { |
| 548 | int32_t expected = static_cast<int32_t>(static_cast<uint32_t>(*i) - |
| 549 | static_cast<uint32_t>(*j)); |
| 550 | int32_t result = runnable.Call(*i, *j); |
| 551 | CHECK_EQ(expected, result); |
| 552 | } |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | |
| 557 | static void CopyTwentyInt32(CallDescriptor* desc) { |
| 558 | const int kNumParams = 20; |
| 559 | int32_t input[kNumParams]; |
| 560 | int32_t output[kNumParams]; |
| 561 | Isolate* isolate = CcTest::InitIsolateOnce(); |
| 562 | HandleScope scope(isolate); |
| 563 | Handle<Code> inner = Handle<Code>::null(); |
| 564 | { |
| 565 | // Writes all parameters into the output buffer. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 566 | Zone zone(isolate->allocator()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 567 | Graph graph(&zone); |
| 568 | RawMachineAssembler raw(isolate, &graph, desc); |
| 569 | Node* base = raw.PointerConstant(output); |
| 570 | for (int i = 0; i < kNumParams; i++) { |
| 571 | Node* offset = raw.Int32Constant(i * sizeof(int32_t)); |
| 572 | raw.Store(MachineRepresentation::kWord32, base, offset, raw.Parameter(i), |
| 573 | kNoWriteBarrier); |
| 574 | } |
| 575 | raw.Return(raw.Int32Constant(42)); |
| 576 | inner = CompileGraph("CopyTwentyInt32", desc, &graph, raw.Export()); |
| 577 | } |
| 578 | |
| 579 | CSignature0<int32_t> csig; |
| 580 | Handle<Code> wrapper = Handle<Code>::null(); |
| 581 | { |
| 582 | // Loads parameters from the input buffer and calls the above code. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 583 | Zone zone(isolate->allocator()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 584 | Graph graph(&zone); |
| 585 | CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); |
| 586 | RawMachineAssembler raw(isolate, &graph, cdesc); |
| 587 | Node* base = raw.PointerConstant(input); |
| 588 | Node* target = raw.HeapConstant(inner); |
| 589 | Node** args = zone.NewArray<Node*>(kNumParams); |
| 590 | for (int i = 0; i < kNumParams; i++) { |
| 591 | Node* offset = raw.Int32Constant(i * sizeof(int32_t)); |
| 592 | args[i] = raw.Load(MachineType::Int32(), base, offset); |
| 593 | } |
| 594 | |
| 595 | Node* call = raw.CallN(desc, target, args); |
| 596 | raw.Return(call); |
| 597 | wrapper = |
| 598 | CompileGraph("CopyTwentyInt32-wrapper", cdesc, &graph, raw.Export()); |
| 599 | } |
| 600 | |
| 601 | CodeRunner<int32_t> runnable(isolate, wrapper, &csig); |
| 602 | |
| 603 | // Run the code, checking it correctly implements the memcpy. |
| 604 | for (int i = 0; i < 5; i++) { |
| 605 | uint32_t base = 1111111111u * i; |
| 606 | for (int j = 0; j < kNumParams; j++) { |
| 607 | input[j] = static_cast<int32_t>(base + 13 * j); |
| 608 | } |
| 609 | |
| 610 | memset(output, 0, sizeof(output)); |
| 611 | CHECK_EQ(42, runnable.Call()); |
| 612 | |
| 613 | for (int j = 0; j < kNumParams; j++) { |
| 614 | CHECK_EQ(input[j], output[j]); |
| 615 | } |
| 616 | } |
| 617 | } |
| 618 | |
| 619 | |
| 620 | static void Test_RunInt32SubWithRet(int retreg) { |
| 621 | Int32Signature sig(2); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 622 | base::AccountingAllocator allocator; |
| 623 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 624 | RegisterPairs pairs; |
| 625 | while (pairs.More()) { |
| 626 | int parray[2]; |
| 627 | int rarray[] = {retreg}; |
| 628 | pairs.Next(&parray[0], &parray[1], false); |
| 629 | Allocator params(parray, 2, nullptr, 0); |
| 630 | Allocator rets(rarray, 1, nullptr, 0); |
| 631 | RegisterConfig config(params, rets); |
| 632 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 633 | TestInt32Sub(desc); |
| 634 | } |
| 635 | } |
| 636 | |
| 637 | |
| 638 | // Separate tests for parallelization. |
| 639 | #define TEST_INT32_SUB_WITH_RET(x) \ |
| 640 | TEST(Run_Int32Sub_all_allocatable_pairs_##x) { \ |
| 641 | if (x < Register::kNumRegisters && \ |
| 642 | Register::from_code(x).IsAllocatable()) { \ |
| 643 | Test_RunInt32SubWithRet(x); \ |
| 644 | } \ |
| 645 | } |
| 646 | |
| 647 | |
| 648 | TEST_INT32_SUB_WITH_RET(0) |
| 649 | TEST_INT32_SUB_WITH_RET(1) |
| 650 | TEST_INT32_SUB_WITH_RET(2) |
| 651 | TEST_INT32_SUB_WITH_RET(3) |
| 652 | TEST_INT32_SUB_WITH_RET(4) |
| 653 | TEST_INT32_SUB_WITH_RET(5) |
| 654 | TEST_INT32_SUB_WITH_RET(6) |
| 655 | TEST_INT32_SUB_WITH_RET(7) |
| 656 | TEST_INT32_SUB_WITH_RET(8) |
| 657 | TEST_INT32_SUB_WITH_RET(9) |
| 658 | TEST_INT32_SUB_WITH_RET(10) |
| 659 | TEST_INT32_SUB_WITH_RET(11) |
| 660 | TEST_INT32_SUB_WITH_RET(12) |
| 661 | TEST_INT32_SUB_WITH_RET(13) |
| 662 | TEST_INT32_SUB_WITH_RET(14) |
| 663 | TEST_INT32_SUB_WITH_RET(15) |
| 664 | TEST_INT32_SUB_WITH_RET(16) |
| 665 | TEST_INT32_SUB_WITH_RET(17) |
| 666 | TEST_INT32_SUB_WITH_RET(18) |
| 667 | TEST_INT32_SUB_WITH_RET(19) |
| 668 | |
| 669 | |
| 670 | TEST(Run_Int32Sub_all_allocatable_single) { |
| 671 | Int32Signature sig(2); |
| 672 | RegisterPairs pairs; |
| 673 | while (pairs.More()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 674 | base::AccountingAllocator allocator; |
| 675 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 676 | int parray[1]; |
| 677 | int rarray[1]; |
| 678 | pairs.Next(&rarray[0], &parray[0], true); |
| 679 | Allocator params(parray, 1, nullptr, 0); |
| 680 | Allocator rets(rarray, 1, nullptr, 0); |
| 681 | RegisterConfig config(params, rets); |
| 682 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 683 | TestInt32Sub(desc); |
| 684 | } |
| 685 | } |
| 686 | |
| 687 | |
| 688 | TEST(Run_CopyTwentyInt32_all_allocatable_pairs) { |
| 689 | Int32Signature sig(20); |
| 690 | RegisterPairs pairs; |
| 691 | while (pairs.More()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 692 | base::AccountingAllocator allocator; |
| 693 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 694 | int parray[2]; |
| 695 | int rarray[] = { |
| 696 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 697 | ->GetAllocatableGeneralCode(0)}; |
| 698 | pairs.Next(&parray[0], &parray[1], false); |
| 699 | Allocator params(parray, 2, nullptr, 0); |
| 700 | Allocator rets(rarray, 1, nullptr, 0); |
| 701 | RegisterConfig config(params, rets); |
| 702 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 703 | CopyTwentyInt32(desc); |
| 704 | } |
| 705 | } |
| 706 | |
| 707 | |
| 708 | template <typename CType> |
| 709 | static void Run_Computation( |
| 710 | CallDescriptor* desc, void (*build)(CallDescriptor*, RawMachineAssembler&), |
| 711 | CType (*compute)(CallDescriptor*, CType* inputs), int seed = 1) { |
| 712 | Computer<CType>::Run(desc, build, compute, seed); |
| 713 | } |
| 714 | |
| 715 | |
| 716 | static uint32_t coeff[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, |
| 717 | 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, |
| 718 | 79, 83, 89, 97, 101, 103, 107, 109, 113}; |
| 719 | |
| 720 | |
| 721 | static void Build_Int32_WeightedSum(CallDescriptor* desc, |
| 722 | RawMachineAssembler& raw) { |
| 723 | Node* result = raw.Int32Constant(0); |
| 724 | for (int i = 0; i < ParamCount(desc); i++) { |
| 725 | Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i])); |
| 726 | result = raw.Int32Add(result, term); |
| 727 | } |
| 728 | raw.Return(result); |
| 729 | } |
| 730 | |
| 731 | |
| 732 | static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) { |
| 733 | uint32_t result = 0; |
| 734 | for (int i = 0; i < ParamCount(desc); i++) { |
| 735 | result += static_cast<uint32_t>(input[i]) * coeff[i]; |
| 736 | } |
| 737 | return static_cast<int32_t>(result); |
| 738 | } |
| 739 | |
| 740 | |
| 741 | static void Test_Int32_WeightedSum_of_size(int count) { |
| 742 | Int32Signature sig(count); |
| 743 | for (int p0 = 0; p0 < Register::kNumRegisters; p0++) { |
| 744 | if (Register::from_code(p0).IsAllocatable()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 745 | base::AccountingAllocator allocator; |
| 746 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 747 | |
| 748 | int parray[] = {p0}; |
| 749 | int rarray[] = { |
| 750 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 751 | ->GetAllocatableGeneralCode(0)}; |
| 752 | Allocator params(parray, 1, nullptr, 0); |
| 753 | Allocator rets(rarray, 1, nullptr, 0); |
| 754 | RegisterConfig config(params, rets); |
| 755 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 756 | Run_Computation<int32_t>(desc, Build_Int32_WeightedSum, |
| 757 | Compute_Int32_WeightedSum, 257 + count); |
| 758 | } |
| 759 | } |
| 760 | } |
| 761 | |
| 762 | |
| 763 | // Separate tests for parallelization. |
| 764 | #define TEST_INT32_WEIGHTEDSUM(x) \ |
| 765 | TEST(Run_Int32_WeightedSum_##x) { Test_Int32_WeightedSum_of_size(x); } |
| 766 | |
| 767 | |
| 768 | TEST_INT32_WEIGHTEDSUM(1) |
| 769 | TEST_INT32_WEIGHTEDSUM(2) |
| 770 | TEST_INT32_WEIGHTEDSUM(3) |
| 771 | TEST_INT32_WEIGHTEDSUM(4) |
| 772 | TEST_INT32_WEIGHTEDSUM(5) |
| 773 | TEST_INT32_WEIGHTEDSUM(7) |
| 774 | TEST_INT32_WEIGHTEDSUM(9) |
| 775 | TEST_INT32_WEIGHTEDSUM(11) |
| 776 | TEST_INT32_WEIGHTEDSUM(17) |
| 777 | TEST_INT32_WEIGHTEDSUM(19) |
| 778 | |
| 779 | |
| 780 | template <int which> |
| 781 | static void Build_Select(CallDescriptor* desc, RawMachineAssembler& raw) { |
| 782 | raw.Return(raw.Parameter(which)); |
| 783 | } |
| 784 | |
| 785 | |
| 786 | template <typename CType, int which> |
| 787 | static CType Compute_Select(CallDescriptor* desc, CType* inputs) { |
| 788 | return inputs[which]; |
| 789 | } |
| 790 | |
| 791 | |
| 792 | template <typename CType, int which> |
| 793 | static void RunSelect(CallDescriptor* desc) { |
| 794 | int count = ParamCount(desc); |
| 795 | if (count <= which) return; |
| 796 | Run_Computation<CType>(desc, Build_Select<which>, |
| 797 | Compute_Select<CType, which>, |
| 798 | 1044 + which + 3 * sizeof(CType)); |
| 799 | } |
| 800 | |
| 801 | |
| 802 | template <int which> |
| 803 | void Test_Int32_Select() { |
| 804 | int parray[] = { |
| 805 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 806 | ->GetAllocatableGeneralCode(0)}; |
| 807 | int rarray[] = { |
| 808 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 809 | ->GetAllocatableGeneralCode(0)}; |
| 810 | Allocator params(parray, 1, nullptr, 0); |
| 811 | Allocator rets(rarray, 1, nullptr, 0); |
| 812 | RegisterConfig config(params, rets); |
| 813 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 814 | base::AccountingAllocator allocator; |
| 815 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 816 | |
| 817 | for (int i = which + 1; i <= 64; i++) { |
| 818 | Int32Signature sig(i); |
| 819 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 820 | RunSelect<int32_t, which>(desc); |
| 821 | } |
| 822 | } |
| 823 | |
| 824 | |
| 825 | // Separate tests for parallelization. |
| 826 | #define TEST_INT32_SELECT(x) \ |
| 827 | TEST(Run_Int32_Select_##x) { Test_Int32_Select<x>(); } |
| 828 | |
| 829 | |
| 830 | TEST_INT32_SELECT(0) |
| 831 | TEST_INT32_SELECT(1) |
| 832 | TEST_INT32_SELECT(2) |
| 833 | TEST_INT32_SELECT(3) |
| 834 | TEST_INT32_SELECT(4) |
| 835 | TEST_INT32_SELECT(5) |
| 836 | TEST_INT32_SELECT(6) |
| 837 | TEST_INT32_SELECT(11) |
| 838 | TEST_INT32_SELECT(15) |
| 839 | TEST_INT32_SELECT(19) |
| 840 | TEST_INT32_SELECT(45) |
| 841 | TEST_INT32_SELECT(62) |
| 842 | TEST_INT32_SELECT(63) |
| 843 | |
| 844 | |
| 845 | TEST(Int64Select_registers) { |
| 846 | if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 847 | ->num_allocatable_general_registers() < 2) |
| 848 | return; |
| 849 | if (kPointerSize < 8) return; // TODO(titzer): int64 on 32-bit platforms |
| 850 | |
| 851 | int rarray[] = { |
| 852 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 853 | ->GetAllocatableGeneralCode(0)}; |
| 854 | ArgsBuffer<int64_t>::Sig sig(2); |
| 855 | |
| 856 | RegisterPairs pairs; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 857 | base::AccountingAllocator allocator; |
| 858 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 859 | while (pairs.More()) { |
| 860 | int parray[2]; |
| 861 | pairs.Next(&parray[0], &parray[1], false); |
| 862 | Allocator params(parray, 2, nullptr, 0); |
| 863 | Allocator rets(rarray, 1, nullptr, 0); |
| 864 | RegisterConfig config(params, rets); |
| 865 | |
| 866 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 867 | RunSelect<int64_t, 0>(desc); |
| 868 | RunSelect<int64_t, 1>(desc); |
| 869 | } |
| 870 | } |
| 871 | |
| 872 | |
| 873 | TEST(Float32Select_registers) { |
| 874 | if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 875 | ->num_allocatable_double_registers() < 2) { |
| 876 | return; |
| 877 | } |
| 878 | |
| 879 | int rarray[] = { |
| 880 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 881 | ->GetAllocatableDoubleCode(0)}; |
| 882 | ArgsBuffer<float32>::Sig sig(2); |
| 883 | |
| 884 | Float32RegisterPairs pairs; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 885 | base::AccountingAllocator allocator; |
| 886 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 887 | while (pairs.More()) { |
| 888 | int parray[2]; |
| 889 | pairs.Next(&parray[0], &parray[1], false); |
| 890 | Allocator params(nullptr, 0, parray, 2); |
| 891 | Allocator rets(nullptr, 0, rarray, 1); |
| 892 | RegisterConfig config(params, rets); |
| 893 | |
| 894 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 895 | RunSelect<float32, 0>(desc); |
| 896 | RunSelect<float32, 1>(desc); |
| 897 | } |
| 898 | } |
| 899 | |
| 900 | |
| 901 | TEST(Float64Select_registers) { |
| 902 | if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 903 | ->num_allocatable_double_registers() < 2) |
| 904 | return; |
| 905 | if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 906 | ->num_allocatable_general_registers() < 2) |
| 907 | return; |
| 908 | int rarray[] = { |
| 909 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 910 | ->GetAllocatableDoubleCode(0)}; |
| 911 | ArgsBuffer<float64>::Sig sig(2); |
| 912 | |
| 913 | Float64RegisterPairs pairs; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 914 | base::AccountingAllocator allocator; |
| 915 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 916 | while (pairs.More()) { |
| 917 | int parray[2]; |
| 918 | pairs.Next(&parray[0], &parray[1], false); |
| 919 | Allocator params(nullptr, 0, parray, 2); |
| 920 | Allocator rets(nullptr, 0, rarray, 1); |
| 921 | RegisterConfig config(params, rets); |
| 922 | |
| 923 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 924 | RunSelect<float64, 0>(desc); |
| 925 | RunSelect<float64, 1>(desc); |
| 926 | } |
| 927 | } |
| 928 | |
| 929 | |
| 930 | TEST(Float32Select_stack_params_return_reg) { |
| 931 | int rarray[] = { |
| 932 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 933 | ->GetAllocatableDoubleCode(0)}; |
| 934 | Allocator params(nullptr, 0, nullptr, 0); |
| 935 | Allocator rets(nullptr, 0, rarray, 1); |
| 936 | RegisterConfig config(params, rets); |
| 937 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 938 | base::AccountingAllocator allocator; |
| 939 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 940 | for (int count = 1; count < 6; count++) { |
| 941 | ArgsBuffer<float32>::Sig sig(count); |
| 942 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 943 | RunSelect<float32, 0>(desc); |
| 944 | RunSelect<float32, 1>(desc); |
| 945 | RunSelect<float32, 2>(desc); |
| 946 | RunSelect<float32, 3>(desc); |
| 947 | RunSelect<float32, 4>(desc); |
| 948 | RunSelect<float32, 5>(desc); |
| 949 | } |
| 950 | } |
| 951 | |
| 952 | |
| 953 | TEST(Float64Select_stack_params_return_reg) { |
| 954 | int rarray[] = { |
| 955 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 956 | ->GetAllocatableDoubleCode(0)}; |
| 957 | Allocator params(nullptr, 0, nullptr, 0); |
| 958 | Allocator rets(nullptr, 0, rarray, 1); |
| 959 | RegisterConfig config(params, rets); |
| 960 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 961 | base::AccountingAllocator allocator; |
| 962 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 963 | for (int count = 1; count < 6; count++) { |
| 964 | ArgsBuffer<float64>::Sig sig(count); |
| 965 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 966 | RunSelect<float64, 0>(desc); |
| 967 | RunSelect<float64, 1>(desc); |
| 968 | RunSelect<float64, 2>(desc); |
| 969 | RunSelect<float64, 3>(desc); |
| 970 | RunSelect<float64, 4>(desc); |
| 971 | RunSelect<float64, 5>(desc); |
| 972 | } |
| 973 | } |
| 974 | |
| 975 | |
| 976 | template <typename CType, int which> |
| 977 | static void Build_Select_With_Call(CallDescriptor* desc, |
| 978 | RawMachineAssembler& raw) { |
| 979 | Handle<Code> inner = Handle<Code>::null(); |
| 980 | int num_params = ParamCount(desc); |
| 981 | CHECK_LE(num_params, kMaxParamCount); |
| 982 | { |
| 983 | Isolate* isolate = CcTest::InitIsolateOnce(); |
| 984 | // Build the actual select. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 985 | Zone zone(isolate->allocator()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 986 | Graph graph(&zone); |
| 987 | RawMachineAssembler raw(isolate, &graph, desc); |
| 988 | raw.Return(raw.Parameter(which)); |
| 989 | inner = CompileGraph("Select-indirection", desc, &graph, raw.Export()); |
| 990 | CHECK(!inner.is_null()); |
| 991 | CHECK(inner->IsCode()); |
| 992 | } |
| 993 | |
| 994 | { |
| 995 | // Build a call to the function that does the select. |
| 996 | Node* target = raw.HeapConstant(inner); |
| 997 | Node** args = raw.zone()->NewArray<Node*>(num_params); |
| 998 | for (int i = 0; i < num_params; i++) { |
| 999 | args[i] = raw.Parameter(i); |
| 1000 | } |
| 1001 | |
| 1002 | Node* call = raw.CallN(desc, target, args); |
| 1003 | raw.Return(call); |
| 1004 | } |
| 1005 | } |
| 1006 | |
| 1007 | |
| 1008 | TEST(Float64StackParamsToStackParams) { |
| 1009 | int rarray[] = { |
| 1010 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1011 | ->GetAllocatableDoubleCode(0)}; |
| 1012 | Allocator params(nullptr, 0, nullptr, 0); |
| 1013 | Allocator rets(nullptr, 0, rarray, 1); |
| 1014 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1015 | base::AccountingAllocator allocator; |
| 1016 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1017 | ArgsBuffer<float64>::Sig sig(2); |
| 1018 | RegisterConfig config(params, rets); |
| 1019 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 1020 | |
| 1021 | Run_Computation<float64>(desc, Build_Select_With_Call<float64, 0>, |
| 1022 | Compute_Select<float64, 0>, 1098); |
| 1023 | |
| 1024 | Run_Computation<float64>(desc, Build_Select_With_Call<float64, 1>, |
| 1025 | Compute_Select<float64, 1>, 1099); |
| 1026 | } |
| 1027 | |
| 1028 | |
| 1029 | void MixedParamTest(int start) { |
| 1030 | if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1031 | ->num_double_registers() < 2) |
| 1032 | return; |
| 1033 | |
| 1034 | // TODO(titzer): mix in 64-bit types on all platforms when supported. |
| 1035 | #if V8_TARGET_ARCH_32_BIT |
| 1036 | static MachineType types[] = { |
| 1037 | MachineType::Int32(), MachineType::Float32(), MachineType::Float64(), |
| 1038 | MachineType::Int32(), MachineType::Float64(), MachineType::Float32(), |
| 1039 | MachineType::Float32(), MachineType::Float64(), MachineType::Int32(), |
| 1040 | MachineType::Float32(), MachineType::Int32(), MachineType::Float64(), |
| 1041 | MachineType::Float64(), MachineType::Float32(), MachineType::Int32(), |
| 1042 | MachineType::Float64(), MachineType::Int32(), MachineType::Float32()}; |
| 1043 | #else |
| 1044 | static MachineType types[] = { |
| 1045 | MachineType::Int32(), MachineType::Int64(), MachineType::Float32(), |
| 1046 | MachineType::Float64(), MachineType::Int32(), MachineType::Float64(), |
| 1047 | MachineType::Float32(), MachineType::Int64(), MachineType::Int64(), |
| 1048 | MachineType::Float32(), MachineType::Float32(), MachineType::Int32(), |
| 1049 | MachineType::Float64(), MachineType::Float64(), MachineType::Int64(), |
| 1050 | MachineType::Int32(), MachineType::Float64(), MachineType::Int32(), |
| 1051 | MachineType::Float32()}; |
| 1052 | #endif |
| 1053 | |
| 1054 | Isolate* isolate = CcTest::InitIsolateOnce(); |
| 1055 | |
| 1056 | // Build machine signature |
| 1057 | MachineType* params = &types[start]; |
| 1058 | const int num_params = static_cast<int>(arraysize(types) - start); |
| 1059 | |
| 1060 | // Build call descriptor |
| 1061 | int parray_gp[] = { |
| 1062 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1063 | ->GetAllocatableGeneralCode(0), |
| 1064 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1065 | ->GetAllocatableGeneralCode(1)}; |
| 1066 | int rarray_gp[] = { |
| 1067 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1068 | ->GetAllocatableGeneralCode(0)}; |
| 1069 | int parray_fp[] = { |
| 1070 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1071 | ->GetAllocatableDoubleCode(0), |
| 1072 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1073 | ->GetAllocatableDoubleCode(1)}; |
| 1074 | int rarray_fp[] = { |
| 1075 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1076 | ->GetAllocatableDoubleCode(0)}; |
| 1077 | Allocator palloc(parray_gp, 2, parray_fp, 2); |
| 1078 | Allocator ralloc(rarray_gp, 1, rarray_fp, 1); |
| 1079 | RegisterConfig config(palloc, ralloc); |
| 1080 | |
| 1081 | for (int which = 0; which < num_params; which++) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1082 | base::AccountingAllocator allocator; |
| 1083 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1084 | HandleScope scope(isolate); |
| 1085 | MachineSignature::Builder builder(&zone, 1, num_params); |
| 1086 | builder.AddReturn(params[which]); |
| 1087 | for (int j = 0; j < num_params; j++) builder.AddParam(params[j]); |
| 1088 | MachineSignature* sig = builder.Build(); |
| 1089 | CallDescriptor* desc = config.Create(&zone, sig); |
| 1090 | |
| 1091 | Handle<Code> select; |
| 1092 | { |
| 1093 | // build the select. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1094 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1095 | Graph graph(&zone); |
| 1096 | RawMachineAssembler raw(isolate, &graph, desc); |
| 1097 | raw.Return(raw.Parameter(which)); |
| 1098 | select = CompileGraph("Compute", desc, &graph, raw.Export()); |
| 1099 | } |
| 1100 | |
| 1101 | { |
| 1102 | // call the select. |
| 1103 | Handle<Code> wrapper = Handle<Code>::null(); |
| 1104 | int32_t expected_ret; |
| 1105 | char bytes[kDoubleSize]; |
| 1106 | V8_ALIGNED(8) char output[kDoubleSize]; |
| 1107 | int expected_size = 0; |
| 1108 | CSignature0<int32_t> csig; |
| 1109 | { |
| 1110 | // Wrap the select code with a callable function that passes constants. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1111 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1112 | Graph graph(&zone); |
| 1113 | CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); |
| 1114 | RawMachineAssembler raw(isolate, &graph, cdesc); |
| 1115 | Node* target = raw.HeapConstant(select); |
| 1116 | Node** args = zone.NewArray<Node*>(num_params); |
| 1117 | int64_t constant = 0x0102030405060708; |
| 1118 | for (int i = 0; i < num_params; i++) { |
| 1119 | MachineType param_type = sig->GetParam(i); |
| 1120 | Node* konst = nullptr; |
| 1121 | if (param_type == MachineType::Int32()) { |
| 1122 | int32_t value[] = {static_cast<int32_t>(constant)}; |
| 1123 | konst = raw.Int32Constant(value[0]); |
| 1124 | if (i == which) memcpy(bytes, value, expected_size = 4); |
| 1125 | } |
| 1126 | if (param_type == MachineType::Int64()) { |
| 1127 | int64_t value[] = {static_cast<int64_t>(constant)}; |
| 1128 | konst = raw.Int64Constant(value[0]); |
| 1129 | if (i == which) memcpy(bytes, value, expected_size = 8); |
| 1130 | } |
| 1131 | if (param_type == MachineType::Float32()) { |
| 1132 | float32 value[] = {static_cast<float32>(constant)}; |
| 1133 | konst = raw.Float32Constant(value[0]); |
| 1134 | if (i == which) memcpy(bytes, value, expected_size = 4); |
| 1135 | } |
| 1136 | if (param_type == MachineType::Float64()) { |
| 1137 | float64 value[] = {static_cast<float64>(constant)}; |
| 1138 | konst = raw.Float64Constant(value[0]); |
| 1139 | if (i == which) memcpy(bytes, value, expected_size = 8); |
| 1140 | } |
| 1141 | CHECK_NOT_NULL(konst); |
| 1142 | |
| 1143 | args[i] = konst; |
| 1144 | constant += 0x1010101010101010; |
| 1145 | } |
| 1146 | |
| 1147 | Node* call = raw.CallN(desc, target, args); |
| 1148 | Node* store = |
| 1149 | raw.StoreToPointer(output, sig->GetReturn().representation(), call); |
| 1150 | USE(store); |
| 1151 | expected_ret = static_cast<int32_t>(constant); |
| 1152 | raw.Return(raw.Int32Constant(expected_ret)); |
| 1153 | wrapper = CompileGraph("Select-mixed-wrapper-const", cdesc, &graph, |
| 1154 | raw.Export()); |
| 1155 | } |
| 1156 | |
| 1157 | CodeRunner<int32_t> runnable(isolate, wrapper, &csig); |
| 1158 | CHECK_EQ(expected_ret, runnable.Call()); |
| 1159 | for (int i = 0; i < expected_size; i++) { |
| 1160 | CHECK_EQ(static_cast<int>(bytes[i]), static_cast<int>(output[i])); |
| 1161 | } |
| 1162 | } |
| 1163 | } |
| 1164 | } |
| 1165 | |
| 1166 | |
| 1167 | TEST(MixedParams_0) { MixedParamTest(0); } |
| 1168 | TEST(MixedParams_1) { MixedParamTest(1); } |
| 1169 | TEST(MixedParams_2) { MixedParamTest(2); } |
| 1170 | TEST(MixedParams_3) { MixedParamTest(3); } |
| 1171 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1172 | template <typename T> |
| 1173 | void TestStackSlot(MachineType slot_type, T expected) { |
| 1174 | // Test: Generate with a function f which reserves a stack slot, call an inner |
| 1175 | // function g from f which writes into the stack slot of f. |
| 1176 | |
| 1177 | if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1178 | ->num_allocatable_double_registers() < 2) |
| 1179 | return; |
| 1180 | |
| 1181 | Isolate* isolate = CcTest::InitIsolateOnce(); |
| 1182 | |
| 1183 | // Lots of code to generate the build descriptor for the inner function. |
| 1184 | int parray_gp[] = { |
| 1185 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1186 | ->GetAllocatableGeneralCode(0), |
| 1187 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1188 | ->GetAllocatableGeneralCode(1)}; |
| 1189 | int rarray_gp[] = { |
| 1190 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1191 | ->GetAllocatableGeneralCode(0)}; |
| 1192 | int parray_fp[] = { |
| 1193 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1194 | ->GetAllocatableDoubleCode(0), |
| 1195 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1196 | ->GetAllocatableDoubleCode(1)}; |
| 1197 | int rarray_fp[] = { |
| 1198 | RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) |
| 1199 | ->GetAllocatableDoubleCode(0)}; |
| 1200 | Allocator palloc(parray_gp, 2, parray_fp, 2); |
| 1201 | Allocator ralloc(rarray_gp, 1, rarray_fp, 1); |
| 1202 | RegisterConfig config(palloc, ralloc); |
| 1203 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 1204 | Zone zone(isolate->allocator()); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1205 | HandleScope scope(isolate); |
| 1206 | MachineSignature::Builder builder(&zone, 1, 12); |
| 1207 | builder.AddReturn(MachineType::Int32()); |
| 1208 | for (int i = 0; i < 10; i++) { |
| 1209 | builder.AddParam(MachineType::Int32()); |
| 1210 | } |
| 1211 | builder.AddParam(slot_type); |
| 1212 | builder.AddParam(MachineType::Pointer()); |
| 1213 | MachineSignature* sig = builder.Build(); |
| 1214 | CallDescriptor* desc = config.Create(&zone, sig); |
| 1215 | |
| 1216 | // Create inner function g. g has lots of parameters so that they are passed |
| 1217 | // over the stack. |
| 1218 | Handle<Code> inner; |
| 1219 | Graph graph(&zone); |
| 1220 | RawMachineAssembler g(isolate, &graph, desc); |
| 1221 | |
| 1222 | g.Store(slot_type.representation(), g.Parameter(11), g.Parameter(10), |
| 1223 | WriteBarrierKind::kNoWriteBarrier); |
| 1224 | g.Return(g.Parameter(9)); |
| 1225 | inner = CompileGraph("Compute", desc, &graph, g.Export()); |
| 1226 | |
| 1227 | // Create function f with a stack slot which calls the inner function g. |
| 1228 | BufferedRawMachineAssemblerTester<T> f(slot_type); |
| 1229 | Node* target = f.HeapConstant(inner); |
| 1230 | Node* stack_slot = f.StackSlot(slot_type.representation()); |
| 1231 | Node* args[12]; |
| 1232 | for (int i = 0; i < 10; i++) { |
| 1233 | args[i] = f.Int32Constant(i); |
| 1234 | } |
| 1235 | args[10] = f.Parameter(0); |
| 1236 | args[11] = stack_slot; |
| 1237 | |
| 1238 | f.CallN(desc, target, args); |
| 1239 | f.Return(f.Load(slot_type, stack_slot, f.IntPtrConstant(0))); |
| 1240 | |
| 1241 | CHECK_EQ(expected, f.Call(expected)); |
| 1242 | } |
| 1243 | |
| 1244 | TEST(RunStackSlotInt32) { |
| 1245 | int32_t magic = 0x12345678; |
| 1246 | TestStackSlot(MachineType::Int32(), magic); |
| 1247 | } |
| 1248 | |
| 1249 | #if !V8_TARGET_ARCH_32_BIT |
| 1250 | TEST(RunStackSlotInt64) { |
| 1251 | int64_t magic = 0x123456789abcdef0; |
| 1252 | TestStackSlot(MachineType::Int64(), magic); |
| 1253 | } |
| 1254 | #endif |
| 1255 | |
| 1256 | TEST(RunStackSlotFloat32) { |
| 1257 | float magic = 1234.125f; |
| 1258 | TestStackSlot(MachineType::Float32(), magic); |
| 1259 | } |
| 1260 | |
| 1261 | TEST(RunStackSlotFloat64) { |
| 1262 | double magic = 3456.375; |
| 1263 | TestStackSlot(MachineType::Float64(), magic); |
| 1264 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1265 | } // namespace compiler |
| 1266 | } // namespace internal |
| 1267 | } // namespace v8 |