| /* | |
| Copyright (c) 2022 Microsoft Corporation. All rights reserved. | |
| Released under Apache 2.0 license as described in the file LICENSE. | |
| Author: Siddharth Bhat | |
| This file contains bare bones bindings to the LLVM C FFI. This enables | |
| `src/Lean/Compiler/IR/EmitLLVM.lean` to produce LLVM bitcode from | |
| Lean's IR. | |
| */ | |
| #include <lean/lean.h> | |
| #include <cassert> | |
| #include "runtime/array_ref.h" | |
| #include "runtime/debug.h" | |
| #include "runtime/string_ref.h" | |
| #ifdef LEAN_LLVM | |
| #include "llvm-c/Analysis.h" | |
| #include "llvm-c/BitReader.h" | |
| #include "llvm-c/BitWriter.h" | |
| #include "llvm-c/Core.h" | |
| #include "llvm-c/Linker.h" | |
| #include "llvm-c/Target.h" | |
| #include "llvm-c/TargetMachine.h" | |
| #include "llvm-c/Types.h" | |
| //#include "llvm-c/Transforms/PassBuilder.h" | |
| //#include "llvm-c/Transforms/PassManagerBuilder.h" | |
| #endif | |
| // This is mostly boilerplate, suppress warnings | |
| #if defined(__clang__) | |
| #pragma clang diagnostic ignored "-Wunused-parameter" | |
| #elif defined(__GNUC__) && !defined(__CLANG__) | |
| #pragma GCC diagnostic ignored "-Wunused-parameter" | |
| #endif | |
| namespace lean { | |
| /* initLLVM : IO Unit */ | |
| extern "C" obj_res initialize_Lean_Compiler_IR_EmitLLVM(uint8_t builtin); | |
| extern "C" LEAN_EXPORT obj_res lean_init_llvm() { | |
| return initialize_Lean_Compiler_IR_EmitLLVM(/*builtin*/ false); | |
| } | |
| /* emitLLVM (env : Environment) (modName : Name) (filepath : FilePath) : IO Unit */ | |
| extern "C" obj_res lean_ir_emit_llvm(obj_arg env, obj_arg mod_name, obj_arg filepath); | |
| extern "C" LEAN_EXPORT obj_res lean_emit_llvm(obj_arg env, obj_arg mod_name, obj_arg filepath) { | |
| return lean_ir_emit_llvm(env, mod_name, filepath); | |
| } | |
| } | |
| extern "C" LEAN_EXPORT lean_object* lean_llvm_initialize_target_info() { | |
| #ifdef LEAN_LLVM | |
| LLVMInitializeAllTargetInfos(); | |
| LLVMInitializeAllTargets(); | |
| LLVMInitializeAllTargetMCs(); | |
| LLVMInitializeAllAsmParsers(); | |
| LLVMInitializeAllAsmPrinters(); | |
| #endif | |
| return lean_box(0); | |
| } | |
| #ifdef LEAN_LLVM | |
| // == LLVM <-> Lean: Target == | |
| static inline size_t Target_to_lean(LLVMTargetRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMTargetRef lean_to_Target(size_t s) { | |
| return reinterpret_cast<LLVMTargetRef>(s); | |
| } | |
| // == LLVM <-> Lean: TargetMachine == | |
| static inline size_t TargetMachine_to_lean(LLVMTargetMachineRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMTargetMachineRef lean_to_TargetMachine(size_t s) { | |
| return reinterpret_cast<LLVMTargetMachineRef>(s); | |
| } | |
| // == LLVM <-> Lean: MemoryBuffer == | |
| static inline size_t MemoryBuffer_to_lean(LLVMMemoryBufferRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMMemoryBufferRef lean_to_MemoryBuffer(size_t s) { | |
| return reinterpret_cast<LLVMMemoryBufferRef>(s); | |
| } | |
| // == LLVM <-> Lean: ModuleRef == | |
| static inline size_t Module_to_lean(LLVMModuleRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMModuleRef lean_to_Module(size_t s) { | |
| return reinterpret_cast<LLVMModuleRef>(s); | |
| } | |
| // == LLVM <-> Lean: ContextRef == | |
| static inline size_t Context_to_lean(LLVMContextRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMContextRef lean_to_Context(size_t s) { | |
| return reinterpret_cast<LLVMContextRef>(s); | |
| } | |
| // == LLVM <-> Lean: TypeRef == | |
| static inline size_t Type_to_lean(LLVMTypeRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMTypeRef lean_to_Type(size_t s) { | |
| return reinterpret_cast<LLVMTypeRef>(s); | |
| } | |
| // == LLVM <-> Lean: ValueRef == | |
| static inline size_t Value_to_lean(LLVMValueRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMValueRef lean_to_Value(size_t s) { | |
| return reinterpret_cast<LLVMValueRef>(s); | |
| } | |
| // == LLVM <-> Lean: BuilderRef == | |
| static inline size_t Builder_to_lean(LLVMBuilderRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMBuilderRef lean_to_Builder(size_t s) { | |
| return reinterpret_cast<LLVMBuilderRef>(s); | |
| } | |
| // == LLVM <-> Lean: BasicBlockRef == | |
| static inline size_t BasicBlock_to_lean(LLVMBasicBlockRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMBasicBlockRef lean_to_BasicBlock(size_t s) { | |
| return reinterpret_cast<LLVMBasicBlockRef>(s); | |
| } | |
| /* TODO: update to new pass manager | |
| // == LLVM <-> Lean: PassManagerRef == | |
| static inline size_t PassManager_to_lean(LLVMPassManagerRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMPassManagerRef lean_to_PassManager(size_t s) { | |
| return reinterpret_cast<LLVMPassManagerRef>(s); | |
| } | |
| // == LLVM <-> Lean: PassManagerRef == | |
| static inline size_t PassManagerBuilder_to_lean(LLVMPassManagerBuilderRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMPassManagerBuilderRef lean_to_PassManagerBuilder(size_t s) { | |
| return reinterpret_cast<LLVMPassManagerBuilderRef>(s); | |
| } | |
| */ | |
| // == LLVM <-> Lean: AttributeRef == | |
| static inline size_t Attribute_to_lean(LLVMAttributeRef s) { | |
| return reinterpret_cast<size_t>(s); | |
| } | |
| static inline LLVMAttributeRef lean_to_Attribute(size_t s) { | |
| return reinterpret_cast<LLVMAttributeRef>(s); | |
| } | |
| #else | |
| typedef int LLVMBasicBlockRef; | |
| typedef int LLVMContextRef; | |
| typedef int LLVMBuilderRef; | |
| typedef int LLVMTargetRef; | |
| typedef int LLVMTargetMachineRef; | |
| typedef int LLVMTypeRef; | |
| typedef int LLVMValueRef; | |
| typedef int LLVMModuleRef; | |
| typedef int LLVMPassManagerRef; | |
| typedef int LLVMPassManagerBuilderRef; | |
| #endif // LEAN_LLVM | |
| // == Array Type <-> C array of types == | |
| // There is redundancy here, but I am loath to clean it up with templates, | |
| // because we will somehow dispatch to the correct `lean_to_*` function. I can't | |
| // think of an immediate, clean way to achieve this (plenty of unclean ways. eg: | |
| // create a templated function that we partial template specialize that tells us | |
| // what the correct `lean_to_*` is. | |
| // Concretely: | |
| // leanToFn<LLVMTypeRef> = lean_to_LLVMType; | |
| // leanToFn<LLVMValueRef> = lean_to_LLVMValue). | |
| LLVMTypeRef *array_ref_to_ArrayLLVMType( | |
| const lean::array_ref<lean_object *> &arr) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| const int nargs = arr.size(); // lean::array_size(args); | |
| // bollu: ouch, this is expensive! There must be a cheaper way? | |
| LLVMTypeRef *tys = (LLVMTypeRef *)malloc(sizeof(LLVMTypeRef) * nargs); | |
| for (int i = 0; i < nargs; ++i) { | |
| tys[i] = lean_to_Type(lean_unbox_usize(arr[i])); | |
| } | |
| return tys; | |
| #endif // LEAN_LLVM | |
| } | |
| // TODO: Is there a nicer way to do this? | |
| LLVMValueRef *array_ref_to_ArrayLLVMValue( | |
| const lean::array_ref<lean_object *> &arr) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| const int nargs = arr.size(); // lean::array_size(args); | |
| // bollu: ouch, this is expensive! There must be a cheaper way? | |
| LLVMValueRef *vals = (LLVMValueRef *)malloc(sizeof(LLVMValueRef) * nargs); | |
| lean_always_assert(vals && "unable to allocate array"); | |
| for (int i = 0; i < nargs; ++i) { | |
| lean_inc(arr[i]); // TODO: do I need this? | |
| vals[i] = lean_to_Value(lean_unbox_usize(arr[i])); | |
| } | |
| return vals; | |
| #endif // LEAN_LLVM | |
| } | |
| // == FFI == | |
| extern "C" LEAN_EXPORT size_t lean_llvm_create_context() { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMContextRef ctx = LLVMContextCreate(); | |
| return Context_to_lean(ctx); | |
| #endif // LEAN_LLVM | |
| }; | |
| extern "C" LEAN_EXPORT size_t lean_llvm_create_module( | |
| size_t ctx, lean_object *str) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMModuleRef mod = LLVMModuleCreateWithNameInContext(lean_string_cstr(str), | |
| lean_to_Context(ctx)); | |
| return Module_to_lean(mod); | |
| #endif // LEAN_LLVM | |
| }; | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_write_bitcode_to_file(size_t ctx, | |
| size_t mod, lean_object *filepath) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| const int err = | |
| LLVMWriteBitcodeToFile(lean_to_Module(mod), lean_string_cstr(filepath)); | |
| lean_always_assert(!err && "unable to write bitcode"); | |
| return lean_box(0); // IO Unit | |
| #endif // LEAN_LLVM | |
| }; | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_module_to_string(size_t ctx, size_t mod) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| char *str = LLVMPrintModuleToString(lean_to_Module(mod)); | |
| lean_object *out = lean_mk_string(str); | |
| free(str); | |
| return out; | |
| #endif // LEAN_LLVM | |
| }; | |
| extern "C" LEAN_EXPORT size_t lean_llvm_add_function( | |
| size_t ctx, size_t mod, lean_object *name, size_t type) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMAddFunction( | |
| lean_to_Module(mod), lean_string_cstr(name), lean_to_Type(type)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_get_named_function( | |
| size_t ctx, size_t mod, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef f = | |
| LLVMGetNamedFunction(lean_to_Module(mod), lean_string_cstr(name)); | |
| return | |
| f ? lean::mk_option_some(lean_box_usize(Value_to_lean(f))) | |
| : lean::mk_option_none(); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_add_global( | |
| size_t ctx, size_t mod, lean_object *name, size_t type) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMAddGlobal(lean_to_Module(mod), lean_to_Type(type), | |
| lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_get_named_global( | |
| size_t ctx, size_t mod, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef g = | |
| LLVMGetNamedGlobal(lean_to_Module(mod), lean_string_cstr(name)); | |
| return | |
| g ? lean::mk_option_some(lean_box_usize(Value_to_lean(g))) | |
| : lean::mk_option_none(); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_global_string( | |
| size_t ctx, size_t builder, lean_object *str, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| lean::string_ref sref = lean::string_ref(str, true); | |
| lean::string_ref nameref = lean::string_ref(name, true); | |
| LLVMValueRef out = LLVMBuildGlobalString(lean_to_Builder(builder), | |
| sref.data(), nameref.data()); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_get_undef(size_t ctx, size_t ty) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMGetUndef(lean_to_Type(ty)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_set_initializer( | |
| size_t ctx, size_t global, size_t initializer) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMSetInitializer(lean_to_Value(global), lean_to_Value(initializer)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_function_type( | |
| size_t ctx, size_t retty, lean_object *argtys, uint8_t isvararg) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| lean::array_ref<lean_object *> arr(argtys, true); | |
| // TODO, this is expensive! Is there a cheaper way? | |
| LLVMTypeRef *tys = array_ref_to_ArrayLLVMType(arr); | |
| LLVMTypeRef out = | |
| LLVMFunctionType(lean_to_Type(retty), tys, arr.size(), isvararg); | |
| free(tys); | |
| return Type_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_opaque_pointer_type_in_context( | |
| size_t ctx, uint64_t addrspace) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| return Type_to_lean(LLVMPointerTypeInContext(lean_to_Context(ctx), addrspace)); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_int_type_in_context(size_t ctx, uint64_t width) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| return Type_to_lean(LLVMIntTypeInContext(lean_to_Context(ctx), width)); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_float_type_in_context(size_t ctx) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| return Type_to_lean(LLVMFloatTypeInContext(lean_to_Context(ctx))); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_void_type_in_context(size_t ctx) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| return Type_to_lean(LLVMVoidTypeInContext(lean_to_Context(ctx))); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_double_type_in_context(size_t ctx) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| return Type_to_lean(LLVMDoubleTypeInContext(lean_to_Context(ctx))); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_pointer_type(size_t ctx, size_t base) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMTypeRef out = LLVMPointerType(lean_to_Type(base), /*addrspace=*/0); | |
| return Type_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_array_type(size_t ctx, size_t base, uint64_t nelem) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMTypeRef out = LLVMArrayType(lean_to_Type(base), /*nelem=*/nelem); | |
| return Type_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_create_builder_in_context(size_t ctx) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| return Builder_to_lean(LLVMCreateBuilderInContext(lean_to_Context(ctx))); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_append_basic_block_in_context( | |
| size_t ctx, size_t fn, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMBasicBlockRef bb = LLVMAppendBasicBlockInContext( | |
| lean_to_Context(ctx), lean_to_Value(fn), lean_string_cstr(name)); | |
| return BasicBlock_to_lean(bb); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_position_builder_at_end( | |
| size_t ctx, size_t builder, size_t bb) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMPositionBuilderAtEnd(lean_to_Builder(builder), lean_to_BasicBlock(bb)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_clear_insertion_position(size_t ctx, size_t builder) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMClearInsertionPosition(lean_to_Builder(builder)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_call2( | |
| size_t ctx, size_t builder, size_t fnty, size_t fnval, lean_object *args, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| lean::array_ref<lean_object *> arr(args, true); | |
| LLVMValueRef *arrArgVals = array_ref_to_ArrayLLVMValue(arr); | |
| LLVMValueRef out = LLVMBuildCall2( | |
| lean_to_Builder(builder), lean_to_Type(fnty), lean_to_Value(fnval), | |
| arrArgVals, arr.size(), lean_string_cstr(name)); | |
| free(arrArgVals); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_cond_br( | |
| size_t ctx, | |
| size_t builder, size_t if_, size_t thenbb, size_t elsebb) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = | |
| LLVMBuildCondBr(lean_to_Builder(builder), lean_to_Value(if_), | |
| lean_to_BasicBlock(thenbb), lean_to_BasicBlock(elsebb)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_br(size_t ctx, size_t builder, size_t bb) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = | |
| LLVMBuildBr(lean_to_Builder(builder), lean_to_BasicBlock(bb)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_build_store(size_t ctx, | |
| size_t builder, size_t v, size_t slot) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMBuildStore(lean_to_Builder(builder), | |
| lean_to_Value(v), lean_to_Value(slot)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_load2(size_t ctx, | |
| size_t builder, size_t ty, size_t slot, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMBuildLoad2( | |
| lean_to_Builder(builder), lean_to_Type(ty), lean_to_Value(slot), lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_alloca(size_t ctx, | |
| size_t builder, size_t type, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMBuildAlloca( | |
| lean_to_Builder(builder), lean_to_Type(type), lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_ret(size_t ctx, size_t builder, size_t v) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMBuildRet(lean_to_Builder(builder), lean_to_Value(v)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_ret_void(size_t builder) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMBuildRetVoid(lean_to_Builder(builder)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_unreachable(size_t ctx, | |
| size_t builder) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMBuildUnreachable(lean_to_Builder(builder)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_inbounds_gep2(size_t ctx, | |
| size_t builder, size_t ty, size_t pointer, lean_object *indices, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| lean::array_ref<lean_object *> indices_array_ref(indices, true); | |
| LLVMValueRef *indices_carr = array_ref_to_ArrayLLVMValue(indices_array_ref); | |
| lean::string_ref name_ref(name, true); | |
| LLVMValueRef out = LLVMBuildInBoundsGEP2( | |
| lean_to_Builder(builder), lean_to_Type(ty), lean_to_Value(pointer), indices_carr, | |
| indices_array_ref.size(), name_ref.data()); | |
| free(indices_carr); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_gep2(size_t ctx, size_t builder, | |
| size_t ty, | |
| size_t pointer, | |
| lean_object *indices, | |
| lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| lean::array_ref<lean_object *> indices_array_ref(indices, true); | |
| LLVMValueRef *indices_carr = array_ref_to_ArrayLLVMValue(indices_array_ref); | |
| lean::string_ref name_ref(name, true); | |
| LLVMValueRef out = | |
| LLVMBuildGEP2(lean_to_Builder(builder), lean_to_Type(ty), lean_to_Value(pointer), | |
| indices_carr, indices_array_ref.size(), name_ref.data()); | |
| free(indices_carr); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_sext(size_t ctx, | |
| size_t builder, size_t val, size_t destty, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = | |
| LLVMBuildSExt(lean_to_Builder(builder), lean_to_Value(val), | |
| lean_to_Type(destty), lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_zext(size_t ctx, | |
| size_t builder, size_t val, size_t destty, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = | |
| LLVMBuildZExt(lean_to_Builder(builder), lean_to_Value(val), | |
| lean_to_Type(destty), lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_sext_or_trunc(size_t ctx, | |
| size_t builder, size_t val, size_t destty, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMTypeRef valType = LLVMTypeOf(lean_to_Value(val)); | |
| LLVMValueRef out; | |
| if (LLVMGetIntTypeWidth(valType) == | |
| LLVMGetIntTypeWidth(lean_to_Type(destty))) { | |
| out = lean_to_Value(val); | |
| } else if (LLVMGetIntTypeWidth(valType) < | |
| LLVMGetIntTypeWidth(lean_to_Type(destty))) { | |
| out = LLVMBuildSExt(lean_to_Builder(builder), lean_to_Value(val), | |
| lean_to_Type(destty), lean_string_cstr(name)); | |
| } else { | |
| out = LLVMBuildTrunc(lean_to_Builder(builder), lean_to_Value(val), | |
| lean_to_Type(destty), lean_string_cstr(name)); | |
| } | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_switch(size_t ctx, | |
| size_t builder, size_t val, size_t elsebb, uint64_t numCases) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = | |
| LLVMBuildSwitch(lean_to_Builder(builder), lean_to_Value(val), | |
| lean_to_BasicBlock(elsebb), numCases); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_ptr_to_int(size_t ctx, | |
| size_t builder, size_t ptr, size_t destty, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = | |
| LLVMBuildPtrToInt(lean_to_Builder(builder), lean_to_Value(ptr), | |
| lean_to_Type(destty), lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_mul(size_t ctx, | |
| size_t builder, | |
| size_t lhs, size_t rhs, | |
| lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = | |
| LLVMBuildMul(lean_to_Builder(builder), lean_to_Value(lhs), | |
| lean_to_Value(rhs), lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_add(size_t ctx, size_t builder, | |
| size_t lhs, size_t rhs, | |
| lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = | |
| LLVMBuildAdd(lean_to_Builder(builder), lean_to_Value(lhs), | |
| lean_to_Value(rhs), lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_sub(size_t ctx, size_t builder, | |
| size_t lhs, size_t rhs, | |
| lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = | |
| LLVMBuildSub(lean_to_Builder(builder), lean_to_Value(lhs), | |
| lean_to_Value(rhs), lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_not(size_t ctx, size_t builder, | |
| size_t v, | |
| lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMBuildNot(lean_to_Builder(builder), lean_to_Value(v), | |
| lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_build_icmp(size_t ctx, | |
| size_t builder, uint64_t predicate, size_t x, size_t y, lean_object *name) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMBuildICmp( | |
| lean_to_Builder(builder), LLVMIntPredicate(predicate), lean_to_Value(x), | |
| lean_to_Value(y), lean_string_cstr(name)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_add_case(size_t ctx, size_t switch_, | |
| size_t onVal, | |
| size_t destbb) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMAddCase(lean_to_Value(switch_), lean_to_Value(onVal), | |
| lean_to_BasicBlock(destbb)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_get_basic_block_parent(size_t ctx, size_t bb) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMGetBasicBlockParent(lean_to_BasicBlock(bb)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_get_insert_block(size_t ctx, size_t builder) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMBasicBlockRef out = LLVMGetInsertBlock(lean_to_Builder(builder)); | |
| return BasicBlock_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_type_of(size_t ctx, size_t val) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMTypeRef ty = LLVMTypeOf(lean_to_Value(val)); | |
| return Type_to_lean(ty); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_print_module_to_string(size_t ctx, size_t mod) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| const char *s = LLVMPrintModuleToString(lean_to_Module(mod)); | |
| return lean::mk_string(s); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_print_module_to_file(size_t ctx, | |
| size_t mod, lean_object *file) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| char *err_str = NULL; | |
| const char *file_cstr = lean_string_cstr(file); | |
| int is_error = LLVMPrintModuleToFile(lean_to_Module(mod), file_cstr, | |
| /*errorMessage=*/&err_str); | |
| if (is_error) { | |
| fprintf(stderr, "'%30s' file:%30s ERROR: %30s\n", __FUNCTION__, file_cstr, err_str); | |
| } | |
| lean_always_assert(!is_error && "failed to print module to file"); | |
| lean_always_assert (err_str == NULL); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_const_int(size_t ctx, size_t ty, uint64_t val, | |
| uint8_t sext) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMConstInt(lean_to_Type(ty), val, sext); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_const_array( | |
| size_t ctx, size_t elemty, lean_object *args) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| lean::array_ref<lean_object *> args_array_ref(args, true); | |
| LLVMValueRef *args_carr = array_ref_to_ArrayLLVMValue(args_array_ref); | |
| LLVMValueRef out = | |
| LLVMConstArray(lean_to_Type(elemty), args_carr, args_array_ref.size()); | |
| free(args_carr); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_const_string( | |
| size_t ctx, lean_object *s) { | |
| lean::string_ref sref = lean::string_ref(s, true); | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = | |
| LLVMConstStringInContext(lean_to_Context(ctx), sref.data(), | |
| sref.length(), /*DontNullTerminate=*/false); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_const_pointer_null( | |
| size_t ctx, size_t elemty) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMConstPointerNull(lean_to_Type(elemty)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t llvm_get_param(size_t ctx, size_t f, uint64_t ix) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMGetParam(lean_to_Value(f), ix); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT uint64_t llvm_count_params(size_t ctx, size_t f) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| unsigned n = LLVMCountParams(lean_to_Value(f)); | |
| return n; | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_set_tail_call( | |
| size_t ctx, size_t fnval, uint8_t isTail) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMSetTailCall(lean_to_Value(fnval), isTail); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t | |
| lean_llvm_create_memory_buffer_with_contents_of_file(size_t ctx, lean_object *path) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMMemoryBufferRef membuf; | |
| char *err_str = NULL; | |
| const char *path_cstr = lean_string_cstr(path); | |
| int is_error = LLVMCreateMemoryBufferWithContentsOfFile( | |
| path_cstr, &membuf, &err_str); | |
| if (is_error) { | |
| fprintf(stderr, "%20s file:%30s ERROR: %30s\n", __FUNCTION__, path_cstr, err_str); | |
| } | |
| lean_always_assert((is_error != 1) && "failed to create membuf from file"); | |
| lean_always_assert(err_str == NULL); | |
| return MemoryBuffer_to_lean(membuf); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_parse_bitcode( | |
| size_t context, size_t membuf) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMModuleRef out_module; | |
| char *err_str = NULL; | |
| int is_error = LLVMParseBitcodeInContext(lean_to_Context(context), | |
| lean_to_MemoryBuffer(membuf), | |
| &out_module, &err_str); | |
| if (is_error) { | |
| fprintf(stderr, "%20s ERROR: %30s\n", __FUNCTION__, err_str); | |
| } | |
| lean_always_assert(!is_error && "failed to parse bitcode"); | |
| lean_always_assert(err_str == NULL); | |
| return Module_to_lean(out_module); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_link_modules(size_t ctx, | |
| size_t dest_module, size_t src_module) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| int is_error = LLVMLinkModules2(lean_to_Module(dest_module), | |
| lean_to_Module(src_module)); | |
| if (is_error) { | |
| fprintf(stderr, "%20s ERROR: unable to link modules\n", __FUNCTION__); | |
| } | |
| lean_always_assert(!is_error && "failed to link modules"); | |
| return lean_box(0); | |
| #endif | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_create_target_machine(size_t ctx, | |
| size_t target, lean_object *tripleStr, lean_object *cpuStr, | |
| lean_object *featuresStr) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| // TODO (bollu): expose this option | |
| const LLVMCodeGenOptLevel optLevel = LLVMCodeGenLevelAggressive; | |
| const LLVMRelocMode relocMode = LLVMRelocPIC; | |
| const LLVMCodeModel codeModel = LLVMCodeModelDefault; | |
| LLVMTargetMachineRef tm = LLVMCreateTargetMachine( | |
| lean_to_Target(target), lean_string_cstr(tripleStr), | |
| lean_string_cstr(cpuStr), lean_string_cstr(featuresStr), optLevel, | |
| relocMode, codeModel); | |
| return TargetMachine_to_lean(tm); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_get_target_from_triple(size_t ctx, | |
| lean_object *triple) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMTargetRef t; | |
| char *errmsg = NULL; | |
| int is_error = | |
| LLVMGetTargetFromTriple(lean_string_cstr(triple), &t, &errmsg); | |
| if (is_error) { | |
| fprintf(stderr, "Unable to find target '%s'. Registered targets:\n", lean_string_cstr(triple)); | |
| for(LLVMTargetRef t = LLVMGetFirstTarget(); t != NULL; t = LLVMGetNextTarget(t)) { | |
| fprintf(stderr, " %-10s - %s\n", LLVMGetTargetName(t), LLVMGetTargetDescription(t)); | |
| } | |
| } | |
| lean_always_assert(!is_error && "failed to get target from triple"); | |
| return Target_to_lean(t); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_get_default_target_triple() { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| char *triple = LLVMGetDefaultTargetTriple(); | |
| lean_object *out = lean::mk_string(triple); | |
| free(triple); | |
| return out; | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_target_machine_emit_to_file(size_t ctx, | |
| size_t target_machine, size_t module, lean_object *filepath, | |
| uint64_t codegenType) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| // TODO (bollu): figure out a story for cross-compilation. | |
| // We currently choose not to invoke LLVMInitializeAllTargetInfos() etc. | |
| // since our build system only enables certain backends. | |
| // LLVMInitializeNativeTargetInfo(); | |
| char *err_msg = NULL; | |
| char *filepath_c_str = const_cast<char *>(lean_string_cstr(filepath)); | |
| int is_error = LLVMTargetMachineEmitToFile( | |
| lean_to_TargetMachine(target_machine), lean_to_Module(module), | |
| filepath_c_str, LLVMCodeGenFileType(codegenType), &err_msg); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| //extern "C" LEAN_EXPORT lean_object *lean_llvm_create_pass_manager(size_t ctx, | |
| // lean_object * /* w */) { | |
| //#ifndef LEAN_LLVM | |
| // lean_always_assert( | |
| // false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| // "the LLVM backend function.")); | |
| //#else | |
| // return PassManager_to_lean(LLVMCreatePassManager()); | |
| //#endif // LEAN_LLVM | |
| //} | |
| // | |
| //extern "C" LEAN_EXPORT lean_object *lean_llvm_run_pass_manager(size_t ctx, size_t pm, size_t mod, | |
| // lean_object * /* w */) { | |
| //#ifndef LEAN_LLVM | |
| // lean_always_assert( | |
| // false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| // "the LLVM backend function.")); | |
| //#else | |
| // int is_error = LLVMRunPassManager(lean_to_PassManager(pm), lean_to_Module(mod)); | |
| // return lean_box(0); | |
| //#endif // LEAN_LLVM | |
| //} | |
| // | |
| //extern "C" LEAN_EXPORT lean_object *lean_llvm_dispose_pass_manager(size_t ctx, size_t pm, | |
| // lean_object * /* w */) { | |
| //#ifndef LEAN_LLVM | |
| // lean_always_assert( | |
| // false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| // "the LLVM backend function.")); | |
| //#else | |
| // LLVMDisposePassManager(lean_to_PassManager(pm)); | |
| // return lean_box(0); | |
| //#endif // LEAN_LLVM | |
| //} | |
| // | |
| //extern "C" LEAN_EXPORT lean_object *lean_llvm_create_pass_manager_builder(size_t ctx, | |
| // lean_object * /* w */) { | |
| //#ifndef LEAN_LLVM | |
| // lean_always_assert( | |
| // false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| // "the LLVM backend function.")); | |
| //#else | |
| // return PassManagerBuilder_to_lean(LLVMPassManagerBuilderCreate()); | |
| //#endif // LEAN_LLVM | |
| //} | |
| // | |
| // | |
| //extern "C" LEAN_EXPORT lean_object *lean_llvm_dispose_pass_manager_builder(size_t ctx, size_t pmb, | |
| // lean_object * /* w */) { | |
| //#ifndef LEAN_LLVM | |
| // lean_always_assert( | |
| // false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| // "the LLVM backend function.")); | |
| //#else | |
| // LLVMPassManagerBuilderDispose(lean_to_PassManagerBuilder(pmb)); | |
| // return lean_box(0); | |
| //#endif // LEAN_LLVM | |
| //} | |
| // | |
| // | |
| //extern "C" LEAN_EXPORT lean_object *lean_llvm_pass_manager_builder_set_opt_level(size_t ctx, size_t pmb, unsigned opt_level, | |
| // lean_object * /* w */) { | |
| //#ifndef LEAN_LLVM | |
| // lean_always_assert( | |
| // false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| // "the LLVM backend function.")); | |
| //#else | |
| // LLVMPassManagerBuilderSetOptLevel(lean_to_PassManagerBuilder(pmb), opt_level); | |
| // return lean_box(0); | |
| //#endif // LEAN_LLVM | |
| //} | |
| // | |
| // | |
| //extern "C" LEAN_EXPORT lean_object *lean_llvm_pass_manager_builder_populate_module_pass_manager(size_t ctx, size_t pmb, size_t pm, | |
| // lean_object * /* w */) { | |
| //#ifndef LEAN_LLVM | |
| // lean_always_assert( | |
| // false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| // "the LLVM backend function.")); | |
| //#else | |
| // LLVMPassManagerBuilderPopulateModulePassManager(lean_to_PassManagerBuilder(pmb), lean_to_PassManager(pm)); | |
| // return lean_box(0); | |
| //#endif // LEAN_LLVM | |
| //} | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_dispose_target_machine(size_t ctx, size_t tm) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMDisposeTargetMachine(lean_to_TargetMachine(tm)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_dispose_module(size_t ctx, size_t mod) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMDisposeModule(lean_to_Module(mod)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_set_visibility(size_t ctx, size_t value, uint64_t vis) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMSetVisibility(lean_to_Value(value), LLVMVisibility(vis)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_set_dll_storage_class(size_t ctx, size_t value, uint64_t cls) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMSetDLLStorageClass(lean_to_Value(value), LLVMDLLStorageClass(cls)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_create_string_attribute(size_t ctx, lean_object* key, lean_object* value) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMAttributeRef attr = LLVMCreateStringAttribute(lean_to_Context(ctx), lean_string_cstr(key), lean_string_len(key), lean_string_cstr(value), lean_string_len(value)); | |
| return Attribute_to_lean(attr); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_add_attribute_at_index(size_t ctx, size_t fn, uint64_t idx, size_t attr) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMAddAttributeAtIndex(lean_to_Value(fn), idx, lean_to_Attribute(attr)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_get_first_global(size_t ctx, size_t mod) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMGetFirstGlobal(lean_to_Module(mod)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_get_next_global(size_t ctx, size_t global) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMGetNextGlobal(lean_to_Value(global)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_get_first_function(size_t ctx, size_t mod) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMGetFirstFunction(lean_to_Module(mod)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_get_next_function(size_t ctx, size_t function) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef out = LLVMGetNextFunction(lean_to_Value(function)); | |
| return Value_to_lean(out); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_set_linkage(size_t ctx, size_t value, uint64_t linkage) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMSetLinkage(lean_to_Value(value), LLVMLinkage(linkage)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_get_value_name2(size_t ctx, size_t value) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| size_t len; | |
| const char *name = LLVMGetValueName2(lean_to_Value(value), &len); | |
| return lean::mk_string(name); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT uint8_t llvm_is_declaration(size_t ctx, size_t global) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| return LLVMIsDeclaration(lean_to_Value(global)); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_verify_module(size_t ctx, size_t mod) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| char* msg = NULL; | |
| LLVMBool broken = LLVMVerifyModule(lean_to_Module(mod), LLVMReturnStatusAction, &msg); | |
| if (broken) { | |
| return lean::mk_option_some(lean_mk_string(msg)); | |
| } else { | |
| return lean::mk_option_none(); | |
| } | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT uint64_t lean_llvm_count_basic_blocks(size_t ctx, size_t fn_val) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef fn_ref = lean_to_Value(fn_val); | |
| return (uint64_t)LLVMCountBasicBlocks(fn_ref); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT size_t lean_llvm_get_entry_basic_block(size_t ctx, size_t fn_val) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMValueRef fn_ref = lean_to_Value(fn_val); | |
| LLVMBasicBlockRef bb_ref = LLVMGetEntryBasicBlock(fn_ref); | |
| return BasicBlock_to_lean(bb_ref); | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_get_first_instruction(size_t ctx, size_t bb) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMBasicBlockRef bb_ref = lean_to_BasicBlock(bb); | |
| LLVMValueRef instr_ref = LLVMGetFirstInstruction(bb_ref); | |
| if (instr_ref == NULL) { | |
| return lean::mk_option_none(); | |
| } else { | |
| return lean::mk_option_some(lean_box_usize(Value_to_lean(instr_ref))); | |
| } | |
| #endif // LEAN_LLVM | |
| } | |
| extern "C" LEAN_EXPORT lean_object *lean_llvm_position_builder_before( | |
| size_t ctx, size_t builder, size_t instr) { | |
| #ifndef LEAN_LLVM | |
| lean_always_assert( | |
| false && ("Please build a version of Lean4 with -DLLVM=ON to invoke " | |
| "the LLVM backend function.")); | |
| #else | |
| LLVMPositionBuilderBefore(lean_to_Builder(builder), lean_to_Value(instr)); | |
| return lean_box(0); | |
| #endif // LEAN_LLVM | |
| } |