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 HIDDEN { 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) HExpression(kMultiplyAccumulate,type,SideEffects::None (),dex_pc)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 IsClonable()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 CanBeMoved()48 bool CanBeMoved() const override { return true; } InstructionDataEquals(const HInstruction * other)49 bool InstructionDataEquals(const HInstruction* other) const override { 50 return op_kind_ == other->AsMultiplyAccumulate()->op_kind_; 51 } 52 GetOpKind()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) HBinaryOperation(kBitwiseNegatedRight,result_type,left,right,SideEffects::None (),dex_pc)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 Evaluate(HIntConstant * x,HIntConstant * y)100 HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const override { 101 return GetBlock()->GetGraph()->GetIntConstant( 102 Compute(x->GetValue(), y->GetValue()), GetDexPc()); 103 } Evaluate(HLongConstant * x,HLongConstant * y)104 HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override { 105 return GetBlock()->GetGraph()->GetLongConstant( 106 Compute(x->GetValue(), y->GetValue()), GetDexPc()); 107 } Evaluate(HFloatConstant * x ATTRIBUTE_UNUSED,HFloatConstant * y ATTRIBUTE_UNUSED)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 } Evaluate(HDoubleConstant * x ATTRIBUTE_UNUSED,HDoubleConstant * y ATTRIBUTE_UNUSED)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 GetOpKind()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: HIntermediateAddressIndex(HInstruction * index,HInstruction * offset,HInstruction * shift,uint32_t dex_pc)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 IsClonable()161 bool IsClonable() const override { return true; } CanBeMoved()162 bool CanBeMoved() const override { return true; } InstructionDataEquals(const HInstruction * other ATTRIBUTE_UNUSED)163 bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const override { 164 return true; 165 } IsActualObject()166 bool IsActualObject() const override { return false; } 167 GetIndex()168 HInstruction* GetIndex() const { return InputAt(0); } GetOffset()169 HInstruction* GetOffset() const { return InputAt(1); } GetShift()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 IsClonable()215 bool IsClonable() const override { return true; } CanBeMoved()216 bool CanBeMoved() const override { return true; } InstructionDataEquals(const HInstruction * other_instr)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 IsShiftOp(OpKind op_kind)224 static bool IsShiftOp(OpKind op_kind) { 225 return kFirstShiftOp <= op_kind && op_kind <= kLastShiftOp; 226 } 227 IsExtensionOp(OpKind op_kind)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 GetInstrKind()237 InstructionKind GetInstrKind() const { return instr_kind_; } GetOpKind()238 OpKind GetOpKind() const { return op_kind_; } GetShiftAmount()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