diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 261 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 5 |
2 files changed, 189 insertions, 77 deletions
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 6795488769..86e5f7c5f4 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1126,30 +1126,43 @@ void CodeGeneratorX86_64::Move(Location destination, Location source) { return; } if (destination.IsRegister()) { + CpuRegister dest = destination.AsRegister<CpuRegister>(); if (source.IsRegister()) { - __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>()); + __ movq(dest, source.AsRegister<CpuRegister>()); } else if (source.IsFpuRegister()) { - __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>()); + __ movd(dest, source.AsFpuRegister<XmmRegister>()); } else if (source.IsStackSlot()) { - __ movl(destination.AsRegister<CpuRegister>(), - Address(CpuRegister(RSP), source.GetStackIndex())); + __ movl(dest, Address(CpuRegister(RSP), source.GetStackIndex())); + } else if (source.IsConstant()) { + HConstant* constant = source.GetConstant(); + if (constant->IsLongConstant()) { + Load64BitValue(dest, constant->AsLongConstant()->GetValue()); + } else { + Load32BitValue(dest, GetInt32ValueOf(constant)); + } } else { DCHECK(source.IsDoubleStackSlot()); - __ movq(destination.AsRegister<CpuRegister>(), - Address(CpuRegister(RSP), source.GetStackIndex())); + __ movq(dest, Address(CpuRegister(RSP), source.GetStackIndex())); } } else if (destination.IsFpuRegister()) { + XmmRegister dest = destination.AsFpuRegister<XmmRegister>(); if (source.IsRegister()) { - __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>()); + __ movd(dest, source.AsRegister<CpuRegister>()); } else if (source.IsFpuRegister()) { - __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); + __ movaps(dest, source.AsFpuRegister<XmmRegister>()); + } else if (source.IsConstant()) { + HConstant* constant = source.GetConstant(); + int64_t value = CodeGenerator::GetInt64ValueOf(constant); + if (constant->IsFloatConstant()) { + Load32BitValue(dest, static_cast<int32_t>(value)); + } else { + Load64BitValue(dest, value); + } } else if (source.IsStackSlot()) { - __ movss(destination.AsFpuRegister<XmmRegister>(), - Address(CpuRegister(RSP), source.GetStackIndex())); + __ movss(dest, Address(CpuRegister(RSP), source.GetStackIndex())); } else { DCHECK(source.IsDoubleStackSlot()); - __ movsd(destination.AsFpuRegister<XmmRegister>(), - Address(CpuRegister(RSP), source.GetStackIndex())); + __ movsd(dest, Address(CpuRegister(RSP), source.GetStackIndex())); } } else if (destination.IsStackSlot()) { if (source.IsRegister()) { @@ -1345,22 +1358,34 @@ void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond, __ j(X86_64FPCondition(cond->GetCondition()), true_label); } -template<class LabelType> -void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* condition, - LabelType* true_target_in, - LabelType* false_target_in) { - // Generated branching requires both targets to be explicit. If either of the - // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead. - LabelType fallthrough_target; - LabelType* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in; - LabelType* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in; - +void InstructionCodeGeneratorX86_64::GenerateCompareTest(HCondition* condition) { LocationSummary* locations = condition->GetLocations(); + Location left = locations->InAt(0); Location right = locations->InAt(1); - Primitive::Type type = condition->InputAt(0)->GetType(); switch (type) { + case Primitive::kPrimBoolean: + case Primitive::kPrimByte: + case Primitive::kPrimChar: + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimNot: { + CpuRegister left_reg = left.AsRegister<CpuRegister>(); + if (right.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(right.GetConstant()); + if (value == 0) { + __ testl(left_reg, left_reg); + } else { + __ cmpl(left_reg, Immediate(value)); + } + } else if (right.IsStackSlot()) { + __ cmpl(left_reg, Address(CpuRegister(RSP), right.GetStackIndex())); + } else { + __ cmpl(left_reg, right.AsRegister<CpuRegister>()); + } + break; + } case Primitive::kPrimLong: { CpuRegister left_reg = left.AsRegister<CpuRegister>(); if (right.IsConstant()) { @@ -1380,7 +1405,6 @@ void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* co } else { __ cmpq(left_reg, right.AsRegister<CpuRegister>()); } - __ j(X86_64IntegerCondition(condition->GetCondition()), true_target); break; } case Primitive::kPrimFloat: { @@ -1395,7 +1419,6 @@ void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* co __ ucomiss(left.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), right.GetStackIndex())); } - GenerateFPJumps(condition, true_target, false_target); break; } case Primitive::kPrimDouble: { @@ -1410,6 +1433,38 @@ void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* co __ ucomisd(left.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), right.GetStackIndex())); } + break; + } + default: + LOG(FATAL) << "Unexpected condition type " << type; + } +} + +template<class LabelType> +void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* condition, + LabelType* true_target_in, + LabelType* false_target_in) { + // Generated branching requires both targets to be explicit. If either of the + // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead. + LabelType fallthrough_target; + LabelType* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in; + LabelType* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in; + + // Generate the comparison to set the CC. + GenerateCompareTest(condition); + + // Now generate the correct jump(s). + Primitive::Type type = condition->InputAt(0)->GetType(); + switch (type) { + case Primitive::kPrimLong: { + __ j(X86_64IntegerCondition(condition->GetCondition()), true_target); + break; + } + case Primitive::kPrimFloat: { + GenerateFPJumps(condition, true_target, false_target); + break; + } + case Primitive::kPrimDouble: { GenerateFPJumps(condition, true_target, false_target); break; } @@ -1564,14 +1619,37 @@ void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) { /* false_target */ nullptr); } +static bool SelectCanUseCMOV(HSelect* select) { + // There are no conditional move instructions for XMMs. + if (Primitive::IsFloatingPointType(select->GetType())) { + return false; + } + + // A FP condition doesn't generate the single CC that we need. + HInstruction* condition = select->GetCondition(); + if (condition->IsCondition() && + Primitive::IsFloatingPointType(condition->InputAt(0)->GetType())) { + return false; + } + + // We can generate a CMOV for this Select. + return true; +} + void LocationsBuilderX86_64::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()); + // Since we can't use CMOV, there is no need to force 'true' into a register. + locations->SetInAt(1, Location::Any()); } else { locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); + if (SelectCanUseCMOV(select)) { + locations->SetInAt(1, Location::RequiresRegister()); + } else { + // Since we can't use CMOV, there is no need to force 'true' into a register. + locations->SetInAt(1, Location::Any()); + } } if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) { locations->SetInAt(2, Location::RequiresRegister()); @@ -1581,13 +1659,52 @@ void LocationsBuilderX86_64::VisitSelect(HSelect* select) { void InstructionCodeGeneratorX86_64::VisitSelect(HSelect* select) { LocationSummary* locations = select->GetLocations(); - NearLabel false_target; - GenerateTestAndBranch<NearLabel>(select, - /* condition_input_index */ 2, - /* true_target */ nullptr, - &false_target); - codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType()); - __ Bind(&false_target); + if (SelectCanUseCMOV(select)) { + // If both the condition and the source types are integer, we can generate + // a CMOV to implement Select. + CpuRegister value_false = locations->InAt(0).AsRegister<CpuRegister>(); + CpuRegister value_true = locations->InAt(1).AsRegister<CpuRegister>(); + DCHECK(locations->InAt(0).Equals(locations->Out())); + + HInstruction* select_condition = select->GetCondition(); + Condition cond = kNotEqual; + + // Figure out how to test the 'condition'. + if (select_condition->IsCondition()) { + HCondition* condition = select_condition->AsCondition(); + if (!condition->IsEmittedAtUseSite()) { + // This was a previously materialized condition. + // Can we use the existing condition code? + if (AreEflagsSetFrom(condition, select)) { + // Materialization was the previous instruction. Condition codes are right. + cond = X86_64IntegerCondition(condition->GetCondition()); + } else { + // No, we have to recreate the condition code. + CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>(); + __ testl(cond_reg, cond_reg); + } + } else { + GenerateCompareTest(condition); + cond = X86_64IntegerCondition(condition->GetCondition()); + } + } else { + // Must be a boolean condition, which needs to be compared to 0. + CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>(); + __ testl(cond_reg, cond_reg); + } + + // If the condition is true, overwrite the output, which already contains false. + // Generate the correct sized CMOV. + __ cmov(cond, value_false, value_true, select->GetType() == Primitive::kPrimLong); + } else { + NearLabel false_target; + GenerateTestAndBranch<NearLabel>(select, + /* condition_input_index */ 2, + /* true_target */ nullptr, + &false_target); + codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType()); + __ Bind(&false_target); + } } void LocationsBuilderX86_64::VisitNativeDebugInfo(HNativeDebugInfo* info) { @@ -2750,11 +2867,7 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } else if (in.IsConstant()) { int32_t v = in.GetConstant()->AsIntConstant()->GetValue(); XmmRegister dest = out.AsFpuRegister<XmmRegister>(); - if (v == 0) { - __ xorps(dest, dest); - } else { - __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v))); - } + codegen_->Load32BitValue(dest, static_cast<float>(v)); } else { __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), in.GetStackIndex()), false); @@ -2768,11 +2881,7 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } else if (in.IsConstant()) { int64_t v = in.GetConstant()->AsLongConstant()->GetValue(); XmmRegister dest = out.AsFpuRegister<XmmRegister>(); - if (v == 0) { - __ xorps(dest, dest); - } else { - __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v))); - } + codegen_->Load64BitValue(dest, static_cast<double>(v)); } else { __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), in.GetStackIndex()), true); @@ -2786,11 +2895,7 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } else if (in.IsConstant()) { double v = in.GetConstant()->AsDoubleConstant()->GetValue(); XmmRegister dest = out.AsFpuRegister<XmmRegister>(); - if (bit_cast<int64_t, double>(v) == 0) { - __ xorps(dest, dest); - } else { - __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v))); - } + codegen_->Load32BitValue(dest, static_cast<float>(v)); } else { __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), in.GetStackIndex())); @@ -2817,11 +2922,7 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } else if (in.IsConstant()) { int32_t v = in.GetConstant()->AsIntConstant()->GetValue(); XmmRegister dest = out.AsFpuRegister<XmmRegister>(); - if (v == 0) { - __ xorpd(dest, dest); - } else { - __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v))); - } + codegen_->Load64BitValue(dest, static_cast<double>(v)); } else { __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), in.GetStackIndex()), false); @@ -2835,11 +2936,7 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } else if (in.IsConstant()) { int64_t v = in.GetConstant()->AsLongConstant()->GetValue(); XmmRegister dest = out.AsFpuRegister<XmmRegister>(); - if (v == 0) { - __ xorpd(dest, dest); - } else { - __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v))); - } + codegen_->Load64BitValue(dest, static_cast<double>(v)); } else { __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), in.GetStackIndex()), true); @@ -2853,11 +2950,7 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver } else if (in.IsConstant()) { float v = in.GetConstant()->AsFloatConstant()->GetValue(); XmmRegister dest = out.AsFpuRegister<XmmRegister>(); - if (bit_cast<int32_t, float>(v) == 0) { - __ xorpd(dest, dest); - } else { - __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v))); - } + codegen_->Load64BitValue(dest, static_cast<double>(v)); } else { __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), Address(CpuRegister(RSP), in.GetStackIndex())); @@ -5196,18 +5289,12 @@ void ParallelMoveResolverX86_64::EmitMove(size_t index) { } } else if (constant->IsFloatConstant()) { float fp_value = constant->AsFloatConstant()->GetValue(); - int32_t value = bit_cast<int32_t, float>(fp_value); if (destination.IsFpuRegister()) { XmmRegister dest = destination.AsFpuRegister<XmmRegister>(); - if (value == 0) { - // easy FP 0.0. - __ xorps(dest, dest); - } else { - __ movss(dest, codegen_->LiteralFloatAddress(fp_value)); - } + codegen_->Load32BitValue(dest, fp_value); } else { DCHECK(destination.IsStackSlot()) << destination; - Immediate imm(value); + Immediate imm(bit_cast<int32_t, float>(fp_value)); __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm); } } else { @@ -5216,11 +5303,7 @@ void ParallelMoveResolverX86_64::EmitMove(size_t index) { int64_t value = bit_cast<int64_t, double>(fp_value); if (destination.IsFpuRegister()) { XmmRegister dest = destination.AsFpuRegister<XmmRegister>(); - if (value == 0) { - __ xorpd(dest, dest); - } else { - __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value)); - } + codegen_->Load64BitValue(dest, fp_value); } else { DCHECK(destination.IsDoubleStackSlot()) << destination; codegen_->Store64BitValueToStack(destination, value); @@ -6467,6 +6550,30 @@ void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) { } } +void CodeGeneratorX86_64::Load32BitValue(XmmRegister dest, int32_t value) { + if (value == 0) { + __ xorps(dest, dest); + } else { + __ movss(dest, LiteralInt32Address(value)); + } +} + +void CodeGeneratorX86_64::Load64BitValue(XmmRegister dest, int64_t value) { + if (value == 0) { + __ xorpd(dest, dest); + } else { + __ movsd(dest, LiteralInt64Address(value)); + } +} + +void CodeGeneratorX86_64::Load32BitValue(XmmRegister dest, float value) { + Load32BitValue(dest, bit_cast<int32_t, float>(value)); +} + +void CodeGeneratorX86_64::Load64BitValue(XmmRegister dest, double value) { + Load64BitValue(dest, bit_cast<int64_t, double>(value)); +} + void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) { DCHECK(dest.IsDoubleStackSlot()); if (IsInt<32>(value)) { diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 318087eb9c..6aa08143dd 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -264,6 +264,7 @@ class InstructionCodeGeneratorX86_64 : public InstructionCodeGenerator { void GenerateExplicitNullCheck(HNullCheck* instruction); void PushOntoFPStack(Location source, uint32_t temp_offset, uint32_t stack_adjustment, bool is_float); + void GenerateCompareTest(HCondition* condition); template<class LabelType> void GenerateTestAndBranch(HInstruction* instruction, size_t condition_input_index, @@ -481,6 +482,10 @@ class CodeGeneratorX86_64 : public CodeGenerator { // Load a 32/64 bit value into a register in the most efficient manner. void Load32BitValue(CpuRegister dest, int32_t value); void Load64BitValue(CpuRegister dest, int64_t value); + void Load32BitValue(XmmRegister dest, int32_t value); + void Load64BitValue(XmmRegister dest, int64_t value); + void Load32BitValue(XmmRegister dest, float value); + void Load64BitValue(XmmRegister dest, double value); Address LiteralCaseTable(HPackedSwitch* switch_instr); |