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

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

Issue 1132753005: Greedy allocator: perf work (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: perf try Created 5 years, 7 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
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/base/adapters.h" 5 #include "src/base/adapters.h"
6 #include "src/compiler/linkage.h" 6 #include "src/compiler/linkage.h"
7 #include "src/compiler/register-allocator.h" 7 #include "src/compiler/register-allocator.h"
8 #include "src/string-stream.h" 8 #include "src/string-stream.h"
9 9
10 namespace v8 { 10 namespace v8 {
(...skipping 29 matching lines...) Expand all
40 40
41 41
42 const InstructionBlock* GetContainingLoop(const InstructionSequence* sequence, 42 const InstructionBlock* GetContainingLoop(const InstructionSequence* sequence,
43 const InstructionBlock* block) { 43 const InstructionBlock* block) {
44 auto index = block->loop_header(); 44 auto index = block->loop_header();
45 if (!index.IsValid()) return nullptr; 45 if (!index.IsValid()) return nullptr;
46 return sequence->InstructionBlockAt(index); 46 return sequence->InstructionBlockAt(index);
47 } 47 }
48 48
49 49
50 unsigned GetContainingLoopCount(const InstructionSequence* sequence,
51 const InstructionBlock* block) {
52 if (block->loop_header().IsValid()) return 1;
Jarin 2015/05/13 13:12:56 Can't you use block->IsLoopHeader()?
53
54 if (block->PredecessorCount() == 0)
Jarin 2015/05/13 13:12:56 Style nit: only omit the parentheses if the statem
55 return 0;
56 else
57 return GetContainingLoopCount(
58 sequence, sequence->InstructionBlockAt(block->predecessors()[0]));
Jarin 2015/05/13 13:12:56 Can we get rid of the recursion? More importantly
59 }
60
61
50 const InstructionBlock* GetInstructionBlock(const InstructionSequence* code, 62 const InstructionBlock* GetInstructionBlock(const InstructionSequence* code,
51 LifetimePosition pos) { 63 LifetimePosition pos) {
52 return code->GetInstructionBlock(pos.ToInstructionIndex()); 64 return code->GetInstructionBlock(pos.ToInstructionIndex());
53 } 65 }
54 66
55 67
56 bool IsBlockBoundary(const InstructionSequence* code, LifetimePosition pos) { 68 bool IsBlockBoundary(const InstructionSequence* code, LifetimePosition pos) {
57 return pos.IsFullStart() && 69 return pos.IsFullStart() &&
58 code->GetInstructionBlock(pos.ToInstructionIndex())->code_start() == 70 code->GetInstructionBlock(pos.ToInstructionIndex())->code_start() ==
59 pos.ToInstructionIndex(); 71 pos.ToInstructionIndex();
(...skipping 728 matching lines...) Expand 10 before | Expand all | Expand 10 after
788 os << "Range: " << range->id() << " "; 800 os << "Range: " << range->id() << " ";
789 if (range->is_phi()) os << "phi "; 801 if (range->is_phi()) os << "phi ";
790 if (range->is_non_loop_phi()) os << "nlphi "; 802 if (range->is_non_loop_phi()) os << "nlphi ";
791 803
792 os << "{" << std::endl; 804 os << "{" << std::endl;
793 auto interval = range->first_interval(); 805 auto interval = range->first_interval();
794 auto use_pos = range->first_pos(); 806 auto use_pos = range->first_pos();
795 PrintableInstructionOperand pio; 807 PrintableInstructionOperand pio;
796 pio.register_configuration_ = printable_range.register_configuration_; 808 pio.register_configuration_ = printable_range.register_configuration_;
797 while (use_pos != nullptr) { 809 while (use_pos != nullptr) {
798 pio.op_ = *use_pos->operand(); 810 if (use_pos->HasOperand()) {
799 os << pio << use_pos->pos() << " "; 811 pio.op_ = *use_pos->operand();
812 os << pio << use_pos->pos() << " ";
813 } else {
814 os << "<no_op> ";
815 }
800 use_pos = use_pos->next(); 816 use_pos = use_pos->next();
801 } 817 }
802 os << std::endl; 818 os << std::endl;
803 819
804 while (interval != nullptr) { 820 while (interval != nullptr) {
805 os << '[' << interval->start() << ", " << interval->end() << ')' 821 os << '[' << interval->start() << ", " << interval->end() << ')'
806 << std::endl; 822 << std::endl;
807 interval = interval->next(); 823 interval = interval->next();
808 } 824 }
809 os << "}"; 825 os << "}";
(...skipping 1027 matching lines...) Expand 10 before | Expand all | Expand 10 after
1837 // Try hoisting out to an outer loop. 1853 // Try hoisting out to an outer loop.
1838 loop_header = GetContainingLoop(code(), loop_header); 1854 loop_header = GetContainingLoop(code(), loop_header);
1839 } 1855 }
1840 1856
1841 return pos; 1857 return pos;
1842 } 1858 }
1843 1859
1844 1860
1845 void RegisterAllocator::Spill(LiveRange* range) { 1861 void RegisterAllocator::Spill(LiveRange* range) {
1846 DCHECK(!range->spilled()); 1862 DCHECK(!range->spilled());
1863 stats_.spills++;
1864
1847 TRACE("Spilling live range %d\n", range->id()); 1865 TRACE("Spilling live range %d\n", range->id());
1848 auto first = range->TopLevel(); 1866 auto first = range->TopLevel();
1849 if (first->HasNoSpillType()) { 1867 if (first->HasNoSpillType()) {
1850 data()->AssignSpillRangeToLiveRange(first); 1868 data()->AssignSpillRangeToLiveRange(first);
1851 } 1869 }
1852 range->Spill(); 1870 range->Spill();
1853 } 1871 }
1854 1872
1855 1873
1856 LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data, 1874 LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data,
1857 RegisterKind kind, Zone* local_zone) 1875 RegisterKind kind, Zone* local_zone)
1858 : RegisterAllocator(data, kind), 1876 : RegisterAllocator(data, kind),
1859 unhandled_live_ranges_(local_zone), 1877 unhandled_live_ranges_(local_zone),
1860 active_live_ranges_(local_zone), 1878 active_live_ranges_(local_zone),
1861 inactive_live_ranges_(local_zone) { 1879 inactive_live_ranges_(local_zone) {
1862 unhandled_live_ranges().reserve( 1880 unhandled_live_ranges().reserve(
1863 static_cast<size_t>(code()->VirtualRegisterCount() * 2)); 1881 static_cast<size_t>(code()->VirtualRegisterCount() * 2));
1864 active_live_ranges().reserve(8); 1882 active_live_ranges().reserve(8);
1865 inactive_live_ranges().reserve(8); 1883 inactive_live_ranges().reserve(8);
1866 // TryAllocateFreeReg and AllocateBlockedReg assume this 1884 // TryAllocateFreeReg and AllocateBlockedReg assume this
1867 // when allocating local arrays. 1885 // when allocating local arrays.
1868 DCHECK(RegisterConfiguration::kMaxDoubleRegisters >= 1886 DCHECK(RegisterConfiguration::kMaxDoubleRegisters >=
1869 this->data()->config()->num_general_registers()); 1887 this->data()->config()->num_general_registers());
1870 } 1888 }
1871 1889
1872 1890
1873 void LinearScanAllocator::AllocateRegisters() { 1891 void LinearScanAllocator::AllocateRegisters() {
1892 stats_.reset();
1893 unsigned range_count = 0;
1874 DCHECK(unhandled_live_ranges().empty()); 1894 DCHECK(unhandled_live_ranges().empty());
1875 DCHECK(active_live_ranges().empty()); 1895 DCHECK(active_live_ranges().empty());
1876 DCHECK(inactive_live_ranges().empty()); 1896 DCHECK(inactive_live_ranges().empty());
1877 1897 TRACE("Begin allocating function %s with the Linear Allocator\n",
1898 data()->debug_name());
1878 for (auto range : data()->live_ranges()) { 1899 for (auto range : data()->live_ranges()) {
1879 if (range == nullptr) continue; 1900 if (range == nullptr) continue;
1880 if (range->kind() == mode()) { 1901 if (range->kind() == mode()) {
1902 range_count++;
1881 AddToUnhandledUnsorted(range); 1903 AddToUnhandledUnsorted(range);
1882 } 1904 }
1883 } 1905 }
1884 SortUnhandled(); 1906 SortUnhandled();
1885 DCHECK(UnhandledIsSorted()); 1907 DCHECK(UnhandledIsSorted());
1886 1908
1887 auto& fixed_ranges = GetFixedRegisters(data(), mode()); 1909 auto& fixed_ranges = GetFixedRegisters(data(), mode());
1888 for (auto current : fixed_ranges) { 1910 for (auto current : fixed_ranges) {
1889 if (current != nullptr) { 1911 if (current != nullptr) {
1890 DCHECK_EQ(mode(), current->kind()); 1912 DCHECK_EQ(mode(), current->kind());
(...skipping 26 matching lines...) Expand all
1917 continue; 1939 continue;
1918 } else if (pos->pos() > current->Start().NextStart()) { 1940 } else if (pos->pos() > current->Start().NextStart()) {
1919 // Do not spill live range eagerly if use position that can benefit from 1941 // Do not spill live range eagerly if use position that can benefit from
1920 // the register is too close to the start of live range. 1942 // the register is too close to the start of live range.
1921 SpillBetween(current, current->Start(), pos->pos()); 1943 SpillBetween(current, current->Start(), pos->pos());
1922 DCHECK(UnhandledIsSorted()); 1944 DCHECK(UnhandledIsSorted());
1923 continue; 1945 continue;
1924 } 1946 }
1925 } 1947 }
1926 1948
1927 if (TryReuseSpillForPhi(current)) continue; 1949 bool cont = false;
1950 TRACE("Entering TryReuseSpillForPhi with range %d\n", current->id());
1951 if (TryReuseSpillForPhi(current)) cont = true;
1952 TRACE("Exiting TryReuseSpillForPhi with range %d\n", current->id());
1953 if (cont) continue;
1928 1954
1929 for (size_t i = 0; i < active_live_ranges().size(); ++i) { 1955 for (size_t i = 0; i < active_live_ranges().size(); ++i) {
1930 auto cur_active = active_live_ranges()[i]; 1956 auto cur_active = active_live_ranges()[i];
1931 if (cur_active->End() <= position) { 1957 if (cur_active->End() <= position) {
1932 ActiveToHandled(cur_active); 1958 ActiveToHandled(cur_active);
1933 --i; // The live range was removed from the list of active live ranges. 1959 --i; // The live range was removed from the list of active live ranges.
1934 } else if (!cur_active->Covers(position)) { 1960 } else if (!cur_active->Covers(position)) {
1935 ActiveToInactive(cur_active); 1961 ActiveToInactive(cur_active);
1936 --i; // The live range was removed from the list of active live ranges. 1962 --i; // The live range was removed from the list of active live ranges.
1937 } 1963 }
1938 } 1964 }
1939 1965
1940 for (size_t i = 0; i < inactive_live_ranges().size(); ++i) { 1966 for (size_t i = 0; i < inactive_live_ranges().size(); ++i) {
1941 auto cur_inactive = inactive_live_ranges()[i]; 1967 auto cur_inactive = inactive_live_ranges()[i];
1942 if (cur_inactive->End() <= position) { 1968 if (cur_inactive->End() <= position) {
1943 InactiveToHandled(cur_inactive); 1969 InactiveToHandled(cur_inactive);
1944 --i; // Live range was removed from the list of inactive live ranges. 1970 --i; // Live range was removed from the list of inactive live ranges.
1945 } else if (cur_inactive->Covers(position)) { 1971 } else if (cur_inactive->Covers(position)) {
1946 InactiveToActive(cur_inactive); 1972 InactiveToActive(cur_inactive);
1947 --i; // Live range was removed from the list of inactive live ranges. 1973 --i; // Live range was removed from the list of inactive live ranges.
1948 } 1974 }
1949 } 1975 }
1950 1976
1951 DCHECK(!current->HasRegisterAssigned() && !current->spilled()); 1977 DCHECK(!current->HasRegisterAssigned() && !current->spilled());
1952 1978
1953 bool result = TryAllocateFreeReg(current); 1979 bool result = TryAllocateFreeReg(current);
1980 TRACE("Failed to allocate free reg for %d\n", current->id());
1954 if (!result) AllocateBlockedReg(current); 1981 if (!result) AllocateBlockedReg(current);
1955 if (current->HasRegisterAssigned()) { 1982 if (current->HasRegisterAssigned()) {
1956 AddToActive(current); 1983 AddToActive(current);
1984 } else {
1985 TRACE("Failed to assign register to %d\n", current->id());
1957 } 1986 }
1958 } 1987 }
1988 TRACE("End allocating function %s with the Linear Allocator\n",
1989 data()->debug_name());
1990 if (FLAG_greedy_stats) {
1991 OFStream os(stdout);
1992 os << "==================================================" << std::endl;
1993 os << "allocation stats for: " << data()->debug_name() << "(" << mode()
1994 << ")" << std::endl;
1995 os << "input ranges: " << range_count << std::endl;
1996 os << "input fixed ranges: " << GetFixedRegisters(data(), mode()).size()
1997 << std::endl;
1998 os << stats_;
1999 os << "==================================================" << std::endl;
2000 }
1959 } 2001 }
1960 2002
1961 2003
1962 const char* LinearScanAllocator::RegisterName(int allocation_index) const { 2004 const char* RegisterAllocator::RegisterName(int allocation_index) const {
1963 if (mode() == GENERAL_REGISTERS) { 2005 if (mode() == GENERAL_REGISTERS) {
1964 return data()->config()->general_register_name(allocation_index); 2006 return data()->config()->general_register_name(allocation_index);
1965 } else { 2007 } else {
1966 return data()->config()->double_register_name(allocation_index); 2008 return data()->config()->double_register_name(allocation_index);
1967 } 2009 }
1968 } 2010 }
1969 2011
1970 2012
1971 void LinearScanAllocator::SetLiveRangeAssignedRegister(LiveRange* range, 2013 void LinearScanAllocator::SetLiveRangeAssignedRegister(LiveRange* range,
1972 int reg) { 2014 int reg) {
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
2120 auto pos = free_until_pos[reg]; 2162 auto pos = free_until_pos[reg];
2121 2163
2122 if (pos <= current->Start()) { 2164 if (pos <= current->Start()) {
2123 // All registers are blocked. 2165 // All registers are blocked.
2124 return false; 2166 return false;
2125 } 2167 }
2126 2168
2127 if (pos < current->End()) { 2169 if (pos < current->End()) {
2128 // Register reg is available at the range start but becomes blocked before 2170 // Register reg is available at the range start but becomes blocked before
2129 // the range end. Split current at position where it becomes blocked. 2171 // the range end. Split current at position where it becomes blocked.
2172 TRACE(
2173 "Register %d is available at the range start but becomes blocked "
2174 "before range %d end\n",
2175 reg, current->id());
2130 auto tail = SplitRangeAt(current, pos); 2176 auto tail = SplitRangeAt(current, pos);
2131 AddToUnhandledSorted(tail); 2177 AddToUnhandledSorted(tail);
2132 } 2178 }
2133 2179
2134 // Register reg is available at the range start and is free until 2180 // Register reg is available at the range start and is free until
2135 // the range end. 2181 // the range end.
2136 DCHECK(pos >= current->End()); 2182 DCHECK(pos >= current->End());
2137 TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg), 2183 TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg),
2138 current->id()); 2184 current->id());
2139 SetLiveRangeAssignedRegister(current, reg); 2185 SetLiveRangeAssignedRegister(current, reg);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
2192 if (use_pos[i] > use_pos[reg]) { 2238 if (use_pos[i] > use_pos[reg]) {
2193 reg = i; 2239 reg = i;
2194 } 2240 }
2195 } 2241 }
2196 2242
2197 auto pos = use_pos[reg]; 2243 auto pos = use_pos[reg];
2198 2244
2199 if (pos < register_use->pos()) { 2245 if (pos < register_use->pos()) {
2200 // All registers are blocked before the first use that requires a register. 2246 // All registers are blocked before the first use that requires a register.
2201 // Spill starting part of live range up to that use. 2247 // Spill starting part of live range up to that use.
2248 TRACE("All registers are blocked before the first use for %d\n",
2249 current->id());
2202 SpillBetween(current, current->Start(), register_use->pos()); 2250 SpillBetween(current, current->Start(), register_use->pos());
2203 return; 2251 return;
2204 } 2252 }
2205 2253
2206 if (block_pos[reg] < current->End()) { 2254 if (block_pos[reg] < current->End()) {
2207 // Register becomes blocked before the current range end. Split before that 2255 // Register becomes blocked before the current range end. Split before that
2208 // position. 2256 // position.
2257 TRACE("Register %d becomes blocked before end of range %d\n", reg,
2258 current->id());
2209 LiveRange* tail = 2259 LiveRange* tail =
2210 SplitBetween(current, current->Start(), block_pos[reg].Start()); 2260 SplitBetween(current, current->Start(), block_pos[reg].Start());
2211 AddToUnhandledSorted(tail); 2261 AddToUnhandledSorted(tail);
2212 } 2262 }
2213 2263
2214 // Register reg is not blocked for the whole range. 2264 // Register reg is not blocked for the whole range.
2215 DCHECK(block_pos[reg] >= current->End()); 2265 DCHECK(block_pos[reg] >= current->End());
2216 TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg), 2266 TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg),
2217 current->id()); 2267 current->id());
2218 SetLiveRangeAssignedRegister(current, reg); 2268 SetLiveRangeAssignedRegister(current, reg);
2219 2269
2220 // This register was not free. Thus we need to find and spill 2270 // This register was not free. Thus we need to find and spill
2221 // parts of active and inactive live regions that use the same register 2271 // parts of active and inactive live regions that use the same register
2222 // at the same lifetime positions as current. 2272 // at the same lifetime positions as current.
2223 SplitAndSpillIntersecting(current); 2273 SplitAndSpillIntersecting(current);
2224 } 2274 }
2225 2275
2226 2276
2227 void LinearScanAllocator::SplitAndSpillIntersecting(LiveRange* current) { 2277 void LinearScanAllocator::SplitAndSpillIntersecting(LiveRange* current) {
2228 DCHECK(current->HasRegisterAssigned()); 2278 DCHECK(current->HasRegisterAssigned());
2229 int reg = current->assigned_register(); 2279 int reg = current->assigned_register();
2230 auto split_pos = current->Start(); 2280 auto split_pos = current->Start();
2231 for (size_t i = 0; i < active_live_ranges().size(); ++i) { 2281 for (size_t i = 0; i < active_live_ranges().size(); ++i) {
2232 auto range = active_live_ranges()[i]; 2282 auto range = active_live_ranges()[i];
2233 if (range->assigned_register() == reg) { 2283 if (range->assigned_register() == reg) {
2234 auto next_pos = range->NextRegisterPosition(current->Start()); 2284 auto next_pos = range->NextRegisterPosition(current->Start());
2235 auto spill_pos = FindOptimalSpillingPos(range, split_pos); 2285 auto spill_pos = FindOptimalSpillingPos(range, split_pos);
2236 if (next_pos == nullptr) { 2286 if (next_pos == nullptr) {
2287 TRACE("SplitAndSpillIntersecting (1). Range %d, for %d\n", range->id(),
2288 current->id());
2237 SpillAfter(range, spill_pos); 2289 SpillAfter(range, spill_pos);
2238 } else { 2290 } else {
2239 // When spilling between spill_pos and next_pos ensure that the range 2291 // When spilling between spill_pos and next_pos ensure that the range
2240 // remains spilled at least until the start of the current live range. 2292 // remains spilled at least until the start of the current live range.
2241 // This guarantees that we will not introduce new unhandled ranges that 2293 // This guarantees that we will not introduce new unhandled ranges that
2242 // start before the current range as this violates allocation invariant 2294 // start before the current range as this violates allocation invariant
2243 // and will lead to an inconsistent state of active and inactive 2295 // and will lead to an inconsistent state of active and inactive
2244 // live-ranges: ranges are allocated in order of their start positions, 2296 // live-ranges: ranges are allocated in order of their start positions,
2245 // ranges are retired from active/inactive when the start of the 2297 // ranges are retired from active/inactive when the start of the
2246 // current live-range is larger than their end. 2298 // current live-range is larger than their end.
2299 TRACE("SplitAndSpillIntersecting (2). Range %d, for %d\n", range->id(),
2300 current->id());
2247 SpillBetweenUntil(range, spill_pos, current->Start(), next_pos->pos()); 2301 SpillBetweenUntil(range, spill_pos, current->Start(), next_pos->pos());
2248 } 2302 }
2249 ActiveToHandled(range); 2303 ActiveToHandled(range);
2250 --i; 2304 --i;
2251 } 2305 }
2252 } 2306 }
2253 2307
2254 for (size_t i = 0; i < inactive_live_ranges().size(); ++i) { 2308 for (size_t i = 0; i < inactive_live_ranges().size(); ++i) {
2255 auto range = inactive_live_ranges()[i]; 2309 auto range = inactive_live_ranges()[i];
2256 DCHECK(range->End() > current->Start()); 2310 DCHECK(range->End() > current->Start());
2257 if (range->assigned_register() == reg && !range->IsFixed()) { 2311 if (range->assigned_register() == reg && !range->IsFixed()) {
2258 LifetimePosition next_intersection = range->FirstIntersection(current); 2312 LifetimePosition next_intersection = range->FirstIntersection(current);
2259 if (next_intersection.IsValid()) { 2313 if (next_intersection.IsValid()) {
2260 UsePosition* next_pos = range->NextRegisterPosition(current->Start()); 2314 UsePosition* next_pos = range->NextRegisterPosition(current->Start());
2261 if (next_pos == nullptr) { 2315 if (next_pos == nullptr) {
2316 TRACE("SplitAndSpillIntersecting (3). Range %d, for %d\n",
2317 range->id(), current->id());
2262 SpillAfter(range, split_pos); 2318 SpillAfter(range, split_pos);
2263 } else { 2319 } else {
2264 next_intersection = Min(next_intersection, next_pos->pos()); 2320 next_intersection = Min(next_intersection, next_pos->pos());
2321 TRACE("SplitAndSpillIntersecting (4). Range %d, for %d\n",
2322 range->id(), current->id());
2265 SpillBetween(range, split_pos, next_intersection); 2323 SpillBetween(range, split_pos, next_intersection);
2266 } 2324 }
2267 InactiveToHandled(range); 2325 InactiveToHandled(range);
2268 --i; 2326 --i;
2269 } 2327 }
2270 } 2328 }
2271 } 2329 }
2272 } 2330 }
2273 2331
2274 2332
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
2463 2521
2464 bool Remove(UseInterval* key) { return storage_.Remove(GetKey(key)); } 2522 bool Remove(UseInterval* key) { return storage_.Remove(GetKey(key)); }
2465 2523
2466 ZoneSplayTree<Config> storage_; 2524 ZoneSplayTree<Config> storage_;
2467 DISALLOW_COPY_AND_ASSIGN(CoalescedLiveRanges); 2525 DISALLOW_COPY_AND_ASSIGN(CoalescedLiveRanges);
2468 }; 2526 };
2469 2527
2470 2528
2471 const std::pair<int, int> CoalescedLiveRanges::Config::kNoKey = {0, 0}; 2529 const std::pair<int, int> CoalescedLiveRanges::Config::kNoKey = {0, 0};
2472 2530
2531
2532 std::ostream& operator<<(std::ostream& os, const AllocatorStats& stats) {
2533 os << "losses after eviction: " << stats.losses_after_eviction << std::endl;
2534 os << "losses, no eviction: " << stats.losses_no_eviction << std::endl;
2535 os << "spills: " << stats.spills << std::endl;
2536 os << "wins: " << stats.wins << std::endl;
2537 os << "split attempts: " << stats.good_split_attempts << std::endl;
2538 os << "split successes: " << stats.good_split_successes << std::endl;
2539 os << "splits above: " << stats.good_split_above << std::endl;
2540 os << "splits below: " << stats.good_split_below << std::endl;
2541 os << "smart splits above: " << stats.good_split_smart_above << std::endl;
2542 os << "smart splits below: " << stats.good_split_smart_below << std::endl;
2543 return os;
2544 }
2545
2546
2473 GreedyAllocator::GreedyAllocator(RegisterAllocationData* data, 2547 GreedyAllocator::GreedyAllocator(RegisterAllocationData* data,
2474 RegisterKind kind, Zone* local_zone) 2548 RegisterKind kind, Zone* local_zone)
2475 : RegisterAllocator(data, kind), 2549 : RegisterAllocator(data, kind),
2476 local_zone_(local_zone), 2550 local_zone_(local_zone),
2477 allocations_(local_zone), 2551 allocations_(local_zone),
2478 queue_(local_zone) {} 2552 queue_(local_zone) {}
2479 2553
2480 2554
2481 unsigned GreedyAllocator::GetLiveRangeSize(LiveRange* range) { 2555 unsigned GreedyAllocator::GetLiveRangeSize(LiveRange* range,
2482 auto interval = range->first_interval(); 2556 LifetimePosition start,
2483 if (interval == nullptr) return 0; 2557 LifetimePosition end) {
2484 2558 return (end.value() - start.value());
2485 unsigned size = 0;
2486 while (interval != nullptr) {
2487 size += (interval->end().value() - interval->start().value());
2488 interval = interval->next();
2489 }
2490
2491 return size;
2492 } 2559 }
2493 2560
2494 2561
2562 unsigned GreedyAllocator::GetLiveRangeSize(LiveRange* range) {
2563 return GetLiveRangeSize(range, range->Start(), range->End());
2564 }
2565
2566
2495 void GreedyAllocator::AssignRangeToRegister(int reg_id, LiveRange* range) { 2567 void GreedyAllocator::AssignRangeToRegister(int reg_id, LiveRange* range) {
2496 allocations_[reg_id]->Insert(range); 2568 allocations_[reg_id]->Insert(range);
2497 if (range->HasRegisterAssigned()) { 2569 if (range->HasRegisterAssigned()) {
2498 DCHECK_EQ(reg_id, range->assigned_register()); 2570 DCHECK_EQ(reg_id, range->assigned_register());
2499 return; 2571 return;
2500 } 2572 }
2573 TRACE("Assigning %s to range %d\n", RegisterName(reg_id), range->id());
2501 range->set_assigned_register(reg_id); 2574 range->set_assigned_register(reg_id);
2502 range->SetUseHints(reg_id); 2575 range->SetUseHints(reg_id);
2503 if (range->is_phi()) { 2576 if (range->is_phi()) {
2504 data()->GetPhiMapValueFor(range->id())->set_assigned_register(reg_id); 2577 data()->GetPhiMapValueFor(range->id())->set_assigned_register(reg_id);
2505 } 2578 }
2506 } 2579 }
2507 2580
2508 2581
2509 float GreedyAllocator::CalculateSpillWeight(LiveRange* range) { 2582 float GreedyAllocator::CalculateSpillWeight(LiveRange* range) {
2510 InstructionOperand* first_hint = nullptr; 2583 return CalculateSpillWeight(range, range->Start(), range->End());
2511 if (range->FirstHintPosition() != nullptr) { 2584 }
2512 first_hint = range->FirstHintPosition()->operand();
2513 }
2514 2585
2586
2587 // Local definition of integer power, to avoid casting std::pow.
2588 unsigned ipow(unsigned b, unsigned e) {
2589 if (e == 0) return 1;
2590 if (e == 1) return b;
2591 auto odd = e & 1;
2592 auto rem = e >> 1;
2593 auto half = ipow(b, rem);
Jarin 2015/05/13 13:12:57 If you wrote this function for efficiency, then yo
2594 auto ret = half * half;
2595 if (odd) ret *= b;
2596 return ret;
2597 }
2598
2599
2600 float GreedyAllocator::CalculateSpillWeight(LiveRange* range,
2601 LifetimePosition start,
2602 LifetimePosition end) {
2515 if (range->IsFixed()) return std::numeric_limits<float>::max(); 2603 if (range->IsFixed()) return std::numeric_limits<float>::max();
2516 bool spill; 2604
2517 if (!FindProgressingSplitPosition(range, &spill).IsValid()) 2605 if (!RangeHasSplitOrSpillPosition(range, start, end))
2518 return std::numeric_limits<float>::max(); 2606 return std::numeric_limits<float>::max();
2519 2607
2520 float multiplier = 1.0;
2521 if (first_hint != nullptr && first_hint->IsRegister()) {
2522 multiplier = 3.0;
2523 }
2524 2608
2525 unsigned use_count = 0; 2609 unsigned use_count = 0;
2526 auto* pos = range->first_pos(); 2610 auto* pos = range->first_pos();
2527 while (pos != nullptr) { 2611 const InstructionBlock* last_block = nullptr;
2528 use_count++; 2612
2529 pos = pos->next(); 2613 unsigned last_loop_count = 0;
2614 unsigned last_use_count = 0;
2615 for (; pos != nullptr; pos = pos->next()) {
2616 if (pos->pos() < start) continue;
2617 if (pos->pos() > end) break;
2618
2619 auto block = GetInstructionBlock(code(), pos->pos());
2620 if (block != last_block) {
2621 last_block = block;
2622 use_count += last_use_count * ipow(2, last_loop_count);
Jarin 2015/05/13 13:12:56 ipow(2, x) --> 1 << x?
2623 last_loop_count = GetContainingLoopCount(code(), block);
2624 last_use_count = 0;
2625 }
2626 if (pos->RegisterIsBeneficial()) last_use_count++;
2530 } 2627 }
2628 use_count += last_use_count * ipow(2, last_loop_count);
Jarin 2015/05/13 13:12:56 ipow(2, x) --> 1 << x?
2531 2629
2532 unsigned range_size = GetLiveRangeSize(range); 2630 unsigned range_size = GetLiveRangeSize(range, start, end);
2533 DCHECK_NE(0U, range_size); 2631 DCHECK_NE(0U, range_size);
2534 2632
2535 return multiplier * static_cast<float>(use_count) / 2633 return static_cast<float>(use_count) / static_cast<float>(range_size);
2536 static_cast<float>(range_size);
2537 }
2538
2539
2540 float GreedyAllocator::CalculateMaxSpillWeight(
2541 const ZoneSet<LiveRange*>& ranges) {
2542 float max = 0.0;
2543 for (auto* r : ranges) {
2544 max = std::max(max, CalculateSpillWeight(r));
2545 }
2546 return max;
2547 } 2634 }
2548 2635
2549 2636
2550 void GreedyAllocator::Evict(LiveRange* range) { 2637 void GreedyAllocator::Evict(LiveRange* range) {
2638 TRACE("Evicting range %d\n", range->id());
2551 bool removed = allocations_[range->assigned_register()]->Remove(range); 2639 bool removed = allocations_[range->assigned_register()]->Remove(range);
2552 CHECK(removed); 2640 CHECK(removed);
2553 range->UnsetUseHints(); 2641 range->UnsetUseHints();
2554 range->UnsetAssignedRegister(); 2642 range->UnsetAssignedRegister();
2555 if (range->is_phi()) { 2643 if (range->is_phi()) {
2556 data()->GetPhiMapValueFor(range->id())->UnsetAssignedRegister(); 2644 data()->GetPhiMapValueFor(range->id())->UnsetAssignedRegister();
2557 } 2645 }
2558 } 2646 }
2559 2647
2560 2648
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
2644 // The split result does not intersect with [start, end[. 2732 // The split result does not intersect with [start, end[.
2645 // Nothing to spill. Just return it for re-processing. 2733 // Nothing to spill. Just return it for re-processing.
2646 return second_part; 2734 return second_part;
2647 } 2735 }
2648 } 2736 }
2649 2737
2650 2738
2651 void GreedyAllocator::Enqueue(LiveRange* range) { 2739 void GreedyAllocator::Enqueue(LiveRange* range) {
2652 if (range == nullptr || range->IsEmpty()) return; 2740 if (range == nullptr || range->IsEmpty()) return;
2653 unsigned size = GetLiveRangeSize(range); 2741 unsigned size = GetLiveRangeSize(range);
2654 TRACE("Enqueuing range %d\n", range->id()); 2742 TRACE("Enqueuing range %d size %d\n", range->id(), size);
2655 queue_.push(std::make_pair(size, range)); 2743 queue_.push(std::make_pair(size, range));
2656 } 2744 }
2657 2745
2658 2746
2659 bool GreedyAllocator::HandleSpillOperands(LiveRange* range) { 2747 bool GreedyAllocator::HandleSpillOperands(LiveRange* range) {
2660 auto position = range->Start(); 2748 auto position = range->Start();
2661 TRACE("Processing interval %d start=%d\n", range->id(), position.value()); 2749 TRACE("Processing interval %d start=%d\n", range->id(), position.value());
2662 2750
2663 if (!range->HasNoSpillType()) { 2751 if (!range->HasNoSpillType()) {
2664 TRACE("Live range %d already has a spill operand\n", range->id()); 2752 TRACE("Live range %d already has a spill operand\n", range->id());
2665 auto next_pos = position; 2753 auto next_pos = position;
2666 if (next_pos.IsGapPosition()) { 2754 if (next_pos.IsGapPosition()) {
2667 next_pos = next_pos.NextStart(); 2755 next_pos = next_pos.NextStart();
2668 } 2756 }
2669 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); 2757 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos);
2670 // If the range already has a spill operand and it doesn't need a 2758 // If the range already has a spill operand and it doesn't need a
2671 // register immediately, split it and spill the first part of the range. 2759 // register immediately, split it and spill the first part of the range.
2672 if (pos == nullptr) { 2760 if (pos == nullptr) {
2673 Spill(range); 2761 Spill(range);
2674 return true; 2762 return true;
2675 } else if (pos->pos() > range->Start().NextStart()) { 2763 } else if (pos->pos() > range->Start().NextStart()) {
2676 // Do not spill live range eagerly if use position that can benefit from 2764 // Do not spill live range eagerly if use position that can benefit from
2677 // the register is too close to the start of live range. 2765 // the register is too close to the start of live range.
2678 auto* reminder = SpillBetweenUntil(range, position, position, pos->pos()); 2766 auto* reminder = SpillBetweenUntil(range, position, position, pos->pos());
2679 Enqueue(reminder); 2767 Enqueue(reminder);
2680 return true; 2768 return true;
2681 } 2769 }
2682 } 2770 }
2683 return TryReuseSpillForPhi(range); 2771 TRACE("Entering TryReuseSpillForPhi with range %d\n", range->id());
2772 bool ret = TryReuseSpillForPhi(range);
2773 TRACE("Exiting TryReuseSpillForPhi with range %d\n", range->id());
2774 return ret;
2684 } 2775 }
2685 2776
2686 2777
2687 void GreedyAllocator::AllocateRegisters() { 2778 void GreedyAllocator::AllocateRegisters() {
2779 stats_.reset();
2780 unsigned range_count = 0;
2781 TRACE("Begin allocating function %s with the Greedy Allocator\n",
2782 data()->debug_name());
2688 for (auto range : data()->live_ranges()) { 2783 for (auto range : data()->live_ranges()) {
2689 if (range == nullptr) continue; 2784 if (range == nullptr) continue;
2690 if (range->kind() == mode()) { 2785 if (range->kind() == mode()) {
2691 DCHECK(!range->HasRegisterAssigned() && !range->spilled()); 2786 DCHECK(!range->HasRegisterAssigned() && !range->spilled());
2692 TRACE("Enqueueing live range %d to priority queue \n", range->id()); 2787 TRACE("Enqueueing live range %d to priority queue \n", range->id());
2693 Enqueue(range); 2788 Enqueue(range);
2789 range_count++;
2694 } 2790 }
2695 } 2791 }
2696 2792
2697 allocations_.resize(num_registers()); 2793 allocations_.resize(num_registers());
2698 for (int i = 0; i < num_registers(); i++) { 2794 for (int i = 0; i < num_registers(); i++) {
2699 allocations_[i] = new (local_zone()) CoalescedLiveRanges(local_zone()); 2795 allocations_[i] = new (local_zone()) CoalescedLiveRanges(local_zone());
2700 } 2796 }
2701 2797
2702 for (auto* current : GetFixedRegisters(data(), mode())) { 2798 for (auto* current : GetFixedRegisters(data(), mode())) {
2703 if (current != nullptr) { 2799 if (current != nullptr) {
2704 DCHECK_EQ(mode(), current->kind()); 2800 DCHECK_EQ(mode(), current->kind());
2705 int reg_nr = current->assigned_register(); 2801 int reg_nr = current->assigned_register();
2706 bool inserted = allocations_[reg_nr]->Insert(current); 2802 bool inserted = allocations_[reg_nr]->Insert(current);
2707 CHECK(inserted); 2803 CHECK(inserted);
2708 } 2804 }
2709 } 2805 }
2710 2806
2711 while (!queue_.empty()) { 2807 while (!queue_.empty()) {
2712 auto current_pair = queue_.top(); 2808 auto current_pair = queue_.top();
2713 queue_.pop(); 2809 queue_.pop();
2714 auto current = current_pair.second; 2810 auto current = current_pair.second;
2811 TRACE("Processing interval %d of size %d\n", current->id(),
2812 current_pair.first);
2715 if (HandleSpillOperands(current)) { 2813 if (HandleSpillOperands(current)) {
2716 continue; 2814 continue;
2717 } 2815 }
2718 bool spill = false; 2816
2719 ZoneSet<LiveRange*> conflicting(local_zone()); 2817 ZoneSet<LiveRange*> conflicting(local_zone());
2720 if (!TryAllocate(current, &conflicting)) { 2818 if (!TryAllocate(current, &conflicting)) {
2721 DCHECK(!conflicting.empty()); 2819 DCHECK(!conflicting.empty());
2722 float this_weight = std::numeric_limits<float>::max(); 2820 float this_weight = CalculateSpillWeight(current);
2723 LifetimePosition split_pos =
2724 FindProgressingSplitPosition(current, &spill);
2725 if (split_pos.IsValid()) {
2726 this_weight = CalculateSpillWeight(current);
2727 }
2728 2821
2729 bool evicted = false; 2822 bool evicted = false;
2730 for (auto* conflict : conflicting) { 2823 for (auto* conflict : conflicting) {
2731 if (CalculateSpillWeight(conflict) < this_weight) { 2824 float conflict_weight = CalculateSpillWeight(conflict);
2825 if (conflict_weight < this_weight) {
2732 Evict(conflict); 2826 Evict(conflict);
2733 Enqueue(conflict); 2827 Enqueue(conflict);
2734 evicted = true; 2828 evicted = true;
2735 } 2829 }
2736 } 2830 }
2737 if (evicted) { 2831 if (evicted) {
2738 conflicting.clear(); 2832 conflicting.clear();
2739 TryAllocate(current, &conflicting); 2833 TryAllocate(current, &conflicting);
2834 if (conflicting.size() == 0) {
2835 stats_.wins++;
2836 } else {
2837 stats_.losses_after_eviction++;
2838 }
2839 } else {
2840 stats_.losses_no_eviction++;
2740 } 2841 }
2741 if (!conflicting.empty()) { 2842 if (conflicting.size() > 0) {
2843 TRACE("Could evict for range %d\n", current->id());
2742 DCHECK(!current->IsFixed() || current->CanBeSpilled(current->Start())); 2844 DCHECK(!current->IsFixed() || current->CanBeSpilled(current->Start()));
2743 DCHECK(split_pos.IsValid()); 2845 // DCHECK(split_pos.IsValid());
Jarin 2015/05/13 13:12:57 Remove.
2744 AllocateBlockedRange(current, split_pos, spill); 2846 AllocateBlockedRange(current, conflicting);
2745 } 2847 }
2746 } 2848 }
2747 } 2849 }
2748 2850
2749 for (size_t i = 0; i < allocations_.size(); ++i) { 2851 for (size_t i = 0; i < allocations_.size(); ++i) {
2750 if (!allocations_[i]->IsEmpty()) { 2852 if (!allocations_[i]->IsEmpty()) {
2751 data()->MarkAllocated(mode(), static_cast<int>(i)); 2853 data()->MarkAllocated(mode(), static_cast<int>(i));
2752 } 2854 }
2753 } 2855 }
2754 } 2856 TRACE("End allocating function %s with the Greedy Allocator\n",
2755 2857 data()->debug_name());
2756 2858 if (FLAG_greedy_stats) {
2757 LifetimePosition GreedyAllocator::GetSplittablePos(LifetimePosition pos) { 2859 OFStream os(stdout);
2758 auto ret = pos.PrevStart().End(); 2860 os << "==================================================" << std::endl;
2861 os << "allocation stats for: " << data()->debug_name() << "(" << mode()
2862 << ")" << std::endl;
2863 os << "input ranges: " << range_count << std::endl;
2864 os << "input fixed ranges: " << GetFixedRegisters(data(), mode()).size()
2865 << std::endl;
2866 os << stats_;
2867 os << "==================================================" << std::endl;
2868 }
2869 }
2870
2871
2872 LifetimePosition GreedyAllocator::GetCorrectSplitPos(LifetimePosition pos) {
2873 LifetimePosition ret;
2759 if (IsBlockBoundary(code(), pos.Start())) { 2874 if (IsBlockBoundary(code(), pos.Start())) {
2760 ret = pos.Start(); 2875 ret = pos.Start();
2876 } else {
2877 ret = pos.PrevStart().End();
2761 } 2878 }
2762 DCHECK(ret <= pos); 2879 DCHECK(ret <= pos);
2763 return ret; 2880 return ret;
2764 } 2881 }
2765 2882
2766 LifetimePosition GreedyAllocator::FindProgressingSplitPosition( 2883 LifetimePosition GreedyAllocator::GetSplittablePos(UsePosition* use_pos,
2767 LiveRange* range, bool* is_spill_pos) { 2884 LiveRange* range) {
2885 DCHECK(use_pos != nullptr);
2768 auto start = range->Start(); 2886 auto start = range->Start();
2769 auto end = range->End(); 2887 auto end = range->End();
2770 2888
2889 auto pos = GetCorrectSplitPos(use_pos->pos());
2890 if (start < pos && pos < end) {
2891 return pos;
2892 }
2893
2894 if (pos >= end) {
2895 return LifetimePosition::Invalid();
Jarin 2015/05/13 13:12:56 How can this happen?
2896 }
2897
2898 auto after = pos.NextFullStart();
2899 if (start < after && after < end) {
2900 return after;
2901 }
2902 if (use_pos->next() != nullptr) {
2903 return GetSplittablePos(use_pos->next(), range);
2904 }
2905 return LifetimePosition::Invalid();
2906 }
2907
2908 bool GreedyAllocator::RangeHasSplitOrSpillPosition(LiveRange* range,
2909 LifetimePosition start,
2910 LifetimePosition end) {
2771 UsePosition* next_reg_use = range->first_pos(); 2911 UsePosition* next_reg_use = range->first_pos();
2912 for (; next_reg_use != nullptr; next_reg_use = next_reg_use->next()) {
2913 if (next_reg_use->pos() > end) break;
2914 if (next_reg_use->pos() < start) continue;
2915 if (next_reg_use->type() == UsePositionType::kRequiresRegister) break;
2916 }
2917
2918 if (next_reg_use == nullptr || next_reg_use->pos() > end) {
2919 auto ret = FindOptimalSpillingPos(range, start);
2920 CHECK(ret.IsValid());
2921 return true;
2922 }
2923 auto pos = GetCorrectSplitPos(next_reg_use->pos());
2924 if (start < pos && pos < end) return true;
2925 while (next_reg_use->next() != nullptr &&
2926 next_reg_use->pos().NextFullStart() > next_reg_use->next()->pos()) {
2927 next_reg_use = next_reg_use->next();
2928 }
2929 CHECK(next_reg_use != nullptr);
2930 pos = next_reg_use->pos().NextFullStart();
2931 if (start < pos && pos < end) return true;
Jarin 2015/05/13 13:12:56 return start < pos && pos < end;
2932 return false;
2933 }
2934
2935 bool GreedyAllocator::FindGoodSplitPoint(LiveRange* range,
2936 const ZoneSet<LiveRange*>& conflicts) {
2937 auto start = range->Start();
2938 auto end = range->End();
2939 end = end.IsInstructionPosition() ? end.End() : end.PrevStart().End();
2940 auto pos = LifetimePosition::Invalid();
2941 float heaviest = 0.0;
2942 stats_.good_split_attempts++;
2943
2944 bool winner_is_smart = false;
2945 bool winner_is_above = false;
2946 for (auto conflict : conflicts) {
2947 bool upper_is_freed = false;
2948 bool using_smart = false;
2949 auto first_intersection = range->FirstIntersection(conflict);
2950 DCHECK(first_intersection.IsValid());
2951 DCHECK(conflict->HasRegisterAssigned());
2952 if (first_intersection == start && FLAG_greedy_below) {
2953 first_intersection = conflict->End();
2954 } else {
2955 upper_is_freed = true;
2956 }
2957 auto corrected_pos = GetCorrectSplitPos(first_intersection);
2958 if (start >= corrected_pos || corrected_pos >= end) continue;
2959 auto candidate_pos =
2960 FLAG_greedy_smart
2961 ? (upper_is_freed ? FindOptimalSplitPos(start, corrected_pos)
2962 : FindOptimalSplitPos(corrected_pos, end))
2963 : corrected_pos;
2964
2965 if (start >= candidate_pos || candidate_pos >= end) {
2966 if (FLAG_greedy_alternative && start < corrected_pos &&
2967 corrected_pos < end) {
2968 candidate_pos = corrected_pos;
2969 } else {
2970 continue;
2971 }
2972 }
2973 using_smart = (candidate_pos != corrected_pos);
2974
2975 float this_weight = 0.0;
2976 if (upper_is_freed) {
2977 this_weight = CalculateSpillWeight(range, start, candidate_pos);
2978 } else {
2979 this_weight = CalculateSpillWeight(range, candidate_pos, end);
2980 }
2981
2982 if (FLAG_greedy_split_longest) {
2983 pos = Max(pos, candidate_pos);
2984 } else if (this_weight > heaviest) {
2985 pos = candidate_pos;
2986 heaviest = this_weight;
2987 winner_is_smart = using_smart;
2988 winner_is_above = upper_is_freed;
2989 }
2990 }
2991
2992 if (!pos.IsValid()) {
2993 // All registers are blocked.
2994 TRACE("All registers are blocked for range %d\n", range->id());
2995 return false;
2996 }
2997 CHECK(FLAG_greedy_split_longest || heaviest > 0.0);
2998
2999 // Register reg is available at the range start but becomes blocked before
3000 // the range end. Split current at position where it becomes blocked.
3001 TRACE("Splitting range %d at position %d where the length is %f", range->id(),
3002 pos.value(), heaviest);
3003
3004 LiveRange* tail = SplitRangeAt(range, pos);
3005 CHECK(tail != range);
3006 Enqueue(tail);
3007 Enqueue(range);
3008 if (winner_is_smart) {
3009 if (winner_is_above) {
3010 stats_.good_split_smart_above++;
3011 } else {
3012 stats_.good_split_smart_below++;
3013 }
3014 } else {
3015 if (winner_is_above) {
3016 stats_.good_split_above++;
3017 } else {
3018 stats_.good_split_below++;
3019 }
3020 }
3021 stats_.good_split_successes++;
3022 return true;
3023 }
3024
3025 void GreedyAllocator::AllocateBlockedRange(
3026 LiveRange* current, const ZoneSet<LiveRange*>& conflicts) {
3027 auto start = current->Start();
3028 auto end = current->End();
3029
3030 UsePosition* next_reg_use = current->first_pos();
2772 while (next_reg_use != nullptr && 3031 while (next_reg_use != nullptr &&
2773 next_reg_use->type() != UsePositionType::kRequiresRegister) { 3032 next_reg_use->type() != UsePositionType::kRequiresRegister) {
2774 next_reg_use = next_reg_use->next(); 3033 next_reg_use = next_reg_use->next();
2775 } 3034 }
2776 3035
2777 if (next_reg_use == nullptr) { 3036 if (next_reg_use == nullptr) {
2778 *is_spill_pos = true; 3037 auto pos = FindOptimalSpillingPos(current, start);
2779 auto ret = FindOptimalSpillingPos(range, start); 3038 DCHECK(pos.IsValid());
2780 DCHECK(ret.IsValid()); 3039 auto tail = SplitRangeAt(current, pos);
2781 return ret;
2782 }
2783
2784 *is_spill_pos = false;
2785 auto reg_pos = next_reg_use->pos();
2786 auto correct_pos = GetSplittablePos(reg_pos);
2787 if (start < correct_pos && correct_pos < end) {
2788 return correct_pos;
2789 }
2790
2791 if (correct_pos >= end) {
2792 return LifetimePosition::Invalid();
2793 }
2794
2795 // Correct_pos must be at or before start. Find the next use position.
2796 next_reg_use = next_reg_use->next();
2797 auto reference = reg_pos;
2798 while (next_reg_use != nullptr) {
2799 auto pos = next_reg_use->pos();
2800 // Skip over tight successive uses.
2801 if (reference.NextStart() < pos) {
2802 break;
2803 }
2804 reference = pos;
2805 next_reg_use = next_reg_use->next();
2806 }
2807
2808 if (next_reg_use == nullptr) {
2809 // While there may not be another use, we may still have space in the range
2810 // to clip off.
2811 correct_pos = reference.NextStart();
2812 if (start < correct_pos && correct_pos < end) {
2813 return correct_pos;
2814 }
2815 return LifetimePosition::Invalid();
2816 }
2817
2818 correct_pos = GetSplittablePos(next_reg_use->pos());
2819 if (start < correct_pos && correct_pos < end) {
2820 DCHECK(reference < correct_pos);
2821 return correct_pos;
2822 }
2823 return LifetimePosition::Invalid();
2824 }
2825
2826
2827 void GreedyAllocator::AllocateBlockedRange(LiveRange* current,
2828 LifetimePosition pos, bool spill) {
2829 auto tail = SplitRangeAt(current, pos);
2830 if (spill) {
2831 Spill(tail); 3040 Spill(tail);
2832 } else { 3041 if (tail != current) {
2833 Enqueue(tail); 3042 Enqueue(current);
2834 } 3043 }
2835 if (tail != current) { 3044 return;
2836 Enqueue(current); 3045 }
2837 } 3046
2838 } 3047 if (FindGoodSplitPoint(current, conflicts)) return;
2839 3048 auto alternate = GetCorrectSplitPos(next_reg_use->pos());
2840 3049 if (start >= alternate || alternate >= end) {
3050 auto reg_use_backup = next_reg_use;
3051 for (; next_reg_use != nullptr; next_reg_use = next_reg_use->next()) {
3052 if (next_reg_use->type() == UsePositionType::kRequiresRegister) {
3053 alternate = next_reg_use->pos();
3054 }
3055 }
3056 alternate = alternate.NextStart();
3057 if (start >= alternate || alternate >= end) {
3058 alternate = GetSplittablePos(reg_use_backup, current);
3059 CHECK(alternate.IsValid());
3060 }
3061 }
3062 auto tail = SplitRangeAt(current, alternate);
3063 Enqueue(tail);
3064 Enqueue(current);
3065 }
3066
3067
2841 SpillSlotLocator::SpillSlotLocator(RegisterAllocationData* data) 3068 SpillSlotLocator::SpillSlotLocator(RegisterAllocationData* data)
2842 : data_(data) {} 3069 : data_(data) {}
2843 3070
2844 3071
2845 void SpillSlotLocator::LocateSpillSlots() { 3072 void SpillSlotLocator::LocateSpillSlots() {
2846 auto code = data()->code(); 3073 auto code = data()->code();
2847 for (auto range : data()->live_ranges()) { 3074 for (auto range : data()->live_ranges()) {
2848 if (range == nullptr || range->IsEmpty() || range->IsChild()) continue; 3075 if (range == nullptr || range->IsEmpty() || range->IsChild()) continue;
2849 // We care only about ranges which spill in the frame. 3076 // We care only about ranges which spill in the frame.
2850 if (!range->HasSpillRange()) continue; 3077 if (!range->HasSpillRange()) continue;
2851 auto spills = range->spills_at_definition(); 3078 auto spills = range->spills_at_definition();
2852 DCHECK_NOT_NULL(spills); 3079 DCHECK_NOT_NULL(spills);
2853 for (; spills != nullptr; spills = spills->next) { 3080 for (; spills != nullptr; spills = spills->next) {
2854 code->GetInstructionBlock(spills->gap_index)->mark_needs_frame(); 3081 code->GetInstructionBlock(spills->gap_index)->mark_needs_frame();
2855 } 3082 }
2856 } 3083 }
2857 } 3084 }
2858 3085
2859 3086
2860 bool GreedyAllocator::TryReuseSpillForPhi(LiveRange* range) { 3087 bool GreedyAllocator::TryReuseSpillForPhi(LiveRange* range) {
2861 if (range->IsChild() || !range->is_phi()) return false; 3088 if (range->IsChild() || !range->is_phi()) return false;
2862 DCHECK(!range->HasSpillOperand()); 3089 DCHECK(!range->HasSpillOperand());
2863
2864 auto phi_map_value = data()->GetPhiMapValueFor(range->id()); 3090 auto phi_map_value = data()->GetPhiMapValueFor(range->id());
2865 auto phi = phi_map_value->phi(); 3091 auto phi = phi_map_value->phi();
2866 auto block = phi_map_value->block(); 3092 auto block = phi_map_value->block();
2867 // Count the number of spilled operands. 3093 // Count the number of spilled operands.
2868 size_t spilled_count = 0; 3094 size_t spilled_count = 0;
2869 LiveRange* first_op = nullptr; 3095 LiveRange* first_op = nullptr;
2870 for (size_t i = 0; i < phi->operands().size(); i++) { 3096 for (size_t i = 0; i < phi->operands().size(); i++) {
2871 int op = phi->operands()[i]; 3097 int op = phi->operands()[i];
2872 LiveRange* op_range = LiveRangeFor(op); 3098 LiveRange* op_range = LiveRangeFor(op);
2873 if (!op_range->HasSpillRange()) continue; 3099 if (!op_range->HasSpillRange()) continue;
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after
3313 ->HasReferenceMap()); 3539 ->HasReferenceMap());
3314 gap_index = pred->last_instruction_index(); 3540 gap_index = pred->last_instruction_index();
3315 position = Instruction::END; 3541 position = Instruction::END;
3316 } 3542 }
3317 data()->AddGapMove(gap_index, position, pred_op, cur_op); 3543 data()->AddGapMove(gap_index, position, pred_op, cur_op);
3318 } 3544 }
3319 3545
3320 3546
3321 void LiveRangeConnector::ConnectRanges(Zone* local_zone) { 3547 void LiveRangeConnector::ConnectRanges(Zone* local_zone) {
3322 DelayedInsertionMap delayed_insertion_map(local_zone); 3548 DelayedInsertionMap delayed_insertion_map(local_zone);
3549 unsigned moves_counter = 0;
3323 for (auto first_range : data()->live_ranges()) { 3550 for (auto first_range : data()->live_ranges()) {
3324 if (first_range == nullptr || first_range->IsChild()) continue; 3551 if (first_range == nullptr || first_range->IsChild()) continue;
3325 for (auto second_range = first_range->next(); second_range != nullptr; 3552 for (auto second_range = first_range->next(); second_range != nullptr;
3326 first_range = second_range, second_range = second_range->next()) { 3553 first_range = second_range, second_range = second_range->next()) {
3327 auto pos = second_range->Start(); 3554 auto pos = second_range->Start();
3328 // Add gap move if the two live ranges touch and there is no block 3555 // Add gap move if the two live ranges touch and there is no block
3329 // boundary. 3556 // boundary.
3330 if (second_range->spilled()) continue; 3557 if (second_range->spilled()) continue;
3331 if (first_range->End() != pos) continue; 3558 if (first_range->End() != pos) continue;
3332 if (IsBlockBoundary(code(), pos) && 3559 if (IsBlockBoundary(code(), pos) &&
(...skipping 11 matching lines...) Expand all
3344 } else { 3571 } else {
3345 if (pos.IsStart()) { 3572 if (pos.IsStart()) {
3346 delay_insertion = true; 3573 delay_insertion = true;
3347 } else { 3574 } else {
3348 gap_index++; 3575 gap_index++;
3349 } 3576 }
3350 gap_pos = delay_insertion ? Instruction::END : Instruction::START; 3577 gap_pos = delay_insertion ? Instruction::END : Instruction::START;
3351 } 3578 }
3352 auto move = code()->InstructionAt(gap_index)->GetOrCreateParallelMove( 3579 auto move = code()->InstructionAt(gap_index)->GetOrCreateParallelMove(
3353 gap_pos, code_zone()); 3580 gap_pos, code_zone());
3581 moves_counter++;
3354 if (!delay_insertion) { 3582 if (!delay_insertion) {
3355 move->AddMove(prev_operand, cur_operand); 3583 move->AddMove(prev_operand, cur_operand);
3356 } else { 3584 } else {
3357 delayed_insertion_map.insert( 3585 delayed_insertion_map.insert(
3358 std::make_pair(std::make_pair(move, prev_operand), cur_operand)); 3586 std::make_pair(std::make_pair(move, prev_operand), cur_operand));
3359 } 3587 }
3360 } 3588 }
3361 } 3589 }
3590 if (FLAG_greedy_stats) {
3591 OFStream os(stdout);
3592 os << "Moves: " << moves_counter << std::endl;
3593 }
3362 if (delayed_insertion_map.empty()) return; 3594 if (delayed_insertion_map.empty()) return;
3363 // Insert all the moves which should occur after the stored move. 3595 // Insert all the moves which should occur after the stored move.
3364 ZoneVector<MoveOperands*> to_insert(local_zone); 3596 ZoneVector<MoveOperands*> to_insert(local_zone);
3365 ZoneVector<MoveOperands*> to_eliminate(local_zone); 3597 ZoneVector<MoveOperands*> to_eliminate(local_zone);
3366 to_insert.reserve(4); 3598 to_insert.reserve(4);
3367 to_eliminate.reserve(4); 3599 to_eliminate.reserve(4);
3368 auto moves = delayed_insertion_map.begin()->first.first; 3600 auto moves = delayed_insertion_map.begin()->first.first;
3369 for (auto it = delayed_insertion_map.begin();; ++it) { 3601 for (auto it = delayed_insertion_map.begin();; ++it) {
3370 bool done = it == delayed_insertion_map.end(); 3602 bool done = it == delayed_insertion_map.end();
3371 if (done || it->first.first != moves) { 3603 if (done || it->first.first != moves) {
(...skipping 11 matching lines...) Expand all
3383 moves = it->first.first; 3615 moves = it->first.first;
3384 } 3616 }
3385 // Gather all MoveOperands for a single ParallelMove. 3617 // Gather all MoveOperands for a single ParallelMove.
3386 auto move = new (code_zone()) MoveOperands(it->first.second, it->second); 3618 auto move = new (code_zone()) MoveOperands(it->first.second, it->second);
3387 auto eliminate = moves->PrepareInsertAfter(move); 3619 auto eliminate = moves->PrepareInsertAfter(move);
3388 to_insert.push_back(move); 3620 to_insert.push_back(move);
3389 if (eliminate != nullptr) to_eliminate.push_back(eliminate); 3621 if (eliminate != nullptr) to_eliminate.push_back(eliminate);
3390 } 3622 }
3391 } 3623 }
3392 3624
3625 // #include "../prints.inc"
Jarin 2015/05/13 13:12:56 Remove this line.
3393 3626
3394 } // namespace compiler 3627 } // namespace compiler
3395 } // namespace internal 3628 } // namespace internal
3396 } // namespace v8 3629 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698