blob: aa187b812b79d231aff02ecfa827673bcbf27ce9 [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),
97 isa_features_(instruction_set_features) {}
98
99 virtual ~MipsAssembler() {
100 for (auto& branch : branches_) {
101 CHECK(branch.IsResolved());
102 }
103 }
jeffhao7fbee072012-08-24 17:56:54 -0700104
105 // Emit Machine Instructions.
jeffhao7fbee072012-08-24 17:56:54 -0700106 void Addu(Register rd, Register rs, Register rt);
jeffhao7fbee072012-08-24 17:56:54 -0700107 void Addiu(Register rt, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700108 void Subu(Register rd, Register rs, Register rt);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200109
110 void MultR2(Register rs, Register rt); // R2
111 void MultuR2(Register rs, Register rt); // R2
112 void DivR2(Register rs, Register rt); // R2
113 void DivuR2(Register rs, Register rt); // R2
114 void MulR2(Register rd, Register rs, Register rt); // R2
115 void DivR2(Register rd, Register rs, Register rt); // R2
116 void ModR2(Register rd, Register rs, Register rt); // R2
117 void DivuR2(Register rd, Register rs, Register rt); // R2
118 void ModuR2(Register rd, Register rs, Register rt); // R2
119 void MulR6(Register rd, Register rs, Register rt); // R6
120 void MuhuR6(Register rd, Register rs, Register rt); // R6
121 void DivR6(Register rd, Register rs, Register rt); // R6
122 void ModR6(Register rd, Register rs, Register rt); // R6
123 void DivuR6(Register rd, Register rs, Register rt); // R6
124 void ModuR6(Register rd, Register rs, Register rt); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700125
126 void And(Register rd, Register rs, Register rt);
127 void Andi(Register rt, Register rs, uint16_t imm16);
128 void Or(Register rd, Register rs, Register rt);
129 void Ori(Register rt, Register rs, uint16_t imm16);
130 void Xor(Register rd, Register rs, Register rt);
131 void Xori(Register rt, Register rs, uint16_t imm16);
132 void Nor(Register rd, Register rs, Register rt);
133
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200134 void Seb(Register rd, Register rt); // R2+
135 void Seh(Register rd, Register rt); // R2+
136
137 void Sll(Register rd, Register rt, int shamt);
138 void Srl(Register rd, Register rt, int shamt);
139 void Sra(Register rd, Register rt, int shamt);
140 void Sllv(Register rd, Register rt, Register rs);
141 void Srlv(Register rd, Register rt, Register rs);
142 void Srav(Register rd, Register rt, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700143
144 void Lb(Register rt, Register rs, uint16_t imm16);
145 void Lh(Register rt, Register rs, uint16_t imm16);
146 void Lw(Register rt, Register rs, uint16_t imm16);
147 void Lbu(Register rt, Register rs, uint16_t imm16);
148 void Lhu(Register rt, Register rs, uint16_t imm16);
149 void Lui(Register rt, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200150 void Sync(uint32_t stype);
151 void Mfhi(Register rd); // R2
152 void Mflo(Register rd); // R2
jeffhao7fbee072012-08-24 17:56:54 -0700153
154 void Sb(Register rt, Register rs, uint16_t imm16);
155 void Sh(Register rt, Register rs, uint16_t imm16);
156 void Sw(Register rt, Register rs, uint16_t imm16);
157
158 void Slt(Register rd, Register rs, Register rt);
159 void Sltu(Register rd, Register rs, Register rt);
160 void Slti(Register rt, Register rs, uint16_t imm16);
161 void Sltiu(Register rt, Register rs, uint16_t imm16);
162
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200163 void B(uint16_t imm16);
164 void Beq(Register rs, Register rt, uint16_t imm16);
165 void Bne(Register rs, Register rt, uint16_t imm16);
166 void Beqz(Register rt, uint16_t imm16);
167 void Bnez(Register rt, uint16_t imm16);
168 void Bltz(Register rt, uint16_t imm16);
169 void Bgez(Register rt, uint16_t imm16);
170 void Blez(Register rt, uint16_t imm16);
171 void Bgtz(Register rt, uint16_t imm16);
172 void J(uint32_t addr26);
173 void Jal(uint32_t addr26);
174 void Jalr(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700175 void Jalr(Register rs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200176 void Jr(Register rs);
177 void Nal();
178 void Auipc(Register rs, uint16_t imm16); // R6
179 void Addiupc(Register rs, uint32_t imm19); // R6
180 void Bc(uint32_t imm26); // R6
181 void Jic(Register rt, uint16_t imm16); // R6
182 void Jialc(Register rt, uint16_t imm16); // R6
183 void Bltc(Register rs, Register rt, uint16_t imm16); // R6
184 void Bltzc(Register rt, uint16_t imm16); // R6
185 void Bgtzc(Register rt, uint16_t imm16); // R6
186 void Bgec(Register rs, Register rt, uint16_t imm16); // R6
187 void Bgezc(Register rt, uint16_t imm16); // R6
188 void Blezc(Register rt, uint16_t imm16); // R6
189 void Bltuc(Register rs, Register rt, uint16_t imm16); // R6
190 void Bgeuc(Register rs, Register rt, uint16_t imm16); // R6
191 void Beqc(Register rs, Register rt, uint16_t imm16); // R6
192 void Bnec(Register rs, Register rt, uint16_t imm16); // R6
193 void Beqzc(Register rs, uint32_t imm21); // R6
194 void Bnezc(Register rs, uint32_t imm21); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700195
196 void AddS(FRegister fd, FRegister fs, FRegister ft);
197 void SubS(FRegister fd, FRegister fs, FRegister ft);
198 void MulS(FRegister fd, FRegister fs, FRegister ft);
199 void DivS(FRegister fd, FRegister fs, FRegister ft);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200200 void AddD(FRegister fd, FRegister fs, FRegister ft);
201 void SubD(FRegister fd, FRegister fs, FRegister ft);
202 void MulD(FRegister fd, FRegister fs, FRegister ft);
203 void DivD(FRegister fd, FRegister fs, FRegister ft);
jeffhao7fbee072012-08-24 17:56:54 -0700204 void MovS(FRegister fd, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200205 void MovD(FRegister fd, FRegister fs);
206 void NegS(FRegister fd, FRegister fs);
207 void NegD(FRegister fd, FRegister fs);
208
209 void Cvtsw(FRegister fd, FRegister fs);
210 void Cvtdw(FRegister fd, FRegister fs);
211 void Cvtsd(FRegister fd, FRegister fs);
212 void Cvtds(FRegister fd, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700213
214 void Mfc1(Register rt, FRegister fs);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200215 void Mtc1(Register rt, FRegister fs);
216 void Mfhc1(Register rt, FRegister fs);
217 void Mthc1(Register rt, FRegister fs);
jeffhao7fbee072012-08-24 17:56:54 -0700218 void Lwc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200219 void Ldc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700220 void Swc1(FRegister ft, Register rs, uint16_t imm16);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200221 void Sdc1(FRegister ft, Register rs, uint16_t imm16);
jeffhao7fbee072012-08-24 17:56:54 -0700222
223 void Break();
jeffhao07030602012-09-26 14:33:14 -0700224 void Nop();
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200225 void Move(Register rd, Register rs);
226 void Clear(Register rd);
227 void Not(Register rd, Register rs);
jeffhao7fbee072012-08-24 17:56:54 -0700228
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200229 // Higher level composite instructions.
230 void LoadConst32(Register rd, int32_t value);
231 void LoadConst64(Register reg_hi, Register reg_lo, int64_t value);
232 void LoadDConst64(FRegister rd, int64_t value, Register temp);
233 void LoadSConst32(FRegister r, int32_t value, Register temp);
234 void StoreConst32ToOffset(int32_t value, Register base, int32_t offset, Register temp);
235 void StoreConst64ToOffset(int64_t value, Register base, int32_t offset, Register temp);
236 void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT);
237
238 // These will generate R2 branches or R6 branches as appropriate.
239 void Bind(MipsLabel* label);
240 void B(MipsLabel* label);
241 void Jalr(MipsLabel* label, Register indirect_reg);
242 void Beq(Register rs, Register rt, MipsLabel* label);
243 void Bne(Register rs, Register rt, MipsLabel* label);
244 void Beqz(Register rt, MipsLabel* label);
245 void Bnez(Register rt, MipsLabel* label);
246 void Bltz(Register rt, MipsLabel* label);
247 void Bgez(Register rt, MipsLabel* label);
248 void Blez(Register rt, MipsLabel* label);
249 void Bgtz(Register rt, MipsLabel* label);
250 void Blt(Register rs, Register rt, MipsLabel* label);
251 void Bge(Register rs, Register rt, MipsLabel* label);
252 void Bltu(Register rs, Register rt, MipsLabel* label);
253 void Bgeu(Register rs, Register rt, MipsLabel* label);
jeffhao7fbee072012-08-24 17:56:54 -0700254
255 void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size);
256 void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset);
257 void LoadSFromOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200258 void LoadDFromOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700259 void StoreToOffset(StoreOperandType type, Register reg, Register base, int32_t offset);
Goran Jakovljevicff734982015-08-24 12:58:55 +0000260 void StoreSToOffset(FRegister reg, Register base, int32_t offset);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200261 void StoreDToOffset(FRegister reg, Register base, int32_t offset);
jeffhao7fbee072012-08-24 17:56:54 -0700262
jeffhao7fbee072012-08-24 17:56:54 -0700263 // Emit data (e.g. encoded instruction or immediate) to the instruction stream.
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200264 void Emit(uint32_t value);
265
266 // Push/pop composite routines.
267 void Push(Register rs);
268 void Pop(Register rd);
269 void PopAndReturn(Register rd, Register rt);
jeffhao7fbee072012-08-24 17:56:54 -0700270
Andreas Gampe85b62f22015-09-09 13:15:38 -0700271 void Bind(Label* label) OVERRIDE {
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200272 Bind(down_cast<MipsLabel*>(label));
Andreas Gampe85b62f22015-09-09 13:15:38 -0700273 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200274 void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
275 UNIMPLEMENTED(FATAL) << "Do not use Jump for MIPS";
Andreas Gampe85b62f22015-09-09 13:15:38 -0700276 }
277
jeffhao7fbee072012-08-24 17:56:54 -0700278 //
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200279 // Overridden common assembler high-level functionality.
jeffhao7fbee072012-08-24 17:56:54 -0700280 //
281
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200282 // Emit code that will create an activation on the stack.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700283 void BuildFrame(size_t frame_size, ManagedRegister method_reg,
284 const std::vector<ManagedRegister>& callee_save_regs,
285 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700286
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200287 // Emit code that will remove an activation from the stack.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700288 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs)
289 OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700290
Ian Rogersdd7624d2014-03-14 17:43:00 -0700291 void IncreaseFrameSize(size_t adjust) OVERRIDE;
292 void DecreaseFrameSize(size_t adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700293
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200294 // Store routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700295 void Store(FrameOffset offs, ManagedRegister msrc, size_t size) OVERRIDE;
296 void StoreRef(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
297 void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700298
Ian Rogersdd7624d2014-03-14 17:43:00 -0700299 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700300
Ian Rogersdd7624d2014-03-14 17:43:00 -0700301 void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister mscratch)
302 OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700303
Ian Rogersdd7624d2014-03-14 17:43:00 -0700304 void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
305 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700306
Ian Rogersdd7624d2014-03-14 17:43:00 -0700307 void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700308
Ian Rogersdd7624d2014-03-14 17:43:00 -0700309 void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off,
310 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700311
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200312 // Load routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700313 void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700314
Ian Rogersdd7624d2014-03-14 17:43:00 -0700315 void LoadFromThread32(ManagedRegister mdest, ThreadOffset<4> src, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700316
Mathieu Chartiere401d142015-04-22 13:56:20 -0700317 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700318
Mathieu Chartiere401d142015-04-22 13:56:20 -0700319 void LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100320 bool unpoison_reference) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700321
Ian Rogersdd7624d2014-03-14 17:43:00 -0700322 void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700323
Ian Rogersdd7624d2014-03-14 17:43:00 -0700324 void LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset<4> offs) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700325
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200326 // Copying routines.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700327 void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700328
Ian Rogersdd7624d2014-03-14 17:43:00 -0700329 void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
330 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700331
Ian Rogersdd7624d2014-03-14 17:43:00 -0700332 void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
333 ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700334
Ian Rogersdd7624d2014-03-14 17:43:00 -0700335 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700336
Ian Rogersdd7624d2014-03-14 17:43:00 -0700337 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700338
Ian Rogersdd7624d2014-03-14 17:43:00 -0700339 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister mscratch,
340 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700341
Ian Rogersdd7624d2014-03-14 17:43:00 -0700342 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
343 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700344
Ian Rogersdd7624d2014-03-14 17:43:00 -0700345 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister mscratch,
346 size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700347
Ian Rogersdd7624d2014-03-14 17:43:00 -0700348 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
349 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700350
Ian Rogersdd7624d2014-03-14 17:43:00 -0700351 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
352 ManagedRegister mscratch, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700353
Ian Rogersdd7624d2014-03-14 17:43:00 -0700354 void MemoryBarrier(ManagedRegister) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700355
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200356 // Sign extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700357 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700358
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200359 // Zero extension.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700360 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700361
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200362 // Exploit fast access in managed code to Thread::Current().
Ian Rogersdd7624d2014-03-14 17:43:00 -0700363 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
364 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700365
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700366 // Set up out_reg to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700367 // value is null and null_allowed. in_reg holds a possibly stale reference
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700368 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700369 // null.
370 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
371 ManagedRegister in_reg, bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700372
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700373 // Set up out_off to hold a Object** into the handle scope, or to be null if the
jeffhao7fbee072012-08-24 17:56:54 -0700374 // value is null and null_allowed.
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700375 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
376 ManagedRegister mscratch, bool null_allowed) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700377
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200378 // src holds a handle scope entry (Object**) load this into dst.
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700379 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700380
381 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
382 // know that src may not be null.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700383 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
384 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700385
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200386 // Call to address held at [base+offset].
Ian Rogersdd7624d2014-03-14 17:43:00 -0700387 void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
388 void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
389 void CallFromThread32(ThreadOffset<4> offset, ManagedRegister mscratch) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700390
jeffhao7fbee072012-08-24 17:56:54 -0700391 // Generate code to check if Thread::Current()->exception_ is non-null
392 // and branch to a ExceptionSlowPath if it is.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700393 void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) OVERRIDE;
jeffhao7fbee072012-08-24 17:56:54 -0700394
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200395 // Emit slow paths queued during assembly and promote short branches to long if needed.
396 void FinalizeCode() OVERRIDE;
397
398 // Emit branches and finalize all instructions.
399 void FinalizeInstructions(const MemoryRegion& region);
400
401 // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS,
402 // must be used instead of MipsLabel::GetPosition()).
403 uint32_t GetLabelLocation(MipsLabel* label) const;
404
405 // Get the final position of a label after local fixup based on the old position
406 // recorded before FinalizeCode().
407 uint32_t GetAdjustedPosition(uint32_t old_position);
408
409 enum BranchCondition {
410 kCondLT,
411 kCondGE,
412 kCondLE,
413 kCondGT,
414 kCondLTZ,
415 kCondGEZ,
416 kCondLEZ,
417 kCondGTZ,
418 kCondEQ,
419 kCondNE,
420 kCondEQZ,
421 kCondNEZ,
422 kCondLTU,
423 kCondGEU,
424 kUncond,
425 };
426 friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs);
427
jeffhao7fbee072012-08-24 17:56:54 -0700428 private:
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200429 class Branch {
430 public:
431 enum Type {
432 // R2 short branches.
433 kUncondBranch,
434 kCondBranch,
435 kCall,
436 // R2 long branches.
437 kLongUncondBranch,
438 kLongCondBranch,
439 kLongCall,
440 // R6 short branches.
441 kR6UncondBranch,
442 kR6CondBranch,
443 kR6Call,
444 // R6 long branches.
445 kR6LongUncondBranch,
446 kR6LongCondBranch,
447 kR6LongCall,
448 };
449 // Bit sizes of offsets defined as enums to minimize chance of typos.
450 enum OffsetBits {
451 kOffset16 = 16,
452 kOffset18 = 18,
453 kOffset21 = 21,
454 kOffset23 = 23,
455 kOffset28 = 28,
456 kOffset32 = 32,
457 };
458
459 static constexpr uint32_t kUnresolved = 0xffffffff; // Unresolved target_
460 static constexpr int32_t kMaxBranchLength = 32;
461 static constexpr int32_t kMaxBranchSize = kMaxBranchLength * sizeof(uint32_t);
462
463 struct BranchInfo {
464 // Branch length as a number of 4-byte-long instructions.
465 uint32_t length;
466 // Ordinal number (0-based) of the first (or the only) instruction that contains the branch's
467 // PC-relative offset (or its most significant 16-bit half, which goes first).
468 uint32_t instr_offset;
469 // Different MIPS instructions with PC-relative offsets apply said offsets to slightly
470 // different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte
471 // instructions) from the instruction containing the offset.
472 uint32_t pc_org;
473 // How large (in bits) a PC-relative offset can be for a given type of branch (kR6CondBranch
474 // is an exception: use kOffset23 for beqzc/bnezc).
475 OffsetBits offset_size;
476 // Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift
477 // count.
478 int offset_shift;
479 };
480 static const BranchInfo branch_info_[/* Type */];
481
482 // Unconditional branch.
483 Branch(bool is_r6, uint32_t location, uint32_t target);
484 // Conditional branch.
485 Branch(bool is_r6,
486 uint32_t location,
487 uint32_t target,
488 BranchCondition condition,
489 Register lhs_reg,
490 Register rhs_reg = ZERO);
491 // Call (branch and link) that stores the target address in a given register (i.e. T9).
492 Branch(bool is_r6, uint32_t location, uint32_t target, Register indirect_reg);
493
494 // Some conditional branches with lhs = rhs are effectively NOPs, while some
495 // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs.
496 // So, we need a way to identify such branches in order to emit no instructions for them
497 // or change them to unconditional.
498 static bool IsNop(BranchCondition condition, Register lhs, Register rhs);
499 static bool IsUncond(BranchCondition condition, Register lhs, Register rhs);
500
501 static BranchCondition OppositeCondition(BranchCondition cond);
502
503 Type GetType() const;
504 BranchCondition GetCondition() const;
505 Register GetLeftRegister() const;
506 Register GetRightRegister() const;
507 uint32_t GetTarget() const;
508 uint32_t GetLocation() const;
509 uint32_t GetOldLocation() const;
510 uint32_t GetLength() const;
511 uint32_t GetOldLength() const;
512 uint32_t GetSize() const;
513 uint32_t GetOldSize() const;
514 uint32_t GetEndLocation() const;
515 uint32_t GetOldEndLocation() const;
516 bool IsLong() const;
517 bool IsResolved() const;
518
519 // Returns the bit size of the signed offset that the branch instruction can handle.
520 OffsetBits GetOffsetSize() const;
521
522 // Calculates the distance between two byte locations in the assembler buffer and
523 // returns the number of bits needed to represent the distance as a signed integer.
524 //
525 // Branch instructions have signed offsets of 16, 19 (addiupc), 21 (beqzc/bnezc),
526 // and 26 (bc) bits, which are additionally shifted left 2 positions at run time.
527 //
528 // Composite branches (made of several instructions) with longer reach have 32-bit
529 // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first).
530 // The composite branches cover the range of PC + +/-2GB.
531 //
532 // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special
533 // case with the addiu instruction and a 16 bit offset.
534 static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target);
535
536 // Resolve a branch when the target is known.
537 void Resolve(uint32_t target);
538
539 // Relocate a branch by a given delta if needed due to expansion of this or another
540 // branch at a given location by this delta (just changes location_ and target_).
541 void Relocate(uint32_t expand_location, uint32_t delta);
542
543 // If the branch is short, changes its type to long.
544 void PromoteToLong();
545
546 // If necessary, updates the type by promoting a short branch to a long branch
547 // based on the branch location and target. Returns the amount (in bytes) by
548 // which the branch size has increased.
549 // max_short_distance caps the maximum distance between location_ and target_
550 // that is allowed for short branches. This is for debugging/testing purposes.
551 // max_short_distance = 0 forces all short branches to become long.
552 // Use the implicit default argument when not debugging/testing.
553 uint32_t PromoteIfNeeded(uint32_t max_short_distance = std::numeric_limits<uint32_t>::max());
554
555 // Returns the location of the instruction(s) containing the offset.
556 uint32_t GetOffsetLocation() const;
557
558 // Calculates and returns the offset ready for encoding in the branch instruction(s).
559 uint32_t GetOffset() const;
560
561 private:
562 // Completes branch construction by determining and recording its type.
563 void InitializeType(bool is_call, bool is_r6);
564 // Helper for the above.
565 void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
566
567 uint32_t old_location_; // Offset into assembler buffer in bytes.
568 uint32_t location_; // Offset into assembler buffer in bytes.
569 uint32_t target_; // Offset into assembler buffer in bytes.
570
571 uint32_t lhs_reg_ : 5; // Left-hand side register in conditional branches or
572 // indirect call register.
573 uint32_t rhs_reg_ : 5; // Right-hand side register in conditional branches.
574 BranchCondition condition_ : 5; // Condition for conditional branches.
575
576 Type type_ : 5; // Current type of the branch.
577 Type old_type_ : 5; // Initial type of the branch.
578 };
579 friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs);
580 friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs);
581
jeffhao7fbee072012-08-24 17:56:54 -0700582 void EmitR(int opcode, Register rs, Register rt, Register rd, int shamt, int funct);
583 void EmitI(int opcode, Register rs, Register rt, uint16_t imm);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200584 void EmitI21(int opcode, Register rs, uint32_t imm21);
585 void EmitI26(int opcode, uint32_t imm26);
jeffhao7fbee072012-08-24 17:56:54 -0700586 void EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct);
587 void EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm);
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200588 void EmitBcond(BranchCondition cond, Register rs, Register rt, uint16_t imm16);
589 void EmitBcondc(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21); // R6
jeffhao7fbee072012-08-24 17:56:54 -0700590
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200591 void Buncond(MipsLabel* label);
592 void Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs = ZERO);
593 void Call(MipsLabel* label, Register indirect_reg);
594 void FinalizeLabeledBranch(MipsLabel* label);
jeffhao7fbee072012-08-24 17:56:54 -0700595
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200596 Branch* GetBranch(uint32_t branch_id);
597 const Branch* GetBranch(uint32_t branch_id) const;
598
599 void PromoteBranches();
600 void EmitBranch(Branch* branch);
601 void EmitBranches();
602
603 // Emits exception block.
604 void EmitExceptionPoll(MipsExceptionSlowPath* exception);
605
606 bool IsR6() const {
607 if (isa_features_ != nullptr) {
608 return isa_features_->IsR6();
609 } else {
610 return false;
611 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000612 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200613
614 bool Is32BitFPU() const {
615 if (isa_features_ != nullptr) {
616 return isa_features_->Is32BitFloatingPoint();
617 } else {
618 return true;
619 }
Goran Jakovljevicff734982015-08-24 12:58:55 +0000620 }
Goran Jakovljevic8c434dc2015-08-26 14:39:44 +0200621
622 // List of exception blocks to generate at the end of the code cache.
623 std::vector<MipsExceptionSlowPath> exception_blocks_;
624
625 std::vector<Branch> branches_;
626
627 // Whether appending instructions at the end of the buffer or overwriting the existing ones.
628 bool overwriting_;
629 // The current overwrite location.
630 uint32_t overwrite_location_;
631
632 // Data for AdjustedPosition(), see the description there.
633 uint32_t last_position_adjustment_;
634 uint32_t last_old_position_;
635 uint32_t last_branch_id_;
636
637 const MipsInstructionSetFeatures* isa_features_;
Goran Jakovljevicff734982015-08-24 12:58:55 +0000638
jeffhao7fbee072012-08-24 17:56:54 -0700639 DISALLOW_COPY_AND_ASSIGN(MipsAssembler);
640};
641
jeffhao7fbee072012-08-24 17:56:54 -0700642} // namespace mips
643} // namespace art
644
Ian Rogers166db042013-07-26 12:05:57 -0700645#endif // ART_COMPILER_UTILS_MIPS_ASSEMBLER_MIPS_H_