view src/cpu/ppc/vm/assembler_ppc.cpp @ 20304:a22acf6d7598

8048112: G1 Full GC needs to support the case when the very first region is not available Summary: Refactor preparation for compaction during Full GC so that it lazily initializes the first compaction point. This also avoids problems later when the first region may not be committed. Also reviewed by K. Barrett. Reviewed-by: brutisso
author tschatzl
date Mon, 21 Jul 2014 10:00:31 +0200
parents 71a71b0bc844
children 327e7269f90d
line wrap: on
line source

/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2012, 2014 SAP AG. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#include "precompiled.hpp"
#include "asm/assembler.inline.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/cardTableModRefBS.hpp"
#include "memory/resourceArea.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/objectMonitor.hpp"
#include "runtime/os.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
#include "gc_implementation/g1/heapRegion.hpp"
#endif // INCLUDE_ALL_GCS

#ifdef PRODUCT
#define BLOCK_COMMENT(str) // nothing
#else
#define BLOCK_COMMENT(str) block_comment(str)
#endif

int AbstractAssembler::code_fill_byte() {
  return 0x00;                  // illegal instruction 0x00000000
}

void Assembler::print_instruction(int inst) {
  Unimplemented();
}

// Patch instruction `inst' at offset `inst_pos' to refer to
// `dest_pos' and return the resulting instruction.  We should have
// pcs, not offsets, but since all is relative, it will work out fine.
int Assembler::patched_branch(int dest_pos, int inst, int inst_pos) {
  int m = 0; // mask for displacement field
  int v = 0; // new value for displacement field

  switch (inv_op_ppc(inst)) {
  case b_op:  m = li(-1); v = li(disp(dest_pos, inst_pos)); break;
  case bc_op: m = bd(-1); v = bd(disp(dest_pos, inst_pos)); break;
    default: ShouldNotReachHere();
  }
  return inst & ~m | v;
}

// Return the offset, relative to _code_begin, of the destination of
// the branch inst at offset pos.
int Assembler::branch_destination(int inst, int pos) {
  int r = 0;
  switch (inv_op_ppc(inst)) {
    case b_op:  r = bxx_destination_offset(inst, pos); break;
    case bc_op: r = inv_bd_field(inst, pos); break;
    default: ShouldNotReachHere();
  }
  return r;
}

// Low-level andi-one-instruction-macro.
void Assembler::andi(Register a, Register s, const int ui16) {
  assert(is_uimm(ui16, 16), "must be 16-bit unsigned immediate");
  if (is_power_of_2_long(((jlong) ui16)+1)) {
    // pow2minus1
    clrldi(a, s, 64-log2_long((((jlong) ui16)+1)));
  } else if (is_power_of_2_long((jlong) ui16)) {
    // pow2
    rlwinm(a, s, 0, 31-log2_long((jlong) ui16), 31-log2_long((jlong) ui16));
  } else if (is_power_of_2_long((jlong)-ui16)) {
    // negpow2
    clrrdi(a, s, log2_long((jlong)-ui16));
  } else {
    andi_(a, s, ui16);
  }
}

// RegisterOrConstant version.
void Assembler::ld(Register d, RegisterOrConstant roc, Register s1) {
  if (roc.is_constant()) {
    if (s1 == noreg) {
      int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true);
      Assembler::ld(d, simm16_rest, d);
    } else if (is_simm(roc.as_constant(), 16)) {
      Assembler::ld(d, roc.as_constant(), s1);
    } else {
      load_const_optimized(d, roc.as_constant());
      Assembler::ldx(d, d, s1);
    }
  } else {
    if (s1 == noreg)
      Assembler::ld(d, 0, roc.as_register());
    else
      Assembler::ldx(d, roc.as_register(), s1);
  }
}

void Assembler::lwa(Register d, RegisterOrConstant roc, Register s1) {
  if (roc.is_constant()) {
    if (s1 == noreg) {
      int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true);
      Assembler::lwa(d, simm16_rest, d);
    } else if (is_simm(roc.as_constant(), 16)) {
      Assembler::lwa(d, roc.as_constant(), s1);
    } else {
      load_const_optimized(d, roc.as_constant());
      Assembler::lwax(d, d, s1);
    }
  } else {
    if (s1 == noreg)
      Assembler::lwa(d, 0, roc.as_register());
    else
      Assembler::lwax(d, roc.as_register(), s1);
  }
}

