1 /*
  2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2014, Red Hat Inc. All rights reserved.
  4  * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
  5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  6  *
  7  * This code is free software; you can redistribute it and/or modify it
  8  * under the terms of the GNU General Public License version 2 only, as
  9  * published by the Free Software Foundation.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  *
 25  */
 26 
 27 #include <stdio.h>
 28 #include <sys/types.h>
 29 
 30 #include "precompiled.hpp"
 31 #include "asm/assembler.hpp"
 32 #include "asm/assembler.inline.hpp"
 33 #include "compiler/disassembler.hpp"
 34 #include "interpreter/interpreter.hpp"
 35 #include "memory/resourceArea.hpp"
 36 #include "runtime/interfaceSupport.inline.hpp"
 37 #include "runtime/sharedRuntime.hpp"
 38 
 39 int AbstractAssembler::code_fill_byte() {
 40   return 0;
 41 }
 42 
 43 void Assembler::add(Register Rd, Register Rn, int64_t increment, Register temp) {
 44   if (is_imm_in_range(increment, 12, 0)) {
 45     addi(Rd, Rn, increment);
 46   } else {
 47     assert_different_registers(Rn, temp);
 48     li(temp, increment);
 49     add(Rd, Rn, temp);
 50   }
 51 }
 52 
 53 void Assembler::addw(Register Rd, Register Rn, int64_t increment, Register temp) {
 54   if (is_imm_in_range(increment, 12, 0)) {
 55     addiw(Rd, Rn, increment);
 56   } else {
 57     assert_different_registers(Rn, temp);
 58     li(temp, increment);
 59     addw(Rd, Rn, temp);
 60   }
 61 }
 62 
 63 void Assembler::sub(Register Rd, Register Rn, int64_t decrement, Register temp) {
 64   if (is_imm_in_range(-decrement, 12, 0)) {
 65     addi(Rd, Rn, -decrement);
 66   } else {
 67     assert_different_registers(Rn, temp);
 68     li(temp, decrement);
 69     sub(Rd, Rn, temp);
 70   }
 71 }
 72 
 73 void Assembler::subw(Register Rd, Register Rn, int64_t decrement, Register temp) {
 74   if (is_imm_in_range(-decrement, 12, 0)) {
 75     addiw(Rd, Rn, -decrement);
 76   } else {
 77     assert_different_registers(Rn, temp);
 78     li(temp, decrement);
 79     subw(Rd, Rn, temp);
 80   }
 81 }
 82 
 83 void Assembler::zext_w(Register Rd, Register Rs) {
 84   add_uw(Rd, Rs, zr);
 85 }
 86 
 87 void Assembler::_li(Register Rd, int64_t imm) {
 88   // int64_t is in range 0x8000 0000 0000 0000 ~ 0x7fff ffff ffff ffff
 89   int shift = 12;
 90   int64_t upper = imm, lower = imm;
 91   // Split imm to a lower 12-bit sign-extended part and the remainder,
 92   // because addi will sign-extend the lower imm.
 93   lower = ((int32_t)imm << 20) >> 20;
 94   upper -= lower;
 95 
 96   // Test whether imm is a 32-bit integer.
 97   if (!(((imm) & ~(int64_t)0x7fffffff) == 0 ||
 98         (((imm) & ~(int64_t)0x7fffffff) == ~(int64_t)0x7fffffff))) {
 99     while (((upper >> shift) & 1) == 0) { shift++; }
100     upper >>= shift;
101     li(Rd, upper);
102     slli(Rd, Rd, shift);
103     if (lower != 0) {
104       addi(Rd, Rd, lower);
105     }
106   } else {
107     // 32-bit integer
108     Register hi_Rd = zr;
109     if (upper != 0) {
110       lui(Rd, (int32_t)upper);
111       hi_Rd = Rd;
112     }
113     if (lower != 0 || hi_Rd == zr) {
114       addiw(Rd, hi_Rd, lower);
115     }
116   }
117 }
118 
119 void Assembler::li64(Register Rd, int64_t imm) {
120    // Load upper 32 bits. upper = imm[63:32], but if imm[31] == 1 or
121    // (imm[31:28] == 0x7ff && imm[19] == 1), upper = imm[63:32] + 1.
122    int64_t lower = imm & 0xffffffff;
123    lower -= ((lower << 44) >> 44);
124    int64_t tmp_imm = ((uint64_t)(imm & 0xffffffff00000000)) + (uint64_t)lower;
125    int32_t upper = (tmp_imm - (int32_t)lower) >> 32;
126 
127    // Load upper 32 bits
128    int64_t up = upper, lo = upper;
129    lo = (lo << 52) >> 52;
130    up -= lo;
131    up = (int32_t)up;
132    lui(Rd, up);
133    addi(Rd, Rd, lo);
134 
135    // Load the rest 32 bits.
136    slli(Rd, Rd, 12);
137    addi(Rd, Rd, (int32_t)lower >> 20);
138    slli(Rd, Rd, 12);
139    lower = ((int32_t)imm << 12) >> 20;
140    addi(Rd, Rd, lower);
141    slli(Rd, Rd, 8);
142    lower = imm & 0xff;
143    addi(Rd, Rd, lower);
144 }
145 
146 void Assembler::li32(Register Rd, int32_t imm) {
147   // int32_t is in range 0x8000 0000 ~ 0x7fff ffff, and imm[31] is the sign bit
148   int64_t upper = imm, lower = imm;
149   lower = (imm << 20) >> 20;
150   upper -= lower;
151   upper = (int32_t)upper;
152   // lui Rd, imm[31:12] + imm[11]
153   lui(Rd, upper);
154   // use addiw to distinguish li32 to li64
155   addiw(Rd, Rd, lower);
156 }
157 
158 #define INSN(NAME, REGISTER)                                       \
159   void Assembler::NAME(const address &dest, Register temp) {       \
160     assert_cond(dest != NULL);                                     \
161     int64_t distance = dest - pc();                                \
162     if (is_imm_in_range(distance, 20, 1)) {                        \
163       jal(REGISTER, distance);                                     \
164     } else {                                                       \
165       assert(temp != noreg, "temp must not be empty register!");   \
166       int32_t offset = 0;                                          \
167       movptr_with_offset(temp, dest, offset);                      \
168       jalr(REGISTER, temp, offset);                                \
169     }                                                              \
170   }                                                                \
171   void Assembler::NAME(Label &l, Register temp) {                  \
172     jal(REGISTER, l, temp);                                        \
173   }                                                                \
174 
175   INSN(j,   x0);
176   INSN(jal, x1);
177 
178 #undef INSN
179 
180 #define INSN(NAME, REGISTER)                                       \
181   void Assembler::NAME(Register Rs) {                              \
182     jalr(REGISTER, Rs, 0);                                         \
183   }
184 
185   INSN(jr,   x0);
186   INSN(jalr, x1);
187 
188 #undef INSN
189 
190 void Assembler::ret() {
191   jalr(x0, x1, 0);
192 }
193 
194 #define INSN(NAME, REGISTER)                                      \
195   void Assembler::NAME(const address &dest, Register temp) {      \
196     assert_cond(dest != NULL);                                    \
197     assert(temp != noreg, "temp must not be empty register!");    \
198     int64_t distance = dest - pc();                               \
199     if (is_offset_in_range(distance, 32)) {                       \
200       auipc(temp, distance + 0x800);                              \
201       jalr(REGISTER, temp, ((int32_t)distance << 20) >> 20);      \
202     } else {                                                      \
203       int32_t offset = 0;                                         \
204       movptr_with_offset(temp, dest, offset);                     \
205       jalr(REGISTER, temp, offset);                               \
206     }                                                             \
207   }
208 
209   INSN(call, x1);
210   INSN(tail, x0);
211 
212 #undef INSN
213 
214 #define INSN(NAME, REGISTER)                                   \
215   void Assembler::NAME(const Address &adr, Register temp) {    \
216     switch (adr.getMode()) {                                   \
217       case Address::literal: {                                 \
218         code_section()->relocate(pc(), adr.rspec());           \
219         NAME(adr.target(), temp);                              \
220         break;                                                 \
221       }                                                        \
222       case Address::base_plus_offset: {                        \
223         int32_t offset = 0;                                    \
224         baseOffset(temp, adr, offset);                         \
225         jalr(REGISTER, temp, offset);                          \
226         break;                                                 \
227       }                                                        \
228       default:                                                 \
229         ShouldNotReachHere();                                  \
230     }                                                          \
231   }
232 
233   INSN(j,    x0);
234   INSN(jal,  x1);
235   INSN(call, x1);
236   INSN(tail, x0);
237 
238 #undef INSN
239 
240 void Assembler::wrap_label(Register r1, Register r2, Label &L, compare_and_branch_insn insn,
241                            compare_and_branch_label_insn neg_insn, bool is_far) {
242   if (is_far) {
243     Label done;
244     (this->*neg_insn)(r1, r2, done, /* is_far */ false);
245     j(L);
246     bind(done);
247   } else {
248     if (L.is_bound()) {
249       (this->*insn)(r1, r2, target(L));
250     } else {
251       L.add_patch_at(code(), locator());
252       (this->*insn)(r1, r2, pc());
253     }
254   }
255 }
256 
257 void Assembler::wrap_label(Register Rt, Label &L, Register tmp, load_insn_by_temp insn) {
258   if (L.is_bound()) {
259     (this->*insn)(Rt, target(L), tmp);
260   } else {
261     L.add_patch_at(code(), locator());
262     (this->*insn)(Rt, pc(), tmp);
263   }
264 }
265 
266 void Assembler::wrap_label(Register Rt, Label &L, jal_jalr_insn insn) {
267   if (L.is_bound()) {
268     (this->*insn)(Rt, target(L));
269   } else {
270     L.add_patch_at(code(), locator());
271     (this->*insn)(Rt, pc());
272   }
273 }
274 
275 void Assembler::movptr_with_offset(Register Rd, address addr, int32_t &offset) {
276   uintptr_t imm64 = (uintptr_t)addr;
277 #ifndef PRODUCT
278   {
279     char buffer[64];
280     snprintf(buffer, sizeof(buffer), "0x%" PRIx64, imm64);
281     block_comment(buffer);
282   }
283 #endif
284   assert(is_unsigned_imm_in_range(imm64, 47, 0) || (imm64 == (uintptr_t)-1),
285          "48-bit overflow in address constant");
286   // Load upper 32 bits
287   int32_t imm = imm64 >> 16;
288   int64_t upper = imm, lower = imm;
289   lower = (lower << 52) >> 52;
290   upper -= lower;
291   upper = (int32_t)upper;
292   lui(Rd, upper);
293   addi(Rd, Rd, lower);
294 
295   // Load the rest 16 bits.
296   slli(Rd, Rd, 11);
297   addi(Rd, Rd, (imm64 >> 5) & 0x7ff);
298   slli(Rd, Rd, 5);
299 
300   // This offset will be used by following jalr/ld.
301   offset = imm64 & 0x1f;
302 }
303 
304 void Assembler::movptr(Register Rd, uintptr_t imm64) {
305   movptr(Rd, (address)imm64);
306 }
307 
308 void Assembler::movptr(Register Rd, address addr) {
309   int offset = 0;
310   movptr_with_offset(Rd, addr, offset);
311   addi(Rd, Rd, offset);
312 }
313 
314 void Assembler::ifence() {
315   fence_i();
316   if (UseConservativeFence) {
317     fence(ir, ir);
318   }
319 }
320 
321 #define INSN(NAME, NEG_INSN)                                                         \
322   void Assembler::NAME(Register Rs, Register Rt, const address &dest) {              \
323     NEG_INSN(Rt, Rs, dest);                                                          \
324   }                                                                                  \
325   void Assembler::NAME(Register Rs, Register Rt, Label &l, bool is_far) {            \
326     NEG_INSN(Rt, Rs, l, is_far);                                                     \
327   }
328 
329   INSN(bgt,  blt);
330   INSN(ble,  bge);
331   INSN(bgtu, bltu);
332   INSN(bleu, bgeu);
333 #undef INSN
334 
335 #undef __
336 
337 Address::Address(address target, relocInfo::relocType rtype) : _base(noreg), _offset(0), _mode(literal) {
338   _target = target;
339   switch (rtype) {
340     case relocInfo::oop_type:
341     case relocInfo::metadata_type:
342       // Oops are a special case. Normally they would be their own section
343       // but in cases like icBuffer they are literals in the code stream that
344       // we don't have a section for. We use none so that we get a literal address
345       // which is always patchable.
346       break;
347     case relocInfo::external_word_type:
348       _rspec = external_word_Relocation::spec(target);
349       break;
350     case relocInfo::internal_word_type:
351       _rspec = internal_word_Relocation::spec(target);
352       break;
353     case relocInfo::opt_virtual_call_type:
354       _rspec = opt_virtual_call_Relocation::spec();
355       break;
356     case relocInfo::static_call_type:
357       _rspec = static_call_Relocation::spec();
358       break;
359     case relocInfo::runtime_call_type:
360       _rspec = runtime_call_Relocation::spec();
361       break;
362     case relocInfo::poll_type:
363     case relocInfo::poll_return_type:
364       _rspec = Relocation::spec_simple(rtype);
365       break;
366     case relocInfo::none:
367       _rspec = RelocationHolder::none;
368       break;
369     default:
370       ShouldNotReachHere();
371   }
372 }