Rewrite LLVM bindings #53
@ -21,7 +21,6 @@ add_executable(bb
|
||||
)
|
||||
|
||||
add_library(c_abi tests/c_abi.c)
|
||||
add_library(llvm_bindings src/llvm.cpp)
|
||||
|
||||
include_directories(src)
|
||||
add_compile_definitions(
|
||||
@ -29,25 +28,25 @@ add_compile_definitions(
|
||||
$<$<NOT:$<CONFIG:Debug>>:BB_DEBUG=0>
|
||||
)
|
||||
|
||||
find_library(llvm_bindings NAMES libllvm_bindings.dylib libllvm_bindings.lib libllvm_bindings.a libllvm_bindingsELF.dll.a libllvm_bindingsELF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_COMMON NAMES liblldCommon.dylib lldCommon.lib lldCommon.a liblldCommon.dll.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_ELF NAMES liblldELF.dylib lldELF.lib lldELF.a liblldELF.dll.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
# find_library(LLD_COFF NAMES liblldCOFF.dylib lldCOFF.lib lldCOFF.a liblldCOFF.dll.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
# find_library(LLD_MACHO NAMES liblldMachO.dylib lldMachO.lib lldMachO.a liblldMachO.dll.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
# find_library(LLD_MINGW NAMES liblldMinGW.dylib lldMinGW.lib lldMinGW.a liblldMinGW.dll.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
# find_library(LLD_WASM NAMES liblldWasm.dylib lldWasm.lib lldWasm.a liblldWasm.dll.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_COFF NAMES liblldCOFF.dylib lldCOFF.lib lldCOFF.a liblldCOFF.dll.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MACHO NAMES liblldMachO.dylib lldMachO.lib lldMachO.a liblldMachO.dll.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_MINGW NAMES liblldMinGW.dylib lldMinGW.lib lldMinGW.a liblldMinGW.dll.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
find_library(LLD_WASM NAMES liblldWasm.dylib lldWasm.lib lldWasm.a liblldWasm.dll.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
|
||||
|
||||
target_link_libraries(llvm_bindings PUBLIC
|
||||
target_link_libraries(bb PUBLIC
|
||||
${LLVM_AVAILABLE_LIBS}
|
||||
${LLD_COMMON}
|
||||
# ${LLD_COFF}
|
||||
${LLD_COFF}
|
||||
${LLD_ELF}
|
||||
# ${LLD_MACHO}
|
||||
# ${LLD_MINGW}
|
||||
# ${LLD_WASM}
|
||||
${LLD_MACHO}
|
||||
${LLD_MINGW}
|
||||
${LLD_WASM}
|
||||
${llvm_bindings}
|
||||
)
|
||||
|
||||
target_link_libraries(bb PUBLIC llvm_bindings)
|
||||
|
||||
add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -Wno-missing-designated-field-initializers -fno-signed-char -fwrapv -fno-strict-aliasing)
|
||||
add_compile_definitions(CMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}")
|
||||
add_compile_definitions(BB_CI=${BB_CI})
|
||||
|
142
src/compiler.bbb
142
src/compiler.bbb
@ -835,6 +835,8 @@ fail = fn () noreturn
|
||||
exit(1);
|
||||
}
|
||||
|
||||
LLVMError = opaque;
|
||||
|
||||
LLVMContext = opaque;
|
||||
LLVMModule = opaque;
|
||||
|
||||
@ -859,6 +861,8 @@ LLVMTargetDataLayout = opaque;
|
||||
LLVMTargetMachine = opaque;
|
||||
LLVMTargetMachineOptions = opaque;
|
||||
|
||||
LLVMPassBuilderOptions = opaque;
|
||||
|
||||
LLVMIntrinsicIndex = enum u32
|
||||
{
|
||||
"llvm.ctlz",
|
||||
@ -2646,43 +2650,10 @@ LLVMOptimizationLevel = enum u3
|
||||
Oz = 5,
|
||||
}
|
||||
|
||||
LLVMOptimizationOptions = bits u64
|
||||
{
|
||||
optimization_level: LLVMOptimizationLevel,
|
||||
debug_info: u1,
|
||||
loop_unrolling: u1,
|
||||
loop_interleaving: u1,
|
||||
loop_vectorization: u1,
|
||||
slp_vectorization: u1,
|
||||
merge_functions: u1,
|
||||
call_graph_profile: u1,
|
||||
unified_lto: u1,
|
||||
assignment_tracking: u1,
|
||||
verify_module: u1,
|
||||
reserved: u51,
|
||||
}
|
||||
|
||||
LLVMCodeGenerationFileType = enum u8
|
||||
LLVMCodeGenerationFileType = enum u32
|
||||
{
|
||||
assembly = 0,
|
||||
object = 1,
|
||||
null = 2,
|
||||
}
|
||||
|
||||
LLVMCodeGenerationOptions = struct
|
||||
{
|
||||
output_dwarf_file_path: []u8,
|
||||
output_file_path: []u8,
|
||||
file_type: LLVMCodeGenerationFileType,
|
||||
optimize_when_possible: u8,
|
||||
verify_module: u8,
|
||||
}
|
||||
|
||||
LLVMCodeGenerationResult = enum u8
|
||||
{
|
||||
success = 0,
|
||||
failed_to_create_file = 1,
|
||||
failed_to_emit_passes = 2,
|
||||
}
|
||||
|
||||
LLVMICmpPredicate = enum u32
|
||||
@ -2931,8 +2902,19 @@ llvm_module_create_function = fn (module: &LLVMModule, function_type: &LLVMType,
|
||||
[extern] LLVMSetFunctionCallConv = fn [cc(c)] (function: &LLVMValue, calling_convention: LLVMCallingConvention) void;
|
||||
[extern] LLVMSetInstructionCallConv = fn [cc(c)] (call: &LLVMValue, calling_convention: LLVMCallingConvention) void;
|
||||
|
||||
[extern] llvm_module_run_optimization_pipeline = fn [cc(c)] (module: &LLVMModule, target_machine: &LLVMTargetMachine, options: &LLVMOptimizationOptions) void;
|
||||
[extern] llvm_module_run_code_generation_pipeline = fn [cc(c)] (module: &LLVMModule, target_machine: &LLVMTargetMachine, options: &LLVMCodeGenerationOptions) LLVMCodeGenerationResult;
|
||||
[extern] LLVMCreatePassBuilderOptions = fn [cc(c)] () &LLVMPassBuilderOptions;
|
||||
|
||||
[extern] LLVMPassBuilderOptionsSetVerifyEach = fn [cc(c)] (options: &LLVMPassBuilderOptions, value: s32) void;
|
||||
[extern] LLVMPassBuilderOptionsSetDebugLogging = fn [cc(c)] (options: &LLVMPassBuilderOptions, value: s32) void;
|
||||
[extern] LLVMPassBuilderOptionsSetLoopInterleaving = fn [cc(c)] (options: &LLVMPassBuilderOptions, value: s32) void;
|
||||
[extern] LLVMPassBuilderOptionsSetLoopVectorization = fn [cc(c)] (options: &LLVMPassBuilderOptions, value: s32) void;
|
||||
[extern] LLVMPassBuilderOptionsSetSLPVectorization = fn [cc(c)] (options: &LLVMPassBuilderOptions, value: s32) void;
|
||||
[extern] LLVMPassBuilderOptionsSetLoopUnrolling = fn [cc(c)] (options: &LLVMPassBuilderOptions, value: s32) void;
|
||||
[extern] LLVMPassBuilderOptionsSetMergeFunctions = fn [cc(c)] (options: &LLVMPassBuilderOptions, value: s32) void;
|
||||
|
||||
[extern] LLVMRunPasses = fn [cc(c)] (module: &LLVMModule, passes: &u8, target_machine: &LLVMTargetMachine, options: &LLVMPassBuilderOptions) &LLVMError;
|
||||
|
||||
[extern] LLVMTargetMachineEmitToFile = fn [cc(c)] (target_machine: &LLVMTargetMachine, module: &LLVMModule, file_name: &u8, file_type: LLVMCodeGenerationFileType, error_message: &&u8) s32;
|
||||
|
||||
LLDResult = struct
|
||||
{
|
||||
@ -17016,38 +16998,52 @@ LLVMObjectGenerate = struct
|
||||
has_debug_info: u1,
|
||||
}
|
||||
|
||||
generate_object = fn (module: &LLVMModule, target_machine: &LLVMTargetMachine, options: LLVMObjectGenerate) LLVMCodeGenerationResult
|
||||
generate_object = fn (module: &LLVMModule, target_machine: &LLVMTargetMachine, options: LLVMObjectGenerate) u1
|
||||
{
|
||||
if (options.run_optimization_passes)
|
||||
{
|
||||
>prefer_speed = options.optimization_level == .O2 or options.optimization_level == .O3;
|
||||
>options: LLVMOptimizationOptions = {
|
||||
.optimization_level = options.optimization_level,
|
||||
.debug_info = options.has_debug_info,
|
||||
.loop_unrolling = prefer_speed,
|
||||
.loop_interleaving = prefer_speed,
|
||||
.loop_vectorization = prefer_speed,
|
||||
.slp_vectorization = prefer_speed,
|
||||
.merge_functions = prefer_speed,
|
||||
.call_graph_profile = 0,
|
||||
.unified_lto = 0,
|
||||
.assignment_tracking = options.has_debug_info,
|
||||
.verify_module = 1,
|
||||
zero,
|
||||
};
|
||||
llvm_module_run_optimization_pipeline(module, target_machine, &options);
|
||||
>prefer_speed: s32 = @extend(options.optimization_level == .O2 or options.optimization_level == .O3);
|
||||
>pass_builder_options = LLVMCreatePassBuilderOptions();
|
||||
LLVMPassBuilderOptionsSetVerifyEach(pass_builder_options, 1);
|
||||
LLVMPassBuilderOptionsSetDebugLogging(pass_builder_options, 0);
|
||||
LLVMPassBuilderOptionsSetLoopInterleaving(pass_builder_options, prefer_speed);
|
||||
LLVMPassBuilderOptionsSetLoopVectorization(pass_builder_options, prefer_speed);
|
||||
LLVMPassBuilderOptionsSetSLPVectorization(pass_builder_options, prefer_speed);
|
||||
LLVMPassBuilderOptionsSetLoopUnrolling(pass_builder_options, prefer_speed);
|
||||
LLVMPassBuilderOptionsSetMergeFunctions(pass_builder_options, prefer_speed);
|
||||
|
||||
>passes: &u8 = undefined;
|
||||
switch (options.optimization_level)
|
||||
{
|
||||
.O0 => { passes = "default<O0>"; },
|
||||
.O1 => { passes = "default<O1>"; },
|
||||
.O2 => { passes = "default<O2>"; },
|
||||
.O3 => { passes = "default<O3>"; },
|
||||
.Os => { passes = "default<Os>"; },
|
||||
.Oz => { passes = "default<Oz>"; },
|
||||
}
|
||||
|
||||
>error = LLVMRunPasses(module, passes, target_machine, pass_builder_options);
|
||||
if (error)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
}
|
||||
|
||||
>code_generation_options: LLVMCodeGenerationOptions = {
|
||||
.output_file_path = options.path,
|
||||
.file_type = .object,
|
||||
.optimize_when_possible = @extend(options.optimization_level > .O0),
|
||||
.verify_module = 1,
|
||||
zero,
|
||||
};
|
||||
>file_name = options.path.pointer;
|
||||
>error_message: &u8 = zero;
|
||||
>result = LLVMTargetMachineEmitToFile(target_machine, module, file_name, .object, &error_message);
|
||||
if (result != 0)
|
||||
{
|
||||
assert(error_message != zero);
|
||||
@trap();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(!error_message);
|
||||
}
|
||||
|
||||
>result = llvm_module_run_code_generation_pipeline(module, target_machine, &code_generation_options);
|
||||
return result;
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
link = fn (module: &Module) void
|
||||
@ -18106,10 +18102,7 @@ emit = fn (module: &Module) void
|
||||
.has_debug_info = module.has_debug_info,
|
||||
});
|
||||
|
||||
if (object_generation_result != .success)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
assert(object_generation_result);
|
||||
|
||||
link(module);
|
||||
}
|
||||
@ -18370,7 +18363,6 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile, envp: &&u8) []u8
|
||||
|
||||
>objects = [ output_object_path ][..];
|
||||
>c_abi_library = "build/libc_abi.a";
|
||||
>llvm_bindings_library = "build/libllvm_bindings.a";
|
||||
|
||||
>library_buffer: [256][]u8 = undefined;
|
||||
>library_directory: []u8 = zero;
|
||||
@ -18485,11 +18477,25 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile, envp: &&u8) []u8
|
||||
library_buffer[library_count] = "lldCommon";
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = "lldCOFF";
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = "lldELF";
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = "lldMachO";
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = "lldMinGW";
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = "lldWasm";
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = "llvm_bindings";
|
||||
library_count += 1;
|
||||
|
||||
library_names = library_buffer[..library_count];
|
||||
library_paths = { .pointer = &llvm_bindings_library, .length = 1 };
|
||||
}
|
||||
else if (string_equal(base_name, "tests"))
|
||||
{
|
||||
|
@ -343,11 +343,26 @@ fn String compile_file(Arena* arena, Compile options)
|
||||
|
||||
library_buffer[library_count] = string_literal("lldCommon");
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = string_literal("lldCOFF");
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = string_literal("lldELF");
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = string_literal("lldMachO");
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = string_literal("lldMinGW");
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = string_literal("lldWasm");
|
||||
library_count += 1;
|
||||
|
||||
library_buffer[library_count] = string_literal("llvm_bindings");
|
||||
library_count += 1;
|
||||
|
||||
library_names = { library_buffer, library_count };
|
||||
library_paths = { &llvm_bindings_library, 1 };
|
||||
}
|
||||
else if (base_name.equal(string_literal("tests")))
|
||||
{
|
||||
|
@ -9176,36 +9176,52 @@ struct ObjectGenerate
|
||||
bool has_debug_info;
|
||||
};
|
||||
|
||||
fn BBLLVMCodeGenerationPipelineResult generate_object(LLVMModuleRef module, LLVMTargetMachineRef target_machine, ObjectGenerate options)
|
||||
fn bool generate_object(LLVMModuleRef module, LLVMTargetMachineRef target_machine, ObjectGenerate options)
|
||||
{
|
||||
if (options.run_optimization_passes)
|
||||
{
|
||||
// BBLLVM
|
||||
bool prefer_speed = options.optimization_level == BBLLVMOptimizationLevel::O2 || options.optimization_level == BBLLVMOptimizationLevel::O3;
|
||||
BBLLVMOptimizationPipelineOptions optimization_options = {
|
||||
.optimization_level = (u64)options.optimization_level,
|
||||
.debug_info = options.has_debug_info,
|
||||
.loop_unrolling = prefer_speed,
|
||||
.loop_interleaving = prefer_speed,
|
||||
.loop_vectorization = prefer_speed,
|
||||
.slp_vectorization = prefer_speed,
|
||||
.merge_functions = prefer_speed,
|
||||
.call_graph_profile = false,
|
||||
.unified_lto = false,
|
||||
.assignment_tracking = options.has_debug_info,
|
||||
.verify_module = true,
|
||||
};
|
||||
llvm_module_run_optimization_pipeline(module, target_machine, optimization_options);
|
||||
auto pass_builder_options = LLVMCreatePassBuilderOptions();
|
||||
LLVMPassBuilderOptionsSetVerifyEach(pass_builder_options, 1);
|
||||
LLVMPassBuilderOptionsSetDebugLogging(pass_builder_options, 0);
|
||||
LLVMPassBuilderOptionsSetLoopInterleaving(pass_builder_options, prefer_speed);
|
||||
LLVMPassBuilderOptionsSetLoopVectorization(pass_builder_options, prefer_speed);
|
||||
LLVMPassBuilderOptionsSetSLPVectorization(pass_builder_options, prefer_speed);
|
||||
LLVMPassBuilderOptionsSetLoopUnrolling(pass_builder_options, prefer_speed);
|
||||
LLVMPassBuilderOptionsSetMergeFunctions(pass_builder_options, prefer_speed);
|
||||
|
||||
const char* passes;
|
||||
switch (options.optimization_level)
|
||||
{
|
||||
case BBLLVMOptimizationLevel::O0: passes = "default<O0>"; break;
|
||||
case BBLLVMOptimizationLevel::O1: passes = "default<O1>"; break;
|
||||
case BBLLVMOptimizationLevel::O2: passes = "default<O2>"; break;
|
||||
case BBLLVMOptimizationLevel::O3: passes = "default<O3>"; break;
|
||||
case BBLLVMOptimizationLevel::Os: passes = "default<Os>"; break;
|
||||
case BBLLVMOptimizationLevel::Oz: passes = "default<Oz>"; break;
|
||||
}
|
||||
|
||||
auto error = LLVMRunPasses(module, passes, target_machine, pass_builder_options);
|
||||
if (error)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
}
|
||||
|
||||
BBLLVMCodeGenerationPipelineOptions code_generation_options = {
|
||||
.output_file_path = options.path,
|
||||
.file_type = BBLLVMCodeGenerationFileType::object_file,
|
||||
.optimize_when_possible = options.optimization_level > BBLLVMOptimizationLevel::O0,
|
||||
.verify_module = true,
|
||||
};
|
||||
auto result = llvm_module_run_code_generation_pipeline(module, target_machine, &code_generation_options);
|
||||
return result;
|
||||
auto file_name = cstr(options.path);
|
||||
char* error_message = 0;
|
||||
auto result = LLVMTargetMachineEmitToFile(target_machine, module, file_name, LLVMObjectFile, &error_message);
|
||||
if (result)
|
||||
{
|
||||
assert(error_message);
|
||||
trap();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(!error_message);
|
||||
}
|
||||
|
||||
return !result;
|
||||
}
|
||||
|
||||
fn void link(Module* module)
|
||||
@ -10057,10 +10073,7 @@ void emit(Module* module)
|
||||
.run_optimization_passes = module->build_mode != BuildMode::debug_none,
|
||||
.has_debug_info = module->has_debug_info,
|
||||
});
|
||||
if (object_generation_result != BBLLVMCodeGenerationPipelineResult::success)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
assert(object_generation_result);
|
||||
|
||||
link(module);
|
||||
}
|
||||
|
49
src/llvm.hpp
49
src/llvm.hpp
@ -7,6 +7,7 @@
|
||||
#include <llvm-c/Target.h>
|
||||
#include <llvm-c/Analysis.h>
|
||||
#include <llvm-c/TargetMachine.h>
|
||||
#include <llvm-c/Transforms/PassBuilder.h>
|
||||
|
||||
struct LLDResult
|
||||
{
|
||||
@ -15,31 +16,6 @@ struct LLDResult
|
||||
bool success;
|
||||
};
|
||||
|
||||
enum class BBLLVMCodeGenerationPipelineResult : u8
|
||||
{
|
||||
success = 0,
|
||||
failed_to_create_file = 1,
|
||||
failed_to_add_emit_passes = 2,
|
||||
};
|
||||
|
||||
enum class BBLLVMCodeGenerationFileType : u8
|
||||
{
|
||||
assembly_file = 0,
|
||||
object_file = 1,
|
||||
null = 2,
|
||||
};
|
||||
|
||||
struct BBLLVMCodeGenerationPipelineOptions
|
||||
{
|
||||
String output_dwarf_file_path;
|
||||
String output_file_path;
|
||||
BBLLVMCodeGenerationFileType file_type;
|
||||
bool optimize_when_possible;
|
||||
bool verify_module;
|
||||
};
|
||||
|
||||
static_assert(sizeof(BBLLVMCodeGenerationPipelineOptions) == 5 * sizeof(u64));
|
||||
|
||||
enum class BBLLVMOptimizationLevel : u8
|
||||
{
|
||||
O0 = 0,
|
||||
@ -50,26 +26,6 @@ enum class BBLLVMOptimizationLevel : u8
|
||||
Oz = 5,
|
||||
};
|
||||
|
||||
#define BB_LLVM_OPTIMIZATION_PIPELINE_OPTIONS_PADDING_BIT_COUNT (51)
|
||||
struct BBLLVMOptimizationPipelineOptions
|
||||
{
|
||||
u64 optimization_level:3;
|
||||
u64 debug_info:1;
|
||||
u64 loop_unrolling:1;
|
||||
u64 loop_interleaving:1;
|
||||
u64 loop_vectorization:1;
|
||||
u64 slp_vectorization:1;
|
||||
u64 merge_functions:1;
|
||||
u64 call_graph_profile:1;
|
||||
u64 unified_lto:1;
|
||||
u64 assignment_tracking:1;
|
||||
u64 verify_module:1;
|
||||
u64 reserved:BB_LLVM_OPTIMIZATION_PIPELINE_OPTIONS_PADDING_BIT_COUNT;
|
||||
};
|
||||
|
||||
static_assert(sizeof(BBLLVMOptimizationPipelineOptions) == sizeof(u64));
|
||||
static_assert(BB_LLVM_OPTIMIZATION_PIPELINE_OPTIONS_PADDING_BIT_COUNT == 51);
|
||||
|
||||
enum class DwarfType
|
||||
{
|
||||
void_type = 0x0,
|
||||
@ -123,9 +79,6 @@ extern "C" LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b
|
||||
|
||||
extern "C" void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type);
|
||||
|
||||
extern "C" void llvm_module_run_optimization_pipeline(LLVMModuleRef module, LLVMTargetMachineRef target_machine, BBLLVMOptimizationPipelineOptions options);
|
||||
extern "C" BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeline(LLVMModuleRef m, LLVMTargetMachineRef tm, const BBLLVMCodeGenerationPipelineOptions* options);
|
||||
|
||||
#define lld_api_args() char* const* argument_pointer, u64 argument_count, bool exit_early, bool disable_output
|
||||
#define lld_api_function_decl(link_name) LLDResult lld_ ## link_name ## _link(lld_api_args())
|
||||
extern "C" lld_api_function_decl(elf);
|
||||
|
Loading…
x
Reference in New Issue
Block a user