diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 897 | ||||
| -rw-r--r-- | src/Module.zig | 48 | ||||
| -rw-r--r-- | src/Sema.zig | 849 | ||||
| -rw-r--r-- | src/Zir.zig | 573 | ||||
| -rw-r--r-- | src/type.zig | 188 | ||||
| -rw-r--r-- | src/value.zig | 58 |
6 files changed, 2185 insertions, 428 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 68e8fcc42e..d7c379c0a0 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -51,6 +51,7 @@ pub fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { astgen.extra.appendAssumeCapacity(switch (field.field_type) { u32 => @field(extra, field.name), Zir.Inst.Ref => @enumToInt(@field(extra, field.name)), + i32 => @bitCast(u32, @field(extra, field.name)), else => @compileError("bad field type"), }); } @@ -237,6 +238,9 @@ pub const ResultLoc = union(enum) { } }; +pub const align_rl: ResultLoc = .{ .ty = .u16_type }; +pub const bool_rl: ResultLoc = .{ .ty = .bool_type }; + pub fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref { return expr(gz, scope, .{ .ty = .type_type }, type_node); } @@ -469,20 +473,22 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn try assign(gz, scope, node); return rvalue(gz, scope, rl, .void_value, node); }, - .assign_bit_and => { - try assignOp(gz, scope, node, .bit_and); + + .assign_bit_shift_left => { + try assignShift(gz, scope, node, .shl); return rvalue(gz, scope, rl, .void_value, node); }, - .assign_bit_or => { - try assignOp(gz, scope, node, .bit_or); + .assign_bit_shift_right => { + try assignShift(gz, scope, node, .shr); return rvalue(gz, scope, rl, .void_value, node); }, - .assign_bit_shift_left => { - try assignOp(gz, scope, node, .shl); + + .assign_bit_and => { + try assignOp(gz, scope, node, .bit_and); return rvalue(gz, scope, rl, .void_value, node); }, - .assign_bit_shift_right => { - try assignOp(gz, scope, node, .shr); + .assign_bit_or => { + try assignOp(gz, scope, node, .bit_or); return rvalue(gz, scope, rl, .void_value, node); }, .assign_bit_xor => { @@ -522,51 +528,54 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn return rvalue(gz, scope, rl, .void_value, node); }, - .add => return simpleBinOp(gz, scope, rl, node, .add), + // zig fmt: off + .bit_shift_left => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl), + .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr), + + .add => return simpleBinOp(gz, scope, rl, node, .add), .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap), - .sub => return simpleBinOp(gz, scope, rl, node, .sub), + .sub => return simpleBinOp(gz, scope, rl, node, .sub), .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap), - .mul => return simpleBinOp(gz, scope, rl, node, .mul), + .mul => return simpleBinOp(gz, scope, rl, node, .mul), .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap), - .div => return simpleBinOp(gz, scope, rl, node, .div), - .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem), - .bit_and => return simpleBinOp(gz, scope, rl, node, .bit_and), - .bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or), - .bit_shift_left => return simpleBinOp(gz, scope, rl, node, .shl), - .bit_shift_right => return simpleBinOp(gz, scope, rl, node, .shr), - .bit_xor => return simpleBinOp(gz, scope, rl, node, .xor), - - .bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq), - .equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq), - .greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt), + .div => return simpleBinOp(gz, scope, rl, node, .div), + .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem), + .bit_and => return simpleBinOp(gz, scope, rl, node, .bit_and), + .bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or), + .bit_xor => return simpleBinOp(gz, scope, rl, node, .xor), + + .bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq), + .equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq), + .greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt), .greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte), - .less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt), - .less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte), + .less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt), + .less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte), - .array_cat => return simpleBinOp(gz, scope, rl, node, .array_cat), - .array_mult => return simpleBinOp(gz, scope, rl, node, .array_mul), + .array_cat => return simpleBinOp(gz, scope, rl, node, .array_cat), + .array_mult => return simpleBinOp(gz, scope, rl, node, .array_mul), - .error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type), + .error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type), .merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets), .bool_and => return boolBinOp(gz, scope, rl, node, .bool_br_and), - .bool_or => return boolBinOp(gz, scope, rl, node, .bool_br_or), + .bool_or => return boolBinOp(gz, scope, rl, node, .bool_br_or), .bool_not => return boolNot(gz, scope, rl, node), - .bit_not => return bitNot(gz, scope, rl, node), + .bit_not => return bitNot(gz, scope, rl, node), - .negation => return negation(gz, scope, rl, node, .negate), + .negation => return negation(gz, scope, rl, node, .negate), .negation_wrap => return negation(gz, scope, rl, node, .negate_wrap), .identifier => return identifier(gz, scope, rl, node), .asm_simple => return asmExpr(gz, scope, rl, node, tree.asmSimple(node)), - .@"asm" => return asmExpr(gz, scope, rl, node, tree.asmFull(node)), + .@"asm" => return asmExpr(gz, scope, rl, node, tree.asmFull(node)), - .string_literal => return stringLiteral(gz, scope, rl, node), + .string_literal => return stringLiteral(gz, scope, rl, node), .multiline_string_literal => return multilineStringLiteral(gz, scope, rl, node), .integer_literal => return integerLiteral(gz, scope, rl, node), + // zig fmt: on .builtin_call_two, .builtin_call_two_comma => { if (node_datas[node].lhs == 0) { @@ -1181,13 +1190,14 @@ fn labeledBlockExpr( // All break operands are values that did not use the result location pointer. if (strat.elide_store_to_block_ptr_instructions) { for (block_scope.labeled_store_to_block_ptr_list.items) |inst| { - zir_tags[inst] = .elided; - zir_datas[inst] = undefined; + // Mark as elided for removal below. + assert(zir_tags[inst] == .store_to_block_ptr); + zir_datas[inst].bin.lhs = .none; } - // TODO technically not needed since we changed the tag to elided but - // would be better still to elide the ones that are in this list. + try block_scope.setBlockBodyEliding(block_inst); + } else { + try block_scope.setBlockBody(block_inst); } - try block_scope.setBlockBody(block_inst); const block_ref = gz.indexToRef(block_inst); switch (rl) { .ref => return block_ref, @@ -1222,20 +1232,24 @@ fn blockExprStmts( .simple_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.simpleVarDecl(statement)), .aligned_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.alignedVarDecl(statement)), + // zig fmt: off .assign => try assign(gz, scope, statement), - .assign_bit_and => try assignOp(gz, scope, statement, .bit_and), - .assign_bit_or => try assignOp(gz, scope, statement, .bit_or), - .assign_bit_shift_left => try assignOp(gz, scope, statement, .shl), - .assign_bit_shift_right => try assignOp(gz, scope, statement, .shr), - .assign_bit_xor => try assignOp(gz, scope, statement, .xor), - .assign_div => try assignOp(gz, scope, statement, .div), - .assign_sub => try assignOp(gz, scope, statement, .sub), + + .assign_bit_shift_left => try assignShift(gz, scope, statement, .shl), + .assign_bit_shift_right => try assignShift(gz, scope, statement, .shr), + + .assign_bit_and => try assignOp(gz, scope, statement, .bit_and), + .assign_bit_or => try assignOp(gz, scope, statement, .bit_or), + .assign_bit_xor => try assignOp(gz, scope, statement, .xor), + .assign_div => try assignOp(gz, scope, statement, .div), + .assign_sub => try assignOp(gz, scope, statement, .sub), .assign_sub_wrap => try assignOp(gz, scope, statement, .subwrap), - .assign_mod => try assignOp(gz, scope, statement, .mod_rem), - .assign_add => try assignOp(gz, scope, statement, .add), + .assign_mod => try assignOp(gz, scope, statement, .mod_rem), + .assign_add => try assignOp(gz, scope, statement, .add), .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap), - .assign_mul => try assignOp(gz, scope, statement, .mul), + .assign_mul => try assignOp(gz, scope, statement, .mul), .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap), + // zig fmt: on else => { // We need to emit an error if the result is not `noreturn` or `void`, but @@ -1313,7 +1327,6 @@ fn blockExprStmts( .func_var_args, .func_extra, .func_extra_var_args, - .has_decl, .int, .float, .float128, @@ -1390,6 +1403,7 @@ fn blockExprStmts( .switch_capture_else_ref, .struct_init_empty, .struct_init, + .union_init_ptr, .field_type, .struct_decl, .struct_decl_packed, @@ -1404,7 +1418,6 @@ fn blockExprStmts( .size_of, .bit_size_of, .this, - .fence, .ret_addr, .builtin_src, .add_with_overflow, @@ -1412,10 +1425,80 @@ fn blockExprStmts( .mul_with_overflow, .shl_with_overflow, .log2_int_type, + .typeof_log2_int_type, + .error_return_trace, + .frame, + .frame_address, + .ptr_to_int, + .align_of, + .bool_to_int, + .embed_file, + .error_name, + .sqrt, + .sin, + .cos, + .exp, + .exp2, + .log, + .log2, + .log10, + .fabs, + .floor, + .ceil, + .trunc, + .round, + .tag_name, + .reify, + .type_name, + .frame_type, + .frame_size, + .float_to_int, + .int_to_float, + .int_to_ptr, + .float_cast, + .int_cast, + .err_set_cast, + .ptr_cast, + .truncate, + .align_cast, + .has_decl, + .has_field, + .clz, + .ctz, + .pop_count, + .byte_swap, + .bit_reverse, + .div_exact, + .div_floor, + .div_trunc, + .mod, + .rem, + .shl_exact, + .shr_exact, + .bit_offset_of, + .byte_offset_of, + .cmpxchg_strong, + .cmpxchg_weak, + .splat, + .reduce, + .shuffle, + .atomic_load, + .atomic_rmw, + .atomic_store, + .mul_add, + .builtin_call, + .field_ptr_type, + .field_parent_ptr, + .memcpy, + .memset, + .builtin_async_call, + .c_import, + .extended, => break :b false, // ZIR instructions that are always either `noreturn` or `void`. .breakpoint, + .fence, .dbg_stmt_node, .ensure_result_used, .ensure_result_non_error, @@ -1432,7 +1515,6 @@ fn blockExprStmts( .ret_tok, .ret_coerce, .@"unreachable", - .elided, .store, .store_node, .store_to_block_ptr, @@ -1441,6 +1523,11 @@ fn blockExprStmts( .repeat, .repeat_inline, .validate_struct_init_ptr, + .panic, + .set_align_stack, + .set_cold, + .set_float_mode, + .set_runtime_safety, => break :b true, } } else switch (maybe_unused_result) { @@ -1702,12 +1789,34 @@ fn assignOp( _ = try gz.addBin(.store, lhs_ptr, result); } +fn assignShift( + gz: *GenZir, + scope: *Scope, + infix_node: ast.Node.Index, + op_inst_tag: Zir.Inst.Tag, +) InnerError!void { + const astgen = gz.astgen; + const tree = &astgen.file.tree; + const node_datas = tree.nodes.items(.data); + + const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); + const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); + const rhs_type = try gz.addUnNode(.typeof_log2_int_type, lhs, infix_node); + const rhs = try expr(gz, scope, .{ .ty = rhs_type }, node_datas[infix_node].rhs); + + const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ + .lhs = lhs, + .rhs = rhs, + }); + _ = try gz.addBin(.store, lhs_ptr, result); +} + fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = &astgen.file.tree; const node_datas = tree.nodes.items(.data); - const operand = try expr(gz, scope, .{ .ty = .bool_type }, node_datas[node].lhs); + const operand = try expr(gz, scope, bool_rl, node_datas[node].lhs); const result = try gz.addUnNode(.bool_not, operand, node); return rvalue(gz, scope, rl, result, node); } @@ -1778,7 +1887,7 @@ fn ptrType( trailing_count += 1; } if (ptr_info.ast.align_node != 0) { - align_ref = try expr(gz, scope, .none, ptr_info.ast.align_node); + align_ref = try expr(gz, scope, align_rl, ptr_info.ast.align_node); trailing_count += 1; } if (ptr_info.ast.bit_range_start != 0) { @@ -1978,19 +2087,16 @@ fn fnDecl( ); const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) - // TODO instead of enum literal type, this needs to be the - // std.builtin.CallingConvention enum. We need to implement importing other files - // and enums in order to fix this. try AstGen.expr( &decl_gz, &decl_gz.base, - .{ .ty = .enum_literal_type }, + .{ .ty = .calling_convention_type }, fn_proto.ast.callconv_expr, ) else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269 - try decl_gz.addSmallStr(.enum_literal_small, "C") + Zir.Inst.Ref.calling_convention_c else - .none; + Zir.Inst.Ref.none; const func_inst: Zir.Inst.Ref = if (body_node == 0) func: { if (is_extern) { @@ -3079,7 +3185,7 @@ fn boolBinOp( ) InnerError!Zir.Inst.Ref { const node_datas = gz.tree().nodes.items(.data); - const lhs = try expr(gz, scope, .{ .ty = .bool_type }, node_datas[node].lhs); + const lhs = try expr(gz, scope, bool_rl, node_datas[node].lhs); const bool_br = try gz.addBoolBr(zir_tag, lhs); var rhs_scope: GenZir = .{ @@ -3089,7 +3195,7 @@ fn boolBinOp( .force_comptime = gz.force_comptime, }; defer rhs_scope.instructions.deinit(gz.astgen.gpa); - const rhs = try expr(&rhs_scope, &rhs_scope.base, .{ .ty = .bool_type }, node_datas[node].rhs); + const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs); _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs); try rhs_scope.setBoolBrBody(bool_br); @@ -3122,7 +3228,7 @@ fn ifExpr( } else if (if_full.payload_token) |payload_token| { return astgen.failTok(payload_token, "TODO implement if optional", .{}); } else { - break :c try expr(&block_scope, &block_scope.base, .{ .ty = .bool_type }, if_full.ast.cond_expr); + break :c try expr(&block_scope, &block_scope.base, bool_rl, if_full.ast.cond_expr); } }; @@ -3291,8 +3397,7 @@ fn whileExpr( } else if (while_full.payload_token) |payload_token| { return astgen.failTok(payload_token, "TODO implement while optional", .{}); } else { - const bool_type_rl: ResultLoc = .{ .ty = .bool_type }; - break :c try expr(&continue_scope, &continue_scope.base, bool_type_rl, while_full.ast.cond_expr); + break :c try expr(&continue_scope, &continue_scope.base, bool_rl, while_full.ast.cond_expr); } }; @@ -4758,37 +4863,8 @@ fn builtinCall( } } + // zig fmt: off switch (info.tag) { - .ptr_to_int => { - const operand = try expr(gz, scope, .none, params[0]); - const result = try gz.addUnNode(.ptrtoint, operand, node); - return rvalue(gz, scope, rl, result, node); - }, - .float_cast => { - const dest_type = try typeExpr(gz, scope, params[0]); - const rhs = try expr(gz, scope, .none, params[1]); - const result = try gz.addPlNode(.floatcast, node, Zir.Inst.Bin{ - .lhs = dest_type, - .rhs = rhs, - }); - return rvalue(gz, scope, rl, result, node); - }, - .int_cast => { - const dest_type = try typeExpr(gz, scope, params[0]); - const rhs = try expr(gz, scope, .none, params[1]); - const result = try gz.addPlNode(.intcast, node, Zir.Inst.Bin{ - .lhs = dest_type, - .rhs = rhs, - }); - return rvalue(gz, scope, rl, result, node); - }, - .breakpoint => { - _ = try gz.add(.{ - .tag = .breakpoint, - .data = .{ .node = gz.nodeIndexToRelative(node) }, - }); - return rvalue(gz, scope, rl, .void_value, node); - }, .import => { const node_tags = tree.nodes.items(.tag); const node_datas = tree.nodes.items(.data); @@ -4804,26 +4880,6 @@ fn builtinCall( const result = try gz.addStrTok(.import, str.index, str_lit_token); return rvalue(gz, scope, rl, result, node); }, - .error_to_int => { - const target = try expr(gz, scope, .none, params[0]); - const result = try gz.addUnNode(.error_to_int, target, node); - return rvalue(gz, scope, rl, result, node); - }, - .int_to_error => { - const target = try expr(gz, scope, .{ .ty = .u16_type }, params[0]); - const result = try gz.addUnNode(.int_to_error, target, node); - return rvalue(gz, scope, rl, result, node); - }, - .compile_error => { - const target = try expr(gz, scope, .none, params[0]); - const result = try gz.addUnNode(.compile_error, target, node); - return rvalue(gz, scope, rl, result, node); - }, - .set_eval_branch_quota => { - const quota = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); - const result = try gz.addUnNode(.set_eval_branch_quota, quota, node); - return rvalue(gz, scope, rl, result, node); - }, .compile_log => { const arg_refs = try astgen.gpa.alloc(Zir.Inst.Ref, params.len); defer astgen.gpa.free(arg_refs); @@ -4850,23 +4906,11 @@ fn builtinCall( }); return rvalue(gz, scope, rl, result, node); }, - .as => return as(gz, scope, rl, node, params[0], params[1]), - .bit_cast => return bitCast(gz, scope, rl, node, params[0], params[1]), - .TypeOf => return typeOf(gz, scope, rl, node, params), - - .int_to_enum => { - const result = try gz.addPlNode(.int_to_enum, node, Zir.Inst.Bin{ - .lhs = try typeExpr(gz, scope, params[0]), - .rhs = try expr(gz, scope, .none, params[1]), - }); - return rvalue(gz, scope, rl, result, node); - }, - - .enum_to_int => { - const operand = try expr(gz, scope, .none, params[0]); - const result = try gz.addUnNode(.enum_to_int, operand, node); - return rvalue(gz, scope, rl, result, node); - }, + .as => return as( gz, scope, rl, node, params[0], params[1]), + .bit_cast => return bitCast( gz, scope, rl, node, params[0], params[1]), + .TypeOf => return typeOf( gz, scope, rl, node, params), + .union_init => return unionInit(gz, scope, rl, node, params), + .c_import => return cImport( gz, scope, rl, node, params[0]), .@"export" => { // TODO: @export is supposed to be able to export things other than functions. @@ -4882,38 +4926,147 @@ fn builtinCall( return rvalue(gz, scope, rl, .void_value, node); }, - .has_decl => { - const container_type = try typeExpr(gz, scope, params[0]); - const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); - const result = try gz.addPlNode(.has_decl, node, Zir.Inst.Bin{ - .lhs = container_type, - .rhs = name, + .breakpoint => return simpleNoOpVoid(gz, scope, rl, node, .breakpoint), + .fence => return simpleNoOpVoid(gz, scope, rl, node, .fence), + + .This => return rvalue(gz, scope, rl, try gz.addNode(.this, node), node), + .return_address => return rvalue(gz, scope, rl, try gz.addNode(.ret_addr, node), node), + .src => return rvalue(gz, scope, rl, try gz.addNode(.builtin_src, node), node), + .error_return_trace => return rvalue(gz, scope, rl, try gz.addNode(.error_return_trace, node), node), + .frame => return rvalue(gz, scope, rl, try gz.addNode(.frame, node), node), + .frame_address => return rvalue(gz, scope, rl, try gz.addNode(.frame_address, node), node), + + .type_info => return simpleUnOpType(gz, scope, rl, node, params[0], .type_info), + .size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .size_of), + .bit_size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .bit_size_of), + .align_of => return simpleUnOpType(gz, scope, rl, node, params[0], .align_of), + + .ptr_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ptr_to_int), + .error_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .error_to_int), + .int_to_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u16_type }, params[0], .int_to_error), + .compile_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .compile_error), + .set_eval_branch_quota => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u32_type }, params[0], .set_eval_branch_quota), + .enum_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .enum_to_int), + .bool_to_int => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .bool_to_int), + .embed_file => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .embed_file), + .error_name => return simpleUnOp(gz, scope, rl, node, .{ .ty = .anyerror_type }, params[0], .error_name), + .panic => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .panic), + .set_align_stack => return simpleUnOp(gz, scope, rl, node, align_rl, params[0], .set_align_stack), + .set_cold => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_cold), + .set_float_mode => return simpleUnOp(gz, scope, rl, node, .{ .ty = .float_mode_type }, params[0], .set_float_mode), + .set_runtime_safety => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_runtime_safety), + .sqrt => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sqrt), + .sin => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sin), + .cos => return simpleUnOp(gz, scope, rl, node, .none, params[0], .cos), + .exp => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp), + .exp2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp2), + .log => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log), + .log2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log2), + .log10 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log10), + .fabs => return simpleUnOp(gz, scope, rl, node, .none, params[0], .fabs), + .floor => return simpleUnOp(gz, scope, rl, node, .none, params[0], .floor), + .ceil => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ceil), + .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc), + .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round), + .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name), + .Type => return simpleUnOp(gz, scope, rl, node, .none, params[0], .reify), + .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name), + .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type), + .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size), + + .float_to_int => return typeCast(gz, scope, rl, node, params[0], params[1], .float_to_int), + .int_to_float => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_float), + .int_to_ptr => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_ptr), + .int_to_enum => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_enum), + .float_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .float_cast), + .int_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .int_cast), + .err_set_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .err_set_cast), + .ptr_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .ptr_cast), + .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate), + .align_cast => { + const dest_align = try comptimeExpr(gz, scope, align_rl, params[0]); + const rhs = try expr(gz, scope, .none, params[1]); + const result = try gz.addPlNode(.align_cast, node, Zir.Inst.Bin{ + .lhs = dest_align, + .rhs = rhs, }); return rvalue(gz, scope, rl, result, node); }, - .type_info => { - const operand = try typeExpr(gz, scope, params[0]); - const result = try gz.addUnNode(.type_info, operand, node); + .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl), + .has_field => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_field), + + .clz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .clz), + .ctz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .ctz), + .pop_count => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .pop_count), + .byte_swap => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .byte_swap), + .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .bit_reverse), + + .div_exact => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_exact), + .div_floor => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_floor), + .div_trunc => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_trunc), + .mod => return divBuiltin(gz, scope, rl, node, params[0], params[1], .mod), + .rem => return divBuiltin(gz, scope, rl, node, params[0], params[1], .rem), + + .shl_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shl_exact), + .shr_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shr_exact), + + .bit_offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .bit_offset_of), + .byte_offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .byte_offset_of), + + .c_undef => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_undef), + .c_include => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_include), + + .cmpxchg_strong => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_strong), + .cmpxchg_weak => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_weak), + + .wasm_memory_size => { + const operand = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); + const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ + .node = gz.nodeIndexToRelative(node), + .operand = operand, + }); return rvalue(gz, scope, rl, result, node); }, - - .size_of => { - const operand = try typeExpr(gz, scope, params[0]); - const result = try gz.addUnNode(.size_of, operand, node); + .wasm_memory_grow => { + const index_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); + const delta_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[1]); + const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{ + .node = gz.nodeIndexToRelative(node), + .lhs = index_arg, + .rhs = delta_arg, + }); return rvalue(gz, scope, rl, result, node); }, - - .bit_size_of => { - const operand = try typeExpr(gz, scope, params[0]); - const result = try gz.addUnNode(.bit_size_of, operand, node); + .c_define => { + const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]); + const value = try comptimeExpr(gz, scope, .none, params[1]); + const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ + .node = gz.nodeIndexToRelative(node), + .lhs = name, + .rhs = value, + }); return rvalue(gz, scope, rl, result, node); }, - .This => return rvalue(gz, scope, rl, try gz.addNode(.this, node), node), - .fence => return rvalue(gz, scope, rl, try gz.addNode(.fence, node), node), - .return_address => return rvalue(gz, scope, rl, try gz.addNode(.ret_addr, node), node), - .src => return rvalue(gz, scope, rl, try gz.addNode(.builtin_src, node), node), + .splat => { + const len = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); + const scalar = try expr(gz, scope, .none, params[1]); + const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{ + .lhs = len, + .rhs = scalar, + }); + return rvalue(gz, scope, rl, result, node); + }, + .reduce => { + const op = try expr(gz, scope, .{ .ty = .reduce_op_type }, params[0]); + const scalar = try expr(gz, scope, .none, params[1]); + const result = try gz.addPlNode(.reduce, node, Zir.Inst.Bin{ + .lhs = op, + .rhs = scalar, + }); + return rvalue(gz, scope, rl, result, node); + }, .add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow), .sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow), @@ -4941,83 +5094,373 @@ fn builtinCall( return rvalue(gz, scope, rl, result, node); }, - .align_cast, - .align_of, - .atomic_load, - .atomic_rmw, - .atomic_store, - .bit_offset_of, - .bool_to_int, - .mul_add, - .byte_swap, - .bit_reverse, - .byte_offset_of, - .call, - .c_define, - .c_import, - .c_include, - .clz, - .cmpxchg_strong, - .cmpxchg_weak, - .ctz, - .c_undef, - .div_exact, - .div_floor, - .div_trunc, - .embed_file, - .error_name, - .error_return_trace, - .err_set_cast, - .field_parent_ptr, - .float_to_int, - .has_field, - .int_to_float, - .int_to_ptr, - .memcpy, - .memset, - .wasm_memory_size, - .wasm_memory_grow, - .mod, - .panic, - .pop_count, - .ptr_cast, - .rem, - .set_align_stack, - .set_cold, - .set_float_mode, - .set_runtime_safety, - .shl_exact, - .shr_exact, - .shuffle, - .splat, - .reduce, - .sqrt, - .sin, - .cos, - .exp, - .exp2, - .log, - .log2, - .log10, - .fabs, - .floor, - .ceil, - .trunc, - .round, - .tag_name, - .truncate, - .Type, - .type_name, - .union_init, - .async_call, - .frame, - .Frame, - .frame_address, - .frame_size, - => return astgen.failNode(node, "TODO: implement builtin function {s}", .{ - builtin_name, - }), + .atomic_load => { + const int_type = try typeExpr(gz, scope, params[0]); + const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ + .ptr_type_simple = .{ + .is_allowzero = false, + .is_mutable = false, + .is_volatile = false, + .size = .One, + .elem_type = int_type, + }, + } }); + const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]); + const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[2]); + const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.Bin{ + .lhs = ptr, + .rhs = ordering, + }); + return rvalue(gz, scope, rl, result, node); + }, + .atomic_rmw => { + const int_type = try typeExpr(gz, scope, params[0]); + const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ + .ptr_type_simple = .{ + .is_allowzero = false, + .is_mutable = true, + .is_volatile = false, + .size = .One, + .elem_type = int_type, + }, + } }); + const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]); + const operation = try expr(gz, scope, .{ .ty = .atomic_rmw_op_type }, params[2]); + const operand = try expr(gz, scope, .{ .ty = int_type }, params[3]); + const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[4]); + const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{ + .ptr = ptr, + .operation = operation, + .operand = operand, + .ordering = ordering, + }); + return rvalue(gz, scope, rl, result, node); + }, + .atomic_store => { + const int_type = try typeExpr(gz, scope, params[0]); + const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ + .ptr_type_simple = .{ + .is_allowzero = false, + .is_mutable = true, + .is_volatile = false, + .size = .One, + .elem_type = int_type, + }, + } }); + const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]); + const operand = try expr(gz, scope, .{ .ty = int_type }, params[2]); + const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[3]); + const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{ + .ptr = ptr, + .operand = operand, + .ordering = ordering, + }); + return rvalue(gz, scope, rl, result, node); + }, + .mul_add => { + const float_type = try typeExpr(gz, scope, params[0]); + const mulend1 = try expr(gz, scope, .{ .ty = float_type }, params[1]); + const mulend2 = try expr(gz, scope, .{ .ty = float_type }, params[2]); + const addend = try expr(gz, scope, .{ .ty = float_type }, params[3]); + const result = try gz.addPlNode(.mul_add, node, Zir.Inst.MulAdd{ + .mulend1 = mulend1, + .mulend2 = mulend2, + .addend = addend, + }); + return rvalue(gz, scope, rl, result, node); + }, + .call => { + const options = try comptimeExpr(gz, scope, .{ .ty = .call_options_type }, params[0]); + const callee = try expr(gz, scope, .none, params[1]); + const args = try expr(gz, scope, .none, params[2]); + const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ + .options = options, + .callee = callee, + .args = args, + }); + return rvalue(gz, scope, rl, result, node); + }, + .field_parent_ptr => { + const parent_type = try typeExpr(gz, scope, params[0]); + const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); + const field_ptr_type = try gz.addBin(.field_ptr_type, parent_type, field_name); + const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{ + .parent_type = parent_type, + .field_name = field_name, + .field_ptr = try expr(gz, scope, .{ .ty = field_ptr_type }, params[2]), + }); + return rvalue(gz, scope, rl, result, node); + }, + .memcpy => { + const result = try gz.addPlNode(.memcpy, node, Zir.Inst.Memcpy{ + .dest = try expr(gz, scope, .{ .ty = .manyptr_u8_type }, params[0]), + .source = try expr(gz, scope, .{ .ty = .manyptr_const_u8_type }, params[1]), + .byte_count = try expr(gz, scope, .{ .ty = .usize_type }, params[2]), + }); + return rvalue(gz, scope, rl, result, node); + }, + .memset => { + const result = try gz.addPlNode(.memset, node, Zir.Inst.Memset{ + .dest = try expr(gz, scope, .{ .ty = .manyptr_u8_type }, params[0]), + .byte = try expr(gz, scope, .{ .ty = .u8_type }, params[1]), + .byte_count = try expr(gz, scope, .{ .ty = .usize_type }, params[2]), + }); + return rvalue(gz, scope, rl, result, node); + }, + .shuffle => { + const result = try gz.addPlNode(.shuffle, node, Zir.Inst.Shuffle{ + .elem_type = try typeExpr(gz, scope, params[0]), + .a = try expr(gz, scope, .none, params[1]), + .b = try expr(gz, scope, .none, params[2]), + .mask = try comptimeExpr(gz, scope, .none, params[3]), + }); + return rvalue(gz, scope, rl, result, node); + }, + .async_call => { + const result = try gz.addPlNode(.builtin_async_call, node, Zir.Inst.AsyncCall{ + .frame_buffer = try expr(gz, scope, .none, params[0]), + .result_ptr = try expr(gz, scope, .none, params[1]), + .fn_ptr = try expr(gz, scope, .none, params[2]), + .args = try expr(gz, scope, .none, params[3]), + }); + return rvalue(gz, scope, rl, result, node); + }, } + // zig fmt: on +} + +fn simpleNoOpVoid( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + tag: Zir.Inst.Tag, +) InnerError!Zir.Inst.Ref { + _ = try gz.addNode(tag, node); + return rvalue(gz, scope, rl, .void_value, node); +} + +fn hasDeclOrField( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + lhs_node: ast.Node.Index, + rhs_node: ast.Node.Index, + tag: Zir.Inst.Tag, +) InnerError!Zir.Inst.Ref { + const container_type = try typeExpr(gz, scope, lhs_node); + const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node); + const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ + .lhs = container_type, + .rhs = name, + }); + return rvalue(gz, scope, rl, result, node); +} + +fn typeCast( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + lhs_node: ast.Node.Index, + rhs_node: ast.Node.Index, + tag: Zir.Inst.Tag, +) InnerError!Zir.Inst.Ref { + const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ + .lhs = try typeExpr(gz, scope, lhs_node), + .rhs = try expr(gz, scope, .none, rhs_node), + }); + return rvalue(gz, scope, rl, result, node); +} + +fn simpleUnOpType( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + operand_node: ast.Node.Index, + tag: Zir.Inst.Tag, +) InnerError!Zir.Inst.Ref { + const operand = try typeExpr(gz, scope, operand_node); + const result = try gz.addUnNode(tag, operand, node); + return rvalue(gz, scope, rl, result, node); +} + +fn simpleUnOp( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + operand_rl: ResultLoc, + operand_node: ast.Node.Index, + tag: Zir.Inst.Tag, +) InnerError!Zir.Inst.Ref { + const operand = try expr(gz, scope, operand_rl, operand_node); + const result = try gz.addUnNode(tag, operand, node); + return rvalue(gz, scope, rl, result, node); +} + +fn cmpxchg( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + params: []const ast.Node.Index, + tag: Zir.Inst.Tag, +) InnerError!Zir.Inst.Ref { + const int_type = try typeExpr(gz, scope, params[0]); + const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ + .ptr_type_simple = .{ + .is_allowzero = false, + .is_mutable = true, + .is_volatile = false, + .size = .One, + .elem_type = int_type, + }, + } }); + const result = try gz.addPlNode(tag, node, Zir.Inst.Cmpxchg{ + // zig fmt: off + .ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]), + .expected_value = try expr(gz, scope, .{ .ty = int_type }, params[2]), + .new_value = try expr(gz, scope, .{ .ty = int_type }, params[3]), + .success_order = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[4]), + .fail_order = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[5]), + // zig fmt: on + }); + return rvalue(gz, scope, rl, result, node); +} + +fn bitBuiltin( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + int_type_node: ast.Node.Index, + operand_node: ast.Node.Index, + tag: Zir.Inst.Tag, +) InnerError!Zir.Inst.Ref { + const int_type = try typeExpr(gz, scope, int_type_node); + const operand = try expr(gz, scope, .{ .ty = int_type }, operand_node); + const result = try gz.addUnNode(tag, operand, node); + return rvalue(gz, scope, rl, result, node); +} + +fn divBuiltin( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + lhs_node: ast.Node.Index, + rhs_node: ast.Node.Index, + tag: Zir.Inst.Tag, +) InnerError!Zir.Inst.Ref { + const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ + .lhs = try expr(gz, scope, .none, lhs_node), + .rhs = try expr(gz, scope, .none, rhs_node), + }); + return rvalue(gz, scope, rl, result, node); +} + +fn simpleCBuiltin( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + operand_node: ast.Node.Index, + tag: Zir.Inst.Extended, +) InnerError!Zir.Inst.Ref { + const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node); + _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ + .node = gz.nodeIndexToRelative(node), + .operand = operand, + }); + return rvalue(gz, scope, rl, .void_value, node); +} + +fn offsetOf( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + lhs_node: ast.Node.Index, + rhs_node: ast.Node.Index, + tag: Zir.Inst.Tag, +) InnerError!Zir.Inst.Ref { + const type_inst = try typeExpr(gz, scope, lhs_node); + const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node); + const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ + .lhs = type_inst, + .rhs = field_name, + }); + return rvalue(gz, scope, rl, result, node); +} + +fn shiftOp( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + lhs_node: ast.Node.Index, + rhs_node: ast.Node.Index, + tag: Zir.Inst.Tag, +) InnerError!Zir.Inst.Ref { + const lhs = try expr(gz, scope, .none, lhs_node); + const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node); + const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, rhs_node); + const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ + .lhs = lhs, + .rhs = rhs, + }); + return rvalue(gz, scope, rl, result, node); +} + +fn cImport( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + body_node: ast.Node.Index, +) InnerError!Zir.Inst.Ref { + const astgen = gz.astgen; + const gpa = astgen.gpa; + + var block_scope: GenZir = .{ + .parent = scope, + .decl_node_index = gz.decl_node_index, + .astgen = astgen, + .force_comptime = true, + .instructions = .{}, + }; + defer block_scope.instructions.deinit(gpa); + + const block_inst = try gz.addBlock(.c_import, node); + const block_result = try expr(&block_scope, &block_scope.base, .none, body_node); + if (!gz.refIsNoReturn(block_result)) { + _ = try block_scope.addBreak(.break_inline, block_inst, .void_value); + } + try block_scope.setBlockBody(block_inst); + try gz.instructions.append(gpa, block_inst); + + return rvalue(gz, scope, rl, .void_value, node); +} + +fn unionInit( + gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + params: []const ast.Node.Index, +) InnerError!Zir.Inst.Ref { + const union_type = try typeExpr(gz, scope, params[0]); + const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); + const union_init_ptr = try gz.addPlNode(.union_init_ptr, node, Zir.Inst.UnionInitPtr{ + .union_type = union_type, + .field_name = field_name, + }); + // TODO: set up a store_to_block_ptr elision thing here + const result = try expr(gz, scope, .{ .ptr = union_init_ptr }, params[2]); + return rvalue(gz, scope, rl, result, node); } fn overflowArithmetic( diff --git a/src/Module.zig b/src/Module.zig index 7c18f8f65a..bc6d0d4a6c 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1198,6 +1198,30 @@ pub const Scope = struct { gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); } + /// Same as `setBlockBody` except we don't copy instructions which are + /// `store_to_block_ptr` instructions with lhs set to .none. + pub fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void { + const gpa = gz.astgen.gpa; + try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + + @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); + const zir_datas = gz.astgen.instructions.items(.data); + const zir_tags = gz.astgen.instructions.items(.tag); + const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{ + .body_len = @intCast(u32, gz.instructions.items.len), + }); + zir_datas[inst].pl_node.payload_index = block_pl_index; + for (gz.instructions.items) |sub_inst| { + if (zir_tags[sub_inst] == .store_to_block_ptr and + zir_datas[sub_inst].bin.lhs == .none) + { + // Decrement `body_len`. + gz.astgen.extra.items[block_pl_index] -= 1; + continue; + } + gz.astgen.extra.appendAssumeCapacity(sub_inst); + } + } + pub fn identAsString(gz: *GenZir, ident_token: ast.TokenIndex) !u32 { const astgen = gz.astgen; const gpa = astgen.gpa; @@ -1445,6 +1469,30 @@ pub const Scope = struct { return gz.indexToRef(new_index); } + pub fn addExtendedPayload( + gz: *GenZir, + opcode: Zir.Inst.Extended, + extra: anytype, + ) !Zir.Inst.Ref { + const gpa = gz.astgen.gpa; + + try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); + try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); + + const payload_index = try gz.astgen.addExtra(extra); + const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); + gz.astgen.instructions.appendAssumeCapacity(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = opcode, + .small = undefined, + .operand = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } + pub fn addArrayTypeSentinel( gz: *GenZir, len: Zir.Inst.Ref, diff --git a/src/Sema.zig b/src/Sema.zig index 6fa6174804..38400b72e8 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -131,159 +131,227 @@ pub fn analyzeBody( while (true) : (i += 1) { const inst = body[i]; map[inst] = switch (tags[inst]) { - .elided => continue, - - .alloc => try sema.zirAlloc(block, inst), - .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), - .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), - .alloc_mut => try sema.zirAllocMut(block, inst), - .array_cat => try sema.zirArrayCat(block, inst), - .array_mul => try sema.zirArrayMul(block, inst), - .array_type => try sema.zirArrayType(block, inst), - .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst), - .as => try sema.zirAs(block, inst), - .as_node => try sema.zirAsNode(block, inst), - .@"asm" => try sema.zirAsm(block, inst, false), - .asm_volatile => try sema.zirAsm(block, inst, true), - .bit_and => try sema.zirBitwise(block, inst, .bit_and), - .bit_not => try sema.zirBitNot(block, inst), - .bit_or => try sema.zirBitwise(block, inst, .bit_or), - .bitcast => try sema.zirBitcast(block, inst), - .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst), - .block => try sema.zirBlock(block, inst), - .bool_not => try sema.zirBoolNot(block, inst), - .bool_and => try sema.zirBoolOp(block, inst, false), - .bool_or => try sema.zirBoolOp(block, inst, true), - .bool_br_and => try sema.zirBoolBr(block, inst, false), - .bool_br_or => try sema.zirBoolBr(block, inst, true), - .call => try sema.zirCall(block, inst, .auto, false), - .call_chkused => try sema.zirCall(block, inst, .auto, true), - .call_compile_time => try sema.zirCall(block, inst, .compile_time, false), - .call_none => try sema.zirCallNone(block, inst, false), - .call_none_chkused => try sema.zirCallNone(block, inst, true), - .cmp_eq => try sema.zirCmp(block, inst, .eq), - .cmp_gt => try sema.zirCmp(block, inst, .gt), - .cmp_gte => try sema.zirCmp(block, inst, .gte), - .cmp_lt => try sema.zirCmp(block, inst, .lt), - .cmp_lte => try sema.zirCmp(block, inst, .lte), - .cmp_neq => try sema.zirCmp(block, inst, .neq), - .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), - .decl_ref => try sema.zirDeclRef(block, inst), - .decl_val => try sema.zirDeclVal(block, inst), - .load => try sema.zirLoad(block, inst), - .elem_ptr => try sema.zirElemPtr(block, inst), - .elem_ptr_node => try sema.zirElemPtrNode(block, inst), - .elem_val => try sema.zirElemVal(block, inst), - .elem_val_node => try sema.zirElemValNode(block, inst), - .enum_literal => try sema.zirEnumLiteral(block, inst), - .enum_literal_small => try sema.zirEnumLiteralSmall(block, inst), - .enum_to_int => try sema.zirEnumToInt(block, inst), - .int_to_enum => try sema.zirIntToEnum(block, inst), - .err_union_code => try sema.zirErrUnionCode(block, inst), - .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst), - .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true), - .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true), - .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false), + // zig fmt: off + .alloc => try sema.zirAlloc(block, inst), + .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), + .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), + .alloc_mut => try sema.zirAllocMut(block, inst), + .array_cat => try sema.zirArrayCat(block, inst), + .array_mul => try sema.zirArrayMul(block, inst), + .array_type => try sema.zirArrayType(block, inst), + .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst), + .as => try sema.zirAs(block, inst), + .as_node => try sema.zirAsNode(block, inst), + .@"asm" => try sema.zirAsm(block, inst, false), + .asm_volatile => try sema.zirAsm(block, inst, true), + .bit_and => try sema.zirBitwise(block, inst, .bit_and), + .bit_not => try sema.zirBitNot(block, inst), + .bit_or => try sema.zirBitwise(block, inst, .bit_or), + .bitcast => try sema.zirBitcast(block, inst), + .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst), + .block => try sema.zirBlock(block, inst), + .bool_not => try sema.zirBoolNot(block, inst), + .bool_and => try sema.zirBoolOp(block, inst, false), + .bool_or => try sema.zirBoolOp(block, inst, true), + .bool_br_and => try sema.zirBoolBr(block, inst, false), + .bool_br_or => try sema.zirBoolBr(block, inst, true), + .c_import => try sema.zirCImport(block, inst), + .call => try sema.zirCall(block, inst, .auto, false), + .call_chkused => try sema.zirCall(block, inst, .auto, true), + .call_compile_time => try sema.zirCall(block, inst, .compile_time, false), + .call_none => try sema.zirCallNone(block, inst, false), + .call_none_chkused => try sema.zirCallNone(block, inst, true), + .cmp_eq => try sema.zirCmp(block, inst, .eq), + .cmp_gt => try sema.zirCmp(block, inst, .gt), + .cmp_gte => try sema.zirCmp(block, inst, .gte), + .cmp_lt => try sema.zirCmp(block, inst, .lt), + .cmp_lte => try sema.zirCmp(block, inst, .lte), + .cmp_neq => try sema.zirCmp(block, inst, .neq), + .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), + .decl_ref => try sema.zirDeclRef(block, inst), + .decl_val => try sema.zirDeclVal(block, inst), + .load => try sema.zirLoad(block, inst), + .elem_ptr => try sema.zirElemPtr(block, inst), + .elem_ptr_node => try sema.zirElemPtrNode(block, inst), + .elem_val => try sema.zirElemVal(block, inst), + .elem_val_node => try sema.zirElemValNode(block, inst), + .enum_literal => try sema.zirEnumLiteral(block, inst), + .enum_literal_small => try sema.zirEnumLiteralSmall(block, inst), + .enum_to_int => try sema.zirEnumToInt(block, inst), + .int_to_enum => try sema.zirIntToEnum(block, inst), + .err_union_code => try sema.zirErrUnionCode(block, inst), + .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst), + .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true), + .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true), + .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false), .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false), - .error_union_type => try sema.zirErrorUnionType(block, inst), - .error_value => try sema.zirErrorValue(block, inst), - .error_to_int => try sema.zirErrorToInt(block, inst), - .int_to_error => try sema.zirIntToError(block, inst), - .field_ptr => try sema.zirFieldPtr(block, inst), - .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), - .field_val => try sema.zirFieldVal(block, inst), - .field_val_named => try sema.zirFieldValNamed(block, inst), - .floatcast => try sema.zirFloatcast(block, inst), - .func => try sema.zirFunc(block, inst, false), - .func_extra => try sema.zirFuncExtra(block, inst, false), - .func_extra_var_args => try sema.zirFuncExtra(block, inst, true), - .func_var_args => try sema.zirFunc(block, inst, true), - .has_decl => try sema.zirHasDecl(block, inst), - .import => try sema.zirImport(block, inst), - .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst), - .int => try sema.zirInt(block, inst), - .float => try sema.zirFloat(block, inst), - .float128 => try sema.zirFloat128(block, inst), - .int_type => try sema.zirIntType(block, inst), - .intcast => try sema.zirIntcast(block, inst), - .is_err => try sema.zirIsErr(block, inst), - .is_err_ptr => try sema.zirIsErrPtr(block, inst), - .is_non_null => try sema.zirIsNull(block, inst, true), - .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true), - .is_null => try sema.zirIsNull(block, inst, false), - .is_null_ptr => try sema.zirIsNullPtr(block, inst, false), - .loop => try sema.zirLoop(block, inst), - .merge_error_sets => try sema.zirMergeErrorSets(block, inst), - .negate => try sema.zirNegate(block, inst, .sub), - .negate_wrap => try sema.zirNegate(block, inst, .subwrap), - .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true), - .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true), - .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), - .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), - .optional_type => try sema.zirOptionalType(block, inst), - .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, inst), - .param_type => try sema.zirParamType(block, inst), - .ptr_type => try sema.zirPtrType(block, inst), - .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst), - .ptrtoint => try sema.zirPtrtoint(block, inst), - .ref => try sema.zirRef(block, inst), - .ret_ptr => try sema.zirRetPtr(block, inst), - .ret_type => try sema.zirRetType(block, inst), - .shl => try sema.zirShl(block, inst), - .shr => try sema.zirShr(block, inst), - .slice_end => try sema.zirSliceEnd(block, inst), - .slice_sentinel => try sema.zirSliceSentinel(block, inst), - .slice_start => try sema.zirSliceStart(block, inst), - .str => try sema.zirStr(block, inst), - .switch_block => try sema.zirSwitchBlock(block, inst, false, .none), - .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none), - .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"), - .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"), - .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under), - .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under), - .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none), - .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none), - .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"), - .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"), - .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under), + .error_union_type => try sema.zirErrorUnionType(block, inst), + .error_value => try sema.zirErrorValue(block, inst), + .error_to_int => try sema.zirErrorToInt(block, inst), + .int_to_error => try sema.zirIntToError(block, inst), + .field_ptr => try sema.zirFieldPtr(block, inst), + .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), + .field_val => try sema.zirFieldVal(block, inst), + .field_val_named => try sema.zirFieldValNamed(block, inst), + .floatcast => try sema.zirFloatcast(block, inst), + .func => try sema.zirFunc(block, inst, false), + .func_extra => try sema.zirFuncExtra(block, inst, false), + .func_extra_var_args => try sema.zirFuncExtra(block, inst, true), + .func_var_args => try sema.zirFunc(block, inst, true), + .import => try sema.zirImport(block, inst), + .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst), + .int => try sema.zirInt(block, inst), + .float => try sema.zirFloat(block, inst), + .float128 => try sema.zirFloat128(block, inst), + .int_type => try sema.zirIntType(block, inst), + .intcast => try sema.zirIntcast(block, inst), + .is_err => try sema.zirIsErr(block, inst), + .is_err_ptr => try sema.zirIsErrPtr(block, inst), + .is_non_null => try sema.zirIsNull(block, inst, true), + .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true), + .is_null => try sema.zirIsNull(block, inst, false), + .is_null_ptr => try sema.zirIsNullPtr(block, inst, false), + .loop => try sema.zirLoop(block, inst), + .merge_error_sets => try sema.zirMergeErrorSets(block, inst), + .negate => try sema.zirNegate(block, inst, .sub), + .negate_wrap => try sema.zirNegate(block, inst, .subwrap), + .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true), + .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true), + .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), + .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), + .optional_type => try sema.zirOptionalType(block, inst), + .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, inst), + .param_type => try sema.zirParamType(block, inst), + .ptr_type => try sema.zirPtrType(block, inst), + .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst), + .ptrtoint => try sema.zirPtrtoint(block, inst), + .ref => try sema.zirRef(block, inst), + .ret_ptr => try sema.zirRetPtr(block, inst), + .ret_type => try sema.zirRetType(block, inst), + .shl => try sema.zirShl(block, inst), + .shr => try sema.zirShr(block, inst), + .slice_end => try sema.zirSliceEnd(block, inst), + .slice_sentinel => try sema.zirSliceSentinel(block, inst), + .slice_start => try sema.zirSliceStart(block, inst), + .str => try sema.zirStr(block, inst), + .switch_block => try sema.zirSwitchBlock(block, inst, false, .none), + .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none), + .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"), + .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"), + .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under), + .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under), + .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none), + .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none), + .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"), + .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"), + .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under), .switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under), - .switch_capture => try sema.zirSwitchCapture(block, inst, false, false), - .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), - .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), - .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), - .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false), - .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true), - .type_info => try sema.zirTypeInfo(block, inst), - .size_of => try sema.zirSizeOf(block, inst), - .bit_size_of => try sema.zirBitSizeOf(block, inst), - .this => try sema.zirThis(block, inst), - .fence => try sema.zirFence(block, inst), - .ret_addr => try sema.zirRetAddr(block, inst), - .builtin_src => try sema.zirBuiltinSrc(block, inst), - .typeof => try sema.zirTypeof(block, inst), - .typeof_elem => try sema.zirTypeofElem(block, inst), - .typeof_peer => try sema.zirTypeofPeer(block, inst), - .log2_int_type => try sema.zirLog2IntType(block, inst), - .xor => try sema.zirBitwise(block, inst, .xor), - .struct_init_empty => try sema.zirStructInitEmpty(block, inst), - .struct_init => try sema.zirStructInit(block, inst), - .field_type => try sema.zirFieldType(block, inst), - - .struct_decl => try sema.zirStructDecl(block, inst, .Auto), - .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed), - .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern), - .enum_decl => try sema.zirEnumDecl(block, inst, false), + .switch_capture => try sema.zirSwitchCapture(block, inst, false, false), + .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), + .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), + .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), + .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false), + .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true), + .type_info => try sema.zirTypeInfo(block, inst), + .size_of => try sema.zirSizeOf(block, inst), + .bit_size_of => try sema.zirBitSizeOf(block, inst), + .this => try sema.zirThis(block, inst), + .ret_addr => try sema.zirRetAddr(block, inst), + .builtin_src => try sema.zirBuiltinSrc(block, inst), + .typeof => try sema.zirTypeof(block, inst), + .typeof_elem => try sema.zirTypeofElem(block, inst), + .typeof_peer => try sema.zirTypeofPeer(block, inst), + .log2_int_type => try sema.zirLog2IntType(block, inst), + .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst), + .xor => try sema.zirBitwise(block, inst, .xor), + .struct_init_empty => try sema.zirStructInitEmpty(block, inst), + .struct_init => try sema.zirStructInit(block, inst), + .union_init_ptr => try sema.zirUnionInitPtr(block, inst), + .field_type => try sema.zirFieldType(block, inst), + .error_return_trace => try sema.zirErrorReturnTrace(block, inst), + .frame => try sema.zirFrame(block, inst), + .frame_address => try sema.zirFrameAddress(block, inst), + .ptr_to_int => try sema.zirPtrToInt(block, inst), + .align_of => try sema.zirAlignOf(block, inst), + .bool_to_int => try sema.zirBoolToInt(block, inst), + .embed_file => try sema.zirEmbedFile(block, inst), + .error_name => try sema.zirErrorName(block, inst), + .tag_name => try sema.zirTagName(block, inst), + .reify => try sema.zirReify(block, inst), + .type_name => try sema.zirTypeName(block, inst), + .frame_type => try sema.zirFrameType(block, inst), + .frame_size => try sema.zirFrameSize(block, inst), + .float_to_int => try sema.zirFloatToInt(block, inst), + .int_to_float => try sema.zirIntToFloat(block, inst), + .int_to_ptr => try sema.zirIntToPtr(block, inst), + .float_cast => try sema.zirFloatCast(block, inst), + .int_cast => try sema.zirIntCast(block, inst), + .err_set_cast => try sema.zirErrSetCast(block, inst), + .ptr_cast => try sema.zirPtrCast(block, inst), + .truncate => try sema.zirTruncate(block, inst), + .align_cast => try sema.zirAlignCast(block, inst), + .has_decl => try sema.zirHasDecl(block, inst), + .has_field => try sema.zirHasField(block, inst), + .clz => try sema.zirClz(block, inst), + .ctz => try sema.zirCtz(block, inst), + .pop_count => try sema.zirPopCount(block, inst), + .byte_swap => try sema.zirByteSwap(block, inst), + .bit_reverse => try sema.zirBitReverse(block, inst), + .div_exact => try sema.zirDivExact(block, inst), + .div_floor => try sema.zirDivFloor(block, inst), + .div_trunc => try sema.zirDivTrunc(block, inst), + .mod => try sema.zirMod(block, inst), + .rem => try sema.zirRem(block, inst), + .shl_exact => try sema.zirShlExact(block, inst), + .shr_exact => try sema.zirShrExact(block, inst), + .bit_offset_of => try sema.zirBitOffsetOf(block, inst), + .byte_offset_of => try sema.zirByteOffsetOf(block, inst), + .cmpxchg_strong => try sema.zirCmpxchg(block, inst), + .cmpxchg_weak => try sema.zirCmpxchg(block, inst), + .splat => try sema.zirSplat(block, inst), + .reduce => try sema.zirReduce(block, inst), + .shuffle => try sema.zirShuffle(block, inst), + .atomic_load => try sema.zirAtomicLoad(block, inst), + .atomic_rmw => try sema.zirAtomicRmw(block, inst), + .atomic_store => try sema.zirAtomicStore(block, inst), + .mul_add => try sema.zirMulAdd(block, inst), + .builtin_call => try sema.zirBuiltinCall(block, inst), + .field_ptr_type => try sema.zirFieldPtrType(block, inst), + .field_parent_ptr => try sema.zirFieldParentPtr(block, inst), + .memcpy => try sema.zirMemcpy(block, inst), + .memset => try sema.zirMemset(block, inst), + .builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst), + .extended => try sema.zirExtended(block, inst), + + .sqrt => try sema.zirUnaryMath(block, inst), + .sin => try sema.zirUnaryMath(block, inst), + .cos => try sema.zirUnaryMath(block, inst), + .exp => try sema.zirUnaryMath(block, inst), + .exp2 => try sema.zirUnaryMath(block, inst), + .log => try sema.zirUnaryMath(block, inst), + .log2 => try sema.zirUnaryMath(block, inst), + .log10 => try sema.zirUnaryMath(block, inst), + .fabs => try sema.zirUnaryMath(block, inst), + .floor => try sema.zirUnaryMath(block, inst), + .ceil => try sema.zirUnaryMath(block, inst), + .trunc => try sema.zirUnaryMath(block, inst), + .round => try sema.zirUnaryMath(block, inst), + + .struct_decl => try sema.zirStructDecl(block, inst, .Auto), + .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed), + .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern), + .enum_decl => try sema.zirEnumDecl(block, inst, false), .enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true), - .union_decl => try sema.zirUnionDecl(block, inst), - .opaque_decl => try sema.zirOpaqueDecl(block, inst), + .union_decl => try sema.zirUnionDecl(block, inst), + .opaque_decl => try sema.zirOpaqueDecl(block, inst), - .add => try sema.zirArithmetic(block, inst), + .add => try sema.zirArithmetic(block, inst), .addwrap => try sema.zirArithmetic(block, inst), - .div => try sema.zirArithmetic(block, inst), + .div => try sema.zirArithmetic(block, inst), .mod_rem => try sema.zirArithmetic(block, inst), - .mul => try sema.zirArithmetic(block, inst), + .mul => try sema.zirArithmetic(block, inst), .mulwrap => try sema.zirArithmetic(block, inst), - .sub => try sema.zirArithmetic(block, inst), + .sub => try sema.zirArithmetic(block, inst), .subwrap => try sema.zirArithmetic(block, inst), .add_with_overflow => try sema.zirOverflowArithmetic(block, inst), @@ -294,15 +362,17 @@ pub fn analyzeBody( // Instructions that we know to *always* be noreturn based solely on their tag. // These functions match the return type of analyzeBody so that we can // tail call them here. - .condbr => return sema.zirCondbr(block, inst), - .@"break" => return sema.zirBreak(block, inst), - .break_inline => return inst, - .compile_error => return sema.zirCompileError(block, inst), - .ret_coerce => return sema.zirRetTok(block, inst, true), - .ret_node => return sema.zirRetNode(block, inst), - .ret_tok => return sema.zirRetTok(block, inst, false), + .break_inline => return inst, + .condbr => return sema.zirCondbr(block, inst), + .@"break" => return sema.zirBreak(block, inst), + .compile_error => return sema.zirCompileError(block, inst), + .ret_coerce => return sema.zirRetTok(block, inst, true), + .ret_node => return sema.zirRetNode(block, inst), + .ret_tok => return sema.zirRetTok(block, inst, false), .@"unreachable" => return sema.zirUnreachable(block, inst), - .repeat => return sema.zirRepeat(block, inst), + .repeat => return sema.zirRepeat(block, inst), + .panic => return sema.zirPanic(block, inst), + // zig fmt: on // Instructions that we know can *never* be noreturn based solely on // their tag. We avoid needlessly checking if they are noreturn and @@ -313,6 +383,10 @@ pub fn analyzeBody( try sema.zirBreakpoint(block, inst); continue; }, + .fence => { + try sema.zirFence(block, inst); + continue; + }, .dbg_stmt_node => { try sema.zirDbgStmtNode(block, inst); continue; @@ -365,6 +439,22 @@ pub fn analyzeBody( try sema.zirExport(block, inst); continue; }, + .set_align_stack => { + try sema.zirSetAlignStack(block, inst); + continue; + }, + .set_cold => { + try sema.zirSetAlignStack(block, inst); + continue; + }, + .set_float_mode => { + try sema.zirSetFloatMode(block, inst); + continue; + }, + .set_runtime_safety => { + try sema.zirSetRuntimeSafety(block, inst); + continue; + }, // Special case instructions to handle comptime control flow. .repeat_inline => { @@ -1382,6 +1472,13 @@ fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError! return always_noreturn; } +fn zirPanic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src: LazySrcLoc = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirPanic", .{}); + //return always_noreturn; +} + fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const tracy = trace(@src()); defer tracy.end(); @@ -1443,6 +1540,16 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerE return sema.analyzeBlockBody(parent_block, src, &child_block, merges); } +fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const tracy = trace(@src()); + defer tracy.end(); + + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + + return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirCImport", .{}); +} + fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const tracy = trace(@src()); defer tracy.end(); @@ -1597,6 +1704,30 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError! try sema.mod.analyzeExport(&block.base, src, export_name, actual_fn.owner_decl); } +fn zirSetAlignStack(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src: LazySrcLoc = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetAlignStack", .{}); +} + +fn zirSetCold(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src: LazySrcLoc = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetCold", .{}); +} + +fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src: LazySrcLoc = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetFloatMode", .{}); +} + +fn zirSetRuntimeSafety(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src: LazySrcLoc = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetRuntimeSafety", .{}); +} + fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { const tracy = trace(@src()); defer tracy.end(); @@ -1607,6 +1738,12 @@ fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint); } +fn zirFence(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { + const src_node = sema.code.instructions.items(.data)[inst].node; + const src: LazySrcLoc = .{ .node_offset = src_node }; + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirFence", .{}); +} + fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index { const tracy = trace(@src()); defer tracy.end(); @@ -3874,10 +4011,15 @@ fn validateSwitchNoRange( return sema.mod.failWithOwnedErrorMsg(&block.base, msg); } -fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { - const tracy = trace(@src()); - defer tracy.end(); +fn zirHasField(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; + const src = inst_data.src(); + + return sema.mod.fail(&block.base, src, "TODO implement zirHasField", .{}); +} +fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const src = inst_data.src(); @@ -4382,16 +4524,13 @@ fn zirThis(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*I const src: LazySrcLoc = .{ .node_offset = src_node }; return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirThis", .{}); } -fn zirFence(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { - const src_node = sema.code.instructions.items(.data)[inst].node; - const src: LazySrcLoc = .{ .node_offset = src_node }; - return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirFence", .{}); -} + fn zirRetAddr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const src_node = sema.code.instructions.items(.data)[inst].node; const src: LazySrcLoc = .{ .node_offset = src_node }; return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirRetAddr", .{}); } + fn zirBuiltinSrc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const src_node = sema.code.instructions.items(.data)[inst].node; const src: LazySrcLoc = .{ .node_offset = src_node }; @@ -4419,6 +4558,12 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr return sema.mod.constType(sema.arena, src, elem_ty); } +fn zirTypeofLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeofLog2IntType", .{}); +} + fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const inst_data = sema.code.instructions.items(.data)[inst].un_node; const src = inst_data.src(); @@ -4827,6 +4972,12 @@ fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In }); } +fn zirUnionInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirUnionInitPtr", .{}); +} + fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); @@ -4839,6 +4990,380 @@ fn zirFieldType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErr return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldType", .{}); } +fn zirErrorReturnTrace(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirErrorReturnTrace", .{}); +} + +fn zirFrame(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrame", .{}); +} + +fn zirFrameAddress(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrameAddress", .{}); +} + +fn zirPtrToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirPtrToInt", .{}); +} + +fn zirAlignOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirAlignOf", .{}); +} + +fn zirBoolToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirBoolToInt", .{}); +} + +fn zirEmbedFile(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirEmbedFile", .{}); +} + +fn zirErrorName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirErrorName", .{}); +} + +fn zirUnaryMath(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirUnaryMath", .{}); +} + +fn zirTagName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirTagName", .{}); +} + +fn zirReify(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify", .{}); +} + +fn zirTypeName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirTypeName", .{}); +} + +fn zirFrameType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrameType", .{}); +} + +fn zirFrameSize(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrameSize", .{}); +} + +fn zirFloatToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirFloatToInt", .{}); +} + +fn zirIntToFloat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntToFloat", .{}); +} + +fn zirIntToPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntToPtr", .{}); +} + +fn zirFloatCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirFloatCast", .{}); +} + +fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntCast", .{}); +} + +fn zirErrSetCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirErrSetCast", .{}); +} + +fn zirPtrCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirPtrCast", .{}); +} + +fn zirTruncate(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirTruncate", .{}); +} + +fn zirAlignCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirAlignCast", .{}); +} + +fn zirClz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirClz", .{}); +} + +fn zirCtz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirCtz", .{}); +} + +fn zirPopCount(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirPopCount", .{}); +} + +fn zirByteSwap(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirByteSwap", .{}); +} + +fn zirBitReverse(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirBitReverse", .{}); +} + +fn zirDivExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirDivExact", .{}); +} + +fn zirDivFloor(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirDivFloor", .{}); +} + +fn zirDivTrunc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirDivTrunc", .{}); +} + +fn zirMod(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirMod", .{}); +} + +fn zirRem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirRem", .{}); +} + +fn zirShlExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirShlExact", .{}); +} + +fn zirShrExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirShrExact", .{}); +} + +fn zirBitOffsetOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirBitOffsetOf", .{}); +} + +fn zirByteOffsetOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirByteOffsetOf", .{}); +} + +fn zirCmpxchg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirCmpxchg", .{}); +} + +fn zirSplat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirSplat", .{}); +} + +fn zirReduce(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirReduce", .{}); +} + +fn zirShuffle(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirShuffle", .{}); +} + +fn zirAtomicLoad(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicLoad", .{}); +} + +fn zirAtomicRmw(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicRmw", .{}); +} + +fn zirAtomicStore(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicStore", .{}); +} + +fn zirMulAdd(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirMulAdd", .{}); +} + +fn zirBuiltinCall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirBuiltinCall", .{}); +} + +fn zirFieldPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldPtrType", .{}); +} + +fn zirFieldParentPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldParentPtr", .{}); +} + +fn zirMemcpy(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirMemcpy", .{}); +} + +fn zirMemset(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirMemset", .{}); +} + +fn zirBuiltinAsyncCall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + return sema.mod.fail(&block.base, src, "TODO: Sema.zirBuiltinAsyncCall", .{}); +} + +fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const extended = sema.code.instructions.items(.data)[inst].extended; + switch (extended.opcode) { + // zig fmt: off + .c_undef => return sema.zirCUndef( block, inst, extended), + .c_include => return sema.zirCInclude( block, inst, extended), + .c_define => return sema.zirCDefine( block, inst, extended), + .wasm_memory_size => return sema.zirWasmMemorySize( block, inst, extended), + .wasm_memory_grow => return sema.zirWasmMemoryGrow( block, inst, extended), + // zig fmt: on + } +} + +fn zirCUndef( + sema: *Sema, + block: *Scope.Block, + inst: Zir.Inst.Index, + extended: Zir.Inst.Extended.InstData, +) InnerError!*Inst { + const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; + const src: LazySrcLoc = .{ .node_offset = extra.node }; + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCUndef", .{}); +} + +fn zirCInclude( + sema: *Sema, + block: *Scope.Block, + inst: Zir.Inst.Index, + extended: Zir.Inst.Extended.InstData, +) InnerError!*Inst { + const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; + const src: LazySrcLoc = .{ .node_offset = extra.node }; + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCInclude", .{}); +} + +fn zirCDefine( + sema: *Sema, + block: *Scope.Block, + inst: Zir.Inst.Index, + extended: Zir.Inst.Extended.InstData, +) InnerError!*Inst { + const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; + const src: LazySrcLoc = .{ .node_offset = extra.node }; + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCDefine", .{}); +} + +fn zirWasmMemorySize( + sema: *Sema, + block: *Scope.Block, + inst: Zir.Inst.Index, + extended: Zir.Inst.Extended.InstData, +) InnerError!*Inst { + const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; + const src: LazySrcLoc = .{ .node_offset = extra.node }; + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirWasmMemorySize", .{}); +} + +fn zirWasmMemoryGrow( + sema: *Sema, + block: *Scope.Block, + inst: Zir.Inst.Index, + extended: Zir.Inst.Extended.InstData, +) InnerError!*Inst { + const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; + const src: LazySrcLoc = .{ .node_offset = extra.node }; + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirWasmMemoryGrow", .{}); +} + fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void { if (sema.func == null) { return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{}); diff --git a/src/Zir.zig b/src/Zir.zig index 879f8d2459..4348b36fa4 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -274,9 +274,6 @@ pub const Inst = struct { /// Uses the `bin` union field. /// LHS is destination element type, RHS is result pointer. coerce_result_ptr, - /// Emit an error message and fail compilation. - /// Uses the `un_node` field. - compile_error, /// Log compile time variables and emit an error message. /// Uses the `pl_node` union field. The AST node is the compile log builtin call. /// The payload is `MultiOp`. @@ -339,9 +336,6 @@ pub const Inst = struct { /// Same as `elem_val` except also stores a source location node. /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`. elem_val_node, - /// This instruction has been deleted late in the astgen phase. It must - /// be ignored, and the corresponding `Data` is undefined. - elided, /// Emits a compile error if the operand is not `void`. /// Uses the `un_node` field. ensure_result_used, @@ -391,9 +385,6 @@ pub const Inst = struct { func_extra, /// Same as `func_extra` but the function is variadic. func_extra_var_args, - /// Implements the `@hasDecl` builtin. - /// Uses the `pl_node` union field. Payload is `Bin`. - has_decl, /// Implements the `@import` builtin. /// Uses the `str_tok` field. import, @@ -412,10 +403,6 @@ pub const Inst = struct { /// Make an integer type out of signedness and bit count. /// Payload is `int_type` int_type, - /// Convert an error type to `u16` - error_to_int, - /// Convert a `u16` to `anyerror` - int_to_error, /// Return a boolean false if an optional is null. `x != null` /// Uses the `un_node` field. is_non_null, @@ -498,16 +485,6 @@ pub const Inst = struct { /// Same as `ret_tok` except the operand needs to get coerced to the function's /// return type. ret_coerce, - /// Changes the maximum number of backwards branches that compile-time - /// code execution can use before giving up and making a compile error. - /// Uses the `un_node` union field. - set_eval_branch_quota, - /// Integer shift-left. Zeroes are shifted in from the right hand side. - /// Uses the `pl_node` union field. Payload is `Bin`. - shl, - /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type. - /// Uses the `pl_node` union field. Payload is `Bin`. - shr, /// Create a pointer type that does not have a sentinel, alignment, or bit range specified. /// Uses the `ptr_type_simple` union field. ptr_type_simple, @@ -573,6 +550,10 @@ pub const Inst = struct { /// of one or more params. /// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`. typeof_peer, + /// Given a value, look at the type of it, which must be an integer type. + /// Returns the integer type for the RHS of a shift operation. + /// Uses the `un_node` field. + typeof_log2_int_type, /// Given an integer type, returns the integer type for the RHS of a shift operation. /// Uses the `un_node` field. log2_int_type, @@ -712,12 +693,10 @@ pub const Inst = struct { /// struct value. /// Uses the `pl_node` field. Payload is `StructInit`. struct_init, - /// Converts an integer into an enum value. - /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand. - int_to_enum, - /// Converts an enum value into an integer. Resulting type will be the tag type - /// of the enum. Uses `un_node`. - enum_to_int, + /// Given a pointer to a union and a comptime known field name, activates that field + /// and returns a pointer to it. + /// Uses the `pl_node` field. Payload is `UnionInitPtr`. + union_init_ptr, /// Implements the `@typeInfo` builtin. Uses `un_node`. type_info, /// Implements the `@sizeOf` builtin. Uses `un_node`. @@ -741,6 +720,224 @@ pub const Inst = struct { /// Implements the `@shlWithOverflow` builtin. Uses `pl_node` with `OverflowArithmetic`. shl_with_overflow, + /// Implements the `@errorReturnTrace` builtin. + /// Uses the `un_node` field. + error_return_trace, + /// Implements the `@frame` builtin. + /// Uses the `un_node` field. + frame, + /// Implements the `@frameAddress` builtin. + /// Uses the `un_node` field. + frame_address, + + /// Implement builtin `@ptrToInt`. Uses `un_node`. + ptr_to_int, + /// Implement builtin `@errToInt`. Uses `un_node`. + error_to_int, + /// Implement builtin `@intToError`. Uses `un_node`. + int_to_error, + /// Emit an error message and fail compilation. + /// Uses the `un_node` field. + compile_error, + /// Changes the maximum number of backwards branches that compile-time + /// code execution can use before giving up and making a compile error. + /// Uses the `un_node` union field. + set_eval_branch_quota, + /// Converts an enum value into an integer. Resulting type will be the tag type + /// of the enum. Uses `un_node`. + enum_to_int, + /// Implement builtin `@alignOf`. Uses `un_node`. + align_of, + /// Implement builtin `@boolToInt`. Uses `un_node`. + bool_to_int, + /// Implement builtin `@embedFile`. Uses `un_node`. + embed_file, + /// Implement builtin `@errorName`. Uses `un_node`. + error_name, + /// Implement builtin `@panic`. Uses `un_node`. + panic, + /// Implement builtin `@setAlignStack`. Uses `un_node`. + set_align_stack, + /// Implement builtin `@setCold`. Uses `un_node`. + set_cold, + /// Implement builtin `@setFloatMode`. Uses `un_node`. + set_float_mode, + /// Implement builtin `@setRuntimeSafety`. Uses `un_node`. + set_runtime_safety, + /// Implement builtin `@sqrt`. Uses `un_node`. + sqrt, + /// Implement builtin `@sin`. Uses `un_node`. + sin, + /// Implement builtin `@cos`. Uses `un_node`. + cos, + /// Implement builtin `@exp`. Uses `un_node`. + exp, + /// Implement builtin `@exp2`. Uses `un_node`. + exp2, + /// Implement builtin `@log`. Uses `un_node`. + log, + /// Implement builtin `@log2`. Uses `un_node`. + log2, + /// Implement builtin `@log10`. Uses `un_node`. + log10, + /// Implement builtin `@fabs`. Uses `un_node`. + fabs, + /// Implement builtin `@floor`. Uses `un_node`. + floor, + /// Implement builtin `@ceil`. Uses `un_node`. + ceil, + /// Implement builtin `@trunc`. Uses `un_node`. + trunc, + /// Implement builtin `@round`. Uses `un_node`. + round, + /// Implement builtin `@tagName`. Uses `un_node`. + tag_name, + /// Implement builtin `@Type`. Uses `un_node`. + reify, + /// Implement builtin `@typeName`. Uses `un_node`. + type_name, + /// Implement builtin `@Frame`. Uses `un_node`. + frame_type, + /// Implement builtin `@frameSize`. Uses `un_node`. + frame_size, + + /// Implements the `@floatToInt` builtin. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. + float_to_int, + /// Implements the `@intToFloat` builtin. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. + int_to_float, + /// Implements the `@intToPtr` builtin. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. + int_to_ptr, + /// Converts an integer into an enum value. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. + int_to_enum, + /// Implements the `@floatCast` builtin. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. + float_cast, + /// Implements the `@intCast` builtin. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. + int_cast, + /// Implements the `@errSetCast` builtin. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. + err_set_cast, + /// Implements the `@ptrCast` builtin. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. + ptr_cast, + /// Implements the `@truncate` builtin. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand. + truncate, + /// Implements the `@alignCast` builtin. + /// Uses `pl_node` with payload `Bin`. `lhs` is dest alignment, `rhs` is operand. + align_cast, + + /// Implements the `@hasDecl` builtin. + /// Uses the `pl_node` union field. Payload is `Bin`. + has_decl, + /// Implements the `@hasField` builtin. + /// Uses the `pl_node` union field. Payload is `Bin`. + has_field, + + /// Implements the `@clz` builtin. Uses the `un_node` union field. + clz, + /// Implements the `@ctz` builtin. Uses the `un_node` union field. + ctz, + /// Implements the `@popCount` builtin. Uses the `un_node` union field. + pop_count, + /// Implements the `@byteSwap` builtin. Uses the `un_node` union field. + byte_swap, + /// Implements the `@bitReverse` builtin. Uses the `un_node` union field. + bit_reverse, + + /// Implements the `@divExact` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + div_exact, + /// Implements the `@divFloor` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + div_floor, + /// Implements the `@divTrunc` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + div_trunc, + /// Implements the `@mod` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + mod, + /// Implements the `@rem` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + rem, + + /// Integer shift-left. Zeroes are shifted in from the right hand side. + /// Uses the `pl_node` union field. Payload is `Bin`. + shl, + /// Implements the `@shlExact` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + shl_exact, + /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type. + /// Uses the `pl_node` union field. Payload is `Bin`. + shr, + /// Implements the `@shrExact` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + shr_exact, + + /// Implements the `@bitOffsetOf` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + bit_offset_of, + /// Implements the `@byteOffsetOf` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + byte_offset_of, + /// Implements the `@cmpxchgStrong` builtin. + /// Uses the `pl_node` union field with payload `Cmpxchg`. + cmpxchg_strong, + /// Implements the `@cmpxchgWeak` builtin. + /// Uses the `pl_node` union field with payload `Cmpxchg`. + cmpxchg_weak, + /// Implements the `@splat` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + splat, + /// Implements the `@reduce` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + reduce, + /// Implements the `@shuffle` builtin. + /// Uses the `pl_node` union field with payload `Shuffle`. + shuffle, + /// Implements the `@atomicLoad` builtin. + /// Uses the `pl_node` union field with payload `Bin`. + atomic_load, + /// Implements the `@atomicRmw` builtin. + /// Uses the `pl_node` union field with payload `AtomicRmw`. + atomic_rmw, + /// Implements the `@atomicStore` builtin. + /// Uses the `pl_node` union field with payload `AtomicStore`. + atomic_store, + /// Implements the `@mulAdd` builtin. + /// Uses the `pl_node` union field with payload `MulAdd`. + mul_add, + /// Implements the `@call` builtin. + /// Uses the `pl_node` union field with payload `BuiltinCall`. + builtin_call, + /// Given a type and a field name, returns a pointer to the field type. + /// Assumed to be part of a `@fieldParentPtr` builtin call. + /// Uses the `bin` union field. LHS is type, RHS is field name. + field_ptr_type, + /// Implements the `@fieldParentPtr` builtin. + /// Uses the `pl_node` union field with payload `FieldParentPtr`. + field_parent_ptr, + /// Implements the `@memcpy` builtin. + /// Uses the `pl_node` union field with payload `Memcpy`. + memcpy, + /// Implements the `@memset` builtin. + /// Uses the `pl_node` union field with payload `Memset`. + memset, + /// Implements the `@asyncCall` builtin. + /// Uses the `pl_node` union field with payload `AsyncCall`. + builtin_async_call, + /// Implements the `@cImport` builtin. + /// Uses the `pl_node` union field with payload `Block`. + c_import, + /// The ZIR instruction tag is one of the `Extended` ones. + /// Uses the `extended` union field. + extended, + /// Returns whether the instruction is one of the control flow "noreturn" types. /// Function calls do not count. pub fn isNoReturn(tag: Tag) bool { @@ -876,11 +1073,11 @@ pub const Inst = struct { .slice_sentinel, .import, .typeof_peer, + .typeof_log2_int_type, .log2_int_type, .resolve_inferred_alloc, .set_eval_branch_quota, .compile_log, - .elided, .switch_capture, .switch_capture_ref, .switch_capture_multi, @@ -902,6 +1099,7 @@ pub const Inst = struct { .validate_struct_init_ptr, .struct_init_empty, .struct_init, + .union_init_ptr, .field_type, .int_to_enum, .enum_to_int, @@ -916,6 +1114,77 @@ pub const Inst = struct { .sub_with_overflow, .mul_with_overflow, .shl_with_overflow, + .error_return_trace, + .frame, + .frame_address, + .ptr_to_int, + .align_of, + .bool_to_int, + .embed_file, + .error_name, + .set_align_stack, + .set_cold, + .set_float_mode, + .set_runtime_safety, + .sqrt, + .sin, + .cos, + .exp, + .exp2, + .log, + .log2, + .log10, + .fabs, + .floor, + .ceil, + .trunc, + .round, + .tag_name, + .reify, + .type_name, + .frame_type, + .frame_size, + .float_to_int, + .int_to_float, + .int_to_ptr, + .float_cast, + .int_cast, + .err_set_cast, + .ptr_cast, + .truncate, + .align_cast, + .has_field, + .clz, + .ctz, + .pop_count, + .byte_swap, + .bit_reverse, + .div_exact, + .div_floor, + .div_trunc, + .mod, + .rem, + .shl_exact, + .shr_exact, + .bit_offset_of, + .byte_offset_of, + .cmpxchg_strong, + .cmpxchg_weak, + .splat, + .reduce, + .shuffle, + .atomic_load, + .atomic_rmw, + .atomic_store, + .mul_add, + .builtin_call, + .field_ptr_type, + .field_parent_ptr, + .memcpy, + .memset, + .builtin_async_call, + .c_import, + .extended, => false, .@"break", @@ -929,11 +1198,33 @@ pub const Inst = struct { .@"unreachable", .repeat, .repeat_inline, + .panic, => true, }; } }; + /// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum. + /// `noreturn` instructions may not go here; they must be part of the main `Tag` enum. + pub const Extended = enum(u16) { + /// `operand` is payload index to `UnNode`. + c_undef, + /// `operand` is payload index to `UnNode`. + c_include, + /// `operand` is payload index to `BinNode`. + c_define, + /// `operand` is payload index to `UnNode`. + wasm_memory_size, + /// `operand` is payload index to `BinNode`. + wasm_memory_grow, + + pub const InstData = struct { + opcode: Extended, + small: u16, + operand: u32, + }; + }; + /// The position of a ZIR instruction within the `Zir` instructions array. pub const Index = u32; @@ -1002,6 +1293,14 @@ pub const Inst = struct { single_const_pointer_to_comptime_int_type, const_slice_u8_type, enum_literal_type, + manyptr_u8_type, + manyptr_const_u8_type, + atomic_ordering_type, + atomic_rmw_op_type, + calling_convention_type, + float_mode_type, + reduce_op_type, + call_options_type, /// `undefined` (untyped) undef, @@ -1025,6 +1324,8 @@ pub const Inst = struct { zero_usize, /// `1` (usize) one_usize, + /// `std.builtin.CallingConvention.C` + calling_convention_c, _, @@ -1191,6 +1492,38 @@ pub const Inst = struct { .ty = Type.initTag(.type), .val = Value.initTag(.enum_literal_type), }, + .manyptr_u8_type = .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.manyptr_u8_type), + }, + .manyptr_const_u8_type = .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.manyptr_const_u8_type), + }, + .atomic_ordering_type = .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.atomic_ordering_type), + }, + .atomic_rmw_op_type = .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.atomic_rmw_op_type), + }, + .calling_convention_type = .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.calling_convention_type), + }, + .float_mode_type = .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.float_mode_type), + }, + .reduce_op_type = .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.reduce_op_type), + }, + .call_options_type = .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.call_options_type), + }, .undef = .{ .ty = Type.initTag(.@"undefined"), @@ -1236,13 +1569,27 @@ pub const Inst = struct { .ty = Type.initTag(.empty_struct_literal), .val = Value.initTag(.empty_struct_value), }, + .calling_convention_c = .{ + .ty = Type.initTag(.calling_convention), + .val = .{ .ptr_otherwise = &calling_convention_c_payload.base }, + }, }); }; + /// We would like this to be const but `Value` wants a mutable pointer for + /// its payload field. Nothing should mutate this though. + var calling_convention_c_payload: Value.Payload.U32 = .{ + .base = .{ .tag = .enum_field_index }, + .data = @enumToInt(std.builtin.CallingConvention.C), + }; + /// All instructions have an 8-byte payload, which is contained within /// this union. `Tag` determines which union field is active, as well as /// how to interpret the data within. pub const Data = union { + /// Used for `Tag.extended`. The extended opcode determines the meaning + /// of the `small` and `operand` fields. + extended: Extended.InstData, /// Used for unary operators, with an AST node source location. un_node: struct { /// Offset from Decl AST node index. @@ -1462,6 +1809,12 @@ pub const Inst = struct { args_len: u32, }; + pub const BuiltinCall = struct { + options: Ref, + callee: Ref, + args: Ref, + }; + /// This data is stored inside extra, with two sets of trailing `Ref`: /// * 0. the then body, according to `then_body_len`. /// * 1. the else body, according to `else_body_len`. @@ -1510,6 +1863,17 @@ pub const Inst = struct { rhs: Ref, }; + pub const BinNode = struct { + node: i32, + lhs: Ref, + rhs: Ref, + }; + + pub const UnNode = struct { + node: i32, + operand: Ref, + }; + /// This form is supported when there are no ranges, and exactly 1 item per block. /// Depending on zir tag and len fields, extra fields trail /// this one in the extra array. @@ -1679,6 +2043,70 @@ pub const Inst = struct { ptr: Ref, }; + pub const Cmpxchg = struct { + ptr: Ref, + expected_value: Ref, + new_value: Ref, + success_order: Ref, + fail_order: Ref, + }; + + pub const AtomicRmw = struct { + ptr: Ref, + operation: Ref, + operand: Ref, + ordering: Ref, + }; + + pub const UnionInitPtr = struct { + union_type: Ref, + field_name: Ref, + }; + + pub const AtomicStore = struct { + ptr: Ref, + operand: Ref, + ordering: Ref, + }; + + pub const MulAdd = struct { + mulend1: Ref, + mulend2: Ref, + addend: Ref, + }; + + pub const FieldParentPtr = struct { + parent_type: Ref, + field_name: Ref, + field_ptr: Ref, + }; + + pub const Memcpy = struct { + dest: Ref, + source: Ref, + byte_count: Ref, + }; + + pub const Memset = struct { + dest: Ref, + byte: Ref, + byte_count: Ref, + }; + + pub const Shuffle = struct { + elem_type: Ref, + a: Ref, + b: Ref, + mask: Ref, + }; + + pub const AsyncCall = struct { + frame_buffer: Ref, + result_ptr: Ref, + fn_ptr: Ref, + args: Ref, + }; + /// Trailing: `CompileErrors.Item` for each `items_len`. pub const CompileErrors = struct { items_len: u32, @@ -1749,13 +2177,11 @@ const Writer = struct { .negate_wrap, .call_none, .call_none_chkused, - .compile_error, .load, .ensure_result_used, .ensure_result_non_error, .ptrtoint, .ret_node, - .set_eval_branch_quota, .resolve_inferred_alloc, .optional_type, .optional_type_from_ptr_elem, @@ -1769,8 +2195,6 @@ const Writer = struct { .err_union_payload_unsafe_ptr, .err_union_code, .err_union_code_ptr, - .int_to_error, - .error_to_int, .is_non_null, .is_null, .is_non_null_ptr, @@ -1780,11 +2204,49 @@ const Writer = struct { .typeof, .typeof_elem, .struct_init_empty, - .enum_to_int, .type_info, .size_of, .bit_size_of, + .typeof_log2_int_type, .log2_int_type, + .ptr_to_int, + .error_to_int, + .int_to_error, + .compile_error, + .set_eval_branch_quota, + .enum_to_int, + .align_of, + .bool_to_int, + .embed_file, + .error_name, + .panic, + .set_align_stack, + .set_cold, + .set_float_mode, + .set_runtime_safety, + .sqrt, + .sin, + .cos, + .exp, + .exp2, + .log, + .log2, + .log10, + .fabs, + .floor, + .ceil, + .trunc, + .round, + .tag_name, + .reify, + .type_name, + .frame_type, + .frame_size, + .clz, + .ctz, + .pop_count, + .byte_swap, + .bit_reverse, => try self.writeUnNode(stream, inst), .ref, @@ -1805,7 +2267,6 @@ const Writer = struct { .float => try self.writeFloat(stream, inst), .float128 => try self.writeFloat128(stream, inst), .str => try self.writeStr(stream, inst), - .elided => try stream.writeAll(")"), .int_type => try self.writeIntType(stream, inst), .@"break", @@ -1824,7 +2285,20 @@ const Writer = struct { .slice_sentinel, .union_decl, .struct_init, + .union_init_ptr, .field_type, + .cmpxchg_strong, + .cmpxchg_weak, + .shuffle, + .atomic_rmw, + .atomic_store, + .mul_add, + .builtin_call, + .field_ptr_type, + .field_parent_ptr, + .memcpy, + .memset, + .builtin_async_call, => try self.writePlNode(stream, inst), .add_with_overflow, @@ -1851,9 +2325,12 @@ const Writer = struct { .cmp_neq, .div, .has_decl, + .has_field, .mod_rem, .shl, + .shl_exact, .shr, + .shr_exact, .xor, .store_node, .error_union_type, @@ -1861,7 +2338,26 @@ const Writer = struct { .merge_error_sets, .bit_and, .bit_or, + .float_to_int, + .int_to_float, + .int_to_ptr, .int_to_enum, + .float_cast, + .int_cast, + .err_set_cast, + .ptr_cast, + .truncate, + .align_cast, + .div_exact, + .div_floor, + .div_trunc, + .mod, + .rem, + .bit_offset_of, + .byte_offset_of, + .splat, + .reduce, + .atomic_load, => try self.writePlNodeBin(stream, inst), .call, @@ -1874,6 +2370,7 @@ const Writer = struct { .block_inline_var, .loop, .validate_struct_init_ptr, + .c_import, => try self.writePlNodeBlock(stream, inst), .condbr, @@ -1926,6 +2423,9 @@ const Writer = struct { .fence, .ret_addr, .builtin_src, + .error_return_trace, + .frame, + .frame_address, => try self.writeNode(stream, inst), .error_value, @@ -1954,6 +2454,7 @@ const Writer = struct { .bitcast, .bitcast_result_ptr, + .extended, => try stream.writeAll("TODO)"), } } diff --git a/src/type.zig b/src/type.zig index 0429fd876a..63c1616506 100644 --- a/src/type.zig +++ b/src/type.zig @@ -83,6 +83,8 @@ pub const Type = extern union { .pointer, .inferred_alloc_const, .inferred_alloc_mut, + .manyptr_u8, + .manyptr_const_u8, => return .Pointer, .optional, @@ -96,11 +98,17 @@ pub const Type = extern union { .empty_struct, .empty_struct_literal, .@"struct", + .call_options, => return .Struct, .enum_full, .enum_nonexhaustive, .enum_simple, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, => return .Enum, .var_args_param => unreachable, // can be any type @@ -205,6 +213,8 @@ pub const Type = extern union { .mut_slice, .optional_single_const_pointer, .optional_single_mut_pointer, + .manyptr_u8, + .manyptr_const_u8, => self.cast(Payload.ElemType), .inferred_alloc_const => unreachable, @@ -271,6 +281,17 @@ pub const Type = extern union { .@"volatile" = false, .size = .Many, } }, + .manyptr_const_u8 => return .{ .data = .{ + .pointee_type = Type.initTag(.u8), + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = false, + .@"volatile" = false, + .size = .Many, + } }, .many_mut_pointer => return .{ .data = .{ .pointee_type = self.castPointer().?.data, .sentinel = null, @@ -282,6 +303,17 @@ pub const Type = extern union { .@"volatile" = false, .size = .Many, } }, + .manyptr_u8 => return .{ .data = .{ + .pointee_type = Type.initTag(.u8), + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = true, + .@"volatile" = false, + .size = .Many, + } }, .c_const_pointer => return .{ .data = .{ .pointee_type = self.castPointer().?.data, .sentinel = null, @@ -576,6 +608,14 @@ pub const Type = extern union { .inferred_alloc_mut, .var_args_param, .empty_struct_literal, + .manyptr_u8, + .manyptr_const_u8, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, => unreachable, .array_u8, @@ -746,6 +786,14 @@ pub const Type = extern union { .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"), .fn_ccc_void_no_args => return writer.writeAll("fn() callconv(.C) void"), .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"), + .manyptr_u8 => return writer.writeAll("[*]u8"), + .manyptr_const_u8 => return writer.writeAll("[*]const u8"), + .atomic_ordering => return writer.writeAll("std.builtin.AtomicOrdering"), + .atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"), + .calling_convention => return writer.writeAll("std.builtin.CallingConvention"), + .float_mode => return writer.writeAll("std.builtin.FloatMode"), + .reduce_op => return writer.writeAll("std.builtin.ReduceOp"), + .call_options => return writer.writeAll("std.builtin.CallOptions"), .function => { const payload = ty.castTag(.function).?.data; try writer.writeAll("fn("); @@ -952,6 +1000,14 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type), .const_slice_u8 => return Value.initTag(.const_slice_u8_type), .enum_literal => return Value.initTag(.enum_literal_type), + .manyptr_u8 => return Value.initTag(.manyptr_u8_type), + .manyptr_const_u8 => return Value.initTag(.manyptr_const_u8_type), + .atomic_ordering => return Value.initTag(.atomic_ordering_type), + .atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type), + .calling_convention => return Value.initTag(.calling_convention_type), + .float_mode => return Value.initTag(.float_mode_type), + .reduce_op => return Value.initTag(.reduce_op_type), + .call_options => return Value.initTag(.call_options_type), .inferred_alloc_const => unreachable, .inferred_alloc_mut => unreachable, else => return Value.Tag.ty.create(allocator, self), @@ -1001,6 +1057,14 @@ pub const Type = extern union { .anyerror_void_error_union, .error_set, .error_set_single, + .manyptr_u8, + .manyptr_const_u8, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, => true, .@"struct" => { @@ -1079,7 +1143,10 @@ pub const Type = extern union { .optional_single_mut_pointer, => return self.cast(Payload.ElemType).?.data.abiAlignment(target), - .const_slice_u8 => return 1, + .manyptr_u8, + .manyptr_const_u8, + .const_slice_u8, + => return 1, .pointer => { const ptr_info = self.castTag(.pointer).?.data; @@ -1102,6 +1169,12 @@ pub const Type = extern union { .bool, .array_u8_sentinel_0, .array_u8, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, => return 1, .fn_noreturn_no_args, // represents machine code; not a pointer @@ -1136,6 +1209,8 @@ pub const Type = extern union { .optional_single_const_pointer, .optional_single_mut_pointer, .pointer, + .manyptr_u8, + .manyptr_const_u8, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), .c_short => return @divExact(CType.short.sizeInBits(target), 8), @@ -1271,6 +1346,12 @@ pub const Type = extern union { .u8, .i8, .bool, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, => return 1, .array_u8 => self.castTag(.array_u8).?.data, @@ -1322,6 +1403,10 @@ pub const Type = extern union { return @divExact(target.cpu.arch.ptrBitWidth(), 8); }, + .manyptr_u8, + .manyptr_const_u8, + => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .c_short => return @divExact(CType.short.sizeInBits(target), 8), .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), .c_int => return @divExact(CType.int.sizeInBits(target), 8), @@ -1475,6 +1560,10 @@ pub const Type = extern union { } }, + .manyptr_u8, + .manyptr_const_u8, + => return target.cpu.arch.ptrBitWidth(), + .c_short => return CType.short.sizeInBits(target), .c_ushort => return CType.ushort.sizeInBits(target), .c_int => return CType.int.sizeInBits(target), @@ -1517,8 +1606,16 @@ pub const Type = extern union { } else if (!payload.payload.hasCodeGenBits()) { return payload.error_set.bitSize(target); } - @panic("TODO abiSize error union"); + @panic("TODO bitSize error union"); }, + + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, + => @panic("TODO at some point we gotta resolve builtin types"), }; } @@ -1564,6 +1661,8 @@ pub const Type = extern union { .many_const_pointer, .many_mut_pointer, + .manyptr_u8, + .manyptr_const_u8, => .Many, .c_const_pointer, @@ -1604,6 +1703,7 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, .const_slice_u8, .const_slice, + .manyptr_const_u8, => true, .pointer => !self.castTag(.pointer).?.data.mutable, @@ -1718,7 +1818,13 @@ pub const Type = extern union { .mut_slice, => self.castPointer().?.data, - .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), + .array_u8, + .array_u8_sentinel_0, + .const_slice_u8, + .manyptr_u8, + .manyptr_const_u8, + => Type.initTag(.u8), + .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), .pointer => self.castTag(.pointer).?.data.pointee_type, @@ -1811,6 +1917,8 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, .array, .array_u8, + .manyptr_u8, + .manyptr_const_u8, => return null, .pointer => return self.castTag(.pointer).?.data.sentinel, @@ -2122,6 +2230,14 @@ pub const Type = extern union { .error_set_single, .@"opaque", .var_args_param, + .manyptr_u8, + .manyptr_const_u8, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, => return null, .@"struct" => { @@ -2281,6 +2397,14 @@ pub const Type = extern union { const enum_simple = ty.castTag(.enum_simple).?.data; return enum_simple.fields.count(); }, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, + => @panic("TODO resolve std.builtin types"), + else => unreachable, } } @@ -2295,6 +2419,13 @@ pub const Type = extern union { const enum_simple = ty.castTag(.enum_simple).?.data; return enum_simple.fields.entries.items[field_index].key; }, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, + => @panic("TODO resolve std.builtin types"), else => unreachable, } } @@ -2309,6 +2440,13 @@ pub const Type = extern union { const enum_simple = ty.castTag(.enum_simple).?.data; return enum_simple.fields.getIndex(field_name); }, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, + => @panic("TODO resolve std.builtin types"), else => unreachable, } } @@ -2345,6 +2483,13 @@ pub const Type = extern union { const enum_simple = ty.castTag(.enum_simple).?.data; return S.fieldWithRange(enum_tag, enum_simple.fields.count()); }, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, + => @panic("TODO resolve std.builtin types"), else => unreachable, } } @@ -2367,6 +2512,13 @@ pub const Type = extern union { const error_set = ty.castTag(.error_set).?.data; return error_set.srcLoc(); }, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, + => @panic("TODO resolve std.builtin types"), else => unreachable, } } @@ -2390,6 +2542,13 @@ pub const Type = extern union { return error_set.owner_decl; }, .@"opaque" => @panic("TODO"), + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, + => @panic("TODO resolve std.builtin types"), else => unreachable, } } @@ -2422,6 +2581,13 @@ pub const Type = extern union { const enum_simple = ty.castTag(.enum_simple).?.data; return S.intInRange(int, enum_simple.fields.count()); }, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, + => @panic("TODO resolve std.builtin types"), else => unreachable, } @@ -2469,6 +2635,14 @@ pub const Type = extern union { comptime_float, noreturn, enum_literal, + manyptr_u8, + manyptr_const_u8, + atomic_ordering, + atomic_rmw_op, + calling_convention, + float_mode, + reduce_op, + call_options, @"null", @"undefined", fn_noreturn_no_args, @@ -2572,6 +2746,14 @@ pub const Type = extern union { .inferred_alloc_mut, .var_args_param, .empty_struct_literal, + .manyptr_u8, + .manyptr_const_u8, + .atomic_ordering, + .atomic_rmw_op, + .calling_convention, + .float_mode, + .reduce_op, + .call_options, => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), .array_u8, diff --git a/src/value.zig b/src/value.zig index a9aec47272..80b21f0713 100644 --- a/src/value.zig +++ b/src/value.zig @@ -64,6 +64,14 @@ pub const Value = extern union { single_const_pointer_to_comptime_int_type, const_slice_u8_type, enum_literal_type, + manyptr_u8_type, + manyptr_const_u8_type, + atomic_ordering_type, + atomic_rmw_op_type, + calling_convention_type, + float_mode_type, + reduce_op_type, + call_options_type, undef, zero, @@ -169,6 +177,14 @@ pub const Value = extern union { .bool_true, .bool_false, .abi_align_default, + .manyptr_u8_type, + .manyptr_const_u8_type, + .atomic_ordering_type, + .atomic_rmw_op_type, + .calling_convention_type, + .float_mode_type, + .reduce_op_type, + .call_options_type, => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"), .int_big_positive, @@ -327,6 +343,14 @@ pub const Value = extern union { .bool_false, .empty_struct_value, .abi_align_default, + .manyptr_u8_type, + .manyptr_const_u8_type, + .atomic_ordering_type, + .atomic_rmw_op_type, + .calling_convention_type, + .float_mode_type, + .reduce_op_type, + .call_options_type, => unreachable, .ty => { @@ -474,6 +498,14 @@ pub const Value = extern union { .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"), .const_slice_u8_type => return out_stream.writeAll("[]const u8"), .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"), + .manyptr_u8_type => return out_stream.writeAll("[*]u8"), + .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"), + .atomic_ordering_type => return out_stream.writeAll("std.builtin.AtomicOrdering"), + .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"), + .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"), + .float_mode_type => return out_stream.writeAll("std.builtin.FloatMode"), + .reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"), + .call_options_type => return out_stream.writeAll("std.builtin.CallOptions"), .abi_align_default => return out_stream.writeAll("(default ABI alignment)"), .empty_struct_value => return out_stream.writeAll("struct {}{}"), @@ -595,6 +627,14 @@ pub const Value = extern union { .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int), .const_slice_u8_type => Type.initTag(.const_slice_u8), .enum_literal_type => Type.initTag(.enum_literal), + .manyptr_u8_type => Type.initTag(.manyptr_u8), + .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8), + .atomic_ordering_type => Type.initTag(.atomic_ordering), + .atomic_rmw_op_type => Type.initTag(.atomic_rmw_op), + .calling_convention_type => Type.initTag(.calling_convention), + .float_mode_type => Type.initTag(.float_mode), + .reduce_op_type => Type.initTag(.reduce_op), + .call_options_type => Type.initTag(.call_options), .int_type => { const payload = self.castTag(.int_type).?.data; @@ -1132,6 +1172,16 @@ pub const Value = extern union { std.hash.autoHash(&hasher, payload.hash()); }, .inferred_alloc => unreachable, + + .manyptr_u8_type, + .manyptr_const_u8_type, + .atomic_ordering_type, + .atomic_rmw_op_type, + .calling_convention_type, + .float_mode_type, + .reduce_op_type, + .call_options_type, + => @panic("TODO this hash function looks pretty broken. audit it"), } return hasher.final(); } @@ -1278,6 +1328,14 @@ pub const Value = extern union { .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, .enum_literal_type, + .manyptr_u8_type, + .manyptr_const_u8_type, + .atomic_ordering_type, + .atomic_rmw_op_type, + .calling_convention_type, + .float_mode_type, + .reduce_op_type, + .call_options_type, => true, .zero, |
