blob: 6d107d571fb0ccf5fe6454d2a19de6bfe3d5481e [file] [log] [blame]
Alexandre Rames44b9cf92015-08-19 15:39:06 +01001/*
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#include "instruction_simplifier_arm64.h"
18
Alexandre Rames8626b742015-11-25 16:28:08 +000019#include "common_arm64.h"
Artem Udovichenko4a0dad62016-01-26 12:28:31 +030020#include "instruction_simplifier_shared.h"
Alexandre Ramese6dbf482015-10-19 10:10:41 +010021#include "mirror/array-inl.h"
Vladimir Marko87f3fcb2016-04-28 15:52:11 +010022#include "mirror/string.h"
Alexandre Ramese6dbf482015-10-19 10:10:41 +010023
Alexandre Rames44b9cf92015-08-19 15:39:06 +010024namespace art {
25namespace arm64 {
26
Alexandre Rames8626b742015-11-25 16:28:08 +000027using helpers::CanFitInShifterOperand;
28using helpers::HasShifterOperand;
29using helpers::ShifterOperandSupportsExtension;
30
Alexandre Rames8626b742015-11-25 16:28:08 +000031bool InstructionSimplifierArm64Visitor::TryMergeIntoShifterOperand(HInstruction* use,
32 HInstruction* bitfield_op,
33 bool do_merge) {
34 DCHECK(HasShifterOperand(use));
35 DCHECK(use->IsBinaryOperation() || use->IsNeg());
36 DCHECK(CanFitInShifterOperand(bitfield_op));
37 DCHECK(!bitfield_op->HasEnvironmentUses());
38
39 Primitive::Type type = use->GetType();
40 if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
41 return false;
42 }
43
44 HInstruction* left;
45 HInstruction* right;
46 if (use->IsBinaryOperation()) {
47 left = use->InputAt(0);
48 right = use->InputAt(1);
49 } else {
50 DCHECK(use->IsNeg());
51 right = use->AsNeg()->InputAt(0);
52 left = GetGraph()->GetConstant(right->GetType(), 0);
53 }
54 DCHECK(left == bitfield_op || right == bitfield_op);
55
56 if (left == right) {
57 // TODO: Handle special transformations in this situation?
58 // For example should we transform `(x << 1) + (x << 1)` into `(x << 2)`?
59 // Or should this be part of a separate transformation logic?
60 return false;
61 }
62
63 bool is_commutative = use->IsBinaryOperation() && use->AsBinaryOperation()->IsCommutative();
64 HInstruction* other_input;
65 if (bitfield_op == right) {
66 other_input = left;
67 } else {
68 if (is_commutative) {
69 other_input = right;
70 } else {
71 return false;
72 }
73 }
74
75 HArm64DataProcWithShifterOp::OpKind op_kind;
76 int shift_amount = 0;
77 HArm64DataProcWithShifterOp::GetOpInfoFromInstruction(bitfield_op, &op_kind, &shift_amount);
78
79 if (HArm64DataProcWithShifterOp::IsExtensionOp(op_kind) &&
80 !ShifterOperandSupportsExtension(use)) {
81 return false;
82 }
83
84 if (do_merge) {
85 HArm64DataProcWithShifterOp* alu_with_op =
86 new (GetGraph()->GetArena()) HArm64DataProcWithShifterOp(use,
87 other_input,
88 bitfield_op->InputAt(0),
89 op_kind,
90 shift_amount,
91 use->GetDexPc());
92 use->GetBlock()->ReplaceAndRemoveInstructionWith(use, alu_with_op);
Vladimir Marko46817b82016-03-29 12:21:58 +010093 if (bitfield_op->GetUses().empty()) {
Alexandre Rames8626b742015-11-25 16:28:08 +000094 bitfield_op->GetBlock()->RemoveInstruction(bitfield_op);
95 }
96 RecordSimplification();
97 }
98
99 return true;
100}
101
102// Merge a bitfield move instruction into its uses if it can be merged in all of them.
103bool InstructionSimplifierArm64Visitor::TryMergeIntoUsersShifterOperand(HInstruction* bitfield_op) {
104 DCHECK(CanFitInShifterOperand(bitfield_op));
105
106 if (bitfield_op->HasEnvironmentUses()) {
107 return false;
108 }
109
110 const HUseList<HInstruction*>& uses = bitfield_op->GetUses();
111
112 // Check whether we can merge the instruction in all its users' shifter operand.
Vladimir Marko46817b82016-03-29 12:21:58 +0100113 for (const HUseListNode<HInstruction*>& use : uses) {
114 HInstruction* user = use.GetUser();
115 if (!HasShifterOperand(user)) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000116 return false;
117 }
Vladimir Marko46817b82016-03-29 12:21:58 +0100118 if (!CanMergeIntoShifterOperand(user, bitfield_op)) {
Alexandre Rames8626b742015-11-25 16:28:08 +0000119 return false;
120 }
121 }
122
123 // Merge the instruction into its uses.
Vladimir Marko46817b82016-03-29 12:21:58 +0100124 for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
125 HInstruction* user = it->GetUser();
126 // Increment `it` now because `*it` will disappear thanks to MergeIntoShifterOperand().
127 ++it;
128 bool merged = MergeIntoShifterOperand(user, bitfield_op);
Alexandre Rames8626b742015-11-25 16:28:08 +0000129 DCHECK(merged);
130 }
131
132 return true;
133}
134
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000135void InstructionSimplifierArm64Visitor::VisitAnd(HAnd* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000136 if (TryMergeNegatedInput(instruction)) {
137 RecordSimplification();
138 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000139}
140
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100141void InstructionSimplifierArm64Visitor::VisitArrayGet(HArrayGet* instruction) {
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100142 size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Artem Serov328429f2016-07-06 16:23:04 +0100143 if (TryExtractArrayAccessAddress(instruction,
144 instruction->GetArray(),
145 instruction->GetIndex(),
146 data_offset)) {
147 RecordSimplification();
148 }
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100149}
150
151void InstructionSimplifierArm64Visitor::VisitArraySet(HArraySet* instruction) {
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100152 size_t access_size = Primitive::ComponentSize(instruction->GetComponentType());
153 size_t data_offset = mirror::Array::DataOffset(access_size).Uint32Value();
Artem Serov328429f2016-07-06 16:23:04 +0100154 if (TryExtractArrayAccessAddress(instruction,
155 instruction->GetArray(),
156 instruction->GetIndex(),
157 data_offset)) {
158 RecordSimplification();
159 }
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100160}
161
Alexandre Rames418318f2015-11-20 15:55:47 +0000162void InstructionSimplifierArm64Visitor::VisitMul(HMul* instruction) {
Artem Udovichenko4a0dad62016-01-26 12:28:31 +0300163 if (TryCombineMultiplyAccumulate(instruction, kArm64)) {
164 RecordSimplification();
Alexandre Rames418318f2015-11-20 15:55:47 +0000165 }
166}
167
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000168void InstructionSimplifierArm64Visitor::VisitOr(HOr* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000169 if (TryMergeNegatedInput(instruction)) {
170 RecordSimplification();
171 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000172}
173
Alexandre Rames8626b742015-11-25 16:28:08 +0000174void InstructionSimplifierArm64Visitor::VisitShl(HShl* instruction) {
175 if (instruction->InputAt(1)->IsConstant()) {
176 TryMergeIntoUsersShifterOperand(instruction);
177 }
178}
179
180void InstructionSimplifierArm64Visitor::VisitShr(HShr* instruction) {
181 if (instruction->InputAt(1)->IsConstant()) {
182 TryMergeIntoUsersShifterOperand(instruction);
183 }
184}
185
186void InstructionSimplifierArm64Visitor::VisitTypeConversion(HTypeConversion* instruction) {
187 Primitive::Type result_type = instruction->GetResultType();
188 Primitive::Type input_type = instruction->GetInputType();
189
190 if (input_type == result_type) {
191 // We let the arch-independent code handle this.
192 return;
193 }
194
195 if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
196 TryMergeIntoUsersShifterOperand(instruction);
197 }
198}
199
200void InstructionSimplifierArm64Visitor::VisitUShr(HUShr* instruction) {
201 if (instruction->InputAt(1)->IsConstant()) {
202 TryMergeIntoUsersShifterOperand(instruction);
203 }
204}
205
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000206void InstructionSimplifierArm64Visitor::VisitXor(HXor* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000207 if (TryMergeNegatedInput(instruction)) {
208 RecordSimplification();
209 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000210}
211
Alexandre Rames44b9cf92015-08-19 15:39:06 +0100212} // namespace arm64
213} // namespace art