| ... | @@ -402,9 +402,21 @@ pub const DeclGen = struct { | ... | @@ -402,9 +402,21 @@ pub const DeclGen = struct { |
| 402 | return result_id; | 402 | return result_id; |
| 403 | } | 403 | } |
| 404 | | 404 | |
| 405 | fn constUndef(self: *DeclGen, ty_ref: SpvType.Ref) Error!IdRef { | 405 | fn constUndef(self: *DeclGen, ty_ref: SpvType.Ref) !IdRef { |
| 406 | const result_id = self.spv.allocId(); | 406 | const result_id = self.spv.allocId(); |
| 407 | try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpUndef, .{ .id_result_type = self.typeId(ty_ref), .id_result = result_id }); | 407 | try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpUndef, .{ |
| | 408 | .id_result_type = self.typeId(ty_ref), |
| | 409 | .id_result = result_id, |
| | 410 | }); |
| | 411 | return result_id; |
| | 412 | } |
| | 413 | |
| | 414 | fn constNull(self: *DeclGen, ty_ref: SpvType.Ref) !IdRef { |
| | 415 | const result_id = self.spv.allocId(); |
| | 416 | try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpConstantNull, .{ |
| | 417 | .id_result_type = self.typeId(ty_ref), |
| | 418 | .id_result = result_id, |
| | 419 | }); |
| 408 | return result_id; | 420 | return result_id; |
| 409 | } | 421 | } |
| 410 | | 422 | |
| ... | @@ -674,7 +686,7 @@ pub const DeclGen = struct { | ... | @@ -674,7 +686,7 @@ pub const DeclGen = struct { |
| 674 | try self.addConstBool(has_payload); | 686 | try self.addConstBool(has_payload); |
| 675 | return; | 687 | return; |
| 676 | } else if (ty.optionalReprIsPayload()) { | 688 | } else if (ty.optionalReprIsPayload()) { |
| 677 | // Optional representation is a nullable pointer. | 689 | // Optional representation is a nullable pointer or slice. |
| 678 | if (val.castTag(.opt_payload)) |payload| { | 690 | if (val.castTag(.opt_payload)) |payload| { |
| 679 | try self.lower(payload_ty, payload.data); | 691 | try self.lower(payload_ty, payload.data); |
| 680 | } else if (has_payload) { | 692 | } else if (has_payload) { |
| ... | @@ -1257,7 +1269,7 @@ pub const DeclGen = struct { | ... | @@ -1257,7 +1269,7 @@ pub const DeclGen = struct { |
| 1257 | | 1269 | |
| 1258 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); | 1270 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); |
| 1259 | if (ty.optionalReprIsPayload()) { | 1271 | if (ty.optionalReprIsPayload()) { |
| 1260 | // Optional is actually a pointer. | 1272 | // Optional is actually a pointer or a slice. |
| 1261 | return payload_ty_ref; | 1273 | return payload_ty_ref; |
| 1262 | } | 1274 | } |
| 1263 | | 1275 | |
| ... | @@ -1523,6 +1535,93 @@ pub const DeclGen = struct { | ... | @@ -1523,6 +1535,93 @@ pub const DeclGen = struct { |
| 1523 | } | 1535 | } |
| 1524 | } | 1536 | } |
| 1525 | | 1537 | |
| | 1538 | /// Convert representation from indirect (in memory) to direct (in 'register') |
| | 1539 | /// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct). |
| | 1540 | fn convertToDirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef { |
| | 1541 | // const direct_ty_ref = try self.resolveType(ty, .direct); |
| | 1542 | return switch (ty.zigTypeTag()) { |
| | 1543 | .Bool => blk: { |
| | 1544 | const direct_bool_ty_ref = try self.resolveType(ty, .direct); |
| | 1545 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); |
| | 1546 | const zero_id = try self.constInt(indirect_bool_ty_ref, 0); |
| | 1547 | const result_id = self.spv.allocId(); |
| | 1548 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ |
| | 1549 | .id_result_type = self.typeId(direct_bool_ty_ref), |
| | 1550 | .id_result = result_id, |
| | 1551 | .operand_1 = operand_id, |
| | 1552 | .operand_2 = zero_id, |
| | 1553 | }); |
| | 1554 | break :blk result_id; |
| | 1555 | }, |
| | 1556 | else => operand_id, |
| | 1557 | }; |
| | 1558 | } |
| | 1559 | |
| | 1560 | /// Convert representation from direct (in 'register) to direct (in memory) |
| | 1561 | /// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect). |
| | 1562 | fn convertToIndirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef { |
| | 1563 | return switch (ty.zigTypeTag()) { |
| | 1564 | .Bool => blk: { |
| | 1565 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); |
| | 1566 | const zero_id = try self.constInt(indirect_bool_ty_ref, 0); |
| | 1567 | const one_id = try self.constInt(indirect_bool_ty_ref, 1); |
| | 1568 | const result_id = self.spv.allocId(); |
| | 1569 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ |
| | 1570 | .id_result_type = self.typeId(indirect_bool_ty_ref), |
| | 1571 | .id_result = result_id, |
| | 1572 | .condition = operand_id, |
| | 1573 | .object_1 = one_id, |
| | 1574 | .object_2 = zero_id, |
| | 1575 | }); |
| | 1576 | break :blk result_id; |
| | 1577 | }, |
| | 1578 | else => operand_id, |
| | 1579 | }; |
| | 1580 | } |
| | 1581 | |
| | 1582 | fn extractField(self: *DeclGen, result_ty: Type, object: IdRef, field: u32) !IdRef { |
| | 1583 | const result_ty_ref = try self.resolveType(result_ty, .indirect); |
| | 1584 | const result_id = self.spv.allocId(); |
| | 1585 | const indexes = [_]u32{field}; |
| | 1586 | try self.func.body.emit(self.spv.gpa, .OpCompositeExtract, .{ |
| | 1587 | .id_result_type = self.typeId(result_ty_ref), |
| | 1588 | .id_result = result_id, |
| | 1589 | .composite = object, |
| | 1590 | .indexes = &indexes, |
| | 1591 | }); |
| | 1592 | // Convert bools; direct structs have their field types as indirect values. |
| | 1593 | return try self.convertToDirect(result_ty, result_id); |
| | 1594 | } |
| | 1595 | |
| | 1596 | fn load(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef) !IdRef { |
| | 1597 | const value_ty = ptr_ty.childType(); |
| | 1598 | const indirect_value_ty_ref = try self.resolveType(value_ty, .indirect); |
| | 1599 | const result_id = self.spv.allocId(); |
| | 1600 | const access = spec.MemoryAccess.Extended{ |
| | 1601 | .Volatile = ptr_ty.isVolatilePtr(), |
| | 1602 | }; |
| | 1603 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| | 1604 | .id_result_type = self.typeId(indirect_value_ty_ref), |
| | 1605 | .id_result = result_id, |
| | 1606 | .pointer = ptr_id, |
| | 1607 | .memory_access = access, |
| | 1608 | }); |
| | 1609 | return try self.convertToDirect(value_ty, result_id); |
| | 1610 | } |
| | 1611 | |
| | 1612 | fn store(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, value_id: IdRef) !void { |
| | 1613 | const value_ty = ptr_ty.childType(); |
| | 1614 | const indirect_value_id = try self.convertToIndirect(value_ty, value_id); |
| | 1615 | const access = spec.MemoryAccess.Extended{ |
| | 1616 | .Volatile = ptr_ty.isVolatilePtr(), |
| | 1617 | }; |
| | 1618 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| | 1619 | .pointer = ptr_id, |
| | 1620 | .object = indirect_value_id, |
| | 1621 | .memory_access = access, |
| | 1622 | }); |
| | 1623 | } |
| | 1624 | |
| 1526 | fn genBody(self: *DeclGen, body: []const Air.Inst.Index) Error!void { | 1625 | fn genBody(self: *DeclGen, body: []const Air.Inst.Index) Error!void { |
| 1527 | for (body) |inst| { | 1626 | for (body) |inst| { |
| 1528 | try self.genInst(inst); | 1627 | try self.genInst(inst); |
| ... | @@ -1615,6 +1714,9 @@ pub const DeclGen = struct { | ... | @@ -1615,6 +1714,9 @@ pub const DeclGen = struct { |
| 1615 | .unwrap_errunion_err => try self.airErrUnionErr(inst), | 1714 | .unwrap_errunion_err => try self.airErrUnionErr(inst), |
| 1616 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), | 1715 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 1617 | | 1716 | |
| | 1717 | .is_null => try self.airIsNull(inst, .is_null), |
| | 1718 | .is_non_null => try self.airIsNull(inst, .is_non_null), |
| | 1719 | |
| 1618 | .assembly => try self.airAssembly(inst), | 1720 | .assembly => try self.airAssembly(inst), |
| 1619 | | 1721 | |
| 1620 | .call => try self.airCall(inst, .auto), | 1722 | .call => try self.airCall(inst, .auto), |
| ... | @@ -1776,18 +1878,17 @@ pub const DeclGen = struct { | ... | @@ -1776,18 +1878,17 @@ pub const DeclGen = struct { |
| 1776 | .float, .bool => unreachable, | 1878 | .float, .bool => unreachable, |
| 1777 | } | 1879 | } |
| 1778 | | 1880 | |
| 1779 | const operand_ty_id = try self.resolveTypeId(operand_ty); | 1881 | // The operand type must be the same as the result type in SPIR-V. |
| 1780 | const result_type_id = try self.resolveTypeId(result_ty); | 1882 | const operand_ty_ref = try self.resolveType(operand_ty, .direct); |
| 1781 | | 1883 | const operand_ty_id = self.typeId(operand_ty_ref); |
| 1782 | const overflow_member_ty_ref = try self.intType(.unsigned, info.bits); | | |
| 1783 | | 1884 | |
| 1784 | const op_result_id = blk: { | 1885 | const op_result_id = blk: { |
| 1785 | // Construct the SPIR-V result type. | 1886 | // Construct the SPIR-V result type. |
| 1786 | // It is almost the same as the zig one, except that the fields must be the same type | 1887 | // It is almost the same as the zig one, except that the fields must be the same type |
| 1787 | // and they must be unsigned. | 1888 | // and they must be unsigned. |
| 1788 | const overflow_result_ty_ref = try self.spv.simpleStructType(&.{ | 1889 | const overflow_result_ty_ref = try self.spv.simpleStructType(&.{ |
| 1789 | .{ .ty = overflow_member_ty_ref, .name = "res" }, | 1890 | .{ .ty = operand_ty_ref, .name = "res" }, |
| 1790 | .{ .ty = overflow_member_ty_ref, .name = "ov" }, | 1891 | .{ .ty = operand_ty_ref, .name = "ov" }, |
| 1791 | }); | 1892 | }); |
| 1792 | const result_id = self.spv.allocId(); | 1893 | const result_id = self.spv.allocId(); |
| 1793 | try self.func.body.emit(self.spv.gpa, .OpIAddCarry, .{ | 1894 | try self.func.body.emit(self.spv.gpa, .OpIAddCarry, .{ |
| ... | @@ -1801,11 +1902,13 @@ pub const DeclGen = struct { | ... | @@ -1801,11 +1902,13 @@ pub const DeclGen = struct { |
| 1801 | | 1902 | |
| 1802 | // Now convert the SPIR-V flavor result into a Zig-flavor result. | 1903 | // Now convert the SPIR-V flavor result into a Zig-flavor result. |
| 1803 | // First, extract the two fields. | 1904 | // First, extract the two fields. |
| 1804 | const unsigned_result = try self.extractField(overflow_member_ty_ref, op_result_id, 0); | 1905 | const unsigned_result = try self.extractField(operand_ty, op_result_id, 0); |
| 1805 | const overflow = try self.extractField(overflow_member_ty_ref, op_result_id, 1); | 1906 | const overflow = try self.extractField(operand_ty, op_result_id, 1); |
| 1806 | | 1907 | |
| 1807 | // We need to convert the results to the types that Zig expects here. | 1908 | // We need to convert the results to the types that Zig expects here. |
| 1808 | // The `result` is the same type except unsigned, so we can just bitcast that. | 1909 | // The `result` is the same type except unsigned, so we can just bitcast that. |
| | 1910 | // TODO: This can be removed in Kernels as there are only unsigned ints. Maybe for |
| | 1911 | // shaders as well? |
| 1809 | const result = try self.bitcast(operand_ty_id, unsigned_result); | 1912 | const result = try self.bitcast(operand_ty_id, unsigned_result); |
| 1810 | | 1913 | |
| 1811 | // The overflow needs to be converted into whatever is used to represent it in Zig. | 1914 | // The overflow needs to be converted into whatever is used to represent it in Zig. |
| ... | @@ -1828,7 +1931,7 @@ pub const DeclGen = struct { | ... | @@ -1828,7 +1931,7 @@ pub const DeclGen = struct { |
| 1828 | const result_id = self.spv.allocId(); | 1931 | const result_id = self.spv.allocId(); |
| 1829 | const constituents = [_]IdRef{ result, casted_overflow }; | 1932 | const constituents = [_]IdRef{ result, casted_overflow }; |
| 1830 | try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ | 1933 | try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ |
| 1831 | .id_result_type = result_type_id, | 1934 | .id_result_type = operand_ty_id, |
| 1832 | .id_result = result_id, | 1935 | .id_result = result_id, |
| 1833 | .constituents = &constituents, | 1936 | .constituents = &constituents, |
| 1834 | }); | 1937 | }); |
| ... | @@ -1980,25 +2083,14 @@ pub const DeclGen = struct { | ... | @@ -1980,25 +2083,14 @@ pub const DeclGen = struct { |
| 1980 | return result_id; | 2083 | return result_id; |
| 1981 | } | 2084 | } |
| 1982 | | 2085 | |
| 1983 | fn extractField(self: *DeclGen, result_ty_ref: SpvType.Ref, object: IdRef, field: u32) !IdRef { | | |
| 1984 | const result_id = self.spv.allocId(); | | |
| 1985 | const indexes = [_]u32{field}; | | |
| 1986 | try self.func.body.emit(self.spv.gpa, .OpCompositeExtract, .{ | | |
| 1987 | .id_result_type = self.typeId(result_ty_ref), | | |
| 1988 | .id_result = result_id, | | |
| 1989 | .composite = object, | | |
| 1990 | .indexes = &indexes, | | |
| 1991 | }); | | |
| 1992 | // TODO: Convert bools, direct structs should have their field types as indirect values. | | |
| 1993 | return result_id; | | |
| 1994 | } | | |
| 1995 | | | |
| 1996 | fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef { | 2086 | fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef { |
| 1997 | if (self.liveness.isUnused(inst)) return null; | 2087 | if (self.liveness.isUnused(inst)) return null; |
| 1998 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2088 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 2089 | const field_ty = self.air.typeOfIndex(inst); |
| | 2090 | const operand_id = try self.resolve(ty_op.operand); |
| 1999 | return try self.extractField( | 2091 | return try self.extractField( |
| 2000 | try self.resolveType(self.air.typeOfIndex(inst), .direct), | 2092 | field_ty, |
| 2001 | try self.resolve(ty_op.operand), | 2093 | operand_id, |
| 2002 | field, | 2094 | field, |
| 2003 | ); | 2095 | ); |
| 2004 | } | 2096 | } |
| ... | @@ -2367,35 +2459,6 @@ pub const DeclGen = struct { | ... | @@ -2367,35 +2459,6 @@ pub const DeclGen = struct { |
| 2367 | return try self.load(ptr_ty, operand); | 2459 | return try self.load(ptr_ty, operand); |
| 2368 | } | 2460 | } |
| 2369 | | 2461 | |
| 2370 | fn load(self: *DeclGen, ptr_ty: Type, ptr: IdRef) !IdRef { | | |
| 2371 | const value_ty = ptr_ty.childType(); | | |
| 2372 | const direct_result_ty_ref = try self.resolveType(value_ty, .direct); | | |
| 2373 | const indirect_result_ty_ref = try self.resolveType(value_ty, .indirect); | | |
| 2374 | const result_id = self.spv.allocId(); | | |
| 2375 | const access = spec.MemoryAccess.Extended{ | | |
| 2376 | .Volatile = ptr_ty.isVolatilePtr(), | | |
| 2377 | }; | | |
| 2378 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ | | |
| 2379 | .id_result_type = self.typeId(indirect_result_ty_ref), | | |
| 2380 | .id_result = result_id, | | |
| 2381 | .pointer = ptr, | | |
| 2382 | .memory_access = access, | | |
| 2383 | }); | | |
| 2384 | if (value_ty.zigTypeTag() == .Bool) { | | |
| 2385 | // Convert indirect bool to direct bool | | |
| 2386 | const zero_id = try self.constInt(indirect_result_ty_ref, 0); | | |
| 2387 | const casted_result_id = self.spv.allocId(); | | |
| 2388 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ | | |
| 2389 | .id_result_type = self.typeId(direct_result_ty_ref), | | |
| 2390 | .id_result = casted_result_id, | | |
| 2391 | .operand_1 = result_id, | | |
| 2392 | .operand_2 = zero_id, | | |
| 2393 | }); | | |
| 2394 | return casted_result_id; | | |
| 2395 | } | | |
| 2396 | return result_id; | | |
| 2397 | } | | |
| 2398 | | | |
| 2399 | fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { | 2462 | fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2400 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2463 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2401 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2464 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| ... | @@ -2405,35 +2468,6 @@ pub const DeclGen = struct { | ... | @@ -2405,35 +2468,6 @@ pub const DeclGen = struct { |
| 2405 | try self.store(ptr_ty, ptr, value); | 2468 | try self.store(ptr_ty, ptr, value); |
| 2406 | } | 2469 | } |
| 2407 | | 2470 | |
| 2408 | fn store(self: *DeclGen, ptr_ty: Type, ptr: IdRef, value: IdRef) !void { | | |
| 2409 | const value_ty = ptr_ty.childType(); | | |
| 2410 | const converted_value = switch (value_ty.zigTypeTag()) { | | |
| 2411 | .Bool => blk: { | | |
| 2412 | const indirect_bool_ty_ref = try self.resolveType(value_ty, .indirect); | | |
| 2413 | const result_id = self.spv.allocId(); | | |
| 2414 | const zero = try self.constInt(indirect_bool_ty_ref, 0); | | |
| 2415 | const one = try self.constInt(indirect_bool_ty_ref, 1); | | |
| 2416 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ | | |
| 2417 | .id_result_type = self.typeId(indirect_bool_ty_ref), | | |
| 2418 | .id_result = result_id, | | |
| 2419 | .condition = value, | | |
| 2420 | .object_1 = one, | | |
| 2421 | .object_2 = zero, | | |
| 2422 | }); | | |
| 2423 | break :blk result_id; | | |
| 2424 | }, | | |
| 2425 | else => value, | | |
| 2426 | }; | | |
| 2427 | const access = spec.MemoryAccess.Extended{ | | |
| 2428 | .Volatile = ptr_ty.isVolatilePtr(), | | |
| 2429 | }; | | |
| 2430 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | | |
| 2431 | .pointer = ptr, | | |
| 2432 | .object = converted_value, | | |
| 2433 | .memory_access = access, | | |
| 2434 | }); | | |
| 2435 | } | | |
| 2436 | | | |
| 2437 | fn airLoop(self: *DeclGen, inst: Air.Inst.Index) !void { | 2471 | fn airLoop(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2438 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2472 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2439 | const loop = self.air.extraData(Air.Block, ty_pl.payload); | 2473 | const loop = self.air.extraData(Air.Block, ty_pl.payload); |
| ... | @@ -2488,14 +2522,13 @@ pub const DeclGen = struct { | ... | @@ -2488,14 +2522,13 @@ pub const DeclGen = struct { |
| 2488 | const payload_ty = self.air.typeOfIndex(inst); | 2522 | const payload_ty = self.air.typeOfIndex(inst); |
| 2489 | | 2523 | |
| 2490 | const err_ty_ref = try self.resolveType(Type.anyerror, .direct); | 2524 | const err_ty_ref = try self.resolveType(Type.anyerror, .direct); |
| 2491 | const payload_ty_ref = try self.resolveType(payload_ty, .direct); | | |
| 2492 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); | 2525 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| 2493 | | 2526 | |
| 2494 | const eu_layout = self.errorUnionLayout(payload_ty); | 2527 | const eu_layout = self.errorUnionLayout(payload_ty); |
| 2495 | | 2528 | |
| 2496 | if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 2529 | if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) { |
| 2497 | const err_id = if (eu_layout.payload_has_bits) | 2530 | const err_id = if (eu_layout.payload_has_bits) |
| 2498 | try self.extractField(err_ty_ref, err_union_id, eu_layout.errorFieldIndex()) | 2531 | try self.extractField(Type.anyerror, err_union_id, eu_layout.errorFieldIndex()) |
| 2499 | else | 2532 | else |
| 2500 | err_union_id; | 2533 | err_union_id; |
| 2501 | | 2534 | |
| ... | @@ -2535,7 +2568,7 @@ pub const DeclGen = struct { | ... | @@ -2535,7 +2568,7 @@ pub const DeclGen = struct { |
| 2535 | return null; | 2568 | return null; |
| 2536 | } | 2569 | } |
| 2537 | | 2570 | |
| 2538 | return try self.extractField(payload_ty_ref, err_union_id, eu_layout.payloadFieldIndex()); | 2571 | return try self.extractField(payload_ty, err_union_id, eu_layout.payloadFieldIndex()); |
| 2539 | } | 2572 | } |
| 2540 | | 2573 | |
| 2541 | fn airErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2574 | fn airErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -2559,7 +2592,7 @@ pub const DeclGen = struct { | ... | @@ -2559,7 +2592,7 @@ pub const DeclGen = struct { |
| 2559 | return operand_id; | 2592 | return operand_id; |
| 2560 | } | 2593 | } |
| 2561 | | 2594 | |
| 2562 | return try self.extractField(err_ty_ref, operand_id, eu_layout.errorFieldIndex()); | 2595 | return try self.extractField(Type.anyerror, operand_id, eu_layout.errorFieldIndex()); |
| 2563 | } | 2596 | } |
| 2564 | | 2597 | |
| 2565 | fn airWrapErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2598 | fn airWrapErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -2598,6 +2631,69 @@ pub const DeclGen = struct { | ... | @@ -2598,6 +2631,69 @@ pub const DeclGen = struct { |
| 2598 | return result_id; | 2631 | return result_id; |
| 2599 | } | 2632 | } |
| 2600 | | 2633 | |
| | 2634 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { |
| | 2635 | if (self.liveness.isUnused(inst)) return null; |
| | 2636 | |
| | 2637 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 2638 | const operand_id = try self.resolve(un_op); |
| | 2639 | const optional_ty = self.air.typeOf(un_op); |
| | 2640 | |
| | 2641 | var buf: Type.Payload.ElemType = undefined; |
| | 2642 | const payload_ty = optional_ty.optionalChild(&buf); |
| | 2643 | |
| | 2644 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| | 2645 | |
| | 2646 | if (optional_ty.optionalReprIsPayload()) { |
| | 2647 | // Pointer payload represents nullability: pointer or slice. |
| | 2648 | |
| | 2649 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| | 2650 | const ptr_ty = if (payload_ty.isSlice()) |
| | 2651 | payload_ty.slicePtrFieldType(&ptr_buf) |
| | 2652 | else |
| | 2653 | payload_ty; |
| | 2654 | |
| | 2655 | const ptr_id = if (payload_ty.isSlice()) |
| | 2656 | try self.extractField(Type.bool, operand_id, 0) |
| | 2657 | else |
| | 2658 | operand_id; |
| | 2659 | |
| | 2660 | const payload_ty_ref = try self.resolveType(ptr_ty, .direct); |
| | 2661 | const null_id = try self.constNull(payload_ty_ref); |
| | 2662 | const result_id = self.spv.allocId(); |
| | 2663 | const operands = .{ |
| | 2664 | .id_result_type = self.typeId(bool_ty_ref), |
| | 2665 | .id_result = result_id, |
| | 2666 | .operand_1 = ptr_id, |
| | 2667 | .operand_2 = null_id, |
| | 2668 | }; |
| | 2669 | switch (pred) { |
| | 2670 | .is_null => try self.func.body.emit(self.spv.gpa, .OpPtrEqual, operands), |
| | 2671 | .is_non_null => try self.func.body.emit(self.spv.gpa, .OpPtrNotEqual, operands), |
| | 2672 | } |
| | 2673 | return result_id; |
| | 2674 | } |
| | 2675 | |
| | 2676 | const is_non_null_id = if (optional_ty.hasRuntimeBitsIgnoreComptime()) |
| | 2677 | try self.extractField(Type.bool, operand_id, 1) |
| | 2678 | else |
| | 2679 | // Optional representation is bool indicating whether the optional is set |
| | 2680 | operand_id; |
| | 2681 | |
| | 2682 | return switch (pred) { |
| | 2683 | .is_null => blk: { |
| | 2684 | // Invert condition |
| | 2685 | const result_id = self.spv.allocId(); |
| | 2686 | try self.func.body.emit(self.spv.gpa, .OpLogicalNot, .{ |
| | 2687 | .id_result_type = self.typeId(bool_ty_ref), |
| | 2688 | .id_result = result_id, |
| | 2689 | .operand = is_non_null_id, |
| | 2690 | }); |
| | 2691 | break :blk result_id; |
| | 2692 | }, |
| | 2693 | .is_non_null => is_non_null_id, |
| | 2694 | }; |
| | 2695 | } |
| | 2696 | |
| 2601 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { | 2697 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2602 | const target = self.getTarget(); | 2698 | const target = self.getTarget(); |
| 2603 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 2699 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |