aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2018-10-27 18:44:28 +0100
committergingerBill <bill@gingerbill.org>2018-10-27 18:44:28 +0100
commit2ddb27869bd704d28e4704648c26b17d00ba2ff5 (patch)
tree2059d031bcfb8d4c448448f90dada2bc85358ce2 /src
parent5c608b01ba8b445511690fe499b811bb2ea15dbe (diff)
Built-in procedure `#defined`
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp57
-rw-r--r--src/ir.cpp53
-rw-r--r--src/ir_print.cpp9
-rw-r--r--src/parser.cpp3
-rw-r--r--src/parser.hpp1
5 files changed, 91 insertions, 32 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 0e4833ef1..6b2a07a86 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -2885,6 +2885,36 @@ bool is_type_normal_pointer(Type *ptr, Type **elem) {
return false;
}
+bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **out_scope = nullptr) {
+ switch (node->kind) {
+ case_ast_node(i, Ident, node);
+ String name = i->token.string;
+ if (nested) {
+ Entity *e = scope_lookup_current(s, name);
+ if (e != nullptr) {
+ if (out_scope) *out_scope = e->scope;
+ return true;
+ }
+ } else {
+ Entity *e = scope_lookup(s, name);
+ if (e != nullptr) {
+ if (out_scope) *out_scope = e->scope;
+ return true;
+ }
+ }
+ case_end;
+ case_ast_node(se, SelectorExpr, node);
+ Ast *lhs = se->expr;
+ Ast *rhs = se->selector;
+ Scope *lhs_scope = nullptr;
+ if (check_identifier_exists(s, lhs, nested, &lhs_scope)) {
+ return check_identifier_exists(lhs_scope, rhs, true);
+ }
+ case_end;
+ }
+ return false;
+}
+
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id) {
ast_node(ce, CallExpr, call);
@@ -2920,6 +2950,15 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
case BuiltinProc_len:
// NOTE(bill): The first arg may be a Type, this will be checked case by case
break;
+
+ case BuiltinProc_DIRECTIVE: {
+ ast_node(bd, BasicDirective, ce->proc);
+ String name = bd->name;
+ if (name == "defined") {
+ break;
+ }
+ /*fallthrough*/
+ }
default:
if (ce->args.count > 0) {
check_multi_expr(c, operand, ce->args[0]);
@@ -2984,6 +3023,22 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
operand->type = t_untyped_bool;
operand->mode = Addressing_Constant;
+ } else if (name == "defined") {
+ if (ce->args.count != 1) {
+ error(call, "'#defined' expects 1 argument, got %td", ce->args.count);
+ return false;
+ }
+ Ast *arg = unparen_expr(ce->args[0]);
+ if (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr) {
+ error(call, "'#defined' expects an identifier or selector expression, got %s", LIT(ast_strings[arg->kind]));
+ return false;
+ }
+
+ bool is_defined = check_identifier_exists(c->scope, arg);
+ operand->type = t_untyped_bool;
+ operand->mode = Addressing_Constant;
+ operand->value = exact_value_bool(is_defined);
+
} else {
GB_PANIC("Unhandled #%.*s", LIT(name));
}
@@ -4957,7 +5012,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
ce->proc->kind == Ast_BasicDirective) {
ast_node(bd, BasicDirective, ce->proc);
String name = bd->name;
- if (name == "location" || name == "assert") {
+ if (name == "location" || name == "assert" || name == "defined") {
operand->mode = Addressing_Builtin;
operand->builtin_id = BuiltinProc_DIRECTIVE;
operand->expr = ce->proc;
diff --git a/src/ir.cpp b/src/ir.cpp
index b1c39a6f8..e6e30283f 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -26,7 +26,7 @@ struct irModule {
Map<irValue *> anonymous_proc_lits; // Key: Ast *
irDebugInfo * debug_compile_unit;
- Array<irDebugInfo *> debug_location_stack;
+ Array<irDebugInfo *> debug_location_stack;
i32 global_string_index;
@@ -598,7 +598,7 @@ struct irDebugInfo {
irDebugInfo *file;
irDebugInfo *scope;
} LexicalBlock;
-
+
struct {
String name;
i32 size;
@@ -659,6 +659,8 @@ struct irDebugInfo {
};
};
+static irDebugInfo IR_DEBUG_INFO_EMPTY = {};
+
struct irGen {
irModule module;
@@ -1692,7 +1694,7 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) {
case Basic_i16:
case Basic_i32:
- case Basic_i64:
+ case Basic_i64:
case Basic_int:
case Basic_rune:
case Basic_typeid:
@@ -1712,7 +1714,7 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) {
// case Basic_complex32:
case Basic_complex64:
- case Basic_complex128:
+ case Basic_complex128:
case Basic_cstring:
case Basic_string:
case Basic_any:
@@ -1916,7 +1918,7 @@ irDebugInfo *ir_add_debug_info_type_bit_field(irModule *module, Type *type, Enti
0,
nullptr,
di);
- // NOTE(lachsinc): Above calls BitFieldValues type_size_of() which returns size in bits,
+ // NOTE(lachsinc): Above calls BitFieldValues type_size_of() which returns size in bits,
// replace with its true bit value here..
field_di->DerivedType.size = size;
field_di->DerivedType.offset = offset; // Offset stored in bits already, no need to convert
@@ -1946,7 +1948,7 @@ irDebugInfo *ir_add_debug_info_type_bit_set(irModule *module, Type *type, Entity
GB_ASSERT(elem_type->Enum.fields.count == base->BitSet.upper + 1);
}
}
-
+
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType);
di->CompositeType.name = named != nullptr ? named->Named.name : str_lit("bit_set");
di->CompositeType.tag = irDebugBasicEncoding_structure_type;
@@ -1974,7 +1976,7 @@ irDebugInfo *ir_add_debug_info_type_bit_set(irModule *module, Type *type, Entity
map_set(&module->debug_info, hash_pointer(field_di), field_di);
array_add(&elements_di->DebugInfoArray.elements, field_di);
}
-
+
return di;
}
@@ -2064,7 +2066,7 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) {
di->CompositeType.name = type->Basic.name;
di->CompositeType.tag = irDebugBasicEncoding_structure_type;
di->CompositeType.size = ir_debug_size_bits(type);
-
+
Type *field_type = nullptr;
if (type->Basic.kind == Basic_complex64) {
field_type = t_f32;
@@ -2421,7 +2423,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD
if (is_type_map(type)) {
// TODO(lachsinc): Looks like "generated_struct_type" map.entries.data is just a u8*, we could
- // always look at the map header and create the debug info manually (if we
+ // always look at the map header and create the debug info manually (if we
// want struct members to be interpreted as the correct type).
// Also; are hashes meant to be interpreted as bool*'s ?? or is that simply slot occupied data?
return ir_add_debug_info_type(module, type->Map.generated_struct_type, e, scope, file);
@@ -2434,7 +2436,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType);
di->BasicType.encoding = irDebugBasicEncoding_unsigned;
// di->BasicType.name = str_lit("todo");
- di->BasicType.size = base->BitFieldValue.bits;
+ di->BasicType.size = base->BitFieldValue.bits;
map_set(&module->debug_info, hash_type(type), di);
return di;
}
@@ -2544,7 +2546,7 @@ irDebugInfo *ir_add_debug_info_local(irProcedure *proc, Entity *e, i32 arg_id) {
di->LocalVariable.pos = e->token.pos;
di->LocalVariable.arg = arg_id;
di->LocalVariable.type = ir_add_debug_info_type(module, e->type, e, scope, file); // TODO(lachsinc): Is this the correct entity to pass? Or do we want a TypeName ??
-
+
map_set(&module->debug_info, hash_entity(e), di);
return di;
}
@@ -2561,12 +2563,12 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc) {
CheckerInfo *info = proc->module->info;
String filename = proc->entity->token.pos.file;
AstFile *f = ast_file_of_filename(info, filename);
- irDebugInfo *file = nullptr;
+ irDebugInfo *file = nullptr;
if (f) {
file = ir_add_debug_info_file(proc->module, f);
}
// TODO(lachsinc): Should scope be made separate to file?
- irDebugInfo *scope = file;
+ irDebugInfo *scope = file;
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_Proc);
map_set(&proc->module->debug_info, hash_entity(entity), di);
@@ -2591,7 +2593,7 @@ irDebugInfo *ir_add_debug_info_location(irModule *m, Ast *node, irDebugInfo *sco
return *existing;
}
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_Location);
- di->Location.pos = ast_token(node).pos;
+ di->Location.pos = ast_token(node).pos;
di->Location.scope = scope;
map_set(&m->debug_info, hash_node(node), di);
return di;
@@ -2613,8 +2615,8 @@ void ir_pop_debug_location(irModule *m) {
//
////////////////////////////////////////////////////////////////
-irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValue *> args, Ast *expr = nullptr);
-irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr = nullptr);
+irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValue *> args, Ast *expr = nullptr, ProcInlining inlining = ProcInlining_none);
+irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr = nullptr, ProcInlining inlining = ProcInlining_none);
irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) {
@@ -2668,7 +2670,8 @@ void ir_emit_zero_init(irProcedure *p, irValue *address, Ast *expr) {
args[1] = ir_const_int(type_size_of(t));
AstPackage *pkg = get_core_package(p->module->info, str_lit("mem"));
if (p->entity != nullptr && p->entity->token.string != "zero" && p->entity->pkg != pkg) {
- ir_emit_package_call(p, "mem", "zero", args, expr);
+ irValue *v = ir_emit_package_call(p, "mem", "zero", args, expr, ProcInlining_no_inline);
+ // v->loc = &IR_DEBUG_INFO_EMPTY; // NOTE(bill): remove debug location
}
ir_emit(p, ir_instr_zero_init(p, address));
}
@@ -2803,7 +2806,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
return result;
}
-irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValue *> args, Ast *expr) {
+irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValue *> args, Ast *expr, ProcInlining inlining) {
String name = make_string_c(cast(char *)name_);
AstPackage *p = proc->module->info->runtime_package;
@@ -2811,10 +2814,10 @@ irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValu
irValue **found = map_get(&proc->module->values, hash_entity(e));
GB_ASSERT_MSG(found != nullptr, "%.*s", LIT(name));
irValue *gp = *found;
- irValue *call = ir_emit_call(proc, gp, args);
+ irValue *call = ir_emit_call(proc, gp, args, inlining);
return call;
}
-irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr) {
+irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr, ProcInlining inlining) {
String name = make_string_c(cast(char *)name_);
String package_name = make_string_c(cast(char *)package_name_);
@@ -2823,7 +2826,7 @@ irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char
irValue **found = map_get(&proc->module->values, hash_entity(e));
GB_ASSERT_MSG(found != nullptr, "%.*s", LIT(name));
irValue *gp = *found;
- irValue *call = ir_emit_call(proc, gp, args);
+ irValue *call = ir_emit_call(proc, gp, args, inlining);
return call;
}
@@ -6766,7 +6769,6 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
}
return ir_addr(elem);
- break;
}
case Type_Slice: {
@@ -6785,7 +6787,6 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
irValue *v = ir_emit_ptr_offset(proc, elem, index);
return ir_addr(v);
- break;
}
case Type_DynamicArray: {
@@ -6804,7 +6805,6 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
irValue *v = ir_emit_ptr_offset(proc, elem, index);
return ir_addr(v);
- break;
}
@@ -6829,7 +6829,6 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
return ir_addr(ir_emit_ptr_offset(proc, elem, index));
- break;
}
}
case_end;
@@ -8540,7 +8539,7 @@ void ir_begin_procedure_body(irProcedure *proc) {
if (proc->module->generate_debug_info && proc->entity && proc->entity->identifier) { // TODO(lachsinc): Better way to determine if these procs are main/runtime_startup.
// TODO(lachsinc): Passing the file for the scope may not be correct for nested procedures? This should probably be
// handled all inside push_debug_location, with just the Ast * we can pull out everything we need to construct scope/file debug info etc.
- ir_add_debug_info_proc(proc);
+ ir_add_debug_info_proc(proc);
ir_push_debug_location(proc->module, proc->entity->identifier, proc->debug_scope);
GB_ASSERT_NOT_NULL(proc->debug_scope);
} else {
@@ -8717,7 +8716,7 @@ void ir_build_proc(irValue *value, irProcedure *parent) {
proc->module->stmt_state_flags = prev_stmt_state_flags;
}
- // NOTE(lachsinc): For now we pop the debug location inside ir_end_procedure_body().
+ // NOTE(lachsinc): For now we pop the debug location inside ir_end_procedure_body().
// This may result in debug info being missing for below.
if (proc->type->Proc.has_proc_default_values) {
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 7c01d6a46..177ae0aa1 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -221,9 +221,10 @@ bool ir_print_debug_location(irFileBuffer *f, irModule *m, irValue *v) {
GB_ASSERT(v->kind == irValue_Instr);
if (v->loc != nullptr) {
- GB_ASSERT(v->loc->kind == irDebugInfo_Location);
- ir_fprintf(f, ", !dbg !%d", v->loc->id);
- return true;
+ if (v->loc->kind == irDebugInfo_Location) {
+ ir_fprintf(f, ", !dbg !%d", v->loc->id);
+ return true;
+ }
} else {
irProcedure *proc = v->Instr.block->proc;
GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0));
@@ -1812,7 +1813,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
irDebugInfo **lookup_di = map_get(&m->debug_info, hash_entity(e));
GB_ASSERT_NOT_NULL(*lookup_di);
irDebugInfo* local_var_di = *lookup_di;
-
+
ir_write_str_lit(f, "call void @llvm.dbg.declare(");
ir_write_str_lit(f, "metadata ");
ir_print_type(f, m, vt);
diff --git a/src/parser.cpp b/src/parser.cpp
index 231a40e99..38678a6dc 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1677,6 +1677,9 @@ Ast *parse_operand(AstFile *f, bool lhs) {
} else if (name.string == "assert") {
Ast *tag = ast_basic_directive(f, token, name.string);
return parse_call_expr(f, tag);
+ } else if (name.string == "defined") {
+ Ast *tag = ast_basic_directive(f, token, name.string);
+ return parse_call_expr(f, tag);
} else {
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
}
diff --git a/src/parser.hpp b/src/parser.hpp
index 4f0b4d260..732d499b8 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -150,6 +150,7 @@ enum ProcTag {
ProcTag_bounds_check = 1<<0,
ProcTag_no_bounds_check = 1<<1,
ProcTag_require_results = 1<<4,
+ ProcTag_no_context = 1<<6,
};
enum ProcCallingConvention {