Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2009 VMware, Inc. |
||
4 | * All Rights Reserved. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * copy of this software and associated documentation files (the |
||
8 | * "Software"), to deal in the Software without restriction, including |
||
9 | * without limitation the rights to use, copy, modify, merge, publish, |
||
10 | * distribute, sub license, and/or sell copies of the Software, and to |
||
11 | * permit persons to whom the Software is furnished to do so, subject to |
||
12 | * the following conditions: |
||
13 | * |
||
14 | * The above copyright notice and this permission notice (including the |
||
15 | * next paragraph) shall be included in all copies or substantial portions |
||
16 | * of the Software. |
||
17 | * |
||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
||
21 | * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR |
||
22 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||
24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
25 | * |
||
26 | **************************************************************************/ |
||
27 | |||
28 | |||
29 | #include "pipe/p_config.h" |
||
30 | #include "pipe/p_compiler.h" |
||
31 | #include "util/u_cpu_detect.h" |
||
32 | #include "util/u_debug.h" |
||
33 | #include "util/u_memory.h" |
||
34 | #include "util/simple_list.h" |
||
35 | #include "os/os_time.h" |
||
36 | #include "lp_bld.h" |
||
37 | #include "lp_bld_debug.h" |
||
38 | #include "lp_bld_misc.h" |
||
39 | #include "lp_bld_init.h" |
||
40 | |||
41 | #include |
||
42 | #include |
||
43 | #include |
||
44 | |||
45 | |||
46 | /* Only MCJIT is available as of LLVM SVN r216982 */ |
||
47 | #if HAVE_LLVM >= 0x0306 |
||
48 | # define USE_MCJIT 1 |
||
49 | #elif defined(PIPE_ARCH_PPC_64) || defined(PIPE_ARCH_S390) || defined(PIPE_ARCH_ARM) || defined(PIPE_ARCH_AARCH64) |
||
50 | # define USE_MCJIT 1 |
||
51 | #else |
||
52 | # define USE_MCJIT 0 |
||
53 | #endif |
||
54 | |||
55 | #if USE_MCJIT |
||
56 | void LLVMLinkInMCJIT(); |
||
57 | #endif |
||
58 | |||
59 | #ifdef DEBUG |
||
60 | unsigned gallivm_debug = 0; |
||
61 | |||
62 | static const struct debug_named_value lp_bld_debug_flags[] = { |
||
63 | { "tgsi", GALLIVM_DEBUG_TGSI, NULL }, |
||
64 | { "ir", GALLIVM_DEBUG_IR, NULL }, |
||
65 | { "asm", GALLIVM_DEBUG_ASM, NULL }, |
||
66 | { "nopt", GALLIVM_DEBUG_NO_OPT, NULL }, |
||
67 | { "perf", GALLIVM_DEBUG_PERF, NULL }, |
||
68 | { "no_brilinear", GALLIVM_DEBUG_NO_BRILINEAR, NULL }, |
||
69 | { "no_rho_approx", GALLIVM_DEBUG_NO_RHO_APPROX, NULL }, |
||
70 | { "no_quad_lod", GALLIVM_DEBUG_NO_QUAD_LOD, NULL }, |
||
71 | { "gc", GALLIVM_DEBUG_GC, NULL }, |
||
72 | DEBUG_NAMED_VALUE_END |
||
73 | }; |
||
74 | |||
75 | DEBUG_GET_ONCE_FLAGS_OPTION(gallivm_debug, "GALLIVM_DEBUG", lp_bld_debug_flags, 0) |
||
76 | #endif |
||
77 | |||
78 | |||
79 | static boolean gallivm_initialized = FALSE; |
||
80 | |||
81 | unsigned lp_native_vector_width; |
||
82 | |||
83 | |||
84 | /* |
||
85 | * Optimization values are: |
||
86 | * - 0: None (-O0) |
||
87 | * - 1: Less (-O1) |
||
88 | * - 2: Default (-O2, -Os) |
||
89 | * - 3: Aggressive (-O3) |
||
90 | * |
||
91 | * See also CodeGenOpt::Level in llvm/Target/TargetMachine.h |
||
92 | */ |
||
93 | enum LLVM_CodeGenOpt_Level { |
||
94 | None, // -O0 |
||
95 | Less, // -O1 |
||
96 | Default, // -O2, -Os |
||
97 | Aggressive // -O3 |
||
98 | }; |
||
99 | |||
100 | |||
101 | /** |
||
102 | * Create the LLVM (optimization) pass manager and install |
||
103 | * relevant optimization passes. |
||
104 | * \return TRUE for success, FALSE for failure |
||
105 | */ |
||
106 | static boolean |
||
107 | create_pass_manager(struct gallivm_state *gallivm) |
||
108 | { |
||
109 | char *td_str; |
||
110 | assert(!gallivm->passmgr); |
||
111 | assert(gallivm->target); |
||
112 | |||
113 | gallivm->passmgr = LLVMCreateFunctionPassManagerForModule(gallivm->module); |
||
114 | if (!gallivm->passmgr) |
||
115 | return FALSE; |
||
116 | /* |
||
117 | * TODO: some per module pass manager with IPO passes might be helpful - |
||
118 | * the generated texture functions may benefit from inlining if they are |
||
119 | * simple, or constant propagation into them, etc. |
||
120 | */ |
||
121 | |||
122 | // Old versions of LLVM get the DataLayout from the pass manager. |
||
123 | LLVMAddTargetData(gallivm->target, gallivm->passmgr); |
||
124 | |||
125 | // New ones from the Module. |
||
126 | td_str = LLVMCopyStringRepOfTargetData(gallivm->target); |
||
127 | LLVMSetDataLayout(gallivm->module, td_str); |
||
128 | free(td_str); |
||
129 | |||
130 | if ((gallivm_debug & GALLIVM_DEBUG_NO_OPT) == 0) { |
||
131 | /* These are the passes currently listed in llvm-c/Transforms/Scalar.h, |
||
132 | * but there are more on SVN. |
||
133 | * TODO: Add more passes. |
||
134 | */ |
||
135 | LLVMAddScalarReplAggregatesPass(gallivm->passmgr); |
||
136 | LLVMAddLICMPass(gallivm->passmgr); |
||
137 | LLVMAddCFGSimplificationPass(gallivm->passmgr); |
||
138 | LLVMAddReassociatePass(gallivm->passmgr); |
||
139 | LLVMAddPromoteMemoryToRegisterPass(gallivm->passmgr); |
||
140 | LLVMAddConstantPropagationPass(gallivm->passmgr); |
||
141 | LLVMAddInstructionCombiningPass(gallivm->passmgr); |
||
142 | LLVMAddGVNPass(gallivm->passmgr); |
||
143 | } |
||
144 | else { |
||
145 | /* We need at least this pass to prevent the backends to fail in |
||
146 | * unexpected ways. |
||
147 | */ |
||
148 | LLVMAddPromoteMemoryToRegisterPass(gallivm->passmgr); |
||
149 | } |
||
150 | |||
151 | return TRUE; |
||
152 | } |
||
153 | |||
154 | |||
155 | /** |
||
156 | * Free gallivm object's LLVM allocations, but not any generated code |
||
157 | * nor the gallivm object itself. |
||
158 | */ |
||
159 | void |
||
160 | gallivm_free_ir(struct gallivm_state *gallivm) |
||
161 | { |
||
162 | if (gallivm->passmgr) { |
||
163 | LLVMDisposePassManager(gallivm->passmgr); |
||
164 | } |
||
165 | |||
166 | if (gallivm->engine) { |
||
167 | /* This will already destroy any associated module */ |
||
168 | LLVMDisposeExecutionEngine(gallivm->engine); |
||
169 | } else if (gallivm->module) { |
||
170 | LLVMDisposeModule(gallivm->module); |
||
171 | } |
||
172 | |||
173 | #if !USE_MCJIT |
||
174 | /* Don't free the TargetData, it's owned by the exec engine */ |
||
175 | #else |
||
176 | if (gallivm->target) { |
||
177 | LLVMDisposeTargetData(gallivm->target); |
||
178 | } |
||
179 | #endif |
||
180 | |||
181 | if (gallivm->builder) |
||
182 | LLVMDisposeBuilder(gallivm->builder); |
||
183 | |||
184 | /* The LLVMContext should be owned by the parent of gallivm. */ |
||
185 | |||
186 | gallivm->engine = NULL; |
||
187 | gallivm->target = NULL; |
||
188 | gallivm->module = NULL; |
||
189 | gallivm->passmgr = NULL; |
||
190 | gallivm->context = NULL; |
||
191 | gallivm->builder = NULL; |
||
192 | } |
||
193 | |||
194 | |||
195 | /** |
||
196 | * Free LLVM-generated code. Should be done AFTER gallivm_free_ir(). |
||
197 | */ |
||
198 | static void |
||
199 | gallivm_free_code(struct gallivm_state *gallivm) |
||
200 | { |
||
201 | assert(!gallivm->module); |
||
202 | assert(!gallivm->engine); |
||
203 | lp_free_generated_code(gallivm->code); |
||
204 | gallivm->code = NULL; |
||
205 | lp_free_memory_manager(gallivm->memorymgr); |
||
206 | gallivm->memorymgr = NULL; |
||
207 | } |
||
208 | |||
209 | |||
210 | static boolean |
||
211 | init_gallivm_engine(struct gallivm_state *gallivm) |
||
212 | { |
||
213 | if (1) { |
||
214 | enum LLVM_CodeGenOpt_Level optlevel; |
||
215 | char *error = NULL; |
||
216 | int ret; |
||
217 | |||
218 | if (gallivm_debug & GALLIVM_DEBUG_NO_OPT) { |
||
219 | optlevel = None; |
||
220 | } |
||
221 | else { |
||
222 | optlevel = Default; |
||
223 | } |
||
224 | |||
225 | ret = lp_build_create_jit_compiler_for_module(&gallivm->engine, |
||
226 | &gallivm->code, |
||
227 | gallivm->module, |
||
228 | gallivm->memorymgr, |
||
229 | (unsigned) optlevel, |
||
230 | USE_MCJIT, |
||
231 | &error); |
||
232 | if (ret) { |
||
233 | _debug_printf("%s\n", error); |
||
234 | LLVMDisposeMessage(error); |
||
235 | goto fail; |
||
236 | } |
||
237 | } |
||
238 | |||
239 | #if !USE_MCJIT |
||
240 | gallivm->target = LLVMGetExecutionEngineTargetData(gallivm->engine); |
||
241 | if (!gallivm->target) |
||
242 | goto fail; |
||
243 | #else |
||
244 | if (0) { |
||
245 | /* |
||
246 | * Dump the data layout strings. |
||
247 | */ |
||
248 | |||
249 | LLVMTargetDataRef target = LLVMGetExecutionEngineTargetData(gallivm->engine); |
||
250 | char *data_layout; |
||
251 | char *engine_data_layout; |
||
252 | |||
253 | data_layout = LLVMCopyStringRepOfTargetData(gallivm->target); |
||
254 | engine_data_layout = LLVMCopyStringRepOfTargetData(target); |
||
255 | |||
256 | if (1) { |
||
257 | debug_printf("module target data = %s\n", data_layout); |
||
258 | debug_printf("engine target data = %s\n", engine_data_layout); |
||
259 | } |
||
260 | |||
261 | free(data_layout); |
||
262 | free(engine_data_layout); |
||
263 | } |
||
264 | #endif |
||
265 | |||
266 | return TRUE; |
||
267 | |||
268 | fail: |
||
269 | return FALSE; |
||
270 | } |
||
271 | |||
272 | |||
273 | /** |
||
274 | * Allocate gallivm LLVM objects. |
||
275 | * \return TRUE for success, FALSE for failure |
||
276 | */ |
||
277 | static boolean |
||
278 | init_gallivm_state(struct gallivm_state *gallivm, const char *name, |
||
279 | LLVMContextRef context) |
||
280 | { |
||
281 | assert(!gallivm->context); |
||
282 | assert(!gallivm->module); |
||
283 | |||
284 | if (!lp_build_init()) |
||
285 | return FALSE; |
||
286 | |||
287 | gallivm->context = context; |
||
288 | |||
289 | if (!gallivm->context) |
||
290 | goto fail; |
||
291 | |||
292 | gallivm->module = LLVMModuleCreateWithNameInContext(name, |
||
293 | gallivm->context); |
||
294 | if (!gallivm->module) |
||
295 | goto fail; |
||
296 | |||
297 | gallivm->builder = LLVMCreateBuilderInContext(gallivm->context); |
||
298 | if (!gallivm->builder) |
||
299 | goto fail; |
||
300 | |||
301 | gallivm->memorymgr = lp_get_default_memory_manager(); |
||
302 | if (!gallivm->memorymgr) |
||
303 | goto fail; |
||
304 | |||
305 | /* FIXME: MC-JIT only allows compiling one module at a time, and it must be |
||
306 | * complete when MC-JIT is created. So defer the MC-JIT engine creation for |
||
307 | * now. |
||
308 | */ |
||
309 | #if !USE_MCJIT |
||
310 | if (!init_gallivm_engine(gallivm)) { |
||
311 | goto fail; |
||
312 | } |
||
313 | #else |
||
314 | /* |
||
315 | * MC-JIT engine compiles the module immediately on creation, so we can't |
||
316 | * obtain the target data from it. Instead we create a target data layout |
||
317 | * from a string. |
||
318 | * |
||
319 | * The produced layout strings are not precisely the same, but should make |
||
320 | * no difference for the kind of optimization passes we run. |
||
321 | * |
||
322 | * For reference this is the layout string on x64: |
||
323 | * |
||
324 | * e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-f128:128:128-n8:16:32:64 |
||
325 | * |
||
326 | * See also: |
||
327 | * - http://llvm.org/docs/LangRef.html#datalayout |
||
328 | */ |
||
329 | |||
330 | { |
||
331 | const unsigned pointer_size = 8 * sizeof(void *); |
||
332 | char layout[512]; |
||
333 | util_snprintf(layout, sizeof layout, "%c-p:%u:%u:%u-i64:64:64-a0:0:%u-s0:%u:%u", |
||
334 | #ifdef PIPE_ARCH_LITTLE_ENDIAN |
||
335 | 'e', // little endian |
||
336 | #else |
||
337 | 'E', // big endian |
||
338 | #endif |
||
339 | pointer_size, pointer_size, pointer_size, // pointer size, abi alignment, preferred alignment |
||
340 | pointer_size, // aggregate preferred alignment |
||
341 | pointer_size, pointer_size); // stack objects abi alignment, preferred alignment |
||
342 | |||
343 | gallivm->target = LLVMCreateTargetData(layout); |
||
344 | if (!gallivm->target) { |
||
345 | return FALSE; |
||
346 | } |
||
347 | } |
||
348 | #endif |
||
349 | |||
350 | if (!create_pass_manager(gallivm)) |
||
351 | goto fail; |
||
352 | |||
353 | return TRUE; |
||
354 | |||
355 | fail: |
||
356 | gallivm_free_ir(gallivm); |
||
357 | gallivm_free_code(gallivm); |
||
358 | return FALSE; |
||
359 | } |
||
360 | |||
361 | |||
362 | boolean |
||
363 | lp_build_init(void) |
||
364 | { |
||
365 | if (gallivm_initialized) |
||
366 | return TRUE; |
||
367 | |||
368 | #ifdef DEBUG |
||
369 | gallivm_debug = debug_get_option_gallivm_debug(); |
||
370 | #endif |
||
371 | |||
372 | lp_set_target_options(); |
||
373 | |||
374 | #if USE_MCJIT |
||
375 | LLVMLinkInMCJIT(); |
||
376 | #else |
||
377 | LLVMLinkInJIT(); |
||
378 | #endif |
||
379 | |||
380 | util_cpu_detect(); |
||
381 | |||
382 | /* AMD Bulldozer AVX's throughput is the same as SSE2; and because using |
||
383 | * 8-wide vector needs more floating ops than 4-wide (due to padding), it is |
||
384 | * actually more efficient to use 4-wide vectors on this processor. |
||
385 | * |
||
386 | * See also: |
||
387 | * - http://www.anandtech.com/show/4955/the-bulldozer-review-amd-fx8150-tested/2 |
||
388 | */ |
||
389 | if (util_cpu_caps.has_avx && |
||
390 | util_cpu_caps.has_intel) { |
||
391 | lp_native_vector_width = 256; |
||
392 | } else { |
||
393 | /* Leave it at 128, even when no SIMD extensions are available. |
||
394 | * Really needs to be a multiple of 128 so can fit 4 floats. |
||
395 | */ |
||
396 | lp_native_vector_width = 128; |
||
397 | } |
||
398 | |||
399 | lp_native_vector_width = debug_get_num_option("LP_NATIVE_VECTOR_WIDTH", |
||
400 | lp_native_vector_width); |
||
401 | |||
402 | if (lp_native_vector_width <= 128) { |
||
403 | /* Hide AVX support, as often LLVM AVX intrinsics are only guarded by |
||
404 | * "util_cpu_caps.has_avx" predicate, and lack the |
||
405 | * "lp_native_vector_width > 128" predicate. And also to ensure a more |
||
406 | * consistent behavior, allowing one to test SSE2 on AVX machines. |
||
407 | * XXX: should not play games with util_cpu_caps directly as it might |
||
408 | * get used for other things outside llvm too. |
||
409 | */ |
||
410 | util_cpu_caps.has_avx = 0; |
||
411 | util_cpu_caps.has_avx2 = 0; |
||
412 | } |
||
413 | |||
414 | #ifdef PIPE_ARCH_PPC_64 |
||
415 | /* Set the NJ bit in VSCR to 0 so denormalized values are handled as |
||
416 | * specified by IEEE standard (PowerISA 2.06 - Section 6.3). This guarantees |
||
417 | * that some rounding and half-float to float handling does not round |
||
418 | * incorrectly to 0. |
||
419 | * XXX: should eventually follow same logic on all platforms. |
||
420 | * Right now denorms get explicitly disabled (but elsewhere) for x86, |
||
421 | * whereas ppc64 explicitly enables them... |
||
422 | */ |
||
423 | if (util_cpu_caps.has_altivec) { |
||
424 | unsigned short mask[] = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, |
||
425 | 0xFFFF, 0xFFFF, 0xFFFE, 0xFFFF }; |
||
426 | __asm ( |
||
427 | "mfvscr %%v1\n" |
||
428 | "vand %0,%%v1,%0\n" |
||
429 | "mtvscr %0" |
||
430 | : |
||
431 | : "r" (*mask) |
||
432 | ); |
||
433 | } |
||
434 | #endif |
||
435 | |||
436 | gallivm_initialized = TRUE; |
||
437 | |||
438 | #if 0 |
||
439 | /* For simulating less capable machines */ |
||
440 | util_cpu_caps.has_sse3 = 0; |
||
441 | util_cpu_caps.has_ssse3 = 0; |
||
442 | util_cpu_caps.has_sse4_1 = 0; |
||
443 | util_cpu_caps.has_avx = 0; |
||
444 | util_cpu_caps.has_f16c = 0; |
||
445 | #endif |
||
446 | |||
447 | return TRUE; |
||
448 | } |
||
449 | |||
450 | |||
451 | |||
452 | /** |
||
453 | * Create a new gallivm_state object. |
||
454 | */ |
||
455 | struct gallivm_state * |
||
456 | gallivm_create(const char *name, LLVMContextRef context) |
||
457 | { |
||
458 | struct gallivm_state *gallivm; |
||
459 | |||
460 | gallivm = CALLOC_STRUCT(gallivm_state); |
||
461 | if (gallivm) { |
||
462 | if (!init_gallivm_state(gallivm, name, context)) { |
||
463 | FREE(gallivm); |
||
464 | gallivm = NULL; |
||
465 | } |
||
466 | } |
||
467 | |||
468 | return gallivm; |
||
469 | } |
||
470 | |||
471 | |||
472 | /** |
||
473 | * Destroy a gallivm_state object. |
||
474 | */ |
||
475 | void |
||
476 | gallivm_destroy(struct gallivm_state *gallivm) |
||
477 | { |
||
478 | gallivm_free_ir(gallivm); |
||
479 | gallivm_free_code(gallivm); |
||
480 | FREE(gallivm); |
||
481 | } |
||
482 | |||
483 | |||
484 | /** |
||
485 | * Validate a function. |
||
486 | * Verification is only done with debug builds. |
||
487 | */ |
||
488 | void |
||
489 | gallivm_verify_function(struct gallivm_state *gallivm, |
||
490 | LLVMValueRef func) |
||
491 | { |
||
492 | /* Verify the LLVM IR. If invalid, dump and abort */ |
||
493 | #ifdef DEBUG |
||
494 | if (LLVMVerifyFunction(func, LLVMPrintMessageAction)) { |
||
495 | lp_debug_dump_value(func); |
||
496 | assert(0); |
||
497 | return; |
||
498 | } |
||
499 | #endif |
||
500 | |||
501 | if (gallivm_debug & GALLIVM_DEBUG_IR) { |
||
502 | /* Print the LLVM IR to stderr */ |
||
503 | lp_debug_dump_value(func); |
||
504 | debug_printf("\n"); |
||
505 | } |
||
506 | } |
||
507 | |||
508 | |||
509 | /** |
||
510 | * Compile a module. |
||
511 | * This does IR optimization on all functions in the module. |
||
512 | */ |
||
513 | void |
||
514 | gallivm_compile_module(struct gallivm_state *gallivm) |
||
515 | { |
||
516 | LLVMValueRef func; |
||
517 | int64_t time_begin = 0; |
||
518 | |||
519 | assert(!gallivm->compiled); |
||
520 | |||
521 | if (gallivm->builder) { |
||
522 | LLVMDisposeBuilder(gallivm->builder); |
||
523 | gallivm->builder = NULL; |
||
524 | } |
||
525 | |||
526 | if (gallivm_debug & GALLIVM_DEBUG_PERF) |
||
527 | time_begin = os_time_get(); |
||
528 | |||
529 | /* Run optimization passes */ |
||
530 | LLVMInitializeFunctionPassManager(gallivm->passmgr); |
||
531 | func = LLVMGetFirstFunction(gallivm->module); |
||
532 | while (func) { |
||
533 | if (0) { |
||
534 | debug_printf("optimizing func %s...\n", LLVMGetValueName(func)); |
||
535 | } |
||
536 | LLVMRunFunctionPassManager(gallivm->passmgr, func); |
||
537 | func = LLVMGetNextFunction(func); |
||
538 | } |
||
539 | LLVMFinalizeFunctionPassManager(gallivm->passmgr); |
||
540 | |||
541 | if (gallivm_debug & GALLIVM_DEBUG_PERF) { |
||
542 | int64_t time_end = os_time_get(); |
||
543 | int time_msec = (int)(time_end - time_begin) / 1000; |
||
544 | debug_printf("optimizing module %s took %d msec\n", |
||
545 | lp_get_module_id(gallivm->module), time_msec); |
||
546 | } |
||
547 | |||
548 | /* Dump byte code to a file */ |
||
549 | if (0) { |
||
550 | LLVMWriteBitcodeToFile(gallivm->module, "llvmpipe.bc"); |
||
551 | debug_printf("llvmpipe.bc written\n"); |
||
552 | debug_printf("Invoke as \"llc -o - llvmpipe.bc\"\n"); |
||
553 | } |
||
554 | |||
555 | #if USE_MCJIT |
||
556 | assert(!gallivm->engine); |
||
557 | if (!init_gallivm_engine(gallivm)) { |
||
558 | assert(0); |
||
559 | } |
||
560 | #endif |
||
561 | assert(gallivm->engine); |
||
562 | |||
563 | ++gallivm->compiled; |
||
564 | |||
565 | if (gallivm_debug & GALLIVM_DEBUG_ASM) { |
||
566 | LLVMValueRef llvm_func = LLVMGetFirstFunction(gallivm->module); |
||
567 | |||
568 | while (llvm_func) { |
||
569 | /* |
||
570 | * Need to filter out functions which don't have an implementation, |
||
571 | * such as the intrinsics. May not be sufficient in case of IPO? |
||
572 | * LLVMGetPointerToGlobal() will abort otherwise. |
||
573 | */ |
||
574 | if (!LLVMIsDeclaration(llvm_func)) { |
||
575 | void *func_code = LLVMGetPointerToGlobal(gallivm->engine, llvm_func); |
||
576 | lp_disassemble(llvm_func, func_code); |
||
577 | } |
||
578 | llvm_func = LLVMGetNextFunction(llvm_func); |
||
579 | } |
||
580 | } |
||
581 | |||
582 | #if defined(PROFILE) |
||
583 | { |
||
584 | LLVMValueRef llvm_func = LLVMGetFirstFunction(gallivm->module); |
||
585 | |||
586 | while (llvm_func) { |
||
587 | if (!LLVMIsDeclaration(llvm_func)) { |
||
588 | void *func_code = LLVMGetPointerToGlobal(gallivm->engine, llvm_func); |
||
589 | lp_profile(llvm_func, func_code); |
||
590 | } |
||
591 | llvm_func = LLVMGetNextFunction(llvm_func); |
||
592 | } |
||
593 | } |
||
594 | #endif |
||
595 | } |
||
596 | |||
597 | |||
598 | |||
599 | func_pointer |
||
600 | gallivm_jit_function(struct gallivm_state *gallivm, |
||
601 | LLVMValueRef func) |
||
602 | { |
||
603 | void *code; |
||
604 | func_pointer jit_func; |
||
605 | |||
606 | assert(gallivm->compiled); |
||
607 | assert(gallivm->engine); |
||
608 | |||
609 | code = LLVMGetPointerToGlobal(gallivm->engine, func); |
||
610 | assert(code); |
||
611 | jit_func = pointer_to_func(code); |
||
612 | |||
613 | return jit_func; |
||
614 | }=> |