| ... | ... | @@ -2167,21 +2167,20 @@ const DeclGen = struct { |
| 2167 | 2167 | const air_tags = self.air.instructions.items(.tag); |
| 2168 | 2168 | const maybe_result_id: ?IdRef = switch (air_tags[@intFromEnum(inst)]) { |
| 2169 | 2169 | // zig fmt: off |
| 2170 | | .add, .add_wrap => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd, true), |
| 2171 | | .sub, .sub_wrap => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub, true), |
| 2172 | | .mul, .mul_wrap => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul, true), |
| 2170 | .add, .add_wrap => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd), |
| 2171 | .sub, .sub_wrap => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub), |
| 2172 | .mul, .mul_wrap => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul), |
| 2173 | 2173 | |
| 2174 | 2174 | .div_float, |
| 2175 | 2175 | .div_float_optimized, |
| 2176 | 2176 | // TODO: Check that this is the right operation. |
| 2177 | 2177 | .div_trunc, |
| 2178 | 2178 | .div_trunc_optimized, |
| 2179 | | => try self.airArithOp(inst, .OpFDiv, .OpSDiv, .OpUDiv, false), |
| 2179 | => try self.airArithOp(inst, .OpFDiv, .OpSDiv, .OpUDiv), |
| 2180 | 2180 | // TODO: Check if this is the right operation |
| 2181 | | // TODO: Make airArithOp for rem not emit a mask for the LHS. |
| 2182 | 2181 | .rem, |
| 2183 | 2182 | .rem_optimized, |
| 2184 | | => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem, false), |
| 2183 | => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem), |
| 2185 | 2184 | |
| 2186 | 2185 | .add_with_overflow => try self.airAddSubOverflow(inst, .OpIAdd, .OpULessThan, .OpSLessThan), |
| 2187 | 2186 | .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan), |
| ... | ... | @@ -2346,13 +2345,10 @@ const DeclGen = struct { |
| 2346 | 2345 | |
| 2347 | 2346 | var wip = try self.elementWise(result_ty); |
| 2348 | 2347 | defer wip.deinit(); |
| 2349 | | for (0..wip.results.len) |i| { |
| 2348 | for (wip.results, 0..) |*result_id, i| { |
| 2350 | 2349 | const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i); |
| 2351 | 2350 | const rhs_elem_id = try wip.elementAt(shift_ty, rhs_id, i); |
| 2352 | 2351 | |
| 2353 | | // TODO: Can we omit normalizing lhs? |
| 2354 | | const lhs_norm_id = try self.normalizeInt(wip.scalar_ty_ref, lhs_elem_id, info); |
| 2355 | | |
| 2356 | 2352 | // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that, |
| 2357 | 2353 | // so just manually upcast it if required. |
| 2358 | 2354 | const shift_id = if (scalar_shift_ty_ref != wip.scalar_ty_ref) blk: { |
| ... | ... | @@ -2364,13 +2360,13 @@ const DeclGen = struct { |
| 2364 | 2360 | }); |
| 2365 | 2361 | break :blk shift_id; |
| 2366 | 2362 | } else rhs_elem_id; |
| 2367 | | const shift_norm_id = try self.normalizeInt(wip.scalar_ty_ref, shift_id, info); |
| 2368 | 2363 | |
| 2364 | const value_id = self.spv.allocId(); |
| 2369 | 2365 | const args = .{ |
| 2370 | 2366 | .id_result_type = wip.scalar_ty_id, |
| 2371 | | .id_result = wip.allocId(i), |
| 2372 | | .base = lhs_norm_id, |
| 2373 | | .shift = shift_norm_id, |
| 2367 | .id_result = value_id, |
| 2368 | .base = lhs_elem_id, |
| 2369 | .shift = shift_id, |
| 2374 | 2370 | }; |
| 2375 | 2371 | |
| 2376 | 2372 | if (result_ty.isSignedInt(mod)) { |
| ... | ... | @@ -2378,6 +2374,8 @@ const DeclGen = struct { |
| 2378 | 2374 | } else { |
| 2379 | 2375 | try self.func.body.emit(self.spv.gpa, unsigned, args); |
| 2380 | 2376 | } |
| 2377 | |
| 2378 | result_id.* = try self.normalize(wip.scalar_ty_ref, value_id, info); |
| 2381 | 2379 | } |
| 2382 | 2380 | return try wip.finalize(); |
| 2383 | 2381 | } |
| ... | ... | @@ -2435,47 +2433,52 @@ const DeclGen = struct { |
| 2435 | 2433 | return result_id; |
| 2436 | 2434 | } |
| 2437 | 2435 | |
| 2438 | | /// This function canonicalizes a "strange" integer value: |
| 2439 | | /// For unsigned integers, the value is masked so that only the relevant bits can contain |
| 2440 | | /// non-zeros. |
| 2441 | | /// For signed integers, the value is also sign extended. |
| 2442 | | fn normalizeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, info: ArithmeticTypeInfo) !IdRef { |
| 2443 | | assert(info.class != .composite_integer); // TODO |
| 2444 | | if (info.bits == info.backing_bits) { |
| 2445 | | return value_id; |
| 2446 | | } |
| 2447 | | |
| 2448 | | switch (info.signedness) { |
| 2449 | | .unsigned => { |
| 2450 | | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; |
| 2451 | | const result_id = self.spv.allocId(); |
| 2452 | | const mask_id = try self.constInt(ty_ref, mask_value); |
| 2453 | | try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{ |
| 2454 | | .id_result_type = self.typeId(ty_ref), |
| 2455 | | .id_result = result_id, |
| 2456 | | .operand_1 = value_id, |
| 2457 | | .operand_2 = mask_id, |
| 2458 | | }); |
| 2459 | | return result_id; |
| 2460 | | }, |
| 2461 | | .signed => { |
| 2462 | | // Shift left and right so that we can copy the sight bit that way. |
| 2463 | | const shift_amt_id = try self.constInt(ty_ref, info.backing_bits - info.bits); |
| 2464 | | const left_id = self.spv.allocId(); |
| 2465 | | try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{ |
| 2466 | | .id_result_type = self.typeId(ty_ref), |
| 2467 | | .id_result = left_id, |
| 2468 | | .base = value_id, |
| 2469 | | .shift = shift_amt_id, |
| 2470 | | }); |
| 2471 | | const right_id = self.spv.allocId(); |
| 2472 | | try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{ |
| 2473 | | .id_result_type = self.typeId(ty_ref), |
| 2474 | | .id_result = right_id, |
| 2475 | | .base = left_id, |
| 2476 | | .shift = shift_amt_id, |
| 2477 | | }); |
| 2478 | | return right_id; |
| 2436 | /// This function normalizes values to a canonical representation |
| 2437 | /// after some arithmetic operation. This mostly consists of wrapping |
| 2438 | /// behavior for strange integers: |
| 2439 | /// - Unsigned integers are bitwise masked with a mask that only passes |
| 2440 | /// the valid bits through. |
| 2441 | /// - Signed integers are also sign extended if they are negative. |
| 2442 | /// All other values are returned unmodified (this makes strange integer |
| 2443 | /// wrapping easier to use in generic operations). |
| 2444 | fn normalize(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, info: ArithmeticTypeInfo) !IdRef { |
| 2445 | switch (info.class) { |
| 2446 | .integer, .bool, .float => return value_id, |
| 2447 | .composite_integer => unreachable, // TODO |
| 2448 | .strange_integer => { |
| 2449 | switch (info.signedness) { |
| 2450 | .unsigned => { |
| 2451 | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; |
| 2452 | const result_id = self.spv.allocId(); |
| 2453 | const mask_id = try self.constInt(ty_ref, mask_value); |
| 2454 | try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{ |
| 2455 | .id_result_type = self.typeId(ty_ref), |
| 2456 | .id_result = result_id, |
| 2457 | .operand_1 = value_id, |
| 2458 | .operand_2 = mask_id, |
| 2459 | }); |
| 2460 | return result_id; |
| 2461 | }, |
| 2462 | .signed => { |
| 2463 | // Shift left and right so that we can copy the sight bit that way. |
| 2464 | const shift_amt_id = try self.constInt(ty_ref, info.backing_bits - info.bits); |
| 2465 | const left_id = self.spv.allocId(); |
| 2466 | try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{ |
| 2467 | .id_result_type = self.typeId(ty_ref), |
| 2468 | .id_result = left_id, |
| 2469 | .base = value_id, |
| 2470 | .shift = shift_amt_id, |
| 2471 | }); |
| 2472 | const right_id = self.spv.allocId(); |
| 2473 | try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{ |
| 2474 | .id_result_type = self.typeId(ty_ref), |
| 2475 | .id_result = right_id, |
| 2476 | .base = left_id, |
| 2477 | .shift = shift_amt_id, |
| 2478 | }); |
| 2479 | return right_id; |
| 2480 | }, |
| 2481 | } |
| 2479 | 2482 | }, |
| 2480 | 2483 | } |
| 2481 | 2484 | } |
| ... | ... | @@ -2486,8 +2489,6 @@ const DeclGen = struct { |
| 2486 | 2489 | comptime fop: Opcode, |
| 2487 | 2490 | comptime sop: Opcode, |
| 2488 | 2491 | comptime uop: Opcode, |
| 2489 | | /// true if this operation holds under modular arithmetic. |
| 2490 | | comptime modular: bool, |
| 2491 | 2492 | ) !?IdRef { |
| 2492 | 2493 | if (self.liveness.isUnused(inst)) return null; |
| 2493 | 2494 | |
| ... | ... | @@ -2501,7 +2502,7 @@ const DeclGen = struct { |
| 2501 | 2502 | assert(self.typeOf(bin_op.lhs).eql(ty, self.module)); |
| 2502 | 2503 | assert(self.typeOf(bin_op.rhs).eql(ty, self.module)); |
| 2503 | 2504 | |
| 2504 | | return try self.arithOp(ty, lhs_id, rhs_id, fop, sop, uop, modular); |
| 2505 | return try self.arithOp(ty, lhs_id, rhs_id, fop, sop, uop); |
| 2505 | 2506 | } |
| 2506 | 2507 | |
| 2507 | 2508 | fn arithOp( |
| ... | ... | @@ -2512,8 +2513,6 @@ const DeclGen = struct { |
| 2512 | 2513 | comptime fop: Opcode, |
| 2513 | 2514 | comptime sop: Opcode, |
| 2514 | 2515 | comptime uop: Opcode, |
| 2515 | | /// true if this operation holds under modular arithmetic. |
| 2516 | | comptime modular: bool, |
| 2517 | 2516 | ) !IdRef { |
| 2518 | 2517 | // Binary operations are generally applicable to both scalar and vector operations |
| 2519 | 2518 | // in SPIR-V, but int and float versions of operations require different opcodes. |
| ... | ... | @@ -2533,25 +2532,16 @@ const DeclGen = struct { |
| 2533 | 2532 | |
| 2534 | 2533 | var wip = try self.elementWise(ty); |
| 2535 | 2534 | defer wip.deinit(); |
| 2536 | | for (0..wip.results.len) |i| { |
| 2535 | for (wip.results, 0..) |*result_id, i| { |
| 2537 | 2536 | const lhs_elem_id = try wip.elementAt(ty, lhs_id, i); |
| 2538 | 2537 | const rhs_elem_id = try wip.elementAt(ty, rhs_id, i); |
| 2539 | 2538 | |
| 2540 | | const lhs_norm_id = if (modular and info.class == .strange_integer) |
| 2541 | | try self.normalizeInt(wip.scalar_ty_ref, lhs_elem_id, info) |
| 2542 | | else |
| 2543 | | lhs_elem_id; |
| 2544 | | |
| 2545 | | const rhs_norm_id = if (modular and info.class == .strange_integer) |
| 2546 | | try self.normalizeInt(wip.scalar_ty_ref, rhs_elem_id, info) |
| 2547 | | else |
| 2548 | | rhs_elem_id; |
| 2549 | | |
| 2539 | const value_id = self.spv.allocId(); |
| 2550 | 2540 | const operands = .{ |
| 2551 | 2541 | .id_result_type = wip.scalar_ty_id, |
| 2552 | | .id_result = wip.allocId(i), |
| 2553 | | .operand_1 = lhs_norm_id, |
| 2554 | | .operand_2 = rhs_norm_id, |
| 2542 | .id_result = value_id, |
| 2543 | .operand_1 = lhs_elem_id, |
| 2544 | .operand_2 = rhs_elem_id, |
| 2555 | 2545 | }; |
| 2556 | 2546 | |
| 2557 | 2547 | switch (opcode_index) { |
| ... | ... | @@ -2563,6 +2553,7 @@ const DeclGen = struct { |
| 2563 | 2553 | |
| 2564 | 2554 | // TODO: Trap on overflow? Probably going to be annoying. |
| 2565 | 2555 | // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap. |
| 2556 | result_id.* = try self.normalize(wip.scalar_ty_ref, value_id, info); |
| 2566 | 2557 | } |
| 2567 | 2558 | |
| 2568 | 2559 | return try wip.finalize(); |
| ... | ... | @@ -2599,24 +2590,22 @@ const DeclGen = struct { |
| 2599 | 2590 | defer wip_result.deinit(); |
| 2600 | 2591 | var wip_ov = try self.elementWise(ov_ty); |
| 2601 | 2592 | defer wip_ov.deinit(); |
| 2602 | | for (wip_result.results, wip_ov.results, 0..) |*value_id, *ov_id, i| { |
| 2593 | for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| { |
| 2603 | 2594 | const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i); |
| 2604 | 2595 | const rhs_elem_id = try wip_result.elementAt(operand_ty, rhs, i); |
| 2605 | 2596 | |
| 2606 | 2597 | // Normalize both so that we can properly check for overflow |
| 2607 | | const lhs_norm_id = try self.normalizeInt(wip_result.scalar_ty_ref, lhs_elem_id, info); |
| 2608 | | const rhs_norm_id = try self.normalizeInt(wip_result.scalar_ty_ref, rhs_elem_id, info); |
| 2609 | | const op_result_id = self.spv.allocId(); |
| 2598 | const value_id = self.spv.allocId(); |
| 2610 | 2599 | |
| 2611 | 2600 | try self.func.body.emit(self.spv.gpa, add, .{ |
| 2612 | 2601 | .id_result_type = wip_result.scalar_ty_id, |
| 2613 | | .id_result = op_result_id, |
| 2614 | | .operand_1 = lhs_norm_id, |
| 2615 | | .operand_2 = rhs_norm_id, |
| 2602 | .id_result = value_id, |
| 2603 | .operand_1 = lhs_elem_id, |
| 2604 | .operand_2 = rhs_elem_id, |
| 2616 | 2605 | }); |
| 2617 | 2606 | |
| 2618 | 2607 | // Normalize the result so that the comparisons go well |
| 2619 | | value_id.* = try self.normalizeInt(wip_result.scalar_ty_ref, op_result_id, info); |
| 2608 | result_id.* = try self.normalize(wip_result.scalar_ty_ref, value_id, info); |
| 2620 | 2609 | |
| 2621 | 2610 | const overflowed_id = switch (info.signedness) { |
| 2622 | 2611 | .unsigned => blk: { |
| ... | ... | @@ -2626,8 +2615,8 @@ const DeclGen = struct { |
| 2626 | 2615 | try self.func.body.emit(self.spv.gpa, ucmp, .{ |
| 2627 | 2616 | .id_result_type = self.typeId(bool_ty_ref), |
| 2628 | 2617 | .id_result = overflowed_id, |
| 2629 | | .operand_1 = value_id.*, |
| 2630 | | .operand_2 = lhs_norm_id, |
| 2618 | .operand_1 = result_id.*, |
| 2619 | .operand_2 = lhs_elem_id, |
| 2631 | 2620 | }); |
| 2632 | 2621 | break :blk overflowed_id; |
| 2633 | 2622 | }, |
| ... | ... | @@ -2654,7 +2643,7 @@ const DeclGen = struct { |
| 2654 | 2643 | try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{ |
| 2655 | 2644 | .id_result_type = self.typeId(bool_ty_ref), |
| 2656 | 2645 | .id_result = rhs_lt_zero_id, |
| 2657 | | .operand_1 = rhs_norm_id, |
| 2646 | .operand_1 = rhs_elem_id, |
| 2658 | 2647 | .operand_2 = zero_id, |
| 2659 | 2648 | }); |
| 2660 | 2649 | |
| ... | ... | @@ -2662,8 +2651,8 @@ const DeclGen = struct { |
| 2662 | 2651 | try self.func.body.emit(self.spv.gpa, scmp, .{ |
| 2663 | 2652 | .id_result_type = self.typeId(bool_ty_ref), |
| 2664 | 2653 | .id_result = value_gt_lhs_id, |
| 2665 | | .operand_1 = lhs_norm_id, |
| 2666 | | .operand_2 = value_id.*, |
| 2654 | .operand_1 = lhs_elem_id, |
| 2655 | .operand_2 = result_id.*, |
| 2667 | 2656 | }); |
| 2668 | 2657 | |
| 2669 | 2658 | const overflowed_id = self.spv.allocId(); |
| ... | ... | @@ -2715,13 +2704,10 @@ const DeclGen = struct { |
| 2715 | 2704 | defer wip_result.deinit(); |
| 2716 | 2705 | var wip_ov = try self.elementWise(ov_ty); |
| 2717 | 2706 | defer wip_ov.deinit(); |
| 2718 | | for (0..wip_result.results.len, wip_ov.results) |i, *ov_id| { |
| 2707 | for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| { |
| 2719 | 2708 | const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i); |
| 2720 | 2709 | const rhs_elem_id = try wip_result.elementAt(shift_ty, rhs, i); |
| 2721 | 2710 | |
| 2722 | | // Normalize both so that we can shift back and check if the result is the same. |
| 2723 | | const lhs_norm_id = try self.normalizeInt(wip_result.scalar_ty_ref, lhs_elem_id, info); |
| 2724 | | |
| 2725 | 2711 | // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that, |
| 2726 | 2712 | // so just manually upcast it if required. |
| 2727 | 2713 | const shift_id = if (scalar_shift_ty_ref != wip_result.scalar_ty_ref) blk: { |
| ... | ... | @@ -2733,29 +2719,41 @@ const DeclGen = struct { |
| 2733 | 2719 | }); |
| 2734 | 2720 | break :blk shift_id; |
| 2735 | 2721 | } else rhs_elem_id; |
| 2736 | | const shift_norm_id = try self.normalizeInt(wip_result.scalar_ty_ref, shift_id, info); |
| 2737 | 2722 | |
| 2723 | const value_id = self.spv.allocId(); |
| 2738 | 2724 | try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{ |
| 2739 | 2725 | .id_result_type = wip_result.scalar_ty_id, |
| 2740 | | .id_result = wip_result.allocId(i), |
| 2741 | | .base = lhs_norm_id, |
| 2742 | | .shift = shift_norm_id, |
| 2726 | .id_result = value_id, |
| 2727 | .base = lhs_elem_id, |
| 2728 | .shift = shift_id, |
| 2743 | 2729 | }); |
| 2730 | result_id.* = try self.normalize(wip_result.scalar_ty_ref, value_id, info); |
| 2744 | 2731 | |
| 2745 | | // To check if overflow happened, just check if the right-shifted result is the same value. |
| 2746 | 2732 | const right_shift_id = self.spv.allocId(); |
| 2747 | | try self.func.body.emit(self.spv.gpa, .OpShiftRightLogical, .{ |
| 2748 | | .id_result_type = wip_result.scalar_ty_id, |
| 2749 | | .id_result = right_shift_id, |
| 2750 | | .base = try self.normalizeInt(wip_result.scalar_ty_ref, wip_result.results[i], info), |
| 2751 | | .shift = shift_norm_id, |
| 2752 | | }); |
| 2733 | switch (info.signedness) { |
| 2734 | .signed => { |
| 2735 | try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{ |
| 2736 | .id_result_type = wip_result.scalar_ty_id, |
| 2737 | .id_result = right_shift_id, |
| 2738 | .base = result_id.*, |
| 2739 | .shift = shift_id, |
| 2740 | }); |
| 2741 | }, |
| 2742 | .unsigned => { |
| 2743 | try self.func.body.emit(self.spv.gpa, .OpShiftRightLogical, .{ |
| 2744 | .id_result_type = wip_result.scalar_ty_id, |
| 2745 | .id_result = right_shift_id, |
| 2746 | .base = result_id.*, |
| 2747 | .shift = shift_id, |
| 2748 | }); |
| 2749 | }, |
| 2750 | } |
| 2753 | 2751 | |
| 2754 | 2752 | const overflowed_id = self.spv.allocId(); |
| 2755 | 2753 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ |
| 2756 | 2754 | .id_result_type = self.typeId(bool_ty_ref), |
| 2757 | 2755 | .id_result = overflowed_id, |
| 2758 | | .operand_1 = lhs_norm_id, |
| 2756 | .operand_1 = lhs_elem_id, |
| 2759 | 2757 | .operand_2 = right_shift_id, |
| 2760 | 2758 | }); |
| 2761 | 2759 | |
| ... | ... | @@ -3113,14 +3111,7 @@ const DeclGen = struct { |
| 3113 | 3111 | .neq => .OpLogicalNotEqual, |
| 3114 | 3112 | else => unreachable, |
| 3115 | 3113 | }, |
| 3116 | | .strange_integer => sign: { |
| 3117 | | const op_ty_ref = try self.resolveType(op_ty, .direct); |
| 3118 | | // Mask operands before performing comparison. |
| 3119 | | cmp_lhs_id = try self.normalizeInt(op_ty_ref, cmp_lhs_id, info); |
| 3120 | | cmp_rhs_id = try self.normalizeInt(op_ty_ref, cmp_rhs_id, info); |
| 3121 | | break :sign info.signedness; |
| 3122 | | }, |
| 3123 | | .integer => info.signedness, |
| 3114 | .integer, .strange_integer => info.signedness, |
| 3124 | 3115 | }; |
| 3125 | 3116 | |
| 3126 | 3117 | break :opcode switch (signedness) { |
| ... | ... | @@ -3252,18 +3243,13 @@ const DeclGen = struct { |
| 3252 | 3243 | const operand_id = try self.resolve(ty_op.operand); |
| 3253 | 3244 | const src_ty = self.typeOf(ty_op.operand); |
| 3254 | 3245 | const dst_ty = self.typeOfIndex(inst); |
| 3255 | | const src_ty_ref = try self.resolveType(src_ty, .direct); |
| 3256 | 3246 | const dst_ty_ref = try self.resolveType(dst_ty, .direct); |
| 3257 | 3247 | |
| 3258 | 3248 | const src_info = try self.arithmeticTypeInfo(src_ty); |
| 3259 | 3249 | const dst_info = try self.arithmeticTypeInfo(dst_ty); |
| 3260 | 3250 | |
| 3261 | | // While intcast promises that the value already fits, the upper bits of a |
| 3262 | | // strange integer may contain garbage. Therefore, mask/sign extend it before. |
| 3263 | | const src_id = try self.normalizeInt(src_ty_ref, operand_id, src_info); |
| 3264 | | |
| 3265 | 3251 | if (src_info.backing_bits == dst_info.backing_bits) { |
| 3266 | | return src_id; |
| 3252 | return operand_id; |
| 3267 | 3253 | } |
| 3268 | 3254 | |
| 3269 | 3255 | const result_id = self.spv.allocId(); |
| ... | ... | @@ -3271,14 +3257,23 @@ const DeclGen = struct { |
| 3271 | 3257 | .signed => try self.func.body.emit(self.spv.gpa, .OpSConvert, .{ |
| 3272 | 3258 | .id_result_type = self.typeId(dst_ty_ref), |
| 3273 | 3259 | .id_result = result_id, |
| 3274 | | .signed_value = src_id, |
| 3260 | .signed_value = operand_id, |
| 3275 | 3261 | }), |
| 3276 | 3262 | .unsigned => try self.func.body.emit(self.spv.gpa, .OpUConvert, .{ |
| 3277 | 3263 | .id_result_type = self.typeId(dst_ty_ref), |
| 3278 | 3264 | .id_result = result_id, |
| 3279 | | .unsigned_value = src_id, |
| 3265 | .unsigned_value = operand_id, |
| 3280 | 3266 | }), |
| 3281 | 3267 | } |
| 3268 | |
| 3269 | // Make sure to normalize the result if shrinking. |
| 3270 | // Because strange ints are sign extended in their backing |
| 3271 | // type, we don't need to normalize when growing the type. The |
| 3272 | // representation is already the same. |
| 3273 | if (dst_info.bits < src_info.bits) { |
| 3274 | return try self.normalize(dst_ty_ref, result_id, dst_info); |
| 3275 | } |
| 3276 | |
| 3282 | 3277 | return result_id; |
| 3283 | 3278 | } |
| 3284 | 3279 | |