void Assembler::lwz(Register d, RegisterOrConstant roc, Register s1) {
  if (roc.is_constant()) {
    if (s1 == noreg) {
      int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true);
      Assembler::lwz(d, simm16_rest, d);
    } else if (is_simm(roc.as_constant(), 16)) {
      Assembler::lwz(d, roc.as_constant(), s1);
    } else {
      load_const_optimized(d, roc.as_constant());
      Assembler::lwzx(d, d, s1);
    }
  } else {
    if (s1 == noreg)
      Assembler::lwz(d, 0, roc.as_register());
    else
      Assembler::lwzx(d, roc.as_register(), s1);
  }
}

void Assembler::lha(Register d, RegisterOrConstant roc, Register s1) {
  if (roc.is_constant()) {
    if (s1 == noreg) {
      int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true);
      Assembler::lha(d, simm16_rest, d);
    } else if (is_simm(roc.as_constant(), 16)) {
      Assembler::lha(d, roc.as_constant(), s1);
    } else {
      load_const_optimized(d, roc.as_constant());
      Assembler::lhax(d, d, s1);
    }
  } else {
    if (s1 == noreg)
      Assembler::lha(d, 0, roc.as_register());
    else
      Assembler::lhax(d, roc.as_register(), s1);
  }
}

void Assembler::lhz(Register d, RegisterOrConstant roc, Register s1) {
  if (roc.is_constant()) {
    if (s1 == noreg) {
      int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true);
      Assembler::lhz(d, simm16_rest, d);
    } else if (is_simm(roc.as_constant(), 16)) {
      Assembler::lhz(d, roc.as_constant(), s1);
    } else {
      load_const_optimized(d, roc.as_constant());
      Assembler::lhzx(d, d, s1);
    }
  } else {
    if (s1 == noreg)
      Assembler::lhz(d, 0, roc.as_register());
    else
      Assembler::lhzx(d, roc.as_register(), s1);
  }
}

void Assembler::lbz(Register d, RegisterOrConstant roc, Register s1) {
  if (roc.is_constant()) {
    if (s1 == noreg) {
      int simm16_rest = load_const_optimized(d, roc.as_constant(), noreg, true);
      Assembler::lbz(d, simm16_rest, d);
    } else if (is_simm(roc.as_constant(), 16)) {
      Assembler::lbz(d, roc.as_constant(), s1);
    } else {
      load_const_optimized(d, roc.as_constant());
      Assembler::lbzx(d, d, s1);
    }
  } else {
    if (s1 == noreg)
      Assembler::lbz(d, 0, roc.as_register());
    else
      Assembler::lbzx(d, roc.as_register(), s1);
  }
}

void Assembler::std(Register d, RegisterOrConstant roc, Register s1, Register tmp) {
  if (roc.is_constant()) {
    if (s1 == noreg) {
      guarantee(tmp != noreg, "Need tmp reg to encode large constants");
      int simm16_rest = load_const_optimized(tmp, roc.as_constant(), noreg, true);
      Assembler::std(d, simm16_rest, tmp);
    } else if (is_simm(roc.as_constant(), 16)) {
      Assembler::std(d, roc.as_constant(), s1);
    } else {
      guarantee(tmp != noreg, "Need tmp reg to encode large constants");
      load_const_optimized(tmp, roc.as_constant());
      Assembler::stdx(d, tmp, s1);
    }
  } else {
    if (s1 == noreg)
      Assembler::std(d, 0, roc.as_register());
    else
      Assembler::stdx(d, roc.as_register(), s1);
  }
}

void Assembler::stw(Register d, RegisterOrConstant roc, Register s1, Register tmp) {
  if (roc.is_constant()) {
    if (s1 == noreg) {
      guarantee(tmp != noreg, "Need tmp reg to encode large constants");
      int simm16_rest = load_const_optimized(tmp, roc.as_constant(), noreg, true);
      Assembler::stw(d, simm16_rest, tmp);
    } else if (is_simm(roc.as_constant(), 16)) {
      Assembler::stw(d, roc.as_constant(), s1);
    } else {
      guarantee(tmp != noreg, "Need tmp reg to encode large constants");
      load_const_optimized(tmp, roc.as_constant());
      Assembler::stwx(d, tmp, s1);
    }
  } else {
    if (s1 == noreg)
      Assembler::stw(d, 0, roc.as_register());
    else
      Assembler::stwx(d, roc.as_register(), s1);
  }
}

