Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |