| ... | @@ -270,6 +270,12 @@ const DeclGen = struct { | ... | @@ -270,6 +270,12 @@ const DeclGen = struct { |
| 270 | /// This is the actual number of bits of the type, not the size of the backing integer. | 270 | /// This is the actual number of bits of the type, not the size of the backing integer. |
| 271 | bits: u16, | 271 | bits: u16, |
| 272 | | 272 | |
| | 273 | /// The number of bits required to store the type. |
| | 274 | /// For `integer` and `float`, this is equal to `bits`. |
| | 275 | /// For `strange_integer` and `bool` this is the size of the backing integer. |
| | 276 | /// For `composite_integer` this is 0 (TODO) |
| | 277 | backing_bits: u16, |
| | 278 | |
| 273 | /// Whether the type is a vector. | 279 | /// Whether the type is a vector. |
| 274 | is_vector: bool, | 280 | is_vector: bool, |
| 275 | | 281 | |
| ... | @@ -499,12 +505,14 @@ const DeclGen = struct { | ... | @@ -499,12 +505,14 @@ const DeclGen = struct { |
| 499 | return switch (ty.zigTypeTag(mod)) { | 505 | return switch (ty.zigTypeTag(mod)) { |
| 500 | .Bool => ArithmeticTypeInfo{ | 506 | .Bool => ArithmeticTypeInfo{ |
| 501 | .bits = 1, // Doesn't matter for this class. | 507 | .bits = 1, // Doesn't matter for this class. |
| | 508 | .backing_bits = self.backingIntBits(1).?, |
| 502 | .is_vector = false, | 509 | .is_vector = false, |
| 503 | .signedness = .unsigned, // Technically, but doesn't matter for this class. | 510 | .signedness = .unsigned, // Technically, but doesn't matter for this class. |
| 504 | .class = .bool, | 511 | .class = .bool, |
| 505 | }, | 512 | }, |
| 506 | .Float => ArithmeticTypeInfo{ | 513 | .Float => ArithmeticTypeInfo{ |
| 507 | .bits = ty.floatBits(target), | 514 | .bits = ty.floatBits(target), |
| | 515 | .backing_bits = ty.floatBits(target), // TODO: F80? |
| 508 | .is_vector = false, | 516 | .is_vector = false, |
| 509 | .signedness = .signed, // Technically, but doesn't matter for this class. | 517 | .signedness = .signed, // Technically, but doesn't matter for this class. |
| 510 | .class = .float, | 518 | .class = .float, |
| ... | @@ -515,6 +523,7 @@ const DeclGen = struct { | ... | @@ -515,6 +523,7 @@ const DeclGen = struct { |
| 515 | const maybe_backing_bits = self.backingIntBits(int_info.bits); | 523 | const maybe_backing_bits = self.backingIntBits(int_info.bits); |
| 516 | break :blk ArithmeticTypeInfo{ | 524 | break :blk ArithmeticTypeInfo{ |
| 517 | .bits = int_info.bits, | 525 | .bits = int_info.bits, |
| | 526 | .backing_bits = maybe_backing_bits orelse 0, |
| 518 | .is_vector = false, | 527 | .is_vector = false, |
| 519 | .signedness = int_info.signedness, | 528 | .signedness = int_info.signedness, |
| 520 | .class = if (maybe_backing_bits) |backing_bits| | 529 | .class = if (maybe_backing_bits) |backing_bits| |
| ... | @@ -2154,17 +2163,48 @@ const DeclGen = struct { | ... | @@ -2154,17 +2163,48 @@ const DeclGen = struct { |
| 2154 | return result_id; | 2163 | return result_id; |
| 2155 | } | 2164 | } |
| 2156 | | 2165 | |
| 2157 | fn maskStrangeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, bits: u16) !IdRef { | 2166 | /// This function canonicalizes a "strange" integer value: |
| 2158 | const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(bits))) - 1; | 2167 | /// For unsigned integers, the value is masked so that only the relevant bits can contain |
| 2159 | const result_id = self.spv.allocId(); | 2168 | /// non-zeros. |
| 2160 | const mask_id = try self.constInt(ty_ref, mask_value); | 2169 | /// For signed integers, the value is also sign extended. |
| 2161 | try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{ | 2170 | fn normalizeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, info: ArithmeticTypeInfo) !IdRef { |
| 2162 | .id_result_type = self.typeId(ty_ref), | 2171 | if (info.bits == info.backing_bits) { |
| 2163 | .id_result = result_id, | 2172 | return value_id; |
| 2164 | .operand_1 = value_id, | 2173 | } |
| 2165 | .operand_2 = mask_id, | 2174 | |
| 2166 | }); | 2175 | switch (info.signedness) { |
| 2167 | return result_id; | 2176 | .unsigned => { |
| | 2177 | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; |
| | 2178 | const result_id = self.spv.allocId(); |
| | 2179 | const mask_id = try self.constInt(ty_ref, mask_value); |
| | 2180 | try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{ |
| | 2181 | .id_result_type = self.typeId(ty_ref), |
| | 2182 | .id_result = result_id, |
| | 2183 | .operand_1 = value_id, |
| | 2184 | .operand_2 = mask_id, |
| | 2185 | }); |
| | 2186 | return result_id; |
| | 2187 | }, |
| | 2188 | .signed => { |
| | 2189 | // Shift left and right so that we can copy the sight bit that way. |
| | 2190 | const shift_amt_id = try self.constInt(ty_ref, info.backing_bits - info.bits); |
| | 2191 | const left_id = self.spv.allocId(); |
| | 2192 | try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{ |
| | 2193 | .id_result_type = self.typeId(ty_ref), |
| | 2194 | .id_result = left_id, |
| | 2195 | .base = value_id, |
| | 2196 | .shift = shift_amt_id, |
| | 2197 | }); |
| | 2198 | const right_id = self.spv.allocId(); |
| | 2199 | try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{ |
| | 2200 | .id_result_type = self.typeId(ty_ref), |
| | 2201 | .id_result = right_id, |
| | 2202 | .base = left_id, |
| | 2203 | .shift = shift_amt_id, |
| | 2204 | }); |
| | 2205 | return right_id; |
| | 2206 | }, |
| | 2207 | } |
| 2168 | } | 2208 | } |
| 2169 | | 2209 | |
| 2170 | fn airArithOp( | 2210 | fn airArithOp( |
| ... | @@ -2199,8 +2239,8 @@ const DeclGen = struct { | ... | @@ -2199,8 +2239,8 @@ const DeclGen = struct { |
| 2199 | }, | 2239 | }, |
| 2200 | .strange_integer => blk: { | 2240 | .strange_integer => blk: { |
| 2201 | if (!modular) { | 2241 | if (!modular) { |
| 2202 | lhs_id = try self.maskStrangeInt(result_ty_ref, lhs_id, info.bits); | 2242 | lhs_id = try self.normalizeInt(result_ty_ref, lhs_id, info); |
| 2203 | rhs_id = try self.maskStrangeInt(result_ty_ref, rhs_id, info.bits); | 2243 | rhs_id = try self.normalizeInt(result_ty_ref, rhs_id, info); |
| 2204 | } | 2244 | } |
| 2205 | break :blk switch (info.signedness) { | 2245 | break :blk switch (info.signedness) { |
| 2206 | .signed => @as(usize, 1), | 2246 | .signed => @as(usize, 1), |
| ... | @@ -2565,8 +2605,8 @@ const DeclGen = struct { | ... | @@ -2565,8 +2605,8 @@ const DeclGen = struct { |
| 2565 | .strange_integer => sign: { | 2605 | .strange_integer => sign: { |
| 2566 | const op_ty_ref = try self.resolveType(op_ty, .direct); | 2606 | const op_ty_ref = try self.resolveType(op_ty, .direct); |
| 2567 | // Mask operands before performing comparison. | 2607 | // Mask operands before performing comparison. |
| 2568 | cmp_lhs_id = try self.maskStrangeInt(op_ty_ref, cmp_lhs_id, info.bits); | 2608 | cmp_lhs_id = try self.normalizeInt(op_ty_ref, cmp_lhs_id, info); |
| 2569 | cmp_rhs_id = try self.maskStrangeInt(op_ty_ref, cmp_rhs_id, info.bits); | 2609 | cmp_rhs_id = try self.normalizeInt(op_ty_ref, cmp_rhs_id, info); |
| 2570 | break :sign info.signedness; | 2610 | break :sign info.signedness; |
| 2571 | }, | 2611 | }, |
| 2572 | .integer => info.signedness, | 2612 | .integer => info.signedness, |