Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2015 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 
     17 #ifndef ART_COMPILER_OPTIMIZING_NODES_SHARED_H_
     18 #define ART_COMPILER_OPTIMIZING_NODES_SHARED_H_
     19 
     20 // This `#include` should never be used by compilation, as this file (`nodes_shared.h`) is included
     21 // in `nodes.h`. However it helps editing tools (e.g. YouCompleteMe) by giving them better context
     22 // (defining `HInstruction` and co).
     23 #include "nodes.h"
     24 
     25 namespace art {
     26 
     27 class HMultiplyAccumulate FINAL : public HExpression<3> {
     28  public:
     29   HMultiplyAccumulate(Primitive::Type type,
     30                       InstructionKind op,
     31                       HInstruction* accumulator,
     32                       HInstruction* mul_left,
     33                       HInstruction* mul_right,
     34                       uint32_t dex_pc = kNoDexPc)
     35       : HExpression(type, SideEffects::None(), dex_pc), op_kind_(op) {
     36     SetRawInputAt(kInputAccumulatorIndex, accumulator);
     37     SetRawInputAt(kInputMulLeftIndex, mul_left);
     38     SetRawInputAt(kInputMulRightIndex, mul_right);
     39   }
     40 
     41   static constexpr int kInputAccumulatorIndex = 0;
     42   static constexpr int kInputMulLeftIndex = 1;
     43   static constexpr int kInputMulRightIndex = 2;
     44 
     45   bool CanBeMoved() const OVERRIDE { return true; }
     46   bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
     47     return op_kind_ == other->AsMultiplyAccumulate()->op_kind_;
     48   }
     49 
     50   InstructionKind GetOpKind() const { return op_kind_; }
     51 
     52   DECLARE_INSTRUCTION(MultiplyAccumulate);
     53 
     54  private:
     55   // Indicates if this is a MADD or MSUB.
     56   const InstructionKind op_kind_;
     57 
     58   DISALLOW_COPY_AND_ASSIGN(HMultiplyAccumulate);
     59 };
     60 
     61 class HBitwiseNegatedRight FINAL : public HBinaryOperation {
     62  public:
     63   HBitwiseNegatedRight(Primitive::Type result_type,
     64                             InstructionKind op,
     65                             HInstruction* left,
     66                             HInstruction* right,
     67                             uint32_t dex_pc = kNoDexPc)
     68     : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc),
     69       op_kind_(op) {
     70     DCHECK(op == HInstruction::kAnd || op == HInstruction::kOr || op == HInstruction::kXor) << op;
     71   }
     72 
     73   template <typename T, typename U>
     74   auto Compute(T x, U y) const -> decltype(x & ~y) {
     75     static_assert(std::is_same<decltype(x & ~y), decltype(x | ~y)>::value &&
     76                   std::is_same<decltype(x & ~y), decltype(x ^ ~y)>::value,
     77                   "Inconsistent negated bitwise types");
     78     switch (op_kind_) {
     79       case HInstruction::kAnd:
     80         return x & ~y;
     81       case HInstruction::kOr:
     82         return x | ~y;
     83       case HInstruction::kXor:
     84         return x ^ ~y;
     85       default:
     86         LOG(FATAL) << "Unreachable";
     87         UNREACHABLE();
     88     }
     89   }
     90 
     91   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
     92     return GetBlock()->GetGraph()->GetIntConstant(
     93         Compute(x->GetValue(), y->GetValue()), GetDexPc());
     94   }
     95   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
     96     return GetBlock()->GetGraph()->GetLongConstant(
     97         Compute(x->GetValue(), y->GetValue()), GetDexPc());
     98   }
     99   HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
    100                       HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
    101     LOG(FATAL) << DebugName() << " is not defined for float values";
    102     UNREACHABLE();
    103   }
    104   HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
    105                       HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE {
    106     LOG(FATAL) << DebugName() << " is not defined for double values";
    107     UNREACHABLE();
    108   }
    109 
    110   InstructionKind GetOpKind() const { return op_kind_; }
    111 
    112   DECLARE_INSTRUCTION(BitwiseNegatedRight);
    113 
    114  private:
    115   // Specifies the bitwise operation, which will be then negated.
    116   const InstructionKind op_kind_;
    117 
    118   DISALLOW_COPY_AND_ASSIGN(HBitwiseNegatedRight);
    119 };
    120 
    121 
    122 // This instruction computes an intermediate address pointing in the 'middle' of an object. The
    123 // result pointer cannot be handled by GC, so extra care is taken to make sure that this value is
    124 // never used across anything that can trigger GC.
    125 // The result of this instruction is not a pointer in the sense of `Primitive::kPrimNot`. So we
    126 // represent it by the type `Primitive::kPrimInt`.
    127 class HIntermediateAddress FINAL : public HExpression<2> {
    128  public:
    129   HIntermediateAddress(HInstruction* base_address, HInstruction* offset, uint32_t dex_pc)
    130       : HExpression(Primitive::kPrimInt, SideEffects::DependsOnGC(), dex_pc) {
    131         DCHECK_EQ(Primitive::ComponentSize(Primitive::kPrimInt),
    132                   Primitive::ComponentSize(Primitive::kPrimNot))
    133             << "kPrimInt and kPrimNot have different sizes.";
    134     SetRawInputAt(0, base_address);
    135     SetRawInputAt(1, offset);
    136   }
    137 
    138   bool CanBeMoved() const OVERRIDE { return true; }
    139   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
    140     return true;
    141   }
    142   bool IsActualObject() const OVERRIDE { return false; }
    143 
    144   HInstruction* GetBaseAddress() const { return InputAt(0); }
    145   HInstruction* GetOffset() const { return InputAt(1); }
    146 
    147   DECLARE_INSTRUCTION(IntermediateAddress);
    148 
    149  private:
    150   DISALLOW_COPY_AND_ASSIGN(HIntermediateAddress);
    151 };
    152 
    153 // This instruction computes part of the array access offset (data and index offset).
    154 //
    155 // For array accesses the element address has the following structure:
    156 // Address = CONST_OFFSET + base_addr + index << ELEM_SHIFT. Taking into account LDR/STR addressing
    157 // modes address part (CONST_OFFSET + index << ELEM_SHIFT) can be shared across array access with
    158 // the same data type and index. For example, for the following loop 5 accesses can share address
    159 // computation:
    160 //
    161 // void foo(int[] a, int[] b, int[] c) {
    162 //   for (i...) {
    163 //     a[i] = a[i] + 5;
    164 //     b[i] = b[i] + c[i];
    165 //   }
    166 // }
    167 //
    168 // Note: as the instruction doesn't involve base array address into computations it has no side
    169 // effects (in comparison of HIntermediateAddress).
    170 class HIntermediateAddressIndex FINAL : public HExpression<3> {
    171  public:
    172   HIntermediateAddressIndex(
    173       HInstruction* index, HInstruction* offset, HInstruction* shift, uint32_t dex_pc)
    174       : HExpression(Primitive::kPrimInt, SideEffects::None(), dex_pc) {
    175     SetRawInputAt(0, index);
    176     SetRawInputAt(1, offset);
    177     SetRawInputAt(2, shift);
    178   }
    179 
    180   bool CanBeMoved() const OVERRIDE { return true; }
    181   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
    182     return true;
    183   }
    184   bool IsActualObject() const OVERRIDE { return false; }
    185 
    186   HInstruction* GetIndex() const { return InputAt(0); }
    187   HInstruction* GetOffset() const { return InputAt(1); }
    188   HInstruction* GetShift() const { return InputAt(2); }
    189 
    190   DECLARE_INSTRUCTION(IntermediateAddressIndex);
    191 
    192  private:
    193   DISALLOW_COPY_AND_ASSIGN(HIntermediateAddressIndex);
    194 };
    195 
    196 class HDataProcWithShifterOp FINAL : public HExpression<2> {
    197  public:
    198   enum OpKind {
    199     kLSL,   // Logical shift left.
    200     kLSR,   // Logical shift right.
    201     kASR,   // Arithmetic shift right.
    202     kUXTB,  // Unsigned extend byte.
    203     kUXTH,  // Unsigned extend half-word.
    204     kUXTW,  // Unsigned extend word.
    205     kSXTB,  // Signed extend byte.
    206     kSXTH,  // Signed extend half-word.
    207     kSXTW,  // Signed extend word.
    208 
    209     // Aliases.
    210     kFirstShiftOp = kLSL,
    211     kLastShiftOp = kASR,
    212     kFirstExtensionOp = kUXTB,
    213     kLastExtensionOp = kSXTW
    214   };
    215   HDataProcWithShifterOp(HInstruction* instr,
    216                          HInstruction* left,
    217                          HInstruction* right,
    218                          OpKind op,
    219                          // The shift argument is unused if the operation
    220                          // is an extension.
    221                          int shift = 0,
    222                          uint32_t dex_pc = kNoDexPc)
    223       : HExpression(instr->GetType(), SideEffects::None(), dex_pc),
    224         instr_kind_(instr->GetKind()), op_kind_(op),
    225         shift_amount_(shift & (instr->GetType() == Primitive::kPrimInt
    226             ? kMaxIntShiftDistance
    227             : kMaxLongShiftDistance)) {
    228     DCHECK(!instr->HasSideEffects());
    229     SetRawInputAt(0, left);
    230     SetRawInputAt(1, right);
    231   }
    232 
    233   bool CanBeMoved() const OVERRIDE { return true; }
    234   bool InstructionDataEquals(const HInstruction* other_instr) const OVERRIDE {
    235     const HDataProcWithShifterOp* other = other_instr->AsDataProcWithShifterOp();
    236     return instr_kind_ == other->instr_kind_ &&
    237         op_kind_ == other->op_kind_ &&
    238         shift_amount_ == other->shift_amount_;
    239   }
    240 
    241   static bool IsShiftOp(OpKind op_kind) {
    242     return kFirstShiftOp <= op_kind && op_kind <= kLastShiftOp;
    243   }
    244 
    245   static bool IsExtensionOp(OpKind op_kind) {
    246     return kFirstExtensionOp <= op_kind && op_kind <= kLastExtensionOp;
    247   }
    248 
    249   // Find the operation kind and shift amount from a bitfield move instruction.
    250   static void GetOpInfoFromInstruction(HInstruction* bitfield_op,
    251                                        /*out*/OpKind* op_kind,
    252                                        /*out*/int* shift_amount);
    253 
    254   InstructionKind GetInstrKind() const { return instr_kind_; }
    255   OpKind GetOpKind() const { return op_kind_; }
    256   int GetShiftAmount() const { return shift_amount_; }
    257 
    258   DECLARE_INSTRUCTION(DataProcWithShifterOp);
    259 
    260  private:
    261   InstructionKind instr_kind_;
    262   OpKind op_kind_;
    263   int shift_amount_;
    264 
    265   friend std::ostream& operator<<(std::ostream& os, OpKind op);
    266 
    267   DISALLOW_COPY_AND_ASSIGN(HDataProcWithShifterOp);
    268 };
    269 
    270 std::ostream& operator<<(std::ostream& os, const HDataProcWithShifterOp::OpKind op);
    271 
    272 }  // namespace art
    273 
    274 #endif  // ART_COMPILER_OPTIMIZING_NODES_SHARED_H_
    275