blob: 57452cc0767c774aa75a3e2c57e984cfde1ea74b [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
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000021// This visitor tries to simplify operations that yield a constant. For example
22// `input * 0` is replaced by a null constant.
23class InstructionWithAbsorbingInputSimplifier : public HGraphVisitor {
24 public:
25 explicit InstructionWithAbsorbingInputSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
26
27 private:
28 void VisitShift(HBinaryOperation* shift);
29
Aart Bik96709f12015-10-28 17:49:07 -070030 void VisitAbove(HAbove* instruction) OVERRIDE;
31 void VisitAboveOrEqual(HAboveOrEqual* instruction) OVERRIDE;
32 void VisitBelow(HBelow* instruction) OVERRIDE;
33 void VisitBelowOrEqual(HBelowOrEqual* instruction) OVERRIDE;
34
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000035 void VisitAnd(HAnd* instruction) OVERRIDE;
Roland Levillain3b55ebb2015-05-08 13:13:19 +010036 void VisitCompare(HCompare* instruction) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000037 void VisitMul(HMul* instruction) OVERRIDE;
38 void VisitOr(HOr* instruction) OVERRIDE;
39 void VisitRem(HRem* instruction) OVERRIDE;
40 void VisitShl(HShl* instruction) OVERRIDE;
41 void VisitShr(HShr* instruction) OVERRIDE;
42 void VisitSub(HSub* instruction) OVERRIDE;
43 void VisitUShr(HUShr* instruction) OVERRIDE;
44 void VisitXor(HXor* instruction) OVERRIDE;
45};
46
Roland Levillain75be2832014-10-17 17:02:00 +010047void HConstantFolding::Run() {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000048 InstructionWithAbsorbingInputSimplifier simplifier(graph_);
Roland Levillain556c3d12014-09-18 15:25:07 +010049 // Process basic blocks in reverse post-order in the dominator tree,
50 // so that an instruction turned into a constant, used as input of
51 // another instruction, may possibly be used to turn that second
52 // instruction into a constant as well.
53 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
54 HBasicBlock* block = it.Current();
55 // Traverse this block's instructions in (forward) order and
56 // replace the ones that can be statically evaluated by a
57 // compile-time counterpart.
Andreas Gampe277ccbd2014-11-03 21:36:10 -080058 for (HInstructionIterator inst_it(block->GetInstructions());
59 !inst_it.Done(); inst_it.Advance()) {
60 HInstruction* inst = inst_it.Current();
Roland Levillain556c3d12014-09-18 15:25:07 +010061 if (inst->IsBinaryOperation()) {
Roland Levillain9240d6a2014-10-20 16:47:04 +010062 // Constant folding: replace `op(a, b)' with a constant at
63 // compile time if `a' and `b' are both constants.
David Brazdil8d5b8b22015-03-24 10:51:52 +000064 HConstant* constant = inst->AsBinaryOperation()->TryStaticEvaluation();
Roland Levillain9240d6a2014-10-20 16:47:04 +010065 if (constant != nullptr) {
David Brazdil8d5b8b22015-03-24 10:51:52 +000066 inst->ReplaceWith(constant);
67 inst->GetBlock()->RemoveInstruction(inst);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000068 } else {
69 inst->Accept(&simplifier);
Roland Levillain9240d6a2014-10-20 16:47:04 +010070 }
71 } else if (inst->IsUnaryOperation()) {
72 // Constant folding: replace `op(a)' with a constant at compile
73 // time if `a' is a constant.
David Brazdil8d5b8b22015-03-24 10:51:52 +000074 HConstant* constant = inst->AsUnaryOperation()->TryStaticEvaluation();
Roland Levillain556c3d12014-09-18 15:25:07 +010075 if (constant != nullptr) {
David Brazdil8d5b8b22015-03-24 10:51:52 +000076 inst->ReplaceWith(constant);
77 inst->GetBlock()->RemoveInstruction(inst);
Roland Levillain556c3d12014-09-18 15:25:07 +010078 }
Mark Mendelle82549b2015-05-06 10:55:34 -040079 } else if (inst->IsTypeConversion()) {
80 // Constant folding: replace `TypeConversion(a)' with a constant at
81 // compile time if `a' is a constant.
82 HConstant* constant = inst->AsTypeConversion()->TryStaticEvaluation();
83 if (constant != nullptr) {
84 inst->ReplaceWith(constant);
85 inst->GetBlock()->RemoveInstruction(inst);
86 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000087 } else if (inst->IsDivZeroCheck()) {
88 // We can safely remove the check if the input is a non-null constant.
89 HDivZeroCheck* check = inst->AsDivZeroCheck();
90 HInstruction* check_input = check->InputAt(0);
91 if (check_input->IsConstant() && !check_input->AsConstant()->IsZero()) {
92 check->ReplaceWith(check_input);
93 check->GetBlock()->RemoveInstruction(check);
94 }
Roland Levillain556c3d12014-09-18 15:25:07 +010095 }
96 }
97 }
98}
99
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000100void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) {
101 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
102 HInstruction* left = instruction->GetLeft();
103 if (left->IsConstant() && left->AsConstant()->IsZero()) {
104 // Replace code looking like
105 // SHL dst, 0, shift_amount
106 // with
107 // CONSTANT 0
108 instruction->ReplaceWith(left);
109 instruction->GetBlock()->RemoveInstruction(instruction);
110 }
111}
112
Aart Bik96709f12015-10-28 17:49:07 -0700113void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
114 if (instruction->GetLeft()->IsConstant() &&
115 instruction->GetLeft()->AsConstant()->IsZero()) {
116 // Replace code looking like
117 // ABOVE dst, 0, src // unsigned 0 > src is always false
118 // with
119 // CONSTANT false
120 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 0));
121 instruction->GetBlock()->RemoveInstruction(instruction);
122 }
123}
124
125void InstructionWithAbsorbingInputSimplifier::VisitAboveOrEqual(HAboveOrEqual* instruction) {
126 if (instruction->GetRight()->IsConstant() &&
127 instruction->GetRight()->AsConstant()->IsZero()) {
128 // Replace code looking like
129 // ABOVE_OR_EQUAL dst, src, 0 // unsigned src >= 0 is always true
130 // with
131 // CONSTANT true
132 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 1));
133 instruction->GetBlock()->RemoveInstruction(instruction);
134 }
135}
136
137void InstructionWithAbsorbingInputSimplifier::VisitBelow(HBelow* instruction) {
138 if (instruction->GetRight()->IsConstant() &&
139 instruction->GetRight()->AsConstant()->IsZero()) {
140 // Replace code looking like
141 // BELOW dst, src, 0 // unsigned src < 0 is always false
142 // with
143 // CONSTANT false
144 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 0));
145 instruction->GetBlock()->RemoveInstruction(instruction);
146 }
147}
148
149void InstructionWithAbsorbingInputSimplifier::VisitBelowOrEqual(HBelowOrEqual* instruction) {
150 if (instruction->GetLeft()->IsConstant() &&
151 instruction->GetLeft()->AsConstant()->IsZero()) {
152 // Replace code looking like
153 // BELOW_OR_EQUAL dst, 0, src // unsigned 0 <= src is always true
154 // with
155 // CONSTANT true
156 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 1));
157 instruction->GetBlock()->RemoveInstruction(instruction);
158 }
159}
160
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000161void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
162 HConstant* input_cst = instruction->GetConstantRight();
163 if ((input_cst != nullptr) && input_cst->IsZero()) {
164 // Replace code looking like
165 // AND dst, src, 0
166 // with
167 // CONSTANT 0
168 instruction->ReplaceWith(input_cst);
169 instruction->GetBlock()->RemoveInstruction(instruction);
170 }
171}
172
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100173void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
174 HConstant* input_cst = instruction->GetConstantRight();
175 if (input_cst != nullptr) {
176 HInstruction* input_value = instruction->GetLeastConstantLeft();
177 if (Primitive::IsFloatingPointType(input_value->GetType()) &&
178 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
179 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
180 // Replace code looking like
181 // CMP{G,L} dst, src, NaN
182 // with
183 // CONSTANT +1 (gt bias)
184 // or
185 // CONSTANT -1 (lt bias)
186 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimInt,
187 (instruction->IsGtBias() ? 1 : -1)));
188 instruction->GetBlock()->RemoveInstruction(instruction);
189 }
190 }
191}
192
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000193void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
194 HConstant* input_cst = instruction->GetConstantRight();
195 Primitive::Type type = instruction->GetType();
196 if (Primitive::IsIntOrLongType(type) &&
197 (input_cst != nullptr) && input_cst->IsZero()) {
198 // Replace code looking like
199 // MUL dst, src, 0
200 // with
201 // CONSTANT 0
202 // Integral multiplication by zero always yields zero, but floating-point
203 // multiplication by zero does not always do. For example `Infinity * 0.0`
204 // should yield a NaN.
205 instruction->ReplaceWith(input_cst);
206 instruction->GetBlock()->RemoveInstruction(instruction);
207 }
208}
209
210void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
211 HConstant* input_cst = instruction->GetConstantRight();
212
213 if (input_cst == nullptr) {
214 return;
215 }
216
217 if (Int64FromConstant(input_cst) == -1) {
218 // Replace code looking like
219 // OR dst, src, 0xFFF...FF
220 // with
221 // CONSTANT 0xFFF...FF
222 instruction->ReplaceWith(input_cst);
223 instruction->GetBlock()->RemoveInstruction(instruction);
224 }
225}
226
227void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
228 Primitive::Type type = instruction->GetType();
229
230 if (!Primitive::IsIntegralType(type)) {
231 return;
232 }
233
234 HBasicBlock* block = instruction->GetBlock();
235
236 if (instruction->GetLeft()->IsConstant() &&
237 instruction->GetLeft()->AsConstant()->IsZero()) {
238 // Replace code looking like
239 // REM dst, 0, src
240 // with
241 // CONSTANT 0
242 instruction->ReplaceWith(instruction->GetLeft());
243 block->RemoveInstruction(instruction);
244 }
245
246 HConstant* cst_right = instruction->GetRight()->AsConstant();
247 if (((cst_right != nullptr) &&
248 (cst_right->IsOne() || cst_right->IsMinusOne())) ||
249 (instruction->GetLeft() == instruction->GetRight())) {
250 // Replace code looking like
251 // REM dst, src, 1
252 // or
253 // REM dst, src, -1
254 // or
255 // REM dst, src, src
256 // with
257 // CONSTANT 0
David Brazdil8d5b8b22015-03-24 10:51:52 +0000258 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
259 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000260 }
261}
262
263void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) {
264 VisitShift(instruction);
265}
266
267void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) {
268 VisitShift(instruction);
269}
270
271void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
272 Primitive::Type type = instruction->GetType();
273
274 if (!Primitive::IsIntegralType(type)) {
275 return;
276 }
277
278 HBasicBlock* block = instruction->GetBlock();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000279
280 // We assume that GVN has run before, so we only perform a pointer
281 // comparison. If for some reason the values are equal but the pointers are
Kenny Root00d597a2015-09-30 13:09:51 -0700282 // different, we are still correct and only miss an optimization
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000283 // opportunity.
284 if (instruction->GetLeft() == instruction->GetRight()) {
285 // Replace code looking like
286 // SUB dst, src, src
287 // with
288 // CONSTANT 0
Kenny Root00d597a2015-09-30 13:09:51 -0700289 // Note that we cannot optimize `x - x` to `0` for floating-point. It does
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000290 // not work when `x` is an infinity.
David Brazdil8d5b8b22015-03-24 10:51:52 +0000291 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
292 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000293 }
294}
295
296void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) {
297 VisitShift(instruction);
298}
299
300void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) {
301 if (instruction->GetLeft() == instruction->GetRight()) {
302 // Replace code looking like
303 // XOR dst, src, src
304 // with
305 // CONSTANT 0
306 Primitive::Type type = instruction->GetType();
307 HBasicBlock* block = instruction->GetBlock();
David Brazdil8d5b8b22015-03-24 10:51:52 +0000308 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
309 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000310 }
311}
312
Roland Levillain556c3d12014-09-18 15:25:07 +0100313} // namespace art