mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-30 21:18:25 +00:00
6961690: load oops from constant table on SPARC
Oops should be loaded from the constant table of an nmethod instead of materializing them with a long code sequence. Reviewed-by: never, kvn
This commit is contained in:
parent
ab725dba1d
commit
ffaadcecea
@ -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
|
||||
// number of extraWords
|
||||
int MacroAssembler::total_frame_size_in_bytes(int extraWords) {
|
||||
|
||||
@ -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, 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, 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) ); }
|
||||
@ -1895,6 +1899,9 @@ public:
|
||||
void patchable_set(intptr_t value, Register d);
|
||||
void set64(jlong value, Register d, Register tmp);
|
||||
|
||||
// Compute size of set64.
|
||||
static int size_of_set64(jlong value);
|
||||
|
||||
// sign-extend 32 to 64
|
||||
inline void signx( Register s, Register d ) { sra( s, 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();
|
||||
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::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
|
||||
|
||||
|
||||
@ -667,6 +667,20 @@ intptr_t get_offset_from_base_2(const MachNode* n, const TypePtr* atype, int dis
|
||||
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
|
||||
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
|
||||
@ -1007,6 +1021,90 @@ void emit_lo(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
|
||||
@ -2247,25 +2345,6 @@ encode %{
|
||||
__ 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 ) %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
Label &L = *($labl$$label);
|
||||
@ -2384,20 +2463,6 @@ encode %{
|
||||
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 ) %{
|
||||
emit3_simm13( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, $src$$constant );
|
||||
%}
|
||||
@ -2411,10 +2476,6 @@ encode %{
|
||||
__ 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 %{
|
||||
if( VerifyStackAtCalls ) {
|
||||
MacroAssembler _masm(&cbuf);
|
||||
@ -2778,35 +2839,6 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
|
||||
__ 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
|
||||
enc_class enc_Clear_Array(iRegX cnt, iRegP base, iRegX temp) %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
@ -3521,6 +3553,29 @@ operand immP() %{
|
||||
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() %{
|
||||
predicate((-4096 < n->get_ptr()) && (n->get_ptr() <= 4095));
|
||||
match(ConP);
|
||||
@ -3616,6 +3671,26 @@ operand immL_32bits() %{
|
||||
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
|
||||
operand immD() %{
|
||||
match(ConD);
|
||||
@ -5981,25 +6056,58 @@ instruct loadConI13( iRegI dst, immI13 src ) %{
|
||||
ins_pipe(ialu_imm);
|
||||
%}
|
||||
|
||||
instruct loadConP(iRegP dst, immP src) %{
|
||||
match(Set dst src);
|
||||
#ifndef _LP64
|
||||
instruct loadConP(iRegP dst, immP con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(DEFAULT_COST * 3/2);
|
||||
format %{ "SET $src,$dst\t!ptr" %}
|
||||
// This rule does not use "expand" unlike loadConI because then
|
||||
// the result type is not known to be an Oop. An ADLC
|
||||
// enhancement will be needed to make that work - not worth it!
|
||||
|
||||
ins_encode( SetPtr( src, dst ) );
|
||||
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);
|
||||
|
||||
%}
|
||||
#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);
|
||||
%}
|
||||
|
||||
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) %{
|
||||
match(Set dst src);
|
||||
|
||||
size(4);
|
||||
format %{ "CLR $dst\t!ptr" %}
|
||||
ins_encode( SetNull( dst ) );
|
||||
ins_encode %{
|
||||
__ clr($dst$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_imm);
|
||||
%}
|
||||
|
||||
@ -6019,7 +6127,9 @@ instruct loadConN0(iRegN dst, immN0 src) %{
|
||||
|
||||
size(4);
|
||||
format %{ "CLR $dst\t! compressed NULL ptr" %}
|
||||
ins_encode( SetNull( dst ) );
|
||||
ins_encode %{
|
||||
__ clr($dst$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_imm);
|
||||
%}
|
||||
|
||||
@ -6034,13 +6144,26 @@ instruct loadConN(iRegN dst, immN src) %{
|
||||
ins_pipe(ialu_hi_lo_reg);
|
||||
%}
|
||||
|
||||
instruct loadConL(iRegL dst, immL src, o7RegL tmp) %{
|
||||
// %%% maybe this should work like loadConD
|
||||
match(Set dst src);
|
||||
// Materialize long value (predicated by immL_cheap).
|
||||
instruct loadConL_set64(iRegL dst, immL_cheap con, o7RegL tmp) %{
|
||||
match(Set dst con);
|
||||
effect(KILL tmp);
|
||||
ins_cost(DEFAULT_COST * 4);
|
||||
format %{ "SET64 $src,$dst KILL $tmp\t! long" %}
|
||||
ins_encode( LdImmL(src, dst, tmp) );
|
||||
ins_cost(DEFAULT_COST * 3);
|
||||
format %{ "SET64 $con,$dst KILL $tmp\t! cheap long" %}
|
||||
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);
|
||||
%}
|
||||
|
||||
@ -6063,50 +6186,24 @@ instruct loadConL13( iRegL dst, immL13 src ) %{
|
||||
ins_pipe(ialu_imm);
|
||||
%}
|
||||
|
||||
instruct loadConF(regF dst, immF src, o7RegP tmp) %{
|
||||
match(Set dst src);
|
||||
effect(KILL tmp);
|
||||
|
||||
#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" %}
|
||||
instruct loadConF(regF dst, immF con) %{
|
||||
match(Set dst con);
|
||||
size(4);
|
||||
format %{ "LDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: float=$con" %}
|
||||
ins_encode %{
|
||||
address float_address = __ float_constant($src$$constant);
|
||||
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);
|
||||
__ ldf(FloatRegisterImpl::S, $constanttablebase, $constantoffset($con), $dst$$FloatRegister);
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
instruct loadConD(regD dst, immD src, o7RegP tmp) %{
|
||||
match(Set dst src);
|
||||
effect(KILL tmp);
|
||||
|
||||
#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" %}
|
||||
instruct loadConD(regD dst, immD con) %{
|
||||
match(Set dst con);
|
||||
size(4);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: double=$con" %}
|
||||
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.
|
||||
//__ ldf(FloatRegisterImpl::D, $tmp$$Register, addrlit.low10(), $dst$$FloatRegister, rspec);
|
||||
__ ldf(FloatRegisterImpl::D, $tmp$$Register, addrlit.low10(), as_DoubleFloatRegister($dst$$reg), rspec);
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset($con), $dst$$FloatRegister);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset($con), as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
@ -8558,16 +8655,15 @@ instruct Repl8B_reg(stackSlotD dst, iRegI src) %{
|
||||
%}
|
||||
|
||||
// Replicate scalar constant to packed byte values in Double register
|
||||
instruct Repl8B_immI(regD dst, immI13 src, o7RegP tmp) %{
|
||||
match(Set dst (Replicate8B src));
|
||||
#ifdef _LP64
|
||||
size(36);
|
||||
#else
|
||||
size(8);
|
||||
#endif
|
||||
format %{ "SETHI hi(&Repl8($src)),$tmp\t!get Repl8B($src) from table\n\t"
|
||||
"LDDF [$tmp+lo(&Repl8($src))],$dst" %}
|
||||
ins_encode( LdReplImmI(src, dst, tmp, (8), (1)) );
|
||||
instruct Repl8B_immI(regD dst, immI13 con) %{
|
||||
match(Set dst (Replicate8B con));
|
||||
size(4);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl8B($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 8, 1)), $dst$$FloatRegister);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 8, 1)), as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
@ -8594,16 +8690,15 @@ instruct Repl4C_reg(stackSlotD dst, iRegI src) %{
|
||||
%}
|
||||
|
||||
// Replicate scalar constant to packed char values in Double register
|
||||
instruct Repl4C_immI(regD dst, immI src, o7RegP tmp) %{
|
||||
match(Set dst (Replicate4C src));
|
||||
#ifdef _LP64
|
||||
size(36);
|
||||
#else
|
||||
size(8);
|
||||
#endif
|
||||
format %{ "SETHI hi(&Repl4($src)),$tmp\t!get Repl4C($src) from table\n\t"
|
||||
"LDDF [$tmp+lo(&Repl4($src))],$dst" %}
|
||||
ins_encode( LdReplImmI(src, dst, tmp, (4), (2)) );
|
||||
instruct Repl4C_immI(regD dst, immI con) %{
|
||||
match(Set dst (Replicate4C con));
|
||||
size(4);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4C($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
@ -8630,16 +8725,15 @@ instruct Repl4S_reg(stackSlotD dst, iRegI src) %{
|
||||
%}
|
||||
|
||||
// Replicate scalar constant to packed short values in Double register
|
||||
instruct Repl4S_immI(regD dst, immI src, o7RegP tmp) %{
|
||||
match(Set dst (Replicate4S src));
|
||||
#ifdef _LP64
|
||||
size(36);
|
||||
#else
|
||||
size(8);
|
||||
#endif
|
||||
format %{ "SETHI hi(&Repl4($src)),$tmp\t!get Repl4S($src) from table\n\t"
|
||||
"LDDF [$tmp+lo(&Repl4($src))],$dst" %}
|
||||
ins_encode( LdReplImmI(src, dst, tmp, (4), (2)) );
|
||||
instruct Repl4S_immI(regD dst, immI con) %{
|
||||
match(Set dst (Replicate4S con));
|
||||
size(4);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4S($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
@ -8664,16 +8758,15 @@ instruct Repl2I_reg(stackSlotD dst, iRegI src) %{
|
||||
%}
|
||||
|
||||
// Replicate scalar zero constant to packed int values in Double register
|
||||
instruct Repl2I_immI(regD dst, immI src, o7RegP tmp) %{
|
||||
match(Set dst (Replicate2I src));
|
||||
#ifdef _LP64
|
||||
size(36);
|
||||
#else
|
||||
size(8);
|
||||
#endif
|
||||
format %{ "SETHI hi(&Repl2($src)),$tmp\t!get Repl2I($src) from table\n\t"
|
||||
"LDDF [$tmp+lo(&Repl2($src))],$dst" %}
|
||||
ins_encode( LdReplImmI(src, dst, tmp, (2), (4)) );
|
||||
instruct Repl2I_immI(regD dst, immI con) %{
|
||||
match(Set dst (Replicate2I con));
|
||||
size(4);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2I($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 2, 4)), $dst$$FloatRegister);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 2, 4)), as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
@ -8929,12 +9022,26 @@ instruct jumpXtnd(iRegX switch_val, o7RegI table) %{
|
||||
|
||||
ins_cost(350);
|
||||
|
||||
format %{ "SETHI [hi(table_base)],O7\n\t"
|
||||
"ADD O7, lo(table_base), O7\n\t"
|
||||
"LD [O7+$switch_val], O7\n\t"
|
||||
format %{ "ADD $constanttablebase, $constantoffset, O7\n\t"
|
||||
"LD [O7 + $switch_val], O7\n\t"
|
||||
"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_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
@ -80,9 +80,6 @@ protected:
|
||||
static bool is_sparc64(int features) { return (features & fmaf_instructions_m) != 0; }
|
||||
|
||||
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:
|
||||
// Initialization
|
||||
@ -105,6 +102,9 @@ public:
|
||||
static bool is_ultra3() { return (_features & ultra3_m) == ultra3_m; }
|
||||
static bool is_sun4v() { return (_features & sun4v_m) != 0; }
|
||||
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 has_fast_fxtof() { return has_v9() && !is_ultra3(); }
|
||||
|
||||
@ -2649,6 +2649,37 @@ void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
|
||||
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) {
|
||||
NOT_LP64(assert(VM_Version::supports_sse(), ""));
|
||||
InstructionMark im(this);
|
||||
@ -4358,16 +4389,6 @@ void Assembler::shrq(Register dst) {
|
||||
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) {
|
||||
InstructionMark im(this);
|
||||
prefixq(dst);
|
||||
@ -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() {
|
||||
pop(rcx);
|
||||
pop(rdx);
|
||||
|
||||
@ -1353,6 +1353,10 @@ private:
|
||||
void sqrtsd(XMMRegister dst, Address 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 stmxcsr( Address dst );
|
||||
@ -2125,6 +2129,9 @@ class MacroAssembler: public Assembler {
|
||||
void comisd(XMMRegister dst, Address src) { Assembler::comisd(dst, 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(AddressLiteral src);
|
||||
|
||||
@ -2138,6 +2145,9 @@ class MacroAssembler: public Assembler {
|
||||
void fld_x(Address src) { Assembler::fld_x(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(AddressLiteral src);
|
||||
|
||||
@ -2154,10 +2164,50 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
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);
|
||||
void addsd(XMMRegister dst, XMMRegister src) { Assembler::addsd(dst, src); }
|
||||
void addsd(XMMRegister dst, Address src) { Assembler::addsd(dst, src); }
|
||||
void addsd(XMMRegister dst, AddressLiteral src) { Assembler::addsd(dst, as_Address(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, Address src) { Assembler::ucomiss(dst, src); }
|
||||
|
||||
@ -506,6 +506,25 @@ void encode_CopyXD( CodeBuffer &cbuf, int dst_encoding, int src_encoding ) {
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
const bool Matcher::constant_table_absolute_addressing = true;
|
||||
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
|
||||
|
||||
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
|
||||
// Empty encoding
|
||||
}
|
||||
|
||||
uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
||||
st->print("# MachConstantBaseNode (empty encoding)");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//=============================================================================
|
||||
#ifndef PRODUCT
|
||||
void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream* st ) const {
|
||||
@ -1320,29 +1339,6 @@ int emit_deopt_handler(CodeBuffer& cbuf) {
|
||||
}
|
||||
|
||||
|
||||
static void emit_double_constant(CodeBuffer& cbuf, double x) {
|
||||
int mark = cbuf.insts()->mark_off();
|
||||
MacroAssembler _masm(&cbuf);
|
||||
address double_address = __ double_constant(x);
|
||||
cbuf.insts()->set_mark_off(mark); // preserve mark across masm shift
|
||||
emit_d32_reloc(cbuf,
|
||||
(int)double_address,
|
||||
internal_word_Relocation::spec(double_address),
|
||||
RELOC_DISP32);
|
||||
}
|
||||
|
||||
static void emit_float_constant(CodeBuffer& cbuf, float x) {
|
||||
int mark = cbuf.insts()->mark_off();
|
||||
MacroAssembler _masm(&cbuf);
|
||||
address float_address = __ float_constant(x);
|
||||
cbuf.insts()->set_mark_off(mark); // preserve mark across masm shift
|
||||
emit_d32_reloc(cbuf,
|
||||
(int)float_address,
|
||||
internal_word_Relocation::spec(float_address),
|
||||
RELOC_DISP32);
|
||||
}
|
||||
|
||||
|
||||
const bool Matcher::match_rule_supported(int opcode) {
|
||||
if (!has_match_rule(opcode))
|
||||
return false;
|
||||
@ -1354,22 +1350,6 @@ int Matcher::regnum_to_fpu_offset(int regnum) {
|
||||
return regnum - 32; // The FP registers are in the second chunk
|
||||
}
|
||||
|
||||
bool is_positive_zero_float(jfloat f) {
|
||||
return jint_cast(f) == jint_cast(0.0F);
|
||||
}
|
||||
|
||||
bool is_positive_one_float(jfloat f) {
|
||||
return jint_cast(f) == jint_cast(1.0F);
|
||||
}
|
||||
|
||||
bool is_positive_zero_double(jdouble d) {
|
||||
return jlong_cast(d) == jlong_cast(0.0);
|
||||
}
|
||||
|
||||
bool is_positive_one_double(jdouble d) {
|
||||
return jlong_cast(d) == jlong_cast(1.0);
|
||||
}
|
||||
|
||||
// This is UltraSparc specific, true just means we have fast l2f conversion
|
||||
const bool Matcher::convL2FSupported(void) {
|
||||
return true;
|
||||
@ -2036,67 +2016,6 @@ encode %{
|
||||
%}
|
||||
|
||||
|
||||
enc_class LdImmD (immD src) %{ // Load Immediate
|
||||
if( is_positive_zero_double($src$$constant)) {
|
||||
// FLDZ
|
||||
emit_opcode(cbuf,0xD9);
|
||||
emit_opcode(cbuf,0xEE);
|
||||
} else if( is_positive_one_double($src$$constant)) {
|
||||
// FLD1
|
||||
emit_opcode(cbuf,0xD9);
|
||||
emit_opcode(cbuf,0xE8);
|
||||
} else {
|
||||
emit_opcode(cbuf,0xDD);
|
||||
emit_rm(cbuf, 0x0, 0x0, 0x5);
|
||||
emit_double_constant(cbuf, $src$$constant);
|
||||
}
|
||||
%}
|
||||
|
||||
|
||||
enc_class LdImmF (immF src) %{ // Load Immediate
|
||||
if( is_positive_zero_float($src$$constant)) {
|
||||
emit_opcode(cbuf,0xD9);
|
||||
emit_opcode(cbuf,0xEE);
|
||||
} else if( is_positive_one_float($src$$constant)) {
|
||||
emit_opcode(cbuf,0xD9);
|
||||
emit_opcode(cbuf,0xE8);
|
||||
} else {
|
||||
$$$emit8$primary;
|
||||
// Load immediate does not have a zero or sign extended version
|
||||
// for 8-bit immediates
|
||||
// First load to TOS, then move to dst
|
||||
emit_rm(cbuf, 0x0, 0x0, 0x5);
|
||||
emit_float_constant(cbuf, $src$$constant);
|
||||
}
|
||||
%}
|
||||
|
||||
enc_class LdImmX (regX dst, immXF con) %{ // Load Immediate
|
||||
emit_rm(cbuf, 0x0, $dst$$reg, 0x5);
|
||||
emit_float_constant(cbuf, $con$$constant);
|
||||
%}
|
||||
|
||||
enc_class LdImmXD (regXD dst, immXD con) %{ // Load Immediate
|
||||
emit_rm(cbuf, 0x0, $dst$$reg, 0x5);
|
||||
emit_double_constant(cbuf, $con$$constant);
|
||||
%}
|
||||
|
||||
enc_class load_conXD (regXD dst, immXD con) %{ // Load double constant
|
||||
// UseXmmLoadAndClearUpper ? movsd(dst, con) : movlpd(dst, con)
|
||||
emit_opcode(cbuf, UseXmmLoadAndClearUpper ? 0xF2 : 0x66);
|
||||
emit_opcode(cbuf, 0x0F);
|
||||
emit_opcode(cbuf, UseXmmLoadAndClearUpper ? 0x10 : 0x12);
|
||||
emit_rm(cbuf, 0x0, $dst$$reg, 0x5);
|
||||
emit_double_constant(cbuf, $con$$constant);
|
||||
%}
|
||||
|
||||
enc_class Opc_MemImm_F(immF src) %{
|
||||
cbuf.set_insts_mark();
|
||||
$$$emit8$primary;
|
||||
emit_rm(cbuf, 0x0, $secondary, 0x5);
|
||||
emit_float_constant(cbuf, $src$$constant);
|
||||
%}
|
||||
|
||||
|
||||
enc_class MovI2X_reg(regX dst, eRegI src) %{
|
||||
emit_opcode(cbuf, 0x66 ); // MOVD dst,src
|
||||
emit_opcode(cbuf, 0x0F );
|
||||
@ -4801,7 +4720,7 @@ operand immD0() %{
|
||||
interface(CONST_INTER);
|
||||
%}
|
||||
|
||||
// Double Immediate
|
||||
// Double Immediate one
|
||||
operand immD1() %{
|
||||
predicate( UseSSE<=1 && n->getd() == 1.0 );
|
||||
match(ConD);
|
||||
@ -4844,7 +4763,17 @@ operand immXD0() %{
|
||||
|
||||
// Float Immediate zero
|
||||
operand immF0() %{
|
||||
predicate( UseSSE == 0 && n->getf() == 0.0 );
|
||||
predicate(UseSSE == 0 && n->getf() == 0.0F);
|
||||
match(ConF);
|
||||
|
||||
op_cost(5);
|
||||
format %{ %}
|
||||
interface(CONST_INTER);
|
||||
%}
|
||||
|
||||
// Float Immediate one
|
||||
operand immF1() %{
|
||||
predicate(UseSSE == 0 && n->getf() == 1.0F);
|
||||
match(ConF);
|
||||
|
||||
op_cost(5);
|
||||
@ -7215,24 +7144,53 @@ instruct loadConL0(eRegL dst, immL0 src, eFlagsReg cr) %{
|
||||
%}
|
||||
|
||||
// The instruction usage is guarded by predicate in operand immF().
|
||||
instruct loadConF(regF dst, immF src) %{
|
||||
match(Set dst src);
|
||||
instruct loadConF(regF dst, immF con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(125);
|
||||
|
||||
format %{ "FLD_S ST,$src\n\t"
|
||||
format %{ "FLD_S ST,[$constantaddress]\t# load from constant table: float=$con\n\t"
|
||||
"FSTP $dst" %}
|
||||
opcode(0xD9, 0x00); /* D9 /0 */
|
||||
ins_encode(LdImmF(src), Pop_Reg_F(dst) );
|
||||
ins_pipe( fpu_reg_con );
|
||||
ins_encode %{
|
||||
__ fld_s($constantaddress($con));
|
||||
__ fstp_d($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg_con);
|
||||
%}
|
||||
|
||||
// The instruction usage is guarded by predicate in operand immF0().
|
||||
instruct loadConF0(regF dst, immF0 con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(125);
|
||||
format %{ "FLDZ ST\n\t"
|
||||
"FSTP $dst" %}
|
||||
ins_encode %{
|
||||
__ fldz();
|
||||
__ fstp_d($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg_con);
|
||||
%}
|
||||
|
||||
// The instruction usage is guarded by predicate in operand immF1().
|
||||
instruct loadConF1(regF dst, immF1 con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(125);
|
||||
format %{ "FLD1 ST\n\t"
|
||||
"FSTP $dst" %}
|
||||
ins_encode %{
|
||||
__ fld1();
|
||||
__ fstp_d($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg_con);
|
||||
%}
|
||||
|
||||
// The instruction usage is guarded by predicate in operand immXF().
|
||||
instruct loadConX(regX dst, immXF con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(125);
|
||||
format %{ "MOVSS $dst,[$con]" %}
|
||||
ins_encode( Opcode(0xF3), Opcode(0x0F), Opcode(0x10), LdImmX(dst, con));
|
||||
ins_pipe( pipe_slow );
|
||||
format %{ "MOVSS $dst,[$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_encode %{
|
||||
__ movflt($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// The instruction usage is guarded by predicate in operand immXF0().
|
||||
@ -7240,28 +7198,63 @@ instruct loadConX0(regX dst, immXF0 src) %{
|
||||
match(Set dst src);
|
||||
ins_cost(100);
|
||||
format %{ "XORPS $dst,$dst\t# float 0.0" %}
|
||||
ins_encode( Opcode(0x0F), Opcode(0x57), RegReg(dst,dst));
|
||||
ins_pipe( pipe_slow );
|
||||
ins_encode %{
|
||||
__ xorps($dst$$XMMRegister, $dst$$XMMRegister);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// The instruction usage is guarded by predicate in operand immD().
|
||||
instruct loadConD(regD dst, immD src) %{
|
||||
match(Set dst src);
|
||||
instruct loadConD(regD dst, immD con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(125);
|
||||
|
||||
format %{ "FLD_D ST,$src\n\t"
|
||||
format %{ "FLD_D ST,[$constantaddress]\t# load from constant table: double=$con\n\t"
|
||||
"FSTP $dst" %}
|
||||
ins_encode(LdImmD(src), Pop_Reg_D(dst) );
|
||||
ins_pipe( fpu_reg_con );
|
||||
ins_encode %{
|
||||
__ fld_d($constantaddress($con));
|
||||
__ fstp_d($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg_con);
|
||||
%}
|
||||
|
||||
// The instruction usage is guarded by predicate in operand immD0().
|
||||
instruct loadConD0(regD dst, immD0 con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(125);
|
||||
|
||||
format %{ "FLDZ ST\n\t"
|
||||
"FSTP $dst" %}
|
||||
ins_encode %{
|
||||
__ fldz();
|
||||
__ fstp_d($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg_con);
|
||||
%}
|
||||
|
||||
// The instruction usage is guarded by predicate in operand immD1().
|
||||
instruct loadConD1(regD dst, immD1 con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(125);
|
||||
|
||||
format %{ "FLD1 ST\n\t"
|
||||
"FSTP $dst" %}
|
||||
ins_encode %{
|
||||
__ fld1();
|
||||
__ fstp_d($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg_con);
|
||||
%}
|
||||
|
||||
// The instruction usage is guarded by predicate in operand immXD().
|
||||
instruct loadConXD(regXD dst, immXD con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(125);
|
||||
format %{ "MOVSD $dst,[$con]" %}
|
||||
ins_encode(load_conXD(dst, con));
|
||||
ins_pipe( pipe_slow );
|
||||
format %{ "MOVSD $dst,[$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_encode %{
|
||||
__ movdbl($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
// The instruction usage is guarded by predicate in operand immXD0().
|
||||
@ -10303,41 +10296,45 @@ instruct addD_mem_reg(memory dst, regD src) %{
|
||||
ins_pipe( fpu_reg_mem );
|
||||
%}
|
||||
|
||||
instruct addD_reg_imm1(regD dst, immD1 src) %{
|
||||
instruct addD_reg_imm1(regD dst, immD1 con) %{
|
||||
predicate(UseSSE<=1);
|
||||
match(Set dst (AddD dst src));
|
||||
match(Set dst (AddD dst con));
|
||||
ins_cost(125);
|
||||
format %{ "FLD1\n\t"
|
||||
"DADDp $dst,ST" %}
|
||||
opcode(0xDE, 0x00);
|
||||
ins_encode( LdImmD(src),
|
||||
OpcP, RegOpc(dst) );
|
||||
ins_pipe( fpu_reg );
|
||||
ins_encode %{
|
||||
__ fld1();
|
||||
__ faddp($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg);
|
||||
%}
|
||||
|
||||
instruct addD_reg_imm(regD dst, immD src) %{
|
||||
instruct addD_reg_imm(regD dst, immD con) %{
|
||||
predicate(UseSSE<=1 && _kids[1]->_leaf->getd() != 0.0 && _kids[1]->_leaf->getd() != 1.0 );
|
||||
match(Set dst (AddD dst src));
|
||||
match(Set dst (AddD dst con));
|
||||
ins_cost(200);
|
||||
format %{ "FLD_D [$src]\n\t"
|
||||
format %{ "FLD_D [$constantaddress]\t# load from constant table: double=$con\n\t"
|
||||
"DADDp $dst,ST" %}
|
||||
opcode(0xDE, 0x00); /* DE /0 */
|
||||
ins_encode( LdImmD(src),
|
||||
OpcP, RegOpc(dst));
|
||||
ins_pipe( fpu_reg_mem );
|
||||
ins_encode %{
|
||||
__ fld_d($constantaddress($con));
|
||||
__ faddp($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg_mem);
|
||||
%}
|
||||
|
||||
instruct addD_reg_imm_round(stackSlotD dst, regD src, immD con) %{
|
||||
predicate(UseSSE<=1 && _kids[0]->_kids[1]->_leaf->getd() != 0.0 && _kids[0]->_kids[1]->_leaf->getd() != 1.0 );
|
||||
match(Set dst (RoundDouble (AddD src con)));
|
||||
ins_cost(200);
|
||||
format %{ "FLD_D [$con]\n\t"
|
||||
format %{ "FLD_D [$constantaddress]\t# load from constant table: double=$con\n\t"
|
||||
"DADD ST,$src\n\t"
|
||||
"FSTP_D $dst\t# D-round" %}
|
||||
opcode(0xD8, 0x00); /* D8 /0 */
|
||||
ins_encode( LdImmD(con),
|
||||
OpcP, RegOpc(src), Pop_Mem_D(dst));
|
||||
ins_pipe( fpu_mem_reg_con );
|
||||
ins_encode %{
|
||||
__ fld_d($constantaddress($con));
|
||||
__ fadd($src$$reg);
|
||||
__ fstp_d(Address(rsp, $dst$$disp));
|
||||
%}
|
||||
ins_pipe(fpu_mem_reg_con);
|
||||
%}
|
||||
|
||||
// Add two double precision floating point values in xmm
|
||||
@ -10352,9 +10349,11 @@ instruct addXD_reg(regXD dst, regXD src) %{
|
||||
instruct addXD_imm(regXD dst, immXD con) %{
|
||||
predicate(UseSSE>=2);
|
||||
match(Set dst (AddD dst con));
|
||||
format %{ "ADDSD $dst,[$con]" %}
|
||||
ins_encode( Opcode(0xF2), Opcode(0x0F), Opcode(0x58), LdImmXD(dst, con) );
|
||||
ins_pipe( pipe_slow );
|
||||
format %{ "ADDSD $dst,[$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_encode %{
|
||||
__ addsd($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct addXD_mem(regXD dst, memory mem) %{
|
||||
@ -10377,9 +10376,11 @@ instruct subXD_reg(regXD dst, regXD src) %{
|
||||
instruct subXD_imm(regXD dst, immXD con) %{
|
||||
predicate(UseSSE>=2);
|
||||
match(Set dst (SubD dst con));
|
||||
format %{ "SUBSD $dst,[$con]" %}
|
||||
ins_encode( Opcode(0xF2), Opcode(0x0F), Opcode(0x5C), LdImmXD(dst, con) );
|
||||
ins_pipe( pipe_slow );
|
||||
format %{ "SUBSD $dst,[$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_encode %{
|
||||
__ subsd($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct subXD_mem(regXD dst, memory mem) %{
|
||||
@ -10402,9 +10403,11 @@ instruct mulXD_reg(regXD dst, regXD src) %{
|
||||
instruct mulXD_imm(regXD dst, immXD con) %{
|
||||
predicate(UseSSE>=2);
|
||||
match(Set dst (MulD dst con));
|
||||
format %{ "MULSD $dst,[$con]" %}
|
||||
ins_encode( Opcode(0xF2), Opcode(0x0F), Opcode(0x59), LdImmXD(dst, con) );
|
||||
ins_pipe( pipe_slow );
|
||||
format %{ "MULSD $dst,[$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_encode %{
|
||||
__ mulsd($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct mulXD_mem(regXD dst, memory mem) %{
|
||||
@ -10428,9 +10431,11 @@ instruct divXD_reg(regXD dst, regXD src) %{
|
||||
instruct divXD_imm(regXD dst, immXD con) %{
|
||||
predicate(UseSSE>=2);
|
||||
match(Set dst (DivD dst con));
|
||||
format %{ "DIVSD $dst,[$con]" %}
|
||||
ins_encode( Opcode(0xF2), Opcode(0x0F), Opcode(0x5E), LdImmXD(dst, con));
|
||||
ins_pipe( pipe_slow );
|
||||
format %{ "DIVSD $dst,[$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_encode %{
|
||||
__ divsd($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct divXD_mem(regXD dst, memory mem) %{
|
||||
@ -10481,16 +10486,17 @@ instruct strictfp_mulD_reg(regDPR1 dst, regnotDPR1 src) %{
|
||||
ins_pipe( fpu_reg_reg );
|
||||
%}
|
||||
|
||||
instruct mulD_reg_imm(regD dst, immD src) %{
|
||||
instruct mulD_reg_imm(regD dst, immD con) %{
|
||||
predicate( UseSSE<=1 && _kids[1]->_leaf->getd() != 0.0 && _kids[1]->_leaf->getd() != 1.0 );
|
||||
match(Set dst (MulD dst src));
|
||||
match(Set dst (MulD dst con));
|
||||
ins_cost(200);
|
||||
format %{ "FLD_D [$src]\n\t"
|
||||
format %{ "FLD_D [$constantaddress]\t# load from constant table: double=$con\n\t"
|
||||
"DMULp $dst,ST" %}
|
||||
opcode(0xDE, 0x1); /* DE /1 */
|
||||
ins_encode( LdImmD(src),
|
||||
OpcP, RegOpc(dst) );
|
||||
ins_pipe( fpu_reg_mem );
|
||||
ins_encode %{
|
||||
__ fld_d($constantaddress($con));
|
||||
__ fmulp($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg_mem);
|
||||
%}
|
||||
|
||||
|
||||
@ -11224,9 +11230,11 @@ instruct addX_reg(regX dst, regX src) %{
|
||||
instruct addX_imm(regX dst, immXF con) %{
|
||||
predicate(UseSSE>=1);
|
||||
match(Set dst (AddF dst con));
|
||||
format %{ "ADDSS $dst,[$con]" %}
|
||||
ins_encode( Opcode(0xF3), Opcode(0x0F), Opcode(0x58), LdImmX(dst, con) );
|
||||
ins_pipe( pipe_slow );
|
||||
format %{ "ADDSS $dst,[$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_encode %{
|
||||
__ addss($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct addX_mem(regX dst, memory mem) %{
|
||||
@ -11249,9 +11257,11 @@ instruct subX_reg(regX dst, regX src) %{
|
||||
instruct subX_imm(regX dst, immXF con) %{
|
||||
predicate(UseSSE>=1);
|
||||
match(Set dst (SubF dst con));
|
||||
format %{ "SUBSS $dst,[$con]" %}
|
||||
ins_encode( Opcode(0xF3), Opcode(0x0F), Opcode(0x5C), LdImmX(dst, con) );
|
||||
ins_pipe( pipe_slow );
|
||||
format %{ "SUBSS $dst,[$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_encode %{
|
||||
__ subss($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct subX_mem(regX dst, memory mem) %{
|
||||
@ -11274,9 +11284,11 @@ instruct mulX_reg(regX dst, regX src) %{
|
||||
instruct mulX_imm(regX dst, immXF con) %{
|
||||
predicate(UseSSE>=1);
|
||||
match(Set dst (MulF dst con));
|
||||
format %{ "MULSS $dst,[$con]" %}
|
||||
ins_encode( Opcode(0xF3), Opcode(0x0F), Opcode(0x59), LdImmX(dst, con) );
|
||||
ins_pipe( pipe_slow );
|
||||
format %{ "MULSS $dst,[$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_encode %{
|
||||
__ mulss($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct mulX_mem(regX dst, memory mem) %{
|
||||
@ -11299,9 +11311,11 @@ instruct divX_reg(regX dst, regX src) %{
|
||||
instruct divX_imm(regX dst, immXF con) %{
|
||||
predicate(UseSSE>=1);
|
||||
match(Set dst (DivF dst con));
|
||||
format %{ "DIVSS $dst,[$con]" %}
|
||||
ins_encode( Opcode(0xF3), Opcode(0x0F), Opcode(0x5E), LdImmX(dst, con) );
|
||||
ins_pipe( pipe_slow );
|
||||
format %{ "DIVSS $dst,[$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_encode %{
|
||||
__ divss($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct divX_mem(regX dst, memory mem) %{
|
||||
@ -11456,31 +11470,33 @@ instruct addF24_mem_mem(stackSlotF dst, memory src1, memory src2) %{
|
||||
|
||||
|
||||
// Spill to obtain 24-bit precision
|
||||
instruct addF24_reg_imm(stackSlotF dst, regF src1, immF src2) %{
|
||||
instruct addF24_reg_imm(stackSlotF dst, regF src, immF con) %{
|
||||
predicate(UseSSE==0 && Compile::current()->select_24_bit_instr());
|
||||
match(Set dst (AddF src1 src2));
|
||||
format %{ "FLD $src1\n\t"
|
||||
"FADD $src2\n\t"
|
||||
match(Set dst (AddF src con));
|
||||
format %{ "FLD $src\n\t"
|
||||
"FADD_S [$constantaddress]\t# load from constant table: float=$con\n\t"
|
||||
"FSTP_S $dst" %}
|
||||
opcode(0xD8, 0x00); /* D8 /0 */
|
||||
ins_encode( Push_Reg_F(src1),
|
||||
Opc_MemImm_F(src2),
|
||||
Pop_Mem_F(dst));
|
||||
ins_pipe( fpu_mem_reg_con );
|
||||
ins_encode %{
|
||||
__ fld_s($src$$reg - 1); // FLD ST(i-1)
|
||||
__ fadd_s($constantaddress($con));
|
||||
__ fstp_s(Address(rsp, $dst$$disp));
|
||||
%}
|
||||
ins_pipe(fpu_mem_reg_con);
|
||||
%}
|
||||
//
|
||||
// This instruction does not round to 24-bits
|
||||
instruct addF_reg_imm(regF dst, regF src1, immF src2) %{
|
||||
instruct addF_reg_imm(regF dst, regF src, immF con) %{
|
||||
predicate(UseSSE==0 && !Compile::current()->select_24_bit_instr());
|
||||
match(Set dst (AddF src1 src2));
|
||||
format %{ "FLD $src1\n\t"
|
||||
"FADD $src2\n\t"
|
||||
"FSTP_S $dst" %}
|
||||
opcode(0xD8, 0x00); /* D8 /0 */
|
||||
ins_encode( Push_Reg_F(src1),
|
||||
Opc_MemImm_F(src2),
|
||||
Pop_Reg_F(dst));
|
||||
ins_pipe( fpu_reg_reg_con );
|
||||
match(Set dst (AddF src con));
|
||||
format %{ "FLD $src\n\t"
|
||||
"FADD_S [$constantaddress]\t# load from constant table: float=$con\n\t"
|
||||
"FSTP $dst" %}
|
||||
ins_encode %{
|
||||
__ fld_s($src$$reg - 1); // FLD ST(i-1)
|
||||
__ fadd_s($constantaddress($con));
|
||||
__ fstp_d($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg_reg_con);
|
||||
%}
|
||||
|
||||
// Spill to obtain 24-bit precision
|
||||
@ -11559,29 +11575,35 @@ instruct mulF24_mem_mem(stackSlotF dst, memory src1, memory src2) %{
|
||||
%}
|
||||
|
||||
// Spill to obtain 24-bit precision
|
||||
instruct mulF24_reg_imm(stackSlotF dst, regF src1, immF src2) %{
|
||||
instruct mulF24_reg_imm(stackSlotF dst, regF src, immF con) %{
|
||||
predicate(UseSSE==0 && Compile::current()->select_24_bit_instr());
|
||||
match(Set dst (MulF src1 src2));
|
||||
match(Set dst (MulF src con));
|
||||
|
||||
format %{ "FMULc $dst,$src1,$src2" %}
|
||||
opcode(0xD8, 0x1); /* D8 /1*/
|
||||
ins_encode( Push_Reg_F(src1),
|
||||
Opc_MemImm_F(src2),
|
||||
Pop_Mem_F(dst));
|
||||
ins_pipe( fpu_mem_reg_con );
|
||||
format %{ "FLD $src\n\t"
|
||||
"FMUL_S [$constantaddress]\t# load from constant table: float=$con\n\t"
|
||||
"FSTP_S $dst" %}
|
||||
ins_encode %{
|
||||
__ fld_s($src$$reg - 1); // FLD ST(i-1)
|
||||
__ fmul_s($constantaddress($con));
|
||||
__ fstp_s(Address(rsp, $dst$$disp));
|
||||
%}
|
||||
ins_pipe(fpu_mem_reg_con);
|
||||
%}
|
||||
//
|
||||
// This instruction does not round to 24-bits
|
||||
instruct mulF_reg_imm(regF dst, regF src1, immF src2) %{
|
||||
instruct mulF_reg_imm(regF dst, regF src, immF con) %{
|
||||
predicate(UseSSE==0 && !Compile::current()->select_24_bit_instr());
|
||||
match(Set dst (MulF src1 src2));
|
||||
match(Set dst (MulF src con));
|
||||
|
||||
format %{ "FMULc $dst. $src1, $src2" %}
|
||||
opcode(0xD8, 0x1); /* D8 /1*/
|
||||
ins_encode( Push_Reg_F(src1),
|
||||
Opc_MemImm_F(src2),
|
||||
Pop_Reg_F(dst));
|
||||
ins_pipe( fpu_reg_reg_con );
|
||||
format %{ "FLD $src\n\t"
|
||||
"FMUL_S [$constantaddress]\t# load from constant table: float=$con\n\t"
|
||||
"FSTP $dst" %}
|
||||
ins_encode %{
|
||||
__ fld_s($src$$reg - 1); // FLD ST(i-1)
|
||||
__ fmul_s($constantaddress($con));
|
||||
__ fstp_d($dst$$reg);
|
||||
%}
|
||||
ins_pipe(fpu_reg_reg_con);
|
||||
%}
|
||||
|
||||
|
||||
@ -12939,16 +12961,11 @@ instruct maxI_eReg(eRegI dst, eRegI src, eFlagsReg flags) %{
|
||||
instruct jumpXtnd(eRegI switch_val) %{
|
||||
match(Jump switch_val);
|
||||
ins_cost(350);
|
||||
|
||||
format %{ "JMP [table_base](,$switch_val,1)\n\t" %}
|
||||
|
||||
format %{ "JMP [$constantaddress](,$switch_val,1)\n\t" %}
|
||||
ins_encode %{
|
||||
address table_base = __ address_table_constant(_index2label);
|
||||
|
||||
// Jump to Address(table_base + switch_reg)
|
||||
InternalAddress table(table_base);
|
||||
Address index(noreg, $switch_val$$Register, Address::times_1);
|
||||
__ jump(ArrayAddress(table, index));
|
||||
__ jump(ArrayAddress($constantaddress, index));
|
||||
%}
|
||||
ins_pc_relative(1);
|
||||
ins_pipe(pipe_jmp);
|
||||
|
||||
@ -832,6 +832,25 @@ void encode_CopyXD( CodeBuffer &cbuf, int dst_encoding, int src_encoding ) {
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
const bool Matcher::constant_table_absolute_addressing = true;
|
||||
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
|
||||
|
||||
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
|
||||
// Empty encoding
|
||||
}
|
||||
|
||||
uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
||||
st->print("# MachConstantBaseNode (empty encoding)");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//=============================================================================
|
||||
#ifndef PRODUCT
|
||||
void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const
|
||||
@ -1922,28 +1941,6 @@ int emit_deopt_handler(CodeBuffer& cbuf)
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void emit_double_constant(CodeBuffer& cbuf, double x) {
|
||||
int mark = cbuf.insts()->mark_off();
|
||||
MacroAssembler _masm(&cbuf);
|
||||
address double_address = __ double_constant(x);
|
||||
cbuf.insts()->set_mark_off(mark); // preserve mark across masm shift
|
||||
emit_d32_reloc(cbuf,
|
||||
(int) (double_address - cbuf.insts_end() - 4),
|
||||
internal_word_Relocation::spec(double_address),
|
||||
RELOC_DISP32);
|
||||
}
|
||||
|
||||
static void emit_float_constant(CodeBuffer& cbuf, float x) {
|
||||
int mark = cbuf.insts()->mark_off();
|
||||
MacroAssembler _masm(&cbuf);
|
||||
address float_address = __ float_constant(x);
|
||||
cbuf.insts()->set_mark_off(mark); // preserve mark across masm shift
|
||||
emit_d32_reloc(cbuf,
|
||||
(int) (float_address - cbuf.insts_end() - 4),
|
||||
internal_word_Relocation::spec(float_address),
|
||||
RELOC_DISP32);
|
||||
}
|
||||
|
||||
|
||||
const bool Matcher::match_rule_supported(int opcode) {
|
||||
if (!has_match_rule(opcode))
|
||||
@ -2789,43 +2786,6 @@ encode %{
|
||||
}
|
||||
%}
|
||||
|
||||
enc_class load_immF(regF dst, immF con)
|
||||
%{
|
||||
// XXX reg_mem doesn't support RIP-relative addressing yet
|
||||
emit_rm(cbuf, 0x0, $dst$$reg & 7, 0x5); // 00 reg 101
|
||||
emit_float_constant(cbuf, $con$$constant);
|
||||
%}
|
||||
|
||||
enc_class load_immD(regD dst, immD con)
|
||||
%{
|
||||
// XXX reg_mem doesn't support RIP-relative addressing yet
|
||||
emit_rm(cbuf, 0x0, $dst$$reg & 7, 0x5); // 00 reg 101
|
||||
emit_double_constant(cbuf, $con$$constant);
|
||||
%}
|
||||
|
||||
enc_class load_conF (regF dst, immF con) %{ // Load float constant
|
||||
emit_opcode(cbuf, 0xF3);
|
||||
if ($dst$$reg >= 8) {
|
||||
emit_opcode(cbuf, Assembler::REX_R);
|
||||
}
|
||||
emit_opcode(cbuf, 0x0F);
|
||||
emit_opcode(cbuf, 0x10);
|
||||
emit_rm(cbuf, 0x0, $dst$$reg & 7, 0x5); // 00 reg 101
|
||||
emit_float_constant(cbuf, $con$$constant);
|
||||
%}
|
||||
|
||||
enc_class load_conD (regD dst, immD con) %{ // Load double constant
|
||||
// UseXmmLoadAndClearUpper ? movsd(dst, con) : movlpd(dst, con)
|
||||
emit_opcode(cbuf, UseXmmLoadAndClearUpper ? 0xF2 : 0x66);
|
||||
if ($dst$$reg >= 8) {
|
||||
emit_opcode(cbuf, Assembler::REX_R);
|
||||
}
|
||||
emit_opcode(cbuf, 0x0F);
|
||||
emit_opcode(cbuf, UseXmmLoadAndClearUpper ? 0x10 : 0x12);
|
||||
emit_rm(cbuf, 0x0, $dst$$reg & 7, 0x5); // 00 reg 101
|
||||
emit_double_constant(cbuf, $con$$constant);
|
||||
%}
|
||||
|
||||
// Encode a reg-reg copy. If it is useless, then empty encoding.
|
||||
enc_class enc_copy(rRegI dst, rRegI src)
|
||||
%{
|
||||
@ -2926,63 +2886,6 @@ encode %{
|
||||
emit_d32(cbuf, 0x00);
|
||||
%}
|
||||
|
||||
enc_class jump_enc(rRegL switch_val, rRegI dest) %{
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
Register switch_reg = as_Register($switch_val$$reg);
|
||||
Register dest_reg = as_Register($dest$$reg);
|
||||
address table_base = masm.address_table_constant(_index2label);
|
||||
|
||||
// We could use jump(ArrayAddress) except that the macro assembler needs to use r10
|
||||
// to do that and the compiler is using that register as one it can allocate.
|
||||
// So we build it all by hand.
|
||||
// Address index(noreg, switch_reg, Address::times_1);
|
||||
// ArrayAddress dispatch(table, index);
|
||||
|
||||
Address dispatch(dest_reg, switch_reg, Address::times_1);
|
||||
|
||||
masm.lea(dest_reg, InternalAddress(table_base));
|
||||
masm.jmp(dispatch);
|
||||
%}
|
||||
|
||||
enc_class jump_enc_addr(rRegL switch_val, immI2 shift, immL32 offset, rRegI dest) %{
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
Register switch_reg = as_Register($switch_val$$reg);
|
||||
Register dest_reg = as_Register($dest$$reg);
|
||||
address table_base = masm.address_table_constant(_index2label);
|
||||
|
||||
// We could use jump(ArrayAddress) except that the macro assembler needs to use r10
|
||||
// to do that and the compiler is using that register as one it can allocate.
|
||||
// So we build it all by hand.
|
||||
// Address index(noreg, switch_reg, (Address::ScaleFactor)$shift$$constant, (int)$offset$$constant);
|
||||
// ArrayAddress dispatch(table, index);
|
||||
|
||||
Address dispatch(dest_reg, switch_reg, (Address::ScaleFactor)$shift$$constant, (int)$offset$$constant);
|
||||
|
||||
masm.lea(dest_reg, InternalAddress(table_base));
|
||||
masm.jmp(dispatch);
|
||||
%}
|
||||
|
||||
enc_class jump_enc_offset(rRegL switch_val, immI2 shift, rRegI dest) %{
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
Register switch_reg = as_Register($switch_val$$reg);
|
||||
Register dest_reg = as_Register($dest$$reg);
|
||||
address table_base = masm.address_table_constant(_index2label);
|
||||
|
||||
// We could use jump(ArrayAddress) except that the macro assembler needs to use r10
|
||||
// to do that and the compiler is using that register as one it can allocate.
|
||||
// So we build it all by hand.
|
||||
// Address index(noreg, switch_reg, (Address::ScaleFactor)$shift$$constant);
|
||||
// ArrayAddress dispatch(table, index);
|
||||
|
||||
Address dispatch(dest_reg, switch_reg, (Address::ScaleFactor)$shift$$constant);
|
||||
masm.lea(dest_reg, InternalAddress(table_base));
|
||||
masm.jmp(dispatch);
|
||||
|
||||
%}
|
||||
|
||||
enc_class lock_prefix()
|
||||
%{
|
||||
if (os::is_MP()) {
|
||||
@ -6641,12 +6544,11 @@ instruct loadConL32(rRegL dst, immL32 src)
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct loadConP(rRegP dst, immP src)
|
||||
%{
|
||||
match(Set dst src);
|
||||
instruct loadConP(rRegP dst, immP con) %{
|
||||
match(Set dst con);
|
||||
|
||||
format %{ "movq $dst, $src\t# ptr" %}
|
||||
ins_encode(load_immP(dst, src));
|
||||
format %{ "movq $dst, $con\t# ptr" %}
|
||||
ins_encode(load_immP(dst, con));
|
||||
ins_pipe(ialu_reg_fat); // XXX
|
||||
%}
|
||||
|
||||
@ -6673,13 +6575,13 @@ instruct loadConP31(rRegP dst, immP31 src, rFlagsReg cr)
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct loadConF(regF dst, immF src)
|
||||
%{
|
||||
match(Set dst src);
|
||||
instruct loadConF(regF dst, immF con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(125);
|
||||
|
||||
format %{ "movss $dst, [$src]" %}
|
||||
ins_encode(load_conF(dst, src));
|
||||
format %{ "movss $dst, [$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_encode %{
|
||||
__ movflt($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -6721,13 +6623,13 @@ instruct loadConF0(regF dst, immF0 src)
|
||||
%}
|
||||
|
||||
// Use the same format since predicate() can not be used here.
|
||||
instruct loadConD(regD dst, immD src)
|
||||
%{
|
||||
match(Set dst src);
|
||||
instruct loadConD(regD dst, immD con) %{
|
||||
match(Set dst con);
|
||||
ins_cost(125);
|
||||
|
||||
format %{ "movsd $dst, [$src]" %}
|
||||
ins_encode(load_conD(dst, src));
|
||||
format %{ "movsd $dst, [$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_encode %{
|
||||
__ movdbl($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -7694,9 +7596,18 @@ instruct jumpXtnd_offset(rRegL switch_val, immI2 shift, rRegI dest) %{
|
||||
predicate(false);
|
||||
effect(TEMP dest);
|
||||
|
||||
format %{ "leaq $dest, table_base\n\t"
|
||||
format %{ "leaq $dest, [$constantaddress]\n\t"
|
||||
"jmp [$dest + $switch_val << $shift]\n\t" %}
|
||||
ins_encode(jump_enc_offset(switch_val, shift, dest));
|
||||
ins_encode %{
|
||||
// We could use jump(ArrayAddress) except that the macro assembler needs to use r10
|
||||
// to do that and the compiler is using that register as one it can allocate.
|
||||
// So we build it all by hand.
|
||||
// Address index(noreg, switch_reg, (Address::ScaleFactor)$shift$$constant);
|
||||
// ArrayAddress dispatch(table, index);
|
||||
Address dispatch($dest$$Register, $switch_val$$Register, (Address::ScaleFactor) $shift$$constant);
|
||||
__ lea($dest$$Register, $constantaddress);
|
||||
__ jmp(dispatch);
|
||||
%}
|
||||
ins_pipe(pipe_jmp);
|
||||
ins_pc_relative(1);
|
||||
%}
|
||||
@ -7706,9 +7617,18 @@ instruct jumpXtnd_addr(rRegL switch_val, immI2 shift, immL32 offset, rRegI dest)
|
||||
ins_cost(350);
|
||||
effect(TEMP dest);
|
||||
|
||||
format %{ "leaq $dest, table_base\n\t"
|
||||
format %{ "leaq $dest, [$constantaddress]\n\t"
|
||||
"jmp [$dest + $switch_val << $shift + $offset]\n\t" %}
|
||||
ins_encode(jump_enc_addr(switch_val, shift, offset, dest));
|
||||
ins_encode %{
|
||||
// We could use jump(ArrayAddress) except that the macro assembler needs to use r10
|
||||
// to do that and the compiler is using that register as one it can allocate.
|
||||
// So we build it all by hand.
|
||||
// Address index(noreg, switch_reg, (Address::ScaleFactor) $shift$$constant, (int) $offset$$constant);
|
||||
// ArrayAddress dispatch(table, index);
|
||||
Address dispatch($dest$$Register, $switch_val$$Register, (Address::ScaleFactor) $shift$$constant, (int) $offset$$constant);
|
||||
__ lea($dest$$Register, $constantaddress);
|
||||
__ jmp(dispatch);
|
||||
%}
|
||||
ins_pipe(pipe_jmp);
|
||||
ins_pc_relative(1);
|
||||
%}
|
||||
@ -7718,9 +7638,18 @@ instruct jumpXtnd(rRegL switch_val, rRegI dest) %{
|
||||
ins_cost(350);
|
||||
effect(TEMP dest);
|
||||
|
||||
format %{ "leaq $dest, table_base\n\t"
|
||||
format %{ "leaq $dest, [$constantaddress]\n\t"
|
||||
"jmp [$dest + $switch_val]\n\t" %}
|
||||
ins_encode(jump_enc(switch_val, dest));
|
||||
ins_encode %{
|
||||
// We could use jump(ArrayAddress) except that the macro assembler needs to use r10
|
||||
// to do that and the compiler is using that register as one it can allocate.
|
||||
// So we build it all by hand.
|
||||
// Address index(noreg, switch_reg, Address::times_1);
|
||||
// ArrayAddress dispatch(table, index);
|
||||
Address dispatch($dest$$Register, $switch_val$$Register, Address::times_1);
|
||||
__ lea($dest$$Register, $constantaddress);
|
||||
__ jmp(dispatch);
|
||||
%}
|
||||
ins_pipe(pipe_jmp);
|
||||
ins_pc_relative(1);
|
||||
%}
|
||||
@ -10376,30 +10305,36 @@ instruct cmpF_cc_memCF(rFlagsRegUCF cr, regF src1, memory src2) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpF_cc_imm(rFlagsRegU cr, regF src1, immF src2)
|
||||
%{
|
||||
match(Set cr (CmpF src1 src2));
|
||||
instruct cmpF_cc_imm(rFlagsRegU cr, regF src, immF con) %{
|
||||
match(Set cr (CmpF src con));
|
||||
|
||||
ins_cost(145);
|
||||
format %{ "ucomiss $src1, $src2\n\t"
|
||||
format %{ "ucomiss $src, [$constantaddress]\t# load from constant table: float=$con\n\t"
|
||||
"jnp,s exit\n\t"
|
||||
"pushfq\t# saw NaN, set CF\n\t"
|
||||
"andq [rsp], #0xffffff2b\n\t"
|
||||
"popfq\n"
|
||||
"exit: nop\t# avoid branch to branch" %}
|
||||
opcode(0x0F, 0x2E);
|
||||
ins_encode(REX_reg_mem(src1, src2), OpcP, OpcS, load_immF(src1, src2),
|
||||
cmpfp_fixup);
|
||||
ins_encode %{
|
||||
Label L_exit;
|
||||
__ ucomiss($src$$XMMRegister, $constantaddress($con));
|
||||
__ jcc(Assembler::noParity, L_exit);
|
||||
__ pushf();
|
||||
__ andq(rsp, 0xffffff2b);
|
||||
__ popf();
|
||||
__ bind(L_exit);
|
||||
__ nop();
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpF_cc_immCF(rFlagsRegUCF cr, regF src1, immF src2) %{
|
||||
match(Set cr (CmpF src1 src2));
|
||||
|
||||
instruct cmpF_cc_immCF(rFlagsRegUCF cr, regF src, immF con) %{
|
||||
match(Set cr (CmpF src con));
|
||||
ins_cost(100);
|
||||
format %{ "ucomiss $src1, $src2" %}
|
||||
opcode(0x0F, 0x2E);
|
||||
ins_encode(REX_reg_mem(src1, src2), OpcP, OpcS, load_immF(src1, src2));
|
||||
format %{ "ucomiss $src, [$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_encode %{
|
||||
__ ucomiss($src$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10458,30 +10393,36 @@ instruct cmpD_cc_memCF(rFlagsRegUCF cr, regD src1, memory src2) %{
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpD_cc_imm(rFlagsRegU cr, regD src1, immD src2)
|
||||
%{
|
||||
match(Set cr (CmpD src1 src2));
|
||||
instruct cmpD_cc_imm(rFlagsRegU cr, regD src, immD con) %{
|
||||
match(Set cr (CmpD src con));
|
||||
|
||||
ins_cost(145);
|
||||
format %{ "ucomisd $src1, [$src2]\n\t"
|
||||
format %{ "ucomisd $src, [$constantaddress]\t# load from constant table: double=$con\n\t"
|
||||
"jnp,s exit\n\t"
|
||||
"pushfq\t# saw NaN, set CF\n\t"
|
||||
"andq [rsp], #0xffffff2b\n\t"
|
||||
"popfq\n"
|
||||
"exit: nop\t# avoid branch to branch" %}
|
||||
opcode(0x66, 0x0F, 0x2E);
|
||||
ins_encode(OpcP, REX_reg_mem(src1, src2), OpcS, OpcT, load_immD(src1, src2),
|
||||
cmpfp_fixup);
|
||||
ins_encode %{
|
||||
Label L_exit;
|
||||
__ ucomisd($src$$XMMRegister, $constantaddress($con));
|
||||
__ jcc(Assembler::noParity, L_exit);
|
||||
__ pushf();
|
||||
__ andq(rsp, 0xffffff2b);
|
||||
__ popf();
|
||||
__ bind(L_exit);
|
||||
__ nop();
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct cmpD_cc_immCF(rFlagsRegUCF cr, regD src1, immD src2) %{
|
||||
match(Set cr (CmpD src1 src2));
|
||||
|
||||
instruct cmpD_cc_immCF(rFlagsRegUCF cr, regD src, immD con) %{
|
||||
match(Set cr (CmpD src con));
|
||||
ins_cost(100);
|
||||
format %{ "ucomisd $src1, [$src2]" %}
|
||||
opcode(0x66, 0x0F, 0x2E);
|
||||
ins_encode(OpcP, REX_reg_mem(src1, src2), OpcS, OpcT, load_immD(src1, src2));
|
||||
format %{ "ucomisd $src, [$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_encode %{
|
||||
__ ucomisd($src$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10528,23 +10469,29 @@ instruct cmpF_mem(rRegI dst, regF src1, memory src2, rFlagsReg cr)
|
||||
%}
|
||||
|
||||
// Compare into -1,0,1
|
||||
instruct cmpF_imm(rRegI dst, regF src1, immF src2, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst (CmpF3 src1 src2));
|
||||
instruct cmpF_imm(rRegI dst, regF src, immF con, rFlagsReg cr) %{
|
||||
match(Set dst (CmpF3 src con));
|
||||
effect(KILL cr);
|
||||
|
||||
ins_cost(275);
|
||||
format %{ "ucomiss $src1, [$src2]\n\t"
|
||||
format %{ "ucomiss $src, [$constantaddress]\t# load from constant table: float=$con\n\t"
|
||||
"movl $dst, #-1\n\t"
|
||||
"jp,s done\n\t"
|
||||
"jb,s done\n\t"
|
||||
"setne $dst\n\t"
|
||||
"movzbl $dst, $dst\n"
|
||||
"done:" %}
|
||||
|
||||
opcode(0x0F, 0x2E);
|
||||
ins_encode(REX_reg_mem(src1, src2), OpcP, OpcS, load_immF(src1, src2),
|
||||
cmpfp3(dst));
|
||||
ins_encode %{
|
||||
Label L_done;
|
||||
Register Rdst = $dst$$Register;
|
||||
__ ucomiss($src$$XMMRegister, $constantaddress($con));
|
||||
__ movl(Rdst, -1);
|
||||
__ jcc(Assembler::parity, L_done);
|
||||
__ jcc(Assembler::below, L_done);
|
||||
__ setb(Assembler::notEqual, Rdst);
|
||||
__ movzbl(Rdst, Rdst);
|
||||
__ bind(L_done);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10591,23 +10538,29 @@ instruct cmpD_mem(rRegI dst, regD src1, memory src2, rFlagsReg cr)
|
||||
%}
|
||||
|
||||
// Compare into -1,0,1
|
||||
instruct cmpD_imm(rRegI dst, regD src1, immD src2, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst (CmpD3 src1 src2));
|
||||
instruct cmpD_imm(rRegI dst, regD src, immD con, rFlagsReg cr) %{
|
||||
match(Set dst (CmpD3 src con));
|
||||
effect(KILL cr);
|
||||
|
||||
ins_cost(275);
|
||||
format %{ "ucomisd $src1, [$src2]\n\t"
|
||||
format %{ "ucomisd $src, [$constantaddress]\t# load from constant table: double=$con\n\t"
|
||||
"movl $dst, #-1\n\t"
|
||||
"jp,s done\n\t"
|
||||
"jb,s done\n\t"
|
||||
"setne $dst\n\t"
|
||||
"movzbl $dst, $dst\n"
|
||||
"done:" %}
|
||||
|
||||
opcode(0x66, 0x0F, 0x2E);
|
||||
ins_encode(OpcP, REX_reg_mem(src1, src2), OpcS, OpcT, load_immD(src1, src2),
|
||||
cmpfp3(dst));
|
||||
ins_encode %{
|
||||
Register Rdst = $dst$$Register;
|
||||
Label L_done;
|
||||
__ ucomisd($src$$XMMRegister, $constantaddress($con));
|
||||
__ movl(Rdst, -1);
|
||||
__ jcc(Assembler::parity, L_done);
|
||||
__ jcc(Assembler::below, L_done);
|
||||
__ setb(Assembler::notEqual, Rdst);
|
||||
__ movzbl(Rdst, Rdst);
|
||||
__ bind(L_done);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10633,14 +10586,13 @@ instruct addF_mem(regF dst, memory src)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct addF_imm(regF dst, immF src)
|
||||
%{
|
||||
match(Set dst (AddF dst src));
|
||||
|
||||
format %{ "addss $dst, [$src]" %}
|
||||
instruct addF_imm(regF dst, immF con) %{
|
||||
match(Set dst (AddF dst con));
|
||||
format %{ "addss $dst, [$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_cost(150); // XXX
|
||||
opcode(0xF3, 0x0F, 0x58);
|
||||
ins_encode(OpcP, REX_reg_mem(dst, src), OpcS, OpcT, load_immF(dst, src));
|
||||
ins_encode %{
|
||||
__ addss($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10666,14 +10618,13 @@ instruct addD_mem(regD dst, memory src)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct addD_imm(regD dst, immD src)
|
||||
%{
|
||||
match(Set dst (AddD dst src));
|
||||
|
||||
format %{ "addsd $dst, [$src]" %}
|
||||
instruct addD_imm(regD dst, immD con) %{
|
||||
match(Set dst (AddD dst con));
|
||||
format %{ "addsd $dst, [$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_cost(150); // XXX
|
||||
opcode(0xF2, 0x0F, 0x58);
|
||||
ins_encode(OpcP, REX_reg_mem(dst, src), OpcS, OpcT, load_immD(dst, src));
|
||||
ins_encode %{
|
||||
__ addsd($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10699,14 +10650,13 @@ instruct subF_mem(regF dst, memory src)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct subF_imm(regF dst, immF src)
|
||||
%{
|
||||
match(Set dst (SubF dst src));
|
||||
|
||||
format %{ "subss $dst, [$src]" %}
|
||||
instruct subF_imm(regF dst, immF con) %{
|
||||
match(Set dst (SubF dst con));
|
||||
format %{ "subss $dst, [$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_cost(150); // XXX
|
||||
opcode(0xF3, 0x0F, 0x5C);
|
||||
ins_encode(OpcP, REX_reg_mem(dst, src), OpcS, OpcT, load_immF(dst, src));
|
||||
ins_encode %{
|
||||
__ subss($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10732,14 +10682,13 @@ instruct subD_mem(regD dst, memory src)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct subD_imm(regD dst, immD src)
|
||||
%{
|
||||
match(Set dst (SubD dst src));
|
||||
|
||||
format %{ "subsd $dst, [$src]" %}
|
||||
instruct subD_imm(regD dst, immD con) %{
|
||||
match(Set dst (SubD dst con));
|
||||
format %{ "subsd $dst, [$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_cost(150); // XXX
|
||||
opcode(0xF2, 0x0F, 0x5C);
|
||||
ins_encode(OpcP, REX_reg_mem(dst, src), OpcS, OpcT, load_immD(dst, src));
|
||||
ins_encode %{
|
||||
__ subsd($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10765,14 +10714,13 @@ instruct mulF_mem(regF dst, memory src)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct mulF_imm(regF dst, immF src)
|
||||
%{
|
||||
match(Set dst (MulF dst src));
|
||||
|
||||
format %{ "mulss $dst, [$src]" %}
|
||||
instruct mulF_imm(regF dst, immF con) %{
|
||||
match(Set dst (MulF dst con));
|
||||
format %{ "mulss $dst, [$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_cost(150); // XXX
|
||||
opcode(0xF3, 0x0F, 0x59);
|
||||
ins_encode(OpcP, REX_reg_mem(dst, src), OpcS, OpcT, load_immF(dst, src));
|
||||
ins_encode %{
|
||||
__ mulss($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10798,14 +10746,13 @@ instruct mulD_mem(regD dst, memory src)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct mulD_imm(regD dst, immD src)
|
||||
%{
|
||||
match(Set dst (MulD dst src));
|
||||
|
||||
format %{ "mulsd $dst, [$src]" %}
|
||||
instruct mulD_imm(regD dst, immD con) %{
|
||||
match(Set dst (MulD dst con));
|
||||
format %{ "mulsd $dst, [$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_cost(150); // XXX
|
||||
opcode(0xF2, 0x0F, 0x59);
|
||||
ins_encode(OpcP, REX_reg_mem(dst, src), OpcS, OpcT, load_immD(dst, src));
|
||||
ins_encode %{
|
||||
__ mulsd($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10831,14 +10778,13 @@ instruct divF_mem(regF dst, memory src)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct divF_imm(regF dst, immF src)
|
||||
%{
|
||||
match(Set dst (DivF dst src));
|
||||
|
||||
format %{ "divss $dst, [$src]" %}
|
||||
instruct divF_imm(regF dst, immF con) %{
|
||||
match(Set dst (DivF dst con));
|
||||
format %{ "divss $dst, [$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_cost(150); // XXX
|
||||
opcode(0xF3, 0x0F, 0x5E);
|
||||
ins_encode(OpcP, REX_reg_mem(dst, src), OpcS, OpcT, load_immF(dst, src));
|
||||
ins_encode %{
|
||||
__ divss($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10864,14 +10810,13 @@ instruct divD_mem(regD dst, memory src)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct divD_imm(regD dst, immD src)
|
||||
%{
|
||||
match(Set dst (DivD dst src));
|
||||
|
||||
format %{ "divsd $dst, [$src]" %}
|
||||
instruct divD_imm(regD dst, immD con) %{
|
||||
match(Set dst (DivD dst con));
|
||||
format %{ "divsd $dst, [$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_cost(150); // XXX
|
||||
opcode(0xF2, 0x0F, 0x5E);
|
||||
ins_encode(OpcP, REX_reg_mem(dst, src), OpcS, OpcT, load_immD(dst, src));
|
||||
ins_encode %{
|
||||
__ divsd($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10897,14 +10842,13 @@ instruct sqrtF_mem(regF dst, memory src)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct sqrtF_imm(regF dst, immF src)
|
||||
%{
|
||||
match(Set dst (ConvD2F (SqrtD (ConvF2D src))));
|
||||
|
||||
format %{ "sqrtss $dst, [$src]" %}
|
||||
instruct sqrtF_imm(regF dst, immF con) %{
|
||||
match(Set dst (ConvD2F (SqrtD (ConvF2D con))));
|
||||
format %{ "sqrtss $dst, [$constantaddress]\t# load from constant table: float=$con" %}
|
||||
ins_cost(150); // XXX
|
||||
opcode(0xF3, 0x0F, 0x51);
|
||||
ins_encode(OpcP, REX_reg_mem(dst, src), OpcS, OpcT, load_immF(dst, src));
|
||||
ins_encode %{
|
||||
__ sqrtss($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -10930,14 +10874,13 @@ instruct sqrtD_mem(regD dst, memory src)
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct sqrtD_imm(regD dst, immD src)
|
||||
%{
|
||||
match(Set dst (SqrtD src));
|
||||
|
||||
format %{ "sqrtsd $dst, [$src]" %}
|
||||
instruct sqrtD_imm(regD dst, immD con) %{
|
||||
match(Set dst (SqrtD con));
|
||||
format %{ "sqrtsd $dst, [$constantaddress]\t# load from constant table: double=$con" %}
|
||||
ins_cost(150); // XXX
|
||||
opcode(0xF2, 0x0F, 0x51);
|
||||
ins_encode(OpcP, REX_reg_mem(dst, src), OpcS, OpcT, load_immD(dst, src));
|
||||
ins_encode %{
|
||||
__ sqrtsd($dst$$XMMRegister, $constantaddress($con));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
|
||||
@ -44,11 +44,11 @@ void VMError::show_message_box(char *buf, int buflen) {
|
||||
jio_snprintf(p, buflen - len,
|
||||
"\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"
|
||||
"Otherwise, press RETURN to abort...",
|
||||
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);
|
||||
|
||||
|
||||
@ -95,7 +95,7 @@ void ADLParser::parse() {
|
||||
if (ident == NULL) { // Empty 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, "opclass")) opclass_parse();
|
||||
else if (!strcmp(ident, "ins_attrib")) ins_attr_parse();
|
||||
@ -216,24 +216,23 @@ void ADLParser::instr_parse(void) {
|
||||
else if (!strcmp(ident, "encode")) {
|
||||
parse_err(SYNERR, "Instructions specify ins_encode, not encode\n");
|
||||
}
|
||||
else if (!strcmp(ident, "ins_encode"))
|
||||
instr->_insencode = ins_encode_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, "effect")) effect_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, "ins_encode")) ins_encode_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, "effect")) effect_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, "constraint")) {
|
||||
parse_err(SYNERR, "Instructions do not specify a constraint\n");
|
||||
}
|
||||
else if (!strcmp(ident, "construct")) {
|
||||
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")) {
|
||||
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
|
||||
// Check identifier to see if it is the name of an attribute
|
||||
const Form *form = _globalNames[ident];
|
||||
@ -323,7 +322,8 @@ void ADLParser::adjust_set_rule(InstructForm *instr) {
|
||||
const char *optype2 = NULL;
|
||||
// Can not have additional base operands in right side of match!
|
||||
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_,
|
||||
// Needed for shared roots of match-trees
|
||||
ChainList *lst = (ChainList *)_AD._chainRules[optype];
|
||||
@ -935,9 +935,9 @@ void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) {
|
||||
// (2)
|
||||
// If we are at a replacement variable,
|
||||
// copy it and record in EncClass
|
||||
if ( _curchar == '$' ) {
|
||||
if (_curchar == '$') {
|
||||
// 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
|
||||
encoding->add_rep_var(rep_var);
|
||||
}
|
||||
@ -2774,47 +2774,122 @@ Predicate *ADLParser::pred_parse(void) {
|
||||
|
||||
//------------------------------ins_encode_parse_block-------------------------
|
||||
// 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
|
||||
// definition, which should be unique.
|
||||
const char * prefix = "__enc_";
|
||||
char* ec_name = (char*)malloc(strlen(inst._ident) + strlen(prefix) + 1);
|
||||
const char* prefix = "__ins_encode_";
|
||||
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);
|
||||
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;
|
||||
const char* param = NULL;
|
||||
inst._parameters.reset();
|
||||
while ((param = inst._parameters.iter()) != NULL) {
|
||||
OperandForm *opForm = (OperandForm*)inst._localNames[param];
|
||||
OperandForm* opForm = (OperandForm*) inst._localNames[param];
|
||||
encoding->add_parameter(opForm->_ident, param);
|
||||
}
|
||||
|
||||
// Add the prologue to create the MacroAssembler
|
||||
encoding->add_code("\n"
|
||||
" // Define a MacroAssembler instance for use by the encoding. The\n"
|
||||
" // name is chosen to match the __ idiom used for assembly in other\n"
|
||||
" // parts of hotspot and assumes the existence of the standard\n"
|
||||
" // #define __ _masm.\n"
|
||||
" MacroAssembler _masm(&cbuf);\n");
|
||||
// Define a MacroAssembler instance for use by the encoding. The
|
||||
// name is chosen to match the __ idiom used for assembly in other
|
||||
// parts of hotspot and assumes the existence of the standard
|
||||
// #define __ _masm.
|
||||
encoding->add_code(" MacroAssembler _masm(&cbuf);\n");
|
||||
|
||||
// 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
|
||||
// created, passing all arguments that we received.
|
||||
InsEncode *encrule = new InsEncode(); // Encode class for instruction
|
||||
NameAndList *params = encrule->add_encode(ec_name);
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
//
|
||||
// making it more compact to take advantage of the MacroAssembler and
|
||||
// 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
|
||||
skipws(); // Skip whitespace
|
||||
@ -2849,11 +2924,12 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
|
||||
next_char(); // Skip '{'
|
||||
|
||||
// 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");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
next_char(); // move past '('
|
||||
skipws();
|
||||
@ -2866,7 +2942,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
|
||||
ec_name = get_ident();
|
||||
if (ec_name == NULL) {
|
||||
parse_err(SYNERR, "Invalid encode class name after 'ins_encode('.\n");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
// Check that encoding is defined in the encode section
|
||||
EncClass *encode_class = _AD._encode->encClass(ec_name);
|
||||
@ -2898,7 +2974,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
|
||||
(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
|
||||
((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) {
|
||||
parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
params->add_entry(param);
|
||||
|
||||
@ -2915,7 +2991,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
|
||||
// Only ',' or ')' are valid after a parameter name
|
||||
parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n",
|
||||
ec_name);
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -2923,11 +2999,11 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
|
||||
// Did not find a parameter
|
||||
if (_curchar == ',') {
|
||||
parse_err(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name);
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
if (_curchar != ')') {
|
||||
parse_err(SYNERR, "Expected ')' after encode parameters.\n");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // WHILE loop collecting parameters
|
||||
@ -2944,7 +3020,7 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
|
||||
else if ( _curchar != ')' ) {
|
||||
// If not a ',' then only a ')' is allowed
|
||||
parse_err(SYNERR, "Expected ')' after encoding %s.\n", ec_name);
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for ',' separating parameters
|
||||
@ -2956,14 +3032,14 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
|
||||
} // done parsing ins_encode methods and their parameters
|
||||
if (_curchar != ')') {
|
||||
parse_err(SYNERR, "Missing ')' at end of ins_encode description.\n");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
next_char(); // move past ')'
|
||||
skipws(); // Skip leading whitespace
|
||||
|
||||
if ( _curchar != ';' ) {
|
||||
parse_err(SYNERR, "Missing ';' at end of ins_encode.\n");
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
next_char(); // move past ';'
|
||||
skipws(); // be friendly to oper_parse()
|
||||
@ -2971,7 +3047,113 @@ InsEncode *ADLParser::ins_encode_parse(InstructForm &inst) {
|
||||
// Debug Stuff
|
||||
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:
|
||||
|
||||
Attribute *attr_parse(char *ident);// Parse instr/operand attribute rule
|
||||
// Parse instruction encode rule
|
||||
InsEncode *ins_encode_parse(InstructForm &inst);
|
||||
InsEncode *ins_encode_parse_block(InstructForm &inst);
|
||||
void ins_encode_parse(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
|
||||
char *size_parse(InstructForm *insr); // Parse instruction size
|
||||
Interface *interface_parse(); // Parse operand interface rule
|
||||
|
||||
@ -126,7 +126,6 @@ private:
|
||||
void chain_rule(FILE *fp, const char *indent, const char *ideal,
|
||||
const Expr *icost, const char *irule,
|
||||
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,
|
||||
const char *result_type, ProductionState &status);
|
||||
Expr *calc_cost(FILE *fp, const char *spaces, MatchList &mList, ProductionState &status);
|
||||
@ -301,13 +300,18 @@ public:
|
||||
void buildMachNodeGenerator(FILE *fp_cpp);
|
||||
|
||||
// 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
|
||||
void definePeephole(FILE *fp, InstructForm *node);
|
||||
void definePeephole (FILE *fp, InstructForm *node);
|
||||
// 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
|
||||
void defineEmit(FILE *fp, InstructForm &node);
|
||||
void defineEmit (FILE *fp, InstructForm &node);
|
||||
|
||||
// Define a MachOper encode method
|
||||
void define_oper_interface(FILE *fp, OperandForm &oper, FormDict &globals,
|
||||
const char *name, const char *encoding);
|
||||
|
||||
@ -30,11 +30,14 @@
|
||||
InstructForm::InstructForm(const char *id, bool ideal_only)
|
||||
: _ident(id), _ideal_only(ideal_only),
|
||||
_localNames(cmpstr, hashstr, Form::arena),
|
||||
_effects(cmpstr, hashstr, Form::arena) {
|
||||
_effects(cmpstr, hashstr, Form::arena),
|
||||
_is_mach_constant(false)
|
||||
{
|
||||
_ftype = Form::INS;
|
||||
|
||||
_matrule = NULL;
|
||||
_insencode = NULL;
|
||||
_constant = NULL;
|
||||
_opcode = NULL;
|
||||
_size = NULL;
|
||||
_attribs = NULL;
|
||||
@ -58,11 +61,14 @@ InstructForm::InstructForm(const char *id, bool ideal_only)
|
||||
InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule)
|
||||
: _ident(id), _ideal_only(false),
|
||||
_localNames(instr->_localNames),
|
||||
_effects(instr->_effects) {
|
||||
_effects(instr->_effects),
|
||||
_is_mach_constant(false)
|
||||
{
|
||||
_ftype = Form::INS;
|
||||
|
||||
_matrule = rule;
|
||||
_insencode = instr->_insencode;
|
||||
_constant = instr->_constant;
|
||||
_opcode = instr->_opcode;
|
||||
_size = instr->_size;
|
||||
_attribs = instr->_attribs;
|
||||
@ -1094,6 +1100,9 @@ const char *InstructForm::mach_base_class(FormDict &globals) const {
|
||||
else if (is_ideal_nop()) {
|
||||
return "MachNopNode";
|
||||
}
|
||||
else if (is_mach_constant()) {
|
||||
return "MachConstantNode";
|
||||
}
|
||||
else if (captures_bottom_type(globals)) {
|
||||
return "MachTypeNode";
|
||||
} else {
|
||||
@ -1190,6 +1199,21 @@ bool InstructForm::check_branch_variant(ArchDesc &AD, InstructForm *short_branch
|
||||
//
|
||||
// Generate the format call for the replacement variable
|
||||
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
|
||||
const Form *form = _localNames[rep_var];
|
||||
if (form == NULL) {
|
||||
@ -1348,6 +1372,7 @@ void InstructForm::output(FILE *fp) {
|
||||
fprintf(fp,"\nInstruction: %s\n", (_ident?_ident:""));
|
||||
if (_matrule) _matrule->output(fp);
|
||||
if (_insencode) _insencode->output(fp);
|
||||
if (_constant) _constant->output(fp);
|
||||
if (_opcode) _opcode->output(fp);
|
||||
if (_attribs) _attribs->output(fp);
|
||||
if (_predicate) _predicate->output(fp);
|
||||
|
||||
@ -74,15 +74,16 @@ class ArchDesc;
|
||||
//------------------------------InstructForm-----------------------------------
|
||||
class InstructForm : public Form {
|
||||
private:
|
||||
bool _ideal_only; // Not a user-defined instruction
|
||||
bool _ideal_only; // Not a user-defined instruction
|
||||
// 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; }
|
||||
bool _is_cisc_alternate;
|
||||
bool _is_cisc_alternate;
|
||||
InstructForm *_cisc_spill_alternate;// cisc possible replacement
|
||||
const char *_cisc_reg_mask_name;
|
||||
InstructForm *_short_branch_form;
|
||||
bool _is_short_branch;
|
||||
bool _is_mach_constant; // true if Node is a MachConstantNode
|
||||
uint _alignment;
|
||||
|
||||
public:
|
||||
@ -94,6 +95,7 @@ public:
|
||||
Opcode *_opcode; // Encoding of the opcode for instruction
|
||||
char *_size; // Size of instruction
|
||||
InsEncode *_insencode; // Encoding class instruction belongs to
|
||||
InsEncode *_constant; // Encoding class constant value belongs to
|
||||
Attribute *_attribs; // List of Attribute rules
|
||||
Predicate *_predicate; // Predicate test for this instruction
|
||||
FormDict _effects; // Dictionary of effect rules
|
||||
@ -251,6 +253,9 @@ public:
|
||||
bool is_short_branch() { return _is_short_branch; }
|
||||
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; }
|
||||
bool has_short_branch_form() { return _short_branch_form != NULL; }
|
||||
// Output short branch prototypes and method bodies
|
||||
|
||||
@ -1496,8 +1496,8 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
|
||||
unsigned i;
|
||||
|
||||
// Generate Expand function header
|
||||
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, "MachNode* %sNode::Expand(State* state, Node_List& proj_list, Node* mem) {\n", node->_ident);
|
||||
fprintf(fp, " Compile* C = Compile::current();\n");
|
||||
// Generate expand code
|
||||
if( node->expands() ) {
|
||||
const char *opid;
|
||||
@ -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");
|
||||
if( node->expands() ) {
|
||||
fprintf(fp," return result;\n");
|
||||
@ -1924,7 +1930,17 @@ public:
|
||||
// No state needed.
|
||||
assert( _opclass == NULL,
|
||||
"'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
|
||||
int param_no = _encoding.rep_var_index(rep_var);
|
||||
if ( param_no == -1 ) {
|
||||
@ -2380,6 +2396,15 @@ private:
|
||||
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 {
|
||||
// Lookup its position in parameter list
|
||||
int param_no = _encoding.rep_var_index(rep_var);
|
||||
@ -2465,37 +2490,39 @@ void ArchDesc::defineSize(FILE *fp, InstructForm &inst) {
|
||||
fprintf(fp,"}\n");
|
||||
}
|
||||
|
||||
void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
|
||||
InsEncode *ins_encode = inst._insencode;
|
||||
// defineEmit -----------------------------------------------------------------
|
||||
void ArchDesc::defineEmit(FILE* fp, InstructForm& inst) {
|
||||
InsEncode* encode = inst._insencode;
|
||||
|
||||
// (1)
|
||||
// Output instruction's emit prototype
|
||||
fprintf(fp,"void %sNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {\n",
|
||||
inst._ident);
|
||||
fprintf(fp, "void %sNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {\n", inst._ident);
|
||||
|
||||
// If user did not define an encode section,
|
||||
// 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,"}\n");
|
||||
fprintf(fp, "}\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// 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"
|
||||
// fprintf( fp, " unsigned idx0 = 0;\n");
|
||||
// For MachConstantNodes which are ideal jump nodes, fill the jump table.
|
||||
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.
|
||||
inst.index_temps( fp, _globalNames );
|
||||
inst.index_temps(fp, _globalNames);
|
||||
|
||||
// Output this instruction's encodings
|
||||
const char *ec_name;
|
||||
bool user_defined = false;
|
||||
ins_encode->reset();
|
||||
while ( (ec_name = ins_encode->encode_class_iter()) != NULL ) {
|
||||
fprintf(fp, " {");
|
||||
encode->reset();
|
||||
while ((ec_name = encode->encode_class_iter()) != NULL) {
|
||||
fprintf(fp, " {\n");
|
||||
// Output user-defined encoding
|
||||
user_defined = true;
|
||||
|
||||
@ -2507,25 +2534,25 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (ins_encode->current_encoding_num_args() != encoding->num_args()) {
|
||||
globalAD->syntax_err(ins_encode->_linenum, "In %s: passing %d arguments to %s but expecting %d",
|
||||
inst._ident, ins_encode->current_encoding_num_args(),
|
||||
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, *ins_encode, inst );
|
||||
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 ) ) {
|
||||
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);
|
||||
fprintf(fp, "%s", ec_code);
|
||||
} else {
|
||||
// A replacement variable or one of its subfields
|
||||
// Obtain replacement variable from list
|
||||
@ -2536,7 +2563,7 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
|
||||
// Emit pending code
|
||||
pending.emit();
|
||||
pending.clear();
|
||||
fprintf(fp, "}\n");
|
||||
fprintf(fp, " }\n");
|
||||
} // end while instruction's encodings
|
||||
|
||||
// Check if user stated which encoding to user
|
||||
@ -2545,7 +2572,86 @@ void ArchDesc::defineEmit(FILE *fp, InstructForm &inst) {
|
||||
}
|
||||
|
||||
// (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) {
|
||||
// If there are multiple defs/kills, or an explicit expand rule, build rule
|
||||
if( instr->expands() || instr->needs_projections() ||
|
||||
instr->has_temps() ||
|
||||
instr->is_mach_constant() ||
|
||||
instr->_matrule != NULL &&
|
||||
instr->num_opnds() != instr->num_unique_opnds() )
|
||||
defineExpand(_CPP_EXPAND_file._fp, instr);
|
||||
@ -3032,8 +3139,9 @@ void ArchDesc::defineClasses(FILE *fp) {
|
||||
// Ensure this is a machine-world instruction
|
||||
if ( instr->ideal_only() ) continue;
|
||||
|
||||
if (instr->_insencode) defineEmit(fp, *instr);
|
||||
if (instr->_size) defineSize(fp, *instr);
|
||||
if (instr->_insencode) defineEmit (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:
|
||||
extern void gen_inst_format(FILE *fp, FormDict &globals, InstructForm &oper, bool for_c_file);
|
||||
|
||||
@ -1550,7 +1550,12 @@ void ArchDesc::declareClasses(FILE *fp) {
|
||||
}
|
||||
|
||||
// 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
|
||||
// encoding class information in the _insencode slot.
|
||||
if ( instr->_insencode ) {
|
||||
@ -1559,7 +1564,7 @@ void ArchDesc::declareClasses(FILE *fp) {
|
||||
|
||||
// virtual function for getting the size of an instruction
|
||||
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.
|
||||
@ -1752,6 +1757,7 @@ void ArchDesc::declareClasses(FILE *fp) {
|
||||
// Virtual methods which are only generated to override base class
|
||||
if( instr->expands() || instr->needs_projections() ||
|
||||
instr->has_temps() ||
|
||||
instr->is_mach_constant() ||
|
||||
instr->_matrule != NULL &&
|
||||
instr->num_opnds() != instr->num_unique_opnds() ) {
|
||||
fprintf(fp," virtual MachNode *Expand(State *state, Node_List &proj_list, Node* mem);\n");
|
||||
@ -1780,24 +1786,6 @@ void ArchDesc::declareClasses(FILE *fp) {
|
||||
// Declare short branch methods, if applicable
|
||||
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
|
||||
if (instr->_ins_pipe) {
|
||||
fprintf(fp," static const Pipeline *pipeline_class();\n");
|
||||
|
||||
@ -292,7 +292,16 @@ class AbstractAssembler : public ResourceObj {
|
||||
address start_a_const(int required_space, int required_align = sizeof(double));
|
||||
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 ptr = start_a_const(sizeof(c), sizeof(c));
|
||||
if (ptr != NULL) {
|
||||
@ -311,6 +320,15 @@ class AbstractAssembler : public ResourceObj {
|
||||
}
|
||||
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 ptr = start_a_const(sizeof(c), sizeof(c));
|
||||
if (ptr != NULL) {
|
||||
@ -321,8 +339,6 @@ class AbstractAssembler : public ResourceObj {
|
||||
}
|
||||
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.
|
||||
// Returns a static address which will eventually contain the constant.
|
||||
|
||||
@ -114,32 +114,4 @@ inline void Label::bind_loc(int pos, int 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
|
||||
|
||||
@ -467,5 +467,18 @@ void Disassembler::decode(nmethod* nm, outputStream* st) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -284,6 +284,9 @@
|
||||
develop(bool, SparcV9RegsHiBitsZero, true, \
|
||||
"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, \
|
||||
"Print ideal graph to XML file / network interface. " \
|
||||
"By default attempts to connect to the visualizer on a socket.") \
|
||||
|
||||
@ -75,6 +75,18 @@
|
||||
# include "adfiles/ad_zero.hpp"
|
||||
#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.
|
||||
|
||||
// Return the index at which m must be inserted (or already exists).
|
||||
@ -432,13 +444,14 @@ void Compile::print_compile_messages() {
|
||||
}
|
||||
|
||||
|
||||
void Compile::init_scratch_buffer_blob() {
|
||||
if( scratch_buffer_blob() != NULL ) return;
|
||||
void Compile::init_scratch_buffer_blob(int const_size) {
|
||||
if (scratch_buffer_blob() != NULL) return;
|
||||
|
||||
// Construct a temporary CodeBuffer to have it construct a BufferBlob
|
||||
// Cache this BufferBlob for this compile.
|
||||
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);
|
||||
// Record the buffer blob for next time.
|
||||
set_scratch_buffer_blob(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-------------------------------------
|
||||
// Helper function that computes size by emitting code
|
||||
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.
|
||||
// This is a pretty expensive way to compute a size,
|
||||
// but it works well enough if seldom used.
|
||||
@ -476,13 +499,20 @@ uint Compile::scratch_emit_size(const Node* n) {
|
||||
address blob_end = (address)locs_buf;
|
||||
assert(blob->content_contains(blob_end), "sanity");
|
||||
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);
|
||||
assert(locs_buf != NULL, "sanity");
|
||||
int lsize = MAX_locs_size / 2;
|
||||
buf.insts()->initialize_shared_locs(&locs_buf[0], lsize);
|
||||
buf.stubs()->initialize_shared_locs(&locs_buf[lsize], lsize);
|
||||
int lsize = MAX_locs_size / 3;
|
||||
buf.consts()->initialize_shared_locs(&locs_buf[lsize * 0], 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());
|
||||
|
||||
// End scratch_emit_size section.
|
||||
set_in_scratch_emit_size(false);
|
||||
|
||||
return buf.insts_size();
|
||||
}
|
||||
|
||||
@ -516,10 +546,13 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
||||
_orig_pc_slot(0),
|
||||
_orig_pc_slot_offset_in_bytes(0),
|
||||
_has_method_handle_invokes(false),
|
||||
_mach_constant_base_node(NULL),
|
||||
_node_bundling_limit(0),
|
||||
_node_bundling_base(NULL),
|
||||
_java_calls(0),
|
||||
_inner_loops(0),
|
||||
_scratch_const_size(-1),
|
||||
_in_scratch_emit_size(false),
|
||||
#ifndef PRODUCT
|
||||
_trace_opto_output(TraceOptoOutput || method()->has_option("TraceOptoOutput")),
|
||||
_printer(IdealGraphPrinter::printer()),
|
||||
@ -783,6 +816,7 @@ Compile::Compile( ciEnv* ci_env,
|
||||
_failure_reason(NULL),
|
||||
_code_buffer("Compile::Fill_buffer"),
|
||||
_has_method_handle_invokes(false),
|
||||
_mach_constant_base_node(NULL),
|
||||
_node_bundling_limit(0),
|
||||
_node_bundling_base(NULL),
|
||||
_java_calls(0),
|
||||
@ -2862,3 +2896,207 @@ Compile::TracePhase::~TracePhase() {
|
||||
_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;
|
||||
class InlineTree;
|
||||
class Int_Array;
|
||||
class Matcher;
|
||||
class MachConstantNode;
|
||||
class MachConstantBaseNode;
|
||||
class MachNode;
|
||||
class MachOper;
|
||||
class MachSafePointNode;
|
||||
class Node;
|
||||
class Node_Array;
|
||||
@ -139,6 +142,81 @@ class Compile : public Phase {
|
||||
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:
|
||||
// Fixed parameters to this compilation.
|
||||
const int _compile_id;
|
||||
@ -212,6 +290,11 @@ class Compile : public Phase {
|
||||
Node* _recent_alloc_obj;
|
||||
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,
|
||||
// tracked per node.
|
||||
enum { _log2_node_notes_block_size = 8,
|
||||
@ -272,6 +355,8 @@ class Compile : public Phase {
|
||||
static int _CompiledZap_count; // counter compared against CompileZap[First/Last]
|
||||
BufferBlob* _scratch_buffer_blob; // 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:
|
||||
// Accessors
|
||||
@ -454,6 +539,12 @@ class Compile : public Phase {
|
||||
_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
|
||||
Node* top() const { return _top; }
|
||||
|
||||
@ -605,13 +696,16 @@ class Compile : public Phase {
|
||||
Dependencies* dependencies() { return env()->dependencies(); }
|
||||
static int CompiledZap_count() { return _CompiledZap_count; }
|
||||
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; }
|
||||
relocInfo* scratch_locs_memory() { return _scratch_locs_memory; }
|
||||
void set_scratch_locs_memory(relocInfo* b) { _scratch_locs_memory = b; }
|
||||
|
||||
// emit to scratch blob, report resulting size
|
||||
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 {
|
||||
MAX_inst_size = 1024,
|
||||
@ -692,7 +786,7 @@ class Compile : public Phase {
|
||||
void Fill_buffer();
|
||||
|
||||
// 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
|
||||
// at the head of a loop.
|
||||
|
||||
@ -89,7 +89,7 @@ void PhaseCFG::replace_block_proj_ctrl( Node *n ) {
|
||||
assert(in0 != NULL, "Only control-dependent");
|
||||
const Node *p = in0->is_block_proj();
|
||||
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
|
||||
Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block
|
||||
uint j = 0;
|
||||
|
||||
@ -489,6 +489,20 @@ void MachTypeNode::dump_spec(outputStream *st) const {
|
||||
}
|
||||
#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
|
||||
void MachNullCheckNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
|
||||
|
||||
@ -231,9 +231,6 @@ public:
|
||||
// Return number of relocatable values contained in this instruction
|
||||
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.
|
||||
virtual uint hash() const;
|
||||
virtual uint cmp( const Node &n ) const;
|
||||
@ -348,6 +345,65 @@ public:
|
||||
#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-----------------------------------
|
||||
// Machine Unvalidated Entry Point Node
|
||||
class MachUEPNode : public MachIdealNode {
|
||||
|
||||
@ -365,6 +365,10 @@ public:
|
||||
// registers? True for Intel but false for most RISCs
|
||||
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();
|
||||
|
||||
// Generate implicit null check for narrow oops if it can fold
|
||||
|
||||
@ -81,6 +81,8 @@ class MachCallLeafNode;
|
||||
class MachCallNode;
|
||||
class MachCallRuntimeNode;
|
||||
class MachCallStaticJavaNode;
|
||||
class MachConstantBaseNode;
|
||||
class MachConstantNode;
|
||||
class MachIfNode;
|
||||
class MachNode;
|
||||
class MachNullCheckNode;
|
||||
@ -566,10 +568,12 @@ public:
|
||||
DEFINE_CLASS_ID(MachCallDynamicJava, MachCallJava, 1)
|
||||
DEFINE_CLASS_ID(MachCallRuntime, MachCall, 1)
|
||||
DEFINE_CLASS_ID(MachCallLeaf, MachCallRuntime, 0)
|
||||
DEFINE_CLASS_ID(MachSpillCopy, Mach, 1)
|
||||
DEFINE_CLASS_ID(MachNullCheck, Mach, 2)
|
||||
DEFINE_CLASS_ID(MachIf, Mach, 3)
|
||||
DEFINE_CLASS_ID(MachTemp, Mach, 4)
|
||||
DEFINE_CLASS_ID(MachSpillCopy, Mach, 1)
|
||||
DEFINE_CLASS_ID(MachNullCheck, Mach, 2)
|
||||
DEFINE_CLASS_ID(MachIf, Mach, 3)
|
||||
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(CatchProj, Proj, 0)
|
||||
@ -734,6 +738,8 @@ public:
|
||||
DEFINE_CLASS_QUERY(MachCallLeaf)
|
||||
DEFINE_CLASS_QUERY(MachCallRuntime)
|
||||
DEFINE_CLASS_QUERY(MachCallStaticJava)
|
||||
DEFINE_CLASS_QUERY(MachConstantBase)
|
||||
DEFINE_CLASS_QUERY(MachConstant)
|
||||
DEFINE_CLASS_QUERY(MachIf)
|
||||
DEFINE_CLASS_QUERY(MachNullCheck)
|
||||
DEFINE_CLASS_QUERY(MachReturn)
|
||||
|
||||
@ -61,11 +61,6 @@ void Compile::Output() {
|
||||
// RootNode goes
|
||||
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 java calls and inner loops which are aligned.
|
||||
if ( C->check_node_count((NodeLimitFudgeFactor + C->java_calls()*3 +
|
||||
@ -333,7 +328,7 @@ void Compile::compute_loop_first_inst_sizes() {
|
||||
//----------------------Shorten_branches---------------------------------------
|
||||
// The architecture description provides short branch variants for some long
|
||||
// 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
|
||||
MachNode *_nop_list[Bundle::_nop_count];
|
||||
@ -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.
|
||||
// Start with 2-bytes of reloc info for the unvalidated entry point
|
||||
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,
|
||||
// relative jmp_end, reloc_size and const_size information.
|
||||
// The second performs short branch substitution using the pessimistic
|
||||
// sizing. The third inserts nops where needed.
|
||||
// relative jmp_end and reloc_size information. The second performs
|
||||
// short branch substitution using the pessimistic sizing. The
|
||||
// third inserts nops where needed.
|
||||
|
||||
Node *nj; // tmp
|
||||
|
||||
@ -381,7 +375,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
|
||||
MachNode *mach = nj->as_Mach();
|
||||
blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding
|
||||
reloc_size += mach->reloc();
|
||||
const_size += mach->const_size();
|
||||
if( mach->is_MachCall() ) {
|
||||
MachCallNode *mcall = mach->as_MachCall();
|
||||
// This destination address is NOT PC-relative
|
||||
@ -398,10 +391,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
|
||||
if (min_offset_from_last_call == 0) {
|
||||
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;
|
||||
@ -562,10 +551,6 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i
|
||||
// a relocation index.
|
||||
// The CodeBuffer will expand the locs array if this estimate is too low.
|
||||
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-----------------------------------
|
||||
@ -1102,10 +1087,39 @@ void Compile::Fill_buffer() {
|
||||
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
|
||||
// the length of the blocks
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1121,12 +1135,12 @@ void Compile::Fill_buffer() {
|
||||
code_req = const_req = stub_req = exception_handler_req = deopt_handler_req = 0x10; // force expansion
|
||||
|
||||
int total_req =
|
||||
const_req +
|
||||
code_req +
|
||||
pad_req +
|
||||
stub_req +
|
||||
exception_handler_req +
|
||||
deopt_handler_req + // deopt handler
|
||||
const_req;
|
||||
deopt_handler_req; // deopt handler
|
||||
|
||||
if (has_method_handle_invokes())
|
||||
total_req += deopt_handler_req; // deopt MH handler
|
||||
@ -1180,6 +1194,11 @@ void Compile::Fill_buffer() {
|
||||
|
||||
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
|
||||
Node *delay_slot = NULL;
|
||||
@ -1196,12 +1215,13 @@ void Compile::Fill_buffer() {
|
||||
cb->flush_bundle(true);
|
||||
|
||||
// Define the label at the beginning of the basic block
|
||||
if( labels_not_set )
|
||||
MacroAssembler(cb).bind( blk_labels[b->_pre_order] );
|
||||
|
||||
else
|
||||
assert( blk_labels[b->_pre_order].loc_pos() == cb->insts_size(),
|
||||
"label position does not match code offset" );
|
||||
if (labels_not_set) {
|
||||
MacroAssembler(cb).bind(blk_labels[b->_pre_order]);
|
||||
} else {
|
||||
assert(blk_labels[b->_pre_order].loc_pos() == cb->insts_size(),
|
||||
err_msg("label position does not match code offset: %d != %d",
|
||||
blk_labels[b->_pre_order].loc_pos(), cb->insts_size()));
|
||||
}
|
||||
|
||||
uint last_inst = b->_nodes.size();
|
||||
|
||||
@ -1718,9 +1738,17 @@ void Compile::ScheduleAndBundle() {
|
||||
// Create a data structure for all the scheduling information
|
||||
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 over all the basic blocks
|
||||
scheduling.DoScheduling();
|
||||
|
||||
// Clear the BufferBlob used for scheduling.
|
||||
clear_scratch_buffer_blob();
|
||||
}
|
||||
|
||||
//------------------------------ComputeLocalLatenciesForward-------------------
|
||||
|
||||
@ -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.
|
||||
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, ®nd);
|
||||
val = skip_copies(n->in(k));
|
||||
}
|
||||
|
||||
if( val == x ) return blk_adjust; // No progress?
|
||||
|
||||
bool single = is_single_register(val->ideal_reg());
|
||||
|
||||
@ -399,8 +399,14 @@ extern "C" void nm(intptr_t p) {
|
||||
extern "C" void disnm(intptr_t p) {
|
||||
Command c("disnm");
|
||||
CodeBlob* cb = CodeCache::find_blob((address) p);
|
||||
cb->print();
|
||||
Disassembler::decode(cb);
|
||||
nmethod* nm = cb->as_nmethod_or_null();
|
||||
if (nm) {
|
||||
nm->print();
|
||||
Disassembler::decode(nm);
|
||||
} else {
|
||||
cb->print();
|
||||
Disassembler::decode(cb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user