authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-30 15:55:05-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-08-30 15:55:05-04:00
logf559ea95b1c37fd6ede8fff6ffb2d74d5c2abc4e
tree6d9714e54fa2223aa6842d8d496d5f3dadd360e8
parent0a42602418dcaf08f13b4220b6c216356f87cbfc
parent7377dce368090e3c49a15d8996cc812adadd3d43
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12686 from Vexu/stage2-fixes

Stage2 fixes

18 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};
306316
307pub const align_rl: ResultLoc = .{ .ty = .u29_type };317pub 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 correct9481 => return result, // type of result is already correct
94719482
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}
47684768
4769pub 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
4769pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Allocator.Error![:0]u8 {4787pub 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
47754793
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 };
47954797
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: on960 // 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}
61576161
6162fn 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
6158fn analyzeInlineCallArg(6180fn 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);
66716693
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(
67176740
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);
67306753
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}
67366762
6737fn emitDbgInline(6763fn 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}
81838223
8184fn zirParamAnytype(8224fn 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();
82268266
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}
82308270
8231fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {8271fn 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
8281fn 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}
82408290
8241fn analyzeAs(8291fn 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_type8300 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(
1045910510
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 };
1046310519
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();
1058510641
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;
1063510694
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}
1961619685
19617fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {19686fn 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}
1962219691
...@@ -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).?);
2187421944
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() and21997 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).?);
2196122031
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);
2196422034
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() and22071 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};
2251822587
22588const 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
22519fn coerceExtra(22597fn 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(
2257522652
22576 // T to ?T22653 // 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 notes22658 // 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 notes22784 // 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 };
2283222915
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 number22929 // 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 }
2285322941
22854 // integer widening22942 // 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 }
2289122980
...@@ -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 error22998 // 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 }
2305223147
23053 if (!report_err) return error.NotCoercible;23148 if (!opts.report_err) return error.NotCoercible;
2305423149
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);
2309023185
23091 // Add notes about function return type23186 // 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/1115424145 // 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 }
2406024155
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,
18061805
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 `NameStrategy1972 /// `small` contains `NameStrategy
1974 reify,1973 reify,
1974 /// Implements the `@asyncCall` builtin.
1975 /// `operand` is payload index to `AsyncCall`.
1976 builtin_async_call,
19751977
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 };
34553457
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}
179179
180pub 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
220pub 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
280pub 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
180pub const Object = struct {290pub 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 );
45244634
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 not8662 // 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 }
933933
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;
938939
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;
6const log = std.log.scoped(.mingw);6const log = std.log.scoped(.mingw);
77
8const builtin = @import("builtin");8const builtin = @import("builtin");
9const target_util = @import("target.zig");
10const Compilation = @import("Compilation.zig");9const Compilation = @import("Compilation.zig");
11const build_options = @import("build_options");10const build_options = @import("build_options");
12const Cache = @import("Cache.zig");11const 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);
406405
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 here412 // 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),
287286
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),
399398
400 .as_node => try self.writeAs(stream, inst),399 .as_node, .as_shift_operand => try self.writeAs(stream, inst),
401400
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 }
536536
...@@ -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 }
816816
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 }
830829
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 @@
1const std = @import("std");1const std = @import("std");
2const llvm = @import("codegen/llvm/bindings.zig");
3const Type = @import("type.zig").Type;2const Type = @import("type.zig").Type;
43
5pub const ArchOsAbi = struct {4pub 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}
319318
320pub 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
360pub 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
420fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {319fn 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
673pub 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
265test "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
298test "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
1328test "@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 @@
1fn myFn(_: usize) void {
2 return;
3}
4pub 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 @@
1export fn entry() void {
2 const llamas1 = makeLlamas(5);
3 const llamas2 = makeLlamas(5);
4 _ = llamas1;
5 _ = llamas2;
6}
7
8fn 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 @@
1pub export fn entry() void {
2 var a: u32 = 0;
3 _ = @as(comptime_int, a);
4}
5pub export fn entry2() void{
6 var a: u32 = 0;
7 _ = @as(comptime_float, a);
8}
9pub export fn entry3() void{
10 comptime var aa: comptime_float = 0.0;
11 var a: f32 = 4;
12 aa = a;
13}
14pub 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 @@
1export fn entry(x: u8) u8 {
2 return 0x11 << x;
3}
4export fn entry1(x: u8) u8 {
5 return 0x11 >> x;
6}
7export fn entry2() void {
8 var x: u5 = 1;
9 _ = @shlExact(12345, x);
10}
11export 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 @@
1export 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 @@
1const std = @import("std");
2const builtin = std.builtin;
3pub fn foo(message: []const u8, stack_trace: ?*builtin.StackTrace) noreturn {
4 @call(.{ .modifier = .always_tail }, bar, .{ message, stack_trace });
5}
6pub fn bar(message: []const u8, stack_trace: ?*builtin.StackTrace) noreturn {
7 _ = message;
8 _ = stack_trace;
9 std.process.exit(0);
10}
11
12pub 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