blob: 7b4f5f7cbb3733a3110e2152feb4713a080f9ee3 [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 Serove1811ed2017-04-27 16:50:47 +0100121// This instruction computes part of the array access offset (data and index offset).
122//
123// For array accesses the element address has the following structure:
124// Address = CONST_OFFSET + base_addr + index << ELEM_SHIFT. Taking into account LDR/STR addressing
125// modes address part (CONST_OFFSET + index << ELEM_SHIFT) can be shared across array access with
126// the same data type and index. For example, for the following loop 5 accesses can share address
127// computation:
128//
129// void foo(int[] a, int[] b, int[] c) {
130// for (i...) {
131// a[i] = a[i] + 5;
132// b[i] = b[i] + c[i];
133// }
134// }
135//
136// Note: as the instruction doesn't involve base array address into computations it has no side
137// effects (in comparison of HIntermediateAddress).
138class HIntermediateAddressIndex FINAL : public HExpression<3> {
139 public:
140 HIntermediateAddressIndex(
141 HInstruction* index, HInstruction* offset, HInstruction* shift, uint32_t dex_pc)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100142 : HExpression(DataType::Type::kInt32, SideEffects::None(), dex_pc) {
Artem Serove1811ed2017-04-27 16:50:47 +0100143 SetRawInputAt(0, index);
144 SetRawInputAt(1, offset);
145 SetRawInputAt(2, shift);
146 }
147
148 bool CanBeMoved() const OVERRIDE { return true; }
149 bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
150 return true;
151 }
152 bool IsActualObject() const OVERRIDE { return false; }
153
154 HInstruction* GetIndex() const { return InputAt(0); }
155 HInstruction* GetOffset() const { return InputAt(1); }
156 HInstruction* GetShift() const { return InputAt(2); }
157
158 DECLARE_INSTRUCTION(IntermediateAddressIndex);
159
160 private:
161 DISALLOW_COPY_AND_ASSIGN(HIntermediateAddressIndex);
162};
163
Anton Kirilov74234da2017-01-13 14:42:47 +0000164class HDataProcWithShifterOp FINAL : public HExpression<2> {
165 public:
166 enum OpKind {
167 kLSL, // Logical shift left.
168 kLSR, // Logical shift right.
169 kASR, // Arithmetic shift right.
170 kUXTB, // Unsigned extend byte.
171 kUXTH, // Unsigned extend half-word.
172 kUXTW, // Unsigned extend word.
173 kSXTB, // Signed extend byte.
174 kSXTH, // Signed extend half-word.
175 kSXTW, // Signed extend word.
176
177 // Aliases.
178 kFirstShiftOp = kLSL,
179 kLastShiftOp = kASR,
180 kFirstExtensionOp = kUXTB,
181 kLastExtensionOp = kSXTW
182 };
183 HDataProcWithShifterOp(HInstruction* instr,
184 HInstruction* left,
185 HInstruction* right,
186 OpKind op,
187 // The shift argument is unused if the operation
188 // is an extension.
189 int shift = 0,
190 uint32_t dex_pc = kNoDexPc)
191 : HExpression(instr->GetType(), SideEffects::None(), dex_pc),
192 instr_kind_(instr->GetKind()), op_kind_(op),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100193 shift_amount_(shift & (instr->GetType() == DataType::Type::kInt32
Anton Kirilov74234da2017-01-13 14:42:47 +0000194 ? kMaxIntShiftDistance
195 : kMaxLongShiftDistance)) {
196 DCHECK(!instr->HasSideEffects());
197 SetRawInputAt(0, left);
198 SetRawInputAt(1, right);
199 }
200
201 bool CanBeMoved() const OVERRIDE { return true; }
202 bool InstructionDataEquals(const HInstruction* other_instr) const OVERRIDE {
203 const HDataProcWithShifterOp* other = other_instr->AsDataProcWithShifterOp();
204 return instr_kind_ == other->instr_kind_ &&
205 op_kind_ == other->op_kind_ &&
206 shift_amount_ == other->shift_amount_;
207 }
208
209 static bool IsShiftOp(OpKind op_kind) {
210 return kFirstShiftOp <= op_kind && op_kind <= kLastShiftOp;
211 }
212
213 static bool IsExtensionOp(OpKind op_kind) {
214 return kFirstExtensionOp <= op_kind && op_kind <= kLastExtensionOp;
215 }
216
217 // Find the operation kind and shift amount from a bitfield move instruction.
218 static void GetOpInfoFromInstruction(HInstruction* bitfield_op,
219 /*out*/OpKind* op_kind,
220 /*out*/int* shift_amount);
221
222 InstructionKind GetInstrKind() const { return instr_kind_; }
223 OpKind GetOpKind() const { return op_kind_; }
224 int GetShiftAmount() const { return shift_amount_; }
225
226 DECLARE_INSTRUCTION(DataProcWithShifterOp);
227
228 private:
229 InstructionKind instr_kind_;
230 OpKind op_kind_;
231 int shift_amount_;
232
233 friend std::ostream& operator<<(std::ostream& os, OpKind op);
234
235 DISALLOW_COPY_AND_ASSIGN(HDataProcWithShifterOp);
236};
237
238std::ostream& operator<<(std::ostream& os, const HDataProcWithShifterOp::OpKind op);
Artem Serov328429f2016-07-06 16:23:04 +0100239
Artem Udovichenko4a0dad62016-01-26 12:28:31 +0300240} // namespace art
241
242#endif // ART_COMPILER_OPTIMIZING_NODES_SHARED_H_