blob: d0dd650024494fa4db4ae485fad53fa092079a1b [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);
jessicahandojo05765752016-09-09 19:01:32 -0700143 // Don't move the array pointer if it is charAt because we need to take the count first.
144 // TODO: Implement reading (length + compression) for String compression feature from
145 // negative offset (count_offset - data_offset) using LDP and clobbering an extra temporary.
146 // Note that "LDR (Immediate)" does not have a "signed offset" encoding.
147 if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
148 return;
149 }
Artem Serov328429f2016-07-06 16:23:04 +0100150 if (TryExtractArrayAccessAddress(instruction,
151 instruction->GetArray(),
152 instruction->GetIndex(),
153 data_offset)) {
154 RecordSimplification();
155 }
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100156}
157
158void InstructionSimplifierArm64Visitor::VisitArraySet(HArraySet* instruction) {
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100159 size_t access_size = Primitive::ComponentSize(instruction->GetComponentType());
160 size_t data_offset = mirror::Array::DataOffset(access_size).Uint32Value();
Artem Serov328429f2016-07-06 16:23:04 +0100161 if (TryExtractArrayAccessAddress(instruction,
162 instruction->GetArray(),
163 instruction->GetIndex(),
164 data_offset)) {
165 RecordSimplification();
166 }
Alexandre Ramese6dbf482015-10-19 10:10:41 +0100167}
168
Alexandre Rames418318f2015-11-20 15:55:47 +0000169void InstructionSimplifierArm64Visitor::VisitMul(HMul* instruction) {
Artem Udovichenko4a0dad62016-01-26 12:28:31 +0300170 if (TryCombineMultiplyAccumulate(instruction, kArm64)) {
171 RecordSimplification();
Alexandre Rames418318f2015-11-20 15:55:47 +0000172 }
173}
174
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000175void InstructionSimplifierArm64Visitor::VisitOr(HOr* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000176 if (TryMergeNegatedInput(instruction)) {
177 RecordSimplification();
178 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000179}
180
Alexandre Rames8626b742015-11-25 16:28:08 +0000181void InstructionSimplifierArm64Visitor::VisitShl(HShl* instruction) {
182 if (instruction->InputAt(1)->IsConstant()) {
183 TryMergeIntoUsersShifterOperand(instruction);
184 }
185}
186
187void InstructionSimplifierArm64Visitor::VisitShr(HShr* instruction) {
188 if (instruction->InputAt(1)->IsConstant()) {
189 TryMergeIntoUsersShifterOperand(instruction);
190 }
191}
192
193void InstructionSimplifierArm64Visitor::VisitTypeConversion(HTypeConversion* instruction) {
194 Primitive::Type result_type = instruction->GetResultType();
195 Primitive::Type input_type = instruction->GetInputType();
196
197 if (input_type == result_type) {
198 // We let the arch-independent code handle this.
199 return;
200 }
201
202 if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
203 TryMergeIntoUsersShifterOperand(instruction);
204 }
205}
206
207void InstructionSimplifierArm64Visitor::VisitUShr(HUShr* instruction) {
208 if (instruction->InputAt(1)->IsConstant()) {
209 TryMergeIntoUsersShifterOperand(instruction);
210 }
211}
212
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000213void InstructionSimplifierArm64Visitor::VisitXor(HXor* instruction) {
Artem Serov7fc63502016-02-09 17:15:29 +0000214 if (TryMergeNegatedInput(instruction)) {
215 RecordSimplification();
216 }
Kevin Brodsky9ff0d202016-01-11 13:43:31 +0000217}
218
Alexandre Rames44b9cf92015-08-19 15:39:06 +0100219} // namespace arm64
220} // namespace art