blob: 14cbf85c3f355416eebd77fdcad54e7800f3c41c [file] [log] [blame]
Artem Udovichenko4a0dad62016-01-26 12:28:31 +03001/*
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
Alexandre Ramesebc32802016-09-19 13:56:18 +010020// 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
Artem Udovichenko4a0dad62016-01-26 12:28:31 +030025namespace art {
26
Vladimir Markofcb503c2016-05-18 12:48:17 +010027class HMultiplyAccumulate FINAL : public HExpression<3> {
Artem Udovichenko4a0dad62016-01-26 12:28:31 +030028 public:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010029 HMultiplyAccumulate(DataType::Type type,
Artem Udovichenko4a0dad62016-01-26 12:28:31 +030030 InstructionKind op,
31 HInstruction* accumulator,
32 HInstruction* mul_left,
33 HInstruction* mul_right,
34 uint32_t dex_pc = kNoDexPc)
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
45 bool CanBeMoved() const OVERRIDE { return true; }
Vladimir Marko372f10e2016-05-17 16:30:10 +010046 bool InstructionDataEquals(const HInstruction* other) const OVERRIDE {
Artem Udovichenko4a0dad62016-01-26 12:28:31 +030047 return op_kind_ == other->AsMultiplyAccumulate()->op_kind_;
48 }
49
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
Vladimir Markofcb503c2016-05-18 12:48:17 +010061class HBitwiseNegatedRight FINAL : public HBinaryOperation {
Artem Serov7fc63502016-02-09 17:15:29 +000062 public:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010063 HBitwiseNegatedRight(DataType::Type result_type,
64 InstructionKind op,
65 HInstruction* left,
66 HInstruction* right,
67 uint32_t dex_pc = kNoDexPc)
Artem Serov7fc63502016-02-09 17:15:29 +000068 : 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
91 HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
92 return GetBlock()->GetGraph()->GetIntConstant(
93 Compute(x->GetValue(), y->GetValue()), GetDexPc());
94 }
95 HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
96 return GetBlock()->GetGraph()->GetLongConstant(
97 Compute(x->GetValue(), y->GetValue()), GetDexPc());
98 }
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 }
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
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
Artem Serov328429f2016-07-06 16:23:04 +0100121
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.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100125// The result of this instruction is not a pointer in the sense of `DataType::Type::kreference`.
126// So we represent it by the type `DataType::Type::kInt`.
Artem Serov328429f2016-07-06 16:23:04 +0100127class HIntermediateAddress FINAL : public HExpression<2> {
128 public:
129 HIntermediateAddress(HInstruction* base_address, HInstruction* offset, uint32_t dex_pc)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100130 : HExpression(DataType::Type::kInt32, SideEffects::DependsOnGC(), dex_pc) {
131 DCHECK_EQ(DataType::Size(DataType::Type::kInt32),
132 DataType::Size(DataType::Type::kReference))
Alexandre Rames91a65162016-09-19 13:54:30 +0100133 << "kPrimInt and kPrimNot have different sizes.";
Artem Serov328429f2016-07-06 16:23:04 +0100134 SetRawInputAt(0, base_address);
135 SetRawInputAt(1, offset);
136 }
137
138 bool CanBeMoved() const OVERRIDE { return true; }
139 bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
140 return true;
141 }
142 bool IsActualObject() const OVERRIDE { return false; }
143
144 HInstruction* GetBaseAddress() const { return InputAt(0); }
145 HInstruction* GetOffset() const { return InputAt(1); }
146
147 DECLARE_INSTRUCTION(IntermediateAddress);
148
149 private:
150 DISALLOW_COPY_AND_ASSIGN(HIntermediateAddress);
151};
152
Artem Serove1811ed2017-04-27 16:50:47 +0100153// 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).
170class HIntermediateAddressIndex FINAL : public HExpression<3> {
171 public:
172 HIntermediateAddressIndex(
173 HInstruction* index, HInstruction* offset, HInstruction* shift, uint32_t dex_pc)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100174 : HExpression(DataType::Type::kInt32, SideEffects::None(), dex_pc) {
Artem Serove1811ed2017-04-27 16:50:47 +0100175 SetRawInputAt(0, index);
176 SetRawInputAt(1, offset);
177 SetRawInputAt(2, shift);
178 }
179
180 bool CanBeMoved() const OVERRIDE { return true; }
181 bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
182 return true;
183 }
184 bool IsActualObject() const OVERRIDE { return false; }
185
186 HInstruction* GetIndex() const { return InputAt(0); }
187 HInstruction* GetOffset() const { return InputAt(1); }
188 HInstruction* GetShift() const { return InputAt(2); }
189
190 DECLARE_INSTRUCTION(IntermediateAddressIndex);
191
192 private:
193 DISALLOW_COPY_AND_ASSIGN(HIntermediateAddressIndex);
194};
195
Anton Kirilov74234da2017-01-13 14:42:47 +0000196class 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),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100225 shift_amount_(shift & (instr->GetType() == DataType::Type::kInt32
Anton Kirilov74234da2017-01-13 14:42:47 +0000226 ? kMaxIntShiftDistance
227 : kMaxLongShiftDistance)) {
228 DCHECK(!instr->HasSideEffects());
229 SetRawInputAt(0, left);
230 SetRawInputAt(1, right);
231 }
232
233 bool CanBeMoved() const OVERRIDE { return true; }
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
241 static bool IsShiftOp(OpKind op_kind) {
242 return kFirstShiftOp <= op_kind && op_kind <= kLastShiftOp;
243 }
244
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
254 InstructionKind GetInstrKind() const { return instr_kind_; }
255 OpKind GetOpKind() const { return op_kind_; }
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
270std::ostream& operator<<(std::ostream& os, const HDataProcWithShifterOp::OpKind op);
Artem Serov328429f2016-07-06 16:23:04 +0100271
Artem Udovichenko4a0dad62016-01-26 12:28:31 +0300272} // namespace art
273
274#endif // ART_COMPILER_OPTIMIZING_NODES_SHARED_H_