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