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 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 21 | const auto GetRegConfig = RegisterConfiguration::Turbofan; |
| 22 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 23 | namespace { |
| 24 | typedef float float32; |
| 25 | typedef double float64; |
| 26 | |
| 27 | // Picks a representative pair of integers from the given range. |
| 28 | // If there are less than {max_pairs} possible pairs, do them all, otherwise try |
| 29 | // to select a representative set. |
| 30 | class Pairs { |
| 31 | public: |
| 32 | Pairs(int max_pairs, int range, const int* codes) |
| 33 | : range_(range), |
| 34 | codes_(codes), |
| 35 | max_pairs_(std::min(max_pairs, range_ * range_)), |
| 36 | counter_(0) {} |
| 37 | |
| 38 | bool More() { return counter_ < max_pairs_; } |
| 39 | |
| 40 | void Next(int* r0, int* r1, bool same_is_ok) { |
| 41 | do { |
| 42 | // Find the next pair. |
| 43 | if (exhaustive()) { |
| 44 | *r0 = codes_[counter_ % range_]; |
| 45 | *r1 = codes_[counter_ / range_]; |
| 46 | } else { |
| 47 | // Try each integer at least once for both r0 and r1. |
| 48 | int index = counter_ / 2; |
| 49 | if (counter_ & 1) { |
| 50 | *r0 = codes_[index % range_]; |
| 51 | *r1 = codes_[index / range_]; |
| 52 | } else { |
| 53 | *r1 = codes_[index % range_]; |
| 54 | *r0 = codes_[index / range_]; |
| 55 | } |
| 56 | } |
| 57 | counter_++; |
| 58 | if ((same_is_ok) || (*r0 != *r1)) break; |
| 59 | if (counter_ == max_pairs_) { |
| 60 | // For the last hurrah, reg#0 with reg#n-1 |
| 61 | *r0 = codes_[0]; |
| 62 | *r1 = codes_[range_ - 1]; |
| 63 | break; |
| 64 | } |
| 65 | } while (true); |
| 66 | } |
| 67 | |
| 68 | private: |
| 69 | int range_; |
| 70 | const int* codes_; |
| 71 | int max_pairs_; |
| 72 | int counter_; |
| 73 | bool exhaustive() { return max_pairs_ == (range_ * range_); } |
| 74 | }; |
| 75 | |
| 76 | |
| 77 | // Pairs of general purpose registers. |
| 78 | class RegisterPairs : public Pairs { |
| 79 | public: |
| 80 | RegisterPairs() |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 81 | : Pairs(100, GetRegConfig()->num_allocatable_general_registers(), |
| 82 | GetRegConfig()->allocatable_general_codes()) {} |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 83 | }; |
| 84 | |
| 85 | |
| 86 | // Pairs of double registers. |
| 87 | class Float32RegisterPairs : public Pairs { |
| 88 | public: |
| 89 | Float32RegisterPairs() |
| 90 | : Pairs( |
| 91 | 100, |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 92 | #if V8_TARGET_ARCH_ARM |
| 93 | // TODO(bbudge) Modify wasm linkage to allow use of all float regs. |
| 94 | GetRegConfig()->num_allocatable_double_registers() / 2 - 2, |
| 95 | #else |
| 96 | GetRegConfig()->num_allocatable_double_registers(), |
| 97 | #endif |
| 98 | GetRegConfig()->allocatable_double_codes()) { |
| 99 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 100 | }; |
| 101 | |
| 102 | |
| 103 | // Pairs of double registers. |
| 104 | class Float64RegisterPairs : public Pairs { |
| 105 | public: |
| 106 | Float64RegisterPairs() |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 107 | : Pairs(100, GetRegConfig()->num_allocatable_double_registers(), |
| 108 | GetRegConfig()->allocatable_double_codes()) {} |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 109 | }; |
| 110 | |
| 111 | |
| 112 | // Helper for allocating either an GP or FP reg, or the next stack slot. |
| 113 | struct Allocator { |
| 114 | Allocator(int* gp, int gpc, int* fp, int fpc) |
| 115 | : gp_count(gpc), |
| 116 | gp_offset(0), |
| 117 | gp_regs(gp), |
| 118 | fp_count(fpc), |
| 119 | fp_offset(0), |
| 120 | fp_regs(fp), |
| 121 | stack_offset(0) {} |
| 122 | |
| 123 | int gp_count; |
| 124 | int gp_offset; |
| 125 | int* gp_regs; |
| 126 | |
| 127 | int fp_count; |
| 128 | int fp_offset; |
| 129 | int* fp_regs; |
| 130 | |
| 131 | int stack_offset; |
| 132 | |
| 133 | LinkageLocation Next(MachineType type) { |
| 134 | if (IsFloatingPoint(type.representation())) { |
| 135 | // Allocate a floating point register/stack location. |
| 136 | if (fp_offset < fp_count) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 137 | int code = fp_regs[fp_offset++]; |
| 138 | #if V8_TARGET_ARCH_ARM |
| 139 | // TODO(bbudge) Modify wasm linkage to allow use of all float regs. |
| 140 | if (type.representation() == MachineRepresentation::kFloat32) code *= 2; |
| 141 | #endif |
| 142 | return LinkageLocation::ForRegister(code); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 143 | } else { |
| 144 | int offset = -1 - stack_offset; |
| 145 | stack_offset += StackWords(type); |
| 146 | return LinkageLocation::ForCallerFrameSlot(offset); |
| 147 | } |
| 148 | } else { |
| 149 | // Allocate a general purpose register/stack location. |
| 150 | if (gp_offset < gp_count) { |
| 151 | return LinkageLocation::ForRegister(gp_regs[gp_offset++]); |
| 152 | } else { |
| 153 | int offset = -1 - stack_offset; |
| 154 | stack_offset += StackWords(type); |
| 155 | return LinkageLocation::ForCallerFrameSlot(offset); |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | int StackWords(MachineType type) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 160 | int size = 1 << ElementSizeLog2Of(type.representation()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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(); |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 258 | CompilationInfo info(ArrayVector("testing"), isolate, graph->zone()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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. |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 639 | #define TEST_INT32_SUB_WITH_RET(x) \ |
| 640 | TEST(Run_Int32Sub_all_allocatable_pairs_##x) { \ |
| 641 | if (x < Register::kNumRegisters && \ |
| 642 | GetRegConfig()->IsAllocatableGeneralCode(x)) { \ |
| 643 | Test_RunInt32SubWithRet(x); \ |
| 644 | } \ |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 645 | } |
| 646 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 647 | TEST_INT32_SUB_WITH_RET(0) |
| 648 | TEST_INT32_SUB_WITH_RET(1) |
| 649 | TEST_INT32_SUB_WITH_RET(2) |
| 650 | TEST_INT32_SUB_WITH_RET(3) |
| 651 | TEST_INT32_SUB_WITH_RET(4) |
| 652 | TEST_INT32_SUB_WITH_RET(5) |
| 653 | TEST_INT32_SUB_WITH_RET(6) |
| 654 | TEST_INT32_SUB_WITH_RET(7) |
| 655 | TEST_INT32_SUB_WITH_RET(8) |
| 656 | TEST_INT32_SUB_WITH_RET(9) |
| 657 | TEST_INT32_SUB_WITH_RET(10) |
| 658 | TEST_INT32_SUB_WITH_RET(11) |
| 659 | TEST_INT32_SUB_WITH_RET(12) |
| 660 | TEST_INT32_SUB_WITH_RET(13) |
| 661 | TEST_INT32_SUB_WITH_RET(14) |
| 662 | TEST_INT32_SUB_WITH_RET(15) |
| 663 | TEST_INT32_SUB_WITH_RET(16) |
| 664 | TEST_INT32_SUB_WITH_RET(17) |
| 665 | TEST_INT32_SUB_WITH_RET(18) |
| 666 | TEST_INT32_SUB_WITH_RET(19) |
| 667 | |
| 668 | |
| 669 | TEST(Run_Int32Sub_all_allocatable_single) { |
| 670 | Int32Signature sig(2); |
| 671 | RegisterPairs pairs; |
| 672 | while (pairs.More()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 673 | base::AccountingAllocator allocator; |
| 674 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 675 | int parray[1]; |
| 676 | int rarray[1]; |
| 677 | pairs.Next(&rarray[0], &parray[0], true); |
| 678 | Allocator params(parray, 1, nullptr, 0); |
| 679 | Allocator rets(rarray, 1, nullptr, 0); |
| 680 | RegisterConfig config(params, rets); |
| 681 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 682 | TestInt32Sub(desc); |
| 683 | } |
| 684 | } |
| 685 | |
| 686 | |
| 687 | TEST(Run_CopyTwentyInt32_all_allocatable_pairs) { |
| 688 | Int32Signature sig(20); |
| 689 | RegisterPairs pairs; |
| 690 | while (pairs.More()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 691 | base::AccountingAllocator allocator; |
| 692 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 693 | int parray[2]; |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 694 | int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 695 | pairs.Next(&parray[0], &parray[1], false); |
| 696 | Allocator params(parray, 2, nullptr, 0); |
| 697 | Allocator rets(rarray, 1, nullptr, 0); |
| 698 | RegisterConfig config(params, rets); |
| 699 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 700 | CopyTwentyInt32(desc); |
| 701 | } |
| 702 | } |
| 703 | |
| 704 | |
| 705 | template <typename CType> |
| 706 | static void Run_Computation( |
| 707 | CallDescriptor* desc, void (*build)(CallDescriptor*, RawMachineAssembler&), |
| 708 | CType (*compute)(CallDescriptor*, CType* inputs), int seed = 1) { |
| 709 | Computer<CType>::Run(desc, build, compute, seed); |
| 710 | } |
| 711 | |
| 712 | |
| 713 | static uint32_t coeff[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, |
| 714 | 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, |
| 715 | 79, 83, 89, 97, 101, 103, 107, 109, 113}; |
| 716 | |
| 717 | |
| 718 | static void Build_Int32_WeightedSum(CallDescriptor* desc, |
| 719 | RawMachineAssembler& raw) { |
| 720 | Node* result = raw.Int32Constant(0); |
| 721 | for (int i = 0; i < ParamCount(desc); i++) { |
| 722 | Node* term = raw.Int32Mul(raw.Parameter(i), raw.Int32Constant(coeff[i])); |
| 723 | result = raw.Int32Add(result, term); |
| 724 | } |
| 725 | raw.Return(result); |
| 726 | } |
| 727 | |
| 728 | |
| 729 | static int32_t Compute_Int32_WeightedSum(CallDescriptor* desc, int32_t* input) { |
| 730 | uint32_t result = 0; |
| 731 | for (int i = 0; i < ParamCount(desc); i++) { |
| 732 | result += static_cast<uint32_t>(input[i]) * coeff[i]; |
| 733 | } |
| 734 | return static_cast<int32_t>(result); |
| 735 | } |
| 736 | |
| 737 | |
| 738 | static void Test_Int32_WeightedSum_of_size(int count) { |
| 739 | Int32Signature sig(count); |
| 740 | for (int p0 = 0; p0 < Register::kNumRegisters; p0++) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 741 | if (GetRegConfig()->IsAllocatableGeneralCode(p0)) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 742 | base::AccountingAllocator allocator; |
| 743 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 744 | |
| 745 | int parray[] = {p0}; |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 746 | int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 747 | Allocator params(parray, 1, nullptr, 0); |
| 748 | Allocator rets(rarray, 1, nullptr, 0); |
| 749 | RegisterConfig config(params, rets); |
| 750 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 751 | Run_Computation<int32_t>(desc, Build_Int32_WeightedSum, |
| 752 | Compute_Int32_WeightedSum, 257 + count); |
| 753 | } |
| 754 | } |
| 755 | } |
| 756 | |
| 757 | |
| 758 | // Separate tests for parallelization. |
| 759 | #define TEST_INT32_WEIGHTEDSUM(x) \ |
| 760 | TEST(Run_Int32_WeightedSum_##x) { Test_Int32_WeightedSum_of_size(x); } |
| 761 | |
| 762 | |
| 763 | TEST_INT32_WEIGHTEDSUM(1) |
| 764 | TEST_INT32_WEIGHTEDSUM(2) |
| 765 | TEST_INT32_WEIGHTEDSUM(3) |
| 766 | TEST_INT32_WEIGHTEDSUM(4) |
| 767 | TEST_INT32_WEIGHTEDSUM(5) |
| 768 | TEST_INT32_WEIGHTEDSUM(7) |
| 769 | TEST_INT32_WEIGHTEDSUM(9) |
| 770 | TEST_INT32_WEIGHTEDSUM(11) |
| 771 | TEST_INT32_WEIGHTEDSUM(17) |
| 772 | TEST_INT32_WEIGHTEDSUM(19) |
| 773 | |
| 774 | |
| 775 | template <int which> |
| 776 | static void Build_Select(CallDescriptor* desc, RawMachineAssembler& raw) { |
| 777 | raw.Return(raw.Parameter(which)); |
| 778 | } |
| 779 | |
| 780 | |
| 781 | template <typename CType, int which> |
| 782 | static CType Compute_Select(CallDescriptor* desc, CType* inputs) { |
| 783 | return inputs[which]; |
| 784 | } |
| 785 | |
| 786 | |
| 787 | template <typename CType, int which> |
| 788 | static void RunSelect(CallDescriptor* desc) { |
| 789 | int count = ParamCount(desc); |
| 790 | if (count <= which) return; |
| 791 | Run_Computation<CType>(desc, Build_Select<which>, |
| 792 | Compute_Select<CType, which>, |
| 793 | 1044 + which + 3 * sizeof(CType)); |
| 794 | } |
| 795 | |
| 796 | |
| 797 | template <int which> |
| 798 | void Test_Int32_Select() { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 799 | int parray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)}; |
| 800 | int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 801 | Allocator params(parray, 1, nullptr, 0); |
| 802 | Allocator rets(rarray, 1, nullptr, 0); |
| 803 | RegisterConfig config(params, rets); |
| 804 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 805 | base::AccountingAllocator allocator; |
| 806 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 807 | |
| 808 | for (int i = which + 1; i <= 64; i++) { |
| 809 | Int32Signature sig(i); |
| 810 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 811 | RunSelect<int32_t, which>(desc); |
| 812 | } |
| 813 | } |
| 814 | |
| 815 | |
| 816 | // Separate tests for parallelization. |
| 817 | #define TEST_INT32_SELECT(x) \ |
| 818 | TEST(Run_Int32_Select_##x) { Test_Int32_Select<x>(); } |
| 819 | |
| 820 | |
| 821 | TEST_INT32_SELECT(0) |
| 822 | TEST_INT32_SELECT(1) |
| 823 | TEST_INT32_SELECT(2) |
| 824 | TEST_INT32_SELECT(3) |
| 825 | TEST_INT32_SELECT(4) |
| 826 | TEST_INT32_SELECT(5) |
| 827 | TEST_INT32_SELECT(6) |
| 828 | TEST_INT32_SELECT(11) |
| 829 | TEST_INT32_SELECT(15) |
| 830 | TEST_INT32_SELECT(19) |
| 831 | TEST_INT32_SELECT(45) |
| 832 | TEST_INT32_SELECT(62) |
| 833 | TEST_INT32_SELECT(63) |
| 834 | |
| 835 | |
| 836 | TEST(Int64Select_registers) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 837 | if (GetRegConfig()->num_allocatable_general_registers() < 2) return; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 838 | if (kPointerSize < 8) return; // TODO(titzer): int64 on 32-bit platforms |
| 839 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 840 | int rarray[] = {GetRegConfig()->GetAllocatableGeneralCode(0)}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 841 | ArgsBuffer<int64_t>::Sig sig(2); |
| 842 | |
| 843 | RegisterPairs pairs; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 844 | base::AccountingAllocator allocator; |
| 845 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 846 | while (pairs.More()) { |
| 847 | int parray[2]; |
| 848 | pairs.Next(&parray[0], &parray[1], false); |
| 849 | Allocator params(parray, 2, nullptr, 0); |
| 850 | Allocator rets(rarray, 1, nullptr, 0); |
| 851 | RegisterConfig config(params, rets); |
| 852 | |
| 853 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 854 | RunSelect<int64_t, 0>(desc); |
| 855 | RunSelect<int64_t, 1>(desc); |
| 856 | } |
| 857 | } |
| 858 | |
| 859 | |
| 860 | TEST(Float32Select_registers) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 861 | if (GetRegConfig()->num_allocatable_double_registers() < 2) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 862 | return; |
| 863 | } |
| 864 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 865 | int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 866 | ArgsBuffer<float32>::Sig sig(2); |
| 867 | |
| 868 | Float32RegisterPairs pairs; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 869 | base::AccountingAllocator allocator; |
| 870 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 871 | while (pairs.More()) { |
| 872 | int parray[2]; |
| 873 | pairs.Next(&parray[0], &parray[1], false); |
| 874 | Allocator params(nullptr, 0, parray, 2); |
| 875 | Allocator rets(nullptr, 0, rarray, 1); |
| 876 | RegisterConfig config(params, rets); |
| 877 | |
| 878 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 879 | RunSelect<float32, 0>(desc); |
| 880 | RunSelect<float32, 1>(desc); |
| 881 | } |
| 882 | } |
| 883 | |
| 884 | |
| 885 | TEST(Float64Select_registers) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 886 | if (GetRegConfig()->num_allocatable_double_registers() < 2) return; |
| 887 | if (GetRegConfig()->num_allocatable_general_registers() < 2) return; |
| 888 | int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 889 | ArgsBuffer<float64>::Sig sig(2); |
| 890 | |
| 891 | Float64RegisterPairs pairs; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 892 | base::AccountingAllocator allocator; |
| 893 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 894 | while (pairs.More()) { |
| 895 | int parray[2]; |
| 896 | pairs.Next(&parray[0], &parray[1], false); |
| 897 | Allocator params(nullptr, 0, parray, 2); |
| 898 | Allocator rets(nullptr, 0, rarray, 1); |
| 899 | RegisterConfig config(params, rets); |
| 900 | |
| 901 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 902 | RunSelect<float64, 0>(desc); |
| 903 | RunSelect<float64, 1>(desc); |
| 904 | } |
| 905 | } |
| 906 | |
| 907 | |
| 908 | TEST(Float32Select_stack_params_return_reg) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 909 | int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 910 | Allocator params(nullptr, 0, nullptr, 0); |
| 911 | Allocator rets(nullptr, 0, rarray, 1); |
| 912 | RegisterConfig config(params, rets); |
| 913 | |
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 | for (int count = 1; count < 6; count++) { |
| 917 | ArgsBuffer<float32>::Sig sig(count); |
| 918 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 919 | RunSelect<float32, 0>(desc); |
| 920 | RunSelect<float32, 1>(desc); |
| 921 | RunSelect<float32, 2>(desc); |
| 922 | RunSelect<float32, 3>(desc); |
| 923 | RunSelect<float32, 4>(desc); |
| 924 | RunSelect<float32, 5>(desc); |
| 925 | } |
| 926 | } |
| 927 | |
| 928 | |
| 929 | TEST(Float64Select_stack_params_return_reg) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 930 | int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 931 | Allocator params(nullptr, 0, nullptr, 0); |
| 932 | Allocator rets(nullptr, 0, rarray, 1); |
| 933 | RegisterConfig config(params, rets); |
| 934 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 935 | base::AccountingAllocator allocator; |
| 936 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 937 | for (int count = 1; count < 6; count++) { |
| 938 | ArgsBuffer<float64>::Sig sig(count); |
| 939 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 940 | RunSelect<float64, 0>(desc); |
| 941 | RunSelect<float64, 1>(desc); |
| 942 | RunSelect<float64, 2>(desc); |
| 943 | RunSelect<float64, 3>(desc); |
| 944 | RunSelect<float64, 4>(desc); |
| 945 | RunSelect<float64, 5>(desc); |
| 946 | } |
| 947 | } |
| 948 | |
| 949 | |
| 950 | template <typename CType, int which> |
| 951 | static void Build_Select_With_Call(CallDescriptor* desc, |
| 952 | RawMachineAssembler& raw) { |
| 953 | Handle<Code> inner = Handle<Code>::null(); |
| 954 | int num_params = ParamCount(desc); |
| 955 | CHECK_LE(num_params, kMaxParamCount); |
| 956 | { |
| 957 | Isolate* isolate = CcTest::InitIsolateOnce(); |
| 958 | // Build the actual select. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 959 | Zone zone(isolate->allocator()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 960 | Graph graph(&zone); |
| 961 | RawMachineAssembler raw(isolate, &graph, desc); |
| 962 | raw.Return(raw.Parameter(which)); |
| 963 | inner = CompileGraph("Select-indirection", desc, &graph, raw.Export()); |
| 964 | CHECK(!inner.is_null()); |
| 965 | CHECK(inner->IsCode()); |
| 966 | } |
| 967 | |
| 968 | { |
| 969 | // Build a call to the function that does the select. |
| 970 | Node* target = raw.HeapConstant(inner); |
| 971 | Node** args = raw.zone()->NewArray<Node*>(num_params); |
| 972 | for (int i = 0; i < num_params; i++) { |
| 973 | args[i] = raw.Parameter(i); |
| 974 | } |
| 975 | |
| 976 | Node* call = raw.CallN(desc, target, args); |
| 977 | raw.Return(call); |
| 978 | } |
| 979 | } |
| 980 | |
| 981 | |
| 982 | TEST(Float64StackParamsToStackParams) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 983 | int rarray[] = {GetRegConfig()->GetAllocatableDoubleCode(0)}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 984 | Allocator params(nullptr, 0, nullptr, 0); |
| 985 | Allocator rets(nullptr, 0, rarray, 1); |
| 986 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 987 | base::AccountingAllocator allocator; |
| 988 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 989 | ArgsBuffer<float64>::Sig sig(2); |
| 990 | RegisterConfig config(params, rets); |
| 991 | CallDescriptor* desc = config.Create(&zone, &sig); |
| 992 | |
| 993 | Run_Computation<float64>(desc, Build_Select_With_Call<float64, 0>, |
| 994 | Compute_Select<float64, 0>, 1098); |
| 995 | |
| 996 | Run_Computation<float64>(desc, Build_Select_With_Call<float64, 1>, |
| 997 | Compute_Select<float64, 1>, 1099); |
| 998 | } |
| 999 | |
| 1000 | |
| 1001 | void MixedParamTest(int start) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1002 | if (GetRegConfig()->num_double_registers() < 2) return; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1003 | |
| 1004 | // TODO(titzer): mix in 64-bit types on all platforms when supported. |
| 1005 | #if V8_TARGET_ARCH_32_BIT |
| 1006 | static MachineType types[] = { |
| 1007 | MachineType::Int32(), MachineType::Float32(), MachineType::Float64(), |
| 1008 | MachineType::Int32(), MachineType::Float64(), MachineType::Float32(), |
| 1009 | MachineType::Float32(), MachineType::Float64(), MachineType::Int32(), |
| 1010 | MachineType::Float32(), MachineType::Int32(), MachineType::Float64(), |
| 1011 | MachineType::Float64(), MachineType::Float32(), MachineType::Int32(), |
| 1012 | MachineType::Float64(), MachineType::Int32(), MachineType::Float32()}; |
| 1013 | #else |
| 1014 | static MachineType types[] = { |
| 1015 | MachineType::Int32(), MachineType::Int64(), MachineType::Float32(), |
| 1016 | MachineType::Float64(), MachineType::Int32(), MachineType::Float64(), |
| 1017 | MachineType::Float32(), MachineType::Int64(), MachineType::Int64(), |
| 1018 | MachineType::Float32(), MachineType::Float32(), MachineType::Int32(), |
| 1019 | MachineType::Float64(), MachineType::Float64(), MachineType::Int64(), |
| 1020 | MachineType::Int32(), MachineType::Float64(), MachineType::Int32(), |
| 1021 | MachineType::Float32()}; |
| 1022 | #endif |
| 1023 | |
| 1024 | Isolate* isolate = CcTest::InitIsolateOnce(); |
| 1025 | |
| 1026 | // Build machine signature |
| 1027 | MachineType* params = &types[start]; |
| 1028 | const int num_params = static_cast<int>(arraysize(types) - start); |
| 1029 | |
| 1030 | // Build call descriptor |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1031 | int parray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0), |
| 1032 | GetRegConfig()->GetAllocatableGeneralCode(1)}; |
| 1033 | int rarray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0)}; |
| 1034 | int parray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0), |
| 1035 | GetRegConfig()->GetAllocatableDoubleCode(1)}; |
| 1036 | int rarray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0)}; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1037 | Allocator palloc(parray_gp, 2, parray_fp, 2); |
| 1038 | Allocator ralloc(rarray_gp, 1, rarray_fp, 1); |
| 1039 | RegisterConfig config(palloc, ralloc); |
| 1040 | |
| 1041 | for (int which = 0; which < num_params; which++) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 1042 | base::AccountingAllocator allocator; |
| 1043 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1044 | HandleScope scope(isolate); |
| 1045 | MachineSignature::Builder builder(&zone, 1, num_params); |
| 1046 | builder.AddReturn(params[which]); |
| 1047 | for (int j = 0; j < num_params; j++) builder.AddParam(params[j]); |
| 1048 | MachineSignature* sig = builder.Build(); |
| 1049 | CallDescriptor* desc = config.Create(&zone, sig); |
| 1050 | |
| 1051 | Handle<Code> select; |
| 1052 | { |
| 1053 | // build the select. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 1054 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1055 | Graph graph(&zone); |
| 1056 | RawMachineAssembler raw(isolate, &graph, desc); |
| 1057 | raw.Return(raw.Parameter(which)); |
| 1058 | select = CompileGraph("Compute", desc, &graph, raw.Export()); |
| 1059 | } |
| 1060 | |
| 1061 | { |
| 1062 | // call the select. |
| 1063 | Handle<Code> wrapper = Handle<Code>::null(); |
| 1064 | int32_t expected_ret; |
| 1065 | char bytes[kDoubleSize]; |
| 1066 | V8_ALIGNED(8) char output[kDoubleSize]; |
| 1067 | int expected_size = 0; |
| 1068 | CSignature0<int32_t> csig; |
| 1069 | { |
| 1070 | // Wrap the select code with a callable function that passes constants. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 1071 | Zone zone(&allocator); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1072 | Graph graph(&zone); |
| 1073 | CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); |
| 1074 | RawMachineAssembler raw(isolate, &graph, cdesc); |
| 1075 | Node* target = raw.HeapConstant(select); |
| 1076 | Node** args = zone.NewArray<Node*>(num_params); |
| 1077 | int64_t constant = 0x0102030405060708; |
| 1078 | for (int i = 0; i < num_params; i++) { |
| 1079 | MachineType param_type = sig->GetParam(i); |
| 1080 | Node* konst = nullptr; |
| 1081 | if (param_type == MachineType::Int32()) { |
| 1082 | int32_t value[] = {static_cast<int32_t>(constant)}; |
| 1083 | konst = raw.Int32Constant(value[0]); |
| 1084 | if (i == which) memcpy(bytes, value, expected_size = 4); |
| 1085 | } |
| 1086 | if (param_type == MachineType::Int64()) { |
| 1087 | int64_t value[] = {static_cast<int64_t>(constant)}; |
| 1088 | konst = raw.Int64Constant(value[0]); |
| 1089 | if (i == which) memcpy(bytes, value, expected_size = 8); |
| 1090 | } |
| 1091 | if (param_type == MachineType::Float32()) { |
| 1092 | float32 value[] = {static_cast<float32>(constant)}; |
| 1093 | konst = raw.Float32Constant(value[0]); |
| 1094 | if (i == which) memcpy(bytes, value, expected_size = 4); |
| 1095 | } |
| 1096 | if (param_type == MachineType::Float64()) { |
| 1097 | float64 value[] = {static_cast<float64>(constant)}; |
| 1098 | konst = raw.Float64Constant(value[0]); |
| 1099 | if (i == which) memcpy(bytes, value, expected_size = 8); |
| 1100 | } |
| 1101 | CHECK_NOT_NULL(konst); |
| 1102 | |
| 1103 | args[i] = konst; |
| 1104 | constant += 0x1010101010101010; |
| 1105 | } |
| 1106 | |
| 1107 | Node* call = raw.CallN(desc, target, args); |
| 1108 | Node* store = |
| 1109 | raw.StoreToPointer(output, sig->GetReturn().representation(), call); |
| 1110 | USE(store); |
| 1111 | expected_ret = static_cast<int32_t>(constant); |
| 1112 | raw.Return(raw.Int32Constant(expected_ret)); |
| 1113 | wrapper = CompileGraph("Select-mixed-wrapper-const", cdesc, &graph, |
| 1114 | raw.Export()); |
| 1115 | } |
| 1116 | |
| 1117 | CodeRunner<int32_t> runnable(isolate, wrapper, &csig); |
| 1118 | CHECK_EQ(expected_ret, runnable.Call()); |
| 1119 | for (int i = 0; i < expected_size; i++) { |
| 1120 | CHECK_EQ(static_cast<int>(bytes[i]), static_cast<int>(output[i])); |
| 1121 | } |
| 1122 | } |
| 1123 | } |
| 1124 | } |
| 1125 | |
| 1126 | |
| 1127 | TEST(MixedParams_0) { MixedParamTest(0); } |
| 1128 | TEST(MixedParams_1) { MixedParamTest(1); } |
| 1129 | TEST(MixedParams_2) { MixedParamTest(2); } |
| 1130 | TEST(MixedParams_3) { MixedParamTest(3); } |
| 1131 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1132 | template <typename T> |
| 1133 | void TestStackSlot(MachineType slot_type, T expected) { |
| 1134 | // Test: Generate with a function f which reserves a stack slot, call an inner |
| 1135 | // function g from f which writes into the stack slot of f. |
| 1136 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1137 | if (GetRegConfig()->num_allocatable_double_registers() < 2) return; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1138 | |
| 1139 | Isolate* isolate = CcTest::InitIsolateOnce(); |
| 1140 | |
| 1141 | // Lots of code to generate the build descriptor for the inner function. |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 1142 | int parray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0), |
| 1143 | GetRegConfig()->GetAllocatableGeneralCode(1)}; |
| 1144 | int rarray_gp[] = {GetRegConfig()->GetAllocatableGeneralCode(0)}; |
| 1145 | int parray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0), |
| 1146 | GetRegConfig()->GetAllocatableDoubleCode(1)}; |
| 1147 | int rarray_fp[] = {GetRegConfig()->GetAllocatableDoubleCode(0)}; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1148 | Allocator palloc(parray_gp, 2, parray_fp, 2); |
| 1149 | Allocator ralloc(rarray_gp, 1, rarray_fp, 1); |
| 1150 | RegisterConfig config(palloc, ralloc); |
| 1151 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 1152 | Zone zone(isolate->allocator()); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1153 | HandleScope scope(isolate); |
| 1154 | MachineSignature::Builder builder(&zone, 1, 12); |
| 1155 | builder.AddReturn(MachineType::Int32()); |
| 1156 | for (int i = 0; i < 10; i++) { |
| 1157 | builder.AddParam(MachineType::Int32()); |
| 1158 | } |
| 1159 | builder.AddParam(slot_type); |
| 1160 | builder.AddParam(MachineType::Pointer()); |
| 1161 | MachineSignature* sig = builder.Build(); |
| 1162 | CallDescriptor* desc = config.Create(&zone, sig); |
| 1163 | |
| 1164 | // Create inner function g. g has lots of parameters so that they are passed |
| 1165 | // over the stack. |
| 1166 | Handle<Code> inner; |
| 1167 | Graph graph(&zone); |
| 1168 | RawMachineAssembler g(isolate, &graph, desc); |
| 1169 | |
| 1170 | g.Store(slot_type.representation(), g.Parameter(11), g.Parameter(10), |
| 1171 | WriteBarrierKind::kNoWriteBarrier); |
| 1172 | g.Return(g.Parameter(9)); |
| 1173 | inner = CompileGraph("Compute", desc, &graph, g.Export()); |
| 1174 | |
| 1175 | // Create function f with a stack slot which calls the inner function g. |
| 1176 | BufferedRawMachineAssemblerTester<T> f(slot_type); |
| 1177 | Node* target = f.HeapConstant(inner); |
| 1178 | Node* stack_slot = f.StackSlot(slot_type.representation()); |
| 1179 | Node* args[12]; |
| 1180 | for (int i = 0; i < 10; i++) { |
| 1181 | args[i] = f.Int32Constant(i); |
| 1182 | } |
| 1183 | args[10] = f.Parameter(0); |
| 1184 | args[11] = stack_slot; |
| 1185 | |
| 1186 | f.CallN(desc, target, args); |
| 1187 | f.Return(f.Load(slot_type, stack_slot, f.IntPtrConstant(0))); |
| 1188 | |
| 1189 | CHECK_EQ(expected, f.Call(expected)); |
| 1190 | } |
| 1191 | |
| 1192 | TEST(RunStackSlotInt32) { |
| 1193 | int32_t magic = 0x12345678; |
| 1194 | TestStackSlot(MachineType::Int32(), magic); |
| 1195 | } |
| 1196 | |
| 1197 | #if !V8_TARGET_ARCH_32_BIT |
| 1198 | TEST(RunStackSlotInt64) { |
| 1199 | int64_t magic = 0x123456789abcdef0; |
| 1200 | TestStackSlot(MachineType::Int64(), magic); |
| 1201 | } |
| 1202 | #endif |
| 1203 | |
| 1204 | TEST(RunStackSlotFloat32) { |
| 1205 | float magic = 1234.125f; |
| 1206 | TestStackSlot(MachineType::Float32(), magic); |
| 1207 | } |
| 1208 | |
| 1209 | TEST(RunStackSlotFloat64) { |
| 1210 | double magic = 3456.375; |
| 1211 | TestStackSlot(MachineType::Float64(), magic); |
| 1212 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1213 | } // namespace compiler |
| 1214 | } // namespace internal |
| 1215 | } // namespace v8 |