| author | |
| committer | |
| log | 078037ab9b410fa13a86eabdfc30918fc83cdcf3 |
| tree | b5e80992e82d015393872fcc57911b03ca7211fd |
| parent | b28b3f6f7b1dd4c3c8a0f3d3a6305a84daed8ead |
* 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 once | 23 | // 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); |
| 401 | 410 | ||
| 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_STACK | 416 | // 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 setrlimit | 418 | // 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 { |
| 969 | 975 | ||
| 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), |
| 971 | 977 | ||
| 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 | }, |
| 401 | 401 | ||
| 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 | } |
| 4460 | 4460 | ||
| 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, |
| 4467 | 4467 | ||
| 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 | } | ||
| 4476 | 4474 | ||
| 4477 | const gpa = sema.gpa; | 4475 | const gpa = sema.gpa; |
| 4478 | 4476 | ||
| ... | @@ -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), |
| 636 | 635 | ||
| 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 | } |
| 2327 | 2331 | ||
| 2328 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { | 2332 | fn 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), |
| 632 | 631 | ||
| 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 | } |
| 2512 | 2516 | ||
| 2513 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { | 2517 | fn 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), |
| 604 | 603 | ||
| 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 | } |
| 1460 | 1464 | ||
| 1461 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { | 1465 | fn 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 | } |
| 2501 | 2506 | ||
| 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), |
| 1229 | 1228 | ||
| 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), |
| 1232 | 1236 | ||
| ... | @@ -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 { |
| 1375 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 1379 | fn 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(); |
| 1377 | 1381 | ||
| 1378 | if (!child_type.isFnOrHasRuntimeBits()) { | 1382 | if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime()) { |
| 1379 | return self.allocStack(Type.usize); // create pointer to void | 1383 | return self.allocStack(Type.usize); // create pointer to void |
| 1380 | } | 1384 | } |
| 1381 | 1385 | ||
| ... | @@ -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 | } |
| 1403 | 1407 | ||
| 1404 | fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 1408 | fn 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), |
| 721 | 720 | ||
| 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 | } |
| 3265 | 3269 | ||
| 3266 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { | 3270 | fn 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), |
| 1723 | 1722 | ||
| 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 { |
| 1904 | 1908 | ||
| 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 | } |
| 1910 | 1914 | ||
| ... | @@ -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 { |
| 1979 | fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { | 1983 | fn 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 | } |
| 2563 | 2567 | ||
| 2564 | fn airCall(f: *Function, inst: Air.Inst.Index) !CValue { | 2568 | fn 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 call | 661 | // 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 | } |
| 714 | 729 | ||
| ... | @@ -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; |
| 939 | 954 | ||
| 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 | } |
| 955 | 957 | ||
| ... | @@ -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), |
| 3177 | 3178 | ||
| 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), |
| 3180 | 3186 | ||
| ... | @@ -3253,7 +3259,7 @@ pub const FuncGen = struct { | ... | @@ -3253,7 +3259,7 @@ pub const FuncGen = struct { |
| 3253 | } | 3259 | } |
| 3254 | } | 3260 | } |
| 3255 | 3261 | ||
| 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 | ); |
| 3304 | 3310 | ||
| ... | @@ -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]; |
| 4065 | 4071 | ||
| 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); |
| 5210 | 5244 | ||
| 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 { |
| 6329 | 6363 | ||
| 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; |
| 6333 | 6367 | ||
| 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), |
| 229 | 229 | ||
| 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 | } |
| 2200 | 2201 | ||
| 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 and | 2212 | 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" { |
| 720 | 720 | ||
| 721 | test "thread local variable" { | 721 | test "thread local variable" { |
| 722 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 722 | 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 | ||
| 723 | 728 | ||
| 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 | } |
| 747 | 752 | ||
| 748 | test "pointer to thread local array" { | 753 | test "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; // TODO | 754 | 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; // TODO | 757 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 752 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 758 | 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 |
| 754 | 760 | ||
| 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{ |
| 15 | 15 | ||
| 16 | test "reference a global threadlocal variable" { | 16 | test "reference a global threadlocal variable" { |
| 17 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 17 | 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 | ||
| 18 | 23 | ||
| 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 | }); |
| 164 | 164 | ||
| 165 | // Incorrect return type | 165 | // 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); |
| 1926 | 1926 | ||
| 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 | }); |
| 1930 | 1930 | ||
| 1931 | // Incorrect return type | 1931 | // 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 | }); |
| 2181 | 2181 | ||
| 2182 | // Incorrect return type | 2182 | // Incorrect return type |