blob: 2163c007e628edec6dcf9624b96e6931517dbcd5 [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
Santiago Aboy Solanesc63bdde2023-03-31 16:04:22 +010021#include "dex/dex_file-inl.h"
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +000022#include "optimizing/data_type.h"
23#include "optimizing/nodes.h"
24
VladimĂ­r Marko434d9682022-11-04 14:04:17 +000025namespace art HIDDEN {
Roland Levillain556c3d12014-09-18 15:25:07 +010026
Roland Levillain1252e972015-08-06 15:46:02 +010027// This visitor tries to simplify instructions that can be evaluated
28// as constants.
Vladimir Marko30759fa2023-04-05 09:43:21 +020029class HConstantFoldingVisitor final : public HGraphDelegateVisitor {
Roland Levillain1252e972015-08-06 15:46:02 +010030 public:
Santiago Aboy Solanes5eb1fd02023-04-18 15:16:06 +010031 HConstantFoldingVisitor(HGraph* graph, OptimizingCompilerStats* stats, bool use_all_optimizations)
32 : HGraphDelegateVisitor(graph, stats), use_all_optimizations_(use_all_optimizations) {}
Roland Levillain1252e972015-08-06 15:46:02 +010033
34 private:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010035 void VisitBasicBlock(HBasicBlock* block) override;
Roland Levillain1252e972015-08-06 15:46:02 +010036
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010037 void VisitUnaryOperation(HUnaryOperation* inst) override;
38 void VisitBinaryOperation(HBinaryOperation* inst) override;
Roland Levillain1252e972015-08-06 15:46:02 +010039
Santiago Aboy Solanesc63bdde2023-03-31 16:04:22 +010040 void VisitArrayLength(HArrayLength* inst) override;
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010041 void VisitDivZeroCheck(HDivZeroCheck* inst) override;
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +000042 void VisitIf(HIf* inst) override;
Santiago Aboy Solanesc63bdde2023-03-31 16:04:22 +010043 void VisitTypeConversion(HTypeConversion* inst) override;
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +000044
45 void PropagateValue(HBasicBlock* starting_block, HInstruction* variable, HConstant* constant);
Roland Levillain1252e972015-08-06 15:46:02 +010046
Santiago Aboy Solanes5eb1fd02023-04-18 15:16:06 +010047 // Use all optimizations without restrictions.
48 bool use_all_optimizations_;
49
Roland Levillain1252e972015-08-06 15:46:02 +010050 DISALLOW_COPY_AND_ASSIGN(HConstantFoldingVisitor);
51};
52
53// This visitor tries to simplify operations with an absorbing input,
54// yielding a constant. For example `input * 0` is replaced by a
55// null constant.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000056class InstructionWithAbsorbingInputSimplifier : public HGraphVisitor {
57 public:
58 explicit InstructionWithAbsorbingInputSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
59
60 private:
61 void VisitShift(HBinaryOperation* shift);
62
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010063 void VisitEqual(HEqual* instruction) override;
64 void VisitNotEqual(HNotEqual* instruction) override;
Vladimir Markoa341f352016-08-31 12:18:20 +010065
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010066 void VisitAbove(HAbove* instruction) override;
67 void VisitAboveOrEqual(HAboveOrEqual* instruction) override;
68 void VisitBelow(HBelow* instruction) override;
69 void VisitBelowOrEqual(HBelowOrEqual* instruction) override;
Aart Bik96709f12015-10-28 17:49:07 -070070
Santiago Aboy Solanesc1d61212023-03-16 10:27:29 +000071 void VisitGreaterThan(HGreaterThan* instruction) override;
72 void VisitGreaterThanOrEqual(HGreaterThanOrEqual* instruction) override;
73 void VisitLessThan(HLessThan* instruction) override;
74 void VisitLessThanOrEqual(HLessThanOrEqual* instruction) override;
75
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010076 void VisitAnd(HAnd* instruction) override;
77 void VisitCompare(HCompare* instruction) override;
78 void VisitMul(HMul* instruction) override;
79 void VisitOr(HOr* instruction) override;
80 void VisitRem(HRem* instruction) override;
81 void VisitShl(HShl* instruction) override;
82 void VisitShr(HShr* instruction) override;
83 void VisitSub(HSub* instruction) override;
84 void VisitUShr(HUShr* instruction) override;
85 void VisitXor(HXor* instruction) override;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000086};
87
Roland Levillain1252e972015-08-06 15:46:02 +010088
Aart Bik24773202018-04-26 10:28:51 -070089bool HConstantFolding::Run() {
Santiago Aboy Solanes5eb1fd02023-04-18 15:16:06 +010090 HConstantFoldingVisitor visitor(graph_, stats_, use_all_optimizations_);
Roland Levillain556c3d12014-09-18 15:25:07 +010091 // Process basic blocks in reverse post-order in the dominator tree,
92 // so that an instruction turned into a constant, used as input of
93 // another instruction, may possibly be used to turn that second
94 // instruction into a constant as well.
Roland Levillain1252e972015-08-06 15:46:02 +010095 visitor.VisitReversePostOrder();
Aart Bik24773202018-04-26 10:28:51 -070096 return true;
Roland Levillain1252e972015-08-06 15:46:02 +010097}
98
99
100void HConstantFoldingVisitor::VisitBasicBlock(HBasicBlock* block) {
101 // Traverse this block's instructions (phis don't need to be
102 // processed) in (forward) order and replace the ones that can be
103 // statically evaluated by a compile-time counterpart.
104 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
105 it.Current()->Accept(this);
Roland Levillain556c3d12014-09-18 15:25:07 +0100106 }
107}
108
Roland Levillain1252e972015-08-06 15:46:02 +0100109void HConstantFoldingVisitor::VisitUnaryOperation(HUnaryOperation* inst) {
110 // Constant folding: replace `op(a)' with a constant at compile
111 // time if `a' is a constant.
112 HConstant* constant = inst->TryStaticEvaluation();
113 if (constant != nullptr) {
114 inst->ReplaceWith(constant);
115 inst->GetBlock()->RemoveInstruction(inst);
116 }
117}
118
119void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
120 // Constant folding: replace `op(a, b)' with a constant at
121 // compile time if `a' and `b' are both constants.
122 HConstant* constant = inst->TryStaticEvaluation();
123 if (constant != nullptr) {
124 inst->ReplaceWith(constant);
125 inst->GetBlock()->RemoveInstruction(inst);
126 } else {
127 InstructionWithAbsorbingInputSimplifier simplifier(GetGraph());
128 inst->Accept(&simplifier);
129 }
130}
131
Roland Levillain1252e972015-08-06 15:46:02 +0100132void 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);
Vladimir Markocde64972023-04-25 16:40:06 +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
Santiago Aboy Solanes5eb1fd02023-04-18 15:16:06 +0100151 if (variable->GetUses().HasExactlyOneElement()) {
152 // Nothing to do, since we only have the `if (variable)` use or the `condition` use.
153 return;
154 }
155
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +0000156 variable->ReplaceUsesDominatedBy(
157 starting_block->GetFirstInstruction(), constant, /* strictly_dominated= */ false);
158
159 if (recording_stats) {
160 uses_after = variable->GetUses().SizeSlow();
161 DCHECK_GE(uses_after, 1u) << "we must at least have the use in the if clause.";
162 DCHECK_GE(uses_before, uses_after);
163 MaybeRecordStat(stats_, MethodCompilationStat::kPropagatedIfValue, uses_before - uses_after);
164 }
165}
166
167void HConstantFoldingVisitor::VisitIf(HIf* inst) {
Santiago Aboy Solanes5eb1fd02023-04-18 15:16:06 +0100168 // This optimization can take a lot of compile time since we have a lot of If instructions in
169 // graphs.
170 if (!use_all_optimizations_) {
171 return;
172 }
173
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +0000174 // Consistency check: the true and false successors do not dominate each other.
175 DCHECK(!inst->IfTrueSuccessor()->Dominates(inst->IfFalseSuccessor()) &&
176 !inst->IfFalseSuccessor()->Dominates(inst->IfTrueSuccessor()));
177
178 HInstruction* if_input = inst->InputAt(0);
179
180 // Already a constant.
181 if (if_input->IsConstant()) {
182 return;
183 }
184
185 // if (variable) {
186 // SSA `variable` guaranteed to be true
187 // } else {
188 // and here false
189 // }
190 PropagateValue(inst->IfTrueSuccessor(), if_input, GetGraph()->GetIntConstant(1));
191 PropagateValue(inst->IfFalseSuccessor(), if_input, GetGraph()->GetIntConstant(0));
192
193 // If the input is a condition, we can propagate the information of the condition itself.
194 if (!if_input->IsCondition()) {
195 return;
196 }
Vladimir Markocde64972023-04-25 16:40:06 +0000197 HCondition* condition = if_input->AsCondition();
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +0000198
199 // We want either `==` or `!=`, since we cannot make assumptions for other conditions e.g. `>`
200 if (!condition->IsEqual() && !condition->IsNotEqual()) {
201 return;
202 }
203
204 HInstruction* left = condition->GetLeft();
205 HInstruction* right = condition->GetRight();
206
207 // We want one of them to be a constant and not the other.
208 if (left->IsConstant() == right->IsConstant()) {
209 return;
210 }
211
212 // At this point we have something like:
213 // if (variable == constant) {
214 // SSA `variable` guaranteed to be equal to constant here
215 // } else {
216 // No guarantees can be made here (usually, see boolean case below).
217 // }
218 // Similarly with variable != constant, except that we can make guarantees in the else case.
219
Vladimir Markocde64972023-04-25 16:40:06 +0000220 HConstant* constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +0000221 HInstruction* variable = left->IsConstant() ? right : left;
222
223 // Don't deal with floats/doubles since they bring a lot of edge cases e.g.
224 // if (f == 0.0f) {
225 // // f is not really guaranteed to be 0.0f. It could be -0.0f, for example
226 // }
227 if (DataType::IsFloatingPointType(variable->GetType())) {
228 return;
229 }
230 DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
231
232 // Sometimes we have an HCompare flowing into an Equals/NonEquals, which can act as a proxy. For
233 // example: `Equals(Compare(var, constant), 0)`. This is common for long, float, and double.
234 if (variable->IsCompare()) {
235 // We only care about equality comparisons so we skip if it is a less or greater comparison.
236 if (!constant->IsArithmeticZero()) {
237 return;
238 }
239
240 // Update left and right to be the ones from the HCompare.
Vladimir Markocde64972023-04-25 16:40:06 +0000241 left = variable->AsCompare()->GetLeft();
242 right = variable->AsCompare()->GetRight();
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +0000243
244 // Re-check that one of them to be a constant and not the other.
245 if (left->IsConstant() == right->IsConstant()) {
246 return;
247 }
248
Vladimir Markocde64972023-04-25 16:40:06 +0000249 constant = left->IsConstant() ? left->AsConstant() : right->AsConstant();
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +0000250 variable = left->IsConstant() ? right : left;
251
252 // Re-check floating point values.
253 if (DataType::IsFloatingPointType(variable->GetType())) {
254 return;
255 }
256 DCHECK(!DataType::IsFloatingPointType(constant->GetType()));
257 }
258
259 // From this block forward we want to replace the SSA value. We use `starting_block` and not the
260 // `if` block as we want to update one of the branches but not the other.
261 HBasicBlock* starting_block =
262 condition->IsEqual() ? inst->IfTrueSuccessor() : inst->IfFalseSuccessor();
263
264 PropagateValue(starting_block, variable, constant);
265
266 // Special case for booleans since they have only two values so we know what to propagate in the
267 // other branch. However, sometimes our boolean values are not compared to 0 or 1. In those cases
268 // we cannot make an assumption for the `else` branch.
269 if (variable->GetType() == DataType::Type::kBool &&
270 constant->IsIntConstant() &&
Vladimir Markocde64972023-04-25 16:40:06 +0000271 (constant->AsIntConstant()->IsTrue() || constant->AsIntConstant()->IsFalse())) {
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +0000272 HBasicBlock* other_starting_block =
273 condition->IsEqual() ? inst->IfFalseSuccessor() : inst->IfTrueSuccessor();
274 DCHECK_NE(other_starting_block, starting_block);
275
Vladimir Markocde64972023-04-25 16:40:06 +0000276 HConstant* other_constant = constant->AsIntConstant()->IsTrue() ?
Santiago Aboy Solanes8c3b58a2022-08-15 13:21:59 +0000277 GetGraph()->GetIntConstant(0) :
278 GetGraph()->GetIntConstant(1);
279 DCHECK_NE(other_constant, constant);
280 PropagateValue(other_starting_block, variable, other_constant);
281 }
282}
Roland Levillain1252e972015-08-06 15:46:02 +0100283
Santiago Aboy Solanesc63bdde2023-03-31 16:04:22 +0100284void HConstantFoldingVisitor::VisitArrayLength(HArrayLength* inst) {
285 HInstruction* input = inst->InputAt(0);
286 if (input->IsLoadString()) {
287 DCHECK(inst->IsStringLength());
Vladimir Markocde64972023-04-25 16:40:06 +0000288 HLoadString* load_string = input->AsLoadString();
Santiago Aboy Solanesc63bdde2023-03-31 16:04:22 +0100289 const DexFile& dex_file = load_string->GetDexFile();
290 const dex::StringId& string_id = dex_file.GetStringId(load_string->GetStringIndex());
291 inst->ReplaceWith(GetGraph()->GetIntConstant(dex_file.GetStringLength(string_id)));
292 }
293}
294
295void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) {
296 // Constant folding: replace `TypeConversion(a)' with a constant at
297 // compile time if `a' is a constant.
298 HConstant* constant = inst->TryStaticEvaluation();
299 if (constant != nullptr) {
300 inst->ReplaceWith(constant);
301 inst->GetBlock()->RemoveInstruction(inst);
302 }
303}
304
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000305void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) {
306 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
307 HInstruction* left = instruction->GetLeft();
Vladimir Markocde64972023-04-25 16:40:06 +0000308 if (left->IsConstant() && left->AsConstant()->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000309 // Replace code looking like
310 // SHL dst, 0, shift_amount
311 // with
312 // CONSTANT 0
313 instruction->ReplaceWith(left);
314 instruction->GetBlock()->RemoveInstruction(instruction);
315 }
316}
317
Vladimir Markoa341f352016-08-31 12:18:20 +0100318void InstructionWithAbsorbingInputSimplifier::VisitEqual(HEqual* instruction) {
Santiago Aboy Solanesc1d61212023-03-16 10:27:29 +0000319 if (instruction->GetLeft() == instruction->GetRight() &&
320 !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
321 // Replace code looking like
322 // EQUAL lhs, lhs
323 // CONSTANT true
324 // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
325 // opposite value.
326 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
327 instruction->GetBlock()->RemoveInstruction(instruction);
328 } else if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
329 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
Vladimir Markoa341f352016-08-31 12:18:20 +0100330 // Replace code looking like
331 // EQUAL lhs, null
332 // where lhs cannot be null with
333 // CONSTANT false
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100334 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
Vladimir Markoa341f352016-08-31 12:18:20 +0100335 instruction->GetBlock()->RemoveInstruction(instruction);
336 }
337}
338
339void InstructionWithAbsorbingInputSimplifier::VisitNotEqual(HNotEqual* instruction) {
Santiago Aboy Solanesc1d61212023-03-16 10:27:29 +0000340 if (instruction->GetLeft() == instruction->GetRight() &&
341 !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
342 // Replace code looking like
343 // NOT_EQUAL lhs, lhs
344 // CONSTANT false
345 // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
346 // opposite value.
347 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
348 instruction->GetBlock()->RemoveInstruction(instruction);
349 } else if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
350 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
Vladimir Markoa341f352016-08-31 12:18:20 +0100351 // Replace code looking like
352 // NOT_EQUAL lhs, null
353 // where lhs cannot be null with
354 // CONSTANT true
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100355 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
Vladimir Markoa341f352016-08-31 12:18:20 +0100356 instruction->GetBlock()->RemoveInstruction(instruction);
357 }
358}
359
Aart Bik96709f12015-10-28 17:49:07 -0700360void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
Santiago Aboy Solanesc1d61212023-03-16 10:27:29 +0000361 if (instruction->GetLeft() == instruction->GetRight()) {
362 // Replace code looking like
363 // ABOVE lhs, lhs
364 // CONSTANT false
365 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
366 instruction->GetBlock()->RemoveInstruction(instruction);
367 } else if (instruction->GetLeft()->IsConstant() &&
Vladimir Markocde64972023-04-25 16:40:06 +0000368 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700369 // Replace code looking like
370 // ABOVE dst, 0, src // unsigned 0 > src is always false
371 // with
372 // CONSTANT false
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100373 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700374 instruction->GetBlock()->RemoveInstruction(instruction);
375 }
376}
377
378void InstructionWithAbsorbingInputSimplifier::VisitAboveOrEqual(HAboveOrEqual* instruction) {
Santiago Aboy Solanesc1d61212023-03-16 10:27:29 +0000379 if (instruction->GetLeft() == instruction->GetRight()) {
380 // Replace code looking like
381 // ABOVE_OR_EQUAL lhs, lhs
382 // CONSTANT true
383 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
384 instruction->GetBlock()->RemoveInstruction(instruction);
385 } else if (instruction->GetRight()->IsConstant() &&
Vladimir Markocde64972023-04-25 16:40:06 +0000386 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700387 // Replace code looking like
388 // ABOVE_OR_EQUAL dst, src, 0 // unsigned src >= 0 is always true
389 // with
390 // CONSTANT true
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100391 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
Aart Bik96709f12015-10-28 17:49:07 -0700392 instruction->GetBlock()->RemoveInstruction(instruction);
393 }
394}
395
396void InstructionWithAbsorbingInputSimplifier::VisitBelow(HBelow* instruction) {
Santiago Aboy Solanesc1d61212023-03-16 10:27:29 +0000397 if (instruction->GetLeft() == instruction->GetRight()) {
398 // Replace code looking like
399 // BELOW lhs, lhs
400 // CONSTANT false
401 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
402 instruction->GetBlock()->RemoveInstruction(instruction);
403 } else if (instruction->GetRight()->IsConstant() &&
Vladimir Markocde64972023-04-25 16:40:06 +0000404 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700405 // Replace code looking like
406 // BELOW dst, src, 0 // unsigned src < 0 is always false
407 // with
408 // CONSTANT false
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100409 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700410 instruction->GetBlock()->RemoveInstruction(instruction);
411 }
412}
413
414void InstructionWithAbsorbingInputSimplifier::VisitBelowOrEqual(HBelowOrEqual* instruction) {
Santiago Aboy Solanesc1d61212023-03-16 10:27:29 +0000415 if (instruction->GetLeft() == instruction->GetRight()) {
416 // Replace code looking like
417 // BELOW_OR_EQUAL lhs, lhs
418 // CONSTANT true
419 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
420 instruction->GetBlock()->RemoveInstruction(instruction);
421 } else if (instruction->GetLeft()->IsConstant() &&
Vladimir Markocde64972023-04-25 16:40:06 +0000422 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700423 // Replace code looking like
424 // BELOW_OR_EQUAL dst, 0, src // unsigned 0 <= src is always true
425 // with
426 // CONSTANT true
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100427 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
Aart Bik96709f12015-10-28 17:49:07 -0700428 instruction->GetBlock()->RemoveInstruction(instruction);
429 }
430}
431
Santiago Aboy Solanesc1d61212023-03-16 10:27:29 +0000432void InstructionWithAbsorbingInputSimplifier::VisitGreaterThan(HGreaterThan* instruction) {
433 if (instruction->GetLeft() == instruction->GetRight() &&
434 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
435 instruction->IsLtBias())) {
436 // Replace code looking like
437 // GREATER_THAN lhs, lhs
438 // CONSTANT false
439 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
440 instruction->GetBlock()->RemoveInstruction(instruction);
441 }
442}
443
444void InstructionWithAbsorbingInputSimplifier::VisitGreaterThanOrEqual(
445 HGreaterThanOrEqual* instruction) {
446 if (instruction->GetLeft() == instruction->GetRight() &&
447 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
448 instruction->IsGtBias())) {
449 // Replace code looking like
450 // GREATER_THAN_OR_EQUAL lhs, lhs
451 // CONSTANT true
452 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
453 instruction->GetBlock()->RemoveInstruction(instruction);
454 }
455}
456
457void InstructionWithAbsorbingInputSimplifier::VisitLessThan(HLessThan* instruction) {
458 if (instruction->GetLeft() == instruction->GetRight() &&
459 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
460 instruction->IsGtBias())) {
461 // Replace code looking like
462 // LESS_THAN lhs, lhs
463 // CONSTANT false
464 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
465 instruction->GetBlock()->RemoveInstruction(instruction);
466 }
467}
468
469void InstructionWithAbsorbingInputSimplifier::VisitLessThanOrEqual(HLessThanOrEqual* instruction) {
470 if (instruction->GetLeft() == instruction->GetRight() &&
471 (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
472 instruction->IsLtBias())) {
473 // Replace code looking like
474 // LESS_THAN_OR_EQUAL lhs, lhs
475 // CONSTANT true
476 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
477 instruction->GetBlock()->RemoveInstruction(instruction);
478 }
479}
480
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000481void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
Balaram Makam4eb6eb42019-09-10 09:41:29 -0500482 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000483 HConstant* input_cst = instruction->GetConstantRight();
Roland Levillain1a653882016-03-18 18:05:57 +0000484 if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000485 // Replace code looking like
486 // AND dst, src, 0
487 // with
488 // CONSTANT 0
489 instruction->ReplaceWith(input_cst);
490 instruction->GetBlock()->RemoveInstruction(instruction);
491 }
Balaram Makam4eb6eb42019-09-10 09:41:29 -0500492
493 HInstruction* left = instruction->GetLeft();
494 HInstruction* right = instruction->GetRight();
495
496 if (left->IsNot() ^ right->IsNot()) {
497 // Replace code looking like
498 // NOT notsrc, src
499 // AND dst, notsrc, src
500 // with
501 // CONSTANT 0
502 HInstruction* hnot = (left->IsNot() ? left : right);
503 HInstruction* hother = (left->IsNot() ? right : left);
Vladimir Markocde64972023-04-25 16:40:06 +0000504 HInstruction* src = hnot->AsNot()->GetInput();
Balaram Makam4eb6eb42019-09-10 09:41:29 -0500505
506 if (src == hother) {
507 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
508 instruction->GetBlock()->RemoveInstruction(instruction);
509 }
510 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000511}
512
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100513void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
514 HConstant* input_cst = instruction->GetConstantRight();
515 if (input_cst != nullptr) {
516 HInstruction* input_value = instruction->GetLeastConstantLeft();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100517 if (DataType::IsFloatingPointType(input_value->GetType()) &&
Vladimir Markocde64972023-04-25 16:40:06 +0000518 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
519 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100520 // Replace code looking like
Roland Levillain31dd3d62016-02-16 12:21:02 +0000521 // CMP{G,L}-{FLOAT,DOUBLE} dst, src, NaN
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100522 // with
523 // CONSTANT +1 (gt bias)
524 // or
525 // CONSTANT -1 (lt bias)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100526 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kInt32,
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100527 (instruction->IsGtBias() ? 1 : -1)));
528 instruction->GetBlock()->RemoveInstruction(instruction);
529 }
530 }
531}
532
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000533void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
534 HConstant* input_cst = instruction->GetConstantRight();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100535 DataType::Type type = instruction->GetType();
536 if (DataType::IsIntOrLongType(type) &&
Roland Levillain1a653882016-03-18 18:05:57 +0000537 (input_cst != nullptr) && input_cst->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000538 // Replace code looking like
539 // MUL dst, src, 0
540 // with
541 // CONSTANT 0
542 // Integral multiplication by zero always yields zero, but floating-point
543 // multiplication by zero does not always do. For example `Infinity * 0.0`
544 // should yield a NaN.
545 instruction->ReplaceWith(input_cst);
546 instruction->GetBlock()->RemoveInstruction(instruction);
547 }
548}
549
550void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
551 HConstant* input_cst = instruction->GetConstantRight();
552
553 if (input_cst == nullptr) {
554 return;
555 }
556
557 if (Int64FromConstant(input_cst) == -1) {
558 // Replace code looking like
559 // OR dst, src, 0xFFF...FF
560 // with
561 // CONSTANT 0xFFF...FF
562 instruction->ReplaceWith(input_cst);
563 instruction->GetBlock()->RemoveInstruction(instruction);
564 }
565}
566
567void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100568 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000569
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100570 if (!DataType::IsIntegralType(type)) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000571 return;
572 }
573
574 HBasicBlock* block = instruction->GetBlock();
575
576 if (instruction->GetLeft()->IsConstant() &&
Vladimir Markocde64972023-04-25 16:40:06 +0000577 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000578 // Replace code looking like
579 // REM dst, 0, src
580 // with
581 // CONSTANT 0
582 instruction->ReplaceWith(instruction->GetLeft());
583 block->RemoveInstruction(instruction);
584 }
585
Vladimir Marko79dc2172023-04-05 10:33:07 +0000586 HConstant* cst_right = instruction->GetRight()->AsConstantOrNull();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000587 if (((cst_right != nullptr) &&
588 (cst_right->IsOne() || cst_right->IsMinusOne())) ||
589 (instruction->GetLeft() == instruction->GetRight())) {
590 // Replace code looking like
591 // REM dst, src, 1
592 // or
593 // REM dst, src, -1
594 // or
595 // REM dst, src, src
596 // with
597 // CONSTANT 0
David Brazdil8d5b8b22015-03-24 10:51:52 +0000598 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
599 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000600 }
601}
602
603void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) {
604 VisitShift(instruction);
605}
606
607void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) {
608 VisitShift(instruction);
609}
610
611void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100612 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000613
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100614 if (!DataType::IsIntegralType(type)) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000615 return;
616 }
617
618 HBasicBlock* block = instruction->GetBlock();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000619
620 // We assume that GVN has run before, so we only perform a pointer
621 // comparison. If for some reason the values are equal but the pointers are
Kenny Root00d597a2015-09-30 13:09:51 -0700622 // different, we are still correct and only miss an optimization
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000623 // opportunity.
624 if (instruction->GetLeft() == instruction->GetRight()) {
625 // Replace code looking like
626 // SUB dst, src, src
627 // with
628 // CONSTANT 0
Kenny Root00d597a2015-09-30 13:09:51 -0700629 // Note that we cannot optimize `x - x` to `0` for floating-point. It does
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000630 // not work when `x` is an infinity.
David Brazdil8d5b8b22015-03-24 10:51:52 +0000631 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
632 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000633 }
634}
635
636void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) {
637 VisitShift(instruction);
638}
639
640void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) {
641 if (instruction->GetLeft() == instruction->GetRight()) {
642 // Replace code looking like
643 // XOR dst, src, src
644 // with
645 // CONSTANT 0
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100646 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000647 HBasicBlock* block = instruction->GetBlock();
David Brazdil8d5b8b22015-03-24 10:51:52 +0000648 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
649 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000650 }
651}
652
Roland Levillain556c3d12014-09-18 15:25:07 +0100653} // namespace art