| ... | @@ -34,6 +34,8 @@ pub const CValue = union(enum) { | ... | @@ -34,6 +34,8 @@ pub const CValue = union(enum) { |
| 34 | /// By-value | 34 | /// By-value |
| 35 | decl: *Decl, | 35 | decl: *Decl, |
| 36 | decl_ref: *Decl, | 36 | decl_ref: *Decl, |
| | 37 | /// An undefined (void *) pointer (cannot be dereferenced) |
| | 38 | undefined_ptr: void, |
| 37 | /// Render the slice as an identifier (using fmtIdent) | 39 | /// Render the slice as an identifier (using fmtIdent) |
| 38 | identifier: []const u8, | 40 | identifier: []const u8, |
| 39 | /// Render these bytes literally. | 41 | /// Render these bytes literally. |
| ... | @@ -311,6 +313,10 @@ pub const Function = struct { | ... | @@ -311,6 +313,10 @@ pub const Function = struct { |
| 311 | fn renderType(f: *Function, w: anytype, t: Type) !void { | 313 | fn renderType(f: *Function, w: anytype, t: Type) !void { |
| 312 | return f.object.dg.renderType(w, t); | 314 | return f.object.dg.renderType(w, t); |
| 313 | } | 315 | } |
| | 316 | |
| | 317 | fn renderTypecast(f: *Function, w: anytype, t: Type) !void { |
| | 318 | return f.object.dg.renderTypecast(w, t); |
| | 319 | } |
| 314 | }; | 320 | }; |
| 315 | | 321 | |
| 316 | /// This data is available when outputting .c code for a `Module`. | 322 | /// This data is available when outputting .c code for a `Module`. |
| ... | @@ -365,10 +371,10 @@ pub const DeclGen = struct { | ... | @@ -365,10 +371,10 @@ pub const DeclGen = struct { |
| 365 | | 371 | |
| 366 | if (ty.isSlice()) { | 372 | if (ty.isSlice()) { |
| 367 | try writer.writeByte('('); | 373 | try writer.writeByte('('); |
| 368 | try dg.renderType(writer, ty); | 374 | try dg.renderTypecast(writer, ty); |
| 369 | try writer.writeAll("){"); | 375 | try writer.writeAll("){"); |
| 370 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 376 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 371 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val); | 377 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr()); |
| 372 | try writer.writeAll(", "); | 378 | try writer.writeAll(", "); |
| 373 | try writer.print("{d}", .{val.sliceLen()}); | 379 | try writer.print("{d}", .{val.sliceLen()}); |
| 374 | try writer.writeAll("}"); | 380 | try writer.writeAll("}"); |
| ... | @@ -389,7 +395,7 @@ pub const DeclGen = struct { | ... | @@ -389,7 +395,7 @@ pub const DeclGen = struct { |
| 389 | } | 395 | } |
| 390 | | 396 | |
| 391 | try writer.writeAll("(("); | 397 | try writer.writeAll("(("); |
| 392 | try dg.renderType(writer, ty); | 398 | try dg.renderTypecast(writer, ty); |
| 393 | try writer.writeAll(")&"); | 399 | try writer.writeAll(")&"); |
| 394 | try dg.renderDeclName(decl, writer); | 400 | try dg.renderDeclName(decl, writer); |
| 395 | try writer.writeByte(')'); | 401 | try writer.writeByte(')'); |
| ... | @@ -445,6 +451,57 @@ pub const DeclGen = struct { | ... | @@ -445,6 +451,57 @@ pub const DeclGen = struct { |
| 445 | } | 451 | } |
| 446 | } | 452 | } |
| 447 | | 453 | |
| | 454 | // Renders a "child" pointer (e.g. ElemPtr, FieldPtr) by recursing |
| | 455 | // to the root decl/variable that acts as its parent |
| | 456 | // |
| | 457 | // Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr, since |
| | 458 | // the Type of their container cannot be retrieved from their own Type |
| | 459 | fn renderChildPtr(dg: *DeclGen, writer: anytype, ptr_val: Value) error{ OutOfMemory, AnalysisFail }!Type { |
| | 460 | switch (ptr_val.tag()) { |
| | 461 | .decl_ref_mut, .decl_ref, .variable => { |
| | 462 | const decl = switch (ptr_val.tag()) { |
| | 463 | .decl_ref => ptr_val.castTag(.decl_ref).?.data, |
| | 464 | .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl, |
| | 465 | .variable => ptr_val.castTag(.variable).?.data.owner_decl, |
| | 466 | else => unreachable, |
| | 467 | }; |
| | 468 | try dg.renderDeclValue(writer, decl.ty, ptr_val, decl); |
| | 469 | return decl.ty; |
| | 470 | }, |
| | 471 | .field_ptr => { |
| | 472 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; |
| | 473 | const index = field_ptr.field_index; |
| | 474 | |
| | 475 | try writer.writeAll("&("); |
| | 476 | const container_ty = try dg.renderChildPtr(writer, field_ptr.container_ptr); |
| | 477 | |
| | 478 | const field_name = switch (container_ty.zigTypeTag()) { |
| | 479 | .Struct => container_ty.structFields().keys()[index], |
| | 480 | .Union => container_ty.unionFields().keys()[index], |
| | 481 | else => unreachable, |
| | 482 | }; |
| | 483 | const field_ty = switch (container_ty.zigTypeTag()) { |
| | 484 | .Struct => container_ty.structFields().values()[index].ty, |
| | 485 | .Union => container_ty.unionFields().values()[index].ty, |
| | 486 | else => unreachable, |
| | 487 | }; |
| | 488 | try writer.print(").{ }", .{fmtIdent(field_name)}); |
| | 489 | |
| | 490 | return field_ty; |
| | 491 | }, |
| | 492 | .elem_ptr => { |
| | 493 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; |
| | 494 | try writer.writeAll("&(*"); |
| | 495 | const container_ty = try dg.renderChildPtr(writer, elem_ptr.array_ptr); |
| | 496 | try writer.print(")[{d}]", .{elem_ptr.index}); |
| | 497 | return container_ty.childType(); |
| | 498 | }, |
| | 499 | .opt_payload_ptr => return dg.fail("implement renderChildPtr for optional payload", .{}), |
| | 500 | .eu_payload_ptr => return dg.fail("implement renderChildPtr for error union payload", .{}), |
| | 501 | else => unreachable, |
| | 502 | } |
| | 503 | } |
| | 504 | |
| 448 | fn renderValue( | 505 | fn renderValue( |
| 449 | dg: *DeclGen, | 506 | dg: *DeclGen, |
| 450 | writer: anytype, | 507 | writer: anytype, |
| ... | @@ -531,24 +588,15 @@ pub const DeclGen = struct { | ... | @@ -531,24 +588,15 @@ pub const DeclGen = struct { |
| 531 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 588 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 532 | | 589 | |
| 533 | try writer.writeByte('('); | 590 | try writer.writeByte('('); |
| 534 | try dg.renderType(writer, ty); | 591 | try dg.renderTypecast(writer, ty); |
| 535 | try writer.writeAll("){"); | 592 | try writer.writeAll("){"); |
| 536 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr); | 593 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr); |
| 537 | try writer.writeAll(", "); | 594 | try writer.writeAll(", "); |
| 538 | try dg.renderValue(writer, Type.usize, slice.len); | 595 | try dg.renderValue(writer, Type.usize, slice.len); |
| 539 | try writer.writeAll("}"); | 596 | try writer.writeAll("}"); |
| 540 | }, | 597 | }, |
| 541 | .elem_ptr => { | 598 | .field_ptr, .elem_ptr, .opt_payload_ptr, .eu_payload_ptr => { |
| 542 | const elem_ptr = val.castTag(.elem_ptr).?.data; | 599 | _ = try dg.renderChildPtr(writer, val); |
| 543 | var arena = std.heap.ArenaAllocator.init(dg.module.gpa); | | |
| 544 | defer arena.deinit(); | | |
| 545 | const elem_ptr_ty = try ty.elemPtrType(arena.allocator()); | | |
| 546 | | | |
| 547 | try writer.writeAll("(&(("); | | |
| 548 | try dg.renderType(writer, ty); | | |
| 549 | try writer.writeByte(')'); | | |
| 550 | try dg.renderValue(writer, elem_ptr_ty, elem_ptr.array_ptr); | | |
| 551 | try writer.print(")[{d}])", .{elem_ptr.index}); | | |
| 552 | }, | 600 | }, |
| 553 | .function => { | 601 | .function => { |
| 554 | const func = val.castTag(.function).?.data; | 602 | const func = val.castTag(.function).?.data; |
| ... | @@ -560,7 +608,7 @@ pub const DeclGen = struct { | ... | @@ -560,7 +608,7 @@ pub const DeclGen = struct { |
| 560 | }, | 608 | }, |
| 561 | .int_u64, .one => { | 609 | .int_u64, .one => { |
| 562 | try writer.writeAll("(("); | 610 | try writer.writeAll("(("); |
| 563 | try dg.renderType(writer, ty); | 611 | try dg.renderTypecast(writer, ty); |
| 564 | try writer.print(")0x{x}u)", .{val.toUnsignedInt()}); | 612 | try writer.print(")0x{x}u)", .{val.toUnsignedInt()}); |
| 565 | }, | 613 | }, |
| 566 | else => unreachable, | 614 | else => unreachable, |
| ... | @@ -605,7 +653,7 @@ pub const DeclGen = struct { | ... | @@ -605,7 +653,7 @@ pub const DeclGen = struct { |
| 605 | return writer.print("{}", .{is_null}); | 653 | return writer.print("{}", .{is_null}); |
| 606 | } | 654 | } |
| 607 | try writer.writeByte('('); | 655 | try writer.writeByte('('); |
| 608 | try dg.renderType(writer, ty); | 656 | try dg.renderTypecast(writer, ty); |
| 609 | try writer.writeAll("){"); | 657 | try writer.writeAll("){"); |
| 610 | if (val.castTag(.opt_payload)) |pl| { | 658 | if (val.castTag(.opt_payload)) |pl| { |
| 611 | const payload_val = pl.data; | 659 | const payload_val = pl.data; |
| ... | @@ -641,7 +689,7 @@ pub const DeclGen = struct { | ... | @@ -641,7 +689,7 @@ pub const DeclGen = struct { |
| 641 | } | 689 | } |
| 642 | | 690 | |
| 643 | try writer.writeByte('('); | 691 | try writer.writeByte('('); |
| 644 | try dg.renderType(writer, ty); | 692 | try dg.renderTypecast(writer, ty); |
| 645 | try writer.writeAll("){"); | 693 | try writer.writeAll("){"); |
| 646 | if (val.castTag(.eu_payload)) |pl| { | 694 | if (val.castTag(.eu_payload)) |pl| { |
| 647 | const payload_val = pl.data; | 695 | const payload_val = pl.data; |
| ... | @@ -703,7 +751,7 @@ pub const DeclGen = struct { | ... | @@ -703,7 +751,7 @@ pub const DeclGen = struct { |
| 703 | const field_vals = val.castTag(.@"struct").?.data; | 751 | const field_vals = val.castTag(.@"struct").?.data; |
| 704 | | 752 | |
| 705 | try writer.writeAll("("); | 753 | try writer.writeAll("("); |
| 706 | try dg.renderType(writer, ty); | 754 | try dg.renderTypecast(writer, ty); |
| 707 | try writer.writeAll("){"); | 755 | try writer.writeAll("){"); |
| 708 | | 756 | |
| 709 | for (field_vals) |field_val, i| { | 757 | for (field_vals) |field_val, i| { |
| ... | @@ -723,7 +771,7 @@ pub const DeclGen = struct { | ... | @@ -723,7 +771,7 @@ pub const DeclGen = struct { |
| 723 | const layout = ty.unionGetLayout(target); | 771 | const layout = ty.unionGetLayout(target); |
| 724 | | 772 | |
| 725 | try writer.writeAll("("); | 773 | try writer.writeAll("("); |
| 726 | try dg.renderType(writer, ty); | 774 | try dg.renderTypecast(writer, ty); |
| 727 | try writer.writeAll("){"); | 775 | try writer.writeAll("){"); |
| 728 | | 776 | |
| 729 | if (ty.unionTagType()) |tag_ty| { | 777 | if (ty.unionTagType()) |tag_ty| { |
| ... | @@ -798,8 +846,9 @@ pub const DeclGen = struct { | ... | @@ -798,8 +846,9 @@ pub const DeclGen = struct { |
| 798 | if (params_written > 0) { | 846 | if (params_written > 0) { |
| 799 | try w.writeAll(", "); | 847 | try w.writeAll(", "); |
| 800 | } | 848 | } |
| 801 | try dg.renderType(w, dg.decl.ty.fnParamType(index)); | 849 | const name = CValue{ .arg = index }; |
| 802 | try w.print(" a{d}", .{index}); | 850 | const alignment = Value.initTag(.abi_align_default); |
| | 851 | try dg.renderTypeAndName(w, dg.decl.ty.fnParamType(index), name, .Mut, alignment); |
| 803 | params_written += 1; | 852 | params_written += 1; |
| 804 | } | 853 | } |
| 805 | | 854 | |
| ... | @@ -837,7 +886,7 @@ pub const DeclGen = struct { | ... | @@ -837,7 +886,7 @@ pub const DeclGen = struct { |
| 837 | if (params_written > 0) { | 886 | if (params_written > 0) { |
| 838 | try bw.writeAll(", "); | 887 | try bw.writeAll(", "); |
| 839 | } | 888 | } |
| 840 | try dg.renderType(bw, fn_info.param_types[index]); | 889 | try dg.renderTypecast(bw, fn_info.param_types[index]); |
| 841 | params_written += 1; | 890 | params_written += 1; |
| 842 | } | 891 | } |
| 843 | | 892 | |
| ... | @@ -868,17 +917,16 @@ pub const DeclGen = struct { | ... | @@ -868,17 +917,16 @@ pub const DeclGen = struct { |
| 868 | const bw = buffer.writer(); | 917 | const bw = buffer.writer(); |
| 869 | | 918 | |
| 870 | try bw.writeAll("typedef struct { "); | 919 | try bw.writeAll("typedef struct { "); |
| 871 | const elem_type = t.elemType(); | 920 | |
| 872 | try dg.renderType(bw, elem_type); | 921 | var ptr_type_buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 873 | if (t.isConstPtr()) { | 922 | const ptr_type = t.slicePtrFieldType(&ptr_type_buf); |
| 874 | try bw.writeAll(" const"); | 923 | const ptr_name = CValue{ .bytes = "ptr" }; |
| 875 | } | 924 | const ptr_alignment = Value.initTag(.abi_align_default); |
| 876 | if (t.isVolatilePtr()) { | 925 | try dg.renderTypeAndName(bw, ptr_type, ptr_name, .Mut, ptr_alignment); |
| 877 | try bw.writeAll(" volatile"); | 926 | |
| 878 | } | 927 | try bw.writeAll("; size_t len; } "); |
| 879 | try bw.writeAll(" *"); | | |
| 880 | try bw.writeAll("ptr; size_t len; } "); | | |
| 881 | const name_index = buffer.items.len; | 928 | const name_index = buffer.items.len; |
| | 929 | const elem_type = t.elemType(); |
| 882 | if (t.isConstPtr()) { | 930 | if (t.isConstPtr()) { |
| 883 | try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)}); | 931 | try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)}); |
| 884 | } else { | 932 | } else { |
| ... | @@ -1003,8 +1051,10 @@ pub const DeclGen = struct { | ... | @@ -1003,8 +1051,10 @@ pub const DeclGen = struct { |
| 1003 | const bw = buffer.writer(); | 1051 | const bw = buffer.writer(); |
| 1004 | | 1052 | |
| 1005 | try bw.writeAll("typedef struct { "); | 1053 | try bw.writeAll("typedef struct { "); |
| 1006 | try dg.renderType(bw, child_type); | 1054 | const payload_name = CValue{ .bytes = "payload" }; |
| 1007 | try bw.writeAll(" payload; uint16_t error; } "); | 1055 | const alignment = Value.initTag(.abi_align_default); |
| | 1056 | try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, alignment); |
| | 1057 | try bw.writeAll("; uint16_t error; } "); |
| 1008 | const name_index = buffer.items.len; | 1058 | const name_index = buffer.items.len; |
| 1009 | if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| { | 1059 | if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| { |
| 1010 | const func = inf_err_set_payload.data.func; | 1060 | const func = inf_err_set_payload.data.func; |
| ... | @@ -1030,14 +1080,47 @@ pub const DeclGen = struct { | ... | @@ -1030,14 +1080,47 @@ pub const DeclGen = struct { |
| 1030 | return name; | 1080 | return name; |
| 1031 | } | 1081 | } |
| 1032 | | 1082 | |
| | 1083 | fn renderArrayTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| | 1084 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| | 1085 | defer buffer.deinit(); |
| | 1086 | const bw = buffer.writer(); |
| | 1087 | |
| | 1088 | const elem_type = t.elemType(); |
| | 1089 | const sentinel_bit = @boolToInt(t.sentinel() != null); |
| | 1090 | const c_len = t.arrayLen() + sentinel_bit; |
| | 1091 | |
| | 1092 | try bw.writeAll("typedef "); |
| | 1093 | try dg.renderType(bw, elem_type); |
| | 1094 | |
| | 1095 | const name_start = buffer.items.len + 1; |
| | 1096 | try bw.print(" zig_A_{s}_{d}", .{ typeToCIdentifier(elem_type), c_len }); |
| | 1097 | const name_end = buffer.items.len; |
| | 1098 | |
| | 1099 | try bw.print("[{d}];\n", .{c_len}); |
| | 1100 | |
| | 1101 | const rendered = buffer.toOwnedSlice(); |
| | 1102 | errdefer dg.typedefs.allocator.free(rendered); |
| | 1103 | const name = rendered[name_start..name_end]; |
| | 1104 | |
| | 1105 | try dg.typedefs.ensureUnusedCapacity(1); |
| | 1106 | dg.typedefs.putAssumeCapacityNoClobber( |
| | 1107 | try t.copy(dg.typedefs_arena), |
| | 1108 | .{ .name = name, .rendered = rendered }, |
| | 1109 | ); |
| | 1110 | |
| | 1111 | return name; |
| | 1112 | } |
| | 1113 | |
| 1033 | fn renderOptionalTypedef(dg: *DeclGen, t: Type, child_type: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { | 1114 | fn renderOptionalTypedef(dg: *DeclGen, t: Type, child_type: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1034 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); | 1115 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1035 | defer buffer.deinit(); | 1116 | defer buffer.deinit(); |
| 1036 | const bw = buffer.writer(); | 1117 | const bw = buffer.writer(); |
| 1037 | | 1118 | |
| 1038 | try bw.writeAll("typedef struct { "); | 1119 | try bw.writeAll("typedef struct { "); |
| 1039 | try dg.renderType(bw, child_type); | 1120 | const payload_name = CValue{ .bytes = "payload" }; |
| 1040 | try bw.writeAll(" payload; bool is_null; } "); | 1121 | const alignment = Value.initTag(.abi_align_default); |
| | 1122 | try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, alignment); |
| | 1123 | try bw.writeAll("; bool is_null; } "); |
| 1041 | const name_index = buffer.items.len; | 1124 | const name_index = buffer.items.len; |
| 1042 | try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)}); | 1125 | try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)}); |
| 1043 | | 1126 | |
| ... | @@ -1054,6 +1137,18 @@ pub const DeclGen = struct { | ... | @@ -1054,6 +1137,18 @@ pub const DeclGen = struct { |
| 1054 | return name; | 1137 | return name; |
| 1055 | } | 1138 | } |
| 1056 | | 1139 | |
| | 1140 | /// Renders a type as a single identifier, generating intermediate typedefs |
| | 1141 | /// if necessary. |
| | 1142 | /// |
| | 1143 | /// This is guaranteed to be valid in both typedefs and declarations/definitions. |
| | 1144 | /// |
| | 1145 | /// There are three type formats in total that we support rendering: |
| | 1146 | /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) | |
| | 1147 | /// |---------------------|-----------------|---------------------| |
| | 1148 | /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" | |
| | 1149 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | |
| | 1150 | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | |
| | 1151 | /// |
| 1057 | fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void { | 1152 | fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void { |
| 1058 | const target = dg.module.getTarget(); | 1153 | const target = dg.module.getTarget(); |
| 1059 | | 1154 | |
| ... | @@ -1130,10 +1225,10 @@ pub const DeclGen = struct { | ... | @@ -1130,10 +1225,10 @@ pub const DeclGen = struct { |
| 1130 | return w.writeAll(" *"); | 1225 | return w.writeAll(" *"); |
| 1131 | }, | 1226 | }, |
| 1132 | .Array => { | 1227 | .Array => { |
| 1133 | // We are referencing the array so it will decay to a C pointer. | 1228 | const name = dg.getTypedefName(t) orelse |
| 1134 | // NB: arrays are not really types in C so they are either specified in the declaration | 1229 | try dg.renderArrayTypedef(t); |
| 1135 | // or are already pointed to; our only job is to render the element type. | 1230 | |
| 1136 | return dg.renderType(w, t.elemType()); | 1231 | return w.writeAll(name); |
| 1137 | }, | 1232 | }, |
| 1138 | .Optional => { | 1233 | .Optional => { |
| 1139 | var opt_buf: Type.Payload.ElemType = undefined; | 1234 | var opt_buf: Type.Payload.ElemType = undefined; |
| ... | @@ -1208,6 +1303,39 @@ pub const DeclGen = struct { | ... | @@ -1208,6 +1303,39 @@ pub const DeclGen = struct { |
| 1208 | } | 1303 | } |
| 1209 | } | 1304 | } |
| 1210 | | 1305 | |
| | 1306 | /// Renders a type in C typecast format. |
| | 1307 | /// |
| | 1308 | /// This is guaranteed to be valid in a typecast expression, but not |
| | 1309 | /// necessarily in a variable/field declaration. |
| | 1310 | /// |
| | 1311 | /// There are three type formats in total that we support rendering: |
| | 1312 | /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) | |
| | 1313 | /// |---------------------|-----------------|---------------------| |
| | 1314 | /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" | |
| | 1315 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | |
| | 1316 | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | |
| | 1317 | /// |
| | 1318 | fn renderTypecast( |
| | 1319 | dg: *DeclGen, |
| | 1320 | w: anytype, |
| | 1321 | ty: Type, |
| | 1322 | //mutability: Mutability, |
| | 1323 | //alignment: Value, |
| | 1324 | ) error{ OutOfMemory, AnalysisFail }!void { |
| | 1325 | const name = CValue{ .bytes = "" }; |
| | 1326 | const alignment = Value.initTag(.abi_align_default); |
| | 1327 | return renderTypeAndName(dg, w, ty, name, .Mut, alignment); |
| | 1328 | } |
| | 1329 | |
| | 1330 | /// Renders a type and name in field declaration/definition format. |
| | 1331 | /// |
| | 1332 | /// There are three type formats in total that we support rendering: |
| | 1333 | /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) | |
| | 1334 | /// |---------------------|-----------------|---------------------| |
| | 1335 | /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" | |
| | 1336 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | |
| | 1337 | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | |
| | 1338 | /// |
| 1211 | fn renderTypeAndName( | 1339 | fn renderTypeAndName( |
| 1212 | dg: *DeclGen, | 1340 | dg: *DeclGen, |
| 1213 | w: anytype, | 1341 | w: anytype, |
| ... | @@ -1219,6 +1347,8 @@ pub const DeclGen = struct { | ... | @@ -1219,6 +1347,8 @@ pub const DeclGen = struct { |
| 1219 | var suffix = std.ArrayList(u8).init(dg.gpa); | 1347 | var suffix = std.ArrayList(u8).init(dg.gpa); |
| 1220 | defer suffix.deinit(); | 1348 | defer suffix.deinit(); |
| 1221 | | 1349 | |
| | 1350 | // Any top-level array types are rendered here as a suffix, which |
| | 1351 | // avoids creating typedefs for every array type |
| 1222 | var render_ty = ty; | 1352 | var render_ty = ty; |
| 1223 | while (render_ty.zigTypeTag() == .Array) { | 1353 | while (render_ty.zigTypeTag() == .Array) { |
| 1224 | const sentinel_bit = @boolToInt(render_ty.sentinel() != null); | 1354 | const sentinel_bit = @boolToInt(render_ty.sentinel() != null); |
| ... | @@ -1267,6 +1397,14 @@ pub const DeclGen = struct { | ... | @@ -1267,6 +1397,14 @@ pub const DeclGen = struct { |
| 1267 | try w.writeByte('&'); | 1397 | try w.writeByte('&'); |
| 1268 | return dg.renderDeclName(decl, w); | 1398 | return dg.renderDeclName(decl, w); |
| 1269 | }, | 1399 | }, |
| | 1400 | .undefined_ptr => { |
| | 1401 | const target = dg.module.getTarget(); |
| | 1402 | switch (target.cpu.arch.ptrBitWidth()) { |
| | 1403 | 32 => try w.writeAll("(void *)0xaaaaaaaa"), |
| | 1404 | 64 => try w.writeAll("(void *)0xaaaaaaaaaaaaaaaa"), |
| | 1405 | else => unreachable, |
| | 1406 | } |
| | 1407 | }, |
| 1270 | .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), | 1408 | .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), |
| 1271 | .bytes => |bytes| return w.writeAll(bytes), | 1409 | .bytes => |bytes| return w.writeAll(bytes), |
| 1272 | } | 1410 | } |
| ... | @@ -1285,6 +1423,7 @@ pub const DeclGen = struct { | ... | @@ -1285,6 +1423,7 @@ pub const DeclGen = struct { |
| 1285 | return w.writeByte(')'); | 1423 | return w.writeByte(')'); |
| 1286 | }, | 1424 | }, |
| 1287 | .decl_ref => |decl| return dg.renderDeclName(decl, w), | 1425 | .decl_ref => |decl| return dg.renderDeclName(decl, w), |
| | 1426 | .undefined_ptr => unreachable, |
| 1288 | .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}), | 1427 | .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}), |
| 1289 | .bytes => |bytes| { | 1428 | .bytes => |bytes| { |
| 1290 | try w.writeAll("(*"); | 1429 | try w.writeAll("(*"); |
| ... | @@ -1676,14 +1815,21 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1676,14 +1815,21 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1676 | | 1815 | |
| 1677 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 1816 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 1678 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; | 1817 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 1818 | const ptr_ty = f.air.typeOf(bin_op.lhs); |
| 1679 | | 1819 | |
| 1680 | const ptr = try f.resolveInst(bin_op.lhs); | 1820 | const ptr = try f.resolveInst(bin_op.lhs); |
| 1681 | const index = try f.resolveInst(bin_op.rhs); | 1821 | const index = try f.resolveInst(bin_op.rhs); |
| 1682 | const writer = f.object.writer(); | 1822 | const writer = f.object.writer(); |
| 1683 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); | 1823 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 1684 | try writer.writeAll(" = &"); | 1824 | |
| 1685 | try f.writeCValue(writer, ptr); | 1825 | try writer.writeAll(" = &("); |
| 1686 | try writer.writeByte('['); | 1826 | if (ptr_ty.ptrSize() == .One) { |
| | 1827 | // It's a pointer to an array, so we need to de-reference. |
| | 1828 | try f.writeCValueDeref(writer, ptr); |
| | 1829 | } else { |
| | 1830 | try f.writeCValue(writer, ptr); |
| | 1831 | } |
| | 1832 | try writer.writeAll(")["); |
| 1687 | try f.writeCValue(writer, index); | 1833 | try f.writeCValue(writer, index); |
| 1688 | try writer.writeAll("];\n"); | 1834 | try writer.writeAll("];\n"); |
| 1689 | return local; | 1835 | return local; |
| ... | @@ -1747,13 +1893,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1747,13 +1893,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1747 | const elem_type = inst_ty.elemType(); | 1893 | const elem_type = inst_ty.elemType(); |
| 1748 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; | 1894 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; |
| 1749 | if (!elem_type.isFnOrHasRuntimeBits()) { | 1895 | if (!elem_type.isFnOrHasRuntimeBits()) { |
| 1750 | const target = f.object.dg.module.getTarget(); | 1896 | return CValue.undefined_ptr; |
| 1751 | const literal = switch (target.cpu.arch.ptrBitWidth()) { | | |
| 1752 | 32 => "(void *)0xaaaaaaaa", | | |
| 1753 | 64 => "(void *)0xaaaaaaaaaaaaaaaa", | | |
| 1754 | else => unreachable, | | |
| 1755 | }; | | |
| 1756 | return CValue{ .bytes = literal }; | | |
| 1757 | } | 1897 | } |
| 1758 | | 1898 | |
| 1759 | const target = f.object.dg.module.getTarget(); | 1899 | const target = f.object.dg.module.getTarget(); |
| ... | @@ -1768,10 +1908,6 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1768,10 +1908,6 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1768 | const local = try f.allocAlignedLocal(elem_type, mutability, alignment_value); | 1908 | const local = try f.allocAlignedLocal(elem_type, mutability, alignment_value); |
| 1769 | try writer.writeAll(";\n"); | 1909 | try writer.writeAll(";\n"); |
| 1770 | | 1910 | |
| 1771 | // Arrays are already pointers so they don't need to be referenced. | | |
| 1772 | if (elem_type.zigTypeTag() == .Array) | | |
| 1773 | return CValue{ .local = local.local }; | | |
| 1774 | | | |
| 1775 | return CValue{ .local_ref = local.local }; | 1911 | return CValue{ .local_ref = local.local }; |
| 1776 | } | 1912 | } |
| 1777 | | 1913 | |
| ... | @@ -1808,38 +1944,22 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1808,38 +1944,22 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1808 | // We need to separately initialize arrays with a memcpy so they must be mutable. | 1944 | // We need to separately initialize arrays with a memcpy so they must be mutable. |
| 1809 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); | 1945 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 1810 | | 1946 | |
| 1811 | switch (operand) { | 1947 | if (is_array) { |
| 1812 | .local_ref => |i| { | 1948 | // Insert a memcpy to initialize this array. The source operand is always a pointer |
| 1813 | const wrapped: CValue = .{ .local = i }; | 1949 | // and thus we only need to know size/type information from the local type/dest. |
| 1814 | try writer.writeAll(" = "); | 1950 | try writer.writeAll(";"); |
| 1815 | try f.writeCValue(writer, wrapped); | 1951 | try f.object.indent_writer.insertNewline(); |
| 1816 | try writer.writeAll(";\n"); | 1952 | try writer.writeAll("memcpy("); |
| 1817 | }, | 1953 | try f.writeCValue(writer, local); |
| 1818 | .decl_ref => |decl| { | 1954 | try writer.writeAll(", "); |
| 1819 | const wrapped: CValue = .{ .decl = decl }; | 1955 | try f.writeCValue(writer, operand); |
| 1820 | try writer.writeAll(" = "); | 1956 | try writer.writeAll(", sizeof("); |
| 1821 | try f.writeCValue(writer, wrapped); | 1957 | try f.writeCValue(writer, local); |
| 1822 | try writer.writeAll(";\n"); | 1958 | try writer.writeAll("));\n"); |
| 1823 | }, | 1959 | } else { |
| 1824 | else => { | 1960 | try writer.writeAll(" = "); |
| 1825 | if (is_array) { | 1961 | try f.writeCValueDeref(writer, operand); |
| 1826 | // Insert a memcpy to initialize this array. The source operand is always a pointer | 1962 | try writer.writeAll(";\n"); |
| 1827 | // and thus we only need to know size/type information from the local type/dest. | | |
| 1828 | try writer.writeAll(";"); | | |
| 1829 | try f.object.indent_writer.insertNewline(); | | |
| 1830 | try writer.writeAll("memcpy("); | | |
| 1831 | try f.writeCValue(writer, local); | | |
| 1832 | try writer.writeAll(", "); | | |
| 1833 | try f.writeCValue(writer, operand); | | |
| 1834 | try writer.writeAll(", sizeof("); | | |
| 1835 | try f.writeCValue(writer, local); | | |
| 1836 | try writer.writeAll("));\n"); | | |
| 1837 | } else { | | |
| 1838 | try writer.writeAll(" = "); | | |
| 1839 | try f.writeCValueDeref(writer, operand); | | |
| 1840 | try writer.writeAll(";\n"); | | |
| 1841 | } | | |
| 1842 | }, | | |
| 1843 | } | 1963 | } |
| 1844 | return local; | 1964 | return local; |
| 1845 | } | 1965 | } |
| ... | @@ -1884,7 +2004,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1884,7 +2004,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1884 | const inst_ty = f.air.typeOfIndex(inst); | 2004 | const inst_ty = f.air.typeOfIndex(inst); |
| 1885 | const local = try f.allocLocal(inst_ty, .Const); | 2005 | const local = try f.allocLocal(inst_ty, .Const); |
| 1886 | try writer.writeAll(" = ("); | 2006 | try writer.writeAll(" = ("); |
| 1887 | try f.renderType(writer, inst_ty); | 2007 | try f.renderTypecast(writer, inst_ty); |
| 1888 | try writer.writeAll(")"); | 2008 | try writer.writeAll(")"); |
| 1889 | try f.writeCValue(writer, operand); | 2009 | try f.writeCValue(writer, operand); |
| 1890 | try writer.writeAll(";\n"); | 2010 | try writer.writeAll(";\n"); |
| ... | @@ -1945,7 +2065,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1945,7 +2065,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1945 | return local; | 2065 | return local; |
| 1946 | } | 2066 | } |
| 1947 | | 2067 | |
| 1948 | fn airStoreUndefined(f: *Function, dest_ptr: CValue, dest_child_type: Type) !CValue { | 2068 | fn airStoreUndefined(f: *Function, dest_ptr: CValue) !CValue { |
| 1949 | const is_debug_build = f.object.dg.module.optimizeMode() == .Debug; | 2069 | const is_debug_build = f.object.dg.module.optimizeMode() == .Debug; |
| 1950 | if (!is_debug_build) | 2070 | if (!is_debug_build) |
| 1951 | return CValue.none; | 2071 | return CValue.none; |
| ... | @@ -1954,11 +2074,7 @@ fn airStoreUndefined(f: *Function, dest_ptr: CValue, dest_child_type: Type) !CVa | ... | @@ -1954,11 +2074,7 @@ fn airStoreUndefined(f: *Function, dest_ptr: CValue, dest_child_type: Type) !CVa |
| 1954 | try writer.writeAll("memset("); | 2074 | try writer.writeAll("memset("); |
| 1955 | try f.writeCValue(writer, dest_ptr); | 2075 | try f.writeCValue(writer, dest_ptr); |
| 1956 | try writer.writeAll(", 0xaa, sizeof("); | 2076 | try writer.writeAll(", 0xaa, sizeof("); |
| 1957 | if (dest_child_type.zigTypeTag() == .Array) { | 2077 | try f.writeCValueDeref(writer, dest_ptr); |
| 1958 | try f.writeCValue(writer, dest_ptr); | | |
| 1959 | } else { | | |
| 1960 | try f.writeCValueDeref(writer, dest_ptr); | | |
| 1961 | } | | |
| 1962 | try writer.writeAll("));\n"); | 2078 | try writer.writeAll("));\n"); |
| 1963 | return CValue.none; | 2079 | return CValue.none; |
| 1964 | } | 2080 | } |
| ... | @@ -1975,58 +2091,40 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1975,58 +2091,40 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1975 | const src_val_is_undefined = | 2091 | const src_val_is_undefined = |
| 1976 | if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; | 2092 | if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; |
| 1977 | if (src_val_is_undefined) | 2093 | if (src_val_is_undefined) |
| 1978 | return try airStoreUndefined(f, dest_ptr, lhs_child_type); | 2094 | return try airStoreUndefined(f, dest_ptr); |
| 1979 | | 2095 | |
| 1980 | const writer = f.object.writer(); | 2096 | const writer = f.object.writer(); |
| 1981 | switch (dest_ptr) { | 2097 | if (lhs_child_type.zigTypeTag() == .Array) { |
| 1982 | .local_ref => |i| { | 2098 | // For this memcpy to safely work we need the rhs to have the same |
| 1983 | const dest: CValue = .{ .local = i }; | 2099 | // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). |
| 1984 | try f.writeCValue(writer, dest); | 2100 | const rhs_type = f.air.typeOf(bin_op.rhs); |
| 1985 | try writer.writeAll(" = "); | 2101 | assert(rhs_type.eql(lhs_child_type)); |
| 1986 | try f.writeCValue(writer, src_val); | 2102 | |
| 1987 | try writer.writeAll(";\n"); | 2103 | // If the source is a constant, writeCValue will emit a brace initialization |
| 1988 | }, | 2104 | // so work around this by initializing into new local. |
| 1989 | .decl_ref => |decl| { | 2105 | // TODO this should be done by manually initializing elements of the dest array |
| 1990 | const dest: CValue = .{ .decl = decl }; | 2106 | const array_src = if (src_val == .constant) blk: { |
| 1991 | try f.writeCValue(writer, dest); | 2107 | const new_local = try f.allocLocal(rhs_type, .Const); |
| 1992 | try writer.writeAll(" = "); | 2108 | try writer.writeAll(" = "); |
| 1993 | try f.writeCValue(writer, src_val); | 2109 | try f.writeCValue(writer, src_val); |
| 1994 | try writer.writeAll(";\n"); | 2110 | try writer.writeAll(";"); |
| 1995 | }, | 2111 | try f.object.indent_writer.insertNewline(); |
| 1996 | else => { | 2112 | |
| 1997 | if (lhs_child_type.zigTypeTag() == .Array) { | 2113 | break :blk new_local; |
| 1998 | // For this memcpy to safely work we need the rhs to have the same | 2114 | } else src_val; |
| 1999 | // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). | 2115 | |
| 2000 | const rhs_type = f.air.typeOf(bin_op.rhs); | 2116 | try writer.writeAll("memcpy("); |
| 2001 | assert(rhs_type.eql(lhs_child_type)); | 2117 | try f.writeCValue(writer, dest_ptr); |
| 2002 | | 2118 | try writer.writeAll(", "); |
| 2003 | // If the source is a constant, writeCValue will emit a brace initialization | 2119 | try f.writeCValue(writer, array_src); |
| 2004 | // so work around this by initializing into new local. | 2120 | try writer.writeAll(", sizeof("); |
| 2005 | // TODO this should be done by manually initializing elements of the dest array | 2121 | try f.writeCValue(writer, array_src); |
| 2006 | const array_src = if (src_val == .constant) blk: { | 2122 | try writer.writeAll("));\n"); |
| 2007 | const new_local = try f.allocLocal(rhs_type, .Const); | 2123 | } else { |
| 2008 | try writer.writeAll(" = "); | 2124 | try f.writeCValueDeref(writer, dest_ptr); |
| 2009 | try f.writeCValue(writer, src_val); | 2125 | try writer.writeAll(" = "); |
| 2010 | try writer.writeAll(";"); | 2126 | try f.writeCValue(writer, src_val); |
| 2011 | try f.object.indent_writer.insertNewline(); | 2127 | try writer.writeAll(";\n"); |
| 2012 | | | |
| 2013 | break :blk new_local; | | |
| 2014 | } else src_val; | | |
| 2015 | | | |
| 2016 | try writer.writeAll("memcpy("); | | |
| 2017 | try f.writeCValue(writer, dest_ptr); | | |
| 2018 | try writer.writeAll(", "); | | |
| 2019 | try f.writeCValue(writer, array_src); | | |
| 2020 | try writer.writeAll(", sizeof("); | | |
| 2021 | try f.writeCValue(writer, array_src); | | |
| 2022 | try writer.writeAll("));\n"); | | |
| 2023 | } else { | | |
| 2024 | try f.writeCValueDeref(writer, dest_ptr); | | |
| 2025 | try writer.writeAll(" = "); | | |
| 2026 | try f.writeCValue(writer, src_val); | | |
| 2027 | try writer.writeAll(";\n"); | | |
| 2028 | } | | |
| 2029 | }, | | |
| 2030 | } | 2128 | } |
| 2031 | return CValue.none; | 2129 | return CValue.none; |
| 2032 | } | 2130 | } |
| ... | @@ -2382,17 +2480,24 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CV | ... | @@ -2382,17 +2480,24 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CV |
| 2382 | const writer = f.object.writer(); | 2480 | const writer = f.object.writer(); |
| 2383 | const inst_ty = f.air.typeOfIndex(inst); | 2481 | const inst_ty = f.air.typeOfIndex(inst); |
| 2384 | const local = try f.allocLocal(inst_ty, .Const); | 2482 | const local = try f.allocLocal(inst_ty, .Const); |
| | 2483 | const elem_ty = switch (inst_ty.ptrSize()) { |
| | 2484 | .One => blk: { |
| | 2485 | const array_ty = inst_ty.childType(); |
| | 2486 | break :blk array_ty.childType(); |
| | 2487 | }, |
| | 2488 | else => inst_ty.childType(), |
| | 2489 | }; |
| 2385 | | 2490 | |
| 2386 | // We must convert to and from integer types to prevent UB if the operation results in a NULL pointer, | 2491 | // We must convert to and from integer types to prevent UB if the operation results in a NULL pointer, |
| 2387 | // or if LHS is NULL. The operation is only UB if the result is NULL and then dereferenced. | 2492 | // or if LHS is NULL. The operation is only UB if the result is NULL and then dereferenced. |
| 2388 | try writer.writeAll(" = ("); | 2493 | try writer.writeAll(" = ("); |
| 2389 | try f.renderType(writer, inst_ty); | 2494 | try f.renderTypecast(writer, inst_ty); |
| 2390 | try writer.writeAll(")(((uintptr_t)"); | 2495 | try writer.writeAll(")(((uintptr_t)"); |
| 2391 | try f.writeCValue(writer, lhs); | 2496 | try f.writeCValue(writer, lhs); |
| 2392 | try writer.print("){s}(", .{operator}); | 2497 | try writer.print("){s}(", .{operator}); |
| 2393 | try f.writeCValue(writer, rhs); | 2498 | try f.writeCValue(writer, rhs); |
| 2394 | try writer.writeAll("*sizeof("); | 2499 | try writer.writeAll("*sizeof("); |
| 2395 | try f.renderType(writer, inst_ty.childType()); | 2500 | try f.renderTypecast(writer, elem_ty); |
| 2396 | try writer.print(")));\n", .{}); | 2501 | try writer.print(")));\n", .{}); |
| 2397 | | 2502 | |
| 2398 | return local; | 2503 | return local; |
| ... | @@ -2580,7 +2685,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2580,7 +2685,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2580 | { | 2685 | { |
| 2581 | const local = try f.allocLocal(inst_ty, .Const); | 2686 | const local = try f.allocLocal(inst_ty, .Const); |
| 2582 | try writer.writeAll(" = ("); | 2687 | try writer.writeAll(" = ("); |
| 2583 | try f.renderType(writer, inst_ty); | 2688 | try f.renderTypecast(writer, inst_ty); |
| 2584 | | 2689 | |
| 2585 | try writer.writeAll(")"); | 2690 | try writer.writeAll(")"); |
| 2586 | try f.writeCValue(writer, operand); | 2691 | try f.writeCValue(writer, operand); |
| ... | @@ -2922,13 +3027,12 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc | ... | @@ -2922,13 +3027,12 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 2922 | }, | 3027 | }, |
| 2923 | else => unreachable, | 3028 | else => unreachable, |
| 2924 | } | 3029 | } |
| 2925 | const addrof = if (field_val_ty.zigTypeTag() == .Array) "" else "&"; | | |
| 2926 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; | 3030 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; |
| 2927 | | 3031 | |
| 2928 | const inst_ty = f.air.typeOfIndex(inst); | 3032 | const inst_ty = f.air.typeOfIndex(inst); |
| 2929 | const local = try f.allocLocal(inst_ty, .Const); | 3033 | const local = try f.allocLocal(inst_ty, .Const); |
| 2930 | | 3034 | |
| 2931 | try writer.print(" = {s}", .{addrof}); | 3035 | try writer.print(" = &", .{}); |
| 2932 | try f.writeCValueDeref(writer, struct_ptr); | 3036 | try f.writeCValueDeref(writer, struct_ptr); |
| 2933 | try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); | 3037 | try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); |
| 2934 | return local; | 3038 | return local; |
| ... | @@ -3114,7 +3218,15 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3114,7 +3218,15 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3114 | const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen(); | 3218 | const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen(); |
| 3115 | | 3219 | |
| 3116 | try writer.writeAll(" = { .ptr = "); | 3220 | try writer.writeAll(" = { .ptr = "); |
| 3117 | try f.writeCValue(writer, operand); | 3221 | if (operand == .undefined_ptr) { |
| | 3222 | // Unfortunately, C does not support any equivalent to |
| | 3223 | // &(*(void *)p)[0], although LLVM does via GetElementPtr |
| | 3224 | try f.writeCValue(writer, CValue.undefined_ptr); |
| | 3225 | } else { |
| | 3226 | try writer.writeAll("&("); |
| | 3227 | try f.writeCValueDeref(writer, operand); |
| | 3228 | try writer.writeAll(")[0]"); |
| | 3229 | } |
| 3118 | try writer.print(", .len = {d} }};\n", .{array_len}); | 3230 | try writer.print(", .len = {d} }};\n", .{array_len}); |
| 3119 | return local; | 3231 | return local; |
| 3120 | } | 3232 | } |
| ... | @@ -3146,7 +3258,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3146,7 +3258,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3146 | const operand = try f.resolveInst(un_op); | 3258 | const operand = try f.resolveInst(un_op); |
| 3147 | | 3259 | |
| 3148 | try writer.writeAll(" = ("); | 3260 | try writer.writeAll(" = ("); |
| 3149 | try f.renderType(writer, inst_ty); | 3261 | try f.renderTypecast(writer, inst_ty); |
| 3150 | try writer.writeAll(")"); | 3262 | try writer.writeAll(")"); |
| 3151 | try f.writeCValue(writer, operand); | 3263 | try f.writeCValue(writer, operand); |
| 3152 | try writer.writeAll(";\n"); | 3264 | try writer.writeAll(";\n"); |