Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openjdk/src/hotspot/cpu/ppc/   (Sun/Oracle ©)  Datei vom 13.11.2022 mit Größe 112 kB image not shown  

Quelle  c1_LIRAssembler_ppc.cpp   Sprache: C

 
/*
 * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2012, 2022 SAP SE. 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/macroAssembler.inline.hpp"
#include "c1/c1_Compilation.hpp"
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "c1/c1_Runtime1.hpp"
#include "c1/c1_ValueStack.hpp"
#include "ci/ciArrayKlass.hpp"
#include "ci/ciInstance.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "memory/universe.hpp"
#include "nativeInst_ppc.hpp"
#include "oops/compressedOops.hpp"
#include "oops/objArrayKlass.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/safepointMechanism.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/macros.hpp"
#include "utilities/powerOfTwo.hpp"

#define __ _masm->


const ConditionRegister LIR_Assembler::BOOL_RESULT = CCR5;


bool LIR_Assembler::is_small_constant(LIR_Opr opr) {
  Unimplemented(); return false// Currently not used on this platform.
}


LIR_Opr LIR_Assembler::receiverOpr() {
  return FrameMap::R3_oop_opr;
}


LIR_Opr LIR_Assembler::osrBufferPointer() {
  return FrameMap::R3_opr;
}


// This specifies the stack pointer decrement needed to build the frame.
int LIR_Assembler::initial_frame_size_in_bytes() const {
  return in_bytes(frame_map()->framesize_in_bytes());
}


// Inline cache check: the inline cached class is in inline_cache_reg;
// we fetch the class of the receiver and compare it with the cached class.
// If they do not match we jump to slow case.
int LIR_Assembler::check_icache() {
  int offset = __ offset();
  __ inline_cache_check(R3_ARG1, R19_inline_cache_reg);
  return offset;
}

void LIR_Assembler::clinit_barrier(ciMethod* method) {
  assert(!method->holder()->is_not_initialized(), "initialization should have been started");

  Label L_skip_barrier;
  Register klass = R20;

  metadata2reg(method->holder()->constant_encoding(), klass);
  __ clinit_barrier(klass, R16_thread, &L_skip_barrier /*L_fast_path*/);

  __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub(), R0);
  __ mtctr(klass);
  __ bctr();

  __ bind(L_skip_barrier);
}

void LIR_Assembler::osr_entry() {
  // On-stack-replacement entry sequence:
  //
  //   1. Create a new compiled activation.
  //   2. Initialize local variables in the compiled activation. The expression
  //      stack must be empty at the osr_bci; it is not initialized.
  //   3. Jump to the continuation address in compiled code to resume execution.

  // OSR entry point
  offsets()->set_value(CodeOffsets::OSR_Entry, code_offset());
  BlockBegin* osr_entry = compilation()->hir()->osr_entry();
  ValueStack* entry_state = osr_entry->end()->state();
  int number_of_locks = entry_state->locks_size();

  // Create a frame for the compiled activation.
  __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes());

  // OSR buffer is
  //
  // locals[nlocals-1..0]
  // monitors[number_of_locks-1..0]
  //
  // Locals is a direct copy of the interpreter frame so in the osr buffer
  // the first slot in the local array is the last local from the interpreter
  // and the last slot is local[0] (receiver) from the interpreter.
  //
  // Similarly with locks. The first lock slot in the osr buffer is the nth lock
  // from the interpreter frame, the nth lock slot in the osr buffer is 0th lock
  // in the interpreter frame (the method lock if a sync method).

  // Initialize monitors in the compiled activation.
  //   R3: pointer to osr buffer
  //
  // All other registers are dead at this point and the locals will be
  // copied into place by code emitted in the IR.

  Register OSR_buf = osrBufferPointer()->as_register();
  { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below");
    int monitor_offset = BytesPerWord * method()->max_locals() +
      (2 * BytesPerWord) * (number_of_locks - 1);
    // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in
    // the OSR buffer using 2 word entries: first the lock and then
    // the oop.
    for (int i = 0; i < number_of_locks; i++) {
      int slot_offset = monitor_offset - ((i * 2) * BytesPerWord);
#ifdef ASSERT
      // Verify the interpreter's monitor has a non-null object.
      {
        Label L;
        __ ld(R0, slot_offset + 1*BytesPerWord, OSR_buf);
        __ cmpdi(CCR0, R0, 0);
        __ bne(CCR0, L);
        __ stop("locked object is NULL");
        __ bind(L);
      }
#endif // ASSERT
      // Copy the lock field into the compiled activation.
      Address ml = frame_map()->address_for_monitor_lock(i),
              mo = frame_map()->address_for_monitor_object(i);
      assert(ml.index() == noreg && mo.index() == noreg, "sanity");
      __ ld(R0, slot_offset + 0, OSR_buf);
      __ std(R0, ml.disp(), ml.base());
      __ ld(R0, slot_offset + 1*BytesPerWord, OSR_buf);
      __ std(R0, mo.disp(), mo.base());
    }
  }
}


int LIR_Assembler::emit_exception_handler() {
  // Generate code for the exception handler.
  address handler_base = __ start_a_stub(exception_handler_size());

  if (handler_base == NULL) {
    // Not enough space left for the handler.
    bailout("exception handler overflow");
    return -1;
  }

  int offset = code_offset();
  address entry_point = CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::handle_exception_from_callee_id));
  //__ load_const_optimized(R0, entry_point);
  __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry_point));
  __ mtctr(R0);
  __ bctr();

  guarantee(code_offset() - offset <= exception_handler_size(), "overflow");
  __ end_a_stub();

  return offset;
}


// Emit the code to remove the frame from the stack in the exception
// unwind path.
int LIR_Assembler::emit_unwind_handler() {
  _masm->block_comment("Unwind handler");

  int offset = code_offset();
  bool preserve_exception = method()->is_synchronized() || compilation()->env()->dtrace_method_probes();
  const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/, Rexception_save = R31;

  // Fetch the exception from TLS and clear out exception related thread state.
  __ ld(Rexception, in_bytes(JavaThread::exception_oop_offset()), R16_thread);
  __ li(R0, 0);
  __ std(R0, in_bytes(JavaThread::exception_oop_offset()), R16_thread);
  __ std(R0, in_bytes(JavaThread::exception_pc_offset()), R16_thread);

  __ bind(_unwind_handler_entry);
  __ verify_not_null_oop(Rexception);
  if (preserve_exception) { __ mr(Rexception_save, Rexception); }

  // Perform needed unlocking
  MonitorExitStub* stub = NULL;
  if (method()->is_synchronized()) {
    monitor_address(0, FrameMap::R4_opr);
    stub = new MonitorExitStub(FrameMap::R4_opr, true, 0);
    __ unlock_object(R5, R6, R4, *stub->entry());
    __ bind(*stub->continuation());
  }

  if (compilation()->env()->dtrace_method_probes()) {
    Unimplemented();
  }

  // Dispatch to the unwind logic.
  address unwind_stub = Runtime1::entry_for(Runtime1::unwind_exception_id);
  //__ load_const_optimized(R0, unwind_stub);
  __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(unwind_stub));
  if (preserve_exception) { __ mr(Rexception, Rexception_save); }
  __ mtctr(R0);
  __ bctr();

  // Emit the slow path assembly.
  if (stub != NULL) {
    stub->emit_code(this);
  }

  return offset;
}


int LIR_Assembler::emit_deopt_handler() {
  // Generate code for deopt handler.
  address handler_base = __ start_a_stub(deopt_handler_size());

  if (handler_base == NULL) {
    // Not enough space left for the handler.
    bailout("deopt handler overflow");
    return -1;
  }

  int offset = code_offset();
  __ bl64_patchable(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type);

  guarantee(code_offset() - offset <= deopt_handler_size(), "overflow");
  __ end_a_stub();

  return offset;
}


void LIR_Assembler::jobject2reg(jobject o, Register reg) {
  if (o == NULL) {
    __ li(reg, 0);
  } else {
    AddressLiteral addrlit = __ constant_oop_address(o);
    __ load_const(reg, addrlit, (reg != R0) ? R0 : noreg);
  }
}


void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo *info) {
  // Allocate a new index in table to hold the object once it's been patched.
  int oop_index = __ oop_recorder()->allocate_oop_index(NULL);
  PatchingStub* patch = new PatchingStub(_masm, patching_id(info), oop_index);

  AddressLiteral addrlit((address)NULL, oop_Relocation::spec(oop_index));
  __ load_const(reg, addrlit, R0);

  patching_epilog(patch, lir_patch_normal, reg, info);
}


void LIR_Assembler::metadata2reg(Metadata* o, Register reg) {
  AddressLiteral md = __ constant_metadata_address(o); // Notify OOP recorder (don't need the relocation)
  __ load_const_optimized(reg, md.value(), (reg != R0) ? R0 : noreg);
}


void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo *info) {
  // Allocate a new index in table to hold the klass once it's been patched.
  int index = __ oop_recorder()->allocate_metadata_index(NULL);
  PatchingStub* patch = new PatchingStub(_masm, PatchingStub::load_klass_id, index);

  AddressLiteral addrlit((address)NULL, metadata_Relocation::spec(index));
  assert(addrlit.rspec().type() == relocInfo::metadata_type, "must be an metadata reloc");
  __ load_const(reg, addrlit, R0);

  patching_epilog(patch, lir_patch_normal, reg, info);
}


void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr temp, LIR_Opr result, CodeEmitInfo* info) {
  const bool is_int = result->is_single_cpu();
  Register Rdividend = is_int ? left->as_register() : left->as_register_lo();
  Register Rdivisor  = noreg;
  Register Rscratch  = temp->as_register();
  Register Rresult   = is_int ? result->as_register() : result->as_register_lo();
  long divisor = -1;

  if (right->is_register()) {
    Rdivisor = is_int ? right->as_register() : right->as_register_lo();
  } else {
    divisor = is_int ? right->as_constant_ptr()->as_jint()
                     : right->as_constant_ptr()->as_jlong();
  }

  assert(Rdividend != Rscratch, "");
  assert(Rdivisor  != Rscratch, "");
  assert(code == lir_idiv || code == lir_irem, "Must be irem or idiv");

  if (Rdivisor == noreg) {
    if (divisor == 1) { // stupid, but can happen
      if (code == lir_idiv) {
        __ mr_if_needed(Rresult, Rdividend);
      } else {
        __ li(Rresult, 0);
      }

    } else if (is_power_of_2(divisor)) {
      // Convert division by a power of two into some shifts and logical operations.
      int log2 = log2i_exact(divisor);

      // Round towards 0.
      if (divisor == 2) {
        if (is_int) {
          __ srwi(Rscratch, Rdividend, 31);
        } else {
          __ srdi(Rscratch, Rdividend, 63);
        }
      } else {
        if (is_int) {
          __ srawi(Rscratch, Rdividend, 31);
        } else {
          __ sradi(Rscratch, Rdividend, 63);
        }
        __ clrldi(Rscratch, Rscratch, 64-log2);
      }
      __ add(Rscratch, Rdividend, Rscratch);

      if (code == lir_idiv) {
        if (is_int) {
          __ srawi(Rresult, Rscratch, log2);
        } else {
          __ sradi(Rresult, Rscratch, log2);
        }
      } else { // lir_irem
        __ clrrdi(Rscratch, Rscratch, log2);
        __ sub(Rresult, Rdividend, Rscratch);
      }

    } else if (divisor == -1) {
      if (code == lir_idiv) {
        __ neg(Rresult, Rdividend);
      } else {
        __ li(Rresult, 0);
      }

    } else {
      __ load_const_optimized(Rscratch, divisor);
      if (code == lir_idiv) {
        if (is_int) {
          __ divw(Rresult, Rdividend, Rscratch); // Can't divide minint/-1.
        } else {
          __ divd(Rresult, Rdividend, Rscratch); // Can't divide minint/-1.
        }
      } else {
        assert(Rscratch != R0, "need both");
        if (is_int) {
          __ divw(R0, Rdividend, Rscratch); // Can't divide minint/-1.
          __ mullw(Rscratch, R0, Rscratch);
        } else {
          __ divd(R0, Rdividend, Rscratch); // Can't divide minint/-1.
          __ mulld(Rscratch, R0, Rscratch);
        }
        __ sub(Rresult, Rdividend, Rscratch);
      }

    }
    return;
  }

  Label regular, done;
  if (is_int) {
    __ cmpwi(CCR0, Rdivisor, -1);
  } else {
    __ cmpdi(CCR0, Rdivisor, -1);
  }
  __ bne(CCR0, regular);
  if (code == lir_idiv) {
    __ neg(Rresult, Rdividend);
    __ b(done);
    __ bind(regular);
    if (is_int) {
      __ divw(Rresult, Rdividend, Rdivisor); // Can't divide minint/-1.
    } else {
      __ divd(Rresult, Rdividend, Rdivisor); // Can't divide minint/-1.
    }
  } else { // lir_irem
    __ li(Rresult, 0);
    __ b(done);
    __ bind(regular);
    if (is_int) {
      __ divw(Rscratch, Rdividend, Rdivisor); // Can't divide minint/-1.
      __ mullw(Rscratch, Rscratch, Rdivisor);
    } else {
      __ divd(Rscratch, Rdividend, Rdivisor); // Can't divide minint/-1.
      __ mulld(Rscratch, Rscratch, Rdivisor);
    }
    __ sub(Rresult, Rdividend, Rscratch);
  }
  __ bind(done);
}


void LIR_Assembler::emit_op3(LIR_Op3* op) {
  switch (op->code()) {
  case lir_idiv:
  case lir_irem:
    arithmetic_idiv(op->code(), op->in_opr1(), op->in_opr2(), op->in_opr3(),
                    op->result_opr(), op->info());
    break;
  case lir_fmad:
    __ fmadd(op->result_opr()->as_double_reg(), op->in_opr1()->as_double_reg(),
             op->in_opr2()->as_double_reg(), op->in_opr3()->as_double_reg());
    break;
  case lir_fmaf:
    __ fmadds(op->result_opr()->as_float_reg(), op->in_opr1()->as_float_reg(),
              op->in_opr2()->as_float_reg(), op->in_opr3()->as_float_reg());
    break;
  default: ShouldNotReachHere(); break;
  }
}


void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) {
#ifdef ASSERT
  assert(op->block() == NULL || op->block()->label() == op->label(), "wrong label");
  if (op->block() != NULL)  _branch_target_blocks.append(op->block());
  if (op->ublock() != NULL) _branch_target_blocks.append(op->ublock());
  assert(op->info() == NULL, "shouldn't have CodeEmitInfo");
#endif

  Label *L = op->label();
  if (op->cond() == lir_cond_always) {
    __ b(*L);
  } else {
    Label done;
    bool is_unordered = false;
    if (op->code() == lir_cond_float_branch) {
      assert(op->ublock() != NULL, "must have unordered successor");
      is_unordered = true;
    } else {
      assert(op->code() == lir_branch, "just checking");
    }

    bool positive = false;
    Assembler::Condition cond = Assembler::equal;
    switch (op->cond()) {
      case lir_cond_equal:        positive = true ; cond = Assembler::equal  ; is_unordered = falsebreak;
      case lir_cond_notEqual:     positive = false; cond = Assembler::equal  ; is_unordered = falsebreak;
      case lir_cond_less:         positive = true ; cond = Assembler::less   ; break;
      case lir_cond_belowEqual:   assert(op->code() != lir_cond_float_branch, ""); // fallthru
      case lir_cond_lessEqual:    positive = false; cond = Assembler::greater; break;
      case lir_cond_greater:      positive = true ; cond = Assembler::greater; break;
      case lir_cond_aboveEqual:   assert(op->code() != lir_cond_float_branch, ""); // fallthru
      case lir_cond_greaterEqual: positive = false; cond = Assembler::less   ; break;
      default:                    ShouldNotReachHere();
    }
    int bo = positive ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0;
    int bi = Assembler::bi0(BOOL_RESULT, cond);
    if (is_unordered) {
      if (positive) {
        if (op->ublock() == op->block()) {
          __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(BOOL_RESULT, Assembler::summary_overflow), *L);
        }
      } else {
        if (op->ublock() != op->block()) { __ bso(BOOL_RESULT, done); }
      }
    }
    __ bc_far_optimized(bo, bi, *L);
    __ bind(done);
  }
}


