authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-06-16 16:06:35+03:30
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-06-18 13:38:58+02:00
loga5fbbb83050f2dad0a9ebc0bd995a5a8f58d0a49
tree13a6b0fb6e761b7dfa8ca09eefe9aa75d59c1e1a
parent93cd157da13b7c89fc809d326555cd56457b6c0b

spirv: composite integers

composite integers (wider than usize) are represented in as `[N]u32` arrays. however, no operations were implemented before. following operations are implemented: - bitwise (and, or, xor, not) - comparison (eq/neq) - add/sub/mul/shl/shr - `@abs`, `@intCast` this removes 36 SPIR-V behavior test skips. also fixed `derivePtr` to use `OpAccessChain` instead of `OpBitcast` for array pointer casts (e.g. `*[100]u8` to `*u8`) in logical addressing mode, where pointer bitcasts are not valid.

14 files changed, 1310 insertions(+), 93 deletions(-)

src/codegen/spirv/CodeGen.zig+1301-37
...@@ -5,6 +5,7 @@ const Signedness = std.lang.Signedness;...@@ -5,6 +5,7 @@ const Signedness = std.lang.Signedness;
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const log = std.log.scoped(.codegen);6const log = std.log.scoped(.codegen);
77
8const builtin = @import("builtin");
8const link = @import("../../link.zig");9const link = @import("../../link.zig");
9const codegen = @import("../../codegen.zig");10const codegen = @import("../../codegen.zig");
10const Zcu = @import("../../Zcu.zig");11const Zcu = @import("../../Zcu.zig");
...@@ -511,8 +512,8 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -511,8 +512,8 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
511 else => {},512 else => {},
512 }513 }
513514
514 if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |builtin| {515 if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |built_in| {
515 try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = builtin } });516 try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = built_in } });
516 }517 }
517518
518 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));519 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));
...@@ -956,6 +957,7 @@ fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {...@@ -956,6 +957,7 @@ fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {
956/// This function, unlike Module.constInt, takes care to bitcast957/// This function, unlike Module.constInt, takes care to bitcast
957/// the value to an unsigned int first for Kernels.958/// the value to an unsigned int first for Kernels.
958fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {959fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
960 const gpa = cg.module.gpa;
959 const zcu = cg.module.zcu;961 const zcu = cg.module.zcu;
960 const target = cg.module.zcu.getTarget();962 const target = cg.module.zcu.getTarget();
961 const scalar_ty = ty.scalarType(zcu);963 const scalar_ty = ty.scalarType(zcu);
...@@ -975,11 +977,18 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {...@@ -975,11 +977,18 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
975 .signed => @bitCast(@as(i64, @intCast(value))),977 .signed => @bitCast(@as(i64, @intCast(value))),
976 .unsigned => @as(u64, @intCast(value)),978 .unsigned => @as(u64, @intCast(value)),
977 };979 };
978 assert(backing_bits == 64);980 const n_limbs = backing_bits / Module.big_int_bits;
979 return cg.constructComposite(result_ty_id, &.{981 const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0;
980 try cg.constInt(.u32, @as(u32, @truncate(value64))),982 const scratch_top = cg.id_scratch.items.len;
981 try cg.constInt(.u32, @as(u32, @truncate(value64 << 32))),983 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
982 });984 const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
985 for (constituents, 0..) |*c, i| {
986 c.* = try cg.constInt(
987 .u32,
988 if (i < 2) @as(u32, @truncate(value64 >> @intCast(i * 32))) else fill,
989 );
990 }
991 return cg.constructComposite(result_ty_id, constituents);
983 }992 }
984993
985 const final_value: spec.LiteralContextDependentNumber = switch (target.os.tag) {994 const final_value: spec.LiteralContextDependentNumber = switch (target.os.tag) {
...@@ -1014,6 +1023,35 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {...@@ -1014,6 +1023,35 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
1014 return cg.constructCompositeSplat(ty, result_id);1023 return cg.constructCompositeSplat(ty, result_id);
1015}1024}
10161025
1026fn constIntBig(cg: *CodeGen, ty: Type, val: Value) !Id {
1027 const gpa = cg.module.gpa;
1028 const zcu = cg.module.zcu;
1029 const int_info = ty.intInfo(zcu);
1030 const backing_bits, _ = cg.module.backingIntBits(int_info.bits);
1031 const n_limbs = backing_bits / Module.big_int_bits;
1032 const result_ty_id = try cg.resolveType(ty, .indirect);
1033
1034 var bigint_space: Value.BigIntSpace = undefined;
1035 const bigint = val.toBigInt(&bigint_space, zcu);
1036
1037 const limb_values = try gpa.alloc(u32, n_limbs);
1038 defer gpa.free(limb_values);
1039
1040 const bytes = std.mem.sliceAsBytes(limb_values);
1041 bigint.writeTwosComplement(bytes, .little);
1042 if (builtin.cpu.arch.endian() == .big) {
1043 for (limb_values) |*limb| limb.* = @byteSwap(limb.*);
1044 }
1045
1046 const scratch_top = cg.id_scratch.items.len;
1047 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
1048 const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
1049 for (constituents, 0..) |*c, i| {
1050 c.* = try cg.constInt(.u32, limb_values[i]);
1051 }
1052 return cg.constructComposite(result_ty_id, constituents);
1053}
1054
1017pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const Id) !Id {1055pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const Id) !Id {
1018 const gpa = cg.module.gpa;1056 const gpa = cg.module.gpa;
1019 const result_id = cg.module.allocId();1057 const result_id = cg.module.allocId();
...@@ -1106,6 +1144,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1106,6 +1144,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
1106 .false, .true => break :cache try cg.constBool(val.toBool(), repr),1144 .false, .true => break :cache try cg.constBool(val.toBool(), repr),
1107 },1145 },
1108 .int => {1146 .int => {
1147 const int_info = ty.intInfo(zcu);
1148 _, const is_big_int = cg.module.backingIntBits(int_info.bits);
1149 if (is_big_int) {
1150 break :cache try cg.constIntBig(ty, val);
1151 }
1109 if (ty.isSignedInt(zcu)) {1152 if (ty.isSignedInt(zcu)) {
1110 break :cache try cg.constInt(ty, val.toSignedInt(zcu));1153 break :cache try cg.constInt(ty, val.toSignedInt(zcu));
1111 } else {1154 } else {
...@@ -1385,15 +1428,32 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {...@@ -1385,15 +1428,32 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1385 }1428 }
13861429
1387 if (oac.byte_offset == 0) {1430 if (oac.byte_offset == 0) {
1388 // Allow changing the pointer type child only to restructure arrays.1431 var depth: u32 = 0;
1389 // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T.1432 var cur = parent_ptr_ty.childType(zcu);
1390 const result_ptr_id = cg.module.allocId();1433 const dst_child = oac.new_ptr_ty.childType(zcu);
1391 try cg.body.emit(gpa, .OpBitcast, .{1434 while (cur.toIntern() != dst_child.toIntern()) {
1392 .id_result_type = result_ty_id,1435 if (cur.zigTypeTag(zcu) == .array) {
1393 .id_result = result_ptr_id,1436 cur = cur.childType(zcu);
1394 .operand = parent_ptr_id,1437 depth += 1;
1395 });1438 } else break;
1396 return result_ptr_id;1439 }
1440 if (depth > 0 and cur.toIntern() == dst_child.toIntern()) {
1441 const scratch_top = cg.id_scratch.items.len;
1442 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
1443 const zero = try cg.constInt(.u32, 0);
1444 const ids = try cg.id_scratch.addManyAsSlice(gpa, depth);
1445 @memset(ids, zero);
1446 return cg.accessChainId(result_ty_id, parent_ptr_id, ids);
1447 }
1448 if (target.os.tag == .opencl) {
1449 const result_ptr_id = cg.module.allocId();
1450 try cg.body.emit(gpa, .OpBitcast, .{
1451 .id_result_type = result_ty_id,
1452 .id_result = result_ptr_id,
1453 .operand = parent_ptr_id,
1454 });
1455 return result_ptr_id;
1456 }
1397 }1457 }
13981458
1399 return cg.fail("cannot perform pointer cast: '{f}' to '{f}'", .{1459 return cg.fail("cannot perform pointer cast: '{f}' to '{f}'", .{
...@@ -1684,10 +1744,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1684,10 +1744,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1684 return try cg.module.opaqueType("u0");1744 return try cg.module.opaqueType("u0");
1685 }1745 }
1686 const int_info = ty.intInfo(zcu);1746 const int_info = ty.intInfo(zcu);
1687 const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits);
1688 if (big_int and backing_bits > 64) {
1689 return cg.fail("integer width of {} bits is not yet supported on the SPIR-V backend", .{int_info.bits});
1690 }
1691 return try cg.module.intType(int_info.signedness, int_info.bits);1747 return try cg.module.intType(int_info.signedness, int_info.bits);
1692 },1748 },
1693 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),1749 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),
...@@ -2216,6 +2272,697 @@ const Temporary = struct {...@@ -2216,6 +2272,697 @@ const Temporary = struct {
2216 }2272 }
2217};2273};
22182274
2275/// composite integers are represented as [N]u32 arrays
2276const CompositeInt = struct {
2277 cg: *CodeGen,
2278 limbs: []Id,
2279 n_limbs: u16,
2280 info: ArithmeticTypeInfo,
2281
2282 fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt {
2283 const n_limbs: u16 = info.backing_bits / Module.big_int_bits;
2284 const gpa = cg.module.gpa;
2285 const u32_ty_id = try cg.resolveType(.u32, .direct);
2286 const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs);
2287 for (limbs, 0..) |*limb, i| {
2288 const result_id = cg.module.allocId();
2289 try cg.body.emit(gpa, .OpCompositeExtract, .{
2290 .id_result_type = u32_ty_id,
2291 .id_result = result_id,
2292 .composite = composite_id,
2293 .indexes = &.{@as(u32, @intCast(i))},
2294 });
2295 limb.* = result_id;
2296 }
2297 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };
2298 }
2299
2300 fn fromLimbs(cg: *CodeGen, limbs: []Id, info: ArithmeticTypeInfo) CompositeInt {
2301 return .{
2302 .cg = cg,
2303 .limbs = limbs,
2304 .n_limbs = @intCast(limbs.len),
2305 .info = info,
2306 };
2307 }
2308
2309 fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt {
2310 const n_limbs: u16 = info.backing_bits / Module.big_int_bits;
2311 const limbs = try cg.id_scratch.addManyAsSlice(cg.module.gpa, n_limbs);
2312 const zero_id = try cg.constInt(.u32, @as(u32, 0));
2313 for (limbs) |*limb| limb.* = zero_id;
2314 return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info };
2315 }
2316
2317 fn materialize(ci: CompositeInt, ty: Type) !Id {
2318 const result_ty_id = try ci.cg.resolveType(ty, .indirect);
2319 return ci.cg.constructComposite(result_ty_id, ci.limbs);
2320 }
2321
2322 fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id {
2323 const cg = ci.cg;
2324 const gpa = cg.module.gpa;
2325 const u32_ty_id = try cg.resolveType(.u32, .direct);
2326 const result_id = cg.module.allocId();
2327 try cg.body.emitRaw(gpa, opcode, 4);
2328 cg.body.writeOperand(Id, u32_ty_id);
2329 cg.body.writeOperand(Id, result_id);
2330 cg.body.writeOperand(Id, lhs);
2331 cg.body.writeOperand(Id, rhs);
2332 return result_id;
2333 }
2334
2335 fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id {
2336 const cg = ci.cg;
2337 const gpa = cg.module.gpa;
2338 const u32_ty_id = try cg.resolveType(.u32, .direct);
2339 const result_id = cg.module.allocId();
2340 try cg.body.emitRaw(gpa, opcode, 3);
2341 cg.body.writeOperand(Id, u32_ty_id);
2342 cg.body.writeOperand(Id, result_id);
2343 cg.body.writeOperand(Id, operand);
2344 return result_id;
2345 }
2346
2347 fn bitwiseOp(ci: CompositeInt, other: CompositeInt, opcode: Opcode) !CompositeInt {
2348 const cg = ci.cg;
2349 const gpa = cg.module.gpa;
2350 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2351 for (result_limbs, 0..) |*r, i| {
2352 r.* = try ci.limbBinOp(opcode, ci.limbs[i], other.limbs[i]);
2353 }
2354 return .fromLimbs(cg, result_limbs, ci.info);
2355 }
2356
2357 fn bitwiseNot(ci: CompositeInt) !CompositeInt {
2358 const cg = ci.cg;
2359 const gpa = cg.module.gpa;
2360 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2361 for (result_limbs, 0..) |*r, i| {
2362 r.* = try ci.limbUnOp(.OpNot, ci.limbs[i]);
2363 }
2364 return .fromLimbs(cg, result_limbs, ci.info);
2365 }
2366
2367 fn cmp(ci: CompositeInt, other: CompositeInt, op: std.math.CompareOperator) !Id {
2368 const cg = ci.cg;
2369 const gpa = cg.module.gpa;
2370 const bool_ty_id = try cg.resolveType(.bool, .direct);
2371
2372 switch (op) {
2373 .eq, .neq => {
2374 var result = blk: {
2375 const r = cg.module.allocId();
2376 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2377 cg.body.writeOperand(Id, bool_ty_id);
2378 cg.body.writeOperand(Id, r);
2379 cg.body.writeOperand(Id, ci.limbs[0]);
2380 cg.body.writeOperand(Id, other.limbs[0]);
2381 break :blk r;
2382 };
2383 for (1..ci.n_limbs) |i| {
2384 const limb_eq = cg.module.allocId();
2385 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2386 cg.body.writeOperand(Id, bool_ty_id);
2387 cg.body.writeOperand(Id, limb_eq);
2388 cg.body.writeOperand(Id, ci.limbs[i]);
2389 cg.body.writeOperand(Id, other.limbs[i]);
2390 const combined = cg.module.allocId();
2391 try cg.body.emitRaw(gpa, .OpLogicalAnd, 4);
2392 cg.body.writeOperand(Id, bool_ty_id);
2393 cg.body.writeOperand(Id, combined);
2394 cg.body.writeOperand(Id, result);
2395 cg.body.writeOperand(Id, limb_eq);
2396 result = combined;
2397 }
2398 if (op == .neq) {
2399 const negated = cg.module.allocId();
2400 try cg.body.emitRaw(gpa, .OpLogicalNot, 3);
2401 cg.body.writeOperand(Id, bool_ty_id);
2402 cg.body.writeOperand(Id, negated);
2403 cg.body.writeOperand(Id, result);
2404 result = negated;
2405 }
2406 return result;
2407 },
2408 .lt, .lte, .gt, .gte => {
2409 const is_lt = (op == .lt or op == .lte);
2410 const is_strict = (op == .lt or op == .gt);
2411 var result = try cg.constBool(!is_strict, .direct);
2412
2413 for (0..ci.n_limbs) |i| {
2414 const l = ci.limbs[i];
2415 const r = other.limbs[i];
2416 const limb_ne = cg.module.allocId();
2417 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
2418 cg.body.writeOperand(Id, bool_ty_id);
2419 cg.body.writeOperand(Id, limb_ne);
2420 cg.body.writeOperand(Id, l);
2421 cg.body.writeOperand(Id, r);
2422
2423 const is_top = (i == ci.n_limbs - 1);
2424 const use_signed = is_top and ci.info.signedness == .signed;
2425 var cmp_l = l;
2426 var cmp_r = r;
2427 if (use_signed) {
2428 const i32_ty_id = try cg.resolveType(.i32, .direct);
2429 const sl = cg.module.allocId();
2430 try cg.body.emit(gpa, .OpBitcast, .{
2431 .id_result_type = i32_ty_id,
2432 .id_result = sl,
2433 .operand = l,
2434 });
2435 const sr = cg.module.allocId();
2436 try cg.body.emit(gpa, .OpBitcast, .{
2437 .id_result_type = i32_ty_id,
2438 .id_result = sr,
2439 .operand = r,
2440 });
2441 cmp_l = sl;
2442 cmp_r = sr;
2443 }
2444
2445 const cmp_opcode: Opcode = if (is_lt)
2446 (if (use_signed) .OpSLessThan else .OpULessThan)
2447 else
2448 (if (use_signed) .OpSGreaterThan else .OpUGreaterThan);
2449
2450 const limb_cmp = cg.module.allocId();
2451 try cg.body.emitRaw(gpa, cmp_opcode, 4);
2452 cg.body.writeOperand(Id, bool_ty_id);
2453 cg.body.writeOperand(Id, limb_cmp);
2454 cg.body.writeOperand(Id, cmp_l);
2455 cg.body.writeOperand(Id, cmp_r);
2456
2457 const selected = cg.module.allocId();
2458 try cg.body.emit(gpa, .OpSelect, .{
2459 .id_result_type = bool_ty_id,
2460 .id_result = selected,
2461 .condition = limb_ne,
2462 .object_1 = limb_cmp,
2463 .object_2 = result,
2464 });
2465 result = selected;
2466 }
2467 return result;
2468 },
2469 }
2470 }
2471
2472 fn addSub(ci: CompositeInt, other: CompositeInt, comptime is_add: bool) !CompositeInt {
2473 const cg = ci.cg;
2474 const gpa = cg.module.gpa;
2475 const pt = cg.pt;
2476 const zcu = cg.module.zcu;
2477 const ip = &zcu.intern_pool;
2478 const comp = zcu.comp;
2479 const io = comp.io;
2480
2481 const u32_zig = try pt.intType(.unsigned, 32);
2482 const u32_ty_id = try cg.resolveType(.u32, .direct);
2483 const carry_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{
2484 .types = &.{ u32_zig.toIntern(), u32_zig.toIntern() },
2485 .values = &.{ .none, .none },
2486 }));
2487 const carry_struct_ty_id = try cg.resolveType(carry_struct_ty, .direct);
2488
2489 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2490 var carry_id = try cg.constInt(.u32, @as(u32, 0));
2491
2492 const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow;
2493
2494 for (0..ci.n_limbs) |i| {
2495 const op1 = cg.module.allocId();
2496 try cg.body.emitRaw(gpa, opcode, 4);
2497 cg.body.writeOperand(Id, carry_struct_ty_id);
2498 cg.body.writeOperand(Id, op1);
2499 cg.body.writeOperand(Id, ci.limbs[i]);
2500 cg.body.writeOperand(Id, other.limbs[i]);
2501
2502 const sum1 = cg.module.allocId();
2503 try cg.body.emit(gpa, .OpCompositeExtract, .{
2504 .id_result_type = u32_ty_id,
2505 .id_result = sum1,
2506 .composite = op1,
2507 .indexes = &.{0},
2508 });
2509 const carry1 = cg.module.allocId();
2510 try cg.body.emit(gpa, .OpCompositeExtract, .{
2511 .id_result_type = u32_ty_id,
2512 .id_result = carry1,
2513 .composite = op1,
2514 .indexes = &.{1},
2515 });
2516
2517 const op2 = cg.module.allocId();
2518 try cg.body.emitRaw(gpa, opcode, 4);
2519 cg.body.writeOperand(Id, carry_struct_ty_id);
2520 cg.body.writeOperand(Id, op2);
2521 cg.body.writeOperand(Id, sum1);
2522 cg.body.writeOperand(Id, carry_id);
2523
2524 result_limbs[i] = cg.module.allocId();
2525 try cg.body.emit(gpa, .OpCompositeExtract, .{
2526 .id_result_type = u32_ty_id,
2527 .id_result = result_limbs[i],
2528 .composite = op2,
2529 .indexes = &.{0},
2530 });
2531 const carry2 = cg.module.allocId();
2532 try cg.body.emit(gpa, .OpCompositeExtract, .{
2533 .id_result_type = u32_ty_id,
2534 .id_result = carry2,
2535 .composite = op2,
2536 .indexes = &.{1},
2537 });
2538
2539 carry_id = try ci.limbBinOp(.OpBitwiseOr, carry1, carry2);
2540 }
2541
2542 return .fromLimbs(cg, result_limbs, ci.info);
2543 }
2544
2545 fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt {
2546 const cg = ci.cg;
2547 const gpa = cg.module.gpa;
2548 const u32_ty_id = try cg.resolveType(.u32, .direct);
2549 const bool_ty_id = try cg.resolveType(.bool, .direct);
2550 const zero_id = try cg.constInt(.u32, @as(u32, 0));
2551 const five_id = try cg.constInt(.u32, @as(u32, 5));
2552 const thirty_one_id = try cg.constInt(.u32, @as(u32, 31));
2553 const thirty_two_id = try cg.constInt(.u32, @as(u32, 32));
2554
2555 const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, five_id);
2556 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);
2557 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);
2558 const frac_is_zero = blk: {
2559 const r = cg.module.allocId();
2560 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2561 cg.body.writeOperand(Id, bool_ty_id);
2562 cg.body.writeOperand(Id, r);
2563 cg.body.writeOperand(Id, frac);
2564 cg.body.writeOperand(Id, zero_id);
2565 break :blk r;
2566 };
2567
2568 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2569
2570 for (0..ci.n_limbs) |i| {
2571 const i_id = try cg.constInt(.u32, @as(u32, @intCast(i)));
2572 var main_val = zero_id;
2573 var carry_val = zero_id;
2574
2575 for (0..ci.n_limbs) |j| {
2576 const j_id = try cg.constInt(.u32, @as(u32, @intCast(j)));
2577 const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole);
2578
2579 const is_main = blk: {
2580 const r = cg.module.allocId();
2581 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2582 cg.body.writeOperand(Id, bool_ty_id);
2583 cg.body.writeOperand(Id, r);
2584 cg.body.writeOperand(Id, j_plus_whole);
2585 cg.body.writeOperand(Id, i_id);
2586 break :blk r;
2587 };
2588 const shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], frac);
2589 main_val = blk: {
2590 const r = cg.module.allocId();
2591 try cg.body.emit(gpa, .OpSelect, .{
2592 .id_result_type = u32_ty_id,
2593 .id_result = r,
2594 .condition = is_main,
2595 .object_1 = shifted,
2596 .object_2 = main_val,
2597 });
2598 break :blk r;
2599 };
2600
2601 const one_id = try cg.constInt(.u32, @as(u32, 1));
2602 const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id);
2603 const is_carry = blk: {
2604 const r = cg.module.allocId();
2605 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2606 cg.body.writeOperand(Id, bool_ty_id);
2607 cg.body.writeOperand(Id, r);
2608 cg.body.writeOperand(Id, j_plus_whole_plus_1);
2609 cg.body.writeOperand(Id, i_id);
2610 break :blk r;
2611 };
2612 const carry_shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], comp_frac);
2613 const guarded_carry = blk: {
2614 const r = cg.module.allocId();
2615 try cg.body.emit(gpa, .OpSelect, .{
2616 .id_result_type = u32_ty_id,
2617 .id_result = r,
2618 .condition = frac_is_zero,
2619 .object_1 = zero_id,
2620 .object_2 = carry_shifted,
2621 });
2622 break :blk r;
2623 };
2624 carry_val = blk: {
2625 const r = cg.module.allocId();
2626 try cg.body.emit(gpa, .OpSelect, .{
2627 .id_result_type = u32_ty_id,
2628 .id_result = r,
2629 .condition = is_carry,
2630 .object_1 = guarded_carry,
2631 .object_2 = carry_val,
2632 });
2633 break :blk r;
2634 };
2635 }
2636
2637 result_limbs[i] = try ci.limbBinOp(.OpBitwiseOr, main_val, carry_val);
2638 }
2639
2640 return .fromLimbs(cg, result_limbs, ci.info);
2641 }
2642
2643 fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt {
2644 const cg = ci.cg;
2645 const gpa = cg.module.gpa;
2646 const u32_ty_id = try cg.resolveType(.u32, .direct);
2647 const bool_ty_id = try cg.resolveType(.bool, .direct);
2648 const zero_id = try cg.constInt(.u32, @as(u32, 0));
2649 const five_id = try cg.constInt(.u32, @as(u32, 5));
2650 const thirty_one_id = try cg.constInt(.u32, @as(u32, 31));
2651 const thirty_two_id = try cg.constInt(.u32, @as(u32, 32));
2652
2653 const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, five_id);
2654 const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id);
2655 const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac);
2656 const frac_is_zero = blk: {
2657 const r = cg.module.allocId();
2658 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2659 cg.body.writeOperand(Id, bool_ty_id);
2660 cg.body.writeOperand(Id, r);
2661 cg.body.writeOperand(Id, frac);
2662 cg.body.writeOperand(Id, zero_id);
2663 break :blk r;
2664 };
2665
2666 const fill_id = if (is_arithmetic) blk: {
2667 const i32_ty_id = try cg.resolveType(.i32, .direct);
2668 const msb_signed = cg.module.allocId();
2669 try cg.body.emit(gpa, .OpBitcast, .{
2670 .id_result_type = i32_ty_id,
2671 .id_result = msb_signed,
2672 .operand = ci.limbs[ci.n_limbs - 1],
2673 });
2674 const shift31 = try cg.constInt(.i32, @as(i32, 31));
2675 const sign_ext = cg.module.allocId();
2676 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
2677 cg.body.writeOperand(Id, i32_ty_id);
2678 cg.body.writeOperand(Id, sign_ext);
2679 cg.body.writeOperand(Id, msb_signed);
2680 cg.body.writeOperand(Id, shift31);
2681 const back = cg.module.allocId();
2682 try cg.body.emit(gpa, .OpBitcast, .{
2683 .id_result_type = u32_ty_id,
2684 .id_result = back,
2685 .operand = sign_ext,
2686 });
2687 break :blk back;
2688 } else zero_id;
2689
2690 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2691
2692 const arith_carry_init = if (is_arithmetic) blk: {
2693 const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac);
2694 const guarded = cg.module.allocId();
2695 try cg.body.emit(gpa, .OpSelect, .{
2696 .id_result_type = u32_ty_id,
2697 .id_result = guarded,
2698 .condition = frac_is_zero,
2699 .object_1 = zero_id,
2700 .object_2 = shifted_fill,
2701 });
2702 break :blk guarded;
2703 } else zero_id;
2704
2705 for (0..ci.n_limbs) |i| {
2706 const i_id = try cg.constInt(.u32, @as(u32, @intCast(i)));
2707 var main_val = fill_id;
2708 var carry_val = arith_carry_init;
2709
2710 for (0..ci.n_limbs) |j| {
2711 const j_id = try cg.constInt(.u32, @as(u32, @intCast(j)));
2712 const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole);
2713 const is_main = blk: {
2714 const r = cg.module.allocId();
2715 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2716 cg.body.writeOperand(Id, bool_ty_id);
2717 cg.body.writeOperand(Id, r);
2718 cg.body.writeOperand(Id, j_id);
2719 cg.body.writeOperand(Id, i_plus_whole);
2720 break :blk r;
2721 };
2722 const shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], frac);
2723 main_val = blk: {
2724 const r = cg.module.allocId();
2725 try cg.body.emit(gpa, .OpSelect, .{
2726 .id_result_type = u32_ty_id,
2727 .id_result = r,
2728 .condition = is_main,
2729 .object_1 = shifted,
2730 .object_2 = main_val,
2731 });
2732 break :blk r;
2733 };
2734
2735 const one_id = try cg.constInt(.u32, @as(u32, 1));
2736 const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id);
2737 const is_carry = blk: {
2738 const r = cg.module.allocId();
2739 try cg.body.emitRaw(gpa, .OpIEqual, 4);
2740 cg.body.writeOperand(Id, bool_ty_id);
2741 cg.body.writeOperand(Id, r);
2742 cg.body.writeOperand(Id, j_id);
2743 cg.body.writeOperand(Id, i_plus_whole_plus_1);
2744 break :blk r;
2745 };
2746 const carry_shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], comp_frac);
2747 const guarded_carry = blk: {
2748 const r = cg.module.allocId();
2749 try cg.body.emit(gpa, .OpSelect, .{
2750 .id_result_type = u32_ty_id,
2751 .id_result = r,
2752 .condition = frac_is_zero,
2753 .object_1 = zero_id,
2754 .object_2 = carry_shifted,
2755 });
2756 break :blk r;
2757 };
2758 carry_val = blk: {
2759 const r = cg.module.allocId();
2760 try cg.body.emit(gpa, .OpSelect, .{
2761 .id_result_type = u32_ty_id,
2762 .id_result = r,
2763 .condition = is_carry,
2764 .object_1 = guarded_carry,
2765 .object_2 = carry_val,
2766 });
2767 break :blk r;
2768 };
2769 }
2770
2771 result_limbs[i] = try ci.limbBinOp(.OpBitwiseOr, main_val, carry_val);
2772 }
2773
2774 return .fromLimbs(cg, result_limbs, ci.info);
2775 }
2776
2777 fn mul(ci: CompositeInt, other: CompositeInt, comptime wide: bool) ![]Id {
2778 const cg = ci.cg;
2779 const gpa = cg.module.gpa;
2780 const pt = cg.pt;
2781 const zcu = cg.module.zcu;
2782 const ip = &zcu.intern_pool;
2783 const comp = zcu.comp;
2784 const io = comp.io;
2785 const target = zcu.getTarget();
2786
2787 const n: usize = ci.n_limbs;
2788 const total: usize = if (wide) 2 * n else n;
2789 const u32_zig = try pt.intType(.unsigned, 32);
2790 const u32_ty_id = try cg.resolveType(.u32, .direct);
2791
2792 const pair_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{
2793 .types = &.{ u32_zig.toIntern(), u32_zig.toIntern() },
2794 .values = &.{ .none, .none },
2795 }));
2796 const pair_struct_ty_id = try cg.resolveType(pair_struct_ty, .direct);
2797
2798 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, total);
2799 const zero_id = try cg.constInt(.u32, @as(u32, 0));
2800 for (result_limbs) |*r| r.* = zero_id;
2801
2802 for (0..n) |i| {
2803 var carry_id = zero_id;
2804 for (0..n) |j| {
2805 const k = i + j;
2806 if (k >= total) break;
2807
2808 var lo: Id = undefined;
2809 var hi: Id = undefined;
2810 switch (target.os.tag) {
2811 .opencl => {
2812 lo = cg.module.allocId();
2813 try cg.body.emitRaw(gpa, .OpIMul, 4);
2814 cg.body.writeOperand(Id, u32_ty_id);
2815 cg.body.writeOperand(Id, lo);
2816 cg.body.writeOperand(Id, ci.limbs[i]);
2817 cg.body.writeOperand(Id, other.limbs[j]);
2818
2819 const set = try cg.importExtendedSet();
2820 hi = cg.module.allocId();
2821 try cg.body.emit(gpa, .OpExtInst, .{
2822 .id_result_type = u32_ty_id,
2823 .id_result = hi,
2824 .set = set,
2825 .instruction = .{ .inst = @intFromEnum(spec.OpenClOpcode.u_mul_hi) },
2826 .id_ref_4 = &.{ ci.limbs[i], other.limbs[j] },
2827 });
2828 },
2829 else => {
2830 const mul_result = cg.module.allocId();
2831 try cg.body.emitRaw(gpa, .OpUMulExtended, 4);
2832 cg.body.writeOperand(Id, pair_struct_ty_id);
2833 cg.body.writeOperand(Id, mul_result);
2834 cg.body.writeOperand(Id, ci.limbs[i]);
2835 cg.body.writeOperand(Id, other.limbs[j]);
2836
2837 lo = cg.module.allocId();
2838 try cg.body.emit(gpa, .OpCompositeExtract, .{
2839 .id_result_type = u32_ty_id,
2840 .id_result = lo,
2841 .composite = mul_result,
2842 .indexes = &.{0},
2843 });
2844 hi = cg.module.allocId();
2845 try cg.body.emit(gpa, .OpCompositeExtract, .{
2846 .id_result_type = u32_ty_id,
2847 .id_result = hi,
2848 .composite = mul_result,
2849 .indexes = &.{1},
2850 });
2851 },
2852 }
2853
2854 const add1 = cg.module.allocId();
2855 try cg.body.emitRaw(gpa, .OpIAddCarry, 4);
2856 cg.body.writeOperand(Id, pair_struct_ty_id);
2857 cg.body.writeOperand(Id, add1);
2858 cg.body.writeOperand(Id, result_limbs[k]);
2859 cg.body.writeOperand(Id, lo);
2860
2861 const sum1 = cg.module.allocId();
2862 try cg.body.emit(gpa, .OpCompositeExtract, .{
2863 .id_result_type = u32_ty_id,
2864 .id_result = sum1,
2865 .composite = add1,
2866 .indexes = &.{0},
2867 });
2868 const c1 = cg.module.allocId();
2869 try cg.body.emit(gpa, .OpCompositeExtract, .{
2870 .id_result_type = u32_ty_id,
2871 .id_result = c1,
2872 .composite = add1,
2873 .indexes = &.{1},
2874 });
2875
2876 const add2 = cg.module.allocId();
2877 try cg.body.emitRaw(gpa, .OpIAddCarry, 4);
2878 cg.body.writeOperand(Id, pair_struct_ty_id);
2879 cg.body.writeOperand(Id, add2);
2880 cg.body.writeOperand(Id, sum1);
2881 cg.body.writeOperand(Id, carry_id);
2882
2883 result_limbs[k] = cg.module.allocId();
2884 try cg.body.emit(gpa, .OpCompositeExtract, .{
2885 .id_result_type = u32_ty_id,
2886 .id_result = result_limbs[k],
2887 .composite = add2,
2888 .indexes = &.{0},
2889 });
2890 const c2 = cg.module.allocId();
2891 try cg.body.emit(gpa, .OpCompositeExtract, .{
2892 .id_result_type = u32_ty_id,
2893 .id_result = c2,
2894 .composite = add2,
2895 .indexes = &.{1},
2896 });
2897
2898 const hi_plus_c1 = try ci.limbBinOp(.OpIAdd, hi, c1);
2899 carry_id = try ci.limbBinOp(.OpIAdd, hi_plus_c1, c2);
2900 }
2901 if (wide and i + n < 2 * n) {
2902 result_limbs[i + n] = try ci.limbBinOp(.OpIAdd, result_limbs[i + n], carry_id);
2903 }
2904 }
2905
2906 return result_limbs;
2907 }
2908
2909 fn normalize(ci: CompositeInt) !CompositeInt {
2910 if (ci.info.bits == ci.info.backing_bits) return ci;
2911 const cg = ci.cg;
2912 const gpa = cg.module.gpa;
2913 const top_bits: u16 = ci.info.bits % Module.big_int_bits;
2914 assert(top_bits != 0);
2915
2916 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs);
2917 for (0..ci.n_limbs - 1) |i| {
2918 result_limbs[i] = ci.limbs[i];
2919 }
2920
2921 const top_limb = ci.limbs[ci.n_limbs - 1];
2922 switch (ci.info.signedness) {
2923 .unsigned => {
2924 const mask_val: u32 = (@as(u32, 1) << @as(u5, @intCast(top_bits))) - 1;
2925 const mask_id = try cg.constInt(.u32, mask_val);
2926 result_limbs[ci.n_limbs - 1] = try ci.limbBinOp(.OpBitwiseAnd, top_limb, mask_id);
2927 },
2928 .signed => {
2929 const u32_ty_id = try cg.resolveType(.u32, .direct);
2930 const i32_ty_id = try cg.resolveType(.i32, .direct);
2931 const shift_amt: u32 = 32 - top_bits;
2932 const shift_id = try cg.constInt(.u32, shift_amt);
2933
2934 const as_signed = cg.module.allocId();
2935 try cg.body.emit(gpa, .OpBitcast, .{
2936 .id_result_type = i32_ty_id,
2937 .id_result = as_signed,
2938 .operand = top_limb,
2939 });
2940 const shifted_left = cg.module.allocId();
2941 try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4);
2942 cg.body.writeOperand(Id, i32_ty_id);
2943 cg.body.writeOperand(Id, shifted_left);
2944 cg.body.writeOperand(Id, as_signed);
2945 cg.body.writeOperand(Id, shift_id);
2946 const shifted_right = cg.module.allocId();
2947 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
2948 cg.body.writeOperand(Id, i32_ty_id);
2949 cg.body.writeOperand(Id, shifted_right);
2950 cg.body.writeOperand(Id, shifted_left);
2951 cg.body.writeOperand(Id, shift_id);
2952 const back = cg.module.allocId();
2953 try cg.body.emit(gpa, .OpBitcast, .{
2954 .id_result_type = u32_ty_id,
2955 .id_result = back,
2956 .operand = shifted_right,
2957 });
2958 result_limbs[ci.n_limbs - 1] = back;
2959 },
2960 }
2961
2962 return .fromLimbs(cg, result_limbs, ci.info);
2963 }
2964};
2965
2219/// Initialize a `Temporary` from an AIR value.2966/// Initialize a `Temporary` from an AIR value.
2220fn temporary(cg: *CodeGen, inst: Air.Inst.Ref) !Temporary {2967fn temporary(cg: *CodeGen, inst: Air.Inst.Ref) !Temporary {
2221 return .{2968 return .{
...@@ -3234,7 +3981,21 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id {...@@ -3234,7 +3981,21 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id {
3234 .xor => .OpBitwiseXor,3981 .xor => .OpBitwiseXor,
3235 },3982 },
3236 .float => unreachable,3983 .float => unreachable,
3237 .composite_integer => unreachable, // TODO3984 .composite_integer => {
3985 const spv_opcode: Opcode = switch (op) {
3986 .bit_and => .OpBitwiseAnd,
3987 .bit_or => .OpBitwiseOr,
3988 .xor => .OpBitwiseXor,
3989 };
3990 const lhs_id = try lhs.materialize(cg);
3991 const rhs_id = try rhs.materialize(cg);
3992 const scratch_top = cg.id_scratch.items.len;
3993 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
3994 const ci_lhs = try CompositeInt.init(cg, lhs_id, info);
3995 const ci_rhs = try CompositeInt.init(cg, rhs_id, info);
3996 const ci_result = try ci_lhs.bitwiseOp(ci_rhs, spv_opcode);
3997 return try ci_result.materialize(lhs.ty);
3998 },
3238 };3999 };
32394000
3240 const result = try cg.buildBinary(opcode, lhs, rhs);4001 const result = try cg.buildBinary(opcode, lhs, rhs);
...@@ -3256,7 +4017,39 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode...@@ -3256,7 +4017,39 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode
32564017
3257 const info = cg.arithmeticTypeInfo(result_ty);4018 const info = cg.arithmeticTypeInfo(result_ty);
3258 switch (info.class) {4019 switch (info.class) {
3259 .composite_integer => return cg.todo("shift ops for composite integers", .{}),4020 .composite_integer => {
4021 const shift_info = cg.arithmeticTypeInfo(shift.ty);
4022 const shift_amt_id = switch (shift_info.class) {
4023 .composite_integer => blk: {
4024 const shift_id = try shift.materialize(cg);
4025 const u32_ty_id = try cg.resolveType(.u32, .direct);
4026 const result_id = cg.module.allocId();
4027 try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{
4028 .id_result_type = u32_ty_id,
4029 .id_result = result_id,
4030 .composite = shift_id,
4031 .indexes = &.{@as(u32, 0)},
4032 });
4033 break :blk result_id;
4034 },
4035 else => blk: {
4036 const converted = try cg.buildConvert(.u32, shift);
4037 break :blk try converted.materialize(cg);
4038 },
4039 };
4040 const base_id = try base.materialize(cg);
4041 const scratch_top = cg.id_scratch.items.len;
4042 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
4043 const ci = try CompositeInt.init(cg, base_id, info);
4044 const ci_result = if (unsigned == .OpShiftLeftLogical)
4045 try ci.shl(shift_amt_id)
4046 else switch (info.signedness) {
4047 .unsigned => try ci.shr(shift_amt_id, false),
4048 .signed => try ci.shr(shift_amt_id, true),
4049 };
4050 const normalized = try ci_result.normalize();
4051 return try normalized.materialize(result_ty);
4052 },
3260 .integer, .strange_integer => {},4053 .integer, .strange_integer => {},
3261 .float, .bool => unreachable,4054 .float, .bool => unreachable,
3262 }4055 }
...@@ -3380,7 +4173,16 @@ fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporar...@@ -3380,7 +4173,16 @@ fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporar
3380 const zcu = cg.module.zcu;4173 const zcu = cg.module.zcu;
3381 const ty = value.ty;4174 const ty = value.ty;
3382 switch (info.class) {4175 switch (info.class) {
3383 .composite_integer, .integer, .bool, .float => return value,4176 .integer, .bool, .float => return value,
4177 .composite_integer => {
4178 if (info.bits == info.backing_bits) return value;
4179 const val_id = try value.materialize(cg);
4180 const scratch_top = cg.id_scratch.items.len;
4181 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
4182 const ci = try CompositeInt.init(cg, val_id, info);
4183 const normalized = try ci.normalize();
4184 return .init(ty, try normalized.materialize(ty));
4185 },
3384 .strange_integer => switch (info.signedness) {4186 .strange_integer => switch (info.signedness) {
3385 .unsigned => {4187 .unsigned => {
3386 const mask_value = @as(u64, std.math.maxInt(u64)) >> @as(u6, @intCast(64 - info.bits));4188 const mask_value = @as(u64, std.math.maxInt(u64)) >> @as(u6, @intCast(64 - info.bits));
...@@ -3484,7 +4286,22 @@ fn airArithOp(...@@ -3484,7 +4286,22 @@ fn airArithOp(
3484 const rhs = try cg.temporary(bin_op.rhs);4286 const rhs = try cg.temporary(bin_op.rhs);
3485 const info = cg.arithmeticTypeInfo(lhs.ty);4287 const info = cg.arithmeticTypeInfo(lhs.ty);
3486 const result = switch (info.class) {4288 const result = switch (info.class) {
3487 .composite_integer => return cg.todo("arith op for composite integers", .{}),4289 .composite_integer => res: {
4290 const lhs_id = try lhs.materialize(cg);
4291 const rhs_id = try rhs.materialize(cg);
4292 const scratch_top = cg.id_scratch.items.len;
4293 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
4294 const ci_lhs = try CompositeInt.init(cg, lhs_id, info);
4295 const ci_rhs = try CompositeInt.init(cg, rhs_id, info);
4296 const ci_result = switch (uop) {
4297 .OpIAdd => try ci_lhs.addSub(ci_rhs, true),
4298 .OpISub => try ci_lhs.addSub(ci_rhs, false),
4299 .OpIMul => CompositeInt.fromLimbs(cg, try ci_lhs.mul(ci_rhs, false), info),
4300 else => return cg.todo("arith op for composite integers", .{}),
4301 };
4302 const normalized = try ci_result.normalize();
4303 break :res Temporary.init(lhs.ty, try normalized.materialize(lhs.ty));
4304 },
3488 .integer, .strange_integer => res: {4305 .integer, .strange_integer => res: {
3489 const raw = switch (info.signedness) {4306 const raw = switch (info.signedness) {
3490 .signed => try cg.buildBinary(sop, lhs, rhs),4307 .signed => try cg.buildBinary(sop, lhs, rhs),
...@@ -3514,18 +4331,50 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {...@@ -3514,18 +4331,50 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
3514 switch (operand_info.class) {4331 switch (operand_info.class) {
3515 .float => return try cg.buildUnary(.f_abs, value),4332 .float => return try cg.buildUnary(.f_abs, value),
3516 .integer, .strange_integer => {4333 .integer, .strange_integer => {
3517 const abs_value = try cg.buildUnary(.i_abs, value);4334 var abs_value = try cg.buildUnary(.i_abs, value);
3518 switch (target.os.tag) {4335 switch (target.os.tag) {
3519 .vulkan, .opengl => {4336 .vulkan, .opengl => {
3520 if (value.ty.intInfo(zcu).signedness == .signed) {4337 if (value.ty.intInfo(zcu).signedness == .signed) {
3521 return cg.todo("perform bitcast after @abs", .{});4338 const abs_id = try abs_value.materialize(cg);
4339 const dst_ty_id = try cg.resolveType(result_ty, .direct);
4340 const cast_id = cg.module.allocId();
4341 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
4342 .id_result_type = dst_ty_id,
4343 .id_result = cast_id,
4344 .operand = abs_id,
4345 });
4346 abs_value = .init(result_ty, cast_id);
3522 }4347 }
3523 },4348 },
3524 else => {},4349 else => {},
3525 }4350 }
3526 return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));4351 return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));
3527 },4352 },
3528 .composite_integer => return cg.todo("@abs for composite integers", .{}),4353 .composite_integer => {
4354 const val_id = try value.materialize(cg);
4355 const scratch_top = cg.id_scratch.items.len;
4356 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
4357 const ci = try CompositeInt.init(cg, val_id, operand_info);
4358 const ci_z = try CompositeInt.zero(cg, operand_info);
4359 const is_neg = try ci.cmp(ci_z, .lt);
4360 const ci_neg = try ci_z.addSub(ci, false);
4361 const result_info = cg.arithmeticTypeInfo(result_ty);
4362 const u32_ty_id = try cg.resolveType(.u32, .direct);
4363 const result_limbs = try cg.id_scratch.addManyAsSlice(cg.module.gpa, ci.n_limbs);
4364 for (0..ci.n_limbs) |i| {
4365 result_limbs[i] = cg.module.allocId();
4366 try cg.body.emit(cg.module.gpa, .OpSelect, .{
4367 .id_result_type = u32_ty_id,
4368 .id_result = result_limbs[i],
4369 .condition = is_neg,
4370 .object_1 = ci_neg.limbs[i],
4371 .object_2 = ci.limbs[i],
4372 });
4373 }
4374 const ci_result = CompositeInt.fromLimbs(cg, result_limbs, result_info);
4375 const normalized = try ci_result.normalize();
4376 return .init(result_ty, try normalized.materialize(result_ty));
4377 },
3529 .bool => unreachable,4378 .bool => unreachable,
3530 }4379 }
3531}4380}
...@@ -3553,7 +4402,69 @@ fn airAddSubOverflow(...@@ -3553,7 +4402,69 @@ fn airAddSubOverflow(
35534402
3554 const info = cg.arithmeticTypeInfo(lhs.ty);4403 const info = cg.arithmeticTypeInfo(lhs.ty);
3555 switch (info.class) {4404 switch (info.class) {
3556 .composite_integer => return cg.todo("add/sub-with-overflow for composite integers", .{}),4405 .composite_integer => {
4406 const lhs_id = try lhs.materialize(cg);
4407 const rhs_id = try rhs.materialize(cg);
4408 const scratch_top = cg.id_scratch.items.len;
4409 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
4410 const ci_lhs = try CompositeInt.init(cg, lhs_id, info);
4411 const ci_rhs = try CompositeInt.init(cg, rhs_id, info);
4412 const ci_sum = if (add == .OpIAdd) try ci_lhs.addSub(ci_rhs, true) else try ci_lhs.addSub(ci_rhs, false);
4413 const ci_result = try ci_sum.normalize();
4414 const result_val_id = try ci_result.materialize(lhs.ty);
4415
4416 const ov_bool = switch (info.signedness) {
4417 .unsigned => blk: {
4418 const ci_res2 = try CompositeInt.init(cg, result_val_id, info);
4419 const ci_lhs2 = try CompositeInt.init(cg, lhs_id, info);
4420 break :blk if (add == .OpIAdd)
4421 try ci_res2.cmp(ci_lhs2, .lt)
4422 else
4423 try ci_res2.cmp(ci_lhs2, .gt);
4424 },
4425 .signed => blk: {
4426 const ci_res2 = try CompositeInt.init(cg, result_val_id, info);
4427 const ci_lhs2 = try CompositeInt.init(cg, lhs_id, info);
4428 const ci_rhs2 = try CompositeInt.init(cg, rhs_id, info);
4429 const ci_z = try CompositeInt.zero(cg, info);
4430 const lhs_neg = try ci_lhs2.cmp(ci_z, .lt);
4431 const rhs_neg = try ci_rhs2.cmp(ci_z, .lt);
4432 const res_neg = try ci_res2.cmp(ci_z, .lt);
4433
4434 const bool_ty_id = try cg.resolveType(.bool, .direct);
4435 const signs_match = cg.module.allocId();
4436 try cg.body.emitRaw(cg.module.gpa, .OpLogicalEqual, 4);
4437 cg.body.writeOperand(Id, bool_ty_id);
4438 cg.body.writeOperand(Id, signs_match);
4439 cg.body.writeOperand(Id, lhs_neg);
4440 cg.body.writeOperand(Id, rhs_neg);
4441 const res_sign_diff = cg.module.allocId();
4442 try cg.body.emitRaw(cg.module.gpa, .OpLogicalNotEqual, 4);
4443 cg.body.writeOperand(Id, bool_ty_id);
4444 cg.body.writeOperand(Id, res_sign_diff);
4445 cg.body.writeOperand(Id, lhs_neg);
4446 cg.body.writeOperand(Id, res_neg);
4447 const ov_cond = if (add == .OpIAdd) signs_match else blk2: {
4448 const not_match = cg.module.allocId();
4449 try cg.body.emitRaw(cg.module.gpa, .OpLogicalNot, 3);
4450 cg.body.writeOperand(Id, bool_ty_id);
4451 cg.body.writeOperand(Id, not_match);
4452 cg.body.writeOperand(Id, signs_match);
4453 break :blk2 not_match;
4454 };
4455 const ov_result = cg.module.allocId();
4456 try cg.body.emitRaw(cg.module.gpa, .OpLogicalAnd, 4);
4457 cg.body.writeOperand(Id, bool_ty_id);
4458 cg.body.writeOperand(Id, ov_result);
4459 cg.body.writeOperand(Id, ov_cond);
4460 cg.body.writeOperand(Id, res_sign_diff);
4461 break :blk ov_result;
4462 },
4463 };
4464 const ov = try cg.intFromBool(.init(.bool, ov_bool), .u1);
4465 const result_ty_id = try cg.resolveType(result_ty, .direct);
4466 return try cg.constructComposite(result_ty_id, &.{ result_val_id, try ov.materialize(cg) });
4467 },
3557 .strange_integer, .integer => {},4468 .strange_integer, .integer => {},
3558 .float, .bool => unreachable,4469 .float, .bool => unreachable,
3559 }4470 }
...@@ -3595,6 +4506,7 @@ fn airAddSubOverflow(...@@ -3595,6 +4506,7 @@ fn airAddSubOverflow(
35954506
3596fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4507fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3597 const pt = cg.pt;4508 const pt = cg.pt;
4509 const gpa = cg.module.gpa;
3598 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4510 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3599 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;4511 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
3600 const lhs = try cg.temporary(extra.lhs);4512 const lhs = try cg.temporary(extra.lhs);
...@@ -3603,7 +4515,158 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -3603,7 +4515,158 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
36034515
3604 const info = cg.arithmeticTypeInfo(lhs.ty);4516 const info = cg.arithmeticTypeInfo(lhs.ty);
3605 switch (info.class) {4517 switch (info.class) {
3606 .composite_integer => return cg.todo("mul-with-overflow for composite integers", .{}),4518 .composite_integer => {
4519 const lhs_id = try lhs.materialize(cg);
4520 const rhs_id = try rhs.materialize(cg);
4521 const scratch_top = cg.id_scratch.items.len;
4522 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
4523 const ci_lhs = try CompositeInt.init(cg, lhs_id, info);
4524 const ci_rhs = try CompositeInt.init(cg, rhs_id, info);
4525
4526 const low_limbs = try ci_lhs.mul(ci_rhs, false);
4527 const ci_result = try CompositeInt.fromLimbs(cg, low_limbs, info).normalize();
4528 const result_val_id = try ci_result.materialize(lhs.ty);
4529
4530 const ci_lhs2 = try CompositeInt.init(cg, lhs_id, info);
4531 const ci_rhs2 = try CompositeInt.init(cg, rhs_id, info);
4532 const wide_limbs = try ci_lhs2.mul(ci_rhs2, true);
4533 const high_limbs = wide_limbs[ci_lhs2.n_limbs..];
4534
4535 const bool_ty_id = try cg.resolveType(.bool, .direct);
4536 const u32_ty_id = try cg.resolveType(.u32, .direct);
4537 const n: usize = info.backing_bits / Module.big_int_bits;
4538
4539 const ov_bool = switch (info.signedness) {
4540 .unsigned => blk: {
4541 const zero_id = try cg.constInt(.u32, @as(u32, 0));
4542 var any_nonzero = cg.module.allocId();
4543 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4544 cg.body.writeOperand(Id, bool_ty_id);
4545 cg.body.writeOperand(Id, any_nonzero);
4546 cg.body.writeOperand(Id, high_limbs[0]);
4547 cg.body.writeOperand(Id, zero_id);
4548
4549 for (1..n) |i| {
4550 const limb_nz = cg.module.allocId();
4551 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4552 cg.body.writeOperand(Id, bool_ty_id);
4553 cg.body.writeOperand(Id, limb_nz);
4554 cg.body.writeOperand(Id, high_limbs[i]);
4555 cg.body.writeOperand(Id, zero_id);
4556
4557 const combined = cg.module.allocId();
4558 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
4559 cg.body.writeOperand(Id, bool_ty_id);
4560 cg.body.writeOperand(Id, combined);
4561 cg.body.writeOperand(Id, any_nonzero);
4562 cg.body.writeOperand(Id, limb_nz);
4563 any_nonzero = combined;
4564 }
4565
4566 break :blk any_nonzero;
4567 },
4568 .signed => blk: {
4569 const ci_res = try CompositeInt.init(cg, result_val_id, info);
4570 const top_limb = ci_res.limbs[n - 1];
4571 const i32_ty_id = try cg.resolveType(.i32, .direct);
4572
4573 const top_bits: u16 = if (info.bits % Module.big_int_bits == 0)
4574 Module.big_int_bits
4575 else
4576 info.bits % Module.big_int_bits;
4577
4578 const shift_amt: u32 = top_bits - 1;
4579 const shift_id = try cg.constInt(.u32, shift_amt);
4580
4581 const as_signed = cg.module.allocId();
4582 try cg.body.emit(gpa, .OpBitcast, .{
4583 .id_result_type = i32_ty_id,
4584 .id_result = as_signed,
4585 .operand = top_limb,
4586 });
4587 const sign_ext = cg.module.allocId();
4588 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
4589 cg.body.writeOperand(Id, i32_ty_id);
4590 cg.body.writeOperand(Id, sign_ext);
4591 cg.body.writeOperand(Id, as_signed);
4592 cg.body.writeOperand(Id, shift_id);
4593 const expected = cg.module.allocId();
4594 try cg.body.emit(gpa, .OpBitcast, .{
4595 .id_result_type = u32_ty_id,
4596 .id_result = expected,
4597 .operand = sign_ext,
4598 });
4599
4600 var any_mismatch = cg.module.allocId();
4601 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4602 cg.body.writeOperand(Id, bool_ty_id);
4603 cg.body.writeOperand(Id, any_mismatch);
4604 cg.body.writeOperand(Id, high_limbs[0]);
4605 cg.body.writeOperand(Id, expected);
4606
4607 for (1..n) |i| {
4608 const limb_ne = cg.module.allocId();
4609 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4610 cg.body.writeOperand(Id, bool_ty_id);
4611 cg.body.writeOperand(Id, limb_ne);
4612 cg.body.writeOperand(Id, high_limbs[i]);
4613 cg.body.writeOperand(Id, expected);
4614
4615 const combined = cg.module.allocId();
4616 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
4617 cg.body.writeOperand(Id, bool_ty_id);
4618 cg.body.writeOperand(Id, combined);
4619 cg.body.writeOperand(Id, any_mismatch);
4620 cg.body.writeOperand(Id, limb_ne);
4621 any_mismatch = combined;
4622 }
4623
4624 if (info.bits != info.backing_bits) {
4625 const top_bits_s: u16 = info.bits % Module.big_int_bits;
4626 const s_shift_id = try cg.constInt(.u32, top_bits_s - 1);
4627
4628 const top_as_signed = cg.module.allocId();
4629 try cg.body.emit(gpa, .OpBitcast, .{
4630 .id_result_type = i32_ty_id,
4631 .id_result = top_as_signed,
4632 .operand = top_limb,
4633 });
4634 const top_sign_ext = cg.module.allocId();
4635 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
4636 cg.body.writeOperand(Id, i32_ty_id);
4637 cg.body.writeOperand(Id, top_sign_ext);
4638 cg.body.writeOperand(Id, top_as_signed);
4639 cg.body.writeOperand(Id, s_shift_id);
4640 const top_expected = cg.module.allocId();
4641 try cg.body.emit(gpa, .OpBitcast, .{
4642 .id_result_type = u32_ty_id,
4643 .id_result = top_expected,
4644 .operand = top_sign_ext,
4645 });
4646 const top_mismatch = cg.module.allocId();
4647 try cg.body.emitRaw(gpa, .OpINotEqual, 4);
4648 cg.body.writeOperand(Id, bool_ty_id);
4649 cg.body.writeOperand(Id, top_mismatch);
4650 cg.body.writeOperand(Id, top_limb);
4651 cg.body.writeOperand(Id, top_expected);
4652
4653 const combined = cg.module.allocId();
4654 try cg.body.emitRaw(gpa, .OpLogicalOr, 4);
4655 cg.body.writeOperand(Id, bool_ty_id);
4656 cg.body.writeOperand(Id, combined);
4657 cg.body.writeOperand(Id, any_mismatch);
4658 cg.body.writeOperand(Id, top_mismatch);
4659 any_mismatch = combined;
4660 }
4661
4662 break :blk any_mismatch;
4663 },
4664 };
4665
4666 const ov = try cg.intFromBool(.init(.bool, ov_bool), .u1);
4667 const result_ty_id = try cg.resolveType(result_ty, .direct);
4668 return try cg.constructComposite(result_ty_id, &.{ result_val_id, try ov.materialize(cg) });
4669 },
3607 .strange_integer, .integer => {},4670 .strange_integer, .integer => {},
3608 .float, .bool => unreachable,4671 .float, .bool => unreachable,
3609 }4672 }
...@@ -3622,7 +4685,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -3622,7 +4685,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3622 1...16 => 32,4685 1...16 => 32,
3623 17...32 => if (largest_int_bits > 32) 64 else null, // Upcast if we can.4686 17...32 => if (largest_int_bits > 32) 64 else null, // Upcast if we can.
3624 33...64 => null, // Always use wide multiplication.4687 33...64 => null, // Always use wide multiplication.
3625 else => unreachable, // TODO: Composite integers4688 else => unreachable,
3626 };4689 };
36274690
3628 const result, const overflowed = switch (info.signedness) {4691 const result, const overflowed = switch (info.signedness) {
...@@ -4245,7 +5308,16 @@ fn cmp(...@@ -4245,7 +5308,16 @@ fn cmp(
42455308
4246 const info = cg.arithmeticTypeInfo(scalar_ty);5309 const info = cg.arithmeticTypeInfo(scalar_ty);
4247 const pred: Opcode = switch (info.class) {5310 const pred: Opcode = switch (info.class) {
4248 .composite_integer => return cg.todo("comparison for composite integers", .{}),5311 .composite_integer => {
5312 const lhs_id = try lhs.materialize(cg);
5313 const rhs_id = try rhs.materialize(cg);
5314 const scratch_top = cg.id_scratch.items.len;
5315 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
5316 const ci_lhs = try CompositeInt.init(cg, lhs_id, info);
5317 const ci_rhs = try CompositeInt.init(cg, rhs_id, info);
5318 const result_id = try ci_lhs.cmp(ci_rhs, op);
5319 return .init(.bool, result_id);
5320 },
4249 .float => switch (op) {5321 .float => switch (op) {
4250 .eq => .OpFOrdEqual,5322 .eq => .OpFOrdEqual,
4251 .neq => .OpFUnordNotEqual,5323 .neq => .OpFUnordNotEqual,
...@@ -4408,6 +5480,192 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4408,6 +5480,192 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4408 const src_info = cg.arithmeticTypeInfo(src.ty);5480 const src_info = cg.arithmeticTypeInfo(src.ty);
4409 const dst_info = cg.arithmeticTypeInfo(dst_ty);5481 const dst_info = cg.arithmeticTypeInfo(dst_ty);
44105482
5483 const src_composite = src_info.class == .composite_integer;
5484 const dst_composite = dst_info.class == .composite_integer;
5485
5486 if (src_composite or dst_composite) {
5487 const gpa = cg.module.gpa;
5488 const scratch_top = cg.id_scratch.items.len;
5489 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
5490
5491 if (src_composite and dst_composite) {
5492 const src_id = try src.materialize(cg);
5493 const src_n: u16 = src_info.backing_bits / Module.big_int_bits;
5494 const dst_n: u16 = dst_info.backing_bits / Module.big_int_bits;
5495 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
5496 const min_n = @min(src_n, dst_n);
5497 const u32_ty_id = try cg.resolveType(.u32, .direct);
5498 for (0..min_n) |i| {
5499 result_limbs[i] = cg.module.allocId();
5500 try cg.body.emit(gpa, .OpCompositeExtract, .{
5501 .id_result_type = u32_ty_id,
5502 .id_result = result_limbs[i],
5503 .composite = src_id,
5504 .indexes = &.{@as(u32, @intCast(i))},
5505 });
5506 }
5507 if (dst_n > src_n) {
5508 const fill = if (src_info.signedness == .signed) blk: {
5509 const i32_ty_id = try cg.resolveType(.i32, .direct);
5510 const msb = result_limbs[src_n - 1];
5511 const msb_signed = cg.module.allocId();
5512 try cg.body.emit(gpa, .OpBitcast, .{
5513 .id_result_type = i32_ty_id,
5514 .id_result = msb_signed,
5515 .operand = msb,
5516 });
5517 const shift31 = try cg.constInt(.i32, @as(i32, 31));
5518 const sign_ext = cg.module.allocId();
5519 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
5520 cg.body.writeOperand(Id, i32_ty_id);
5521 cg.body.writeOperand(Id, sign_ext);
5522 cg.body.writeOperand(Id, msb_signed);
5523 cg.body.writeOperand(Id, shift31);
5524 const back = cg.module.allocId();
5525 try cg.body.emit(gpa, .OpBitcast, .{
5526 .id_result_type = u32_ty_id,
5527 .id_result = back,
5528 .operand = sign_ext,
5529 });
5530 break :blk back;
5531 } else try cg.constInt(.u32, @as(u32, 0));
5532 for (min_n..dst_n) |i| {
5533 result_limbs[i] = fill;
5534 }
5535 }
5536 const ci = CompositeInt.fromLimbs(cg, result_limbs, dst_info);
5537 const normalized = try ci.normalize();
5538 return try normalized.materialize(dst_ty);
5539 } else if (src_composite and !dst_composite) {
5540 const src_id = try src.materialize(cg);
5541 const u32_ty_id = try cg.resolveType(.u32, .direct);
5542 if (dst_info.backing_bits <= 32) {
5543 const limb0 = cg.module.allocId();
5544 try cg.body.emit(gpa, .OpCompositeExtract, .{
5545 .id_result_type = u32_ty_id,
5546 .id_result = limb0,
5547 .composite = src_id,
5548 .indexes = &.{@as(u32, 0)},
5549 });
5550 const tmp: Temporary = .init(.u32, limb0);
5551 const converted = try cg.buildConvert(dst_ty, tmp);
5552 const result = if (dst_info.bits < src_info.bits)
5553 try cg.normalize(converted, dst_info)
5554 else
5555 converted;
5556 return try result.materialize(cg);
5557 } else {
5558 const limb0 = cg.module.allocId();
5559 try cg.body.emit(gpa, .OpCompositeExtract, .{
5560 .id_result_type = u32_ty_id,
5561 .id_result = limb0,
5562 .composite = src_id,
5563 .indexes = &.{@as(u32, 0)},
5564 });
5565 const limb1 = cg.module.allocId();
5566 try cg.body.emit(gpa, .OpCompositeExtract, .{
5567 .id_result_type = u32_ty_id,
5568 .id_result = limb1,
5569 .composite = src_id,
5570 .indexes = &.{@as(u32, 1)},
5571 });
5572 const u64_ty_id = try cg.resolveType(.u64, .direct);
5573 const lo = cg.module.allocId();
5574 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5575 cg.body.writeOperand(Id, u64_ty_id);
5576 cg.body.writeOperand(Id, lo);
5577 cg.body.writeOperand(Id, limb0);
5578 const hi = cg.module.allocId();
5579 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5580 cg.body.writeOperand(Id, u64_ty_id);
5581 cg.body.writeOperand(Id, hi);
5582 cg.body.writeOperand(Id, limb1);
5583 const shift32 = try cg.constInt(.u64, @as(u64, 32));
5584 const hi_shifted = cg.module.allocId();
5585 try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4);
5586 cg.body.writeOperand(Id, u64_ty_id);
5587 cg.body.writeOperand(Id, hi_shifted);
5588 cg.body.writeOperand(Id, hi);
5589 cg.body.writeOperand(Id, shift32);
5590 const combined = cg.module.allocId();
5591 try cg.body.emitRaw(gpa, .OpBitwiseOr, 4);
5592 cg.body.writeOperand(Id, u64_ty_id);
5593 cg.body.writeOperand(Id, combined);
5594 cg.body.writeOperand(Id, lo);
5595 cg.body.writeOperand(Id, hi_shifted);
5596 const tmp: Temporary = .init(.u64, combined);
5597 const converted = try cg.buildConvert(dst_ty, tmp);
5598 const result = if (dst_info.bits < src_info.bits)
5599 try cg.normalize(converted, dst_info)
5600 else
5601 converted;
5602 return try result.materialize(cg);
5603 }
5604 } else {
5605 const dst_n: u16 = dst_info.backing_bits / Module.big_int_bits;
5606 const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n);
5607 const u32_ty_id = try cg.resolveType(.u32, .direct);
5608
5609 if (src_info.backing_bits <= 32) {
5610 const converted = try cg.buildConvert(.u32, src);
5611 result_limbs[0] = try converted.materialize(cg);
5612 } else {
5613 const src_as_u64 = try cg.buildConvert(.u64, src);
5614 const src_id = try src_as_u64.materialize(cg);
5615 result_limbs[0] = cg.module.allocId();
5616 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5617 cg.body.writeOperand(Id, u32_ty_id);
5618 cg.body.writeOperand(Id, result_limbs[0]);
5619 cg.body.writeOperand(Id, src_id);
5620 const u64_ty_id = try cg.resolveType(.u64, .direct);
5621 const shift32 = try cg.constInt(.u64, @as(u64, 32));
5622 const hi = cg.module.allocId();
5623 try cg.body.emitRaw(gpa, .OpShiftRightLogical, 4);
5624 cg.body.writeOperand(Id, u64_ty_id);
5625 cg.body.writeOperand(Id, hi);
5626 cg.body.writeOperand(Id, src_id);
5627 cg.body.writeOperand(Id, shift32);
5628 result_limbs[1] = cg.module.allocId();
5629 try cg.body.emitRaw(gpa, .OpUConvert, 3);
5630 cg.body.writeOperand(Id, u32_ty_id);
5631 cg.body.writeOperand(Id, result_limbs[1]);
5632 cg.body.writeOperand(Id, hi);
5633 }
5634 // Sign/zero-extend remaining limbs.
5635 const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2;
5636 const fill = if (src_info.signedness == .signed) blk: {
5637 const i32_ty_id = try cg.resolveType(.i32, .direct);
5638 const msb = result_limbs[fill_start - 1];
5639 const msb_signed = cg.module.allocId();
5640 try cg.body.emit(gpa, .OpBitcast, .{
5641 .id_result_type = i32_ty_id,
5642 .id_result = msb_signed,
5643 .operand = msb,
5644 });
5645 const shift31 = try cg.constInt(.i32, @as(i32, 31));
5646 const sign_ext = cg.module.allocId();
5647 try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4);
5648 cg.body.writeOperand(Id, i32_ty_id);
5649 cg.body.writeOperand(Id, sign_ext);
5650 cg.body.writeOperand(Id, msb_signed);
5651 cg.body.writeOperand(Id, shift31);
5652 const back = cg.module.allocId();
5653 try cg.body.emit(gpa, .OpBitcast, .{
5654 .id_result_type = u32_ty_id,
5655 .id_result = back,
5656 .operand = sign_ext,
5657 });
5658 break :blk back;
5659 } else try cg.constInt(.u32, @as(u32, 0));
5660 for (fill_start..dst_n) |i| {
5661 result_limbs[i] = fill;
5662 }
5663 const ci = CompositeInt.fromLimbs(cg, result_limbs, dst_info);
5664 const normalized = try ci.normalize();
5665 return try normalized.materialize(dst_ty);
5666 }
5667 }
5668
4411 if (src_info.backing_bits == dst_info.backing_bits) {5669 if (src_info.backing_bits == dst_info.backing_bits) {
4412 const result = if (dst_info.bits < src_info.bits)5670 const result = if (dst_info.bits < src_info.bits)
4413 try cg.normalize(src.pun(dst_ty), dst_info)5671 try cg.normalize(src.pun(dst_ty), dst_info)
...@@ -4513,7 +5771,15 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4513,7 +5771,15 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4513 const result = switch (info.class) {5771 const result = switch (info.class) {
4514 .bool => try cg.buildUnary(.l_not, operand),5772 .bool => try cg.buildUnary(.l_not, operand),
4515 .float => unreachable,5773 .float => unreachable,
4516 .composite_integer => return cg.todo("bitwise not for composite integers", .{}),5774 .composite_integer => blk: {
5775 const op_id = try operand.materialize(cg);
5776 const scratch_top = cg.id_scratch.items.len;
5777 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
5778 const ci = try CompositeInt.init(cg, op_id, info);
5779 const notted = try ci.bitwiseNot();
5780 const normalized = try notted.normalize();
5781 break :blk Temporary.init(result_ty, try normalized.materialize(result_ty));
5782 },
4517 .strange_integer, .integer => blk: {5783 .strange_integer, .integer => blk: {
4518 const complement = try cg.buildUnary(.bit_not, operand);5784 const complement = try cg.buildUnary(.bit_not, operand);
4519 break :blk try cg.normalize(complement, info);5785 break :blk try cg.normalize(complement, info);
...@@ -6198,9 +7464,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6198,9 +7464,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6198 const value: Value = .fromInterned(item.toInterned().?);7464 const value: Value = .fromInterned(item.toInterned().?);
6199 const int_val: u64 = switch (cond_ty.zigTypeTag(zcu)) {7465 const int_val: u64 = switch (cond_ty.zigTypeTag(zcu)) {
6200 .bool, .int => if (cond_ty.isSignedInt(zcu)) @bitCast(value.toSignedInt(zcu)) else value.toUnsignedInt(zcu),7466 .bool, .int => if (cond_ty.isSignedInt(zcu)) @bitCast(value.toSignedInt(zcu)) else value.toUnsignedInt(zcu),
6201 .@"enum" => blk: {7467 .@"enum" => value.intFromEnum(zcu).toUnsignedInt(zcu),
6202 break :blk value.intFromEnum(zcu).toUnsignedInt(zcu); // TODO: composite integer constants
6203 },
6204 .error_set => value.getErrorInt(zcu),7468 .error_set => value.getErrorInt(zcu),
6205 .pointer => value.toUnsignedInt(zcu),7469 .pointer => value.toUnsignedInt(zcu),
6206 else => unreachable,7470 else => unreachable,
...@@ -6502,7 +7766,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)...@@ -6502,7 +7766,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
6502fn builtin3D(7766fn builtin3D(
6503 cg: *CodeGen,7767 cg: *CodeGen,
6504 result_ty: Type,7768 result_ty: Type,
6505 builtin: spec.BuiltIn,7769 built_in: spec.BuiltIn,
6506 dimension: u32,7770 dimension: u32,
6507 out_of_range_value: anytype,7771 out_of_range_value: anytype,
6508) !Id {7772) !Id {
...@@ -6511,7 +7775,7 @@ fn builtin3D(...@@ -6511,7 +7775,7 @@ fn builtin3D(
6511 const u32_ty_id = try cg.module.intType(.unsigned, 32);7775 const u32_ty_id = try cg.module.intType(.unsigned, 32);
6512 const vec_ty_id = try cg.module.vectorType(3, u32_ty_id);7776 const vec_ty_id = try cg.module.vectorType(3, u32_ty_id);
6513 const ptr_ty_id = try cg.module.ptrType(vec_ty_id, .input);7777 const ptr_ty_id = try cg.module.ptrType(vec_ty_id, .input);
6514 const spv_decl_index = try cg.module.builtin(ptr_ty_id, builtin, .input);7778 const spv_decl_index = try cg.module.builtin(ptr_ty_id, built_in, .input);
6515 try cg.module.decl_deps.append(gpa, spv_decl_index);7779 try cg.module.decl_deps.append(gpa, spv_decl_index);
6516 const ptr_id = cg.module.declPtr(spv_decl_index).result_id;7780 const ptr_id = cg.module.declPtr(spv_decl_index).result_id;
6517 const vec_id = cg.module.allocId();7781 const vec_id = cg.module.allocId();
src/codegen/spirv/Module.zig-2
...@@ -658,8 +658,6 @@ pub fn intType(module: *Module, signedness: std.lang.Signedness, bits: u16) !Id...@@ -658,8 +658,6 @@ pub fn intType(module: *Module, signedness: std.lang.Signedness, bits: u16) !Id
658 };658 };
659 const backing_bits, const big_int = module.backingIntBits(bits);659 const backing_bits, const big_int = module.backingIntBits(bits);
660 if (big_int) {660 if (big_int) {
661 // TODO: support composite integers larger than 64 bit
662 assert(backing_bits <= 64);
663 const u32_ty = try module.intType(.unsigned, 32);661 const u32_ty = try module.intType(.unsigned, 32);
664 const len_id = try module.constant(u32_ty, .{ .uint32 = backing_bits / big_int_bits });662 const len_id = try module.constant(u32_ty, .{ .uint32 = backing_bits / big_int_bits });
665 return module.arrayType(len_id, u32_ty);663 return module.arrayType(len_id, u32_ty);
src/target.zig-1
...@@ -953,7 +953,6 @@ pub inline fn backendSupportsFeature(backend: std.lang.CompilerBackend, comptime...@@ -953,7 +953,6 @@ pub inline fn backendSupportsFeature(backend: std.lang.CompilerBackend, comptime
953 // threads because they would all just be locking the same mutex to953 // threads because they would all just be locking the same mutex to
954 // protect Builder.954 // protect Builder.
955 .stage2_llvm => false,955 .stage2_llvm => false,
956 .stage2_spirv => true,
957 // Please do not make any more exceptions. Backends must support956 // Please do not make any more exceptions. Backends must support
958 // being run in a separate thread from now on.957 // being run in a separate thread from now on.
959 else => true,958 else => true,
test/behavior/abs.zig-3
...@@ -7,7 +7,6 @@ test "@abs integers" {...@@ -7,7 +7,6 @@ test "@abs integers" {
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1110
12 try comptime testAbsIntegers();11 try comptime testAbsIntegers();
13 try testAbsIntegers();12 try testAbsIntegers();
...@@ -54,7 +53,6 @@ test "@abs signed C ABI integers" {...@@ -54,7 +53,6 @@ test "@abs signed C ABI integers" {
54 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO55 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5856
59 const S = struct {57 const S = struct {
60 fn doTheTest() !void {58 fn doTheTest() !void {
...@@ -146,7 +144,6 @@ test "@abs big int <= 128 bits" {...@@ -146,7 +144,6 @@ test "@abs big int <= 128 bits" {
146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO146 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
149 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
150 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO147 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
151148
152 try comptime testAbsSignedBigInt();149 try comptime testAbsSignedBigInt();
test/behavior/basic.zig-7
...@@ -24,7 +24,6 @@ fn testTruncate(x: u32) u8 {...@@ -24,7 +24,6 @@ fn testTruncate(x: u32) u8 {
24}24}
2525
26test "truncate to non-power-of-two integers" {26test "truncate to non-power-of-two integers" {
27 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO27 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2928
30 try testTrunc(u32, u1, 0b10101, 0b1);29 try testTrunc(u32, u1, 0b10101, 0b1);
...@@ -41,7 +40,6 @@ test "truncate to non-power-of-two integers" {...@@ -41,7 +40,6 @@ test "truncate to non-power-of-two integers" {
41test "truncate to non-power-of-two integers from 128-bit" {40test "truncate to non-power-of-two integers from 128-bit" {
42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO41 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4543
46 try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010101, 0x01);44 try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010101, 0x01);
47 try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010110, 0x00);45 try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010110, 0x00);
...@@ -299,7 +297,6 @@ const global_b: *const i32 = &global_a;...@@ -299,7 +297,6 @@ const global_b: *const i32 = &global_a;
299const global_c: *const f32 = @as(*const f32, @ptrCast(global_b));297const global_c: *const f32 = @as(*const f32, @ptrCast(global_b));
300test "compile time global reinterpret" {298test "compile time global reinterpret" {
301 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;299 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
302
303 const d = @as(*const i32, @ptrCast(global_c));300 const d = @as(*const i32, @ptrCast(global_c));
304 try expect(d.* == 1234);301 try expect(d.* == 1234);
305}302}
...@@ -1217,8 +1214,6 @@ fn testUnsignedCmp(comptime T: type) !void {...@@ -1217,8 +1214,6 @@ fn testUnsignedCmp(comptime T: type) !void {
1217}1214}
12181215
1219test "integer compare <= 64 bits" {1216test "integer compare <= 64 bits" {
1220 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1221
1222 inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| {1217 inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| {
1223 try testUnsignedCmp(T);1218 try testUnsignedCmp(T);
1224 try comptime testUnsignedCmp(T);1219 try comptime testUnsignedCmp(T);
...@@ -1231,7 +1226,6 @@ test "integer compare <= 64 bits" {...@@ -1231,7 +1226,6 @@ test "integer compare <= 64 bits" {
12311226
1232test "integer compare <= 128 bits" {1227test "integer compare <= 128 bits" {
1233 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1228 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1234 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12351229
1236 inline for (.{ u65, u96, u127, u128 }) |T| {1230 inline for (.{ u65, u96, u127, u128 }) |T| {
1237 try testUnsignedCmp(T);1231 try testUnsignedCmp(T);
...@@ -1245,7 +1239,6 @@ test "integer compare <= 128 bits" {...@@ -1245,7 +1239,6 @@ test "integer compare <= 128 bits" {
12451239
1246test "integer compare > 128 bits" {1240test "integer compare > 128 bits" {
1247 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1241 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1248 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12491242
1250 inline for (.{ u129, u255, u512, u800 }) |T| {1243 inline for (.{ u129, u255, u512, u800 }) |T| {
1251 try testUnsignedCmp(T);1244 try testUnsignedCmp(T);
test/behavior/enum.zig-2
...@@ -26,7 +26,6 @@ const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };...@@ -26,7 +26,6 @@ const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };
2626
27test "int to enum" {27test "int to enum" {
28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3029
31 try testEnumFromIntEval(3);30 try testEnumFromIntEval(3);
32}31}
...@@ -974,7 +973,6 @@ test "@tagName" {...@@ -974,7 +973,6 @@ test "@tagName" {
974 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;973 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
975 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;974 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
976 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO975 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
977 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
978 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;976 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
979977
980 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));978 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
test/behavior/eval.zig-3
...@@ -456,7 +456,6 @@ test "binary math operator in partially inlined function" {...@@ -456,7 +456,6 @@ test "binary math operator in partially inlined function" {
456test "comptime shl" {456test "comptime shl" {
457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
459 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
460459
461 const a: u128 = 3;460 const a: u128 = 3;
462 const b: u7 = 63;461 const b: u7 = 63;
...@@ -904,7 +903,6 @@ test "const local with comptime init through array init" {...@@ -904,7 +903,6 @@ test "const local with comptime init through array init" {
904}903}
905904
906test "closure capture type of runtime-known parameter" {905test "closure capture type of runtime-known parameter" {
907 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
908 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO906 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
909907
910 const S = struct {908 const S = struct {
...@@ -1185,7 +1183,6 @@ test "lazy sizeof is resolved in division" {...@@ -1185,7 +1183,6 @@ test "lazy sizeof is resolved in division" {
1185}1183}
11861184
1187test "lazy sizeof union tag size in compare" {1185test "lazy sizeof union tag size in compare" {
1188 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11891186
1190 const A = union(enum) {1187 const A = union(enum) {
1191 a: void,1188 a: void,
test/behavior/floatop.zig-1
...@@ -144,7 +144,6 @@ test "cmp f64" {...@@ -144,7 +144,6 @@ test "cmp f64" {
144test "cmp f128" {144test "cmp f128" {
145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;146 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
147 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
148 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;147 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
149148
150 try testCmp(f128);149 try testCmp(f128);
test/behavior/int128.zig-3
...@@ -7,7 +7,6 @@ const builtin = @import("builtin");...@@ -7,7 +7,6 @@ const builtin = @import("builtin");
7test "uint128" {7test "uint128" {
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1211
13 var buff: u128 = maxInt(u128);12 var buff: u128 = maxInt(u128);
...@@ -45,7 +44,6 @@ test "undefined 128 bit int" {...@@ -45,7 +44,6 @@ test "undefined 128 bit int" {
45test "int128" {44test "int128" {
46 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO45 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO46 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
49 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;47 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5048
51 var buff: i128 = -1;49 var buff: i128 = -1;
...@@ -90,7 +88,6 @@ test "truncate int128" {...@@ -90,7 +88,6 @@ test "truncate int128" {
90test "shift int128" {88test "shift int128" {
91 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO90 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
93 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
94 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;91 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9592
96 const types = .{ u128, i128 };93 const types = .{ u128, i128 };
test/behavior/math.zig-18
...@@ -383,7 +383,6 @@ fn not(comptime T: type, a: T) T {...@@ -383,7 +383,6 @@ fn not(comptime T: type, a: T) T {
383383
384test "binary not" {384test "binary not" {
385 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;385 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
386 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
387386
388 try expect(not(u0, 0) == 0);387 try expect(not(u0, 0) == 0);
389 try expect(not(u1, 0) == 1);388 try expect(not(u1, 0) == 1);
...@@ -424,7 +423,6 @@ test "binary not" {...@@ -424,7 +423,6 @@ test "binary not" {
424test "binary not big int <= 128 bits" {423test "binary not big int <= 128 bits" {
425 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
426 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO425 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
427 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
428 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;426 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
429427
430 try expect(not(u65, 1) == 0x1_FFFFFFFF_FFFFFFFE);428 try expect(not(u65, 1) == 0x1_FFFFFFFF_FFFFFFFE);
...@@ -659,7 +657,6 @@ fn testSignedWrappingEval(x: i32) !void {...@@ -659,7 +657,6 @@ fn testSignedWrappingEval(x: i32) !void {
659}657}
660658
661test "signed negation wrapping" {659test "signed negation wrapping" {
662 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
663660
664 try testSignedNegationWrappingEval(minInt(i16));661 try testSignedNegationWrappingEval(minInt(i16));
665 try comptime testSignedNegationWrappingEval(minInt(i16));662 try comptime testSignedNegationWrappingEval(minInt(i16));
...@@ -763,7 +760,6 @@ fn should_not_be_zero(x: f128) !void {...@@ -763,7 +760,6 @@ fn should_not_be_zero(x: f128) !void {
763test "umax wrapped squaring" {760test "umax wrapped squaring" {
764 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;761 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
765 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;762 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
766 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
767763
768 {764 {
769 var x: u4 = maxInt(u4);765 var x: u4 = maxInt(u4);
...@@ -820,7 +816,6 @@ test "umax wrapped squaring" {...@@ -820,7 +816,6 @@ test "umax wrapped squaring" {
820test "128-bit multiplication" {816test "128-bit multiplication" {
821 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO817 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
822 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO818 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
823 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
824 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;819 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
825 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;820 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
826821
...@@ -873,7 +868,6 @@ test "@addWithOverflow <= 128 bits" {...@@ -873,7 +868,6 @@ test "@addWithOverflow <= 128 bits" {
873 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO868 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
874 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO869 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
875 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;870 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
876 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
877871
878 try testAddWithOverflow(u65, 4, 105, 109, 0);872 try testAddWithOverflow(u65, 4, 105, 109, 0);
879 try testAddWithOverflow(u65, 1000, 100, 1100, 0);873 try testAddWithOverflow(u65, 1000, 100, 1100, 0);
...@@ -1000,7 +994,6 @@ test "extensive @mulWithOverflow" {...@@ -1000,7 +994,6 @@ test "extensive @mulWithOverflow" {
1000 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;994 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1001 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO995 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1002 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;996 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1003 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1004997
1005 try testMulWithOverflow(u5, 3, 10, 30, 0);998 try testMulWithOverflow(u5, 3, 10, 30, 0);
1006 try testMulWithOverflow(u5, 3, 11, 1, 1);999 try testMulWithOverflow(u5, 3, 11, 1, 1);
...@@ -1207,7 +1200,6 @@ test "@subWithOverflow <= 128 bits" {...@@ -1207,7 +1200,6 @@ test "@subWithOverflow <= 128 bits" {
1207 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1200 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1208 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1201 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1209 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1202 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1210 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
12111203
1212 try testSubWithOverflow(u65, 4, 105, maxInt(u65) - 100, 1);1204 try testSubWithOverflow(u65, 4, 105, maxInt(u65) - 100, 1);
1213 try testSubWithOverflow(u65, 1000, 100, 900, 0);1205 try testSubWithOverflow(u65, 1000, 100, 900, 0);
...@@ -1371,7 +1363,6 @@ fn testAnd(comptime T: type, a: T, b: T, expected: T) !void {...@@ -1371,7 +1363,6 @@ fn testAnd(comptime T: type, a: T, b: T, expected: T) !void {
1371test "and > 128 bits" {1363test "and > 128 bits" {
1372 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1373 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;1365 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1374 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13751366
1376 try testAnd(u140, (1 << 139) | (1 << 70) | 0xaa, (1 << 139) | (1 << 69) | 0xcc, (1 << 139) | 0x88);1367 try testAnd(u140, (1 << 139) | (1 << 70) | 0xaa, (1 << 139) | (1 << 69) | 0xcc, (1 << 139) | 0x88);
1377 try testAnd(u140, maxInt(u140), 1 << 100, 1 << 100);1368 try testAnd(u140, maxInt(u140), 1 << 100, 1 << 100);
...@@ -1431,7 +1422,6 @@ fn testXor(comptime T: type, a: T, b: T, expected: T) !void {...@@ -1431,7 +1422,6 @@ fn testXor(comptime T: type, a: T, b: T, expected: T) !void {
1431test "xor > 128 bits" {1422test "xor > 128 bits" {
1432 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1433 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;1424 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1434 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14351425
1436 try testXor(u140, 0, maxInt(u140), maxInt(u140));1426 try testXor(u140, 0, maxInt(u140), maxInt(u140));
1437 try testXor(u140, 1 << 139, 1 << 139, 0);1427 try testXor(u140, 1 << 139, 1 << 139, 0);
...@@ -1461,7 +1451,6 @@ fn testNot(comptime T: type, a: T, expected: T) !void {...@@ -1461,7 +1451,6 @@ fn testNot(comptime T: type, a: T, expected: T) !void {
1461test "not > 128 bits" {1451test "not > 128 bits" {
1462 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1452 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1463 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;1453 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1464 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14651454
1466 try testNot(u140, 0, maxInt(u140));1455 try testNot(u140, 0, maxInt(u140));
1467 try testNot(u140, maxInt(u140), 0);1456 try testNot(u140, maxInt(u140), 0);
...@@ -1491,7 +1480,6 @@ fn testShl(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void {...@@ -1491,7 +1480,6 @@ fn testShl(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void {
1491test "shl > 128 bits" {1480test "shl > 128 bits" {
1492 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1481 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1493 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;1482 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1494 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14951483
1496 try testShl(u140, 1 << 5, 10, 1 << 15);1484 try testShl(u140, 1 << 5, 10, 1 << 15);
1497 try testShl(u140, 3, 138, (1 << 139) | (1 << 138));1485 try testShl(u140, 3, 138, (1 << 139) | (1 << 138));
...@@ -1521,7 +1509,6 @@ fn testShr(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void {...@@ -1521,7 +1509,6 @@ fn testShr(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void {
1521test "shr > 128 bits" {1509test "shr > 128 bits" {
1522 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1510 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1523 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;1511 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1524 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15251512
1526 try testShr(u140, 1 << 139, 39, 1 << 100);1513 try testShr(u140, 1 << 139, 39, 1 << 100);
1527 try testShr(u140, (1 << 70) | 8, 3, (1 << 67) | 1);1514 try testShr(u140, (1 << 70) | 8, 3, (1 << 67) | 1);
...@@ -2534,7 +2521,6 @@ test "partially-runtime integer vector division would be illegal if vector eleme...@@ -2534,7 +2521,6 @@ test "partially-runtime integer vector division would be illegal if vector eleme
2534 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2521 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2535 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2522 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2536 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2523 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2537 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2538 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;2524 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;
25392525
2540 var lhs: @Vector(2, i8) = .{ -128, 5 };2526 var lhs: @Vector(2, i8) = .{ -128, 5 };
...@@ -2562,7 +2548,6 @@ test "float vector division of comptime zero by runtime nan is nan" {...@@ -2562,7 +2548,6 @@ test "float vector division of comptime zero by runtime nan is nan" {
2562 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2548 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2563 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2549 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2564 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2550 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2565 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
25662551
2567 const ct_zero: @Vector(1, f32) = .{0};2552 const ct_zero: @Vector(1, f32) = .{0};
2568 var rt_nan: @Vector(1, f32) = .{math.nan(f32)};2553 var rt_nan: @Vector(1, f32) = .{math.nan(f32)};
...@@ -2579,7 +2564,6 @@ test "float vector multiplication of comptime zero by runtime nan is nan" {...@@ -2579,7 +2564,6 @@ test "float vector multiplication of comptime zero by runtime nan is nan" {
2579 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2564 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2580 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2565 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2581 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2566 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2582 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
25832567
2584 const ct_zero: @Vector(1, f32) = .{0};2568 const ct_zero: @Vector(1, f32) = .{0};
2585 var rt_nan: @Vector(1, f32) = .{math.nan(f32)};2569 var rt_nan: @Vector(1, f32) = .{math.nan(f32)};
...@@ -2594,7 +2578,6 @@ test "comptime float vector division of zero by nan is nan" {...@@ -2594,7 +2578,6 @@ test "comptime float vector division of zero by nan is nan" {
2594 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2578 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2595 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2579 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2596 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2580 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2597 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
25982581
2599 const ct_zero: @Vector(1, f32) = .{0};2582 const ct_zero: @Vector(1, f32) = .{0};
2600 const ct_nan: @Vector(1, f32) = .{math.nan(f32)};2583 const ct_nan: @Vector(1, f32) = .{math.nan(f32)};
...@@ -2608,7 +2591,6 @@ test "comptime float vector multiplication of zero by nan is nan" {...@@ -2608,7 +2591,6 @@ test "comptime float vector multiplication of zero by nan is nan" {
2608 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2591 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2609 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2592 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2610 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2593 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2611 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
26122594
2613 const ct_zero: @Vector(1, f32) = .{0};2595 const ct_zero: @Vector(1, f32) = .{0};
2614 const ct_nan: @Vector(1, f32) = .{math.nan(f32)};2596 const ct_nan: @Vector(1, f32) = .{math.nan(f32)};
test/behavior/muladd.zig-2
...@@ -6,7 +6,6 @@ test "@mulAdd" {...@@ -6,7 +6,6 @@ test "@mulAdd" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
109
11 try comptime testMulAdd();10 try comptime testMulAdd();
12 try testMulAdd();11 try testMulAdd();
...@@ -33,7 +32,6 @@ test "@mulAdd f16" {...@@ -33,7 +32,6 @@ test "@mulAdd f16" {
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO33 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;34 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
36 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3735
38 try comptime testMulAdd16();36 try comptime testMulAdd16();
39 try testMulAdd16();37 try testMulAdd16();
test/behavior/while.zig-3
...@@ -38,7 +38,6 @@ fn staticWhileLoop2() i32 {...@@ -38,7 +38,6 @@ fn staticWhileLoop2() i32 {
38}38}
3939
40test "while with continue expression" {40test "while with continue expression" {
41 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4241
43 var sum: i32 = 0;42 var sum: i32 = 0;
44 {43 {
...@@ -158,7 +157,6 @@ test "while with optional as condition with else" {...@@ -158,7 +157,6 @@ test "while with optional as condition with else" {
158 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
160 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;159 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
161 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
162160
163 numbers_left = 10;161 numbers_left = 10;
164 var sum: i32 = 0;162 var sum: i32 = 0;
...@@ -176,7 +174,6 @@ test "while with optional as condition with else" {...@@ -176,7 +174,6 @@ test "while with optional as condition with else" {
176test "while with error union condition" {174test "while with error union condition" {
177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
178 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;176 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
179 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
180177
181 numbers_left = 10;178 numbers_left = 10;
182 var sum: i32 = 0;179 var sum: i32 = 0;
test/behavior/widening.zig-1
...@@ -6,7 +6,6 @@ const builtin = @import("builtin");...@@ -6,7 +6,6 @@ const builtin = @import("builtin");
6test "integer widening" {6test "integer widening" {
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
12 var a: u8 = 250;11 var a: u8 = 250;
test/behavior/wrapping_arithmetic.zig+9-10
...@@ -3,7 +3,6 @@ const builtin = @import("builtin");...@@ -3,7 +3,6 @@ const builtin = @import("builtin");
3const minInt = std.math.minInt;3const minInt = std.math.minInt;
4const maxInt = std.math.maxInt;4const maxInt = std.math.maxInt;
5const expect = std.testing.expect;5const expect = std.testing.expect;
6const skip128 = builtin.zig_backend == .stage2_spirv;
76
8test "wrapping add" {7test "wrapping add" {
9 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -14,14 +13,14 @@ test "wrapping add" {...@@ -14,14 +13,14 @@ test "wrapping add" {
14 try testWrapAdd(i8, -128, -128, 0);13 try testWrapAdd(i8, -128, -128, 0);
15 try testWrapAdd(i2, 1, 1, -2);14 try testWrapAdd(i2, 1, 1, -2);
16 try testWrapAdd(i64, maxInt(i64), 1, minInt(i64));15 try testWrapAdd(i64, maxInt(i64), 1, minInt(i64));
17 if (!skip128) try testWrapAdd(i128, maxInt(i128), -maxInt(i128), 0);16 try testWrapAdd(i128, maxInt(i128), -maxInt(i128), 0);
18 if (!skip128) try testWrapAdd(i128, minInt(i128), maxInt(i128), -1);17 try testWrapAdd(i128, minInt(i128), maxInt(i128), -1);
19 try testWrapAdd(i8, 127, 127, -2);18 try testWrapAdd(i8, 127, 127, -2);
20 try testWrapAdd(u8, 3, 10, 13);19 try testWrapAdd(u8, 3, 10, 13);
21 try testWrapAdd(u8, 255, 255, 254);20 try testWrapAdd(u8, 255, 255, 254);
22 try testWrapAdd(u2, 3, 2, 1);21 try testWrapAdd(u2, 3, 2, 1);
23 try testWrapAdd(u3, 7, 1, 0);22 try testWrapAdd(u3, 7, 1, 0);
24 if (!skip128) try testWrapAdd(u128, maxInt(u128), 1, minInt(u128));23 try testWrapAdd(u128, maxInt(u128), 1, minInt(u128));
25 }24 }
2625
27 fn testWrapAdd(comptime T: type, lhs: T, rhs: T, expected: T) !void {26 fn testWrapAdd(comptime T: type, lhs: T, rhs: T, expected: T) !void {
...@@ -51,12 +50,12 @@ test "wrapping subtraction" {...@@ -51,12 +50,12 @@ test "wrapping subtraction" {
51 try testWrapSub(i8, -128, -128, 0);50 try testWrapSub(i8, -128, -128, 0);
52 try testWrapSub(i8, -1, 127, -128);51 try testWrapSub(i8, -1, 127, -128);
53 try testWrapSub(i64, minInt(i64), 1, maxInt(i64));52 try testWrapSub(i64, minInt(i64), 1, maxInt(i64));
54 if (!skip128) try testWrapSub(i128, maxInt(i128), -1, minInt(i128));53 try testWrapSub(i128, maxInt(i128), -1, minInt(i128));
55 if (!skip128) try testWrapSub(i128, minInt(i128), -maxInt(i128), -1);54 try testWrapSub(i128, minInt(i128), -maxInt(i128), -1);
56 try testWrapSub(u8, 10, 3, 7);55 try testWrapSub(u8, 10, 3, 7);
57 try testWrapSub(u8, 0, 255, 1);56 try testWrapSub(u8, 0, 255, 1);
58 try testWrapSub(u5, 0, 31, 1);57 try testWrapSub(u5, 0, 31, 1);
59 if (!skip128) try testWrapSub(u128, 0, maxInt(u128), 1);58 try testWrapSub(u128, 0, maxInt(u128), 1);
60 }59 }
6160
62 fn testWrapSub(comptime T: type, lhs: T, rhs: T, expected: T) !void {61 fn testWrapSub(comptime T: type, lhs: T, rhs: T, expected: T) !void {
...@@ -88,11 +87,11 @@ test "wrapping multiplication" {...@@ -88,11 +87,11 @@ test "wrapping multiplication" {
88 try testWrapMul(i8, -128, -128, 0);87 try testWrapMul(i8, -128, -128, 0);
89 try testWrapMul(i8, maxInt(i8), maxInt(i8), 1);88 try testWrapMul(i8, maxInt(i8), maxInt(i8), 1);
90 try testWrapMul(i16, maxInt(i16), -1, minInt(i16) + 1);89 try testWrapMul(i16, maxInt(i16), -1, minInt(i16) + 1);
91 if (!skip128) try testWrapMul(i128, maxInt(i128), -1, minInt(i128) + 1);90 try testWrapMul(i128, maxInt(i128), -1, minInt(i128) + 1);
92 if (!skip128) try testWrapMul(i128, minInt(i128), -1, minInt(i128));91 try testWrapMul(i128, minInt(i128), -1, minInt(i128));
93 try testWrapMul(u8, 10, 3, 30);92 try testWrapMul(u8, 10, 3, 30);
94 try testWrapMul(u8, 2, 255, 254);93 try testWrapMul(u8, 2, 255, 254);
95 if (!skip128) try testWrapMul(u128, maxInt(u128), maxInt(u128), 1);94 try testWrapMul(u128, maxInt(u128), maxInt(u128), 1);
96 }95 }
9796
98 fn testWrapMul(comptime T: type, lhs: T, rhs: T, expected: T) !void {97 fn testWrapMul(comptime T: type, lhs: T, rhs: T, expected: T) !void {