void Assembler::sth(Register d, RegisterOrConstant roc, Register s1, Register tmp) {
  if (roc.is_constant()) {
    if (s1 == noreg) {
      guarantee(tmp != noreg, "Need tmp reg to encode large constants");
      int simm16_rest = load_const_optimized(tmp, roc.as_constant(), noreg, true);
      Assembler::sth(d, simm16_rest, tmp);
    } else if (is_simm(roc.as_constant(), 16)) {
      Assembler::sth(d, roc.as_constant(), s1);
    } else {
      guarantee(tmp != noreg, "Need tmp reg to encode large constants");
      load_const_optimized(tmp, roc.as_constant());
      Assembler::sthx(d, tmp, s1);
    }
  } else {
    if (s1 == noreg)
      Assembler::sth(d, 0, roc.as_register());
    else
      Assembler::sthx(d, roc.as_register(), s1);
  }
}

void Assembler::stb(Register d, RegisterOrConstant roc, Register s1, Register tmp) {
  if (roc.is_constant()) {
    if (s1 == noreg) {
      guarantee(tmp != noreg, "Need tmp reg to encode large constants");
      int simm16_rest = load_const_optimized(tmp, roc.as_constant(), noreg, true);
      Assembler::stb(d, simm16_rest, tmp);
    } else if (is_simm(roc.as_constant(), 16)) {
      Assembler::stb(d, roc.as_constant(), s1);
    } else {
      guarantee(tmp != noreg, "Need tmp reg to encode large constants");
      load_const_optimized(tmp, roc.as_constant());
      Assembler::stbx(d, tmp, s1);
    }
  } else {
    if (s1 == noreg)
      Assembler::stb(d, 0, roc.as_register());
    else
      Assembler::stbx(d, roc.as_register(), s1);
  }
}

void Assembler::add(Register d, RegisterOrConstant roc, Register s1) {
  if (roc.is_constant()) {
    intptr_t c = roc.as_constant();
    assert(is_simm(c, 16), "too big");
    addi(d, s1, (int)c);
  }
  else add(d, roc.as_register(), s1);
}

void Assembler::subf(Register d, RegisterOrConstant roc, Register s1) {
  if (roc.is_constant()) {
    intptr_t c = roc.as_constant();
    assert(is_simm(-c, 16), "too big");
    addi(d, s1, (int)-c);
  }
  else subf(d, roc.as_register(), s1);
}

void Assembler::cmpd(ConditionRegister d, RegisterOrConstant roc, Register s1) {
  if (roc.is_constant()) {
    intptr_t c = roc.as_constant();
    assert(is_simm(c, 16), "too big");
    cmpdi(d, s1, (int)c);
  }
  else cmpd(d, roc.as_register(), s1);
}

// Load a 64 bit constant. Patchable.
void Assembler::load_const(Register d, long x, Register tmp) {
  // 64-bit value: x = xa xb xc xd
  int xa = (x >> 48) & 0xffff;
  int xb = (x >> 32) & 0xffff;
  int xc = (x >> 16) & 0xffff;
  int xd = (x >>  0) & 0xffff;
  if (tmp == noreg) {
    Assembler::lis( d, (int)(short)xa);
    Assembler::ori( d, d, (unsigned int)xb);
    Assembler::sldi(d, d, 32);
    Assembler::oris(d, d, (unsigned int)xc);
    Assembler::ori( d, d, (unsigned int)xd);
  } else {
    // exploit instruction level parallelism if we have a tmp register
    assert_different_registers(d, tmp);
    Assembler::lis(tmp, (int)(short)xa);
    Assembler::lis(d, (int)(short)xc);
    Assembler::ori(tmp, tmp, (unsigned int)xb);
    Assembler::ori(d, d, (unsigned int)xd);
    Assembler::insrdi(d, tmp, 32, 0);
  }
}