void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) {
  Bytecodes::Code code = op->bytecode();
  LIR_Opr src = op->in_opr(),
          dst = op->result_opr();

  switch(code) {
    case Bytecodes::_i2l: {
      __ extsw(dst->as_register_lo(), src->as_register());
      break;
    }
    case Bytecodes::_l2i: {
      __ mr_if_needed(dst->as_register(), src->as_register_lo()); // high bits are garbage
      break;
    }
    case Bytecodes::_i2b: {
      __ extsb(dst->as_register(), src->as_register());
      break;
    }
    case Bytecodes::_i2c: {
      __ clrldi(dst->as_register(), src->as_register(), 64-16);
      break;
    }
    case Bytecodes::_i2s: {
      __ extsh(dst->as_register(), src->as_register());
      break;
    }
    case Bytecodes::_i2d:
    case Bytecodes::_l2d: {
      bool src_in_memory = !VM_Version::has_mtfprd();
      FloatRegister rdst = dst->as_double_reg();
      FloatRegister rsrc;
      if (src_in_memory) {
        rsrc = src->as_double_reg(); // via mem
      } else {
        // move src to dst register
        if (code == Bytecodes::_i2d) {
          __ mtfprwa(rdst, src->as_register());
        } else {
          __ mtfprd(rdst, src->as_register_lo());
        }
        rsrc = rdst;
      }
      __ fcfid(rdst, rsrc);
      break;
    }
    case Bytecodes::_i2f:
    case Bytecodes::_l2f: {
      bool src_in_memory = !VM_Version::has_mtfprd();
      FloatRegister rdst = dst->as_float_reg();
      FloatRegister rsrc;
      if (src_in_memory) {
        rsrc = src->as_double_reg(); // via mem
      } else {
        // move src to dst register
        if (code == Bytecodes::_i2f) {
          __ mtfprwa(rdst, src->as_register());
        } else {
          __ mtfprd(rdst, src->as_register_lo());
        }
        rsrc = rdst;
      }
      if (VM_Version::has_fcfids()) {
        __ fcfids(rdst, rsrc);
      } else {
        assert(code == Bytecodes::_i2f, "fcfid+frsp needs fixup code to avoid rounding incompatibility");
        __ fcfid(rdst, rsrc);
        __ frsp(rdst, rdst);
      }
      break;
    }
    case Bytecodes::_f2d: {
      __ fmr_if_needed(dst->as_double_reg(), src->as_float_reg());
      break;
    }
    case Bytecodes::_d2f: {
      __ frsp(dst->as_float_reg(), src->as_double_reg());
      break;
    }
    case Bytecodes::_d2i:
    case Bytecodes::_f2i: {
      bool dst_in_memory = !VM_Version::has_mtfprd();
      FloatRegister rsrc = (code == Bytecodes::_d2i) ? src->as_double_reg() : src->as_float_reg();
      Address       addr = dst_in_memory ? frame_map()->address_for_slot(dst->double_stack_ix()) : Address();
      Label L;
      // Result must be 0 if value is NaN; test by comparing value to itself.
      __ fcmpu(CCR0, rsrc, rsrc);
      if (dst_in_memory) {
        __ li(R0, 0); // 0 in case of NAN
        __ std(R0, addr.disp(), addr.base());
      } else {
        __ li(dst->as_register(), 0);
      }
      __ bso(CCR0, L);
      __ fctiwz(rsrc, rsrc); // USE_KILL
      if (dst_in_memory) {
        __ stfd(rsrc, addr.disp(), addr.base());
      } else {
        __ mffprd(dst->as_register(), rsrc);
      }
      __ bind(L);
      break;
    }
    case Bytecodes::_d2l:
    case Bytecodes::_f2l: {
      bool dst_in_memory = !VM_Version::has_mtfprd();
      FloatRegister rsrc = (code == Bytecodes::_d2l) ? src->as_double_reg() : src->as_float_reg();
      Address       addr = dst_in_memory ? frame_map()->address_for_slot(dst->double_stack_ix()) : Address();
      Label L;
      // Result must be 0 if value is NaN; test by comparing value to itself.
      __ fcmpu(CCR0, rsrc, rsrc);
      if (dst_in_memory) {
        __ li(R0, 0); // 0 in case of NAN
        __ std(R0, addr.disp(), addr.base());
      } else {
        __ li(dst->as_register_lo(), 0);
      }
      __ bso(CCR0, L);
      __ fctidz(rsrc, rsrc); // USE_KILL
      if (dst_in_memory) {
        __ stfd(rsrc, addr.disp(), addr.base());
      } else {
        __ mffprd(dst->as_register_lo(), rsrc);
      }
      __ bind(L);
      break;
    }

    default: ShouldNotReachHere();
  }
}


void LIR_Assembler::align_call(LIR_Code) {
  // do nothing since all instructions are word aligned on ppc
}


bool LIR_Assembler::emit_trampoline_stub_for_call(address target, Register Rtoc) {
  int start_offset = __ offset();
  // Put the entry point as a constant into the constant pool.
  const address entry_point_toc_addr   = __ address_constant(target, RelocationHolder::none);
  if (entry_point_toc_addr == NULL) {
    bailout("const section overflow");
    return false;
  }
  const int     entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr);

  // Emit the trampoline stub which will be related to the branch-and-link below.
  address stub = __ emit_trampoline_stub(entry_point_toc_offset, start_offset, Rtoc);
  if (!stub) {
    bailout("no space for trampoline stub");
    return false;
  }
  return true;
}


void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
  assert(rtype==relocInfo::opt_virtual_call_type || rtype==relocInfo::static_call_type, "unexpected rtype");

  bool success = emit_trampoline_stub_for_call(op->addr());
  if (!success) { return; }

  __ relocate(rtype);
  // Note: At this point we do not have the address of the trampoline
  // stub, and the entry point might be too far away for bl, so __ pc()
  // serves as dummy and the bl will be patched later.
  __ code()->set_insts_mark();
  __ bl(__ pc());
  add_call_info(code_offset(), op->info());
  __ post_call_nop();
}


void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
  __ calculate_address_from_global_toc(R2_TOC, __ method_toc());

  // Virtual call relocation will point to ic load.
  address virtual_call_meta_addr = __ pc();
  // Load a clear inline cache.
  AddressLiteral empty_ic((address) Universe::non_oop_word());
  bool success = __ load_const_from_method_toc(R19_inline_cache_reg, empty_ic, R2_TOC);
  if (!success) {
    bailout("const section overflow");
    return;
  }
  // Call to fixup routine. Fixup routine uses ScopeDesc info
  // to determine who we intended to call.
  __ relocate(virtual_call_Relocation::spec(virtual_call_meta_addr));

  success = emit_trampoline_stub_for_call(op->addr(), R2_TOC);
  if (!success) { return; }

  // Note: At this point we do not have the address of the trampoline
  // stub, and the entry point might be too far away for bl, so __ pc()
  // serves as dummy and the bl will be patched later.
  __ bl(__ pc());
  add_call_info(code_offset(), op->info());
  __ post_call_nop();
}

void LIR_Assembler::explicit_null_check(Register addr, CodeEmitInfo* info) {
  ImplicitNullCheckStub* stub = new ImplicitNullCheckStub(code_offset(), info);
  __ null_check(addr, stub->entry());
  append_code_stub(stub);
}


// Attention: caller must encode oop if needed
int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide) {
  int store_offset;
  if (!Assembler::is_simm16(offset)) {
    // For offsets larger than a simm16 we setup the offset.
    assert(wide && !from_reg->is_same_register(FrameMap::R0_opr), "large offset only supported in special case");
    __ load_const_optimized(R0, offset);
    store_offset = store(from_reg, base, R0, type, wide);
  } else {
    store_offset = code_offset();
    switch (type) {
      case T_BOOLEAN: // fall through
      case T_BYTE  : __ stb(from_reg->as_register(), offset, base); break;
      case T_CHAR  :
      case T_SHORT : __ sth(from_reg->as_register(), offset, base); break;
      case T_INT   : __ stw(from_reg->as_register(), offset, base); break;
      case T_LONG  : __ std(from_reg->as_register_lo(), offset, base); break;
      case T_ADDRESS:
      case T_METADATA: __ std(from_reg->as_register(), offset, base); break;
      case T_ARRAY : // fall through
      case T_OBJECT:
        {
          if (UseCompressedOops && !wide) {
            // Encoding done in caller
            __ stw(from_reg->as_register(), offset, base);
            __ verify_coop(from_reg->as_register(), FILE_AND_LINE);
          } else {
            __ std(from_reg->as_register(), offset, base);
            __ verify_oop(from_reg->as_register(), FILE_AND_LINE);
          }
          break;
        }
      case T_FLOAT : __ stfs(from_reg->as_float_reg(), offset, base); break;
      case T_DOUBLE: __ stfd(from_reg->as_double_reg(), offset, base); break;
      default      : ShouldNotReachHere();
    }
  }
  return store_offset;
}


