diff options
-rw-r--r-- | compiler/Android.mk | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 27 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 34 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/graph_visualizer.cc | 10 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_arm.cc | 30 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_arm.h | 58 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_arm64.cc | 133 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_arm64.h | 4 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_shared.cc | 189 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_shared.h | 28 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 17 | ||||
-rw-r--r-- | compiler/optimizing/nodes_arm64.h | 34 | ||||
-rw-r--r-- | compiler/optimizing/nodes_shared.h | 58 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 6 | ||||
-rw-r--r-- | test/550-checker-multiply-accumulate/src/Main.java | 235 |
17 files changed, 191 insertions, 678 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index 6eeef3f567..458973684e 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -143,9 +143,7 @@ LIBART_COMPILER_SRC_FILES_arm64 := \ jni/quick/arm64/calling_convention_arm64.cc \ linker/arm64/relative_patcher_arm64.cc \ optimizing/code_generator_arm64.cc \ - optimizing/instruction_simplifier_arm.cc \ optimizing/instruction_simplifier_arm64.cc \ - optimizing/instruction_simplifier_shared.cc \ optimizing/intrinsics_arm64.cc \ utils/arm64/assembler_arm64.cc \ utils/arm64/managed_register_arm64.cc \ diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index f265a0c7d3..272579219f 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -6449,33 +6449,6 @@ Literal* CodeGeneratorARM::DeduplicateMethodCodeLiteral(MethodReference target_m return DeduplicateMethodLiteral(target_method, &call_patches_); } -void LocationsBuilderARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) { - LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall); - locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex, - Location::RequiresRegister()); - locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister()); - locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); -} - -void InstructionCodeGeneratorARM::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) { - LocationSummary* locations = instr->GetLocations(); - Register res = locations->Out().AsRegister<Register>(); - Register accumulator = locations->InAt(HMultiplyAccumulate::kInputAccumulatorIndex) - .AsRegister<Register>(); - Register mul_left = locations->InAt(HMultiplyAccumulate::kInputMulLeftIndex) - .AsRegister<Register>(); - Register mul_right = locations->InAt(HMultiplyAccumulate::kInputMulRightIndex) - .AsRegister<Register>(); - - if (instr->GetOpKind() == HInstruction::kAdd) { - __ mla(res, mul_left, mul_right, accumulator); - } else { - __ mls(res, mul_left, mul_right, accumulator); - } -} - void LocationsBuilderARM::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) { // Nothing to do, this should be removed during prepare for register allocator. LOG(FATAL) << "Unreachable"; diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index df2126c653..d45ea973f9 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -159,7 +159,6 @@ class LocationsBuilderARM : public HGraphVisitor { FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION) - FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION) #undef DECLARE_VISIT_INSTRUCTION @@ -198,7 +197,6 @@ class InstructionCodeGeneratorARM : public InstructionCodeGenerator { FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION) - FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION) #undef DECLARE_VISIT_INSTRUCTION diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 3fdd7186d1..3d65e9c53c 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -1952,27 +1952,21 @@ void InstructionCodeGeneratorARM64::VisitArm64IntermediateAddress( Operand(InputOperandAt(instruction, 1))); } -void LocationsBuilderARM64::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) { +void LocationsBuilderARM64::VisitArm64MultiplyAccumulate(HArm64MultiplyAccumulate* instr) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr, LocationSummary::kNoCall); - HInstruction* accumulator = instr->InputAt(HMultiplyAccumulate::kInputAccumulatorIndex); - if (instr->GetOpKind() == HInstruction::kSub && - accumulator->IsConstant() && - accumulator->AsConstant()->IsZero()) { - // Don't allocate register for Mneg instruction. - } else { - locations->SetInAt(HMultiplyAccumulate::kInputAccumulatorIndex, - Location::RequiresRegister()); - } - locations->SetInAt(HMultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister()); - locations->SetInAt(HMultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister()); + locations->SetInAt(HArm64MultiplyAccumulate::kInputAccumulatorIndex, + Location::RequiresRegister()); + locations->SetInAt(HArm64MultiplyAccumulate::kInputMulLeftIndex, Location::RequiresRegister()); + locations->SetInAt(HArm64MultiplyAccumulate::kInputMulRightIndex, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } -void InstructionCodeGeneratorARM64::VisitMultiplyAccumulate(HMultiplyAccumulate* instr) { +void InstructionCodeGeneratorARM64::VisitArm64MultiplyAccumulate(HArm64MultiplyAccumulate* instr) { Register res = OutputRegister(instr); - Register mul_left = InputRegisterAt(instr, HMultiplyAccumulate::kInputMulLeftIndex); - Register mul_right = InputRegisterAt(instr, HMultiplyAccumulate::kInputMulRightIndex); + Register accumulator = InputRegisterAt(instr, HArm64MultiplyAccumulate::kInputAccumulatorIndex); + Register mul_left = InputRegisterAt(instr, HArm64MultiplyAccumulate::kInputMulLeftIndex); + Register mul_right = InputRegisterAt(instr, HArm64MultiplyAccumulate::kInputMulRightIndex); // Avoid emitting code that could trigger Cortex A53's erratum 835769. // This fixup should be carried out for all multiply-accumulate instructions: @@ -1992,18 +1986,10 @@ void InstructionCodeGeneratorARM64::VisitMultiplyAccumulate(HMultiplyAccumulate* } if (instr->GetOpKind() == HInstruction::kAdd) { - Register accumulator = InputRegisterAt(instr, HMultiplyAccumulate::kInputAccumulatorIndex); __ Madd(res, mul_left, mul_right, accumulator); } else { DCHECK(instr->GetOpKind() == HInstruction::kSub); - HInstruction* accum_instr = instr->InputAt(HMultiplyAccumulate::kInputAccumulatorIndex); - if (accum_instr->IsConstant() && accum_instr->AsConstant()->IsZero()) { - __ Mneg(res, mul_left, mul_right); - } else { - Register accumulator = InputRegisterAt(instr, - HMultiplyAccumulate::kInputAccumulatorIndex); - __ Msub(res, mul_left, mul_right, accumulator); - } + __ Msub(res, mul_left, mul_right, accumulator); } } diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 98303f67ad..8eb9fcc558 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -195,7 +195,6 @@ class InstructionCodeGeneratorARM64 : public InstructionCodeGenerator { FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION) - FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION) #undef DECLARE_VISIT_INSTRUCTION @@ -246,7 +245,6 @@ class LocationsBuilderARM64 : public HGraphVisitor { FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION) - FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION) #undef DECLARE_VISIT_INSTRUCTION diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 3c88ba7ba7..32c3a925e0 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -426,12 +426,6 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { StartAttributeStream("kind") << (try_boundary->IsEntry() ? "entry" : "exit"); } -#if defined(ART_ENABLE_CODEGEN_arm) || defined(ART_ENABLE_CODEGEN_arm64) - void VisitMultiplyAccumulate(HMultiplyAccumulate* instruction) OVERRIDE { - StartAttributeStream("kind") << instruction->GetOpKind(); - } -#endif - #ifdef ART_ENABLE_CODEGEN_arm64 void VisitArm64DataProcWithShifterOp(HArm64DataProcWithShifterOp* instruction) OVERRIDE { StartAttributeStream("kind") << instruction->GetInstrKind() << "+" << instruction->GetOpKind(); @@ -439,6 +433,10 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { StartAttributeStream("shift") << instruction->GetShiftAmount(); } } + + void VisitArm64MultiplyAccumulate(HArm64MultiplyAccumulate* instruction) OVERRIDE { + StartAttributeStream("kind") << instruction->GetOpKind(); + } #endif bool IsPass(const char* name) { diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc deleted file mode 100644 index db1f9a79aa..0000000000 --- a/compiler/optimizing/instruction_simplifier_arm.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#include "instruction_simplifier_arm.h" -#include "instruction_simplifier_shared.h" - -namespace art { -namespace arm { - -void InstructionSimplifierArmVisitor::VisitMul(HMul* instruction) { - if (TryCombineMultiplyAccumulate(instruction, kArm)) { - RecordSimplification(); - } -} - -} // namespace arm -} // namespace art diff --git a/compiler/optimizing/instruction_simplifier_arm.h b/compiler/optimizing/instruction_simplifier_arm.h deleted file mode 100644 index 379b95d6ae..0000000000 --- a/compiler/optimizing/instruction_simplifier_arm.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_ARM_H_ -#define ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_ARM_H_ - -#include "nodes.h" -#include "optimization.h" - -namespace art { -namespace arm { - -class InstructionSimplifierArmVisitor : public HGraphVisitor { - public: - InstructionSimplifierArmVisitor(HGraph* graph, OptimizingCompilerStats* stats) - : HGraphVisitor(graph), stats_(stats) {} - - private: - void RecordSimplification() { - if (stats_ != nullptr) { - stats_->RecordStat(kInstructionSimplificationsArch); - } - } - - void VisitMul(HMul* instruction) OVERRIDE; - - OptimizingCompilerStats* stats_; -}; - - -class InstructionSimplifierArm : public HOptimization { - public: - InstructionSimplifierArm(HGraph* graph, OptimizingCompilerStats* stats) - : HOptimization(graph, "instruction_simplifier_arm", stats) {} - - void Run() OVERRIDE { - InstructionSimplifierArmVisitor visitor(graph_, stats_); - visitor.VisitReversePostOrder(); - } -}; - -} // namespace arm -} // namespace art - -#endif // ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_ARM_H_ diff --git a/compiler/optimizing/instruction_simplifier_arm64.cc b/compiler/optimizing/instruction_simplifier_arm64.cc index 83126a5c4d..4bcfc54791 100644 --- a/compiler/optimizing/instruction_simplifier_arm64.cc +++ b/compiler/optimizing/instruction_simplifier_arm64.cc @@ -17,7 +17,6 @@ #include "instruction_simplifier_arm64.h" #include "common_arm64.h" -#include "instruction_simplifier_shared.h" #include "mirror/array-inl.h" namespace art { @@ -180,6 +179,67 @@ bool InstructionSimplifierArm64Visitor::TryMergeIntoUsersShifterOperand(HInstruc return true; } +bool InstructionSimplifierArm64Visitor::TrySimpleMultiplyAccumulatePatterns( + HMul* mul, HBinaryOperation* input_binop, HInstruction* input_other) { + DCHECK(Primitive::IsIntOrLongType(mul->GetType())); + DCHECK(input_binop->IsAdd() || input_binop->IsSub()); + DCHECK_NE(input_binop, input_other); + if (!input_binop->HasOnlyOneNonEnvironmentUse()) { + return false; + } + + // Try to interpret patterns like + // a * (b <+/-> 1) + // as + // (a * b) <+/-> a + HInstruction* input_a = input_other; + HInstruction* input_b = nullptr; // Set to a non-null value if we found a pattern to optimize. + HInstruction::InstructionKind op_kind; + + if (input_binop->IsAdd()) { + if ((input_binop->GetConstantRight() != nullptr) && input_binop->GetConstantRight()->IsOne()) { + // Interpret + // a * (b + 1) + // as + // (a * b) + a + input_b = input_binop->GetLeastConstantLeft(); + op_kind = HInstruction::kAdd; + } + } else { + DCHECK(input_binop->IsSub()); + if (input_binop->GetRight()->IsConstant() && + input_binop->GetRight()->AsConstant()->IsMinusOne()) { + // Interpret + // a * (b - (-1)) + // as + // a + (a * b) + input_b = input_binop->GetLeft(); + op_kind = HInstruction::kAdd; + } else if (input_binop->GetLeft()->IsConstant() && + input_binop->GetLeft()->AsConstant()->IsOne()) { + // Interpret + // a * (1 - b) + // as + // a - (a * b) + input_b = input_binop->GetRight(); + op_kind = HInstruction::kSub; + } + } + + if (input_b == nullptr) { + // We did not find a pattern we can optimize. + return false; + } + + HArm64MultiplyAccumulate* mulacc = new(GetGraph()->GetArena()) HArm64MultiplyAccumulate( + mul->GetType(), op_kind, input_a, input_a, input_b, mul->GetDexPc()); + + mul->GetBlock()->ReplaceAndRemoveInstructionWith(mul, mulacc); + input_binop->GetBlock()->RemoveInstruction(input_binop); + + return false; +} + void InstructionSimplifierArm64Visitor::VisitArrayGet(HArrayGet* instruction) { TryExtractArrayAccessAddress(instruction, instruction->GetArray(), @@ -195,8 +255,75 @@ void InstructionSimplifierArm64Visitor::VisitArraySet(HArraySet* instruction) { } void InstructionSimplifierArm64Visitor::VisitMul(HMul* instruction) { - if (TryCombineMultiplyAccumulate(instruction, kArm64)) { - RecordSimplification(); + Primitive::Type type = instruction->GetType(); + if (!Primitive::IsIntOrLongType(type)) { + return; + } + + HInstruction* use = instruction->HasNonEnvironmentUses() + ? instruction->GetUses().GetFirst()->GetUser() + : nullptr; + + if (instruction->HasOnlyOneNonEnvironmentUse() && (use->IsAdd() || use->IsSub())) { + // Replace code looking like + // MUL tmp, x, y + // SUB dst, acc, tmp + // with + // MULSUB dst, acc, x, y + // Note that we do not want to (unconditionally) perform the merge when the + // multiplication has multiple uses and it can be merged in all of them. + // Multiple uses could happen on the same control-flow path, and we would + // then increase the amount of work. In the future we could try to evaluate + // whether all uses are on different control-flow paths (using dominance and + // reverse-dominance information) and only perform the merge when they are. + HInstruction* accumulator = nullptr; + HBinaryOperation* binop = use->AsBinaryOperation(); + HInstruction* binop_left = binop->GetLeft(); + HInstruction* binop_right = binop->GetRight(); + // Be careful after GVN. This should not happen since the `HMul` has only + // one use. + DCHECK_NE(binop_left, binop_right); + if (binop_right == instruction) { + accumulator = binop_left; + } else if (use->IsAdd()) { + DCHECK_EQ(binop_left, instruction); + accumulator = binop_right; + } + + if (accumulator != nullptr) { + HArm64MultiplyAccumulate* mulacc = + new (GetGraph()->GetArena()) HArm64MultiplyAccumulate(type, + binop->GetKind(), + accumulator, + instruction->GetLeft(), + instruction->GetRight()); + + binop->GetBlock()->ReplaceAndRemoveInstructionWith(binop, mulacc); + DCHECK(!instruction->HasUses()); + instruction->GetBlock()->RemoveInstruction(instruction); + RecordSimplification(); + return; + } + } + + // Use multiply accumulate instruction for a few simple patterns. + // We prefer not applying the following transformations if the left and + // right inputs perform the same operation. + // We rely on GVN having squashed the inputs if appropriate. However the + // results are still correct even if that did not happen. + if (instruction->GetLeft() == instruction->GetRight()) { + return; + } + + HInstruction* left = instruction->GetLeft(); + HInstruction* right = instruction->GetRight(); + if ((right->IsAdd() || right->IsSub()) && + TrySimpleMultiplyAccumulatePatterns(instruction, right->AsBinaryOperation(), left)) { + return; + } + if ((left->IsAdd() || left->IsSub()) && + TrySimpleMultiplyAccumulatePatterns(instruction, left->AsBinaryOperation(), right)) { + return; } } diff --git a/compiler/optimizing/instruction_simplifier_arm64.h b/compiler/optimizing/instruction_simplifier_arm64.h index 37a34c0373..b7f490bb8c 100644 --- a/compiler/optimizing/instruction_simplifier_arm64.h +++ b/compiler/optimizing/instruction_simplifier_arm64.h @@ -51,6 +51,10 @@ class InstructionSimplifierArm64Visitor : public HGraphVisitor { return TryMergeIntoShifterOperand(use, bitfield_op, true); } + bool TrySimpleMultiplyAccumulatePatterns(HMul* mul, + HBinaryOperation* input_binop, + HInstruction* input_other); + // HInstruction visitors, sorted alphabetically. void VisitArrayGet(HArrayGet* instruction) OVERRIDE; void VisitArraySet(HArraySet* instruction) OVERRIDE; diff --git a/compiler/optimizing/instruction_simplifier_shared.cc b/compiler/optimizing/instruction_simplifier_shared.cc deleted file mode 100644 index 45d196fa6d..0000000000 --- a/compiler/optimizing/instruction_simplifier_shared.cc +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#include "instruction_simplifier_shared.h" - -namespace art { - -namespace { - -bool TrySimpleMultiplyAccumulatePatterns(HMul* mul, - HBinaryOperation* input_binop, - HInstruction* input_other) { - DCHECK(Primitive::IsIntOrLongType(mul->GetType())); - DCHECK(input_binop->IsAdd() || input_binop->IsSub()); - DCHECK_NE(input_binop, input_other); - if (!input_binop->HasOnlyOneNonEnvironmentUse()) { - return false; - } - - // Try to interpret patterns like - // a * (b <+/-> 1) - // as - // (a * b) <+/-> a - HInstruction* input_a = input_other; - HInstruction* input_b = nullptr; // Set to a non-null value if we found a pattern to optimize. - HInstruction::InstructionKind op_kind; - - if (input_binop->IsAdd()) { - if ((input_binop->GetConstantRight() != nullptr) && input_binop->GetConstantRight()->IsOne()) { - // Interpret - // a * (b + 1) - // as - // (a * b) + a - input_b = input_binop->GetLeastConstantLeft(); - op_kind = HInstruction::kAdd; - } - } else { - DCHECK(input_binop->IsSub()); - if (input_binop->GetRight()->IsConstant() && - input_binop->GetRight()->AsConstant()->IsMinusOne()) { - // Interpret - // a * (b - (-1)) - // as - // a + (a * b) - input_b = input_binop->GetLeft(); - op_kind = HInstruction::kAdd; - } else if (input_binop->GetLeft()->IsConstant() && - input_binop->GetLeft()->AsConstant()->IsOne()) { - // Interpret - // a * (1 - b) - // as - // a - (a * b) - input_b = input_binop->GetRight(); - op_kind = HInstruction::kSub; - } - } - - if (input_b == nullptr) { - // We did not find a pattern we can optimize. - return false; - } - - ArenaAllocator* arena = mul->GetBlock()->GetGraph()->GetArena(); - HMultiplyAccumulate* mulacc = new(arena) HMultiplyAccumulate( - mul->GetType(), op_kind, input_a, input_a, input_b, mul->GetDexPc()); - - mul->GetBlock()->ReplaceAndRemoveInstructionWith(mul, mulacc); - input_binop->GetBlock()->RemoveInstruction(input_binop); - - return true; -} - -} // namespace - -bool TryCombineMultiplyAccumulate(HMul* mul, InstructionSet isa) { - Primitive::Type type = mul->GetType(); - switch (isa) { - case kArm: - case kThumb2: - if (type != Primitive::kPrimInt) { - return false; - } - break; - case kArm64: - if (!Primitive::IsIntOrLongType(type)) { - return false; - } - break; - default: - return false; - } - - HInstruction* use = mul->HasNonEnvironmentUses() - ? mul->GetUses().GetFirst()->GetUser() - : nullptr; - - ArenaAllocator* arena = mul->GetBlock()->GetGraph()->GetArena(); - - if (mul->HasOnlyOneNonEnvironmentUse()) { - if (use->IsAdd() || use->IsSub()) { - // Replace code looking like - // MUL tmp, x, y - // SUB dst, acc, tmp - // with - // MULSUB dst, acc, x, y - // Note that we do not want to (unconditionally) perform the merge when the - // multiplication has multiple uses and it can be merged in all of them. - // Multiple uses could happen on the same control-flow path, and we would - // then increase the amount of work. In the future we could try to evaluate - // whether all uses are on different control-flow paths (using dominance and - // reverse-dominance information) and only perform the merge when they are. - HInstruction* accumulator = nullptr; - HBinaryOperation* binop = use->AsBinaryOperation(); - HInstruction* binop_left = binop->GetLeft(); - HInstruction* binop_right = binop->GetRight(); - // Be careful after GVN. This should not happen since the `HMul` has only - // one use. - DCHECK_NE(binop_left, binop_right); - if (binop_right == mul) { - accumulator = binop_left; - } else if (use->IsAdd()) { - DCHECK_EQ(binop_left, mul); - accumulator = binop_right; - } - - if (accumulator != nullptr) { - HMultiplyAccumulate* mulacc = - new (arena) HMultiplyAccumulate(type, - binop->GetKind(), - accumulator, - mul->GetLeft(), - mul->GetRight()); - - binop->GetBlock()->ReplaceAndRemoveInstructionWith(binop, mulacc); - DCHECK(!mul->HasUses()); - mul->GetBlock()->RemoveInstruction(mul); - return true; - } - } else if (use->IsNeg() && isa != kArm) { - HMultiplyAccumulate* mulacc = - new (arena) HMultiplyAccumulate(type, - HInstruction::kSub, - mul->GetBlock()->GetGraph()->GetConstant(type, 0), - mul->GetLeft(), - mul->GetRight()); - - use->GetBlock()->ReplaceAndRemoveInstructionWith(use, mulacc); - DCHECK(!mul->HasUses()); - mul->GetBlock()->RemoveInstruction(mul); - return true; - } - } - - // Use multiply accumulate instruction for a few simple patterns. - // We prefer not applying the following transformations if the left and - // right inputs perform the same operation. - // We rely on GVN having squashed the inputs if appropriate. However the - // results are still correct even if that did not happen. - if (mul->GetLeft() == mul->GetRight()) { - return false; - } - - HInstruction* left = mul->GetLeft(); - HInstruction* right = mul->GetRight(); - if ((right->IsAdd() || right->IsSub()) && - TrySimpleMultiplyAccumulatePatterns(mul, right->AsBinaryOperation(), left)) { - return true; - } - if ((left->IsAdd() || left->IsSub()) && - TrySimpleMultiplyAccumulatePatterns(mul, left->AsBinaryOperation(), right)) { - return true; - } - return false; -} - -} // namespace art diff --git a/compiler/optimizing/instruction_simplifier_shared.h b/compiler/optimizing/instruction_simplifier_shared.h deleted file mode 100644 index 9832ecc058..0000000000 --- a/compiler/optimizing/instruction_simplifier_shared.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_SHARED_H_ -#define ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_SHARED_H_ - -#include "nodes.h" - -namespace art { - -bool TryCombineMultiplyAccumulate(HMul* mul, InstructionSet isa); - -} // namespace art - -#endif // ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_SHARED_H_ diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 57fa558129..019be5d494 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1226,16 +1226,6 @@ class HLoopInformationOutwardIterator : public ValueObject { M(UShr, BinaryOperation) \ M(Xor, BinaryOperation) \ -/* - * Instructions, shared across several (not all) architectures. - */ -#if !defined(ART_ENABLE_CODEGEN_arm) && !defined(ART_ENABLE_CODEGEN_arm64) -#define FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) -#else -#define FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) \ - M(MultiplyAccumulate, Instruction) -#endif - #ifndef ART_ENABLE_CODEGEN_arm #define FOR_EACH_CONCRETE_INSTRUCTION_ARM(M) #else @@ -1248,7 +1238,8 @@ class HLoopInformationOutwardIterator : public ValueObject { #else #define FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M) \ M(Arm64DataProcWithShifterOp, Instruction) \ - M(Arm64IntermediateAddress, Instruction) + M(Arm64IntermediateAddress, Instruction) \ + M(Arm64MultiplyAccumulate, Instruction) #endif #define FOR_EACH_CONCRETE_INSTRUCTION_MIPS(M) @@ -1268,7 +1259,6 @@ class HLoopInformationOutwardIterator : public ValueObject { #define FOR_EACH_CONCRETE_INSTRUCTION(M) \ FOR_EACH_CONCRETE_INSTRUCTION_COMMON(M) \ - FOR_EACH_CONCRETE_INSTRUCTION_SHARED(M) \ FOR_EACH_CONCRETE_INSTRUCTION_ARM(M) \ FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M) \ FOR_EACH_CONCRETE_INSTRUCTION_MIPS(M) \ @@ -5728,9 +5718,6 @@ class HParallelMove : public HTemplateInstruction<0> { } // namespace art -#if defined(ART_ENABLE_CODEGEN_arm) || defined(ART_ENABLE_CODEGEN_arm64) -#include "nodes_shared.h" -#endif #ifdef ART_ENABLE_CODEGEN_arm #include "nodes_arm.h" #endif diff --git a/compiler/optimizing/nodes_arm64.h b/compiler/optimizing/nodes_arm64.h index 173852a55d..445cdab191 100644 --- a/compiler/optimizing/nodes_arm64.h +++ b/compiler/optimizing/nodes_arm64.h @@ -118,6 +118,40 @@ class HArm64IntermediateAddress : public HExpression<2> { DISALLOW_COPY_AND_ASSIGN(HArm64IntermediateAddress); }; +class HArm64MultiplyAccumulate : public HExpression<3> { + public: + HArm64MultiplyAccumulate(Primitive::Type type, + InstructionKind op, + HInstruction* accumulator, + HInstruction* mul_left, + HInstruction* mul_right, + uint32_t dex_pc = kNoDexPc) + : HExpression(type, SideEffects::None(), dex_pc), op_kind_(op) { + SetRawInputAt(kInputAccumulatorIndex, accumulator); + SetRawInputAt(kInputMulLeftIndex, mul_left); + SetRawInputAt(kInputMulRightIndex, mul_right); + } + + static constexpr int kInputAccumulatorIndex = 0; + static constexpr int kInputMulLeftIndex = 1; + static constexpr int kInputMulRightIndex = 2; + + bool CanBeMoved() const OVERRIDE { return true; } + bool InstructionDataEquals(HInstruction* other) const OVERRIDE { + return op_kind_ == other->AsArm64MultiplyAccumulate()->op_kind_; + } + + InstructionKind GetOpKind() const { return op_kind_; } + + DECLARE_INSTRUCTION(Arm64MultiplyAccumulate); + + private: + // Indicates if this is a MADD or MSUB. + InstructionKind op_kind_; + + DISALLOW_COPY_AND_ASSIGN(HArm64MultiplyAccumulate); +}; + } // namespace art #endif // ART_COMPILER_OPTIMIZING_NODES_ARM64_H_ diff --git a/compiler/optimizing/nodes_shared.h b/compiler/optimizing/nodes_shared.h deleted file mode 100644 index b04b622838..0000000000 --- a/compiler/optimizing/nodes_shared.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef ART_COMPILER_OPTIMIZING_NODES_SHARED_H_ -#define ART_COMPILER_OPTIMIZING_NODES_SHARED_H_ - -namespace art { - -class HMultiplyAccumulate : public HExpression<3> { - public: - HMultiplyAccumulate(Primitive::Type type, - InstructionKind op, - HInstruction* accumulator, - HInstruction* mul_left, - HInstruction* mul_right, - uint32_t dex_pc = kNoDexPc) - : HExpression(type, SideEffects::None(), dex_pc), op_kind_(op) { - SetRawInputAt(kInputAccumulatorIndex, accumulator); - SetRawInputAt(kInputMulLeftIndex, mul_left); - SetRawInputAt(kInputMulRightIndex, mul_right); - } - - static constexpr int kInputAccumulatorIndex = 0; - static constexpr int kInputMulLeftIndex = 1; - static constexpr int kInputMulRightIndex = 2; - - bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - return op_kind_ == other->AsMultiplyAccumulate()->op_kind_; - } - - InstructionKind GetOpKind() const { return op_kind_; } - - DECLARE_INSTRUCTION(MultiplyAccumulate); - - private: - // Indicates if this is a MADD or MSUB. - const InstructionKind op_kind_; - - DISALLOW_COPY_AND_ASSIGN(HMultiplyAccumulate); -}; - -} // namespace art - -#endif // ART_COMPILER_OPTIMIZING_NODES_SHARED_H_ diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 4da48bdfc3..fffd00535c 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -62,7 +62,6 @@ #include "induction_var_analysis.h" #include "inliner.h" #include "instruction_simplifier.h" -#include "instruction_simplifier_arm.h" #include "intrinsics.h" #include "jit/debugger_interface.h" #include "jit/jit_code_cache.h" @@ -446,11 +445,8 @@ static void RunArchOptimizations(InstructionSet instruction_set, case kThumb2: case kArm: { arm::DexCacheArrayFixups* fixups = new (arena) arm::DexCacheArrayFixups(graph, stats); - arm::InstructionSimplifierArm* simplifier = - new (arena) arm::InstructionSimplifierArm(graph, stats); HOptimization* arm_optimizations[] = { - fixups, - simplifier + fixups }; RunOptimizations(arm_optimizations, arraysize(arm_optimizations), pass_observer); break; diff --git a/test/550-checker-multiply-accumulate/src/Main.java b/test/550-checker-multiply-accumulate/src/Main.java index 549ed990f2..2d0688d57e 100644 --- a/test/550-checker-multiply-accumulate/src/Main.java +++ b/test/550-checker-multiply-accumulate/src/Main.java @@ -47,7 +47,7 @@ public class Main { /// CHECK: <<Acc:i\d+>> ParameterValue /// CHECK: <<Left:i\d+>> ParameterValue /// CHECK: <<Right:i\d+>> ParameterValue - /// CHECK: <<MulAdd:i\d+>> MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Add + /// CHECK: <<MulAdd:i\d+>> Arm64MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Add /// CHECK: Return [<<MulAdd>>] /// CHECK-START-ARM64: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm64 (after) @@ -57,28 +57,6 @@ public class Main { /// CHECK-START-ARM64: int Main.$opt$noinline$mulAdd(int, int, int) disassembly (after) /// CHECK: madd w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} - /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm (before) - /// CHECK: <<Acc:i\d+>> ParameterValue - /// CHECK: <<Left:i\d+>> ParameterValue - /// CHECK: <<Right:i\d+>> ParameterValue - /// CHECK: <<Mul:i\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Add:i\d+>> Add [<<Acc>>,<<Mul>>] - /// CHECK: Return [<<Add>>] - - /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm (after) - /// CHECK: <<Acc:i\d+>> ParameterValue - /// CHECK: <<Left:i\d+>> ParameterValue - /// CHECK: <<Right:i\d+>> ParameterValue - /// CHECK: <<MulAdd:i\d+>> MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Add - /// CHECK: Return [<<MulAdd>>] - - /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm (after) - /// CHECK-NOT: Mul - /// CHECK-NOT: Add - - /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) disassembly (after) - /// CHECK: mla w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} - public static int $opt$noinline$mulAdd(int acc, int left, int right) { if (doThrow) throw new Error(); return acc + left * right; @@ -100,7 +78,7 @@ public class Main { /// CHECK: <<Acc:j\d+>> ParameterValue /// CHECK: <<Left:j\d+>> ParameterValue /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<MulSub:j\d+>> MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Sub + /// CHECK: <<MulSub:j\d+>> Arm64MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Sub /// CHECK: Return [<<MulSub>>] /// CHECK-START-ARM64: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm64 (after) @@ -110,28 +88,6 @@ public class Main { /// CHECK-START-ARM64: long Main.$opt$noinline$mulSub(long, long, long) disassembly (after) /// CHECK: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} - /// CHECK-START-ARM: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm (before) - /// CHECK: <<Acc:j\d+>> ParameterValue - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Sub:j\d+>> Sub [<<Acc>>,<<Mul>>] - /// CHECK: Return [<<Sub>>] - - /// CHECK-START-ARM: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm (after) - /// CHECK: <<Acc:j\d+>> ParameterValue - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<MulSub:j\d+>> MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Sub - /// CHECK: Return [<<MulSub>>] - - /// CHECK-START-ARM: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm (after) - /// CHECK-NOT: Mul - /// CHECK-NOT: Sub - - /// CHECK-START-ARM: long Main.$opt$noinline$mulSub(long, long, long) disassembly (after) - /// CHECK: mls x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} - public static long $opt$noinline$mulSub(long acc, long left, long right) { if (doThrow) throw new Error(); return acc - left * right; @@ -161,28 +117,7 @@ public class Main { /// CHECK: Return [<<Or>>] /// CHECK-START-ARM64: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm64 (after) - /// CHECK-NOT: MultiplyAccumulate - - /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm (before) - /// CHECK: <<Acc:i\d+>> ParameterValue - /// CHECK: <<Left:i\d+>> ParameterValue - /// CHECK: <<Right:i\d+>> ParameterValue - /// CHECK: <<Mul:i\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Add:i\d+>> Add [<<Acc>>,<<Mul>>] - /// CHECK: <<Or:i\d+>> Or [<<Mul>>,<<Add>>] - /// CHECK: Return [<<Or>>] - - /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm (after) - /// CHECK: <<Acc:i\d+>> ParameterValue - /// CHECK: <<Left:i\d+>> ParameterValue - /// CHECK: <<Right:i\d+>> ParameterValue - /// CHECK: <<Mul:i\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Add:i\d+>> Add [<<Acc>>,<<Mul>>] - /// CHECK: <<Or:i\d+>> Or [<<Mul>>,<<Add>>] - /// CHECK: Return [<<Or>>] - - /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm (after) - /// CHECK-NOT: MultiplyAccumulate + /// CHECK-NOT: Arm64MultiplyAccumulate public static int $opt$noinline$multipleUses1(int acc, int left, int right) { if (doThrow) throw new Error(); @@ -216,30 +151,7 @@ public class Main { /// CHECK: Return [<<Res>>] /// CHECK-START-ARM64: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm64 (after) - /// CHECK-NOT: MultiplyAccumulate - - /// CHECK-START-ARM: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm (before) - /// CHECK: <<Acc:j\d+>> ParameterValue - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Add:j\d+>> Add [<<Acc>>,<<Mul>>] - /// CHECK: <<Sub:j\d+>> Sub [<<Acc>>,<<Mul>>] - /// CHECK: <<Res:j\d+>> Add [<<Add>>,<<Sub>>] - /// CHECK: Return [<<Res>>] - - /// CHECK-START-ARM: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm (after) - /// CHECK: <<Acc:j\d+>> ParameterValue - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Add:j\d+>> Add [<<Acc>>,<<Mul>>] - /// CHECK: <<Sub:j\d+>> Sub [<<Acc>>,<<Mul>>] - /// CHECK: <<Res:j\d+>> Add [<<Add>>,<<Sub>>] - /// CHECK: Return [<<Res>>] - - /// CHECK-START-ARM: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm (after) - /// CHECK-NOT: MultiplyAccumulate + /// CHECK-NOT: Arm64MultiplyAccumulate public static long $opt$noinline$multipleUses2(long acc, long left, long right) { @@ -264,7 +176,7 @@ public class Main { /// CHECK-START-ARM64: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm64 (after) /// CHECK: <<Acc:i\d+>> ParameterValue /// CHECK: <<Var:i\d+>> ParameterValue - /// CHECK: <<MulAdd:i\d+>> MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Add + /// CHECK: <<MulAdd:i\d+>> Arm64MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Add /// CHECK: Return [<<MulAdd>>] /// CHECK-START-ARM64: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm64 (after) @@ -274,27 +186,6 @@ public class Main { /// CHECK-START-ARM64: int Main.$opt$noinline$mulPlusOne(int, int) disassembly (after) /// CHECK: madd w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} - /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm (before) - /// CHECK: <<Acc:i\d+>> ParameterValue - /// CHECK: <<Var:i\d+>> ParameterValue - /// CHECK: <<Const1:i\d+>> IntConstant 1 - /// CHECK: <<Add:i\d+>> Add [<<Var>>,<<Const1>>] - /// CHECK: <<Mul:i\d+>> Mul [<<Acc>>,<<Add>>] - /// CHECK: Return [<<Mul>>] - - /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm (after) - /// CHECK: <<Acc:i\d+>> ParameterValue - /// CHECK: <<Var:i\d+>> ParameterValue - /// CHECK: <<MulAdd:i\d+>> MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Add - /// CHECK: Return [<<MulAdd>>] - - /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm (after) - /// CHECK-NOT: Mul - /// CHECK-NOT: Add - - /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) disassembly (after) - /// CHECK: mla w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} - public static int $opt$noinline$mulPlusOne(int acc, int var) { if (doThrow) throw new Error(); return acc * (var + 1); @@ -316,7 +207,7 @@ public class Main { /// CHECK-START-ARM64: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm64 (after) /// CHECK: <<Acc:j\d+>> ParameterValue /// CHECK: <<Var:j\d+>> ParameterValue - /// CHECK: <<MulSub:j\d+>> MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Sub + /// CHECK: <<MulSub:j\d+>> Arm64MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Sub /// CHECK: Return [<<MulSub>>] /// CHECK-START-ARM64: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm64 (after) @@ -326,123 +217,11 @@ public class Main { /// CHECK-START-ARM64: long Main.$opt$noinline$mulMinusOne(long, long) disassembly (after) /// CHECK: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} - /// CHECK-START-ARM: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm (before) - /// CHECK: <<Acc:j\d+>> ParameterValue - /// CHECK: <<Var:j\d+>> ParameterValue - /// CHECK: <<Const1:j\d+>> LongConstant 1 - /// CHECK: <<Sub:j\d+>> Sub [<<Const1>>,<<Var>>] - /// CHECK: <<Mul:j\d+>> Mul [<<Acc>>,<<Sub>>] - /// CHECK: Return [<<Mul>>] - - /// CHECK-START-ARM: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm (after) - /// CHECK: <<Acc:j\d+>> ParameterValue - /// CHECK: <<Var:j\d+>> ParameterValue - /// CHECK: <<MulSub:j\d+>> MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Sub - /// CHECK: Return [<<MulSub>>] - - /// CHECK-START-ARM: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm (after) - /// CHECK-NOT: Mul - /// CHECK-NOT: Sub - - /// CHECK-START-ARM: long Main.$opt$noinline$mulMinusOne(long, long) disassembly (after) - /// CHECK: mls x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} - public static long $opt$noinline$mulMinusOne(long acc, long var) { if (doThrow) throw new Error(); return acc * (1 - var); } - /** - * Test basic merging of `MUL+NEG` into `MULNEG`. - */ - - /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm64 (before) - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Neg:j\d+>> Neg [<<Mul>>] - /// CHECK: Return [<<Neg>>] - - /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm64 (after) - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<MulNeg:j\d+>> MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Sub - /// CHECK: Return [<<MulNeg>>] - - /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm64 (after) - /// CHECK-NOT: Mul - /// CHECK-NOT: Neg - - /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) disassembly (after) - /// CHECK: mneg x{{\d+}}, x{{\d+}}, x{{\d+}} - - /// CHECK-START-ARM: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm (before) - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Neg:j\d+>> Neg [<<Mul>>,<<Mul>>] - /// CHECK: Return [<<Neg>>] - - /// CHECK-START-ARM: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm (after) - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Neg:j\d+>> Neg [<<Mul>>,<<Mul>>] - /// CHECK: Return [<<Neg>>] - - /// CHECK-START-ARM: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm (after) - /// CHECK-NOT: MultiplyAccumulate - - public static int $opt$noinline$mulNeg(int left, int right) { - if (doThrow) throw new Error(); - return - (left * right); - } - - /** - * Test basic merging of `MUL+NEG` into `MULNEG`. - */ - - /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm64 (before) - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Neg:j\d+>> Neg [<<Mul>>] - /// CHECK: Return [<<Neg>>] - - /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm64 (after) - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<MulNeg:j\d+>> MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Sub - /// CHECK: Return [<<MulNeg>>] - - /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm64 (after) - /// CHECK-NOT: Mul - /// CHECK-NOT: Neg - - /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) disassembly (after) - /// CHECK: mneg x{{\d+}}, x{{\d+}}, x{{\d+}} - - /// CHECK-START-ARM: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm (before) - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Neg:j\d+>> Neg [<<Mul>>,<<Mul>>] - /// CHECK: Return [<<Neg>>] - - /// CHECK-START-ARM: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm (after) - /// CHECK: <<Left:j\d+>> ParameterValue - /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] - /// CHECK: <<Neg:j\d+>> Neg [<<Mul>>,<<Mul>>] - /// CHECK: Return [<<Neg>>] - - /// CHECK-START-ARM: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm (after) - /// CHECK-NOT: MultiplyAccumulate - - public static long $opt$noinline$mulNeg(long left, long right) { - if (doThrow) throw new Error(); - return - (left * right); - } public static void main(String[] args) { assertIntEquals(7, $opt$noinline$mulAdd(1, 2, 3)); @@ -451,7 +230,5 @@ public class Main { assertLongEquals(20, $opt$noinline$multipleUses2(10, 11, 12)); assertIntEquals(195, $opt$noinline$mulPlusOne(13, 14)); assertLongEquals(-225, $opt$noinline$mulMinusOne(15, 16)); - assertIntEquals(-306, $opt$noinline$mulNeg(17, 18)); - assertLongEquals(-380, $opt$noinline$mulNeg(19, 20)); } } |