Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add crate for mangling Shiika methods #323

Merged
merged 4 commits into from
Dec 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions lib/shiika_ffi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
name = "shiika_ffi"
version = "0.1.0"
edition = "2018"
3 changes: 3 additions & 0 deletions lib/shiika_ffi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# shiika_ffi

Currently this crate just provides `mangle_method` function which returns the llvm function name of a Shiika method.
23 changes: 23 additions & 0 deletions lib/shiika_ffi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pub fn mangle_method(method_name: &str) -> String {
method_name
// Replace '_' to use '_' as delimiter
.replace("_", "__")
// Replace symbols to make the function callable from Rust(skc_rustlib)
.replace("::", "_")
.replace("Meta:", "Meta_")
.replace("#", "_")
.replace("+@", "uplus_")
.replace("-@", "uminus_")
.replace("+", "add_")
.replace("-", "sub_")
.replace("*", "mul_")
.replace("/", "div_")
.replace("%", "mod_")
.replace("==", "eq_")
.replace("<", "lt_")
.replace(">", "gt_")
.replace("<=", "le_")
.replace(">=", "ge_")
.replace("[]", "aref_")
.replace("[]=", "aset_")
}
12 changes: 12 additions & 0 deletions lib/shiika_ffi_macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "shiika_ffi_macro"
version = "0.1.0"
edition = "2018"

[lib]
proc-macro = true

[dependencies]
shiika_ffi = { path = "../shiika_ffi" }
syn = { version = "1.0.82", features = ["full"] }
quote = "1.0"
3 changes: 3 additions & 0 deletions lib/shiika_ffi_macro/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# shiika_ffi_macro

This crate provides `#[shiika_method(...)]` attribute which expands into `#[export_name = "..."]`.
17 changes: 17 additions & 0 deletions lib/shiika_ffi_macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use proc_macro::TokenStream;
use quote::quote;
use shiika_ffi::mangle_method;
use syn::parse_macro_input;

#[proc_macro_attribute]
pub fn shiika_method(args: TokenStream, input: TokenStream) -> TokenStream {
let method_name = parse_macro_input!(args as syn::LitStr);
let function_definition = parse_macro_input!(input as syn::ItemFn);

let mangled_name = mangle_method(&method_name.value());
let gen = quote! {
#[export_name = #mangled_name]
#function_definition
};
gen.into()
}
1 change: 1 addition & 0 deletions lib/skc_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
shiika_core = { path = "../shiika_core" }
shiika_ast = { path = "../shiika_ast" }
shiika_ffi = { path = "../shiika_ffi" }
skc_hir = { path = "../skc_hir" }
skc_mir = { path = "../skc_mir" }
anyhow = "1.0"
Expand Down
32 changes: 23 additions & 9 deletions lib/skc_codegen/src/boxing.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::utils::llvm_func_name;
use crate::values::*;
use crate::CodeGen;
use inkwell::types::*;
Expand Down Expand Up @@ -137,52 +138,65 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
let str_i8ptr = function.get_nth_param(0).unwrap();
let bytesize = function.get_nth_param(1).unwrap().into_int_value();
let args = vec![self.box_i8ptr(str_i8ptr), self.box_int(&bytesize)];
let sk_str = self.call_method_func("Meta:String#new", receiver, &args, "sk_str");
let sk_str = self.call_method_func(
&method_fullname(&metaclass_fullname("String"), "new"),
receiver,
&args,
"sk_str",
);
self.build_return(&sk_str);
}

