authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-03 19:49:25-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-16 20:47:30-05:00
log0d9079f46654e39763bbd66090c85cdc466cc18c
tree8ca45ac5fe35c223d5f26c70a8e247e790509a5f
parent870443f7fabefa753a1653a275172a4a04fe8c34

x86_64: implement element access


4 files changed, 179 insertions(+), 48 deletions(-)

src/arch/x86_64/CodeGen.zig+146-48
...@@ -2492,8 +2492,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2492,8 +2492,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2492 .atomic_store_seq_cst => try cg.airAtomicStore(inst, .seq_cst),2492 .atomic_store_seq_cst => try cg.airAtomicStore(inst, .seq_cst),
24932493
2494 .array_elem_val => try cg.airArrayElemVal(inst),2494 .array_elem_val => try cg.airArrayElemVal(inst),
2495 .slice_elem_val => try cg.airSliceElemVal(inst),
2496 .ptr_elem_val => try cg.airPtrElemVal(inst),
24972495
2498 .optional_payload => try cg.airOptionalPayload(inst),2496 .optional_payload => try cg.airOptionalPayload(inst),
2499 .unwrap_errunion_err => try cg.airUnwrapErrUnionErr(inst),2497 .unwrap_errunion_err => try cg.airUnwrapErrUnionErr(inst),
...@@ -3995,7 +3993,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -3995,7 +3993,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
3995 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .load_frame = .{3993 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .load_frame = .{
3996 .index = .ret_addr,3994 .index = .ret_addr,
3997 } });3995 } });
3998 while (try slot.toAnyReg(cg)) {}3996 while (try slot.toRegClass(true, .general_purpose, cg)) {}
3999 try slot.moveTo(inst, cg);3997 try slot.moveTo(inst, cg);
4000 },3998 },
4001 .frame_addr => if (use_old) try cg.airFrameAddress(inst) else {3999 .frame_addr => if (use_old) try cg.airFrameAddress(inst) else {
...@@ -9445,7 +9443,111 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9445,7 +9443,111 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9445 try ops[0].toOffset(0, cg);9443 try ops[0].toOffset(0, cg);
9446 try ops[0].moveTo(inst, cg);9444 try ops[0].moveTo(inst, cg);
9447 },9445 },
9448 .slice_elem_ptr, .ptr_elem_ptr => |tag| if (use_old) switch (tag) {9446 .slice_elem_val, .ptr_elem_val => |air_tag| if (use_old) switch (air_tag) {
9447 else => unreachable,
9448 .slice_elem_val => try cg.airSliceElemVal(inst),
9449 .ptr_elem_val => try cg.airPtrElemVal(inst),
9450 } else {
9451 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
9452 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
9453 switch (air_tag) {
9454 else => unreachable,
9455 .slice_elem_val => try ops[0].toLimb(0, cg),
9456 .ptr_elem_val => {},
9457 }
9458 var res: [1]Temp = undefined;
9459 const res_ty = cg.typeOfIndex(inst);
9460 cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{
9461 .dst_constraints = .{.{ .int = .byte }},
9462 .patterns = &.{
9463 .{ .src = .{ .to_gpr, .simm32 } },
9464 .{ .src = .{ .to_gpr, .to_gpr } },
9465 },
9466 .dst_temps = .{.{ .rc = .general_purpose }},
9467 .each = .{ .once = &.{
9468 .{ ._, ._, .movzx, .dst0d, .leai(.byte, .src0, .src1), ._, ._ },
9469 } },
9470 }, .{
9471 .dst_constraints = .{.{ .int = .word }},
9472 .patterns = &.{
9473 .{ .src = .{ .to_gpr, .simm32 } },
9474 .{ .src = .{ .to_gpr, .to_gpr } },
9475 },
9476 .dst_temps = .{.{ .rc = .general_purpose }},
9477 .each = .{ .once = &.{
9478 .{ ._, ._, .movzx, .dst0d, .leasi(.word, .src0, .@"2", .src1), ._, ._ },
9479 } },
9480 }, .{
9481 .dst_constraints = .{.{ .int = .dword }},
9482 .patterns = &.{
9483 .{ .src = .{ .to_gpr, .simm32 } },
9484 .{ .src = .{ .to_gpr, .to_gpr } },
9485 },
9486 .dst_temps = .{.{ .rc = .general_purpose }},
9487 .each = .{ .once = &.{
9488 .{ ._, ._, .mov, .dst0d, .leasi(.dword, .src0, .@"4", .src1), ._, ._ },
9489 } },
9490 }, .{
9491 .required_features = .{ .@"64bit", null, null, null },
9492 .dst_constraints = .{.{ .int = .qword }},
9493 .patterns = &.{
9494 .{ .src = .{ .to_gpr, .simm32 } },
9495 .{ .src = .{ .to_gpr, .to_gpr } },
9496 },
9497 .dst_temps = .{.{ .rc = .general_purpose }},
9498 .each = .{ .once = &.{
9499 .{ ._, ._, .mov, .dst0q, .leasi(.qword, .src0, .@"8", .src1), ._, ._ },
9500 } },
9501 } }) catch |err| switch (err) {
9502 error.SelectFailed => switch (res_ty.abiSize(zcu)) {
9503 0 => res[0] = try cg.tempFromValue(res_ty, .none),
9504 else => |elem_size| {
9505 while (true) for (&ops) |*op| {
9506 if (try op.toRegClass(true, .general_purpose, cg)) break;
9507 } else break;
9508 const lhs_reg = ops[0].unwrap(cg).temp.tracking(cg).short.register.to64();
9509 const rhs_reg = ops[1].unwrap(cg).temp.tracking(cg).short.register.to64();
9510 if (!std.math.isPowerOfTwo(elem_size)) {
9511 try cg.spillEflagsIfOccupied();
9512 try cg.asmRegisterRegisterImmediate(
9513 .{ .i_, .mul },
9514 rhs_reg,
9515 rhs_reg,
9516 .u(elem_size),
9517 );
9518 try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
9519 .base = .{ .reg = lhs_reg },
9520 .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },
9521 });
9522 } else if (elem_size > 8) {
9523 try cg.spillEflagsIfOccupied();
9524 try cg.asmRegisterImmediate(
9525 .{ ._l, .sh },
9526 rhs_reg,
9527 .u(std.math.log2_int(u64, elem_size)),
9528 );
9529 try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
9530 .base = .{ .reg = lhs_reg },
9531 .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },
9532 });
9533 } else try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
9534 .base = .{ .reg = lhs_reg },
9535 .mod = .{ .rm = .{
9536 .size = .qword,
9537 .index = rhs_reg,
9538 .scale = .fromFactor(@intCast(elem_size)),
9539 } },
9540 });
9541 res[0] = try ops[0].load(res_ty, cg);
9542 },
9543 },
9544 else => |e| return e,
9545 };
9546 if (ops[0].index != res[0].index) try ops[0].die(cg);
9547 if (ops[1].index != res[0].index) try ops[1].die(cg);
9548 try res[0].moveTo(inst, cg);
9549 },
9550 .slice_elem_ptr, .ptr_elem_ptr => |air_tag| if (use_old) switch (air_tag) {
9449 else => unreachable,9551 else => unreachable,
9450 .slice_elem_ptr => try cg.airSliceElemPtr(inst),9552 .slice_elem_ptr => try cg.airSliceElemPtr(inst),
9451 .ptr_elem_ptr => try cg.airPtrElemPtr(inst),9553 .ptr_elem_ptr => try cg.airPtrElemPtr(inst),
...@@ -9453,7 +9555,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9453,7 +9555,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9453 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;9555 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
9454 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;9556 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
9455 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });9557 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
9456 switch (tag) {9558 switch (air_tag) {
9457 else => unreachable,9559 else => unreachable,
9458 .slice_elem_ptr => try ops[0].toLimb(0, cg),9560 .slice_elem_ptr => try ops[0].toLimb(0, cg),
9459 .ptr_elem_ptr => {},9561 .ptr_elem_ptr => {},
...@@ -9463,7 +9565,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9463,7 +9565,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9463 const elem_size = dst_ty.childType(zcu).abiSize(zcu);9565 const elem_size = dst_ty.childType(zcu).abiSize(zcu);
9464 if (elem_size == 0) break :zero_offset;9566 if (elem_size == 0) break :zero_offset;
9465 while (true) for (&ops) |*op| {9567 while (true) for (&ops) |*op| {
9466 if (try op.toAnyReg(cg)) break;9568 if (try op.toRegClass(true, .general_purpose, cg)) break;
9467 } else break;9569 } else break;
9468 const lhs_reg = ops[0].unwrap(cg).temp.tracking(cg).short.register.to64();9570 const lhs_reg = ops[0].unwrap(cg).temp.tracking(cg).short.register.to64();
9469 const rhs_reg = ops[1].unwrap(cg).temp.tracking(cg).short.register.to64();9571 const rhs_reg = ops[1].unwrap(cg).temp.tracking(cg).short.register.to64();
...@@ -27718,6 +27820,7 @@ const Temp = struct {...@@ -27718,6 +27820,7 @@ const Temp = struct {
27718 },27820 },
27719 };27821 };
27720 const new_temp_index = cg.next_temp_index;27822 const new_temp_index = cg.next_temp_index;
27823 try cg.register_manager.getReg(new_reg, new_temp_index.toIndex());
27721 cg.temp_type[@intFromEnum(new_temp_index)] = ty;27824 cg.temp_type[@intFromEnum(new_temp_index)] = ty;
27722 try cg.genSetReg(new_reg, ty, val, .{});27825 try cg.genSetReg(new_reg, ty, val, .{});
27723 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });27826 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
...@@ -27727,27 +27830,6 @@ const Temp = struct {...@@ -27727,27 +27830,6 @@ const Temp = struct {
27727 return true;27830 return true;
27728 }27831 }
2772927832
27730 fn toAnyReg(temp: *Temp, cg: *CodeGen) !bool {
27731 const val, const ty = switch (temp.unwrap(cg)) {
27732 .ref => |ref| .{ temp.tracking(cg).short, cg.typeOf(ref) },
27733 .temp => |temp_index| val: {
27734 const temp_tracking = temp_index.tracking(cg);
27735 if (temp_tracking.short == .register) return false;
27736 break :val .{ temp_tracking.short, temp_index.typeOf(cg) };
27737 },
27738 };
27739 const new_temp_index = cg.next_temp_index;
27740 cg.temp_type[@intFromEnum(new_temp_index)] = ty;
27741 const new_reg =
27742 try cg.register_manager.allocReg(new_temp_index.toIndex(), cg.regSetForType(ty));
27743 try cg.genSetReg(new_reg, ty, val, .{});
27744 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
27745 try temp.die(cg);
27746 cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
27747 temp.* = .{ .index = new_temp_index.toIndex() };
27748 return true;
27749 }
27750
27751 fn toRegClass(temp: *Temp, mut: bool, rc: Register.Class, cg: *CodeGen) !bool {27833 fn toRegClass(temp: *Temp, mut: bool, rc: Register.Class, cg: *CodeGen) !bool {
27752 const val = temp.tracking(cg).short;27834 const val = temp.tracking(cg).short;
27753 if (!mut or temp.isMut(cg)) switch (val) {27835 if (!mut or temp.isMut(cg)) switch (val) {
...@@ -27769,7 +27851,7 @@ const Temp = struct {...@@ -27769,7 +27851,7 @@ const Temp = struct {
2776927851
27770 fn toPair(first_temp: *Temp, second_temp: *Temp, cg: *CodeGen) !void {27852 fn toPair(first_temp: *Temp, second_temp: *Temp, cg: *CodeGen) !void {
27771 while (true) for ([_]*Temp{ first_temp, second_temp }) |part_temp| {27853 while (true) for ([_]*Temp{ first_temp, second_temp }) |part_temp| {
27772 if (try part_temp.toAnyReg(cg)) break;27854 if (try part_temp.toRegClass(true, .general_purpose, cg)) break;
27773 } else break;27855 } else break;
27774 const first_temp_tracking = first_temp.unwrap(cg).temp.tracking(cg);27856 const first_temp_tracking = first_temp.unwrap(cg).temp.tracking(cg);
27775 const second_temp_tracking = second_temp.unwrap(cg).temp.tracking(cg);27857 const second_temp_tracking = second_temp.unwrap(cg).temp.tracking(cg);
...@@ -27824,12 +27906,12 @@ const Temp = struct {...@@ -27824,12 +27906,12 @@ const Temp = struct {
27824 .load_got,27906 .load_got,
27825 .load_tlv,27907 .load_tlv,
27826 .load_frame,27908 .load_frame,
27827 => return temp.toAnyReg(cg),27909 => return temp.toRegClass(true, .general_purpose, cg),
27828 .lea_symbol => |sym_off| {27910 .lea_symbol => |sym_off| {
27829 const off = sym_off.off;27911 const off = sym_off.off;
27830 if (off == 0) return false;27912 if (off == 0) return false;
27831 try temp.toOffset(-off, cg);27913 try temp.toOffset(-off, cg);
27832 while (try temp.toAnyReg(cg)) {}27914 while (try temp.toRegClass(true, .general_purpose, cg)) {}
27833 try temp.toOffset(off, cg);27915 try temp.toOffset(off, cg);
27834 return true;27916 return true;
27835 },27917 },
...@@ -27868,24 +27950,16 @@ const Temp = struct {...@@ -27868,24 +27950,16 @@ const Temp = struct {
27868 }27950 }
2786927951
27870 fn load(ptr: *Temp, val_ty: Type, cg: *CodeGen) !Temp {27952 fn load(ptr: *Temp, val_ty: Type, cg: *CodeGen) !Temp {
27871 const val_abi_size: u32 = @intCast(val_ty.abiSize(cg.pt.zcu));
27872 const val = try cg.tempAlloc(val_ty);27953 const val = try cg.tempAlloc(val_ty);
27873 switch (val.tracking(cg).short) {27954 switch (val.tracking(cg).short) {
27874 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),27955 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
27875 .register => |val_reg| {27956 .register => |val_reg| {
27876 while (try ptr.toLea(cg)) {}27957 while (try ptr.toLea(cg)) {}
27877 switch (val_reg.class()) {27958 try cg.genSetReg(val_reg, val_ty, ptr.tracking(cg).short.deref(), .{});
27878 .general_purpose => try cg.asmRegisterMemory(
27879 .{ ._, .mov },
27880 registerAlias(val_reg, val_abi_size),
27881 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),
27882 ),
27883 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
27884 }
27885 },27959 },
27886 .load_frame => |val_frame_addr| {27960 .load_frame => |val_frame_addr| {
27887 var val_ptr = try cg.tempFromValue(.usize, .{ .lea_frame = val_frame_addr });27961 var val_ptr = try cg.tempFromValue(.usize, .{ .lea_frame = val_frame_addr });
27888 var len = try cg.tempFromValue(.usize, .{ .immediate = val_abi_size });27962 var len = try cg.tempFromValue(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
27889 try val_ptr.memcpy(ptr, &len, cg);27963 try val_ptr.memcpy(ptr, &len, cg);
27890 try val_ptr.die(cg);27964 try val_ptr.die(cg);
27891 try len.die(cg);27965 try len.die(cg);
...@@ -27908,7 +27982,7 @@ const Temp = struct {...@@ -27908,7 +27982,7 @@ const Temp = struct {
27908 );27982 );
27909 } else continue :val .{ .register = undefined },27983 } else continue :val .{ .register = undefined },
27910 .register => {27984 .register => {
27911 while (try ptr.toLea(cg) or try val.toAnyReg(cg)) {}27985 while (try ptr.toLea(cg) or try val.toRegClass(true, .general_purpose, cg)) {}
27912 const val_reg = val.tracking(cg).short.register;27986 const val_reg = val.tracking(cg).short.register;
27913 switch (val_reg.class()) {27987 switch (val_reg.class()) {
27914 .general_purpose => try cg.asmMemoryRegister(27988 .general_purpose => try cg.asmMemoryRegister(
...@@ -28224,6 +28298,7 @@ const Select = struct {...@@ -28224,6 +28298,7 @@ const Select = struct {
28224 any_int,28298 any_int,
28225 any_signed_int,28299 any_signed_int,
28226 any_float,28300 any_float,
28301 po2_any,
28227 bool_vec: Memory.Size,28302 bool_vec: Memory.Size,
28228 vec: Memory.Size,28303 vec: Memory.Size,
28229 signed_int_vec: Memory.Size,28304 signed_int_vec: Memory.Size,
...@@ -28250,15 +28325,17 @@ const Select = struct {...@@ -28250,15 +28325,17 @@ const Select = struct {
28250 unsigned_or_exact_remainder_int: struct { of: Memory.Size, is: Memory.Size },28325 unsigned_or_exact_remainder_int: struct { of: Memory.Size, is: Memory.Size },
28251 signed_int: Memory.Size,28326 signed_int: Memory.Size,
28252 unsigned_int: Memory.Size,28327 unsigned_int: Memory.Size,
28328 elem_int: Memory.Size,
2825328329
28254 fn accepts(constraint: Constraint, ty: Type, cg: *CodeGen) bool {28330 fn accepts(constraint: Constraint, ty: Type, cg: *CodeGen) bool {
28255 const zcu = cg.pt.zcu;28331 const zcu = cg.pt.zcu;
28256 switch (constraint) {28332 switch (constraint) {
28257 .any => return true,28333 .any => return true,
28258 .any_bool_vec => return ty.isVector(zcu) and ty.scalarType(zcu).toIntern() == .bool_type,28334 .any_bool_vec => return ty.isVector(zcu) and ty.childType(zcu).toIntern() == .bool_type,
28259 .any_int => return ty.toIntern() == .bool_type or ty.isPtrAtRuntime(zcu) or ty.isAbiInt(zcu),28335 .any_int => return ty.toIntern() == .bool_type or ty.isPtrAtRuntime(zcu) or ty.isAbiInt(zcu),
28260 .any_signed_int => return ty.isAbiInt(zcu) and ty.intInfo(zcu).signedness == .signed,28336 .any_signed_int => return ty.isAbiInt(zcu) and ty.intInfo(zcu).signedness == .signed,
28261 .any_float => return ty.scalarType(zcu).isRuntimeFloat(),28337 .any_float => return ty.isRuntimeFloat(),
28338 .po2_any => return std.math.isPowerOfTwo(ty.abiSize(zcu)),
28262 .bool_vec => |size| return ty.isVector(zcu) and ty.scalarType(zcu).toIntern() == .bool_type and28339 .bool_vec => |size| return ty.isVector(zcu) and ty.scalarType(zcu).toIntern() == .bool_type and
28263 size.bitSize(cg.target) >= ty.vectorLen(zcu),28340 size.bitSize(cg.target) >= ty.vectorLen(zcu),
28264 .vec => |size| return ty.isVector(zcu) and ty.scalarType(zcu).toIntern() != .bool_type and28341 .vec => |size| return ty.isVector(zcu) and ty.scalarType(zcu).toIntern() != .bool_type and
...@@ -28434,6 +28511,12 @@ const Select = struct {...@@ -28434,6 +28511,12 @@ const Select = struct {
28434 const int_info = ty.intInfo(zcu);28511 const int_info = ty.intInfo(zcu);
28435 return int_info.signedness == .unsigned and size.bitSize(cg.target) >= int_info.bits;28512 return int_info.signedness == .unsigned and size.bitSize(cg.target) >= int_info.bits;
28436 },28513 },
28514 .elem_int => |size| {
28515 const elem_ty = ty.childType(zcu);
28516 if (elem_ty.toIntern() == .bool_type) return true;
28517 if (elem_ty.isPtrAtRuntime(zcu)) return size.bitSize(cg.target) >= cg.target.ptrBitWidth();
28518 return elem_ty.isAbiInt(zcu) and size.bitSize(cg.target) >= elem_ty.intInfo(zcu).bits;
28519 },
28437 }28520 }
28438 }28521 }
28439 };28522 };
...@@ -29107,7 +29190,14 @@ const Select = struct {...@@ -29107,7 +29190,14 @@ const Select = struct {
29107 const UnsignedImm = @Type(.{29190 const UnsignedImm = @Type(.{
29108 .int = .{ .signedness = .unsigned, .bits = @typeInfo(SignedImm).int.bits },29191 .int = .{ .signedness = .unsigned, .bits = @typeInfo(SignedImm).int.bits },
29109 });29192 });
29110 return op.imm + @as(i5, op.adjust.factor) * op.adjust.scale.toFactor() * @as(SignedImm, switch (op.adjust.amount) {29193 return switch (op.index.ref) {
29194 else => |ref| switch (ref.deref(s).tracking(s.cg).short) {
29195 else => unreachable,
29196 .immediate => |imm| op.index.scale.toFactor() * @as(i32, @intCast(imm)),
29197 .register => 0,
29198 },
29199 .none => 0,
29200 } + @as(i5, op.adjust.factor) * op.adjust.scale.toFactor() * @as(SignedImm, switch (op.adjust.amount) {
29111 .none => 0,29201 .none => 0,
29112 .ptr_size => @divExact(s.cg.target.ptrBitWidth(), 8),29202 .ptr_size => @divExact(s.cg.target.ptrBitWidth(), 8),
29113 .ptr_bit_size => s.cg.target.ptrBitWidth(),29203 .ptr_bit_size => s.cg.target.ptrBitWidth(),
...@@ -29120,7 +29210,7 @@ const Select = struct {...@@ -29120,7 +29210,7 @@ const Select = struct {
29120 op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu),29210 op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu),
29121 @divExact(op.base.size.bitSize(s.cg.target), 8),29211 @divExact(op.base.size.bitSize(s.cg.target), 8),
29122 )),29212 )),
29123 .src0_elem_size => @intCast(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),29213 .src0_elem_size => @intCast(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).childType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
29124 .smin => @as(SignedImm, std.math.minInt(SignedImm)) >> @truncate(29214 .smin => @as(SignedImm, std.math.minInt(SignedImm)) >> @truncate(
29125 -%op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu),29215 -%op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu),
29126 ),29216 ),
...@@ -29130,7 +29220,7 @@ const Select = struct {...@@ -29130,7 +29220,7 @@ const Select = struct {
29130 .umax => @bitCast(@as(UnsignedImm, std.math.maxInt(UnsignedImm)) >> @truncate(29220 .umax => @bitCast(@as(UnsignedImm, std.math.maxInt(UnsignedImm)) >> @truncate(
29131 -%op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu),29221 -%op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu),
29132 )),29222 )),
29133 });29223 }) + op.imm;
29134 }29224 }
2913529225
29136 fn lower(op: Select.Operand, s: *Select) !CodeGen.Operand {29226 fn lower(op: Select.Operand, s: *Select) !CodeGen.Operand {
...@@ -29160,7 +29250,11 @@ const Select = struct {...@@ -29160,7 +29250,11 @@ const Select = struct {
29160 .mod = .{ .rm = .{29250 .mod = .{ .rm = .{
29161 .size = op.base.size,29251 .size = op.base.size,
29162 .index = switch (op.index.ref) {29252 .index = switch (op.index.ref) {
29163 else => |ref| registerAlias(ref.deref(s).tracking(s.cg).short.register, @divExact(s.cg.target.ptrBitWidth(), 8)),29253 else => |ref| switch (ref.deref(s).tracking(s.cg).short) {
29254 else => unreachable,
29255 .immediate => .none,
29256 .register => |index_reg| registerAlias(index_reg, @divExact(s.cg.target.ptrBitWidth(), 8)),
29257 },
29164 .none => .none,29258 .none => .none,
29165 },29259 },
29166 .scale = op.index.scale,29260 .scale = op.index.scale,
...@@ -29170,7 +29264,11 @@ const Select = struct {...@@ -29170,7 +29264,11 @@ const Select = struct {
29170 .mem => .{ .mem = try op.base.ref.deref(s).tracking(s.cg).short.mem(s.cg, .{29264 .mem => .{ .mem = try op.base.ref.deref(s).tracking(s.cg).short.mem(s.cg, .{
29171 .size = op.base.size,29265 .size = op.base.size,
29172 .index = switch (op.index.ref) {29266 .index = switch (op.index.ref) {
29173 else => |ref| registerAlias(ref.deref(s).tracking(s.cg).short.register, @divExact(s.cg.target.ptrBitWidth(), 8)),29267 else => |ref| switch (ref.deref(s).tracking(s.cg).short) {
29268 else => unreachable,
29269 .immediate => .none,
29270 .register => |index_reg| registerAlias(index_reg, @divExact(s.cg.target.ptrBitWidth(), 8)),
29271 },
29174 .none => .none,29272 .none => .none,
29175 },29273 },
29176 .scale = op.index.scale,29274 .scale = op.index.scale,
test/behavior/x86_64.zig+1
...@@ -5,4 +5,5 @@ test {...@@ -5,4 +5,5 @@ test {
5 if (builtin.zig_backend != .stage2_x86_64) return error.SkipZigTest;5 if (builtin.zig_backend != .stage2_x86_64) return error.SkipZigTest;
6 if (builtin.object_format == .coff) return error.SkipZigTest;6 if (builtin.object_format == .coff) return error.SkipZigTest;
7 _ = @import("x86_64/math.zig");7 _ = @import("x86_64/math.zig");
8 _ = @import("x86_64/mem.zig");
8}9}
test/behavior/x86_64/build.zig+1
...@@ -88,6 +88,7 @@ pub fn build(b: *std.Build) void {...@@ -88,6 +88,7 @@ pub fn build(b: *std.Build) void {
88 const cpu = query.serializeCpuAlloc(b.allocator) catch @panic("OOM");88 const cpu = query.serializeCpuAlloc(b.allocator) catch @panic("OOM");
89 for ([_][]const u8{89 for ([_][]const u8{
90 "math.zig",90 "math.zig",
91 "mem.zig",
91 }) |path| {92 }) |path| {
92 const test_mod = b.createModule(.{93 const test_mod = b.createModule(.{
93 .root_source_file = b.path(path),94 .root_source_file = b.path(path),
test/behavior/x86_64/mem.zig created+31
...@@ -0,0 +1,31 @@
1fn access(comptime array: anytype) !void {
2 var slice: []const @typeInfo(@TypeOf(array)).array.child = undefined;
3 slice = &array;
4 inline for (0.., &array) |ct_index, *elem| {
5 var rt_index: usize = undefined;
6 rt_index = ct_index;
7 if (&slice.ptr[ct_index] != elem) return error.Unexpected;
8 if (&slice[ct_index] != elem) return error.Unexpected;
9 if (&slice.ptr[rt_index] != elem) return error.Unexpected;
10 if (&slice[rt_index] != elem) return error.Unexpected;
11 if (slice.ptr[ct_index] != elem.*) return error.Unexpected;
12 if (slice[ct_index] != elem.*) return error.Unexpected;
13 if (slice.ptr[rt_index] != elem.*) return error.Unexpected;
14 if (slice[rt_index] != elem.*) return error.Unexpected;
15 }
16}
17test access {
18 try access([3]u8{ 0xdb, 0xef, 0xbd });
19 try access([3]u16{ 0x340e, 0x3654, 0x88d7 });
20 try access([3]u32{ 0xd424c2c0, 0x2d6ac466, 0x5a0cfaba });
21 try access([3]u64{
22 0x9327a4f5221666a6,
23 0x5c34d3ddd84a8b12,
24 0xbae087f39f649260,
25 });
26 try access([3]u128{
27 0x601cf010065444d4d42d5536dd9b95db,
28 0xa03f592fcaa22d40af23a0c735531e3c,
29 0x5da44907b31602b95c2d93f0b582ceab,
30 });
31}