Skip to content

Commit

Permalink
Merge pull request #6448 from roc-lang/dev-backend-glue-new
Browse files Browse the repository at this point in the history
glue with the dev backend works again
  • Loading branch information
folkertdev authored Jan 29, 2024
2 parents 1c62a41 + 28ab816 commit eadc0d3
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 45 deletions.
24 changes: 21 additions & 3 deletions crates/compiler/gen_dev/src/generic64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2949,7 +2949,11 @@ impl<
self.load_layout_alignment(list_layout, Symbol::DEV_TMP);

// Load element_width argument (usize).
self.load_layout_stack_size(*ret_layout, Symbol::DEV_TMP2);
let element_layout = match self.interner().get_repr(*ret_layout) {
LayoutRepr::Builtin(Builtin::List(e)) => e,
_ => unreachable!(),
};
self.load_layout_stack_size(element_layout, Symbol::DEV_TMP2);

// Load UpdateMode.Immutable argument (0u8)
let u8_layout = Layout::U8;
Expand Down Expand Up @@ -4871,14 +4875,28 @@ impl<

// move a zero into the lower 8 bytes
ASM::mov_reg64_imm64(buf, tmp_reg, 0x0);
ASM::mov_base32_reg64(buf, base_offset, tmp_reg);
ASM::mov_base32_reg64(buf, base_offset + 8, tmp_reg);

ASM::mov_base32_reg64(buf, base_offset + 8, src_reg);
ASM::mov_base32_reg64(buf, base_offset, src_reg);

self.free_symbol(&tmp);

return;
}
(U128, I128) | (I128, U128) => {
let to_offset = self.storage_manager.claim_stack_area_layout(
self.layout_interner,
*dst,
Layout::from_int_width(target),
);

let (from_offset, size) = self.storage_manager.stack_offset_and_size(src);

self.storage_manager
.copy_to_stack_offset(buf, size, from_offset, to_offset);

return;
}

_ => {}
}
Expand Down
22 changes: 22 additions & 0 deletions crates/compiler/gen_dev/src/object_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@ pub fn build_module<'a, 'r>(
layout_interner: &'r mut STLayoutInterner<'a>,
target: &Triple,
procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>,
) -> Object<'a> {
let module_object = build_module_help(env, interns, layout_interner, target, procedures);

if std::env::var("ROC_DEV_WRITE_OBJ").is_ok() {
let module_out = module_object
.write()
.expect("failed to build output object");

let file_path = std::env::temp_dir().join("app.o");
println!("gen-test object file written to {}", file_path.display());
std::fs::write(&file_path, module_out).expect("failed to write object to file");
}

module_object
}

