fix codegen for pointers to void

This commit is contained in:
Andrew Kelley 2016-01-27 14:18:20 -07:00
parent 261517aa44
commit 707154da36
4 changed files with 208 additions and 129 deletions

View File

@ -788,6 +788,8 @@ struct TypeTableEntryStruct {
// set this flag temporarily to detect infinite loops // set this flag temporarily to detect infinite loops
bool embedded_in_current; bool embedded_in_current;
bool reported_infinite_err; bool reported_infinite_err;
// whether we've finished resolving it
bool complete;
}; };
struct TypeTableEntryMaybe { struct TypeTableEntryMaybe {
@ -812,6 +814,8 @@ struct TypeTableEntryEnum {
// set this flag temporarily to detect infinite loops // set this flag temporarily to detect infinite loops
bool embedded_in_current; bool embedded_in_current;
bool reported_infinite_err; bool reported_infinite_err;
// whether we've finished resolving it
bool complete;
}; };
struct TypeTableEntryFn { struct TypeTableEntryFn {

View File

@ -25,6 +25,7 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
BlockContext *context, AstNode *node, Buf *err_name); BlockContext *context, AstNode *node, Buf *err_name);
static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node); TypeTableEntry *expected_type, AstNode *node);
static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);
static AstNode *first_executing_node(AstNode *node) { static AstNode *first_executing_node(AstNode *node) {
switch (node->type) { switch (node->type) {
@ -152,17 +153,34 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
return *parent_pointer; return *parent_pointer;
} else { } else {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
const char *const_str = is_const ? "const " : ""; const char *const_str = is_const ? "const " : "";
buf_resize(&entry->name, 0); buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name)); buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
bool zero_bits;
if (child_type->size_in_bits == 0) {
if (child_type->id == TypeTableEntryIdStruct) {
zero_bits = child_type->data.structure.complete;
} else if (child_type->id == TypeTableEntryIdEnum) {
zero_bits = child_type->data.enumeration.complete;
} else {
zero_bits = true;
}
} else {
zero_bits = false;
}
if (!zero_bits) {
entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
entry->size_in_bits = g->pointer_size_bytes * 8; entry->size_in_bits = g->pointer_size_bytes * 8;
entry->align_in_bits = g->pointer_size_bytes * 8; entry->align_in_bits = g->pointer_size_bytes * 8;
assert(child_type->di_type); assert(child_type->di_type);
entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type, entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type,
entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name)); entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
}
entry->data.pointer.child_type = child_type; entry->data.pointer.child_type = child_type;
entry->data.pointer.is_const = is_const; entry->data.pointer.is_const = is_const;
@ -511,6 +529,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
// after the gen_param_index += 1 because 0 is the return type // after the gen_param_index += 1 because 0 is the return type
param_di_types[gen_param_index] = gen_type->di_type; param_di_types[gen_param_index] = gen_type->di_type;
gen_return_type = g->builtin_types.entry_void; gen_return_type = g->builtin_types.entry_void;
} else if (return_type->size_in_bits == 0) {
gen_return_type = g->builtin_types.entry_void;
} else { } else {
gen_return_type = return_type; gen_return_type = return_type;
} }
@ -584,7 +604,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ? LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?
LLVMInternalLinkage : LLVMExternalLinkage); LLVMInternalLinkage : LLVMExternalLinkage);
if (gen_return_type->id == TypeTableEntryIdUnreachable) { if (return_type->id == TypeTableEntryIdUnreachable) {
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute); LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
} }
LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention); LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention);
@ -707,6 +727,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
// unset temporary flag // unset temporary flag
enum_type->data.enumeration.embedded_in_current = false; enum_type->data.enumeration.embedded_in_current = false;
enum_type->data.enumeration.complete = true;
if (!enum_type->data.enumeration.is_invalid) { if (!enum_type->data.enumeration.is_invalid) {
enum_type->data.enumeration.gen_field_count = gen_field_index; enum_type->data.enumeration.gen_field_count = gen_field_index;
@ -872,6 +893,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
struct_type->data.structure.embedded_in_current = false; struct_type->data.structure.embedded_in_current = false;
struct_type->data.structure.gen_field_count = gen_field_index; struct_type->data.structure.gen_field_count = gen_field_index;
struct_type->data.structure.complete = true;
if (!struct_type->data.structure.is_invalid) { if (!struct_type->data.structure.is_invalid) {
@ -1186,7 +1208,9 @@ static bool type_has_codegen_value(TypeTableEntryId id) {
static void add_global_const_expr(CodeGen *g, Expr *expr) { static void add_global_const_expr(CodeGen *g, Expr *expr) {
if (expr->const_val.ok && if (expr->const_val.ok &&
type_has_codegen_value(expr->type_entry->id) && !expr->has_global_const) type_has_codegen_value(expr->type_entry->id) &&
!expr->has_global_const &&
expr->type_entry->size_in_bits > 0)
{ {
g->global_const_list.append(expr); g->global_const_list.append(expr);
expr->has_global_const = true; expr->has_global_const = true;
@ -1776,7 +1800,7 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
add_node_error(g, node, buf_sprintf("void expression expects no arguments")); add_node_error(g, node, buf_sprintf("void expression expects no arguments"));
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
} else { } else {
return container_type; return resolve_expr_const_val_as_void(g, node);
} }
} else if (container_type->id == TypeTableEntryIdUnreachable) { } else if (container_type->id == TypeTableEntryIdUnreachable) {
if (container_init_expr->entries.length != 0) { if (container_init_expr->entries.length != 0) {
@ -1925,6 +1949,12 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
return return_type; return return_type;
} }
static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
return g->builtin_types.entry_void;
}
static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type) { static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type) {
Expr *expr = get_resolved_expr(node); Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true; expr->const_val.ok = true;

View File

@ -510,7 +510,6 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
} }
TypeTableEntry *src_return_type = fn_type->data.fn.src_return_type; TypeTableEntry *src_return_type = fn_type->data.fn.src_return_type;
TypeTableEntry *gen_return_type = fn_type->data.fn.gen_return_type;
int fn_call_param_count = node->data.fn_call_expr.params.length; int fn_call_param_count = node->data.fn_call_expr.params.length;
bool first_arg_ret = handle_is_ptr(src_return_type); bool first_arg_ret = handle_is_ptr(src_return_type);
@ -544,7 +543,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val, LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val,
gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, ""); gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");
if (gen_return_type->id == TypeTableEntryIdUnreachable) { if (src_return_type->id == TypeTableEntryIdUnreachable) {
return LLVMBuildUnreachable(g->builder); return LLVMBuildUnreachable(g->builder);
} else if (first_arg_ret) { } else if (first_arg_ret) {
return node->data.fn_call_expr.tmp_ptr; return node->data.fn_call_expr.tmp_ptr;
@ -821,8 +820,6 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
VariableTableEntry *var = find_variable(expr_node->block_context, VariableTableEntry *var = find_variable(expr_node->block_context,
&node->data.symbol_expr.symbol); &node->data.symbol_expr.symbol);
assert(var); assert(var);
// semantic checking ensures no variables are constant
assert(!var->is_const);
*out_type_entry = var->type; *out_type_entry = var->type;
target_ref = var->value_ref; target_ref = var->value_ref;
@ -895,9 +892,14 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
case PrefixOpDereference: case PrefixOpDereference:
{ {
LLVMValueRef expr = gen_expr(g, expr_node); LLVMValueRef expr = gen_expr(g, expr_node);
TypeTableEntry *type_entry = get_expr_type(expr_node);
if (type_entry->size_in_bits == 0) {
return nullptr;
} else {
add_debug_source_node(g, node); add_debug_source_node(g, node);
return LLVMBuildLoad(g->builder, expr, ""); return LLVMBuildLoad(g->builder, expr, "");
} }
}
case PrefixOpMaybe: case PrefixOpMaybe:
{ {
zig_panic("TODO codegen PrefixOpMaybe"); zig_panic("TODO codegen PrefixOpMaybe");
@ -2182,9 +2184,13 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
Expr *expr = get_resolved_expr(node); Expr *expr = get_resolved_expr(node);
if (expr->const_val.ok) { if (expr->const_val.ok) {
if (expr->type_entry->size_in_bits == 0) {
return nullptr;
} else {
assert(expr->const_llvm_val); assert(expr->const_llvm_val);
return expr->const_llvm_val; return expr->const_llvm_val;
} }
}
switch (node->type) { switch (node->type) {
case NodeTypeBinOpExpr: case NodeTypeBinOpExpr:
return gen_bin_op_expr(g, node); return gen_bin_op_expr(g, node);
@ -2291,12 +2297,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
return LLVMGetUndef(type_entry->type_ref); return LLVMGetUndef(type_entry->type_ref);
} }
if (type_entry->id == TypeTableEntryIdInt) { switch (type_entry->id) {
case TypeTableEntryIdInt:
return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false); return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
} else if (type_entry->id == TypeTableEntryIdPureError) { case TypeTableEntryIdPureError:
assert(const_val->data.x_err.err); assert(const_val->data.x_err.err);
return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref, const_val->data.x_err.err->value, false); return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,
} else if (type_entry->id == TypeTableEntryIdFloat) { const_val->data.x_err.err->value, false);
case TypeTableEntryIdFloat:
if (const_val->data.x_bignum.kind == BigNumKindFloat) { if (const_val->data.x_bignum.kind == BigNumKindFloat) {
return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float); return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
} else { } else {
@ -2306,13 +2314,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
} }
return LLVMConstReal(type_entry->type_ref, x); return LLVMConstReal(type_entry->type_ref, x);
} }
} else if (type_entry->id == TypeTableEntryIdBool) { case TypeTableEntryIdBool:
if (const_val->data.x_bool) { if (const_val->data.x_bool) {
return LLVMConstAllOnes(LLVMInt1Type()); return LLVMConstAllOnes(LLVMInt1Type());
} else { } else {
return LLVMConstNull(LLVMInt1Type()); return LLVMConstNull(LLVMInt1Type());
} }
} else if (type_entry->id == TypeTableEntryIdMaybe) { case TypeTableEntryIdMaybe:
{
TypeTableEntry *child_type = type_entry->data.maybe.child_type; TypeTableEntry *child_type = type_entry->data.maybe.child_type;
LLVMValueRef child_val; LLVMValueRef child_val;
LLVMValueRef maybe_val; LLVMValueRef maybe_val;
@ -2328,15 +2337,23 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
maybe_val, maybe_val,
}; };
return LLVMConstStruct(fields, 2, false); return LLVMConstStruct(fields, 2, false);
} else if (type_entry->id == TypeTableEntryIdStruct) { }
case TypeTableEntryIdStruct:
{
LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count); LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
for (int i = 0; i < type_entry->data.structure.src_field_count; i += 1) { for (int i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
TypeStructField *type_struct_field = &type_entry->data.structure.fields[i]; TypeStructField *type_struct_field = &type_entry->data.structure.fields[i];
if (type_struct_field->gen_index == -1) {
continue;
}
fields[type_struct_field->gen_index] = gen_const_val(g, type_struct_field->type_entry, fields[type_struct_field->gen_index] = gen_const_val(g, type_struct_field->type_entry,
const_val->data.x_struct.fields[i]); const_val->data.x_struct.fields[i]);
} }
return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); return LLVMConstNamedStruct(type_entry->type_ref, fields,
} else if (type_entry->id == TypeTableEntryIdArray) { type_entry->data.structure.gen_field_count);
}
case TypeTableEntryIdArray:
{
TypeTableEntry *child_type = type_entry->data.array.child_type; TypeTableEntry *child_type = type_entry->data.array.child_type;
uint64_t len = type_entry->data.array.len; uint64_t len = type_entry->data.array.len;
LLVMValueRef *values = allocate<LLVMValueRef>(len); LLVMValueRef *values = allocate<LLVMValueRef>(len);
@ -2345,7 +2362,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
values[i] = gen_const_val(g, child_type, field_value); values[i] = gen_const_val(g, child_type, field_value);
} }
return LLVMConstArray(child_type->type_ref, values, len); return LLVMConstArray(child_type->type_ref, values, len);
} else if (type_entry->id == TypeTableEntryIdEnum) { }
case TypeTableEntryIdEnum:
{
LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false); LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
if (type_entry->data.enumeration.gen_field_count == 0) { if (type_entry->data.enumeration.gen_field_count == 0) {
@ -2353,9 +2372,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
} else { } else {
zig_panic("TODO"); zig_panic("TODO");
} }
} else if (type_entry->id == TypeTableEntryIdFn) { }
case TypeTableEntryIdFn:
return const_val->data.x_fn->fn_value; return const_val->data.x_fn->fn_value;
} else if (type_entry->id == TypeTableEntryIdPointer) { case TypeTableEntryIdPointer:
{
TypeTableEntry *child_type = type_entry->data.pointer.child_type; TypeTableEntry *child_type = type_entry->data.pointer.child_type;
int len = const_val->data.x_ptr.len; int len = const_val->data.x_ptr.len;
LLVMValueRef target_val; LLVMValueRef target_val;
@ -2381,7 +2402,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
} else { } else {
return global_value; return global_value;
} }
} else if (type_entry->id == TypeTableEntryIdErrorUnion) { }
case TypeTableEntryIdErrorUnion:
{
TypeTableEntry *child_type = type_entry->data.error.child_type; TypeTableEntry *child_type = type_entry->data.error.child_type;
if (child_type->size_in_bits == 0) { if (child_type->size_in_bits == 0) {
uint64_t value = const_val->data.x_err.err ? const_val->data.x_err.err->value : 0; uint64_t value = const_val->data.x_err.err ? const_val->data.x_err.err->value : 0;
@ -2402,8 +2425,16 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
}; };
return LLVMConstStruct(fields, 2, false); return LLVMConstStruct(fields, 2, false);
} }
} else { }
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdVoid:
zig_unreachable(); zig_unreachable();
} }
} }
@ -2438,7 +2469,8 @@ static void do_code_gen(CodeGen *g) {
VariableTableEntry *var = g->global_vars.at(i); VariableTableEntry *var = g->global_vars.at(i);
if (var->type->id == TypeTableEntryIdNumLitFloat || if (var->type->id == TypeTableEntryIdNumLitFloat ||
var->type->id == TypeTableEntryIdNumLitInt) var->type->id == TypeTableEntryIdNumLitInt ||
var->type->size_in_bits == 0)
{ {
continue; continue;
} }

View File

@ -1316,6 +1316,19 @@ pub fn main(args: [][]u8) -> %void {
%%stdout.printf("BAD\n"); %%stdout.printf("BAD\n");
} }
%%stdout.printf("OK\n"); %%stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("pointer to void return type", R"SOURCE(
import "std.zig";
const x = void{};
fn f() -> &void {
%%stdout.printf("OK\n");
return &x;
}
pub fn main(args: [][]u8) -> %void {
const a = f();
return *a;
} }
)SOURCE", "OK\n"); )SOURCE", "OK\n");
} }