CACAO
Aarch64Emitter.hpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/aarch64/Aarch64Emitter.hpp
2 
3  Copyright (C) 2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 
6  This file is part of CACAO.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2, or (at
11  your option) any later version.
12 
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  02110-1301, USA.
22 
23 */
24 
25 #ifndef _JIT_COMPILER2_AARCH64_EMITTER
26 #define _JIT_COMPILER2_AARCH64_EMITTER
27 
28 #include <cmath>
29 
33 
34 #include "vm/types.hpp"
35 
36 namespace cacao {
37 namespace jit {
38 namespace compiler2 {
39 namespace aarch64 {
40 
41 class Reg {
42 public:
43  static Reg X(u1 reg) { return Reg(reg, &XConf); }
44  static Reg W(u1 reg) { return Reg(reg, &WConf); }
45  static Reg H(u1 reg) { return Reg(reg, &HConf); }
46  static Reg B(u1 reg) { return Reg(reg, &BConf); }
47 
48  static Reg D(u1 reg) { return Reg(reg, &DConf); }
49  static Reg S(u1 reg) { return Reg(reg, &SConf); }
50 
51  static Reg XZR;
52  static Reg WZR;
53 
54  static Reg XSP;
55  static Reg XFP;
56 
57  u1 r() const { return reg; }
58 
59  u1 sf() const { return conf->sf; }
60  u1 type() const { return conf->type; }
61  u1 size() const { return conf->size; }
62  u1 v() const { return conf->v; }
63  const Reg* zero() const { return conf->zero; }
64 
65 private:
67  u1 sf;
70  u1 v;
71 
72  const Reg* const zero;
73  };
74 
75  explicit Reg(u1 reg, const RegConfiguration* const conf)
76  : reg(reg), conf(conf) {}
77 
79  const RegConfiguration* const conf;
80 
85 
88 };
89 
90 
91 class Shift {
92 public:
93  struct SHIFT {
94  const u1 code;
95  private:
96  SHIFT(u1 code) : code(code) {}
97  friend class Shift;
98  };
99 
100  static const SHIFT LSL;
101  static const SHIFT LSR;
102  static const SHIFT ASR;
103 };
104 
105 
106 class Emitter {
107 private:
110 
111 public:
112  explicit Emitter() : instructions() {}
113 
114  void sbfm(const Reg& rd, const Reg& rn, u1 immr, u1 imms);
115  void sxtw(const Reg& xd, const Reg& wn) { sbfm(xd, wn, 0, 31); }
116  void sxtb(const Reg& rd, const Reg& rn) { sbfm(rd, rn, 0, 7); }
117  void sxth(const Reg& rd, const Reg& rn) { sbfm(rd, rn, 0, 15); }
118 
119  void ubfm(const Reg& rd, const Reg& rn, u1 immr, u1 imms);
120  void uxth(const Reg& wd, const Reg& wn) { ubfm(wd, wn, 0, 15); }
121  void ubfx(const Reg& wd, const Reg& wn) { ubfm(wd, wn, 0, 31); }
122 
123  void add(const Reg& rd, const Reg& rn, s2 imm);
124  void sub(const Reg& rd, const Reg& rn, s2 imm);
125  void subs(const Reg& rd, const Reg& rn, s2 imm);
126  void cmp(const Reg& rn, s2 imm) { subs(Reg::XZR, rn, imm); }
127 
128  void movn(const Reg& rd, u2 imm);
129  void movz(const Reg& rd, u2 imm);
130  void movk(const Reg& rd, u2 imm, u1 shift = 0);
131 
132  void bcond(u1 cond, s4 offset) {
133  s4 off = offset >> 2;
134  off++;
135  u4 instr = 0x54000000 | lsl(off, 5) | cond;
136  instructions.push_back(instr);
137  }
138 
139  void b(s4 offset) {
140  s4 off = offset >> 2;
141  off++;
142  u4 instr = 0x14000000 | (off & 0x3ffffff);
143  instructions.push_back(instr);
144  }
145 
146  void blr(const Reg& rd) {
147  u4 instr = 0xd63f0000 | lsl(rd.r(), 5);
148  instructions.push_back(instr);
149  }
150 
151  void ldr(const Reg& rt, s4 offset);
152 
153  void ldur(const Reg& rt, const Reg& rn, s2 imm = 0);
154  void stur(const Reg& rt, const Reg& rn, s2 imm = 0);
155 
156  void ldr(const Reg& rt, const Reg& rn, s2 imm = 0);
157  void str(const Reg& rt, const Reg& rn, s2 imm = 0);
158 
159  void ldr(const Reg& rt, const Reg& rn, const Reg& rm);
160 
161  void add(const Reg& rd, const Reg& rn, const Reg& rm,
162  Shift::SHIFT shift = Shift::LSL, u1 amount = 0);
163  void sub(const Reg& rd, const Reg& rn, const Reg& rm);
164  void subs(const Reg& rd, const Reg& rn, const Reg& rm);
165  void neg(const Reg& rd, const Reg& rm);
166  void cmp(const Reg& rn, const Reg& rm);
167 
168  void csel(const Reg& rd, const Reg& rn, const Reg& rm, Cond::COND cond);
169 
170  void mul(const Reg& rd, const Reg& rn, const Reg& rm);
171  void madd(const Reg& rd, const Reg& rn, const Reg& rm, const Reg& ra);
172  void msub(const Reg& rd, const Reg& rn, const Reg& rm, const Reg& ra);
173 
174  void nop() { instructions.push_back(0xd503201f); }
175  void mov(const Reg& rd, const Reg& rm) { orr(rd, *rd.zero(), rm); }
176  void andd(const Reg& rd, const Reg& rn, const Reg& rm);
177  void orr(const Reg& rd, const Reg& rn, const Reg& rm);
178 
179  void sdiv(const Reg& rd, const Reg& rn, const Reg& rm);
180 
181  void fcmp(const Reg& rn, const Reg& rm);
182 
183  void fmov(const Reg& rd, const Reg& rn);
184  void fneg(const Reg& rd, const Reg& rn);
185  void fcvt(const Reg& rd, const Reg& rn);
186 
187  void fadd(const Reg& rd, const Reg& rn, const Reg& rm);
188  void fdiv(const Reg& rd, const Reg& rn, const Reg& rm);
189  void fmul(const Reg& rd, const Reg& rn, const Reg& rm);
190  void fsub(const Reg& rd, const Reg& rn, const Reg& rm);
191 
192  void scvtf(const Reg& rd, const Reg& rn);
193 
194  void trap(const Reg& rd, int type);
195 
196  void emit(CodeMemory* cm);
197  void emit(CodeFragment& cf);
198  void emitRaw(u4 instr) { instructions.push_back(instr); }
199 
200 private:
201  template<typename T>
202  u4 lsl(T a, u1 amount) { return a << amount; }
203 
204  void add_subtract_immediate(u1 sf, u1 op, u1 s, u1 shift, s2 imm,
205  u1 rn, u1 rd) {
206  assert(imm >= 0 && imm <= 4095);
207  u4 instr = 0x11000000 | lsl(sf, 31) | lsl(op, 30) | lsl(s, 29)
208  | lsl(shift, 22) | lsl(imm, 10) | lsl(rn, 5) | rd;
209  instructions.push_back(instr);
210  }
211 
212  void bitfield(u1 sf, u1 opc, u1 n, u1 immr, u1 imms, u1 rn, u1 rd) {
213  u4 instr = 0x13000000 | lsl(sf, 31) | lsl(opc, 29) | lsl(n, 22)
214  | lsl(immr, 16) | lsl(imms, 10) | lsl(rn, 5) | rd;
215  instructions.push_back(instr);
216  }
217 
218  void move_wide_immediate(u1 sf, u1 opc, u1 hw, u2 imm, u1 rd) {
219  u4 instr = 0x12800000 | lsl(sf, 31) | lsl(opc, 29) | lsl(hw, 21)
220  | lsl(imm, 5) | rd;
221  instructions.push_back(instr);
222  }
223 
224  void load_literal(u1 opc, u1 v, s4 imm, u1 rt) {
225  // TODO: validate imm
226  s4 off = (imm / 4) & 0x7ffff;
227  off += 1;
228  u4 instr = 0x18000000 | lsl(opc, 30) | lsl(v, 26) | lsl(off, 5) | rt;
229  instructions.push_back(instr);
230  }
231 
232  void load_store_unscaled(u1 size, u1 v, u1 opc, s2 imm, u1 rn, u1 rt) {
233  assert(imm >= -256 && imm <= 255);
234  u4 instr = 0x38000000 | lsl(size, 30) | lsl(v, 26) | lsl(opc, 22)
235  | lsl(imm & 0x1ff, 12) | lsl(rn, 5) | rt;
236  instructions.push_back(instr);
237  }
238 
239  void load_store_register(u1 size, u1 v, u1 opc, u1 rm, u1 option, u1 s,
240  u1 rn, u1 rt) {
241  u4 instr = 0x38200800 | lsl(size, 30) | lsl(v, 26) | lsl(opc, 22)
242  | lsl(rm, 16) | lsl(option, 13) | lsl(s, 12)
243  | lsl(rn, 5) | rt;
244  instructions.push_back(instr);
245  }
246 
247  void load_store_unsigned(u1 size, u1 v, u1 opc, s2 imm, u1 rn, u1 rt) {
248  imm = imm / std::pow(2, size);
249  assert(imm >= 0 && imm <= 4096);
250  u4 instr = 0x39000000 | lsl(size, 30) | lsl(v, 26) | lsl(opc, 22)
251  | lsl(imm, 10) | lsl(rn, 5) | rt;
252  instructions.push_back(instr);
253  }
254 
255  void add_subtract_shifted_register(u1 sf, u1 opc, u1 s, u1 shift, u1 rm,
256  u1 imm, u1 rn, u1 rd) {
257  u4 instr = 0x0b000000 | lsl(sf, 31) | lsl(opc, 30) | lsl(s, 29)
258  | lsl(shift, 22) | lsl(rm, 16) | lsl(imm, 10) | lsl(rn, 5)
259  | rd;
260  instructions.push_back(instr);
261  }
262 
263  void conditional_select(u1 sf, u1 op, u1 s, u1 rm, u1 cond, u1 op2,
264  u1 rn, u1 rd) {
265  u4 instr = 0x1a800000 | lsl(sf, 31) | lsl(op, 30) | lsl(s, 29)
266  | lsl(rm, 16) | lsl(cond, 12) | lsl(op2, 10)
267  | lsl(rn, 5) | rd;
268  instructions.push_back(instr);
269  }
270 
271  void data_processing_2_source(u1 sf, u1 s, u1 rm, u1 op, u1 rn, u1 rd) {
272  u4 instr = 0x1ac00000 | lsl(sf, 31) | lsl(s, 29) | lsl(rm, 16)
273  | lsl(op, 10) | lsl(rn, 5) | rd;
274  instructions.push_back(instr);
275  }
276 
277  void data_processing_3_source(u1 sf, u1 op54, u1 op31, u1 rm, u1 o0,
278  u1 ra, u1 rn, u1 rd) {
279  u4 instr = 0x1b000000 | lsl(sf, 31) | lsl(op54, 29) | lsl(op31, 21)
280  | lsl(rm, 16) | lsl(o0, 15) | lsl(ra, 10) | lsl(rn, 5) | rd;
281  instructions.push_back(instr);
282  }
283 
284  void logical_shifted_register(u1 sf, u1 opc, u1 n, u1 rm, u1 rn, u1 rd) {
285  u4 instr = 0x0a000000 | lsl(sf, 31) | lsl(opc, 29) | lsl(n, 21)
286  | lsl(rm, 16) | lsl(rn, 5) | rd;
287  instructions.push_back(instr);
288  }
289 
290  void fp_compare(u1 m, u1 s, u1 type, u1 rm, u1 op, u1 rn, u1 op2) {
291  u4 instr = 0x1e202000 | lsl(m, 31) | lsl(s, 29) | lsl(type, 22)
292  | lsl(rm, 16) | lsl(op, 14) | lsl(rn, 5) | op2;
293  instructions.push_back(instr);
294  }
295 
296  void fp_data_processing_1(u1 m, u1 s, u1 type, u1 op, u1 rn, u1 rd) {
297  u4 instr = 0x1e204000 | lsl(m, 31) | lsl(s, 29) | lsl(type, 22)
298  | lsl(op, 15) | lsl(rn, 5) | rd;
299  instructions.push_back(instr);
300  }
301 
302  void fp_data_processing_2(u1 m, u1 s, u1 type, u1 rm, u1 op, u1 rn, u1 rd) {
303  u4 instr = 0x1e200800 | lsl(m, 31) | lsl(s, 29) | lsl(type, 22)
304  | lsl(rm, 16) | lsl(op, 12) | lsl(rn, 5) | rd;
305  instructions.push_back(instr);
306  }
307 
308  void conversion_fp_integer(u1 sf, u1 s, u1 type, u1 rmode, u1 op,
309  u1 rn, u1 rd) {
310  u4 instr = 0x1e200000 | lsl(sf, 31) | lsl(s, 29) | lsl(type, 22)
311  | lsl(rmode, 19) | lsl(op, 16) | lsl(rn, 5) | rd;
312  instructions.push_back(instr);
313  }
314 
315  void trap_encode(u1 rd, s4 type) {
316  u4 instr = 0xe7000000 | lsl(type & 0xff, 8) | rd;
317  instructions.push_back(instr);
318  }
319 };
320 
321 
322 } // end namespace aarch64
323 } // end namespace compiler2
324 } // end namespace jit
325 } // end namespace cacao
326 
327 #endif // JIT_COMPILER2_AARCH64_EMITTER
328 
329 
330 /*
331  * These are local overrides for various environment variables in Emacs.
332  * Please do not remove this and leave it at the end of the file, where
333  * Emacs will automagically detect them.
334  * ---------------------------------------------------------------------
335  * Local variables:
336  * mode: c++
337  * indent-tabs-mode: t
338  * c-basic-offset: 4
339  * tab-width: 4
340  * End:
341  * vim:noexpandtab:sw=4:ts=4:
342  */
void movk(const Reg &rd, u2 imm, u1 shift=0)
#define ra
Definition: md-asm.hpp:62
void move_wide_immediate(u1 sf, u1 opc, u1 hw, u2 imm, u1 rd)
void fneg(const Reg &rd, const Reg &rn)
void add_subtract_shifted_register(u1 sf, u1 opc, u1 s, u1 shift, u1 rm, u1 imm, u1 rn, u1 rd)
void load_store_register(u1 size, u1 v, u1 opc, u1 rm, u1 option, u1 s, u1 rn, u1 rt)
void fp_data_processing_2(u1 m, u1 s, u1 type, u1 rm, u1 op, u1 rn, u1 rd)
void ldur(const Reg &rt, const Reg &rn, s2 imm=0)
void fmul(const Reg &rd, const Reg &rn, const Reg &rm)
u2 op
Definition: disass.cpp:129
void csel(const Reg &rd, const Reg &rn, const Reg &rm, Cond::COND cond)
void fadd(const Reg &rd, const Reg &rn, const Reg &rm)
void sxth(const Reg &rd, const Reg &rn)
void fcvt(const Reg &rd, const Reg &rn)
void add(const Reg &rd, const Reg &rn, s2 imm)
void msub(const Reg &rd, const Reg &rn, const Reg &rm, const Reg &ra)
void neg(const Reg &rd, const Reg &rm)
uint8_t u1
Definition: types.hpp:40
void str(const Reg &rt, const Reg &rn, s2 imm=0)
void orr(const Reg &rd, const Reg &rn, const Reg &rm)
JNIEnv jthread jobject jclass jlong size
Definition: jvmti.h:387
void bitfield(u1 sf, u1 opc, u1 n, u1 immr, u1 imms, u1 rn, u1 rd)
const RegConfiguration *const conf
void sdiv(const Reg &rd, const Reg &rn, const Reg &rm)
void load_store_unscaled(u1 size, u1 v, u1 opc, s2 imm, u1 rn, u1 rt)
void andd(const Reg &rd, const Reg &rn, const Reg &rm)
void fdiv(const Reg &rd, const Reg &rn, const Reg &rm)
void data_processing_3_source(u1 sf, u1 op54, u1 op31, u1 rm, u1 o0, u1 ra, u1 rn, u1 rd)
uint16_t u2
Definition: types.hpp:43
std::vector< T, Allocator< T > > type
Definition: vector.hpp:38
void sub(const Reg &rd, const Reg &rn, s2 imm)
void scvtf(const Reg &rd, const Reg &rn)
void ubfm(const Reg &rd, const Reg &rn, u1 immr, u1 imms)
int32_t s4
Definition: types.hpp:45
void stur(const Reg &rt, const Reg &rn, s2 imm=0)
void subs(const Reg &rd, const Reg &rn, s2 imm)
void fmov(const Reg &rd, const Reg &rn)
void conditional_select(u1 sf, u1 op, u1 s, u1 rm, u1 cond, u1 op2, u1 rn, u1 rd)
uint32_t u4
Definition: types.hpp:46
void mul(const Reg &rd, const Reg &rn, const Reg &rm)
void madd(const Reg &rd, const Reg &rn, const Reg &rm, const Reg &ra)
void sxtb(const Reg &rd, const Reg &rn)
void sxtw(const Reg &xd, const Reg &wn)
void fcmp(const Reg &rn, const Reg &rm)
alloc::vector< u4 >::type instruction_list
void logical_shifted_register(u1 sf, u1 opc, u1 n, u1 rm, u1 rn, u1 rd)
void fsub(const Reg &rd, const Reg &rn, const Reg &rm)
void fp_data_processing_1(u1 m, u1 s, u1 type, u1 op, u1 rn, u1 rd)
void mov(const Reg &rd, const Reg &rm)
void ldr(const Reg &rt, s4 offset)
void trap(const Reg &rd, int type)
void add_subtract_immediate(u1 sf, u1 op, u1 s, u1 shift, s2 imm, u1 rn, u1 rd)
int16_t s2
Definition: types.hpp:42
Segment reference.
Definition: Segment.hpp:44
void fp_compare(u1 m, u1 s, u1 type, u1 rm, u1 op, u1 rn, u1 op2)
void data_processing_2_source(u1 sf, u1 s, u1 rm, u1 op, u1 rn, u1 rd)
Reg(u1 reg, const RegConfiguration *const conf)
void load_literal(u1 opc, u1 v, s4 imm, u1 rt)
void sbfm(const Reg &rd, const Reg &rn, u1 immr, u1 imms)
void uxth(const Reg &wd, const Reg &wn)
void load_store_unsigned(u1 size, u1 v, u1 opc, s2 imm, u1 rn, u1 rt)
void ubfx(const Reg &wd, const Reg &wn)
void conversion_fp_integer(u1 sf, u1 s, u1 type, u1 rmode, u1 op, u1 rn, u1 rd)