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