summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/optimizing/code_generator_arm64.cc1
-rw-r--r--compiler/optimizing/instruction_simplifier.cc84
-rw-r--r--compiler/optimizing/instruction_simplifier.h9
-rw-r--r--compiler/optimizing/optimization.cc8
-rw-r--r--compiler/optimizing/optimization.h1
-rw-r--r--compiler/optimizing/optimizing_compiler.cc4
6 files changed, 99 insertions, 8 deletions
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 70cef4967c..4a618de617 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -3067,7 +3067,6 @@ void InstructionCodeGeneratorARM64::GenerateResultRemWithAnyConstant(
Register quotient,
int64_t divisor,
UseScratchRegisterScope* temps_scope) {
- // TODO: Strength reduction for msub.
Register temp_imm = temps_scope->AcquireSameSizeAs(out);
__ Mov(temp_imm, divisor);
__ Msub(out, quotient, temp_imm, dividend);
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 5ac77a5484..d586306a2c 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -37,10 +37,12 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor {
public:
InstructionSimplifierVisitor(HGraph* graph,
CodeGenerator* codegen,
- OptimizingCompilerStats* stats)
+ OptimizingCompilerStats* stats,
+ bool be_loop_friendly)
: HGraphDelegateVisitor(graph),
codegen_(codegen),
- stats_(stats) {}
+ stats_(stats),
+ be_loop_friendly_(be_loop_friendly) {}
bool Run();
@@ -65,6 +67,7 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor {
bool TryHandleAssociativeAndCommutativeOperation(HBinaryOperation* instruction);
bool TrySubtractionChainSimplification(HBinaryOperation* instruction);
bool TryCombineVecMultiplyAccumulate(HVecMul* mul);
+ void TryToReuseDiv(HRem* rem);
void VisitShift(HBinaryOperation* shift);
void VisitEqual(HEqual* equal) override;
@@ -90,6 +93,7 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor {
void VisitAbove(HAbove* condition) override;
void VisitAboveOrEqual(HAboveOrEqual* condition) override;
void VisitDiv(HDiv* instruction) override;
+ void VisitRem(HRem* instruction) override;
void VisitMul(HMul* instruction) override;
void VisitNeg(HNeg* instruction) override;
void VisitNot(HNot* instruction) override;
@@ -122,6 +126,13 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor {
OptimizingCompilerStats* stats_;
bool simplification_occurred_ = false;
int simplifications_at_current_position_ = 0;
+ // Prohibit optimizations which can affect HInductionVarAnalysis/HLoopOptimization
+ // and prevent loop optimizations:
+ // true - avoid such optimizations.
+ // false - allow such optimizations.
+ // Checked by the following optimizations:
+ // - TryToReuseDiv: simplification of Div+Rem into Div+Mul+Sub.
+ bool be_loop_friendly_;
// We ensure we do not loop infinitely. The value should not be too high, since that
// would allow looping around the same basic block too many times. The value should
// not be too low either, however, since we want to allow revisiting a basic block
@@ -135,7 +146,9 @@ bool InstructionSimplifier::Run() {
visitor.VisitReversePostOrder();
}
- InstructionSimplifierVisitor visitor(graph_, codegen_, stats_);
+ bool be_loop_friendly = (use_all_optimizations_ == false);
+
+ InstructionSimplifierVisitor visitor(graph_, codegen_, stats_, be_loop_friendly);
return visitor.Run();
}
@@ -1691,6 +1704,71 @@ void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
}
}
+
+// Search HDiv having the specified dividend and divisor which is in the specified basic block.
+// Return nullptr if nothing has been found.
+static HInstruction* FindDivWithInputsInBasicBlock(HInstruction* dividend,
+ HInstruction* divisor,
+ HBasicBlock* basic_block) {
+ for (const HUseListNode<HInstruction*>& use : dividend->GetUses()) {
+ HInstruction* user = use.GetUser();
+ if (user->GetBlock() == basic_block && user->IsDiv() && user->InputAt(1) == divisor) {
+ return user;
+ }
+ }
+ return nullptr;
+}
+
+// If there is Div with the same inputs as Rem and in the same basic block, it can be reused.
+// Rem is replaced with Mul+Sub which use the found Div.
+void InstructionSimplifierVisitor::TryToReuseDiv(HRem* rem) {
+ // As the optimization replaces Rem with Mul+Sub they prevent some loop optimizations
+ // if the Rem is in a loop.
+ // Check if it is allowed to optimize such Rems.
+ if (rem->IsInLoop() && be_loop_friendly_) {
+ return;
+ }
+ DataType::Type type = rem->GetResultType();
+ if (!DataType::IsIntOrLongType(type)) {
+ return;
+ }
+
+ HBasicBlock* basic_block = rem->GetBlock();
+ HInstruction* dividend = rem->GetLeft();
+ HInstruction* divisor = rem->GetRight();
+
+ if (divisor->IsConstant()) {
+ HConstant* input_cst = rem->GetConstantRight();
+ DCHECK(input_cst->IsIntConstant() || input_cst->IsLongConstant());
+ int64_t cst_value = Int64FromConstant(input_cst);
+ if (cst_value == std::numeric_limits<int64_t>::min() || IsPowerOfTwo(std::abs(cst_value))) {
+ // Such cases are usually handled in the code generator because they don't need Div at all.
+ return;
+ }
+ }
+
+ HInstruction* quotient = FindDivWithInputsInBasicBlock(dividend, divisor, basic_block);
+ if (quotient == nullptr) {
+ return;
+ }
+ if (!quotient->StrictlyDominates(rem)) {
+ quotient->MoveBefore(rem);
+ }
+
+ ArenaAllocator* allocator = GetGraph()->GetAllocator();
+ HInstruction* mul = new (allocator) HMul(type, quotient, divisor);
+ basic_block->InsertInstructionBefore(mul, rem);
+ HInstruction* sub = new (allocator) HSub(type, dividend, mul);
+ basic_block->InsertInstructionBefore(sub, rem);
+ rem->ReplaceWith(sub);
+ basic_block->RemoveInstruction(rem);
+ RecordSimplification();
+}
+
+void InstructionSimplifierVisitor::VisitRem(HRem* rem) {
+ TryToReuseDiv(rem);
+}
+
void InstructionSimplifierVisitor::VisitMul(HMul* instruction) {
HConstant* input_cst = instruction->GetConstantRight();
HInstruction* input_other = instruction->GetLeastConstantLeft();
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index 982a24a6f0..feea771096 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -40,9 +40,11 @@ class InstructionSimplifier : public HOptimization {
InstructionSimplifier(HGraph* graph,
CodeGenerator* codegen,
OptimizingCompilerStats* stats = nullptr,
- const char* name = kInstructionSimplifierPassName)
+ const char* name = kInstructionSimplifierPassName,
+ bool use_all_optimizations = false)
: HOptimization(graph, name, stats),
- codegen_(codegen) {}
+ codegen_(codegen),
+ use_all_optimizations_(use_all_optimizations) {}
static constexpr const char* kInstructionSimplifierPassName = "instruction_simplifier";
@@ -51,6 +53,9 @@ class InstructionSimplifier : public HOptimization {
private:
CodeGenerator* codegen_;
+ // Use all optimizations without restrictions.
+ bool use_all_optimizations_;
+
DISALLOW_COPY_AND_ASSIGN(InstructionSimplifier);
};
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index ec3b8c4904..424fbd9f45 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -83,6 +83,7 @@ const char* OptimizationPassName(OptimizationPass pass) {
return HInliner::kInlinerPassName;
case OptimizationPass::kSelectGenerator:
return HSelectGenerator::kSelectGeneratorPassName;
+ case OptimizationPass::kAggressiveInstructionSimplifier:
case OptimizationPass::kInstructionSimplifier:
return InstructionSimplifier::kInstructionSimplifierPassName;
case OptimizationPass::kCHAGuardOptimization:
@@ -248,6 +249,13 @@ ArenaVector<HOptimization*> ConstructOptimizations(
case OptimizationPass::kInstructionSimplifier:
opt = new (allocator) InstructionSimplifier(graph, codegen, stats, pass_name);
break;
+ case OptimizationPass::kAggressiveInstructionSimplifier:
+ opt = new (allocator) InstructionSimplifier(graph,
+ codegen,
+ stats,
+ pass_name,
+ /* use_all_optimizations_ = */ true);
+ break;
case OptimizationPass::kCHAGuardOptimization:
opt = new (allocator) CHAGuardOptimization(graph, pass_name);
break;
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index 4a515bcc90..f8aea9680d 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -66,6 +66,7 @@ class HOptimization : public ArenaObject<kArenaAllocOptimization> {
// field is preferred over a string lookup at places where performance matters.
// TODO: generate this table and lookup methods below automatically?
enum class OptimizationPass {
+ kAggressiveInstructionSimplifier,
kBoundsCheckElimination,
kCHAGuardOptimization,
kCodeSinking,
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 45d31bad79..8d4aa9fd5d 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -643,7 +643,7 @@ void OptimizingCompiler::RunOptimizations(HGraph* graph,
// Simplification.
OptDef(OptimizationPass::kConstantFolding,
"constant_folding$after_bce"),
- OptDef(OptimizationPass::kInstructionSimplifier,
+ OptDef(OptimizationPass::kAggressiveInstructionSimplifier,
"instruction_simplifier$after_bce"),
// Other high-level optimizations.
OptDef(OptimizationPass::kSideEffectsAnalysis,
@@ -656,7 +656,7 @@ void OptimizingCompiler::RunOptimizations(HGraph* graph,
// The codegen has a few assumptions that only the instruction simplifier
// can satisfy. For example, the code generator does not expect to see a
// HTypeConversion from a type to the same type.
- OptDef(OptimizationPass::kInstructionSimplifier,
+ OptDef(OptimizationPass::kAggressiveInstructionSimplifier,
"instruction_simplifier$before_codegen"),
// Eliminate constructor fences after code sinking to avoid
// complicated sinking logic to split a fence with many inputs.