blob: 01c6490f88252e71ec3cad5ae7eba9df6b506651 [file] [log] [blame]
jeffhao7fbee072012-08-24 17:56:54 -07001/*
2 * Copyright (C) 2011 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
Ian Rogers166db042013-07-26 12:05:57 -070017#ifndef ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_
18#define ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_
jeffhao7fbee072012-08-24 17:56:54 -070019
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020020#include <utility>
jeffhao7fbee072012-08-24 17:56:54 -070021#include <vector>
Elliott Hughes76160052012-12-12 16:31:20 -080022
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020023#include "arch/mips/instruction_set_features_mips.h"
Elliott Hughes76160052012-12-12 16:31:20 -080024#include "base/macros.h"
jeffhao7fbee072012-08-24 17:56:54 -070025#include "constants_mips.h"
26#include "globals.h"
27#include "managed_register_mips.h"
jeffhao7fbee072012-08-24 17:56:54 -070028#include "offsets.h"
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020029#include "utils/assembler.h"
30#include "utils/label.h"
jeffhao7fbee072012-08-24 17:56:54 -070031
32namespace art {
33namespace mips {
jeffhao7fbee072012-08-24 17:56:54 -070034
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020035static constexpr size_t kMipsWordSize = 4;
36static constexpr size_t kMipsDoublewordSize = 8;
37
jeffhao7fbee072012-08-24 17:56:54 -070038enum LoadOperandType {
39 kLoadSignedByte,
40 kLoadUnsignedByte,
41 kLoadSignedHalfword,
42 kLoadUnsignedHalfword,
43 kLoadWord,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020044 kLoadDoubleword
jeffhao7fbee072012-08-24 17:56:54 -070045};
46
47enum StoreOperandType {
48 kStoreByte,
49 kStoreHalfword,
50 kStoreWord,
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020051 kStoreDoubleword
52};
53
54class MipsLabel : public Label {
55 public:
56 MipsLabel() : prev_branch_id_plus_one_(0) {}
57
58 MipsLabel(MipsLabel&& src)
59 : Label(std::move(src)), prev_branch_id_plus_one_(src.prev_branch_id_plus_one_) {}
60
61 private:
62 uint32_t prev_branch_id_plus_one_; // To get distance from preceding branch, if any.
63
64 friend class MipsAssembler;
65 DISALLOW_COPY_AND_ASSIGN(MipsLabel);
66};
67
68// Slowpath entered when Thread::Current()->_exception is non-null.
69class MipsExceptionSlowPath {
70 public:
71 explicit MipsExceptionSlowPath(MipsManagedRegister scratch, size_t stack_adjust)
72 : scratch_(scratch), stack_adjust_(stack_adjust) {}
73
74 MipsExceptionSlowPath(MipsExceptionSlowPath&& src)
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -080075 : scratch_(src.scratch_),
76 stack_adjust_(src.stack_adjust_),
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020077 exception_entry_(std::move(src.exception_entry_)) {}
78
79 private:
80 MipsLabel* Entry() { return &exception_entry_; }
81 const MipsManagedRegister scratch_;
82 const size_t stack_adjust_;
83 MipsLabel exception_entry_;
84
85 friend class MipsAssembler;
86 DISALLOW_COPY_AND_ASSIGN(MipsExceptionSlowPath);
jeffhao7fbee072012-08-24 17:56:54 -070087};
88
Ian Rogersdd7624d2014-03-14 17:43:00 -070089class MipsAssembler FINAL : public Assembler {
jeffhao7fbee072012-08-24 17:56:54 -070090 public:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +020091 explicit MipsAssembler(const MipsInstructionSetFeatures* instruction_set_features = nullptr)
92 : overwriting_(false),
93 overwrite_location_(0),
94 last_position_adjustment_(0),
95 last_old_position_(0),
96 last_branch_id_(0),
Vladimir Marko10ef6942015-10-22 15:25:54 +010097 isa_features_(instruction_set_features) {
98 cfi().DelayEmittingAdvancePCs();
99 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200100
101 virtual ~MipsAssembler() {
102 for (auto& branch : branches_) {
103 CHECK(branch.IsResolved());
104 }
105 }
jeffhao7fbee072012-08-24 17:56:54 -0700106
107 // Emit Machine Instructions.
jeffhao7fbee072012-08-24 17:56:54 -0700108 void Addu(Register rd, Register rs, Register rt);
jeffhao7fbee072012-08-24 17:56:54 -0700109 void Addiu(Register rt, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700110 void Subu(Register rd, Register rs, Register rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200111
112 void MultR2(Register rs, Register rt); // R2
113 void MultuR2(Register rs, Register rt); // R2
114 void DivR2(Register rs, Register rt); // R2
115 void DivuR2(Register rs, Register rt); // R2
116 void MulR2(Register rd, Register rs, Register rt); // R2
117 void DivR2(Register rd, Register rs, Register rt); // R2
118 void ModR2(Register rd, Register rs, Register rt); // R2
119 void DivuR2(Register rd, Register rs, Register rt); // R2
120 void ModuR2(Register rd, Register rs, Register rt); // R2
121 void MulR6(Register rd, Register rs, Register rt); // R6
Alexey Frunze7e99e052015-11-24 19:28:01 -0800122 void MuhR6(Register rd, Register rs, Register rt); // R6
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200123 void MuhuR6(Register rd, Register rs, Register rt); // R6
124 void DivR6(Register rd, Register rs, Register rt); // R6
125 void ModR6(Register rd, Register rs, Register rt); // R6
126 void DivuR6(Register rd, Register rs, Register rt); // R6
127 void ModuR6(Register rd, Register rs, Register rt); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700128
129 void And(Register rd, Register rs, Register rt);
130 void Andi(Register rt, Register rs, uint16_t imm16);
131 void Or(Register rd, Register rs, Register rt);
132 void Ori(Register rt, Register rs, uint16_t imm16);
133 void Xor(Register rd, Register rs, Register rt);
134 void Xori(Register rt, Register rs, uint16_t imm16);
135 void Nor(Register rd, Register rs, Register rt);
136
Chris Larsene3845472015-11-18 12:27:15 -0800137 void Movz(Register rd, Register rs, Register rt); // R2
138 void Movn(Register rd, Register rs, Register rt); // R2
139 void Seleqz(Register rd, Register rs, Register rt); // R6
140 void Selnez(Register rd, Register rs, Register rt); // R6
141 void ClzR6(Register rd, Register rs);
142 void ClzR2(Register rd, Register rs);
143 void CloR6(Register rd, Register rs);
144 void CloR2(Register rd, Register rs);
145
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200146 void Seb(Register rd, Register rt); // R2+
147 void Seh(Register rd, Register rt); // R2+
Chris Larsen3f8bf652015-10-28 10:08:56 -0700148 void Wsbh(Register rd, Register rt); // R2+
Chris Larsen70014c82015-11-18 12:26:08 -0800149 void Bitswap(Register rd, Register rt); // R6
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200150
151 void Sll(Register rd, Register rt, int shamt);
152 void Srl(Register rd, Register rt, int shamt);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700153 void Rotr(Register rd, Register rt, int shamt); // R2+
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200154 void Sra(Register rd, Register rt, int shamt);
155 void Sllv(Register rd, Register rt, Register rs);
156 void Srlv(Register rd, Register rt, Register rs);
Chris Larsene16ce5a2015-11-18 12:30:20 -0800157 void Rotrv(Register rd, Register rt, Register rs); // R2+
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200158 void Srav(Register rd, Register rt, Register rs);
Alexey Frunze5c7aed32015-11-25 19:41:54 -0800159 void Ext(Register rd, Register rt, int pos, int size); // R2+
160 void Ins(Register rd, Register rt, int pos, int size); // R2+
jeffhao7fbee072012-08-24 17:56:54 -0700161
162 void Lb(Register rt, Register rs, uint16_t imm16);
163 void Lh(Register rt, Register rs, uint16_t imm16);
164 void Lw(Register rt, Register rs, uint16_t imm16);
165 void Lbu(Register rt, Register rs, uint16_t imm16);
166 void Lhu(Register rt, Register rs, uint16_t imm16);
167 void Lui(Register rt, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200168 void Sync(uint32_t stype);
169 void Mfhi(Register rd); // R2
170 void Mflo(Register rd); // R2
jeffhao7fbee072012-08-24 17:56:54 -0700171
172 void Sb(Register rt, Register rs, uint16_t imm16);
173 void Sh(Register rt, Register rs, uint16_t imm16);
174 void Sw(Register rt, Register rs, uint16_t imm16);
175
176 void Slt(Register rd, Register rs, Register rt);
177 void Sltu(Register rd, Register rs, Register rt);
178 void Slti(Register rt, Register rs, uint16_t imm16);
179 void Sltiu(Register rt, Register rs, uint16_t imm16);
180
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200181 void B(uint16_t imm16);
182 void Beq(Register rs, Register rt, uint16_t imm16);
183 void Bne(Register rs, Register rt, uint16_t imm16);
184 void Beqz(Register rt, uint16_t imm16);
185 void Bnez(Register rt, uint16_t imm16);
186 void Bltz(Register rt, uint16_t imm16);
187 void Bgez(Register rt, uint16_t imm16);
188 void Blez(Register rt, uint16_t imm16);
189 void Bgtz(Register rt, uint16_t imm16);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800190 void Bc1f(int cc, uint16_t imm16); // R2
191 void Bc1t(int cc, uint16_t imm16); // R2
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200192 void J(uint32_t addr26);
193 void Jal(uint32_t addr26);
194 void Jalr(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700195 void Jalr(Register rs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200196 void Jr(Register rs);
197 void Nal();
198 void Auipc(Register rs, uint16_t imm16); // R6
199 void Addiupc(Register rs, uint32_t imm19); // R6
200 void Bc(uint32_t imm26); // R6
201 void Jic(Register rt, uint16_t imm16); // R6
202 void Jialc(Register rt, uint16_t imm16); // R6
203 void Bltc(Register rs, Register rt, uint16_t imm16); // R6
204 void Bltzc(Register rt, uint16_t imm16); // R6
205 void Bgtzc(Register rt, uint16_t imm16); // R6
206 void Bgec(Register rs, Register rt, uint16_t imm16); // R6
207 void Bgezc(Register rt, uint16_t imm16); // R6
208 void Blezc(Register rt, uint16_t imm16); // R6
209 void Bltuc(Register rs, Register rt, uint16_t imm16); // R6
210 void Bgeuc(Register rs, Register rt, uint16_t imm16); // R6
211 void Beqc(Register rs, Register rt, uint16_t imm16); // R6
212 void Bnec(Register rs, Register rt, uint16_t imm16); // R6
213 void Beqzc(Register rs, uint32_t imm21); // R6
214 void Bnezc(Register rs, uint32_t imm21); // R6
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800215 void Bc1eqz(FRegister ft, uint16_t imm16); // R6
216 void Bc1nez(FRegister ft, uint16_t imm16); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700217
218 void AddS(FRegister fd, FRegister fs, FRegister ft);
219 void SubS(FRegister fd, FRegister fs, FRegister ft);
220 void MulS(FRegister fd, FRegister fs, FRegister ft);
221 void DivS(FRegister fd, FRegister fs, FRegister ft);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200222 void AddD(FRegister fd, FRegister fs, FRegister ft);
223 void SubD(FRegister fd, FRegister fs, FRegister ft);
224 void MulD(FRegister fd, FRegister fs, FRegister ft);
225 void DivD(FRegister fd, FRegister fs, FRegister ft);
jeffhao7fbee072012-08-24 17:56:54 -0700226 void MovS(FRegister fd, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200227 void MovD(FRegister fd, FRegister fs);
228 void NegS(FRegister fd, FRegister fs);
229 void NegD(FRegister fd, FRegister fs);
230
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800231 void CunS(int cc, FRegister fs, FRegister ft); // R2
232 void CeqS(int cc, FRegister fs, FRegister ft); // R2
233 void CueqS(int cc, FRegister fs, FRegister ft); // R2
234 void ColtS(int cc, FRegister fs, FRegister ft); // R2
235 void CultS(int cc, FRegister fs, FRegister ft); // R2
236 void ColeS(int cc, FRegister fs, FRegister ft); // R2
237 void CuleS(int cc, FRegister fs, FRegister ft); // R2
238 void CunD(int cc, FRegister fs, FRegister ft); // R2
239 void CeqD(int cc, FRegister fs, FRegister ft); // R2
240 void CueqD(int cc, FRegister fs, FRegister ft); // R2
241 void ColtD(int cc, FRegister fs, FRegister ft); // R2
242 void CultD(int cc, FRegister fs, FRegister ft); // R2
243 void ColeD(int cc, FRegister fs, FRegister ft); // R2
244 void CuleD(int cc, FRegister fs, FRegister ft); // R2
245 void CmpUnS(FRegister fd, FRegister fs, FRegister ft); // R6
246 void CmpEqS(FRegister fd, FRegister fs, FRegister ft); // R6
247 void CmpUeqS(FRegister fd, FRegister fs, FRegister ft); // R6
248 void CmpLtS(FRegister fd, FRegister fs, FRegister ft); // R6
249 void CmpUltS(FRegister fd, FRegister fs, FRegister ft); // R6
250 void CmpLeS(FRegister fd, FRegister fs, FRegister ft); // R6
251 void CmpUleS(FRegister fd, FRegister fs, FRegister ft); // R6
252 void CmpOrS(FRegister fd, FRegister fs, FRegister ft); // R6
253 void CmpUneS(FRegister fd, FRegister fs, FRegister ft); // R6
254 void CmpNeS(FRegister fd, FRegister fs, FRegister ft); // R6
255 void CmpUnD(FRegister fd, FRegister fs, FRegister ft); // R6
256 void CmpEqD(FRegister fd, FRegister fs, FRegister ft); // R6
257 void CmpUeqD(FRegister fd, FRegister fs, FRegister ft); // R6
258 void CmpLtD(FRegister fd, FRegister fs, FRegister ft); // R6
259 void CmpUltD(FRegister fd, FRegister fs, FRegister ft); // R6
260 void CmpLeD(FRegister fd, FRegister fs, FRegister ft); // R6
261 void CmpUleD(FRegister fd, FRegister fs, FRegister ft); // R6
262 void CmpOrD(FRegister fd, FRegister fs, FRegister ft); // R6
263 void CmpUneD(FRegister fd, FRegister fs, FRegister ft); // R6
264 void CmpNeD(FRegister fd, FRegister fs, FRegister ft); // R6
265 void Movf(Register rd, Register rs, int cc); // R2
266 void Movt(Register rd, Register rs, int cc); // R2
267
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800268 void TruncLS(FRegister fd, FRegister fs); // R2+, FR=1
269 void TruncLD(FRegister fd, FRegister fs); // R2+, FR=1
270 void TruncWS(FRegister fd, FRegister fs);
271 void TruncWD(FRegister fd, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200272 void Cvtsw(FRegister fd, FRegister fs);
273 void Cvtdw(FRegister fd, FRegister fs);
274 void Cvtsd(FRegister fd, FRegister fs);
275 void Cvtds(FRegister fd, FRegister fs);
Alexey Frunzebaf60b72015-12-22 15:15:03 -0800276 void Cvtsl(FRegister fd, FRegister fs); // R2+, FR=1
277 void Cvtdl(FRegister fd, FRegister fs); // R2+, FR=1
jeffhao7fbee072012-08-24 17:56:54 -0700278
279 void Mfc1(Register rt, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200280 void Mtc1(Register rt, FRegister fs);
281 void Mfhc1(Register rt, FRegister fs);
282 void Mthc1(Register rt, FRegister fs);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800283 void MoveFromFpuHigh(Register rt, FRegister fs);
284 void MoveToFpuHigh(Register rt, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700285 void Lwc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200286 void Ldc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700287 void Swc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200288 void Sdc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700289
290 void Break();
jeffhao07030602012-09-26 14:33:14 -0700291 void Nop();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200292 void Move(Register rd, Register rs);
293 void Clear(Register rd);
294 void Not(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700295
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200296 // Higher level composite instructions.
297 void LoadConst32(Register rd, int32_t value);
298 void LoadConst64(Register reg_hi, Register reg_lo, int64_t value);
299 void LoadDConst64(FRegister rd, int64_t value, Register temp);
300 void LoadSConst32(FRegister r, int32_t value, Register temp);
301 void StoreConst32ToOffset(int32_t value, Register base, int32_t offset, Register temp);
302 void StoreConst64ToOffset(int64_t value, Register base, int32_t offset, Register temp);
303 void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT);
304
305 // These will generate R2 branches or R6 branches as appropriate.
306 void Bind(MipsLabel* label);
307 void B(MipsLabel* label);
308 void Jalr(MipsLabel* label, Register indirect_reg);
309 void Beq(Register rs, Register rt, MipsLabel* label);
310 void Bne(Register rs, Register rt, MipsLabel* label);
311 void Beqz(Register rt, MipsLabel* label);
312 void Bnez(Register rt, MipsLabel* label);
313 void Bltz(Register rt, MipsLabel* label);
314 void Bgez(Register rt, MipsLabel* label);
315 void Blez(Register rt, MipsLabel* label);
316 void Bgtz(Register rt, MipsLabel* label);
317 void Blt(Register rs, Register rt, MipsLabel* label);
318 void Bge(Register rs, Register rt, MipsLabel* label);
319 void Bltu(Register rs, Register rt, MipsLabel* label);
320 void Bgeu(Register rs, Register rt, MipsLabel* label);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800321 void Bc1f(int cc, MipsLabel* label); // R2
322 void Bc1t(int cc, MipsLabel* label); // R2
323 void Bc1eqz(FRegister ft, MipsLabel* label); // R6
324 void Bc1nez(FRegister ft, MipsLabel* label); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700325
326 void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size);
327 void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset);
328 void LoadSFromOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200329 void LoadDFromOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700330 void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset);
Goran Jakovljevicff734982015-08-24 12:58:55 +0000331 void StoreSToOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200332 void StoreDToOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700333
jeffhao7fbee072012-08-24 17:56:54 -0700334 // Emit data (e.g. encoded instruction or immediate) to the instruction stream.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200335 void Emit(uint32_t value);
336
337 // Push/pop composite routines.
338 void Push(Register rs);
339 void Pop(Register rd);
340 void PopAndReturn(Register rd, Register rt);
jeffhao7fbee072012-08-24 17:56:54 -0700341
Andreas Gampe85b62f22015-09-09 13:15:38 -0700342 void Bind(Label* label) OVERRIDE {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200343 Bind(down_cast<MipsLabel*>(label));
Andreas Gampe85b62f22015-09-09 13:15:38 -0700344 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200345 void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
346 UNIMPLEMENTED(FATAL) << "Do not use Jump for MIPS";
Andreas Gampe85b62f22015-09-09 13:15:38 -0700347 }
348
jeffhao7fbee072012-08-24 17:56:54 -0700349 //
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200350 // Overridden common assembler high-level functionality.
jeffhao7fbee072012-08-24 17:56:54 -0700351 //
352
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200353 // Emit code that will create an activation on the stack.
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800354 void BuildFrame(size_t frame_size,
355 ManagedRegister method_reg,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700356 const std::vector<ManagedRegister>& callee_save_regs,
357 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700358
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200359 // Emit code that will remove an activation from the stack.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700360 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
361 OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700362
Ian Rogersdd7624d2014-03-14 17:43:00 -0700363 void IncreaseFrameSize(size_t adjust) OVERRIDE;
364 void DecreaseFrameSize(size_t adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700365
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200366 // Store routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700367 void Store(FrameOffset offs, ManagedRegister msrc, size_t size) OVERRIDE;
368 void StoreRef(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
369 void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700370
Ian Rogersdd7624d2014-03-14 17:43:00 -0700371 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700372
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800373 void StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest,
374 uint32_t imm,
375 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700376
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800377 void StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs,
378 FrameOffset fr_offs,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700379 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700380
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800381 void StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700382
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800383 void StoreSpanning(FrameOffset dest,
384 ManagedRegister msrc,
385 FrameOffset in_off,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700386 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700387
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200388 // Load routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700389 void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700390
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800391 void LoadFromThread32(ManagedRegister mdest,
392 ThreadOffset<kMipsWordSize> src,
393 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700394
Mathieu Chartiere401d142015-04-22 13:56:20 -0700395 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700396
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800397 void LoadRef(ManagedRegister mdest,
398 ManagedRegister base,
399 MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100400 bool unpoison_reference) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700401
Ian Rogersdd7624d2014-03-14 17:43:00 -0700402 void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700403
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800404 void LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset<kMipsWordSize> offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700405
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200406 // Copying routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700407 void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700408
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800409 void CopyRawPtrFromThread32(FrameOffset fr_offs,
410 ThreadOffset<kMipsWordSize> thr_offs,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700411 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700412
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800413 void CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs,
414 FrameOffset fr_offs,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700415 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700416
Ian Rogersdd7624d2014-03-14 17:43:00 -0700417 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700418
Ian Rogersdd7624d2014-03-14 17:43:00 -0700419 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700420
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800421 void Copy(FrameOffset dest,
422 ManagedRegister src_base,
423 Offset src_offset,
424 ManagedRegister mscratch,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700425 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700426
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800427 void Copy(ManagedRegister dest_base,
428 Offset dest_offset,
429 FrameOffset src,
430 ManagedRegister mscratch,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700431 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700432
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800433 void Copy(FrameOffset dest,
434 FrameOffset src_base,
435 Offset src_offset,
436 ManagedRegister mscratch,
437 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700438
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800439 void Copy(ManagedRegister dest,
440 Offset dest_offset,
441 ManagedRegister src,
442 Offset src_offset,
443 ManagedRegister mscratch,
444 size_t size) OVERRIDE;
445
446 void Copy(FrameOffset dest,
447 Offset dest_offset,
448 FrameOffset src,
449 Offset src_offset,
450 ManagedRegister mscratch,
451 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700452
Ian Rogersdd7624d2014-03-14 17:43:00 -0700453 void MemoryBarrier(ManagedRegister) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700454
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200455 // Sign extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700456 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700457
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200458 // Zero extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700459 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700460
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200461 // Exploit fast access in managed code to Thread::Current().
Ian Rogersdd7624d2014-03-14 17:43:00 -0700462 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
463 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700464
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700465 // Set up out_reg to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700466 // value is null and null_allowed. in_reg holds a possibly stale reference
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700467 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700468 // null.
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800469 void CreateHandleScopeEntry(ManagedRegister out_reg,
470 FrameOffset handlescope_offset,
471 ManagedRegister in_reg,
472 bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700473
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700474 // Set up out_off to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700475 // value is null and null_allowed.
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800476 void CreateHandleScopeEntry(FrameOffset out_off,
477 FrameOffset handlescope_offset,
478 ManagedRegister mscratch,
479 bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700480
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200481 // src holds a handle scope entry (Object**) load this into dst.
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700482 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700483
484 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
485 // know that src may not be null.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700486 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
487 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700488
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200489 // Call to address held at [base+offset].
Ian Rogersdd7624d2014-03-14 17:43:00 -0700490 void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
491 void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800492 void CallFromThread32(ThreadOffset<kMipsWordSize> offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700493
jeffhao7fbee072012-08-24 17:56:54 -0700494 // Generate code to check if Thread::Current()->exception_ is non-null
495 // and branch to a ExceptionSlowPath if it is.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700496 void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700497
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200498 // Emit slow paths queued during assembly and promote short branches to long if needed.
499 void FinalizeCode() OVERRIDE;
500
501 // Emit branches and finalize all instructions.
502 void FinalizeInstructions(const MemoryRegion& region);
503
504 // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS,
505 // must be used instead of MipsLabel::GetPosition()).
506 uint32_t GetLabelLocation(MipsLabel* label) const;
507
508 // Get the final position of a label after local fixup based on the old position
509 // recorded before FinalizeCode().
510 uint32_t GetAdjustedPosition(uint32_t old_position);
511
512 enum BranchCondition {
513 kCondLT,
514 kCondGE,
515 kCondLE,
516 kCondGT,
517 kCondLTZ,
518 kCondGEZ,
519 kCondLEZ,
520 kCondGTZ,
521 kCondEQ,
522 kCondNE,
523 kCondEQZ,
524 kCondNEZ,
525 kCondLTU,
526 kCondGEU,
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800527 kCondF, // Floating-point predicate false.
528 kCondT, // Floating-point predicate true.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200529 kUncond,
530 };
531 friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs);
532
jeffhao7fbee072012-08-24 17:56:54 -0700533 private:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200534 class Branch {
535 public:
536 enum Type {
537 // R2 short branches.
538 kUncondBranch,
539 kCondBranch,
540 kCall,
541 // R2 long branches.
542 kLongUncondBranch,
543 kLongCondBranch,
544 kLongCall,
545 // R6 short branches.
546 kR6UncondBranch,
547 kR6CondBranch,
548 kR6Call,
549 // R6 long branches.
550 kR6LongUncondBranch,
551 kR6LongCondBranch,
552 kR6LongCall,
553 };
554 // Bit sizes of offsets defined as enums to minimize chance of typos.
555 enum OffsetBits {
556 kOffset16 = 16,
557 kOffset18 = 18,
558 kOffset21 = 21,
559 kOffset23 = 23,
560 kOffset28 = 28,
561 kOffset32 = 32,
562 };
563
564 static constexpr uint32_t kUnresolved = 0xffffffff; // Unresolved target_
565 static constexpr int32_t kMaxBranchLength = 32;
566 static constexpr int32_t kMaxBranchSize = kMaxBranchLength * sizeof(uint32_t);
567
568 struct BranchInfo {
569 // Branch length as a number of 4-byte-long instructions.
570 uint32_t length;
571 // Ordinal number (0-based) of the first (or the only) instruction that contains the branch's
572 // PC-relative offset (or its most significant 16-bit half, which goes first).
573 uint32_t instr_offset;
574 // Different MIPS instructions with PC-relative offsets apply said offsets to slightly
575 // different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte
576 // instructions) from the instruction containing the offset.
577 uint32_t pc_org;
578 // How large (in bits) a PC-relative offset can be for a given type of branch (kR6CondBranch
579 // is an exception: use kOffset23 for beqzc/bnezc).
580 OffsetBits offset_size;
581 // Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift
582 // count.
583 int offset_shift;
584 };
585 static const BranchInfo branch_info_[/* Type */];
586
587 // Unconditional branch.
588 Branch(bool is_r6, uint32_t location, uint32_t target);
589 // Conditional branch.
590 Branch(bool is_r6,
591 uint32_t location,
592 uint32_t target,
593 BranchCondition condition,
594 Register lhs_reg,
595 Register rhs_reg = ZERO);
596 // Call (branch and link) that stores the target address in a given register (i.e. T9).
597 Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg);
598
599 // Some conditional branches with lhs = rhs are effectively NOPs, while some
600 // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs.
601 // So, we need a way to identify such branches in order to emit no instructions for them
602 // or change them to unconditional.
603 static bool IsNop(BranchCondition condition, Register lhs, Register rhs);
604 static bool IsUncond(BranchCondition condition, Register lhs, Register rhs);
605
606 static BranchCondition OppositeCondition(BranchCondition cond);
607
608 Type GetType() const;
609 BranchCondition GetCondition() const;
610 Register GetLeftRegister() const;
611 Register GetRightRegister() const;
612 uint32_t GetTarget() const;
613 uint32_t GetLocation() const;
614 uint32_t GetOldLocation() const;
615 uint32_t GetLength() const;
616 uint32_t GetOldLength() const;
617 uint32_t GetSize() const;
618 uint32_t GetOldSize() const;
619 uint32_t GetEndLocation() const;
620 uint32_t GetOldEndLocation() const;
621 bool IsLong() const;
622 bool IsResolved() const;
623
624 // Returns the bit size of the signed offset that the branch instruction can handle.
625 OffsetBits GetOffsetSize() const;
626
627 // Calculates the distance between two byte locations in the assembler buffer and
628 // returns the number of bits needed to represent the distance as a signed integer.
629 //
630 // Branch instructions have signed offsets of 16, 19 (addiupc), 21 (beqzc/bnezc),
631 // and 26 (bc) bits, which are additionally shifted left 2 positions at run time.
632 //
633 // Composite branches (made of several instructions) with longer reach have 32-bit
634 // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first).
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800635 // The composite branches cover the range of PC + +/-2GB on MIPS32 CPUs. However,
636 // the range is not end-to-end on MIPS64 (unless addresses are forced to zero- or
637 // sign-extend from 32 to 64 bits by the appropriate CPU configuration).
638 // Consider the following implementation of a long unconditional branch, for
639 // example:
640 //
641 // auipc at, offset_31_16 // at = pc + sign_extend(offset_31_16) << 16
642 // jic at, offset_15_0 // pc = at + sign_extend(offset_15_0)
643 //
644 // Both of the above instructions take 16-bit signed offsets as immediate operands.
645 // When bit 15 of offset_15_0 is 1, it effectively causes subtraction of 0x10000
646 // due to sign extension. This must be compensated for by incrementing offset_31_16
647 // by 1. offset_31_16 can only be incremented by 1 if it's not 0x7FFF. If it is
648 // 0x7FFF, adding 1 will overflow the positive offset into the negative range.
649 // Therefore, the long branch range is something like from PC - 0x80000000 to
650 // PC + 0x7FFF7FFF, IOW, shorter by 32KB on one side.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200651 //
652 // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special
653 // case with the addiu instruction and a 16 bit offset.
654 static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target);
655
656 // Resolve a branch when the target is known.
657 void Resolve(uint32_t target);
658
659 // Relocate a branch by a given delta if needed due to expansion of this or another
660 // branch at a given location by this delta (just changes location_ and target_).
661 void Relocate(uint32_t expand_location, uint32_t delta);
662
663 // If the branch is short, changes its type to long.
664 void PromoteToLong();
665
666 // If necessary, updates the type by promoting a short branch to a long branch
667 // based on the branch location and target. Returns the amount (in bytes) by
668 // which the branch size has increased.
669 // max_short_distance caps the maximum distance between location_ and target_
670 // that is allowed for short branches. This is for debugging/testing purposes.
671 // max_short_distance = 0 forces all short branches to become long.
672 // Use the implicit default argument when not debugging/testing.
673 uint32_t PromoteIfNeeded(uint32_t max_short_distance = std::numeric_limits<uint32_t>::max());
674
675 // Returns the location of the instruction(s) containing the offset.
676 uint32_t GetOffsetLocation() const;
677
678 // Calculates and returns the offset ready for encoding in the branch instruction(s).
679 uint32_t GetOffset() const;
680
681 private:
682 // Completes branch construction by determining and recording its type.
683 void InitializeType(bool is_call, bool is_r6);
684 // Helper for the above.
685 void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
686
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800687 uint32_t old_location_; // Offset into assembler buffer in bytes.
688 uint32_t location_; // Offset into assembler buffer in bytes.
689 uint32_t target_; // Offset into assembler buffer in bytes.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200690
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800691 uint32_t lhs_reg_; // Left-hand side register in conditional branches or
692 // indirect call register.
693 uint32_t rhs_reg_; // Right-hand side register in conditional branches.
694 BranchCondition condition_; // Condition for conditional branches.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200695
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800696 Type type_; // Current type of the branch.
697 Type old_type_; // Initial type of the branch.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200698 };
699 friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs);
700 friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs);
701
jeffhao7fbee072012-08-24 17:56:54 -0700702 void EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct);
703 void EmitI(int opcode, Register rs, Register rt, uint16_t imm);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200704 void EmitI21(int opcode, Register rs, uint32_t imm21);
705 void EmitI26(int opcode, uint32_t imm26);
jeffhao7fbee072012-08-24 17:56:54 -0700706 void EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct);
707 void EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800708 void EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16);
709 void EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21);
jeffhao7fbee072012-08-24 17:56:54 -0700710
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200711 void Buncond(MipsLabel* label);
712 void Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs = ZERO);
713 void Call(MipsLabel* label, Register indirect_reg);
714 void FinalizeLabeledBranch(MipsLabel* label);
jeffhao7fbee072012-08-24 17:56:54 -0700715
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200716 Branch* GetBranch(uint32_t branch_id);
717 const Branch* GetBranch(uint32_t branch_id) const;
718
719 void PromoteBranches();
720 void EmitBranch(Branch* branch);
721 void EmitBranches();
Vladimir Marko10ef6942015-10-22 15:25:54 +0100722 void PatchCFI(size_t number_of_delayed_adjust_pcs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200723
724 // Emits exception block.
725 void EmitExceptionPoll(MipsExceptionSlowPath* exception);
726
727 bool IsR6() const {
728 if (isa_features_ != nullptr) {
729 return isa_features_->IsR6();
730 } else {
731 return false;
732 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000733 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200734
735 bool Is32BitFPU() const {
736 if (isa_features_ != nullptr) {
737 return isa_features_->Is32BitFloatingPoint();
738 } else {
739 return true;
740 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000741 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200742
743 // List of exception blocks to generate at the end of the code cache.
744 std::vector<MipsExceptionSlowPath> exception_blocks_;
745
746 std::vector<Branch> branches_;
747
748 // Whether appending instructions at the end of the buffer or overwriting the existing ones.
749 bool overwriting_;
750 // The current overwrite location.
751 uint32_t overwrite_location_;
752
753 // Data for AdjustedPosition(), see the description there.
754 uint32_t last_position_adjustment_;
755 uint32_t last_old_position_;
756 uint32_t last_branch_id_;
757
758 const MipsInstructionSetFeatures* isa_features_;
Goran Jakovljevicff734982015-08-24 12:58:55 +0000759
jeffhao7fbee072012-08-24 17:56:54 -0700760 DISALLOW_COPY_AND_ASSIGN(MipsAssembler);
761};
762
jeffhao7fbee072012-08-24 17:56:54 -0700763} // namespace mips
764} // namespace art
765
Ian Rogers166db042013-07-26 12:05:57 -0700766#endif // ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_