blob: f569aa858c8b68472e2c2564ff6a3f55c1f5e4d1 [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);
jeffhao7fbee072012-08-24 17:56:54 -0700159
160 void Lb(Register rt, Register rs, uint16_t imm16);
161 void Lh(Register rt, Register rs, uint16_t imm16);
162 void Lw(Register rt, Register rs, uint16_t imm16);
163 void Lbu(Register rt, Register rs, uint16_t imm16);
164 void Lhu(Register rt, Register rs, uint16_t imm16);
165 void Lui(Register rt, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200166 void Sync(uint32_t stype);
167 void Mfhi(Register rd); // R2
168 void Mflo(Register rd); // R2
jeffhao7fbee072012-08-24 17:56:54 -0700169
170 void Sb(Register rt, Register rs, uint16_t imm16);
171 void Sh(Register rt, Register rs, uint16_t imm16);
172 void Sw(Register rt, Register rs, uint16_t imm16);
173
174 void Slt(Register rd, Register rs, Register rt);
175 void Sltu(Register rd, Register rs, Register rt);
176 void Slti(Register rt, Register rs, uint16_t imm16);
177 void Sltiu(Register rt, Register rs, uint16_t imm16);
178
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200179 void B(uint16_t imm16);
180 void Beq(Register rs, Register rt, uint16_t imm16);
181 void Bne(Register rs, Register rt, uint16_t imm16);
182 void Beqz(Register rt, uint16_t imm16);
183 void Bnez(Register rt, uint16_t imm16);
184 void Bltz(Register rt, uint16_t imm16);
185 void Bgez(Register rt, uint16_t imm16);
186 void Blez(Register rt, uint16_t imm16);
187 void Bgtz(Register rt, uint16_t imm16);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800188 void Bc1f(int cc, uint16_t imm16); // R2
189 void Bc1t(int cc, uint16_t imm16); // R2
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200190 void J(uint32_t addr26);
191 void Jal(uint32_t addr26);
192 void Jalr(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700193 void Jalr(Register rs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200194 void Jr(Register rs);
195 void Nal();
196 void Auipc(Register rs, uint16_t imm16); // R6
197 void Addiupc(Register rs, uint32_t imm19); // R6
198 void Bc(uint32_t imm26); // R6
199 void Jic(Register rt, uint16_t imm16); // R6
200 void Jialc(Register rt, uint16_t imm16); // R6
201 void Bltc(Register rs, Register rt, uint16_t imm16); // R6
202 void Bltzc(Register rt, uint16_t imm16); // R6
203 void Bgtzc(Register rt, uint16_t imm16); // R6
204 void Bgec(Register rs, Register rt, uint16_t imm16); // R6
205 void Bgezc(Register rt, uint16_t imm16); // R6
206 void Blezc(Register rt, uint16_t imm16); // R6
207 void Bltuc(Register rs, Register rt, uint16_t imm16); // R6
208 void Bgeuc(Register rs, Register rt, uint16_t imm16); // R6
209 void Beqc(Register rs, Register rt, uint16_t imm16); // R6
210 void Bnec(Register rs, Register rt, uint16_t imm16); // R6
211 void Beqzc(Register rs, uint32_t imm21); // R6
212 void Bnezc(Register rs, uint32_t imm21); // R6
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800213 void Bc1eqz(FRegister ft, uint16_t imm16); // R6
214 void Bc1nez(FRegister ft, uint16_t imm16); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700215
216 void AddS(FRegister fd, FRegister fs, FRegister ft);
217 void SubS(FRegister fd, FRegister fs, FRegister ft);
218 void MulS(FRegister fd, FRegister fs, FRegister ft);
219 void DivS(FRegister fd, FRegister fs, FRegister ft);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200220 void AddD(FRegister fd, FRegister fs, FRegister ft);
221 void SubD(FRegister fd, FRegister fs, FRegister ft);
222 void MulD(FRegister fd, FRegister fs, FRegister ft);
223 void DivD(FRegister fd, FRegister fs, FRegister ft);
jeffhao7fbee072012-08-24 17:56:54 -0700224 void MovS(FRegister fd, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200225 void MovD(FRegister fd, FRegister fs);
226 void NegS(FRegister fd, FRegister fs);
227 void NegD(FRegister fd, FRegister fs);
228
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800229 void CunS(int cc, FRegister fs, FRegister ft); // R2
230 void CeqS(int cc, FRegister fs, FRegister ft); // R2
231 void CueqS(int cc, FRegister fs, FRegister ft); // R2
232 void ColtS(int cc, FRegister fs, FRegister ft); // R2
233 void CultS(int cc, FRegister fs, FRegister ft); // R2
234 void ColeS(int cc, FRegister fs, FRegister ft); // R2
235 void CuleS(int cc, FRegister fs, FRegister ft); // R2
236 void CunD(int cc, FRegister fs, FRegister ft); // R2
237 void CeqD(int cc, FRegister fs, FRegister ft); // R2
238 void CueqD(int cc, FRegister fs, FRegister ft); // R2
239 void ColtD(int cc, FRegister fs, FRegister ft); // R2
240 void CultD(int cc, FRegister fs, FRegister ft); // R2
241 void ColeD(int cc, FRegister fs, FRegister ft); // R2
242 void CuleD(int cc, FRegister fs, FRegister ft); // R2
243 void CmpUnS(FRegister fd, FRegister fs, FRegister ft); // R6
244 void CmpEqS(FRegister fd, FRegister fs, FRegister ft); // R6
245 void CmpUeqS(FRegister fd, FRegister fs, FRegister ft); // R6
246 void CmpLtS(FRegister fd, FRegister fs, FRegister ft); // R6
247 void CmpUltS(FRegister fd, FRegister fs, FRegister ft); // R6
248 void CmpLeS(FRegister fd, FRegister fs, FRegister ft); // R6
249 void CmpUleS(FRegister fd, FRegister fs, FRegister ft); // R6
250 void CmpOrS(FRegister fd, FRegister fs, FRegister ft); // R6
251 void CmpUneS(FRegister fd, FRegister fs, FRegister ft); // R6
252 void CmpNeS(FRegister fd, FRegister fs, FRegister ft); // R6
253 void CmpUnD(FRegister fd, FRegister fs, FRegister ft); // R6
254 void CmpEqD(FRegister fd, FRegister fs, FRegister ft); // R6
255 void CmpUeqD(FRegister fd, FRegister fs, FRegister ft); // R6
256 void CmpLtD(FRegister fd, FRegister fs, FRegister ft); // R6
257 void CmpUltD(FRegister fd, FRegister fs, FRegister ft); // R6
258 void CmpLeD(FRegister fd, FRegister fs, FRegister ft); // R6
259 void CmpUleD(FRegister fd, FRegister fs, FRegister ft); // R6
260 void CmpOrD(FRegister fd, FRegister fs, FRegister ft); // R6
261 void CmpUneD(FRegister fd, FRegister fs, FRegister ft); // R6
262 void CmpNeD(FRegister fd, FRegister fs, FRegister ft); // R6
263 void Movf(Register rd, Register rs, int cc); // R2
264 void Movt(Register rd, Register rs, int cc); // R2
265
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200266 void Cvtsw(FRegister fd, FRegister fs);
267 void Cvtdw(FRegister fd, FRegister fs);
268 void Cvtsd(FRegister fd, FRegister fs);
269 void Cvtds(FRegister fd, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700270
271 void Mfc1(Register rt, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200272 void Mtc1(Register rt, FRegister fs);
273 void Mfhc1(Register rt, FRegister fs);
274 void Mthc1(Register rt, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700275 void Lwc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200276 void Ldc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700277 void Swc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200278 void Sdc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700279
280 void Break();
jeffhao07030602012-09-26 14:33:14 -0700281 void Nop();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200282 void Move(Register rd, Register rs);
283 void Clear(Register rd);
284 void Not(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700285
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200286 // Higher level composite instructions.
287 void LoadConst32(Register rd, int32_t value);
288 void LoadConst64(Register reg_hi, Register reg_lo, int64_t value);
289 void LoadDConst64(FRegister rd, int64_t value, Register temp);
290 void LoadSConst32(FRegister r, int32_t value, Register temp);
291 void StoreConst32ToOffset(int32_t value, Register base, int32_t offset, Register temp);
292 void StoreConst64ToOffset(int64_t value, Register base, int32_t offset, Register temp);
293 void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT);
294
295 // These will generate R2 branches or R6 branches as appropriate.
296 void Bind(MipsLabel* label);
297 void B(MipsLabel* label);
298 void Jalr(MipsLabel* label, Register indirect_reg);
299 void Beq(Register rs, Register rt, MipsLabel* label);
300 void Bne(Register rs, Register rt, MipsLabel* label);
301 void Beqz(Register rt, MipsLabel* label);
302 void Bnez(Register rt, MipsLabel* label);
303 void Bltz(Register rt, MipsLabel* label);
304 void Bgez(Register rt, MipsLabel* label);
305 void Blez(Register rt, MipsLabel* label);
306 void Bgtz(Register rt, MipsLabel* label);
307 void Blt(Register rs, Register rt, MipsLabel* label);
308 void Bge(Register rs, Register rt, MipsLabel* label);
309 void Bltu(Register rs, Register rt, MipsLabel* label);
310 void Bgeu(Register rs, Register rt, MipsLabel* label);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800311 void Bc1f(int cc, MipsLabel* label); // R2
312 void Bc1t(int cc, MipsLabel* label); // R2
313 void Bc1eqz(FRegister ft, MipsLabel* label); // R6
314 void Bc1nez(FRegister ft, MipsLabel* label); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700315
316 void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size);
317 void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset);
318 void LoadSFromOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200319 void LoadDFromOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700320 void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset);
Goran Jakovljevicff734982015-08-24 12:58:55 +0000321 void StoreSToOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200322 void StoreDToOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700323
jeffhao7fbee072012-08-24 17:56:54 -0700324 // Emit data (e.g. encoded instruction or immediate) to the instruction stream.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200325 void Emit(uint32_t value);
326
327 // Push/pop composite routines.
328 void Push(Register rs);
329 void Pop(Register rd);
330 void PopAndReturn(Register rd, Register rt);
jeffhao7fbee072012-08-24 17:56:54 -0700331
Andreas Gampe85b62f22015-09-09 13:15:38 -0700332 void Bind(Label* label) OVERRIDE {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200333 Bind(down_cast<MipsLabel*>(label));
Andreas Gampe85b62f22015-09-09 13:15:38 -0700334 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200335 void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
336 UNIMPLEMENTED(FATAL) << "Do not use Jump for MIPS";
Andreas Gampe85b62f22015-09-09 13:15:38 -0700337 }
338
jeffhao7fbee072012-08-24 17:56:54 -0700339 //
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200340 // Overridden common assembler high-level functionality.
jeffhao7fbee072012-08-24 17:56:54 -0700341 //
342
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200343 // Emit code that will create an activation on the stack.
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800344 void BuildFrame(size_t frame_size,
345 ManagedRegister method_reg,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700346 const std::vector<ManagedRegister>& callee_save_regs,
347 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700348
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200349 // Emit code that will remove an activation from the stack.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700350 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
351 OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700352
Ian Rogersdd7624d2014-03-14 17:43:00 -0700353 void IncreaseFrameSize(size_t adjust) OVERRIDE;
354 void DecreaseFrameSize(size_t adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700355
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200356 // Store routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700357 void Store(FrameOffset offs, ManagedRegister msrc, size_t size) OVERRIDE;
358 void StoreRef(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
359 void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700360
Ian Rogersdd7624d2014-03-14 17:43:00 -0700361 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700362
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800363 void StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest,
364 uint32_t imm,
365 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700366
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800367 void StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs,
368 FrameOffset fr_offs,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700369 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700370
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800371 void StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700372
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800373 void StoreSpanning(FrameOffset dest,
374 ManagedRegister msrc,
375 FrameOffset in_off,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700376 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700377
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200378 // Load routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700379 void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700380
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800381 void LoadFromThread32(ManagedRegister mdest,
382 ThreadOffset<kMipsWordSize> src,
383 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700384
Mathieu Chartiere401d142015-04-22 13:56:20 -0700385 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700386
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800387 void LoadRef(ManagedRegister mdest,
388 ManagedRegister base,
389 MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100390 bool unpoison_reference) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700391
Ian Rogersdd7624d2014-03-14 17:43:00 -0700392 void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700393
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800394 void LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset<kMipsWordSize> offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700395
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200396 // Copying routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700397 void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700398
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800399 void CopyRawPtrFromThread32(FrameOffset fr_offs,
400 ThreadOffset<kMipsWordSize> thr_offs,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700401 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700402
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800403 void CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs,
404 FrameOffset fr_offs,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700405 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700406
Ian Rogersdd7624d2014-03-14 17:43:00 -0700407 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700408
Ian Rogersdd7624d2014-03-14 17:43:00 -0700409 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700410
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800411 void Copy(FrameOffset dest,
412 ManagedRegister src_base,
413 Offset src_offset,
414 ManagedRegister mscratch,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700415 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700416
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800417 void Copy(ManagedRegister dest_base,
418 Offset dest_offset,
419 FrameOffset src,
420 ManagedRegister mscratch,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700421 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700422
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800423 void Copy(FrameOffset dest,
424 FrameOffset src_base,
425 Offset src_offset,
426 ManagedRegister mscratch,
427 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700428
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800429 void Copy(ManagedRegister dest,
430 Offset dest_offset,
431 ManagedRegister src,
432 Offset src_offset,
433 ManagedRegister mscratch,
434 size_t size) OVERRIDE;
435
436 void Copy(FrameOffset dest,
437 Offset dest_offset,
438 FrameOffset src,
439 Offset src_offset,
440 ManagedRegister mscratch,
441 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700442
Ian Rogersdd7624d2014-03-14 17:43:00 -0700443 void MemoryBarrier(ManagedRegister) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700444
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200445 // Sign extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700446 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700447
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200448 // Zero extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700449 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700450
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200451 // Exploit fast access in managed code to Thread::Current().
Ian Rogersdd7624d2014-03-14 17:43:00 -0700452 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
453 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700454
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700455 // Set up out_reg to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700456 // value is null and null_allowed. in_reg holds a possibly stale reference
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700457 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700458 // null.
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800459 void CreateHandleScopeEntry(ManagedRegister out_reg,
460 FrameOffset handlescope_offset,
461 ManagedRegister in_reg,
462 bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700463
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700464 // Set up out_off to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700465 // value is null and null_allowed.
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800466 void CreateHandleScopeEntry(FrameOffset out_off,
467 FrameOffset handlescope_offset,
468 ManagedRegister mscratch,
469 bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700470
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200471 // src holds a handle scope entry (Object**) load this into dst.
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700472 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700473
474 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
475 // know that src may not be null.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700476 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
477 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700478
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200479 // Call to address held at [base+offset].
Ian Rogersdd7624d2014-03-14 17:43:00 -0700480 void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
481 void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800482 void CallFromThread32(ThreadOffset<kMipsWordSize> offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700483
jeffhao7fbee072012-08-24 17:56:54 -0700484 // Generate code to check if Thread::Current()->exception_ is non-null
485 // and branch to a ExceptionSlowPath if it is.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700486 void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700487
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200488 // Emit slow paths queued during assembly and promote short branches to long if needed.
489 void FinalizeCode() OVERRIDE;
490
491 // Emit branches and finalize all instructions.
492 void FinalizeInstructions(const MemoryRegion& region);
493
494 // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS,
495 // must be used instead of MipsLabel::GetPosition()).
496 uint32_t GetLabelLocation(MipsLabel* label) const;
497
498 // Get the final position of a label after local fixup based on the old position
499 // recorded before FinalizeCode().
500 uint32_t GetAdjustedPosition(uint32_t old_position);
501
502 enum BranchCondition {
503 kCondLT,
504 kCondGE,
505 kCondLE,
506 kCondGT,
507 kCondLTZ,
508 kCondGEZ,
509 kCondLEZ,
510 kCondGTZ,
511 kCondEQ,
512 kCondNE,
513 kCondEQZ,
514 kCondNEZ,
515 kCondLTU,
516 kCondGEU,
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800517 kCondF, // Floating-point predicate false.
518 kCondT, // Floating-point predicate true.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200519 kUncond,
520 };
521 friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs);
522
jeffhao7fbee072012-08-24 17:56:54 -0700523 private:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200524 class Branch {
525 public:
526 enum Type {
527 // R2 short branches.
528 kUncondBranch,
529 kCondBranch,
530 kCall,
531 // R2 long branches.
532 kLongUncondBranch,
533 kLongCondBranch,
534 kLongCall,
535 // R6 short branches.
536 kR6UncondBranch,
537 kR6CondBranch,
538 kR6Call,
539 // R6 long branches.
540 kR6LongUncondBranch,
541 kR6LongCondBranch,
542 kR6LongCall,
543 };
544 // Bit sizes of offsets defined as enums to minimize chance of typos.
545 enum OffsetBits {
546 kOffset16 = 16,
547 kOffset18 = 18,
548 kOffset21 = 21,
549 kOffset23 = 23,
550 kOffset28 = 28,
551 kOffset32 = 32,
552 };
553
554 static constexpr uint32_t kUnresolved = 0xffffffff; // Unresolved target_
555 static constexpr int32_t kMaxBranchLength = 32;
556 static constexpr int32_t kMaxBranchSize = kMaxBranchLength * sizeof(uint32_t);
557
558 struct BranchInfo {
559 // Branch length as a number of 4-byte-long instructions.
560 uint32_t length;
561 // Ordinal number (0-based) of the first (or the only) instruction that contains the branch's
562 // PC-relative offset (or its most significant 16-bit half, which goes first).
563 uint32_t instr_offset;
564 // Different MIPS instructions with PC-relative offsets apply said offsets to slightly
565 // different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte
566 // instructions) from the instruction containing the offset.
567 uint32_t pc_org;
568 // How large (in bits) a PC-relative offset can be for a given type of branch (kR6CondBranch
569 // is an exception: use kOffset23 for beqzc/bnezc).
570 OffsetBits offset_size;
571 // Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift
572 // count.
573 int offset_shift;
574 };
575 static const BranchInfo branch_info_[/* Type */];
576
577 // Unconditional branch.
578 Branch(bool is_r6, uint32_t location, uint32_t target);
579 // Conditional branch.
580 Branch(bool is_r6,
581 uint32_t location,
582 uint32_t target,
583 BranchCondition condition,
584 Register lhs_reg,
585 Register rhs_reg = ZERO);
586 // Call (branch and link) that stores the target address in a given register (i.e. T9).
587 Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg);
588
589 // Some conditional branches with lhs = rhs are effectively NOPs, while some
590 // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs.
591 // So, we need a way to identify such branches in order to emit no instructions for them
592 // or change them to unconditional.
593 static bool IsNop(BranchCondition condition, Register lhs, Register rhs);
594 static bool IsUncond(BranchCondition condition, Register lhs, Register rhs);
595
596 static BranchCondition OppositeCondition(BranchCondition cond);
597
598 Type GetType() const;
599 BranchCondition GetCondition() const;
600 Register GetLeftRegister() const;
601 Register GetRightRegister() const;
602 uint32_t GetTarget() const;
603 uint32_t GetLocation() const;
604 uint32_t GetOldLocation() const;
605 uint32_t GetLength() const;
606 uint32_t GetOldLength() const;
607 uint32_t GetSize() const;
608 uint32_t GetOldSize() const;
609 uint32_t GetEndLocation() const;
610 uint32_t GetOldEndLocation() const;
611 bool IsLong() const;
612 bool IsResolved() const;
613
614 // Returns the bit size of the signed offset that the branch instruction can handle.
615 OffsetBits GetOffsetSize() const;
616
617 // Calculates the distance between two byte locations in the assembler buffer and
618 // returns the number of bits needed to represent the distance as a signed integer.
619 //
620 // Branch instructions have signed offsets of 16, 19 (addiupc), 21 (beqzc/bnezc),
621 // and 26 (bc) bits, which are additionally shifted left 2 positions at run time.
622 //
623 // Composite branches (made of several instructions) with longer reach have 32-bit
624 // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first).
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800625 // The composite branches cover the range of PC + +/-2GB on MIPS32 CPUs. However,
626 // the range is not end-to-end on MIPS64 (unless addresses are forced to zero- or
627 // sign-extend from 32 to 64 bits by the appropriate CPU configuration).
628 // Consider the following implementation of a long unconditional branch, for
629 // example:
630 //
631 // auipc at, offset_31_16 // at = pc + sign_extend(offset_31_16) << 16
632 // jic at, offset_15_0 // pc = at + sign_extend(offset_15_0)
633 //
634 // Both of the above instructions take 16-bit signed offsets as immediate operands.
635 // When bit 15 of offset_15_0 is 1, it effectively causes subtraction of 0x10000
636 // due to sign extension. This must be compensated for by incrementing offset_31_16
637 // by 1. offset_31_16 can only be incremented by 1 if it's not 0x7FFF. If it is
638 // 0x7FFF, adding 1 will overflow the positive offset into the negative range.
639 // Therefore, the long branch range is something like from PC - 0x80000000 to
640 // PC + 0x7FFF7FFF, IOW, shorter by 32KB on one side.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200641 //
642 // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special
643 // case with the addiu instruction and a 16 bit offset.
644 static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target);
645
646 // Resolve a branch when the target is known.
647 void Resolve(uint32_t target);
648
649 // Relocate a branch by a given delta if needed due to expansion of this or another
650 // branch at a given location by this delta (just changes location_ and target_).
651 void Relocate(uint32_t expand_location, uint32_t delta);
652
653 // If the branch is short, changes its type to long.
654 void PromoteToLong();
655
656 // If necessary, updates the type by promoting a short branch to a long branch
657 // based on the branch location and target. Returns the amount (in bytes) by
658 // which the branch size has increased.
659 // max_short_distance caps the maximum distance between location_ and target_
660 // that is allowed for short branches. This is for debugging/testing purposes.
661 // max_short_distance = 0 forces all short branches to become long.
662 // Use the implicit default argument when not debugging/testing.
663 uint32_t PromoteIfNeeded(uint32_t max_short_distance = std::numeric_limits<uint32_t>::max());
664
665 // Returns the location of the instruction(s) containing the offset.
666 uint32_t GetOffsetLocation() const;
667
668 // Calculates and returns the offset ready for encoding in the branch instruction(s).
669 uint32_t GetOffset() const;
670
671 private:
672 // Completes branch construction by determining and recording its type.
673 void InitializeType(bool is_call, bool is_r6);
674 // Helper for the above.
675 void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
676
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800677 uint32_t old_location_; // Offset into assembler buffer in bytes.
678 uint32_t location_; // Offset into assembler buffer in bytes.
679 uint32_t target_; // Offset into assembler buffer in bytes.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200680
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800681 uint32_t lhs_reg_; // Left-hand side register in conditional branches or
682 // indirect call register.
683 uint32_t rhs_reg_; // Right-hand side register in conditional branches.
684 BranchCondition condition_; // Condition for conditional branches.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200685
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800686 Type type_; // Current type of the branch.
687 Type old_type_; // Initial type of the branch.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200688 };
689 friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs);
690 friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs);
691
jeffhao7fbee072012-08-24 17:56:54 -0700692 void EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct);
693 void EmitI(int opcode, Register rs, Register rt, uint16_t imm);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200694 void EmitI21(int opcode, Register rs, uint32_t imm21);
695 void EmitI26(int opcode, uint32_t imm26);
jeffhao7fbee072012-08-24 17:56:54 -0700696 void EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct);
697 void EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800698 void EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16);
699 void EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21);
jeffhao7fbee072012-08-24 17:56:54 -0700700
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200701 void Buncond(MipsLabel* label);
702 void Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs = ZERO);
703 void Call(MipsLabel* label, Register indirect_reg);
704 void FinalizeLabeledBranch(MipsLabel* label);
jeffhao7fbee072012-08-24 17:56:54 -0700705
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200706 Branch* GetBranch(uint32_t branch_id);
707 const Branch* GetBranch(uint32_t branch_id) const;
708
709 void PromoteBranches();
710 void EmitBranch(Branch* branch);
711 void EmitBranches();
Vladimir Marko10ef6942015-10-22 15:25:54 +0100712 void PatchCFI(size_t number_of_delayed_adjust_pcs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200713
714 // Emits exception block.
715 void EmitExceptionPoll(MipsExceptionSlowPath* exception);
716
717 bool IsR6() const {
718 if (isa_features_ != nullptr) {
719 return isa_features_->IsR6();
720 } else {
721 return false;
722 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000723 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200724
725 bool Is32BitFPU() const {
726 if (isa_features_ != nullptr) {
727 return isa_features_->Is32BitFloatingPoint();
728 } else {
729 return true;
730 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000731 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200732
733 // List of exception blocks to generate at the end of the code cache.
734 std::vector<MipsExceptionSlowPath> exception_blocks_;
735
736 std::vector<Branch> branches_;
737
738 // Whether appending instructions at the end of the buffer or overwriting the existing ones.
739 bool overwriting_;
740 // The current overwrite location.
741 uint32_t overwrite_location_;
742
743 // Data for AdjustedPosition(), see the description there.
744 uint32_t last_position_adjustment_;
745 uint32_t last_old_position_;
746 uint32_t last_branch_id_;
747
748 const MipsInstructionSetFeatures* isa_features_;
Goran Jakovljevicff734982015-08-24 12:58:55 +0000749
jeffhao7fbee072012-08-24 17:56:54 -0700750 DISALLOW_COPY_AND_ASSIGN(MipsAssembler);
751};
752
jeffhao7fbee072012-08-24 17:56:54 -0700753} // namespace mips
754} // namespace art
755
Ian Rogers166db042013-07-26 12:05:57 -0700756#endif // ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_