• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 "pc_relative_fixups_mips.h"
18 #include "code_generator_mips.h"
19 #include "intrinsics_mips.h"
20 
21 namespace art {
22 namespace mips {
23 
24 /**
25  * Finds instructions that need the constant area base as an input.
26  */
27 class PCRelativeHandlerVisitor : public HGraphVisitor {
28  public:
PCRelativeHandlerVisitor(HGraph * graph,CodeGenerator * codegen)29   PCRelativeHandlerVisitor(HGraph* graph, CodeGenerator* codegen)
30       : HGraphVisitor(graph),
31         codegen_(down_cast<CodeGeneratorMIPS*>(codegen)),
32         base_(nullptr) {}
33 
MoveBaseIfNeeded()34   void MoveBaseIfNeeded() {
35     if (base_ != nullptr) {
36       // Bring the base closer to the first use (previously, it was in the
37       // entry block) and relieve some pressure on the register allocator
38       // while avoiding recalculation of the base in a loop.
39       base_->MoveBeforeFirstUserAndOutOfLoops();
40       // Computing the base for PC-relative literals will clobber RA with
41       // the NAL instruction on R2. Take a note of this before generating
42       // the method entry.
43       codegen_->ClobberRA();
44     }
45   }
46 
47  private:
InitializePCRelativeBasePointer()48   void InitializePCRelativeBasePointer() {
49     // Ensure we only initialize the pointer once.
50     if (base_ != nullptr) {
51       return;
52     }
53     // Insert the base at the start of the entry block, move it to a better
54     // position later in MoveBaseIfNeeded().
55     base_ = new (GetGraph()->GetArena()) HMipsComputeBaseMethodAddress();
56     HBasicBlock* entry_block = GetGraph()->GetEntryBlock();
57     entry_block->InsertInstructionBefore(base_, entry_block->GetFirstInstruction());
58     DCHECK(base_ != nullptr);
59   }
60 
VisitLoadClass(HLoadClass * load_class)61   void VisitLoadClass(HLoadClass* load_class) OVERRIDE {
62     HLoadClass::LoadKind load_kind = load_class->GetLoadKind();
63     switch (load_kind) {
64       case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
65       case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
66       case HLoadClass::LoadKind::kBootImageAddress:
67       case HLoadClass::LoadKind::kBssEntry:
68         // Add a base register for PC-relative literals on R2.
69         InitializePCRelativeBasePointer();
70         load_class->AddSpecialInput(base_);
71         break;
72       default:
73         break;
74     }
75   }
76 
VisitLoadString(HLoadString * load_string)77   void VisitLoadString(HLoadString* load_string) OVERRIDE {
78     HLoadString::LoadKind load_kind = load_string->GetLoadKind();
79     switch (load_kind) {
80       case HLoadString::LoadKind::kBootImageLinkTimeAddress:
81       case HLoadString::LoadKind::kBootImageAddress:
82       case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
83       case HLoadString::LoadKind::kBssEntry:
84         // Add a base register for PC-relative literals on R2.
85         InitializePCRelativeBasePointer();
86         load_string->AddSpecialInput(base_);
87         break;
88       default:
89         break;
90     }
91   }
92 
VisitPackedSwitch(HPackedSwitch * switch_insn)93   void VisitPackedSwitch(HPackedSwitch* switch_insn) OVERRIDE {
94     if (switch_insn->GetNumEntries() <=
95         InstructionCodeGeneratorMIPS::kPackedSwitchJumpTableThreshold) {
96       return;
97     }
98     // We need to replace the HPackedSwitch with a HMipsPackedSwitch in order to
99     // address the constant area.
100     InitializePCRelativeBasePointer();
101     HGraph* graph = GetGraph();
102     HBasicBlock* block = switch_insn->GetBlock();
103     HMipsPackedSwitch* mips_switch = new (graph->GetArena()) HMipsPackedSwitch(
104         switch_insn->GetStartValue(),
105         switch_insn->GetNumEntries(),
106         switch_insn->InputAt(0),
107         base_,
108         switch_insn->GetDexPc());
109     block->ReplaceAndRemoveInstructionWith(switch_insn, mips_switch);
110   }
111 
112   CodeGeneratorMIPS* codegen_;
113 
114   // The generated HMipsComputeBaseMethodAddress in the entry block needed as an
115   // input to the HMipsLoadFromConstantTable instructions.
116   HMipsComputeBaseMethodAddress* base_;
117 };
118 
Run()119 void PcRelativeFixups::Run() {
120   CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen_);
121   if (mips_codegen->GetInstructionSetFeatures().IsR6()) {
122     // Do nothing for R6 because it has PC-relative addressing.
123     return;
124   }
125   if (graph_->HasIrreducibleLoops()) {
126     // Do not run this optimization, as irreducible loops do not work with an instruction
127     // that can be live-in at the irreducible loop header.
128     return;
129   }
130   PCRelativeHandlerVisitor visitor(graph_, codegen_);
131   visitor.VisitInsertionOrder();
132   visitor.MoveBaseIfNeeded();
133 }
134 
135 }  // namespace mips
136 }  // namespace art
137