| author | |
| committer | |
| log | f559ea95b1c37fd6ede8fff6ffb2d74d5c2abc4e |
| tree | 6d9714e54fa2223aa6842d8d496d5f3dadd360e8 |
| parent | 0a42602418dcaf08f13b4220b6c216356f87cbfc |
| parent | 7377dce368090e3c49a15d8996cc812adadd3d43 |
| signature |
Stage2 fixes18 files changed, 528 insertions(+), 201 deletions(-)
src/AstGen.zig+22-11| ... | @@ -226,6 +226,8 @@ pub const ResultLoc = union(enum) { | ... | @@ -226,6 +226,8 @@ pub const ResultLoc = union(enum) { |
| 226 | ref, | 226 | ref, |
| 227 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. | 227 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. |
| 228 | ty: Zir.Inst.Ref, | 228 | ty: Zir.Inst.Ref, |
| 229 | /// Same as `ty` but for shift operands. | ||
| 230 | ty_shift_operand: Zir.Inst.Ref, | ||
| 229 | /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion, | 231 | /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion, |
| 230 | /// so no `as` instruction needs to be emitted. | 232 | /// so no `as` instruction needs to be emitted. |
| 231 | coerced_ty: Zir.Inst.Ref, | 233 | coerced_ty: Zir.Inst.Ref, |
| ... | @@ -259,7 +261,7 @@ pub const ResultLoc = union(enum) { | ... | @@ -259,7 +261,7 @@ pub const ResultLoc = union(enum) { |
| 259 | fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy { | 261 | fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy { |
| 260 | switch (rl) { | 262 | switch (rl) { |
| 261 | // In this branch there will not be any store_to_block_ptr instructions. | 263 | // In this branch there will not be any store_to_block_ptr instructions. |
| 262 | .none, .ty, .coerced_ty, .ref => return .{ | 264 | .none, .ty, .ty_shift_operand, .coerced_ty, .ref => return .{ |
| 263 | .tag = .break_operand, | 265 | .tag = .break_operand, |
| 264 | .elide_store_to_block_ptr_instructions = false, | 266 | .elide_store_to_block_ptr_instructions = false, |
| 265 | }, | 267 | }, |
| ... | @@ -302,6 +304,14 @@ pub const ResultLoc = union(enum) { | ... | @@ -302,6 +304,14 @@ pub const ResultLoc = union(enum) { |
| 302 | else => rl, | 304 | else => rl, |
| 303 | }; | 305 | }; |
| 304 | } | 306 | } |
| 307 | |||
| 308 | fn zirTag(rl: ResultLoc) Zir.Inst.Tag { | ||
| 309 | return switch (rl) { | ||
| 310 | .ty => .as_node, | ||
| 311 | .ty_shift_operand => .as_shift_operand, | ||
| 312 | else => unreachable, | ||
| 313 | }; | ||
| 314 | } | ||
| 305 | }; | 315 | }; |
| 306 | 316 | ||
| 307 | pub const align_rl: ResultLoc = .{ .ty = .u29_type }; | 317 | pub const align_rl: ResultLoc = .{ .ty = .u29_type }; |
| ... | @@ -1385,7 +1395,7 @@ fn arrayInitExpr( | ... | @@ -1385,7 +1395,7 @@ fn arrayInitExpr( |
| 1385 | const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; | 1395 | const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; |
| 1386 | return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); | 1396 | return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); |
| 1387 | }, | 1397 | }, |
| 1388 | .ty, .coerced_ty => { | 1398 | .ty, .ty_shift_operand, .coerced_ty => { |
| 1389 | const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; | 1399 | const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; |
| 1390 | const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); | 1400 | const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); |
| 1391 | return rvalue(gz, rl, result, node); | 1401 | return rvalue(gz, rl, result, node); |
| ... | @@ -1631,7 +1641,7 @@ fn structInitExpr( | ... | @@ -1631,7 +1641,7 @@ fn structInitExpr( |
| 1631 | return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); | 1641 | return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); |
| 1632 | } | 1642 | } |
| 1633 | }, | 1643 | }, |
| 1634 | .ty, .coerced_ty => |ty_inst| { | 1644 | .ty, .ty_shift_operand, .coerced_ty => |ty_inst| { |
| 1635 | if (struct_init.ast.type_expr == 0) { | 1645 | if (struct_init.ast.type_expr == 0) { |
| 1636 | const result = try structInitExprRlNone(gz, scope, node, struct_init, ty_inst, .struct_init_anon); | 1646 | const result = try structInitExprRlNone(gz, scope, node, struct_init, ty_inst, .struct_init_anon); |
| 1637 | return rvalue(gz, rl, result, node); | 1647 | return rvalue(gz, rl, result, node); |
| ... | @@ -2327,6 +2337,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2327,6 +2337,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2327 | .anyframe_type, | 2337 | .anyframe_type, |
| 2328 | .as, | 2338 | .as, |
| 2329 | .as_node, | 2339 | .as_node, |
| 2340 | .as_shift_operand, | ||
| 2330 | .bit_and, | 2341 | .bit_and, |
| 2331 | .bitcast, | 2342 | .bitcast, |
| 2332 | .bit_or, | 2343 | .bit_or, |
| ... | @@ -2497,7 +2508,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2497,7 +2508,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2497 | .field_parent_ptr, | 2508 | .field_parent_ptr, |
| 2498 | .maximum, | 2509 | .maximum, |
| 2499 | .minimum, | 2510 | .minimum, |
| 2500 | .builtin_async_call, | ||
| 2501 | .c_import, | 2511 | .c_import, |
| 2502 | .@"resume", | 2512 | .@"resume", |
| 2503 | .@"await", | 2513 | .@"await", |
| ... | @@ -7278,7 +7288,7 @@ fn as( | ... | @@ -7278,7 +7288,7 @@ fn as( |
| 7278 | ) InnerError!Zir.Inst.Ref { | 7288 | ) InnerError!Zir.Inst.Ref { |
| 7279 | const dest_type = try typeExpr(gz, scope, lhs); | 7289 | const dest_type = try typeExpr(gz, scope, lhs); |
| 7280 | switch (rl) { | 7290 | switch (rl) { |
| 7281 | .none, .discard, .ref, .ty, .coerced_ty => { | 7291 | .none, .discard, .ref, .ty, .ty_shift_operand, .coerced_ty => { |
| 7282 | const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node); | 7292 | const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node); |
| 7283 | return rvalue(gz, rl, result, node); | 7293 | return rvalue(gz, rl, result, node); |
| 7284 | }, | 7294 | }, |
| ... | @@ -7959,7 +7969,8 @@ fn builtinCall( | ... | @@ -7959,7 +7969,8 @@ fn builtinCall( |
| 7959 | return rvalue(gz, rl, result, node); | 7969 | return rvalue(gz, rl, result, node); |
| 7960 | }, | 7970 | }, |
| 7961 | .async_call => { | 7971 | .async_call => { |
| 7962 | const result = try gz.addPlNode(.builtin_async_call, node, Zir.Inst.AsyncCall{ | 7972 | const result = try gz.addExtendedPayload(.builtin_async_call, Zir.Inst.AsyncCall{ |
| 7973 | .node = gz.nodeIndexToRelative(node), | ||
| 7963 | .frame_buffer = try expr(gz, scope, .none, params[0]), | 7974 | .frame_buffer = try expr(gz, scope, .none, params[0]), |
| 7964 | .result_ptr = try expr(gz, scope, .none, params[1]), | 7975 | .result_ptr = try expr(gz, scope, .none, params[1]), |
| 7965 | .fn_ptr = try expr(gz, scope, .none, params[2]), | 7976 | .fn_ptr = try expr(gz, scope, .none, params[2]), |
| ... | @@ -8178,7 +8189,7 @@ fn shiftOp( | ... | @@ -8178,7 +8189,7 @@ fn shiftOp( |
| 8178 | ) InnerError!Zir.Inst.Ref { | 8189 | ) InnerError!Zir.Inst.Ref { |
| 8179 | const lhs = try expr(gz, scope, .none, lhs_node); | 8190 | const lhs = try expr(gz, scope, .none, lhs_node); |
| 8180 | const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node); | 8191 | const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node); |
| 8181 | const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, rhs_node); | 8192 | const rhs = try expr(gz, scope, .{ .ty_shift_operand = log2_int_type }, rhs_node); |
| 8182 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ | 8193 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ |
| 8183 | .lhs = lhs, | 8194 | .lhs = lhs, |
| 8184 | .rhs = rhs, | 8195 | .rhs = rhs, |
| ... | @@ -9409,7 +9420,7 @@ fn rvalue( | ... | @@ -9409,7 +9420,7 @@ fn rvalue( |
| 9409 | } | 9420 | } |
| 9410 | return indexToRef(gop.value_ptr.*); | 9421 | return indexToRef(gop.value_ptr.*); |
| 9411 | }, | 9422 | }, |
| 9412 | .ty => |ty_inst| { | 9423 | .ty, .ty_shift_operand => |ty_inst| { |
| 9413 | // Quickly eliminate some common, unnecessary type coercion. | 9424 | // Quickly eliminate some common, unnecessary type coercion. |
| 9414 | const as_ty = @as(u64, @enumToInt(Zir.Inst.Ref.type_type)) << 32; | 9425 | const as_ty = @as(u64, @enumToInt(Zir.Inst.Ref.type_type)) << 32; |
| 9415 | const as_comptime_int = @as(u64, @enumToInt(Zir.Inst.Ref.comptime_int_type)) << 32; | 9426 | const as_comptime_int = @as(u64, @enumToInt(Zir.Inst.Ref.comptime_int_type)) << 32; |
| ... | @@ -9470,7 +9481,7 @@ fn rvalue( | ... | @@ -9470,7 +9481,7 @@ fn rvalue( |
| 9470 | => return result, // type of result is already correct | 9481 | => return result, // type of result is already correct |
| 9471 | 9482 | ||
| 9472 | // Need an explicit type coercion instruction. | 9483 | // Need an explicit type coercion instruction. |
| 9473 | else => return gz.addPlNode(.as_node, src_node, Zir.Inst.As{ | 9484 | else => return gz.addPlNode(rl.zirTag(), src_node, Zir.Inst.As{ |
| 9474 | .dest_type = ty_inst, | 9485 | .dest_type = ty_inst, |
| 9475 | .operand = result, | 9486 | .operand = result, |
| 9476 | }), | 9487 | }), |
| ... | @@ -10350,7 +10361,7 @@ const GenZir = struct { | ... | @@ -10350,7 +10361,7 @@ const GenZir = struct { |
| 10350 | // we emit ZIR for the block break instructions to have the result values, | 10361 | // we emit ZIR for the block break instructions to have the result values, |
| 10351 | // and then rvalue() on that to pass the value to the result location. | 10362 | // and then rvalue() on that to pass the value to the result location. |
| 10352 | switch (parent_rl) { | 10363 | switch (parent_rl) { |
| 10353 | .ty, .coerced_ty => |ty_inst| { | 10364 | .ty, .ty_shift_operand, .coerced_ty => |ty_inst| { |
| 10354 | gz.rl_ty_inst = ty_inst; | 10365 | gz.rl_ty_inst = ty_inst; |
| 10355 | gz.break_result_loc = parent_rl; | 10366 | gz.break_result_loc = parent_rl; |
| 10356 | }, | 10367 | }, |
| ... | @@ -11506,7 +11517,7 @@ const GenZir = struct { | ... | @@ -11506,7 +11517,7 @@ const GenZir = struct { |
| 11506 | fn addRet(gz: *GenZir, rl: ResultLoc, operand: Zir.Inst.Ref, node: Ast.Node.Index) !void { | 11517 | fn addRet(gz: *GenZir, rl: ResultLoc, operand: Zir.Inst.Ref, node: Ast.Node.Index) !void { |
| 11507 | switch (rl) { | 11518 | switch (rl) { |
| 11508 | .ptr => |ret_ptr| _ = try gz.addUnNode(.ret_load, ret_ptr, node), | 11519 | .ptr => |ret_ptr| _ = try gz.addUnNode(.ret_load, ret_ptr, node), |
| 11509 | .ty => _ = try gz.addUnNode(.ret_node, operand, node), | 11520 | .ty, .ty_shift_operand => _ = try gz.addUnNode(.ret_node, operand, node), |
| 11510 | else => unreachable, | 11521 | else => unreachable, |
| 11511 | } | 11522 | } |
| 11512 | } | 11523 | } |
src/Autodoc.zig+1-1| ... | @@ -1888,7 +1888,7 @@ fn walkInstruction( | ... | @@ -1888,7 +1888,7 @@ fn walkInstruction( |
| 1888 | .expr = .{ .typeInfo = operand_index }, | 1888 | .expr = .{ .typeInfo = operand_index }, |
| 1889 | }; | 1889 | }; |
| 1890 | }, | 1890 | }, |
| 1891 | .as_node => { | 1891 | .as_node, .as_shift_operand => { |
| 1892 | const pl_node = data[inst_index].pl_node; | 1892 | const pl_node = data[inst_index].pl_node; |
| 1893 | const extra = file.zir.extraData(Zir.Inst.As, pl_node.payload_index); | 1893 | const extra = file.zir.extraData(Zir.Inst.As, pl_node.payload_index); |
| 1894 | const dest_type_walk = try self.walkRef( | 1894 | const dest_type_walk = try self.walkRef( |
src/Compilation.zig+19-17| ... | @@ -4766,6 +4766,24 @@ pub fn dump_argv(argv: []const []const u8) void { | ... | @@ -4766,6 +4766,24 @@ pub fn dump_argv(argv: []const []const u8) void { |
| 4766 | std.debug.print("{s}\n", .{argv[argv.len - 1]}); | 4766 | std.debug.print("{s}\n", .{argv[argv.len - 1]}); |
| 4767 | } | 4767 | } |
| 4768 | 4768 | ||
| 4769 | pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend { | ||
| 4770 | const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; | ||
| 4771 | if (use_stage1) return .stage1; | ||
| 4772 | if (build_options.have_llvm and comp.bin_file.options.use_llvm) return .stage2_llvm; | ||
| 4773 | const target = comp.bin_file.options.target; | ||
| 4774 | if (target.ofmt == .c) return .stage2_c; | ||
| 4775 | return switch (target.cpu.arch) { | ||
| 4776 | .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm, | ||
| 4777 | .arm, .armeb, .thumb, .thumbeb => .stage2_arm, | ||
| 4778 | .x86_64 => .stage2_x86_64, | ||
| 4779 | .i386 => .stage2_x86, | ||
| 4780 | .aarch64, .aarch64_be, .aarch64_32 => .stage2_aarch64, | ||
| 4781 | .riscv64 => .stage2_riscv64, | ||
| 4782 | .sparc64 => .stage2_sparc64, | ||
| 4783 | else => .other, | ||
| 4784 | }; | ||
| 4785 | } | ||
| 4786 | |||
| 4769 | pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Allocator.Error![:0]u8 { | 4787 | pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Allocator.Error![:0]u8 { |
| 4770 | const tracy_trace = trace(@src()); | 4788 | const tracy_trace = trace(@src()); |
| 4771 | defer tracy_trace.end(); | 4789 | defer tracy_trace.end(); |
| ... | @@ -4775,23 +4793,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca | ... | @@ -4775,23 +4793,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca |
| 4775 | 4793 | ||
| 4776 | const target = comp.getTarget(); | 4794 | const target = comp.getTarget(); |
| 4777 | const generic_arch_name = target.cpu.arch.genericName(); | 4795 | const generic_arch_name = target.cpu.arch.genericName(); |
| 4778 | const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; | 4796 | const zig_backend = comp.getZigBackend(); |
| 4779 | |||
| 4780 | const zig_backend: std.builtin.CompilerBackend = blk: { | ||
| 4781 | if (use_stage1) break :blk .stage1; | ||
| 4782 | if (build_options.have_llvm and comp.bin_file.options.use_llvm) break :blk .stage2_llvm; | ||
| 4783 | if (target.ofmt == .c) break :blk .stage2_c; | ||
| 4784 | break :blk switch (target.cpu.arch) { | ||
| 4785 | .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm, | ||
| 4786 | .arm, .armeb, .thumb, .thumbeb => .stage2_arm, | ||
| 4787 | .x86_64 => .stage2_x86_64, | ||
| 4788 | .i386 => .stage2_x86, | ||
| 4789 | .aarch64, .aarch64_be, .aarch64_32 => .stage2_aarch64, | ||
| 4790 | .riscv64 => .stage2_riscv64, | ||
| 4791 | .sparc64 => .stage2_sparc64, | ||
| 4792 | else => .other, | ||
| 4793 | }; | ||
| 4794 | }; | ||
| 4795 | 4797 | ||
| 4796 | @setEvalBranchQuota(4000); | 4798 | @setEvalBranchQuota(4000); |
| 4797 | try buffer.writer().print( | 4799 | try buffer.writer().print( |
src/Sema.zig+134-39| ... | @@ -712,6 +712,7 @@ fn analyzeBodyInner( | ... | @@ -712,6 +712,7 @@ fn analyzeBodyInner( |
| 712 | .vector_type => try sema.zirVectorType(block, inst), | 712 | .vector_type => try sema.zirVectorType(block, inst), |
| 713 | .as => try sema.zirAs(block, inst), | 713 | .as => try sema.zirAs(block, inst), |
| 714 | .as_node => try sema.zirAsNode(block, inst), | 714 | .as_node => try sema.zirAsNode(block, inst), |
| 715 | .as_shift_operand => try sema.zirAsShiftOperand(block, inst), | ||
| 715 | .bit_and => try sema.zirBitwise(block, inst, .bit_and), | 716 | .bit_and => try sema.zirBitwise(block, inst, .bit_and), |
| 716 | .bit_not => try sema.zirBitNot(block, inst), | 717 | .bit_not => try sema.zirBitNot(block, inst), |
| 717 | .bit_or => try sema.zirBitwise(block, inst, .bit_or), | 718 | .bit_or => try sema.zirBitwise(block, inst, .bit_or), |
| ... | @@ -848,7 +849,6 @@ fn analyzeBodyInner( | ... | @@ -848,7 +849,6 @@ fn analyzeBodyInner( |
| 848 | .mul_add => try sema.zirMulAdd(block, inst), | 849 | .mul_add => try sema.zirMulAdd(block, inst), |
| 849 | .builtin_call => try sema.zirBuiltinCall(block, inst), | 850 | .builtin_call => try sema.zirBuiltinCall(block, inst), |
| 850 | .field_parent_ptr => try sema.zirFieldParentPtr(block, inst), | 851 | .field_parent_ptr => try sema.zirFieldParentPtr(block, inst), |
| 851 | .builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst), | ||
| 852 | .@"resume" => try sema.zirResume(block, inst), | 852 | .@"resume" => try sema.zirResume(block, inst), |
| 853 | .@"await" => try sema.zirAwait(block, inst), | 853 | .@"await" => try sema.zirAwait(block, inst), |
| 854 | .array_base_ptr => try sema.zirArrayBasePtr(block, inst), | 854 | .array_base_ptr => try sema.zirArrayBasePtr(block, inst), |
| ... | @@ -956,6 +956,7 @@ fn analyzeBodyInner( | ... | @@ -956,6 +956,7 @@ fn analyzeBodyInner( |
| 956 | .error_to_int => try sema.zirErrorToInt( block, extended), | 956 | .error_to_int => try sema.zirErrorToInt( block, extended), |
| 957 | .int_to_error => try sema.zirIntToError( block, extended), | 957 | .int_to_error => try sema.zirIntToError( block, extended), |
| 958 | .reify => try sema.zirReify( block, extended, inst), | 958 | .reify => try sema.zirReify( block, extended, inst), |
| 959 | .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended), | ||
| 959 | // zig fmt: on | 960 | // zig fmt: on |
| 960 | .fence => { | 961 | .fence => { |
| 961 | try sema.zirFence(block, extended); | 962 | try sema.zirFence(block, extended); |
| ... | @@ -6152,9 +6153,30 @@ fn analyzeCall( | ... | @@ -6152,9 +6153,30 @@ fn analyzeCall( |
| 6152 | if (ensure_result_used) { | 6153 | if (ensure_result_used) { |
| 6153 | try sema.ensureResultUsed(block, result, call_src); | 6154 | try sema.ensureResultUsed(block, result, call_src); |
| 6154 | } | 6155 | } |
| 6156 | if (call_tag == .call_always_tail) { | ||
| 6157 | return sema.handleTailCall(block, call_src, func_ty, result); | ||
| 6158 | } | ||
| 6155 | return result; | 6159 | return result; |
| 6156 | } | 6160 | } |
| 6157 | 6161 | ||
| 6162 | fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { | ||
| 6163 | const target = sema.mod.getTarget(); | ||
| 6164 | const backend = sema.mod.comp.getZigBackend(); | ||
| 6165 | if (!target_util.supportsTailCall(target, backend)) { | ||
| 6166 | return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{ | ||
| 6167 | @tagName(backend), @tagName(target.cpu.arch), | ||
| 6168 | }); | ||
| 6169 | } | ||
| 6170 | const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl); | ||
| 6171 | if (!func_ty.eql(func_decl.ty, sema.mod)) { | ||
| 6172 | return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ | ||
| 6173 | func_ty.fmt(sema.mod), func_decl.ty.fmt(sema.mod), | ||
| 6174 | }); | ||
| 6175 | } | ||
| 6176 | _ = try block.addUnOp(.ret, result); | ||
| 6177 | return Air.Inst.Ref.unreachable_value; | ||
| 6178 | } | ||
| 6179 | |||
| 6158 | fn analyzeInlineCallArg( | 6180 | fn analyzeInlineCallArg( |
| 6159 | sema: *Sema, | 6181 | sema: *Sema, |
| 6160 | arg_block: *Block, | 6182 | arg_block: *Block, |
| ... | @@ -6670,7 +6692,8 @@ fn instantiateGenericCall( | ... | @@ -6670,7 +6692,8 @@ fn instantiateGenericCall( |
| 6670 | try sema.requireFunctionBlock(block, call_src); | 6692 | try sema.requireFunctionBlock(block, call_src); |
| 6671 | 6693 | ||
| 6672 | const comptime_args = callee.comptime_args.?; | 6694 | const comptime_args = callee.comptime_args.?; |
| 6673 | const new_fn_info = mod.declPtr(callee.owner_decl).ty.fnInfo(); | 6695 | const func_ty = mod.declPtr(callee.owner_decl).ty; |
| 6696 | const new_fn_info = func_ty.fnInfo(); | ||
| 6674 | const runtime_args_len = @intCast(u32, new_fn_info.param_types.len); | 6697 | const runtime_args_len = @intCast(u32, new_fn_info.param_types.len); |
| 6675 | const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len); | 6698 | const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len); |
| 6676 | { | 6699 | { |
| ... | @@ -6717,7 +6740,7 @@ fn instantiateGenericCall( | ... | @@ -6717,7 +6740,7 @@ fn instantiateGenericCall( |
| 6717 | 6740 | ||
| 6718 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + | 6741 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 6719 | runtime_args_len); | 6742 | runtime_args_len); |
| 6720 | const func_inst = try block.addInst(.{ | 6743 | const result = try block.addInst(.{ |
| 6721 | .tag = call_tag, | 6744 | .tag = call_tag, |
| 6722 | .data = .{ .pl_op = .{ | 6745 | .data = .{ .pl_op = .{ |
| 6723 | .operand = callee_inst, | 6746 | .operand = callee_inst, |
| ... | @@ -6729,9 +6752,12 @@ fn instantiateGenericCall( | ... | @@ -6729,9 +6752,12 @@ fn instantiateGenericCall( |
| 6729 | sema.appendRefsAssumeCapacity(runtime_args); | 6752 | sema.appendRefsAssumeCapacity(runtime_args); |
| 6730 | 6753 | ||
| 6731 | if (ensure_result_used) { | 6754 | if (ensure_result_used) { |
| 6732 | try sema.ensureResultUsed(block, func_inst, call_src); | 6755 | try sema.ensureResultUsed(block, result, call_src); |
| 6733 | } | 6756 | } |
| 6734 | return func_inst; | 6757 | if (call_tag == .call_always_tail) { |
| 6758 | return sema.handleTailCall(block, call_src, func_ty, result); | ||
| 6759 | } | ||
| 6760 | return result; | ||
| 6735 | } | 6761 | } |
| 6736 | 6762 | ||
| 6737 | fn emitDbgInline( | 6763 | fn emitDbgInline( |
| ... | @@ -8177,8 +8203,22 @@ fn zirParam( | ... | @@ -8177,8 +8203,22 @@ fn zirParam( |
| 8177 | .is_comptime = comptime_syntax, | 8203 | .is_comptime = comptime_syntax, |
| 8178 | .name = param_name, | 8204 | .name = param_name, |
| 8179 | }); | 8205 | }); |
| 8180 | const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison)); | 8206 | |
| 8181 | try sema.inst_map.putNoClobber(sema.gpa, inst, result); | 8207 | if (is_comptime) { |
| 8208 | // If this is a comptime parameter we can add a constant generic_poison | ||
| 8209 | // since this is also a generic parameter. | ||
| 8210 | const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison)); | ||
| 8211 | try sema.inst_map.putNoClobber(sema.gpa, inst, result); | ||
| 8212 | } else { | ||
| 8213 | // Otherwise we need a dummy runtime instruction. | ||
| 8214 | const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len); | ||
| 8215 | try sema.air_instructions.append(sema.gpa, .{ | ||
| 8216 | .tag = .alloc, | ||
| 8217 | .data = .{ .ty = param_ty }, | ||
| 8218 | }); | ||
| 8219 | const result = Air.indexToRef(result_index); | ||
| 8220 | try sema.inst_map.putNoClobber(sema.gpa, inst, result); | ||
| 8221 | } | ||
| 8182 | } | 8222 | } |
| 8183 | 8223 | ||
| 8184 | fn zirParamAnytype( | 8224 | fn zirParamAnytype( |
| ... | @@ -8225,7 +8265,7 @@ fn zirAs(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst | ... | @@ -8225,7 +8265,7 @@ fn zirAs(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst |
| 8225 | defer tracy.end(); | 8265 | defer tracy.end(); |
| 8226 | 8266 | ||
| 8227 | const bin_inst = sema.code.instructions.items(.data)[inst].bin; | 8267 | const bin_inst = sema.code.instructions.items(.data)[inst].bin; |
| 8228 | return sema.analyzeAs(block, sema.src, bin_inst.lhs, bin_inst.rhs); | 8268 | return sema.analyzeAs(block, sema.src, bin_inst.lhs, bin_inst.rhs, false); |
| 8229 | } | 8269 | } |
| 8230 | 8270 | ||
| 8231 | fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 8271 | fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -8235,7 +8275,17 @@ fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -8235,7 +8275,17 @@ fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 8235 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 8275 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 8236 | const src = inst_data.src(); | 8276 | const src = inst_data.src(); |
| 8237 | const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data; | 8277 | const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data; |
| 8238 | return sema.analyzeAs(block, src, extra.dest_type, extra.operand); | 8278 | return sema.analyzeAs(block, src, extra.dest_type, extra.operand, false); |
| 8279 | } | ||
| 8280 | |||
| 8281 | fn zirAsShiftOperand(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | ||
| 8282 | const tracy = trace(@src()); | ||
| 8283 | defer tracy.end(); | ||
| 8284 | |||
| 8285 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 8286 | const src = inst_data.src(); | ||
| 8287 | const extra = sema.code.extraData(Zir.Inst.As, inst_data.payload_index).data; | ||
| 8288 | return sema.analyzeAs(block, src, extra.dest_type, extra.operand, true); | ||
| 8239 | } | 8289 | } |
| 8240 | 8290 | ||
| 8241 | fn analyzeAs( | 8291 | fn analyzeAs( |
| ... | @@ -8244,6 +8294,7 @@ fn analyzeAs( | ... | @@ -8244,6 +8294,7 @@ fn analyzeAs( |
| 8244 | src: LazySrcLoc, | 8294 | src: LazySrcLoc, |
| 8245 | zir_dest_type: Zir.Inst.Ref, | 8295 | zir_dest_type: Zir.Inst.Ref, |
| 8246 | zir_operand: Zir.Inst.Ref, | 8296 | zir_operand: Zir.Inst.Ref, |
| 8297 | no_cast_to_comptime_int: bool, | ||
| 8247 | ) CompileError!Air.Inst.Ref { | 8298 | ) CompileError!Air.Inst.Ref { |
| 8248 | const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index| | 8299 | const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index| |
| 8249 | sema.code.instructions.items(.tag)[ptr_index] == .ret_type | 8300 | sema.code.instructions.items(.tag)[ptr_index] == .ret_type |
| ... | @@ -8255,7 +8306,7 @@ fn analyzeAs( | ... | @@ -8255,7 +8306,7 @@ fn analyzeAs( |
| 8255 | if (dest_ty.zigTypeTag() == .NoReturn) { | 8306 | if (dest_ty.zigTypeTag() == .NoReturn) { |
| 8256 | return sema.fail(block, src, "cannot cast to noreturn", .{}); | 8307 | return sema.fail(block, src, "cannot cast to noreturn", .{}); |
| 8257 | } | 8308 | } |
| 8258 | return sema.coerceExtra(block, dest_ty, operand, src, true, is_ret) catch |err| switch (err) { | 8309 | return sema.coerceExtra(block, dest_ty, operand, src, .{ .is_ret = is_ret, .no_cast_to_comptime_int = no_cast_to_comptime_int }) catch |err| switch (err) { |
| 8259 | error.NotCoercible => unreachable, | 8310 | error.NotCoercible => unreachable, |
| 8260 | else => |e| return e, | 8311 | else => |e| return e, |
| 8261 | }; | 8312 | }; |
| ... | @@ -10459,7 +10510,12 @@ fn zirShl( | ... | @@ -10459,7 +10510,12 @@ fn zirShl( |
| 10459 | 10510 | ||
| 10460 | const runtime_src = if (maybe_lhs_val) |lhs_val| rs: { | 10511 | const runtime_src = if (maybe_lhs_val) |lhs_val| rs: { |
| 10461 | if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty); | 10512 | if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty); |
| 10462 | const rhs_val = maybe_rhs_val orelse break :rs rhs_src; | 10513 | const rhs_val = maybe_rhs_val orelse { |
| 10514 | if (scalar_ty.zigTypeTag() == .ComptimeInt) { | ||
| 10515 | return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be a comptime known", .{}); | ||
| 10516 | } | ||
| 10517 | break :rs rhs_src; | ||
| 10518 | }; | ||
| 10463 | 10519 | ||
| 10464 | const val = switch (air_tag) { | 10520 | const val = switch (air_tag) { |
| 10465 | .shl_exact => val: { | 10521 | .shl_exact => val: { |
| ... | @@ -10583,7 +10639,10 @@ fn zirShr( | ... | @@ -10583,7 +10639,10 @@ fn zirShr( |
| 10583 | const target = sema.mod.getTarget(); | 10639 | const target = sema.mod.getTarget(); |
| 10584 | const scalar_ty = lhs_ty.scalarType(); | 10640 | const scalar_ty = lhs_ty.scalarType(); |
| 10585 | 10641 | ||
| 10586 | const runtime_src = if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| rs: { | 10642 | const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs); |
| 10643 | const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs); | ||
| 10644 | |||
| 10645 | const runtime_src = if (maybe_rhs_val) |rhs_val| rs: { | ||
| 10587 | if (rhs_val.isUndef()) { | 10646 | if (rhs_val.isUndef()) { |
| 10588 | return sema.addConstUndef(lhs_ty); | 10647 | return sema.addConstUndef(lhs_ty); |
| 10589 | } | 10648 | } |
| ... | @@ -10615,7 +10674,7 @@ fn zirShr( | ... | @@ -10615,7 +10674,7 @@ fn zirShr( |
| 10615 | }); | 10674 | }); |
| 10616 | } | 10675 | } |
| 10617 | } | 10676 | } |
| 10618 | if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| { | 10677 | if (maybe_lhs_val) |lhs_val| { |
| 10619 | if (lhs_val.isUndef()) { | 10678 | if (lhs_val.isUndef()) { |
| 10620 | return sema.addConstUndef(lhs_ty); | 10679 | return sema.addConstUndef(lhs_ty); |
| 10621 | } | 10680 | } |
| ... | @@ -10633,6 +10692,10 @@ fn zirShr( | ... | @@ -10633,6 +10692,10 @@ fn zirShr( |
| 10633 | } | 10692 | } |
| 10634 | } else rhs_src; | 10693 | } else rhs_src; |
| 10635 | 10694 | ||
| 10695 | if (maybe_rhs_val == null and scalar_ty.zigTypeTag() == .ComptimeInt) { | ||
| 10696 | return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be a comptime known", .{}); | ||
| 10697 | } | ||
| 10698 | |||
| 10636 | try sema.requireRuntimeBlock(block, src, runtime_src); | 10699 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 10637 | const result = try block.addBinOp(air_tag, lhs, rhs); | 10700 | const result = try block.addBinOp(air_tag, lhs, rhs); |
| 10638 | if (block.wantSafety()) { | 10701 | if (block.wantSafety()) { |
| ... | @@ -15353,7 +15416,7 @@ fn analyzeRet( | ... | @@ -15353,7 +15416,7 @@ fn analyzeRet( |
| 15353 | if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { | 15416 | if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { |
| 15354 | try sema.addToInferredErrorSet(uncasted_operand); | 15417 | try sema.addToInferredErrorSet(uncasted_operand); |
| 15355 | } | 15418 | } |
| 15356 | const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, true, true) catch |err| switch (err) { | 15419 | const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, .{ .is_ret = true }) catch |err| switch (err) { |
| 15357 | error.NotCoercible => unreachable, | 15420 | error.NotCoercible => unreachable, |
| 15358 | else => |e| return e, | 15421 | else => |e| return e, |
| 15359 | }; | 15422 | }; |
| ... | @@ -19262,7 +19325,7 @@ fn resolveCallOptions( | ... | @@ -19262,7 +19325,7 @@ fn resolveCallOptions( |
| 19262 | return wanted_modifier; | 19325 | return wanted_modifier; |
| 19263 | }, | 19326 | }, |
| 19264 | // These can be upgraded to comptime. nosuspend bit can be safely ignored. | 19327 | // These can be upgraded to comptime. nosuspend bit can be safely ignored. |
| 19265 | .always_tail, .always_inline, .compile_time => { | 19328 | .always_inline, .compile_time => { |
| 19266 | _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse { | 19329 | _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse { |
| 19267 | return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(wanted_modifier)}); | 19330 | return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(wanted_modifier)}); |
| 19268 | }; | 19331 | }; |
| ... | @@ -19272,6 +19335,12 @@ fn resolveCallOptions( | ... | @@ -19272,6 +19335,12 @@ fn resolveCallOptions( |
| 19272 | } | 19335 | } |
| 19273 | return wanted_modifier; | 19336 | return wanted_modifier; |
| 19274 | }, | 19337 | }, |
| 19338 | .always_tail => { | ||
| 19339 | if (is_comptime) { | ||
| 19340 | return .compile_time; | ||
| 19341 | } | ||
| 19342 | return wanted_modifier; | ||
| 19343 | }, | ||
| 19275 | .async_kw => { | 19344 | .async_kw => { |
| 19276 | if (is_nosuspend) { | 19345 | if (is_nosuspend) { |
| 19277 | return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{}); | 19346 | return sema.fail(block, modifier_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{}); |
| ... | @@ -19614,9 +19683,9 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -19614,9 +19683,9 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 19614 | }); | 19683 | }); |
| 19615 | } | 19684 | } |
| 19616 | 19685 | ||
| 19617 | fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 19686 | fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 19618 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 19687 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 19619 | const src = inst_data.src(); | 19688 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 19620 | return sema.failWithUseOfAsync(block, src); | 19689 | return sema.failWithUseOfAsync(block, src); |
| 19621 | } | 19690 | } |
| 19622 | 19691 | ||
| ... | @@ -21871,6 +21940,7 @@ fn unionFieldPtr( | ... | @@ -21871,6 +21940,7 @@ fn unionFieldPtr( |
| 21871 | .mutable = union_ptr_ty.ptrIsMutable(), | 21940 | .mutable = union_ptr_ty.ptrIsMutable(), |
| 21872 | .@"addrspace" = union_ptr_ty.ptrAddressSpace(), | 21941 | .@"addrspace" = union_ptr_ty.ptrAddressSpace(), |
| 21873 | }); | 21942 | }); |
| 21943 | const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?); | ||
| 21874 | 21944 | ||
| 21875 | if (initializing and field.ty.zigTypeTag() == .NoReturn) { | 21945 | if (initializing and field.ty.zigTypeTag() == .NoReturn) { |
| 21876 | const msg = msg: { | 21946 | const msg = msg: { |
| ... | @@ -21892,11 +21962,10 @@ fn unionFieldPtr( | ... | @@ -21892,11 +21962,10 @@ fn unionFieldPtr( |
| 21892 | if (union_val.isUndef()) { | 21962 | if (union_val.isUndef()) { |
| 21893 | return sema.failWithUseOfUndef(block, src); | 21963 | return sema.failWithUseOfUndef(block, src); |
| 21894 | } | 21964 | } |
| 21895 | const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?; | ||
| 21896 | const tag_and_val = union_val.castTag(.@"union").?.data; | 21965 | const tag_and_val = union_val.castTag(.@"union").?.data; |
| 21897 | var field_tag_buf: Value.Payload.U32 = .{ | 21966 | var field_tag_buf: Value.Payload.U32 = .{ |
| 21898 | .base = .{ .tag = .enum_field_index }, | 21967 | .base = .{ .tag = .enum_field_index }, |
| 21899 | .data = @intCast(u32, enum_field_index), | 21968 | .data = enum_field_index, |
| 21900 | }; | 21969 | }; |
| 21901 | const field_tag = Value.initPayload(&field_tag_buf.base); | 21970 | const field_tag = Value.initPayload(&field_tag_buf.base); |
| 21902 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); | 21971 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); |
| ... | @@ -21928,7 +21997,7 @@ fn unionFieldPtr( | ... | @@ -21928,7 +21997,7 @@ fn unionFieldPtr( |
| 21928 | if (!initializing and union_obj.layout == .Auto and block.wantSafety() and | 21997 | if (!initializing and union_obj.layout == .Auto and block.wantSafety() and |
| 21929 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) | 21998 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) |
| 21930 | { | 21999 | { |
| 21931 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); | 22000 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); |
| 21932 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); | 22001 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); |
| 21933 | // TODO would it be better if get_union_tag supported pointers to unions? | 22002 | // TODO would it be better if get_union_tag supported pointers to unions? |
| 21934 | const union_val = try block.addTyOp(.load, union_ty, union_ptr); | 22003 | const union_val = try block.addTyOp(.load, union_ty, union_ptr); |
| ... | @@ -21958,15 +22027,15 @@ fn unionFieldVal( | ... | @@ -21958,15 +22027,15 @@ fn unionFieldVal( |
| 21958 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 22027 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; |
| 21959 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); | 22028 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 21960 | const field = union_obj.fields.values()[field_index]; | 22029 | const field = union_obj.fields.values()[field_index]; |
| 22030 | const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?); | ||
| 21961 | 22031 | ||
| 21962 | if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| { | 22032 | if (try sema.resolveMaybeUndefVal(block, src, union_byval)) |union_val| { |
| 21963 | if (union_val.isUndef()) return sema.addConstUndef(field.ty); | 22033 | if (union_val.isUndef()) return sema.addConstUndef(field.ty); |
| 21964 | 22034 | ||
| 21965 | const tag_and_val = union_val.castTag(.@"union").?.data; | 22035 | const tag_and_val = union_val.castTag(.@"union").?.data; |
| 21966 | const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?; | ||
| 21967 | var field_tag_buf: Value.Payload.U32 = .{ | 22036 | var field_tag_buf: Value.Payload.U32 = .{ |
| 21968 | .base = .{ .tag = .enum_field_index }, | 22037 | .base = .{ .tag = .enum_field_index }, |
| 21969 | .data = @intCast(u32, enum_field_index), | 22038 | .data = enum_field_index, |
| 21970 | }; | 22039 | }; |
| 21971 | const field_tag = Value.initPayload(&field_tag_buf.base); | 22040 | const field_tag = Value.initPayload(&field_tag_buf.base); |
| 21972 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); | 22041 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); |
| ... | @@ -22002,7 +22071,7 @@ fn unionFieldVal( | ... | @@ -22002,7 +22071,7 @@ fn unionFieldVal( |
| 22002 | if (union_obj.layout == .Auto and block.wantSafety() and | 22071 | if (union_obj.layout == .Auto and block.wantSafety() and |
| 22003 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) | 22072 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) |
| 22004 | { | 22073 | { |
| 22005 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); | 22074 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); |
| 22006 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); | 22075 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); |
| 22007 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval); | 22076 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval); |
| 22008 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); | 22077 | const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag); |
| ... | @@ -22504,7 +22573,7 @@ fn coerce( | ... | @@ -22504,7 +22573,7 @@ fn coerce( |
| 22504 | inst: Air.Inst.Ref, | 22573 | inst: Air.Inst.Ref, |
| 22505 | inst_src: LazySrcLoc, | 22574 | inst_src: LazySrcLoc, |
| 22506 | ) CompileError!Air.Inst.Ref { | 22575 | ) CompileError!Air.Inst.Ref { |
| 22507 | return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, true, false) catch |err| switch (err) { | 22576 | return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, .{}) catch |err| switch (err) { |
| 22508 | error.NotCoercible => unreachable, | 22577 | error.NotCoercible => unreachable, |
| 22509 | else => |e| return e, | 22578 | else => |e| return e, |
| 22510 | }; | 22579 | }; |
| ... | @@ -22516,14 +22585,22 @@ const CoersionError = CompileError || error{ | ... | @@ -22516,14 +22585,22 @@ const CoersionError = CompileError || error{ |
| 22516 | NotCoercible, | 22585 | NotCoercible, |
| 22517 | }; | 22586 | }; |
| 22518 | 22587 | ||
| 22588 | const CoerceOpts = struct { | ||
| 22589 | /// Should coerceExtra emit error messages. | ||
| 22590 | report_err: bool = true, | ||
| 22591 | /// Ignored if `report_err == false`. | ||
| 22592 | is_ret: bool = false, | ||
| 22593 | /// Should coercion to comptime_int ermit an error message. | ||
| 22594 | no_cast_to_comptime_int: bool = false, | ||
| 22595 | }; | ||
| 22596 | |||
| 22519 | fn coerceExtra( | 22597 | fn coerceExtra( |
| 22520 | sema: *Sema, | 22598 | sema: *Sema, |
| 22521 | block: *Block, | 22599 | block: *Block, |
| 22522 | dest_ty_unresolved: Type, | 22600 | dest_ty_unresolved: Type, |
| 22523 | inst: Air.Inst.Ref, | 22601 | inst: Air.Inst.Ref, |
| 22524 | inst_src: LazySrcLoc, | 22602 | inst_src: LazySrcLoc, |
| 22525 | report_err: bool, | 22603 | opts: CoerceOpts, |
| 22526 | is_ret: bool, | ||
| 22527 | ) CoersionError!Air.Inst.Ref { | 22604 | ) CoersionError!Air.Inst.Ref { |
| 22528 | switch (dest_ty_unresolved.tag()) { | 22605 | switch (dest_ty_unresolved.tag()) { |
| 22529 | .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src), | 22606 | .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src), |
| ... | @@ -22575,7 +22652,7 @@ fn coerceExtra( | ... | @@ -22575,7 +22652,7 @@ fn coerceExtra( |
| 22575 | 22652 | ||
| 22576 | // T to ?T | 22653 | // T to ?T |
| 22577 | const child_type = try dest_ty.optionalChildAlloc(sema.arena); | 22654 | const child_type = try dest_ty.optionalChildAlloc(sema.arena); |
| 22578 | const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, false, is_ret) catch |err| switch (err) { | 22655 | const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { |
| 22579 | error.NotCoercible => { | 22656 | error.NotCoercible => { |
| 22580 | if (in_memory_result == .no_match) { | 22657 | if (in_memory_result == .no_match) { |
| 22581 | // Try to give more useful notes | 22658 | // Try to give more useful notes |
| ... | @@ -22691,7 +22768,7 @@ fn coerceExtra( | ... | @@ -22691,7 +22768,7 @@ fn coerceExtra( |
| 22691 | return sema.addConstant(dest_ty, Value.@"null"); | 22768 | return sema.addConstant(dest_ty, Value.@"null"); |
| 22692 | }, | 22769 | }, |
| 22693 | .ComptimeInt => { | 22770 | .ComptimeInt => { |
| 22694 | const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, false, is_ret) catch |err| switch (err) { | 22771 | const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { |
| 22695 | error.NotCoercible => break :pointer, | 22772 | error.NotCoercible => break :pointer, |
| 22696 | else => |e| return e, | 22773 | else => |e| return e, |
| 22697 | }; | 22774 | }; |
| ... | @@ -22702,7 +22779,7 @@ fn coerceExtra( | ... | @@ -22702,7 +22779,7 @@ fn coerceExtra( |
| 22702 | .signed => Type.isize, | 22779 | .signed => Type.isize, |
| 22703 | .unsigned => Type.usize, | 22780 | .unsigned => Type.usize, |
| 22704 | }; | 22781 | }; |
| 22705 | const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, false, is_ret) catch |err| switch (err) { | 22782 | const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { |
| 22706 | error.NotCoercible => { | 22783 | error.NotCoercible => { |
| 22707 | // Try to give more useful notes | 22784 | // Try to give more useful notes |
| 22708 | in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src); | 22785 | in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src); |
| ... | @@ -22828,7 +22905,13 @@ fn coerceExtra( | ... | @@ -22828,7 +22905,13 @@ fn coerceExtra( |
| 22828 | }, | 22905 | }, |
| 22829 | .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) { | 22906 | .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) { |
| 22830 | .Float, .ComptimeFloat => float: { | 22907 | .Float, .ComptimeFloat => float: { |
| 22831 | const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :float; | 22908 | const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse { |
| 22909 | if (dest_ty.zigTypeTag() == .ComptimeInt) { | ||
| 22910 | if (!opts.report_err) return error.NotCoercible; | ||
| 22911 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime known"); | ||
| 22912 | } | ||
| 22913 | break :float; | ||
| 22914 | }; | ||
| 22832 | 22915 | ||
| 22833 | if (val.floatHasFraction()) { | 22916 | if (val.floatHasFraction()) { |
| 22834 | return sema.fail( | 22917 | return sema.fail( |
| ... | @@ -22845,11 +22928,16 @@ fn coerceExtra( | ... | @@ -22845,11 +22928,16 @@ fn coerceExtra( |
| 22845 | if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { | 22928 | if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { |
| 22846 | // comptime known integer to other number | 22929 | // comptime known integer to other number |
| 22847 | if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) { | 22930 | if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) { |
| 22848 | if (!report_err) return error.NotCoercible; | 22931 | if (!opts.report_err) return error.NotCoercible; |
| 22849 | return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }); | 22932 | return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }); |
| 22850 | } | 22933 | } |
| 22851 | return try sema.addConstant(dest_ty, val); | 22934 | return try sema.addConstant(dest_ty, val); |
| 22852 | } | 22935 | } |
| 22936 | if (dest_ty.zigTypeTag() == .ComptimeInt) { | ||
| 22937 | if (!opts.report_err) return error.NotCoercible; | ||
| 22938 | if (opts.no_cast_to_comptime_int) return inst; | ||
| 22939 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime known"); | ||
| 22940 | } | ||
| 22853 | 22941 | ||
| 22854 | // integer widening | 22942 | // integer widening |
| 22855 | const dst_info = dest_ty.intInfo(target); | 22943 | const dst_info = dest_ty.intInfo(target); |
| ... | @@ -22886,6 +22974,7 @@ fn coerceExtra( | ... | @@ -22886,6 +22974,7 @@ fn coerceExtra( |
| 22886 | } | 22974 | } |
| 22887 | return try sema.addConstant(dest_ty, result_val); | 22975 | return try sema.addConstant(dest_ty, result_val); |
| 22888 | } else if (dest_ty.zigTypeTag() == .ComptimeFloat) { | 22976 | } else if (dest_ty.zigTypeTag() == .ComptimeFloat) { |
| 22977 | if (!opts.report_err) return error.NotCoercible; | ||
| 22889 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime known"); | 22978 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime known"); |
| 22890 | } | 22979 | } |
| 22891 | 22980 | ||
| ... | @@ -22898,7 +22987,13 @@ fn coerceExtra( | ... | @@ -22898,7 +22987,13 @@ fn coerceExtra( |
| 22898 | } | 22987 | } |
| 22899 | }, | 22988 | }, |
| 22900 | .Int, .ComptimeInt => int: { | 22989 | .Int, .ComptimeInt => int: { |
| 22901 | const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :int; | 22990 | const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse { |
| 22991 | if (dest_ty.zigTypeTag() == .ComptimeFloat) { | ||
| 22992 | if (!opts.report_err) return error.NotCoercible; | ||
| 22993 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime known"); | ||
| 22994 | } | ||
| 22995 | break :int; | ||
| 22996 | }; | ||
| 22902 | const result_val = try val.intToFloat(sema.arena, inst_ty, dest_ty, target); | 22997 | const result_val = try val.intToFloat(sema.arena, inst_ty, dest_ty, target); |
| 22903 | // TODO implement this compile error | 22998 | // TODO implement this compile error |
| 22904 | //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); | 22999 | //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); |
| ... | @@ -23050,9 +23145,9 @@ fn coerceExtra( | ... | @@ -23050,9 +23145,9 @@ fn coerceExtra( |
| 23050 | return sema.addConstUndef(dest_ty); | 23145 | return sema.addConstUndef(dest_ty); |
| 23051 | } | 23146 | } |
| 23052 | 23147 | ||
| 23053 | if (!report_err) return error.NotCoercible; | 23148 | if (!opts.report_err) return error.NotCoercible; |
| 23054 | 23149 | ||
| 23055 | if (is_ret and dest_ty.zigTypeTag() == .NoReturn) { | 23150 | if (opts.is_ret and dest_ty.zigTypeTag() == .NoReturn) { |
| 23056 | const msg = msg: { | 23151 | const msg = msg: { |
| 23057 | const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{}); | 23152 | const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{}); |
| 23058 | errdefer msg.destroy(sema.gpa); | 23153 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -23089,7 +23184,7 @@ fn coerceExtra( | ... | @@ -23089,7 +23184,7 @@ fn coerceExtra( |
| 23089 | try in_memory_result.report(sema, block, inst_src, msg); | 23184 | try in_memory_result.report(sema, block, inst_src, msg); |
| 23090 | 23185 | ||
| 23091 | // Add notes about function return type | 23186 | // Add notes about function return type |
| 23092 | if (is_ret and sema.mod.test_functions.get(sema.func.?.owner_decl) == null) { | 23187 | if (opts.is_ret and sema.mod.test_functions.get(sema.func.?.owner_decl) == null) { |
| 23093 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; | 23188 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 23094 | const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); | 23189 | const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); |
| 23095 | if (inst_ty.isError() and !dest_ty.isError()) { | 23190 | if (inst_ty.isError() and !dest_ty.isError()) { |
| ... | @@ -24050,7 +24145,7 @@ fn storePtr2( | ... | @@ -24050,7 +24145,7 @@ fn storePtr2( |
| 24050 | // https://github.com/ziglang/zig/issues/11154 | 24145 | // https://github.com/ziglang/zig/issues/11154 |
| 24051 | if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { | 24146 | if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { |
| 24052 | const vector_ty = sema.typeOf(vector_ptr).childType(); | 24147 | const vector_ty = sema.typeOf(vector_ptr).childType(); |
| 24053 | const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, true, is_ret) catch |err| switch (err) { | 24148 | const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { |
| 24054 | error.NotCoercible => unreachable, | 24149 | error.NotCoercible => unreachable, |
| 24055 | else => |e| return e, | 24150 | else => |e| return e, |
| 24056 | }; | 24151 | }; |
| ... | @@ -24058,7 +24153,7 @@ fn storePtr2( | ... | @@ -24058,7 +24153,7 @@ fn storePtr2( |
| 24058 | return; | 24153 | return; |
| 24059 | } | 24154 | } |
| 24060 | 24155 | ||
| 24061 | const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, true, is_ret) catch |err| switch (err) { | 24156 | const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { |
| 24062 | error.NotCoercible => unreachable, | 24157 | error.NotCoercible => unreachable, |
| 24063 | else => |e| return e, | 24158 | else => |e| return e, |
| 24064 | }; | 24159 | }; |
| ... | @@ -26793,7 +26888,7 @@ fn wrapErrorUnionPayload( | ... | @@ -26793,7 +26888,7 @@ fn wrapErrorUnionPayload( |
| 26793 | inst_src: LazySrcLoc, | 26888 | inst_src: LazySrcLoc, |
| 26794 | ) !Air.Inst.Ref { | 26889 | ) !Air.Inst.Ref { |
| 26795 | const dest_payload_ty = dest_ty.errorUnionPayload(); | 26890 | const dest_payload_ty = dest_ty.errorUnionPayload(); |
| 26796 | const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, false, false); | 26891 | const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false }); |
| 26797 | if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| { | 26892 | if (try sema.resolveMaybeUndefVal(block, inst_src, coerced)) |val| { |
| 26798 | return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val)); | 26893 | return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val)); |
| 26799 | } | 26894 | } |
src/Zir.zig+9-6| ... | @@ -242,6 +242,8 @@ pub const Inst = struct { | ... | @@ -242,6 +242,8 @@ pub const Inst = struct { |
| 242 | /// Type coercion to the function's return type. | 242 | /// Type coercion to the function's return type. |
| 243 | /// Uses the `pl_node` field. Payload is `As`. AST node could be many things. | 243 | /// Uses the `pl_node` field. Payload is `As`. AST node could be many things. |
| 244 | as_node, | 244 | as_node, |
| 245 | /// Same as `as_node` but ignores runtime to comptime int error. | ||
| 246 | as_shift_operand, | ||
| 245 | /// Bitwise AND. `&` | 247 | /// Bitwise AND. `&` |
| 246 | bit_and, | 248 | bit_and, |
| 247 | /// Reinterpret the memory representation of a value as a different type. | 249 | /// Reinterpret the memory representation of a value as a different type. |
| ... | @@ -942,9 +944,6 @@ pub const Inst = struct { | ... | @@ -942,9 +944,6 @@ pub const Inst = struct { |
| 942 | /// Implements the `@maximum` builtin. | 944 | /// Implements the `@maximum` builtin. |
| 943 | /// Uses the `pl_node` union field with payload `Bin` | 945 | /// Uses the `pl_node` union field with payload `Bin` |
| 944 | maximum, | 946 | maximum, |
| 945 | /// Implements the `@asyncCall` builtin. | ||
| 946 | /// Uses the `pl_node` union field with payload `AsyncCall`. | ||
| 947 | builtin_async_call, | ||
| 948 | /// Implements the `@cImport` builtin. | 947 | /// Implements the `@cImport` builtin. |
| 949 | /// Uses the `pl_node` union field with payload `Block`. | 948 | /// Uses the `pl_node` union field with payload `Block`. |
| 950 | c_import, | 949 | c_import, |
| ... | @@ -1029,6 +1028,7 @@ pub const Inst = struct { | ... | @@ -1029,6 +1028,7 @@ pub const Inst = struct { |
| 1029 | .anyframe_type, | 1028 | .anyframe_type, |
| 1030 | .as, | 1029 | .as, |
| 1031 | .as_node, | 1030 | .as_node, |
| 1031 | .as_shift_operand, | ||
| 1032 | .bit_and, | 1032 | .bit_and, |
| 1033 | .bitcast, | 1033 | .bitcast, |
| 1034 | .bit_or, | 1034 | .bit_or, |
| ... | @@ -1231,7 +1231,6 @@ pub const Inst = struct { | ... | @@ -1231,7 +1231,6 @@ pub const Inst = struct { |
| 1231 | .memcpy, | 1231 | .memcpy, |
| 1232 | .memset, | 1232 | .memset, |
| 1233 | .minimum, | 1233 | .minimum, |
| 1234 | .builtin_async_call, | ||
| 1235 | .c_import, | 1234 | .c_import, |
| 1236 | .@"resume", | 1235 | .@"resume", |
| 1237 | .@"await", | 1236 | .@"await", |
| ... | @@ -1339,6 +1338,7 @@ pub const Inst = struct { | ... | @@ -1339,6 +1338,7 @@ pub const Inst = struct { |
| 1339 | .anyframe_type, | 1338 | .anyframe_type, |
| 1340 | .as, | 1339 | .as, |
| 1341 | .as_node, | 1340 | .as_node, |
| 1341 | .as_shift_operand, | ||
| 1342 | .bit_and, | 1342 | .bit_and, |
| 1343 | .bitcast, | 1343 | .bitcast, |
| 1344 | .bit_or, | 1344 | .bit_or, |
| ... | @@ -1513,7 +1513,6 @@ pub const Inst = struct { | ... | @@ -1513,7 +1513,6 @@ pub const Inst = struct { |
| 1513 | .field_parent_ptr, | 1513 | .field_parent_ptr, |
| 1514 | .maximum, | 1514 | .maximum, |
| 1515 | .minimum, | 1515 | .minimum, |
| 1516 | .builtin_async_call, | ||
| 1517 | .c_import, | 1516 | .c_import, |
| 1518 | .@"resume", | 1517 | .@"resume", |
| 1519 | .@"await", | 1518 | .@"await", |
| ... | @@ -1577,6 +1576,7 @@ pub const Inst = struct { | ... | @@ -1577,6 +1576,7 @@ pub const Inst = struct { |
| 1577 | .anyframe_type = .un_node, | 1576 | .anyframe_type = .un_node, |
| 1578 | .as = .bin, | 1577 | .as = .bin, |
| 1579 | .as_node = .pl_node, | 1578 | .as_node = .pl_node, |
| 1579 | .as_shift_operand = .pl_node, | ||
| 1580 | .bit_and = .pl_node, | 1580 | .bit_and = .pl_node, |
| 1581 | .bitcast = .pl_node, | 1581 | .bitcast = .pl_node, |
| 1582 | .bit_not = .un_node, | 1582 | .bit_not = .un_node, |
| ... | @@ -1801,7 +1801,6 @@ pub const Inst = struct { | ... | @@ -1801,7 +1801,6 @@ pub const Inst = struct { |
| 1801 | .memcpy = .pl_node, | 1801 | .memcpy = .pl_node, |
| 1802 | .memset = .pl_node, | 1802 | .memset = .pl_node, |
| 1803 | .minimum = .pl_node, | 1803 | .minimum = .pl_node, |
| 1804 | .builtin_async_call = .pl_node, | ||
| 1805 | .c_import = .pl_node, | 1804 | .c_import = .pl_node, |
| 1806 | 1805 | ||
| 1807 | .alloc = .un_node, | 1806 | .alloc = .un_node, |
| ... | @@ -1972,6 +1971,9 @@ pub const Inst = struct { | ... | @@ -1972,6 +1971,9 @@ pub const Inst = struct { |
| 1972 | /// `operand` is payload index to `UnNode`. | 1971 | /// `operand` is payload index to `UnNode`. |
| 1973 | /// `small` contains `NameStrategy | 1972 | /// `small` contains `NameStrategy |
| 1974 | reify, | 1973 | reify, |
| 1974 | /// Implements the `@asyncCall` builtin. | ||
| 1975 | /// `operand` is payload index to `AsyncCall`. | ||
| 1976 | builtin_async_call, | ||
| 1975 | 1977 | ||
| 1976 | pub const InstData = struct { | 1978 | pub const InstData = struct { |
| 1977 | opcode: Extended, | 1979 | opcode: Extended, |
| ... | @@ -3454,6 +3456,7 @@ pub const Inst = struct { | ... | @@ -3454,6 +3456,7 @@ pub const Inst = struct { |
| 3454 | }; | 3456 | }; |
| 3455 | 3457 | ||
| 3456 | pub const AsyncCall = struct { | 3458 | pub const AsyncCall = struct { |
| 3459 | node: i32, | ||
| 3457 | frame_buffer: Ref, | 3460 | frame_buffer: Ref, |
| 3458 | result_ptr: Ref, | 3461 | result_ptr: Ref, |
| 3459 | fn_ptr: Ref, | 3462 | fn_ptr: Ref, |
src/codegen/llvm.zig+127-4| ... | @@ -177,6 +177,116 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 { | ... | @@ -177,6 +177,116 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 { |
| 177 | return llvm_triple.toOwnedSliceSentinel(0); | 177 | return llvm_triple.toOwnedSliceSentinel(0); |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | pub fn targetOs(os_tag: std.Target.Os.Tag) llvm.OSType { | ||
| 181 | return switch (os_tag) { | ||
| 182 | .freestanding, .other, .opencl, .glsl450, .vulkan, .plan9 => .UnknownOS, | ||
| 183 | .windows, .uefi => .Win32, | ||
| 184 | .ananas => .Ananas, | ||
| 185 | .cloudabi => .CloudABI, | ||
| 186 | .dragonfly => .DragonFly, | ||
| 187 | .freebsd => .FreeBSD, | ||
| 188 | .fuchsia => .Fuchsia, | ||
| 189 | .ios => .IOS, | ||
| 190 | .kfreebsd => .KFreeBSD, | ||
| 191 | .linux => .Linux, | ||
| 192 | .lv2 => .Lv2, | ||
| 193 | .macos => .MacOSX, | ||
| 194 | .netbsd => .NetBSD, | ||
| 195 | .openbsd => .OpenBSD, | ||
| 196 | .solaris => .Solaris, | ||
| 197 | .zos => .ZOS, | ||
| 198 | .haiku => .Haiku, | ||
| 199 | .minix => .Minix, | ||
| 200 | .rtems => .RTEMS, | ||
| 201 | .nacl => .NaCl, | ||
| 202 | .aix => .AIX, | ||
| 203 | .cuda => .CUDA, | ||
| 204 | .nvcl => .NVCL, | ||
| 205 | .amdhsa => .AMDHSA, | ||
| 206 | .ps4 => .PS4, | ||
| 207 | .elfiamcu => .ELFIAMCU, | ||
| 208 | .tvos => .TvOS, | ||
| 209 | .watchos => .WatchOS, | ||
| 210 | .mesa3d => .Mesa3D, | ||
| 211 | .contiki => .Contiki, | ||
| 212 | .amdpal => .AMDPAL, | ||
| 213 | .hermit => .HermitCore, | ||
| 214 | .hurd => .Hurd, | ||
| 215 | .wasi => .WASI, | ||
| 216 | .emscripten => .Emscripten, | ||
| 217 | }; | ||
| 218 | } | ||
| 219 | |||
| 220 | pub fn targetArch(arch_tag: std.Target.Cpu.Arch) llvm.ArchType { | ||
| 221 | return switch (arch_tag) { | ||
| 222 | .arm => .arm, | ||
| 223 | .armeb => .armeb, | ||
| 224 | .aarch64 => .aarch64, | ||
| 225 | .aarch64_be => .aarch64_be, | ||
| 226 | .aarch64_32 => .aarch64_32, | ||
| 227 | .arc => .arc, | ||
| 228 | .avr => .avr, | ||
| 229 | .bpfel => .bpfel, | ||
| 230 | .bpfeb => .bpfeb, | ||
| 231 | .csky => .csky, | ||
| 232 | .hexagon => .hexagon, | ||
| 233 | .m68k => .m68k, | ||
| 234 | .mips => .mips, | ||
| 235 | .mipsel => .mipsel, | ||
| 236 | .mips64 => .mips64, | ||
| 237 | .mips64el => .mips64el, | ||
| 238 | .msp430 => .msp430, | ||
| 239 | .powerpc => .ppc, | ||
| 240 | .powerpcle => .ppcle, | ||
| 241 | .powerpc64 => .ppc64, | ||
| 242 | .powerpc64le => .ppc64le, | ||
| 243 | .r600 => .r600, | ||
| 244 | .amdgcn => .amdgcn, | ||
| 245 | .riscv32 => .riscv32, | ||
| 246 | .riscv64 => .riscv64, | ||
| 247 | .sparc => .sparc, | ||
| 248 | .sparc64 => .sparcv9, // In LLVM, sparc64 == sparcv9. | ||
| 249 | .sparcel => .sparcel, | ||
| 250 | .s390x => .systemz, | ||
| 251 | .tce => .tce, | ||
| 252 | .tcele => .tcele, | ||
| 253 | .thumb => .thumb, | ||
| 254 | .thumbeb => .thumbeb, | ||
| 255 | .i386 => .x86, | ||
| 256 | .x86_64 => .x86_64, | ||
| 257 | .xcore => .xcore, | ||
| 258 | .nvptx => .nvptx, | ||
| 259 | .nvptx64 => .nvptx64, | ||
| 260 | .le32 => .le32, | ||
| 261 | .le64 => .le64, | ||
| 262 | .amdil => .amdil, | ||
| 263 | .amdil64 => .amdil64, | ||
| 264 | .hsail => .hsail, | ||
| 265 | .hsail64 => .hsail64, | ||
| 266 | .spir => .spir, | ||
| 267 | .spir64 => .spir64, | ||
| 268 | .kalimba => .kalimba, | ||
| 269 | .shave => .shave, | ||
| 270 | .lanai => .lanai, | ||
| 271 | .wasm32 => .wasm32, | ||
| 272 | .wasm64 => .wasm64, | ||
| 273 | .renderscript32 => .renderscript32, | ||
| 274 | .renderscript64 => .renderscript64, | ||
| 275 | .ve => .ve, | ||
| 276 | .spu_2, .spirv32, .spirv64 => .UnknownArch, | ||
| 277 | }; | ||
| 278 | } | ||
| 279 | |||
| 280 | pub fn supportsTailCall(target: std.Target) bool { | ||
| 281 | switch (target.cpu.arch) { | ||
| 282 | .wasm32, .wasm64 => return std.Target.wasm.featureSetHas(target.cpu.features, .tail_call), | ||
| 283 | // Although these ISAs support tail calls, LLVM does not support tail calls on them. | ||
| 284 | .mips, .mipsel, .mips64, .mips64el => return false, | ||
| 285 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => return false, | ||
| 286 | else => return true, | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 180 | pub const Object = struct { | 290 | pub const Object = struct { |
| 181 | gpa: Allocator, | 291 | gpa: Allocator, |
| 182 | module: *Module, | 292 | module: *Module, |
| ... | @@ -4522,7 +4632,7 @@ pub const FuncGen = struct { | ... | @@ -4522,7 +4632,7 @@ pub const FuncGen = struct { |
| 4522 | "", | 4632 | "", |
| 4523 | ); | 4633 | ); |
| 4524 | 4634 | ||
| 4525 | if (return_type.isNoReturn()) { | 4635 | if (return_type.isNoReturn() and attr != .AlwaysTail) { |
| 4526 | _ = self.builder.buildUnreachable(); | 4636 | _ = self.builder.buildUnreachable(); |
| 4527 | return null; | 4637 | return null; |
| 4528 | } | 4638 | } |
| ... | @@ -8527,12 +8637,26 @@ pub const FuncGen = struct { | ... | @@ -8527,12 +8637,26 @@ pub const FuncGen = struct { |
| 8527 | const union_llvm_ty = try self.dg.lowerType(union_ty); | 8637 | const union_llvm_ty = try self.dg.lowerType(union_ty); |
| 8528 | const target = self.dg.module.getTarget(); | 8638 | const target = self.dg.module.getTarget(); |
| 8529 | const layout = union_ty.unionGetLayout(target); | 8639 | const layout = union_ty.unionGetLayout(target); |
| 8640 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | ||
| 8641 | const tag_int = blk: { | ||
| 8642 | const tag_ty = union_ty.unionTagTypeHypothetical(); | ||
| 8643 | const union_field_name = union_obj.fields.keys()[extra.field_index]; | ||
| 8644 | const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?; | ||
| 8645 | var tag_val_payload: Value.Payload.U32 = .{ | ||
| 8646 | .base = .{ .tag = .enum_field_index }, | ||
| 8647 | .data = @intCast(u32, enum_field_index), | ||
| 8648 | }; | ||
| 8649 | const tag_val = Value.initPayload(&tag_val_payload.base); | ||
| 8650 | var int_payload: Value.Payload.U64 = undefined; | ||
| 8651 | const tag_int_val = tag_val.enumToInt(tag_ty, &int_payload); | ||
| 8652 | break :blk tag_int_val.toUnsignedInt(target); | ||
| 8653 | }; | ||
| 8530 | if (layout.payload_size == 0) { | 8654 | if (layout.payload_size == 0) { |
| 8531 | if (layout.tag_size == 0) { | 8655 | if (layout.tag_size == 0) { |
| 8532 | return null; | 8656 | return null; |
| 8533 | } | 8657 | } |
| 8534 | assert(!isByRef(union_ty)); | 8658 | assert(!isByRef(union_ty)); |
| 8535 | return union_llvm_ty.constInt(extra.field_index, .False); | 8659 | return union_llvm_ty.constInt(tag_int, .False); |
| 8536 | } | 8660 | } |
| 8537 | assert(isByRef(union_ty)); | 8661 | assert(isByRef(union_ty)); |
| 8538 | // The llvm type of the alloca will the the named LLVM union type, which will not | 8662 | // The llvm type of the alloca will the the named LLVM union type, which will not |
| ... | @@ -8541,7 +8665,6 @@ pub const FuncGen = struct { | ... | @@ -8541,7 +8665,6 @@ pub const FuncGen = struct { |
| 8541 | // then set the fields appropriately. | 8665 | // then set the fields appropriately. |
| 8542 | const result_ptr = self.buildAlloca(union_llvm_ty); | 8666 | const result_ptr = self.buildAlloca(union_llvm_ty); |
| 8543 | const llvm_payload = try self.resolveInst(extra.init); | 8667 | const llvm_payload = try self.resolveInst(extra.init); |
| 8544 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | ||
| 8545 | assert(union_obj.haveFieldTypes()); | 8668 | assert(union_obj.haveFieldTypes()); |
| 8546 | const field = union_obj.fields.values()[extra.field_index]; | 8669 | const field = union_obj.fields.values()[extra.field_index]; |
| 8547 | const field_llvm_ty = try self.dg.lowerType(field.ty); | 8670 | const field_llvm_ty = try self.dg.lowerType(field.ty); |
| ... | @@ -8625,7 +8748,7 @@ pub const FuncGen = struct { | ... | @@ -8625,7 +8748,7 @@ pub const FuncGen = struct { |
| 8625 | }; | 8748 | }; |
| 8626 | const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, indices.len, ""); | 8749 | const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, indices.len, ""); |
| 8627 | const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty); | 8750 | const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty); |
| 8628 | const llvm_tag = tag_llvm_ty.constInt(extra.field_index, .False); | 8751 | const llvm_tag = tag_llvm_ty.constInt(tag_int, .False); |
| 8629 | const store_inst = self.builder.buildStore(llvm_tag, field_ptr); | 8752 | const store_inst = self.builder.buildStore(llvm_tag, field_ptr); |
| 8630 | store_inst.setAlignment(union_obj.tag_ty.abiAlignment(target)); | 8753 | store_inst.setAlignment(union_obj.tag_ty.abiAlignment(target)); |
| 8631 | } | 8754 | } |
src/link.zig+4-3| ... | @@ -931,9 +931,10 @@ pub const File = struct { | ... | @@ -931,9 +931,10 @@ pub const File = struct { |
| 931 | std.debug.print("\n", .{}); | 931 | std.debug.print("\n", .{}); |
| 932 | } | 932 | } |
| 933 | 933 | ||
| 934 | const llvm = @import("codegen/llvm/bindings.zig"); | 934 | const llvm_bindings = @import("codegen/llvm/bindings.zig"); |
| 935 | const os_type = @import("target.zig").osToLLVM(base.options.target.os.tag); | 935 | const llvm = @import("codegen/llvm.zig"); |
| 936 | const bad = llvm.WriteArchive(full_out_path_z, object_files.items.ptr, object_files.items.len, os_type); | 936 | const os_tag = llvm.targetOs(base.options.target.os.tag); |
| 937 | const bad = llvm_bindings.WriteArchive(full_out_path_z, object_files.items.ptr, object_files.items.len, os_tag); | ||
| 937 | if (bad) return error.UnableToWriteArchive; | 938 | if (bad) return error.UnableToWriteArchive; |
| 938 | 939 | ||
| 939 | if (!base.options.disable_lld_caching) { | 940 | if (!base.options.disable_lld_caching) { |
src/mingw.zig+4-4| ... | @@ -6,7 +6,6 @@ const assert = std.debug.assert; | ... | @@ -6,7 +6,6 @@ const assert = std.debug.assert; |
| 6 | const log = std.log.scoped(.mingw); | 6 | const log = std.log.scoped(.mingw); |
| 7 | 7 | ||
| 8 | const builtin = @import("builtin"); | 8 | const builtin = @import("builtin"); |
| 9 | const target_util = @import("target.zig"); | ||
| 10 | const Compilation = @import("Compilation.zig"); | 9 | const Compilation = @import("Compilation.zig"); |
| 11 | const build_options = @import("build_options"); | 10 | const build_options = @import("build_options"); |
| 12 | const Cache = @import("Cache.zig"); | 11 | const Cache = @import("Cache.zig"); |
| ... | @@ -404,11 +403,12 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { | ... | @@ -404,11 +403,12 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { |
| 404 | }); | 403 | }); |
| 405 | errdefer comp.gpa.free(lib_final_path); | 404 | errdefer comp.gpa.free(lib_final_path); |
| 406 | 405 | ||
| 407 | const llvm = @import("codegen/llvm/bindings.zig"); | 406 | const llvm_bindings = @import("codegen/llvm/bindings.zig"); |
| 408 | const arch_type = target_util.archToLLVM(target.cpu.arch); | 407 | const llvm = @import("codegen/llvm.zig"); |
| 408 | const arch_tag = llvm.targetArch(target.cpu.arch); | ||
| 409 | const def_final_path_z = try arena.dupeZ(u8, def_final_path); | 409 | const def_final_path_z = try arena.dupeZ(u8, def_final_path); |
| 410 | const lib_final_path_z = try arena.dupeZ(u8, lib_final_path); | 410 | const lib_final_path_z = try arena.dupeZ(u8, lib_final_path); |
| 411 | if (llvm.WriteImportLibrary(def_final_path_z.ptr, arch_type, lib_final_path_z.ptr, true)) { | 411 | if (llvm_bindings.WriteImportLibrary(def_final_path_z.ptr, arch_tag, lib_final_path_z.ptr, true)) { |
| 412 | // TODO surface a proper error here | 412 | // TODO surface a proper error here |
| 413 | log.err("unable to turn {s}.def into {s}.lib", .{ lib_name, lib_name }); | 413 | log.err("unable to turn {s}.def into {s}.lib", .{ lib_name, lib_name }); |
| 414 | return error.WritingImportLibFailed; | 414 | return error.WritingImportLibFailed; |
src/print_zir.zig+5-6| ... | @@ -283,7 +283,6 @@ const Writer = struct { | ... | @@ -283,7 +283,6 @@ const Writer = struct { |
| 283 | .mul_add => try self.writeMulAdd(stream, inst), | 283 | .mul_add => try self.writeMulAdd(stream, inst), |
| 284 | .field_parent_ptr => try self.writeFieldParentPtr(stream, inst), | 284 | .field_parent_ptr => try self.writeFieldParentPtr(stream, inst), |
| 285 | .builtin_call => try self.writeBuiltinCall(stream, inst), | 285 | .builtin_call => try self.writeBuiltinCall(stream, inst), |
| 286 | .builtin_async_call => try self.writeBuiltinAsyncCall(stream, inst), | ||
| 287 | 286 | ||
| 288 | .struct_init_anon, | 287 | .struct_init_anon, |
| 289 | .struct_init_anon_ref, | 288 | .struct_init_anon_ref, |
| ... | @@ -397,7 +396,7 @@ const Writer = struct { | ... | @@ -397,7 +396,7 @@ const Writer = struct { |
| 397 | .field_val_named, | 396 | .field_val_named, |
| 398 | => try self.writePlNodeFieldNamed(stream, inst), | 397 | => try self.writePlNodeFieldNamed(stream, inst), |
| 399 | 398 | ||
| 400 | .as_node => try self.writeAs(stream, inst), | 399 | .as_node, .as_shift_operand => try self.writeAs(stream, inst), |
| 401 | 400 | ||
| 402 | .repeat, | 401 | .repeat, |
| 403 | .repeat_inline, | 402 | .repeat_inline, |
| ... | @@ -531,6 +530,7 @@ const Writer = struct { | ... | @@ -531,6 +530,7 @@ const Writer = struct { |
| 531 | try stream.writeAll(") "); | 530 | try stream.writeAll(") "); |
| 532 | try self.writeSrc(stream, src); | 531 | try self.writeSrc(stream, src); |
| 533 | }, | 532 | }, |
| 533 | .builtin_async_call => try self.writeBuiltinAsyncCall(stream, extended), | ||
| 534 | } | 534 | } |
| 535 | } | 535 | } |
| 536 | 536 | ||
| ... | @@ -814,9 +814,8 @@ const Writer = struct { | ... | @@ -814,9 +814,8 @@ const Writer = struct { |
| 814 | try self.writeSrc(stream, inst_data.src()); | 814 | try self.writeSrc(stream, inst_data.src()); |
| 815 | } | 815 | } |
| 816 | 816 | ||
| 817 | fn writeBuiltinAsyncCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | 817 | fn writeBuiltinAsyncCall(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { |
| 818 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | 818 | const extra = self.code.extraData(Zir.Inst.AsyncCall, extended.operand).data; |
| 819 | const extra = self.code.extraData(Zir.Inst.AsyncCall, inst_data.payload_index).data; | ||
| 820 | try self.writeInstRef(stream, extra.frame_buffer); | 819 | try self.writeInstRef(stream, extra.frame_buffer); |
| 821 | try stream.writeAll(", "); | 820 | try stream.writeAll(", "); |
| 822 | try self.writeInstRef(stream, extra.result_ptr); | 821 | try self.writeInstRef(stream, extra.result_ptr); |
| ... | @@ -825,7 +824,7 @@ const Writer = struct { | ... | @@ -825,7 +824,7 @@ const Writer = struct { |
| 825 | try stream.writeAll(", "); | 824 | try stream.writeAll(", "); |
| 826 | try self.writeInstRef(stream, extra.args); | 825 | try self.writeInstRef(stream, extra.args); |
| 827 | try stream.writeAll(") "); | 826 | try stream.writeAll(") "); |
| 828 | try self.writeSrc(stream, inst_data.src()); | 827 | try self.writeSrc(stream, LazySrcLoc.nodeOffset(extra.node)); |
| 829 | } | 828 | } |
| 830 | 829 | ||
| 831 | fn writeParam(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | 830 | fn writeParam(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { |
src/target.zig+7-101| ... | @@ -1,5 +1,4 @@ | ... | @@ -1,5 +1,4 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const llvm = @import("codegen/llvm/bindings.zig"); | ||
| 3 | const Type = @import("type.zig").Type; | 2 | const Type = @import("type.zig").Type; |
| 4 | 3 | ||
| 5 | pub const ArchOsAbi = struct { | 4 | pub const ArchOsAbi = struct { |
| ... | @@ -317,106 +316,6 @@ pub fn supportsReturnAddress(target: std.Target) bool { | ... | @@ -317,106 +316,6 @@ pub fn supportsReturnAddress(target: std.Target) bool { |
| 317 | }; | 316 | }; |
| 318 | } | 317 | } |
| 319 | 318 | ||
| 320 | pub fn osToLLVM(os_tag: std.Target.Os.Tag) llvm.OSType { | ||
| 321 | return switch (os_tag) { | ||
| 322 | .freestanding, .other, .opencl, .glsl450, .vulkan, .plan9 => .UnknownOS, | ||
| 323 | .windows, .uefi => .Win32, | ||
| 324 | .ananas => .Ananas, | ||
| 325 | .cloudabi => .CloudABI, | ||
| 326 | .dragonfly => .DragonFly, | ||
| 327 | .freebsd => .FreeBSD, | ||
| 328 | .fuchsia => .Fuchsia, | ||
| 329 | .ios => .IOS, | ||
| 330 | .kfreebsd => .KFreeBSD, | ||
| 331 | .linux => .Linux, | ||
| 332 | .lv2 => .Lv2, | ||
| 333 | .macos => .MacOSX, | ||
| 334 | .netbsd => .NetBSD, | ||
| 335 | .openbsd => .OpenBSD, | ||
| 336 | .solaris => .Solaris, | ||
| 337 | .zos => .ZOS, | ||
| 338 | .haiku => .Haiku, | ||
| 339 | .minix => .Minix, | ||
| 340 | .rtems => .RTEMS, | ||
| 341 | .nacl => .NaCl, | ||
| 342 | .aix => .AIX, | ||
| 343 | .cuda => .CUDA, | ||
| 344 | .nvcl => .NVCL, | ||
| 345 | .amdhsa => .AMDHSA, | ||
| 346 | .ps4 => .PS4, | ||
| 347 | .elfiamcu => .ELFIAMCU, | ||
| 348 | .tvos => .TvOS, | ||
| 349 | .watchos => .WatchOS, | ||
| 350 | .mesa3d => .Mesa3D, | ||
| 351 | .contiki => .Contiki, | ||
| 352 | .amdpal => .AMDPAL, | ||
| 353 | .hermit => .HermitCore, | ||
| 354 | .hurd => .Hurd, | ||
| 355 | .wasi => .WASI, | ||
| 356 | .emscripten => .Emscripten, | ||
| 357 | }; | ||
| 358 | } | ||
| 359 | |||
| 360 | pub fn archToLLVM(arch_tag: std.Target.Cpu.Arch) llvm.ArchType { | ||
| 361 | return switch (arch_tag) { | ||
| 362 | .arm => .arm, | ||
| 363 | .armeb => .armeb, | ||
| 364 | .aarch64 => .aarch64, | ||
| 365 | .aarch64_be => .aarch64_be, | ||
| 366 | .aarch64_32 => .aarch64_32, | ||
| 367 | .arc => .arc, | ||
| 368 | .avr => .avr, | ||
| 369 | .bpfel => .bpfel, | ||
| 370 | .bpfeb => .bpfeb, | ||
| 371 | .csky => .csky, | ||
| 372 | .hexagon => .hexagon, | ||
| 373 | .m68k => .m68k, | ||
| 374 | .mips => .mips, | ||
| 375 | .mipsel => .mipsel, | ||
| 376 | .mips64 => .mips64, | ||
| 377 | .mips64el => .mips64el, | ||
| 378 | .msp430 => .msp430, | ||
| 379 | .powerpc => .ppc, | ||
| 380 | .powerpcle => .ppcle, | ||
| 381 | .powerpc64 => .ppc64, | ||
| 382 | .powerpc64le => .ppc64le, | ||
| 383 | .r600 => .r600, | ||
| 384 | .amdgcn => .amdgcn, | ||
| 385 | .riscv32 => .riscv32, | ||
| 386 | .riscv64 => .riscv64, | ||
| 387 | .sparc => .sparc, | ||
| 388 | .sparc64 => .sparcv9, // In LLVM, sparc64 == sparcv9. | ||
| 389 | .sparcel => .sparcel, | ||
| 390 | .s390x => .systemz, | ||
| 391 | .tce => .tce, | ||
| 392 | .tcele => .tcele, | ||
| 393 | .thumb => .thumb, | ||
| 394 | .thumbeb => .thumbeb, | ||
| 395 | .i386 => .x86, | ||
| 396 | .x86_64 => .x86_64, | ||
| 397 | .xcore => .xcore, | ||
| 398 | .nvptx => .nvptx, | ||
| 399 | .nvptx64 => .nvptx64, | ||
| 400 | .le32 => .le32, | ||
| 401 | .le64 => .le64, | ||
| 402 | .amdil => .amdil, | ||
| 403 | .amdil64 => .amdil64, | ||
| 404 | .hsail => .hsail, | ||
| 405 | .hsail64 => .hsail64, | ||
| 406 | .spir => .spir, | ||
| 407 | .spir64 => .spir64, | ||
| 408 | .kalimba => .kalimba, | ||
| 409 | .shave => .shave, | ||
| 410 | .lanai => .lanai, | ||
| 411 | .wasm32 => .wasm32, | ||
| 412 | .wasm64 => .wasm64, | ||
| 413 | .renderscript32 => .renderscript32, | ||
| 414 | .renderscript64 => .renderscript64, | ||
| 415 | .ve => .ve, | ||
| 416 | .spu_2, .spirv32, .spirv64 => .UnknownArch, | ||
| 417 | }; | ||
| 418 | } | ||
| 419 | |||
| 420 | fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool { | 319 | fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool { |
| 421 | if (ignore_case) { | 320 | if (ignore_case) { |
| 422 | return std.ascii.eqlIgnoreCase(a, b); | 321 | return std.ascii.eqlIgnoreCase(a, b); |
| ... | @@ -770,3 +669,10 @@ pub fn supportsFunctionAlignment(target: std.Target) bool { | ... | @@ -770,3 +669,10 @@ pub fn supportsFunctionAlignment(target: std.Target) bool { |
| 770 | else => true, | 669 | else => true, |
| 771 | }; | 670 | }; |
| 772 | } | 671 | } |
| 672 | |||
| 673 | pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool { | ||
| 674 | switch (backend) { | ||
| 675 | .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target), | ||
| 676 | else => return false, | ||
| 677 | } | ||
| 678 | } |
test/behavior/call.zig+68| ... | @@ -261,3 +261,71 @@ test "arguments to comptime parameters generated in comptime blocks" { | ... | @@ -261,3 +261,71 @@ test "arguments to comptime parameters generated in comptime blocks" { |
| 261 | }; | 261 | }; |
| 262 | S.foo(S.fortyTwo()); | 262 | S.foo(S.fortyTwo()); |
| 263 | } | 263 | } |
| 264 | |||
| 265 | test "forced tail call" { | ||
| 266 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | ||
| 267 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 268 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 269 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 270 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 271 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 272 | |||
| 273 | if (builtin.zig_backend == .stage2_llvm) { | ||
| 274 | // Only attempt this test on targets we know have tail call support in LLVM. | ||
| 275 | if (builtin.cpu.arch != .x86_64 and builtin.cpu.arch != .aarch64) { | ||
| 276 | return error.SkipZigTest; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | const S = struct { | ||
| 281 | fn fibonacciTailInternal(n: u16, a: u16, b: u16) u16 { | ||
| 282 | if (n == 0) return a; | ||
| 283 | if (n == 1) return b; | ||
| 284 | return @call( | ||
| 285 | .{ .modifier = .always_tail }, | ||
| 286 | fibonacciTailInternal, | ||
| 287 | .{ n - 1, b, a + b }, | ||
| 288 | ); | ||
| 289 | } | ||
| 290 | |||
| 291 | fn fibonacciTail(n: u16) u16 { | ||
| 292 | return fibonacciTailInternal(n, 0, 1); | ||
| 293 | } | ||
| 294 | }; | ||
| 295 | try expect(S.fibonacciTail(10) == 55); | ||
| 296 | } | ||
| 297 | |||
| 298 | test "inline call preserves tail call" { | ||
| 299 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | ||
| 300 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 301 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 302 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 303 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 304 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 305 | |||
| 306 | if (builtin.zig_backend == .stage2_llvm) { | ||
| 307 | // Only attempt this test on targets we know have tail call support in LLVM. | ||
| 308 | if (builtin.cpu.arch != .x86_64 and builtin.cpu.arch != .aarch64) { | ||
| 309 | return error.SkipZigTest; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | const max = std.math.maxInt(u16); | ||
| 314 | const S = struct { | ||
| 315 | var a: u16 = 0; | ||
| 316 | fn foo() void { | ||
| 317 | return bar(); | ||
| 318 | } | ||
| 319 | |||
| 320 | inline fn bar() void { | ||
| 321 | if (a == max) return; | ||
| 322 | // Stack overflow if not tail called | ||
| 323 | var buf: [max]u16 = undefined; | ||
| 324 | buf[a] = a; | ||
| 325 | a += 1; | ||
| 326 | return @call(.{ .modifier = .always_tail }, foo, .{}); | ||
| 327 | } | ||
| 328 | }; | ||
| 329 | S.foo(); | ||
| 330 | try expect(S.a == std.math.maxInt(u16)); | ||
| 331 | } |
test/behavior/union.zig+28| ... | @@ -1324,3 +1324,31 @@ test "union and enum field order doesn't match" { | ... | @@ -1324,3 +1324,31 @@ test "union and enum field order doesn't match" { |
| 1324 | x = .b; | 1324 | x = .b; |
| 1325 | try expect(x == .b); | 1325 | try expect(x == .b); |
| 1326 | } | 1326 | } |
| 1327 | |||
| 1328 | test "@unionInit uses tag value instead of field index" { | ||
| 1329 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 1330 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1331 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 1332 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 1333 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 1334 | |||
| 1335 | const E = enum(u8) { | ||
| 1336 | b = 255, | ||
| 1337 | a = 3, | ||
| 1338 | }; | ||
| 1339 | const U = union(E) { | ||
| 1340 | a: usize, | ||
| 1341 | b: isize, | ||
| 1342 | }; | ||
| 1343 | var i: isize = -1; | ||
| 1344 | var u = @unionInit(U, "b", i); | ||
| 1345 | { | ||
| 1346 | var a = u.b; | ||
| 1347 | try expect(a == i); | ||
| 1348 | } | ||
| 1349 | { | ||
| 1350 | var a = &u.b; | ||
| 1351 | try expect(a.* == i); | ||
| 1352 | } | ||
| 1353 | try expect(@enumToInt(u) == 255); | ||
| 1354 | } |
test/cases/compile_errors/invalid_tail_call.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | fn myFn(_: usize) void { | ||
| 2 | return; | ||
| 3 | } | ||
| 4 | pub export fn entry() void { | ||
| 5 | @call(.{ .modifier = .always_tail }, myFn, .{0}); | ||
| 6 | } | ||
| 7 | |||
| 8 | // error | ||
| 9 | // backend=llvm | ||
| 10 | // target=native | ||
| 11 | // | ||
| 12 | // :5:5: error: unable to perform tail call: type of function being called 'fn(usize) void' does not match type of calling function 'fn() callconv(.C) void' | ||
test/cases/compile_errors/non-comptime-parameter-used-as-array-size.zig created+16| ... | @@ -0,0 +1,16 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | const llamas1 = makeLlamas(5); | ||
| 3 | const llamas2 = makeLlamas(5); | ||
| 4 | _ = llamas1; | ||
| 5 | _ = llamas2; | ||
| 6 | } | ||
| 7 | |||
| 8 | fn makeLlamas(count: usize) [count]u8 { | ||
| 9 | _ = count; | ||
| 10 | } | ||
| 11 | |||
| 12 | // error | ||
| 13 | // target=native | ||
| 14 | // | ||
| 15 | // :8:30: error: unable to resolve comptime value | ||
| 16 | // :8:30: note: array length must be comptime known | ||
test/cases/compile_errors/runtime_to_comptime_num.zig created+31| ... | @@ -0,0 +1,31 @@ | ||
| 1 | pub export fn entry() void { | ||
| 2 | var a: u32 = 0; | ||
| 3 | _ = @as(comptime_int, a); | ||
| 4 | } | ||
| 5 | pub export fn entry2() void{ | ||
| 6 | var a: u32 = 0; | ||
| 7 | _ = @as(comptime_float, a); | ||
| 8 | } | ||
| 9 | pub export fn entry3() void{ | ||
| 10 | comptime var aa: comptime_float = 0.0; | ||
| 11 | var a: f32 = 4; | ||
| 12 | aa = a; | ||
| 13 | } | ||
| 14 | pub export fn entry4() void{ | ||
| 15 | comptime var aa: comptime_int = 0.0; | ||
| 16 | var a: f32 = 4; | ||
| 17 | aa = a; | ||
| 18 | } | ||
| 19 | |||
| 20 | // error | ||
| 21 | // backend=stage2 | ||
| 22 | // target=native | ||
| 23 | // | ||
| 24 | // :3:27: error: unable to resolve comptime value | ||
| 25 | // :3:27: note: value being casted to 'comptime_int' must be comptime known | ||
| 26 | // :7:29: error: unable to resolve comptime value | ||
| 27 | // :7:29: note: value being casted to 'comptime_float' must be comptime known | ||
| 28 | // :12:10: error: unable to resolve comptime value | ||
| 29 | // :12:10: note: value being casted to 'comptime_float' must be comptime known | ||
| 30 | // :17:10: error: unable to resolve comptime value | ||
| 31 | // :17:10: note: value being casted to 'comptime_int' must be comptime known | ||
test/cases/compile_errors/shifting_without_int_type_or_comptime_known.zig created+23| ... | @@ -0,0 +1,23 @@ | ||
| 1 | export fn entry(x: u8) u8 { | ||
| 2 | return 0x11 << x; | ||
| 3 | } | ||
| 4 | export fn entry1(x: u8) u8 { | ||
| 5 | return 0x11 >> x; | ||
| 6 | } | ||
| 7 | export fn entry2() void { | ||
| 8 | var x: u5 = 1; | ||
| 9 | _ = @shlExact(12345, x); | ||
| 10 | } | ||
| 11 | export fn entry3() void { | ||
| 12 | var x: u5 = 1; | ||
| 13 | _ = @shrExact(12345, x); | ||
| 14 | } | ||
| 15 | |||
| 16 | // error | ||
| 17 | // backend=stage2 | ||
| 18 | // target=native | ||
| 19 | // | ||
| 20 | // :2:17: error: LHS of shift must be a fixed-width integer type, or RHS must be a comptime known | ||
| 21 | // :5:17: error: LHS of shift must be a fixed-width integer type, or RHS must be a comptime known | ||
| 22 | // :9:9: error: LHS of shift must be a fixed-width integer type, or RHS must be a comptime known | ||
| 23 | // :13:9: error: LHS of shift must be a fixed-width integer type, or RHS must be a comptime known | ||
test/cases/compile_errors/stage1/obj/shifting_without_int_type_or_comptime_known.zig deleted-9| ... | @@ -1,9 +0,0 @@ | ||
| 1 | export fn entry(x: u8) u8 { | ||
| 2 | return 0x11 << x; | ||
| 3 | } | ||
| 4 | |||
| 5 | // error | ||
| 6 | // backend=stage1 | ||
| 7 | // target=native | ||
| 8 | // | ||
| 9 | // tmp.zig:2:17: error: LHS of shift must be a fixed-width integer type, or RHS must be compile-time known | ||
test/cases/taill_call_noreturn.zig created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = std.builtin; | ||
| 3 | pub fn foo(message: []const u8, stack_trace: ?*builtin.StackTrace) noreturn { | ||
| 4 | @call(.{ .modifier = .always_tail }, bar, .{ message, stack_trace }); | ||
| 5 | } | ||
| 6 | pub fn bar(message: []const u8, stack_trace: ?*builtin.StackTrace) noreturn { | ||
| 7 | _ = message; | ||
| 8 | _ = stack_trace; | ||
| 9 | std.process.exit(0); | ||
| 10 | } | ||
| 11 | |||
| 12 | pub fn main() void { | ||
| 13 | foo("foo", null); | ||
| 14 | } | ||
| 15 | |||
| 16 | // run | ||
| 17 | // backend=llvm | ||
| 18 | // target=x86_64-linux,x86_64-macos,aarch64-linux,aarch64-macos | ||