aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorRobin Voetter <robin@voetter.nl>2021-05-15 01:38:39 +0200
committerRobin Voetter <robin@voetter.nl>2021-05-16 14:13:23 +0200
commit458c338aeb0ce72e772c19efcfc633f908ee91b3 (patch)
tree01b7158a7c5309f74da0abb9cc89998852614c03 /src/codegen
parentde6df2bc12c1cec81bb3c562a9395098c92d8239 (diff)
downloadzig-458c338aeb0ce72e772c19efcfc633f908ee91b3.tar.gz
zig-458c338aeb0ce72e772c19efcfc633f908ee91b3.zip
SPIR-V: Compute backing integer bits
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/spirv.zig45
1 files changed, 43 insertions, 2 deletions
diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig
index 9ceaf107d8..fd153533c8 100644
--- a/src/codegen/spirv.zig
+++ b/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,