Commit 458c338aeb
Changed files (1)
src
codegen
src/codegen/spirv.zig
@@ -2,6 +2,8 @@ const std = @import("std");
const Allocator = std.mem.Allocator;
const log = std.log.scoped(.codegen);
+const Target = std.Target;
+
const spec = @import("spirv/spec.zig");
const Module = @import("../Module.zig");
const Decl = Module.Decl;
@@ -63,6 +65,43 @@ pub const DeclGen = struct {
return error.AnalysisFail;
}
+ /// SPIR-V requires enabling specific integer sizes through capabilities, and so if they are not enabled, we need
+ /// to emulate them in other instructions/types. This function returns, given an integer bit width (signed or unsigned, sign
+ /// included), the width of the underlying type which represents it, given the enabled features for the current target.
+ /// If the result is `null`, the largest type the target platform supports natively is not able to perform computations using
+ /// that size. In this case, multiple elements of the largest type should be used.
+ /// The backing type will be chosen as the smallest supported integer larger or equal to it in number of bits.
+ /// The result is valid to be used with OpTypeInt.
+ /// TODO: The extension SPV_INTEL_arbitrary_precision_integers allows any integer size (at least up to 32 bits).
+ /// TODO: This probably needs an ABI-version as well (especially in combination with SPV_INTEL_arbitrary_precision_integers).
+ fn backingIntBits(self: *DeclGen, bits: u32) ?u32 {
+ // TODO: Figure out what to do with u0/i0.
+ std.debug.assert(bits != 0);
+
+ const target = self.module.getTarget();
+
+ // 8, 16 and 64-bit integers require the Int8, Int16 and Inr64 capabilities respectively.
+ const ints = [_]struct{ bits: u32, feature: ?Target.spirv.Feature } {
+ .{ .bits = 8, .feature = .Int8 },
+ .{ .bits = 16, .feature = .Int16 },
+ .{ .bits = 32, .feature = null },
+ .{ .bits = 64, .feature = .Int64 },
+ };
+
+ for (ints) |int| {
+ const has_feature = if (int.feature) |feature|
+ Target.spirv.featureSetHas(target.cpu.features, feature)
+ else
+ true;
+
+ if (bits <= int.bits and has_feature) {
+ return int.bits;
+ }
+ }
+
+ return null;
+ }
+
pub fn getOrGenType(self: *DeclGen, t: Type) !u32 {
// We can't use getOrPut here so we can recursively generate types.
if (self.types.get(t)) |already_generated| {
@@ -76,10 +115,12 @@ pub const DeclGen = struct {
.Bool => try writeInstruction(&self.spv.types_and_globals, .OpTypeBool, &[_]u32{ result }),
.Int => {
const int_info = t.intInfo(self.module.getTarget());
- // TODO: Capabilities.
+ const backing_bits = self.backingIntBits(int_info.bits) orelse
+ return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: implement fallback for integer of {} bits", .{ int_info.bits });
+
try writeInstruction(&self.spv.types_and_globals, .OpTypeInt, &[_]u32{
result,
- int_info.bits,
+ backing_bits,
switch (int_info.signedness) {
.unsigned => 0,
.signed => 1,