From 9f584977719defd39897a4a3326e040a569839e2 Mon Sep 17 00:00:00 2001 From: Ali Chraghi Date: Tue, 21 Mar 2023 11:08:06 +0330 Subject: [PATCH] dusk: abilibity to reference global decl after current decl --- libs/dusk/src/AstGen.zig | 876 ++++++++++++++++++++++---------------- libs/dusk/src/IR.zig | 445 +++++++++++++------ libs/dusk/test/boids.wgsl | 8 +- libs/dusk/test/main.zig | 1 + 4 files changed, 826 insertions(+), 504 deletions(-) diff --git a/libs/dusk/src/AstGen.zig b/libs/dusk/src/AstGen.zig index d9f4fdf1..d2395a13 100644 --- a/libs/dusk/src/AstGen.zig +++ b/libs/dusk/src/AstGen.zig @@ -7,45 +7,24 @@ const AstGen = @This(); allocator: std.mem.Allocator, tree: *const Ast, -strings: std.ArrayListUnmanaged(u8) = .{}, instructions: std.ArrayListUnmanaged(IR.Inst) = .{}, -refs: std.ArrayListUnmanaged(IR.Ref) = .{}, -scratch: std.ArrayListUnmanaged(IR.Ref) = .{}, +refs: std.ArrayListUnmanaged(IR.Inst.Ref) = .{}, +strings: std.ArrayListUnmanaged(u8) = .{}, +scratch: std.ArrayListUnmanaged(IR.Inst.Ref) = .{}, errors: std.ArrayListUnmanaged(ErrorMsg) = .{}, scope_pool: std.heap.MemoryPool(Scope), -pub const Scope = union(enum) { - root: Root, - func: Function, - block: Block, +pub const Scope = struct { + tag: Tag, + /// only null if tag == .root + parent: ?*Scope, + decls: std.AutoHashMapUnmanaged(Ast.Index, IR.Inst.Ref) = .{}, - pub const Root = struct { - decls: std.StringHashMapUnmanaged(?IR.Ref) = .{}, + pub const Tag = enum { + root, + func, + block, }; - - /// parent is always Root - pub const Function = struct { - parent: *Scope, - decls: std.StringHashMapUnmanaged(?IR.Ref) = .{}, - }; - - pub const Block = struct { - parent: *Scope, - decls: std.StringHashMapUnmanaged(?IR.Ref) = .{}, - }; - - pub fn parent(self: *Scope) ?*Scope { - return switch (self.*) { - .root => null, - inline .func, .block => |*r| r.parent, - }; - } - - pub fn decls(self: *Scope) *std.StringHashMapUnmanaged(?IR.Ref) { - return switch (self.*) { - inline else => |*r| &r.decls, - }; - } }; pub fn deinit(self: *AstGen) void { @@ -58,32 +37,35 @@ pub fn deinit(self: *AstGen) void { self.errors.deinit(self.allocator); } -pub fn translationUnit(self: *AstGen) !bool { +pub fn genTranslationUnit(self: *AstGen) !u32 { const global_decls = self.tree.spanToList(0); const scratch_top = self.scratch.items.len; defer self.scratch.shrinkRetainingCapacity(scratch_top); var root_scope = try self.scope_pool.create(); - root_scope.* = .{ .root = .{} }; + root_scope.* = .{ .tag = .root, .parent = null }; + try self.scanDecls(root_scope, global_decls); for (global_decls) |node| { - const global = try self.globalDecl(root_scope, node) orelse continue; + const global = self.genDecl(root_scope, node) catch |err| switch (err) { + error.AnalysisFail => continue, + error.OutOfMemory => return error.OutOfMemory, + }; try self.scratch.append(self.allocator, global); } if (self.errors.items.len > 0) { - return false; + return error.AnalysisFail; } - _ = try self.addList(self.scratch.items[scratch_top..]); - - return true; + return try self.addRefList(self.scratch.items[scratch_top..]); } pub fn scanDecls(self: *AstGen, scope: *Scope, decls: []const Ast.Index) !void { - std.debug.assert(scope.decls().count() == 0); + std.debug.assert(scope.decls.count() == 0); + for (decls) |decl| { const loc = self.declNameLoc(decl).?; const name = loc.slice(self.tree.source); @@ -98,49 +80,82 @@ pub fn scanDecls(self: *AstGen, scope: *Scope, decls: []const Ast.Index) !void { // ); // } - const gop = try scope.decls().getOrPut(self.scope_pool.arena.allocator(), name); - if (gop.found_existing) { - try self.addError( - loc, - "redeclaration of '{s}'", - .{name}, - null, - ); - return; // TODO? + var name_iter = scope.decls.keyIterator(); + while (name_iter.next()) |node| { + if (std.mem.eql(u8, self.declNameLoc(node.*).?.slice(self.tree.source), name)) { + try self.addError( + loc, + "redeclaration of '{s}'", + .{name}, + try ErrorMsg.Note.create( + self.allocator, + self.declNameLoc(node.*).?, + "other declaration here", + .{}, + ), + ); + return error.AnalysisFail; + } } - gop.value_ptr.* = null; + + try scope.decls.putNoClobber(self.scope_pool.arena.allocator(), decl, .none); } } -pub fn globalDecl(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { +pub fn genDecl(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref { + const ref = scope.decls.get(node).?; + if (ref != .none) return ref; + const decl = switch (self.tree.nodeTag(node)) { - .global_variable => try self.globalVariable(scope, node), - .type_alias => try self.typeAlias(scope, node), // TODO: this returns a type not a real decl - .struct_decl => try self.structDecl(scope, node), - else => return null, + .global_variable => try self.genGlobalVariable(scope, node), + .type_alias => try self.genTypeAlias(scope, node), + .struct_decl => try self.genStruct(scope, node), + else => return error.AnalysisFail, // TODO: else prong should not ever be trigerred }; - - const gop = scope.decls().getOrPutAssumeCapacity(self.declNameLoc(node).?.slice(self.tree.source)); - std.debug.assert(gop.found_existing); - gop.value_ptr.* = decl orelse IR.null_ref; - + scope.decls.putAssumeCapacity(node, decl); return decl; } -pub fn typeAlias(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { - return self.allTypes(scope, self.tree.nodeLHS(node)); +pub fn declRef(self: *AstGen, scope: *Scope, loc: Token.Loc) !IR.Inst.Ref { + const name = loc.slice(self.tree.source); + + var s = scope; + while (true) { + var name_iter = s.decls.keyIterator(); + while (name_iter.next()) |node| { + if (std.mem.eql(u8, self.declNameLoc(node.*).?.slice(self.tree.source), name)) { + return self.genDecl(scope, node.*); + } + } + s = scope.parent orelse break; + } + + try self.addError( + loc, + "use of undeclared identifier '{s}'", + .{name}, + null, + ); + return error.AnalysisFail; } -pub fn globalVariable(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { +pub fn genTypeAlias(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref { + return self.genType(scope, self.tree.nodeLHS(node)); +} + +pub fn genGlobalVariable(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .global_variable); + + const inst = try self.reserveInst(); const gv = self.tree.extraData(Ast.Node.GlobalVarDecl, self.tree.nodeLHS(node)); // for (self.tree.spanToList(gv.attrs), 0..) |attr_node, i| { // const attr = switch (self.tree.nodeTag(attr_node)) { // .attr => {}, // }; // } - var var_type = IR.null_ref; + var var_type = IR.Inst.Ref.none; if (gv.type != Ast.null_index) { - var_type = try self.allTypes(scope, gv.type) orelse return null; + var_type = try self.genType(scope, gv.type); } var addr_space: Ast.AddressSpace = .none; @@ -156,59 +171,43 @@ pub fn globalVariable(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { } const name_index = try self.addString(self.declNameLoc(node).?.slice(self.tree.source)); - return try self.addInst(.global_variable, .{ - .global_variable = .{ - .name = name_index, - .type = var_type, - .addr_space = addr_space, - .access_mode = access_mode, - .attrs = 0, // TODO + self.instructions.items[inst] = .{ + .tag = .global_variable_decl, + .data = .{ + .global_variable_decl = .{ + .name = name_index, + .type = var_type, + .addr_space = addr_space, + .access_mode = access_mode, + .attrs = 0, // TODO + }, }, - }); + }; + return IR.Inst.toRef(inst); } -pub fn structDecl(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { +pub fn genStruct(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .struct_decl); + + const inst = try self.reserveInst(); + const scratch_top = self.scratch.items.len; defer self.scratch.shrinkRetainingCapacity(scratch_top); const member_list = self.tree.spanToList(self.tree.nodeLHS(node)); for (member_list, 0..) |member_node, i| { + const member_inst = try self.reserveInst(); const member_loc = self.tree.tokenLoc(self.tree.nodeToken(member_node)); const member_type_node = self.tree.nodeRHS(member_node); const member_type_name = self.tree.tokenLoc(self.tree.nodeToken(member_type_node)); - const member_type_ref = try self.allTypes(scope, member_type_node) orelse continue; + const member_type_ref = self.genType(scope, member_type_node) catch |err| switch (err) { + error.AnalysisFail => continue, + error.OutOfMemory => return error.OutOfMemory, + }; - switch (self.instructions.items[member_type_ref].tag) { - .bool_type, - .i32_type, - .u32_type, - .f32_type, - .f16_type, - .vector_type, - .matrix_type, - .atomic_type, - .struct_decl, - => {}, - .array_type => { - if (self.instructions.items[member_type_ref].data.array_type.size == IR.null_ref and i + 1 != member_list.len) { - try self.addError( - member_loc, - "struct member with runtime-sized array type, must be the last member of the structure", - .{}, - null, - ); - continue; - } - }, - .ptr_type, - .sampler_type, - .comparison_sampler_type, - .sampled_texture_type, - .multisampled_texture_type, - .storage_texture_type, - .depth_texture_type, - .external_sampled_texture_type, - => { + switch (member_type_ref) { + .bool_type, .i32_type, .u32_type, .f32_type, .f16_type => {}, + .sampler_type, .comparison_sampler_type, .external_sampled_texture_type => { try self.addError( member_loc, "invalid struct member type '{s}'", @@ -217,31 +216,66 @@ pub fn structDecl(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { ); continue; }, - else => unreachable, + .none, .true_literal, .false_literal => unreachable, + _ => switch (self.instructions.items[member_type_ref.toIndex().?].tag) { + .vector_type, .matrix_type, .atomic_type, .struct_decl => {}, + .array_type => { + if (self.instructions.items[member_type_ref.toIndex().?].data.array_type.size == .none and i + 1 != member_list.len) { + try self.addError( + member_loc, + "struct member with runtime-sized array type, must be the last member of the structure", + .{}, + null, + ); + continue; + } + }, + .ptr_type, + .sampled_texture_type, + .multisampled_texture_type, + .storage_texture_type, + .depth_texture_type, + => { + try self.addError( + member_loc, + "invalid struct member type '{s}'", + .{member_type_name.slice(self.tree.source)}, + null, + ); + continue; + }, + else => unreachable, + }, } const name_index = try self.addString(member_loc.slice(self.tree.source)); - const member_inst = try self.addInst(.struct_member, .{ - .struct_member = .{ - .name = name_index, - .type = member_type_ref, - .@"align" = 0, // TODO + self.instructions.items[member_inst] = .{ + .tag = .struct_member, + .data = .{ + .struct_member = .{ + .name = name_index, + .type = member_type_ref, + .@"align" = 0, // TODO + }, }, - }); - try self.scratch.append(self.allocator, member_inst); + }; + try self.scratch.append(self.allocator, IR.Inst.toRef(member_inst)); } const name = self.declNameLoc(node).?.slice(self.tree.source); const name_index = try self.addString(name); - const list = try self.addList(self.scratch.items[scratch_top..]); - const inst = try self.addInst(.struct_decl, .{ - .struct_decl = .{ - .name = name_index, - .members = list, - }, - }); + const list = try self.addRefList(self.scratch.items[scratch_top..]); - return inst; + self.instructions.items[inst] = .{ + .tag = .struct_decl, + .data = .{ + .struct_decl = .{ + .name = name_index, + .members = list, + }, + }, + }; + return IR.Inst.toRef(inst); } pub fn addString(self: *AstGen, str: []const u8) error{OutOfMemory}!u32 { @@ -252,17 +286,22 @@ pub fn addString(self: *AstGen, str: []const u8) error{OutOfMemory}!u32 { return @intCast(u32, self.strings.items.len - len); } -pub fn addList(self: *AstGen, list: []const IR.Ref) error{OutOfMemory}!u32 { +pub fn addRefList(self: *AstGen, list: []const IR.Inst.Ref) error{OutOfMemory}!u32 { const len = list.len + 1; try self.refs.ensureUnusedCapacity(self.allocator, len); - self.refs.appendAssumeCapacity(@intCast(u32, list.len)); self.refs.appendSliceAssumeCapacity(list); - return @intCast(u32, self.refs.items.len - list.len); + self.refs.appendAssumeCapacity(.none); + return @intCast(u32, self.refs.items.len - len); } -pub fn addInst(self: *AstGen, tag: IR.Inst.Tag, data: IR.Inst.Data) error{OutOfMemory}!IR.Ref { - try self.instructions.append(self.allocator, .{ .tag = tag, .data = data }); - return @intCast(u32, self.instructions.items.len - 1); +pub fn reserveInst(self: *AstGen) error{OutOfMemory}!IR.Inst.Index { + try self.instructions.append(self.allocator, undefined); + return @intCast(IR.Inst.Index, self.instructions.items.len - 1); +} + +pub fn addInst(self: *AstGen, inst: IR.Inst) error{OutOfMemory}!IR.Inst.Index { + try self.instructions.append(self.allocator, inst); + return @intCast(IR.Inst.Index, self.instructions.items.len - 1); } // // pub fn expression(self: *AstGen, node: Ast.Index) !?IR.Expression { @@ -335,82 +374,80 @@ pub fn addInst(self: *AstGen, tag: IR.Inst.Tag, data: IR.Inst.Data) error{OutOfM // // return str[0] == 't'; // // } -pub fn allTypes(self: *AstGen, scope: *Scope, node: Ast.Index) error{OutOfMemory}!?IR.Ref { +pub fn genType(self: *AstGen, scope: *Scope, node: Ast.Index) error{ AnalysisFail, OutOfMemory }!IR.Inst.Ref { return switch (self.tree.nodeTag(node)) { - .bool_type => try self.boolType(node), - .number_type => try self.numberType(node), - .vector_type => try self.vectorType(scope, node) orelse return null, - .matrix_type => try self.matrixType(scope, node) orelse return null, - .atomic_type => try self.atomicType(scope, node) orelse return null, - .array_type => try self.arrayType(scope, node) orelse return null, + .bool_type => try self.genBoolType(node), + .number_type => try self.genNumberType(node), + .vector_type => try self.genVectorType(scope, node), + .matrix_type => try self.genMatrixType(scope, node), + .atomic_type => try self.genAtomicType(scope, node), + .array_type => try self.genArrayType(scope, node), .user_type => { const node_loc = self.tree.tokenLoc(self.tree.nodeToken(node)); - const decl = try self.declRef(scope, node_loc) orelse return null; - switch (self.instructions.items[decl].tag) { + const decl_ref = try self.declRef(scope, node_loc); + switch (decl_ref) { .bool_type, .i32_type, .u32_type, .f32_type, .f16_type, - .vector_type, - .matrix_type, - .atomic_type, - .array_type, - .ptr_type, .sampler_type, .comparison_sampler_type, - .sampled_texture_type, - .multisampled_texture_type, - .storage_texture_type, - .depth_texture_type, .external_sampled_texture_type, - .struct_decl, - => return decl, - .global_variable => { - try self.addError( - node_loc, - "'{s}' is not a type", - .{node_loc.slice(self.tree.source)}, - null, - ); - return null; + => return decl_ref, + .none, .true_literal, .false_literal => unreachable, + _ => switch (self.instructions.items[decl_ref.toIndex().?].tag) { + .vector_type, + .matrix_type, + .atomic_type, + .array_type, + .ptr_type, + .sampled_texture_type, + .multisampled_texture_type, + .storage_texture_type, + .depth_texture_type, + .struct_decl, + => return decl_ref, + .global_variable_decl => { + try self.addError( + node_loc, + "'{s}' is not a type", + .{node_loc.slice(self.tree.source)}, + null, + ); + return error.AnalysisFail; + }, + else => unreachable, }, - else => unreachable, } }, - .sampler_type => try self.samplerType(node), - .sampled_texture_type => try self.sampledTextureType(scope, node) orelse return null, - .multisampled_texture_type => try self.multisampledTextureType(scope, node) orelse return null, - .storage_texture_type => try self.storageTextureType(node) orelse return null, - .depth_texture_type => try self.depthTextureType(node) orelse return null, - .external_texture_type => try self.externalTextureType(node), + .sampler_type => try self.genSamplerType(node), + .sampled_texture_type => try self.genSampledTextureType(scope, node), + .multisampled_texture_type => try self.genMultigenSampledTextureType(scope, node), + .storage_texture_type => try self.genStorageTextureType(node), + .depth_texture_type => try self.genDepthTextureType(node), + .external_texture_type => try self.genExternalTextureType(node), else => unreachable, }; } -pub fn sampledTextureType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { +pub fn genSampledTextureType(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .sampled_texture_type); + + const inst = try self.reserveInst(); const component_type_node = self.tree.nodeLHS(node); - const component_type = try self.allTypes(scope, component_type_node) orelse return null; - switch (self.instructions.items[component_type].tag) { + const component_type_ref = try self.genType(scope, component_type_node); + + switch (component_type_ref) { .i32_type, .u32_type, .f32_type, => {}, .bool_type, .f16_type, - .vector_type, - .matrix_type, - .atomic_type, - .array_type, - .ptr_type, .sampler_type, .comparison_sampler_type, - .sampled_texture_type, - .multisampled_texture_type, - .storage_texture_type, - .depth_texture_type, .external_sampled_texture_type, - .struct_decl, => { try self.addError( self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), @@ -423,17 +460,44 @@ pub fn sampledTextureType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Re .{}, ), ); - return null; + return error.AnalysisFail; + }, + .none, .true_literal, .false_literal => unreachable, + _ => switch (self.instructions.items[component_type_ref.toIndex().?].tag) { + .vector_type, + .matrix_type, + .atomic_type, + .array_type, + .ptr_type, + .sampled_texture_type, + .multisampled_texture_type, + .storage_texture_type, + .depth_texture_type, + .struct_decl, + => { + try self.addError( + self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), + "invalid sampled texture component type", + .{}, + try ErrorMsg.Note.create( + self.allocator, + null, + "must be 'i32', 'u32' or 'f32'", + .{}, + ), + ); + return error.AnalysisFail; + }, + else => unreachable, }, - else => unreachable, } - const tag = self.tree.tokenTag(self.tree.nodeToken(node)); - return try self.addInst( - .sampled_texture_type, - .{ + const token_tag = self.tree.tokenTag(self.tree.nodeToken(node)); + self.instructions.items[inst] = .{ + .tag = .sampled_texture_type, + .data = .{ .sampled_texture_type = .{ - .kind = switch (tag) { + .kind = switch (token_tag) { .k_texture_sampled_1d => .@"1d", .k_texture_sampled_2d => .@"2d", .k_texture_sampled_2d_array => .@"2d_array", @@ -442,35 +506,30 @@ pub fn sampledTextureType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Re .k_texture_sampled_cube_array => .cube_array, else => unreachable, }, - .component_type = component_type, + .component_type = component_type_ref, }, }, - ); + }; + return IR.Inst.toRef(inst); } -pub fn multisampledTextureType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { +pub fn genMultigenSampledTextureType(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .multisampled_texture_type); + + const inst = try self.reserveInst(); const component_type_node = self.tree.nodeLHS(node); - const component_type = try self.allTypes(scope, component_type_node) orelse return null; - switch (self.instructions.items[component_type].tag) { + const component_type_ref = try self.genType(scope, component_type_node); + + switch (component_type_ref) { .i32_type, .u32_type, .f32_type, => {}, .bool_type, .f16_type, - .vector_type, - .matrix_type, - .atomic_type, - .array_type, - .ptr_type, .sampler_type, .comparison_sampler_type, - .sampled_texture_type, - .multisampled_texture_type, - .storage_texture_type, - .depth_texture_type, .external_sampled_texture_type, - .struct_decl, => { try self.addError( self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), @@ -483,51 +542,87 @@ pub fn multisampledTextureType(self: *AstGen, scope: *Scope, node: Ast.Index) !? .{}, ), ); - return null; + return error.AnalysisFail; + }, + .none, .true_literal, .false_literal => unreachable, + _ => switch (self.instructions.items[component_type_ref.toIndex().?].tag) { + .vector_type, + .matrix_type, + .atomic_type, + .array_type, + .ptr_type, + .sampled_texture_type, + .multisampled_texture_type, + .storage_texture_type, + .depth_texture_type, + .struct_decl, + => { + try self.addError( + self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), + "invalid multisampled texture component type", + .{}, + try ErrorMsg.Note.create( + self.allocator, + null, + "must be 'i32', 'u32' or 'f32'", + .{}, + ), + ); + return error.AnalysisFail; + }, + else => unreachable, }, - else => unreachable, } - const tag = self.tree.tokenTag(self.tree.nodeToken(node)); - return try self.addInst( - .multisampled_texture_type, - .{ + const token_tag = self.tree.tokenTag(self.tree.nodeToken(node)); + self.instructions.items[inst] = .{ + .tag = .multisampled_texture_type, + .data = .{ .multisampled_texture_type = .{ - .kind = switch (tag) { + .kind = switch (token_tag) { .k_texture_multisampled_2d => .@"2d", else => unreachable, }, - .component_type = component_type, + .component_type = component_type_ref, }, }, - ); + }; + + return IR.Inst.toRef(inst); } -pub fn storageTextureType(self: *AstGen, node: Ast.Index) !?IR.Ref { +pub fn genStorageTextureType(self: *AstGen, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .storage_texture_type); + const texel_format_loc = self.tree.tokenLoc(self.tree.nodeLHS(node)); const texel_format = std.meta.stringToEnum(Ast.TexelFormat, texel_format_loc.slice(self.tree.source)).?; const access_mode_loc = self.tree.tokenLoc(self.tree.nodeRHS(node)); const access_mode_full = std.meta.stringToEnum(Ast.AccessMode, access_mode_loc.slice(self.tree.source)).?; - const access_mode: IR.Inst.Data.MultisampledTextureTypeKind = switch (access_mode_full) { - .write => .write, + const access_mode = switch (access_mode_full) { + .write => IR.Inst.StorageTextureType.AccessMode.write, else => { try self.addError( access_mode_loc, "invalid access mode", .{}, - try ErrorMsg.Note.create(self.allocator, null, "only 'write' is allowed", .{}), + try ErrorMsg.Note.create( + self.allocator, + null, + "only 'write' is allowed", + .{}, + ), ); - return null; + return error.AnalysisFail; }, }; - const tag = self.tree.tokenTag(self.tree.nodeToken(node)); - return try self.addInst( - .storage_texture_type, - .{ + const token_tag = self.tree.tokenTag(self.tree.nodeToken(node)); + const inst = try self.addInst(.{ + .tag = .storage_texture_type, + .data = .{ .storage_texture_type = .{ - .kind = switch (tag) { + .kind = switch (token_tag) { .k_texture_storage_1d => .@"1d", .k_texture_storage_2d => .@"2d", .k_texture_storage_2d_array => .@"2d_array", @@ -538,15 +633,19 @@ pub fn storageTextureType(self: *AstGen, node: Ast.Index) !?IR.Ref { .access_mode = access_mode, }, }, - ); + }); + + return IR.Inst.toRef(inst); } -pub fn depthTextureType(self: *AstGen, node: Ast.Index) !?IR.Ref { - const tag = self.tree.tokenTag(self.tree.nodeToken(node)); - return try self.addInst( - .depth_texture_type, - .{ - .depth_texture_type = switch (tag) { +pub fn genDepthTextureType(self: *AstGen, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .depth_texture_type); + + const token_tag = self.tree.tokenTag(self.tree.nodeToken(node)); + const inst = try self.addInst(.{ + .tag = .depth_texture_type, + .data = .{ + .depth_texture_type = switch (token_tag) { .k_texture_depth_2d => .@"2d", .k_texture_depth_2d_array => .@"2d_array", .k_texture_depth_cube => .cube, @@ -555,70 +654,56 @@ pub fn depthTextureType(self: *AstGen, node: Ast.Index) !?IR.Ref { else => unreachable, }, }, - ); + }); + return IR.Inst.toRef(inst); } -pub fn externalTextureType(self: *AstGen, node: Ast.Index) !?IR.Ref { +pub fn genExternalTextureType(self: *AstGen, node: Ast.Index) !IR.Inst.Ref { std.debug.assert(self.tree.nodeTag(node) == .external_texture_type); - return try self.addInst(.external_sampled_texture_type, .{ .none = 0 }); + return .external_sampled_texture_type; } -pub fn boolType(self: *AstGen, node: Ast.Index) !IR.Ref { - const inst_tag: IR.Inst.Tag = switch (self.tree.nodeTag(node)) { - .bool_type => .bool_type, - else => unreachable, - }; - return try self.addInst(inst_tag, .{ .none = 0 }); +pub fn genBoolType(self: *AstGen, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .bool_type); + return .bool_type; } -pub fn numberType(self: *AstGen, node: Ast.Index) !IR.Ref { +pub fn genNumberType(self: *AstGen, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .number_type); + const token = self.tree.nodeToken(node); const token_tag = self.tree.tokenTag(token); - const inst_tag: IR.Inst.Tag = switch (token_tag) { + return switch (token_tag) { .k_i32 => .i32_type, .k_u32 => .u32_type, .k_f32 => .f32_type, .k_f16 => .f16_type, else => unreachable, }; - return try self.addInst(inst_tag, .{ .none = 0 }); } -pub fn samplerType(self: *AstGen, node: Ast.Index) !IR.Ref { +pub fn genSamplerType(self: *AstGen, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .sampler_type); + const token = self.tree.nodeToken(node); const token_tag = self.tree.tokenTag(token); - const inst_tag: IR.Inst.Tag = switch (token_tag) { + return switch (token_tag) { .k_sampler => .sampler_type, .k_comparison_sampler => .comparison_sampler_type, else => unreachable, }; - return try self.addInst(inst_tag, .{ .none = 0 }); } -pub fn vectorType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { +pub fn genVectorType(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .vector_type); + + const inst = try self.reserveInst(); const component_type_node = self.tree.nodeLHS(node); - const component_type = try self.allTypes(scope, component_type_node) orelse return null; - switch (self.instructions.items[component_type].tag) { - .bool_type, - .i32_type, - .u32_type, - .f32_type, - .f16_type, - => {}, - .vector_type, - .matrix_type, - .atomic_type, - .array_type, - .ptr_type, - .sampler_type, - .comparison_sampler_type, - .sampled_texture_type, - .multisampled_texture_type, - .storage_texture_type, - .depth_texture_type, - .external_sampled_texture_type, - .struct_decl, - => { + const component_type_ref = try self.genType(scope, component_type_node); + + switch (component_type_ref) { + .bool_type, .i32_type, .u32_type, .f32_type, .f16_type => {}, + .sampler_type, .comparison_sampler_type, .external_sampled_texture_type => { try self.addError( self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), "invalid vector component type", @@ -630,15 +715,42 @@ pub fn vectorType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { .{}, ), ); - return null; + return error.AnalysisFail; + }, + .none, .true_literal, .false_literal => unreachable, + _ => switch (self.instructions.items[component_type_ref.toIndex().?].tag) { + .vector_type, + .matrix_type, + .atomic_type, + .array_type, + .ptr_type, + .sampled_texture_type, + .multisampled_texture_type, + .storage_texture_type, + .depth_texture_type, + .struct_decl, + => { + try self.addError( + self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), + "invalid vector component type", + .{}, + try ErrorMsg.Note.create( + self.allocator, + null, + "must be 'i32', 'u32', 'f32', 'f16' or 'bool'", + .{}, + ), + ); + return error.AnalysisFail; + }, + else => unreachable, }, - else => unreachable, } const token_tag = self.tree.tokenTag(self.tree.nodeToken(node)); - return try self.addInst( - .vector_type, - .{ + self.instructions.items[inst] = .{ + .tag = .vector_type, + .data = .{ .vector_type = .{ .size = switch (token_tag) { .k_vec2 => .two, @@ -646,35 +758,31 @@ pub fn vectorType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { .k_vec4 => .four, else => unreachable, }, - .component_type = component_type, + .component_type = component_type_ref, }, }, - ); + }; + + return IR.Inst.toRef(inst); } -pub fn matrixType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { +pub fn genMatrixType(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .matrix_type); + + const inst = try self.reserveInst(); const component_type_node = self.tree.nodeLHS(node); - const component_type = try self.allTypes(scope, component_type_node) orelse return null; - switch (self.instructions.items[component_type].tag) { + const component_type_ref = try self.genType(scope, component_type_node); + + switch (component_type_ref) { .f32_type, .f16_type, => {}, .bool_type, .i32_type, .u32_type, - .vector_type, - .matrix_type, - .atomic_type, - .array_type, - .ptr_type, .sampler_type, .comparison_sampler_type, - .sampled_texture_type, - .multisampled_texture_type, - .storage_texture_type, - .depth_texture_type, .external_sampled_texture_type, - .struct_decl, => { try self.addError( self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), @@ -687,15 +795,42 @@ pub fn matrixType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { .{}, ), ); - return null; + return error.AnalysisFail; + }, + .none, .true_literal, .false_literal => unreachable, + _ => switch (self.instructions.items[component_type_ref.toIndex().?].tag) { + .vector_type, + .matrix_type, + .atomic_type, + .array_type, + .ptr_type, + .sampled_texture_type, + .multisampled_texture_type, + .storage_texture_type, + .depth_texture_type, + .struct_decl, + => { + try self.addError( + self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), + "invalid matrix component type", + .{}, + try ErrorMsg.Note.create( + self.allocator, + null, + "must be 'f32' or 'f16'", + .{}, + ), + ); + return error.AnalysisFail; + }, + else => unreachable, }, - else => unreachable, } const token_tag = self.tree.tokenTag(self.tree.nodeToken(node)); - return try self.addInst( - .matrix_type, - .{ + self.instructions.items[inst] = .{ + .tag = .matrix_type, + .data = .{ .matrix_type = .{ .cols = switch (token_tag) { .k_mat2x2, .k_mat2x3, .k_mat2x4 => .two, @@ -709,35 +844,31 @@ pub fn matrixType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { .k_mat2x4, .k_mat3x4, .k_mat4x4 => .four, else => unreachable, }, - .component_type = component_type, + .component_type = component_type_ref, }, }, - ); + }; + + return IR.Inst.toRef(inst); } -pub fn atomicType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { +pub fn genAtomicType(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .atomic_type); + + const inst = try self.reserveInst(); const component_type_node = self.tree.nodeLHS(node); - const component_type = try self.allTypes(scope, component_type_node) orelse return null; - switch (self.instructions.items[component_type].tag) { + const component_type_ref = try self.genType(scope, component_type_node); + + switch (component_type_ref) { .i32_type, .u32_type, => {}, .bool_type, .f32_type, .f16_type, - .vector_type, - .matrix_type, - .atomic_type, - .array_type, - .ptr_type, .sampler_type, .comparison_sampler_type, - .sampled_texture_type, - .multisampled_texture_type, - .storage_texture_type, - .depth_texture_type, .external_sampled_texture_type, - .struct_decl, => { try self.addError( self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), @@ -750,46 +881,62 @@ pub fn atomicType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { .{}, ), ); - return null; + return error.AnalysisFail; + }, + .none, .true_literal, .false_literal => unreachable, + _ => switch (self.instructions.items[component_type_ref.toIndex().?].tag) { + .vector_type, + .matrix_type, + .atomic_type, + .array_type, + .ptr_type, + .sampled_texture_type, + .multisampled_texture_type, + .storage_texture_type, + .depth_texture_type, + .struct_decl, + => { + try self.addError( + self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), + "invalid atomic component type", + .{}, + try ErrorMsg.Note.create( + self.allocator, + null, + "must be 'i32' or 'u32'", + .{}, + ), + ); + return error.AnalysisFail; + }, + else => unreachable, }, - else => unreachable, } - return try self.addInst(.atomic_type, .{ .atomic_type = .{ .component_type = component_type } }); + self.instructions.items[inst] = .{ + .tag = .atomic_type, + .data = .{ .atomic_type = .{ .component_type = component_type_ref } }, + }; + + return IR.Inst.toRef(inst); } -pub fn arrayType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { +pub fn genArrayType(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref { + std.debug.assert(self.tree.nodeTag(node) == .array_type); + + const inst = try self.reserveInst(); const component_type_node = self.tree.nodeLHS(node); - const component_type = try self.allTypes(scope, component_type_node) orelse return null; - switch (self.instructions.items[component_type].tag) { + const component_type_ref = try self.genType(scope, component_type_node); + + switch (component_type_ref) { .bool_type, .i32_type, .u32_type, .f32_type, .f16_type, - .vector_type, - .matrix_type, - .atomic_type, - .struct_decl, => {}, - .array_type => { - if (self.instructions.items[component_type].data.array_type.size == IR.null_ref) { - try self.addError( - self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), - "array componet type can not be a runtime-sized array", - .{}, - null, - ); - return null; - } - }, - .ptr_type, .sampler_type, .comparison_sampler_type, - .sampled_texture_type, - .multisampled_texture_type, - .storage_texture_type, - .depth_texture_type, .external_sampled_texture_type, => { try self.addError( @@ -798,48 +945,61 @@ pub fn arrayType(self: *AstGen, scope: *Scope, node: Ast.Index) !?IR.Ref { .{}, null, ); - return null; + return error.AnalysisFail; + }, + .none, .true_literal, .false_literal => unreachable, + _ => switch (self.instructions.items[component_type_ref.toIndex().?].tag) { + .vector_type, + .matrix_type, + .atomic_type, + .struct_decl, + => {}, + .array_type => { + if (self.instructions.items[component_type_ref.toIndex().?].data.array_type.size == .none) { + try self.addError( + self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), + "array componet type can not be a runtime-sized array", + .{}, + null, + ); + return error.AnalysisFail; + } + }, + .ptr_type, + .sampled_texture_type, + .multisampled_texture_type, + .storage_texture_type, + .depth_texture_type, + => { + try self.addError( + self.tree.tokenLoc(self.tree.nodeToken(component_type_node)), + "invalid array component type", + .{}, + null, + ); + return error.AnalysisFail; + }, + else => unreachable, }, - else => unreachable, } const size_node = self.tree.nodeRHS(node); - var size_ref = IR.null_ref; + var size_ref = IR.Inst.Ref.none; if (size_node != Ast.null_index) { // TODO } - return try self.addInst( - .array_type, - .{ + self.instructions.items[inst] = .{ + .tag = .array_type, + .data = .{ .array_type = .{ - .component_type = component_type, + .component_type = component_type_ref, .size = size_ref, }, }, - ); -} + }; -pub fn declRef(self: *AstGen, scope: *Scope, loc: Token.Loc) !?IR.Ref { - const name = loc.slice(self.tree.source); - var s = scope; - while (true) { - const decl = scope.decls().get(name) orelse { - s = s.parent() orelse break; - continue; - } orelse return null; - if (decl == IR.null_ref) { - break; - } - return decl; - } - try self.addError( - loc, - "use of undeclared identifier '{s}'", - .{name}, - null, - ); - return null; + return IR.Inst.toRef(inst); } pub fn declNameLoc(self: *AstGen, node: Ast.Index) ?Token.Loc { diff --git a/libs/dusk/src/IR.zig b/libs/dusk/src/IR.zig index 24e5b641..fa7bbc4d 100644 --- a/libs/dusk/src/IR.zig +++ b/libs/dusk/src/IR.zig @@ -5,8 +5,9 @@ const ErrorMsg = @import("main.zig").ErrorMsg; const IR = @This(); allocator: std.mem.Allocator, +globals_index: u32, instructions: []const Inst, -refs: []const Ref, +refs: []const Inst.Ref, strings: []const u8, pub fn deinit(self: IR) void { @@ -28,28 +29,65 @@ pub fn generate(allocator: std.mem.Allocator, tree: *const Ast) !AstGenResult { }; defer astgen.deinit(); - if (!try astgen.translationUnit()) { - return .{ .errors = try astgen.errors.toOwnedSlice(allocator) }; - } + const globals_index = astgen.genTranslationUnit() catch |err| switch (err) { + error.AnalysisFail => return .{ .errors = try astgen.errors.toOwnedSlice(allocator) }, + error.OutOfMemory => return error.OutOfMemory, + }; return .{ .ir = .{ .allocator = allocator, + .globals_index = globals_index, .instructions = try astgen.instructions.toOwnedSlice(allocator), .refs = try astgen.refs.toOwnedSlice(allocator), .strings = try astgen.strings.toOwnedSlice(allocator), } }; } -pub const Ref = u32; -pub const null_ref: Ref = std.math.maxInt(Ref); +pub fn getStr(self: IR, index: u32) []const u8 { + return std.mem.sliceTo(self.strings[index..], 0); +} -pub const Inst = packed struct { +pub const Inst = struct { tag: Tag, data: Data, + pub const Index = u32; + + const ref_start_index = @typeInfo(Ref).Enum.fields.len; + pub fn toRef(index: Inst.Index) Ref { + return @intToEnum(Ref, ref_start_index + index); + } + + pub const Ref = enum(u32) { + none, + + bool_type, + i32_type, + u32_type, + f32_type, + f16_type, + sampler_type, + comparison_sampler_type, + external_sampled_texture_type, + + true_literal, + false_literal, + + _, + + pub fn toIndex(inst: Ref) ?Inst.Index { + const ref_int = @enumToInt(inst); + if (ref_int >= ref_start_index) { + return @intCast(Inst.Index, ref_int - ref_start_index); + } else { + return null; + } + } + }; + pub const Tag = enum(u6) { - /// data is global_variable - global_variable, + /// data is global_variable_decl + global_variable_decl, /// data is struct_decl struct_decl, @@ -67,16 +105,6 @@ pub const Inst = packed struct { /// data is attr_interpolate attr_interpolate, - /// data is none - bool_type, - /// data is none - i32_type, - /// data is none - u32_type, - /// data is none - f32_type, - /// data is none - f16_type, /// data is vector_type vector_type, /// data is matrix_type @@ -87,10 +115,6 @@ pub const Inst = packed struct { array_type, /// data is ptr_type ptr_type, - /// data is none - sampler_type, - /// data is none - comparison_sampler_type, /// data is sampled_texture_type sampled_texture_type, /// data is multisampled_texture_type @@ -99,17 +123,11 @@ pub const Inst = packed struct { storage_texture_type, /// data is depth_texture_type depth_texture_type, - /// data is none - external_sampled_texture_type, /// data is integer_literal integer_literal, /// data is float_literal float_literal, - /// data is none - true_literal, - /// data is none - false_literal, /// data is ref not, @@ -163,134 +181,277 @@ pub const Inst = packed struct { member_access, /// data is binary (lhs is expr, rhs is type) bitcast, + + pub fn isDecl(self: Tag) bool { + return switch (self) { + .global_variable_decl, .struct_decl => true, + else => false, + }; + } }; - pub const Data = packed union { - /// TODO: https://github.com/ziglang/zig/issues/14980 - none: u1, + pub const Data = union { ref: Ref, - global_variable: packed struct { - /// index to null-terminated string in `strings` - name: u32, - type: Ref, - addr_space: Ast.AddressSpace = .none, - access_mode: Ast.AccessMode = .none, - /// length of attributes - attrs: u4 = 0, - }, - struct_decl: packed struct { - /// index to null-terminated string in `strings` - name: u32, - /// length of the member Ref's which comes after this - members: u32, - }, - struct_member: packed struct { - /// index to null-terminated string in `strings` - name: u32, - type: Ref, - @"align": u29, // 0 means null - }, + global_variable_decl: GlobalVariableDecl, + struct_decl: StructDecl, + struct_member: StructMember, /// attributes with no argument. - attr_simple: enum { - invariant, - @"const", - vertex, - fragment, - compute, - }, + attr_simple: AttrSimple, /// attributes with an expression argument. - attr_expr: packed struct { - kind: enum { - @"align", - binding, - group, - id, - location, - size, - }, - expr: Ref, - }, + attr_expr: AttrExpr, /// @builtin attribute which accepts a BuiltinValue argument. attr_builtin: Ast.BuiltinValue, /// @workgroup attribute. accepts at laest 1 argument. - attr_workgroup: packed struct { - expr0: Ref, - expr1: Ref = null_ref, - expr2: Ref = null_ref, - }, + attr_workgroup: AttrWorkgroup, /// @interpolate attribute. accepts 2 arguments. - attr_interpolate: packed struct { - type: Ast.InterpolationType, - sample: Ast.InterpolationSample, - }, - vector_type: packed struct { - component_type: Ref, - size: enum { two, three, four }, - }, - matrix_type: packed struct { - component_type: Ref, - cols: enum { two, three, four }, - rows: enum { two, three, four }, - }, - atomic_type: packed struct { component_type: Ref }, - array_type: packed struct { - component_type: Ref, - size: Ref = null_ref, - }, - ptr_type: packed struct { - component_type: Ref, - addr_space: Ast.AddressSpace, - access_mode: Ast.AccessMode, - }, - sampled_texture_type: packed struct { - kind: enum { - @"1d", - @"2d", - @"2d_array", - @"3d", - cube, - cube_array, - }, - component_type: Ref, - }, - multisampled_texture_type: packed struct { - kind: enum { @"2d" }, - component_type: Ref, - }, - storage_texture_type: packed struct { - kind: enum { - @"1d", - @"2d", - @"2d_array", - @"3d", - }, - texel_format: Ast.TexelFormat, - access_mode: MultisampledTextureTypeKind, - }, - depth_texture_type: enum { - @"2d", - @"2d_array", - cube, - cube_array, - multisampled_2d, - }, + attr_interpolate: AttrInterpolate, + vector_type: VectorType, + matrix_type: MatrixType, + atomic_type: AtomicType, + array_type: ArrayType, + ptr_type: PointerType, + sampled_texture_type: SampledTextureType, + multisampled_texture_type: MultisampledTextureType, + storage_texture_type: StorageTextureType, + depth_texture_type: DepthTextureType, integer_literal: i64, float_literal: f64, /// meaning of LHS and RHS depends on the corresponding Tag. - binary: packed struct { - lhs: Ref, - rhs: Ref, - }, - member_access: packed struct { - base: Ref, - /// index to null-terminated string in `strings` - name: u32, - }, + binary: BinaryExpr, + member_access: MemberAccess, + }; - pub const MultisampledTextureTypeKind = enum { write }; + pub const GlobalVariableDecl = struct { + /// index to null-terminated string in `strings` + name: u32, + type: Ref, + addr_space: Ast.AddressSpace = .none, + access_mode: Ast.AccessMode = .none, + /// length of attributes + attrs: u4 = 0, + }; + + pub const StructDecl = struct { + /// index to null-terminated string in `strings` + name: u32, + /// length of the member Ref's which comes after this + members: u32, + }; + + pub const StructMember = struct { + /// index to null-terminated string in `strings` + name: u32, + type: Ref, + @"align": u29, // 0 means null + }; + + pub const AttrSimple = enum { + invariant, + @"const", + vertex, + fragment, + compute, + }; + + pub const AttrExpr = struct { + kind: Kind, + expr: Ref, + + pub const Kind = enum { + @"align", + binding, + group, + id, + location, + size, + }; + }; + + pub const AttrWorkgroup = struct { + expr0: Ref, + expr1: Ref = .none, + expr2: Ref = .none, + }; + + pub const AttrInterpolate = struct { + type: Ast.InterpolationType, + sample: Ast.InterpolationSample, + }; + + pub const VectorType = struct { + component_type: Ref, + size: Size, + + pub const Size = enum { two, three, four }; + }; + + pub const MatrixType = struct { + component_type: Ref, + cols: VectorType.Size, + rows: VectorType.Size, + }; + + pub const AtomicType = struct { component_type: Ref }; + + pub const ArrayType = struct { + component_type: Ref, + size: Ref = .none, + }; + + pub const PointerType = struct { + component_type: Ref, + addr_space: Ast.AddressSpace, + access_mode: Ast.AccessMode, + }; + + pub const SampledTextureType = struct { + kind: Kind, + component_type: Ref, + + pub const Kind = enum { + @"1d", + @"2d", + @"2d_array", + @"3d", + cube, + cube_array, + }; + }; + + pub const MultisampledTextureType = struct { + kind: Kind, + component_type: Ref, + + pub const Kind = enum { @"2d" }; + }; + + pub const StorageTextureType = struct { + kind: Kind, + texel_format: Ast.TexelFormat, + access_mode: AccessMode, + + pub const Kind = enum { + @"1d", + @"2d", + @"2d_array", + @"3d", + }; + + pub const AccessMode = enum { write }; + }; + + pub const DepthTextureType = enum { + @"2d", + @"2d_array", + cube, + cube_array, + multisampled_2d, + }; + + pub const BinaryExpr = struct { + lhs: Ref, + rhs: Ref, + }; + + pub const MemberAccess = struct { + base: Ref, + /// index to null-terminated string in `strings` + name: u32, }; comptime { - std.debug.assert(@bitSizeOf(Inst) <= 104); // 13B + std.debug.assert(@sizeOf(Inst) <= 24); } }; + +pub fn print(self: IR, writer: anytype) !void { + const globals = std.mem.sliceTo(self.refs[self.globals_index..], .none); + for (globals) |ref| { + try self.printInst(writer, 0, ref, false); + } +} + +pub fn printInst(self: IR, writer: anytype, indention: u16, ref: Inst.Ref, as_ref: bool) !void { + switch (ref) { + .none, + .bool_type, + .i32_type, + .u32_type, + .f32_type, + .f16_type, + .sampler_type, + .comparison_sampler_type, + .external_sampled_texture_type, + .true_literal, + .false_literal, + => { + try writer.print("{s}()", .{@tagName(ref)}); + }, + _ => { + const index = ref.toIndex().?; + const inst = self.instructions[index]; + + if (as_ref and inst.tag.isDecl()) { + try writer.print("%{d}", .{index}); + return; + } + + try writer.print("%{d} = {s}{{", .{ index, @tagName(inst.tag) }); + switch (inst.tag) { + .global_variable_decl => { + try writer.writeByte('\n'); + + try printIndent(writer, indention + 1); + try writer.writeAll(".type = "); + try self.printInst(writer, indention + 2, inst.data.global_variable_decl.type, true); + try writer.writeAll(",\n"); + + try printIndent(writer, indention); + try writer.writeAll("},\n"); + }, + .struct_decl => { + try writer.writeByte('\n'); + + try printIndent(writer, indention + 1); + try writer.print(".name = \"{s}\",\n", .{self.getStr(inst.data.struct_decl.name)}); + + const members = std.mem.sliceTo(self.refs[inst.data.struct_decl.members..], .none); + try printIndent(writer, indention + 1); + try writer.writeAll(".members = [\n"); + for (members) |member| { + try printIndent(writer, indention + 2); + try self.printInst(writer, indention + 2, member, false); + } + try printIndent(writer, indention + 1); + try writer.writeAll("],\n"); + + try printIndent(writer, indention); + try writer.writeAll("},\n"); + }, + .struct_member => { + try writer.writeByte('\n'); + + try printIndent(writer, indention + 1); + try writer.print(".name = \"{s}\",\n", .{self.getStr(inst.data.struct_member.name)}); + + try printIndent(writer, indention + 1); + try writer.writeAll(".type = "); + try self.printInst(writer, indention + 2, inst.data.struct_member.type, true); + try writer.writeAll(",\n"); + + try printIndent(writer, indention); + try writer.writeAll("},\n"); + }, + else => { + try writer.print("TODO", .{}); + try writer.writeAll("}"); + }, + } + }, + } +} + +const indention_size = 2; +pub fn printIndent(writer: anytype, indent: u16) !void { + try writer.writeByteNTimes(' ', indent * indention_size); +} diff --git a/libs/dusk/test/boids.wgsl b/libs/dusk/test/boids.wgsl index caa67df7..4ef52f84 100644 --- a/libs/dusk/test/boids.wgsl +++ b/libs/dusk/test/boids.wgsl @@ -1,5 +1,9 @@ const NUM_PARTICLES: u32 = 1500u; +struct Particles { + particles : array +} + struct Particle { pos : vec2, vel : vec2, @@ -15,10 +19,6 @@ struct SimParams { rule3Scale : f32, } -struct Particles { - particles : array -} - @group(0) @binding(0) var params : SimParams; @group(0) @binding(1) var particlesSrc : Particles; @group(0) @binding(2) var particlesDst : Particles; diff --git a/libs/dusk/test/main.zig b/libs/dusk/test/main.zig index e6f2d17c..bd64ab98 100644 --- a/libs/dusk/test/main.zig +++ b/libs/dusk/test/main.zig @@ -183,6 +183,7 @@ test "boids" { const source = @embedFile("boids.wgsl"); var ir = try expectIR(source); defer ir.deinit(); + // try ir.print(std.io.getStdOut().writer()); } test "gkurve" {