authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-21 01:49:28-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-09-21 01:49:28-07:00
log010d9a63f20d8a4bd14cff0ada690b2d127a0371
tree12b56ddfe5a5b235ef0676832902a0b04ad7d57a
parent3fbb88c4bd146ca7bd9e7ab5da9c4b05298f3b34
parent633162eb0c8d302ba7585cd308e01237409f042e
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25154 from ziglang/no-decl-val-3

rework byval ZIR instructions; forbid runtime vector indexes

58 files changed, 938 insertions(+), 1609 deletions(-)

doc/langref/test_overaligned_packed_struct.zig+1-1
......@@ -8,7 +8,7 @@ const S = packed struct {
88test "overaligned pointer to packed struct" {
99 var foo: S align(4) = .{ .a = 1, .b = 2 };
1010 const ptr: *align(4) S = &foo;
11 const ptr_to_b: *u32 = &ptr.b;
11 const ptr_to_b = &ptr.b;
1212 try expect(ptr_to_b.* == 2);
1313}
1414
lib/std/Io/Writer.zig+21-15
......@@ -1370,19 +1370,12 @@ pub fn printValue(
13701370 },
13711371 .array => {
13721372 if (!is_any) @compileError("cannot format array without a specifier (i.e. {s} or {any})");
1373 if (max_depth == 0) return w.writeAll("{ ... }");
1374 try w.writeAll("{ ");
1375 for (value, 0..) |elem, i| {
1376 try w.printValue(fmt, options, elem, max_depth - 1);
1377 if (i < value.len - 1) {
1378 try w.writeAll(", ");
1379 }
1380 }
1381 try w.writeAll(" }");
1373 return printArray(w, fmt, options, &value, max_depth);
13821374 },
1383 .vector => {
1375 .vector => |vector| {
13841376 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1385 return printVector(w, fmt, options, value, max_depth);
1377 const array: [vector.len]vector.child = value;
1378 return printArray(w, fmt, options, &array, max_depth);
13861379 },
13871380 .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"),
13881381 .type => {
......@@ -1436,12 +1429,25 @@ pub fn printVector(
14361429 value: anytype,
14371430 max_depth: usize,
14381431) Error!void {
1439 const len = @typeInfo(@TypeOf(value)).vector.len;
1432 const vector = @typeInfo(@TypeOf(value)).vector;
1433 const array: [vector.len]vector.child = value;
1434 return printArray(w, fmt, options, &array, max_depth);
1435}
1436
1437pub fn printArray(
1438 w: *Writer,
1439 comptime fmt: []const u8,
1440 options: std.fmt.Options,
1441 ptr_to_array: anytype,
1442 max_depth: usize,
1443) Error!void {
14401444 if (max_depth == 0) return w.writeAll("{ ... }");
14411445 try w.writeAll("{ ");
1442 inline for (0..len) |i| {
1443 try w.printValue(fmt, options, value[i], max_depth - 1);
1444 if (i < len - 1) try w.writeAll(", ");
1446 for (ptr_to_array, 0..) |elem, i| {
1447 try w.printValue(fmt, options, elem, max_depth - 1);
1448 if (i < ptr_to_array.len - 1) {
1449 try w.writeAll(", ");
1450 }
14451451 }
14461452 try w.writeAll(" }");
14471453}
lib/std/Progress.zig+15-5
......@@ -1248,7 +1248,9 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } {
12481248 i += progress_pulsing.len;
12491249 } else {
12501250 const percent = completed_items * 100 / estimated_total;
1251 i += (std.fmt.bufPrint(buf[i..], @"progress_normal {d}", .{percent}) catch &.{}).len;
1251 if (std.fmt.bufPrint(buf[i..], @"progress_normal {d}", .{percent})) |b| {
1252 i += b.len;
1253 } else |_| {}
12521254 }
12531255 },
12541256 .success => {
......@@ -1265,7 +1267,9 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } {
12651267 i += progress_pulsing_error.len;
12661268 } else {
12671269 const percent = completed_items * 100 / estimated_total;
1268 i += (std.fmt.bufPrint(buf[i..], @"progress_error {d}", .{percent}) catch &.{}).len;
1270 if (std.fmt.bufPrint(buf[i..], @"progress_error {d}", .{percent})) |b| {
1271 i += b.len;
1272 } else |_| {}
12691273 }
12701274 },
12711275 }
......@@ -1364,12 +1368,18 @@ fn computeNode(
13641368 if (!is_empty_root) {
13651369 if (name.len != 0 or estimated_total > 0) {
13661370 if (estimated_total > 0) {
1367 i += (std.fmt.bufPrint(buf[i..], "[{d}/{d}] ", .{ completed_items, estimated_total }) catch &.{}).len;
1371 if (std.fmt.bufPrint(buf[i..], "[{d}/{d}] ", .{ completed_items, estimated_total })) |b| {
1372 i += b.len;
1373 } else |_| {}
13681374 } else if (completed_items != 0) {
1369 i += (std.fmt.bufPrint(buf[i..], "[{d}] ", .{completed_items}) catch &.{}).len;
1375 if (std.fmt.bufPrint(buf[i..], "[{d}] ", .{completed_items})) |b| {
1376 i += b.len;
1377 } else |_| {}
13701378 }
13711379 if (name.len != 0) {
1372 i += (std.fmt.bufPrint(buf[i..], "{s}", .{name}) catch &.{}).len;
1380 if (std.fmt.bufPrint(buf[i..], "{s}", .{name})) |b| {
1381 i += b.len;
1382 } else |_| {}
13731383 }
13741384 }
13751385
lib/std/Target.zig+1-1
......@@ -1187,7 +1187,7 @@ pub const Cpu = struct {
11871187 pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize)));
11881188 pub const ShiftInt = std.math.Log2Int(usize);
11891189
1190 pub const empty = Set{ .ints = [1]usize{0} ** usize_count };
1190 pub const empty: Set = .{ .ints = @splat(0) };
11911191
11921192 pub fn isEmpty(set: Set) bool {
11931193 return for (set.ints) |x| {
lib/std/Thread.zig+5
......@@ -1661,6 +1661,11 @@ test "Thread.getCurrentId" {
16611661test "thread local storage" {
16621662 if (builtin.single_threaded) return error.SkipZigTest;
16631663
1664 if (builtin.cpu.arch == .thumbeb) {
1665 // https://github.com/ziglang/zig/issues/24061
1666 return error.SkipZigTest;
1667 }
1668
16641669 const thread1 = try Thread.spawn(.{}, testTls, .{});
16651670 const thread2 = try Thread.spawn(.{}, testTls, .{});
16661671 try testTls();
lib/std/crypto/chacha20.zig+11-11
......@@ -215,8 +215,8 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type
215215 }
216216 }
217217
218 fn hashToBytes(comptime dm: usize, out: *[64 * dm]u8, x: BlockVec) void {
219 for (0..dm) |d| {
218 fn hashToBytes(comptime dm: usize, out: *[64 * dm]u8, x: *const BlockVec) void {
219 inline for (0..dm) |d| {
220220 for (0..4) |i| {
221221 mem.writeInt(u32, out[64 * d + 16 * i + 0 ..][0..4], x[i][0 + 4 * d], .little);
222222 mem.writeInt(u32, out[64 * d + 16 * i + 4 ..][0..4], x[i][1 + 4 * d], .little);
......@@ -242,7 +242,7 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type
242242 while (degree >= d and i + 64 * d <= in.len) : (i += 64 * d) {
243243 chacha20Core(x[0..], ctx);
244244 contextFeedback(&x, ctx);
245 hashToBytes(d, buf[0 .. 64 * d], x);
245 hashToBytes(d, buf[0 .. 64 * d], &x);
246246
247247 var xout = out[i..];
248248 const xin = in[i..];
......@@ -266,7 +266,7 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type
266266 if (i < in.len) {
267267 chacha20Core(x[0..], ctx);
268268 contextFeedback(&x, ctx);
269 hashToBytes(1, buf[0..64], x);
269 hashToBytes(1, buf[0..64], &x);
270270
271271 var xout = out[i..];
272272 const xin = in[i..];
......@@ -284,7 +284,7 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type
284284 while (degree >= d and i + 64 * d <= out.len) : (i += 64 * d) {
285285 chacha20Core(x[0..], ctx);
286286 contextFeedback(&x, ctx);
287 hashToBytes(d, out[i..][0 .. 64 * d], x);
287 hashToBytes(d, out[i..][0 .. 64 * d], &x);
288288 inline for (0..d) |d_| {
289289 if (count64) {
290290 const next = @addWithOverflow(ctx[3][4 * d_], d);
......@@ -301,7 +301,7 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type
301301 contextFeedback(&x, ctx);
302302
303303 var buf: [64]u8 = undefined;
304 hashToBytes(1, buf[0..], x);
304 hashToBytes(1, buf[0..], &x);
305305 @memcpy(out[i..], buf[0 .. out.len - i]);
306306 }
307307 }
......@@ -394,7 +394,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type {
394394 }
395395 }
396396
397 fn hashToBytes(out: *[64]u8, x: BlockVec) void {
397 fn hashToBytes(out: *[64]u8, x: *const BlockVec) void {
398398 for (0..4) |i| {
399399 mem.writeInt(u32, out[16 * i + 0 ..][0..4], x[i * 4 + 0], .little);
400400 mem.writeInt(u32, out[16 * i + 4 ..][0..4], x[i * 4 + 1], .little);
......@@ -417,7 +417,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type {
417417 while (i + 64 <= in.len) : (i += 64) {
418418 chacha20Core(x[0..], ctx);
419419 contextFeedback(&x, ctx);
420 hashToBytes(buf[0..], x);
420 hashToBytes(buf[0..], &x);
421421
422422 var xout = out[i..];
423423 const xin = in[i..];
......@@ -438,7 +438,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type {
438438 if (i < in.len) {
439439 chacha20Core(x[0..], ctx);
440440 contextFeedback(&x, ctx);
441 hashToBytes(buf[0..], x);
441 hashToBytes(buf[0..], &x);
442442
443443 var xout = out[i..];
444444 const xin = in[i..];
......@@ -455,7 +455,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type {
455455 while (i + 64 <= out.len) : (i += 64) {
456456 chacha20Core(x[0..], ctx);
457457 contextFeedback(&x, ctx);
458 hashToBytes(out[i..][0..64], x);
458 hashToBytes(out[i..][0..64], &x);
459459 if (count64) {
460460 const next = @addWithOverflow(ctx[12], 1);
461461 ctx[12] = next[0];
......@@ -469,7 +469,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type {
469469 contextFeedback(&x, ctx);
470470
471471 var buf: [64]u8 = undefined;
472 hashToBytes(buf[0..], x);
472 hashToBytes(buf[0..], &x);
473473 @memcpy(out[i..], buf[0 .. out.len - i]);
474474 }
475475 }
lib/std/json/static.zig+8-9
......@@ -389,7 +389,7 @@ pub fn innerParse(
389389 switch (try source.peekNextTokenType()) {
390390 .array_begin => {
391391 // Typical array.
392 return internalParseArray(T, arrayInfo.child, arrayInfo.len, allocator, source, options);
392 return internalParseArray(T, arrayInfo.child, allocator, source, options);
393393 },
394394 .string => {
395395 if (arrayInfo.child != u8) return error.UnexpectedToken;
......@@ -440,10 +440,11 @@ pub fn innerParse(
440440 }
441441 },
442442
443 .vector => |vecInfo| {
443 .vector => |vector_info| {
444444 switch (try source.peekNextTokenType()) {
445445 .array_begin => {
446 return internalParseArray(T, vecInfo.child, vecInfo.len, allocator, source, options);
446 const A = [vector_info.len]vector_info.child;
447 return try internalParseArray(A, vector_info.child, allocator, source, options);
447448 },
448449 else => return error.UnexpectedToken,
449450 }
......@@ -519,7 +520,6 @@ pub fn innerParse(
519520fn internalParseArray(
520521 comptime T: type,
521522 comptime Child: type,
522 comptime len: comptime_int,
523523 allocator: Allocator,
524524 source: anytype,
525525 options: ParseOptions,
......@@ -527,9 +527,8 @@ fn internalParseArray(
527527 assert(.array_begin == try source.next());
528528
529529 var r: T = undefined;
530 var i: usize = 0;
531 while (i < len) : (i += 1) {
532 r[i] = try innerParse(Child, allocator, source, options);
530 for (&r) |*elem| {
531 elem.* = try innerParse(Child, allocator, source, options);
533532 }
534533
535534 if (.array_end != try source.next()) return error.UnexpectedToken;
......@@ -569,12 +568,12 @@ pub fn innerParseFromValue(
569568 if (@round(f) != f) return error.InvalidNumber;
570569 if (f > @as(@TypeOf(f), @floatFromInt(std.math.maxInt(T)))) return error.Overflow;
571570 if (f < @as(@TypeOf(f), @floatFromInt(std.math.minInt(T)))) return error.Overflow;
572 return @as(T, @intFromFloat(f));
571 return @intFromFloat(f);
573572 },
574573 .integer => |i| {
575574 if (i > std.math.maxInt(T)) return error.Overflow;
576575 if (i < std.math.minInt(T)) return error.Overflow;
577 return @as(T, @intCast(i));
576 return @intCast(i);
578577 },
579578 .number_string, .string => |s| {
580579 return sliceToInt(T, s);
lib/std/meta.zig+1-7
......@@ -742,13 +742,7 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool {
742742 if (!eql(e, b[i])) return false;
743743 return true;
744744 },
745 .vector => |info| {
746 var i: usize = 0;
747 while (i < info.len) : (i += 1) {
748 if (!eql(a[i], b[i])) return false;
749 }
750 return true;
751 },
745 .vector => return @reduce(.And, a == b),
752746 .pointer => |info| {
753747 return switch (info.size) {
754748 .one, .many, .c => a == b,
lib/std/testing.zig+4-11
......@@ -135,15 +135,9 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void {
135135 .array => |array| try expectEqualSlices(array.child, &expected, &actual),
136136
137137 .vector => |info| {
138 var i: usize = 0;
139 while (i < info.len) : (i += 1) {
140 if (!std.meta.eql(expected[i], actual[i])) {
141 print("index {d} incorrect. expected {any}, found {any}\n", .{
142 i, expected[i], actual[i],
143 });
144 return error.TestExpectedEqual;
145 }
146 }
138 const expect_array: [info.len]info.child = expected;
139 const actual_array: [info.len]info.child = actual;
140 try expectEqualSlices(info.child, &expect_array, &actual_array);
147141 },
148142
149143 .@"struct" => |structType| {
......@@ -828,8 +822,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe
828822 print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).vector.len });
829823 return error.TestExpectedEqual;
830824 }
831 var i: usize = 0;
832 while (i < info.len) : (i += 1) {
825 inline for (0..info.len) |i| {
833826 expectEqualDeep(expected[i], actual[i]) catch |e| {
834827 print("index {d} incorrect. expected {any}, found {any}\n", .{
835828 i, expected[i], actual[i],
lib/std/zig/AstGen.zig+20-16
......@@ -2728,12 +2728,12 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
27282728 .elem_ptr,
27292729 .elem_val,
27302730 .elem_ptr_node,
2731 .elem_val_node,
2731 .elem_ptr_load,
27322732 .elem_val_imm,
27332733 .field_ptr,
2734 .field_val,
2734 .field_ptr_load,
27352735 .field_ptr_named,
2736 .field_val_named,
2736 .field_ptr_named_load,
27372737 .func,
27382738 .func_inferred,
27392739 .func_fancy,
......@@ -6160,7 +6160,7 @@ fn fieldAccess(
61606160 switch (ri.rl) {
61616161 .ref, .ref_coerced_ty => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node),
61626162 else => {
6163 const access = try addFieldAccess(.field_val, gz, scope, .{ .rl = .none }, node);
6163 const access = try addFieldAccess(.field_ptr_load, gz, scope, .{ .rl = .ref }, node);
61646164 return rvalue(gz, ri, access, node);
61656165 },
61666166 }
......@@ -6210,14 +6210,14 @@ fn arrayAccess(
62106210 },
62116211 else => {
62126212 const lhs_node, const rhs_node = tree.nodeData(node).node_and_node;
6213 const lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node);
6213 const lhs = try expr(gz, scope, .{ .rl = .ref }, lhs_node);
62146214
62156215 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
62166216
62176217 const rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, rhs_node);
62186218 try emitDbgStmt(gz, cursor);
62196219
6220 return rvalue(gz, ri, try gz.addPlNode(.elem_val_node, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs }), node);
6220 return rvalue(gz, ri, try gz.addPlNode(.elem_ptr_load, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs }), node);
62216221 },
62226222 }
62236223}
......@@ -9286,17 +9286,21 @@ fn builtinCall(
92869286 return rvalue(gz, ri, result, node);
92879287 },
92889288 .field => {
9289 if (ri.rl == .ref or ri.rl == .ref_coerced_ty) {
9290 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
9291 .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]),
9292 .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name),
9293 });
9289 switch (ri.rl) {
9290 .ref, .ref_coerced_ty => {
9291 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
9292 .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]),
9293 .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name),
9294 });
9295 },
9296 else => {
9297 const result = try gz.addPlNode(.field_ptr_named_load, node, Zir.Inst.FieldNamed{
9298 .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]),
9299 .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name),
9300 });
9301 return rvalue(gz, ri, result, node);
9302 },
92949303 }
9295 const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{
9296 .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
9297 .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name),
9298 });
9299 return rvalue(gz, ri, result, node);
93009304 },
93019305 .FieldType => {
93029306 const ty_inst = try typeExpr(gz, scope, params[0]);
lib/std/zig/Zir.zig+34-21
......@@ -420,6 +420,7 @@ pub const Inst = struct {
420420 /// is the local's value.
421421 dbg_var_val,
422422 /// Uses a name to identify a Decl and takes a pointer to it.
423 ///
423424 /// Uses the `str_tok` union field.
424425 decl_ref,
425426 /// Uses a name to identify a Decl and uses it as a value.
......@@ -440,12 +441,17 @@ pub const Inst = struct {
440441 /// Payload is `Bin`.
441442 /// No OOB safety check is emitted.
442443 elem_ptr,
443 /// Given an array, slice, or pointer, returns the element at the provided index.
444 /// Given a pointer to an array, slice, or pointer, loads the element
445 /// at the provided index.
446 ///
444447 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
445 elem_val_node,
446 /// Same as `elem_val_node` but used only for for loop.
447 /// Uses the `pl_node` union field. AST node is the condition of a for loop.
448 /// Payload is `Bin`.
448 elem_ptr_load,
449 /// Given an array, slice, or pointer, returns the element at the
450 /// provided index.
451 ///
452 /// Uses the `pl_node` union field. AST node is the condition of a for
453 /// loop. Payload is `Bin`.
454 ///
449455 /// No OOB safety check is emitted.
450456 elem_val,
451457 /// Same as `elem_val` but takes the index as an immediate value.
......@@ -472,19 +478,26 @@ pub const Inst = struct {
472478 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
473479 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
474480 field_ptr,
475 /// Given a struct or object that contains virtual fields, returns the named field.
481 /// Given a pointer to a struct or object that contains virtual fields, loads from the
482 /// named field.
483 ///
476484 /// The field name is stored in string_bytes. Used by a.b syntax.
485 ///
477486 /// This instruction also accepts a pointer.
487 ///
478488 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
479 field_val,
489 field_ptr_load,
480490 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
481491 /// to the named field. The field name is a comptime instruction. Used by @field.
482492 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
483493 field_ptr_named,
484 /// Given a struct or object that contains virtual fields, returns the named field.
494 /// Given a pointer to a struct or object that contains virtual fields,
495 /// loads from the named field.
496 ///
485497 /// The field name is a comptime instruction. Used by @field.
498 ///
486499 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
487 field_val_named,
500 field_ptr_named_load,
488501 /// Returns a function type, or a function instance, depending on whether
489502 /// the body_len is 0. Calling convention is auto.
490503 /// Uses the `pl_node` union field. `payload_index` points to a `Func`.
......@@ -1138,16 +1151,16 @@ pub const Inst = struct {
11381151 .elem_ptr,
11391152 .elem_val,
11401153 .elem_ptr_node,
1141 .elem_val_node,
1154 .elem_ptr_load,
11421155 .elem_val_imm,
11431156 .ensure_result_used,
11441157 .ensure_result_non_error,
11451158 .ensure_err_union_payload_void,
11461159 .@"export",
11471160 .field_ptr,
1148 .field_val,
1161 .field_ptr_load,
11491162 .field_ptr_named,
1150 .field_val_named,
1163 .field_ptr_named_load,
11511164 .func,
11521165 .func_inferred,
11531166 .func_fancy,
......@@ -1432,12 +1445,12 @@ pub const Inst = struct {
14321445 .elem_ptr,
14331446 .elem_val,
14341447 .elem_ptr_node,
1435 .elem_val_node,
1448 .elem_ptr_load,
14361449 .elem_val_imm,
14371450 .field_ptr,
1438 .field_val,
1451 .field_ptr_load,
14391452 .field_ptr_named,
1440 .field_val_named,
1453 .field_ptr_named_load,
14411454 .func,
14421455 .func_inferred,
14431456 .func_fancy,
......@@ -1679,7 +1692,7 @@ pub const Inst = struct {
16791692 .elem_ptr = .pl_node,
16801693 .elem_ptr_node = .pl_node,
16811694 .elem_val = .pl_node,
1682 .elem_val_node = .pl_node,
1695 .elem_ptr_load = .pl_node,
16831696 .elem_val_imm = .elem_val_imm,
16841697 .ensure_result_used = .un_node,
16851698 .ensure_result_non_error = .un_node,
......@@ -1688,9 +1701,9 @@ pub const Inst = struct {
16881701 .error_value = .str_tok,
16891702 .@"export" = .pl_node,
16901703 .field_ptr = .pl_node,
1691 .field_val = .pl_node,
1704 .field_ptr_load = .pl_node,
16921705 .field_ptr_named = .pl_node,
1693 .field_val_named = .pl_node,
1706 .field_ptr_named_load = .pl_node,
16941707 .func = .pl_node,
16951708 .func_inferred = .pl_node,
16961709 .func_fancy = .pl_node,
......@@ -4215,7 +4228,7 @@ fn findTrackableInner(
42154228 .div,
42164229 .elem_ptr_node,
42174230 .elem_ptr,
4218 .elem_val_node,
4231 .elem_ptr_load,
42194232 .elem_val,
42204233 .elem_val_imm,
42214234 .ensure_result_used,
......@@ -4225,9 +4238,9 @@ fn findTrackableInner(
42254238 .error_value,
42264239 .@"export",
42274240 .field_ptr,
4228 .field_val,
4241 .field_ptr_load,
42294242 .field_ptr_named,
4230 .field_val_named,
4243 .field_ptr_named_load,
42314244 .import,
42324245 .int,
42334246 .int_big,
lib/std/zon/Serializer.zig+15-16
......@@ -157,13 +157,11 @@ pub fn valueArbitraryDepth(self: *Serializer, val: anytype, options: ValueOption
157157 }
158158 },
159159 .array => {
160 var container = try self.beginTuple(
161 .{ .whitespace_style = .{ .fields = val.len } },
162 );
163 for (val) |item_val| {
164 try container.fieldArbitraryDepth(item_val, options);
165 }
166 try container.end();
160 try valueArbitraryDepthArray(self, @TypeOf(val), &val, options);
161 },
162 .vector => |vector| {
163 const array: [vector.len]vector.child = val;
164 try valueArbitraryDepthArray(self, @TypeOf(array), &array, options);
167165 },
168166 .@"struct" => |@"struct"| if (@"struct".is_tuple) {
169167 var container = try self.beginTuple(
......@@ -231,20 +229,21 @@ pub fn valueArbitraryDepth(self: *Serializer, val: anytype, options: ValueOption
231229 } else {
232230 try self.writer.writeAll("null");
233231 },
234 .vector => |vector| {
235 var container = try self.beginTuple(
236 .{ .whitespace_style = .{ .fields = vector.len } },
237 );
238 for (0..vector.len) |i| {
239 try container.fieldArbitraryDepth(val[i], options);
240 }
241 try container.end();
242 },
243232
244233 else => comptime unreachable,
245234 }
246235}
247236
237fn valueArbitraryDepthArray(s: *Serializer, comptime A: type, array: *const A, options: ValueOptions) Error!void {
238 var container = try s.beginTuple(
239 .{ .whitespace_style = .{ .fields = array.len } },
240 );
241 for (array) |elem| {
242 try container.fieldArbitraryDepth(elem, options);
243 }
244 try container.end();
245}
246
248247/// Serialize an integer.
249248pub fn int(self: *Serializer, val: anytype) Error!void {
250249 try self.writer.printInt(val, 10, .lower, .{});
lib/std/zon/parse.zig+17-37
......@@ -430,8 +430,12 @@ pub fn free(gpa: Allocator, value: anytype) void {
430430 .many, .c => comptime unreachable,
431431 }
432432 },
433 .array => for (value) |item| {
434 free(gpa, item);
433 .array => {
434 freeArray(gpa, @TypeOf(value), &value);
435 },
436 .vector => |vector| {
437 const array: [vector.len]vector.child = value;
438 freeArray(gpa, @TypeOf(array), &array);
435439 },
436440 .@"struct" => |@"struct"| inline for (@"struct".fields) |field| {
437441 free(gpa, @field(value, field.name));
......@@ -446,12 +450,15 @@ pub fn free(gpa: Allocator, value: anytype) void {
446450 .optional => if (value) |some| {
447451 free(gpa, some);
448452 },
449 .vector => |vector| for (0..vector.len) |i| free(gpa, value[i]),
450453 .void => {},
451454 else => comptime unreachable,
452455 }
453456}
454457
458fn freeArray(gpa: Allocator, comptime A: type, array: *const A) void {
459 for (array) |elem| free(gpa, elem);
460}
461
455462fn requiresAllocator(T: type) bool {
456463 _ = valid_types;
457464 return switch (@typeInfo(T)) {
......@@ -521,12 +528,15 @@ const Parser = struct {
521528 else => comptime unreachable,
522529 },
523530 .array => return self.parseArray(T, node),
531 .vector => |vector| {
532 const A = [vector.len]vector.child;
533 return try self.parseArray(A, node);
534 },
524535 .@"struct" => |@"struct"| if (@"struct".is_tuple)
525536 return self.parseTuple(T, node)
526537 else
527538 return self.parseStruct(T, node),
528539 .@"union" => return self.parseUnion(T, node),
529 .vector => return self.parseVector(T, node),
530540
531541 else => comptime unreachable,
532542 }
......@@ -786,6 +796,7 @@ const Parser = struct {
786796
787797 elem.* = try self.parseExpr(array_info.child, nodes.at(@intCast(i)));
788798 }
799 if (array_info.sentinel()) |s| result[result.len] = s;
789800 return result;
790801 }
791802
......@@ -998,37 +1009,6 @@ const Parser = struct {
9981009 }
9991010 }
10001011
1001 fn parseVector(
1002 self: *@This(),
1003 T: type,
1004 node: Zoir.Node.Index,
1005 ) !T {
1006 const vector_info = @typeInfo(T).vector;
1007
1008 const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
1009 .array_literal => |nodes| nodes,
1010 .empty_literal => .{ .start = node, .len = 0 },
1011 else => return error.WrongType,
1012 };
1013
1014 var result: T = undefined;
1015
1016 if (nodes.len != vector_info.len) {
1017 return self.failNodeFmt(
1018 node,
1019 "expected {} vector elements; found {}",
1020 .{ vector_info.len, nodes.len },
1021 );
1022 }
1023
1024 for (0..vector_info.len) |i| {
1025 errdefer for (0..i) |j| free(self.gpa, result[j]);
1026 result[i] = try self.parseExpr(vector_info.child, nodes.at(@intCast(i)));
1027 }
1028
1029 return result;
1030 }
1031
10321012 fn failTokenFmt(
10331013 self: @This(),
10341014 token: Ast.TokenIndex,
......@@ -3209,7 +3189,7 @@ test "std.zon vector" {
32093189 fromSlice(@Vector(2, f32), gpa, ".{0.5}", &diag, .{}),
32103190 );
32113191 try std.testing.expectFmt(
3212 "1:2: error: expected 2 vector elements; found 1\n",
3192 "1:2: error: expected 2 array elements; found 1\n",
32133193 "{f}",
32143194 .{diag},
32153195 );
......@@ -3224,7 +3204,7 @@ test "std.zon vector" {
32243204 fromSlice(@Vector(2, f32), gpa, ".{0.5, 1.5, 2.5}", &diag, .{}),
32253205 );
32263206 try std.testing.expectFmt(
3227 "1:2: error: expected 2 vector elements; found 3\n",
3207 "1:13: error: index 2 outside of array of length 2\n",
32283208 "{f}",
32293209 .{diag},
32303210 );
src/Air.zig+18-12
......@@ -166,19 +166,25 @@ pub const Inst = struct {
166166 mod,
167167 /// Same as `mod` with optimized float mode.
168168 mod_optimized,
169 /// Add an offset to a pointer, returning a new pointer.
170 /// The offset is in element type units, not bytes.
171 /// Wrapping is illegal behavior.
172 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.
173 /// The pointer may be a slice.
174 /// Uses the `ty_pl` field. Payload is `Bin`.
169 /// Add an offset, in element type units, to a pointer, returning a new
170 /// pointer. Element type may not be zero bits.
171 ///
172 /// Wrapping is illegal behavior. If the newly computed address is
173 /// outside the provenance of the operand, the result is undefined.
174 ///
175 /// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer,
176 /// rhs is the offset. Result type is the same as lhs. The operand may
177 /// be a slice.
175178 ptr_add,
176 /// Subtract an offset from a pointer, returning a new pointer.
177 /// The offset is in element type units, not bytes.
178 /// Wrapping is illegal behavior.
179 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.
180 /// The pointer may be a slice.
181 /// Uses the `ty_pl` field. Payload is `Bin`.
179 /// Subtract an offset, in element type units, from a pointer,
180 /// returning a new pointer. Element type may not be zero bits.
181 ///
182 /// Wrapping is illegal behavior. If the newly computed address is
183 /// outside the provenance of the operand, the result is undefined.
184 ///
185 /// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer,
186 /// rhs is the offset. Result type is the same as lhs. The operand may
187 /// be a slice.
182188 ptr_sub,
183189 /// Given two operands which can be floats, integers, or vectors, returns the
184190 /// greater of the operands. For vectors it operates element-wise.
src/Air/Legalize.zig+4-6
......@@ -2682,12 +2682,10 @@ const Block = struct {
26822682 },
26832683 .@"packed" => switch (agg_ty.zigTypeTag(zcu)) {
26842684 else => unreachable,
2685 .@"struct" => switch (agg_ty.packedStructFieldPtrInfo(agg_ptr_ty, @intCast(field_index), pt)) {
2686 .bit_ptr => |packed_offset| {
2687 field_ptr_info.packed_offset = packed_offset;
2688 break :field_ptr_align agg_ptr_align;
2689 },
2690 .byte_ptr => |ptr_info| ptr_info.alignment,
2685 .@"struct" => {
2686 const packed_offset = agg_ty.packedStructFieldPtrInfo(agg_ptr_ty, @intCast(field_index), pt);
2687 field_ptr_info.packed_offset = packed_offset;
2688 break :field_ptr_align agg_ptr_align;
26912689 },
26922690 .@"union" => {
26932691 field_ptr_info.packed_offset = .{
src/Air/Liveness.zig-495
......@@ -207,501 +207,6 @@ pub fn operandDies(l: Liveness, inst: Air.Inst.Index, operand: OperandInt) bool
207207 return (l.tomb_bits[usize_index] & mask) != 0;
208208}
209209
210const OperandCategory = enum {
211 /// The operand lives on, but this instruction cannot possibly mutate memory.
212 none,
213 /// The operand lives on and this instruction can mutate memory.
214 write,
215 /// The operand dies at this instruction.
216 tomb,
217 /// The operand lives on, and this instruction is noreturn.
218 noret,
219 /// This instruction is too complicated for analysis, no information is available.
220 complex,
221};
222
223/// Given an instruction that we are examining, and an operand that we are looking for,
224/// returns a classification.
225pub fn categorizeOperand(
226 l: Liveness,
227 air: Air,
228 zcu: *Zcu,
229 inst: Air.Inst.Index,
230 operand: Air.Inst.Index,
231 ip: *const InternPool,
232) OperandCategory {
233 const air_tags = air.instructions.items(.tag);
234 const air_datas = air.instructions.items(.data);
235 const operand_ref = operand.toRef();
236 switch (air_tags[@intFromEnum(inst)]) {
237 .add,
238 .add_safe,
239 .add_wrap,
240 .add_sat,
241 .add_optimized,
242 .sub,
243 .sub_safe,
244 .sub_wrap,
245 .sub_sat,
246 .sub_optimized,
247 .mul,
248 .mul_safe,
249 .mul_wrap,
250 .mul_sat,
251 .mul_optimized,
252 .div_float,
253 .div_trunc,
254 .div_floor,
255 .div_exact,
256 .rem,
257 .mod,
258 .bit_and,
259 .bit_or,
260 .xor,
261 .cmp_lt,
262 .cmp_lte,
263 .cmp_eq,
264 .cmp_gte,
265 .cmp_gt,
266 .cmp_neq,
267 .bool_and,
268 .bool_or,
269 .array_elem_val,
270 .slice_elem_val,
271 .ptr_elem_val,
272 .shl,
273 .shl_exact,
274 .shl_sat,
275 .shr,
276 .shr_exact,
277 .min,
278 .max,
279 .div_float_optimized,
280 .div_trunc_optimized,
281 .div_floor_optimized,
282 .div_exact_optimized,
283 .rem_optimized,
284 .mod_optimized,
285 .neg_optimized,
286 .cmp_lt_optimized,
287 .cmp_lte_optimized,
288 .cmp_eq_optimized,
289 .cmp_gte_optimized,
290 .cmp_gt_optimized,
291 .cmp_neq_optimized,
292 => {
293 const o = air_datas[@intFromEnum(inst)].bin_op;
294 if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
295 if (o.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
296 return .none;
297 },
298
299 .store,
300 .store_safe,
301 .atomic_store_unordered,
302 .atomic_store_monotonic,
303 .atomic_store_release,
304 .atomic_store_seq_cst,
305 .set_union_tag,
306 .memset,
307 .memset_safe,
308 .memcpy,
309 .memmove,
310 => {
311 const o = air_datas[@intFromEnum(inst)].bin_op;
312 if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
313 if (o.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .write);
314 return .write;
315 },
316
317 .vector_store_elem => {
318 const o = air_datas[@intFromEnum(inst)].vector_store_elem;
319 const extra = air.extraData(Air.Bin, o.payload).data;
320 if (o.vector_ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
321 if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
322 if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 2, .none);
323 return .write;
324 },
325
326 .arg,
327 .alloc,
328 .inferred_alloc,
329 .inferred_alloc_comptime,
330 .ret_ptr,
331 .trap,
332 .breakpoint,
333 .repeat,
334 .switch_dispatch,
335 .dbg_stmt,
336 .dbg_empty_stmt,
337 .unreach,
338 .ret_addr,
339 .frame_addr,
340 .wasm_memory_size,
341 .err_return_trace,
342 .save_err_return_trace_index,
343 .runtime_nav_ptr,
344 .c_va_start,
345 .work_item_id,
346 .work_group_size,
347 .work_group_id,
348 => return .none,
349
350 .not,
351 .bitcast,
352 .load,
353 .fpext,
354 .fptrunc,
355 .intcast,
356 .intcast_safe,
357 .trunc,
358 .optional_payload,
359 .optional_payload_ptr,
360 .wrap_optional,
361 .unwrap_errunion_payload,
362 .unwrap_errunion_err,
363 .unwrap_errunion_payload_ptr,
364 .unwrap_errunion_err_ptr,
365 .wrap_errunion_payload,
366 .wrap_errunion_err,
367 .slice_ptr,
368 .slice_len,
369 .ptr_slice_len_ptr,
370 .ptr_slice_ptr_ptr,
371 .struct_field_ptr_index_0,
372 .struct_field_ptr_index_1,
373 .struct_field_ptr_index_2,
374 .struct_field_ptr_index_3,
375 .array_to_slice,
376 .int_from_float,
377 .int_from_float_optimized,
378 .int_from_float_safe,
379 .int_from_float_optimized_safe,
380 .float_from_int,
381 .get_union_tag,
382 .clz,
383 .ctz,
384 .popcount,
385 .byte_swap,
386 .bit_reverse,
387 .splat,
388 .error_set_has_value,
389 .addrspace_cast,
390 .c_va_arg,
391 .c_va_copy,
392 .abs,
393 => {
394 const o = air_datas[@intFromEnum(inst)].ty_op;
395 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
396 return .none;
397 },
398
399 .optional_payload_ptr_set,
400 .errunion_payload_ptr_set,
401 => {
402 const o = air_datas[@intFromEnum(inst)].ty_op;
403 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
404 return .write;
405 },
406
407 .is_null,
408 .is_non_null,
409 .is_null_ptr,
410 .is_non_null_ptr,
411 .is_err,
412 .is_non_err,
413 .is_err_ptr,
414 .is_non_err_ptr,
415 .is_named_enum_value,
416 .tag_name,
417 .error_name,
418 .sqrt,
419 .sin,
420 .cos,
421 .tan,
422 .exp,
423 .exp2,
424 .log,
425 .log2,
426 .log10,
427 .floor,
428 .ceil,
429 .round,
430 .trunc_float,
431 .neg,
432 .cmp_lt_errors_len,
433 .c_va_end,
434 => {
435 const o = air_datas[@intFromEnum(inst)].un_op;
436 if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
437 return .none;
438 },
439
440 .ret,
441 .ret_safe,
442 .ret_load,
443 => {
444 const o = air_datas[@intFromEnum(inst)].un_op;
445 if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .noret);
446 return .noret;
447 },
448
449 .set_err_return_trace => {
450 const o = air_datas[@intFromEnum(inst)].un_op;
451 if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
452 return .write;
453 },
454
455 .add_with_overflow,
456 .sub_with_overflow,
457 .mul_with_overflow,
458 .shl_with_overflow,
459 .ptr_add,
460 .ptr_sub,
461 .ptr_elem_ptr,
462 .slice_elem_ptr,
463 .slice,
464 => {
465 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
466 const extra = air.extraData(Air.Bin, ty_pl.payload).data;
467 if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
468 if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
469 return .none;
470 },
471
472 .dbg_var_ptr,
473 .dbg_var_val,
474 .dbg_arg_inline,
475 => {
476 const o = air_datas[@intFromEnum(inst)].pl_op.operand;
477 if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
478 return .none;
479 },
480
481 .prefetch => {
482 const prefetch = air_datas[@intFromEnum(inst)].prefetch;
483 if (prefetch.ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
484 return .none;
485 },
486
487 .call, .call_always_tail, .call_never_tail, .call_never_inline => {
488 const inst_data = air_datas[@intFromEnum(inst)].pl_op;
489 const callee = inst_data.operand;
490 const extra = air.extraData(Air.Call, inst_data.payload);
491 const args = @as([]const Air.Inst.Ref, @ptrCast(air.extra.items[extra.end..][0..extra.data.args_len]));
492 if (args.len + 1 <= bpi - 1) {
493 if (callee == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
494 for (args, 0..) |arg, i| {
495 if (arg == operand_ref) return matchOperandSmallIndex(l, inst, @as(OperandInt, @intCast(i + 1)), .write);
496 }
497 return .write;
498 }
499 var bt = l.iterateBigTomb(inst);
500 if (bt.feed()) {
501 if (callee == operand_ref) return .tomb;
502 } else {
503 if (callee == operand_ref) return .write;
504 }
505 for (args) |arg| {
506 if (bt.feed()) {
507 if (arg == operand_ref) return .tomb;
508 } else {
509 if (arg == operand_ref) return .write;
510 }
511 }
512 return .write;
513 },
514 .select => {
515 const pl_op = air_datas[@intFromEnum(inst)].pl_op;
516 const extra = air.extraData(Air.Bin, pl_op.payload).data;
517 if (pl_op.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
518 if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
519 if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 2, .none);
520 return .none;
521 },
522 .shuffle_one => {
523 const unwrapped = air.unwrapShuffleOne(zcu, inst);
524 if (unwrapped.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
525 return .none;
526 },
527 .shuffle_two => {
528 const unwrapped = air.unwrapShuffleTwo(zcu, inst);
529 if (unwrapped.operand_a == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
530 if (unwrapped.operand_b == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
531 return .none;
532 },
533 .reduce, .reduce_optimized => {
534 const reduce = air_datas[@intFromEnum(inst)].reduce;
535 if (reduce.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
536 return .none;
537 },
538 .cmp_vector, .cmp_vector_optimized => {
539 const extra = air.extraData(Air.VectorCmp, air_datas[@intFromEnum(inst)].ty_pl.payload).data;
540 if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
541 if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
542 return .none;
543 },
544 .aggregate_init => {
545 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
546 const aggregate_ty = ty_pl.ty.toType();
547 const len = @as(usize, @intCast(aggregate_ty.arrayLenIp(ip)));
548 const elements = @as([]const Air.Inst.Ref, @ptrCast(air.extra.items[ty_pl.payload..][0..len]));
549
550 if (elements.len <= bpi - 1) {
551 for (elements, 0..) |elem, i| {
552 if (elem == operand_ref) return matchOperandSmallIndex(l, inst, @as(OperandInt, @intCast(i)), .none);
553 }
554 return .none;
555 }
556
557 var bt = l.iterateBigTomb(inst);
558 for (elements) |elem| {
559 if (bt.feed()) {
560 if (elem == operand_ref) return .tomb;
561 } else {
562 if (elem == operand_ref) return .write;
563 }
564 }
565 return .write;
566 },
567 .union_init => {
568 const extra = air.extraData(Air.UnionInit, air_datas[@intFromEnum(inst)].ty_pl.payload).data;
569 if (extra.init == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
570 return .none;
571 },
572 .struct_field_ptr, .struct_field_val => {
573 const extra = air.extraData(Air.StructField, air_datas[@intFromEnum(inst)].ty_pl.payload).data;
574 if (extra.struct_operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
575 return .none;
576 },
577 .field_parent_ptr => {
578 const extra = air.extraData(Air.FieldParentPtr, air_datas[@intFromEnum(inst)].ty_pl.payload).data;
579 if (extra.field_ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
580 return .none;
581 },
582 .cmpxchg_strong, .cmpxchg_weak => {
583 const extra = air.extraData(Air.Cmpxchg, air_datas[@intFromEnum(inst)].ty_pl.payload).data;
584 if (extra.ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
585 if (extra.expected_value == operand_ref) return matchOperandSmallIndex(l, inst, 1, .write);
586 if (extra.new_value == operand_ref) return matchOperandSmallIndex(l, inst, 2, .write);
587 return .write;
588 },
589 .mul_add => {
590 const pl_op = air_datas[@intFromEnum(inst)].pl_op;
591 const extra = air.extraData(Air.Bin, pl_op.payload).data;
592 if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
593 if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
594 if (pl_op.operand == operand_ref) return matchOperandSmallIndex(l, inst, 2, .none);
595 return .none;
596 },
597 .atomic_load => {
598 const ptr = air_datas[@intFromEnum(inst)].atomic_load.ptr;
599 if (ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
600 return .none;
601 },
602 .atomic_rmw => {
603 const pl_op = air_datas[@intFromEnum(inst)].pl_op;
604 const extra = air.extraData(Air.AtomicRmw, pl_op.payload).data;
605 if (pl_op.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
606 if (extra.operand == operand_ref) return matchOperandSmallIndex(l, inst, 1, .write);
607 return .write;
608 },
609
610 .br => {
611 const br = air_datas[@intFromEnum(inst)].br;
612 if (br.operand == operand_ref) return matchOperandSmallIndex(l, operand, 0, .noret);
613 return .noret;
614 },
615 .assembly => {
616 return .complex;
617 },
618 .block, .dbg_inline_block => |tag| {
619 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
620 const body: []const Air.Inst.Index = @ptrCast(switch (tag) {
621 inline .block, .dbg_inline_block => |comptime_tag| body: {
622 const extra = air.extraData(switch (comptime_tag) {
623 .block => Air.Block,
624 .dbg_inline_block => Air.DbgInlineBlock,
625 else => unreachable,
626 }, ty_pl.payload);
627 break :body air.extra.items[extra.end..][0..extra.data.body_len];
628 },
629 else => unreachable,
630 });
631
632 if (body.len == 1 and air_tags[@intFromEnum(body[0])] == .cond_br) {
633 // Peephole optimization for "panic-like" conditionals, which have
634 // one empty branch and another which calls a `noreturn` function.
635 // This allows us to infer that safety checks do not modify memory,
636 // as far as control flow successors are concerned.
637
638 const inst_data = air_datas[@intFromEnum(body[0])].pl_op;
639 const cond_extra = air.extraData(Air.CondBr, inst_data.payload);
640 if (inst_data.operand == operand_ref and operandDies(l, body[0], 0))
641 return .tomb;
642
643 if (cond_extra.data.then_body_len > 2 or cond_extra.data.else_body_len > 2)
644 return .complex;
645
646 const then_body: []const Air.Inst.Index = @ptrCast(air.extra.items[cond_extra.end..][0..cond_extra.data.then_body_len]);
647 const else_body: []const Air.Inst.Index = @ptrCast(air.extra.items[cond_extra.end + cond_extra.data.then_body_len ..][0..cond_extra.data.else_body_len]);
648 if (then_body.len > 1 and air_tags[@intFromEnum(then_body[1])] != .unreach)
649 return .complex;
650 if (else_body.len > 1 and air_tags[@intFromEnum(else_body[1])] != .unreach)
651 return .complex;
652
653 var operand_live: bool = true;
654 for (&[_]Air.Inst.Index{ then_body[0], else_body[0] }) |cond_inst| {
655 if (l.categorizeOperand(air, zcu, cond_inst, operand, ip) == .tomb)
656 operand_live = false;
657
658 switch (air_tags[@intFromEnum(cond_inst)]) {
659 .br => { // Breaks immediately back to block
660 const br = air_datas[@intFromEnum(cond_inst)].br;
661 if (br.block_inst != inst)
662 return .complex;
663 },
664 .call => {}, // Calls a noreturn function
665 else => return .complex,
666 }
667 }
668 return if (operand_live) .none else .tomb;
669 }
670
671 return .complex;
672 },
673
674 .@"try",
675 .try_cold,
676 .try_ptr,
677 .try_ptr_cold,
678 .loop,
679 .cond_br,
680 .switch_br,
681 .loop_switch_br,
682 => return .complex,
683
684 .wasm_memory_grow => {
685 const pl_op = air_datas[@intFromEnum(inst)].pl_op;
686 if (pl_op.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
687 return .none;
688 },
689 }
690}
691
692fn matchOperandSmallIndex(
693 l: Liveness,
694 inst: Air.Inst.Index,
695 operand: OperandInt,
696 default: OperandCategory,
697) OperandCategory {
698 if (operandDies(l, inst, operand)) {
699 return .tomb;
700 } else {
701 return default;
702 }
703}
704
705210/// Higher level API.
706211pub const CondBrSlices = struct {
707212 then_deaths: []const Air.Inst.Index,
src/Sema.zig+88-52
......@@ -1193,7 +1193,7 @@ fn analyzeBodyInner(
11931193 .elem_ptr => try sema.zirElemPtr(block, inst),
11941194 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
11951195 .elem_val => try sema.zirElemVal(block, inst),
1196 .elem_val_node => try sema.zirElemValNode(block, inst),
1196 .elem_ptr_load => try sema.zirElemPtrLoad(block, inst),
11971197 .elem_val_imm => try sema.zirElemValImm(block, inst),
11981198 .elem_type => try sema.zirElemType(block, inst),
11991199 .indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst),
......@@ -1211,8 +1211,8 @@ fn analyzeBodyInner(
12111211 .error_value => try sema.zirErrorValue(block, inst),
12121212 .field_ptr => try sema.zirFieldPtr(block, inst),
12131213 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
1214 .field_val => try sema.zirFieldVal(block, inst),
1215 .field_val_named => try sema.zirFieldValNamed(block, inst),
1214 .field_ptr_load => try sema.zirFieldPtrLoad(block, inst),
1215 .field_ptr_named_load => try sema.zirFieldPtrNamedLoad(block, inst),
12161216 .func => try sema.zirFunc(block, inst, false),
12171217 .func_inferred => try sema.zirFunc(block, inst, true),
12181218 .func_fancy => try sema.zirFuncFancy(block, inst),
......@@ -3756,9 +3756,9 @@ fn zirAllocExtended(
37563756 const pt = sema.pt;
37573757 const gpa = sema.gpa;
37583758 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
3759 const var_src = block.nodeOffset(extra.data.src_node);
37593760 const ty_src = block.src(.{ .node_offset_var_decl_ty = extra.data.src_node });
37603761 const align_src = block.src(.{ .node_offset_var_decl_align = extra.data.src_node });
3761 const init_src = block.src(.{ .node_offset_var_decl_init = extra.data.src_node });
37623762 const small: Zir.Inst.AllocExtended.Small = @bitCast(extended.small);
37633763
37643764 var extra_index: usize = extra.end;
......@@ -3777,7 +3777,7 @@ fn zirAllocExtended(
37773777
37783778 if (block.isComptime() or small.is_comptime) {
37793779 if (small.has_type) {
3780 return sema.analyzeComptimeAlloc(block, init_src, var_ty, alignment);
3780 return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment);
37813781 } else {
37823782 try sema.air_instructions.append(gpa, .{
37833783 .tag = .inferred_alloc_comptime,
......@@ -3792,7 +3792,7 @@ fn zirAllocExtended(
37923792 }
37933793
37943794 if (small.has_type and try var_ty.comptimeOnlySema(pt)) {
3795 return sema.analyzeComptimeAlloc(block, init_src, var_ty, alignment);
3795 return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment);
37963796 }
37973797
37983798 if (small.has_type) {
......@@ -3802,8 +3802,8 @@ fn zirAllocExtended(
38023802 const target = pt.zcu.getTarget();
38033803 try var_ty.resolveLayout(pt);
38043804 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
3805 const var_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node });
3806 return sema.fail(block, var_src, "local variable in naked function", .{});
3805 const store_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node });
3806 return sema.fail(block, store_src, "local variable in naked function", .{});
38073807 }
38083808 const ptr_type = try sema.pt.ptrTypeSema(.{
38093809 .child = var_ty.toIntern(),
......@@ -3842,9 +3842,9 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
38423842
38433843 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
38443844 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
3845 const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node });
3845 const var_src = block.nodeOffset(inst_data.src_node);
38463846 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
3847 return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none);
3847 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
38483848}
38493849
38503850fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -4254,11 +4254,11 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
42544254
42554255 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
42564256 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
4257 const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node });
4257 const var_src = block.nodeOffset(inst_data.src_node);
42584258
42594259 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
42604260 if (block.isComptime() or try var_ty.comptimeOnlySema(pt)) {
4261 return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none);
4261 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
42624262 }
42634263 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
42644264 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
......@@ -4284,14 +4284,14 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
42844284
42854285 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
42864286 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
4287 const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node });
4287 const var_src = block.nodeOffset(inst_data.src_node);
42884288 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
42894289 if (block.isComptime()) {
4290 return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none);
4290 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
42914291 }
42924292 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
4293 const var_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
4294 return sema.fail(block, var_src, "local variable in naked function", .{});
4293 const store_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
4294 return sema.fail(block, store_src, "local variable in naked function", .{});
42954295 }
42964296 try sema.validateVarType(block, ty_src, var_ty, false);
42974297 const target = pt.zcu.getTarget();
......@@ -9711,7 +9711,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
97119711 return block.addBitCast(dest_ty, operand);
97129712}
97139713
9714fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
9714fn zirFieldPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
97159715 const tracy = trace(@src());
97169716 defer tracy.end();
97179717
......@@ -9727,8 +9727,8 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
97279727 sema.code.nullTerminatedString(extra.field_name_start),
97289728 .no_embedded_nulls,
97299729 );
9730 const object = try sema.resolveInst(extra.lhs);
9731 return sema.fieldVal(block, src, object, field_name, field_name_src);
9730 const object_ptr = try sema.resolveInst(extra.lhs);
9731 return fieldPtrLoad(sema, block, src, object_ptr, field_name, field_name_src);
97329732}
97339733
97349734fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -9779,7 +9779,7 @@ fn zirStructInitFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
97799779 }
97809780}
97819781
9782fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
9782fn zirFieldPtrNamedLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
97839783 const tracy = trace(@src());
97849784 defer tracy.end();
97859785
......@@ -9787,9 +9787,9 @@ fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
97879787 const src = block.nodeOffset(inst_data.src_node);
97889788 const field_name_src = block.builtinCallArgSrc(inst_data.src_node, 1);
97899789 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
9790 const object = try sema.resolveInst(extra.lhs);
9790 const object_ptr = try sema.resolveInst(extra.lhs);
97919791 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name });
9792 return sema.fieldVal(block, src, object, field_name, field_name_src);
9792 return fieldPtrLoad(sema, block, src, object_ptr, field_name, field_name_src);
97939793}
97949794
97959795fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -10102,7 +10102,7 @@ fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1010210102 return sema.elemVal(block, src, array, elem_index, src, false);
1010310103}
1010410104
10105fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
10105fn zirElemPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1010610106 const tracy = trace(@src());
1010710107 defer tracy.end();
1010810108
......@@ -10110,10 +10110,18 @@ fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1011010110 const src = block.nodeOffset(inst_data.src_node);
1011110111 const elem_index_src = block.src(.{ .node_offset_array_access_index = inst_data.src_node });
1011210112 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
10113 const array = try sema.resolveInst(extra.lhs);
10113 const array_ptr = try sema.resolveInst(extra.lhs);
1011410114 const uncoerced_elem_index = try sema.resolveInst(extra.rhs);
10115 if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| {
10116 const array_ptr_ty = sema.typeOf(array_ptr);
10117 if (try sema.pointerDeref(block, src, array_ptr_val, array_ptr_ty)) |array_val| {
10118 const array: Air.Inst.Ref = .fromValue(array_val);
10119 return elemVal(sema, block, src, array, uncoerced_elem_index, elem_index_src, true);
10120 }
10121 }
1011510122 const elem_index = try sema.coerce(block, .usize, uncoerced_elem_index, elem_index_src);
10116 return sema.elemVal(block, src, array, elem_index, elem_index_src, true);
10123 const elem_ptr = try elemPtr(sema, block, src, array_ptr, elem_index, elem_index_src, false, true);
10124 return analyzeLoad(sema, block, src, elem_ptr, elem_index_src);
1011710125}
1011810126
1011910127fn zirElemValImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -13612,7 +13620,6 @@ fn maybeErrorUnwrap(
1361213620 .str,
1361313621 .as_node,
1361413622 .panic,
13615 .field_val,
1361613623 => {},
1361713624 else => return false,
1361813625 }
......@@ -13631,7 +13638,6 @@ fn maybeErrorUnwrap(
1363113638 },
1363213639 .str => try sema.zirStr(inst),
1363313640 .as_node => try sema.zirAsNode(block, inst),
13634 .field_val => try sema.zirFieldVal(block, inst),
1363513641 .@"unreachable" => {
1363613642 try safetyPanicUnwrapError(sema, block, operand_src, operand);
1363713643 return true;
......@@ -15996,7 +16002,6 @@ fn splat(sema: *Sema, ty: Type, val: Value) !Value {
1599616002fn analyzeArithmetic(
1599716003 sema: *Sema,
1599816004 block: *Block,
15999 /// TODO performance investigation: make this comptime?
1600016005 zir_tag: Zir.Inst.Tag,
1600116006 lhs: Air.Inst.Ref,
1600216007 rhs: Air.Inst.Ref,
......@@ -16195,6 +16200,11 @@ fn analyzePtrArithmetic(
1619516200 const ptr_info = ptr_ty.ptrInfo(zcu);
1619616201 assert(ptr_info.flags.size == .many or ptr_info.flags.size == .c);
1619716202
16203 if ((try sema.typeHasOnePossibleValue(.fromInterned(ptr_info.child))) != null) {
16204 // Offset will be multiplied by zero, so result is the same as the base pointer.
16205 return ptr;
16206 }
16207
1619816208 const new_ptr_ty = t: {
1619916209 // Calculate the new pointer alignment.
1620016210 // This code is duplicated in `Type.elemPtrType`.
......@@ -26673,6 +26683,33 @@ fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
2667326683 }
2667426684}
2667526685
26686fn fieldPtrLoad(
26687 sema: *Sema,
26688 block: *Block,
26689 src: LazySrcLoc,
26690 object_ptr: Air.Inst.Ref,
26691 field_name: InternPool.NullTerminatedString,
26692 field_name_src: LazySrcLoc,
26693) CompileError!Air.Inst.Ref {
26694 const pt = sema.pt;
26695 const zcu = pt.zcu;
26696 const object_ptr_ty = sema.typeOf(object_ptr);
26697 const pointee_ty = object_ptr_ty.childType(zcu);
26698 if (try typeHasOnePossibleValue(sema, pointee_ty)) |opv| {
26699 const object: Air.Inst.Ref = .fromValue(opv);
26700 return fieldVal(sema, block, src, object, field_name, field_name_src);
26701 }
26702
26703 if (try sema.resolveDefinedValue(block, src, object_ptr)) |object_ptr_val| {
26704 if (try sema.pointerDeref(block, src, object_ptr_val, object_ptr_ty)) |object_val| {
26705 const object: Air.Inst.Ref = .fromValue(object_val);
26706 return fieldVal(sema, block, src, object, field_name, field_name_src);
26707 }
26708 }
26709 const field_ptr = try sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
26710 return analyzeLoad(sema, block, src, field_ptr, field_name_src);
26711}
26712
2667626713fn fieldVal(
2667726714 sema: *Sema,
2667826715 block: *Block,
......@@ -26892,7 +26929,7 @@ fn fieldPtr(
2689226929 const ptr_info = object_ty.ptrInfo(zcu);
2689326930 const new_ptr_ty = try pt.ptrTypeSema(.{
2689426931 .child = Type.fromInterned(ptr_info.child).childType(zcu).toIntern(),
26895 .sentinel = if (object_ty.sentinel(zcu)) |s| s.toIntern() else .none,
26932 .sentinel = if (inner_ty.sentinel(zcu)) |s| s.toIntern() else .none,
2689626933 .flags = .{
2689726934 .size = .many,
2689826935 .alignment = ptr_info.flags.alignment,
......@@ -27420,15 +27457,9 @@ fn structFieldPtrByIndex(
2742027457
2742127458 if (struct_type.layout == .@"packed") {
2742227459 assert(!field_is_comptime);
27423 switch (struct_ty.packedStructFieldPtrInfo(struct_ptr_ty, field_index, pt)) {
27424 .bit_ptr => |packed_offset| {
27425 ptr_ty_data.flags.alignment = parent_align;
27426 ptr_ty_data.packed_offset = packed_offset;
27427 },
27428 .byte_ptr => |ptr_info| {
27429 ptr_ty_data.flags.alignment = ptr_info.alignment;
27430 },
27431 }
27460 const packed_offset = struct_ty.packedStructFieldPtrInfo(struct_ptr_ty, field_index, pt);
27461 ptr_ty_data.flags.alignment = parent_align;
27462 ptr_ty_data.packed_offset = packed_offset;
2743227463 } else if (struct_type.layout == .@"extern") {
2743327464 assert(!field_is_comptime);
2743427465 // For extern structs, field alignment might be bigger than type's
......@@ -27972,6 +28003,7 @@ fn elemVal(
2797228003 }
2797328004}
2797428005
28006/// Called when the index or indexable is runtime known.
2797528007fn validateRuntimeElemAccess(
2797628008 sema: *Sema,
2797728009 block: *Block,
......@@ -28236,6 +28268,10 @@ fn elemPtrArray(
2823628268 try sema.validateRuntimeValue(block, array_ptr_src, array_ptr);
2823728269 }
2823828270
28271 if (offset == null and array_ty.zigTypeTag(zcu) == .vector) {
28272 return sema.fail(block, elem_index_src, "vector index not comptime known", .{});
28273 }
28274
2823928275 // Runtime check is only needed if unable to comptime check.
2824028276 if (oob_safety and block.wantSafety() and offset == null) {
2824128277 const len_inst = try pt.intRef(.usize, array_len);
......@@ -30634,6 +30670,19 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul
3063430670 } };
3063530671 return false;
3063630672 }
30673
30674 if (inst_info.packed_offset.host_size != dest_info.packed_offset.host_size or
30675 inst_info.packed_offset.bit_offset != dest_info.packed_offset.bit_offset)
30676 {
30677 in_memory_result.* = .{ .ptr_bit_range = .{
30678 .actual_host = inst_info.packed_offset.host_size,
30679 .wanted_host = dest_info.packed_offset.host_size,
30680 .actual_offset = inst_info.packed_offset.bit_offset,
30681 .wanted_offset = dest_info.packed_offset.bit_offset,
30682 } };
30683 return false;
30684 }
30685
3063730686 return true;
3063830687}
3063930688
......@@ -31425,19 +31474,6 @@ fn analyzeLoad(
3142531474 }
3142631475 }
3142731476
31428 if (ptr_ty.ptrInfo(zcu).flags.vector_index == .runtime) {
31429 const ptr_inst = ptr.toIndex().?;
31430 const air_tags = sema.air_instructions.items(.tag);
31431 if (air_tags[@intFromEnum(ptr_inst)] == .ptr_elem_ptr) {
31432 const ty_pl = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].ty_pl;
31433 const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data;
31434 return block.addBinOp(.ptr_elem_val, bin_op.lhs, bin_op.rhs);
31435 }
31436 return sema.fail(block, ptr_src, "unable to determine vector element index of type '{f}'", .{
31437 ptr_ty.fmt(pt),
31438 });
31439 }
31440
3144131477 return block.addTyOp(.load, elem_ty, ptr);
3144231478}
3144331479
......@@ -34954,7 +34990,7 @@ fn resolveInferredErrorSet(
3495434990 const resolved_ty = func.resolvedErrorSetUnordered(ip);
3495534991 if (resolved_ty != .none) return resolved_ty;
3495634992
34957 if (zcu.analysis_in_progress.contains(AnalUnit.wrap(.{ .func = func_index }))) {
34993 if (zcu.analysis_in_progress.contains(.wrap(.{ .func = func_index }))) {
3495834994 return sema.fail(block, src, "unable to resolve inferred error set", .{});
3495934995 }
3496034996
src/Type.zig+9-32
......@@ -3514,22 +3514,17 @@ pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } {
35143514 return .{ cur_ty, cur_len };
35153515}
35163516
3517pub fn packedStructFieldPtrInfo(struct_ty: Type, parent_ptr_ty: Type, field_idx: u32, pt: Zcu.PerThread) union(enum) {
3518 /// The result is a bit-pointer with the same value and a new packed offset.
3519 bit_ptr: InternPool.Key.PtrType.PackedOffset,
3520 /// The result is a standard pointer.
3521 byte_ptr: struct {
3522 /// The byte offset of the field pointer from the parent pointer value.
3523 offset: u64,
3524 /// The alignment of the field pointer type.
3525 alignment: InternPool.Alignment,
3526 },
3527} {
3517/// Returns a bit-pointer with the same value and a new packed offset.
3518pub fn packedStructFieldPtrInfo(
3519 struct_ty: Type,
3520 parent_ptr_ty: Type,
3521 field_idx: u32,
3522 pt: Zcu.PerThread,
3523) InternPool.Key.PtrType.PackedOffset {
35283524 comptime assert(Type.packed_struct_layout_version == 2);
35293525
35303526 const zcu = pt.zcu;
35313527 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
3532 const field_ty = struct_ty.fieldType(field_idx, zcu);
35333528
35343529 var bit_offset: u16 = 0;
35353530 var running_bits: u16 = 0;
......@@ -3552,28 +3547,10 @@ pub fn packedStructFieldPtrInfo(struct_ty: Type, parent_ptr_ty: Type, field_idx:
35523547 bit_offset,
35533548 };
35543549
3555 // If the field happens to be byte-aligned, simplify the pointer type.
3556 // We can only do this if the pointee's bit size matches its ABI byte size,
3557 // so that loads and stores do not interfere with surrounding packed bits.
3558 //
3559 // TODO: we do not attempt this with big-endian targets yet because of nested
3560 // structs and floats. I need to double-check the desired behavior for big endian
3561 // targets before adding the necessary complications to this code. This will not
3562 // cause miscompilations; it only means the field pointer uses bit masking when it
3563 // might not be strictly necessary.
3564 if (res_bit_offset % 8 == 0 and field_ty.bitSize(zcu) == field_ty.abiSize(zcu) * 8 and zcu.getTarget().cpu.arch.endian() == .little) {
3565 const byte_offset = res_bit_offset / 8;
3566 const new_align = Alignment.fromLog2Units(@ctz(byte_offset | parent_ptr_ty.ptrAlignment(zcu).toByteUnits().?));
3567 return .{ .byte_ptr = .{
3568 .offset = byte_offset,
3569 .alignment = new_align,
3570 } };
3571 }
3572
3573 return .{ .bit_ptr = .{
3550 return .{
35743551 .host_size = res_host_size,
35753552 .bit_offset = res_bit_offset,
3576 } };
3553 };
35773554}
35783555
35793556pub fn resolveLayout(ty: Type, pt: Zcu.PerThread) SemaError!void {
src/Value.zig+22-30
......@@ -2149,15 +2149,18 @@ pub fn makeBool(x: bool) Value {
21492149 return if (x) .true else .false;
21502150}
21512151
2152/// `parent_ptr` must be a single-pointer to some optional.
2152/// `parent_ptr` must be a single-pointer or C pointer to some optional.
2153///
21532154/// Returns a pointer to the payload of the optional.
2155///
21542156/// May perform type resolution.
21552157pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
21562158 const zcu = pt.zcu;
21572159 const parent_ptr_ty = parent_ptr.typeOf(zcu);
21582160 const opt_ty = parent_ptr_ty.childType(zcu);
2161 const ptr_size = parent_ptr_ty.ptrSize(zcu);
21592162
2160 assert(parent_ptr_ty.ptrSize(zcu) == .one);
2163 assert(ptr_size == .one or ptr_size == .c);
21612164 assert(opt_ty.zigTypeTag(zcu) == .optional);
21622165
21632166 const result_ty = try pt.ptrTypeSema(info: {
......@@ -2212,9 +2215,12 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
22122215 } }));
22132216}
22142217
2215/// `parent_ptr` must be a single-pointer to a struct, union, or slice.
2218/// `parent_ptr` must be a single-pointer or c pointer to a struct, union, or slice.
2219///
22162220/// Returns a pointer to the aggregate field at the specified index.
2221///
22172222/// For slices, uses `slice_ptr_index` and `slice_len_index`.
2223///
22182224/// May perform type resolution.
22192225pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
22202226 const zcu = pt.zcu;
......@@ -2222,7 +2228,7 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
22222228 const aggregate_ty = parent_ptr_ty.childType(zcu);
22232229
22242230 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
2225 assert(parent_ptr_info.flags.size == .one);
2231 assert(parent_ptr_info.flags.size == .one or parent_ptr_info.flags.size == .c);
22262232
22272233 // Exiting this `switch` indicates that the `field` pointer representation should be used.
22282234 // `field_align` may be `.none` to represent the natural alignment of `field_ty`, but is not necessarily.
......@@ -2249,32 +2255,18 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
22492255 });
22502256 return parent_ptr.getOffsetPtr(byte_off, result_ty, pt);
22512257 },
2252 .@"packed" => switch (aggregate_ty.packedStructFieldPtrInfo(parent_ptr_ty, field_idx, pt)) {
2253 .bit_ptr => |packed_offset| {
2254 const result_ty = try pt.ptrType(info: {
2255 var new = parent_ptr_info;
2256 new.packed_offset = packed_offset;
2257 new.child = field_ty.toIntern();
2258 if (new.flags.alignment == .none) {
2259 new.flags.alignment = try aggregate_ty.abiAlignmentSema(pt);
2260 }
2261 break :info new;
2262 });
2263 return pt.getCoerced(parent_ptr, result_ty);
2264 },
2265 .byte_ptr => |ptr_info| {
2266 const result_ty = try pt.ptrTypeSema(info: {
2267 var new = parent_ptr_info;
2268 new.child = field_ty.toIntern();
2269 new.packed_offset = .{
2270 .host_size = 0,
2271 .bit_offset = 0,
2272 };
2273 new.flags.alignment = ptr_info.alignment;
2274 break :info new;
2275 });
2276 return parent_ptr.getOffsetPtr(ptr_info.offset, result_ty, pt);
2277 },
2258 .@"packed" => {
2259 const packed_offset = aggregate_ty.packedStructFieldPtrInfo(parent_ptr_ty, field_idx, pt);
2260 const result_ty = try pt.ptrType(info: {
2261 var new = parent_ptr_info;
2262 new.packed_offset = packed_offset;
2263 new.child = field_ty.toIntern();
2264 if (new.flags.alignment == .none) {
2265 new.flags.alignment = try aggregate_ty.abiAlignmentSema(pt);
2266 }
2267 break :info new;
2268 });
2269 return pt.getCoerced(parent_ptr, result_ty);
22782270 },
22792271 }
22802272 },
src/Zcu/PerThread.zig+24-8
......@@ -700,7 +700,7 @@ fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage)
700700
701701 const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
702702
703 try zcu.analysis_in_progress.put(gpa, unit, {});
703 try zcu.analysis_in_progress.putNoClobber(gpa, unit, {});
704704 defer assert(zcu.analysis_in_progress.swapRemove(unit));
705705
706706 // Before we begin, collect:
......@@ -864,7 +864,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
864864 const file = zcu.fileByIndex(inst_resolved.file);
865865 const zir = file.zir.?;
866866
867 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
867 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});
868868 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
869869
870870 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
......@@ -958,6 +958,8 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
958958
959959 log.debug("ensureNavValUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
960960
961 assert(!zcu.analysis_in_progress.contains(anal_unit));
962
961963 // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the
962964 // status is `.unresolved`, which indicates that the value is outdated because it has *never*
963965 // been analyzed so far.
......@@ -1090,10 +1092,19 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
10901092 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
10911093 const file = zcu.fileByIndex(inst_resolved.file);
10921094 const zir = file.zir.?;
1095 const zir_decl = zir.getDeclaration(inst_resolved.inst);
10931096
1094 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1097 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});
10951098 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
10961099
1100 // If there's no type body, we are also resolving the type here.
1101 if (zir_decl.type_body == null) {
1102 try zcu.analysis_in_progress.putNoClobber(gpa, .wrap(.{ .nav_ty = nav_id }), {});
1103 }
1104 errdefer if (zir_decl.type_body == null) {
1105 _ = zcu.analysis_in_progress.swapRemove(.wrap(.{ .nav_ty = nav_id }));
1106 };
1107
10971108 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
10981109 defer analysis_arena.deinit();
10991110
......@@ -1133,8 +1144,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
11331144 };
11341145 defer block.instructions.deinit(gpa);
11351146
1136 const zir_decl = zir.getDeclaration(inst_resolved.inst);
1137
11381147 const ty_src = block.src(.{ .node_offset_var_decl_ty = .zero });
11391148 const init_src = block.src(.{ .node_offset_var_decl_init = .zero });
11401149 const align_src = block.src(.{ .node_offset_var_decl_align = .zero });
......@@ -1305,6 +1314,9 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
13051314
13061315 // Mark the unit as completed before evaluating the export!
13071316 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1317 if (zir_decl.type_body == null) {
1318 assert(zcu.analysis_in_progress.swapRemove(.wrap(.{ .nav_ty = nav_id })));
1319 }
13081320
13091321 if (zir_decl.linkage == .@"export") {
13101322 const export_src = block.src(.{ .token_offset = @enumFromInt(@intFromBool(zir_decl.is_pub)) });
......@@ -1347,6 +1359,8 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
13471359
13481360 log.debug("ensureNavTypeUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
13491361
1362 assert(!zcu.analysis_in_progress.contains(anal_unit));
1363
13501364 const type_resolved_by_value: bool = from_val: {
13511365 const analysis = nav.analysis orelse break :from_val false;
13521366 const inst_resolved = analysis.zir_index.resolveFull(ip) orelse break :from_val false;
......@@ -1463,8 +1477,8 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
14631477 const file = zcu.fileByIndex(inst_resolved.file);
14641478 const zir = file.zir.?;
14651479
1466 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1467 defer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
1480 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});
1481 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
14681482
14691483 const zir_decl = zir.getDeclaration(inst_resolved.inst);
14701484 const type_body = zir_decl.type_body.?;
......@@ -1587,6 +1601,8 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z
15871601
15881602 log.debug("ensureFuncBodyUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
15891603
1604 assert(!zcu.analysis_in_progress.contains(anal_unit));
1605
15901606 const func = zcu.funcInfo(func_index);
15911607
15921608 assert(func.ty == func.uncoerced_ty); // analyze the body of the original function, not a coerced one
......@@ -2781,7 +2797,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
27812797 const file = zcu.fileByIndex(inst_info.file);
27822798 const zir = file.zir.?;
27832799
2784 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
2800 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});
27852801 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
27862802
27872803 func.setAnalyzed(ip);
src/arch/x86_64/CodeGen.zig+348-351
......@@ -2291,7 +2291,7 @@ fn genBodyBlock(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
22912291}
22922292
22932293fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2294 @setEvalBranchQuota(29_400);
2294 @setEvalBranchQuota(29_500);
22952295 const pt = cg.pt;
22962296 const zcu = pt.zcu;
22972297 const ip = &zcu.intern_pool;
......@@ -86774,52 +86774,313 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
8677486774 const is_non_err = try cg.tempInit(.bool, .{ .eflags = .e });
8677586775 try is_non_err.finish(inst, &.{un_op}, &ops, cg);
8677686776 },
86777 .load => fallback: {
86777 .load => {
8677886778 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
8677986779 const val_ty = ty_op.ty.toType();
86780 const ptr_ty = cg.typeOf(ty_op.operand);
86781 const ptr_info = ptr_ty.ptrInfo(zcu);
86782 if (ptr_info.packed_offset.host_size > 0 and
86783 (ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type))
86784 break :fallback try cg.airLoad(inst);
8678586780 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
86786 const res = try ops[0].load(val_ty, .{
86787 .disp = switch (ptr_info.flags.vector_index) {
86788 .none => 0,
86789 .runtime => unreachable,
86790 else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)),
86781 var res: [1]Temp = undefined;
86782 cg.select(&res, &.{val_ty}, &ops, comptime &.{ .{
86783 .src_constraints = .{ .{ .ptr_bool_vec_elem = .byte }, .any, .any },
86784 .patterns = &.{
86785 .{ .src = .{ .to_gpr, .none, .none } },
8679186786 },
86792 }, cg);
86793 try res.finish(inst, &.{ty_op.operand}, &ops, cg);
86787 .extra_temps = .{
86788 .{ .type = .u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .general_purpose } } },
86789 .unused,
86790 .unused,
86791 .unused,
86792 .unused,
86793 .unused,
86794 .unused,
86795 .unused,
86796 .unused,
86797 .unused,
86798 .unused,
86799 },
86800 .dst_temps = .{ .{ .cc = .c }, .unused },
86801 .clobbers = .{ .eflags = true },
86802 .each = .{ .once = &.{
86803 .{ ._, ._, .movzx, .tmp0d, .lea(.src0b), ._, ._ },
86804 .{ ._, ._, .bt, .tmp0d, .ua(.src0, .add_vector_index), ._, ._ },
86805 } },
86806 }, .{
86807 .src_constraints = .{ .{ .ptr_bool_vec_elem = .word }, .any, .any },
86808 .patterns = &.{
86809 .{ .src = .{ .to_gpr, .none, .none } },
86810 },
86811 .dst_temps = .{ .{ .cc = .c }, .unused },
86812 .clobbers = .{ .eflags = true },
86813 .each = .{ .once = &.{
86814 .{ ._, ._, .bt, .lea(.src0w), .ua(.src0, .add_vector_index), ._, ._ },
86815 } },
86816 }, .{
86817 .src_constraints = .{ .ptr_any_bool_vec_elem, .any, .any },
86818 .patterns = &.{
86819 .{ .src = .{ .to_gpr, .none, .none } },
86820 },
86821 .dst_temps = .{ .{ .cc = .c }, .unused },
86822 .clobbers = .{ .eflags = true },
86823 .each = .{ .once = &.{
86824 .{ ._, ._, .bt, .leaa(.src0d, .add_vector_index_div_8_down_4), .ua(.src0, .add_vector_index_rem_32), ._, ._ },
86825 } },
86826 } }) catch |err| switch (err) {
86827 error.SelectFailed => res[0] = try ops[0].load(val_ty, .{
86828 .disp = switch (cg.typeOf(ty_op.operand).ptrInfo(zcu).flags.vector_index) {
86829 .none => 0,
86830 .runtime => unreachable,
86831 else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)),
86832 },
86833 }, cg),
86834 else => |e| return e,
86835 };
86836 try res[0].finish(inst, &.{ty_op.operand}, &ops, cg);
8679486837 },
8679586838 .ret => try cg.airRet(inst, false),
8679686839 .ret_safe => try cg.airRet(inst, true),
8679786840 .ret_load => try cg.airRetLoad(inst),
86798 .store, .store_safe => |air_tag| fallback: {
86841 .store, .store_safe => |air_tag| {
8679986842 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
86800 const ptr_ty = cg.typeOf(bin_op.lhs);
86801 const ptr_info = ptr_ty.ptrInfo(zcu);
86802 const val_ty = cg.typeOf(bin_op.rhs);
86803 if (ptr_info.packed_offset.host_size > 0 and
86804 (ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type))
86805 break :fallback try cg.airStore(inst, switch (air_tag) {
86806 else => unreachable,
86807 .store => false,
86808 .store_safe => true,
86809 });
8681086843 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
86811 try ops[0].store(&ops[1], .{
86812 .disp = switch (ptr_info.flags.vector_index) {
86813 .none => 0,
86814 .runtime => unreachable,
86815 else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)),
86844 cg.select(&.{}, &.{}, &ops, comptime &.{ .{
86845 .src_constraints = .{ .{ .ptr_bool_vec_elem = .byte }, .bool, .any },
86846 .patterns = &.{
86847 .{ .src = .{ .to_gpr, .{ .imm = 0 }, .none } },
8681686848 },
86817 .safe = switch (air_tag) {
86818 else => unreachable,
86819 .store => false,
86820 .store_safe => true,
86849 .extra_temps = .{
86850 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
86851 .unused,
86852 .unused,
86853 .unused,
86854 .unused,
86855 .unused,
86856 .unused,
86857 .unused,
86858 .unused,
86859 .unused,
86860 .unused,
8682186861 },
86822 }, cg);
86862 .clobbers = .{ .eflags = true },
86863 .each = .{ .once = &.{
86864 .{ ._, ._, .movzx, .tmp0d, .lea(.src0b), ._, ._ },
86865 .{ ._, ._r, .bt, .tmp0d, .ua(.src0, .add_vector_index), ._, ._ },
86866 .{ ._, ._, .mov, .lea(.src0b), .tmp0b, ._, ._ },
86867 } },
86868 }, .{
86869 .src_constraints = .{ .{ .ptr_bool_vec_elem = .byte }, .bool, .any },
86870 .patterns = &.{
86871 .{ .src = .{ .to_gpr, .{ .imm = 1 }, .none } },
86872 },
86873 .extra_temps = .{
86874 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
86875 .unused,
86876 .unused,
86877 .unused,
86878 .unused,
86879 .unused,
86880 .unused,
86881 .unused,
86882 .unused,
86883 .unused,
86884 .unused,
86885 },
86886 .clobbers = .{ .eflags = true },
86887 .each = .{ .once = &.{
86888 .{ ._, ._, .movzx, .tmp0d, .lea(.src0b), ._, ._ },
86889 .{ ._, ._s, .bt, .tmp0d, .ua(.src0, .add_vector_index), ._, ._ },
86890 .{ ._, ._, .mov, .lea(.src0b), .tmp0b, ._, ._ },
86891 } },
86892 }, .{
86893 .required_features = .{ .cmov, null, null, null },
86894 .src_constraints = .{ .{ .ptr_bool_vec_elem = .byte }, .bool, .any },
86895 .patterns = &.{
86896 .{ .src = .{ .to_gpr, .to_gpr, .none } },
86897 },
86898 .extra_temps = .{
86899 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
86900 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
86901 .unused,
86902 .unused,
86903 .unused,
86904 .unused,
86905 .unused,
86906 .unused,
86907 .unused,
86908 .unused,
86909 .unused,
86910 },
86911 .clobbers = .{ .eflags = true },
86912 .each = .{ .once = &.{
86913 .{ ._, ._, .movzx, .tmp0d, .lea(.src0b), ._, ._ },
86914 .{ ._, ._, .mov, .tmp1d, .tmp0d, ._, ._ },
86915 .{ ._, ._r, .bt, .tmp1d, .ua(.src0, .add_vector_index), ._, ._ },
86916 .{ ._, ._s, .bt, .tmp0d, .ua(.src0, .add_vector_index), ._, ._ },
86917 .{ ._, ._, .@"test", .src1b, .si(1), ._, ._ },
86918 .{ ._, ._z, .cmov, .tmp0d, .tmp1d, ._, ._ },
86919 .{ ._, ._, .mov, .lea(.src0b), .tmp0b, ._, ._ },
86920 } },
86921 }, .{
86922 .src_constraints = .{ .{ .ptr_bool_vec_elem = .byte }, .bool, .any },
86923 .patterns = &.{
86924 .{ .src = .{ .to_gpr, .to_gpr, .none } },
86925 },
86926 .extra_temps = .{
86927 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
86928 .unused,
86929 .unused,
86930 .unused,
86931 .unused,
86932 .unused,
86933 .unused,
86934 .unused,
86935 .unused,
86936 .unused,
86937 .unused,
86938 },
86939 .clobbers = .{ .eflags = true },
86940 .each = .{ .once = &.{
86941 .{ ._, ._, .movzx, .tmp0d, .lea(.src0b), ._, ._ },
86942 .{ ._, ._, .@"test", .src1b, .si(1), ._, ._ },
86943 .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
86944 .{ ._, ._r, .bt, .tmp0d, .ua(.src0, .add_vector_index), ._, ._ },
86945 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
86946 .{ .@"0:", ._s, .bt, .tmp0d, .ua(.src0, .add_vector_index), ._, ._ },
86947 .{ .@"1:", ._, .mov, .lea(.src0b), .tmp0b, ._, ._ },
86948 } },
86949 }, .{
86950 .src_constraints = .{ .{ .ptr_bool_vec_elem = .word }, .bool, .any },
86951 .patterns = &.{
86952 .{ .src = .{ .to_gpr, .{ .imm = 0 }, .none } },
86953 },
86954 .clobbers = .{ .eflags = true },
86955 .each = .{ .once = &.{
86956 .{ ._, ._r, .bt, .lea(.src0w), .ua(.src0, .add_vector_index), ._, ._ },
86957 } },
86958 }, .{
86959 .src_constraints = .{ .{ .ptr_bool_vec_elem = .word }, .bool, .any },
86960 .patterns = &.{
86961 .{ .src = .{ .to_gpr, .{ .imm = 1 }, .none } },
86962 },
86963 .clobbers = .{ .eflags = true },
86964 .each = .{ .once = &.{
86965 .{ ._, ._s, .bt, .lea(.src0w), .ua(.src0, .add_vector_index), ._, ._ },
86966 } },
86967 }, .{
86968 .required_features = .{ .cmov, null, null, null },
86969 .src_constraints = .{ .{ .ptr_bool_vec_elem = .word }, .bool, .any },
86970 .patterns = &.{
86971 .{ .src = .{ .to_gpr, .to_gpr, .none } },
86972 },
86973 .extra_temps = .{
86974 .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
86975 .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
86976 .unused,
86977 .unused,
86978 .unused,
86979 .unused,
86980 .unused,
86981 .unused,
86982 .unused,
86983 .unused,
86984 .unused,
86985 },
86986 .clobbers = .{ .eflags = true },
86987 .each = .{ .once = &.{
86988 .{ ._, ._, .movzx, .tmp0d, .lea(.src0w), ._, ._ },
86989 .{ ._, ._, .mov, .tmp1d, .tmp0d, ._, ._ },
86990 .{ ._, ._r, .bt, .tmp1d, .ua(.src0, .add_vector_index), ._, ._ },
86991 .{ ._, ._s, .bt, .tmp0d, .ua(.src0, .add_vector_index), ._, ._ },
86992 .{ ._, ._, .@"test", .src1b, .si(1), ._, ._ },
86993 .{ ._, ._z, .cmov, .tmp0d, .tmp1d, ._, ._ },
86994 .{ ._, ._, .mov, .lea(.src0w), .tmp0w, ._, ._ },
86995 } },
86996 }, .{
86997 .src_constraints = .{ .{ .ptr_bool_vec_elem = .word }, .bool, .any },
86998 .patterns = &.{
86999 .{ .src = .{ .to_gpr, .to_gpr, .none } },
87000 },
87001 .clobbers = .{ .eflags = true },
87002 .each = .{ .once = &.{
87003 .{ ._, ._, .@"test", .src1b, .si(1), ._, ._ },
87004 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
87005 .{ ._, ._r, .bt, .lea(.src0w), .ua(.src0, .add_vector_index), ._, ._ },
87006 .{ ._, ._mp, .j, .@"0f", ._, ._, ._ },
87007 .{ .@"1:", ._s, .bt, .lea(.src0w), .ua(.src0, .add_vector_index), ._, ._ },
87008 } },
87009 }, .{
87010 .src_constraints = .{ .ptr_any_bool_vec_elem, .bool, .any },
87011 .patterns = &.{
87012 .{ .src = .{ .to_gpr, .{ .imm = 0 }, .none } },
87013 },
87014 .clobbers = .{ .eflags = true },
87015 .each = .{ .once = &.{
87016 .{ ._, ._r, .bt, .leaa(.src0d, .add_vector_index_div_8_down_4), .ua(.src0, .add_vector_index_rem_32), ._, ._ },
87017 } },
87018 }, .{
87019 .src_constraints = .{ .ptr_any_bool_vec_elem, .bool, .any },
87020 .patterns = &.{
87021 .{ .src = .{ .to_gpr, .{ .imm = 1 }, .none } },
87022 },
87023 .clobbers = .{ .eflags = true },
87024 .each = .{ .once = &.{
87025 .{ ._, ._s, .bt, .leaa(.src0d, .add_vector_index_div_8_down_4), .ua(.src0, .add_vector_index_rem_32), ._, ._ },
87026 } },
87027 }, .{
87028 .required_features = .{ .cmov, null, null, null },
87029 .src_constraints = .{ .ptr_any_bool_vec_elem, .bool, .any },
87030 .patterns = &.{
87031 .{ .src = .{ .to_gpr, .to_gpr, .none } },
87032 },
87033 .extra_temps = .{
87034 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
87035 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
87036 .unused,
87037 .unused,
87038 .unused,
87039 .unused,
87040 .unused,
87041 .unused,
87042 .unused,
87043 .unused,
87044 .unused,
87045 },
87046 .clobbers = .{ .eflags = true },
87047 .each = .{ .once = &.{
87048 .{ ._, ._, .mov, .tmp0d, .leaa(.src0d, .add_vector_index_div_8_down_4), ._, ._ },
87049 .{ ._, ._, .mov, .tmp1d, .tmp0d, ._, ._ },
87050 .{ ._, ._r, .bt, .tmp1d, .ua(.src0, .add_vector_index_rem_32), ._, ._ },
87051 .{ ._, ._s, .bt, .tmp0d, .ua(.src0, .add_vector_index_rem_32), ._, ._ },
87052 .{ ._, ._, .@"test", .src1b, .si(1), ._, ._ },
87053 .{ ._, ._z, .cmov, .tmp0d, .tmp1d, ._, ._ },
87054 .{ ._, ._, .mov, .leaa(.src0d, .add_vector_index_div_8_down_4), .tmp0d, ._, ._ },
87055 } },
87056 }, .{
87057 .src_constraints = .{ .ptr_any_bool_vec_elem, .bool, .any },
87058 .patterns = &.{
87059 .{ .src = .{ .to_gpr, .to_gpr, .none } },
87060 },
87061 .clobbers = .{ .eflags = true },
87062 .each = .{ .once = &.{
87063 .{ ._, ._, .@"test", .src1b, .si(1), ._, ._ },
87064 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
87065 .{ ._, ._r, .bt, .leaa(.src0d, .add_vector_index_div_8_down_4), .ua(.src0, .add_vector_index_rem_32), ._, ._ },
87066 .{ ._, ._mp, .j, .@"0f", ._, ._, ._ },
87067 .{ .@"1:", ._s, .bt, .leaa(.src0d, .add_vector_index_div_8_down_4), .ua(.src0, .add_vector_index_rem_32), ._, ._ },
87068 } },
87069 } }) catch |err| switch (err) {
87070 error.SelectFailed => try ops[0].store(&ops[1], .{
87071 .disp = switch (cg.typeOf(bin_op.lhs).ptrInfo(zcu).flags.vector_index) {
87072 .none => 0,
87073 .runtime => unreachable,
87074 else => |vector_index| @intCast(cg.typeOf(bin_op.rhs).abiSize(zcu) * @intFromEnum(vector_index)),
87075 },
87076 .safe = switch (air_tag) {
87077 else => unreachable,
87078 .store => false,
87079 .store_safe => true,
87080 },
87081 }, cg),
87082 else => |e| return e,
87083 };
8682387084 for (ops) |op| try op.die(cg);
8682487085 },
8682587086 .unreach => {},
......@@ -100863,7 +101124,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100863101124 .dst_temps = .{ .{ .cc = .c }, .unused },
100864101125 .clobbers = .{ .eflags = true },
100865101126 .each = .{ .once = &.{
100866 .{ ._, ._, .bt, .src0d, .ua(.none, .add_src1_rem_32), ._, ._ },
101127 .{ ._, ._, .bt, .src0d, .ua(.none, .add_src1), ._, ._ },
100867101128 } },
100868101129 }, .{
100869101130 .src_constraints = .{ .{ .bool_vec = .dword }, .any, .any },
......@@ -100884,7 +101145,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100884101145 .dst_temps = .{ .{ .cc = .c }, .unused },
100885101146 .clobbers = .{ .eflags = true },
100886101147 .each = .{ .once = &.{
100887 .{ ._, ._, .bt, .src0q, .ua(.none, .add_src1_rem_64), ._, ._ },
101148 .{ ._, ._, .bt, .src0q, .ua(.none, .add_src1), ._, ._ },
100888101149 } },
100889101150 }, .{
100890101151 .required_features = .{ .@"64bit", null, null, null },
......@@ -174481,114 +174742,6 @@ fn reuseOperandAdvanced(
174481174742 return true;
174482174743}
174483174744
174484fn packedLoad(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void {
174485 const pt = self.pt;
174486 const zcu = pt.zcu;
174487
174488 const ptr_info = ptr_ty.ptrInfo(zcu);
174489 const val_ty: Type = .fromInterned(ptr_info.child);
174490 if (!val_ty.hasRuntimeBitsIgnoreComptime(zcu)) return;
174491 const val_abi_size: u32 = @intCast(val_ty.abiSize(zcu));
174492
174493 const val_bit_size: u32 = @intCast(val_ty.bitSize(zcu));
174494 const ptr_bit_off = ptr_info.packed_offset.bit_offset + switch (ptr_info.flags.vector_index) {
174495 .none => 0,
174496 .runtime => unreachable,
174497 else => |vector_index| @intFromEnum(vector_index) * val_bit_size,
174498 };
174499 if (ptr_bit_off % 8 == 0) {
174500 {
174501 const mat_ptr_mcv: MCValue = switch (ptr_mcv) {
174502 .immediate, .register, .register_offset, .lea_frame => ptr_mcv,
174503 else => .{ .register = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
174504 };
174505 const mat_ptr_lock = switch (mat_ptr_mcv) {
174506 .register => |mat_ptr_reg| self.register_manager.lockReg(mat_ptr_reg),
174507 else => null,
174508 };
174509 defer if (mat_ptr_lock) |lock| self.register_manager.unlockReg(lock);
174510
174511 try self.load(dst_mcv, ptr_ty, mat_ptr_mcv.offset(@intCast(@divExact(ptr_bit_off, 8))));
174512 }
174513
174514 if (val_abi_size * 8 > val_bit_size) {
174515 if (dst_mcv.isRegister()) {
174516 try self.truncateRegister(val_ty, dst_mcv.getReg().?);
174517 } else {
174518 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
174519 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
174520 defer self.register_manager.unlockReg(tmp_lock);
174521
174522 const hi_mcv = dst_mcv.address().offset(@intCast(val_bit_size / 64 * 8)).deref();
174523 try self.genSetReg(tmp_reg, .usize, hi_mcv, .{});
174524 try self.truncateRegister(val_ty, tmp_reg);
174525 try self.genCopy(.usize, hi_mcv, .{ .register = tmp_reg }, .{});
174526 }
174527 }
174528 return;
174529 }
174530
174531 if (val_abi_size > 8) return self.fail("TODO implement packed load of {f}", .{val_ty.fmt(pt)});
174532
174533 const limb_abi_size: u31 = @min(val_abi_size, 8);
174534 const limb_abi_bits = limb_abi_size * 8;
174535 const val_byte_off: i32 = @intCast(ptr_bit_off / limb_abi_bits * limb_abi_size);
174536 const val_bit_off = ptr_bit_off % limb_abi_bits;
174537 const val_extra_bits = self.regExtraBits(val_ty);
174538
174539 const ptr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
174540 const ptr_lock = self.register_manager.lockRegAssumeUnused(ptr_reg);
174541 defer self.register_manager.unlockReg(ptr_lock);
174542
174543 const dst_reg = switch (dst_mcv) {
174544 .register => |reg| reg,
174545 else => try self.register_manager.allocReg(null, abi.RegisterClass.gp),
174546 };
174547 const dst_lock = self.register_manager.lockReg(dst_reg);
174548 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
174549
174550 const load_abi_size =
174551 if (val_bit_off < val_extra_bits) val_abi_size else val_abi_size * 2;
174552 if (load_abi_size <= 8) {
174553 const load_reg = registerAlias(dst_reg, load_abi_size);
174554 try self.asmRegisterMemory(.{ ._, .mov }, load_reg, .{
174555 .base = .{ .reg = ptr_reg },
174556 .mod = .{ .rm = .{
174557 .size = .fromSize(load_abi_size),
174558 .disp = val_byte_off,
174559 } },
174560 });
174561 try self.spillEflagsIfOccupied();
174562 try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, .u(val_bit_off));
174563 } else {
174564 const tmp_reg =
174565 registerAlias(try self.register_manager.allocReg(null, abi.RegisterClass.gp), val_abi_size);
174566 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
174567 defer self.register_manager.unlockReg(tmp_lock);
174568
174569 const dst_alias = registerAlias(dst_reg, val_abi_size);
174570 try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{
174571 .base = .{ .reg = ptr_reg },
174572 .mod = .{ .rm = .{
174573 .size = .fromSize(val_abi_size),
174574 .disp = val_byte_off,
174575 } },
174576 });
174577 try self.asmRegisterMemory(.{ ._, .mov }, tmp_reg, .{
174578 .base = .{ .reg = ptr_reg },
174579 .mod = .{ .rm = .{
174580 .size = .fromSize(val_abi_size),
174581 .disp = val_byte_off + limb_abi_size,
174582 } },
174583 });
174584 try self.spillEflagsIfOccupied();
174585 try self.asmRegisterRegisterImmediate(.{ ._rd, .sh }, dst_alias, tmp_reg, .u(val_bit_off));
174586 }
174587
174588 if (val_extra_bits > 0) try self.truncateRegister(val_ty, dst_reg);
174589 try self.genCopy(val_ty, dst_mcv, .{ .register = dst_reg }, .{});
174590}
174591
174592174745fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void {
174593174746 const pt = self.pt;
174594174747 const zcu = pt.zcu;
......@@ -174636,174 +174789,6 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
174636174789 }
174637174790}
174638174791
174639fn airLoad(self: *CodeGen, inst: Air.Inst.Index) !void {
174640 const pt = self.pt;
174641 const zcu = pt.zcu;
174642 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
174643 const elem_ty = self.typeOfIndex(inst);
174644 const result: MCValue = result: {
174645 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
174646
174647 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
174648 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
174649 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
174650
174651 const ptr_ty = self.typeOf(ty_op.operand);
174652 const elem_size = elem_ty.abiSize(zcu);
174653
174654 const elem_rs = self.regSetForType(elem_ty);
174655 const ptr_rs = self.regSetForType(ptr_ty);
174656
174657 const ptr_mcv = try self.resolveInst(ty_op.operand);
174658 const dst_mcv = if (elem_size <= 8 and std.math.isPowerOfTwo(elem_size) and
174659 elem_rs.supersetOf(ptr_rs) and self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv))
174660 // The MCValue that holds the pointer can be re-used as the value.
174661 ptr_mcv
174662 else
174663 try self.allocRegOrMem(inst, true);
174664
174665 const ptr_info = ptr_ty.ptrInfo(zcu);
174666 if (ptr_info.flags.vector_index != .none or ptr_info.packed_offset.host_size > 0) {
174667 try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv);
174668 } else {
174669 try self.load(dst_mcv, ptr_ty, ptr_mcv);
174670 }
174671
174672 if (elem_ty.isAbiInt(zcu) and elem_size * 8 > elem_ty.bitSize(zcu)) {
174673 const high_mcv: MCValue = switch (dst_mcv) {
174674 .register => |dst_reg| .{ .register = dst_reg },
174675 .register_pair => |dst_regs| .{ .register = dst_regs[1] },
174676 else => dst_mcv.address().offset(@intCast((elem_size - 1) / 8 * 8)).deref(),
174677 };
174678 const high_reg = if (high_mcv.isRegister())
174679 high_mcv.getReg().?
174680 else
174681 try self.copyToTmpRegister(.usize, high_mcv);
174682 const high_lock = self.register_manager.lockReg(high_reg);
174683 defer if (high_lock) |lock| self.register_manager.unlockReg(lock);
174684
174685 try self.truncateRegister(elem_ty, high_reg);
174686 if (!high_mcv.isRegister()) try self.genCopy(
174687 if (elem_size <= 8) elem_ty else .usize,
174688 high_mcv,
174689 .{ .register = high_reg },
174690 .{},
174691 );
174692 }
174693 break :result dst_mcv;
174694 };
174695 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
174696}
174697
174698fn packedStore(self: *CodeGen, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void {
174699 const pt = self.pt;
174700 const zcu = pt.zcu;
174701 const ptr_info = ptr_ty.ptrInfo(zcu);
174702 const src_ty: Type = .fromInterned(ptr_info.child);
174703 if (!src_ty.hasRuntimeBitsIgnoreComptime(zcu)) return;
174704
174705 const limb_abi_size: u16 = @min(ptr_info.packed_offset.host_size, 8);
174706 const limb_abi_bits = limb_abi_size * 8;
174707 const limb_ty = try pt.intType(.unsigned, limb_abi_bits);
174708
174709 const src_bit_size = src_ty.bitSize(zcu);
174710 const ptr_bit_off = ptr_info.packed_offset.bit_offset + switch (ptr_info.flags.vector_index) {
174711 .none => 0,
174712 .runtime => unreachable,
174713 else => |vector_index| @intFromEnum(vector_index) * src_bit_size,
174714 };
174715 const src_byte_off: i32 = @intCast(ptr_bit_off / limb_abi_bits * limb_abi_size);
174716 const src_bit_off = ptr_bit_off % limb_abi_bits;
174717
174718 const ptr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
174719 const ptr_lock = self.register_manager.lockRegAssumeUnused(ptr_reg);
174720 defer self.register_manager.unlockReg(ptr_lock);
174721
174722 const mat_src_mcv: MCValue = mat_src_mcv: switch (src_mcv) {
174723 .register => if (src_bit_size > 64) {
174724 const frame_index = try self.allocFrameIndex(.initSpill(src_ty, self.pt.zcu));
174725 try self.genSetMem(.{ .frame = frame_index }, 0, src_ty, src_mcv, .{});
174726 break :mat_src_mcv .{ .load_frame = .{ .index = frame_index } };
174727 } else src_mcv,
174728 else => src_mcv,
174729 };
174730
174731 var limb_i: u16 = 0;
174732 while (limb_i * limb_abi_bits < src_bit_off + src_bit_size) : (limb_i += 1) {
174733 const part_bit_off = if (limb_i == 0) src_bit_off else 0;
174734 const part_bit_size =
174735 @min(src_bit_off + src_bit_size - limb_i * limb_abi_bits, limb_abi_bits) - part_bit_off;
174736 const limb_mem: Memory = .{
174737 .base = .{ .reg = ptr_reg },
174738 .mod = .{ .rm = .{
174739 .size = .fromSize(limb_abi_size),
174740 .disp = src_byte_off + limb_i * limb_abi_size,
174741 } },
174742 };
174743
174744 const part_mask = (@as(u64, std.math.maxInt(u64)) >> @intCast(64 - part_bit_size)) <<
174745 @intCast(part_bit_off);
174746 const part_mask_not = part_mask ^ (@as(u64, std.math.maxInt(u64)) >> @intCast(64 - limb_abi_bits));
174747 if (limb_abi_size <= 4) {
174748 try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, .u(part_mask_not));
174749 } else if (std.math.cast(i32, @as(i64, @bitCast(part_mask_not)))) |small| {
174750 try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, .s(small));
174751 } else {
174752 const part_mask_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
174753 try self.asmRegisterImmediate(.{ ._, .mov }, part_mask_reg, .u(part_mask_not));
174754 try self.asmMemoryRegister(.{ ._, .@"and" }, limb_mem, part_mask_reg);
174755 }
174756
174757 if (src_bit_size <= 64) {
174758 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
174759 const tmp_mcv = MCValue{ .register = tmp_reg };
174760 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
174761 defer self.register_manager.unlockReg(tmp_lock);
174762
174763 try self.genSetReg(tmp_reg, limb_ty, mat_src_mcv, .{});
174764 switch (limb_i) {
174765 0 => try self.genShiftBinOpMir(
174766 .{ ._l, .sh },
174767 limb_ty,
174768 tmp_mcv,
174769 .u8,
174770 .{ .immediate = src_bit_off },
174771 ),
174772 1 => try self.genShiftBinOpMir(
174773 .{ ._r, .sh },
174774 limb_ty,
174775 tmp_mcv,
174776 .u8,
174777 .{ .immediate = limb_abi_bits - src_bit_off },
174778 ),
174779 else => unreachable,
174780 }
174781 try self.genBinOpMir(.{ ._, .@"and" }, limb_ty, tmp_mcv, .{ .immediate = part_mask });
174782 try self.asmMemoryRegister(
174783 .{ ._, .@"or" },
174784 limb_mem,
174785 registerAlias(tmp_reg, limb_abi_size),
174786 );
174787 } else if (src_bit_size <= 128 and src_bit_off == 0) {
174788 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
174789 const tmp_mcv = MCValue{ .register = tmp_reg };
174790 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
174791 defer self.register_manager.unlockReg(tmp_lock);
174792
174793 try self.genSetReg(tmp_reg, limb_ty, switch (limb_i) {
174794 0 => mat_src_mcv,
174795 else => mat_src_mcv.address().offset(limb_i * limb_abi_size).deref(),
174796 }, .{});
174797 try self.genBinOpMir(.{ ._, .@"and" }, limb_ty, tmp_mcv, .{ .immediate = part_mask });
174798 try self.asmMemoryRegister(
174799 .{ ._, .@"or" },
174800 limb_mem,
174801 registerAlias(tmp_reg, limb_abi_size),
174802 );
174803 } else return self.fail("TODO: implement packed store of {f}", .{src_ty.fmt(pt)});
174804 }
174805}
174806
174807174792fn store(
174808174793 self: *CodeGen,
174809174794 ptr_ty: Type,
......@@ -174857,35 +174842,6 @@ fn store(
174857174842 }
174858174843}
174859174844
174860fn airStore(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
174861 const pt = self.pt;
174862 const zcu = pt.zcu;
174863 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
174864
174865 result: {
174866 if (!safety and (try self.resolveInst(bin_op.rhs)) == .undef) break :result;
174867
174868 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
174869 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
174870 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
174871
174872 const ptr_ty = self.typeOf(bin_op.lhs);
174873 const ptr_info = ptr_ty.ptrInfo(zcu);
174874 const is_packed = ptr_info.flags.vector_index != .none or ptr_info.packed_offset.host_size > 0;
174875 if (is_packed) try self.spillEflagsIfOccupied();
174876
174877 const src_mcv = try self.resolveInst(bin_op.rhs);
174878 const ptr_mcv = try self.resolveInst(bin_op.lhs);
174879
174880 if (is_packed) {
174881 try self.packedStore(ptr_ty, ptr_mcv, src_mcv);
174882 } else {
174883 try self.store(ptr_ty, ptr_mcv, src_mcv, .{ .safety = safety });
174884 }
174885 }
174886 return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
174887}
174888
174889174845fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue {
174890174846 const pt = self.pt;
174891174847 const zcu = pt.zcu;
......@@ -187019,15 +186975,21 @@ const Temp = struct {
187019186975 },
187020186976 .struct_type => {
187021186977 assert(src_regs.len - part_index == std.math.divCeil(u32, src_abi_size, 8) catch unreachable);
187022 break :part_ty .u64;
186978 break :part_ty switch (src_abi_size) {
186979 0, 3, 5...7 => unreachable,
186980 1 => .u8,
186981 2 => .u16,
186982 4 => .u32,
186983 else => .u64,
186984 };
186985 },
186986 .tuple_type => |tuple_type| {
186987 assert(tuple_type.types.len == src_regs.len);
186988 break :part_ty .fromInterned(tuple_type.types.get(ip)[part_index]);
187023186989 },
187024186990 };
187025186991 const part_size: u31 = @intCast(part_ty.abiSize(zcu));
187026186992 const src_rc = src_reg.class();
187027 const part_bit_size = switch (src_rc) {
187028 else => 8 * part_size,
187029 .x87 => part_ty.bitSize(zcu),
187030 };
187031186993 if (src_rc == .x87 or std.math.isPowerOfTwo(part_size)) {
187032186994 // hack around linker relocation bugs
187033186995 switch (ptr.tracking(cg).short) {
......@@ -187036,7 +186998,15 @@ const Temp = struct {
187036186998 }
187037186999 const strat = try cg.moveStrategy(part_ty, src_rc, false);
187038187000 try strat.write(cg, try ptr.tracking(cg).short.deref().mem(cg, .{
187039 .size = .fromBitSize(part_bit_size),
187001 .size = switch (src_rc) {
187002 else => .fromBitSize(8 * part_size),
187003 .x87 => switch (abi.classifySystemV(src_ty, zcu, cg.target, .other)[part_index]) {
187004 else => unreachable,
187005 .float => .dword,
187006 .float_combine, .sse => .qword,
187007 .x87 => .tbyte,
187008 },
187009 },
187040187010 .disp = part_disp,
187041187011 }), registerAlias(src_reg, part_size));
187042187012 } else {
......@@ -192157,6 +192127,8 @@ const Select = struct {
192157192127 exact_bool_vec: u16,
192158192128 ptr_any_bool_vec,
192159192129 ptr_bool_vec: Memory.Size,
192130 ptr_any_bool_vec_elem,
192131 ptr_bool_vec_elem: Memory.Size,
192160192132 remainder_bool_vec: OfIsSizes,
192161192133 exact_remainder_bool_vec: struct { of: Memory.Size, is: u16 },
192162192134 signed_int_vec: Memory.Size,
......@@ -192259,6 +192231,22 @@ const Select = struct {
192259192231 .vector_type => |vector_type| vector_type.child == .bool_type and size.bitSize(cg.target) >= vector_type.len,
192260192232 else => false,
192261192233 },
192234 .ptr_any_bool_vec_elem => {
192235 const ptr_info = ty.ptrInfo(zcu);
192236 return switch (ptr_info.flags.vector_index) {
192237 .none => false,
192238 .runtime => unreachable,
192239 else => ptr_info.child == .bool_type,
192240 };
192241 },
192242 .ptr_bool_vec_elem => |size| {
192243 const ptr_info = ty.ptrInfo(zcu);
192244 return switch (ptr_info.flags.vector_index) {
192245 .none => false,
192246 .runtime => unreachable,
192247 else => ptr_info.child == .bool_type and size.bitSize(cg.target) >= ptr_info.packed_offset.host_size,
192248 };
192249 },
192262192250 .remainder_bool_vec => |of_is| ty.isVector(zcu) and ty.scalarType(zcu).toIntern() == .bool_type and
192263192251 of_is.is.bitSize(cg.target) >= (ty.vectorLen(zcu) - 1) % of_is.of.bitSize(cg.target) + 1,
192264192252 .exact_remainder_bool_vec => |of_is| ty.isVector(zcu) and ty.scalarType(zcu).toIntern() == .bool_type and
......@@ -193252,7 +193240,7 @@ const Select = struct {
193252193240 ref: Ref,
193253193241 scale: Memory.Scale = .@"1",
193254193242 } = .{ .ref = .none },
193255 unused: u3 = 0,
193243 unused: u2 = 0,
193256193244 },
193257193245 imm: i32 = 0,
193258193246
......@@ -193265,9 +193253,9 @@ const Select = struct {
193265193253 lea,
193266193254 mem,
193267193255 };
193268 const Adjust = packed struct(u10) {
193256 const Adjust = packed struct(u11) {
193269193257 sign: enum(u1) { neg, pos },
193270 lhs: enum(u5) {
193258 lhs: enum(u6) {
193271193259 none,
193272193260 ptr_size,
193273193261 ptr_bit_size,
......@@ -193289,6 +193277,7 @@ const Select = struct {
193289193277 src0_elem_size,
193290193278 dst0_elem_size,
193291193279 src0_elem_size_mul_src1,
193280 vector_index,
193292193281 src1,
193293193282 src1_sub_bit_size,
193294193283 log2_src0_elem_size,
......@@ -193359,9 +193348,13 @@ const Select = struct {
193359193348 const sub_src0_elem_size: Adjust = .{ .sign = .neg, .lhs = .src0_elem_size, .op = .mul, .rhs = .@"1" };
193360193349 const add_src0_elem_size_mul_src1: Adjust = .{ .sign = .pos, .lhs = .src0_elem_size_mul_src1, .op = .mul, .rhs = .@"1" };
193361193350 const sub_src0_elem_size_mul_src1: Adjust = .{ .sign = .neg, .lhs = .src0_elem_size_mul_src1, .op = .mul, .rhs = .@"1" };
193351 const add_vector_index: Adjust = .{ .sign = .pos, .lhs = .vector_index, .op = .mul, .rhs = .@"1" };
193352 const add_vector_index_rem_32: Adjust = .{ .sign = .pos, .lhs = .vector_index, .op = .rem_8_mul, .rhs = .@"4" };
193353 const add_vector_index_div_8_down_4: Adjust = .{ .sign = .pos, .lhs = .vector_index, .op = .div_8_down, .rhs = .@"4" };
193362193354 const add_dst0_elem_size: Adjust = .{ .sign = .pos, .lhs = .dst0_elem_size, .op = .mul, .rhs = .@"1" };
193363193355 const sub_dst0_elem_size: Adjust = .{ .sign = .neg, .lhs = .dst0_elem_size, .op = .mul, .rhs = .@"1" };
193364193356 const add_src1_div_8_down_4: Adjust = .{ .sign = .pos, .lhs = .src1, .op = .div_8_down, .rhs = .@"4" };
193357 const add_src1: Adjust = .{ .sign = .pos, .lhs = .src1, .op = .mul, .rhs = .@"1" };
193365193358 const add_src1_rem_32: Adjust = .{ .sign = .pos, .lhs = .src1, .op = .rem_8_mul, .rhs = .@"4" };
193366193359 const add_src1_rem_64: Adjust = .{ .sign = .pos, .lhs = .src1, .op = .rem_8_mul, .rhs = .@"8" };
193367193360 const add_src1_sub_bit_size: Adjust = .{ .sign = .pos, .lhs = .src1_sub_bit_size, .op = .mul, .rhs = .@"1" };
......@@ -194244,6 +194237,10 @@ const Select = struct {
194244194237 .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
194245194238 .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) *
194246194239 Select.Operand.Ref.src1.valueOf(s).immediate),
194240 .vector_index => switch (op.flags.base.ref.typeOf(s).ptrInfo(s.cg.pt.zcu).flags.vector_index) {
194241 .none, .runtime => unreachable,
194242 else => |vector_index| @intFromEnum(vector_index),
194243 },
194247194244 .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate),
194248194245 .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) -
194249194246 @as(SignedImm, @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s)))),
src/codegen/aarch64/Select.zig+48-28
......@@ -5821,29 +5821,21 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
58215821 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
58225822 },
58235823 .unwrap_errunion_err_ptr => {
5824 if (isel.live_values.fetchRemove(air.inst_index)) |error_ptr_vi| unused: {
5825 defer error_ptr_vi.value.deref(isel);
5824 if (isel.live_values.fetchRemove(air.inst_index)) |error_vi| {
5825 defer error_vi.value.deref(isel);
58265826 const ty_op = air.data(air.inst_index).ty_op;
5827 switch (codegen.errUnionErrorOffset(
5828 isel.air.typeOf(ty_op.operand, ip).childType(zcu).errorUnionPayload(zcu),
5829 zcu,
5830 )) {
5831 0 => try error_ptr_vi.value.move(isel, ty_op.operand),
5832 else => |error_offset| {
5833 const error_ptr_ra = try error_ptr_vi.value.defReg(isel) orelse break :unused;
5834 const error_union_ptr_vi = try isel.use(ty_op.operand);
5835 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
5836 const lo12: u12 = @truncate(error_offset >> 0);
5837 const hi12: u12 = @intCast(error_offset >> 12);
5838 if (hi12 > 0) try isel.emit(.add(
5839 error_ptr_ra.x(),
5840 if (lo12 > 0) error_ptr_ra.x() else error_union_ptr_mat.ra.x(),
5841 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5842 ));
5843 if (lo12 > 0) try isel.emit(.add(error_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
5844 try error_union_ptr_mat.finish(isel);
5845 },
5846 }
5827 const error_union_ptr_ty = isel.air.typeOf(ty_op.operand, ip);
5828 const error_union_ptr_info = error_union_ptr_ty.ptrInfo(zcu);
5829 const error_union_ptr_vi = try isel.use(ty_op.operand);
5830 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
5831 _ = try error_vi.value.load(isel, ty_op.ty.toType(), error_union_ptr_mat.ra, .{
5832 .offset = codegen.errUnionErrorOffset(
5833 ZigType.fromInterned(error_union_ptr_info.child).errorUnionPayload(zcu),
5834 zcu,
5835 ),
5836 .@"volatile" = error_union_ptr_info.flags.is_volatile,
5837 });
5838 try error_union_ptr_mat.finish(isel);
58475839 }
58485840 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
58495841 },
......@@ -6147,6 +6139,26 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
61476139 }
61486140 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
61496141 },
6142 .ptr_slice_len_ptr => {
6143 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
6144 defer dst_vi.value.deref(isel);
6145 const ty_op = air.data(air.inst_index).ty_op;
6146 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
6147 const src_vi = try isel.use(ty_op.operand);
6148 const src_mat = try src_vi.matReg(isel);
6149 try isel.emit(.add(dst_ra.x(), src_mat.ra.x(), .{ .immediate = 8 }));
6150 try src_mat.finish(isel);
6151 }
6152 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6153 },
6154 .ptr_slice_ptr_ptr => {
6155 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {
6156 defer dst_vi.value.deref(isel);
6157 const ty_op = air.data(air.inst_index).ty_op;
6158 try dst_vi.value.move(isel, ty_op.operand);
6159 }
6160 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6161 },
61506162 .array_elem_val => {
61516163 if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: {
61526164 defer elem_vi.value.deref(isel);
......@@ -8011,6 +8023,7 @@ pub fn layout(
80118023 while (save_index < saves.len) {
80128024 if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and
80138025 saves[save_index + 0].class == saves[save_index + 1].class and
8026 saves[save_index + 0].size == saves[save_index + 1].size and
80148027 saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset)
80158028 {
80168029 try isel.emit(.ldp(
......@@ -8317,7 +8330,7 @@ fn elemPtr(
83178330 }),
83188331 2 => {
83198332 const shift: u6 = @intCast(@ctz(elem_size));
8320 const temp_ra = temp_ra: switch (op) {
8333 const temp_ra, const free_temp_ra = temp_ra: switch (op) {
83218334 .add => switch (base_ra) {
83228335 else => {
83238336 const temp_ra = try isel.allocIntReg();
......@@ -8326,7 +8339,7 @@ fn elemPtr(
83268339 .register = temp_ra.x(),
83278340 .shift = .{ .lsl = shift },
83288341 } }));
8329 break :temp_ra temp_ra;
8342 break :temp_ra .{ temp_ra, true };
83308343 },
83318344 .zr => {
83328345 if (shift > 0) try isel.emit(.ubfm(elem_ptr_ra.x(), elem_ptr_ra.x(), .{
......@@ -8334,7 +8347,7 @@ fn elemPtr(
83348347 .immr = -%shift,
83358348 .imms = ~shift,
83368349 }));
8337 break :temp_ra elem_ptr_ra;
8350 break :temp_ra .{ elem_ptr_ra, false };
83388351 },
83398352 },
83408353 .sub => {
......@@ -8344,10 +8357,10 @@ fn elemPtr(
83448357 .register = temp_ra.x(),
83458358 .shift = .{ .lsl = shift },
83468359 } }));
8347 break :temp_ra temp_ra;
8360 break :temp_ra .{ temp_ra, true };
83488361 },
83498362 };
8350 defer if (temp_ra != elem_ptr_ra) isel.freeReg(temp_ra);
8363 defer if (free_temp_ra) isel.freeReg(temp_ra);
83518364 try isel.emit(.add(temp_ra.x(), index_mat.ra.x(), .{ .shifted_register = .{
83528365 .register = index_mat.ra.x(),
83538366 .shift = .{ .lsl = @intCast(63 - @clz(elem_size) - shift) },
......@@ -9276,7 +9289,14 @@ pub const Value = struct {
92769289 part_offset -= part_size;
92779290 var wrapped_res_part_it = res_vi.field(ty, part_offset, part_size);
92789291 const wrapped_res_part_vi = try wrapped_res_part_it.only(isel);
9279 const wrapped_res_part_ra = try wrapped_res_part_vi.?.defReg(isel) orelse if (need_carry) .zr else continue;
9292 const wrapped_res_part_ra = wrapped_res_part_ra: {
9293 const overflow_ra_lock: RegLock = switch (opts.overflow) {
9294 .ra => |ra| isel.lockReg(ra),
9295 else => .empty,
9296 };
9297 defer overflow_ra_lock.unlock(isel);
9298 break :wrapped_res_part_ra try wrapped_res_part_vi.?.defReg(isel) orelse if (need_carry) .zr else continue;
9299 };
92809300 const unwrapped_res_part_ra = unwrapped_res_part_ra: {
92819301 if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra;
92829302 if (int_info.bits % 32 == 0) {
src/codegen/llvm.zig+21-81
......@@ -4980,8 +4980,8 @@ pub const FuncGen = struct {
49804980 .breakpoint => try self.airBreakpoint(inst),
49814981 .ret_addr => try self.airRetAddr(inst),
49824982 .frame_addr => try self.airFrameAddress(inst),
4983 .@"try" => try self.airTry(body[i..], false),
4984 .try_cold => try self.airTry(body[i..], true),
4983 .@"try" => try self.airTry(inst, false),
4984 .try_cold => try self.airTry(inst, true),
49854985 .try_ptr => try self.airTryPtr(inst, false),
49864986 .try_ptr_cold => try self.airTryPtr(inst, true),
49874987 .intcast => try self.airIntCast(inst, false),
......@@ -4989,7 +4989,7 @@ pub const FuncGen = struct {
49894989 .trunc => try self.airTrunc(inst),
49904990 .fptrunc => try self.airFptrunc(inst),
49914991 .fpext => try self.airFpext(inst),
4992 .load => try self.airLoad(body[i..]),
4992 .load => try self.airLoad(inst),
49934993 .not => try self.airNot(inst),
49944994 .store => try self.airStore(inst, false),
49954995 .store_safe => try self.airStore(inst, true),
......@@ -5045,7 +5045,7 @@ pub const FuncGen = struct {
50455045 .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst),
50465046
50475047 .struct_field_ptr => try self.airStructFieldPtr(inst),
5048 .struct_field_val => try self.airStructFieldVal(body[i..]),
5048 .struct_field_val => try self.airStructFieldVal(inst),
50495049
50505050 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
50515051 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
......@@ -5054,18 +5054,18 @@ pub const FuncGen = struct {
50545054
50555055 .field_parent_ptr => try self.airFieldParentPtr(inst),
50565056
5057 .array_elem_val => try self.airArrayElemVal(body[i..]),
5058 .slice_elem_val => try self.airSliceElemVal(body[i..]),
5057 .array_elem_val => try self.airArrayElemVal(inst),
5058 .slice_elem_val => try self.airSliceElemVal(inst),
50595059 .slice_elem_ptr => try self.airSliceElemPtr(inst),
5060 .ptr_elem_val => try self.airPtrElemVal(body[i..]),
5060 .ptr_elem_val => try self.airPtrElemVal(inst),
50615061 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
50625062
5063 .optional_payload => try self.airOptionalPayload(body[i..]),
5063 .optional_payload => try self.airOptionalPayload(inst),
50645064 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
50655065 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
50665066
5067 .unwrap_errunion_payload => try self.airErrUnionPayload(body[i..], false),
5068 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(body[i..], true),
5067 .unwrap_errunion_payload => try self.airErrUnionPayload(inst, false),
5068 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),
50695069 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),
50705070 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
50715071 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
......@@ -6266,19 +6266,14 @@ pub const FuncGen = struct {
62666266 // No need to reset the insert cursor since this instruction is noreturn.
62676267 }
62686268
6269 fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index, err_cold: bool) !Builder.Value {
6270 const pt = self.ng.pt;
6271 const zcu = pt.zcu;
6272 const inst = body_tail[0];
6269 fn airTry(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value {
62736270 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
62746271 const err_union = try self.resolveInst(pl_op.operand);
62756272 const extra = self.air.extraData(Air.Try, pl_op.payload);
62766273 const body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]);
62776274 const err_union_ty = self.typeOf(pl_op.operand);
6278 const payload_ty = self.typeOfIndex(inst);
6279 const can_elide_load = if (isByRef(payload_ty, zcu)) self.canElideLoad(body_tail) else false;
62806275 const is_unused = self.liveness.isUnused(inst);
6281 return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused, err_cold);
6276 return lowerTry(self, err_union, body, err_union_ty, false, false, is_unused, err_cold);
62826277 }
62836278
62846279 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value {
......@@ -6824,11 +6819,10 @@ pub const FuncGen = struct {
68246819 return self.wip.gepStruct(slice_llvm_ty, slice_ptr, index, "");
68256820 }
68266821
6827 fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
6822 fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
68286823 const o = self.ng.object;
68296824 const pt = self.ng.pt;
68306825 const zcu = pt.zcu;
6831 const inst = body_tail[0];
68326826 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
68336827 const slice_ty = self.typeOf(bin_op.lhs);
68346828 const slice = try self.resolveInst(bin_op.lhs);
......@@ -6838,9 +6832,6 @@ pub const FuncGen = struct {
68386832 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
68396833 const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
68406834 if (isByRef(elem_ty, zcu)) {
6841 if (self.canElideLoad(body_tail))
6842 return ptr;
6843
68446835 self.maybeMarkAllowZeroAccess(slice_ty.ptrInfo(zcu));
68456836
68466837 const slice_align = (slice_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm();
......@@ -6867,11 +6858,10 @@ pub const FuncGen = struct {
68676858 return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
68686859 }
68696860
6870 fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
6861 fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
68716862 const o = self.ng.object;
68726863 const pt = self.ng.pt;
68736864 const zcu = pt.zcu;
6874 const inst = body_tail[0];
68756865
68766866 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
68776867 const array_ty = self.typeOf(bin_op.lhs);
......@@ -6884,9 +6874,7 @@ pub const FuncGen = struct {
68846874 try o.builder.intValue(try o.lowerType(pt, Type.usize), 0), rhs,
68856875 };
68866876 if (isByRef(elem_ty, zcu)) {
6887 const elem_ptr =
6888 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
6889 if (canElideLoad(self, body_tail)) return elem_ptr;
6877 const elem_ptr = try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
68906878 const elem_alignment = elem_ty.abiAlignment(zcu).toLlvm();
68916879 return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal);
68926880 } else {
......@@ -6900,11 +6888,10 @@ pub const FuncGen = struct {
69006888 return self.wip.extractElement(array_llvm_val, rhs, "");
69016889 }
69026890
6903 fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
6891 fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
69046892 const o = self.ng.object;
69056893 const pt = self.ng.pt;
69066894 const zcu = pt.zcu;
6907 const inst = body_tail[0];
69086895 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
69096896 const ptr_ty = self.typeOf(bin_op.lhs);
69106897 const elem_ty = ptr_ty.childType(zcu);
......@@ -6918,10 +6905,7 @@ pub const FuncGen = struct {
69186905 else
69196906 &.{rhs}, "");
69206907 if (isByRef(elem_ty, zcu)) {
6921 if (self.canElideLoad(body_tail)) return ptr;
6922
69236908 self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu));
6924
69256909 const ptr_align = (ptr_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm();
69266910 return self.loadByRef(ptr, elem_ty, ptr_align, if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal);
69276911 }
......@@ -6974,11 +6958,10 @@ pub const FuncGen = struct {
69746958 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);
69756959 }
69766960
6977 fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
6961 fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
69786962 const o = self.ng.object;
69796963 const pt = self.ng.pt;
69806964 const zcu = pt.zcu;
6981 const inst = body_tail[0];
69826965 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
69836966 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
69846967 const struct_ty = self.typeOf(struct_field.struct_operand);
......@@ -7052,9 +7035,6 @@ pub const FuncGen = struct {
70527035 .flags = .{ .alignment = alignment },
70537036 });
70547037 if (isByRef(field_ty, zcu)) {
7055 if (canElideLoad(self, body_tail))
7056 return field_ptr;
7057
70587038 assert(alignment != .none);
70597039 const field_alignment = alignment.toLlvm();
70607040 return self.loadByRef(field_ptr, field_ty, field_alignment, .normal);
......@@ -7070,7 +7050,6 @@ pub const FuncGen = struct {
70707050 try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, "");
70717051 const payload_alignment = layout.payload_align.toLlvm();
70727052 if (isByRef(field_ty, zcu)) {
7073 if (canElideLoad(self, body_tail)) return field_ptr;
70747053 return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal);
70757054 } else {
70767055 return self.loadTruncate(.normal, field_ty, field_ptr, payload_alignment);
......@@ -7829,11 +7808,10 @@ pub const FuncGen = struct {
78297808 return self.wip.gepStruct(optional_llvm_ty, operand, 0, "");
78307809 }
78317810
7832 fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
7811 fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
78337812 const o = self.ng.object;
78347813 const pt = self.ng.pt;
78357814 const zcu = pt.zcu;
7836 const inst = body_tail[0];
78377815 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
78387816 const operand = try self.resolveInst(ty_op.operand);
78397817 const optional_ty = self.typeOf(ty_op.operand);
......@@ -7846,19 +7824,13 @@ pub const FuncGen = struct {
78467824 }
78477825
78487826 const opt_llvm_ty = try o.lowerType(pt, optional_ty);
7849 const can_elide_load = if (isByRef(payload_ty, zcu)) self.canElideLoad(body_tail) else false;
7850 return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, can_elide_load);
7827 return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, false);
78517828 }
78527829
7853 fn airErrUnionPayload(
7854 self: *FuncGen,
7855 body_tail: []const Air.Inst.Index,
7856 operand_is_ptr: bool,
7857 ) !Builder.Value {
7830 fn airErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index, operand_is_ptr: bool) !Builder.Value {
78587831 const o = self.ng.object;
78597832 const pt = self.ng.pt;
78607833 const zcu = pt.zcu;
7861 const inst = body_tail[0];
78627834 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
78637835 const operand = try self.resolveInst(ty_op.operand);
78647836 const operand_ty = self.typeOf(ty_op.operand);
......@@ -7877,7 +7849,6 @@ pub const FuncGen = struct {
78777849 const payload_alignment = payload_ty.abiAlignment(zcu).toLlvm();
78787850 const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
78797851 if (isByRef(payload_ty, zcu)) {
7880 if (self.canElideLoad(body_tail)) return payload_ptr;
78817852 return self.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal);
78827853 }
78837854 const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
......@@ -9740,45 +9711,14 @@ pub const FuncGen = struct {
97409711 return .none;
97419712 }
97429713
9743 /// As an optimization, we want to avoid unnecessary copies of isByRef=true
9744 /// types. Here, we scan forward in the current block, looking to see if
9745 /// this load dies before any side effects occur. In such case, we can
9746 /// safely return the operand without making a copy.
9747 ///
9748 /// The first instruction of `body_tail` is the one whose copy we want to elide.
9749 fn canElideLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) bool {
9750 const zcu = fg.ng.pt.zcu;
9751 const ip = &zcu.intern_pool;
9752 for (body_tail[1..]) |body_inst| {
9753 switch (fg.liveness.categorizeOperand(fg.air, zcu, body_inst, body_tail[0], ip)) {
9754 .none => continue,
9755 .write, .noret, .complex => return false,
9756 .tomb => return true,
9757 }
9758 }
9759 // The only way to get here is to hit the end of a loop instruction
9760 // (implicit repeat).
9761 return false;
9762 }
9763
9764 fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
9714 fn airLoad(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
97659715 const pt = fg.ng.pt;
97669716 const zcu = pt.zcu;
9767 const inst = body_tail[0];
97689717 const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
97699718 const ptr_ty = fg.typeOf(ty_op.operand);
97709719 const ptr_info = ptr_ty.ptrInfo(zcu);
97719720 const ptr = try fg.resolveInst(ty_op.operand);
9772
9773 elide: {
9774 if (ptr_info.flags.alignment != .none) break :elide;
9775 if (!isByRef(Type.fromInterned(ptr_info.child), zcu)) break :elide;
9776 if (!canElideLoad(fg, body_tail)) break :elide;
9777 return ptr;
9778 }
9779
97809721 fg.maybeMarkAllowZeroAccess(ptr_info);
9781
97829722 return fg.load(ptr, ptr_ty);
97839723 }
97849724
src/print_zir.zig+3-3
......@@ -406,7 +406,7 @@ const Writer = struct {
406406 .memset,
407407 .memmove,
408408 .elem_ptr_node,
409 .elem_val_node,
409 .elem_ptr_load,
410410 .elem_ptr,
411411 .elem_val,
412412 .array_type,
......@@ -450,14 +450,14 @@ const Writer = struct {
450450
451451 .switch_block_err_union => try self.writeSwitchBlockErrUnion(stream, inst),
452452
453 .field_val,
453 .field_ptr_load,
454454 .field_ptr,
455455 .decl_literal,
456456 .decl_literal_no_coerce,
457457 => try self.writePlNodeField(stream, inst),
458458
459459 .field_ptr_named,
460 .field_val_named,
460 .field_ptr_named_load,
461461 => try self.writePlNodeFieldNamed(stream, inst),
462462
463463 .as_node, .as_shift_operand => try self.writeAs(stream, inst),
test/behavior/align.zig-1
......@@ -392,7 +392,6 @@ test "read 128-bit field from default aligned struct in global memory" {
392392}
393393
394394test "struct field explicit alignment" {
395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
396395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
397396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
398397 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
test/behavior/array.zig+21
......@@ -1125,3 +1125,24 @@ test "splat with an error union or optional result type" {
11251125 _ = try S.doTest(@Vector(4, u32));
11261126 _ = try S.doTest([4]u32);
11271127}
1128
1129test "resist alias of explicit copy of array passed as arg" {
1130 const S = struct {
1131 const Thing = [1]u32;
1132
1133 fn destroy_and_replace(box_b: *Thing, a: Thing, box_a: *Thing) void {
1134 box_a.* = undefined;
1135 box_b.* = a;
1136 }
1137 };
1138
1139 var buf_a: S.Thing = .{1234};
1140 var buf_b: S.Thing = .{5678};
1141 const box_a = &buf_a;
1142 const box_b = &buf_b;
1143
1144 const a = box_a.*; // explicit copy
1145 S.destroy_and_replace(box_b, a, box_a);
1146
1147 try expect(buf_b[0] == 1234);
1148}
test/behavior/bitcast.zig-1
......@@ -511,7 +511,6 @@ test "@bitCast of packed struct of bools all false" {
511511}
512512
513513test "@bitCast of packed struct containing pointer" {
514 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
515514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
516515 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
517516 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
test/behavior/error.zig-1
......@@ -951,7 +951,6 @@ test "returning an error union containing a type with no runtime bits" {
951951}
952952
953953test "try used in recursive function with inferred error set" {
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
955954 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
956955 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
957956
test/behavior/field_parent_ptr.zig+3
......@@ -1032,6 +1032,7 @@ test "@fieldParentPtr packed struct first zero-bit field" {
10321032 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
10331033 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10341034 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1035 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10351036
10361037 const C = packed struct {
10371038 a: u0 = 0,
......@@ -1137,6 +1138,7 @@ test "@fieldParentPtr packed struct middle zero-bit field" {
11371138 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
11381139 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11391140 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1141 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11401142
11411143 const C = packed struct {
11421144 a: f32 = 3.14,
......@@ -1242,6 +1244,7 @@ test "@fieldParentPtr packed struct last zero-bit field" {
12421244 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
12431245 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12441246 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12451248
12461249 const C = packed struct {
12471250 a: f32 = 3.14,
test/behavior/floatop.zig-1
......@@ -1741,7 +1741,6 @@ test "comptime calls are only memoized when float arguments are bit-for-bit equa
17411741test "result location forwarded through unary float builtins" {
17421742 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
17431743 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1744 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17451744 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
17461745 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17471746 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/globals.zig-1
......@@ -14,7 +14,6 @@ test "store to global array" {
1414
1515var vpos = @Vector(2, f32){ 0.0, 0.0 };
1616test "store to global vector" {
17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1817 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1918 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2019
test/behavior/math.zig+1-5
......@@ -139,11 +139,7 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void {
139139 const len_a = @typeInfo(@TypeOf(a)).vector.len;
140140 const len_b = @typeInfo(@TypeOf(b)).vector.len;
141141 try expect(len_a == len_b);
142
143 var i: usize = 0;
144 while (i < len_a) : (i += 1) {
145 try expect(a[i] == b[i]);
146 }
142 try expect(@reduce(.And, a == b));
147143}
148144
149145test "@ctz" {
test/behavior/memset.zig-1
......@@ -122,7 +122,6 @@ test "memset with large array element, runtime known" {
122122}
123123
124124test "memset with large array element, comptime known" {
125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
126125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
127126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
128127 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/packed-struct.zig+53-86
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33const assert = std.debug.assert;
44const expect = std.testing.expect;
55const expectEqual = std.testing.expectEqual;
6const native_endian = builtin.cpu.arch.endian();
76
87test "flags in packed structs" {
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -163,26 +162,24 @@ test "correct sizeOf and offsets in packed structs" {
163162 try expectEqual(22, @bitOffsetOf(PStruct, "u10_b"));
164163 try expectEqual(4, @sizeOf(PStruct));
165164
166 if (native_endian == .little) {
167 const s1 = @as(PStruct, @bitCast(@as(u32, 0x12345678)));
168 try expectEqual(false, s1.bool_a);
169 try expectEqual(false, s1.bool_b);
170 try expectEqual(false, s1.bool_c);
171 try expectEqual(true, s1.bool_d);
172 try expectEqual(true, s1.bool_e);
173 try expectEqual(true, s1.bool_f);
174 try expectEqual(1, s1.u1_a);
175 try expectEqual(false, s1.bool_g);
176 try expectEqual(0, s1.u1_b);
177 try expectEqual(3, s1.u3_a);
178 try expectEqual(0b1101000101, s1.u10_a);
179 try expectEqual(0b0001001000, s1.u10_b);
180
181 const s2 = @as(packed struct { x: u1, y: u7, z: u24 }, @bitCast(@as(u32, 0xd5c71ff4)));
182 try expectEqual(0, s2.x);
183 try expectEqual(0b1111010, s2.y);
184 try expectEqual(0xd5c71f, s2.z);
185 }
165 const s1 = @as(PStruct, @bitCast(@as(u32, 0x12345678)));
166 try expectEqual(false, s1.bool_a);
167 try expectEqual(false, s1.bool_b);
168 try expectEqual(false, s1.bool_c);
169 try expectEqual(true, s1.bool_d);
170 try expectEqual(true, s1.bool_e);
171 try expectEqual(true, s1.bool_f);
172 try expectEqual(1, s1.u1_a);
173 try expectEqual(false, s1.bool_g);
174 try expectEqual(0, s1.u1_b);
175 try expectEqual(3, s1.u3_a);
176 try expectEqual(0b1101000101, s1.u10_a);
177 try expectEqual(0b0001001000, s1.u10_b);
178
179 const s2 = @as(packed struct { x: u1, y: u7, z: u24 }, @bitCast(@as(u32, 0xd5c71ff4)));
180 try expectEqual(0, s2.x);
181 try expectEqual(0b1111010, s2.y);
182 try expectEqual(0xd5c71f, s2.z);
186183}
187184
188185test "nested packed structs" {
......@@ -202,15 +199,13 @@ test "nested packed structs" {
202199 try expectEqual(3, @offsetOf(S3, "y"));
203200 try expectEqual(24, @bitOffsetOf(S3, "y"));
204201
205 if (native_endian == .little) {
206 const s3 = @as(S3Padded, @bitCast(@as(u64, 0xe952d5c71ff4))).s3;
207 try expectEqual(0xf4, s3.x.a);
208 try expectEqual(0x1f, s3.x.b);
209 try expectEqual(0xc7, s3.x.c);
210 try expectEqual(0xd5, s3.y.d);
211 try expectEqual(0x52, s3.y.e);
212 try expectEqual(0xe9, s3.y.f);
213 }
202 const s3 = @as(S3Padded, @bitCast(@as(u64, 0xe952d5c71ff4))).s3;
203 try expectEqual(0xf4, s3.x.a);
204 try expectEqual(0x1f, s3.x.b);
205 try expectEqual(0xc7, s3.x.c);
206 try expectEqual(0xd5, s3.y.d);
207 try expectEqual(0x52, s3.y.e);
208 try expectEqual(0xe9, s3.y.f);
214209
215210 const S4 = packed struct { a: i32, b: i8 };
216211 const S5 = packed struct { a: i32, b: i8, c: S4 };
......@@ -230,10 +225,10 @@ test "nested packed structs" {
230225}
231226
232227test "regular in irregular packed struct" {
233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
234228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
235229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
236230 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
231 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
237232
238233 const Irregular = packed struct {
239234 bar: Regular = Regular{},
......@@ -253,7 +248,6 @@ test "nested packed struct unaligned" {
253248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
254249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
255250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
256 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
257251
258252 const S1 = packed struct {
259253 a: u4,
......@@ -321,10 +315,10 @@ test "nested packed struct unaligned" {
321315}
322316
323317test "byte-aligned field pointer offsets" {
324 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
325318 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
326319 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
327320 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
328322
329323 const S = struct {
330324 const A = packed struct {
......@@ -346,21 +340,12 @@ test "byte-aligned field pointer offsets" {
346340 .c = 3,
347341 .d = 4,
348342 };
349 switch (comptime builtin.cpu.arch.endian()) {
350 .little => {
351 comptime assert(@TypeOf(&a.a) == *align(4) u8);
352 comptime assert(@TypeOf(&a.b) == *u8);
353 comptime assert(@TypeOf(&a.c) == *align(2) u8);
354 comptime assert(@TypeOf(&a.d) == *u8);
355 },
356 .big => {
357 // TODO re-evaluate packed struct endianness
358 comptime assert(@TypeOf(&a.a) == *align(4:0:4) u8);
359 comptime assert(@TypeOf(&a.b) == *align(4:8:4) u8);
360 comptime assert(@TypeOf(&a.c) == *align(4:16:4) u8);
361 comptime assert(@TypeOf(&a.d) == *align(4:24:4) u8);
362 },
363 }
343
344 comptime assert(@TypeOf(&a.a) == *align(4:0:4) u8);
345 comptime assert(@TypeOf(&a.b) == *align(4:8:4) u8);
346 comptime assert(@TypeOf(&a.c) == *align(4:16:4) u8);
347 comptime assert(@TypeOf(&a.d) == *align(4:24:4) u8);
348
364349 try expect(a.a == 1);
365350 try expect(a.b == 2);
366351 try expect(a.c == 3);
......@@ -394,16 +379,10 @@ test "byte-aligned field pointer offsets" {
394379 .a = 1,
395380 .b = 2,
396381 };
397 switch (comptime builtin.cpu.arch.endian()) {
398 .little => {
399 comptime assert(@TypeOf(&b.a) == *align(4) u16);
400 comptime assert(@TypeOf(&b.b) == *u16);
401 },
402 .big => {
403 comptime assert(@TypeOf(&b.a) == *align(4:0:4) u16);
404 comptime assert(@TypeOf(&b.b) == *align(4:16:4) u16);
405 },
406 }
382
383 comptime assert(@TypeOf(&b.a) == *align(4:0:4) u16);
384 comptime assert(@TypeOf(&b.b) == *align(4:16:4) u16);
385
407386 try expect(b.a == 1);
408387 try expect(b.b == 2);
409388
......@@ -428,7 +407,6 @@ test "nested packed struct field pointers" {
428407 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
429408 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // ubsan unaligned pointer access
430409 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
431 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
432410
433411 const S2 = packed struct {
434412 base: u8,
......@@ -485,7 +463,6 @@ test "@intFromPtr on a packed struct field" {
485463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
486464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
487465 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
488 if (native_endian != .little) return error.SkipZigTest;
489466
490467 const S = struct {
491468 const P = packed struct {
......@@ -500,14 +477,13 @@ test "@intFromPtr on a packed struct field" {
500477 .z = 0,
501478 };
502479 };
503 try expect(@intFromPtr(&S.p0.z) - @intFromPtr(&S.p0.x) == 2);
480 try expect(@intFromPtr(&S.p0.z) - @intFromPtr(&S.p0.x) == 0);
504481}
505482
506483test "@intFromPtr on a packed struct field unaligned and nested" {
507484 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
508485 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
509486 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
510 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
511487
512488 const S1 = packed struct {
513489 a: u4,
......@@ -567,16 +543,16 @@ test "@intFromPtr on a packed struct field unaligned and nested" {
567543 else => {},
568544 }
569545 try expect(@intFromPtr(&S2.s.base) - @intFromPtr(&S2.s) == 0);
570 try expect(@intFromPtr(&S2.s.p0.a) - @intFromPtr(&S2.s) == 1);
571 try expect(@intFromPtr(&S2.s.p0.b) - @intFromPtr(&S2.s) == 1);
572 try expect(@intFromPtr(&S2.s.p0.c) - @intFromPtr(&S2.s) == 2);
546 try expect(@intFromPtr(&S2.s.p0.a) - @intFromPtr(&S2.s) == 0);
547 try expect(@intFromPtr(&S2.s.p0.b) - @intFromPtr(&S2.s) == 0);
548 try expect(@intFromPtr(&S2.s.p0.c) - @intFromPtr(&S2.s) == 0);
573549 try expect(@intFromPtr(&S2.s.bit0) - @intFromPtr(&S2.s) == 0);
574550 try expect(@intFromPtr(&S2.s.p1.a) - @intFromPtr(&S2.s) == 0);
575551 try expect(@intFromPtr(&S2.s.p2.a) - @intFromPtr(&S2.s) == 0);
576 try expect(@intFromPtr(&S2.s.p2.b) - @intFromPtr(&S2.s) == 5);
577 try expect(@intFromPtr(&S2.s.p3.a) - @intFromPtr(&S2.s) == 6);
578 try expect(@intFromPtr(&S2.s.p3.b) - @intFromPtr(&S2.s) == 6);
579 try expect(@intFromPtr(&S2.s.p3.c) - @intFromPtr(&S2.s) == 7);
552 try expect(@intFromPtr(&S2.s.p2.b) - @intFromPtr(&S2.s) == 0);
553 try expect(@intFromPtr(&S2.s.p3.a) - @intFromPtr(&S2.s) == 0);
554 try expect(@intFromPtr(&S2.s.p3.b) - @intFromPtr(&S2.s) == 0);
555 try expect(@intFromPtr(&S2.s.p3.c) - @intFromPtr(&S2.s) == 0);
580556
581557 const S3 = packed struct {
582558 pad: u8,
......@@ -599,7 +575,7 @@ test "@intFromPtr on a packed struct field unaligned and nested" {
599575 comptime assert(@TypeOf(&S3.v0.s.v) == *align(4:10:4) u3);
600576 comptime assert(@TypeOf(&S3.v0.s.s.v) == *align(4:13:4) u2);
601577 comptime assert(@TypeOf(&S3.v0.s.s.s.bit0) == *align(4:15:4) u1);
602 comptime assert(@TypeOf(&S3.v0.s.s.s.byte) == *align(2) u8);
578 comptime assert(@TypeOf(&S3.v0.s.s.s.byte) == *align(4:16:4) u8);
603579 comptime assert(@TypeOf(&S3.v0.s.s.s.bit1) == *align(4:24:4) u1);
604580 try expect(@intFromPtr(&S3.v0.v) - @intFromPtr(&S3.v0) == 0);
605581 try expect(@intFromPtr(&S3.v0.s) - @intFromPtr(&S3.v0) == 0);
......@@ -608,7 +584,7 @@ test "@intFromPtr on a packed struct field unaligned and nested" {
608584 try expect(@intFromPtr(&S3.v0.s.s.v) - @intFromPtr(&S3.v0) == 0);
609585 try expect(@intFromPtr(&S3.v0.s.s.s) - @intFromPtr(&S3.v0) == 0);
610586 try expect(@intFromPtr(&S3.v0.s.s.s.bit0) - @intFromPtr(&S3.v0) == 0);
611 try expect(@intFromPtr(&S3.v0.s.s.s.byte) - @intFromPtr(&S3.v0) == 2);
587 try expect(@intFromPtr(&S3.v0.s.s.s.byte) - @intFromPtr(&S3.v0) == 0);
612588 try expect(@intFromPtr(&S3.v0.s.s.s.bit1) - @intFromPtr(&S3.v0) == 0);
613589}
614590
......@@ -653,13 +629,13 @@ test "optional pointer in packed struct" {
653629}
654630
655631test "nested packed struct field access test" {
656 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
657632 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
658633 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits
659634 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
660635 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
661636 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
662637 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
638 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
663639
664640 const Vec2 = packed struct {
665641 x: f32,
......@@ -774,9 +750,9 @@ test "nested packed struct field access test" {
774750}
775751
776752test "nested packed struct at non-zero offset" {
777 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
778753 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
779754 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
755 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
780756
781757 const Pair = packed struct(u24) {
782758 a: u16 = 0,
......@@ -871,7 +847,6 @@ test "nested packed struct at non-zero offset 2" {
871847}
872848
873849test "runtime init of unnamed packed struct type" {
874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
875850 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
876851 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
877852 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -916,21 +891,13 @@ test "overaligned pointer to packed struct" {
916891 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
917892 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
918893 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
894 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
919895
920896 const S = packed struct { a: u32, b: u32 };
921897 var foo: S align(4) = .{ .a = 123, .b = 456 };
922898 const ptr: *align(4) S = &foo;
923 switch (comptime builtin.cpu.arch.endian()) {
924 .little => {
925 const ptr_to_b: *u32 = &ptr.b;
926 try expect(ptr_to_b.* == 456);
927 },
928 .big => {
929 // Byte aligned packed struct field pointers have not been implemented yet.
930 const ptr_to_a: *align(4:0:8) u32 = &ptr.a;
931 try expect(ptr_to_a.* == 123);
932 },
933 }
899 const ptr_to_a: *align(4:0:8) u32 = &ptr.a;
900 try expect(ptr_to_a.* == 123);
934901}
935902
936903test "packed struct initialized in bitcast" {
......@@ -1345,11 +1312,11 @@ test "assign packed struct initialized with RLS to packed struct literal field"
13451312}
13461313
13471314test "byte-aligned packed relocation" {
1348 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13491315 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
13501316 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
13511317 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13521318 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1319 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13531320
13541321 const S = struct {
13551322 var global: u8 align(2) = 0;
test/behavior/pointers.zig+8-1
......@@ -419,7 +419,6 @@ test "pointer sentinel with enums" {
419419}
420420
421421test "pointer sentinel with optional element" {
422 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
423422 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
424423 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
425424 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -779,3 +778,11 @@ test "pointers to elements of many-ptr to zero-bit type" {
779778
780779 try expect(a == b);
781780}
781
782test "comptime C pointer to optional pointer" {
783 const opt: ?*u8 = @ptrFromInt(0x1000);
784 const outer_ptr: [*c]const ?*u8 = &opt;
785 const inner_ptr = &outer_ptr.*.?;
786 comptime assert(@TypeOf(inner_ptr) == [*c]const *u8);
787 comptime assert(@intFromPtr(inner_ptr.*) == 0x1000);
788}
test/behavior/struct.zig+25-3
......@@ -376,10 +376,10 @@ const APackedStruct = packed struct {
376376};
377377
378378test "packed struct" {
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
380379 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
381380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
382381 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
383383
384384 var foo = APackedStruct{
385385 .x = 1,
......@@ -744,11 +744,11 @@ const S0 = struct {
744744var g_foo: S0 = S0.init();
745745
746746test "packed struct with fp fields" {
747 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
748747 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
749748 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
750749 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
751750 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
751 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
752752
753753 const S = packed struct {
754754 data0: f32,
......@@ -1924,7 +1924,6 @@ test "runtime value in nested initializer passed as pointer to function" {
19241924}
19251925
19261926test "struct field default value is a call" {
1927 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19281927 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19291928 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19301929
......@@ -2154,3 +2153,26 @@ test "align 1 struct parameter dereferenced and returned" {
21542153 .little => try expect(s.a == 0x05040302),
21552154 }
21562155}
2156
2157test "avoid unused field function body compile error" {
2158 const Case = struct {
2159 const This = @This();
2160
2161 const S = struct {
2162 a: usize = 1,
2163 b: fn () void = This.functionThatDoesNotCompile,
2164 };
2165
2166 const s: S = .{};
2167
2168 fn entry() usize {
2169 return s.a;
2170 }
2171
2172 pub fn functionThatDoesNotCompile() void {
2173 @compileError("told you so");
2174 }
2175 };
2176
2177 try expect(Case.entry() == 1);
2178}
test/behavior/switch_on_captured_error.zig-1
......@@ -300,7 +300,6 @@ test "switch on error union catch capture" {
300300}
301301
302302test "switch on error union if else capture" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
304303 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
305304 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
306305
test/behavior/try.zig-2
......@@ -122,7 +122,6 @@ test "'return try' through conditional" {
122122}
123123
124124test "try ptr propagation const" {
125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
126125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
127126 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
128127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
......@@ -155,7 +154,6 @@ test "try ptr propagation const" {
155154}
156155
157156test "try ptr propagation mutate" {
158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
159157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
160158 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
161159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
test/behavior/tuple.zig-1
......@@ -384,7 +384,6 @@ test "tuple initialized with a runtime known value" {
384384}
385385
386386test "tuple of struct concatenation and coercion to array" {
387 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
388387 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
389388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
390389 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/type.zig-1
......@@ -408,7 +408,6 @@ test "Type.Enum" {
408408}
409409
410410test "Type.Union" {
411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
412411 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
413412 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
414413
test/behavior/union.zig+1-3
......@@ -1335,9 +1335,9 @@ test "union field ptr - zero sized field" {
13351335}
13361336
13371337test "packed union in packed struct" {
1338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13391338 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13401339 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13411341
13421342 const S = packed struct {
13431343 nested: packed union {
......@@ -1420,7 +1420,6 @@ test "union reassignment can use previous value" {
14201420}
14211421
14221422test "reinterpreting enum value inside packed union" {
1423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14241423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14251424
14261425 const U = packed union {
......@@ -1612,7 +1611,6 @@ test "memset extern union" {
16121611}
16131612
16141613test "memset packed union" {
1615 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16161614 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16171615
16181616 const U = packed union {
test/behavior/var_args.zig-1
......@@ -186,7 +186,6 @@ test "coerce reference to var arg" {
186186}
187187
188188test "variadic functions" {
189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
190189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
191190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
192191 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
test/behavior/vector.zig+21-57
......@@ -394,7 +394,6 @@ test "vector @splat" {
394394}
395395
396396test "load vector elements via comptime index" {
397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
398397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
399398 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
400399
......@@ -415,7 +414,6 @@ test "load vector elements via comptime index" {
415414}
416415
417416test "store vector elements via comptime index" {
418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
419417 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
420418 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421419
......@@ -441,49 +439,6 @@ test "store vector elements via comptime index" {
441439 try comptime S.doTheTest();
442440}
443441
444test "load vector elements via runtime index" {
445 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
446 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
447
448 const S = struct {
449 fn doTheTest() !void {
450 var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined };
451 _ = &v;
452 var i: u32 = 0;
453 try expect(v[i] == 1);
454 i += 1;
455 try expect(v[i] == 2);
456 i += 1;
457 try expect(v[i] == 3);
458 }
459 };
460
461 try S.doTheTest();
462 try comptime S.doTheTest();
463}
464
465test "store vector elements via runtime index" {
466 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
467 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
468 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
469
470 const S = struct {
471 fn doTheTest() !void {
472 var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined };
473 var i: u32 = 2;
474 v[i] = 1;
475 try expect(v[1] == 5);
476 try expect(v[2] == 1);
477 i += 1;
478 v[i] = -364;
479 try expect(-364 == v[3]);
480 }
481 };
482
483 try S.doTheTest();
484 try comptime S.doTheTest();
485}
486
487442test "initialize vector which is a struct field" {
488443 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
489444 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -567,20 +522,20 @@ test "vector division operators" {
567522 };
568523 if (!is_signed_int) {
569524 const d0 = x / y;
570 for (@as([4]T, d0), 0..) |v, i| {
525 inline for (@as([4]T, d0), 0..) |v, i| {
571526 try expect(x[i] / y[i] == v);
572527 }
573528 }
574529 const d1 = @divExact(x, y);
575 for (@as([4]T, d1), 0..) |v, i| {
530 inline for (@as([4]T, d1), 0..) |v, i| {
576531 try expect(@divExact(x[i], y[i]) == v);
577532 }
578533 const d2 = @divFloor(x, y);
579 for (@as([4]T, d2), 0..) |v, i| {
534 inline for (@as([4]T, d2), 0..) |v, i| {
580535 try expect(@divFloor(x[i], y[i]) == v);
581536 }
582537 const d3 = @divTrunc(x, y);
583 for (@as([4]T, d3), 0..) |v, i| {
538 inline for (@as([4]T, d3), 0..) |v, i| {
584539 try expect(@divTrunc(x[i], y[i]) == v);
585540 }
586541 }
......@@ -592,16 +547,16 @@ test "vector division operators" {
592547 };
593548 if (!is_signed_int and @typeInfo(T) != .float) {
594549 const r0 = x % y;
595 for (@as([4]T, r0), 0..) |v, i| {
550 inline for (@as([4]T, r0), 0..) |v, i| {
596551 try expect(x[i] % y[i] == v);
597552 }
598553 }
599554 const r1 = @mod(x, y);
600 for (@as([4]T, r1), 0..) |v, i| {
555 inline for (@as([4]T, r1), 0..) |v, i| {
601556 try expect(@mod(x[i], y[i]) == v);
602557 }
603558 const r2 = @rem(x, y);
604 for (@as([4]T, r2), 0..) |v, i| {
559 inline for (@as([4]T, r2), 0..) |v, i| {
605560 try expect(@rem(x[i], y[i]) == v);
606561 }
607562 }
......@@ -651,10 +606,15 @@ test "vector bitwise not operator" {
651606 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
652607 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
653608
609 if (builtin.cpu.arch == .aarch64_be) {
610 // https://github.com/ziglang/zig/issues/24061
611 return error.SkipZigTest;
612 }
613
654614 const S = struct {
655615 fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void {
656616 const y = ~x;
657 for (@as([4]T, y), 0..) |v, i| {
617 inline for (@as([4]T, y), 0..) |v, i| {
658618 try expect(~x[i] == v);
659619 }
660620 }
......@@ -685,10 +645,15 @@ test "vector boolean not operator" {
685645 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
686646 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
687647
648 if (builtin.cpu.arch == .aarch64_be) {
649 // https://github.com/ziglang/zig/issues/24061
650 return error.SkipZigTest;
651 }
652
688653 const S = struct {
689654 fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void {
690655 const y = !x;
691 for (@as([4]T, y), 0..) |v, i| {
656 inline for (@as([4]T, y), 0..) |v, i| {
692657 try expect(!x[i] == v);
693658 }
694659 }
......@@ -1359,7 +1324,6 @@ test "alignment of vectors" {
13591324}
13601325
13611326test "loading the second vector from a slice of vectors" {
1362 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13631327 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
13641328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13651329 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1450,6 +1414,7 @@ test "zero multiplicand" {
14501414 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14511415 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14521416 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
1417 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14531418
14541419 const zeros = @Vector(2, u32){ 0.0, 0.0 };
14551420 var ones = @Vector(2, u32){ 1.0, 1.0 };
......@@ -1530,8 +1495,7 @@ test "store packed vector element" {
15301495
15311496 var v = @Vector(4, u1){ 1, 1, 1, 1 };
15321497 try expectEqual(@Vector(4, u1){ 1, 1, 1, 1 }, v);
1533 var index: usize = 0;
1534 _ = &index;
1498 const index: usize = 0;
15351499 v[index] = 0;
15361500 try expectEqual(@Vector(4, u1){ 0, 1, 1, 1 }, v);
15371501}
test/behavior/x86_64/access.zig+3-10
......@@ -52,22 +52,15 @@ fn accessVector(comptime init: anytype) !void {
5252 var vector: Vector = undefined;
5353 vector = init;
5454 inline for (0..@typeInfo(Vector).vector.len) |ct_index| {
55 var rt_index: usize = undefined;
56 rt_index = ct_index;
57 if (&vector[rt_index] != &vector[ct_index]) return error.Unexpected;
58 if (vector[rt_index] != init[ct_index]) return error.Unexpected;
55 if (&vector[ct_index] != &vector[ct_index]) return error.Unexpected;
5956 if (vector[ct_index] != init[ct_index]) return error.Unexpected;
60 vector[rt_index] = rt_vals[0];
61 if (vector[rt_index] != ct_vals[0]) return error.Unexpected;
57 vector[ct_index] = rt_vals[0];
6258 if (vector[ct_index] != ct_vals[0]) return error.Unexpected;
63 vector[rt_index] = ct_vals[1];
64 if (vector[rt_index] != ct_vals[1]) return error.Unexpected;
59 vector[ct_index] = ct_vals[1];
6560 if (vector[ct_index] != ct_vals[1]) return error.Unexpected;
6661 vector[ct_index] = ct_vals[0];
67 if (vector[rt_index] != ct_vals[0]) return error.Unexpected;
6862 if (vector[ct_index] != ct_vals[0]) return error.Unexpected;
6963 vector[ct_index] = rt_vals[1];
70 if (vector[rt_index] != ct_vals[1]) return error.Unexpected;
7164 if (vector[ct_index] != ct_vals[1]) return error.Unexpected;
7265 }
7366}
test/cases/compile_errors/comptime_var_referenced_at_runtime.zig+10-10
......@@ -75,31 +75,31 @@ export fn bax() void {
7575//
7676// :5:19: error: runtime value contains reference to comptime var
7777// :5:19: note: comptime var pointers are not available at runtime
78// :4:27: note: 'runtime_value' points to comptime var declared here
78// :4:14: note: 'runtime_value' points to comptime var declared here
7979// :12:40: error: runtime value contains reference to comptime var
8080// :12:40: note: comptime var pointers are not available at runtime
81// :11:27: note: 'runtime_value' points to comptime var declared here
81// :11:14: note: 'runtime_value' points to comptime var declared here
8282// :19:50: error: runtime value contains reference to comptime var
8383// :19:50: note: comptime var pointers are not available at runtime
84// :18:27: note: 'runtime_value' points to comptime var declared here
84// :18:14: note: 'runtime_value' points to comptime var declared here
8585// :28:9: error: runtime value contains reference to comptime var
8686// :28:9: note: comptime var pointers are not available at runtime
87// :27:27: note: 'runtime_value' points to comptime var declared here
87// :27:14: note: 'runtime_value' points to comptime var declared here
8888// :36:9: error: runtime value contains reference to comptime var
8989// :36:9: note: comptime var pointers are not available at runtime
90// :35:27: note: 'runtime_value' points to comptime var declared here
90// :35:14: note: 'runtime_value' points to comptime var declared here
9191// :41:12: error: runtime value contains reference to comptime var
9292// :41:12: note: comptime var pointers are not available at runtime
93// :40:27: note: 'runtime_value' points to comptime var declared here
93// :40:14: note: 'runtime_value' points to comptime var declared here
9494// :46:39: error: runtime value contains reference to comptime var
9595// :46:39: note: comptime var pointers are not available at runtime
96// :45:27: note: 'runtime_value' points to comptime var declared here
96// :45:14: note: 'runtime_value' points to comptime var declared here
9797// :55:18: error: runtime value contains reference to comptime var
9898// :55:18: note: comptime var pointers are not available at runtime
99// :51:30: note: 'runtime_value' points to comptime var declared here
99// :51:14: note: 'runtime_value' points to comptime var declared here
100100// :63:18: error: runtime value contains reference to comptime var
101101// :63:18: note: comptime var pointers are not available at runtime
102// :59:27: note: 'runtime_value' points to comptime var declared here
102// :59:14: note: 'runtime_value' points to comptime var declared here
103103// :71:19: error: runtime value contains reference to comptime var
104104// :71:19: note: comptime var pointers are not available at runtime
105// :67:30: note: 'runtime_value' points to comptime var declared here
105// :67:14: note: 'runtime_value' points to comptime var declared here
test/cases/compile_errors/comptime_var_referenced_by_decl.zig+8-8
......@@ -47,19 +47,19 @@ export var h: *[1]u32 = h: {
4747// error
4848//
4949// :1:27: error: global variable contains reference to comptime var
50// :2:18: note: 'a' points to comptime var declared here
50// :2:5: note: 'a' points to comptime var declared here
5151// :6:30: error: global variable contains reference to comptime var
52// :7:18: note: 'b[0]' points to comptime var declared here
52// :7:5: note: 'b[0]' points to comptime var declared here
5353// :11:30: error: global variable contains reference to comptime var
54// :12:18: note: 'c' points to comptime var declared here
54// :12:5: note: 'c' points to comptime var declared here
5555// :16:33: error: global variable contains reference to comptime var
56// :17:18: note: 'd' points to comptime var declared here
56// :17:5: note: 'd' points to comptime var declared here
5757// :22:24: error: global variable contains reference to comptime var
58// :23:18: note: 'e.ptr' points to comptime var declared here
58// :23:5: note: 'e.ptr' points to comptime var declared here
5959// :28:33: error: global variable contains reference to comptime var
60// :29:18: note: 'f' points to comptime var declared here
60// :29:5: note: 'f' points to comptime var declared here
6161// :34:40: error: global variable contains reference to comptime var
6262// :34:40: note: 'g' points to 'v0[0]', where
63// :36:24: note: 'v0[1]' points to comptime var declared here
63// :36:5: note: 'v0[1]' points to comptime var declared here
6464// :42:28: error: global variable contains reference to comptime var
65// :43:22: note: 'h' points to comptime var declared here
65// :43:5: note: 'h' points to comptime var declared here
test/cases/compile_errors/comptime_var_referenced_by_type.zig+2-1
......@@ -21,5 +21,6 @@ comptime {
2121// error
2222//
2323// :7:16: error: captured value contains reference to comptime var
24// :16:30: note: 'wrapper.ptr' points to comptime var declared here
24// :7:16: note: 'wrapper' points to '@as(*const tmp.Wrapper, @ptrCast(&v0)).*', where
25// :16:5: note: 'v0.ptr' points to comptime var declared here
2526// :17:29: note: called at comptime here
test/cases/compile_errors/enum_field_value_references_enum.zig+2
......@@ -1,6 +1,8 @@
11pub const Foo = enum(c_int) {
22 A = Foo.B,
33 C = D,
4
5 pub const B = 0;
46};
57export fn entry() void {
68 const s: Foo = Foo.E;
test/cases/compile_errors/enum_field_value_references_nonexistent_circular.zig created+13
......@@ -0,0 +1,13 @@
1pub const Foo = enum(c_int) {
2 A = Foo.B,
3 C = D,
4};
5export fn entry() void {
6 const s: Foo = Foo.E;
7 _ = s;
8}
9const D = 1;
10
11// error
12//
13// :1:5: error: dependency loop detected
test/cases/compile_errors/for_comptime_array_pointer.zig+1-1
......@@ -9,4 +9,4 @@ export fn foo() void {
99//
1010// :3:10: error: runtime value contains reference to comptime var
1111// :3:10: note: comptime var pointers are not available at runtime
12// :2:34: note: 'runtime_value' points to comptime var declared here
12// :2:14: note: 'runtime_value' points to comptime var declared here
test/cases/compile_errors/implicitly_increasing_pointer_alignment.zig deleted-19
......@@ -1,19 +0,0 @@
1const Foo = packed struct {
2 a: u8,
3 b: u32,
4};
5
6export fn entry() void {
7 var foo = Foo{ .a = 1, .b = 10 };
8 bar(&foo.b);
9}
10
11fn bar(x: *u32) void {
12 x.* += 1;
13}
14
15// error
16//
17// :8:9: error: expected type '*u32', found '*align(1) u32'
18// :8:9: note: pointer alignment '1' cannot cast into pointer alignment '4'
19// :11:11: note: parameter type declared here
test/cases/compile_errors/implicitly_increasing_slice_alignment.zig deleted-19
......@@ -1,19 +0,0 @@
1const Foo = packed struct {
2 a: u8,
3 b: u32,
4};
5
6export fn entry() void {
7 var foo = Foo{ .a = 1, .b = 10 };
8 foo.b += 1;
9 bar(@as(*[1]u32, &foo.b)[0..]);
10}
11
12fn bar(x: []u32) void {
13 x[0] += 1;
14}
15
16// error
17//
18// :9:22: error: expected type '*[1]u32', found '*align(1) u32'
19// :9:22: note: pointer alignment '1' cannot cast into pointer alignment '4'
test/cases/compile_errors/load_vector_pointer_with_unknown_runtime_index.zig+1-1
......@@ -12,4 +12,4 @@ fn loadv(ptr: anytype) i31 {
1212
1313// error
1414//
15// :10:15: error: unable to determine vector element index of type '*align(16:0:4:?) i31'
15// :5:22: error: vector index not comptime known
test/cases/compile_errors/store_vector_pointer_with_unknown_runtime_index.zig+1-1
......@@ -12,4 +12,4 @@ fn storev(ptr: anytype, val: i31) void {
1212
1313// error
1414//
15// :10:8: error: unable to determine vector element index of type '*align(16:0:4:?) i31'
15// :6:15: error: vector index not comptime known
test/cases/pie_linux.zig+1-1
......@@ -6,5 +6,5 @@ pub fn main() void {}
66
77// run
88// backend=llvm
9// target=arm-linux,armeb-linux,thumb-linux,thumbeb-linux,aarch64-linux,aarch64_be-linux,loongarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux,powerpc-linux,powerpcle-linux,powerpc64-linux,powerpc64le-linux,riscv32-linux,riscv64-linux,s390x-linux,x86-linux,x86_64-linux
9// target=arm-linux,armeb-linux,thumb-linux,thumbeb-linux,aarch64-linux,aarch64_be-linux,loongarch64-linux,mips-linux,mipsel-linux,mips64-linux,mips64el-linux,powerpc-linux,powerpcle-linux,powerpc64-linux,powerpc64le-linux,riscv32-linux,riscv64-linux,x86-linux,x86_64-linux
1010// pie=true
test/run_translated_c.zig-104
......@@ -1316,110 +1316,6 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
13161316 \\}
13171317 , "");
13181318
1319 cases.add("basic vector expressions",
1320 \\#include <stdlib.h>
1321 \\#include <stdint.h>
1322 \\typedef int16_t __v8hi __attribute__((__vector_size__(16)));
1323 \\int main(int argc, char**argv) {
1324 \\ __v8hi uninitialized;
1325 \\ __v8hi empty_init = {};
1326 \\ for (int i = 0; i < 8; i++) {
1327 \\ if (empty_init[i] != 0) abort();
1328 \\ }
1329 \\ __v8hi partial_init = {0, 1, 2, 3};
1330 \\
1331 \\ __v8hi a = {0, 1, 2, 3, 4, 5, 6, 7};
1332 \\ __v8hi b = (__v8hi) {100, 200, 300, 400, 500, 600, 700, 800};
1333 \\
1334 \\ __v8hi sum = a + b;
1335 \\ for (int i = 0; i < 8; i++) {
1336 \\ if (sum[i] != a[i] + b[i]) abort();
1337 \\ }
1338 \\ return 0;
1339 \\}
1340 , "");
1341
1342 cases.add("__builtin_shufflevector",
1343 \\#include <stdlib.h>
1344 \\#include <stdint.h>
1345 \\typedef int16_t __v4hi __attribute__((__vector_size__(8)));
1346 \\typedef int16_t __v8hi __attribute__((__vector_size__(16)));
1347 \\int main(int argc, char**argv) {
1348 \\ __v8hi v8_a = {0, 1, 2, 3, 4, 5, 6, 7};
1349 \\ __v8hi v8_b = {100, 200, 300, 400, 500, 600, 700, 800};
1350 \\ __v8hi shuffled = __builtin_shufflevector(v8_a, v8_b, 0, 1, 2, 3, 8, 9, 10, 11);
1351 \\ for (int i = 0; i < 8; i++) {
1352 \\ if (i < 4) {
1353 \\ if (shuffled[i] != v8_a[i]) abort();
1354 \\ } else {
1355 \\ if (shuffled[i] != v8_b[i - 4]) abort();
1356 \\ }
1357 \\ }
1358 \\ shuffled = __builtin_shufflevector(
1359 \\ (__v8hi) {-1, -1, -1, -1, -1, -1, -1, -1},
1360 \\ (__v8hi) {42, 42, 42, 42, 42, 42, 42, 42},
1361 \\ 0, 1, 2, 3, 8, 9, 10, 11
1362 \\ );
1363 \\ for (int i = 0; i < 8; i++) {
1364 \\ if (i < 4) {
1365 \\ if (shuffled[i] != -1) abort();
1366 \\ } else {
1367 \\ if (shuffled[i] != 42) abort();
1368 \\ }
1369 \\ }
1370 \\ __v4hi shuffled_to_fewer_elements = __builtin_shufflevector(v8_a, v8_b, 0, 1, 8, 9);
1371 \\ for (int i = 0; i < 4; i++) {
1372 \\ if (i < 2) {
1373 \\ if (shuffled_to_fewer_elements[i] != v8_a[i]) abort();
1374 \\ } else {
1375 \\ if (shuffled_to_fewer_elements[i] != v8_b[i - 2]) abort();
1376 \\ }
1377 \\ }
1378 \\ __v4hi v4_a = {0, 1, 2, 3};
1379 \\ __v4hi v4_b = {100, 200, 300, 400};
1380 \\ __v8hi shuffled_to_more_elements = __builtin_shufflevector(v4_a, v4_b, 0, 1, 2, 3, 4, 5, 6, 7);
1381 \\ for (int i = 0; i < 4; i++) {
1382 \\ if (shuffled_to_more_elements[i] != v4_a[i]) abort();
1383 \\ if (shuffled_to_more_elements[i + 4] != v4_b[i]) abort();
1384 \\ }
1385 \\ return 0;
1386 \\}
1387 , "");
1388
1389 cases.add("__builtin_convertvector",
1390 \\#include <stdlib.h>
1391 \\#include <stdint.h>
1392 \\typedef int16_t __v8hi __attribute__((__vector_size__(16)));
1393 \\typedef uint16_t __v8hu __attribute__((__vector_size__(16)));
1394 \\int main(int argc, char**argv) {
1395 \\ __v8hi signed_vector = { 1, 2, 3, 4, -1, -2, -3,-4};
1396 \\ __v8hu unsigned_vector = __builtin_convertvector(signed_vector, __v8hu);
1397 \\
1398 \\ for (int i = 0; i < 8; i++) {
1399 \\ if (unsigned_vector[i] != (uint16_t)signed_vector[i]) abort();
1400 \\ }
1401 \\ return 0;
1402 \\}
1403 , "");
1404
1405 cases.add("vector casting",
1406 \\#include <stdlib.h>
1407 \\#include <stdint.h>
1408 \\typedef int8_t __v8qi __attribute__((__vector_size__(8)));
1409 \\typedef uint8_t __v8qu __attribute__((__vector_size__(8)));
1410 \\int main(int argc, char**argv) {
1411 \\ __v8qi signed_vector = { 1, 2, 3, 4, -1, -2, -3,-4};
1412 \\
1413 \\ uint64_t big_int = (uint64_t) signed_vector;
1414 \\ if (big_int != 0x01020304FFFEFDFCULL && big_int != 0xFCFDFEFF04030201ULL) abort();
1415 \\ __v8qu unsigned_vector = (__v8qu) big_int;
1416 \\ for (int i = 0; i < 8; i++) {
1417 \\ if (unsigned_vector[i] != (uint8_t)signed_vector[i] && unsigned_vector[i] != (uint8_t)signed_vector[7 - i]) abort();
1418 \\ }
1419 \\ return 0;
1420 \\}
1421 , "");
1422
14231319 cases.add("break from switch statement. Issue #8387",
14241320 \\#include <stdlib.h>
14251321 \\int switcher(int x) {
test/standalone/stack_iterator/unwind_freestanding.zig+1-1
......@@ -37,7 +37,7 @@ noinline fn frame0(expected: *[4]usize, unwound: *[4]usize) void {
3737}
3838
3939// No-OS entrypoint
40export fn _start() callconv(.c) noreturn {
40export fn _start() callconv(.withStackAlign(.c, 1)) noreturn {
4141 var expected: [4]usize = undefined;
4242 var unwound: [4]usize = undefined;
4343 frame0(&expected, &unwound);
test/tests.zig+24-18
......@@ -1344,27 +1344,33 @@ const test_targets = blk: {
13441344
13451345 // SPIR-V Targets
13461346
1347 .{
1348 .target = std.Target.Query.parse(.{
1349 .arch_os_abi = "spirv64-vulkan",
1350 .cpu_features = "vulkan_v1_2+float16+float64",
1351 }) catch unreachable,
1352 .use_llvm = false,
1353 .use_lld = false,
1354 .skip_modules = &.{ "c-import", "zigc", "std" },
1355 },
1347 // Disabled due to no active maintainer (feel free to fix the failures
1348 // and then re-enable at any time). The failures occur due to changing AIR
1349 // from the frontend, and backend being incomplete.
1350 //.{
1351 // .target = std.Target.Query.parse(.{
1352 // .arch_os_abi = "spirv64-vulkan",
1353 // .cpu_features = "vulkan_v1_2+float16+float64",
1354 // }) catch unreachable,
1355 // .use_llvm = false,
1356 // .use_lld = false,
1357 // .skip_modules = &.{ "c-import", "zigc", "std" },
1358 //},
13561359
13571360 // WASI Targets
13581361
1359 .{
1360 .target = .{
1361 .cpu_arch = .wasm32,
1362 .os_tag = .wasi,
1363 .abi = .none,
1364 },
1365 .use_llvm = false,
1366 .use_lld = false,
1367 },
1362 // Disabled due to no active maintainer (feel free to fix the failures
1363 // and then re-enable at any time). The failures occur due to backend
1364 // miscompilation of different AIR from the frontend.
1365 //.{
1366 // .target = .{
1367 // .cpu_arch = .wasm32,
1368 // .os_tag = .wasi,
1369 // .abi = .none,
1370 // },
1371 // .use_llvm = false,
1372 // .use_lld = false,
1373 //},
13681374 .{
13691375 .target = .{
13701376 .cpu_arch = .wasm32,