authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-18 14:08:06-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-18 14:08:06-05:00
log60bb1d4e1c262ff36c18cefe974aa2f773483af4
tree159ff6e30d4f74006783bfcd76a9de7fd0acedb4
parent736b9dcdd60b83c07bfbdb69c62facfbe10611f1
parent1639fd4c45ee816c7c67963fbff3513a32f5737b
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10906 from topolarity/cbe-array-support

stage2 CBE: Implement 2D array support

3 files changed, 364 insertions(+), 207 deletions(-)

src/codegen/c.zig+327-207
...@@ -34,6 +34,8 @@ pub const CValue = union(enum) {...@@ -34,6 +34,8 @@ pub const CValue = union(enum) {
34 /// By-value34 /// 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 }
293295
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};
302321
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 {
352371
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 }
377396
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 }
434453
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;
519589
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 }
629690
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;
691752
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("){");
695756
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);
711772
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("){");
715776
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 }
792854
...@@ -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 }
830892
...@@ -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();
856918
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();
9911052
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 }
10191082
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();
10241118
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)});
10301126
...@@ -1041,6 +1137,18 @@ pub const DeclGen = struct {...@@ -1041,6 +1137,18 @@ pub const DeclGen = struct {
1041 return name;1137 return name;
1042 }1138 }
10431139
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();
10461154
...@@ -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 declaration1229 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 }
11971305
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();
12081349
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 }
12611412
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),
14951669
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, "=="),
15001674
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 {
16411815
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);
16441819
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 }
17231898
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");
17351910
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}
17421913
...@@ -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);
17751946
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 pointer1962 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}
19122067
1913fn airStoreUndefined(f: *Function, dest_ptr: CValue, dest_child_type: Type) !CValue {2068fn 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;
19172072
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}
19482081
...@@ -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);
19622095
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 same2114 } 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);
19852118 try writer.writeAll(", ");
1986 // If the source is a constant, writeCValue will emit a brace initialization2119 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 array2121 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 };
23692490
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", .{});
23812502
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);
25682689
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 }
28542975
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");
28582978
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);
28632983
2864 try writer.writeAll(")->payload;\n");2984 try writer.writeAll(".payload;\n");
2865 return local;2985 return local;
2866}2986}
28672987
...@@ -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 "";
29123031
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}
29293040
...@@ -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 }
29773088
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) {
29833092 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}
29873099
...@@ -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 {
3069fn airIsErr(3181fn 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}
30963208
...@@ -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();
31073219
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);
31393259
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");
test/behavior/basic.zig+32
...@@ -436,6 +436,38 @@ test "array 2D const double ptr" {...@@ -436,6 +436,38 @@ test "array 2D const double ptr" {
436 try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);436 try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
437}437}
438438
439test "array 2D const double ptr with offset" {
440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
441 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
442 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
443 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
444
445 const rect_2d_vertexes = [_][2]f32{
446 [_]f32{ 3.0, 4.239 },
447 [_]f32{ 1.0, 2.0 },
448 };
449 try testArray2DConstDoublePtr(&rect_2d_vertexes[1][0]);
450}
451
452test "array 3D const double ptr with offset" {
453 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
454 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
455 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
456 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
457
458 const rect_3d_vertexes = [_][2][2]f32{
459 [_][2]f32{
460 [_]f32{ 3.0, 4.239 },
461 [_]f32{ 3.5, 7.2 },
462 },
463 [_][2]f32{
464 [_]f32{ 3.0, 4.239 },
465 [_]f32{ 1.0, 2.0 },
466 },
467 };
468 try testArray2DConstDoublePtr(&rect_3d_vertexes[1][1][0]);
469}
470
439fn testArray2DConstDoublePtr(ptr: *const f32) !void {471fn testArray2DConstDoublePtr(ptr: *const f32) !void {
440 const ptr2 = @ptrCast([*]const f32, ptr);472 const ptr2 = @ptrCast([*]const f32, ptr);
441 try expect(ptr2[0] == 1.0);473 try expect(ptr2[0] == 1.0);
test/behavior/undefined.zig+5
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const expect = std.testing.expect;3const expect = std.testing.expect;
3const mem = std.mem;4const mem = std.mem;
45
...@@ -12,6 +13,10 @@ fn initStaticArray() [10]i32 {...@@ -12,6 +13,10 @@ fn initStaticArray() [10]i32 {
12}13}
13const static_array = initStaticArray();14const static_array = initStaticArray();
14test "init static array to undefined" {15test "init static array to undefined" {
16 // This test causes `initStaticArray()` to be codegen'd, and the
17 // C backend does not yet support returning arrays, so it fails
18 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
19
15 try expect(static_array[0] == 1);20 try expect(static_array[0] == 1);
16 try expect(static_array[4] == 2);21 try expect(static_array[4] == 2);
17 try expect(static_array[7] == 3);22 try expect(static_array[7] == 3);