// Attention: caller must encode oop if needed
int LIR_Assembler::store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide) {
  int store_offset = code_offset();
  switch (type) {
    case T_BOOLEAN: // fall through
    case T_BYTE  : __ stbx(from_reg->as_register(), base, disp); break;
    case T_CHAR  :
    case T_SHORT : __ sthx(from_reg->as_register(), base, disp); break;
    case T_INT   : __ stwx(from_reg->as_register(), base, disp); break;
    case T_LONG  :
#ifdef _LP64
      __ stdx(from_reg->as_register_lo(), base, disp);
#else
      Unimplemented();
#endif
      break;
    case T_ADDRESS:
      __ stdx(from_reg->as_register(), base, disp);
      break;
    case T_ARRAY : // fall through
    case T_OBJECT:
      {
        if (UseCompressedOops && !wide) {
          // Encoding done in caller.
          __ stwx(from_reg->as_register(), base, disp);
          __ verify_coop(from_reg->as_register(), FILE_AND_LINE); // kills R0
        } else {
          __ stdx(from_reg->as_register(), base, disp);
          __ verify_oop(from_reg->as_register(), FILE_AND_LINE); // kills R0
        }
        break;
      }
    case T_FLOAT : __ stfsx(from_reg->as_float_reg(), base, disp); break;
    case T_DOUBLE: __ stfdx(from_reg->as_double_reg(), base, disp); break;
    default      : ShouldNotReachHere();
  }
  return store_offset;
}


int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide) {
  int load_offset;
  if (!Assembler::is_simm16(offset)) {
    // For offsets larger than a simm16 we setup the offset.
    __ load_const_optimized(R0, offset);
    load_offset = load(base, R0, to_reg, type, wide);
  } else {
    load_offset = code_offset();
    switch(type) {
      case T_BOOLEAN: // fall through
      case T_BYTE  :   __ lbz(to_reg->as_register(), offset, base);
                       __ extsb(to_reg->as_register(), to_reg->as_register()); break;
      case T_CHAR  :   __ lhz(to_reg->as_register(), offset, base); break;
      case T_SHORT :   __ lha(to_reg->as_register(), offset, base); break;
      case T_INT   :   __ lwa(to_reg->as_register(), offset, base); break;
      case T_LONG  :   __ ld(to_reg->as_register_lo(), offset, base); break;
      case T_METADATA: __ ld(to_reg->as_register(), offset, base); break;
      case T_ADDRESS:
        __ ld(to_reg->as_register(), offset, base);
        break;
      case T_ARRAY : // fall through
      case T_OBJECT:
        {
          if (UseCompressedOops && !wide) {
            __ lwz(to_reg->as_register(), offset, base);
            __ decode_heap_oop(to_reg->as_register());
          } else {
            __ ld(to_reg->as_register(), offset, base);
          }
          __ verify_oop(to_reg->as_register(), FILE_AND_LINE);
          break;
        }
      case T_FLOAT:  __ lfs(to_reg->as_float_reg(), offset, base); break;
      case T_DOUBLE: __ lfd(to_reg->as_double_reg(), offset, base); break;
      default      : ShouldNotReachHere();
    }
  }
  return load_offset;
}


int LIR_Assembler::load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide) {
  int load_offset = code_offset();
  switch(type) {
    case T_BOOLEAN: // fall through
    case T_BYTE  :  __ lbzx(to_reg->as_register(), base, disp);
                    __ extsb(to_reg->as_register(), to_reg->as_register()); break;
    case T_CHAR  :  __ lhzx(to_reg->as_register(), base, disp); break;
    case T_SHORT :  __ lhax(to_reg->as_register(), base, disp); break;
    case T_INT   :  __ lwax(to_reg->as_register(), base, disp); break;
    case T_ADDRESS: __ ldx(to_reg->as_register(), base, disp); break;
    case T_ARRAY : // fall through
    case T_OBJECT:
      {
        if (UseCompressedOops && !wide) {
          __ lwzx(to_reg->as_register(), base, disp);
          __ decode_heap_oop(to_reg->as_register());
        } else {
          __ ldx(to_reg->as_register(), base, disp);
        }
        __ verify_oop(to_reg->as_register(), FILE_AND_LINE);
        break;
      }
    case T_FLOAT:  __ lfsx(to_reg->as_float_reg() , base, disp); break;
    case T_DOUBLE: __ lfdx(to_reg->as_double_reg(), base, disp); break;
    case T_LONG  :
#ifdef _LP64
      __ ldx(to_reg->as_register_lo(), base, disp);
#else
      Unimplemented();
#endif
      break;
    default      : ShouldNotReachHere();
  }
  return load_offset;
}


void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) {
  LIR_Const* c = src->as_constant_ptr();
  Register src_reg = R0;
  switch (c->type()) {
    case T_INT:
    case T_FLOAT: {
      int value = c->as_jint_bits();
      __ load_const_optimized(src_reg, value);
      Address addr = frame_map()->address_for_slot(dest->single_stack_ix());
      __ stw(src_reg, addr.disp(), addr.base());
      break;
    }
    case T_ADDRESS: {
      int value = c->as_jint_bits();
      __ load_const_optimized(src_reg, value);
      Address addr = frame_map()->address_for_slot(dest->single_stack_ix());
      __ std(src_reg, addr.disp(), addr.base());
      break;
    }
    case T_OBJECT: {
      jobject2reg(c->as_jobject(), src_reg);
      Address addr = frame_map()->address_for_slot(dest->single_stack_ix());
      __ std(src_reg, addr.disp(), addr.base());
      break;
    }
    case T_LONG:
    case T_DOUBLE: {
      int value = c->as_jlong_bits();
      __ load_const_optimized(src_reg, value);
      Address addr = frame_map()->address_for_double_slot(dest->double_stack_ix());
      __ std(src_reg, addr.disp(), addr.base());
      break;
    }
    default:
      Unimplemented();
  }
}


void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) {
  LIR_Const* c = src->as_constant_ptr();
  LIR_Address* addr = dest->as_address_ptr();
  Register base = addr->base()->as_pointer_register();
  LIR_Opr tmp = LIR_OprFact::illegalOpr;
  int offset = -1;
  // Null check for large offsets in LIRGenerator::do_StoreField.
  bool needs_explicit_null_check = !ImplicitNullChecks;

  if (info != NULL && needs_explicit_null_check) {
    explicit_null_check(base, info);
  }

  switch (c->type()) {
    case T_FLOAT: type = T_INT;
    case T_INT:
    case T_ADDRESS: {
      tmp = FrameMap::R0_opr;
      __ load_const_optimized(tmp->as_register(), c->as_jint_bits());
      break;
    }
    case T_DOUBLE: type = T_LONG;
    case T_LONG: {
      tmp = FrameMap::R0_long_opr;
      __ load_const_optimized(tmp->as_register_lo(), c->as_jlong_bits());
      break;
    }
    case T_OBJECT: {
      tmp = FrameMap::R0_opr;
      if (UseCompressedOops && !wide && c->as_jobject() != NULL) {
        AddressLiteral oop_addr = __ constant_oop_address(c->as_jobject());
        // Don't care about sign extend (will use stw).
        __ lis(R0, 0); // Will get patched.
        __ relocate(oop_addr.rspec(), /*compressed format*/ 1);
        __ ori(R0, R0, 0); // Will get patched.
      } else {
        jobject2reg(c->as_jobject(), R0);
      }
      break;
    }
    default:
      Unimplemented();
  }

  // Handle either reg+reg or reg+disp address.
  if (addr->index()->is_valid()) {
    assert(addr->disp() == 0, "must be zero");
    offset = store(tmp, base, addr->index()->as_pointer_register(), type, wide);
  } else {
    assert(Assembler::is_simm16(addr->disp()), "can't handle larger addresses");
    offset = store(tmp, base, addr->disp(), type, wide);
  }

  if (info != NULL) {
    assert(offset != -1, "offset should've been set");
    if (!needs_explicit_null_check) {
      add_debug_info_for_null_check(offset, info);
    }
  }
}


