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

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

Issue 513213002: Generate some intrinsics using our IR. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 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 | Annotate | Revision Log
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 // Class for intrinsifying functions. 4 // Class for intrinsifying functions.
5 5
6 #include "vm/assembler.h" 6 #include "vm/assembler.h"
7 #include "vm/intrinsifier.h" 7 #include "vm/intrinsifier.h"
8 #include "vm/flags.h" 8 #include "vm/flags.h"
9 #include "vm/object.h" 9 #include "vm/object.h"
10 #include "vm/symbols.h" 10 #include "vm/symbols.h"
11 11
12 #include "vm/flow_graph.h"
13 #include "vm/flow_graph_compiler.h"
14 #include "vm/flow_graph_allocator.h"
15 #include "vm/flow_graph_builder.h"
16 #include "vm/il_printer.h"
17 #include "vm/intermediate_language.h"
18 #include "vm/parser.h"
19
12 namespace dart { 20 namespace dart {
13 21
14 DEFINE_FLAG(bool, intrinsify, true, "Instrinsify when possible"); 22 DEFINE_FLAG(bool, intrinsify, true, "Instrinsify when possible");
15 DECLARE_FLAG(bool, throw_on_javascript_int_overflow); 23 DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
24 DECLARE_FLAG(bool, code_comments);
25 DECLARE_FLAG(bool, print_flow_graph);
26 DECLARE_FLAG(bool, print_flow_graph_optimized);
16 27
17 bool Intrinsifier::CanIntrinsify(const Function& function) { 28 bool Intrinsifier::CanIntrinsify(const Function& function) {
18 if (!FLAG_intrinsify) return false; 29 if (!FLAG_intrinsify) return false;
19 if (function.IsClosureFunction()) return false; 30 if (function.IsClosureFunction()) return false;
20 // Can occur because of compile-all flag. 31 // Can occur because of compile-all flag.
21 if (function.is_external()) return false; 32 if (function.is_external()) return false;
22 return function.is_intrinsic(); 33 return function.is_intrinsic();
23 } 34 }
24 35
25 36
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 73
63 // Set up all math lib functions that can be intrisified. 74 // Set up all math lib functions that can be intrisified.
64 lib = Library::MathLibrary(); 75 lib = Library::MathLibrary();
65 ASSERT(!lib.IsNull()); 76 ASSERT(!lib.IsNull());
66 MATH_LIB_INTRINSIC_LIST(SETUP_FUNCTION); 77 MATH_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
67 78
68 // Set up all dart:typed_data lib functions that can be intrisified. 79 // Set up all dart:typed_data lib functions that can be intrisified.
69 lib = Library::TypedDataLibrary(); 80 lib = Library::TypedDataLibrary();
70 ASSERT(!lib.IsNull()); 81 ASSERT(!lib.IsNull());
71 TYPED_DATA_LIB_INTRINSIC_LIST(SETUP_FUNCTION); 82 TYPED_DATA_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
83 GRAPH_INTRINSICS_LIST(SETUP_FUNCTION);
72 84
73 // Setup all dart:profiler lib functions that can be intrinsified. 85 // Setup all dart:profiler lib functions that can be intrinsified.
74 lib = Library::ProfilerLibrary(); 86 lib = Library::ProfilerLibrary();
75 ASSERT(!lib.IsNull()); 87 ASSERT(!lib.IsNull());
76 PROFILER_LIB_INTRINSIC_LIST(SETUP_FUNCTION); 88 PROFILER_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
77 89
78 #undef SETUP_FUNCTION 90 #undef SETUP_FUNCTION
79 } 91 }
80 92
81 93
82 void Intrinsifier::Intrinsify(const Function& function, Assembler* assembler) { 94 static void EmitCodeFor(FlowGraphCompiler* compiler,
95 FlowGraph* graph) {
96 compiler->assembler()->Comment("Graph intrinsic");
97 for (intptr_t i = 0; i < graph->reverse_postorder().length(); i++) {
98 BlockEntryInstr* block = graph->reverse_postorder()[i];
99 if (block->IsGraphEntry()) continue; // No code for graph entry needed.
100 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
101 Instruction* instr = it.Current();
102 if (FLAG_code_comments) compiler->EmitComment(instr);
103 if (instr->IsParallelMove()) {
104 compiler->parallel_move_resolver()->EmitNativeCode(
105 instr->AsParallelMove());
106 } else {
107 ASSERT(instr->locs() != NULL);
108 // Calls are not supported in intrinsics code.
109 ASSERT(!instr->locs()->can_call());
110 // Intrinsic code only allows constants that can always be loaded
111 // without constant pool on all platforms. There is no constant pool
112 // register set up in intrinsic code. We could allow old-space constants
113 // as they don't move, but restrict to smi and VM objects for now.
114 ASSERT(!instr->IsConstant() ||
115 (instr->AsConstant()->value().IsSmi() ||
116 instr->AsConstant()->value().InVMHeap()));
117 instr->EmitNativeCode(compiler);
118 }
119 }
120 }
121 }
122
123
124 bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function,
125 FlowGraphCompiler* compiler) {
126 ZoneGrowableArray<const ICData*>* ic_data_array =
127 new ZoneGrowableArray<const ICData*>();
128 FlowGraphBuilder builder(const_cast<ParsedFunction*>(&parsed_function),
129 *ic_data_array,
130 NULL, // NULL = not inlining.
131 -1); // No OSR id.
132
133 intptr_t block_id = builder.AllocateBlockId();
134 TargetEntryInstr* normal_entry =
135 new TargetEntryInstr(block_id,
136 CatchClauseNode::kInvalidTryIndex);
137 GraphEntryInstr* graph_entry = new GraphEntryInstr(
138 &parsed_function, normal_entry, -1); // No OSR id.
139 FlowGraph* graph = new FlowGraph(builder, graph_entry, block_id);
140 const Function& function = parsed_function.function();
141 switch (function.recognized_kind()) {
142 #define EMIT_CASE(test_class_name, test_function_name, enum_name, fp) \
143 case MethodRecognizer::k##enum_name: \
144 ASSERT(function.CheckSourceFingerprint(fp)); \
145 Build_##enum_name(graph); \
146 break;
147
148 GRAPH_INTRINSICS_LIST(EMIT_CASE);
149 default:
150 return false;
151 #undef EMIT_CASE
152 }
153
154 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) {
155 OS::Print("Intrinsic graph before\n");
156 FlowGraphPrinter printer(*graph);
157 printer.PrintBlocks();
158 }
159
160 // Perform register allocation on the SSA graph.
161 FlowGraphAllocator allocator(*graph, true); // Intrinsic mode.
162 allocator.AllocateRegisters();
163
164 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) {
165 OS::Print("Intrinsic graph after\n");
166 FlowGraphPrinter printer(*graph);
167 printer.PrintBlocks();
168 }
169 EmitCodeFor(compiler, graph);
170 return true;
171 }
172
173
174 void Intrinsifier::Intrinsify(const ParsedFunction& parsed_function,
175 FlowGraphCompiler* compiler) {
176 const Function& function = parsed_function.function();
83 if (!CanIntrinsify(function)) return; 177 if (!CanIntrinsify(function)) return;
84 178
179 if (GraphIntrinsify(parsed_function, compiler)) return;
180
181
85 #define EMIT_CASE(test_class_name, test_function_name, enum_name, fp) \ 182 #define EMIT_CASE(test_class_name, test_function_name, enum_name, fp) \
86 case MethodRecognizer::k##enum_name: \ 183 case MethodRecognizer::k##enum_name: \
87 ASSERT(function.CheckSourceFingerprint(fp)); \ 184 ASSERT(function.CheckSourceFingerprint(fp)); \
88 assembler->Comment("Intrinsic"); \ 185 compiler->assembler()->Comment("Intrinsic"); \
89 enum_name(assembler); \ 186 enum_name(compiler->assembler()); \
90 break; 187 break;
91 188
92 if (FLAG_throw_on_javascript_int_overflow && (Smi::kBits >= 32)) { 189 if (FLAG_throw_on_javascript_int_overflow && (Smi::kBits >= 32)) {
93 // Integer intrinsics are in the core library, but we don't want to 190 // Integer intrinsics are in the core library, but we don't want to
94 // intrinsify when Smi > 32 bits if we are looking for javascript integer 191 // intrinsify when Smi > 32 bits if we are looking for javascript integer
95 // overflow. 192 // overflow.
96 switch (function.recognized_kind()) { 193 switch (function.recognized_kind()) {
97 CORE_LIB_INTRINSIC_LIST(EMIT_CASE); 194 ALL_INTRINSICS_NO_INTEGER_LIB_LIST(EMIT_CASE);
98 MATH_LIB_INTRINSIC_LIST(EMIT_CASE);
99 TYPED_DATA_LIB_INTRINSIC_LIST(EMIT_CASE);
100 PROFILER_LIB_INTRINSIC_LIST(EMIT_CASE);
101 default: 195 default:
102 break; 196 break;
103 } 197 }
104 } else { 198 } else {
105 switch (function.recognized_kind()) { 199 switch (function.recognized_kind()) {
106 CORE_LIB_INTRINSIC_LIST(EMIT_CASE); 200 ALL_INTRINSICS_LIST(EMIT_CASE);
107 CORE_INTEGER_LIB_INTRINSIC_LIST(EMIT_CASE);
108 MATH_LIB_INTRINSIC_LIST(EMIT_CASE);
109 TYPED_DATA_LIB_INTRINSIC_LIST(EMIT_CASE);
110 PROFILER_LIB_INTRINSIC_LIST(EMIT_CASE);
111 default: 201 default:
112 UNREACHABLE(); 202 UNREACHABLE();
113 break; 203 break;
114 } 204 }
115 } 205 }
116 #undef EMIT_INTRINSIC 206 #undef EMIT_INTRINSIC
117 } 207 }
118 208
209
210 class BlockBuilder : public ValueObject {
211 public:
212 BlockBuilder(FlowGraph* flow_graph, TargetEntryInstr* entry)
213 : flow_graph_(flow_graph), entry_(entry), current_(entry) { }
214
215 Definition* AddToInitialDefinitions(Definition* def) {
216 def->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
217 flow_graph_->AddToInitialDefinitions(def);
218 return def;
219 }
220
221 Definition* AddDefinition(Definition* def) {
222 def->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
223 current_->LinkTo(def);
224 current_ = def;
225 return def;
226 }
227
228 Instruction* AddInstruction(Instruction* instr) {
229 current_->LinkTo(instr);
230 current_ = instr;
231 return instr;
232 }
233
234 void AddIntrinsicReturn(Value* value) {
235 ReturnInstr* instr = new ReturnInstr(-1, // No token position.
236 value,
237 true); // Intrinsic return.
238 AddInstruction(instr);
239 entry_->set_last_instruction(instr);
240 }
241
242 private:
243 FlowGraph* flow_graph_;
244 BlockEntryInstr* entry_;
245 Instruction* current_;
246 };
247
248
249 static void PrepareIndexedOp(BlockBuilder* builder,
250 Definition* array,
251 Definition* index,
252 intptr_t length_offset) {
253 builder->AddInstruction(
254 new CheckSmiInstr(new Value(index),
255 Isolate::kNoDeoptId,
256 -1)); // no token pos
257
258 Definition* length = builder->AddDefinition(
259 new LoadFieldInstr(new Value(array),
260 length_offset,
261 Type::ZoneHandle(Type::SmiType()),
262 true)); // immutable
263 builder->AddInstruction(
264 new CheckArrayBoundInstr(new Value(length),
265 new Value(index),
266 Isolate::kNoDeoptId));
267 }
268
269
270 void Intrinsifier::Build_Uint8ArrayGetIndexed(FlowGraph* flow_graph) {
271 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
272 TargetEntryInstr* normal_entry = graph_entry->normal_entry();
273 BlockBuilder builder(flow_graph, normal_entry);
274
275 Definition* index = builder.AddToInitialDefinitions(
276 new ParameterInstr(1, graph_entry, SPREG));
277 Definition* array = builder.AddToInitialDefinitions(
278 new ParameterInstr(2, graph_entry, SPREG));
279
280 PrepareIndexedOp(&builder, array, index, TypedData::length_offset());
281
282 Definition* result = builder.AddDefinition(
283 new LoadIndexedInstr(new Value(array),
284 new Value(index),
285 1, // index scale
286 kTypedDataUint8ArrayCid,
287 Isolate::kNoDeoptId,
288 -1)); // no token pos
289 builder.AddIntrinsicReturn(new Value(result));
290 }
291
292
293 void Intrinsifier::Build_ExternalUint8ArrayGetIndexed(FlowGraph* flow_graph) {
294 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
295 TargetEntryInstr* normal_entry = graph_entry->normal_entry();
296 BlockBuilder builder(flow_graph, normal_entry);
297
298 Definition* index = builder.AddToInitialDefinitions(
299 new ParameterInstr(1, graph_entry, SPREG));
300 Definition* array = builder.AddToInitialDefinitions(
301 new ParameterInstr(2, graph_entry, SPREG));
302
303 PrepareIndexedOp(&builder, array, index, ExternalTypedData::length_offset());
304
305 Definition* elements = builder.AddDefinition(
306 new LoadUntaggedInstr(new Value(array),
307 ExternalTypedData::data_offset()));
308 Definition* result = builder.AddDefinition(
309 new LoadIndexedInstr(new Value(elements),
310 new Value(index),
311 1, // index scale
312 kExternalTypedDataUint8ArrayCid,
313 Isolate::kNoDeoptId,
314 -1)); // no token pos
315 builder.AddIntrinsicReturn(new Value(result));
316 }
317
318
319 void Intrinsifier::Build_Uint8ArraySetIndexed(FlowGraph* flow_graph) {
320 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
321 TargetEntryInstr* normal_entry = graph_entry->normal_entry();
322 BlockBuilder builder(flow_graph, normal_entry);
323
324 Definition* value = builder.AddToInitialDefinitions(
325 new ParameterInstr(1, graph_entry, SPREG));
326 Definition* index = builder.AddToInitialDefinitions(
327 new ParameterInstr(2, graph_entry, SPREG));
328 Definition* array = builder.AddToInitialDefinitions(
329 new ParameterInstr(3, graph_entry, SPREG));
330
331 PrepareIndexedOp(&builder, array, index, TypedData::length_offset());
332
333 builder.AddInstruction(
334 new CheckSmiInstr(new Value(value),
335 Isolate::kNoDeoptId,
336 -1)); // no token pos
337
338 builder.AddInstruction(
339 new StoreIndexedInstr(new Value(array),
340 new Value(index),
341 new Value(value),
342 kNoStoreBarrier,
343 1, // index scale
344 kTypedDataUint8ArrayCid,
345 Isolate::kNoDeoptId,
346 -1)); // no token pos.
347 // Return null.
348 Definition* null_def = builder.AddDefinition(
349 new ConstantInstr(Object::ZoneHandle(Object::null())));
350 builder.AddIntrinsicReturn(new Value(null_def));
351 }
352
353
354 void Intrinsifier::Build_ExternalUint8ArraySetIndexed(FlowGraph* flow_graph) {
355 GraphEntryInstr* graph_entry = flow_graph->graph_entry();
356 TargetEntryInstr* normal_entry = graph_entry->normal_entry();
357 BlockBuilder builder(flow_graph, normal_entry);
358
359 Definition* value = builder.AddToInitialDefinitions(
360 new ParameterInstr(1, graph_entry, SPREG));
361 Definition* index = builder.AddToInitialDefinitions(
362 new ParameterInstr(2, graph_entry, SPREG));
363 Definition* array = builder.AddToInitialDefinitions(
364 new ParameterInstr(3, graph_entry, SPREG));
365
366 PrepareIndexedOp(&builder, array, index, ExternalTypedData::length_offset());
367
368 builder.AddInstruction(
369 new CheckSmiInstr(new Value(value),
370 Isolate::kNoDeoptId,
371 -1)); // no token pos
372 Definition* elements = builder.AddDefinition(
373 new LoadUntaggedInstr(new Value(array),
374 ExternalTypedData::data_offset()));
375 builder.AddInstruction(
376 new StoreIndexedInstr(new Value(elements),
377 new Value(index),
378 new Value(value),
379 kNoStoreBarrier,
380 1, // index scale
381 kExternalTypedDataUint8ArrayCid,
382 Isolate::kNoDeoptId,
383 -1)); // no token pos.
384 // Return null.
385 Definition* null_def = builder.AddDefinition(
386 new ConstantInstr(Object::ZoneHandle(Object::null())));
387 builder.AddIntrinsicReturn(new Value(null_def));
388 }
389
119 } // namespace dart 390 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698