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