blob: 62366f6a8b76b1293301287a9fdd00aed1242686 [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
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);
188 void J(uint32_t addr26);
189 void Jal(uint32_t addr26);
190 void Jalr(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700191 void Jalr(Register rs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200192 void Jr(Register rs);
193 void Nal();
194 void Auipc(Register rs, uint16_t imm16); // R6
195 void Addiupc(Register rs, uint32_t imm19); // R6
196 void Bc(uint32_t imm26); // R6
197 void Jic(Register rt, uint16_t imm16); // R6
198 void Jialc(Register rt, uint16_t imm16); // R6
199 void Bltc(Register rs, Register rt, uint16_t imm16); // R6
200 void Bltzc(Register rt, uint16_t imm16); // R6
201 void Bgtzc(Register rt, uint16_t imm16); // R6
202 void Bgec(Register rs, Register rt, uint16_t imm16); // R6
203 void Bgezc(Register rt, uint16_t imm16); // R6
204 void Blezc(Register rt, uint16_t imm16); // R6
205 void Bltuc(Register rs, Register rt, uint16_t imm16); // R6
206 void Bgeuc(Register rs, Register rt, uint16_t imm16); // R6
207 void Beqc(Register rs, Register rt, uint16_t imm16); // R6
208 void Bnec(Register rs, Register rt, uint16_t imm16); // R6
209 void Beqzc(Register rs, uint32_t imm21); // R6
210 void Bnezc(Register rs, uint32_t imm21); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700211
212 void AddS(FRegister fd, FRegister fs, FRegister ft);
213 void SubS(FRegister fd, FRegister fs, FRegister ft);
214 void MulS(FRegister fd, FRegister fs, FRegister ft);
215 void DivS(FRegister fd, FRegister fs, FRegister ft);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200216 void AddD(FRegister fd, FRegister fs, FRegister ft);
217 void SubD(FRegister fd, FRegister fs, FRegister ft);
218 void MulD(FRegister fd, FRegister fs, FRegister ft);
219 void DivD(FRegister fd, FRegister fs, FRegister ft);
jeffhao7fbee072012-08-24 17:56:54 -0700220 void MovS(FRegister fd, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200221 void MovD(FRegister fd, FRegister fs);
222 void NegS(FRegister fd, FRegister fs);
223 void NegD(FRegister fd, FRegister fs);
224
225 void Cvtsw(FRegister fd, FRegister fs);
226 void Cvtdw(FRegister fd, FRegister fs);
227 void Cvtsd(FRegister fd, FRegister fs);
228 void Cvtds(FRegister fd, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700229
230 void Mfc1(Register rt, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200231 void Mtc1(Register rt, FRegister fs);
232 void Mfhc1(Register rt, FRegister fs);
233 void Mthc1(Register rt, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700234 void Lwc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200235 void Ldc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700236 void Swc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200237 void Sdc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700238
239 void Break();
jeffhao07030602012-09-26 14:33:14 -0700240 void Nop();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200241 void Move(Register rd, Register rs);
242 void Clear(Register rd);
243 void Not(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700244
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200245 // Higher level composite instructions.
246 void LoadConst32(Register rd, int32_t value);
247 void LoadConst64(Register reg_hi, Register reg_lo, int64_t value);
248 void LoadDConst64(FRegister rd, int64_t value, Register temp);
249 void LoadSConst32(FRegister r, int32_t value, Register temp);
250 void StoreConst32ToOffset(int32_t value, Register base, int32_t offset, Register temp);
251 void StoreConst64ToOffset(int64_t value, Register base, int32_t offset, Register temp);
252 void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT);
253
254 // These will generate R2 branches or R6 branches as appropriate.
255 void Bind(MipsLabel* label);
256 void B(MipsLabel* label);
257 void Jalr(MipsLabel* label, Register indirect_reg);
258 void Beq(Register rs, Register rt, MipsLabel* label);
259 void Bne(Register rs, Register rt, MipsLabel* label);
260 void Beqz(Register rt, MipsLabel* label);
261 void Bnez(Register rt, MipsLabel* label);
262 void Bltz(Register rt, MipsLabel* label);
263 void Bgez(Register rt, MipsLabel* label);
264 void Blez(Register rt, MipsLabel* label);
265 void Bgtz(Register rt, MipsLabel* label);
266 void Blt(Register rs, Register rt, MipsLabel* label);
267 void Bge(Register rs, Register rt, MipsLabel* label);
268 void Bltu(Register rs, Register rt, MipsLabel* label);
269 void Bgeu(Register rs, Register rt, MipsLabel* label);
jeffhao7fbee072012-08-24 17:56:54 -0700270
271 void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size);
272 void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset);
273 void LoadSFromOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200274 void LoadDFromOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700275 void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset);
Goran Jakovljevicff734982015-08-24 12:58:55 +0000276 void StoreSToOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200277 void StoreDToOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700278
jeffhao7fbee072012-08-24 17:56:54 -0700279 // Emit data (e.g. encoded instruction or immediate) to the instruction stream.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200280 void Emit(uint32_t value);
281
282 // Push/pop composite routines.
283 void Push(Register rs);
284 void Pop(Register rd);
285 void PopAndReturn(Register rd, Register rt);
jeffhao7fbee072012-08-24 17:56:54 -0700286
Andreas Gampe85b62f22015-09-09 13:15:38 -0700287 void Bind(Label* label) OVERRIDE {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200288 Bind(down_cast<MipsLabel*>(label));
Andreas Gampe85b62f22015-09-09 13:15:38 -0700289 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200290 void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
291 UNIMPLEMENTED(FATAL) << "Do not use Jump for MIPS";
Andreas Gampe85b62f22015-09-09 13:15:38 -0700292 }
293
jeffhao7fbee072012-08-24 17:56:54 -0700294 //
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200295 // Overridden common assembler high-level functionality.
jeffhao7fbee072012-08-24 17:56:54 -0700296 //
297
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200298 // Emit code that will create an activation on the stack.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700299 void BuildFrame(size_t frame_size, ManagedRegister method_reg,
300 const std::vector<ManagedRegister>& callee_save_regs,
301 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700302
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200303 // Emit code that will remove an activation from the stack.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700304 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
305 OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700306
Ian Rogersdd7624d2014-03-14 17:43:00 -0700307 void IncreaseFrameSize(size_t adjust) OVERRIDE;
308 void DecreaseFrameSize(size_t adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700309
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200310 // Store routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700311 void Store(FrameOffset offs, ManagedRegister msrc, size_t size) OVERRIDE;
312 void StoreRef(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
313 void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700314
Ian Rogersdd7624d2014-03-14 17:43:00 -0700315 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700316
Ian Rogersdd7624d2014-03-14 17:43:00 -0700317 void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister mscratch)
318 OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700319
Ian Rogersdd7624d2014-03-14 17:43:00 -0700320 void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
321 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700322
Ian Rogersdd7624d2014-03-14 17:43:00 -0700323 void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700324
Ian Rogersdd7624d2014-03-14 17:43:00 -0700325 void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off,
326 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700327
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200328 // Load routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700329 void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700330
Ian Rogersdd7624d2014-03-14 17:43:00 -0700331 void LoadFromThread32(ManagedRegister mdest, ThreadOffset<4> src, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700332
Mathieu Chartiere401d142015-04-22 13:56:20 -0700333 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700334
Mathieu Chartiere401d142015-04-22 13:56:20 -0700335 void LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100336 bool unpoison_reference) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700337
Ian Rogersdd7624d2014-03-14 17:43:00 -0700338 void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700339
Ian Rogersdd7624d2014-03-14 17:43:00 -0700340 void LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset<4> offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700341
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200342 // Copying routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700343 void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700344
Ian Rogersdd7624d2014-03-14 17:43:00 -0700345 void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
346 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700347
Ian Rogersdd7624d2014-03-14 17:43:00 -0700348 void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
349 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700350
Ian Rogersdd7624d2014-03-14 17:43:00 -0700351 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700352
Ian Rogersdd7624d2014-03-14 17:43:00 -0700353 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700354
Ian Rogersdd7624d2014-03-14 17:43:00 -0700355 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister mscratch,
356 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700357
Ian Rogersdd7624d2014-03-14 17:43:00 -0700358 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
359 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700360
Ian Rogersdd7624d2014-03-14 17:43:00 -0700361 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister mscratch,
362 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700363
Ian Rogersdd7624d2014-03-14 17:43:00 -0700364 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
365 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700366
Ian Rogersdd7624d2014-03-14 17:43:00 -0700367 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
368 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700369
Ian Rogersdd7624d2014-03-14 17:43:00 -0700370 void MemoryBarrier(ManagedRegister) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700371
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200372 // Sign extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700373 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700374
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200375 // Zero extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700376 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700377
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200378 // Exploit fast access in managed code to Thread::Current().
Ian Rogersdd7624d2014-03-14 17:43:00 -0700379 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
380 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700381
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700382 // Set up out_reg to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700383 // value is null and null_allowed. in_reg holds a possibly stale reference
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700384 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700385 // null.
386 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
387 ManagedRegister in_reg, bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700388
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700389 // Set up out_off to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700390 // value is null and null_allowed.
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700391 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
392 ManagedRegister mscratch, bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700393
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200394 // src holds a handle scope entry (Object**) load this into dst.
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700395 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700396
397 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
398 // know that src may not be null.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700399 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
400 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700401
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200402 // Call to address held at [base+offset].
Ian Rogersdd7624d2014-03-14 17:43:00 -0700403 void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
404 void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
405 void CallFromThread32(ThreadOffset<4> offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700406
jeffhao7fbee072012-08-24 17:56:54 -0700407 // Generate code to check if Thread::Current()->exception_ is non-null
408 // and branch to a ExceptionSlowPath if it is.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700409 void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700410
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200411 // Emit slow paths queued during assembly and promote short branches to long if needed.
412 void FinalizeCode() OVERRIDE;
413
414 // Emit branches and finalize all instructions.
415 void FinalizeInstructions(const MemoryRegion& region);
416
417 // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS,
418 // must be used instead of MipsLabel::GetPosition()).
419 uint32_t GetLabelLocation(MipsLabel* label) const;
420
421 // Get the final position of a label after local fixup based on the old position
422 // recorded before FinalizeCode().
423 uint32_t GetAdjustedPosition(uint32_t old_position);
424
425 enum BranchCondition {
426 kCondLT,
427 kCondGE,
428 kCondLE,
429 kCondGT,
430 kCondLTZ,
431 kCondGEZ,
432 kCondLEZ,
433 kCondGTZ,
434 kCondEQ,
435 kCondNE,
436 kCondEQZ,
437 kCondNEZ,
438 kCondLTU,
439 kCondGEU,
440 kUncond,
441 };
442 friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs);
443
jeffhao7fbee072012-08-24 17:56:54 -0700444 private:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200445 class Branch {
446 public:
447 enum Type {
448 // R2 short branches.
449 kUncondBranch,
450 kCondBranch,
451 kCall,
452 // R2 long branches.
453 kLongUncondBranch,
454 kLongCondBranch,
455 kLongCall,
456 // R6 short branches.
457 kR6UncondBranch,
458 kR6CondBranch,
459 kR6Call,
460 // R6 long branches.
461 kR6LongUncondBranch,
462 kR6LongCondBranch,
463 kR6LongCall,
464 };
465 // Bit sizes of offsets defined as enums to minimize chance of typos.
466 enum OffsetBits {
467 kOffset16 = 16,
468 kOffset18 = 18,
469 kOffset21 = 21,
470 kOffset23 = 23,
471 kOffset28 = 28,
472 kOffset32 = 32,
473 };
474
475 static constexpr uint32_t kUnresolved = 0xffffffff; // Unresolved target_
476 static constexpr int32_t kMaxBranchLength = 32;
477 static constexpr int32_t kMaxBranchSize = kMaxBranchLength * sizeof(uint32_t);
478
479 struct BranchInfo {
480 // Branch length as a number of 4-byte-long instructions.
481 uint32_t length;
482 // Ordinal number (0-based) of the first (or the only) instruction that contains the branch's
483 // PC-relative offset (or its most significant 16-bit half, which goes first).
484 uint32_t instr_offset;
485 // Different MIPS instructions with PC-relative offsets apply said offsets to slightly
486 // different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte
487 // instructions) from the instruction containing the offset.
488 uint32_t pc_org;
489 // How large (in bits) a PC-relative offset can be for a given type of branch (kR6CondBranch
490 // is an exception: use kOffset23 for beqzc/bnezc).
491 OffsetBits offset_size;
492 // Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift
493 // count.
494 int offset_shift;
495 };
496 static const BranchInfo branch_info_[/* Type */];
497
498 // Unconditional branch.
499 Branch(bool is_r6, uint32_t location, uint32_t target);
500 // Conditional branch.
501 Branch(bool is_r6,
502 uint32_t location,
503 uint32_t target,
504 BranchCondition condition,
505 Register lhs_reg,
506 Register rhs_reg = ZERO);
507 // Call (branch and link) that stores the target address in a given register (i.e. T9).
508 Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg);
509
510 // Some conditional branches with lhs = rhs are effectively NOPs, while some
511 // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs.
512 // So, we need a way to identify such branches in order to emit no instructions for them
513 // or change them to unconditional.
514 static bool IsNop(BranchCondition condition, Register lhs, Register rhs);
515 static bool IsUncond(BranchCondition condition, Register lhs, Register rhs);
516
517 static BranchCondition OppositeCondition(BranchCondition cond);
518
519 Type GetType() const;
520 BranchCondition GetCondition() const;
521 Register GetLeftRegister() const;
522 Register GetRightRegister() const;
523 uint32_t GetTarget() const;
524 uint32_t GetLocation() const;
525 uint32_t GetOldLocation() const;
526 uint32_t GetLength() const;
527 uint32_t GetOldLength() const;
528 uint32_t GetSize() const;
529 uint32_t GetOldSize() const;
530 uint32_t GetEndLocation() const;
531 uint32_t GetOldEndLocation() const;
532 bool IsLong() const;
533 bool IsResolved() const;
534
535 // Returns the bit size of the signed offset that the branch instruction can handle.
536 OffsetBits GetOffsetSize() const;
537
538 // Calculates the distance between two byte locations in the assembler buffer and
539 // returns the number of bits needed to represent the distance as a signed integer.
540 //
541 // Branch instructions have signed offsets of 16, 19 (addiupc), 21 (beqzc/bnezc),
542 // and 26 (bc) bits, which are additionally shifted left 2 positions at run time.
543 //
544 // Composite branches (made of several instructions) with longer reach have 32-bit
545 // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first).
546 // The composite branches cover the range of PC + +/-2GB.
547 //
548 // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special
549 // case with the addiu instruction and a 16 bit offset.
550 static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target);
551
552 // Resolve a branch when the target is known.
553 void Resolve(uint32_t target);
554
555 // Relocate a branch by a given delta if needed due to expansion of this or another
556 // branch at a given location by this delta (just changes location_ and target_).
557 void Relocate(uint32_t expand_location, uint32_t delta);
558
559 // If the branch is short, changes its type to long.
560 void PromoteToLong();
561
562 // If necessary, updates the type by promoting a short branch to a long branch
563 // based on the branch location and target. Returns the amount (in bytes) by
564 // which the branch size has increased.
565 // max_short_distance caps the maximum distance between location_ and target_
566 // that is allowed for short branches. This is for debugging/testing purposes.
567 // max_short_distance = 0 forces all short branches to become long.
568 // Use the implicit default argument when not debugging/testing.
569 uint32_t PromoteIfNeeded(uint32_t max_short_distance = std::numeric_limits<uint32_t>::max());
570
571 // Returns the location of the instruction(s) containing the offset.
572 uint32_t GetOffsetLocation() const;
573
574 // Calculates and returns the offset ready for encoding in the branch instruction(s).
575 uint32_t GetOffset() const;
576
577 private:
578 // Completes branch construction by determining and recording its type.
579 void InitializeType(bool is_call, bool is_r6);
580 // Helper for the above.
581 void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
582
583 uint32_t old_location_; // Offset into assembler buffer in bytes.
584 uint32_t location_; // Offset into assembler buffer in bytes.
585 uint32_t target_; // Offset into assembler buffer in bytes.
586
587 uint32_t lhs_reg_ : 5; // Left-hand side register in conditional branches or
588 // indirect call register.
589 uint32_t rhs_reg_ : 5; // Right-hand side register in conditional branches.
590 BranchCondition condition_ : 5; // Condition for conditional branches.
591
592 Type type_ : 5; // Current type of the branch.
593 Type old_type_ : 5; // Initial type of the branch.
594 };
595 friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs);
596 friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs);
597
jeffhao7fbee072012-08-24 17:56:54 -0700598 void EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct);
599 void EmitI(int opcode, Register rs, Register rt, uint16_t imm);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200600 void EmitI21(int opcode, Register rs, uint32_t imm21);
601 void EmitI26(int opcode, uint32_t imm26);
jeffhao7fbee072012-08-24 17:56:54 -0700602 void EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct);
603 void EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200604 void EmitBcond(BranchCondition cond, Register rs, Register rt, uint16_t imm16);
605 void EmitBcondc(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700606
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200607 void Buncond(MipsLabel* label);
608 void Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs = ZERO);
609 void Call(MipsLabel* label, Register indirect_reg);
610 void FinalizeLabeledBranch(MipsLabel* label);
jeffhao7fbee072012-08-24 17:56:54 -0700611
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200612 Branch* GetBranch(uint32_t branch_id);
613 const Branch* GetBranch(uint32_t branch_id) const;
614
615 void PromoteBranches();
616 void EmitBranch(Branch* branch);
617 void EmitBranches();
Vladimir Marko10ef6942015-10-22 15:25:54 +0100618 void PatchCFI(size_t number_of_delayed_adjust_pcs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200619
620 // Emits exception block.
621 void EmitExceptionPoll(MipsExceptionSlowPath* exception);
622
623 bool IsR6() const {
624 if (isa_features_ != nullptr) {
625 return isa_features_->IsR6();
626 } else {
627 return false;
628 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000629 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200630
631 bool Is32BitFPU() const {
632 if (isa_features_ != nullptr) {
633 return isa_features_->Is32BitFloatingPoint();
634 } else {
635 return true;
636 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000637 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200638
639 // List of exception blocks to generate at the end of the code cache.
640 std::vector<MipsExceptionSlowPath> exception_blocks_;
641
642 std::vector<Branch> branches_;
643
644 // Whether appending instructions at the end of the buffer or overwriting the existing ones.
645 bool overwriting_;
646 // The current overwrite location.
647 uint32_t overwrite_location_;
648
649 // Data for AdjustedPosition(), see the description there.
650 uint32_t last_position_adjustment_;
651 uint32_t last_old_position_;
652 uint32_t last_branch_id_;
653
654 const MipsInstructionSetFeatures* isa_features_;
Goran Jakovljevicff734982015-08-24 12:58:55 +0000655
jeffhao7fbee072012-08-24 17:56:54 -0700656 DISALLOW_COPY_AND_ASSIGN(MipsAssembler);
657};
658
jeffhao7fbee072012-08-24 17:56:54 -0700659} // namespace mips
660} // namespace art
661
Ian Rogers166db042013-07-26 12:05:57 -0700662#endif // ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_