| ... | @@ -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. |
| ... | @@ -291,6 +293,19 @@ pub const Function = struct { | ... | @@ -291,6 +293,19 @@ pub const Function = struct { |
| 291 | } | 293 | } |
| 292 | } | 294 | } |
| 293 | | 295 | |
| | 296 | fn writeCValueDeref(f: *Function, w: anytype, c_value: CValue) !void { |
| | 297 | switch (c_value) { |
| | 298 | .constant => |inst| { |
| | 299 | const ty = f.air.typeOf(inst); |
| | 300 | const val = f.air.value(inst).?; |
| | 301 | try w.writeAll("(*"); |
| | 302 | try f.object.dg.renderValue(w, ty, val); |
| | 303 | return w.writeByte(')'); |
| | 304 | }, |
| | 305 | else => return f.object.dg.writeCValueDeref(w, c_value), |
| | 306 | } |
| | 307 | } |
| | 308 | |
| 294 | fn fail(f: *Function, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { | 309 | fn fail(f: *Function, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { |
| 295 | return f.object.dg.fail(format, args); | 310 | return f.object.dg.fail(format, args); |
| 296 | } | 311 | } |
| ... | @@ -298,6 +313,10 @@ pub const Function = struct { | ... | @@ -298,6 +313,10 @@ pub const Function = struct { |
| 298 | fn renderType(f: *Function, w: anytype, t: Type) !void { | 313 | fn renderType(f: *Function, w: anytype, t: Type) !void { |
| 299 | return f.object.dg.renderType(w, t); | 314 | return f.object.dg.renderType(w, t); |
| 300 | } | 315 | } |
| | 316 | |
| | 317 | fn renderTypecast(f: *Function, w: anytype, t: Type) !void { |
| | 318 | return f.object.dg.renderTypecast(w, t); |
| | 319 | } |
| 301 | }; | 320 | }; |
| 302 | | 321 | |
| 303 | /// This data is available when outputting .c code for a `Module`. | 322 | /// This data is available when outputting .c code for a `Module`. |
| ... | @@ -352,10 +371,10 @@ pub const DeclGen = struct { | ... | @@ -352,10 +371,10 @@ pub const DeclGen = struct { |
| 352 | | 371 | |
| 353 | if (ty.isSlice()) { | 372 | if (ty.isSlice()) { |
| 354 | try writer.writeByte('('); | 373 | try writer.writeByte('('); |
| 355 | try dg.renderType(writer, ty); | 374 | try dg.renderTypecast(writer, ty); |
| 356 | try writer.writeAll("){"); | 375 | try writer.writeAll("){"); |
| 357 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 376 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 358 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val); | 377 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr()); |
| 359 | try writer.writeAll(", "); | 378 | try writer.writeAll(", "); |
| 360 | try writer.print("{d}", .{val.sliceLen()}); | 379 | try writer.print("{d}", .{val.sliceLen()}); |
| 361 | try writer.writeAll("}"); | 380 | try writer.writeAll("}"); |
| ... | @@ -376,7 +395,7 @@ pub const DeclGen = struct { | ... | @@ -376,7 +395,7 @@ pub const DeclGen = struct { |
| 376 | } | 395 | } |
| 377 | | 396 | |
| 378 | try writer.writeAll("(("); | 397 | try writer.writeAll("(("); |
| 379 | try dg.renderType(writer, ty); | 398 | try dg.renderTypecast(writer, ty); |
| 380 | try writer.writeAll(")&"); | 399 | try writer.writeAll(")&"); |
| 381 | try dg.renderDeclName(decl, writer); | 400 | try dg.renderDeclName(decl, writer); |
| 382 | try writer.writeByte(')'); | 401 | try writer.writeByte(')'); |
| ... | @@ -432,6 +451,57 @@ pub const DeclGen = struct { | ... | @@ -432,6 +451,57 @@ pub const DeclGen = struct { |
| 432 | } | 451 | } |
| 433 | } | 452 | } |
| 434 | | 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 | |
| 435 | fn renderValue( | 505 | fn renderValue( |
| 436 | dg: *DeclGen, | 506 | dg: *DeclGen, |
| 437 | writer: anytype, | 507 | writer: anytype, |
| ... | @@ -518,24 +588,15 @@ pub const DeclGen = struct { | ... | @@ -518,24 +588,15 @@ pub const DeclGen = struct { |
| 518 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 588 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 519 | | 589 | |
| 520 | try writer.writeByte('('); | 590 | try writer.writeByte('('); |
| 521 | try dg.renderType(writer, ty); | 591 | try dg.renderTypecast(writer, ty); |
| 522 | try writer.writeAll("){"); | 592 | try writer.writeAll("){"); |
| 523 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr); | 593 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr); |
| 524 | try writer.writeAll(", "); | 594 | try writer.writeAll(", "); |
| 525 | try dg.renderValue(writer, Type.usize, slice.len); | 595 | try dg.renderValue(writer, Type.usize, slice.len); |
| 526 | try writer.writeAll("}"); | 596 | try writer.writeAll("}"); |
| 527 | }, | 597 | }, |
| 528 | .elem_ptr => { | 598 | .field_ptr, .elem_ptr, .opt_payload_ptr, .eu_payload_ptr => { |
| 529 | const elem_ptr = val.castTag(.elem_ptr).?.data; | 599 | _ = try dg.renderChildPtr(writer, val); |
| 530 | var arena = std.heap.ArenaAllocator.init(dg.module.gpa); | | |
| 531 | defer arena.deinit(); | | |
| 532 | const elem_ptr_ty = try ty.elemPtrType(arena.allocator()); | | |
| 533 | | | |
| 534 | try writer.writeAll("(&(("); | | |
| 535 | try dg.renderType(writer, ty); | | |
| 536 | try writer.writeByte(')'); | | |
| 537 | try dg.renderValue(writer, elem_ptr_ty, elem_ptr.array_ptr); | | |
| 538 | try writer.print(")[{d}])", .{elem_ptr.index}); | | |
| 539 | }, | 600 | }, |
| 540 | .function => { | 601 | .function => { |
| 541 | const func = val.castTag(.function).?.data; | 602 | const func = val.castTag(.function).?.data; |
| ... | @@ -547,7 +608,7 @@ pub const DeclGen = struct { | ... | @@ -547,7 +608,7 @@ pub const DeclGen = struct { |
| 547 | }, | 608 | }, |
| 548 | .int_u64, .one => { | 609 | .int_u64, .one => { |
| 549 | try writer.writeAll("(("); | 610 | try writer.writeAll("(("); |
| 550 | try dg.renderType(writer, ty); | 611 | try dg.renderTypecast(writer, ty); |
| 551 | try writer.print(")0x{x}u)", .{val.toUnsignedInt()}); | 612 | try writer.print(")0x{x}u)", .{val.toUnsignedInt()}); |
| 552 | }, | 613 | }, |
| 553 | else => unreachable, | 614 | else => unreachable, |
| ... | @@ -592,7 +653,7 @@ pub const DeclGen = struct { | ... | @@ -592,7 +653,7 @@ pub const DeclGen = struct { |
| 592 | return writer.print("{}", .{is_null}); | 653 | return writer.print("{}", .{is_null}); |
| 593 | } | 654 | } |
| 594 | try writer.writeByte('('); | 655 | try writer.writeByte('('); |
| 595 | try dg.renderType(writer, ty); | 656 | try dg.renderTypecast(writer, ty); |
| 596 | try writer.writeAll("){"); | 657 | try writer.writeAll("){"); |
| 597 | if (val.castTag(.opt_payload)) |pl| { | 658 | if (val.castTag(.opt_payload)) |pl| { |
| 598 | const payload_val = pl.data; | 659 | const payload_val = pl.data; |
| ... | @@ -628,7 +689,7 @@ pub const DeclGen = struct { | ... | @@ -628,7 +689,7 @@ pub const DeclGen = struct { |
| 628 | } | 689 | } |
| 629 | | 690 | |
| 630 | try writer.writeByte('('); | 691 | try writer.writeByte('('); |
| 631 | try dg.renderType(writer, ty); | 692 | try dg.renderTypecast(writer, ty); |
| 632 | try writer.writeAll("){"); | 693 | try writer.writeAll("){"); |
| 633 | if (val.castTag(.eu_payload)) |pl| { | 694 | if (val.castTag(.eu_payload)) |pl| { |
| 634 | const payload_val = pl.data; | 695 | const payload_val = pl.data; |
| ... | @@ -690,7 +751,7 @@ pub const DeclGen = struct { | ... | @@ -690,7 +751,7 @@ pub const DeclGen = struct { |
| 690 | const field_vals = val.castTag(.@"struct").?.data; | 751 | const field_vals = val.castTag(.@"struct").?.data; |
| 691 | | 752 | |
| 692 | try writer.writeAll("("); | 753 | try writer.writeAll("("); |
| 693 | try dg.renderType(writer, ty); | 754 | try dg.renderTypecast(writer, ty); |
| 694 | try writer.writeAll("){"); | 755 | try writer.writeAll("){"); |
| 695 | | 756 | |
| 696 | for (field_vals) |field_val, i| { | 757 | for (field_vals) |field_val, i| { |
| ... | @@ -710,7 +771,7 @@ pub const DeclGen = struct { | ... | @@ -710,7 +771,7 @@ pub const DeclGen = struct { |
| 710 | const layout = ty.unionGetLayout(target); | 771 | const layout = ty.unionGetLayout(target); |
| 711 | | 772 | |
| 712 | try writer.writeAll("("); | 773 | try writer.writeAll("("); |
| 713 | try dg.renderType(writer, ty); | 774 | try dg.renderTypecast(writer, ty); |
| 714 | try writer.writeAll("){"); | 775 | try writer.writeAll("){"); |
| 715 | | 776 | |
| 716 | if (ty.unionTagType()) |tag_ty| { | 777 | if (ty.unionTagType()) |tag_ty| { |
| ... | @@ -785,8 +846,9 @@ pub const DeclGen = struct { | ... | @@ -785,8 +846,9 @@ pub const DeclGen = struct { |
| 785 | if (params_written > 0) { | 846 | if (params_written > 0) { |
| 786 | try w.writeAll(", "); | 847 | try w.writeAll(", "); |
| 787 | } | 848 | } |
| 788 | try dg.renderType(w, dg.decl.ty.fnParamType(index)); | 849 | const name = CValue{ .arg = index }; |
| 789 | 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); |
| 790 | params_written += 1; | 852 | params_written += 1; |
| 791 | } | 853 | } |
| 792 | | 854 | |
| ... | @@ -824,7 +886,7 @@ pub const DeclGen = struct { | ... | @@ -824,7 +886,7 @@ pub const DeclGen = struct { |
| 824 | if (params_written > 0) { | 886 | if (params_written > 0) { |
| 825 | try bw.writeAll(", "); | 887 | try bw.writeAll(", "); |
| 826 | } | 888 | } |
| 827 | try dg.renderType(bw, fn_info.param_types[index]); | 889 | try dg.renderTypecast(bw, fn_info.param_types[index]); |
| 828 | params_written += 1; | 890 | params_written += 1; |
| 829 | } | 891 | } |
| 830 | | 892 | |
| ... | @@ -855,17 +917,16 @@ pub const DeclGen = struct { | ... | @@ -855,17 +917,16 @@ pub const DeclGen = struct { |
| 855 | const bw = buffer.writer(); | 917 | const bw = buffer.writer(); |
| 856 | | 918 | |
| 857 | try bw.writeAll("typedef struct { "); | 919 | try bw.writeAll("typedef struct { "); |
| 858 | const elem_type = t.elemType(); | 920 | |
| 859 | try dg.renderType(bw, elem_type); | 921 | var ptr_type_buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 860 | if (t.isConstPtr()) { | 922 | const ptr_type = t.slicePtrFieldType(&ptr_type_buf); |
| 861 | try bw.writeAll(" const"); | 923 | const ptr_name = CValue{ .bytes = "ptr" }; |
| 862 | } | 924 | const ptr_alignment = Value.initTag(.abi_align_default); |
| 863 | if (t.isVolatilePtr()) { | 925 | try dg.renderTypeAndName(bw, ptr_type, ptr_name, .Mut, ptr_alignment); |
| 864 | try bw.writeAll(" volatile"); | 926 | |
| 865 | } | 927 | try bw.writeAll("; size_t len; } "); |
| 866 | try bw.writeAll(" *"); | | |
| 867 | try bw.writeAll("ptr; size_t len; } "); | | |
| 868 | const name_index = buffer.items.len; | 928 | const name_index = buffer.items.len; |
| | 929 | const elem_type = t.elemType(); |
| 869 | if (t.isConstPtr()) { | 930 | if (t.isConstPtr()) { |
| 870 | try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)}); | 931 | try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)}); |
| 871 | } else { | 932 | } else { |
| ... | @@ -990,8 +1051,10 @@ pub const DeclGen = struct { | ... | @@ -990,8 +1051,10 @@ pub const DeclGen = struct { |
| 990 | const bw = buffer.writer(); | 1051 | const bw = buffer.writer(); |
| 991 | | 1052 | |
| 992 | try bw.writeAll("typedef struct { "); | 1053 | try bw.writeAll("typedef struct { "); |
| 993 | try dg.renderType(bw, child_type); | 1054 | const payload_name = CValue{ .bytes = "payload" }; |
| 994 | 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; } "); |
| 995 | const name_index = buffer.items.len; | 1058 | const name_index = buffer.items.len; |
| 996 | 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| { |
| 997 | const func = inf_err_set_payload.data.func; | 1060 | const func = inf_err_set_payload.data.func; |
| ... | @@ -1017,14 +1080,47 @@ pub const DeclGen = struct { | ... | @@ -1017,14 +1080,47 @@ pub const DeclGen = struct { |
| 1017 | return name; | 1080 | return name; |
| 1018 | } | 1081 | } |
| 1019 | | 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 | |
| 1020 | 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 { |
| 1021 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); | 1115 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1022 | defer buffer.deinit(); | 1116 | defer buffer.deinit(); |
| 1023 | const bw = buffer.writer(); | 1117 | const bw = buffer.writer(); |
| 1024 | | 1118 | |
| 1025 | try bw.writeAll("typedef struct { "); | 1119 | try bw.writeAll("typedef struct { "); |
| 1026 | try dg.renderType(bw, child_type); | 1120 | const payload_name = CValue{ .bytes = "payload" }; |
| 1027 | 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; } "); |
| 1028 | const name_index = buffer.items.len; | 1124 | const name_index = buffer.items.len; |
| 1029 | try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)}); | 1125 | try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)}); |
| 1030 | | 1126 | |
| ... | @@ -1041,6 +1137,18 @@ pub const DeclGen = struct { | ... | @@ -1041,6 +1137,18 @@ pub const DeclGen = struct { |
| 1041 | return name; | 1137 | return name; |
| 1042 | } | 1138 | } |
| 1043 | | 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 | /// |
| 1044 | 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 { |
| 1045 | const target = dg.module.getTarget(); | 1153 | const target = dg.module.getTarget(); |
| 1046 | | 1154 | |
| ... | @@ -1117,10 +1225,10 @@ pub const DeclGen = struct { | ... | @@ -1117,10 +1225,10 @@ pub const DeclGen = struct { |
| 1117 | return w.writeAll(" *"); | 1225 | return w.writeAll(" *"); |
| 1118 | }, | 1226 | }, |
| 1119 | .Array => { | 1227 | .Array => { |
| 1120 | // We are referencing the array so it will decay to a C pointer. | 1228 | const name = dg.getTypedefName(t) orelse |
| 1121 | // NB: arrays are not really types in C so they are either specified in the declaration | 1229 | try dg.renderArrayTypedef(t); |
| 1122 | // or are already pointed to; our only job is to render the element type. | 1230 | |
| 1123 | return dg.renderType(w, t.elemType()); | 1231 | return w.writeAll(name); |
| 1124 | }, | 1232 | }, |
| 1125 | .Optional => { | 1233 | .Optional => { |
| 1126 | var opt_buf: Type.Payload.ElemType = undefined; | 1234 | var opt_buf: Type.Payload.ElemType = undefined; |
| ... | @@ -1195,6 +1303,39 @@ pub const DeclGen = struct { | ... | @@ -1195,6 +1303,39 @@ pub const DeclGen = struct { |
| 1195 | } | 1303 | } |
| 1196 | } | 1304 | } |
| 1197 | | 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 | /// |
| 1198 | fn renderTypeAndName( | 1339 | fn renderTypeAndName( |
| 1199 | dg: *DeclGen, | 1340 | dg: *DeclGen, |
| 1200 | w: anytype, | 1341 | w: anytype, |
| ... | @@ -1206,6 +1347,8 @@ pub const DeclGen = struct { | ... | @@ -1206,6 +1347,8 @@ pub const DeclGen = struct { |
| 1206 | var suffix = std.ArrayList(u8).init(dg.gpa); | 1347 | var suffix = std.ArrayList(u8).init(dg.gpa); |
| 1207 | defer suffix.deinit(); | 1348 | defer suffix.deinit(); |
| 1208 | | 1349 | |
| | 1350 | // Any top-level array types are rendered here as a suffix, which |
| | 1351 | // avoids creating typedefs for every array type |
| 1209 | var render_ty = ty; | 1352 | var render_ty = ty; |
| 1210 | while (render_ty.zigTypeTag() == .Array) { | 1353 | while (render_ty.zigTypeTag() == .Array) { |
| 1211 | const sentinel_bit = @boolToInt(render_ty.sentinel() != null); | 1354 | const sentinel_bit = @boolToInt(render_ty.sentinel() != null); |
| ... | @@ -1254,11 +1397,42 @@ pub const DeclGen = struct { | ... | @@ -1254,11 +1397,42 @@ pub const DeclGen = struct { |
| 1254 | try w.writeByte('&'); | 1397 | try w.writeByte('&'); |
| 1255 | return dg.renderDeclName(decl, w); | 1398 | return dg.renderDeclName(decl, w); |
| 1256 | }, | 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 | }, |
| 1257 | .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), | 1408 | .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), |
| 1258 | .bytes => |bytes| return w.writeAll(bytes), | 1409 | .bytes => |bytes| return w.writeAll(bytes), |
| 1259 | } | 1410 | } |
| 1260 | } | 1411 | } |
| 1261 | | 1412 | |
| | 1413 | fn writeCValueDeref(dg: DeclGen, w: anytype, c_value: CValue) !void { |
| | 1414 | switch (c_value) { |
| | 1415 | .none => unreachable, |
| | 1416 | .local => |i| return w.print("(*t{d})", .{i}), |
| | 1417 | .local_ref => |i| return w.print("t{d}", .{i}), |
| | 1418 | .constant => unreachable, |
| | 1419 | .arg => |i| return w.print("(*a{d})", .{i}), |
| | 1420 | .decl => |decl| { |
| | 1421 | try w.writeAll("(*"); |
| | 1422 | try dg.renderDeclName(decl, w); |
| | 1423 | return w.writeByte(')'); |
| | 1424 | }, |
| | 1425 | .decl_ref => |decl| return dg.renderDeclName(decl, w), |
| | 1426 | .undefined_ptr => unreachable, |
| | 1427 | .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}), |
| | 1428 | .bytes => |bytes| { |
| | 1429 | try w.writeAll("(*"); |
| | 1430 | try w.writeAll(bytes); |
| | 1431 | return w.writeByte(')'); |
| | 1432 | }, |
| | 1433 | } |
| | 1434 | } |
| | 1435 | |
| 1262 | fn renderDeclName(dg: DeclGen, decl: *Decl, writer: anytype) !void { | 1436 | fn renderDeclName(dg: DeclGen, decl: *Decl, writer: anytype) !void { |
| 1263 | if (dg.module.decl_exports.get(decl)) |exports| { | 1437 | if (dg.module.decl_exports.get(decl)) |exports| { |
| 1264 | return writer.writeAll(exports[0].options.name); | 1438 | return writer.writeAll(exports[0].options.name); |
| ... | @@ -1493,10 +1667,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -1493,10 +1667,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1493 | .optional_payload_ptr => try airOptionalPayload(f, inst), | 1667 | .optional_payload_ptr => try airOptionalPayload(f, inst), |
| 1494 | .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst), | 1668 | .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst), |
| 1495 | | 1669 | |
| 1496 | .is_err => try airIsErr(f, inst, "", ".", "!="), | 1670 | .is_err => try airIsErr(f, inst, false, "!="), |
| 1497 | .is_non_err => try airIsErr(f, inst, "", ".", "=="), | 1671 | .is_non_err => try airIsErr(f, inst, false, "=="), |
| 1498 | .is_err_ptr => try airIsErr(f, inst, "*", "->", "!="), | 1672 | .is_err_ptr => try airIsErr(f, inst, true, "!="), |
| 1499 | .is_non_err_ptr => try airIsErr(f, inst, "*", "->", "=="), | 1673 | .is_non_err_ptr => try airIsErr(f, inst, true, "=="), |
| 1500 | | 1674 | |
| 1501 | .is_null => try airIsNull(f, inst, "==", ""), | 1675 | .is_null => try airIsNull(f, inst, "==", ""), |
| 1502 | .is_non_null => try airIsNull(f, inst, "!=", ""), | 1676 | .is_non_null => try airIsNull(f, inst, "!=", ""), |
| ... | @@ -1641,14 +1815,21 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1641,14 +1815,21 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1641 | | 1815 | |
| 1642 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 1816 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 1643 | 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); |
| 1644 | | 1819 | |
| 1645 | const ptr = try f.resolveInst(bin_op.lhs); | 1820 | const ptr = try f.resolveInst(bin_op.lhs); |
| 1646 | const index = try f.resolveInst(bin_op.rhs); | 1821 | const index = try f.resolveInst(bin_op.rhs); |
| 1647 | const writer = f.object.writer(); | 1822 | const writer = f.object.writer(); |
| 1648 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); | 1823 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 1649 | try writer.writeAll(" = &"); | 1824 | |
| 1650 | try f.writeCValue(writer, ptr); | 1825 | try writer.writeAll(" = &("); |
| 1651 | 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(")["); |
| 1652 | try f.writeCValue(writer, index); | 1833 | try f.writeCValue(writer, index); |
| 1653 | try writer.writeAll("];\n"); | 1834 | try writer.writeAll("];\n"); |
| 1654 | return local; | 1835 | return local; |
| ... | @@ -1712,13 +1893,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1712,13 +1893,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1712 | const elem_type = inst_ty.elemType(); | 1893 | const elem_type = inst_ty.elemType(); |
| 1713 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; | 1894 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; |
| 1714 | if (!elem_type.isFnOrHasRuntimeBits()) { | 1895 | if (!elem_type.isFnOrHasRuntimeBits()) { |
| 1715 | const target = f.object.dg.module.getTarget(); | 1896 | return CValue.undefined_ptr; |
| 1716 | const literal = switch (target.cpu.arch.ptrBitWidth()) { | | |
| 1717 | 32 => "(void *)0xaaaaaaaa", | | |
| 1718 | 64 => "(void *)0xaaaaaaaaaaaaaaaa", | | |
| 1719 | else => unreachable, | | |
| 1720 | }; | | |
| 1721 | return CValue{ .bytes = literal }; | | |
| 1722 | } | 1897 | } |
| 1723 | | 1898 | |
| 1724 | const target = f.object.dg.module.getTarget(); | 1899 | const target = f.object.dg.module.getTarget(); |
| ... | @@ -1733,10 +1908,6 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1733,10 +1908,6 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1733 | const local = try f.allocAlignedLocal(elem_type, mutability, alignment_value); | 1908 | const local = try f.allocAlignedLocal(elem_type, mutability, alignment_value); |
| 1734 | try writer.writeAll(";\n"); | 1909 | try writer.writeAll(";\n"); |
| 1735 | | 1910 | |
| 1736 | // Arrays are already pointers so they don't need to be referenced. | | |
| 1737 | if (elem_type.zigTypeTag() == .Array) | | |
| 1738 | return CValue{ .local = local.local }; | | |
| 1739 | | | |
| 1740 | return CValue{ .local_ref = local.local }; | 1911 | return CValue{ .local_ref = local.local }; |
| 1741 | } | 1912 | } |
| 1742 | | 1913 | |
| ... | @@ -1773,38 +1944,22 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1773,38 +1944,22 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1773 | // 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. |
| 1774 | 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); |
| 1775 | | 1946 | |
| 1776 | switch (operand) { | 1947 | if (is_array) { |
| 1777 | .local_ref => |i| { | 1948 | // Insert a memcpy to initialize this array. The source operand is always a pointer |
| 1778 | const wrapped: CValue = .{ .local = i }; | 1949 | // and thus we only need to know size/type information from the local type/dest. |
| 1779 | try writer.writeAll(" = "); | 1950 | try writer.writeAll(";"); |
| 1780 | try f.writeCValue(writer, wrapped); | 1951 | try f.object.indent_writer.insertNewline(); |
| 1781 | try writer.writeAll(";\n"); | 1952 | try writer.writeAll("memcpy("); |
| 1782 | }, | 1953 | try f.writeCValue(writer, local); |
| 1783 | .decl_ref => |decl| { | 1954 | try writer.writeAll(", "); |
| 1784 | const wrapped: CValue = .{ .decl = decl }; | 1955 | try f.writeCValue(writer, operand); |
| 1785 | try writer.writeAll(" = "); | 1956 | try writer.writeAll(", sizeof("); |
| 1786 | try f.writeCValue(writer, wrapped); | 1957 | try f.writeCValue(writer, local); |
| 1787 | try writer.writeAll(";\n"); | 1958 | try writer.writeAll("));\n"); |
| 1788 | }, | 1959 | } else { |
| 1789 | else => { | 1960 | try writer.writeAll(" = "); |
| 1790 | if (is_array) { | 1961 | try f.writeCValueDeref(writer, operand); |
| 1791 | // Insert a memcpy to initialize this array. The source operand is always a pointer | 1962 | try writer.writeAll(";\n"); |
| 1792 | // and thus we only need to know size/type information from the local type/dest. | | |
| 1793 | try writer.writeAll(";"); | | |
| 1794 | try f.object.indent_writer.insertNewline(); | | |
| 1795 | try writer.writeAll("memcpy("); | | |
| 1796 | try f.writeCValue(writer, local); | | |
| 1797 | try writer.writeAll(", "); | | |
| 1798 | try f.writeCValue(writer, operand); | | |
| 1799 | try writer.writeAll(", sizeof("); | | |
| 1800 | try f.writeCValue(writer, local); | | |
| 1801 | try writer.writeAll("));\n"); | | |
| 1802 | } else { | | |
| 1803 | try writer.writeAll(" = *"); | | |
| 1804 | try f.writeCValue(writer, operand); | | |
| 1805 | try writer.writeAll(";\n"); | | |
| 1806 | } | | |
| 1807 | }, | | |
| 1808 | } | 1963 | } |
| 1809 | return local; | 1964 | return local; |
| 1810 | } | 1965 | } |
| ... | @@ -1849,7 +2004,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1849,7 +2004,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1849 | const inst_ty = f.air.typeOfIndex(inst); | 2004 | const inst_ty = f.air.typeOfIndex(inst); |
| 1850 | const local = try f.allocLocal(inst_ty, .Const); | 2005 | const local = try f.allocLocal(inst_ty, .Const); |
| 1851 | try writer.writeAll(" = ("); | 2006 | try writer.writeAll(" = ("); |
| 1852 | try f.renderType(writer, inst_ty); | 2007 | try f.renderTypecast(writer, inst_ty); |
| 1853 | try writer.writeAll(")"); | 2008 | try writer.writeAll(")"); |
| 1854 | try f.writeCValue(writer, operand); | 2009 | try f.writeCValue(writer, operand); |
| 1855 | try writer.writeAll(";\n"); | 2010 | try writer.writeAll(";\n"); |
| ... | @@ -1910,39 +2065,17 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1910,39 +2065,17 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1910 | return local; | 2065 | return local; |
| 1911 | } | 2066 | } |
| 1912 | | 2067 | |
| 1913 | fn airStoreUndefined(f: *Function, dest_ptr: CValue, dest_child_type: Type) !CValue { | 2068 | fn airStoreUndefined(f: *Function, dest_ptr: CValue) !CValue { |
| 1914 | const is_debug_build = f.object.dg.module.optimizeMode() == .Debug; | 2069 | const is_debug_build = f.object.dg.module.optimizeMode() == .Debug; |
| 1915 | if (!is_debug_build) | 2070 | if (!is_debug_build) |
| 1916 | return CValue.none; | 2071 | return CValue.none; |
| 1917 | | 2072 | |
| 1918 | const writer = f.object.writer(); | 2073 | const writer = f.object.writer(); |
| 1919 | switch (dest_ptr) { | 2074 | try writer.writeAll("memset("); |
| 1920 | .local_ref => |i| { | 2075 | try f.writeCValue(writer, dest_ptr); |
| 1921 | const dest: CValue = .{ .local = i }; | 2076 | try writer.writeAll(", 0xaa, sizeof("); |
| 1922 | try writer.writeAll("memset(&"); | 2077 | try f.writeCValueDeref(writer, dest_ptr); |
| 1923 | try f.writeCValue(writer, dest); | 2078 | try writer.writeAll("));\n"); |
| 1924 | try writer.writeAll(", 0xaa, sizeof("); | | |
| 1925 | try f.writeCValue(writer, dest); | | |
| 1926 | try writer.writeAll("));\n"); | | |
| 1927 | }, | | |
| 1928 | .decl_ref => |decl| { | | |
| 1929 | const dest: CValue = .{ .decl = decl }; | | |
| 1930 | try writer.writeAll("memset(&"); | | |
| 1931 | try f.writeCValue(writer, dest); | | |
| 1932 | try writer.writeAll(", 0xaa, sizeof("); | | |
| 1933 | try f.writeCValue(writer, dest); | | |
| 1934 | try writer.writeAll("));\n"); | | |
| 1935 | }, | | |
| 1936 | else => { | | |
| 1937 | const indirection = if (dest_child_type.zigTypeTag() == .Array) "" else "*"; | | |
| 1938 | | | |
| 1939 | try writer.writeAll("memset("); | | |
| 1940 | try f.writeCValue(writer, dest_ptr); | | |
| 1941 | try writer.print(", 0xaa, sizeof({s}", .{indirection}); | | |
| 1942 | try f.writeCValue(writer, dest_ptr); | | |
| 1943 | try writer.writeAll("));\n"); | | |
| 1944 | }, | | |
| 1945 | } | | |
| 1946 | return CValue.none; | 2079 | return CValue.none; |
| 1947 | } | 2080 | } |
| 1948 | | 2081 | |
| ... | @@ -1958,59 +2091,40 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1958,59 +2091,40 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1958 | const src_val_is_undefined = | 2091 | const src_val_is_undefined = |
| 1959 | 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; |
| 1960 | if (src_val_is_undefined) | 2093 | if (src_val_is_undefined) |
| 1961 | return try airStoreUndefined(f, dest_ptr, lhs_child_type); | 2094 | return try airStoreUndefined(f, dest_ptr); |
| 1962 | | 2095 | |
| 1963 | const writer = f.object.writer(); | 2096 | const writer = f.object.writer(); |
| 1964 | switch (dest_ptr) { | 2097 | if (lhs_child_type.zigTypeTag() == .Array) { |
| 1965 | .local_ref => |i| { | 2098 | // For this memcpy to safely work we need the rhs to have the same |
| 1966 | const dest: CValue = .{ .local = i }; | 2099 | // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). |
| 1967 | try f.writeCValue(writer, dest); | 2100 | const rhs_type = f.air.typeOf(bin_op.rhs); |
| 1968 | try writer.writeAll(" = "); | 2101 | assert(rhs_type.eql(lhs_child_type)); |
| 1969 | try f.writeCValue(writer, src_val); | 2102 | |
| 1970 | try writer.writeAll(";\n"); | 2103 | // If the source is a constant, writeCValue will emit a brace initialization |
| 1971 | }, | 2104 | // so work around this by initializing into new local. |
| 1972 | .decl_ref => |decl| { | 2105 | // TODO this should be done by manually initializing elements of the dest array |
| 1973 | const dest: CValue = .{ .decl = decl }; | 2106 | const array_src = if (src_val == .constant) blk: { |
| 1974 | try f.writeCValue(writer, dest); | 2107 | const new_local = try f.allocLocal(rhs_type, .Const); |
| 1975 | try writer.writeAll(" = "); | 2108 | try writer.writeAll(" = "); |
| 1976 | try f.writeCValue(writer, src_val); | 2109 | try f.writeCValue(writer, src_val); |
| 1977 | try writer.writeAll(";\n"); | 2110 | try writer.writeAll(";"); |
| 1978 | }, | 2111 | try f.object.indent_writer.insertNewline(); |
| 1979 | else => { | 2112 | |
| 1980 | if (lhs_child_type.zigTypeTag() == .Array) { | 2113 | break :blk new_local; |
| 1981 | // For this memcpy to safely work we need the rhs to have the same | 2114 | } else src_val; |
| 1982 | // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). | 2115 | |
| 1983 | const rhs_type = f.air.typeOf(bin_op.rhs); | 2116 | try writer.writeAll("memcpy("); |
| 1984 | assert(rhs_type.eql(lhs_child_type)); | 2117 | try f.writeCValue(writer, dest_ptr); |
| 1985 | | 2118 | try writer.writeAll(", "); |
| 1986 | // If the source is a constant, writeCValue will emit a brace initialization | 2119 | try f.writeCValue(writer, array_src); |
| 1987 | // so work around this by initializing into new local. | 2120 | try writer.writeAll(", sizeof("); |
| 1988 | // TODO this should be done by manually initializing elements of the dest array | 2121 | try f.writeCValue(writer, array_src); |
| 1989 | const array_src = if (src_val == .constant) blk: { | 2122 | try writer.writeAll("));\n"); |
| 1990 | const new_local = try f.allocLocal(rhs_type, .Const); | 2123 | } else { |
| 1991 | try writer.writeAll(" = "); | 2124 | try f.writeCValueDeref(writer, dest_ptr); |
| 1992 | try f.writeCValue(writer, src_val); | 2125 | try writer.writeAll(" = "); |
| 1993 | try writer.writeAll(";"); | 2126 | try f.writeCValue(writer, src_val); |
| 1994 | try f.object.indent_writer.insertNewline(); | 2127 | try writer.writeAll(";\n"); |
| 1995 | | | |
| 1996 | break :blk new_local; | | |
| 1997 | } else src_val; | | |
| 1998 | | | |
| 1999 | try writer.writeAll("memcpy("); | | |
| 2000 | try f.writeCValue(writer, dest_ptr); | | |
| 2001 | try writer.writeAll(", "); | | |
| 2002 | try f.writeCValue(writer, array_src); | | |
| 2003 | try writer.writeAll(", sizeof("); | | |
| 2004 | try f.writeCValue(writer, array_src); | | |
| 2005 | try writer.writeAll("));\n"); | | |
| 2006 | } else { | | |
| 2007 | try writer.writeAll("*"); | | |
| 2008 | try f.writeCValue(writer, dest_ptr); | | |
| 2009 | try writer.writeAll(" = "); | | |
| 2010 | try f.writeCValue(writer, src_val); | | |
| 2011 | try writer.writeAll(";\n"); | | |
| 2012 | } | | |
| 2013 | }, | | |
| 2014 | } | 2128 | } |
| 2015 | return CValue.none; | 2129 | return CValue.none; |
| 2016 | } | 2130 | } |
| ... | @@ -2366,17 +2480,24 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CV | ... | @@ -2366,17 +2480,24 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CV |
| 2366 | const writer = f.object.writer(); | 2480 | const writer = f.object.writer(); |
| 2367 | const inst_ty = f.air.typeOfIndex(inst); | 2481 | const inst_ty = f.air.typeOfIndex(inst); |
| 2368 | 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 | }; |
| 2369 | | 2490 | |
| 2370 | // 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, |
| 2371 | // 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. |
| 2372 | try writer.writeAll(" = ("); | 2493 | try writer.writeAll(" = ("); |
| 2373 | try f.renderType(writer, inst_ty); | 2494 | try f.renderTypecast(writer, inst_ty); |
| 2374 | try writer.writeAll(")(((uintptr_t)"); | 2495 | try writer.writeAll(")(((uintptr_t)"); |
| 2375 | try f.writeCValue(writer, lhs); | 2496 | try f.writeCValue(writer, lhs); |
| 2376 | try writer.print("){s}(", .{operator}); | 2497 | try writer.print("){s}(", .{operator}); |
| 2377 | try f.writeCValue(writer, rhs); | 2498 | try f.writeCValue(writer, rhs); |
| 2378 | try writer.writeAll("*sizeof("); | 2499 | try writer.writeAll("*sizeof("); |
| 2379 | try f.renderType(writer, inst_ty.childType()); | 2500 | try f.renderTypecast(writer, elem_ty); |
| 2380 | try writer.print(")));\n", .{}); | 2501 | try writer.print(")));\n", .{}); |
| 2381 | | 2502 | |
| 2382 | return local; | 2503 | return local; |
| ... | @@ -2564,7 +2685,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2564,7 +2685,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2564 | { | 2685 | { |
| 2565 | const local = try f.allocLocal(inst_ty, .Const); | 2686 | const local = try f.allocLocal(inst_ty, .Const); |
| 2566 | try writer.writeAll(" = ("); | 2687 | try writer.writeAll(" = ("); |
| 2567 | try f.renderType(writer, inst_ty); | 2688 | try f.renderTypecast(writer, inst_ty); |
| 2568 | | 2689 | |
| 2569 | try writer.writeAll(")"); | 2690 | try writer.writeAll(")"); |
| 2570 | try f.writeCValue(writer, operand); | 2691 | try f.writeCValue(writer, operand); |
| ... | @@ -2852,16 +2973,15 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2852,16 +2973,15 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2852 | return operand; | 2973 | return operand; |
| 2853 | } | 2974 | } |
| 2854 | | 2975 | |
| 2855 | try writer.writeAll("("); | 2976 | try f.writeCValueDeref(writer, operand); |
| 2856 | try f.writeCValue(writer, operand); | 2977 | try writer.writeAll(".is_null = false;\n"); |
| 2857 | try writer.writeAll(")->is_null = false;\n"); | | |
| 2858 | | 2978 | |
| 2859 | const inst_ty = f.air.typeOfIndex(inst); | 2979 | const inst_ty = f.air.typeOfIndex(inst); |
| 2860 | const local = try f.allocLocal(inst_ty, .Const); | 2980 | const local = try f.allocLocal(inst_ty, .Const); |
| 2861 | try writer.writeAll(" = &("); | 2981 | try writer.writeAll(" = &"); |
| 2862 | try f.writeCValue(writer, operand); | 2982 | try f.writeCValueDeref(writer, operand); |
| 2863 | | 2983 | |
| 2864 | try writer.writeAll(")->payload;\n"); | 2984 | try writer.writeAll(".payload;\n"); |
| 2865 | return local; | 2985 | return local; |
| 2866 | } | 2986 | } |
| 2867 | | 2987 | |
| ... | @@ -2907,23 +3027,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc | ... | @@ -2907,23 +3027,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 2907 | }, | 3027 | }, |
| 2908 | else => unreachable, | 3028 | else => unreachable, |
| 2909 | } | 3029 | } |
| 2910 | const addrof = if (field_val_ty.zigTypeTag() == .Array) "" else "&"; | | |
| 2911 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; | 3030 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; |
| 2912 | | 3031 | |
| 2913 | const inst_ty = f.air.typeOfIndex(inst); | 3032 | const inst_ty = f.air.typeOfIndex(inst); |
| 2914 | const local = try f.allocLocal(inst_ty, .Const); | 3033 | const local = try f.allocLocal(inst_ty, .Const); |
| 2915 | switch (struct_ptr) { | 3034 | |
| 2916 | .local_ref => |i| { | 3035 | try writer.print(" = &", .{}); |
| 2917 | try writer.print(" = {s}t{d}.{s}{ };\n", .{ | 3036 | try f.writeCValueDeref(writer, struct_ptr); |
| 2918 | addrof, i, payload, fmtIdent(field_name), | 3037 | try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); |
| 2919 | }); | | |
| 2920 | }, | | |
| 2921 | else => { | | |
| 2922 | try writer.print(" = {s}", .{addrof}); | | |
| 2923 | try f.writeCValue(writer, struct_ptr); | | |
| 2924 | try writer.print("->{s}{ };\n", .{ payload, fmtIdent(field_name) }); | | |
| 2925 | }, | | |
| 2926 | } | | |
| 2927 | return local; | 3038 | return local; |
| 2928 | } | 3039 | } |
| 2929 | | 3040 | |
| ... | @@ -2975,13 +3086,14 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2975,13 +3086,14 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2975 | } | 3086 | } |
| 2976 | } | 3087 | } |
| 2977 | | 3088 | |
| 2978 | const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else "."; | | |
| 2979 | | | |
| 2980 | const local = try f.allocLocal(inst_ty, .Const); | 3089 | const local = try f.allocLocal(inst_ty, .Const); |
| 2981 | try writer.writeAll(" = ("); | 3090 | try writer.writeAll(" = "); |
| 2982 | try f.writeCValue(writer, operand); | 3091 | if (operand_ty.zigTypeTag() == .Pointer) { |
| 2983 | | 3092 | try f.writeCValueDeref(writer, operand); |
| 2984 | try writer.print("){s}error;\n", .{maybe_deref}); | 3093 | } else { |
| | 3094 | try f.writeCValue(writer, operand); |
| | 3095 | } |
| | 3096 | try writer.writeAll(".error;\n"); |
| 2985 | return local; | 3097 | return local; |
| 2986 | } | 3098 | } |
| 2987 | | 3099 | |
| ... | @@ -3069,8 +3181,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3069,8 +3181,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3069 | fn airIsErr( | 3181 | fn airIsErr( |
| 3070 | f: *Function, | 3182 | f: *Function, |
| 3071 | inst: Air.Inst.Index, | 3183 | inst: Air.Inst.Index, |
| 3072 | deref_prefix: [*:0]const u8, | 3184 | is_ptr: bool, |
| 3073 | deref_suffix: [*:0]const u8, | | |
| 3074 | op_str: [*:0]const u8, | 3185 | op_str: [*:0]const u8, |
| 3075 | ) !CValue { | 3186 | ) !CValue { |
| 3076 | if (f.liveness.isUnused(inst)) | 3187 | if (f.liveness.isUnused(inst)) |
| ... | @@ -3082,15 +3193,16 @@ fn airIsErr( | ... | @@ -3082,15 +3193,16 @@ fn airIsErr( |
| 3082 | const operand_ty = f.air.typeOf(un_op); | 3193 | const operand_ty = f.air.typeOf(un_op); |
| 3083 | const local = try f.allocLocal(Type.initTag(.bool), .Const); | 3194 | const local = try f.allocLocal(Type.initTag(.bool), .Const); |
| 3084 | const payload_ty = operand_ty.errorUnionPayload(); | 3195 | const payload_ty = operand_ty.errorUnionPayload(); |
| 3085 | if (!payload_ty.hasRuntimeBits()) { | 3196 | try writer.writeAll(" = "); |
| 3086 | try writer.print(" = {s}", .{deref_prefix}); | 3197 | if (is_ptr) { |
| 3087 | try f.writeCValue(writer, operand); | 3198 | try f.writeCValueDeref(writer, operand); |
| 3088 | try writer.print(" {s} 0;\n", .{op_str}); | | |
| 3089 | } else { | 3199 | } else { |
| 3090 | try writer.writeAll(" = "); | | |
| 3091 | try f.writeCValue(writer, operand); | 3200 | try f.writeCValue(writer, operand); |
| 3092 | try writer.print("{s}error {s} 0;\n", .{ deref_suffix, op_str }); | | |
| 3093 | } | 3201 | } |
| | 3202 | if (payload_ty.hasRuntimeBits()) { |
| | 3203 | try writer.writeAll(".error"); |
| | 3204 | } |
| | 3205 | try writer.print(" {s} 0;\n", .{op_str}); |
| 3094 | return local; | 3206 | return local; |
| 3095 | } | 3207 | } |
| 3096 | | 3208 | |
| ... | @@ -3106,7 +3218,15 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3106,7 +3218,15 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3106 | const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen(); | 3218 | const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen(); |
| 3107 | | 3219 | |
| 3108 | try writer.writeAll(" = { .ptr = "); | 3220 | try writer.writeAll(" = { .ptr = "); |
| 3109 | 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 | } |
| 3110 | try writer.print(", .len = {d} }};\n", .{array_len}); | 3230 | try writer.print(", .len = {d} }};\n", .{array_len}); |
| 3111 | return local; | 3231 | return local; |
| 3112 | } | 3232 | } |
| ... | @@ -3138,7 +3258,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3138,7 +3258,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3138 | const operand = try f.resolveInst(un_op); | 3258 | const operand = try f.resolveInst(un_op); |
| 3139 | | 3259 | |
| 3140 | try writer.writeAll(" = ("); | 3260 | try writer.writeAll(" = ("); |
| 3141 | try f.renderType(writer, inst_ty); | 3261 | try f.renderTypecast(writer, inst_ty); |
| 3142 | try writer.writeAll(")"); | 3262 | try writer.writeAll(")"); |
| 3143 | try f.writeCValue(writer, operand); | 3263 | try f.writeCValue(writer, operand); |
| 3144 | try writer.writeAll(";\n"); | 3264 | try writer.writeAll(";\n"); |