| author | |
| committer | |
| log | 39420838061a9049fbc889212836a9d4d2ab9af4 |
| tree | de835335172000e497871f9593bac17bcff882c0 |
| parent | 3eeb70540d7f40526b4f4549deb6e2bc792bb3b2 |
| parent | 436f53f55d3191bfa56418d98130d763fa5a6b22 |
| signature |
spirv: implement `@divFloor`, `@floor`, `@mod` and `@mulWithOverflow`11 files changed, 241 insertions(+), 75 deletions(-)
src/codegen/spirv.zig+198-38| ... | @@ -1016,7 +1016,7 @@ const DeclGen = struct { | ... | @@ -1016,7 +1016,7 @@ const DeclGen = struct { |
| 1016 | const elem_ty = Type.fromInterned(array_type.child); | 1016 | const elem_ty = Type.fromInterned(array_type.child); |
| 1017 | const elem_ty_ref = try self.resolveType(elem_ty, .indirect); | 1017 | const elem_ty_ref = try self.resolveType(elem_ty, .indirect); |
| 1018 | 1018 | ||
| 1019 | const constituents = try self.gpa.alloc(IdRef, @as(u32, @intCast(ty.arrayLenIncludingSentinel(mod)))); | 1019 | const constituents = try self.gpa.alloc(IdRef, @intCast(ty.arrayLenIncludingSentinel(mod))); |
| 1020 | defer self.gpa.free(constituents); | 1020 | defer self.gpa.free(constituents); |
| 1021 | 1021 | ||
| 1022 | switch (aggregate.storage) { | 1022 | switch (aggregate.storage) { |
| ... | @@ -1736,7 +1736,6 @@ const DeclGen = struct { | ... | @@ -1736,7 +1736,6 @@ const DeclGen = struct { |
| 1736 | .EnumLiteral, | 1736 | .EnumLiteral, |
| 1737 | .ComptimeFloat, | 1737 | .ComptimeFloat, |
| 1738 | .ComptimeInt, | 1738 | .ComptimeInt, |
| 1739 | .Type, | ||
| 1740 | => unreachable, // Must be comptime. | 1739 | => unreachable, // Must be comptime. |
| 1741 | 1740 | ||
| 1742 | else => |tag| return self.todo("Implement zig type '{}'", .{tag}), | 1741 | else => |tag| return self.todo("Implement zig type '{}'", .{tag}), |
| ... | @@ -2316,21 +2315,23 @@ const DeclGen = struct { | ... | @@ -2316,21 +2315,23 @@ const DeclGen = struct { |
| 2316 | .sub, .sub_wrap, .sub_optimized => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub), | 2315 | .sub, .sub_wrap, .sub_optimized => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub), |
| 2317 | .mul, .mul_wrap, .mul_optimized => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul), | 2316 | .mul, .mul_wrap, .mul_optimized => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul), |
| 2318 | 2317 | ||
| 2318 | |||
| 2319 | .abs => try self.airAbs(inst), | 2319 | .abs => try self.airAbs(inst), |
| 2320 | .floor => try self.airFloor(inst), | ||
| 2321 | |||
| 2322 | .div_floor => try self.airDivFloor(inst), | ||
| 2320 | 2323 | ||
| 2321 | .div_float, | 2324 | .div_float, |
| 2322 | .div_float_optimized, | 2325 | .div_float_optimized, |
| 2323 | // TODO: Check that this is the right operation. | ||
| 2324 | .div_trunc, | 2326 | .div_trunc, |
| 2325 | .div_trunc_optimized, | 2327 | .div_trunc_optimized => try self.airArithOp(inst, .OpFDiv, .OpSDiv, .OpUDiv), |
| 2326 | => try self.airArithOp(inst, .OpFDiv, .OpSDiv, .OpUDiv), | 2328 | .rem, .rem_optimized => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem), |
| 2327 | // TODO: Check if this is the right operation | 2329 | .mod, .mod_optimized => try self.airArithOp(inst, .OpFMod, .OpSMod, .OpSMod), |
| 2328 | .rem, | 2330 | |
| 2329 | .rem_optimized, | ||
| 2330 | => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem), | ||
| 2331 | 2331 | ||
| 2332 | .add_with_overflow => try self.airAddSubOverflow(inst, .OpIAdd, .OpULessThan, .OpSLessThan), | 2332 | .add_with_overflow => try self.airAddSubOverflow(inst, .OpIAdd, .OpULessThan, .OpSLessThan), |
| 2333 | .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan), | 2333 | .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan), |
| 2334 | .mul_with_overflow => try self.airMulOverflow(inst), | ||
| 2334 | .shl_with_overflow => try self.airShlOverflow(inst), | 2335 | .shl_with_overflow => try self.airShlOverflow(inst), |
| 2335 | 2336 | ||
| 2336 | .mul_add => try self.airMulAdd(inst), | 2337 | .mul_add => try self.airMulAdd(inst), |
| ... | @@ -2340,7 +2341,7 @@ const DeclGen = struct { | ... | @@ -2340,7 +2341,7 @@ const DeclGen = struct { |
| 2340 | 2341 | ||
| 2341 | .splat => try self.airSplat(inst), | 2342 | .splat => try self.airSplat(inst), |
| 2342 | .reduce, .reduce_optimized => try self.airReduce(inst), | 2343 | .reduce, .reduce_optimized => try self.airReduce(inst), |
| 2343 | .shuffle => try self.airShuffle(inst), | 2344 | .shuffle => try self.airShuffle(inst), |
| 2344 | 2345 | ||
| 2345 | .ptr_add => try self.airPtrAdd(inst), | 2346 | .ptr_add => try self.airPtrAdd(inst), |
| 2346 | .ptr_sub => try self.airPtrSub(inst), | 2347 | .ptr_sub => try self.airPtrSub(inst), |
| ... | @@ -2661,6 +2662,95 @@ const DeclGen = struct { | ... | @@ -2661,6 +2662,95 @@ const DeclGen = struct { |
| 2661 | } | 2662 | } |
| 2662 | } | 2663 | } |
| 2663 | 2664 | ||
| 2665 | fn airDivFloor(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | ||
| 2666 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | ||
| 2667 | const lhs_id = try self.resolve(bin_op.lhs); | ||
| 2668 | const rhs_id = try self.resolve(bin_op.rhs); | ||
| 2669 | const ty = self.typeOfIndex(inst); | ||
| 2670 | const ty_ref = try self.resolveType(ty, .direct); | ||
| 2671 | const info = self.arithmeticTypeInfo(ty); | ||
| 2672 | switch (info.class) { | ||
| 2673 | .composite_integer => unreachable, // TODO | ||
| 2674 | .integer, .strange_integer => { | ||
| 2675 | const zero_id = try self.constInt(ty_ref, 0); | ||
| 2676 | const one_id = try self.constInt(ty_ref, 1); | ||
| 2677 | |||
| 2678 | // (a ^ b) > 0 | ||
| 2679 | const bin_bitwise_id = try self.binOpSimple(ty, lhs_id, rhs_id, .OpBitwiseXor); | ||
| 2680 | const is_positive_id = try self.cmp(.gt, Type.bool, ty, bin_bitwise_id, zero_id); | ||
| 2681 | |||
| 2682 | // a / b | ||
| 2683 | const positive_div_id = try self.arithOp(ty, lhs_id, rhs_id, .OpFDiv, .OpSDiv, .OpUDiv); | ||
| 2684 | |||
| 2685 | // - (abs(a) + abs(b) - 1) / abs(b) | ||
| 2686 | const lhs_abs = try self.abs(ty, ty, lhs_id); | ||
| 2687 | const rhs_abs = try self.abs(ty, ty, rhs_id); | ||
| 2688 | const negative_div_lhs = try self.arithOp( | ||
| 2689 | ty, | ||
| 2690 | try self.arithOp(ty, lhs_abs, rhs_abs, .OpFAdd, .OpIAdd, .OpIAdd), | ||
| 2691 | one_id, | ||
| 2692 | .OpFSub, | ||
| 2693 | .OpISub, | ||
| 2694 | .OpISub, | ||
| 2695 | ); | ||
| 2696 | const negative_div_id = try self.arithOp(ty, negative_div_lhs, rhs_abs, .OpFDiv, .OpSDiv, .OpUDiv); | ||
| 2697 | const negated_negative_div_id = self.spv.allocId(); | ||
| 2698 | try self.func.body.emit(self.spv.gpa, .OpSNegate, .{ | ||
| 2699 | .id_result_type = self.typeId(ty_ref), | ||
| 2700 | .id_result = negated_negative_div_id, | ||
| 2701 | .operand = negative_div_id, | ||
| 2702 | }); | ||
| 2703 | |||
| 2704 | const result_id = self.spv.allocId(); | ||
| 2705 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ | ||
| 2706 | .id_result_type = self.typeId(ty_ref), | ||
| 2707 | .id_result = result_id, | ||
| 2708 | .condition = is_positive_id, | ||
| 2709 | .object_1 = positive_div_id, | ||
| 2710 | .object_2 = negated_negative_div_id, | ||
| 2711 | }); | ||
| 2712 | return result_id; | ||
| 2713 | }, | ||
| 2714 | .float => { | ||
| 2715 | const div_id = try self.arithOp(ty, lhs_id, rhs_id, .OpFDiv, .OpSDiv, .OpUDiv); | ||
| 2716 | return try self.floor(ty, div_id); | ||
| 2717 | }, | ||
| 2718 | .bool => unreachable, | ||
| 2719 | } | ||
| 2720 | } | ||
| 2721 | |||
| 2722 | fn airFloor(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | ||
| 2723 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; | ||
| 2724 | const operand_id = try self.resolve(un_op); | ||
| 2725 | const result_ty = self.typeOfIndex(inst); | ||
| 2726 | return try self.floor(result_ty, operand_id); | ||
| 2727 | } | ||
| 2728 | |||
| 2729 | fn floor(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef { | ||
| 2730 | const target = self.getTarget(); | ||
| 2731 | const ty_ref = try self.resolveType(ty, .direct); | ||
| 2732 | const ext_inst: Word = switch (target.os.tag) { | ||
| 2733 | .opencl => 25, | ||
| 2734 | .vulkan => 8, | ||
| 2735 | else => unreachable, | ||
| 2736 | }; | ||
| 2737 | const set_id = switch (target.os.tag) { | ||
| 2738 | .opencl => try self.spv.importInstructionSet(.@"OpenCL.std"), | ||
| 2739 | .vulkan => try self.spv.importInstructionSet(.@"GLSL.std.450"), | ||
| 2740 | else => unreachable, | ||
| 2741 | }; | ||
| 2742 | |||
| 2743 | const result_id = self.spv.allocId(); | ||
| 2744 | try self.func.body.emit(self.spv.gpa, .OpExtInst, .{ | ||
| 2745 | .id_result_type = self.typeId(ty_ref), | ||
| 2746 | .id_result = result_id, | ||
| 2747 | .set = set_id, | ||
| 2748 | .instruction = .{ .inst = ext_inst }, | ||
| 2749 | .id_ref_4 = &.{operand_id}, | ||
| 2750 | }); | ||
| 2751 | return result_id; | ||
| 2752 | } | ||
| 2753 | |||
| 2664 | fn airArithOp( | 2754 | fn airArithOp( |
| 2665 | self: *DeclGen, | 2755 | self: *DeclGen, |
| 2666 | inst: Air.Inst.Index, | 2756 | inst: Air.Inst.Index, |
| ... | @@ -2668,7 +2758,6 @@ const DeclGen = struct { | ... | @@ -2668,7 +2758,6 @@ const DeclGen = struct { |
| 2668 | comptime sop: Opcode, | 2758 | comptime sop: Opcode, |
| 2669 | comptime uop: Opcode, | 2759 | comptime uop: Opcode, |
| 2670 | ) !?IdRef { | 2760 | ) !?IdRef { |
| 2671 | |||
| 2672 | // LHS and RHS are guaranteed to have the same type, and AIR guarantees | 2761 | // LHS and RHS are guaranteed to have the same type, and AIR guarantees |
| 2673 | // the result to be the same as the LHS and RHS, which matches SPIR-V. | 2762 | // the result to be the same as the LHS and RHS, which matches SPIR-V. |
| 2674 | const ty = self.typeOfIndex(inst); | 2763 | const ty = self.typeOfIndex(inst); |
| ... | @@ -2700,8 +2789,8 @@ const DeclGen = struct { | ... | @@ -2700,8 +2789,8 @@ const DeclGen = struct { |
| 2700 | return self.todo("binary operations for composite integers", .{}); | 2789 | return self.todo("binary operations for composite integers", .{}); |
| 2701 | }, | 2790 | }, |
| 2702 | .integer, .strange_integer => switch (info.signedness) { | 2791 | .integer, .strange_integer => switch (info.signedness) { |
| 2703 | .signed => @as(usize, 1), | 2792 | .signed => 1, |
| 2704 | .unsigned => @as(usize, 2), | 2793 | .unsigned => 2, |
| 2705 | }, | 2794 | }, |
| 2706 | .float => 0, | 2795 | .float => 0, |
| 2707 | .bool => unreachable, | 2796 | .bool => unreachable, |
| ... | @@ -2737,12 +2826,16 @@ const DeclGen = struct { | ... | @@ -2737,12 +2826,16 @@ const DeclGen = struct { |
| 2737 | } | 2826 | } |
| 2738 | 2827 | ||
| 2739 | fn airAbs(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2828 | fn airAbs(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2740 | const target = self.getTarget(); | ||
| 2741 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 2829 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 2742 | const operand_id = try self.resolve(ty_op.operand); | 2830 | const operand_id = try self.resolve(ty_op.operand); |
| 2743 | // Note: operand_ty may be signed, while ty is always unsigned! | 2831 | // Note: operand_ty may be signed, while ty is always unsigned! |
| 2744 | const operand_ty = self.typeOf(ty_op.operand); | 2832 | const operand_ty = self.typeOf(ty_op.operand); |
| 2745 | const result_ty = self.typeOfIndex(inst); | 2833 | const result_ty = self.typeOfIndex(inst); |
| 2834 | return try self.abs(result_ty, operand_ty, operand_id); | ||
| 2835 | } | ||
| 2836 | |||
| 2837 | fn abs(self: *DeclGen, result_ty: Type, operand_ty: Type, operand_id: IdRef) !IdRef { | ||
| 2838 | const target = self.getTarget(); | ||
| 2746 | const operand_info = self.arithmeticTypeInfo(operand_ty); | 2839 | const operand_info = self.arithmeticTypeInfo(operand_ty); |
| 2747 | 2840 | ||
| 2748 | var wip = try self.elementWise(result_ty, false); | 2841 | var wip = try self.elementWise(result_ty, false); |
| ... | @@ -2907,6 +3000,61 @@ const DeclGen = struct { | ... | @@ -2907,6 +3000,61 @@ const DeclGen = struct { |
| 2907 | ); | 3000 | ); |
| 2908 | } | 3001 | } |
| 2909 | 3002 | ||
| 3003 | fn airMulOverflow(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | ||
| 3004 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | ||
| 3005 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | ||
| 3006 | const lhs = try self.resolve(extra.lhs); | ||
| 3007 | const rhs = try self.resolve(extra.rhs); | ||
| 3008 | |||
| 3009 | const result_ty = self.typeOfIndex(inst); | ||
| 3010 | const operand_ty = self.typeOf(extra.lhs); | ||
| 3011 | const ov_ty = result_ty.structFieldType(1, self.module); | ||
| 3012 | |||
| 3013 | const info = self.arithmeticTypeInfo(operand_ty); | ||
| 3014 | switch (info.class) { | ||
| 3015 | .composite_integer => return self.todo("overflow ops for composite integers", .{}), | ||
| 3016 | .strange_integer, .integer => {}, | ||
| 3017 | .float, .bool => unreachable, | ||
| 3018 | } | ||
| 3019 | |||
| 3020 | var wip_result = try self.elementWise(operand_ty, true); | ||
| 3021 | defer wip_result.deinit(); | ||
| 3022 | var wip_ov = try self.elementWise(ov_ty, true); | ||
| 3023 | defer wip_ov.deinit(); | ||
| 3024 | |||
| 3025 | const zero_id = try self.constInt(wip_result.ty_ref, 0); | ||
| 3026 | const zero_ov_id = try self.constInt(wip_ov.ty_ref, 0); | ||
| 3027 | const one_ov_id = try self.constInt(wip_ov.ty_ref, 1); | ||
| 3028 | |||
| 3029 | for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| { | ||
| 3030 | const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i); | ||
| 3031 | const rhs_elem_id = try wip_result.elementAt(operand_ty, rhs, i); | ||
| 3032 | |||
| 3033 | result_id.* = try self.arithOp(wip_result.ty, lhs_elem_id, rhs_elem_id, .OpFMul, .OpIMul, .OpIMul); | ||
| 3034 | |||
| 3035 | // (a != 0) and (x / a != b) | ||
| 3036 | const not_zero_id = try self.cmp(.neq, Type.bool, wip_result.ty, lhs_elem_id, zero_id); | ||
| 3037 | const res_rhs_id = try self.arithOp(wip_result.ty, result_id.*, lhs_elem_id, .OpFDiv, .OpSDiv, .OpUDiv); | ||
| 3038 | const res_rhs_not_rhs_id = try self.cmp(.neq, Type.bool, wip_result.ty, res_rhs_id, rhs_elem_id); | ||
| 3039 | const cond_id = try self.binOpSimple(Type.bool, not_zero_id, res_rhs_not_rhs_id, .OpLogicalAnd); | ||
| 3040 | |||
| 3041 | ov_id.* = self.spv.allocId(); | ||
| 3042 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ | ||
| 3043 | .id_result_type = wip_ov.ty_id, | ||
| 3044 | .id_result = ov_id.*, | ||
| 3045 | .condition = cond_id, | ||
| 3046 | .object_1 = one_ov_id, | ||
| 3047 | .object_2 = zero_ov_id, | ||
| 3048 | }); | ||
| 3049 | } | ||
| 3050 | |||
| 3051 | return try self.constructStruct( | ||
| 3052 | result_ty, | ||
| 3053 | &.{ operand_ty, ov_ty }, | ||
| 3054 | &.{ try wip_result.finalize(), try wip_ov.finalize() }, | ||
| 3055 | ); | ||
| 3056 | } | ||
| 3057 | |||
| 2910 | fn airShlOverflow(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3058 | fn airShlOverflow(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2911 | const mod = self.module; | 3059 | const mod = self.module; |
| 2912 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 3060 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | @@ -3692,19 +3840,22 @@ const DeclGen = struct { | ... | @@ -3692,19 +3840,22 @@ const DeclGen = struct { |
| 3692 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3840 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3693 | const operand_ty = self.typeOf(ty_op.operand); | 3841 | const operand_ty = self.typeOf(ty_op.operand); |
| 3694 | const operand_id = try self.resolve(ty_op.operand); | 3842 | const operand_id = try self.resolve(ty_op.operand); |
| 3695 | const operand_info = self.arithmeticTypeInfo(operand_ty); | 3843 | const result_ty = self.typeOfIndex(inst); |
| 3696 | const dest_ty = self.typeOfIndex(inst); | 3844 | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 3697 | const dest_ty_id = try self.resolveTypeId(dest_ty); | 3845 | return try self.floatFromInt(result_ty_ref, operand_ty, operand_id); |
| 3846 | } | ||
| 3698 | 3847 | ||
| 3848 | fn floatFromInt(self: *DeclGen, result_ty_ref: CacheRef, operand_ty: Type, operand_id: IdRef) !IdRef { | ||
| 3849 | const operand_info = self.arithmeticTypeInfo(operand_ty); | ||
| 3699 | const result_id = self.spv.allocId(); | 3850 | const result_id = self.spv.allocId(); |
| 3700 | switch (operand_info.signedness) { | 3851 | switch (operand_info.signedness) { |
| 3701 | .signed => try self.func.body.emit(self.spv.gpa, .OpConvertSToF, .{ | 3852 | .signed => try self.func.body.emit(self.spv.gpa, .OpConvertSToF, .{ |
| 3702 | .id_result_type = dest_ty_id, | 3853 | .id_result_type = self.typeId(result_ty_ref), |
| 3703 | .id_result = result_id, | 3854 | .id_result = result_id, |
| 3704 | .signed_value = operand_id, | 3855 | .signed_value = operand_id, |
| 3705 | }), | 3856 | }), |
| 3706 | .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertUToF, .{ | 3857 | .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertUToF, .{ |
| 3707 | .id_result_type = dest_ty_id, | 3858 | .id_result_type = self.typeId(result_ty_ref), |
| 3708 | .id_result = result_id, | 3859 | .id_result = result_id, |
| 3709 | .unsigned_value = operand_id, | 3860 | .unsigned_value = operand_id, |
| 3710 | }), | 3861 | }), |
| ... | @@ -3715,19 +3866,22 @@ const DeclGen = struct { | ... | @@ -3715,19 +3866,22 @@ const DeclGen = struct { |
| 3715 | fn airIntFromFloat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3866 | fn airIntFromFloat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3716 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3867 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3717 | const operand_id = try self.resolve(ty_op.operand); | 3868 | const operand_id = try self.resolve(ty_op.operand); |
| 3718 | const dest_ty = self.typeOfIndex(inst); | 3869 | const result_ty = self.typeOfIndex(inst); |
| 3719 | const dest_info = self.arithmeticTypeInfo(dest_ty); | 3870 | return try self.intFromFloat(result_ty, operand_id); |
| 3720 | const dest_ty_id = try self.resolveTypeId(dest_ty); | 3871 | } |
| 3721 | 3872 | ||
| 3873 | fn intFromFloat(self: *DeclGen, result_ty: Type, operand_id: IdRef) !IdRef { | ||
| 3874 | const result_info = self.arithmeticTypeInfo(result_ty); | ||
| 3875 | const result_ty_ref = try self.resolveType(result_ty, .direct); | ||
| 3722 | const result_id = self.spv.allocId(); | 3876 | const result_id = self.spv.allocId(); |
| 3723 | switch (dest_info.signedness) { | 3877 | switch (result_info.signedness) { |
| 3724 | .signed => try self.func.body.emit(self.spv.gpa, .OpConvertFToS, .{ | 3878 | .signed => try self.func.body.emit(self.spv.gpa, .OpConvertFToS, .{ |
| 3725 | .id_result_type = dest_ty_id, | 3879 | .id_result_type = self.typeId(result_ty_ref), |
| 3726 | .id_result = result_id, | 3880 | .id_result = result_id, |
| 3727 | .float_value = operand_id, | 3881 | .float_value = operand_id, |
| 3728 | }), | 3882 | }), |
| 3729 | .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertFToU, .{ | 3883 | .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertFToU, .{ |
| 3730 | .id_result_type = dest_ty_id, | 3884 | .id_result_type = self.typeId(result_ty_ref), |
| 3731 | .id_result = result_id, | 3885 | .id_result = result_id, |
| 3732 | .float_value = operand_id, | 3886 | .float_value = operand_id, |
| 3733 | }), | 3887 | }), |
| ... | @@ -5237,20 +5391,21 @@ const DeclGen = struct { | ... | @@ -5237,20 +5391,21 @@ const DeclGen = struct { |
| 5237 | 5391 | ||
| 5238 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { | 5392 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 5239 | const mod = self.module; | 5393 | const mod = self.module; |
| 5394 | const target = self.getTarget(); | ||
| 5240 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; | 5395 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 5241 | const cond_ty = self.typeOf(pl_op.operand); | 5396 | const cond_ty = self.typeOf(pl_op.operand); |
| 5242 | const cond = try self.resolve(pl_op.operand); | 5397 | const cond = try self.resolve(pl_op.operand); |
| 5243 | const cond_indirect = try self.convertToIndirect(cond_ty, cond); | 5398 | var cond_indirect = try self.convertToIndirect(cond_ty, cond); |
| 5244 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); | 5399 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 5245 | 5400 | ||
| 5246 | const cond_words: u32 = switch (cond_ty.zigTypeTag(mod)) { | 5401 | const cond_words: u32 = switch (cond_ty.zigTypeTag(mod)) { |
| 5247 | .Bool => 1, | 5402 | .Bool, .ErrorSet => 1, |
| 5248 | .Int => blk: { | 5403 | .Int => blk: { |
| 5249 | const bits = cond_ty.intInfo(mod).bits; | 5404 | const bits = cond_ty.intInfo(mod).bits; |
| 5250 | const backing_bits = self.backingIntBits(bits) orelse { | 5405 | const backing_bits = self.backingIntBits(bits) orelse { |
| 5251 | return self.todo("implement composite int switch", .{}); | 5406 | return self.todo("implement composite int switch", .{}); |
| 5252 | }; | 5407 | }; |
| 5253 | break :blk if (backing_bits <= 32) @as(u32, 1) else 2; | 5408 | break :blk if (backing_bits <= 32) 1 else 2; |
| 5254 | }, | 5409 | }, |
| 5255 | .Enum => blk: { | 5410 | .Enum => blk: { |
| 5256 | const int_ty = cond_ty.intTagType(mod); | 5411 | const int_ty = cond_ty.intTagType(mod); |
| ... | @@ -5258,10 +5413,14 @@ const DeclGen = struct { | ... | @@ -5258,10 +5413,14 @@ const DeclGen = struct { |
| 5258 | const backing_bits = self.backingIntBits(int_info.bits) orelse { | 5413 | const backing_bits = self.backingIntBits(int_info.bits) orelse { |
| 5259 | return self.todo("implement composite int switch", .{}); | 5414 | return self.todo("implement composite int switch", .{}); |
| 5260 | }; | 5415 | }; |
| 5261 | break :blk if (backing_bits <= 32) @as(u32, 1) else 2; | 5416 | break :blk if (backing_bits <= 32) 1 else 2; |
| 5417 | }, | ||
| 5418 | .Pointer => blk: { | ||
| 5419 | cond_indirect = try self.intFromPtr(cond_indirect); | ||
| 5420 | break :blk target.ptrBitWidth() / 32; | ||
| 5262 | }, | 5421 | }, |
| 5263 | .ErrorSet => 1, | 5422 | // TODO: Figure out which types apply here, and work around them as we can only do integers. |
| 5264 | else => return self.todo("implement switch for type {s}", .{@tagName(cond_ty.zigTypeTag(mod))}), // TODO: Figure out which types apply here, and work around them as we can only do integers. | 5423 | else => return self.todo("implement switch for type {s}", .{@tagName(cond_ty.zigTypeTag(mod))}), |
| 5265 | }; | 5424 | }; |
| 5266 | 5425 | ||
| 5267 | const num_cases = switch_br.data.cases_len; | 5426 | const num_cases = switch_br.data.cases_len; |
| ... | @@ -5308,7 +5467,7 @@ const DeclGen = struct { | ... | @@ -5308,7 +5467,7 @@ const DeclGen = struct { |
| 5308 | for (0..num_cases) |case_i| { | 5467 | for (0..num_cases) |case_i| { |
| 5309 | // SPIR-V needs a literal here, which' width depends on the case condition. | 5468 | // SPIR-V needs a literal here, which' width depends on the case condition. |
| 5310 | const case = self.air.extraData(Air.SwitchBr.Case, extra_index); | 5469 | const case = self.air.extraData(Air.SwitchBr.Case, extra_index); |
| 5311 | const items = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[case.end..][0..case.data.items_len])); | 5470 | const items: []const Air.Inst.Ref = @ptrCast(self.air.extra[case.end..][0..case.data.items_len]); |
| 5312 | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; | 5471 | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; |
| 5313 | extra_index = case.end + case.data.items_len + case_body.len; | 5472 | extra_index = case.end + case.data.items_len + case_body.len; |
| 5314 | 5473 | ||
| ... | @@ -5316,13 +5475,14 @@ const DeclGen = struct { | ... | @@ -5316,13 +5475,14 @@ const DeclGen = struct { |
| 5316 | 5475 | ||
| 5317 | for (items) |item| { | 5476 | for (items) |item| { |
| 5318 | const value = (try self.air.value(item, mod)) orelse unreachable; | 5477 | const value = (try self.air.value(item, mod)) orelse unreachable; |
| 5319 | const int_val = switch (cond_ty.zigTypeTag(mod)) { | 5478 | const int_val: u64 = switch (cond_ty.zigTypeTag(mod)) { |
| 5320 | .Bool, .Int => if (cond_ty.isSignedInt(mod)) @as(u64, @bitCast(value.toSignedInt(mod))) else value.toUnsignedInt(mod), | 5479 | .Bool, .Int => if (cond_ty.isSignedInt(mod)) @bitCast(value.toSignedInt(mod)) else value.toUnsignedInt(mod), |
| 5321 | .Enum => blk: { | 5480 | .Enum => blk: { |
| 5322 | // TODO: figure out of cond_ty is correct (something with enum literals) | 5481 | // TODO: figure out of cond_ty is correct (something with enum literals) |
| 5323 | break :blk (try value.intFromEnum(cond_ty, mod)).toUnsignedInt(mod); // TODO: composite integer constants | 5482 | break :blk (try value.intFromEnum(cond_ty, mod)).toUnsignedInt(mod); // TODO: composite integer constants |
| 5324 | }, | 5483 | }, |
| 5325 | .ErrorSet => value.getErrorInt(mod), | 5484 | .ErrorSet => value.getErrorInt(mod), |
| 5485 | .Pointer => value.toUnsignedInt(mod), | ||
| 5326 | else => unreachable, | 5486 | else => unreachable, |
| 5327 | }; | 5487 | }; |
| 5328 | const int_lit: spec.LiteralContextDependentNumber = switch (cond_words) { | 5488 | const int_lit: spec.LiteralContextDependentNumber = switch (cond_words) { |
| ... | @@ -5438,14 +5598,14 @@ const DeclGen = struct { | ... | @@ -5438,14 +5598,14 @@ const DeclGen = struct { |
| 5438 | const extra = self.air.extraData(Air.Asm, ty_pl.payload); | 5598 | const extra = self.air.extraData(Air.Asm, ty_pl.payload); |
| 5439 | 5599 | ||
| 5440 | const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0; | 5600 | const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0; |
| 5441 | const clobbers_len = @as(u31, @truncate(extra.data.flags)); | 5601 | const clobbers_len: u31 = @truncate(extra.data.flags); |
| 5442 | 5602 | ||
| 5443 | if (!is_volatile and self.liveness.isUnused(inst)) return null; | 5603 | if (!is_volatile and self.liveness.isUnused(inst)) return null; |
| 5444 | 5604 | ||
| 5445 | var extra_i: usize = extra.end; | 5605 | var extra_i: usize = extra.end; |
| 5446 | const outputs = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[extra_i..][0..extra.data.outputs_len])); | 5606 | const outputs: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra_i..][0..extra.data.outputs_len]); |
| 5447 | extra_i += outputs.len; | 5607 | extra_i += outputs.len; |
| 5448 | const inputs = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[extra_i..][0..extra.data.inputs_len])); | 5608 | const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra_i..][0..extra.data.inputs_len]); |
| 5449 | extra_i += inputs.len; | 5609 | extra_i += inputs.len; |
| 5450 | 5610 | ||
| 5451 | if (outputs.len > 1) { | 5611 | if (outputs.len > 1) { |
| ... | @@ -5567,7 +5727,7 @@ const DeclGen = struct { | ... | @@ -5567,7 +5727,7 @@ const DeclGen = struct { |
| 5567 | const mod = self.module; | 5727 | const mod = self.module; |
| 5568 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; | 5728 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 5569 | const extra = self.air.extraData(Air.Call, pl_op.payload); | 5729 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 5570 | const args = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len])); | 5730 | const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]); |
| 5571 | const callee_ty = self.typeOf(pl_op.operand); | 5731 | const callee_ty = self.typeOf(pl_op.operand); |
| 5572 | const zig_fn_ty = switch (callee_ty.zigTypeTag(mod)) { | 5732 | const zig_fn_ty = switch (callee_ty.zigTypeTag(mod)) { |
| 5573 | .Fn => callee_ty, | 5733 | .Fn => callee_ty, |
src/codegen/spirv/Assembler.zig+29-9| ... | @@ -256,10 +256,18 @@ fn todo(self: *Assembler, comptime fmt: []const u8, args: anytype) Error { | ... | @@ -256,10 +256,18 @@ fn todo(self: *Assembler, comptime fmt: []const u8, args: anytype) Error { |
| 256 | /// If this function returns `error.AssembleFail`, an explanatory | 256 | /// If this function returns `error.AssembleFail`, an explanatory |
| 257 | /// error message has already been emitted into `self.errors`. | 257 | /// error message has already been emitted into `self.errors`. |
| 258 | fn processInstruction(self: *Assembler) !void { | 258 | fn processInstruction(self: *Assembler) !void { |
| 259 | const result = switch (self.inst.opcode) { | 259 | const result: AsmValue = switch (self.inst.opcode) { |
| 260 | .OpEntryPoint => { | 260 | .OpEntryPoint => { |
| 261 | return self.fail(0, "cannot export entry points via OpEntryPoint, export the kernel using callconv(.Kernel)", .{}); | 261 | return self.fail(0, "cannot export entry points via OpEntryPoint, export the kernel using callconv(.Kernel)", .{}); |
| 262 | }, | 262 | }, |
| 263 | .OpExtInstImport => blk: { | ||
| 264 | const set_name_offset = self.inst.operands.items[1].string; | ||
| 265 | const set_name = std.mem.sliceTo(self.inst.string_bytes.items[set_name_offset..], 0); | ||
| 266 | const set_tag = std.meta.stringToEnum(spec.InstructionSet, set_name) orelse { | ||
| 267 | return self.fail(set_name_offset, "unknown instruction set: {s}", .{set_name}); | ||
| 268 | }; | ||
| 269 | break :blk .{ .value = try self.spv.importInstructionSet(set_tag) }; | ||
| 270 | }, | ||
| 263 | else => switch (self.inst.opcode.class()) { | 271 | else => switch (self.inst.opcode.class()) { |
| 264 | .TypeDeclaration => try self.processTypeInstruction(), | 272 | .TypeDeclaration => try self.processTypeInstruction(), |
| 265 | else => if (try self.processGenericInstruction()) |result| | 273 | else => if (try self.processGenericInstruction()) |result| |
| ... | @@ -309,7 +317,7 @@ fn processTypeInstruction(self: *Assembler) !AsmValue { | ... | @@ -309,7 +317,7 @@ fn processTypeInstruction(self: *Assembler) !AsmValue { |
| 309 | return self.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits}); | 317 | return self.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits}); |
| 310 | }, | 318 | }, |
| 311 | } | 319 | } |
| 312 | break :blk try self.spv.resolve(.{ .float_type = .{ .bits = @as(u16, @intCast(bits)) } }); | 320 | break :blk try self.spv.resolve(.{ .float_type = .{ .bits = @intCast(bits) } }); |
| 313 | }, | 321 | }, |
| 314 | .OpTypeVector => try self.spv.resolve(.{ .vector_type = .{ | 322 | .OpTypeVector => try self.spv.resolve(.{ .vector_type = .{ |
| 315 | .component_type = try self.resolveTypeRef(operands[1].ref_id), | 323 | .component_type = try self.resolveTypeRef(operands[1].ref_id), |
| ... | @@ -364,6 +372,7 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue { | ... | @@ -364,6 +372,7 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue { |
| 364 | .OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes, | 372 | .OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes, |
| 365 | .OpVariable => switch (@as(spec.StorageClass, @enumFromInt(operands[2].value))) { | 373 | .OpVariable => switch (@as(spec.StorageClass, @enumFromInt(operands[2].value))) { |
| 366 | .Function => &self.func.prologue, | 374 | .Function => &self.func.prologue, |
| 375 | .UniformConstant => &self.spv.sections.types_globals_constants, | ||
| 367 | else => { | 376 | else => { |
| 368 | // This is currently disabled because global variables are required to be | 377 | // This is currently disabled because global variables are required to be |
| 369 | // emitted in the proper order, and this should be honored in inline assembly | 378 | // emitted in the proper order, and this should be honored in inline assembly |
| ... | @@ -473,14 +482,14 @@ fn parseInstruction(self: *Assembler) !void { | ... | @@ -473,14 +482,14 @@ fn parseInstruction(self: *Assembler) !void { |
| 473 | self.inst.string_bytes.shrinkRetainingCapacity(0); | 482 | self.inst.string_bytes.shrinkRetainingCapacity(0); |
| 474 | 483 | ||
| 475 | const lhs_result_tok = self.currentToken(); | 484 | const lhs_result_tok = self.currentToken(); |
| 476 | const maybe_lhs_result = if (self.eatToken(.result_id_assign)) blk: { | 485 | const maybe_lhs_result: ?AsmValue.Ref = if (self.eatToken(.result_id_assign)) blk: { |
| 477 | const name = self.tokenText(lhs_result_tok)[1..]; | 486 | const name = self.tokenText(lhs_result_tok)[1..]; |
| 478 | const entry = try self.value_map.getOrPut(self.gpa, name); | 487 | const entry = try self.value_map.getOrPut(self.gpa, name); |
| 479 | try self.expectToken(.equals); | 488 | try self.expectToken(.equals); |
| 480 | if (!entry.found_existing) { | 489 | if (!entry.found_existing) { |
| 481 | entry.value_ptr.* = .just_declared; | 490 | entry.value_ptr.* = .just_declared; |
| 482 | } | 491 | } |
| 483 | break :blk @as(AsmValue.Ref, @intCast(entry.index)); | 492 | break :blk @intCast(entry.index); |
| 484 | } else null; | 493 | } else null; |
| 485 | 494 | ||
| 486 | const opcode_tok = self.currentToken(); | 495 | const opcode_tok = self.currentToken(); |
| ... | @@ -550,6 +559,7 @@ fn parseOperand(self: *Assembler, kind: spec.OperandKind) Error!void { | ... | @@ -550,6 +559,7 @@ fn parseOperand(self: *Assembler, kind: spec.OperandKind) Error!void { |
| 550 | .LiteralInteger => try self.parseLiteralInteger(), | 559 | .LiteralInteger => try self.parseLiteralInteger(), |
| 551 | .LiteralString => try self.parseString(), | 560 | .LiteralString => try self.parseString(), |
| 552 | .LiteralContextDependentNumber => try self.parseContextDependentNumber(), | 561 | .LiteralContextDependentNumber => try self.parseContextDependentNumber(), |
| 562 | .LiteralExtInstInteger => try self.parseLiteralExtInstInteger(), | ||
| 553 | .PairIdRefIdRef => try self.parsePhiSource(), | 563 | .PairIdRefIdRef => try self.parsePhiSource(), |
| 554 | else => return self.todo("parse operand of type {s}", .{@tagName(kind)}), | 564 | else => return self.todo("parse operand of type {s}", .{@tagName(kind)}), |
| 555 | }, | 565 | }, |
| ... | @@ -641,7 +651,7 @@ fn parseRefId(self: *Assembler) !void { | ... | @@ -641,7 +651,7 @@ fn parseRefId(self: *Assembler) !void { |
| 641 | entry.value_ptr.* = .unresolved_forward_reference; | 651 | entry.value_ptr.* = .unresolved_forward_reference; |
| 642 | } | 652 | } |
| 643 | 653 | ||
| 644 | const index = @as(AsmValue.Ref, @intCast(entry.index)); | 654 | const index: AsmValue.Ref = @intCast(entry.index); |
| 645 | try self.inst.operands.append(self.gpa, .{ .ref_id = index }); | 655 | try self.inst.operands.append(self.gpa, .{ .ref_id = index }); |
| 646 | } | 656 | } |
| 647 | 657 | ||
| ... | @@ -660,6 +670,16 @@ fn parseLiteralInteger(self: *Assembler) !void { | ... | @@ -660,6 +670,16 @@ fn parseLiteralInteger(self: *Assembler) !void { |
| 660 | try self.inst.operands.append(self.gpa, .{ .literal32 = value }); | 670 | try self.inst.operands.append(self.gpa, .{ .literal32 = value }); |
| 661 | } | 671 | } |
| 662 | 672 | ||
| 673 | fn parseLiteralExtInstInteger(self: *Assembler) !void { | ||
| 674 | const tok = self.currentToken(); | ||
| 675 | try self.expectToken(.value); | ||
| 676 | const text = self.tokenText(tok); | ||
| 677 | const value = std.fmt.parseInt(u32, text, 0) catch { | ||
| 678 | return self.fail(tok.start, "'{s}' is not a valid 32-bit integer literal", .{text}); | ||
| 679 | }; | ||
| 680 | try self.inst.operands.append(self.gpa, .{ .literal32 = value }); | ||
| 681 | } | ||
| 682 | |||
| 663 | fn parseString(self: *Assembler) !void { | 683 | fn parseString(self: *Assembler) !void { |
| 664 | const tok = self.currentToken(); | 684 | const tok = self.currentToken(); |
| 665 | try self.expectToken(.string); | 685 | try self.expectToken(.string); |
| ... | @@ -673,7 +693,7 @@ fn parseString(self: *Assembler) !void { | ... | @@ -673,7 +693,7 @@ fn parseString(self: *Assembler) !void { |
| 673 | else | 693 | else |
| 674 | text[1..]; | 694 | text[1..]; |
| 675 | 695 | ||
| 676 | const string_offset = @as(u32, @intCast(self.inst.string_bytes.items.len)); | 696 | const string_offset: u32 = @intCast(self.inst.string_bytes.items.len); |
| 677 | try self.inst.string_bytes.ensureUnusedCapacity(self.gpa, literal.len + 1); | 697 | try self.inst.string_bytes.ensureUnusedCapacity(self.gpa, literal.len + 1); |
| 678 | self.inst.string_bytes.appendSliceAssumeCapacity(literal); | 698 | self.inst.string_bytes.appendSliceAssumeCapacity(literal); |
| 679 | self.inst.string_bytes.appendAssumeCapacity(0); | 699 | self.inst.string_bytes.appendAssumeCapacity(0); |
| ... | @@ -730,9 +750,9 @@ fn parseContextDependentInt(self: *Assembler, signedness: std.builtin.Signedness | ... | @@ -730,9 +750,9 @@ fn parseContextDependentInt(self: *Assembler, signedness: std.builtin.Signedness |
| 730 | 750 | ||
| 731 | // Note, we store the sign-extended version here. | 751 | // Note, we store the sign-extended version here. |
| 732 | if (width <= @bitSizeOf(spec.Word)) { | 752 | if (width <= @bitSizeOf(spec.Word)) { |
| 733 | try self.inst.operands.append(self.gpa, .{ .literal32 = @as(u32, @truncate(@as(u128, @bitCast(int)))) }); | 753 | try self.inst.operands.append(self.gpa, .{ .literal32 = @truncate(@as(u128, @bitCast(int))) }); |
| 734 | } else { | 754 | } else { |
| 735 | try self.inst.operands.append(self.gpa, .{ .literal64 = @as(u64, @truncate(@as(u128, @bitCast(int)))) }); | 755 | try self.inst.operands.append(self.gpa, .{ .literal64 = @truncate(@as(u128, @bitCast(int))) }); |
| 736 | } | 756 | } |
| 737 | return; | 757 | return; |
| 738 | } | 758 | } |
| ... | @@ -753,7 +773,7 @@ fn parseContextDependentFloat(self: *Assembler, comptime width: u16) !void { | ... | @@ -753,7 +773,7 @@ fn parseContextDependentFloat(self: *Assembler, comptime width: u16) !void { |
| 753 | return self.fail(tok.start, "'{s}' is not a valid {}-bit float literal", .{ text, width }); | 773 | return self.fail(tok.start, "'{s}' is not a valid {}-bit float literal", .{ text, width }); |
| 754 | }; | 774 | }; |
| 755 | 775 | ||
| 756 | const float_bits = @as(Int, @bitCast(value)); | 776 | const float_bits: Int = @bitCast(value); |
| 757 | if (width <= @bitSizeOf(spec.Word)) { | 777 | if (width <= @bitSizeOf(spec.Word)) { |
| 758 | try self.inst.operands.append(self.gpa, .{ .literal32 = float_bits }); | 778 | try self.inst.operands.append(self.gpa, .{ .literal32 = float_bits }); |
| 759 | } else { | 779 | } else { |
src/codegen/spirv/Module.zig+4-4| ... | @@ -429,8 +429,8 @@ pub fn constInt(self: *Module, ty_ref: CacheRef, value: anytype) !IdRef { | ... | @@ -429,8 +429,8 @@ pub fn constInt(self: *Module, ty_ref: CacheRef, value: anytype) !IdRef { |
| 429 | return try self.resolveId(.{ .int = .{ | 429 | return try self.resolveId(.{ .int = .{ |
| 430 | .ty = ty_ref, | 430 | .ty = ty_ref, |
| 431 | .value = switch (ty.signedness) { | 431 | .value = switch (ty.signedness) { |
| 432 | .signed => Value{ .int64 = @as(i64, @intCast(value)) }, | 432 | .signed => Value{ .int64 = @intCast(value) }, |
| 433 | .unsigned => Value{ .uint64 = @as(u64, @intCast(value)) }, | 433 | .unsigned => Value{ .uint64 = @intCast(value) }, |
| 434 | }, | 434 | }, |
| 435 | } }); | 435 | } }); |
| 436 | } | 436 | } |
| ... | @@ -500,9 +500,9 @@ pub fn declPtr(self: *Module, index: Decl.Index) *Decl { | ... | @@ -500,9 +500,9 @@ pub fn declPtr(self: *Module, index: Decl.Index) *Decl { |
| 500 | 500 | ||
| 501 | /// Declare ALL dependencies for a decl. | 501 | /// Declare ALL dependencies for a decl. |
| 502 | pub fn declareDeclDeps(self: *Module, decl_index: Decl.Index, deps: []const Decl.Index) !void { | 502 | pub fn declareDeclDeps(self: *Module, decl_index: Decl.Index, deps: []const Decl.Index) !void { |
| 503 | const begin_dep = @as(u32, @intCast(self.decl_deps.items.len)); | 503 | const begin_dep: u32 = @intCast(self.decl_deps.items.len); |
| 504 | try self.decl_deps.appendSlice(self.gpa, deps); | 504 | try self.decl_deps.appendSlice(self.gpa, deps); |
| 505 | const end_dep = @as(u32, @intCast(self.decl_deps.items.len)); | 505 | const end_dep: u32 = @intCast(self.decl_deps.items.len); |
| 506 | 506 | ||
| 507 | const decl = self.declPtr(decl_index); | 507 | const decl = self.declPtr(decl_index); |
| 508 | decl.begin_dep = begin_dep; | 508 | decl.begin_dep = begin_dep; |
src/codegen/spirv/Section.zig+10-10| ... | @@ -115,8 +115,8 @@ pub fn writeWords(section: *Section, words: []const Word) void { | ... | @@ -115,8 +115,8 @@ pub fn writeWords(section: *Section, words: []const Word) void { |
| 115 | 115 | ||
| 116 | pub fn writeDoubleWord(section: *Section, dword: DoubleWord) void { | 116 | pub fn writeDoubleWord(section: *Section, dword: DoubleWord) void { |
| 117 | section.writeWords(&.{ | 117 | section.writeWords(&.{ |
| 118 | @as(Word, @truncate(dword)), | 118 | @truncate(dword), |
| 119 | @as(Word, @truncate(dword >> @bitSizeOf(Word))), | 119 | @truncate(dword >> @bitSizeOf(Word)), |
| 120 | }); | 120 | }); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| ... | @@ -196,12 +196,12 @@ fn writeString(section: *Section, str: []const u8) void { | ... | @@ -196,12 +196,12 @@ fn writeString(section: *Section, str: []const u8) void { |
| 196 | 196 | ||
| 197 | fn writeContextDependentNumber(section: *Section, operand: spec.LiteralContextDependentNumber) void { | 197 | fn writeContextDependentNumber(section: *Section, operand: spec.LiteralContextDependentNumber) void { |
| 198 | switch (operand) { | 198 | switch (operand) { |
| 199 | .int32 => |int| section.writeWord(@as(Word, @bitCast(int))), | 199 | .int32 => |int| section.writeWord(@bitCast(int)), |
| 200 | .uint32 => |int| section.writeWord(@as(Word, @bitCast(int))), | 200 | .uint32 => |int| section.writeWord(@bitCast(int)), |
| 201 | .int64 => |int| section.writeDoubleWord(@as(DoubleWord, @bitCast(int))), | 201 | .int64 => |int| section.writeDoubleWord(@bitCast(int)), |
| 202 | .uint64 => |int| section.writeDoubleWord(@as(DoubleWord, @bitCast(int))), | 202 | .uint64 => |int| section.writeDoubleWord(@bitCast(int)), |
| 203 | .float32 => |float| section.writeWord(@as(Word, @bitCast(float))), | 203 | .float32 => |float| section.writeWord(@bitCast(float)), |
| 204 | .float64 => |float| section.writeDoubleWord(@as(DoubleWord, @bitCast(float))), | 204 | .float64 => |float| section.writeDoubleWord(@bitCast(float)), |
| 205 | } | 205 | } |
| 206 | } | 206 | } |
| 207 | 207 | ||
| ... | @@ -274,8 +274,8 @@ fn operandSize(comptime Operand: type, operand: Operand) usize { | ... | @@ -274,8 +274,8 @@ fn operandSize(comptime Operand: type, operand: Operand) usize { |
| 274 | spec.LiteralString => std.math.divCeil(usize, operand.len + 1, @sizeOf(Word)) catch unreachable, // Add one for zero-terminator | 274 | spec.LiteralString => std.math.divCeil(usize, operand.len + 1, @sizeOf(Word)) catch unreachable, // Add one for zero-terminator |
| 275 | 275 | ||
| 276 | spec.LiteralContextDependentNumber => switch (operand) { | 276 | spec.LiteralContextDependentNumber => switch (operand) { |
| 277 | .int32, .uint32, .float32 => @as(usize, 1), | 277 | .int32, .uint32, .float32 => 1, |
| 278 | .int64, .uint64, .float64 => @as(usize, 2), | 278 | .int64, .uint64, .float64 => 2, |
| 279 | }, | 279 | }, |
| 280 | 280 | ||
| 281 | // TODO: Where this type is used (OpSpecConstantOp) is currently not correct in the spec | 281 | // TODO: Where this type is used (OpSpecConstantOp) is currently not correct in the spec |
test/behavior/floatop.zig-3| ... | @@ -1089,7 +1089,6 @@ test "@floor f16" { | ... | @@ -1089,7 +1089,6 @@ test "@floor f16" { |
| 1089 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1089 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1090 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1090 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1091 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | 1091 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 1092 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1093 | 1092 | ||
| 1094 | try testFloor(f16); | 1093 | try testFloor(f16); |
| 1095 | try comptime testFloor(f16); | 1094 | try comptime testFloor(f16); |
| ... | @@ -1100,7 +1099,6 @@ test "@floor f32/f64" { | ... | @@ -1100,7 +1099,6 @@ test "@floor f32/f64" { |
| 1100 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1099 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1101 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1100 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1102 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | 1101 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 1103 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1104 | 1102 | ||
| 1105 | try testFloor(f32); | 1103 | try testFloor(f32); |
| 1106 | try comptime testFloor(f32); | 1104 | try comptime testFloor(f32); |
| ... | @@ -1162,7 +1160,6 @@ fn testFloor(comptime T: type) !void { | ... | @@ -1162,7 +1160,6 @@ fn testFloor(comptime T: type) !void { |
| 1162 | test "@floor with vectors" { | 1160 | test "@floor with vectors" { |
| 1163 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1161 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1164 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1162 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1165 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1166 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1163 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1167 | if (builtin.zig_backend == .stage2_x86_64 and | 1164 | if (builtin.zig_backend == .stage2_x86_64 and |
| 1168 | !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; | 1165 | !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; |
test/behavior/for.zig-1| ... | @@ -226,7 +226,6 @@ test "else continue outer for" { | ... | @@ -226,7 +226,6 @@ test "else continue outer for" { |
| 226 | 226 | ||
| 227 | test "for loop with else branch" { | 227 | test "for loop with else branch" { |
| 228 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 228 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 229 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 230 | 229 | ||
| 231 | { | 230 | { |
| 232 | var x = [_]u32{ 1, 2 }; | 231 | var x = [_]u32{ 1, 2 }; |
test/behavior/hasdecl.zig-4| ... | @@ -12,8 +12,6 @@ const Bar = struct { | ... | @@ -12,8 +12,6 @@ const Bar = struct { |
| 12 | }; | 12 | }; |
| 13 | 13 | ||
| 14 | test "@hasDecl" { | 14 | test "@hasDecl" { |
| 15 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 16 | |||
| 17 | try expect(@hasDecl(Foo, "public_thing")); | 15 | try expect(@hasDecl(Foo, "public_thing")); |
| 18 | try expect(!@hasDecl(Foo, "private_thing")); | 16 | try expect(!@hasDecl(Foo, "private_thing")); |
| 19 | try expect(!@hasDecl(Foo, "no_thing")); | 17 | try expect(!@hasDecl(Foo, "no_thing")); |
| ... | @@ -24,8 +22,6 @@ test "@hasDecl" { | ... | @@ -24,8 +22,6 @@ test "@hasDecl" { |
| 24 | } | 22 | } |
| 25 | 23 | ||
| 26 | test "@hasDecl using a sliced string literal" { | 24 | test "@hasDecl using a sliced string literal" { |
| 27 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 28 | |||
| 29 | try expect(@hasDecl(@This(), "std") == true); | 25 | try expect(@hasDecl(@This(), "std") == true); |
| 30 | try expect(@hasDecl(@This(), "std"[0..0]) == false); | 26 | try expect(@hasDecl(@This(), "std"[0..0]) == false); |
| 31 | try expect(@hasDecl(@This(), "std"[0..1]) == false); | 27 | try expect(@hasDecl(@This(), "std"[0..1]) == false); |
test/behavior/int_div.zig-1| ... | @@ -6,7 +6,6 @@ test "integer division" { | ... | @@ -6,7 +6,6 @@ test "integer division" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 10 | 9 | ||
| 11 | try testDivision(); | 10 | try testDivision(); |
| 12 | try comptime testDivision(); | 11 | try comptime testDivision(); |
test/behavior/math.zig-3| ... | @@ -788,7 +788,6 @@ test "small int addition" { | ... | @@ -788,7 +788,6 @@ test "small int addition" { |
| 788 | test "basic @mulWithOverflow" { | 788 | test "basic @mulWithOverflow" { |
| 789 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 789 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 790 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 790 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 791 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 792 | 791 | ||
| 793 | { | 792 | { |
| 794 | var a: u8 = 86; | 793 | var a: u8 = 86; |
| ... | @@ -821,7 +820,6 @@ test "basic @mulWithOverflow" { | ... | @@ -821,7 +820,6 @@ test "basic @mulWithOverflow" { |
| 821 | test "extensive @mulWithOverflow" { | 820 | test "extensive @mulWithOverflow" { |
| 822 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 821 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 823 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 822 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 824 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 825 | 823 | ||
| 826 | { | 824 | { |
| 827 | var a: u5 = 3; | 825 | var a: u5 = 3; |
| ... | @@ -998,7 +996,6 @@ test "@mulWithOverflow bitsize > 32" { | ... | @@ -998,7 +996,6 @@ test "@mulWithOverflow bitsize > 32" { |
| 998 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 996 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 999 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 997 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1000 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 998 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1001 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1002 | 999 | ||
| 1003 | { | 1000 | { |
| 1004 | var a: u62 = 3; | 1001 | var a: u62 = 3; |
test/behavior/switch.zig-1| ... | @@ -640,7 +640,6 @@ test "switch prong pointer capture alignment" { | ... | @@ -640,7 +640,6 @@ test "switch prong pointer capture alignment" { |
| 640 | test "switch on pointer type" { | 640 | test "switch on pointer type" { |
| 641 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 641 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 642 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 642 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 643 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 644 | 643 | ||
| 645 | const S = struct { | 644 | const S = struct { |
| 646 | const X = struct { | 645 | const X = struct { |
test/behavior/vector.zig-1| ... | @@ -1136,7 +1136,6 @@ test "@mulWithOverflow" { | ... | @@ -1136,7 +1136,6 @@ test "@mulWithOverflow" { |
| 1136 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1136 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1137 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1137 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1138 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1138 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1139 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1140 | 1139 | ||
| 1141 | const S = struct { | 1140 | const S = struct { |
| 1142 | fn doTheTest() !void { | 1141 | fn doTheTest() !void { |