blob: 57fc19a6e9b9eb5c1ba59a54b12337cd68f12cc6 [file] [log] [blame]
Andreas Gampe57b34292015-01-14 15:45:59 -08001/*
2 * Copyright (C) 2014 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
17#ifndef ART_COMPILER_UTILS_MIPS64_ASSEMBLER_MIPS64_H_
18#define ART_COMPILER_UTILS_MIPS64_ASSEMBLER_MIPS64_H_
19
Alexey Frunzea0e87b02015-09-24 22:57:20 -070020#include <utility>
Andreas Gampe57b34292015-01-14 15:45:59 -080021#include <vector>
22
23#include "base/macros.h"
24#include "constants_mips64.h"
25#include "globals.h"
26#include "managed_register_mips64.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080027#include "offsets.h"
Alexey Frunzea0e87b02015-09-24 22:57:20 -070028#include "utils/assembler.h"
29#include "utils/label.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080030
31namespace art {
32namespace mips64 {
33
Alexey Frunzea0e87b02015-09-24 22:57:20 -070034static constexpr size_t kMipsDoublewordSize = 8;
35
Andreas Gampe57b34292015-01-14 15:45:59 -080036enum LoadOperandType {
37 kLoadSignedByte,
38 kLoadUnsignedByte,
39 kLoadSignedHalfword,
40 kLoadUnsignedHalfword,
41 kLoadWord,
Douglas Leungd90957f2015-04-30 19:22:49 -070042 kLoadUnsignedWord,
Andreas Gampe57b34292015-01-14 15:45:59 -080043 kLoadDoubleword
44};
45
46enum StoreOperandType {
47 kStoreByte,
48 kStoreHalfword,
49 kStoreWord,
50 kStoreDoubleword
51};
52
Chris Larsen14500822015-10-01 11:35:18 -070053// Used to test the values returned by ClassS/ClassD.
54enum FPClassMaskType {
55 kSignalingNaN = 0x001,
56 kQuietNaN = 0x002,
57 kNegativeInfinity = 0x004,
58 kNegativeNormal = 0x008,
59 kNegativeSubnormal = 0x010,
60 kNegativeZero = 0x020,
61 kPositiveInfinity = 0x040,
62 kPositiveNormal = 0x080,
63 kPositiveSubnormal = 0x100,
64 kPositiveZero = 0x200,
65};
66
Alexey Frunzea0e87b02015-09-24 22:57:20 -070067class Mips64Label : public Label {
68 public:
69 Mips64Label() : prev_branch_id_plus_one_(0) {}
70
71 Mips64Label(Mips64Label&& src)
72 : Label(std::move(src)), prev_branch_id_plus_one_(src.prev_branch_id_plus_one_) {}
73
74 private:
75 uint32_t prev_branch_id_plus_one_; // To get distance from preceding branch, if any.
76
77 friend class Mips64Assembler;
78 DISALLOW_COPY_AND_ASSIGN(Mips64Label);
79};
80
81// Slowpath entered when Thread::Current()->_exception is non-null.
82class Mips64ExceptionSlowPath {
83 public:
84 explicit Mips64ExceptionSlowPath(Mips64ManagedRegister scratch, size_t stack_adjust)
85 : scratch_(scratch), stack_adjust_(stack_adjust) {}
86
87 Mips64ExceptionSlowPath(Mips64ExceptionSlowPath&& src)
88 : scratch_(src.scratch_),
89 stack_adjust_(src.stack_adjust_),
90 exception_entry_(std::move(src.exception_entry_)) {}
91
92 private:
93 Mips64Label* Entry() { return &exception_entry_; }
94 const Mips64ManagedRegister scratch_;
95 const size_t stack_adjust_;
96 Mips64Label exception_entry_;
97
98 friend class Mips64Assembler;
99 DISALLOW_COPY_AND_ASSIGN(Mips64ExceptionSlowPath);
100};
101
Andreas Gampe57b34292015-01-14 15:45:59 -0800102class Mips64Assembler FINAL : public Assembler {
103 public:
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700104 Mips64Assembler()
105 : overwriting_(false),
106 overwrite_location_(0),
107 last_position_adjustment_(0),
108 last_old_position_(0),
109 last_branch_id_(0) {
110 cfi().DelayEmittingAdvancePCs();
111 }
112
113 virtual ~Mips64Assembler() {
114 for (auto& branch : branches_) {
115 CHECK(branch.IsResolved());
116 }
117 }
Andreas Gampe57b34292015-01-14 15:45:59 -0800118
119 // Emit Machine Instructions.
Andreas Gampe57b34292015-01-14 15:45:59 -0800120 void Addu(GpuRegister rd, GpuRegister rs, GpuRegister rt);
121 void Addiu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700122 void Daddu(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64
123 void Daddiu(GpuRegister rt, GpuRegister rs, uint16_t imm16); // MIPS64
Andreas Gampe57b34292015-01-14 15:45:59 -0800124 void Subu(GpuRegister rd, GpuRegister rs, GpuRegister rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700125 void Dsubu(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64
126
Alexey Frunzec857c742015-09-23 15:12:39 -0700127 void MulR6(GpuRegister rd, GpuRegister rs, GpuRegister rt);
128 void MuhR6(GpuRegister rd, GpuRegister rs, GpuRegister rt);
129 void DivR6(GpuRegister rd, GpuRegister rs, GpuRegister rt);
130 void ModR6(GpuRegister rd, GpuRegister rs, GpuRegister rt);
131 void DivuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt);
132 void ModuR6(GpuRegister rd, GpuRegister rs, GpuRegister rt);
133 void Dmul(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64
134 void Dmuh(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64
135 void Ddiv(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64
136 void Dmod(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64
137 void Ddivu(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64
138 void Dmodu(GpuRegister rd, GpuRegister rs, GpuRegister rt); // MIPS64
Andreas Gampe57b34292015-01-14 15:45:59 -0800139
140 void And(GpuRegister rd, GpuRegister rs, GpuRegister rt);
141 void Andi(GpuRegister rt, GpuRegister rs, uint16_t imm16);
142 void Or(GpuRegister rd, GpuRegister rs, GpuRegister rt);
143 void Ori(GpuRegister rt, GpuRegister rs, uint16_t imm16);
144 void Xor(GpuRegister rd, GpuRegister rs, GpuRegister rt);
145 void Xori(GpuRegister rt, GpuRegister rs, uint16_t imm16);
146 void Nor(GpuRegister rd, GpuRegister rs, GpuRegister rt);
147
Alexey Frunzec857c742015-09-23 15:12:39 -0700148 void Bitswap(GpuRegister rd, GpuRegister rt);
149 void Dbitswap(GpuRegister rd, GpuRegister rt);
150 void Seb(GpuRegister rd, GpuRegister rt);
151 void Seh(GpuRegister rd, GpuRegister rt);
152 void Dsbh(GpuRegister rd, GpuRegister rt);
153 void Dshd(GpuRegister rd, GpuRegister rt);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700154 void Dext(GpuRegister rs, GpuRegister rt, int pos, int size_less_one); // MIPS64
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700155 void Wsbh(GpuRegister rd, GpuRegister rt);
156 void Sc(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
157 void Scd(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
158 void Ll(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
159 void Lld(GpuRegister rt, GpuRegister base, int16_t imm9 = 0);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700160
161 void Sll(GpuRegister rd, GpuRegister rt, int shamt);
162 void Srl(GpuRegister rd, GpuRegister rt, int shamt);
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700163 void Rotr(GpuRegister rd, GpuRegister rt, int shamt);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700164 void Sra(GpuRegister rd, GpuRegister rt, int shamt);
165 void Sllv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
166 void Srlv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
Chris Larsen9aebff22015-09-22 17:54:15 -0700167 void Rotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700168 void Srav(GpuRegister rd, GpuRegister rt, GpuRegister rs);
169 void Dsll(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
170 void Dsrl(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
Chris Larsen9aebff22015-09-22 17:54:15 -0700171 void Drotr(GpuRegister rd, GpuRegister rt, int shamt);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700172 void Dsra(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
173 void Dsll32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
174 void Dsrl32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
Chris Larsen9aebff22015-09-22 17:54:15 -0700175 void Drotr32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
Alexey Frunze4dda3372015-06-01 18:31:49 -0700176 void Dsra32(GpuRegister rd, GpuRegister rt, int shamt); // MIPS64
177 void Dsllv(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64
178 void Dsrlv(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64
Chris Larsen9aebff22015-09-22 17:54:15 -0700179 void Drotrv(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64
Alexey Frunze4dda3372015-06-01 18:31:49 -0700180 void Dsrav(GpuRegister rd, GpuRegister rt, GpuRegister rs); // MIPS64
Andreas Gampe57b34292015-01-14 15:45:59 -0800181
182 void Lb(GpuRegister rt, GpuRegister rs, uint16_t imm16);
183 void Lh(GpuRegister rt, GpuRegister rs, uint16_t imm16);
184 void Lw(GpuRegister rt, GpuRegister rs, uint16_t imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700185 void Ld(GpuRegister rt, GpuRegister rs, uint16_t imm16); // MIPS64
Andreas Gampe57b34292015-01-14 15:45:59 -0800186 void Lbu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
187 void Lhu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700188 void Lwu(GpuRegister rt, GpuRegister rs, uint16_t imm16); // MIPS64
Andreas Gampe57b34292015-01-14 15:45:59 -0800189 void Lui(GpuRegister rt, uint16_t imm16);
Alexey Frunzec857c742015-09-23 15:12:39 -0700190 void Dahi(GpuRegister rs, uint16_t imm16); // MIPS64
191 void Dati(GpuRegister rs, uint16_t imm16); // MIPS64
Alexey Frunze4dda3372015-06-01 18:31:49 -0700192 void Sync(uint32_t stype);
Andreas Gampe57b34292015-01-14 15:45:59 -0800193
194 void Sb(GpuRegister rt, GpuRegister rs, uint16_t imm16);
195 void Sh(GpuRegister rt, GpuRegister rs, uint16_t imm16);
196 void Sw(GpuRegister rt, GpuRegister rs, uint16_t imm16);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700197 void Sd(GpuRegister rt, GpuRegister rs, uint16_t imm16); // MIPS64
Andreas Gampe57b34292015-01-14 15:45:59 -0800198
199 void Slt(GpuRegister rd, GpuRegister rs, GpuRegister rt);
200 void Sltu(GpuRegister rd, GpuRegister rs, GpuRegister rt);
201 void Slti(GpuRegister rt, GpuRegister rs, uint16_t imm16);
202 void Sltiu(GpuRegister rt, GpuRegister rs, uint16_t imm16);
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700203 void Seleqz(GpuRegister rd, GpuRegister rs, GpuRegister rt);
204 void Selnez(GpuRegister rd, GpuRegister rs, GpuRegister rt);
205 void Clz(GpuRegister rd, GpuRegister rs);
206 void Clo(GpuRegister rd, GpuRegister rs);
207 void Dclz(GpuRegister rd, GpuRegister rs);
208 void Dclo(GpuRegister rd, GpuRegister rs);
Andreas Gampe57b34292015-01-14 15:45:59 -0800209
Alexey Frunze4dda3372015-06-01 18:31:49 -0700210 void Jalr(GpuRegister rd, GpuRegister rs);
Andreas Gampe57b34292015-01-14 15:45:59 -0800211 void Jalr(GpuRegister rs);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700212 void Jr(GpuRegister rs);
Alexey Frunzec857c742015-09-23 15:12:39 -0700213 void Auipc(GpuRegister rs, uint16_t imm16);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700214 void Addiupc(GpuRegister rs, uint32_t imm19);
215 void Bc(uint32_t imm26);
Alexey Frunzec857c742015-09-23 15:12:39 -0700216 void Jic(GpuRegister rt, uint16_t imm16);
217 void Jialc(GpuRegister rt, uint16_t imm16);
218 void Bltc(GpuRegister rs, GpuRegister rt, uint16_t imm16);
219 void Bltzc(GpuRegister rt, uint16_t imm16);
220 void Bgtzc(GpuRegister rt, uint16_t imm16);
221 void Bgec(GpuRegister rs, GpuRegister rt, uint16_t imm16);
222 void Bgezc(GpuRegister rt, uint16_t imm16);
223 void Blezc(GpuRegister rt, uint16_t imm16);
224 void Bltuc(GpuRegister rs, GpuRegister rt, uint16_t imm16);
225 void Bgeuc(GpuRegister rs, GpuRegister rt, uint16_t imm16);
226 void Beqc(GpuRegister rs, GpuRegister rt, uint16_t imm16);
227 void Bnec(GpuRegister rs, GpuRegister rt, uint16_t imm16);
228 void Beqzc(GpuRegister rs, uint32_t imm21);
229 void Bnezc(GpuRegister rs, uint32_t imm21);
Andreas Gampe57b34292015-01-14 15:45:59 -0800230
231 void AddS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
232 void SubS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
233 void MulS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
234 void DivS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
235 void AddD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
236 void SubD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
237 void MulD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
238 void DivD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700239 void SqrtS(FpuRegister fd, FpuRegister fs);
240 void SqrtD(FpuRegister fd, FpuRegister fs);
241 void AbsS(FpuRegister fd, FpuRegister fs);
242 void AbsD(FpuRegister fd, FpuRegister fs);
Andreas Gampe57b34292015-01-14 15:45:59 -0800243 void MovS(FpuRegister fd, FpuRegister fs);
244 void MovD(FpuRegister fd, FpuRegister fs);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700245 void NegS(FpuRegister fd, FpuRegister fs);
246 void NegD(FpuRegister fd, FpuRegister fs);
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700247 void RoundLS(FpuRegister fd, FpuRegister fs);
248 void RoundLD(FpuRegister fd, FpuRegister fs);
249 void RoundWS(FpuRegister fd, FpuRegister fs);
250 void RoundWD(FpuRegister fd, FpuRegister fs);
251 void CeilLS(FpuRegister fd, FpuRegister fs);
252 void CeilLD(FpuRegister fd, FpuRegister fs);
253 void CeilWS(FpuRegister fd, FpuRegister fs);
254 void CeilWD(FpuRegister fd, FpuRegister fs);
255 void FloorLS(FpuRegister fd, FpuRegister fs);
256 void FloorLD(FpuRegister fd, FpuRegister fs);
257 void FloorWS(FpuRegister fd, FpuRegister fs);
258 void FloorWD(FpuRegister fd, FpuRegister fs);
259 void SelS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
260 void SelD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
261 void RintS(FpuRegister fd, FpuRegister fs);
262 void RintD(FpuRegister fd, FpuRegister fs);
263 void ClassS(FpuRegister fd, FpuRegister fs);
264 void ClassD(FpuRegister fd, FpuRegister fs);
265 void MinS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
266 void MinD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
267 void MaxS(FpuRegister fd, FpuRegister fs, FpuRegister ft);
268 void MaxD(FpuRegister fd, FpuRegister fs, FpuRegister ft);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700269
270 void Cvtsw(FpuRegister fd, FpuRegister fs);
271 void Cvtdw(FpuRegister fd, FpuRegister fs);
272 void Cvtsd(FpuRegister fd, FpuRegister fs);
273 void Cvtds(FpuRegister fd, FpuRegister fs);
Chris Larsen51417632015-10-02 13:24:25 -0700274 void Cvtsl(FpuRegister fd, FpuRegister fs);
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700275 void Cvtdl(FpuRegister fd, FpuRegister fs);
Andreas Gampe57b34292015-01-14 15:45:59 -0800276
277 void Mfc1(GpuRegister rt, FpuRegister fs);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700278 void Mtc1(GpuRegister rt, FpuRegister fs);
279 void Dmfc1(GpuRegister rt, FpuRegister fs); // MIPS64
280 void Dmtc1(GpuRegister rt, FpuRegister fs); // MIPS64
Andreas Gampe57b34292015-01-14 15:45:59 -0800281 void Lwc1(FpuRegister ft, GpuRegister rs, uint16_t imm16);
282 void Ldc1(FpuRegister ft, GpuRegister rs, uint16_t imm16);
283 void Swc1(FpuRegister ft, GpuRegister rs, uint16_t imm16);
284 void Sdc1(FpuRegister ft, GpuRegister rs, uint16_t imm16);
285
286 void Break();
287 void Nop();
Alexey Frunze4dda3372015-06-01 18:31:49 -0700288 void Move(GpuRegister rd, GpuRegister rs);
289 void Clear(GpuRegister rd);
290 void Not(GpuRegister rd, GpuRegister rs);
Andreas Gampe57b34292015-01-14 15:45:59 -0800291
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700292 // Higher level composite instructions.
Alexey Frunze4dda3372015-06-01 18:31:49 -0700293 void LoadConst32(GpuRegister rd, int32_t value);
294 void LoadConst64(GpuRegister rd, int64_t value); // MIPS64
295
Alexey Frunze4dda3372015-06-01 18:31:49 -0700296 void Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp = AT); // MIPS64
297
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700298 void Bind(Label* label) OVERRIDE {
299 Bind(down_cast<Mips64Label*>(label));
Andreas Gampe85b62f22015-09-09 13:15:38 -0700300 }
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700301 void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
302 UNIMPLEMENTED(FATAL) << "Do not use Jump for MIPS64";
303 }
304
305 void Bind(Mips64Label* label);
306 void Bc(Mips64Label* label);
307 void Jialc(Mips64Label* label, GpuRegister indirect_reg);
308 void Bltc(GpuRegister rs, GpuRegister rt, Mips64Label* label);
309 void Bltzc(GpuRegister rt, Mips64Label* label);
310 void Bgtzc(GpuRegister rt, Mips64Label* label);
311 void Bgec(GpuRegister rs, GpuRegister rt, Mips64Label* label);
312 void Bgezc(GpuRegister rt, Mips64Label* label);
313 void Blezc(GpuRegister rt, Mips64Label* label);
314 void Bltuc(GpuRegister rs, GpuRegister rt, Mips64Label* label);
315 void Bgeuc(GpuRegister rs, GpuRegister rt, Mips64Label* label);
316 void Beqc(GpuRegister rs, GpuRegister rt, Mips64Label* label);
317 void Bnec(GpuRegister rs, GpuRegister rt, Mips64Label* label);
318 void Beqzc(GpuRegister rs, Mips64Label* label);
319 void Bnezc(GpuRegister rs, Mips64Label* label);
Andreas Gampe57b34292015-01-14 15:45:59 -0800320
321 void EmitLoad(ManagedRegister m_dst, GpuRegister src_register, int32_t src_offset, size_t size);
322 void LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base, int32_t offset);
323 void LoadFpuFromOffset(LoadOperandType type, FpuRegister reg, GpuRegister base, int32_t offset);
324 void StoreToOffset(StoreOperandType type, GpuRegister reg, GpuRegister base, int32_t offset);
325 void StoreFpuToOffset(StoreOperandType type, FpuRegister reg, GpuRegister base, int32_t offset);
326
327 // Emit data (e.g. encoded instruction or immediate) to the instruction stream.
Alexey Frunze4dda3372015-06-01 18:31:49 -0700328 void Emit(uint32_t value);
Andreas Gampe57b34292015-01-14 15:45:59 -0800329
330 //
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700331 // Overridden common assembler high-level functionality.
Andreas Gampe57b34292015-01-14 15:45:59 -0800332 //
333
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700334 // Emit code that will create an activation on the stack.
Andreas Gampe57b34292015-01-14 15:45:59 -0800335 void BuildFrame(size_t frame_size, ManagedRegister method_reg,
336 const std::vector<ManagedRegister>& callee_save_regs,
337 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE;
338
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700339 // Emit code that will remove an activation from the stack.
Andreas Gampe57b34292015-01-14 15:45:59 -0800340 void RemoveFrame(size_t frame_size,
341 const std::vector<ManagedRegister>& callee_save_regs) OVERRIDE;
342
343 void IncreaseFrameSize(size_t adjust) OVERRIDE;
344 void DecreaseFrameSize(size_t adjust) OVERRIDE;
345
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700346 // Store routines.
Andreas Gampe57b34292015-01-14 15:45:59 -0800347 void Store(FrameOffset offs, ManagedRegister msrc, size_t size) OVERRIDE;
348 void StoreRef(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
349 void StoreRawPtr(FrameOffset dest, ManagedRegister msrc) OVERRIDE;
350
351 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE;
352
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700353 void StoreStackOffsetToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs, FrameOffset fr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -0800354 ManagedRegister mscratch) OVERRIDE;
355
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700356 void StoreStackPointerToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs) OVERRIDE;
Andreas Gampe57b34292015-01-14 15:45:59 -0800357
358 void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off,
359 ManagedRegister mscratch) OVERRIDE;
360
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700361 // Load routines.
Andreas Gampe57b34292015-01-14 15:45:59 -0800362 void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE;
363
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700364 void LoadFromThread64(ManagedRegister mdest,
365 ThreadOffset<kMipsDoublewordSize> src,
366 size_t size) OVERRIDE;
Andreas Gampe57b34292015-01-14 15:45:59 -0800367
Mathieu Chartiere401d142015-04-22 13:56:20 -0700368 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
Andreas Gampe57b34292015-01-14 15:45:59 -0800369
Mathieu Chartiere401d142015-04-22 13:56:20 -0700370 void LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
Roland Levillain4d027112015-07-01 15:41:14 +0100371 bool unpoison_reference) OVERRIDE;
Andreas Gampe57b34292015-01-14 15:45:59 -0800372
373 void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
374
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700375 void LoadRawPtrFromThread64(ManagedRegister mdest,
376 ThreadOffset<kMipsDoublewordSize> offs) OVERRIDE;
Andreas Gampe57b34292015-01-14 15:45:59 -0800377
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700378 // Copying routines.
Andreas Gampe57b34292015-01-14 15:45:59 -0800379 void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE;
380
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700381 void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset<kMipsDoublewordSize> thr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -0800382 ManagedRegister mscratch) OVERRIDE;
383
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700384 void CopyRawPtrToThread64(ThreadOffset<kMipsDoublewordSize> thr_offs, FrameOffset fr_offs,
Andreas Gampe57b34292015-01-14 15:45:59 -0800385 ManagedRegister mscratch) OVERRIDE;
386
387 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE;
388
389 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE;
390
391 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister mscratch,
392 size_t size) OVERRIDE;
393
394 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
395 ManagedRegister mscratch, size_t size) OVERRIDE;
396
397 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister mscratch,
398 size_t size) OVERRIDE;
399
400 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset,
401 ManagedRegister mscratch, size_t size) OVERRIDE;
402
403 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
404 ManagedRegister mscratch, size_t size) OVERRIDE;
405
406 void MemoryBarrier(ManagedRegister) OVERRIDE;
407
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700408 // Sign extension.
Andreas Gampe57b34292015-01-14 15:45:59 -0800409 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE;
410
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700411 // Zero extension.
Andreas Gampe57b34292015-01-14 15:45:59 -0800412 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE;
413
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700414 // Exploit fast access in managed code to Thread::Current().
Andreas Gampe57b34292015-01-14 15:45:59 -0800415 void GetCurrentThread(ManagedRegister tr) OVERRIDE;
416 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister mscratch) OVERRIDE;
417
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700418 // Set up out_reg to hold a Object** into the handle scope, or to be null if the
Andreas Gampe57b34292015-01-14 15:45:59 -0800419 // value is null and null_allowed. in_reg holds a possibly stale reference
420 // that can be used to avoid loading the handle scope entry to see if the value is
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700421 // null.
Andreas Gampe57b34292015-01-14 15:45:59 -0800422 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
423 ManagedRegister in_reg, bool null_allowed) OVERRIDE;
424
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700425 // Set up out_off to hold a Object** into the handle scope, or to be null if the
Andreas Gampe57b34292015-01-14 15:45:59 -0800426 // value is null and null_allowed.
427 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, ManagedRegister
428 mscratch, bool null_allowed) OVERRIDE;
429
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700430 // src holds a handle scope entry (Object**) load this into dst.
Andreas Gampe57b34292015-01-14 15:45:59 -0800431 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE;
432
433 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
434 // know that src may not be null.
435 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE;
436 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE;
437
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700438 // Call to address held at [base+offset].
Andreas Gampe57b34292015-01-14 15:45:59 -0800439 void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE;
440 void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE;
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700441 void CallFromThread64(ThreadOffset<kMipsDoublewordSize> offset,
442 ManagedRegister mscratch) OVERRIDE;
Andreas Gampe57b34292015-01-14 15:45:59 -0800443
444 // Generate code to check if Thread::Current()->exception_ is non-null
445 // and branch to a ExceptionSlowPath if it is.
446 void ExceptionPoll(ManagedRegister mscratch, size_t stack_adjust) OVERRIDE;
447
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700448 // Emit slow paths queued during assembly and promote short branches to long if needed.
449 void FinalizeCode() OVERRIDE;
450
451 // Emit branches and finalize all instructions.
452 void FinalizeInstructions(const MemoryRegion& region);
453
454 // Returns the (always-)current location of a label (can be used in class CodeGeneratorMIPS64,
455 // must be used instead of Mips64Label::GetPosition()).
456 uint32_t GetLabelLocation(Mips64Label* label) const;
457
458 // Get the final position of a label after local fixup based on the old position
459 // recorded before FinalizeCode().
460 uint32_t GetAdjustedPosition(uint32_t old_position);
461
462 enum BranchCondition {
463 kCondLT,
464 kCondGE,
465 kCondLE,
466 kCondGT,
467 kCondLTZ,
468 kCondGEZ,
469 kCondLEZ,
470 kCondGTZ,
471 kCondEQ,
472 kCondNE,
473 kCondEQZ,
474 kCondNEZ,
475 kCondLTU,
476 kCondGEU,
477 kUncond,
478 };
479 friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs);
480
Andreas Gampe57b34292015-01-14 15:45:59 -0800481 private:
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700482 class Branch {
483 public:
484 enum Type {
485 // Short branches.
486 kUncondBranch,
487 kCondBranch,
488 kCall,
489 // Long branches.
490 kLongUncondBranch,
491 kLongCondBranch,
492 kLongCall,
493 };
494
495 // Bit sizes of offsets defined as enums to minimize chance of typos.
496 enum OffsetBits {
497 kOffset16 = 16,
498 kOffset18 = 18,
499 kOffset21 = 21,
500 kOffset23 = 23,
501 kOffset28 = 28,
502 kOffset32 = 32,
503 };
504
505 static constexpr uint32_t kUnresolved = 0xffffffff; // Unresolved target_
506 static constexpr int32_t kMaxBranchLength = 32;
507 static constexpr int32_t kMaxBranchSize = kMaxBranchLength * sizeof(uint32_t);
508
509 struct BranchInfo {
510 // Branch length as a number of 4-byte-long instructions.
511 uint32_t length;
512 // Ordinal number (0-based) of the first (or the only) instruction that contains the branch's
513 // PC-relative offset (or its most significant 16-bit half, which goes first).
514 uint32_t instr_offset;
515 // Different MIPS instructions with PC-relative offsets apply said offsets to slightly
516 // different origins, e.g. to PC or PC+4. Encode the origin distance (as a number of 4-byte
517 // instructions) from the instruction containing the offset.
518 uint32_t pc_org;
519 // How large (in bits) a PC-relative offset can be for a given type of branch (kCondBranch is
520 // an exception: use kOffset23 for beqzc/bnezc).
521 OffsetBits offset_size;
522 // Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift
523 // count.
524 int offset_shift;
525 };
526 static const BranchInfo branch_info_[/* Type */];
527
528 // Unconditional branch.
529 Branch(uint32_t location, uint32_t target);
530 // Conditional branch.
531 Branch(uint32_t location,
532 uint32_t target,
533 BranchCondition condition,
534 GpuRegister lhs_reg,
535 GpuRegister rhs_reg = ZERO);
536 // Call (branch and link) that stores the target address in a given register (i.e. T9).
537 Branch(uint32_t location, uint32_t target, GpuRegister indirect_reg);
538
539 // Some conditional branches with lhs = rhs are effectively NOPs, while some
540 // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs.
541 // So, we need a way to identify such branches in order to emit no instructions for them
542 // or change them to unconditional.
543 static bool IsNop(BranchCondition condition, GpuRegister lhs, GpuRegister rhs);
544 static bool IsUncond(BranchCondition condition, GpuRegister lhs, GpuRegister rhs);
545
546 static BranchCondition OppositeCondition(BranchCondition cond);
547
548 Type GetType() const;
549 BranchCondition GetCondition() const;
550 GpuRegister GetLeftRegister() const;
551 GpuRegister GetRightRegister() const;
552 uint32_t GetTarget() const;
553 uint32_t GetLocation() const;
554 uint32_t GetOldLocation() const;
555 uint32_t GetLength() const;
556 uint32_t GetOldLength() const;
557 uint32_t GetSize() const;
558 uint32_t GetOldSize() const;
559 uint32_t GetEndLocation() const;
560 uint32_t GetOldEndLocation() const;
561 bool IsLong() const;
562 bool IsResolved() const;
563
564 // Returns the bit size of the signed offset that the branch instruction can handle.
565 OffsetBits GetOffsetSize() const;
566
567 // Calculates the distance between two byte locations in the assembler buffer and
568 // returns the number of bits needed to represent the distance as a signed integer.
569 //
570 // Branch instructions have signed offsets of 16, 19 (addiupc), 21 (beqzc/bnezc),
571 // and 26 (bc) bits, which are additionally shifted left 2 positions at run time.
572 //
573 // Composite branches (made of several instructions) with longer reach have 32-bit
574 // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first).
575 // The composite branches cover the range of PC + ~+/-2GB. The range is not end-to-end,
576 // however. Consider the following implementation of a long unconditional branch, for
577 // example:
578 //
579 // auipc at, offset_31_16 // at = pc + sign_extend(offset_31_16) << 16
580 // jic at, offset_15_0 // pc = at + sign_extend(offset_15_0)
581 //
582 // Both of the above instructions take 16-bit signed offsets as immediate operands.
583 // When bit 15 of offset_15_0 is 1, it effectively causes subtraction of 0x10000
584 // due to sign extension. This must be compensated for by incrementing offset_31_16
585 // by 1. offset_31_16 can only be incremented by 1 if it's not 0x7FFF. If it is
586 // 0x7FFF, adding 1 will overflow the positive offset into the negative range.
587 // Therefore, the long branch range is something like from PC - 0x80000000 to
588 // PC + 0x7FFF7FFF, IOW, shorter by 32KB on one side.
589 //
590 // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special
591 // case with the addiu instruction and a 16 bit offset.
592 static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target);
593
594 // Resolve a branch when the target is known.
595 void Resolve(uint32_t target);
596
597 // Relocate a branch by a given delta if needed due to expansion of this or another
598 // branch at a given location by this delta (just changes location_ and target_).
599 void Relocate(uint32_t expand_location, uint32_t delta);
600
601 // If the branch is short, changes its type to long.
602 void PromoteToLong();
603
604 // If necessary, updates the type by promoting a short branch to a long branch
605 // based on the branch location and target. Returns the amount (in bytes) by
606 // which the branch size has increased.
607 // max_short_distance caps the maximum distance between location_ and target_
608 // that is allowed for short branches. This is for debugging/testing purposes.
609 // max_short_distance = 0 forces all short branches to become long.
610 // Use the implicit default argument when not debugging/testing.
611 uint32_t PromoteIfNeeded(uint32_t max_short_distance = std::numeric_limits<uint32_t>::max());
612
613 // Returns the location of the instruction(s) containing the offset.
614 uint32_t GetOffsetLocation() const;
615
616 // Calculates and returns the offset ready for encoding in the branch instruction(s).
617 uint32_t GetOffset() const;
618
619 private:
620 // Completes branch construction by determining and recording its type.
621 void InitializeType(bool is_call);
622 // Helper for the above.
623 void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
624
625 uint32_t old_location_; // Offset into assembler buffer in bytes.
626 uint32_t location_; // Offset into assembler buffer in bytes.
627 uint32_t target_; // Offset into assembler buffer in bytes.
628
629 GpuRegister lhs_reg_; // Left-hand side register in conditional branches or
630 // indirect call register.
631 GpuRegister rhs_reg_; // Right-hand side register in conditional branches.
632 BranchCondition condition_; // Condition for conditional branches.
633
634 Type type_; // Current type of the branch.
635 Type old_type_; // Initial type of the branch.
636 };
637 friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs);
638 friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs);
639
Andreas Gampe57b34292015-01-14 15:45:59 -0800640 void EmitR(int opcode, GpuRegister rs, GpuRegister rt, GpuRegister rd, int shamt, int funct);
Chris Larsen2fadd7b2015-08-14 14:56:10 -0700641 void EmitRsd(int opcode, GpuRegister rs, GpuRegister rd, int shamt, int funct);
642 void EmitRtd(int opcode, GpuRegister rt, GpuRegister rd, int shamt, int funct);
Andreas Gampe57b34292015-01-14 15:45:59 -0800643 void EmitI(int opcode, GpuRegister rs, GpuRegister rt, uint16_t imm);
Alexey Frunze4dda3372015-06-01 18:31:49 -0700644 void EmitI21(int opcode, GpuRegister rs, uint32_t imm21);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700645 void EmitI26(int opcode, uint32_t imm26);
Andreas Gampe57b34292015-01-14 15:45:59 -0800646 void EmitFR(int opcode, int fmt, FpuRegister ft, FpuRegister fs, FpuRegister fd, int funct);
647 void EmitFI(int opcode, int fmt, FpuRegister rt, uint16_t imm);
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700648 void EmitBcondc(BranchCondition cond, GpuRegister rs, GpuRegister rt, uint32_t imm16_21);
649
650 void Buncond(Mips64Label* label);
651 void Bcond(Mips64Label* label,
652 BranchCondition condition,
653 GpuRegister lhs,
654 GpuRegister rhs = ZERO);
655 void Call(Mips64Label* label, GpuRegister indirect_reg);
656 void FinalizeLabeledBranch(Mips64Label* label);
657
658 Branch* GetBranch(uint32_t branch_id);
659 const Branch* GetBranch(uint32_t branch_id) const;
660
661 void PromoteBranches();
662 void EmitBranch(Branch* branch);
663 void EmitBranches();
664 void PatchCFI();
665
666 // Emits exception block.
667 void EmitExceptionPoll(Mips64ExceptionSlowPath* exception);
668
669 // List of exception blocks to generate at the end of the code cache.
670 std::vector<Mips64ExceptionSlowPath> exception_blocks_;
671
672 std::vector<Branch> branches_;
673
674 // Whether appending instructions at the end of the buffer or overwriting the existing ones.
675 bool overwriting_;
676 // The current overwrite location.
677 uint32_t overwrite_location_;
678
679 // Data for AdjustedPosition(), see the description there.
680 uint32_t last_position_adjustment_;
681 uint32_t last_old_position_;
682 uint32_t last_branch_id_;
Andreas Gampe57b34292015-01-14 15:45:59 -0800683
Andreas Gampe57b34292015-01-14 15:45:59 -0800684 DISALLOW_COPY_AND_ASSIGN(Mips64Assembler);
685};
686
Andreas Gampe57b34292015-01-14 15:45:59 -0800687} // namespace mips64
688} // namespace art
689
690#endif // ART_COMPILER_UTILS_MIPS64_ASSEMBLER_MIPS64_H_