Add sizeof & alignof builtins
This commit is contained in:
parent
2a3e2171b0
commit
800de413cf
13 changed files with 178 additions and 95 deletions
|
|
@ -670,8 +670,7 @@ func unlock_mutex(mutex: mutex mut*):
|
||||||
|
|
||||||
func make_default_scene() -> scene:
|
func make_default_scene() -> scene:
|
||||||
let object_count = 8ul
|
let object_count = 8ul
|
||||||
// No sizeof yet...
|
let objects = allocate(object_count * sizeof(object)) as object mut*
|
||||||
let objects = allocate(object_count * 20ul * 4ul) as object mut*
|
|
||||||
|
|
||||||
// Filling all objects in the same function overflows the max stack size
|
// Filling all objects in the same function overflows the max stack size
|
||||||
// dictated by arm64 limitations (add immediate is bound by 12 bits => 4Kb)
|
// dictated by arm64 limitations (add immediate is bound by 12 bits => 4Kb)
|
||||||
|
|
@ -814,8 +813,8 @@ func main():
|
||||||
mut report_count = 0u
|
mut report_count = 0u
|
||||||
|
|
||||||
let thread_count = 9ul
|
let thread_count = 9ul
|
||||||
let threads = allocate(thread_count * 8ul) as thread mut*
|
let threads = allocate(thread_count * sizeof(thread)) as thread mut*
|
||||||
let threads_data = allocate(thread_count * 104ul) as thread_data mut*
|
let threads_data = allocate(thread_count * sizeof(thread_data)) as thread_data mut*
|
||||||
|
|
||||||
mut th = 0ul
|
mut th = 0ul
|
||||||
while th < thread_count:
|
while th < thread_count:
|
||||||
|
|
@ -825,7 +824,7 @@ func main():
|
||||||
data.camera = camera
|
data.camera = camera
|
||||||
data.ystart = th
|
data.ystart = th
|
||||||
data.ystep = thread_count
|
data.ystep = thread_count
|
||||||
data.done_mutex = allocate(64ul) as mutex mut*
|
data.done_mutex = allocate(sizeof(mutex)) as mutex mut*
|
||||||
create_mutex(data.done_mutex)
|
create_mutex(data.done_mutex)
|
||||||
data.done = 0ul
|
data.done = 0ul
|
||||||
threads[th] = create_thread(thread_func, data as unit mut*)
|
threads[th] = create_thread(thread_func, data as unit mut*)
|
||||||
|
|
|
||||||
29
libs/ast/include/pslang/ast/builtins.hpp
Normal file
29
libs/ast/include/pslang/ast/builtins.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <pslang/ast/expression_fwd.hpp>
|
||||||
|
#include <pslang/ast/type_fwd.hpp>
|
||||||
|
#include <pslang/ast/location.hpp>
|
||||||
|
#include <pslang/types/type_fwd.hpp>
|
||||||
|
|
||||||
|
namespace pslang::ast
|
||||||
|
{
|
||||||
|
|
||||||
|
struct sizeof_operator
|
||||||
|
{
|
||||||
|
expression_ptr expression;
|
||||||
|
type_ptr type;
|
||||||
|
location location;
|
||||||
|
types::type_ptr inferred_source_type = nullptr;
|
||||||
|
types::type_ptr inferred_type = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct alignof_operator
|
||||||
|
{
|
||||||
|
expression_ptr expression;
|
||||||
|
type_ptr type;
|
||||||
|
location location;
|
||||||
|
types::type_ptr inferred_source_type = nullptr;
|
||||||
|
types::type_ptr inferred_type = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include <pslang/ast/array.hpp>
|
#include <pslang/ast/array.hpp>
|
||||||
#include <pslang/ast/struct.hpp>
|
#include <pslang/ast/struct.hpp>
|
||||||
#include <pslang/ast/control.hpp>
|
#include <pslang/ast/control.hpp>
|
||||||
|
#include <pslang/ast/builtins.hpp>
|
||||||
#include <pslang/ast/expression_fwd.hpp>
|
#include <pslang/ast/expression_fwd.hpp>
|
||||||
#include <pslang/types/type_fwd.hpp>
|
#include <pslang/types/type_fwd.hpp>
|
||||||
|
|
||||||
|
|
@ -42,7 +43,9 @@ namespace pslang::ast
|
||||||
array,
|
array,
|
||||||
array_access,
|
array_access,
|
||||||
field_access,
|
field_access,
|
||||||
if_expression
|
if_expression,
|
||||||
|
sizeof_operator,
|
||||||
|
alignof_operator
|
||||||
>;
|
>;
|
||||||
|
|
||||||
struct expression
|
struct expression
|
||||||
|
|
|
||||||
|
|
@ -13,53 +13,8 @@ namespace pslang::ast
|
||||||
{
|
{
|
||||||
using const_expression_visitor::apply;
|
using const_expression_visitor::apply;
|
||||||
|
|
||||||
template <typename T>
|
template <typename Node>
|
||||||
location apply(primitive_literal_base<T> const & node)
|
location apply(Node const & node)
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
location apply(identifier const & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
location apply(unary_operation const & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
location apply(binary_operation const & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
location apply(cast_operation const & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
location apply(function_call const & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
location apply(array const & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
location apply(array_access const & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
location apply(field_access const & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
location apply(if_expression const & node)
|
|
||||||
{
|
{
|
||||||
return node.location;
|
return node.location;
|
||||||
}
|
}
|
||||||
|
|
@ -76,47 +31,8 @@ namespace pslang::ast
|
||||||
return std::make_unique<types::type>(types::primitive_type{types::primitive_type_base<T>{}});
|
return std::make_unique<types::type>(types::primitive_type{types::primitive_type_base<T>{}});
|
||||||
}
|
}
|
||||||
|
|
||||||
types::type_ptr apply(identifier const & node)
|
template <typename Node>
|
||||||
{
|
types::type_ptr apply(Node const & node)
|
||||||
return node.inferred_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
types::type_ptr apply(unary_operation const & node)
|
|
||||||
{
|
|
||||||
return node.inferred_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
types::type_ptr apply(binary_operation const & node)
|
|
||||||
{
|
|
||||||
return node.inferred_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
types::type_ptr apply(cast_operation const & node)
|
|
||||||
{
|
|
||||||
return node.inferred_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
types::type_ptr apply(function_call const & node)
|
|
||||||
{
|
|
||||||
return node.inferred_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
types::type_ptr apply(array const & node)
|
|
||||||
{
|
|
||||||
return node.inferred_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
types::type_ptr apply(array_access const & node)
|
|
||||||
{
|
|
||||||
return node.inferred_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
types::type_ptr apply(field_access const & node)
|
|
||||||
{
|
|
||||||
return node.inferred_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
types::type_ptr apply(if_expression const & node)
|
|
||||||
{
|
{
|
||||||
return node.inferred_type;
|
return node.inferred_type;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -367,6 +367,38 @@ namespace pslang::ast
|
||||||
child(*node.if_true);
|
child(*node.if_true);
|
||||||
child(*node.if_false);
|
child(*node.if_false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void apply(sizeof_operator const & node)
|
||||||
|
{
|
||||||
|
put_indent(out, options);
|
||||||
|
if (node.expression)
|
||||||
|
{
|
||||||
|
out << "sizeof\n";
|
||||||
|
child(*node.expression);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out << "sizeof ";
|
||||||
|
print(out, *node.type);
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply(alignof_operator const & node)
|
||||||
|
{
|
||||||
|
put_indent(out, options);
|
||||||
|
if (node.expression)
|
||||||
|
{
|
||||||
|
out << "alignof\n";
|
||||||
|
child(*node.expression);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out << "sizeof ";
|
||||||
|
print(out, *node.type);
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct statement_print_visitor
|
struct statement_print_visitor
|
||||||
|
|
|
||||||
|
|
@ -288,6 +288,22 @@ namespace pslang::ast
|
||||||
apply(*if_expression.if_false);
|
apply(*if_expression.if_false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void apply(sizeof_operator const & sizeof_operator)
|
||||||
|
{
|
||||||
|
if (sizeof_operator.expression)
|
||||||
|
apply(*sizeof_operator.expression);
|
||||||
|
if (sizeof_operator.type)
|
||||||
|
apply(*sizeof_operator.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply(alignof_operator const & alignof_operator)
|
||||||
|
{
|
||||||
|
if (alignof_operator.expression)
|
||||||
|
apply(*alignof_operator.expression);
|
||||||
|
if (alignof_operator.type)
|
||||||
|
apply(*alignof_operator.type);
|
||||||
|
}
|
||||||
|
|
||||||
void apply(expression_ptr const & expression_ptr)
|
void apply(expression_ptr const & expression_ptr)
|
||||||
{
|
{
|
||||||
apply(*expression_ptr);
|
apply(*expression_ptr);
|
||||||
|
|
|
||||||
|
|
@ -818,6 +818,46 @@ namespace pslang::ast
|
||||||
node.inferred_type = true_type;
|
node.inferred_type = true_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void apply(sizeof_operator & node)
|
||||||
|
{
|
||||||
|
if (node.expression && node.type)
|
||||||
|
throw invalid_ast_error("sizeof node cannot have both an expression and a type", node.location);
|
||||||
|
|
||||||
|
if (node.expression)
|
||||||
|
{
|
||||||
|
apply(*node.expression);
|
||||||
|
node.inferred_source_type = get_type(*node.expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.type)
|
||||||
|
{
|
||||||
|
resolve_types(*node.type);
|
||||||
|
node.inferred_source_type = get_type(*node.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.inferred_type = std::make_shared<types::type>(types::primitive_type{types::u64_type{}});
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply(alignof_operator & node)
|
||||||
|
{
|
||||||
|
if (node.expression && node.type)
|
||||||
|
throw invalid_ast_error("alignof node cannot have both an expression and a type", node.location);
|
||||||
|
|
||||||
|
if (node.expression)
|
||||||
|
{
|
||||||
|
apply(*node.expression);
|
||||||
|
node.inferred_source_type = get_type(*node.expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.type)
|
||||||
|
{
|
||||||
|
resolve_types(*node.type);
|
||||||
|
node.inferred_source_type = get_type(*node.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.inferred_type = std::make_shared<types::type>(types::primitive_type{types::u64_type{}});
|
||||||
|
}
|
||||||
|
|
||||||
void apply(expression_ptr const & node)
|
void apply(expression_ptr const & node)
|
||||||
{
|
{
|
||||||
apply(*node);
|
apply(*node);
|
||||||
|
|
|
||||||
|
|
@ -691,6 +691,16 @@ namespace pslang::interpreter
|
||||||
throw std::runtime_error("Not implemented");
|
throw std::runtime_error("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value eval_impl(context & context, ast::sizeof_operator const & sizeof_operator)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
value eval_impl(context & context, ast::alignof_operator const & alignof_operator)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
value eval_impl(context & context, ast::expression_ptr const & expression)
|
value eval_impl(context & context, ast::expression_ptr const & expression)
|
||||||
{
|
{
|
||||||
return std::visit([&](auto const & expression){ return eval_impl(context, expression); }, *expression);
|
return std::visit([&](auto const & expression){ return eval_impl(context, expression); }, *expression);
|
||||||
|
|
@ -784,6 +794,16 @@ namespace pslang::interpreter
|
||||||
throw std::runtime_error("Not implemented");
|
throw std::runtime_error("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value * eval_ref_impl(context & context, ast::sizeof_operator const & sizeof_operator)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
value * eval_ref_impl(context & context, ast::alignof_operator const & alignof_operator)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
value * eval_ref_impl(context & context, ast::expression_ptr const & expression)
|
value * eval_ref_impl(context & context, ast::expression_ptr const & expression)
|
||||||
{
|
{
|
||||||
return std::visit([&](auto const & expression){ return eval_ref_impl(context, expression); }, *expression);
|
return std::visit([&](auto const & expression){ return eval_ref_impl(context, expression); }, *expression);
|
||||||
|
|
|
||||||
|
|
@ -513,6 +513,18 @@ namespace pslang::ir
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_ref apply(ast::sizeof_operator const & node)
|
||||||
|
{
|
||||||
|
mcontext.nodes->emplace_back(literal{ast::literal{ast::u64_literal{ast::type_size(*node.inferred_source_type)}}}, node.inferred_type);
|
||||||
|
return last();
|
||||||
|
}
|
||||||
|
|
||||||
|
node_ref apply(ast::alignof_operator const & node)
|
||||||
|
{
|
||||||
|
mcontext.nodes->emplace_back(literal{ast::literal{ast::u64_literal{ast::type_alignment(*node.inferred_source_type)}}}, node.inferred_type);
|
||||||
|
return last();
|
||||||
|
}
|
||||||
|
|
||||||
// Statements
|
// Statements
|
||||||
|
|
||||||
node_ref apply(ast::expression_ptr const & node)
|
node_ref apply(ast::expression_ptr const & node)
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ return { return bp::make_return(ctx.location); }
|
||||||
struct { return bp::make_struct(ctx.location); }
|
struct { return bp::make_struct(ctx.location); }
|
||||||
true { return bp::make_true(ctx.location); }
|
true { return bp::make_true(ctx.location); }
|
||||||
false { return bp::make_false(ctx.location); }
|
false { return bp::make_false(ctx.location); }
|
||||||
|
sizeof { return bp::make_sizeof(ctx.location); }
|
||||||
|
alignof { return bp::make_alignof(ctx.location); }
|
||||||
|
|
||||||
unit { return bp::make_unit(ctx.location); }
|
unit { return bp::make_unit(ctx.location); }
|
||||||
bool { return bp::make_bool(ctx.location); }
|
bool { return bp::make_bool(ctx.location); }
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,8 @@ template <typename T>
|
||||||
%token struct
|
%token struct
|
||||||
%token true
|
%token true
|
||||||
%token false
|
%token false
|
||||||
|
%token sizeof
|
||||||
|
%token alignof
|
||||||
|
|
||||||
%token unit
|
%token unit
|
||||||
%token bool
|
%token bool
|
||||||
|
|
@ -355,6 +357,8 @@ expression
|
||||||
| asterisk expression %prec DEREFERENCE { $$ = ast::unary_operation{ast::unary_operation_type::dereference, std::make_unique<ast::expression>($2), @$ }; }
|
| asterisk expression %prec DEREFERENCE { $$ = ast::unary_operation{ast::unary_operation_type::dereference, std::make_unique<ast::expression>($2), @$ }; }
|
||||||
| postfix_expression { $$ = $1; }
|
| postfix_expression { $$ = $1; }
|
||||||
| if expression then expression else expression { $$ = ast::if_expression{ std::make_unique<ast::expression>($2), std::make_unique<ast::expression>($4), std::make_unique<ast::expression>($6), @$ }; }
|
| if expression then expression else expression { $$ = ast::if_expression{ std::make_unique<ast::expression>($2), std::make_unique<ast::expression>($4), std::make_unique<ast::expression>($6), @$ }; }
|
||||||
|
| sizeof lparen type_expression rparen { $$ = ast::sizeof_operator{ nullptr, std::make_unique<ast::type>($3), @$ }; }
|
||||||
|
| alignof lparen type_expression rparen { $$ = ast::alignof_operator{ nullptr, std::make_unique<ast::type>($3), @$ }; }
|
||||||
;
|
;
|
||||||
|
|
||||||
postfix_expression
|
postfix_expression
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
Future plans:
|
Future plans:
|
||||||
* Globals (requires a separate mmaped segment in JIT compiler)
|
* Globals (requires a separate mmaped segment in JIT compiler)
|
||||||
|
* Merge ast types and values (helps for sizeof/alignof builtins, also paves the path for metaprogramming)
|
||||||
* Function overloading: separate functions from values (again) in interpreter, allow casting to specific function type to take function value
|
* Function overloading: separate functions from values (again) in interpreter, allow casting to specific function type to take function value
|
||||||
* Const propagation: annotate expression AST nodes that are computable in compile-time
|
* Const propagation: annotate expression AST nodes that are computable in compile-time
|
||||||
* Generic parameters: can be either values or `t : type`, but always compile-time
|
* Generic parameters: can be either values or `t : type`, but always compile-time
|
||||||
|
|
@ -27,11 +28,11 @@ Optimizer plans:
|
||||||
General backlog:
|
General backlog:
|
||||||
* Mutually recursive structs (relevant only with pointers)
|
* Mutually recursive structs (relevant only with pointers)
|
||||||
* Empty array expression
|
* Empty array expression
|
||||||
* Calling functions as methods
|
|
||||||
* Replace std::runtime_error with appropriate custom exception types
|
* Replace std::runtime_error with appropriate custom exception types
|
||||||
* Replace std::ostringstream with std::format (need support for std::format in type/ast printing)
|
* Replace std::ostringstream with std::format (need support for std::format in type/ast printing)
|
||||||
* TEST COVERAGE!!!
|
* TEST COVERAGE!!!
|
||||||
|
|
||||||
|
|
||||||
Platform-dependent operations backlog:
|
Platform-dependent operations backlog:
|
||||||
* Division by zero (returns 0 on arm64, triggers an interrupt on x86) - declare as UB?
|
* Division by zero (returns 0 on arm64, triggers an interrupt on x86) - declare as UB?
|
||||||
* Floating-point <-> integer conversion (is rounding the same on all platforms?)
|
* Floating-point <-> integer conversion (is rounding the same on all platforms?)
|
||||||
|
|
|
||||||
9
spec.txt
9
spec.txt
|
|
@ -139,6 +139,15 @@ Assignment:
|
||||||
x = 15 // requires x to be a mut variable
|
x = 15 // requires x to be a mut variable
|
||||||
*p = 15 // p must be a pointer to mut
|
*p = 15 // p must be a pointer to mut
|
||||||
|
|
||||||
|
Special built-ins:
|
||||||
|
typeof(value)
|
||||||
|
sizeof(type)
|
||||||
|
sizeof(value) // same as sizeof(typeof(value))
|
||||||
|
alignof(type)
|
||||||
|
alignof(value) // same as alignof(typeof(value))
|
||||||
|
offsetof(struct type, field)
|
||||||
|
offsetof(field access expression)
|
||||||
|
|
||||||
======== FLOW CONTROL ========
|
======== FLOW CONTROL ========
|
||||||
|
|
||||||
Flow control:
|
Flow control:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue