aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/spirv/Module.zig
diff options
context:
space:
mode:
authorRobin Voetter <robin@voetter.nl>2022-01-30 20:48:16 +0100
committerRobin Voetter <robin@voetter.nl>2022-11-23 19:17:58 +0100
commit074ba69ba6c730e1095bdf78bdcc31bb37c358b1 (patch)
treecb8bcc25858aa976bd21bd82ed9bce8b8d3c50ca /src/codegen/spirv/Module.zig
parent32ce2f91a92c23d46c6836a6dd68ae0f08bb04c5 (diff)
downloadzig-074ba69ba6c730e1095bdf78bdcc31bb37c358b1.tar.gz
zig-074ba69ba6c730e1095bdf78bdcc31bb37c358b1.zip
spirv: assembler
spirv: introduce SpvModule.Fn to generate function code into spirv: assembler error message setup spirv: runtime spec info spirv: inline assembly tokenizer spirv: inline assembly lhs result/opcode parsing spirv: forgot to fmt spirv: tokenize opcodes and assigned result-ids spirv: operand parsing setup spirv: assembler string literals spirv: assembler integer literals spirv: assembler value enums spirv: assembler bit masks spirv: update assembler to new asm air format spirv: target 1.5 for now Current vulkan sdk version (1.3.204) ships spirv tools targetting 1.5, and so these do not work with binaries targetting 1.6 yet. In the future, this version number should be decided by the target. spirv: store operands in flat arraylist. Instead of having dedicated Operand variants for variadic operands, just flatten them and store them in the normal inst.operands list. This is a little simpler, but is not easily decodable in the operand data representation. spirv: parse variadic assembly operands spirv: improve assembler result-id tokenization spirv: begin instruction processing spirv: only remove decl if it was actually allocated spirv: work around weird miscompilation Seems like there are problems with switch in anonymous struct literals. spirv: begin resolving some types in assembler spirv: improve instruction processing spirv: rename some types + process OpTypeInt spirv: process OpTypeVector spirv: process OpTypeMatrix and OpTypeSampler spirv: add opcode class to spec, remove @exclude'd instructions spirv: process more type instructions spirv: OpTypeFunction spirv: OpTypeOpaque spirv: parse LiteralContextDependentNumber operands spirv: emit assembly instruction into right section spirv: parse OpPhi parameters spirv: inline assembly inputs spirv: also copy air types spirv: inline assembly outputs spirv: spir-v address spaces spirv: basic vector constants/types and shuffle spirv: assembler OpTypeImage spirv: some stuff spirv: remove spirv address spaces for now
Diffstat (limited to 'src/codegen/spirv/Module.zig')
-rw-r--r--src/codegen/spirv/Module.zig66
1 files changed, 56 insertions, 10 deletions
diff --git a/src/codegen/spirv/Module.zig b/src/codegen/spirv/Module.zig
index 59ed1b9b78..f37b04bff3 100644
--- a/src/codegen/spirv/Module.zig
+++ b/src/codegen/spirv/Module.zig
@@ -24,6 +24,37 @@ const Type = @import("type.zig").Type;
const TypeCache = std.ArrayHashMapUnmanaged(Type, IdResultType, Type.ShallowHashContext32, true);
+/// This structure represents a function that is in-progress of being emitted.
+/// Commonly, the contents of this structure will be merged with the appropriate
+/// sections of the module and re-used. Note that the SPIR-V module system makes
+/// no attempt of compacting result-id's, so any Fn instance should ultimately
+/// be merged into the module it's result-id's are allocated from.
+pub const Fn = struct {
+ /// The prologue of this function; this section contains the function's
+ /// OpFunction, OpFunctionParameter, OpLabel and OpVariable instructions, and
+ /// is separated from the actual function contents as OpVariable instructions
+ /// must appear in the first block of a function definition.
+ prologue: Section = .{},
+ /// The code of the body of this function.
+ /// This section should also contain the OpFunctionEnd instruction marking
+ /// the end of this function definition.
+ body: Section = .{},
+
+ /// Reset this function without deallocating resources, so that
+ /// it may be used to emit code for another function.
+ pub fn reset(self: *Fn) void {
+ self.prologue.reset();
+ self.body.reset();
+ }
+
+ /// Free the resources owned by this function.
+ pub fn deinit(self: *Fn, a: Allocator) void {
+ self.prologue.deinit(a);
+ self.body.deinit(a);
+ self.* = undefined;
+ }
+};
+
/// A general-purpose allocator which may be used to allocate resources for this module
gpa: Allocator,
@@ -40,7 +71,8 @@ sections: struct {
// memory model defined by target, not required here.
/// OpEntryPoint instructions.
entry_points: Section = .{},
- // OpExecutionMode and OpExecutionModeId instructions - skip for now.
+ /// OpExecutionMode and OpExecutionModeId instructions.
+ execution_modes: Section = .{},
/// OpString, OpSourcExtension, OpSource, OpSourceContinued.
debug_strings: Section = .{},
// OpName, OpMemberName - skip for now.
@@ -81,6 +113,7 @@ pub fn deinit(self: *Module) void {
self.sections.capabilities.deinit(self.gpa);
self.sections.extensions.deinit(self.gpa);
self.sections.entry_points.deinit(self.gpa);
+ self.sections.execution_modes.deinit(self.gpa);
self.sections.debug_strings.deinit(self.gpa);
self.sections.annotations.deinit(self.gpa);
self.sections.types_globals_constants.deinit(self.gpa);
@@ -107,7 +140,7 @@ pub fn flush(self: Module, file: std.fs.File) !void {
const header = [_]Word{
spec.magic_number,
- (spec.version.major << 16) | (spec.version.minor << 8),
+ (1 << 16) | (5 << 8),
0, // TODO: Register Zig compiler magic number.
self.idBound(),
0, // Schema (currently reserved for future use)
@@ -119,6 +152,7 @@ pub fn flush(self: Module, file: std.fs.File) !void {
self.sections.capabilities.toWords(),
self.sections.extensions.toWords(),
self.sections.entry_points.toWords(),
+ self.sections.execution_modes.toWords(),
self.sections.debug_strings.toWords(),
self.sections.annotations.toWords(),
self.sections.types_globals_constants.toWords(),
@@ -140,6 +174,12 @@ pub fn flush(self: Module, file: std.fs.File) !void {
try file.pwritevAll(&iovc_buffers, 0);
}
+/// Merge the sections making up a function declaration into this module.
+pub fn addFunction(self: *Module, func: Fn) !void {
+ try self.sections.functions.append(self.gpa, func.prologue);
+ try self.sections.functions.append(self.gpa, func.body);
+}
+
/// Fetch the result-id of an OpString instruction that encodes the path of the source
/// file of the decl. This function may also emit an OpSource with source-level information regarding
/// the decl.
@@ -175,11 +215,13 @@ pub fn resolveType(self: *Module, ty: Type) !Type.Ref {
if (!result.found_existing) {
result.value_ptr.* = try self.emitType(ty);
}
+
return result.index;
}
pub fn resolveTypeId(self: *Module, ty: Type) !IdRef {
- return self.typeResultId(try self.resolveType(ty));
+ const type_ref = try self.resolveType(ty);
+ return self.typeResultId(type_ref);
}
/// Get the result-id of a particular type, by reference. Asserts type_ref is valid.
@@ -208,14 +250,18 @@ pub fn emitType(self: *Module, ty: Type) !IdResultType {
switch (ty.tag()) {
.void => try types.emit(self.gpa, .OpTypeVoid, result_id_operand),
.bool => try types.emit(self.gpa, .OpTypeBool, result_id_operand),
- .int => try types.emit(self.gpa, .OpTypeInt, .{
- .id_result = result_id,
- .width = ty.payload(.int).width,
- .signedness = switch (ty.payload(.int).signedness) {
- .unsigned => @as(spec.LiteralInteger, 0),
+ .int => {
+ const signedness: spec.LiteralInteger = switch (ty.payload(.int).signedness) {
+ .unsigned => 0,
.signed => 1,
- },
- }),
+ };
+
+ try types.emit(self.gpa, .OpTypeInt, .{
+ .id_result = result_id,
+ .width = ty.payload(.int).width,
+ .signedness = signedness,
+ });
+ },
.float => try types.emit(self.gpa, .OpTypeFloat, .{
.id_result = result_id,
.width = ty.payload(.float).width,