| ... | ... | @@ -34,6 +34,8 @@ pub const CValue = union(enum) { |
| 34 | 34 | /// By-value |
| 35 | 35 | decl: *Decl, |
| 36 | 36 | decl_ref: *Decl, |
| 37 | /// An undefined (void *) pointer (cannot be dereferenced) |
| 38 | undefined_ptr: void, |
| 37 | 39 | /// Render the slice as an identifier (using fmtIdent) |
| 38 | 40 | identifier: []const u8, |
| 39 | 41 | /// Render these bytes literally. |
| ... | ... | @@ -311,6 +313,10 @@ pub const Function = struct { |
| 311 | 313 | fn renderType(f: *Function, w: anytype, t: Type) !void { |
| 312 | 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 | 322 | /// This data is available when outputting .c code for a `Module`. |
| ... | ... | @@ -365,10 +371,10 @@ pub const DeclGen = struct { |
| 365 | 371 | |
| 366 | 372 | if (ty.isSlice()) { |
| 367 | 373 | try writer.writeByte('('); |
| 368 | | try dg.renderType(writer, ty); |
| 374 | try dg.renderTypecast(writer, ty); |
| 369 | 375 | try writer.writeAll("){"); |
| 370 | 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 | 378 | try writer.writeAll(", "); |
| 373 | 379 | try writer.print("{d}", .{val.sliceLen()}); |
| 374 | 380 | try writer.writeAll("}"); |
| ... | ... | @@ -389,7 +395,7 @@ pub const DeclGen = struct { |
| 389 | 395 | } |
| 390 | 396 | |
| 391 | 397 | try writer.writeAll("(("); |
| 392 | | try dg.renderType(writer, ty); |
| 398 | try dg.renderTypecast(writer, ty); |
| 393 | 399 | try writer.writeAll(")&"); |
| 394 | 400 | try dg.renderDeclName(decl, writer); |
| 395 | 401 | try writer.writeByte(')'); |
| ... | ... | @@ -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 | 505 | fn renderValue( |
| 449 | 506 | dg: *DeclGen, |
| 450 | 507 | writer: anytype, |
| ... | ... | @@ -531,24 +588,15 @@ pub const DeclGen = struct { |
| 531 | 588 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 532 | 589 | |
| 533 | 590 | try writer.writeByte('('); |
| 534 | | try dg.renderType(writer, ty); |
| 591 | try dg.renderTypecast(writer, ty); |
| 535 | 592 | try writer.writeAll("){"); |
| 536 | 593 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr); |
| 537 | 594 | try writer.writeAll(", "); |
| 538 | 595 | try dg.renderValue(writer, Type.usize, slice.len); |
| 539 | 596 | try writer.writeAll("}"); |
| 540 | 597 | }, |
| 541 | | .elem_ptr => { |
| 542 | | const elem_ptr = val.castTag(.elem_ptr).?.data; |
| 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}); |
| 598 | .field_ptr, .elem_ptr, .opt_payload_ptr, .eu_payload_ptr => { |
| 599 | _ = try dg.renderChildPtr(writer, val); |
| 552 | 600 | }, |
| 553 | 601 | .function => { |
| 554 | 602 | const func = val.castTag(.function).?.data; |
| ... | ... | @@ -560,7 +608,7 @@ pub const DeclGen = struct { |
| 560 | 608 | }, |
| 561 | 609 | .int_u64, .one => { |
| 562 | 610 | try writer.writeAll("(("); |
| 563 | | try dg.renderType(writer, ty); |
| 611 | try dg.renderTypecast(writer, ty); |
| 564 | 612 | try writer.print(")0x{x}u)", .{val.toUnsignedInt()}); |
| 565 | 613 | }, |
| 566 | 614 | else => unreachable, |
| ... | ... | @@ -605,7 +653,7 @@ pub const DeclGen = struct { |
| 605 | 653 | return writer.print("{}", .{is_null}); |
| 606 | 654 | } |
| 607 | 655 | try writer.writeByte('('); |
| 608 | | try dg.renderType(writer, ty); |
| 656 | try dg.renderTypecast(writer, ty); |
| 609 | 657 | try writer.writeAll("){"); |
| 610 | 658 | if (val.castTag(.opt_payload)) |pl| { |
| 611 | 659 | const payload_val = pl.data; |
| ... | ... | @@ -641,7 +689,7 @@ pub const DeclGen = struct { |
| 641 | 689 | } |
| 642 | 690 | |
| 643 | 691 | try writer.writeByte('('); |
| 644 | | try dg.renderType(writer, ty); |
| 692 | try dg.renderTypecast(writer, ty); |
| 645 | 693 | try writer.writeAll("){"); |
| 646 | 694 | if (val.castTag(.eu_payload)) |pl| { |
| 647 | 695 | const payload_val = pl.data; |
| ... | ... | @@ -703,7 +751,7 @@ pub const DeclGen = struct { |
| 703 | 751 | const field_vals = val.castTag(.@"struct").?.data; |
| 704 | 752 | |
| 705 | 753 | try writer.writeAll("("); |
| 706 | | try dg.renderType(writer, ty); |
| 754 | try dg.renderTypecast(writer, ty); |
| 707 | 755 | try writer.writeAll("){"); |
| 708 | 756 | |
| 709 | 757 | for (field_vals) |field_val, i| { |
| ... | ... | @@ -723,7 +771,7 @@ pub const DeclGen = struct { |
| 723 | 771 | const layout = ty.unionGetLayout(target); |
| 724 | 772 | |
| 725 | 773 | try writer.writeAll("("); |
| 726 | | try dg.renderType(writer, ty); |
| 774 | try dg.renderTypecast(writer, ty); |
| 727 | 775 | try writer.writeAll("){"); |
| 728 | 776 | |
| 729 | 777 | if (ty.unionTagType()) |tag_ty| { |
| ... | ... | @@ -798,8 +846,9 @@ pub const DeclGen = struct { |
| 798 | 846 | if (params_written > 0) { |
| 799 | 847 | try w.writeAll(", "); |
| 800 | 848 | } |
| 801 | | try dg.renderType(w, dg.decl.ty.fnParamType(index)); |
| 802 | | try w.print(" a{d}", .{index}); |
| 849 | const name = CValue{ .arg = index }; |
| 850 | const alignment = Value.initTag(.abi_align_default); |
| 851 | try dg.renderTypeAndName(w, dg.decl.ty.fnParamType(index), name, .Mut, alignment); |
| 803 | 852 | params_written += 1; |
| 804 | 853 | } |
| 805 | 854 | |
| ... | ... | @@ -837,7 +886,7 @@ pub const DeclGen = struct { |
| 837 | 886 | if (params_written > 0) { |
| 838 | 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 | 890 | params_written += 1; |
| 842 | 891 | } |
| 843 | 892 | |
| ... | ... | @@ -868,17 +917,16 @@ pub const DeclGen = struct { |
| 868 | 917 | const bw = buffer.writer(); |
| 869 | 918 | |
| 870 | 919 | try bw.writeAll("typedef struct { "); |
| 871 | | const elem_type = t.elemType(); |
| 872 | | try dg.renderType(bw, elem_type); |
| 873 | | if (t.isConstPtr()) { |
| 874 | | try bw.writeAll(" const"); |
| 875 | | } |
| 876 | | if (t.isVolatilePtr()) { |
| 877 | | try bw.writeAll(" volatile"); |
| 878 | | } |
| 879 | | try bw.writeAll(" *"); |
| 880 | | try bw.writeAll("ptr; size_t len; } "); |
| 920 | |
| 921 | var ptr_type_buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 922 | const ptr_type = t.slicePtrFieldType(&ptr_type_buf); |
| 923 | const ptr_name = CValue{ .bytes = "ptr" }; |
| 924 | const ptr_alignment = Value.initTag(.abi_align_default); |
| 925 | try dg.renderTypeAndName(bw, ptr_type, ptr_name, .Mut, ptr_alignment); |
| 926 | |
| 927 | try bw.writeAll("; size_t len; } "); |
| 881 | 928 | const name_index = buffer.items.len; |
| 929 | const elem_type = t.elemType(); |
| 882 | 930 | if (t.isConstPtr()) { |
| 883 | 931 | try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)}); |
| 884 | 932 | } else { |
| ... | ... | @@ -1003,8 +1051,10 @@ pub const DeclGen = struct { |
| 1003 | 1051 | const bw = buffer.writer(); |
| 1004 | 1052 | |
| 1005 | 1053 | try bw.writeAll("typedef struct { "); |
| 1006 | | try dg.renderType(bw, child_type); |
| 1007 | | try bw.writeAll(" payload; uint16_t error; } "); |
| 1054 | const payload_name = CValue{ .bytes = "payload" }; |
| 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 | 1058 | const name_index = buffer.items.len; |
| 1009 | 1059 | if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| { |
| 1010 | 1060 | const func = inf_err_set_payload.data.func; |
| ... | ... | @@ -1030,14 +1080,47 @@ pub const DeclGen = struct { |
| 1030 | 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 | 1114 | fn renderOptionalTypedef(dg: *DeclGen, t: Type, child_type: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1034 | 1115 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1035 | 1116 | defer buffer.deinit(); |
| 1036 | 1117 | const bw = buffer.writer(); |
| 1037 | 1118 | |
| 1038 | 1119 | try bw.writeAll("typedef struct { "); |
| 1039 | | try dg.renderType(bw, child_type); |
| 1040 | | try bw.writeAll(" payload; bool is_null; } "); |
| 1120 | const payload_name = CValue{ .bytes = "payload" }; |
| 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 | 1124 | const name_index = buffer.items.len; |
| 1042 | 1125 | try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)}); |
| 1043 | 1126 | |
| ... | ... | @@ -1054,6 +1137,18 @@ pub const DeclGen = struct { |
| 1054 | 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 | 1152 | fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void { |
| 1058 | 1153 | const target = dg.module.getTarget(); |
| 1059 | 1154 | |
| ... | ... | @@ -1130,10 +1225,10 @@ pub const DeclGen = struct { |
| 1130 | 1225 | return w.writeAll(" *"); |
| 1131 | 1226 | }, |
| 1132 | 1227 | .Array => { |
| 1133 | | // We are referencing the array so it will decay to a C pointer. |
| 1134 | | // NB: arrays are not really types in C so they are either specified in the declaration |
| 1135 | | // or are already pointed to; our only job is to render the element type. |
| 1136 | | return dg.renderType(w, t.elemType()); |
| 1228 | const name = dg.getTypedefName(t) orelse |
| 1229 | try dg.renderArrayTypedef(t); |
| 1230 | |
| 1231 | return w.writeAll(name); |
| 1137 | 1232 | }, |
| 1138 | 1233 | .Optional => { |
| 1139 | 1234 | var opt_buf: Type.Payload.ElemType = undefined; |
| ... | ... | @@ -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 | 1339 | fn renderTypeAndName( |
| 1212 | 1340 | dg: *DeclGen, |
| 1213 | 1341 | w: anytype, |
| ... | ... | @@ -1219,6 +1347,8 @@ pub const DeclGen = struct { |
| 1219 | 1347 | var suffix = std.ArrayList(u8).init(dg.gpa); |
| 1220 | 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 | 1352 | var render_ty = ty; |
| 1223 | 1353 | while (render_ty.zigTypeTag() == .Array) { |
| 1224 | 1354 | const sentinel_bit = @boolToInt(render_ty.sentinel() != null); |
| ... | ... | @@ -1267,6 +1397,14 @@ pub const DeclGen = struct { |
| 1267 | 1397 | try w.writeByte('&'); |
| 1268 | 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 | 1408 | .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), |
| 1271 | 1409 | .bytes => |bytes| return w.writeAll(bytes), |
| 1272 | 1410 | } |
| ... | ... | @@ -1285,6 +1423,7 @@ pub const DeclGen = struct { |
| 1285 | 1423 | return w.writeByte(')'); |
| 1286 | 1424 | }, |
| 1287 | 1425 | .decl_ref => |decl| return dg.renderDeclName(decl, w), |
| 1426 | .undefined_ptr => unreachable, |
| 1288 | 1427 | .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}), |
| 1289 | 1428 | .bytes => |bytes| { |
| 1290 | 1429 | try w.writeAll("(*"); |
| ... | ... | @@ -1676,14 +1815,21 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1676 | 1815 | |
| 1677 | 1816 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 1678 | 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 | 1820 | const ptr = try f.resolveInst(bin_op.lhs); |
| 1681 | 1821 | const index = try f.resolveInst(bin_op.rhs); |
| 1682 | 1822 | const writer = f.object.writer(); |
| 1683 | 1823 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 1684 | | try writer.writeAll(" = &"); |
| 1685 | | try f.writeCValue(writer, ptr); |
| 1686 | | try writer.writeByte('['); |
| 1824 | |
| 1825 | try writer.writeAll(" = &("); |
| 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 | 1833 | try f.writeCValue(writer, index); |
| 1688 | 1834 | try writer.writeAll("];\n"); |
| 1689 | 1835 | return local; |
| ... | ... | @@ -1747,13 +1893,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1747 | 1893 | const elem_type = inst_ty.elemType(); |
| 1748 | 1894 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; |
| 1749 | 1895 | if (!elem_type.isFnOrHasRuntimeBits()) { |
| 1750 | | const target = f.object.dg.module.getTarget(); |
| 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 }; |
| 1896 | return CValue.undefined_ptr; |
| 1757 | 1897 | } |
| 1758 | 1898 | |
| 1759 | 1899 | const target = f.object.dg.module.getTarget(); |
| ... | ... | @@ -1768,10 +1908,6 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1768 | 1908 | const local = try f.allocAlignedLocal(elem_type, mutability, alignment_value); |
| 1769 | 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 | 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 | 1944 | // We need to separately initialize arrays with a memcpy so they must be mutable. |
| 1809 | 1945 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 1810 | 1946 | |
| 1811 | | switch (operand) { |
| 1812 | | .local_ref => |i| { |
| 1813 | | const wrapped: CValue = .{ .local = i }; |
| 1814 | | try writer.writeAll(" = "); |
| 1815 | | try f.writeCValue(writer, wrapped); |
| 1816 | | try writer.writeAll(";\n"); |
| 1817 | | }, |
| 1818 | | .decl_ref => |decl| { |
| 1819 | | const wrapped: CValue = .{ .decl = decl }; |
| 1820 | | try writer.writeAll(" = "); |
| 1821 | | try f.writeCValue(writer, wrapped); |
| 1822 | | try writer.writeAll(";\n"); |
| 1823 | | }, |
| 1824 | | else => { |
| 1825 | | if (is_array) { |
| 1826 | | // Insert a memcpy to initialize this array. The source operand is always a pointer |
| 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 | | }, |
| 1947 | if (is_array) { |
| 1948 | // Insert a memcpy to initialize this array. The source operand is always a pointer |
| 1949 | // and thus we only need to know size/type information from the local type/dest. |
| 1950 | try writer.writeAll(";"); |
| 1951 | try f.object.indent_writer.insertNewline(); |
| 1952 | try writer.writeAll("memcpy("); |
| 1953 | try f.writeCValue(writer, local); |
| 1954 | try writer.writeAll(", "); |
| 1955 | try f.writeCValue(writer, operand); |
| 1956 | try writer.writeAll(", sizeof("); |
| 1957 | try f.writeCValue(writer, local); |
| 1958 | try writer.writeAll("));\n"); |
| 1959 | } else { |
| 1960 | try writer.writeAll(" = "); |
| 1961 | try f.writeCValueDeref(writer, operand); |
| 1962 | try writer.writeAll(";\n"); |
| 1843 | 1963 | } |
| 1844 | 1964 | return local; |
| 1845 | 1965 | } |
| ... | ... | @@ -1884,7 +2004,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1884 | 2004 | const inst_ty = f.air.typeOfIndex(inst); |
| 1885 | 2005 | const local = try f.allocLocal(inst_ty, .Const); |
| 1886 | 2006 | try writer.writeAll(" = ("); |
| 1887 | | try f.renderType(writer, inst_ty); |
| 2007 | try f.renderTypecast(writer, inst_ty); |
| 1888 | 2008 | try writer.writeAll(")"); |
| 1889 | 2009 | try f.writeCValue(writer, operand); |
| 1890 | 2010 | try writer.writeAll(";\n"); |
| ... | ... | @@ -1945,7 +2065,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1945 | 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 | 2069 | const is_debug_build = f.object.dg.module.optimizeMode() == .Debug; |
| 1950 | 2070 | if (!is_debug_build) |
| 1951 | 2071 | return CValue.none; |
| ... | ... | @@ -1954,11 +2074,7 @@ fn airStoreUndefined(f: *Function, dest_ptr: CValue, dest_child_type: Type) !CVa |
| 1954 | 2074 | try writer.writeAll("memset("); |
| 1955 | 2075 | try f.writeCValue(writer, dest_ptr); |
| 1956 | 2076 | try writer.writeAll(", 0xaa, sizeof("); |
| 1957 | | if (dest_child_type.zigTypeTag() == .Array) { |
| 1958 | | try f.writeCValue(writer, dest_ptr); |
| 1959 | | } else { |
| 1960 | | try f.writeCValueDeref(writer, dest_ptr); |
| 1961 | | } |
| 2077 | try f.writeCValueDeref(writer, dest_ptr); |
| 1962 | 2078 | try writer.writeAll("));\n"); |
| 1963 | 2079 | return CValue.none; |
| 1964 | 2080 | } |
| ... | ... | @@ -1975,58 +2091,40 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1975 | 2091 | const src_val_is_undefined = |
| 1976 | 2092 | if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; |
| 1977 | 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 | 2096 | const writer = f.object.writer(); |
| 1981 | | switch (dest_ptr) { |
| 1982 | | .local_ref => |i| { |
| 1983 | | const dest: CValue = .{ .local = i }; |
| 1984 | | try f.writeCValue(writer, dest); |
| 1985 | | try writer.writeAll(" = "); |
| 1986 | | try f.writeCValue(writer, src_val); |
| 1987 | | try writer.writeAll(";\n"); |
| 1988 | | }, |
| 1989 | | .decl_ref => |decl| { |
| 1990 | | const dest: CValue = .{ .decl = decl }; |
| 1991 | | try f.writeCValue(writer, dest); |
| 2097 | if (lhs_child_type.zigTypeTag() == .Array) { |
| 2098 | // For this memcpy to safely work we need the rhs to have the same |
| 2099 | // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). |
| 2100 | const rhs_type = f.air.typeOf(bin_op.rhs); |
| 2101 | assert(rhs_type.eql(lhs_child_type)); |
| 2102 | |
| 2103 | // If the source is a constant, writeCValue will emit a brace initialization |
| 2104 | // so work around this by initializing into new local. |
| 2105 | // TODO this should be done by manually initializing elements of the dest array |
| 2106 | const array_src = if (src_val == .constant) blk: { |
| 2107 | const new_local = try f.allocLocal(rhs_type, .Const); |
| 1992 | 2108 | try writer.writeAll(" = "); |
| 1993 | 2109 | try f.writeCValue(writer, src_val); |
| 1994 | | try writer.writeAll(";\n"); |
| 1995 | | }, |
| 1996 | | else => { |
| 1997 | | if (lhs_child_type.zigTypeTag() == .Array) { |
| 1998 | | // For this memcpy to safely work we need the rhs to have the same |
| 1999 | | // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). |
| 2000 | | const rhs_type = f.air.typeOf(bin_op.rhs); |
| 2001 | | assert(rhs_type.eql(lhs_child_type)); |
| 2002 | | |
| 2003 | | // If the source is a constant, writeCValue will emit a brace initialization |
| 2004 | | // so work around this by initializing into new local. |
| 2005 | | // TODO this should be done by manually initializing elements of the dest array |
| 2006 | | const array_src = if (src_val == .constant) blk: { |
| 2007 | | const new_local = try f.allocLocal(rhs_type, .Const); |
| 2008 | | try writer.writeAll(" = "); |
| 2009 | | try f.writeCValue(writer, src_val); |
| 2010 | | try writer.writeAll(";"); |
| 2011 | | try f.object.indent_writer.insertNewline(); |
| 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 | | }, |
| 2110 | try writer.writeAll(";"); |
| 2111 | try f.object.indent_writer.insertNewline(); |
| 2112 | |
| 2113 | break :blk new_local; |
| 2114 | } else src_val; |
| 2115 | |
| 2116 | try writer.writeAll("memcpy("); |
| 2117 | try f.writeCValue(writer, dest_ptr); |
| 2118 | try writer.writeAll(", "); |
| 2119 | try f.writeCValue(writer, array_src); |
| 2120 | try writer.writeAll(", sizeof("); |
| 2121 | try f.writeCValue(writer, array_src); |
| 2122 | try writer.writeAll("));\n"); |
| 2123 | } else { |
| 2124 | try f.writeCValueDeref(writer, dest_ptr); |
| 2125 | try writer.writeAll(" = "); |
| 2126 | try f.writeCValue(writer, src_val); |
| 2127 | try writer.writeAll(";\n"); |
| 2030 | 2128 | } |
| 2031 | 2129 | return CValue.none; |
| 2032 | 2130 | } |
| ... | ... | @@ -2382,17 +2480,24 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CV |
| 2382 | 2480 | const writer = f.object.writer(); |
| 2383 | 2481 | const inst_ty = f.air.typeOfIndex(inst); |
| 2384 | 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 | 2491 | // We must convert to and from integer types to prevent UB if the operation results in a NULL pointer, |
| 2387 | 2492 | // or if LHS is NULL. The operation is only UB if the result is NULL and then dereferenced. |
| 2388 | 2493 | try writer.writeAll(" = ("); |
| 2389 | | try f.renderType(writer, inst_ty); |
| 2494 | try f.renderTypecast(writer, inst_ty); |
| 2390 | 2495 | try writer.writeAll(")(((uintptr_t)"); |
| 2391 | 2496 | try f.writeCValue(writer, lhs); |
| 2392 | 2497 | try writer.print("){s}(", .{operator}); |
| 2393 | 2498 | try f.writeCValue(writer, rhs); |
| 2394 | 2499 | try writer.writeAll("*sizeof("); |
| 2395 | | try f.renderType(writer, inst_ty.childType()); |
| 2500 | try f.renderTypecast(writer, elem_ty); |
| 2396 | 2501 | try writer.print(")));\n", .{}); |
| 2397 | 2502 | |
| 2398 | 2503 | return local; |
| ... | ... | @@ -2580,7 +2685,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2580 | 2685 | { |
| 2581 | 2686 | const local = try f.allocLocal(inst_ty, .Const); |
| 2582 | 2687 | try writer.writeAll(" = ("); |
| 2583 | | try f.renderType(writer, inst_ty); |
| 2688 | try f.renderTypecast(writer, inst_ty); |
| 2584 | 2689 | |
| 2585 | 2690 | try writer.writeAll(")"); |
| 2586 | 2691 | try f.writeCValue(writer, operand); |
| ... | ... | @@ -2922,13 +3027,12 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 2922 | 3027 | }, |
| 2923 | 3028 | else => unreachable, |
| 2924 | 3029 | } |
| 2925 | | const addrof = if (field_val_ty.zigTypeTag() == .Array) "" else "&"; |
| 2926 | 3030 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; |
| 2927 | 3031 | |
| 2928 | 3032 | const inst_ty = f.air.typeOfIndex(inst); |
| 2929 | 3033 | const local = try f.allocLocal(inst_ty, .Const); |
| 2930 | 3034 | |
| 2931 | | try writer.print(" = {s}", .{addrof}); |
| 3035 | try writer.print(" = &", .{}); |
| 2932 | 3036 | try f.writeCValueDeref(writer, struct_ptr); |
| 2933 | 3037 | try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); |
| 2934 | 3038 | return local; |
| ... | ... | @@ -3114,7 +3218,15 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3114 | 3218 | const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen(); |
| 3115 | 3219 | |
| 3116 | 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 | 3230 | try writer.print(", .len = {d} }};\n", .{array_len}); |
| 3119 | 3231 | return local; |
| 3120 | 3232 | } |
| ... | ... | @@ -3146,7 +3258,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3146 | 3258 | const operand = try f.resolveInst(un_op); |
| 3147 | 3259 | |
| 3148 | 3260 | try writer.writeAll(" = ("); |
| 3149 | | try f.renderType(writer, inst_ty); |
| 3261 | try f.renderTypecast(writer, inst_ty); |
| 3150 | 3262 | try writer.writeAll(")"); |
| 3151 | 3263 | try f.writeCValue(writer, operand); |
| 3152 | 3264 | try writer.writeAll(";\n"); |