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 class HDataProcWithShifterOp FINAL : public HExpression<2> {
154  public:
155   enum OpKind {
156     kLSL,   // Logical shift left.
157     kLSR,   // Logical shift right.
158     kASR,   // Arithmetic shift right.
159     kUXTB,  // Unsigned extend byte.
160     kUXTH,  // Unsigned extend half-word.
161     kUXTW,  // Unsigned extend word.
162     kSXTB,  // Signed extend byte.
163     kSXTH,  // Signed extend half-word.
164     kSXTW,  // Signed extend word.
165 
166     // Aliases.
167     kFirstShiftOp = kLSL,
168     kLastShiftOp = kASR,
169     kFirstExtensionOp = kUXTB,
170     kLastExtensionOp = kSXTW
171   };
172   HDataProcWithShifterOp(HInstruction* instr,
173                          HInstruction* left,
174                          HInstruction* right,
175                          OpKind op,
176                          // The shift argument is unused if the operation
177                          // is an extension.
178                          int shift = 0,
179                          uint32_t dex_pc = kNoDexPc)
180       : HExpression(instr->GetType(), SideEffects::None(), dex_pc),
181         instr_kind_(instr->GetKind()), op_kind_(op),
182         shift_amount_(shift & (instr->GetType() == Primitive::kPrimInt
183             ? kMaxIntShiftDistance
184             : kMaxLongShiftDistance)) {
185     DCHECK(!instr->HasSideEffects());
186     SetRawInputAt(0, left);
187     SetRawInputAt(1, right);
188   }
189 
CanBeMoved()190   bool CanBeMoved() const OVERRIDE { return true; }
InstructionDataEquals(const HInstruction * other_instr)191   bool InstructionDataEquals(const HInstruction* other_instr) const OVERRIDE {
192     const HDataProcWithShifterOp* other = other_instr->AsDataProcWithShifterOp();
193     return instr_kind_ == other->instr_kind_ &&
194         op_kind_ == other->op_kind_ &&
195         shift_amount_ == other->shift_amount_;
196   }
197 
IsShiftOp(OpKind op_kind)198   static bool IsShiftOp(OpKind op_kind) {
199     return kFirstShiftOp <= op_kind && op_kind <= kLastShiftOp;
200   }
201 
IsExtensionOp(OpKind op_kind)202   static bool IsExtensionOp(OpKind op_kind) {
203     return kFirstExtensionOp <= op_kind && op_kind <= kLastExtensionOp;
204   }
205 
206   // Find the operation kind and shift amount from a bitfield move instruction.
207   static void GetOpInfoFromInstruction(HInstruction* bitfield_op,
208                                        /*out*/OpKind* op_kind,
209                                        /*out*/int* shift_amount);
210 
GetInstrKind()211   InstructionKind GetInstrKind() const { return instr_kind_; }
GetOpKind()212   OpKind GetOpKind() const { return op_kind_; }
GetShiftAmount()213   int GetShiftAmount() const { return shift_amount_; }
214 
215   DECLARE_INSTRUCTION(DataProcWithShifterOp);
216 
217  private:
218   InstructionKind instr_kind_;
219   OpKind op_kind_;
220   int shift_amount_;
221 
222   friend std::ostream& operator<<(std::ostream& os, OpKind op);
223 
224   DISALLOW_COPY_AND_ASSIGN(HDataProcWithShifterOp);
225 };
226 
227 std::ostream& operator<<(std::ostream& os, const HDataProcWithShifterOp::OpKind op);
228 
229 }  // namespace art
230 
231 #endif  // ART_COMPILER_OPTIMIZING_NODES_SHARED_H_
232