| ... | ... | @@ -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. |
| ... | ... | @@ -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 | 309 | fn fail(f: *Function, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { |
| 295 | 310 | return f.object.dg.fail(format, args); |
| 296 | 311 | } |
| ... | ... | @@ -298,6 +313,10 @@ pub const Function = struct { |
| 298 | 313 | fn renderType(f: *Function, w: anytype, t: Type) !void { |
| 299 | 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 | 322 | /// This data is available when outputting .c code for a `Module`. |
| ... | ... | @@ -352,10 +371,10 @@ pub const DeclGen = struct { |
| 352 | 371 | |
| 353 | 372 | if (ty.isSlice()) { |
| 354 | 373 | try writer.writeByte('('); |
| 355 | | try dg.renderType(writer, ty); |
| 374 | try dg.renderTypecast(writer, ty); |
| 356 | 375 | try writer.writeAll("){"); |
| 357 | 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 | 378 | try writer.writeAll(", "); |
| 360 | 379 | try writer.print("{d}", .{val.sliceLen()}); |
| 361 | 380 | try writer.writeAll("}"); |
| ... | ... | @@ -376,7 +395,7 @@ pub const DeclGen = struct { |
| 376 | 395 | } |
| 377 | 396 | |
| 378 | 397 | try writer.writeAll("(("); |
| 379 | | try dg.renderType(writer, ty); |
| 398 | try dg.renderTypecast(writer, ty); |
| 380 | 399 | try writer.writeAll(")&"); |
| 381 | 400 | try dg.renderDeclName(decl, writer); |
| 382 | 401 | try writer.writeByte(')'); |
| ... | ... | @@ -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 | 505 | fn renderValue( |
| 436 | 506 | dg: *DeclGen, |
| 437 | 507 | writer: anytype, |
| ... | ... | @@ -518,24 +588,15 @@ pub const DeclGen = struct { |
| 518 | 588 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 519 | 589 | |
| 520 | 590 | try writer.writeByte('('); |
| 521 | | try dg.renderType(writer, ty); |
| 591 | try dg.renderTypecast(writer, ty); |
| 522 | 592 | try writer.writeAll("){"); |
| 523 | 593 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr); |
| 524 | 594 | try writer.writeAll(", "); |
| 525 | 595 | try dg.renderValue(writer, Type.usize, slice.len); |
| 526 | 596 | try writer.writeAll("}"); |
| 527 | 597 | }, |
| 528 | | .elem_ptr => { |
| 529 | | const elem_ptr = val.castTag(.elem_ptr).?.data; |
| 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}); |
| 598 | .field_ptr, .elem_ptr, .opt_payload_ptr, .eu_payload_ptr => { |
| 599 | _ = try dg.renderChildPtr(writer, val); |
| 539 | 600 | }, |
| 540 | 601 | .function => { |
| 541 | 602 | const func = val.castTag(.function).?.data; |
| ... | ... | @@ -547,7 +608,7 @@ pub const DeclGen = struct { |
| 547 | 608 | }, |
| 548 | 609 | .int_u64, .one => { |
| 549 | 610 | try writer.writeAll("(("); |
| 550 | | try dg.renderType(writer, ty); |
| 611 | try dg.renderTypecast(writer, ty); |
| 551 | 612 | try writer.print(")0x{x}u)", .{val.toUnsignedInt()}); |
| 552 | 613 | }, |
| 553 | 614 | else => unreachable, |
| ... | ... | @@ -592,7 +653,7 @@ pub const DeclGen = struct { |
| 592 | 653 | return writer.print("{}", .{is_null}); |
| 593 | 654 | } |
| 594 | 655 | try writer.writeByte('('); |
| 595 | | try dg.renderType(writer, ty); |
| 656 | try dg.renderTypecast(writer, ty); |
| 596 | 657 | try writer.writeAll("){"); |
| 597 | 658 | if (val.castTag(.opt_payload)) |pl| { |
| 598 | 659 | const payload_val = pl.data; |
| ... | ... | @@ -628,7 +689,7 @@ pub const DeclGen = struct { |
| 628 | 689 | } |
| 629 | 690 | |
| 630 | 691 | try writer.writeByte('('); |
| 631 | | try dg.renderType(writer, ty); |
| 692 | try dg.renderTypecast(writer, ty); |
| 632 | 693 | try writer.writeAll("){"); |
| 633 | 694 | if (val.castTag(.eu_payload)) |pl| { |
| 634 | 695 | const payload_val = pl.data; |
| ... | ... | @@ -690,7 +751,7 @@ pub const DeclGen = struct { |
| 690 | 751 | const field_vals = val.castTag(.@"struct").?.data; |
| 691 | 752 | |
| 692 | 753 | try writer.writeAll("("); |
| 693 | | try dg.renderType(writer, ty); |
| 754 | try dg.renderTypecast(writer, ty); |
| 694 | 755 | try writer.writeAll("){"); |
| 695 | 756 | |
| 696 | 757 | for (field_vals) |field_val, i| { |
| ... | ... | @@ -710,7 +771,7 @@ pub const DeclGen = struct { |
| 710 | 771 | const layout = ty.unionGetLayout(target); |
| 711 | 772 | |
| 712 | 773 | try writer.writeAll("("); |
| 713 | | try dg.renderType(writer, ty); |
| 774 | try dg.renderTypecast(writer, ty); |
| 714 | 775 | try writer.writeAll("){"); |
| 715 | 776 | |
| 716 | 777 | if (ty.unionTagType()) |tag_ty| { |
| ... | ... | @@ -785,8 +846,9 @@ pub const DeclGen = struct { |
| 785 | 846 | if (params_written > 0) { |
| 786 | 847 | try w.writeAll(", "); |
| 787 | 848 | } |
| 788 | | try dg.renderType(w, dg.decl.ty.fnParamType(index)); |
| 789 | | 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); |
| 790 | 852 | params_written += 1; |
| 791 | 853 | } |
| 792 | 854 | |
| ... | ... | @@ -824,7 +886,7 @@ pub const DeclGen = struct { |
| 824 | 886 | if (params_written > 0) { |
| 825 | 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 | 890 | params_written += 1; |
| 829 | 891 | } |
| 830 | 892 | |
| ... | ... | @@ -855,17 +917,16 @@ pub const DeclGen = struct { |
| 855 | 917 | const bw = buffer.writer(); |
| 856 | 918 | |
| 857 | 919 | try bw.writeAll("typedef struct { "); |
| 858 | | const elem_type = t.elemType(); |
| 859 | | try dg.renderType(bw, elem_type); |
| 860 | | if (t.isConstPtr()) { |
| 861 | | try bw.writeAll(" const"); |
| 862 | | } |
| 863 | | if (t.isVolatilePtr()) { |
| 864 | | try bw.writeAll(" volatile"); |
| 865 | | } |
| 866 | | try bw.writeAll(" *"); |
| 867 | | 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; } "); |
| 868 | 928 | const name_index = buffer.items.len; |
| 929 | const elem_type = t.elemType(); |
| 869 | 930 | if (t.isConstPtr()) { |
| 870 | 931 | try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)}); |
| 871 | 932 | } else { |
| ... | ... | @@ -990,8 +1051,10 @@ pub const DeclGen = struct { |
| 990 | 1051 | const bw = buffer.writer(); |
| 991 | 1052 | |
| 992 | 1053 | try bw.writeAll("typedef struct { "); |
| 993 | | try dg.renderType(bw, child_type); |
| 994 | | 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; } "); |
| 995 | 1058 | const name_index = buffer.items.len; |
| 996 | 1059 | if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| { |
| 997 | 1060 | const func = inf_err_set_payload.data.func; |
| ... | ... | @@ -1017,14 +1080,47 @@ pub const DeclGen = struct { |
| 1017 | 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 | 1114 | fn renderOptionalTypedef(dg: *DeclGen, t: Type, child_type: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1021 | 1115 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1022 | 1116 | defer buffer.deinit(); |
| 1023 | 1117 | const bw = buffer.writer(); |
| 1024 | 1118 | |
| 1025 | 1119 | try bw.writeAll("typedef struct { "); |
| 1026 | | try dg.renderType(bw, child_type); |
| 1027 | | 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; } "); |
| 1028 | 1124 | const name_index = buffer.items.len; |
| 1029 | 1125 | try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)}); |
| 1030 | 1126 | |
| ... | ... | @@ -1041,6 +1137,18 @@ pub const DeclGen = struct { |
| 1041 | 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 | 1152 | fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void { |
| 1045 | 1153 | const target = dg.module.getTarget(); |
| 1046 | 1154 | |
| ... | ... | @@ -1117,10 +1225,10 @@ pub const DeclGen = struct { |
| 1117 | 1225 | return w.writeAll(" *"); |
| 1118 | 1226 | }, |
| 1119 | 1227 | .Array => { |
| 1120 | | // We are referencing the array so it will decay to a C pointer. |
| 1121 | | // NB: arrays are not really types in C so they are either specified in the declaration |
| 1122 | | // or are already pointed to; our only job is to render the element type. |
| 1123 | | return dg.renderType(w, t.elemType()); |
| 1228 | const name = dg.getTypedefName(t) orelse |
| 1229 | try dg.renderArrayTypedef(t); |
| 1230 | |
| 1231 | return w.writeAll(name); |
| 1124 | 1232 | }, |
| 1125 | 1233 | .Optional => { |
| 1126 | 1234 | var opt_buf: Type.Payload.ElemType = undefined; |
| ... | ... | @@ -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 | 1339 | fn renderTypeAndName( |
| 1199 | 1340 | dg: *DeclGen, |
| 1200 | 1341 | w: anytype, |
| ... | ... | @@ -1206,6 +1347,8 @@ pub const DeclGen = struct { |
| 1206 | 1347 | var suffix = std.ArrayList(u8).init(dg.gpa); |
| 1207 | 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 | 1352 | var render_ty = ty; |
| 1210 | 1353 | while (render_ty.zigTypeTag() == .Array) { |
| 1211 | 1354 | const sentinel_bit = @boolToInt(render_ty.sentinel() != null); |
| ... | ... | @@ -1254,11 +1397,42 @@ pub const DeclGen = struct { |
| 1254 | 1397 | try w.writeByte('&'); |
| 1255 | 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 | 1408 | .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), |
| 1258 | 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 | 1436 | fn renderDeclName(dg: DeclGen, decl: *Decl, writer: anytype) !void { |
| 1263 | 1437 | if (dg.module.decl_exports.get(decl)) |exports| { |
| 1264 | 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 | 1667 | .optional_payload_ptr => try airOptionalPayload(f, inst), |
| 1494 | 1668 | .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst), |
| 1495 | 1669 | |
| 1496 | | .is_err => try airIsErr(f, inst, "", ".", "!="), |
| 1497 | | .is_non_err => try airIsErr(f, inst, "", ".", "=="), |
| 1498 | | .is_err_ptr => try airIsErr(f, inst, "*", "->", "!="), |
| 1499 | | .is_non_err_ptr => try airIsErr(f, inst, "*", "->", "=="), |
| 1670 | .is_err => try airIsErr(f, inst, false, "!="), |
| 1671 | .is_non_err => try airIsErr(f, inst, false, "=="), |
| 1672 | .is_err_ptr => try airIsErr(f, inst, true, "!="), |
| 1673 | .is_non_err_ptr => try airIsErr(f, inst, true, "=="), |
| 1500 | 1674 | |
| 1501 | 1675 | .is_null => try airIsNull(f, inst, "==", ""), |
| 1502 | 1676 | .is_non_null => try airIsNull(f, inst, "!=", ""), |
| ... | ... | @@ -1641,14 +1815,21 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1641 | 1815 | |
| 1642 | 1816 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 1643 | 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 | 1820 | const ptr = try f.resolveInst(bin_op.lhs); |
| 1646 | 1821 | const index = try f.resolveInst(bin_op.rhs); |
| 1647 | 1822 | const writer = f.object.writer(); |
| 1648 | 1823 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 1649 | | try writer.writeAll(" = &"); |
| 1650 | | try f.writeCValue(writer, ptr); |
| 1651 | | 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(")["); |
| 1652 | 1833 | try f.writeCValue(writer, index); |
| 1653 | 1834 | try writer.writeAll("];\n"); |
| 1654 | 1835 | return local; |
| ... | ... | @@ -1712,13 +1893,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1712 | 1893 | const elem_type = inst_ty.elemType(); |
| 1713 | 1894 | const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; |
| 1714 | 1895 | if (!elem_type.isFnOrHasRuntimeBits()) { |
| 1715 | | const target = f.object.dg.module.getTarget(); |
| 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 }; |
| 1896 | return CValue.undefined_ptr; |
| 1722 | 1897 | } |
| 1723 | 1898 | |
| 1724 | 1899 | const target = f.object.dg.module.getTarget(); |
| ... | ... | @@ -1733,10 +1908,6 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1733 | 1908 | const local = try f.allocAlignedLocal(elem_type, mutability, alignment_value); |
| 1734 | 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 | 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 | 1944 | // We need to separately initialize arrays with a memcpy so they must be mutable. |
| 1774 | 1945 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 1775 | 1946 | |
| 1776 | | switch (operand) { |
| 1777 | | .local_ref => |i| { |
| 1778 | | const wrapped: CValue = .{ .local = i }; |
| 1779 | | try writer.writeAll(" = "); |
| 1780 | | try f.writeCValue(writer, wrapped); |
| 1781 | | try writer.writeAll(";\n"); |
| 1782 | | }, |
| 1783 | | .decl_ref => |decl| { |
| 1784 | | const wrapped: CValue = .{ .decl = decl }; |
| 1785 | | try writer.writeAll(" = "); |
| 1786 | | try f.writeCValue(writer, wrapped); |
| 1787 | | try writer.writeAll(";\n"); |
| 1788 | | }, |
| 1789 | | else => { |
| 1790 | | if (is_array) { |
| 1791 | | // Insert a memcpy to initialize this array. The source operand is always a pointer |
| 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 | | }, |
| 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"); |
| 1808 | 1963 | } |
| 1809 | 1964 | return local; |
| 1810 | 1965 | } |
| ... | ... | @@ -1849,7 +2004,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1849 | 2004 | const inst_ty = f.air.typeOfIndex(inst); |
| 1850 | 2005 | const local = try f.allocLocal(inst_ty, .Const); |
| 1851 | 2006 | try writer.writeAll(" = ("); |
| 1852 | | try f.renderType(writer, inst_ty); |
| 2007 | try f.renderTypecast(writer, inst_ty); |
| 1853 | 2008 | try writer.writeAll(")"); |
| 1854 | 2009 | try f.writeCValue(writer, operand); |
| 1855 | 2010 | try writer.writeAll(";\n"); |
| ... | ... | @@ -1910,39 +2065,17 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1910 | 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 | 2069 | const is_debug_build = f.object.dg.module.optimizeMode() == .Debug; |
| 1915 | 2070 | if (!is_debug_build) |
| 1916 | 2071 | return CValue.none; |
| 1917 | 2072 | |
| 1918 | 2073 | const writer = f.object.writer(); |
| 1919 | | switch (dest_ptr) { |
| 1920 | | .local_ref => |i| { |
| 1921 | | const dest: CValue = .{ .local = i }; |
| 1922 | | try writer.writeAll("memset(&"); |
| 1923 | | try f.writeCValue(writer, dest); |
| 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 | | } |
| 2074 | try writer.writeAll("memset("); |
| 2075 | try f.writeCValue(writer, dest_ptr); |
| 2076 | try writer.writeAll(", 0xaa, sizeof("); |
| 2077 | try f.writeCValueDeref(writer, dest_ptr); |
| 2078 | try writer.writeAll("));\n"); |
| 1946 | 2079 | return CValue.none; |
| 1947 | 2080 | } |
| 1948 | 2081 | |
| ... | ... | @@ -1958,59 +2091,40 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1958 | 2091 | const src_val_is_undefined = |
| 1959 | 2092 | if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; |
| 1960 | 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 | 2096 | const writer = f.object.writer(); |
| 1964 | | switch (dest_ptr) { |
| 1965 | | .local_ref => |i| { |
| 1966 | | const dest: CValue = .{ .local = i }; |
| 1967 | | try f.writeCValue(writer, dest); |
| 1968 | | try writer.writeAll(" = "); |
| 1969 | | try f.writeCValue(writer, src_val); |
| 1970 | | try writer.writeAll(";\n"); |
| 1971 | | }, |
| 1972 | | .decl_ref => |decl| { |
| 1973 | | const dest: CValue = .{ .decl = decl }; |
| 1974 | | 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); |
| 1975 | 2108 | try writer.writeAll(" = "); |
| 1976 | 2109 | try f.writeCValue(writer, src_val); |
| 1977 | | try writer.writeAll(";\n"); |
| 1978 | | }, |
| 1979 | | else => { |
| 1980 | | if (lhs_child_type.zigTypeTag() == .Array) { |
| 1981 | | // For this memcpy to safely work we need the rhs to have the same |
| 1982 | | // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). |
| 1983 | | const rhs_type = f.air.typeOf(bin_op.rhs); |
| 1984 | | assert(rhs_type.eql(lhs_child_type)); |
| 1985 | | |
| 1986 | | // If the source is a constant, writeCValue will emit a brace initialization |
| 1987 | | // so work around this by initializing into new local. |
| 1988 | | // TODO this should be done by manually initializing elements of the dest array |
| 1989 | | const array_src = if (src_val == .constant) blk: { |
| 1990 | | const new_local = try f.allocLocal(rhs_type, .Const); |
| 1991 | | try writer.writeAll(" = "); |
| 1992 | | try f.writeCValue(writer, src_val); |
| 1993 | | try writer.writeAll(";"); |
| 1994 | | try f.object.indent_writer.insertNewline(); |
| 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 | | }, |
| 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"); |
| 2014 | 2128 | } |
| 2015 | 2129 | return CValue.none; |
| 2016 | 2130 | } |
| ... | ... | @@ -2366,17 +2480,24 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CV |
| 2366 | 2480 | const writer = f.object.writer(); |
| 2367 | 2481 | const inst_ty = f.air.typeOfIndex(inst); |
| 2368 | 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 | 2491 | // We must convert to and from integer types to prevent UB if the operation results in a NULL pointer, |
| 2371 | 2492 | // or if LHS is NULL. The operation is only UB if the result is NULL and then dereferenced. |
| 2372 | 2493 | try writer.writeAll(" = ("); |
| 2373 | | try f.renderType(writer, inst_ty); |
| 2494 | try f.renderTypecast(writer, inst_ty); |
| 2374 | 2495 | try writer.writeAll(")(((uintptr_t)"); |
| 2375 | 2496 | try f.writeCValue(writer, lhs); |
| 2376 | 2497 | try writer.print("){s}(", .{operator}); |
| 2377 | 2498 | try f.writeCValue(writer, rhs); |
| 2378 | 2499 | try writer.writeAll("*sizeof("); |
| 2379 | | try f.renderType(writer, inst_ty.childType()); |
| 2500 | try f.renderTypecast(writer, elem_ty); |
| 2380 | 2501 | try writer.print(")));\n", .{}); |
| 2381 | 2502 | |
| 2382 | 2503 | return local; |
| ... | ... | @@ -2564,7 +2685,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2564 | 2685 | { |
| 2565 | 2686 | const local = try f.allocLocal(inst_ty, .Const); |
| 2566 | 2687 | try writer.writeAll(" = ("); |
| 2567 | | try f.renderType(writer, inst_ty); |
| 2688 | try f.renderTypecast(writer, inst_ty); |
| 2568 | 2689 | |
| 2569 | 2690 | try writer.writeAll(")"); |
| 2570 | 2691 | try f.writeCValue(writer, operand); |
| ... | ... | @@ -2852,16 +2973,15 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2852 | 2973 | return operand; |
| 2853 | 2974 | } |
| 2854 | 2975 | |
| 2855 | | try writer.writeAll("("); |
| 2856 | | try f.writeCValue(writer, operand); |
| 2857 | | try writer.writeAll(")->is_null = false;\n"); |
| 2976 | try f.writeCValueDeref(writer, operand); |
| 2977 | try writer.writeAll(".is_null = false;\n"); |
| 2858 | 2978 | |
| 2859 | 2979 | const inst_ty = f.air.typeOfIndex(inst); |
| 2860 | 2980 | const local = try f.allocLocal(inst_ty, .Const); |
| 2861 | | try writer.writeAll(" = &("); |
| 2862 | | try f.writeCValue(writer, operand); |
| 2981 | try writer.writeAll(" = &"); |
| 2982 | try f.writeCValueDeref(writer, operand); |
| 2863 | 2983 | |
| 2864 | | try writer.writeAll(")->payload;\n"); |
| 2984 | try writer.writeAll(".payload;\n"); |
| 2865 | 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 | 3027 | }, |
| 2908 | 3028 | else => unreachable, |
| 2909 | 3029 | } |
| 2910 | | const addrof = if (field_val_ty.zigTypeTag() == .Array) "" else "&"; |
| 2911 | 3030 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; |
| 2912 | 3031 | |
| 2913 | 3032 | const inst_ty = f.air.typeOfIndex(inst); |
| 2914 | 3033 | const local = try f.allocLocal(inst_ty, .Const); |
| 2915 | | switch (struct_ptr) { |
| 2916 | | .local_ref => |i| { |
| 2917 | | try writer.print(" = {s}t{d}.{s}{ };\n", .{ |
| 2918 | | addrof, i, 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 | | } |
| 3034 | |
| 3035 | try writer.print(" = &", .{}); |
| 3036 | try f.writeCValueDeref(writer, struct_ptr); |
| 3037 | try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); |
| 2927 | 3038 | return local; |
| 2928 | 3039 | } |
| 2929 | 3040 | |
| ... | ... | @@ -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 | 3089 | const local = try f.allocLocal(inst_ty, .Const); |
| 2981 | | try writer.writeAll(" = ("); |
| 2982 | | try f.writeCValue(writer, operand); |
| 2983 | | |
| 2984 | | try writer.print("){s}error;\n", .{maybe_deref}); |
| 3090 | try writer.writeAll(" = "); |
| 3091 | if (operand_ty.zigTypeTag() == .Pointer) { |
| 3092 | try f.writeCValueDeref(writer, operand); |
| 3093 | } else { |
| 3094 | try f.writeCValue(writer, operand); |
| 3095 | } |
| 3096 | try writer.writeAll(".error;\n"); |
| 2985 | 3097 | return local; |
| 2986 | 3098 | } |
| 2987 | 3099 | |
| ... | ... | @@ -3069,8 +3181,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3069 | 3181 | fn airIsErr( |
| 3070 | 3182 | f: *Function, |
| 3071 | 3183 | inst: Air.Inst.Index, |
| 3072 | | deref_prefix: [*:0]const u8, |
| 3073 | | deref_suffix: [*:0]const u8, |
| 3184 | is_ptr: bool, |
| 3074 | 3185 | op_str: [*:0]const u8, |
| 3075 | 3186 | ) !CValue { |
| 3076 | 3187 | if (f.liveness.isUnused(inst)) |
| ... | ... | @@ -3082,15 +3193,16 @@ fn airIsErr( |
| 3082 | 3193 | const operand_ty = f.air.typeOf(un_op); |
| 3083 | 3194 | const local = try f.allocLocal(Type.initTag(.bool), .Const); |
| 3084 | 3195 | const payload_ty = operand_ty.errorUnionPayload(); |
| 3085 | | if (!payload_ty.hasRuntimeBits()) { |
| 3086 | | try writer.print(" = {s}", .{deref_prefix}); |
| 3087 | | try f.writeCValue(writer, operand); |
| 3088 | | try writer.print(" {s} 0;\n", .{op_str}); |
| 3196 | try writer.writeAll(" = "); |
| 3197 | if (is_ptr) { |
| 3198 | try f.writeCValueDeref(writer, operand); |
| 3089 | 3199 | } else { |
| 3090 | | try writer.writeAll(" = "); |
| 3091 | 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 | 3206 | return local; |
| 3095 | 3207 | } |
| 3096 | 3208 | |
| ... | ... | @@ -3106,7 +3218,15 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3106 | 3218 | const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen(); |
| 3107 | 3219 | |
| 3108 | 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 | 3230 | try writer.print(", .len = {d} }};\n", .{array_len}); |
| 3111 | 3231 | return local; |
| 3112 | 3232 | } |
| ... | ... | @@ -3138,7 +3258,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3138 | 3258 | const operand = try f.resolveInst(un_op); |
| 3139 | 3259 | |
| 3140 | 3260 | try writer.writeAll(" = ("); |
| 3141 | | try f.renderType(writer, inst_ty); |
| 3261 | try f.renderTypecast(writer, inst_ty); |
| 3142 | 3262 | try writer.writeAll(")"); |
| 3143 | 3263 | try f.writeCValue(writer, operand); |
| 3144 | 3264 | try writer.writeAll(";\n"); |