diff options
author | 2016-02-09 17:15:29 +0000 | |
---|---|---|
committer | 2016-03-11 12:49:27 +0000 | |
commit | 7fc6350f6f1ab04b52b9cd7542e0790528296cbe (patch) | |
tree | 26a33ef7bb2e49a9b7c7d9436194a92cb447b317 | |
parent | b7f257f353b1eb2db2732939a0404c118316891d (diff) |
Integrate BitwiseNegated into shared framework.
Share implementation between arm and arm64.
Change-Id: I0dd12e772cb23b4c181fd0b1e2a447470b1d8702
-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 | ||||
-rw-r--r-- | test/564-checker-negbitwise/src/Main.java | 137 |
13 files changed, 316 insertions, 139 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_ diff --git a/test/564-checker-negbitwise/src/Main.java b/test/564-checker-negbitwise/src/Main.java index 3de7be7161..ccb8ff4fdf 100644 --- a/test/564-checker-negbitwise/src/Main.java +++ b/test/564-checker-negbitwise/src/Main.java @@ -45,7 +45,7 @@ public class Main { /// CHECK-START-ARM64: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_arm64 (after) /// CHECK: <<Base:i\d+>> ParameterValue /// CHECK: <<Mask:i\d+>> ParameterValue - /// CHECK: <<NegOp:i\d+>> Arm64BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:And + /// CHECK: <<NegOp:i\d+>> BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:And /// CHECK: Return [<<NegOp>>] /// CHECK-START-ARM64: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_arm64 (after) @@ -55,6 +55,27 @@ public class Main { /// CHECK-START-ARM64: int Main.$opt$noinline$notAnd(int, int) disassembly (after) /// CHECK: bic w{{\d+}}, w{{\d+}}, w{{\d+}} + + /// CHECK-START-ARM: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_arm (before) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<Not:i\d+>> Not [<<Mask>>] + /// CHECK: <<Op:i\d+>> And [<<Base>>,<<Not>>] + /// CHECK: Return [<<Op>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_arm (after) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<NegOp:i\d+>> BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:And + /// CHECK: Return [<<NegOp>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_arm (after) + /// CHECK-NOT: Not + /// CHECK-NOT: And + + /// CHECK-START-ARM: int Main.$opt$noinline$notAnd(int, int) disassembly (after) + /// CHECK: bic.w r{{\d+}}, r{{\d+}}, r{{\d+}} + public static int $opt$noinline$notAnd(int base, int mask) { if (doThrow) throw new Error(); return base & ~mask; @@ -74,7 +95,7 @@ public class Main { /// CHECK-START-ARM64: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_arm64 (after) /// CHECK: <<Base:j\d+>> ParameterValue /// CHECK: <<Mask:j\d+>> ParameterValue - /// CHECK: <<NegOp:j\d+>> Arm64BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:Or + /// CHECK: <<NegOp:j\d+>> BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:Or /// CHECK: Return [<<NegOp>>] /// CHECK-START-ARM64: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_arm64 (after) @@ -84,6 +105,27 @@ public class Main { /// CHECK-START-ARM64: long Main.$opt$noinline$notOr(long, long) disassembly (after) /// CHECK: orn x{{\d+}}, x{{\d+}}, x{{\d+}} + + /// CHECK-START-ARM: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_arm (before) + /// CHECK: <<Base:j\d+>> ParameterValue + /// CHECK: <<Mask:j\d+>> ParameterValue + /// CHECK: <<Not:j\d+>> Not [<<Mask>>] + /// CHECK: <<Op:j\d+>> Or [<<Base>>,<<Not>>] + /// CHECK: Return [<<Op>>] + + /// CHECK-START-ARM: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_arm (after) + /// CHECK: <<Base:j\d+>> ParameterValue + /// CHECK: <<Mask:j\d+>> ParameterValue + /// CHECK: <<NegOp:j\d+>> BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:Or + /// CHECK: Return [<<NegOp>>] + + /// CHECK-START-ARM: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_arm (after) + /// CHECK-NOT: Not + /// CHECK-NOT: Or + + /// CHECK-START-ARM: long Main.$opt$noinline$notOr(long, long) disassembly (after) + /// CHECK: orn.w r{{\d+}}, r{{\d+}}, r{{\d+}} + public static long $opt$noinline$notOr(long base, long mask) { if (doThrow) throw new Error(); return base | ~mask; @@ -103,7 +145,7 @@ public class Main { /// CHECK-START-ARM64: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_arm64 (after) /// CHECK: <<Base:i\d+>> ParameterValue /// CHECK: <<Mask:i\d+>> ParameterValue - /// CHECK: <<NegOp:i\d+>> Arm64BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:Xor + /// CHECK: <<NegOp:i\d+>> BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:Xor /// CHECK: Return [<<NegOp>>] /// CHECK-START-ARM64: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_arm64 (after) @@ -113,39 +155,63 @@ public class Main { /// CHECK-START-ARM64: int Main.$opt$noinline$notXor(int, int) disassembly (after) /// CHECK: eon w{{\d+}}, w{{\d+}}, w{{\d+}} + + /// CHECK-START-ARM: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_arm (before) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<Not:i\d+>> Not [<<Mask>>] + /// CHECK: <<Op:i\d+>> Xor [<<Base>>,<<Not>>] + /// CHECK: Return [<<Op>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_arm (after) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<Not:i\d+>> Not [<<Mask>>] + /// CHECK: <<Op:i\d+>> Xor [<<Base>>,<<Not>>] + /// CHECK: Return [<<Op>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_arm (after) + /// CHECK-NOT: BitwiseNegatedRight + public static int $opt$noinline$notXor(int base, int mask) { if (doThrow) throw new Error(); return base ^ ~mask; } /** - * Check that the transformation is also done when the base is a constant. + * Check that transformation is done when the argument is a constant. */ - /// CHECK-START-ARM64: int Main.$opt$noinline$notXorConstant(int) instruction_simplifier_arm64 (before) - /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK-START-ARM64: int Main.$opt$noinline$notAndConstant(int) instruction_simplifier_arm64 (before) + /// CHECK: <<Base:i\d+>> ParameterValue /// CHECK: <<Constant:i\d+>> IntConstant - /// CHECK: <<Not:i\d+>> Not [<<Mask>>] - /// CHECK: <<Op:i\d+>> Xor [<<Not>>,<<Constant>>] + /// CHECK: <<Not:i\d+>> Not [<<Base>>] + /// CHECK: <<Op:i\d+>> And [<<Not>>,<<Constant>>] /// CHECK: Return [<<Op>>] - /// CHECK-START-ARM64: int Main.$opt$noinline$notXorConstant(int) instruction_simplifier_arm64 (after) - /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK-START-ARM64: int Main.$opt$noinline$notAndConstant(int) instruction_simplifier_arm64 (after) + /// CHECK: <<Base:i\d+>> ParameterValue /// CHECK: <<Constant:i\d+>> IntConstant - /// CHECK: <<NegOp:i\d+>> Arm64BitwiseNegatedRight [<<Constant>>,<<Mask>>] kind:Xor + /// CHECK: <<NegOp:i\d+>> BitwiseNegatedRight [<<Constant>>,<<Base>>] kind:And /// CHECK: Return [<<NegOp>>] - /// CHECK-START-ARM64: int Main.$opt$noinline$notXorConstant(int) instruction_simplifier_arm64 (after) - /// CHECK-NOT: Not - /// CHECK-NOT: Xor - /// CHECK-START-ARM64: int Main.$opt$noinline$notXorConstant(int) disassembly (after) - /// CHECK: mov <<Reg:w\d+>>, #0xf - /// CHECK: eon w{{\d+}}, <<Reg>>, w{{\d+}} + /// CHECK-START-ARM: int Main.$opt$noinline$notAndConstant(int) instruction_simplifier_arm (before) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Constant:i\d+>> IntConstant + /// CHECK: <<Not:i\d+>> Not [<<Base>>] + /// CHECK: <<Op:i\d+>> And [<<Not>>,<<Constant>>] + /// CHECK: Return [<<Op>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$notAndConstant(int) instruction_simplifier_arm (after) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Constant:i\d+>> IntConstant + /// CHECK: <<NegOp:i\d+>> BitwiseNegatedRight [<<Constant>>,<<Base>>] kind:And + /// CHECK: Return [<<NegOp>>] - public static int $opt$noinline$notXorConstant(int mask) { + public static int $opt$noinline$notAndConstant(int mask) { if (doThrow) throw new Error(); - return 0xf ^ ~mask; + return 0xf & ~mask; } /** @@ -173,7 +239,31 @@ public class Main { /// CHECK: Return [<<Add>>] /// CHECK-START-ARM64: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_arm64 (after) - /// CHECK-NOT: Arm64BitwiseNegatedRight + /// CHECK-NOT: BitwiseNegatedRight + + + /// CHECK-START-ARM: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_arm (before) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<One:i\d+>> IntConstant + /// CHECK: <<Not:i\d+>> Not [<<Mask>>] + /// CHECK: <<Op1:i\d+>> And [<<Not>>,<<One>>] + /// CHECK: <<Op2:i\d+>> And [<<Base>>,<<Not>>] + /// CHECK: <<Add:i\d+>> Add [<<Op1>>,<<Op2>>] + /// CHECK: Return [<<Add>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_arm (after) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<One:i\d+>> IntConstant + /// CHECK: <<Not:i\d+>> Not [<<Mask>>] + /// CHECK: <<Op1:i\d+>> And [<<Not>>,<<One>>] + /// CHECK: <<Op2:i\d+>> And [<<Base>>,<<Not>>] + /// CHECK: <<Add:i\d+>> Add [<<Op1>>,<<Op2>>] + /// CHECK: Return [<<Add>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_arm (after) + /// CHECK-NOT: BitwiseNegatedRight public static int $opt$noinline$notAndMultipleUses(int base, int mask) { if (doThrow) throw new Error(); @@ -189,7 +279,10 @@ public class Main { // have been applied then Not/Not/Or is replaced by And/Not. /// CHECK-START-ARM64: int Main.$opt$noinline$deMorganOr(int, int) instruction_simplifier_arm64 (after) - /// CHECK-NOT: Arm64BitwiseNegatedRight + /// CHECK-NOT: BitwiseNegatedRight + + /// CHECK-START-ARM: int Main.$opt$noinline$deMorganOr(int, int) instruction_simplifier_arm (after) + /// CHECK-NOT: BitwiseNegatedRight public static int $opt$noinline$deMorganOr(int a, int b) { if (doThrow) throw new Error(); @@ -200,7 +293,7 @@ public class Main { assertIntEquals(0xe, $opt$noinline$notAnd(0xf, 0x1)); assertLongEquals(~0x0, $opt$noinline$notOr(0xf, 0x1)); assertIntEquals(~0xe, $opt$noinline$notXor(0xf, 0x1)); - assertIntEquals(~0xe, $opt$noinline$notXorConstant(0x1)); + assertIntEquals(0xe, $opt$noinline$notAndConstant(0x1)); assertIntEquals(0xe, $opt$noinline$notAndMultipleUses(0xf, 0x1)); assertIntEquals(~0x1, $opt$noinline$deMorganOr(0x3, 0x1)); } |