// Load a 64 bit constant, optimized, not identifyable.
// Tmp can be used to increase ILP. Set return_simm16_rest=true to get a
// 16 bit immediate offset.
int Assembler::load_const_optimized(Register d, long x, Register tmp, bool return_simm16_rest) {
  // Avoid accidentally trying to use R0 for indexed addressing.
  assert(d != R0, "R0 not allowed");
  assert_different_registers(d, tmp);

  short xa, xb, xc, xd; // Four 16-bit chunks of const.
  long rem = x;         // Remaining part of const.

  xd = rem & 0xFFFF;    // Lowest 16-bit chunk.
  rem = (rem >> 16) + ((unsigned short)xd >> 15); // Compensation for sign extend.

  if (rem == 0) { // opt 1: simm16
    li(d, xd);
    return 0;
  }

  xc = rem & 0xFFFF; // Next 16-bit chunk.
  rem = (rem >> 16) + ((unsigned short)xc >> 15); // Compensation for sign extend.

  if (rem == 0) { // opt 2: simm32
    lis(d, xc);
  } else { // High 32 bits needed.

    if (tmp != noreg) { // opt 3: We have a temp reg.
      // No carry propagation between xc and higher chunks here (use logical instructions).
      xa = (x >> 48) & 0xffff;
      xb = (x >> 32) & 0xffff; // No sign compensation, we use lis+ori or li to allow usage of R0.
      bool load_xa = (xa != 0) || (xb < 0);
      bool return_xd = false;

      if (load_xa) { lis(tmp, xa); }
      if (xc) { lis(d, xc); }
      if (load_xa) {
        if (xb) { ori(tmp, tmp, (unsigned short)xb); } // No addi, we support tmp == R0.
      } else {
        li(tmp, xb); // non-negative
      }
      if (xc) {
        if (return_simm16_rest && xd >= 0) { return_xd = true; } // >= 0 to avoid carry propagation after insrdi/rldimi.
        else if (xd) { addi(d, d, xd); }
      } else {
        li(d, xd);
      }
      insrdi(d, tmp, 32, 0);
      return return_xd ? xd : 0; // non-negative
    }

    xb = rem & 0xFFFF; // Next 16-bit chunk.
    rem = (rem >> 16) + ((unsigned short)xb >> 15); // Compensation for sign extend.

    xa = rem & 0xFFFF; // Highest 16-bit chunk.

    // opt 4: avoid adding 0
    if (xa) { // Highest 16-bit needed?
      lis(d, xa);
      if (xb) { addi(d, d, xb); }
    } else {
      li(d, xb);
    }
    sldi(d, d, 32);
    if (xc) { addis(d, d, xc); }
  }

  // opt 5: Return offset to be inserted into following instruction.
  if (return_simm16_rest) return xd;

  if (xd) { addi(d, d, xd); }
  return 0;
}

