summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/code_generator_riscv64.cc314
-rw-r--r--compiler/optimizing/code_generator_riscv64.h12
-rw-r--r--compiler/optimizing/optimizing_compiler.cc1
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: