diff options
Diffstat (limited to 'src/AstGen.zig')
| -rw-r--r-- | src/AstGen.zig | 897 |
1 files changed, 670 insertions, 227 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( |
