1 /*
2  * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 #ifndef CPU_ARM_VM_ASSEMBLER_ARM_HPP
26 #define CPU_ARM_VM_ASSEMBLER_ARM_HPP
27 
28 #include "utilities/macros.hpp"
29 
30 enum AsmCondition {
31   eq, ne, cs, cc, mi, pl, vs, vc,
32   hi, ls, ge, lt, gt, le, al, nv,
33   number_of_conditions,
34   // alternative names
35   hs = cs,
36   lo = cc
37 };
38 
39 enum AsmShift {
40   lsl, lsr, asr, ror
41 };
42 
43 
44 enum AsmOffset {
45   basic_offset = 1 << 24,
46   pre_indexed  = 1 << 24 | 1 << 21,
47   post_indexed = 0
48 };
49 
50 
51 enum AsmWriteback {
52   no_writeback,
53   writeback
54 };
55 
56 enum AsmOffsetOp {
57   sub_offset = 0,
58   add_offset = 1
59 };
60 
61 
62 // ARM Addressing Modes 2 and 3 - Load and store
63 class Address {
64  private:
65   Register  _base;
66   Register  _index;
67   int       _disp;
68   AsmOffset _mode;
69   RelocationHolder   _rspec;
70   int       _shift_imm;
71   AsmShift  _shift;
72   AsmOffsetOp _offset_op;
73 
abs(int x)74   static inline int abs(int x) { return x < 0 ? -x : x; }
up(int x)75   static inline int up (int x) { return x < 0 ?  0 : 1; }
76 
77   static const AsmShift LSL = lsl;
78 
79  public:
Address()80   Address() : _base(noreg) {}
81 
Address(Register rn,int offset=0,AsmOffset mode=basic_offset)82   Address(Register rn, int offset = 0, AsmOffset mode = basic_offset) {
83     _base = rn;
84     _index = noreg;
85     _disp = offset;
86     _mode = mode;
87     _shift_imm = 0;
88     _shift = lsl;
89     _offset_op = add_offset;
90   }
91 
92 #ifdef ASSERT
Address(Register rn,ByteSize offset,AsmOffset mode=basic_offset)93   Address(Register rn, ByteSize offset, AsmOffset mode = basic_offset) {
94     _base = rn;
95     _index = noreg;
96     _disp = in_bytes(offset);
97     _mode = mode;
98     _shift_imm = 0;
99     _shift = lsl;
100     _offset_op = add_offset;
101   }
102 #endif
103 
Address(Register rn,Register rm,AsmShift shift=lsl,int shift_imm=0,AsmOffset mode=basic_offset,AsmOffsetOp offset_op=add_offset)104   Address(Register rn, Register rm, AsmShift shift = lsl,
105           int shift_imm = 0, AsmOffset mode = basic_offset,
106           AsmOffsetOp offset_op = add_offset) {
107     _base = rn;
108     _index = rm;
109     _disp = 0;
110     _shift = shift;
111     _shift_imm = shift_imm;
112     _mode = mode;
113     _offset_op = offset_op;
114   }
115 
Address(Register rn,RegisterOrConstant offset,AsmShift shift=lsl,int shift_imm=0)116   Address(Register rn, RegisterOrConstant offset, AsmShift shift = lsl,
117           int shift_imm = 0) {
118     _base = rn;
119     if (offset.is_constant()) {
120       _index = noreg;
121       {
122         int off = (int) offset.as_constant();
123         if (shift_imm != 0) {
124           assert(shift == lsl,"shift not yet encoded");
125           off =  off << shift_imm;
126         }
127         _disp = off;
128       }
129       _shift = lsl;
130       _shift_imm = 0;
131     } else {
132       _index = offset.as_register();
133       _disp = 0;
134       _shift = shift;
135       _shift_imm = shift_imm;
136     }
137     _mode = basic_offset;
138     _offset_op = add_offset;
139   }
140 
141   // [base + index * wordSize]
indexed_ptr(Register base,Register index)142   static Address indexed_ptr(Register base, Register index) {
143     return Address(base, index, LSL, LogBytesPerWord);
144   }
145 
146   // [base + index * BytesPerInt]
indexed_32(Register base,Register index)147   static Address indexed_32(Register base, Register index) {
148     return Address(base, index, LSL, LogBytesPerInt);
149   }
150 
151   // [base + index * BytesPerHeapOop]
indexed_oop(Register base,Register index)152   static Address indexed_oop(Register base, Register index) {
153     return Address(base, index, LSL, LogBytesPerHeapOop);
154   }
155 
plus_disp(int disp) const156   Address plus_disp(int disp) const {
157     assert((disp == 0) || (_index == noreg),"can't apply an offset to a register indexed address");
158     Address a = (*this);
159     a._disp += disp;
160     return a;
161   }
162 
rebase(Register new_base) const163   Address rebase(Register new_base) const {
164     Address a = (*this);
165     a._base = new_base;
166     return a;
167   }
168 
encoding2() const169   int encoding2() const {
170     assert(_mode == basic_offset || _base != PC, "unpredictable instruction");
171     if (_index == noreg) {
172       assert(-4096 < _disp && _disp < 4096, "encoding constraint");
173       return _mode | up(_disp) << 23 | _base->encoding() << 16 | abs(_disp);
174     } else {
175       assert(_index != PC && (_mode == basic_offset || _index != _base), "unpredictable instruction");
176       assert(_disp == 0 && (_shift_imm >> 5) == 0, "encoding constraint");
177       return 1 << 25 | _offset_op << 23 | _mode | _base->encoding() << 16 |
178              _shift_imm << 7 | _shift << 5 | _index->encoding();
179     }
180   }
181 
encoding3() const182   int encoding3() const {
183     assert(_mode == basic_offset || _base != PC, "unpredictable instruction");
184     if (_index == noreg) {
185       assert(-256 < _disp && _disp < 256, "encoding constraint");
186       return _mode | up(_disp) << 23 | 1 << 22 | _base->encoding() << 16 |
187              (abs(_disp) & 0xf0) << 4 | abs(_disp) & 0x0f;
188     } else {
189       assert(_index != PC && (_mode == basic_offset || _index != _base), "unpredictable instruction");
190       assert(_disp == 0 && _shift == lsl && _shift_imm == 0, "encoding constraint");
191       return _mode | _offset_op << 23 | _base->encoding() << 16 | _index->encoding();
192     }
193   }
194 
encoding_ex() const195   int encoding_ex() const {
196     assert(_index == noreg && _disp == 0 && _mode == basic_offset &&
197            _base != PC, "encoding constraint");
198     return _base->encoding() << 16;
199   }
200 
encoding_vfp() const201   int encoding_vfp() const {
202     assert(_index == noreg && _mode == basic_offset, "encoding constraint");
203     assert(-1024 < _disp && _disp < 1024 && (_disp & 3) == 0, "encoding constraint");
204     return _base->encoding() << 16 | up(_disp) << 23 | abs(_disp) >> 2;
205   }
206 
encoding_simd() const207   int encoding_simd() const {
208     assert(_base != PC, "encoding constraint");
209     assert(_index != PC && _index != SP, "encoding constraint");
210     assert(_disp == 0, "encoding constraint");
211     assert(_shift == 0, "encoding constraint");
212     assert(_index == noreg || _mode == basic_offset, "encoding constraint");
213     assert(_mode == basic_offset || _mode == post_indexed, "encoding constraint");
214     int index;
215     if (_index == noreg) {
216       if (_mode == post_indexed)
217         index = 13;
218       else
219         index = 15;
220     } else {
221       index = _index->encoding();
222     }
223 
224     return _base->encoding() << 16 | index;
225   }
226 
base() const227   Register base() const {
228     return _base;
229   }
230 
index() const231   Register index() const {
232     return _index;
233   }
234 
disp() const235   int disp() const {
236     return _disp;
237   }
238 
mode() const239   AsmOffset mode() const {
240     return _mode;
241   }
242 
shift_imm() const243   int shift_imm() const {
244     return _shift_imm;
245   }
246 
shift() const247   AsmShift shift() const {
248     return _shift;
249   }
250 
offset_op() const251   AsmOffsetOp offset_op() const {
252     return _offset_op;
253   }
254 
uses(Register reg) const255   bool uses(Register reg) const { return _base == reg || _index == reg; }
256 
rtype()257   const relocInfo::relocType rtype() { return _rspec.type(); }
rspec()258   const RelocationHolder&    rspec() { return _rspec; }
259 
260   // Convert the raw encoding form into the form expected by the
261   // constructor for Address.
262   static Address make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc);
263 };
264 
265 #ifdef COMPILER2
266 class VFP {
267   // Helper classes to detect whether a floating point constant can be
268   // encoded in a fconstd or fconsts instruction
269   // The conversion from the imm8, 8 bit constant, to the floating
270   // point value encoding is done with either:
271   // for single precision: imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,5):imm8<5:0>:Zeros(19)
272   // or
273   // for double precision: imm8<7>:NOT(imm8<6>):Replicate(imm8<6>,8):imm8<5:0>:Zeros(48)
274 
275  private:
276   class fpnum {
277    public:
278     virtual unsigned int f_hi4() const = 0;
279     virtual bool f_lo_is_null() const = 0;
280     virtual int e() const = 0;
281     virtual unsigned int s() const = 0;
282 
can_be_imm8() const283     inline bool can_be_imm8() const { return e() >= -3 && e() <= 4 && f_lo_is_null(); }
imm8() const284     inline unsigned char imm8() const { int v = (s() << 7) | (((e() - 1) & 0x7) << 4) | f_hi4(); assert((v >> 8) == 0, "overflow"); return v; }
285   };
286 
287  public:
288   class float_num : public fpnum {
289    public:
float_num(float v)290     float_num(float v) {
291       _num.val = v;
292     }
293 
f_hi4() const294     virtual unsigned int f_hi4() const { return (_num.bits << 9) >> (19+9); }
f_lo_is_null() const295     virtual bool f_lo_is_null() const { return (_num.bits & ((1 << 19) - 1)) == 0; }
e() const296     virtual int e() const { return ((_num.bits << 1) >> (23+1)) - 127; }
s() const297     virtual unsigned int s() const { return _num.bits >> 31; }
298 
299    private:
300     union {
301       float val;
302       unsigned int bits;
303     } _num;
304   };
305 
306   class double_num : public fpnum {
307    public:
double_num(double v)308     double_num(double v) {
309       _num.val = v;
310     }
311 
f_hi4() const312     virtual unsigned int f_hi4() const { return (_num.bits << 12) >> (48+12); }
f_lo_is_null() const313     virtual bool f_lo_is_null() const { return (_num.bits & ((1LL << 48) - 1)) == 0; }
e() const314     virtual int e() const { return ((_num.bits << 1) >> (52+1)) - 1023; }
s() const315     virtual unsigned int s() const { return _num.bits >> 63; }
316 
317    private:
318     union {
319       double val;
320       unsigned long long bits;
321     } _num;
322   };
323 };
324 #endif
325 
326 #include "assembler_arm_32.hpp"
327 
328 
329 #endif // CPU_ARM_VM_ASSEMBLER_ARM_HPP
330