| ... | ... | @@ -2317,6 +2317,9 @@ const DeclGen = struct { |
| 2317 | 2317 | .mul, .mul_wrap, .mul_optimized => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul), |
| 2318 | 2318 | |
| 2319 | 2319 | .abs => try self.airAbs(inst), |
| 2320 | .floor => try self.airFloor(inst), |
| 2321 | |
| 2322 | .div_floor => try self.airDivFloor(inst), |
| 2320 | 2323 | |
| 2321 | 2324 | .div_float, |
| 2322 | 2325 | .div_float_optimized, |
| ... | ... | @@ -2328,6 +2331,11 @@ const DeclGen = struct { |
| 2328 | 2331 | .rem, |
| 2329 | 2332 | .rem_optimized, |
| 2330 | 2333 | => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem), |
| 2334 | // TODO: Check if this is the right operation |
| 2335 | .mod, |
| 2336 | .mod_optimized, |
| 2337 | => try self.airArithOp(inst, .OpFMod, .OpSMod, .OpSMod), |
| 2338 | |
| 2331 | 2339 | |
| 2332 | 2340 | .add_with_overflow => try self.airAddSubOverflow(inst, .OpIAdd, .OpULessThan, .OpSLessThan), |
| 2333 | 2341 | .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan), |
| ... | ... | @@ -2661,6 +2669,95 @@ const DeclGen = struct { |
| 2661 | 2669 | } |
| 2662 | 2670 | } |
| 2663 | 2671 | |
| 2672 | fn airDivFloor(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2673 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2674 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2675 | const rhs_id = try self.resolve(bin_op.rhs); |
| 2676 | const ty = self.typeOfIndex(inst); |
| 2677 | const ty_ref = try self.resolveType(ty, .direct); |
| 2678 | const info = self.arithmeticTypeInfo(ty); |
| 2679 | switch (info.class) { |
| 2680 | .composite_integer => unreachable, // TODO |
| 2681 | .integer, .strange_integer => { |
| 2682 | const zero_id = try self.constInt(ty_ref, 0); |
| 2683 | const one_id = try self.constInt(ty_ref, 1); |
| 2684 | |
| 2685 | // (a ^ b) > 0 |
| 2686 | const bin_bitwise_id = try self.binOpSimple(ty, lhs_id, rhs_id, .OpBitwiseXor); |
| 2687 | const is_positive_id = try self.cmp(.gt, Type.bool, ty, bin_bitwise_id, zero_id); |
| 2688 | |
| 2689 | // a / b |
| 2690 | const positive_div_id = try self.arithOp(ty, lhs_id, rhs_id, .OpFDiv, .OpSDiv, .OpUDiv); |
| 2691 | |
| 2692 | // - (abs(a) + abs(b) - 1) / abs(b) |
| 2693 | const lhs_abs = try self.abs(ty, ty, lhs_id); |
| 2694 | const rhs_abs = try self.abs(ty, ty, rhs_id); |
| 2695 | const negative_div_lhs = try self.arithOp( |
| 2696 | ty, |
| 2697 | try self.arithOp(ty, lhs_abs, rhs_abs, .OpFAdd, .OpIAdd, .OpIAdd), |
| 2698 | one_id, |
| 2699 | .OpFSub, |
| 2700 | .OpISub, |
| 2701 | .OpISub, |
| 2702 | ); |
| 2703 | const negative_div_id = try self.arithOp(ty, negative_div_lhs, rhs_abs, .OpFDiv, .OpSDiv, .OpUDiv); |
| 2704 | const negated_negative_div_id = self.spv.allocId(); |
| 2705 | try self.func.body.emit(self.spv.gpa, .OpSNegate, .{ |
| 2706 | .id_result_type = self.typeId(ty_ref), |
| 2707 | .id_result = negated_negative_div_id, |
| 2708 | .operand = negative_div_id, |
| 2709 | }); |
| 2710 | |
| 2711 | const result_id = self.spv.allocId(); |
| 2712 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ |
| 2713 | .id_result_type = self.typeId(ty_ref), |
| 2714 | .id_result = result_id, |
| 2715 | .condition = is_positive_id, |
| 2716 | .object_1 = positive_div_id, |
| 2717 | .object_2 = negated_negative_div_id, |
| 2718 | }); |
| 2719 | return result_id; |
| 2720 | }, |
| 2721 | .float => { |
| 2722 | const div_id = try self.arithOp(ty, lhs_id, rhs_id, .OpFDiv, .OpSDiv, .OpUDiv); |
| 2723 | return try self.floor(ty, div_id); |
| 2724 | }, |
| 2725 | .bool => unreachable, |
| 2726 | } |
| 2727 | } |
| 2728 | |
| 2729 | fn airFloor(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2730 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 2731 | const operand_id = try self.resolve(un_op); |
| 2732 | const result_ty = self.typeOfIndex(inst); |
| 2733 | return try self.floor(result_ty, operand_id); |
| 2734 | } |
| 2735 | |
| 2736 | fn floor(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef { |
| 2737 | const target = self.getTarget(); |
| 2738 | const ty_ref = try self.resolveType(ty, .direct); |
| 2739 | const ext_inst: Word = switch (target.os.tag) { |
| 2740 | .opencl => 25, |
| 2741 | .vulkan => 8, |
| 2742 | else => unreachable, |
| 2743 | }; |
| 2744 | const set_id = switch (target.os.tag) { |
| 2745 | .opencl => try self.spv.importInstructionSet(.opencl), |
| 2746 | .vulkan => try self.spv.importInstructionSet(.glsl), |
| 2747 | else => unreachable, |
| 2748 | }; |
| 2749 | |
| 2750 | const result_id = self.spv.allocId(); |
| 2751 | try self.func.body.emit(self.spv.gpa, .OpExtInst, .{ |
| 2752 | .id_result_type = self.typeId(ty_ref), |
| 2753 | .id_result = result_id, |
| 2754 | .set = set_id, |
| 2755 | .instruction = .{ .inst = ext_inst }, |
| 2756 | .id_ref_4 = &.{operand_id}, |
| 2757 | }); |
| 2758 | return result_id; |
| 2759 | } |
| 2760 | |
| 2664 | 2761 | fn airArithOp( |
| 2665 | 2762 | self: *DeclGen, |
| 2666 | 2763 | inst: Air.Inst.Index, |
| ... | ... | @@ -2668,7 +2765,6 @@ const DeclGen = struct { |
| 2668 | 2765 | comptime sop: Opcode, |
| 2669 | 2766 | comptime uop: Opcode, |
| 2670 | 2767 | ) !?IdRef { |
| 2671 | | |
| 2672 | 2768 | // LHS and RHS are guaranteed to have the same type, and AIR guarantees |
| 2673 | 2769 | // the result to be the same as the LHS and RHS, which matches SPIR-V. |
| 2674 | 2770 | const ty = self.typeOfIndex(inst); |
| ... | ... | @@ -2737,12 +2833,16 @@ const DeclGen = struct { |
| 2737 | 2833 | } |
| 2738 | 2834 | |
| 2739 | 2835 | fn airAbs(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2740 | | const target = self.getTarget(); |
| 2741 | 2836 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 2742 | 2837 | const operand_id = try self.resolve(ty_op.operand); |
| 2743 | 2838 | // Note: operand_ty may be signed, while ty is always unsigned! |
| 2744 | 2839 | const operand_ty = self.typeOf(ty_op.operand); |
| 2745 | 2840 | const result_ty = self.typeOfIndex(inst); |
| 2841 | return try self.abs(result_ty, operand_ty, operand_id); |
| 2842 | } |
| 2843 | |
| 2844 | fn abs(self: *DeclGen, result_ty: Type, operand_ty: Type, operand_id: IdRef) !IdRef { |
| 2845 | const target = self.getTarget(); |
| 2746 | 2846 | const operand_info = self.arithmeticTypeInfo(operand_ty); |
| 2747 | 2847 | |
| 2748 | 2848 | var wip = try self.elementWise(result_ty, false); |
| ... | ... | @@ -3692,19 +3792,22 @@ const DeclGen = struct { |
| 3692 | 3792 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3693 | 3793 | const operand_ty = self.typeOf(ty_op.operand); |
| 3694 | 3794 | const operand_id = try self.resolve(ty_op.operand); |
| 3695 | | const operand_info = self.arithmeticTypeInfo(operand_ty); |
| 3696 | | const dest_ty = self.typeOfIndex(inst); |
| 3697 | | const dest_ty_id = try self.resolveTypeId(dest_ty); |
| 3795 | const result_ty = self.typeOfIndex(inst); |
| 3796 | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 3797 | return try self.floatFromInt(result_ty_ref, operand_ty, operand_id); |
| 3798 | } |
| 3698 | 3799 | |
| 3800 | fn floatFromInt(self: *DeclGen, result_ty_ref: CacheRef, operand_ty: Type, operand_id: IdRef) !IdRef { |
| 3801 | const operand_info = self.arithmeticTypeInfo(operand_ty); |
| 3699 | 3802 | const result_id = self.spv.allocId(); |
| 3700 | 3803 | switch (operand_info.signedness) { |
| 3701 | 3804 | .signed => try self.func.body.emit(self.spv.gpa, .OpConvertSToF, .{ |
| 3702 | | .id_result_type = dest_ty_id, |
| 3805 | .id_result_type = self.typeId(result_ty_ref), |
| 3703 | 3806 | .id_result = result_id, |
| 3704 | 3807 | .signed_value = operand_id, |
| 3705 | 3808 | }), |
| 3706 | 3809 | .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertUToF, .{ |
| 3707 | | .id_result_type = dest_ty_id, |
| 3810 | .id_result_type = self.typeId(result_ty_ref), |
| 3708 | 3811 | .id_result = result_id, |
| 3709 | 3812 | .unsigned_value = operand_id, |
| 3710 | 3813 | }), |
| ... | ... | @@ -3715,19 +3818,22 @@ const DeclGen = struct { |
| 3715 | 3818 | fn airIntFromFloat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3716 | 3819 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3717 | 3820 | const operand_id = try self.resolve(ty_op.operand); |
| 3718 | | const dest_ty = self.typeOfIndex(inst); |
| 3719 | | const dest_info = self.arithmeticTypeInfo(dest_ty); |
| 3720 | | const dest_ty_id = try self.resolveTypeId(dest_ty); |
| 3821 | const result_ty = self.typeOfIndex(inst); |
| 3822 | return try self.intFromFloat(result_ty, operand_id); |
| 3823 | } |
| 3721 | 3824 | |
| 3825 | fn intFromFloat(self: *DeclGen, result_ty: Type, operand_id: IdRef) !IdRef { |
| 3826 | const result_info = self.arithmeticTypeInfo(result_ty); |
| 3827 | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 3722 | 3828 | const result_id = self.spv.allocId(); |
| 3723 | | switch (dest_info.signedness) { |
| 3829 | switch (result_info.signedness) { |
| 3724 | 3830 | .signed => try self.func.body.emit(self.spv.gpa, .OpConvertFToS, .{ |
| 3725 | | .id_result_type = dest_ty_id, |
| 3831 | .id_result_type = self.typeId(result_ty_ref), |
| 3726 | 3832 | .id_result = result_id, |
| 3727 | 3833 | .float_value = operand_id, |
| 3728 | 3834 | }), |
| 3729 | 3835 | .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertFToU, .{ |
| 3730 | | .id_result_type = dest_ty_id, |
| 3836 | .id_result_type = self.typeId(result_ty_ref), |
| 3731 | 3837 | .id_result = result_id, |
| 3732 | 3838 | .float_value = operand_id, |
| 3733 | 3839 | }), |
| ... | ... | @@ -5237,14 +5343,15 @@ const DeclGen = struct { |
| 5237 | 5343 | |
| 5238 | 5344 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 5239 | 5345 | const mod = self.module; |
| 5346 | const target = self.getTarget(); |
| 5240 | 5347 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 5241 | 5348 | const cond_ty = self.typeOf(pl_op.operand); |
| 5242 | 5349 | const cond = try self.resolve(pl_op.operand); |
| 5243 | | const cond_indirect = try self.convertToIndirect(cond_ty, cond); |
| 5350 | var cond_indirect = try self.convertToIndirect(cond_ty, cond); |
| 5244 | 5351 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 5245 | 5352 | |
| 5246 | 5353 | const cond_words: u32 = switch (cond_ty.zigTypeTag(mod)) { |
| 5247 | | .Bool => 1, |
| 5354 | .Bool, .ErrorSet => 1, |
| 5248 | 5355 | .Int => blk: { |
| 5249 | 5356 | const bits = cond_ty.intInfo(mod).bits; |
| 5250 | 5357 | const backing_bits = self.backingIntBits(bits) orelse { |
| ... | ... | @@ -5260,8 +5367,12 @@ const DeclGen = struct { |
| 5260 | 5367 | }; |
| 5261 | 5368 | break :blk if (backing_bits <= 32) @as(u32, 1) else 2; |
| 5262 | 5369 | }, |
| 5263 | | .ErrorSet => 1, |
| 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. |
| 5370 | .Pointer => blk: { |
| 5371 | cond_indirect = try self.intFromPtr(cond_indirect); |
| 5372 | break :blk target.ptrBitWidth() / 32; |
| 5373 | }, |
| 5374 | // TODO: Figure out which types apply here, and work around them as we can only do integers. |
| 5375 | else => return self.todo("implement switch for type {s}", .{@tagName(cond_ty.zigTypeTag(mod))}), |
| 5265 | 5376 | }; |
| 5266 | 5377 | |
| 5267 | 5378 | const num_cases = switch_br.data.cases_len; |
| ... | ... | @@ -5316,13 +5427,14 @@ const DeclGen = struct { |
| 5316 | 5427 | |
| 5317 | 5428 | for (items) |item| { |
| 5318 | 5429 | const value = (try self.air.value(item, mod)) orelse unreachable; |
| 5319 | | const int_val = switch (cond_ty.zigTypeTag(mod)) { |
| 5430 | const int_val: u64 = switch (cond_ty.zigTypeTag(mod)) { |
| 5320 | 5431 | .Bool, .Int => if (cond_ty.isSignedInt(mod)) @as(u64, @bitCast(value.toSignedInt(mod))) else value.toUnsignedInt(mod), |
| 5321 | 5432 | .Enum => blk: { |
| 5322 | 5433 | // TODO: figure out of cond_ty is correct (something with enum literals) |
| 5323 | 5434 | break :blk (try value.intFromEnum(cond_ty, mod)).toUnsignedInt(mod); // TODO: composite integer constants |
| 5324 | 5435 | }, |
| 5325 | 5436 | .ErrorSet => value.getErrorInt(mod), |
| 5437 | .Pointer => value.toUnsignedInt(mod), |
| 5326 | 5438 | else => unreachable, |
| 5327 | 5439 | }; |
| 5328 | 5440 | const int_lit: spec.LiteralContextDependentNumber = switch (cond_words) { |