/// Convert LLVM bool(i1) into Shiika Bool
pub fn box_bool(&self, b: inkwell::values::IntValue<'run>) -> SkObj<'run> {
SkObj(self.call_llvm_func("box_bool", &[b.into()], "sk_bool"))
SkObj(self.call_llvm_func(&llvm_func_name("box_bool"), &[b.into()], "sk_bool"))
}

/// Convert Shiika Bool into LLVM bool(i1)
pub fn unbox_bool(&self, sk_bool: SkObj<'run>) -> inkwell::values::IntValue<'run> {
self.call_llvm_func("unbox_bool", &[sk_bool.0], "llvm_bool")
self.call_llvm_func(&llvm_func_name("unbox_bool"), &[sk_bool.0], "llvm_bool")
.into_int_value()
}

/// Convert LLVM int into Shiika Int
pub fn box_int(&self, i: &inkwell::values::IntValue<'run>) -> SkObj<'run> {
SkObj(self.call_llvm_func("box_int", &[i.as_basic_value_enum()], "sk_int"))
SkObj(self.call_llvm_func(
&llvm_func_name("box_int"),
&[i.as_basic_value_enum()],
"sk_int",
))
}

/// Convert Shiika Int into LLVM int
pub fn unbox_int(&self, sk_int: SkObj<'run>) -> inkwell::values::IntValue<'run> {
self.call_llvm_func("unbox_int", &[sk_int.0], "llvm_int")
self.call_llvm_func(&llvm_func_name("unbox_int"), &[sk_int.0], "llvm_int")
.into_int_value()
}

/// Convert LLVM float into Shiika Float
pub fn box_float(&self, fl: &inkwell::values::FloatValue<'run>) -> SkObj<'run> {
SkObj(self.call_llvm_func("box_float", &[fl.as_basic_value_enum()], "sk_float"))
SkObj(self.call_llvm_func(
&llvm_func_name("box_float"),
&[fl.as_basic_value_enum()],
"sk_float",
))
}

/// Convert Shiika Float into LLVM float
pub fn unbox_float(&self, sk_float: SkObj<'run>) -> inkwell::values::FloatValue<'run> {
self.call_llvm_func("unbox_float", &[sk_float.0], "llvm_float")
self.call_llvm_func(&llvm_func_name("unbox_float"), &[sk_float.0], "llvm_float")
.into_float_value()
}

/// Convert LLVM i8* into Shiika::Internal::Ptr
pub fn box_i8ptr(&self, p: inkwell::values::BasicValueEnum<'run>) -> SkObj<'run> {
SkObj(self.call_llvm_func("box_i8ptr", &[p], "sk_ptr"))
SkObj(self.call_llvm_func(&llvm_func_name("box_i8ptr"), &[p], "sk_ptr"))
}

/// Convert Shiika::Internal::Ptr into LLVM i8*
pub fn unbox_i8ptr(&self, sk_obj: SkObj<'run>) -> I8Ptr<'run> {
I8Ptr(
self.call_llvm_func("unbox_i8ptr", &[sk_obj.0], "llvm_ptr")
self.call_llvm_func(&llvm_func_name("unbox_i8ptr"), &[sk_obj.0], "llvm_ptr")
.into_pointer_value(),
)
}
Expand Down
75 changes: 56 additions & 19 deletions lib/skc_codegen/src/gen_exprs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::code_gen_context::*;
use crate::utils::*;
use crate::values::*;
use crate::CodeGen;
use anyhow::Result;
Expand Down Expand Up @@ -100,9 +101,13 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
captures,
ret_ty,
..
} => Ok(Some(
self.gen_lambda_expr(ctx, name, params, captures, ret_ty),
)),
} => Ok(Some(self.gen_lambda_expr(
ctx,
&llvm_func_name(name),
params,
captures,
ret_ty,
))),
HirSelfExpression => Ok(Some(self.gen_self_expression(ctx, &expr.ty))),
HirArrayLiteral { exprs } => self.gen_array_literal(ctx, exprs),
HirFloatLiteral { value } => Ok(Some(self.gen_float_literal(*value))),
Expand Down Expand Up @@ -598,8 +603,8 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
if ret_ty.is_void_type() {
let exit_status =
self.build_ivar_load(lambda_obj, FN_X_EXIT_STATUS_IDX, "@exit_status");
let eq = self.gen_llvm_func_call(
"Int#==",
let eq = self.gen_method_func_call(
&method_fullname(&class_fullname("Int"), "=="),
exit_status,
vec![self.box_int(&self.i64_type.const_int(EXIT_BREAK, false))],
);
Expand All @@ -611,11 +616,25 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
Ok(Some(SkObj(result)))
}

/// Generate llvm function call
fn gen_method_func_call(
&self,
method_fullname: &MethodFullname,
receiver_value: SkObj<'run>,
arg_values: Vec<SkObj<'run>>,
) -> SkObj<'run> {
self.gen_llvm_func_call(
&method_func_name(method_fullname),
receiver_value,
arg_values,
)
}

/// Generate llvm function call
// REFACTOR: make this public and make `receiver_value` optional
fn gen_llvm_func_call(
&self,
func_name: &str,
func_name: &LlvmFuncName,
receiver_value: SkObj<'run>,
arg_values: Vec<SkObj<'run>>,
) -> SkObj<'run> {
Expand Down Expand Up @@ -688,7 +707,7 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
fn gen_lambda_expr(
&self,
ctx: &mut CodeGenContext<'hir, 'run>,
func_name: &str,
func_name: &LlvmFuncName,
params: &[MethodParam],
captures: &'hir [HirLambdaCapture],
ret_ty: &TermTy,
Expand All @@ -698,7 +717,7 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
let mut arg_types = (1..=params.len()).map(|_| &obj_type).collect::<Vec<_>>();
arg_types.insert(0, fn_x_type);
let func_type = self.llvm_func_type(None, &arg_types, ret_ty);
self.module.add_function(func_name, func_type, None);
self.module.add_function(&func_name.0, func_type, None);

// eg. Fn1.new(fnptr, the_self, captures)
let cls_name = format!("Fn{}", params.len());
Expand All @@ -711,16 +730,20 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
let sk_ptr = self.box_i8ptr(fnptr_i8);
let the_self = self.gen_self_expression(ctx, &ty::raw("Object"));
let arg_values = vec![sk_ptr, the_self, self._gen_lambda_captures(ctx, captures)];
self.gen_llvm_func_call(&format!("Meta:{}#new", cls_name), meta, arg_values)
self.gen_method_func_call(
&method_fullname(&metaclass_fullname(cls_name), "new"),
meta,
arg_values,
)
}

fn _gen_lambda_captures(
&self,
ctx: &mut CodeGenContext<'hir, 'run>,
captures: &'hir [HirLambdaCapture],
) -> SkObj<'run> {
let ary = self.gen_llvm_func_call(
"Meta:Array#new",
let ary = self.gen_method_func_call(
&method_fullname(&metaclass_fullname("Array"), "new"),
self.gen_const_ref(&toplevel_const("Array")),
vec![],
);
Expand All @@ -740,7 +763,12 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
}
};
let obj = self.bitcast(item, &ty::raw("Object"), "capture_item");
self.call_method_func("Array#push", ary.clone(), &[obj], "_");
self.call_method_func(
&method_fullname(&class_fullname("Array"), "push"),
ary.clone(),
&[obj],
"_",
);
}
ary
}
Expand Down Expand Up @@ -769,15 +797,20 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
exprs: &'hir [HirExpression],
) -> Result<Option<SkObj<'run>>> {
let ary = self.call_method_func(
"Meta:Array#new",
&method_fullname(&metaclass_fullname("Array"), "new"),
self.gen_const_ref(&toplevel_const("Array")),
Default::default(),
"ary",
);
for expr in exprs {
let item = self.gen_expr(ctx, expr)?.unwrap();
let obj = self.bitcast(item, &ty::raw("Object"), "obj");
self.call_method_func("Array#push", ary.clone(), &[obj], "_");
self.call_method_func(
&method_fullname(&class_fullname("Array"), "push"),
ary.clone(),
&[obj],
"_",
);
}
Ok(Some(ary))
}
Expand All @@ -803,7 +836,11 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
let bytesize = self
.i64_type
.const_int(self.str_literals[*idx].len() as u64, false);
SkObj(self.call_llvm_func("gen_literal_string", &[i8ptr, bytesize.into()], "sk_str"))
SkObj(self.call_llvm_func(
&llvm_func_name("gen_literal_string"),
&[i8ptr, bytesize.into()],
"sk_str",
))
}

fn gen_boolean_literal(&self, value: bool) -> SkObj<'run> {
Expand Down Expand Up @@ -843,8 +880,8 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
self.builder.position_at_end(block);

let captures = self._gen_get_lambda_captures(ctx);
let item = self.gen_llvm_func_call(
"Array#[]",
let item = self.gen_method_func_call(
&method_fullname(&class_fullname("Array"), "[]"),
captures,
vec![self.gen_decimal_literal(*idx_in_captures as i64)],
);
Expand Down Expand Up @@ -884,8 +921,8 @@ impl<'hir, 'run, 'ictx> CodeGen<'hir, 'run, 'ictx> {
self.builder.position_at_end(block);

let captures = self._gen_get_lambda_captures(ctx);
let ptr_ = self.gen_llvm_func_call(
"Array#[]",
let ptr_ = self.gen_method_func_call(
&method_fullname(&class_fullname("Array"), "[]"),
captures,
vec![self.gen_decimal_literal(*idx_in_captures as i64)],
);
Expand Down
Loading