diff options
author | Calin Juravle <calin@google.com> | 2014-11-18 23:06:35 +0000 |
---|---|---|
committer | Calin Juravle <calin@google.com> | 2014-11-24 16:06:55 +0000 |
commit | 9aec02fc5df5518c16f1e5a9b6cb198a192db973 (patch) | |
tree | fe924b37f395af1bb50f55ee6c87c66b727f00af /compiler/optimizing | |
parent | 20032e512c003a8f42735c4e1eca19c1472bb95e (diff) | |
download | art-9aec02fc5df5518c16f1e5a9b6cb198a192db973.tar.gz art-9aec02fc5df5518c16f1e5a9b6cb198a192db973.tar.bz2 art-9aec02fc5df5518c16f1e5a9b6cb198a192db973.zip |
[optimizing compiler] Add shifts
Added SHL, SHR, USHR for arm, x86, x86_64.
Change-Id: I971f594e270179457e6958acf1401ff7630df07e
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/builder.cc | 92 | ||||
-rw-r--r-- | compiler/optimizing/builder.h | 6 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 118 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 5 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 133 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.h | 5 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 101 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 59 |
10 files changed, 521 insertions, 2 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index be8631ad4..b26146069 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -305,6 +305,15 @@ void HGraphBuilder::Binop_23x(const Instruction& instruction, } template<typename T> +void HGraphBuilder::Binop_23x_shift(const Instruction& instruction, + Primitive::Type type) { + HInstruction* first = LoadLocal(instruction.VRegB(), type); + HInstruction* second = LoadLocal(instruction.VRegC(), Primitive::kPrimInt); + current_block_->AddInstruction(new (arena_) T(type, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +template<typename T> void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type) { HInstruction* first = LoadLocal(instruction.VRegA(), type); HInstruction* second = LoadLocal(instruction.VRegB(), type); @@ -313,6 +322,14 @@ void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type ty } template<typename T> +void HGraphBuilder::Binop_12x_shift(const Instruction& instruction, Primitive::Type type) { + HInstruction* first = LoadLocal(instruction.VRegA(), type); + HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt); + current_block_->AddInstruction(new (arena_) T(type, first, second)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +template<typename T> void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc) { @@ -1141,6 +1158,36 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::SHL_INT: { + Binop_23x_shift<HShl>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::SHL_LONG: { + Binop_23x_shift<HShl>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::SHR_INT: { + Binop_23x_shift<HShr>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::SHR_LONG: { + Binop_23x_shift<HShr>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::USHR_INT: { + Binop_23x_shift<HUShr>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::USHR_LONG: { + Binop_23x_shift<HUShr>(instruction, Primitive::kPrimLong); + break; + } + case Instruction::OR_INT: { Binop_23x<HOr>(instruction, Primitive::kPrimInt); break; @@ -1240,6 +1287,36 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::SHL_INT_2ADDR: { + Binop_12x_shift<HShl>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::SHL_LONG_2ADDR: { + Binop_12x_shift<HShl>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::SHR_INT_2ADDR: { + Binop_12x_shift<HShr>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::SHR_LONG_2ADDR: { + Binop_12x_shift<HShr>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::USHR_INT_2ADDR: { + Binop_12x_shift<HUShr>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::USHR_LONG_2ADDR: { + Binop_12x_shift<HUShr>(instruction, Primitive::kPrimLong); + break; + } + case Instruction::DIV_FLOAT_2ADDR: { Binop_12x<HDiv>(instruction, Primitive::kPrimFloat, dex_pc); break; @@ -1354,6 +1431,21 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::SHL_INT_LIT8: { + Binop_22b<HShl>(instruction, false); + break; + } + + case Instruction::SHR_INT_LIT8: { + Binop_22b<HShr>(instruction, false); + break; + } + + case Instruction::USHR_INT_LIT8: { + Binop_22b<HUShr>(instruction, false); + break; + } + case Instruction::NEW_INSTANCE: { current_block_->AddInstruction( new (arena_) HNewInstance(dex_pc, instruction.VRegB_21c())); diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 897bcece7..204005daa 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -105,12 +105,18 @@ class HGraphBuilder : public ValueObject { void Binop_23x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc); template<typename T> + void Binop_23x_shift(const Instruction& instruction, Primitive::Type type); + + template<typename T> void Binop_12x(const Instruction& instruction, Primitive::Type type); template<typename T> void Binop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc); template<typename T> + void Binop_12x_shift(const Instruction& instruction, Primitive::Type type); + + template<typename T> void Binop_22b(const Instruction& instruction, bool reverse); template<typename T> diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 1701ef5f0..a204e2149 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -2087,6 +2087,124 @@ void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) } } +void LocationsBuilderARM::HandleShift(HBinaryOperation* op) { + DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); + + LocationSummary::CallKind call_kind = op->GetResultType() == Primitive::kPrimLong + ? LocationSummary::kCall + : LocationSummary::kNoCall; + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(op, call_kind); + + switch (op->GetResultType()) { + case Primitive::kPrimInt: { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1))); + locations->SetOut(Location::RequiresRegister()); + break; + } + case Primitive::kPrimLong: { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); + locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); + // The runtime helper puts the output in R0,R2. + locations->SetOut(Location::RegisterPairLocation(R0, R2)); + break; + } + default: + LOG(FATAL) << "Unexpected operation type " << op->GetResultType(); + } +} + +void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) { + DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); + + LocationSummary* locations = op->GetLocations(); + Location out = locations->Out(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + + Primitive::Type type = op->GetResultType(); + switch (type) { + case Primitive::kPrimInt: { + Register out_reg = out.As<Register>(); + Register first_reg = first.As<Register>(); + // Arm doesn't mask the shift count so we need to do it ourselves. + if (second.IsRegister()) { + Register second_reg = second.As<Register>(); + __ and_(second_reg, second_reg, ShifterOperand(kMaxIntShiftValue)); + if (op->IsShl()) { + __ Lsl(out_reg, first_reg, second_reg); + } else if (op->IsShr()) { + __ Asr(out_reg, first_reg, second_reg); + } else { + __ Lsr(out_reg, first_reg, second_reg); + } + } else { + int32_t cst = second.GetConstant()->AsIntConstant()->GetValue(); + uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue); + if (shift_value == 0) { // arm does not support shifting with 0 immediate. + __ Mov(out_reg, first_reg); + } else if (op->IsShl()) { + __ Lsl(out_reg, first_reg, shift_value); + } else if (op->IsShr()) { + __ Asr(out_reg, first_reg, shift_value); + } else { + __ Lsr(out_reg, first_reg, shift_value); + } + } + break; + } + case Primitive::kPrimLong: { + // TODO: Inline the assembly instead of calling the runtime. + InvokeRuntimeCallingConvention calling_convention; + DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(2), second.As<Register>()); + DCHECK_EQ(R0, out.AsRegisterPairLow<Register>()); + DCHECK_EQ(R2, out.AsRegisterPairHigh<Register>()); + + int32_t entry_point_offset; + if (op->IsShl()) { + entry_point_offset = QUICK_ENTRY_POINT(pShlLong); + } else if (op->IsShr()) { + entry_point_offset = QUICK_ENTRY_POINT(pShrLong); + } else { + entry_point_offset = QUICK_ENTRY_POINT(pUshrLong); + } + __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset); + __ blx(LR); + break; + } + default: + LOG(FATAL) << "Unexpected operation type " << type; + } +} + +void LocationsBuilderARM::VisitShl(HShl* shl) { + HandleShift(shl); +} + +void InstructionCodeGeneratorARM::VisitShl(HShl* shl) { + HandleShift(shl); +} + +void LocationsBuilderARM::VisitShr(HShr* shr) { + HandleShift(shr); +} + +void InstructionCodeGeneratorARM::VisitShr(HShr* shr) { + HandleShift(shr); +} + +void LocationsBuilderARM::VisitUShr(HUShr* ushr) { + HandleShift(ushr); +} + +void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) { + HandleShift(ushr); +} + void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index c00fac1a3..226e635d0 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -109,6 +109,7 @@ class LocationsBuilderARM : public HGraphVisitor { private: void HandleInvoke(HInvoke* invoke); void HandleBitwiseOperation(HBinaryOperation* operation); + void HandleShift(HBinaryOperation* operation); CodeGeneratorARM* const codegen_; InvokeDexCallingConventionVisitor parameter_visitor_; @@ -136,6 +137,7 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeARM* slow_path, Register class_reg); void HandleBitwiseOperation(HBinaryOperation* operation); + void HandleShift(HBinaryOperation* operation); ArmAssembler* const assembler_; CodeGeneratorARM* const codegen_; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 82dced5e4..7a8b941c2 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -801,7 +801,10 @@ InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph, #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \ M(ParallelMove) \ - M(Rem) + M(Rem) \ + M(Shl) \ + M(Shr) \ + M(UShr) \ #define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 3c53cea0b..917b7dd2b 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -2129,6 +2129,139 @@ void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) } } +void LocationsBuilderX86::HandleShift(HBinaryOperation* op) { + DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); + + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall); + + switch (op->GetResultType()) { + case Primitive::kPrimInt: { + locations->SetInAt(0, Location::RequiresRegister()); + // The shift count needs to be in CL. + locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1))); + locations->SetOut(Location::SameAsFirstInput()); + break; + } + case Primitive::kPrimLong: { + locations->SetInAt(0, Location::RequiresRegister()); + // The shift count needs to be in CL. + locations->SetInAt(1, Location::RegisterLocation(ECX)); + locations->SetOut(Location::SameAsFirstInput()); + break; + } + default: + LOG(FATAL) << "Unexpected op type " << op->GetResultType(); + } +} + +void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) { + DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); + + LocationSummary* locations = op->GetLocations(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + DCHECK(first.Equals(locations->Out())); + + switch (op->GetResultType()) { + case Primitive::kPrimInt: { + Register first_reg = first.As<Register>(); + if (second.IsRegister()) { + Register second_reg = second.As<Register>(); + DCHECK_EQ(ECX, second_reg); + if (op->IsShl()) { + __ shll(first_reg, second_reg); + } else if (op->IsShr()) { + __ sarl(first_reg, second_reg); + } else { + __ shrl(first_reg, second_reg); + } + } else { + Immediate imm(second.GetConstant()->AsIntConstant()->GetValue()); + if (op->IsShl()) { + __ shll(first_reg, imm); + } else if (op->IsShr()) { + __ sarl(first_reg, imm); + } else { + __ shrl(first_reg, imm); + } + } + break; + } + case Primitive::kPrimLong: { + Register second_reg = second.As<Register>(); + DCHECK_EQ(ECX, second_reg); + if (op->IsShl()) { + GenerateShlLong(first, second_reg); + } else if (op->IsShr()) { + GenerateShrLong(first, second_reg); + } else { + GenerateUShrLong(first, second_reg); + } + break; + } + default: + LOG(FATAL) << "Unexpected op type " << op->GetResultType(); + } +} + +void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) { + Label done; + __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter); + __ shll(loc.AsRegisterPairLow<Register>(), shifter); + __ testl(shifter, Immediate(32)); + __ j(kEqual, &done); + __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>()); + __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0)); + __ Bind(&done); +} + +void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) { + Label done; + __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter); + __ sarl(loc.AsRegisterPairHigh<Register>(), shifter); + __ testl(shifter, Immediate(32)); + __ j(kEqual, &done); + __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>()); + __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31)); + __ Bind(&done); +} + +void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) { + Label done; + __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter); + __ shrl(loc.AsRegisterPairHigh<Register>(), shifter); + __ testl(shifter, Immediate(32)); + __ j(kEqual, &done); + __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>()); + __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0)); + __ Bind(&done); +} + +void LocationsBuilderX86::VisitShl(HShl* shl) { + HandleShift(shl); +} + +void InstructionCodeGeneratorX86::VisitShl(HShl* shl) { + HandleShift(shl); +} + +void LocationsBuilderX86::VisitShr(HShr* shr) { + HandleShift(shr); +} + +void InstructionCodeGeneratorX86::VisitShr(HShr* shr) { + HandleShift(shr); +} + +void LocationsBuilderX86::VisitUShr(HUShr* ushr) { + HandleShift(ushr); +} + +void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) { + HandleShift(ushr); +} + void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 0aff6cc49..aed06c04d 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -104,6 +104,7 @@ class LocationsBuilderX86 : public HGraphVisitor { private: void HandleBitwiseOperation(HBinaryOperation* instruction); void HandleInvoke(HInvoke* invoke); + void HandleShift(HBinaryOperation* instruction); CodeGeneratorX86* const codegen_; InvokeDexCallingConventionVisitor parameter_visitor_; @@ -132,6 +133,10 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor { void GenerateClassInitializationCheck(SlowPathCodeX86* slow_path, Register class_reg); void HandleBitwiseOperation(HBinaryOperation* instruction); void GenerateDivRemIntegral(HBinaryOperation* instruction); + void HandleShift(HBinaryOperation* instruction); + void GenerateShlLong(const Location& loc, Register shifter); + void GenerateShrLong(const Location& loc, Register shifter); + void GenerateUShrLong(const Location& loc, Register shifter); X86Assembler* const assembler_; CodeGeneratorX86* const codegen_; diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 97f5e5c7a..69f031aab 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -2026,6 +2026,107 @@ void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instructio } } +void LocationsBuilderX86_64::HandleShift(HBinaryOperation* op) { + DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); + + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall); + + switch (op->GetResultType()) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + locations->SetInAt(0, Location::RequiresRegister()); + // The shift count needs to be in CL. + locations->SetInAt(1, Location::ByteRegisterOrConstant(RCX, op->InputAt(1))); + locations->SetOut(Location::SameAsFirstInput()); + break; + } + default: + LOG(FATAL) << "Unexpected operation type " << op->GetResultType(); + } +} + +void InstructionCodeGeneratorX86_64::HandleShift(HBinaryOperation* op) { + DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); + + LocationSummary* locations = op->GetLocations(); + CpuRegister first_reg = locations->InAt(0).As<CpuRegister>(); + Location second = locations->InAt(1); + + switch (op->GetResultType()) { + case Primitive::kPrimInt: { + if (second.IsRegister()) { + CpuRegister second_reg = second.As<CpuRegister>(); + if (op->IsShl()) { + __ shll(first_reg, second_reg); + } else if (op->IsShr()) { + __ sarl(first_reg, second_reg); + } else { + __ shrl(first_reg, second_reg); + } + } else { + Immediate imm(second.GetConstant()->AsIntConstant()->GetValue()); + if (op->IsShl()) { + __ shll(first_reg, imm); + } else if (op->IsShr()) { + __ sarl(first_reg, imm); + } else { + __ shrl(first_reg, imm); + } + } + break; + } + case Primitive::kPrimLong: { + if (second.IsRegister()) { + CpuRegister second_reg = second.As<CpuRegister>(); + if (op->IsShl()) { + __ shlq(first_reg, second_reg); + } else if (op->IsShr()) { + __ sarq(first_reg, second_reg); + } else { + __ shrq(first_reg, second_reg); + } + } else { + Immediate imm(second.GetConstant()->AsIntConstant()->GetValue()); + if (op->IsShl()) { + __ shlq(first_reg, imm); + } else if (op->IsShr()) { + __ sarq(first_reg, imm); + } else { + __ shrq(first_reg, imm); + } + } + break; + } + default: + LOG(FATAL) << "Unexpected operation type " << op->GetResultType(); + } +} + +void LocationsBuilderX86_64::VisitShl(HShl* shl) { + HandleShift(shl); +} + +void InstructionCodeGeneratorX86_64::VisitShl(HShl* shl) { + HandleShift(shl); +} + +void LocationsBuilderX86_64::VisitShr(HShr* shr) { + HandleShift(shr); +} + +void InstructionCodeGeneratorX86_64::VisitShr(HShr* shr) { + HandleShift(shr); +} + +void LocationsBuilderX86_64::VisitUShr(HUShr* ushr) { + HandleShift(ushr); +} + +void InstructionCodeGeneratorX86_64::VisitUShr(HUShr* ushr) { + HandleShift(ushr); +} + void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 29c679d8f..794b81ffb 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -108,6 +108,7 @@ class LocationsBuilderX86_64 : public HGraphVisitor { private: void HandleInvoke(HInvoke* invoke); void HandleBitwiseOperation(HBinaryOperation* operation); + void HandleShift(HBinaryOperation* operation); CodeGeneratorX86_64* const codegen_; InvokeDexCallingConventionVisitor parameter_visitor_; @@ -136,6 +137,7 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor { void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg); void HandleBitwiseOperation(HBinaryOperation* operation); void GenerateDivRemIntegral(HBinaryOperation* instruction); + void HandleShift(HBinaryOperation* operation); X86_64Assembler* const assembler_; CodeGeneratorX86_64* const codegen_; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 7d52d7d22..b47549add 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -42,6 +42,9 @@ static const int kDefaultNumberOfPredecessors = 2; static const int kDefaultNumberOfDominatedBlocks = 1; static const int kDefaultNumberOfBackEdges = 1; +static constexpr uint32_t kMaxIntShiftValue = 0x1f; +static constexpr uint64_t kMaxLongShiftValue = 0x3f; + enum IfCondition { kCondEQ, kCondNE, @@ -521,9 +524,11 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(ParallelMove, Instruction) \ M(ParameterValue, Instruction) \ M(Phi, Instruction) \ - M(Rem, BinaryOperation) \ + M(Rem, BinaryOperation) \ M(Return, Instruction) \ M(ReturnVoid, Instruction) \ + M(Shl, BinaryOperation) \ + M(Shr, BinaryOperation) \ M(StaticFieldGet, Instruction) \ M(StaticFieldSet, Instruction) \ M(StoreLocal, Instruction) \ @@ -532,6 +537,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(Temporary, Instruction) \ M(Throw, Instruction) \ M(TypeConversion, Instruction) \ + M(UShr, BinaryOperation) \ M(Xor, BinaryOperation) \ #define FOR_EACH_INSTRUCTION(M) \ @@ -1831,6 +1837,57 @@ class HDivZeroCheck : public HExpression<1> { DISALLOW_COPY_AND_ASSIGN(HDivZeroCheck); }; +class HShl : public HBinaryOperation { + public: + HShl(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x << (y & kMaxIntShiftValue); } + int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x << (y & kMaxLongShiftValue); } + + DECLARE_INSTRUCTION(Shl); + + private: + DISALLOW_COPY_AND_ASSIGN(HShl); +}; + +class HShr : public HBinaryOperation { + public: + HShr(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x >> (y & kMaxIntShiftValue); } + int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x >> (y & kMaxLongShiftValue); } + + DECLARE_INSTRUCTION(Shr); + + private: + DISALLOW_COPY_AND_ASSIGN(HShr); +}; + +class HUShr : public HBinaryOperation { + public: + HUShr(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { + uint32_t ux = static_cast<uint32_t>(x); + uint32_t uy = static_cast<uint32_t>(y) & kMaxIntShiftValue; + return static_cast<int32_t>(ux >> uy); + } + + int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { + uint64_t ux = static_cast<uint64_t>(x); + uint64_t uy = static_cast<uint64_t>(y) & kMaxLongShiftValue; + return static_cast<int64_t>(ux >> uy); + } + + DECLARE_INSTRUCTION(UShr); + + private: + DISALLOW_COPY_AND_ASSIGN(HUShr); +}; + class HAnd : public HBinaryOperation { public: HAnd(Primitive::Type result_type, HInstruction* left, HInstruction* right) |