blob: a6f14616bf98529e6ed2b21fa0a00c6e0d5acb66 [file] [log] [blame]
Mark Mendell94991072015-10-06 14:58:32 -04001/*
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
Vladimir Marko0f7dca42015-11-02 14:36:43 +000017#include "pc_relative_fixups_x86.h"
Vladimir Markof3e0ee22015-12-17 15:23:13 +000018#include "code_generator_x86.h"
Mark Mendell94991072015-10-06 14:58:32 -040019
20namespace art {
21namespace x86 {
22
23/**
24 * Finds instructions that need the constant area base as an input.
25 */
Vladimir Marko0f7dca42015-11-02 14:36:43 +000026class PCRelativeHandlerVisitor : public HGraphVisitor {
Mark Mendell94991072015-10-06 14:58:32 -040027 public:
Vladimir Marko0f7dca42015-11-02 14:36:43 +000028 explicit PCRelativeHandlerVisitor(HGraph* graph) : HGraphVisitor(graph), base_(nullptr) {}
Mark Mendell94991072015-10-06 14:58:32 -040029
Vladimir Markofb337ea2015-11-25 15:25:10 +000030 void MoveBaseIfNeeded() {
31 if (base_ != nullptr) {
32 // Bring the base closer to the first use (previously, it was in the
33 // entry block) and relieve some pressure on the register allocator
34 // while avoiding recalculation of the base in a loop.
35 base_->MoveBeforeFirstUserAndOutOfLoops();
36 }
37 }
38
Mark Mendell94991072015-10-06 14:58:32 -040039 private:
40 void VisitAdd(HAdd* add) OVERRIDE {
41 BinaryFP(add);
42 }
43
44 void VisitSub(HSub* sub) OVERRIDE {
45 BinaryFP(sub);
46 }
47
48 void VisitMul(HMul* mul) OVERRIDE {
49 BinaryFP(mul);
50 }
51
52 void VisitDiv(HDiv* div) OVERRIDE {
53 BinaryFP(div);
54 }
55
Mark P Mendell2f10a5f2016-01-25 14:47:50 +000056 void VisitCompare(HCompare* compare) OVERRIDE {
57 BinaryFP(compare);
58 }
59
Mark Mendell94991072015-10-06 14:58:32 -040060 void VisitReturn(HReturn* ret) OVERRIDE {
61 HConstant* value = ret->InputAt(0)->AsConstant();
62 if ((value != nullptr && Primitive::IsFloatingPointType(value->GetType()))) {
63 ReplaceInput(ret, value, 0, true);
64 }
65 }
66
67 void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
68 HandleInvoke(invoke);
69 }
70
71 void VisitInvokeVirtual(HInvokeVirtual* invoke) OVERRIDE {
72 HandleInvoke(invoke);
73 }
74
75 void VisitInvokeInterface(HInvokeInterface* invoke) OVERRIDE {
76 HandleInvoke(invoke);
77 }
78
79 void BinaryFP(HBinaryOperation* bin) {
80 HConstant* rhs = bin->InputAt(1)->AsConstant();
Mark P Mendell2f10a5f2016-01-25 14:47:50 +000081 if (rhs != nullptr && Primitive::IsFloatingPointType(rhs->GetType())) {
Mark Mendell94991072015-10-06 14:58:32 -040082 ReplaceInput(bin, rhs, 1, false);
83 }
84 }
85
Mark P Mendell2f10a5f2016-01-25 14:47:50 +000086 void VisitEqual(HEqual* cond) OVERRIDE {
87 BinaryFP(cond);
88 }
89
90 void VisitNotEqual(HNotEqual* cond) OVERRIDE {
91 BinaryFP(cond);
92 }
93
94 void VisitLessThan(HLessThan* cond) OVERRIDE {
95 BinaryFP(cond);
96 }
97
98 void VisitLessThanOrEqual(HLessThanOrEqual* cond) OVERRIDE {
99 BinaryFP(cond);
100 }
101
102 void VisitGreaterThan(HGreaterThan* cond) OVERRIDE {
103 BinaryFP(cond);
104 }
105
106 void VisitGreaterThanOrEqual(HGreaterThanOrEqual* cond) OVERRIDE {
107 BinaryFP(cond);
108 }
109
110 void VisitNeg(HNeg* neg) OVERRIDE {
111 if (Primitive::IsFloatingPointType(neg->GetType())) {
112 // We need to replace the HNeg with a HX86FPNeg in order to address the constant area.
113 InitializePCRelativeBasePointer();
114 HGraph* graph = GetGraph();
115 HBasicBlock* block = neg->GetBlock();
116 HX86FPNeg* x86_fp_neg = new (graph->GetArena()) HX86FPNeg(
117 neg->GetType(),
118 neg->InputAt(0),
119 base_,
120 neg->GetDexPc());
121 block->ReplaceAndRemoveInstructionWith(neg, x86_fp_neg);
122 }
123 }
124
Mark Mendell94991072015-10-06 14:58:32 -0400125 void VisitPackedSwitch(HPackedSwitch* switch_insn) OVERRIDE {
Vladimir Markof3e0ee22015-12-17 15:23:13 +0000126 if (switch_insn->GetNumEntries() <=
127 InstructionCodeGeneratorX86::kPackedSwitchJumpTableThreshold) {
128 return;
129 }
Mark Mendell94991072015-10-06 14:58:32 -0400130 // We need to replace the HPackedSwitch with a HX86PackedSwitch in order to
131 // address the constant area.
Vladimir Markofb337ea2015-11-25 15:25:10 +0000132 InitializePCRelativeBasePointer();
Mark Mendell94991072015-10-06 14:58:32 -0400133 HGraph* graph = GetGraph();
134 HBasicBlock* block = switch_insn->GetBlock();
135 HX86PackedSwitch* x86_switch = new (graph->GetArena()) HX86PackedSwitch(
136 switch_insn->GetStartValue(),
137 switch_insn->GetNumEntries(),
138 switch_insn->InputAt(0),
139 base_,
140 switch_insn->GetDexPc());
141 block->ReplaceAndRemoveInstructionWith(switch_insn, x86_switch);
142 }
143
Vladimir Markofb337ea2015-11-25 15:25:10 +0000144 void InitializePCRelativeBasePointer() {
Mark Mendell94991072015-10-06 14:58:32 -0400145 // Ensure we only initialize the pointer once.
146 if (base_ != nullptr) {
147 return;
148 }
149
Vladimir Markofb337ea2015-11-25 15:25:10 +0000150 // Insert the base at the start of the entry block, move it to a better
151 // position later in MoveBaseIfNeeded().
152 base_ = new (GetGraph()->GetArena()) HX86ComputeBaseMethodAddress();
153 HBasicBlock* entry_block = GetGraph()->GetEntryBlock();
154 entry_block->InsertInstructionBefore(base_, entry_block->GetFirstInstruction());
Mark Mendell94991072015-10-06 14:58:32 -0400155 DCHECK(base_ != nullptr);
156 }
157
158 void ReplaceInput(HInstruction* insn, HConstant* value, int input_index, bool materialize) {
Vladimir Markofb337ea2015-11-25 15:25:10 +0000159 InitializePCRelativeBasePointer();
Mark Mendell94991072015-10-06 14:58:32 -0400160 HX86LoadFromConstantTable* load_constant =
David Brazdilb3e773e2016-01-26 11:28:37 +0000161 new (GetGraph()->GetArena()) HX86LoadFromConstantTable(base_, value);
162 if (!materialize) {
163 load_constant->MarkEmittedAtUseSite();
164 }
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000165 insn->GetBlock()->InsertInstructionBefore(load_constant, insn);
Mark Mendell94991072015-10-06 14:58:32 -0400166 insn->ReplaceInput(load_constant, input_index);
167 }
168
169 void HandleInvoke(HInvoke* invoke) {
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000170 // If this is an invoke-static/-direct with PC-relative dex cache array
171 // addressing, we need the PC-relative address base.
172 HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect();
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000173 // We can't add a pointer to the constant area if we already have a current
174 // method pointer. This may arise when sharpening doesn't remove the current
175 // method pointer from the invoke.
176 if (invoke_static_or_direct != nullptr &&
177 invoke_static_or_direct->HasCurrentMethodInput()) {
178 DCHECK(!invoke_static_or_direct->HasPcRelativeDexCache());
179 return;
180 }
181
182 bool base_added = false;
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000183 if (invoke_static_or_direct != nullptr && invoke_static_or_direct->HasPcRelativeDexCache()) {
Vladimir Markofb337ea2015-11-25 15:25:10 +0000184 InitializePCRelativeBasePointer();
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000185 // Add the extra parameter base_.
Vladimir Markoc53c0792015-11-19 15:48:33 +0000186 invoke_static_or_direct->AddSpecialInput(base_);
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000187 base_added = true;
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000188 }
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000189
Mark Mendell94991072015-10-06 14:58:32 -0400190 // Ensure that we can load FP arguments from the constant area.
191 for (size_t i = 0, e = invoke->InputCount(); i < e; i++) {
192 HConstant* input = invoke->InputAt(i)->AsConstant();
193 if (input != nullptr && Primitive::IsFloatingPointType(input->GetType())) {
194 ReplaceInput(invoke, input, i, true);
195 }
196 }
Mark P Mendell2f10a5f2016-01-25 14:47:50 +0000197
198 // These intrinsics need the constant area.
199 switch (invoke->GetIntrinsic()) {
200 case Intrinsics::kMathAbsDouble:
201 case Intrinsics::kMathAbsFloat:
202 case Intrinsics::kMathMaxDoubleDouble:
203 case Intrinsics::kMathMaxFloatFloat:
204 case Intrinsics::kMathMinDoubleDouble:
205 case Intrinsics::kMathMinFloatFloat:
206 if (!base_added) {
207 DCHECK(invoke_static_or_direct != nullptr);
208 DCHECK(!invoke_static_or_direct->HasCurrentMethodInput());
209 InitializePCRelativeBasePointer();
210 invoke_static_or_direct->AddSpecialInput(base_);
211 }
212 break;
213 default:
214 break;
215 }
Mark Mendell94991072015-10-06 14:58:32 -0400216 }
217
218 // The generated HX86ComputeBaseMethodAddress in the entry block needed as an
219 // input to the HX86LoadFromConstantTable instructions.
220 HX86ComputeBaseMethodAddress* base_;
221};
222
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000223void PcRelativeFixups::Run() {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000224 if (graph_->HasIrreducibleLoops()) {
225 // Do not run this optimization, as irreducible loops do not work with an instruction
226 // that can be live-in at the irreducible loop header.
227 return;
228 }
Vladimir Marko0f7dca42015-11-02 14:36:43 +0000229 PCRelativeHandlerVisitor visitor(graph_);
Mark Mendell94991072015-10-06 14:58:32 -0400230 visitor.VisitInsertionOrder();
Vladimir Markofb337ea2015-11-25 15:25:10 +0000231 visitor.MoveBaseIfNeeded();
Mark Mendell94991072015-10-06 14:58:32 -0400232}
233
234} // namespace x86
235} // namespace art