| author | |
| committer | |
| log | 025611629f95cda21ff93a517406ea8387ad9cfb |
| tree | ae0a5a16e5780b5c20111a0ec2059eb4c3fe8ea2 |
| parent | 6d68a494c8a5abf86c406a82c0f744a999084abe |
3 files changed, 107 insertions(+), 12 deletions(-)
src/arch/x86_64/CodeGen.zig+103-7| ... | @@ -101399,8 +101399,66 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -101399,8 +101399,66 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 101399 | 101399 | ||
| 101400 | .memset => try cg.airMemset(inst, false), | 101400 | .memset => try cg.airMemset(inst, false), |
| 101401 | .memset_safe => try cg.airMemset(inst, true), | 101401 | .memset_safe => try cg.airMemset(inst, true), |
| 101402 | .memcpy => try cg.airMemcpy(inst), | 101402 | .memcpy, .memmove => |air_tag| if (use_old) switch (air_tag) { |
| 101403 | .memmove => try cg.airMemmove(inst), | 101403 | else => unreachable, |
| 101404 | .memcpy => try cg.airMemcpy(inst), | ||
| 101405 | .memmove => return cg.fail("TODO implement airMemmove for {}", .{cg.target.cpu.arch}), | ||
| 101406 | } else { | ||
| 101407 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; | ||
| 101408 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }) ++ .{undefined}; | ||
| 101409 | ops[2] = ops[0].getByteLen(cg) catch |err| switch (err) { | ||
| 101410 | error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {}", .{ | ||
| 101411 | @tagName(air_tag), | ||
| 101412 | cg.typeOf(bin_op.lhs).fmt(pt), | ||
| 101413 | cg.typeOf(bin_op.rhs).fmt(pt), | ||
| 101414 | ops[0].tracking(cg), | ||
| 101415 | ops[1].tracking(cg), | ||
| 101416 | }), | ||
| 101417 | else => |e| return e, | ||
| 101418 | }; | ||
| 101419 | try ops[0].toSlicePtr(cg); | ||
| 101420 | cg.select(&.{}, &.{}, &ops, switch (air_tag) { | ||
| 101421 | else => unreachable, | ||
| 101422 | inline .memcpy, .memmove => |symbol| comptime &.{.{ | ||
| 101423 | .patterns = &.{ | ||
| 101424 | .{ .src = .{ | ||
| 101425 | .{ .to_param_gpr = .{ .cc = .ccc, .index = 0 } }, | ||
| 101426 | .{ .to_param_gpr = .{ .cc = .ccc, .index = 1 } }, | ||
| 101427 | .{ .to_param_gpr = .{ .cc = .ccc, .index = 2 } }, | ||
| 101428 | } }, | ||
| 101429 | }, | ||
| 101430 | .call_frame = .{ .alignment = .@"16" }, | ||
| 101431 | .extra_temps = .{ | ||
| 101432 | .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(symbol) } } }, | ||
| 101433 | .unused, | ||
| 101434 | .unused, | ||
| 101435 | .unused, | ||
| 101436 | .unused, | ||
| 101437 | .unused, | ||
| 101438 | .unused, | ||
| 101439 | .unused, | ||
| 101440 | .unused, | ||
| 101441 | .unused, | ||
| 101442 | .unused, | ||
| 101443 | }, | ||
| 101444 | .clobbers = .{ .eflags = true, .caller_preserved = .ccc }, | ||
| 101445 | .each = .{ .once = &.{ | ||
| 101446 | .{ ._, ._, .call, .tmp0d, ._, ._, ._ }, | ||
| 101447 | } }, | ||
| 101448 | }}, | ||
| 101449 | }) catch |err| switch (err) { | ||
| 101450 | error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {} {}", .{ | ||
| 101451 | @tagName(air_tag), | ||
| 101452 | cg.typeOf(bin_op.lhs).fmt(pt), | ||
| 101453 | cg.typeOf(bin_op.rhs).fmt(pt), | ||
| 101454 | ops[0].tracking(cg), | ||
| 101455 | ops[1].tracking(cg), | ||
| 101456 | ops[2].tracking(cg), | ||
| 101457 | }), | ||
| 101458 | else => |e| return e, | ||
| 101459 | }; | ||
| 101460 | for (ops) |op| try op.die(cg); | ||
| 101461 | }, | ||
| 101404 | .cmpxchg_weak, .cmpxchg_strong => try cg.airCmpxchg(inst), | 101462 | .cmpxchg_weak, .cmpxchg_strong => try cg.airCmpxchg(inst), |
| 101405 | .atomic_load => try cg.airAtomicLoad(inst), | 101463 | .atomic_load => try cg.airAtomicLoad(inst), |
| 101406 | .atomic_store_unordered => try cg.airAtomicStore(inst, .unordered), | 101464 | .atomic_store_unordered => try cg.airAtomicStore(inst, .unordered), |
| ... | @@ -118458,11 +118516,6 @@ fn airMemcpy(self: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -118458,11 +118516,6 @@ fn airMemcpy(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 118458 | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); | 118516 | return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 118459 | } | 118517 | } |
| 118460 | 118518 | ||
| 118461 | fn airMemmove(self: *CodeGen, inst: Air.Inst.Index) !void { | ||
| 118462 | _ = inst; | ||
| 118463 | return self.fail("TODO implement airMemmove for {}", .{self.target.cpu.arch}); | ||
| 118464 | } | ||
| 118465 | |||
| 118466 | fn airTagName(self: *CodeGen, inst: Air.Inst.Index, only_safety: bool) !void { | 118519 | fn airTagName(self: *CodeGen, inst: Air.Inst.Index, only_safety: bool) !void { |
| 118467 | const pt = self.pt; | 118520 | const pt = self.pt; |
| 118468 | const zcu = pt.zcu; | 118521 | const zcu = pt.zcu; |
| ... | @@ -122137,6 +122190,49 @@ const Temp = struct { | ... | @@ -122137,6 +122190,49 @@ const Temp = struct { |
| 122137 | return .{ .index = new_temp_index.toIndex() }; | 122190 | return .{ .index = new_temp_index.toIndex() }; |
| 122138 | } | 122191 | } |
| 122139 | 122192 | ||
| 122193 | fn getByteLen(temp: *Temp, cg: *CodeGen) Select.Error!Temp { | ||
| 122194 | const zcu = cg.pt.zcu; | ||
| 122195 | const ip = &zcu.intern_pool; | ||
| 122196 | const ptr_info = ip.indexToKey(temp.typeOf(cg).toIntern()).ptr_type; | ||
| 122197 | switch (ptr_info.flags.size) { | ||
| 122198 | .one => { | ||
| 122199 | const array_info = ip.indexToKey(ptr_info.child).array_type; | ||
| 122200 | return cg.tempInit(.usize, .{ | ||
| 122201 | .immediate = Type.fromInterned(array_info.child).abiSize(zcu) * array_info.len, | ||
| 122202 | }); | ||
| 122203 | }, | ||
| 122204 | .many, .c => unreachable, | ||
| 122205 | .slice => { | ||
| 122206 | const elem_size = Type.fromInterned(ptr_info.child).abiSize(zcu); | ||
| 122207 | var len = try temp.getLimb(.usize, 1, cg); | ||
| 122208 | while (try len.toRegClass(true, .general_purpose, cg)) {} | ||
| 122209 | const len_reg = len.tracking(cg).short.register.to64(); | ||
| 122210 | if (!std.math.isPowerOfTwo(elem_size)) { | ||
| 122211 | try cg.spillEflagsIfOccupied(); | ||
| 122212 | try cg.asmRegisterRegisterImmediate( | ||
| 122213 | .{ .i_, .mul }, | ||
| 122214 | len_reg, | ||
| 122215 | len_reg, | ||
| 122216 | .u(elem_size), | ||
| 122217 | ); | ||
| 122218 | } else if (elem_size > 8) { | ||
| 122219 | try cg.spillEflagsIfOccupied(); | ||
| 122220 | try cg.asmRegisterImmediate( | ||
| 122221 | .{ ._l, .sh }, | ||
| 122222 | len_reg, | ||
| 122223 | .u(std.math.log2_int(u64, elem_size)), | ||
| 122224 | ); | ||
| 122225 | } else if (elem_size != 1) try cg.asmRegisterMemory(.{ ._, .lea }, len_reg, .{ | ||
| 122226 | .mod = .{ .rm = .{ | ||
| 122227 | .index = len_reg, | ||
| 122228 | .scale = .fromFactor(@intCast(elem_size)), | ||
| 122229 | } }, | ||
| 122230 | }); | ||
| 122231 | return len; | ||
| 122232 | }, | ||
| 122233 | } | ||
| 122234 | } | ||
| 122235 | |||
| 122140 | fn toLimb(temp: *Temp, limb_ty: Type, limb_index: u28, cg: *CodeGen) InnerError!void { | 122236 | fn toLimb(temp: *Temp, limb_ty: Type, limb_index: u28, cg: *CodeGen) InnerError!void { |
| 122141 | switch (temp.unwrap(cg)) { | 122237 | switch (temp.unwrap(cg)) { |
| 122142 | .ref => {}, | 122238 | .ref => {}, |
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1| ... | @@ -6,7 +6,6 @@ var x: u8 = 1; | ... | @@ -6,7 +6,6 @@ var x: u8 = 1; |
| 6 | 6 | ||
| 7 | // This excludes builtin functions that return void or noreturn that cannot be tested. | 7 | // This excludes builtin functions that return void or noreturn that cannot be tested. |
| 8 | test { | 8 | test { |
| 9 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 10 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 9 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 12 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 11 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
test/behavior/memmove.zig+4-4| ... | @@ -3,13 +3,13 @@ const builtin = @import("builtin"); | ... | @@ -3,13 +3,13 @@ const builtin = @import("builtin"); |
| 3 | const expect = std.testing.expect; | 3 | const expect = std.testing.expect; |
| 4 | 4 | ||
| 5 | test "memmove and memset intrinsics" { | 5 | test "memmove and memset intrinsics" { |
| 6 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 9 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 11 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 10 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 12 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 11 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 12 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | ||
| 13 | 13 | ||
| 14 | try testMemmoveMemset(); | 14 | try testMemmoveMemset(); |
| 15 | try comptime testMemmoveMemset(); | 15 | try comptime testMemmoveMemset(); |
| ... | @@ -33,13 +33,13 @@ fn testMemmoveMemset() !void { | ... | @@ -33,13 +33,13 @@ fn testMemmoveMemset() !void { |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | test "@memmove with both operands single-ptr-to-array, one is null-terminated" { | 35 | test "@memmove with both operands single-ptr-to-array, one is null-terminated" { |
| 36 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 37 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 36 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 38 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 37 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 39 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | 38 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 40 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 39 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 41 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 40 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 42 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 41 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 42 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | ||
| 43 | 43 | ||
| 44 | try testMemmoveBothSinglePtrArrayOneIsNullTerminated(); | 44 | try testMemmoveBothSinglePtrArrayOneIsNullTerminated(); |
| 45 | try comptime testMemmoveBothSinglePtrArrayOneIsNullTerminated(); | 45 | try comptime testMemmoveBothSinglePtrArrayOneIsNullTerminated(); |
| ... | @@ -79,13 +79,13 @@ fn testMemmoveBothSinglePtrArrayOneIsNullTerminated() !void { | ... | @@ -79,13 +79,13 @@ fn testMemmoveBothSinglePtrArrayOneIsNullTerminated() !void { |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | test "@memmove dest many pointer" { | 81 | test "@memmove dest many pointer" { |
| 82 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 83 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 82 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 84 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 83 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 85 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | 84 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 86 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 85 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 87 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 86 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 88 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 87 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 88 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | ||
| 89 | 89 | ||
| 90 | try testMemmoveDestManyPtr(); | 90 | try testMemmoveDestManyPtr(); |
| 91 | try comptime testMemmoveDestManyPtr(); | 91 | try comptime testMemmoveDestManyPtr(); |
| ... | @@ -123,13 +123,13 @@ fn testMemmoveDestManyPtr() !void { | ... | @@ -123,13 +123,13 @@ fn testMemmoveDestManyPtr() !void { |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | test "@memmove slice" { | 125 | test "@memmove slice" { |
| 126 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 127 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 126 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 128 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 127 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 129 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | 128 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 130 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 129 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 131 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 130 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 132 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 131 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 132 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | ||
| 133 | 133 | ||
| 134 | try testMemmoveSlice(); | 134 | try testMemmoveSlice(); |
| 135 | try comptime testMemmoveSlice(); | 135 | try comptime testMemmoveSlice(); |