Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: src/compiler/register-allocator.cc

Issue 810403003: [turbofan] remove checks for virtual register overflow (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/register-allocator.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/linkage.h" 5 #include "src/compiler/linkage.h"
6 #include "src/compiler/register-allocator.h" 6 #include "src/compiler/register-allocator.h"
7 #include "src/string-stream.h" 7 #include "src/string-stream.h"
8 8
9 namespace v8 { 9 namespace v8 {
10 namespace internal { 10 namespace internal {
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 fixed_live_ranges_(this->config()->num_general_registers(), nullptr, 568 fixed_live_ranges_(this->config()->num_general_registers(), nullptr,
569 local_zone()), 569 local_zone()),
570 fixed_double_live_ranges_(this->config()->num_double_registers(), nullptr, 570 fixed_double_live_ranges_(this->config()->num_double_registers(), nullptr,
571 local_zone()), 571 local_zone()),
572 unhandled_live_ranges_(local_zone()), 572 unhandled_live_ranges_(local_zone()),
573 active_live_ranges_(local_zone()), 573 active_live_ranges_(local_zone()),
574 inactive_live_ranges_(local_zone()), 574 inactive_live_ranges_(local_zone()),
575 reusable_slots_(local_zone()), 575 reusable_slots_(local_zone()),
576 spill_ranges_(local_zone()), 576 spill_ranges_(local_zone()),
577 mode_(UNALLOCATED_REGISTERS), 577 mode_(UNALLOCATED_REGISTERS),
578 num_registers_(-1), 578 num_registers_(-1) {
579 allocation_ok_(true) {
580 DCHECK(this->config()->num_general_registers() <= 579 DCHECK(this->config()->num_general_registers() <=
581 RegisterConfiguration::kMaxGeneralRegisters); 580 RegisterConfiguration::kMaxGeneralRegisters);
582 DCHECK(this->config()->num_double_registers() <= 581 DCHECK(this->config()->num_double_registers() <=
583 RegisterConfiguration::kMaxDoubleRegisters); 582 RegisterConfiguration::kMaxDoubleRegisters);
584 // TryAllocateFreeReg and AllocateBlockedReg assume this 583 // TryAllocateFreeReg and AllocateBlockedReg assume this
585 // when allocating local arrays. 584 // when allocating local arrays.
586 DCHECK(RegisterConfiguration::kMaxDoubleRegisters >= 585 DCHECK(RegisterConfiguration::kMaxDoubleRegisters >=
587 this->config()->num_general_registers()); 586 this->config()->num_general_registers());
588 unhandled_live_ranges().reserve( 587 unhandled_live_ranges().reserve(
589 static_cast<size_t>(code->VirtualRegisterCount() * 2)); 588 static_cast<size_t>(code->VirtualRegisterCount() * 2));
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after
1017 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); 1016 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos);
1018 if (pos == nullptr) { 1017 if (pos == nullptr) {
1019 auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); 1018 auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel());
1020 CHECK(first_op_spill->TryMerge(spill_range)); 1019 CHECK(first_op_spill->TryMerge(spill_range));
1021 Spill(range); 1020 Spill(range);
1022 return true; 1021 return true;
1023 } else if (pos->pos().Value() > range->Start().NextInstruction().Value()) { 1022 } else if (pos->pos().Value() > range->Start().NextInstruction().Value()) {
1024 auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); 1023 auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel());
1025 CHECK(first_op_spill->TryMerge(spill_range)); 1024 CHECK(first_op_spill->TryMerge(spill_range));
1026 SpillBetween(range, range->Start(), pos->pos()); 1025 SpillBetween(range, range->Start(), pos->pos());
1027 if (!AllocationOk()) return false;
1028 DCHECK(UnhandledIsSorted()); 1026 DCHECK(UnhandledIsSorted());
1029 return true; 1027 return true;
1030 } 1028 }
1031 return false; 1029 return false;
1032 } 1030 }
1033 1031
1034 1032
1035 void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) { 1033 void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) {
1036 int start = block->first_instruction_index(); 1034 int start = block->first_instruction_index();
1037 int end = block->last_instruction_index(); 1035 int end = block->last_instruction_index();
1038 DCHECK_NE(-1, start); 1036 DCHECK_NE(-1, start);
1039 for (int i = start; i <= end; ++i) { 1037 for (int i = start; i <= end; ++i) {
1040 if (code()->IsGapAt(i)) { 1038 if (code()->IsGapAt(i)) {
1041 Instruction* instr = nullptr; 1039 Instruction* instr = nullptr;
1042 Instruction* prev_instr = nullptr; 1040 Instruction* prev_instr = nullptr;
1043 if (i < end) instr = InstructionAt(i + 1); 1041 if (i < end) instr = InstructionAt(i + 1);
1044 if (i > start) prev_instr = InstructionAt(i - 1); 1042 if (i > start) prev_instr = InstructionAt(i - 1);
1045 MeetConstraintsBetween(prev_instr, instr, i); 1043 MeetConstraintsBetween(prev_instr, instr, i);
1046 if (!AllocationOk()) return;
1047 } 1044 }
1048 } 1045 }
1049 1046
1050 // Meet register constraints for the instruction in the end. 1047 // Meet register constraints for the instruction in the end.
1051 if (!code()->IsGapAt(end)) { 1048 if (!code()->IsGapAt(end)) {
1052 MeetRegisterConstraintsForLastInstructionInBlock(block); 1049 MeetRegisterConstraintsForLastInstructionInBlock(block);
1053 } 1050 }
1054 } 1051 }
1055 1052
1056 1053
(...skipping 868 matching lines...) Expand 10 before | Expand all | Expand 10 after
1925 // If the range already has a spill operand and it doesn't need a 1922 // If the range already has a spill operand and it doesn't need a
1926 // register immediately, split it and spill the first part of the range. 1923 // register immediately, split it and spill the first part of the range.
1927 if (pos == nullptr) { 1924 if (pos == nullptr) {
1928 Spill(current); 1925 Spill(current);
1929 continue; 1926 continue;
1930 } else if (pos->pos().Value() > 1927 } else if (pos->pos().Value() >
1931 current->Start().NextInstruction().Value()) { 1928 current->Start().NextInstruction().Value()) {
1932 // Do not spill live range eagerly if use position that can benefit from 1929 // Do not spill live range eagerly if use position that can benefit from
1933 // the register is too close to the start of live range. 1930 // the register is too close to the start of live range.
1934 SpillBetween(current, current->Start(), pos->pos()); 1931 SpillBetween(current, current->Start(), pos->pos());
1935 if (!AllocationOk()) return;
1936 DCHECK(UnhandledIsSorted()); 1932 DCHECK(UnhandledIsSorted());
1937 continue; 1933 continue;
1938 } 1934 }
1939 } 1935 }
1940 1936
1941 if (FLAG_turbo_reuse_spill_slots) { 1937 if (FLAG_turbo_reuse_spill_slots) {
1942 if (TryReuseSpillForPhi(current)) { 1938 if (TryReuseSpillForPhi(current)) {
1943 continue; 1939 continue;
1944 } 1940 }
1945 if (!AllocationOk()) return;
1946 } 1941 }
1947 1942
1948 for (size_t i = 0; i < active_live_ranges().size(); ++i) { 1943 for (size_t i = 0; i < active_live_ranges().size(); ++i) {
1949 auto cur_active = active_live_ranges()[i]; 1944 auto cur_active = active_live_ranges()[i];
1950 if (cur_active->End().Value() <= position.Value()) { 1945 if (cur_active->End().Value() <= position.Value()) {
1951 ActiveToHandled(cur_active); 1946 ActiveToHandled(cur_active);
1952 --i; // The live range was removed from the list of active live ranges. 1947 --i; // The live range was removed from the list of active live ranges.
1953 } else if (!cur_active->Covers(position)) { 1948 } else if (!cur_active->Covers(position)) {
1954 ActiveToInactive(cur_active); 1949 ActiveToInactive(cur_active);
1955 --i; // The live range was removed from the list of active live ranges. 1950 --i; // The live range was removed from the list of active live ranges.
1956 } 1951 }
1957 } 1952 }
1958 1953
1959 for (size_t i = 0; i < inactive_live_ranges().size(); ++i) { 1954 for (size_t i = 0; i < inactive_live_ranges().size(); ++i) {
1960 auto cur_inactive = inactive_live_ranges()[i]; 1955 auto cur_inactive = inactive_live_ranges()[i];
1961 if (cur_inactive->End().Value() <= position.Value()) { 1956 if (cur_inactive->End().Value() <= position.Value()) {
1962 InactiveToHandled(cur_inactive); 1957 InactiveToHandled(cur_inactive);
1963 --i; // Live range was removed from the list of inactive live ranges. 1958 --i; // Live range was removed from the list of inactive live ranges.
1964 } else if (cur_inactive->Covers(position)) { 1959 } else if (cur_inactive->Covers(position)) {
1965 InactiveToActive(cur_inactive); 1960 InactiveToActive(cur_inactive);
1966 --i; // Live range was removed from the list of inactive live ranges. 1961 --i; // Live range was removed from the list of inactive live ranges.
1967 } 1962 }
1968 } 1963 }
1969 1964
1970 DCHECK(!current->HasRegisterAssigned() && !current->IsSpilled()); 1965 DCHECK(!current->HasRegisterAssigned() && !current->IsSpilled());
1971 1966
1972 bool result = TryAllocateFreeReg(current); 1967 bool result = TryAllocateFreeReg(current);
1973 if (!AllocationOk()) return;
1974
1975 if (!result) AllocateBlockedReg(current); 1968 if (!result) AllocateBlockedReg(current);
1976 if (!AllocationOk()) return;
1977
1978 if (current->HasRegisterAssigned()) { 1969 if (current->HasRegisterAssigned()) {
1979 AddToActive(current); 1970 AddToActive(current);
1980 } 1971 }
1981 } 1972 }
1982 1973
1983 reusable_slots().clear(); 1974 reusable_slots().clear();
1984 active_live_ranges().clear(); 1975 active_live_ranges().clear();
1985 inactive_live_ranges().clear(); 1976 inactive_live_ranges().clear();
1986 } 1977 }
1987 1978
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
2179 2170
2180 if (pos.Value() <= current->Start().Value()) { 2171 if (pos.Value() <= current->Start().Value()) {
2181 // All registers are blocked. 2172 // All registers are blocked.
2182 return false; 2173 return false;
2183 } 2174 }
2184 2175
2185 if (pos.Value() < current->End().Value()) { 2176 if (pos.Value() < current->End().Value()) {
2186 // Register reg is available at the range start but becomes blocked before 2177 // Register reg is available at the range start but becomes blocked before
2187 // the range end. Split current at position where it becomes blocked. 2178 // the range end. Split current at position where it becomes blocked.
2188 auto tail = SplitRangeAt(current, pos); 2179 auto tail = SplitRangeAt(current, pos);
2189 if (!AllocationOk()) return false;
2190 AddToUnhandledSorted(tail); 2180 AddToUnhandledSorted(tail);
2191 } 2181 }
2192 2182
2193 // Register reg is available at the range start and is free until 2183 // Register reg is available at the range start and is free until
2194 // the range end. 2184 // the range end.
2195 DCHECK(pos.Value() >= current->End().Value()); 2185 DCHECK(pos.Value() >= current->End().Value());
2196 TraceAlloc("Assigning free reg %s to live range %d\n", RegisterName(reg), 2186 TraceAlloc("Assigning free reg %s to live range %d\n", RegisterName(reg),
2197 current->id()); 2187 current->id());
2198 SetLiveRangeAssignedRegister(current, reg); 2188 SetLiveRangeAssignedRegister(current, reg);
2199 2189
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
2260 // Spill starting part of live range up to that use. 2250 // Spill starting part of live range up to that use.
2261 SpillBetween(current, current->Start(), register_use->pos()); 2251 SpillBetween(current, current->Start(), register_use->pos());
2262 return; 2252 return;
2263 } 2253 }
2264 2254
2265 if (block_pos[reg].Value() < current->End().Value()) { 2255 if (block_pos[reg].Value() < current->End().Value()) {
2266 // Register becomes blocked before the current range end. Split before that 2256 // Register becomes blocked before the current range end. Split before that
2267 // position. 2257 // position.
2268 LiveRange* tail = SplitBetween(current, current->Start(), 2258 LiveRange* tail = SplitBetween(current, current->Start(),
2269 block_pos[reg].InstructionStart()); 2259 block_pos[reg].InstructionStart());
2270 if (!AllocationOk()) return;
2271 AddToUnhandledSorted(tail); 2260 AddToUnhandledSorted(tail);
2272 } 2261 }
2273 2262
2274 // Register reg is not blocked for the whole range. 2263 // Register reg is not blocked for the whole range.
2275 DCHECK(block_pos[reg].Value() >= current->End().Value()); 2264 DCHECK(block_pos[reg].Value() >= current->End().Value());
2276 TraceAlloc("Assigning blocked reg %s to live range %d\n", RegisterName(reg), 2265 TraceAlloc("Assigning blocked reg %s to live range %d\n", RegisterName(reg),
2277 current->id()); 2266 current->id());
2278 SetLiveRangeAssignedRegister(current, reg); 2267 SetLiveRangeAssignedRegister(current, reg);
2279 2268
2280 // This register was not free. Thus we need to find and spill 2269 // This register was not free. Thus we need to find and spill
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
2339 // When spilling between spill_pos and next_pos ensure that the range 2328 // When spilling between spill_pos and next_pos ensure that the range
2340 // remains spilled at least until the start of the current live range. 2329 // remains spilled at least until the start of the current live range.
2341 // This guarantees that we will not introduce new unhandled ranges that 2330 // This guarantees that we will not introduce new unhandled ranges that
2342 // start before the current range as this violates allocation invariant 2331 // start before the current range as this violates allocation invariant
2343 // and will lead to an inconsistent state of active and inactive 2332 // and will lead to an inconsistent state of active and inactive
2344 // live-ranges: ranges are allocated in order of their start positions, 2333 // live-ranges: ranges are allocated in order of their start positions,
2345 // ranges are retired from active/inactive when the start of the 2334 // ranges are retired from active/inactive when the start of the
2346 // current live-range is larger than their end. 2335 // current live-range is larger than their end.
2347 SpillBetweenUntil(range, spill_pos, current->Start(), next_pos->pos()); 2336 SpillBetweenUntil(range, spill_pos, current->Start(), next_pos->pos());
2348 } 2337 }
2349 if (!AllocationOk()) return;
2350 ActiveToHandled(range); 2338 ActiveToHandled(range);
2351 --i; 2339 --i;
2352 } 2340 }
2353 } 2341 }
2354 2342
2355 for (size_t i = 0; i < inactive_live_ranges().size(); ++i) { 2343 for (size_t i = 0; i < inactive_live_ranges().size(); ++i) {
2356 auto range = inactive_live_ranges()[i]; 2344 auto range = inactive_live_ranges()[i];
2357 DCHECK(range->End().Value() > current->Start().Value()); 2345 DCHECK(range->End().Value() > current->Start().Value());
2358 if (range->assigned_register() == reg && !range->IsFixed()) { 2346 if (range->assigned_register() == reg && !range->IsFixed()) {
2359 LifetimePosition next_intersection = range->FirstIntersection(current); 2347 LifetimePosition next_intersection = range->FirstIntersection(current);
2360 if (next_intersection.IsValid()) { 2348 if (next_intersection.IsValid()) {
2361 UsePosition* next_pos = range->NextRegisterPosition(current->Start()); 2349 UsePosition* next_pos = range->NextRegisterPosition(current->Start());
2362 if (next_pos == nullptr) { 2350 if (next_pos == nullptr) {
2363 SpillAfter(range, split_pos); 2351 SpillAfter(range, split_pos);
2364 } else { 2352 } else {
2365 next_intersection = Min(next_intersection, next_pos->pos()); 2353 next_intersection = Min(next_intersection, next_pos->pos());
2366 SpillBetween(range, split_pos, next_intersection); 2354 SpillBetween(range, split_pos, next_intersection);
2367 } 2355 }
2368 if (!AllocationOk()) return;
2369 InactiveToHandled(range); 2356 InactiveToHandled(range);
2370 --i; 2357 --i;
2371 } 2358 }
2372 } 2359 }
2373 } 2360 }
2374 } 2361 }
2375 2362
2376 2363
2377 bool RegisterAllocator::IsBlockBoundary(LifetimePosition pos) { 2364 bool RegisterAllocator::IsBlockBoundary(LifetimePosition pos) {
2378 return pos.IsInstructionStart() && 2365 return pos.IsInstructionStart() &&
2379 InstructionAt(pos.InstructionIndex())->IsBlockStart(); 2366 InstructionAt(pos.InstructionIndex())->IsBlockStart();
2380 } 2367 }
2381 2368
2382 2369
2383 LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range, 2370 LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range,
2384 LifetimePosition pos) { 2371 LifetimePosition pos) {
2385 DCHECK(!range->IsFixed()); 2372 DCHECK(!range->IsFixed());
2386 TraceAlloc("Splitting live range %d at %d\n", range->id(), pos.Value()); 2373 TraceAlloc("Splitting live range %d at %d\n", range->id(), pos.Value());
2387 2374
2388 if (pos.Value() <= range->Start().Value()) return range; 2375 if (pos.Value() <= range->Start().Value()) return range;
2389 2376
2390 // We can't properly connect liveranges if split occured at the end 2377 // We can't properly connect liveranges if split occured at the end
2391 // of control instruction. 2378 // of control instruction.
2392 DCHECK(pos.IsInstructionStart() || 2379 DCHECK(pos.IsInstructionStart() ||
2393 !InstructionAt(pos.InstructionIndex())->IsControl()); 2380 !InstructionAt(pos.InstructionIndex())->IsControl());
2394 2381
2395 int vreg = GetVirtualRegister(); 2382 int vreg = GetVirtualRegister();
2396 if (!AllocationOk()) return nullptr;
2397 auto result = LiveRangeFor(vreg); 2383 auto result = LiveRangeFor(vreg);
2398 range->SplitAt(pos, result, local_zone()); 2384 range->SplitAt(pos, result, local_zone());
2399 return result; 2385 return result;
2400 } 2386 }
2401 2387
2402 2388
2403 LiveRange* RegisterAllocator::SplitBetween(LiveRange* range, 2389 LiveRange* RegisterAllocator::SplitBetween(LiveRange* range,
2404 LifetimePosition start, 2390 LifetimePosition start,
2405 LifetimePosition end) { 2391 LifetimePosition end) {
2406 DCHECK(!range->IsFixed()); 2392 DCHECK(!range->IsFixed());
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
2444 // position unless end_block is a loop header itself. 2430 // position unless end_block is a loop header itself.
2445 if (block == end_block && !end_block->IsLoopHeader()) return end; 2431 if (block == end_block && !end_block->IsLoopHeader()) return end;
2446 2432
2447 return LifetimePosition::FromInstructionIndex( 2433 return LifetimePosition::FromInstructionIndex(
2448 block->first_instruction_index()); 2434 block->first_instruction_index());
2449 } 2435 }
2450 2436
2451 2437
2452 void RegisterAllocator::SpillAfter(LiveRange* range, LifetimePosition pos) { 2438 void RegisterAllocator::SpillAfter(LiveRange* range, LifetimePosition pos) {
2453 auto second_part = SplitRangeAt(range, pos); 2439 auto second_part = SplitRangeAt(range, pos);
2454 if (!AllocationOk()) return;
2455 Spill(second_part); 2440 Spill(second_part);
2456 } 2441 }
2457 2442
2458 2443
2459 void RegisterAllocator::SpillBetween(LiveRange* range, LifetimePosition start, 2444 void RegisterAllocator::SpillBetween(LiveRange* range, LifetimePosition start,
2460 LifetimePosition end) { 2445 LifetimePosition end) {
2461 SpillBetweenUntil(range, start, start, end); 2446 SpillBetweenUntil(range, start, start, end);
2462 } 2447 }
2463 2448
2464 2449
2465 void RegisterAllocator::SpillBetweenUntil(LiveRange* range, 2450 void RegisterAllocator::SpillBetweenUntil(LiveRange* range,
2466 LifetimePosition start, 2451 LifetimePosition start,
2467 LifetimePosition until, 2452 LifetimePosition until,
2468 LifetimePosition end) { 2453 LifetimePosition end) {
2469 CHECK(start.Value() < end.Value()); 2454 CHECK(start.Value() < end.Value());
2470 auto second_part = SplitRangeAt(range, start); 2455 auto second_part = SplitRangeAt(range, start);
2471 if (!AllocationOk()) return;
2472 2456
2473 if (second_part->Start().Value() < end.Value()) { 2457 if (second_part->Start().Value() < end.Value()) {
2474 // The split result intersects with [start, end[. 2458 // The split result intersects with [start, end[.
2475 // Split it at position between ]start+1, end[, spill the middle part 2459 // Split it at position between ]start+1, end[, spill the middle part
2476 // and put the rest to unhandled. 2460 // and put the rest to unhandled.
2477 auto third_part = SplitBetween( 2461 auto third_part = SplitBetween(
2478 second_part, Max(second_part->Start().InstructionEnd(), until), 2462 second_part, Max(second_part->Start().InstructionEnd(), until),
2479 end.PrevInstruction().InstructionEnd()); 2463 end.PrevInstruction().InstructionEnd());
2480 if (!AllocationOk()) return;
2481 2464
2482 DCHECK(third_part != second_part); 2465 DCHECK(third_part != second_part);
2483 2466
2484 Spill(second_part); 2467 Spill(second_part);
2485 AddToUnhandledSorted(third_part); 2468 AddToUnhandledSorted(third_part);
2486 } else { 2469 } else {
2487 // The split result does not intersect with [start, end[. 2470 // The split result does not intersect with [start, end[.
2488 // Nothing to spill. Just put it to unhandled as whole. 2471 // Nothing to spill. Just put it to unhandled as whole.
2489 AddToUnhandledSorted(second_part); 2472 AddToUnhandledSorted(second_part);
2490 } 2473 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
2539 } else { 2522 } else {
2540 DCHECK(range->Kind() == GENERAL_REGISTERS); 2523 DCHECK(range->Kind() == GENERAL_REGISTERS);
2541 assigned_registers_->Add(reg); 2524 assigned_registers_->Add(reg);
2542 } 2525 }
2543 range->set_assigned_register(reg, code_zone()); 2526 range->set_assigned_register(reg, code_zone());
2544 } 2527 }
2545 2528
2546 } // namespace compiler 2529 } // namespace compiler
2547 } // namespace internal 2530 } // namespace internal
2548 } // namespace v8 2531 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/register-allocator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698