提交 5928bc3c 编写于 作者: T twisti

6961690: load oops from constant table on SPARC

Summary: oops should be loaded from the constant table of an nmethod instead of materializing them with a long code sequence.
Reviewed-by: never, kvn
上级 b2f75e8c
...@@ -1443,6 +1443,45 @@ void MacroAssembler::set64(jlong value, Register d, Register tmp) { ...@@ -1443,6 +1443,45 @@ void MacroAssembler::set64(jlong value, Register d, Register tmp) {
} }
} }
int MacroAssembler::size_of_set64(jlong value) {
v9_dep();
int hi = (int)(value >> 32);
int lo = (int)(value & ~0);
int count = 0;
// (Matcher::isSimpleConstant64 knows about the following optimizations.)
if (Assembler::is_simm13(lo) && value == lo) {
count++;
} else if (hi == 0) {
count++;
if (low10(lo) != 0)
count++;
}
else if (hi == -1) {
count += 2;
}
else if (lo == 0) {
if (Assembler::is_simm13(hi)) {
count++;
} else {
count++;
if (low10(hi) != 0)
count++;
}
count++;
}
else {
count += 2;
if (low10(hi) != 0)
count++;
if (low10(lo) != 0)
count++;
count += 2;
}
return count;
}
// compute size in bytes of sparc frame, given // compute size in bytes of sparc frame, given
// number of extraWords // number of extraWords
int MacroAssembler::total_frame_size_in_bytes(int extraWords) { int MacroAssembler::total_frame_size_in_bytes(int extraWords) {
......
...@@ -1621,6 +1621,10 @@ public: ...@@ -1621,6 +1621,10 @@ public:
void sub( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | rs2(s2) ); } void sub( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | rs2(s2) ); }
void sub( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } void sub( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// Note: offset is added to s2.
inline void sub(Register s1, RegisterOrConstant s2, Register d, int offset = 0);
void subcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | rs2(s2) ); } void subcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | rs2(s2) ); }
void subcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } void subcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
void subc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | rs2(s2) ); } void subc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | rs2(s2) ); }
...@@ -1895,6 +1899,9 @@ public: ...@@ -1895,6 +1899,9 @@ public:
void patchable_set(intptr_t value, Register d); void patchable_set(intptr_t value, Register d);
void set64(jlong value, Register d, Register tmp); void set64(jlong value, Register d, Register tmp);
// Compute size of set64.
static int size_of_set64(jlong value);
// sign-extend 32 to 64 // sign-extend 32 to 64
inline void signx( Register s, Register d ) { sra( s, G0, d); } inline void signx( Register s, Register d ) { sra( s, G0, d); }
inline void signx( Register d ) { sra( d, G0, d); } inline void signx( Register d ) { sra( d, G0, d); }
......
...@@ -328,6 +328,11 @@ inline void Assembler::stcsr( int crd, Register s1, int simm13a) { v8_only(); ...@@ -328,6 +328,11 @@ inline void Assembler::stcsr( int crd, Register s1, int simm13a) { v8_only();
inline void Assembler::stdcq( int crd, Register s1, Register s2) { v8_only(); emit_long( op(ldst_op) | fcn(crd) | op3(stdcq_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::stdcq( int crd, Register s1, Register s2) { v8_only(); emit_long( op(ldst_op) | fcn(crd) | op3(stdcq_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stdcq( int crd, Register s1, int simm13a) { v8_only(); emit_data( op(ldst_op) | fcn(crd) | op3(stdcq_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } inline void Assembler::stdcq( int crd, Register s1, int simm13a) { v8_only(); emit_data( op(ldst_op) | fcn(crd) | op3(stdcq_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::sub(Register s1, RegisterOrConstant s2, Register d, int offset) {
if (s2.is_register()) sub(s1, s2.as_register(), d);
else { sub(s1, s2.as_constant() + offset, d); offset = 0; }
if (offset != 0) sub(d, offset, d);
}
// pp 231 // pp 231
......
...@@ -667,6 +667,20 @@ intptr_t get_offset_from_base_2(const MachNode* n, const TypePtr* atype, int dis ...@@ -667,6 +667,20 @@ intptr_t get_offset_from_base_2(const MachNode* n, const TypePtr* atype, int dis
return offset; return offset;
} }
static inline jdouble replicate_immI(int con, int count, int width) {
// Load a constant replicated "count" times with width "width"
int bit_width = width * 8;
jlong elt_val = con;
elt_val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits
jlong val = elt_val;
for (int i = 0; i < count - 1; i++) {
val <<= bit_width;
val |= elt_val;
}
jdouble dval = *((jdouble*) &val); // coerce to double type
return dval;
}
// Standard Sparc opcode form2 field breakdown // Standard Sparc opcode form2 field breakdown
static inline void emit2_19(CodeBuffer &cbuf, int f30, int f29, int f25, int f22, int f20, int f19, int f0 ) { static inline void emit2_19(CodeBuffer &cbuf, int f30, int f29, int f25, int f22, int f20, int f19, int f0 ) {
f0 &= (1<<19)-1; // Mask displacement to 19 bits f0 &= (1<<19)-1; // Mask displacement to 19 bits
...@@ -1007,6 +1021,90 @@ void emit_lo(CodeBuffer &cbuf, int val) { } ...@@ -1007,6 +1021,90 @@ void emit_lo(CodeBuffer &cbuf, int val) { }
void emit_hi(CodeBuffer &cbuf, int val) { } void emit_hi(CodeBuffer &cbuf, int val) { }
//=============================================================================
const bool Matcher::constant_table_absolute_addressing = false;
const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask;
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
Compile* C = ra_->C;
Compile::ConstantTable& constant_table = C->constant_table();
MacroAssembler _masm(&cbuf);
Register r = as_Register(ra_->get_encode(this));
CodeSection* cs = __ code()->consts();
int consts_size = cs->align_at_start(cs->size());
if (UseRDPCForConstantTableBase) {
// For the following RDPC logic to work correctly the consts
// section must be allocated right before the insts section. This
// assert checks for that. The layout and the SECT_* constants
// are defined in src/share/vm/asm/codeBuffer.hpp.
assert(CodeBuffer::SECT_CONSTS + 1 == CodeBuffer::SECT_INSTS, "must be");
int offset = __ offset();
int disp;
// If the displacement from the current PC to the constant table
// base fits into simm13 we set the constant table base to the
// current PC.
if (__ is_simm13(-(consts_size + offset))) {
constant_table.set_table_base_offset(-(consts_size + offset));
disp = 0;
} else {
// If the offset of the top constant (last entry in the table)
// fits into simm13 we set the constant table base to the actual
// table base.
if (__ is_simm13(constant_table.top_offset())) {
constant_table.set_table_base_offset(0);
disp = consts_size + offset;
} else {
// Otherwise we set the constant table base in the middle of the
// constant table.
int half_consts_size = consts_size / 2;
assert(half_consts_size * 2 == consts_size, "sanity");
constant_table.set_table_base_offset(-half_consts_size); // table base offset gets added to the load displacement.
disp = half_consts_size + offset;
}
}
__ rdpc(r);
if (disp != 0) {
assert(r != O7, "need temporary");
__ sub(r, __ ensure_simm13_or_reg(disp, O7), r);
}
}
else {
// Materialize the constant table base.
assert(constant_table.size() == consts_size, err_msg("must be: %d == %d", constant_table.size(), consts_size));
address baseaddr = cs->start() + -(constant_table.table_base_offset());
RelocationHolder rspec = internal_word_Relocation::spec(baseaddr);
AddressLiteral base(baseaddr, rspec);
__ set(base, r);
}
}
uint MachConstantBaseNode::size(PhaseRegAlloc*) const {
if (UseRDPCForConstantTableBase) {
// This is really the worst case but generally it's only 1 instruction.
return 4 /*rdpc*/ + 4 /*sub*/ + MacroAssembler::worst_case_size_of_set();
} else {
return MacroAssembler::worst_case_size_of_set();
}
}
#ifndef PRODUCT
void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
char reg[128];
ra_->dump_register(this, reg);
if (UseRDPCForConstantTableBase) {
st->print("RDPC %s\t! constant table base", reg);
} else {
st->print("SET &constanttable,%s\t! constant table base", reg);
}
}
#endif
//============================================================================= //=============================================================================
#ifndef PRODUCT #ifndef PRODUCT
...@@ -2247,25 +2345,6 @@ encode %{ ...@@ -2247,25 +2345,6 @@ encode %{
__ delayed()->nop(); __ delayed()->nop();
%} %}
enc_class jump_enc( iRegX switch_val, o7RegI table) %{
MacroAssembler _masm(&cbuf);
Register switch_reg = as_Register($switch_val$$reg);
Register table_reg = O7;
address table_base = __ address_table_constant(_index2label);
RelocationHolder rspec = internal_word_Relocation::spec(table_base);
// Move table address into a register.
__ set(table_base, table_reg, rspec);
// Jump to base address + switch value
__ ld_ptr(table_reg, switch_reg, table_reg);
__ jmp(table_reg, G0);
__ delayed()->nop();
%}
enc_class enc_ba( Label labl ) %{ enc_class enc_ba( Label labl ) %{
MacroAssembler _masm(&cbuf); MacroAssembler _masm(&cbuf);
Label &L = *($labl$$label); Label &L = *($labl$$label);
...@@ -2384,20 +2463,6 @@ encode %{ ...@@ -2384,20 +2463,6 @@ encode %{
cbuf.insts()->emit_int32(op); cbuf.insts()->emit_int32(op);
%} %}
// Utility encoding for loading a 64 bit Pointer into a register
// The 64 bit pointer is stored in the generated code stream
enc_class SetPtr( immP src, iRegP rd ) %{
Register dest = reg_to_register_object($rd$$reg);
MacroAssembler _masm(&cbuf);
// [RGV] This next line should be generated from ADLC
if ( _opnds[1]->constant_is_oop() ) {
intptr_t val = $src$$constant;
__ set_oop_constant((jobject)val, dest);
} else { // non-oop pointers, e.g. card mark base, heap top
__ set($src$$constant, dest);
}
%}
enc_class Set13( immI13 src, iRegI rd ) %{ enc_class Set13( immI13 src, iRegI rd ) %{
emit3_simm13( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, $src$$constant ); emit3_simm13( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, $src$$constant );
%} %}
...@@ -2411,10 +2476,6 @@ encode %{ ...@@ -2411,10 +2476,6 @@ encode %{
__ set($src$$constant, reg_to_register_object($rd$$reg)); __ set($src$$constant, reg_to_register_object($rd$$reg));
%} %}
enc_class SetNull( iRegI rd ) %{
emit3_simm13( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, 0 );
%}
enc_class call_epilog %{ enc_class call_epilog %{
if( VerifyStackAtCalls ) { if( VerifyStackAtCalls ) {
MacroAssembler _masm(&cbuf); MacroAssembler _masm(&cbuf);
...@@ -2778,35 +2839,6 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{ ...@@ -2778,35 +2839,6 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
__ float_cmp( $primary, -1, Fsrc1, Fsrc2, Rdst); __ float_cmp( $primary, -1, Fsrc1, Fsrc2, Rdst);
%} %}
enc_class LdImmL (immL src, iRegL dst, o7RegL tmp) %{ // Load Immediate
MacroAssembler _masm(&cbuf);
Register dest = reg_to_register_object($dst$$reg);
Register temp = reg_to_register_object($tmp$$reg);
__ set64( $src$$constant, dest, temp );
%}
enc_class LdReplImmI(immI src, regD dst, o7RegP tmp, int count, int width) %{
// Load a constant replicated "count" times with width "width"
int bit_width = $width$$constant * 8;
jlong elt_val = $src$$constant;
elt_val &= (((jlong)1) << bit_width) - 1; // mask off sign bits
jlong val = elt_val;
for (int i = 0; i < $count$$constant - 1; i++) {
val <<= bit_width;
val |= elt_val;
}
jdouble dval = *(jdouble*)&val; // coerce to double type
MacroAssembler _masm(&cbuf);
address double_address = __ double_constant(dval);
RelocationHolder rspec = internal_word_Relocation::spec(double_address);
AddressLiteral addrlit(double_address, rspec);
__ sethi(addrlit, $tmp$$Register);
// XXX This is a quick fix for 6833573.
//__ ldf(FloatRegisterImpl::D, $tmp$$Register, addrlit.low10(), $dst$$FloatRegister, rspec);
__ ldf(FloatRegisterImpl::D, $tmp$$Register, addrlit.low10(), as_DoubleFloatRegister($dst$$reg), rspec);
%}
// Compiler ensures base is doubleword aligned and cnt is count of doublewords // Compiler ensures base is doubleword aligned and cnt is count of doublewords
enc_class enc_Clear_Array(iRegX cnt, iRegP base, iRegX temp) %{ enc_class enc_Clear_Array(iRegX cnt, iRegP base, iRegX temp) %{
MacroAssembler _masm(&cbuf); MacroAssembler _masm(&cbuf);
...@@ -3521,6 +3553,29 @@ operand immP() %{ ...@@ -3521,6 +3553,29 @@ operand immP() %{
interface(CONST_INTER); interface(CONST_INTER);
%} %}
// Pointer Immediate: 32 or 64-bit
operand immP_set() %{
predicate(!VM_Version::is_niagara1_plus());
match(ConP);
op_cost(5);
// formats are generated automatically for constants and base registers
format %{ %}
interface(CONST_INTER);
%}
// Pointer Immediate: 32 or 64-bit
// From Niagara2 processors on a load should be better than materializing.
operand immP_load() %{
predicate(VM_Version::is_niagara1_plus());
match(ConP);
op_cost(5);
// formats are generated automatically for constants and base registers
format %{ %}
interface(CONST_INTER);
%}
operand immP13() %{ operand immP13() %{
predicate((-4096 < n->get_ptr()) && (n->get_ptr() <= 4095)); predicate((-4096 < n->get_ptr()) && (n->get_ptr() <= 4095));
match(ConP); match(ConP);
...@@ -3616,6 +3671,26 @@ operand immL_32bits() %{ ...@@ -3616,6 +3671,26 @@ operand immL_32bits() %{
interface(CONST_INTER); interface(CONST_INTER);
%} %}
// Long Immediate: cheap (materialize in <= 3 instructions)
operand immL_cheap() %{
predicate(!VM_Version::is_niagara1_plus() || MacroAssembler::size_of_set64(n->get_long()) <= 3);
match(ConL);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Long Immediate: expensive (materialize in > 3 instructions)
operand immL_expensive() %{
predicate(VM_Version::is_niagara1_plus() && MacroAssembler::size_of_set64(n->get_long()) > 3);
match(ConL);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}
// Double Immediate // Double Immediate
operand immD() %{ operand immD() %{
match(ConD); match(ConD);
...@@ -5981,25 +6056,58 @@ instruct loadConI13( iRegI dst, immI13 src ) %{ ...@@ -5981,25 +6056,58 @@ instruct loadConI13( iRegI dst, immI13 src ) %{
ins_pipe(ialu_imm); ins_pipe(ialu_imm);
%} %}
instruct loadConP(iRegP dst, immP src) %{ #ifndef _LP64
match(Set dst src); instruct loadConP(iRegP dst, immP con) %{
match(Set dst con);
ins_cost(DEFAULT_COST * 3/2); ins_cost(DEFAULT_COST * 3/2);
format %{ "SET $src,$dst\t!ptr" %} format %{ "SET $con,$dst\t!ptr" %}
// This rule does not use "expand" unlike loadConI because then ins_encode %{
// the result type is not known to be an Oop. An ADLC // [RGV] This next line should be generated from ADLC
// enhancement will be needed to make that work - not worth it! if (_opnds[1]->constant_is_oop()) {
intptr_t val = $con$$constant;
ins_encode( SetPtr( src, dst ) ); __ set_oop_constant((jobject) val, $dst$$Register);
} else { // non-oop pointers, e.g. card mark base, heap top
__ set($con$$constant, $dst$$Register);
}
%}
ins_pipe(loadConP);
%}
#else
instruct loadConP_set(iRegP dst, immP_set con) %{
match(Set dst con);
ins_cost(DEFAULT_COST * 3/2);
format %{ "SET $con,$dst\t! ptr" %}
ins_encode %{
// [RGV] This next line should be generated from ADLC
if (_opnds[1]->constant_is_oop()) {
intptr_t val = $con$$constant;
__ set_oop_constant((jobject) val, $dst$$Register);
} else { // non-oop pointers, e.g. card mark base, heap top
__ set($con$$constant, $dst$$Register);
}
%}
ins_pipe(loadConP); ins_pipe(loadConP);
%}
instruct loadConP_load(iRegP dst, immP_load con) %{
match(Set dst con);
ins_cost(MEMORY_REF_COST);
format %{ "LD [$constanttablebase + $constantoffset],$dst\t! load from constant table: ptr=$con" %}
ins_encode %{
__ ld_ptr($constanttablebase, $constantoffset($con), $dst$$Register);
%}
ins_pipe(loadConP);
%} %}
#endif // _LP64
instruct loadConP0(iRegP dst, immP0 src) %{ instruct loadConP0(iRegP dst, immP0 src) %{
match(Set dst src); match(Set dst src);
size(4); size(4);
format %{ "CLR $dst\t!ptr" %} format %{ "CLR $dst\t!ptr" %}
ins_encode( SetNull( dst ) ); ins_encode %{
__ clr($dst$$Register);
%}
ins_pipe(ialu_imm); ins_pipe(ialu_imm);
%} %}
...@@ -6019,7 +6127,9 @@ instruct loadConN0(iRegN dst, immN0 src) %{ ...@@ -6019,7 +6127,9 @@ instruct loadConN0(iRegN dst, immN0 src) %{
size(4); size(4);
format %{ "CLR $dst\t! compressed NULL ptr" %} format %{ "CLR $dst\t! compressed NULL ptr" %}
ins_encode( SetNull( dst ) ); ins_encode %{
__ clr($dst$$Register);
%}
ins_pipe(ialu_imm); ins_pipe(ialu_imm);
%} %}
...@@ -6034,13 +6144,26 @@ instruct loadConN(iRegN dst, immN src) %{ ...@@ -6034,13 +6144,26 @@ instruct loadConN(iRegN dst, immN src) %{
ins_pipe(ialu_hi_lo_reg); ins_pipe(ialu_hi_lo_reg);
%} %}
instruct loadConL(iRegL dst, immL src, o7RegL tmp) %{ // Materialize long value (predicated by immL_cheap).
// %%% maybe this should work like loadConD instruct loadConL_set64(iRegL dst, immL_cheap con, o7RegL tmp) %{
match(Set dst src); match(Set dst con);
effect(KILL tmp); effect(KILL tmp);
ins_cost(DEFAULT_COST * 4); ins_cost(DEFAULT_COST * 3);
format %{ "SET64 $src,$dst KILL $tmp\t! long" %} format %{ "SET64 $con,$dst KILL $tmp\t! cheap long" %}
ins_encode( LdImmL(src, dst, tmp) ); ins_encode %{
__ set64($con$$constant, $dst$$Register, $tmp$$Register);
%}
ins_pipe(loadConL);
%}
// Load long value from constant table (predicated by immL_expensive).
instruct loadConL_ldx(iRegL dst, immL_expensive con) %{
match(Set dst con);
ins_cost(MEMORY_REF_COST);
format %{ "LDX [$constanttablebase + $constantoffset],$dst\t! load from constant table: long=$con" %}
ins_encode %{
__ ldx($constanttablebase, $constantoffset($con), $dst$$Register);
%}
ins_pipe(loadConL); ins_pipe(loadConL);
%} %}
...@@ -6063,50 +6186,24 @@ instruct loadConL13( iRegL dst, immL13 src ) %{ ...@@ -6063,50 +6186,24 @@ instruct loadConL13( iRegL dst, immL13 src ) %{
ins_pipe(ialu_imm); ins_pipe(ialu_imm);
%} %}
instruct loadConF(regF dst, immF src, o7RegP tmp) %{ instruct loadConF(regF dst, immF con) %{
match(Set dst src); match(Set dst con);
effect(KILL tmp); size(4);
format %{ "LDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: float=$con" %}
#ifdef _LP64
size(8*4);
#else
size(2*4);
#endif
format %{ "SETHI hi(&$src),$tmp\t!get float $src from table\n\t"
"LDF [$tmp+lo(&$src)],$dst" %}
ins_encode %{ ins_encode %{
address float_address = __ float_constant($src$$constant); __ ldf(FloatRegisterImpl::S, $constanttablebase, $constantoffset($con), $dst$$FloatRegister);
RelocationHolder rspec = internal_word_Relocation::spec(float_address);
AddressLiteral addrlit(float_address, rspec);
__ sethi(addrlit, $tmp$$Register);
__ ldf(FloatRegisterImpl::S, $tmp$$Register, addrlit.low10(), $dst$$FloatRegister, rspec);
%} %}
ins_pipe(loadConFD); ins_pipe(loadConFD);
%} %}
instruct loadConD(regD dst, immD src, o7RegP tmp) %{ instruct loadConD(regD dst, immD con) %{
match(Set dst src); match(Set dst con);
effect(KILL tmp); size(4);
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: double=$con" %}
#ifdef _LP64
size(8*4);
#else
size(2*4);
#endif
format %{ "SETHI hi(&$src),$tmp\t!get double $src from table\n\t"
"LDDF [$tmp+lo(&$src)],$dst" %}
ins_encode %{ ins_encode %{
address double_address = __ double_constant($src$$constant);
RelocationHolder rspec = internal_word_Relocation::spec(double_address);
AddressLiteral addrlit(double_address, rspec);
__ sethi(addrlit, $tmp$$Register);
// XXX This is a quick fix for 6833573. // XXX This is a quick fix for 6833573.
//__ ldf(FloatRegisterImpl::D, $tmp$$Register, addrlit.low10(), $dst$$FloatRegister, rspec); //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset($con), $dst$$FloatRegister);
__ ldf(FloatRegisterImpl::D, $tmp$$Register, addrlit.low10(), as_DoubleFloatRegister($dst$$reg), rspec); __ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset($con), as_DoubleFloatRegister($dst$$reg));
%} %}
ins_pipe(loadConFD); ins_pipe(loadConFD);
%} %}
...@@ -8558,16 +8655,15 @@ instruct Repl8B_reg(stackSlotD dst, iRegI src) %{ ...@@ -8558,16 +8655,15 @@ instruct Repl8B_reg(stackSlotD dst, iRegI src) %{
%} %}
// Replicate scalar constant to packed byte values in Double register // Replicate scalar constant to packed byte values in Double register
instruct Repl8B_immI(regD dst, immI13 src, o7RegP tmp) %{ instruct Repl8B_immI(regD dst, immI13 con) %{
match(Set dst (Replicate8B src)); match(Set dst (Replicate8B con));
#ifdef _LP64 size(4);
size(36); format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl8B($con)" %}
#else ins_encode %{
size(8); // XXX This is a quick fix for 6833573.
#endif //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 8, 1)), $dst$$FloatRegister);
format %{ "SETHI hi(&Repl8($src)),$tmp\t!get Repl8B($src) from table\n\t" __ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 8, 1)), as_DoubleFloatRegister($dst$$reg));
"LDDF [$tmp+lo(&Repl8($src))],$dst" %} %}
ins_encode( LdReplImmI(src, dst, tmp, (8), (1)) );
ins_pipe(loadConFD); ins_pipe(loadConFD);
%} %}
...@@ -8594,16 +8690,15 @@ instruct Repl4C_reg(stackSlotD dst, iRegI src) %{ ...@@ -8594,16 +8690,15 @@ instruct Repl4C_reg(stackSlotD dst, iRegI src) %{
%} %}
// Replicate scalar constant to packed char values in Double register // Replicate scalar constant to packed char values in Double register
instruct Repl4C_immI(regD dst, immI src, o7RegP tmp) %{ instruct Repl4C_immI(regD dst, immI con) %{
match(Set dst (Replicate4C src)); match(Set dst (Replicate4C con));
#ifdef _LP64 size(4);
size(36); format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4C($con)" %}
#else ins_encode %{
size(8); // XXX This is a quick fix for 6833573.
#endif //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
format %{ "SETHI hi(&Repl4($src)),$tmp\t!get Repl4C($src) from table\n\t" __ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), as_DoubleFloatRegister($dst$$reg));
"LDDF [$tmp+lo(&Repl4($src))],$dst" %} %}
ins_encode( LdReplImmI(src, dst, tmp, (4), (2)) );
ins_pipe(loadConFD); ins_pipe(loadConFD);
%} %}
...@@ -8630,16 +8725,15 @@ instruct Repl4S_reg(stackSlotD dst, iRegI src) %{ ...@@ -8630,16 +8725,15 @@ instruct Repl4S_reg(stackSlotD dst, iRegI src) %{
%} %}
// Replicate scalar constant to packed short values in Double register // Replicate scalar constant to packed short values in Double register
instruct Repl4S_immI(regD dst, immI src, o7RegP tmp) %{ instruct Repl4S_immI(regD dst, immI con) %{
match(Set dst (Replicate4S src)); match(Set dst (Replicate4S con));
#ifdef _LP64 size(4);
size(36); format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4S($con)" %}
#else ins_encode %{
size(8); // XXX This is a quick fix for 6833573.
#endif //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
format %{ "SETHI hi(&Repl4($src)),$tmp\t!get Repl4S($src) from table\n\t" __ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), as_DoubleFloatRegister($dst$$reg));
"LDDF [$tmp+lo(&Repl4($src))],$dst" %} %}
ins_encode( LdReplImmI(src, dst, tmp, (4), (2)) );
ins_pipe(loadConFD); ins_pipe(loadConFD);
%} %}
...@@ -8664,16 +8758,15 @@ instruct Repl2I_reg(stackSlotD dst, iRegI src) %{ ...@@ -8664,16 +8758,15 @@ instruct Repl2I_reg(stackSlotD dst, iRegI src) %{
%} %}
// Replicate scalar zero constant to packed int values in Double register // Replicate scalar zero constant to packed int values in Double register
instruct Repl2I_immI(regD dst, immI src, o7RegP tmp) %{ instruct Repl2I_immI(regD dst, immI con) %{
match(Set dst (Replicate2I src)); match(Set dst (Replicate2I con));
#ifdef _LP64 size(4);
size(36); format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2I($con)" %}
#else ins_encode %{
size(8); // XXX This is a quick fix for 6833573.
#endif //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 2, 4)), $dst$$FloatRegister);
format %{ "SETHI hi(&Repl2($src)),$tmp\t!get Repl2I($src) from table\n\t" __ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 2, 4)), as_DoubleFloatRegister($dst$$reg));
"LDDF [$tmp+lo(&Repl2($src))],$dst" %} %}
ins_encode( LdReplImmI(src, dst, tmp, (2), (4)) );
ins_pipe(loadConFD); ins_pipe(loadConFD);
%} %}
...@@ -8929,12 +9022,26 @@ instruct jumpXtnd(iRegX switch_val, o7RegI table) %{ ...@@ -8929,12 +9022,26 @@ instruct jumpXtnd(iRegX switch_val, o7RegI table) %{
ins_cost(350); ins_cost(350);
format %{ "SETHI [hi(table_base)],O7\n\t" format %{ "ADD $constanttablebase, $constantoffset, O7\n\t"
"ADD O7, lo(table_base), O7\n\t" "LD [O7 + $switch_val], O7\n\t"
"LD [O7+$switch_val], O7\n\t"
"JUMP O7" "JUMP O7"
%} %}
ins_encode( jump_enc( switch_val, table) ); ins_encode %{
// Calculate table address into a register.
Register table_reg;
Register label_reg = O7;
if (constant_offset() == 0) {
table_reg = $constanttablebase;
} else {
table_reg = O7;
__ add($constanttablebase, $constantoffset, table_reg);
}
// Jump to base address + switch value
__ ld_ptr(table_reg, $switch_val$$Register, label_reg);
__ jmp(label_reg, G0);
__ delayed()->nop();
%}
ins_pc_relative(1); ins_pc_relative(1);
ins_pipe(ialu_reg_reg); ins_pipe(ialu_reg_reg);
%} %}
......
...@@ -80,9 +80,6 @@ protected: ...@@ -80,9 +80,6 @@ protected:
static bool is_sparc64(int features) { return (features & fmaf_instructions_m) != 0; } static bool is_sparc64(int features) { return (features & fmaf_instructions_m) != 0; }
static int maximum_niagara1_processor_count() { return 32; } static int maximum_niagara1_processor_count() { return 32; }
// Returns true if the platform is in the niagara line and
// newer than the niagara1.
static bool is_niagara1_plus();
public: public:
// Initialization // Initialization
...@@ -105,6 +102,9 @@ public: ...@@ -105,6 +102,9 @@ public:
static bool is_ultra3() { return (_features & ultra3_m) == ultra3_m; } static bool is_ultra3() { return (_features & ultra3_m) == ultra3_m; }
static bool is_sun4v() { return (_features & sun4v_m) != 0; } static bool is_sun4v() { return (_features & sun4v_m) != 0; }
static bool is_niagara1() { return is_niagara1(_features); } static bool is_niagara1() { return is_niagara1(_features); }
// Returns true if the platform is in the niagara line and
// newer than the niagara1.
static bool is_niagara1_plus();
static bool is_sparc64() { return is_sparc64(_features); } static bool is_sparc64() { return is_sparc64(_features); }
static bool has_fast_fxtof() { return has_v9() && !is_ultra3(); } static bool has_fast_fxtof() { return has_v9() && !is_ultra3(); }
......
...@@ -2649,6 +2649,37 @@ void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) { ...@@ -2649,6 +2649,37 @@ void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
emit_byte(0xC0 | encode); emit_byte(0xC0 | encode);
} }
void Assembler::sqrtsd(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
emit_byte(0xF2);
prefix(src, dst);
emit_byte(0x0F);
emit_byte(0x51);
emit_operand(dst, src);
}
void Assembler::sqrtss(XMMRegister dst, XMMRegister src) {
// HMM Table D-1 says sse2
// NOT_LP64(assert(VM_Version::supports_sse(), ""));
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
emit_byte(0xF3);
int encode = prefix_and_encode(dst->encoding(), src->encoding());
emit_byte(0x0F);
emit_byte(0x51);
emit_byte(0xC0 | encode);
}
void Assembler::sqrtss(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
emit_byte(0xF3);
prefix(src, dst);
emit_byte(0x0F);
emit_byte(0x51);
emit_operand(dst, src);
}
void Assembler::stmxcsr( Address dst) { void Assembler::stmxcsr( Address dst) {
NOT_LP64(assert(VM_Version::supports_sse(), "")); NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this); InstructionMark im(this);
...@@ -4358,16 +4389,6 @@ void Assembler::shrq(Register dst) { ...@@ -4358,16 +4389,6 @@ void Assembler::shrq(Register dst) {
emit_byte(0xE8 | encode); emit_byte(0xE8 | encode);
} }
void Assembler::sqrtsd(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
emit_byte(0xF2);
prefix(src, dst);
emit_byte(0x0F);
emit_byte(0x51);
emit_operand(dst, src);
}
void Assembler::subq(Address dst, int32_t imm32) { void Assembler::subq(Address dst, int32_t imm32) {
InstructionMark im(this); InstructionMark im(this);
prefixq(dst); prefixq(dst);
...@@ -4929,10 +4950,6 @@ void MacroAssembler::movptr(Address dst, intptr_t src) { ...@@ -4929,10 +4950,6 @@ void MacroAssembler::movptr(Address dst, intptr_t src) {
} }
void MacroAssembler::movsd(XMMRegister dst, AddressLiteral src) {
movsd(dst, as_Address(src));
}
void MacroAssembler::pop_callee_saved_registers() { void MacroAssembler::pop_callee_saved_registers() {
pop(rcx); pop(rcx);
pop(rdx); pop(rdx);
......
...@@ -1353,6 +1353,10 @@ private: ...@@ -1353,6 +1353,10 @@ private:
void sqrtsd(XMMRegister dst, Address src); void sqrtsd(XMMRegister dst, Address src);
void sqrtsd(XMMRegister dst, XMMRegister src); void sqrtsd(XMMRegister dst, XMMRegister src);
// Compute Square Root of Scalar Single-Precision Floating-Point Value
void sqrtss(XMMRegister dst, Address src);
void sqrtss(XMMRegister dst, XMMRegister src);
void std() { emit_byte(0xfd); } void std() { emit_byte(0xfd); }
void stmxcsr( Address dst ); void stmxcsr( Address dst );
...@@ -2125,6 +2129,9 @@ class MacroAssembler: public Assembler { ...@@ -2125,6 +2129,9 @@ class MacroAssembler: public Assembler {
void comisd(XMMRegister dst, Address src) { Assembler::comisd(dst, src); } void comisd(XMMRegister dst, Address src) { Assembler::comisd(dst, src); }
void comisd(XMMRegister dst, AddressLiteral src); void comisd(XMMRegister dst, AddressLiteral src);
void fadd_s(Address src) { Assembler::fadd_s(src); }
void fadd_s(AddressLiteral src) { Assembler::fadd_s(as_Address(src)); }
void fldcw(Address src) { Assembler::fldcw(src); } void fldcw(Address src) { Assembler::fldcw(src); }
void fldcw(AddressLiteral src); void fldcw(AddressLiteral src);
...@@ -2138,6 +2145,9 @@ class MacroAssembler: public Assembler { ...@@ -2138,6 +2145,9 @@ class MacroAssembler: public Assembler {
void fld_x(Address src) { Assembler::fld_x(src); } void fld_x(Address src) { Assembler::fld_x(src); }
void fld_x(AddressLiteral src); void fld_x(AddressLiteral src);
void fmul_s(Address src) { Assembler::fmul_s(src); }
void fmul_s(AddressLiteral src) { Assembler::fmul_s(as_Address(src)); }
void ldmxcsr(Address src) { Assembler::ldmxcsr(src); } void ldmxcsr(Address src) { Assembler::ldmxcsr(src); }
void ldmxcsr(AddressLiteral src); void ldmxcsr(AddressLiteral src);
...@@ -2154,10 +2164,50 @@ private: ...@@ -2154,10 +2164,50 @@ private:
public: public:
void movsd(XMMRegister dst, XMMRegister src) { Assembler::movsd(dst, src); } void addsd(XMMRegister dst, XMMRegister src) { Assembler::addsd(dst, src); }
void movsd(Address dst, XMMRegister src) { Assembler::movsd(dst, src); } void addsd(XMMRegister dst, Address src) { Assembler::addsd(dst, src); }
void movsd(XMMRegister dst, Address src) { Assembler::movsd(dst, src); } void addsd(XMMRegister dst, AddressLiteral src) { Assembler::addsd(dst, as_Address(src)); }
void movsd(XMMRegister dst, AddressLiteral src);
void addss(XMMRegister dst, XMMRegister src) { Assembler::addss(dst, src); }
void addss(XMMRegister dst, Address src) { Assembler::addss(dst, src); }
void addss(XMMRegister dst, AddressLiteral src) { Assembler::addss(dst, as_Address(src)); }
void divsd(XMMRegister dst, XMMRegister src) { Assembler::divsd(dst, src); }
void divsd(XMMRegister dst, Address src) { Assembler::divsd(dst, src); }
void divsd(XMMRegister dst, AddressLiteral src) { Assembler::divsd(dst, as_Address(src)); }
void divss(XMMRegister dst, XMMRegister src) { Assembler::divss(dst, src); }
void divss(XMMRegister dst, Address src) { Assembler::divss(dst, src); }
void divss(XMMRegister dst, AddressLiteral src) { Assembler::divss(dst, as_Address(src)); }
void movsd(XMMRegister dst, XMMRegister src) { Assembler::movsd(dst, src); }
void movsd(Address dst, XMMRegister src) { Assembler::movsd(dst, src); }
void movsd(XMMRegister dst, Address src) { Assembler::movsd(dst, src); }
void movsd(XMMRegister dst, AddressLiteral src) { Assembler::movsd(dst, as_Address(src)); }
void mulsd(XMMRegister dst, XMMRegister src) { Assembler::mulsd(dst, src); }
void mulsd(XMMRegister dst, Address src) { Assembler::mulsd(dst, src); }
void mulsd(XMMRegister dst, AddressLiteral src) { Assembler::mulsd(dst, as_Address(src)); }
void mulss(XMMRegister dst, XMMRegister src) { Assembler::mulss(dst, src); }
void mulss(XMMRegister dst, Address src) { Assembler::mulss(dst, src); }
void mulss(XMMRegister dst, AddressLiteral src) { Assembler::mulss(dst, as_Address(src)); }
void sqrtsd(XMMRegister dst, XMMRegister src) { Assembler::sqrtsd(dst, src); }
void sqrtsd(XMMRegister dst, Address src) { Assembler::sqrtsd(dst, src); }
void sqrtsd(XMMRegister dst, AddressLiteral src) { Assembler::sqrtsd(dst, as_Address(src)); }
void sqrtss(XMMRegister dst, XMMRegister src) { Assembler::sqrtss(dst, src); }
void sqrtss(XMMRegister dst, Address src) { Assembler::sqrtss(dst, src); }
void sqrtss(XMMRegister dst, AddressLiteral src) { Assembler::sqrtss(dst, as_Address(src)); }
void subsd(XMMRegister dst, XMMRegister src) { Assembler::subsd(dst, src); }
void subsd(XMMRegister dst, Address src) { Assembler::subsd(dst, src); }
void subsd(XMMRegister dst, AddressLiteral src) { Assembler::subsd(dst, as_Address(src)); }
void subss(XMMRegister dst, XMMRegister src) { Assembler::subss(dst, src); }
void subss(XMMRegister dst, Address src) { Assembler::subss(dst, src); }
void subss(XMMRegister dst, AddressLiteral src) { Assembler::subss(dst, as_Address(src)); }
void ucomiss(XMMRegister dst, XMMRegister src) { Assembler::ucomiss(dst, src); } void ucomiss(XMMRegister dst, XMMRegister src) { Assembler::ucomiss(dst, src); }
void ucomiss(XMMRegister dst, Address src) { Assembler::ucomiss(dst, src); } void ucomiss(XMMRegister dst, Address src) { Assembler::ucomiss(dst, src); }
......
此差异已折叠。
此差异已折叠。
...@@ -44,11 +44,11 @@ void VMError::show_message_box(char *buf, int buflen) { ...@@ -44,11 +44,11 @@ void VMError::show_message_box(char *buf, int buflen) {
jio_snprintf(p, buflen - len, jio_snprintf(p, buflen - len,
"\n\n" "\n\n"
"Do you want to debug the problem?\n\n" "Do you want to debug the problem?\n\n"
"To debug, run 'gdb /proc/%d/exe %d'; then switch to thread " INTX_FORMAT "\n" "To debug, run 'gdb /proc/%d/exe %d'; then switch to thread " INTX_FORMAT " (" INTPTR_FORMAT ")\n"
"Enter 'yes' to launch gdb automatically (PATH must include gdb)\n" "Enter 'yes' to launch gdb automatically (PATH must include gdb)\n"
"Otherwise, press RETURN to abort...", "Otherwise, press RETURN to abort...",
os::current_process_id(), os::current_process_id(), os::current_process_id(), os::current_process_id(),
os::current_thread_id()); os::current_thread_id(), os::current_thread_id());
yes = os::message_box("Unexpected Error", buf); yes = os::message_box("Unexpected Error", buf);
......
...@@ -95,7 +95,7 @@ void ADLParser::parse() { ...@@ -95,7 +95,7 @@ void ADLParser::parse() {
if (ident == NULL) { // Empty line if (ident == NULL) { // Empty line
continue; // Get the next line continue; // Get the next line
} }
if (!strcmp(ident, "instruct")) instr_parse(); if (!strcmp(ident, "instruct")) instr_parse();
else if (!strcmp(ident, "operand")) oper_parse(); else if (!strcmp(ident, "operand")) oper_parse();
else if (!strcmp(ident, "opclass")) opclass_parse(); else if (!strcmp(ident, "opclass")) opclass_parse();
else if (!strcmp(ident, "ins_attrib")) ins_attr_parse(); else if (!strcmp(ident, "ins_attrib")) ins_attr_parse();
...@@ -216,24 +216,23 @@ void ADLParser::instr_parse(void) { ...@@ -216,24 +216,23 @@ void ADLParser::instr_parse(void) {
else if (!strcmp(ident, "encode")) { else if (!strcmp(ident, "encode")) {
parse_err(SYNERR, "Instructions specify ins_encode, not encode\n"); parse_err(SYNERR, "Instructions specify ins_encode, not encode\n");
} }
else if (!strcmp(ident, "ins_encode")) else if (!strcmp(ident, "ins_encode")) ins_encode_parse(*instr);
instr->_insencode = ins_encode_parse(*instr); else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr);
else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr); else if (!strcmp(ident, "size")) instr->_size = size_parse(instr);
else if (!strcmp(ident, "size")) instr->_size = size_parse(instr); else if (!strcmp(ident, "effect")) effect_parse(instr);
else if (!strcmp(ident, "effect")) effect_parse(instr); else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr);
else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr); else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse();
else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse();
else if (!strcmp(ident, "constraint")) { else if (!strcmp(ident, "constraint")) {
parse_err(SYNERR, "Instructions do not specify a constraint\n"); parse_err(SYNERR, "Instructions do not specify a constraint\n");
} }
else if (!strcmp(ident, "construct")) { else if (!strcmp(ident, "construct")) {
parse_err(SYNERR, "Instructions do not specify a construct\n"); parse_err(SYNERR, "Instructions do not specify a construct\n");
} }
else if (!strcmp(ident, "format")) instr->_format = format_parse(); else if (!strcmp(ident, "format")) instr->_format = format_parse();
else if (!strcmp(ident, "interface")) { else if (!strcmp(ident, "interface")) {
parse_err(SYNERR, "Instructions do not specify an interface\n"); parse_err(SYNERR, "Instructions do not specify an interface\n");
} }
else if (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr); else if (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr);
else { // Done with staticly defined parts of instruction definition else { // Done with staticly defined parts of instruction definition
// Check identifier to see if it is the name of an attribute // Check identifier to see if it is the name of an attribute
const Form *form = _globalNames[ident]; const Form *form = _globalNames[ident];
...@@ -323,7 +322,8 @@ void ADLParser::adjust_set_rule(InstructForm *instr) { ...@@ -323,7 +322,8 @@ void ADLParser::adjust_set_rule(InstructForm *instr) {
const char *optype2 = NULL; const char *optype2 = NULL;
// Can not have additional base operands in right side of match! // Can not have additional base operands in right side of match!
if ( ! right->base_operand( position, _globalNames, result2, name2, optype2) ) { if ( ! right->base_operand( position, _globalNames, result2, name2, optype2) ) {
assert( instr->_predicate == NULL, "ADLC does not support instruction chain rules with predicates"); if (instr->_predicate != NULL)
parse_err(SYNERR, "ADLC does not support instruction chain rules with predicates");
// Chain from input _ideal_operand_type_, // Chain from input _ideal_operand_type_,
// Needed for shared roots of match-trees // Needed for shared roots of match-trees
ChainList *lst = (ChainList *)_AD._chainRules[optype]; ChainList *lst = (ChainList *)_AD._chainRules[optype];
...@@ -935,9 +935,9 @@ void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) { ...@@ -935,9 +935,9 @@ void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) {
// (2) // (2)
// If we are at a replacement variable, // If we are at a replacement variable,
// copy it and record in EncClass // copy it and record in EncClass
if ( _curchar == '$' ) { if (_curchar == '$') {
// Found replacement Variable // Found replacement Variable
char *rep_var = get_rep_var_ident_dup(); char* rep_var = get_rep_var_ident_dup();
// Add flag to _strings list indicating we should check _rep_vars // Add flag to _strings list indicating we should check _rep_vars
encoding->add_rep_var(rep_var); encoding->add_rep_var(rep_var);
} }
...@@ -2774,47 +2774,122 @@ Predicate *ADLParser::pred_parse(void) { ...@@ -2774,47 +2774,122 @@ Predicate *ADLParser::pred_parse(void) {
//------------------------------ins_encode_parse_block------------------------- //------------------------------ins_encode_parse_block-------------------------
// Parse the block form of ins_encode. See ins_encode_parse for more details // Parse the block form of ins_encode. See ins_encode_parse for more details
InsEncode *ADLParser::ins_encode_parse_block(InstructForm &inst) { void ADLParser::ins_encode_parse_block(InstructForm& inst) {
// Create a new encoding name based on the name of the instruction // Create a new encoding name based on the name of the instruction
// definition, which should be unique. // definition, which should be unique.
const char * prefix = "__enc_"; const char* prefix = "__ins_encode_";
char* ec_name = (char*)malloc(strlen(inst._ident) + strlen(prefix) + 1); char* ec_name = (char*) malloc(strlen(inst._ident) + strlen(prefix) + 1);
sprintf(ec_name, "%s%s", prefix, inst._ident); sprintf(ec_name, "%s%s", prefix, inst._ident);
assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"); assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");
EncClass *encoding = _AD._encode->add_EncClass(ec_name); EncClass* encoding = _AD._encode->add_EncClass(ec_name);
encoding->_linenum = linenum(); encoding->_linenum = linenum();
// synthesize the arguments list for the enc_class from the // synthesize the arguments list for the enc_class from the
// arguments to the instruct definition. // arguments to the instruct definition.
const char * param = NULL; const char* param = NULL;
inst._parameters.reset(); inst._parameters.reset();
while ((param = inst._parameters.iter()) != NULL) { while ((param = inst._parameters.iter()) != NULL) {
OperandForm *opForm = (OperandForm*)inst._localNames[param]; OperandForm* opForm = (OperandForm*) inst._localNames[param];
encoding->add_parameter(opForm->_ident, param); encoding->add_parameter(opForm->_ident, param);
} }
// Add the prologue to create the MacroAssembler // Define a MacroAssembler instance for use by the encoding. The
encoding->add_code("\n" // name is chosen to match the __ idiom used for assembly in other
" // Define a MacroAssembler instance for use by the encoding. The\n" // parts of hotspot and assumes the existence of the standard
" // name is chosen to match the __ idiom used for assembly in other\n" // #define __ _masm.
" // parts of hotspot and assumes the existence of the standard\n" encoding->add_code(" MacroAssembler _masm(&cbuf);\n");
" // #define __ _masm.\n"
" MacroAssembler _masm(&cbuf);\n");
// Parse the following %{ }% block // Parse the following %{ }% block
enc_class_parse_block(encoding, ec_name); ins_encode_parse_block_impl(inst, encoding, ec_name);
// Build an encoding rule which invokes the encoding rule we just // Build an encoding rule which invokes the encoding rule we just
// created, passing all arguments that we received. // created, passing all arguments that we received.
InsEncode *encrule = new InsEncode(); // Encode class for instruction InsEncode* encrule = new InsEncode(); // Encode class for instruction
NameAndList *params = encrule->add_encode(ec_name); NameAndList* params = encrule->add_encode(ec_name);
inst._parameters.reset(); inst._parameters.reset();
while ((param = inst._parameters.iter()) != NULL) { while ((param = inst._parameters.iter()) != NULL) {
params->add_entry(param); params->add_entry(param);
} }
return encrule; // Set encode class of this instruction.
inst._insencode = encrule;
}
void ADLParser::ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name) {
skipws_no_preproc(); // Skip leading whitespace
// Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block
if (_AD._adlocation_debug) {
encoding->add_code(get_line_string());
}
// Collect the parts of the encode description
// (1) strings that are passed through to output
// (2) replacement/substitution variable, preceeded by a '$'
while ((_curchar != '%') && (*(_ptr+1) != '}')) {
// (1)
// Check if there is a string to pass through to output
char *start = _ptr; // Record start of the next string
while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {
// If at the start of a comment, skip past it
if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
skipws_no_preproc();
} else {
// ELSE advance to the next character, or start of the next line
next_char_or_line();
}
}
// If a string was found, terminate it and record in EncClass
if (start != _ptr) {
*_ptr = '\0'; // Terminate the string
encoding->add_code(start);
}
// (2)
// If we are at a replacement variable,
// copy it and record in EncClass
if (_curchar == '$') {
// Found replacement Variable
char* rep_var = get_rep_var_ident_dup();
// Add flag to _strings list indicating we should check _rep_vars
encoding->add_rep_var(rep_var);
skipws();
// Check if this instruct is a MachConstantNode.
if (strcmp(rep_var, "constanttablebase") == 0) {
// This instruct is a MachConstantNode.
inst.set_is_mach_constant(true);
if (_curchar == '(') {
parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument (only constantaddress and constantoffset)", ec_name);
return;
}
}
else if ((strcmp(rep_var, "constantaddress") == 0) ||
(strcmp(rep_var, "constantoffset") == 0)) {
// This instruct is a MachConstantNode.
inst.set_is_mach_constant(true);
// If the constant keyword has an argument, parse it.
if (_curchar == '(') constant_parse(inst);
}
}
} // end while part of format description
next_char(); // Skip '%'
next_char(); // Skip '}'
skipws();
if (_AD._adlocation_debug) {
encoding->add_code(end_line_marker());
}
// Debug Stuff
if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);
} }
...@@ -2838,7 +2913,7 @@ InsEncode *ADLParser::ins_encode_parse_block(InstructForm &inst) { ...@@ -2838,7 +2913,7 @@ InsEncode *ADLParser::ins_encode_parse_block(InstructForm &inst) {
// //
// making it more compact to take advantage of the MacroAssembler and // making it more compact to take advantage of the MacroAssembler and
// placing the assembly closer to it's use by instructions. // placing the assembly closer to it's use by instructions.
InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) { void ADLParser::ins_encode_parse(InstructForm& inst) {
// Parse encode class name // Parse encode class name
skipws(); // Skip whitespace skipws(); // Skip whitespace
...@@ -2849,11 +2924,12 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) { ...@@ -2849,11 +2924,12 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
next_char(); // Skip '{' next_char(); // Skip '{'
// Parse the block form of ins_encode // Parse the block form of ins_encode
return ins_encode_parse_block(inst); ins_encode_parse_block(inst);
return;
} }
parse_err(SYNERR, "missing '%%{' or '(' in ins_encode definition\n"); parse_err(SYNERR, "missing '%%{' or '(' in ins_encode definition\n");
return NULL; return;
} }
next_char(); // move past '(' next_char(); // move past '('
skipws(); skipws();
...@@ -2866,7 +2942,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) { ...@@ -2866,7 +2942,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
ec_name = get_ident(); ec_name = get_ident();
if (ec_name == NULL) { if (ec_name == NULL) {
parse_err(SYNERR, "Invalid encode class name after 'ins_encode('.\n"); parse_err(SYNERR, "Invalid encode class name after 'ins_encode('.\n");
return NULL; return;
} }
// Check that encoding is defined in the encode section // Check that encoding is defined in the encode section
EncClass *encode_class = _AD._encode->encClass(ec_name); EncClass *encode_class = _AD._encode->encClass(ec_name);
...@@ -2898,7 +2974,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) { ...@@ -2898,7 +2974,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) && (Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) { ((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) {
parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name); parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);
return NULL; return;
} }
params->add_entry(param); params->add_entry(param);
...@@ -2915,7 +2991,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) { ...@@ -2915,7 +2991,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
// Only ',' or ')' are valid after a parameter name // Only ',' or ')' are valid after a parameter name
parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n", parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n",
ec_name); ec_name);
return NULL; return;
} }
} else { } else {
...@@ -2923,11 +2999,11 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) { ...@@ -2923,11 +2999,11 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
// Did not find a parameter // Did not find a parameter
if (_curchar == ',') { if (_curchar == ',') {
parse_err(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name); parse_err(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name);
return NULL; return;
} }
if (_curchar != ')') { if (_curchar != ')') {
parse_err(SYNERR, "Expected ')' after encode parameters.\n"); parse_err(SYNERR, "Expected ')' after encode parameters.\n");
return NULL; return;
} }
} }
} // WHILE loop collecting parameters } // WHILE loop collecting parameters
...@@ -2944,7 +3020,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) { ...@@ -2944,7 +3020,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
else if ( _curchar != ')' ) { else if ( _curchar != ')' ) {
// If not a ',' then only a ')' is allowed // If not a ',' then only a ')' is allowed
parse_err(SYNERR, "Expected ')' after encoding %s.\n", ec_name); parse_err(SYNERR, "Expected ')' after encoding %s.\n", ec_name);
return NULL; return;
} }
// Check for ',' separating parameters // Check for ',' separating parameters
...@@ -2956,14 +3032,14 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) { ...@@ -2956,14 +3032,14 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
} // done parsing ins_encode methods and their parameters } // done parsing ins_encode methods and their parameters
if (_curchar != ')') { if (_curchar != ')') {
parse_err(SYNERR, "Missing ')' at end of ins_encode description.\n"); parse_err(SYNERR, "Missing ')' at end of ins_encode description.\n");
return NULL; return;
} }
next_char(); // move past ')' next_char(); // move past ')'
skipws(); // Skip leading whitespace skipws(); // Skip leading whitespace
if ( _curchar != ';' ) { if ( _curchar != ';' ) {
parse_err(SYNERR, "Missing ';' at end of ins_encode.\n"); parse_err(SYNERR, "Missing ';' at end of ins_encode.\n");
return NULL; return;
} }
next_char(); // move past ';' next_char(); // move past ';'
skipws(); // be friendly to oper_parse() skipws(); // be friendly to oper_parse()
...@@ -2971,7 +3047,113 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) { ...@@ -2971,7 +3047,113 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
// Debug Stuff // Debug Stuff
if (_AD._adl_debug > 1) fprintf(stderr,"Instruction Encode: %s\n", ec_name); if (_AD._adl_debug > 1) fprintf(stderr,"Instruction Encode: %s\n", ec_name);
return encrule; // Set encode class of this instruction.
inst._insencode = encrule;
}
//------------------------------constant_parse---------------------------------
// Parse a constant expression.
void ADLParser::constant_parse(InstructForm& inst) {
// Create a new encoding name based on the name of the instruction
// definition, which should be unique.
const char* prefix = "__constant_";
char* ec_name = (char*) malloc(strlen(inst._ident) + strlen(prefix) + 1);
sprintf(ec_name, "%s%s", prefix, inst._ident);
assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");
EncClass* encoding = _AD._encode->add_EncClass(ec_name);
encoding->_linenum = linenum();
// synthesize the arguments list for the enc_class from the
// arguments to the instruct definition.
const char* param = NULL;
inst._parameters.reset();
while ((param = inst._parameters.iter()) != NULL) {
OperandForm* opForm = (OperandForm*) inst._localNames[param];
encoding->add_parameter(opForm->_ident, param);
}
// Parse the following ( ) expression.
constant_parse_expression(encoding, ec_name);
// Build an encoding rule which invokes the encoding rule we just
// created, passing all arguments that we received.
InsEncode* encrule = new InsEncode(); // Encode class for instruction
NameAndList* params = encrule->add_encode(ec_name);
inst._parameters.reset();
while ((param = inst._parameters.iter()) != NULL) {
params->add_entry(param);
}
// Set encode class of this instruction.
inst._constant = encrule;
}
//------------------------------constant_parse_expression----------------------
void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) {
skipws();
// Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block
if (_AD._adlocation_debug) {
encoding->add_code(get_line_string());
}
// Start code line.
encoding->add_code(" _constant = C->constant_table().add");
// Parse everything in ( ) expression.
encoding->add_code("(");
next_char(); // Skip '('
int parens_depth = 1;
// Collect the parts of the constant expression.
// (1) strings that are passed through to output
// (2) replacement/substitution variable, preceeded by a '$'
while (parens_depth > 0) {
if (_curchar == '(') {
parens_depth++;
encoding->add_code("(");
next_char();
}
else if (_curchar == ')') {
parens_depth--;
encoding->add_code(")");
next_char();
}
else {
// (1)
// Check if there is a string to pass through to output
char *start = _ptr; // Record start of the next string
while ((_curchar != '$') && (_curchar != '(') && (_curchar != ')')) {
next_char();
}
// If a string was found, terminate it and record in EncClass
if (start != _ptr) {
*_ptr = '\0'; // Terminate the string
encoding->add_code(start);
}
// (2)
// If we are at a replacement variable, copy it and record in EncClass.
if (_curchar == '$') {
// Found replacement Variable
char* rep_var = get_rep_var_ident_dup();
encoding->add_rep_var(rep_var);
}
}
}
// Finish code line.
encoding->add_code(";");
if (_AD._adlocation_debug) {
encoding->add_code(end_line_marker());
}
// Debug Stuff
if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);
} }
......
...@@ -156,8 +156,13 @@ protected: ...@@ -156,8 +156,13 @@ protected:
Attribute *attr_parse(char *ident);// Parse instr/operand attribute rule Attribute *attr_parse(char *ident);// Parse instr/operand attribute rule
// Parse instruction encode rule // Parse instruction encode rule
InsEncode *ins_encode_parse(InstructForm &inst); void ins_encode_parse(InstructForm &inst);
InsEncode *ins_encode_parse_block(InstructForm &inst); void ins_encode_parse_block(InstructForm &inst);
void ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name);
void constant_parse(InstructForm& inst);
void constant_parse_expression(EncClass* encoding, char* ec_name);
Opcode *opcode_parse(InstructForm *insr); // Parse instruction opcode Opcode *opcode_parse(InstructForm *insr); // Parse instruction opcode
char *size_parse(InstructForm *insr); // Parse instruction size char *size_parse(InstructForm *insr); // Parse instruction size
Interface *interface_parse(); // Parse operand interface rule Interface *interface_parse(); // Parse operand interface rule
......
...@@ -126,7 +126,6 @@ private: ...@@ -126,7 +126,6 @@ private:
void chain_rule(FILE *fp, const char *indent, const char *ideal, void chain_rule(FILE *fp, const char *indent, const char *ideal,
const Expr *icost, const char *irule, const Expr *icost, const char *irule,
Dict &operands_chained_from, ProductionState &status); Dict &operands_chained_from, ProductionState &status);
void chain_rule_c(FILE *fp, char *indent, char *ideal, char *irule); // %%%%% TODO: remove this
void expand_opclass(FILE *fp, const char *indent, const Expr *cost, void expand_opclass(FILE *fp, const char *indent, const Expr *cost,
const char *result_type, ProductionState &status); const char *result_type, ProductionState &status);
Expr *calc_cost(FILE *fp, const char *spaces, MatchList &mList, ProductionState &status); Expr *calc_cost(FILE *fp, const char *spaces, MatchList &mList, ProductionState &status);
...@@ -301,13 +300,18 @@ public: ...@@ -301,13 +300,18 @@ public:
void buildMachNodeGenerator(FILE *fp_cpp); void buildMachNodeGenerator(FILE *fp_cpp);
// Generator for Expand methods for instructions with expand rules // Generator for Expand methods for instructions with expand rules
void defineExpand(FILE *fp, InstructForm *node); void defineExpand (FILE *fp, InstructForm *node);
// Generator for Peephole methods for instructions with peephole rules // Generator for Peephole methods for instructions with peephole rules
void definePeephole(FILE *fp, InstructForm *node); void definePeephole (FILE *fp, InstructForm *node);
// Generator for Size methods for instructions // Generator for Size methods for instructions
void defineSize(FILE *fp, InstructForm &node); void defineSize (FILE *fp, InstructForm &node);
public:
// Generator for EvalConstantValue methods for instructions
void defineEvalConstant(FILE *fp, InstructForm &node);
// Generator for Emit methods for instructions // Generator for Emit methods for instructions
void defineEmit(FILE *fp, InstructForm &node); void defineEmit (FILE *fp, InstructForm &node);
// Define a MachOper encode method // Define a MachOper encode method
void define_oper_interface(FILE *fp, OperandForm &oper, FormDict &globals, void define_oper_interface(FILE *fp, OperandForm &oper, FormDict &globals,
const char *name, const char *encoding); const char *name, const char *encoding);
......
...@@ -30,11 +30,14 @@ ...@@ -30,11 +30,14 @@
InstructForm::InstructForm(const char *id, bool ideal_only) InstructForm::InstructForm(const char *id, bool ideal_only)
: _ident(id), _ideal_only(ideal_only), : _ident(id), _ideal_only(ideal_only),
_localNames(cmpstr, hashstr, Form::arena), _localNames(cmpstr, hashstr, Form::arena),
_effects(cmpstr, hashstr, Form::arena) { _effects(cmpstr, hashstr, Form::arena),
_is_mach_constant(false)
{
_ftype = Form::INS; _ftype = Form::INS;
_matrule = NULL; _matrule = NULL;
_insencode = NULL; _insencode = NULL;
_constant = NULL;
_opcode = NULL; _opcode = NULL;
_size = NULL; _size = NULL;
_attribs = NULL; _attribs = NULL;
...@@ -58,11 +61,14 @@ InstructForm::InstructForm(const char *id, bool ideal_only) ...@@ -58,11 +61,14 @@ InstructForm::InstructForm(const char *id, bool ideal_only)
InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule) InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule)
: _ident(id), _ideal_only(false), : _ident(id), _ideal_only(false),
_localNames(instr->_localNames), _localNames(instr->_localNames),
_effects(instr->_effects) { _effects(instr->_effects),
_is_mach_constant(false)
{
_ftype = Form::INS; _ftype = Form::INS;
_matrule = rule; _matrule = rule;
_insencode = instr->_insencode; _insencode = instr->_insencode;
_constant = instr->_constant;
_opcode = instr->_opcode; _opcode = instr->_opcode;
_size = instr->_size; _size = instr->_size;
_attribs = instr->_attribs; _attribs = instr->_attribs;
...@@ -1094,6 +1100,9 @@ const char *InstructForm::mach_base_class(FormDict &globals) const { ...@@ -1094,6 +1100,9 @@ const char *InstructForm::mach_base_class(FormDict &globals) const {
else if (is_ideal_nop()) { else if (is_ideal_nop()) {
return "MachNopNode"; return "MachNopNode";
} }
else if (is_mach_constant()) {
return "MachConstantNode";
}
else if (captures_bottom_type(globals)) { else if (captures_bottom_type(globals)) {
return "MachTypeNode"; return "MachTypeNode";
} else { } else {
...@@ -1190,6 +1199,21 @@ bool InstructForm::check_branch_variant(ArchDesc &AD, InstructForm *short_branch ...@@ -1190,6 +1199,21 @@ bool InstructForm::check_branch_variant(ArchDesc &AD, InstructForm *short_branch
// //
// Generate the format call for the replacement variable // Generate the format call for the replacement variable
void InstructForm::rep_var_format(FILE *fp, const char *rep_var) { void InstructForm::rep_var_format(FILE *fp, const char *rep_var) {
// Handle special constant table variables.
if (strcmp(rep_var, "constanttablebase") == 0) {
fprintf(fp, "char reg[128]; ra->dump_register(in(mach_constant_base_node_input()), reg);\n");
fprintf(fp, "st->print(\"%%s\");\n");
return;
}
if (strcmp(rep_var, "constantoffset") == 0) {
fprintf(fp, "st->print(\"#%%d\", constant_offset());\n");
return;
}
if (strcmp(rep_var, "constantaddress") == 0) {
fprintf(fp, "st->print(\"constant table base + #%%d\", constant_offset());\n");
return;
}
// Find replacement variable's type // Find replacement variable's type
const Form *form = _localNames[rep_var]; const Form *form = _localNames[rep_var];
if (form == NULL) { if (form == NULL) {
...@@ -1348,6 +1372,7 @@ void InstructForm::output(FILE *fp) { ...@@ -1348,6 +1372,7 @@ void InstructForm::output(FILE *fp) {
fprintf(fp,"\nInstruction: %s\n", (_ident?_ident:"")); fprintf(fp,"\nInstruction: %s\n", (_ident?_ident:""));
if (_matrule) _matrule->output(fp); if (_matrule) _matrule->output(fp);
if (_insencode) _insencode->output(fp); if (_insencode) _insencode->output(fp);
if (_constant) _constant->output(fp);
if (_opcode) _opcode->output(fp); if (_opcode) _opcode->output(fp);
if (_attribs) _attribs->output(fp); if (_attribs) _attribs->output(fp);
if (_predicate) _predicate->output(fp); if (_predicate) _predicate->output(fp);
......
...@@ -74,15 +74,16 @@ class ArchDesc; ...@@ -74,15 +74,16 @@ class ArchDesc;
//------------------------------InstructForm----------------------------------- //------------------------------InstructForm-----------------------------------
class InstructForm : public Form { class InstructForm : public Form {
private: private:
bool _ideal_only; // Not a user-defined instruction bool _ideal_only; // Not a user-defined instruction
// Members used for tracking CISC-spilling // Members used for tracking CISC-spilling
uint _cisc_spill_operand;// Which operand may cisc-spill uint _cisc_spill_operand;// Which operand may cisc-spill
void set_cisc_spill_operand(uint op_index) { _cisc_spill_operand = op_index; } void set_cisc_spill_operand(uint op_index) { _cisc_spill_operand = op_index; }
bool _is_cisc_alternate; bool _is_cisc_alternate;
InstructForm *_cisc_spill_alternate;// cisc possible replacement InstructForm *_cisc_spill_alternate;// cisc possible replacement
const char *_cisc_reg_mask_name; const char *_cisc_reg_mask_name;
InstructForm *_short_branch_form; InstructForm *_short_branch_form;
bool _is_short_branch; bool _is_short_branch;
bool _is_mach_constant; // true if Node is a MachConstantNode
uint _alignment; uint _alignment;
public: public:
...@@ -94,6 +95,7 @@ public: ...@@ -94,6 +95,7 @@ public:
Opcode *_opcode; // Encoding of the opcode for instruction Opcode *_opcode; // Encoding of the opcode for instruction
char *_size; // Size of instruction char *_size; // Size of instruction
InsEncode *_insencode; // Encoding class instruction belongs to InsEncode *_insencode; // Encoding class instruction belongs to
InsEncode *_constant; // Encoding class constant value belongs to
Attribute *_attribs; // List of Attribute rules Attribute *_attribs; // List of Attribute rules
Predicate *_predicate; // Predicate test for this instruction Predicate *_predicate; // Predicate test for this instruction
FormDict _effects; // Dictionary of effect rules FormDict _effects; // Dictionary of effect rules
...@@ -251,6 +253,9 @@ public: ...@@ -251,6 +253,9 @@ public:
bool is_short_branch() { return _is_short_branch; } bool is_short_branch() { return _is_short_branch; }
void set_short_branch(bool val) { _is_short_branch = val; } void set_short_branch(bool val) { _is_short_branch = val; }
bool is_mach_constant() const { return _is_mach_constant; }
void set_is_mach_constant(bool x) { _is_mach_constant = x; }
InstructForm *short_branch_form() { return _short_branch_form; } InstructForm *short_branch_form() { return _short_branch_form; }
bool has_short_branch_form() { return _short_branch_form != NULL; } bool has_short_branch_form() { return _short_branch_form != NULL; }
// Output short branch prototypes and method bodies // Output short branch prototypes and method bodies
......
...@@ -1496,8 +1496,8 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { ...@@ -1496,8 +1496,8 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
unsigned i; unsigned i;
// Generate Expand function header // Generate Expand function header
fprintf(fp,"MachNode *%sNode::Expand(State *state, Node_List &proj_list, Node* mem) {\n", node->_ident); fprintf(fp, "MachNode* %sNode::Expand(State* state, Node_List& proj_list, Node* mem) {\n", node->_ident);
fprintf(fp,"Compile* C = Compile::current();\n"); fprintf(fp, " Compile* C = Compile::current();\n");
// Generate expand code // Generate expand code
if( node->expands() ) { if( node->expands() ) {
const char *opid; const char *opid;
...@@ -1818,6 +1818,12 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { ...@@ -1818,6 +1818,12 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
} }
} }
// If the node is a MachConstantNode, insert the MachConstantBaseNode edge.
// NOTE: this edge must be the last input (see MachConstantNode::mach_constant_base_node_input).
if (node->is_mach_constant()) {
fprintf(fp," add_req(C->mach_constant_base_node());\n");
}
fprintf(fp,"\n"); fprintf(fp,"\n");
if( node->expands() ) { if( node->expands() ) {
fprintf(fp," return result;\n"); fprintf(fp," return result;\n");
...@@ -1924,7 +1930,17 @@ public: ...@@ -1924,7 +1930,17 @@ public:
// No state needed. // No state needed.
assert( _opclass == NULL, assert( _opclass == NULL,
"'primary', 'secondary' and 'tertiary' don't follow operand."); "'primary', 'secondary' and 'tertiary' don't follow operand.");
} else { }
else if ((strcmp(rep_var, "constanttablebase") == 0) ||
(strcmp(rep_var, "constantoffset") == 0) ||
(strcmp(rep_var, "constantaddress") == 0)) {
if (!_inst.is_mach_constant()) {
_AD.syntax_err(_encoding._linenum,
"Replacement variable %s not allowed in instruct %s (only in MachConstantNode).\n",
rep_var, _encoding._name);
}
}
else {
// Lookup its position in parameter list // Lookup its position in parameter list
int param_no = _encoding.rep_var_index(rep_var); int param_no = _encoding.rep_var_index(rep_var);
if ( param_no == -1 ) { if ( param_no == -1 ) {
...@@ -2380,6 +2396,15 @@ private: ...@@ -2380,6 +2396,15 @@ private:
rep_var, _inst._ident, _encoding._name); rep_var, _inst._ident, _encoding._name);
} }
} }
else if (strcmp(rep_var, "constanttablebase") == 0) {
fprintf(_fp, "as_Register(ra_->get_encode(in(mach_constant_base_node_input())))");
}
else if (strcmp(rep_var, "constantoffset") == 0) {
fprintf(_fp, "constant_offset()");
}
else if (strcmp(rep_var, "constantaddress") == 0) {
fprintf(_fp, "InternalAddress(__ code()->consts()->start() + constant_offset())");
}
else { else {
// Lookup its position in parameter list // Lookup its position in parameter list
int param_no = _encoding.rep_var_index(rep_var); int param_no = _encoding.rep_var_index(rep_var);
...@@ -2465,37 +2490,39 @@ void ArchDesc::defineSize(FILE *fp, InstructForm &inst) { ...@@ -2465,37 +2490,39 @@ void ArchDesc::defineSize(FILE *fp, InstructForm &inst) {
fprintf(fp,"}\n"); fprintf(fp,"}\n");
} }
void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) { // defineEmit -----------------------------------------------------------------
InsEncode *ins_encode = inst._insencode; void ArchDesc::defineEmit(FILE* fp, InstructForm& inst) {
InsEncode* encode = inst._insencode;
// (1) // (1)
// Output instruction's emit prototype // Output instruction's emit prototype
fprintf(fp,"void %sNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {\n", fprintf(fp, "void %sNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {\n", inst._ident);
inst._ident);
// If user did not define an encode section, // If user did not define an encode section,
// provide stub that does not generate any machine code. // provide stub that does not generate any machine code.
if( (_encode == NULL) || (ins_encode == NULL) ) { if( (_encode == NULL) || (encode == NULL) ) {
fprintf(fp, " // User did not define an encode section.\n"); fprintf(fp, " // User did not define an encode section.\n");
fprintf(fp,"}\n"); fprintf(fp, "}\n");
return; return;
} }
// Save current instruction's starting address (helps with relocation). // Save current instruction's starting address (helps with relocation).
fprintf(fp, " cbuf.set_insts_mark();\n"); fprintf(fp, " cbuf.set_insts_mark();\n");
// // // idx0 is only needed for syntactic purposes and only by "storeSSI" // For MachConstantNodes which are ideal jump nodes, fill the jump table.
// fprintf( fp, " unsigned idx0 = 0;\n"); if (inst.is_mach_constant() && inst.is_ideal_jump()) {
fprintf(fp, " ra_->C->constant_table().fill_jump_table(cbuf, (MachConstantNode*) this, _index2label);\n");
}
// Output each operand's offset into the array of registers. // Output each operand's offset into the array of registers.
inst.index_temps( fp, _globalNames ); inst.index_temps(fp, _globalNames);
// Output this instruction's encodings // Output this instruction's encodings
const char *ec_name; const char *ec_name;
bool user_defined = false; bool user_defined = false;
ins_encode->reset(); encode->reset();
while ( (ec_name = ins_encode->encode_class_iter()) != NULL ) { while ((ec_name = encode->encode_class_iter()) != NULL) {
fprintf(fp, " {"); fprintf(fp, " {\n");
// Output user-defined encoding // Output user-defined encoding
user_defined = true; user_defined = true;
...@@ -2507,25 +2534,25 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) { ...@@ -2507,25 +2534,25 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
abort(); abort();
} }
if (ins_encode->current_encoding_num_args() != encoding->num_args()) { if (encode->current_encoding_num_args() != encoding->num_args()) {
globalAD->syntax_err(ins_encode->_linenum, "In %s: passing %d arguments to %s but expecting %d", globalAD->syntax_err(encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",
inst._ident, ins_encode->current_encoding_num_args(), inst._ident, encode->current_encoding_num_args(),
ec_name, encoding->num_args()); ec_name, encoding->num_args());
} }
DefineEmitState pending(fp, *this, *encoding, *ins_encode, inst ); DefineEmitState pending(fp, *this, *encoding, *encode, inst);
encoding->_code.reset(); encoding->_code.reset();
encoding->_rep_vars.reset(); encoding->_rep_vars.reset();
// Process list of user-defined strings, // Process list of user-defined strings,
// and occurrences of replacement variables. // and occurrences of replacement variables.
// Replacement Vars are pushed into a list and then output // Replacement Vars are pushed into a list and then output
while ( (ec_code = encoding->_code.iter()) != NULL ) { while ((ec_code = encoding->_code.iter()) != NULL) {
if ( ! encoding->_code.is_signal( ec_code ) ) { if (!encoding->_code.is_signal(ec_code)) {
// Emit pending code // Emit pending code
pending.emit(); pending.emit();
pending.clear(); pending.clear();
// Emit this code section // Emit this code section
fprintf(fp,"%s", ec_code); fprintf(fp, "%s", ec_code);
} else { } else {
// A replacement variable or one of its subfields // A replacement variable or one of its subfields
// Obtain replacement variable from list // Obtain replacement variable from list
...@@ -2536,7 +2563,7 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) { ...@@ -2536,7 +2563,7 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
// Emit pending code // Emit pending code
pending.emit(); pending.emit();
pending.clear(); pending.clear();
fprintf(fp, "}\n"); fprintf(fp, " }\n");
} // end while instruction's encodings } // end while instruction's encodings
// Check if user stated which encoding to user // Check if user stated which encoding to user
...@@ -2545,7 +2572,86 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) { ...@@ -2545,7 +2572,86 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
} }
// (3) and (4) // (3) and (4)
fprintf(fp,"}\n"); fprintf(fp, "}\n");
}
// defineEvalConstant ---------------------------------------------------------
void ArchDesc::defineEvalConstant(FILE* fp, InstructForm& inst) {
InsEncode* encode = inst._constant;
// (1)
// Output instruction's emit prototype
fprintf(fp, "void %sNode::eval_constant(Compile* C) {\n", inst._ident);
// For ideal jump nodes, allocate a jump table.
if (inst.is_ideal_jump()) {
fprintf(fp, " _constant = C->constant_table().allocate_jump_table(this);\n");
}
// If user did not define an encode section,
// provide stub that does not generate any machine code.
if ((_encode == NULL) || (encode == NULL)) {
fprintf(fp, " // User did not define an encode section.\n");
fprintf(fp, "}\n");
return;
}
// Output this instruction's encodings
const char *ec_name;
bool user_defined = false;
encode->reset();
while ((ec_name = encode->encode_class_iter()) != NULL) {
fprintf(fp, " {\n");
// Output user-defined encoding
user_defined = true;
const char *ec_code = NULL;
const char *ec_rep_var = NULL;
EncClass *encoding = _encode->encClass(ec_name);
if (encoding == NULL) {
fprintf(stderr, "User did not define contents of this encode_class: %s\n", ec_name);
abort();
}
if (encode->current_encoding_num_args() != encoding->num_args()) {
globalAD->syntax_err(encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",
inst._ident, encode->current_encoding_num_args(),
ec_name, encoding->num_args());
}
DefineEmitState pending(fp, *this, *encoding, *encode, inst);
encoding->_code.reset();
encoding->_rep_vars.reset();
// Process list of user-defined strings,
// and occurrences of replacement variables.
// Replacement Vars are pushed into a list and then output
while ((ec_code = encoding->_code.iter()) != NULL) {
if (!encoding->_code.is_signal(ec_code)) {
// Emit pending code
pending.emit();
pending.clear();
// Emit this code section
fprintf(fp, "%s", ec_code);
} else {
// A replacement variable or one of its subfields
// Obtain replacement variable from list
ec_rep_var = encoding->_rep_vars.iter();
pending.add_rep_var(ec_rep_var);
}
}
// Emit pending code
pending.emit();
pending.clear();
fprintf(fp, " }\n");
} // end while instruction's encodings
// Check if user stated which encoding to user
if (user_defined == false) {
fprintf(fp, " // User did not define which encode class to use.\n");
}
// (3) and (4)
fprintf(fp, "}\n");
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -2952,6 +3058,7 @@ void ArchDesc::defineClasses(FILE *fp) { ...@@ -2952,6 +3058,7 @@ void ArchDesc::defineClasses(FILE *fp) {
// If there are multiple defs/kills, or an explicit expand rule, build rule // If there are multiple defs/kills, or an explicit expand rule, build rule
if( instr->expands() || instr->needs_projections() || if( instr->expands() || instr->needs_projections() ||
instr->has_temps() || instr->has_temps() ||
instr->is_mach_constant() ||
instr->_matrule != NULL && instr->_matrule != NULL &&
instr->num_opnds() != instr->num_unique_opnds() ) instr->num_opnds() != instr->num_unique_opnds() )
defineExpand(_CPP_EXPAND_file._fp, instr); defineExpand(_CPP_EXPAND_file._fp, instr);
...@@ -3032,8 +3139,9 @@ void ArchDesc::defineClasses(FILE *fp) { ...@@ -3032,8 +3139,9 @@ void ArchDesc::defineClasses(FILE *fp) {
// Ensure this is a machine-world instruction // Ensure this is a machine-world instruction
if ( instr->ideal_only() ) continue; if ( instr->ideal_only() ) continue;
if (instr->_insencode) defineEmit(fp, *instr); if (instr->_insencode) defineEmit (fp, *instr);
if (instr->_size) defineSize(fp, *instr); if (instr->is_mach_constant()) defineEvalConstant(fp, *instr);
if (instr->_size) defineSize (fp, *instr);
// side-call to generate output that used to be in the header file: // side-call to generate output that used to be in the header file:
extern void gen_inst_format(FILE *fp, FormDict &globals, InstructForm &oper, bool for_c_file); extern void gen_inst_format(FILE *fp, FormDict &globals, InstructForm &oper, bool for_c_file);
......
...@@ -1550,7 +1550,12 @@ void ArchDesc::declareClasses(FILE *fp) { ...@@ -1550,7 +1550,12 @@ void ArchDesc::declareClasses(FILE *fp) {
} }
// virtual functions for encode and format // virtual functions for encode and format
//
// Virtual function for evaluating the constant.
if (instr->is_mach_constant()) {
fprintf(fp," virtual void eval_constant(Compile* C);\n");
}
// Output the opcode function and the encode function here using the // Output the opcode function and the encode function here using the
// encoding class information in the _insencode slot. // encoding class information in the _insencode slot.
if ( instr->_insencode ) { if ( instr->_insencode ) {
...@@ -1559,7 +1564,7 @@ void ArchDesc::declareClasses(FILE *fp) { ...@@ -1559,7 +1564,7 @@ void ArchDesc::declareClasses(FILE *fp) {
// virtual function for getting the size of an instruction // virtual function for getting the size of an instruction
if ( instr->_size ) { if ( instr->_size ) {
fprintf(fp," virtual uint size(PhaseRegAlloc *ra_) const;\n"); fprintf(fp," virtual uint size(PhaseRegAlloc *ra_) const;\n");
} }
// Return the top-level ideal opcode. // Return the top-level ideal opcode.
...@@ -1752,6 +1757,7 @@ void ArchDesc::declareClasses(FILE *fp) { ...@@ -1752,6 +1757,7 @@ void ArchDesc::declareClasses(FILE *fp) {
// Virtual methods which are only generated to override base class // Virtual methods which are only generated to override base class
if( instr->expands() || instr->needs_projections() || if( instr->expands() || instr->needs_projections() ||
instr->has_temps() || instr->has_temps() ||
instr->is_mach_constant() ||
instr->_matrule != NULL && instr->_matrule != NULL &&
instr->num_opnds() != instr->num_unique_opnds() ) { instr->num_opnds() != instr->num_unique_opnds() ) {
fprintf(fp," virtual MachNode *Expand(State *state, Node_List &proj_list, Node* mem);\n"); fprintf(fp," virtual MachNode *Expand(State *state, Node_List &proj_list, Node* mem);\n");
...@@ -1780,24 +1786,6 @@ void ArchDesc::declareClasses(FILE *fp) { ...@@ -1780,24 +1786,6 @@ void ArchDesc::declareClasses(FILE *fp) {
// Declare short branch methods, if applicable // Declare short branch methods, if applicable
instr->declare_short_branch_methods(fp); instr->declare_short_branch_methods(fp);
// Instructions containing a constant that will be entered into the
// float/double table redefine the base virtual function
#ifdef SPARC
// Sparc doubles entries in the constant table require more space for
// alignment. (expires 9/98)
int table_entries = (3 * instr->num_consts( _globalNames, Form::idealD ))
+ instr->num_consts( _globalNames, Form::idealF );
#else
int table_entries = instr->num_consts( _globalNames, Form::idealD )
+ instr->num_consts( _globalNames, Form::idealF );
#endif
if( table_entries != 0 ) {
fprintf(fp," virtual int const_size() const {");
fprintf(fp, " return %d;", table_entries);
fprintf(fp, " }\n");
}
// See if there is an "ins_pipe" declaration for this instruction // See if there is an "ins_pipe" declaration for this instruction
if (instr->_ins_pipe) { if (instr->_ins_pipe) {
fprintf(fp," static const Pipeline *pipeline_class();\n"); fprintf(fp," static const Pipeline *pipeline_class();\n");
......
...@@ -292,7 +292,16 @@ class AbstractAssembler : public ResourceObj { ...@@ -292,7 +292,16 @@ class AbstractAssembler : public ResourceObj {
address start_a_const(int required_space, int required_align = sizeof(double)); address start_a_const(int required_space, int required_align = sizeof(double));
void end_a_const(); void end_a_const();
// fp constants support // constants support
address long_constant(jlong c) {
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
*(jlong*)ptr = c;
_code_pos = ptr + sizeof(c);
end_a_const();
}
return ptr;
}
address double_constant(jdouble c) { address double_constant(jdouble c) {
address ptr = start_a_const(sizeof(c), sizeof(c)); address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) { if (ptr != NULL) {
...@@ -311,6 +320,15 @@ class AbstractAssembler : public ResourceObj { ...@@ -311,6 +320,15 @@ class AbstractAssembler : public ResourceObj {
} }
return ptr; return ptr;
} }
address address_constant(address c) {
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
*(address*)ptr = c;
_code_pos = ptr + sizeof(c);
end_a_const();
}
return ptr;
}
address address_constant(address c, RelocationHolder const& rspec) { address address_constant(address c, RelocationHolder const& rspec) {
address ptr = start_a_const(sizeof(c), sizeof(c)); address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) { if (ptr != NULL) {
...@@ -321,8 +339,6 @@ class AbstractAssembler : public ResourceObj { ...@@ -321,8 +339,6 @@ class AbstractAssembler : public ResourceObj {
} }
return ptr; return ptr;
} }
inline address address_constant(Label& L);
inline address address_table_constant(GrowableArray<Label*> label);
// Bootstrapping aid to cope with delayed determination of constants. // Bootstrapping aid to cope with delayed determination of constants.
// Returns a static address which will eventually contain the constant. // Returns a static address which will eventually contain the constant.
......
...@@ -114,32 +114,4 @@ inline void Label::bind_loc(int pos, int sect) { ...@@ -114,32 +114,4 @@ inline void Label::bind_loc(int pos, int sect) {
bind_loc(CodeBuffer::locator(pos, sect)); bind_loc(CodeBuffer::locator(pos, sect));
} }
address AbstractAssembler::address_constant(Label& L) {
address c = NULL;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
relocate(Relocation::spec_simple(relocInfo::internal_word_type));
*(address*)ptr = c = code_section()->target(L, ptr);
_code_pos = ptr + sizeof(c);
end_a_const();
}
return ptr;
}
address AbstractAssembler::address_table_constant(GrowableArray<Label*> labels) {
int addressSize = sizeof(address);
int sizeLabel = addressSize * labels.length();
address ptr = start_a_const(sizeLabel, addressSize);
if (ptr != NULL) {
address *labelLoc = (address*)ptr;
for (int i=0; i < labels.length(); i++) {
emit_address(code_section()->target(*labels.at(i), (address)&labelLoc[i]));
code_section()->relocate((address)&labelLoc[i], relocInfo::internal_word_type);
}
end_a_const();
}
return ptr;
}
#endif // SHARE_VM_ASM_ASSEMBLER_INLINE_HPP #endif // SHARE_VM_ASM_ASSEMBLER_INLINE_HPP
...@@ -467,5 +467,18 @@ void Disassembler::decode(nmethod* nm, outputStream* st) { ...@@ -467,5 +467,18 @@ void Disassembler::decode(nmethod* nm, outputStream* st) {
env.set_total_ticks(total_bucket_count); env.set_total_ticks(total_bucket_count);
} }
// Print constant table.
if (nm->consts_size() > 0) {
nm->print_nmethod_labels(env.output(), nm->consts_begin());
int offset = 0;
for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) {
if ((offset % 8) == 0) {
env.output()->print_cr(" " INTPTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, (intptr_t) p, offset, *((int32_t*) p), *((int64_t*) p));
} else {
env.output()->print_cr(" " INTPTR_FORMAT " (offset: %4d): " PTR32_FORMAT, (intptr_t) p, offset, *((int32_t*) p));
}
}
}
env.decode_instructions(p, end); env.decode_instructions(p, end);
} }
...@@ -284,6 +284,9 @@ ...@@ -284,6 +284,9 @@
develop(bool, SparcV9RegsHiBitsZero, true, \ develop(bool, SparcV9RegsHiBitsZero, true, \
"Assume Sparc V9 I&L registers on V8+ systems are zero-extended") \ "Assume Sparc V9 I&L registers on V8+ systems are zero-extended") \
\ \
product(bool, UseRDPCForConstantTableBase, false, \
"Use Sparc RDPC instruction for the constant table base.") \
\
develop(intx, PrintIdealGraphLevel, 0, \ develop(intx, PrintIdealGraphLevel, 0, \
"Print ideal graph to XML file / network interface. " \ "Print ideal graph to XML file / network interface. " \
"By default attempts to connect to the visualizer on a socket.") \ "By default attempts to connect to the visualizer on a socket.") \
......
...@@ -75,6 +75,18 @@ ...@@ -75,6 +75,18 @@
# include "adfiles/ad_zero.hpp" # include "adfiles/ad_zero.hpp"
#endif #endif
// -------------------- Compile::mach_constant_base_node -----------------------
// Constant table base node singleton.
MachConstantBaseNode* Compile::mach_constant_base_node() {
if (_mach_constant_base_node == NULL) {
_mach_constant_base_node = new (C) MachConstantBaseNode();
_mach_constant_base_node->add_req(C->root());
}
return _mach_constant_base_node;
}
/// Support for intrinsics. /// Support for intrinsics.
// Return the index at which m must be inserted (or already exists). // Return the index at which m must be inserted (or already exists).
...@@ -432,13 +444,14 @@ void Compile::print_compile_messages() { ...@@ -432,13 +444,14 @@ void Compile::print_compile_messages() {
} }
void Compile::init_scratch_buffer_blob() { void Compile::init_scratch_buffer_blob(int const_size) {
if( scratch_buffer_blob() != NULL ) return; if (scratch_buffer_blob() != NULL) return;
// Construct a temporary CodeBuffer to have it construct a BufferBlob // Construct a temporary CodeBuffer to have it construct a BufferBlob
// Cache this BufferBlob for this compile. // Cache this BufferBlob for this compile.
ResourceMark rm; ResourceMark rm;
int size = (MAX_inst_size + MAX_stubs_size + MAX_const_size); _scratch_const_size = const_size;
int size = (MAX_inst_size + MAX_stubs_size + _scratch_const_size);
BufferBlob* blob = BufferBlob::create("Compile::scratch_buffer", size); BufferBlob* blob = BufferBlob::create("Compile::scratch_buffer", size);
// Record the buffer blob for next time. // Record the buffer blob for next time.
set_scratch_buffer_blob(blob); set_scratch_buffer_blob(blob);
...@@ -455,9 +468,19 @@ void Compile::init_scratch_buffer_blob() { ...@@ -455,9 +468,19 @@ void Compile::init_scratch_buffer_blob() {
} }
void Compile::clear_scratch_buffer_blob() {
assert(scratch_buffer_blob(), "no BufferBlob set");
set_scratch_buffer_blob(NULL);
set_scratch_locs_memory(NULL);
}
//-----------------------scratch_emit_size------------------------------------- //-----------------------scratch_emit_size-------------------------------------
// Helper function that computes size by emitting code // Helper function that computes size by emitting code
uint Compile::scratch_emit_size(const Node* n) { uint Compile::scratch_emit_size(const Node* n) {
// Start scratch_emit_size section.
set_in_scratch_emit_size(true);
// Emit into a trash buffer and count bytes emitted. // Emit into a trash buffer and count bytes emitted.
// This is a pretty expensive way to compute a size, // This is a pretty expensive way to compute a size,
// but it works well enough if seldom used. // but it works well enough if seldom used.
...@@ -476,13 +499,20 @@ uint Compile::scratch_emit_size(const Node* n) { ...@@ -476,13 +499,20 @@ uint Compile::scratch_emit_size(const Node* n) {
address blob_end = (address)locs_buf; address blob_end = (address)locs_buf;
assert(blob->content_contains(blob_end), "sanity"); assert(blob->content_contains(blob_end), "sanity");
CodeBuffer buf(blob_begin, blob_end - blob_begin); CodeBuffer buf(blob_begin, blob_end - blob_begin);
buf.initialize_consts_size(MAX_const_size); buf.initialize_consts_size(_scratch_const_size);
buf.initialize_stubs_size(MAX_stubs_size); buf.initialize_stubs_size(MAX_stubs_size);
assert(locs_buf != NULL, "sanity"); assert(locs_buf != NULL, "sanity");
int lsize = MAX_locs_size / 2; int lsize = MAX_locs_size / 3;
buf.insts()->initialize_shared_locs(&locs_buf[0], lsize); buf.consts()->initialize_shared_locs(&locs_buf[lsize * 0], lsize);
buf.stubs()->initialize_shared_locs(&locs_buf[lsize], lsize); buf.insts()->initialize_shared_locs( &locs_buf[lsize * 1], lsize);
buf.stubs()->initialize_shared_locs( &locs_buf[lsize * 2], lsize);
// Do the emission.
n->emit(buf, this->regalloc()); n->emit(buf, this->regalloc());
// End scratch_emit_size section.
set_in_scratch_emit_size(false);
return buf.insts_size(); return buf.insts_size();
} }
...@@ -516,10 +546,13 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr ...@@ -516,10 +546,13 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
_orig_pc_slot(0), _orig_pc_slot(0),
_orig_pc_slot_offset_in_bytes(0), _orig_pc_slot_offset_in_bytes(0),
_has_method_handle_invokes(false), _has_method_handle_invokes(false),
_mach_constant_base_node(NULL),
_node_bundling_limit(0), _node_bundling_limit(0),
_node_bundling_base(NULL), _node_bundling_base(NULL),
_java_calls(0), _java_calls(0),
_inner_loops(0), _inner_loops(0),
_scratch_const_size(-1),
_in_scratch_emit_size(false),
#ifndef PRODUCT #ifndef PRODUCT
_trace_opto_output(TraceOptoOutput || method()->has_option("TraceOptoOutput")), _trace_opto_output(TraceOptoOutput || method()->has_option("TraceOptoOutput")),
_printer(IdealGraphPrinter::printer()), _printer(IdealGraphPrinter::printer()),
...@@ -783,6 +816,7 @@ Compile::Compile( ciEnv* ci_env, ...@@ -783,6 +816,7 @@ Compile::Compile( ciEnv* ci_env,
_failure_reason(NULL), _failure_reason(NULL),
_code_buffer("Compile::Fill_buffer"), _code_buffer("Compile::Fill_buffer"),
_has_method_handle_invokes(false), _has_method_handle_invokes(false),
_mach_constant_base_node(NULL),
_node_bundling_limit(0), _node_bundling_limit(0),
_node_bundling_base(NULL), _node_bundling_base(NULL),
_java_calls(0), _java_calls(0),
...@@ -2862,3 +2896,207 @@ Compile::TracePhase::~TracePhase() { ...@@ -2862,3 +2896,207 @@ Compile::TracePhase::~TracePhase() {
_log->done("phase nodes='%d'", C->unique()); _log->done("phase nodes='%d'", C->unique());
} }
} }
//=============================================================================
// Two Constant's are equal when the type and the value are equal.
bool Compile::Constant::operator==(const Constant& other) {
if (type() != other.type() ) return false;
if (can_be_reused() != other.can_be_reused()) return false;
// For floating point values we compare the bit pattern.
switch (type()) {
case T_FLOAT: return (_value.i == other._value.i);
case T_LONG:
case T_DOUBLE: return (_value.j == other._value.j);
case T_OBJECT:
case T_ADDRESS: return (_value.l == other._value.l);
case T_VOID: return (_value.l == other._value.l); // jump-table entries
default: ShouldNotReachHere();
}
return false;
}
// Emit constants grouped in the following order:
static BasicType type_order[] = {
T_FLOAT, // 32-bit
T_OBJECT, // 32 or 64-bit
T_ADDRESS, // 32 or 64-bit
T_DOUBLE, // 64-bit
T_LONG, // 64-bit
T_VOID, // 32 or 64-bit (jump-tables are at the end of the constant table for code emission reasons)
T_ILLEGAL
};
static int type_to_size_in_bytes(BasicType t) {
switch (t) {
case T_LONG: return sizeof(jlong );
case T_FLOAT: return sizeof(jfloat );
case T_DOUBLE: return sizeof(jdouble);
// We use T_VOID as marker for jump-table entries (labels) which
// need an interal word relocation.
case T_VOID:
case T_ADDRESS:
case T_OBJECT: return sizeof(jobject);
}
ShouldNotReachHere();
return -1;
}
void Compile::ConstantTable::calculate_offsets_and_size() {
int size = 0;
for (int t = 0; type_order[t] != T_ILLEGAL; t++) {
BasicType type = type_order[t];
for (int i = 0; i < _constants.length(); i++) {
Constant con = _constants.at(i);
if (con.type() != type) continue; // Skip other types.
// Align size for type.
int typesize = type_to_size_in_bytes(con.type());
size = align_size_up(size, typesize);
// Set offset.
con.set_offset(size);
_constants.at_put(i, con);
// Add type size.
size = size + typesize;
}
}
// Align size up to the next section start (which is insts; see
// CodeBuffer::align_at_start).
assert(_size == -1, "already set?");
_size = align_size_up(size, CodeEntryAlignment);
if (Matcher::constant_table_absolute_addressing) {
set_table_base_offset(0); // No table base offset required
} else {
if (UseRDPCForConstantTableBase) {
// table base offset is set in MachConstantBaseNode::emit
} else {
// When RDPC is not used, the table base is set into the middle of
// the constant table.
int half_size = _size / 2;
assert(half_size * 2 == _size, "sanity");
set_table_base_offset(-half_size);
}
}
}
void Compile::ConstantTable::emit(CodeBuffer& cb) {
MacroAssembler _masm(&cb);
for (int t = 0; type_order[t] != T_ILLEGAL; t++) {
BasicType type = type_order[t];
for (int i = 0; i < _constants.length(); i++) {
Constant con = _constants.at(i);
if (con.type() != type) continue; // Skip other types.
address constant_addr;
switch (con.type()) {
case T_LONG: constant_addr = _masm.long_constant( con.get_jlong() ); break;
case T_FLOAT: constant_addr = _masm.float_constant( con.get_jfloat() ); break;
case T_DOUBLE: constant_addr = _masm.double_constant(con.get_jdouble()); break;
case T_OBJECT: {
jobject obj = con.get_jobject();
int oop_index = _masm.oop_recorder()->find_index(obj);
constant_addr = _masm.address_constant((address) obj, oop_Relocation::spec(oop_index));
break;
}
case T_ADDRESS: {
address addr = (address) con.get_jobject();
constant_addr = _masm.address_constant(addr);
break;
}
// We use T_VOID as marker for jump-table entries (labels) which
// need an interal word relocation.
case T_VOID: {
// Write a dummy word. The real value is filled in later
// in fill_jump_table_in_constant_table.
address addr = (address) con.get_jobject();
constant_addr = _masm.address_constant(addr);
break;
}
default: ShouldNotReachHere();
}
assert(constant_addr != NULL, "consts section too small");
assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), err_msg("must be: %d == %d", constant_addr - _masm.code()->consts()->start(), con.offset()));
}
}
}
int Compile::ConstantTable::find_offset(Constant& con) const {
int idx = _constants.find(con);
assert(idx != -1, "constant must be in constant table");
int offset = _constants.at(idx).offset();
assert(offset != -1, "constant table not emitted yet?");
return offset;
}
void Compile::ConstantTable::add(Constant& con) {
if (con.can_be_reused()) {
int idx = _constants.find(con);
if (idx != -1 && _constants.at(idx).can_be_reused()) {
return;
}
}
(void) _constants.append(con);
}
Compile::Constant Compile::ConstantTable::add(BasicType type, jvalue value) {
Constant con(type, value);
add(con);
return con;
}
Compile::Constant Compile::ConstantTable::add(MachOper* oper) {
jvalue value;
BasicType type = oper->type()->basic_type();
switch (type) {
case T_LONG: value.j = oper->constantL(); break;
case T_FLOAT: value.f = oper->constantF(); break;
case T_DOUBLE: value.d = oper->constantD(); break;
case T_OBJECT:
case T_ADDRESS: value.l = (jobject) oper->constant(); break;
default: ShouldNotReachHere();
}
return add(type, value);
}
Compile::Constant Compile::ConstantTable::allocate_jump_table(MachConstantNode* n) {
jvalue value;
// We can use the node pointer here to identify the right jump-table
// as this method is called from Compile::Fill_buffer right before
// the MachNodes are emitted and the jump-table is filled (means the
// MachNode pointers do not change anymore).
value.l = (jobject) n;
Constant con(T_VOID, value, false); // Labels of a jump-table cannot be reused.
for (uint i = 0; i < n->outcnt(); i++) {
add(con);
}
return con;
}
void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const {
// If called from Compile::scratch_emit_size do nothing.
if (Compile::current()->in_scratch_emit_size()) return;
assert(labels.is_nonempty(), "must be");
assert((uint) labels.length() == n->outcnt(), err_msg("must be equal: %d == %d", labels.length(), n->outcnt()));
// Since MachConstantNode::constant_offset() also contains
// table_base_offset() we need to subtract the table_base_offset()
// to get the plain offset into the constant table.
int offset = n->constant_offset() - table_base_offset();
MacroAssembler _masm(&cb);
address* jump_table_base = (address*) (_masm.code()->consts()->start() + offset);
for (int i = 0; i < labels.length(); i++) {
address* constant_addr = &jump_table_base[i];
assert(*constant_addr == (address) n, "all jump-table entries must contain node pointer");
*constant_addr = cb.consts()->target(*labels.at(i), (address) constant_addr);
cb.consts()->relocate((address) constant_addr, relocInfo::internal_word_type);
}
}
...@@ -48,7 +48,10 @@ class ConnectionGraph; ...@@ -48,7 +48,10 @@ class ConnectionGraph;
class InlineTree; class InlineTree;
class Int_Array; class Int_Array;
class Matcher; class Matcher;
class MachConstantNode;
class MachConstantBaseNode;
class MachNode; class MachNode;
class MachOper;
class MachSafePointNode; class MachSafePointNode;
class Node; class Node;
class Node_Array; class Node_Array;
...@@ -139,6 +142,81 @@ class Compile : public Phase { ...@@ -139,6 +142,81 @@ class Compile : public Phase {
trapHistLength = methodDataOopDesc::_trap_hist_limit trapHistLength = methodDataOopDesc::_trap_hist_limit
}; };
// Constant entry of the constant table.
class Constant {
private:
BasicType _type;
jvalue _value;
int _offset; // offset of this constant (in bytes) relative to the constant table base.
bool _can_be_reused; // true (default) if the value can be shared with other users.
public:
Constant() : _type(T_ILLEGAL), _offset(-1), _can_be_reused(true) { _value.l = 0; }
Constant(BasicType type, jvalue value, bool can_be_reused = true) :
_type(type),
_value(value),
_offset(-1),
_can_be_reused(can_be_reused)
{}
bool operator==(const Constant& other);
BasicType type() const { return _type; }
jlong get_jlong() const { return _value.j; }
jfloat get_jfloat() const { return _value.f; }
jdouble get_jdouble() const { return _value.d; }
jobject get_jobject() const { return _value.l; }
int offset() const { return _offset; }
void set_offset(int offset) { _offset = offset; }
bool can_be_reused() const { return _can_be_reused; }
};
// Constant table.
class ConstantTable {
private:
GrowableArray<Constant> _constants; // Constants of this table.
int _size; // Size in bytes the emitted constant table takes (including padding).
int _table_base_offset; // Offset of the table base that gets added to the constant offsets.
public:
ConstantTable() :
_size(-1),
_table_base_offset(-1) // We can use -1 here since the constant table is always bigger than 2 bytes (-(size / 2), see MachConstantBaseNode::emit).
{}
int size() const { assert(_size != -1, "size not yet calculated"); return _size; }
void set_table_base_offset(int x) { assert(_table_base_offset == -1, "set only once"); _table_base_offset = x; }
int table_base_offset() const { assert(_table_base_offset != -1, "table base offset not yet set"); return _table_base_offset; }
void emit(CodeBuffer& cb);
// Returns the offset of the last entry (the top) of the constant table.
int top_offset() const { assert(_constants.top().offset() != -1, "constant not yet bound"); return _constants.top().offset(); }
void calculate_offsets_and_size();
int find_offset(Constant& con) const;
void add(Constant& con);
Constant add(BasicType type, jvalue value);
Constant add(MachOper* oper);
Constant add(jfloat f) {
jvalue value; value.f = f;
return add(T_FLOAT, value);
}
Constant add(jdouble d) {
jvalue value; value.d = d;
return add(T_DOUBLE, value);
}
// Jump table
Constant allocate_jump_table(MachConstantNode* n);
void fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const;
};
private: private:
// Fixed parameters to this compilation. // Fixed parameters to this compilation.
const int _compile_id; const int _compile_id;
...@@ -212,6 +290,11 @@ class Compile : public Phase { ...@@ -212,6 +290,11 @@ class Compile : public Phase {
Node* _recent_alloc_obj; Node* _recent_alloc_obj;
Node* _recent_alloc_ctl; Node* _recent_alloc_ctl;
// Constant table
ConstantTable _constant_table; // The constant table for this compile.
MachConstantBaseNode* _mach_constant_base_node; // Constant table base node singleton.
// Blocked array of debugging and profiling information, // Blocked array of debugging and profiling information,
// tracked per node. // tracked per node.
enum { _log2_node_notes_block_size = 8, enum { _log2_node_notes_block_size = 8,
...@@ -272,6 +355,8 @@ class Compile : public Phase { ...@@ -272,6 +355,8 @@ class Compile : public Phase {
static int _CompiledZap_count; // counter compared against CompileZap[First/Last] static int _CompiledZap_count; // counter compared against CompileZap[First/Last]
BufferBlob* _scratch_buffer_blob; // For temporary code buffers. BufferBlob* _scratch_buffer_blob; // For temporary code buffers.
relocInfo* _scratch_locs_memory; // For temporary code buffers. relocInfo* _scratch_locs_memory; // For temporary code buffers.
int _scratch_const_size; // For temporary code buffers.
bool _in_scratch_emit_size; // true when in scratch_emit_size.
public: public:
// Accessors // Accessors
...@@ -454,6 +539,12 @@ class Compile : public Phase { ...@@ -454,6 +539,12 @@ class Compile : public Phase {
_recent_alloc_obj = obj; _recent_alloc_obj = obj;
} }
// Constant table
ConstantTable& constant_table() { return _constant_table; }
MachConstantBaseNode* mach_constant_base_node();
bool has_mach_constant_base_node() const { return _mach_constant_base_node != NULL; }
// Handy undefined Node // Handy undefined Node
Node* top() const { return _top; } Node* top() const { return _top; }
...@@ -605,13 +696,16 @@ class Compile : public Phase { ...@@ -605,13 +696,16 @@ class Compile : public Phase {
Dependencies* dependencies() { return env()->dependencies(); } Dependencies* dependencies() { return env()->dependencies(); }
static int CompiledZap_count() { return _CompiledZap_count; } static int CompiledZap_count() { return _CompiledZap_count; }
BufferBlob* scratch_buffer_blob() { return _scratch_buffer_blob; } BufferBlob* scratch_buffer_blob() { return _scratch_buffer_blob; }
void init_scratch_buffer_blob(); void init_scratch_buffer_blob(int const_size);
void clear_scratch_buffer_blob();
void set_scratch_buffer_blob(BufferBlob* b) { _scratch_buffer_blob = b; } void set_scratch_buffer_blob(BufferBlob* b) { _scratch_buffer_blob = b; }
relocInfo* scratch_locs_memory() { return _scratch_locs_memory; } relocInfo* scratch_locs_memory() { return _scratch_locs_memory; }
void set_scratch_locs_memory(relocInfo* b) { _scratch_locs_memory = b; } void set_scratch_locs_memory(relocInfo* b) { _scratch_locs_memory = b; }
// emit to scratch blob, report resulting size // emit to scratch blob, report resulting size
uint scratch_emit_size(const Node* n); uint scratch_emit_size(const Node* n);
void set_in_scratch_emit_size(bool x) { _in_scratch_emit_size = x; }
bool in_scratch_emit_size() const { return _in_scratch_emit_size; }
enum ScratchBufferBlob { enum ScratchBufferBlob {
MAX_inst_size = 1024, MAX_inst_size = 1024,
...@@ -692,7 +786,7 @@ class Compile : public Phase { ...@@ -692,7 +786,7 @@ class Compile : public Phase {
void Fill_buffer(); void Fill_buffer();
// Determine which variable sized branches can be shortened // Determine which variable sized branches can be shortened
void Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size, int& const_size); void Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size);
// Compute the size of first NumberOfLoopInstrToAlign instructions // Compute the size of first NumberOfLoopInstrToAlign instructions
// at the head of a loop. // at the head of a loop.
......
...@@ -89,7 +89,7 @@ void PhaseCFG::replace_block_proj_ctrl( Node *n ) { ...@@ -89,7 +89,7 @@ void PhaseCFG::replace_block_proj_ctrl( Node *n ) {
assert(in0 != NULL, "Only control-dependent"); assert(in0 != NULL, "Only control-dependent");
const Node *p = in0->is_block_proj(); const Node *p = in0->is_block_proj();
if (p != NULL && p != n) { // Control from a block projection? if (p != NULL && p != n) { // Control from a block projection?
assert(!n->pinned() || n->is_SafePointScalarObject(), "only SafePointScalarObject pinned node is expected here"); assert(!n->pinned() || n->is_MachConstantBase() || n->is_SafePointScalarObject(), "only pinned MachConstantBase or SafePointScalarObject node is expected here");
// Find trailing Region // Find trailing Region
Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block
uint j = 0; uint j = 0;
......
...@@ -489,6 +489,20 @@ void MachTypeNode::dump_spec(outputStream *st) const { ...@@ -489,6 +489,20 @@ void MachTypeNode::dump_spec(outputStream *st) const {
} }
#endif #endif
//=============================================================================
int MachConstantNode::constant_offset() {
int offset = _constant.offset();
// Bind the offset lazily.
if (offset == -1) {
Compile::ConstantTable& constant_table = Compile::current()->constant_table();
offset = constant_table.table_base_offset() + constant_table.find_offset(_constant);
_constant.set_offset(offset);
}
return offset;
}
//============================================================================= //=============================================================================
#ifndef PRODUCT #ifndef PRODUCT
void MachNullCheckNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { void MachNullCheckNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
......
...@@ -231,9 +231,6 @@ public: ...@@ -231,9 +231,6 @@ public:
// Return number of relocatable values contained in this instruction // Return number of relocatable values contained in this instruction
virtual int reloc() const { return 0; } virtual int reloc() const { return 0; }
// Return number of words used for double constants in this instruction
virtual int const_size() const { return 0; }
// Hash and compare over operands. Used to do GVN on machine Nodes. // Hash and compare over operands. Used to do GVN on machine Nodes.
virtual uint hash() const; virtual uint hash() const;
virtual uint cmp( const Node &n ) const; virtual uint cmp( const Node &n ) const;
...@@ -348,6 +345,65 @@ public: ...@@ -348,6 +345,65 @@ public:
#endif #endif
}; };
//------------------------------MachConstantBaseNode--------------------------
// Machine node that represents the base address of the constant table.
class MachConstantBaseNode : public MachIdealNode {
public:
static const RegMask& _out_RegMask; // We need the out_RegMask statically in MachConstantNode::in_RegMask().
public:
MachConstantBaseNode() : MachIdealNode() {
init_class_id(Class_MachConstantBase);
}
virtual const class Type* bottom_type() const { return TypeRawPtr::NOTNULL; }
virtual uint ideal_reg() const { return Op_RegP; }
virtual uint oper_input_base() const { return 1; }
virtual void emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const;
virtual uint size(PhaseRegAlloc* ra_) const;
virtual bool pinned() const { return UseRDPCForConstantTableBase; }
static const RegMask& static_out_RegMask() { return _out_RegMask; }
virtual const RegMask& out_RegMask() const { return static_out_RegMask(); }
#ifndef PRODUCT
virtual const char* Name() const { return "MachConstantBaseNode"; }
virtual void format(PhaseRegAlloc*, outputStream* st) const;
#endif
};
//------------------------------MachConstantNode-------------------------------
// Machine node that holds a constant which is stored in the constant table.
class MachConstantNode : public MachNode {
protected:
Compile::Constant _constant; // This node's constant.
public:
MachConstantNode() : MachNode() {
init_class_id(Class_MachConstant);
}
virtual void eval_constant(Compile* C) {
#ifdef ASSERT
tty->print("missing MachConstantNode eval_constant function: ");
dump();
#endif
ShouldNotCallThis();
}
virtual const RegMask &in_RegMask(uint idx) const {
if (idx == mach_constant_base_node_input())
return MachConstantBaseNode::static_out_RegMask();
return MachNode::in_RegMask(idx);
}
// Input edge of MachConstantBaseNode.
uint mach_constant_base_node_input() const { return req() - 1; }
int constant_offset();
int constant_offset() const { return ((MachConstantNode*) this)->constant_offset(); }
};
//------------------------------MachUEPNode----------------------------------- //------------------------------MachUEPNode-----------------------------------
// Machine Unvalidated Entry Point Node // Machine Unvalidated Entry Point Node
class MachUEPNode : public MachIdealNode { class MachUEPNode : public MachIdealNode {
......
...@@ -365,6 +365,10 @@ public: ...@@ -365,6 +365,10 @@ public:
// registers? True for Intel but false for most RISCs // registers? True for Intel but false for most RISCs
static const bool clone_shift_expressions; static const bool clone_shift_expressions;
// Should constant table entries be accessed with loads using
// absolute addressing? True for x86 but false for most RISCs.
static const bool constant_table_absolute_addressing;
static bool narrow_oop_use_complex_address(); static bool narrow_oop_use_complex_address();
// Generate implicit null check for narrow oops if it can fold // Generate implicit null check for narrow oops if it can fold
......
...@@ -81,6 +81,8 @@ class MachCallLeafNode; ...@@ -81,6 +81,8 @@ class MachCallLeafNode;
class MachCallNode; class MachCallNode;
class MachCallRuntimeNode; class MachCallRuntimeNode;
class MachCallStaticJavaNode; class MachCallStaticJavaNode;
class MachConstantBaseNode;
class MachConstantNode;
class MachIfNode; class MachIfNode;
class MachNode; class MachNode;
class MachNullCheckNode; class MachNullCheckNode;
...@@ -566,10 +568,12 @@ public: ...@@ -566,10 +568,12 @@ public:
DEFINE_CLASS_ID(MachCallDynamicJava, MachCallJava, 1) DEFINE_CLASS_ID(MachCallDynamicJava, MachCallJava, 1)
DEFINE_CLASS_ID(MachCallRuntime, MachCall, 1) DEFINE_CLASS_ID(MachCallRuntime, MachCall, 1)
DEFINE_CLASS_ID(MachCallLeaf, MachCallRuntime, 0) DEFINE_CLASS_ID(MachCallLeaf, MachCallRuntime, 0)
DEFINE_CLASS_ID(MachSpillCopy, Mach, 1) DEFINE_CLASS_ID(MachSpillCopy, Mach, 1)
DEFINE_CLASS_ID(MachNullCheck, Mach, 2) DEFINE_CLASS_ID(MachNullCheck, Mach, 2)
DEFINE_CLASS_ID(MachIf, Mach, 3) DEFINE_CLASS_ID(MachIf, Mach, 3)
DEFINE_CLASS_ID(MachTemp, Mach, 4) DEFINE_CLASS_ID(MachTemp, Mach, 4)
DEFINE_CLASS_ID(MachConstantBase, Mach, 5)
DEFINE_CLASS_ID(MachConstant, Mach, 6)
DEFINE_CLASS_ID(Proj, Node, 2) DEFINE_CLASS_ID(Proj, Node, 2)
DEFINE_CLASS_ID(CatchProj, Proj, 0) DEFINE_CLASS_ID(CatchProj, Proj, 0)
...@@ -734,6 +738,8 @@ public: ...@@ -734,6 +738,8 @@ public:
DEFINE_CLASS_QUERY(MachCallLeaf) DEFINE_CLASS_QUERY(MachCallLeaf)
DEFINE_CLASS_QUERY(MachCallRuntime) DEFINE_CLASS_QUERY(MachCallRuntime)
DEFINE_CLASS_QUERY(MachCallStaticJava) DEFINE_CLASS_QUERY(MachCallStaticJava)
DEFINE_CLASS_QUERY(MachConstantBase)
DEFINE_CLASS_QUERY(MachConstant)
DEFINE_CLASS_QUERY(MachIf) DEFINE_CLASS_QUERY(MachIf)
DEFINE_CLASS_QUERY(MachNullCheck) DEFINE_CLASS_QUERY(MachNullCheck)
DEFINE_CLASS_QUERY(MachReturn) DEFINE_CLASS_QUERY(MachReturn)
......
...@@ -61,11 +61,6 @@ void Compile::Output() { ...@@ -61,11 +61,6 @@ void Compile::Output() {
// RootNode goes // RootNode goes
assert( _cfg->_broot->_nodes.size() == 0, "" ); assert( _cfg->_broot->_nodes.size() == 0, "" );
// Initialize the space for the BufferBlob used to find and verify
// instruction size in MachNode::emit_size()
init_scratch_buffer_blob();
if (failing()) return; // Out of memory
// The number of new nodes (mostly MachNop) is proportional to // The number of new nodes (mostly MachNop) is proportional to
// the number of java calls and inner loops which are aligned. // the number of java calls and inner loops which are aligned.
if ( C->check_node_count((NodeLimitFudgeFactor + C->java_calls()*3 + if ( C->check_node_count((NodeLimitFudgeFactor + C->java_calls()*3 +
...@@ -333,7 +328,7 @@ void Compile::compute_loop_first_inst_sizes() { ...@@ -333,7 +328,7 @@ void Compile::compute_loop_first_inst_sizes() {
//----------------------Shorten_branches--------------------------------------- //----------------------Shorten_branches---------------------------------------
// The architecture description provides short branch variants for some long // The architecture description provides short branch variants for some long
// branch instructions. Replace eligible long branches with short branches. // branch instructions. Replace eligible long branches with short branches.
void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size, int& const_size) { void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, int& stub_size) {
// fill in the nop array for bundling computations // fill in the nop array for bundling computations
MachNode *_nop_list[Bundle::_nop_count]; MachNode *_nop_list[Bundle::_nop_count];
...@@ -353,12 +348,11 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i ...@@ -353,12 +348,11 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
// Size in bytes of all relocation entries, including those in local stubs. // Size in bytes of all relocation entries, including those in local stubs.
// Start with 2-bytes of reloc info for the unvalidated entry point // Start with 2-bytes of reloc info for the unvalidated entry point
reloc_size = 1; // Number of relocation entries reloc_size = 1; // Number of relocation entries
const_size = 0; // size of fp constants in words
// Make three passes. The first computes pessimistic blk_starts, // Make three passes. The first computes pessimistic blk_starts,
// relative jmp_end, reloc_size and const_size information. // relative jmp_end and reloc_size information. The second performs
// The second performs short branch substitution using the pessimistic // short branch substitution using the pessimistic sizing. The
// sizing. The third inserts nops where needed. // third inserts nops where needed.
Node *nj; // tmp Node *nj; // tmp
...@@ -381,7 +375,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i ...@@ -381,7 +375,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
MachNode *mach = nj->as_Mach(); MachNode *mach = nj->as_Mach();
blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding
reloc_size += mach->reloc(); reloc_size += mach->reloc();
const_size += mach->const_size();
if( mach->is_MachCall() ) { if( mach->is_MachCall() ) {
MachCallNode *mcall = mach->as_MachCall(); MachCallNode *mcall = mach->as_MachCall();
// This destination address is NOT PC-relative // This destination address is NOT PC-relative
...@@ -398,10 +391,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i ...@@ -398,10 +391,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
if (min_offset_from_last_call == 0) { if (min_offset_from_last_call == 0) {
blk_size += nop_size; blk_size += nop_size;
} }
} else if (mach->ideal_Opcode() == Op_Jump) {
const_size += b->_num_succs; // Address table size
// The size is valid even for 64 bit since it is
// multiplied by 2*jintSize on this method exit.
} }
} }
min_offset_from_last_call += inst_size; min_offset_from_last_call += inst_size;
...@@ -562,10 +551,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i ...@@ -562,10 +551,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
// a relocation index. // a relocation index.
// The CodeBuffer will expand the locs array if this estimate is too low. // The CodeBuffer will expand the locs array if this estimate is too low.
reloc_size *= 10 / sizeof(relocInfo); reloc_size *= 10 / sizeof(relocInfo);
// Adjust const_size to number of bytes
const_size *= 2*jintSize; // both float and double take two words per entry
} }
//------------------------------FillLocArray----------------------------------- //------------------------------FillLocArray-----------------------------------
...@@ -1102,10 +1087,39 @@ void Compile::Fill_buffer() { ...@@ -1102,10 +1087,39 @@ void Compile::Fill_buffer() {
blk_labels[i].init(); blk_labels[i].init();
} }
if (has_mach_constant_base_node()) {
// Fill the constant table.
// Note: This must happen before Shorten_branches.
for (i = 0; i < _cfg->_num_blocks; i++) {
Block* b = _cfg->_blocks[i];
for (uint j = 0; j < b->_nodes.size(); j++) {
Node* n = b->_nodes[j];
// If the node is a MachConstantNode evaluate the constant
// value section.
if (n->is_MachConstant()) {
MachConstantNode* machcon = n->as_MachConstant();
machcon->eval_constant(C);
}
}
}
// Calculate the offsets of the constants and the size of the
// constant table (including the padding to the next section).
constant_table().calculate_offsets_and_size();
const_req = constant_table().size();
}
// Initialize the space for the BufferBlob used to find and verify
// instruction size in MachNode::emit_size()
init_scratch_buffer_blob(const_req);
if (failing()) return; // Out of memory
// If this machine supports different size branch offsets, then pre-compute // If this machine supports different size branch offsets, then pre-compute
// the length of the blocks // the length of the blocks
if( _matcher->is_short_branch_offset(-1, 0) ) { if( _matcher->is_short_branch_offset(-1, 0) ) {
Shorten_branches(blk_labels, code_req, locs_req, stub_req, const_req); Shorten_branches(blk_labels, code_req, locs_req, stub_req);
labels_not_set = false; labels_not_set = false;
} }
...@@ -1121,12 +1135,12 @@ void Compile::Fill_buffer() { ...@@ -1121,12 +1135,12 @@ void Compile::Fill_buffer() {
code_req = const_req = stub_req = exception_handler_req = deopt_handler_req = 0x10; // force expansion code_req = const_req = stub_req = exception_handler_req = deopt_handler_req = 0x10; // force expansion
int total_req = int total_req =
const_req +
code_req + code_req +
pad_req + pad_req +
stub_req + stub_req +
exception_handler_req + exception_handler_req +
deopt_handler_req + // deopt handler deopt_handler_req; // deopt handler
const_req;
if (has_method_handle_invokes()) if (has_method_handle_invokes())
total_req += deopt_handler_req; // deopt MH handler total_req += deopt_handler_req; // deopt MH handler
...@@ -1180,6 +1194,11 @@ void Compile::Fill_buffer() { ...@@ -1180,6 +1194,11 @@ void Compile::Fill_buffer() {
NonSafepointEmitter non_safepoints(this); // emit non-safepoints lazily NonSafepointEmitter non_safepoints(this); // emit non-safepoints lazily
// Emit the constant table.
if (has_mach_constant_base_node()) {
constant_table().emit(*cb);
}
// ------------------ // ------------------
// Now fill in the code buffer // Now fill in the code buffer
Node *delay_slot = NULL; Node *delay_slot = NULL;
...@@ -1196,12 +1215,13 @@ void Compile::Fill_buffer() { ...@@ -1196,12 +1215,13 @@ void Compile::Fill_buffer() {
cb->flush_bundle(true); cb->flush_bundle(true);
// Define the label at the beginning of the basic block // Define the label at the beginning of the basic block
if( labels_not_set ) if (labels_not_set) {
MacroAssembler(cb).bind( blk_labels[b->_pre_order] ); MacroAssembler(cb).bind(blk_labels[b->_pre_order]);
} else {
else assert(blk_labels[b->_pre_order].loc_pos() == cb->insts_size(),
assert( blk_labels[b->_pre_order].loc_pos() == cb->insts_size(), err_msg("label position does not match code offset: %d != %d",
"label position does not match code offset" ); blk_labels[b->_pre_order].loc_pos(), cb->insts_size()));
}
uint last_inst = b->_nodes.size(); uint last_inst = b->_nodes.size();
...@@ -1718,9 +1738,17 @@ void Compile::ScheduleAndBundle() { ...@@ -1718,9 +1738,17 @@ void Compile::ScheduleAndBundle() {
// Create a data structure for all the scheduling information // Create a data structure for all the scheduling information
Scheduling scheduling(Thread::current()->resource_area(), *this); Scheduling scheduling(Thread::current()->resource_area(), *this);
// Initialize the space for the BufferBlob used to find and verify
// instruction size in MachNode::emit_size()
init_scratch_buffer_blob(MAX_const_size);
if (failing()) return; // Out of memory
// Walk backwards over each basic block, computing the needed alignment // Walk backwards over each basic block, computing the needed alignment
// Walk over all the basic blocks // Walk over all the basic blocks
scheduling.DoScheduling(); scheduling.DoScheduling();
// Clear the BufferBlob used for scheduling.
clear_scratch_buffer_blob();
} }
//------------------------------ComputeLocalLatenciesForward------------------- //------------------------------ComputeLocalLatenciesForward-------------------
......
...@@ -200,6 +200,19 @@ int PhaseChaitin::elide_copy( Node *n, int k, Block *current_block, Node_List &v ...@@ -200,6 +200,19 @@ int PhaseChaitin::elide_copy( Node *n, int k, Block *current_block, Node_List &v
// then reloaded BUT survives in a register the whole way. // then reloaded BUT survives in a register the whole way.
Node *val = skip_copies(n->in(k)); Node *val = skip_copies(n->in(k));
if (val == x && nk_idx != 0 &&
regnd[nk_reg] != NULL && regnd[nk_reg] != x &&
n2lidx(x) == n2lidx(regnd[nk_reg])) {
// When rematerialzing nodes and stretching lifetimes, the
// allocator will reuse the original def for multidef LRG instead
// of the current reaching def because it can't know it's safe to
// do so. After allocation completes if they are in the same LRG
// then it should use the current reaching def instead.
n->set_req(k, regnd[nk_reg]);
blk_adjust += yank_if_dead(val, current_block, &value, &regnd);
val = skip_copies(n->in(k));
}
if( val == x ) return blk_adjust; // No progress? if( val == x ) return blk_adjust; // No progress?
bool single = is_single_register(val->ideal_reg()); bool single = is_single_register(val->ideal_reg());
......
...@@ -399,8 +399,14 @@ extern "C" void nm(intptr_t p) { ...@@ -399,8 +399,14 @@ extern "C" void nm(intptr_t p) {
extern "C" void disnm(intptr_t p) { extern "C" void disnm(intptr_t p) {
Command c("disnm"); Command c("disnm");
CodeBlob* cb = CodeCache::find_blob((address) p); CodeBlob* cb = CodeCache::find_blob((address) p);
cb->print(); nmethod* nm = cb->as_nmethod_or_null();
Disassembler::decode(cb); if (nm) {
nm->print();
Disassembler::decode(nm);
} else {
cb->print();
Disassembler::decode(cb);
}
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册