fn build_module_help<'a, 'r>(
env: &'r Env<'a>,
interns: &'r mut Interns,
layout_interner: &'r mut STLayoutInterner<'a>,
target: &Triple,
procedures: MutMap<(symbol::Symbol, ProcLayout<'a>), Proc<'a>>,
) -> Object<'a> {
match target {
Triple {
Expand Down
24 changes: 24 additions & 0 deletions crates/compiler/test_gen/src/gen_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,30 @@ fn list_append_longer_list() {
);
}

#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_append_record() {
assert_evals_to!(
indoc!(
r#"
[
{ name: "foo", content: "cfoo" },
{ name: "bar", content: "cbar" },
{ name: "baz", content: "cbaz" },
]
|> List.append { name: "spam", content: "cspam" }
"#
),
RocList::from_slice(&[
(RocStr::from("cfoo"), RocStr::from("foo"),),
(RocStr::from("cbar"), RocStr::from("bar"),),
(RocStr::from("cbaz"), RocStr::from("baz"),),
(RocStr::from("cspam"), RocStr::from("spam"),),
]),
RocList<(RocStr, RocStr)>
);
}

#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_prepend() {
Expand Down
5 changes: 3 additions & 2 deletions crates/compiler/test_gen/src/gen_num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2320,7 +2320,7 @@ num_conversion_tests! {
to_i64_truncate_wraps, "10_000_000_000_000_000_000i128", -8446744073709551616
)
"Num.toI128", i128, (
to_i128_same_width, "15u128", 15
to_i128_same_width, "15u128", 15, ["gen-dev"]
to_i128_extend, "15i8", 15
)
"Num.toU8", u8, (
Expand All @@ -2347,8 +2347,9 @@ num_conversion_tests! {
to_u64_truncate_wraps, "10_000_000_000_000_000_000_000i128", 1864712049423024128
)
"Num.toU128", u128, (
to_u128_same_width, "15i128", 15
to_u128_same_width, "15i128", 15, ["gen-dev"]
to_u128_extend, "15i8", 15
to_u128_big, "11562537357600483583u64", 11562537357600483583, ["gen-dev"]
)
"Num.toNat", usize, (
to_nat_same_width, "15i64", 15, ["gen-wasm", "gen-dev"]
Expand Down
6 changes: 0 additions & 6 deletions crates/compiler/test_gen/src/helpers/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,6 @@ pub fn helper(
let builtins_host_tempfile =
roc_bitcode::host_tempfile().expect("failed to write host builtins object to tempfile");

if std::env::var("ROC_DEV_WRITE_OBJ").is_ok() {
let file_path = std::env::temp_dir().join("app.o");
println!("gen-test object file written to {}", file_path.display());
std::fs::copy(&app_o_file, file_path).unwrap();
}

let (mut child, dylib_path) = link(
&target,
app_o_file.clone(),
Expand Down
104 changes: 70 additions & 34 deletions crates/glue/src/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,46 +131,19 @@ pub fn generate(
}

let lib = unsafe { Library::new(lib_path) }.unwrap();
type MakeGlueReturnType =
roc_std::RocResult<roc_std::RocList<roc_type::File>, roc_std::RocStr>;
type MakeGlue = unsafe extern "C" fn(
*mut RocCallResult<MakeGlueReturnType>,
&roc_std::RocList<roc_type::Types>,
);

let make_glue: libloading::Symbol<MakeGlue> = unsafe {
lib.get("roc__makeGlueForHost_1_exposed_generic".as_bytes())
.unwrap_or_else(|_| panic!("Unable to load glue function"))
};
let roc_types: roc_std::RocList<roc_type::Types> =
types.iter().map(|x| x.into()).collect();
let mut files =
RocCallResult::new(roc_std::RocResult::err(roc_std::RocStr::empty()));
unsafe { make_glue(&mut files, &roc_types) };

// Roc will free data passed into it. So forget that data.
std::mem::forget(roc_types);

let files: Result<roc_std::RocList<roc_type::File>, roc_std::RocStr> =
match Result::from(files) {
Err((msg, tag)) => match tag {
CrashTag::Roc => panic!(r#"Roc failed with message: "{msg}""#),
CrashTag::User => panic!(r#"User crash with message: "{msg}""#),
},
Ok(x) => x.into(),
};

let files = files.unwrap_or_else(|err| {
eprintln!("Glue generation failed: {err}");

process::exit(1);
});

// NOTE: DO NOT DROP LIB! the return value will include static roc strings that
// are only kept alive when the dynamic library is not unloaded!
let files = call_roc_make_glue(&lib, backend, roc_types);

for roc_type::File { name, content } in &files {
let valid_name = PathBuf::from(name.as_str())
.components()
.all(|comp| matches!(comp, Component::CurDir | Component::Normal(_)));
if !valid_name {
eprintln!("File name was invalid: {}", &name);
if !valid_name || name.is_empty() {
eprintln!("File name was invalid: {:?}", &name);

process::exit(1);
}
Expand Down Expand Up @@ -243,6 +216,69 @@ pub fn generate(
}
}

fn call_roc_make_glue(
lib: &Library,
backend: CodeGenBackend,
roc_types: roc_std::RocList<roc_type::Types>,
) -> roc_std::RocList<roc_type::File> {
let roc_call_result = match backend {
CodeGenBackend::Assembly(_) => {
type MakeGlueReturnType = RocCallResult<
roc_std::RocResult<roc_std::RocList<roc_type::File>, roc_std::RocStr>,
>;
type MakeGlue =
unsafe extern "C" fn(roc_std::RocList<roc_type::Types>) -> MakeGlueReturnType;

let name_of_main = "test_main";

let make_glue: libloading::Symbol<MakeGlue> = unsafe {
lib.get(name_of_main.as_bytes())
.unwrap_or_else(|_| panic!("Unable to load glue function"))
};

unsafe { make_glue(roc_types) }
}
CodeGenBackend::Llvm(_) => {
type MakeGlueReturnType =
roc_std::RocResult<roc_std::RocList<roc_type::File>, roc_std::RocStr>;
type MakeGlue = unsafe extern "C" fn(
*mut RocCallResult<MakeGlueReturnType>,
&roc_std::RocList<roc_type::Types>,
);

let name_of_main = "roc__makeGlueForHost_1_exposed_generic";

let make_glue: libloading::Symbol<MakeGlue> = unsafe {
lib.get(name_of_main.as_bytes())
.unwrap_or_else(|_| panic!("Unable to load glue function"))
};
let mut files = RocCallResult::new(roc_std::RocResult::err(roc_std::RocStr::empty()));
unsafe { make_glue(&mut files, &roc_types) };

// Roc will free data passed into it. So forget that data.
std::mem::forget(roc_types);

files
}

CodeGenBackend::Wasm => todo!(),
};

match Result::from(roc_call_result) {
Err((msg, tag)) => match tag {
CrashTag::Roc => panic!(r#"Roc failed with message: "{msg}""#),
CrashTag::User => panic!(r#"User crash with message: "{msg}""#),
},
Ok(files_or_error) => match Result::from(files_or_error) {
Err(err) => {
eprintln!("Glue generation failed: {err}");
process::exit(1);
}
Ok(files) => files,
},
}
}

fn number_lambda_sets(subs: &Subs, initial: Variable) -> Vec<Variable> {
let mut lambda_sets = vec![];
let mut stack = vec![initial];
Expand Down

0 comments on commit eadc0d3

Please sign in to comment.