Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 1927 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1938 compiler->AddSlowPathCode(slow_path); | 1938 compiler->AddSlowPathCode(slow_path); |
| 1939 | 1939 |
| 1940 __ LoadImmediate(IP, Isolate::Current()->stack_limit_address()); | 1940 __ LoadImmediate(IP, Isolate::Current()->stack_limit_address()); |
| 1941 __ ldr(IP, Address(IP)); | 1941 __ ldr(IP, Address(IP)); |
| 1942 __ cmp(SP, ShifterOperand(IP)); | 1942 __ cmp(SP, ShifterOperand(IP)); |
| 1943 __ b(slow_path->entry_label(), LS); | 1943 __ b(slow_path->entry_label(), LS); |
| 1944 __ Bind(slow_path->exit_label()); | 1944 __ Bind(slow_path->exit_label()); |
| 1945 } | 1945 } |
| 1946 | 1946 |
| 1947 | 1947 |
| 1948 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | |
| 1949 BinarySmiOpInstr* shift_left) { | |
| 1950 const bool is_truncating = shift_left->is_truncating(); | |
| 1951 const LocationSummary& locs = *shift_left->locs(); | |
| 1952 Register left = locs.in(0).reg(); | |
| 1953 Register result = locs.out().reg(); | |
| 1954 Label* deopt = shift_left->CanDeoptimize() ? | |
| 1955 compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL; | |
| 1956 if (locs.in(1).IsConstant()) { | |
| 1957 const Object& constant = locs.in(1).constant(); | |
| 1958 ASSERT(constant.IsSmi()); | |
| 1959 // Immediate shift operation takes 5 bits for the count. | |
| 1960 const intptr_t kCountLimit = 0x1F; | |
| 1961 const intptr_t value = Smi::Cast(constant).Value(); | |
| 1962 if (value == 0) { | |
| 1963 // No code needed. | |
| 1964 } else if ((value < 0) || (value >= kCountLimit)) { | |
| 1965 // This condition may not be known earlier in some cases because | |
| 1966 // of constant propagation, inlining, etc. | |
| 1967 if ((value >=kCountLimit) && is_truncating) { | |
| 1968 __ mov(result, ShifterOperand(0)); | |
| 1969 } else { | |
| 1970 // Result is Mint or exception. | |
| 1971 __ b(deopt); | |
| 1972 } | |
| 1973 } else { | |
| 1974 if (!is_truncating) { | |
| 1975 // Check for overflow (preserve left). | |
| 1976 __ Lsl(IP, left, value); | |
| 1977 __ cmp(left, ShifterOperand(IP, ASR, value)); | |
| 1978 __ b(deopt, NE); // Overflow. | |
| 1979 } | |
| 1980 // Shift for result now we know there is no overflow. | |
| 1981 __ Lsl(result, left, value); | |
| 1982 } | |
| 1983 return; | |
| 1984 } | |
| 1985 | |
| 1986 // Right (locs.in(1)) is not constant. | |
| 1987 Register right = locs.in(1).reg(); | |
| 1988 Range* right_range = shift_left->right()->definition()->range(); | |
| 1989 if (shift_left->left()->BindsToConstant() && !is_truncating) { | |
| 1990 // TODO(srdjan): Implement code below for is_truncating(). | |
| 1991 // If left is constant, we know the maximal allowed size for right. | |
| 1992 const Object& obj = shift_left->left()->BoundConstant(); | |
| 1993 if (obj.IsSmi()) { | |
| 1994 const intptr_t left_int = Smi::Cast(obj).Value(); | |
| 1995 if (left_int == 0) { | |
| 1996 __ cmp(right, ShifterOperand(0)); | |
| 1997 __ b(deopt, MI); | |
| 1998 return; | |
| 1999 } | |
| 2000 intptr_t tmp = (left_int > 0) ? left_int : ~left_int; | |
| 2001 intptr_t max_right = kSmiBits; | |
| 2002 while ((tmp >>= 1) != 0) { | |
|
zra
2013/05/28 19:43:32
Could you use Utils::HighestBit here?
regis
2013/05/28 21:10:15
Done here and for ia32/x64.
Note that Utils::High
| |
| 2003 max_right--; | |
| 2004 } | |
| 2005 const bool right_needs_check = | |
| 2006 (right_range == NULL) || | |
| 2007 !right_range->IsWithin(0, max_right - 1); | |
| 2008 if (right_needs_check) { | |
| 2009 __ cmp(right, | |
| 2010 ShifterOperand(reinterpret_cast<int32_t>(Smi::New(max_right)))); | |
| 2011 __ b(deopt, CS); | |
| 2012 } | |
| 2013 __ SmiUntag(right); | |
| 2014 __ Lsl(result, left, right); | |
| 2015 } | |
| 2016 return; | |
| 2017 } | |
| 2018 | |
| 2019 const bool right_needs_check = | |
| 2020 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); | |
| 2021 if (is_truncating) { | |
| 2022 if (right_needs_check) { | |
| 2023 const bool right_may_be_negative = | |
| 2024 (right_range == NULL) || | |
| 2025 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); | |
| 2026 if (right_may_be_negative) { | |
| 2027 ASSERT(shift_left->CanDeoptimize()); | |
| 2028 __ cmp(right, ShifterOperand(0)); | |
| 2029 __ b(deopt, MI); | |
| 2030 } | |
| 2031 Label done, is_not_zero; | |
| 2032 __ cmp(right, | |
| 2033 ShifterOperand(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); | |
| 2034 __ mov(result, ShifterOperand(0), CS); | |
| 2035 __ SmiUntag(right, CC); | |
| 2036 __ Lsl(result, left, right, CC); | |
| 2037 } else { | |
| 2038 __ SmiUntag(right); | |
| 2039 __ Lsl(result, left, right); | |
| 2040 } | |
| 2041 } else { | |
| 2042 if (right_needs_check) { | |
| 2043 ASSERT(shift_left->CanDeoptimize()); | |
| 2044 __ cmp(right, | |
| 2045 ShifterOperand(reinterpret_cast<int32_t>(Smi::New(Smi::kBits)))); | |
| 2046 __ b(deopt, CS); | |
| 2047 } | |
| 2048 // Left is not a constant. | |
| 2049 // Check if count too large for handling it inlined. | |
| 2050 __ SmiUntag(right); | |
| 2051 // Overflow test (preserve left and right); | |
| 2052 __ Lsl(IP, left, right); | |
| 2053 __ cmp(left, ShifterOperand(IP, ASR, right)); | |
| 2054 __ b(deopt, NE); // Overflow. | |
| 2055 // Shift for result now we know there is no overflow. | |
| 2056 __ Lsl(result, left, right); | |
| 2057 } | |
| 2058 } | |
| 2059 | |
| 2060 | |
| 1948 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { | 2061 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const { |
| 1949 const intptr_t kNumInputs = 2; | 2062 const intptr_t kNumInputs = 2; |
| 1950 if (op_kind() == Token::kTRUNCDIV) { | 2063 if (op_kind() == Token::kTRUNCDIV) { |
| 1951 UNIMPLEMENTED(); | 2064 UNIMPLEMENTED(); |
| 1952 return NULL; | 2065 return NULL; |
| 1953 } else { | 2066 } else { |
| 1954 const intptr_t kNumTemps = 0; | 2067 const intptr_t kNumTemps = 0; |
| 1955 LocationSummary* summary = | 2068 LocationSummary* summary = |
| 1956 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2069 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 1957 summary->set_in(0, Location::RequiresRegister()); | 2070 summary->set_in(0, Location::RequiresRegister()); |
| 1958 summary->set_in(1, Location::RegisterOrSmiConstant(right())); | 2071 summary->set_in(1, Location::RegisterOrSmiConstant(right())); |
| 1959 // We make use of 3-operand instructions by not requiring result register | 2072 // We make use of 3-operand instructions by not requiring result register |
| 1960 // to be identical to first input register as on Intel. | 2073 // to be identical to first input register as on Intel. |
| 1961 summary->set_out(Location::RequiresRegister()); | 2074 summary->set_out(Location::RequiresRegister()); |
| 1962 return summary; | 2075 return summary; |
| 1963 } | 2076 } |
| 1964 } | 2077 } |
| 1965 | 2078 |
| 1966 | 2079 |
| 1967 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2080 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1968 if (op_kind() == Token::kSHL) { | 2081 if (op_kind() == Token::kSHL) { |
| 1969 UNIMPLEMENTED(); | 2082 EmitSmiShiftLeft(compiler, this); |
| 1970 return; | 2083 return; |
| 1971 } | 2084 } |
| 1972 | 2085 |
| 1973 ASSERT(!is_truncating()); | 2086 ASSERT(!is_truncating()); |
| 1974 Register left = locs()->in(0).reg(); | 2087 Register left = locs()->in(0).reg(); |
| 1975 Register result = locs()->out().reg(); | 2088 Register result = locs()->out().reg(); |
| 1976 Label* deopt = NULL; | 2089 Label* deopt = NULL; |
| 1977 if (CanDeoptimize()) { | 2090 if (CanDeoptimize()) { |
| 1978 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); | 2091 deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); |
| 1979 } | 2092 } |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2053 ShifterOperand shifter_op; | 2166 ShifterOperand shifter_op; |
| 2054 if (ShifterOperand::CanHold(imm, &shifter_op)) { | 2167 if (ShifterOperand::CanHold(imm, &shifter_op)) { |
| 2055 __ eor(result, left, shifter_op); | 2168 __ eor(result, left, shifter_op); |
| 2056 } else { | 2169 } else { |
| 2057 __ LoadImmediate(IP, imm); | 2170 __ LoadImmediate(IP, imm); |
| 2058 __ eor(result, left, ShifterOperand(IP)); | 2171 __ eor(result, left, ShifterOperand(IP)); |
| 2059 } | 2172 } |
| 2060 break; | 2173 break; |
| 2061 } | 2174 } |
| 2062 case Token::kSHR: { | 2175 case Token::kSHR: { |
| 2063 UNIMPLEMENTED(); | 2176 // sarl operation masks the count to 5 bits. |
| 2177 const intptr_t kCountLimit = 0x1F; | |
| 2178 intptr_t value = Smi::Cast(constant).Value(); | |
| 2179 | |
| 2180 if (value == 0) { | |
| 2181 // TODO(vegorov): should be handled outside. | |
| 2182 break; | |
| 2183 } else if (value < 0) { | |
| 2184 // TODO(vegorov): should be handled outside. | |
| 2185 __ b(deopt); | |
| 2186 break; | |
| 2187 } | |
| 2188 | |
| 2189 value = value + kSmiTagSize; | |
| 2190 if (value >= kCountLimit) value = kCountLimit; | |
| 2191 | |
| 2192 __ Asr(result, left, value); | |
| 2193 __ SmiTag(result); | |
| 2064 break; | 2194 break; |
| 2065 } | 2195 } |
| 2066 | 2196 |
| 2067 default: | 2197 default: |
| 2068 UNREACHABLE(); | 2198 UNREACHABLE(); |
| 2069 break; | 2199 break; |
| 2070 } | 2200 } |
| 2071 return; | 2201 return; |
| 2072 } | 2202 } |
| 2073 | 2203 |
| (...skipping 949 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3023 compiler->GenerateCall(token_pos(), | 3153 compiler->GenerateCall(token_pos(), |
| 3024 &label, | 3154 &label, |
| 3025 PcDescriptors::kOther, | 3155 PcDescriptors::kOther, |
| 3026 locs()); | 3156 locs()); |
| 3027 __ Drop(2); // Discard type arguments and receiver. | 3157 __ Drop(2); // Discard type arguments and receiver. |
| 3028 } | 3158 } |
| 3029 | 3159 |
| 3030 } // namespace dart | 3160 } // namespace dart |
| 3031 | 3161 |
| 3032 #endif // defined TARGET_ARCH_ARM | 3162 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |