goetz@6458: /* goetz@6458: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. goetz@6515: * Copyright 2012, 2014 SAP AG. All rights reserved. goetz@6458: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. goetz@6458: * goetz@6458: * This code is free software; you can redistribute it and/or modify it goetz@6458: * under the terms of the GNU General Public License version 2 only, as goetz@6458: * published by the Free Software Foundation. goetz@6458: * goetz@6458: * This code is distributed in the hope that it will be useful, but WITHOUT goetz@6458: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or goetz@6458: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License goetz@6458: * version 2 for more details (a copy is included in the LICENSE file that goetz@6458: * accompanied this code). goetz@6458: * goetz@6458: * You should have received a copy of the GNU General Public License version goetz@6458: * 2 along with this work; if not, write to the Free Software Foundation, goetz@6458: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. goetz@6458: * goetz@6458: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA goetz@6458: * or visit www.oracle.com if you need additional information or have any goetz@6458: * questions. goetz@6458: * goetz@6458: */ goetz@6458: goetz@6458: #include "precompiled.hpp" goetz@6458: #include "asm/assembler.inline.hpp" goetz@6458: #include "gc_interface/collectedHeap.inline.hpp" goetz@6458: #include "interpreter/interpreter.hpp" goetz@6458: #include "memory/cardTableModRefBS.hpp" goetz@6458: #include "memory/resourceArea.hpp" goetz@6458: #include "prims/methodHandles.hpp" goetz@6458: #include "runtime/biasedLocking.hpp" goetz@6458: #include "runtime/interfaceSupport.hpp" goetz@6458: #include "runtime/objectMonitor.hpp" goetz@6458: #include "runtime/os.hpp" goetz@6458: #include "runtime/sharedRuntime.hpp" goetz@6458: #include "runtime/stubRoutines.hpp" goetz@6515: #include "utilities/macros.hpp" goetz@6458: #if INCLUDE_ALL_GCS goetz@6458: #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" goetz@6458: #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" goetz@6458: #include "gc_implementation/g1/heapRegion.hpp" goetz@6458: #endif // INCLUDE_ALL_GCS goetz@6458: goetz@6458: #ifdef PRODUCT goetz@6458: #define BLOCK_COMMENT(str) // nothing goetz@6458: #else goetz@6458: #define BLOCK_COMMENT(str) block_comment(str) goetz@6458: #endif goetz@6458: goetz@6458: int AbstractAssembler::code_fill_byte() { goetz@6458: return 0x00; // illegal instruction 0x00000000 goetz@6458: } goetz@6458: goetz@6458: void Assembler::print_instruction(int inst) { goetz@6458: Unimplemented(); goetz@6458: } goetz@6458: goetz@6458: // Patch instruction `inst' at offset `inst_pos' to refer to goetz@6458: // `dest_pos' and return the resulting instruction. We should have goetz@6458: // pcs, not offsets, but since all is relative, it will work out fine. goetz@6458: int Assembler::patched_branch(int dest_pos, int inst, int inst_pos) { goetz@6458: int m = 0; // mask for displacement field goetz@6458: int v = 0; // new value for displacement field goetz@6458: goetz@6458: switch (inv_op_ppc(inst)) { goetz@6458: case b_op: m = li(-1); v = li(disp(dest_pos, inst_pos)); break; goetz@6458: case bc_op: m = bd(-1); v = bd(disp(dest_pos, inst_pos)); break; goetz@6458: default: ShouldNotReachHere(); goetz@6458: } goetz@6458: return inst & ~m | v; goetz@6458: } goetz@6458: goetz@6458: // Return the offset, relative to _code_begin, of the destination of goetz@6458: // the branch inst at offset pos. goetz@6458: int Assembler::branch_destination(int inst, int pos) { goetz@6458: int r = 0; goetz@6458: switch (inv_op_ppc(inst)) { goetz@6458: case b_op: r = bxx_destination_offset(inst, pos); break; goetz@6458: case bc_op: r = inv_bd_field(inst, pos); break; goetz@6458: default: ShouldNotReachHere(); goetz@6458: } goetz@6458: return r; goetz@6458: } goetz@6458: goetz@6458: // Low-level andi-one-instruction-macro. goetz@6458: void Assembler::andi(Register a, Register s, const int ui16) { goetz@6458: assert(is_uimm(ui16, 16), "must be 16-bit unsigned immediate"); goetz@6458: if (is_power_of_2_long(((jlong) ui16)+1)) { goetz@6458: // pow2minus1 goetz@6458: clrldi(a, s, 64-log2_long((((jlong) ui16)+1))); goetz@6458: } else if (is_power_of_2_long((jlong) ui16)) { goetz@6458: // pow2 goetz@6458: rlwinm(a, s, 0, 31-log2_long((jlong) ui16), 31-log2_long((jlong) ui16)); goetz@6458: } else if (is_power_of_2_long((jlong)-ui16)) { goetz@6458: // negpow2 goetz@6458: clrrdi(a, s, log2_long((jlong)-ui16)); goetz@6458: } else { goetz@6458: andi_(a, s, ui16); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: // RegisterOrConstant version. goetz@6458: void Assembler::ld(Register d, RegisterOrConstant roc, Register s1) { goetz@6458: if (roc.is_constant()) { goetz@6458: if (s1 == noreg) { goetz@6458: int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true); goetz@6458: Assembler::ld(d, simm16_rest, d); goetz@6458: } else if (is_simm(roc.as_constant(), 16)) { goetz@6458: Assembler::ld(d, roc.as_constant(), s1); goetz@6458: } else { goetz@6458: load_const_optimized(d, roc.as_constant()); goetz@6458: Assembler::ldx(d, d, s1); goetz@6458: } goetz@6458: } else { goetz@6458: if (s1 == noreg) goetz@6458: Assembler::ld(d, 0, roc.as_register()); goetz@6458: else goetz@6458: Assembler::ldx(d, roc.as_register(), s1); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: void Assembler::lwa(Register d, RegisterOrConstant roc, Register s1) { goetz@6458: if (roc.is_constant()) { goetz@6458: if (s1 == noreg) { goetz@6458: int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true); goetz@6458: Assembler::lwa(d, simm16_rest, d); goetz@6458: } else if (is_simm(roc.as_constant(), 16)) { goetz@6458: Assembler::lwa(d, roc.as_constant(), s1); goetz@6458: } else { goetz@6458: load_const_optimized(d, roc.as_constant()); goetz@6458: Assembler::lwax(d, d, s1); goetz@6458: } goetz@6458: } else { goetz@6458: if (s1 == noreg) goetz@6458: Assembler::lwa(d, 0, roc.as_register()); goetz@6458: else goetz@6458: Assembler::lwax(d, roc.as_register(), s1); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: void Assembler::lwz(Register d, RegisterOrConstant roc, Register s1) { goetz@6458: if (roc.is_constant()) { goetz@6458: if (s1 == noreg) { goetz@6458: int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true); goetz@6458: Assembler::lwz(d, simm16_rest, d); goetz@6458: } else if (is_simm(roc.as_constant(), 16)) { goetz@6458: Assembler::lwz(d, roc.as_constant(), s1); goetz@6458: } else { goetz@6458: load_const_optimized(d, roc.as_constant()); goetz@6458: Assembler::lwzx(d, d, s1); goetz@6458: } goetz@6458: } else { goetz@6458: if (s1 == noreg) goetz@6458: Assembler::lwz(d, 0, roc.as_register()); goetz@6458: else goetz@6458: Assembler::lwzx(d, roc.as_register(), s1); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: void Assembler::lha(Register d, RegisterOrConstant roc, Register s1) { goetz@6458: if (roc.is_constant()) { goetz@6458: if (s1 == noreg) { goetz@6458: int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true); goetz@6458: Assembler::lha(d, simm16_rest, d); goetz@6458: } else if (is_simm(roc.as_constant(), 16)) { goetz@6458: Assembler::lha(d, roc.as_constant(), s1); goetz@6458: } else { goetz@6458: load_const_optimized(d, roc.as_constant()); goetz@6458: Assembler::lhax(d, d, s1); goetz@6458: } goetz@6458: } else { goetz@6458: if (s1 == noreg) goetz@6458: Assembler::lha(d, 0, roc.as_register()); goetz@6458: else goetz@6458: Assembler::lhax(d, roc.as_register(), s1); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: void Assembler::lhz(Register d, RegisterOrConstant roc, Register s1) { goetz@6458: if (roc.is_constant()) { goetz@6458: if (s1 == noreg) { goetz@6458: int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true); goetz@6458: Assembler::lhz(d, simm16_rest, d); goetz@6458: } else if (is_simm(roc.as_constant(), 16)) { goetz@6458: Assembler::lhz(d, roc.as_constant(), s1); goetz@6458: } else { goetz@6458: load_const_optimized(d, roc.as_constant()); goetz@6458: Assembler::lhzx(d, d, s1); goetz@6458: } goetz@6458: } else { goetz@6458: if (s1 == noreg) goetz@6458: Assembler::lhz(d, 0, roc.as_register()); goetz@6458: else goetz@6458: Assembler::lhzx(d, roc.as_register(), s1); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: void Assembler::lbz(Register d, RegisterOrConstant roc, Register s1) { goetz@6458: if (roc.is_constant()) { goetz@6458: if (s1 == noreg) { goetz@6458: int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true); goetz@6458: Assembler::lbz(d, simm16_rest, d); goetz@6458: } else if (is_simm(roc.as_constant(), 16)) { goetz@6458: Assembler::lbz(d, roc.as_constant(), s1); goetz@6458: } else { goetz@6458: load_const_optimized(d, roc.as_constant()); goetz@6458: Assembler::lbzx(d, d, s1); goetz@6458: } goetz@6458: } else { goetz@6458: if (s1 == noreg) goetz@6458: Assembler::lbz(d, 0, roc.as_register()); goetz@6458: else goetz@6458: Assembler::lbzx(d, roc.as_register(), s1); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: void Assembler::std(Register d, RegisterOrConstant roc, Register s1, Register tmp) { goetz@6458: if (roc.is_constant()) { goetz@6458: if (s1 == noreg) { goetz@6458: guarantee(tmp != noreg, "Need tmp reg to encode large constants"); goetz@6458: int simm16_rest = load_const_optimized(tmp, roc.as_constant(), noreg, true); goetz@6458: Assembler::std(d, simm16_rest, tmp); goetz@6458: } else if (is_simm(roc.as_constant(), 16)) { goetz@6458: Assembler::std(d, roc.as_constant(), s1); goetz@6458: } else { goetz@6458: guarantee(tmp != noreg, "Need tmp reg to encode large constants"); goetz@6458: load_const_optimized(tmp, roc.as_constant()); goetz@6458: Assembler::stdx(d, tmp, s1); goetz@6458: } goetz@6458: } else { goetz@6458: if (s1 == noreg) goetz@6458: Assembler::std(d, 0, roc.as_register()); goetz@6458: else goetz@6458: Assembler::stdx(d, roc.as_register(), s1); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: void Assembler::stw(Register d, RegisterOrConstant roc, Register s1, Register tmp) { goetz@6458: if (roc.is_constant()) { goetz@6458: if (s1 == noreg) { goetz@6458: guarantee(tmp != noreg, "Need tmp reg to encode large constants"); goetz@6458: int simm16_rest = load_const_optimized(tmp, roc.as_constant(), noreg, true); goetz@6458: Assembler::stw(d, simm16_rest, tmp); goetz@6458: } else if (is_simm(roc.as_constant(), 16)) { goetz@6458: Assembler::stw(d, roc.as_constant(), s1); goetz@6458: } else { goetz@6458: guarantee(tmp != noreg, "Need tmp reg to encode large constants"); goetz@6458: load_const_optimized(tmp, roc.as_constant()); goetz@6458: Assembler::stwx(d, tmp, s1); goetz@6458: } goetz@6458: } else { goetz@6458: if (s1 == noreg) goetz@6458: Assembler::stw(d, 0, roc.as_register()); goetz@6458: else goetz@6458: Assembler::stwx(d, roc.as_register(), s1); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: void Assembler::sth(Register d, RegisterOrConstant roc, Register s1, Register tmp) { goetz@6458: if (roc.is_constant()) { goetz@6458: if (s1 == noreg) { goetz@6458: guarantee(tmp != noreg, "Need tmp reg to encode large constants"); goetz@6458: int simm16_rest = load_const_optimized(tmp, roc.as_constant(), noreg, true); goetz@6458: Assembler::sth(d, simm16_rest, tmp); goetz@6458: } else if (is_simm(roc.as_constant(), 16)) { goetz@6458: Assembler::sth(d, roc.as_constant(), s1); goetz@6458: } else { goetz@6458: guarantee(tmp != noreg, "Need tmp reg to encode large constants"); goetz@6458: load_const_optimized(tmp, roc.as_constant()); goetz@6458: Assembler::sthx(d, tmp, s1); goetz@6458: } goetz@6458: } else { goetz@6458: if (s1 == noreg) goetz@6458: Assembler::sth(d, 0, roc.as_register()); goetz@6458: else goetz@6458: Assembler::sthx(d, roc.as_register(), s1); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: void Assembler::stb(Register d, RegisterOrConstant roc, Register s1, Register tmp) { goetz@6458: if (roc.is_constant()) { goetz@6458: if (s1 == noreg) { goetz@6458: guarantee(tmp != noreg, "Need tmp reg to encode large constants"); goetz@6458: int simm16_rest = load_const_optimized(tmp, roc.as_constant(), noreg, true); goetz@6458: Assembler::stb(d, simm16_rest, tmp); goetz@6458: } else if (is_simm(roc.as_constant(), 16)) { goetz@6458: Assembler::stb(d, roc.as_constant(), s1); goetz@6458: } else { goetz@6458: guarantee(tmp != noreg, "Need tmp reg to encode large constants"); goetz@6458: load_const_optimized(tmp, roc.as_constant()); goetz@6458: Assembler::stbx(d, tmp, s1); goetz@6458: } goetz@6458: } else { goetz@6458: if (s1 == noreg) goetz@6458: Assembler::stb(d, 0, roc.as_register()); goetz@6458: else goetz@6458: Assembler::stbx(d, roc.as_register(), s1); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: void Assembler::add(Register d, RegisterOrConstant roc, Register s1) { goetz@6458: if (roc.is_constant()) { goetz@6458: intptr_t c = roc.as_constant(); goetz@6458: assert(is_simm(c, 16), "too big"); goetz@6458: addi(d, s1, (int)c); goetz@6458: } goetz@6458: else add(d, roc.as_register(), s1); goetz@6458: } goetz@6458: goetz@6458: void Assembler::subf(Register d, RegisterOrConstant roc, Register s1) { goetz@6458: if (roc.is_constant()) { goetz@6458: intptr_t c = roc.as_constant(); goetz@6458: assert(is_simm(-c, 16), "too big"); goetz@6458: addi(d, s1, (int)-c); goetz@6458: } goetz@6458: else subf(d, roc.as_register(), s1); goetz@6458: } goetz@6458: goetz@6458: void Assembler::cmpd(ConditionRegister d, RegisterOrConstant roc, Register s1) { goetz@6458: if (roc.is_constant()) { goetz@6458: intptr_t c = roc.as_constant(); goetz@6458: assert(is_simm(c, 16), "too big"); goetz@6458: cmpdi(d, s1, (int)c); goetz@6458: } goetz@6458: else cmpd(d, roc.as_register(), s1); goetz@6458: } goetz@6458: goetz@6458: // Load a 64 bit constant. Patchable. goetz@6458: void Assembler::load_const(Register d, long x, Register tmp) { goetz@6458: // 64-bit value: x = xa xb xc xd goetz@6458: int xa = (x >> 48) & 0xffff; goetz@6458: int xb = (x >> 32) & 0xffff; goetz@6458: int xc = (x >> 16) & 0xffff; goetz@6458: int xd = (x >> 0) & 0xffff; goetz@6458: if (tmp == noreg) { goetz@6458: Assembler::lis( d, (int)(short)xa); goetz@6458: Assembler::ori( d, d, (unsigned int)xb); goetz@6458: Assembler::sldi(d, d, 32); goetz@6458: Assembler::oris(d, d, (unsigned int)xc); goetz@6458: Assembler::ori( d, d, (unsigned int)xd); goetz@6458: } else { goetz@6458: // exploit instruction level parallelism if we have a tmp register goetz@6458: assert_different_registers(d, tmp); goetz@6458: Assembler::lis(tmp, (int)(short)xa); goetz@6458: Assembler::lis(d, (int)(short)xc); goetz@6458: Assembler::ori(tmp, tmp, (unsigned int)xb); goetz@6458: Assembler::ori(d, d, (unsigned int)xd); goetz@6458: Assembler::insrdi(d, tmp, 32, 0); goetz@6458: } goetz@6458: } goetz@6458: goetz@6458: // Load a 64 bit constant, optimized, not identifyable. goetz@6458: // Tmp can be used to increase ILP. Set return_simm16_rest=true to get a goetz@6458: // 16 bit immediate offset. goetz@6458: int Assembler::load_const_optimized(Register d, long x, Register tmp, bool return_simm16_rest) { goetz@6458: // Avoid accidentally trying to use R0 for indexed addressing. goetz@6458: assert(d != R0, "R0 not allowed"); goetz@6458: assert_different_registers(d, tmp); goetz@6458: goetz@6458: short xa, xb, xc, xd; // Four 16-bit chunks of const. goetz@6458: long rem = x; // Remaining part of const. goetz@6458: goetz@6458: xd = rem & 0xFFFF; // Lowest 16-bit chunk. goetz@6458: rem = (rem >> 16) + ((unsigned short)xd >> 15); // Compensation for sign extend. goetz@6458: goetz@6458: if (rem == 0) { // opt 1: simm16 goetz@6458: li(d, xd); goetz@6458: return 0; goetz@6458: } goetz@6458: goetz@6458: xc = rem & 0xFFFF; // Next 16-bit chunk. goetz@6458: rem = (rem >> 16) + ((unsigned short)xc >> 15); // Compensation for sign extend. goetz@6458: goetz@6458: if (rem == 0) { // opt 2: simm32 goetz@6458: lis(d, xc); goetz@6458: } else { // High 32 bits needed. goetz@6458: goetz@6458: if (tmp != noreg) { // opt 3: We have a temp reg. goetz@6458: // No carry propagation between xc and higher chunks here (use logical instructions). goetz@6458: xa = (x >> 48) & 0xffff; goetz@6458: xb = (x >> 32) & 0xffff; // No sign compensation, we use lis+ori or li to allow usage of R0. goetz@6458: bool load_xa = (xa != 0) || (xb < 0); goetz@6458: bool return_xd = false; goetz@6458: goetz@6515: if (load_xa) { lis(tmp, xa); } goetz@6515: if (xc) { lis(d, xc); } goetz@6458: if (load_xa) { goetz@6515: if (xb) { ori(tmp, tmp, (unsigned short)xb); } // No addi, we support tmp == R0. goetz@6458: } else { goetz@6458: li(tmp, xb); // non-negative goetz@6458: } goetz@6458: if (xc) { goetz@6458: if (return_simm16_rest && xd >= 0) { return_xd = true; } // >= 0 to avoid carry propagation after insrdi/rldimi. goetz@6458: else if (xd) { addi(d, d, xd); } goetz@6458: } else { goetz@6458: li(d, xd); goetz@6458: } goetz@6458: insrdi(d, tmp, 32, 0); goetz@6458: return return_xd ? xd : 0; // non-negative goetz@6458: } goetz@6458: goetz@6458: xb = rem & 0xFFFF; // Next 16-bit chunk. goetz@6458: rem = (rem >> 16) + ((unsigned short)xb >> 15); // Compensation for sign extend. goetz@6458: goetz@6458: xa = rem & 0xFFFF; // Highest 16-bit chunk. goetz@6458: goetz@6458: // opt 4: avoid adding 0 goetz@6458: if (xa) { // Highest 16-bit needed? goetz@6458: lis(d, xa); goetz@6515: if (xb) { addi(d, d, xb); } goetz@6458: } else { goetz@6458: li(d, xb); goetz@6458: } goetz@6458: sldi(d, d, 32); goetz@6515: if (xc) { addis(d, d, xc); } goetz@6458: } goetz@6458: goetz@6458: // opt 5: Return offset to be inserted into following instruction. goetz@6458: if (return_simm16_rest) return xd; goetz@6458: goetz@6515: if (xd) { addi(d, d, xd); } goetz@6458: return 0; goetz@6458: } goetz@6458: goetz@6458: #ifndef PRODUCT goetz@6458: // Test of ppc assembler. goetz@6458: void Assembler::test_asm() { goetz@6458: // PPC 1, section 3.3.8, Fixed-Point Arithmetic Instructions goetz@6458: addi( R0, R1, 10); goetz@6458: addis( R5, R2, 11); goetz@6458: addic_( R3, R31, 42); goetz@6458: subfic( R21, R12, 2112); goetz@6458: add( R3, R2, R1); goetz@6458: add_( R11, R22, R30); goetz@6458: subf( R7, R6, R5); goetz@6458: subf_( R8, R9, R4); goetz@6458: addc( R11, R12, R13); goetz@6458: addc_( R14, R14, R14); goetz@6458: subfc( R15, R16, R17); goetz@6458: subfc_( R18, R20, R19); goetz@6458: adde( R20, R22, R24); goetz@6458: adde_( R29, R27, R26); goetz@6458: subfe( R28, R1, R0); goetz@6458: subfe_( R21, R11, R29); goetz@6458: neg( R21, R22); goetz@6458: neg_( R13, R23); goetz@6458: mulli( R0, R11, -31); goetz@6458: mulld( R1, R18, R21); goetz@6458: mulld_( R2, R17, R22); goetz@6458: mullw( R3, R16, R23); goetz@6458: mullw_( R4, R15, R24); goetz@6458: divd( R5, R14, R25); goetz@6458: divd_( R6, R13, R26); goetz@6458: divw( R7, R12, R27); goetz@6458: divw_( R8, R11, R28); goetz@6458: goetz@6458: li( R3, -4711); goetz@6458: goetz@6458: // PPC 1, section 3.3.9, Fixed-Point Compare Instructions goetz@6458: cmpi( CCR7, 0, R27, 4711); goetz@6458: cmp( CCR0, 1, R14, R11); goetz@6458: cmpli( CCR5, 1, R17, 45); goetz@6458: cmpl( CCR3, 0, R9, R10); goetz@6458: goetz@6458: cmpwi( CCR7, R27, 4711); goetz@6458: cmpw( CCR0, R14, R11); goetz@6458: cmplwi( CCR5, R17, 45); goetz@6458: cmplw( CCR3, R9, R10); goetz@6458: goetz@6458: cmpdi( CCR7, R27, 4711); goetz@6458: cmpd( CCR0, R14, R11); goetz@6458: cmpldi( CCR5, R17, 45); goetz@6458: cmpld( CCR3, R9, R10); goetz@6458: goetz@6458: // PPC 1, section 3.3.11, Fixed-Point Logical Instructions goetz@6458: andi_( R4, R5, 0xff); goetz@6458: andis_( R12, R13, 0x7b51); goetz@6458: ori( R1, R4, 13); goetz@6458: oris( R3, R5, 177); goetz@6458: xori( R7, R6, 51); goetz@6458: xoris( R29, R0, 1); goetz@6458: andr( R17, R21, R16); goetz@6458: and_( R3, R5, R15); goetz@6458: orr( R2, R1, R9); goetz@6458: or_( R17, R15, R11); goetz@6458: xorr( R19, R18, R10); goetz@6458: xor_( R31, R21, R11); goetz@6458: nand( R5, R7, R3); goetz@6458: nand_( R3, R1, R0); goetz@6458: nor( R2, R3, R5); goetz@6458: nor_( R3, R6, R8); goetz@6458: andc( R25, R12, R11); goetz@6458: andc_( R24, R22, R21); goetz@6458: orc( R20, R10, R12); goetz@6458: orc_( R22, R2, R13); goetz@6458: goetz@6458: nop(); goetz@6458: goetz@6458: // PPC 1, section 3.3.12, Fixed-Point Rotate and Shift Instructions goetz@6458: sld( R5, R6, R8); goetz@6458: sld_( R3, R5, R9); goetz@6458: slw( R2, R1, R10); goetz@6458: slw_( R6, R26, R16); goetz@6458: srd( R16, R24, R8); goetz@6458: srd_( R21, R14, R7); goetz@6458: srw( R22, R25, R29); goetz@6458: srw_( R5, R18, R17); goetz@6458: srad( R7, R11, R0); goetz@6458: srad_( R9, R13, R1); goetz@6458: sraw( R7, R15, R2); goetz@6458: sraw_( R4, R17, R3); goetz@6458: sldi( R3, R18, 63); goetz@6458: sldi_( R2, R20, 30); goetz@6458: slwi( R1, R21, 30); goetz@6458: slwi_( R7, R23, 8); goetz@6458: srdi( R0, R19, 2); goetz@6458: srdi_( R12, R24, 5); goetz@6458: srwi( R13, R27, 6); goetz@6458: srwi_( R14, R29, 7); goetz@6458: sradi( R15, R30, 9); goetz@6458: sradi_( R16, R31, 19); goetz@6458: srawi( R17, R31, 15); goetz@6458: srawi_( R18, R31, 12); goetz@6458: goetz@6458: clrrdi( R3, R30, 5); goetz@6458: clrldi( R9, R10, 11); goetz@6458: goetz@6458: rldicr( R19, R20, 13, 15); goetz@6458: rldicr_(R20, R20, 16, 14); goetz@6458: rldicl( R21, R21, 30, 33); goetz@6458: rldicl_(R22, R1, 20, 25); goetz@6458: rlwinm( R23, R2, 25, 10, 11); goetz@6458: rlwinm_(R24, R3, 12, 13, 14); goetz@6458: goetz@6458: // PPC 1, section 3.3.2 Fixed-Point Load Instructions goetz@6458: lwzx( R3, R5, R7); goetz@6458: lwz( R11, 0, R1); goetz@6458: lwzu( R31, -4, R11); goetz@6458: goetz@6458: lwax( R3, R5, R7); goetz@6458: lwa( R31, -4, R11); goetz@6458: lhzx( R3, R5, R7); goetz@6458: lhz( R31, -4, R11); goetz@6458: lhzu( R31, -4, R11); goetz@6458: goetz@6458: goetz@6458: lhax( R3, R5, R7); goetz@6458: lha( R31, -4, R11); goetz@6458: lhau( R11, 0, R1); goetz@6458: goetz@6458: lbzx( R3, R5, R7); goetz@6458: lbz( R31, -4, R11); goetz@6458: lbzu( R11, 0, R1); goetz@6458: goetz@6458: ld( R31, -4, R11); goetz@6458: ldx( R3, R5, R7); goetz@6458: ldu( R31, -4, R11); goetz@6458: goetz@6458: // PPC 1, section 3.3.3 Fixed-Point Store Instructions goetz@6458: stwx( R3, R5, R7); goetz@6458: stw( R31, -4, R11); goetz@6458: stwu( R11, 0, R1); goetz@6458: goetz@6458: sthx( R3, R5, R7 ); goetz@6458: sth( R31, -4, R11); goetz@6458: sthu( R31, -4, R11); goetz@6458: goetz@6458: stbx( R3, R5, R7); goetz@6458: stb( R31, -4, R11); goetz@6458: stbu( R31, -4, R11); goetz@6458: goetz@6458: std( R31, -4, R11); goetz@6458: stdx( R3, R5, R7); goetz@6458: stdu( R31, -4, R11); goetz@6458: goetz@6458: // PPC 1, section 3.3.13 Move To/From System Register Instructions goetz@6458: mtlr( R3); goetz@6458: mflr( R3); goetz@6458: mtctr( R3); goetz@6458: mfctr( R3); goetz@6458: mtcrf( 0xff, R15); goetz@6458: mtcr( R15); goetz@6458: mtcrf( 0x03, R15); goetz@6458: mtcr( R15); goetz@6458: mfcr( R15); goetz@6458: goetz@6458: // PPC 1, section 2.4.1 Branch Instructions goetz@6458: Label lbl1, lbl2, lbl3; goetz@6458: bind(lbl1); goetz@6458: goetz@6458: b(pc()); goetz@6458: b(pc() - 8); goetz@6458: b(lbl1); goetz@6458: b(lbl2); goetz@6458: b(lbl3); goetz@6458: goetz@6458: bl(pc() - 8); goetz@6458: bl(lbl1); goetz@6458: bl(lbl2); goetz@6458: goetz@6458: bcl(4, 10, pc() - 8); goetz@6458: bcl(4, 10, lbl1); goetz@6458: bcl(4, 10, lbl2); goetz@6458: goetz@6458: bclr( 4, 6, 0); goetz@6458: bclrl(4, 6, 0); goetz@6458: goetz@6458: bind(lbl2); goetz@6458: goetz@6458: bcctr( 4, 6, 0); goetz@6458: bcctrl(4, 6, 0); goetz@6458: goetz@6458: blt(CCR0, lbl2); goetz@6458: bgt(CCR1, lbl2); goetz@6458: beq(CCR2, lbl2); goetz@6458: bso(CCR3, lbl2); goetz@6458: bge(CCR4, lbl2); goetz@6458: ble(CCR5, lbl2); goetz@6458: bne(CCR6, lbl2); goetz@6458: bns(CCR7, lbl2); goetz@6458: goetz@6458: bltl(CCR0, lbl2); goetz@6458: bgtl(CCR1, lbl2); goetz@6458: beql(CCR2, lbl2); goetz@6458: bsol(CCR3, lbl2); goetz@6458: bgel(CCR4, lbl2); goetz@6458: blel(CCR5, lbl2); goetz@6458: bnel(CCR6, lbl2); goetz@6458: bnsl(CCR7, lbl2); goetz@6458: blr(); goetz@6458: goetz@6458: sync(); goetz@6458: icbi( R1, R2); goetz@6458: dcbst(R2, R3); goetz@6458: goetz@6458: // FLOATING POINT instructions ppc. goetz@6458: // PPC 1, section 4.6.2 Floating-Point Load Instructions goetz@6458: lfs( F1, -11, R3); goetz@6458: lfsu(F2, 123, R4); goetz@6458: lfsx(F3, R5, R6); goetz@6458: lfd( F4, 456, R7); goetz@6458: lfdu(F5, 789, R8); goetz@6458: lfdx(F6, R10, R11); goetz@6458: goetz@6458: // PPC 1, section 4.6.3 Floating-Point Store Instructions goetz@6458: stfs( F7, 876, R12); goetz@6458: stfsu( F8, 543, R13); goetz@6458: stfsx( F9, R14, R15); goetz@6458: stfd( F10, 210, R16); goetz@6458: stfdu( F11, 111, R17); goetz@6458: stfdx( F12, R18, R19); goetz@6458: goetz@6458: // PPC 1, section 4.6.4 Floating-Point Move Instructions goetz@6458: fmr( F13, F14); goetz@6458: fmr_( F14, F15); goetz@6458: fneg( F16, F17); goetz@6458: fneg_( F18, F19); goetz@6458: fabs( F20, F21); goetz@6458: fabs_( F22, F23); goetz@6458: fnabs( F24, F25); goetz@6458: fnabs_(F26, F27); goetz@6458: goetz@6458: // PPC 1, section 4.6.5.1 Floating-Point Elementary Arithmetic goetz@6458: // Instructions goetz@6458: fadd( F28, F29, F30); goetz@6458: fadd_( F31, F0, F1); goetz@6458: fadds( F2, F3, F4); goetz@6458: fadds_(F5, F6, F7); goetz@6458: fsub( F8, F9, F10); goetz@6458: fsub_( F11, F12, F13); goetz@6458: fsubs( F14, F15, F16); goetz@6458: fsubs_(F17, F18, F19); goetz@6458: fmul( F20, F21, F22); goetz@6458: fmul_( F23, F24, F25); goetz@6458: fmuls( F26, F27, F28); goetz@6458: fmuls_(F29, F30, F31); goetz@6458: fdiv( F0, F1, F2); goetz@6458: fdiv_( F3, F4, F5); goetz@6458: fdivs( F6, F7, F8); goetz@6458: fdivs_(F9, F10, F11); goetz@6458: goetz@6458: // PPC 1, section 4.6.6 Floating-Point Rounding and Conversion goetz@6458: // Instructions goetz@6458: frsp( F12, F13); goetz@6458: fctid( F14, F15); goetz@6458: fctidz(F16, F17); goetz@6458: fctiw( F18, F19); goetz@6458: fctiwz(F20, F21); goetz@6458: fcfid( F22, F23); goetz@6458: goetz@6458: // PPC 1, section 4.6.7 Floating-Point Compare Instructions goetz@6458: fcmpu( CCR7, F24, F25); goetz@6458: goetz@6458: tty->print_cr("\ntest_asm disassembly (0x%lx 0x%lx):", code()->insts_begin(), code()->insts_end()); goetz@6458: code()->decode(); goetz@6458: } goetz@6515: goetz@6458: #endif // !PRODUCT