authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-05-15 01:38:39+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-05-16 14:13:23+02:00
log458c338aeb0ce72e772c19efcfc633f908ee91b3
tree01b7158a7c5309f74da0abb9cc89998852614c03
parentde6df2bc12c1cec81bb3c562a9395098c92d8239

SPIR-V: Compute backing integer bits


1 files changed, 43 insertions(+), 2 deletions(-)

src/codegen/spirv.zig+43-2
......@@ -2,6 +2,8 @@ const std = @import("std");
22const Allocator = std.mem.Allocator;
33const log = std.log.scoped(.codegen);
44
5const Target = std.Target;
6
57const spec = @import("spirv/spec.zig");
68const Module = @import("../Module.zig");
79const Decl = Module.Decl;
......@@ -63,6 +65,43 @@ pub const DeclGen = struct {
6365 return error.AnalysisFail;
6466 }
6567
68 /// SPIR-V requires enabling specific integer sizes through capabilities, and so if they are not enabled, we need
69 /// to emulate them in other instructions/types. This function returns, given an integer bit width (signed or unsigned, sign
70 /// included), the width of the underlying type which represents it, given the enabled features for the current target.
71 /// If the result is `null`, the largest type the target platform supports natively is not able to perform computations using
72 /// that size. In this case, multiple elements of the largest type should be used.
73 /// The backing type will be chosen as the smallest supported integer larger or equal to it in number of bits.
74 /// The result is valid to be used with OpTypeInt.
75 /// TODO: The extension SPV_INTEL_arbitrary_precision_integers allows any integer size (at least up to 32 bits).
76 /// TODO: This probably needs an ABI-version as well (especially in combination with SPV_INTEL_arbitrary_precision_integers).
77 fn backingIntBits(self: *DeclGen, bits: u32) ?u32 {
78 // TODO: Figure out what to do with u0/i0.
79 std.debug.assert(bits != 0);
80
81 const target = self.module.getTarget();
82
83 // 8, 16 and 64-bit integers require the Int8, Int16 and Inr64 capabilities respectively.
84 const ints = [_]struct{ bits: u32, feature: ?Target.spirv.Feature } {
85 .{ .bits = 8, .feature = .Int8 },
86 .{ .bits = 16, .feature = .Int16 },
87 .{ .bits = 32, .feature = null },
88 .{ .bits = 64, .feature = .Int64 },
89 };
90
91 for (ints) |int| {
92 const has_feature = if (int.feature) |feature|
93 Target.spirv.featureSetHas(target.cpu.features, feature)
94 else
95 true;
96
97 if (bits <= int.bits and has_feature) {
98 return int.bits;
99 }
100 }
101
102 return null;
103 }
104
66105 pub fn getOrGenType(self: *DeclGen, t: Type) !u32 {
67106 // We can't use getOrPut here so we can recursively generate types.
68107 if (self.types.get(t)) |already_generated| {
......@@ -76,10 +115,12 @@ pub const DeclGen = struct {
76115 .Bool => try writeInstruction(&self.spv.types_and_globals, .OpTypeBool, &[_]u32{ result }),
77116 .Int => {
78117 const int_info = t.intInfo(self.module.getTarget());
79 // TODO: Capabilities.
118 const backing_bits = self.backingIntBits(int_info.bits) orelse
119 return self.fail(.{.node_offset = 0}, "TODO: SPIR-V backend: implement fallback for integer of {} bits", .{ int_info.bits });
120
80121 try writeInstruction(&self.spv.types_and_globals, .OpTypeInt, &[_]u32{
81122 result,
82 int_info.bits,
123 backing_bits,
83124 switch (int_info.signedness) {
84125 .unsigned => 0,
85126 .signed => 1,