Ensure the graph is correctly typed.
We used to be forgiving because of HIntConstant(0) also being
used for null. We now create a special HNullConstant for such uses.
Also, we need to run the dead phi elimination twice during ssa
building to ensure the correctness.
Change-Id: If479efa3680d3358800aebb1cca692fa2d94f6e5
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index bf3ed14..5b395c8 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -636,6 +636,8 @@
} else if (current->IsIntConstant()) {
int32_t value = current->AsIntConstant()->GetValue();
stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, value);
+ } else if (current->IsNullConstant()) {
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, 0);
} else {
DCHECK(current->IsFloatConstant());
int32_t value = bit_cast<float, int32_t>(current->AsFloatConstant()->GetValue());
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 0310877..f46a36d 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -245,6 +245,32 @@
return GetFrameSize() == (CallPushesPC() ? GetWordSize() : 0);
}
+ static int32_t GetInt32ValueOf(HConstant* constant) {
+ if (constant->IsIntConstant()) {
+ return constant->AsIntConstant()->GetValue();
+ } else if (constant->IsNullConstant()) {
+ return 0;
+ } else {
+ DCHECK(constant->IsFloatConstant());
+ return bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
+ }
+ }
+
+ static int64_t GetInt64ValueOf(HConstant* constant) {
+ if (constant->IsIntConstant()) {
+ return constant->AsIntConstant()->GetValue();
+ } else if (constant->IsNullConstant()) {
+ return 0;
+ } else if (constant->IsFloatConstant()) {
+ return bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
+ } else if (constant->IsLongConstant()) {
+ return constant->AsLongConstant()->GetValue();
+ } else {
+ DCHECK(constant->IsDoubleConstant());
+ return bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue());
+ }
+ }
+
protected:
CodeGenerator(HGraph* graph,
size_t number_of_core_registers,
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 2a79f82..7b0231b 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -779,8 +779,8 @@
if (locations != nullptr && locations->Out().IsConstant()) {
HConstant* const_to_move = locations->Out().GetConstant();
- if (const_to_move->IsIntConstant()) {
- int32_t value = const_to_move->AsIntConstant()->GetValue();
+ if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
+ int32_t value = GetInt32ValueOf(const_to_move);
if (location.IsRegister()) {
__ LoadImmediate(location.AsRegister<Register>(), value);
} else {
@@ -947,8 +947,8 @@
__ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
} else {
DCHECK(locations->InAt(1).IsConstant());
- int32_t value =
- locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+ HConstant* constant = locations->InAt(1).GetConstant();
+ int32_t value = CodeGenerator::GetInt32ValueOf(constant);
ShifterOperand operand;
if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
__ cmp(left, operand);
@@ -1109,6 +1109,17 @@
UNUSED(constant);
}
+void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
+ // Will be generated at use site.
+ UNUSED(constant);
+}
+
void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
@@ -3399,9 +3410,9 @@
}
} else {
DCHECK(source.IsConstant()) << source;
- HInstruction* constant = source.GetConstant();
- if (constant->IsIntConstant()) {
- int32_t value = constant->AsIntConstant()->GetValue();
+ HConstant* constant = source.GetConstant();
+ if (constant->IsIntConstant() || constant->IsNullConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(constant);
if (destination.IsRegister()) {
__ LoadImmediate(destination.AsRegister<Register>(), value);
} else {
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index ec716a4..8220207 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -491,18 +491,21 @@
Primitive::Type type = instruction->GetType();
DCHECK_NE(type, Primitive::kPrimVoid);
- if (instruction->IsIntConstant() || instruction->IsLongConstant()) {
- int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue()
- : instruction->AsLongConstant()->GetValue();
+ if (instruction->IsIntConstant()
+ || instruction->IsLongConstant()
+ || instruction->IsNullConstant()) {
+ int64_t value = GetInt64ValueOf(instruction->AsConstant());
if (location.IsRegister()) {
Register dst = RegisterFrom(location, type);
- DCHECK((instruction->IsIntConstant() && dst.Is32Bits()) ||
+ DCHECK(((instruction->IsIntConstant() || instruction->IsNullConstant()) && dst.Is32Bits()) ||
(instruction->IsLongConstant() && dst.Is64Bits()));
__ Mov(dst, value);
} else {
DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
UseScratchRegisterScope temps(GetVIXLAssembler());
- Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
+ Register temp = (instruction->IsIntConstant() || instruction->IsNullConstant())
+ ? temps.AcquireW()
+ : temps.AcquireX();
__ Mov(temp, value);
__ Str(temp, StackOperandFrom(location));
}
@@ -643,10 +646,12 @@
}
void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
- if (constant->IsIntConstant() || constant->IsLongConstant()) {
- __ Mov(Register(destination),
- constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
- : constant->AsLongConstant()->GetValue());
+ if (constant->IsIntConstant()) {
+ __ Mov(Register(destination), constant->AsIntConstant()->GetValue());
+ } else if (constant->IsLongConstant()) {
+ __ Mov(Register(destination), constant->AsLongConstant()->GetValue());
+ } else if (constant->IsNullConstant()) {
+ __ Mov(Register(destination), 0);
} else if (constant->IsFloatConstant()) {
__ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
} else {
@@ -660,6 +665,8 @@
DCHECK(constant.IsConstant());
HConstant* cst = constant.GetConstant();
return (cst->IsIntConstant() && type == Primitive::kPrimInt) ||
+ // Null is mapped to a core W register, which we associate with kPrimInt.
+ (cst->IsNullConstant() && type == Primitive::kPrimInt) ||
(cst->IsLongConstant() && type == Primitive::kPrimLong) ||
(cst->IsFloatConstant() && type == Primitive::kPrimFloat) ||
(cst->IsDoubleConstant() && type == Primitive::kPrimDouble);
@@ -680,7 +687,9 @@
if (unspecified_type) {
HConstant* src_cst = source.IsConstant() ? source.GetConstant() : nullptr;
if (source.IsStackSlot() ||
- (src_cst != nullptr && (src_cst->IsIntConstant() || src_cst->IsFloatConstant()))) {
+ (src_cst != nullptr && (src_cst->IsIntConstant()
+ || src_cst->IsFloatConstant()
+ || src_cst->IsNullConstant()))) {
// For stack slots and 32bit constants, a 64bit type is appropriate.
type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
} else {
@@ -726,7 +735,7 @@
UseScratchRegisterScope temps(GetVIXLAssembler());
HConstant* src_cst = source.GetConstant();
CPURegister temp;
- if (src_cst->IsIntConstant()) {
+ if (src_cst->IsIntConstant() || src_cst->IsNullConstant()) {
temp = temps.AcquireW();
} else if (src_cst->IsLongConstant()) {
temp = temps.AcquireX();
@@ -1770,6 +1779,16 @@
UNUSED(constant);
}
+void LocationsBuilderARM64::VisitNullConstant(HNullConstant* constant) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
+ locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorARM64::VisitNullConstant(HNullConstant* constant) {
+ // Will be generated at use site.
+ UNUSED(constant);
+}
+
void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 1a95f41..8a73eb4 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -602,13 +602,7 @@
__ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
} else if (source.IsConstant()) {
HConstant* constant = source.GetConstant();
- int32_t value;
- if (constant->IsIntConstant()) {
- value = constant->AsIntConstant()->GetValue();
- } else {
- DCHECK(constant->IsFloatConstant());
- value = bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
- }
+ int32_t value = GetInt32ValueOf(constant);
__ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
} else {
DCHECK(source.IsStackSlot());
@@ -674,8 +668,8 @@
if (locations != nullptr && locations->Out().IsConstant()) {
HConstant* const_to_move = locations->Out().GetConstant();
- if (const_to_move->IsIntConstant()) {
- Immediate imm(const_to_move->AsIntConstant()->GetValue());
+ if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
+ Immediate imm(GetInt32ValueOf(const_to_move));
if (location.IsRegister()) {
__ movl(location.AsRegister<Register>(), imm);
} else if (location.IsStackSlot()) {
@@ -925,7 +919,7 @@
locations->InAt(1).AsRegister<Register>());
} else if (locations->InAt(1).IsConstant()) {
HConstant* instruction = locations->InAt(1).GetConstant();
- Immediate imm(instruction->AsIntConstant()->GetValue());
+ Immediate imm(CodeGenerator::GetInt32ValueOf(instruction));
__ cmpl(locations->InAt(0).AsRegister<Register>(), imm);
} else {
__ cmpl(locations->InAt(0).AsRegister<Register>(),
@@ -994,6 +988,17 @@
UNUSED(constant);
}
+void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
+ // Will be generated at use site.
+ UNUSED(constant);
+}
+
void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
@@ -3500,8 +3505,8 @@
}
} else if (source.IsConstant()) {
HConstant* constant = source.GetConstant();
- if (constant->IsIntConstant()) {
- Immediate imm(constant->AsIntConstant()->GetValue());
+ if (constant->IsIntConstant() || constant->IsNullConstant()) {
+ Immediate imm(CodeGenerator::GetInt32ValueOf(constant));
if (destination.IsRegister()) {
__ movl(destination.AsRegister<Register>(), imm);
} else {
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 88f1753..f7ec67f 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -607,13 +607,7 @@
source.AsFpuRegister<XmmRegister>());
} else if (source.IsConstant()) {
HConstant* constant = source.GetConstant();
- int32_t value;
- if (constant->IsFloatConstant()) {
- value = bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
- } else {
- DCHECK(constant->IsIntConstant());
- value = constant->AsIntConstant()->GetValue();
- }
+ int32_t value = GetInt32ValueOf(constant);
__ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
} else {
DCHECK(source.IsStackSlot()) << source;
@@ -657,8 +651,8 @@
if (locations != nullptr && locations->Out().IsConstant()) {
HConstant* const_to_move = locations->Out().GetConstant();
- if (const_to_move->IsIntConstant()) {
- Immediate imm(const_to_move->AsIntConstant()->GetValue());
+ if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
+ Immediate imm(GetInt32ValueOf(const_to_move));
if (location.IsRegister()) {
__ movl(location.AsRegister<CpuRegister>(), imm);
} else if (location.IsStackSlot()) {
@@ -814,7 +808,7 @@
if (rhs.IsRegister()) {
__ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
} else if (rhs.IsConstant()) {
- int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue();
+ int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
if (constant == 0) {
__ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
} else {
@@ -1034,6 +1028,17 @@
UNUSED(constant);
}
+void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
+ // Will be generated at use site.
+ UNUSED(constant);
+}
+
void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
@@ -3263,8 +3268,8 @@
}
} else if (source.IsConstant()) {
HConstant* constant = source.GetConstant();
- if (constant->IsIntConstant()) {
- int32_t value = constant->AsIntConstant()->GetValue();
+ if (constant->IsIntConstant() || constant->IsNullConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(constant);
if (destination.IsRegister()) {
if (value == 0) {
__ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 4ebb136..ef10428 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -285,6 +285,19 @@
}
}
+static Primitive::Type PrimitiveKind(Primitive::Type type) {
+ switch (type) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimInt:
+ return Primitive::kPrimInt;
+ default:
+ return type;
+ }
+}
+
void SSAChecker::VisitPhi(HPhi* phi) {
VisitInstruction(phi);
@@ -321,18 +334,17 @@
}
}
}
-}
-
-static Primitive::Type PrimitiveKind(Primitive::Type type) {
- switch (type) {
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimShort:
- case Primitive::kPrimChar:
- case Primitive::kPrimInt:
- return Primitive::kPrimInt;
- default:
- return type;
+ // Ensure that the inputs have the same primitive kind as the phi.
+ for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
+ HInstruction* input = phi->InputAt(i);
+ if (PrimitiveKind(input->GetType()) != PrimitiveKind(phi->GetType())) {
+ AddError(StringPrintf(
+ "Input %d at index %zu of phi %d from block %d does not have the "
+ "same type as the phi: %s versus %s",
+ input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
+ Primitive::PrettyDescriptor(input->GetType()),
+ Primitive::PrettyDescriptor(phi->GetType())));
+ }
}
}
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 835bca6..c592737 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -184,6 +184,10 @@
output_ << " " << instruction->GetValue();
}
+ void VisitPhi(HPhi* phi) OVERRIDE {
+ output_ << " " << phi->GetRegNumber();
+ }
+
void PrintInstruction(HInstruction* instruction) {
output_ << instruction->DebugName();
instruction->Accept(this);
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index cd36598..4a574b0 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -292,6 +292,15 @@
return true;
}
+HNullConstant* HGraph::GetNullConstant() {
+ if (cached_null_constant_ == nullptr) {
+ cached_null_constant_ = new (arena_) HNullConstant();
+ entry_block_->InsertInstructionBefore(cached_null_constant_,
+ entry_block_->GetLastInstruction());
+ }
+ return cached_null_constant_;
+}
+
void HLoopInformation::Add(HBasicBlock* block) {
blocks_.SetBit(block->GetBlockId());
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index fd88e42..cebde3b 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -34,6 +34,7 @@
class HIntConstant;
class HInvoke;
class HGraphVisitor;
+class HNullConstant;
class HPhi;
class HSuspendCheck;
class LiveInterval;
@@ -194,6 +195,8 @@
return reverse_post_order_;
}
+ HNullConstant* GetNullConstant();
+
private:
HBasicBlock* FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const;
void VisitBlockForDominatorTree(HBasicBlock* block,
@@ -233,6 +236,9 @@
// The current id to assign to a newly added instruction. See HInstruction.id_.
int32_t current_instruction_id_;
+ // Cached null constant that might be created when building SSA form.
+ HNullConstant* cached_null_constant_;
+
ART_FRIEND_TEST(GraphTest, IfSuccessorSimpleJoinBlock1);
DISALLOW_COPY_AND_ASSIGN(HGraph);
};
@@ -610,6 +616,7 @@
M(NewInstance, Instruction) \
M(Not, UnaryOperation) \
M(NotEqual, Condition) \
+ M(NullConstant, Instruction) \
M(NullCheck, Instruction) \
M(Or, BinaryOperation) \
M(ParallelMove, Instruction) \
@@ -914,7 +921,10 @@
// Does not apply for all instructions, but having this at top level greatly
// simplifies the null check elimination.
- virtual bool CanBeNull() const { return true; }
+ virtual bool CanBeNull() const {
+ DCHECK_EQ(GetType(), Primitive::kPrimNot) << "CanBeNull only applies to reference types";
+ return true;
+ }
virtual bool CanDoImplicitNullCheck() const { return false; }
@@ -1675,6 +1685,22 @@
DISALLOW_COPY_AND_ASSIGN(HDoubleConstant);
};
+class HNullConstant : public HConstant {
+ public:
+ HNullConstant() : HConstant(Primitive::kPrimNot) {}
+
+ bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ return true;
+ }
+
+ size_t ComputeHashCode() const OVERRIDE { return 0; }
+
+ DECLARE_INSTRUCTION(NullConstant);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HNullConstant);
+};
+
// Constants of the type int. Those can be from Dex instructions, or
// synthesized (for example with the if-eqz instruction).
class HIntConstant : public HConstant {
diff --git a/compiler/optimizing/primitive_type_propagation.cc b/compiler/optimizing/primitive_type_propagation.cc
index 7e274f6..fe23fcf 100644
--- a/compiler/optimizing/primitive_type_propagation.cc
+++ b/compiler/optimizing/primitive_type_propagation.cc
@@ -40,6 +40,7 @@
// Re-compute and update the type of the instruction. Returns
// whether or not the type was changed.
bool PrimitiveTypePropagation::UpdateType(HPhi* phi) {
+ DCHECK(phi->IsLive());
Primitive::Type existing = phi->GetType();
Primitive::Type new_type = existing;
@@ -49,15 +50,20 @@
}
phi->SetType(new_type);
- if (new_type == Primitive::kPrimDouble || new_type == Primitive::kPrimFloat) {
+ if (new_type == Primitive::kPrimDouble
+ || new_type == Primitive::kPrimFloat
+ || new_type == Primitive::kPrimNot) {
// If the phi is of floating point type, we need to update its inputs to that
// type. For inputs that are phis, we need to recompute their types.
for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
HInstruction* input = phi->InputAt(i);
if (input->GetType() != new_type) {
- HInstruction* equivalent = SsaBuilder::GetFloatOrDoubleEquivalent(phi, input, new_type);
+ HInstruction* equivalent = (new_type == Primitive::kPrimNot)
+ ? SsaBuilder::GetReferenceTypeEquivalent(input)
+ : SsaBuilder::GetFloatOrDoubleEquivalent(phi, input, new_type);
phi->ReplaceInput(equivalent, i);
if (equivalent->IsPhi()) {
+ equivalent->AsPhi()->SetLive();
AddToWorklist(equivalent->AsPhi());
}
}
@@ -78,15 +84,9 @@
if (block->IsLoopHeader()) {
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
HPhi* phi = it.Current()->AsPhi();
- // Set the initial type for the phi. Use the non back edge input for reaching
- // a fixed point faster.
- Primitive::Type phi_type = phi->GetType();
- // We merge with the existing type, that has been set by the SSA builder.
- DCHECK(phi_type == Primitive::kPrimVoid
- || phi_type == Primitive::kPrimFloat
- || phi_type == Primitive::kPrimDouble);
- phi->SetType(MergeTypes(phi->InputAt(0)->GetType(), phi->GetType()));
- AddToWorklist(phi);
+ if (phi->IsLive()) {
+ AddToWorklist(phi);
+ }
}
} else {
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
@@ -95,7 +95,10 @@
// doing a reverse post-order visit, therefore either the phi users are
// non-loop phi and will be visited later in the visit, or are loop-phis,
// and they are already in the work list.
- UpdateType(it.Current()->AsPhi());
+ HPhi* phi = it.Current()->AsPhi();
+ if (phi->IsLive()) {
+ UpdateType(phi);
+ }
}
}
}
@@ -110,13 +113,14 @@
}
void PrimitiveTypePropagation::AddToWorklist(HPhi* instruction) {
+ DCHECK(instruction->IsLive());
worklist_.Add(instruction);
}
void PrimitiveTypePropagation::AddDependentInstructionsToWorklist(HPhi* instruction) {
for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
HPhi* phi = it.Current()->GetUser()->AsPhi();
- if (phi != nullptr) {
+ if (phi != nullptr && phi->IsLive()) {
AddToWorklist(phi);
}
}
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 24e6837..4f17b6f 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -18,10 +18,6 @@
namespace art {
-// TODO: Only do the analysis on reference types. We currently have to handle
-// the `null` constant, that is represented as a `HIntConstant` and therefore
-// has the Primitive::kPrimInt type.
-
void ReferenceTypePropagation::Run() {
// Compute null status for instructions.
@@ -54,8 +50,10 @@
// Set the initial type for the phi. Use the non back edge input for reaching
// a fixed point faster.
HPhi* phi = it.Current()->AsPhi();
- AddToWorklist(phi);
- phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
+ if (phi->GetType() == Primitive::kPrimNot) {
+ AddToWorklist(phi);
+ phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
+ }
}
} else {
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
@@ -64,7 +62,10 @@
// doing a reverse post-order visit, therefore either the phi users are
// non-loop phi and will be visited later in the visit, or are loop-phis,
// and they are already in the work list.
- UpdateNullability(it.Current()->AsPhi());
+ HPhi* phi = it.Current()->AsPhi();
+ if (phi->GetType() == Primitive::kPrimNot) {
+ UpdateNullability(phi);
+ }
}
}
}
@@ -79,6 +80,7 @@
}
void ReferenceTypePropagation::AddToWorklist(HPhi* instruction) {
+ DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot);
worklist_.Add(instruction);
}
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index c9a21aa..3dc7505 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -42,20 +42,33 @@
}
}
- // 3) Remove dead phis. This will remove phis that are only used by environments:
+ // 3) Mark dead phis. This will mark phis that are only used by environments:
// at the DEX level, the type of these phis does not need to be consistent, but
// our code generator will complain if the inputs of a phi do not have the same
- // type (modulo the special case of `null`).
- SsaDeadPhiElimination dead_phis(GetGraph());
- dead_phis.Run();
+ // type. The marking allows the type propagation to know which phis it needs
+ // to handle. We mark but do not eliminate: the elimination will be done in
+ // step 5).
+ {
+ SsaDeadPhiElimination dead_phis(GetGraph());
+ dead_phis.MarkDeadPhis();
+ }
// 4) Propagate types of phis. At this point, phis are typed void in the general
- // case, or float or double when we created a floating-point equivalent. So we
+ // case, or float/double/reference when we created an equivalent phi. So we
// need to propagate the types across phis to give them a correct type.
PrimitiveTypePropagation type_propagation(GetGraph());
type_propagation.Run();
- // 5) Clear locals.
+ // 5) Step 4) changes inputs of phis which may lead to dead phis again. We re-run
+ // the algorithm and this time elimimates them.
+ // TODO: Make this work with debug info and reference liveness. We currently
+ // eagerly remove phis used in environments.
+ {
+ SsaDeadPhiElimination dead_phis(GetGraph());
+ dead_phis.Run();
+ }
+
+ // 6) Clear locals.
// TODO: Move this to a dead code eliminator phase.
for (HInstructionIterator it(GetGraph()->GetEntryBlock()->GetInstructions());
!it.Done();
@@ -185,15 +198,24 @@
/**
* Because of Dex format, we might end up having the same phi being
- * used for non floating point operations and floating point operations. Because
- * we want the graph to be correctly typed (and thereafter avoid moves between
+ * used for non floating point operations and floating point / reference operations.
+ * Because we want the graph to be correctly typed (and thereafter avoid moves between
* floating point registers and core registers), we need to create a copy of the
- * phi with a floating point type.
+ * phi with a floating point / reference type.
*/
-static HPhi* GetFloatOrDoubleEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
- // We place the floating point phi next to this phi.
+static HPhi* GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
+ // We place the floating point /reference phi next to this phi.
HInstruction* next = phi->GetNext();
- if (next == nullptr || (next->AsPhi()->GetRegNumber() != phi->GetRegNumber())) {
+ if (next != nullptr
+ && next->AsPhi()->GetRegNumber() == phi->GetRegNumber()
+ && next->GetType() != type) {
+ // Move to the next phi to see if it is the one we are looking for.
+ next = next->GetNext();
+ }
+
+ if (next == nullptr
+ || (next->AsPhi()->GetRegNumber() != phi->GetRegNumber())
+ || (next->GetType() != type)) {
ArenaAllocator* allocator = phi->GetBlock()->GetGraph()->GetArena();
HPhi* new_phi = new (allocator) HPhi(allocator, phi->GetRegNumber(), phi->InputCount(), type);
for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
@@ -223,7 +245,7 @@
} else if (value->IsIntConstant()) {
return GetFloatEquivalent(value->AsIntConstant());
} else if (value->IsPhi()) {
- return GetFloatOrDoubleEquivalentOfPhi(value->AsPhi(), type);
+ return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), type);
} else {
// For other instructions, we assume the verifier has checked that the dex format is correctly
// typed and the value in a dex register will not be used for both floating point and
@@ -234,12 +256,25 @@
}
}
+HInstruction* SsaBuilder::GetReferenceTypeEquivalent(HInstruction* value) {
+ if (value->IsIntConstant()) {
+ DCHECK_EQ(value->AsIntConstant()->GetValue(), 0);
+ return value->GetBlock()->GetGraph()->GetNullConstant();
+ } else {
+ DCHECK(value->IsPhi());
+ return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), Primitive::kPrimNot);
+ }
+}
+
void SsaBuilder::VisitLoadLocal(HLoadLocal* load) {
HInstruction* value = current_locals_->GetInstructionAt(load->GetLocal()->GetRegNumber());
- if (load->GetType() != value->GetType()
- && (load->GetType() == Primitive::kPrimFloat || load->GetType() == Primitive::kPrimDouble)) {
- // If the operation requests a specific type, we make sure its input is of that type.
- value = GetFloatOrDoubleEquivalent(load, value, load->GetType());
+ // If the operation requests a specific type, we make sure its input is of that type.
+ if (load->GetType() != value->GetType()) {
+ if (load->GetType() == Primitive::kPrimFloat || load->GetType() == Primitive::kPrimDouble) {
+ value = GetFloatOrDoubleEquivalent(load, value, load->GetType());
+ } else if (load->GetType() == Primitive::kPrimNot) {
+ value = GetReferenceTypeEquivalent(value);
+ }
}
load->ReplaceWith(value);
load->GetBlock()->RemoveInstruction(load);
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 2eec87b..148e959 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -58,6 +58,8 @@
HInstruction* instruction,
Primitive::Type type);
+ static HInstruction* GetReferenceTypeEquivalent(HInstruction* instruction);
+
private:
// Locals for the current block being visited.
HEnvironment* current_locals_;
diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc
index fd30c1b..f66a1c8 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -19,6 +19,11 @@
namespace art {
void SsaDeadPhiElimination::Run() {
+ MarkDeadPhis();
+ EliminateDeadPhis();
+}
+
+void SsaDeadPhiElimination::MarkDeadPhis() {
// Add to the worklist phis referenced by non-phi instructions.
for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
HBasicBlock* block = it.Current();
@@ -49,7 +54,9 @@
}
}
}
+}
+void SsaDeadPhiElimination::EliminateDeadPhis() {
// Remove phis that are not live. Visit in post order so that phis
// that are not inputs of loop phis can be removed when they have
// no users left (dead phis might use dead phis).
diff --git a/compiler/optimizing/ssa_phi_elimination.h b/compiler/optimizing/ssa_phi_elimination.h
index b789971..88a5279 100644
--- a/compiler/optimizing/ssa_phi_elimination.h
+++ b/compiler/optimizing/ssa_phi_elimination.h
@@ -34,6 +34,9 @@
void Run() OVERRIDE;
+ void MarkDeadPhis();
+ void EliminateDeadPhis();
+
private:
GrowableArray<HPhi*> worklist_;