c1_LIR.hpp revision 0
/*
* Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
class BlockBegin;
class BlockList;
class LIR_Assembler;
class CodeEmitInfo;
class CodeStub;
class CodeStubList;
class ArrayCopyStub;
class LIR_Op;
class ciType;
class ValueType;
class LIR_OpVisitState;
class FpuStackSim;
//---------------------------------------------------------------------
// LIR Operands
// LIR_OprDesc
// LIR_OprPtr
// LIR_Const
// LIR_Address
//---------------------------------------------------------------------
class LIR_OprDesc;
class LIR_OprPtr;
class LIR_Const;
class LIR_Address;
class LIR_OprVisitor;
typedef LIR_OprDesc* LIR_Opr;
typedef int RegNr;
// define LIR_OprPtr early so LIR_OprDesc can refer to it
class LIR_OprPtr: public CompilationResourceObj {
public:
};
// LIR constants
class LIR_Const: public LIR_OprPtr {
private:
void type_check(BasicType t1, BasicType t2) const { assert(type() == t1 || type() == t2, "type check"); }
public:
LIR_Const(void* p) {
#ifdef _LP64
#else
#endif
}
virtual LIR_Const* as_constant() { return this; }
#ifdef _LP64
#else
#endif
jint as_jint_lo_bits() const {
} else {
return as_jint_lo();
}
}
jint as_jint_hi_bits() const {
} else {
return as_jint_hi();
}
}
bool is_zero_float() {
}
bool is_one_float() {
}
bool is_zero_double() {
jdouble d = as_jdouble();
}
bool is_one_double() {
jdouble d = as_jdouble();
}
};
//---------------------LIR Operand descriptor------------------------------------
//
// The class LIR_OprDesc represents a LIR instruction operand;
// Constants and addresses are represented as resource area allocated
// structures (see above).
// Registers and stack locations are inlined into the this pointer
// (see value function).
class LIR_OprDesc: public CompilationResourceObj {
public:
// value structure:
// data opr-type opr-kind
// +--------------+-------+-------+
// [max...........|7 6 5 4|3 2 1 0]
// ^
// is_pointer bit
//
// lowest bit cleared, means it is a structure pointer
// we need 4 bits to represent types
private:
friend class LIR_OprFact;
// Conversion
}
enum OprKind {
pointer_value = 0
, stack_value = 1
, cpu_register = 3
, fpu_register = 5
, illegal_value = 7
};
enum OprBits {
pointer_bits = 1
, kind_bits = 3
, type_bits = 4
, size_bits = 2
, destroys_bits = 1
, virtual_bits = 1
, is_xmm_bits = 1
, last_use_bits = 1
};
enum OprShift {
kind_shift = 0
, reg1_shift = data_shift
};
enum OprSize {
single_size = 0 << size_shift
};
enum OprMask {
};
public:
enum {
};
static inline LIR_Opr illegalOpr();
enum OprType {
};
OprType type_field_valid() const { assert(is_register() || is_stack(), "should not be called otherwise"); return (OprType)(value() & type_mask); }
switch (t) {
case T_LONG:
case T_DOUBLE:
return double_size;
break;
case T_FLOAT:
case T_BOOLEAN:
case T_CHAR:
case T_BYTE:
case T_SHORT:
case T_INT:
case T_OBJECT:
case T_ARRAY:
return single_size;
break;
default:
}
}
void validate_type() const PRODUCT_RETURN;
if (is_pointer()) {
}
return as_BasicType(type_field());
}
// checks whether types are same
}
}
bool is_float_kind() const { return is_pointer() ? pointer()->is_float_kind() : (kind_field() == fpu_register); }
bool is_oop() const;
// semantic for fpu- and xmm-registers:
// * is_float and is_double return true for xmm_registers
// (so is_single_fpu and is_single_xmm are true)
// * So you must always check for is_???_xmm prior to is_???_fpu to
// distinguish between fpu- and xmm-registers
bool is_single_stack() const { validate_type(); return check_value_mask(kind_mask | size_mask, stack_value | single_size); }
bool is_double_stack() const { validate_type(); return check_value_mask(kind_mask | size_mask, stack_value | double_size); }
bool is_virtual_cpu() const { validate_type(); return check_value_mask(kind_mask | virtual_mask, cpu_register | virtual_mask); }
bool is_fixed_cpu() const { validate_type(); return check_value_mask(kind_mask | virtual_mask, cpu_register); }
bool is_single_cpu() const { validate_type(); return check_value_mask(kind_mask | size_mask, cpu_register | single_size); }
bool is_double_cpu() const { validate_type(); return check_value_mask(kind_mask | size_mask, cpu_register | double_size); }
bool is_virtual_fpu() const { validate_type(); return check_value_mask(kind_mask | virtual_mask, fpu_register | virtual_mask); }
bool is_fixed_fpu() const { validate_type(); return check_value_mask(kind_mask | virtual_mask, fpu_register); }
bool is_single_fpu() const { validate_type(); return check_value_mask(kind_mask | size_mask, fpu_register | single_size); }
bool is_double_fpu() const { validate_type(); return check_value_mask(kind_mask | size_mask, fpu_register | double_size); }
bool is_xmm_register() const { validate_type(); return check_value_mask(kind_mask | is_xmm_mask, fpu_register | is_xmm_mask); }
bool is_single_xmm() const { validate_type(); return check_value_mask(kind_mask | size_mask | is_xmm_mask, fpu_register | single_size | is_xmm_mask); }
bool is_double_xmm() const { validate_type(); return check_value_mask(kind_mask | size_mask | is_xmm_mask, fpu_register | double_size | is_xmm_mask); }
// fast accessor functions for special bits that do not work for pointers
// (in this functions, the check for is_pointer() is omitted)
bool is_single_word() const { assert(is_register() || is_stack(), "type check"); return check_value_mask(size_mask, single_size); }
bool is_double_word() const { assert(is_register() || is_stack(), "type check"); return check_value_mask(size_mask, double_size); }
bool is_virtual_register() const { assert(is_register(), "type check"); return check_value_mask(virtual_mask, virtual_mask); }
bool is_oop_register() const { assert(is_register() || is_stack(), "type check"); return type_field_valid() == object_type; }
BasicType type_register() const { assert(is_register() || is_stack(), "type check"); return as_BasicType(type_field_valid()); }
bool is_last_use() const { assert(is_register(), "only works for registers"); return (value() & last_use_mask) != 0; }
bool is_fpu_stack_offset() const { assert(is_register(), "only works for registers"); return (value() & is_fpu_stack_offset_mask) != 0; }
LIR_Opr make_last_use() { assert(is_register(), "only works for registers"); return (LIR_Opr)(value() | last_use_mask); }
LIR_Opr make_fpu_stack_offset() { assert(is_register(), "only works for registers"); return (LIR_Opr)(value() | is_fpu_stack_offset_mask); }
int single_stack_ix() const { assert(is_single_stack() && !is_virtual(), "type check"); return (int)data(); }
int double_stack_ix() const { assert(is_double_stack() && !is_virtual(), "type check"); return (int)data(); }
RegNr cpu_regnr() const { assert(is_single_cpu() && !is_virtual(), "type check"); return (RegNr)data(); }
RegNr cpu_regnrLo() const { assert(is_double_cpu() && !is_virtual(), "type check"); return (RegNr)lo_reg_half(); }
RegNr cpu_regnrHi() const { assert(is_double_cpu() && !is_virtual(), "type check"); return (RegNr)hi_reg_half(); }
RegNr fpu_regnr() const { assert(is_single_fpu() && !is_virtual(), "type check"); return (RegNr)data(); }
RegNr fpu_regnrLo() const { assert(is_double_fpu() && !is_virtual(), "type check"); return (RegNr)lo_reg_half(); }
RegNr fpu_regnrHi() const { assert(is_double_fpu() && !is_virtual(), "type check"); return (RegNr)hi_reg_half(); }
RegNr xmm_regnr() const { assert(is_single_xmm() && !is_virtual(), "type check"); return (RegNr)data(); }
RegNr xmm_regnrLo() const { assert(is_double_xmm() && !is_virtual(), "type check"); return (RegNr)lo_reg_half(); }
RegNr xmm_regnrHi() const { assert(is_double_xmm() && !is_virtual(), "type check"); return (RegNr)hi_reg_half(); }
Register as_register() const;
Register as_register_lo() const;
Register as_register_hi() const;
#ifdef _LP64
if (is_double_cpu()) {
return as_register_lo();
}
#endif
return as_register();
}
#ifdef IA32
XMMRegister as_xmm_float_reg() const;
XMMRegister as_xmm_double_reg() const;
// for compatibility with RInfo
int fpu () const { return lo_reg_half(); }
#endif
#ifdef SPARC
FloatRegister as_float_reg () const;
FloatRegister as_double_reg () const;
#endif
void print() const PRODUCT_RETURN;
};
switch (type) {
case T_OBJECT:
case T_ILLEGAL: // fall through
}
}
switch (t) {
default: ShouldNotReachHere(); return T_ILLEGAL;
}
}
// LIR_Address
class LIR_Address: public LIR_OprPtr {
friend class LIR_OpVisitState;
public:
// NOTE: currently these must be the log2 of the scale factor (and
// must also be equivalent to the ScaleFactor enum in
enum Scale {
times_1 = 0,
times_2 = 1,
times_4 = 2,
times_8 = 3
};
private:
public:
#ifdef IA32
#endif
bool equals(LIR_Address* other) const { return base() == other->base() && index() == other->index() && disp() == other->disp() && scale() == other->scale(); }
virtual LIR_Address* as_address() { return this; }
void verify() const PRODUCT_RETURN;
};
// operand factory
class LIR_OprFact: public AllStatic {
public:
static LIR_Opr illegalOpr;
static LIR_Opr single_cpu(int reg) { return (LIR_Opr)((reg << LIR_OprDesc::reg1_shift) | LIR_OprDesc::int_type | LIR_OprDesc::cpu_register | LIR_OprDesc::single_size); }
static LIR_Opr single_cpu_oop(int reg) { return (LIR_Opr)((reg << LIR_OprDesc::reg1_shift) | LIR_OprDesc::object_type | LIR_OprDesc::cpu_register | LIR_OprDesc::single_size); }
static LIR_Opr double_cpu(int reg1, int reg2) { return (LIR_Opr)((reg1 << LIR_OprDesc::reg1_shift) | (reg2 << LIR_OprDesc::reg2_shift) | LIR_OprDesc::long_type | LIR_OprDesc::cpu_register | LIR_OprDesc::double_size); }
static LIR_Opr single_fpu(int reg) { return (LIR_Opr)((reg << LIR_OprDesc::reg1_shift) | LIR_OprDesc::float_type | LIR_OprDesc::fpu_register | LIR_OprDesc::single_size); }
#ifdef SPARC
static LIR_Opr double_fpu(int reg1, int reg2) { return (LIR_Opr)((reg1 << LIR_OprDesc::reg1_shift) | (reg2 << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | LIR_OprDesc::fpu_register | LIR_OprDesc::double_size); }
#endif
#ifdef IA32
static LIR_Opr double_fpu(int reg) { return (LIR_Opr)((reg << LIR_OprDesc::reg1_shift) | (reg << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | LIR_OprDesc::fpu_register | LIR_OprDesc::double_size); }
static LIR_Opr single_xmm(int reg) { return (LIR_Opr)((reg << LIR_OprDesc::reg1_shift) | LIR_OprDesc::float_type | LIR_OprDesc::fpu_register | LIR_OprDesc::single_size | LIR_OprDesc::is_xmm_mask); }
static LIR_Opr double_xmm(int reg) { return (LIR_Opr)((reg << LIR_OprDesc::reg1_shift) | (reg << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | LIR_OprDesc::fpu_register | LIR_OprDesc::double_size | LIR_OprDesc::is_xmm_mask); }
#endif
switch (type) {
case T_OBJECT: // fall through
case T_ARRAY: res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::object_type | LIR_OprDesc::cpu_register | LIR_OprDesc::single_size | LIR_OprDesc::virtual_mask); break;
case T_INT: res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::int_type | LIR_OprDesc::cpu_register | LIR_OprDesc::single_size | LIR_OprDesc::virtual_mask); break;
case T_LONG: res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::long_type | LIR_OprDesc::cpu_register | LIR_OprDesc::double_size | LIR_OprDesc::virtual_mask); break;
case T_FLOAT: res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::float_type | LIR_OprDesc::fpu_register | LIR_OprDesc::single_size | LIR_OprDesc::virtual_mask); break;
case T_DOUBLE: res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::double_type | LIR_OprDesc::fpu_register | LIR_OprDesc::double_size | LIR_OprDesc::virtual_mask); break;
}
#ifdef ASSERT
res->validate_type();
// old-style calculation; check if old and new method are equal
#endif
return res;
}
// 'index' is computed by FrameMap::local_stack_pos(index); do not use other parameters as
// the index is platform independent; a double stack useing indeces 2 and 3 has always
// index 2.
switch (type) {
case T_OBJECT: // fall through
case T_ARRAY: res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::object_type | LIR_OprDesc::stack_value | LIR_OprDesc::single_size); break;
case T_INT: res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::int_type | LIR_OprDesc::stack_value | LIR_OprDesc::single_size); break;
case T_LONG: res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::long_type | LIR_OprDesc::stack_value | LIR_OprDesc::double_size); break;
case T_FLOAT: res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::float_type | LIR_OprDesc::stack_value | LIR_OprDesc::single_size); break;
case T_DOUBLE: res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::double_type | LIR_OprDesc::stack_value | LIR_OprDesc::double_size); break;
}
#ifdef ASSERT
LIR_Opr old_res = (LIR_Opr)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::stack_value | as_OprType(type) | LIR_OprDesc::size_for(type));
#endif
return res;
}
};
//-------------------------------------------------------------------------------
// LIR Instructions
//-------------------------------------------------------------------------------
//
// Note:
// - every instruction has a result operand
// - every instruction has an CodeEmitInfo operand (can be revisited later)
// - every instruction has a LIR_OpCode operand
// - LIR_OpN, means an instruction that has N input operands
//
// class hierarchy:
//
class LIR_Op;
class LIR_Op0;
class LIR_OpLabel;
class LIR_Op1;
class LIR_OpBranch;
class LIR_OpConvert;
class LIR_OpAllocObj;
class LIR_OpRoundFP;
class LIR_Op2;
class LIR_OpDelay;
class LIR_Op3;
class LIR_OpAllocArray;
class LIR_OpCall;
class LIR_OpJavaCall;
class LIR_OpRTCall;
class LIR_OpArrayCopy;
class LIR_OpLock;
class LIR_OpTypeCheck;
class LIR_OpCompareAndSwap;
class LIR_OpProfileCall;
// LIR operation codes
enum LIR_Code {
, lir_nop
, end_op0
, lir_fxch
, lir_fld
, lir_push
, lir_pop
, lir_leal
, lir_neg
, lir_move
, end_op1
, lir_cmp
, lir_add
, lir_sub
, lir_mul
, lir_div
, lir_rem
, lir_sqrt
, lir_abs
, lir_sin
, lir_cos
, lir_tan
, lir_log
, lir_shl
, lir_shr
, lir_ushr
, end_op2
, lir_idiv
, lir_irem
, end_op3
, lir_lock
};
enum LIR_Condition {
, lir_cond_unknown = -1
};
enum LIR_PatchCode {
};
enum LIR_MoveKind {
};
// --------------------------------------------------
// LIR_Op
// --------------------------------------------------
class LIR_Op: public CompilationResourceObj {
friend class LIR_OpVisitState;
#ifdef ASSERT
private:
const char * _file;
int _line;
#endif
protected:
unsigned short _code;
unsigned short _flags;
int _id; // value id for register allocation
int _fpu_pop_count;
protected:
static bool is_in_range(LIR_Code test, LIR_Code start, LIR_Code end) { return start < test && test < end; }
public:
LIR_Op()
, _flags(0)
#ifdef ASSERT
, _line(0)
#endif
, _fpu_pop_count(0)
, _id(-1) {}
, _flags(0)
#ifdef ASSERT
, _line(0)
#endif
, _fpu_pop_count(0)
, _id(-1) {}
#ifdef ASSERT
}
#endif
virtual const char * name() const PRODUCT_RETURN0;
// FPU stack simulation helpers -- only used on Intel
void set_fpu_pop_count(int count) { assert(count >= 0 && count <= 1, "currently only 0 and 1 are valid"); _fpu_pop_count = count; }
int fpu_pop_count() const { return _fpu_pop_count; }
bool pop_fpu_stack() { return _fpu_pop_count > 0; }
virtual void verify() const {}
};
// for calls
class LIR_OpCall: public LIR_Op {
friend class LIR_OpVisitState;
protected:
protected:
public:
virtual LIR_OpCall* as_OpCall() { return this; }
};
// --------------------------------------------------
// LIR_OpJavaCall
// --------------------------------------------------
class LIR_OpJavaCall: public LIR_OpCall {
friend class LIR_OpVisitState;
private:
public:
intptr_t vtable_offset() const {
}
virtual LIR_OpJavaCall* as_OpJavaCall() { return this; }
};
// --------------------------------------------------
// LIR_OpLabel
// --------------------------------------------------
// Location where a branch can continue
class LIR_OpLabel: public LIR_Op {
friend class LIR_OpVisitState;
private:
public:
virtual LIR_OpLabel* as_OpLabel() { return this; }
};
// LIR_OpArrayCopy
class LIR_OpArrayCopy: public LIR_Op {
friend class LIR_OpVisitState;
private:
int _flags;
public:
enum Flags {
src_null_check = 1 << 0,
};
LIR_OpArrayCopy(LIR_Opr src, LIR_Opr src_pos, LIR_Opr dst, LIR_Opr dst_pos, LIR_Opr length, LIR_Opr tmp,
virtual LIR_OpArrayCopy* as_OpArrayCopy() { return this; }
};
// --------------------------------------------------
// LIR_Op0
// --------------------------------------------------
friend class LIR_OpVisitState;
public:
: LIR_Op(code, LIR_OprFact::illegalOpr, NULL) { assert(is_in_range(code, begin_op0, end_op0), "code check"); }
};
// --------------------------------------------------
// LIR_Op1
// --------------------------------------------------
friend class LIR_OpVisitState;
protected:
LIR_PatchCode _patch; // only required with patchin (NEEDS_CLEANUP: do we want a special instruction for patching?)
}
public:
LIR_Op1(LIR_Code code, LIR_Opr opr, LIR_Opr result = LIR_OprFact::illegalOpr, BasicType type = T_ILLEGAL, LIR_PatchCode patch = lir_patch_none, CodeEmitInfo* info = NULL)
LIR_Op1(LIR_Code code, LIR_Opr opr, LIR_Opr result, BasicType type, LIR_PatchCode patch, CodeEmitInfo* info, LIR_MoveKind kind)
}
LIR_MoveKind move_kind() const {
return (LIR_MoveKind)_flags;
}
virtual const char * name() const PRODUCT_RETURN0;
virtual void verify() const;
};
// for runtime calls
class LIR_OpRTCall: public LIR_OpCall {
friend class LIR_OpVisitState;
private:
public:
virtual LIR_OpRTCall* as_OpRTCall() { return this; }
virtual void verify() const;
};
class LIR_OpBranch: public LIR_Op {
friend class LIR_OpVisitState;
private:
public:
// for unordered comparisons
void change_block(BlockBegin* b);
void change_ublock(BlockBegin* b);
void negate_cond();
virtual LIR_OpBranch* as_OpBranch() { return this; }
};
class ConversionStub;
class LIR_OpConvert: public LIR_Op1 {
friend class LIR_OpVisitState;
private:
public:
virtual LIR_OpConvert* as_OpConvert() { return this; }
};
// LIR_OpAllocObj
class LIR_OpAllocObj : public LIR_Op1 {
friend class LIR_OpVisitState;
private:
int _hdr_size;
int _obj_size;
bool _init_check;
public:
int header_size() const { return _hdr_size; }
int object_size() const { return _obj_size; }
bool init_check() const { return _init_check; }
virtual LIR_OpAllocObj * as_OpAllocObj () { return this; }
};
// LIR_OpRoundFP
class LIR_OpRoundFP : public LIR_Op1 {
friend class LIR_OpVisitState;
private:
public:
, _tmp(stack_loc_temp) {}
virtual LIR_OpRoundFP* as_OpRoundFP() { return this; }
};
// LIR_OpTypeCheck
class LIR_OpTypeCheck: public LIR_Op {
friend class LIR_OpVisitState;
private:
bool _fast_check;
// Helpers for Tier1UpdateMethodData
int _profiled_bci;
public:
ciKlass* klass() const { assert(code() == lir_instanceof || code() == lir_checkcast, "not valid"); return _klass; }
bool fast_check() const { assert(code() == lir_instanceof || code() == lir_checkcast, "not valid"); return _fast_check; }
// methodDataOop profiling
int profiled_bci() { return _profiled_bci; }
virtual LIR_OpTypeCheck* as_OpTypeCheck() { return this; }
};
// LIR_Op2
friend class LIR_OpVisitState;
int _fpu_stack_size; // for sin/cos implementation on Intel
protected:
void verify() const;
public:
LIR_Op2(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, CodeEmitInfo* info = NULL)
, _fpu_stack_size(0)
}
, _fpu_stack_size(0)
}
, _fpu_stack_size(0)
}
, _fpu_stack_size(0)
}
LIR_Condition condition() const {
assert(code() == lir_cmp || code() == lir_cmove, "only valid for cmp and cmove"); return _condition;
}
int fpu_stack_size() const { return _fpu_stack_size; }
};
class LIR_OpAllocArray : public LIR_Op {
friend class LIR_OpVisitState;
private:
public:
LIR_OpAllocArray(LIR_Opr klass, LIR_Opr len, LIR_Opr result, LIR_Opr t1, LIR_Opr t2, LIR_Opr t3, LIR_Opr t4, BasicType type, CodeStub* stub)
virtual LIR_OpAllocArray * as_OpAllocArray () { return this; }
};
friend class LIR_OpVisitState;
private:
public:
LIR_Op3(LIR_Code code, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr opr3, LIR_Opr result, CodeEmitInfo* info = NULL)
};
//--------------------------------
class LabelObj: public CompilationResourceObj {
private:
public:
LabelObj() {}
};
class LIR_OpLock: public LIR_Op {
friend class LIR_OpVisitState;
private:
public:
LIR_OpLock(LIR_Code code, LIR_Opr hdr, LIR_Opr obj, LIR_Opr lock, LIR_Opr scratch, CodeStub* stub, CodeEmitInfo* info)
virtual LIR_OpLock* as_OpLock() { return this; }
};
class LIR_OpDelay: public LIR_Op {
friend class LIR_OpVisitState;
private:
public:
}
virtual LIR_OpDelay* as_OpDelay() { return this; }
};
// LIR_OpCompareAndSwap
class LIR_OpCompareAndSwap : public LIR_Op {
friend class LIR_OpVisitState;
private:
public:
LIR_OpCompareAndSwap(LIR_Code code, LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, LIR_Opr t1, LIR_Opr t2)
virtual LIR_OpCompareAndSwap * as_OpCompareAndSwap () { return this; }
};
// LIR_OpProfileCall
class LIR_OpProfileCall : public LIR_Op {
friend class LIR_OpVisitState;
private:
int _profiled_bci;
public:
// Destroys recv
LIR_OpProfileCall(LIR_Code code, ciMethod* profiled_method, int profiled_bci, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder)
, _known_holder(known_holder) { }
int profiled_bci() const { return _profiled_bci; }
virtual LIR_OpProfileCall* as_OpProfileCall() { return this; }
};
class LIR_InsertionBuffer;
//--------------------------------LIR_List---------------------------------------------------
// Maintains a list of LIR instructions (one instance of LIR_List per basic block)
// The LIR instructions are appended by the LIR_List class itself;
//
// Notes:
// - all offsets are(should be) in bytes
// - local positions are specified with an offset, with offset 0 being local 0
class LIR_List: public CompilationResourceObj {
private:
#ifndef PRODUCT
#endif
#ifdef ASSERT
const char * _file;
int _line;
#endif
#ifndef PRODUCT
if (PrintIRWithLIR) {
}
#endif // PRODUCT
#ifdef ASSERT
_line = 0;
#endif
}
public:
#ifdef ASSERT
#endif
//---------- accessors ---------------
// insert LIR_Ops in buffer to right places in LIR_List
//---------- mutators ---------------
void insert_before(int i, LIR_List* op_list) { _operations.insert_before(i, op_list->instructions_list()); }
//---------- printing -------------
void print_instructions() PRODUCT_RETURN;
//---------- instructions -------------
CodeEmitInfo* info) {
}
append(new LIR_OpJavaCall(lir_static_call, method, LIR_OprFact::illegalOpr, result, dest, arguments, info));
}
}
append(new LIR_OpJavaCall(lir_virtual_call, method, receiver, result, vtable_offset, arguments, info));
}
// result is a stack location for old backend and vreg for UseLinearScan
// stack_loc_temp is an illegal register for old backend
void roundfp(LIR_Opr reg, LIR_Opr stack_loc_temp, LIR_Opr result) { append(new LIR_OpRoundFP(reg, stack_loc_temp, result)); }
void unaligned_move(LIR_Address* src, LIR_Opr dst) { append(new LIR_Op1(lir_move, LIR_OprFact::address(src), dst, dst->type(), lir_patch_none, NULL, lir_move_unaligned)); }
void unaligned_move(LIR_Opr src, LIR_Address* dst) { append(new LIR_Op1(lir_move, src, LIR_OprFact::address(dst), src->type(), lir_patch_none, NULL, lir_move_unaligned)); }
void unaligned_move(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_move, src, dst, dst->type(), lir_patch_none, NULL, lir_move_unaligned)); }
void move(LIR_Opr src, LIR_Opr dst, CodeEmitInfo* info = NULL) { append(new LIR_Op1(lir_move, src, dst, dst->type(), lir_patch_none, info)); }
void move(LIR_Address* src, LIR_Opr dst, CodeEmitInfo* info = NULL) { append(new LIR_Op1(lir_move, LIR_OprFact::address(src), dst, src->type(), lir_patch_none, info)); }
void move(LIR_Opr src, LIR_Address* dst, CodeEmitInfo* info = NULL) { append(new LIR_Op1(lir_move, src, LIR_OprFact::address(dst), dst->type(), lir_patch_none, info)); }
void volatile_move(LIR_Opr src, LIR_Opr dst, BasicType type, CodeEmitInfo* info = NULL, LIR_PatchCode patch_code = lir_patch_none) { append(new LIR_Op1(lir_move, src, dst, type, patch_code, info, lir_move_volatile)); }
void oop2reg (jobject o, LIR_Opr reg) { append(new LIR_Op1(lir_move, LIR_OprFact::oopConst(o), reg)); }
void convert(Bytecodes::Code code, LIR_Opr left, LIR_Opr dst, ConversionStub* stub = NULL/*, bool is_32bit = false*/) { append(new LIR_OpConvert(code, left, dst, stub)); }
void logical_and (LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_logic_and, left, right, dst)); }
void logical_or (LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_logic_or, left, right, dst)); }
void logical_xor (LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_logic_xor, left, right, dst)); }
void null_check(LIR_Opr opr, CodeEmitInfo* info) { append(new LIR_Op1(lir_null_check, opr, info)); }
void throw_exception(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { append(new LIR_Op2(lir_throw, exceptionPC, exceptionOop, LIR_OprFact::illegalOpr, info)); }
void unwind_exception(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { append(new LIR_Op2(lir_unwind, exceptionPC, exceptionOop, LIR_OprFact::illegalOpr, info)); }
}
}
}
}
void log10 (LIR_Opr from, LIR_Opr to, LIR_Opr tmp) { append(new LIR_Op2(lir_log10, from, tmp, to)); }
void sin (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_sin , from, tmp1, to, tmp2)); }
void cos (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_cos , from, tmp1, to, tmp2)); }
void tan (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_tan , from, tmp1, to, tmp2)); }
void add (LIR_Opr left, LIR_Opr right, LIR_Opr res) { append(new LIR_Op2(lir_add, left, right, res)); }
void sub (LIR_Opr left, LIR_Opr right, LIR_Opr res, CodeEmitInfo* info = NULL) { append(new LIR_Op2(lir_sub, left, right, res, info)); }
void mul (LIR_Opr left, LIR_Opr right, LIR_Opr res) { append(new LIR_Op2(lir_mul, left, right, res)); }
void mul_strictfp (LIR_Opr left, LIR_Opr right, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_mul_strictfp, left, right, res, tmp)); }
void div (LIR_Opr left, LIR_Opr right, LIR_Opr res, CodeEmitInfo* info = NULL) { append(new LIR_Op2(lir_div, left, right, res, info)); }
void div_strictfp (LIR_Opr left, LIR_Opr right, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_div_strictfp, left, right, res, tmp)); }
void rem (LIR_Opr left, LIR_Opr right, LIR_Opr res, CodeEmitInfo* info = NULL) { append(new LIR_Op2(lir_rem, left, right, res, info)); }
void volatile_load_mem_reg(LIR_Address* address, LIR_Opr dst, CodeEmitInfo* info, LIR_PatchCode patch_code = lir_patch_none);
void volatile_load_unsafe_reg(LIR_Opr base, LIR_Opr offset, LIR_Opr dst, BasicType type, CodeEmitInfo* info, LIR_PatchCode patch_code);
void load(LIR_Address* addr, LIR_Opr src, CodeEmitInfo* info = NULL, LIR_PatchCode patch_code = lir_patch_none);
void store_mem_int(jint v, LIR_Opr base, int offset_in_bytes, BasicType type, CodeEmitInfo* info, LIR_PatchCode patch_code = lir_patch_none);
void store_mem_oop(jobject o, LIR_Opr base, int offset_in_bytes, BasicType type, CodeEmitInfo* info, LIR_PatchCode patch_code = lir_patch_none);
void store(LIR_Opr src, LIR_Address* addr, CodeEmitInfo* info = NULL, LIR_PatchCode patch_code = lir_patch_none);
void volatile_store_mem_reg(LIR_Opr src, LIR_Address* address, CodeEmitInfo* info, LIR_PatchCode patch_code = lir_patch_none);
void volatile_store_unsafe_reg(LIR_Opr src, LIR_Opr base, LIR_Opr offset, BasicType type, CodeEmitInfo* info, LIR_PatchCode patch_code);
void allocate_object(LIR_Opr dst, LIR_Opr t1, LIR_Opr t2, LIR_Opr t3, LIR_Opr t4, int header_size, int object_size, LIR_Opr klass, bool init_check, CodeStub* stub);
void allocate_array(LIR_Opr dst, LIR_Opr len, LIR_Opr t1,LIR_Opr t2, LIR_Opr t3,LIR_Opr t4, BasicType type, LIR_Opr klass, CodeStub* stub);
// jump is an unconditional branch
}
}
}
}
}
void shift_left(LIR_Opr value, int count, LIR_Opr dst) { shift_left(value, LIR_OprFact::intConst(count), dst, LIR_OprFact::illegalOpr); }
void shift_right(LIR_Opr value, int count, LIR_Opr dst) { shift_right(value, LIR_OprFact::intConst(count), dst, LIR_OprFact::illegalOpr); }
void unsigned_shift_right(LIR_Opr value, int count, LIR_Opr dst) { unsigned_shift_right(value, LIR_OprFact::intConst(count), dst, LIR_OprFact::illegalOpr); }
void lcmp2int(LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_cmp_l2i, left, right, dst)); }
}
}
void load_stack_address_monitor(int monitor_ix, LIR_Opr dst) { append(new LIR_Op1(lir_monaddr, LIR_OprFact::intConst(monitor_ix), dst)); }
void lock_object(LIR_Opr hdr, LIR_Opr obj, LIR_Opr lock, LIR_Opr scratch, CodeStub* stub, CodeEmitInfo* info);
void arraycopy(LIR_Opr src, LIR_Opr src_pos, LIR_Opr dst, LIR_Opr dst_pos, LIR_Opr length, LIR_Opr tmp, ciArrayKlass* expected_type, int flags, CodeEmitInfo* info) { append(new LIR_OpArrayCopy(src, src_pos, dst, dst_pos, length, tmp, expected_type, flags, info)); }
void instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch);
void store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception);
// methodDataOop profiling
void profile_call(ciMethod* method, int bci, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* cha_klass) { append(new LIR_OpProfileCall(lir_profile_call, method, bci, mdo, recv, t1, cha_klass)); }
};
class LIR_InsertionBuffer : public CompilationResourceObj {
private:
LIR_List* _lir; // the lir list where ops of this buffer should be inserted later (NULL when uninitialized)
// list of insertion points. index and count are stored alternately:
// _index_and_count[i * 2]: the index into lir list where "count" ops should be inserted
// _index_and_count[i * 2 + 1]: the number of ops to be inserted at index
// the LIR_Ops to be inserted
void append_new(int index, int count) { _index_and_count.append(index); _index_and_count.append(count); }
#ifdef ASSERT
void verify();
#endif
public:
// must be called before using the insertion buffer
void init(LIR_List* lir) { assert(!initialized(), "already initialized"); _lir = lir; _index_and_count.clear(); _ops.clear(); }
// called automatically when the buffer is appended to the LIR_List
// accessors
// append an instruction to the buffer
// instruction
void move(int index, LIR_Opr src, LIR_Opr dst, CodeEmitInfo* info = NULL) { append(index, new LIR_Op1(lir_move, src, dst, dst->type(), lir_patch_none, info)); }
};
//
// LIR_OpVisitState is used for manipulating LIR_Ops in an abstract way.
// Calling a LIR_Op's visit function with a LIR_OpVisitState causes
// information about the input, output and temporaries used by the
// op to be recorded. It also records whether the op has call semantics
// and also records all the CodeEmitInfos used by this op.
//
class LIR_OpVisitState: public StackObj {
public:
typedef enum { inputMode, firstMode = inputMode, tempMode, outputMode, numModes, invalidMode = -1 } OprMode;
enum {
maxNumberOfOperands = 14,
maxNumberOfInfos = 4
};
private:
// optimization: the operands and infos are not stored in a variable-length
// list, but in a fixed-size array to save time of size checks and resizing
int _info_len;
bool _has_call;
bool _has_slow_case;
// only include register operands
// addresses are decomposed to the base and index registers
// constants and stack operands are ignored
if (opr->is_register()) {
} else if (opr->is_pointer()) {
// special handling for addresses: add base and index register of the address
// both are always input operands!
}
}
} else {
}
} else {
}
}
}
public:
LIR_OpVisitState() { reset(); }
bool has_slow_case() const { return _has_slow_case; }
void reset() {
_has_call = false;
_has_slow_case = false;
_oprs_len[outputMode] = 0;
_info_len = 0;
}
}
}
}
int info_count() const {
return _info_len;
}
}
// collects all register operands of the instruction
#if ASSERT
// check that an operation has no operands
#endif
// LIR_Op visitor functions use these to fill in the state
void do_slow_case() { _has_slow_case = true; }
_has_slow_case = true;
}
};