dusk: rewrite AstGen.zig and IR.zig

This commit is contained in:
Ali Chraghi 2023-03-20 01:41:07 +03:30 committed by Stephen Gutekanst
parent 46c5ca1dd0
commit 624ab118db
5 changed files with 1043 additions and 479 deletions

View file

@ -171,7 +171,7 @@ pub const Node = struct {
/// RHS : block
fn_decl,
/// TOK : ident
/// LHS : ? Attributes
/// LHS : ?span(Attribute)
/// RHS : type
fn_param,
@ -367,7 +367,7 @@ pub const Node = struct {
/// RHS : --
user_type,
// ####### Attr #######
// ####### Attribute #######
// TOK : attr
attr,
@ -650,6 +650,7 @@ pub const InterpolationSample = enum {
};
pub const AddressSpace = enum {
none, // TODO
function,
private,
workgroup,
@ -658,6 +659,7 @@ pub const AddressSpace = enum {
};
pub const AccessMode = enum {
none, // TODO
read,
write,
read_write,

File diff suppressed because it is too large Load diff

View file

@ -4,11 +4,15 @@ const Ast = @import("Ast.zig");
const ErrorMsg = @import("main.zig").ErrorMsg;
const IR = @This();
arena: std.heap.ArenaAllocator,
root: TranslationUnit,
allocator: std.mem.Allocator,
instructions: []const Inst,
refs: []const Ref,
strings: []const u8,
pub fn deinit(self: IR) void {
self.arena.deinit();
self.allocator.free(self.instructions);
self.allocator.free(self.refs);
self.allocator.free(self.strings);
}
pub const AstGenResult = union(enum) {
@ -17,193 +21,276 @@ pub const AstGenResult = union(enum) {
};
pub fn generate(allocator: std.mem.Allocator, tree: *const Ast) !AstGenResult {
var arena = std.heap.ArenaAllocator.init(allocator);
errdefer arena.deinit();
var astgen = AstGen{
.arena = arena.allocator(),
.allocator = allocator,
.tree = tree,
.errors = .{},
.scope_pool = std.heap.MemoryPool(AstGen.Scope).init(allocator),
};
defer astgen.deinit();
const root = try astgen.translationUnit() orelse {
arena.deinit();
return .{
.errors = try astgen.errors.toOwnedSlice(allocator),
};
};
if (!try astgen.translationUnit()) {
return .{ .errors = try astgen.errors.toOwnedSlice(allocator) };
}
return .{ .ir = .{ .arena = arena, .root = root } };
return .{ .ir = .{
.allocator = allocator,
.instructions = try astgen.instructions.toOwnedSlice(allocator),
.refs = try astgen.refs.toOwnedSlice(allocator),
.strings = try astgen.strings.toOwnedSlice(allocator),
} };
}
pub const TranslationUnit = []const GlobalDecl;
pub const Ref = u32;
pub const null_ref: Ref = std.math.maxInt(Ref);
pub const GlobalDecl = union(enum) {
variable: GlobalVariable,
@"struct": StructDecl,
};
pub const Inst = packed struct {
tag: Tag,
data: Data,
pub const GlobalVariable = struct {
name: []const u8,
type: union(enum) {},
expr: Expression,
};
pub const Tag = enum(u6) {
/// data is global_variable
global_variable,
pub const StructDecl = struct {
name: []const u8,
members: []const StructMember,
};
/// data is struct_decl
struct_decl,
/// data is struct_member
struct_member,
pub const StructMember = struct {
name: []const u8,
type: Type,
/// data is attr_simple
attr_simple,
/// data is attr_expr
attr_expr,
/// data is attr_builtin
attr_builtin,
/// data is attr_workgroup
attr_workgroup,
/// data is attr_interpolate
attr_interpolate,
pub const Type = union(enum) {
bool,
@"struct": []const u8,
number: NumberType,
vector: VectorType,
matrix: MatrixType,
atomic: AtomicType,
array: ArrayType,
/// 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
matrix_type,
/// data is atomic_type
atomic_type,
/// data is array_type
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
multisampled_texture_type,
/// data is storage_texture_type
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,
/// data is ref
negate,
/// data is ref
deref,
/// data is ref
addr_of,
/// data is binary
mul,
/// data is binary
div,
/// data is binary
mod,
/// data is binary
add,
/// data is binary
sub,
/// data is binary
shift_left,
/// data is binary
shift_right,
/// data is binary
binary_and,
/// data is binary
binary_or,
/// data is binary
binary_xor,
/// data is binary
circuit_and,
/// data is binary
circuit_or,
/// data is binary
equal,
/// data is binary
not_equal,
/// data is binary
less,
/// data is binary
less_equal,
/// data is binary
greater,
/// data is binary
greater_equal,
/// data is binary
index,
/// data is member_access
member_access,
/// data is binary (lhs is expr, rhs is type)
bitcast,
};
};
pub const Expression = union(enum) {
literal: Literal,
ident: []const u8,
unary: struct {
op: UnaryOperator,
expr: *const Expression,
},
binary: struct {
op: BinaryOperator,
lhs: *const Expression,
rhs: *const Expression,
},
index: struct {
base: *const Expression,
index: *const Expression,
},
member: struct {
base: *const Expression,
field: []const u8,
},
bitcast: struct {
expr: *const Expression,
to: union(enum) {
number: NumberType,
vector: VectorType,
pub const Data = packed union {
/// TODO: https://github.com/ziglang/zig/issues/14980
none: u1,
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
},
/// attributes with no argument.
attr_simple: enum {
invariant,
@"const",
vertex,
fragment,
compute,
},
/// attributes with an expression argument.
attr_expr: packed struct {
kind: enum {
@"align",
binding,
group,
id,
location,
size,
},
expr: Ref,
},
/// @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,
},
/// @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,
},
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,
},
},
};
pub const Literal = union(enum) {
number: NumberLiteral,
bool: bool,
};
pub const NumberLiteral = union(enum) {
int: i64,
float: f64,
};
pub const UnaryOperator = enum {
not,
negate,
addr_of,
deref,
};
pub const BinaryOperator = enum {
mul,
div,
mod,
add,
sub,
shift_left,
shift_right,
binary_and,
binary_or,
binary_xor,
circuit_and,
circuit_or,
equal,
not_equal,
less,
less_equal,
greater,
greater_equal,
};
pub const NumberType = enum {
i32,
u32,
f32,
f16,
};
pub const VectorType = struct {
size: Size,
component_type: Type,
pub const Type = union(enum) {
bool,
number: NumberType,
pub const MultisampledTextureTypeKind = enum { write };
};
pub const Size = enum {
vec2,
vec3,
vec4,
};
};
pub const MatrixType = struct {
size: Size,
component_type: Type,
pub const Type = enum {
f32,
f16,
abstract_float,
};
pub const Size = enum {
mat2x2,
mat2x3,
mat2x4,
mat3x2,
mat3x3,
mat3x4,
mat4x2,
mat4x3,
mat4x4,
};
};
pub const AtomicType = struct {
component_type: Type,
pub const Type = enum {
u32,
i32,
};
};
pub const ArrayType = struct {
component_type: Type,
size: ?NumberLiteral = null,
pub const Type = union(enum) {
bool,
number: NumberType,
@"struct": []const u8,
vector: VectorType,
matrix: MatrixType,
atomic: AtomicType,
array: *Type,
};
comptime {
std.debug.assert(@bitSizeOf(Inst) <= 104); // 13B
}
};

View file

@ -2,10 +2,8 @@
const std = @import("std");
const Ast = @import("Ast.zig");
const Token = @import("Token.zig");
const Tokenizer = @import("Tokenizer.zig");
const Extension = @import("main.zig").Extension;
const ErrorMsg = @import("main.zig").ErrorMsg;
const comptimePrint = std.fmt.comptimePrint;
const fieldNames = std.meta.fieldNames;
const Parser = @This();
@ -1877,7 +1875,7 @@ fn addExtra(p: *Parser, extra: anytype) error{OutOfMemory}!Ast.Index {
try p.extra.ensureUnusedCapacity(p.allocator, fields.len);
const result = @intCast(Ast.Index, p.extra.items.len);
inline for (fields) |field| {
comptime std.debug.assert(field.type == Ast.Index or field.type == Ast.Index);
comptime std.debug.assert(field.type == Ast.Index);
p.extra.appendAssumeCapacity(@field(extra, field.name));
}
return result;

View file

@ -152,6 +152,10 @@ fn expectError(source: [:0]const u8, err: dusk.ErrorMsg) !void {
.{ err.note.?.msg, err_list[0].note.?.msg },
);
}
if (err.note == null) {
std.debug.print("\x1b[31mnote missed: {s}\x1b[0m\n", .{err_list[0].note.?.msg});
return error.NoteMissed;
}
try expect(std.mem.eql(u8, err.note.?.msg, err_list[0].note.?.msg));
if (err_list[0].note.?.loc) |_| {
errdefer {
@ -232,7 +236,22 @@ test "variable & expressions" {
// try expect(ir.nodeTag(@"7") == .number_literal);
}
test "analyser errors" {
test "simple analyse's result" {
// {
// const source =
// \\type T0 = f32;
// \\type T1 = T0;
// \\type T2 = T1;
// \\type T3 = T2;
// \\struct S0 { m0: T3 }
// ;
// var ir = try expectIR(source);
// // try std.testing.expect(ir.root[0].@"struct".members[0].type.number == .f32);
// ir.deinit();
// }
}
test "must error" {
{
const source = "^";
try expectError(source, .{
@ -260,18 +279,17 @@ test "analyser errors" {
\\struct S0 { m: S1 }
;
try expectError(source, .{
.msg = "'S1' is neither an struct or type alias",
.msg = "'S1' is not a type",
.loc = .{ .start = 27, .end = 29 },
});
}
{
const source =
\\type T = sampler;
\\struct S0 { m: T }
\\struct S0 { m: sampler }
;
try expectError(source, .{
.msg = "invalid struct member type 'T'",
.loc = .{ .start = 30, .end = 31 },
.msg = "invalid struct member type 'sampler'",
.loc = .{ .start = 12, .end = 13 },
});
}
{
@ -285,4 +303,23 @@ test "analyser errors" {
.note = .{ .msg = "other declaration here", .loc = .{ .start = 4, .end = 6 } },
});
}
{
const source = "struct S { m0: vec2<sampler> }";
try expectError(source, .{
.msg = "invalid vector component type",
.loc = .{ .start = 20, .end = 27 },
.note = .{ .msg = "must be 'i32', 'u32', 'f32', 'f16' or 'bool'" },
});
}
{
const source =
\\type T0 = sampler;
\\type T1 = texture_1d<T0>;
;
try expectError(source, .{
.msg = "invalid sampled texture component type",
.loc = .{ .start = 40, .end = 42 },
.note = .{ .msg = "must be 'i32', 'u32' or 'f32'" },
});
}
}