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;
55const assert = std.debug.assert;
66const log = std.log.scoped(.codegen);
77
8const builtin = @import("builtin");
89const link = @import("../../link.zig");
910const codegen = @import("../../codegen.zig");
1011const Zcu = @import("../../Zcu.zig");
......@@ -511,8 +512,8 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
511512 else => {},
512513 }
513514
514 if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |builtin| {
515 try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = builtin } });
515 if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |built_in| {
516 try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = built_in } });
516517 }
517518
518519 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));
......@@ -956,6 +957,7 @@ fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {
956957/// This function, unlike Module.constInt, takes care to bitcast
957958/// the value to an unsigned int first for Kernels.
958959fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
960 const gpa = cg.module.gpa;
959961 const zcu = cg.module.zcu;
960962 const target = cg.module.zcu.getTarget();
961963 const scalar_ty = ty.scalarType(zcu);
......@@ -975,11 +977,18 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
975977 .signed => @bitCast(@as(i64, @intCast(value))),
976978 .unsigned => @as(u64, @intCast(value)),
977979 };
978 assert(backing_bits == 64);
979 return cg.constructComposite(result_ty_id, &.{
980 try cg.constInt(.u32, @as(u32, @truncate(value64))),
981 try cg.constInt(.u32, @as(u32, @truncate(value64 << 32))),
982 });
980 const n_limbs = backing_bits / Module.big_int_bits;
981 const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0;
982 const scratch_top = cg.id_scratch.items.len;
983 defer cg.id_scratch.shrinkRetainingCapacity(scratch_top);
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);
983992 }
984993
985994 const final_value: spec.LiteralContextDependentNumber = switch (target.os.tag) {
......@@ -1014,6 +1023,35 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
10141023 return cg.constructCompositeSplat(ty, result_id);
10151024}
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
10171055pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const Id) !Id {
10181056 const gpa = cg.module.gpa;
10191057 const result_id = cg.module.allocId();
......@@ -1106,6 +1144,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
11061144 .false, .true => break :cache try cg.constBool(val.toBool(), repr),
11071145 },
11081146 .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 }
11091152 if (ty.isSignedInt(zcu)) {
11101153 break :cache try cg.constInt(ty, val.toSignedInt(zcu));
11111154 } else {
......@@ -1385,15 +1428,32 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
13851428 }
13861429
13871430 if (oac.byte_offset == 0) {
1388 // Allow changing the pointer type child only to restructure arrays.
1389 // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T.
1390 const result_ptr_id = cg.module.allocId();
1391 try cg.body.emit(gpa, .OpBitcast, .{
1392 .id_result_type = result_ty_id,
1393 .id_result = result_ptr_id,
1394 .operand = parent_ptr_id,
1395 });
1396 return result_ptr_id;
1431 var depth: u32 = 0;
1432 var cur = parent_ptr_ty.childType(zcu);
1433 const dst_child = oac.new_ptr_ty.childType(zcu);
1434 while (cur.toIntern() != dst_child.toIntern()) {
1435 if (cur.zigTypeTag(zcu) == .array) {
1436 cur = cur.childType(zcu);
1437 depth += 1;
1438 } else break;
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 }
13971457 }
13981458
13991459 return cg.fail("cannot perform pointer cast: '{f}' to '{f}'", .{
......@@ -1684,10 +1744,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
16841744 return try cg.module.opaqueType("u0");
16851745 }
16861746 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 }
16911747 return try cg.module.intType(int_info.signedness, int_info.bits);
16921748 },
16931749 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),
......@@ -2216,6 +2272,697 @@ const Temporary = struct {
22162272 }
22172273};
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
22192966/// Initialize a `Temporary` from an AIR value.
22202967fn temporary(cg: *CodeGen, inst: Air.Inst.Ref) !Temporary {
22212968 return .{
......@@ -3234,7 +3981,21 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id {
32343981 .xor => .OpBitwiseXor,
32353982 },
32363983 .float => unreachable,
3237 .composite_integer => unreachable, // TODO
3984 .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 },
32383999 };
32394000
32404001 const result = try cg.buildBinary(opcode, lhs, rhs);
......@@ -3256,7 +4017,39 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode
32564017
32574018 const info = cg.arithmeticTypeInfo(result_ty);
32584019 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 },
32604053 .integer, .strange_integer => {},
32614054 .float, .bool => unreachable,
32624055 }
......@@ -3380,7 +4173,16 @@ fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporar
33804173 const zcu = cg.module.zcu;
33814174 const ty = value.ty;
33824175 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 },
33844186 .strange_integer => switch (info.signedness) {
33854187 .unsigned => {
33864188 const mask_value = @as(u64, std.math.maxInt(u64)) >> @as(u6, @intCast(64 - info.bits));
......@@ -3484,7 +4286,22 @@ fn airArithOp(
34844286 const rhs = try cg.temporary(bin_op.rhs);
34854287 const info = cg.arithmeticTypeInfo(lhs.ty);
34864288 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 },
34884305 .integer, .strange_integer => res: {
34894306 const raw = switch (info.signedness) {
34904307 .signed => try cg.buildBinary(sop, lhs, rhs),
......@@ -3514,18 +4331,50 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
35144331 switch (operand_info.class) {
35154332 .float => return try cg.buildUnary(.f_abs, value),
35164333 .integer, .strange_integer => {
3517 const abs_value = try cg.buildUnary(.i_abs, value);
4334 var abs_value = try cg.buildUnary(.i_abs, value);
35184335 switch (target.os.tag) {
35194336 .vulkan, .opengl => {
35204337 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);
35224347 }
35234348 },
35244349 else => {},
35254350 }
35264351 return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty));
35274352 },
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 },
35294378 .bool => unreachable,
35304379 }
35314380}
......@@ -3553,7 +4402,69 @@ fn airAddSubOverflow(
35534402
35544403 const info = cg.arithmeticTypeInfo(lhs.ty);
35554404 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 },
35574468 .strange_integer, .integer => {},
35584469 .float, .bool => unreachable,
35594470 }
......@@ -3595,6 +4506,7 @@ fn airAddSubOverflow(
35954506
35964507fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
35974508 const pt = cg.pt;
4509 const gpa = cg.module.gpa;
35984510 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
35994511 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
36004512 const lhs = try cg.temporary(extra.lhs);
......@@ -3603,7 +4515,158 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
36034515
36044516 const info = cg.arithmeticTypeInfo(lhs.ty);
36054517 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 },
36074670 .strange_integer, .integer => {},
36084671 .float, .bool => unreachable,
36094672 }
......@@ -3622,7 +4685,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
36224685 1...16 => 32,
36234686 17...32 => if (largest_int_bits > 32) 64 else null, // Upcast if we can.
36244687 33...64 => null, // Always use wide multiplication.
3625 else => unreachable, // TODO: Composite integers
4688 else => unreachable,
36264689 };
36274690
36284691 const result, const overflowed = switch (info.signedness) {
......@@ -4245,7 +5308,16 @@ fn cmp(
42455308
42465309 const info = cg.arithmeticTypeInfo(scalar_ty);
42475310 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 },
42495321 .float => switch (op) {
42505322 .eq => .OpFOrdEqual,
42515323 .neq => .OpFUnordNotEqual,
......@@ -4408,6 +5480,192 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
44085480 const src_info = cg.arithmeticTypeInfo(src.ty);
44095481 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
44115669 if (src_info.backing_bits == dst_info.backing_bits) {
44125670 const result = if (dst_info.bits < src_info.bits)
44135671 try cg.normalize(src.pun(dst_ty), dst_info)
......@@ -4513,7 +5771,15 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
45135771 const result = switch (info.class) {
45145772 .bool => try cg.buildUnary(.l_not, operand),
45155773 .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 },
45175783 .strange_integer, .integer => blk: {
45185784 const complement = try cg.buildUnary(.bit_not, operand);
45195785 break :blk try cg.normalize(complement, info);
......@@ -6198,9 +7464,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
61987464 const value: Value = .fromInterned(item.toInterned().?);
61997465 const int_val: u64 = switch (cond_ty.zigTypeTag(zcu)) {
62007466 .bool, .int => if (cond_ty.isSignedInt(zcu)) @bitCast(value.toSignedInt(zcu)) else value.toUnsignedInt(zcu),
6201 .@"enum" => blk: {
6202 break :blk value.intFromEnum(zcu).toUnsignedInt(zcu); // TODO: composite integer constants
6203 },
7467 .@"enum" => value.intFromEnum(zcu).toUnsignedInt(zcu),
62047468 .error_set => value.getErrorInt(zcu),
62057469 .pointer => value.toUnsignedInt(zcu),
62067470 else => unreachable,
......@@ -6502,7 +7766,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
65027766fn builtin3D(
65037767 cg: *CodeGen,
65047768 result_ty: Type,
6505 builtin: spec.BuiltIn,
7769 built_in: spec.BuiltIn,
65067770 dimension: u32,
65077771 out_of_range_value: anytype,
65087772) !Id {
......@@ -6511,7 +7775,7 @@ fn builtin3D(
65117775 const u32_ty_id = try cg.module.intType(.unsigned, 32);
65127776 const vec_ty_id = try cg.module.vectorType(3, u32_ty_id);
65137777 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);
65157779 try cg.module.decl_deps.append(gpa, spv_decl_index);
65167780 const ptr_id = cg.module.declPtr(spv_decl_index).result_id;
65177781 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
658658 };
659659 const backing_bits, const big_int = module.backingIntBits(bits);
660660 if (big_int) {
661 // TODO: support composite integers larger than 64 bit
662 assert(backing_bits <= 64);
663661 const u32_ty = try module.intType(.unsigned, 32);
664662 const len_id = try module.constant(u32_ty, .{ .uint32 = backing_bits / big_int_bits });
665663 return module.arrayType(len_id, u32_ty);
src/target.zig-1
......@@ -953,7 +953,6 @@ pub inline fn backendSupportsFeature(backend: std.lang.CompilerBackend, comptime
953953 // threads because they would all just be locking the same mutex to
954954 // protect Builder.
955955 .stage2_llvm => false,
956 .stage2_spirv => true,
957956 // Please do not make any more exceptions. Backends must support
958957 // being run in a separate thread from now on.
959958 else => true,
test/behavior/abs.zig-3
......@@ -7,7 +7,6 @@ test "@abs integers" {
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1110
1211 try comptime testAbsIntegers();
1312 try testAbsIntegers();
......@@ -54,7 +53,6 @@ test "@abs signed C ABI integers" {
5453 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5554 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5655 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5856
5957 const S = struct {
6058 fn doTheTest() !void {
......@@ -146,7 +144,6 @@ test "@abs big int <= 128 bits" {
146144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
147145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148146 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
149 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
150147 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
151148
152149 try comptime testAbsSignedBigInt();
test/behavior/basic.zig-7
......@@ -24,7 +24,6 @@ fn testTruncate(x: u32) u8 {
2424}
2525
2626test "truncate to non-power-of-two integers" {
27 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2827 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2928
3029 try testTrunc(u32, u1, 0b10101, 0b1);
......@@ -41,7 +40,6 @@ test "truncate to non-power-of-two integers" {
4140test "truncate to non-power-of-two integers from 128-bit" {
4241 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4543
4644 try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010101, 0x01);
4745 try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010110, 0x00);
......@@ -299,7 +297,6 @@ const global_b: *const i32 = &global_a;
299297const global_c: *const f32 = @as(*const f32, @ptrCast(global_b));
300298test "compile time global reinterpret" {
301299 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
302
303300 const d = @as(*const i32, @ptrCast(global_c));
304301 try expect(d.* == 1234);
305302}
......@@ -1217,8 +1214,6 @@ fn testUnsignedCmp(comptime T: type) !void {
12171214}
12181215
12191216test "integer compare <= 64 bits" {
1220 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1221
12221217 inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| {
12231218 try testUnsignedCmp(T);
12241219 try comptime testUnsignedCmp(T);
......@@ -1231,7 +1226,6 @@ test "integer compare <= 64 bits" {
12311226
12321227test "integer compare <= 128 bits" {
12331228 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1234 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12351229
12361230 inline for (.{ u65, u96, u127, u128 }) |T| {
12371231 try testUnsignedCmp(T);
......@@ -1245,7 +1239,6 @@ test "integer compare <= 128 bits" {
12451239
12461240test "integer compare > 128 bits" {
12471241 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1248 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12491242
12501243 inline for (.{ u129, u255, u512, u800 }) |T| {
12511244 try testUnsignedCmp(T);
test/behavior/enum.zig-2
......@@ -26,7 +26,6 @@ const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };
2626
2727test "int to enum" {
2828 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3029
3130 try testEnumFromIntEval(3);
3231}
......@@ -974,7 +973,6 @@ test "@tagName" {
974973 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
975974 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
976975 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
977 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
978976 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
979977
980978 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" {
456456test "comptime shl" {
457457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
458458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
459 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
460459
461460 const a: u128 = 3;
462461 const b: u7 = 63;
......@@ -904,7 +903,6 @@ test "const local with comptime init through array init" {
904903}
905904
906905test "closure capture type of runtime-known parameter" {
907 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
908906 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
909907
910908 const S = struct {
......@@ -1185,7 +1183,6 @@ test "lazy sizeof is resolved in division" {
11851183}
11861184
11871185test "lazy sizeof union tag size in compare" {
1188 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11891186
11901187 const A = union(enum) {
11911188 a: void,
test/behavior/floatop.zig-1
......@@ -144,7 +144,6 @@ test "cmp f64" {
144144test "cmp f128" {
145145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
146146 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
147 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
148147 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
149148
150149 try testCmp(f128);
test/behavior/int128.zig-3
......@@ -7,7 +7,6 @@ const builtin = @import("builtin");
77test "uint128" {
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1110 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1211
1312 var buff: u128 = maxInt(u128);
......@@ -45,7 +44,6 @@ test "undefined 128 bit int" {
4544test "int128" {
4645 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4746 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4947 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5048
5149 var buff: i128 = -1;
......@@ -90,7 +88,6 @@ test "truncate int128" {
9088test "shift int128" {
9189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9290 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
93 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
9491 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9592
9693 const types = .{ u128, i128 };
test/behavior/math.zig-18
......@@ -383,7 +383,6 @@ fn not(comptime T: type, a: T) T {
383383
384384test "binary not" {
385385 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
386 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
387386
388387 try expect(not(u0, 0) == 0);
389388 try expect(not(u1, 0) == 1);
......@@ -424,7 +423,6 @@ test "binary not" {
424423test "binary not big int <= 128 bits" {
425424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
426425 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
427 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
428426 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
429427
430428 try expect(not(u65, 1) == 0x1_FFFFFFFF_FFFFFFFE);
......@@ -659,7 +657,6 @@ fn testSignedWrappingEval(x: i32) !void {
659657}
660658
661659test "signed negation wrapping" {
662 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
663660
664661 try testSignedNegationWrappingEval(minInt(i16));
665662 try comptime testSignedNegationWrappingEval(minInt(i16));
......@@ -763,7 +760,6 @@ fn should_not_be_zero(x: f128) !void {
763760test "umax wrapped squaring" {
764761 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
765762 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
766 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
767763
768764 {
769765 var x: u4 = maxInt(u4);
......@@ -820,7 +816,6 @@ test "umax wrapped squaring" {
820816test "128-bit multiplication" {
821817 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
822818 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
823 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
824819 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
825820 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
826821
......@@ -873,7 +868,6 @@ test "@addWithOverflow <= 128 bits" {
873868 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
874869 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
875870 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
876 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
877871
878872 try testAddWithOverflow(u65, 4, 105, 109, 0);
879873 try testAddWithOverflow(u65, 1000, 100, 1100, 0);
......@@ -1000,7 +994,6 @@ test "extensive @mulWithOverflow" {
1000994 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1001995 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1002996 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1003 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1004997
1005998 try testMulWithOverflow(u5, 3, 10, 30, 0);
1006999 try testMulWithOverflow(u5, 3, 11, 1, 1);
......@@ -1207,7 +1200,6 @@ test "@subWithOverflow <= 128 bits" {
12071200 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12081201 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12091202 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1210 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
12111203
12121204 try testSubWithOverflow(u65, 4, 105, maxInt(u65) - 100, 1);
12131205 try testSubWithOverflow(u65, 1000, 100, 900, 0);
......@@ -1371,7 +1363,6 @@ fn testAnd(comptime T: type, a: T, b: T, expected: T) !void {
13711363test "and > 128 bits" {
13721364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13731365 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1374 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13751366
13761367 try testAnd(u140, (1 << 139) | (1 << 70) | 0xaa, (1 << 139) | (1 << 69) | 0xcc, (1 << 139) | 0x88);
13771368 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 {
14311422test "xor > 128 bits" {
14321423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14331424 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1434 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14351425
14361426 try testXor(u140, 0, maxInt(u140), maxInt(u140));
14371427 try testXor(u140, 1 << 139, 1 << 139, 0);
......@@ -1461,7 +1451,6 @@ fn testNot(comptime T: type, a: T, expected: T) !void {
14611451test "not > 128 bits" {
14621452 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14631453 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1464 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14651454
14661455 try testNot(u140, 0, maxInt(u140));
14671456 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 {
14911480test "shl > 128 bits" {
14921481 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14931482 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1494 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14951483
14961484 try testShl(u140, 1 << 5, 10, 1 << 15);
14971485 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 {
15211509test "shr > 128 bits" {
15221510 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15231511 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1524 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15251512
15261513 try testShr(u140, 1 << 139, 39, 1 << 100);
15271514 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
25342521 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25352522 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25362523 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2537 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
25382524 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;
25392525
25402526 var lhs: @Vector(2, i8) = .{ -128, 5 };
......@@ -2562,7 +2548,6 @@ test "float vector division of comptime zero by runtime nan is nan" {
25622548 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25632549 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25642550 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2565 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
25662551
25672552 const ct_zero: @Vector(1, f32) = .{0};
25682553 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" {
25792564 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25802565 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25812566 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2582 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
25832567
25842568 const ct_zero: @Vector(1, f32) = .{0};
25852569 var rt_nan: @Vector(1, f32) = .{math.nan(f32)};
......@@ -2594,7 +2578,6 @@ test "comptime float vector division of zero by nan is nan" {
25942578 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25952579 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25962580 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2597 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
25982581
25992582 const ct_zero: @Vector(1, f32) = .{0};
26002583 const ct_nan: @Vector(1, f32) = .{math.nan(f32)};
......@@ -2608,7 +2591,6 @@ test "comptime float vector multiplication of zero by nan is nan" {
26082591 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26092592 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26102593 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2611 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
26122594
26132595 const ct_zero: @Vector(1, f32) = .{0};
26142596 const ct_nan: @Vector(1, f32) = .{math.nan(f32)};
test/behavior/muladd.zig-2
......@@ -6,7 +6,6 @@ test "@mulAdd" {
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
109
1110 try comptime testMulAdd();
1211 try testMulAdd();
......@@ -33,7 +32,6 @@ test "@mulAdd f16" {
3332 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3433 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3534 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
36 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3735
3836 try comptime testMulAdd16();
3937 try testMulAdd16();
test/behavior/while.zig-3
......@@ -38,7 +38,6 @@ fn staticWhileLoop2() i32 {
3838}
3939
4040test "while with continue expression" {
41 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4241
4342 var sum: i32 = 0;
4443 {
......@@ -158,7 +157,6 @@ test "while with optional as condition with else" {
158157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
159158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
160159 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
161 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
162160
163161 numbers_left = 10;
164162 var sum: i32 = 0;
......@@ -176,7 +174,6 @@ test "while with optional as condition with else" {
176174test "while with error union condition" {
177175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
178176 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
179 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
180177
181178 numbers_left = 10;
182179 var sum: i32 = 0;
test/behavior/widening.zig-1
......@@ -6,7 +6,6 @@ const builtin = @import("builtin");
66test "integer widening" {
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
1211 var a: u8 = 250;
test/behavior/wrapping_arithmetic.zig+9-10
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33const minInt = std.math.minInt;
44const maxInt = std.math.maxInt;
55const expect = std.testing.expect;
6const skip128 = builtin.zig_backend == .stage2_spirv;
76
87test "wrapping add" {
98 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -14,14 +13,14 @@ test "wrapping add" {
1413 try testWrapAdd(i8, -128, -128, 0);
1514 try testWrapAdd(i2, 1, 1, -2);
1615 try testWrapAdd(i64, maxInt(i64), 1, minInt(i64));
17 if (!skip128) try testWrapAdd(i128, maxInt(i128), -maxInt(i128), 0);
18 if (!skip128) try testWrapAdd(i128, minInt(i128), maxInt(i128), -1);
16 try testWrapAdd(i128, maxInt(i128), -maxInt(i128), 0);
17 try testWrapAdd(i128, minInt(i128), maxInt(i128), -1);
1918 try testWrapAdd(i8, 127, 127, -2);
2019 try testWrapAdd(u8, 3, 10, 13);
2120 try testWrapAdd(u8, 255, 255, 254);
2221 try testWrapAdd(u2, 3, 2, 1);
2322 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));
2524 }
2625
2726 fn testWrapAdd(comptime T: type, lhs: T, rhs: T, expected: T) !void {
......@@ -51,12 +50,12 @@ test "wrapping subtraction" {
5150 try testWrapSub(i8, -128, -128, 0);
5251 try testWrapSub(i8, -1, 127, -128);
5352 try testWrapSub(i64, minInt(i64), 1, maxInt(i64));
54 if (!skip128) try testWrapSub(i128, maxInt(i128), -1, minInt(i128));
55 if (!skip128) try testWrapSub(i128, minInt(i128), -maxInt(i128), -1);
53 try testWrapSub(i128, maxInt(i128), -1, minInt(i128));
54 try testWrapSub(i128, minInt(i128), -maxInt(i128), -1);
5655 try testWrapSub(u8, 10, 3, 7);
5756 try testWrapSub(u8, 0, 255, 1);
5857 try testWrapSub(u5, 0, 31, 1);
59 if (!skip128) try testWrapSub(u128, 0, maxInt(u128), 1);
58 try testWrapSub(u128, 0, maxInt(u128), 1);
6059 }
6160
6261 fn testWrapSub(comptime T: type, lhs: T, rhs: T, expected: T) !void {
......@@ -88,11 +87,11 @@ test "wrapping multiplication" {
8887 try testWrapMul(i8, -128, -128, 0);
8988 try testWrapMul(i8, maxInt(i8), maxInt(i8), 1);
9089 try testWrapMul(i16, maxInt(i16), -1, minInt(i16) + 1);
91 if (!skip128) try testWrapMul(i128, maxInt(i128), -1, minInt(i128) + 1);
92 if (!skip128) try testWrapMul(i128, minInt(i128), -1, minInt(i128));
90 try testWrapMul(i128, maxInt(i128), -1, minInt(i128) + 1);
91 try testWrapMul(i128, minInt(i128), -1, minInt(i128));
9392 try testWrapMul(u8, 10, 3, 30);
9493 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);
9695 }
9796
9897 fn testWrapMul(comptime T: type, lhs: T, rhs: T, expected: T) !void {