CACAO
CodeGenPass.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/CodeGenPass.cpp - CodeGenPass
2 
3  Copyright (C) 2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 
6  This file is part of CACAO.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2, or (at
11  your option) any later version.
12 
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  02110-1301, USA.
22 
23 */
24 
32 
33 #include "toolbox/logging.hpp"
34 
35 #include "mm/codememory.hpp"
36 #include "vm/types.hpp"
37 #include "vm/jit/jit.hpp"
38 #include "vm/jit/methodtree.hpp"
39 
40 #include "vm/jit/disass.hpp"
41 
42 #include "mm/memory.hpp"
43 
44 #include "md.hpp"
45 
46 #define DEBUG_NAME "compiler2/CodeGen"
47 
48 STAT_DECLARE_VAR(std::size_t, compiler_last_codesize, 0)
49 STAT_DECLARE_VAR(std::size_t, num_remaining_moves,0)
50 
51 namespace cacao {
52 namespace jit {
53 namespace compiler2 {
54 
55 #ifdef ENABLE_LOGGING
56 Option<bool> CodeGenPass::print_code("PrintCodeSegment","compiler2: print code segment",false,::cacao::option::xx_root());
57 Option<bool> CodeGenPass::print_data("PrintDataSegment","compiler2: print data segment",false,::cacao::option::xx_root());
58 #endif
59 
60 bool CodeGenPass::run(JITData &JD) {
61  MachineInstructionSchedule *MIS = get_Pass<MachineInstructionSchedulingPass>();
62  CodeMemory *CM = JD.get_CodeMemory();
63  CodeSegment &CS = CM->get_CodeSegment();
64 
65  // NOTE reverse so we see jump targets (which are not backedges) before
66  // the jump.
67  MachineBasicBlock *MBB = NULL;
68  std::size_t bb_start = 0;
70  e = MIS->rend() ; i != e ; ++i ) {
71  MBB = *i;
72  bb_start = CS.size();
74  e = MBB->rend(); i != e ; ++i) {
75  MachineInstruction *MI = *i;
76  std::size_t start = CS.size();
77  LOG2("MInst: " << MI << " emitted instruction:" << nl);
78  MI->emit(CM);
79  std::size_t end = CS.size();
80  #if defined(ENABLE_STATISTICS)
81  if (MI->is_move() && start != end) {
82  STATISTICS(++num_remaining_moves);
83  }
84  #endif
85  if (DEBUG_COND_N(2)) {
86  if ( start == end) {
87  LOG2("none" << nl);
88  } else {
90  while(start != end--) {
91  tmp.push_back(CS.at(end));
92  }
93  #if defined(ENABLE_DISASSEMBLER)
94  disassemble(&tmp.front(), &tmp.front() + tmp.size());
95  #else
96  // TODO print hex code
97  #endif
98  }
99  }
100  }
101  std::size_t bb_end = CS.size();
102  bbmap[MBB] = bb_end - bb_start;
103  }
104  assert(MBB != NULL);
105  // create stack frame
107  // fix last block (frame start, alignment)
108  bbmap[MBB] = CS.size() - bb_start;
109  // link code memory
110  CM->link();
111  // finish
112  finish(JD);
113  return true;
114 }
115 
116 std::size_t CodeGenPass::get_block_size(MachineBasicBlock *MBB) const {
117  BasicBlockMap::const_iterator i = bbmap.find(MBB);
118  if (i == bbmap.end())
119  return 0;
120  return i->second;
121 }
122 
123 namespace {
124 
125 #ifdef ENABLE_LOGGING
126 void print_hex(OStream &OS, u1 *start, u1 *end, uint32_t num_bytes_per_line = 8) {
127  OS << hex;
128  for(u1 *ptr = start, *e = end; ptr < e; ++ptr) {
129  if ( (ptr - start) % num_bytes_per_line == 0) {
130  OS << nl << "0x" << setz(16) << (u8) ptr << ": ";
131  }
132  OS << setz(2) << *ptr << ' ';
133  }
134  OS << dec << nl;
135 }
136 #endif
137 
138 } // end anonymous namespace
139 
140 void CodeGenPass::finish(JITData &JD) {
141  CodeMemory *CM = JD.get_CodeMemory();
142  CodeSegment &CS = CM->get_CodeSegment();
143  DataSegment &DS = CM->get_DataSegment();
144 #if 0
145  s4 alignedmcodelen;
146  jumpref *jr;
147  s4 alignedlen;
148 #endif
149  u1 *epoint;
150 
151  /* Get required compiler data. */
152 
153  codeinfo* code = JD.get_jitdata()->code;
154 #if 0
155  codegendata* cd = jd->cd;
156  registerdata* rd = jd->rd;
157 #endif
158 
159  /* prevent compiler warning */
160 
161 
162  /* calculate the code length */
163 
164  #if 0
165  s4 mcodelen = (s4) (JD.get_CodeMemory()->get_end() - JD.get_CodeMemory()->get_start());
166  s4 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
167  s4 dseglen = (s4) JD.get_CodeMemory()->data_size();
168  s4 aligneddseglen = MEMORY_ALIGN(dseglen, MAX_ALIGN);
169 
170 
171  s4 alignedlen = alignedmcodelen + aligneddseglen;
172  #endif
173 
174 #if 0
175  STATISTICS(count_code_len += mcodelen);
176  STATISTICS(count_data_len += cd->dseglen);
177 #endif
178 
179  /* allocate new memory */
180 
181  // Note that the DataSegment and the CodeSegment shall be aligned!
182  code->mcodelength = DS.size() + CS.size();
183  code->mcode = CNEW(u1, code->mcodelength);
184 
185  /* set the entrypoint of the method */
186 
187  assert(code->entrypoint == NULL);
188  code->entrypoint = epoint = (code->mcode + DS.size());
189 
190  /* fill the data segment (code->entrypoint must already be set!) */
191  MCOPY((void *) code->mcode, DS.get_start(), u1, DS.size());
192 
193  #if 0
194  size_t offset = 1;
195  /// @Cpp11 Could use vector::data()
196  for (CodeMemory::const_data_iterator i = JD.get_CodeMemory()->data_begin(),
197  e = JD.get_CodeMemory()->data_end() ; i != e; ++i) {
198  u1* ptr = epoint - offset++;
199  *ptr = *i;
200  LOG3("" << ptr
201  << ": " << hex << *i << " " << *ptr << dec << nl);
202  assert(ptr >= code->mcode);
203  }
204  #endif
205 
206  LOG2("mcode: " << code->mcode << nl);
207  LOG2("entry: " << code->entrypoint << nl);
208 
209  if (DEBUG_COND_N(2)) {
210  for(u8 *ptr = reinterpret_cast<u8*>(code->mcode),
211  *e = reinterpret_cast<u8*>(code->entrypoint); ptr < e; ++ptr) {
212  LOG2("" << setz(16) << hex << ptr
213  << ": " << setz(16) << (u8)*ptr << dec << nl);
214  }
215  }
216 
217  STATISTICS(compiler_last_codesize = code->mcodelength);
218 
219 #if 0
220  STATISTICS(count_code_len += mcodelen);
221  STATISTICS(count_data_len += cd->dseglen);
222 #endif
223 
224 
225 #if 0
226  dseg_finish(jd);
227 #endif
228 
229  /* copy code to the new location */
230 
231  CS.reverse();
232  MCOPY((void *) code->entrypoint, CS.get_start(), u1, CS.size());
233 
234  /* Fill runtime information about generated code. */
235 
236 #if 0
237  code->stackframesize = cd->stackframesize;
238  code->synchronizedoffset = rd->memuse * 8;
239  code->savedintcount = INT_SAV_CNT - rd->savintreguse;
240  code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
241 #else
242  code->stackframesize = 0;
243  code->synchronizedoffset = 0;
244  code->savedintcount = 0;
245  code->savedfltcount = 0;
246 #endif
247 #if defined(HAS_ADDRESS_REGISTER_FILE)
248  code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
249 #endif
250 
251  /* Create the exception table. */
252 
253 #if 0
255 #endif
256 
257  /* Create the linenumber table. */
258 
259 #if 0
260  code->linenumbertable = new LinenumberTable(jd);
261 
262  /* jump table resolving */
263  for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
264  *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
265  (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
266 
267 #endif
268  /* patcher resolving */
269 
270  patcher_resolve(code);
271  LOG2("Patchers:" << nl);
272  #if !defined(NDEBUG)
273  DEBUG2(patcher_list_show(code));
274  #endif
275 #if 0
276 #if defined(ENABLE_REPLACEMENT)
277  /* replacement point resolving */
278  {
279  int i;
280  rplpoint *rp;
281 
282  rp = code->rplpoints;
283  for (i=0; i<code->rplpointcount; ++i, ++rp) {
284  rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
285  }
286  }
287 #endif /* defined(ENABLE_REPLACEMENT) */
288 
289 #endif
290  /* Insert method into methodtree to find the entrypoint. */
291 
292  methodtree_insert(code->entrypoint, code->entrypoint + CS.size());
293 
294 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
295  /* resolve data segment references */
296 
297 #if 0
298  dseg_resolve_datareferences(jd);
299 #endif
300 #endif
301 
302  /* flush the instruction and data caches */
303 
304  md_cacheflush(code->mcode, code->mcodelength);
305 
306 #ifdef ENABLE_LOGGING
307  if (print_data) {
308  dbg() << nl << "Data Segment: " << *JD.get_Method() << hex;
309  print_hex(dbg(), code->mcode, code->entrypoint);
310  }
311  if (print_code) {
312  dbg() << nl << "Code Segment: " << *JD.get_Method() << hex;
313  print_hex(dbg(), code->entrypoint, code->mcode + code->mcodelength);
314  }
315 #endif
316 
317 }
318 
319 // pass usage
320 PassUsage& CodeGenPass::get_PassUsage(PassUsage &PU) const {
323  return PU;
324 }
325 // the address of this variable is used to identify the pass
326 char CodeGenPass::ID = 0;
327 
328 // registrate Pass
329 static PassRegistry<CodeGenPass> X("CodeGenPass");
330 
331 } // end namespace compiler2
332 } // end namespace jit
333 } // end namespace cacao
334 
335 
336 /*
337  * These are local overrides for various environment variables in Emacs.
338  * Please do not remove this and leave it at the end of the file, where
339  * Emacs will automagically detect them.
340  * ---------------------------------------------------------------------
341  * Local variables:
342  * mode: c++
343  * indent-tabs-mode: t
344  * c-basic-offset: 4
345  * tab-width: 4
346  * End:
347  * vim:noexpandtab:sw=4:ts=4:
348  */
basicblock * target
#define STATISTICS(x)
Wrapper for statistics only code.
Definition: statistics.hpp:975
reverse_iterator rbegin()
returns an reverse_iterator to the beginning
std::reverse_iterator< const_iterator > const_reverse_iterator
reverse_iterator rend()
returns an reverse_iterator to the end
Linenumber table of a Java method.
virtual void emit(CodeMemory *CM) const
emit machine code
uint8_t savedfltcount
Definition: code.hpp:91
int32_t stackframesize
Definition: code.hpp:88
jumpref * next
codeinfo * code
Definition: jit.hpp:128
A basic block of (scheduled) machine instructions.
u1 at(std::size_t i) const
get content
Definition: Segment.hpp:194
s4 mpc
Definition: jit.hpp:345
StackSlotManager * get_StackSlotManager()
Definition: JITData.hpp:56
int savintreguse
Definition: reg.hpp:88
void patcher_resolve(codeinfo *code)
Resolve all patchers in the current JIT run.
uint8_t u1
Definition: types.hpp:40
Hex hex
Definition: OStream.cpp:50
s4 mcodelength
Definition: code.hpp:85
std::size_t size() const
get size
Definition: Segment.hpp:153
#define DEBUG_COND_N(VERBOSE)
Definition: Debug.hpp:112
jitdata * get_jitdata() const
Definition: JITData.hpp:51
void md_cacheflush(u1 *addr, s4 nbytes)
Definition: md.c:49
const CodeSegment & get_CodeSegment() const
get CodeSegment
Definition: CodeMemory.hpp:65
void(* functionptr)(void)
Definition: global.hpp:39
#define INT_SAV_CNT
Definition: md-abi.hpp:73
u1 * mcode
Definition: code.hpp:83
void reverse()
reverse content
Definition: Segment.hpp:203
#define MAX_ALIGN
Definition: global.hpp:102
#define DEBUG2(STMT)
Definition: Debug.hpp:127
Instruction::InstID tmp[]
Definition: Matcher.cpp:55
void patcher_list_show(codeinfo *code)
Show the content of the whole patcher reference list for debugging purposes.
CodeMemory * get_CodeMemory()
Definition: JITData.hpp:57
std::vector< T, Allocator< T > > type
Definition: vector.hpp:38
jumpref * jumpreferences
uint64_t u8
Definition: types.hpp:49
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
Simple stream class for formatted output.
Definition: OStream.hpp:141
Container::const_reverse_iterator const_reverse_iterator
void dseg_finish(jitdata *jd)
Definition: dseg.cpp:46
MIIterator i
#define LOG2(STMT)
Definition: logging.hpp:93
int32_t s4
Definition: types.hpp:45
OStream & OS
virtual void create_frame(CodeMemory *CM, StackSlotManager *SSM) const =0
int savfltreguse
Definition: reg.hpp:91
#define LOG3(STMT)
Definition: logging.hpp:94
MIIterator e
#define FLT_SAV_CNT
Definition: md-abi.hpp:80
Proxy to encode explicit and implicit successors.
void exceptiontable_create(jitdata *jd)
int memuse
Definition: reg.hpp:84
int32_t synchronizedoffset
Definition: code.hpp:89
LinenumberTable * linenumbertable
Definition: code.hpp:94
OptionPrefix & xx_root()
Definition: Option.cpp:39
reverse_iterator rbegin()
returns an reverse_iterator to the beginning
#define MEMORY_ALIGN(pos, size)
Definition: memory.hpp:37
void methodtree_insert(void *startpc, void *endpc)
Definition: methodtree.cpp:148
void disassemble(u1 *start, u1 *end)
Definition: disass.cpp:403
reverse_iterator rend()
returns an reverse_iterator to the end
u1 * get_start()
get start address
Definition: Segment.hpp:173
#define MCOPY(dest, src, type, num)
Definition: memory.hpp:103
uintptr_t ptrint
Definition: types.hpp:54
static PassRegistry< BasicBlockSchedulingPass > X("BasicBlockSchedulingPass")
Nl nl
Definition: OStream.cpp:56
static SetZero setz(size_t w)
Definition: OStream.hpp:398
#define STAT_DECLARE_VAR(type, var, init)
Declare an external statistics variable.
Definition: statistics.hpp:963
Dec dec
Definition: OStream.cpp:48
uint8_t savedintcount
Definition: code.hpp:90
OStream & dbg()
The default destination for logging messages.
void add_requires()
PassName is required.
Definition: PassUsage.hpp:78
const DataSegment & get_DataSegment() const
get DataSegment
Definition: CodeMemory.hpp:69
u1 * entrypoint
Definition: code.hpp:84
#define CNEW(type, num)
Definition: codememory.hpp:34