void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) {
  LIR_Const* c = src->as_constant_ptr();
  LIR_Opr to_reg = dest;

  switch (c->type()) {
    case T_INT: {
      assert(patch_code == lir_patch_none, "no patching handled here");
      __ load_const_optimized(dest->as_register(), c->as_jint(), R0);
      break;
    }
    case T_ADDRESS: {
      assert(patch_code == lir_patch_none, "no patching handled here");
      __ load_const_optimized(dest->as_register(), c->as_jint(), R0);  // Yes, as_jint ...
      break;
    }
    case T_LONG: {
      assert(patch_code == lir_patch_none, "no patching handled here");
      __ load_const_optimized(dest->as_register_lo(), c->as_jlong(), R0);
      break;
    }

    case T_OBJECT: {
      if (patch_code == lir_patch_none) {
        jobject2reg(c->as_jobject(), to_reg->as_register());
      } else {
        jobject2reg_with_patching(to_reg->as_register(), info);
      }
      break;
    }

    case T_METADATA:
      {
        if (patch_code == lir_patch_none) {
          metadata2reg(c->as_metadata(), to_reg->as_register());
        } else {
          klass2reg_with_patching(to_reg->as_register(), info);
        }
      }
      break;

    case T_FLOAT:
      {
        if (to_reg->is_single_fpu()) {
          address const_addr = __ float_constant(c->as_jfloat());
          if (const_addr == NULL) {
            bailout("const section overflow");
            break;
          }
          RelocationHolder rspec = internal_word_Relocation::spec(const_addr);
          __ relocate(rspec);
          __ load_const(R0, const_addr);
          __ lfsx(to_reg->as_float_reg(), R0);
        } else {
          assert(to_reg->is_single_cpu(), "Must be a cpu register.");
          __ load_const_optimized(to_reg->as_register(), jint_cast(c->as_jfloat()), R0);
        }
      }
      break;

    case T_DOUBLE:
      {
        if (to_reg->is_double_fpu()) {
          address const_addr = __ double_constant(c->as_jdouble());
          if (const_addr == NULL) {
            bailout("const section overflow");
            break;
          }
          RelocationHolder rspec = internal_word_Relocation::spec(const_addr);
          __ relocate(rspec);
          __ load_const(R0, const_addr);
          __ lfdx(to_reg->as_double_reg(), R0);
        } else {
          assert(to_reg->is_double_cpu(), "Must be a long register.");
          __ load_const_optimized(to_reg->as_register_lo(), jlong_cast(c->as_jdouble()), R0);
        }
      }
      break;

    default:
      ShouldNotReachHere();
  }
}


Address LIR_Assembler::as_Address(LIR_Address* addr) {
  Unimplemented(); return Address();
}


inline RegisterOrConstant index_or_disp(LIR_Address* addr) {
  if (addr->index()->is_illegal()) {
    return (RegisterOrConstant)(addr->disp());
  } else {
    return (RegisterOrConstant)(addr->index()->as_pointer_register());
  }
}


void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) {
  const Register tmp = R0;
  switch (type) {
    case T_INT:
    case T_FLOAT: {
      Address from = frame_map()->address_for_slot(src->single_stack_ix());
      Address to   = frame_map()->address_for_slot(dest->single_stack_ix());
      __ lwz(tmp, from.disp(), from.base());
      __ stw(tmp, to.disp(), to.base());
      break;
    }
    case T_ADDRESS:
    case T_OBJECT: {
      Address from = frame_map()->address_for_slot(src->single_stack_ix());
      Address to   = frame_map()->address_for_slot(dest->single_stack_ix());
      __ ld(tmp, from.disp(), from.base());
      __ std(tmp, to.disp(), to.base());
      break;
    }
    case T_LONG:
    case T_DOUBLE: {
      Address from = frame_map()->address_for_double_slot(src->double_stack_ix());
      Address to   = frame_map()->address_for_double_slot(dest->double_stack_ix());
      __ ld(tmp, from.disp(), from.base());
      __ std(tmp, to.disp(), to.base());
      break;
    }

    default:
      ShouldNotReachHere();
  }
}


Address LIR_Assembler::as_Address_hi(LIR_Address* addr) {
  Unimplemented(); return Address();
}


Address LIR_Assembler::as_Address_lo(LIR_Address* addr) {
  Unimplemented(); return Address();
}


void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type,
                            LIR_PatchCode patch_code, CodeEmitInfo* info, bool wide) {

  assert(type != T_METADATA, "load of metadata ptr not supported");
  LIR_Address* addr = src_opr->as_address_ptr();
  LIR_Opr to_reg = dest;

  Register src = addr->base()->as_pointer_register();
  Register disp_reg = noreg;
  int disp_value = addr->disp();
  bool needs_patching = (patch_code != lir_patch_none);
  // null check for large offsets in LIRGenerator::do_LoadField
  bool needs_explicit_null_check = !os::zero_page_read_protected() || !ImplicitNullChecks;

  if (info != NULL && needs_explicit_null_check) {
    explicit_null_check(src, info);
  }

  if (addr->base()->type() == T_OBJECT) {
    __ verify_oop(src, FILE_AND_LINE);
  }

  PatchingStub* patch = NULL;
  if (needs_patching) {
    patch = new PatchingStub(_masm, PatchingStub::access_field_id);
    assert(!to_reg->is_double_cpu() ||
           patch_code == lir_patch_none ||
           patch_code == lir_patch_normal, "patching doesn't match register");
  }

  if (addr->index()->is_illegal()) {
    if (!Assembler::is_simm16(disp_value)) {
      if (needs_patching) {
        __ load_const32(R0, 0); // patchable int
      } else {
        __ load_const_optimized(R0, disp_value);
      }
      disp_reg = R0;
    }
  } else {
    disp_reg = addr->index()->as_pointer_register();
    assert(disp_value == 0, "can't handle 3 operand addresses");
  }

  // Remember the offset of the load. The patching_epilog must be done
  // before the call to add_debug_info, otherwise the PcDescs don't get
  // entered in increasing order.
  int offset;

  if (disp_reg == noreg) {
    assert(Assembler::is_simm16(disp_value), "should have set this up");
    offset = load(src, disp_value, to_reg, type, wide);
  } else {
    offset = load(src, disp_reg, to_reg, type, wide);
  }

  if (patch != NULL) {
    patching_epilog(patch, patch_code, src, info);
  }
  if (info != NULL && !needs_explicit_null_check) {
    add_debug_info_for_null_check(offset, info);
  }
}


void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) {
  Address addr;
  if (src->is_single_word()) {
    addr = frame_map()->address_for_slot(src->single_stack_ix());
  } else if (src->is_double_word())  {
    addr = frame_map()->address_for_double_slot(src->double_stack_ix());
  }

  load(addr.base(), addr.disp(), dest, dest->type(), true /*wide*/);
}


void LIR_Assembler::reg2stack(LIR_Opr from_reg, LIR_Opr dest, BasicType type, bool pop_fpu_stack) {
  Address addr;
  if (dest->is_single_word()) {
    addr = frame_map()->address_for_slot(dest->single_stack_ix());
  } else if (dest->is_double_word())  {
    addr = frame_map()->address_for_slot(dest->double_stack_ix());
  }

  store(from_reg, addr.base(), addr.disp(), from_reg->type(), true /*wide*/);
}


void LIR_Assembler::reg2reg(LIR_Opr from_reg, LIR_Opr to_reg) {
  if (from_reg->is_float_kind() && to_reg->is_float_kind()) {
    if (from_reg->is_double_fpu()) {
      // double to double moves
      assert(to_reg->is_double_fpu(), "should match");
      __ fmr_if_needed(to_reg->as_double_reg(), from_reg->as_double_reg());
    } else {
      // float to float moves
      assert(to_reg->is_single_fpu(), "should match");
      __ fmr_if_needed(to_reg->as_float_reg(), from_reg->as_float_reg());
    }
  } else if (!from_reg->is_float_kind() && !to_reg->is_float_kind()) {
    if (from_reg->is_double_cpu()) {
      __ mr_if_needed(to_reg->as_pointer_register(), from_reg->as_pointer_register());
    } else if (to_reg->is_double_cpu()) {
      // int to int moves
      __ mr_if_needed(to_reg->as_register_lo(), from_reg->as_register());
    } else {
      // int to int moves
      __ mr_if_needed(to_reg->as_register(), from_reg->as_register());
    }
  } else {
    ShouldNotReachHere();
  }
  if (is_reference_type(to_reg->type())) {
    __ verify_oop(to_reg->as_register(), FILE_AND_LINE);
  }
}


