| /* | 
 |  * Copyright (C) 2014 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include "constant_folding.h" | 
 |  | 
 | namespace art { | 
 |  | 
 | // This visitor tries to simplify operations that yield a constant. For example | 
 | // `input * 0` is replaced by a null constant. | 
 | class InstructionWithAbsorbingInputSimplifier : public HGraphVisitor { | 
 |  public: | 
 |   explicit InstructionWithAbsorbingInputSimplifier(HGraph* graph) : HGraphVisitor(graph) {} | 
 |  | 
 |  private: | 
 |   void VisitShift(HBinaryOperation* shift); | 
 |  | 
 |   void VisitAnd(HAnd* instruction) OVERRIDE; | 
 |   void VisitMul(HMul* instruction) OVERRIDE; | 
 |   void VisitOr(HOr* instruction) OVERRIDE; | 
 |   void VisitRem(HRem* instruction) OVERRIDE; | 
 |   void VisitShl(HShl* instruction) OVERRIDE; | 
 |   void VisitShr(HShr* instruction) OVERRIDE; | 
 |   void VisitSub(HSub* instruction) OVERRIDE; | 
 |   void VisitUShr(HUShr* instruction) OVERRIDE; | 
 |   void VisitXor(HXor* instruction) OVERRIDE; | 
 | }; | 
 |  | 
 | void HConstantFolding::Run() { | 
 |   InstructionWithAbsorbingInputSimplifier simplifier(graph_); | 
 |   // Process basic blocks in reverse post-order in the dominator tree, | 
 |   // so that an instruction turned into a constant, used as input of | 
 |   // another instruction, may possibly be used to turn that second | 
 |   // instruction into a constant as well. | 
 |   for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) { | 
 |     HBasicBlock* block = it.Current(); | 
 |     // Traverse this block's instructions in (forward) order and | 
 |     // replace the ones that can be statically evaluated by a | 
 |     // compile-time counterpart. | 
 |     for (HInstructionIterator inst_it(block->GetInstructions()); | 
 |          !inst_it.Done(); inst_it.Advance()) { | 
 |       HInstruction* inst = inst_it.Current(); | 
 |       if (inst->IsBinaryOperation()) { | 
 |         // Constant folding: replace `op(a, b)' with a constant at | 
 |         // compile time if `a' and `b' are both constants. | 
 |         HConstant* constant = inst->AsBinaryOperation()->TryStaticEvaluation(); | 
 |         if (constant != nullptr) { | 
 |           inst->ReplaceWith(constant); | 
 |           inst->GetBlock()->RemoveInstruction(inst); | 
 |         } else { | 
 |           inst->Accept(&simplifier); | 
 |         } | 
 |       } else if (inst->IsUnaryOperation()) { | 
 |         // Constant folding: replace `op(a)' with a constant at compile | 
 |         // time if `a' is a constant. | 
 |         HConstant* constant = inst->AsUnaryOperation()->TryStaticEvaluation(); | 
 |         if (constant != nullptr) { | 
 |           inst->ReplaceWith(constant); | 
 |           inst->GetBlock()->RemoveInstruction(inst); | 
 |         } | 
 |       } else if (inst->IsDivZeroCheck()) { | 
 |         // We can safely remove the check if the input is a non-null constant. | 
 |         HDivZeroCheck* check = inst->AsDivZeroCheck(); | 
 |         HInstruction* check_input = check->InputAt(0); | 
 |         if (check_input->IsConstant() && !check_input->AsConstant()->IsZero()) { | 
 |           check->ReplaceWith(check_input); | 
 |           check->GetBlock()->RemoveInstruction(check); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void InstructionWithAbsorbingInputSimplifier::VisitShift(HBinaryOperation* instruction) { | 
 |   DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr()); | 
 |   HInstruction* left = instruction->GetLeft(); | 
 |   if (left->IsConstant() && left->AsConstant()->IsZero()) { | 
 |     // Replace code looking like | 
 |     //    SHL dst, 0, shift_amount | 
 |     // with | 
 |     //    CONSTANT 0 | 
 |     instruction->ReplaceWith(left); | 
 |     instruction->GetBlock()->RemoveInstruction(instruction); | 
 |   } | 
 | } | 
 |  | 
 | void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) { | 
 |   HConstant* input_cst = instruction->GetConstantRight(); | 
 |   if ((input_cst != nullptr) && input_cst->IsZero()) { | 
 |     // Replace code looking like | 
 |     //    AND dst, src, 0 | 
 |     // with | 
 |     //    CONSTANT 0 | 
 |     instruction->ReplaceWith(input_cst); | 
 |     instruction->GetBlock()->RemoveInstruction(instruction); | 
 |   } | 
 | } | 
 |  | 
 | void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) { | 
 |   HConstant* input_cst = instruction->GetConstantRight(); | 
 |   Primitive::Type type = instruction->GetType(); | 
 |   if (Primitive::IsIntOrLongType(type) && | 
 |       (input_cst != nullptr) && input_cst->IsZero()) { | 
 |     // Replace code looking like | 
 |     //    MUL dst, src, 0 | 
 |     // with | 
 |     //    CONSTANT 0 | 
 |     // Integral multiplication by zero always yields zero, but floating-point | 
 |     // multiplication by zero does not always do. For example `Infinity * 0.0` | 
 |     // should yield a NaN. | 
 |     instruction->ReplaceWith(input_cst); | 
 |     instruction->GetBlock()->RemoveInstruction(instruction); | 
 |   } | 
 | } | 
 |  | 
 | void InstructionWithAbsorbingInputSimplifier::VisitOr(HOr* instruction) { | 
 |   HConstant* input_cst = instruction->GetConstantRight(); | 
 |  | 
 |   if (input_cst == nullptr) { | 
 |     return; | 
 |   } | 
 |  | 
 |   if (Int64FromConstant(input_cst) == -1) { | 
 |     // Replace code looking like | 
 |     //    OR dst, src, 0xFFF...FF | 
 |     // with | 
 |     //    CONSTANT 0xFFF...FF | 
 |     instruction->ReplaceWith(input_cst); | 
 |     instruction->GetBlock()->RemoveInstruction(instruction); | 
 |   } | 
 | } | 
 |  | 
 | void InstructionWithAbsorbingInputSimplifier::VisitRem(HRem* instruction) { | 
 |   Primitive::Type type = instruction->GetType(); | 
 |  | 
 |   if (!Primitive::IsIntegralType(type)) { | 
 |     return; | 
 |   } | 
 |  | 
 |   HBasicBlock* block = instruction->GetBlock(); | 
 |  | 
 |   if (instruction->GetLeft()->IsConstant() && | 
 |       instruction->GetLeft()->AsConstant()->IsZero()) { | 
 |     // Replace code looking like | 
 |     //    REM dst, 0, src | 
 |     // with | 
 |     //    CONSTANT 0 | 
 |     instruction->ReplaceWith(instruction->GetLeft()); | 
 |     block->RemoveInstruction(instruction); | 
 |   } | 
 |  | 
 |   HConstant* cst_right = instruction->GetRight()->AsConstant(); | 
 |   if (((cst_right != nullptr) && | 
 |        (cst_right->IsOne() || cst_right->IsMinusOne())) || | 
 |       (instruction->GetLeft() == instruction->GetRight())) { | 
 |     // Replace code looking like | 
 |     //    REM dst, src, 1 | 
 |     // or | 
 |     //    REM dst, src, -1 | 
 |     // or | 
 |     //    REM dst, src, src | 
 |     // with | 
 |     //    CONSTANT 0 | 
 |     instruction->ReplaceWith(GetGraph()->GetConstant(type, 0)); | 
 |     block->RemoveInstruction(instruction); | 
 |   } | 
 | } | 
 |  | 
 | void InstructionWithAbsorbingInputSimplifier::VisitShl(HShl* instruction) { | 
 |   VisitShift(instruction); | 
 | } | 
 |  | 
 | void InstructionWithAbsorbingInputSimplifier::VisitShr(HShr* instruction) { | 
 |   VisitShift(instruction); | 
 | } | 
 |  | 
 | void InstructionWithAbsorbingInputSimplifier::VisitSub(HSub* instruction) { | 
 |   Primitive::Type type = instruction->GetType(); | 
 |  | 
 |   if (!Primitive::IsIntegralType(type)) { | 
 |     return; | 
 |   } | 
 |  | 
 |   HBasicBlock* block = instruction->GetBlock(); | 
 |  | 
 |   // We assume that GVN has run before, so we only perform a pointer | 
 |   // comparison.  If for some reason the values are equal but the pointers are | 
 |   // different, we are still correct and only miss an optimisation | 
 |   // opportunity. | 
 |   if (instruction->GetLeft() == instruction->GetRight()) { | 
 |     // Replace code looking like | 
 |     //    SUB dst, src, src | 
 |     // with | 
 |     //    CONSTANT 0 | 
 |     // Note that we cannot optimise `x - x` to `0` for floating-point. It does | 
 |     // not work when `x` is an infinity. | 
 |     instruction->ReplaceWith(GetGraph()->GetConstant(type, 0)); | 
 |     block->RemoveInstruction(instruction); | 
 |   } | 
 | } | 
 |  | 
 | void InstructionWithAbsorbingInputSimplifier::VisitUShr(HUShr* instruction) { | 
 |   VisitShift(instruction); | 
 | } | 
 |  | 
 | void InstructionWithAbsorbingInputSimplifier::VisitXor(HXor* instruction) { | 
 |   if (instruction->GetLeft() == instruction->GetRight()) { | 
 |     // Replace code looking like | 
 |     //    XOR dst, src, src | 
 |     // with | 
 |     //    CONSTANT 0 | 
 |     Primitive::Type type = instruction->GetType(); | 
 |     HBasicBlock* block = instruction->GetBlock(); | 
 |     instruction->ReplaceWith(GetGraph()->GetConstant(type, 0)); | 
 |     block->RemoveInstruction(instruction); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace art |