| author | |
| committer | |
| log | 010d9a63f20d8a4bd14cff0ada690b2d127a0371 |
| tree | 12b56ddfe5a5b235ef0676832902a0b04ad7d57a |
| parent | 3fbb88c4bd146ca7bd9e7ab5da9c4b05298f3b34 |
| parent | 633162eb0c8d302ba7585cd308e01237409f042e |
| signature |
rework byval ZIR instructions; forbid runtime vector indexes58 files changed, 938 insertions(+), 1609 deletions(-)
doc/langref/test_overaligned_packed_struct.zig+1-1| ... | ... | @@ -8,7 +8,7 @@ const S = packed struct { |
| 8 | 8 | test "overaligned pointer to packed struct" { |
| 9 | 9 | var foo: S align(4) = .{ .a = 1, .b = 2 }; |
| 10 | 10 | const ptr: *align(4) S = &foo; |
| 11 | const ptr_to_b: *u32 = &ptr.b; | |
| 11 | const ptr_to_b = &ptr.b; | |
| 12 | 12 | try expect(ptr_to_b.* == 2); |
| 13 | 13 | } |
| 14 | 14 |
lib/std/Io/Writer.zig+21-15| ... | ... | @@ -1370,19 +1370,12 @@ pub fn printValue( |
| 1370 | 1370 | }, |
| 1371 | 1371 | .array => { |
| 1372 | 1372 | 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); | |
| 1382 | 1374 | }, |
| 1383 | .vector => { | |
| 1375 | .vector => |vector| { | |
| 1384 | 1376 | 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); | |
| 1386 | 1379 | }, |
| 1387 | 1380 | .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"), |
| 1388 | 1381 | .type => { |
| ... | ... | @@ -1436,12 +1429,25 @@ pub fn printVector( |
| 1436 | 1429 | value: anytype, |
| 1437 | 1430 | max_depth: usize, |
| 1438 | 1431 | ) 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 | ||
| 1437 | pub 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 { | |
| 1440 | 1444 | if (max_depth == 0) return w.writeAll("{ ... }"); |
| 1441 | 1445 | 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 | } | |
| 1445 | 1451 | } |
| 1446 | 1452 | try w.writeAll(" }"); |
| 1447 | 1453 | } |
lib/std/Progress.zig+15-5| ... | ... | @@ -1248,7 +1248,9 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } { |
| 1248 | 1248 | i += progress_pulsing.len; |
| 1249 | 1249 | } else { |
| 1250 | 1250 | 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 |_| {} | |
| 1252 | 1254 | } |
| 1253 | 1255 | }, |
| 1254 | 1256 | .success => { |
| ... | ... | @@ -1265,7 +1267,9 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } { |
| 1265 | 1267 | i += progress_pulsing_error.len; |
| 1266 | 1268 | } else { |
| 1267 | 1269 | 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 |_| {} | |
| 1269 | 1273 | } |
| 1270 | 1274 | }, |
| 1271 | 1275 | } |
| ... | ... | @@ -1364,12 +1368,18 @@ fn computeNode( |
| 1364 | 1368 | if (!is_empty_root) { |
| 1365 | 1369 | if (name.len != 0 or estimated_total > 0) { |
| 1366 | 1370 | 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 |_| {} | |
| 1368 | 1374 | } 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 |_| {} | |
| 1370 | 1378 | } |
| 1371 | 1379 | 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 |_| {} | |
| 1373 | 1383 | } |
| 1374 | 1384 | } |
| 1375 | 1385 |
lib/std/Target.zig+1-1| ... | ... | @@ -1187,7 +1187,7 @@ pub const Cpu = struct { |
| 1187 | 1187 | pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize))); |
| 1188 | 1188 | pub const ShiftInt = std.math.Log2Int(usize); |
| 1189 | 1189 | |
| 1190 | pub const empty = Set{ .ints = [1]usize{0} ** usize_count }; | |
| 1190 | pub const empty: Set = .{ .ints = @splat(0) }; | |
| 1191 | 1191 | |
| 1192 | 1192 | pub fn isEmpty(set: Set) bool { |
| 1193 | 1193 | return for (set.ints) |x| { |
lib/std/Thread.zig+5| ... | ... | @@ -1661,6 +1661,11 @@ test "Thread.getCurrentId" { |
| 1661 | 1661 | test "thread local storage" { |
| 1662 | 1662 | if (builtin.single_threaded) return error.SkipZigTest; |
| 1663 | 1663 | |
| 1664 | if (builtin.cpu.arch == .thumbeb) { | |
| 1665 | // https://github.com/ziglang/zig/issues/24061 | |
| 1666 | return error.SkipZigTest; | |
| 1667 | } | |
| 1668 | ||
| 1664 | 1669 | const thread1 = try Thread.spawn(.{}, testTls, .{}); |
| 1665 | 1670 | const thread2 = try Thread.spawn(.{}, testTls, .{}); |
| 1666 | 1671 | try testTls(); |
lib/std/crypto/chacha20.zig+11-11| ... | ... | @@ -215,8 +215,8 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 215 | 215 | } |
| 216 | 216 | } |
| 217 | 217 | |
| 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| { | |
| 220 | 220 | for (0..4) |i| { |
| 221 | 221 | mem.writeInt(u32, out[64 * d + 16 * i + 0 ..][0..4], x[i][0 + 4 * d], .little); |
| 222 | 222 | 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 |
| 242 | 242 | while (degree >= d and i + 64 * d <= in.len) : (i += 64 * d) { |
| 243 | 243 | chacha20Core(x[0..], ctx); |
| 244 | 244 | contextFeedback(&x, ctx); |
| 245 | hashToBytes(d, buf[0 .. 64 * d], x); | |
| 245 | hashToBytes(d, buf[0 .. 64 * d], &x); | |
| 246 | 246 | |
| 247 | 247 | var xout = out[i..]; |
| 248 | 248 | const xin = in[i..]; |
| ... | ... | @@ -266,7 +266,7 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 266 | 266 | if (i < in.len) { |
| 267 | 267 | chacha20Core(x[0..], ctx); |
| 268 | 268 | contextFeedback(&x, ctx); |
| 269 | hashToBytes(1, buf[0..64], x); | |
| 269 | hashToBytes(1, buf[0..64], &x); | |
| 270 | 270 | |
| 271 | 271 | var xout = out[i..]; |
| 272 | 272 | const xin = in[i..]; |
| ... | ... | @@ -284,7 +284,7 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 284 | 284 | while (degree >= d and i + 64 * d <= out.len) : (i += 64 * d) { |
| 285 | 285 | chacha20Core(x[0..], ctx); |
| 286 | 286 | contextFeedback(&x, ctx); |
| 287 | hashToBytes(d, out[i..][0 .. 64 * d], x); | |
| 287 | hashToBytes(d, out[i..][0 .. 64 * d], &x); | |
| 288 | 288 | inline for (0..d) |d_| { |
| 289 | 289 | if (count64) { |
| 290 | 290 | const next = @addWithOverflow(ctx[3][4 * d_], d); |
| ... | ... | @@ -301,7 +301,7 @@ fn ChaChaVecImpl(comptime rounds_nb: usize, comptime degree: comptime_int) type |
| 301 | 301 | contextFeedback(&x, ctx); |
| 302 | 302 | |
| 303 | 303 | var buf: [64]u8 = undefined; |
| 304 | hashToBytes(1, buf[0..], x); | |
| 304 | hashToBytes(1, buf[0..], &x); | |
| 305 | 305 | @memcpy(out[i..], buf[0 .. out.len - i]); |
| 306 | 306 | } |
| 307 | 307 | } |
| ... | ... | @@ -394,7 +394,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { |
| 394 | 394 | } |
| 395 | 395 | } |
| 396 | 396 | |
| 397 | fn hashToBytes(out: *[64]u8, x: BlockVec) void { | |
| 397 | fn hashToBytes(out: *[64]u8, x: *const BlockVec) void { | |
| 398 | 398 | for (0..4) |i| { |
| 399 | 399 | mem.writeInt(u32, out[16 * i + 0 ..][0..4], x[i * 4 + 0], .little); |
| 400 | 400 | 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 { |
| 417 | 417 | while (i + 64 <= in.len) : (i += 64) { |
| 418 | 418 | chacha20Core(x[0..], ctx); |
| 419 | 419 | contextFeedback(&x, ctx); |
| 420 | hashToBytes(buf[0..], x); | |
| 420 | hashToBytes(buf[0..], &x); | |
| 421 | 421 | |
| 422 | 422 | var xout = out[i..]; |
| 423 | 423 | const xin = in[i..]; |
| ... | ... | @@ -438,7 +438,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { |
| 438 | 438 | if (i < in.len) { |
| 439 | 439 | chacha20Core(x[0..], ctx); |
| 440 | 440 | contextFeedback(&x, ctx); |
| 441 | hashToBytes(buf[0..], x); | |
| 441 | hashToBytes(buf[0..], &x); | |
| 442 | 442 | |
| 443 | 443 | var xout = out[i..]; |
| 444 | 444 | const xin = in[i..]; |
| ... | ... | @@ -455,7 +455,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { |
| 455 | 455 | while (i + 64 <= out.len) : (i += 64) { |
| 456 | 456 | chacha20Core(x[0..], ctx); |
| 457 | 457 | contextFeedback(&x, ctx); |
| 458 | hashToBytes(out[i..][0..64], x); | |
| 458 | hashToBytes(out[i..][0..64], &x); | |
| 459 | 459 | if (count64) { |
| 460 | 460 | const next = @addWithOverflow(ctx[12], 1); |
| 461 | 461 | ctx[12] = next[0]; |
| ... | ... | @@ -469,7 +469,7 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type { |
| 469 | 469 | contextFeedback(&x, ctx); |
| 470 | 470 | |
| 471 | 471 | var buf: [64]u8 = undefined; |
| 472 | hashToBytes(buf[0..], x); | |
| 472 | hashToBytes(buf[0..], &x); | |
| 473 | 473 | @memcpy(out[i..], buf[0 .. out.len - i]); |
| 474 | 474 | } |
| 475 | 475 | } |
lib/std/json/static.zig+8-9| ... | ... | @@ -389,7 +389,7 @@ pub fn innerParse( |
| 389 | 389 | switch (try source.peekNextTokenType()) { |
| 390 | 390 | .array_begin => { |
| 391 | 391 | // Typical array. |
| 392 | return internalParseArray(T, arrayInfo.child, arrayInfo.len, allocator, source, options); | |
| 392 | return internalParseArray(T, arrayInfo.child, allocator, source, options); | |
| 393 | 393 | }, |
| 394 | 394 | .string => { |
| 395 | 395 | if (arrayInfo.child != u8) return error.UnexpectedToken; |
| ... | ... | @@ -440,10 +440,11 @@ pub fn innerParse( |
| 440 | 440 | } |
| 441 | 441 | }, |
| 442 | 442 | |
| 443 | .vector => |vecInfo| { | |
| 443 | .vector => |vector_info| { | |
| 444 | 444 | switch (try source.peekNextTokenType()) { |
| 445 | 445 | .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); | |
| 447 | 448 | }, |
| 448 | 449 | else => return error.UnexpectedToken, |
| 449 | 450 | } |
| ... | ... | @@ -519,7 +520,6 @@ pub fn innerParse( |
| 519 | 520 | fn internalParseArray( |
| 520 | 521 | comptime T: type, |
| 521 | 522 | comptime Child: type, |
| 522 | comptime len: comptime_int, | |
| 523 | 523 | allocator: Allocator, |
| 524 | 524 | source: anytype, |
| 525 | 525 | options: ParseOptions, |
| ... | ... | @@ -527,9 +527,8 @@ fn internalParseArray( |
| 527 | 527 | assert(.array_begin == try source.next()); |
| 528 | 528 | |
| 529 | 529 | 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); | |
| 533 | 532 | } |
| 534 | 533 | |
| 535 | 534 | if (.array_end != try source.next()) return error.UnexpectedToken; |
| ... | ... | @@ -569,12 +568,12 @@ pub fn innerParseFromValue( |
| 569 | 568 | if (@round(f) != f) return error.InvalidNumber; |
| 570 | 569 | if (f > @as(@TypeOf(f), @floatFromInt(std.math.maxInt(T)))) return error.Overflow; |
| 571 | 570 | if (f < @as(@TypeOf(f), @floatFromInt(std.math.minInt(T)))) return error.Overflow; |
| 572 | return @as(T, @intFromFloat(f)); | |
| 571 | return @intFromFloat(f); | |
| 573 | 572 | }, |
| 574 | 573 | .integer => |i| { |
| 575 | 574 | if (i > std.math.maxInt(T)) return error.Overflow; |
| 576 | 575 | if (i < std.math.minInt(T)) return error.Overflow; |
| 577 | return @as(T, @intCast(i)); | |
| 576 | return @intCast(i); | |
| 578 | 577 | }, |
| 579 | 578 | .number_string, .string => |s| { |
| 580 | 579 | return sliceToInt(T, s); |
lib/std/meta.zig+1-7| ... | ... | @@ -742,13 +742,7 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool { |
| 742 | 742 | if (!eql(e, b[i])) return false; |
| 743 | 743 | return true; |
| 744 | 744 | }, |
| 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), | |
| 752 | 746 | .pointer => |info| { |
| 753 | 747 | return switch (info.size) { |
| 754 | 748 | .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 { |
| 135 | 135 | .array => |array| try expectEqualSlices(array.child, &expected, &actual), |
| 136 | 136 | |
| 137 | 137 | .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); | |
| 147 | 141 | }, |
| 148 | 142 | |
| 149 | 143 | .@"struct" => |structType| { |
| ... | ... | @@ -828,8 +822,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe |
| 828 | 822 | print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).vector.len }); |
| 829 | 823 | return error.TestExpectedEqual; |
| 830 | 824 | } |
| 831 | var i: usize = 0; | |
| 832 | while (i < info.len) : (i += 1) { | |
| 825 | inline for (0..info.len) |i| { | |
| 833 | 826 | expectEqualDeep(expected[i], actual[i]) catch |e| { |
| 834 | 827 | print("index {d} incorrect. expected {any}, found {any}\n", .{ |
| 835 | 828 | 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 |
| 2728 | 2728 | .elem_ptr, |
| 2729 | 2729 | .elem_val, |
| 2730 | 2730 | .elem_ptr_node, |
| 2731 | .elem_val_node, | |
| 2731 | .elem_ptr_load, | |
| 2732 | 2732 | .elem_val_imm, |
| 2733 | 2733 | .field_ptr, |
| 2734 | .field_val, | |
| 2734 | .field_ptr_load, | |
| 2735 | 2735 | .field_ptr_named, |
| 2736 | .field_val_named, | |
| 2736 | .field_ptr_named_load, | |
| 2737 | 2737 | .func, |
| 2738 | 2738 | .func_inferred, |
| 2739 | 2739 | .func_fancy, |
| ... | ... | @@ -6160,7 +6160,7 @@ fn fieldAccess( |
| 6160 | 6160 | switch (ri.rl) { |
| 6161 | 6161 | .ref, .ref_coerced_ty => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node), |
| 6162 | 6162 | 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); | |
| 6164 | 6164 | return rvalue(gz, ri, access, node); |
| 6165 | 6165 | }, |
| 6166 | 6166 | } |
| ... | ... | @@ -6210,14 +6210,14 @@ fn arrayAccess( |
| 6210 | 6210 | }, |
| 6211 | 6211 | else => { |
| 6212 | 6212 | 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); | |
| 6214 | 6214 | |
| 6215 | 6215 | const cursor = maybeAdvanceSourceCursorToMainToken(gz, node); |
| 6216 | 6216 | |
| 6217 | 6217 | const rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, rhs_node); |
| 6218 | 6218 | try emitDbgStmt(gz, cursor); |
| 6219 | 6219 | |
| 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); | |
| 6221 | 6221 | }, |
| 6222 | 6222 | } |
| 6223 | 6223 | } |
| ... | ... | @@ -9286,17 +9286,21 @@ fn builtinCall( |
| 9286 | 9286 | return rvalue(gz, ri, result, node); |
| 9287 | 9287 | }, |
| 9288 | 9288 | .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 | }, | |
| 9294 | 9303 | } |
| 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); | |
| 9300 | 9304 | }, |
| 9301 | 9305 | .FieldType => { |
| 9302 | 9306 | const ty_inst = try typeExpr(gz, scope, params[0]); |
lib/std/zig/Zir.zig+34-21| ... | ... | @@ -420,6 +420,7 @@ pub const Inst = struct { |
| 420 | 420 | /// is the local's value. |
| 421 | 421 | dbg_var_val, |
| 422 | 422 | /// Uses a name to identify a Decl and takes a pointer to it. |
| 423 | /// | |
| 423 | 424 | /// Uses the `str_tok` union field. |
| 424 | 425 | decl_ref, |
| 425 | 426 | /// Uses a name to identify a Decl and uses it as a value. |
| ... | ... | @@ -440,12 +441,17 @@ pub const Inst = struct { |
| 440 | 441 | /// Payload is `Bin`. |
| 441 | 442 | /// No OOB safety check is emitted. |
| 442 | 443 | 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 | /// | |
| 444 | 447 | /// 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 | /// | |
| 449 | 455 | /// No OOB safety check is emitted. |
| 450 | 456 | elem_val, |
| 451 | 457 | /// Same as `elem_val` but takes the index as an immediate value. |
| ... | ... | @@ -472,19 +478,26 @@ pub const Inst = struct { |
| 472 | 478 | /// to the named field. The field name is stored in string_bytes. Used by a.b syntax. |
| 473 | 479 | /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. |
| 474 | 480 | 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 | /// | |
| 476 | 484 | /// The field name is stored in string_bytes. Used by a.b syntax. |
| 485 | /// | |
| 477 | 486 | /// This instruction also accepts a pointer. |
| 487 | /// | |
| 478 | 488 | /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field. |
| 479 | field_val, | |
| 489 | field_ptr_load, | |
| 480 | 490 | /// Given a pointer to a struct or object that contains virtual fields, returns a pointer |
| 481 | 491 | /// to the named field. The field name is a comptime instruction. Used by @field. |
| 482 | 492 | /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed. |
| 483 | 493 | 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 | /// | |
| 485 | 497 | /// The field name is a comptime instruction. Used by @field. |
| 498 | /// | |
| 486 | 499 | /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed. |
| 487 | field_val_named, | |
| 500 | field_ptr_named_load, | |
| 488 | 501 | /// Returns a function type, or a function instance, depending on whether |
| 489 | 502 | /// the body_len is 0. Calling convention is auto. |
| 490 | 503 | /// Uses the `pl_node` union field. `payload_index` points to a `Func`. |
| ... | ... | @@ -1138,16 +1151,16 @@ pub const Inst = struct { |
| 1138 | 1151 | .elem_ptr, |
| 1139 | 1152 | .elem_val, |
| 1140 | 1153 | .elem_ptr_node, |
| 1141 | .elem_val_node, | |
| 1154 | .elem_ptr_load, | |
| 1142 | 1155 | .elem_val_imm, |
| 1143 | 1156 | .ensure_result_used, |
| 1144 | 1157 | .ensure_result_non_error, |
| 1145 | 1158 | .ensure_err_union_payload_void, |
| 1146 | 1159 | .@"export", |
| 1147 | 1160 | .field_ptr, |
| 1148 | .field_val, | |
| 1161 | .field_ptr_load, | |
| 1149 | 1162 | .field_ptr_named, |
| 1150 | .field_val_named, | |
| 1163 | .field_ptr_named_load, | |
| 1151 | 1164 | .func, |
| 1152 | 1165 | .func_inferred, |
| 1153 | 1166 | .func_fancy, |
| ... | ... | @@ -1432,12 +1445,12 @@ pub const Inst = struct { |
| 1432 | 1445 | .elem_ptr, |
| 1433 | 1446 | .elem_val, |
| 1434 | 1447 | .elem_ptr_node, |
| 1435 | .elem_val_node, | |
| 1448 | .elem_ptr_load, | |
| 1436 | 1449 | .elem_val_imm, |
| 1437 | 1450 | .field_ptr, |
| 1438 | .field_val, | |
| 1451 | .field_ptr_load, | |
| 1439 | 1452 | .field_ptr_named, |
| 1440 | .field_val_named, | |
| 1453 | .field_ptr_named_load, | |
| 1441 | 1454 | .func, |
| 1442 | 1455 | .func_inferred, |
| 1443 | 1456 | .func_fancy, |
| ... | ... | @@ -1679,7 +1692,7 @@ pub const Inst = struct { |
| 1679 | 1692 | .elem_ptr = .pl_node, |
| 1680 | 1693 | .elem_ptr_node = .pl_node, |
| 1681 | 1694 | .elem_val = .pl_node, |
| 1682 | .elem_val_node = .pl_node, | |
| 1695 | .elem_ptr_load = .pl_node, | |
| 1683 | 1696 | .elem_val_imm = .elem_val_imm, |
| 1684 | 1697 | .ensure_result_used = .un_node, |
| 1685 | 1698 | .ensure_result_non_error = .un_node, |
| ... | ... | @@ -1688,9 +1701,9 @@ pub const Inst = struct { |
| 1688 | 1701 | .error_value = .str_tok, |
| 1689 | 1702 | .@"export" = .pl_node, |
| 1690 | 1703 | .field_ptr = .pl_node, |
| 1691 | .field_val = .pl_node, | |
| 1704 | .field_ptr_load = .pl_node, | |
| 1692 | 1705 | .field_ptr_named = .pl_node, |
| 1693 | .field_val_named = .pl_node, | |
| 1706 | .field_ptr_named_load = .pl_node, | |
| 1694 | 1707 | .func = .pl_node, |
| 1695 | 1708 | .func_inferred = .pl_node, |
| 1696 | 1709 | .func_fancy = .pl_node, |
| ... | ... | @@ -4215,7 +4228,7 @@ fn findTrackableInner( |
| 4215 | 4228 | .div, |
| 4216 | 4229 | .elem_ptr_node, |
| 4217 | 4230 | .elem_ptr, |
| 4218 | .elem_val_node, | |
| 4231 | .elem_ptr_load, | |
| 4219 | 4232 | .elem_val, |
| 4220 | 4233 | .elem_val_imm, |
| 4221 | 4234 | .ensure_result_used, |
| ... | ... | @@ -4225,9 +4238,9 @@ fn findTrackableInner( |
| 4225 | 4238 | .error_value, |
| 4226 | 4239 | .@"export", |
| 4227 | 4240 | .field_ptr, |
| 4228 | .field_val, | |
| 4241 | .field_ptr_load, | |
| 4229 | 4242 | .field_ptr_named, |
| 4230 | .field_val_named, | |
| 4243 | .field_ptr_named_load, | |
| 4231 | 4244 | .import, |
| 4232 | 4245 | .int, |
| 4233 | 4246 | .int_big, |
lib/std/zon/Serializer.zig+15-16| ... | ... | @@ -157,13 +157,11 @@ pub fn valueArbitraryDepth(self: *Serializer, val: anytype, options: ValueOption |
| 157 | 157 | } |
| 158 | 158 | }, |
| 159 | 159 | .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); | |
| 167 | 165 | }, |
| 168 | 166 | .@"struct" => |@"struct"| if (@"struct".is_tuple) { |
| 169 | 167 | var container = try self.beginTuple( |
| ... | ... | @@ -231,20 +229,21 @@ pub fn valueArbitraryDepth(self: *Serializer, val: anytype, options: ValueOption |
| 231 | 229 | } else { |
| 232 | 230 | try self.writer.writeAll("null"); |
| 233 | 231 | }, |
| 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 | }, | |
| 243 | 232 | |
| 244 | 233 | else => comptime unreachable, |
| 245 | 234 | } |
| 246 | 235 | } |
| 247 | 236 | |
| 237 | fn 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 | ||
| 248 | 247 | /// Serialize an integer. |
| 249 | 248 | pub fn int(self: *Serializer, val: anytype) Error!void { |
| 250 | 249 | 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 { |
| 430 | 430 | .many, .c => comptime unreachable, |
| 431 | 431 | } |
| 432 | 432 | }, |
| 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); | |
| 435 | 439 | }, |
| 436 | 440 | .@"struct" => |@"struct"| inline for (@"struct".fields) |field| { |
| 437 | 441 | free(gpa, @field(value, field.name)); |
| ... | ... | @@ -446,12 +450,15 @@ pub fn free(gpa: Allocator, value: anytype) void { |
| 446 | 450 | .optional => if (value) |some| { |
| 447 | 451 | free(gpa, some); |
| 448 | 452 | }, |
| 449 | .vector => |vector| for (0..vector.len) |i| free(gpa, value[i]), | |
| 450 | 453 | .void => {}, |
| 451 | 454 | else => comptime unreachable, |
| 452 | 455 | } |
| 453 | 456 | } |
| 454 | 457 | |
| 458 | fn freeArray(gpa: Allocator, comptime A: type, array: *const A) void { | |
| 459 | for (array) |elem| free(gpa, elem); | |
| 460 | } | |
| 461 | ||
| 455 | 462 | fn requiresAllocator(T: type) bool { |
| 456 | 463 | _ = valid_types; |
| 457 | 464 | return switch (@typeInfo(T)) { |
| ... | ... | @@ -521,12 +528,15 @@ const Parser = struct { |
| 521 | 528 | else => comptime unreachable, |
| 522 | 529 | }, |
| 523 | 530 | .array => return self.parseArray(T, node), |
| 531 | .vector => |vector| { | |
| 532 | const A = [vector.len]vector.child; | |
| 533 | return try self.parseArray(A, node); | |
| 534 | }, | |
| 524 | 535 | .@"struct" => |@"struct"| if (@"struct".is_tuple) |
| 525 | 536 | return self.parseTuple(T, node) |
| 526 | 537 | else |
| 527 | 538 | return self.parseStruct(T, node), |
| 528 | 539 | .@"union" => return self.parseUnion(T, node), |
| 529 | .vector => return self.parseVector(T, node), | |
| 530 | 540 | |
| 531 | 541 | else => comptime unreachable, |
| 532 | 542 | } |
| ... | ... | @@ -786,6 +796,7 @@ const Parser = struct { |
| 786 | 796 | |
| 787 | 797 | elem.* = try self.parseExpr(array_info.child, nodes.at(@intCast(i))); |
| 788 | 798 | } |
| 799 | if (array_info.sentinel()) |s| result[result.len] = s; | |
| 789 | 800 | return result; |
| 790 | 801 | } |
| 791 | 802 | |
| ... | ... | @@ -998,37 +1009,6 @@ const Parser = struct { |
| 998 | 1009 | } |
| 999 | 1010 | } |
| 1000 | 1011 | |
| 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 | ||
| 1032 | 1012 | fn failTokenFmt( |
| 1033 | 1013 | self: @This(), |
| 1034 | 1014 | token: Ast.TokenIndex, |
| ... | ... | @@ -3209,7 +3189,7 @@ test "std.zon vector" { |
| 3209 | 3189 | fromSlice(@Vector(2, f32), gpa, ".{0.5}", &diag, .{}), |
| 3210 | 3190 | ); |
| 3211 | 3191 | 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", | |
| 3213 | 3193 | "{f}", |
| 3214 | 3194 | .{diag}, |
| 3215 | 3195 | ); |
| ... | ... | @@ -3224,7 +3204,7 @@ test "std.zon vector" { |
| 3224 | 3204 | fromSlice(@Vector(2, f32), gpa, ".{0.5, 1.5, 2.5}", &diag, .{}), |
| 3225 | 3205 | ); |
| 3226 | 3206 | 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", | |
| 3228 | 3208 | "{f}", |
| 3229 | 3209 | .{diag}, |
| 3230 | 3210 | ); |
src/Air.zig+18-12| ... | ... | @@ -166,19 +166,25 @@ pub const Inst = struct { |
| 166 | 166 | mod, |
| 167 | 167 | /// Same as `mod` with optimized float mode. |
| 168 | 168 | 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. | |
| 175 | 178 | 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. | |
| 182 | 188 | ptr_sub, |
| 183 | 189 | /// Given two operands which can be floats, integers, or vectors, returns the |
| 184 | 190 | /// greater of the operands. For vectors it operates element-wise. |
src/Air/Legalize.zig+4-6| ... | ... | @@ -2682,12 +2682,10 @@ const Block = struct { |
| 2682 | 2682 | }, |
| 2683 | 2683 | .@"packed" => switch (agg_ty.zigTypeTag(zcu)) { |
| 2684 | 2684 | 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; | |
| 2691 | 2689 | }, |
| 2692 | 2690 | .@"union" => { |
| 2693 | 2691 | 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 |
| 207 | 207 | return (l.tomb_bits[usize_index] & mask) != 0; |
| 208 | 208 | } |
| 209 | 209 | |
| 210 | const 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. | |
| 225 | pub 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 | ||
| 692 | fn 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 | ||
| 705 | 210 | /// Higher level API. |
| 706 | 211 | pub const CondBrSlices = struct { |
| 707 | 212 | then_deaths: []const Air.Inst.Index, |
src/Sema.zig+88-52| ... | ... | @@ -1193,7 +1193,7 @@ fn analyzeBodyInner( |
| 1193 | 1193 | .elem_ptr => try sema.zirElemPtr(block, inst), |
| 1194 | 1194 | .elem_ptr_node => try sema.zirElemPtrNode(block, inst), |
| 1195 | 1195 | .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), | |
| 1197 | 1197 | .elem_val_imm => try sema.zirElemValImm(block, inst), |
| 1198 | 1198 | .elem_type => try sema.zirElemType(block, inst), |
| 1199 | 1199 | .indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst), |
| ... | ... | @@ -1211,8 +1211,8 @@ fn analyzeBodyInner( |
| 1211 | 1211 | .error_value => try sema.zirErrorValue(block, inst), |
| 1212 | 1212 | .field_ptr => try sema.zirFieldPtr(block, inst), |
| 1213 | 1213 | .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), | |
| 1216 | 1216 | .func => try sema.zirFunc(block, inst, false), |
| 1217 | 1217 | .func_inferred => try sema.zirFunc(block, inst, true), |
| 1218 | 1218 | .func_fancy => try sema.zirFuncFancy(block, inst), |
| ... | ... | @@ -3756,9 +3756,9 @@ fn zirAllocExtended( |
| 3756 | 3756 | const pt = sema.pt; |
| 3757 | 3757 | const gpa = sema.gpa; |
| 3758 | 3758 | const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); |
| 3759 | const var_src = block.nodeOffset(extra.data.src_node); | |
| 3759 | 3760 | const ty_src = block.src(.{ .node_offset_var_decl_ty = extra.data.src_node }); |
| 3760 | 3761 | 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 }); | |
| 3762 | 3762 | const small: Zir.Inst.AllocExtended.Small = @bitCast(extended.small); |
| 3763 | 3763 | |
| 3764 | 3764 | var extra_index: usize = extra.end; |
| ... | ... | @@ -3777,7 +3777,7 @@ fn zirAllocExtended( |
| 3777 | 3777 | |
| 3778 | 3778 | if (block.isComptime() or small.is_comptime) { |
| 3779 | 3779 | if (small.has_type) { |
| 3780 | return sema.analyzeComptimeAlloc(block, init_src, var_ty, alignment); | |
| 3780 | return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment); | |
| 3781 | 3781 | } else { |
| 3782 | 3782 | try sema.air_instructions.append(gpa, .{ |
| 3783 | 3783 | .tag = .inferred_alloc_comptime, |
| ... | ... | @@ -3792,7 +3792,7 @@ fn zirAllocExtended( |
| 3792 | 3792 | } |
| 3793 | 3793 | |
| 3794 | 3794 | 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); | |
| 3796 | 3796 | } |
| 3797 | 3797 | |
| 3798 | 3798 | if (small.has_type) { |
| ... | ... | @@ -3802,8 +3802,8 @@ fn zirAllocExtended( |
| 3802 | 3802 | const target = pt.zcu.getTarget(); |
| 3803 | 3803 | try var_ty.resolveLayout(pt); |
| 3804 | 3804 | 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", .{}); | |
| 3807 | 3807 | } |
| 3808 | 3808 | const ptr_type = try sema.pt.ptrTypeSema(.{ |
| 3809 | 3809 | .child = var_ty.toIntern(), |
| ... | ... | @@ -3842,9 +3842,9 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 3842 | 3842 | |
| 3843 | 3843 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 3844 | 3844 | 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); | |
| 3846 | 3846 | 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); | |
| 3848 | 3848 | } |
| 3849 | 3849 | |
| 3850 | 3850 | fn 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 |
| 4254 | 4254 | |
| 4255 | 4255 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 4256 | 4256 | 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); | |
| 4258 | 4258 | |
| 4259 | 4259 | const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); |
| 4260 | 4260 | 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); | |
| 4262 | 4262 | } |
| 4263 | 4263 | if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { |
| 4264 | 4264 | 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 |
| 4284 | 4284 | |
| 4285 | 4285 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 4286 | 4286 | 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); | |
| 4288 | 4288 | const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); |
| 4289 | 4289 | if (block.isComptime()) { |
| 4290 | return sema.analyzeComptimeAlloc(block, init_src, var_ty, .none); | |
| 4290 | return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); | |
| 4291 | 4291 | } |
| 4292 | 4292 | 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", .{}); | |
| 4295 | 4295 | } |
| 4296 | 4296 | try sema.validateVarType(block, ty_src, var_ty, false); |
| 4297 | 4297 | const target = pt.zcu.getTarget(); |
| ... | ... | @@ -9711,7 +9711,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 9711 | 9711 | return block.addBitCast(dest_ty, operand); |
| 9712 | 9712 | } |
| 9713 | 9713 | |
| 9714 | fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 9714 | fn zirFieldPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 9715 | 9715 | const tracy = trace(@src()); |
| 9716 | 9716 | defer tracy.end(); |
| 9717 | 9717 | |
| ... | ... | @@ -9727,8 +9727,8 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 9727 | 9727 | sema.code.nullTerminatedString(extra.field_name_start), |
| 9728 | 9728 | .no_embedded_nulls, |
| 9729 | 9729 | ); |
| 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); | |
| 9732 | 9732 | } |
| 9733 | 9733 | |
| 9734 | 9734 | fn 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 |
| 9779 | 9779 | } |
| 9780 | 9780 | } |
| 9781 | 9781 | |
| 9782 | fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 9782 | fn zirFieldPtrNamedLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 9783 | 9783 | const tracy = trace(@src()); |
| 9784 | 9784 | defer tracy.end(); |
| 9785 | 9785 | |
| ... | ... | @@ -9787,9 +9787,9 @@ fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 9787 | 9787 | const src = block.nodeOffset(inst_data.src_node); |
| 9788 | 9788 | const field_name_src = block.builtinCallArgSrc(inst_data.src_node, 1); |
| 9789 | 9789 | 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); | |
| 9791 | 9791 | 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); | |
| 9793 | 9793 | } |
| 9794 | 9794 | |
| 9795 | 9795 | fn 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 |
| 10102 | 10102 | return sema.elemVal(block, src, array, elem_index, src, false); |
| 10103 | 10103 | } |
| 10104 | 10104 | |
| 10105 | fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 10105 | fn zirElemPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 10106 | 10106 | const tracy = trace(@src()); |
| 10107 | 10107 | defer tracy.end(); |
| 10108 | 10108 | |
| ... | ... | @@ -10110,10 +10110,18 @@ fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10110 | 10110 | const src = block.nodeOffset(inst_data.src_node); |
| 10111 | 10111 | const elem_index_src = block.src(.{ .node_offset_array_access_index = inst_data.src_node }); |
| 10112 | 10112 | 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); | |
| 10114 | 10114 | 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 | } | |
| 10115 | 10122 | 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); | |
| 10117 | 10125 | } |
| 10118 | 10126 | |
| 10119 | 10127 | fn zirElemValImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -13612,7 +13620,6 @@ fn maybeErrorUnwrap( |
| 13612 | 13620 | .str, |
| 13613 | 13621 | .as_node, |
| 13614 | 13622 | .panic, |
| 13615 | .field_val, | |
| 13616 | 13623 | => {}, |
| 13617 | 13624 | else => return false, |
| 13618 | 13625 | } |
| ... | ... | @@ -13631,7 +13638,6 @@ fn maybeErrorUnwrap( |
| 13631 | 13638 | }, |
| 13632 | 13639 | .str => try sema.zirStr(inst), |
| 13633 | 13640 | .as_node => try sema.zirAsNode(block, inst), |
| 13634 | .field_val => try sema.zirFieldVal(block, inst), | |
| 13635 | 13641 | .@"unreachable" => { |
| 13636 | 13642 | try safetyPanicUnwrapError(sema, block, operand_src, operand); |
| 13637 | 13643 | return true; |
| ... | ... | @@ -15996,7 +16002,6 @@ fn splat(sema: *Sema, ty: Type, val: Value) !Value { |
| 15996 | 16002 | fn analyzeArithmetic( |
| 15997 | 16003 | sema: *Sema, |
| 15998 | 16004 | block: *Block, |
| 15999 | /// TODO performance investigation: make this comptime? | |
| 16000 | 16005 | zir_tag: Zir.Inst.Tag, |
| 16001 | 16006 | lhs: Air.Inst.Ref, |
| 16002 | 16007 | rhs: Air.Inst.Ref, |
| ... | ... | @@ -16195,6 +16200,11 @@ fn analyzePtrArithmetic( |
| 16195 | 16200 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 16196 | 16201 | assert(ptr_info.flags.size == .many or ptr_info.flags.size == .c); |
| 16197 | 16202 | |
| 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 | ||
| 16198 | 16208 | const new_ptr_ty = t: { |
| 16199 | 16209 | // Calculate the new pointer alignment. |
| 16200 | 16210 | // This code is duplicated in `Type.elemPtrType`. |
| ... | ... | @@ -26673,6 +26683,33 @@ fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void { |
| 26673 | 26683 | } |
| 26674 | 26684 | } |
| 26675 | 26685 | |
| 26686 | fn 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 | ||
| 26676 | 26713 | fn fieldVal( |
| 26677 | 26714 | sema: *Sema, |
| 26678 | 26715 | block: *Block, |
| ... | ... | @@ -26892,7 +26929,7 @@ fn fieldPtr( |
| 26892 | 26929 | const ptr_info = object_ty.ptrInfo(zcu); |
| 26893 | 26930 | const new_ptr_ty = try pt.ptrTypeSema(.{ |
| 26894 | 26931 | .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, | |
| 26896 | 26933 | .flags = .{ |
| 26897 | 26934 | .size = .many, |
| 26898 | 26935 | .alignment = ptr_info.flags.alignment, |
| ... | ... | @@ -27420,15 +27457,9 @@ fn structFieldPtrByIndex( |
| 27420 | 27457 | |
| 27421 | 27458 | if (struct_type.layout == .@"packed") { |
| 27422 | 27459 | 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; | |
| 27432 | 27463 | } else if (struct_type.layout == .@"extern") { |
| 27433 | 27464 | assert(!field_is_comptime); |
| 27434 | 27465 | // For extern structs, field alignment might be bigger than type's |
| ... | ... | @@ -27972,6 +28003,7 @@ fn elemVal( |
| 27972 | 28003 | } |
| 27973 | 28004 | } |
| 27974 | 28005 | |
| 28006 | /// Called when the index or indexable is runtime known. | |
| 27975 | 28007 | fn validateRuntimeElemAccess( |
| 27976 | 28008 | sema: *Sema, |
| 27977 | 28009 | block: *Block, |
| ... | ... | @@ -28236,6 +28268,10 @@ fn elemPtrArray( |
| 28236 | 28268 | try sema.validateRuntimeValue(block, array_ptr_src, array_ptr); |
| 28237 | 28269 | } |
| 28238 | 28270 | |
| 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 | ||
| 28239 | 28275 | // Runtime check is only needed if unable to comptime check. |
| 28240 | 28276 | if (oob_safety and block.wantSafety() and offset == null) { |
| 28241 | 28277 | 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 |
| 30634 | 30670 | } }; |
| 30635 | 30671 | return false; |
| 30636 | 30672 | } |
| 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 | ||
| 30637 | 30686 | return true; |
| 30638 | 30687 | } |
| 30639 | 30688 | |
| ... | ... | @@ -31425,19 +31474,6 @@ fn analyzeLoad( |
| 31425 | 31474 | } |
| 31426 | 31475 | } |
| 31427 | 31476 | |
| 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 | ||
| 31441 | 31477 | return block.addTyOp(.load, elem_ty, ptr); |
| 31442 | 31478 | } |
| 31443 | 31479 | |
| ... | ... | @@ -34954,7 +34990,7 @@ fn resolveInferredErrorSet( |
| 34954 | 34990 | const resolved_ty = func.resolvedErrorSetUnordered(ip); |
| 34955 | 34991 | if (resolved_ty != .none) return resolved_ty; |
| 34956 | 34992 | |
| 34957 | if (zcu.analysis_in_progress.contains(AnalUnit.wrap(.{ .func = func_index }))) { | |
| 34993 | if (zcu.analysis_in_progress.contains(.wrap(.{ .func = func_index }))) { | |
| 34958 | 34994 | return sema.fail(block, src, "unable to resolve inferred error set", .{}); |
| 34959 | 34995 | } |
| 34960 | 34996 |
src/Type.zig+9-32| ... | ... | @@ -3514,22 +3514,17 @@ pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } { |
| 3514 | 3514 | return .{ cur_ty, cur_len }; |
| 3515 | 3515 | } |
| 3516 | 3516 | |
| 3517 | pub 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. | |
| 3518 | pub fn packedStructFieldPtrInfo( | |
| 3519 | struct_ty: Type, | |
| 3520 | parent_ptr_ty: Type, | |
| 3521 | field_idx: u32, | |
| 3522 | pt: Zcu.PerThread, | |
| 3523 | ) InternPool.Key.PtrType.PackedOffset { | |
| 3528 | 3524 | comptime assert(Type.packed_struct_layout_version == 2); |
| 3529 | 3525 | |
| 3530 | 3526 | const zcu = pt.zcu; |
| 3531 | 3527 | const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu); |
| 3532 | const field_ty = struct_ty.fieldType(field_idx, zcu); | |
| 3533 | 3528 | |
| 3534 | 3529 | var bit_offset: u16 = 0; |
| 3535 | 3530 | var running_bits: u16 = 0; |
| ... | ... | @@ -3552,28 +3547,10 @@ pub fn packedStructFieldPtrInfo(struct_ty: Type, parent_ptr_ty: Type, field_idx: |
| 3552 | 3547 | bit_offset, |
| 3553 | 3548 | }; |
| 3554 | 3549 | |
| 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 .{ | |
| 3574 | 3551 | .host_size = res_host_size, |
| 3575 | 3552 | .bit_offset = res_bit_offset, |
| 3576 | } }; | |
| 3553 | }; | |
| 3577 | 3554 | } |
| 3578 | 3555 | |
| 3579 | 3556 | pub fn resolveLayout(ty: Type, pt: Zcu.PerThread) SemaError!void { |
src/Value.zig+22-30| ... | ... | @@ -2149,15 +2149,18 @@ pub fn makeBool(x: bool) Value { |
| 2149 | 2149 | return if (x) .true else .false; |
| 2150 | 2150 | } |
| 2151 | 2151 | |
| 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 | /// | |
| 2153 | 2154 | /// Returns a pointer to the payload of the optional. |
| 2155 | /// | |
| 2154 | 2156 | /// May perform type resolution. |
| 2155 | 2157 | pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value { |
| 2156 | 2158 | const zcu = pt.zcu; |
| 2157 | 2159 | const parent_ptr_ty = parent_ptr.typeOf(zcu); |
| 2158 | 2160 | const opt_ty = parent_ptr_ty.childType(zcu); |
| 2161 | const ptr_size = parent_ptr_ty.ptrSize(zcu); | |
| 2159 | 2162 | |
| 2160 | assert(parent_ptr_ty.ptrSize(zcu) == .one); | |
| 2163 | assert(ptr_size == .one or ptr_size == .c); | |
| 2161 | 2164 | assert(opt_ty.zigTypeTag(zcu) == .optional); |
| 2162 | 2165 | |
| 2163 | 2166 | const result_ty = try pt.ptrTypeSema(info: { |
| ... | ... | @@ -2212,9 +2215,12 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value { |
| 2212 | 2215 | } })); |
| 2213 | 2216 | } |
| 2214 | 2217 | |
| 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 | /// | |
| 2216 | 2220 | /// Returns a pointer to the aggregate field at the specified index. |
| 2221 | /// | |
| 2217 | 2222 | /// For slices, uses `slice_ptr_index` and `slice_len_index`. |
| 2223 | /// | |
| 2218 | 2224 | /// May perform type resolution. |
| 2219 | 2225 | pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value { |
| 2220 | 2226 | const zcu = pt.zcu; |
| ... | ... | @@ -2222,7 +2228,7 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value { |
| 2222 | 2228 | const aggregate_ty = parent_ptr_ty.childType(zcu); |
| 2223 | 2229 | |
| 2224 | 2230 | 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); | |
| 2226 | 2232 | |
| 2227 | 2233 | // Exiting this `switch` indicates that the `field` pointer representation should be used. |
| 2228 | 2234 | // `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 { |
| 2249 | 2255 | }); |
| 2250 | 2256 | return parent_ptr.getOffsetPtr(byte_off, result_ty, pt); |
| 2251 | 2257 | }, |
| 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); | |
| 2278 | 2270 | }, |
| 2279 | 2271 | } |
| 2280 | 2272 | }, |
src/Zcu/PerThread.zig+24-8| ... | ... | @@ -700,7 +700,7 @@ fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) |
| 700 | 700 | |
| 701 | 701 | const unit: AnalUnit = .wrap(.{ .memoized_state = stage }); |
| 702 | 702 | |
| 703 | try zcu.analysis_in_progress.put(gpa, unit, {}); | |
| 703 | try zcu.analysis_in_progress.putNoClobber(gpa, unit, {}); | |
| 704 | 704 | defer assert(zcu.analysis_in_progress.swapRemove(unit)); |
| 705 | 705 | |
| 706 | 706 | // Before we begin, collect: |
| ... | ... | @@ -864,7 +864,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu |
| 864 | 864 | const file = zcu.fileByIndex(inst_resolved.file); |
| 865 | 865 | const zir = file.zir.?; |
| 866 | 866 | |
| 867 | try zcu.analysis_in_progress.put(gpa, anal_unit, {}); | |
| 867 | try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {}); | |
| 868 | 868 | defer assert(zcu.analysis_in_progress.swapRemove(anal_unit)); |
| 869 | 869 | |
| 870 | 870 | var analysis_arena: std.heap.ArenaAllocator = .init(gpa); |
| ... | ... | @@ -958,6 +958,8 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu |
| 958 | 958 | |
| 959 | 959 | log.debug("ensureNavValUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); |
| 960 | 960 | |
| 961 | assert(!zcu.analysis_in_progress.contains(anal_unit)); | |
| 962 | ||
| 961 | 963 | // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the |
| 962 | 964 | // status is `.unresolved`, which indicates that the value is outdated because it has *never* |
| 963 | 965 | // been analyzed so far. |
| ... | ... | @@ -1090,10 +1092,19 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr |
| 1090 | 1092 | const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail; |
| 1091 | 1093 | const file = zcu.fileByIndex(inst_resolved.file); |
| 1092 | 1094 | const zir = file.zir.?; |
| 1095 | const zir_decl = zir.getDeclaration(inst_resolved.inst); | |
| 1093 | 1096 | |
| 1094 | try zcu.analysis_in_progress.put(gpa, anal_unit, {}); | |
| 1097 | try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {}); | |
| 1095 | 1098 | errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit); |
| 1096 | 1099 | |
| 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 | ||
| 1097 | 1108 | var analysis_arena: std.heap.ArenaAllocator = .init(gpa); |
| 1098 | 1109 | defer analysis_arena.deinit(); |
| 1099 | 1110 | |
| ... | ... | @@ -1133,8 +1144,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr |
| 1133 | 1144 | }; |
| 1134 | 1145 | defer block.instructions.deinit(gpa); |
| 1135 | 1146 | |
| 1136 | const zir_decl = zir.getDeclaration(inst_resolved.inst); | |
| 1137 | ||
| 1138 | 1147 | const ty_src = block.src(.{ .node_offset_var_decl_ty = .zero }); |
| 1139 | 1148 | const init_src = block.src(.{ .node_offset_var_decl_init = .zero }); |
| 1140 | 1149 | 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 |
| 1305 | 1314 | |
| 1306 | 1315 | // Mark the unit as completed before evaluating the export! |
| 1307 | 1316 | 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 | } | |
| 1308 | 1320 | |
| 1309 | 1321 | if (zir_decl.linkage == .@"export") { |
| 1310 | 1322 | 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 |
| 1347 | 1359 | |
| 1348 | 1360 | log.debug("ensureNavTypeUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); |
| 1349 | 1361 | |
| 1362 | assert(!zcu.analysis_in_progress.contains(anal_unit)); | |
| 1363 | ||
| 1350 | 1364 | const type_resolved_by_value: bool = from_val: { |
| 1351 | 1365 | const analysis = nav.analysis orelse break :from_val false; |
| 1352 | 1366 | 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 |
| 1463 | 1477 | const file = zcu.fileByIndex(inst_resolved.file); |
| 1464 | 1478 | const zir = file.zir.?; |
| 1465 | 1479 | |
| 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)); | |
| 1468 | 1482 | |
| 1469 | 1483 | const zir_decl = zir.getDeclaration(inst_resolved.inst); |
| 1470 | 1484 | const type_body = zir_decl.type_body.?; |
| ... | ... | @@ -1587,6 +1601,8 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z |
| 1587 | 1601 | |
| 1588 | 1602 | log.debug("ensureFuncBodyUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); |
| 1589 | 1603 | |
| 1604 | assert(!zcu.analysis_in_progress.contains(anal_unit)); | |
| 1605 | ||
| 1590 | 1606 | const func = zcu.funcInfo(func_index); |
| 1591 | 1607 | |
| 1592 | 1608 | 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 |
| 2781 | 2797 | const file = zcu.fileByIndex(inst_info.file); |
| 2782 | 2798 | const zir = file.zir.?; |
| 2783 | 2799 | |
| 2784 | try zcu.analysis_in_progress.put(gpa, anal_unit, {}); | |
| 2800 | try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {}); | |
| 2785 | 2801 | errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit); |
| 2786 | 2802 | |
| 2787 | 2803 | 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 { |
| 2291 | 2291 | } |
| 2292 | 2292 | |
| 2293 | 2293 | fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 2294 | @setEvalBranchQuota(29_400); | |
| 2294 | @setEvalBranchQuota(29_500); | |
| 2295 | 2295 | const pt = cg.pt; |
| 2296 | 2296 | const zcu = pt.zcu; |
| 2297 | 2297 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -86774,52 +86774,313 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 86774 | 86774 | const is_non_err = try cg.tempInit(.bool, .{ .eflags = .e }); |
| 86775 | 86775 | try is_non_err.finish(inst, &.{un_op}, &ops, cg); |
| 86776 | 86776 | }, |
| 86777 | .load => fallback: { | |
| 86777 | .load => { | |
| 86778 | 86778 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 86779 | 86779 | 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); | |
| 86785 | 86780 | 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 } }, | |
| 86791 | 86786 | }, |
| 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); | |
| 86794 | 86837 | }, |
| 86795 | 86838 | .ret => try cg.airRet(inst, false), |
| 86796 | 86839 | .ret_safe => try cg.airRet(inst, true), |
| 86797 | 86840 | .ret_load => try cg.airRetLoad(inst), |
| 86798 | .store, .store_safe => |air_tag| fallback: { | |
| 86841 | .store, .store_safe => |air_tag| { | |
| 86799 | 86842 | 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 | }); | |
| 86810 | 86843 | 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 } }, | |
| 86816 | 86848 | }, |
| 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, | |
| 86821 | 86861 | }, |
| 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 | }; | |
| 86823 | 87084 | for (ops) |op| try op.die(cg); |
| 86824 | 87085 | }, |
| 86825 | 87086 | .unreach => {}, |
| ... | ... | @@ -100863,7 +101124,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 100863 | 101124 | .dst_temps = .{ .{ .cc = .c }, .unused }, |
| 100864 | 101125 | .clobbers = .{ .eflags = true }, |
| 100865 | 101126 | .each = .{ .once = &.{ |
| 100866 | .{ ._, ._, .bt, .src0d, .ua(.none, .add_src1_rem_32), ._, ._ }, | |
| 101127 | .{ ._, ._, .bt, .src0d, .ua(.none, .add_src1), ._, ._ }, | |
| 100867 | 101128 | } }, |
| 100868 | 101129 | }, .{ |
| 100869 | 101130 | .src_constraints = .{ .{ .bool_vec = .dword }, .any, .any }, |
| ... | ... | @@ -100884,7 +101145,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 100884 | 101145 | .dst_temps = .{ .{ .cc = .c }, .unused }, |
| 100885 | 101146 | .clobbers = .{ .eflags = true }, |
| 100886 | 101147 | .each = .{ .once = &.{ |
| 100887 | .{ ._, ._, .bt, .src0q, .ua(.none, .add_src1_rem_64), ._, ._ }, | |
| 101148 | .{ ._, ._, .bt, .src0q, .ua(.none, .add_src1), ._, ._ }, | |
| 100888 | 101149 | } }, |
| 100889 | 101150 | }, .{ |
| 100890 | 101151 | .required_features = .{ .@"64bit", null, null, null }, |
| ... | ... | @@ -174481,114 +174742,6 @@ fn reuseOperandAdvanced( |
| 174481 | 174742 | return true; |
| 174482 | 174743 | } |
| 174483 | 174744 | |
| 174484 | fn 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 | ||
| 174592 | 174745 | fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { |
| 174593 | 174746 | const pt = self.pt; |
| 174594 | 174747 | const zcu = pt.zcu; |
| ... | ... | @@ -174636,174 +174789,6 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE |
| 174636 | 174789 | } |
| 174637 | 174790 | } |
| 174638 | 174791 | |
| 174639 | fn 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 | ||
| 174698 | fn 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 | ||
| 174807 | 174792 | fn store( |
| 174808 | 174793 | self: *CodeGen, |
| 174809 | 174794 | ptr_ty: Type, |
| ... | ... | @@ -174857,35 +174842,6 @@ fn store( |
| 174857 | 174842 | } |
| 174858 | 174843 | } |
| 174859 | 174844 | |
| 174860 | fn 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 | ||
| 174889 | 174845 | fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { |
| 174890 | 174846 | const pt = self.pt; |
| 174891 | 174847 | const zcu = pt.zcu; |
| ... | ... | @@ -187019,15 +186975,21 @@ const Temp = struct { |
| 187019 | 186975 | }, |
| 187020 | 186976 | .struct_type => { |
| 187021 | 186977 | 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]); | |
| 187023 | 186989 | }, |
| 187024 | 186990 | }; |
| 187025 | 186991 | const part_size: u31 = @intCast(part_ty.abiSize(zcu)); |
| 187026 | 186992 | 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 | }; | |
| 187031 | 186993 | if (src_rc == .x87 or std.math.isPowerOfTwo(part_size)) { |
| 187032 | 186994 | // hack around linker relocation bugs |
| 187033 | 186995 | switch (ptr.tracking(cg).short) { |
| ... | ... | @@ -187036,7 +186998,15 @@ const Temp = struct { |
| 187036 | 186998 | } |
| 187037 | 186999 | const strat = try cg.moveStrategy(part_ty, src_rc, false); |
| 187038 | 187000 | 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 | }, | |
| 187040 | 187010 | .disp = part_disp, |
| 187041 | 187011 | }), registerAlias(src_reg, part_size)); |
| 187042 | 187012 | } else { |
| ... | ... | @@ -192157,6 +192127,8 @@ const Select = struct { |
| 192157 | 192127 | exact_bool_vec: u16, |
| 192158 | 192128 | ptr_any_bool_vec, |
| 192159 | 192129 | ptr_bool_vec: Memory.Size, |
| 192130 | ptr_any_bool_vec_elem, | |
| 192131 | ptr_bool_vec_elem: Memory.Size, | |
| 192160 | 192132 | remainder_bool_vec: OfIsSizes, |
| 192161 | 192133 | exact_remainder_bool_vec: struct { of: Memory.Size, is: u16 }, |
| 192162 | 192134 | signed_int_vec: Memory.Size, |
| ... | ... | @@ -192259,6 +192231,22 @@ const Select = struct { |
| 192259 | 192231 | .vector_type => |vector_type| vector_type.child == .bool_type and size.bitSize(cg.target) >= vector_type.len, |
| 192260 | 192232 | else => false, |
| 192261 | 192233 | }, |
| 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 | }, | |
| 192262 | 192250 | .remainder_bool_vec => |of_is| ty.isVector(zcu) and ty.scalarType(zcu).toIntern() == .bool_type and |
| 192263 | 192251 | of_is.is.bitSize(cg.target) >= (ty.vectorLen(zcu) - 1) % of_is.of.bitSize(cg.target) + 1, |
| 192264 | 192252 | .exact_remainder_bool_vec => |of_is| ty.isVector(zcu) and ty.scalarType(zcu).toIntern() == .bool_type and |
| ... | ... | @@ -193252,7 +193240,7 @@ const Select = struct { |
| 193252 | 193240 | ref: Ref, |
| 193253 | 193241 | scale: Memory.Scale = .@"1", |
| 193254 | 193242 | } = .{ .ref = .none }, |
| 193255 | unused: u3 = 0, | |
| 193243 | unused: u2 = 0, | |
| 193256 | 193244 | }, |
| 193257 | 193245 | imm: i32 = 0, |
| 193258 | 193246 | |
| ... | ... | @@ -193265,9 +193253,9 @@ const Select = struct { |
| 193265 | 193253 | lea, |
| 193266 | 193254 | mem, |
| 193267 | 193255 | }; |
| 193268 | const Adjust = packed struct(u10) { | |
| 193256 | const Adjust = packed struct(u11) { | |
| 193269 | 193257 | sign: enum(u1) { neg, pos }, |
| 193270 | lhs: enum(u5) { | |
| 193258 | lhs: enum(u6) { | |
| 193271 | 193259 | none, |
| 193272 | 193260 | ptr_size, |
| 193273 | 193261 | ptr_bit_size, |
| ... | ... | @@ -193289,6 +193277,7 @@ const Select = struct { |
| 193289 | 193277 | src0_elem_size, |
| 193290 | 193278 | dst0_elem_size, |
| 193291 | 193279 | src0_elem_size_mul_src1, |
| 193280 | vector_index, | |
| 193292 | 193281 | src1, |
| 193293 | 193282 | src1_sub_bit_size, |
| 193294 | 193283 | log2_src0_elem_size, |
| ... | ... | @@ -193359,9 +193348,13 @@ const Select = struct { |
| 193359 | 193348 | const sub_src0_elem_size: Adjust = .{ .sign = .neg, .lhs = .src0_elem_size, .op = .mul, .rhs = .@"1" }; |
| 193360 | 193349 | const add_src0_elem_size_mul_src1: Adjust = .{ .sign = .pos, .lhs = .src0_elem_size_mul_src1, .op = .mul, .rhs = .@"1" }; |
| 193361 | 193350 | 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" }; | |
| 193362 | 193354 | const add_dst0_elem_size: Adjust = .{ .sign = .pos, .lhs = .dst0_elem_size, .op = .mul, .rhs = .@"1" }; |
| 193363 | 193355 | const sub_dst0_elem_size: Adjust = .{ .sign = .neg, .lhs = .dst0_elem_size, .op = .mul, .rhs = .@"1" }; |
| 193364 | 193356 | 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" }; | |
| 193365 | 193358 | const add_src1_rem_32: Adjust = .{ .sign = .pos, .lhs = .src1, .op = .rem_8_mul, .rhs = .@"4" }; |
| 193366 | 193359 | const add_src1_rem_64: Adjust = .{ .sign = .pos, .lhs = .src1, .op = .rem_8_mul, .rhs = .@"8" }; |
| 193367 | 193360 | 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 { |
| 194244 | 194237 | .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), |
| 194245 | 194238 | .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * |
| 194246 | 194239 | 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 | }, | |
| 194247 | 194244 | .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate), |
| 194248 | 194245 | .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) - |
| 194249 | 194246 | @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, |
| 5821 | 5821 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| 5822 | 5822 | }, |
| 5823 | 5823 | .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); | |
| 5826 | 5826 | 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); | |
| 5847 | 5839 | } |
| 5848 | 5840 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| 5849 | 5841 | }, |
| ... | ... | @@ -6147,6 +6139,26 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 6147 | 6139 | } |
| 6148 | 6140 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| 6149 | 6141 | }, |
| 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 | }, | |
| 6150 | 6162 | .array_elem_val => { |
| 6151 | 6163 | if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: { |
| 6152 | 6164 | defer elem_vi.value.deref(isel); |
| ... | ... | @@ -8011,6 +8023,7 @@ pub fn layout( |
| 8011 | 8023 | while (save_index < saves.len) { |
| 8012 | 8024 | if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and |
| 8013 | 8025 | saves[save_index + 0].class == saves[save_index + 1].class and |
| 8026 | saves[save_index + 0].size == saves[save_index + 1].size and | |
| 8014 | 8027 | saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset) |
| 8015 | 8028 | { |
| 8016 | 8029 | try isel.emit(.ldp( |
| ... | ... | @@ -8317,7 +8330,7 @@ fn elemPtr( |
| 8317 | 8330 | }), |
| 8318 | 8331 | 2 => { |
| 8319 | 8332 | 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) { | |
| 8321 | 8334 | .add => switch (base_ra) { |
| 8322 | 8335 | else => { |
| 8323 | 8336 | const temp_ra = try isel.allocIntReg(); |
| ... | ... | @@ -8326,7 +8339,7 @@ fn elemPtr( |
| 8326 | 8339 | .register = temp_ra.x(), |
| 8327 | 8340 | .shift = .{ .lsl = shift }, |
| 8328 | 8341 | } })); |
| 8329 | break :temp_ra temp_ra; | |
| 8342 | break :temp_ra .{ temp_ra, true }; | |
| 8330 | 8343 | }, |
| 8331 | 8344 | .zr => { |
| 8332 | 8345 | if (shift > 0) try isel.emit(.ubfm(elem_ptr_ra.x(), elem_ptr_ra.x(), .{ |
| ... | ... | @@ -8334,7 +8347,7 @@ fn elemPtr( |
| 8334 | 8347 | .immr = -%shift, |
| 8335 | 8348 | .imms = ~shift, |
| 8336 | 8349 | })); |
| 8337 | break :temp_ra elem_ptr_ra; | |
| 8350 | break :temp_ra .{ elem_ptr_ra, false }; | |
| 8338 | 8351 | }, |
| 8339 | 8352 | }, |
| 8340 | 8353 | .sub => { |
| ... | ... | @@ -8344,10 +8357,10 @@ fn elemPtr( |
| 8344 | 8357 | .register = temp_ra.x(), |
| 8345 | 8358 | .shift = .{ .lsl = shift }, |
| 8346 | 8359 | } })); |
| 8347 | break :temp_ra temp_ra; | |
| 8360 | break :temp_ra .{ temp_ra, true }; | |
| 8348 | 8361 | }, |
| 8349 | 8362 | }; |
| 8350 | defer if (temp_ra != elem_ptr_ra) isel.freeReg(temp_ra); | |
| 8363 | defer if (free_temp_ra) isel.freeReg(temp_ra); | |
| 8351 | 8364 | try isel.emit(.add(temp_ra.x(), index_mat.ra.x(), .{ .shifted_register = .{ |
| 8352 | 8365 | .register = index_mat.ra.x(), |
| 8353 | 8366 | .shift = .{ .lsl = @intCast(63 - @clz(elem_size) - shift) }, |
| ... | ... | @@ -9276,7 +9289,14 @@ pub const Value = struct { |
| 9276 | 9289 | part_offset -= part_size; |
| 9277 | 9290 | var wrapped_res_part_it = res_vi.field(ty, part_offset, part_size); |
| 9278 | 9291 | 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 | }; | |
| 9280 | 9300 | const unwrapped_res_part_ra = unwrapped_res_part_ra: { |
| 9281 | 9301 | if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra; |
| 9282 | 9302 | if (int_info.bits % 32 == 0) { |
src/codegen/llvm.zig+21-81| ... | ... | @@ -4980,8 +4980,8 @@ pub const FuncGen = struct { |
| 4980 | 4980 | .breakpoint => try self.airBreakpoint(inst), |
| 4981 | 4981 | .ret_addr => try self.airRetAddr(inst), |
| 4982 | 4982 | .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), | |
| 4985 | 4985 | .try_ptr => try self.airTryPtr(inst, false), |
| 4986 | 4986 | .try_ptr_cold => try self.airTryPtr(inst, true), |
| 4987 | 4987 | .intcast => try self.airIntCast(inst, false), |
| ... | ... | @@ -4989,7 +4989,7 @@ pub const FuncGen = struct { |
| 4989 | 4989 | .trunc => try self.airTrunc(inst), |
| 4990 | 4990 | .fptrunc => try self.airFptrunc(inst), |
| 4991 | 4991 | .fpext => try self.airFpext(inst), |
| 4992 | .load => try self.airLoad(body[i..]), | |
| 4992 | .load => try self.airLoad(inst), | |
| 4993 | 4993 | .not => try self.airNot(inst), |
| 4994 | 4994 | .store => try self.airStore(inst, false), |
| 4995 | 4995 | .store_safe => try self.airStore(inst, true), |
| ... | ... | @@ -5045,7 +5045,7 @@ pub const FuncGen = struct { |
| 5045 | 5045 | .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst), |
| 5046 | 5046 | |
| 5047 | 5047 | .struct_field_ptr => try self.airStructFieldPtr(inst), |
| 5048 | .struct_field_val => try self.airStructFieldVal(body[i..]), | |
| 5048 | .struct_field_val => try self.airStructFieldVal(inst), | |
| 5049 | 5049 | |
| 5050 | 5050 | .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0), |
| 5051 | 5051 | .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1), |
| ... | ... | @@ -5054,18 +5054,18 @@ pub const FuncGen = struct { |
| 5054 | 5054 | |
| 5055 | 5055 | .field_parent_ptr => try self.airFieldParentPtr(inst), |
| 5056 | 5056 | |
| 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), | |
| 5059 | 5059 | .slice_elem_ptr => try self.airSliceElemPtr(inst), |
| 5060 | .ptr_elem_val => try self.airPtrElemVal(body[i..]), | |
| 5060 | .ptr_elem_val => try self.airPtrElemVal(inst), | |
| 5061 | 5061 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 5062 | 5062 | |
| 5063 | .optional_payload => try self.airOptionalPayload(body[i..]), | |
| 5063 | .optional_payload => try self.airOptionalPayload(inst), | |
| 5064 | 5064 | .optional_payload_ptr => try self.airOptionalPayloadPtr(inst), |
| 5065 | 5065 | .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst), |
| 5066 | 5066 | |
| 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), | |
| 5069 | 5069 | .unwrap_errunion_err => try self.airErrUnionErr(inst, false), |
| 5070 | 5070 | .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true), |
| 5071 | 5071 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), |
| ... | ... | @@ -6266,19 +6266,14 @@ pub const FuncGen = struct { |
| 6266 | 6266 | // No need to reset the insert cursor since this instruction is noreturn. |
| 6267 | 6267 | } |
| 6268 | 6268 | |
| 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 { | |
| 6273 | 6270 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 6274 | 6271 | const err_union = try self.resolveInst(pl_op.operand); |
| 6275 | 6272 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 6276 | 6273 | const body: []const Air.Inst.Index = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.body_len]); |
| 6277 | 6274 | 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; | |
| 6280 | 6275 | 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); | |
| 6282 | 6277 | } |
| 6283 | 6278 | |
| 6284 | 6279 | fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value { |
| ... | ... | @@ -6824,11 +6819,10 @@ pub const FuncGen = struct { |
| 6824 | 6819 | return self.wip.gepStruct(slice_llvm_ty, slice_ptr, index, ""); |
| 6825 | 6820 | } |
| 6826 | 6821 | |
| 6827 | fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { | |
| 6822 | fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { | |
| 6828 | 6823 | const o = self.ng.object; |
| 6829 | 6824 | const pt = self.ng.pt; |
| 6830 | 6825 | const zcu = pt.zcu; |
| 6831 | const inst = body_tail[0]; | |
| 6832 | 6826 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6833 | 6827 | const slice_ty = self.typeOf(bin_op.lhs); |
| 6834 | 6828 | const slice = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -6838,9 +6832,6 @@ pub const FuncGen = struct { |
| 6838 | 6832 | const base_ptr = try self.wip.extractValue(slice, &.{0}, ""); |
| 6839 | 6833 | const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, ""); |
| 6840 | 6834 | if (isByRef(elem_ty, zcu)) { |
| 6841 | if (self.canElideLoad(body_tail)) | |
| 6842 | return ptr; | |
| 6843 | ||
| 6844 | 6835 | self.maybeMarkAllowZeroAccess(slice_ty.ptrInfo(zcu)); |
| 6845 | 6836 | |
| 6846 | 6837 | const slice_align = (slice_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm(); |
| ... | ... | @@ -6867,11 +6858,10 @@ pub const FuncGen = struct { |
| 6867 | 6858 | return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, ""); |
| 6868 | 6859 | } |
| 6869 | 6860 | |
| 6870 | fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { | |
| 6861 | fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { | |
| 6871 | 6862 | const o = self.ng.object; |
| 6872 | 6863 | const pt = self.ng.pt; |
| 6873 | 6864 | const zcu = pt.zcu; |
| 6874 | const inst = body_tail[0]; | |
| 6875 | 6865 | |
| 6876 | 6866 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6877 | 6867 | const array_ty = self.typeOf(bin_op.lhs); |
| ... | ... | @@ -6884,9 +6874,7 @@ pub const FuncGen = struct { |
| 6884 | 6874 | try o.builder.intValue(try o.lowerType(pt, Type.usize), 0), rhs, |
| 6885 | 6875 | }; |
| 6886 | 6876 | 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, ""); | |
| 6890 | 6878 | const elem_alignment = elem_ty.abiAlignment(zcu).toLlvm(); |
| 6891 | 6879 | return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal); |
| 6892 | 6880 | } else { |
| ... | ... | @@ -6900,11 +6888,10 @@ pub const FuncGen = struct { |
| 6900 | 6888 | return self.wip.extractElement(array_llvm_val, rhs, ""); |
| 6901 | 6889 | } |
| 6902 | 6890 | |
| 6903 | fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { | |
| 6891 | fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { | |
| 6904 | 6892 | const o = self.ng.object; |
| 6905 | 6893 | const pt = self.ng.pt; |
| 6906 | 6894 | const zcu = pt.zcu; |
| 6907 | const inst = body_tail[0]; | |
| 6908 | 6895 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 6909 | 6896 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 6910 | 6897 | const elem_ty = ptr_ty.childType(zcu); |
| ... | ... | @@ -6918,10 +6905,7 @@ pub const FuncGen = struct { |
| 6918 | 6905 | else |
| 6919 | 6906 | &.{rhs}, ""); |
| 6920 | 6907 | if (isByRef(elem_ty, zcu)) { |
| 6921 | if (self.canElideLoad(body_tail)) return ptr; | |
| 6922 | ||
| 6923 | 6908 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); |
| 6924 | ||
| 6925 | 6909 | const ptr_align = (ptr_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm(); |
| 6926 | 6910 | return self.loadByRef(ptr, elem_ty, ptr_align, if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal); |
| 6927 | 6911 | } |
| ... | ... | @@ -6974,11 +6958,10 @@ pub const FuncGen = struct { |
| 6974 | 6958 | return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index); |
| 6975 | 6959 | } |
| 6976 | 6960 | |
| 6977 | fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { | |
| 6961 | fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { | |
| 6978 | 6962 | const o = self.ng.object; |
| 6979 | 6963 | const pt = self.ng.pt; |
| 6980 | 6964 | const zcu = pt.zcu; |
| 6981 | const inst = body_tail[0]; | |
| 6982 | 6965 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 6983 | 6966 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 6984 | 6967 | const struct_ty = self.typeOf(struct_field.struct_operand); |
| ... | ... | @@ -7052,9 +7035,6 @@ pub const FuncGen = struct { |
| 7052 | 7035 | .flags = .{ .alignment = alignment }, |
| 7053 | 7036 | }); |
| 7054 | 7037 | if (isByRef(field_ty, zcu)) { |
| 7055 | if (canElideLoad(self, body_tail)) | |
| 7056 | return field_ptr; | |
| 7057 | ||
| 7058 | 7038 | assert(alignment != .none); |
| 7059 | 7039 | const field_alignment = alignment.toLlvm(); |
| 7060 | 7040 | return self.loadByRef(field_ptr, field_ty, field_alignment, .normal); |
| ... | ... | @@ -7070,7 +7050,6 @@ pub const FuncGen = struct { |
| 7070 | 7050 | try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, ""); |
| 7071 | 7051 | const payload_alignment = layout.payload_align.toLlvm(); |
| 7072 | 7052 | if (isByRef(field_ty, zcu)) { |
| 7073 | if (canElideLoad(self, body_tail)) return field_ptr; | |
| 7074 | 7053 | return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal); |
| 7075 | 7054 | } else { |
| 7076 | 7055 | return self.loadTruncate(.normal, field_ty, field_ptr, payload_alignment); |
| ... | ... | @@ -7829,11 +7808,10 @@ pub const FuncGen = struct { |
| 7829 | 7808 | return self.wip.gepStruct(optional_llvm_ty, operand, 0, ""); |
| 7830 | 7809 | } |
| 7831 | 7810 | |
| 7832 | fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value { | |
| 7811 | fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { | |
| 7833 | 7812 | const o = self.ng.object; |
| 7834 | 7813 | const pt = self.ng.pt; |
| 7835 | 7814 | const zcu = pt.zcu; |
| 7836 | const inst = body_tail[0]; | |
| 7837 | 7815 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 7838 | 7816 | const operand = try self.resolveInst(ty_op.operand); |
| 7839 | 7817 | const optional_ty = self.typeOf(ty_op.operand); |
| ... | ... | @@ -7846,19 +7824,13 @@ pub const FuncGen = struct { |
| 7846 | 7824 | } |
| 7847 | 7825 | |
| 7848 | 7826 | 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); | |
| 7851 | 7828 | } |
| 7852 | 7829 | |
| 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 { | |
| 7858 | 7831 | const o = self.ng.object; |
| 7859 | 7832 | const pt = self.ng.pt; |
| 7860 | 7833 | const zcu = pt.zcu; |
| 7861 | const inst = body_tail[0]; | |
| 7862 | 7834 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 7863 | 7835 | const operand = try self.resolveInst(ty_op.operand); |
| 7864 | 7836 | const operand_ty = self.typeOf(ty_op.operand); |
| ... | ... | @@ -7877,7 +7849,6 @@ pub const FuncGen = struct { |
| 7877 | 7849 | const payload_alignment = payload_ty.abiAlignment(zcu).toLlvm(); |
| 7878 | 7850 | const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); |
| 7879 | 7851 | if (isByRef(payload_ty, zcu)) { |
| 7880 | if (self.canElideLoad(body_tail)) return payload_ptr; | |
| 7881 | 7852 | return self.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); |
| 7882 | 7853 | } |
| 7883 | 7854 | const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset]; |
| ... | ... | @@ -9740,45 +9711,14 @@ pub const FuncGen = struct { |
| 9740 | 9711 | return .none; |
| 9741 | 9712 | } |
| 9742 | 9713 | |
| 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 { | |
| 9765 | 9715 | const pt = fg.ng.pt; |
| 9766 | 9716 | const zcu = pt.zcu; |
| 9767 | const inst = body_tail[0]; | |
| 9768 | 9717 | const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 9769 | 9718 | const ptr_ty = fg.typeOf(ty_op.operand); |
| 9770 | 9719 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 9771 | 9720 | 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 | ||
| 9780 | 9721 | fg.maybeMarkAllowZeroAccess(ptr_info); |
| 9781 | ||
| 9782 | 9722 | return fg.load(ptr, ptr_ty); |
| 9783 | 9723 | } |
| 9784 | 9724 |
src/print_zir.zig+3-3| ... | ... | @@ -406,7 +406,7 @@ const Writer = struct { |
| 406 | 406 | .memset, |
| 407 | 407 | .memmove, |
| 408 | 408 | .elem_ptr_node, |
| 409 | .elem_val_node, | |
| 409 | .elem_ptr_load, | |
| 410 | 410 | .elem_ptr, |
| 411 | 411 | .elem_val, |
| 412 | 412 | .array_type, |
| ... | ... | @@ -450,14 +450,14 @@ const Writer = struct { |
| 450 | 450 | |
| 451 | 451 | .switch_block_err_union => try self.writeSwitchBlockErrUnion(stream, inst), |
| 452 | 452 | |
| 453 | .field_val, | |
| 453 | .field_ptr_load, | |
| 454 | 454 | .field_ptr, |
| 455 | 455 | .decl_literal, |
| 456 | 456 | .decl_literal_no_coerce, |
| 457 | 457 | => try self.writePlNodeField(stream, inst), |
| 458 | 458 | |
| 459 | 459 | .field_ptr_named, |
| 460 | .field_val_named, | |
| 460 | .field_ptr_named_load, | |
| 461 | 461 | => try self.writePlNodeFieldNamed(stream, inst), |
| 462 | 462 | |
| 463 | 463 | .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" { |
| 392 | 392 | } |
| 393 | 393 | |
| 394 | 394 | test "struct field explicit alignment" { |
| 395 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 396 | 395 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 397 | 396 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 398 | 397 | 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" { |
| 1125 | 1125 | _ = try S.doTest(@Vector(4, u32)); |
| 1126 | 1126 | _ = try S.doTest([4]u32); |
| 1127 | 1127 | } |
| 1128 | ||
| 1129 | test "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" { |
| 511 | 511 | } |
| 512 | 512 | |
| 513 | 513 | test "@bitCast of packed struct containing pointer" { |
| 514 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 515 | 514 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 516 | 515 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 517 | 516 | 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" { |
| 951 | 951 | } |
| 952 | 952 | |
| 953 | 953 | test "try used in recursive function with inferred error set" { |
| 954 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 955 | 954 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 956 | 955 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 957 | 956 |
test/behavior/field_parent_ptr.zig+3| ... | ... | @@ -1032,6 +1032,7 @@ test "@fieldParentPtr packed struct first zero-bit field" { |
| 1032 | 1032 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 1033 | 1033 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1034 | 1034 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1035 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1035 | 1036 | |
| 1036 | 1037 | const C = packed struct { |
| 1037 | 1038 | a: u0 = 0, |
| ... | ... | @@ -1137,6 +1138,7 @@ test "@fieldParentPtr packed struct middle zero-bit field" { |
| 1137 | 1138 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 1138 | 1139 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1139 | 1140 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1141 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1140 | 1142 | |
| 1141 | 1143 | const C = packed struct { |
| 1142 | 1144 | a: f32 = 3.14, |
| ... | ... | @@ -1242,6 +1244,7 @@ test "@fieldParentPtr packed struct last zero-bit field" { |
| 1242 | 1244 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 1243 | 1245 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1244 | 1246 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1247 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1245 | 1248 | |
| 1246 | 1249 | const C = packed struct { |
| 1247 | 1250 | 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 |
| 1741 | 1741 | test "result location forwarded through unary float builtins" { |
| 1742 | 1742 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1743 | 1743 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1744 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1745 | 1744 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 1746 | 1745 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1747 | 1746 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/globals.zig-1| ... | ... | @@ -14,7 +14,6 @@ test "store to global array" { |
| 14 | 14 | |
| 15 | 15 | var vpos = @Vector(2, f32){ 0.0, 0.0 }; |
| 16 | 16 | test "store to global vector" { |
| 17 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 18 | 17 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 19 | 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 20 | 19 |
test/behavior/math.zig+1-5| ... | ... | @@ -139,11 +139,7 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void { |
| 139 | 139 | const len_a = @typeInfo(@TypeOf(a)).vector.len; |
| 140 | 140 | const len_b = @typeInfo(@TypeOf(b)).vector.len; |
| 141 | 141 | 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)); | |
| 147 | 143 | } |
| 148 | 144 | |
| 149 | 145 | test "@ctz" { |
test/behavior/memset.zig-1| ... | ... | @@ -122,7 +122,6 @@ test "memset with large array element, runtime known" { |
| 122 | 122 | } |
| 123 | 123 | |
| 124 | 124 | test "memset with large array element, comptime known" { |
| 125 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 126 | 125 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 127 | 126 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 128 | 127 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/packed-struct.zig+53-86| ... | ... | @@ -3,7 +3,6 @@ const builtin = @import("builtin"); |
| 3 | 3 | const assert = std.debug.assert; |
| 4 | 4 | const expect = std.testing.expect; |
| 5 | 5 | const expectEqual = std.testing.expectEqual; |
| 6 | const native_endian = builtin.cpu.arch.endian(); | |
| 7 | 6 | |
| 8 | 7 | test "flags in packed structs" { |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -163,26 +162,24 @@ test "correct sizeOf and offsets in packed structs" { |
| 163 | 162 | try expectEqual(22, @bitOffsetOf(PStruct, "u10_b")); |
| 164 | 163 | try expectEqual(4, @sizeOf(PStruct)); |
| 165 | 164 | |
| 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); | |
| 186 | 183 | } |
| 187 | 184 | |
| 188 | 185 | test "nested packed structs" { |
| ... | ... | @@ -202,15 +199,13 @@ test "nested packed structs" { |
| 202 | 199 | try expectEqual(3, @offsetOf(S3, "y")); |
| 203 | 200 | try expectEqual(24, @bitOffsetOf(S3, "y")); |
| 204 | 201 | |
| 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); | |
| 214 | 209 | |
| 215 | 210 | const S4 = packed struct { a: i32, b: i8 }; |
| 216 | 211 | const S5 = packed struct { a: i32, b: i8, c: S4 }; |
| ... | ... | @@ -230,10 +225,10 @@ test "nested packed structs" { |
| 230 | 225 | } |
| 231 | 226 | |
| 232 | 227 | test "regular in irregular packed struct" { |
| 233 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 234 | 228 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 235 | 229 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 236 | 230 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 231 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 237 | 232 | |
| 238 | 233 | const Irregular = packed struct { |
| 239 | 234 | bar: Regular = Regular{}, |
| ... | ... | @@ -253,7 +248,6 @@ test "nested packed struct unaligned" { |
| 253 | 248 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 254 | 249 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 255 | 250 | 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 | |
| 257 | 251 | |
| 258 | 252 | const S1 = packed struct { |
| 259 | 253 | a: u4, |
| ... | ... | @@ -321,10 +315,10 @@ test "nested packed struct unaligned" { |
| 321 | 315 | } |
| 322 | 316 | |
| 323 | 317 | test "byte-aligned field pointer offsets" { |
| 324 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 325 | 318 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 326 | 319 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 327 | 320 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 321 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 328 | 322 | |
| 329 | 323 | const S = struct { |
| 330 | 324 | const A = packed struct { |
| ... | ... | @@ -346,21 +340,12 @@ test "byte-aligned field pointer offsets" { |
| 346 | 340 | .c = 3, |
| 347 | 341 | .d = 4, |
| 348 | 342 | }; |
| 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 | ||
| 364 | 349 | try expect(a.a == 1); |
| 365 | 350 | try expect(a.b == 2); |
| 366 | 351 | try expect(a.c == 3); |
| ... | ... | @@ -394,16 +379,10 @@ test "byte-aligned field pointer offsets" { |
| 394 | 379 | .a = 1, |
| 395 | 380 | .b = 2, |
| 396 | 381 | }; |
| 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 | ||
| 407 | 386 | try expect(b.a == 1); |
| 408 | 387 | try expect(b.b == 2); |
| 409 | 388 | |
| ... | ... | @@ -428,7 +407,6 @@ test "nested packed struct field pointers" { |
| 428 | 407 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 429 | 408 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // ubsan unaligned pointer access |
| 430 | 409 | 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 | |
| 432 | 410 | |
| 433 | 411 | const S2 = packed struct { |
| 434 | 412 | base: u8, |
| ... | ... | @@ -485,7 +463,6 @@ test "@intFromPtr on a packed struct field" { |
| 485 | 463 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 486 | 464 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 487 | 465 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 488 | if (native_endian != .little) return error.SkipZigTest; | |
| 489 | 466 | |
| 490 | 467 | const S = struct { |
| 491 | 468 | const P = packed struct { |
| ... | ... | @@ -500,14 +477,13 @@ test "@intFromPtr on a packed struct field" { |
| 500 | 477 | .z = 0, |
| 501 | 478 | }; |
| 502 | 479 | }; |
| 503 | try expect(@intFromPtr(&S.p0.z) - @intFromPtr(&S.p0.x) == 2); | |
| 480 | try expect(@intFromPtr(&S.p0.z) - @intFromPtr(&S.p0.x) == 0); | |
| 504 | 481 | } |
| 505 | 482 | |
| 506 | 483 | test "@intFromPtr on a packed struct field unaligned and nested" { |
| 507 | 484 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 508 | 485 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 509 | 486 | 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 | |
| 511 | 487 | |
| 512 | 488 | const S1 = packed struct { |
| 513 | 489 | a: u4, |
| ... | ... | @@ -567,16 +543,16 @@ test "@intFromPtr on a packed struct field unaligned and nested" { |
| 567 | 543 | else => {}, |
| 568 | 544 | } |
| 569 | 545 | 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); | |
| 573 | 549 | try expect(@intFromPtr(&S2.s.bit0) - @intFromPtr(&S2.s) == 0); |
| 574 | 550 | try expect(@intFromPtr(&S2.s.p1.a) - @intFromPtr(&S2.s) == 0); |
| 575 | 551 | 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); | |
| 580 | 556 | |
| 581 | 557 | const S3 = packed struct { |
| 582 | 558 | pad: u8, |
| ... | ... | @@ -599,7 +575,7 @@ test "@intFromPtr on a packed struct field unaligned and nested" { |
| 599 | 575 | comptime assert(@TypeOf(&S3.v0.s.v) == *align(4:10:4) u3); |
| 600 | 576 | comptime assert(@TypeOf(&S3.v0.s.s.v) == *align(4:13:4) u2); |
| 601 | 577 | 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); | |
| 603 | 579 | comptime assert(@TypeOf(&S3.v0.s.s.s.bit1) == *align(4:24:4) u1); |
| 604 | 580 | try expect(@intFromPtr(&S3.v0.v) - @intFromPtr(&S3.v0) == 0); |
| 605 | 581 | try expect(@intFromPtr(&S3.v0.s) - @intFromPtr(&S3.v0) == 0); |
| ... | ... | @@ -608,7 +584,7 @@ test "@intFromPtr on a packed struct field unaligned and nested" { |
| 608 | 584 | try expect(@intFromPtr(&S3.v0.s.s.v) - @intFromPtr(&S3.v0) == 0); |
| 609 | 585 | try expect(@intFromPtr(&S3.v0.s.s.s) - @intFromPtr(&S3.v0) == 0); |
| 610 | 586 | 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); | |
| 612 | 588 | try expect(@intFromPtr(&S3.v0.s.s.s.bit1) - @intFromPtr(&S3.v0) == 0); |
| 613 | 589 | } |
| 614 | 590 | |
| ... | ... | @@ -653,13 +629,13 @@ test "optional pointer in packed struct" { |
| 653 | 629 | } |
| 654 | 630 | |
| 655 | 631 | test "nested packed struct field access test" { |
| 656 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 657 | 632 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 658 | 633 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits |
| 659 | 634 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 660 | 635 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 661 | 636 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 662 | 637 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 638 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 663 | 639 | |
| 664 | 640 | const Vec2 = packed struct { |
| 665 | 641 | x: f32, |
| ... | ... | @@ -774,9 +750,9 @@ test "nested packed struct field access test" { |
| 774 | 750 | } |
| 775 | 751 | |
| 776 | 752 | test "nested packed struct at non-zero offset" { |
| 777 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 778 | 753 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 779 | 754 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 755 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 780 | 756 | |
| 781 | 757 | const Pair = packed struct(u24) { |
| 782 | 758 | a: u16 = 0, |
| ... | ... | @@ -871,7 +847,6 @@ test "nested packed struct at non-zero offset 2" { |
| 871 | 847 | } |
| 872 | 848 | |
| 873 | 849 | test "runtime init of unnamed packed struct type" { |
| 874 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 875 | 850 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 876 | 851 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 877 | 852 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -916,21 +891,13 @@ test "overaligned pointer to packed struct" { |
| 916 | 891 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 917 | 892 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 918 | 893 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 894 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 919 | 895 | |
| 920 | 896 | const S = packed struct { a: u32, b: u32 }; |
| 921 | 897 | var foo: S align(4) = .{ .a = 123, .b = 456 }; |
| 922 | 898 | 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); | |
| 934 | 901 | } |
| 935 | 902 | |
| 936 | 903 | test "packed struct initialized in bitcast" { |
| ... | ... | @@ -1345,11 +1312,11 @@ test "assign packed struct initialized with RLS to packed struct literal field" |
| 1345 | 1312 | } |
| 1346 | 1313 | |
| 1347 | 1314 | test "byte-aligned packed relocation" { |
| 1348 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1349 | 1315 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1350 | 1316 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 1351 | 1317 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1352 | 1318 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 1319 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1353 | 1320 | |
| 1354 | 1321 | const S = struct { |
| 1355 | 1322 | var global: u8 align(2) = 0; |
test/behavior/pointers.zig+8-1| ... | ... | @@ -419,7 +419,6 @@ test "pointer sentinel with enums" { |
| 419 | 419 | } |
| 420 | 420 | |
| 421 | 421 | test "pointer sentinel with optional element" { |
| 422 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 423 | 422 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 424 | 423 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 425 | 424 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -779,3 +778,11 @@ test "pointers to elements of many-ptr to zero-bit type" { |
| 779 | 778 | |
| 780 | 779 | try expect(a == b); |
| 781 | 780 | } |
| 781 | ||
| 782 | test "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 { |
| 376 | 376 | }; |
| 377 | 377 | |
| 378 | 378 | test "packed struct" { |
| 379 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 380 | 379 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 381 | 380 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 382 | 381 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 382 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 383 | 383 | |
| 384 | 384 | var foo = APackedStruct{ |
| 385 | 385 | .x = 1, |
| ... | ... | @@ -744,11 +744,11 @@ const S0 = struct { |
| 744 | 744 | var g_foo: S0 = S0.init(); |
| 745 | 745 | |
| 746 | 746 | test "packed struct with fp fields" { |
| 747 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 748 | 747 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 749 | 748 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 750 | 749 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 751 | 750 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 751 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 752 | 752 | |
| 753 | 753 | const S = packed struct { |
| 754 | 754 | data0: f32, |
| ... | ... | @@ -1924,7 +1924,6 @@ test "runtime value in nested initializer passed as pointer to function" { |
| 1924 | 1924 | } |
| 1925 | 1925 | |
| 1926 | 1926 | test "struct field default value is a call" { |
| 1927 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1928 | 1927 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1929 | 1928 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1930 | 1929 | |
| ... | ... | @@ -2154,3 +2153,26 @@ test "align 1 struct parameter dereferenced and returned" { |
| 2154 | 2153 | .little => try expect(s.a == 0x05040302), |
| 2155 | 2154 | } |
| 2156 | 2155 | } |
| 2156 | ||
| 2157 | test "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" { |
| 300 | 300 | } |
| 301 | 301 | |
| 302 | 302 | test "switch on error union if else capture" { |
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 304 | 303 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 305 | 304 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 306 | 305 |
test/behavior/try.zig-2| ... | ... | @@ -122,7 +122,6 @@ test "'return try' through conditional" { |
| 122 | 122 | } |
| 123 | 123 | |
| 124 | 124 | test "try ptr propagation const" { |
| 125 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 126 | 125 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 127 | 126 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 128 | 127 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| ... | ... | @@ -155,7 +154,6 @@ test "try ptr propagation const" { |
| 155 | 154 | } |
| 156 | 155 | |
| 157 | 156 | test "try ptr propagation mutate" { |
| 158 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 159 | 157 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 160 | 158 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 161 | 159 | 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" { |
| 384 | 384 | } |
| 385 | 385 | |
| 386 | 386 | test "tuple of struct concatenation and coercion to array" { |
| 387 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 388 | 387 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 389 | 388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 390 | 389 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/type.zig-1| ... | ... | @@ -408,7 +408,6 @@ test "Type.Enum" { |
| 408 | 408 | } |
| 409 | 409 | |
| 410 | 410 | test "Type.Union" { |
| 411 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 412 | 411 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 413 | 412 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 414 | 413 |
test/behavior/union.zig+1-3| ... | ... | @@ -1335,9 +1335,9 @@ test "union field ptr - zero sized field" { |
| 1335 | 1335 | } |
| 1336 | 1336 | |
| 1337 | 1337 | test "packed union in packed struct" { |
| 1338 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1339 | 1338 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1340 | 1339 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1340 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1341 | 1341 | |
| 1342 | 1342 | const S = packed struct { |
| 1343 | 1343 | nested: packed union { |
| ... | ... | @@ -1420,7 +1420,6 @@ test "union reassignment can use previous value" { |
| 1420 | 1420 | } |
| 1421 | 1421 | |
| 1422 | 1422 | test "reinterpreting enum value inside packed union" { |
| 1423 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1424 | 1423 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1425 | 1424 | |
| 1426 | 1425 | const U = packed union { |
| ... | ... | @@ -1612,7 +1611,6 @@ test "memset extern union" { |
| 1612 | 1611 | } |
| 1613 | 1612 | |
| 1614 | 1613 | test "memset packed union" { |
| 1615 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1616 | 1614 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1617 | 1615 | |
| 1618 | 1616 | const U = packed union { |
test/behavior/var_args.zig-1| ... | ... | @@ -186,7 +186,6 @@ test "coerce reference to var arg" { |
| 186 | 186 | } |
| 187 | 187 | |
| 188 | 188 | test "variadic functions" { |
| 189 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 190 | 189 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 191 | 190 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 192 | 191 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
test/behavior/vector.zig+21-57| ... | ... | @@ -394,7 +394,6 @@ test "vector @splat" { |
| 394 | 394 | } |
| 395 | 395 | |
| 396 | 396 | test "load vector elements via comptime index" { |
| 397 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 398 | 397 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 399 | 398 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 400 | 399 | |
| ... | ... | @@ -415,7 +414,6 @@ test "load vector elements via comptime index" { |
| 415 | 414 | } |
| 416 | 415 | |
| 417 | 416 | test "store vector elements via comptime index" { |
| 418 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 419 | 417 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 420 | 418 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 421 | 419 | |
| ... | ... | @@ -441,49 +439,6 @@ test "store vector elements via comptime index" { |
| 441 | 439 | try comptime S.doTheTest(); |
| 442 | 440 | } |
| 443 | 441 | |
| 444 | test "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 | ||
| 465 | test "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 | ||
| 487 | 442 | test "initialize vector which is a struct field" { |
| 488 | 443 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 489 | 444 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -567,20 +522,20 @@ test "vector division operators" { |
| 567 | 522 | }; |
| 568 | 523 | if (!is_signed_int) { |
| 569 | 524 | const d0 = x / y; |
| 570 | for (@as([4]T, d0), 0..) |v, i| { | |
| 525 | inline for (@as([4]T, d0), 0..) |v, i| { | |
| 571 | 526 | try expect(x[i] / y[i] == v); |
| 572 | 527 | } |
| 573 | 528 | } |
| 574 | 529 | const d1 = @divExact(x, y); |
| 575 | for (@as([4]T, d1), 0..) |v, i| { | |
| 530 | inline for (@as([4]T, d1), 0..) |v, i| { | |
| 576 | 531 | try expect(@divExact(x[i], y[i]) == v); |
| 577 | 532 | } |
| 578 | 533 | const d2 = @divFloor(x, y); |
| 579 | for (@as([4]T, d2), 0..) |v, i| { | |
| 534 | inline for (@as([4]T, d2), 0..) |v, i| { | |
| 580 | 535 | try expect(@divFloor(x[i], y[i]) == v); |
| 581 | 536 | } |
| 582 | 537 | const d3 = @divTrunc(x, y); |
| 583 | for (@as([4]T, d3), 0..) |v, i| { | |
| 538 | inline for (@as([4]T, d3), 0..) |v, i| { | |
| 584 | 539 | try expect(@divTrunc(x[i], y[i]) == v); |
| 585 | 540 | } |
| 586 | 541 | } |
| ... | ... | @@ -592,16 +547,16 @@ test "vector division operators" { |
| 592 | 547 | }; |
| 593 | 548 | if (!is_signed_int and @typeInfo(T) != .float) { |
| 594 | 549 | const r0 = x % y; |
| 595 | for (@as([4]T, r0), 0..) |v, i| { | |
| 550 | inline for (@as([4]T, r0), 0..) |v, i| { | |
| 596 | 551 | try expect(x[i] % y[i] == v); |
| 597 | 552 | } |
| 598 | 553 | } |
| 599 | 554 | const r1 = @mod(x, y); |
| 600 | for (@as([4]T, r1), 0..) |v, i| { | |
| 555 | inline for (@as([4]T, r1), 0..) |v, i| { | |
| 601 | 556 | try expect(@mod(x[i], y[i]) == v); |
| 602 | 557 | } |
| 603 | 558 | const r2 = @rem(x, y); |
| 604 | for (@as([4]T, r2), 0..) |v, i| { | |
| 559 | inline for (@as([4]T, r2), 0..) |v, i| { | |
| 605 | 560 | try expect(@rem(x[i], y[i]) == v); |
| 606 | 561 | } |
| 607 | 562 | } |
| ... | ... | @@ -651,10 +606,15 @@ test "vector bitwise not operator" { |
| 651 | 606 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 652 | 607 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 653 | 608 | |
| 609 | if (builtin.cpu.arch == .aarch64_be) { | |
| 610 | // https://github.com/ziglang/zig/issues/24061 | |
| 611 | return error.SkipZigTest; | |
| 612 | } | |
| 613 | ||
| 654 | 614 | const S = struct { |
| 655 | 615 | fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void { |
| 656 | 616 | const y = ~x; |
| 657 | for (@as([4]T, y), 0..) |v, i| { | |
| 617 | inline for (@as([4]T, y), 0..) |v, i| { | |
| 658 | 618 | try expect(~x[i] == v); |
| 659 | 619 | } |
| 660 | 620 | } |
| ... | ... | @@ -685,10 +645,15 @@ test "vector boolean not operator" { |
| 685 | 645 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 686 | 646 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 687 | 647 | |
| 648 | if (builtin.cpu.arch == .aarch64_be) { | |
| 649 | // https://github.com/ziglang/zig/issues/24061 | |
| 650 | return error.SkipZigTest; | |
| 651 | } | |
| 652 | ||
| 688 | 653 | const S = struct { |
| 689 | 654 | fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void { |
| 690 | 655 | const y = !x; |
| 691 | for (@as([4]T, y), 0..) |v, i| { | |
| 656 | inline for (@as([4]T, y), 0..) |v, i| { | |
| 692 | 657 | try expect(!x[i] == v); |
| 693 | 658 | } |
| 694 | 659 | } |
| ... | ... | @@ -1359,7 +1324,6 @@ test "alignment of vectors" { |
| 1359 | 1324 | } |
| 1360 | 1325 | |
| 1361 | 1326 | test "loading the second vector from a slice of vectors" { |
| 1362 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1363 | 1327 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1364 | 1328 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1365 | 1329 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1450,6 +1414,7 @@ test "zero multiplicand" { |
| 1450 | 1414 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1451 | 1415 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1452 | 1416 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 1417 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1453 | 1418 | |
| 1454 | 1419 | const zeros = @Vector(2, u32){ 0.0, 0.0 }; |
| 1455 | 1420 | var ones = @Vector(2, u32){ 1.0, 1.0 }; |
| ... | ... | @@ -1530,8 +1495,7 @@ test "store packed vector element" { |
| 1530 | 1495 | |
| 1531 | 1496 | var v = @Vector(4, u1){ 1, 1, 1, 1 }; |
| 1532 | 1497 | try expectEqual(@Vector(4, u1){ 1, 1, 1, 1 }, v); |
| 1533 | var index: usize = 0; | |
| 1534 | _ = &index; | |
| 1498 | const index: usize = 0; | |
| 1535 | 1499 | v[index] = 0; |
| 1536 | 1500 | try expectEqual(@Vector(4, u1){ 0, 1, 1, 1 }, v); |
| 1537 | 1501 | } |
test/behavior/x86_64/access.zig+3-10| ... | ... | @@ -52,22 +52,15 @@ fn accessVector(comptime init: anytype) !void { |
| 52 | 52 | var vector: Vector = undefined; |
| 53 | 53 | vector = init; |
| 54 | 54 | 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; | |
| 59 | 56 | 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]; | |
| 62 | 58 | 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]; | |
| 65 | 60 | if (vector[ct_index] != ct_vals[1]) return error.Unexpected; |
| 66 | 61 | vector[ct_index] = ct_vals[0]; |
| 67 | if (vector[rt_index] != ct_vals[0]) return error.Unexpected; | |
| 68 | 62 | if (vector[ct_index] != ct_vals[0]) return error.Unexpected; |
| 69 | 63 | vector[ct_index] = rt_vals[1]; |
| 70 | if (vector[rt_index] != ct_vals[1]) return error.Unexpected; | |
| 71 | 64 | if (vector[ct_index] != ct_vals[1]) return error.Unexpected; |
| 72 | 65 | } |
| 73 | 66 | } |
test/cases/compile_errors/comptime_var_referenced_at_runtime.zig+10-10| ... | ... | @@ -75,31 +75,31 @@ export fn bax() void { |
| 75 | 75 | // |
| 76 | 76 | // :5:19: error: runtime value contains reference to comptime var |
| 77 | 77 | // :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 | |
| 79 | 79 | // :12:40: error: runtime value contains reference to comptime var |
| 80 | 80 | // :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 | |
| 82 | 82 | // :19:50: error: runtime value contains reference to comptime var |
| 83 | 83 | // :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 | |
| 85 | 85 | // :28:9: error: runtime value contains reference to comptime var |
| 86 | 86 | // :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 | |
| 88 | 88 | // :36:9: error: runtime value contains reference to comptime var |
| 89 | 89 | // :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 | |
| 91 | 91 | // :41:12: error: runtime value contains reference to comptime var |
| 92 | 92 | // :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 | |
| 94 | 94 | // :46:39: error: runtime value contains reference to comptime var |
| 95 | 95 | // :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 | |
| 97 | 97 | // :55:18: error: runtime value contains reference to comptime var |
| 98 | 98 | // :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 | |
| 100 | 100 | // :63:18: error: runtime value contains reference to comptime var |
| 101 | 101 | // :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 | |
| 103 | 103 | // :71:19: error: runtime value contains reference to comptime var |
| 104 | 104 | // :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: { |
| 47 | 47 | // error |
| 48 | 48 | // |
| 49 | 49 | // :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 | |
| 51 | 51 | // :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 | |
| 53 | 53 | // :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 | |
| 55 | 55 | // :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 | |
| 57 | 57 | // :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 | |
| 59 | 59 | // :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 | |
| 61 | 61 | // :34:40: error: global variable contains reference to comptime var |
| 62 | 62 | // :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 | |
| 64 | 64 | // :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 { |
| 21 | 21 | // error |
| 22 | 22 | // |
| 23 | 23 | // :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 | |
| 25 | 26 | // :17:29: note: called at comptime here |
test/cases/compile_errors/enum_field_value_references_enum.zig+2| ... | ... | @@ -1,6 +1,8 @@ |
| 1 | 1 | pub const Foo = enum(c_int) { |
| 2 | 2 | A = Foo.B, |
| 3 | 3 | C = D, |
| 4 | ||
| 5 | pub const B = 0; | |
| 4 | 6 | }; |
| 5 | 7 | export fn entry() void { |
| 6 | 8 | const s: Foo = Foo.E; |
test/cases/compile_errors/enum_field_value_references_nonexistent_circular.zig created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | pub const Foo = enum(c_int) { | |
| 2 | A = Foo.B, | |
| 3 | C = D, | |
| 4 | }; | |
| 5 | export fn entry() void { | |
| 6 | const s: Foo = Foo.E; | |
| 7 | _ = s; | |
| 8 | } | |
| 9 | const 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 { |
| 9 | 9 | // |
| 10 | 10 | // :3:10: error: runtime value contains reference to comptime var |
| 11 | 11 | // :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 @@ |
| 1 | const Foo = packed struct { | |
| 2 | a: u8, | |
| 3 | b: u32, | |
| 4 | }; | |
| 5 | ||
| 6 | export fn entry() void { | |
| 7 | var foo = Foo{ .a = 1, .b = 10 }; | |
| 8 | bar(&foo.b); | |
| 9 | } | |
| 10 | ||
| 11 | fn 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 @@ |
| 1 | const Foo = packed struct { | |
| 2 | a: u8, | |
| 3 | b: u32, | |
| 4 | }; | |
| 5 | ||
| 6 | export 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 | ||
| 12 | fn 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 { |
| 12 | 12 | |
| 13 | 13 | // error |
| 14 | 14 | // |
| 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 { |
| 12 | 12 | |
| 13 | 13 | // error |
| 14 | 14 | // |
| 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 {} |
| 6 | 6 | |
| 7 | 7 | // run |
| 8 | 8 | // 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 | |
| 10 | 10 | // pie=true |
test/run_translated_c.zig-104| ... | ... | @@ -1316,110 +1316,6 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 1316 | 1316 | \\} |
| 1317 | 1317 | , ""); |
| 1318 | 1318 | |
| 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 | ||
| 1423 | 1319 | cases.add("break from switch statement. Issue #8387", |
| 1424 | 1320 | \\#include <stdlib.h> |
| 1425 | 1321 | \\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 { |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | 39 | // No-OS entrypoint |
| 40 | export fn _start() callconv(.c) noreturn { | |
| 40 | export fn _start() callconv(.withStackAlign(.c, 1)) noreturn { | |
| 41 | 41 | var expected: [4]usize = undefined; |
| 42 | 42 | var unwound: [4]usize = undefined; |
| 43 | 43 | frame0(&expected, &unwound); |
test/tests.zig+24-18| ... | ... | @@ -1344,27 +1344,33 @@ const test_targets = blk: { |
| 1344 | 1344 | |
| 1345 | 1345 | // SPIR-V Targets |
| 1346 | 1346 | |
| 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 | //}, | |
| 1356 | 1359 | |
| 1357 | 1360 | // WASI Targets |
| 1358 | 1361 | |
| 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 | //}, | |
| 1368 | 1374 | .{ |
| 1369 | 1375 | .target = .{ |
| 1370 | 1376 | .cpu_arch = .wasm32, |