blob: 489b62df0af5bd7651f7be59e10a17d2f28e952e [file] [log] [blame]
Roland Levillain556c3d12014-09-18 15:25:07 +01001/*
2 * Copyright (C) 2014 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
Roland Levillain75be2832014-10-17 17:02:00 +010017#include "constant_folding.h"
Roland Levillain556c3d12014-09-18 15:25:07 +010018
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +000019#include <algorithm>
20
21#include "optimizing/data_type.h"
22#include "optimizing/nodes.h"
23
VladimĂ­r Marko434d9682022-11-04 14:04:17 +000024namespace art HIDDEN {
Roland Levillain556c3d12014-09-18 15:25:07 +010025
Roland Levillain1252e972015-08-06 15:46:02 +010026// This visitor tries to simplify instructions that can be evaluated
27// as constants.
28class HConstantFoldingVisitor : public HGraphDelegateVisitor {
29 public:
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +000030 explicit HConstantFoldingVisitor(HGraph* graph, OptimizingCompilerStats* stats)
31 : HGraphDelegateVisitor(graph, stats) {}
Roland Levillain1252e972015-08-06 15:46:02 +010032
33 private:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010034 void VisitBasicBlock(HBasicBlock* block) override;
Roland Levillain1252e972015-08-06 15:46:02 +010035
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010036 void VisitUnaryOperation(HUnaryOperation* inst) override;
37 void VisitBinaryOperation(HBinaryOperation* inst) override;
Roland Levillain1252e972015-08-06 15:46:02 +010038
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010039 void VisitTypeConversion(HTypeConversion* inst) override;
40 void VisitDivZeroCheck(HDivZeroCheck* inst) override;
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +000041 void VisitIf(HIf* inst) override;
42
43 void PropagateValue(HBasicBlock* starting_block, HInstruction* variable, HConstant* constant);
Roland Levillain1252e972015-08-06 15:46:02 +010044
45 DISALLOW_COPY_AND_ASSIGN(HConstantFoldingVisitor);
46};
47
48// This visitor tries to simplify operations with an absorbing input,
49// yielding a constant. For example `input * 0` is replaced by a
50// null constant.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000051class InstructionWithAbsorbingInputSimplifier : public HGraphVisitor {
52 public:
53 explicit InstructionWithAbsorbingInputSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
54
55 private:
56 void VisitShift(HBinaryOperation* shift);
57
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010058 void VisitEqual(HEqual* instruction) override;
59 void VisitNotEqual(HNotEqual* instruction) override;
Vladimir Markoa341f352016-08-31 12:18:20 +010060
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010061 void VisitAbove(HAbove* instruction) override;
62 void VisitAboveOrEqual(HAboveOrEqual* instruction) override;
63 void VisitBelow(HBelow* instruction) override;
64 void VisitBelowOrEqual(HBelowOrEqual* instruction) override;
Aart Bik96709f12015-10-28 17:49:07 -070065
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010066 void VisitAnd(HAnd* instruction) override;
67 void VisitCompare(HCompare* instruction) override;
68 void VisitMul(HMul* instruction) override;
69 void VisitOr(HOr* instruction) override;
70 void VisitRem(HRem* instruction) override;
71 void VisitShl(HShl* instruction) override;
72 void VisitShr(HShr* instruction) override;
73 void VisitSub(HSub* instruction) override;
74 void VisitUShr(HUShr* instruction) override;
75 void VisitXor(HXor* instruction) override;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000076};
77
Roland Levillain1252e972015-08-06 15:46:02 +010078
Aart Bik24773202018-04-26 10:28:51 -070079bool HConstantFolding::Run() {
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +000080 HConstantFoldingVisitor visitor(graph_, stats_);
Roland Levillain556c3d12014-09-18 15:25:07 +010081 // Process basic blocks in reverse post-order in the dominator tree,
82 // so that an instruction turned into a constant, used as input of
83 // another instruction, may possibly be used to turn that second
84 // instruction into a constant as well.
Roland Levillain1252e972015-08-06 15:46:02 +010085 visitor.VisitReversePostOrder();
Aart Bik24773202018-04-26 10:28:51 -070086 return true;
Roland Levillain1252e972015-08-06 15:46:02 +010087}
88
89
90void HConstantFoldingVisitor::VisitBasicBlock(HBasicBlock* block) {
91 // Traverse this block's instructions (phis don't need to be
92 // processed) in (forward) order and replace the ones that can be
93 // statically evaluated by a compile-time counterpart.
94 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
95 it.Current()->Accept(this);
Roland Levillain556c3d12014-09-18 15:25:07 +010096 }
97}
98
Roland Levillain1252e972015-08-06 15:46:02 +010099void HConstantFoldingVisitor::VisitUnaryOperation(HUnaryOperation* inst) {
100 // Constant folding: replace `op(a)' with a constant at compile
101 // time if `a' is a constant.
102 HConstant* constant = inst->TryStaticEvaluation();
103 if (constant != nullptr) {
104 inst->ReplaceWith(constant);
105 inst->GetBlock()->RemoveInstruction(inst);
106 }
107}
108
109void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
110 // Constant folding: replace `op(a, b)' with a constant at
111 // compile time if `a' and `b' are both constants.
112 HConstant* constant = inst->TryStaticEvaluation();
113 if (constant != nullptr) {
114 inst->ReplaceWith(constant);
115 inst->GetBlock()->RemoveInstruction(inst);
116 } else {
117 InstructionWithAbsorbingInputSimplifier simplifier(GetGraph());
118 inst->Accept(&simplifier);
119 }
120}
121
122void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) {
123 // Constant folding: replace `TypeConversion(a)' with a constant at
124 // compile time if `a' is a constant.
Mingyao Yang75bb2f32017-11-30 14:45:44 -0800125 HConstant* constant = inst->TryStaticEvaluation();
Roland Levillain1252e972015-08-06 15:46:02 +0100126 if (constant != nullptr) {
127 inst->ReplaceWith(constant);
128 inst->GetBlock()->RemoveInstruction(inst);
129 }
130}
131
132void HConstantFoldingVisitor::VisitDivZeroCheck(HDivZeroCheck* inst) {
133 // We can safely remove the check if the input is a non-null constant.
134 HInstruction* check_input = inst->InputAt(0);
Roland Levillain1a653882016-03-18 18:05:57 +0000135 if (check_input->IsConstant() && !check_input->AsConstant()->IsArithmeticZero()) {
Roland Levillain1252e972015-08-06 15:46:02 +0100136 inst->ReplaceWith(check_input);
137 inst->GetBlock()->RemoveInstruction(inst);
138 }
139}
140
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +0000141void HConstantFoldingVisitor::PropagateValue(HBasicBlock* starting_block,
142 HInstruction* variable,
143 HConstant* constant) {
144 const bool recording_stats = stats_ != nullptr;
145 size_t uses_before = 0;
146 size_t uses_after = 0;
147 if (recording_stats) {
148 uses_before = variable->GetUses().SizeSlow();
149 }
150
151 variable->ReplaceUsesDominatedBy(
152 starting_block->GetFirstInstruction(), constant, /* strictly_dominated= */ false);
153
154 if (recording_stats) {
155 uses_after = variable->GetUses().SizeSlow();
156 DCHECK_GE(uses_after, 1u) << "we must at least have the use in the if clause.";
157 DCHECK_GE(uses_before, uses_after);
158 MaybeRecordStat(stats_, MethodCompilationStat::kPropagatedIfValue, uses_before - uses_after);
159 }
160}
161
162void HConstantFoldingVisitor::VisitIf(HIf* inst) {
163 // Consistency check: the true and false successors do not dominate each other.
164 DCHECK(!inst->IfTrueSuccessor()->Dominates(inst->IfFalseSuccessor()) &&
165 !inst->IfFalseSuccessor()->Dominates(inst->IfTrueSuccessor()));
166
167 HInstruction* if_input = inst->InputAt(0);
168
169 // Already a constant.
170 if (if_input->IsConstant()) {
171 return;
172 }
173
174 // if (variable) {
175 // SSA `variable` guaranteed to be true
176 // } else {
177 // and here false
178 // }
179 PropagateValue(inst->IfTrueSuccessor(), if_input, GetGraph()->GetIntConstant(1));
180 PropagateValue(inst->IfFalseSuccessor(), if_input, GetGraph()->GetIntConstant(0));
181
182 // If the input is a condition, we can propagate the information of the condition itself.
183 if (!if_input->IsCondition()) {
184 return;
185 }
186 HCondition* condition = if_input->AsCondition();
187
188 // We want either `==` or `!=`, since we cannot make assumptions for other conditions e.g. `>`
189 if (!condition->IsEqual() && !condition->IsNotEqual()) {
190 return;
191 }
192
193 HInstruction* left = condition->GetLeft();
194 HInstruction* right = condition->GetRight();
195
196 // We want one of them to be a constant and not the other.
197 if (left->IsConstant() == right->IsConstant()) {
198 return;
199 }
200
201 // At this point we have something like:
202 // if (variable == constant) {
203 // SSA `variable` guaranteed to be equal to constant here
204 // } else {
205 // No guarantees can be made here (usually, see boolean case below).
206 // }
207 // Similarly with variable != constant, except that we can make guarantees in the else case.
208
209 HConstant* constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
210 HInstruction* variable = left->IsConstant() ? right : left;
211
212 // Don't deal with floats/doubles since they bring a lot of edge cases e.g.
213 // if (f == 0.0f) {
214 // // f is not really guaranteed to be 0.0f. It could be -0.0f, for example
215 // }
216 if (DataType::IsFloatingPointType(variable->GetType())) {
217 return;
218 }
219 DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
220
221 // Sometimes we have an HCompare flowing into an Equals/NonEquals, which can act as a proxy. For
222 // example: `Equals(Compare(var, constant), 0)`. This is common for long, float, and double.
223 if (variable->IsCompare()) {
224 // We only care about equality comparisons so we skip if it is a less or greater comparison.
225 if (!constant->IsArithmeticZero()) {
226 return;
227 }
228
229 // Update left and right to be the ones from the HCompare.
230 left = variable->AsCompare()->GetLeft();
231 right = variable->AsCompare()->GetRight();
232
233 // Re-check that one of them to be a constant and not the other.
234 if (left->IsConstant() == right->IsConstant()) {
235 return;
236 }
237
238 constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
239 variable = left->IsConstant() ? right : left;
240
241 // Re-check floating point values.
242 if (DataType::IsFloatingPointType(variable->GetType())) {
243 return;
244 }
245 DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
246 }
247
248 // From this block forward we want to replace the SSA value. We use `starting_block` and not the
249 // `if` block as we want to update one of the branches but not the other.
250 HBasicBlock* starting_block =
251 condition->IsEqual() ? inst->IfTrueSuccessor() : inst->IfFalseSuccessor();
252
253 PropagateValue(starting_block, variable, constant);
254
255 // Special case for booleans since they have only two values so we know what to propagate in the
256 // other branch. However, sometimes our boolean values are not compared to 0 or 1. In those cases
257 // we cannot make an assumption for the `else` branch.
258 if (variable->GetType() == DataType::Type::kBool &&
259 constant->IsIntConstant() &&
260 (constant->AsIntConstant()->IsTrue() || constant->AsIntConstant()->IsFalse())) {
261 HBasicBlock* other_starting_block =
262 condition->IsEqual() ? inst->IfFalseSuccessor() : inst->IfTrueSuccessor();
263 DCHECK_NE(other_starting_block, starting_block);
264
265 HConstant* other_constant = constant->AsIntConstant()->IsTrue() ?
266 GetGraph()->GetIntConstant(0) :
267 GetGraph()->GetIntConstant(1);
268 DCHECK_NE(other_constant, constant);
269 PropagateValue(other_starting_block, variable, other_constant);
270 }
271}
Roland Levillain1252e972015-08-06 15:46:02 +0100272
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000273void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) {
274 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
275 HInstruction* left = instruction->GetLeft();
Roland Levillain1a653882016-03-18 18:05:57 +0000276 if (left->IsConstant() && left->AsConstant()->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000277 // Replace code looking like
278 // SHL dst, 0, shift_amount
279 // with
280 // CONSTANT 0
281 instruction->ReplaceWith(left);
282 instruction->GetBlock()->RemoveInstruction(instruction);
283 }
284}
285
Vladimir Markoa341f352016-08-31 12:18:20 +0100286void InstructionWithAbsorbingInputSimplifier::VisitEqual(HEqual* instruction) {
287 if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
288 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
289 // Replace code looking like
290 // EQUAL lhs, null
291 // where lhs cannot be null with
292 // CONSTANT false
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100293 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
Vladimir Markoa341f352016-08-31 12:18:20 +0100294 instruction->GetBlock()->RemoveInstruction(instruction);
295 }
296}
297
298void InstructionWithAbsorbingInputSimplifier::VisitNotEqual(HNotEqual* instruction) {
299 if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
300 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
301 // Replace code looking like
302 // NOT_EQUAL lhs, null
303 // where lhs cannot be null with
304 // CONSTANT true
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100305 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
Vladimir Markoa341f352016-08-31 12:18:20 +0100306 instruction->GetBlock()->RemoveInstruction(instruction);
307 }
308}
309
Aart Bik96709f12015-10-28 17:49:07 -0700310void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
311 if (instruction->GetLeft()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000312 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700313 // Replace code looking like
314 // ABOVE dst, 0, src // unsigned 0 > src is always false
315 // with
316 // CONSTANT false
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100317 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700318 instruction->GetBlock()->RemoveInstruction(instruction);
319 }
320}
321
322void InstructionWithAbsorbingInputSimplifier::VisitAboveOrEqual(HAboveOrEqual* instruction) {
323 if (instruction->GetRight()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000324 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700325 // Replace code looking like
326 // ABOVE_OR_EQUAL dst, src, 0 // unsigned src >= 0 is always true
327 // with
328 // CONSTANT true
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100329 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
Aart Bik96709f12015-10-28 17:49:07 -0700330 instruction->GetBlock()->RemoveInstruction(instruction);
331 }
332}
333
334void InstructionWithAbsorbingInputSimplifier::VisitBelow(HBelow* instruction) {
335 if (instruction->GetRight()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000336 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700337 // Replace code looking like
338 // BELOW dst, src, 0 // unsigned src < 0 is always false
339 // with
340 // CONSTANT false
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100341 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700342 instruction->GetBlock()->RemoveInstruction(instruction);
343 }
344}
345
346void InstructionWithAbsorbingInputSimplifier::VisitBelowOrEqual(HBelowOrEqual* instruction) {
347 if (instruction->GetLeft()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000348 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700349 // Replace code looking like
350 // BELOW_OR_EQUAL dst, 0, src // unsigned 0 <= src is always true
351 // with
352 // CONSTANT true
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100353 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
Aart Bik96709f12015-10-28 17:49:07 -0700354 instruction->GetBlock()->RemoveInstruction(instruction);
355 }
356}
357
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000358void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
Balaram Makam4eb6eb42019-09-10 09:41:29 -0500359 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000360 HConstant* input_cst = instruction->GetConstantRight();
Roland Levillain1a653882016-03-18 18:05:57 +0000361 if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000362 // Replace code looking like
363 // AND dst, src, 0
364 // with
365 // CONSTANT 0
366 instruction->ReplaceWith(input_cst);
367 instruction->GetBlock()->RemoveInstruction(instruction);
368 }
Balaram Makam4eb6eb42019-09-10 09:41:29 -0500369
370 HInstruction* left = instruction->GetLeft();
371 HInstruction* right = instruction->GetRight();
372
373 if (left->IsNot() ^ right->IsNot()) {
374 // Replace code looking like
375 // NOT notsrc, src
376 // AND dst, notsrc, src
377 // with
378 // CONSTANT 0
379 HInstruction* hnot = (left->IsNot() ? left : right);
380 HInstruction* hother = (left->IsNot() ? right : left);
381 HInstruction* src = hnot->AsNot()->GetInput();
382
383 if (src == hother) {
384 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
385 instruction->GetBlock()->RemoveInstruction(instruction);
386 }
387 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000388}
389
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100390void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
391 HConstant* input_cst = instruction->GetConstantRight();
392 if (input_cst != nullptr) {
393 HInstruction* input_value = instruction->GetLeastConstantLeft();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100394 if (DataType::IsFloatingPointType(input_value->GetType()) &&
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100395 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
396 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
397 // Replace code looking like
Roland Levillain31dd3d62016-02-16 12:21:02 +0000398 // CMP{G,L}-{FLOAT,DOUBLE} dst, src, NaN
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100399 // with
400 // CONSTANT +1 (gt bias)
401 // or
402 // CONSTANT -1 (lt bias)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100403 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kInt32,
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100404 (instruction->IsGtBias() ? 1 : -1)));
405 instruction->GetBlock()->RemoveInstruction(instruction);
406 }
407 }
408}
409
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000410void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
411 HConstant* input_cst = instruction->GetConstantRight();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100412 DataType::Type type = instruction->GetType();
413 if (DataType::IsIntOrLongType(type) &&
Roland Levillain1a653882016-03-18 18:05:57 +0000414 (input_cst != nullptr) && input_cst->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000415 // Replace code looking like
416 // MUL dst, src, 0
417 // with
418 // CONSTANT 0
419 // Integral multiplication by zero always yields zero, but floating-point
420 // multiplication by zero does not always do. For example `Infinity * 0.0`
421 // should yield a NaN.
422 instruction->ReplaceWith(input_cst);
423 instruction->GetBlock()->RemoveInstruction(instruction);
424 }
425}
426
427void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
428 HConstant* input_cst = instruction->GetConstantRight();
429
430 if (input_cst == nullptr) {
431 return;
432 }
433
434 if (Int64FromConstant(input_cst) == -1) {
435 // Replace code looking like
436 // OR dst, src, 0xFFF...FF
437 // with
438 // CONSTANT 0xFFF...FF
439 instruction->ReplaceWith(input_cst);
440 instruction->GetBlock()->RemoveInstruction(instruction);
441 }
442}
443
444void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100445 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000446
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100447 if (!DataType::IsIntegralType(type)) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000448 return;
449 }
450
451 HBasicBlock* block = instruction->GetBlock();
452
453 if (instruction->GetLeft()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000454 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000455 // Replace code looking like
456 // REM dst, 0, src
457 // with
458 // CONSTANT 0
459 instruction->ReplaceWith(instruction->GetLeft());
460 block->RemoveInstruction(instruction);
461 }
462
463 HConstant* cst_right = instruction->GetRight()->AsConstant();
464 if (((cst_right != nullptr) &&
465 (cst_right->IsOne() || cst_right->IsMinusOne())) ||
466 (instruction->GetLeft() == instruction->GetRight())) {
467 // Replace code looking like
468 // REM dst, src, 1
469 // or
470 // REM dst, src, -1
471 // or
472 // REM dst, src, src
473 // with
474 // CONSTANT 0
David Brazdil8d5b8b22015-03-24 10:51:52 +0000475 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
476 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000477 }
478}
479
480void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) {
481 VisitShift(instruction);
482}
483
484void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) {
485 VisitShift(instruction);
486}
487
488void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100489 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000490
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100491 if (!DataType::IsIntegralType(type)) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000492 return;
493 }
494
495 HBasicBlock* block = instruction->GetBlock();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000496
497 // We assume that GVN has run before, so we only perform a pointer
498 // comparison. If for some reason the values are equal but the pointers are
Kenny Root00d597a2015-09-30 13:09:51 -0700499 // different, we are still correct and only miss an optimization
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000500 // opportunity.
501 if (instruction->GetLeft() == instruction->GetRight()) {
502 // Replace code looking like
503 // SUB dst, src, src
504 // with
505 // CONSTANT 0
Kenny Root00d597a2015-09-30 13:09:51 -0700506 // Note that we cannot optimize `x - x` to `0` for floating-point. It does
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000507 // not work when `x` is an infinity.
David Brazdil8d5b8b22015-03-24 10:51:52 +0000508 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
509 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000510 }
511}
512
513void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) {
514 VisitShift(instruction);
515}
516
517void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) {
518 if (instruction->GetLeft() == instruction->GetRight()) {
519 // Replace code looking like
520 // XOR dst, src, src
521 // with
522 // CONSTANT 0
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100523 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000524 HBasicBlock* block = instruction->GetBlock();
David Brazdil8d5b8b22015-03-24 10:51:52 +0000525 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
526 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000527 }
528}
529
Roland Levillain556c3d12014-09-18 15:25:07 +0100530} // namespace art