blob: 013ad60662632afa78d0f78b794c79cdfdcaac97 [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
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200137 void Seb(Register rd, Register rt); // R2+
138 void Seh(Register rd, Register rt); // R2+
Chris Larsen3f8bf652015-10-28 10:08:56 -0700139 void Wsbh(Register rd, Register rt); // R2+
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200140
141 void Sll(Register rd, Register rt, int shamt);
142 void Srl(Register rd, Register rt, int shamt);
Chris Larsen3f8bf652015-10-28 10:08:56 -0700143 void Rotr(Register rd, Register rt, int shamt); // R2+
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200144 void Sra(Register rd, Register rt, int shamt);
145 void Sllv(Register rd, Register rt, Register rs);
146 void Srlv(Register rd, Register rt, Register rs);
147 void Srav(Register rd, Register rt, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700148
149 void Lb(Register rt, Register rs, uint16_t imm16);
150 void Lh(Register rt, Register rs, uint16_t imm16);
151 void Lw(Register rt, Register rs, uint16_t imm16);
152 void Lbu(Register rt, Register rs, uint16_t imm16);
153 void Lhu(Register rt, Register rs, uint16_t imm16);
154 void Lui(Register rt, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200155 void Sync(uint32_t stype);
156 void Mfhi(Register rd); // R2
157 void Mflo(Register rd); // R2
jeffhao7fbee072012-08-24 17:56:54 -0700158
159 void Sb(Register rt, Register rs, uint16_t imm16);
160 void Sh(Register rt, Register rs, uint16_t imm16);
161 void Sw(Register rt, Register rs, uint16_t imm16);
162
163 void Slt(Register rd, Register rs, Register rt);
164 void Sltu(Register rd, Register rs, Register rt);
165 void Slti(Register rt, Register rs, uint16_t imm16);
166 void Sltiu(Register rt, Register rs, uint16_t imm16);
167
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200168 void B(uint16_t imm16);
169 void Beq(Register rs, Register rt, uint16_t imm16);
170 void Bne(Register rs, Register rt, uint16_t imm16);
171 void Beqz(Register rt, uint16_t imm16);
172 void Bnez(Register rt, uint16_t imm16);
173 void Bltz(Register rt, uint16_t imm16);
174 void Bgez(Register rt, uint16_t imm16);
175 void Blez(Register rt, uint16_t imm16);
176 void Bgtz(Register rt, uint16_t imm16);
177 void J(uint32_t addr26);
178 void Jal(uint32_t addr26);
179 void Jalr(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700180 void Jalr(Register rs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200181 void Jr(Register rs);
182 void Nal();
183 void Auipc(Register rs, uint16_t imm16); // R6
184 void Addiupc(Register rs, uint32_t imm19); // R6
185 void Bc(uint32_t imm26); // R6
186 void Jic(Register rt, uint16_t imm16); // R6
187 void Jialc(Register rt, uint16_t imm16); // R6
188 void Bltc(Register rs, Register rt, uint16_t imm16); // R6
189 void Bltzc(Register rt, uint16_t imm16); // R6
190 void Bgtzc(Register rt, uint16_t imm16); // R6
191 void Bgec(Register rs, Register rt, uint16_t imm16); // R6
192 void Bgezc(Register rt, uint16_t imm16); // R6
193 void Blezc(Register rt, uint16_t imm16); // R6
194 void Bltuc(Register rs, Register rt, uint16_t imm16); // R6
195 void Bgeuc(Register rs, Register rt, uint16_t imm16); // R6
196 void Beqc(Register rs, Register rt, uint16_t imm16); // R6
197 void Bnec(Register rs, Register rt, uint16_t imm16); // R6
198 void Beqzc(Register rs, uint32_t imm21); // R6
199 void Bnezc(Register rs, uint32_t imm21); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700200
201 void AddS(FRegister fd, FRegister fs, FRegister ft);
202 void SubS(FRegister fd, FRegister fs, FRegister ft);
203 void MulS(FRegister fd, FRegister fs, FRegister ft);
204 void DivS(FRegister fd, FRegister fs, FRegister ft);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200205 void AddD(FRegister fd, FRegister fs, FRegister ft);
206 void SubD(FRegister fd, FRegister fs, FRegister ft);
207 void MulD(FRegister fd, FRegister fs, FRegister ft);
208 void DivD(FRegister fd, FRegister fs, FRegister ft);
jeffhao7fbee072012-08-24 17:56:54 -0700209 void MovS(FRegister fd, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200210 void MovD(FRegister fd, FRegister fs);
211 void NegS(FRegister fd, FRegister fs);
212 void NegD(FRegister fd, FRegister fs);
213
214 void Cvtsw(FRegister fd, FRegister fs);
215 void Cvtdw(FRegister fd, FRegister fs);
216 void Cvtsd(FRegister fd, FRegister fs);
217 void Cvtds(FRegister fd, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700218
219 void Mfc1(Register rt, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200220 void Mtc1(Register rt, FRegister fs);
221 void Mfhc1(Register rt, FRegister fs);
222 void Mthc1(Register rt, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700223 void Lwc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200224 void Ldc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700225 void Swc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200226 void Sdc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700227
228 void Break();
jeffhao07030602012-09-26 14:33:14 -0700229 void Nop();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200230 void Move(Register rd, Register rs);
231 void Clear(Register rd);
232 void Not(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700233
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200234 // Higher level composite instructions.
235 void LoadConst32(Register rd, int32_t value);
236 void LoadConst64(Register reg_hi, Register reg_lo, int64_t value);
237 void LoadDConst64(FRegister rd, int64_t value, Register temp);
238 void LoadSConst32(FRegister r, int32_t value, Register temp);
239 void StoreConst32ToOffset(int32_t value, Register base, int32_t offset, Register temp);
240 void StoreConst64ToOffset(int64_t value, Register base, int32_t offset, Register temp);
241 void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT);
242
243 // These will generate R2 branches or R6 branches as appropriate.
244 void Bind(MipsLabel* label);
245 void B(MipsLabel* label);
246 void Jalr(MipsLabel* label, Register indirect_reg);
247 void Beq(Register rs, Register rt, MipsLabel* label);
248 void Bne(Register rs, Register rt, MipsLabel* label);
249 void Beqz(Register rt, MipsLabel* label);
250 void Bnez(Register rt, MipsLabel* label);
251 void Bltz(Register rt, MipsLabel* label);
252 void Bgez(Register rt, MipsLabel* label);
253 void Blez(Register rt, MipsLabel* label);
254 void Bgtz(Register rt, MipsLabel* label);
255 void Blt(Register rs, Register rt, MipsLabel* label);
256 void Bge(Register rs, Register rt, MipsLabel* label);
257 void Bltu(Register rs, Register rt, MipsLabel* label);
258 void Bgeu(Register rs, Register rt, MipsLabel* label);
jeffhao7fbee072012-08-24 17:56:54 -0700259
260 void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size);
261 void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset);
262 void LoadSFromOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200263 void LoadDFromOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700264 void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset);
Goran Jakovljevicff734982015-08-24 12:58:55 +0000265 void StoreSToOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200266 void StoreDToOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700267
jeffhao7fbee072012-08-24 17:56:54 -0700268 // Emit data (e.g. encoded instruction or immediate) to the instruction stream.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200269 void Emit(uint32_t value);
270
271 // Push/pop composite routines.
272 void Push(Register rs);
273 void Pop(Register rd);
274 void PopAndReturn(Register rd, Register rt);
jeffhao7fbee072012-08-24 17:56:54 -0700275
Andreas Gampe85b62f22015-09-09 13:15:38 -0700276 void Bind(Label* label) OVERRIDE {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200277 Bind(down_cast<MipsLabel*>(label));
Andreas Gampe85b62f22015-09-09 13:15:38 -0700278 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200279 void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
280 UNIMPLEMENTED(FATAL) << "Do not use Jump for MIPS";
Andreas Gampe85b62f22015-09-09 13:15:38 -0700281 }
282
jeffhao7fbee072012-08-24 17:56:54 -0700283 //
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200284 // Overridden common assembler high-level functionality.
jeffhao7fbee072012-08-24 17:56:54 -0700285 //
286
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200287 // Emit code that will create an activation on the stack.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700288 void BuildFrame(size_t frame_size, ManagedRegister method_reg,
289 const std::vector<ManagedRegister>& callee_save_regs,
290 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700291
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200292 // Emit code that will remove an activation from the stack.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700293 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
294 OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700295
Ian Rogersdd7624d2014-03-14 17:43:00 -0700296 void IncreaseFrameSize(size_t adjust) OVERRIDE;
297 void DecreaseFrameSize(size_t adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700298
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200299 // Store routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700300 void Store(FrameOffset offs, ManagedRegister msrc, size_t size) OVERRIDE;
301 void StoreRef(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
302 void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700303
Ian Rogersdd7624d2014-03-14 17:43:00 -0700304 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700305
Ian Rogersdd7624d2014-03-14 17:43:00 -0700306 void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister mscratch)
307 OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700308
Ian Rogersdd7624d2014-03-14 17:43:00 -0700309 void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
310 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700311
Ian Rogersdd7624d2014-03-14 17:43:00 -0700312 void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700313
Ian Rogersdd7624d2014-03-14 17:43:00 -0700314 void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off,
315 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700316
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200317 // Load routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700318 void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700319
Ian Rogersdd7624d2014-03-14 17:43:00 -0700320 void LoadFromThread32(ManagedRegister mdest, ThreadOffset<4> src, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700321
Mathieu Chartiere401d142015-04-22 13:56:20 -0700322 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700323
Mathieu Chartiere401d142015-04-22 13:56:20 -0700324 void LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100325 bool unpoison_reference) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700326
Ian Rogersdd7624d2014-03-14 17:43:00 -0700327 void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700328
Ian Rogersdd7624d2014-03-14 17:43:00 -0700329 void LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset<4> offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700330
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200331 // Copying routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700332 void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700333
Ian Rogersdd7624d2014-03-14 17:43:00 -0700334 void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
335 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700336
Ian Rogersdd7624d2014-03-14 17:43:00 -0700337 void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
338 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700339
Ian Rogersdd7624d2014-03-14 17:43:00 -0700340 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700341
Ian Rogersdd7624d2014-03-14 17:43:00 -0700342 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700343
Ian Rogersdd7624d2014-03-14 17:43:00 -0700344 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister mscratch,
345 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700346
Ian Rogersdd7624d2014-03-14 17:43:00 -0700347 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
348 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700349
Ian Rogersdd7624d2014-03-14 17:43:00 -0700350 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister mscratch,
351 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700352
Ian Rogersdd7624d2014-03-14 17:43:00 -0700353 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
354 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700355
Ian Rogersdd7624d2014-03-14 17:43:00 -0700356 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
357 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700358
Ian Rogersdd7624d2014-03-14 17:43:00 -0700359 void MemoryBarrier(ManagedRegister) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700360
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200361 // Sign extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700362 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700363
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200364 // Zero extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700365 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700366
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200367 // Exploit fast access in managed code to Thread::Current().
Ian Rogersdd7624d2014-03-14 17:43:00 -0700368 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
369 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700370
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700371 // Set up out_reg to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700372 // value is null and null_allowed. in_reg holds a possibly stale reference
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700373 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700374 // null.
375 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
376 ManagedRegister in_reg, bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700377
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700378 // Set up out_off to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700379 // value is null and null_allowed.
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700380 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
381 ManagedRegister mscratch, bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700382
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200383 // src holds a handle scope entry (Object**) load this into dst.
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700384 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700385
386 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
387 // know that src may not be null.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700388 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
389 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700390
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200391 // Call to address held at [base+offset].
Ian Rogersdd7624d2014-03-14 17:43:00 -0700392 void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
393 void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
394 void CallFromThread32(ThreadOffset<4> offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700395
jeffhao7fbee072012-08-24 17:56:54 -0700396 // Generate code to check if Thread::Current()->exception_ is non-null
397 // and branch to a ExceptionSlowPath if it is.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700398 void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700399
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200400 // Emit slow paths queued during assembly and promote short branches to long if needed.
401 void FinalizeCode() OVERRIDE;
402
403 // Emit branches and finalize all instructions.
404 void FinalizeInstructions(const MemoryRegion& region);
405
406 // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS,
407 // must be used instead of MipsLabel::GetPosition()).
408 uint32_t GetLabelLocation(MipsLabel* label) const;
409
410 // Get the final position of a label after local fixup based on the old position
411 // recorded before FinalizeCode().
412 uint32_t GetAdjustedPosition(uint32_t old_position);
413
414 enum BranchCondition {
415 kCondLT,
416 kCondGE,
417 kCondLE,
418 kCondGT,
419 kCondLTZ,
420 kCondGEZ,
421 kCondLEZ,
422 kCondGTZ,
423 kCondEQ,
424 kCondNE,
425 kCondEQZ,
426 kCondNEZ,
427 kCondLTU,
428 kCondGEU,
429 kUncond,
430 };
431 friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs);
432
jeffhao7fbee072012-08-24 17:56:54 -0700433 private:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200434 class Branch {
435 public:
436 enum Type {
437 // R2 short branches.
438 kUncondBranch,
439 kCondBranch,
440 kCall,
441 // R2 long branches.
442 kLongUncondBranch,
443 kLongCondBranch,
444 kLongCall,
445 // R6 short branches.
446 kR6UncondBranch,
447 kR6CondBranch,
448 kR6Call,
449 // R6 long branches.
450 kR6LongUncondBranch,
451 kR6LongCondBranch,
452 kR6LongCall,
453 };
454 // Bit sizes of offsets defined as enums to minimize chance of typos.
455 enum OffsetBits {
456 kOffset16 = 16,
457 kOffset18 = 18,
458 kOffset21 = 21,
459 kOffset23 = 23,
460 kOffset28 = 28,
461 kOffset32 = 32,
462 };
463
464 static constexpr uint32_t kUnresolved = 0xffffffff; // Unresolved target_
465 static constexpr int32_t kMaxBranchLength = 32;
466 static constexpr int32_t kMaxBranchSize = kMaxBranchLength * sizeof(uint32_t);
467
468 struct BranchInfo {
469 // Branch length as a number of 4-byte-long instructions.
470 uint32_t length;
471 // Ordinal number (0-based) of the first (or the only) instruction that contains the branch's
472 // PC-relative offset (or its most significant 16-bit half, which goes first).
473 uint32_t instr_offset;
474 // Different MIPS instructions with PC-relative offsets apply said offsets to slightly
475 // different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte
476 // instructions) from the instruction containing the offset.
477 uint32_t pc_org;
478 // How large (in bits) a PC-relative offset can be for a given type of branch (kR6CondBranch
479 // is an exception: use kOffset23 for beqzc/bnezc).
480 OffsetBits offset_size;
481 // Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift
482 // count.
483 int offset_shift;
484 };
485 static const BranchInfo branch_info_[/* Type */];
486
487 // Unconditional branch.
488 Branch(bool is_r6, uint32_t location, uint32_t target);
489 // Conditional branch.
490 Branch(bool is_r6,
491 uint32_t location,
492 uint32_t target,
493 BranchCondition condition,
494 Register lhs_reg,
495 Register rhs_reg = ZERO);
496 // Call (branch and link) that stores the target address in a given register (i.e. T9).
497 Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg);
498
499 // Some conditional branches with lhs = rhs are effectively NOPs, while some
500 // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs.
501 // So, we need a way to identify such branches in order to emit no instructions for them
502 // or change them to unconditional.
503 static bool IsNop(BranchCondition condition, Register lhs, Register rhs);
504 static bool IsUncond(BranchCondition condition, Register lhs, Register rhs);
505
506 static BranchCondition OppositeCondition(BranchCondition cond);
507
508 Type GetType() const;
509 BranchCondition GetCondition() const;
510 Register GetLeftRegister() const;
511 Register GetRightRegister() const;
512 uint32_t GetTarget() const;
513 uint32_t GetLocation() const;
514 uint32_t GetOldLocation() const;
515 uint32_t GetLength() const;
516 uint32_t GetOldLength() const;
517 uint32_t GetSize() const;
518 uint32_t GetOldSize() const;
519 uint32_t GetEndLocation() const;
520 uint32_t GetOldEndLocation() const;
521 bool IsLong() const;
522 bool IsResolved() const;
523
524 // Returns the bit size of the signed offset that the branch instruction can handle.
525 OffsetBits GetOffsetSize() const;
526
527 // Calculates the distance between two byte locations in the assembler buffer and
528 // returns the number of bits needed to represent the distance as a signed integer.
529 //
530 // Branch instructions have signed offsets of 16, 19 (addiupc), 21 (beqzc/bnezc),
531 // and 26 (bc) bits, which are additionally shifted left 2 positions at run time.
532 //
533 // Composite branches (made of several instructions) with longer reach have 32-bit
534 // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first).
535 // The composite branches cover the range of PC + +/-2GB.
536 //
537 // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special
538 // case with the addiu instruction and a 16 bit offset.
539 static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target);
540
541 // Resolve a branch when the target is known.
542 void Resolve(uint32_t target);
543
544 // Relocate a branch by a given delta if needed due to expansion of this or another
545 // branch at a given location by this delta (just changes location_ and target_).
546 void Relocate(uint32_t expand_location, uint32_t delta);
547
548 // If the branch is short, changes its type to long.
549 void PromoteToLong();
550
551 // If necessary, updates the type by promoting a short branch to a long branch
552 // based on the branch location and target. Returns the amount (in bytes) by
553 // which the branch size has increased.
554 // max_short_distance caps the maximum distance between location_ and target_
555 // that is allowed for short branches. This is for debugging/testing purposes.
556 // max_short_distance = 0 forces all short branches to become long.
557 // Use the implicit default argument when not debugging/testing.
558 uint32_t PromoteIfNeeded(uint32_t max_short_distance = std::numeric_limits<uint32_t>::max());
559
560 // Returns the location of the instruction(s) containing the offset.
561 uint32_t GetOffsetLocation() const;
562
563 // Calculates and returns the offset ready for encoding in the branch instruction(s).
564 uint32_t GetOffset() const;
565
566 private:
567 // Completes branch construction by determining and recording its type.
568 void InitializeType(bool is_call, bool is_r6);
569 // Helper for the above.
570 void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
571
572 uint32_t old_location_; // Offset into assembler buffer in bytes.
573 uint32_t location_; // Offset into assembler buffer in bytes.
574 uint32_t target_; // Offset into assembler buffer in bytes.
575
576 uint32_t lhs_reg_ : 5; // Left-hand side register in conditional branches or
577 // indirect call register.
578 uint32_t rhs_reg_ : 5; // Right-hand side register in conditional branches.
579 BranchCondition condition_ : 5; // Condition for conditional branches.
580
581 Type type_ : 5; // Current type of the branch.
582 Type old_type_ : 5; // Initial type of the branch.
583 };
584 friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs);
585 friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs);
586
jeffhao7fbee072012-08-24 17:56:54 -0700587 void EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct);
588 void EmitI(int opcode, Register rs, Register rt, uint16_t imm);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200589 void EmitI21(int opcode, Register rs, uint32_t imm21);
590 void EmitI26(int opcode, uint32_t imm26);
jeffhao7fbee072012-08-24 17:56:54 -0700591 void EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct);
592 void EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200593 void EmitBcond(BranchCondition cond, Register rs, Register rt, uint16_t imm16);
594 void EmitBcondc(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700595
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200596 void Buncond(MipsLabel* label);
597 void Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs = ZERO);
598 void Call(MipsLabel* label, Register indirect_reg);
599 void FinalizeLabeledBranch(MipsLabel* label);
jeffhao7fbee072012-08-24 17:56:54 -0700600
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200601 Branch* GetBranch(uint32_t branch_id);
602 const Branch* GetBranch(uint32_t branch_id) const;
603
604 void PromoteBranches();
605 void EmitBranch(Branch* branch);
606 void EmitBranches();
Vladimir Marko10ef6942015-10-22 15:25:54 +0100607 void PatchCFI(size_t number_of_delayed_adjust_pcs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200608
609 // Emits exception block.
610 void EmitExceptionPoll(MipsExceptionSlowPath* exception);
611
612 bool IsR6() const {
613 if (isa_features_ != nullptr) {
614 return isa_features_->IsR6();
615 } else {
616 return false;
617 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000618 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200619
620 bool Is32BitFPU() const {
621 if (isa_features_ != nullptr) {
622 return isa_features_->Is32BitFloatingPoint();
623 } else {
624 return true;
625 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000626 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200627
628 // List of exception blocks to generate at the end of the code cache.
629 std::vector<MipsExceptionSlowPath> exception_blocks_;
630
631 std::vector<Branch> branches_;
632
633 // Whether appending instructions at the end of the buffer or overwriting the existing ones.
634 bool overwriting_;
635 // The current overwrite location.
636 uint32_t overwrite_location_;
637
638 // Data for AdjustedPosition(), see the description there.
639 uint32_t last_position_adjustment_;
640 uint32_t last_old_position_;
641 uint32_t last_branch_id_;
642
643 const MipsInstructionSetFeatures* isa_features_;
Goran Jakovljevicff734982015-08-24 12:58:55 +0000644
jeffhao7fbee072012-08-24 17:56:54 -0700645 DISALLOW_COPY_AND_ASSIGN(MipsAssembler);
646};
647
jeffhao7fbee072012-08-24 17:56:54 -0700648} // namespace mips
649} // namespace art
650
Ian Rogers166db042013-07-26 12:05:57 -0700651#endif // ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_