Compare commits
12 Commits
45665e2d49
...
e053872b10
Author | SHA1 | Date |
---|---|---|
|
e053872b10 | |
|
53d44b9595 | |
|
6153f94b05 | |
|
4730b595f3 | |
|
c2fdb12397 | |
|
82bf14785b | |
|
2d4329e23c | |
|
679656f9e1 | |
|
210d9e2334 | |
|
181ac3ec1a | |
|
3acdfb304d | |
|
6e24da9cc5 |
|
@ -56,9 +56,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.3"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
|
||||
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
@ -117,9 +117,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.98"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
|
||||
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -129,9 +129,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.4"
|
||||
version = "4.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
|
||||
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -139,9 +139,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.2"
|
||||
version = "4.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
|
||||
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -151,9 +151,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.4"
|
||||
version = "4.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
|
||||
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
|
@ -163,9 +163,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
|
@ -945,9 +945,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.4"
|
||||
version = "1.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -957,9 +957,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.6"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -968,9 +968,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
|
||||
[[package]]
|
||||
name = "runkernel"
|
||||
|
@ -1269,9 +1269,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.12"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
|
||||
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
|
@ -1309,9 +1309,9 @@ checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
|
|||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
|
|
|
@ -28,8 +28,9 @@ use pyo3::create_exception;
|
|||
use parking_lot::{Mutex, RwLock};
|
||||
|
||||
use nac3core::{
|
||||
codegen::irrt::load_irrt,
|
||||
codegen::{concrete_type::ConcreteTypeStore, CodeGenTask, WithCall, WorkerRegistry},
|
||||
codegen::irrt::load_irrt,
|
||||
codegen::tracert::TraceRuntimeConfig,
|
||||
symbol_resolver::SymbolResolver,
|
||||
toplevel::{
|
||||
composer::{ComposerConfig, TopLevelComposer},
|
||||
|
@ -608,6 +609,7 @@ impl Nac3 {
|
|||
threads,
|
||||
top_level.clone(),
|
||||
&self.llvm_options,
|
||||
&TraceRuntimeConfig::default(),
|
||||
&f
|
||||
);
|
||||
registry.add_task(task);
|
||||
|
|
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
|||
authors = ["M-Labs"]
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
tracing = []
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.13"
|
||||
crossbeam = "0.8"
|
||||
|
@ -23,4 +26,5 @@ indoc = "2.0"
|
|||
insta = "=1.11.0"
|
||||
|
||||
[build-dependencies]
|
||||
itertools = "0.13"
|
||||
regex = "1.10"
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use regex::Regex;
|
||||
use std::{
|
||||
env,
|
||||
fs::File,
|
||||
|
@ -6,17 +5,29 @@ use std::{
|
|||
path::Path,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
use std::ffi::OsStr;
|
||||
|
||||
fn main() {
|
||||
const FILE: &str = "src/codegen/irrt/irrt.c";
|
||||
use itertools::Itertools;
|
||||
use regex::Regex;
|
||||
|
||||
/// Extracts the extension-less filename from a [`Path`].
|
||||
fn path_to_extless_filename(path: &Path) -> &str {
|
||||
path.file_name()
|
||||
.map(Path::new)
|
||||
.and_then(Path::file_stem)
|
||||
.and_then(OsStr::to_str)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Compiles a source C file into LLVM bitcode.
|
||||
fn compile_file_to_ir(path: &Path, filename_without_ext: &str) {
|
||||
/*
|
||||
* HACK: Sadly, clang doesn't let us emit generic LLVM bitcode.
|
||||
* Compiling for WASM32 and filtering the output with regex is the closest we can get.
|
||||
*/
|
||||
let flags: &[&str] = &[
|
||||
"--target=wasm32",
|
||||
FILE,
|
||||
path.to_str().unwrap(),
|
||||
"-fno-discard-value-names",
|
||||
match env::var("PROFILE").as_deref() {
|
||||
Ok("debug") => "-O0",
|
||||
|
@ -31,7 +42,7 @@ fn main() {
|
|||
"-",
|
||||
];
|
||||
|
||||
println!("cargo:rerun-if-changed={FILE}");
|
||||
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
let out_path = Path::new(&out_dir);
|
||||
|
||||
|
@ -44,8 +55,7 @@ fn main() {
|
|||
})
|
||||
.unwrap();
|
||||
|
||||
// https://github.com/rust-lang/regex/issues/244
|
||||
let output = std::str::from_utf8(&output.stdout).unwrap().replace("\r\n", "\n");
|
||||
let output = std::str::from_utf8(&output.stdout).unwrap();
|
||||
let mut filtered_output = String::with_capacity(output.len());
|
||||
|
||||
let regex_filter = Regex::new(r"(?ms:^define.*?\}$)|(?m:^declare.*?$)").unwrap();
|
||||
|
@ -61,18 +71,36 @@ fn main() {
|
|||
|
||||
println!("cargo:rerun-if-env-changed=DEBUG_DUMP_IRRT");
|
||||
if env::var("DEBUG_DUMP_IRRT").is_ok() {
|
||||
let mut file = File::create(out_path.join("irrt.ll")).unwrap();
|
||||
let mut file = File::create(out_path.join(format!("{filename_without_ext}.ll"))).unwrap();
|
||||
file.write_all(output.as_bytes()).unwrap();
|
||||
let mut file = File::create(out_path.join("irrt-filtered.ll")).unwrap();
|
||||
let mut file = File::create(out_path.join(format!("{filename_without_ext}-filtered.ll"))).unwrap();
|
||||
file.write_all(filtered_output.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
let mut llvm_as = Command::new("llvm-as-irrt")
|
||||
.stdin(Stdio::piped())
|
||||
.arg("-o")
|
||||
.arg(out_path.join("irrt.bc"))
|
||||
.arg(out_path.join(format!("{filename_without_ext}.bc")))
|
||||
.spawn()
|
||||
.unwrap();
|
||||
llvm_as.stdin.as_mut().unwrap().write_all(filtered_output.as_bytes()).unwrap();
|
||||
assert!(llvm_as.wait().unwrap().success());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
const IRRT_SOURCE_PATHS: &[&str] = &[
|
||||
"src/codegen/irrt/irrt.c",
|
||||
"src/codegen/tracert/tracert.c",
|
||||
];
|
||||
|
||||
assert!(IRRT_SOURCE_PATHS.iter()
|
||||
.map(Path::new)
|
||||
.map(path_to_extless_filename)
|
||||
.all_unique());
|
||||
|
||||
for path in IRRT_SOURCE_PATHS {
|
||||
let path = Path::new(path);
|
||||
|
||||
compile_file_to_ir(path, path_to_extless_filename(path))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use inkwell::{
|
||||
IntPredicate,
|
||||
AddressSpace, IntPredicate,
|
||||
types::{AnyTypeEnum, BasicTypeEnum, IntType, PointerType},
|
||||
values::{BasicValueEnum, IntValue, PointerValue},
|
||||
};
|
||||
use inkwell::types::BasicType;
|
||||
use inkwell::values::BasicValue;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::types::{ArrayType, BasicType, StructType};
|
||||
use inkwell::values::{ArrayValue, BasicValue, StructValue};
|
||||
use crate::codegen::{
|
||||
CodeGenContext,
|
||||
CodeGenerator,
|
||||
|
@ -14,13 +15,39 @@ use crate::codegen::{
|
|||
};
|
||||
|
||||
/// A LLVM type that is used to represent a non-primitive type in NAC3.
|
||||
pub trait ProxyType<'ctx> {
|
||||
/// The underlying type as represented by an LLVM type.
|
||||
pub trait ProxyType<'ctx>: Into<Self::Base> {
|
||||
/// The LLVM type of which values of this type possess. This is usually a
|
||||
/// [LLVM pointer type][PointerType].
|
||||
type Base: BasicType<'ctx>;
|
||||
|
||||
/// The underlying LLVM type used to represent values. This is usually the element type of
|
||||
/// [`Base`] if it is a pointer, otherwise this is the same type as `Base`.
|
||||
type Underlying: BasicType<'ctx>;
|
||||
|
||||
/// The type of values represented by this type.
|
||||
type Value: ProxyValue<'ctx>;
|
||||
|
||||
/// Creates a new value of this type.
|
||||
fn new_value<G: CodeGenerator + ?Sized>(
|
||||
&self,
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
name: Option<&'ctx str>,
|
||||
) -> Self::Value;
|
||||
|
||||
/// Creates a new array value of this type.
|
||||
fn new_array_value<G: CodeGenerator + ?Sized>(
|
||||
&self,
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
size: IntValue<'ctx>,
|
||||
name: Option<&'ctx str>,
|
||||
) -> ArraySliceValue<'ctx> {
|
||||
generator
|
||||
.gen_array_var_alloc(ctx, self.as_underlying_type().as_basic_type_enum(), size, name)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Creates a [`value`][ProxyValue] with this as its type.
|
||||
fn create_value(
|
||||
&self,
|
||||
|
@ -28,23 +55,39 @@ pub trait ProxyType<'ctx> {
|
|||
name: Option<&'ctx str>,
|
||||
) -> Self::Value;
|
||||
|
||||
/// Returns the base type of this proxy.
|
||||
/// Returns the [base type][Self::Base] of this proxy.
|
||||
fn as_base_type(&self) -> Self::Base;
|
||||
|
||||
/// Returns the [underlying type][Self::Underlying] of this proxy.
|
||||
fn as_underlying_type(&self) -> Self::Underlying;
|
||||
}
|
||||
|
||||
/// A LLVM type that is used to represent a non-primitive value in NAC3.
|
||||
pub trait ProxyValue<'ctx> {
|
||||
/// The underlying type as represented by an LLVM value.
|
||||
pub trait ProxyValue<'ctx>: Into<Self::Base> {
|
||||
/// The type of LLVM values represented by this instance. This is usually the
|
||||
/// [LLVM pointer type][PointerValue].
|
||||
type Base: BasicValue<'ctx>;
|
||||
|
||||
/// The underlying type of LLVM values represented by this instance. This is usually the element
|
||||
/// type of [`Base`] if it is a pointer, otherwise this is the same type as `Base`.
|
||||
type Underlying: BasicValue<'ctx>;
|
||||
|
||||
/// The type of this value.
|
||||
type Type: ProxyType<'ctx>;
|
||||
|
||||
/// Returns the [type][ProxyType] of this value.
|
||||
fn get_type(&self) -> Self::Type;
|
||||
|
||||
/// Returns the base value of this proxy.
|
||||
/// Returns the [base value][Self::Base] of this proxy.
|
||||
fn as_base_value(&self) -> Self::Base;
|
||||
|
||||
/// Loads this value into its [underlying representation][Self::Underlying]. Usually involves a
|
||||
/// `getelementptr` if [`Self::Base`] is a [pointer value][PointerValue].
|
||||
fn as_underlying_value(
|
||||
&self,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
name: Option<&'ctx str>,
|
||||
) -> Self::Underlying;
|
||||
}
|
||||
|
||||
/// An LLVM value that is array-like, i.e. it contains a contiguous, sequenced collection of
|
||||
|
@ -463,6 +506,27 @@ impl<'ctx> ListType<'ctx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates an instance of [`ListType`].
|
||||
#[must_use]
|
||||
pub fn new<G: CodeGenerator + ?Sized>(
|
||||
generator: &G,
|
||||
ctx: &'ctx Context,
|
||||
element_type: BasicTypeEnum<'ctx>,
|
||||
) -> Self {
|
||||
let llvm_usize = generator.get_size_type(ctx);
|
||||
let llvm_list = ctx
|
||||
.struct_type(
|
||||
&[
|
||||
element_type.ptr_type(AddressSpace::default()).into(),
|
||||
llvm_usize.into(),
|
||||
],
|
||||
false,
|
||||
)
|
||||
.ptr_type(AddressSpace::default());
|
||||
|
||||
ListType::from_type(llvm_list, llvm_usize)
|
||||
}
|
||||
|
||||
/// Creates an [`ListType`] from a [`PointerType`].
|
||||
#[must_use]
|
||||
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||
|
@ -477,26 +541,41 @@ impl<'ctx> ListType<'ctx> {
|
|||
self.as_base_type()
|
||||
.get_element_type()
|
||||
.into_struct_type()
|
||||
.get_field_type_at_index(0)
|
||||
.get_field_type_at_index(1)
|
||||
.map(BasicTypeEnum::into_int_type)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Returns the element type of this `list` type.
|
||||
#[must_use]
|
||||
pub fn element_type(&self) -> BasicTypeEnum<'ctx> {
|
||||
pub fn element_type(&self) -> AnyTypeEnum<'ctx> {
|
||||
self.as_base_type()
|
||||
.get_element_type()
|
||||
.into_struct_type()
|
||||
.get_field_type_at_index(1)
|
||||
.get_field_type_at_index(0)
|
||||
.map(BasicTypeEnum::into_pointer_type)
|
||||
.map(PointerType::get_element_type)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> ProxyType<'ctx> for ListType<'ctx> {
|
||||
type Base = PointerType<'ctx>;
|
||||
type Underlying = StructType<'ctx>;
|
||||
type Value = ListValue<'ctx>;
|
||||
|
||||
fn new_value<G: CodeGenerator + ?Sized>(
|
||||
&self,
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
name: Option<&'ctx str>,
|
||||
) -> Self::Value {
|
||||
self.create_value(
|
||||
generator.gen_var_alloc(ctx, self.as_underlying_type().into(), name).unwrap(),
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
fn create_value(
|
||||
&self,
|
||||
value: <Self::Value as ProxyValue<'ctx>>::Base,
|
||||
|
@ -510,6 +589,10 @@ impl<'ctx> ProxyType<'ctx> for ListType<'ctx> {
|
|||
fn as_base_type(&self) -> Self::Base {
|
||||
self.ty
|
||||
}
|
||||
|
||||
fn as_underlying_type(&self) -> Self::Underlying {
|
||||
self.as_base_type().get_element_type().into_struct_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> From<ListType<'ctx>> for PointerType<'ctx> {
|
||||
|
@ -629,6 +712,7 @@ impl<'ctx> ListValue<'ctx> {
|
|||
|
||||
impl<'ctx> ProxyValue<'ctx> for ListValue<'ctx> {
|
||||
type Base = PointerValue<'ctx>;
|
||||
type Underlying = StructValue<'ctx>;
|
||||
type Type = ListType<'ctx>;
|
||||
|
||||
fn get_type(&self) -> Self::Type {
|
||||
|
@ -638,6 +722,17 @@ impl<'ctx> ProxyValue<'ctx> for ListValue<'ctx> {
|
|||
fn as_base_value(&self) -> Self::Base {
|
||||
self.value
|
||||
}
|
||||
|
||||
fn as_underlying_value(
|
||||
&self,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
name: Option<&'ctx str>,
|
||||
) -> Self::Underlying {
|
||||
ctx.builder
|
||||
.build_load(self.as_base_value(), name.unwrap_or_default())
|
||||
.map(BasicValueEnum::into_struct_value)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> From<ListValue<'ctx>> for PointerValue<'ctx> {
|
||||
|
@ -757,6 +852,15 @@ impl<'ctx> RangeType<'ctx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates an instance of [`RangeType`].
|
||||
#[must_use]
|
||||
pub fn new(ctx: &'ctx Context) -> Self {
|
||||
let llvm_i32 = ctx.i32_type();
|
||||
let llvm_range = llvm_i32.array_type(3).ptr_type(AddressSpace::default());
|
||||
|
||||
RangeType::from_type(llvm_range)
|
||||
}
|
||||
|
||||
/// Creates an [`RangeType`] from a [`PointerType`].
|
||||
#[must_use]
|
||||
pub fn from_type(ptr_ty: PointerType<'ctx>) -> Self {
|
||||
|
@ -778,8 +882,21 @@ impl<'ctx> RangeType<'ctx> {
|
|||
|
||||
impl<'ctx> ProxyType<'ctx> for RangeType<'ctx> {
|
||||
type Base = PointerType<'ctx>;
|
||||
type Underlying = ArrayType<'ctx>;
|
||||
type Value = RangeValue<'ctx>;
|
||||
|
||||
fn new_value<G: CodeGenerator + ?Sized>(
|
||||
&self,
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
name: Option<&'ctx str>,
|
||||
) -> Self::Value {
|
||||
self.create_value(
|
||||
generator.gen_var_alloc(ctx, self.as_underlying_type().into(), name).unwrap(),
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
fn create_value(&self, value: <Self::Value as ProxyValue<'ctx>>::Base, name: Option<&'ctx str>) -> Self::Value {
|
||||
debug_assert_eq!(value.get_type(), self.as_base_type());
|
||||
|
||||
|
@ -789,6 +906,10 @@ impl<'ctx> ProxyType<'ctx> for RangeType<'ctx> {
|
|||
fn as_base_type(&self) -> Self::Base {
|
||||
self.ty
|
||||
}
|
||||
|
||||
fn as_underlying_type(&self) -> Self::Underlying {
|
||||
self.as_base_type().get_element_type().into_array_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> From<RangeType<'ctx>> for PointerType<'ctx> {
|
||||
|
@ -890,7 +1011,7 @@ impl<'ctx> RangeValue<'ctx> {
|
|||
) {
|
||||
debug_assert_eq!(end.get_type().get_bit_width(), 32);
|
||||
|
||||
let pend = self.ptr_to_start(ctx);
|
||||
let pend = self.ptr_to_end(ctx);
|
||||
ctx.builder.build_store(pend, end).unwrap();
|
||||
}
|
||||
|
||||
|
@ -915,7 +1036,7 @@ impl<'ctx> RangeValue<'ctx> {
|
|||
) {
|
||||
debug_assert_eq!(step.get_type().get_bit_width(), 32);
|
||||
|
||||
let pstep = self.ptr_to_start(ctx);
|
||||
let pstep = self.ptr_to_step(ctx);
|
||||
ctx.builder.build_store(pstep, step).unwrap();
|
||||
}
|
||||
|
||||
|
@ -935,6 +1056,7 @@ impl<'ctx> RangeValue<'ctx> {
|
|||
|
||||
impl<'ctx> ProxyValue<'ctx> for RangeValue<'ctx> {
|
||||
type Base = PointerValue<'ctx>;
|
||||
type Underlying = ArrayValue<'ctx>;
|
||||
type Type = RangeType<'ctx>;
|
||||
|
||||
fn get_type(&self) -> Self::Type {
|
||||
|
@ -944,6 +1066,17 @@ impl<'ctx> ProxyValue<'ctx> for RangeValue<'ctx> {
|
|||
fn as_base_value(&self) -> Self::Base {
|
||||
self.value
|
||||
}
|
||||
|
||||
fn as_underlying_value(
|
||||
&self,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
name: Option<&'ctx str>,
|
||||
) -> Self::Underlying {
|
||||
ctx.builder
|
||||
.build_load(self.as_base_value(), name.unwrap_or_default())
|
||||
.map(BasicValueEnum::into_array_value)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> From<RangeValue<'ctx>> for PointerValue<'ctx> {
|
||||
|
@ -1005,6 +1138,34 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates an instance of [`ListType`].
|
||||
#[must_use]
|
||||
pub fn new<G: CodeGenerator + ?Sized>(
|
||||
generator: &G,
|
||||
ctx: &'ctx Context,
|
||||
dtype: BasicTypeEnum<'ctx>,
|
||||
) -> Self {
|
||||
let llvm_usize = generator.get_size_type(ctx);
|
||||
|
||||
// struct NDArray { num_dims: size_t, dims: size_t*, data: T* }
|
||||
//
|
||||
// * num_dims: Number of dimensions in the array
|
||||
// * dims: Pointer to an array containing the size of each dimension
|
||||
// * data: Pointer to an array containing the array data
|
||||
let llvm_ndarray = ctx
|
||||
.struct_type(
|
||||
&[
|
||||
llvm_usize.into(),
|
||||
llvm_usize.ptr_type(AddressSpace::default()).into(),
|
||||
dtype.ptr_type(AddressSpace::default()).into(),
|
||||
],
|
||||
false,
|
||||
)
|
||||
.ptr_type(AddressSpace::default());
|
||||
|
||||
NDArrayType::from_type(llvm_ndarray, llvm_usize)
|
||||
}
|
||||
|
||||
/// Creates an [`NDArrayType`] from a [`PointerType`].
|
||||
#[must_use]
|
||||
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||
|
@ -1037,8 +1198,23 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||
|
||||
impl<'ctx> ProxyType<'ctx> for NDArrayType<'ctx> {
|
||||
type Base = PointerType<'ctx>;
|
||||
type Underlying = StructType<'ctx>;
|
||||
type Value = NDArrayValue<'ctx>;
|
||||
|
||||
fn new_value<G: CodeGenerator + ?Sized>(
|
||||
&self,
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
name: Option<&'ctx str>,
|
||||
) -> Self::Value {
|
||||
self.create_value(
|
||||
generator
|
||||
.gen_var_alloc(ctx, self.as_underlying_type().into(), name)
|
||||
.unwrap(),
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
fn create_value(
|
||||
&self,
|
||||
value: <Self::Value as ProxyValue<'ctx>>::Base,
|
||||
|
@ -1052,6 +1228,10 @@ impl<'ctx> ProxyType<'ctx> for NDArrayType<'ctx> {
|
|||
fn as_base_type(&self) -> Self::Base {
|
||||
self.ty
|
||||
}
|
||||
|
||||
fn as_underlying_type(&self) -> Self::Underlying {
|
||||
self.as_base_type().get_element_type().into_struct_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> From<NDArrayType<'ctx>> for PointerType<'ctx> {
|
||||
|
@ -1198,6 +1378,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||
|
||||
impl<'ctx> ProxyValue<'ctx> for NDArrayValue<'ctx> {
|
||||
type Base = PointerValue<'ctx>;
|
||||
type Underlying = StructValue<'ctx>;
|
||||
type Type = NDArrayType<'ctx>;
|
||||
|
||||
fn get_type(&self) -> Self::Type {
|
||||
|
@ -1207,6 +1388,17 @@ impl<'ctx> ProxyValue<'ctx> for NDArrayValue<'ctx> {
|
|||
fn as_base_value(&self) -> Self::Base {
|
||||
self.value
|
||||
}
|
||||
|
||||
fn as_underlying_value(
|
||||
&self,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
name: Option<&'ctx str>,
|
||||
) -> Self::Underlying {
|
||||
ctx.builder
|
||||
.build_load(self.as_base_value(), name.unwrap_or_default())
|
||||
.map(BasicValueEnum::into_struct_value)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> From<NDArrayValue<'ctx>> for PointerValue<'ctx> {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::iter::once;
|
||||
use inkwell::AddressSpace;
|
||||
use inkwell::attributes::{Attribute, AttributeLoc};
|
||||
use inkwell::values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue};
|
||||
use itertools::Either;
|
||||
use inkwell::values::{BasicValue, BasicValueEnum, CallSiteValue, FloatValue, IntValue};
|
||||
use itertools::{Either, Itertools};
|
||||
|
||||
use crate::codegen::CodeGenContext;
|
||||
|
||||
|
@ -610,4 +612,47 @@ pub fn call_nextafter<'ctx>(
|
|||
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
||||
.map(Either::unwrap_left)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Invokes the `printf` function.
|
||||
pub fn call_printf<'ctx>(
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
format: &str,
|
||||
args: &[BasicValueEnum<'ctx>],
|
||||
) -> IntValue<'ctx> {
|
||||
const FN_NAME: &str = "printf";
|
||||
|
||||
let llvm_i8 = ctx.ctx.i8_type();
|
||||
let llvm_i32 = ctx.ctx.i32_type();
|
||||
let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default());
|
||||
|
||||
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
||||
let fn_type = llvm_i32.fn_type(&[llvm_pi8.into()], true);
|
||||
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
||||
for attr in ["nofree", "nounwind"] {
|
||||
func.add_attribute(
|
||||
AttributeLoc::Function,
|
||||
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0)
|
||||
);
|
||||
}
|
||||
|
||||
func
|
||||
});
|
||||
|
||||
let pformat = ctx.builder.build_global_string_ptr(&format!("{format}\0"), "")
|
||||
.map(|v| v.as_basic_value_enum())
|
||||
.map(BasicValueEnum::into_pointer_value)
|
||||
.unwrap();
|
||||
|
||||
let fn_args = once(&pformat.as_basic_value_enum()).chain(args)
|
||||
.cloned()
|
||||
.map(BasicValueEnum::into)
|
||||
.collect_vec();
|
||||
|
||||
ctx.builder
|
||||
.build_call(extern_fn, fn_args.as_slice(), "")
|
||||
.map(CallSiteValue::try_as_basic_value)
|
||||
.map(|v| v.map_left(BasicValueEnum::into_int_value))
|
||||
.map(Either::unwrap_left)
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{
|
||||
codegen::classes::{ListType, NDArrayType, ProxyType, RangeType},
|
||||
symbol_resolver::{StaticValue, SymbolResolver},
|
||||
toplevel::{
|
||||
helper::PRIMITIVE_DEF_IDS,
|
||||
|
@ -49,12 +50,17 @@ pub mod irrt;
|
|||
pub mod llvm_intrinsics;
|
||||
pub mod numpy;
|
||||
pub mod stmt;
|
||||
pub mod tracert;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
use concrete_type::{ConcreteType, ConcreteTypeEnum, ConcreteTypeStore};
|
||||
pub use generator::{CodeGenerator, DefaultCodeGenerator};
|
||||
use tracert::TraceRuntimeConfig;
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
use crate::codegen::tracert::TraceRuntimeState;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct StaticValueStore {
|
||||
|
@ -199,6 +205,9 @@ pub struct CodeGenContext<'ctx, 'a> {
|
|||
/// See [need_sret].
|
||||
pub need_sret: bool,
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
pub tracert_state: Option<TraceRuntimeState>,
|
||||
|
||||
/// The current source location.
|
||||
pub current_loc: Location,
|
||||
}
|
||||
|
@ -247,6 +256,9 @@ pub struct WorkerRegistry {
|
|||
|
||||
/// LLVM-related options for code generation.
|
||||
pub llvm_options: CodeGenLLVMOptions,
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
tracert_config: TraceRuntimeConfig,
|
||||
}
|
||||
|
||||
impl WorkerRegistry {
|
||||
|
@ -257,6 +269,7 @@ impl WorkerRegistry {
|
|||
generators: Vec<Box<G>>,
|
||||
top_level_ctx: Arc<TopLevelContext>,
|
||||
llvm_options: &CodeGenLLVMOptions,
|
||||
_tracert_config: &TraceRuntimeConfig,
|
||||
f: &Arc<WithCall>,
|
||||
) -> (Arc<WorkerRegistry>, Vec<thread::JoinHandle<()>>) {
|
||||
let (sender, receiver) = unbounded();
|
||||
|
@ -278,6 +291,8 @@ impl WorkerRegistry {
|
|||
wait_condvar,
|
||||
top_level_ctx,
|
||||
llvm_options: llvm_options.clone(),
|
||||
#[cfg(feature = "tracing")]
|
||||
tracert_config: _tracert_config.clone(),
|
||||
});
|
||||
|
||||
let mut handles = Vec::new();
|
||||
|
@ -452,7 +467,6 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
|
|||
}
|
||||
|
||||
TObj { obj_id, .. } if *obj_id == PRIMITIVE_DEF_IDS.ndarray => {
|
||||
let llvm_usize = generator.get_size_type(ctx);
|
||||
let (dtype, _) = unpack_ndarray_var_tys(unifier, ty);
|
||||
let element_type = get_llvm_type(
|
||||
ctx,
|
||||
|
@ -464,17 +478,7 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
|
|||
dtype,
|
||||
);
|
||||
|
||||
// struct NDArray { num_dims: size_t, dims: size_t*, data: T* }
|
||||
//
|
||||
// * num_dims: Number of dimensions in the array
|
||||
// * dims: Pointer to an array containing the size of each dimension
|
||||
// * data: Pointer to an array containing the array data
|
||||
let fields = [
|
||||
llvm_usize.into(),
|
||||
llvm_usize.ptr_type(AddressSpace::default()).into(),
|
||||
element_type.ptr_type(AddressSpace::default()).into(),
|
||||
];
|
||||
ctx.struct_type(&fields, false).ptr_type(AddressSpace::default()).into()
|
||||
NDArrayType::new(generator, ctx, element_type).as_base_type().into()
|
||||
}
|
||||
|
||||
_ => unreachable!("LLVM type for primitive {} is missing", unifier.stringify(ty)),
|
||||
|
@ -528,15 +532,11 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
|
|||
ctx.struct_type(&fields, false).into()
|
||||
}
|
||||
TList { ty } => {
|
||||
// a struct with an integer and a pointer to an array
|
||||
let element_type = get_llvm_type(
|
||||
ctx, module, generator, unifier, top_level, type_cache, *ty,
|
||||
);
|
||||
let fields = [
|
||||
element_type.ptr_type(AddressSpace::default()).into(),
|
||||
generator.get_size_type(ctx).into(),
|
||||
];
|
||||
ctx.struct_type(&fields, false).ptr_type(AddressSpace::default()).into()
|
||||
|
||||
ListType::new(generator, ctx, element_type).as_base_type().into()
|
||||
}
|
||||
TVirtual { .. } => unimplemented!(),
|
||||
_ => unreachable!("{}", ty_enum.get_type_name()),
|
||||
|
@ -671,7 +671,7 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
|
|||
Some(t) => t.as_basic_type_enum()
|
||||
}
|
||||
}),
|
||||
(primitives.range, context.i32_type().array_type(3).ptr_type(AddressSpace::default()).into()),
|
||||
(primitives.range, RangeType::new(context).as_base_type().into()),
|
||||
(primitives.exception, {
|
||||
let name = "Exception";
|
||||
if let Some(t) = module.get_struct_type(name) {
|
||||
|
@ -889,6 +889,12 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte
|
|||
unifier,
|
||||
static_value_store,
|
||||
need_sret: has_sret,
|
||||
#[cfg(feature = "tracing")]
|
||||
tracert_state: if registry.tracert_config.enabled_tags.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(TraceRuntimeState::create(registry.tracert_config.clone()))
|
||||
},
|
||||
current_loc: Location::default(),
|
||||
debug_info: (dibuilder, compile_unit, func_scope.as_debug_info_scope()),
|
||||
};
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
use inkwell::{IntPredicate, OptimizationLevel, types::BasicType, values::{BasicValueEnum, IntValue, PointerValue}};
|
||||
use inkwell::{AddressSpace, IntPredicate, OptimizationLevel, types::BasicType, values::{BasicValueEnum, IntValue, PointerValue}};
|
||||
use inkwell::types::{AnyTypeEnum, BasicTypeEnum, PointerType};
|
||||
use nac3parser::ast::{Operator, StrRef};
|
||||
use crate::{
|
||||
codegen::{
|
||||
classes::{
|
||||
ArrayLikeIndexer,
|
||||
ArrayLikeValue,
|
||||
ListType,
|
||||
ListValue,
|
||||
NDArrayType,
|
||||
NDArrayValue,
|
||||
ProxyType,
|
||||
ProxyValue,
|
||||
TypedArrayLikeAccessor,
|
||||
TypedArrayLikeAdapter,
|
||||
|
@ -31,9 +35,10 @@ use crate::{
|
|||
symbol_resolver::ValueEnum,
|
||||
toplevel::{
|
||||
DefinitionId,
|
||||
helper::PRIMITIVE_DEF_IDS,
|
||||
numpy::{make_ndarray_ty, unpack_ndarray_var_tys},
|
||||
},
|
||||
typecheck::typedef::{FunSignature, Type},
|
||||
typecheck::typedef::{FunSignature, Type, TypeEnum},
|
||||
};
|
||||
|
||||
/// Creates an uninitialized `NDArray` instance.
|
||||
|
@ -589,6 +594,405 @@ fn call_ndarray_full_impl<'ctx, G: CodeGenerator + ?Sized>(
|
|||
Ok(ndarray)
|
||||
}
|
||||
|
||||
/// Returns the number of dimensions for a multidimensional list as an [`IntValue`].
|
||||
fn llvm_ndlist_get_ndims<'ctx, G: CodeGenerator + ?Sized>(
|
||||
generator: &G,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
ty: PointerType<'ctx>,
|
||||
) -> IntValue<'ctx> {
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
|
||||
let list_ty = ListType::from_type(ty, llvm_usize);
|
||||
let list_elem_ty = list_ty.element_type();
|
||||
|
||||
let ndims = llvm_usize.const_int(1, false);
|
||||
match list_elem_ty {
|
||||
AnyTypeEnum::PointerType(ptr_ty) if ListType::is_type(ptr_ty, llvm_usize).is_ok() => {
|
||||
ndims.const_add(llvm_ndlist_get_ndims(generator, ctx, ptr_ty))
|
||||
}
|
||||
|
||||
AnyTypeEnum::PointerType(ptr_ty) if NDArrayType::is_type(ptr_ty, llvm_usize).is_ok() => {
|
||||
todo!("Getting ndims for list[ndarray] not supported")
|
||||
}
|
||||
|
||||
_ => ndims,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of dimensions for an array-like object as an [`IntValue`].
|
||||
fn llvm_arraylike_get_ndims<'ctx, G: CodeGenerator + ?Sized>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
) -> IntValue<'ctx> {
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
|
||||
match value {
|
||||
BasicValueEnum::PointerValue(v) if NDArrayValue::is_instance(v, llvm_usize).is_ok() => {
|
||||
NDArrayValue::from_ptr_val(v, llvm_usize, None).load_ndims(ctx)
|
||||
}
|
||||
|
||||
BasicValueEnum::PointerValue(v) if ListValue::is_instance(v, llvm_usize).is_ok() => {
|
||||
llvm_ndlist_get_ndims(generator, ctx, v.get_type())
|
||||
}
|
||||
|
||||
_ => llvm_usize.const_zero(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Flattens and copies the values from a multidimensional list into an [`NDArrayValue`].
|
||||
fn ndarray_from_ndlist_impl<'ctx, G: CodeGenerator + ?Sized>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
elem_ty: Type,
|
||||
(dst_arr, dst_slice_ptr): (NDArrayValue<'ctx>, PointerValue<'ctx>),
|
||||
src_lst: ListValue<'ctx>,
|
||||
dim: u64,
|
||||
) -> Result<(), String> {
|
||||
let llvm_i1 = ctx.ctx.bool_type();
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
|
||||
let list_elem_ty = src_lst.get_type().element_type();
|
||||
|
||||
match list_elem_ty {
|
||||
AnyTypeEnum::PointerType(ptr_ty) if ListType::is_type(ptr_ty, llvm_usize).is_ok() => {
|
||||
// The stride of elements in this dimension, i.e. the number of elements between arr[i]
|
||||
// and arr[i + 1] in this dimension
|
||||
let stride = call_ndarray_calc_size(
|
||||
generator,
|
||||
ctx,
|
||||
&dst_arr.dim_sizes(),
|
||||
(Some(llvm_usize.const_int(dim + 1, false)), None),
|
||||
);
|
||||
|
||||
gen_for_range_callback(
|
||||
generator,
|
||||
ctx,
|
||||
true,
|
||||
|_, _| Ok(llvm_usize.const_zero()),
|
||||
(|_, ctx| Ok(src_lst.load_size(ctx, None)), false),
|
||||
|_, _| Ok(llvm_usize.const_int(1, false)),
|
||||
|generator, ctx, i| {
|
||||
let offset = ctx.builder.build_int_mul(
|
||||
stride,
|
||||
i,
|
||||
"",
|
||||
).unwrap();
|
||||
|
||||
let dst_ptr = unsafe {
|
||||
ctx.builder.build_gep(dst_slice_ptr, &[offset], "").unwrap()
|
||||
};
|
||||
|
||||
let nested_lst_elem = ListValue::from_ptr_val(
|
||||
unsafe {
|
||||
src_lst.data().get_unchecked(ctx, generator, &i, None)
|
||||
}.into_pointer_value(),
|
||||
llvm_usize,
|
||||
None,
|
||||
);
|
||||
|
||||
ndarray_from_ndlist_impl(
|
||||
generator,
|
||||
ctx,
|
||||
elem_ty,
|
||||
(dst_arr, dst_ptr),
|
||||
nested_lst_elem,
|
||||
dim + 1,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
AnyTypeEnum::PointerType(ptr_ty) if NDArrayType::is_type(ptr_ty, llvm_usize).is_ok() => {
|
||||
todo!("Not implemented for list[ndarray]")
|
||||
}
|
||||
|
||||
_ => {
|
||||
let lst_len = src_lst.load_size(ctx, None);
|
||||
let sizeof_elem = ctx.get_llvm_type(generator, elem_ty).size_of().unwrap();
|
||||
let cpy_len = ctx.builder.build_int_mul(
|
||||
ctx.builder.build_int_z_extend_or_bit_cast(lst_len, llvm_usize, "").unwrap(),
|
||||
sizeof_elem,
|
||||
""
|
||||
).unwrap();
|
||||
|
||||
call_memcpy_generic(
|
||||
ctx,
|
||||
dst_slice_ptr,
|
||||
src_lst.data().base_ptr(ctx, generator),
|
||||
cpy_len,
|
||||
llvm_i1.const_zero(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// LLVM-typed implementation for `ndarray.array`.
|
||||
fn call_ndarray_array_impl<'ctx, G: CodeGenerator + ?Sized>(
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
elem_ty: Type,
|
||||
object: BasicValueEnum<'ctx>,
|
||||
copy: IntValue<'ctx>,
|
||||
ndmin: IntValue<'ctx>,
|
||||
) -> Result<NDArrayValue<'ctx>, String> {
|
||||
let llvm_i1 = ctx.ctx.bool_type();
|
||||
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||
|
||||
let ndmin = ctx.builder
|
||||
.build_int_z_extend_or_bit_cast(ndmin, llvm_usize, "")
|
||||
.unwrap();
|
||||
|
||||
// TODO(Derppening): Add assertions for sizes of different dimensions
|
||||
|
||||
// object is not a pointer - 0-dim NDArray
|
||||
if !object.is_pointer_value() {
|
||||
let ndarray = create_ndarray_const_shape(
|
||||
generator,
|
||||
ctx,
|
||||
elem_ty,
|
||||
&[],
|
||||
)?;
|
||||
|
||||
unsafe {
|
||||
ndarray.data()
|
||||
.set_unchecked(ctx, generator, &llvm_usize.const_zero(), object);
|
||||
}
|
||||
|
||||
return Ok(ndarray)
|
||||
}
|
||||
|
||||
let object = object.into_pointer_value();
|
||||
|
||||
// object is an NDArray instance - copy object unless copy=0 && ndmin < object.ndims
|
||||
if NDArrayValue::is_instance(object, llvm_usize).is_ok() {
|
||||
let object = NDArrayValue::from_ptr_val(object, llvm_usize, None);
|
||||
|
||||
let ndarray = gen_if_else_expr_callback(
|
||||
generator,
|
||||
ctx,
|
||||
|_, ctx| {
|
||||
let copy_nez = ctx.builder
|
||||
.build_int_compare(IntPredicate::NE, copy, llvm_i1.const_zero(), "")
|
||||
.unwrap();
|
||||
let ndmin_gt_ndims = ctx.builder
|
||||
.build_int_compare(IntPredicate::UGT, ndmin, object.load_ndims(ctx), "")
|
||||
.unwrap();
|
||||
|
||||
Ok(ctx.builder
|
||||
.build_and(copy_nez, ndmin_gt_ndims, "")
|
||||
.unwrap())
|
||||
},
|
||||
|generator, ctx| {
|
||||
let ndarray = create_ndarray_dyn_shape(
|
||||
generator,
|
||||
ctx,
|
||||
elem_ty,
|
||||
&object,
|
||||
|_, ctx, object| {
|
||||
let ndims = object.load_ndims(ctx);
|
||||
let ndmin_gt_ndims = ctx.builder
|
||||
.build_int_compare(IntPredicate::UGT, ndmin, object.load_ndims(ctx), "")
|
||||
.unwrap();
|
||||
|
||||
Ok(ctx.builder
|
||||
.build_select(ndmin_gt_ndims, ndmin, ndims, "")
|
||||
.map(BasicValueEnum::into_int_value)
|
||||
.unwrap())
|
||||
},
|
||||
|generator, ctx, object, idx| {
|
||||
let ndims = object.load_ndims(ctx);
|
||||
let ndmin = llvm_intrinsics::call_int_umax(ctx, ndims, ndmin, None);
|
||||
// The number of dimensions to prepend 1's to
|
||||
let offset = ctx.builder.build_int_sub(ndmin, ndims, "").unwrap();
|
||||
|
||||
Ok(gen_if_else_expr_callback(
|
||||
generator,
|
||||
ctx,
|
||||
|_, ctx| {
|
||||
Ok(ctx.builder
|
||||
.build_int_compare(IntPredicate::UGE, idx, offset, "")
|
||||
.unwrap())
|
||||
},
|
||||
|_, _| {
|
||||
Ok(Some(llvm_usize.const_int(1, false)))
|
||||
},
|
||||
|_, ctx| {
|
||||
Ok(Some(ctx.builder.build_int_sub(
|
||||
idx,
|
||||
offset,
|
||||
""
|
||||
).unwrap()))
|
||||
},
|
||||
)?.map(BasicValueEnum::into_int_value).unwrap())
|
||||
},
|
||||
)?;
|
||||
|
||||
ndarray_sliced_copyto_impl(
|
||||
generator,
|
||||
ctx,
|
||||
elem_ty,
|
||||
(ndarray, ndarray.data().base_ptr(ctx, generator)),
|
||||
(object, object.data().base_ptr(ctx, generator)),
|
||||
0,
|
||||
&[],
|
||||
)?;
|
||||
|
||||
Ok(Some(ndarray.as_base_value()))
|
||||
},
|
||||
|_, _| {
|
||||
Ok(Some(object.as_base_value()))
|
||||
},
|
||||
)?;
|
||||
|
||||
return Ok(NDArrayValue::from_ptr_val(
|
||||
ndarray.map(BasicValueEnum::into_pointer_value).unwrap(),
|
||||
llvm_usize,
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
||||
// Remaining case: TList
|
||||
assert!(ListValue::is_instance(object, llvm_usize).is_ok());
|
||||
let object = ListValue::from_ptr_val(object, llvm_usize, None);
|
||||
|
||||
// The number of dimensions to prepend 1's to
|
||||
let ndims = llvm_ndlist_get_ndims(generator, ctx, object.as_base_value().get_type());
|
||||
let ndmin = llvm_intrinsics::call_int_umax(ctx, ndims, ndmin, None);
|
||||
let offset = ctx.builder.build_int_sub(ndmin, ndims, "").unwrap();
|
||||
|
||||
let ndarray = create_ndarray_dyn_shape(
|
||||
generator,
|
||||
ctx,
|
||||
elem_ty,
|
||||
&object,
|
||||
|generator, ctx, object| {
|
||||
let ndims = llvm_ndlist_get_ndims(generator, ctx, object.as_base_value().get_type());
|
||||
let ndmin_gt_ndims = ctx.builder
|
||||
.build_int_compare(IntPredicate::UGT, ndmin, ndims, "")
|
||||
.unwrap();
|
||||
|
||||
Ok(ctx.builder
|
||||
.build_select(ndmin_gt_ndims, ndmin, ndims, "")
|
||||
.map(BasicValueEnum::into_int_value)
|
||||
.unwrap())
|
||||
},
|
||||
|generator, ctx, object, idx| {
|
||||
Ok(gen_if_else_expr_callback(
|
||||
generator,
|
||||
ctx,
|
||||
|_, ctx| {
|
||||
Ok(ctx.builder
|
||||
.build_int_compare(IntPredicate::ULT, idx, offset, "")
|
||||
.unwrap())
|
||||
},
|
||||
|_, _| {
|
||||
Ok(Some(llvm_usize.const_int(1, false)))
|
||||
},
|
||||
|generator, ctx| {
|
||||
let make_llvm_list = |elem_ty: BasicTypeEnum<'ctx>| {
|
||||
ctx.ctx.struct_type(
|
||||
&[
|
||||
elem_ty.ptr_type(AddressSpace::default()).into(),
|
||||
llvm_usize.into(),
|
||||
],
|
||||
false,
|
||||
)
|
||||
};
|
||||
|
||||
let llvm_i8 = ctx.ctx.i8_type();
|
||||
let llvm_list_i8 = make_llvm_list(llvm_i8.into());
|
||||
let llvm_plist_i8 = llvm_list_i8.ptr_type(AddressSpace::default());
|
||||
|
||||
// Cast list to { i8*, usize } since we only care about the size
|
||||
let lst = generator.gen_var_alloc(
|
||||
ctx,
|
||||
ListType::new(generator, ctx.ctx, llvm_i8.into()).as_base_type().into(),
|
||||
None,
|
||||
).unwrap();
|
||||
ctx.builder.build_store(
|
||||
lst,
|
||||
ctx.builder.build_bitcast(
|
||||
object.as_base_value(),
|
||||
llvm_plist_i8,
|
||||
"",
|
||||
).unwrap(),
|
||||
).unwrap();
|
||||
|
||||
let stop = ctx.builder.build_int_sub(idx, offset, "").unwrap();
|
||||
gen_for_range_callback(
|
||||
generator,
|
||||
ctx,
|
||||
true,
|
||||
|_, _| Ok(llvm_usize.const_zero()),
|
||||
(|_, _| Ok(stop), false),
|
||||
|_, _| Ok(llvm_usize.const_int(1, false)),
|
||||
|generator, ctx, _| {
|
||||
let plist_plist_i8 = make_llvm_list(llvm_plist_i8.into())
|
||||
.ptr_type(AddressSpace::default());
|
||||
|
||||
let this_dim = ctx.builder
|
||||
.build_load(lst, "")
|
||||
.map(BasicValueEnum::into_pointer_value)
|
||||
.map(|v| ctx.builder.build_bitcast(v, plist_plist_i8, "").unwrap())
|
||||
.map(BasicValueEnum::into_pointer_value)
|
||||
.unwrap();
|
||||
let this_dim = ListValue::from_ptr_val(
|
||||
this_dim,
|
||||
llvm_usize,
|
||||
None,
|
||||
);
|
||||
|
||||
// TODO: Assert this_dim.sz != 0
|
||||
|
||||
let next_dim = unsafe {
|
||||
this_dim.data()
|
||||
.get_unchecked(ctx, generator, &llvm_usize.const_zero(), None)
|
||||
}.into_pointer_value();
|
||||
ctx.builder.build_store(
|
||||
lst,
|
||||
ctx.builder.build_bitcast(
|
||||
next_dim,
|
||||
llvm_plist_i8,
|
||||
"",
|
||||
).unwrap(),
|
||||
).unwrap();
|
||||
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
let lst = ListValue::from_ptr_val(
|
||||
ctx.builder
|
||||
.build_load(lst, "")
|
||||
.map(BasicValueEnum::into_pointer_value)
|
||||
.unwrap(),
|
||||
llvm_usize,
|
||||
None,
|
||||
);
|
||||
|
||||
Ok(Some(lst.load_size(ctx, None)))
|
||||
},
|
||||
)?.map(BasicValueEnum::into_int_value).unwrap())
|
||||
},
|
||||
)?;
|
||||
|
||||
ndarray_from_ndlist_impl(
|
||||
generator,
|
||||
ctx,
|
||||
elem_ty,
|
||||
(ndarray, ndarray.data().base_ptr(ctx, generator)),
|
||||
object,
|
||||
0,
|
||||
)?;
|
||||
|
||||
Ok(ndarray)
|
||||
}
|
||||
|
||||
/// LLVM-typed implementation for generating the implementation for `ndarray.eye`.
|
||||
///
|
||||
/// * `elem_ty` - The element type of the `NDArray`.
|
||||
|
@ -1450,6 +1854,69 @@ pub fn gen_ndarray_full<'ctx>(
|
|||
).map(NDArrayValue::into)
|
||||
}
|
||||
|
||||
pub fn gen_ndarray_array<'ctx>(
|
||||
context: &mut CodeGenContext<'ctx, '_>,
|
||||
obj: &Option<(Type, ValueEnum<'ctx>)>,
|
||||
fun: (&FunSignature, DefinitionId),
|
||||
args: &[(Option<StrRef>, ValueEnum<'ctx>)],
|
||||
generator: &mut dyn CodeGenerator,
|
||||
) -> Result<PointerValue<'ctx>, String> {
|
||||
assert!(obj.is_none());
|
||||
assert!(matches!(args.len(), 1..=3));
|
||||
|
||||
let obj_ty = fun.0.args[0].ty;
|
||||
let obj_elem_ty = match &*context.unifier.get_ty(obj_ty) {
|
||||
TypeEnum::TObj { obj_id, .. } if *obj_id == PRIMITIVE_DEF_IDS.ndarray => {
|
||||
unpack_ndarray_var_tys(&mut context.unifier, obj_ty).0
|
||||
}
|
||||
|
||||
TypeEnum::TList { ty } => {
|
||||
let mut ty = *ty;
|
||||
while let TypeEnum::TList { ty: elem_ty } = &*context.unifier.get_ty_immutable(ty) {
|
||||
ty = *elem_ty;
|
||||
}
|
||||
ty
|
||||
},
|
||||
|
||||
_ => obj_ty,
|
||||
};
|
||||
let obj_arg = args[0].1.clone()
|
||||
.to_basic_value_enum(context, generator, obj_ty)?;
|
||||
|
||||
let copy_arg = if let Some(arg) =
|
||||
args.iter().find(|arg| arg.0.is_some_and(|name| name == fun.0.args[1].name)) {
|
||||
let copy_ty = fun.0.args[1].ty;
|
||||
arg.1.clone().to_basic_value_enum(context, generator, copy_ty)?
|
||||
} else {
|
||||
context.gen_symbol_val(
|
||||
generator,
|
||||
fun.0.args[1].default_value.as_ref().unwrap(),
|
||||
fun.0.args[1].ty,
|
||||
)
|
||||
};
|
||||
|
||||
let ndmin_arg = if let Some(arg) =
|
||||
args.iter().find(|arg| arg.0.is_some_and(|name| name == fun.0.args[2].name)) {
|
||||
let ndmin_ty = fun.0.args[2].ty;
|
||||
arg.1.clone().to_basic_value_enum(context, generator, ndmin_ty)?
|
||||
} else {
|
||||
context.gen_symbol_val(
|
||||
generator,
|
||||
fun.0.args[2].default_value.as_ref().unwrap(),
|
||||
fun.0.args[2].ty,
|
||||
)
|
||||
};
|
||||
|
||||
call_ndarray_array_impl(
|
||||
generator,
|
||||
context,
|
||||
obj_elem_ty,
|
||||
obj_arg,
|
||||
copy_arg.into_int_value(),
|
||||
ndmin_arg.into_int_value(),
|
||||
).map(NDArrayValue::into)
|
||||
}
|
||||
|
||||
/// Generates LLVM IR for `ndarray.eye`.
|
||||
pub fn gen_ndarray_eye<'ctx>(
|
||||
context: &mut CodeGenContext<'ctx, '_>,
|
||||
|
|
|
@ -872,12 +872,14 @@ pub fn gen_if_else_expr_callback<'ctx, 'a, G, CondFn, ThenFn, ElseFn, R>(
|
|||
|
||||
ctx.builder.position_at_end(then_bb);
|
||||
let then_val = then_fn(generator, ctx)?;
|
||||
let then_end_bb = ctx.builder.get_insert_block().unwrap();
|
||||
if !ctx.is_terminated() {
|
||||
ctx.builder.build_unconditional_branch(end_bb).unwrap();
|
||||
}
|
||||
|
||||
ctx.builder.position_at_end(else_bb);
|
||||
let else_val = else_fn(generator, ctx)?;
|
||||
let else_end_bb = ctx.builder.get_insert_block().unwrap();
|
||||
if !ctx.is_terminated() {
|
||||
ctx.builder.build_unconditional_branch(end_bb).unwrap();
|
||||
}
|
||||
|
@ -889,7 +891,7 @@ pub fn gen_if_else_expr_callback<'ctx, 'a, G, CondFn, ThenFn, ElseFn, R>(
|
|||
assert_eq!(tv_ty, ev.as_basic_value_enum().get_type());
|
||||
|
||||
let phi = ctx.builder.build_phi(tv_ty, "").unwrap();
|
||||
phi.add_incoming(&[(&tv, then_bb), (&ev, else_bb)]);
|
||||
phi.add_incoming(&[(&tv, then_end_bb), (&ev, else_end_bb)]);
|
||||
|
||||
Some(phi.as_basic_value())
|
||||
},
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use crate::{
|
||||
codegen::{
|
||||
concrete_type::ConcreteTypeStore, CodeGenContext, CodeGenLLVMOptions,
|
||||
CodeGenTargetMachineOptions, CodeGenTask, DefaultCodeGenerator, WithCall, WorkerRegistry,
|
||||
classes::{ListType, NDArrayType, ProxyType, RangeType},
|
||||
concrete_type::ConcreteTypeStore, CodeGenContext, CodeGenerator, CodeGenLLVMOptions,
|
||||
CodeGenTargetMachineOptions, CodeGenTask, DefaultCodeGenerator, tracert::TraceRuntimeConfig,
|
||||
WithCall, WorkerRegistry,
|
||||
},
|
||||
symbol_resolver::{SymbolResolver, ValueEnum},
|
||||
toplevel::{
|
||||
|
@ -230,6 +232,7 @@ fn test_primitives() {
|
|||
threads,
|
||||
top_level,
|
||||
&llvm_options,
|
||||
&TraceRuntimeConfig::default(),
|
||||
&f
|
||||
);
|
||||
registry.add_task(task);
|
||||
|
@ -420,8 +423,41 @@ fn test_simple_call() {
|
|||
threads,
|
||||
top_level,
|
||||
&llvm_options,
|
||||
&TraceRuntimeConfig::default(),
|
||||
&f
|
||||
);
|
||||
registry.add_task(task);
|
||||
registry.wait_tasks_complete(handles);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classes_list_type_new() {
|
||||
let ctx = inkwell::context::Context::create();
|
||||
let generator = DefaultCodeGenerator::new(String::new(), 64);
|
||||
|
||||
let llvm_i32 = ctx.i32_type();
|
||||
let llvm_usize = generator.get_size_type(&ctx);
|
||||
|
||||
let llvm_list = ListType::new(&generator, &ctx, llvm_i32.into());
|
||||
assert!(ListType::is_type(llvm_list.as_base_type(), llvm_usize).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classes_range_type_new() {
|
||||
let ctx = inkwell::context::Context::create();
|
||||
|
||||
let llvm_range = RangeType::new(&ctx);
|
||||
assert!(RangeType::is_type(llvm_range.as_base_type()).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classes_ndarray_type_new() {
|
||||
let ctx = inkwell::context::Context::create();
|
||||
let generator = DefaultCodeGenerator::new(String::new(), 64);
|
||||
|
||||
let llvm_i32 = ctx.i32_type();
|
||||
let llvm_usize = generator.get_size_type(&ctx);
|
||||
|
||||
let llvm_ndarray = NDArrayType::new(&generator, &ctx, llvm_i32.into());
|
||||
assert!(NDArrayType::is_type(llvm_ndarray.as_base_type(), llvm_usize).is_ok());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
use inkwell::AtomicOrdering;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::memory_buffer::MemoryBuffer;
|
||||
use inkwell::module::Module;
|
||||
use inkwell::values::BasicValueEnum;
|
||||
use crate::codegen::{CodeGenContext, extern_fns};
|
||||
|
||||
#[derive(Eq, Clone, PartialEq)]
|
||||
pub struct TraceRuntimeConfig {
|
||||
pub enabled_tags: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for TraceRuntimeConfig {
|
||||
fn default() -> Self {
|
||||
TraceRuntimeConfig {
|
||||
enabled_tags: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
#[derive(Eq, Clone, PartialEq)]
|
||||
pub struct TraceRuntimeState {
|
||||
config: TraceRuntimeConfig,
|
||||
indent: usize,
|
||||
}
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
impl TraceRuntimeState {
|
||||
pub fn create(config: TraceRuntimeConfig) -> TraceRuntimeState {
|
||||
TraceRuntimeState {
|
||||
config,
|
||||
indent: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn load_tracert<'ctx>(ctx: &'ctx Context, config: &TraceRuntimeConfig) -> Option<Module<'ctx>> {
|
||||
#[cfg(feature = "tracing")]
|
||||
{
|
||||
if !config.enabled_tags.is_empty() {
|
||||
let bitcode_buf = MemoryBuffer::create_from_memory_range(
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/tracert.bc")),
|
||||
"tracert_bitcode_buffer",
|
||||
);
|
||||
let module = Module::parse_bitcode_from_buffer(&bitcode_buf, ctx).unwrap();
|
||||
|
||||
return Some(module)
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
// TODO: Might need to redesign how trace logging should be done
|
||||
|
||||
pub fn trace_log<'ctx>(
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
tag: &'static str,
|
||||
format: &'static str,
|
||||
args: &[BasicValueEnum<'ctx>],
|
||||
) {
|
||||
#[cfg(feature = "tracing")]
|
||||
{
|
||||
if let None = ctx.tracert_state {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Add indentation
|
||||
let str = format!("[TRACING] {tag} - {format}\n\0");
|
||||
extern_fns::call_printf(ctx, &str, args);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trace_log_with_location<'ctx>(
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
tag: &'static str,
|
||||
format: &str,
|
||||
args: &[BasicValueEnum<'ctx>],
|
||||
file: &'static str,
|
||||
line: u32,
|
||||
column: u32,
|
||||
) {
|
||||
#[cfg(feature = "tracing")]
|
||||
{
|
||||
if let None = ctx.tracert_state {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Add indentation
|
||||
let str = format!("[TRACING] {file}:{line}:{column}:{tag} - {format}\n\0");
|
||||
extern_fns::call_printf(ctx, &str, args);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trace_push_level<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>) {
|
||||
#[cfg(feature = "tracing")]
|
||||
{
|
||||
if let Some(tracert_state) = &mut ctx.tracert_state {
|
||||
debug_assert!(tracert_state.indent < usize::MAX);
|
||||
if tracert_state.indent < usize::MAX {
|
||||
tracert_state.indent += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trace_pop_level<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>) {
|
||||
#[cfg(feature = "tracing")]
|
||||
{
|
||||
if let Some(tracert_state) = &mut ctx.tracert_state {
|
||||
debug_assert!(tracert_state.indent > 0);
|
||||
if tracert_state.indent > 0 {
|
||||
tracert_state.indent -= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mfence<'ctx>(ctx: &mut CodeGenContext<'ctx, '_>) {
|
||||
if cfg!(feature = "tracing") {
|
||||
ctx.builder.build_fence(AtomicOrdering::SequentiallyConsistent, 0, "").unwrap();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
// stdio.h
|
||||
int printf(const char *format, ...);
|
|
@ -12,7 +12,15 @@ use itertools::Either;
|
|||
use crate::{
|
||||
codegen::{
|
||||
builtin_fns,
|
||||
classes::{ArrayLikeValue, NDArrayValue, RangeValue, TypedArrayLikeAccessor},
|
||||
classes::{
|
||||
ArrayLikeValue,
|
||||
NDArrayValue,
|
||||
ProxyType,
|
||||
ProxyValue,
|
||||
RangeValue,
|
||||
RangeType,
|
||||
TypedArrayLikeAccessor,
|
||||
},
|
||||
expr::destructure_range,
|
||||
irrt::*,
|
||||
numpy::*,
|
||||
|
@ -780,6 +788,42 @@ pub fn get_builtins(unifier: &mut Unifier, primitives: &PrimitiveStore) -> Built
|
|||
}),
|
||||
)
|
||||
},
|
||||
{
|
||||
let tv = unifier.get_fresh_var(Some("T".into()), None);
|
||||
|
||||
Arc::new(RwLock::new(TopLevelDef::Function {
|
||||
name: "np_array".into(),
|
||||
simple_name: "np_array".into(),
|
||||
signature: unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
||||
args: vec![
|
||||
FuncArg { name: "object".into(), ty: tv.0, default_value: None },
|
||||
FuncArg {
|
||||
name: "copy".into(),
|
||||
ty: boolean,
|
||||
default_value: Some(SymbolValue::Bool(true)),
|
||||
},
|
||||
FuncArg {
|
||||
name: "ndmin".into(),
|
||||
ty: int32,
|
||||
default_value: Some(SymbolValue::U32(0)),
|
||||
},
|
||||
],
|
||||
ret: ndarray,
|
||||
vars: VarMap::from([(tv.1, tv.0)]),
|
||||
})),
|
||||
var_id: vec![tv.1],
|
||||
instance_to_symbol: HashMap::default(),
|
||||
instance_to_stmt: HashMap::default(),
|
||||
resolver: None,
|
||||
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|
||||
|ctx, obj, fun, args, generator| {
|
||||
gen_ndarray_array(ctx, &obj, fun, &args, generator)
|
||||
.map(|val| Some(val.as_basic_value_enum()))
|
||||
},
|
||||
)))),
|
||||
loc: None,
|
||||
}))
|
||||
},
|
||||
Arc::new(RwLock::new(TopLevelDef::Function {
|
||||
name: "np_eye".into(),
|
||||
simple_name: "np_eye".into(),
|
||||
|
@ -943,26 +987,53 @@ pub fn get_builtins(unifier: &mut Unifier, primitives: &PrimitiveStore) -> Built
|
|||
let mut stop = None;
|
||||
let mut step = None;
|
||||
let int32 = ctx.ctx.i32_type();
|
||||
let zero = int32.const_zero();
|
||||
let ty_i32 = ctx.primitives.int32;
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
if arg.0 == Some("start".into()) {
|
||||
start = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||
start = Some(arg.1
|
||||
.clone()
|
||||
.to_basic_value_enum(ctx, generator, ty_i32)?
|
||||
.into_int_value()
|
||||
);
|
||||
} else if arg.0 == Some("stop".into()) {
|
||||
stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||
stop = Some(
|
||||
arg.1
|
||||
.clone()
|
||||
.to_basic_value_enum(ctx, generator, ty_i32)?
|
||||
.into_int_value()
|
||||
);
|
||||
} else if arg.0 == Some("step".into()) {
|
||||
step = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||
step = Some(
|
||||
arg.1
|
||||
.clone()
|
||||
.to_basic_value_enum(ctx, generator, ty_i32)?
|
||||
.into_int_value()
|
||||
);
|
||||
} else if i == 0 {
|
||||
start = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||
start = Some(
|
||||
arg.1
|
||||
.clone()
|
||||
.to_basic_value_enum(ctx, generator, ty_i32)?
|
||||
.into_int_value()
|
||||
);
|
||||
} else if i == 1 {
|
||||
stop = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||
stop = Some(
|
||||
arg.1
|
||||
.clone()
|
||||
.to_basic_value_enum(ctx, generator, ty_i32)?
|
||||
.into_int_value()
|
||||
);
|
||||
} else if i == 2 {
|
||||
step = Some(arg.1.clone().to_basic_value_enum(ctx, generator, ty_i32)?);
|
||||
step = Some(
|
||||
arg.1
|
||||
.clone()
|
||||
.to_basic_value_enum(ctx, generator, ty_i32)?
|
||||
.into_int_value()
|
||||
);
|
||||
}
|
||||
}
|
||||
let step = match step {
|
||||
Some(step) => {
|
||||
let step = step.into_int_value();
|
||||
// assert step != 0, throw exception if not
|
||||
let not_zero = ctx.builder
|
||||
.build_int_compare(
|
||||
|
@ -989,30 +1060,13 @@ pub fn get_builtins(unifier: &mut Unifier, primitives: &PrimitiveStore) -> Built
|
|||
start = None;
|
||||
v
|
||||
});
|
||||
let start = start.unwrap_or_else(|| int32.const_zero().into());
|
||||
let ty = int32.array_type(3);
|
||||
let ptr = generator.gen_var_alloc(ctx, ty.into(), Some("range")).unwrap();
|
||||
unsafe {
|
||||
let a = ctx.builder
|
||||
.build_in_bounds_gep(ptr, &[zero, zero], "start")
|
||||
.unwrap();
|
||||
let b = ctx.builder
|
||||
.build_in_bounds_gep(
|
||||
ptr,
|
||||
&[zero, int32.const_int(1, false)],
|
||||
"end",
|
||||
)
|
||||
.unwrap();
|
||||
let c = ctx.builder.build_in_bounds_gep(
|
||||
ptr,
|
||||
&[zero, int32.const_int(2, false)],
|
||||
"step",
|
||||
).unwrap();
|
||||
ctx.builder.build_store(a, start).unwrap();
|
||||
ctx.builder.build_store(b, stop).unwrap();
|
||||
ctx.builder.build_store(c, step).unwrap();
|
||||
}
|
||||
Ok(Some(ptr.into()))
|
||||
let start = start.unwrap_or_else(|| int32.const_zero());
|
||||
|
||||
let ptr = RangeType::new(ctx.ctx).new_value(generator, ctx, Some("range"));
|
||||
ptr.store_start(ctx, start);
|
||||
ptr.store_end(ctx, stop);
|
||||
ptr.store_step(ctx, step);
|
||||
Ok(Some(ptr.as_base_value().into()))
|
||||
},
|
||||
)))),
|
||||
loc: None,
|
||||
|
|
|
@ -105,7 +105,7 @@ impl TopLevelComposer {
|
|||
builtin_id.insert(name, DefinitionId(id));
|
||||
} else if let TopLevelDef::Class { name, constructor, object_id, .. } = &*def
|
||||
{
|
||||
assert_eq!(id, object_id.0, "Object id of class '{}' should match its index in builtin name list", name);
|
||||
assert_eq!(id, object_id.0, "Object id of class '{name}' should match its index in builtin name list");
|
||||
if let Some(constructor) = constructor {
|
||||
builtin_ty.insert(*name, *constructor);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
use crate::symbol_resolver::SymbolValue;
|
||||
use crate::toplevel::numpy::unpack_ndarray_var_tys;
|
||||
use crate::typecheck::typedef::{Mapping, VarMap};
|
||||
use nac3parser::ast::{Constant, Location};
|
||||
|
||||
|
@ -691,3 +692,35 @@ pub fn parse_parameter_default_value(
|
|||
]))
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtains the element type of an array-like type.
|
||||
pub fn arraylike_flatten_element_type(unifier: &mut Unifier, ty: Type) -> Type {
|
||||
match &*unifier.get_ty(ty) {
|
||||
TypeEnum::TObj { obj_id, .. } if *obj_id == PRIMITIVE_DEF_IDS.ndarray =>
|
||||
unpack_ndarray_var_tys(unifier, ty).0,
|
||||
|
||||
TypeEnum::TList { ty } => arraylike_flatten_element_type(unifier, *ty),
|
||||
_ => ty
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtains the number of dimensions of an array-like type.
|
||||
pub fn arraylike_get_ndims(unifier: &mut Unifier, ty: Type) -> u64 {
|
||||
match &*unifier.get_ty(ty) {
|
||||
TypeEnum::TObj { obj_id, .. } if *obj_id == PRIMITIVE_DEF_IDS.ndarray => {
|
||||
let ndims = unpack_ndarray_var_tys(unifier, ty).1;
|
||||
let TypeEnum::TLiteral { values, .. } = &*unifier.get_ty_immutable(ndims) else {
|
||||
panic!("Expected TLiteral for ndarray.ndims, got {}", unifier.stringify(ndims))
|
||||
};
|
||||
|
||||
if values.len() > 1 {
|
||||
todo!("Getting num of dimensions for ndarray with more than one ndim bound is unimplemented")
|
||||
}
|
||||
|
||||
u64::try_from(values[0].clone()).unwrap()
|
||||
}
|
||||
|
||||
TypeEnum::TList { ty } => arraylike_get_ndims(unifier, *ty) + 1,
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ expression: res_vec
|
|||
[
|
||||
"Class {\nname: \"Generic_A\",\nancestors: [\"Generic_A[V]\", \"B\"],\nfields: [\"aa\", \"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\"), (\"fun\", \"fn[[a:int32], V]\")],\ntype_vars: [\"V\"]\n}\n",
|
||||
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [238]\n}\n",
|
||||
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [239]\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",
|
||||
|
|
|
@ -7,7 +7,7 @@ expression: res_vec
|
|||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B[typevar227]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar227\"]\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B[typevar228]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar228\"]\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"C\",\nancestors: [\"C\", \"B[bool]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n",
|
||||
|
|
|
@ -5,8 +5,8 @@ expression: res_vec
|
|||
[
|
||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"A\",\nancestors: [\"A[T, V]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [240]\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [245]\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [241]\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [246]\n}\n",
|
||||
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[list[float], int32]], none]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
|
|
|
@ -3,7 +3,7 @@ source: nac3core/src/toplevel/test.rs
|
|||
expression: res_vec
|
||||
---
|
||||
[
|
||||
"Class {\nname: \"A\",\nancestors: [\"A[typevar226, typevar227]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar226\", \"typevar227\"]\n}\n",
|
||||
"Class {\nname: \"A\",\nancestors: [\"A[typevar227, typevar228]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar227\", \"typevar228\"]\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[float, bool], b:B], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[float, bool]], A[bool, int32]]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\")],\ntype_vars: []\n}\n",
|
||||
|
|
|
@ -6,12 +6,12 @@ expression: res_vec
|
|||
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [246]\n}\n",
|
||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [247]\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B\", \"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"C\",\nancestors: [\"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [254]\n}\n",
|
||||
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [255]\n}\n",
|
||||
]
|
||||
|
|
|
@ -9,7 +9,7 @@ use super::{magic_methods::*, type_error::TypeError, typedef::CallId};
|
|||
use crate::{
|
||||
symbol_resolver::{SymbolResolver, SymbolValue},
|
||||
toplevel::{
|
||||
helper::PRIMITIVE_DEF_IDS,
|
||||
helper::{arraylike_flatten_element_type, arraylike_get_ndims, PRIMITIVE_DEF_IDS},
|
||||
numpy::{make_ndarray_ty, unpack_ndarray_var_tys},
|
||||
TopLevelContext,
|
||||
},
|
||||
|
@ -812,7 +812,7 @@ impl<'a> Inferencer<'a> {
|
|||
location: Location,
|
||||
func: &ast::Expr<()>,
|
||||
args: &mut Vec<ast::Expr<()>>,
|
||||
keywords: &Vec<Located<ast::KeywordData>>,
|
||||
keywords: &[Located<ast::KeywordData>],
|
||||
) -> Result<Option<ast::Expr<Option<Type>>>, HashSet<String>> {
|
||||
let Located { location: func_location, node: ExprKind::Name { id, ctx }, .. } = func else {
|
||||
return Ok(None)
|
||||
|
@ -1254,6 +1254,77 @@ impl<'a> Inferencer<'a> {
|
|||
}))
|
||||
}
|
||||
|
||||
// 1-argument ndarray n-dimensional creation functions
|
||||
if id == &"np_array".into() && args.len() == 1 {
|
||||
let arg0 = self.fold_expr(args.remove(0))?;
|
||||
|
||||
let keywords = keywords.iter()
|
||||
.map(|v| fold::fold_keyword(self, v.clone()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let ndmin_kw = keywords.iter()
|
||||
.find(|kwarg| kwarg.node.arg.is_some_and(|id| id == "ndmin".into()));
|
||||
|
||||
let ty = arraylike_flatten_element_type(self.unifier, arg0.custom.unwrap());
|
||||
let ndims = if let Some(ndmin_kw) = ndmin_kw {
|
||||
match &ndmin_kw.node.value.node {
|
||||
ExprKind::Constant { value, .. } => match value {
|
||||
ast::Constant::Int(value) => *value as u64,
|
||||
_ => return Err(HashSet::from(["Expected uint64 for ndims".to_string()])),
|
||||
}
|
||||
|
||||
_ => arraylike_get_ndims(self.unifier, arg0.custom.unwrap())
|
||||
}
|
||||
} else {
|
||||
arraylike_get_ndims(self.unifier, arg0.custom.unwrap())
|
||||
};
|
||||
let ndims = self.unifier.get_fresh_literal(
|
||||
vec![SymbolValue::U64(ndims)],
|
||||
None,
|
||||
);
|
||||
let ret = make_ndarray_ty(
|
||||
self.unifier,
|
||||
self.primitives,
|
||||
Some(ty),
|
||||
Some(ndims),
|
||||
);
|
||||
|
||||
let custom = self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
||||
args: vec![
|
||||
FuncArg {
|
||||
name: "object".into(),
|
||||
ty: arg0.custom.unwrap(),
|
||||
default_value: None
|
||||
},
|
||||
FuncArg {
|
||||
name: "copy".into(),
|
||||
ty: self.primitives.bool,
|
||||
default_value: Some(SymbolValue::Bool(true)),
|
||||
},
|
||||
FuncArg {
|
||||
name: "ndmin".into(),
|
||||
ty: self.primitives.int32,
|
||||
default_value: Some(SymbolValue::U32(0)),
|
||||
},
|
||||
],
|
||||
ret,
|
||||
vars: VarMap::new(),
|
||||
}));
|
||||
|
||||
return Ok(Some(Located {
|
||||
location,
|
||||
custom: Some(ret),
|
||||
node: ExprKind::Call {
|
||||
func: Box::new(Located {
|
||||
custom: Some(custom),
|
||||
location: func.location,
|
||||
node: ExprKind::Name { id: *id, ctx: ctx.clone() },
|
||||
}),
|
||||
args: vec![arg0],
|
||||
keywords,
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
@ -1264,11 +1335,10 @@ impl<'a> Inferencer<'a> {
|
|||
mut args: Vec<ast::Expr<()>>,
|
||||
keywords: Vec<Located<ast::KeywordData>>,
|
||||
) -> Result<ast::Expr<Option<Type>>, HashSet<String>> {
|
||||
let func = if let Some(spec_call_func) = self.try_fold_special_call(location, &func, &mut args, &keywords)? {
|
||||
if let Some(spec_call_func) = self.try_fold_special_call(location, &func, &mut args, &keywords)? {
|
||||
return Ok(spec_call_func)
|
||||
} else {
|
||||
func
|
||||
};
|
||||
}
|
||||
|
||||
let func = Box::new(self.fold_expr(func)?);
|
||||
let args = args.into_iter().map(|v| self.fold_expr(v)).collect::<Result<Vec<_>, _>>()?;
|
||||
let keywords = keywords
|
||||
|
|
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
|||
authors = ["M-Labs"]
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
tracing = ["nac3core/tracing"]
|
||||
|
||||
[dependencies]
|
||||
parking_lot = "0.12"
|
||||
nac3parser = { path = "../nac3parser" }
|
||||
|
|
|
@ -73,13 +73,20 @@ void output_int32_list(struct cslice *slice) {
|
|||
putchar('\n');
|
||||
}
|
||||
|
||||
void output_str(struct cslice *slice) {
|
||||
const char *data = (const char *) slice->data;
|
||||
void output_str_impl(const struct cslice* slice, bool newline) {
|
||||
const char *data = (const char *) slice->data;
|
||||
|
||||
for (usize i = 0; i < slice->len; ++i) {
|
||||
putchar(data[i]);
|
||||
}
|
||||
putchar('\n');
|
||||
for (usize i = 0; i < slice->len; ++i) {
|
||||
putchar(data[i]);
|
||||
}
|
||||
|
||||
if (newline) {
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
void output_str(struct cslice *slice) {
|
||||
output_str_impl(slice, true);
|
||||
}
|
||||
|
||||
uint64_t dbg_stack_address(__attribute__((unused)) struct cslice *slice) {
|
||||
|
@ -94,8 +101,34 @@ uint32_t __nac3_personality(uint32_t state, uint32_t exception_object, uint32_t
|
|||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
struct exception {
|
||||
uint32_t name;
|
||||
struct cslice file;
|
||||
uint32_t line;
|
||||
uint32_t col;
|
||||
struct cslice func;
|
||||
struct cslice message;
|
||||
uint64_t param0;
|
||||
uint64_t param1;
|
||||
uint64_t param2;
|
||||
};
|
||||
|
||||
void output_exception(const struct exception *ex) {
|
||||
fputs("exception { location: ", stdout);
|
||||
output_str_impl(&ex->file, false);
|
||||
printf(":%u:%u, func: ", ex->line, ex->col);
|
||||
output_str_impl(&ex->func, false);
|
||||
fputs(", message: ", stdout);
|
||||
output_str_impl(&ex->message, false);
|
||||
printf(", params: [%lu, %lu, %lu] }\n", ex->param0, ex->param1, ex->param2);
|
||||
}
|
||||
|
||||
uint32_t __nac3_raise(uint32_t state, uint32_t exception_object, uint32_t context) {
|
||||
printf("__nac3_raise(state: %u, exception_object: %u, context: %u)\n", state, exception_object, context);
|
||||
printf("__nac3_raise(state: %#10x, exception_object: %#10x, context: %#10x)\n", state, exception_object, context);
|
||||
|
||||
struct exception *ex = (struct exception *)((0x7ffffffful << 16) | state);
|
||||
output_exception(ex);
|
||||
|
||||
exit(101);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
|
|
@ -170,6 +170,7 @@ def patch(module):
|
|||
module.np_full = np.full
|
||||
module.np_eye = np.eye
|
||||
module.np_identity = np.identity
|
||||
module.np_array = np.array
|
||||
|
||||
# NumPy Math functions
|
||||
module.np_isnan = np.isnan
|
||||
|
|
|
@ -97,6 +97,19 @@ def test_ndarray_eye():
|
|||
n: ndarray[float, 2] = np_eye(2)
|
||||
output_ndarray_float_2(n)
|
||||
|
||||
def test_ndarray_array():
|
||||
n1: ndarray[float, 1] = np_array([1.0, 2.0, 3.0])
|
||||
output_ndarray_float_1(n1)
|
||||
n1to2: ndarray[float, 2] = np_array([1.0, 2.0, 3.0], ndmin=2)
|
||||
output_ndarray_float_2(n1to2)
|
||||
n2: ndarray[float, 2] = np_array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
|
||||
output_ndarray_float_2(n2)
|
||||
|
||||
# Copy
|
||||
n2_cpy: ndarray[float, 2] = np_array(n2, copy=False)
|
||||
n2_cpy.fill(0.0)
|
||||
output_ndarray_float_2(n2_cpy)
|
||||
|
||||
def test_ndarray_identity():
|
||||
n: ndarray[float, 2] = np_identity(2)
|
||||
output_ndarray_float_2(n)
|
||||
|
@ -1373,6 +1386,7 @@ def run() -> int32:
|
|||
test_ndarray_ones()
|
||||
test_ndarray_full()
|
||||
test_ndarray_eye()
|
||||
test_ndarray_array()
|
||||
test_ndarray_identity()
|
||||
test_ndarray_fill()
|
||||
test_ndarray_copy()
|
||||
|
|
|
@ -13,7 +13,8 @@ use std::collections::HashSet;
|
|||
use nac3core::{
|
||||
codegen::{
|
||||
concrete_type::ConcreteTypeStore, irrt::load_irrt, CodeGenLLVMOptions,
|
||||
CodeGenTargetMachineOptions, CodeGenTask, DefaultCodeGenerator, WithCall, WorkerRegistry,
|
||||
CodeGenTargetMachineOptions, CodeGenTask, DefaultCodeGenerator,
|
||||
tracert::{load_tracert, TraceRuntimeConfig}, WithCall, WorkerRegistry,
|
||||
},
|
||||
symbol_resolver::SymbolResolver,
|
||||
toplevel::{
|
||||
|
@ -68,6 +69,9 @@ struct CommandLineArgs {
|
|||
/// Additional target features to enable/disable, specified using the `+`/`-` prefixes.
|
||||
#[arg(long)]
|
||||
target_features: Option<String>,
|
||||
|
||||
#[arg(long)]
|
||||
trace: Vec<String>,
|
||||
}
|
||||
|
||||
fn handle_typevar_definition(
|
||||
|
@ -258,6 +262,7 @@ fn main() {
|
|||
triple,
|
||||
mcpu,
|
||||
target_features,
|
||||
trace,
|
||||
} = cli;
|
||||
|
||||
Target::initialize_all(&InitializationConfig::default());
|
||||
|
@ -289,6 +294,9 @@ fn main() {
|
|||
// The default behavior for -O<n> where n>3 defaults to O3 for both Clang and GCC
|
||||
_ => OptimizationLevel::Aggressive,
|
||||
};
|
||||
let tracert_config = TraceRuntimeConfig {
|
||||
enabled_tags: trace,
|
||||
};
|
||||
|
||||
let program = match fs::read_to_string(file_name.clone()) {
|
||||
Ok(program) => program,
|
||||
|
@ -405,7 +413,13 @@ fn main() {
|
|||
let threads = (0..threads)
|
||||
.map(|i| Box::new(DefaultCodeGenerator::new(format!("module{i}"), SIZE_T)))
|
||||
.collect();
|
||||
let (registry, handles) = WorkerRegistry::create_workers(threads, top_level, &llvm_options, &f);
|
||||
let (registry, handles) = WorkerRegistry::create_workers(
|
||||
threads,
|
||||
top_level,
|
||||
&llvm_options,
|
||||
&tracert_config,
|
||||
&f,
|
||||
);
|
||||
registry.add_task(task);
|
||||
registry.wait_tasks_complete(handles);
|
||||
|
||||
|
@ -436,6 +450,14 @@ fn main() {
|
|||
}
|
||||
main.link_in_module(irrt).unwrap();
|
||||
|
||||
if let Some(tracert) = load_tracert(&context, &tracert_config) {
|
||||
if emit_llvm {
|
||||
tracert.write_bitcode_to_path(Path::new("tracert.bc"));
|
||||
}
|
||||
|
||||
main.link_in_module(tracert).unwrap();
|
||||
}
|
||||
|
||||
let mut function_iter = main.get_first_function();
|
||||
while let Some(func) = function_iter {
|
||||
if func.count_basic_blocks() > 0 && func.get_name().to_str().unwrap() != "run" {
|
||||
|
|
Loading…
Reference in New Issue