diff options
author | Roland Levillain <rpl@google.com> | 2014-10-20 16:36:47 +0100 |
---|---|---|
committer | Roland Levillain <rpl@google.com> | 2014-10-21 13:48:32 +0100 |
commit | 88cb1755e1d6acaed0f66ce65d7a2a4465053342 (patch) | |
tree | 6ffdd07aa75a38eae9376bd95d0991a789cd624c | |
parent | 1e642b5e5b2958ffc1653f5f42f2d091bbd8549e (diff) | |
download | art-88cb1755e1d6acaed0f66ce65d7a2a4465053342.tar.gz art-88cb1755e1d6acaed0f66ce65d7a2a4465053342.tar.bz2 art-88cb1755e1d6acaed0f66ce65d7a2a4465053342.zip |
Implement int negate instruction in the optimizing compiler.
- Add support for the neg-int (integer two's complement
negate) instruction in the optimizing compiler.
- Add a HNeg node type for control-flow graphs and an
intermediate HUnaryOperation base class.
- Generate ARM, x86 and x86-64 code for integer HNeg nodes.
Change-Id: I72fd3e1e5311a75c38a8cb665a9211a20325a42e
-rw-r--r-- | compiler/optimizing/builder.cc | 12 | ||||
-rw-r--r-- | compiler/optimizing/builder.h | 3 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 41 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 41 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 41 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 32 | ||||
-rw-r--r-- | test/411-optimizing-arith/src/Main.java | 32 |
7 files changed, 202 insertions, 0 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 2648d4d670..2f1a092ea8 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -267,6 +267,13 @@ HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const { } template<typename T> +void HGraphBuilder::Unop_12x(const Instruction& instruction, Primitive::Type type) { + HInstruction* first = LoadLocal(instruction.VRegB(), type); + current_block_->AddInstruction(new (arena_) T(type, first)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +template<typename T> void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type) { HInstruction* first = LoadLocal(instruction.VRegB(), type); HInstruction* second = LoadLocal(instruction.VRegC(), type); @@ -678,6 +685,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::NEG_INT: { + Unop_12x<HNeg>(instruction, Primitive::kPrimInt); + break; + } + case Instruction::ADD_INT: { Binop_23x<HAdd>(instruction, Primitive::kPrimInt); break; diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index e68cdb0b1d..90e50ad951 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -95,6 +95,9 @@ class HGraphBuilder : public ValueObject { bool InitializeParameters(uint16_t number_of_parameters); template<typename T> + void Unop_12x(const Instruction& instruction, Primitive::Type type); + + template<typename T> void Binop_23x(const Instruction& instruction, Primitive::Type type); template<typename T> diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index a2cf670b0f..bfada27d2c 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1016,6 +1016,47 @@ void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderARM::VisitNeg(HNeg* neg) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + +void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) { + LocationSummary* locations = neg->GetLocations(); + Location out = locations->Out(); + Location in = locations->InAt(0); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + DCHECK(in.IsRegister()); + __ rsbs(out.As<Register>(), in.As<Register>(), ShifterOperand(0)); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + void LocationsBuilderARM::VisitAdd(HAdd* add) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 041acdf91e..82c703a6f6 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -957,6 +957,47 @@ void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderX86::VisitNeg(HNeg* neg) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + +void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) { + LocationSummary* locations = neg->GetLocations(); + Location out = locations->Out(); + Location in = locations->InAt(0); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + DCHECK(in.IsRegister()); + __ negl(out.As<Register>()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + void LocationsBuilderX86::VisitAdd(HAdd* add) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 5fa930512b..0105231513 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -933,6 +933,47 @@ void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderX86_64::VisitNeg(HNeg* neg) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + +void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) { + LocationSummary* locations = neg->GetLocations(); + Location out = locations->Out(); + Location in = locations->InAt(0); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + DCHECK(in.IsRegister()); + __ negl(out.As<CpuRegister>()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + void LocationsBuilderX86_64::VisitAdd(HAdd* add) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 7bb71b6012..26d9bd1b32 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -503,10 +503,12 @@ class HBasicBlock : public ArenaObject { M(Temporary, Instruction) \ M(SuspendCheck, Instruction) \ M(Mul, BinaryOperation) \ + M(Neg, UnaryOperation) #define FOR_EACH_INSTRUCTION(M) \ FOR_EACH_CONCRETE_INSTRUCTION(M) \ M(Constant, Instruction) \ + M(UnaryOperation, Instruction) \ M(BinaryOperation, Instruction) \ M(Invoke, Instruction) @@ -1086,6 +1088,25 @@ class HIf : public HTemplateInstruction<1> { DISALLOW_COPY_AND_ASSIGN(HIf); }; +class HUnaryOperation : public HExpression<1> { + public: + HUnaryOperation(Primitive::Type result_type, HInstruction* input) + : HExpression(result_type, SideEffects::None()) { + SetRawInputAt(0, input); + } + + HInstruction* GetInput() const { return InputAt(0); } + Primitive::Type GetResultType() const { return GetType(); } + + virtual bool CanBeMoved() const { return true; } + virtual bool InstructionDataEquals(HInstruction* other) const { return true; } + + DECLARE_INSTRUCTION(UnaryOperation); + + private: + DISALLOW_COPY_AND_ASSIGN(HUnaryOperation); +}; + class HBinaryOperation : public HExpression<2> { public: HBinaryOperation(Primitive::Type result_type, @@ -1518,6 +1539,17 @@ class HNewInstance : public HExpression<0> { DISALLOW_COPY_AND_ASSIGN(HNewInstance); }; +class HNeg : public HUnaryOperation { + public: + explicit HNeg(Primitive::Type result_type, HInstruction* input) + : HUnaryOperation(result_type, input) {} + + DECLARE_INSTRUCTION(Neg); + + private: + DISALLOW_COPY_AND_ASSIGN(HNeg); +}; + class HAdd : public HBinaryOperation { public: HAdd(Primitive::Type result_type, HInstruction* left, HInstruction* right) diff --git a/test/411-optimizing-arith/src/Main.java b/test/411-optimizing-arith/src/Main.java index 74c47a606c..2b3ba33a6a 100644 --- a/test/411-optimizing-arith/src/Main.java +++ b/test/411-optimizing-arith/src/Main.java @@ -33,6 +33,7 @@ public class Main { public static void main(String[] args) { mul(); + neg(); } public static void mul() { @@ -51,6 +52,34 @@ public class Main { expectEquals(36L, $opt$Mul(-12L, -3L)); expectEquals(33L, $opt$Mul(1L, 3L) * 11); expectEquals(240518168583L, $opt$Mul(34359738369L, 7L)); // (2^35 + 1) * 7 + + $opt$InplaceNegOne(1); + } + + public static void neg() { + expectEquals(-1, $opt$Neg(1)); + expectEquals(1, $opt$Neg(-1)); + expectEquals(0, $opt$Neg(0)); + expectEquals(51, $opt$Neg(-51)); + expectEquals(-51, $opt$Neg(51)); + expectEquals(2147483647, $opt$Neg(-2147483647)); // (2^31 - 1) + expectEquals(-2147483647, $opt$Neg(2147483647)); // -(2^31 - 1) + // From the Java 7 SE Edition specification: + // http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.15.4 + // + // For integer values, negation is the same as subtraction from + // zero. The Java programming language uses two's-complement + // representation for integers, and the range of two's-complement + // values is not symmetric, so negation of the maximum negative + // int or long results in that same maximum negative number. + // Overflow occurs in this case, but no exception is thrown. + // For all integer values x, -x equals (~x)+1.'' + expectEquals(-2147483648, $opt$Neg(-2147483648)); // -(2^31) + } + + public static void $opt$InplaceNegOne(int a) { + a = -a; + expectEquals(-1, a); } static int $opt$Mul(int a, int b) { @@ -61,4 +90,7 @@ public class Main { return a * b; } + static int $opt$Neg(int a){ + return -a; + } } |