| ... | @@ -443,32 +443,43 @@ pub const DeclGen = struct { | ... | @@ -443,32 +443,43 @@ pub const DeclGen = struct { |
| 443 | return self.spv.typeResultId(type_ref); | 443 | return self.spv.typeResultId(type_ref); |
| 444 | } | 444 | } |
| 445 | | 445 | |
| | 446 | /// Create an integer type suitable for storing at least 'bits' bits. |
| | 447 | fn intType(self: *DeclGen, signedness: std.builtin.Signedness, bits: u16) !SpvType.Ref { |
| | 448 | const backing_bits = self.backingIntBits(bits) orelse { |
| | 449 | // TODO: Integers too big for any native type are represented as "composite integers": |
| | 450 | // An array of largestSupportedIntBits. |
| | 451 | return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits }); |
| | 452 | }; |
| | 453 | |
| | 454 | const payload = try self.spv.arena.create(SpvType.Payload.Int); |
| | 455 | payload.* = .{ |
| | 456 | .width = backing_bits, |
| | 457 | .signedness = signedness, |
| | 458 | }; |
| | 459 | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); |
| | 460 | } |
| | 461 | |
| 446 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. | 462 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. |
| 447 | fn resolveType(self: *DeclGen, ty: Type) Error!SpvType.Ref { | 463 | fn resolveType(self: *DeclGen, ty: Type) Error!SpvType.Ref { |
| 448 | const target = self.getTarget(); | 464 | const target = self.getTarget(); |
| 449 | return switch (ty.zigTypeTag()) { | 465 | switch (ty.zigTypeTag()) { |
| 450 | .Void => try self.spv.resolveType(SpvType.initTag(.void)), | 466 | .Void, .NoReturn => return try self.spv.resolveType(SpvType.initTag(.void)), |
| 451 | .Bool => blk: { | 467 | .Bool => { |
| 452 | // TODO: SPIR-V booleans are opaque. For local variables this is fine, but for structs | 468 | // TODO: SPIR-V booleans are opaque. For local variables this is fine, but for structs |
| 453 | // members we want to use integer types instead. | 469 | // members we want to use integer types instead. |
| 454 | break :blk try self.spv.resolveType(SpvType.initTag(.bool)); | 470 | return try self.spv.resolveType(SpvType.initTag(.bool)); |
| 455 | }, | 471 | }, |
| 456 | .Int => blk: { | 472 | .Int => { |
| 457 | const int_info = ty.intInfo(target); | 473 | const int_info = ty.intInfo(target); |
| 458 | const backing_bits = self.backingIntBits(int_info.bits) orelse { | 474 | return try self.intType(int_info.signedness, int_info.bits); |
| 459 | // TODO: Integers too big for any native type are represented as "composite integers": | 475 | }, |
| 460 | // An array of largestSupportedIntBits. | 476 | .Enum => { |
| 461 | return self.todo("Implement composite int type {}", .{ty.fmtDebug()}); | 477 | var buffer: Type.Payload.Bits = undefined; |
| 462 | }; | 478 | const int_ty = ty.intTagType(&buffer); |
| 463 | | 479 | const int_info = int_ty.intInfo(target); |
| 464 | const payload = try self.spv.arena.create(SpvType.Payload.Int); | 480 | return try self.intType(.unsigned, int_info.bits); |
| 465 | payload.* = .{ | | |
| 466 | .width = backing_bits, | | |
| 467 | .signedness = int_info.signedness, | | |
| 468 | }; | | |
| 469 | break :blk try self.spv.resolveType(SpvType.initPayload(&payload.base)); | | |
| 470 | }, | 481 | }, |
| 471 | .Float => blk: { | 482 | .Float => { |
| 472 | // We can (and want) not really emulate floating points with other floating point types like with the integer types, | 483 | // We can (and want) not really emulate floating points with other floating point types like with the integer types, |
| 473 | // so if the float is not supported, just return an error. | 484 | // so if the float is not supported, just return an error. |
| 474 | const bits = ty.floatBits(target); | 485 | const bits = ty.floatBits(target); |
| ... | @@ -488,9 +499,9 @@ pub const DeclGen = struct { | ... | @@ -488,9 +499,9 @@ pub const DeclGen = struct { |
| 488 | payload.* = .{ | 499 | payload.* = .{ |
| 489 | .width = bits, | 500 | .width = bits, |
| 490 | }; | 501 | }; |
| 491 | break :blk try self.spv.resolveType(SpvType.initPayload(&payload.base)); | 502 | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); |
| 492 | }, | 503 | }, |
| 493 | .Fn => blk: { | 504 | .Fn => { |
| 494 | // TODO: Put this somewhere in Sema.zig | 505 | // TODO: Put this somewhere in Sema.zig |
| 495 | if (ty.fnIsVarArgs()) | 506 | if (ty.fnIsVarArgs()) |
| 496 | return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); | 507 | return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); |
| ... | @@ -504,9 +515,9 @@ pub const DeclGen = struct { | ... | @@ -504,9 +515,9 @@ pub const DeclGen = struct { |
| 504 | | 515 | |
| 505 | const payload = try self.spv.arena.create(SpvType.Payload.Function); | 516 | const payload = try self.spv.arena.create(SpvType.Payload.Function); |
| 506 | payload.* = .{ .return_type = return_type, .parameters = param_types }; | 517 | payload.* = .{ .return_type = return_type, .parameters = param_types }; |
| 507 | break :blk try self.spv.resolveType(SpvType.initPayload(&payload.base)); | 518 | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); |
| 508 | }, | 519 | }, |
| 509 | .Pointer => blk: { | 520 | .Pointer => { |
| 510 | const payload = try self.spv.arena.create(SpvType.Payload.Pointer); | 521 | const payload = try self.spv.arena.create(SpvType.Payload.Pointer); |
| 511 | payload.* = .{ | 522 | payload.* = .{ |
| 512 | .storage_class = spirvStorageClass(ty.ptrAddressSpace()), | 523 | .storage_class = spirvStorageClass(ty.ptrAddressSpace()), |
| ... | @@ -516,9 +527,9 @@ pub const DeclGen = struct { | ... | @@ -516,9 +527,9 @@ pub const DeclGen = struct { |
| 516 | .alignment = null, | 527 | .alignment = null, |
| 517 | .max_byte_offset = null, | 528 | .max_byte_offset = null, |
| 518 | }; | 529 | }; |
| 519 | break :blk try self.spv.resolveType(SpvType.initPayload(&payload.base)); | 530 | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); |
| 520 | }, | 531 | }, |
| 521 | .Vector => blk: { | 532 | .Vector => { |
| 522 | // Although not 100% the same, Zig vectors map quite neatly to SPIR-V vectors (including many integer and float operations | 533 | // Although not 100% the same, Zig vectors map quite neatly to SPIR-V vectors (including many integer and float operations |
| 523 | // which work on them), so simply use those. | 534 | // which work on them), so simply use those. |
| 524 | // Note: SPIR-V vectors only support bools, ints and floats, so pointer vectors need to be supported another way. | 535 | // Note: SPIR-V vectors only support bools, ints and floats, so pointer vectors need to be supported another way. |
| ... | @@ -533,7 +544,7 @@ pub const DeclGen = struct { | ... | @@ -533,7 +544,7 @@ pub const DeclGen = struct { |
| 533 | .component_type = try self.resolveType(ty.elemType()), | 544 | .component_type = try self.resolveType(ty.elemType()), |
| 534 | .component_count = @intCast(u32, ty.vectorLen()), | 545 | .component_count = @intCast(u32, ty.vectorLen()), |
| 535 | }; | 546 | }; |
| 536 | break :blk try self.spv.resolveType(SpvType.initPayload(&payload.base)); | 547 | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); |
| 537 | }, | 548 | }, |
| 538 | | 549 | |
| 539 | .Null, | 550 | .Null, |
| ... | @@ -545,7 +556,7 @@ pub const DeclGen = struct { | ... | @@ -545,7 +556,7 @@ pub const DeclGen = struct { |
| 545 | => unreachable, // Must be comptime. | 556 | => unreachable, // Must be comptime. |
| 546 | | 557 | |
| 547 | else => |tag| return self.todo("Implement zig type '{}'", .{tag}), | 558 | else => |tag| return self.todo("Implement zig type '{}'", .{tag}), |
| 548 | }; | 559 | } |
| 549 | } | 560 | } |
| 550 | | 561 | |
| 551 | fn spirvStorageClass(as: std.builtin.AddressSpace) spec.StorageClass { | 562 | fn spirvStorageClass(as: std.builtin.AddressSpace) spec.StorageClass { |