blob: d50b4f698ecec7d164cb7756b0bb41489c02e419 [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)
75 : scratch_(std::move(src.scratch_)),
76 stack_adjust_(std::move(src.stack_adjust_)),
77 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
122 void MuhuR6(Register rd, Register rs, Register rt); // R6
123 void DivR6(Register rd, Register rs, Register rt); // R6
124 void ModR6(Register rd, Register rs, Register rt); // R6
125 void DivuR6(Register rd, Register rs, Register rt); // R6
126 void ModuR6(Register rd, Register rs, Register rt); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700127
128 void And(Register rd, Register rs, Register rt);
129 void Andi(Register rt, Register rs, uint16_t imm16);
130 void Or(Register rd, Register rs, Register rt);
131 void Ori(Register rt, Register rs, uint16_t imm16);
132 void Xor(Register rd, Register rs, Register rt);
133 void Xori(Register rt, Register rs, uint16_t imm16);
134 void Nor(Register rd, Register rs, Register rt);
135
Chris Larsene3845472015-11-18 12:27:15 -0800136 void Movz(Register rd, Register rs, Register rt); // R2
137 void Movn(Register rd, Register rs, Register rt); // R2
138 void Seleqz(Register rd, Register rs, Register rt); // R6
139 void Selnez(Register rd, Register rs, Register rt); // R6
140 void ClzR6(Register rd, Register rs);
141 void ClzR2(Register rd, Register rs);
142 void CloR6(Register rd, Register rs);
143 void CloR2(Register rd, Register rs);
144
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200145 void Seb(Register rd, Register rt); // R2+
146 void Seh(Register rd, Register rt); // R2+
Chris Larsen3f8bf652015-10-28 10:08:56 -0700147 void Wsbh(Register rd, Register rt); // R2+
Chris Larsen70014c82015-11-18 12:26:08 -0800148 void Bitswap(Register rd, Register rt); // R6
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200149
150 void Sll(Register rd, Register rt, int shamt);
151 void Srl(Register rd, Register rt, int shamt);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700152 void Rotr(Register rd, Register rt, int shamt); // R2+
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200153 void Sra(Register rd, Register rt, int shamt);
154 void Sllv(Register rd, Register rt, Register rs);
155 void Srlv(Register rd, Register rt, Register rs);
Chris Larsene16ce5a2015-11-18 12:30:20 -0800156 void Rotrv(Register rd, Register rt, Register rs); // R2+
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200157 void Srav(Register rd, Register rt, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700158
159 void Lb(Register rt, Register rs, uint16_t imm16);
160 void Lh(Register rt, Register rs, uint16_t imm16);
161 void Lw(Register rt, Register rs, uint16_t imm16);
162 void Lbu(Register rt, Register rs, uint16_t imm16);
163 void Lhu(Register rt, Register rs, uint16_t imm16);
164 void Lui(Register rt, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200165 void Sync(uint32_t stype);
166 void Mfhi(Register rd); // R2
167 void Mflo(Register rd); // R2
jeffhao7fbee072012-08-24 17:56:54 -0700168
169 void Sb(Register rt, Register rs, uint16_t imm16);
170 void Sh(Register rt, Register rs, uint16_t imm16);
171 void Sw(Register rt, Register rs, uint16_t imm16);
172
173 void Slt(Register rd, Register rs, Register rt);
174 void Sltu(Register rd, Register rs, Register rt);
175 void Slti(Register rt, Register rs, uint16_t imm16);
176 void Sltiu(Register rt, Register rs, uint16_t imm16);
177
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200178 void B(uint16_t imm16);
179 void Beq(Register rs, Register rt, uint16_t imm16);
180 void Bne(Register rs, Register rt, uint16_t imm16);
181 void Beqz(Register rt, uint16_t imm16);
182 void Bnez(Register rt, uint16_t imm16);
183 void Bltz(Register rt, uint16_t imm16);
184 void Bgez(Register rt, uint16_t imm16);
185 void Blez(Register rt, uint16_t imm16);
186 void Bgtz(Register rt, uint16_t imm16);
187 void J(uint32_t addr26);
188 void Jal(uint32_t addr26);
189 void Jalr(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700190 void Jalr(Register rs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200191 void Jr(Register rs);
192 void Nal();
193 void Auipc(Register rs, uint16_t imm16); // R6
194 void Addiupc(Register rs, uint32_t imm19); // R6
195 void Bc(uint32_t imm26); // R6
196 void Jic(Register rt, uint16_t imm16); // R6
197 void Jialc(Register rt, uint16_t imm16); // R6
198 void Bltc(Register rs, Register rt, uint16_t imm16); // R6
199 void Bltzc(Register rt, uint16_t imm16); // R6
200 void Bgtzc(Register rt, uint16_t imm16); // R6
201 void Bgec(Register rs, Register rt, uint16_t imm16); // R6
202 void Bgezc(Register rt, uint16_t imm16); // R6
203 void Blezc(Register rt, uint16_t imm16); // R6
204 void Bltuc(Register rs, Register rt, uint16_t imm16); // R6
205 void Bgeuc(Register rs, Register rt, uint16_t imm16); // R6
206 void Beqc(Register rs, Register rt, uint16_t imm16); // R6
207 void Bnec(Register rs, Register rt, uint16_t imm16); // R6
208 void Beqzc(Register rs, uint32_t imm21); // R6
209 void Bnezc(Register rs, uint32_t imm21); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700210
211 void AddS(FRegister fd, FRegister fs, FRegister ft);
212 void SubS(FRegister fd, FRegister fs, FRegister ft);
213 void MulS(FRegister fd, FRegister fs, FRegister ft);
214 void DivS(FRegister fd, FRegister fs, FRegister ft);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200215 void AddD(FRegister fd, FRegister fs, FRegister ft);
216 void SubD(FRegister fd, FRegister fs, FRegister ft);
217 void MulD(FRegister fd, FRegister fs, FRegister ft);
218 void DivD(FRegister fd, FRegister fs, FRegister ft);
jeffhao7fbee072012-08-24 17:56:54 -0700219 void MovS(FRegister fd, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200220 void MovD(FRegister fd, FRegister fs);
221 void NegS(FRegister fd, FRegister fs);
222 void NegD(FRegister fd, FRegister fs);
223
224 void Cvtsw(FRegister fd, FRegister fs);
225 void Cvtdw(FRegister fd, FRegister fs);
226 void Cvtsd(FRegister fd, FRegister fs);
227 void Cvtds(FRegister fd, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700228
229 void Mfc1(Register rt, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200230 void Mtc1(Register rt, FRegister fs);
231 void Mfhc1(Register rt, FRegister fs);
232 void Mthc1(Register rt, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700233 void Lwc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200234 void Ldc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700235 void Swc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200236 void Sdc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700237
238 void Break();
jeffhao07030602012-09-26 14:33:14 -0700239 void Nop();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200240 void Move(Register rd, Register rs);
241 void Clear(Register rd);
242 void Not(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700243
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200244 // Higher level composite instructions.
245 void LoadConst32(Register rd, int32_t value);
246 void LoadConst64(Register reg_hi, Register reg_lo, int64_t value);
247 void LoadDConst64(FRegister rd, int64_t value, Register temp);
248 void LoadSConst32(FRegister r, int32_t value, Register temp);
249 void StoreConst32ToOffset(int32_t value, Register base, int32_t offset, Register temp);
250 void StoreConst64ToOffset(int64_t value, Register base, int32_t offset, Register temp);
251 void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT);
252
253 // These will generate R2 branches or R6 branches as appropriate.
254 void Bind(MipsLabel* label);
255 void B(MipsLabel* label);
256 void Jalr(MipsLabel* label, Register indirect_reg);
257 void Beq(Register rs, Register rt, MipsLabel* label);
258 void Bne(Register rs, Register rt, MipsLabel* label);
259 void Beqz(Register rt, MipsLabel* label);
260 void Bnez(Register rt, MipsLabel* label);
261 void Bltz(Register rt, MipsLabel* label);
262 void Bgez(Register rt, MipsLabel* label);
263 void Blez(Register rt, MipsLabel* label);
264 void Bgtz(Register rt, MipsLabel* label);
265 void Blt(Register rs, Register rt, MipsLabel* label);
266 void Bge(Register rs, Register rt, MipsLabel* label);
267 void Bltu(Register rs, Register rt, MipsLabel* label);
268 void Bgeu(Register rs, Register rt, MipsLabel* label);
jeffhao7fbee072012-08-24 17:56:54 -0700269
270 void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size);
271 void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset);
272 void LoadSFromOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200273 void LoadDFromOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700274 void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset);
Goran Jakovljevicff734982015-08-24 12:58:55 +0000275 void StoreSToOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200276 void StoreDToOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700277
jeffhao7fbee072012-08-24 17:56:54 -0700278 // Emit data (e.g. encoded instruction or immediate) to the instruction stream.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200279 void Emit(uint32_t value);
280
281 // Push/pop composite routines.
282 void Push(Register rs);
283 void Pop(Register rd);
284 void PopAndReturn(Register rd, Register rt);
jeffhao7fbee072012-08-24 17:56:54 -0700285
Andreas Gampe85b62f22015-09-09 13:15:38 -0700286 void Bind(Label* label) OVERRIDE {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200287 Bind(down_cast<MipsLabel*>(label));
Andreas Gampe85b62f22015-09-09 13:15:38 -0700288 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200289 void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
290 UNIMPLEMENTED(FATAL) << "Do not use Jump for MIPS";
Andreas Gampe85b62f22015-09-09 13:15:38 -0700291 }
292
jeffhao7fbee072012-08-24 17:56:54 -0700293 //
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200294 // Overridden common assembler high-level functionality.
jeffhao7fbee072012-08-24 17:56:54 -0700295 //
296
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200297 // Emit code that will create an activation on the stack.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700298 void BuildFrame(size_t frame_size, ManagedRegister method_reg,
299 const std::vector<ManagedRegister>& callee_save_regs,
300 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700301
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200302 // Emit code that will remove an activation from the stack.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700303 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
304 OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700305
Ian Rogersdd7624d2014-03-14 17:43:00 -0700306 void IncreaseFrameSize(size_t adjust) OVERRIDE;
307 void DecreaseFrameSize(size_t adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700308
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200309 // Store routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700310 void Store(FrameOffset offs, ManagedRegister msrc, size_t size) OVERRIDE;
311 void StoreRef(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
312 void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700313
Ian Rogersdd7624d2014-03-14 17:43:00 -0700314 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700315
Ian Rogersdd7624d2014-03-14 17:43:00 -0700316 void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister mscratch)
317 OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700318
Ian Rogersdd7624d2014-03-14 17:43:00 -0700319 void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
320 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700321
Ian Rogersdd7624d2014-03-14 17:43:00 -0700322 void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700323
Ian Rogersdd7624d2014-03-14 17:43:00 -0700324 void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off,
325 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700326
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200327 // Load routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700328 void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700329
Ian Rogersdd7624d2014-03-14 17:43:00 -0700330 void LoadFromThread32(ManagedRegister mdest, ThreadOffset<4> src, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700331
Mathieu Chartiere401d142015-04-22 13:56:20 -0700332 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700333
Mathieu Chartiere401d142015-04-22 13:56:20 -0700334 void LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100335 bool unpoison_reference) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700336
Ian Rogersdd7624d2014-03-14 17:43:00 -0700337 void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700338
Ian Rogersdd7624d2014-03-14 17:43:00 -0700339 void LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset<4> offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700340
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200341 // Copying routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700342 void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700343
Ian Rogersdd7624d2014-03-14 17:43:00 -0700344 void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
345 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700346
Ian Rogersdd7624d2014-03-14 17:43:00 -0700347 void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
348 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700349
Ian Rogersdd7624d2014-03-14 17:43:00 -0700350 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700351
Ian Rogersdd7624d2014-03-14 17:43:00 -0700352 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700353
Ian Rogersdd7624d2014-03-14 17:43:00 -0700354 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister mscratch,
355 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700356
Ian Rogersdd7624d2014-03-14 17:43:00 -0700357 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
358 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700359
Ian Rogersdd7624d2014-03-14 17:43:00 -0700360 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister mscratch,
361 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700362
Ian Rogersdd7624d2014-03-14 17:43:00 -0700363 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
364 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700365
Ian Rogersdd7624d2014-03-14 17:43:00 -0700366 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
367 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700368
Ian Rogersdd7624d2014-03-14 17:43:00 -0700369 void MemoryBarrier(ManagedRegister) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700370
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200371 // Sign extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700372 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700373
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200374 // Zero extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700375 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700376
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200377 // Exploit fast access in managed code to Thread::Current().
Ian Rogersdd7624d2014-03-14 17:43:00 -0700378 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
379 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700380
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700381 // Set up out_reg to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700382 // value is null and null_allowed. in_reg holds a possibly stale reference
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700383 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700384 // null.
385 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
386 ManagedRegister in_reg, bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700387
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700388 // Set up out_off to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700389 // value is null and null_allowed.
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700390 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
391 ManagedRegister mscratch, bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700392
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200393 // src holds a handle scope entry (Object**) load this into dst.
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700394 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700395
396 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
397 // know that src may not be null.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700398 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
399 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700400
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200401 // Call to address held at [base+offset].
Ian Rogersdd7624d2014-03-14 17:43:00 -0700402 void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
403 void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
404 void CallFromThread32(ThreadOffset<4> offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700405
jeffhao7fbee072012-08-24 17:56:54 -0700406 // Generate code to check if Thread::Current()->exception_ is non-null
407 // and branch to a ExceptionSlowPath if it is.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700408 void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700409
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200410 // Emit slow paths queued during assembly and promote short branches to long if needed.
411 void FinalizeCode() OVERRIDE;
412
413 // Emit branches and finalize all instructions.
414 void FinalizeInstructions(const MemoryRegion& region);
415
416 // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS,
417 // must be used instead of MipsLabel::GetPosition()).
418 uint32_t GetLabelLocation(MipsLabel* label) const;
419
420 // Get the final position of a label after local fixup based on the old position
421 // recorded before FinalizeCode().
422 uint32_t GetAdjustedPosition(uint32_t old_position);
423
424 enum BranchCondition {
425 kCondLT,
426 kCondGE,
427 kCondLE,
428 kCondGT,
429 kCondLTZ,
430 kCondGEZ,
431 kCondLEZ,
432 kCondGTZ,
433 kCondEQ,
434 kCondNE,
435 kCondEQZ,
436 kCondNEZ,
437 kCondLTU,
438 kCondGEU,
439 kUncond,
440 };
441 friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs);
442
jeffhao7fbee072012-08-24 17:56:54 -0700443 private:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200444 class Branch {
445 public:
446 enum Type {
447 // R2 short branches.
448 kUncondBranch,
449 kCondBranch,
450 kCall,
451 // R2 long branches.
452 kLongUncondBranch,
453 kLongCondBranch,
454 kLongCall,
455 // R6 short branches.
456 kR6UncondBranch,
457 kR6CondBranch,
458 kR6Call,
459 // R6 long branches.
460 kR6LongUncondBranch,
461 kR6LongCondBranch,
462 kR6LongCall,
463 };
464 // Bit sizes of offsets defined as enums to minimize chance of typos.
465 enum OffsetBits {
466 kOffset16 = 16,
467 kOffset18 = 18,
468 kOffset21 = 21,
469 kOffset23 = 23,
470 kOffset28 = 28,
471 kOffset32 = 32,
472 };
473
474 static constexpr uint32_t kUnresolved = 0xffffffff; // Unresolved target_
475 static constexpr int32_t kMaxBranchLength = 32;
476 static constexpr int32_t kMaxBranchSize = kMaxBranchLength * sizeof(uint32_t);
477
478 struct BranchInfo {
479 // Branch length as a number of 4-byte-long instructions.
480 uint32_t length;
481 // Ordinal number (0-based) of the first (or the only) instruction that contains the branch's
482 // PC-relative offset (or its most significant 16-bit half, which goes first).
483 uint32_t instr_offset;
484 // Different MIPS instructions with PC-relative offsets apply said offsets to slightly
485 // different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte
486 // instructions) from the instruction containing the offset.
487 uint32_t pc_org;
488 // How large (in bits) a PC-relative offset can be for a given type of branch (kR6CondBranch
489 // is an exception: use kOffset23 for beqzc/bnezc).
490 OffsetBits offset_size;
491 // Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift
492 // count.
493 int offset_shift;
494 };
495 static const BranchInfo branch_info_[/* Type */];
496
497 // Unconditional branch.
498 Branch(bool is_r6, uint32_t location, uint32_t target);
499 // Conditional branch.
500 Branch(bool is_r6,
501 uint32_t location,
502 uint32_t target,
503 BranchCondition condition,
504 Register lhs_reg,
505 Register rhs_reg = ZERO);
506 // Call (branch and link) that stores the target address in a given register (i.e. T9).
507 Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg);
508
509 // Some conditional branches with lhs = rhs are effectively NOPs, while some
510 // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs.
511 // So, we need a way to identify such branches in order to emit no instructions for them
512 // or change them to unconditional.
513 static bool IsNop(BranchCondition condition, Register lhs, Register rhs);
514 static bool IsUncond(BranchCondition condition, Register lhs, Register rhs);
515
516 static BranchCondition OppositeCondition(BranchCondition cond);
517
518 Type GetType() const;
519 BranchCondition GetCondition() const;
520 Register GetLeftRegister() const;
521 Register GetRightRegister() const;
522 uint32_t GetTarget() const;
523 uint32_t GetLocation() const;
524 uint32_t GetOldLocation() const;
525 uint32_t GetLength() const;
526 uint32_t GetOldLength() const;
527 uint32_t GetSize() const;
528 uint32_t GetOldSize() const;
529 uint32_t GetEndLocation() const;
530 uint32_t GetOldEndLocation() const;
531 bool IsLong() const;
532 bool IsResolved() const;
533
534 // Returns the bit size of the signed offset that the branch instruction can handle.
535 OffsetBits GetOffsetSize() const;
536
537 // Calculates the distance between two byte locations in the assembler buffer and
538 // returns the number of bits needed to represent the distance as a signed integer.
539 //
540 // Branch instructions have signed offsets of 16, 19 (addiupc), 21 (beqzc/bnezc),
541 // and 26 (bc) bits, which are additionally shifted left 2 positions at run time.
542 //
543 // Composite branches (made of several instructions) with longer reach have 32-bit
544 // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first).
545 // The composite branches cover the range of PC + +/-2GB.
546 //
547 // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special
548 // case with the addiu instruction and a 16 bit offset.
549 static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target);
550
551 // Resolve a branch when the target is known.
552 void Resolve(uint32_t target);
553
554 // Relocate a branch by a given delta if needed due to expansion of this or another
555 // branch at a given location by this delta (just changes location_ and target_).
556 void Relocate(uint32_t expand_location, uint32_t delta);
557
558 // If the branch is short, changes its type to long.
559 void PromoteToLong();
560
561 // If necessary, updates the type by promoting a short branch to a long branch
562 // based on the branch location and target. Returns the amount (in bytes) by
563 // which the branch size has increased.
564 // max_short_distance caps the maximum distance between location_ and target_
565 // that is allowed for short branches. This is for debugging/testing purposes.
566 // max_short_distance = 0 forces all short branches to become long.
567 // Use the implicit default argument when not debugging/testing.
568 uint32_t PromoteIfNeeded(uint32_t max_short_distance = std::numeric_limits<uint32_t>::max());
569
570 // Returns the location of the instruction(s) containing the offset.
571 uint32_t GetOffsetLocation() const;
572
573 // Calculates and returns the offset ready for encoding in the branch instruction(s).
574 uint32_t GetOffset() const;
575
576 private:
577 // Completes branch construction by determining and recording its type.
578 void InitializeType(bool is_call, bool is_r6);
579 // Helper for the above.
580 void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
581
582 uint32_t old_location_; // Offset into assembler buffer in bytes.
583 uint32_t location_; // Offset into assembler buffer in bytes.
584 uint32_t target_; // Offset into assembler buffer in bytes.
585
586 uint32_t lhs_reg_ : 5; // Left-hand side register in conditional branches or
587 // indirect call register.
588 uint32_t rhs_reg_ : 5; // Right-hand side register in conditional branches.
589 BranchCondition condition_ : 5; // Condition for conditional branches.
590
591 Type type_ : 5; // Current type of the branch.
592 Type old_type_ : 5; // Initial type of the branch.
593 };
594 friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs);
595 friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs);
596
jeffhao7fbee072012-08-24 17:56:54 -0700597 void EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct);
598 void EmitI(int opcode, Register rs, Register rt, uint16_t imm);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200599 void EmitI21(int opcode, Register rs, uint32_t imm21);
600 void EmitI26(int opcode, uint32_t imm26);
jeffhao7fbee072012-08-24 17:56:54 -0700601 void EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct);
602 void EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200603 void EmitBcond(BranchCondition cond, Register rs, Register rt, uint16_t imm16);
604 void EmitBcondc(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700605
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200606 void Buncond(MipsLabel* label);
607 void Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs = ZERO);
608 void Call(MipsLabel* label, Register indirect_reg);
609 void FinalizeLabeledBranch(MipsLabel* label);
jeffhao7fbee072012-08-24 17:56:54 -0700610
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200611 Branch* GetBranch(uint32_t branch_id);
612 const Branch* GetBranch(uint32_t branch_id) const;
613
614 void PromoteBranches();
615 void EmitBranch(Branch* branch);
616 void EmitBranches();
Vladimir Marko10ef6942015-10-22 15:25:54 +0100617 void PatchCFI(size_t number_of_delayed_adjust_pcs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200618
619 // Emits exception block.
620 void EmitExceptionPoll(MipsExceptionSlowPath* exception);
621
622 bool IsR6() const {
623 if (isa_features_ != nullptr) {
624 return isa_features_->IsR6();
625 } else {
626 return false;
627 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000628 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200629
630 bool Is32BitFPU() const {
631 if (isa_features_ != nullptr) {
632 return isa_features_->Is32BitFloatingPoint();
633 } else {
634 return true;
635 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000636 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200637
638 // List of exception blocks to generate at the end of the code cache.
639 std::vector<MipsExceptionSlowPath> exception_blocks_;
640
641 std::vector<Branch> branches_;
642
643 // Whether appending instructions at the end of the buffer or overwriting the existing ones.
644 bool overwriting_;
645 // The current overwrite location.
646 uint32_t overwrite_location_;
647
648 // Data for AdjustedPosition(), see the description there.
649 uint32_t last_position_adjustment_;
650 uint32_t last_old_position_;
651 uint32_t last_branch_id_;
652
653 const MipsInstructionSetFeatures* isa_features_;
Goran Jakovljevicff734982015-08-24 12:58:55 +0000654
jeffhao7fbee072012-08-24 17:56:54 -0700655 DISALLOW_COPY_AND_ASSIGN(MipsAssembler);
656};
657
jeffhao7fbee072012-08-24 17:56:54 -0700658} // namespace mips
659} // namespace art
660
Ian Rogers166db042013-07-26 12:05:57 -0700661#endif // ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_