blob: c5765ac7d670285488f631b32ad4bd5dbbfee0e1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _EMITTER_IR_H
#define _EMITTER_IR_H
#include "tl/memory_pool.h"
#include "merced.h"
#include "open/types.h"
// defines
#define Patch Enc_Patch
#define Code_Patch Enc_Code_Patch
#define Branch_Patch Enc_Branch_Patch
#define Movl_Patch Enc_Movl_Patch
//////////////////////////////////////////////////////////////////
// class IPF_Encoder
//////////////////////////////////////////////////////////////////
class IPF_Encoder : public Merced_Encoder {
public:
IPF_Encoder() : Merced_Encoder(0) {
assert(*(U_32*)"JIT1"==0x3154494A);
// assure little-endian because get_slot01_code_image() needs it
}
void code_emit() { LDIE(51, "Not implemented"); } // shouldn't be called
void get_slot01_code_image(uint64 *p_code_image1, uint64 *p_code_image2) {
uint64& code_image1 = *p_code_image1;
uint64& code_image2 = *p_code_image2;
code_image1 = *(uint64 *)_char_value; // 5..45, little-endian
assert((slot_num==1 && (code_image1 & 0xFFFFC0000000001Full)==0) || // gashiman - Make constants gcc friendly
(slot_num==2 && (code_image1 & 0x000000000000001Full)==0) ); // gashiman - Make constants gcc friendly
code_image1 >>= 5;
if (slot_num!=1) {
assert(slot_num==2);
code_image2 = ((*((uint64 *)_char_value) >> 46)|(*((uint64 *)_char_value + 1) << 18));
assert((code_image2 & 0xFFFFFE0000000000ull)==0); // gashiman - Make constants gcc friendly
} else
code_image2 = 0;
slot_num = 0; // reset slot_num
{ ((uint64 *)_char_value)[0] = 0;
((uint64 *)_char_value)[1] = 0;
}
}
};
//////////////////////////////////////////////////////////////////
// class Encoder_All_Reg_BV
//////////////////////////////////////////////////////////////////
// number of registers
#define ENC_N_GEN_REG 128
#define ENC_N_FLOAT_REG 128
#define ENC_N_BRANCH_REG 8
#define ENC_N_PRED_REG 64
#define ENC_N_APPL_REG 128
#define ENC_N_REG (ENC_N_GEN_REG + ENC_N_FLOAT_REG + ENC_N_BRANCH_REG + ENC_N_PRED_REG + ENC_N_APPL_REG)
// A bit vector for representing all registers
// Logically, this class is a result of partial evaluation of the class
// Bit_Vector, for a fixed vector length equal to ENC_N_REG.
#define ENC_WORD_SIZE 64
#define ENC_ALL_REG_WORDS (ENC_N_REG/ENC_WORD_SIZE + 1)
#define ENC_UINT64_ONE ((uint64)0x01)
class Enc_All_Reg_BV {
uint64 _words[ENC_ALL_REG_WORDS];
public:
Enc_All_Reg_BV() {}
Enc_All_Reg_BV(bool init) {
if (init) set_all();
else reset_all();
}
void *operator new(size_t sz,tl::MemoryPool &mm) {return mm.alloc(sz);}
void operator delete (void *p, tl::MemoryPool& m) { }
void set(unsigned bit) {
assert(bit<ENC_N_REG);
_words[bit/ENC_WORD_SIZE] |= (ENC_UINT64_ONE << (bit % ENC_WORD_SIZE));
}
void reset(unsigned bit) {
assert(bit<ENC_N_REG);
_words[bit/ENC_WORD_SIZE] &= ~(ENC_UINT64_ONE << (bit % ENC_WORD_SIZE));
}
uint64 is_set(unsigned bit) {
assert(bit<ENC_N_REG);
return _words[bit/ENC_WORD_SIZE] & (ENC_UINT64_ONE << (bit % ENC_WORD_SIZE));
}
void set_all () {
memset(_words, 0xff, ENC_ALL_REG_WORDS * (ENC_WORD_SIZE/8));
}
void reset_all () {
memset(_words, 0x00, ENC_ALL_REG_WORDS * (ENC_WORD_SIZE/8));
}
int does_intersect(Enc_All_Reg_BV * bv) {
for (int i=0; i<ENC_ALL_REG_WORDS; i++) {
if (_words[i] & bv->_words[i])
return true;
}
return false;
}
};
//////////////////////////////////////////////////////////////////
// Enumerated types
//////////////////////////////////////////////////////////////////
// memory location types
enum Encoder_Memory_Type {
ENC_MT_unknown =0,
ENC_MT_field_handle =1,
ENC_MT_sp_offset =2,
ENC_MT_array_element =3,
ENC_MT_vt_entry =4,
ENC_MT_switch_entry =5,
ENC_MT_array_entry =6,
ENC_MT_object_vt =7,
ENC_MT_vt_class =8,
ENC_MT_quick_thread =9,
};
// special instructions that have exceptions for RAW and WAW orderings
#define ENC_SI_none 0x00
#define ENC_SI_brcall 0x01
#define ENC_SI_mtbr 0x02
#define ENC_SI_icmp 0x04
#define ENC_SI_cmp_and 0x08
#define ENC_SI_cmp_or 0x10
#define ENC_SI_mtip 0x20
#define ENC_SI_start_igroup 0x40
#define ENC_SI_end_igroup 0x80
// instruction flags
#define ENC_IF_mem_access 0x01 // instr is a memory access
#define ENC_IF_possible_exc 0x02 // instr might throw exception
#define ENC_IF_target 0x04 // instr is a target
#define ENC_IF_to_be_patched 0x08 // instr needs patching
#define ENC_IF_filled 0x10 // slot is filled
#define ENC_IF_should_stay_empty 0x20 // slot should stay empty
#define ENC_IF_instr_start 0x40 // slot is start of instr,i.e., not 2nd slot of ST_il
// target
#define ENC_NOT_A_TARGET 0xFFFFFFFFFFFFFFFF
// reference track
#define ENC_REF_dontcare 0x00
#define ENC_REF_set '1'
#define ENC_REF_reset '0'
//////////////////////////////////////////////////////////////////
// struct Encoder_Instr_IR
//////////////////////////////////////////////////////////////////
struct Encoder_Instr_IR {
uint64 code_image1;
// data for register dependency checking
union {
uint64 fast; // bit vector for 64 registers
Enc_All_Reg_BV * slow; // pointer to a bit vector for all registers
} read_regs;
union {
uint64 fast; // bit vector for 64 registers
Enc_All_Reg_BV * slow; // pointer to a bit vector for all registers
} written_regs;
uint16 bytecode_addr;
EM_Syllable_Type syl_type;
U_8 flags;
U_8 special_instr;
U_8 def_ref;
Encoder_Memory_Type mem_type;
uint64 mem_value;
unsigned patch_target_id;
Encoder_Instr_IR () : code_image1(0), syl_type(ST_null),
flags(0) {
read_regs.fast=written_regs.fast=0;
}
void init(bool fast_dep_check, int slot_number) {
code_image1=0;
bytecode_addr=0;
syl_type=ST_null;
flags = 0;
def_ref=ENC_REF_dontcare;
if (fast_dep_check)
read_regs.fast=written_regs.fast=0;
special_instr=ENC_SI_none;
}
int is_filled() { return (flags & ENC_IF_filled);}
int is_empty() { return !is_filled();}
int should_stay_empty() { return (flags & ENC_IF_should_stay_empty);}
int is_instr_head() { return (flags & ENC_IF_instr_start);}
int can_be_filled() {
return !(flags & (ENC_IF_filled | ENC_IF_should_stay_empty));
}
void filled() {flags |= ENC_IF_filled | ENC_IF_instr_start;}
void filled_tail() { flags |= ENC_IF_filled;}
void set_should_stay_empty() {flags |= ENC_IF_should_stay_empty;}
int is_mem_access() { return (flags & ENC_IF_mem_access);}
int may_throw_exc() { return (flags & ENC_IF_possible_exc);}
int is_target () { return (flags & ENC_IF_target);}
int needs_patching(){ return (flags & ENC_IF_to_be_patched);}
void set_is_mem_access() { flags |= ENC_IF_mem_access;}
void set_may_throw_exc() { flags |= ENC_IF_possible_exc;}
void set_is_target() { flags |= ENC_IF_target;}
void reset_is_target() { flags &= ~ENC_IF_target;}
void set_needs_patching(){ flags |= ENC_IF_to_be_patched;}
int is_call() { return special_instr == ENC_SI_brcall;}
int starts_inst_group() {return special_instr & ENC_SI_start_igroup;}
int ends_inst_group() {return special_instr & ENC_SI_end_igroup;}
};
struct Encoder_Unscheduled_Instr_IR : public Encoder_Instr_IR {
uint64 code_image2;
unsigned target_id;
// data for GC1 support
unsigned dest_ref; // destination position in a ref def vector
unsigned base_pos; // base pos if interior ptr. NOT_A_BASE if know that
// it is not an interior pointer
uint64 ref_info; // prepared reference info
void init(bool fast_dep_check, int slot_number) {
Encoder_Instr_IR::init(fast_dep_check, slot_number);
code_image2=0;
target_id=unsigned(-1);
dest_ref = 0;
}
};
//////////////////////////////////////////////////////////////////////////
// code patching
//////////////////////////////////////////////////////////////////////////
class Patch {
protected:
Patch *const _next; // next patch in list
Patch(Patch *n) : _next(n) {}
public:
virtual void apply(char *code_buffer, uint64* taret_offset_tbl) = 0;
Patch *next() {return _next;}
};
class Code_Patch : public Patch {
public:
Code_Patch(Patch *n, uint64 o, unsigned s, unsigned p) :
Patch(n), offset(o), slot(s), patch_target_id(p) {}
virtual void apply(char *code_buffer, uint64* target_offset_tbl) = 0;
void *operator new(size_t sz,tl::MemoryPool& m) {return m.alloc(sz);}
void operator delete (void *p, tl::MemoryPool& m) { }
protected:
const uint64 offset; // offset of instruction being patched
const int slot; // slot of instruction being patched
const unsigned patch_target_id; // id of a target that needs replacing
};
class Branch_Patch : public Code_Patch {
public:
Branch_Patch(Patch *n, uint64 o, unsigned s, unsigned p) :
Code_Patch(n,o,s,p) {}
void apply(char *code_buffer, uint64* target_offset_tbl);
};
class Movl_Patch : public Code_Patch {
public:
Movl_Patch (Patch *n, uint64 o, unsigned s, unsigned p) :
Code_Patch(n,o,s,p) {}
void apply(char * code_buffer, uint64 * target_offset_tbl);
};
class Switch_Patch : public Patch {
public:
Switch_Patch(Patch *n, unsigned tgt_id, uint64 * addr) :
Patch(n), switch_target_id(tgt_id), entry_addr(addr) {}
void apply(char * code_buffer, uint64* target_offset_tbl);
void *operator new(size_t sz, tl::MemoryPool& m) {return m.alloc(sz);}
void operator delete (void *p, tl::MemoryPool& m) { }
protected:
const unsigned switch_target_id; // id of a target that needs patching
uint64 * const entry_addr; // address of the data entry with the target
};
//////////////////////////////////////////////////////////////////////////
// miscelaneous structures
//////////////////////////////////////////////////////////////////////////
#define ENC_N_WBUF_INSTR ((ENC_WBUF_LEN) * (ENC_N_SLOTS))
#define ENC_BDL_needs_stop 0x01
#define ENC_BDL_is_target 0x02
struct Encoder_Bundle_IR {
Encoder_Instr_IR * slots;
uint16 avail_tmplts; // a bit vector for 12 templates
EM_Templates tmplt_number;
U_8 flags;
unsigned target_id;
void init(bool fast_reg_dep_check) {
int i;
assert (ENC_N_TMPLT <= 16);
avail_tmplts = ENC_ALL_AVLB_TMPLTS;
for (i=0;i<ENC_N_SLOTS; i++)
slots[i].init(fast_reg_dep_check,i);
tmplt_number=TMPLT_bad1;
flags = ENC_BDL_needs_stop;
}
int is_not_empty() {
return (slots[0].is_filled() || slots[1].is_filled() || slots[2].is_filled());
}
};
#endif // EMITTER_IR_H