Add lli support for running example test cases #327
|
@ -9,6 +9,7 @@
|
||||||
in rec {
|
in rec {
|
||||||
packages.x86_64-linux = rec {
|
packages.x86_64-linux = rec {
|
||||||
llvm-nac3 = pkgs.callPackage ./nix/llvm {};
|
llvm-nac3 = pkgs.callPackage ./nix/llvm {};
|
||||||
|
clang-unwrapped = pkgs.runCommandNoCC "clang-unwrapped" {} "mkdir -p $out/bin; ln -s ${pkgs.llvmPackages_14.clang-unwrapped}/bin/clang $out/bin/clang-unwrapped";
|
||||||
nac3artiq = pkgs.python3Packages.toPythonModule (
|
nac3artiq = pkgs.python3Packages.toPythonModule (
|
||||||
pkgs.rustPlatform.buildRustPackage rec {
|
pkgs.rustPlatform.buildRustPackage rec {
|
||||||
name = "nac3artiq";
|
name = "nac3artiq";
|
||||||
|
@ -18,7 +19,7 @@
|
||||||
lockFile = ./Cargo.lock;
|
lockFile = ./Cargo.lock;
|
||||||
};
|
};
|
||||||
passthru.cargoLock = cargoLock;
|
passthru.cargoLock = cargoLock;
|
||||||
nativeBuildInputs = [ pkgs.python3 pkgs.llvmPackages_14.clang-unwrapped pkgs.llvmPackages_14.llvm.out llvm-nac3 ];
|
nativeBuildInputs = [ pkgs.python3 pkgs.llvmPackages_14.clang packages.x86_64-linux.clang-unwrapped pkgs.llvmPackages_14.llvm.out llvm-nac3 ];
|
||||||
buildInputs = [ pkgs.python3 llvm-nac3 ];
|
buildInputs = [ pkgs.python3 llvm-nac3 ];
|
||||||
checkInputs = [ (pkgs.python3.withPackages(ps: [ ps.numpy ])) ];
|
checkInputs = [ (pkgs.python3.withPackages(ps: [ ps.numpy ])) ];
|
||||||
checkPhase =
|
checkPhase =
|
||||||
|
@ -143,7 +144,8 @@
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
# build dependencies
|
# build dependencies
|
||||||
packages.x86_64-linux.llvm-nac3
|
packages.x86_64-linux.llvm-nac3
|
||||||
llvmPackages_14.clang-unwrapped # IRRT
|
llvmPackages_14.clang # demo
|
||||||
|
packages.x86_64-linux.clang-unwrapped # IRRT
|
||||||
pkgs.llvmPackages_14.llvm.out # IRRT
|
pkgs.llvmPackages_14.llvm.out # IRRT
|
||||||
cargo
|
cargo
|
||||||
rustc
|
rustc
|
||||||
|
|
|
@ -29,7 +29,7 @@ fn main() {
|
||||||
"-o",
|
"-o",
|
||||||
"-",
|
"-",
|
||||||
];
|
];
|
||||||
let output = Command::new("clang")
|
let output = Command::new("clang-unwrapped")
|
||||||
.args(FLAG)
|
.args(FLAG)
|
||||||
.output()
|
.output()
|
||||||
.map(|o| {
|
.map(|o| {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Requires at least one argument"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
demo="${@:-1}"
|
||||||
|
set -- "${@:1:$(($# - 1))}"
|
||||||
|
|
||||||
|
echo -n "Checking $demo... "
|
||||||
|
./interpret_demo.py "$demo" > interpreted.log
|
||||||
|
./run_demo.sh "$@" "$demo" > run.log
|
||||||
|
./run_demo_lli.sh "$@" "$demo" > run_lli.log
|
||||||
|
diff -Nau interpreted.log run.log
|
||||||
|
diff -Nau interpreted.log run_lli.log
|
||||||
|
echo "ok"
|
||||||
|
|
||||||
|
rm -f interpreted.log run.log run_lli.log
|
||||||
sb10q marked this conversation as resolved
Outdated
|
|
@ -4,12 +4,8 @@ set -e
|
||||||
|
|
||||||
count=0
|
count=0
|
||||||
for demo in src/*.py; do
|
for demo in src/*.py; do
|
||||||
echo -n "checking $demo... "
|
./check_demo.sh "$@" "$demo"
|
||||||
./interpret_demo.py $demo > interpreted.log
|
((count += 1))
|
||||||
./run_demo.sh "$@" $demo > run.log
|
|
||||||
diff -Nau interpreted.log run.log
|
|
||||||
derppening marked this conversation as resolved
Outdated
sb10q
commented
Just add a Just add a `run_demo_lli.sh > run_lli.log` and keep this structure, which avoids invoking the interpreter multiple times and overwriting files.
|
|||||||
echo "ok"
|
|
||||||
let "count+=1"
|
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "Ran $count demo checks - PASSED"
|
echo "Ran $count demo checks - PASSED"
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if __SIZEOF_POINTER__ == 8
|
||||||
|
#define usize uint64_t
|
||||||
|
#elif __SIZEOF_POINTER__ == 4
|
||||||
|
#define usize uint32_t
|
||||||
|
#else
|
||||||
|
#error "Unsupported platform - Platform is not 32-bit or 64-bit"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void output_int32(const int32_t x) {
|
||||||
|
printf("%d\n", x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_int64(const int64_t x) {
|
||||||
|
printf("%ld\n", x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_uint32(const uint32_t x) {
|
||||||
|
printf("%d\n", x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_uint64(const uint64_t x) {
|
||||||
|
printf("%ld\n", x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_float64(const double x) {
|
||||||
|
printf("%f\n", x);
|
||||||
|
}
|
||||||
|
void output_asciiart(const int32_t x) {
|
||||||
|
const char* chars = " .,-:;i+hHM$*#@ ";
|
||||||
|
if (x < 0) {
|
||||||
|
putchar('\n');
|
||||||
|
} else {
|
||||||
|
putchar(chars[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cslice {
|
||||||
|
const void* data;
|
||||||
|
usize len;
|
||||||
|
};
|
||||||
|
|
||||||
|
void output_int32_list(struct cslice* slice) {
|
||||||
|
const int32_t* data = (const int32_t*) slice->data;
|
||||||
|
|
||||||
|
putchar('[');
|
||||||
|
for (usize i = 0; i < slice->len; ++i) {
|
||||||
|
if (i == slice->len - 1) {
|
||||||
|
printf("%d", data[i]);
|
||||||
|
} else {
|
||||||
|
printf("%d, ", data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putchar(']');
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_str(struct cslice* slice) {
|
||||||
|
const char* data = (const char*) slice->data;
|
||||||
|
|
||||||
|
for (usize i = 0; i < slice->len; ++i) {
|
||||||
|
putchar(data[i]);
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t __nac3_personality(uint32_t state, uint32_t exception_object, uint32_t context) {
|
||||||
|
printf("__nac3_personality(state: %u, exception_object: %u, context: %u\n", state, exception_object, context);
|
||||||
|
exit(101);
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
exit(101);
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __nac3_end_catch(void) {}
|
||||||
|
|
||||||
|
extern int32_t run(void);
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
run();
|
||||||
|
}
|
|
@ -1,111 +0,0 @@
|
||||||
use std::io;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::process::exit;
|
|
||||||
|
|
||||||
mod cslice {
|
|
||||||
// copied from https://github.com/dherman/cslice
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::slice;
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct CSlice<'a, T> {
|
|
||||||
base: *const T,
|
|
||||||
len: usize,
|
|
||||||
marker: PhantomData<&'a ()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> AsRef<[T]> for CSlice<'a, T> {
|
|
||||||
fn as_ref(&self) -> &[T] {
|
|
||||||
unsafe { slice::from_raw_parts(self.base, self.len) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn output_int32(x: i32) {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn output_int64(x: i64) {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn output_uint32(x: u32) {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn output_uint64(x: u64) {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn output_float64(x: f64) {
|
|
||||||
// debug output to preserve the digits after the decimal points
|
|
||||||
// to match python `print` function
|
|
||||||
println!("{:?}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn output_asciiart(x: i32) {
|
|
||||||
let chars = " .,-:;i+hHM$*#@ ";
|
|
||||||
if x < 0 {
|
|
||||||
println!("");
|
|
||||||
} else {
|
|
||||||
print!("{}", chars.chars().nth(x as usize).unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn output_str(x: &cslice::CSlice<u8>) {
|
|
||||||
for e in x.as_ref().iter() {
|
|
||||||
print!("{}", char::from(*e));
|
|
||||||
}
|
|
||||||
println!();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn output_int32_list(x: &cslice::CSlice<i32>) {
|
|
||||||
print!("[");
|
|
||||||
let mut it = x.as_ref().iter().peekable();
|
|
||||||
while let Some(e) = it.next() {
|
|
||||||
if it.peek().is_none() {
|
|
||||||
print!("{}", e);
|
|
||||||
} else {
|
|
||||||
print!("{}, ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("]");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn __nac3_personality(_state: u32, _exception_object: u32, _context: u32) -> u32 {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn __nac3_raise(state: u32, exception_object: u32, context: u32) -> u32 {
|
|
||||||
writeln!(io::stderr(),
|
|
||||||
"__nac3_raise(state: {:#010x}, exception_object: {:#010x}, context: {:#010x})",
|
|
||||||
state,
|
|
||||||
exception_object,
|
|
||||||
context
|
|
||||||
).unwrap();
|
|
||||||
exit(101);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn __nac3_end_catch() {}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
fn run() -> i32;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
unsafe {
|
|
||||||
run();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -48,17 +48,21 @@ def patch(module):
|
||||||
else:
|
else:
|
||||||
sys.stdout.write(" .,-:;i+hHM$*#@ "[x])
|
sys.stdout.write(" .,-:;i+hHM$*#@ "[x])
|
||||||
|
|
||||||
|
def output_float(x):
|
||||||
|
print("%f" % x)
|
||||||
|
|
||||||
def extern(fun):
|
def extern(fun):
|
||||||
name = fun.__name__
|
name = fun.__name__
|
||||||
if name == "output_asciiart":
|
if name == "output_asciiart":
|
||||||
return output_asciiart
|
return output_asciiart
|
||||||
|
elif name == "output_float64":
|
||||||
|
return output_float
|
||||||
elif name in {
|
elif name in {
|
||||||
"output_int32",
|
"output_int32",
|
||||||
"output_int64",
|
"output_int64",
|
||||||
"output_int32_list",
|
"output_int32_list",
|
||||||
"output_uint32",
|
"output_uint32",
|
||||||
"output_uint64",
|
"output_uint64",
|
||||||
"output_float64",
|
|
||||||
"output_str",
|
"output_str",
|
||||||
}:
|
}:
|
||||||
return print
|
return print
|
||||||
|
|
|
@ -14,7 +14,9 @@ else
|
||||||
nac3standalone=../../target/x86_64-unknown-linux-gnu/release/nac3standalone
|
nac3standalone=../../target/x86_64-unknown-linux-gnu/release/nac3standalone
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f *.o
|
rm -f "*.o" demo
|
||||||
sb10q marked this conversation as resolved
sb10q
commented
Why? The next commands will overwrite them. Why? The next commands will overwrite them.
derppening
commented
I just found it to be intuitive that if you are removing the object files, then the output executable should also be removed. I just found it to be intuitive that if you are removing the object files, then the output executable should also be removed.
|
|||||||
|
|
||||||
$nac3standalone "$@"
|
$nac3standalone "$@"
|
||||||
rustc -o demo demo.rs -Crelocation-model=static -Clink-arg=./module.o
|
clang -c -std=gnu11 -Wall -Wextra -O3 -o demo.o demo.c
|
||||||
|
clang -o demo module.o demo.o
|
||||||
./demo
|
./demo
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "No argument supplied"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e ../../target/release/nac3standalone ]; then
|
||||||
|
nac3standalone=../../target/release/nac3standalone
|
||||||
|
else
|
||||||
|
# used by Nix builds
|
||||||
|
nac3standalone=../../target/x86_64-unknown-linux-gnu/release/nac3standalone
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "*.o" "*.bc" demo
|
||||||
|
|
||||||
|
$nac3standalone --emit-llvm "$@"
|
||||||
|
clang -c -std=gnu11 -Wall -Wextra -O3 -emit-llvm -o demo.bc demo.c
|
||||||
|
lli --extra-module demo.bc --extra-module irrt.bc main.bc
|
||||||
sb10q
commented
I don't think you need to add IRRT here. The output of the compiler (nac3core) is already supposed to inline IRRT. I don't think you need to add IRRT here. The output of the compiler (nac3core) is already supposed to inline IRRT.
derppening
commented
This is necessary, as the This is necessary, as the `nac3standalone` program will only generate LLVM bitcode for the module-under-compilation (rather than including the dependencies).
sb10q
commented
I would change it so it also emits the already compiled and integrated IRRT then, instead of compiling it redundantly (and with the wrong compiler). I would change it so it also emits the already compiled and integrated IRRT then, instead of compiling it redundantly (and with the wrong compiler).
|
|
@ -14,6 +14,10 @@ def output_uint32(x: uint32):
|
||||||
def output_uint64(x: uint64):
|
def output_uint64(x: uint64):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@extern
|
||||||
|
def output_float64(x: float):
|
||||||
|
...
|
||||||
|
|
||||||
@extern
|
@extern
|
||||||
def output_int32_list(x: list[int32]):
|
def output_int32_list(x: list[int32]):
|
||||||
...
|
...
|
||||||
|
@ -38,6 +42,15 @@ def test_output_uint32():
|
||||||
def test_output_uint64():
|
def test_output_uint64():
|
||||||
output_uint64(uint64(256))
|
output_uint64(uint64(256))
|
||||||
|
|
||||||
|
def test_output_float64():
|
||||||
|
output_float64(0.0)
|
||||||
|
output_float64(1.0)
|
||||||
|
output_float64(-1.0)
|
||||||
|
output_float64(128.0)
|
||||||
|
output_float64(-128.0)
|
||||||
|
output_float64(16.25)
|
||||||
|
output_float64(-16.25)
|
||||||
|
|
||||||
def test_output_asciiart():
|
def test_output_asciiart():
|
||||||
for i in range(17):
|
for i in range(17):
|
||||||
output_asciiart(i)
|
output_asciiart(i)
|
||||||
|
@ -54,6 +67,7 @@ def run() -> int32:
|
||||||
test_output_int64()
|
test_output_int64()
|
||||||
test_output_uint32()
|
test_output_uint32()
|
||||||
test_output_uint64()
|
test_output_uint64()
|
||||||
|
test_output_float64()
|
||||||
test_output_asciiart()
|
test_output_asciiart()
|
||||||
test_output_int32_list()
|
test_output_int32_list()
|
||||||
test_output_str_family()
|
test_output_str_family()
|
||||||
|
|
|
@ -354,7 +354,12 @@ fn main() {
|
||||||
|
|
||||||
main.link_in_module(other).unwrap();
|
main.link_in_module(other).unwrap();
|
||||||
}
|
}
|
||||||
main.link_in_module(load_irrt(&context)).unwrap();
|
|
||||||
|
let irrt = load_irrt(&context);
|
||||||
|
if emit_llvm {
|
||||||
|
irrt.write_bitcode_to_path(Path::new("irrt.bc"));
|
||||||
|
}
|
||||||
|
main.link_in_module(irrt).unwrap();
|
||||||
|
|
||||||
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 {
|
||||||
|
|
Loading…
Reference in New Issue
Just keep them, they can be used for debugging if the test failed.
If the test failed, the files won't be deleted anyways because the script will exit after running
diff
, so it doesn't matter.