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 {
2222 // The self-hosted compiler is not fully capable of handling all of this start.zig file.
2323 // Until then, we have simplified logic here for self-hosted. TODO remove this once
2424 // 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 {
2635 if (builtin.output_mode == .Exe) {
2736 if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) {
2837 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
......@@ -399,6 +408,11 @@ fn posixCallMainAndExit() noreturn {
399408 // Initialize the TLS area.
400409 std.os.linux.tls.initStaticTLS(phdrs);
401410
411 if (builtin.zig_backend == .stage2_llvm) {
412 root.main();
413 exit2(0);
414 }
415
402416 // The way Linux executables represent stack size is via the PT_GNU_STACK
403417 // program header. However the kernel does not recognize it; it always gives 8 MiB.
404418 // 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 {
226226 /// Uses the `pl_op` field with the `Call` payload. operand is the callee.
227227 /// Triggers `resolveTypeLayout` on the return type of the callee.
228228 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,
229235 /// Count leading zeroes of an integer according to its representation in twos complement.
230236 /// Result type will always be an unsigned integer big enough to fit the answer.
231237 /// Uses the `ty_op` field.
......@@ -969,7 +975,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
969975
970976 .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 => {
973979 const callee_ty = air.typeOf(datas[inst].pl_op.operand);
974980 switch (callee_ty.zigTypeTag()) {
975981 .Fn => return callee_ty.fnReturnType(),
src/Liveness.zig+1-1
......@@ -399,7 +399,7 @@ fn analyzeInst(
399399 return trackOperands(a, new_set, inst, main_tomb, .{ prefetch.ptr, .none, .none });
400400 },
401401
402 .call => {
402 .call, .call_always_tail, .call_never_tail, .call_never_inline => {
403403 const inst_data = inst_datas[inst].pl_op;
404404 const callee = inst_data.operand;
405405 const extra = a.air.extraData(Air.Call, inst_data.payload);
src/Sema.zig+13-13
......@@ -4458,21 +4458,19 @@ fn analyzeCall(
44584458 );
44594459 }
44604460
4461 switch (modifier) {
4461 const call_tag: Air.Inst.Tag = switch (modifier) {
44624462 .auto,
44634463 .always_inline,
44644464 .compile_time,
44654465 .no_async,
4466 => {},
4467
4468 .async_kw,
4469 .never_tail,
4470 .never_inline,
4471 .always_tail,
4472 => return sema.fail(block, call_src, "TODO implement call with modifier {}", .{
4473 modifier,
4474 }),
4475 }
4466 => Air.Inst.Tag.call,
4467
4468 .never_tail => Air.Inst.Tag.call_never_tail,
4469 .never_inline => Air.Inst.Tag.call_never_inline,
4470 .always_tail => Air.Inst.Tag.call_always_tail,
4471
4472 .async_kw => return sema.fail(block, call_src, "TODO implement async call", .{}),
4473 };
44764474
44774475 const gpa = sema.gpa;
44784476
......@@ -4490,6 +4488,7 @@ fn analyzeCall(
44904488 func_ty_info,
44914489 ensure_result_used,
44924490 uncasted_args,
4491 call_tag,
44934492 )) |some| {
44944493 return some;
44954494 } else |err| switch (err) {
......@@ -4771,7 +4770,7 @@ fn analyzeCall(
47714770 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
47724771 args.len);
47734772 const func_inst = try block.addInst(.{
4774 .tag = .call,
4773 .tag = call_tag,
47754774 .data = .{ .pl_op = .{
47764775 .operand = func,
47774776 .payload = sema.addExtraAssumeCapacity(Air.Call{
......@@ -4798,6 +4797,7 @@ fn instantiateGenericCall(
47984797 func_ty_info: Type.Payload.Function.Data,
47994798 ensure_result_used: bool,
48004799 uncasted_args: []const Air.Inst.Ref,
4800 call_tag: Air.Inst.Tag,
48014801) CompileError!Air.Inst.Ref {
48024802 const mod = sema.mod;
48034803 const gpa = sema.gpa;
......@@ -5107,7 +5107,7 @@ fn instantiateGenericCall(
51075107 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
51085108 runtime_args_len);
51095109 const func_inst = try block.addInst(.{
5110 .tag = .call,
5110 .tag = call_tag,
51115111 .data = .{ .pl_op = .{
51125112 .operand = callee_inst,
51135113 .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 {
585585 .ret_addr => try self.airRetAddr(inst),
586586 .frame_addr => try self.airFrameAddress(inst),
587587 .fence => try self.airFence(),
588 .call => try self.airCall(inst),
589588 .cond_br => try self.airCondBr(inst),
590589 .dbg_stmt => try self.airDbgStmt(inst),
591590 .fptrunc => try self.airFptrunc(inst),
......@@ -634,6 +633,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
634633 .prefetch => try self.airPrefetch(inst),
635634 .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
637641 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
638642 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
639643 .atomic_store_release => try self.airAtomicStore(inst, .Release),
......@@ -2325,7 +2329,8 @@ fn airFence(self: *Self) !void {
23252329 //return self.finishAirBookkeeping();
23262330}
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", .{});
23292334 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
23302335 const callee = pl_op.operand;
23312336 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 {
581581 .ret_addr => try self.airRetAddr(inst),
582582 .frame_addr => try self.airFrameAddress(inst),
583583 .fence => try self.airFence(),
584 .call => try self.airCall(inst),
585584 .cond_br => try self.airCondBr(inst),
586585 .dbg_stmt => try self.airDbgStmt(inst),
587586 .fptrunc => try self.airFptrunc(inst),
......@@ -630,6 +629,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
630629 .prefetch => try self.airPrefetch(inst),
631630 .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
633637 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
634638 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
635639 .atomic_store_release => try self.airAtomicStore(inst, .Release),
......@@ -2510,7 +2514,8 @@ fn airFence(self: *Self) !void {
25102514 //return self.finishAirBookkeeping();
25112515}
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", .{});
25142519 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
25152520 const callee = pl_op.operand;
25162521 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 {
553553 .ret_addr => try self.airRetAddr(inst),
554554 .frame_addr => try self.airFrameAddress(inst),
555555 .fence => try self.airFence(),
556 .call => try self.airCall(inst),
557556 .cond_br => try self.airCondBr(inst),
558557 .dbg_stmt => try self.airDbgStmt(inst),
559558 .fptrunc => try self.airFptrunc(inst),
......@@ -602,6 +601,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
602601 .prefetch => try self.airPrefetch(inst),
603602 .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
605609 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
606610 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
607611 .atomic_store_release => try self.airAtomicStore(inst, .Release),
......@@ -1458,7 +1462,8 @@ fn airFence(self: *Self) !void {
14581462 //return self.finishAirBookkeeping();
14591463}
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", .{});
14621467 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
14631468 const fn_ty = self.air.typeOf(pl_op.operand);
14641469 const callee = pl_op.operand;
......@@ -2496,7 +2501,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
24962501 result.stack_byte_count = next_stack_offset;
24972502 result.stack_align = 16;
24982503 },
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}),
25002505 }
25012506
25022507 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 {
12181218 .breakpoint => self.airBreakpoint(inst),
12191219 .br => self.airBr(inst),
12201220 .bool_to_int => self.airBoolToInt(inst),
1221 .call => self.airCall(inst),
12221221 .cond_br => self.airCondBr(inst),
12231222 .dbg_stmt => WValue.none,
12241223 .intcast => self.airIntcast(inst),
......@@ -1227,6 +1226,11 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
12271226 .float_to_int => self.airFloatToInt(inst),
12281227 .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
12301234 .is_err => self.airIsErr(inst, .i32_ne),
12311235 .is_non_err => self.airIsErr(inst, .i32_eq),
12321236
......@@ -1375,7 +1379,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
13751379fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
13761380 const child_type = self.air.typeOfIndex(inst).childType();
13771381
1378 if (!child_type.isFnOrHasRuntimeBits()) {
1382 if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
13791383 return self.allocStack(Type.usize); // create pointer to void
13801384 }
13811385
......@@ -1401,7 +1405,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
14011405 return .none;
14021406}
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", .{});
14051410 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
14061411 const extra = self.air.extraData(Air.Call, pl_op.payload);
14071412 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 {
670670 .ret_addr => try self.airRetAddr(inst),
671671 .frame_addr => try self.airFrameAddress(inst),
672672 .fence => try self.airFence(),
673 .call => try self.airCall(inst),
674673 .cond_br => try self.airCondBr(inst),
675674 .dbg_stmt => try self.airDbgStmt(inst),
676675 .fptrunc => try self.airFptrunc(inst),
......@@ -719,6 +718,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
719718 .prefetch => try self.airPrefetch(inst),
720719 .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
722726 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
723727 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
724728 .atomic_store_release => try self.airAtomicStore(inst, .Release),
......@@ -3263,7 +3267,8 @@ fn airFence(self: *Self) !void {
32633267 //return self.finishAirBookkeeping();
32643268}
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", .{});
32673272 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
32683273 const callee = pl_op.operand;
32693274 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
16851685 .assembly => try airAsm(f, inst),
16861686 .block => try airBlock(f, inst),
16871687 .bitcast => try airBitcast(f, inst),
1688 .call => try airCall(f, inst),
16891688 .dbg_stmt => try airDbgStmt(f, inst),
16901689 .intcast => try airIntCast(f, inst),
16911690 .trunc => try airTrunc(f, inst),
......@@ -1721,6 +1720,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
17211720 .union_init => try airUnionInit(f, inst),
17221721 .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
17241728 .int_to_float,
17251729 .float_to_int,
17261730 .fptrunc,
......@@ -1904,7 +1908,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
19041908
19051909 const elem_type = inst_ty.elemType();
19061910 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
1907 if (!elem_type.isFnOrHasRuntimeBits()) {
1911 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
19081912 return CValue.undefined_ptr;
19091913 }
19101914
......@@ -1979,7 +1983,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
19791983fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
19801984 const un_op = f.air.instructions.items(.data)[inst].un_op;
19811985 const writer = f.object.writer();
1982 if (f.air.typeOf(un_op).isFnOrHasRuntimeBits()) {
1986 if (f.air.typeOf(un_op).isFnOrHasRuntimeBitsIgnoreComptime()) {
19831987 const operand = try f.resolveInst(un_op);
19841988 try writer.writeAll("return ");
19851989 try f.writeCValue(writer, operand);
......@@ -1995,7 +1999,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
19951999 const writer = f.object.writer();
19962000 const ptr_ty = f.air.typeOf(un_op);
19972001 const ret_ty = ptr_ty.childType();
1998 if (!ret_ty.isFnOrHasRuntimeBits()) {
2002 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
19992003 try writer.writeAll("return;\n");
20002004 }
20012005 const ptr = try f.resolveInst(un_op);
......@@ -2561,7 +2565,18 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
25612565 return local;
25622566}
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 }
25652580 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
25662581 const extra = f.air.extraData(Air.Call, pl_op.payload);
25672582 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 {
661661 // If the module does not already have the function, we ignore this function call
662662 // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.
663663 const llvm_global = self.decl_map.get(decl) orelse return;
664 const is_extern = decl.isExtern();
665 if (is_extern) {
664 if (decl.isExtern()) {
666665 llvm_global.setValueName(decl.name);
667666 llvm_global.setUnnamedAddr(.False);
668667 llvm_global.setLinkage(.External);
669668 if (decl.val.castTag(.variable)) |variable| {
670 if (variable.data.is_threadlocal) llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
671 if (variable.data.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak);
669 if (variable.data.is_threadlocal) {
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 }
672677 }
673678 } else if (exports.len != 0) {
674679 const exp_name = exports[0].options.name;
......@@ -681,7 +686,9 @@ pub const Object = struct {
681686 .LinkOnce => llvm_global.setLinkage(.LinkOnceODR),
682687 }
683688 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 }
685692 }
686693 // If a Decl is exported more than one time (which is rare),
687694 // we add aliases for all but the first export.
......@@ -709,6 +716,14 @@ pub const Object = struct {
709716 llvm_global.setValueName2(fqn.ptr, fqn.len);
710717 llvm_global.setLinkage(.Internal);
711718 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 }
712727 }
713728 }
714729
......@@ -937,19 +952,6 @@ pub const DeclGen = struct {
937952 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);
938953 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
953955 return llvm_global;
954956 }
955957
......@@ -1033,8 +1035,8 @@ pub const DeclGen = struct {
10331035 const elem_ty = ptr_info.pointee_type;
10341036 const lower_elem_ty = switch (elem_ty.zigTypeTag()) {
10351037 .Opaque, .Fn => true,
1036 .Array => elem_ty.childType().hasRuntimeBits(),
1037 else => elem_ty.hasRuntimeBits(),
1038 .Array => elem_ty.childType().hasRuntimeBitsIgnoreComptime(),
1039 else => elem_ty.hasRuntimeBitsIgnoreComptime(),
10381040 };
10391041 const llvm_elem_ty = if (lower_elem_ty)
10401042 try dg.llvmType(elem_ty)
......@@ -3158,7 +3160,6 @@ pub const FuncGen = struct {
31583160 .breakpoint => try self.airBreakpoint(inst),
31593161 .ret_addr => try self.airRetAddr(inst),
31603162 .frame_addr => try self.airFrameAddress(inst),
3161 .call => try self.airCall(inst),
31623163 .cond_br => try self.airCondBr(inst),
31633164 .intcast => try self.airIntCast(inst),
31643165 .trunc => try self.airTrunc(inst),
......@@ -3175,6 +3176,11 @@ pub const FuncGen = struct {
31753176 .slice_ptr => try self.airSliceField(inst, 0),
31763177 .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
31783184 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
31793185 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
31803186
......@@ -3253,7 +3259,7 @@ pub const FuncGen = struct {
32533259 }
32543260 }
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 {
32573263 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
32583264 const extra = self.air.extraData(Air.Call, pl_op.payload);
32593265 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 {
32983304 llvm_args.items.ptr,
32993305 @intCast(c_uint, llvm_args.items.len),
33003306 toLlvmCallConv(zig_fn_ty.fnCallingConvention(), target),
3301 .Auto,
3307 attr,
33023308 "",
33033309 );
33043310
......@@ -4063,6 +4069,34 @@ pub const FuncGen = struct {
40634069 }
40644070 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
40664100 const ret_ty = self.air.typeOfIndex(inst);
40674101 const ret_llvm_ty = try self.dg.llvmType(ret_ty);
40684102 const llvm_fn_ty = llvm.functionType(
......@@ -4073,8 +4107,8 @@ pub const FuncGen = struct {
40734107 );
40744108 const asm_fn = llvm.getInlineAsm(
40754109 llvm_fn_ty,
4076 asm_source.ptr,
4077 asm_source.len,
4110 rendered_template.items.ptr,
4111 rendered_template.items.len,
40784112 llvm_constraints.items.ptr,
40794113 llvm_constraints.items.len,
40804114 llvm.Bool.fromBool(is_volatile),
......@@ -5206,7 +5240,7 @@ pub const FuncGen = struct {
52065240 if (self.liveness.isUnused(inst)) return null;
52075241 const ptr_ty = self.air.typeOfIndex(inst);
52085242 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
52115245 const pointee_llvm_ty = try self.dg.llvmType(pointee_type);
52125246 const alloca_inst = self.buildAlloca(pointee_llvm_ty);
......@@ -5220,7 +5254,7 @@ pub const FuncGen = struct {
52205254 if (self.liveness.isUnused(inst)) return null;
52215255 const ptr_ty = self.air.typeOfIndex(inst);
52225256 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);
52245258 if (self.ret_ptr) |ret_ptr| return ret_ptr;
52255259 const ret_llvm_ty = try self.dg.llvmType(ret_ty);
52265260 const target = self.dg.module.getTarget();
......@@ -5457,7 +5491,7 @@ pub const FuncGen = struct {
54575491 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
54585492 const ptr_ty = self.air.typeOf(bin_op.lhs);
54595493 const operand_ty = ptr_ty.childType();
5460 if (!operand_ty.isFnOrHasRuntimeBits()) return null;
5494 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return null;
54615495 var ptr = try self.resolveInst(bin_op.lhs);
54625496 var element = try self.resolveInst(bin_op.rhs);
54635497 const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);
......@@ -6329,7 +6363,7 @@ pub const FuncGen = struct {
63296363
63306364 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {
63316365 const info = ptr_ty.ptrInfo().data;
6332 if (!info.pointee_type.hasRuntimeBits()) return null;
6366 if (!info.pointee_type.hasRuntimeBitsIgnoreComptime()) return null;
63336367
63346368 const target = self.dg.module.getTarget();
63356369 const ptr_alignment = ptr_ty.ptrAlignment(target);
......@@ -6384,7 +6418,7 @@ pub const FuncGen = struct {
63846418 ) void {
63856419 const info = ptr_ty.ptrInfo().data;
63866420 const elem_ty = info.pointee_type;
6387 if (!elem_ty.isFnOrHasRuntimeBits()) {
6421 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
63886422 return;
63896423 }
63906424 const target = self.dg.module.getTarget();
src/print_air.zig+6-1
......@@ -227,12 +227,17 @@ const Writer = struct {
227227 .ptr_elem_ptr,
228228 => 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
230236 .struct_field_ptr => try w.writeStructField(s, inst),
231237 .struct_field_val => try w.writeStructField(s, inst),
232238 .constant => try w.writeConstant(s, inst),
233239 .assembly => try w.writeAssembly(s, inst),
234240 .dbg_stmt => try w.writeDbgStmt(s, inst),
235 .call => try w.writeCall(s, inst),
236241 .aggregate_init => try w.writeAggregateInit(s, inst),
237242 .union_init => try w.writeUnionInit(s, inst),
238243 .br => try w.writeBr(s, inst),
src/print_zir.zig+1
......@@ -1942,6 +1942,7 @@ const Writer = struct {
19421942 break :blk init_inst;
19431943 };
19441944 try self.writeFlag(stream, ", is_extern", small.is_extern);
1945 try self.writeFlag(stream, ", is_threadlocal", small.is_threadlocal);
19451946 try self.writeOptionalInstRef(stream, ", align=", align_inst);
19461947 try self.writeOptionalInstRef(stream, ", init=", init_inst);
19471948 try stream.writeAll("))");
src/type.zig+10-1
......@@ -2187,7 +2187,8 @@ pub const Type = extern union {
21872187 if (fn_info.is_generic) return false;
21882188 if (fn_info.is_var_args) return true;
21892189 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.
21912192 .Inline => return false,
21922193 else => {},
21932194 }
......@@ -2198,6 +2199,14 @@ pub const Type = extern union {
21982199 }
21992200 }
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
22012210 pub fn isNoReturn(self: Type) bool {
22022211 const definitely_correct_result =
22032212 self.tag_if_small_enough != .bound_fn and
test/behavior/basic.zig+8-2
......@@ -720,6 +720,11 @@ test "string concatenation" {
720720
721721test "thread local variable" {
722722 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
724729 const S = struct {
725730 threadlocal var t: i32 = 1234;
......@@ -746,11 +751,12 @@ fn maybe(x: bool) anyerror!?u32 {
746751}
747752
748753test "pointer to thread local array" {
749 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
750754 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
751757 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
752758 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
753 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
759 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO
754760
755761 const s = "Hello world";
756762 std.mem.copy(u8, buffer[0..], s);
test/behavior/bugs/7250.zig+5
......@@ -15,6 +15,11 @@ threadlocal var g_uart0 = nrfx_uart_t{
1515
1616test "reference a global threadlocal variable" {
1717 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
1924 _ = nrfx_uart_rx(&g_uart0);
2025}
test/stage2/aarch64.zig+1-1
......@@ -159,7 +159,7 @@ pub fn addCases(ctx: *TestContext) !void {
159159 {
160160 var case = ctx.exe("hello world with updates", macos_aarch64);
161161 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'",
163163 });
164164
165165 // Incorrect return type
test/stage2/x86_64.zig+2-2
......@@ -1925,7 +1925,7 @@ fn addLinuxTestCases(ctx: *TestContext) !void {
19251925 var case = ctx.exe("hello world with updates", linux_x64);
19261926
19271927 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'",
19291929 });
19301930
19311931 // Incorrect return type
......@@ -2176,7 +2176,7 @@ fn addMacOsTestCases(ctx: *TestContext) !void {
21762176 {
21772177 var case = ctx.exe("darwin hello world with updates", macos_x64);
21782178 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'",
21802180 });
21812181
21822182 // Incorrect return type