forked from M-Labs/nac3
core: add error raising in IRRT & codegen IRRT CallFunction util
This commit is contained in:
parent
cb2b7bec3e
commit
49ab9087d8
|
@ -33,6 +33,7 @@ use inkwell::{
|
||||||
OptimizationLevel,
|
OptimizationLevel,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use nac3core::codegen::irrt::setup_irrt_exceptions;
|
||||||
use nac3core::codegen::{gen_func_impl, CodeGenLLVMOptions, CodeGenTargetMachineOptions};
|
use nac3core::codegen::{gen_func_impl, CodeGenLLVMOptions, CodeGenTargetMachineOptions};
|
||||||
use nac3core::toplevel::builtins::get_exn_constructor;
|
use nac3core::toplevel::builtins::get_exn_constructor;
|
||||||
use nac3core::typecheck::typedef::{TypeEnum, Unifier, VarMap};
|
use nac3core::typecheck::typedef::{TypeEnum, Unifier, VarMap};
|
||||||
|
@ -498,6 +499,11 @@ impl Nac3 {
|
||||||
.register_top_level(synthesized.pop().unwrap(), Some(resolver.clone()), "", false)
|
.register_top_level(synthesized.pop().unwrap(), Some(resolver.clone()), "", false)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
// Process IRRT
|
||||||
|
let context = inkwell::context::Context::create();
|
||||||
|
let irrt = load_irrt(&context);
|
||||||
|
setup_irrt_exceptions(&context, &irrt, resolver.as_ref());
|
||||||
|
|
||||||
let fun_signature =
|
let fun_signature =
|
||||||
FunSignature { args: vec![], ret: self.primitive.none, vars: VarMap::new() };
|
FunSignature { args: vec![], ret: self.primitive.none, vars: VarMap::new() };
|
||||||
let mut store = ConcreteTypeStore::new();
|
let mut store = ConcreteTypeStore::new();
|
||||||
|
@ -668,7 +674,7 @@ impl Nac3 {
|
||||||
membuffer.lock().push(buffer);
|
membuffer.lock().push(buffer);
|
||||||
});
|
});
|
||||||
|
|
||||||
let context = inkwell::context::Context::create();
|
// Link all modules into `main`.
|
||||||
let buffers = membuffers.lock();
|
let buffers = membuffers.lock();
|
||||||
let main = context
|
let main = context
|
||||||
.create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main"))
|
.create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main"))
|
||||||
|
@ -697,8 +703,7 @@ impl Nac3 {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
main.link_in_module(load_irrt(&context))
|
main.link_in_module(irrt).map_err(|err| CompileError::new_err(err.to_string()))?;
|
||||||
.map_err(|err| CompileError::new_err(err.to_string()))?;
|
|
||||||
|
|
||||||
let mut function_iter = main.get_first_function();
|
let mut function_iter = main.get_first_function();
|
||||||
while let Some(func) = function_iter {
|
while let Some(func) = function_iter {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <irrt/int_defs.hpp>
|
||||||
|
|
||||||
|
template <typename SizeT>
|
||||||
|
struct CSlice {
|
||||||
|
uint8_t* base;
|
||||||
|
SizeT len;
|
||||||
|
};
|
|
@ -0,0 +1,123 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <irrt/cslice.hpp>
|
||||||
|
#include <irrt/int_defs.hpp>
|
||||||
|
#include <irrt/util.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The int type of ARTIQ exception IDs.
|
||||||
|
*
|
||||||
|
* It is always `int32_t`
|
||||||
|
*/
|
||||||
|
typedef int32_t ExceptionId;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A set of exceptions IRRT can use.
|
||||||
|
* Must be synchronized with `setup_irrt_exceptions` in `nac3core/src/codegen/irrt/mod.rs`.
|
||||||
|
* All exception IDs are initialized by `setup_irrt_exceptions`.
|
||||||
|
*/
|
||||||
|
#ifdef IRRT_TESTING
|
||||||
|
// If we are doing IRRT tests (i.e., running `cargo test -F test`), define them with a fake set of IDs.
|
||||||
|
ExceptionId EXN_INDEX_ERROR = 0;
|
||||||
|
ExceptionId EXN_VALUE_ERROR = 1;
|
||||||
|
ExceptionId EXN_ASSERTION_ERROR = 2;
|
||||||
|
ExceptionId EXN_RUNTIME_ERROR = 3;
|
||||||
|
ExceptionId EXN_TYPE_ERROR = 4;
|
||||||
|
#else
|
||||||
|
extern "C" {
|
||||||
|
ExceptionId EXN_INDEX_ERROR;
|
||||||
|
ExceptionId EXN_VALUE_ERROR;
|
||||||
|
ExceptionId EXN_ASSERTION_ERROR;
|
||||||
|
ExceptionId EXN_RUNTIME_ERROR;
|
||||||
|
ExceptionId EXN_TYPE_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/**
|
||||||
|
* @brief NAC3's Exception struct
|
||||||
|
*/
|
||||||
|
template <typename SizeT>
|
||||||
|
struct Exception {
|
||||||
|
ExceptionId id;
|
||||||
|
CSlice<SizeT> filename;
|
||||||
|
int32_t line;
|
||||||
|
int32_t column;
|
||||||
|
CSlice<SizeT> function;
|
||||||
|
CSlice<SizeT> msg;
|
||||||
|
int64_t params[3];
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Declare/Define `__nac3_raise`
|
||||||
|
#ifdef IRRT_TESTING
|
||||||
|
#include <cstdio>
|
||||||
|
void __nac3_raise(void* err) {
|
||||||
|
// TODO: Print the error content?
|
||||||
|
printf("__nac3_raise called. Exiting...\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/**
|
||||||
|
* @brief Extern function to `__nac3_raise`
|
||||||
|
*
|
||||||
|
* The parameter `err` could be `Exception<int32_t>` or `Exception<int64_t>`. The caller
|
||||||
|
* must make sure to pass `Exception`s with the correct `SizeT` depending on the `size_t` of the runtime.
|
||||||
|
*/
|
||||||
|
extern "C" void __nac3_raise(void* err);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const int64_t NO_PARAM = 0;
|
||||||
|
|
||||||
|
// Helper function to raise an exception with `__nac3_raise`
|
||||||
|
// Do not use this function directly. See `raise_exception`.
|
||||||
|
template <typename SizeT>
|
||||||
|
void _raise_exception_helper(ExceptionId id, const char* filename, int32_t line,
|
||||||
|
const char* function, const char* msg,
|
||||||
|
int64_t param0, int64_t param1, int64_t param2) {
|
||||||
|
Exception<SizeT> e = {
|
||||||
|
.id = id,
|
||||||
|
.filename = {.base = (uint8_t*)filename,
|
||||||
|
.len = (int32_t)cstr_utils::length(filename)},
|
||||||
|
.line = line,
|
||||||
|
.column = 0,
|
||||||
|
.function = {.base = (uint8_t*)function,
|
||||||
|
.len = (int32_t)cstr_utils::length(function)},
|
||||||
|
.msg = {.base = (uint8_t*)msg, .len = (int32_t)cstr_utils::length(msg)},
|
||||||
|
};
|
||||||
|
e.params[0] = param0;
|
||||||
|
e.params[1] = param1;
|
||||||
|
e.params[2] = param2;
|
||||||
|
__nac3_raise((void*)&e);
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Raise an exception with location details (location in the IRRT source files).
|
||||||
|
* @param SizeT The runtime `size_t` type.
|
||||||
|
* @param id The ID of the exception to raise.
|
||||||
|
* @param msg A global constant C-string of the error message.
|
||||||
|
*
|
||||||
|
* `param0` and `param2` are optional format arguments of `msg`. They should be set to
|
||||||
|
* `NO_PARAM` to indicate they are unused.
|
||||||
|
*/
|
||||||
|
#define raise_exception(SizeT, id, msg, param0, param1, param2) \
|
||||||
|
_raise_exception_helper<SizeT>(id, __FILE__, __LINE__, __FUNCTION__, msg, \
|
||||||
|
param0, param1, param2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Throw a dummy error for testing.
|
||||||
|
*/
|
||||||
|
template <typename SizeT>
|
||||||
|
void throw_dummy_error() {
|
||||||
|
raise_exception(SizeT, EXN_RUNTIME_ERROR, "dummy error", NO_PARAM, NO_PARAM,
|
||||||
|
NO_PARAM);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void __nac3_throw_dummy_error() { throw_dummy_error<int32_t>(); }
|
||||||
|
|
||||||
|
void __nac3_throw_dummy_error64() { throw_dummy_error<int64_t>(); }
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <irrt/core.hpp>
|
#include <irrt/core.hpp>
|
||||||
|
#include <irrt/exception.hpp>
|
||||||
#include <irrt/int_defs.hpp>
|
#include <irrt/int_defs.hpp>
|
||||||
#include <irrt/util.hpp>
|
#include <irrt/util.hpp>
|
|
@ -1,9 +1,15 @@
|
||||||
// This file will be compiled like a real C++ program,
|
// This file will be compiled like a real C++ program,
|
||||||
// and we do have the luxury to use the standard libraries.
|
// and we do have the luxury to use the standard libraries.
|
||||||
// That is if the nix flakes do not have issues... especially on msys2...
|
// That is if the nix flakes do not have issues... especially on msys2...
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
// Special macro to inform `#include <irrt/*>` that we
|
||||||
|
// are testing.
|
||||||
|
#define IRRT_TESTING
|
||||||
|
|
||||||
#include <test/test_core.hpp>
|
#include <test/test_core.hpp>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
use crate::symbol_resolver::SymbolResolver;
|
||||||
use crate::typecheck::typedef::Type;
|
use crate::typecheck::typedef::Type;
|
||||||
|
|
||||||
mod test;
|
mod test;
|
||||||
|
pub mod util;
|
||||||
|
|
||||||
use super::model::*;
|
use super::model::*;
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -12,6 +14,7 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::codegen::classes::TypedArrayLikeAccessor;
|
use crate::codegen::classes::TypedArrayLikeAccessor;
|
||||||
use crate::codegen::stmt::gen_for_callback_incrementing;
|
use crate::codegen::stmt::gen_for_callback_incrementing;
|
||||||
|
use inkwell::values::BasicValue;
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
attributes::{Attribute, AttributeLoc},
|
attributes::{Attribute, AttributeLoc},
|
||||||
context::Context,
|
context::Context,
|
||||||
|
@ -23,6 +26,8 @@ use inkwell::{
|
||||||
};
|
};
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
use nac3parser::ast::Expr;
|
use nac3parser::ast::Expr;
|
||||||
|
use util::function::CallFunction;
|
||||||
|
use util::get_sizet_dependent_function_name;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn load_irrt(ctx: &Context) -> Module {
|
pub fn load_irrt(ctx: &Context) -> Module {
|
||||||
|
@ -946,3 +951,39 @@ pub fn call_ndarray_calc_broadcast_index<
|
||||||
Box::new(|_, v| v.into()),
|
Box::new(|_, v| v.into()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn call_nac3_throw_dummy_error<'ctx>(tyctx: TypeContext<'ctx>, ctx: &CodeGenContext<'ctx, '_>) {
|
||||||
|
CallFunction::begin(
|
||||||
|
tyctx,
|
||||||
|
ctx,
|
||||||
|
&get_sizet_dependent_function_name(tyctx, "__nac3_throw_dummy_error"),
|
||||||
|
)
|
||||||
|
.returning_void();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize all global `EXN_*` exception IDs in IRRT with the [`SymbolResolver`].
|
||||||
|
pub fn setup_irrt_exceptions<'ctx>(
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
module: &Module<'ctx>,
|
||||||
|
symbol_resolver: &dyn SymbolResolver,
|
||||||
|
) {
|
||||||
|
let exn_id_type = ctx.i32_type();
|
||||||
|
|
||||||
|
let errors = &[
|
||||||
|
("EXN_INDEX_ERROR", "0:IndexError"),
|
||||||
|
("EXN_VALUE_ERROR", "0:ValueError"),
|
||||||
|
("EXN_ASSERTION_ERROR", "0:AssertionError"),
|
||||||
|
("EXN_RUNTIME_ERROR", "0:RuntimeError"),
|
||||||
|
("EXN_TYPE_ERROR", "0:TypeError"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (irrt_name, symbol_name) in errors {
|
||||||
|
let exn_id = symbol_resolver.get_string_id(symbol_name);
|
||||||
|
let exn_id = exn_id_type.const_int(exn_id as u64, false).as_basic_value_enum();
|
||||||
|
|
||||||
|
let global = module.get_global(irrt_name).unwrap_or_else(|| {
|
||||||
|
panic!("Exception symbol name '{irrt_name}' should exist in the IRRT LLVM module")
|
||||||
|
});
|
||||||
|
global.set_initializer(&exn_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
use crate::codegen::model::*;
|
||||||
|
|
||||||
|
// When [`TypeContext::size_type`] is 32-bits, the function name is "{fn_name}".
|
||||||
|
// When [`TypeContext::size_type`] is 64-bits, the function name is "{fn_name}64".
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_sizet_dependent_function_name(tyctx: TypeContext<'_>, name: &str) -> String {
|
||||||
|
let mut name = name.to_owned();
|
||||||
|
match tyctx.size_type.get_bit_width() {
|
||||||
|
32 => {}
|
||||||
|
64 => name.push_str("64"),
|
||||||
|
bit_width => {
|
||||||
|
panic!("Unsupported int type bit width {bit_width}, must be either 32-bits or 64-bits")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod function {
|
||||||
|
use crate::codegen::{model::*, CodeGenContext};
|
||||||
|
use inkwell::{
|
||||||
|
types::{BasicMetadataTypeEnum, BasicType, FunctionType},
|
||||||
|
values::{AnyValue, BasicMetadataValueEnum, BasicValue, BasicValueEnum, CallSiteValue},
|
||||||
|
};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Arg<'ctx> {
|
||||||
|
ty: BasicMetadataTypeEnum<'ctx>,
|
||||||
|
val: BasicMetadataValueEnum<'ctx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper structure to reduce IRRT Inkwell function call boilerplate
|
||||||
|
pub struct CallFunction<'ctx, 'a, 'b, 'c> {
|
||||||
|
tyctx: TypeContext<'ctx>,
|
||||||
|
ctx: &'b CodeGenContext<'ctx, 'a>,
|
||||||
|
/// Function name
|
||||||
|
name: &'c str,
|
||||||
|
/// Call arguments
|
||||||
|
args: Vec<Arg<'ctx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, 'a, 'b, 'c> CallFunction<'ctx, 'a, 'b, 'c> {
|
||||||
|
pub fn begin(
|
||||||
|
tyctx: TypeContext<'ctx>,
|
||||||
|
ctx: &'b CodeGenContext<'ctx, 'a>,
|
||||||
|
name: &'c str,
|
||||||
|
) -> Self {
|
||||||
|
CallFunction { tyctx, ctx, name, args: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Push a call argument to the function call.
|
||||||
|
///
|
||||||
|
/// The `_name` parameter is there for self-documentation purposes.
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn arg<M: Model<'ctx>>(mut self, _name: &str, arg: Instance<'ctx, M>) -> Self {
|
||||||
|
let arg = Arg {
|
||||||
|
ty: arg.model.get_type(self.tyctx, self.ctx.ctx).as_basic_type_enum().into(),
|
||||||
|
val: arg.value.as_basic_value_enum().into(),
|
||||||
|
};
|
||||||
|
self.args.push(arg);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call the function and expect the function to return a value of type of `return_model`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn returning<M: Model<'ctx>>(self, name: &str, return_model: M) -> Instance<'ctx, M> {
|
||||||
|
let ret_ty = return_model.get_type(self.tyctx, self.ctx.ctx);
|
||||||
|
|
||||||
|
let ret = self.get_function(|tys| ret_ty.fn_type(tys, false), name);
|
||||||
|
let ret = BasicValueEnum::try_from(ret.as_any_value_enum()).unwrap(); // Must work
|
||||||
|
let ret = return_model.check_value(self.tyctx, self.ctx.ctx, ret).unwrap(); // Must work
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like [`CallFunction::returning_`] but `return_model` is automatically inferred.
|
||||||
|
#[must_use]
|
||||||
|
pub fn returning_auto<M: Model<'ctx> + Default>(self, name: &str) -> Instance<'ctx, M> {
|
||||||
|
self.returning(name, M::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call the function and expect the function to return a void-type.
|
||||||
|
pub fn returning_void(self) {
|
||||||
|
let ret_ty = self.ctx.ctx.void_type();
|
||||||
|
|
||||||
|
let _ = self.get_function(|tys| ret_ty.fn_type(tys, false), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_function<F>(&self, make_fn_type: F, return_value_name: &str) -> CallSiteValue<'ctx>
|
||||||
|
where
|
||||||
|
F: FnOnce(&[BasicMetadataTypeEnum<'ctx>]) -> FunctionType<'ctx>,
|
||||||
|
{
|
||||||
|
// Get the LLVM function, declare the function if it doesn't exist - it will be defined by other
|
||||||
|
// components of NAC3.
|
||||||
|
let func = self.ctx.module.get_function(self.name).unwrap_or_else(|| {
|
||||||
|
let tys = self.args.iter().map(|arg| arg.ty).collect_vec();
|
||||||
|
let fn_type = make_fn_type(&tys);
|
||||||
|
self.ctx.module.add_function(self.name, fn_type, None)
|
||||||
|
});
|
||||||
|
|
||||||
|
let vals = self.args.iter().map(|arg| arg.val).collect_vec();
|
||||||
|
self.ctx.builder.build_call(func, &vals, return_value_name).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ use inkwell::{
|
||||||
memory_buffer::MemoryBuffer, passes::PassBuilderOptions, support::is_multithreaded, targets::*,
|
memory_buffer::MemoryBuffer, passes::PassBuilderOptions, support::is_multithreaded, targets::*,
|
||||||
OptimizationLevel,
|
OptimizationLevel,
|
||||||
};
|
};
|
||||||
|
use nac3core::codegen::irrt::setup_irrt_exceptions;
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::{
|
codegen::{
|
||||||
concrete_type::ConcreteTypeStore, irrt::load_irrt, CodeGenLLVMOptions,
|
concrete_type::ConcreteTypeStore, irrt::load_irrt, CodeGenLLVMOptions,
|
||||||
|
@ -314,6 +315,16 @@ fn main() {
|
||||||
let resolver =
|
let resolver =
|
||||||
Arc::new(Resolver(internal_resolver.clone())) as Arc<dyn SymbolResolver + Send + Sync>;
|
Arc::new(Resolver(internal_resolver.clone())) as Arc<dyn SymbolResolver + Send + Sync>;
|
||||||
|
|
||||||
|
let context = inkwell::context::Context::create();
|
||||||
|
|
||||||
|
// Process IRRT
|
||||||
|
let irrt = load_irrt(&context);
|
||||||
|
setup_irrt_exceptions(&context, &irrt, resolver.as_ref());
|
||||||
|
if emit_llvm {
|
||||||
|
irrt.write_bitcode_to_path(Path::new("irrt.bc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the Python script
|
||||||
let parser_result = parser::parse_program(&program, file_name.into()).unwrap();
|
let parser_result = parser::parse_program(&program, file_name.into()).unwrap();
|
||||||
|
|
||||||
for stmt in parser_result {
|
for stmt in parser_result {
|
||||||
|
@ -418,8 +429,8 @@ fn main() {
|
||||||
registry.add_task(task);
|
registry.add_task(task);
|
||||||
registry.wait_tasks_complete(handles);
|
registry.wait_tasks_complete(handles);
|
||||||
|
|
||||||
|
// Link all modules together into `main`
|
||||||
let buffers = membuffers.lock();
|
let buffers = membuffers.lock();
|
||||||
let context = inkwell::context::Context::create();
|
|
||||||
let main = context
|
let main = context
|
||||||
.create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main"))
|
.create_module_from_ir(MemoryBuffer::create_from_memory_range(&buffers[0], "main"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -439,12 +450,9 @@ fn main() {
|
||||||
main.link_in_module(other).unwrap();
|
main.link_in_module(other).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let irrt = load_irrt(&context);
|
|
||||||
if emit_llvm {
|
|
||||||
irrt.write_bitcode_to_path(Path::new("irrt.bc"));
|
|
||||||
}
|
|
||||||
main.link_in_module(irrt).unwrap();
|
main.link_in_module(irrt).unwrap();
|
||||||
|
|
||||||
|
// Private all functions except "run"
|
||||||
let mut function_iter = main.get_first_function();
|
let mut function_iter = main.get_first_function();
|
||||||
while let Some(func) = function_iter {
|
while let Some(func) = function_iter {
|
||||||
if func.count_basic_blocks() > 0 && func.get_name().to_str().unwrap() != "run" {
|
if func.count_basic_blocks() > 0 && func.get_name().to_str().unwrap() != "run" {
|
||||||
|
@ -453,6 +461,7 @@ fn main() {
|
||||||
function_iter = func.get_next_function();
|
function_iter = func.get_next_function();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optimize `main`
|
||||||
let target_machine = llvm_options
|
let target_machine = llvm_options
|
||||||
.target
|
.target
|
||||||
.create_target_machine(llvm_options.opt_level)
|
.create_target_machine(llvm_options.opt_level)
|
||||||
|
@ -466,6 +475,7 @@ fn main() {
|
||||||
panic!("Failed to run optimization for module `main`: {}", err.to_string());
|
panic!("Failed to run optimization for module `main`: {}", err.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write output
|
||||||
target_machine
|
target_machine
|
||||||
.write_to_file(&main, FileType::Object, Path::new("module.o"))
|
.write_to_file(&main, FileType::Object, Path::new("module.o"))
|
||||||
.expect("couldn't write module to file");
|
.expect("couldn't write module to file");
|
||||||
|
|
Loading…
Reference in New Issue