Mercurial > hg > graal-compiler
view src/cpu/ppc/vm/assembler_ppc.cpp @ 14436:b0133e4187d3
8028471: PPC64 (part 215): opto: Extend ImplicitNullCheck optimization.
Summary: Fixed Implicit NULL check optimization for AIX, where the page at address '0' is only write-protected.
Reviewed-by: kvn
author | goetz |
---|---|
date | Thu, 21 Nov 2013 18:29:34 -0800 |
parents | ec28f9c041ff |
children | 71a71b0bc844 |
line wrap: on
line source
/* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright 2012, 2013 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.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" #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, 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