/* unit -> bool */
CAMLprim value llvm_ee_initialize(value Unit) {
  LLVMLinkInMCJIT();

  return Val_bool(!LLVMInitializeNativeTarget() &&
                  !LLVMInitializeNativeAsmParser() &&
                  !LLVMInitializeNativeAsmPrinter());
}
Exemple #2
0
bool codegen_llvm_init()
{
  LLVMLinkInMCJIT();
  LLVMInitializeNativeTarget();
  LLVMInitializeAllTargets();
  LLVMInitializeAllTargetMCs();
  LLVMInitializeAllTargetInfos();
  LLVMInitializeAllAsmPrinters();
  LLVMInitializeAllAsmParsers();
  LLVMEnablePrettyStackTrace();
  LLVMInstallFatalErrorHandler(fatal_error);

  LLVMPassRegistryRef passreg = LLVMGetGlobalPassRegistry();
  LLVMInitializeCore(passreg);
  LLVMInitializeTransformUtils(passreg);
  LLVMInitializeScalarOpts(passreg);
  LLVMInitializeObjCARCOpts(passreg);
  LLVMInitializeVectorization(passreg);
  LLVMInitializeInstCombine(passreg);
  LLVMInitializeIPO(passreg);
  LLVMInitializeInstrumentation(passreg);
  LLVMInitializeAnalysis(passreg);
  LLVMInitializeIPA(passreg);
  LLVMInitializeCodeGen(passreg);
  LLVMInitializeTarget(passreg);

  return true;
}
Exemple #3
0
int main(int argc, char const *argv[]) {
    LLVMModuleRef mod = LLVMModuleCreateWithName("my_module");

    LLVMTypeRef param_types[] = { LLVMInt32Type(), LLVMInt32Type() };
    LLVMTypeRef ret_type = LLVMFunctionType(LLVMInt32Type(), param_types, 2, 0);
    LLVMValueRef sum = LLVMAddFunction(mod, "sum", ret_type);

    LLVMBasicBlockRef entry = LLVMAppendBasicBlock(sum, "entry");

    LLVMBuilderRef builder = LLVMCreateBuilder();
    LLVMPositionBuilderAtEnd(builder, entry);
    LLVMValueRef tmp = LLVMBuildAdd(builder, LLVMGetParam(sum, 0), LLVMGetParam(sum, 1), "tmp");
    LLVMBuildRet(builder, tmp);

    char *error = NULL;
    LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
    LLVMDisposeMessage(error);

    LLVMExecutionEngineRef engine;
    error = NULL;
    LLVMLinkInMCJIT();
    LLVMInitializeNativeAsmPrinter();
    LLVMInitializeNativeTarget();
    if (LLVMCreateExecutionEngineForModule(&engine, mod, &error) != 0) {
        fprintf(stderr, "failed to create execution engine\n");
        abort();
    }
    if (error) {
        fprintf(stderr, "error: %s\n", error);
        LLVMDisposeMessage(error);
        exit(EXIT_FAILURE);
    }

    if (argc < 3) {
        fprintf(stderr, "usage: %s x y\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    long long x = strtoll(argv[1], NULL, 10);
    long long y = strtoll(argv[2], NULL, 10);

    LLVMGenericValueRef args[] = {
        LLVMCreateGenericValueOfInt(LLVMInt32Type(), x, 0),
        LLVMCreateGenericValueOfInt(LLVMInt32Type(), y, 0)
    };
    LLVMGenericValueRef res = LLVMRunFunction(engine, sum, 2, args);
    printf("%d\n", (int)LLVMGenericValueToInt(res, 0));

    // Write out bitcode to file
    if (LLVMWriteBitcodeToFile(mod, "sum.bc") != 0) {
        fprintf(stderr, "error writing bitcode to file, skipping\n");
    }

    LLVMDisposeBuilder(builder);
    LLVMDisposeExecutionEngine(engine);
}
Exemple #4
0
void
lp_build_init(void)
{
   if (gallivm_initialized)
      return;

#ifdef DEBUG
   gallivm_debug = debug_get_option_gallivm_debug();
#endif

   lp_set_target_options();

#if USE_MCJIT
   LLVMLinkInMCJIT();
#else
   LLVMLinkInJIT();
#endif

   util_cpu_detect();

   /* AMD Bulldozer AVX's throughput is the same as SSE2; and because using
    * 8-wide vector needs more floating ops than 4-wide (due to padding), it is
    * actually more efficient to use 4-wide vectors on this processor.
    *
    * See also:
    * - http://www.anandtech.com/show/4955/the-bulldozer-review-amd-fx8150-tested/2
    */
   if (HAVE_AVX &&
       util_cpu_caps.has_avx &&
       util_cpu_caps.has_intel) {
      lp_native_vector_width = 256;
   } else {
      /* Leave it at 128, even when no SIMD extensions are available.
       * Really needs to be a multiple of 128 so can fit 4 floats.
       */
      lp_native_vector_width = 128;
   }
 
   lp_native_vector_width = debug_get_num_option("LP_NATIVE_VECTOR_WIDTH",
                                                 lp_native_vector_width);

   gallivm_initialized = TRUE;

#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
}
Exemple #5
0
extern "C" JSC::LLVMAPI* initializeAndGetJSCLLVMAPI(void (*callback)(const char*, ...))
{
    g_llvmTrapCallback = callback;
    
    LLVMInstallFatalErrorHandler(llvmCrash);

    if (!LLVMStartMultithreaded())
        callback("Could not start LLVM multithreading");
    
    LLVMLinkInMCJIT();
    
    // You think you want to call LLVMInitializeNativeTarget()? Think again. This presumes that
    // LLVM was ./configured correctly, which won't be the case in cross-compilation situations.
    
#if CPU(X86_64)
    LLVMInitializeX86TargetInfo();
    LLVMInitializeX86Target();
    LLVMInitializeX86TargetMC();
    LLVMInitializeX86AsmPrinter();
    LLVMInitializeX86Disassembler();
#elif CPU(ARM64)
    LLVMInitializeARM64TargetInfo();
    LLVMInitializeARM64Target();
    LLVMInitializeARM64TargetMC();
    LLVMInitializeARM64AsmPrinter();
    LLVMInitializeARM64Disassembler();
#else
    UNREACHABLE_FOR_PLATFORM();
#endif
    
    const char* args[] = {
        "llvmForJSC.dylib",
        "-enable-stackmap-liveness=true",
        "-enable-patchpoint-liveness=true"
    };
    llvm::cl::ParseCommandLineOptions(sizeof(args) / sizeof(const char*), args);
    
    JSC::LLVMAPI* result = new JSC::LLVMAPI;
    
#define LLVM_API_FUNCTION_ASSIGNMENT(returnType, name, signature) \
    result->name = LLVM##name;
    FOR_EACH_LLVM_API_FUNCTION(LLVM_API_FUNCTION_ASSIGNMENT);
#undef LLVM_API_FUNCTION_ASSIGNMENT
    
    return result;
}
void
lp_build_init(void)
{
   if (gallivm_initialized)
      return;

#ifdef DEBUG
   gallivm_debug = debug_get_option_gallivm_debug();
#endif

   lp_set_target_options();

#if USE_MCJIT
   LLVMLinkInMCJIT();
#else
   LLVMLinkInJIT();
#endif

   util_cpu_detect();

   if (HAVE_AVX &&
       util_cpu_caps.has_avx) {
      lp_native_vector_width = 256;
   } else {
      /* Leave it at 128, even when no SIMD extensions are available.
       * Really needs to be a multiple of 128 so can fit 4 floats.
       */
      lp_native_vector_width = 128;
   }
 
   lp_native_vector_width = debug_get_num_option("LP_NATIVE_VECTOR_WIDTH",
                                                 lp_native_vector_width);

   gallivm_initialized = TRUE;

#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
}
Exemple #7
0
extern "C" JSC::LLVMAPI* initializeAndGetJSCLLVMAPI(void (*callback)(const char*, ...))
{
    g_llvmTrapCallback = callback;
    
    LLVMInstallFatalErrorHandler(llvmCrash);

    if (!LLVMStartMultithreaded())
        callback("Could not start LLVM multithreading");
    
    LLVMLinkInMCJIT();
    LLVMInitializeNativeTarget();
    LLVMInitializeX86AsmPrinter();
    LLVMInitializeX86Disassembler();
    
    JSC::LLVMAPI* result = new JSC::LLVMAPI;
    
#define LLVM_API_FUNCTION_ASSIGNMENT(returnType, name, signature) \
    result->name = LLVM##name;
    FOR_EACH_LLVM_API_FUNCTION(LLVM_API_FUNCTION_ASSIGNMENT);
#undef LLVM_API_FUNCTION_ASSIGNMENT
    
    return result;
}
Exemple #8
0
void init_core(void)
{
  LLVMLinkInMCJIT();
  LLVMInitializeNativeTarget();
  LLVMInitializeNativeAsmPrinter();
  LLVMInitializeNativeAsmParser();

  llvm_module_tag = scm_make_smob_type("llvm_module", sizeof(struct llvm_module_t));
  scm_set_smob_free(llvm_module_tag, free_llvm_module);

  llvm_function_tag = scm_make_smob_type("llvm_function", sizeof(struct llvm_function_t));
  scm_set_smob_free(llvm_function_tag, free_llvm_function);

  llvm_value_tag = scm_make_smob_type("llvm_value", sizeof(struct llvm_value_t));

  llvm_basic_block_tag = scm_make_smob_type("llvm_basic_block", sizeof(struct llvm_basic_block_t));

  scm_c_define("llvm-bool"  , scm_from_int(SCM_FOREIGN_TYPE_LAST + 1));
  scm_c_define("llvm-void"  , scm_from_int(SCM_FOREIGN_TYPE_VOID    ));
  scm_c_define("llvm-float" , scm_from_int(SCM_FOREIGN_TYPE_FLOAT   ));
  scm_c_define("llvm-double", scm_from_int(SCM_FOREIGN_TYPE_DOUBLE  ));
  scm_c_define("llvm-uint8" , scm_from_int(SCM_FOREIGN_TYPE_UINT8   ));
  scm_c_define("llvm-int8"  , scm_from_int(SCM_FOREIGN_TYPE_INT8    ));
  scm_c_define("llvm-uint16", scm_from_int(SCM_FOREIGN_TYPE_UINT16  ));
  scm_c_define("llvm-int16" , scm_from_int(SCM_FOREIGN_TYPE_INT16   ));
  scm_c_define("llvm-uint32", scm_from_int(SCM_FOREIGN_TYPE_UINT32  ));
  scm_c_define("llvm-int32" , scm_from_int(SCM_FOREIGN_TYPE_INT32   ));
  scm_c_define("llvm-uint64", scm_from_int(SCM_FOREIGN_TYPE_UINT64  ));
  scm_c_define("llvm-int64" , scm_from_int(SCM_FOREIGN_TYPE_INT64   ));
  scm_c_define("llvm-int-slt" , scm_from_int(LLVMIntSLT));
  scm_c_define("llvm-int-ult" , scm_from_int(LLVMIntULT));
  scm_c_define("llvm-int-sle" , scm_from_int(LLVMIntSLE));
  scm_c_define("llvm-int-ule" , scm_from_int(LLVMIntULE));
  scm_c_define("llvm-int-ugt" , scm_from_int(LLVMIntUGT));
  scm_c_define("llvm-int-sgt" , scm_from_int(LLVMIntSGT));
  scm_c_define("llvm-int-uge" , scm_from_int(LLVMIntUGE));
  scm_c_define("llvm-int-sge" , scm_from_int(LLVMIntSGE));
  scm_c_define("llvm-int-eq"  , scm_from_int(LLVMIntEQ ));
  scm_c_define("llvm-int-ne"  , scm_from_int(LLVMIntNE ));
  scm_c_define("llvm-real-lt" , scm_from_int(LLVMRealOLT));
  scm_c_define("llvm-real-le" , scm_from_int(LLVMRealOLE));
  scm_c_define("llvm-real-gt" , scm_from_int(LLVMRealOGT));
  scm_c_define("llvm-real-ge" , scm_from_int(LLVMRealOGE));
  scm_c_define("llvm-real-eq" , scm_from_int(LLVMRealOEQ));
  scm_c_define("llvm-real-ne" , scm_from_int(LLVMRealONE));
  scm_c_define_gsubr("make-llvm-module-base"       , 0, 0, 0, SCM_FUNC(make_llvm_module_base       ));
  scm_c_define_gsubr("llvm-module-destroy"         , 1, 0, 0, SCM_FUNC(llvm_module_destroy         ));
  scm_c_define_gsubr("llvm-dump-module"            , 1, 0, 0, SCM_FUNC(llvm_dump_module            ));
  scm_c_define_gsubr("make-llvm-function"          , 4, 0, 0, SCM_FUNC(make_llvm_function          ));
  scm_c_define_gsubr("llvm-function-destroy"       , 1, 0, 0, SCM_FUNC(llvm_function_destroy       ));
  scm_c_define_gsubr("llvm-function-return"        , 2, 0, 0, SCM_FUNC(llvm_function_return        ));
  scm_c_define_gsubr("llvm-function-return-void"   , 1, 0, 0, SCM_FUNC(llvm_function_return_void   ));
  scm_c_define_gsubr("llvm-compile-module"         , 1, 0, 0, SCM_FUNC(llvm_compile_module         ));
  scm_c_define_gsubr("llvm-get-function-address"   , 2, 0, 0, SCM_FUNC(llvm_get_function_address   ));
  scm_c_define_gsubr("llvm-verify-module"          , 1, 0, 0, SCM_FUNC(llvm_verify_module          ));
  scm_c_define_gsubr("make-llvm-basic-block"       , 2, 0, 0, SCM_FUNC(make_llvm_basic_block       ));
  scm_c_define_gsubr("llvm-position-builder-at-end", 2, 0, 0, SCM_FUNC(llvm_position_builder_at_end));
  scm_c_define_gsubr("llvm-build-branch"           , 2, 0, 0, SCM_FUNC(llvm_build_branch           ));
  scm_c_define_gsubr("llvm-build-cond-branch"      , 4, 0, 0, SCM_FUNC(llvm_build_cond_branch      ));
  scm_c_define_gsubr("llvm-build-select"           , 4, 0, 0, SCM_FUNC(llvm_build_select           ));
  scm_c_define_gsubr("make-llvm-constant"          , 2, 0, 0, SCM_FUNC(make_llvm_constant          ));
  scm_c_define_gsubr("llvm-get-type"               , 1, 0, 0, SCM_FUNC(llvm_get_type               ));
  scm_c_define_gsubr("llvm-build-load"             , 3, 0, 0, SCM_FUNC(llvm_build_load             ));
  scm_c_define_gsubr("llvm-build-store"            , 4, 0, 0, SCM_FUNC(llvm_build_store            ));
  scm_c_define_gsubr("llvm-get-param"              , 2, 0, 0, SCM_FUNC(llvm_get_param              ));
  scm_c_define_gsubr("llvm-build-neg"              , 2, 0, 0, SCM_FUNC(llvm_build_neg              ));
  scm_c_define_gsubr("llvm-build-fneg"             , 2, 0, 0, SCM_FUNC(llvm_build_fneg             ));
  scm_c_define_gsubr("llvm-build-not"              , 2, 0, 0, SCM_FUNC(llvm_build_not              ));
  scm_c_define_gsubr("llvm-build-add"              , 3, 0, 0, SCM_FUNC(llvm_build_add              ));
  scm_c_define_gsubr("llvm-build-fadd"             , 3, 0, 0, SCM_FUNC(llvm_build_fadd             ));
  scm_c_define_gsubr("llvm-build-sub"              , 3, 0, 0, SCM_FUNC(llvm_build_sub              ));
  scm_c_define_gsubr("llvm-build-fsub"             , 3, 0, 0, SCM_FUNC(llvm_build_fsub             ));
  scm_c_define_gsubr("llvm-build-mul"              , 3, 0, 0, SCM_FUNC(llvm_build_mul              ));
  scm_c_define_gsubr("llvm-build-fmul"             , 3, 0, 0, SCM_FUNC(llvm_build_fmul             ));
  scm_c_define_gsubr("llvm-build-udiv"             , 3, 0, 0, SCM_FUNC(llvm_build_udiv             ));
  scm_c_define_gsubr("llvm-build-sdiv"             , 3, 0, 0, SCM_FUNC(llvm_build_sdiv             ));
  scm_c_define_gsubr("llvm-build-fdiv"             , 3, 0, 0, SCM_FUNC(llvm_build_fdiv             ));
  scm_c_define_gsubr("llvm-build-shl"              , 3, 0, 0, SCM_FUNC(llvm_build_shl              ));
  scm_c_define_gsubr("llvm-build-lshr"             , 3, 0, 0, SCM_FUNC(llvm_build_lshr             ));
  scm_c_define_gsubr("llvm-build-ashr"             , 3, 0, 0, SCM_FUNC(llvm_build_ashr             ));
  scm_c_define_gsubr("llvm-build-urem"             , 3, 0, 0, SCM_FUNC(llvm_build_urem             ));
  scm_c_define_gsubr("llvm-build-srem"             , 3, 0, 0, SCM_FUNC(llvm_build_srem             ));
  scm_c_define_gsubr("llvm-build-frem"             , 3, 0, 0, SCM_FUNC(llvm_build_frem             ));
  scm_c_define_gsubr("llvm-build-and"              , 3, 0, 0, SCM_FUNC(llvm_build_and              ));
  scm_c_define_gsubr("llvm-build-or"               , 3, 0, 0, SCM_FUNC(llvm_build_or               ));
  scm_c_define_gsubr("llvm-build-xor"              , 3, 0, 0, SCM_FUNC(llvm_build_xor              ));
  scm_c_define_gsubr("llvm-build-trunc"            , 3, 0, 0, SCM_FUNC(llvm_build_trunc            ));
  scm_c_define_gsubr("llvm-build-sext"             , 3, 0, 0, SCM_FUNC(llvm_build_sext             ));
  scm_c_define_gsubr("llvm-build-zext"             , 3, 0, 0, SCM_FUNC(llvm_build_zext             ));
  scm_c_define_gsubr("llvm-build-fp-cast"          , 3, 0, 0, SCM_FUNC(llvm_build_fp_cast          ));
  scm_c_define_gsubr("llvm-build-fp-to-si"         , 3, 0, 0, SCM_FUNC(llvm_build_fp_to_si         ));
  scm_c_define_gsubr("llvm-build-fp-to-ui"         , 3, 0, 0, SCM_FUNC(llvm_build_fp_to_ui         ));
  scm_c_define_gsubr("llvm-build-si-to-fp"         , 3, 0, 0, SCM_FUNC(llvm_build_si_to_fp         ));
  scm_c_define_gsubr("llvm-build-ui-to-fp"         , 3, 0, 0, SCM_FUNC(llvm_build_ui_to_fp         ));
  scm_c_define_gsubr("llvm-build-call"             , 6, 0, 0, SCM_FUNC(llvm_build_call             ));
  scm_c_define_gsubr("llvm-build-integer-cmp"      , 4, 0, 0, SCM_FUNC(llvm_build_integer_cmp      ));
  scm_c_define_gsubr("llvm-build-float-cmp"        , 4, 0, 0, SCM_FUNC(llvm_build_float_cmp        ));
  scm_c_define_gsubr("llvm-build-alloca"           , 2, 0, 0, SCM_FUNC(llvm_build_alloca           ));
  scm_c_define_gsubr("llvm-build-phi"              , 2, 0, 0, SCM_FUNC(llvm_build_phi              ));
  scm_c_define_gsubr("llvm-add-incoming"           , 3, 0, 0, SCM_FUNC(llvm_add_incoming           ));
}
Exemple #9
0
jit_compiler::jit_compiler(std::unique_ptr<llvm::Module>&& _module, std::unordered_map<std::string, std::uintptr_t>&& table)
{
	verify(HERE), s_memory;

	std::string result;

	const auto module_ptr = _module.get();

	// Initialization
	llvm::InitializeNativeTarget();
	llvm::InitializeNativeTargetAsmPrinter();
	LLVMLinkInMCJIT();
	const auto _cpu = llvm::sys::getHostCPUName();

	m_engine.reset(llvm::EngineBuilder(std::move(_module))
		.setErrorStr(&result)
		.setMCJITMemoryManager(std::make_unique<MemoryManager>(std::move(table)))
		.setOptLevel(llvm::CodeGenOpt::Aggressive)
		.setCodeModel((u64)s_memory <= 0x60000000 ? llvm::CodeModel::Small : llvm::CodeModel::Large) // TODO
		.setMCPU(_cpu == "skylake" ? "haswell" : _cpu)
		.create());

	if (!m_engine)
	{
		fmt::throw_exception("LLVM: Failed to create ExecutionEngine: %s", result);
	}

	m_engine->setProcessAllSections(true); // ???
	m_engine->RegisterJITEventListener(&s_listener);
	m_engine->finalizeObject();

	for (auto& func : module_ptr->functions())
	{
		if (!func.empty())
		{
			const std::string& name = func.getName();

			// Register compiled function
			m_map[name] = m_engine->getFunctionAddress(name);
		}

		// Delete IR to lower memory consumption
		func.deleteBody();
	}

#ifdef _WIN32
	// Register .xdata UNWIND_INFO (.pdata section is empty for some reason)
	std::set<u64> func_set;

	for (const auto& pair : m_map)
	{
		func_set.emplace(pair.second);
	}

	const u64 base = (u64)s_memory;
	const u8* bits = s_unwind_info;

	s_unwind.clear();
	s_unwind.reserve(m_map.size());

	for (const u64 addr : func_set)
	{
		// Find next function address
		const auto _next = func_set.upper_bound(addr);
		const u64 next = _next != func_set.end() ? *_next : (u64)s_code_addr + s_code_size;

		// Generate RUNTIME_FUNCTION record
		RUNTIME_FUNCTION uw;
		uw.BeginAddress = static_cast<u32>(addr - base);
		uw.EndAddress   = static_cast<u32>(next - base);
		uw.UnwindData   = static_cast<u32>((u64)bits - base);
		s_unwind.emplace_back(uw);

		// Parse .xdata UNWIND_INFO record
		const u8 flags = *bits++; // Version and flags
		const u8 prolog = *bits++; // Size of prolog
		const u8 count = *bits++; // Count of unwind codes
		const u8 frame = *bits++; // Frame Reg + Off
		bits += ::align(std::max<u8>(1, count), 2) * sizeof(u16); // UNWIND_CODE array

		if (flags != 1) 
		{
			// Can't happen for trivial code
			LOG_ERROR(GENERAL, "LLVM: unsupported UNWIND_INFO version/flags (0x%02x)", flags);
			break;
		}

		LOG_TRACE(GENERAL, "LLVM: .xdata at 0x%llx: function 0x%x..0x%x: p0x%02x, c0x%02x, f0x%02x", uw.UnwindData + base, uw.BeginAddress + base, uw.EndAddress + base, prolog, count, frame);
	}

	if (s_unwind_info + s_unwind_size != bits)
	{
		LOG_ERROR(GENERAL, "LLVM: .xdata analysis failed! (%p != %p)", s_unwind_info + s_unwind_size, bits);
	}
	else if (!RtlAddFunctionTable(s_unwind.data(), (DWORD)s_unwind.size(), base))
	{
		LOG_ERROR(GENERAL, "RtlAddFunctionTable(%p) failed! Error %u", s_unwind_info, GetLastError());
	}
	else
	{
		LOG_SUCCESS(GENERAL, "LLVM: UNWIND_INFO registered (%p, size=0x%llx)", s_unwind_info, s_unwind_size);
	}
#endif
}
Exemple #10
0
int main(int c, char **v)
{
    LLVMContextRef *contexts;
    LLVMModuleRef *modules;
    char *error;
    const char *mode = "opt";
    const char **filenames;
    unsigned numFiles;
    unsigned i;
    bool moreOptions;
    static int verboseFlag = 0;
    static int timingFlag = 0;
    static int disassembleFlag = 0;
    bool manyContexts = true;
    double beforeAll;
    
    if (c == 1)
        usage();
    
    moreOptions = true;
    while (moreOptions) {
        static struct option longOptions[] = {
            {"verbose", no_argument, &verboseFlag, 1},
            {"timing", no_argument, &timingFlag, 1},
            {"disassemble", no_argument, &disassembleFlag, 1},
            {"mode", required_argument, 0, 0},
            {"contexts", required_argument, 0, 0},
            {"help", no_argument, 0, 0}
        };
        
        int optionIndex;
        int optionValue;
        
        optionValue = getopt_long(c, v, "", longOptions, &optionIndex);
        
        switch (optionValue) {
        case -1:
            moreOptions = false;
            break;
            
        case 0: {
            const char* thisOption = longOptions[optionIndex].name;
            if (!strcmp(thisOption, "help"))
                usage();
            if (!strcmp(thisOption, "contexts")) {
                if (!strcasecmp(optarg, "one"))
                    manyContexts = false;
                else if (!strcasecmp(optarg, "many"))
                    manyContexts = true;
                else {
                    fprintf(stderr, "Invalid argument for --contexts.\n");
                    exit(1);
                }
                break;
            }
            if (!strcmp(thisOption, "mode")) {
                mode = strdup(optarg);
                break;
            }
            break;
        }
            
        case '?':
            exit(0);
            break;
            
        default:
            printf("optionValue = %d\n", optionValue);
            abort();
            break;
        }
    }
    
    LLVMLinkInMCJIT();
    LLVMInitializeNativeTarget();
    LLVMInitializeX86AsmPrinter();
    LLVMInitializeX86Disassembler();

    filenames = (const char **)(v + optind);
    numFiles = c - optind;
    
    contexts = malloc(sizeof(LLVMContextRef) * numFiles);
    modules = malloc(sizeof(LLVMModuleRef) * numFiles);
    
    if (manyContexts) {
        for (i = 0; i < numFiles; ++i)
            contexts[i] = LLVMContextCreate();
    } else {
        LLVMContextRef context = LLVMContextCreate();
        for (i = 0; i < numFiles; ++i)
            contexts[i] = context;
    }
    
    for (i = 0; i < numFiles; ++i) {
        LLVMMemoryBufferRef buffer;
        const char* filename = filenames[i];
        
        if (LLVMCreateMemoryBufferWithContentsOfFile(filename, &buffer, &error)) {
            fprintf(stderr, "Error reading file %s: %s\n", filename, error);
            exit(1);
        }
        
        if (LLVMParseBitcodeInContext(contexts[i], buffer, modules + i, &error)) {
            fprintf(stderr, "Error parsing file %s: %s\n", filename, error);
            exit(1);
        }
        
        LLVMDisposeMemoryBuffer(buffer);
        
        if (verboseFlag) {
            printf("Module #%u (%s) after parsing:\n", i, filename);
            LLVMDumpModule(modules[i]);
        }
    }

    if (verboseFlag)
        printf("Generating code for modules...\n");
    
    if (timingFlag)
        beforeAll = currentTime();
    for (i = 0; i < numFiles; ++i) {
        LLVMModuleRef module;
        LLVMExecutionEngineRef engine;
        struct LLVMMCJITCompilerOptions options;
        LLVMValueRef value;
        LLVMPassManagerRef functionPasses = 0;
        LLVMPassManagerRef modulePasses = 0;
        
        double before;
        
        if (timingFlag)
            before = currentTime();
        
        module = modules[i];

        LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
        options.OptLevel = 2;
        options.EnableFastISel = 0;
        options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
            0, mmAllocateCodeSection, mmAllocateDataSection, mmApplyPermissions, mmDestroy);
    
        if (LLVMCreateMCJITCompilerForModule(&engine, module, &options, sizeof(options), &error)) {
            fprintf(stderr, "Error building MCJIT: %s\n", error);
            exit(1);
        }
    
        if (!strcasecmp(mode, "simple")) {
            modulePasses = LLVMCreatePassManager();
            LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), modulePasses);
            LLVMAddConstantPropagationPass(modulePasses);
            LLVMAddInstructionCombiningPass(modulePasses);
            LLVMAddPromoteMemoryToRegisterPass(modulePasses);
            LLVMAddBasicAliasAnalysisPass(modulePasses);
            LLVMAddTypeBasedAliasAnalysisPass(modulePasses);
            LLVMAddGVNPass(modulePasses);
            LLVMAddCFGSimplificationPass(modulePasses);
            LLVMRunPassManager(modulePasses, module);
        } else if (!strcasecmp(mode, "opt")) {
            LLVMPassManagerBuilderRef passBuilder;

            passBuilder = LLVMPassManagerBuilderCreate();
            LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
            LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
        
            functionPasses = LLVMCreateFunctionPassManagerForModule(module);
            modulePasses = LLVMCreatePassManager();
        
            LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), modulePasses);
        
            LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder, functionPasses);
            LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
        
            LLVMPassManagerBuilderDispose(passBuilder);
        
            LLVMInitializeFunctionPassManager(functionPasses);
            for (value = LLVMGetFirstFunction(module); value; value = LLVMGetNextFunction(value))
                LLVMRunFunctionPassManager(functionPasses, value);
            LLVMFinalizeFunctionPassManager(functionPasses);
        
            LLVMRunPassManager(modulePasses, module);
        } else {
            fprintf(stderr, "Bad optimization mode: %s.\n", mode);
            fprintf(stderr, "Valid modes are: \"simple\" or \"opt\".\n");
            exit(1);
        }

        if (verboseFlag) {
            printf("Module #%d (%s) after optimization:\n", i, filenames[i]);
            LLVMDumpModule(module);
        }
    
        for (value = LLVMGetFirstFunction(module); value; value = LLVMGetNextFunction(value)) {
            if (LLVMIsDeclaration(value))
                continue;
            LLVMGetPointerToGlobal(engine, value);
        }

        if (functionPasses)
            LLVMDisposePassManager(functionPasses);
        if (modulePasses)
            LLVMDisposePassManager(modulePasses);
    
        LLVMDisposeExecutionEngine(engine);
        
        if (timingFlag) {
            double after = currentTime();
            printf("Module #%d (%s) took %lf ms.\n", i, filenames[i], (after - before) * 1000);
        }
    }
    if (timingFlag) {
        double after = currentTime();
        printf("Compilation took a total of %lf ms.\n", (after - beforeAll) * 1000);
    }
    
    if (disassembleFlag) {
        LLVMDisasmContextRef disassembler;
        struct MemorySection *section;
        
        disassembler = LLVMCreateDisasm("x86_64-apple-darwin", 0, 0, 0, symbolLookupCallback);
        if (!disassembler) {
            fprintf(stderr, "Error building disassembler.\n");
            exit(1);
        }
    
        for (section = sectionHead; section; section = section->next) {
            printf("Disassembly for section %p:\n", section);
        
            char pcString[20];
            char instructionString[1000];
            uint8_t *pc;
            uint8_t *end;
        
            pc = section->start;
            end = pc + section->size;
        
            while (pc < end) {
                snprintf(
                    pcString, sizeof(pcString), "0x%lx",
                    (unsigned long)(uintptr_t)pc);
            
                size_t instructionSize = LLVMDisasmInstruction(
                    disassembler, pc, end - pc, (uintptr_t)pc,
                    instructionString, sizeof(instructionString));
            
                if (!instructionSize)
                    snprintf(instructionString, sizeof(instructionString), ".byte 0x%02x", *pc++);
                else
                    pc += instructionSize;
            
                printf("    %16s: %s\n", pcString, instructionString);
            }
        }
    }
    
    return 0;
}