diff options
-rw-r--r-- | compiler/optimizing/code_generator_riscv64.cc | 314 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_riscv64.h | 12 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 1 |
3 files changed, 172 insertions, 155 deletions
diff --git a/compiler/optimizing/code_generator_riscv64.cc b/compiler/optimizing/code_generator_riscv64.cc index 9ece9bc1f2..658afadc7f 100644 --- a/compiler/optimizing/code_generator_riscv64.cc +++ b/compiler/optimizing/code_generator_riscv64.cc @@ -70,19 +70,11 @@ static constexpr FRegister kFpuCalleeSaves[] = { #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kRiscv64PointerSize, x).Int32Value() Location RegisterOrZeroBitPatternLocation(HInstruction* instruction) { - DCHECK(!DataType::IsFloatingPointType(instruction->GetType())); return IsZeroBitPattern(instruction) ? Location::ConstantLocation(instruction) : Location::RequiresRegister(); } -Location FpuRegisterOrZeroBitPatternLocation(HInstruction* instruction) { - DCHECK(DataType::IsFloatingPointType(instruction->GetType())); - return IsZeroBitPattern(instruction) - ? Location::ConstantLocation(instruction) - : Location::RequiresFpuRegister(); -} - XRegister InputXRegisterOrZero(Location location) { if (location.IsConstant()) { DCHECK(location.GetConstant()->IsZeroBitPattern()); @@ -862,11 +854,6 @@ inline void InstructionCodeGeneratorRISCV64::FMv( FpUnOp<FRegister, &Riscv64Assembler::FMvS, &Riscv64Assembler::FMvD>(rd, rs1, type); } -inline void InstructionCodeGeneratorRISCV64::FMvX( - XRegister rd, FRegister rs1, DataType::Type type) { - FpUnOp<XRegister, &Riscv64Assembler::FMvXW, &Riscv64Assembler::FMvXD>(rd, rs1, type); -} - inline void InstructionCodeGeneratorRISCV64::FClass( XRegister rd, FRegister rs1, DataType::Type type) { FpUnOp<XRegister, &Riscv64Assembler::FClassS, &Riscv64Assembler::FClassD>(rd, rs1, type); @@ -1505,19 +1492,11 @@ void InstructionCodeGeneratorRISCV64::GenerateDivRemIntegral(HBinaryOperation* i void InstructionCodeGeneratorRISCV64::GenerateIntLongCondition(IfCondition cond, LocationSummary* locations) { XRegister rd = locations->Out().AsRegister<XRegister>(); - GenerateIntLongCondition(cond, locations, rd, /*to_all_bits=*/ false); -} - -void InstructionCodeGeneratorRISCV64::GenerateIntLongCondition(IfCondition cond, - LocationSummary* locations, - XRegister rd, - bool to_all_bits) { XRegister rs1 = locations->InAt(0).AsRegister<XRegister>(); Location rs2_location = locations->InAt(1); bool use_imm = rs2_location.IsConstant(); int64_t imm = use_imm ? CodeGenerator::GetInt64ValueOf(rs2_location.GetConstant()) : 0; XRegister rs2 = use_imm ? kNoXRegister : rs2_location.AsRegister<XRegister>(); - bool reverse_condition = false; switch (cond) { case kCondEQ: case kCondNE: @@ -1542,8 +1521,10 @@ void InstructionCodeGeneratorRISCV64::GenerateIntLongCondition(IfCondition cond, } else { __ Slt(rd, rs1, rs2); } - // Calculate `rs1 >= rhs` as `!(rs1 < rhs)` since there's only the SLT but no SGE. - reverse_condition = (cond == kCondGE); + if (cond == kCondGE) { + // Calculate `rs1 >= rhs` as `!(rs1 < rhs)` since there's only the SLT but no SGE. + __ Xori(rd, rd, 1); + } break; case kCondLE: @@ -1555,9 +1536,11 @@ void InstructionCodeGeneratorRISCV64::GenerateIntLongCondition(IfCondition cond, } else { __ Slt(rd, rs2, rs1); } - // Calculate `rs1 > imm` as `!(rs1 < imm + 1)` and calculate - // `rs1 <= rs2` as `!(rs2 < rs1)` since there's only the SLT but no SGE. - reverse_condition = ((cond == kCondGT) == use_imm); + if ((cond == kCondGT) == use_imm) { + // Calculate `rs1 > imm` as `!(rs1 < imm + 1)` and calculate + // `rs1 <= rs2` as `!(rs2 < rs1)` since there's only the SLT but no SGE. + __ Xori(rd, rd, 1); + } break; case kCondB: @@ -1571,8 +1554,10 @@ void InstructionCodeGeneratorRISCV64::GenerateIntLongCondition(IfCondition cond, } else { __ Sltu(rd, rs1, rs2); } - // Calculate `rs1 AE rhs` as `!(rs1 B rhs)` since there's only the SLTU but no SGEU. - reverse_condition = (cond == kCondAE); + if (cond == kCondAE) { + // Calculate `rs1 AE rhs` as `!(rs1 B rhs)` since there's only the SLTU but no SGEU. + __ Xori(rd, rd, 1); + } break; case kCondBE: @@ -1587,23 +1572,13 @@ void InstructionCodeGeneratorRISCV64::GenerateIntLongCondition(IfCondition cond, } else { __ Sltu(rd, rs2, rs1); } - // Calculate `rs1 A imm` as `!(rs1 B imm + 1)` and calculate - // `rs1 BE rs2` as `!(rs2 B rs1)` since there's only the SLTU but no SGEU. - reverse_condition = ((cond == kCondA) == use_imm); + if ((cond == kCondA) == use_imm) { + // Calculate `rs1 A imm` as `!(rs1 B imm + 1)` and calculate + // `rs1 BE rs2` as `!(rs2 B rs1)` since there's only the SLTU but no SGEU. + __ Xori(rd, rd, 1); + } break; } - if (to_all_bits) { - // Store the result to all bits; in other words, "true" is represented by -1. - if (reverse_condition) { - __ Addi(rd, rd, -1); // 0 -> -1, 1 -> 0 - } else { - __ Neg(rd, rd); // 0 -> 0, 1 -> -1 - } - } else { - if (reverse_condition) { - __ Xori(rd, rd, 1); - } - } } void InstructionCodeGeneratorRISCV64::GenerateIntLongCompareAndBranch(IfCondition cond, @@ -1682,20 +1657,6 @@ void InstructionCodeGeneratorRISCV64::GenerateFpCondition(IfCondition cond, DataType::Type type, LocationSummary* locations, Riscv64Label* label) { - DCHECK_EQ(label != nullptr, locations->Out().IsInvalid()); - ScratchRegisterScope srs(GetAssembler()); - XRegister rd = - (label != nullptr) ? srs.AllocateXRegister() : locations->Out().AsRegister<XRegister>(); - GenerateFpCondition(cond, gt_bias, type, locations, label, rd, /*to_all_bits=*/ false); -} - -void InstructionCodeGeneratorRISCV64::GenerateFpCondition(IfCondition cond, - bool gt_bias, - DataType::Type type, - LocationSummary* locations, - Riscv64Label* label, - XRegister rd, - bool to_all_bits) { // RISCV-V FP compare instructions yield the following values: // l<r l=r l>r Unordered // FEQ l,r 0 1 0 0 @@ -1731,7 +1692,12 @@ void InstructionCodeGeneratorRISCV64::GenerateFpCondition(IfCondition cond, FRegister rs1 = locations->InAt(0).AsFpuRegister<FRegister>(); FRegister rs2 = locations->InAt(1).AsFpuRegister<FRegister>(); + DCHECK_EQ(label != nullptr, locations->Out().IsInvalid()); + ScratchRegisterScope srs(GetAssembler()); + XRegister rd = + (label != nullptr) ? srs.AllocateXRegister() : locations->Out().AsRegister<XRegister>(); bool reverse_condition = false; + switch (cond) { case kCondEQ: FEq(rd, rs1, rs2, type); @@ -1783,13 +1749,6 @@ void InstructionCodeGeneratorRISCV64::GenerateFpCondition(IfCondition cond, } else { __ Bnez(rd, label); } - } else if (to_all_bits) { - // Store the result to all bits; in other words, "true" is represented by -1. - if (reverse_condition) { - __ Addi(rd, rd, -1); // 0 -> -1, 1 -> 0 - } else { - __ Neg(rd, rd); // 0 -> 0, 1 -> -1 - } } else { if (reverse_condition) { __ Xori(rd, rd, 1); @@ -2407,9 +2366,12 @@ void InstructionCodeGeneratorRISCV64::HandleFieldSet(HInstruction* instruction, swap_src = srs.AllocateXRegister(); __ Mv(swap_src, value.AsRegister<XRegister>()); codegen_->PoisonHeapReference(swap_src); - } else if (DataType::IsFloatingPointType(type) && !value.IsConstant()) { + } else if (type == DataType::Type::kFloat64 && !value.IsConstant()) { + swap_src = srs.AllocateXRegister(); + __ FMvXD(swap_src, value.AsFpuRegister<FRegister>()); + } else if (type == DataType::Type::kFloat32 && !value.IsConstant()) { swap_src = srs.AllocateXRegister(); - FMvX(swap_src, value.AsFpuRegister<FRegister>(), type); + __ FMvXW(swap_src, value.AsFpuRegister<FRegister>()); } else { swap_src = InputXRegisterOrZero(value); } @@ -4789,9 +4751,15 @@ void InstructionCodeGeneratorRISCV64::VisitReturn(HReturn* instruction) { if (GetGraph()->IsCompilingOsr()) { // To simplify callers of an OSR method, we put a floating point return value // in both floating point and core return registers. - DataType::Type type = instruction->InputAt(0)->GetType(); - if (DataType::IsFloatingPointType(type)) { - FMvX(A0, FA0, type); + switch (instruction->InputAt(0)->GetType()) { + case DataType::Type::kFloat32: + __ FMvXW(A0, FA0); + break; + case DataType::Type::kFloat64: + __ FMvXD(A0, FA0); + break; + default: + break; } } codegen_->GenerateFrameExit(); @@ -4928,15 +4896,21 @@ void InstructionCodeGeneratorRISCV64::VisitUnresolvedStaticFieldSet( void LocationsBuilderRISCV64::VisitSelect(HSelect* instruction) { LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction); if (DataType::IsFloatingPointType(instruction->GetType())) { - locations->SetInAt(0, FpuRegisterOrZeroBitPatternLocation(instruction->GetFalseValue())); - locations->SetInAt(1, FpuRegisterOrZeroBitPatternLocation(instruction->GetTrueValue())); + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); - if (!locations->InAt(0).IsConstant() && !locations->InAt(1).IsConstant()) { - locations->AddTemp(Location::RequiresRegister()); - } } else { - locations->SetInAt(0, RegisterOrZeroBitPatternLocation(instruction->GetFalseValue())); - locations->SetInAt(1, RegisterOrZeroBitPatternLocation(instruction->GetTrueValue())); + HConstant* cst_true_value = instruction->GetTrueValue()->AsConstantOrNull(); + HConstant* cst_false_value = instruction->GetFalseValue()->AsConstantOrNull(); + bool is_true_value_constant = cst_true_value != nullptr; + bool is_false_value_constant = cst_false_value != nullptr; + bool true_value_in_register = !is_true_value_constant; + bool false_value_in_register = !is_false_value_constant; + + locations->SetInAt(1, true_value_in_register ? Location::RequiresRegister() + : Location::ConstantLocation(cst_true_value)); + locations->SetInAt(0, false_value_in_register ? Location::RequiresRegister() + : Location::ConstantLocation(cst_false_value)); locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); } @@ -4948,78 +4922,134 @@ void LocationsBuilderRISCV64::VisitSelect(HSelect* instruction) { void InstructionCodeGeneratorRISCV64::VisitSelect(HSelect* instruction) { LocationSummary* locations = instruction->GetLocations(); HCondition* cond = instruction->GetCondition()->AsCondition(); - ScratchRegisterScope srs(GetAssembler()); - XRegister tmp = srs.AllocateXRegister(); if (!IsBooleanValueOrMaterializedCondition(cond)) { - DataType::Type cond_type = cond->InputAt(0)->GetType(); - IfCondition if_cond = cond->GetCondition(); - if (DataType::IsFloatingPointType(cond_type)) { - GenerateFpCondition(if_cond, - cond->IsGtBias(), - cond_type, - cond->GetLocations(), - /*label=*/ nullptr, - tmp, - /*to_all_bits=*/ true); + if (DataType::IsFloatingPointType(cond->InputAt(0)->GetType())) { + // compare left and right + // ... + // beq/bne/... true_label + // FMv dst, false_value + // J done + // true_label: + // FMv dst, true_value + // done: + // FIXME(riscv64): The type of the select can differ from the type of the condition. + FRegister true_register = locations->InAt(0).AsRegister<FRegister>(); + FRegister false_register = locations->InAt(1).AsRegister<FRegister>(); + FRegister dst = locations->Out().AsRegister<FRegister>(); + Riscv64Label true_label; + Riscv64Label done_label; + DataType::Type type = cond->InputAt(0)->GetType(); + GenerateFpCondition( + cond->GetCondition(), cond->IsGtBias(), type, cond->GetLocations(), &true_label); + FMv(dst, false_register, type); + __ J(&done_label); + __ Bind(&true_label); + FMv(dst, true_register, type); + __ Bind(&done_label); } else { - GenerateIntLongCondition(if_cond, cond->GetLocations(), tmp, /*to_all_bits=*/ true); + // compare left and right + // ... + // beq/bne/... true_label + // mv dst, false_register/LoadConst64 dst, false_constant + // J done + // true_label: + // mv dst, true_register/LoadConst64 dst, false_constant + // done + Riscv64Label true_label; + Riscv64Label done_label; + Location true_location = locations->InAt(0); + Location false_location = locations->InAt(1); + XRegister dst = locations->Out().AsRegister<XRegister>(); + + GenerateIntLongCompareAndBranch(cond->GetCondition(), cond->GetLocations(), &true_label); + if (false_location.IsConstant()) { + __ LoadConst64(dst, codegen_->GetInt64ValueOf(false_location.GetConstant()->AsConstant())); + } else { + __ Mv(dst, locations->InAt(1).AsRegister<XRegister>()); + } + __ J(&done_label); + + __ Bind(&true_label); + if (true_location.IsConstant()) { + __ LoadConst64(dst, codegen_->GetInt64ValueOf(true_location.GetConstant()->AsConstant())); + } else { + __ Mv(dst, locations->InAt(0).AsRegister<XRegister>()); + } + __ Bind(&done_label); } } else { - // TODO(riscv64): Remove the normalizing SNEZ when we can ensure that booleans - // have only values 0 and 1. b/279302742 - __ Snez(tmp, locations->InAt(2).AsRegister<XRegister>()); - __ Neg(tmp, tmp); - } - - XRegister true_reg, false_reg, xor_reg, out_reg; - DataType::Type type = instruction->GetType(); - if (DataType::IsFloatingPointType(type)) { - if (locations->InAt(0).IsConstant()) { - DCHECK(locations->InAt(0).GetConstant()->IsZeroBitPattern()); - false_reg = Zero; + XRegister cond_register = locations->InAt(2).AsRegister<XRegister>(); + + if (DataType::IsFloatingPointType(instruction->GetType())) { + // fmv.x.d/w tmp0, true_value + // fmv.x.d/w tmp1, false_value + // neg tmp2, cond + // xor tmp3, tmp0, tmp1 + // and tmp3, tmp3, tmp2 + // xor tmp2, tmp0, tmp3 + // fmv.d/w.x fd, tmp2 + FRegister true_register = locations->InAt(0).AsRegister<FRegister>(); + FRegister false_register = locations->InAt(1).AsRegister<FRegister>(); + FRegister dst = locations->Out().AsRegister<FRegister>(); + ScratchRegisterScope srs(GetAssembler()); + // FIXME(riscv64): We have only two scratch registers. + XRegister tmp0 = srs.AllocateXRegister(); + XRegister tmp1 = srs.AllocateXRegister(); + XRegister tmp2 = srs.AllocateXRegister(); + XRegister tmp3 = srs.AllocateXRegister(); + if (DataType::Is64BitType(instruction->GetType())) { + __ FMvXD(tmp0, true_register); + } else { + __ FMvXW(tmp0, true_register); + } + if (DataType::Is64BitType(instruction->GetType())) { + __ FMvXD(tmp1, false_register); + } else { + __ FMvXW(tmp1, false_register); + } + __ Neg(tmp2, cond_register); + __ Xor(tmp3, tmp0, tmp1); + __ And(tmp3, tmp3, tmp2); + __ Xor(tmp2, tmp0, tmp3); + if (DataType::Is64BitType(instruction->GetType())) { + __ FMvDX(dst, tmp2); + } else { + __ FMvWX(dst, tmp2); + } } else { - false_reg = srs.AllocateXRegister(); - FMvX(false_reg, locations->InAt(0).AsFpuRegister<FRegister>(), type); + // li rs1, true_value, if needed + // li rs2, false_value, if needed + // neg tmp1, cond + // xor tmp2, rs1, rs2 + // and tmp2, tmp2, tmp1 + // xor rd, rs1, tmp2 + Location true_location = locations->InAt(0); + Location false_location = locations->InAt(1); + XRegister dst = locations->Out().AsRegister<XRegister>(); + ScratchRegisterScope srs(GetAssembler()); + XRegister true_register; + XRegister false_register; + XRegister tmp1 = srs.AllocateXRegister(); + XRegister tmp2 = srs.AllocateXRegister(); + if (true_location.IsConstant()) { + true_register = srs.AllocateXRegister(); + __ LoadConst64(true_register, + codegen_->GetInt64ValueOf(true_location.GetConstant()->AsConstant())); + } else { + true_register = locations->InAt(0).AsRegister<XRegister>(); + } + if (false_location.IsConstant()) { + false_register = srs.AllocateXRegister(); + __ LoadConst64(false_register, + codegen_->GetInt64ValueOf(false_location.GetConstant()->AsConstant())); + } else { + false_register = locations->InAt(1).AsRegister<XRegister>(); + } + __ Neg(tmp1, cond_register); + __ Xor(tmp2, true_register, false_register); + __ And(tmp2, tmp2, tmp1); + __ Xor(dst, true_register, tmp2); } - if (locations->InAt(1).IsConstant()) { - DCHECK(locations->InAt(1).GetConstant()->IsZeroBitPattern()); - true_reg = Zero; - } else { - true_reg = (false_reg == Zero) ? srs.AllocateXRegister() - : locations->GetTemp(0).AsRegister<XRegister>(); - FMvX(true_reg, locations->InAt(1).AsFpuRegister<FRegister>(), type); - } - // We can clobber the "true value" with the XOR result. - // Note: The XOR is not emitted if `true_reg == Zero`, see below. - xor_reg = true_reg; - out_reg = tmp; - } else { - false_reg = InputXRegisterOrZero(locations->InAt(0)); - true_reg = InputXRegisterOrZero(locations->InAt(1)); - xor_reg = srs.AllocateXRegister(); - out_reg = locations->Out().AsRegister<XRegister>(); - } - - // We use a branch-free implementation of `HSelect`. - // With `tmp` initialized to 0 for `false` and -1 for `true`: - // xor xor_reg, false_reg, true_reg - // and tmp, tmp, xor_reg - // xor out_reg, tmp, false_reg - if (false_reg == Zero) { - xor_reg = true_reg; - } else if (true_reg == Zero) { - xor_reg = false_reg; - } else { - DCHECK_NE(xor_reg, Zero); - __ Xor(xor_reg, false_reg, true_reg); - } - __ And(tmp, tmp, xor_reg); - __ Xor(out_reg, tmp, false_reg); - - if (type == DataType::Type::kFloat64) { - __ FMvDX(locations->Out().AsFpuRegister<FRegister>(), out_reg); - } else if (type == DataType::Type::kFloat32) { - __ FMvWX(locations->Out().AsFpuRegister<FRegister>(), out_reg); } } diff --git a/compiler/optimizing/code_generator_riscv64.h b/compiler/optimizing/code_generator_riscv64.h index cd58c0e465..b547317904 100644 --- a/compiler/optimizing/code_generator_riscv64.h +++ b/compiler/optimizing/code_generator_riscv64.h @@ -473,10 +473,6 @@ class InstructionCodeGeneratorRISCV64 : public InstructionCodeGenerator { void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); void GenerateDivRemIntegral(HBinaryOperation* instruction); void GenerateIntLongCondition(IfCondition cond, LocationSummary* locations); - void GenerateIntLongCondition(IfCondition cond, - LocationSummary* locations, - XRegister rd, - bool to_all_bits); void GenerateIntLongCompareAndBranch(IfCondition cond, LocationSummary* locations, Riscv64Label* label); @@ -485,13 +481,6 @@ class InstructionCodeGeneratorRISCV64 : public InstructionCodeGenerator { DataType::Type type, LocationSummary* locations, Riscv64Label* label = nullptr); - void GenerateFpCondition(IfCondition cond, - bool gt_bias, - DataType::Type type, - LocationSummary* locations, - Riscv64Label* label, - XRegister rd, - bool to_all_bits); void GenerateMethodEntryExitHook(HInstruction* instruction); void HandleGoto(HInstruction* got, HBasicBlock* successor); void GenPackedSwitchWithCompares(XRegister adjusted, @@ -527,7 +516,6 @@ class InstructionCodeGeneratorRISCV64 : public InstructionCodeGenerator { void FAbs(FRegister rd, FRegister rs1, DataType::Type type); void FNeg(FRegister rd, FRegister rs1, DataType::Type type); void FMv(FRegister rd, FRegister rs1, DataType::Type type); - void FMvX(XRegister rd, FRegister rs1, DataType::Type type); void FClass(XRegister rd, FRegister rs1, DataType::Type type); void Load(Location out, XRegister rs1, int32_t offset, DataType::Type type); diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index bc0a66f7db..0fea53c247 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -770,7 +770,6 @@ static bool CanAssembleGraphForRiscv64(HGraph* graph) { case HInstruction::kExit: case HInstruction::kGoto: case HInstruction::kPackedSwitch: - case HInstruction::kSelect: case HInstruction::kTryBoundary: case HInstruction::kClearException: case HInstruction::kLoadException: |