text: /*===-- executionengine_ocaml.c - LLVM OCaml Glue ---------------*- C++ -*-===*\
  |*                                                                            *|
  |*                     The LLVM Compiler Infrastructure                       *|
  |*                                                                            *|
  |* This file is distributed under the University of Illinois Open Source      *|
  |* License. See LICENSE.TXT for details.                                      *|
  |*                                                                            *|
  |*===----------------------------------------------------------------------===*|
  |*                                                                            *|
  |* This file glues LLVM's OCaml interface to its C interface. These functions *|
  |* are by and large transparent wrappers to the corresponding C functions.    *|
  |*                                                                            *|
  |* Note that these functions intentionally take liberties with the CAMLparamX *|
  |* macros, since most of the parameters are not GC heap objects.              *|
  |*                                                                            *|
  \*===----------------------------------------------------------------------===*/
  
  #include <string.h>
  #include <assert.h>
  #include "llvm-c/ExecutionEngine.h"
  #include "llvm-c/Target.h"
  #include "caml/alloc.h"
  #include "caml/custom.h"
  #include "caml/fail.h"
  #include "caml/memory.h"
  #include "caml/callback.h"
  
  void llvm_raise(value Prototype, char *Message);
  
  /* unit -> bool */
  CAMLprim value llvm_ee_initialize(value Unit) {
    LLVMLinkInMCJIT();
  
    return Val_bool(!LLVMInitializeNativeTarget() &&
                    !LLVMInitializeNativeAsmParser() &&
                    !LLVMInitializeNativeAsmPrinter());
  }
  
  /* llmodule -> llcompileroption -> ExecutionEngine.t */
  CAMLprim LLVMExecutionEngineRef llvm_ee_create(value OptRecordOpt, LLVMModuleRef M) {
    value OptRecord;
    LLVMExecutionEngineRef MCJIT;
    char *Error;
    struct LLVMMCJITCompilerOptions Options;
  
    LLVMInitializeMCJITCompilerOptions(&Options, sizeof(Options));
    if (OptRecordOpt != Val_int(0)) {
      OptRecord = Field(OptRecordOpt, 0);
      Options.OptLevel = Int_val(Field(OptRecord, 0));
      Options.CodeModel = Int_val(Field(OptRecord, 1));
      Options.NoFramePointerElim = Int_val(Field(OptRecord, 2));
      Options.EnableFastISel = Int_val(Field(OptRecord, 3));
      Options.MCJMM = NULL;
    }
  
    if (LLVMCreateMCJITCompilerForModule(&MCJIT, M, &Options,
                                        sizeof(Options), &Error))
      llvm_raise(*caml_named_value("Llvm_executionengine.Error"), Error);
    return MCJIT;
  }
  
  /* ExecutionEngine.t -> unit */
  CAMLprim value llvm_ee_dispose(LLVMExecutionEngineRef EE) {
    LLVMDisposeExecutionEngine(EE);
    return Val_unit;
  }
  
  /* llmodule -> ExecutionEngine.t -> unit */
  CAMLprim value llvm_ee_add_module(LLVMModuleRef M, LLVMExecutionEngineRef EE) {
    LLVMAddModule(EE, M);
    return Val_unit;
  }
  
  /* llmodule -> ExecutionEngine.t -> llmodule */
  CAMLprim value llvm_ee_remove_module(LLVMModuleRef M, LLVMExecutionEngineRef EE) {
    LLVMModuleRef RemovedModule;
    char *Error;
    if (LLVMRemoveModule(EE, M, &RemovedModule, &Error))
      llvm_raise(*caml_named_value("Llvm_executionengine.Error"), Error);
    return Val_unit;
  }
  
  /* ExecutionEngine.t -> unit */
  CAMLprim value llvm_ee_run_static_ctors(LLVMExecutionEngineRef EE) {
    LLVMRunStaticConstructors(EE);
    return Val_unit;
  }
  
  /* ExecutionEngine.t -> unit */
  CAMLprim value llvm_ee_run_static_dtors(LLVMExecutionEngineRef EE) {
    LLVMRunStaticDestructors(EE);
    return Val_unit;
  }
  
  extern value llvm_alloc_data_layout(LLVMTargetDataRef TargetData);
  
  /* ExecutionEngine.t -> Llvm_target.DataLayout.t */
  CAMLprim value llvm_ee_get_data_layout(LLVMExecutionEngineRef EE) {
    value DataLayout;
    LLVMTargetDataRef OrigDataLayout;
    char* TargetDataCStr;
  
    OrigDataLayout = LLVMGetExecutionEngineTargetData(EE);
    TargetDataCStr = LLVMCopyStringRepOfTargetData(OrigDataLayout);
    DataLayout = llvm_alloc_data_layout(LLVMCreateTargetData(TargetDataCStr));
    LLVMDisposeMessage(TargetDataCStr);
  
    return DataLayout;
  }
  
  /* Llvm.llvalue -> int64 -> llexecutionengine -> unit */
  CAMLprim value llvm_ee_add_global_mapping(LLVMValueRef Global, value Ptr,
                                            LLVMExecutionEngineRef EE) {
    LLVMAddGlobalMapping(EE, Global, (void*) (Int64_val(Ptr)));
    return Val_unit;
  }
  
  CAMLprim value llvm_ee_get_global_value_address(value Name,
  						LLVMExecutionEngineRef EE) {
    return caml_copy_int64((int64_t) LLVMGetGlobalValueAddress(EE, String_val(Name)));
  }
  
  CAMLprim value llvm_ee_get_function_address(value Name,
  					    LLVMExecutionEngineRef EE) {
    return caml_copy_int64((int64_t) LLVMGetFunctionAddress(EE, String_val(Name)));
  }
  