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

Side by Side Diff: runtime/vm/flow_graph.cc

Issue 2265873005: VM: Remove more duplicate code between AOT and JIT compiler. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: fix comment Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/flow_graph.h ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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/flow_graph.h" 5 #include "vm/flow_graph.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/cha.h" 8 #include "vm/cha.h"
9 #include "vm/flow_graph_builder.h" 9 #include "vm/flow_graph_builder.h"
10 #include "vm/flow_graph_compiler.h" 10 #include "vm/flow_graph_compiler.h"
(...skipping 2036 matching lines...) Expand 10 before | Expand all | Expand 10 after
2047 ASSERT((replacement == NULL) || current->IsDefinition()); 2047 ASSERT((replacement == NULL) || current->IsDefinition());
2048 ReplaceCurrentInstruction(&it, current, replacement); 2048 ReplaceCurrentInstruction(&it, current, replacement);
2049 changed = true; 2049 changed = true;
2050 } 2050 }
2051 } 2051 }
2052 } 2052 }
2053 return changed; 2053 return changed;
2054 } 2054 }
2055 2055
2056 2056
2057 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
2058 // shift can be a truncating Smi shift-left and result is always Smi.
2059 // Merging occurs only per basic-block.
2060 void FlowGraph::TryOptimizePatterns() {
2061 if (!FLAG_truncating_left_shift) return;
2062 GrowableArray<BinarySmiOpInstr*> div_mod_merge;
2063 GrowableArray<MathUnaryInstr*> sin_cos_merge;
2064 for (BlockIterator block_it = reverse_postorder_iterator();
2065 !block_it.Done();
2066 block_it.Advance()) {
2067 // Merging only per basic-block.
2068 div_mod_merge.Clear();
2069 sin_cos_merge.Clear();
2070 ForwardInstructionIterator it(block_it.Current());
2071 for (; !it.Done(); it.Advance()) {
2072 if (it.Current()->IsBinarySmiOp()) {
2073 BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
2074 if (binop->op_kind() == Token::kBIT_AND) {
2075 OptimizeLeftShiftBitAndSmiOp(&it,
2076 binop,
2077 binop->left()->definition(),
2078 binop->right()->definition());
2079 } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
2080 (binop->op_kind() == Token::kMOD)) {
2081 if (binop->HasUses()) {
2082 div_mod_merge.Add(binop);
2083 }
2084 }
2085 } else if (it.Current()->IsBinaryMintOp()) {
2086 BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
2087 if (mintop->op_kind() == Token::kBIT_AND) {
2088 OptimizeLeftShiftBitAndSmiOp(&it,
2089 mintop,
2090 mintop->left()->definition(),
2091 mintop->right()->definition());
2092 }
2093 } else if (it.Current()->IsMathUnary()) {
2094 MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
2095 if ((math_unary->kind() == MathUnaryInstr::kSin) ||
2096 (math_unary->kind() == MathUnaryInstr::kCos)) {
2097 if (math_unary->HasUses()) {
2098 sin_cos_merge.Add(math_unary);
2099 }
2100 }
2101 }
2102 }
2103 TryMergeTruncDivMod(&div_mod_merge);
2104 TryMergeMathUnary(&sin_cos_merge);
2105 }
2106 }
2107
2108
2109 static bool IsPositiveOrZeroSmiConst(Definition* d) {
2110 ConstantInstr* const_instr = d->AsConstant();
2111 if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
2112 return Smi::Cast(const_instr->value()).Value() >= 0;
2113 }
2114 return false;
2115 }
2116
2117
2118 static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
2119 BinarySmiOpInstr* instr = d->AsBinarySmiOp();
2120 if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
2121 return instr;
2122 }
2123 return NULL;
2124 }
2125
2126
2127 void FlowGraph::OptimizeLeftShiftBitAndSmiOp(
2128 ForwardInstructionIterator* current_iterator,
2129 Definition* bit_and_instr,
2130 Definition* left_instr,
2131 Definition* right_instr) {
2132 ASSERT(bit_and_instr != NULL);
2133 ASSERT((left_instr != NULL) && (right_instr != NULL));
2134
2135 // Check for pattern, smi_shift_left must be single-use.
2136 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
2137 if (!is_positive_or_zero) {
2138 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
2139 }
2140 if (!is_positive_or_zero) return;
2141
2142 BinarySmiOpInstr* smi_shift_left = NULL;
2143 if (bit_and_instr->InputAt(0)->IsSingleUse()) {
2144 smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
2145 }
2146 if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
2147 smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
2148 }
2149 if (smi_shift_left == NULL) return;
2150
2151 // Pattern recognized.
2152 smi_shift_left->mark_truncating();
2153 ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
2154 if (bit_and_instr->IsBinaryMintOp()) {
2155 // Replace Mint op with Smi op.
2156 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
2157 Token::kBIT_AND,
2158 new(Z) Value(left_instr),
2159 new(Z) Value(right_instr),
2160 Thread::kNoDeoptId); // BIT_AND cannot deoptimize.
2161 bit_and_instr->ReplaceWith(smi_op, current_iterator);
2162 }
2163 }
2164
2165
2166 // Dart:
2167 // var x = d % 10;
2168 // var y = d ~/ 10;
2169 // var z = x + y;
2170 //
2171 // IL:
2172 // v4 <- %(v2, v3)
2173 // v5 <- ~/(v2, v3)
2174 // v6 <- +(v4, v5)
2175 //
2176 // IL optimized:
2177 // v4 <- DIVMOD(v2, v3);
2178 // v5 <- LoadIndexed(v4, 0); // ~/ result
2179 // v6 <- LoadIndexed(v4, 1); // % result
2180 // v7 <- +(v5, v6)
2181 // Because of the environment it is important that merged instruction replaces
2182 // first original instruction encountered.
2183 void FlowGraph::TryMergeTruncDivMod(
2184 GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
2185 if (merge_candidates->length() < 2) {
2186 // Need at least a TRUNCDIV and a MOD.
2187 return;
2188 }
2189 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
2190 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
2191 if (curr_instr == NULL) {
2192 // Instruction was merged already.
2193 continue;
2194 }
2195 ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
2196 (curr_instr->op_kind() == Token::kMOD));
2197 // Check if there is kMOD/kTRUNDIV binop with same inputs.
2198 const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
2199 Token::kMOD : Token::kTRUNCDIV;
2200 Definition* left_def = curr_instr->left()->definition();
2201 Definition* right_def = curr_instr->right()->definition();
2202 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
2203 BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
2204 // 'other_binop' can be NULL if it was already merged.
2205 if ((other_binop != NULL) &&
2206 (other_binop->op_kind() == other_kind) &&
2207 (other_binop->left()->definition() == left_def) &&
2208 (other_binop->right()->definition() == right_def)) {
2209 (*merge_candidates)[k] = NULL; // Clear it.
2210 ASSERT(curr_instr->HasUses());
2211 AppendExtractNthOutputForMerged(
2212 curr_instr,
2213 MergedMathInstr::OutputIndexOf(curr_instr->op_kind()),
2214 kTagged, kSmiCid);
2215 ASSERT(other_binop->HasUses());
2216 AppendExtractNthOutputForMerged(
2217 other_binop,
2218 MergedMathInstr::OutputIndexOf(other_binop->op_kind()),
2219 kTagged, kSmiCid);
2220
2221 ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(2);
2222 args->Add(new(Z) Value(curr_instr->left()->definition()));
2223 args->Add(new(Z) Value(curr_instr->right()->definition()));
2224
2225 // Replace with TruncDivMod.
2226 MergedMathInstr* div_mod = new(Z) MergedMathInstr(
2227 args,
2228 curr_instr->deopt_id(),
2229 MergedMathInstr::kTruncDivMod);
2230 curr_instr->ReplaceWith(div_mod, NULL);
2231 other_binop->ReplaceUsesWith(div_mod);
2232 other_binop->RemoveFromGraph();
2233 // Only one merge possible. Because canonicalization happens later,
2234 // more candidates are possible.
2235 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
2236 break;
2237 }
2238 }
2239 }
2240 }
2241
2242
2243 // Tries to merge MathUnary operations, in this case sine and cosine.
2244 void FlowGraph::TryMergeMathUnary(
2245 GrowableArray<MathUnaryInstr*>* merge_candidates) {
2246 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
2247 !FLAG_merge_sin_cos) {
2248 return;
2249 }
2250 if (merge_candidates->length() < 2) {
2251 // Need at least a SIN and a COS.
2252 return;
2253 }
2254 for (intptr_t i = 0; i < merge_candidates->length(); i++) {
2255 MathUnaryInstr* curr_instr = (*merge_candidates)[i];
2256 if (curr_instr == NULL) {
2257 // Instruction was merged already.
2258 continue;
2259 }
2260 const intptr_t kind = curr_instr->kind();
2261 ASSERT((kind == MathUnaryInstr::kSin) ||
2262 (kind == MathUnaryInstr::kCos));
2263 // Check if there is sin/cos binop with same inputs.
2264 const intptr_t other_kind = (kind == MathUnaryInstr::kSin) ?
2265 MathUnaryInstr::kCos : MathUnaryInstr::kSin;
2266 Definition* def = curr_instr->value()->definition();
2267 for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
2268 MathUnaryInstr* other_op = (*merge_candidates)[k];
2269 // 'other_op' can be NULL if it was already merged.
2270 if ((other_op != NULL) && (other_op->kind() == other_kind) &&
2271 (other_op->value()->definition() == def)) {
2272 (*merge_candidates)[k] = NULL; // Clear it.
2273 ASSERT(curr_instr->HasUses());
2274 AppendExtractNthOutputForMerged(curr_instr,
2275 MergedMathInstr::OutputIndexOf(kind),
2276 kUnboxedDouble, kDoubleCid);
2277 ASSERT(other_op->HasUses());
2278 AppendExtractNthOutputForMerged(
2279 other_op,
2280 MergedMathInstr::OutputIndexOf(other_kind),
2281 kUnboxedDouble, kDoubleCid);
2282 ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
2283 args->Add(new(Z) Value(curr_instr->value()->definition()));
2284 // Replace with SinCos.
2285 MergedMathInstr* sin_cos =
2286 new(Z) MergedMathInstr(args,
2287 curr_instr->DeoptimizationTarget(),
2288 MergedMathInstr::kSinCos);
2289 curr_instr->ReplaceWith(sin_cos, NULL);
2290 other_op->ReplaceUsesWith(sin_cos);
2291 other_op->RemoveFromGraph();
2292 // Only one merge possible. Because canonicalization happens later,
2293 // more candidates are possible.
2294 // TODO(srdjan): Allow merging of sin/cos into sincos.
2295 break;
2296 }
2297 }
2298 }
2299 }
2300
2301
2302 void FlowGraph::AppendExtractNthOutputForMerged(Definition* instr,
2303 intptr_t index,
2304 Representation rep,
2305 intptr_t cid) {
2306 ExtractNthOutputInstr* extract =
2307 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
2308 instr->ReplaceUsesWith(extract);
2309 InsertAfter(instr, extract, NULL, FlowGraph::kValue);
2310 }
2311
2312
2313
2314
2057 } // namespace dart 2315 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph.h ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698