diff --git a/CMakeLists.txt b/CMakeLists.txt index b53ab0a2b5b0c9a5b4d65a28ac5bd5be3ed3be7e..ceb5a83a0cb030577f749401204bd8963a5a5879 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -508,6 +508,7 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/unicode.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/Ast.zig" + "${CMAKE_SOURCE_DIR}/lib/std/zig/AstRlAnnotate.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/CrossTarget.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/c_builtins.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/Parse.zig" @@ -521,7 +522,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/zig/tokenizer.zig" "${CMAKE_SOURCE_DIR}/src/Air.zig" "${CMAKE_SOURCE_DIR}/src/AstGen.zig" - "${CMAKE_SOURCE_DIR}/src/AstRlAnnotate.zig" "${CMAKE_SOURCE_DIR}/src/Compilation.zig" "${CMAKE_SOURCE_DIR}/src/Liveness.zig" "${CMAKE_SOURCE_DIR}/src/Module.zig" diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 85d1ae4868d57ed586bf534bfc3cbf6b6df0925d..2d2aaf17ba40d0c673af65ef917c51bbea19fbd4 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -17,6 +17,8 @@ pub const primitives = @import("zig/primitives.zig"); pub const Ast = @import("zig/Ast.zig"); pub const system = @import("zig/system.zig"); pub const CrossTarget = @import("zig/CrossTarget.zig"); +pub const BuiltinFn = @import("zig/BuiltinFn.zig"); +pub const AstRlAnnotate = @import("zig/AstRlAnnotate.zig"); // Character literal parsing pub const ParsedCharLiteral = string_literal.ParsedCharLiteral; diff --git a/lib/std/zig/AstRlAnnotate.zig b/lib/std/zig/AstRlAnnotate.zig new file mode 100644 index 0000000000000000000000000000000000000000..a43de68951c124ce6a37a8cc865b12ba91bc48db --- /dev/null +++ b/lib/std/zig/AstRlAnnotate.zig @@ -0,0 +1,1105 @@ +//! AstRlAnnotate is a simple pass which runs over the AST before AstGen to +//! determine which expressions require result locations. +//! +//! In some cases, AstGen can choose whether to provide a result pointer or to +//! just use standard `break` instructions from a block. The latter choice can +//! result in more efficient ZIR and runtime code, but does not allow for RLS to +//! occur. Thus, we want to provide a real result pointer (from an alloc) only +//! when necessary. +//! +//! To achive this, we need to determine which expressions require a result +//! pointer. This pass is reponsible for analyzing all syntax forms which may +//! provide a result location and, if sub-expressions consume this result +//! pointer non-trivially (e.g. writing through field pointers), marking the +//! node as requiring a result location. + +const std = @import("std"); +const AstRlAnnotate = @This(); +const Ast = std.zig.Ast; +const Allocator = std.mem.Allocator; +const AutoHashMapUnmanaged = std.AutoHashMapUnmanaged; +const BuiltinFn = std.zig.BuiltinFn; +const assert = std.debug.assert; + +gpa: Allocator, +arena: Allocator, +tree: *const Ast, + +/// Certain nodes are placed in this set under the following conditions: +/// * if-else: either branch consumes the result location +/// * labeled block: any break consumes the result location +/// * switch: any prong consumes the result location +/// * orelse/catch: the RHS expression consumes the result location +/// * while/for: any break consumes the result location +/// * @as: the second operand consumes the result location +/// * const: the init expression consumes the result location +/// * return: the return expression consumes the result location +nodes_need_rl: RlNeededSet = .{}, + +pub const RlNeededSet = AutoHashMapUnmanaged(Ast.Node.Index, void); + +const ResultInfo = packed struct { + /// Do we have a known result type? + have_type: bool, + /// Do we (potentially) have a result pointer? Note that this pointer's type + /// may not be known due to it being an inferred alloc. + have_ptr: bool, + + const none: ResultInfo = .{ .have_type = false, .have_ptr = false }; + const typed_ptr: ResultInfo = .{ .have_type = true, .have_ptr = true }; + const inferred_ptr: ResultInfo = .{ .have_type = false, .have_ptr = true }; + const type_only: ResultInfo = .{ .have_type = true, .have_ptr = false }; +}; + +/// A labeled block or a loop. When this block is broken from, `consumes_res_ptr` +/// should be set if the break expression consumed the result pointer. +const Block = struct { + parent: ?*Block, + label: ?[]const u8, + is_loop: bool, + ri: ResultInfo, + consumes_res_ptr: bool, +}; + +pub fn annotate(gpa: Allocator, arena: Allocator, tree: Ast) Allocator.Error!RlNeededSet { + var astrl: AstRlAnnotate = .{ + .gpa = gpa, + .arena = arena, + .tree = &tree, + }; + defer astrl.deinit(gpa); + + if (tree.errors.len != 0) { + // We can't perform analysis on a broken AST. AstGen will not run in + // this case. + return .{}; + } + + for (tree.containerDeclRoot().ast.members) |member_node| { + _ = try astrl.expr(member_node, null, ResultInfo.none); + } + + return astrl.nodes_need_rl.move(); +} + +fn deinit(astrl: *AstRlAnnotate, gpa: Allocator) void { + astrl.nodes_need_rl.deinit(gpa); +} + +fn containerDecl( + astrl: *AstRlAnnotate, + block: ?*Block, + full: Ast.full.ContainerDecl, +) !void { + const tree = astrl.tree; + const token_tags = tree.tokens.items(.tag); + switch (token_tags[full.ast.main_token]) { + .keyword_struct => { + if (full.ast.arg != 0) { + _ = try astrl.expr(full.ast.arg, block, ResultInfo.type_only); + } + for (full.ast.members) |member_node| { + _ = try astrl.expr(member_node, block, ResultInfo.none); + } + }, + .keyword_union => { + if (full.ast.arg != 0) { + _ = try astrl.expr(full.ast.arg, block, ResultInfo.type_only); + } + for (full.ast.members) |member_node| { + _ = try astrl.expr(member_node, block, ResultInfo.none); + } + }, + .keyword_enum => { + if (full.ast.arg != 0) { + _ = try astrl.expr(full.ast.arg, block, ResultInfo.type_only); + } + for (full.ast.members) |member_node| { + _ = try astrl.expr(member_node, block, ResultInfo.none); + } + }, + .keyword_opaque => { + for (full.ast.members) |member_node| { + _ = try astrl.expr(member_node, block, ResultInfo.none); + } + }, + else => unreachable, + } +} + +/// Returns true if `rl` provides a result pointer and the expression consumes it. +fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultInfo) Allocator.Error!bool { + const tree = astrl.tree; + const token_tags = tree.tokens.items(.tag); + const node_datas = tree.nodes.items(.data); + const node_tags = tree.nodes.items(.tag); + switch (node_tags[node]) { + .root, + .switch_case_one, + .switch_case_inline_one, + .switch_case, + .switch_case_inline, + .switch_range, + .for_range, + .asm_output, + .asm_input, + => unreachable, + + .@"errdefer", .@"defer" => { + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); + return false; + }, + + .container_field_init, + .container_field_align, + .container_field, + => { + const full = tree.fullContainerField(node).?; + _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.type_only); + if (full.ast.align_expr != 0) { + _ = try astrl.expr(full.ast.align_expr, block, ResultInfo.type_only); + } + if (full.ast.value_expr != 0) { + _ = try astrl.expr(full.ast.value_expr, block, ResultInfo.type_only); + } + return false; + }, + .@"usingnamespace" => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); + return false; + }, + .test_decl => { + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); + return false; + }, + .global_var_decl, + .local_var_decl, + .simple_var_decl, + .aligned_var_decl, + => { + const full = tree.fullVarDecl(node).?; + const init_ri = if (full.ast.type_node != 0) init_ri: { + _ = try astrl.expr(full.ast.type_node, block, ResultInfo.type_only); + break :init_ri ResultInfo.typed_ptr; + } else ResultInfo.inferred_ptr; + if (full.ast.init_node == 0) { + // No init node, so we're done. + return false; + } + switch (token_tags[full.ast.mut_token]) { + .keyword_const => { + const init_consumes_rl = try astrl.expr(full.ast.init_node, block, init_ri); + if (init_consumes_rl) { + try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); + } + return false; + }, + .keyword_var => { + // We'll create an alloc either way, so don't care if the + // result pointer is consumed. + _ = try astrl.expr(full.ast.init_node, block, init_ri); + return false; + }, + else => unreachable, + } + }, + .assign_destructure => { + const lhs_count = tree.extra_data[node_datas[node].lhs]; + const all_lhs = tree.extra_data[node_datas[node].lhs + 1 ..][0..lhs_count]; + for (all_lhs) |lhs| { + _ = try astrl.expr(lhs, block, ResultInfo.none); + } + // We don't need to gather any meaningful data here, because destructures always use RLS + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); + return false; + }, + .assign => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.typed_ptr); + return false; + }, + .assign_shl, + .assign_shl_sat, + .assign_shr, + .assign_bit_and, + .assign_bit_or, + .assign_bit_xor, + .assign_div, + .assign_sub, + .assign_sub_wrap, + .assign_sub_sat, + .assign_mod, + .assign_add, + .assign_add_wrap, + .assign_add_sat, + .assign_mul, + .assign_mul_wrap, + .assign_mul_sat, + => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); + return false; + }, + .shl, .shr => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); + return false; + }, + .add, + .add_wrap, + .add_sat, + .sub, + .sub_wrap, + .sub_sat, + .mul, + .mul_wrap, + .mul_sat, + .div, + .mod, + .shl_sat, + .bit_and, + .bit_or, + .bit_xor, + .bang_equal, + .equal_equal, + .greater_than, + .greater_or_equal, + .less_than, + .less_or_equal, + .array_cat, + => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); + return false; + }, + .array_mult => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); + return false; + }, + .error_union, .merge_error_sets => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); + return false; + }, + .bool_and, + .bool_or, + => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); + return false; + }, + .bool_not => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); + return false; + }, + .bit_not, .negation, .negation_wrap => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + return false; + }, + + // These nodes are leaves and never consume a result location. + .identifier, + .string_literal, + .multiline_string_literal, + .number_literal, + .unreachable_literal, + .asm_simple, + .@"asm", + .enum_literal, + .error_value, + .anyframe_literal, + .@"continue", + .char_literal, + .error_set_decl, + => return false, + + .builtin_call_two, .builtin_call_two_comma => { + if (node_datas[node].lhs == 0) { + return astrl.builtinCall(block, ri, node, &.{}); + } else if (node_datas[node].rhs == 0) { + return astrl.builtinCall(block, ri, node, &.{node_datas[node].lhs}); + } else { + return astrl.builtinCall(block, ri, node, &.{ node_datas[node].lhs, node_datas[node].rhs }); + } + }, + .builtin_call, .builtin_call_comma => { + const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; + return astrl.builtinCall(block, ri, node, params); + }, + + .call_one, + .call_one_comma, + .async_call_one, + .async_call_one_comma, + .call, + .call_comma, + .async_call, + .async_call_comma, + => { + var buf: [1]Ast.Node.Index = undefined; + const full = tree.fullCall(&buf, node).?; + _ = try astrl.expr(full.ast.fn_expr, block, ResultInfo.none); + for (full.ast.params) |param_node| { + _ = try astrl.expr(param_node, block, ResultInfo.type_only); + } + return switch (node_tags[node]) { + .call_one, + .call_one_comma, + .call, + .call_comma, + => false, // TODO: once function calls are passed result locations this will change + .async_call_one, + .async_call_one_comma, + .async_call, + .async_call_comma, + => ri.have_ptr, // always use result ptr for frames + else => unreachable, + }; + }, + + .@"return" => { + if (node_datas[node].lhs != 0) { + const ret_val_consumes_rl = try astrl.expr(node_datas[node].lhs, block, ResultInfo.typed_ptr); + if (ret_val_consumes_rl) { + try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); + } + } + return false; + }, + + .field_access => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + return false; + }, + + .if_simple, .@"if" => { + const full = tree.fullIf(node).?; + if (full.error_token != null or full.payload_token != null) { + _ = try astrl.expr(full.ast.cond_expr, block, ResultInfo.none); + } else { + _ = try astrl.expr(full.ast.cond_expr, block, ResultInfo.type_only); // bool + } + + if (full.ast.else_expr == 0) { + _ = try astrl.expr(full.ast.then_expr, block, ResultInfo.none); + return false; + } else { + const then_uses_rl = try astrl.expr(full.ast.then_expr, block, ri); + const else_uses_rl = try astrl.expr(full.ast.else_expr, block, ri); + const uses_rl = then_uses_rl or else_uses_rl; + if (uses_rl) try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); + return uses_rl; + } + }, + + .while_simple, .while_cont, .@"while" => { + const full = tree.fullWhile(node).?; + const label: ?[]const u8 = if (full.label_token) |label_token| label: { + break :label try astrl.identString(label_token); + } else null; + if (full.error_token != null or full.payload_token != null) { + _ = try astrl.expr(full.ast.cond_expr, block, ResultInfo.none); + } else { + _ = try astrl.expr(full.ast.cond_expr, block, ResultInfo.type_only); // bool + } + var new_block: Block = .{ + .parent = block, + .label = label, + .is_loop = true, + .ri = ri, + .consumes_res_ptr = false, + }; + if (full.ast.cont_expr != 0) { + _ = try astrl.expr(full.ast.cont_expr, &new_block, ResultInfo.none); + } + _ = try astrl.expr(full.ast.then_expr, &new_block, ResultInfo.none); + const else_consumes_rl = if (full.ast.else_expr != 0) else_rl: { + break :else_rl try astrl.expr(full.ast.else_expr, block, ri); + } else false; + if (new_block.consumes_res_ptr or else_consumes_rl) { + try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); + return true; + } else { + return false; + } + }, + + .for_simple, .@"for" => { + const full = tree.fullFor(node).?; + const label: ?[]const u8 = if (full.label_token) |label_token| label: { + break :label try astrl.identString(label_token); + } else null; + for (full.ast.inputs) |input| { + if (node_tags[input] == .for_range) { + _ = try astrl.expr(node_datas[input].lhs, block, ResultInfo.type_only); + if (node_datas[input].rhs != 0) { + _ = try astrl.expr(node_datas[input].rhs, block, ResultInfo.type_only); + } + } else { + _ = try astrl.expr(input, block, ResultInfo.none); + } + } + var new_block: Block = .{ + .parent = block, + .label = label, + .is_loop = true, + .ri = ri, + .consumes_res_ptr = false, + }; + _ = try astrl.expr(full.ast.then_expr, &new_block, ResultInfo.none); + const else_consumes_rl = if (full.ast.else_expr != 0) else_rl: { + break :else_rl try astrl.expr(full.ast.else_expr, block, ri); + } else false; + if (new_block.consumes_res_ptr or else_consumes_rl) { + try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); + return true; + } else { + return false; + } + }, + + .slice_open => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); + return false; + }, + .slice => { + const extra = tree.extraData(node_datas[node].rhs, Ast.Node.Slice); + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + _ = try astrl.expr(extra.start, block, ResultInfo.type_only); + _ = try astrl.expr(extra.end, block, ResultInfo.type_only); + return false; + }, + .slice_sentinel => { + const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SliceSentinel); + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + _ = try astrl.expr(extra.start, block, ResultInfo.type_only); + if (extra.end != 0) { + _ = try astrl.expr(extra.end, block, ResultInfo.type_only); + } + _ = try astrl.expr(extra.sentinel, block, ResultInfo.none); + return false; + }, + .deref => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + return false; + }, + .address_of => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + return false; + }, + .optional_type => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); + return false; + }, + .grouped_expression, + .@"try", + .@"await", + .@"nosuspend", + .unwrap_optional, + => return astrl.expr(node_datas[node].lhs, block, ri), + + .block_two, .block_two_semicolon => { + if (node_datas[node].lhs == 0) { + return astrl.blockExpr(block, ri, node, &.{}); + } else if (node_datas[node].rhs == 0) { + return astrl.blockExpr(block, ri, node, &.{node_datas[node].lhs}); + } else { + return astrl.blockExpr(block, ri, node, &.{ node_datas[node].lhs, node_datas[node].rhs }); + } + }, + .block, .block_semicolon => { + const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; + return astrl.blockExpr(block, ri, node, statements); + }, + .anyframe_type => { + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); + return false; + }, + .@"catch", .@"orelse" => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + const rhs_consumes_rl = try astrl.expr(node_datas[node].rhs, block, ri); + if (rhs_consumes_rl) { + try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); + } + return rhs_consumes_rl; + }, + + .ptr_type_aligned, + .ptr_type_sentinel, + .ptr_type, + .ptr_type_bit_range, + => { + const full = tree.fullPtrType(node).?; + _ = try astrl.expr(full.ast.child_type, block, ResultInfo.type_only); + if (full.ast.sentinel != 0) { + _ = try astrl.expr(full.ast.sentinel, block, ResultInfo.type_only); + } + if (full.ast.addrspace_node != 0) { + _ = try astrl.expr(full.ast.addrspace_node, block, ResultInfo.type_only); + } + if (full.ast.align_node != 0) { + _ = try astrl.expr(full.ast.align_node, block, ResultInfo.type_only); + } + if (full.ast.bit_range_start != 0) { + assert(full.ast.bit_range_end != 0); + _ = try astrl.expr(full.ast.bit_range_start, block, ResultInfo.type_only); + _ = try astrl.expr(full.ast.bit_range_end, block, ResultInfo.type_only); + } + return false; + }, + + .container_decl, + .container_decl_trailing, + .container_decl_arg, + .container_decl_arg_trailing, + .container_decl_two, + .container_decl_two_trailing, + .tagged_union, + .tagged_union_trailing, + .tagged_union_enum_tag, + .tagged_union_enum_tag_trailing, + .tagged_union_two, + .tagged_union_two_trailing, + => { + var buf: [2]Ast.Node.Index = undefined; + try astrl.containerDecl(block, tree.fullContainerDecl(&buf, node).?); + return false; + }, + + .@"break" => { + if (node_datas[node].rhs == 0) { + // Breaks with void are not interesting + return false; + } + + var opt_cur_block = block; + if (node_datas[node].lhs == 0) { + // No label - we're breaking from a loop. + while (opt_cur_block) |cur_block| : (opt_cur_block = cur_block.parent) { + if (cur_block.is_loop) break; + } + } else { + const break_label = try astrl.identString(node_datas[node].lhs); + while (opt_cur_block) |cur_block| : (opt_cur_block = cur_block.parent) { + const block_label = cur_block.label orelse continue; + if (std.mem.eql(u8, block_label, break_label)) break; + } + } + + if (opt_cur_block) |target_block| { + const consumes_break_rl = try astrl.expr(node_datas[node].rhs, block, target_block.ri); + if (consumes_break_rl) target_block.consumes_res_ptr = true; + } else { + // No corresponding scope to break from - AstGen will emit an error. + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); + } + + return false; + }, + + .array_type => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); + return false; + }, + .array_type_sentinel => { + const extra = tree.extraData(node_datas[node].rhs, Ast.Node.ArrayTypeSentinel); + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); + _ = try astrl.expr(extra.elem_type, block, ResultInfo.type_only); + _ = try astrl.expr(extra.sentinel, block, ResultInfo.type_only); + return false; + }, + .array_access => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); + return false; + }, + .@"comptime" => { + // AstGen will emit an error if the scope is already comptime, so we can assume it is + // not. This means the result location is not forwarded. + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + return false; + }, + .@"switch", .switch_comma => { + const operand_node = node_datas[node].lhs; + const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SubRange); + const case_nodes = tree.extra_data[extra.start..extra.end]; + + _ = try astrl.expr(operand_node, block, ResultInfo.none); + + var any_prong_consumed_rl = false; + for (case_nodes) |case_node| { + const case = tree.fullSwitchCase(case_node).?; + for (case.ast.values) |item_node| { + if (node_tags[item_node] == .switch_range) { + _ = try astrl.expr(node_datas[item_node].lhs, block, ResultInfo.none); + _ = try astrl.expr(node_datas[item_node].rhs, block, ResultInfo.none); + } else { + _ = try astrl.expr(item_node, block, ResultInfo.none); + } + } + if (try astrl.expr(case.ast.target_expr, block, ri)) { + any_prong_consumed_rl = true; + } + } + if (any_prong_consumed_rl) { + try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); + } + return any_prong_consumed_rl; + }, + .@"suspend" => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + return false; + }, + .@"resume" => { + _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); + return false; + }, + + .array_init_one, + .array_init_one_comma, + .array_init_dot_two, + .array_init_dot_two_comma, + .array_init_dot, + .array_init_dot_comma, + .array_init, + .array_init_comma, + => { + var buf: [2]Ast.Node.Index = undefined; + const full = tree.fullArrayInit(&buf, node).?; + + if (full.ast.type_expr != 0) { + // Explicitly typed init does not participate in RLS + _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none); + for (full.ast.elements) |elem_init| { + _ = try astrl.expr(elem_init, block, ResultInfo.type_only); + } + return false; + } + + if (ri.have_type) { + // Always forward type information + // If we have a result pointer, we use and forward it + for (full.ast.elements) |elem_init| { + _ = try astrl.expr(elem_init, block, ri); + } + return ri.have_ptr; + } else { + // Untyped init does not consume result location + for (full.ast.elements) |elem_init| { + _ = try astrl.expr(elem_init, block, ResultInfo.none); + } + return false; + } + }, + + .struct_init_one, + .struct_init_one_comma, + .struct_init_dot_two, + .struct_init_dot_two_comma, + .struct_init_dot, + .struct_init_dot_comma, + .struct_init, + .struct_init_comma, + => { + var buf: [2]Ast.Node.Index = undefined; + const full = tree.fullStructInit(&buf, node).?; + + if (full.ast.type_expr != 0) { + // Explicitly typed init does not participate in RLS + _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none); + for (full.ast.fields) |field_init| { + _ = try astrl.expr(field_init, block, ResultInfo.type_only); + } + return false; + } + + if (ri.have_type) { + // Always forward type information + // If we have a result pointer, we use and forward it + for (full.ast.fields) |field_init| { + _ = try astrl.expr(field_init, block, ri); + } + return ri.have_ptr; + } else { + // Untyped init does not consume result location + for (full.ast.fields) |field_init| { + _ = try astrl.expr(field_init, block, ResultInfo.none); + } + return false; + } + }, + + .fn_proto_simple, + .fn_proto_multi, + .fn_proto_one, + .fn_proto, + .fn_decl, + => { + var buf: [1]Ast.Node.Index = undefined; + const full = tree.fullFnProto(&buf, node).?; + const body_node = if (node_tags[node] == .fn_decl) node_datas[node].rhs else 0; + { + var it = full.iterate(tree); + while (it.next()) |param| { + if (param.anytype_ellipsis3 == null) { + _ = try astrl.expr(param.type_expr, block, ResultInfo.type_only); + } + } + } + if (full.ast.align_expr != 0) { + _ = try astrl.expr(full.ast.align_expr, block, ResultInfo.type_only); + } + if (full.ast.addrspace_expr != 0) { + _ = try astrl.expr(full.ast.addrspace_expr, block, ResultInfo.type_only); + } + if (full.ast.section_expr != 0) { + _ = try astrl.expr(full.ast.section_expr, block, ResultInfo.type_only); + } + if (full.ast.callconv_expr != 0) { + _ = try astrl.expr(full.ast.callconv_expr, block, ResultInfo.type_only); + } + _ = try astrl.expr(full.ast.return_type, block, ResultInfo.type_only); + if (body_node != 0) { + _ = try astrl.expr(body_node, block, ResultInfo.none); + } + return false; + }, + } +} + +fn identString(astrl: *AstRlAnnotate, token: Ast.TokenIndex) ![]const u8 { + const tree = astrl.tree; + const token_tags = tree.tokens.items(.tag); + assert(token_tags[token] == .identifier); + const ident_name = tree.tokenSlice(token); + if (!std.mem.startsWith(u8, ident_name, "@")) { + return ident_name; + } + return std.zig.string_literal.parseAlloc(astrl.arena, ident_name[1..]) catch |err| switch (err) { + error.OutOfMemory => error.OutOfMemory, + error.InvalidLiteral => "", // This pass can safely return garbage on invalid AST + }; +} + +fn blockExpr(astrl: *AstRlAnnotate, parent_block: ?*Block, ri: ResultInfo, node: Ast.Node.Index, statements: []const Ast.Node.Index) !bool { + const tree = astrl.tree; + const token_tags = tree.tokens.items(.tag); + const main_tokens = tree.nodes.items(.main_token); + + const lbrace = main_tokens[node]; + if (token_tags[lbrace - 1] == .colon and + token_tags[lbrace - 2] == .identifier) + { + // Labeled block + var new_block: Block = .{ + .parent = parent_block, + .label = try astrl.identString(lbrace - 2), + .is_loop = false, + .ri = ri, + .consumes_res_ptr = false, + }; + for (statements) |statement| { + _ = try astrl.expr(statement, &new_block, ResultInfo.none); + } + if (new_block.consumes_res_ptr) { + try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); + } + return new_block.consumes_res_ptr; + } else { + // Unlabeled block + for (statements) |statement| { + _ = try astrl.expr(statement, parent_block, ResultInfo.none); + } + return false; + } +} + +fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.Node.Index, args: []const Ast.Node.Index) !bool { + _ = ri; // Currently, no builtin consumes its result location. + + const tree = astrl.tree; + const main_tokens = tree.nodes.items(.main_token); + const builtin_token = main_tokens[node]; + const builtin_name = tree.tokenSlice(builtin_token); + const info = BuiltinFn.list.get(builtin_name) orelse return false; + if (info.param_count) |expected| { + if (expected != args.len) return false; + } + switch (info.tag) { + .import => return false, + .compile_log, .TypeOf => { + for (args) |arg_node| { + _ = try astrl.expr(arg_node, block, ResultInfo.none); + } + return false; + }, + .as => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + return false; + }, + .bit_cast => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + return false; + }, + .union_init => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + _ = try astrl.expr(args[2], block, ResultInfo.type_only); + return false; + }, + .c_import => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + return false; + }, + .min, .max => { + for (args) |arg_node| { + _ = try astrl.expr(arg_node, block, ResultInfo.none); + } + return false; + }, + .@"export" => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + return false; + }, + .@"extern" => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + return false; + }, + // These builtins take no args and do not consume the result pointer. + .src, + .This, + .return_address, + .error_return_trace, + .frame, + .breakpoint, + .in_comptime, + .panic, + .trap, + .c_va_start, + => return false, + // TODO: this is a workaround for llvm/llvm-project#68409 + // Zig tracking issue: #16876 + .frame_address => return true, + // These builtins take a single argument with a known result type, but do not consume their + // result pointer. + .size_of, + .bit_size_of, + .align_of, + .compile_error, + .set_eval_branch_quota, + .int_from_bool, + .int_from_error, + .error_from_int, + .embed_file, + .error_name, + .set_runtime_safety, + .Type, + .c_undef, + .c_include, + .wasm_memory_size, + .splat, + .fence, + .set_float_mode, + .set_align_stack, + .set_cold, + .type_info, + .work_item_id, + .work_group_size, + .work_group_id, + => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + return false; + }, + // These builtins take a single argument with no result information and do not consume their + // result pointer. + .int_from_ptr, + .int_from_enum, + .sqrt, + .sin, + .cos, + .tan, + .exp, + .exp2, + .log, + .log2, + .log10, + .abs, + .floor, + .ceil, + .trunc, + .round, + .tag_name, + .type_name, + .Frame, + .frame_size, + .int_from_float, + .float_from_int, + .ptr_from_int, + .enum_from_int, + .float_cast, + .int_cast, + .truncate, + .error_cast, + .ptr_cast, + .align_cast, + .addrspace_cast, + .const_cast, + .volatile_cast, + .clz, + .ctz, + .pop_count, + .byte_swap, + .bit_reverse, + => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + return false; + }, + .div_exact, + .div_floor, + .div_trunc, + .mod, + .rem, + => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + _ = try astrl.expr(args[1], block, ResultInfo.none); + return false; + }, + .shl_exact, .shr_exact => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + return false; + }, + .bit_offset_of, + .offset_of, + .field_parent_ptr, + .has_decl, + .has_field, + .field, + => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + return false; + }, + .wasm_memory_grow => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + return false; + }, + .c_define => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.none); + return false; + }, + .reduce => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.none); + return false; + }, + .add_with_overflow, .sub_with_overflow, .mul_with_overflow, .shl_with_overflow => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + _ = try astrl.expr(args[1], block, ResultInfo.none); + return false; + }, + .atomic_load => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.none); + _ = try astrl.expr(args[2], block, ResultInfo.type_only); + return false; + }, + .atomic_rmw => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.none); + _ = try astrl.expr(args[2], block, ResultInfo.type_only); + _ = try astrl.expr(args[3], block, ResultInfo.type_only); + _ = try astrl.expr(args[4], block, ResultInfo.type_only); + return false; + }, + .atomic_store => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.none); + _ = try astrl.expr(args[2], block, ResultInfo.type_only); + _ = try astrl.expr(args[3], block, ResultInfo.type_only); + return false; + }, + .mul_add => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + _ = try astrl.expr(args[2], block, ResultInfo.type_only); + return false; + }, + .call => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.none); + _ = try astrl.expr(args[2], block, ResultInfo.none); + return false; + }, + .memcpy => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + _ = try astrl.expr(args[1], block, ResultInfo.none); + return false; + }, + .memset => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + return false; + }, + .shuffle => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.none); + _ = try astrl.expr(args[2], block, ResultInfo.none); + _ = try astrl.expr(args[3], block, ResultInfo.none); + return false; + }, + .select => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.none); + _ = try astrl.expr(args[2], block, ResultInfo.none); + _ = try astrl.expr(args[3], block, ResultInfo.none); + return false; + }, + .async_call => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + _ = try astrl.expr(args[1], block, ResultInfo.none); + _ = try astrl.expr(args[2], block, ResultInfo.none); + _ = try astrl.expr(args[3], block, ResultInfo.none); + return false; // buffer passed as arg for frame data + }, + .Vector => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + return false; + }, + .prefetch => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + return false; + }, + .c_va_arg => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + return false; + }, + .c_va_copy => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + return false; + }, + .c_va_end => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + return false; + }, + .cmpxchg_strong, .cmpxchg_weak => { + _ = try astrl.expr(args[0], block, ResultInfo.none); + _ = try astrl.expr(args[1], block, ResultInfo.type_only); + _ = try astrl.expr(args[2], block, ResultInfo.type_only); + _ = try astrl.expr(args[3], block, ResultInfo.type_only); + _ = try astrl.expr(args[4], block, ResultInfo.type_only); + return false; + }, + } +} diff --git a/lib/std/zig/BuiltinFn.zig b/lib/std/zig/BuiltinFn.zig new file mode 100644 index 0000000000000000000000000000000000000000..3296114ef9d31c1e4576435851ec7928fcf402b9 --- /dev/null +++ b/lib/std/zig/BuiltinFn.zig @@ -0,0 +1,1017 @@ +const std = @import("std"); + +pub const Tag = enum { + add_with_overflow, + addrspace_cast, + align_cast, + align_of, + as, + async_call, + atomic_load, + atomic_rmw, + atomic_store, + bit_cast, + bit_offset_of, + int_from_bool, + bit_size_of, + breakpoint, + mul_add, + byte_swap, + bit_reverse, + offset_of, + call, + c_define, + c_import, + c_include, + clz, + cmpxchg_strong, + cmpxchg_weak, + compile_error, + compile_log, + const_cast, + ctz, + c_undef, + c_va_arg, + c_va_copy, + c_va_end, + c_va_start, + div_exact, + div_floor, + div_trunc, + embed_file, + int_from_enum, + error_name, + error_return_trace, + int_from_error, + error_cast, + @"export", + @"extern", + fence, + field, + field_parent_ptr, + float_cast, + int_from_float, + frame, + Frame, + frame_address, + frame_size, + has_decl, + has_field, + import, + in_comptime, + int_cast, + enum_from_int, + error_from_int, + float_from_int, + ptr_from_int, + max, + memcpy, + memset, + min, + wasm_memory_size, + wasm_memory_grow, + mod, + mul_with_overflow, + panic, + pop_count, + prefetch, + ptr_cast, + int_from_ptr, + rem, + return_address, + select, + set_align_stack, + set_cold, + set_eval_branch_quota, + set_float_mode, + set_runtime_safety, + shl_exact, + shl_with_overflow, + shr_exact, + shuffle, + size_of, + splat, + reduce, + src, + sqrt, + sin, + cos, + tan, + exp, + exp2, + log, + log2, + log10, + abs, + floor, + ceil, + trunc, + round, + sub_with_overflow, + tag_name, + This, + trap, + truncate, + Type, + type_info, + type_name, + TypeOf, + union_init, + Vector, + volatile_cast, + work_item_id, + work_group_size, + work_group_id, +}; + +pub const MemLocRequirement = enum { + /// The builtin never needs a memory location. + never, + /// The builtin always needs a memory location. + always, + /// The builtin forwards the question to argument at index 0. + forward0, + /// The builtin forwards the question to argument at index 1. + forward1, +}; + +pub const EvalToError = enum { + /// The builtin cannot possibly evaluate to an error. + never, + /// The builtin will always evaluate to an error. + always, + /// The builtin may or may not evaluate to an error depending on the parameters. + maybe, +}; + +tag: Tag, + +/// Info about the builtin call's ability to take advantage of a result location pointer. +needs_mem_loc: MemLocRequirement = .never, +/// Info about the builtin call's possibility of returning an error. +eval_to_error: EvalToError = .never, +/// `true` if the builtin call can be the left-hand side of an expression (assigned to). +allows_lvalue: bool = false, +/// The number of parameters to this builtin function. `null` means variable number +/// of parameters. +param_count: ?u8, + +pub const list = list: { + @setEvalBranchQuota(3000); + break :list std.ComptimeStringMap(@This(), .{ + .{ + "@addWithOverflow", + .{ + .tag = .add_with_overflow, + .param_count = 2, + }, + }, + .{ + "@addrSpaceCast", + .{ + .tag = .addrspace_cast, + .param_count = 1, + }, + }, + .{ + "@alignCast", + .{ + .tag = .align_cast, + .param_count = 1, + }, + }, + .{ + "@alignOf", + .{ + .tag = .align_of, + .param_count = 1, + }, + }, + .{ + "@as", + .{ + .tag = .as, + .needs_mem_loc = .forward1, + .eval_to_error = .maybe, + .param_count = 2, + }, + }, + .{ + "@asyncCall", + .{ + .tag = .async_call, + .param_count = 4, + }, + }, + .{ + "@atomicLoad", + .{ + .tag = .atomic_load, + .param_count = 3, + }, + }, + .{ + "@atomicRmw", + .{ + .tag = .atomic_rmw, + .param_count = 5, + }, + }, + .{ + "@atomicStore", + .{ + .tag = .atomic_store, + .param_count = 4, + }, + }, + .{ + "@bitCast", + .{ + .tag = .bit_cast, + .needs_mem_loc = .forward0, + .param_count = 1, + }, + }, + .{ + "@bitOffsetOf", + .{ + .tag = .bit_offset_of, + .param_count = 2, + }, + }, + .{ + "@intFromBool", + .{ + .tag = .int_from_bool, + .param_count = 1, + }, + }, + .{ + "@bitSizeOf", + .{ + .tag = .bit_size_of, + .param_count = 1, + }, + }, + .{ + "@breakpoint", + .{ + .tag = .breakpoint, + .param_count = 0, + }, + }, + .{ + "@mulAdd", + .{ + .tag = .mul_add, + .param_count = 4, + }, + }, + .{ + "@byteSwap", + .{ + .tag = .byte_swap, + .param_count = 1, + }, + }, + .{ + "@bitReverse", + .{ + .tag = .bit_reverse, + .param_count = 1, + }, + }, + .{ + "@offsetOf", + .{ + .tag = .offset_of, + .param_count = 2, + }, + }, + .{ + "@call", + .{ + .tag = .call, + .needs_mem_loc = .always, + .eval_to_error = .maybe, + .param_count = 3, + }, + }, + .{ + "@cDefine", + .{ + .tag = .c_define, + .param_count = 2, + }, + }, + .{ + "@cImport", + .{ + .tag = .c_import, + .param_count = 1, + }, + }, + .{ + "@cInclude", + .{ + .tag = .c_include, + .param_count = 1, + }, + }, + .{ + "@clz", + .{ + .tag = .clz, + .param_count = 1, + }, + }, + .{ + "@cmpxchgStrong", + .{ + .tag = .cmpxchg_strong, + .param_count = 6, + }, + }, + .{ + "@cmpxchgWeak", + .{ + .tag = .cmpxchg_weak, + .param_count = 6, + }, + }, + .{ + "@compileError", + .{ + .tag = .compile_error, + .param_count = 1, + }, + }, + .{ + "@compileLog", + .{ + .tag = .compile_log, + .param_count = null, + }, + }, + .{ + "@constCast", + .{ + .tag = .const_cast, + .param_count = 1, + }, + }, + .{ + "@ctz", + .{ + .tag = .ctz, + .param_count = 1, + }, + }, + .{ + "@cUndef", + .{ + .tag = .c_undef, + .param_count = 1, + }, + }, + .{ + "@cVaArg", .{ + .tag = .c_va_arg, + .param_count = 2, + }, + }, + .{ + "@cVaCopy", .{ + .tag = .c_va_copy, + .param_count = 1, + }, + }, + .{ + "@cVaEnd", .{ + .tag = .c_va_end, + .param_count = 1, + }, + }, + .{ + "@cVaStart", .{ + .tag = .c_va_start, + .param_count = 0, + }, + }, + .{ + "@divExact", + .{ + .tag = .div_exact, + .param_count = 2, + }, + }, + .{ + "@divFloor", + .{ + .tag = .div_floor, + .param_count = 2, + }, + }, + .{ + "@divTrunc", + .{ + .tag = .div_trunc, + .param_count = 2, + }, + }, + .{ + "@embedFile", + .{ + .tag = .embed_file, + .param_count = 1, + }, + }, + .{ + "@intFromEnum", + .{ + .tag = .int_from_enum, + .param_count = 1, + }, + }, + .{ + "@errorName", + .{ + .tag = .error_name, + .param_count = 1, + }, + }, + .{ + "@errorReturnTrace", + .{ + .tag = .error_return_trace, + .param_count = 0, + }, + }, + .{ + "@intFromError", + .{ + .tag = .int_from_error, + .param_count = 1, + }, + }, + .{ + "@errorCast", + .{ + .tag = .error_cast, + .eval_to_error = .always, + .param_count = 1, + }, + }, + .{ + "@export", + .{ + .tag = .@"export", + .param_count = 2, + }, + }, + .{ + "@extern", + .{ + .tag = .@"extern", + .param_count = 2, + }, + }, + .{ + "@fence", + .{ + .tag = .fence, + .param_count = 1, + }, + }, + .{ + "@field", + .{ + .tag = .field, + .needs_mem_loc = .always, + .eval_to_error = .maybe, + .param_count = 2, + .allows_lvalue = true, + }, + }, + .{ + "@fieldParentPtr", + .{ + .tag = .field_parent_ptr, + .param_count = 3, + }, + }, + .{ + "@floatCast", + .{ + .tag = .float_cast, + .param_count = 1, + }, + }, + .{ + "@intFromFloat", + .{ + .tag = .int_from_float, + .param_count = 1, + }, + }, + .{ + "@frame", + .{ + .tag = .frame, + .param_count = 0, + }, + }, + .{ + "@Frame", + .{ + .tag = .Frame, + .param_count = 1, + }, + }, + .{ + "@frameAddress", + .{ + .tag = .frame_address, + .param_count = 0, + }, + }, + .{ + "@frameSize", + .{ + .tag = .frame_size, + .param_count = 1, + }, + }, + .{ + "@hasDecl", + .{ + .tag = .has_decl, + .param_count = 2, + }, + }, + .{ + "@hasField", + .{ + .tag = .has_field, + .param_count = 2, + }, + }, + .{ + "@import", + .{ + .tag = .import, + .param_count = 1, + }, + }, + .{ + "@inComptime", + .{ + .tag = .in_comptime, + .param_count = 0, + }, + }, + .{ + "@intCast", + .{ + .tag = .int_cast, + .param_count = 1, + }, + }, + .{ + "@enumFromInt", + .{ + .tag = .enum_from_int, + .param_count = 1, + }, + }, + .{ + "@errorFromInt", + .{ + .tag = .error_from_int, + .eval_to_error = .always, + .param_count = 1, + }, + }, + .{ + "@floatFromInt", + .{ + .tag = .float_from_int, + .param_count = 1, + }, + }, + .{ + "@ptrFromInt", + .{ + .tag = .ptr_from_int, + .param_count = 1, + }, + }, + .{ + "@max", + .{ + .tag = .max, + .param_count = null, + }, + }, + .{ + "@memcpy", + .{ + .tag = .memcpy, + .param_count = 2, + }, + }, + .{ + "@memset", + .{ + .tag = .memset, + .param_count = 2, + }, + }, + .{ + "@min", + .{ + .tag = .min, + .param_count = null, + }, + }, + .{ + "@wasmMemorySize", + .{ + .tag = .wasm_memory_size, + .param_count = 1, + }, + }, + .{ + "@wasmMemoryGrow", + .{ + .tag = .wasm_memory_grow, + .param_count = 2, + }, + }, + .{ + "@mod", + .{ + .tag = .mod, + .param_count = 2, + }, + }, + .{ + "@mulWithOverflow", + .{ + .tag = .mul_with_overflow, + .param_count = 2, + }, + }, + .{ + "@panic", + .{ + .tag = .panic, + .param_count = 1, + }, + }, + .{ + "@popCount", + .{ + .tag = .pop_count, + .param_count = 1, + }, + }, + .{ + "@prefetch", + .{ + .tag = .prefetch, + .param_count = 2, + }, + }, + .{ + "@ptrCast", + .{ + .tag = .ptr_cast, + .param_count = 1, + }, + }, + .{ + "@intFromPtr", + .{ + .tag = .int_from_ptr, + .param_count = 1, + }, + }, + .{ + "@rem", + .{ + .tag = .rem, + .param_count = 2, + }, + }, + .{ + "@returnAddress", + .{ + .tag = .return_address, + .param_count = 0, + }, + }, + .{ + "@select", + .{ + .tag = .select, + .param_count = 4, + }, + }, + .{ + "@setAlignStack", + .{ + .tag = .set_align_stack, + .param_count = 1, + }, + }, + .{ + "@setCold", + .{ + .tag = .set_cold, + .param_count = 1, + }, + }, + .{ + "@setEvalBranchQuota", + .{ + .tag = .set_eval_branch_quota, + .param_count = 1, + }, + }, + .{ + "@setFloatMode", + .{ + .tag = .set_float_mode, + .param_count = 1, + }, + }, + .{ + "@setRuntimeSafety", + .{ + .tag = .set_runtime_safety, + .param_count = 1, + }, + }, + .{ + "@shlExact", + .{ + .tag = .shl_exact, + .param_count = 2, + }, + }, + .{ + "@shlWithOverflow", + .{ + .tag = .shl_with_overflow, + .param_count = 2, + }, + }, + .{ + "@shrExact", + .{ + .tag = .shr_exact, + .param_count = 2, + }, + }, + .{ + "@shuffle", + .{ + .tag = .shuffle, + .param_count = 4, + }, + }, + .{ + "@sizeOf", + .{ + .tag = .size_of, + .param_count = 1, + }, + }, + .{ + "@splat", + .{ + .tag = .splat, + .param_count = 1, + }, + }, + .{ + "@reduce", + .{ + .tag = .reduce, + .param_count = 2, + }, + }, + .{ + "@src", + .{ + .tag = .src, + .needs_mem_loc = .always, + .param_count = 0, + }, + }, + .{ + "@sqrt", + .{ + .tag = .sqrt, + .param_count = 1, + }, + }, + .{ + "@sin", + .{ + .tag = .sin, + .param_count = 1, + }, + }, + .{ + "@cos", + .{ + .tag = .cos, + .param_count = 1, + }, + }, + .{ + "@tan", + .{ + .tag = .tan, + .param_count = 1, + }, + }, + .{ + "@exp", + .{ + .tag = .exp, + .param_count = 1, + }, + }, + .{ + "@exp2", + .{ + .tag = .exp2, + .param_count = 1, + }, + }, + .{ + "@log", + .{ + .tag = .log, + .param_count = 1, + }, + }, + .{ + "@log2", + .{ + .tag = .log2, + .param_count = 1, + }, + }, + .{ + "@log10", + .{ + .tag = .log10, + .param_count = 1, + }, + }, + .{ + "@abs", + .{ + .tag = .abs, + .param_count = 1, + }, + }, + .{ + "@floor", + .{ + .tag = .floor, + .param_count = 1, + }, + }, + .{ + "@ceil", + .{ + .tag = .ceil, + .param_count = 1, + }, + }, + .{ + "@trunc", + .{ + .tag = .trunc, + .param_count = 1, + }, + }, + .{ + "@round", + .{ + .tag = .round, + .param_count = 1, + }, + }, + .{ + "@subWithOverflow", + .{ + .tag = .sub_with_overflow, + .param_count = 2, + }, + }, + .{ + "@tagName", + .{ + .tag = .tag_name, + .param_count = 1, + }, + }, + .{ + "@This", + .{ + .tag = .This, + .param_count = 0, + }, + }, + .{ + "@trap", + .{ + .tag = .trap, + .param_count = 0, + }, + }, + .{ + "@truncate", + .{ + .tag = .truncate, + .param_count = 1, + }, + }, + .{ + "@Type", + .{ + .tag = .Type, + .param_count = 1, + }, + }, + .{ + "@typeInfo", + .{ + .tag = .type_info, + .param_count = 1, + }, + }, + .{ + "@typeName", + .{ + .tag = .type_name, + .param_count = 1, + }, + }, + .{ + "@TypeOf", + .{ + .tag = .TypeOf, + .param_count = null, + }, + }, + .{ + "@unionInit", + .{ + .tag = .union_init, + .needs_mem_loc = .always, + .param_count = 3, + }, + }, + .{ + "@Vector", + .{ + .tag = .Vector, + .param_count = 2, + }, + }, + .{ + "@volatileCast", + .{ + .tag = .volatile_cast, + .param_count = 1, + }, + }, + .{ + "@workItemId", .{ + .tag = .work_item_id, + .param_count = 1, + }, + }, + .{ + "@workGroupSize", + .{ + .tag = .work_group_size, + .param_count = 1, + }, + }, + .{ + "@workGroupId", + .{ + .tag = .work_group_id, + .param_count = 1, + }, + }, + }); +}; diff --git a/src/AstGen.zig b/src/AstGen.zig index 0d1fa6c06194323ae34c2b96d4df0f9f40684abb..7bae5cafb055fe423105d8b083fffaa3339df115 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -13,9 +13,8 @@ const StringIndexContext = std.hash_map.StringIndexContext; const isPrimitive = std.zig.primitives.isPrimitive; const Zir = @import("Zir.zig"); -const trace = @import("tracy.zig").trace; -const BuiltinFn = @import("BuiltinFn.zig"); -const AstRlAnnotate = @import("AstRlAnnotate.zig"); +const BuiltinFn = std.zig.BuiltinFn; +const AstRlAnnotate = std.zig.AstRlAnnotate; gpa: Allocator, tree: *const Ast, @@ -2265,9 +2264,6 @@ fn blockExpr( block_node: Ast.Node.Index, statements: []const Ast.Node.Index, ) InnerError!Zir.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const astgen = gz.astgen; const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); @@ -2349,9 +2345,6 @@ fn labeledBlockExpr( statements: []const Ast.Node.Index, force_comptime: bool, ) InnerError!Zir.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const astgen = gz.astgen; const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); @@ -7473,9 +7466,6 @@ fn identifier( ri: ResultInfo, ident: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - const astgen = gz.astgen; const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); diff --git a/src/AstRlAnnotate.zig b/src/AstRlAnnotate.zig deleted file mode 100644 index c751adea9d6c142f8cab50426566ffba39c150b9..0000000000000000000000000000000000000000 --- a/src/AstRlAnnotate.zig +++ /dev/null @@ -1,1105 +0,0 @@ -//! AstRlAnnotate is a simple pass which runs over the AST before AstGen to -//! determine which expressions require result locations. -//! -//! In some cases, AstGen can choose whether to provide a result pointer or to -//! just use standard `break` instructions from a block. The latter choice can -//! result in more efficient ZIR and runtime code, but does not allow for RLS to -//! occur. Thus, we want to provide a real result pointer (from an alloc) only -//! when necessary. -//! -//! To achive this, we need to determine which expressions require a result -//! pointer. This pass is reponsible for analyzing all syntax forms which may -//! provide a result location and, if sub-expressions consume this result -//! pointer non-trivially (e.g. writing through field pointers), marking the -//! node as requiring a result location. - -const std = @import("std"); -const AstRlAnnotate = @This(); -const Ast = std.zig.Ast; -const Allocator = std.mem.Allocator; -const AutoHashMapUnmanaged = std.AutoHashMapUnmanaged; -const BuiltinFn = @import("BuiltinFn.zig"); -const assert = std.debug.assert; - -gpa: Allocator, -arena: Allocator, -tree: *const Ast, - -/// Certain nodes are placed in this set under the following conditions: -/// * if-else: either branch consumes the result location -/// * labeled block: any break consumes the result location -/// * switch: any prong consumes the result location -/// * orelse/catch: the RHS expression consumes the result location -/// * while/for: any break consumes the result location -/// * @as: the second operand consumes the result location -/// * const: the init expression consumes the result location -/// * return: the return expression consumes the result location -nodes_need_rl: RlNeededSet = .{}, - -pub const RlNeededSet = AutoHashMapUnmanaged(Ast.Node.Index, void); - -const ResultInfo = packed struct { - /// Do we have a known result type? - have_type: bool, - /// Do we (potentially) have a result pointer? Note that this pointer's type - /// may not be known due to it being an inferred alloc. - have_ptr: bool, - - const none: ResultInfo = .{ .have_type = false, .have_ptr = false }; - const typed_ptr: ResultInfo = .{ .have_type = true, .have_ptr = true }; - const inferred_ptr: ResultInfo = .{ .have_type = false, .have_ptr = true }; - const type_only: ResultInfo = .{ .have_type = true, .have_ptr = false }; -}; - -/// A labeled block or a loop. When this block is broken from, `consumes_res_ptr` -/// should be set if the break expression consumed the result pointer. -const Block = struct { - parent: ?*Block, - label: ?[]const u8, - is_loop: bool, - ri: ResultInfo, - consumes_res_ptr: bool, -}; - -pub fn annotate(gpa: Allocator, arena: Allocator, tree: Ast) Allocator.Error!RlNeededSet { - var astrl: AstRlAnnotate = .{ - .gpa = gpa, - .arena = arena, - .tree = &tree, - }; - defer astrl.deinit(gpa); - - if (tree.errors.len != 0) { - // We can't perform analysis on a broken AST. AstGen will not run in - // this case. - return .{}; - } - - for (tree.containerDeclRoot().ast.members) |member_node| { - _ = try astrl.expr(member_node, null, ResultInfo.none); - } - - return astrl.nodes_need_rl.move(); -} - -fn deinit(astrl: *AstRlAnnotate, gpa: Allocator) void { - astrl.nodes_need_rl.deinit(gpa); -} - -fn containerDecl( - astrl: *AstRlAnnotate, - block: ?*Block, - full: Ast.full.ContainerDecl, -) !void { - const tree = astrl.tree; - const token_tags = tree.tokens.items(.tag); - switch (token_tags[full.ast.main_token]) { - .keyword_struct => { - if (full.ast.arg != 0) { - _ = try astrl.expr(full.ast.arg, block, ResultInfo.type_only); - } - for (full.ast.members) |member_node| { - _ = try astrl.expr(member_node, block, ResultInfo.none); - } - }, - .keyword_union => { - if (full.ast.arg != 0) { - _ = try astrl.expr(full.ast.arg, block, ResultInfo.type_only); - } - for (full.ast.members) |member_node| { - _ = try astrl.expr(member_node, block, ResultInfo.none); - } - }, - .keyword_enum => { - if (full.ast.arg != 0) { - _ = try astrl.expr(full.ast.arg, block, ResultInfo.type_only); - } - for (full.ast.members) |member_node| { - _ = try astrl.expr(member_node, block, ResultInfo.none); - } - }, - .keyword_opaque => { - for (full.ast.members) |member_node| { - _ = try astrl.expr(member_node, block, ResultInfo.none); - } - }, - else => unreachable, - } -} - -/// Returns true if `rl` provides a result pointer and the expression consumes it. -fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultInfo) Allocator.Error!bool { - const tree = astrl.tree; - const token_tags = tree.tokens.items(.tag); - const node_datas = tree.nodes.items(.data); - const node_tags = tree.nodes.items(.tag); - switch (node_tags[node]) { - .root, - .switch_case_one, - .switch_case_inline_one, - .switch_case, - .switch_case_inline, - .switch_range, - .for_range, - .asm_output, - .asm_input, - => unreachable, - - .@"errdefer", .@"defer" => { - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); - return false; - }, - - .container_field_init, - .container_field_align, - .container_field, - => { - const full = tree.fullContainerField(node).?; - _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.type_only); - if (full.ast.align_expr != 0) { - _ = try astrl.expr(full.ast.align_expr, block, ResultInfo.type_only); - } - if (full.ast.value_expr != 0) { - _ = try astrl.expr(full.ast.value_expr, block, ResultInfo.type_only); - } - return false; - }, - .@"usingnamespace" => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); - return false; - }, - .test_decl => { - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); - return false; - }, - .global_var_decl, - .local_var_decl, - .simple_var_decl, - .aligned_var_decl, - => { - const full = tree.fullVarDecl(node).?; - const init_ri = if (full.ast.type_node != 0) init_ri: { - _ = try astrl.expr(full.ast.type_node, block, ResultInfo.type_only); - break :init_ri ResultInfo.typed_ptr; - } else ResultInfo.inferred_ptr; - if (full.ast.init_node == 0) { - // No init node, so we're done. - return false; - } - switch (token_tags[full.ast.mut_token]) { - .keyword_const => { - const init_consumes_rl = try astrl.expr(full.ast.init_node, block, init_ri); - if (init_consumes_rl) { - try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); - } - return false; - }, - .keyword_var => { - // We'll create an alloc either way, so don't care if the - // result pointer is consumed. - _ = try astrl.expr(full.ast.init_node, block, init_ri); - return false; - }, - else => unreachable, - } - }, - .assign_destructure => { - const lhs_count = tree.extra_data[node_datas[node].lhs]; - const all_lhs = tree.extra_data[node_datas[node].lhs + 1 ..][0..lhs_count]; - for (all_lhs) |lhs| { - _ = try astrl.expr(lhs, block, ResultInfo.none); - } - // We don't need to gather any meaningful data here, because destructures always use RLS - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); - return false; - }, - .assign => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.typed_ptr); - return false; - }, - .assign_shl, - .assign_shl_sat, - .assign_shr, - .assign_bit_and, - .assign_bit_or, - .assign_bit_xor, - .assign_div, - .assign_sub, - .assign_sub_wrap, - .assign_sub_sat, - .assign_mod, - .assign_add, - .assign_add_wrap, - .assign_add_sat, - .assign_mul, - .assign_mul_wrap, - .assign_mul_sat, - => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); - return false; - }, - .shl, .shr => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); - return false; - }, - .add, - .add_wrap, - .add_sat, - .sub, - .sub_wrap, - .sub_sat, - .mul, - .mul_wrap, - .mul_sat, - .div, - .mod, - .shl_sat, - .bit_and, - .bit_or, - .bit_xor, - .bang_equal, - .equal_equal, - .greater_than, - .greater_or_equal, - .less_than, - .less_or_equal, - .array_cat, - => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); - return false; - }, - .array_mult => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); - return false; - }, - .error_union, .merge_error_sets => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); - return false; - }, - .bool_and, - .bool_or, - => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); - return false; - }, - .bool_not => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); - return false; - }, - .bit_not, .negation, .negation_wrap => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - return false; - }, - - // These nodes are leaves and never consume a result location. - .identifier, - .string_literal, - .multiline_string_literal, - .number_literal, - .unreachable_literal, - .asm_simple, - .@"asm", - .enum_literal, - .error_value, - .anyframe_literal, - .@"continue", - .char_literal, - .error_set_decl, - => return false, - - .builtin_call_two, .builtin_call_two_comma => { - if (node_datas[node].lhs == 0) { - return astrl.builtinCall(block, ri, node, &.{}); - } else if (node_datas[node].rhs == 0) { - return astrl.builtinCall(block, ri, node, &.{node_datas[node].lhs}); - } else { - return astrl.builtinCall(block, ri, node, &.{ node_datas[node].lhs, node_datas[node].rhs }); - } - }, - .builtin_call, .builtin_call_comma => { - const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; - return astrl.builtinCall(block, ri, node, params); - }, - - .call_one, - .call_one_comma, - .async_call_one, - .async_call_one_comma, - .call, - .call_comma, - .async_call, - .async_call_comma, - => { - var buf: [1]Ast.Node.Index = undefined; - const full = tree.fullCall(&buf, node).?; - _ = try astrl.expr(full.ast.fn_expr, block, ResultInfo.none); - for (full.ast.params) |param_node| { - _ = try astrl.expr(param_node, block, ResultInfo.type_only); - } - return switch (node_tags[node]) { - .call_one, - .call_one_comma, - .call, - .call_comma, - => false, // TODO: once function calls are passed result locations this will change - .async_call_one, - .async_call_one_comma, - .async_call, - .async_call_comma, - => ri.have_ptr, // always use result ptr for frames - else => unreachable, - }; - }, - - .@"return" => { - if (node_datas[node].lhs != 0) { - const ret_val_consumes_rl = try astrl.expr(node_datas[node].lhs, block, ResultInfo.typed_ptr); - if (ret_val_consumes_rl) { - try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); - } - } - return false; - }, - - .field_access => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - return false; - }, - - .if_simple, .@"if" => { - const full = tree.fullIf(node).?; - if (full.error_token != null or full.payload_token != null) { - _ = try astrl.expr(full.ast.cond_expr, block, ResultInfo.none); - } else { - _ = try astrl.expr(full.ast.cond_expr, block, ResultInfo.type_only); // bool - } - - if (full.ast.else_expr == 0) { - _ = try astrl.expr(full.ast.then_expr, block, ResultInfo.none); - return false; - } else { - const then_uses_rl = try astrl.expr(full.ast.then_expr, block, ri); - const else_uses_rl = try astrl.expr(full.ast.else_expr, block, ri); - const uses_rl = then_uses_rl or else_uses_rl; - if (uses_rl) try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); - return uses_rl; - } - }, - - .while_simple, .while_cont, .@"while" => { - const full = tree.fullWhile(node).?; - const label: ?[]const u8 = if (full.label_token) |label_token| label: { - break :label try astrl.identString(label_token); - } else null; - if (full.error_token != null or full.payload_token != null) { - _ = try astrl.expr(full.ast.cond_expr, block, ResultInfo.none); - } else { - _ = try astrl.expr(full.ast.cond_expr, block, ResultInfo.type_only); // bool - } - var new_block: Block = .{ - .parent = block, - .label = label, - .is_loop = true, - .ri = ri, - .consumes_res_ptr = false, - }; - if (full.ast.cont_expr != 0) { - _ = try astrl.expr(full.ast.cont_expr, &new_block, ResultInfo.none); - } - _ = try astrl.expr(full.ast.then_expr, &new_block, ResultInfo.none); - const else_consumes_rl = if (full.ast.else_expr != 0) else_rl: { - break :else_rl try astrl.expr(full.ast.else_expr, block, ri); - } else false; - if (new_block.consumes_res_ptr or else_consumes_rl) { - try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); - return true; - } else { - return false; - } - }, - - .for_simple, .@"for" => { - const full = tree.fullFor(node).?; - const label: ?[]const u8 = if (full.label_token) |label_token| label: { - break :label try astrl.identString(label_token); - } else null; - for (full.ast.inputs) |input| { - if (node_tags[input] == .for_range) { - _ = try astrl.expr(node_datas[input].lhs, block, ResultInfo.type_only); - if (node_datas[input].rhs != 0) { - _ = try astrl.expr(node_datas[input].rhs, block, ResultInfo.type_only); - } - } else { - _ = try astrl.expr(input, block, ResultInfo.none); - } - } - var new_block: Block = .{ - .parent = block, - .label = label, - .is_loop = true, - .ri = ri, - .consumes_res_ptr = false, - }; - _ = try astrl.expr(full.ast.then_expr, &new_block, ResultInfo.none); - const else_consumes_rl = if (full.ast.else_expr != 0) else_rl: { - break :else_rl try astrl.expr(full.ast.else_expr, block, ri); - } else false; - if (new_block.consumes_res_ptr or else_consumes_rl) { - try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); - return true; - } else { - return false; - } - }, - - .slice_open => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); - return false; - }, - .slice => { - const extra = tree.extraData(node_datas[node].rhs, Ast.Node.Slice); - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - _ = try astrl.expr(extra.start, block, ResultInfo.type_only); - _ = try astrl.expr(extra.end, block, ResultInfo.type_only); - return false; - }, - .slice_sentinel => { - const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SliceSentinel); - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - _ = try astrl.expr(extra.start, block, ResultInfo.type_only); - if (extra.end != 0) { - _ = try astrl.expr(extra.end, block, ResultInfo.type_only); - } - _ = try astrl.expr(extra.sentinel, block, ResultInfo.none); - return false; - }, - .deref => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - return false; - }, - .address_of => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - return false; - }, - .optional_type => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); - return false; - }, - .grouped_expression, - .@"try", - .@"await", - .@"nosuspend", - .unwrap_optional, - => return astrl.expr(node_datas[node].lhs, block, ri), - - .block_two, .block_two_semicolon => { - if (node_datas[node].lhs == 0) { - return astrl.blockExpr(block, ri, node, &.{}); - } else if (node_datas[node].rhs == 0) { - return astrl.blockExpr(block, ri, node, &.{node_datas[node].lhs}); - } else { - return astrl.blockExpr(block, ri, node, &.{ node_datas[node].lhs, node_datas[node].rhs }); - } - }, - .block, .block_semicolon => { - const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; - return astrl.blockExpr(block, ri, node, statements); - }, - .anyframe_type => { - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); - return false; - }, - .@"catch", .@"orelse" => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - const rhs_consumes_rl = try astrl.expr(node_datas[node].rhs, block, ri); - if (rhs_consumes_rl) { - try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); - } - return rhs_consumes_rl; - }, - - .ptr_type_aligned, - .ptr_type_sentinel, - .ptr_type, - .ptr_type_bit_range, - => { - const full = tree.fullPtrType(node).?; - _ = try astrl.expr(full.ast.child_type, block, ResultInfo.type_only); - if (full.ast.sentinel != 0) { - _ = try astrl.expr(full.ast.sentinel, block, ResultInfo.type_only); - } - if (full.ast.addrspace_node != 0) { - _ = try astrl.expr(full.ast.addrspace_node, block, ResultInfo.type_only); - } - if (full.ast.align_node != 0) { - _ = try astrl.expr(full.ast.align_node, block, ResultInfo.type_only); - } - if (full.ast.bit_range_start != 0) { - assert(full.ast.bit_range_end != 0); - _ = try astrl.expr(full.ast.bit_range_start, block, ResultInfo.type_only); - _ = try astrl.expr(full.ast.bit_range_end, block, ResultInfo.type_only); - } - return false; - }, - - .container_decl, - .container_decl_trailing, - .container_decl_arg, - .container_decl_arg_trailing, - .container_decl_two, - .container_decl_two_trailing, - .tagged_union, - .tagged_union_trailing, - .tagged_union_enum_tag, - .tagged_union_enum_tag_trailing, - .tagged_union_two, - .tagged_union_two_trailing, - => { - var buf: [2]Ast.Node.Index = undefined; - try astrl.containerDecl(block, tree.fullContainerDecl(&buf, node).?); - return false; - }, - - .@"break" => { - if (node_datas[node].rhs == 0) { - // Breaks with void are not interesting - return false; - } - - var opt_cur_block = block; - if (node_datas[node].lhs == 0) { - // No label - we're breaking from a loop. - while (opt_cur_block) |cur_block| : (opt_cur_block = cur_block.parent) { - if (cur_block.is_loop) break; - } - } else { - const break_label = try astrl.identString(node_datas[node].lhs); - while (opt_cur_block) |cur_block| : (opt_cur_block = cur_block.parent) { - const block_label = cur_block.label orelse continue; - if (std.mem.eql(u8, block_label, break_label)) break; - } - } - - if (opt_cur_block) |target_block| { - const consumes_break_rl = try astrl.expr(node_datas[node].rhs, block, target_block.ri); - if (consumes_break_rl) target_block.consumes_res_ptr = true; - } else { - // No corresponding scope to break from - AstGen will emit an error. - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.none); - } - - return false; - }, - - .array_type => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); - return false; - }, - .array_type_sentinel => { - const extra = tree.extraData(node_datas[node].rhs, Ast.Node.ArrayTypeSentinel); - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.type_only); - _ = try astrl.expr(extra.elem_type, block, ResultInfo.type_only); - _ = try astrl.expr(extra.sentinel, block, ResultInfo.type_only); - return false; - }, - .array_access => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - _ = try astrl.expr(node_datas[node].rhs, block, ResultInfo.type_only); - return false; - }, - .@"comptime" => { - // AstGen will emit an error if the scope is already comptime, so we can assume it is - // not. This means the result location is not forwarded. - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - return false; - }, - .@"switch", .switch_comma => { - const operand_node = node_datas[node].lhs; - const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SubRange); - const case_nodes = tree.extra_data[extra.start..extra.end]; - - _ = try astrl.expr(operand_node, block, ResultInfo.none); - - var any_prong_consumed_rl = false; - for (case_nodes) |case_node| { - const case = tree.fullSwitchCase(case_node).?; - for (case.ast.values) |item_node| { - if (node_tags[item_node] == .switch_range) { - _ = try astrl.expr(node_datas[item_node].lhs, block, ResultInfo.none); - _ = try astrl.expr(node_datas[item_node].rhs, block, ResultInfo.none); - } else { - _ = try astrl.expr(item_node, block, ResultInfo.none); - } - } - if (try astrl.expr(case.ast.target_expr, block, ri)) { - any_prong_consumed_rl = true; - } - } - if (any_prong_consumed_rl) { - try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); - } - return any_prong_consumed_rl; - }, - .@"suspend" => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - return false; - }, - .@"resume" => { - _ = try astrl.expr(node_datas[node].lhs, block, ResultInfo.none); - return false; - }, - - .array_init_one, - .array_init_one_comma, - .array_init_dot_two, - .array_init_dot_two_comma, - .array_init_dot, - .array_init_dot_comma, - .array_init, - .array_init_comma, - => { - var buf: [2]Ast.Node.Index = undefined; - const full = tree.fullArrayInit(&buf, node).?; - - if (full.ast.type_expr != 0) { - // Explicitly typed init does not participate in RLS - _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none); - for (full.ast.elements) |elem_init| { - _ = try astrl.expr(elem_init, block, ResultInfo.type_only); - } - return false; - } - - if (ri.have_type) { - // Always forward type information - // If we have a result pointer, we use and forward it - for (full.ast.elements) |elem_init| { - _ = try astrl.expr(elem_init, block, ri); - } - return ri.have_ptr; - } else { - // Untyped init does not consume result location - for (full.ast.elements) |elem_init| { - _ = try astrl.expr(elem_init, block, ResultInfo.none); - } - return false; - } - }, - - .struct_init_one, - .struct_init_one_comma, - .struct_init_dot_two, - .struct_init_dot_two_comma, - .struct_init_dot, - .struct_init_dot_comma, - .struct_init, - .struct_init_comma, - => { - var buf: [2]Ast.Node.Index = undefined; - const full = tree.fullStructInit(&buf, node).?; - - if (full.ast.type_expr != 0) { - // Explicitly typed init does not participate in RLS - _ = try astrl.expr(full.ast.type_expr, block, ResultInfo.none); - for (full.ast.fields) |field_init| { - _ = try astrl.expr(field_init, block, ResultInfo.type_only); - } - return false; - } - - if (ri.have_type) { - // Always forward type information - // If we have a result pointer, we use and forward it - for (full.ast.fields) |field_init| { - _ = try astrl.expr(field_init, block, ri); - } - return ri.have_ptr; - } else { - // Untyped init does not consume result location - for (full.ast.fields) |field_init| { - _ = try astrl.expr(field_init, block, ResultInfo.none); - } - return false; - } - }, - - .fn_proto_simple, - .fn_proto_multi, - .fn_proto_one, - .fn_proto, - .fn_decl, - => { - var buf: [1]Ast.Node.Index = undefined; - const full = tree.fullFnProto(&buf, node).?; - const body_node = if (node_tags[node] == .fn_decl) node_datas[node].rhs else 0; - { - var it = full.iterate(tree); - while (it.next()) |param| { - if (param.anytype_ellipsis3 == null) { - _ = try astrl.expr(param.type_expr, block, ResultInfo.type_only); - } - } - } - if (full.ast.align_expr != 0) { - _ = try astrl.expr(full.ast.align_expr, block, ResultInfo.type_only); - } - if (full.ast.addrspace_expr != 0) { - _ = try astrl.expr(full.ast.addrspace_expr, block, ResultInfo.type_only); - } - if (full.ast.section_expr != 0) { - _ = try astrl.expr(full.ast.section_expr, block, ResultInfo.type_only); - } - if (full.ast.callconv_expr != 0) { - _ = try astrl.expr(full.ast.callconv_expr, block, ResultInfo.type_only); - } - _ = try astrl.expr(full.ast.return_type, block, ResultInfo.type_only); - if (body_node != 0) { - _ = try astrl.expr(body_node, block, ResultInfo.none); - } - return false; - }, - } -} - -fn identString(astrl: *AstRlAnnotate, token: Ast.TokenIndex) ![]const u8 { - const tree = astrl.tree; - const token_tags = tree.tokens.items(.tag); - assert(token_tags[token] == .identifier); - const ident_name = tree.tokenSlice(token); - if (!std.mem.startsWith(u8, ident_name, "@")) { - return ident_name; - } - return std.zig.string_literal.parseAlloc(astrl.arena, ident_name[1..]) catch |err| switch (err) { - error.OutOfMemory => error.OutOfMemory, - error.InvalidLiteral => "", // This pass can safely return garbage on invalid AST - }; -} - -fn blockExpr(astrl: *AstRlAnnotate, parent_block: ?*Block, ri: ResultInfo, node: Ast.Node.Index, statements: []const Ast.Node.Index) !bool { - const tree = astrl.tree; - const token_tags = tree.tokens.items(.tag); - const main_tokens = tree.nodes.items(.main_token); - - const lbrace = main_tokens[node]; - if (token_tags[lbrace - 1] == .colon and - token_tags[lbrace - 2] == .identifier) - { - // Labeled block - var new_block: Block = .{ - .parent = parent_block, - .label = try astrl.identString(lbrace - 2), - .is_loop = false, - .ri = ri, - .consumes_res_ptr = false, - }; - for (statements) |statement| { - _ = try astrl.expr(statement, &new_block, ResultInfo.none); - } - if (new_block.consumes_res_ptr) { - try astrl.nodes_need_rl.putNoClobber(astrl.gpa, node, {}); - } - return new_block.consumes_res_ptr; - } else { - // Unlabeled block - for (statements) |statement| { - _ = try astrl.expr(statement, parent_block, ResultInfo.none); - } - return false; - } -} - -fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.Node.Index, args: []const Ast.Node.Index) !bool { - _ = ri; // Currently, no builtin consumes its result location. - - const tree = astrl.tree; - const main_tokens = tree.nodes.items(.main_token); - const builtin_token = main_tokens[node]; - const builtin_name = tree.tokenSlice(builtin_token); - const info = BuiltinFn.list.get(builtin_name) orelse return false; - if (info.param_count) |expected| { - if (expected != args.len) return false; - } - switch (info.tag) { - .import => return false, - .compile_log, .TypeOf => { - for (args) |arg_node| { - _ = try astrl.expr(arg_node, block, ResultInfo.none); - } - return false; - }, - .as => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - return false; - }, - .bit_cast => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - return false; - }, - .union_init => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - _ = try astrl.expr(args[2], block, ResultInfo.type_only); - return false; - }, - .c_import => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - return false; - }, - .min, .max => { - for (args) |arg_node| { - _ = try astrl.expr(arg_node, block, ResultInfo.none); - } - return false; - }, - .@"export" => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - return false; - }, - .@"extern" => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - return false; - }, - // These builtins take no args and do not consume the result pointer. - .src, - .This, - .return_address, - .error_return_trace, - .frame, - .breakpoint, - .in_comptime, - .panic, - .trap, - .c_va_start, - => return false, - // TODO: this is a workaround for llvm/llvm-project#68409 - // Zig tracking issue: #16876 - .frame_address => return true, - // These builtins take a single argument with a known result type, but do not consume their - // result pointer. - .size_of, - .bit_size_of, - .align_of, - .compile_error, - .set_eval_branch_quota, - .int_from_bool, - .int_from_error, - .error_from_int, - .embed_file, - .error_name, - .set_runtime_safety, - .Type, - .c_undef, - .c_include, - .wasm_memory_size, - .splat, - .fence, - .set_float_mode, - .set_align_stack, - .set_cold, - .type_info, - .work_item_id, - .work_group_size, - .work_group_id, - => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - return false; - }, - // These builtins take a single argument with no result information and do not consume their - // result pointer. - .int_from_ptr, - .int_from_enum, - .sqrt, - .sin, - .cos, - .tan, - .exp, - .exp2, - .log, - .log2, - .log10, - .abs, - .floor, - .ceil, - .trunc, - .round, - .tag_name, - .type_name, - .Frame, - .frame_size, - .int_from_float, - .float_from_int, - .ptr_from_int, - .enum_from_int, - .float_cast, - .int_cast, - .truncate, - .error_cast, - .ptr_cast, - .align_cast, - .addrspace_cast, - .const_cast, - .volatile_cast, - .clz, - .ctz, - .pop_count, - .byte_swap, - .bit_reverse, - => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - return false; - }, - .div_exact, - .div_floor, - .div_trunc, - .mod, - .rem, - => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.none); - return false; - }, - .shl_exact, .shr_exact => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - return false; - }, - .bit_offset_of, - .offset_of, - .field_parent_ptr, - .has_decl, - .has_field, - .field, - => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - return false; - }, - .wasm_memory_grow => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - return false; - }, - .c_define => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.none); - return false; - }, - .reduce => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.none); - return false; - }, - .add_with_overflow, .sub_with_overflow, .mul_with_overflow, .shl_with_overflow => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.none); - return false; - }, - .atomic_load => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.none); - _ = try astrl.expr(args[2], block, ResultInfo.type_only); - return false; - }, - .atomic_rmw => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.none); - _ = try astrl.expr(args[2], block, ResultInfo.type_only); - _ = try astrl.expr(args[3], block, ResultInfo.type_only); - _ = try astrl.expr(args[4], block, ResultInfo.type_only); - return false; - }, - .atomic_store => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.none); - _ = try astrl.expr(args[2], block, ResultInfo.type_only); - _ = try astrl.expr(args[3], block, ResultInfo.type_only); - return false; - }, - .mul_add => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - _ = try astrl.expr(args[2], block, ResultInfo.type_only); - return false; - }, - .call => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.none); - _ = try astrl.expr(args[2], block, ResultInfo.none); - return false; - }, - .memcpy => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.none); - return false; - }, - .memset => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - return false; - }, - .shuffle => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.none); - _ = try astrl.expr(args[2], block, ResultInfo.none); - _ = try astrl.expr(args[3], block, ResultInfo.none); - return false; - }, - .select => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.none); - _ = try astrl.expr(args[2], block, ResultInfo.none); - _ = try astrl.expr(args[3], block, ResultInfo.none); - return false; - }, - .async_call => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.none); - _ = try astrl.expr(args[2], block, ResultInfo.none); - _ = try astrl.expr(args[3], block, ResultInfo.none); - return false; // buffer passed as arg for frame data - }, - .Vector => { - _ = try astrl.expr(args[0], block, ResultInfo.type_only); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - return false; - }, - .prefetch => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - return false; - }, - .c_va_arg => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - return false; - }, - .c_va_copy => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - return false; - }, - .c_va_end => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - return false; - }, - .cmpxchg_strong, .cmpxchg_weak => { - _ = try astrl.expr(args[0], block, ResultInfo.none); - _ = try astrl.expr(args[1], block, ResultInfo.type_only); - _ = try astrl.expr(args[2], block, ResultInfo.type_only); - _ = try astrl.expr(args[3], block, ResultInfo.type_only); - _ = try astrl.expr(args[4], block, ResultInfo.type_only); - return false; - }, - } -} diff --git a/src/BuiltinFn.zig b/src/BuiltinFn.zig deleted file mode 100644 index 3296114ef9d31c1e4576435851ec7928fcf402b9..0000000000000000000000000000000000000000 --- a/src/BuiltinFn.zig +++ /dev/null @@ -1,1017 +0,0 @@ -const std = @import("std"); - -pub const Tag = enum { - add_with_overflow, - addrspace_cast, - align_cast, - align_of, - as, - async_call, - atomic_load, - atomic_rmw, - atomic_store, - bit_cast, - bit_offset_of, - int_from_bool, - bit_size_of, - breakpoint, - mul_add, - byte_swap, - bit_reverse, - offset_of, - call, - c_define, - c_import, - c_include, - clz, - cmpxchg_strong, - cmpxchg_weak, - compile_error, - compile_log, - const_cast, - ctz, - c_undef, - c_va_arg, - c_va_copy, - c_va_end, - c_va_start, - div_exact, - div_floor, - div_trunc, - embed_file, - int_from_enum, - error_name, - error_return_trace, - int_from_error, - error_cast, - @"export", - @"extern", - fence, - field, - field_parent_ptr, - float_cast, - int_from_float, - frame, - Frame, - frame_address, - frame_size, - has_decl, - has_field, - import, - in_comptime, - int_cast, - enum_from_int, - error_from_int, - float_from_int, - ptr_from_int, - max, - memcpy, - memset, - min, - wasm_memory_size, - wasm_memory_grow, - mod, - mul_with_overflow, - panic, - pop_count, - prefetch, - ptr_cast, - int_from_ptr, - rem, - return_address, - select, - set_align_stack, - set_cold, - set_eval_branch_quota, - set_float_mode, - set_runtime_safety, - shl_exact, - shl_with_overflow, - shr_exact, - shuffle, - size_of, - splat, - reduce, - src, - sqrt, - sin, - cos, - tan, - exp, - exp2, - log, - log2, - log10, - abs, - floor, - ceil, - trunc, - round, - sub_with_overflow, - tag_name, - This, - trap, - truncate, - Type, - type_info, - type_name, - TypeOf, - union_init, - Vector, - volatile_cast, - work_item_id, - work_group_size, - work_group_id, -}; - -pub const MemLocRequirement = enum { - /// The builtin never needs a memory location. - never, - /// The builtin always needs a memory location. - always, - /// The builtin forwards the question to argument at index 0. - forward0, - /// The builtin forwards the question to argument at index 1. - forward1, -}; - -pub const EvalToError = enum { - /// The builtin cannot possibly evaluate to an error. - never, - /// The builtin will always evaluate to an error. - always, - /// The builtin may or may not evaluate to an error depending on the parameters. - maybe, -}; - -tag: Tag, - -/// Info about the builtin call's ability to take advantage of a result location pointer. -needs_mem_loc: MemLocRequirement = .never, -/// Info about the builtin call's possibility of returning an error. -eval_to_error: EvalToError = .never, -/// `true` if the builtin call can be the left-hand side of an expression (assigned to). -allows_lvalue: bool = false, -/// The number of parameters to this builtin function. `null` means variable number -/// of parameters. -param_count: ?u8, - -pub const list = list: { - @setEvalBranchQuota(3000); - break :list std.ComptimeStringMap(@This(), .{ - .{ - "@addWithOverflow", - .{ - .tag = .add_with_overflow, - .param_count = 2, - }, - }, - .{ - "@addrSpaceCast", - .{ - .tag = .addrspace_cast, - .param_count = 1, - }, - }, - .{ - "@alignCast", - .{ - .tag = .align_cast, - .param_count = 1, - }, - }, - .{ - "@alignOf", - .{ - .tag = .align_of, - .param_count = 1, - }, - }, - .{ - "@as", - .{ - .tag = .as, - .needs_mem_loc = .forward1, - .eval_to_error = .maybe, - .param_count = 2, - }, - }, - .{ - "@asyncCall", - .{ - .tag = .async_call, - .param_count = 4, - }, - }, - .{ - "@atomicLoad", - .{ - .tag = .atomic_load, - .param_count = 3, - }, - }, - .{ - "@atomicRmw", - .{ - .tag = .atomic_rmw, - .param_count = 5, - }, - }, - .{ - "@atomicStore", - .{ - .tag = .atomic_store, - .param_count = 4, - }, - }, - .{ - "@bitCast", - .{ - .tag = .bit_cast, - .needs_mem_loc = .forward0, - .param_count = 1, - }, - }, - .{ - "@bitOffsetOf", - .{ - .tag = .bit_offset_of, - .param_count = 2, - }, - }, - .{ - "@intFromBool", - .{ - .tag = .int_from_bool, - .param_count = 1, - }, - }, - .{ - "@bitSizeOf", - .{ - .tag = .bit_size_of, - .param_count = 1, - }, - }, - .{ - "@breakpoint", - .{ - .tag = .breakpoint, - .param_count = 0, - }, - }, - .{ - "@mulAdd", - .{ - .tag = .mul_add, - .param_count = 4, - }, - }, - .{ - "@byteSwap", - .{ - .tag = .byte_swap, - .param_count = 1, - }, - }, - .{ - "@bitReverse", - .{ - .tag = .bit_reverse, - .param_count = 1, - }, - }, - .{ - "@offsetOf", - .{ - .tag = .offset_of, - .param_count = 2, - }, - }, - .{ - "@call", - .{ - .tag = .call, - .needs_mem_loc = .always, - .eval_to_error = .maybe, - .param_count = 3, - }, - }, - .{ - "@cDefine", - .{ - .tag = .c_define, - .param_count = 2, - }, - }, - .{ - "@cImport", - .{ - .tag = .c_import, - .param_count = 1, - }, - }, - .{ - "@cInclude", - .{ - .tag = .c_include, - .param_count = 1, - }, - }, - .{ - "@clz", - .{ - .tag = .clz, - .param_count = 1, - }, - }, - .{ - "@cmpxchgStrong", - .{ - .tag = .cmpxchg_strong, - .param_count = 6, - }, - }, - .{ - "@cmpxchgWeak", - .{ - .tag = .cmpxchg_weak, - .param_count = 6, - }, - }, - .{ - "@compileError", - .{ - .tag = .compile_error, - .param_count = 1, - }, - }, - .{ - "@compileLog", - .{ - .tag = .compile_log, - .param_count = null, - }, - }, - .{ - "@constCast", - .{ - .tag = .const_cast, - .param_count = 1, - }, - }, - .{ - "@ctz", - .{ - .tag = .ctz, - .param_count = 1, - }, - }, - .{ - "@cUndef", - .{ - .tag = .c_undef, - .param_count = 1, - }, - }, - .{ - "@cVaArg", .{ - .tag = .c_va_arg, - .param_count = 2, - }, - }, - .{ - "@cVaCopy", .{ - .tag = .c_va_copy, - .param_count = 1, - }, - }, - .{ - "@cVaEnd", .{ - .tag = .c_va_end, - .param_count = 1, - }, - }, - .{ - "@cVaStart", .{ - .tag = .c_va_start, - .param_count = 0, - }, - }, - .{ - "@divExact", - .{ - .tag = .div_exact, - .param_count = 2, - }, - }, - .{ - "@divFloor", - .{ - .tag = .div_floor, - .param_count = 2, - }, - }, - .{ - "@divTrunc", - .{ - .tag = .div_trunc, - .param_count = 2, - }, - }, - .{ - "@embedFile", - .{ - .tag = .embed_file, - .param_count = 1, - }, - }, - .{ - "@intFromEnum", - .{ - .tag = .int_from_enum, - .param_count = 1, - }, - }, - .{ - "@errorName", - .{ - .tag = .error_name, - .param_count = 1, - }, - }, - .{ - "@errorReturnTrace", - .{ - .tag = .error_return_trace, - .param_count = 0, - }, - }, - .{ - "@intFromError", - .{ - .tag = .int_from_error, - .param_count = 1, - }, - }, - .{ - "@errorCast", - .{ - .tag = .error_cast, - .eval_to_error = .always, - .param_count = 1, - }, - }, - .{ - "@export", - .{ - .tag = .@"export", - .param_count = 2, - }, - }, - .{ - "@extern", - .{ - .tag = .@"extern", - .param_count = 2, - }, - }, - .{ - "@fence", - .{ - .tag = .fence, - .param_count = 1, - }, - }, - .{ - "@field", - .{ - .tag = .field, - .needs_mem_loc = .always, - .eval_to_error = .maybe, - .param_count = 2, - .allows_lvalue = true, - }, - }, - .{ - "@fieldParentPtr", - .{ - .tag = .field_parent_ptr, - .param_count = 3, - }, - }, - .{ - "@floatCast", - .{ - .tag = .float_cast, - .param_count = 1, - }, - }, - .{ - "@intFromFloat", - .{ - .tag = .int_from_float, - .param_count = 1, - }, - }, - .{ - "@frame", - .{ - .tag = .frame, - .param_count = 0, - }, - }, - .{ - "@Frame", - .{ - .tag = .Frame, - .param_count = 1, - }, - }, - .{ - "@frameAddress", - .{ - .tag = .frame_address, - .param_count = 0, - }, - }, - .{ - "@frameSize", - .{ - .tag = .frame_size, - .param_count = 1, - }, - }, - .{ - "@hasDecl", - .{ - .tag = .has_decl, - .param_count = 2, - }, - }, - .{ - "@hasField", - .{ - .tag = .has_field, - .param_count = 2, - }, - }, - .{ - "@import", - .{ - .tag = .import, - .param_count = 1, - }, - }, - .{ - "@inComptime", - .{ - .tag = .in_comptime, - .param_count = 0, - }, - }, - .{ - "@intCast", - .{ - .tag = .int_cast, - .param_count = 1, - }, - }, - .{ - "@enumFromInt", - .{ - .tag = .enum_from_int, - .param_count = 1, - }, - }, - .{ - "@errorFromInt", - .{ - .tag = .error_from_int, - .eval_to_error = .always, - .param_count = 1, - }, - }, - .{ - "@floatFromInt", - .{ - .tag = .float_from_int, - .param_count = 1, - }, - }, - .{ - "@ptrFromInt", - .{ - .tag = .ptr_from_int, - .param_count = 1, - }, - }, - .{ - "@max", - .{ - .tag = .max, - .param_count = null, - }, - }, - .{ - "@memcpy", - .{ - .tag = .memcpy, - .param_count = 2, - }, - }, - .{ - "@memset", - .{ - .tag = .memset, - .param_count = 2, - }, - }, - .{ - "@min", - .{ - .tag = .min, - .param_count = null, - }, - }, - .{ - "@wasmMemorySize", - .{ - .tag = .wasm_memory_size, - .param_count = 1, - }, - }, - .{ - "@wasmMemoryGrow", - .{ - .tag = .wasm_memory_grow, - .param_count = 2, - }, - }, - .{ - "@mod", - .{ - .tag = .mod, - .param_count = 2, - }, - }, - .{ - "@mulWithOverflow", - .{ - .tag = .mul_with_overflow, - .param_count = 2, - }, - }, - .{ - "@panic", - .{ - .tag = .panic, - .param_count = 1, - }, - }, - .{ - "@popCount", - .{ - .tag = .pop_count, - .param_count = 1, - }, - }, - .{ - "@prefetch", - .{ - .tag = .prefetch, - .param_count = 2, - }, - }, - .{ - "@ptrCast", - .{ - .tag = .ptr_cast, - .param_count = 1, - }, - }, - .{ - "@intFromPtr", - .{ - .tag = .int_from_ptr, - .param_count = 1, - }, - }, - .{ - "@rem", - .{ - .tag = .rem, - .param_count = 2, - }, - }, - .{ - "@returnAddress", - .{ - .tag = .return_address, - .param_count = 0, - }, - }, - .{ - "@select", - .{ - .tag = .select, - .param_count = 4, - }, - }, - .{ - "@setAlignStack", - .{ - .tag = .set_align_stack, - .param_count = 1, - }, - }, - .{ - "@setCold", - .{ - .tag = .set_cold, - .param_count = 1, - }, - }, - .{ - "@setEvalBranchQuota", - .{ - .tag = .set_eval_branch_quota, - .param_count = 1, - }, - }, - .{ - "@setFloatMode", - .{ - .tag = .set_float_mode, - .param_count = 1, - }, - }, - .{ - "@setRuntimeSafety", - .{ - .tag = .set_runtime_safety, - .param_count = 1, - }, - }, - .{ - "@shlExact", - .{ - .tag = .shl_exact, - .param_count = 2, - }, - }, - .{ - "@shlWithOverflow", - .{ - .tag = .shl_with_overflow, - .param_count = 2, - }, - }, - .{ - "@shrExact", - .{ - .tag = .shr_exact, - .param_count = 2, - }, - }, - .{ - "@shuffle", - .{ - .tag = .shuffle, - .param_count = 4, - }, - }, - .{ - "@sizeOf", - .{ - .tag = .size_of, - .param_count = 1, - }, - }, - .{ - "@splat", - .{ - .tag = .splat, - .param_count = 1, - }, - }, - .{ - "@reduce", - .{ - .tag = .reduce, - .param_count = 2, - }, - }, - .{ - "@src", - .{ - .tag = .src, - .needs_mem_loc = .always, - .param_count = 0, - }, - }, - .{ - "@sqrt", - .{ - .tag = .sqrt, - .param_count = 1, - }, - }, - .{ - "@sin", - .{ - .tag = .sin, - .param_count = 1, - }, - }, - .{ - "@cos", - .{ - .tag = .cos, - .param_count = 1, - }, - }, - .{ - "@tan", - .{ - .tag = .tan, - .param_count = 1, - }, - }, - .{ - "@exp", - .{ - .tag = .exp, - .param_count = 1, - }, - }, - .{ - "@exp2", - .{ - .tag = .exp2, - .param_count = 1, - }, - }, - .{ - "@log", - .{ - .tag = .log, - .param_count = 1, - }, - }, - .{ - "@log2", - .{ - .tag = .log2, - .param_count = 1, - }, - }, - .{ - "@log10", - .{ - .tag = .log10, - .param_count = 1, - }, - }, - .{ - "@abs", - .{ - .tag = .abs, - .param_count = 1, - }, - }, - .{ - "@floor", - .{ - .tag = .floor, - .param_count = 1, - }, - }, - .{ - "@ceil", - .{ - .tag = .ceil, - .param_count = 1, - }, - }, - .{ - "@trunc", - .{ - .tag = .trunc, - .param_count = 1, - }, - }, - .{ - "@round", - .{ - .tag = .round, - .param_count = 1, - }, - }, - .{ - "@subWithOverflow", - .{ - .tag = .sub_with_overflow, - .param_count = 2, - }, - }, - .{ - "@tagName", - .{ - .tag = .tag_name, - .param_count = 1, - }, - }, - .{ - "@This", - .{ - .tag = .This, - .param_count = 0, - }, - }, - .{ - "@trap", - .{ - .tag = .trap, - .param_count = 0, - }, - }, - .{ - "@truncate", - .{ - .tag = .truncate, - .param_count = 1, - }, - }, - .{ - "@Type", - .{ - .tag = .Type, - .param_count = 1, - }, - }, - .{ - "@typeInfo", - .{ - .tag = .type_info, - .param_count = 1, - }, - }, - .{ - "@typeName", - .{ - .tag = .type_name, - .param_count = 1, - }, - }, - .{ - "@TypeOf", - .{ - .tag = .TypeOf, - .param_count = null, - }, - }, - .{ - "@unionInit", - .{ - .tag = .union_init, - .needs_mem_loc = .always, - .param_count = 3, - }, - }, - .{ - "@Vector", - .{ - .tag = .Vector, - .param_count = 2, - }, - }, - .{ - "@volatileCast", - .{ - .tag = .volatile_cast, - .param_count = 1, - }, - }, - .{ - "@workItemId", .{ - .tag = .work_item_id, - .param_count = 1, - }, - }, - .{ - "@workGroupSize", - .{ - .tag = .work_group_size, - .param_count = 1, - }, - }, - .{ - "@workGroupId", - .{ - .tag = .work_group_id, - .param_count = 1, - }, - }, - }); -}; diff --git a/src/Module.zig b/src/Module.zig index 9112523d33750ef132c48e44b4b418fc926e29de..fd5bb5b5dce7ef50c37c5e55ebc91ea89d0f2fcd 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -34,7 +34,7 @@ const isUpDir = @import("introspect.zig").isUpDir; const clang = @import("clang.zig"); const InternPool = @import("InternPool.zig"); const Alignment = InternPool.Alignment; -const BuiltinFn = @import("BuiltinFn.zig"); +const BuiltinFn = std.zig.BuiltinFn; comptime { @setEvalBranchQuota(4000); diff --git a/src/reduce/Walk.zig b/src/reduce/Walk.zig index a27d893c5d51537b884235ecb8df8811e6999842..572243d82970c3dc3cfe5a1f26db279a13bba559 100644 --- a/src/reduce/Walk.zig +++ b/src/reduce/Walk.zig @@ -2,7 +2,7 @@ const std = @import("std"); const Ast = std.zig.Ast; const Walk = @This(); const assert = std.debug.assert; -const BuiltinFn = @import("../BuiltinFn.zig"); +const BuiltinFn = std.zig.BuiltinFn; ast: *const Ast, transformations: *std.ArrayList(Transformation),