void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type,
                            LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack,
                            bool wide) {
  assert(type != T_METADATA, "store of metadata ptr not supported");
  LIR_Address* addr = dest->as_address_ptr();

  Register src = addr->base()->as_pointer_register();
  Register disp_reg = noreg;
  int disp_value = addr->disp();
  bool needs_patching = (patch_code != lir_patch_none);
  bool compress_oop = (is_reference_type(type)) && UseCompressedOops && !wide &&
                      CompressedOops::mode() != CompressedOops::UnscaledNarrowOop;
  bool load_disp = addr->index()->is_illegal() && !Assembler::is_simm16(disp_value);
  bool use_R29 = compress_oop && load_disp; // Avoid register conflict, also do null check before killing R29.
  // Null check for large offsets in LIRGenerator::do_StoreField.
  bool needs_explicit_null_check = !ImplicitNullChecks || use_R29;

  if (info != NULL && needs_explicit_null_check) {
    explicit_null_check(src, info);
  }

  if (addr->base()->is_oop_register()) {
    __ verify_oop(src, FILE_AND_LINE);
  }

  PatchingStub* patch = NULL;
  if (needs_patching) {
    patch = new PatchingStub(_masm, PatchingStub::access_field_id);
    assert(!from_reg->is_double_cpu() ||
           patch_code == lir_patch_none ||
           patch_code == lir_patch_normal, "patching doesn't match register");
  }

  if (addr->index()->is_illegal()) {
    if (load_disp) {
      disp_reg = use_R29 ? R29_TOC : R0;
      if (needs_patching) {
        __ load_const32(disp_reg, 0); // patchable int
      } else {
        __ load_const_optimized(disp_reg, disp_value);
      }
    }
  } else {
    disp_reg = addr->index()->as_pointer_register();
    assert(disp_value == 0, "can't handle 3 operand addresses");
  }

  // remember the offset of the store. The patching_epilog must be done
  // before the call to add_debug_info_for_null_check, otherwise the PcDescs don't get
  // entered in increasing order.
  int offset;

  if (compress_oop) {
    Register co = __ encode_heap_oop(R0, from_reg->as_register());
    from_reg = FrameMap::as_opr(co);
  }

  if (disp_reg == noreg) {
    assert(Assembler::is_simm16(disp_value), "should have set this up");
    offset = store(from_reg, src, disp_value, type, wide);
  } else {
    offset = store(from_reg, src, disp_reg, type, wide);
  }

  if (use_R29) {
    __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R0); // reinit
  }

  if (patch != NULL) {
    patching_epilog(patch, patch_code, src, info);
  }

  if (info != NULL && !needs_explicit_null_check) {
    add_debug_info_for_null_check(offset, info);
  }
}


void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) {
  const Register return_pc = R31;  // Must survive C-call to enable_stack_reserved_zone().
  const Register temp      = R12;

  // Pop the stack before the safepoint code.
  int frame_size = initial_frame_size_in_bytes();
  if (Assembler::is_simm(frame_size, 16)) {
    __ addi(R1_SP, R1_SP, frame_size);
  } else {
    __ pop_frame();
  }

  // Restore return pc relative to callers' sp.
  __ ld(return_pc, _abi0(lr), R1_SP);
  // Move return pc to LR.
  __ mtlr(return_pc);

  if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
    __ reserved_stack_check(return_pc);
  }

  // We need to mark the code position where the load from the safepoint
  // polling page was emitted as relocInfo::poll_return_type here.
  if (!UseSIGTRAP) {
    code_stub->set_safepoint_offset(__ offset());
    __ relocate(relocInfo::poll_return_type);
  }
  __ safepoint_poll(*code_stub->entry(), temp, true /* at_return */, true /* in_nmethod */);

  // Return.
  __ blr();
}


int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) {
  const Register poll_addr = tmp->as_register();
  __ ld(poll_addr, in_bytes(JavaThread::polling_page_offset()), R16_thread);
  if (info != NULL) {
    add_debug_info_for_branch(info);
  }
  int offset = __ offset();
  __ relocate(relocInfo::poll_type);
  __ load_from_polling_page(poll_addr);

  return offset;
}


void LIR_Assembler::emit_static_call_stub() {
  address call_pc = __ pc();
  address stub = __ start_a_stub(static_call_stub_size());
  if (stub == NULL) {
    bailout("static call stub overflow");
    return;
  }

  // For java_to_interp stubs we use R11_scratch1 as scratch register
  // and in call trampoline stubs we use R12_scratch2. This way we
  // can distinguish them (see is_NativeCallTrampolineStub_at()).
  const Register reg_scratch = R11_scratch1;

  // Create a static stub relocation which relates this stub
  // with the call instruction at insts_call_instruction_offset in the
  // instructions code-section.
  int start = __ offset();
  __ relocate(static_stub_Relocation::spec(call_pc));

  // Now, create the stub's code:
  // - load the TOC
  // - load the inline cache oop from the constant pool
  // - load the call target from the constant pool
  // - call
  __ calculate_address_from_global_toc(reg_scratch, __ method_toc());
  AddressLiteral ic = __ allocate_metadata_address((Metadata *)NULL);
  bool success = __ load_const_from_method_toc(R19_inline_cache_reg, ic, reg_scratch, /*fixed_size*/ true);

  if (ReoptimizeCallSequences) {
    __ b64_patchable((address)-1, relocInfo::none);
  } else {
    AddressLiteral a((address)-1);
    success = success && __ load_const_from_method_toc(reg_scratch, a, reg_scratch, /*fixed_size*/ true);
    __ mtctr(reg_scratch);
    __ bctr();
  }
  if (!success) {
    bailout("const section overflow");
    return;
  }

  assert(__ offset() - start <= static_call_stub_size(), "stub too big");
  __ end_a_stub();
}


void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Op2* op) {
  bool unsigned_comp = (condition == lir_cond_belowEqual || condition == lir_cond_aboveEqual);
  if (opr1->is_single_fpu()) {
    __ fcmpu(BOOL_RESULT, opr1->as_float_reg(), opr2->as_float_reg());
  } else if (opr1->is_double_fpu()) {
    __ fcmpu(BOOL_RESULT, opr1->as_double_reg(), opr2->as_double_reg());
  } else if (opr1->is_single_cpu()) {
    if (opr2->is_constant()) {
      switch (opr2->as_constant_ptr()->type()) {
        case T_INT:
          {
            jint con = opr2->as_constant_ptr()->as_jint();
            if (unsigned_comp) {
              if (Assembler::is_uimm(con, 16)) {
                __ cmplwi(BOOL_RESULT, opr1->as_register(), con);
              } else {
                __ load_const_optimized(R0, con);
                __ cmplw(BOOL_RESULT, opr1->as_register(), R0);
              }
            } else {
              if (Assembler::is_simm(con, 16)) {
                __ cmpwi(BOOL_RESULT, opr1->as_register(), con);
              } else {
                __ load_const_optimized(R0, con);
                __ cmpw(BOOL_RESULT, opr1->as_register(), R0);
              }
            }
          }
          break;

        case T_OBJECT:
          // There are only equal/notequal comparisons on objects.
          {
            assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "oops");
            jobject con = opr2->as_constant_ptr()->as_jobject();
            if (con == NULL) {
              __ cmpdi(BOOL_RESULT, opr1->as_register(), 0);
            } else {
              jobject2reg(con, R0);
              __ cmpd(BOOL_RESULT, opr1->as_register(), R0);
            }
          }
          break;

        case T_METADATA:
          // We only need, for now, comparison with NULL for metadata.
          {
            assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "oops");
            Metadata* p = opr2->as_constant_ptr()->as_metadata();
            if (p == NULL) {
              __ cmpdi(BOOL_RESULT, opr1->as_register(), 0);
            } else {
              ShouldNotReachHere();
            }
          }
          break;

        default:
          ShouldNotReachHere();
          break;
      }
    } else {
      assert(opr1->type() != T_ADDRESS && opr2->type() != T_ADDRESS, "currently unsupported");
      if (is_reference_type(opr1->type())) {
        // There are only equal/notequal comparisons on objects.
        assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "oops");
        __ cmpd(BOOL_RESULT, opr1->as_register(), opr2->as_register());
      } else {
        if (unsigned_comp) {
          __ cmplw(BOOL_RESULT, opr1->as_register(), opr2->as_register());
        } else {
          __ cmpw(BOOL_RESULT, opr1->as_register(), opr2->as_register());
        }
      }
    }
  } else if (opr1->is_double_cpu()) {
    if (opr2->is_constant()) {
      jlong con = opr2->as_constant_ptr()->as_jlong();
      if (unsigned_comp) {
        if (Assembler::is_uimm(con, 16)) {
          __ cmpldi(BOOL_RESULT, opr1->as_register_lo(), con);
        } else {
          __ load_const_optimized(R0, con);
          __ cmpld(BOOL_RESULT, opr1->as_register_lo(), R0);
        }
      } else {
        if (Assembler::is_simm(con, 16)) {
          __ cmpdi(BOOL_RESULT, opr1->as_register_lo(), con);
        } else {
          __ load_const_optimized(R0, con);
          __ cmpd(BOOL_RESULT, opr1->as_register_lo(), R0);
        }
      }
    } else if (opr2->is_register()) {
      if (unsigned_comp) {
        __ cmpld(BOOL_RESULT, opr1->as_register_lo(), opr2->as_register_lo());
      } else {
        __ cmpd(BOOL_RESULT, opr1->as_register_lo(), opr2->as_register_lo());
      }
    } else {
      ShouldNotReachHere();
    }
  } else {
    ShouldNotReachHere();
  }
}


