diff --git a/boot/symbol.cc b/boot/symbol.cc index ffa56a7..fef6ab6 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -339,7 +339,7 @@ namespace elna::boot std::shared_ptr variable_info::is_variable() { - return std::static_pointer_cast(shared_from_this());; + return std::static_pointer_cast(shared_from_this()); } std::shared_ptr builtin_symbol_table() diff --git a/gcc/elna-builtins.cc b/gcc/elna-builtins.cc index e3cda7c..60b929c 100644 --- a/gcc/elna-builtins.cc +++ b/gcc/elna-builtins.cc @@ -73,8 +73,6 @@ namespace elna::gcc declare_builtin_type(symbol_table, "Float", elna_float_type_node); declare_builtin_type(symbol_table, "String", elna_string_type_node); - symbol_table->enter("unreachable", *elna_global_decls->get("__builtin_unreachable")); - return symbol_table; } } diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 7774e1c..3ed458d 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -148,7 +148,7 @@ namespace elna::gcc if (!is_assignable_from(TREE_VALUE(current_parameter), this->current_expression)) { error_at(argument_location, - "cannot assign value of type '%s' to variable of type '%s'", + "Cannot assign value of type '%s' to variable of type '%s'", print_type(TREE_TYPE(this->current_expression)).c_str(), print_type(TREE_VALUE(current_parameter)).c_str()); this->current_expression = error_mark_node; @@ -202,7 +202,7 @@ namespace elna::gcc } if (!is_void_type(record_fields)) { - error_at(call_location, "too few arguments, expected %i, got %lu", + error_at(call_location, "Too few arguments, expected %i, got %lu", list_length(TYPE_FIELDS(symbol)), arguments.size()); this->current_expression = error_mark_node; } @@ -212,8 +212,62 @@ namespace elna::gcc } } + void generic_visitor::build_assert_builtin(location_t call_location, + const std::vector& arguments) + { + if (arguments.size() != 1) + { + error_at(call_location, "assert expects exactly one boolean argument, got %lu", arguments.size()); + this->current_expression = error_mark_node; + } + else + { + arguments.at(0)->accept(this); + tree argument_type = TREE_TYPE(this->current_expression); + + if (argument_type != elna_bool_type_node) + { + error_at(call_location, "assert expects exactly one boolean argument, got %s", + print_type(argument_type).c_str()); + this->current_expression = error_mark_node; + } + tree constant_expression = extract_constant(this->current_expression); + if (constant_expression == boolean_false_node) + { + this->current_expression = call_built_in(call_location, "__builtin_unreachable", void_type_node); + } + else if (constant_expression != boolean_true_node) + { + this->current_expression = call_built_in(call_location, "__builtin_trap", void_type_node); + } + else + { + this->current_expression = NULL_TREE; + } + } + } + + bool generic_visitor::build_builtin_procedures(boot::procedure_call *call) + { + location_t call_location = get_location(&call->position()); + + if (boot::variable_expression *named_call = call->callable().is_variable()) + { + if (named_call->name == "assert") + { + build_assert_builtin(call_location, call->arguments); + return true; + } + } + return false; + } + void generic_visitor::visit(boot::procedure_call *call) { + if (build_builtin_procedures(call)) + { + return; + } location_t call_location = get_location(&call->position()); call->callable().accept(this); @@ -599,13 +653,8 @@ namespace elna::gcc right, elna_string_ptr_field_node, NULL_TREE); tree length_equality = build2(equality_code, elna_bool_type_node, lhs_length, rhs_length); - tree *memcmp = elna_global_decls->get("__builtin_memcmp"); - gcc_assert(memcmp != nullptr); - - tree fndecl_type = build_function_type(integer_type_node, TYPE_ARG_TYPES(*memcmp)); - tree memcmp_addr = build1(ADDR_EXPR, build_pointer_type(fndecl_type), *memcmp); - tree memcmp_call = build_call_nary(integer_type_node, memcmp_addr, 3, lhs_ptr, rhs_ptr, lhs_length); - + tree memcmp_call = call_built_in(UNKNOWN_LOCATION, "__builtin_memcmp", integer_type_node, + lhs_ptr, rhs_ptr, lhs_length); tree equals_zero = build2(equality_code, elna_bool_type_node, memcmp_call, integer_zero_node); return build2(combination_code, elna_bool_type_node, length_equality, equals_zero); @@ -768,7 +817,7 @@ namespace elna::gcc location_t definition_location = get_location(&definition->position()); definition->body().accept(this); - if (extract_constant(definition_location)) + if (assert_constant(definition_location)) { this->current_expression = fold_init(this->current_expression); } @@ -1490,7 +1539,7 @@ namespace elna::gcc case_label->accept(this); location_t case_location = get_location(&case_label->position()); - if (extract_constant(case_location) + if (assert_constant(case_location) && !is_assignable_from(unqualified_condition, this->current_expression)) { error_at(case_location, "Case type '%s' does not match the expression type '%s'", @@ -1535,20 +1584,19 @@ namespace elna::gcc this->current_expression = NULL_TREE; } - bool generic_visitor::extract_constant(location_t expression_location) + bool generic_visitor::assert_constant(location_t expression_location) { - int code = TREE_CODE(this->current_expression); + tree constant_expression = extract_constant(this->current_expression); - if (code == CONST_DECL) - { - this->current_expression = DECL_INITIAL(this->current_expression); - } - else if (TREE_CODE_CLASS(code) != tcc_constant) + if (constant_expression == NULL_TREE) { error_at(expression_location, "Expected a constant expression"); this->current_expression = error_mark_node; - return false; } - return true; + else + { + this->current_expression = constant_expression; + } + return this->current_expression != error_mark_node; } } diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index a1d7f0b..3767ea9 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -249,4 +249,19 @@ namespace elna::gcc return label_decl; } + + tree extract_constant(tree expression) + { + int code = TREE_CODE(expression); + + if (code == CONST_DECL) + { + return DECL_INITIAL(expression); + } + else if (TREE_CODE_CLASS(code) == tcc_constant) + { + return expression; + } + return NULL_TREE; + } } diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 968238b..ad2a141 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -40,7 +40,6 @@ namespace elna::gcc std::shared_ptr symbols, std::unordered_map& unresolved, std::vector& path); - class generic_visitor final : public boot::parser_visitor { tree current_expression{ NULL_TREE }; @@ -68,11 +67,13 @@ namespace elna::gcc tree procedure_address, const std::vector& arguments); void build_record_call(location_t call_location, tree symbol, const std::vector& arguments); + bool build_builtin_procedures(boot::procedure_call *call); + void build_assert_builtin(location_t call_location, const std::vector& arguments); bool expect_trait_type_only(boot::traits_expression *trait); bool expect_trait_for_integral_type(boot::traits_expression *trait); void visit_statements(const std::vector& statements); - bool extract_constant(location_t expression_location); + bool assert_constant(location_t expression_location); public: generic_visitor(std::shared_ptr symbol_table, diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index 335dc0c..cafe435 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #include "elna/boot/ast.h" #include "elna/boot/symbol.h" +#include "elna/gcc/elna1.h" namespace elna::gcc { @@ -82,4 +83,18 @@ namespace elna::gcc tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name); tree build_global_pointer_type(tree type); tree build_label_decl(const char *name, location_t loc); + + tree extract_constant(tree expression); + + template + tree call_built_in(location_t call_location, const char *name, tree return_type, Args... arguments) + { + tree *builtin = elna_global_decls->get(name); + gcc_assert(builtin != nullptr); + + tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(*builtin)); + tree builtin_addr = build1_loc(call_location, ADDR_EXPR, build_pointer_type(fndecl_type), *builtin); + + return build_call_nary(return_type, builtin_addr, sizeof...(Args), arguments...); + } } diff --git a/include/elna/gcc/elna1.h b/include/elna/gcc/elna1.h index 418c832..1a418d8 100644 --- a/include/elna/gcc/elna1.h +++ b/include/elna/gcc/elna1.h @@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ +#pragma once + enum elna_tree_index { ELNA_TI_INT_TYPE,