diff options
-rw-r--r-- | compiler/optimizing/builder.cc | 90 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 73 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.h | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 98 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.h | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 81 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 4 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 51 | ||||
-rw-r--r-- | compiler/utils/x86/assembler_x86.cc | 23 | ||||
-rw-r--r-- | compiler/utils/x86/assembler_x86.h | 3 | ||||
-rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.cc | 47 | ||||
-rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.h | 6 | ||||
-rw-r--r-- | test/411-optimizing-arith/src/Main.java | 2 | ||||
-rw-r--r-- | test/427-bitwise/expected.txt | 0 | ||||
-rw-r--r-- | test/427-bitwise/info.txt | 1 | ||||
-rw-r--r-- | test/427-bitwise/src/Main.java | 233 |
17 files changed, 717 insertions, 6 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index e338178f73..d3ac4e02cf 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -1047,6 +1047,36 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::AND_INT: { + Binop_23x<HAnd>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::AND_LONG: { + Binop_23x<HAnd>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::OR_INT: { + Binop_23x<HOr>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::OR_LONG: { + Binop_23x<HOr>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::XOR_INT: { + Binop_23x<HXor>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::XOR_LONG: { + Binop_23x<HXor>(instruction, Primitive::kPrimLong); + break; + } + case Instruction::ADD_LONG_2ADDR: { Binop_12x<HAdd>(instruction, Primitive::kPrimLong); break; @@ -1118,11 +1148,56 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::AND_INT_2ADDR: { + Binop_12x<HAnd>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::AND_LONG_2ADDR: { + Binop_12x<HAnd>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::OR_INT_2ADDR: { + Binop_12x<HOr>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::OR_LONG_2ADDR: { + Binop_12x<HOr>(instruction, Primitive::kPrimLong); + break; + } + + case Instruction::XOR_INT_2ADDR: { + Binop_12x<HXor>(instruction, Primitive::kPrimInt); + break; + } + + case Instruction::XOR_LONG_2ADDR: { + Binop_12x<HXor>(instruction, Primitive::kPrimLong); + break; + } + case Instruction::ADD_INT_LIT16: { Binop_22s<HAdd>(instruction, false); break; } + case Instruction::AND_INT_LIT16: { + Binop_22s<HAnd>(instruction, false); + break; + } + + case Instruction::OR_INT_LIT16: { + Binop_22s<HOr>(instruction, false); + break; + } + + case Instruction::XOR_INT_LIT16: { + Binop_22s<HXor>(instruction, false); + break; + } + case Instruction::RSUB_INT: { Binop_22s<HSub>(instruction, true); break; @@ -1138,6 +1213,21 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::AND_INT_LIT8: { + Binop_22b<HAnd>(instruction, false); + break; + } + + case Instruction::OR_INT_LIT8: { + Binop_22b<HOr>(instruction, false); + break; + } + + case Instruction::XOR_INT_LIT8: { + Binop_22b<HXor>(instruction, false); + break; + } + case Instruction::RSUB_INT_LIT8: { Binop_22b<HSub>(instruction, true); break; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index c2e9a2e5da..56546c2901 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -2809,5 +2809,78 @@ void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instr instruction->GetDexPc()); } +void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } + +void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + DCHECK(instruction->GetResultType() == Primitive::kPrimInt + || instruction->GetResultType() == Primitive::kPrimLong); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + bool output_overlaps = (instruction->GetResultType() == Primitive::kPrimLong); + locations->SetOut(Location::RequiresRegister(), output_overlaps); +} + +void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = instruction->GetLocations(); + + if (instruction->GetResultType() == Primitive::kPrimInt) { + Register first = locations->InAt(0).As<Register>(); + Register second = locations->InAt(1).As<Register>(); + Register out = locations->Out().As<Register>(); + if (instruction->IsAnd()) { + __ and_(out, first, ShifterOperand(second)); + } else if (instruction->IsOr()) { + __ orr(out, first, ShifterOperand(second)); + } else { + DCHECK(instruction->IsXor()); + __ eor(out, first, ShifterOperand(second)); + } + } else { + DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + Location out = locations->Out(); + if (instruction->IsAnd()) { + __ and_(out.AsRegisterPairLow<Register>(), + first.AsRegisterPairLow<Register>(), + ShifterOperand(second.AsRegisterPairLow<Register>())); + __ and_(out.AsRegisterPairHigh<Register>(), + first.AsRegisterPairHigh<Register>(), + ShifterOperand(second.AsRegisterPairHigh<Register>())); + } else if (instruction->IsOr()) { + __ orr(out.AsRegisterPairLow<Register>(), + first.AsRegisterPairLow<Register>(), + ShifterOperand(second.AsRegisterPairLow<Register>())); + __ orr(out.AsRegisterPairHigh<Register>(), + first.AsRegisterPairHigh<Register>(), + ShifterOperand(second.AsRegisterPairHigh<Register>())); + } else { + DCHECK(instruction->IsXor()); + __ eor(out.AsRegisterPairLow<Register>(), + first.AsRegisterPairLow<Register>(), + ShifterOperand(second.AsRegisterPairLow<Register>())); + __ eor(out.AsRegisterPairHigh<Register>(), + first.AsRegisterPairHigh<Register>(), + ShifterOperand(second.AsRegisterPairHigh<Register>())); + } + } +} + } // namespace arm } // namespace art diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 5d519937f4..d69531002d 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -105,9 +105,10 @@ class LocationsBuilderARM : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION + private: void HandleInvoke(HInvoke* invoke); + void HandleBitwiseOperation(HBinaryOperation* operation); - private: CodeGeneratorARM* const codegen_; InvokeDexCallingConventionVisitor parameter_visitor_; @@ -133,6 +134,7 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { // the suspend call. void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeARM* slow_path, Register class_reg); + void HandleBitwiseOperation(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 95c2fe7fa6..887a4efa19 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -631,6 +631,7 @@ InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph, codegen_(codegen) {} #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \ + M(And) \ M(CheckCast) \ M(ClinitCheck) \ M(DivZeroCheck) \ @@ -640,11 +641,13 @@ InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph, M(LoadException) \ M(LoadString) \ M(MonitorOperation) \ + M(Or) \ M(ParallelMove) \ M(StaticFieldGet) \ M(StaticFieldSet) \ M(Throw) \ M(TypeConversion) \ + M(Xor) \ #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 bed44b2940..d470345765 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1448,7 +1448,7 @@ void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) { } case Primitive::kPrimLong: { - if (second.IsRegister()) { + if (second.IsRegisterPair()) { __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); } else { @@ -1524,7 +1524,7 @@ void InstructionCodeGeneratorX86::VisitSub(HSub* sub) { } case Primitive::kPrimLong: { - if (second.IsRegister()) { + if (second.IsRegisterPair()) { __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); } else { @@ -2919,5 +2919,99 @@ void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instr codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); } +void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } + +void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + DCHECK(instruction->GetResultType() == Primitive::kPrimInt + || instruction->GetResultType() == Primitive::kPrimLong); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::Any()); + locations->SetOut(Location::SameAsFirstInput()); +} + +void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = instruction->GetLocations(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + DCHECK(first.Equals(locations->Out())); + + if (instruction->GetResultType() == Primitive::kPrimInt) { + if (second.IsRegister()) { + if (instruction->IsAnd()) { + __ andl(first.As<Register>(), second.As<Register>()); + } else if (instruction->IsOr()) { + __ orl(first.As<Register>(), second.As<Register>()); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<Register>(), second.As<Register>()); + } + } else if (second.IsConstant()) { + if (instruction->IsAnd()) { + __ andl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue())); + } else if (instruction->IsOr()) { + __ orl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue())); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue())); + } + } else { + if (instruction->IsAnd()) { + __ andl(first.As<Register>(), Address(ESP, second.GetStackIndex())); + } else if (instruction->IsOr()) { + __ orl(first.As<Register>(), Address(ESP, second.GetStackIndex())); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<Register>(), Address(ESP, second.GetStackIndex())); + } + } + } else { + DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); + if (second.IsRegisterPair()) { + if (instruction->IsAnd()) { + __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); + __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); + } else if (instruction->IsOr()) { + __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); + __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); + __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); + } + } else { + if (instruction->IsAnd()) { + __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); + __ andl(first.AsRegisterPairHigh<Register>(), + Address(ESP, second.GetHighStackIndex(kX86WordSize))); + } else if (instruction->IsOr()) { + __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); + __ orl(first.AsRegisterPairHigh<Register>(), + Address(ESP, second.GetHighStackIndex(kX86WordSize))); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); + __ xorl(first.AsRegisterPairHigh<Register>(), + Address(ESP, second.GetHighStackIndex(kX86WordSize))); + } + } + } +} + } // namespace x86 } // namespace art diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 85fe21ca76..9e42b0a90c 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -100,9 +100,10 @@ class LocationsBuilderX86 : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION + private: + void HandleBitwiseOperation(HBinaryOperation* instruction); void HandleInvoke(HInvoke* invoke); - private: CodeGeneratorX86* const codegen_; InvokeDexCallingConventionVisitor parameter_visitor_; @@ -128,6 +129,7 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor { // the suspend call. void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeX86* slow_path, Register class_reg); + void HandleBitwiseOperation(HBinaryOperation* instruction); 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 112c17975a..3c7dd3f56a 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -2910,5 +2910,86 @@ void InstructionCodeGeneratorX86_64::VisitMonitorOperation(HMonitorOperation* in codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); } +void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } +void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } + +void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + DCHECK(instruction->GetResultType() == Primitive::kPrimInt + || instruction->GetResultType() == Primitive::kPrimLong); + locations->SetInAt(0, Location::RequiresRegister()); + if (instruction->GetType() == Primitive::kPrimInt) { + locations->SetInAt(1, Location::Any()); + } else { + // Request a register to avoid loading a 64bits constant. + locations->SetInAt(1, Location::RequiresRegister()); + } + locations->SetOut(Location::SameAsFirstInput()); +} + +void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) { + HandleBitwiseOperation(instruction); +} + +void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) { + LocationSummary* locations = instruction->GetLocations(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + DCHECK(first.Equals(locations->Out())); + + if (instruction->GetResultType() == Primitive::kPrimInt) { + if (second.IsRegister()) { + if (instruction->IsAnd()) { + __ andl(first.As<CpuRegister>(), second.As<CpuRegister>()); + } else if (instruction->IsOr()) { + __ orl(first.As<CpuRegister>(), second.As<CpuRegister>()); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<CpuRegister>(), second.As<CpuRegister>()); + } + } else if (second.IsConstant()) { + Immediate imm(second.GetConstant()->AsIntConstant()->GetValue()); + if (instruction->IsAnd()) { + __ andl(first.As<CpuRegister>(), imm); + } else if (instruction->IsOr()) { + __ orl(first.As<CpuRegister>(), imm); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<CpuRegister>(), imm); + } + } else { + Address address(CpuRegister(RSP), second.GetStackIndex()); + if (instruction->IsAnd()) { + __ andl(first.As<CpuRegister>(), address); + } else if (instruction->IsOr()) { + __ orl(first.As<CpuRegister>(), address); + } else { + DCHECK(instruction->IsXor()); + __ xorl(first.As<CpuRegister>(), address); + } + } + } else { + DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); + if (instruction->IsAnd()) { + __ andq(first.As<CpuRegister>(), second.As<CpuRegister>()); + } else if (instruction->IsOr()) { + __ orq(first.As<CpuRegister>(), second.As<CpuRegister>()); + } else { + DCHECK(instruction->IsXor()); + __ xorq(first.As<CpuRegister>(), second.As<CpuRegister>()); + } + } +} + } // namespace x86_64 } // namespace art diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 9565b6f876..52806f34d4 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -104,9 +104,10 @@ class LocationsBuilderX86_64 : public HGraphVisitor { #undef DECLARE_VISIT_INSTRUCTION + private: void HandleInvoke(HInvoke* invoke); + void HandleBitwiseOperation(HBinaryOperation* operation); - private: CodeGeneratorX86_64* const codegen_; InvokeDexCallingConventionVisitor parameter_visitor_; @@ -132,6 +133,7 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor { // the suspend call. void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg); + void HandleBitwiseOperation(HBinaryOperation* operation); X86_64Assembler* const assembler_; CodeGeneratorX86_64* const codegen_; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 1545b0a026..6224a11f24 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -475,6 +475,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { #define FOR_EACH_CONCRETE_INSTRUCTION(M) \ M(Add, BinaryOperation) \ + M(And, BinaryOperation) \ M(ArrayGet, Instruction) \ M(ArrayLength, Instruction) \ M(ArraySet, Instruction) \ @@ -516,6 +517,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(Not, UnaryOperation) \ M(NotEqual, Condition) \ M(NullCheck, Instruction) \ + M(Or, BinaryOperation) \ M(ParallelMove, Instruction) \ M(ParameterValue, Instruction) \ M(Phi, Instruction) \ @@ -529,6 +531,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(Temporary, Instruction) \ M(Throw, Instruction) \ M(TypeConversion, Instruction) \ + M(Xor, BinaryOperation) \ #define FOR_EACH_INSTRUCTION(M) \ FOR_EACH_CONCRETE_INSTRUCTION(M) \ @@ -1791,6 +1794,54 @@ class HDivZeroCheck : public HExpression<1> { DISALLOW_COPY_AND_ASSIGN(HDivZeroCheck); }; +class HAnd : public HBinaryOperation { + public: + HAnd(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + bool IsCommutative() OVERRIDE { return true; } + + int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x & y; } + int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x & y; } + + DECLARE_INSTRUCTION(And); + + private: + DISALLOW_COPY_AND_ASSIGN(HAnd); +}; + +class HOr : public HBinaryOperation { + public: + HOr(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + bool IsCommutative() OVERRIDE { return true; } + + int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x | y; } + int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x | y; } + + DECLARE_INSTRUCTION(Or); + + private: + DISALLOW_COPY_AND_ASSIGN(HOr); +}; + +class HXor : public HBinaryOperation { + public: + HXor(Primitive::Type result_type, HInstruction* left, HInstruction* right) + : HBinaryOperation(result_type, left, right) {} + + bool IsCommutative() OVERRIDE { return true; } + + int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x ^ y; } + int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x ^ y; } + + DECLARE_INSTRUCTION(Xor); + + private: + DISALLOW_COPY_AND_ASSIGN(HXor); +}; + // The value of a parameter in this method. Its location depends on // the calling convention. class HParameterValue : public HExpression<0> { diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index 4ddf9793fd..8ebb40e338 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -873,6 +873,13 @@ void X86Assembler::andl(Register dst, Register src) { } +void X86Assembler::andl(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x23); + EmitOperand(reg, address); +} + + void X86Assembler::andl(Register dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitComplex(4, Operand(dst), imm); @@ -886,6 +893,13 @@ void X86Assembler::orl(Register dst, Register src) { } +void X86Assembler::orl(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0B); + EmitOperand(reg, address); +} + + void X86Assembler::orl(Register dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitComplex(1, Operand(dst), imm); @@ -898,11 +912,20 @@ void X86Assembler::xorl(Register dst, Register src) { EmitOperand(dst, Operand(src)); } + +void X86Assembler::xorl(Register reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x33); + EmitOperand(reg, address); +} + + void X86Assembler::xorl(Register dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitComplex(6, Operand(dst), imm); } + void X86Assembler::addl(Register reg, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitComplex(0, Operand(reg), imm); diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index de4e6de878..8aed9348d6 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -350,12 +350,15 @@ class X86Assembler FINAL : public Assembler { void andl(Register dst, const Immediate& imm); void andl(Register dst, Register src); + void andl(Register dst, const Address& address); void orl(Register dst, const Immediate& imm); void orl(Register dst, Register src); + void orl(Register dst, const Address& address); void xorl(Register dst, Register src); void xorl(Register dst, const Immediate& imm); + void xorl(Register dst, const Address& address); void addl(Register dst, Register src); void addl(Register reg, const Immediate& imm); diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index c75fa786e8..5d1c9af202 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -1014,6 +1014,14 @@ void X86_64Assembler::andl(CpuRegister dst, CpuRegister src) { } +void X86_64Assembler::andl(CpuRegister reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(reg, address); + EmitUint8(0x23); + EmitOperand(reg.LowBits(), address); +} + + void X86_64Assembler::andl(CpuRegister dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst); @@ -1029,6 +1037,14 @@ void X86_64Assembler::andq(CpuRegister reg, const Immediate& imm) { } +void X86_64Assembler::andq(CpuRegister dst, CpuRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitRex64(dst, src); + EmitUint8(0x23); + EmitOperand(dst.LowBits(), Operand(src)); +} + + void X86_64Assembler::orl(CpuRegister dst, CpuRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst, src); @@ -1037,6 +1053,14 @@ void X86_64Assembler::orl(CpuRegister dst, CpuRegister src) { } +void X86_64Assembler::orl(CpuRegister reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(reg, address); + EmitUint8(0x0B); + EmitOperand(reg.LowBits(), address); +} + + void X86_64Assembler::orl(CpuRegister dst, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst); @@ -1044,6 +1068,14 @@ void X86_64Assembler::orl(CpuRegister dst, const Immediate& imm) { } +void X86_64Assembler::orq(CpuRegister dst, CpuRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitRex64(dst, src); + EmitUint8(0x0B); + EmitOperand(dst.LowBits(), Operand(src)); +} + + void X86_64Assembler::xorl(CpuRegister dst, CpuRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOptionalRex32(dst, src); @@ -1052,6 +1084,21 @@ void X86_64Assembler::xorl(CpuRegister dst, CpuRegister src) { } +void X86_64Assembler::xorl(CpuRegister reg, const Address& address) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(reg, address); + EmitUint8(0x33); + EmitOperand(reg.LowBits(), address); +} + + +void X86_64Assembler::xorl(CpuRegister dst, const Immediate& imm) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(dst); + EmitComplex(6, Operand(dst), imm); +} + + void X86_64Assembler::xorq(CpuRegister dst, CpuRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitRex64(dst, src); diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 42d774a558..285b4cfc43 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -398,12 +398,18 @@ class X86_64Assembler FINAL : public Assembler { void andl(CpuRegister dst, const Immediate& imm); void andl(CpuRegister dst, CpuRegister src); + void andl(CpuRegister reg, const Address& address); void andq(CpuRegister dst, const Immediate& imm); + void andq(CpuRegister dst, CpuRegister src); void orl(CpuRegister dst, const Immediate& imm); void orl(CpuRegister dst, CpuRegister src); + void orl(CpuRegister reg, const Address& address); + void orq(CpuRegister dst, CpuRegister src); void xorl(CpuRegister dst, CpuRegister src); + void xorl(CpuRegister dst, const Immediate& imm); + void xorl(CpuRegister reg, const Address& address); void xorq(CpuRegister dst, const Immediate& imm); void xorq(CpuRegister dst, CpuRegister src); diff --git a/test/411-optimizing-arith/src/Main.java b/test/411-optimizing-arith/src/Main.java index a22c516ff4..3a5d7c05c9 100644 --- a/test/411-optimizing-arith/src/Main.java +++ b/test/411-optimizing-arith/src/Main.java @@ -101,7 +101,7 @@ public class Main { expectEquals(0L, $opt$Mul(3L, 0L)); expectEquals(-3L, $opt$Mul(1L, -3L)); expectEquals(36L, $opt$Mul(-12L, -3L)); - expectEquals(33L, $opt$Mul(1L, 3L) * 11F); + expectEquals(33L, $opt$Mul(1L, 3L) * 11L); expectEquals(240518168583L, $opt$Mul(34359738369L, 7L)); // (2^35 + 1) * 7 } diff --git a/test/427-bitwise/expected.txt b/test/427-bitwise/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/427-bitwise/expected.txt diff --git a/test/427-bitwise/info.txt b/test/427-bitwise/info.txt new file mode 100644 index 0000000000..47628479c7 --- /dev/null +++ b/test/427-bitwise/info.txt @@ -0,0 +1 @@ +Tests for the and/or/xor opcodes. diff --git a/test/427-bitwise/src/Main.java b/test/427-bitwise/src/Main.java new file mode 100644 index 0000000000..e9840669dd --- /dev/null +++ b/test/427-bitwise/src/Main.java @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Note that $opt$ is a marker for the optimizing compiler to ensure +// it does compile the method. +public class Main { + + public static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void main(String[] args) { + andInt(); + andLong(); + + orInt(); + orLong(); + + xorInt(); + xorLong(); + } + + private static void andInt() { + expectEquals(1, $opt$And(5, 3)); + expectEquals(0, $opt$And(0, 0)); + expectEquals(0, $opt$And(0, 3)); + expectEquals(0, $opt$And(3, 0)); + expectEquals(1, $opt$And(1, -3)); + expectEquals(-12, $opt$And(-12, -3)); + + expectEquals(1, $opt$AndLit8(1)); + expectEquals(0, $opt$AndLit8(0)); + expectEquals(0, $opt$AndLit8(0)); + expectEquals(3, $opt$AndLit8(3)); + expectEquals(4, $opt$AndLit8(-12)); + + expectEquals(0, $opt$AndLit16(1)); + expectEquals(0, $opt$AndLit16(0)); + expectEquals(0, $opt$AndLit16(0)); + expectEquals(0, $opt$AndLit16(3)); + expectEquals(65280, $opt$AndLit16(-12)); + } + + private static void andLong() { + expectEquals(1L, $opt$And(5L, 3L)); + expectEquals(0L, $opt$And(0L, 0L)); + expectEquals(0L, $opt$And(0L, 3L)); + expectEquals(0L, $opt$And(3L, 0L)); + expectEquals(1L, $opt$And(1L, -3L)); + expectEquals(-12L, $opt$And(-12L, -3L)); + + expectEquals(1L, $opt$AndLit8(1L)); + expectEquals(0L, $opt$AndLit8(0L)); + expectEquals(0L, $opt$AndLit8(0L)); + expectEquals(3L, $opt$AndLit8(3L)); + expectEquals(4L, $opt$AndLit8(-12L)); + + expectEquals(0L, $opt$AndLit16(1L)); + expectEquals(0L, $opt$AndLit16(0L)); + expectEquals(0L, $opt$AndLit16(0L)); + expectEquals(0L, $opt$AndLit16(3L)); + expectEquals(65280L, $opt$AndLit16(-12L)); + } + + static int $opt$And(int a, int b) { + return a & b; + } + + static int $opt$AndLit8(int a) { + return a & 0xF; + } + + static int $opt$AndLit16(int a) { + return a & 0xFF00; + } + + static long $opt$And(long a, long b) { + return a & b; + } + + static long $opt$AndLit8(long a) { + return a & 0xF; + } + + static long $opt$AndLit16(long a) { + return a & 0xFF00; + } + + private static void orInt() { + expectEquals(7, $opt$Or(5, 3)); + expectEquals(0, $opt$Or(0, 0)); + expectEquals(3, $opt$Or(0, 3)); + expectEquals(3, $opt$Or(3, 0)); + expectEquals(-3, $opt$Or(1, -3)); + expectEquals(-3, $opt$Or(-12, -3)); + + expectEquals(15, $opt$OrLit8(1)); + expectEquals(15, $opt$OrLit8(0)); + expectEquals(15, $opt$OrLit8(3)); + expectEquals(-1, $opt$OrLit8(-12)); + + expectEquals(0xFF01, $opt$OrLit16(1)); + expectEquals(0xFF00, $opt$OrLit16(0)); + expectEquals(0xFF03, $opt$OrLit16(3)); + expectEquals(-12, $opt$OrLit16(-12)); + } + + private static void orLong() { + expectEquals(7L, $opt$Or(5L, 3L)); + expectEquals(0L, $opt$Or(0L, 0L)); + expectEquals(3L, $opt$Or(0L, 3L)); + expectEquals(3L, $opt$Or(3L, 0L)); + expectEquals(-3L, $opt$Or(1L, -3L)); + expectEquals(-3L, $opt$Or(-12L, -3L)); + + expectEquals(15L, $opt$OrLit8(1L)); + expectEquals(15L, $opt$OrLit8(0L)); + expectEquals(15L, $opt$OrLit8(3L)); + expectEquals(-1L, $opt$OrLit8(-12L)); + + expectEquals(0xFF01L, $opt$OrLit16(1L)); + expectEquals(0xFF00L, $opt$OrLit16(0L)); + expectEquals(0xFF03L, $opt$OrLit16(3L)); + expectEquals(-12L, $opt$OrLit16(-12L)); + } + + static int $opt$Or(int a, int b) { + return a | b; + } + + static int $opt$OrLit8(int a) { + return a | 0xF; + } + + static int $opt$OrLit16(int a) { + return a | 0xFF00; + } + + static long $opt$Or(long a, long b) { + return a | b; + } + + static long $opt$OrLit8(long a) { + return a | 0xF; + } + + static long $opt$OrLit16(long a) { + return a | 0xFF00; + } + + private static void xorInt() { + expectEquals(6, $opt$Xor(5, 3)); + expectEquals(0, $opt$Xor(0, 0)); + expectEquals(3, $opt$Xor(0, 3)); + expectEquals(3, $opt$Xor(3, 0)); + expectEquals(-4, $opt$Xor(1, -3)); + expectEquals(9, $opt$Xor(-12, -3)); + + expectEquals(14, $opt$XorLit8(1)); + expectEquals(15, $opt$XorLit8(0)); + expectEquals(12, $opt$XorLit8(3)); + expectEquals(-5, $opt$XorLit8(-12)); + + expectEquals(0xFF01, $opt$XorLit16(1)); + expectEquals(0xFF00, $opt$XorLit16(0)); + expectEquals(0xFF03, $opt$XorLit16(3)); + expectEquals(-0xFF0c, $opt$XorLit16(-12)); + } + + private static void xorLong() { + expectEquals(6L, $opt$Xor(5L, 3L)); + expectEquals(0L, $opt$Xor(0L, 0L)); + expectEquals(3L, $opt$Xor(0L, 3L)); + expectEquals(3L, $opt$Xor(3L, 0L)); + expectEquals(-4L, $opt$Xor(1L, -3L)); + expectEquals(9L, $opt$Xor(-12L, -3L)); + + expectEquals(14L, $opt$XorLit8(1L)); + expectEquals(15L, $opt$XorLit8(0L)); + expectEquals(12L, $opt$XorLit8(3L)); + expectEquals(-5L, $opt$XorLit8(-12L)); + + expectEquals(0xFF01L, $opt$XorLit16(1L)); + expectEquals(0xFF00L, $opt$XorLit16(0L)); + expectEquals(0xFF03L, $opt$XorLit16(3L)); + expectEquals(-0xFF0cL, $opt$XorLit16(-12L)); + } + + static int $opt$Xor(int a, int b) { + return a ^ b; + } + + static int $opt$XorLit8(int a) { + return a ^ 0xF; + } + + static int $opt$XorLit16(int a) { + return a ^ 0xFF00; + } + + static long $opt$Xor(long a, long b) { + return a ^ b; + } + + static long $opt$XorLit8(long a) { + return a ^ 0xF; + } + + static long $opt$XorLit16(long a) { + return a ^ 0xFF00; + } +} |