void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst, LIR_Op2* op){
  const Register Rdst = dst->as_register();
  if (code == lir_cmp_fd2i || code == lir_ucmp_fd2i) {
    bool is_unordered_less = (code == lir_ucmp_fd2i);
    if (left->is_single_fpu()) {
      __ fcmpu(CCR0, left->as_float_reg(), right->as_float_reg());
    } else if (left->is_double_fpu()) {
      __ fcmpu(CCR0, left->as_double_reg(), right->as_double_reg());
    } else {
      ShouldNotReachHere();
    }
    __ set_cmpu3(Rdst, is_unordered_less); // is_unordered_less ? -1 : 1
  } else if (code == lir_cmp_l2i) {
    __ cmpd(CCR0, left->as_register_lo(), right->as_register_lo());
    __ set_cmp3(Rdst);  // set result as follows: <: -1, =: 0, >: 1
  } else {
    ShouldNotReachHere();
  }
}


inline void load_to_reg(LIR_Assembler *lasm, LIR_Opr src, LIR_Opr dst) {
  if (src->is_constant()) {
    lasm->const2reg(src, dst, lir_patch_none, NULL);
  } else if (src->is_register()) {
    lasm->reg2reg(src, dst);
  } else if (src->is_stack()) {
    lasm->stack2reg(src, dst, dst->type());
  } else {
    ShouldNotReachHere();
  }
}

void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type,
                          LIR_Opr cmp_opr1, LIR_Opr cmp_opr2) {
  assert(cmp_opr1 == LIR_OprFact::illegalOpr && cmp_opr2 == LIR_OprFact::illegalOpr, "unnecessary cmp oprs on ppc");

  if (opr1->is_equal(opr2) || opr1->is_same_register(opr2)) {
    load_to_reg(this, opr1, result); // Condition doesn't matter.
    return;
  }

  bool positive = false;
  Assembler::Condition cond = Assembler::equal;
  switch (condition) {
    case lir_cond_equal:        positive = true ; cond = Assembler::equal  ; break;
    case lir_cond_notEqual:     positive = false; cond = Assembler::equal  ; break;
    case lir_cond_less:         positive = true ; cond = Assembler::less   ; break;
    case lir_cond_belowEqual:
    case lir_cond_lessEqual:    positive = false; cond = Assembler::greater; break;
    case lir_cond_greater:      positive = true ; cond = Assembler::greater; break;
    case lir_cond_aboveEqual:
    case lir_cond_greaterEqual: positive = false; cond = Assembler::less   ; break;
    default:                    ShouldNotReachHere();
  }

  // Try to use isel on >=Power7.
  if (VM_Version::has_isel() && result->is_cpu_register()) {
    bool o1_is_reg = opr1->is_cpu_register(), o2_is_reg = opr2->is_cpu_register();
    const Register result_reg = result->is_single_cpu() ? result->as_register() : result->as_register_lo();

    // We can use result_reg to load one operand if not already in register.
    Register first  = o1_is_reg ? (opr1->is_single_cpu() ? opr1->as_register() : opr1->as_register_lo()) : result_reg,
             second = o2_is_reg ? (opr2->is_single_cpu() ? opr2->as_register() : opr2->as_register_lo()) : result_reg;

    if (first != second) {
      if (!o1_is_reg) {
        load_to_reg(this, opr1, result);
      }

      if (!o2_is_reg) {
        load_to_reg(this, opr2, result);
      }

      __ isel(result_reg, BOOL_RESULT, cond, !positive, first, second);
      return;
    }
  } // isel

  load_to_reg(this, opr1, result);

  Label skip;
  int bo = positive ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0;
  int bi = Assembler::bi0(BOOL_RESULT, cond);
  __ bc(bo, bi, skip);

  load_to_reg(this, opr2, result);
  __ bind(skip);
}


void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest,
                             CodeEmitInfo* info, bool pop_fpu_stack) {
  assert(info == NULL, "unused on this code path");
  assert(left->is_register(), "wrong items state");
  assert(dest->is_register(), "wrong items state");

  if (right->is_register()) {
    if (dest->is_float_kind()) {

      FloatRegister lreg, rreg, res;
      if (right->is_single_fpu()) {
        lreg = left->as_float_reg();
        rreg = right->as_float_reg();
        res  = dest->as_float_reg();
        switch (code) {
          case lir_add: __ fadds(res, lreg, rreg); break;
          case lir_sub: __ fsubs(res, lreg, rreg); break;
          case lir_mul: __ fmuls(res, lreg, rreg); break;
          case lir_div: __ fdivs(res, lreg, rreg); break;
          default: ShouldNotReachHere();
        }
      } else {
        lreg = left->as_double_reg();
        rreg = right->as_double_reg();
        res  = dest->as_double_reg();
        switch (code) {
          case lir_add: __ fadd(res, lreg, rreg); break;
          case lir_sub: __ fsub(res, lreg, rreg); break;
          case lir_mul: __ fmul(res, lreg, rreg); break;
          case lir_div: __ fdiv(res, lreg, rreg); break;
          default: ShouldNotReachHere();
        }
      }

    } else if (dest->is_double_cpu()) {

      Register dst_lo = dest->as_register_lo();
      Register op1_lo = left->as_pointer_register();
      Register op2_lo = right->as_pointer_register();

      switch (code) {
        case lir_add: __ add(dst_lo, op1_lo, op2_lo); break;
        case lir_sub: __ sub(dst_lo, op1_lo, op2_lo); break;
        case lir_mul: __ mulld(dst_lo, op1_lo, op2_lo); break;
        default: ShouldNotReachHere();
      }
    } else {
      assert (right->is_single_cpu(), "Just Checking");

      Register lreg = left->as_register();
      Register res  = dest->as_register();
      Register rreg = right->as_register();
      switch (code) {
        case lir_add:  __ add  (res, lreg, rreg); break;
        case lir_sub:  __ sub  (res, lreg, rreg); break;
        case lir_mul:  __ mullw(res, lreg, rreg); break;
        default: ShouldNotReachHere();
      }
    }
  } else {
    assert (right->is_constant(), "must be constant");

    if (dest->is_single_cpu()) {
      Register lreg = left->as_register();
      Register res  = dest->as_register();
      int    simm16 = right->as_constant_ptr()->as_jint();

      switch (code) {
        case lir_sub:  assert(Assembler::is_simm16(-simm16), "cannot encode"); // see do_ArithmeticOp_Int
                       simm16 = -simm16;
        case lir_add:  if (res == lreg && simm16 == 0) break;
                       __ addi(res, lreg, simm16); break;
        case lir_mul:  if (res == lreg && simm16 == 1) break;
                       __ mulli(res, lreg, simm16); break;
        default: ShouldNotReachHere();
      }
    } else {
      Register lreg = left->as_pointer_register();
      Register res  = dest->as_register_lo();
      long con = right->as_constant_ptr()->as_jlong();
      assert(Assembler::is_simm16(con), "must be simm16");

      switch (code) {
        case lir_sub:  assert(Assembler::is_simm16(-con), "cannot encode");  // see do_ArithmeticOp_Long
                       con = -con;
        case lir_add:  if (res == lreg && con == 0) break;
                       __ addi(res, lreg, (int)con); break;
        case lir_mul:  if (res == lreg && con == 1) break;
                       __ mulli(res, lreg, (int)con); break;
        default: ShouldNotReachHere();
      }
    }
  }
}


