authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-11 00:04:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-11 00:04:42-07:00
log078037ab9b410fa13a86eabdfc30918fc83cdcf3
treeb5e80992e82d015393872fcc57911b03ca7211fd
parentb28b3f6f7b1dd4c3c8a0f3d3a6305a84daed8ead

stage2: passing threadlocal tests for x86_64-linux

* use the real start code for LLVM backend with x86_64-linux - there is still a check for zig_backend after initializing the TLS area to skip some stuff. * introduce new AIR instructions and implement them for the LLVM backend. They are the same as `call` except with a modifier. - call_always_tail - call_never_tail - call_never_inline * LLVM backend calls hasRuntimeBitsIgnoringComptime in more places to avoid unnecessarily depending on comptimeOnly being resolved for some types. * LLVM backend: remove duplicate code for setting linkage and value name. The canonical place for this is in `updateDeclExports`. * LLVM backend: do some assembly template massaging to make `%%` rendered as `%`. More hacks will be needed to make inline assembly catch up with stage1.

18 files changed, 190 insertions(+), 70 deletions(-)

lib/std/start.zig+15-1
...@@ -22,7 +22,16 @@ comptime {...@@ -22,7 +22,16 @@ comptime {
22 // The self-hosted compiler is not fully capable of handling all of this start.zig file.22 // The self-hosted compiler is not fully capable of handling all of this start.zig file.
23 // Until then, we have simplified logic here for self-hosted. TODO remove this once23 // Until then, we have simplified logic here for self-hosted. TODO remove this once
24 // self-hosted is capable enough to handle all of the real start.zig logic.24 // self-hosted is capable enough to handle all of the real start.zig logic.
25 if (builtin.zig_backend != .stage1) {25 if (builtin.zig_backend == .stage2_wasm or
26 builtin.zig_backend == .stage2_c or
27 builtin.zig_backend == .stage2_x86_64 or
28 builtin.zig_backend == .stage2_x86 or
29 builtin.zig_backend == .stage2_aarch64 or
30 builtin.zig_backend == .stage2_arm or
31 builtin.zig_backend == .stage2_riscv64 or
32 (builtin.zig_backend == .stage2_llvm and native_os != .linux) or
33 (builtin.zig_backend == .stage2_llvm and native_arch != .x86_64))
34 {
26 if (builtin.output_mode == .Exe) {35 if (builtin.output_mode == .Exe) {
27 if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) {36 if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) {
28 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {37 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
...@@ -399,6 +408,11 @@ fn posixCallMainAndExit() noreturn {...@@ -399,6 +408,11 @@ fn posixCallMainAndExit() noreturn {
399 // Initialize the TLS area.408 // Initialize the TLS area.
400 std.os.linux.tls.initStaticTLS(phdrs);409 std.os.linux.tls.initStaticTLS(phdrs);
401410
411 if (builtin.zig_backend == .stage2_llvm) {
412 root.main();
413 exit2(0);
414 }
415
402 // The way Linux executables represent stack size is via the PT_GNU_STACK416 // The way Linux executables represent stack size is via the PT_GNU_STACK
403 // program header. However the kernel does not recognize it; it always gives 8 MiB.417 // program header. However the kernel does not recognize it; it always gives 8 MiB.
404 // Here we look for the stack size in our program headers and use setrlimit418 // Here we look for the stack size in our program headers and use setrlimit
src/Air.zig+7-1
...@@ -226,6 +226,12 @@ pub const Inst = struct {...@@ -226,6 +226,12 @@ pub const Inst = struct {
226 /// Uses the `pl_op` field with the `Call` payload. operand is the callee.226 /// Uses the `pl_op` field with the `Call` payload. operand is the callee.
227 /// Triggers `resolveTypeLayout` on the return type of the callee.227 /// Triggers `resolveTypeLayout` on the return type of the callee.
228 call,228 call,
229 /// Same as `call` except with the `always_tail` attribute.
230 call_always_tail,
231 /// Same as `call` except with the `never_tail` attribute.
232 call_never_tail,
233 /// Same as `call` except with the `never_inline` attribute.
234 call_never_inline,
229 /// Count leading zeroes of an integer according to its representation in twos complement.235 /// Count leading zeroes of an integer according to its representation in twos complement.
230 /// Result type will always be an unsigned integer big enough to fit the answer.236 /// Result type will always be an unsigned integer big enough to fit the answer.
231 /// Uses the `ty_op` field.237 /// Uses the `ty_op` field.
...@@ -969,7 +975,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -969,7 +975,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
969975
970 .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0),976 .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0),
971977
972 .call => {978 .call, .call_always_tail, .call_never_tail, .call_never_inline => {
973 const callee_ty = air.typeOf(datas[inst].pl_op.operand);979 const callee_ty = air.typeOf(datas[inst].pl_op.operand);
974 switch (callee_ty.zigTypeTag()) {980 switch (callee_ty.zigTypeTag()) {
975 .Fn => return callee_ty.fnReturnType(),981 .Fn => return callee_ty.fnReturnType(),
src/Liveness.zig+1-1
...@@ -399,7 +399,7 @@ fn analyzeInst(...@@ -399,7 +399,7 @@ fn analyzeInst(
399 return trackOperands(a, new_set, inst, main_tomb, .{ prefetch.ptr, .none, .none });399 return trackOperands(a, new_set, inst, main_tomb, .{ prefetch.ptr, .none, .none });
400 },400 },
401401
402 .call => {402 .call, .call_always_tail, .call_never_tail, .call_never_inline => {
403 const inst_data = inst_datas[inst].pl_op;403 const inst_data = inst_datas[inst].pl_op;
404 const callee = inst_data.operand;404 const callee = inst_data.operand;
405 const extra = a.air.extraData(Air.Call, inst_data.payload);405 const extra = a.air.extraData(Air.Call, inst_data.payload);
src/Sema.zig+13-13
...@@ -4458,21 +4458,19 @@ fn analyzeCall(...@@ -4458,21 +4458,19 @@ fn analyzeCall(
4458 );4458 );
4459 }4459 }
44604460
4461 switch (modifier) {4461 const call_tag: Air.Inst.Tag = switch (modifier) {
4462 .auto,4462 .auto,
4463 .always_inline,4463 .always_inline,
4464 .compile_time,4464 .compile_time,
4465 .no_async,4465 .no_async,
4466 => {},4466 => Air.Inst.Tag.call,
44674467
4468 .async_kw,4468 .never_tail => Air.Inst.Tag.call_never_tail,
4469 .never_tail,4469 .never_inline => Air.Inst.Tag.call_never_inline,
4470 .never_inline,4470 .always_tail => Air.Inst.Tag.call_always_tail,
4471 .always_tail,4471
4472 => return sema.fail(block, call_src, "TODO implement call with modifier {}", .{4472 .async_kw => return sema.fail(block, call_src, "TODO implement async call", .{}),
4473 modifier,4473 };
4474 }),
4475 }
44764474
4477 const gpa = sema.gpa;4475 const gpa = sema.gpa;
44784476
...@@ -4490,6 +4488,7 @@ fn analyzeCall(...@@ -4490,6 +4488,7 @@ fn analyzeCall(
4490 func_ty_info,4488 func_ty_info,
4491 ensure_result_used,4489 ensure_result_used,
4492 uncasted_args,4490 uncasted_args,
4491 call_tag,
4493 )) |some| {4492 )) |some| {
4494 return some;4493 return some;
4495 } else |err| switch (err) {4494 } else |err| switch (err) {
...@@ -4771,7 +4770,7 @@ fn analyzeCall(...@@ -4771,7 +4770,7 @@ fn analyzeCall(
4771 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +4770 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
4772 args.len);4771 args.len);
4773 const func_inst = try block.addInst(.{4772 const func_inst = try block.addInst(.{
4774 .tag = .call,4773 .tag = call_tag,
4775 .data = .{ .pl_op = .{4774 .data = .{ .pl_op = .{
4776 .operand = func,4775 .operand = func,
4777 .payload = sema.addExtraAssumeCapacity(Air.Call{4776 .payload = sema.addExtraAssumeCapacity(Air.Call{
...@@ -4798,6 +4797,7 @@ fn instantiateGenericCall(...@@ -4798,6 +4797,7 @@ fn instantiateGenericCall(
4798 func_ty_info: Type.Payload.Function.Data,4797 func_ty_info: Type.Payload.Function.Data,
4799 ensure_result_used: bool,4798 ensure_result_used: bool,
4800 uncasted_args: []const Air.Inst.Ref,4799 uncasted_args: []const Air.Inst.Ref,
4800 call_tag: Air.Inst.Tag,
4801) CompileError!Air.Inst.Ref {4801) CompileError!Air.Inst.Ref {
4802 const mod = sema.mod;4802 const mod = sema.mod;
4803 const gpa = sema.gpa;4803 const gpa = sema.gpa;
...@@ -5107,7 +5107,7 @@ fn instantiateGenericCall(...@@ -5107,7 +5107,7 @@ fn instantiateGenericCall(
5107 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +5107 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
5108 runtime_args_len);5108 runtime_args_len);
5109 const func_inst = try block.addInst(.{5109 const func_inst = try block.addInst(.{
5110 .tag = .call,5110 .tag = call_tag,
5111 .data = .{ .pl_op = .{5111 .data = .{ .pl_op = .{
5112 .operand = callee_inst,5112 .operand = callee_inst,
5113 .payload = sema.addExtraAssumeCapacity(Air.Call{5113 .payload = sema.addExtraAssumeCapacity(Air.Call{
src/arch/aarch64/CodeGen.zig+7-2
...@@ -585,7 +585,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -585,7 +585,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
585 .ret_addr => try self.airRetAddr(inst),585 .ret_addr => try self.airRetAddr(inst),
586 .frame_addr => try self.airFrameAddress(inst),586 .frame_addr => try self.airFrameAddress(inst),
587 .fence => try self.airFence(),587 .fence => try self.airFence(),
588 .call => try self.airCall(inst),
589 .cond_br => try self.airCondBr(inst),588 .cond_br => try self.airCondBr(inst),
590 .dbg_stmt => try self.airDbgStmt(inst),589 .dbg_stmt => try self.airDbgStmt(inst),
591 .fptrunc => try self.airFptrunc(inst),590 .fptrunc => try self.airFptrunc(inst),
...@@ -634,6 +633,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -634,6 +633,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
634 .prefetch => try self.airPrefetch(inst),633 .prefetch => try self.airPrefetch(inst),
635 .mul_add => try self.airMulAdd(inst),634 .mul_add => try self.airMulAdd(inst),
636635
636 .call => try self.airCall(inst, .auto),
637 .call_always_tail => try self.airCall(inst, .always_tail),
638 .call_never_tail => try self.airCall(inst, .never_tail),
639 .call_never_inline => try self.airCall(inst, .never_inline),
640
637 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),641 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
638 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),642 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
639 .atomic_store_release => try self.airAtomicStore(inst, .Release),643 .atomic_store_release => try self.airAtomicStore(inst, .Release),
...@@ -2325,7 +2329,8 @@ fn airFence(self: *Self) !void {...@@ -2325,7 +2329,8 @@ fn airFence(self: *Self) !void {
2325 //return self.finishAirBookkeeping();2329 //return self.finishAirBookkeeping();
2326}2330}
23272331
2328fn airCall(self: *Self, inst: Air.Inst.Index) !void {2332fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void {
2333 if (modifier == .always_tail) return self.fail("TODO implement tail calls for aarch64", .{});
2329 const pl_op = self.air.instructions.items(.data)[inst].pl_op;2334 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2330 const callee = pl_op.operand;2335 const callee = pl_op.operand;
2331 const extra = self.air.extraData(Air.Call, pl_op.payload);2336 const extra = self.air.extraData(Air.Call, pl_op.payload);
src/arch/arm/CodeGen.zig+7-2
...@@ -581,7 +581,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -581,7 +581,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
581 .ret_addr => try self.airRetAddr(inst),581 .ret_addr => try self.airRetAddr(inst),
582 .frame_addr => try self.airFrameAddress(inst),582 .frame_addr => try self.airFrameAddress(inst),
583 .fence => try self.airFence(),583 .fence => try self.airFence(),
584 .call => try self.airCall(inst),
585 .cond_br => try self.airCondBr(inst),584 .cond_br => try self.airCondBr(inst),
586 .dbg_stmt => try self.airDbgStmt(inst),585 .dbg_stmt => try self.airDbgStmt(inst),
587 .fptrunc => try self.airFptrunc(inst),586 .fptrunc => try self.airFptrunc(inst),
...@@ -630,6 +629,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -630,6 +629,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
630 .prefetch => try self.airPrefetch(inst),629 .prefetch => try self.airPrefetch(inst),
631 .mul_add => try self.airMulAdd(inst),630 .mul_add => try self.airMulAdd(inst),
632631
632 .call => try self.airCall(inst, .auto),
633 .call_always_tail => try self.airCall(inst, .always_tail),
634 .call_never_tail => try self.airCall(inst, .never_tail),
635 .call_never_inline => try self.airCall(inst, .never_inline),
636
633 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),637 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
634 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),638 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
635 .atomic_store_release => try self.airAtomicStore(inst, .Release),639 .atomic_store_release => try self.airAtomicStore(inst, .Release),
...@@ -2510,7 +2514,8 @@ fn airFence(self: *Self) !void {...@@ -2510,7 +2514,8 @@ fn airFence(self: *Self) !void {
2510 //return self.finishAirBookkeeping();2514 //return self.finishAirBookkeeping();
2511}2515}
25122516
2513fn airCall(self: *Self, inst: Air.Inst.Index) !void {2517fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void {
2518 if (modifier == .always_tail) return self.fail("TODO implement tail calls for arm", .{});
2514 const pl_op = self.air.instructions.items(.data)[inst].pl_op;2519 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2515 const callee = pl_op.operand;2520 const callee = pl_op.operand;
2516 const extra = self.air.extraData(Air.Call, pl_op.payload);2521 const extra = self.air.extraData(Air.Call, pl_op.payload);
src/arch/riscv64/CodeGen.zig+8-3
...@@ -553,7 +553,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -553,7 +553,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
553 .ret_addr => try self.airRetAddr(inst),553 .ret_addr => try self.airRetAddr(inst),
554 .frame_addr => try self.airFrameAddress(inst),554 .frame_addr => try self.airFrameAddress(inst),
555 .fence => try self.airFence(),555 .fence => try self.airFence(),
556 .call => try self.airCall(inst),
557 .cond_br => try self.airCondBr(inst),556 .cond_br => try self.airCondBr(inst),
558 .dbg_stmt => try self.airDbgStmt(inst),557 .dbg_stmt => try self.airDbgStmt(inst),
559 .fptrunc => try self.airFptrunc(inst),558 .fptrunc => try self.airFptrunc(inst),
...@@ -602,6 +601,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -602,6 +601,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
602 .prefetch => try self.airPrefetch(inst),601 .prefetch => try self.airPrefetch(inst),
603 .mul_add => try self.airMulAdd(inst),602 .mul_add => try self.airMulAdd(inst),
604603
604 .call => try self.airCall(inst, .auto),
605 .call_always_tail => try self.airCall(inst, .always_tail),
606 .call_never_tail => try self.airCall(inst, .never_tail),
607 .call_never_inline => try self.airCall(inst, .never_inline),
608
605 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),609 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
606 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),610 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
607 .atomic_store_release => try self.airAtomicStore(inst, .Release),611 .atomic_store_release => try self.airAtomicStore(inst, .Release),
...@@ -1458,7 +1462,8 @@ fn airFence(self: *Self) !void {...@@ -1458,7 +1462,8 @@ fn airFence(self: *Self) !void {
1458 //return self.finishAirBookkeeping();1462 //return self.finishAirBookkeeping();
1459}1463}
14601464
1461fn airCall(self: *Self, inst: Air.Inst.Index) !void {1465fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void {
1466 if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{});
1462 const pl_op = self.air.instructions.items(.data)[inst].pl_op;1467 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1463 const fn_ty = self.air.typeOf(pl_op.operand);1468 const fn_ty = self.air.typeOf(pl_op.operand);
1464 const callee = pl_op.operand;1469 const callee = pl_op.operand;
...@@ -2496,7 +2501,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -2496,7 +2501,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
2496 result.stack_byte_count = next_stack_offset;2501 result.stack_byte_count = next_stack_offset;
2497 result.stack_align = 16;2502 result.stack_align = 16;
2498 },2503 },
2499 else => return self.fail("TODO implement function parameters for {} on aarch64", .{cc}),2504 else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}),
2500 }2505 }
25012506
2502 if (ret_ty.zigTypeTag() == .NoReturn) {2507 if (ret_ty.zigTypeTag() == .NoReturn) {
src/arch/wasm/CodeGen.zig+8-3
...@@ -1218,7 +1218,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1218,7 +1218,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1218 .breakpoint => self.airBreakpoint(inst),1218 .breakpoint => self.airBreakpoint(inst),
1219 .br => self.airBr(inst),1219 .br => self.airBr(inst),
1220 .bool_to_int => self.airBoolToInt(inst),1220 .bool_to_int => self.airBoolToInt(inst),
1221 .call => self.airCall(inst),
1222 .cond_br => self.airCondBr(inst),1221 .cond_br => self.airCondBr(inst),
1223 .dbg_stmt => WValue.none,1222 .dbg_stmt => WValue.none,
1224 .intcast => self.airIntcast(inst),1223 .intcast => self.airIntcast(inst),
...@@ -1227,6 +1226,11 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1227,6 +1226,11 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1227 .float_to_int => self.airFloatToInt(inst),1226 .float_to_int => self.airFloatToInt(inst),
1228 .get_union_tag => self.airGetUnionTag(inst),1227 .get_union_tag => self.airGetUnionTag(inst),
12291228
1229 .call => self.airCall(inst, .auto),
1230 .call_always_tail => self.airCall(inst, .always_tail),
1231 .call_never_tail => self.airCall(inst, .never_tail),
1232 .call_never_inline => self.airCall(inst, .never_inline),
1233
1230 .is_err => self.airIsErr(inst, .i32_ne),1234 .is_err => self.airIsErr(inst, .i32_ne),
1231 .is_non_err => self.airIsErr(inst, .i32_eq),1235 .is_non_err => self.airIsErr(inst, .i32_eq),
12321236
...@@ -1375,7 +1379,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1375,7 +1379,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1375fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {1379fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1376 const child_type = self.air.typeOfIndex(inst).childType();1380 const child_type = self.air.typeOfIndex(inst).childType();
13771381
1378 if (!child_type.isFnOrHasRuntimeBits()) {1382 if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
1379 return self.allocStack(Type.usize); // create pointer to void1383 return self.allocStack(Type.usize); // create pointer to void
1380 }1384 }
13811385
...@@ -1401,7 +1405,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1401,7 +1405,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1401 return .none;1405 return .none;
1402}1406}
14031407
1404fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {1408fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) InnerError!WValue {
1409 if (modifier == .always_tail) return self.fail("TODO implement tail calls for wasm", .{});
1405 const pl_op = self.air.instructions.items(.data)[inst].pl_op;1410 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1406 const extra = self.air.extraData(Air.Call, pl_op.payload);1411 const extra = self.air.extraData(Air.Call, pl_op.payload);
1407 const args = self.air.extra[extra.end..][0..extra.data.args_len];1412 const args = self.air.extra[extra.end..][0..extra.data.args_len];
src/arch/x86_64/CodeGen.zig+7-2
...@@ -670,7 +670,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -670,7 +670,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
670 .ret_addr => try self.airRetAddr(inst),670 .ret_addr => try self.airRetAddr(inst),
671 .frame_addr => try self.airFrameAddress(inst),671 .frame_addr => try self.airFrameAddress(inst),
672 .fence => try self.airFence(),672 .fence => try self.airFence(),
673 .call => try self.airCall(inst),
674 .cond_br => try self.airCondBr(inst),673 .cond_br => try self.airCondBr(inst),
675 .dbg_stmt => try self.airDbgStmt(inst),674 .dbg_stmt => try self.airDbgStmt(inst),
676 .fptrunc => try self.airFptrunc(inst),675 .fptrunc => try self.airFptrunc(inst),
...@@ -719,6 +718,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -719,6 +718,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
719 .prefetch => try self.airPrefetch(inst),718 .prefetch => try self.airPrefetch(inst),
720 .mul_add => try self.airMulAdd(inst),719 .mul_add => try self.airMulAdd(inst),
721720
721 .call => try self.airCall(inst, .auto),
722 .call_always_tail => try self.airCall(inst, .always_tail),
723 .call_never_tail => try self.airCall(inst, .never_tail),
724 .call_never_inline => try self.airCall(inst, .never_inline),
725
722 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),726 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
723 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),727 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
724 .atomic_store_release => try self.airAtomicStore(inst, .Release),728 .atomic_store_release => try self.airAtomicStore(inst, .Release),
...@@ -3263,7 +3267,8 @@ fn airFence(self: *Self) !void {...@@ -3263,7 +3267,8 @@ fn airFence(self: *Self) !void {
3263 //return self.finishAirBookkeeping();3267 //return self.finishAirBookkeeping();
3264}3268}
32653269
3266fn airCall(self: *Self, inst: Air.Inst.Index) !void {3270fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier) !void {
3271 if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{});
3267 const pl_op = self.air.instructions.items(.data)[inst].pl_op;3272 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3268 const callee = pl_op.operand;3273 const callee = pl_op.operand;
3269 const extra = self.air.extraData(Air.Call, pl_op.payload);3274 const extra = self.air.extraData(Air.Call, pl_op.payload);
src/codegen/c.zig+20-5
...@@ -1685,7 +1685,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1685,7 +1685,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1685 .assembly => try airAsm(f, inst),1685 .assembly => try airAsm(f, inst),
1686 .block => try airBlock(f, inst),1686 .block => try airBlock(f, inst),
1687 .bitcast => try airBitcast(f, inst),1687 .bitcast => try airBitcast(f, inst),
1688 .call => try airCall(f, inst),
1689 .dbg_stmt => try airDbgStmt(f, inst),1688 .dbg_stmt => try airDbgStmt(f, inst),
1690 .intcast => try airIntCast(f, inst),1689 .intcast => try airIntCast(f, inst),
1691 .trunc => try airTrunc(f, inst),1690 .trunc => try airTrunc(f, inst),
...@@ -1721,6 +1720,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1721,6 +1720,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1721 .union_init => try airUnionInit(f, inst),1720 .union_init => try airUnionInit(f, inst),
1722 .prefetch => try airPrefetch(f, inst),1721 .prefetch => try airPrefetch(f, inst),
17231722
1723 .call => try airCall(f, inst, .auto),
1724 .call_always_tail => try airCall(f, inst, .always_tail),
1725 .call_never_tail => try airCall(f, inst, .never_tail),
1726 .call_never_inline => try airCall(f, inst, .never_inline),
1727
1724 .int_to_float,1728 .int_to_float,
1725 .float_to_int,1729 .float_to_int,
1726 .fptrunc,1730 .fptrunc,
...@@ -1904,7 +1908,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1904,7 +1908,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
19041908
1905 const elem_type = inst_ty.elemType();1909 const elem_type = inst_ty.elemType();
1906 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;1910 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
1907 if (!elem_type.isFnOrHasRuntimeBits()) {1911 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
1908 return CValue.undefined_ptr;1912 return CValue.undefined_ptr;
1909 }1913 }
19101914
...@@ -1979,7 +1983,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1979,7 +1983,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
1979fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {1983fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
1980 const un_op = f.air.instructions.items(.data)[inst].un_op;1984 const un_op = f.air.instructions.items(.data)[inst].un_op;
1981 const writer = f.object.writer();1985 const writer = f.object.writer();
1982 if (f.air.typeOf(un_op).isFnOrHasRuntimeBits()) {1986 if (f.air.typeOf(un_op).isFnOrHasRuntimeBitsIgnoreComptime()) {
1983 const operand = try f.resolveInst(un_op);1987 const operand = try f.resolveInst(un_op);
1984 try writer.writeAll("return ");1988 try writer.writeAll("return ");
1985 try f.writeCValue(writer, operand);1989 try f.writeCValue(writer, operand);
...@@ -1995,7 +1999,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1995,7 +1999,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
1995 const writer = f.object.writer();1999 const writer = f.object.writer();
1996 const ptr_ty = f.air.typeOf(un_op);2000 const ptr_ty = f.air.typeOf(un_op);
1997 const ret_ty = ptr_ty.childType();2001 const ret_ty = ptr_ty.childType();
1998 if (!ret_ty.isFnOrHasRuntimeBits()) {2002 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
1999 try writer.writeAll("return;\n");2003 try writer.writeAll("return;\n");
2000 }2004 }
2001 const ptr = try f.resolveInst(un_op);2005 const ptr = try f.resolveInst(un_op);
...@@ -2561,7 +2565,18 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2561,7 +2565,18 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
2561 return local;2565 return local;
2562}2566}
25632567
2564fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {2568fn airCall(
2569 f: *Function,
2570 inst: Air.Inst.Index,
2571 modifier: std.builtin.CallOptions.Modifier,
2572) !CValue {
2573 switch (modifier) {
2574 .auto => {},
2575 .always_tail => return f.fail("TODO: C backend: call with always_tail attribute", .{}),
2576 .never_tail => return f.fail("TODO: C backend: call with never_tail attribute", .{}),
2577 .never_inline => return f.fail("TODO: C backend: call with never_inline attribute", .{}),
2578 else => unreachable,
2579 }
2565 const pl_op = f.air.instructions.items(.data)[inst].pl_op;2580 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
2566 const extra = f.air.extraData(Air.Call, pl_op.payload);2581 const extra = f.air.extraData(Air.Call, pl_op.payload);
2567 const args = @bitCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);2582 const args = @bitCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);
src/codegen/llvm.zig+64-30
...@@ -661,14 +661,19 @@ pub const Object = struct {...@@ -661,14 +661,19 @@ pub const Object = struct {
661 // If the module does not already have the function, we ignore this function call661 // If the module does not already have the function, we ignore this function call
662 // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.662 // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.
663 const llvm_global = self.decl_map.get(decl) orelse return;663 const llvm_global = self.decl_map.get(decl) orelse return;
664 const is_extern = decl.isExtern();664 if (decl.isExtern()) {
665 if (is_extern) {
666 llvm_global.setValueName(decl.name);665 llvm_global.setValueName(decl.name);
667 llvm_global.setUnnamedAddr(.False);666 llvm_global.setUnnamedAddr(.False);
668 llvm_global.setLinkage(.External);667 llvm_global.setLinkage(.External);
669 if (decl.val.castTag(.variable)) |variable| {668 if (decl.val.castTag(.variable)) |variable| {
670 if (variable.data.is_threadlocal) llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);669 if (variable.data.is_threadlocal) {
671 if (variable.data.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak);670 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
671 } else {
672 llvm_global.setThreadLocalMode(.NotThreadLocal);
673 }
674 if (variable.data.is_weak_linkage) {
675 llvm_global.setLinkage(.ExternalWeak);
676 }
672 }677 }
673 } else if (exports.len != 0) {678 } else if (exports.len != 0) {
674 const exp_name = exports[0].options.name;679 const exp_name = exports[0].options.name;
...@@ -681,7 +686,9 @@ pub const Object = struct {...@@ -681,7 +686,9 @@ pub const Object = struct {
681 .LinkOnce => llvm_global.setLinkage(.LinkOnceODR),686 .LinkOnce => llvm_global.setLinkage(.LinkOnceODR),
682 }687 }
683 if (decl.val.castTag(.variable)) |variable| {688 if (decl.val.castTag(.variable)) |variable| {
684 if (variable.data.is_threadlocal) llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);689 if (variable.data.is_threadlocal) {
690 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
691 }
685 }692 }
686 // If a Decl is exported more than one time (which is rare),693 // If a Decl is exported more than one time (which is rare),
687 // we add aliases for all but the first export.694 // we add aliases for all but the first export.
...@@ -709,6 +716,14 @@ pub const Object = struct {...@@ -709,6 +716,14 @@ pub const Object = struct {
709 llvm_global.setValueName2(fqn.ptr, fqn.len);716 llvm_global.setValueName2(fqn.ptr, fqn.len);
710 llvm_global.setLinkage(.Internal);717 llvm_global.setLinkage(.Internal);
711 llvm_global.setUnnamedAddr(.True);718 llvm_global.setUnnamedAddr(.True);
719 if (decl.val.castTag(.variable)) |variable| {
720 const single_threaded = module.comp.bin_file.options.single_threaded;
721 if (variable.data.is_threadlocal and !single_threaded) {
722 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
723 } else {
724 llvm_global.setThreadLocalMode(.NotThreadLocal);
725 }
726 }
712 }727 }
713 }728 }
714729
...@@ -937,19 +952,6 @@ pub const DeclGen = struct {...@@ -937,19 +952,6 @@ pub const DeclGen = struct {
937 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);952 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);
938 gop.value_ptr.* = llvm_global;953 gop.value_ptr.* = llvm_global;
939954
940 if (decl.isExtern()) {
941 llvm_global.setValueName(decl.name);
942 llvm_global.setUnnamedAddr(.False);
943 llvm_global.setLinkage(.External);
944 if (decl.val.castTag(.variable)) |variable| {
945 if (variable.data.is_threadlocal) llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
946 if (variable.data.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak);
947 }
948 } else {
949 llvm_global.setLinkage(.Internal);
950 llvm_global.setUnnamedAddr(.True);
951 }
952
953 return llvm_global;955 return llvm_global;
954 }956 }
955957
...@@ -1033,8 +1035,8 @@ pub const DeclGen = struct {...@@ -1033,8 +1035,8 @@ pub const DeclGen = struct {
1033 const elem_ty = ptr_info.pointee_type;1035 const elem_ty = ptr_info.pointee_type;
1034 const lower_elem_ty = switch (elem_ty.zigTypeTag()) {1036 const lower_elem_ty = switch (elem_ty.zigTypeTag()) {
1035 .Opaque, .Fn => true,1037 .Opaque, .Fn => true,
1036 .Array => elem_ty.childType().hasRuntimeBits(),1038 .Array => elem_ty.childType().hasRuntimeBitsIgnoreComptime(),
1037 else => elem_ty.hasRuntimeBits(),1039 else => elem_ty.hasRuntimeBitsIgnoreComptime(),
1038 };1040 };
1039 const llvm_elem_ty = if (lower_elem_ty)1041 const llvm_elem_ty = if (lower_elem_ty)
1040 try dg.llvmType(elem_ty)1042 try dg.llvmType(elem_ty)
...@@ -3158,7 +3160,6 @@ pub const FuncGen = struct {...@@ -3158,7 +3160,6 @@ pub const FuncGen = struct {
3158 .breakpoint => try self.airBreakpoint(inst),3160 .breakpoint => try self.airBreakpoint(inst),
3159 .ret_addr => try self.airRetAddr(inst),3161 .ret_addr => try self.airRetAddr(inst),
3160 .frame_addr => try self.airFrameAddress(inst),3162 .frame_addr => try self.airFrameAddress(inst),
3161 .call => try self.airCall(inst),
3162 .cond_br => try self.airCondBr(inst),3163 .cond_br => try self.airCondBr(inst),
3163 .intcast => try self.airIntCast(inst),3164 .intcast => try self.airIntCast(inst),
3164 .trunc => try self.airTrunc(inst),3165 .trunc => try self.airTrunc(inst),
...@@ -3175,6 +3176,11 @@ pub const FuncGen = struct {...@@ -3175,6 +3176,11 @@ pub const FuncGen = struct {
3175 .slice_ptr => try self.airSliceField(inst, 0),3176 .slice_ptr => try self.airSliceField(inst, 0),
3176 .slice_len => try self.airSliceField(inst, 1),3177 .slice_len => try self.airSliceField(inst, 1),
31773178
3179 .call => try self.airCall(inst, .Auto),
3180 .call_always_tail => try self.airCall(inst, .AlwaysTail),
3181 .call_never_tail => try self.airCall(inst, .NeverTail),
3182 .call_never_inline => try self.airCall(inst, .NeverInline),
3183
3178 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),3184 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
3179 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),3185 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
31803186
...@@ -3253,7 +3259,7 @@ pub const FuncGen = struct {...@@ -3253,7 +3259,7 @@ pub const FuncGen = struct {
3253 }3259 }
3254 }3260 }
32553261
3256 fn airCall(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3262 fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !?*const llvm.Value {
3257 const pl_op = self.air.instructions.items(.data)[inst].pl_op;3263 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3258 const extra = self.air.extraData(Air.Call, pl_op.payload);3264 const extra = self.air.extraData(Air.Call, pl_op.payload);
3259 const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);3265 const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
...@@ -3298,7 +3304,7 @@ pub const FuncGen = struct {...@@ -3298,7 +3304,7 @@ pub const FuncGen = struct {
3298 llvm_args.items.ptr,3304 llvm_args.items.ptr,
3299 @intCast(c_uint, llvm_args.items.len),3305 @intCast(c_uint, llvm_args.items.len),
3300 toLlvmCallConv(zig_fn_ty.fnCallingConvention(), target),3306 toLlvmCallConv(zig_fn_ty.fnCallingConvention(), target),
3301 .Auto,3307 attr,
3302 "",3308 "",
3303 );3309 );
33043310
...@@ -4063,6 +4069,34 @@ pub const FuncGen = struct {...@@ -4063,6 +4069,34 @@ pub const FuncGen = struct {
4063 }4069 }
4064 const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];4070 const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
40654071
4072 // hackety hacks until stage2 has proper inline asm in the frontend.
4073 var rendered_template = std.ArrayList(u8).init(self.gpa);
4074 defer rendered_template.deinit();
4075
4076 const State = enum { start, percent };
4077
4078 var state: State = .start;
4079
4080 for (asm_source) |byte| {
4081 switch (state) {
4082 .start => switch (byte) {
4083 '%' => state = .percent,
4084 else => try rendered_template.append(byte),
4085 },
4086 .percent => switch (byte) {
4087 '%' => {
4088 try rendered_template.append('%');
4089 state = .start;
4090 },
4091 else => {
4092 try rendered_template.append('%');
4093 try rendered_template.append(byte);
4094 state = .start;
4095 },
4096 },
4097 }
4098 }
4099
4066 const ret_ty = self.air.typeOfIndex(inst);4100 const ret_ty = self.air.typeOfIndex(inst);
4067 const ret_llvm_ty = try self.dg.llvmType(ret_ty);4101 const ret_llvm_ty = try self.dg.llvmType(ret_ty);
4068 const llvm_fn_ty = llvm.functionType(4102 const llvm_fn_ty = llvm.functionType(
...@@ -4073,8 +4107,8 @@ pub const FuncGen = struct {...@@ -4073,8 +4107,8 @@ pub const FuncGen = struct {
4073 );4107 );
4074 const asm_fn = llvm.getInlineAsm(4108 const asm_fn = llvm.getInlineAsm(
4075 llvm_fn_ty,4109 llvm_fn_ty,
4076 asm_source.ptr,4110 rendered_template.items.ptr,
4077 asm_source.len,4111 rendered_template.items.len,
4078 llvm_constraints.items.ptr,4112 llvm_constraints.items.ptr,
4079 llvm_constraints.items.len,4113 llvm_constraints.items.len,
4080 llvm.Bool.fromBool(is_volatile),4114 llvm.Bool.fromBool(is_volatile),
...@@ -5206,7 +5240,7 @@ pub const FuncGen = struct {...@@ -5206,7 +5240,7 @@ pub const FuncGen = struct {
5206 if (self.liveness.isUnused(inst)) return null;5240 if (self.liveness.isUnused(inst)) return null;
5207 const ptr_ty = self.air.typeOfIndex(inst);5241 const ptr_ty = self.air.typeOfIndex(inst);
5208 const pointee_type = ptr_ty.childType();5242 const pointee_type = ptr_ty.childType();
5209 if (!pointee_type.isFnOrHasRuntimeBits()) return self.dg.lowerPtrToVoid(ptr_ty);5243 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
52105244
5211 const pointee_llvm_ty = try self.dg.llvmType(pointee_type);5245 const pointee_llvm_ty = try self.dg.llvmType(pointee_type);
5212 const alloca_inst = self.buildAlloca(pointee_llvm_ty);5246 const alloca_inst = self.buildAlloca(pointee_llvm_ty);
...@@ -5220,7 +5254,7 @@ pub const FuncGen = struct {...@@ -5220,7 +5254,7 @@ pub const FuncGen = struct {
5220 if (self.liveness.isUnused(inst)) return null;5254 if (self.liveness.isUnused(inst)) return null;
5221 const ptr_ty = self.air.typeOfIndex(inst);5255 const ptr_ty = self.air.typeOfIndex(inst);
5222 const ret_ty = ptr_ty.childType();5256 const ret_ty = ptr_ty.childType();
5223 if (!ret_ty.isFnOrHasRuntimeBits()) return self.dg.lowerPtrToVoid(ptr_ty);5257 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
5224 if (self.ret_ptr) |ret_ptr| return ret_ptr;5258 if (self.ret_ptr) |ret_ptr| return ret_ptr;
5225 const ret_llvm_ty = try self.dg.llvmType(ret_ty);5259 const ret_llvm_ty = try self.dg.llvmType(ret_ty);
5226 const target = self.dg.module.getTarget();5260 const target = self.dg.module.getTarget();
...@@ -5457,7 +5491,7 @@ pub const FuncGen = struct {...@@ -5457,7 +5491,7 @@ pub const FuncGen = struct {
5457 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5491 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5458 const ptr_ty = self.air.typeOf(bin_op.lhs);5492 const ptr_ty = self.air.typeOf(bin_op.lhs);
5459 const operand_ty = ptr_ty.childType();5493 const operand_ty = ptr_ty.childType();
5460 if (!operand_ty.isFnOrHasRuntimeBits()) return null;5494 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return null;
5461 var ptr = try self.resolveInst(bin_op.lhs);5495 var ptr = try self.resolveInst(bin_op.lhs);
5462 var element = try self.resolveInst(bin_op.rhs);5496 var element = try self.resolveInst(bin_op.rhs);
5463 const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);5497 const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);
...@@ -6329,7 +6363,7 @@ pub const FuncGen = struct {...@@ -6329,7 +6363,7 @@ pub const FuncGen = struct {
63296363
6330 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {6364 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {
6331 const info = ptr_ty.ptrInfo().data;6365 const info = ptr_ty.ptrInfo().data;
6332 if (!info.pointee_type.hasRuntimeBits()) return null;6366 if (!info.pointee_type.hasRuntimeBitsIgnoreComptime()) return null;
63336367
6334 const target = self.dg.module.getTarget();6368 const target = self.dg.module.getTarget();
6335 const ptr_alignment = ptr_ty.ptrAlignment(target);6369 const ptr_alignment = ptr_ty.ptrAlignment(target);
...@@ -6384,7 +6418,7 @@ pub const FuncGen = struct {...@@ -6384,7 +6418,7 @@ pub const FuncGen = struct {
6384 ) void {6418 ) void {
6385 const info = ptr_ty.ptrInfo().data;6419 const info = ptr_ty.ptrInfo().data;
6386 const elem_ty = info.pointee_type;6420 const elem_ty = info.pointee_type;
6387 if (!elem_ty.isFnOrHasRuntimeBits()) {6421 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
6388 return;6422 return;
6389 }6423 }
6390 const target = self.dg.module.getTarget();6424 const target = self.dg.module.getTarget();
src/print_air.zig+6-1
...@@ -227,12 +227,17 @@ const Writer = struct {...@@ -227,12 +227,17 @@ const Writer = struct {
227 .ptr_elem_ptr,227 .ptr_elem_ptr,
228 => try w.writeTyPlBin(s, inst),228 => try w.writeTyPlBin(s, inst),
229229
230 .call,
231 .call_always_tail,
232 .call_never_tail,
233 .call_never_inline,
234 => try w.writeCall(s, inst),
235
230 .struct_field_ptr => try w.writeStructField(s, inst),236 .struct_field_ptr => try w.writeStructField(s, inst),
231 .struct_field_val => try w.writeStructField(s, inst),237 .struct_field_val => try w.writeStructField(s, inst),
232 .constant => try w.writeConstant(s, inst),238 .constant => try w.writeConstant(s, inst),
233 .assembly => try w.writeAssembly(s, inst),239 .assembly => try w.writeAssembly(s, inst),
234 .dbg_stmt => try w.writeDbgStmt(s, inst),240 .dbg_stmt => try w.writeDbgStmt(s, inst),
235 .call => try w.writeCall(s, inst),
236 .aggregate_init => try w.writeAggregateInit(s, inst),241 .aggregate_init => try w.writeAggregateInit(s, inst),
237 .union_init => try w.writeUnionInit(s, inst),242 .union_init => try w.writeUnionInit(s, inst),
238 .br => try w.writeBr(s, inst),243 .br => try w.writeBr(s, inst),
src/print_zir.zig+1
...@@ -1942,6 +1942,7 @@ const Writer = struct {...@@ -1942,6 +1942,7 @@ const Writer = struct {
1942 break :blk init_inst;1942 break :blk init_inst;
1943 };1943 };
1944 try self.writeFlag(stream, ", is_extern", small.is_extern);1944 try self.writeFlag(stream, ", is_extern", small.is_extern);
1945 try self.writeFlag(stream, ", is_threadlocal", small.is_threadlocal);
1945 try self.writeOptionalInstRef(stream, ", align=", align_inst);1946 try self.writeOptionalInstRef(stream, ", align=", align_inst);
1946 try self.writeOptionalInstRef(stream, ", init=", init_inst);1947 try self.writeOptionalInstRef(stream, ", init=", init_inst);
1947 try stream.writeAll("))");1948 try stream.writeAll("))");
src/type.zig+10-1
...@@ -2187,7 +2187,8 @@ pub const Type = extern union {...@@ -2187,7 +2187,8 @@ pub const Type = extern union {
2187 if (fn_info.is_generic) return false;2187 if (fn_info.is_generic) return false;
2188 if (fn_info.is_var_args) return true;2188 if (fn_info.is_var_args) return true;
2189 switch (fn_info.cc) {2189 switch (fn_info.cc) {
2190 // If there was a comptime calling convention, it should also return false here.2190 // If there was a comptime calling convention,
2191 // it should also return false here.
2191 .Inline => return false,2192 .Inline => return false,
2192 else => {},2193 else => {},
2193 }2194 }
...@@ -2198,6 +2199,14 @@ pub const Type = extern union {...@@ -2198,6 +2199,14 @@ pub const Type = extern union {
2198 }2199 }
2199 }2200 }
22002201
2202 /// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive.
2203 pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type) bool {
2204 return switch (ty.zigTypeTag()) {
2205 .Fn => true,
2206 else => return ty.hasRuntimeBitsIgnoreComptime(),
2207 };
2208 }
2209
2201 pub fn isNoReturn(self: Type) bool {2210 pub fn isNoReturn(self: Type) bool {
2202 const definitely_correct_result =2211 const definitely_correct_result =
2203 self.tag_if_small_enough != .bound_fn and2212 self.tag_if_small_enough != .bound_fn and
test/behavior/basic.zig+8-2
...@@ -720,6 +720,11 @@ test "string concatenation" {...@@ -720,6 +720,11 @@ test "string concatenation" {
720720
721test "thread local variable" {721test "thread local variable" {
722 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO722 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
723 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
724 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
725 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
726 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
727 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO
723728
724 const S = struct {729 const S = struct {
725 threadlocal var t: i32 = 1234;730 threadlocal var t: i32 = 1234;
...@@ -746,11 +751,12 @@ fn maybe(x: bool) anyerror!?u32 {...@@ -746,11 +751,12 @@ fn maybe(x: bool) anyerror!?u32 {
746}751}
747752
748test "pointer to thread local array" {753test "pointer to thread local array" {
749 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
750 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO754 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
755 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
756 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
751 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO757 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
752 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO758 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
753 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO759 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO
754760
755 const s = "Hello world";761 const s = "Hello world";
756 std.mem.copy(u8, buffer[0..], s);762 std.mem.copy(u8, buffer[0..], s);
test/behavior/bugs/7250.zig+5
...@@ -15,6 +15,11 @@ threadlocal var g_uart0 = nrfx_uart_t{...@@ -15,6 +15,11 @@ threadlocal var g_uart0 = nrfx_uart_t{
1515
16test "reference a global threadlocal variable" {16test "reference a global threadlocal variable" {
17 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO
1823
19 _ = nrfx_uart_rx(&g_uart0);24 _ = nrfx_uart_rx(&g_uart0);
20}25}
test/stage2/aarch64.zig+1-1
...@@ -159,7 +159,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -159,7 +159,7 @@ pub fn addCases(ctx: *TestContext) !void {
159 {159 {
160 var case = ctx.exe("hello world with updates", macos_aarch64);160 var case = ctx.exe("hello world with updates", macos_aarch64);
161 case.addError("", &[_][]const u8{161 case.addError("", &[_][]const u8{
162 ":99:9: error: struct 'tmp.tmp' has no member named 'main'",162 ":108:9: error: struct 'tmp.tmp' has no member named 'main'",
163 });163 });
164164
165 // Incorrect return type165 // Incorrect return type
test/stage2/x86_64.zig+2-2
...@@ -1925,7 +1925,7 @@ fn addLinuxTestCases(ctx: *TestContext) !void {...@@ -1925,7 +1925,7 @@ fn addLinuxTestCases(ctx: *TestContext) !void {
1925 var case = ctx.exe("hello world with updates", linux_x64);1925 var case = ctx.exe("hello world with updates", linux_x64);
19261926
1927 case.addError("", &[_][]const u8{1927 case.addError("", &[_][]const u8{
1928 ":99:9: error: struct 'tmp.tmp' has no member named 'main'",1928 ":108:9: error: struct 'tmp.tmp' has no member named 'main'",
1929 });1929 });
19301930
1931 // Incorrect return type1931 // Incorrect return type
...@@ -2176,7 +2176,7 @@ fn addMacOsTestCases(ctx: *TestContext) !void {...@@ -2176,7 +2176,7 @@ fn addMacOsTestCases(ctx: *TestContext) !void {
2176 {2176 {
2177 var case = ctx.exe("darwin hello world with updates", macos_x64);2177 var case = ctx.exe("darwin hello world with updates", macos_x64);
2178 case.addError("", &[_][]const u8{2178 case.addError("", &[_][]const u8{
2179 ":99:9: error: struct 'tmp.tmp' has no member named 'main'",2179 ":108:9: error: struct 'tmp.tmp' has no member named 'main'",
2180 });2180 });
21812181
2182 // Incorrect return type2182 // Incorrect return type