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

Unified Diff: runtime/vm/flow_graph_optimizer.cc

Issue 345563007: Add Uint32 representation (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 5 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
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/flow_graph_optimizer.cc
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index b1996d6a32c90a325371a263382d94ce3d3ffe47..fa5db4ded883864c43848e90aa74406a86314450 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -44,6 +44,8 @@ DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress");
DEFINE_FLAG(bool, truncating_left_shift, true,
"Optimize left shift to truncate if possible");
DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis.");
+DEFINE_FLAG(bool, trace_integer_ir_selection, false,
+ "Print integer IR selection optimization pass.");
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, source_lines);
DECLARE_FLAG(bool, trace_type_check_elimination);
@@ -608,10 +610,12 @@ void FlowGraphOptimizer::InsertConversion(Representation from,
const intptr_t deopt_id = (deopt_target != NULL) ?
deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
converted = new(I) UnboxIntegerInstr(use->CopyWithType(), deopt_id);
-
} else if ((from == kUnboxedMint) && (to == kTagged)) {
converted = new(I) BoxIntegerInstr(use->CopyWithType());
-
+ } else if ((from == kUnboxedMint) && (to == kUnboxedUint32)) {
+ converted = new(I) UnboxedIntConverterInstr(from, to, use->CopyWithType());
+ } else if ((from == kUnboxedUint32) && (to == kUnboxedMint)) {
+ converted = new(I) UnboxedIntConverterInstr(from, to, use->CopyWithType());
} else if (from == kUnboxedMint && to == kUnboxedDouble) {
ASSERT(CanUnboxDouble());
// Convert by boxing/unboxing.
@@ -4512,7 +4516,290 @@ bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
}
-// Range analysis for smi values.
+// Replaces Mint IL instructions with Uint32 IL instructions
+// when possible. Uses output of RangeAnalysis.
+class IntegerInstructionSelector : public ValueObject {
+ public:
+ explicit IntegerInstructionSelector(FlowGraph* flow_graph)
+ : flow_graph_(flow_graph),
+ isolate_(NULL) {
+ ASSERT(flow_graph_ != NULL);
+ isolate_ = flow_graph_->isolate();
+ ASSERT(isolate_ != NULL);
+ selected_uint32_defs_ =
+ new(I) BitVector(flow_graph_->current_ssa_temp_index());
+ }
+
+ void Select();
+
+ private:
+ bool IsPotentialUint32Definition(Definition* def);
+ void FindPotentialUint32Definitions();
+ bool IsUint32NarrowingDefinition(Definition* def);
+ void FindUint32NarrowingDefinitions();
+ bool AllUsesAreUint32Narrowing(Value* list_head);
+ bool CanBecomeUint32(Definition* def);
+ void Propagate();
+ Definition* ConstructReplacementFor(Definition* def);
+ void ReplaceInstructions();
+
+ Isolate* isolate() const { return isolate_; }
+
+ GrowableArray<Definition*> potential_uint32_defs_;
+ BitVector* selected_uint32_defs_;
+
+ FlowGraph* flow_graph_;
+ Isolate* isolate_;
+};
+
+
+void IntegerInstructionSelector::Select() {
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("---- starting integer ir selection -------\n");
+ }
+ FindPotentialUint32Definitions();
+ FindUint32NarrowingDefinitions();
+ Propagate();
+ ReplaceInstructions();
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("---- after integer ir selection -------\n");
+ FlowGraphPrinter printer(*flow_graph_);
+ printer.PrintBlocks();
+ }
+}
+
+
+bool IntegerInstructionSelector::IsPotentialUint32Definition(Definition* def) {
+ // TODO(johnmccutchan): Consider Smi operations, to avoid unnecessary tagging
+ // & untagged of intermediate results.
+ // TODO(johnmccutchan): Consider phis.
+ return def->IsBoxInteger() || // BoxMint.
+ def->IsUnboxInteger() || // UnboxMint.
+ def->IsBinaryMintOp() ||
+ def->IsShiftMintOp() ||
+ def->IsUnaryMintOp();
+}
+
+
+void IntegerInstructionSelector::FindPotentialUint32Definitions() {
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("++++ Finding potential Uint32 definitions:\n");
+ }
+
+ for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
+ !block_it.Done();
+ block_it.Advance()) {
+ BlockEntryInstr* block = block_it.Current();
+
+ for (ForwardInstructionIterator instr_it(block);
+ !instr_it.Done();
+ instr_it.Advance()) {
+ Instruction* current = instr_it.Current();
+ Definition* defn = current->AsDefinition();
+ if ((defn != NULL) && (defn->ssa_temp_index() != -1)) {
+ if (IsPotentialUint32Definition(defn)) {
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("Adding %s\n", current->ToCString());
+ }
+ potential_uint32_defs_.Add(defn);
+ }
+ }
+ }
+ }
+}
+
+
+// BinaryMintOp masks and stores into unsigned typed arrays that truncate the
+// value into a Uint32 range.
+bool IntegerInstructionSelector::IsUint32NarrowingDefinition(Definition* def) {
+ if (def->IsBinaryMintOp()) {
+ BinaryMintOpInstr* op = def->AsBinaryMintOp();
+ // Must be a mask operation.
+ if (op->op_kind() != Token::kBIT_AND) {
+ return false;
+ }
+ Range* range = op->range();
+ if ((range == NULL) ||
+ !range->IsWithin(0, static_cast<int64_t>(kMaxUint32))) {
+ return false;
+ }
+ return true;
+ }
+ // TODO(johnmccutchan): Add typed array stores.
+ return false;
+}
+
+
+void IntegerInstructionSelector::FindUint32NarrowingDefinitions() {
+ ASSERT(selected_uint32_defs_ != NULL);
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("++++ Selecting Uint32 definitions:\n");
+ OS::Print("++++ Initial set:\n");
+ }
+ for (intptr_t i = 0; i < potential_uint32_defs_.length(); i++) {
+ Definition* defn = potential_uint32_defs_[i];
+ if (IsUint32NarrowingDefinition(defn)) {
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("Adding %s\n", defn->ToCString());
+ }
+ selected_uint32_defs_->Add(defn->ssa_temp_index());
+ }
+ }
+}
+
+
+bool IntegerInstructionSelector::AllUsesAreUint32Narrowing(Value* list_head) {
+ for (Value::Iterator it(list_head);
+ !it.Done();
+ it.Advance()) {
+ Value* use = it.Current();
+ Definition* defn = use->instruction()->AsDefinition();
+ if ((defn == NULL) ||
+ (defn->ssa_temp_index() == -1) ||
+ !selected_uint32_defs_->Contains(defn->ssa_temp_index())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool IntegerInstructionSelector::CanBecomeUint32(Definition* def) {
+ ASSERT(IsPotentialUint32Definition(def));
+ if (def->IsBoxInteger()) {
+ // If a BoxInteger's input is a candidate, the box is a candidate.
+ BoxIntegerInstr* box = def->AsBoxInteger();
+ Definition* box_input = box->value()->definition();
+ return selected_uint32_defs_->Contains(box_input->ssa_temp_index());
+ }
+ // A right shift with an input outside of Uint32 range cannot be converted
+ // because we need the high bits.
+ if (def->IsShiftMintOp()) {
+ ShiftMintOpInstr* op = def->AsShiftMintOp();
+ if (op->op_kind() == Token::kSHR) {
+ Definition* shift_input = op->left()->definition();
+ ASSERT(shift_input != NULL);
+ Range* range = shift_input->range();
+ if ((range == NULL) ||
+ !range->IsWithin(0, static_cast<int64_t>(kMaxUint32))) {
+ return false;
+ }
+ }
+ }
+ if (!def->HasUses()) {
+ // No uses, skip.
+ return false;
+ }
+ return AllUsesAreUint32Narrowing(def->input_use_list()) &&
+ AllUsesAreUint32Narrowing(def->env_use_list());
+}
+
+
+void IntegerInstructionSelector::Propagate() {
+ ASSERT(selected_uint32_defs_ != NULL);
+ bool changed = true;
+ intptr_t iteration = 0;
+ while (changed) {
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("+++ Iteration: %" Pd "\n", iteration++);
+ }
+ changed = false;
+ for (intptr_t i = 0; i < potential_uint32_defs_.length(); i++) {
+ Definition* defn = potential_uint32_defs_[i];
+ if (selected_uint32_defs_->Contains(defn->ssa_temp_index())) {
+ // Already marked as a candidate, skip.
+ continue;
+ }
+ if (defn->IsConstant()) {
+ // Skip constants.
+ continue;
+ }
+ if (CanBecomeUint32(defn)) {
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("Adding %s\n", defn->ToCString());
+ }
+ // Found a new candidate.
+ selected_uint32_defs_->Add(defn->ssa_temp_index());
+ // Haven't reached fixed point yet.
+ changed = true;
+ }
+ }
+ }
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("Reached fixed point\n");
+ }
+}
+
+
+Definition* IntegerInstructionSelector::ConstructReplacementFor(
+ Definition* def) {
+ // Should only see mint definitions.
+ ASSERT(IsPotentialUint32Definition(def));
+ // Should not see constant instructions.
+ ASSERT(!def->IsConstant());
+ if (def->IsBinaryMintOp()) {
+ BinaryMintOpInstr* op = def->AsBinaryMintOp();
+ Token::Kind op_kind = op->op_kind();
+ Value* left = op->left()->CopyWithType();
+ Value* right = op->right()->CopyWithType();
+ intptr_t deopt_id = op->DeoptimizationTarget();
+ return new(I) BinaryUint32OpInstr(op_kind, left, right, deopt_id);
+ } else if (def->IsBoxInteger()) {
+ BoxIntegerInstr* box = def->AsBoxInteger();
+ Value* value = box->value()->CopyWithType();
+ return new(I) BoxUint32Instr(value);
+ } else if (def->IsUnboxInteger()) {
+ UnboxIntegerInstr* unbox = def->AsUnboxInteger();
+ Value* value = unbox->value()->CopyWithType();
+ intptr_t deopt_id = unbox->deopt_id();
+ return new(I) UnboxUint32Instr(value, deopt_id);
+ } else if (def->IsUnaryMintOp()) {
+ UnaryMintOpInstr* op = def->AsUnaryMintOp();
+ Token::Kind op_kind = op->op_kind();
+ Value* value = op->value()->CopyWithType();
+ intptr_t deopt_id = op->DeoptimizationTarget();
+ return new(I) UnaryUint32OpInstr(op_kind, value, deopt_id);
+ } else if (def->IsShiftMintOp()) {
+ ShiftMintOpInstr* op = def->AsShiftMintOp();
+ Token::Kind op_kind = op->op_kind();
+ Value* left = op->left()->CopyWithType();
+ Value* right = op->right()->CopyWithType();
+ intptr_t deopt_id = op->DeoptimizationTarget();
+ return new(I) ShiftUint32OpInstr(op_kind, left, right, deopt_id);
+ }
+ UNREACHABLE();
+ return NULL;
+}
+
+
+void IntegerInstructionSelector::ReplaceInstructions() {
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("++++ Replacing instructions:\n");
+ }
+ for (intptr_t i = 0; i < potential_uint32_defs_.length(); i++) {
+ Definition* defn = potential_uint32_defs_[i];
+ if (!selected_uint32_defs_->Contains(defn->ssa_temp_index())) {
+ // Not a candidate.
+ continue;
+ }
+ Definition* replacement = ConstructReplacementFor(defn);
+ ASSERT(replacement != NULL);
+ if (FLAG_trace_integer_ir_selection) {
+ OS::Print("Replacing %s with %s\n", defn->ToCString(),
+ replacement->ToCString());
+ }
+ defn->ReplaceWith(replacement, NULL);
+ ASSERT(flow_graph_->VerifyUseLists());
+ }
+}
+
+void FlowGraphOptimizer::SelectIntegerInstructions() {
+ IntegerInstructionSelector iis(flow_graph_);
+ iis.Select();
+}
+
+
+// Range analysis for integer values.
class RangeAnalysis : public ValueObject {
public:
explicit RangeAnalysis(FlowGraph* flow_graph)
@@ -4621,6 +4908,8 @@ void RangeAnalysis::Analyze() {
CollectValues();
InsertConstraints();
InferRanges();
+ IntegerInstructionSelector iis(flow_graph_);
+ iis.Select();
RemoveConstraints();
}
@@ -8484,6 +8773,24 @@ void ConstantPropagator::HandleBinaryOp(Definition* instr,
}
+void ConstantPropagator::TruncateInteger(Definition* defn, int64_t mask) {
+ const Object& value = defn->constant_value();
+ if (IsNonConstant(value)) {
+ return;
+ }
+ ASSERT(IsConstant(value));
+ if (!value.IsInteger()) {
+ return;
+ }
+ const Integer& value_int = Integer::Cast(value);
+ int64_t truncated = value_int.AsInt64Value() & mask;
+ Instance& result = Integer::ZoneHandle(I, Integer::New(truncated));
+ result = result.CheckAndCanonicalize(NULL);
+ ASSERT(!result.IsNull());
+ SetValue(defn, result);
+}
+
+
void ConstantPropagator::VisitBinarySmiOp(BinarySmiOpInstr* instr) {
HandleBinaryOp(instr, instr->op_kind(), *instr->left(), *instr->right());
}
@@ -8916,6 +9223,42 @@ void ConstantPropagator::VisitBoxInt32x4(BoxInt32x4Instr* instr) {
}
+void ConstantPropagator::VisitBoxUint32(BoxUint32Instr* instr) {
+ // TODO(kmillikin): Handle box operation.
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitUnboxUint32(UnboxUint32Instr* instr) {
+ // TODO(kmillikin): Handle unbox operation.
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitUnboxedIntConverter(
+ UnboxedIntConverterInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitBinaryUint32Op(BinaryUint32OpInstr* instr) {
+ HandleBinaryOp(instr, instr->op_kind(), *instr->left(), *instr->right());
+ TruncateInteger(instr, static_cast<int64_t>(0xFFFFFFFF));
+}
+
+
+void ConstantPropagator::VisitShiftUint32Op(ShiftUint32OpInstr* instr) {
+ HandleBinaryOp(instr, instr->op_kind(), *instr->left(), *instr->right());
+ TruncateInteger(instr, static_cast<int64_t>(0xFFFFFFFF));
+}
+
+
+void ConstantPropagator::VisitUnaryUint32Op(UnaryUint32OpInstr* instr) {
+ // TODO(kmillikin): Handle unary operations.
+ SetValue(instr, non_constant_);
+}
+
+
void ConstantPropagator::Analyze() {
GraphEntryInstr* entry = graph_->graph_entry();
reachable_->Add(entry->preorder_number());
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698