authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-09 09:48:29-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-16 20:47:30-05:00
log666d76d85c1dc2f107d0a57b424983082672943e
tree0c80f3d3fce09874a00cca67c6cc80a79923f65e
parent6d1fc0f51cf835e8ed503a2089450b1f280d1216

x86_64: implement load and store


2 files changed, 302 insertions(+), 125 deletions(-)

src/arch/x86_64/CodeGen.zig+301-124
...@@ -257,6 +257,7 @@ pub const MCValue = union(enum) {...@@ -257,6 +257,7 @@ pub const MCValue = union(enum) {
257 };257 };
258 }258 }
259259
260 // hack around linker relocation bugs
260 fn isBase(mcv: MCValue) bool {261 fn isBase(mcv: MCValue) bool {
261 return switch (mcv) {262 return switch (mcv) {
262 .memory, .indirect, .load_frame => true,263 .memory, .indirect, .load_frame => true,
...@@ -2398,8 +2399,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2398,8 +2399,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2398 .add_wrap,2399 .add_wrap,
2399 .sub,2400 .sub,
2400 .sub_wrap,2401 .sub_wrap,
2401 .bool_and,
2402 .bool_or,
2403 .min,2402 .min,
2404 .max,2403 .max,
2405 => |air_tag| try cg.airBinOp(inst, air_tag),2404 => |air_tag| try cg.airBinOp(inst, air_tag),
...@@ -2454,9 +2453,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2454,9 +2453,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2454 .is_null => try cg.airIsNull(inst),2453 .is_null => try cg.airIsNull(inst),
2455 .is_non_err => try cg.airIsNonErr(inst),2454 .is_non_err => try cg.airIsNonErr(inst),
2456 .is_err => try cg.airIsErr(inst),2455 .is_err => try cg.airIsErr(inst),
2457 .load => try cg.airLoad(inst),
2458 .store => try cg.airStore(inst, false),
2459 .store_safe => try cg.airStore(inst, true),
2460 .float_from_int => try cg.airFloatFromInt(inst),2456 .float_from_int => try cg.airFloatFromInt(inst),
2461 .int_from_float => try cg.airIntFromFloat(inst),2457 .int_from_float => try cg.airIntFromFloat(inst),
2462 .cmpxchg_strong => try cg.airCmpxchg(inst),2458 .cmpxchg_strong => try cg.airCmpxchg(inst),
...@@ -2791,14 +2787,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2791,14 +2787,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2791 try slot.moveTo(inst, cg);2787 try slot.moveTo(inst, cg);
2792 },2788 },
2793 .assembly => try cg.airAsm(inst),2789 .assembly => try cg.airAsm(inst),
2794 .bit_and, .bit_or, .xor => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else {2790 .bit_and, .bit_or, .xor, .bool_and, .bool_or => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else {
2795 const bin_op = air_datas[@intFromEnum(inst)].bin_op;2791 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
2796 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });2792 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
2797 var res: [1]Temp = undefined;2793 var res: [1]Temp = undefined;
2798 cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) {2794 cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) {
2799 else => unreachable,2795 else => unreachable,
2800 .bit_and => .@"and",2796 .bit_and, .bool_and => .@"and",
2801 .bit_or => .@"or",2797 .bit_or, .bool_or => .@"or",
2802 .xor => .xor,2798 .xor => .xor,
2803 })) {2799 })) {
2804 else => unreachable,2800 else => unreachable,
...@@ -9601,6 +9597,25 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9601,6 +9597,25 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9601 try ops[0].die(cg);9597 try ops[0].die(cg);
9602 try is_non_err.moveTo(inst, cg);9598 try is_non_err.moveTo(inst, cg);
9603 },9599 },
9600 .load => if (use_old) try cg.airLoad(inst) else fallback: {
9601 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
9602 const val_ty = ty_op.ty.toType();
9603 const ptr_ty = cg.typeOf(ty_op.operand);
9604 const ptr_info = ptr_ty.ptrInfo(zcu);
9605 if (ptr_info.packed_offset.host_size > 0 and
9606 (ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type))
9607 break :fallback try cg.airLoad(inst);
9608 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
9609 var res = try ops[0].load(val_ty, .{
9610 .disp = switch (ptr_info.flags.vector_index) {
9611 .none => 0,
9612 .runtime => unreachable,
9613 else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)),
9614 },
9615 }, cg);
9616 for (ops) |op| if (op.index != res.index) try op.die(cg);
9617 try res.moveTo(inst, cg);
9618 },
9604 .int_from_ptr => if (use_old) try cg.airIntFromPtr(inst) else {9619 .int_from_ptr => if (use_old) try cg.airIntFromPtr(inst) else {
9605 const un_op = air_datas[@intFromEnum(inst)].un_op;9620 const un_op = air_datas[@intFromEnum(inst)].un_op;
9606 var ops = try cg.tempsFromOperands(inst, .{un_op});9621 var ops = try cg.tempsFromOperands(inst, .{un_op});
...@@ -9615,6 +9630,37 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9615,6 +9630,37 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9615 .ret => try cg.airRet(inst, false),9630 .ret => try cg.airRet(inst, false),
9616 .ret_safe => try cg.airRet(inst, true),9631 .ret_safe => try cg.airRet(inst, true),
9617 .ret_load => try cg.airRetLoad(inst),9632 .ret_load => try cg.airRetLoad(inst),
9633 .store, .store_safe => |air_tag| if (use_old) try cg.airStore(inst, switch (air_tag) {
9634 else => unreachable,
9635 .store => false,
9636 .store_safe => true,
9637 }) else fallback: {
9638 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
9639 const ptr_ty = cg.typeOf(bin_op.lhs);
9640 const ptr_info = ptr_ty.ptrInfo(zcu);
9641 const val_ty = cg.typeOf(bin_op.rhs);
9642 if (ptr_info.packed_offset.host_size > 0 and
9643 (ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type))
9644 break :fallback try cg.airStore(inst, switch (air_tag) {
9645 else => unreachable,
9646 .store => false,
9647 .store_safe => true,
9648 });
9649 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
9650 try ops[0].store(&ops[1], .{
9651 .disp = switch (ptr_info.flags.vector_index) {
9652 .none => 0,
9653 .runtime => unreachable,
9654 else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)),
9655 },
9656 .safe = switch (air_tag) {
9657 else => unreachable,
9658 .store => false,
9659 .store_safe => true,
9660 },
9661 }, cg);
9662 for (ops) |op| try op.die(cg);
9663 },
9618 .unreach => {},9664 .unreach => {},
9619 .optional_payload_ptr => if (use_old) try cg.airOptionalPayloadPtr(inst) else {9665 .optional_payload_ptr => if (use_old) try cg.airOptionalPayloadPtr(inst) else {
9620 const ty_op = air_datas[@intFromEnum(inst)].ty_op;9666 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
...@@ -9630,7 +9676,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9630,7 +9676,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9630 const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu));9676 const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu));
9631 try ops[0].toOffset(opt_child_abi_size, cg);9677 try ops[0].toOffset(opt_child_abi_size, cg);
9632 var has_value = try cg.tempInit(.bool, .{ .immediate = 1 });9678 var has_value = try cg.tempInit(.bool, .{ .immediate = 1 });
9633 try ops[0].store(0, &has_value, cg);9679 try ops[0].store(&has_value, .{}, cg);
9634 try has_value.die(cg);9680 try has_value.die(cg);
9635 try ops[0].toOffset(-opt_child_abi_size, cg);9681 try ops[0].toOffset(-opt_child_abi_size, cg);
9636 }9682 }
...@@ -9652,7 +9698,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9652,7 +9698,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9652 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));9698 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
9653 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});9699 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
9654 try ops[0].toOffset(eu_err_off, cg);9700 try ops[0].toOffset(eu_err_off, cg);
9655 var err = try ops[0].load(0, eu_ty.errorUnionSet(zcu), cg);9701 var err = try ops[0].load(eu_ty.errorUnionSet(zcu), .{}, cg);
9656 try ops[0].die(cg);9702 try ops[0].die(cg);
9657 try err.moveTo(inst, cg);9703 try err.moveTo(inst, cg);
9658 },9704 },
...@@ -9666,7 +9712,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9666,7 +9712,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9666 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});9712 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
9667 try ops[0].toOffset(eu_err_off, cg);9713 try ops[0].toOffset(eu_err_off, cg);
9668 var no_err = try cg.tempInit(eu_err_ty, .{ .immediate = 0 });9714 var no_err = try cg.tempInit(eu_err_ty, .{ .immediate = 0 });
9669 try ops[0].store(0, &no_err, cg);9715 try ops[0].store(&no_err, .{}, cg);
9670 try no_err.die(cg);9716 try no_err.die(cg);
9671 try ops[0].toOffset(eu_pl_off - eu_err_off, cg);9717 try ops[0].toOffset(eu_pl_off - eu_err_off, cg);
9672 try ops[0].moveTo(inst, cg);9718 try ops[0].moveTo(inst, cg);
...@@ -9682,43 +9728,29 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9682,43 +9728,29 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9682 ), cg);9728 ), cg);
9683 try ops[0].moveTo(inst, cg);9729 try ops[0].moveTo(inst, cg);
9684 },9730 },
9685 .struct_field_ptr_index_0 => if (use_old) try cg.airStructFieldPtrIndex(inst, 0) else {9731 .struct_field_ptr_index_0,
9686 const ty_op = air_datas[@intFromEnum(inst)].ty_op;9732 .struct_field_ptr_index_1,
9687 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});9733 .struct_field_ptr_index_2,
9688 try ops[0].toOffset(cg.fieldOffset(9734 .struct_field_ptr_index_3,
9689 cg.typeOf(ty_op.operand),9735 => |air_tag| if (use_old) try cg.airStructFieldPtrIndex(inst, switch (air_tag) {
9690 ty_op.ty.toType(),9736 else => unreachable,
9691 0,9737 .struct_field_ptr_index_0 => 0,
9692 ), cg);9738 .struct_field_ptr_index_1 => 1,
9693 try ops[0].moveTo(inst, cg);9739 .struct_field_ptr_index_2 => 2,
9694 },9740 .struct_field_ptr_index_3 => 3,
9695 .struct_field_ptr_index_1 => if (use_old) try cg.airStructFieldPtrIndex(inst, 1) else {9741 }) else {
9696 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
9697 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
9698 try ops[0].toOffset(cg.fieldOffset(
9699 cg.typeOf(ty_op.operand),
9700 ty_op.ty.toType(),
9701 1,
9702 ), cg);
9703 try ops[0].moveTo(inst, cg);
9704 },
9705 .struct_field_ptr_index_2 => if (use_old) try cg.airStructFieldPtrIndex(inst, 2) else {
9706 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
9707 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
9708 try ops[0].toOffset(cg.fieldOffset(
9709 cg.typeOf(ty_op.operand),
9710 ty_op.ty.toType(),
9711 2,
9712 ), cg);
9713 try ops[0].moveTo(inst, cg);
9714 },
9715 .struct_field_ptr_index_3 => if (use_old) try cg.airStructFieldPtrIndex(inst, 3) else {
9716 const ty_op = air_datas[@intFromEnum(inst)].ty_op;9742 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
9717 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});9743 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
9718 try ops[0].toOffset(cg.fieldOffset(9744 try ops[0].toOffset(cg.fieldOffset(
9719 cg.typeOf(ty_op.operand),9745 cg.typeOf(ty_op.operand),
9720 ty_op.ty.toType(),9746 ty_op.ty.toType(),
9721 3,9747 switch (air_tag) {
9748 else => unreachable,
9749 .struct_field_ptr_index_0 => 0,
9750 .struct_field_ptr_index_1 => 1,
9751 .struct_field_ptr_index_2 => 2,
9752 .struct_field_ptr_index_3 => 3,
9753 },
9722 ), cg);9754 ), cg);
9723 try ops[0].moveTo(inst, cg);9755 try ops[0].moveTo(inst, cg);
9724 },9756 },
...@@ -9733,7 +9765,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9733,7 +9765,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9733 };9765 };
9734 if (field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {9766 if (field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
9735 var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand});9767 var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand});
9736 var res = try ops[0].read(field_off, field_ty, cg);9768 var res = try ops[0].read(field_ty, .{ .disp = field_off }, cg);
9737 for (ops) |op| if (op.index != res.index) try op.die(cg);9769 for (ops) |op| if (op.index != res.index) try op.die(cg);
9738 try res.moveTo(inst, cg);9770 try res.moveTo(inst, cg);
9739 } else {9771 } else {
...@@ -9748,7 +9780,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9748,7 +9780,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9748 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });9780 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
9749 const union_layout = union_ty.unionGetLayout(zcu);9781 const union_layout = union_ty.unionGetLayout(zcu);
9750 // hack around Sema OPV bugs9782 // hack around Sema OPV bugs
9751 if (union_layout.tag_size > 0) try ops[0].store(@intCast(union_layout.tagOffset()), &ops[1], cg);9783 if (union_layout.tag_size > 0) try ops[0].store(&ops[1], .{
9784 .disp = @intCast(union_layout.tagOffset()),
9785 }, cg);
9752 for (ops) |op| try op.die(cg);9786 for (ops) |op| try op.die(cg);
9753 },9787 },
9754 .get_union_tag => if (use_old) try cg.airGetUnionTag(inst) else {9788 .get_union_tag => if (use_old) try cg.airGetUnionTag(inst) else {
...@@ -9757,7 +9791,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9757,7 +9791,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9757 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});9791 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
9758 const union_layout = union_ty.unionGetLayout(zcu);9792 const union_layout = union_ty.unionGetLayout(zcu);
9759 assert(union_layout.tag_size > 0);9793 assert(union_layout.tag_size > 0);
9760 var res = try ops[0].read(@intCast(union_layout.tagOffset()), ty_op.ty.toType(), cg);9794 var res = try ops[0].read(ty_op.ty.toType(), .{
9795 .disp = @intCast(union_layout.tagOffset()),
9796 }, cg);
9761 for (ops) |op| if (op.index != res.index) try op.die(cg);9797 for (ops) |op| if (op.index != res.index) try op.die(cg);
9762 try res.moveTo(inst, cg);9798 try res.moveTo(inst, cg);
9763 },9799 },
...@@ -9916,7 +9952,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -9916,7 +9952,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9916 .scale = .fromFactor(@intCast(elem_size)),9952 .scale = .fromFactor(@intCast(elem_size)),
9917 } },9953 } },
9918 });9954 });
9919 res[0] = try ops[0].load(0, res_ty, cg);9955 res[0] = try ops[0].load(res_ty, .{}, cg);
9920 },9956 },
9921 },9957 },
9922 else => |e| return e,9958 else => |e| return e,
...@@ -10002,10 +10038,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -10002,10 +10038,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
10002 union_ty.unionTagTypeSafety(zcu).?,10038 union_ty.unionTagTypeSafety(zcu).?,
10003 extra.field_index,10039 extra.field_index,
10004 ));10040 ));
10005 try res.write(@intCast(union_layout.tagOffset()), &tag_temp, cg);10041 try res.write(&tag_temp, .{
10042 .disp = @intCast(union_layout.tagOffset()),
10043 }, cg);
10006 try tag_temp.die(cg);10044 try tag_temp.die(cg);
10007 }10045 }
10008 try res.write(@intCast(union_layout.payloadOffset()), &ops[0], cg);10046 try res.write(&ops[0], .{
10047 .disp = @intCast(union_layout.payloadOffset()),
10048 }, cg);
10009 try ops[0].die(cg);10049 try ops[0].die(cg);
10010 try res.moveTo(inst, cg);10050 try res.moveTo(inst, cg);
10011 },10051 },
...@@ -28338,6 +28378,7 @@ const Temp = struct {...@@ -28338,6 +28378,7 @@ const Temp = struct {
28338 return true;28378 return true;
28339 }28379 }
2834028380
28381 // hack around linker relocation bugs
28341 fn toBase(temp: *Temp, cg: *CodeGen) !bool {28382 fn toBase(temp: *Temp, cg: *CodeGen) !bool {
28342 const temp_tracking = temp.tracking(cg);28383 const temp_tracking = temp.tracking(cg);
28343 if (temp_tracking.short.isBase()) return false;28384 if (temp_tracking.short.isBase()) return false;
...@@ -28354,17 +28395,38 @@ const Temp = struct {...@@ -28354,17 +28395,38 @@ const Temp = struct {
28354 return true;28395 return true;
28355 }28396 }
2835628397
28357 fn load(ptr: *Temp, disp: i32, val_ty: Type, cg: *CodeGen) !Temp {28398 const AccessOptions = struct {
28399 disp: i32 = 0,
28400 safe: bool = false,
28401 };
28402
28403 fn load(ptr: *Temp, val_ty: Type, opts: AccessOptions, cg: *CodeGen) !Temp {
28358 const val = try cg.tempAlloc(val_ty);28404 const val = try cg.tempAlloc(val_ty);
28405 try ptr.toOffset(opts.disp, cg);
28406 while (try ptr.toLea(cg)) {}
28359 const val_mcv = val.tracking(cg).short;28407 const val_mcv = val.tracking(cg).short;
28360 switch (val_mcv) {28408 switch (val_mcv) {
28361 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),28409 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
28362 .register => |val_reg| {28410 .register => |val_reg| try ptr.loadReg(val_ty, registerAlias(
28411 val_reg,
28412 @intCast(val_ty.abiSize(cg.pt.zcu)),
28413 ), cg),
28414 inline .register_pair,
28415 .register_triple,
28416 .register_quadruple,
28417 => |val_regs| for (val_regs) |val_reg| {
28418 try ptr.loadReg(val_ty, val_reg, cg);
28419 try ptr.toOffset(@divExact(val_reg.bitSize(), 8), cg);
28363 while (try ptr.toLea(cg)) {}28420 while (try ptr.toLea(cg)) {}
28364 try cg.genSetReg(val_reg, val_ty, ptr.tracking(cg).short.offset(disp).deref(), .{});28421 },
28422 .register_offset => |val_reg_off| switch (val_reg_off.off) {
28423 0 => try ptr.loadReg(val_ty, registerAlias(
28424 val_reg_off.reg,
28425 @intCast(val_ty.abiSize(cg.pt.zcu)),
28426 ), cg),
28427 else => unreachable,
28365 },28428 },
28366 .memory, .indirect, .load_frame, .load_symbol => {28429 .memory, .indirect, .load_frame, .load_symbol => {
28367 try ptr.toOffset(disp, cg);
28368 var val_ptr = try cg.tempInit(.usize, val_mcv.address());28430 var val_ptr = try cg.tempInit(.usize, val_mcv.address());
28369 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });28431 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
28370 try val_ptr.memcpy(ptr, &len, cg);28432 try val_ptr.memcpy(ptr, &len, cg);
...@@ -28375,103 +28437,158 @@ const Temp = struct {...@@ -28375,103 +28437,158 @@ const Temp = struct {
28375 return val;28437 return val;
28376 }28438 }
2837728439
28378 fn store(ptr: *Temp, disp: i32, val: *Temp, cg: *CodeGen) !void {28440 fn store(ptr: *Temp, val: *Temp, opts: AccessOptions, cg: *CodeGen) !void {
28379 const val_ty = val.typeOf(cg);28441 const val_ty = val.typeOf(cg);
28380 val: switch (val.tracking(cg).short) {28442 try ptr.toOffset(opts.disp, cg);
28381 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),28443 while (try ptr.toLea(cg)) {}
28382 .immediate => |val_imm| {28444 val_to_gpr: while (true) : (while (try ptr.toLea(cg) or
28383 const val_op: Immediate = if (std.math.cast(u32, val_imm)) |val_uimm32|28445 try val.toRegClass(false, .general_purpose, cg))
28384 .u(val_uimm32)28446 {}) {
28385 else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|28447 const val_mcv = val.tracking(cg).short;
28386 .s(val_simm32)28448 switch (val_mcv) {
28387 else28449 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
28388 continue :val .{ .register = undefined };28450 .undef => if (opts.safe) {
28389 while (try ptr.toLea(cg)) {}28451 var pat = try cg.tempInit(.u8, .{ .immediate = 0xaa });
28390 try cg.asmMemoryImmediate(28452 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
28391 .{ ._, .mov },28453 try ptr.memset(&pat, &len, cg);
28392 try ptr.tracking(cg).short.deref().mem(cg, .{28454 try pat.die(cg);
28393 .size = cg.memSize(val_ty),28455 try len.die(cg);
28394 .disp = disp,28456 },
28395 }),28457 .immediate => |val_imm| {
28396 val_op,28458 const val_op: Immediate = if (std.math.cast(u31, val_imm)) |val_uimm31|
28397 );28459 .u(val_uimm31)
28398 },28460 else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
28399 .register => {28461 .s(val_simm32)
28400 while (try ptr.toLea(cg) or try val.toRegClass(true, .general_purpose, cg)) {}28462 else
28401 const val_reg = val.tracking(cg).short.register;28463 continue :val_to_gpr;
28402 switch (val_reg.class()) {28464 // hack around linker relocation bugs
28403 .general_purpose => try cg.asmMemoryRegister(28465 switch (ptr.tracking(cg).short) {
28466 else => {},
28467 .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {},
28468 }
28469 try cg.asmMemoryImmediate(
28404 .{ ._, .mov },28470 .{ ._, .mov },
28405 try ptr.tracking(cg).short.deref().mem(cg, .{28471 try ptr.tracking(cg).short.deref().mem(cg, .{
28406 .size = cg.memSize(val_ty),28472 .size = cg.memSize(val_ty),
28407 .disp = disp,
28408 }),28473 }),
28409 registerAlias(val_reg, @intCast(val_ty.abiSize(cg.pt.zcu))),28474 val_op,
28410 ),28475 );
28411 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),28476 },
28412 }28477 .eflags => |cc| {
28413 },28478 // hack around linker relocation bugs
28414 }28479 switch (ptr.tracking(cg).short) {
28415 }28480 else => {},
2841628481 .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {},
28417 fn read(src: *Temp, disp: i32, val_ty: Type, cg: *CodeGen) !Temp {28482 }
28418 var val = try cg.tempAlloc(val_ty);28483 try cg.asmSetccMemory(
28419 while (try src.toBase(cg)) {}28484 cc,
28420 val_to_gpr: while (true) : (while (try val.toRegClass(false, .general_purpose, cg)) {}) {28485 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }),
28421 const val_mcv = val.tracking(cg).short;28486 );
28422 switch (val_mcv) {28487 },
28423 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),28488 .register => |val_reg| try ptr.storeReg(val_ty, registerAlias(
28424 .register => |val_reg| try src.readReg(disp, val_ty, registerAlias(
28425 val_reg,28489 val_reg,
28426 @intCast(val_ty.abiSize(cg.pt.zcu)),28490 @intCast(val_ty.abiSize(cg.pt.zcu)),
28427 ), cg),28491 ), cg),
28428 inline .register_pair, .register_triple, .register_quadruple => |val_regs| {28492 inline .register_pair,
28429 var part_disp = disp;28493 .register_triple,
28430 for (val_regs) |val_reg| {28494 .register_quadruple,
28431 try src.readReg(disp, val_ty, val_reg, cg);28495 => |val_regs| for (val_regs) |val_reg| {
28432 part_disp += @divExact(val_reg.bitSize(), 8);28496 try ptr.storeReg(val_ty, val_reg, cg);
28433 }28497 try ptr.toOffset(@divExact(val_reg.bitSize(), 8), cg);
28498 while (try ptr.toLea(cg)) {}
28434 },28499 },
28435 .register_offset => |val_reg_off| switch (val_reg_off.off) {28500 .register_offset => |val_reg_off| switch (val_reg_off.off) {
28436 0 => try src.readReg(disp, val_ty, registerAlias(28501 0 => try ptr.storeReg(val_ty, registerAlias(
28437 val_reg_off.reg,28502 val_reg_off.reg,
28438 @intCast(val_ty.abiSize(cg.pt.zcu)),28503 @intCast(val_ty.abiSize(cg.pt.zcu)),
28439 ), cg),28504 ), cg),
28440 else => continue :val_to_gpr,28505 else => continue :val_to_gpr,
28441 },28506 },
28507 .register_overflow => |val_reg_ov| {
28508 const ip = &cg.pt.zcu.intern_pool;
28509 const first_ty: Type = .fromInterned(first_ty: switch (ip.indexToKey(val_ty.toIntern())) {
28510 .tuple_type => |tuple_type| {
28511 const tuple_field_types = tuple_type.types.get(ip);
28512 assert(tuple_field_types.len == 2 and tuple_field_types[1] == .u1_type);
28513 break :first_ty tuple_field_types[0];
28514 },
28515 .opt_type => |opt_child| {
28516 assert(!val_ty.optionalReprIsPayload(cg.pt.zcu));
28517 break :first_ty opt_child;
28518 },
28519 else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }),
28520 });
28521 const first_size: u31 = @intCast(first_ty.abiSize(cg.pt.zcu));
28522 try ptr.storeReg(first_ty, registerAlias(val_reg_ov.reg, first_size), cg);
28523 try ptr.toOffset(first_size, cg);
28524 try cg.asmSetccMemory(
28525 val_reg_ov.eflags,
28526 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }),
28527 );
28528 },
28442 .lea_frame, .lea_symbol => continue :val_to_gpr,28529 .lea_frame, .lea_symbol => continue :val_to_gpr,
28443 .memory, .indirect, .load_frame, .load_symbol => {28530 .memory, .indirect, .load_frame, .load_symbol => {
28444 var val_ptr = try cg.tempInit(.usize, val_mcv.address());28531 var val_ptr = try cg.tempInit(.usize, val_mcv.address());
28445 var src_ptr = try cg.tempInit(.usize, src.tracking(cg).short.address().offset(disp));
28446 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });28532 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
28447 try val_ptr.memcpy(&src_ptr, &len, cg);28533 try ptr.memcpy(&val_ptr, &len, cg);
28448 try val_ptr.die(cg);28534 try val_ptr.die(cg);
28449 try src_ptr.die(cg);
28450 try len.die(cg);28535 try len.die(cg);
28451 },28536 },
28452 }28537 }
28453 return val;28538 break;
28454 }28539 }
28455 }28540 }
2845628541
28457 fn readReg(src: Temp, disp: i32, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void {28542 fn read(src: *Temp, val_ty: Type, opts: AccessOptions, cg: *CodeGen) !Temp {
28458 const strat = try cg.moveStrategy(dst_ty, dst_reg.class(), false);28543 var val = try cg.tempAlloc(val_ty);
28459 try strat.read(cg, dst_reg, try src.tracking(cg).short.mem(cg, .{28544 while (try src.toBase(cg)) {}
28460 .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())),28545 const val_mcv = val.tracking(cg).short;
28461 .disp = disp,28546 switch (val_mcv) {
28462 }));28547 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
28548 .register => |val_reg| try src.readReg(opts.disp, val_ty, registerAlias(
28549 val_reg,
28550 @intCast(val_ty.abiSize(cg.pt.zcu)),
28551 ), cg),
28552 inline .register_pair, .register_triple, .register_quadruple => |val_regs| {
28553 var disp = opts.disp;
28554 for (val_regs) |val_reg| {
28555 try src.readReg(disp, val_ty, val_reg, cg);
28556 disp += @divExact(val_reg.bitSize(), 8);
28557 }
28558 },
28559 .register_offset => |val_reg_off| switch (val_reg_off.off) {
28560 0 => try src.readReg(opts.disp, val_ty, registerAlias(
28561 val_reg_off.reg,
28562 @intCast(val_ty.abiSize(cg.pt.zcu)),
28563 ), cg),
28564 else => unreachable,
28565 },
28566 .memory, .indirect, .load_frame, .load_symbol => {
28567 var val_ptr = try cg.tempInit(.usize, val_mcv.address());
28568 var src_ptr =
28569 try cg.tempInit(.usize, src.tracking(cg).short.address().offset(opts.disp));
28570 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
28571 try val_ptr.memcpy(&src_ptr, &len, cg);
28572 try val_ptr.die(cg);
28573 try src_ptr.die(cg);
28574 try len.die(cg);
28575 },
28576 }
28577 return val;
28463 }28578 }
2846428579
28465 fn write(dst: *Temp, disp: i32, val: *Temp, cg: *CodeGen) !void {28580 fn write(dst: *Temp, val: *Temp, opts: AccessOptions, cg: *CodeGen) !void {
28466 const val_ty = val.typeOf(cg);28581 const val_ty = val.typeOf(cg);
28467 while (try dst.toBase(cg)) {}28582 while (try dst.toBase(cg)) {}
28468 val_to_gpr: while (true) : (while (try val.toRegClass(false, .general_purpose, cg)) {}) {28583 val_to_gpr: while (true) : (while (try dst.toBase(cg) or
28584 try val.toRegClass(false, .general_purpose, cg))
28585 {}) {
28469 const val_mcv = val.tracking(cg).short;28586 const val_mcv = val.tracking(cg).short;
28470 switch (val_mcv) {28587 switch (val_mcv) {
28471 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),28588 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
28472 .immediate => |val_imm| {28589 .immediate => |val_imm| {
28473 const val_op: Immediate = if (std.math.cast(u32, val_imm)) |val_uimm32|28590 const val_op: Immediate = if (std.math.cast(u31, val_imm)) |val_uimm31|
28474 .u(val_uimm32)28591 .u(val_uimm31)
28475 else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|28592 else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
28476 .s(val_simm32)28593 .s(val_simm32)
28477 else28594 else
...@@ -28480,24 +28597,24 @@ const Temp = struct {...@@ -28480,24 +28597,24 @@ const Temp = struct {
28480 .{ ._, .mov },28597 .{ ._, .mov },
28481 try dst.tracking(cg).short.mem(cg, .{28598 try dst.tracking(cg).short.mem(cg, .{
28482 .size = cg.memSize(val_ty),28599 .size = cg.memSize(val_ty),
28483 .disp = disp,28600 .disp = opts.disp,
28484 }),28601 }),
28485 val_op,28602 val_op,
28486 );28603 );
28487 },28604 },
28488 .register => |val_reg| try dst.writeReg(disp, val_ty, registerAlias(28605 .register => |val_reg| try dst.writeReg(opts.disp, val_ty, registerAlias(
28489 val_reg,28606 val_reg,
28490 @intCast(val_ty.abiSize(cg.pt.zcu)),28607 @intCast(val_ty.abiSize(cg.pt.zcu)),
28491 ), cg),28608 ), cg),
28492 inline .register_pair, .register_triple, .register_quadruple => |val_regs| {28609 inline .register_pair, .register_triple, .register_quadruple => |val_regs| {
28493 var part_disp = disp;28610 var disp = opts.disp;
28494 for (val_regs) |val_reg| {28611 for (val_regs) |val_reg| {
28495 try dst.writeReg(part_disp, val_ty, val_reg, cg);28612 try dst.writeReg(disp, val_ty, val_reg, cg);
28496 part_disp += @divExact(val_reg.bitSize(), 8);28613 disp += @divExact(val_reg.bitSize(), 8);
28497 }28614 }
28498 },28615 },
28499 .register_offset => |val_reg_off| switch (val_reg_off.off) {28616 .register_offset => |val_reg_off| switch (val_reg_off.off) {
28500 0 => try dst.writeReg(disp, val_ty, registerAlias(28617 0 => try dst.writeReg(opts.disp, val_ty, registerAlias(
28501 val_reg_off.reg,28618 val_reg_off.reg,
28502 @intCast(val_ty.abiSize(cg.pt.zcu)),28619 @intCast(val_ty.abiSize(cg.pt.zcu)),
28503 ), cg),28620 ), cg),
...@@ -28505,7 +28622,8 @@ const Temp = struct {...@@ -28505,7 +28622,8 @@ const Temp = struct {
28505 },28622 },
28506 .lea_frame, .lea_symbol => continue :val_to_gpr,28623 .lea_frame, .lea_symbol => continue :val_to_gpr,
28507 .memory, .indirect, .load_frame, .load_symbol => {28624 .memory, .indirect, .load_frame, .load_symbol => {
28508 var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(disp));28625 var dst_ptr =
28626 try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(opts.disp));
28509 var val_ptr = try cg.tempInit(.usize, val_mcv.address());28627 var val_ptr = try cg.tempInit(.usize, val_mcv.address());
28510 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });28628 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
28511 try dst_ptr.memcpy(&val_ptr, &len, cg);28629 try dst_ptr.memcpy(&val_ptr, &len, cg);
...@@ -28514,10 +28632,62 @@ const Temp = struct {...@@ -28514,10 +28632,62 @@ const Temp = struct {
28514 try len.die(cg);28632 try len.die(cg);
28515 },28633 },
28516 }28634 }
28517 return;28635 break;
28636 }
28637 }
28638
28639 fn loadReg(ptr: *Temp, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void {
28640 const dst_rc = dst_reg.class();
28641 const strat = try cg.moveStrategy(dst_ty, dst_rc, false);
28642 // hack around linker relocation bugs
28643 switch (ptr.tracking(cg).short) {
28644 else => {},
28645 .lea_symbol => |sym_off| if (dst_rc != .general_purpose or sym_off.off != 0)
28646 while (try ptr.toRegClass(false, .general_purpose, cg)) {},
28647 }
28648 try strat.read(cg, dst_reg, try ptr.tracking(cg).short.deref().mem(cg, .{
28649 .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())),
28650 }));
28651 }
28652
28653 fn storeReg(ptr: *Temp, src_ty: Type, src_reg: Register, cg: *CodeGen) !void {
28654 const src_rc = src_reg.class();
28655 const src_abi_size = src_ty.abiSize(cg.pt.zcu);
28656 const strat = try cg.moveStrategy(src_ty, src_rc, false);
28657 // hack around linker relocation bugs
28658 switch (ptr.tracking(cg).short) {
28659 else => {},
28660 .lea_symbol => |sym_off| if (src_rc != .general_purpose or sym_off.off != 0)
28661 while (try ptr.toRegClass(false, .general_purpose, cg)) {},
28662 }
28663 if (src_rc == .x87 or std.math.isPowerOfTwo(src_abi_size)) {
28664 try strat.write(cg, try ptr.tracking(cg).short.deref().mem(cg, .{
28665 .size = .fromBitSize(@min(8 * src_abi_size, src_reg.bitSize())),
28666 }), src_reg);
28667 } else {
28668 const frame_alloc: FrameAlloc = .initSpill(src_ty, cg.pt.zcu);
28669 const frame_index = try cg.allocFrameIndex(frame_alloc);
28670 const frame_size: Memory.Size = .fromSize(frame_alloc.abi_size);
28671 try strat.write(cg, .{
28672 .base = .{ .frame = frame_index },
28673 .mod = .{ .rm = .{ .size = frame_size } },
28674 }, src_reg);
28675 var src_ptr = try cg.tempInit(.usize, .{ .lea_frame = .{ .index = frame_index } });
28676 var len = try cg.tempInit(.usize, .{ .immediate = src_abi_size });
28677 try ptr.memcpy(&src_ptr, &len, cg);
28678 try src_ptr.die(cg);
28679 try len.die(cg);
28518 }28680 }
28519 }28681 }
2852028682
28683 fn readReg(src: Temp, disp: i32, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void {
28684 const strat = try cg.moveStrategy(dst_ty, dst_reg.class(), false);
28685 try strat.read(cg, dst_reg, try src.tracking(cg).short.mem(cg, .{
28686 .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())),
28687 .disp = disp,
28688 }));
28689 }
28690
28521 fn writeReg(dst: Temp, disp: i32, src_ty: Type, src_reg: Register, cg: *CodeGen) !void {28691 fn writeReg(dst: Temp, disp: i32, src_ty: Type, src_reg: Register, cg: *CodeGen) !void {
28522 const src_rc = src_reg.class();28692 const src_rc = src_reg.class();
28523 const src_abi_size = src_ty.abiSize(cg.pt.zcu);28693 const src_abi_size = src_ty.abiSize(cg.pt.zcu);
...@@ -28552,6 +28722,13 @@ const Temp = struct {...@@ -28552,6 +28722,13 @@ const Temp = struct {
28552 try cg.asmOpOnly(.{ .@"rep _sb", .mov });28722 try cg.asmOpOnly(.{ .@"rep _sb", .mov });
28553 }28723 }
2855428724
28725 fn memset(dst: *Temp, val: *Temp, len: *Temp, cg: *CodeGen) !void {
28726 while (true) for ([_]*Temp{ dst, val, len }, [_]Register{ .rdi, .rax, .rcx }) |temp, reg| {
28727 if (try temp.toReg(reg, cg)) break;
28728 } else break;
28729 try cg.asmOpOnly(.{ .@"rep _sb", .sto });
28730 }
28731
28555 fn moveTo(temp: Temp, inst: Air.Inst.Index, cg: *CodeGen) !void {28732 fn moveTo(temp: Temp, inst: Air.Inst.Index, cg: *CodeGen) !void {
28556 if (cg.liveness.isUnused(inst)) try temp.die(cg) else switch (temp.unwrap(cg)) {28733 if (cg.liveness.isUnused(inst)) try temp.die(cg) else switch (temp.unwrap(cg)) {
28557 .ref => {28734 .ref => {
test/behavior/basic.zig+1-1
...@@ -1169,10 +1169,10 @@ test "arrays and vectors with big integers" {...@@ -1169,10 +1169,10 @@ test "arrays and vectors with big integers" {
1169 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1169 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;1170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1172 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1173 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;1172 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1174 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1173 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1175 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1174 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1175 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
11761176
1177 inline for (.{ u65528, u65529, u65535 }) |Int| {1177 inline for (.{ u65528, u65529, u65535 }) |Int| {
1178 var a: [1]Int = undefined;1178 var a: [1]Int = undefined;