diff options
author | 2024-05-30 17:05:54 +0500 | |
---|---|---|
committer | 2024-06-12 10:42:45 +0000 | |
commit | b658a268e2e76e429702c2929d24ebbbf909e947 (patch) | |
tree | 2366f34aecd290dcc988dbb3d1923e9471d8370e | |
parent | 05e428dacb0b4877960e3b1c0d50cb9c90f378d5 (diff) |
riscv: Expand BitwiseNegatedRight to riscv64, optimize
Add BitwiseNegatedRight optimization for riscv:
And + Not -> AndNot
Or + Not -> OrNot
Xor + Not -> XorNot
By compiling facebook app using dex2oat I got:
169 cases of And + Not pattern
9 cases of Or + Not pattern
1 case of Xor + Not pattern.
Test: art/test/testrunner/testrunner.py --target --64 --ndebug --optimizing
Change-Id: Icc2db96770378005d2fb01176298a067e1a0e4ad
-rw-r--r-- | compiler/optimizing/code_generator_riscv64.cc | 31 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 10 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 10 | ||||
-rw-r--r-- | compiler/optimizing/graph_visualizer.cc | 6 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 72 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier.h | 13 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_arm.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_arm64.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_riscv64.cc | 26 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_shared.cc | 73 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_shared.h | 12 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 59 | ||||
-rw-r--r-- | compiler/optimizing/nodes_shared.h | 70 | ||||
-rw-r--r-- | test/564-checker-negbitwise/src/Main.java | 134 |
14 files changed, 359 insertions, 159 deletions
diff --git a/compiler/optimizing/code_generator_riscv64.cc b/compiler/optimizing/code_generator_riscv64.cc index 75d5db83a0..8581c38895 100644 --- a/compiler/optimizing/code_generator_riscv64.cc +++ b/compiler/optimizing/code_generator_riscv64.cc @@ -5440,6 +5440,37 @@ void InstructionCodeGeneratorRISCV64::VisitRiscv64ShiftAdd(HRiscv64ShiftAdd* ins } } +void LocationsBuilderRISCV64::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) { + DCHECK(codegen_->GetInstructionSetFeatures().HasZbb()); + DCHECK(DataType::IsIntegralType(instruction->GetType())) << instruction->GetType(); + + LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); +} + +void InstructionCodeGeneratorRISCV64::VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) { + LocationSummary* locations = instruction->GetLocations(); + XRegister lhs = locations->InAt(0).AsRegister<XRegister>(); + XRegister rhs = locations->InAt(1).AsRegister<XRegister>(); + XRegister dst = locations->Out().AsRegister<XRegister>(); + + switch (instruction->GetOpKind()) { + case HInstruction::kAnd: + __ Andn(dst, lhs, rhs); + break; + case HInstruction::kOr: + __ Orn(dst, lhs, rhs); + break; + case HInstruction::kXor: + __ Xnor(dst, lhs, rhs); + break; + default: + LOG(FATAL) << "Unreachable"; + } +} + void LocationsBuilderRISCV64::VisitVecReplicateScalar(HVecReplicateScalar* instruction) { UNUSED(instruction); LOG(FATAL) << "Unimplemented"; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 2f6dde3df7..f549da189f 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -9302,6 +9302,16 @@ bool InstructionCodeGeneratorX86::CpuHasAvx2FeatureFlag() { return codegen_->GetInstructionSetFeatures().HasAVX2(); } +void LocationsBuilderX86::VisitBitwiseNegatedRight( + [[maybe_unused]] HBitwiseNegatedRight* instruction) { + LOG(FATAL) << "Unimplemented"; +} + +void InstructionCodeGeneratorX86::VisitBitwiseNegatedRight( + [[maybe_unused]] HBitwiseNegatedRight* instruction) { + LOG(FATAL) << "Unimplemented"; +} + #undef __ } // namespace x86 diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 5c9ee8fea4..e2b4344be9 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -8561,6 +8561,16 @@ bool InstructionCodeGeneratorX86_64::CpuHasAvx2FeatureFlag() { return codegen_->GetInstructionSetFeatures().HasAVX2(); } +void LocationsBuilderX86_64::VisitBitwiseNegatedRight( + [[maybe_unused]] HBitwiseNegatedRight* instruction) { + LOG(FATAL) << "Unimplemented"; +} + +void InstructionCodeGeneratorX86_64::VisitBitwiseNegatedRight( + [[maybe_unused]] HBitwiseNegatedRight* instruction) { + LOG(FATAL) << "Unimplemented"; +} + #undef __ } // namespace x86_64 diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index bc8ebb5917..46db4489d6 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -628,12 +628,12 @@ class HGraphVisualizerPrinter final : public HGraphDelegateVisitor { DataType::ToSigned(arg_type)); } -#if defined(ART_ENABLE_CODEGEN_arm) || defined(ART_ENABLE_CODEGEN_arm64) - void VisitMultiplyAccumulate(HMultiplyAccumulate* instruction) override { + void VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) override { StartAttributeStream("kind") << instruction->GetOpKind(); } - void VisitBitwiseNegatedRight(HBitwiseNegatedRight* instruction) override { +#if defined(ART_ENABLE_CODEGEN_arm) || defined(ART_ENABLE_CODEGEN_arm64) + void VisitMultiplyAccumulate(HMultiplyAccumulate* instruction) override { StartAttributeStream("kind") << instruction->GetOpKind(); } diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 56bbd8017f..e972e4795e 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -3405,4 +3405,76 @@ void InstructionSimplifierVisitor::VisitVecMul(HVecMul* instruction) { } } +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()->GetAllocator()) + HBitwiseNegatedRight(op->GetType(), op->GetKind(), hother, src, op->GetDexPc()); + + op->GetBlock()->ReplaceAndRemoveInstructionWith(op, neg_op); + hnot->GetBlock()->RemoveInstruction(hnot); + return true; + } + } + + return false; +} + +bool TryMergeWithAnd(HSub* instruction) { + HAnd* and_instr = instruction->GetRight()->AsAndOrNull(); + if (and_instr == nullptr) { + return false; + } + + HInstruction* value = instruction->GetLeft(); + + HInstruction* left = and_instr->GetLeft(); + const bool left_is_equal = left == value; + HInstruction* right = and_instr->GetRight(); + const bool right_is_equal = right == value; + if (!left_is_equal && !right_is_equal) { + return false; + } + + HBitwiseNegatedRight* bnr = new (instruction->GetBlock()->GetGraph()->GetAllocator()) + HBitwiseNegatedRight(instruction->GetType(), + HInstruction::InstructionKind::kAnd, + value, + left_is_equal ? right : left, + instruction->GetDexPc()); + instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bnr); + // Since we don't run DCE after this phase, try to manually remove the And instruction. + if (!and_instr->HasUses()) { + and_instr->GetBlock()->RemoveInstruction(and_instr); + } + return true; +} + } // namespace art diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h index 98ebaafebc..6f9e1f334e 100644 --- a/compiler/optimizing/instruction_simplifier.h +++ b/compiler/optimizing/instruction_simplifier.h @@ -60,6 +60,19 @@ class InstructionSimplifier : public HOptimization { DISALLOW_COPY_AND_ASSIGN(InstructionSimplifier); }; +// For bitwise operations (And/Or/Xor) with a negated input, try to use +// a negated bitwise instruction. +bool TryMergeNegatedInput(HBinaryOperation* op); + +// Convert +// i1: AND a, b +// SUB a, i1 +// into: +// BIC a, a, b +// +// It also works if `i1` is AND b, a +bool TryMergeWithAnd(HSub* instruction); + } // namespace art #endif // ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_H_ diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc index aefa27628b..a050f86363 100644 --- a/compiler/optimizing/instruction_simplifier_arm.cc +++ b/compiler/optimizing/instruction_simplifier_arm.cc @@ -18,6 +18,7 @@ #include "code_generator.h" #include "common_arm.h" +#include "instruction_simplifier.h" #include "instruction_simplifier_shared.h" #include "mirror/array-inl.h" #include "mirror/string.h" diff --git a/compiler/optimizing/instruction_simplifier_arm64.cc b/compiler/optimizing/instruction_simplifier_arm64.cc index d0fbe1382b..f57448d70f 100644 --- a/compiler/optimizing/instruction_simplifier_arm64.cc +++ b/compiler/optimizing/instruction_simplifier_arm64.cc @@ -17,6 +17,7 @@ #include "instruction_simplifier_arm64.h" #include "common_arm64.h" +#include "instruction_simplifier.h" #include "instruction_simplifier_shared.h" #include "mirror/array-inl.h" #include "mirror/string.h" diff --git a/compiler/optimizing/instruction_simplifier_riscv64.cc b/compiler/optimizing/instruction_simplifier_riscv64.cc index 0b9f8c58b1..8f47f66d8b 100644 --- a/compiler/optimizing/instruction_simplifier_riscv64.cc +++ b/compiler/optimizing/instruction_simplifier_riscv64.cc @@ -16,6 +16,8 @@ #include "instruction_simplifier_riscv64.h" +#include "instruction_simplifier.h" + namespace art HIDDEN { namespace riscv64 { @@ -86,6 +88,30 @@ class InstructionSimplifierRiscv64Visitor final : public HGraphVisitor { } } + void VisitAnd(HAnd* inst) override { + if (TryMergeNegatedInput(inst)) { + RecordSimplification(); + } + } + + void VisitOr(HOr* inst) override { + if (TryMergeNegatedInput(inst)) { + RecordSimplification(); + } + } + + void VisitSub(HSub* inst) override { + if (TryMergeWithAnd(inst)) { + RecordSimplification(); + } + } + + void VisitXor(HXor* inst) override { + if (TryMergeNegatedInput(inst)) { + RecordSimplification(); + } + } + OptimizingCompilerStats* stats_ = nullptr; }; diff --git a/compiler/optimizing/instruction_simplifier_shared.cc b/compiler/optimizing/instruction_simplifier_shared.cc index deb8f93492..b7d76da548 100644 --- a/compiler/optimizing/instruction_simplifier_shared.cc +++ b/compiler/optimizing/instruction_simplifier_shared.cc @@ -187,79 +187,6 @@ 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()->GetAllocator()) - HBitwiseNegatedRight(op->GetType(), op->GetKind(), hother, src, op->GetDexPc()); - - op->GetBlock()->ReplaceAndRemoveInstructionWith(op, neg_op); - hnot->GetBlock()->RemoveInstruction(hnot); - return true; - } - } - - return false; -} - -bool TryMergeWithAnd(HSub* instruction) { - HAnd* and_instr = instruction->GetRight()->AsAndOrNull(); - if (and_instr == nullptr) { - return false; - } - - HInstruction* value = instruction->GetLeft(); - - HInstruction* left = and_instr->GetLeft(); - const bool left_is_equal = left == value; - HInstruction* right = and_instr->GetRight(); - const bool right_is_equal = right == value; - if (!left_is_equal && !right_is_equal) { - return false; - } - - HBitwiseNegatedRight* bnr = new (instruction->GetBlock()->GetGraph()->GetAllocator()) - HBitwiseNegatedRight(instruction->GetType(), - HInstruction::InstructionKind::kAnd, - value, - left_is_equal ? right : left, - instruction->GetDexPc()); - instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, bnr); - // Since we don't run DCE after this phase, try to manually remove the And instruction. - if (!and_instr->HasUses()) { - and_instr->GetBlock()->RemoveInstruction(and_instr); - } - return true; -} - bool TryExtractArrayAccessAddress(CodeGenerator* codegen, HInstruction* access, HInstruction* array, diff --git a/compiler/optimizing/instruction_simplifier_shared.h b/compiler/optimizing/instruction_simplifier_shared.h index ca6d5286c5..de70ec5a8a 100644 --- a/compiler/optimizing/instruction_simplifier_shared.h +++ b/compiler/optimizing/instruction_simplifier_shared.h @@ -62,18 +62,6 @@ inline bool IsSubRightSubLeftShl(HSub *sub) { } // namespace helpers 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); - -// Convert -// i1: AND a, b -// SUB a, i1 -// into: -// BIC a, a, b -// -// It also works if `i1` is AND b, a -bool TryMergeWithAnd(HSub* instruction); bool TryExtractArrayAccessAddress(CodeGenerator* codegen, HInstruction* access, diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 89369f59f1..1e3aca64db 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1527,6 +1527,7 @@ class HLoopInformationOutwardIterator : public ValueObject { M(ArraySet, Instruction) \ M(Below, Condition) \ M(BelowOrEqual, Condition) \ + M(BitwiseNegatedRight, BinaryOperation) \ M(BooleanNot, UnaryOperation) \ M(BoundsCheck, Instruction) \ M(BoundType, Instruction) \ @@ -1657,7 +1658,6 @@ class HLoopInformationOutwardIterator : public ValueObject { #define FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) #else #define FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) \ - M(BitwiseNegatedRight, Instruction) \ M(DataProcWithShifterOp, Instruction) \ M(MultiplyAccumulate, Instruction) \ M(IntermediateAddressIndex, Instruction) @@ -8389,6 +8389,63 @@ class HParallelMove final : public HExpression<0> { ArenaVector<MoveOperands> moves_; }; +class HBitwiseNegatedRight final : public HBinaryOperation { + public: + HBitwiseNegatedRight(DataType::Type result_type, + InstructionKind op, + HInstruction* left, + HInstruction* right, + uint32_t dex_pc = kNoDexPc) + : HBinaryOperation( + kBitwiseNegatedRight, 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(); + } + } + + bool InstructionDataEquals(const HInstruction* other) const override { + return op_kind_ == other->AsBitwiseNegatedRight()->op_kind_; + } + + 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()); + } + + InstructionKind GetOpKind() const { return op_kind_; } + + DECLARE_INSTRUCTION(BitwiseNegatedRight); + + protected: + DEFAULT_COPY_CONSTRUCTOR(BitwiseNegatedRight); + + private: + // Specifies the bitwise operation, which will be then negated. + const InstructionKind op_kind_; +}; + // This instruction computes an intermediate address pointing in the 'middle' of an object. The // result pointer cannot be handled by GC, so extra care is taken to make sure that this value is // never used across anything that can trigger GC. diff --git a/compiler/optimizing/nodes_shared.h b/compiler/optimizing/nodes_shared.h index d627c6daee..abb9f959c0 100644 --- a/compiler/optimizing/nodes_shared.h +++ b/compiler/optimizing/nodes_shared.h @@ -62,76 +62,6 @@ class HMultiplyAccumulate final : public HExpression<3> { const InstructionKind op_kind_; }; -class HBitwiseNegatedRight final : public HBinaryOperation { - public: - HBitwiseNegatedRight(DataType::Type result_type, - InstructionKind op, - HInstruction* left, - HInstruction* right, - uint32_t dex_pc = kNoDexPc) - : HBinaryOperation(kBitwiseNegatedRight, - 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(); - } - } - - bool InstructionDataEquals(const HInstruction* other) const override { - return op_kind_ == other->AsBitwiseNegatedRight()->op_kind_; - } - - 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([[maybe_unused]] HFloatConstant* x, - [[maybe_unused]] HFloatConstant* y) const override { - LOG(FATAL) << DebugName() << " is not defined for float values"; - UNREACHABLE(); - } - HConstant* Evaluate([[maybe_unused]] HDoubleConstant* x, - [[maybe_unused]] HDoubleConstant* y) const override { - LOG(FATAL) << DebugName() << " is not defined for double values"; - UNREACHABLE(); - } - - InstructionKind GetOpKind() const { return op_kind_; } - - DECLARE_INSTRUCTION(BitwiseNegatedRight); - - protected: - DEFAULT_COPY_CONSTRUCTOR(BitwiseNegatedRight); - - private: - // Specifies the bitwise operation, which will be then negated. - const InstructionKind op_kind_; -}; - // This instruction computes part of the array access offset (data and index offset). // // For array accesses the element address has the following structure: diff --git a/test/564-checker-negbitwise/src/Main.java b/test/564-checker-negbitwise/src/Main.java index 0387af48e4..6f38542b0c 100644 --- a/test/564-checker-negbitwise/src/Main.java +++ b/test/564-checker-negbitwise/src/Main.java @@ -73,6 +73,27 @@ public class Main { /// CHECK-START-ARM: int Main.$opt$noinline$notAnd(int, int) disassembly (after) /// CHECK: bic r{{\d+}}, r{{\d+}}, r{{\d+}} + + /// CHECK-START-RISCV64: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_riscv64 (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-RISCV64: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_riscv64 (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-RISCV64: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Not + /// CHECK-NOT: And + + /// CHECK-START-RISCV64: int Main.$opt$noinline$notAnd(int, int) disassembly (after) + /// CHECK: andn a{{\d+}}, a{{\d+}}, a{{\d+}} + public static int $opt$noinline$notAnd(int base, int mask) { return base & ~mask; } @@ -122,6 +143,27 @@ public class Main { /// CHECK-START-ARM: long Main.$opt$noinline$notOr(long, long) disassembly (after) /// CHECK: orn r{{\d+}}, r{{\d+}}, r{{\d+}} + + /// CHECK-START-RISCV64: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_riscv64 (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-RISCV64: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_riscv64 (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-RISCV64: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Not + /// CHECK-NOT: Or + + /// CHECK-START-RISCV64: long Main.$opt$noinline$notOr(long, long) disassembly (after) + /// CHECK: orn a{{\d+}}, a{{\d+}}, a{{\d+}} + public static long $opt$noinline$notOr(long base, long mask) { return base | ~mask; } @@ -168,6 +210,27 @@ public class Main { /// CHECK-START-ARM: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_arm (after) /// CHECK-NOT: BitwiseNegatedRight + + /// CHECK-START-RISCV64: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_riscv64 (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-RISCV64: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_riscv64 (after) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<NegOp:i\d+>> BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:Xor + /// CHECK: Return [<<NegOp>>] + + /// CHECK-START-RISCV64: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Not + /// CHECK-NOT: Xor + + /// CHECK-START-RISCV64: int Main.$opt$noinline$notXor(int, int) disassembly (after) + /// CHECK: xnor a{{\d+}}, a{{\d+}}, a{{\d+}} + public static int $opt$noinline$notXor(int base, int mask) { return base ^ ~mask; } @@ -203,6 +266,20 @@ public class Main { /// CHECK: <<NegOp:i\d+>> BitwiseNegatedRight [<<Constant>>,<<Base>>] kind:And /// CHECK: Return [<<NegOp>>] + + /// CHECK-START-RISCV64: int Main.$opt$noinline$notAndConstant(int) instruction_simplifier_riscv64 (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-RISCV64: int Main.$opt$noinline$notAndConstant(int) instruction_simplifier_riscv64 (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$notAndConstant(int mask) { return 0xf & ~mask; } @@ -258,6 +335,30 @@ public class Main { /// CHECK-START-ARM: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_arm (after) /// CHECK-NOT: BitwiseNegatedRight + + /// CHECK-START-RISCV64: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_riscv64 (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-RISCV64: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_riscv64 (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-RISCV64: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: BitwiseNegatedRight + public static int $opt$noinline$notAndMultipleUses(int base, int mask) { int tmp = ~mask; return (tmp & 0x1) + (base & tmp); @@ -276,6 +377,9 @@ public class Main { /// CHECK-START-ARM: int Main.$opt$noinline$deMorganOr(int, int) instruction_simplifier_arm (after) /// CHECK-NOT: BitwiseNegatedRight + /// CHECK-START-RISCV64: int Main.$opt$noinline$deMorganOr(int, int) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: BitwiseNegatedRight + public static int $opt$noinline$deMorganOr(int a, int b) { return ~a | ~b; } @@ -309,6 +413,21 @@ public class Main { /// CHECK-START-ARM64: int Main.$noinline$AndSubIntoBic(int, int) instruction_simplifier_arm64 (after) /// CHECK: BitwiseNegatedRight kind:And + + + /// CHECK-START-RISCV64: int Main.$noinline$AndSubIntoBic(int, int) instruction_simplifier_riscv64 (before) + /// CHECK: <<HAnd:i\d+>> And [<<Left:i\d+>>,<<Right:i\d+>>] + /// CHECK: Sub [<<Left>>,<<HAnd>>] + + /// CHECK-START-RISCV64: int Main.$noinline$AndSubIntoBic(int, int) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: And + + /// CHECK-START-RISCV64: int Main.$noinline$AndSubIntoBic(int, int) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Sub + + /// CHECK-START-RISCV64: int Main.$noinline$AndSubIntoBic(int, int) instruction_simplifier_riscv64 (after) + /// CHECK: BitwiseNegatedRight kind:And + public static int $noinline$AndSubIntoBic(int a, int b) { return a - (a & b); } @@ -342,6 +461,21 @@ public class Main { /// CHECK-START-ARM64: int Main.$noinline$AndSubIntoBic_v2(int, int) instruction_simplifier_arm64 (after) /// CHECK: BitwiseNegatedRight kind:And + + + /// CHECK-START-RISCV64: int Main.$noinline$AndSubIntoBic_v2(int, int) instruction_simplifier_riscv64 (before) + /// CHECK: <<HAnd:i\d+>> And [<<Left:i\d+>>,<<Right:i\d+>>] + /// CHECK: Sub [<<Right>>,<<HAnd>>] + + /// CHECK-START-RISCV64: int Main.$noinline$AndSubIntoBic_v2(int, int) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: And + + /// CHECK-START-RISCV64: int Main.$noinline$AndSubIntoBic_v2(int, int) instruction_simplifier_riscv64 (after) + /// CHECK-NOT: Sub + + /// CHECK-START-RISCV64: int Main.$noinline$AndSubIntoBic_v2(int, int) instruction_simplifier_riscv64 (after) + /// CHECK: BitwiseNegatedRight kind:And + public static int $noinline$AndSubIntoBic_v2(int a, int b) { return b - (a & b); } |