| author | |
| committer | |
| log | 2322d45d80a88730b356b6a2b0101bcffb5a0afd |
| tree | f35786acf74d59974d4acd6303b08875f5bb649c |
| parent | 07f05426fc0c28ad19f87002d5d4d0366e54b7c9 |
| parent | 91dce64d10ec0da057c1bdceb586e56f7d265880 |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31672
Reviewed-by: Andrew Kelley <andrew@ziglang.org>5 files changed, 228 insertions(+), 44 deletions(-)
lib/std/Build/Step/Compile.zig+18| ... | ... | @@ -219,6 +219,8 @@ generated_docs: ?*GeneratedFile, |
| 219 | 219 | generated_asm: ?*GeneratedFile, |
| 220 | 220 | generated_bin: ?*GeneratedFile, |
| 221 | 221 | generated_pdb: ?*GeneratedFile, |
| 222 | // hack for stage2_x86_64 + coff | |
| 223 | generated_compiler_rt_dyn_lib: ?*GeneratedFile, | |
| 222 | 224 | generated_implib: ?*GeneratedFile, |
| 223 | 225 | generated_llvm_bc: ?*GeneratedFile, |
| 224 | 226 | generated_llvm_ir: ?*GeneratedFile, |
| ... | ... | @@ -441,6 +443,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 441 | 443 | .generated_asm = null, |
| 442 | 444 | .generated_bin = null, |
| 443 | 445 | .generated_pdb = null, |
| 446 | .generated_compiler_rt_dyn_lib = null, | |
| 444 | 447 | .generated_implib = null, |
| 445 | 448 | .generated_llvm_bc = null, |
| 446 | 449 | .generated_llvm_ir = null, |
| ... | ... | @@ -691,6 +694,13 @@ pub fn producesPdbFile(compile: *Compile) bool { |
| 691 | 694 | return compile.isDynamicLibrary() or compile.kind == .exe or compile.kind == .@"test"; |
| 692 | 695 | } |
| 693 | 696 | |
| 697 | pub fn producesCompilerRtDynLib(compile: *Compile) bool { | |
| 698 | if (compile.rootModuleTarget().ofmt != .coff) return false; | |
| 699 | if (compile.bundle_compiler_rt orelse (compile.kind == .exe or compile.isDynamicLibrary())) | |
| 700 | return compile.use_llvm == false; | |
| 701 | return false; | |
| 702 | } | |
| 703 | ||
| 694 | 704 | pub fn producesImplib(compile: *Compile) bool { |
| 695 | 705 | return compile.isDll(); |
| 696 | 706 | } |
| ... | ... | @@ -869,6 +879,12 @@ pub fn getEmittedPdb(compile: *Compile) LazyPath { |
| 869 | 879 | return compile.getEmittedFileGeneric(&compile.generated_pdb); |
| 870 | 880 | } |
| 871 | 881 | |
| 882 | /// Returns the generated compiler_rt dynamic library. | |
| 883 | /// This is a hack for stage2_x86_64 + coff. | |
| 884 | pub fn getEmittedCompilerRtDynLib(compile: *Compile) ?LazyPath { | |
| 885 | return compile.getEmittedFileGeneric(&compile.generated_compiler_rt_dyn_lib); | |
| 886 | } | |
| 887 | ||
| 872 | 888 | /// Returns the path to the generated documentation directory. |
| 873 | 889 | pub fn getEmittedDocs(compile: *Compile) LazyPath { |
| 874 | 890 | return compile.getEmittedFileGeneric(&compile.generated_docs); |
| ... | ... | @@ -1794,6 +1810,8 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 1794 | 1810 | // zig fmt: off |
| 1795 | 1811 | if (compile.generated_bin) |lp| lp.path = compile.outputPath(output_dir, .bin); |
| 1796 | 1812 | if (compile.generated_pdb) |lp| lp.path = compile.outputPath(output_dir, .pdb); |
| 1813 | // hack for stage2_x86_64 + coff | |
| 1814 | if (compile.generated_compiler_rt_dyn_lib) |lp| lp.path = compile.outputPath(output_dir, .compiler_rt_dyn_lib); | |
| 1797 | 1815 | if (compile.generated_implib) |lp| lp.path = compile.outputPath(output_dir, .implib); |
| 1798 | 1816 | if (compile.generated_h) |lp| lp.path = compile.outputPath(output_dir, .h); |
| 1799 | 1817 | if (compile.generated_docs) |lp| lp.path = compile.outputPath(output_dir, .docs); |
lib/std/Build/Step/InstallArtifact.zig+18| ... | ... | @@ -17,6 +17,10 @@ emitted_implib: ?LazyPath, |
| 17 | 17 | pdb_dir: ?InstallDir, |
| 18 | 18 | emitted_pdb: ?LazyPath, |
| 19 | 19 | |
| 20 | // hack for stage2_x86_64 + coff | |
| 21 | compiler_rt_dyn_lib_dir: ?InstallDir, | |
| 22 | emitted_compiler_rt_dyn_lib: ?LazyPath, | |
| 23 | ||
| 20 | 24 | h_dir: ?InstallDir, |
| 21 | 25 | emitted_h: ?LazyPath, |
| 22 | 26 | |
| ... | ... | @@ -35,6 +39,7 @@ pub const Options = struct { |
| 35 | 39 | /// Which installation directory to put the main output file into. |
| 36 | 40 | dest_dir: Dir = .default, |
| 37 | 41 | pdb_dir: Dir = .default, |
| 42 | compiler_rt_dyn_lib_dir: Dir = .default, | |
| 38 | 43 | h_dir: Dir = .default, |
| 39 | 44 | implib_dir: Dir = .default, |
| 40 | 45 | |
| ... | ... | @@ -75,6 +80,11 @@ pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *Ins |
| 75 | 80 | .default => if (artifact.producesPdbFile()) dest_dir else null, |
| 76 | 81 | .override => |o| o, |
| 77 | 82 | }, |
| 83 | .compiler_rt_dyn_lib_dir = switch (options.compiler_rt_dyn_lib_dir) { | |
| 84 | .disabled => null, | |
| 85 | .default => if (artifact.producesCompilerRtDynLib()) dest_dir else null, | |
| 86 | .override => |o| o, | |
| 87 | }, | |
| 78 | 88 | .h_dir = switch (options.h_dir) { |
| 79 | 89 | .disabled => null, |
| 80 | 90 | .default => if (artifact.kind == .lib) .header else null, |
| ... | ... | @@ -98,6 +108,7 @@ pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *Ins |
| 98 | 108 | |
| 99 | 109 | .emitted_bin = null, |
| 100 | 110 | .emitted_pdb = null, |
| 111 | .emitted_compiler_rt_dyn_lib = null, | |
| 101 | 112 | .emitted_h = null, |
| 102 | 113 | .emitted_implib = null, |
| 103 | 114 | |
| ... | ... | @@ -107,6 +118,7 @@ pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *Ins |
| 107 | 118 | install_artifact.step.dependOn(&artifact.step); |
| 108 | 119 | |
| 109 | 120 | if (install_artifact.dest_dir != null) install_artifact.emitted_bin = artifact.getEmittedBin(); |
| 121 | if (install_artifact.compiler_rt_dyn_lib_dir != null) install_artifact.emitted_compiler_rt_dyn_lib = artifact.getEmittedCompilerRtDynLib(); | |
| 110 | 122 | if (install_artifact.pdb_dir != null) install_artifact.emitted_pdb = artifact.getEmittedPdb(); |
| 111 | 123 | // https://github.com/ziglang/zig/issues/9698 |
| 112 | 124 | //if (install_artifact.h_dir != null) install_artifact.emitted_h = artifact.getEmittedH(); |
| ... | ... | @@ -135,6 +147,12 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 135 | 147 | install_artifact.artifact.installed_path = full_dest_path; |
| 136 | 148 | } |
| 137 | 149 | |
| 150 | if (install_artifact.compiler_rt_dyn_lib_dir) |compiler_rt_dir| { | |
| 151 | const full_compiler_rt_path = b.getInstallPath(compiler_rt_dir, install_artifact.emitted_compiler_rt_dyn_lib.?.basename(b, step)); | |
| 152 | const p = try step.installFile(install_artifact.emitted_compiler_rt_dyn_lib.?, full_compiler_rt_path); | |
| 153 | all_cached = all_cached and p == .fresh; | |
| 154 | } | |
| 155 | ||
| 138 | 156 | if (install_artifact.implib_dir) |implib_dir| { |
| 139 | 157 | const full_implib_path = b.getInstallPath(implib_dir, install_artifact.emitted_implib.?.basename(b, step)); |
| 140 | 158 | const p = try step.installFile(install_artifact.emitted_implib.?, full_implib_path); |
lib/std/zig.zig+4| ... | ... | @@ -986,11 +986,14 @@ pub const EmitArtifact = enum { |
| 986 | 986 | docs, |
| 987 | 987 | pdb, |
| 988 | 988 | h, |
| 989 | compiler_rt_dyn_lib, | |
| 989 | 990 | |
| 990 | 991 | /// If using `Server` to communicate with the compiler, it will place requested artifacts in |
| 991 | 992 | /// paths under the output directory, where those paths are named according to this function. |
| 992 | 993 | /// Returned string is allocated with `gpa` and owned by the caller. |
| 993 | 994 | pub fn cacheName(ea: EmitArtifact, gpa: Allocator, opts: BinNameOptions) Allocator.Error![]const u8 { |
| 995 | // hack for stage2_x86_64 + coff. See Coff.flush. | |
| 996 | if (ea == .compiler_rt_dyn_lib) return "compiler_rt.dll"; | |
| 994 | 997 | const suffix: []const u8 = switch (ea) { |
| 995 | 998 | .bin => return binNameAlloc(gpa, opts), |
| 996 | 999 | .@"asm" => ".s", |
| ... | ... | @@ -1000,6 +1003,7 @@ pub const EmitArtifact = enum { |
| 1000 | 1003 | .docs => "-docs", |
| 1001 | 1004 | .pdb => ".pdb", |
| 1002 | 1005 | .h => ".h", |
| 1006 | .compiler_rt_dyn_lib => unreachable, | |
| 1003 | 1007 | }; |
| 1004 | 1008 | return std.fmt.allocPrint(gpa, "{s}{s}", .{ opts.root_name, suffix }); |
| 1005 | 1009 | } |
src/codegen/x86_64/CodeGen.zig+135-39| ... | ... | @@ -2049,7 +2049,16 @@ fn gen( |
| 2049 | 2049 | |
| 2050 | 2050 | self.performReloc(skip_sse_reloc); |
| 2051 | 2051 | }, |
| 2052 | .x86_64_win => return self.fail("TODO implement gen var arg function for Win64", .{}), | |
| 2052 | .x86_64_win => { | |
| 2053 | for (abi.Win64.c_abi_int_param_regs[0..], 0..) |reg, reg_i| | |
| 2054 | try self.genSetMem( | |
| 2055 | .{ .frame = .args_frame }, | |
| 2056 | @intCast(reg_i * 8), | |
| 2057 | .usize, | |
| 2058 | .{ .register = reg }, | |
| 2059 | .{}, | |
| 2060 | ); | |
| 2061 | }, | |
| 2053 | 2062 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 2054 | 2063 | }; |
| 2055 | 2064 | |
| ... | ... | @@ -176020,12 +176029,22 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 176020 | 176029 | .indirect => |reg_off| try self.register_manager.getReg(reg_off.reg, null), |
| 176021 | 176030 | else => unreachable, |
| 176022 | 176031 | } |
| 176023 | for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, *frame_index| | |
| 176032 | for (call_info.args, arg_types, args, frame_indices, 0..) |dst_arg, arg_ty, src_arg, *frame_index, arg_i| | |
| 176024 | 176033 | switch (dst_arg) { |
| 176025 | 176034 | .none => {}, |
| 176026 | 176035 | .register => |reg| { |
| 176027 | 176036 | try self.register_manager.getReg(reg, null); |
| 176028 | 176037 | try reg_locks.append(self.register_manager.lockReg(reg)); |
| 176038 | ||
| 176039 | if (fn_info.is_var_args and | |
| 176040 | fn_info.cc == .x86_64_win and | |
| 176041 | reg.class() == .sse and | |
| 176042 | arg_i < abi.Win64.c_abi_int_param_regs.len) | |
| 176043 | { | |
| 176044 | // Floating point arguments must be duplicated into the equivalent integer registers on this ABI | |
| 176045 | const int_reg = abi.Win64.c_abi_int_param_regs[arg_i]; | |
| 176046 | try reg_locks.append(self.register_manager.lockReg(int_reg)); | |
| 176047 | } | |
| 176029 | 176048 | }, |
| 176030 | 176049 | .register_pair => |regs| { |
| 176031 | 176050 | for (regs) |reg| try self.register_manager.getReg(reg, null); |
| ... | ... | @@ -176129,7 +176148,7 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 176129 | 176148 | else => unreachable, |
| 176130 | 176149 | } |
| 176131 | 176150 | |
| 176132 | for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, frame_index| | |
| 176151 | for (call_info.args, arg_types, args, frame_indices, 0..) |dst_arg, arg_ty, src_arg, frame_index, arg_i| | |
| 176133 | 176152 | switch (dst_arg) { |
| 176134 | 176153 | .none, .load_frame => {}, |
| 176135 | 176154 | .register => |dst_reg| switch (fn_info.cc) { |
| ... | ... | @@ -176144,6 +176163,16 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 176144 | 176163 | try self.genSetReg(dst_alias, promoted_ty, src_arg, opts); |
| 176145 | 176164 | if (promoted_ty.toIntern() != arg_ty.toIntern()) |
| 176146 | 176165 | try self.truncateRegister(arg_ty, dst_alias); |
| 176166 | ||
| 176167 | if (fn_info.is_var_args and | |
| 176168 | fn_info.cc == .x86_64_win and | |
| 176169 | dst_reg.class() == .sse and | |
| 176170 | arg_i < abi.Win64.c_abi_int_param_regs.len) | |
| 176171 | { | |
| 176172 | const int_dst_reg = abi.Win64.c_abi_int_param_regs[arg_i]; | |
| 176173 | const int_dst_alias = registerAlias(int_dst_reg, promoted_abi_size); | |
| 176174 | try self.genSetReg(int_dst_alias, promoted_ty, .{ .register = dst_alias }, opts); | |
| 176175 | } | |
| 176147 | 176176 | }, |
| 176148 | 176177 | }, |
| 176149 | 176178 | .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg, opts), |
| ... | ... | @@ -176180,7 +176209,8 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 176180 | 176209 | else => unreachable, |
| 176181 | 176210 | }; |
| 176182 | 176211 | |
| 176183 | if (fn_info.is_var_args) try self.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count)); | |
| 176212 | if (fn_info.is_var_args and fn_info.cc == .x86_64_sysv) | |
| 176213 | try self.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count)); | |
| 176184 | 176214 | |
| 176185 | 176215 | // Due to incremental compilation, how function calls are generated depends |
| 176186 | 176216 | // on linking. |
| ... | ... | @@ -180792,7 +180822,18 @@ fn airVaStart(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 180792 | 180822 | field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu)); |
| 180793 | 180823 | break :result .{ .load_frame = .{ .index = dst_fi } }; |
| 180794 | 180824 | }, |
| 180795 | .x86_64_win => return self.fail("TODO implement c_va_start for Win64", .{}), | |
| 180825 | .x86_64_win => result: { | |
| 180826 | const dst_fi = try self.allocFrameIndex(.initSpill(va_list_ty, zcu)); | |
| 180827 | const fn_info = zcu.typeToFunc(self.fn_type).?; | |
| 180828 | try self.genSetMem( | |
| 180829 | .{ .frame = dst_fi }, | |
| 180830 | 0, | |
| 180831 | ptr_anyopaque_ty, | |
| 180832 | .{ .lea_frame = .{ .index = .args_frame, .off = @intCast(fn_info.param_types.len * 8) } }, | |
| 180833 | .{}, | |
| 180834 | ); | |
| 180835 | break :result .{ .load_frame = .{ .index = dst_fi } }; | |
| 180836 | }, | |
| 180796 | 180837 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 180797 | 180838 | }; |
| 180798 | 180839 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| ... | ... | @@ -180931,48 +180972,103 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 180931 | 180972 | break :result dst_mcv; |
| 180932 | 180973 | } |
| 180933 | 180974 | |
| 180934 | assert(ty.toIntern() == .f32_type and promote_ty.toIntern() == .f64_type); | |
| 180935 | const dst_mcv = if (promote_mcv.isRegister()) | |
| 180936 | promote_mcv | |
| 180937 | else | |
| 180938 | try self.copyToRegisterWithInstTracking(inst, ty, promote_mcv); | |
| 180939 | const dst_reg = dst_mcv.getReg().?.to128(); | |
| 180940 | const dst_lock = self.register_manager.lockReg(dst_reg); | |
| 180941 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | |
| 180975 | try self.convertFloatVarArg(inst, ty, promote_ty, promote_mcv); | |
| 180976 | break :result promote_mcv; | |
| 180977 | }, | |
| 180978 | .x86_64_win => result: { | |
| 180979 | try self.spillEflagsIfOccupied(); | |
| 180942 | 180980 | |
| 180943 | if (self.hasFeature(.avx)) if (promote_mcv.isBase()) try self.asmRegisterRegisterMemory( | |
| 180944 | .{ .v_ss, .cvtsd2 }, | |
| 180945 | dst_reg, | |
| 180946 | dst_reg, | |
| 180947 | try promote_mcv.mem(self, .{ .size = .qword }), | |
| 180948 | ) else try self.asmRegisterRegisterRegister( | |
| 180949 | .{ .v_ss, .cvtsd2 }, | |
| 180950 | dst_reg, | |
| 180951 | dst_reg, | |
| 180952 | (if (promote_mcv.isRegister()) | |
| 180953 | promote_mcv.getReg().? | |
| 180954 | else | |
| 180955 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), | |
| 180956 | ) else if (promote_mcv.isBase()) try self.asmRegisterMemory( | |
| 180957 | .{ ._ss, .cvtsd2 }, | |
| 180958 | dst_reg, | |
| 180959 | try promote_mcv.mem(self, .{ .size = .qword }), | |
| 180960 | ) else try self.asmRegisterRegister( | |
| 180961 | .{ ._ss, .cvtsd2 }, | |
| 180962 | dst_reg, | |
| 180963 | (if (promote_mcv.isRegister()) | |
| 180964 | promote_mcv.getReg().? | |
| 180965 | else | |
| 180966 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), | |
| 180967 | ); | |
| 180981 | const promote_mcv = try self.allocTempRegOrMem(promote_ty, true); | |
| 180982 | const promote_lock = switch (promote_mcv) { | |
| 180983 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | |
| 180984 | else => null, | |
| 180985 | }; | |
| 180986 | defer if (promote_lock) |lock| self.register_manager.unlockReg(lock); | |
| 180987 | ||
| 180988 | const ptr_arg_list_reg = | |
| 180989 | try self.copyToTmpRegister(self.typeOf(ty_op.operand), .{ .air_ref = ty_op.operand }); | |
| 180990 | const ptr_arg_list_lock = self.register_manager.lockRegAssumeUnused(ptr_arg_list_reg); | |
| 180991 | defer self.register_manager.unlockReg(ptr_arg_list_lock); | |
| 180992 | ||
| 180993 | const next_arg_ptr: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg } }; | |
| 180994 | ||
| 180995 | const class = abi.classifyWindows(promote_ty, zcu, self.target, .arg); | |
| 180996 | switch (class) { | |
| 180997 | .integer, .sse => { | |
| 180998 | const next_arg_ptr_reg = try self.copyToTmpRegister(.usize, next_arg_ptr); | |
| 180999 | if (!unused) try self.genCopy(promote_ty, promote_mcv, .{ | |
| 181000 | .indirect = .{ .reg = next_arg_ptr_reg }, | |
| 181001 | }, .{}); | |
| 181002 | try self.asmRegisterMemory(.{ ._, .lea }, next_arg_ptr_reg, .{ | |
| 181003 | .base = .{ .reg = next_arg_ptr_reg.to64() }, | |
| 181004 | .mod = .{ .rm = .{ .disp = 8 } }, | |
| 181005 | }); | |
| 181006 | try self.genCopy(.usize, next_arg_ptr, .{ .register = next_arg_ptr_reg }, .{}); | |
| 181007 | }, | |
| 181008 | .memory => unreachable, | |
| 181009 | else => return self.fail("TODO implement c_va_arg for {f} on Win64", .{promote_ty.fmt(pt)}), | |
| 181010 | } | |
| 181011 | ||
| 181012 | if (unused) break :result .unreach; | |
| 181013 | if (ty.toIntern() == promote_ty.toIntern()) break :result promote_mcv; | |
| 181014 | ||
| 181015 | if (!promote_ty.isRuntimeFloat()) { | |
| 181016 | const dst_mcv = try self.allocRegOrMem(inst, true); | |
| 181017 | try self.genCopy(ty, dst_mcv, promote_mcv, .{}); | |
| 181018 | break :result dst_mcv; | |
| 181019 | } | |
| 181020 | ||
| 181021 | try self.convertFloatVarArg(inst, ty, promote_ty, promote_mcv); | |
| 180968 | 181022 | break :result promote_mcv; |
| 180969 | 181023 | }, |
| 180970 | .x86_64_win => return self.fail("TODO implement c_va_arg for Win64", .{}), | |
| 180971 | 181024 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 180972 | 181025 | }; |
| 180973 | 181026 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 180974 | 181027 | } |
| 180975 | 181028 | |
| 181029 | fn convertFloatVarArg( | |
| 181030 | self: *CodeGen, | |
| 181031 | inst: Air.Inst.Index, | |
| 181032 | ty: Type, | |
| 181033 | promote_ty: Type, | |
| 181034 | promote_mcv: MCValue, | |
| 181035 | ) !void { | |
| 181036 | assert(ty.toIntern() == .f32_type and promote_ty.toIntern() == .f64_type); | |
| 181037 | const dst_mcv = if (promote_mcv.isRegister()) | |
| 181038 | promote_mcv | |
| 181039 | else | |
| 181040 | try self.copyToRegisterWithInstTracking(inst, ty, promote_mcv); | |
| 181041 | const dst_reg = dst_mcv.getReg().?.to128(); | |
| 181042 | const dst_lock = self.register_manager.lockReg(dst_reg); | |
| 181043 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | |
| 181044 | ||
| 181045 | if (self.hasFeature(.avx)) if (promote_mcv.isBase()) try self.asmRegisterRegisterMemory( | |
| 181046 | .{ .v_ss, .cvtsd2 }, | |
| 181047 | dst_reg, | |
| 181048 | dst_reg, | |
| 181049 | try promote_mcv.mem(self, .{ .size = .qword }), | |
| 181050 | ) else try self.asmRegisterRegisterRegister( | |
| 181051 | .{ .v_ss, .cvtsd2 }, | |
| 181052 | dst_reg, | |
| 181053 | dst_reg, | |
| 181054 | (if (promote_mcv.isRegister()) | |
| 181055 | promote_mcv.getReg().? | |
| 181056 | else | |
| 181057 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), | |
| 181058 | ) else if (promote_mcv.isBase()) try self.asmRegisterMemory( | |
| 181059 | .{ ._ss, .cvtsd2 }, | |
| 181060 | dst_reg, | |
| 181061 | try promote_mcv.mem(self, .{ .size = .qword }), | |
| 181062 | ) else try self.asmRegisterRegister( | |
| 181063 | .{ ._ss, .cvtsd2 }, | |
| 181064 | dst_reg, | |
| 181065 | (if (promote_mcv.isRegister()) | |
| 181066 | promote_mcv.getReg().? | |
| 181067 | else | |
| 181068 | try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(), | |
| 181069 | ); | |
| 181070 | } | |
| 181071 | ||
| 180976 | 181072 | fn airVaCopy(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 180977 | 181073 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 180978 | 181074 | const ptr_va_list_ty = self.typeOf(ty_op.operand); |
test/behavior/var_args.zig+53-5| ... | ... | @@ -101,7 +101,7 @@ test "simple variadic function" { |
| 101 | 101 | // https://github.com/ziglang/zig/issues/14096 |
| 102 | 102 | return error.SkipZigTest; |
| 103 | 103 | } |
| 104 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; // TODO | |
| 104 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO | |
| 105 | 105 | if (builtin.cpu.arch == .s390x and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21350 |
| 106 | 106 | if (builtin.cpu.arch.isSPARC() and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23718 |
| 107 | 107 | if (builtin.cpu.arch.isRISCV() and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/25064 |
| ... | ... | @@ -163,7 +163,7 @@ test "coerce reference to var arg" { |
| 163 | 163 | // https://github.com/ziglang/zig/issues/14096 |
| 164 | 164 | return error.SkipZigTest; |
| 165 | 165 | } |
| 166 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; // TODO | |
| 166 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO | |
| 167 | 167 | if (builtin.cpu.arch == .s390x and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21350 |
| 168 | 168 | |
| 169 | 169 | const S = struct { |
| ... | ... | @@ -195,7 +195,7 @@ test "variadic functions" { |
| 195 | 195 | // https://github.com/ziglang/zig/issues/14096 |
| 196 | 196 | return error.SkipZigTest; |
| 197 | 197 | } |
| 198 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; // TODO | |
| 198 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO | |
| 199 | 199 | if (builtin.cpu.arch == .s390x and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21350 |
| 200 | 200 | if (builtin.cpu.arch.isSPARC() and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23718 |
| 201 | 201 | if (builtin.cpu.arch.isRISCV() and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/25064 |
| ... | ... | @@ -248,7 +248,7 @@ test "copy VaList" { |
| 248 | 248 | // https://github.com/ziglang/zig/issues/14096 |
| 249 | 249 | return error.SkipZigTest; |
| 250 | 250 | } |
| 251 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; // TODO | |
| 251 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO | |
| 252 | 252 | if (builtin.cpu.arch == .s390x and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21350 |
| 253 | 253 | if (builtin.cpu.arch.isSPARC() and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23718 |
| 254 | 254 | if (builtin.cpu.arch.isRISCV() and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/25064 |
| ... | ... | @@ -283,7 +283,7 @@ test "unused VaList arg" { |
| 283 | 283 | // https://github.com/ziglang/zig/issues/14096 |
| 284 | 284 | return error.SkipZigTest; |
| 285 | 285 | } |
| 286 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) { | |
| 286 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows and builtin.zig_backend == .stage2_llvm) { | |
| 287 | 287 | // https://github.com/ziglang/zig/issues/16961 |
| 288 | 288 | return error.SkipZigTest; // TODO |
| 289 | 289 | } |
| ... | ... | @@ -305,3 +305,51 @@ test "unused VaList arg" { |
| 305 | 305 | const x = S.thirdArg(0, @as(c_int, 1), @as(c_int, 2)); |
| 306 | 306 | try std.testing.expectEqual(@as(c_int, 2), x); |
| 307 | 307 | } |
| 308 | ||
| 309 | test "floating point VaList args" { | |
| 310 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 311 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 312 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 313 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 314 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/16961 | |
| 315 | ||
| 316 | // Float register arguments are handled specially on cc == .x86_64_win, so it's important that we test all 4 slots, | |
| 317 | // and pre-C23 doesn't allow a variadic function without at least one non-variadic argument. | |
| 318 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 319 | ||
| 320 | const S = struct { | |
| 321 | fn proxy(...) callconv(.c) void { | |
| 322 | var ap = @cVaStart(); | |
| 323 | defer @cVaEnd(&ap); | |
| 324 | ||
| 325 | var out_f32: [3]f32 = undefined; | |
| 326 | var out_f64: [3]f64 = undefined; | |
| 327 | out_f32[0] = @cVaArg(&ap, f32); | |
| 328 | out_f64[0] = @cVaArg(&ap, f64); | |
| 329 | out_f32[1] = @cVaArg(&ap, f32); | |
| 330 | out_f64[1] = @cVaArg(&ap, f64); | |
| 331 | out_f32[2] = @cVaArg(&ap, f32); | |
| 332 | out_f64[2] = @cVaArg(&ap, f64); | |
| 333 | @cVaArg(&ap, *[3]f32).* = out_f32; | |
| 334 | @cVaArg(&ap, *[3]f64).* = out_f64; | |
| 335 | } | |
| 336 | }; | |
| 337 | ||
| 338 | const expected_f32: []const f32 = &.{ 1000, std.math.floatMax(f32), std.math.floatMin(f32) }; | |
| 339 | const expected_f64: []const f64 = &.{ 2000, std.math.floatMax(f64), std.math.floatMin(f64) }; | |
| 340 | var actual_f32: [3]f32 = undefined; | |
| 341 | var actual_f64: [3]f64 = undefined; | |
| 342 | S.proxy( | |
| 343 | expected_f32[0], | |
| 344 | expected_f64[0], | |
| 345 | expected_f32[1], | |
| 346 | expected_f64[1], | |
| 347 | expected_f32[2], | |
| 348 | expected_f64[2], | |
| 349 | &actual_f32, | |
| 350 | &actual_f64, | |
| 351 | ); | |
| 352 | ||
| 353 | try std.testing.expectEqualSlices(f32, expected_f32, &actual_f32); | |
| 354 | try std.testing.expectEqualSlices(f64, expected_f64, &actual_f64); | |
| 355 | } |