diff options
author | 2016-02-09 17:15:29 +0000 | |
---|---|---|
committer | 2016-03-11 12:49:27 +0000 | |
commit | 7fc6350f6f1ab04b52b9cd7542e0790528296cbe (patch) | |
tree | 26a33ef7bb2e49a9b7c7d9436194a92cb447b317 /compiler/optimizing | |
parent | b7f257f353b1eb2db2732939a0404c118316891d (diff) |
Integrate BitwiseNegated into shared framework.
Share implementation between arm and arm64.
Change-Id: I0dd12e772cb23b4c181fd0b1e2a447470b1d8702
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 65 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 5 | ||||
-rw-r--r-- | compiler/optimizing/graph_visualizer.cc | 6 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_arm.cc | 13 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_arm.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_arm64.cc | 55 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_arm64.h | 4 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_shared.cc | 43 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_shared.h | 3 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/nodes_arm64.h | 60 | ||||
-rw-r--r-- | compiler/optimizing/nodes_shared.h | 60 |
12 files changed, 201 insertions, 117 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index aa9b01f30b..0b7fefafdd 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -5727,6 +5727,71 @@ void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } + +void LocationsBuilderARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* 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()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); +} + +void InstructionCodeGeneratorARM::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) { + LocationSummary* locations = instruction->GetLocations(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + Location out = locations->Out(); + + if (instruction->GetResultType() == Primitive::kPrimInt) { + Register first_reg = first.AsRegister<Register>(); + ShifterOperand second_reg(second.AsRegister<Register>()); + Register out_reg = out.AsRegister<Register>(); + + switch (instruction->GetOpKind()) { + case HInstruction::kAnd: + __ bic(out_reg, first_reg, second_reg); + break; + case HInstruction::kOr: + __ orn(out_reg, first_reg, second_reg); + break; + // There is no EON on arm. + case HInstruction::kXor: + default: + LOG(FATAL) << "Unexpected instruction " << instruction->DebugName(); + UNREACHABLE(); + } + return; + + } else { + DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); + Register first_low = first.AsRegisterPairLow<Register>(); + Register first_high = first.AsRegisterPairHigh<Register>(); + ShifterOperand second_low(second.AsRegisterPairLow<Register>()); + ShifterOperand second_high(second.AsRegisterPairHigh<Register>()); + Register out_low = out.AsRegisterPairLow<Register>(); + Register out_high = out.AsRegisterPairHigh<Register>(); + + switch (instruction->GetOpKind()) { + case HInstruction::kAnd: + __ bic(out_low, first_low, second_low); + __ bic(out_high, first_high, second_high); + break; + case HInstruction::kOr: + __ orn(out_low, first_low, second_low); + __ orn(out_high, first_high, second_high); + break; + // There is no EON on arm. + case HInstruction::kXor: + default: + LOG(FATAL) << "Unexpected instruction " << instruction->DebugName(); + UNREACHABLE(); + } + } +} + void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) { // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier). if (value == 0xffffffffu) { diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 985dc056f6..89b9e2c599 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -1862,7 +1862,7 @@ void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) { HandleBinaryOp(instruction); } -void LocationsBuilderARM64::VisitArm64BitwiseNegatedRight(HArm64BitwiseNegatedRight* instr) { +void LocationsBuilderARM64::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instr) { DCHECK(Primitive::IsIntegralType(instr->GetType())) << instr->GetType(); LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); locations->SetInAt(0, Location::RequiresRegister()); @@ -1871,8 +1871,7 @@ void LocationsBuilderARM64::VisitArm64BitwiseNegatedRight(HArm64BitwiseNegatedRi locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } -void InstructionCodeGeneratorARM64::VisitArm64BitwiseNegatedRight( - HArm64BitwiseNegatedRight* instr) { +void InstructionCodeGeneratorARM64::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instr) { Register dst = OutputRegister(instr); Register lhs = InputRegisterAt(instr, 0); Register rhs = InputRegisterAt(instr, 1); diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index b9638f2027..4f1e90cd7f 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -440,13 +440,13 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { void VisitMultiplyAccumulate(HMultiplyAccumulate* instruction) OVERRIDE { StartAttributeStream("kind") << instruction->GetOpKind(); } -#endif -#ifdef ART_ENABLE_CODEGEN_arm64 - void VisitArm64BitwiseNegatedRight(HArm64BitwiseNegatedRight* instruction) OVERRIDE { + void VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) OVERRIDE { StartAttributeStream("kind") << instruction->GetOpKind(); } +#endif +#ifdef ART_ENABLE_CODEGEN_arm64 void VisitArm64DataProcWithShifterOp(HArm64DataProcWithShifterOp* instruction) OVERRIDE { StartAttributeStream("kind") << instruction->GetInstrKind() << "+" << instruction->GetOpKind(); if (HArm64DataProcWithShifterOp::IsShiftOp(instruction->GetOpKind())) { diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc index db1f9a79aa..cd026b8770 100644 --- a/compiler/optimizing/instruction_simplifier_arm.cc +++ b/compiler/optimizing/instruction_simplifier_arm.cc @@ -26,5 +26,18 @@ void InstructionSimplifierArmVisitor::VisitMul(HMul* instruction) { } } +void InstructionSimplifierArmVisitor::VisitOr(HOr* instruction) { + if (TryMergeNegatedInput(instruction)) { + RecordSimplification(); + } +} + +void InstructionSimplifierArmVisitor::VisitAnd(HAnd* instruction) { + if (TryMergeNegatedInput(instruction)) { + RecordSimplification(); + } +} + + } // namespace arm } // namespace art diff --git a/compiler/optimizing/instruction_simplifier_arm.h b/compiler/optimizing/instruction_simplifier_arm.h index 379b95d6ae..14c940eb21 100644 --- a/compiler/optimizing/instruction_simplifier_arm.h +++ b/compiler/optimizing/instruction_simplifier_arm.h @@ -36,6 +36,8 @@ class InstructionSimplifierArmVisitor : public HGraphVisitor { } void VisitMul(HMul* instruction) OVERRIDE; + void VisitOr(HOr* instruction) OVERRIDE; + void VisitAnd(HAnd* instruction) OVERRIDE; OptimizingCompilerStats* stats_; }; diff --git a/compiler/optimizing/instruction_simplifier_arm64.cc b/compiler/optimizing/instruction_simplifier_arm64.cc index c2bbdccc29..f00d960877 100644 --- a/compiler/optimizing/instruction_simplifier_arm64.cc +++ b/compiler/optimizing/instruction_simplifier_arm64.cc @@ -180,51 +180,10 @@ bool InstructionSimplifierArm64Visitor::TryMergeIntoUsersShifterOperand(HInstruc return true; } -bool InstructionSimplifierArm64Visitor::TryMergeNegatedInput(HBinaryOperation* op) { - DCHECK(op->IsAnd() || op->IsOr() || op->IsXor()) << op->DebugName(); - HInstruction* left = op->GetLeft(); - HInstruction* right = op->GetRight(); - - // Only consider the case where there is exactly one Not, with 2 Not's De - // Morgan's laws should be applied instead. - if (left->IsNot() ^ right->IsNot()) { - HInstruction* hnot = (left->IsNot() ? left : right); - HInstruction* hother = (left->IsNot() ? right : left); - - // Only do the simplification if the Not has only one use and can thus be - // safely removed. Even though ARM64 negated bitwise operations do not have - // an immediate variant (only register), we still do the simplification when - // `hother` is a constant, because it removes an instruction if the constant - // cannot be encoded as an immediate: - // mov r0, #large_constant - // neg r2, r1 - // and r0, r0, r2 - // becomes: - // mov r0, #large_constant - // bic r0, r0, r1 - if (hnot->HasOnlyOneNonEnvironmentUse()) { - // Replace code looking like - // NOT tmp, mask - // AND dst, src, tmp (respectively ORR, EOR) - // with - // BIC dst, src, mask (respectively ORN, EON) - HInstruction* src = hnot->AsNot()->GetInput(); - - HArm64BitwiseNegatedRight* neg_op = new (GetGraph()->GetArena()) - HArm64BitwiseNegatedRight(op->GetType(), op->GetKind(), hother, src, op->GetDexPc()); - - op->GetBlock()->ReplaceAndRemoveInstructionWith(op, neg_op); - hnot->GetBlock()->RemoveInstruction(hnot); - RecordSimplification(); - return true; - } - } - - return false; -} - void InstructionSimplifierArm64Visitor::VisitAnd(HAnd* instruction) { - TryMergeNegatedInput(instruction); + if (TryMergeNegatedInput(instruction)) { + RecordSimplification(); + } } void InstructionSimplifierArm64Visitor::VisitArrayGet(HArrayGet* instruction) { @@ -248,7 +207,9 @@ void InstructionSimplifierArm64Visitor::VisitMul(HMul* instruction) { } void InstructionSimplifierArm64Visitor::VisitOr(HOr* instruction) { - TryMergeNegatedInput(instruction); + if (TryMergeNegatedInput(instruction)) { + RecordSimplification(); + } } void InstructionSimplifierArm64Visitor::VisitShl(HShl* instruction) { @@ -284,7 +245,9 @@ void InstructionSimplifierArm64Visitor::VisitUShr(HUShr* instruction) { } void InstructionSimplifierArm64Visitor::VisitXor(HXor* instruction) { - TryMergeNegatedInput(instruction); + if (TryMergeNegatedInput(instruction)) { + RecordSimplification(); + } } } // namespace arm64 diff --git a/compiler/optimizing/instruction_simplifier_arm64.h b/compiler/optimizing/instruction_simplifier_arm64.h index cf8458713f..338120bbbc 100644 --- a/compiler/optimizing/instruction_simplifier_arm64.h +++ b/compiler/optimizing/instruction_simplifier_arm64.h @@ -51,10 +51,6 @@ class InstructionSimplifierArm64Visitor : public HGraphVisitor { return TryMergeIntoShifterOperand(use, bitfield_op, true); } - // For bitwise operations (And/Or/Xor) with a negated input, try to use - // a negated bitwise instruction. - bool TryMergeNegatedInput(HBinaryOperation* op); - // HInstruction visitors, sorted alphabetically. void VisitAnd(HAnd* instruction) OVERRIDE; void VisitArrayGet(HArrayGet* instruction) OVERRIDE; diff --git a/compiler/optimizing/instruction_simplifier_shared.cc b/compiler/optimizing/instruction_simplifier_shared.cc index 45d196fa6d..a11b5bd5c3 100644 --- a/compiler/optimizing/instruction_simplifier_shared.cc +++ b/compiler/optimizing/instruction_simplifier_shared.cc @@ -186,4 +186,47 @@ bool TryCombineMultiplyAccumulate(HMul* mul, InstructionSet isa) { return false; } + +bool TryMergeNegatedInput(HBinaryOperation* op) { + DCHECK(op->IsAnd() || op->IsOr() || op->IsXor()) << op->DebugName(); + HInstruction* left = op->GetLeft(); + HInstruction* right = op->GetRight(); + + // Only consider the case where there is exactly one Not, with 2 Not's De + // Morgan's laws should be applied instead. + if (left->IsNot() ^ right->IsNot()) { + HInstruction* hnot = (left->IsNot() ? left : right); + HInstruction* hother = (left->IsNot() ? right : left); + + // Only do the simplification if the Not has only one use and can thus be + // safely removed. Even though ARM64 negated bitwise operations do not have + // an immediate variant (only register), we still do the simplification when + // `hother` is a constant, because it removes an instruction if the constant + // cannot be encoded as an immediate: + // mov r0, #large_constant + // neg r2, r1 + // and r0, r0, r2 + // becomes: + // mov r0, #large_constant + // bic r0, r0, r1 + if (hnot->HasOnlyOneNonEnvironmentUse()) { + // Replace code looking like + // NOT tmp, mask + // AND dst, src, tmp (respectively ORR, EOR) + // with + // BIC dst, src, mask (respectively ORN, EON) + HInstruction* src = hnot->AsNot()->GetInput(); + + HBitwiseNegatedRight* neg_op = new (hnot->GetBlock()->GetGraph()->GetArena()) + HBitwiseNegatedRight(op->GetType(), op->GetKind(), hother, src, op->GetDexPc()); + + op->GetBlock()->ReplaceAndRemoveInstructionWith(op, neg_op); + hnot->GetBlock()->RemoveInstruction(hnot); + return true; + } + } + + return false; +} + } // namespace art diff --git a/compiler/optimizing/instruction_simplifier_shared.h b/compiler/optimizing/instruction_simplifier_shared.h index 9832ecc058..b1fe8f4756 100644 --- a/compiler/optimizing/instruction_simplifier_shared.h +++ b/compiler/optimizing/instruction_simplifier_shared.h @@ -22,6 +22,9 @@ namespace art { bool TryCombineMultiplyAccumulate(HMul* mul, InstructionSet isa); +// For bitwise operations (And/Or/Xor) with a negated input, try to use +// a negated bitwise instruction. +bool TryMergeNegatedInput(HBinaryOperation* op); } // namespace art diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index ecb690ff62..be304f610d 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1265,6 +1265,7 @@ class HLoopInformationOutwardIterator : public ValueObject { #define FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) #else #define FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) \ + M(BitwiseNegatedRight, Instruction) \ M(MultiplyAccumulate, Instruction) #endif @@ -1279,7 +1280,6 @@ class HLoopInformationOutwardIterator : public ValueObject { #define FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M) #else #define FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M) \ - M(Arm64BitwiseNegatedRight, Instruction) \ M(Arm64DataProcWithShifterOp, Instruction) \ M(Arm64IntermediateAddress, Instruction) #endif diff --git a/compiler/optimizing/nodes_arm64.h b/compiler/optimizing/nodes_arm64.h index 75a71e78b8..173852a55d 100644 --- a/compiler/optimizing/nodes_arm64.h +++ b/compiler/optimizing/nodes_arm64.h @@ -118,66 +118,6 @@ class HArm64IntermediateAddress : public HExpression<2> { DISALLOW_COPY_AND_ASSIGN(HArm64IntermediateAddress); }; -class HArm64BitwiseNegatedRight : public HBinaryOperation { - public: - HArm64BitwiseNegatedRight(Primitive::Type result_type, - InstructionKind op, - HInstruction* left, - HInstruction* right, - uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc), - op_kind_(op) { - DCHECK(op == HInstruction::kAnd || op == HInstruction::kOr || op == HInstruction::kXor) << op; - } - - template <typename T, typename U> - auto Compute(T x, U y) const -> decltype(x & ~y) { - static_assert(std::is_same<decltype(x & ~y), decltype(x | ~y)>::value && - std::is_same<decltype(x & ~y), decltype(x ^ ~y)>::value, - "Inconsistent negated bitwise types"); - switch (op_kind_) { - case HInstruction::kAnd: - return x & ~y; - case HInstruction::kOr: - return x | ~y; - case HInstruction::kXor: - return x ^ ~y; - default: - LOG(FATAL) << "Unreachable"; - UNREACHABLE(); - } - } - - HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetIntConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); - } - HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { - return GetBlock()->GetGraph()->GetLongConstant( - Compute(x->GetValue(), y->GetValue()), GetDexPc()); - } - HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, - HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { - LOG(FATAL) << DebugName() << " is not defined for float values"; - UNREACHABLE(); - } - HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, - HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { - LOG(FATAL) << DebugName() << " is not defined for double values"; - UNREACHABLE(); - } - - InstructionKind GetOpKind() const { return op_kind_; } - - DECLARE_INSTRUCTION(Arm64BitwiseNegatedRight); - - private: - // Specifies the bitwise operation, which will be then negated. - const InstructionKind op_kind_; - - DISALLOW_COPY_AND_ASSIGN(HArm64BitwiseNegatedRight); -}; - } // namespace art #endif // ART_COMPILER_OPTIMIZING_NODES_ARM64_H_ diff --git a/compiler/optimizing/nodes_shared.h b/compiler/optimizing/nodes_shared.h index b04b622838..c10c718ff4 100644 --- a/compiler/optimizing/nodes_shared.h +++ b/compiler/optimizing/nodes_shared.h @@ -53,6 +53,66 @@ class HMultiplyAccumulate : public HExpression<3> { DISALLOW_COPY_AND_ASSIGN(HMultiplyAccumulate); }; +class HBitwiseNegatedRight : public HBinaryOperation { + public: + HBitwiseNegatedRight(Primitive::Type result_type, + InstructionKind op, + HInstruction* left, + HInstruction* right, + uint32_t dex_pc = kNoDexPc) + : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc), + op_kind_(op) { + DCHECK(op == HInstruction::kAnd || op == HInstruction::kOr || op == HInstruction::kXor) << op; + } + + template <typename T, typename U> + auto Compute(T x, U y) const -> decltype(x & ~y) { + static_assert(std::is_same<decltype(x & ~y), decltype(x | ~y)>::value && + std::is_same<decltype(x & ~y), decltype(x ^ ~y)>::value, + "Inconsistent negated bitwise types"); + switch (op_kind_) { + case HInstruction::kAnd: + return x & ~y; + case HInstruction::kOr: + return x | ~y; + case HInstruction::kXor: + return x ^ ~y; + default: + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); + } + } + + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetLongConstant( + Compute(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for float values"; + UNREACHABLE(); + } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { + LOG(FATAL) << DebugName() << " is not defined for double values"; + UNREACHABLE(); + } + + InstructionKind GetOpKind() const { return op_kind_; } + + DECLARE_INSTRUCTION(BitwiseNegatedRight); + + private: + // Specifies the bitwise operation, which will be then negated. + const InstructionKind op_kind_; + + DISALLOW_COPY_AND_ASSIGN(HBitwiseNegatedRight); +}; + } // namespace art #endif // ART_COMPILER_OPTIMIZING_NODES_SHARED_H_ |