[optimizing compiler] Add shifts
Added SHL, SHR, USHR for arm, x86, x86_64.
Change-Id: I971f594e270179457e6958acf1401ff7630df07e
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index be8631a..b261460 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -305,6 +305,15 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 897bcec..204005d 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -105,12 +105,18 @@
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 1701ef5..a204e21 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2087,6 +2087,124 @@
}
}
+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 c00fac1..226e635 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -109,6 +109,7 @@
private:
void HandleInvoke(HInvoke* invoke);
void HandleBitwiseOperation(HBinaryOperation* operation);
+ void HandleShift(HBinaryOperation* operation);
CodeGeneratorARM* const codegen_;
InvokeDexCallingConventionVisitor parameter_visitor_;
@@ -136,6 +137,7 @@
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 82dced5..7a8b941 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -801,7 +801,10 @@
#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 3c53cea..917b7dd 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -2129,6 +2129,139 @@
}
}
+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 0aff6cc..aed06c0 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -104,6 +104,7 @@
private:
void HandleBitwiseOperation(HBinaryOperation* instruction);
void HandleInvoke(HInvoke* invoke);
+ void HandleShift(HBinaryOperation* instruction);
CodeGeneratorX86* const codegen_;
InvokeDexCallingConventionVisitor parameter_visitor_;
@@ -132,6 +133,10 @@
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 97f5e5c..69f031a 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -2026,6 +2026,107 @@
}
}
+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 29c679d..794b81f 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -108,6 +108,7 @@
private:
void HandleInvoke(HInvoke* invoke);
void HandleBitwiseOperation(HBinaryOperation* operation);
+ void HandleShift(HBinaryOperation* operation);
CodeGeneratorX86_64* const codegen_;
InvokeDexCallingConventionVisitor parameter_visitor_;
@@ -136,6 +137,7 @@
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 7d52d7d..b47549a 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -42,6 +42,9 @@
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 @@
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 @@
M(Temporary, Instruction) \
M(Throw, Instruction) \
M(TypeConversion, Instruction) \
+ M(UShr, BinaryOperation) \
M(Xor, BinaryOperation) \
#define FOR_EACH_INSTRUCTION(M) \
@@ -1831,6 +1837,57 @@
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)