#ifndef PRODUCT
// Test of ppc assembler.
void Assembler::test_asm() {
  // PPC 1, section 3.3.8, Fixed-Point Arithmetic Instructions
  addi(   R0,  R1,  10);
  addis(  R5,  R2,  11);
  addic_( R3,  R31, 42);
  subfic( R21, R12, 2112);
  add(    R3,  R2,  R1);
  add_(   R11, R22, R30);
  subf(   R7,  R6,  R5);
  subf_(  R8,  R9,  R4);
  addc(   R11, R12, R13);
  addc_(  R14, R14, R14);
  subfc(  R15, R16, R17);
  subfc_( R18, R20, R19);
  adde(   R20, R22, R24);
  adde_(  R29, R27, R26);
  subfe(  R28, R1,  R0);
  subfe_( R21, R11, R29);
  neg(    R21, R22);
  neg_(   R13, R23);
  mulli(  R0,  R11, -31);
  mulld(  R1,  R18, R21);
  mulld_( R2,  R17, R22);
  mullw(  R3,  R16, R23);
  mullw_( R4,  R15, R24);
  divd(   R5,  R14, R25);
  divd_(  R6,  R13, R26);
  divw(   R7,  R12, R27);
  divw_(  R8,  R11, R28);

  li(     R3, -4711);

  // PPC 1, section 3.3.9, Fixed-Point Compare Instructions
  cmpi(   CCR7,  0, R27, 4711);
  cmp(    CCR0, 1, R14, R11);
  cmpli(  CCR5,  1, R17, 45);
  cmpl(   CCR3, 0, R9,  R10);

  cmpwi(  CCR7,  R27, 4711);
  cmpw(   CCR0, R14, R11);
  cmplwi( CCR5,  R17, 45);
  cmplw(  CCR3, R9,  R10);

  cmpdi(  CCR7,  R27, 4711);
  cmpd(   CCR0, R14, R11);
  cmpldi( CCR5,  R17, 45);
  cmpld(  CCR3, R9,  R10);

  // PPC 1, section 3.3.11, Fixed-Point Logical Instructions
  andi_(  R4,  R5,  0xff);
  andis_( R12, R13, 0x7b51);
  ori(    R1,  R4,  13);
  oris(   R3,  R5,  177);
  xori(   R7,  R6,  51);
  xoris(  R29, R0,  1);
  andr(   R17, R21, R16);
  and_(   R3,  R5,  R15);
  orr(    R2,  R1,  R9);
  or_(    R17, R15, R11);
  xorr(   R19, R18, R10);
  xor_(   R31, R21, R11);
  nand(   R5,  R7,  R3);
  nand_(  R3,  R1,  R0);
  nor(    R2,  R3,  R5);
  nor_(   R3,  R6,  R8);
  andc(   R25, R12, R11);
  andc_(  R24, R22, R21);
  orc(    R20, R10, R12);
  orc_(   R22, R2,  R13);

  nop();

  // PPC 1, section 3.3.12, Fixed-Point Rotate and Shift Instructions
  sld(    R5,  R6,  R8);
  sld_(   R3,  R5,  R9);
  slw(    R2,  R1,  R10);
  slw_(   R6,  R26, R16);
  srd(    R16, R24, R8);
  srd_(   R21, R14, R7);
  srw(    R22, R25, R29);
  srw_(   R5,  R18, R17);
  srad(   R7,  R11, R0);
  srad_(  R9,  R13, R1);
  sraw(   R7,  R15, R2);
  sraw_(  R4,  R17, R3);
  sldi(   R3,  R18, 63);
  sldi_(  R2,  R20, 30);
  slwi(   R1,  R21, 30);
  slwi_(  R7,  R23, 8);
  srdi(   R0,  R19, 2);
  srdi_(  R12, R24, 5);
  srwi(   R13, R27, 6);
  srwi_(  R14, R29, 7);
  sradi(  R15, R30, 9);
  sradi_( R16, R31, 19);
  srawi(  R17, R31, 15);
  srawi_( R18, R31, 12);

  clrrdi( R3, R30, 5);
  clrldi( R9, R10, 11);

  rldicr( R19, R20, 13, 15);
  rldicr_(R20, R20, 16, 14);
  rldicl( R21, R21, 30, 33);
  rldicl_(R22, R1,  20, 25);
  rlwinm( R23, R2,  25, 10, 11);
  rlwinm_(R24, R3,  12, 13, 14);

  // PPC 1, section 3.3.2 Fixed-Point Load Instructions
  lwzx(   R3,  R5, R7);
  lwz(    R11,  0, R1);
  lwzu(   R31, -4, R11);

  lwax(   R3,  R5, R7);
  lwa(    R31, -4, R11);
  lhzx(   R3,  R5, R7);
  lhz(    R31, -4, R11);
  lhzu(   R31, -4, R11);


  lhax(   R3,  R5, R7);
  lha(    R31, -4, R11);
  lhau(   R11,  0, R1);

  lbzx(   R3,  R5, R7);
  lbz(    R31, -4, R11);
  lbzu(   R11,  0, R1);

  ld(     R31, -4, R11);
  ldx(    R3,  R5, R7);
  ldu(    R31, -4, R11);

  //  PPC 1, section 3.3.3 Fixed-Point Store Instructions
  stwx(   R3,  R5, R7);
  stw(    R31, -4, R11);
  stwu(   R11,  0, R1);

  sthx(   R3,  R5, R7 );
  sth(    R31, -4, R11);
  sthu(   R31, -4, R11);

  stbx(   R3,  R5, R7);
  stb(    R31, -4, R11);
  stbu(   R31, -4, R11);

  std(    R31, -4, R11);
  stdx(   R3,  R5, R7);
  stdu(   R31, -4, R11);

 // PPC 1, section 3.3.13 Move To/From System Register Instructions
  mtlr(   R3);
  mflr(   R3);
  mtctr(  R3);
  mfctr(  R3);
  mtcrf(  0xff, R15);
  mtcr(   R15);
  mtcrf(  0x03, R15);
  mtcr(   R15);
  mfcr(   R15);

 // PPC 1, section 2.4.1 Branch Instructions
  Label lbl1, lbl2, lbl3;
  bind(lbl1);

  b(pc());
  b(pc() - 8);
  b(lbl1);
  b(lbl2);
  b(lbl3);

  bl(pc() - 8);
  bl(lbl1);
  bl(lbl2);

  bcl(4, 10, pc() - 8);
  bcl(4, 10, lbl1);
  bcl(4, 10, lbl2);

  bclr( 4, 6, 0);
  bclrl(4, 6, 0);

  bind(lbl2);

  bcctr( 4, 6, 0);
  bcctrl(4, 6, 0);

  blt(CCR0, lbl2);
  bgt(CCR1, lbl2);
  beq(CCR2, lbl2);
  bso(CCR3, lbl2);
  bge(CCR4, lbl2);
  ble(CCR5, lbl2);
  bne(CCR6, lbl2);
  bns(CCR7, lbl2);

  bltl(CCR0, lbl2);
  bgtl(CCR1, lbl2);
  beql(CCR2, lbl2);
  bsol(CCR3, lbl2);
  bgel(CCR4, lbl2);
  blel(CCR5, lbl2);
  bnel(CCR6, lbl2);
  bnsl(CCR7, lbl2);
  blr();

  sync();
  icbi( R1, R2);
  dcbst(R2, R3);

  // FLOATING POINT instructions ppc.
  // PPC 1, section 4.6.2 Floating-Point Load Instructions
  lfs( F1, -11, R3);
  lfsu(F2, 123, R4);
  lfsx(F3, R5,  R6);
  lfd( F4, 456, R7);
  lfdu(F5, 789, R8);
  lfdx(F6, R10, R11);

  // PPC 1, section 4.6.3 Floating-Point Store Instructions
  stfs(  F7,  876, R12);
  stfsu( F8,  543, R13);
  stfsx( F9,  R14, R15);
  stfd(  F10, 210, R16);
  stfdu( F11, 111, R17);
  stfdx( F12, R18, R19);

  // PPC 1, section 4.6.4 Floating-Point Move Instructions
  fmr(   F13, F14);
  fmr_(  F14, F15);
  fneg(  F16, F17);
  fneg_( F18, F19);
  fabs(  F20, F21);
  fabs_( F22, F23);
  fnabs( F24, F25);
  fnabs_(F26, F27);

  // PPC 1, section 4.6.5.1 Floating-Point Elementary Arithmetic
  // Instructions
  fadd(  F28, F29, F30);
  fadd_( F31, F0,  F1);
  fadds( F2,  F3,  F4);
  fadds_(F5,  F6,  F7);
  fsub(  F8,  F9,  F10);
  fsub_( F11, F12, F13);
  fsubs( F14, F15, F16);
  fsubs_(F17, F18, F19);
  fmul(  F20, F21, F22);
  fmul_( F23, F24, F25);
  fmuls( F26, F27, F28);
  fmuls_(F29, F30, F31);
  fdiv(  F0,  F1,  F2);
  fdiv_( F3,  F4,  F5);
  fdivs( F6,  F7,  F8);
  fdivs_(F9,  F10, F11);

  // PPC 1, section 4.6.6 Floating-Point Rounding and Conversion
  // Instructions
  frsp(  F12, F13);
  fctid( F14, F15);
  fctidz(F16, F17);
  fctiw( F18, F19);
  fctiwz(F20, F21);
  fcfid( F22, F23);

  // PPC 1, section 4.6.7 Floating-Point Compare Instructions
  fcmpu( CCR7, F24, F25);

  tty->print_cr("\ntest_asm disassembly (0x%lx 0x%lx):", code()->insts_begin(), code()->insts_end());
  code()->decode();
}

#endif // !PRODUCT