ART: Implement HSelect
This patch adds a new HIR instruction to Optimizing. HSelect returns
one of two inputs based on the outcome of a condition.
This is only initial implementation which:
- defines the new instruction,
- repurposes BooleanSimplifier to emit it,
- extends InstructionSimplifier to statically resolve it,
- updates existing code and tests accordingly.
Code generators currently emit fallback if/then/else code and will be
updated in follow-up CLs to use platform-specific conditional moves
when possible.
Change-Id: Ib61b17146487ebe6b55350c2b589f0b971dcaaee
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 2b81dba..894ee07 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1285,11 +1285,9 @@
}
void CodeGeneratorARM::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
- if (Primitive::Is64BitType(dst_type)) {
- Move64(dst, src);
- } else {
- Move32(dst, src);
- }
+ HParallelMove move(GetGraph()->GetArena());
+ move.AddMove(src, dst, dst_type, nullptr);
+ GetMoveResolver()->EmitNativeCode(&move);
}
void CodeGeneratorARM::AddLocationAsTemp(Location location, LocationSummary* locations) {
@@ -1612,6 +1610,32 @@
/* false_target */ nullptr);
}
+void LocationsBuilderARM::VisitSelect(HSelect* select) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
+ if (Primitive::IsFloatingPointType(select->GetType())) {
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::RequiresFpuRegister());
+ } else {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ }
+ if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
+ locations->SetInAt(2, Location::RequiresRegister());
+ }
+ locations->SetOut(Location::SameAsFirstInput());
+}
+
+void InstructionCodeGeneratorARM::VisitSelect(HSelect* select) {
+ LocationSummary* locations = select->GetLocations();
+ Label false_target;
+ GenerateTestAndBranch(select,
+ /* condition_input_index */ 2,
+ /* true_target */ nullptr,
+ &false_target);
+ codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
+ __ Bind(&false_target);
+}
+
void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
new (GetGraph()->GetArena()) LocationSummary(info);
}
@@ -4973,6 +4997,8 @@
if (source.IsRegister()) {
if (destination.IsRegister()) {
__ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>());
+ } else if (destination.IsFpuRegister()) {
+ __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>());
} else {
DCHECK(destination.IsStackSlot());
__ StoreToOffset(kStoreWord, source.AsRegister<Register>(),
@@ -4990,7 +5016,9 @@
__ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex());
}
} else if (source.IsFpuRegister()) {
- if (destination.IsFpuRegister()) {
+ if (destination.IsRegister()) {
+ __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>());
+ } else if (destination.IsFpuRegister()) {
__ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>());
} else {
DCHECK(destination.IsStackSlot());
@@ -5014,6 +5042,10 @@
if (destination.IsRegisterPair()) {
__ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
__ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
+ } else if (destination.IsFpuRegisterPair()) {
+ __ vmovdrr(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
+ source.AsRegisterPairLow<Register>(),
+ source.AsRegisterPairHigh<Register>());
} else {
DCHECK(destination.IsDoubleStackSlot()) << destination;
DCHECK(ExpectedPairLayout(source));
@@ -5021,7 +5053,11 @@
kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex());
}
} else if (source.IsFpuRegisterPair()) {
- if (destination.IsFpuRegisterPair()) {
+ if (destination.IsRegisterPair()) {
+ __ vmovrrd(destination.AsRegisterPairLow<Register>(),
+ destination.AsRegisterPairHigh<Register>(),
+ FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
+ } else if (destination.IsFpuRegisterPair()) {
__ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()),
FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()));
} else {