blob: c3e88f39c3650b350b628b029deac27d288e53dd [file] [log] [blame]
David Brazdil46e2a392015-03-16 17:31:52 +00001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "boolean_simplifier.h"
18
19namespace art {
20
David Brazdil769c9e52015-04-27 13:54:09 +010021void HBooleanSimplifier::TryRemovingNegatedCondition(HBasicBlock* block) {
22 DCHECK(block->EndsWithIf());
23
24 // Check if the condition is a Boolean negation.
25 HIf* if_instruction = block->GetLastInstruction()->AsIf();
26 HInstruction* boolean_not = if_instruction->InputAt(0);
27 if (!boolean_not->IsBooleanNot()) {
28 return;
29 }
30
31 // Make BooleanNot's input the condition of the If and swap branches.
32 if_instruction->ReplaceInput(boolean_not->InputAt(0), 0);
33 block->SwapSuccessors();
34
35 // Remove the BooleanNot if it is now unused.
36 if (!boolean_not->HasUses()) {
37 boolean_not->GetBlock()->RemoveInstruction(boolean_not);
38 }
Jean-Philippe Halimi06241b12015-09-03 17:28:38 +020039
40 MaybeRecordStat(MethodCompilationStat::kBooleanSimplifier);
David Brazdil769c9e52015-04-27 13:54:09 +010041}
42
David Brazdil46e2a392015-03-16 17:31:52 +000043// Returns true if 'block1' and 'block2' are empty, merge into the same single
44// successor and the successor can only be reached from them.
45static bool BlocksDoMergeTogether(HBasicBlock* block1, HBasicBlock* block2) {
46 if (!block1->IsSingleGoto() || !block2->IsSingleGoto()) return false;
Vladimir Markoec7802a2015-10-01 20:57:57 +010047 HBasicBlock* succ1 = block1->GetSuccessors()[0];
48 HBasicBlock* succ2 = block2->GetSuccessors()[0];
Vladimir Marko60584552015-09-03 13:35:12 +000049 return succ1 == succ2 && succ1->GetPredecessors().size() == 2u;
David Brazdil46e2a392015-03-16 17:31:52 +000050}
51
52// Returns true if the outcome of the branching matches the boolean value of
53// the branching condition.
54static bool PreservesCondition(HInstruction* input_true, HInstruction* input_false) {
David Brazdilb2bd1c52015-03-25 11:17:37 +000055 return input_true->IsIntConstant() && input_true->AsIntConstant()->IsOne()
56 && input_false->IsIntConstant() && input_false->AsIntConstant()->IsZero();
David Brazdil46e2a392015-03-16 17:31:52 +000057}
58
59// Returns true if the outcome of the branching is exactly opposite of the
60// boolean value of the branching condition.
61static bool NegatesCondition(HInstruction* input_true, HInstruction* input_false) {
David Brazdilb2bd1c52015-03-25 11:17:37 +000062 return input_true->IsIntConstant() && input_true->AsIntConstant()->IsZero()
63 && input_false->IsIntConstant() && input_false->AsIntConstant()->IsOne();
David Brazdil46e2a392015-03-16 17:31:52 +000064}
65
66// Returns an instruction with the opposite boolean value from 'cond'.
67static HInstruction* GetOppositeCondition(HInstruction* cond) {
68 HGraph* graph = cond->GetBlock()->GetGraph();
69 ArenaAllocator* allocator = graph->GetArena();
70
71 if (cond->IsCondition()) {
72 HInstruction* lhs = cond->InputAt(0);
73 HInstruction* rhs = cond->InputAt(1);
Aart Bike9f37602015-10-09 11:15:55 -070074 switch (cond->AsCondition()->GetOppositeCondition()) { // get *opposite*
75 case kCondEQ: return new (allocator) HEqual(lhs, rhs);
76 case kCondNE: return new (allocator) HNotEqual(lhs, rhs);
77 case kCondLT: return new (allocator) HLessThan(lhs, rhs);
78 case kCondLE: return new (allocator) HLessThanOrEqual(lhs, rhs);
79 case kCondGT: return new (allocator) HGreaterThan(lhs, rhs);
80 case kCondGE: return new (allocator) HGreaterThanOrEqual(lhs, rhs);
81 case kCondB: return new (allocator) HBelow(lhs, rhs);
82 case kCondBE: return new (allocator) HBelowOrEqual(lhs, rhs);
83 case kCondA: return new (allocator) HAbove(lhs, rhs);
84 case kCondAE: return new (allocator) HAboveOrEqual(lhs, rhs);
David Brazdil46e2a392015-03-16 17:31:52 +000085 }
86 } else if (cond->IsIntConstant()) {
David Brazdilb2bd1c52015-03-25 11:17:37 +000087 HIntConstant* int_const = cond->AsIntConstant();
88 if (int_const->IsZero()) {
David Brazdil8d5b8b22015-03-24 10:51:52 +000089 return graph->GetIntConstant(1);
David Brazdil46e2a392015-03-16 17:31:52 +000090 } else {
David Brazdilb2bd1c52015-03-25 11:17:37 +000091 DCHECK(int_const->IsOne());
David Brazdil8d5b8b22015-03-24 10:51:52 +000092 return graph->GetIntConstant(0);
David Brazdil46e2a392015-03-16 17:31:52 +000093 }
94 }
Aart Bike9f37602015-10-09 11:15:55 -070095 // General case when 'cond' is another instruction of type boolean,
96 // as verified by SSAChecker.
97 return new (allocator) HBooleanNot(cond);
David Brazdil46e2a392015-03-16 17:31:52 +000098}
99
David Brazdil769c9e52015-04-27 13:54:09 +0100100void HBooleanSimplifier::TryRemovingBooleanSelection(HBasicBlock* block) {
101 DCHECK(block->EndsWithIf());
102
103 // Find elements of the pattern.
104 HIf* if_instruction = block->GetLastInstruction()->AsIf();
105 HBasicBlock* true_block = if_instruction->IfTrueSuccessor();
106 HBasicBlock* false_block = if_instruction->IfFalseSuccessor();
107 if (!BlocksDoMergeTogether(true_block, false_block)) {
108 return;
109 }
Vladimir Markoec7802a2015-10-01 20:57:57 +0100110 HBasicBlock* merge_block = true_block->GetSuccessors()[0];
David Brazdil769c9e52015-04-27 13:54:09 +0100111 if (!merge_block->HasSinglePhi()) {
112 return;
113 }
114 HPhi* phi = merge_block->GetFirstPhi()->AsPhi();
115 HInstruction* true_value = phi->InputAt(merge_block->GetPredecessorIndexOf(true_block));
116 HInstruction* false_value = phi->InputAt(merge_block->GetPredecessorIndexOf(false_block));
117
118 // Check if the selection negates/preserves the value of the condition and
119 // if so, generate a suitable replacement instruction.
120 HInstruction* if_condition = if_instruction->InputAt(0);
Mark Mendellc4701932015-04-10 13:18:51 -0400121
122 // Don't change FP compares. The definition of compares involving NaNs forces
123 // the compares to be done as written by the user.
124 if (if_condition->IsCondition() &&
125 Primitive::IsFloatingPointType(if_condition->InputAt(0)->GetType())) {
126 return;
127 }
128
David Brazdil769c9e52015-04-27 13:54:09 +0100129 HInstruction* replacement;
130 if (NegatesCondition(true_value, false_value)) {
131 replacement = GetOppositeCondition(if_condition);
132 if (replacement->GetBlock() == nullptr) {
133 block->InsertInstructionBefore(replacement, if_instruction);
134 }
135 } else if (PreservesCondition(true_value, false_value)) {
136 replacement = if_condition;
137 } else {
138 return;
139 }
140
141 // Replace the selection outcome with the new instruction.
142 phi->ReplaceWith(replacement);
143 merge_block->RemovePhi(phi);
144
145 // Delete the true branch and merge the resulting chain of blocks
146 // 'block->false_block->merge_block' into one.
147 true_block->DisconnectAndDelete();
148 block->MergeWith(false_block);
149 block->MergeWith(merge_block);
150
Jean-Philippe Halimi06241b12015-09-03 17:28:38 +0200151 MaybeRecordStat(MethodCompilationStat::kBooleanSimplifier);
152
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100153 // No need to update any dominance information, as we are simplifying
154 // a simple diamond shape, where the join block is merged with the
155 // entry block. Any following blocks would have had the join block
156 // as a dominator, and `MergeWith` handles changing that to the
157 // entry block.
David Brazdil769c9e52015-04-27 13:54:09 +0100158}
159
David Brazdil46e2a392015-03-16 17:31:52 +0000160void HBooleanSimplifier::Run() {
161 // Iterate in post order in the unlikely case that removing one occurrence of
David Brazdil769c9e52015-04-27 13:54:09 +0100162 // the selection pattern empties a branch block of another occurrence.
163 // Otherwise the order does not matter.
David Brazdil46e2a392015-03-16 17:31:52 +0000164 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
165 HBasicBlock* block = it.Current();
David Brazdilb2bd1c52015-03-25 11:17:37 +0000166 if (!block->EndsWithIf()) continue;
David Brazdil46e2a392015-03-16 17:31:52 +0000167
David Brazdil769c9e52015-04-27 13:54:09 +0100168 // If condition is negated, remove the negation and swap the branches.
169 TryRemovingNegatedCondition(block);
David Brazdil46e2a392015-03-16 17:31:52 +0000170
David Brazdil769c9e52015-04-27 13:54:09 +0100171 // If this is a boolean-selection diamond pattern, replace its result with
172 // the condition value (or its negation) and simplify the graph.
173 TryRemovingBooleanSelection(block);
David Brazdil46e2a392015-03-16 17:31:52 +0000174 }
175}
176
177} // namespace art