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)
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