1/* 2 * Copyright (C) 2016 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/* 18 Art assembly interpreter notes: 19 20 First validate assembly code by implementing ExecuteXXXImpl() style body (doesn't 21 handle invoke, allows higher-level code to create frame & shadow frame. 22 23 Once that's working, support direct entry code & eliminate shadow frame (and 24 excess locals allocation. 25 26 Some (hopefully) temporary ugliness. We'll treat rFP as pointing to the 27 base of the vreg array within the shadow frame. Access the other fields, 28 dex_pc_, method_ and number_of_vregs_ via negative offsets. For now, we'll continue 29 the shadow frame mechanism of double-storing object references - via rFP & 30 number_of_vregs_. 31 32 */ 33 34#include "asm_support.h" 35#include "interpreter/cfi_asm_support.h" 36 37#if (__mips==32) && (__mips_isa_rev>=2) 38#define MIPS32REVGE2 /* mips32r2 and greater */ 39#if (__mips==32) && (__mips_isa_rev>=5) 40#define FPU64 /* 64 bit FPU */ 41#if (__mips==32) && (__mips_isa_rev>=6) 42#define MIPS32REVGE6 /* mips32r6 and greater */ 43#endif 44#endif 45#endif 46 47/* MIPS definitions and declarations 48 49 reg nick purpose 50 s0 rPC interpreted program counter, used for fetching instructions 51 s1 rFP interpreted frame pointer, used for accessing locals and args 52 s2 rSELF self (Thread) pointer 53 s3 rIBASE interpreted instruction base pointer, used for computed goto 54 s4 rINST first 16-bit code unit of current instruction 55 s5 rOBJ object pointer 56 s6 rREFS base of object references in shadow frame (ideally, we'll get rid of this later). 57 s7 rTEMP used as temp storage that can survive a function call 58 s8 rPROFILE branch profiling countdown 59 60*/ 61 62/* single-purpose registers, given names for clarity */ 63#define rPC s0 64#define CFI_DEX 16 // DWARF register number of the register holding dex-pc (s0). 65#define CFI_TMP 4 // DWARF register number of the first argument register (a0). 66#define rFP s1 67#define rSELF s2 68#define rIBASE s3 69#define rINST s4 70#define rOBJ s5 71#define rREFS s6 72#define rTEMP s7 73#define rPROFILE s8 74 75#define rARG0 a0 76#define rARG1 a1 77#define rARG2 a2 78#define rARG3 a3 79#define rRESULT0 v0 80#define rRESULT1 v1 81 82/* GP register definitions */ 83#define zero $$0 /* always zero */ 84#define AT $$at /* assembler temp */ 85#define v0 $$2 /* return value */ 86#define v1 $$3 87#define a0 $$4 /* argument registers */ 88#define a1 $$5 89#define a2 $$6 90#define a3 $$7 91#define t0 $$8 /* temp registers (not saved across subroutine calls) */ 92#define t1 $$9 93#define t2 $$10 94#define t3 $$11 95#define t4 $$12 96#define t5 $$13 97#define t6 $$14 98#define t7 $$15 99#define ta0 $$12 /* alias */ 100#define ta1 $$13 101#define ta2 $$14 102#define ta3 $$15 103#define s0 $$16 /* saved across subroutine calls (callee saved) */ 104#define s1 $$17 105#define s2 $$18 106#define s3 $$19 107#define s4 $$20 108#define s5 $$21 109#define s6 $$22 110#define s7 $$23 111#define t8 $$24 /* two more temp registers */ 112#define t9 $$25 113#define k0 $$26 /* kernel temporary */ 114#define k1 $$27 115#define gp $$28 /* global pointer */ 116#define sp $$29 /* stack pointer */ 117#define s8 $$30 /* one more callee saved */ 118#define ra $$31 /* return address */ 119 120/* FP register definitions */ 121#define fv0 $$f0 122#define fv0f $$f1 123#define fv1 $$f2 124#define fv1f $$f3 125#define fa0 $$f12 126#define fa0f $$f13 127#define fa1 $$f14 128#define fa1f $$f15 129#define ft0 $$f4 130#define ft0f $$f5 131#define ft1 $$f6 132#define ft1f $$f7 133#define ft2 $$f8 134#define ft2f $$f9 135#define ft3 $$f10 136#define ft3f $$f11 137#define ft4 $$f16 138#define ft4f $$f17 139#define ft5 $$f18 140#define ft5f $$f19 141#define fs0 $$f20 142#define fs0f $$f21 143#define fs1 $$f22 144#define fs1f $$f23 145#define fs2 $$f24 146#define fs2f $$f25 147#define fs3 $$f26 148#define fs3f $$f27 149#define fs4 $$f28 150#define fs4f $$f29 151#define fs5 $$f30 152#define fs5f $$f31 153 154#ifndef MIPS32REVGE6 155#define fcc0 $$fcc0 156#define fcc1 $$fcc1 157#endif 158 159#ifdef MIPS32REVGE2 160#define SEB(rd, rt) \ 161 seb rd, rt 162#define SEH(rd, rt) \ 163 seh rd, rt 164#define INSERT_HIGH_HALF(rd_lo, rt_hi) \ 165 ins rd_lo, rt_hi, 16, 16 166#else 167#define SEB(rd, rt) \ 168 sll rd, rt, 24; \ 169 sra rd, rd, 24 170#define SEH(rd, rt) \ 171 sll rd, rt, 16; \ 172 sra rd, rd, 16 173/* Clobbers rt_hi on pre-R2. */ 174#define INSERT_HIGH_HALF(rd_lo, rt_hi) \ 175 sll rt_hi, rt_hi, 16; \ 176 or rd_lo, rt_hi 177#endif 178 179#ifdef FPU64 180#define MOVE_TO_FPU_HIGH(r, flo, fhi) \ 181 mthc1 r, flo 182#else 183#define MOVE_TO_FPU_HIGH(r, flo, fhi) \ 184 mtc1 r, fhi 185#endif 186 187#ifdef MIPS32REVGE6 188#define JR(rt) \ 189 jic rt, 0 190#define LSA(rd, rs, rt, sa) \ 191 .if sa; \ 192 lsa rd, rs, rt, sa; \ 193 .else; \ 194 addu rd, rs, rt; \ 195 .endif 196#else 197#define JR(rt) \ 198 jalr zero, rt 199#define LSA(rd, rs, rt, sa) \ 200 .if sa; \ 201 .set push; \ 202 .set noat; \ 203 sll AT, rs, sa; \ 204 addu rd, AT, rt; \ 205 .set pop; \ 206 .else; \ 207 addu rd, rs, rt; \ 208 .endif 209#endif 210 211/* 212 * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs. So, 213 * to access other shadow frame fields, we need to use a backwards offset. Define those here. 214 */ 215#define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET) 216#define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET) 217#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET) 218#define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET) 219#define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET) 220#define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET) 221#define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET) 222#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET) 223#define OFF_FP_SHADOWFRAME OFF_FP(0) 224 225#define MTERP_PROFILE_BRANCHES 1 226#define MTERP_LOGGING 0 227 228/* 229 * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects. Must 230 * be done *before* something throws. 231 * 232 * It's okay to do this more than once. 233 * 234 * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped 235 * dex byte codes. However, the rest of the runtime expects dex pc to be an instruction 236 * offset into the code_items_[] array. For effiency, we will "export" the 237 * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC 238 * to convert to a dex pc when needed. 239 */ 240#define EXPORT_PC() \ 241 sw rPC, OFF_FP_DEX_PC_PTR(rFP) 242 243#define EXPORT_DEX_PC(tmp) \ 244 lw tmp, OFF_FP_DEX_INSTRUCTIONS(rFP); \ 245 sw rPC, OFF_FP_DEX_PC_PTR(rFP); \ 246 subu tmp, rPC, tmp; \ 247 sra tmp, tmp, 1; \ 248 sw tmp, OFF_FP_DEX_PC(rFP) 249 250/* 251 * Fetch the next instruction from rPC into rINST. Does not advance rPC. 252 */ 253#define FETCH_INST() lhu rINST, (rPC) 254 255/* 256 * Fetch the next instruction from the specified offset. Advances rPC 257 * to point to the next instruction. "_count" is in 16-bit code units. 258 * 259 * This must come AFTER anything that can throw an exception, or the 260 * exception catch may miss. (This also implies that it must come after 261 * EXPORT_PC().) 262 */ 263#define FETCH_ADVANCE_INST(_count) \ 264 lhu rINST, ((_count)*2)(rPC); \ 265 addu rPC, rPC, ((_count) * 2) 266 267/* 268 * Similar to FETCH_ADVANCE_INST, but does not update rPC. Used to load 269 * rINST ahead of possible exception point. Be sure to manually advance rPC 270 * later. 271 */ 272#define PREFETCH_INST(_count) lhu rINST, ((_count)*2)(rPC) 273 274/* Advance rPC by some number of code units. */ 275#define ADVANCE(_count) addu rPC, rPC, ((_count) * 2) 276 277/* 278 * Fetch the next instruction from an offset specified by rd. Updates 279 * rPC to point to the next instruction. "rd" must specify the distance 280 * in bytes, *not* 16-bit code units, and may be a signed value. 281 */ 282#define FETCH_ADVANCE_INST_RB(rd) \ 283 addu rPC, rPC, rd; \ 284 lhu rINST, (rPC) 285 286/* 287 * Fetch a half-word code unit from an offset past the current PC. The 288 * "_count" value is in 16-bit code units. Does not advance rPC. 289 * 290 * The "_S" variant works the same but treats the value as signed. 291 */ 292#define FETCH(rd, _count) lhu rd, ((_count) * 2)(rPC) 293#define FETCH_S(rd, _count) lh rd, ((_count) * 2)(rPC) 294 295/* 296 * Fetch one byte from an offset past the current PC. Pass in the same 297 * "_count" as you would for FETCH, and an additional 0/1 indicating which 298 * byte of the halfword you want (lo/hi). 299 */ 300#define FETCH_B(rd, _count, _byte) lbu rd, ((_count) * 2 + _byte)(rPC) 301 302/* 303 * Put the instruction's opcode field into the specified register. 304 */ 305#define GET_INST_OPCODE(rd) and rd, rINST, 0xFF 306 307/* 308 * Transform opcode into branch target address. 309 */ 310#define GET_OPCODE_TARGET(rd) \ 311 sll rd, rd, ${handler_size_bits}; \ 312 addu rd, rIBASE, rd 313 314/* 315 * Begin executing the opcode in rd. 316 */ 317#define GOTO_OPCODE(rd) \ 318 GET_OPCODE_TARGET(rd); \ 319 JR(rd) 320 321/* 322 * Get/set the 32-bit value from a Dalvik register. 323 */ 324#define GET_VREG(rd, rix) LOAD_eas2(rd, rFP, rix) 325 326#define GET_VREG_F(rd, rix) \ 327 .set noat; \ 328 EAS2(AT, rFP, rix); \ 329 l.s rd, (AT); \ 330 .set at 331 332#ifdef MIPS32REVGE6 333#define SET_VREG(rd, rix) \ 334 lsa t8, rix, rFP, 2; \ 335 sw rd, 0(t8); \ 336 lsa t8, rix, rREFS, 2; \ 337 sw zero, 0(t8) 338#else 339#define SET_VREG(rd, rix) \ 340 .set noat; \ 341 sll AT, rix, 2; \ 342 addu t8, rFP, AT; \ 343 sw rd, 0(t8); \ 344 addu t8, rREFS, AT; \ 345 .set at; \ 346 sw zero, 0(t8) 347#endif 348 349#ifdef MIPS32REVGE6 350#define SET_VREG_OBJECT(rd, rix) \ 351 lsa t8, rix, rFP, 2; \ 352 sw rd, 0(t8); \ 353 lsa t8, rix, rREFS, 2; \ 354 sw rd, 0(t8) 355#else 356#define SET_VREG_OBJECT(rd, rix) \ 357 .set noat; \ 358 sll AT, rix, 2; \ 359 addu t8, rFP, AT; \ 360 sw rd, 0(t8); \ 361 addu t8, rREFS, AT; \ 362 .set at; \ 363 sw rd, 0(t8) 364#endif 365 366#ifdef MIPS32REVGE6 367#define SET_VREG64(rlo, rhi, rix) \ 368 lsa t8, rix, rFP, 2; \ 369 sw rlo, 0(t8); \ 370 sw rhi, 4(t8); \ 371 lsa t8, rix, rREFS, 2; \ 372 sw zero, 0(t8); \ 373 sw zero, 4(t8) 374#else 375#define SET_VREG64(rlo, rhi, rix) \ 376 .set noat; \ 377 sll AT, rix, 2; \ 378 addu t8, rFP, AT; \ 379 sw rlo, 0(t8); \ 380 sw rhi, 4(t8); \ 381 addu t8, rREFS, AT; \ 382 .set at; \ 383 sw zero, 0(t8); \ 384 sw zero, 4(t8) 385#endif 386 387#ifdef MIPS32REVGE6 388#define SET_VREG_F(rd, rix) \ 389 lsa t8, rix, rFP, 2; \ 390 s.s rd, 0(t8); \ 391 lsa t8, rix, rREFS, 2; \ 392 sw zero, 0(t8) 393#else 394#define SET_VREG_F(rd, rix) \ 395 .set noat; \ 396 sll AT, rix, 2; \ 397 addu t8, rFP, AT; \ 398 s.s rd, 0(t8); \ 399 addu t8, rREFS, AT; \ 400 .set at; \ 401 sw zero, 0(t8) 402#endif 403 404#ifdef MIPS32REVGE6 405#define SET_VREG64_F(rlo, rhi, rix) \ 406 lsa t8, rix, rFP, 2; \ 407 .set noat; \ 408 mfhc1 AT, rlo; \ 409 s.s rlo, 0(t8); \ 410 sw AT, 4(t8); \ 411 .set at; \ 412 lsa t8, rix, rREFS, 2; \ 413 sw zero, 0(t8); \ 414 sw zero, 4(t8) 415#elif defined(FPU64) 416#define SET_VREG64_F(rlo, rhi, rix) \ 417 .set noat; \ 418 sll AT, rix, 2; \ 419 addu t8, rREFS, AT; \ 420 sw zero, 0(t8); \ 421 sw zero, 4(t8); \ 422 addu t8, rFP, AT; \ 423 mfhc1 AT, rlo; \ 424 sw AT, 4(t8); \ 425 .set at; \ 426 s.s rlo, 0(t8) 427#else 428#define SET_VREG64_F(rlo, rhi, rix) \ 429 .set noat; \ 430 sll AT, rix, 2; \ 431 addu t8, rFP, AT; \ 432 s.s rlo, 0(t8); \ 433 s.s rhi, 4(t8); \ 434 addu t8, rREFS, AT; \ 435 .set at; \ 436 sw zero, 0(t8); \ 437 sw zero, 4(t8) 438#endif 439 440/* Combination of the SET_VREG and GOTO_OPCODE functions to save 1 instruction */ 441#ifdef MIPS32REVGE6 442#define SET_VREG_GOTO(rd, rix, dst) \ 443 .set noreorder; \ 444 GET_OPCODE_TARGET(dst); \ 445 lsa t8, rix, rFP, 2; \ 446 sw rd, 0(t8); \ 447 lsa t8, rix, rREFS, 2; \ 448 jalr zero, dst; \ 449 sw zero, 0(t8); \ 450 .set reorder 451#else 452#define SET_VREG_GOTO(rd, rix, dst) \ 453 .set noreorder; \ 454 GET_OPCODE_TARGET(dst); \ 455 .set noat; \ 456 sll AT, rix, 2; \ 457 addu t8, rFP, AT; \ 458 sw rd, 0(t8); \ 459 addu t8, rREFS, AT; \ 460 .set at; \ 461 jalr zero, dst; \ 462 sw zero, 0(t8); \ 463 .set reorder 464#endif 465 466/* Combination of the SET_VREG_OBJECT and GOTO_OPCODE functions to save 1 instruction */ 467#ifdef MIPS32REVGE6 468#define SET_VREG_OBJECT_GOTO(rd, rix, dst) \ 469 .set noreorder; \ 470 GET_OPCODE_TARGET(dst); \ 471 lsa t8, rix, rFP, 2; \ 472 sw rd, 0(t8); \ 473 lsa t8, rix, rREFS, 2; \ 474 jalr zero, dst; \ 475 sw rd, 0(t8); \ 476 .set reorder 477#else 478#define SET_VREG_OBJECT_GOTO(rd, rix, dst) \ 479 .set noreorder; \ 480 GET_OPCODE_TARGET(dst); \ 481 .set noat; \ 482 sll AT, rix, 2; \ 483 addu t8, rFP, AT; \ 484 sw rd, 0(t8); \ 485 addu t8, rREFS, AT; \ 486 .set at; \ 487 jalr zero, dst; \ 488 sw rd, 0(t8); \ 489 .set reorder 490#endif 491 492/* Combination of the SET_VREG64 and GOTO_OPCODE functions to save 1 instruction */ 493#ifdef MIPS32REVGE6 494#define SET_VREG64_GOTO(rlo, rhi, rix, dst) \ 495 .set noreorder; \ 496 GET_OPCODE_TARGET(dst); \ 497 lsa t8, rix, rFP, 2; \ 498 sw rlo, 0(t8); \ 499 sw rhi, 4(t8); \ 500 lsa t8, rix, rREFS, 2; \ 501 sw zero, 0(t8); \ 502 jalr zero, dst; \ 503 sw zero, 4(t8); \ 504 .set reorder 505#else 506#define SET_VREG64_GOTO(rlo, rhi, rix, dst) \ 507 .set noreorder; \ 508 GET_OPCODE_TARGET(dst); \ 509 .set noat; \ 510 sll AT, rix, 2; \ 511 addu t8, rFP, AT; \ 512 sw rlo, 0(t8); \ 513 sw rhi, 4(t8); \ 514 addu t8, rREFS, AT; \ 515 .set at; \ 516 sw zero, 0(t8); \ 517 jalr zero, dst; \ 518 sw zero, 4(t8); \ 519 .set reorder 520#endif 521 522/* Combination of the SET_VREG_F and GOTO_OPCODE functions to save 1 instruction */ 523#ifdef MIPS32REVGE6 524#define SET_VREG_F_GOTO(rd, rix, dst) \ 525 .set noreorder; \ 526 GET_OPCODE_TARGET(dst); \ 527 lsa t8, rix, rFP, 2; \ 528 s.s rd, 0(t8); \ 529 lsa t8, rix, rREFS, 2; \ 530 jalr zero, dst; \ 531 sw zero, 0(t8); \ 532 .set reorder 533#else 534#define SET_VREG_F_GOTO(rd, rix, dst) \ 535 .set noreorder; \ 536 GET_OPCODE_TARGET(dst); \ 537 .set noat; \ 538 sll AT, rix, 2; \ 539 addu t8, rFP, AT; \ 540 s.s rd, 0(t8); \ 541 addu t8, rREFS, AT; \ 542 .set at; \ 543 jalr zero, dst; \ 544 sw zero, 0(t8); \ 545 .set reorder 546#endif 547 548/* Combination of the SET_VREG64_F and GOTO_OPCODE functions to save 1 instruction */ 549#ifdef MIPS32REVGE6 550#define SET_VREG64_F_GOTO(rlo, rhi, rix, dst) \ 551 .set noreorder; \ 552 GET_OPCODE_TARGET(dst); \ 553 lsa t8, rix, rFP, 2; \ 554 .set noat; \ 555 mfhc1 AT, rlo; \ 556 s.s rlo, 0(t8); \ 557 sw AT, 4(t8); \ 558 .set at; \ 559 lsa t8, rix, rREFS, 2; \ 560 sw zero, 0(t8); \ 561 jalr zero, dst; \ 562 sw zero, 4(t8); \ 563 .set reorder 564#elif defined(FPU64) 565#define SET_VREG64_F_GOTO(rlo, rhi, rix, dst) \ 566 .set noreorder; \ 567 GET_OPCODE_TARGET(dst); \ 568 .set noat; \ 569 sll AT, rix, 2; \ 570 addu t8, rREFS, AT; \ 571 sw zero, 0(t8); \ 572 sw zero, 4(t8); \ 573 addu t8, rFP, AT; \ 574 mfhc1 AT, rlo; \ 575 sw AT, 4(t8); \ 576 .set at; \ 577 jalr zero, dst; \ 578 s.s rlo, 0(t8); \ 579 .set reorder 580#else 581#define SET_VREG64_F_GOTO(rlo, rhi, rix, dst) \ 582 .set noreorder; \ 583 GET_OPCODE_TARGET(dst); \ 584 .set noat; \ 585 sll AT, rix, 2; \ 586 addu t8, rFP, AT; \ 587 s.s rlo, 0(t8); \ 588 s.s rhi, 4(t8); \ 589 addu t8, rREFS, AT; \ 590 .set at; \ 591 sw zero, 0(t8); \ 592 jalr zero, dst; \ 593 sw zero, 4(t8); \ 594 .set reorder 595#endif 596 597#define GET_OPA(rd) srl rd, rINST, 8 598#ifdef MIPS32REVGE2 599#define GET_OPA4(rd) ext rd, rINST, 8, 4 600#else 601#define GET_OPA4(rd) GET_OPA(rd); and rd, 0xf 602#endif 603#define GET_OPB(rd) srl rd, rINST, 12 604 605/* 606 * Form an Effective Address rd = rbase + roff<<shift; 607 * Uses reg AT on pre-R6. 608 */ 609#define EASN(rd, rbase, roff, shift) LSA(rd, roff, rbase, shift) 610 611#define EAS1(rd, rbase, roff) EASN(rd, rbase, roff, 1) 612#define EAS2(rd, rbase, roff) EASN(rd, rbase, roff, 2) 613#define EAS3(rd, rbase, roff) EASN(rd, rbase, roff, 3) 614#define EAS4(rd, rbase, roff) EASN(rd, rbase, roff, 4) 615 616#define LOAD_eas2(rd, rbase, roff) \ 617 .set noat; \ 618 EAS2(AT, rbase, roff); \ 619 lw rd, 0(AT); \ 620 .set at 621 622#define STORE_eas2(rd, rbase, roff) \ 623 .set noat; \ 624 EAS2(AT, rbase, roff); \ 625 sw rd, 0(AT); \ 626 .set at 627 628#define LOAD_RB_OFF(rd, rbase, off) lw rd, off(rbase) 629#define STORE_RB_OFF(rd, rbase, off) sw rd, off(rbase) 630 631#define STORE64_off(rlo, rhi, rbase, off) \ 632 sw rlo, off(rbase); \ 633 sw rhi, (off+4)(rbase) 634#define LOAD64_off(rlo, rhi, rbase, off) \ 635 lw rlo, off(rbase); \ 636 lw rhi, (off+4)(rbase) 637 638#define STORE64(rlo, rhi, rbase) STORE64_off(rlo, rhi, rbase, 0) 639#define LOAD64(rlo, rhi, rbase) LOAD64_off(rlo, rhi, rbase, 0) 640 641#ifdef FPU64 642#define STORE64_off_F(rlo, rhi, rbase, off) \ 643 s.s rlo, off(rbase); \ 644 .set noat; \ 645 mfhc1 AT, rlo; \ 646 sw AT, (off+4)(rbase); \ 647 .set at 648#define LOAD64_off_F(rlo, rhi, rbase, off) \ 649 l.s rlo, off(rbase); \ 650 .set noat; \ 651 lw AT, (off+4)(rbase); \ 652 mthc1 AT, rlo; \ 653 .set at 654#else 655#define STORE64_off_F(rlo, rhi, rbase, off) \ 656 s.s rlo, off(rbase); \ 657 s.s rhi, (off+4)(rbase) 658#define LOAD64_off_F(rlo, rhi, rbase, off) \ 659 l.s rlo, off(rbase); \ 660 l.s rhi, (off+4)(rbase) 661#endif 662 663#define STORE64_F(rlo, rhi, rbase) STORE64_off_F(rlo, rhi, rbase, 0) 664#define LOAD64_F(rlo, rhi, rbase) LOAD64_off_F(rlo, rhi, rbase, 0) 665 666 667#define LOAD_base_offMirrorArray_length(rd, rbase) LOAD_RB_OFF(rd, rbase, MIRROR_ARRAY_LENGTH_OFFSET) 668 669#define STACK_STORE(rd, off) sw rd, off(sp) 670#define STACK_LOAD(rd, off) lw rd, off(sp) 671#define CREATE_STACK(n) subu sp, sp, n 672#define DELETE_STACK(n) addu sp, sp, n 673 674#define LOAD_ADDR(dest, addr) la dest, addr 675#define LOAD_IMM(dest, imm) li dest, imm 676#define MOVE_REG(dest, src) move dest, src 677#define STACK_SIZE 128 678 679#define STACK_OFFSET_ARG04 16 680#define STACK_OFFSET_ARG05 20 681#define STACK_OFFSET_ARG06 24 682#define STACK_OFFSET_ARG07 28 683#define STACK_OFFSET_GP 84 684 685#define JAL(n) jal n 686#define BAL(n) bal n 687 688/* 689 * FP register usage restrictions: 690 * 1) We don't use the callee save FP registers so we don't have to save them. 691 * 2) We don't use the odd FP registers so we can share code with mips32r6. 692 */ 693#define STACK_STORE_FULL() CREATE_STACK(STACK_SIZE); \ 694 STACK_STORE(ra, 124); \ 695 STACK_STORE(s8, 120); \ 696 STACK_STORE(s0, 116); \ 697 STACK_STORE(s1, 112); \ 698 STACK_STORE(s2, 108); \ 699 STACK_STORE(s3, 104); \ 700 STACK_STORE(s4, 100); \ 701 STACK_STORE(s5, 96); \ 702 STACK_STORE(s6, 92); \ 703 STACK_STORE(s7, 88); 704 705#define STACK_LOAD_FULL() STACK_LOAD(gp, STACK_OFFSET_GP); \ 706 STACK_LOAD(s7, 88); \ 707 STACK_LOAD(s6, 92); \ 708 STACK_LOAD(s5, 96); \ 709 STACK_LOAD(s4, 100); \ 710 STACK_LOAD(s3, 104); \ 711 STACK_LOAD(s2, 108); \ 712 STACK_LOAD(s1, 112); \ 713 STACK_LOAD(s0, 116); \ 714 STACK_LOAD(s8, 120); \ 715 STACK_LOAD(ra, 124); \ 716 DELETE_STACK(STACK_SIZE) 717 718#define REFRESH_IBASE() \ 719 lw rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF) 720 721/* Constants for float/double_to_int/long conversions */ 722#define INT_MIN 0x80000000 723#define INT_MIN_AS_FLOAT 0xCF000000 724#define INT_MIN_AS_DOUBLE_HIGH 0xC1E00000 725#define LONG_MIN_HIGH 0x80000000 726#define LONG_MIN_AS_FLOAT 0xDF000000 727#define LONG_MIN_AS_DOUBLE_HIGH 0xC3E00000 728