blob: c802c27ea6b0c0cab526fe8a5a39d348346af239 [file] [log] [blame]
Dave Allison65fcc2c2014-04-28 13:45:27 -07001/*
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_ARM_ASSEMBLER_THUMB2_H_
18#define ART_COMPILER_UTILS_ARM_ASSEMBLER_THUMB2_H_
19
Vladimir Markocf93a5c2015-06-16 11:33:24 +000020#include <deque>
Dave Allison65fcc2c2014-04-28 13:45:27 -070021#include <vector>
22
23#include "base/logging.h"
24#include "constants_arm.h"
25#include "utils/arm/managed_register_arm.h"
26#include "utils/arm/assembler_arm.h"
Vladimir Marko6b756b52015-07-14 11:58:38 +010027#include "utils/array_ref.h"
Dave Allison65fcc2c2014-04-28 13:45:27 -070028#include "offsets.h"
Dave Allison65fcc2c2014-04-28 13:45:27 -070029
30namespace art {
31namespace arm {
32
Dave Allison65fcc2c2014-04-28 13:45:27 -070033class Thumb2Assembler FINAL : public ArmAssembler {
34 public:
Nicolas Geoffrayd126ba12015-05-20 11:25:27 +010035 explicit Thumb2Assembler(bool can_relocate_branches = true)
36 : can_relocate_branches_(can_relocate_branches),
Nicolas Geoffray8d486732014-07-16 16:23:40 +010037 force_32bit_(false),
38 it_cond_index_(kNoItCondition),
Vladimir Markocf93a5c2015-06-16 11:33:24 +000039 next_condition_(AL),
40 fixups_(),
Vladimir Marko6b756b52015-07-14 11:58:38 +010041 fixup_dependents_(),
Vladimir Markocf93a5c2015-06-16 11:33:24 +000042 literals_(),
43 last_position_adjustment_(0u),
44 last_old_position_(0u),
45 last_fixup_id_(0u) {
Dave Allison65fcc2c2014-04-28 13:45:27 -070046 }
47
48 virtual ~Thumb2Assembler() {
Dave Allison65fcc2c2014-04-28 13:45:27 -070049 }
50
51 bool IsThumb() const OVERRIDE {
52 return true;
53 }
54
55 bool IsForced32Bit() const {
56 return force_32bit_;
57 }
58
Nicolas Geoffrayd126ba12015-05-20 11:25:27 +010059 bool CanRelocateBranches() const {
60 return can_relocate_branches_;
Nicolas Geoffray8d486732014-07-16 16:23:40 +010061 }
62
Vladimir Markocf93a5c2015-06-16 11:33:24 +000063 void FinalizeCode() OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -070064
65 // Data-processing instructions.
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010066 virtual void and_(Register rd, Register rn, const ShifterOperand& so,
67 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -070068
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010069 virtual void eor(Register rd, Register rn, const ShifterOperand& so,
70 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -070071
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010072 virtual void sub(Register rd, Register rn, const ShifterOperand& so,
73 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -070074
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010075 virtual void rsb(Register rd, Register rn, const ShifterOperand& so,
76 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -070077
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010078 virtual void add(Register rd, Register rn, const ShifterOperand& so,
79 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -070080
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010081 virtual void adc(Register rd, Register rn, const ShifterOperand& so,
82 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -070083
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010084 virtual void sbc(Register rd, Register rn, const ShifterOperand& so,
85 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -070086
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010087 virtual void rsc(Register rd, Register rn, const ShifterOperand& so,
88 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -070089
90 void tst(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE;
91
92 void teq(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE;
93
94 void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE;
95
96 void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE;
97
Vladimir Marko73cf0fb2015-07-30 15:07:22 +010098 virtual void orr(Register rd, Register rn, const ShifterOperand& so,
99 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700100
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100101 virtual void mov(Register rd, const ShifterOperand& so,
102 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700103
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100104 virtual void bic(Register rd, Register rn, const ShifterOperand& so,
105 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700106
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100107 virtual void mvn(Register rd, const ShifterOperand& so,
108 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700109
110 // Miscellaneous data-processing instructions.
111 void clz(Register rd, Register rm, Condition cond = AL) OVERRIDE;
112 void movw(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE;
113 void movt(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE;
114
115 // Multiply instructions.
116 void mul(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE;
117 void mla(Register rd, Register rn, Register rm, Register ra,
118 Condition cond = AL) OVERRIDE;
119 void mls(Register rd, Register rn, Register rm, Register ra,
120 Condition cond = AL) OVERRIDE;
Zheng Xuc6667102015-05-15 16:08:45 +0800121 void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
122 Condition cond = AL) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700123 void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
124 Condition cond = AL) OVERRIDE;
125
126 void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE;
127 void udiv(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE;
128
Roland Levillain981e4542014-11-14 11:47:14 +0000129 // Bit field extract instructions.
Roland Levillain51d3fc42014-11-13 14:11:42 +0000130 void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE;
Roland Levillain981e4542014-11-14 11:47:14 +0000131 void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, Condition cond = AL) OVERRIDE;
Roland Levillain51d3fc42014-11-13 14:11:42 +0000132
Dave Allison65fcc2c2014-04-28 13:45:27 -0700133 // Load/store instructions.
134 void ldr(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
135 void str(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
136
137 void ldrb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
138 void strb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
139
140 void ldrh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
141 void strh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
142
143 void ldrsb(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
144 void ldrsh(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
145
Roland Levillain4af147e2015-04-07 13:54:49 +0100146 // Load/store register dual instructions using registers `rd` and `rd` + 1.
Dave Allison65fcc2c2014-04-28 13:45:27 -0700147 void ldrd(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
148 void strd(Register rd, const Address& ad, Condition cond = AL) OVERRIDE;
149
Roland Levillain4af147e2015-04-07 13:54:49 +0100150 // Load/store register dual instructions using registers `rd` and `rd2`.
151 // Note that contrary to the ARM A1 encoding, the Thumb-2 T1 encoding
152 // does not require `rd` to be even, nor `rd2' to be equal to `rd` + 1.
153 void ldrd(Register rd, Register rd2, const Address& ad, Condition cond);
154 void strd(Register rd, Register rd2, const Address& ad, Condition cond);
155
156
Dave Allison65fcc2c2014-04-28 13:45:27 -0700157 void ldm(BlockAddressMode am, Register base,
158 RegList regs, Condition cond = AL) OVERRIDE;
159 void stm(BlockAddressMode am, Register base,
160 RegList regs, Condition cond = AL) OVERRIDE;
161
162 void ldrex(Register rd, Register rn, Condition cond = AL) OVERRIDE;
163 void strex(Register rd, Register rt, Register rn, Condition cond = AL) OVERRIDE;
164
165 void ldrex(Register rd, Register rn, uint16_t imm, Condition cond = AL);
166 void strex(Register rd, Register rt, Register rn, uint16_t imm, Condition cond = AL);
167
Calin Juravle52c48962014-12-16 17:02:57 +0000168 void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) OVERRIDE;
169 void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700170
171 // Miscellaneous instructions.
172 void clrex(Condition cond = AL) OVERRIDE;
173 void nop(Condition cond = AL) OVERRIDE;
174
175 void bkpt(uint16_t imm16) OVERRIDE;
176 void svc(uint32_t imm24) OVERRIDE;
177
178 // If-then
179 void it(Condition firstcond, ItState i1 = kItOmitted,
180 ItState i2 = kItOmitted, ItState i3 = kItOmitted) OVERRIDE;
181
182 void cbz(Register rn, Label* target) OVERRIDE;
183 void cbnz(Register rn, Label* target) OVERRIDE;
184
185 // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles).
186 void vmovsr(SRegister sn, Register rt, Condition cond = AL) OVERRIDE;
187 void vmovrs(Register rt, SRegister sn, Condition cond = AL) OVERRIDE;
188 void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) OVERRIDE;
189 void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) OVERRIDE;
190 void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) OVERRIDE;
191 void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) OVERRIDE;
192 void vmovs(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
193 void vmovd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE;
194
195 // Returns false if the immediate cannot be encoded.
196 bool vmovs(SRegister sd, float s_imm, Condition cond = AL) OVERRIDE;
197 bool vmovd(DRegister dd, double d_imm, Condition cond = AL) OVERRIDE;
198
199 void vldrs(SRegister sd, const Address& ad, Condition cond = AL) OVERRIDE;
200 void vstrs(SRegister sd, const Address& ad, Condition cond = AL) OVERRIDE;
201 void vldrd(DRegister dd, const Address& ad, Condition cond = AL) OVERRIDE;
202 void vstrd(DRegister dd, const Address& ad, Condition cond = AL) OVERRIDE;
203
204 void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
205 void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
206 void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
207 void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
208 void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
209 void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
210 void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
211 void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
212 void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
213 void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
214 void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) OVERRIDE;
215 void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) OVERRIDE;
216
217 void vabss(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
218 void vabsd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE;
219 void vnegs(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
220 void vnegd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE;
221 void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
222 void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE;
223
224 void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE;
225 void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE;
226 void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
227 void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE;
228 void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
229 void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE;
230 void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
231 void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) OVERRIDE;
232 void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
233 void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) OVERRIDE;
234
235 void vcmps(SRegister sd, SRegister sm, Condition cond = AL) OVERRIDE;
236 void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) OVERRIDE;
237 void vcmpsz(SRegister sd, Condition cond = AL) OVERRIDE;
238 void vcmpdz(DRegister dd, Condition cond = AL) OVERRIDE;
239 void vmstat(Condition cond = AL) OVERRIDE; // VMRS APSR_nzcv, FPSCR
240
241 void vpushs(SRegister reg, int nregs, Condition cond = AL) OVERRIDE;
242 void vpushd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
243 void vpops(SRegister reg, int nregs, Condition cond = AL) OVERRIDE;
244 void vpopd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
245
246 // Branch instructions.
247 void b(Label* label, Condition cond = AL);
248 void bl(Label* label, Condition cond = AL);
249 void blx(Label* label);
250 void blx(Register rm, Condition cond = AL) OVERRIDE;
251 void bx(Register rm, Condition cond = AL) OVERRIDE;
252
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100253 virtual void Lsl(Register rd, Register rm, uint32_t shift_imm,
254 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
255 virtual void Lsr(Register rd, Register rm, uint32_t shift_imm,
256 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
257 virtual void Asr(Register rd, Register rm, uint32_t shift_imm,
258 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
259 virtual void Ror(Register rd, Register rm, uint32_t shift_imm,
260 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
261 virtual void Rrx(Register rd, Register rm,
262 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison45fdb932014-06-25 12:37:10 -0700263
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100264 virtual void Lsl(Register rd, Register rm, Register rn,
265 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
266 virtual void Lsr(Register rd, Register rm, Register rn,
267 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
268 virtual void Asr(Register rd, Register rm, Register rn,
269 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
270 virtual void Ror(Register rd, Register rm, Register rn,
271 Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700272
273 void Push(Register rd, Condition cond = AL) OVERRIDE;
274 void Pop(Register rd, Condition cond = AL) OVERRIDE;
275
276 void PushList(RegList regs, Condition cond = AL) OVERRIDE;
277 void PopList(RegList regs, Condition cond = AL) OVERRIDE;
278
279 void Mov(Register rd, Register rm, Condition cond = AL) OVERRIDE;
280
281 void CompareAndBranchIfZero(Register r, Label* label) OVERRIDE;
282 void CompareAndBranchIfNonZero(Register r, Label* label) OVERRIDE;
283
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100284 // Memory barriers.
285 void dmb(DmbOptions flavor) OVERRIDE;
286
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000287 // Get the final position of a label after local fixup based on the old position
288 // recorded before FinalizeCode().
289 uint32_t GetAdjustedPosition(uint32_t old_position) OVERRIDE;
290
291 using ArmAssembler::NewLiteral; // Make the helper template visible.
292
293 Literal* NewLiteral(size_t size, const uint8_t* data) OVERRIDE;
294 void LoadLiteral(Register rt, Literal* literal) OVERRIDE;
295 void LoadLiteral(Register rt, Register rt2, Literal* literal) OVERRIDE;
296 void LoadLiteral(SRegister sd, Literal* literal) OVERRIDE;
297 void LoadLiteral(DRegister dd, Literal* literal) OVERRIDE;
298
Dave Allison65fcc2c2014-04-28 13:45:27 -0700299 // Add signed constant value to rd. May clobber IP.
300 void AddConstant(Register rd, int32_t value, Condition cond = AL) OVERRIDE;
301 void AddConstant(Register rd, Register rn, int32_t value,
302 Condition cond = AL) OVERRIDE;
303 void AddConstantSetFlags(Register rd, Register rn, int32_t value,
304 Condition cond = AL) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700305
306 // Load and Store. May clobber IP.
307 void LoadImmediate(Register rd, int32_t value, Condition cond = AL) OVERRIDE;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700308 void MarkExceptionHandler(Label* label) OVERRIDE;
309 void LoadFromOffset(LoadOperandType type,
310 Register reg,
311 Register base,
312 int32_t offset,
313 Condition cond = AL) OVERRIDE;
314 void StoreToOffset(StoreOperandType type,
315 Register reg,
316 Register base,
317 int32_t offset,
318 Condition cond = AL) OVERRIDE;
319 void LoadSFromOffset(SRegister reg,
320 Register base,
321 int32_t offset,
322 Condition cond = AL) OVERRIDE;
323 void StoreSToOffset(SRegister reg,
324 Register base,
325 int32_t offset,
326 Condition cond = AL) OVERRIDE;
327 void LoadDFromOffset(DRegister reg,
328 Register base,
329 int32_t offset,
330 Condition cond = AL) OVERRIDE;
331 void StoreDToOffset(DRegister reg,
332 Register base,
333 int32_t offset,
334 Condition cond = AL) OVERRIDE;
335
Nicolas Geoffray3bcc8ea2014-11-28 15:00:02 +0000336 bool ShifterOperandCanHold(Register rd,
337 Register rn,
338 Opcode opcode,
339 uint32_t immediate,
340 ShifterOperand* shifter_op) OVERRIDE;
341
Dave Allison65fcc2c2014-04-28 13:45:27 -0700342
Ian Rogers13735952014-10-08 12:43:28 -0700343 static bool IsInstructionForExceptionHandling(uintptr_t pc);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700344
345 // Emit data (e.g. encoded instruction or immediate) to the.
346 // instruction stream.
347 void Emit32(int32_t value); // Emit a 32 bit instruction in thumb format.
348 void Emit16(int16_t value); // Emit a 16 bit instruction in little endian format.
349 void Bind(Label* label) OVERRIDE;
350
351 void MemoryBarrier(ManagedRegister scratch) OVERRIDE;
352
353 // Force the assembler to generate 32 bit instructions.
354 void Force32Bit() {
355 force_32bit_ = true;
356 }
357
358 private:
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000359 typedef uint16_t FixupId;
360
361 // Fixup: branches and literal pool references.
362 //
363 // The thumb2 architecture allows branches to be either 16 or 32 bit instructions. This
364 // depends on both the type of branch and the offset to which it is branching. The 16-bit
365 // cbz and cbnz instructions may also need to be replaced with a separate 16-bit compare
366 // instruction and a 16- or 32-bit branch instruction. Load from a literal pool can also be
367 // 16-bit or 32-bit instruction and, if the method is large, we may need to use a sequence
368 // of instructions to make up for the limited range of load literal instructions (up to
369 // 4KiB for the 32-bit variant). When generating code for these insns we don't know the
370 // size before hand, so we assume it is the smallest available size and determine the final
371 // code offsets and sizes and emit code in FinalizeCode().
372 //
373 // To handle this, we keep a record of every branch and literal pool load in the program.
374 // The actual instruction encoding for these is delayed until we know the final size of
375 // every instruction. When we bind a label to a branch we don't know the final location yet
376 // as some preceding instructions may need to be expanded, so we record a non-final offset.
377 // In FinalizeCode(), we expand the sizes of branches and literal loads that are out of
378 // range. With each expansion, we need to update dependent Fixups, i.e. insntructios with
379 // target on the other side of the expanded insn, as their offsets change and this may
380 // trigger further expansion.
381 //
382 // All Fixups have a 'fixup id' which is a 16 bit unsigned number used to identify the
383 // Fixup. For each unresolved label we keep a singly-linked list of all Fixups pointing
384 // to it, using the fixup ids as links. The first link is stored in the label's position
385 // (the label is linked but not bound), the following links are stored in the code buffer,
386 // in the placeholder where we will eventually emit the actual code.
387
388 class Fixup {
389 public:
390 // Branch type.
391 enum Type : uint8_t {
392 kConditional, // B<cond>.
393 kUnconditional, // B.
394 kUnconditionalLink, // BL.
395 kUnconditionalLinkX, // BLX.
396 kCompareAndBranchXZero, // cbz/cbnz.
397 kLoadLiteralNarrow, // Load narrrow integer literal.
398 kLoadLiteralWide, // Load wide integer literal.
399 kLoadFPLiteralSingle, // Load FP literal single.
400 kLoadFPLiteralDouble, // Load FP literal double.
401 };
402
403 // Calculated size of branch instruction based on type and offset.
404 enum Size : uint8_t {
405 // Branch variants.
406 kBranch16Bit,
407 kBranch32Bit,
408 // NOTE: We don't support branches which would require multiple instructions, i.e.
409 // conditinoal branches beyond +-1MiB and unconditional branches beyond +-16MiB.
410
411 // CBZ/CBNZ variants.
412 kCbxz16Bit, // CBZ/CBNZ rX, label; X < 8; 7-bit positive offset.
413 kCbxz32Bit, // CMP rX, #0 + Bcc label; X < 8; 16-bit Bcc; +-8-bit offset.
414 kCbxz48Bit, // CMP rX, #0 + Bcc label; X < 8; 32-bit Bcc; up to +-1MiB offset.
415
416 // Load integer literal variants.
417 // LDR rX, label; X < 8; 16-bit variant up to 1KiB offset; 2 bytes.
418 kLiteral1KiB,
419 // LDR rX, label; 32-bit variant up to 4KiB offset; 4 bytes.
420 kLiteral4KiB,
421 // MOV rX, imm16 + ADD rX, pc + LDR rX, [rX]; X < 8; up to 64KiB offset; 8 bytes.
422 kLiteral64KiB,
423 // MOV rX, modimm + ADD rX, pc + LDR rX, [rX, #imm12]; up to 1MiB offset; 10 bytes.
424 kLiteral1MiB,
425 // NOTE: We don't provide the 12-byte version of kLiteralFar below where the LDR is 16-bit.
426 // MOV rX, imm16 + MOVT rX, imm16 + ADD rX, pc + LDR rX, [rX]; any offset; 14 bytes.
427 kLiteralFar,
428
429 // Load long or FP literal variants.
430 // VLDR s/dX, label; 32-bit insn, up to 1KiB offset; 4 bytes.
431 kLongOrFPLiteral1KiB,
432 // MOV ip, modimm + ADD ip, pc + VLDR s/dX, [IP, #imm8*4]; up to 256KiB offset; 10 bytes.
433 kLongOrFPLiteral256KiB,
434 // MOV ip, imm16 + MOVT ip, imm16 + ADD ip, pc + VLDR s/dX, [IP]; any offset; 14 bytes.
435 kLongOrFPLiteralFar,
436 };
437
438 // Unresolved branch possibly with a condition.
439 static Fixup Branch(uint32_t location, Type type, Size size = kBranch16Bit,
440 Condition cond = AL) {
441 DCHECK(type == kConditional || type == kUnconditional ||
442 type == kUnconditionalLink || type == kUnconditionalLinkX);
443 DCHECK(size == kBranch16Bit || size == kBranch32Bit);
444 DCHECK(size == kBranch32Bit || (type == kConditional || type == kUnconditional));
445 return Fixup(kNoRegister, kNoRegister, kNoSRegister, kNoDRegister,
446 cond, type, size, location);
447 }
448
449 // Unresolved compare-and-branch instruction with a register and condition (EQ or NE).
450 static Fixup CompareAndBranch(uint32_t location, Register rn, Condition cond) {
451 DCHECK(cond == EQ || cond == NE);
452 return Fixup(rn, kNoRegister, kNoSRegister, kNoDRegister,
453 cond, kCompareAndBranchXZero, kCbxz16Bit, location);
454 }
455
456 // Load narrow literal.
457 static Fixup LoadNarrowLiteral(uint32_t location, Register rt, Size size = kLiteral1KiB) {
458 DCHECK(size == kLiteral1KiB || size == kLiteral4KiB || size == kLiteral64KiB ||
459 size == kLiteral1MiB || size == kLiteralFar);
460 DCHECK(!IsHighRegister(rt) || (size != kLiteral1KiB && size != kLiteral64KiB));
461 return Fixup(rt, kNoRegister, kNoSRegister, kNoDRegister,
462 AL, kLoadLiteralNarrow, size, location);
463 }
464
465 // Load wide literal.
466 static Fixup LoadWideLiteral(uint32_t location, Register rt, Register rt2,
467 Size size = kLongOrFPLiteral1KiB) {
468 DCHECK(size == kLongOrFPLiteral1KiB || size == kLongOrFPLiteral256KiB ||
469 size == kLongOrFPLiteralFar);
470 DCHECK(!IsHighRegister(rt) || (size != kLiteral1KiB && size != kLiteral64KiB));
471 return Fixup(rt, rt2, kNoSRegister, kNoDRegister,
472 AL, kLoadLiteralWide, size, location);
473 }
474
475 // Load FP single literal.
476 static Fixup LoadSingleLiteral(uint32_t location, SRegister sd,
477 Size size = kLongOrFPLiteral1KiB) {
478 DCHECK(size == kLongOrFPLiteral1KiB || size == kLongOrFPLiteral256KiB ||
479 size == kLongOrFPLiteralFar);
480 return Fixup(kNoRegister, kNoRegister, sd, kNoDRegister,
481 AL, kLoadFPLiteralSingle, size, location);
482 }
483
484 // Load FP double literal.
485 static Fixup LoadDoubleLiteral(uint32_t location, DRegister dd,
486 Size size = kLongOrFPLiteral1KiB) {
487 DCHECK(size == kLongOrFPLiteral1KiB || size == kLongOrFPLiteral256KiB ||
488 size == kLongOrFPLiteralFar);
489 return Fixup(kNoRegister, kNoRegister, kNoSRegister, dd,
490 AL, kLoadFPLiteralDouble, size, location);
491 }
492
493 Type GetType() const {
494 return type_;
495 }
496
Vladimir Marko663c9342015-07-22 11:28:14 +0100497 bool IsLoadLiteral() const {
498 return GetType() >= kLoadLiteralNarrow;
499 }
500
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000501 Size GetOriginalSize() const {
502 return original_size_;
503 }
504
505 Size GetSize() const {
506 return size_;
507 }
508
509 uint32_t GetOriginalSizeInBytes() const;
510
511 uint32_t GetSizeInBytes() const;
512
513 uint32_t GetLocation() const {
514 return location_;
515 }
516
517 uint32_t GetAdjustment() const {
518 return adjustment_;
519 }
520
Vladimir Marko6b756b52015-07-14 11:58:38 +0100521 // Prepare the assembler->fixup_dependents_ and each Fixup's dependents_start_/count_.
522 static void PrepareDependents(Thumb2Assembler* assembler);
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000523
Vladimir Marko6b756b52015-07-14 11:58:38 +0100524 ArrayRef<FixupId> Dependents(const Thumb2Assembler& assembler) const {
525 return ArrayRef<FixupId>(assembler.fixup_dependents_.get() + dependents_start_,
526 dependents_count_);
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000527 }
528
529 // Resolve a branch when the target is known.
530 void Resolve(uint32_t target) {
531 DCHECK_EQ(target_, kUnresolved);
532 DCHECK_NE(target, kUnresolved);
533 target_ = target;
534 }
535
536 // Check if the current size is OK for current location_, target_ and adjustment_.
537 // If not, increase the size. Return the size increase, 0 if unchanged.
538 // If the target if after this Fixup, also add the difference to adjustment_,
539 // so that we don't need to consider forward Fixups as their own dependencies.
540 uint32_t AdjustSizeIfNeeded(uint32_t current_code_size);
541
542 // Increase adjustments. This is called for dependents of a Fixup when its size changes.
543 void IncreaseAdjustment(uint32_t increase) {
544 adjustment_ += increase;
545 }
546
547 // Finalize the branch with an adjustment to the location. Both location and target are updated.
548 void Finalize(uint32_t location_adjustment) {
549 DCHECK_NE(target_, kUnresolved);
550 location_ += location_adjustment;
551 target_ += location_adjustment;
552 }
553
554 // Emit the branch instruction into the assembler buffer. This does the
555 // encoding into the thumb instruction.
556 void Emit(AssemblerBuffer* buffer, uint32_t code_size) const;
557
558 private:
559 Fixup(Register rn, Register rt2, SRegister sd, DRegister dd,
560 Condition cond, Type type, Size size, uint32_t location)
561 : rn_(rn),
562 rt2_(rt2),
563 sd_(sd),
564 dd_(dd),
565 cond_(cond),
566 type_(type),
567 original_size_(size), size_(size),
568 location_(location),
569 target_(kUnresolved),
570 adjustment_(0u),
Vladimir Marko6b756b52015-07-14 11:58:38 +0100571 dependents_count_(0u),
572 dependents_start_(0u) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000573 }
574 static size_t SizeInBytes(Size size);
575
576 // The size of padding added before the literal pool.
577 static size_t LiteralPoolPaddingSize(uint32_t current_code_size);
578
579 // Returns the offset from the PC-using insn to the target.
580 int32_t GetOffset(uint32_t current_code_size) const;
581
582 size_t IncreaseSize(Size new_size);
583
584 int32_t LoadWideOrFpEncoding(Register rbase, int32_t offset) const;
585
586 static constexpr uint32_t kUnresolved = 0xffffffff; // Value for target_ for unresolved.
587
588 const Register rn_; // Rn for cbnz/cbz, Rt for literal loads.
589 Register rt2_; // For kLoadLiteralWide.
590 SRegister sd_; // For kLoadFPLiteralSingle.
591 DRegister dd_; // For kLoadFPLiteralDouble.
592 const Condition cond_;
593 const Type type_;
594 Size original_size_;
595 Size size_;
596 uint32_t location_; // Offset into assembler buffer in bytes.
597 uint32_t target_; // Offset into assembler buffer in bytes.
598 uint32_t adjustment_; // The number of extra bytes inserted between location_ and target_.
Vladimir Marko6b756b52015-07-14 11:58:38 +0100599 // Fixups that require adjustment when current size changes are stored in a single
600 // array in the assembler and we store only the start index and count here.
601 uint32_t dependents_count_;
602 uint32_t dependents_start_;
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000603 };
604
Dave Allison65fcc2c2014-04-28 13:45:27 -0700605 // Emit a single 32 or 16 bit data processing instruction.
606 void EmitDataProcessing(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700607 Opcode opcode,
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100608 SetCc set_cc,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700609 Register rn,
610 Register rd,
611 const ShifterOperand& so);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700612
613 // Must the instruction be 32 bits or can it possibly be encoded
614 // in 16 bits?
615 bool Is32BitDataProcessing(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700616 Opcode opcode,
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100617 SetCc set_cc,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700618 Register rn,
619 Register rd,
620 const ShifterOperand& so);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700621
622 // Emit a 32 bit data processing instruction.
623 void Emit32BitDataProcessing(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700624 Opcode opcode,
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100625 SetCc set_cc,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700626 Register rn,
627 Register rd,
628 const ShifterOperand& so);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700629
630 // Emit a 16 bit data processing instruction.
631 void Emit16BitDataProcessing(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700632 Opcode opcode,
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100633 SetCc set_cc,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700634 Register rn,
635 Register rd,
636 const ShifterOperand& so);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700637
638 void Emit16BitAddSub(Condition cond,
639 Opcode opcode,
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100640 SetCc set_cc,
Dave Allison65fcc2c2014-04-28 13:45:27 -0700641 Register rn,
642 Register rd,
643 const ShifterOperand& so);
644
645 uint16_t EmitCompareAndBranch(Register rn, uint16_t prev, bool n);
646
647 void EmitLoadStore(Condition cond,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700648 bool load,
649 bool byte,
650 bool half,
651 bool is_signed,
652 Register rd,
653 const Address& ad);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700654
655 void EmitMemOpAddressMode3(Condition cond,
656 int32_t mode,
657 Register rd,
658 const Address& ad);
659
660 void EmitMultiMemOp(Condition cond,
661 BlockAddressMode am,
662 bool load,
663 Register base,
664 RegList regs);
665
666 void EmitMulOp(Condition cond,
667 int32_t opcode,
668 Register rd,
669 Register rn,
670 Register rm,
671 Register rs);
672
673 void EmitVFPsss(Condition cond,
674 int32_t opcode,
675 SRegister sd,
676 SRegister sn,
677 SRegister sm);
678
679 void EmitVFPddd(Condition cond,
680 int32_t opcode,
681 DRegister dd,
682 DRegister dn,
683 DRegister dm);
684
685 void EmitVFPsd(Condition cond,
686 int32_t opcode,
687 SRegister sd,
688 DRegister dm);
689
690 void EmitVFPds(Condition cond,
691 int32_t opcode,
692 DRegister dd,
693 SRegister sm);
694
695 void EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond);
696
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000697 void EmitBranch(Condition cond, Label* label, bool link, bool x);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700698 static int32_t EncodeBranchOffset(int32_t offset, int32_t inst);
699 static int DecodeBranchOffset(int32_t inst);
700 int32_t EncodeTstOffset(int offset, int32_t inst);
701 int DecodeTstOffset(int32_t inst);
Vladimir Marko73cf0fb2015-07-30 15:07:22 +0100702 void EmitShift(Register rd, Register rm, Shift shift, uint8_t amount,
703 Condition cond = AL, SetCc set_cc = kCcDontCare);
704 void EmitShift(Register rd, Register rn, Shift shift, Register rm,
705 Condition cond = AL, SetCc set_cc = kCcDontCare);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700706
Nicolas Geoffrayd126ba12015-05-20 11:25:27 +0100707 // Whether the assembler can relocate branches. If false, unresolved branches will be
708 // emitted on 32bits.
709 bool can_relocate_branches_;
710
711 // Force the assembler to use 32 bit thumb2 instructions.
712 bool force_32bit_;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700713
714 // IfThen conditions. Used to check that conditional instructions match the preceding IT.
715 Condition it_conditions_[4];
716 uint8_t it_cond_index_;
717 Condition next_condition_;
718
719 void SetItCondition(ItState s, Condition cond, uint8_t index);
720
721 void CheckCondition(Condition cond) {
722 CHECK_EQ(cond, next_condition_);
723
724 // Move to the next condition if there is one.
725 if (it_cond_index_ < 3) {
726 ++it_cond_index_;
727 next_condition_ = it_conditions_[it_cond_index_];
728 } else {
729 next_condition_ = AL;
730 }
731 }
732
733 void CheckConditionLastIt(Condition cond) {
734 if (it_cond_index_ < 3) {
735 // Check that the next condition is AL. This means that the
736 // current condition is the last in the IT block.
737 CHECK_EQ(it_conditions_[it_cond_index_ + 1], AL);
738 }
739 CheckCondition(cond);
740 }
741
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000742 FixupId AddFixup(Fixup fixup) {
743 FixupId fixup_id = static_cast<FixupId>(fixups_.size());
744 fixups_.push_back(fixup);
745 // For iterating using FixupId, we need the next id to be representable.
746 DCHECK_EQ(static_cast<size_t>(static_cast<FixupId>(fixups_.size())), fixups_.size());
747 return fixup_id;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700748 }
749
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000750 Fixup* GetFixup(FixupId fixup_id) {
751 DCHECK_LT(fixup_id, fixups_.size());
752 return &fixups_[fixup_id];
Dave Allison65fcc2c2014-04-28 13:45:27 -0700753 }
754
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000755 void BindLabel(Label* label, uint32_t bound_pc);
756 void BindLiterals();
757 void AdjustFixupIfNeeded(Fixup* fixup, uint32_t* current_code_size,
758 std::deque<FixupId>* fixups_to_recalculate);
759 uint32_t AdjustFixups();
760 void EmitFixups(uint32_t adjusted_code_size);
761 void EmitLiterals();
Dave Allison65fcc2c2014-04-28 13:45:27 -0700762
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000763 static int16_t BEncoding16(int32_t offset, Condition cond);
764 static int32_t BEncoding32(int32_t offset, Condition cond);
765 static int16_t CbxzEncoding16(Register rn, int32_t offset, Condition cond);
766 static int16_t CmpRnImm8Encoding16(Register rn, int32_t value);
767 static int16_t AddRdnRmEncoding16(Register rdn, Register rm);
768 static int32_t MovwEncoding32(Register rd, int32_t value);
769 static int32_t MovtEncoding32(Register rd, int32_t value);
770 static int32_t MovModImmEncoding32(Register rd, int32_t value);
771 static int16_t LdrLitEncoding16(Register rt, int32_t offset);
772 static int32_t LdrLitEncoding32(Register rt, int32_t offset);
773 static int32_t LdrdEncoding32(Register rt, Register rt2, Register rn, int32_t offset);
774 static int32_t VldrsEncoding32(SRegister sd, Register rn, int32_t offset);
775 static int32_t VldrdEncoding32(DRegister dd, Register rn, int32_t offset);
776 static int16_t LdrRtRnImm5Encoding16(Register rt, Register rn, int32_t offset);
777 static int32_t LdrRtRnImm12Encoding(Register rt, Register rn, int32_t offset);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700778
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000779 std::vector<Fixup> fixups_;
Vladimir Marko6b756b52015-07-14 11:58:38 +0100780 std::unique_ptr<FixupId[]> fixup_dependents_;
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000781
782 // Use std::deque<> for literal labels to allow insertions at the end
783 // without invalidating pointers and references to existing elements.
784 std::deque<Literal> literals_;
785
786 // Data for AdjustedPosition(), see the description there.
787 uint32_t last_position_adjustment_;
788 uint32_t last_old_position_;
789 FixupId last_fixup_id_;
Dave Allison65fcc2c2014-04-28 13:45:27 -0700790};
791
792} // namespace arm
793} // namespace art
794
795#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_THUMB2_H_