lp_bld_init.c revision 4c73030d47f39441d718157f7d9a59c136bbfac0
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_compiler.h" 30#include "util/u_cpu_detect.h" 31#include "util/u_debug.h" 32#include "util/u_memory.h" 33#include "util/u_simple_list.h" 34#include "lp_bld_debug.h" 35#include "lp_bld_init.h" 36 37#include <llvm-c/Transforms/Scalar.h> 38 39 40#ifdef DEBUG 41unsigned gallivm_debug = 0; 42 43static const struct debug_named_value lp_bld_debug_flags[] = { 44 { "tgsi", GALLIVM_DEBUG_TGSI, NULL }, 45 { "ir", GALLIVM_DEBUG_IR, NULL }, 46 { "asm", GALLIVM_DEBUG_ASM, NULL }, 47 { "nopt", GALLIVM_DEBUG_NO_OPT, NULL }, 48 { "perf", GALLIVM_DEBUG_PERF, NULL }, 49 { "no_brilinear", GALLIVM_DEBUG_NO_BRILINEAR, NULL }, 50 { "gc", GALLIVM_DEBUG_GC, NULL }, 51 DEBUG_NAMED_VALUE_END 52}; 53 54DEBUG_GET_ONCE_FLAGS_OPTION(gallivm_debug, "GALLIVM_DEBUG", lp_bld_debug_flags, 0) 55#endif 56 57 58static boolean gallivm_initialized = FALSE; 59 60 61/* 62 * Optimization values are: 63 * - 0: None (-O0) 64 * - 1: Less (-O1) 65 * - 2: Default (-O2, -Os) 66 * - 3: Aggressive (-O3) 67 * 68 * See also CodeGenOpt::Level in llvm/Target/TargetMachine.h 69 */ 70enum LLVM_CodeGenOpt_Level { 71#if HAVE_LLVM >= 0x207 72 None, // -O0 73 Less, // -O1 74 Default, // -O2, -Os 75 Aggressive // -O3 76#else 77 Default, 78 None, 79 Aggressive 80#endif 81}; 82 83 84/** 85 * LLVM 2.6 permits only one ExecutionEngine to be created. This is it. 86 */ 87static LLVMExecutionEngineRef GlobalEngine = NULL; 88 89/** 90 * Same gallivm state shared by all contexts. 91 */ 92static struct gallivm_state *GlobalGallivm = NULL; 93 94 95 96 97extern void 98lp_register_oprofile_jit_event_listener(LLVMExecutionEngineRef EE); 99 100extern void 101lp_set_target_options(void); 102 103 104 105/** 106 * Create the LLVM (optimization) pass manager and install 107 * relevant optimization passes. 108 * \return TRUE for success, FALSE for failure 109 */ 110static boolean 111create_pass_manager(struct gallivm_state *gallivm) 112{ 113 assert(!gallivm->passmgr); 114 115 gallivm->passmgr = LLVMCreateFunctionPassManager(gallivm->provider); 116 if (!gallivm->passmgr) 117 return FALSE; 118 119 LLVMAddTargetData(gallivm->target, gallivm->passmgr); 120 121 if ((gallivm_debug & GALLIVM_DEBUG_NO_OPT) == 0) { 122 /* These are the passes currently listed in llvm-c/Transforms/Scalar.h, 123 * but there are more on SVN. 124 * TODO: Add more passes. 125 */ 126 LLVMAddCFGSimplificationPass(gallivm->passmgr); 127 128 if (HAVE_LLVM >= 0x207 && sizeof(void*) == 4) { 129 /* For LLVM >= 2.7 and 32-bit build, use this order of passes to 130 * avoid generating bad code. 131 * Test with piglit glsl-vs-sqrt-zero test. 132 */ 133 LLVMAddConstantPropagationPass(gallivm->passmgr); 134 LLVMAddPromoteMemoryToRegisterPass(gallivm->passmgr); 135 } 136 else { 137 LLVMAddPromoteMemoryToRegisterPass(gallivm->passmgr); 138 LLVMAddConstantPropagationPass(gallivm->passmgr); 139 } 140 141 if (util_cpu_caps.has_sse4_1) { 142 /* FIXME: There is a bug in this pass, whereby the combination 143 * of fptosi and sitofp (necessary for trunc/floor/ceil/round 144 * implementation) somehow becomes invalid code. 145 */ 146 LLVMAddInstructionCombiningPass(gallivm->passmgr); 147 } 148 LLVMAddGVNPass(gallivm->passmgr); 149 } 150 else { 151 /* We need at least this pass to prevent the backends to fail in 152 * unexpected ways. 153 */ 154 LLVMAddPromoteMemoryToRegisterPass(gallivm->passmgr); 155 } 156 157 return TRUE; 158} 159 160 161/** 162 * Free gallivm object's LLVM allocations, but not the gallivm object itself. 163 */ 164static void 165free_gallivm_state(struct gallivm_state *gallivm) 166{ 167#if HAVE_LLVM >= 0x207 /* XXX or 0x208? */ 168 /* This leads to crashes w/ some versions of LLVM */ 169 LLVMModuleRef mod; 170 char *error; 171 172 if (gallivm->engine && gallivm->provider) 173 LLVMRemoveModuleProvider(gallivm->engine, gallivm->provider, 174 &mod, &error); 175#endif 176 177#if 0 178 /* XXX this seems to crash with all versions of LLVM */ 179 if (gallivm->provider) 180 LLVMDisposeModuleProvider(gallivm->provider); 181#endif 182 183 if (gallivm->passmgr) 184 LLVMDisposePassManager(gallivm->passmgr); 185 186#if HAVE_LLVM >= 0x207 187 if (gallivm->module) 188 LLVMDisposeModule(gallivm->module); 189#endif 190 191#if 0 192 /* Don't free the exec engine, it's a global/singleton */ 193 if (gallivm->engine) 194 LLVMDisposeExecutionEngine(gallivm->engine); 195#endif 196 197#if 0 198 /* Don't free the TargetData, it's owned by the exec engine */ 199 LLVMDisposeTargetData(gallivm->target); 200#endif 201 202 if (gallivm->context) 203 LLVMContextDispose(gallivm->context); 204 205 if (gallivm->builder) 206 LLVMDisposeBuilder(gallivm->builder); 207 208 gallivm->engine = NULL; 209 gallivm->target = NULL; 210 gallivm->module = NULL; 211 gallivm->provider = NULL; 212 gallivm->passmgr = NULL; 213 gallivm->context = NULL; 214 gallivm->builder = NULL; 215} 216 217 218/** 219 * Allocate gallivm LLVM objects. 220 * \return TRUE for success, FALSE for failure 221 */ 222static boolean 223init_gallivm_state(struct gallivm_state *gallivm) 224{ 225 assert(!gallivm->context); 226 assert(!gallivm->module); 227 assert(!gallivm->provider); 228 229 lp_build_init(); 230 231 gallivm->context = LLVMContextCreate(); 232 if (!gallivm->context) 233 goto fail; 234 235 gallivm->module = LLVMModuleCreateWithNameInContext("gallivm", 236 gallivm->context); 237 if (!gallivm->module) 238 goto fail; 239 240 gallivm->provider = 241 LLVMCreateModuleProviderForExistingModule(gallivm->module); 242 if (!gallivm->provider) 243 goto fail; 244 245 if (!GlobalEngine) { 246 /* We can only create one LLVMExecutionEngine (w/ LLVM 2.6 anyway) */ 247 enum LLVM_CodeGenOpt_Level optlevel; 248 char *error = NULL; 249 250 if (gallivm_debug & GALLIVM_DEBUG_NO_OPT) { 251 optlevel = None; 252 } 253 else { 254 optlevel = Default; 255 } 256 257 if (LLVMCreateJITCompiler(&GlobalEngine, gallivm->provider, 258 (unsigned) optlevel, &error)) { 259 _debug_printf("%s\n", error); 260 LLVMDisposeMessage(error); 261 goto fail; 262 } 263 264#if defined(DEBUG) || defined(PROFILE) 265 lp_register_oprofile_jit_event_listener(GlobalEngine); 266#endif 267 } 268 269 gallivm->engine = GlobalEngine; 270 271 LLVMAddModuleProvider(gallivm->engine, gallivm->provider);//new 272 273 gallivm->target = LLVMGetExecutionEngineTargetData(gallivm->engine); 274 if (!gallivm->target) 275 goto fail; 276 277 if (!create_pass_manager(gallivm)) 278 goto fail; 279 280 gallivm->builder = LLVMCreateBuilderInContext(gallivm->context); 281 if (!gallivm->builder) 282 goto fail; 283 284 return TRUE; 285 286fail: 287 free_gallivm_state(gallivm); 288 return FALSE; 289} 290 291 292struct callback 293{ 294 garbage_collect_callback_func func; 295 void *cb_data; 296 struct callback *prev, *next; 297}; 298 299 300/** list of all garbage collector callbacks */ 301static struct callback callback_list = {NULL, NULL, NULL, NULL}; 302 303 304/** 305 * Register a function with gallivm which will be called when we 306 * do garbage collection. 307 */ 308void 309gallivm_register_garbage_collector_callback(garbage_collect_callback_func func, 310 void *cb_data) 311{ 312 struct callback *cb; 313 314 if (!callback_list.prev) { 315 make_empty_list(&callback_list); 316 } 317 318 /* see if already in list */ 319 foreach(cb, &callback_list) { 320 if (cb->func == func && cb->cb_data == cb_data) 321 return; 322 } 323 324 /* add to list */ 325 cb = CALLOC_STRUCT(callback); 326 if (cb) { 327 cb->func = func; 328 cb->cb_data = cb_data; 329 insert_at_head(&callback_list, cb); 330 } 331} 332 333 334/** 335 * Remove a callback. 336 */ 337void 338gallivm_remove_garbage_collector_callback(garbage_collect_callback_func func, 339 void *cb_data) 340{ 341 struct callback *cb; 342 343 /* search list */ 344 foreach(cb, &callback_list) { 345 if (cb->func == func && cb->cb_data == cb_data) { 346 /* found, remove it */ 347 remove_from_list(cb); 348 return; 349 } 350 } 351} 352 353 354/** 355 * Call the callback functions (which are typically in the 356 * draw module and llvmpipe driver. 357 */ 358static void 359call_garbage_collector_callbacks(void) 360{ 361 struct callback *cb; 362 foreach(cb, &callback_list) { 363 cb->func(cb->cb_data); 364 } 365} 366 367 368 369/** 370 * Other gallium components using gallivm should call this periodically 371 * to let us do garbage collection (or at least try to free memory 372 * accumulated by the LLVM libraries). 373 */ 374void 375gallivm_garbage_collect(struct gallivm_state *gallivm) 376{ 377 if (gallivm->context) { 378 if (gallivm_debug & GALLIVM_DEBUG_GC) 379 debug_printf("***** Doing LLVM garbage collection\n"); 380 381 call_garbage_collector_callbacks(); 382 free_gallivm_state(gallivm); 383 init_gallivm_state(gallivm); 384 } 385} 386 387 388void 389lp_build_init(void) 390{ 391 if (gallivm_initialized) 392 return; 393 394#ifdef DEBUG 395 gallivm_debug = debug_get_option_gallivm_debug(); 396#endif 397 398 lp_set_target_options(); 399 400 LLVMInitializeNativeTarget(); 401 402 LLVMLinkInJIT(); 403 404 util_cpu_detect(); 405 406 gallivm_initialized = TRUE; 407 408#if 0 409 /* For simulating less capable machines */ 410 util_cpu_caps.has_sse3 = 0; 411 util_cpu_caps.has_ssse3 = 0; 412 util_cpu_caps.has_sse4_1 = 0; 413#endif 414} 415 416 417 418/** 419 * Create a new gallivm_state object. 420 * Note that we return a singleton. 421 */ 422struct gallivm_state * 423gallivm_create(void) 424{ 425 if (!GlobalGallivm) { 426 GlobalGallivm = CALLOC_STRUCT(gallivm_state); 427 if (GlobalGallivm) { 428 if (!init_gallivm_state(GlobalGallivm)) { 429 FREE(GlobalGallivm); 430 GlobalGallivm = NULL; 431 } 432 } 433 } 434 return GlobalGallivm; 435} 436 437 438/** 439 * Destroy a gallivm_state object. 440 */ 441void 442gallivm_destroy(struct gallivm_state *gallivm) 443{ 444 /* No-op: don't destroy the singleton */ 445 (void) gallivm; 446} 447 448 449 450/* 451 * Hack to allow the linking of release LLVM static libraries on a debug build. 452 * 453 * See also: 454 * - http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/7234ea2b-0042-42ed-b4e2-5d8644dfb57d 455 */ 456#if defined(_MSC_VER) && defined(_DEBUG) 457#include <crtdefs.h> 458_CRTIMP void __cdecl 459_invalid_parameter_noinfo(void) {} 460#endif 461