void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr thread, LIR_Opr dest, LIR_Op* op) {
  switch (code) {
    case lir_sqrt: {
      __ fsqrt(dest->as_double_reg(), value->as_double_reg());
      break;
    }
    case lir_abs: {
      __ fabs(dest->as_double_reg(), value->as_double_reg());
      break;
    }
    default: {
      ShouldNotReachHere();
      break;
    }
  }
}


void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) {
  if (right->is_constant()) { // see do_LogicOp
    long uimm;
    Register d, l;
    if (dest->is_single_cpu()) {
      uimm = right->as_constant_ptr()->as_jint();
      d = dest->as_register();
      l = left->as_register();
    } else {
      uimm = right->as_constant_ptr()->as_jlong();
      d = dest->as_register_lo();
      l = left->as_register_lo();
    }
    long uimms  = (unsigned long)uimm >> 16,
         uimmss = (unsigned long)uimm >> 32;

    switch (code) {
      case lir_logic_and:
        if (uimmss != 0 || (uimms != 0 && (uimm & 0xFFFF) != 0) || is_power_of_2(uimm)) {
          __ andi(d, l, uimm); // special cases
        } else if (uimms != 0) { __ andis_(d, l, uimms); }
        else { __ andi_(d, l, uimm); }
        break;

      case lir_logic_or:
        if (uimms != 0) { assert((uimm & 0xFFFF) == 0, "sanity"); __ oris(d, l, uimms); }
        else { __ ori(d, l, uimm); }
        break;

      case lir_logic_xor:
        if (uimm == -1) { __ nand(d, l, l); } // special case
        else if (uimms != 0) { assert((uimm & 0xFFFF) == 0, "sanity"); __ xoris(d, l, uimms); }
        else { __ xori(d, l, uimm); }
        break;

      default: ShouldNotReachHere();
    }
  } else {
    assert(right->is_register(), "right should be in register");

    if (dest->is_single_cpu()) {
      switch (code) {
        case lir_logic_and: __ andr(dest->as_register(), left->as_register(), right->as_register()); break;
        case lir_logic_or:  __ orr (dest->as_register(), left->as_register(), right->as_register()); break;
        case lir_logic_xor: __ xorr(dest->as_register(), left->as_register(), right->as_register()); break;
        default: ShouldNotReachHere();
      }
    } else {
      Register l = (left->is_single_cpu() && left->is_oop_register()) ? left->as_register() :
                                                                        left->as_register_lo();
      Register r = (right->is_single_cpu() && right->is_oop_register()) ? right->as_register() :
                                                                          right->as_register_lo();

      switch (code) {
        case lir_logic_and: __ andr(dest->as_register_lo(), l, r); break;
        case lir_logic_or:  __ orr (dest->as_register_lo(), l, r); break;
        case lir_logic_xor: __ xorr(dest->as_register_lo(), l, r); break;
        default: ShouldNotReachHere();
      }
    }
  }
}


int LIR_Assembler::shift_amount(BasicType t) {
  int elem_size = type2aelembytes(t);
  switch (elem_size) {
    case 1 : return 0;
    case 2 : return 1;
    case 4 : return 2;
    case 8 : return 3;
  }
  ShouldNotReachHere();
  return -1;
}


void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) {
  info->add_register_oop(exceptionOop);

  // Reuse the debug info from the safepoint poll for the throw op itself.
  address pc_for_athrow = __ pc();
  int pc_for_athrow_offset = __ offset();
  //RelocationHolder rspec = internal_word_Relocation::spec(pc_for_athrow);
  //__ relocate(rspec);
  //__ load_const(exceptionPC->as_register(), pc_for_athrow, R0);
  __ calculate_address_from_global_toc(exceptionPC->as_register(), pc_for_athrow, truetrue/*add_relocation*/ true);
  add_call_info(pc_for_athrow_offset, info); // for exception handler

  address stub = Runtime1::entry_for(compilation()->has_fpu_code() ? Runtime1::handle_exception_id
                                                                   : Runtime1::handle_exception_nofpu_id);
  //__ load_const_optimized(R0, stub);
  __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
  __ mtctr(R0);
  __ bctr();
}


void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) {
  // Note: Not used with EnableDebuggingOnDemand.
  assert(exceptionOop->as_register() == R3, "should match");
  __ b(_unwind_handler_entry);
}


void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
  Register src = op->src()->as_register();
  Register dst = op->dst()->as_register();
  Register src_pos = op->src_pos()->as_register();
  Register dst_pos = op->dst_pos()->as_register();
  Register length  = op->length()->as_register();
  Register tmp = op->tmp()->as_register();
  Register tmp2 = R0;

  int flags = op->flags();
  ciArrayKlass* default_type = op->expected_type();
  BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL;
  if (basic_type == T_ARRAY) basic_type = T_OBJECT;

  // Set up the arraycopy stub information.
  ArrayCopyStub* stub = op->stub();
  const int frame_resize = frame::abi_reg_args_size - sizeof(frame::jit_abi); // C calls need larger frame.

  // Always do stub if no type information is available. It's ok if
  // the known type isn't loaded since the code sanity checks
  // in debug mode and the type isn't required when we know the exact type
  // also check that the type is an array type.
  if (op->expected_type() == NULL) {
    assert(src->is_nonvolatile() && src_pos->is_nonvolatile() && dst->is_nonvolatile() && dst_pos->is_nonvolatile() &&
           length->is_nonvolatile(), "must preserve");
    address copyfunc_addr = StubRoutines::generic_arraycopy();
    assert(copyfunc_addr != NULL, "generic arraycopy stub required");

    // 3 parms are int. Convert to long.
    __ mr(R3_ARG1, src);
    __ extsw(R4_ARG2, src_pos);
    __ mr(R5_ARG3, dst);
    __ extsw(R6_ARG4, dst_pos);
    __ extsw(R7_ARG5, length);

#ifndef PRODUCT
    if (PrintC1Statistics) {
      address counter = (address)&Runtime1::_generic_arraycopystub_cnt;
      int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true);
      __ lwz(R11_scratch1, simm16_offs, tmp);
      __ addi(R11_scratch1, R11_scratch1, 1);
      __ stw(R11_scratch1, simm16_offs, tmp);
    }
#endif
    __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0);

    __ nand(tmp, R3_RET, R3_RET);
    __ subf(length, tmp, length);
    __ add(src_pos, tmp, src_pos);
    __ add(dst_pos, tmp, dst_pos);

    __ cmpwi(CCR0, R3_RET, 0);
    __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::less), *stub->entry());
    __ bind(*stub->continuation());
    return;
  }

  assert(default_type != NULL && default_type->is_array_klass(), "must be true at this point");
  Label cont, slow, copyfunc;

  bool simple_check_flag_set = flags & (LIR_OpArrayCopy::src_null_check |
                                        LIR_OpArrayCopy::dst_null_check |
                                        LIR_OpArrayCopy::src_pos_positive_check |
                                        LIR_OpArrayCopy::dst_pos_positive_check |
                                        LIR_OpArrayCopy::length_positive_check);

  // Use only one conditional branch for simple checks.
  if (simple_check_flag_set) {
    ConditionRegister combined_check = CCR1, tmp_check = CCR1;

    // Make sure src and dst are non-null.
    if (flags & LIR_OpArrayCopy::src_null_check) {
      __ cmpdi(combined_check, src, 0);
      tmp_check = CCR0;
    }

    if (flags & LIR_OpArrayCopy::dst_null_check) {
      __ cmpdi(tmp_check, dst, 0);
      if (tmp_check != combined_check) {
        __ cror(combined_check, Assembler::equal, tmp_check, Assembler::equal);
      }
      tmp_check = CCR0;
--> --------------------

--> maximum size reached

--> --------------------

96%


¤ Dauer der Verarbeitung: 0.44 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.