Again co-developed with @bollu. Based on top of: #3225 While hunting down the performance discrepancy on qsort.lean between C and LLVM we noticed there was a single, trivially optimizeable, alloca (LLVM's stack memory allocation instruction) that had load/stores in the hot code path. We then found: https://groups.google.com/g/llvm-dev/c/e90HiFcFF7Y. TLDR: `mem2reg`, the pass responsible for getting rid of allocas if possible, only triggers on an alloca if it is in the first BB. The allocas of the current implementation get put right at the location where they are needed -> they are ignored by mem2reg. Thus we decided to add functionality that allows us to push all allocas up into the first BB. We initially wanted to write `buildPrologueAlloca` in a `withReader` style so: 1. get the current position of the builder 2. jump to first BB and do the thing 3. revert position to the original However the LLVM C API does not expose an option to obtain the current position of an IR builder. Thus we ended up at the current implementation which resets the builder position to the end of the BB that the function was called from. This is valid because we never operate anywhere but the end of the current BB in the LLVM emitter. The numbers on the qsort benchmark got improved by the change as expected, however we are not fully there yet: ``` C: Benchmark 1: ./qsort.lean.out 400 Time (mean ± σ): 2.005 s ± 0.013 s [User: 1.996 s, System: 0.003 s] Range (min … max): 1.993 s … 2.036 s 10 runs LLVM before aligning the types Benchmark 1: ./qsort.lean.out 400 Time (mean ± σ): 2.151 s ± 0.007 s [User: 2.146 s, System: 0.001 s] Range (min … max): 2.142 s … 2.161 s 10 runs LLVM after aligning the types Benchmark 1: ./qsort.lean.out 400 Time (mean ± σ): 2.073 s ± 0.011 s [User: 2.067 s, System: 0.002 s] Range (min … max): 2.060 s … 2.097 s 10 runs LLVM after this Benchmark 1: ./qsort.lean.out 400 Time (mean ± σ): 2.038 s ± 0.009 s [User: 2.032 s, System: 0.001 s] Range (min … max): 2.027 s … 2.052 s 10 runs ``` Note: If you wish to merge this PR independently from its predecessor, there is no technical dependency between the two, I'm merely stacking them so we can see the performance impacts of each more clearly.
1498 lines
56 KiB
C++
1498 lines
56 KiB
C++
/*
|
|
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
|
|
|
|
extern "C" LEAN_EXPORT lean_object* lean_llvm_initialize_target_info(lean_object * /* w */) {
|
|
|
|
#ifdef LEAN_LLVM
|
|
LLVMInitializeAllTargetInfos();
|
|
LLVMInitializeAllTargets();
|
|
LLVMInitializeAllTargetMCs();
|
|
LLVMInitializeAllAsmParsers();
|
|
LLVMInitializeAllAsmPrinters();
|
|
#endif
|
|
|
|
return lean_io_result_mk_ok(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);
|
|
}
|
|
|
|
// == 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 lean_object *lean_llvm_create_context(
|
|
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
|
|
LLVMContextRef ctx = LLVMContextCreate();
|
|
return lean_io_result_mk_ok(lean_box_usize(Context_to_lean(ctx)));
|
|
#endif // LEAN_LLVM
|
|
};
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_create_module(
|
|
size_t ctx, lean_object *str, 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
|
|
LLVMModuleRef mod = LLVMModuleCreateWithNameInContext(lean_string_cstr(str),
|
|
lean_to_Context(ctx));
|
|
return lean_io_result_mk_ok(lean_box_usize(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, 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
|
|
const int err =
|
|
LLVMWriteBitcodeToFile(lean_to_Module(mod), lean_string_cstr(filepath));
|
|
lean_always_assert(!err && "unable to write bitcode");
|
|
return lean_io_result_mk_ok(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, 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
|
|
char *str = LLVMPrintModuleToString(lean_to_Module(mod));
|
|
lean_object *out = lean_io_result_mk_ok(lean_mk_string(str));
|
|
free(str);
|
|
return out;
|
|
#endif // LEAN_LLVM
|
|
};
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_add_function(
|
|
size_t ctx, size_t mod, lean_object *name, size_t type, 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
|
|
LLVMValueRef out = LLVMAddFunction(
|
|
lean_to_Module(mod), lean_string_cstr(name), lean_to_Type(type));
|
|
return lean_io_result_mk_ok(lean_box_usize(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, 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
|
|
LLVMValueRef f =
|
|
LLVMGetNamedFunction(lean_to_Module(mod), lean_string_cstr(name));
|
|
return lean_io_result_mk_ok(
|
|
f ? lean::mk_option_some(lean_box_usize(Value_to_lean(f)))
|
|
: lean::mk_option_none());
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_add_global(
|
|
size_t ctx, size_t mod, lean_object *name, size_t type, 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
|
|
LLVMValueRef out = LLVMAddGlobal(lean_to_Module(mod), lean_to_Type(type),
|
|
lean_string_cstr(name));
|
|
|
|
return lean_io_result_mk_ok(lean_box_usize(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, 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
|
|
LLVMValueRef g =
|
|
LLVMGetNamedGlobal(lean_to_Module(mod), lean_string_cstr(name));
|
|
return lean_io_result_mk_ok(
|
|
g ? lean::mk_option_some(lean_box_usize(Value_to_lean(g)))
|
|
: lean::mk_option_none());
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_global_string(
|
|
size_t ctx, size_t builder, lean_object *str, lean_object *name,
|
|
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
|
|
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 lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_undef(size_t ctx, size_t ty,
|
|
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
|
|
LLVMValueRef out = LLVMGetUndef(lean_to_Type(ty));
|
|
return lean_io_result_mk_ok(lean_box_usize(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, 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
|
|
LLVMSetInitializer(lean_to_Value(global), lean_to_Value(initializer));
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_function_type(
|
|
size_t ctx, size_t retty, lean_object *argtys, uint8_t isvararg,
|
|
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
|
|
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 lean_io_result_mk_ok(lean_box_usize(Type_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_opaque_pointer_type_in_context(
|
|
size_t ctx, uint64_t addrspace, 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 lean_io_result_mk_ok(lean_box_usize(
|
|
Type_to_lean(LLVMPointerTypeInContext(lean_to_Context(ctx), addrspace))));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_int_type_in_context(
|
|
size_t ctx, uint64_t width, 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 lean_io_result_mk_ok(lean_box_usize(
|
|
Type_to_lean(LLVMIntTypeInContext(lean_to_Context(ctx), width))));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_float_type_in_context(
|
|
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 lean_io_result_mk_ok(lean_box_usize(
|
|
Type_to_lean(LLVMFloatTypeInContext(lean_to_Context(ctx)))));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_void_type_in_context(
|
|
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 lean_io_result_mk_ok(lean_box_usize(
|
|
Type_to_lean(LLVMVoidTypeInContext(lean_to_Context(ctx)))));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_double_type_in_context(
|
|
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 lean_io_result_mk_ok(lean_box_usize(
|
|
Type_to_lean(LLVMDoubleTypeInContext(lean_to_Context(ctx)))));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_pointer_type(
|
|
size_t ctx, size_t base, 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
|
|
LLVMTypeRef out = LLVMPointerType(lean_to_Type(base), /*addrspace=*/0);
|
|
return lean_io_result_mk_ok(lean_box_usize(Type_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_array_type(
|
|
size_t ctx, size_t base, uint64_t nelem, 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
|
|
LLVMTypeRef out = LLVMArrayType(lean_to_Type(base), /*nelem=*/nelem);
|
|
return lean_io_result_mk_ok(lean_box_usize(Type_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_create_builder_in_context(
|
|
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 lean_io_result_mk_ok(lean_box_usize(
|
|
Builder_to_lean(LLVMCreateBuilderInContext(lean_to_Context(ctx)))));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_append_basic_block_in_context(
|
|
size_t ctx, size_t fn, lean_object *name, 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
|
|
LLVMBasicBlockRef bb = LLVMAppendBasicBlockInContext(
|
|
lean_to_Context(ctx), lean_to_Value(fn), lean_string_cstr(name));
|
|
return lean_io_result_mk_ok(lean_box_usize(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, 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
|
|
LLVMPositionBuilderAtEnd(lean_to_Builder(builder), lean_to_BasicBlock(bb));
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_clear_insertion_position(size_t ctx,
|
|
size_t builder, 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
|
|
LLVMClearInsertionPosition(lean_to_Builder(builder));
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_call2(
|
|
size_t ctx, size_t builder, size_t fnty, size_t fnval, lean_object *args,
|
|
lean_object *name, 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
|
|
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 lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_cond_br(
|
|
size_t ctx,
|
|
size_t builder, size_t if_, size_t thenbb, size_t elsebb,
|
|
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
|
|
LLVMValueRef out =
|
|
LLVMBuildCondBr(lean_to_Builder(builder), lean_to_Value(if_),
|
|
lean_to_BasicBlock(thenbb), lean_to_BasicBlock(elsebb));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_br(size_t ctx, size_t builder,
|
|
size_t bb,
|
|
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
|
|
LLVMValueRef out =
|
|
LLVMBuildBr(lean_to_Builder(builder), lean_to_BasicBlock(bb));
|
|
return lean_io_result_mk_ok(lean_box_usize(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, 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
|
|
LLVMValueRef out = LLVMBuildStore(lean_to_Builder(builder),
|
|
lean_to_Value(v), lean_to_Value(slot));
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_load2(size_t ctx,
|
|
size_t builder, size_t ty, size_t slot, lean_object *name, 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
|
|
LLVMValueRef out = LLVMBuildLoad2(
|
|
lean_to_Builder(builder), lean_to_Type(ty), lean_to_Value(slot), lean_string_cstr(name));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_alloca(size_t ctx,
|
|
size_t builder, size_t type, lean_object *name, 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
|
|
LLVMValueRef out = LLVMBuildAlloca(
|
|
lean_to_Builder(builder), lean_to_Type(type), lean_string_cstr(name));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_ret(size_t ctx, size_t builder,
|
|
size_t v,
|
|
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
|
|
LLVMValueRef out = LLVMBuildRet(lean_to_Builder(builder), lean_to_Value(v));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_ret_void(
|
|
size_t builder, 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
|
|
LLVMValueRef out = LLVMBuildRetVoid(lean_to_Builder(builder));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_unreachable(size_t ctx,
|
|
size_t builder, 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
|
|
LLVMValueRef out = LLVMBuildUnreachable(lean_to_Builder(builder));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_inbounds_gep2(size_t ctx,
|
|
size_t builder, size_t ty, size_t pointer, lean_object *indices, lean_object *name,
|
|
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
|
|
|
|
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 lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_gep2(size_t ctx, size_t builder,
|
|
size_t ty,
|
|
size_t pointer,
|
|
lean_object *indices,
|
|
lean_object *name,
|
|
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
|
|
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 lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_sext(size_t ctx,
|
|
size_t builder, size_t val, size_t destty, lean_object *name,
|
|
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
|
|
LLVMValueRef out =
|
|
LLVMBuildSExt(lean_to_Builder(builder), lean_to_Value(val),
|
|
lean_to_Type(destty), lean_string_cstr(name));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_zext(size_t ctx,
|
|
size_t builder, size_t val, size_t destty, lean_object *name,
|
|
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
|
|
LLVMValueRef out =
|
|
LLVMBuildZExt(lean_to_Builder(builder), lean_to_Value(val),
|
|
lean_to_Type(destty), lean_string_cstr(name));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_sext_or_trunc(size_t ctx,
|
|
size_t builder, size_t val, size_t destty, lean_object *name,
|
|
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
|
|
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 lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_switch(size_t ctx,
|
|
size_t builder, size_t val, size_t elsebb, uint64_t numCases,
|
|
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
|
|
LLVMValueRef out =
|
|
LLVMBuildSwitch(lean_to_Builder(builder), lean_to_Value(val),
|
|
lean_to_BasicBlock(elsebb), numCases);
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_ptr_to_int(size_t ctx,
|
|
size_t builder, size_t ptr, size_t destty, lean_object *name,
|
|
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
|
|
LLVMValueRef out =
|
|
LLVMBuildPtrToInt(lean_to_Builder(builder), lean_to_Value(ptr),
|
|
lean_to_Type(destty), lean_string_cstr(name));
|
|
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_mul(size_t ctx,
|
|
size_t builder,
|
|
size_t lhs, size_t rhs,
|
|
lean_object *name,
|
|
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
|
|
LLVMValueRef out =
|
|
LLVMBuildMul(lean_to_Builder(builder), lean_to_Value(lhs),
|
|
lean_to_Value(rhs), lean_string_cstr(name));
|
|
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_add(size_t ctx, size_t builder,
|
|
size_t lhs, size_t rhs,
|
|
lean_object *name,
|
|
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
|
|
LLVMValueRef out =
|
|
LLVMBuildAdd(lean_to_Builder(builder), lean_to_Value(lhs),
|
|
lean_to_Value(rhs), lean_string_cstr(name));
|
|
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_sub(size_t ctx, size_t builder,
|
|
size_t lhs, size_t rhs,
|
|
lean_object *name,
|
|
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
|
|
LLVMValueRef out =
|
|
LLVMBuildSub(lean_to_Builder(builder), lean_to_Value(lhs),
|
|
lean_to_Value(rhs), lean_string_cstr(name));
|
|
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_not(size_t ctx, size_t builder,
|
|
size_t v,
|
|
lean_object *name,
|
|
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
|
|
LLVMValueRef out = LLVMBuildNot(lean_to_Builder(builder), lean_to_Value(v),
|
|
lean_string_cstr(name));
|
|
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_build_icmp(size_t ctx,
|
|
size_t builder, uint64_t predicate, size_t x, size_t y, lean_object *name,
|
|
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
|
|
LLVMValueRef out = LLVMBuildICmp(
|
|
lean_to_Builder(builder), LLVMIntPredicate(predicate), lean_to_Value(x),
|
|
lean_to_Value(y), lean_string_cstr(name));
|
|
|
|
return lean_io_result_mk_ok(lean_box_usize(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,
|
|
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
|
|
LLVMAddCase(lean_to_Value(switch_), lean_to_Value(onVal),
|
|
lean_to_BasicBlock(destbb));
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_basic_block_parent(size_t ctx,
|
|
size_t bb, 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
|
|
LLVMValueRef out = LLVMGetBasicBlockParent(lean_to_BasicBlock(bb));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_insert_block(size_t ctx,
|
|
size_t builder, 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
|
|
LLVMBasicBlockRef out = LLVMGetInsertBlock(lean_to_Builder(builder));
|
|
return lean_io_result_mk_ok(lean_box_usize(BasicBlock_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_type_of(size_t ctx, size_t val,
|
|
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
|
|
LLVMTypeRef ty = LLVMTypeOf(lean_to_Value(val));
|
|
return lean_io_result_mk_ok(lean_box_usize(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, 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
|
|
const char *s = LLVMPrintModuleToString(lean_to_Module(mod));
|
|
return lean_io_result_mk_ok(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, 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
|
|
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_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_const_int(size_t ctx, size_t ty, uint64_t val,
|
|
uint8_t sext,
|
|
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
|
|
LLVMValueRef out = LLVMConstInt(lean_to_Type(ty), val, sext);
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_const_array(
|
|
size_t ctx, size_t elemty, lean_object *args, 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
|
|
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 lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_const_string(
|
|
size_t ctx, lean_object *s, lean_object * /* w */) {
|
|
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 lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_const_pointer_null(
|
|
size_t ctx, size_t elemty, 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
|
|
|
|
LLVMValueRef out = LLVMConstPointerNull(lean_to_Type(elemty));
|
|
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *llvm_get_param(size_t ctx, size_t f, uint64_t ix,
|
|
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
|
|
LLVMValueRef out = LLVMGetParam(lean_to_Value(f), ix);
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object * llvm_count_params(size_t ctx, size_t f,
|
|
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
|
|
unsigned n = LLVMCountParams(lean_to_Value(f));
|
|
return lean_io_result_mk_ok(lean_box_uint64(n));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_set_tail_call(
|
|
size_t ctx, size_t fnval, uint8_t isTail, 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
|
|
LLVMSetTailCall(lean_to_Value(fnval), isTail);
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *
|
|
lean_llvm_create_memory_buffer_with_contents_of_file(size_t ctx, lean_object *path,
|
|
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
|
|
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 lean_io_result_mk_ok(lean_box_usize(MemoryBuffer_to_lean(membuf)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_parse_bitcode(
|
|
size_t context, size_t membuf, 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
|
|
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 lean_io_result_mk_ok(lean_box_usize(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, 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 = 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_io_result_mk_ok(lean_box(0));
|
|
#endif
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_create_target_machine(size_t ctx,
|
|
size_t target, lean_object *tripleStr, lean_object *cpuStr,
|
|
lean_object *featuresStr, 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
|
|
// 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 lean_io_result_mk_ok(lean_box_usize(TargetMachine_to_lean(tm)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_target_from_triple(size_t ctx,
|
|
lean_object *triple, 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
|
|
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 lean_io_result_mk_ok(lean_box_usize(Target_to_lean(t)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_default_target_triple(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
|
|
char *triple = LLVMGetDefaultTargetTriple();
|
|
lean_object *out = lean::mk_string(triple);
|
|
free(triple);
|
|
return lean_io_result_mk_ok(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, 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
|
|
// 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_io_result_mk_ok(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 lean_io_result_mk_ok(lean_box_usize(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_io_result_mk_ok(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_io_result_mk_ok(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 lean_io_result_mk_ok(lean_box_usize(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_io_result_mk_ok(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_io_result_mk_ok(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_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_dispose_target_machine(size_t ctx, size_t tm,
|
|
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
|
|
LLVMDisposeTargetMachine(lean_to_TargetMachine(tm));
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_dispose_module(size_t ctx, 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
|
|
LLVMDisposeModule(lean_to_Module(mod));
|
|
return lean_io_result_mk_ok(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,
|
|
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
|
|
LLVMSetVisibility(lean_to_Value(value), LLVMVisibility(vis));
|
|
return lean_io_result_mk_ok(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,
|
|
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
|
|
LLVMSetDLLStorageClass(lean_to_Value(value), LLVMDLLStorageClass(cls));
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_create_string_attribute(size_t ctx, lean_object* key, lean_object* value,
|
|
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
|
|
LLVMAttributeRef attr = LLVMCreateStringAttribute(lean_to_Context(ctx), lean_string_cstr(key), lean_string_len(key), lean_string_cstr(value), lean_string_len(value));
|
|
return lean_io_result_mk_ok(lean_box_usize(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,
|
|
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
|
|
LLVMAddAttributeAtIndex(lean_to_Value(fn), idx, lean_to_Attribute(attr));
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_first_global(size_t ctx, 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
|
|
LLVMValueRef out = LLVMGetFirstGlobal(lean_to_Module(mod));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_next_global(size_t ctx, size_t global,
|
|
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
|
|
LLVMValueRef out = LLVMGetNextGlobal(lean_to_Value(global));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_first_function(size_t ctx, 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
|
|
LLVMValueRef out = LLVMGetFirstFunction(lean_to_Module(mod));
|
|
return lean_io_result_mk_ok(lean_box_usize(Value_to_lean(out)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_next_function(size_t ctx, size_t function,
|
|
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
|
|
LLVMValueRef out = LLVMGetNextFunction(lean_to_Value(function));
|
|
return lean_io_result_mk_ok(lean_box_usize(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,
|
|
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
|
|
LLVMSetLinkage(lean_to_Value(value), LLVMLinkage(linkage));
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_value_name2(size_t ctx, size_t value,
|
|
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
|
|
size_t len;
|
|
const char *name = LLVMGetValueName2(lean_to_Value(value), &len);
|
|
return lean_io_result_mk_ok(lean::mk_string(name));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *llvm_is_declaration(size_t ctx, size_t global, 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
|
|
uint8_t is_bool = LLVMIsDeclaration(lean_to_Value(global));
|
|
return lean_io_result_mk_ok(lean_box(is_bool));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_verify_module(size_t ctx, 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
|
|
char* msg = NULL;
|
|
LLVMBool broken = LLVMVerifyModule(lean_to_Module(mod), LLVMReturnStatusAction, &msg);
|
|
if (broken) {
|
|
return lean_io_result_mk_ok(lean::mk_option_some(lean_mk_string(msg)));
|
|
} else {
|
|
return lean_io_result_mk_ok(lean::mk_option_none());
|
|
}
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_count_basic_blocks(size_t ctx, size_t fn_val,
|
|
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
|
|
LLVMValueRef fn_ref = lean_to_Value(fn_val);
|
|
return lean_io_result_mk_ok(lean_box_uint64((uint64_t)LLVMCountBasicBlocks(fn_ref)));
|
|
#endif // LEAN_LLVM
|
|
}
|
|
|
|
extern "C" LEAN_EXPORT lean_object *lean_llvm_get_entry_basic_block(size_t ctx, size_t fn_val,
|
|
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
|
|
LLVMValueRef fn_ref = lean_to_Value(fn_val);
|
|
LLVMBasicBlockRef bb_ref = LLVMGetEntryBasicBlock(fn_ref);
|
|
return lean_io_result_mk_ok(lean_box_usize(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,
|
|
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
|
|
LLVMBasicBlockRef bb_ref = lean_to_BasicBlock(bb);
|
|
LLVMValueRef instr_ref = LLVMGetFirstInstruction(bb_ref);
|
|
if (instr_ref == NULL) {
|
|
return lean_io_result_mk_ok(lean::mk_option_none());
|
|
} else {
|
|
return lean_io_result_mk_ok(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, 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
|
|
LLVMPositionBuilderBefore(lean_to_Builder(builder), lean_to_Value(instr));
|
|
return lean_io_result_mk_ok(lean_box(0));
|
|
#endif // LEAN_LLVM
|
|
}
|