Skip to content

Commit

Permalink
refactor(rivetc.codegen): use slices to implement variadic arguments
Browse files Browse the repository at this point in the history
Previously, `DynArray` was used for variadic arguments, but that meant
making an extra allocation on the heap even if no argument was passed
(since `DynArray` is boxed). With this change, that extra allocation is
removed.
  • Loading branch information
StunxFS committed Dec 26, 2023
1 parent 98d348f commit 3b3c4ba
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 37 deletions.
10 changes: 10 additions & 0 deletions lib/core/src/Slice.ri
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ struct Slice {
elem_size: uint;
len: uint;

#[inline]
func new(ptr: rawptr, elem_size: uint) -> Self {
return Slice(ptr, elem_size);
}

#[unsafe; inline]
func from_array(arr: rawptr, elem_size: uint, len: uint) -> Self {
return Self(arr, elem_size, len);
}

func get(&self, idx: uint) -> rawptr {
if idx >= self.len {
runtime_error("slice index out of range (index: {}, len: {})", idx, self.len);
Expand Down
6 changes: 3 additions & 3 deletions lib/core/src/TokenIterator.ri
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Copyright (C) 2023-present Jose Mendoza - All rights reserved. Use of this
// source code is governed by an MIT license that can be found in the LICENSE
// Copyright (C) 2023-present Jose Mendoza - All rights reserved. Use of this
// source code is governed by an MIT license that can be found in the LICENSE
// file.

pub struct TokenIterator {
buffer: string;
delimiter_bytes: []uint8;
delimiter_bytes: [:]uint8;
mut index: uint;

/// Returns a slice of the current token, or none if tokenization is
Expand Down
8 changes: 4 additions & 4 deletions lib/rivet/src/checker/types.ri
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,15 @@ extend Checker {
got_sym := got.symbol() ?? return false;

if expected is .Variadic {
vec_info := @as(ast.TypeInfo.DynArray, expected_sym.info);
slice_info := @as(ast.TypeInfo.Slice, expected_sym.info);
if got is .Variadic(variadic) {
return vec_info.elem_type == variadic.inner;
return slice_info.elem_type == variadic.inner;
}
elem_sym := vec_info.elem_type.symbol()?;
elem_sym := slice_info.elem_type.symbol()?;
if got_sym.info is .Trait(trait_info) && elem_sym in trait_info.bases {
return true;
}
return self.check_compatible_types(got, vec_info.elem_type);
return self.check_compatible_types(got, slice_info.elem_type);
}

if expected is .Func && got is .Func {
Expand Down
2 changes: 1 addition & 1 deletion lib/rivet/src/resolver/types.ri
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ extend Resolver {
if elem_sym.info is .Trait(mut trait_info) {
trait_info.has_objects = true;
}
variadic.sym = self.env.universe.add_or_get_dyn_array(variadic.inner, false);
variadic.sym = self.env.universe.add_or_get_slice(variadic.inner, false);
true
} else {
false
Expand Down
67 changes: 40 additions & 27 deletions rivetc/src/codegen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ def gen_stmt(self, stmt):
ir.InstKind.GetElementPtr, [iterable, idx], value_t_ir
)
else:
value = ir.Selector(ir.VOID_PTR_T, iterable, ir.Name("ptr"))
value = ir.Selector(ir.RAWPTR_T, iterable, ir.Name("ptr"))
value = ir.Inst(
ir.InstKind.Add, [
ir.Inst(
Expand Down Expand Up @@ -592,12 +592,12 @@ def gen_expr_with_cast(self, expected_typ_, expr, custom_tmp = None):

if isinstance(
res_expr.typ, ir.Pointer
) and res_expr.typ != ir.VOID_PTR_T:
) and res_expr.typ != ir.RAWPTR_T:
if isinstance(expected_typ, ir.Pointer):
if not expected_typ.is_managed:
nr_level_expected = expected_typ.nr_level()
nr_level = res_expr.typ.nr_level()
if nr_level > nr_level_expected and expected_typ != ir.VOID_PTR_T:
if nr_level > nr_level_expected and expected_typ != ir.RAWPTR_T:
while nr_level > nr_level_expected:
if isinstance(
res_expr.typ, ir.Pointer
Expand All @@ -622,7 +622,7 @@ def gen_expr_with_cast(self, expected_typ_, expr, custom_tmp = None):
elif isinstance(
expected_typ, ir.Pointer
) and not expected_typ.is_managed and res_expr.typ not in (
ir.VOID_T, ir.VOID_PTR_T
ir.VOID_T, ir.RAWPTR_T
):
nr_level_expected = expected_typ.nr_level()
nr_level = res_expr.typ.nr_level(
Expand Down Expand Up @@ -682,7 +682,7 @@ def gen_expr(self, expr, custom_tmp = None):
elif isinstance(expr, ast.ParExpr):
return self.gen_expr(expr.expr)
elif isinstance(expr, ast.NoneLiteral):
return ir.NoneLit(ir.VOID_PTR_T)
return ir.NoneLit(ir.RAWPTR_T)
elif isinstance(expr, ast.BoolLiteral):
return ir.IntLit(ir.BOOL_T, str(int(expr.lit)))
elif isinstance(expr, ast.CharLiteral):
Expand Down Expand Up @@ -803,7 +803,7 @@ def gen_expr(self, expr, custom_tmp = None):
ir.InstKind.Call, [
ir.Name("_R4core10trait_castF"),
ir.Selector(
ir.VOID_PTR_T, res, ir.Name("obj")
ir.RAWPTR_T, res, ir.Name("obj")
),
ir.Selector(
ir.UINT_T, res, ir.Name("_idx_")
Expand Down Expand Up @@ -1162,7 +1162,7 @@ def gen_expr(self, expr, custom_tmp = None):
)
args.append(
ir.Selector(
ir.VOID_PTR_T,
ir.RAWPTR_T,
ir.Inst(
ir.InstKind.LoadPtr, [
ir.Inst(
Expand All @@ -1186,7 +1186,7 @@ def gen_expr(self, expr, custom_tmp = None):
if left_sym.kind == TypeKind.Trait and not expr.sym.has_body:
args.append(
ir.Selector(
ir.VOID_PTR_T, self_expr, ir.Name("obj")
ir.RAWPTR_T, self_expr, ir.Name("obj")
)
)
else:
Expand Down Expand Up @@ -1283,7 +1283,7 @@ def gen_expr(self, expr, custom_tmp = None):
)
args.append(self.variadic_args(vargs, var_arg.typ.typ))
else:
args.append(self.empty_dyn_array(var_arg.typ.symbol()))
args.append(self.empty_slice(var_arg.typ.symbol()))
if expr.sym.ret_typ == self.comp.never_t:
self.gen_defer_stmts(
scope = expr.scope, run_defer_previous = True
Expand Down Expand Up @@ -1492,7 +1492,7 @@ def gen_expr(self, expr, custom_tmp = None):
ir.Inst(
ir.InstKind.Cmp,
[ir.Name("=="), left,
ir.NoneLit(ir.VOID_PTR_T)]
ir.NoneLit(ir.RAWPTR_T)]
), panic_l, exit_l
)
value = left
Expand Down Expand Up @@ -1744,7 +1744,7 @@ def gen_expr(self, expr, custom_tmp = None):
op = "==" if expr.op == Kind.Eq else "!="
return ir.Inst(
ir.InstKind.Cmp,
[op, left, ir.NoneLit(ir.VOID_PTR_T)], ir.BOOL_T
[op, left, ir.NoneLit(ir.RAWPTR_T)], ir.BOOL_T
)
val = ir.Selector(ir.BOOL_T, left, ir.Name("is_none"))
if expr.op == Kind.Ne:
Expand All @@ -1762,7 +1762,7 @@ def gen_expr(self, expr, custom_tmp = None):
cond = ir.Inst(
ir.InstKind.Cmp,
[ir.Name("=="), left,
ir.NoneLit(ir.VOID_PTR_T)]
ir.NoneLit(ir.RAWPTR_T)]
)
else:
cond = ir.Selector(ir.BOOL_T, left, ir.Name("is_none"))
Expand Down Expand Up @@ -1879,7 +1879,7 @@ def gen_expr(self, expr, custom_tmp = None):
val = ir.Inst(
ir.InstKind.Cast, [
ir.Selector(
ir.VOID_PTR_T, left, ir.Name("obj")
ir.RAWPTR_T, left, ir.Name("obj")
), var_t2
]
)
Expand Down Expand Up @@ -2244,7 +2244,7 @@ def gen_expr(self, expr, custom_tmp = None):
val = ir.Inst(
ir.InstKind.Cast, [
ir.Selector(
ir.VOID_PTR_T, match_expr,
ir.RAWPTR_T, match_expr,
ir.Name("obj")
), var_t
]
Expand Down Expand Up @@ -2591,7 +2591,7 @@ def runtime_error(self, msg):
self.cur_func.add_call(
"_R4core13runtime_errorF", [
self.gen_string_literal(utils.smart_quote(msg, False)),
self.empty_dyn_array(self.comp.universe["[]core.Stringable"])
self.empty_slice(self.comp.universe["[]core.Stringable"])
]
)

Expand All @@ -2601,7 +2601,7 @@ def variadic_args(self, vargs, var_arg_typ_):
elem_size, _ = self.comp.type_size(var_arg_typ_)
return ir.Inst(
ir.InstKind.Call, [
ir.Name("_R4core8DynArray19from_array_no_allocF"),
ir.Name("_R4core5Slice10from_arrayF"),
ir.ArrayLit(self.ir_type(var_arg_typ_), vargs),
ir.IntLit(ir.UINT_T, str(elem_size)),
ir.IntLit(ir.UINT_T, str(len(vargs)))
Expand All @@ -2610,13 +2610,13 @@ def variadic_args(self, vargs, var_arg_typ_):

def default_value(self, typ, custom_tmp = None):
if isinstance(typ, (type.Ptr, type.Func)):
return ir.NoneLit(ir.VOID_PTR_T)
return ir.NoneLit(ir.RAWPTR_T)
if isinstance(typ, type.Option):
if typ.is_pointer():
return ir.NoneLit(ir.VOID_PTR_T)
return ir.NoneLit(ir.RAWPTR_T)
return self.option_none(typ)
if typ == self.comp.rune_t:
return ir.RuneLit("\\0")
return ir.RuneLit("0")
elif typ in (
self.comp.bool_t, self.comp.int8_t, self.comp.int16_t,
self.comp.int32_t, self.comp.int64_t, self.comp.uint8_t,
Expand All @@ -2637,6 +2637,8 @@ def default_value(self, typ, custom_tmp = None):
return ir.ArrayLit(
self.ir_type(typ), [self.default_value(typ_sym.info.elem_typ)]
)
elif typ_sym.kind == TypeKind.Slice:
return self.empty_slice(typ_sym)
elif typ_sym.kind == TypeKind.DynArray:
return self.empty_dyn_array(typ_sym)
elif typ_sym.kind == TypeKind.Enum:
Expand Down Expand Up @@ -2671,7 +2673,7 @@ def default_value(self, typ, custom_tmp = None):
elif typ_sym.kind == TypeKind.Trait:
if typ_sym.default_value:
return self.gen_expr_with_cast(typ, typ_sym.default_value)
return ir.NoneLit(ir.VOID_PTR_T)
return ir.NoneLit(ir.RAWPTR_T)
return None

def empty_dyn_array(self, typ_sym, cap = None):
Expand All @@ -2685,6 +2687,17 @@ def empty_dyn_array(self, typ_sym, cap = None):
]
)

def empty_slice(self, typ_sym):
elem_typ = typ_sym.info.elem_typ
_, _ = self.comp.type_size(elem_typ)
return ir.Inst(
ir.InstKind.Call, [
ir.Name("_R4core5Slice3newF"),
ir.Ident(ir.RAWPTR_T, "NULL"),
ir.IntLit(ir.UINT_T, "0")
]
)

def gen_string_literal(self, lit, size = None):
size = size or utils.bytestr(lit).len
if size == 0:
Expand Down Expand Up @@ -2779,14 +2792,14 @@ def trait_value(self, value, value_typ, trait_typ):
], ir.UINT_T
)
self.cur_func.store(
ir.Selector(ir.VOID_PTR_T, tmp, ir.Name("obj")),
ir.Selector(ir.VOID_PTR_T, value, ir.Name("obj"))
ir.Selector(ir.RAWPTR_T, tmp, ir.Name("obj")),
ir.Selector(ir.RAWPTR_T, value, ir.Name("obj"))
)
else:
vtbl_idx_x = trait_sym.info.indexof(value_sym)
index = ir.IntLit(ir.UINT_T, str(vtbl_idx_x))
self.cur_func.store(
ir.Selector(ir.VOID_PTR_T, tmp, ir.Name("obj")), value
ir.Selector(ir.RAWPTR_T, tmp, ir.Name("obj")), value
)
self.cur_func.store(ir.Selector(ir.UINT_T, tmp, ir.Name("_id_")), index)
self.cur_func.store(
Expand Down Expand Up @@ -2915,7 +2928,7 @@ def gen_guard_expr(self, expr, entry_label, exit_label, gen_cond = True):
cond = ir.Inst(
ir.InstKind.Cmp,
[ir.Name("!="), gexpr,
ir.NoneLit(ir.VOID_PTR_T)]
ir.NoneLit(ir.RAWPTR_T)]
)
self.cur_func.inline_alloca(self.ir_type(expr.typ), var_name, gexpr)
else:
Expand Down Expand Up @@ -2978,7 +2991,7 @@ def ir_type(self, typ, gen_self_arg = False):
elif isinstance(typ, type.Func):
args = []
if gen_self_arg:
args.append(ir.VOID_PTR_T)
args.append(ir.RAWPTR_T)
for arg in typ.args:
arg_t = self.ir_type(arg.typ)
if arg.is_mut and not isinstance(arg_t, ir.Pointer):
Expand Down Expand Up @@ -3006,7 +3019,7 @@ def ir_type(self, typ, gen_self_arg = False):
elif typ_sym.kind == TypeKind.Never:
return ir.VOID_T
elif typ_sym.kind == TypeKind.None_:
return ir.VOID_PTR_T
return ir.RAWPTR_T
elif typ_sym.kind == TypeKind.Enum:
if typ_sym.info.is_tagged:
typ = ir.Type(cg_utils.mangle_symbol(typ_sym))
Expand Down Expand Up @@ -3066,7 +3079,7 @@ def gen_types(self):
ir.Field("_rc_", ir.UINT_T),
ir.Field("_idx_", ir.UINT_T),
ir.Field("_id_", ir.UINT_T),
ir.Field("obj", ir.VOID_PTR_T),
ir.Field("obj", ir.RAWPTR_T),
]
for f in ts.fields:
f_typ = self.ir_type(f.typ)
Expand Down
2 changes: 1 addition & 1 deletion rivetc/src/codegen/ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def __eq__(self, other):
return str(self) == str(other)

VOID_T = Type("void")
VOID_PTR_T = VOID_T.ptr()
RAWPTR_T = VOID_T.ptr()
BOOL_T = Type("bool")
RUNE_T = Type("rune")
C_INT_T = Type("int")
Expand Down
2 changes: 1 addition & 1 deletion rivetc/src/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ def resolve_type(self, typ):
elem_sym = typ.typ.symbol()
if elem_sym.kind == type.TypeKind.Trait:
elem_sym.info.has_objects = True
typ.resolve(self.comp.universe.add_or_get_dyn_array(typ.typ))
typ.resolve(self.comp.universe.add_or_get_slice(typ.typ))
return True
elif isinstance(typ, type.Array):
if self.resolve_type(typ.typ):
Expand Down

0 comments on commit 3b3c4ba

Please sign in to comment.