| ... | @@ -510,7 +510,6 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -510,7 +510,6 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 510 | } | 510 | } |
| 511 | | 511 | |
| 512 | TypeTableEntry *src_return_type = fn_type->data.fn.src_return_type; | 512 | TypeTableEntry *src_return_type = fn_type->data.fn.src_return_type; |
| 513 | TypeTableEntry *gen_return_type = fn_type->data.fn.gen_return_type; | | |
| 514 | | 513 | |
| 515 | int fn_call_param_count = node->data.fn_call_expr.params.length; | 514 | int fn_call_param_count = node->data.fn_call_expr.params.length; |
| 516 | bool first_arg_ret = handle_is_ptr(src_return_type); | 515 | bool first_arg_ret = handle_is_ptr(src_return_type); |
| ... | @@ -544,7 +543,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -544,7 +543,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 544 | LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val, | 543 | LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val, |
| 545 | gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, ""); | 544 | gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, ""); |
| 546 | | 545 | |
| 547 | if (gen_return_type->id == TypeTableEntryIdUnreachable) { | 546 | if (src_return_type->id == TypeTableEntryIdUnreachable) { |
| 548 | return LLVMBuildUnreachable(g->builder); | 547 | return LLVMBuildUnreachable(g->builder); |
| 549 | } else if (first_arg_ret) { | 548 | } else if (first_arg_ret) { |
| 550 | return node->data.fn_call_expr.tmp_ptr; | 549 | return node->data.fn_call_expr.tmp_ptr; |
| ... | @@ -821,8 +820,6 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, | ... | @@ -821,8 +820,6 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, |
| 821 | VariableTableEntry *var = find_variable(expr_node->block_context, | 820 | VariableTableEntry *var = find_variable(expr_node->block_context, |
| 822 | &node->data.symbol_expr.symbol); | 821 | &node->data.symbol_expr.symbol); |
| 823 | assert(var); | 822 | assert(var); |
| 824 | // semantic checking ensures no variables are constant | | |
| 825 | assert(!var->is_const); | | |
| 826 | | 823 | |
| 827 | *out_type_entry = var->type; | 824 | *out_type_entry = var->type; |
| 828 | target_ref = var->value_ref; | 825 | target_ref = var->value_ref; |
| ... | @@ -895,8 +892,13 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { | ... | @@ -895,8 +892,13 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 895 | case PrefixOpDereference: | 892 | case PrefixOpDereference: |
| 896 | { | 893 | { |
| 897 | LLVMValueRef expr = gen_expr(g, expr_node); | 894 | LLVMValueRef expr = gen_expr(g, expr_node); |
| 898 | add_debug_source_node(g, node); | 895 | TypeTableEntry *type_entry = get_expr_type(expr_node); |
| 899 | return LLVMBuildLoad(g->builder, expr, ""); | 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 | } |
| 900 | } | 902 | } |
| 901 | case PrefixOpMaybe: | 903 | case PrefixOpMaybe: |
| 902 | { | 904 | { |
| ... | @@ -2182,8 +2184,12 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { | ... | @@ -2182,8 +2184,12 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { |
| 2182 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | 2184 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 2183 | Expr *expr = get_resolved_expr(node); | 2185 | Expr *expr = get_resolved_expr(node); |
| 2184 | if (expr->const_val.ok) { | 2186 | if (expr->const_val.ok) { |
| 2185 | assert(expr->const_llvm_val); | 2187 | if (expr->type_entry->size_in_bits == 0) { |
| 2186 | return expr->const_llvm_val; | 2188 | return nullptr; |
| | 2189 | } else { |
| | 2190 | assert(expr->const_llvm_val); |
| | 2191 | return expr->const_llvm_val; |
| | 2192 | } |
| 2187 | } | 2193 | } |
| 2188 | switch (node->type) { | 2194 | switch (node->type) { |
| 2189 | case NodeTypeBinOpExpr: | 2195 | case NodeTypeBinOpExpr: |
| ... | @@ -2291,119 +2297,144 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE | ... | @@ -2291,119 +2297,144 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2291 | return LLVMGetUndef(type_entry->type_ref); | 2297 | return LLVMGetUndef(type_entry->type_ref); |
| 2292 | } | 2298 | } |
| 2293 | | 2299 | |
| 2294 | if (type_entry->id == TypeTableEntryIdInt) { | 2300 | switch (type_entry->id) { |
| 2295 | return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false); | 2301 | case TypeTableEntryIdInt: |
| 2296 | } else if (type_entry->id == TypeTableEntryIdPureError) { | 2302 | return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false); |
| 2297 | assert(const_val->data.x_err.err); | 2303 | case TypeTableEntryIdPureError: |
| 2298 | return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref, const_val->data.x_err.err->value, false); | 2304 | assert(const_val->data.x_err.err); |
| 2299 | } else if (type_entry->id == TypeTableEntryIdFloat) { | 2305 | return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref, |
| 2300 | if (const_val->data.x_bignum.kind == BigNumKindFloat) { | 2306 | const_val->data.x_err.err->value, false); |
| 2301 | return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float); | 2307 | case TypeTableEntryIdFloat: |
| 2302 | } else { | 2308 | if (const_val->data.x_bignum.kind == BigNumKindFloat) { |
| 2303 | int64_t x = const_val->data.x_bignum.data.x_uint; | 2309 | return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float); |
| 2304 | if (const_val->data.x_bignum.is_negative) { | 2310 | } else { |
| 2305 | x = -x; | 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); |
| 2306 | } | 2316 | } |
| 2307 | return LLVMConstReal(type_entry->type_ref, x); | 2317 | case TypeTableEntryIdBool: |
| 2308 | } | 2318 | if (const_val->data.x_bool) { |
| 2309 | } else if (type_entry->id == TypeTableEntryIdBool) { | 2319 | return LLVMConstAllOnes(LLVMInt1Type()); |
| 2310 | if (const_val->data.x_bool) { | 2320 | } else { |
| 2311 | return LLVMConstAllOnes(LLVMInt1Type()); | 2321 | return LLVMConstNull(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]); | | |
| 2368 | } | 2322 | } |
| 2369 | target_val = LLVMConstArray(child_type->type_ref, values, len); | 2323 | case TypeTableEntryIdMaybe: |
| 2370 | } else { | 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: |
| 2371 | zig_unreachable(); | 2436 | 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); | | |
| 2378 | | 2437 | |
| 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(); | | |
| 2407 | } | 2438 | } |
| 2408 | } | 2439 | } |
| 2409 | | 2440 | |
| ... | @@ -2438,7 +2469,8 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -2438,7 +2469,8 @@ static void do_code_gen(CodeGen *g) { |
| 2438 | VariableTableEntry *var = g->global_vars.at(i); | 2469 | VariableTableEntry *var = g->global_vars.at(i); |
| 2439 | | 2470 | |
| 2440 | if (var->type->id == TypeTableEntryIdNumLitFloat || | 2471 | if (var->type->id == TypeTableEntryIdNumLitFloat || |
| 2441 | var->type->id == TypeTableEntryIdNumLitInt) | 2472 | var->type->id == TypeTableEntryIdNumLitInt || |
| | 2473 | var->type->size_in_bits == 0) |
| 2442 | { | 2474 | { |
| 2443 | continue; | 2475 | continue; |
| 2444 | } | 2476 | } |