blob: e0aa4ff48913288eb20a86e603d3e8a75d8856f6 [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
30 void VisitAnd(HAnd* instruction) OVERRIDE;
Roland Levillain3b55ebb2015-05-08 13:13:19 +010031 void VisitCompare(HCompare* instruction) OVERRIDE;
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000032 void VisitMul(HMul* instruction) OVERRIDE;
33 void VisitOr(HOr* instruction) OVERRIDE;
34 void VisitRem(HRem* instruction) OVERRIDE;
35 void VisitShl(HShl* instruction) OVERRIDE;
36 void VisitShr(HShr* instruction) OVERRIDE;
37 void VisitSub(HSub* instruction) OVERRIDE;
38 void VisitUShr(HUShr* instruction) OVERRIDE;
39 void VisitXor(HXor* instruction) OVERRIDE;
40};
41
Roland Levillain75be2832014-10-17 17:02:00 +010042void HConstantFolding::Run() {
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000043 InstructionWithAbsorbingInputSimplifier simplifier(graph_);
Roland Levillain556c3d12014-09-18 15:25:07 +010044 // Process basic blocks in reverse post-order in the dominator tree,
45 // so that an instruction turned into a constant, used as input of
46 // another instruction, may possibly be used to turn that second
47 // instruction into a constant as well.
48 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
49 HBasicBlock* block = it.Current();
50 // Traverse this block's instructions in (forward) order and
51 // replace the ones that can be statically evaluated by a
52 // compile-time counterpart.
Andreas Gampe277ccbd2014-11-03 21:36:10 -080053 for (HInstructionIterator inst_it(block->GetInstructions());
54 !inst_it.Done(); inst_it.Advance()) {
55 HInstruction* inst = inst_it.Current();
Roland Levillain556c3d12014-09-18 15:25:07 +010056 if (inst->IsBinaryOperation()) {
Roland Levillain9240d6a2014-10-20 16:47:04 +010057 // Constant folding: replace `op(a, b)' with a constant at
58 // compile time if `a' and `b' are both constants.
David Brazdil8d5b8b22015-03-24 10:51:52 +000059 HConstant* constant = inst->AsBinaryOperation()->TryStaticEvaluation();
Roland Levillain9240d6a2014-10-20 16:47:04 +010060 if (constant != nullptr) {
David Brazdil8d5b8b22015-03-24 10:51:52 +000061 inst->ReplaceWith(constant);
62 inst->GetBlock()->RemoveInstruction(inst);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000063 } else {
64 inst->Accept(&simplifier);
Roland Levillain9240d6a2014-10-20 16:47:04 +010065 }
66 } else if (inst->IsUnaryOperation()) {
67 // Constant folding: replace `op(a)' with a constant at compile
68 // time if `a' is a constant.
David Brazdil8d5b8b22015-03-24 10:51:52 +000069 HConstant* constant = inst->AsUnaryOperation()->TryStaticEvaluation();
Roland Levillain556c3d12014-09-18 15:25:07 +010070 if (constant != nullptr) {
David Brazdil8d5b8b22015-03-24 10:51:52 +000071 inst->ReplaceWith(constant);
72 inst->GetBlock()->RemoveInstruction(inst);
Roland Levillain556c3d12014-09-18 15:25:07 +010073 }
Mark Mendelle82549b2015-05-06 10:55:34 -040074 } else if (inst->IsTypeConversion()) {
75 // Constant folding: replace `TypeConversion(a)' with a constant at
76 // compile time if `a' is a constant.
77 HConstant* constant = inst->AsTypeConversion()->TryStaticEvaluation();
78 if (constant != nullptr) {
79 inst->ReplaceWith(constant);
80 inst->GetBlock()->RemoveInstruction(inst);
81 }
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000082 } else if (inst->IsDivZeroCheck()) {
83 // We can safely remove the check if the input is a non-null constant.
84 HDivZeroCheck* check = inst->AsDivZeroCheck();
85 HInstruction* check_input = check->InputAt(0);
86 if (check_input->IsConstant() && !check_input->AsConstant()->IsZero()) {
87 check->ReplaceWith(check_input);
88 check->GetBlock()->RemoveInstruction(check);
89 }
Roland Levillain556c3d12014-09-18 15:25:07 +010090 }
91 }
92 }
93}
94
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +000095void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) {
96 DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
97 HInstruction* left = instruction->GetLeft();
98 if (left->IsConstant() && left->AsConstant()->IsZero()) {
99 // Replace code looking like
100 // SHL dst, 0, shift_amount
101 // with
102 // CONSTANT 0
103 instruction->ReplaceWith(left);
104 instruction->GetBlock()->RemoveInstruction(instruction);
105 }
106}
107
108void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
109 HConstant* input_cst = instruction->GetConstantRight();
110 if ((input_cst != nullptr) && input_cst->IsZero()) {
111 // Replace code looking like
112 // AND dst, src, 0
113 // with
114 // CONSTANT 0
115 instruction->ReplaceWith(input_cst);
116 instruction->GetBlock()->RemoveInstruction(instruction);
117 }
118}
119
Roland Levillain3b55ebb2015-05-08 13:13:19 +0100120void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
121 HConstant* input_cst = instruction->GetConstantRight();
122 if (input_cst != nullptr) {
123 HInstruction* input_value = instruction->GetLeastConstantLeft();
124 if (Primitive::IsFloatingPointType(input_value->GetType()) &&
125 ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
126 (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
127 // Replace code looking like
128 // CMP{G,L} dst, src, NaN
129 // with
130 // CONSTANT +1 (gt bias)
131 // or
132 // CONSTANT -1 (lt bias)
133 instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimInt,
134 (instruction->IsGtBias() ? 1 : -1)));
135 instruction->GetBlock()->RemoveInstruction(instruction);
136 }
137 }
138}
139
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000140void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
141 HConstant* input_cst = instruction->GetConstantRight();
142 Primitive::Type type = instruction->GetType();
143 if (Primitive::IsIntOrLongType(type) &&
144 (input_cst != nullptr) && input_cst->IsZero()) {
145 // Replace code looking like
146 // MUL dst, src, 0
147 // with
148 // CONSTANT 0
149 // Integral multiplication by zero always yields zero, but floating-point
150 // multiplication by zero does not always do. For example `Infinity * 0.0`
151 // should yield a NaN.
152 instruction->ReplaceWith(input_cst);
153 instruction->GetBlock()->RemoveInstruction(instruction);
154 }
155}
156
157void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) {
158 HConstant* input_cst = instruction->GetConstantRight();
159
160 if (input_cst == nullptr) {
161 return;
162 }
163
164 if (Int64FromConstant(input_cst) == -1) {
165 // Replace code looking like
166 // OR dst, src, 0xFFF...FF
167 // with
168 // CONSTANT 0xFFF...FF
169 instruction->ReplaceWith(input_cst);
170 instruction->GetBlock()->RemoveInstruction(instruction);
171 }
172}
173
174void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) {
175 Primitive::Type type = instruction->GetType();
176
177 if (!Primitive::IsIntegralType(type)) {
178 return;
179 }
180
181 HBasicBlock* block = instruction->GetBlock();
182
183 if (instruction->GetLeft()->IsConstant() &&
184 instruction->GetLeft()->AsConstant()->IsZero()) {
185 // Replace code looking like
186 // REM dst, 0, src
187 // with
188 // CONSTANT 0
189 instruction->ReplaceWith(instruction->GetLeft());
190 block->RemoveInstruction(instruction);
191 }
192
193 HConstant* cst_right = instruction->GetRight()->AsConstant();
194 if (((cst_right != nullptr) &&
195 (cst_right->IsOne() || cst_right->IsMinusOne())) ||
196 (instruction->GetLeft() == instruction->GetRight())) {
197 // Replace code looking like
198 // REM dst, src, 1
199 // or
200 // REM dst, src, -1
201 // or
202 // REM dst, src, src
203 // with
204 // CONSTANT 0
David Brazdil8d5b8b22015-03-24 10:51:52 +0000205 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
206 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000207 }
208}
209
210void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) {
211 VisitShift(instruction);
212}
213
214void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) {
215 VisitShift(instruction);
216}
217
218void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) {
219 Primitive::Type type = instruction->GetType();
220
221 if (!Primitive::IsIntegralType(type)) {
222 return;
223 }
224
225 HBasicBlock* block = instruction->GetBlock();
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000226
227 // We assume that GVN has run before, so we only perform a pointer
228 // comparison. If for some reason the values are equal but the pointers are
Kenny Root00d597a2015-09-30 13:09:51 -0700229 // different, we are still correct and only miss an optimization
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000230 // opportunity.
231 if (instruction->GetLeft() == instruction->GetRight()) {
232 // Replace code looking like
233 // SUB dst, src, src
234 // with
235 // CONSTANT 0
Kenny Root00d597a2015-09-30 13:09:51 -0700236 // Note that we cannot optimize `x - x` to `0` for floating-point. It does
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000237 // not work when `x` is an infinity.
David Brazdil8d5b8b22015-03-24 10:51:52 +0000238 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
239 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000240 }
241}
242
243void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) {
244 VisitShift(instruction);
245}
246
247void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) {
248 if (instruction->GetLeft() == instruction->GetRight()) {
249 // Replace code looking like
250 // XOR dst, src, src
251 // with
252 // CONSTANT 0
253 Primitive::Type type = instruction->GetType();
254 HBasicBlock* block = instruction->GetBlock();
David Brazdil8d5b8b22015-03-24 10:51:52 +0000255 instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
256 block->RemoveInstruction(instruction);
Alexandre Ramesb2fd7bc2015-03-11 16:48:16 +0000257 }
258}
259
Roland Levillain556c3d12014-09-18 15:25:07 +0100260} // namespace art