summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/code_generator_riscv64.cc140
1 files changed, 120 insertions, 20 deletions
diff --git a/compiler/optimizing/code_generator_riscv64.cc b/compiler/optimizing/code_generator_riscv64.cc
index c7468bf961..9125da3565 100644
--- a/compiler/optimizing/code_generator_riscv64.cc
+++ b/compiler/optimizing/code_generator_riscv64.cc
@@ -377,13 +377,121 @@ void InstructionCodeGeneratorRISCV64::HandleCondition(HCondition* instruction) {
}
void LocationsBuilderRISCV64::HandleShift(HBinaryOperation* instruction) {
- UNUSED(instruction);
- LOG(FATAL) << "Unimplemented";
+ DCHECK(instruction->IsShl() ||
+ instruction->IsShr() ||
+ instruction->IsUShr() ||
+ instruction->IsRor());
+
+ LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
+ DataType::Type type = instruction->GetResultType();
+ switch (type) {
+ case DataType::Type::kInt32:
+ case DataType::Type::kInt64: {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unexpected shift type " << type;
+ UNREACHABLE();
+ }
}
void InstructionCodeGeneratorRISCV64::HandleShift(HBinaryOperation* instruction) {
- UNUSED(instruction);
- LOG(FATAL) << "Unimplemented";
+ DCHECK(instruction->IsShl() ||
+ instruction->IsShr() ||
+ instruction->IsUShr() ||
+ instruction->IsRor());
+ LocationSummary* locations = instruction->GetLocations();
+ DataType::Type type = instruction->GetType();
+
+ switch (type) {
+ case DataType::Type::kInt32:
+ case DataType::Type::kInt64: {
+ XRegister rd = locations->Out().AsRegister<XRegister>();
+ XRegister rs1 = locations->InAt(0).AsRegister<XRegister>();
+ Location rs2_location = locations->InAt(1);
+
+ if (rs2_location.IsConstant()) {
+ int64_t imm = CodeGenerator::GetInt64ValueOf(rs2_location.GetConstant());
+ uint32_t shamt =
+ imm & (type == DataType::Type::kInt32 ? kMaxIntShiftDistance : kMaxLongShiftDistance);
+
+ if (shamt == 0) {
+ if (rd != rs1) {
+ __ Mv(rd, rs1);
+ }
+ } else if (type == DataType::Type::kInt32) {
+ if (instruction->IsShl()) {
+ __ Slliw(rd, rs1, shamt);
+ } else if (instruction->IsShr()) {
+ __ Sraiw(rd, rs1, shamt);
+ } else if (instruction->IsUShr()) {
+ __ Srliw(rd, rs1, shamt);
+ } else {
+ ScratchRegisterScope srs(GetAssembler());
+ XRegister tmp = srs.AllocateXRegister();
+ __ Srliw(tmp, rs1, shamt);
+ __ Slliw(rd, rs1, 32 - shamt);
+ __ Or(rd, rd, tmp);
+ }
+ } else {
+ if (instruction->IsShl()) {
+ __ Slli(rd, rs1, shamt);
+ } else if (instruction->IsShr()) {
+ __ Srai(rd, rs1, shamt);
+ } else if (instruction->IsUShr()) {
+ __ Srli(rd, rs1, shamt);
+ } else {
+ ScratchRegisterScope srs(GetAssembler());
+ XRegister tmp = srs.AllocateXRegister();
+ __ Srli(tmp, rs1, shamt);
+ __ Slli(rd, rs1, 64 - shamt);
+ __ Or(rd, rd, tmp);
+ }
+ }
+ } else {
+ XRegister rs2 = rs2_location.AsRegister<XRegister>();
+ if (type == DataType::Type::kInt32) {
+ if (instruction->IsShl()) {
+ __ Sllw(rd, rs1, rs2);
+ } else if (instruction->IsShr()) {
+ __ Sraw(rd, rs1, rs2);
+ } else if (instruction->IsUShr()) {
+ __ Srlw(rd, rs1, rs2);
+ } else {
+ ScratchRegisterScope srs(GetAssembler());
+ XRegister tmp = srs.AllocateXRegister();
+ XRegister tmp2 = srs.AllocateXRegister();
+ __ Srlw(tmp, rs1, rs2);
+ __ Sub(tmp2, Zero, rs2); // tmp2 = -rs; we can use this instead of `32 - rs`
+ __ Sllw(rd, rs1, tmp2); // because only low 5 bits are used for SLLW.
+ __ Or(rd, rd, tmp);
+ }
+ } else {
+ if (instruction->IsShl()) {
+ __ Sll(rd, rs1, rs2);
+ } else if (instruction->IsShr()) {
+ __ Sra(rd, rs1, rs2);
+ } else if (instruction->IsUShr()) {
+ __ Srl(rd, rs1, rs2);
+ } else {
+ ScratchRegisterScope srs(GetAssembler());
+ XRegister tmp = srs.AllocateXRegister();
+ XRegister tmp2 = srs.AllocateXRegister();
+ __ Srl(tmp, rs1, rs2);
+ __ Sub(tmp2, Zero, rs2); // tmp2 = -rs; we can use this instead of `64 - rs`
+ __ Sll(rd, rs1, tmp2); // because only low 6 bits are used for SLL.
+ __ Or(rd, rd, tmp);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unexpected shift operation type " << type;
+ }
}
void LocationsBuilderRISCV64::HandleFieldSet(HInstruction* instruction,
@@ -1168,33 +1276,27 @@ void InstructionCodeGeneratorRISCV64::VisitReturnVoid(HReturnVoid* instruction)
}
void LocationsBuilderRISCV64::VisitRor(HRor* instruction) {
- UNUSED(instruction);
- LOG(FATAL) << "Unimplemented";
+ HandleShift(instruction);
}
void InstructionCodeGeneratorRISCV64::VisitRor(HRor* instruction) {
- UNUSED(instruction);
- LOG(FATAL) << "Unimplemented";
+ HandleShift(instruction);
}
void LocationsBuilderRISCV64::VisitShl(HShl* instruction) {
- UNUSED(instruction);
- LOG(FATAL) << "Unimplemented";
+ HandleShift(instruction);
}
void InstructionCodeGeneratorRISCV64::VisitShl(HShl* instruction) {
- UNUSED(instruction);
- LOG(FATAL) << "Unimplemented";
+ HandleShift(instruction);
}
void LocationsBuilderRISCV64::VisitShr(HShr* instruction) {
- UNUSED(instruction);
- LOG(FATAL) << "Unimplemented";
+ HandleShift(instruction);
}
void InstructionCodeGeneratorRISCV64::VisitShr(HShr* instruction) {
- UNUSED(instruction);
- LOG(FATAL) << "Unimplemented";
+ HandleShift(instruction);
}
void LocationsBuilderRISCV64::VisitStaticFieldGet(HStaticFieldGet* instruction) {
@@ -1336,13 +1438,11 @@ void InstructionCodeGeneratorRISCV64::VisitTypeConversion(HTypeConversion* instr
}
void LocationsBuilderRISCV64::VisitUShr(HUShr* instruction) {
- UNUSED(instruction);
- LOG(FATAL) << "Unimplemented";
+ HandleShift(instruction);
}
void InstructionCodeGeneratorRISCV64::VisitUShr(HUShr* instruction) {
- UNUSED(instruction);
- LOG(FATAL) << "Unimplemented";
+ HandleShift(instruction);
}
void LocationsBuilderRISCV64::VisitXor(HXor* instruction) {