Add astgen scaffolding with ZIR data structures and first passing test
Introduce zir.h/zir.c with ZIR instruction types (269 tags, 56 extended opcodes, 8-byte Data union) ported from lib/std/zig/Zir.zig, and astgen.h/astgen.c implementing the empty-container fast path that produces correct ZIR for empty source files. The test infrastructure in astgen_test.zig compares C astGen() output field-by-field against Zig's std.zig.AstGen.generate() using tag-based dispatch, avoiding raw byte comparison since Zig's Data union has no guaranteed in-memory layout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
69
astgen.c
Normal file
69
astgen.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "astgen.h"
|
||||
#include "common.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Blake3("auto") truncated to 128 bits, as 4 x uint32_t (LE).
|
||||
// This is std.zig.hashSrc("auto") used for the fields_hash of
|
||||
// an empty auto-layout struct.
|
||||
static const uint32_t HASH_AUTO[4]
|
||||
= { 0x8e48032fu, 0x49f070dfu, 0x17991ae1u, 0xa6c4651au };
|
||||
|
||||
// StructDecl.Small packed struct layout (all zero for empty auto):
|
||||
// bits 0-5: booleans (has_captures/fields/decls_len, has_backing_int,
|
||||
// known_non_opv, known_comptime_only)
|
||||
// bits 6-7: name_strategy (parent=0)
|
||||
// bits 8-9: layout (auto=0)
|
||||
// bits 10-12: booleans (any_default_inits/comptime_fields/aligned_fields)
|
||||
// bits 13-15: padding
|
||||
|
||||
Zir astGen(const Ast* ast) {
|
||||
Zir zir;
|
||||
memset(&zir, 0, sizeof(zir));
|
||||
|
||||
// Allocate instruction arrays (1 instruction: root struct_decl).
|
||||
zir.inst_cap = 1;
|
||||
zir.inst_tags = ARR_INIT(ZirInstTag, 1);
|
||||
zir.inst_datas = ARR_INIT(ZirInstData, 1);
|
||||
|
||||
// Allocate extra: 2 reserved + 6 StructDecl payload = 8.
|
||||
zir.extra_cap = 8;
|
||||
zir.extra = ARR_INIT(uint32_t, 8);
|
||||
|
||||
// Allocate string_bytes: 1 byte (reserved index 0).
|
||||
zir.string_bytes_cap = 1;
|
||||
zir.string_bytes = ARR_INIT(uint8_t, 1);
|
||||
zir.string_bytes[0] = 0;
|
||||
zir.string_bytes_len = 1;
|
||||
|
||||
// Reserved extra slots.
|
||||
zir.extra[ZIR_EXTRA_COMPILE_ERRORS] = 0;
|
||||
zir.extra[ZIR_EXTRA_IMPORTS] = 0;
|
||||
zir.extra_len = ZIR_EXTRA_RESERVED_COUNT;
|
||||
|
||||
// StructDecl payload at extra[2..7]:
|
||||
// fields_hash[0..3], src_line, src_node
|
||||
uint32_t payload_index = zir.extra_len;
|
||||
zir.extra[zir.extra_len++] = HASH_AUTO[0];
|
||||
zir.extra[zir.extra_len++] = HASH_AUTO[1];
|
||||
zir.extra[zir.extra_len++] = HASH_AUTO[2];
|
||||
zir.extra[zir.extra_len++] = HASH_AUTO[3];
|
||||
zir.extra[zir.extra_len++] = 0; // src_line
|
||||
zir.extra[zir.extra_len++] = 0; // src_node (root)
|
||||
|
||||
// Instruction 0: extended/struct_decl.
|
||||
ZirInstData data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.extended.opcode = (uint16_t)ZIR_EXT_STRUCT_DECL;
|
||||
data.extended.small = 0; // all flags zero for empty auto struct
|
||||
data.extended.operand = payload_index;
|
||||
|
||||
zir.inst_tags[0] = ZIR_INST_EXTENDED;
|
||||
zir.inst_datas[0] = data;
|
||||
zir.inst_len = 1;
|
||||
|
||||
zir.has_compile_errors = false;
|
||||
|
||||
(void)ast;
|
||||
return zir;
|
||||
}
|
||||
11
astgen.h
Normal file
11
astgen.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// astgen.h — AST to ZIR conversion, ported from lib/std/zig/AstGen.zig.
|
||||
#ifndef _ZIG0_ASTGEN_H__
|
||||
#define _ZIG0_ASTGEN_H__
|
||||
|
||||
#include "ast.h"
|
||||
#include "zir.h"
|
||||
|
||||
// Convert AST to ZIR.
|
||||
Zir astGen(const Ast* ast);
|
||||
|
||||
#endif
|
||||
122
astgen_test.zig
Normal file
122
astgen_test.zig
Normal file
@@ -0,0 +1,122 @@
|
||||
const std = @import("std");
|
||||
const Ast = std.zig.Ast;
|
||||
const Zir = std.zig.Zir;
|
||||
const AstGen = std.zig.AstGen;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const c = @cImport({
|
||||
@cInclude("astgen.h");
|
||||
});
|
||||
|
||||
test "astgen: empty source" {
|
||||
const gpa = std.testing.allocator;
|
||||
|
||||
const source: [:0]const u8 = "";
|
||||
|
||||
// Reference: parse and generate ZIR with Zig.
|
||||
var tree = try Ast.parse(gpa, source, .zig);
|
||||
defer tree.deinit(gpa);
|
||||
var ref_zir = try AstGen.generate(gpa, tree);
|
||||
defer ref_zir.deinit(gpa);
|
||||
|
||||
// Test: parse and generate ZIR with C.
|
||||
var c_ast = c.astParse(source.ptr, @intCast(source.len));
|
||||
defer c.astDeinit(&c_ast);
|
||||
var c_zir = c.astGen(&c_ast);
|
||||
defer c.zirDeinit(&c_zir);
|
||||
|
||||
try expectEqualZir(ref_zir, c_zir);
|
||||
}
|
||||
|
||||
fn expectEqualZir(ref: Zir, got: c.Zir) !void {
|
||||
// Compare instruction count.
|
||||
const ref_len: u32 = @intCast(ref.instructions.len);
|
||||
try std.testing.expectEqual(ref_len, got.inst_len);
|
||||
|
||||
// Compare instructions (tag + data) field-by-field.
|
||||
const ref_tags = ref.instructions.items(.tag);
|
||||
const ref_datas = ref.instructions.items(.data);
|
||||
for (0..ref_len) |i| {
|
||||
const ref_tag: u8 = @intFromEnum(ref_tags[i]);
|
||||
const got_tag: u8 = @intCast(got.inst_tags[i]);
|
||||
if (ref_tag != got_tag) {
|
||||
std.debug.print(
|
||||
"inst_tags[{d}] mismatch: ref={d} got={d}\n",
|
||||
.{ i, ref_tag, got_tag },
|
||||
);
|
||||
return error.TestExpectedEqual;
|
||||
}
|
||||
try expectEqualData(i, ref_tags[i], ref_datas[i], got.inst_datas[i]);
|
||||
}
|
||||
|
||||
// Compare extra data.
|
||||
const ref_extra_len: u32 = @intCast(ref.extra.len);
|
||||
try std.testing.expectEqual(ref_extra_len, got.extra_len);
|
||||
for (0..ref_extra_len) |i| {
|
||||
if (ref.extra[i] != got.extra[i]) {
|
||||
std.debug.print(
|
||||
"extra[{d}] mismatch: ref=0x{x:0>8} got=0x{x:0>8}\n",
|
||||
.{ i, ref.extra[i], got.extra[i] },
|
||||
);
|
||||
return error.TestExpectedEqual;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare string bytes.
|
||||
const ref_sb_len: u32 = @intCast(ref.string_bytes.len);
|
||||
try std.testing.expectEqual(ref_sb_len, got.string_bytes_len);
|
||||
for (0..ref_sb_len) |i| {
|
||||
if (ref.string_bytes[i] != got.string_bytes[i]) {
|
||||
std.debug.print(
|
||||
"string_bytes[{d}] mismatch: ref=0x{x:0>2} got=0x{x:0>2}\n",
|
||||
.{ i, ref.string_bytes[i], got.string_bytes[i] },
|
||||
);
|
||||
return error.TestExpectedEqual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compare a single instruction's data, dispatching by tag.
|
||||
/// Zig's Data union has no guaranteed in-memory layout, so we
|
||||
/// compare each variant's fields individually.
|
||||
fn expectEqualData(
|
||||
idx: usize,
|
||||
tag: Zir.Inst.Tag,
|
||||
ref: Zir.Inst.Data,
|
||||
got: c.ZirInstData,
|
||||
) !void {
|
||||
switch (tag) {
|
||||
.extended => {
|
||||
const r = ref.extended;
|
||||
const g = got.extended;
|
||||
if (@intFromEnum(r.opcode) != g.opcode or
|
||||
r.small != g.small or
|
||||
r.operand != g.operand)
|
||||
{
|
||||
std.debug.print(
|
||||
"inst_datas[{d}] (extended) mismatch:\n" ++
|
||||
" ref: opcode={d} small=0x{x:0>4} operand={d}\n" ++
|
||||
" got: opcode={d} small=0x{x:0>4} operand={d}\n",
|
||||
.{
|
||||
idx,
|
||||
@intFromEnum(r.opcode),
|
||||
r.small,
|
||||
r.operand,
|
||||
g.opcode,
|
||||
g.small,
|
||||
g.operand,
|
||||
},
|
||||
);
|
||||
return error.TestExpectedEqual;
|
||||
}
|
||||
},
|
||||
// Add more tag handlers as AstGen implementation grows.
|
||||
else => {
|
||||
std.debug.print(
|
||||
"inst_datas[{d}]: unhandled tag {d} in comparison\n",
|
||||
.{ idx, @intFromEnum(tag) },
|
||||
);
|
||||
return error.TestUnexpectedResult;
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ const headers = &[_][]const u8{
|
||||
"common.h",
|
||||
"ast.h",
|
||||
"parser.h",
|
||||
"zir.h",
|
||||
"astgen.h",
|
||||
};
|
||||
|
||||
const c_lib_files = &[_][]const u8{
|
||||
@@ -12,6 +14,8 @@ const c_lib_files = &[_][]const u8{
|
||||
"ast.c",
|
||||
"zig0.c",
|
||||
"parser.c",
|
||||
"zir.c",
|
||||
"astgen.c",
|
||||
};
|
||||
|
||||
const all_c_files = c_lib_files ++ &[_][]const u8{"main.c"};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
test "zig0 test suite" {
|
||||
_ = @import("tokenizer_test.zig");
|
||||
_ = @import("parser_test.zig");
|
||||
_ = @import("astgen_test.zig");
|
||||
}
|
||||
|
||||
19
zir.c
Normal file
19
zir.c
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "zir.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void zirDeinit(Zir* zir) {
|
||||
free(zir->inst_tags);
|
||||
free(zir->inst_datas);
|
||||
free(zir->extra);
|
||||
free(zir->string_bytes);
|
||||
zir->inst_tags = NULL;
|
||||
zir->inst_datas = NULL;
|
||||
zir->extra = NULL;
|
||||
zir->string_bytes = NULL;
|
||||
zir->inst_len = 0;
|
||||
zir->inst_cap = 0;
|
||||
zir->extra_len = 0;
|
||||
zir->extra_cap = 0;
|
||||
zir->string_bytes_len = 0;
|
||||
zir->string_bytes_cap = 0;
|
||||
}
|
||||
466
zir.h
Normal file
466
zir.h
Normal file
@@ -0,0 +1,466 @@
|
||||
// zir.h — ZIR data structures, ported from lib/std/zig/Zir.zig.
|
||||
#ifndef _ZIG0_ZIR_H__
|
||||
#define _ZIG0_ZIR_H__
|
||||
|
||||
#include "common.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// --- ZIR instruction tags (uint8_t) ---
|
||||
// Matches Zir.Inst.Tag enum order from Zir.zig.
|
||||
|
||||
#define ZIR_INST_FOREACH_TAG(TAG) \
|
||||
TAG(ZIR_INST_ADD) \
|
||||
TAG(ZIR_INST_ADDWRAP) \
|
||||
TAG(ZIR_INST_ADD_SAT) \
|
||||
TAG(ZIR_INST_ADD_UNSAFE) \
|
||||
TAG(ZIR_INST_SUB) \
|
||||
TAG(ZIR_INST_SUBWRAP) \
|
||||
TAG(ZIR_INST_SUB_SAT) \
|
||||
TAG(ZIR_INST_MUL) \
|
||||
TAG(ZIR_INST_MULWRAP) \
|
||||
TAG(ZIR_INST_MUL_SAT) \
|
||||
TAG(ZIR_INST_DIV_EXACT) \
|
||||
TAG(ZIR_INST_DIV_FLOOR) \
|
||||
TAG(ZIR_INST_DIV_TRUNC) \
|
||||
TAG(ZIR_INST_MOD) \
|
||||
TAG(ZIR_INST_REM) \
|
||||
TAG(ZIR_INST_MOD_REM) \
|
||||
TAG(ZIR_INST_SHL) \
|
||||
TAG(ZIR_INST_SHL_EXACT) \
|
||||
TAG(ZIR_INST_SHL_SAT) \
|
||||
TAG(ZIR_INST_SHR) \
|
||||
TAG(ZIR_INST_SHR_EXACT) \
|
||||
TAG(ZIR_INST_PARAM) \
|
||||
TAG(ZIR_INST_PARAM_COMPTIME) \
|
||||
TAG(ZIR_INST_PARAM_ANYTYPE) \
|
||||
TAG(ZIR_INST_PARAM_ANYTYPE_COMPTIME) \
|
||||
TAG(ZIR_INST_ARRAY_CAT) \
|
||||
TAG(ZIR_INST_ARRAY_MUL) \
|
||||
TAG(ZIR_INST_ARRAY_TYPE) \
|
||||
TAG(ZIR_INST_ARRAY_TYPE_SENTINEL) \
|
||||
TAG(ZIR_INST_VECTOR_TYPE) \
|
||||
TAG(ZIR_INST_ELEM_TYPE) \
|
||||
TAG(ZIR_INST_INDEXABLE_PTR_ELEM_TYPE) \
|
||||
TAG(ZIR_INST_SPLAT_OP_RESULT_TY) \
|
||||
TAG(ZIR_INST_INDEXABLE_PTR_LEN) \
|
||||
TAG(ZIR_INST_ANYFRAME_TYPE) \
|
||||
TAG(ZIR_INST_AS_NODE) \
|
||||
TAG(ZIR_INST_AS_SHIFT_OPERAND) \
|
||||
TAG(ZIR_INST_BIT_AND) \
|
||||
TAG(ZIR_INST_BITCAST) \
|
||||
TAG(ZIR_INST_BIT_NOT) \
|
||||
TAG(ZIR_INST_BIT_OR) \
|
||||
TAG(ZIR_INST_BLOCK) \
|
||||
TAG(ZIR_INST_BLOCK_COMPTIME) \
|
||||
TAG(ZIR_INST_BLOCK_INLINE) \
|
||||
TAG(ZIR_INST_DECLARATION) \
|
||||
TAG(ZIR_INST_SUSPEND_BLOCK) \
|
||||
TAG(ZIR_INST_BOOL_NOT) \
|
||||
TAG(ZIR_INST_BOOL_BR_AND) \
|
||||
TAG(ZIR_INST_BOOL_BR_OR) \
|
||||
TAG(ZIR_INST_BREAK) \
|
||||
TAG(ZIR_INST_BREAK_INLINE) \
|
||||
TAG(ZIR_INST_SWITCH_CONTINUE) \
|
||||
TAG(ZIR_INST_CHECK_COMPTIME_CONTROL_FLOW) \
|
||||
TAG(ZIR_INST_CALL) \
|
||||
TAG(ZIR_INST_FIELD_CALL) \
|
||||
TAG(ZIR_INST_BUILTIN_CALL) \
|
||||
TAG(ZIR_INST_CMP_LT) \
|
||||
TAG(ZIR_INST_CMP_LTE) \
|
||||
TAG(ZIR_INST_CMP_EQ) \
|
||||
TAG(ZIR_INST_CMP_GTE) \
|
||||
TAG(ZIR_INST_CMP_GT) \
|
||||
TAG(ZIR_INST_CMP_NEQ) \
|
||||
TAG(ZIR_INST_CONDBR) \
|
||||
TAG(ZIR_INST_CONDBR_INLINE) \
|
||||
TAG(ZIR_INST_TRY) \
|
||||
TAG(ZIR_INST_TRY_PTR) \
|
||||
TAG(ZIR_INST_ERROR_SET_DECL) \
|
||||
TAG(ZIR_INST_DBG_STMT) \
|
||||
TAG(ZIR_INST_DBG_VAR_PTR) \
|
||||
TAG(ZIR_INST_DBG_VAR_VAL) \
|
||||
TAG(ZIR_INST_DECL_REF) \
|
||||
TAG(ZIR_INST_DECL_VAL) \
|
||||
TAG(ZIR_INST_LOAD) \
|
||||
TAG(ZIR_INST_DIV) \
|
||||
TAG(ZIR_INST_ELEM_PTR_NODE) \
|
||||
TAG(ZIR_INST_ELEM_PTR) \
|
||||
TAG(ZIR_INST_ELEM_VAL_NODE) \
|
||||
TAG(ZIR_INST_ELEM_VAL) \
|
||||
TAG(ZIR_INST_ELEM_VAL_IMM) \
|
||||
TAG(ZIR_INST_ENSURE_RESULT_USED) \
|
||||
TAG(ZIR_INST_ENSURE_RESULT_NON_ERROR) \
|
||||
TAG(ZIR_INST_ENSURE_ERR_UNION_PAYLOAD_VOID) \
|
||||
TAG(ZIR_INST_ERROR_UNION_TYPE) \
|
||||
TAG(ZIR_INST_ERROR_VALUE) \
|
||||
TAG(ZIR_INST_EXPORT) \
|
||||
TAG(ZIR_INST_FIELD_PTR) \
|
||||
TAG(ZIR_INST_FIELD_VAL) \
|
||||
TAG(ZIR_INST_FIELD_PTR_NAMED) \
|
||||
TAG(ZIR_INST_FIELD_VAL_NAMED) \
|
||||
TAG(ZIR_INST_FUNC) \
|
||||
TAG(ZIR_INST_FUNC_INFERRED) \
|
||||
TAG(ZIR_INST_FUNC_FANCY) \
|
||||
TAG(ZIR_INST_IMPORT) \
|
||||
TAG(ZIR_INST_INT) \
|
||||
TAG(ZIR_INST_INT_BIG) \
|
||||
TAG(ZIR_INST_FLOAT) \
|
||||
TAG(ZIR_INST_FLOAT128) \
|
||||
TAG(ZIR_INST_INT_TYPE) \
|
||||
TAG(ZIR_INST_IS_NON_NULL) \
|
||||
TAG(ZIR_INST_IS_NON_NULL_PTR) \
|
||||
TAG(ZIR_INST_IS_NON_ERR) \
|
||||
TAG(ZIR_INST_IS_NON_ERR_PTR) \
|
||||
TAG(ZIR_INST_RET_IS_NON_ERR) \
|
||||
TAG(ZIR_INST_LOOP) \
|
||||
TAG(ZIR_INST_REPEAT) \
|
||||
TAG(ZIR_INST_REPEAT_INLINE) \
|
||||
TAG(ZIR_INST_FOR_LEN) \
|
||||
TAG(ZIR_INST_MERGE_ERROR_SETS) \
|
||||
TAG(ZIR_INST_REF) \
|
||||
TAG(ZIR_INST_RET_NODE) \
|
||||
TAG(ZIR_INST_RET_LOAD) \
|
||||
TAG(ZIR_INST_RET_IMPLICIT) \
|
||||
TAG(ZIR_INST_RET_ERR_VALUE) \
|
||||
TAG(ZIR_INST_RET_ERR_VALUE_CODE) \
|
||||
TAG(ZIR_INST_RET_PTR) \
|
||||
TAG(ZIR_INST_RET_TYPE) \
|
||||
TAG(ZIR_INST_PTR_TYPE) \
|
||||
TAG(ZIR_INST_SLICE_START) \
|
||||
TAG(ZIR_INST_SLICE_END) \
|
||||
TAG(ZIR_INST_SLICE_SENTINEL) \
|
||||
TAG(ZIR_INST_SLICE_LENGTH) \
|
||||
TAG(ZIR_INST_SLICE_SENTINEL_TY) \
|
||||
TAG(ZIR_INST_STORE_NODE) \
|
||||
TAG(ZIR_INST_STORE_TO_INFERRED_PTR) \
|
||||
TAG(ZIR_INST_STR) \
|
||||
TAG(ZIR_INST_NEGATE) \
|
||||
TAG(ZIR_INST_NEGATE_WRAP) \
|
||||
TAG(ZIR_INST_TYPEOF) \
|
||||
TAG(ZIR_INST_TYPEOF_BUILTIN) \
|
||||
TAG(ZIR_INST_TYPEOF_LOG2_INT_TYPE) \
|
||||
TAG(ZIR_INST_UNREACHABLE) \
|
||||
TAG(ZIR_INST_XOR) \
|
||||
TAG(ZIR_INST_OPTIONAL_TYPE) \
|
||||
TAG(ZIR_INST_OPTIONAL_PAYLOAD_SAFE) \
|
||||
TAG(ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE) \
|
||||
TAG(ZIR_INST_OPTIONAL_PAYLOAD_SAFE_PTR) \
|
||||
TAG(ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE_PTR) \
|
||||
TAG(ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE) \
|
||||
TAG(ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE_PTR) \
|
||||
TAG(ZIR_INST_ERR_UNION_CODE) \
|
||||
TAG(ZIR_INST_ERR_UNION_CODE_PTR) \
|
||||
TAG(ZIR_INST_ENUM_LITERAL) \
|
||||
TAG(ZIR_INST_DECL_LITERAL) \
|
||||
TAG(ZIR_INST_DECL_LITERAL_NO_COERCE) \
|
||||
TAG(ZIR_INST_SWITCH_BLOCK) \
|
||||
TAG(ZIR_INST_SWITCH_BLOCK_REF) \
|
||||
TAG(ZIR_INST_SWITCH_BLOCK_ERR_UNION) \
|
||||
TAG(ZIR_INST_VALIDATE_DEREF) \
|
||||
TAG(ZIR_INST_VALIDATE_DESTRUCTURE) \
|
||||
TAG(ZIR_INST_FIELD_TYPE_REF) \
|
||||
TAG(ZIR_INST_OPT_EU_BASE_PTR_INIT) \
|
||||
TAG(ZIR_INST_COERCE_PTR_ELEM_TY) \
|
||||
TAG(ZIR_INST_VALIDATE_REF_TY) \
|
||||
TAG(ZIR_INST_VALIDATE_CONST) \
|
||||
TAG(ZIR_INST_STRUCT_INIT_EMPTY) \
|
||||
TAG(ZIR_INST_STRUCT_INIT_EMPTY_RESULT) \
|
||||
TAG(ZIR_INST_STRUCT_INIT_EMPTY_REF_RESULT) \
|
||||
TAG(ZIR_INST_STRUCT_INIT_ANON) \
|
||||
TAG(ZIR_INST_STRUCT_INIT) \
|
||||
TAG(ZIR_INST_STRUCT_INIT_REF) \
|
||||
TAG(ZIR_INST_VALIDATE_STRUCT_INIT_TY) \
|
||||
TAG(ZIR_INST_VALIDATE_STRUCT_INIT_RESULT_TY) \
|
||||
TAG(ZIR_INST_VALIDATE_PTR_STRUCT_INIT) \
|
||||
TAG(ZIR_INST_STRUCT_INIT_FIELD_TYPE) \
|
||||
TAG(ZIR_INST_STRUCT_INIT_FIELD_PTR) \
|
||||
TAG(ZIR_INST_ARRAY_INIT_ANON) \
|
||||
TAG(ZIR_INST_ARRAY_INIT) \
|
||||
TAG(ZIR_INST_ARRAY_INIT_REF) \
|
||||
TAG(ZIR_INST_VALIDATE_ARRAY_INIT_TY) \
|
||||
TAG(ZIR_INST_VALIDATE_ARRAY_INIT_RESULT_TY) \
|
||||
TAG(ZIR_INST_VALIDATE_ARRAY_INIT_REF_TY) \
|
||||
TAG(ZIR_INST_VALIDATE_PTR_ARRAY_INIT) \
|
||||
TAG(ZIR_INST_ARRAY_INIT_ELEM_TYPE) \
|
||||
TAG(ZIR_INST_ARRAY_INIT_ELEM_PTR) \
|
||||
TAG(ZIR_INST_UNION_INIT) \
|
||||
TAG(ZIR_INST_TYPE_INFO) \
|
||||
TAG(ZIR_INST_SIZE_OF) \
|
||||
TAG(ZIR_INST_BIT_SIZE_OF) \
|
||||
TAG(ZIR_INST_INT_FROM_PTR) \
|
||||
TAG(ZIR_INST_COMPILE_ERROR) \
|
||||
TAG(ZIR_INST_SET_EVAL_BRANCH_QUOTA) \
|
||||
TAG(ZIR_INST_INT_FROM_ENUM) \
|
||||
TAG(ZIR_INST_ALIGN_OF) \
|
||||
TAG(ZIR_INST_INT_FROM_BOOL) \
|
||||
TAG(ZIR_INST_EMBED_FILE) \
|
||||
TAG(ZIR_INST_ERROR_NAME) \
|
||||
TAG(ZIR_INST_PANIC) \
|
||||
TAG(ZIR_INST_TRAP) \
|
||||
TAG(ZIR_INST_SET_RUNTIME_SAFETY) \
|
||||
TAG(ZIR_INST_SQRT) \
|
||||
TAG(ZIR_INST_SIN) \
|
||||
TAG(ZIR_INST_COS) \
|
||||
TAG(ZIR_INST_TAN) \
|
||||
TAG(ZIR_INST_EXP) \
|
||||
TAG(ZIR_INST_EXP2) \
|
||||
TAG(ZIR_INST_LOG) \
|
||||
TAG(ZIR_INST_LOG2) \
|
||||
TAG(ZIR_INST_LOG10) \
|
||||
TAG(ZIR_INST_ABS) \
|
||||
TAG(ZIR_INST_FLOOR) \
|
||||
TAG(ZIR_INST_CEIL) \
|
||||
TAG(ZIR_INST_TRUNC) \
|
||||
TAG(ZIR_INST_ROUND) \
|
||||
TAG(ZIR_INST_TAG_NAME) \
|
||||
TAG(ZIR_INST_TYPE_NAME) \
|
||||
TAG(ZIR_INST_FRAME_TYPE) \
|
||||
TAG(ZIR_INST_INT_FROM_FLOAT) \
|
||||
TAG(ZIR_INST_FLOAT_FROM_INT) \
|
||||
TAG(ZIR_INST_PTR_FROM_INT) \
|
||||
TAG(ZIR_INST_ENUM_FROM_INT) \
|
||||
TAG(ZIR_INST_FLOAT_CAST) \
|
||||
TAG(ZIR_INST_INT_CAST) \
|
||||
TAG(ZIR_INST_PTR_CAST) \
|
||||
TAG(ZIR_INST_TRUNCATE) \
|
||||
TAG(ZIR_INST_HAS_DECL) \
|
||||
TAG(ZIR_INST_HAS_FIELD) \
|
||||
TAG(ZIR_INST_CLZ) \
|
||||
TAG(ZIR_INST_CTZ) \
|
||||
TAG(ZIR_INST_POP_COUNT) \
|
||||
TAG(ZIR_INST_BYTE_SWAP) \
|
||||
TAG(ZIR_INST_BIT_REVERSE) \
|
||||
TAG(ZIR_INST_BIT_OFFSET_OF) \
|
||||
TAG(ZIR_INST_OFFSET_OF) \
|
||||
TAG(ZIR_INST_SPLAT) \
|
||||
TAG(ZIR_INST_REDUCE) \
|
||||
TAG(ZIR_INST_SHUFFLE) \
|
||||
TAG(ZIR_INST_ATOMIC_LOAD) \
|
||||
TAG(ZIR_INST_ATOMIC_RMW) \
|
||||
TAG(ZIR_INST_ATOMIC_STORE) \
|
||||
TAG(ZIR_INST_MUL_ADD) \
|
||||
TAG(ZIR_INST_MEMCPY) \
|
||||
TAG(ZIR_INST_MEMMOVE) \
|
||||
TAG(ZIR_INST_MEMSET) \
|
||||
TAG(ZIR_INST_MIN) \
|
||||
TAG(ZIR_INST_MAX) \
|
||||
TAG(ZIR_INST_C_IMPORT) \
|
||||
TAG(ZIR_INST_ALLOC) \
|
||||
TAG(ZIR_INST_ALLOC_MUT) \
|
||||
TAG(ZIR_INST_ALLOC_COMPTIME_MUT) \
|
||||
TAG(ZIR_INST_ALLOC_INFERRED) \
|
||||
TAG(ZIR_INST_ALLOC_INFERRED_MUT) \
|
||||
TAG(ZIR_INST_ALLOC_INFERRED_COMPTIME) \
|
||||
TAG(ZIR_INST_ALLOC_INFERRED_COMPTIME_MUT) \
|
||||
TAG(ZIR_INST_RESOLVE_INFERRED_ALLOC) \
|
||||
TAG(ZIR_INST_MAKE_PTR_CONST) \
|
||||
TAG(ZIR_INST_RESUME) \
|
||||
TAG(ZIR_INST_DEFER) \
|
||||
TAG(ZIR_INST_DEFER_ERR_CODE) \
|
||||
TAG(ZIR_INST_SAVE_ERR_RET_INDEX) \
|
||||
TAG(ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL) \
|
||||
TAG(ZIR_INST_RESTORE_ERR_RET_INDEX_FN_ENTRY) \
|
||||
TAG(ZIR_INST_EXTENDED)
|
||||
|
||||
#define ZIR_GENERATE_ENUM(e) e,
|
||||
typedef enum { ZIR_INST_FOREACH_TAG(ZIR_GENERATE_ENUM) } ZirInstTag;
|
||||
|
||||
// --- ZIR extended opcodes (uint16_t) ---
|
||||
// Matches Zir.Inst.Extended enum order from Zir.zig.
|
||||
|
||||
#define ZIR_EXT_FOREACH_TAG(TAG) \
|
||||
TAG(ZIR_EXT_STRUCT_DECL) \
|
||||
TAG(ZIR_EXT_ENUM_DECL) \
|
||||
TAG(ZIR_EXT_UNION_DECL) \
|
||||
TAG(ZIR_EXT_OPAQUE_DECL) \
|
||||
TAG(ZIR_EXT_TUPLE_DECL) \
|
||||
TAG(ZIR_EXT_THIS) \
|
||||
TAG(ZIR_EXT_RET_ADDR) \
|
||||
TAG(ZIR_EXT_BUILTIN_SRC) \
|
||||
TAG(ZIR_EXT_ERROR_RETURN_TRACE) \
|
||||
TAG(ZIR_EXT_FRAME) \
|
||||
TAG(ZIR_EXT_FRAME_ADDRESS) \
|
||||
TAG(ZIR_EXT_ALLOC) \
|
||||
TAG(ZIR_EXT_BUILTIN_EXTERN) \
|
||||
TAG(ZIR_EXT_ASM) \
|
||||
TAG(ZIR_EXT_ASM_EXPR) \
|
||||
TAG(ZIR_EXT_COMPILE_LOG) \
|
||||
TAG(ZIR_EXT_TYPEOF_PEER) \
|
||||
TAG(ZIR_EXT_MIN_MULTI) \
|
||||
TAG(ZIR_EXT_MAX_MULTI) \
|
||||
TAG(ZIR_EXT_ADD_WITH_OVERFLOW) \
|
||||
TAG(ZIR_EXT_SUB_WITH_OVERFLOW) \
|
||||
TAG(ZIR_EXT_MUL_WITH_OVERFLOW) \
|
||||
TAG(ZIR_EXT_SHL_WITH_OVERFLOW) \
|
||||
TAG(ZIR_EXT_C_UNDEF) \
|
||||
TAG(ZIR_EXT_C_INCLUDE) \
|
||||
TAG(ZIR_EXT_C_DEFINE) \
|
||||
TAG(ZIR_EXT_WASM_MEMORY_SIZE) \
|
||||
TAG(ZIR_EXT_WASM_MEMORY_GROW) \
|
||||
TAG(ZIR_EXT_PREFETCH) \
|
||||
TAG(ZIR_EXT_SET_FLOAT_MODE) \
|
||||
TAG(ZIR_EXT_ERROR_CAST) \
|
||||
TAG(ZIR_EXT_BREAKPOINT) \
|
||||
TAG(ZIR_EXT_DISABLE_INSTRUMENTATION) \
|
||||
TAG(ZIR_EXT_DISABLE_INTRINSICS) \
|
||||
TAG(ZIR_EXT_SELECT) \
|
||||
TAG(ZIR_EXT_INT_FROM_ERROR) \
|
||||
TAG(ZIR_EXT_ERROR_FROM_INT) \
|
||||
TAG(ZIR_EXT_REIFY) \
|
||||
TAG(ZIR_EXT_CMPXCHG) \
|
||||
TAG(ZIR_EXT_C_VA_ARG) \
|
||||
TAG(ZIR_EXT_C_VA_COPY) \
|
||||
TAG(ZIR_EXT_C_VA_END) \
|
||||
TAG(ZIR_EXT_C_VA_START) \
|
||||
TAG(ZIR_EXT_PTR_CAST_FULL) \
|
||||
TAG(ZIR_EXT_PTR_CAST_NO_DEST) \
|
||||
TAG(ZIR_EXT_WORK_ITEM_ID) \
|
||||
TAG(ZIR_EXT_WORK_GROUP_SIZE) \
|
||||
TAG(ZIR_EXT_WORK_GROUP_ID) \
|
||||
TAG(ZIR_EXT_IN_COMPTIME) \
|
||||
TAG(ZIR_EXT_RESTORE_ERR_RET_INDEX) \
|
||||
TAG(ZIR_EXT_CLOSURE_GET) \
|
||||
TAG(ZIR_EXT_VALUE_PLACEHOLDER) \
|
||||
TAG(ZIR_EXT_FIELD_PARENT_PTR) \
|
||||
TAG(ZIR_EXT_BUILTIN_VALUE) \
|
||||
TAG(ZIR_EXT_BRANCH_HINT) \
|
||||
TAG(ZIR_EXT_INPLACE_ARITH_RESULT_TY) \
|
||||
TAG(ZIR_EXT_DBG_EMPTY_STMT) \
|
||||
TAG(ZIR_EXT_ASTGEN_ERROR)
|
||||
|
||||
#define ZIR_EXT_GENERATE_ENUM(e) e,
|
||||
typedef enum { ZIR_EXT_FOREACH_TAG(ZIR_EXT_GENERATE_ENUM) } ZirInstExtended;
|
||||
|
||||
// --- ZIR instruction data (8-byte union) ---
|
||||
// Matches Zir.Inst.Data union from Zir.zig.
|
||||
|
||||
typedef uint32_t ZirInstIndex;
|
||||
typedef uint32_t ZirInstRef;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint16_t opcode;
|
||||
uint16_t small;
|
||||
uint32_t operand;
|
||||
} extended;
|
||||
struct {
|
||||
int32_t src_node;
|
||||
ZirInstRef operand;
|
||||
} un_node;
|
||||
struct {
|
||||
int32_t src_tok;
|
||||
ZirInstRef operand;
|
||||
} un_tok;
|
||||
struct {
|
||||
int32_t src_node;
|
||||
uint32_t payload_index;
|
||||
} pl_node;
|
||||
struct {
|
||||
int32_t src_tok;
|
||||
uint32_t payload_index;
|
||||
} pl_tok;
|
||||
struct {
|
||||
ZirInstRef lhs;
|
||||
ZirInstRef rhs;
|
||||
} bin;
|
||||
struct {
|
||||
uint32_t start;
|
||||
uint32_t len;
|
||||
} str;
|
||||
struct {
|
||||
uint32_t start;
|
||||
int32_t src_tok;
|
||||
} str_tok;
|
||||
int32_t tok;
|
||||
int32_t node;
|
||||
uint64_t int_val;
|
||||
double float_val;
|
||||
struct {
|
||||
uint8_t flags;
|
||||
uint8_t size;
|
||||
uint16_t _pad;
|
||||
uint32_t payload_index;
|
||||
} ptr_type;
|
||||
struct {
|
||||
int32_t src_node;
|
||||
uint8_t signedness;
|
||||
uint8_t _pad;
|
||||
uint16_t bit_count;
|
||||
} int_type;
|
||||
struct {
|
||||
int32_t src_node;
|
||||
uint32_t _pad;
|
||||
} unreachable_data;
|
||||
struct {
|
||||
ZirInstRef operand;
|
||||
uint32_t payload_index;
|
||||
} break_data;
|
||||
struct {
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
} dbg_stmt;
|
||||
struct {
|
||||
int32_t src_node;
|
||||
ZirInstIndex inst;
|
||||
} inst_node;
|
||||
struct {
|
||||
uint32_t str;
|
||||
ZirInstRef operand;
|
||||
} str_op;
|
||||
struct {
|
||||
uint32_t index;
|
||||
uint32_t len;
|
||||
} defer_data;
|
||||
struct {
|
||||
ZirInstRef err_code;
|
||||
uint32_t payload_index;
|
||||
} defer_err_code;
|
||||
struct {
|
||||
ZirInstRef operand;
|
||||
uint32_t _pad;
|
||||
} save_err_ret_index;
|
||||
struct {
|
||||
ZirInstRef operand;
|
||||
uint32_t idx;
|
||||
} elem_val_imm;
|
||||
struct {
|
||||
uint32_t src_node;
|
||||
uint32_t payload_index;
|
||||
} declaration;
|
||||
} ZirInstData;
|
||||
|
||||
// --- ZIR built-in refs ---
|
||||
// Matches Zir.Inst.Ref enum from Zir.zig.
|
||||
// Values below REF_START_INDEX are InternPool indices.
|
||||
|
||||
#define ZIR_REF_START_INDEX 124
|
||||
#define ZIR_REF_NONE UINT32_MAX
|
||||
#define ZIR_MAIN_STRUCT_INST 0
|
||||
|
||||
// --- Extra indices reserved at the start of extra[] ---
|
||||
// Matches Zir.ExtraIndex enum from Zir.zig.
|
||||
|
||||
#define ZIR_EXTRA_COMPILE_ERRORS 0
|
||||
#define ZIR_EXTRA_IMPORTS 1
|
||||
#define ZIR_EXTRA_RESERVED_COUNT 2
|
||||
|
||||
// --- Zir output structure ---
|
||||
|
||||
typedef struct {
|
||||
uint32_t inst_len;
|
||||
uint32_t inst_cap;
|
||||
ZirInstTag* inst_tags;
|
||||
ZirInstData* inst_datas;
|
||||
uint32_t extra_len;
|
||||
uint32_t extra_cap;
|
||||
uint32_t* extra;
|
||||
uint32_t string_bytes_len;
|
||||
uint32_t string_bytes_cap;
|
||||
uint8_t* string_bytes;
|
||||
bool has_compile_errors;
|
||||
} Zir;
|
||||
|
||||
void zirDeinit(Zir* zir);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user