• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
HExpression(type,SideEffects::None (),dex_pc)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 
CanBeMoved()45   bool CanBeMoved() const OVERRIDE { return true; }
InstructionDataEquals(const HInstruction * other)46   bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
47     return op_kind_ == other->AsMultiplyAccumulate()->op_kind_;
48   }
49 
GetOpKind()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)
HBinaryOperation(result_type,left,right,SideEffects::None (),dex_pc)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 
Evaluate(HIntConstant * x,HIntConstant * y)91   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
92     return GetBlock()->GetGraph()->GetIntConstant(
93         Compute(x->GetValue(), y->GetValue()), GetDexPc());
94   }
Evaluate(HLongConstant * x,HLongConstant * y)95   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
96     return GetBlock()->GetGraph()->GetLongConstant(
97         Compute(x->GetValue(), y->GetValue()), GetDexPc());
98   }
Evaluate(HFloatConstant * x ATTRIBUTE_UNUSED,HFloatConstant * y ATTRIBUTE_UNUSED)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   }
Evaluate(HDoubleConstant * x ATTRIBUTE_UNUSED,HDoubleConstant * y ATTRIBUTE_UNUSED)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 
GetOpKind()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:
HIntermediateAddress(HInstruction * base_address,HInstruction * offset,uint32_t dex_pc)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 
CanBeMoved()138   bool CanBeMoved() const OVERRIDE { return true; }
InstructionDataEquals(const HInstruction * other ATTRIBUTE_UNUSED)139   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
140     return true;
141   }
IsActualObject()142   bool IsActualObject() const OVERRIDE { return false; }
143 
GetBaseAddress()144   HInstruction* GetBaseAddress() const { return InputAt(0); }
GetOffset()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:
HIntermediateAddressIndex(HInstruction * index,HInstruction * offset,HInstruction * shift,uint32_t dex_pc)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 
CanBeMoved()180   bool CanBeMoved() const OVERRIDE { return true; }
InstructionDataEquals(const HInstruction * other ATTRIBUTE_UNUSED)181   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
182     return true;
183   }
IsActualObject()184   bool IsActualObject() const OVERRIDE { return false; }
185 
GetIndex()186   HInstruction* GetIndex() const { return InputAt(0); }
GetOffset()187   HInstruction* GetOffset() const { return InputAt(1); }
GetShift()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 
CanBeMoved()233   bool CanBeMoved() const OVERRIDE { return true; }
InstructionDataEquals(const HInstruction * other_instr)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 
IsShiftOp(OpKind op_kind)241   static bool IsShiftOp(OpKind op_kind) {
242     return kFirstShiftOp <= op_kind && op_kind <= kLastShiftOp;
243   }
244 
IsExtensionOp(OpKind op_kind)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 
GetInstrKind()254   InstructionKind GetInstrKind() const { return instr_kind_; }
GetOpKind()255   OpKind GetOpKind() const { return op_kind_; }
GetShiftAmount()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