authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-27 14:18:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-27 14:18:20-07:00
log707154da36ee10c7893cacfafdd3034385d69103
tree6504a69798b28899d131de6def91e11ab7a2c18d
parent261517aa4443404e0ab7b7925937a5c1046f58f5

fix codegen for pointers to void


4 files changed, 206 insertions(+), 127 deletions(-)

src/all_types.hpp+4
......@@ -788,6 +788,8 @@ struct TypeTableEntryStruct {
788788 // set this flag temporarily to detect infinite loops
789789 bool embedded_in_current;
790790 bool reported_infinite_err;
791 // whether we've finished resolving it
792 bool complete;
791793};
792794
793795struct TypeTableEntryMaybe {
......@@ -812,6 +814,8 @@ struct TypeTableEntryEnum {
812814 // set this flag temporarily to detect infinite loops
813815 bool embedded_in_current;
814816 bool reported_infinite_err;
817 // whether we've finished resolving it
818 bool complete;
815819};
816820
817821struct TypeTableEntryFn {
src/analyze.cpp+39-9
......@@ -25,6 +25,7 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
2525 BlockContext *context, AstNode *node, Buf *err_name);
2626static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2727 TypeTableEntry *expected_type, AstNode *node);
28static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);
2829
2930static AstNode *first_executing_node(AstNode *node) {
3031 switch (node->type) {
......@@ -152,17 +153,34 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
152153 return *parent_pointer;
153154 } else {
154155 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
155 entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
156156
157157 const char *const_str = is_const ? "const " : "";
158158 buf_resize(&entry->name, 0);
159159 buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
160160
161 entry->size_in_bits = g->pointer_size_bytes * 8;
162 entry->align_in_bits = g->pointer_size_bytes * 8;
163 assert(child_type->di_type);
164 entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type,
165 entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
161 bool zero_bits;
162 if (child_type->size_in_bits == 0) {
163 if (child_type->id == TypeTableEntryIdStruct) {
164 zero_bits = child_type->data.structure.complete;
165 } else if (child_type->id == TypeTableEntryIdEnum) {
166 zero_bits = child_type->data.enumeration.complete;
167 } else {
168 zero_bits = true;
169 }
170 } else {
171 zero_bits = false;
172 }
173
174 if (!zero_bits) {
175 entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
176
177 entry->size_in_bits = g->pointer_size_bytes * 8;
178 entry->align_in_bits = g->pointer_size_bytes * 8;
179 assert(child_type->di_type);
180 entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type,
181 entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
182 }
183
166184 entry->data.pointer.child_type = child_type;
167185 entry->data.pointer.is_const = is_const;
168186
......@@ -511,6 +529,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
511529 // after the gen_param_index += 1 because 0 is the return type
512530 param_di_types[gen_param_index] = gen_type->di_type;
513531 gen_return_type = g->builtin_types.entry_void;
532 } else if (return_type->size_in_bits == 0) {
533 gen_return_type = g->builtin_types.entry_void;
514534 } else {
515535 gen_return_type = return_type;
516536 }
......@@ -584,7 +604,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
584604 LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?
585605 LLVMInternalLinkage : LLVMExternalLinkage);
586606
587 if (gen_return_type->id == TypeTableEntryIdUnreachable) {
607 if (return_type->id == TypeTableEntryIdUnreachable) {
588608 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
589609 }
590610 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
707727
708728 // unset temporary flag
709729 enum_type->data.enumeration.embedded_in_current = false;
730 enum_type->data.enumeration.complete = true;
710731
711732 if (!enum_type->data.enumeration.is_invalid) {
712733 enum_type->data.enumeration.gen_field_count = gen_field_index;
......@@ -872,6 +893,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
872893 struct_type->data.structure.embedded_in_current = false;
873894
874895 struct_type->data.structure.gen_field_count = gen_field_index;
896 struct_type->data.structure.complete = true;
875897
876898 if (!struct_type->data.structure.is_invalid) {
877899
......@@ -1186,7 +1208,9 @@ static bool type_has_codegen_value(TypeTableEntryId id) {
11861208
11871209static void add_global_const_expr(CodeGen *g, Expr *expr) {
11881210 if (expr->const_val.ok &&
1189 type_has_codegen_value(expr->type_entry->id) && !expr->has_global_const)
1211 type_has_codegen_value(expr->type_entry->id) &&
1212 !expr->has_global_const &&
1213 expr->type_entry->size_in_bits > 0)
11901214 {
11911215 g->global_const_list.append(expr);
11921216 expr->has_global_const = true;
......@@ -1776,7 +1800,7 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
17761800 add_node_error(g, node, buf_sprintf("void expression expects no arguments"));
17771801 return g->builtin_types.entry_invalid;
17781802 } else {
1779 return container_type;
1803 return resolve_expr_const_val_as_void(g, node);
17801804 }
17811805 } else if (container_type->id == TypeTableEntryIdUnreachable) {
17821806 if (container_init_expr->entries.length != 0) {
......@@ -1925,6 +1949,12 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
19251949 return return_type;
19261950}
19271951
1952static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node) {
1953 Expr *expr = get_resolved_expr(node);
1954 expr->const_val.ok = true;
1955 return g->builtin_types.entry_void;
1956}
1957
19281958static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type) {
19291959 Expr *expr = get_resolved_expr(node);
19301960 expr->const_val.ok = true;
src/codegen.cpp+150-118
......@@ -510,7 +510,6 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
510510 }
511511
512512 TypeTableEntry *src_return_type = fn_type->data.fn.src_return_type;
513 TypeTableEntry *gen_return_type = fn_type->data.fn.gen_return_type;
514513
515514 int fn_call_param_count = node->data.fn_call_expr.params.length;
516515 bool first_arg_ret = handle_is_ptr(src_return_type);
......@@ -544,7 +543,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
544543 LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val,
545544 gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");
546545
547 if (gen_return_type->id == TypeTableEntryIdUnreachable) {
546 if (src_return_type->id == TypeTableEntryIdUnreachable) {
548547 return LLVMBuildUnreachable(g->builder);
549548 } else if (first_arg_ret) {
550549 return node->data.fn_call_expr.tmp_ptr;
......@@ -821,8 +820,6 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
821820 VariableTableEntry *var = find_variable(expr_node->block_context,
822821 &node->data.symbol_expr.symbol);
823822 assert(var);
824 // semantic checking ensures no variables are constant
825 assert(!var->is_const);
826823
827824 *out_type_entry = var->type;
828825 target_ref = var->value_ref;
......@@ -895,8 +892,13 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
895892 case PrefixOpDereference:
896893 {
897894 LLVMValueRef expr = gen_expr(g, expr_node);
898 add_debug_source_node(g, node);
899 return LLVMBuildLoad(g->builder, expr, "");
895 TypeTableEntry *type_entry = get_expr_type(expr_node);
896 if (type_entry->size_in_bits == 0) {
897 return nullptr;
898 } else {
899 add_debug_source_node(g, node);
900 return LLVMBuildLoad(g->builder, expr, "");
901 }
900902 }
901903 case PrefixOpMaybe:
902904 {
......@@ -2182,8 +2184,12 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
21822184static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
21832185 Expr *expr = get_resolved_expr(node);
21842186 if (expr->const_val.ok) {
2185 assert(expr->const_llvm_val);
2186 return expr->const_llvm_val;
2187 if (expr->type_entry->size_in_bits == 0) {
2188 return nullptr;
2189 } else {
2190 assert(expr->const_llvm_val);
2191 return expr->const_llvm_val;
2192 }
21872193 }
21882194 switch (node->type) {
21892195 case NodeTypeBinOpExpr:
......@@ -2291,119 +2297,144 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
22912297 return LLVMGetUndef(type_entry->type_ref);
22922298 }
22932299
2294 if (type_entry->id == TypeTableEntryIdInt) {
2295 return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
2296 } else if (type_entry->id == TypeTableEntryIdPureError) {
2297 assert(const_val->data.x_err.err);
2298 return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref, const_val->data.x_err.err->value, false);
2299 } else if (type_entry->id == TypeTableEntryIdFloat) {
2300 if (const_val->data.x_bignum.kind == BigNumKindFloat) {
2301 return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
2302 } else {
2303 int64_t x = const_val->data.x_bignum.data.x_uint;
2304 if (const_val->data.x_bignum.is_negative) {
2305 x = -x;
2300 switch (type_entry->id) {
2301 case TypeTableEntryIdInt:
2302 return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
2303 case TypeTableEntryIdPureError:
2304 assert(const_val->data.x_err.err);
2305 return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,
2306 const_val->data.x_err.err->value, false);
2307 case TypeTableEntryIdFloat:
2308 if (const_val->data.x_bignum.kind == BigNumKindFloat) {
2309 return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
2310 } else {
2311 int64_t x = const_val->data.x_bignum.data.x_uint;
2312 if (const_val->data.x_bignum.is_negative) {
2313 x = -x;
2314 }
2315 return LLVMConstReal(type_entry->type_ref, x);
23062316 }
2307 return LLVMConstReal(type_entry->type_ref, x);
2308 }
2309 } else if (type_entry->id == TypeTableEntryIdBool) {
2310 if (const_val->data.x_bool) {
2311 return LLVMConstAllOnes(LLVMInt1Type());
2312 } else {
2313 return LLVMConstNull(LLVMInt1Type());
2314 }
2315 } else if (type_entry->id == TypeTableEntryIdMaybe) {
2316 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
2317 LLVMValueRef child_val;
2318 LLVMValueRef maybe_val;
2319 if (const_val->data.x_maybe) {
2320 child_val = gen_const_val(g, child_type, const_val->data.x_maybe);
2321 maybe_val = LLVMConstAllOnes(LLVMInt1Type());
2322 } else {
2323 child_val = LLVMConstNull(child_type->type_ref);
2324 maybe_val = LLVMConstNull(LLVMInt1Type());
2325 }
2326 LLVMValueRef fields[] = {
2327 child_val,
2328 maybe_val,
2329 };
2330 return LLVMConstStruct(fields, 2, false);
2331 } else if (type_entry->id == TypeTableEntryIdStruct) {
2332 LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
2333 for (int i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
2334 TypeStructField *type_struct_field = &type_entry->data.structure.fields[i];
2335 fields[type_struct_field->gen_index] = gen_const_val(g, type_struct_field->type_entry,
2336 const_val->data.x_struct.fields[i]);
2337 }
2338 return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count);
2339 } else if (type_entry->id == TypeTableEntryIdArray) {
2340 TypeTableEntry *child_type = type_entry->data.array.child_type;
2341 uint64_t len = type_entry->data.array.len;
2342 LLVMValueRef *values = allocate<LLVMValueRef>(len);
2343 for (int i = 0; i < len; i += 1) {
2344 ConstExprValue *field_value = const_val->data.x_array.fields[i];
2345 values[i] = gen_const_val(g, child_type, field_value);
2346 }
2347 return LLVMConstArray(child_type->type_ref, values, len);
2348 } else if (type_entry->id == TypeTableEntryIdEnum) {
2349 LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
2350 LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
2351 if (type_entry->data.enumeration.gen_field_count == 0) {
2352 return tag_value;
2353 } else {
2354 zig_panic("TODO");
2355 }
2356 } else if (type_entry->id == TypeTableEntryIdFn) {
2357 return const_val->data.x_fn->fn_value;
2358 } else if (type_entry->id == TypeTableEntryIdPointer) {
2359 TypeTableEntry *child_type = type_entry->data.pointer.child_type;
2360 int len = const_val->data.x_ptr.len;
2361 LLVMValueRef target_val;
2362 if (len == 1) {
2363 target_val = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[0]);
2364 } else if (len > 1) {
2365 LLVMValueRef *values = allocate<LLVMValueRef>(len);
2366 for (int i = 0; i < len; i += 1) {
2367 values[i] = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[i]);
2317 case TypeTableEntryIdBool:
2318 if (const_val->data.x_bool) {
2319 return LLVMConstAllOnes(LLVMInt1Type());
2320 } else {
2321 return LLVMConstNull(LLVMInt1Type());
23682322 }
2369 target_val = LLVMConstArray(child_type->type_ref, values, len);
2370 } else {
2323 case TypeTableEntryIdMaybe:
2324 {
2325 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
2326 LLVMValueRef child_val;
2327 LLVMValueRef maybe_val;
2328 if (const_val->data.x_maybe) {
2329 child_val = gen_const_val(g, child_type, const_val->data.x_maybe);
2330 maybe_val = LLVMConstAllOnes(LLVMInt1Type());
2331 } else {
2332 child_val = LLVMConstNull(child_type->type_ref);
2333 maybe_val = LLVMConstNull(LLVMInt1Type());
2334 }
2335 LLVMValueRef fields[] = {
2336 child_val,
2337 maybe_val,
2338 };
2339 return LLVMConstStruct(fields, 2, false);
2340 }
2341 case TypeTableEntryIdStruct:
2342 {
2343 LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
2344 for (int i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
2345 TypeStructField *type_struct_field = &type_entry->data.structure.fields[i];
2346 if (type_struct_field->gen_index == -1) {
2347 continue;
2348 }
2349 fields[type_struct_field->gen_index] = gen_const_val(g, type_struct_field->type_entry,
2350 const_val->data.x_struct.fields[i]);
2351 }
2352 return LLVMConstNamedStruct(type_entry->type_ref, fields,
2353 type_entry->data.structure.gen_field_count);
2354 }
2355 case TypeTableEntryIdArray:
2356 {
2357 TypeTableEntry *child_type = type_entry->data.array.child_type;
2358 uint64_t len = type_entry->data.array.len;
2359 LLVMValueRef *values = allocate<LLVMValueRef>(len);
2360 for (int i = 0; i < len; i += 1) {
2361 ConstExprValue *field_value = const_val->data.x_array.fields[i];
2362 values[i] = gen_const_val(g, child_type, field_value);
2363 }
2364 return LLVMConstArray(child_type->type_ref, values, len);
2365 }
2366 case TypeTableEntryIdEnum:
2367 {
2368 LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
2369 LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
2370 if (type_entry->data.enumeration.gen_field_count == 0) {
2371 return tag_value;
2372 } else {
2373 zig_panic("TODO");
2374 }
2375 }
2376 case TypeTableEntryIdFn:
2377 return const_val->data.x_fn->fn_value;
2378 case TypeTableEntryIdPointer:
2379 {
2380 TypeTableEntry *child_type = type_entry->data.pointer.child_type;
2381 int len = const_val->data.x_ptr.len;
2382 LLVMValueRef target_val;
2383 if (len == 1) {
2384 target_val = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[0]);
2385 } else if (len > 1) {
2386 LLVMValueRef *values = allocate<LLVMValueRef>(len);
2387 for (int i = 0; i < len; i += 1) {
2388 values[i] = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[i]);
2389 }
2390 target_val = LLVMConstArray(child_type->type_ref, values, len);
2391 } else {
2392 zig_unreachable();
2393 }
2394 LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(target_val), "");
2395 LLVMSetInitializer(global_value, target_val);
2396 LLVMSetLinkage(global_value, LLVMPrivateLinkage);
2397 LLVMSetGlobalConstant(global_value, type_entry->data.pointer.is_const);
2398 LLVMSetUnnamedAddr(global_value, true);
2399
2400 if (len > 1) {
2401 return LLVMConstBitCast(global_value, type_entry->type_ref);
2402 } else {
2403 return global_value;
2404 }
2405 }
2406 case TypeTableEntryIdErrorUnion:
2407 {
2408 TypeTableEntry *child_type = type_entry->data.error.child_type;
2409 if (child_type->size_in_bits == 0) {
2410 uint64_t value = const_val->data.x_err.err ? const_val->data.x_err.err->value : 0;
2411 return LLVMConstInt(g->err_tag_type->type_ref, value, false);
2412 } else {
2413 LLVMValueRef err_tag_value;
2414 LLVMValueRef err_payload_value;
2415 if (const_val->data.x_err.err) {
2416 err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err.err->value, false);
2417 err_payload_value = LLVMConstNull(child_type->type_ref);
2418 } else {
2419 err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
2420 err_payload_value = gen_const_val(g, child_type, const_val->data.x_err.payload);
2421 }
2422 LLVMValueRef fields[] = {
2423 err_tag_value,
2424 err_payload_value,
2425 };
2426 return LLVMConstStruct(fields, 2, false);
2427 }
2428 }
2429 case TypeTableEntryIdInvalid:
2430 case TypeTableEntryIdMetaType:
2431 case TypeTableEntryIdUnreachable:
2432 case TypeTableEntryIdNumLitFloat:
2433 case TypeTableEntryIdNumLitInt:
2434 case TypeTableEntryIdUndefLit:
2435 case TypeTableEntryIdVoid:
23712436 zig_unreachable();
2372 }
2373 LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(target_val), "");
2374 LLVMSetInitializer(global_value, target_val);
2375 LLVMSetLinkage(global_value, LLVMPrivateLinkage);
2376 LLVMSetGlobalConstant(global_value, type_entry->data.pointer.is_const);
2377 LLVMSetUnnamedAddr(global_value, true);
23782437
2379 if (len > 1) {
2380 return LLVMConstBitCast(global_value, type_entry->type_ref);
2381 } else {
2382 return global_value;
2383 }
2384 } else if (type_entry->id == TypeTableEntryIdErrorUnion) {
2385 TypeTableEntry *child_type = type_entry->data.error.child_type;
2386 if (child_type->size_in_bits == 0) {
2387 uint64_t value = const_val->data.x_err.err ? const_val->data.x_err.err->value : 0;
2388 return LLVMConstInt(g->err_tag_type->type_ref, value, false);
2389 } else {
2390 LLVMValueRef err_tag_value;
2391 LLVMValueRef err_payload_value;
2392 if (const_val->data.x_err.err) {
2393 err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err.err->value, false);
2394 err_payload_value = LLVMConstNull(child_type->type_ref);
2395 } else {
2396 err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
2397 err_payload_value = gen_const_val(g, child_type, const_val->data.x_err.payload);
2398 }
2399 LLVMValueRef fields[] = {
2400 err_tag_value,
2401 err_payload_value,
2402 };
2403 return LLVMConstStruct(fields, 2, false);
2404 }
2405 } else {
2406 zig_unreachable();
24072438 }
24082439}
24092440
......@@ -2438,7 +2469,8 @@ static void do_code_gen(CodeGen *g) {
24382469 VariableTableEntry *var = g->global_vars.at(i);
24392470
24402471 if (var->type->id == TypeTableEntryIdNumLitFloat ||
2441 var->type->id == TypeTableEntryIdNumLitInt)
2472 var->type->id == TypeTableEntryIdNumLitInt ||
2473 var->type->size_in_bits == 0)
24422474 {
24432475 continue;
24442476 }
test/run_tests.cpp+13
......@@ -1316,6 +1316,19 @@ pub fn main(args: [][]u8) -> %void {
13161316 %%stdout.printf("BAD\n");
13171317 }
13181318 %%stdout.printf("OK\n");
1319}
1320 )SOURCE", "OK\n");
1321
1322 add_simple_case("pointer to void return type", R"SOURCE(
1323import "std.zig";
1324const x = void{};
1325fn f() -> &void {
1326 %%stdout.printf("OK\n");
1327 return &x;
1328}
1329pub fn main(args: [][]u8) -> %void {
1330 const a = f();
1331 return *a;
13191332}
13201333 )SOURCE", "OK\n");
13211334}