blob: bb78c2357ee3bf5a518ab0b2e9472d6bf26d19c7 [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
19namespace art {
20
Roland Levillain1252e972015-08-06 15:46:02 +010021// This visitor tries to simplify instructions that can be evaluated
22// as constants.
23class HConstantFoldingVisitor : public HGraphDelegateVisitor {
24 public:
25 explicit HConstantFoldingVisitor(HGraph* graph)
26 : HGraphDelegateVisitor(graph) {}
27
28 private:
29 void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
30
31 void VisitUnaryOperation(HUnaryOperation* inst) OVERRIDE;
32 void VisitBinaryOperation(HBinaryOperation* inst) OVERRIDE;
33
34 void VisitTypeConversion(HTypeConversion* inst) OVERRIDE;
35 void VisitDivZeroCheck(HDivZeroCheck* inst) OVERRIDE;
36
37 DISALLOW_COPY_AND_ASSIGN(HConstantFoldingVisitor);
38};
39
40// This visitor tries to simplify operations with an absorbing input,
41// yielding a constant. For example `input * 0` is replaced by a
42// null constant.
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000043class InstructionWithAbsorbingInputSimplifier : public HGraphVisitor {
44 public:
45 explicit InstructionWithAbsorbingInputSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
46
47 private:
48 void VisitShift(HBinaryOperation* shift);
49
Vladimir Markoa341f352016-08-31 12:18:20 +010050 void VisitEqual(HEqual* instruction) OVERRIDE;
51 void VisitNotEqual(HNotEqual* instruction) OVERRIDE;
52
Aart Bik96709f12015-10-28 17:49:07 -070053 void VisitAbove(HAbove* instruction) OVERRIDE;
54 void VisitAboveOrEqual(HAboveOrEqual* instruction) OVERRIDE;
55 void VisitBelow(HBelow* instruction) OVERRIDE;
56 void VisitBelowOrEqual(HBelowOrEqual* instruction) OVERRIDE;
57
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000058 void VisitAnd(HAnd* instruction) OVERRIDE;
Roland Levillain3b55ebb2015-05-08 13:13:19 +010059 void VisitCompare(HCompare* instruction) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000060 void VisitMul(HMul* instruction) OVERRIDE;
61 void VisitOr(HOr* instruction) OVERRIDE;
62 void VisitRem(HRem* instruction) OVERRIDE;
63 void VisitShl(HShl* instruction) OVERRIDE;
64 void VisitShr(HShr* instruction) OVERRIDE;
65 void VisitSub(HSub* instruction) OVERRIDE;
66 void VisitUShr(HUShr* instruction) OVERRIDE;
67 void VisitXor(HXor* instruction) OVERRIDE;
68};
69
Roland Levillain1252e972015-08-06 15:46:02 +010070
Aart Bik24773202018-04-26 10:28:51 -070071bool HConstantFolding::Run() {
Roland Levillain1252e972015-08-06 15:46:02 +010072 HConstantFoldingVisitor visitor(graph_);
Roland Levillain556c3d12014-09-18 15:25:07 +010073 // Process basic blocks in reverse post-order in the dominator tree,
74 // so that an instruction turned into a constant, used as input of
75 // another instruction, may possibly be used to turn that second
76 // instruction into a constant as well.
Roland Levillain1252e972015-08-06 15:46:02 +010077 visitor.VisitReversePostOrder();
Aart Bik24773202018-04-26 10:28:51 -070078 return true;
Roland Levillain1252e972015-08-06 15:46:02 +010079}
80
81
82void HConstantFoldingVisitor::VisitBasicBlock(HBasicBlock* block) {
83 // Traverse this block's instructions (phis don't need to be
84 // processed) in (forward) order and replace the ones that can be
85 // statically evaluated by a compile-time counterpart.
86 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
87 it.Current()->Accept(this);
Roland Levillain556c3d12014-09-18 15:25:07 +010088 }
89}
90
Roland Levillain1252e972015-08-06 15:46:02 +010091void HConstantFoldingVisitor::VisitUnaryOperation(HUnaryOperation* inst) {
92 // Constant folding: replace `op(a)' with a constant at compile
93 // time if `a' is a constant.
94 HConstant* constant = inst->TryStaticEvaluation();
95 if (constant != nullptr) {
96 inst->ReplaceWith(constant);
97 inst->GetBlock()->RemoveInstruction(inst);
98 }
99}
100
101void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
102 // Constant folding: replace `op(a, b)' with a constant at
103 // compile time if `a' and `b' are both constants.
104 HConstant* constant = inst->TryStaticEvaluation();
105 if (constant != nullptr) {
106 inst->ReplaceWith(constant);
107 inst->GetBlock()->RemoveInstruction(inst);
108 } else {
109 InstructionWithAbsorbingInputSimplifier simplifier(GetGraph());
110 inst->Accept(&simplifier);
111 }
112}
113
114void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) {
115 // Constant folding: replace `TypeConversion(a)' with a constant at
116 // compile time if `a' is a constant.
Mingyao Yang75bb2f32017-11-30 14:45:44 -0800117 HConstant* constant = inst->TryStaticEvaluation();
Roland Levillain1252e972015-08-06 15:46:02 +0100118 if (constant != nullptr) {
119 inst->ReplaceWith(constant);
120 inst->GetBlock()->RemoveInstruction(inst);
121 }
122}
123
124void HConstantFoldingVisitor::VisitDivZeroCheck(HDivZeroCheck* inst) {
125 // We can safely remove the check if the input is a non-null constant.
126 HInstruction* check_input = inst->InputAt(0);
Roland Levillain1a653882016-03-18 18:05:57 +0000127 if (check_input->IsConstant() && !check_input->AsConstant()->IsArithmeticZero()) {
Roland Levillain1252e972015-08-06 15:46:02 +0100128 inst->ReplaceWith(check_input);
129 inst->GetBlock()->RemoveInstruction(inst);
130 }
131}
132
133
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000134void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) {
135 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
136 HInstruction* left = instruction->GetLeft();
Roland Levillain1a653882016-03-18 18:05:57 +0000137 if (left->IsConstant() && left->AsConstant()->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000138 // Replace code looking like
139 // SHL dst, 0, shift_amount
140 // with
141 // CONSTANT 0
142 instruction->ReplaceWith(left);
143 instruction->GetBlock()->RemoveInstruction(instruction);
144 }
145}
146
Vladimir Markoa341f352016-08-31 12:18:20 +0100147void InstructionWithAbsorbingInputSimplifier::VisitEqual(HEqual* instruction) {
148 if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
149 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
150 // Replace code looking like
151 // EQUAL lhs, null
152 // where lhs cannot be null with
153 // CONSTANT false
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100154 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
Vladimir Markoa341f352016-08-31 12:18:20 +0100155 instruction->GetBlock()->RemoveInstruction(instruction);
156 }
157}
158
159void InstructionWithAbsorbingInputSimplifier::VisitNotEqual(HNotEqual* instruction) {
160 if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
161 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
162 // Replace code looking like
163 // NOT_EQUAL lhs, null
164 // where lhs cannot be null with
165 // CONSTANT true
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100166 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
Vladimir Markoa341f352016-08-31 12:18:20 +0100167 instruction->GetBlock()->RemoveInstruction(instruction);
168 }
169}
170
Aart Bik96709f12015-10-28 17:49:07 -0700171void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
172 if (instruction->GetLeft()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000173 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700174 // Replace code looking like
175 // ABOVE dst, 0, src // unsigned 0 > src is always false
176 // with
177 // CONSTANT false
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100178 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700179 instruction->GetBlock()->RemoveInstruction(instruction);
180 }
181}
182
183void InstructionWithAbsorbingInputSimplifier::VisitAboveOrEqual(HAboveOrEqual* instruction) {
184 if (instruction->GetRight()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000185 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700186 // Replace code looking like
187 // ABOVE_OR_EQUAL dst, src, 0 // unsigned src >= 0 is always true
188 // with
189 // CONSTANT true
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100190 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
Aart Bik96709f12015-10-28 17:49:07 -0700191 instruction->GetBlock()->RemoveInstruction(instruction);
192 }
193}
194
195void InstructionWithAbsorbingInputSimplifier::VisitBelow(HBelow* instruction) {
196 if (instruction->GetRight()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000197 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700198 // Replace code looking like
199 // BELOW dst, src, 0 // unsigned src < 0 is always false
200 // with
201 // CONSTANT false
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100202 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
Aart Bik96709f12015-10-28 17:49:07 -0700203 instruction->GetBlock()->RemoveInstruction(instruction);
204 }
205}
206
207void InstructionWithAbsorbingInputSimplifier::VisitBelowOrEqual(HBelowOrEqual* instruction) {
208 if (instruction->GetLeft()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000209 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700210 // Replace code looking like
211 // BELOW_OR_EQUAL dst, 0, src // unsigned 0 <= src is always true
212 // with
213 // CONSTANT true
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100214 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
Aart Bik96709f12015-10-28 17:49:07 -0700215 instruction->GetBlock()->RemoveInstruction(instruction);
216 }
217}
218
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000219void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
220 HConstant* input_cst = instruction->GetConstantRight();
Roland Levillain1a653882016-03-18 18:05:57 +0000221 if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000222 // Replace code looking like
223 // AND dst, src, 0
224 // with
225 // CONSTANT 0
226 instruction->ReplaceWith(input_cst);
227 instruction->GetBlock()->RemoveInstruction(instruction);
228 }
229}
230
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100231void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
232 HConstant* input_cst = instruction->GetConstantRight();
233 if (input_cst != nullptr) {
234 HInstruction* input_value = instruction->GetLeastConstantLeft();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100235 if (DataType::IsFloatingPointType(input_value->GetType()) &&
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100236 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
237 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
238 // Replace code looking like
Roland Levillain31dd3d62016-02-16 12:21:02 +0000239 // CMP{G,L}-{FLOAT,DOUBLE} dst, src, NaN
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100240 // with
241 // CONSTANT +1 (gt bias)
242 // or
243 // CONSTANT -1 (lt bias)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100244 instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kInt32,
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100245 (instruction->IsGtBias() ? 1 : -1)));
246 instruction->GetBlock()->RemoveInstruction(instruction);
247 }
248 }
249}
250
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000251void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
252 HConstant* input_cst = instruction->GetConstantRight();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100253 DataType::Type type = instruction->GetType();
254 if (DataType::IsIntOrLongType(type) &&
Roland Levillain1a653882016-03-18 18:05:57 +0000255 (input_cst != nullptr) && input_cst->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000256 // Replace code looking like
257 // MUL dst, src, 0
258 // with
259 // CONSTANT 0
260 // Integral multiplication by zero always yields zero, but floating-point
261 // multiplication by zero does not always do. For example `Infinity * 0.0`
262 // should yield a NaN.
263 instruction->ReplaceWith(input_cst);
264 instruction->GetBlock()->RemoveInstruction(instruction);
265 }
266}
267
268void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
269 HConstant* input_cst = instruction->GetConstantRight();
270
271 if (input_cst == nullptr) {
272 return;
273 }
274
275 if (Int64FromConstant(input_cst) == -1) {
276 // Replace code looking like
277 // OR dst, src, 0xFFF...FF
278 // with
279 // CONSTANT 0xFFF...FF
280 instruction->ReplaceWith(input_cst);
281 instruction->GetBlock()->RemoveInstruction(instruction);
282 }
283}
284
285void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100286 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000287
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100288 if (!DataType::IsIntegralType(type)) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000289 return;
290 }
291
292 HBasicBlock* block = instruction->GetBlock();
293
294 if (instruction->GetLeft()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000295 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000296 // Replace code looking like
297 // REM dst, 0, src
298 // with
299 // CONSTANT 0
300 instruction->ReplaceWith(instruction->GetLeft());
301 block->RemoveInstruction(instruction);
302 }
303
304 HConstant* cst_right = instruction->GetRight()->AsConstant();
305 if (((cst_right != nullptr) &&
306 (cst_right->IsOne() || cst_right->IsMinusOne())) ||
307 (instruction->GetLeft() == instruction->GetRight())) {
308 // Replace code looking like
309 // REM dst, src, 1
310 // or
311 // REM dst, src, -1
312 // or
313 // REM dst, src, src
314 // with
315 // CONSTANT 0
David Brazdil8d5b8b22015-03-24 10:51:52 +0000316 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
317 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000318 }
319}
320
321void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) {
322 VisitShift(instruction);
323}
324
325void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) {
326 VisitShift(instruction);
327}
328
329void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100330 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000331
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100332 if (!DataType::IsIntegralType(type)) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000333 return;
334 }
335
336 HBasicBlock* block = instruction->GetBlock();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000337
338 // We assume that GVN has run before, so we only perform a pointer
339 // comparison. If for some reason the values are equal but the pointers are
Kenny Root00d597a2015-09-30 13:09:51 -0700340 // different, we are still correct and only miss an optimization
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000341 // opportunity.
342 if (instruction->GetLeft() == instruction->GetRight()) {
343 // Replace code looking like
344 // SUB dst, src, src
345 // with
346 // CONSTANT 0
Kenny Root00d597a2015-09-30 13:09:51 -0700347 // Note that we cannot optimize `x - x` to `0` for floating-point. It does
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000348 // not work when `x` is an infinity.
David Brazdil8d5b8b22015-03-24 10:51:52 +0000349 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
350 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000351 }
352}
353
354void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) {
355 VisitShift(instruction);
356}
357
358void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) {
359 if (instruction->GetLeft() == instruction->GetRight()) {
360 // Replace code looking like
361 // XOR dst, src, src
362 // with
363 // CONSTANT 0
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100364 DataType::Type type = instruction->GetType();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000365 HBasicBlock* block = instruction->GetBlock();
David Brazdil8d5b8b22015-03-24 10:51:52 +0000366 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
367 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000368 }
369}
370
Roland Levillain556c3d12014-09-18 15:25:07 +0100371} // namespace art