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

Unified 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, 4 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 side-by-side diff with in-line comments
Download patch
Index: runtime/vm/intrinsifier.cc
===================================================================
--- runtime/vm/intrinsifier.cc (revision 39651)
+++ runtime/vm/intrinsifier.cc (working copy)
@@ -9,10 +9,21 @@
#include "vm/object.h"
#include "vm/symbols.h"
+#include "vm/flow_graph.h"
+#include "vm/flow_graph_compiler.h"
+#include "vm/flow_graph_allocator.h"
+#include "vm/flow_graph_builder.h"
+#include "vm/il_printer.h"
+#include "vm/intermediate_language.h"
+#include "vm/parser.h"
+
namespace dart {
DEFINE_FLAG(bool, intrinsify, true, "Instrinsify when possible");
DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
+DECLARE_FLAG(bool, code_comments);
+DECLARE_FLAG(bool, print_flow_graph);
+DECLARE_FLAG(bool, print_flow_graph_optimized);
bool Intrinsifier::CanIntrinsify(const Function& function) {
if (!FLAG_intrinsify) return false;
@@ -69,6 +80,7 @@
lib = Library::TypedDataLibrary();
ASSERT(!lib.IsNull());
TYPED_DATA_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
+ GRAPH_INTRINSICS_LIST(SETUP_FUNCTION);
// Setup all dart:profiler lib functions that can be intrinsified.
lib = Library::ProfilerLibrary();
@@ -79,14 +91,99 @@
}
-void Intrinsifier::Intrinsify(const Function& function, Assembler* assembler) {
+static void EmitCodeFor(FlowGraphCompiler* compiler,
+ FlowGraph* graph) {
+ compiler->assembler()->Comment("Graph intrinsic");
+ for (intptr_t i = 0; i < graph->reverse_postorder().length(); i++) {
+ BlockEntryInstr* block = graph->reverse_postorder()[i];
+ if (block->IsGraphEntry()) continue; // No code for graph entry needed.
+ for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+ Instruction* instr = it.Current();
+ if (FLAG_code_comments) compiler->EmitComment(instr);
+ if (instr->IsParallelMove()) {
+ compiler->parallel_move_resolver()->EmitNativeCode(
+ instr->AsParallelMove());
+ } else {
+ ASSERT(instr->locs() != NULL);
+ // Calls are not supported in intrinsics code.
+ ASSERT(!instr->locs()->can_call());
+ // Intrinsic code only allows constants that can always be loaded
+ // without constant pool on all platforms. There is no constant pool
+ // register set up in intrinsic code. We could allow old-space constants
+ // as they don't move, but restrict to smi and VM objects for now.
+ ASSERT(!instr->IsConstant() ||
+ (instr->AsConstant()->value().IsSmi() ||
+ instr->AsConstant()->value().InVMHeap()));
+ instr->EmitNativeCode(compiler);
+ }
+ }
+ }
+}
+
+
+bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function,
+ FlowGraphCompiler* compiler) {
+ ZoneGrowableArray<const ICData*>* ic_data_array =
+ new ZoneGrowableArray<const ICData*>();
+ FlowGraphBuilder builder(const_cast<ParsedFunction*>(&parsed_function),
+ *ic_data_array,
+ NULL, // NULL = not inlining.
+ -1); // No OSR id.
+
+ intptr_t block_id = builder.AllocateBlockId();
+ TargetEntryInstr* normal_entry =
+ new TargetEntryInstr(block_id,
+ CatchClauseNode::kInvalidTryIndex);
+ GraphEntryInstr* graph_entry = new GraphEntryInstr(
+ &parsed_function, normal_entry, -1); // No OSR id.
+ FlowGraph* graph = new FlowGraph(builder, graph_entry, block_id);
+ const Function& function = parsed_function.function();
+ switch (function.recognized_kind()) {
+#define EMIT_CASE(test_class_name, test_function_name, enum_name, fp) \
+ case MethodRecognizer::k##enum_name: \
+ ASSERT(function.CheckSourceFingerprint(fp)); \
+ Build_##enum_name(graph); \
+ break;
+
+ GRAPH_INTRINSICS_LIST(EMIT_CASE);
+ default:
+ return false;
+#undef EMIT_CASE
+ }
+
+ if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) {
+ OS::Print("Intrinsic graph before\n");
+ FlowGraphPrinter printer(*graph);
+ printer.PrintBlocks();
+ }
+
+ // Perform register allocation on the SSA graph.
+ FlowGraphAllocator allocator(*graph, true); // Intrinsic mode.
+ allocator.AllocateRegisters();
+
+ if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) {
+ OS::Print("Intrinsic graph after\n");
+ FlowGraphPrinter printer(*graph);
+ printer.PrintBlocks();
+ }
+ EmitCodeFor(compiler, graph);
+ return true;
+}
+
+
+void Intrinsifier::Intrinsify(const ParsedFunction& parsed_function,
+ FlowGraphCompiler* compiler) {
+ const Function& function = parsed_function.function();
if (!CanIntrinsify(function)) return;
+ if (GraphIntrinsify(parsed_function, compiler)) return;
+
+
#define EMIT_CASE(test_class_name, test_function_name, enum_name, fp) \
case MethodRecognizer::k##enum_name: \
ASSERT(function.CheckSourceFingerprint(fp)); \
- assembler->Comment("Intrinsic"); \
- enum_name(assembler); \
+ compiler->assembler()->Comment("Intrinsic"); \
+ enum_name(compiler->assembler()); \
break;
if (FLAG_throw_on_javascript_int_overflow && (Smi::kBits >= 32)) {
@@ -94,20 +191,13 @@
// intrinsify when Smi > 32 bits if we are looking for javascript integer
// overflow.
switch (function.recognized_kind()) {
- CORE_LIB_INTRINSIC_LIST(EMIT_CASE);
- MATH_LIB_INTRINSIC_LIST(EMIT_CASE);
- TYPED_DATA_LIB_INTRINSIC_LIST(EMIT_CASE);
- PROFILER_LIB_INTRINSIC_LIST(EMIT_CASE);
+ ALL_INTRINSICS_NO_INTEGER_LIB_LIST(EMIT_CASE);
default:
break;
}
} else {
switch (function.recognized_kind()) {
- CORE_LIB_INTRINSIC_LIST(EMIT_CASE);
- CORE_INTEGER_LIB_INTRINSIC_LIST(EMIT_CASE);
- MATH_LIB_INTRINSIC_LIST(EMIT_CASE);
- TYPED_DATA_LIB_INTRINSIC_LIST(EMIT_CASE);
- PROFILER_LIB_INTRINSIC_LIST(EMIT_CASE);
+ ALL_INTRINSICS_LIST(EMIT_CASE);
default:
UNREACHABLE();
break;
@@ -116,4 +206,185 @@
#undef EMIT_INTRINSIC
}
+
+class BlockBuilder : public ValueObject {
+ public:
+ BlockBuilder(FlowGraph* flow_graph, TargetEntryInstr* entry)
+ : flow_graph_(flow_graph), entry_(entry), current_(entry) { }
+
+ Definition* AddToInitialDefinitions(Definition* def) {
+ def->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
+ flow_graph_->AddToInitialDefinitions(def);
+ return def;
+ }
+
+ Definition* AddDefinition(Definition* def) {
+ def->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
+ current_->LinkTo(def);
+ current_ = def;
+ return def;
+ }
+
+ Instruction* AddInstruction(Instruction* instr) {
+ current_->LinkTo(instr);
+ current_ = instr;
+ return instr;
+ }
+
+ void AddIntrinsicReturn(Value* value) {
+ ReturnInstr* instr = new ReturnInstr(-1, // No token position.
+ value,
+ true); // Intrinsic return.
+ AddInstruction(instr);
+ entry_->set_last_instruction(instr);
+ }
+
+ private:
+ FlowGraph* flow_graph_;
+ BlockEntryInstr* entry_;
+ Instruction* current_;
+};
+
+
+static void PrepareIndexedOp(BlockBuilder* builder,
+ Definition* array,
+ Definition* index,
+ intptr_t length_offset) {
+ builder->AddInstruction(
+ new CheckSmiInstr(new Value(index),
+ Isolate::kNoDeoptId,
+ -1)); // no token pos
+
+ Definition* length = builder->AddDefinition(
+ new LoadFieldInstr(new Value(array),
+ length_offset,
+ Type::ZoneHandle(Type::SmiType()),
+ true)); // immutable
+ builder->AddInstruction(
+ new CheckArrayBoundInstr(new Value(length),
+ new Value(index),
+ Isolate::kNoDeoptId));
+}
+
+
+void Intrinsifier::Build_Uint8ArrayGetIndexed(FlowGraph* flow_graph) {
+ GraphEntryInstr* graph_entry = flow_graph->graph_entry();
+ TargetEntryInstr* normal_entry = graph_entry->normal_entry();
+ BlockBuilder builder(flow_graph, normal_entry);
+
+ Definition* index = builder.AddToInitialDefinitions(
+ new ParameterInstr(1, graph_entry, SPREG));
+ Definition* array = builder.AddToInitialDefinitions(
+ new ParameterInstr(2, graph_entry, SPREG));
+
+ PrepareIndexedOp(&builder, array, index, TypedData::length_offset());
+
+ Definition* result = builder.AddDefinition(
+ new LoadIndexedInstr(new Value(array),
+ new Value(index),
+ 1, // index scale
+ kTypedDataUint8ArrayCid,
+ Isolate::kNoDeoptId,
+ -1)); // no token pos
+ builder.AddIntrinsicReturn(new Value(result));
+}
+
+
+void Intrinsifier::Build_ExternalUint8ArrayGetIndexed(FlowGraph* flow_graph) {
+ GraphEntryInstr* graph_entry = flow_graph->graph_entry();
+ TargetEntryInstr* normal_entry = graph_entry->normal_entry();
+ BlockBuilder builder(flow_graph, normal_entry);
+
+ Definition* index = builder.AddToInitialDefinitions(
+ new ParameterInstr(1, graph_entry, SPREG));
+ Definition* array = builder.AddToInitialDefinitions(
+ new ParameterInstr(2, graph_entry, SPREG));
+
+ PrepareIndexedOp(&builder, array, index, ExternalTypedData::length_offset());
+
+ Definition* elements = builder.AddDefinition(
+ new LoadUntaggedInstr(new Value(array),
+ ExternalTypedData::data_offset()));
+ Definition* result = builder.AddDefinition(
+ new LoadIndexedInstr(new Value(elements),
+ new Value(index),
+ 1, // index scale
+ kExternalTypedDataUint8ArrayCid,
+ Isolate::kNoDeoptId,
+ -1)); // no token pos
+ builder.AddIntrinsicReturn(new Value(result));
+}
+
+
+void Intrinsifier::Build_Uint8ArraySetIndexed(FlowGraph* flow_graph) {
+ GraphEntryInstr* graph_entry = flow_graph->graph_entry();
+ TargetEntryInstr* normal_entry = graph_entry->normal_entry();
+ BlockBuilder builder(flow_graph, normal_entry);
+
+ Definition* value = builder.AddToInitialDefinitions(
+ new ParameterInstr(1, graph_entry, SPREG));
+ Definition* index = builder.AddToInitialDefinitions(
+ new ParameterInstr(2, graph_entry, SPREG));
+ Definition* array = builder.AddToInitialDefinitions(
+ new ParameterInstr(3, graph_entry, SPREG));
+
+ PrepareIndexedOp(&builder, array, index, TypedData::length_offset());
+
+ builder.AddInstruction(
+ new CheckSmiInstr(new Value(value),
+ Isolate::kNoDeoptId,
+ -1)); // no token pos
+
+ builder.AddInstruction(
+ new StoreIndexedInstr(new Value(array),
+ new Value(index),
+ new Value(value),
+ kNoStoreBarrier,
+ 1, // index scale
+ kTypedDataUint8ArrayCid,
+ Isolate::kNoDeoptId,
+ -1)); // no token pos.
+ // Return null.
+ Definition* null_def = builder.AddDefinition(
+ new ConstantInstr(Object::ZoneHandle(Object::null())));
+ builder.AddIntrinsicReturn(new Value(null_def));
+}
+
+
+void Intrinsifier::Build_ExternalUint8ArraySetIndexed(FlowGraph* flow_graph) {
+ GraphEntryInstr* graph_entry = flow_graph->graph_entry();
+ TargetEntryInstr* normal_entry = graph_entry->normal_entry();
+ BlockBuilder builder(flow_graph, normal_entry);
+
+ Definition* value = builder.AddToInitialDefinitions(
+ new ParameterInstr(1, graph_entry, SPREG));
+ Definition* index = builder.AddToInitialDefinitions(
+ new ParameterInstr(2, graph_entry, SPREG));
+ Definition* array = builder.AddToInitialDefinitions(
+ new ParameterInstr(3, graph_entry, SPREG));
+
+ PrepareIndexedOp(&builder, array, index, ExternalTypedData::length_offset());
+
+ builder.AddInstruction(
+ new CheckSmiInstr(new Value(value),
+ Isolate::kNoDeoptId,
+ -1)); // no token pos
+ Definition* elements = builder.AddDefinition(
+ new LoadUntaggedInstr(new Value(array),
+ ExternalTypedData::data_offset()));
+ builder.AddInstruction(
+ new StoreIndexedInstr(new Value(elements),
+ new Value(index),
+ new Value(value),
+ kNoStoreBarrier,
+ 1, // index scale
+ kExternalTypedDataUint8ArrayCid,
+ Isolate::kNoDeoptId,
+ -1)); // no token pos.
+ // Return null.
+ Definition* null_def = builder.AddDefinition(
+ new ConstantInstr(Object::ZoneHandle(Object::null())));
+ builder.AddIntrinsicReturn(new Value(null_def));
+}
+
} // namespace dart

Powered by Google App Engine
This is Rietveld 408576698