| author | |
| committer | |
| log | 735cdbfdaca6405d1465ea859032412499c658d8 |
| tree | a3b6655d26985adafbf71903c5d5bb7049a45454 |
| parent | aee7ad3de2e3c334ec5aac2d355e4eed086f1cdf |
7 files changed, 151 insertions(+), 22 deletions(-)
src/all_types.hpp+19-2| ... | ... | @@ -90,6 +90,11 @@ enum ConstPtrSpecial { |
| 90 | 90 | // This means that the pointer points to inline memory, so attempting |
| 91 | 91 | // to write a non-compile-time known value is an error |
| 92 | 92 | ConstPtrSpecialInline, |
| 93 | // This means that we did a compile-time pointer reinterpret and we cannot | |
| 94 | // understand the value of pointee at compile time. However, we will still | |
| 95 | // emit a binary with a compile time known address. | |
| 96 | // In this case index is the numeric address value. | |
| 97 | ConstPtrSpecialRuntime, | |
| 93 | 98 | }; |
| 94 | 99 | |
| 95 | 100 | struct ConstPtrValue { |
| ... | ... | @@ -427,8 +432,6 @@ struct AstNodeUnwrapErrorExpr { |
| 427 | 432 | enum CastOp { |
| 428 | 433 | CastOpNoCast, // signifies the function call expression is not a cast |
| 429 | 434 | CastOpNoop, // fn call expr is a cast, but does nothing |
| 430 | CastOpPtrToInt, | |
| 431 | CastOpIntToPtr, | |
| 432 | 435 | CastOpErrToInt, |
| 433 | 436 | CastOpIntToFloat, |
| 434 | 437 | CastOpFloatToInt, |
| ... | ... | @@ -1453,6 +1456,8 @@ enum IrInstructionId { |
| 1453 | 1456 | IrInstructionIdInitEnum, |
| 1454 | 1457 | IrInstructionIdPointerReinterpret, |
| 1455 | 1458 | IrInstructionIdWidenOrShorten, |
| 1459 | IrInstructionIdIntToPtr, | |
| 1460 | IrInstructionIdPtrToInt, | |
| 1456 | 1461 | }; |
| 1457 | 1462 | |
| 1458 | 1463 | struct IrInstruction { |
| ... | ... | @@ -2101,6 +2106,18 @@ struct IrInstructionWidenOrShorten { |
| 2101 | 2106 | IrInstruction *target; |
| 2102 | 2107 | }; |
| 2103 | 2108 | |
| 2109 | struct IrInstructionPtrToInt { | |
| 2110 | IrInstruction base; | |
| 2111 | ||
| 2112 | IrInstruction *target; | |
| 2113 | }; | |
| 2114 | ||
| 2115 | struct IrInstructionIntToPtr { | |
| 2116 | IrInstruction base; | |
| 2117 | ||
| 2118 | IrInstruction *target; | |
| 2119 | }; | |
| 2120 | ||
| 2104 | 2121 | enum LValPurpose { |
| 2105 | 2122 | LValPurposeNone, |
| 2106 | 2123 | LValPurposeAssign, |
src/codegen.cpp+16-4| ... | ... | @@ -969,10 +969,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, |
| 969 | 969 | } else { |
| 970 | 970 | zig_panic("TODO"); |
| 971 | 971 | } |
| 972 | case CastOpPtrToInt: | |
| 973 | return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 974 | case CastOpIntToPtr: | |
| 975 | return LLVMBuildIntToPtr(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 976 | 972 | case CastOpResizeSlice: |
| 977 | 973 | { |
| 978 | 974 | assert(cast_instruction->tmp_ptr); |
| ... | ... | @@ -1114,6 +1110,18 @@ static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executa |
| 1114 | 1110 | instruction->base.value.type, target_val); |
| 1115 | 1111 | } |
| 1116 | 1112 | |
| 1113 | static LLVMValueRef ir_render_int_to_ptr(CodeGen *g, IrExecutable *executable, IrInstructionIntToPtr *instruction) { | |
| 1114 | TypeTableEntry *wanted_type = instruction->base.value.type; | |
| 1115 | LLVMValueRef target_val = ir_llvm_value(g, instruction->target); | |
| 1116 | return LLVMBuildIntToPtr(g->builder, target_val, wanted_type->type_ref, ""); | |
| 1117 | } | |
| 1118 | ||
| 1119 | static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, IrInstructionPtrToInt *instruction) { | |
| 1120 | TypeTableEntry *wanted_type = instruction->base.value.type; | |
| 1121 | LLVMValueRef target_val = ir_llvm_value(g, instruction->target); | |
| 1122 | return LLVMBuildPtrToInt(g->builder, target_val, wanted_type->type_ref, ""); | |
| 1123 | } | |
| 1124 | ||
| 1117 | 1125 | static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable, |
| 1118 | 1126 | IrInstructionUnreachable *unreachable_instruction) |
| 1119 | 1127 | { |
| ... | ... | @@ -2347,6 +2355,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 2347 | 2355 | return ir_render_pointer_reinterpret(g, executable, (IrInstructionPointerReinterpret *)instruction); |
| 2348 | 2356 | case IrInstructionIdWidenOrShorten: |
| 2349 | 2357 | return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction); |
| 2358 | case IrInstructionIdPtrToInt: | |
| 2359 | return ir_render_ptr_to_int(g, executable, (IrInstructionPtrToInt *)instruction); | |
| 2360 | case IrInstructionIdIntToPtr: | |
| 2361 | return ir_render_int_to_ptr(g, executable, (IrInstructionIntToPtr *)instruction); | |
| 2350 | 2362 | case IrInstructionIdContainerInitList: |
| 2351 | 2363 | return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); |
| 2352 | 2364 | case IrInstructionIdSwitchVar: |
src/ir.cpp+84-4| ... | ... | @@ -52,6 +52,7 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ |
| 52 | 52 | |
| 53 | 53 | ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) { |
| 54 | 54 | assert(const_val->special == ConstValSpecialStatic); |
| 55 | assert(const_val->data.x_ptr.special != ConstPtrSpecialRuntime); | |
| 55 | 56 | ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr; |
| 56 | 57 | size_t index = const_val->data.x_ptr.index; |
| 57 | 58 | |
| ... | ... | @@ -459,6 +460,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten * |
| 459 | 460 | return IrInstructionIdWidenOrShorten; |
| 460 | 461 | } |
| 461 | 462 | |
| 463 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrToInt *) { | |
| 464 | return IrInstructionIdPtrToInt; | |
| 465 | } | |
| 466 | ||
| 467 | static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToPtr *) { | |
| 468 | return IrInstructionIdIntToPtr; | |
| 469 | } | |
| 470 | ||
| 462 | 471 | template<typename T> |
| 463 | 472 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 464 | 473 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1899,6 +1908,30 @@ static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, As |
| 1899 | 1908 | return &instruction->base; |
| 1900 | 1909 | } |
| 1901 | 1910 | |
| 1911 | static IrInstruction *ir_build_int_to_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1912 | IrInstruction *target) | |
| 1913 | { | |
| 1914 | IrInstructionIntToPtr *instruction = ir_build_instruction<IrInstructionIntToPtr>( | |
| 1915 | irb, scope, source_node); | |
| 1916 | instruction->target = target; | |
| 1917 | ||
| 1918 | ir_ref_instruction(target); | |
| 1919 | ||
| 1920 | return &instruction->base; | |
| 1921 | } | |
| 1922 | ||
| 1923 | static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1924 | IrInstruction *target) | |
| 1925 | { | |
| 1926 | IrInstructionPtrToInt *instruction = ir_build_instruction<IrInstructionPtrToInt>( | |
| 1927 | irb, scope, source_node); | |
| 1928 | instruction->target = target; | |
| 1929 | ||
| 1930 | ir_ref_instruction(target); | |
| 1931 | ||
| 1932 | return &instruction->base; | |
| 1933 | } | |
| 1934 | ||
| 1902 | 1935 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 1903 | 1936 | results[ReturnKindUnconditional] = 0; |
| 1904 | 1937 | results[ReturnKindError] = 0; |
| ... | ... | @@ -4657,8 +4690,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, |
| 4657 | 4690 | *const_val = *other_val; |
| 4658 | 4691 | const_val->type = new_type; |
| 4659 | 4692 | break; |
| 4660 | case CastOpPtrToInt: | |
| 4661 | case CastOpIntToPtr: | |
| 4662 | 4693 | case CastOpResizeSlice: |
| 4663 | 4694 | case CastOpBytesToSlice: |
| 4664 | 4695 | // can't do it |
| ... | ... | @@ -5234,6 +5265,51 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction |
| 5234 | 5265 | return result; |
| 5235 | 5266 | } |
| 5236 | 5267 | |
| 5268 | static IrInstruction *ir_analyze_ptr_to_int(IrAnalyze *ira, IrInstruction *source_instr, | |
| 5269 | IrInstruction *target, TypeTableEntry *wanted_type) | |
| 5270 | { | |
| 5271 | assert(wanted_type->id == TypeTableEntryIdInt); | |
| 5272 | ||
| 5273 | if (instr_is_comptime(target)) { | |
| 5274 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | |
| 5275 | if (!val) | |
| 5276 | return ira->codegen->invalid_instruction; | |
| 5277 | if (val->data.x_ptr.special == ConstPtrSpecialRuntime) { | |
| 5278 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 5279 | source_instr->source_node, wanted_type, val->depends_on_compile_var); | |
| 5280 | bignum_init_unsigned(&result->value.data.x_bignum, val->data.x_ptr.index); | |
| 5281 | return result; | |
| 5282 | } | |
| 5283 | } | |
| 5284 | ||
| 5285 | IrInstruction *result = ir_build_ptr_to_int(&ira->new_irb, source_instr->scope, | |
| 5286 | source_instr->source_node, target); | |
| 5287 | result->value.type = wanted_type; | |
| 5288 | return result; | |
| 5289 | } | |
| 5290 | ||
| 5291 | static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, | |
| 5292 | IrInstruction *target, TypeTableEntry *wanted_type) | |
| 5293 | { | |
| 5294 | assert(wanted_type->id == TypeTableEntryIdPointer); | |
| 5295 | ||
| 5296 | if (instr_is_comptime(target)) { | |
| 5297 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | |
| 5298 | if (!val) | |
| 5299 | return ira->codegen->invalid_instruction; | |
| 5300 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 5301 | source_instr->source_node, wanted_type, val->depends_on_compile_var); | |
| 5302 | result->value.data.x_ptr.base_ptr = nullptr; | |
| 5303 | result->value.data.x_ptr.index = bignum_to_twos_complement(&val->data.x_bignum); | |
| 5304 | result->value.data.x_ptr.special = ConstPtrSpecialRuntime; | |
| 5305 | return result; | |
| 5306 | } | |
| 5307 | ||
| 5308 | IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, source_instr->scope, | |
| 5309 | source_instr->source_node, target); | |
| 5310 | result->value.type = wanted_type; | |
| 5311 | return result; | |
| 5312 | } | |
| 5237 | 5313 | |
| 5238 | 5314 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, |
| 5239 | 5315 | TypeTableEntry *wanted_type, IrInstruction *value) |
| ... | ... | @@ -5270,7 +5346,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 5270 | 5346 | if ((wanted_type_canon == isize_type || wanted_type_canon == usize_type) && |
| 5271 | 5347 | type_is_codegen_pointer(actual_type_canon)) |
| 5272 | 5348 | { |
| 5273 | return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpPtrToInt, false); | |
| 5349 | return ir_analyze_ptr_to_int(ira, source_instr, value, wanted_type); | |
| 5274 | 5350 | } |
| 5275 | 5351 | |
| 5276 | 5352 | |
| ... | ... | @@ -5278,7 +5354,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 5278 | 5354 | if (wanted_type_canon->id == TypeTableEntryIdPointer && |
| 5279 | 5355 | (actual_type_canon == isize_type || actual_type_canon == usize_type)) |
| 5280 | 5356 | { |
| 5281 | return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToPtr, false); | |
| 5357 | return ir_analyze_int_to_ptr(ira, source_instr, value, wanted_type); | |
| 5282 | 5358 | } |
| 5283 | 5359 | |
| 5284 | 5360 | // explicit widening or shortening cast |
| ... | ... | @@ -9937,6 +10013,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 9937 | 10013 | case IrInstructionIdInvalid: |
| 9938 | 10014 | case IrInstructionIdPointerReinterpret: |
| 9939 | 10015 | case IrInstructionIdWidenOrShorten: |
| 10016 | case IrInstructionIdIntToPtr: | |
| 10017 | case IrInstructionIdPtrToInt: | |
| 9940 | 10018 | case IrInstructionIdStructInit: |
| 9941 | 10019 | case IrInstructionIdStructFieldPtr: |
| 9942 | 10020 | case IrInstructionIdEnumFieldPtr: |
| ... | ... | @@ -10244,6 +10322,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 10244 | 10322 | case IrInstructionIdInitEnum: |
| 10245 | 10323 | case IrInstructionIdPointerReinterpret: |
| 10246 | 10324 | case IrInstructionIdWidenOrShorten: |
| 10325 | case IrInstructionIdPtrToInt: | |
| 10326 | case IrInstructionIdIntToPtr: | |
| 10247 | 10327 | return false; |
| 10248 | 10328 | case IrInstructionIdAsm: |
| 10249 | 10329 | { |
src/ir_print.cpp+23-1| ... | ... | @@ -98,7 +98,11 @@ static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| 98 | 98 | } |
| 99 | 99 | case TypeTableEntryIdPointer: |
| 100 | 100 | fprintf(irp->f, "&"); |
| 101 | ir_print_const_value(irp, const_ptr_pointee(const_val)); | |
| 101 | if (const_val->data.x_ptr.special == ConstPtrSpecialRuntime) { | |
| 102 | fprintf(irp->f, "(runtime pointer value)"); | |
| 103 | } else { | |
| 104 | ir_print_const_value(irp, const_ptr_pointee(const_val)); | |
| 105 | } | |
| 102 | 106 | return; |
| 103 | 107 | case TypeTableEntryIdFn: |
| 104 | 108 | { |
| ... | ... | @@ -934,6 +938,18 @@ static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten |
| 934 | 938 | fprintf(irp->f, ")"); |
| 935 | 939 | } |
| 936 | 940 | |
| 941 | static void ir_print_ptr_to_int(IrPrint *irp, IrInstructionPtrToInt *instruction) { | |
| 942 | fprintf(irp->f, "@ptrToInt("); | |
| 943 | ir_print_other_instruction(irp, instruction->target); | |
| 944 | fprintf(irp->f, ")"); | |
| 945 | } | |
| 946 | ||
| 947 | static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction) { | |
| 948 | fprintf(irp->f, "@intToPtr("); | |
| 949 | ir_print_other_instruction(irp, instruction->target); | |
| 950 | fprintf(irp->f, ")"); | |
| 951 | } | |
| 952 | ||
| 937 | 953 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 938 | 954 | ir_print_prefix(irp, instruction); |
| 939 | 955 | switch (instruction->id) { |
| ... | ... | @@ -1179,6 +1195,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1179 | 1195 | case IrInstructionIdWidenOrShorten: |
| 1180 | 1196 | ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction); |
| 1181 | 1197 | break; |
| 1198 | case IrInstructionIdPtrToInt: | |
| 1199 | ir_print_ptr_to_int(irp, (IrInstructionPtrToInt *)instruction); | |
| 1200 | break; | |
| 1201 | case IrInstructionIdIntToPtr: | |
| 1202 | ir_print_int_to_ptr(irp, (IrInstructionIntToPtr *)instruction); | |
| 1203 | break; | |
| 1182 | 1204 | } |
| 1183 | 1205 | fprintf(irp->f, "\n"); |
| 1184 | 1206 | } |
src/parseh.cpp+1-1| ... | ... | @@ -1203,7 +1203,7 @@ static void process_symbol_macros(Context *c) { |
| 1203 | 1203 | if (var_type->id == TypeTableEntryIdMaybe && !tld_var->var->src_is_const) { |
| 1204 | 1204 | TypeTableEntry *child_type = var_type->data.maybe.child_type; |
| 1205 | 1205 | if (child_type->id == TypeTableEntryIdFn) { |
| 1206 | zig_panic("TODO"); | |
| 1206 | zig_panic("TODO macro alias of function pointer in .h file"); | |
| 1207 | 1207 | //Tld *fn_tld = create_inline_fn_alias(c, ms.name, tld_var->var); |
| 1208 | 1208 | //c->macro_table.put(ms.name, fn_tld); |
| 1209 | 1209 | continue; |
test/cases/misc.zig+8| ... | ... | @@ -414,6 +414,14 @@ fn testTakeAddressOfParameter(f: f32) { |
| 414 | 414 | } |
| 415 | 415 | |
| 416 | 416 | |
| 417 | fn intToPtrCast() { | |
| 418 | @setFnTest(this); | |
| 419 | ||
| 420 | const x = isize(13); | |
| 421 | const y = (&u8)(x); | |
| 422 | const z = usize(y); | |
| 423 | assert(z == 13); | |
| 424 | } | |
| 417 | 425 | |
| 418 | 426 | |
| 419 | 427 |
test/self_hosted.zig-10| ... | ... | @@ -11,16 +11,6 @@ fn getFirstByte(inline T: type, mem: []T) -> u8 { |
| 11 | 11 | } |
| 12 | 12 | |
| 13 | 13 | |
| 14 | // TODO not passing | |
| 15 | fn intToPtrCast() { | |
| 16 | @setFnTest(this); | |
| 17 | ||
| 18 | const x = isize(13); | |
| 19 | const y = (&u8)(x); | |
| 20 | const z = usize(y); | |
| 21 | assert(z == 13); | |
| 22 | } | |
| 23 | ||
| 24 | 14 | // TODO not passing |
| 25 | 15 | fn pointerToVoidReturnType() { |
| 26 | 16 | @setFnTest(this); |