blob: 5f39a49d68a1bd4f40871adabd5a405c76efc235 [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
Roland Levillain75be2832014-10-17 17:02:00 +010071void 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();
78}
79
80
81void HConstantFoldingVisitor::VisitBasicBlock(HBasicBlock* block) {
82 // Traverse this block's instructions (phis don't need to be
83 // processed) in (forward) order and replace the ones that can be
84 // statically evaluated by a compile-time counterpart.
85 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
86 it.Current()->Accept(this);
Roland Levillain556c3d12014-09-18 15:25:07 +010087 }
88}
89
Roland Levillain1252e972015-08-06 15:46:02 +010090void HConstantFoldingVisitor::VisitUnaryOperation(HUnaryOperation* inst) {
91 // Constant folding: replace `op(a)' with a constant at compile
92 // time if `a' is a constant.
93 HConstant* constant = inst->TryStaticEvaluation();
94 if (constant != nullptr) {
95 inst->ReplaceWith(constant);
96 inst->GetBlock()->RemoveInstruction(inst);
97 }
98}
99
100void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
101 // Constant folding: replace `op(a, b)' with a constant at
102 // compile time if `a' and `b' are both constants.
103 HConstant* constant = inst->TryStaticEvaluation();
104 if (constant != nullptr) {
105 inst->ReplaceWith(constant);
106 inst->GetBlock()->RemoveInstruction(inst);
107 } else {
108 InstructionWithAbsorbingInputSimplifier simplifier(GetGraph());
109 inst->Accept(&simplifier);
110 }
111}
112
113void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) {
114 // Constant folding: replace `TypeConversion(a)' with a constant at
115 // compile time if `a' is a constant.
116 HConstant* constant = inst->AsTypeConversion()->TryStaticEvaluation();
117 if (constant != nullptr) {
118 inst->ReplaceWith(constant);
119 inst->GetBlock()->RemoveInstruction(inst);
120 }
121}
122
123void HConstantFoldingVisitor::VisitDivZeroCheck(HDivZeroCheck* inst) {
124 // We can safely remove the check if the input is a non-null constant.
125 HInstruction* check_input = inst->InputAt(0);
Roland Levillain1a653882016-03-18 18:05:57 +0000126 if (check_input->IsConstant() && !check_input->AsConstant()->IsArithmeticZero()) {
Roland Levillain1252e972015-08-06 15:46:02 +0100127 inst->ReplaceWith(check_input);
128 inst->GetBlock()->RemoveInstruction(inst);
129 }
130}
131
132
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000133void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) {
134 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
135 HInstruction* left = instruction->GetLeft();
Roland Levillain1a653882016-03-18 18:05:57 +0000136 if (left->IsConstant() && left->AsConstant()->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000137 // Replace code looking like
138 // SHL dst, 0, shift_amount
139 // with
140 // CONSTANT 0
141 instruction->ReplaceWith(left);
142 instruction->GetBlock()->RemoveInstruction(instruction);
143 }
144}
145
Vladimir Markoa341f352016-08-31 12:18:20 +0100146void InstructionWithAbsorbingInputSimplifier::VisitEqual(HEqual* instruction) {
147 if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
148 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
149 // Replace code looking like
150 // EQUAL lhs, null
151 // where lhs cannot be null with
152 // CONSTANT false
153 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 0));
154 instruction->GetBlock()->RemoveInstruction(instruction);
155 }
156}
157
158void InstructionWithAbsorbingInputSimplifier::VisitNotEqual(HNotEqual* instruction) {
159 if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
160 (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
161 // Replace code looking like
162 // NOT_EQUAL lhs, null
163 // where lhs cannot be null with
164 // CONSTANT true
165 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 1));
166 instruction->GetBlock()->RemoveInstruction(instruction);
167 }
168}
169
Aart Bik96709f12015-10-28 17:49:07 -0700170void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
171 if (instruction->GetLeft()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000172 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700173 // Replace code looking like
174 // ABOVE dst, 0, src // unsigned 0 > src is always false
175 // with
176 // CONSTANT false
177 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 0));
178 instruction->GetBlock()->RemoveInstruction(instruction);
179 }
180}
181
182void InstructionWithAbsorbingInputSimplifier::VisitAboveOrEqual(HAboveOrEqual* instruction) {
183 if (instruction->GetRight()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000184 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700185 // Replace code looking like
186 // ABOVE_OR_EQUAL dst, src, 0 // unsigned src >= 0 is always true
187 // with
188 // CONSTANT true
189 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 1));
190 instruction->GetBlock()->RemoveInstruction(instruction);
191 }
192}
193
194void InstructionWithAbsorbingInputSimplifier::VisitBelow(HBelow* instruction) {
195 if (instruction->GetRight()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000196 instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700197 // Replace code looking like
198 // BELOW dst, src, 0 // unsigned src < 0 is always false
199 // with
200 // CONSTANT false
201 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 0));
202 instruction->GetBlock()->RemoveInstruction(instruction);
203 }
204}
205
206void InstructionWithAbsorbingInputSimplifier::VisitBelowOrEqual(HBelowOrEqual* instruction) {
207 if (instruction->GetLeft()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000208 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Aart Bik96709f12015-10-28 17:49:07 -0700209 // Replace code looking like
210 // BELOW_OR_EQUAL dst, 0, src // unsigned 0 <= src is always true
211 // with
212 // CONSTANT true
213 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 1));
214 instruction->GetBlock()->RemoveInstruction(instruction);
215 }
216}
217
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000218void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
219 HConstant* input_cst = instruction->GetConstantRight();
Roland Levillain1a653882016-03-18 18:05:57 +0000220 if ((input_cst != nullptr) && input_cst->IsZeroBitPattern()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000221 // Replace code looking like
222 // AND dst, src, 0
223 // with
224 // CONSTANT 0
225 instruction->ReplaceWith(input_cst);
226 instruction->GetBlock()->RemoveInstruction(instruction);
227 }
228}
229
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100230void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
231 HConstant* input_cst = instruction->GetConstantRight();
232 if (input_cst != nullptr) {
233 HInstruction* input_value = instruction->GetLeastConstantLeft();
234 if (Primitive::IsFloatingPointType(input_value->GetType()) &&
235 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
236 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
237 // Replace code looking like
Roland Levillain31dd3d62016-02-16 12:21:02 +0000238 // CMP{G,L}-{FLOAT,DOUBLE} dst, src, NaN
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100239 // with
240 // CONSTANT +1 (gt bias)
241 // or
242 // CONSTANT -1 (lt bias)
243 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimInt,
244 (instruction->IsGtBias() ? 1 : -1)));
245 instruction->GetBlock()->RemoveInstruction(instruction);
246 }
247 }
248}
249
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000250void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
251 HConstant* input_cst = instruction->GetConstantRight();
252 Primitive::Type type = instruction->GetType();
253 if (Primitive::IsIntOrLongType(type) &&
Roland Levillain1a653882016-03-18 18:05:57 +0000254 (input_cst != nullptr) && input_cst->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000255 // Replace code looking like
256 // MUL dst, src, 0
257 // with
258 // CONSTANT 0
259 // Integral multiplication by zero always yields zero, but floating-point
260 // multiplication by zero does not always do. For example `Infinity * 0.0`
261 // should yield a NaN.
262 instruction->ReplaceWith(input_cst);
263 instruction->GetBlock()->RemoveInstruction(instruction);
264 }
265}
266
267void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
268 HConstant* input_cst = instruction->GetConstantRight();
269
270 if (input_cst == nullptr) {
271 return;
272 }
273
274 if (Int64FromConstant(input_cst) == -1) {
275 // Replace code looking like
276 // OR dst, src, 0xFFF...FF
277 // with
278 // CONSTANT 0xFFF...FF
279 instruction->ReplaceWith(input_cst);
280 instruction->GetBlock()->RemoveInstruction(instruction);
281 }
282}
283
284void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
285 Primitive::Type type = instruction->GetType();
286
287 if (!Primitive::IsIntegralType(type)) {
288 return;
289 }
290
291 HBasicBlock* block = instruction->GetBlock();
292
293 if (instruction->GetLeft()->IsConstant() &&
Roland Levillain1a653882016-03-18 18:05:57 +0000294 instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000295 // Replace code looking like
296 // REM dst, 0, src
297 // with
298 // CONSTANT 0
299 instruction->ReplaceWith(instruction->GetLeft());
300 block->RemoveInstruction(instruction);
301 }
302
303 HConstant* cst_right = instruction->GetRight()->AsConstant();
304 if (((cst_right != nullptr) &&
305 (cst_right->IsOne() || cst_right->IsMinusOne())) ||
306 (instruction->GetLeft() == instruction->GetRight())) {
307 // Replace code looking like
308 // REM dst, src, 1
309 // or
310 // REM dst, src, -1
311 // or
312 // REM dst, src, src
313 // with
314 // CONSTANT 0
David Brazdil8d5b8b22015-03-24 10:51:52 +0000315 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
316 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000317 }
318}
319
320void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) {
321 VisitShift(instruction);
322}
323
324void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) {
325 VisitShift(instruction);
326}
327
328void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
329 Primitive::Type type = instruction->GetType();
330
331 if (!Primitive::IsIntegralType(type)) {
332 return;
333 }
334
335 HBasicBlock* block = instruction->GetBlock();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000336
337 // We assume that GVN has run before, so we only perform a pointer
338 // comparison. If for some reason the values are equal but the pointers are
Kenny Root00d597a2015-09-30 13:09:51 -0700339 // different, we are still correct and only miss an optimization
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000340 // opportunity.
341 if (instruction->GetLeft() == instruction->GetRight()) {
342 // Replace code looking like
343 // SUB dst, src, src
344 // with
345 // CONSTANT 0
Kenny Root00d597a2015-09-30 13:09:51 -0700346 // Note that we cannot optimize `x - x` to `0` for floating-point. It does
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000347 // not work when `x` is an infinity.
David Brazdil8d5b8b22015-03-24 10:51:52 +0000348 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
349 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000350 }
351}
352
353void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) {
354 VisitShift(instruction);
355}
356
357void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) {
358 if (instruction->GetLeft() == instruction->GetRight()) {
359 // Replace code looking like
360 // XOR dst, src, src
361 // with
362 // CONSTANT 0
363 Primitive::Type type = instruction->GetType();
364 HBasicBlock* block = instruction->GetBlock();
David Brazdil8d5b8b22015-03-24 10:51:52 +0000365 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
366 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000367 }
368}
369
Roland Levillain556c3d12014-09-18 15:25:07 +0100370} // namespace art