| ... | @@ -2111,7 +2111,8 @@ const DeclGen = struct { | ... | @@ -2111,7 +2111,8 @@ const DeclGen = struct { |
| 2111 | .bool_and => try self.airBinOpSimple(inst, .OpLogicalAnd), | 2111 | .bool_and => try self.airBinOpSimple(inst, .OpLogicalAnd), |
| 2112 | .bool_or => try self.airBinOpSimple(inst, .OpLogicalOr), | 2112 | .bool_or => try self.airBinOpSimple(inst, .OpLogicalOr), |
| 2113 | | 2113 | |
| 2114 | .shl => try self.airShift(inst, .OpShiftLeftLogical), | 2114 | .shl, .shl_exact => try self.airShift(inst, .OpShiftLeftLogical, .OpShiftLeftLogical), |
| | 2115 | .shr, .shr_exact => try self.airShift(inst, .OpShiftRightLogical, .OpShiftRightArithmetic), |
| 2115 | | 2116 | |
| 2116 | .min => try self.airMinMax(inst, .lt), | 2117 | .min => try self.airMinMax(inst, .lt), |
| 2117 | .max => try self.airMinMax(inst, .gt), | 2118 | .max => try self.airMinMax(inst, .gt), |
| ... | @@ -2254,28 +2255,42 @@ const DeclGen = struct { | ... | @@ -2254,28 +2255,42 @@ const DeclGen = struct { |
| 2254 | return try self.binOpSimple(ty, lhs_id, rhs_id, opcode); | 2255 | return try self.binOpSimple(ty, lhs_id, rhs_id, opcode); |
| 2255 | } | 2256 | } |
| 2256 | | 2257 | |
| 2257 | fn airShift(self: *DeclGen, inst: Air.Inst.Index, comptime opcode: Opcode) !?IdRef { | 2258 | fn airShift(self: *DeclGen, inst: Air.Inst.Index, comptime unsigned: Opcode, comptime signed: Opcode) !?IdRef { |
| 2258 | if (self.liveness.isUnused(inst)) return null; | 2259 | if (self.liveness.isUnused(inst)) return null; |
| | 2260 | const mod = self.module; |
| 2259 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2261 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2260 | const lhs_id = try self.resolve(bin_op.lhs); | 2262 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2261 | const rhs_id = try self.resolve(bin_op.rhs); | 2263 | const rhs_id = try self.resolve(bin_op.rhs); |
| 2262 | const result_type_id = try self.resolveTypeId(self.typeOfIndex(inst)); | 2264 | const result_ty = self.typeOfIndex(inst); |
| 2263 | | 2265 | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 2264 | // the shift and the base must be the same type in SPIR-V, but in Zig the shift is a smaller int. | | |
| 2265 | const shift_id = self.spv.allocId(); | | |
| 2266 | try self.func.body.emit(self.spv.gpa, .OpUConvert, .{ | | |
| 2267 | .id_result_type = result_type_id, | | |
| 2268 | .id_result = shift_id, | | |
| 2269 | .unsigned_value = rhs_id, | | |
| 2270 | }); | | |
| 2271 | | 2266 | |
| 2272 | const result_id = self.spv.allocId(); | 2267 | const result_id = self.spv.allocId(); |
| 2273 | try self.func.body.emit(self.spv.gpa, opcode, .{ | 2268 | |
| 2274 | .id_result_type = result_type_id, | 2269 | // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that, |
| | 2270 | // so just manually upcast it if required. |
| | 2271 | const shift_ty_ref = try self.resolveType(self.typeOf(bin_op.rhs), .direct); |
| | 2272 | const shift_id = if (shift_ty_ref != result_ty_ref) blk: { |
| | 2273 | const shift_id = self.spv.allocId(); |
| | 2274 | try self.func.body.emit(self.spv.gpa, .OpUConvert, .{ |
| | 2275 | .id_result_type = self.typeId(result_ty_ref), |
| | 2276 | .id_result = shift_id, |
| | 2277 | .unsigned_value = rhs_id, |
| | 2278 | }); |
| | 2279 | break :blk shift_id; |
| | 2280 | } else rhs_id; |
| | 2281 | |
| | 2282 | const args = .{ |
| | 2283 | .id_result_type = self.typeId(result_ty_ref), |
| 2275 | .id_result = result_id, | 2284 | .id_result = result_id, |
| 2276 | .base = lhs_id, | 2285 | .base = lhs_id, |
| 2277 | .shift = shift_id, | 2286 | .shift = shift_id, |
| 2278 | }); | 2287 | }; |
| | 2288 | |
| | 2289 | if (result_ty.isSignedInt(mod)) { |
| | 2290 | try self.func.body.emit(self.spv.gpa, signed, args); |
| | 2291 | } else { |
| | 2292 | try self.func.body.emit(self.spv.gpa, unsigned, args); |
| | 2293 | } |
| 2279 | return result_id; | 2294 | return result_id; |
| 2280 | } | 2295 | } |
| 2281 | | 2296 | |