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:20] == 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 relocate(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 int64_t imm64 = (int64_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 == (int64_t)-1), 285 "bit 47 overflows in address constant"); 286 // Load upper 31 bits 287 int64_t imm = imm64 >> 17; 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 17 bits. 296 slli(Rd, Rd, 11); 297 addi(Rd, Rd, (imm64 >> 6) & 0x7ff); 298 slli(Rd, Rd, 6); 299 300 // This offset will be used by following jalr/ld. 301 offset = imm64 & 0x3f; 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 #define INSN(NAME, NEG_INSN) \ 315 void Assembler::NAME(Register Rs, Register Rt, const address &dest) { \ 316 NEG_INSN(Rt, Rs, dest); \ 317 } \ 318 void Assembler::NAME(Register Rs, Register Rt, Label &l, bool is_far) { \ 319 NEG_INSN(Rt, Rs, l, is_far); \ 320 } 321 322 INSN(bgt, blt); 323 INSN(ble, bge); 324 INSN(bgtu, bltu); 325 INSN(bleu, bgeu); 326 #undef INSN 327 328 #undef __ 329 330 Address::Address(address target, relocInfo::relocType rtype) : _base(noreg), _offset(0), _mode(literal) { 331 _target = target; 332 switch (rtype) { 333 case relocInfo::oop_type: 334 case relocInfo::metadata_type: 335 // Oops are a special case. Normally they would be their own section 336 // but in cases like icBuffer they are literals in the code stream that 337 // we don't have a section for. We use none so that we get a literal address 338 // which is always patchable. 339 break; 340 case relocInfo::external_word_type: 341 _rspec = external_word_Relocation::spec(target); 342 break; 343 case relocInfo::internal_word_type: 344 _rspec = internal_word_Relocation::spec(target); 345 break; 346 case relocInfo::opt_virtual_call_type: 347 _rspec = opt_virtual_call_Relocation::spec(); 348 break; 349 case relocInfo::static_call_type: 350 _rspec = static_call_Relocation::spec(); 351 break; 352 case relocInfo::runtime_call_type: 353 _rspec = runtime_call_Relocation::spec(); 354 break; 355 case relocInfo::poll_type: 356 case relocInfo::poll_return_type: 357 _rspec = Relocation::spec_simple(rtype); 358 break; 359 case relocInfo::none: 360 _rspec = RelocationHolder::none; 361 break; 362 default: 363 ShouldNotReachHere(); 364 } 365 }