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 HIDDEN {
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 // This instruction computes part of the array access offset (data and index offset).
66 //
67 // For array accesses the element address has the following structure:
68 // Address = CONST_OFFSET + base_addr + index << ELEM_SHIFT. Taking into account LDR/STR addressing
69 // modes address part (CONST_OFFSET + index << ELEM_SHIFT) can be shared across array access with
70 // the same data type and index. For example, for the following loop 5 accesses can share address
71 // computation:
72 //
73 // void foo(int[] a, int[] b, int[] c) {
74 //   for (i...) {
75 //     a[i] = a[i] + 5;
76 //     b[i] = b[i] + c[i];
77 //   }
78 // }
79 //
80 // Note: as the instruction doesn't involve base array address into computations it has no side
81 // effects (in comparison of HIntermediateAddress).
82 class HIntermediateAddressIndex final : public HExpression<3> {
83  public:
HIntermediateAddressIndex(HInstruction * index,HInstruction * offset,HInstruction * shift,uint32_t dex_pc)84   HIntermediateAddressIndex(
85       HInstruction* index, HInstruction* offset, HInstruction* shift, uint32_t dex_pc)
86       : HExpression(kIntermediateAddressIndex,
87                     DataType::Type::kInt32,
88                     SideEffects::None(),
89                     dex_pc) {
90     SetRawInputAt(0, index);
91     SetRawInputAt(1, offset);
92     SetRawInputAt(2, shift);
93   }
94 
IsClonable()95   bool IsClonable() const override { return true; }
CanBeMoved()96   bool CanBeMoved() const override { return true; }
InstructionDataEquals(const HInstruction * other)97   bool InstructionDataEquals([[maybe_unused]] const HInstruction* other) const override {
98     return true;
99   }
IsActualObject()100   bool IsActualObject() const override { return false; }
101 
GetIndex()102   HInstruction* GetIndex() const { return InputAt(0); }
GetOffset()103   HInstruction* GetOffset() const { return InputAt(1); }
GetShift()104   HInstruction* GetShift() const { return InputAt(2); }
105 
106   DECLARE_INSTRUCTION(IntermediateAddressIndex);
107 
108  protected:
109   DEFAULT_COPY_CONSTRUCTOR(IntermediateAddressIndex);
110 };
111 
112 class HDataProcWithShifterOp final : public HExpression<2> {
113  public:
114   enum OpKind {
115     kLSL,   // Logical shift left.
116     kLSR,   // Logical shift right.
117     kASR,   // Arithmetic shift right.
118     kUXTB,  // Unsigned extend byte.
119     kUXTH,  // Unsigned extend half-word.
120     kUXTW,  // Unsigned extend word.
121     kSXTB,  // Signed extend byte.
122     kSXTH,  // Signed extend half-word.
123     kSXTW,  // Signed extend word.
124 
125     // Aliases.
126     kFirstShiftOp = kLSL,
127     kLastShiftOp = kASR,
128     kFirstExtensionOp = kUXTB,
129     kLastExtensionOp = kSXTW
130   };
131   HDataProcWithShifterOp(HInstruction* instr,
132                          HInstruction* left,
133                          HInstruction* right,
134                          OpKind op,
135                          // The shift argument is unused if the operation
136                          // is an extension.
137                          int shift = 0,
138                          uint32_t dex_pc = kNoDexPc)
139       : HExpression(kDataProcWithShifterOp, instr->GetType(), SideEffects::None(), dex_pc),
140         instr_kind_(instr->GetKind()), op_kind_(op),
141         shift_amount_(shift & (instr->GetType() == DataType::Type::kInt32
142             ? kMaxIntShiftDistance
143             : kMaxLongShiftDistance)) {
144     DCHECK(!instr->HasSideEffects());
145     SetRawInputAt(0, left);
146     SetRawInputAt(1, right);
147   }
148 
IsClonable()149   bool IsClonable() const override { return true; }
CanBeMoved()150   bool CanBeMoved() const override { return true; }
InstructionDataEquals(const HInstruction * other_instr)151   bool InstructionDataEquals(const HInstruction* other_instr) const override {
152     const HDataProcWithShifterOp* other = other_instr->AsDataProcWithShifterOp();
153     return instr_kind_ == other->instr_kind_ &&
154         op_kind_ == other->op_kind_ &&
155         shift_amount_ == other->shift_amount_;
156   }
157 
IsShiftOp(OpKind op_kind)158   static bool IsShiftOp(OpKind op_kind) {
159     return kFirstShiftOp <= op_kind && op_kind <= kLastShiftOp;
160   }
161 
IsExtensionOp(OpKind op_kind)162   static bool IsExtensionOp(OpKind op_kind) {
163     return kFirstExtensionOp <= op_kind && op_kind <= kLastExtensionOp;
164   }
165 
166   // Find the operation kind and shift amount from a bitfield move instruction.
167   static void GetOpInfoFromInstruction(HInstruction* bitfield_op,
168                                        /*out*/OpKind* op_kind,
169                                        /*out*/int* shift_amount);
170 
GetInstrKind()171   InstructionKind GetInstrKind() const { return instr_kind_; }
GetOpKind()172   OpKind GetOpKind() const { return op_kind_; }
GetShiftAmount()173   int GetShiftAmount() const { return shift_amount_; }
174 
175   DECLARE_INSTRUCTION(DataProcWithShifterOp);
176 
177  protected:
178   DEFAULT_COPY_CONSTRUCTOR(DataProcWithShifterOp);
179 
180  private:
181   InstructionKind instr_kind_;
182   OpKind op_kind_;
183   int shift_amount_;
184 
185   friend std::ostream& operator<<(std::ostream& os, OpKind op);
186 };
187 
188 std::ostream& operator<<(std::ostream& os, const HDataProcWithShifterOp::OpKind op);
189 
190 }  // namespace art
191 
192 #endif  // ART_COMPILER_OPTIMIZING_NODES_SHARED_H_
193