parent
52e19b4a9b
commit
83b68c9f13
|
@ -575,11 +575,11 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
|
|||
context->parent = parent;
|
||||
context->variable_table.init(8);
|
||||
|
||||
if (parent) {
|
||||
context->fn_entry = parent->fn_entry;
|
||||
} else if (node && node->type == NodeTypeFnDef) {
|
||||
if (node && node->type == NodeTypeFnDef) {
|
||||
AstNode *fn_proto_node = node->data.fn_def.fn_proto;
|
||||
context->fn_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;
|
||||
} else if (parent) {
|
||||
context->fn_entry = parent->fn_entry;
|
||||
}
|
||||
|
||||
if (context->fn_entry) {
|
||||
|
@ -589,16 +589,26 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
|
|||
return context;
|
||||
}
|
||||
|
||||
LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
|
||||
while (true) {
|
||||
static VariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
|
||||
while (context && context->fn_entry) {
|
||||
auto entry = context->variable_table.maybe_get(name);
|
||||
if (entry != nullptr)
|
||||
return entry->value;
|
||||
|
||||
context = context->parent;
|
||||
if (context == nullptr)
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VariableTableEntry *find_variable(BlockContext *context, Buf *name) {
|
||||
while (context) {
|
||||
auto entry = context->variable_table.maybe_get(name);
|
||||
if (entry != nullptr)
|
||||
return entry->value;
|
||||
|
||||
context = context->parent;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructField **out_tsf, int *out_i) {
|
||||
|
@ -728,14 +738,13 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
|
|||
return return_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_variable_name(CodeGen *g, BlockContext *context,
|
||||
static TypeTableEntry *analyze_variable_name(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
AstNode *node, Buf *variable_name)
|
||||
{
|
||||
LocalVariableTableEntry *local_variable = find_local_variable(context, variable_name);
|
||||
if (local_variable) {
|
||||
return local_variable->type;
|
||||
VariableTableEntry *var = find_variable(context, variable_name);
|
||||
if (var) {
|
||||
return var->type;
|
||||
} else {
|
||||
// TODO: check global variables also
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
|
@ -919,7 +928,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
|
|||
TypeTableEntry *expected_rhs_type = nullptr;
|
||||
if (lhs_node->type == NodeTypeSymbol) {
|
||||
Buf *name = &lhs_node->data.symbol;
|
||||
LocalVariableTableEntry *var = find_local_variable(context, name);
|
||||
VariableTableEntry *var = find_variable(context, name);
|
||||
if (var) {
|
||||
if (var->is_const) {
|
||||
add_node_error(g, lhs_node,
|
||||
|
@ -1065,8 +1074,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
|
|||
zig_unreachable();
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
|
||||
BlockContext *context, TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
|
||||
|
||||
|
@ -1102,20 +1111,21 @@ static TypeTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry
|
|||
TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
|
||||
assert(type != nullptr); // should have been caught by the parser
|
||||
|
||||
LocalVariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol);
|
||||
VariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol);
|
||||
if (existing_variable) {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("redeclaration of variable '%s'", buf_ptr(&variable_declaration->symbol)));
|
||||
} else {
|
||||
LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1);
|
||||
VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
|
||||
buf_init_from_buf(&variable_entry->name, &variable_declaration->symbol);
|
||||
variable_entry->type = type;
|
||||
variable_entry->is_const = variable_declaration->is_const;
|
||||
variable_entry->is_ptr = true;
|
||||
variable_entry->decl_node = node;
|
||||
context->variable_table.put(&variable_entry->name, variable_entry);
|
||||
return variable_entry;
|
||||
}
|
||||
return g->builtin_types.entry_void;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
|
@ -1200,7 +1210,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
|||
break;
|
||||
}
|
||||
case NodeTypeVariableDeclaration:
|
||||
return_type = analyze_variable_declaration(g, import, context, expected_type, node);
|
||||
analyze_variable_declaration(g, import, context, expected_type, node);
|
||||
return_type = g->builtin_types.entry_void;
|
||||
break;
|
||||
case NodeTypeGoto:
|
||||
{
|
||||
|
@ -1220,7 +1231,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
|||
{
|
||||
for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
|
||||
AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
|
||||
analyze_variable_name(g, context, node, &asm_output->variable_name);
|
||||
analyze_variable_name(g, import, context, node, &asm_output->variable_name);
|
||||
}
|
||||
for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
|
||||
AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
|
||||
|
@ -1330,7 +1341,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
|||
|
||||
case NodeTypeSymbol:
|
||||
{
|
||||
return_type = analyze_variable_name(g, context, node, &node->data.symbol);
|
||||
return_type = analyze_variable_name(g, import, context, node, &node->data.symbol);
|
||||
break;
|
||||
}
|
||||
case NodeTypeCastExpr:
|
||||
|
@ -1429,7 +1440,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
|
|||
assert(fn_proto_node->type == NodeTypeFnProto);
|
||||
|
||||
alloc_codegen_node(node);
|
||||
BlockContext *context = new_block_context(node, nullptr);
|
||||
BlockContext *context = new_block_context(node, import->block_context);
|
||||
node->codegen_node->data.fn_def_node.block_context = context;
|
||||
|
||||
AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
|
||||
|
@ -1442,14 +1453,14 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
|
|||
assert(param_decl->type->type == NodeTypeType);
|
||||
TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry;
|
||||
|
||||
LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1);
|
||||
VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
|
||||
buf_init_from_buf(&variable_entry->name, ¶m_decl->name);
|
||||
variable_entry->type = type;
|
||||
variable_entry->is_const = true;
|
||||
variable_entry->decl_node = param_decl_node;
|
||||
variable_entry->arg_index = i;
|
||||
|
||||
LocalVariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name);
|
||||
VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name);
|
||||
if (!existing_entry) {
|
||||
// unique definition
|
||||
context->variable_table.put(&variable_entry->name, variable_entry);
|
||||
|
@ -1505,8 +1516,12 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
|
|||
// nothing to do
|
||||
break;
|
||||
case NodeTypeVariableDeclaration:
|
||||
analyze_variable_declaration(g, import, import->block_context, nullptr, node);
|
||||
break;
|
||||
{
|
||||
VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context,
|
||||
nullptr, node);
|
||||
g->global_vars.append(var);
|
||||
break;
|
||||
}
|
||||
case NodeTypeDirective:
|
||||
case NodeTypeParamDecl:
|
||||
case NodeTypeFnProto:
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
struct FnTableEntry;
|
||||
struct BlockContext;
|
||||
struct TypeTableEntry;
|
||||
struct VariableTableEntry;
|
||||
|
||||
struct TypeTableEntryPointer {
|
||||
TypeTableEntry *pointer_child;
|
||||
|
@ -177,6 +178,7 @@ struct CodeGen {
|
|||
// The function prototypes this module includes. In the case of external declarations,
|
||||
// there will not be a corresponding fn_defs entry.
|
||||
ZigList<FnTableEntry *> fn_protos;
|
||||
ZigList<VariableTableEntry *> global_vars;
|
||||
|
||||
OutType out_type;
|
||||
FnTableEntry *cur_fn;
|
||||
|
@ -192,7 +194,7 @@ struct CodeGen {
|
|||
ImportTableEntry *root_import;
|
||||
};
|
||||
|
||||
struct LocalVariableTableEntry {
|
||||
struct VariableTableEntry {
|
||||
Buf name;
|
||||
TypeTableEntry *type;
|
||||
LLVMValueRef value_ref;
|
||||
|
@ -204,10 +206,10 @@ struct LocalVariableTableEntry {
|
|||
};
|
||||
|
||||
struct BlockContext {
|
||||
AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or null for module scope
|
||||
AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot
|
||||
FnTableEntry *fn_entry; // null at the module scope
|
||||
BlockContext *parent; // null when this is the root
|
||||
HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
|
||||
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
|
||||
ZigList<AstNode *> cast_expr_alloca_list;
|
||||
LLVMZigDIScope *di_scope;
|
||||
};
|
||||
|
@ -234,7 +236,7 @@ struct ExprNode {
|
|||
};
|
||||
|
||||
struct AssignNode {
|
||||
LocalVariableTableEntry *var_entry;
|
||||
VariableTableEntry *var_entry;
|
||||
};
|
||||
|
||||
struct BlockNode {
|
||||
|
@ -295,7 +297,7 @@ void semantic_analyze(CodeGen *g);
|
|||
void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
|
||||
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
|
||||
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
|
||||
LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name);
|
||||
VariableTableEntry *find_variable(BlockContext *context, Buf *name);
|
||||
BlockContext *new_block_context(AstNode *node, BlockContext *parent);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -558,7 +558,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
|
|||
LLVMValueRef target_ref;
|
||||
TypeTableEntry *op1_type;
|
||||
if (lhs_node->type == NodeTypeSymbol) {
|
||||
LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
|
||||
VariableTableEntry *var = find_variable(node->codegen_node->expr_node.block_context,
|
||||
&lhs_node->data.symbol);
|
||||
|
||||
// semantic checking ensures no variables are constant
|
||||
|
@ -807,7 +807,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
|
|||
buf_append_char(&constraint_buf, ',');
|
||||
}
|
||||
|
||||
LocalVariableTableEntry *variable = find_local_variable(
|
||||
VariableTableEntry *variable = find_variable(
|
||||
node->codegen_node->expr_node.block_context,
|
||||
&asm_output->variable_name);
|
||||
assert(variable);
|
||||
|
@ -851,7 +851,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
|
|||
return gen_return_expr(g, node);
|
||||
case NodeTypeVariableDeclaration:
|
||||
{
|
||||
LocalVariableTableEntry *variable = find_local_variable(
|
||||
VariableTableEntry *variable = find_variable(
|
||||
node->codegen_node->expr_node.block_context,
|
||||
&node->data.variable_declaration.symbol);
|
||||
|
||||
|
@ -940,13 +940,14 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
|
|||
}
|
||||
case NodeTypeSymbol:
|
||||
{
|
||||
LocalVariableTableEntry *variable = find_local_variable(
|
||||
VariableTableEntry *variable = find_variable(
|
||||
node->codegen_node->expr_node.block_context,
|
||||
&node->data.symbol);
|
||||
assert(variable);
|
||||
if (variable->type->id == TypeTableEntryIdVoid) {
|
||||
return nullptr;
|
||||
} else if (variable->is_ptr) {
|
||||
assert(variable->value_ref);
|
||||
if (variable->type->id == TypeTableEntryIdArray) {
|
||||
return variable->value_ref;
|
||||
} else if (variable->type->id == TypeTableEntryIdStruct) {
|
||||
|
@ -1035,9 +1036,25 @@ static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) {
|
|||
static void do_code_gen(CodeGen *g) {
|
||||
assert(!g->errors.length);
|
||||
|
||||
// Generate module level variables
|
||||
for (int i = 0; i < g->global_vars.length; i += 1) {
|
||||
VariableTableEntry *var = g->global_vars.at(i);
|
||||
|
||||
LLVMValueRef init_val = gen_expr(g, var->decl_node->data.variable_declaration.expr);
|
||||
|
||||
// TODO if the global is exported, set external linkage
|
||||
LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), "");
|
||||
LLVMSetLinkage(global_value, LLVMPrivateLinkage);
|
||||
LLVMSetInitializer(global_value, init_val);
|
||||
LLVMSetGlobalConstant(global_value, var->is_const);
|
||||
LLVMSetUnnamedAddr(global_value, true);
|
||||
|
||||
var->value_ref = global_value;
|
||||
}
|
||||
|
||||
// Generate function prototypes
|
||||
for (int i = 0; i < g->fn_protos.length; i += 1) {
|
||||
FnTableEntry *fn_table_entry = g->fn_protos.at(i);
|
||||
for (int fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) {
|
||||
FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i);
|
||||
|
||||
AstNode *proto_node = fn_table_entry->proto_node;
|
||||
assert(proto_node->type == NodeTypeFnProto);
|
||||
|
@ -1090,14 +1107,13 @@ static void do_code_gen(CodeGen *g) {
|
|||
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
|
||||
|
||||
// Add debug info.
|
||||
LLVMZigDIScope *fn_scope = LLVMZigFileToScope(import->di_file);
|
||||
unsigned line_number = fn_def_node->line + 1;
|
||||
unsigned scope_line = line_number;
|
||||
bool is_definition = true;
|
||||
unsigned flags = 0;
|
||||
bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
|
||||
LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder,
|
||||
fn_scope, buf_ptr(&fn_proto->name), "", import->di_file, line_number,
|
||||
import->block_context->di_scope, buf_ptr(&fn_proto->name), "", import->di_file, line_number,
|
||||
create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage,
|
||||
is_definition, scope_line, flags, is_optimized, fn);
|
||||
|
||||
|
@ -1123,7 +1139,7 @@ static void do_code_gen(CodeGen *g) {
|
|||
assert(param_decl->type == NodeTypeParamDecl);
|
||||
if (is_param_decl_type_void(g, param_decl))
|
||||
continue;
|
||||
LocalVariableTableEntry *parameter_variable = fn_def_node->codegen_node->data.fn_def_node.block_context->variable_table.get(¶m_decl->data.param_decl.name);
|
||||
VariableTableEntry *parameter_variable = fn_def_node->codegen_node->data.fn_def_node.block_context->variable_table.get(¶m_decl->data.param_decl.name);
|
||||
parameter_variable->value_ref = params[non_void_index];
|
||||
non_void_index += 1;
|
||||
}
|
||||
|
@ -1135,7 +1151,7 @@ static void do_code_gen(CodeGen *g) {
|
|||
for (int bc_i = 0; bc_i < fn_table_entry->all_block_contexts.length; bc_i += 1) {
|
||||
BlockContext *block_context = fn_table_entry->all_block_contexts.at(bc_i);
|
||||
|
||||
if (block_context->parent) {
|
||||
if (!block_context->di_scope) {
|
||||
LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder,
|
||||
block_context->parent->di_scope,
|
||||
import->di_file,
|
||||
|
@ -1152,7 +1168,7 @@ static void do_code_gen(CodeGen *g) {
|
|||
if (!entry)
|
||||
break;
|
||||
|
||||
LocalVariableTableEntry *var = entry->value;
|
||||
VariableTableEntry *var = entry->value;
|
||||
if (var->type->id == TypeTableEntryIdVoid)
|
||||
continue;
|
||||
|
||||
|
@ -1530,7 +1546,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src
|
|||
import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
|
||||
g->import_table.put(full_path, import_entry);
|
||||
|
||||
import_entry->block_context = new_block_context(nullptr, nullptr);
|
||||
import_entry->block_context = new_block_context(import_entry->root, nullptr);
|
||||
import_entry->block_context->di_scope = LLVMZigFileToScope(import_entry->di_file);
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
const SYS_write : isize = 1;
|
||||
const stdout_fileno : isize = 1;
|
||||
|
||||
fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
|
||||
var result : isize;
|
||||
asm volatile ("
|
||||
|
@ -13,15 +16,12 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
|
|||
return result;
|
||||
}
|
||||
|
||||
// TODO constants for SYS_write and stdout_fileno
|
||||
pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {
|
||||
const SYS_write : isize = 1;
|
||||
return syscall3(SYS_write, fd, buf as isize, count as isize);
|
||||
}
|
||||
|
||||
// TODO error handling
|
||||
// TODO handle buffering and flushing
|
||||
pub fn print_str(str : string) -> isize {
|
||||
const stdout_fileno : isize = 1;
|
||||
return write(stdout_fileno, str.ptr, str.len);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue