gallivm: fix lp_build_sample_offset() crash when indexing a 1-D texture
[mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_init.c
index de07c222a39e1ec052e924f3ee39df2ac17bef75..69353dea09e40c2a431a0486c68d76949253ee9a 100644 (file)
 
 
 #include "pipe/p_compiler.h"
+#include "util/u_cpu_detect.h"
 #include "util/u_debug.h"
+#include "lp_bld_debug.h"
 #include "lp_bld_init.h"
 
+#include <llvm-c/Transforms/Scalar.h>
+
+
+#ifdef DEBUG
+unsigned gallivm_debug = 0;
+
+static const struct debug_named_value lp_bld_debug_flags[] = {
+   { "tgsi",   GALLIVM_DEBUG_TGSI, NULL },
+   { "ir",     GALLIVM_DEBUG_IR, NULL },
+   { "asm",    GALLIVM_DEBUG_ASM, NULL },
+   { "nopt",   GALLIVM_DEBUG_NO_OPT, NULL },
+   DEBUG_NAMED_VALUE_END
+};
+#endif
+
 
 LLVMModuleRef lp_build_module = NULL;
 LLVMExecutionEngineRef lp_build_engine = NULL;
 LLVMModuleProviderRef lp_build_provider = NULL;
 LLVMTargetDataRef lp_build_target = NULL;
+LLVMPassManagerRef lp_build_pass = NULL;
+
+
+/*
+ * Optimization values are:
+ * - 0: None (-O0)
+ * - 1: Less (-O1)
+ * - 2: Default (-O2, -Os)
+ * - 3: Aggressive (-O3)
+ *
+ * See also CodeGenOpt::Level in llvm/Target/TargetMachine.h
+ */
+enum LLVM_CodeGenOpt_Level {
+#if HAVE_LLVM >= 0x207
+   None,        // -O0
+   Less,        // -O1
+   Default,     // -O2, -Os
+   Aggressive   // -O3
+#else
+   Default,
+   None,
+   Aggressive
+#endif
+};
+
+
+extern void
+lp_register_oprofile_jit_event_listener(LLVMExecutionEngineRef EE);
+
+extern void
+lp_set_target_options(void);
 
 
 void
 lp_build_init(void)
 {
+#ifdef DEBUG
+   gallivm_debug = debug_get_flags_option("GALLIVM_DEBUG", lp_bld_debug_flags, 0 );
+#endif
+
+   lp_set_target_options();
+
    LLVMInitializeNativeTarget();
 
    LLVMLinkInJIT();
@@ -51,17 +105,66 @@ lp_build_init(void)
       lp_build_provider = LLVMCreateModuleProviderForExistingModule(lp_build_module);
 
    if (!lp_build_engine) {
+      enum LLVM_CodeGenOpt_Level optlevel;
       char *error = NULL;
 
-      if (LLVMCreateJITCompiler(&lp_build_engine, lp_build_provider, 1, &error)) {
+      if (gallivm_debug & GALLIVM_DEBUG_NO_OPT) {
+         optlevel = None;
+      }
+      else {
+         optlevel = Default;
+      }
+
+      if (LLVMCreateJITCompiler(&lp_build_engine, lp_build_provider,
+                                (unsigned)optlevel, &error)) {
          _debug_printf("%s\n", error);
          LLVMDisposeMessage(error);
          assert(0);
       }
+
+#if defined(DEBUG) || defined(PROFILE)
+      lp_register_oprofile_jit_event_listener(lp_build_engine);
+#endif
    }
 
    if (!lp_build_target)
       lp_build_target = LLVMGetExecutionEngineTargetData(lp_build_engine);
+
+   if (!lp_build_pass) {
+      lp_build_pass = LLVMCreateFunctionPassManager(lp_build_provider);
+      LLVMAddTargetData(lp_build_target, lp_build_pass);
+
+      if ((gallivm_debug & GALLIVM_DEBUG_NO_OPT) == 0) {
+         /* These are the passes currently listed in llvm-c/Transforms/Scalar.h,
+          * but there are more on SVN. */
+         /* TODO: Add more passes */
+         LLVMAddCFGSimplificationPass(lp_build_pass);
+         LLVMAddPromoteMemoryToRegisterPass(lp_build_pass);
+         LLVMAddConstantPropagationPass(lp_build_pass);
+         if(util_cpu_caps.has_sse4_1) {
+            /* FIXME: There is a bug in this pass, whereby the combination of fptosi
+             * and sitofp (necessary for trunc/floor/ceil/round implementation)
+             * somehow becomes invalid code.
+             */
+            LLVMAddInstructionCombiningPass(lp_build_pass);
+         }
+         LLVMAddGVNPass(lp_build_pass);
+      } else {
+         /* We need at least this pass to prevent the backends to fail in
+          * unexpected ways.
+          */
+         LLVMAddPromoteMemoryToRegisterPass(lp_build_pass);
+      }
+   }
+
+   util_cpu_detect();
+
+#if 0
+   /* For simulating less capable machines */
+   util_cpu_caps.has_sse3 = 0;
+   util_cpu_caps.has_ssse3 = 0;
+   util_cpu_caps.has_sse4_1 = 0;
+#endif
 }