| ... | ... | @@ -257,6 +257,7 @@ pub const MCValue = union(enum) { |
| 257 | 257 | }; |
| 258 | 258 | } |
| 259 | 259 | |
| 260 | // hack around linker relocation bugs |
| 260 | 261 | fn isBase(mcv: MCValue) bool { |
| 261 | 262 | return switch (mcv) { |
| 262 | 263 | .memory, .indirect, .load_frame => true, |
| ... | ... | @@ -2398,8 +2399,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 2398 | 2399 | .add_wrap, |
| 2399 | 2400 | .sub, |
| 2400 | 2401 | .sub_wrap, |
| 2401 | | .bool_and, |
| 2402 | | .bool_or, |
| 2403 | 2402 | .min, |
| 2404 | 2403 | .max, |
| 2405 | 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 | 2453 | .is_null => try cg.airIsNull(inst), |
| 2455 | 2454 | .is_non_err => try cg.airIsNonErr(inst), |
| 2456 | 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 | 2456 | .float_from_int => try cg.airFloatFromInt(inst), |
| 2461 | 2457 | .int_from_float => try cg.airIntFromFloat(inst), |
| 2462 | 2458 | .cmpxchg_strong => try cg.airCmpxchg(inst), |
| ... | ... | @@ -2791,14 +2787,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 2791 | 2787 | try slot.moveTo(inst, cg); |
| 2792 | 2788 | }, |
| 2793 | 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 | 2791 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; |
| 2796 | 2792 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 2797 | 2793 | var res: [1]Temp = undefined; |
| 2798 | 2794 | cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) { |
| 2799 | 2795 | else => unreachable, |
| 2800 | | .bit_and => .@"and", |
| 2801 | | .bit_or => .@"or", |
| 2796 | .bit_and, .bool_and => .@"and", |
| 2797 | .bit_or, .bool_or => .@"or", |
| 2802 | 2798 | .xor => .xor, |
| 2803 | 2799 | })) { |
| 2804 | 2800 | else => unreachable, |
| ... | ... | @@ -9601,6 +9597,25 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 9601 | 9597 | try ops[0].die(cg); |
| 9602 | 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 | 9619 | .int_from_ptr => if (use_old) try cg.airIntFromPtr(inst) else { |
| 9605 | 9620 | const un_op = air_datas[@intFromEnum(inst)].un_op; |
| 9606 | 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 | 9630 | .ret => try cg.airRet(inst, false), |
| 9616 | 9631 | .ret_safe => try cg.airRet(inst, true), |
| 9617 | 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 | 9664 | .unreach => {}, |
| 9619 | 9665 | .optional_payload_ptr => if (use_old) try cg.airOptionalPayloadPtr(inst) else { |
| 9620 | 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 | 9676 | const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu)); |
| 9631 | 9677 | try ops[0].toOffset(opt_child_abi_size, cg); |
| 9632 | 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 | 9680 | try has_value.die(cg); |
| 9635 | 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 | 9698 | const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu)); |
| 9653 | 9699 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9654 | 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 | 9702 | try ops[0].die(cg); |
| 9657 | 9703 | try err.moveTo(inst, cg); |
| 9658 | 9704 | }, |
| ... | ... | @@ -9666,7 +9712,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 9666 | 9712 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9667 | 9713 | try ops[0].toOffset(eu_err_off, cg); |
| 9668 | 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 | 9716 | try no_err.die(cg); |
| 9671 | 9717 | try ops[0].toOffset(eu_pl_off - eu_err_off, cg); |
| 9672 | 9718 | try ops[0].moveTo(inst, cg); |
| ... | ... | @@ -9682,43 +9728,29 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 9682 | 9728 | ), cg); |
| 9683 | 9729 | try ops[0].moveTo(inst, cg); |
| 9684 | 9730 | }, |
| 9685 | | .struct_field_ptr_index_0 => if (use_old) try cg.airStructFieldPtrIndex(inst, 0) else { |
| 9686 | | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9687 | | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9688 | | try ops[0].toOffset(cg.fieldOffset( |
| 9689 | | cg.typeOf(ty_op.operand), |
| 9690 | | ty_op.ty.toType(), |
| 9691 | | 0, |
| 9692 | | ), cg); |
| 9693 | | try ops[0].moveTo(inst, cg); |
| 9694 | | }, |
| 9695 | | .struct_field_ptr_index_1 => if (use_old) try cg.airStructFieldPtrIndex(inst, 1) 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 { |
| 9731 | .struct_field_ptr_index_0, |
| 9732 | .struct_field_ptr_index_1, |
| 9733 | .struct_field_ptr_index_2, |
| 9734 | .struct_field_ptr_index_3, |
| 9735 | => |air_tag| if (use_old) try cg.airStructFieldPtrIndex(inst, switch (air_tag) { |
| 9736 | else => unreachable, |
| 9737 | .struct_field_ptr_index_0 => 0, |
| 9738 | .struct_field_ptr_index_1 => 1, |
| 9739 | .struct_field_ptr_index_2 => 2, |
| 9740 | .struct_field_ptr_index_3 => 3, |
| 9741 | }) else { |
| 9716 | 9742 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 9717 | 9743 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9718 | 9744 | try ops[0].toOffset(cg.fieldOffset( |
| 9719 | 9745 | cg.typeOf(ty_op.operand), |
| 9720 | 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 | 9754 | ), cg); |
| 9723 | 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 | 9765 | }; |
| 9734 | 9766 | if (field_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 9735 | 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 | 9769 | for (ops) |op| if (op.index != res.index) try op.die(cg); |
| 9738 | 9770 | try res.moveTo(inst, cg); |
| 9739 | 9771 | } else { |
| ... | ... | @@ -9748,7 +9780,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 9748 | 9780 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 9749 | 9781 | const union_layout = union_ty.unionGetLayout(zcu); |
| 9750 | 9782 | // 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 | 9786 | for (ops) |op| try op.die(cg); |
| 9753 | 9787 | }, |
| 9754 | 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 | 9791 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 9758 | 9792 | const union_layout = union_ty.unionGetLayout(zcu); |
| 9759 | 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 | 9797 | for (ops) |op| if (op.index != res.index) try op.die(cg); |
| 9762 | 9798 | try res.moveTo(inst, cg); |
| 9763 | 9799 | }, |
| ... | ... | @@ -9916,7 +9952,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 9916 | 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 | 9958 | else => |e| return e, |
| ... | ... | @@ -10002,10 +10038,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 10002 | 10038 | union_ty.unionTagTypeSafety(zcu).?, |
| 10003 | 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 | 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 | 10049 | try ops[0].die(cg); |
| 10010 | 10050 | try res.moveTo(inst, cg); |
| 10011 | 10051 | }, |
| ... | ... | @@ -28338,6 +28378,7 @@ const Temp = struct { |
| 28338 | 28378 | return true; |
| 28339 | 28379 | } |
| 28340 | 28380 | |
| 28381 | // hack around linker relocation bugs |
| 28341 | 28382 | fn toBase(temp: *Temp, cg: *CodeGen) !bool { |
| 28342 | 28383 | const temp_tracking = temp.tracking(cg); |
| 28343 | 28384 | if (temp_tracking.short.isBase()) return false; |
| ... | ... | @@ -28354,17 +28395,38 @@ const Temp = struct { |
| 28354 | 28395 | return true; |
| 28355 | 28396 | } |
| 28356 | 28397 | |
| 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 | 28404 | const val = try cg.tempAlloc(val_ty); |
| 28405 | try ptr.toOffset(opts.disp, cg); |
| 28406 | while (try ptr.toLea(cg)) {} |
| 28359 | 28407 | const val_mcv = val.tracking(cg).short; |
| 28360 | 28408 | switch (val_mcv) { |
| 28361 | 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 | 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 | 28429 | .memory, .indirect, .load_frame, .load_symbol => { |
| 28367 | | try ptr.toOffset(disp, cg); |
| 28368 | 28430 | var val_ptr = try cg.tempInit(.usize, val_mcv.address()); |
| 28369 | 28431 | var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); |
| 28370 | 28432 | try val_ptr.memcpy(ptr, &len, cg); |
| ... | ... | @@ -28375,103 +28437,158 @@ const Temp = struct { |
| 28375 | 28437 | return val; |
| 28376 | 28438 | } |
| 28377 | 28439 | |
| 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 | 28441 | const val_ty = val.typeOf(cg); |
| 28380 | | val: switch (val.tracking(cg).short) { |
| 28381 | | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28382 | | .immediate => |val_imm| { |
| 28383 | | const val_op: Immediate = if (std.math.cast(u32, val_imm)) |val_uimm32| |
| 28384 | | .u(val_uimm32) |
| 28385 | | else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32| |
| 28386 | | .s(val_simm32) |
| 28387 | | else |
| 28388 | | continue :val .{ .register = undefined }; |
| 28389 | | while (try ptr.toLea(cg)) {} |
| 28390 | | try cg.asmMemoryImmediate( |
| 28391 | | .{ ._, .mov }, |
| 28392 | | try ptr.tracking(cg).short.deref().mem(cg, .{ |
| 28393 | | .size = cg.memSize(val_ty), |
| 28394 | | .disp = disp, |
| 28395 | | }), |
| 28396 | | val_op, |
| 28397 | | ); |
| 28398 | | }, |
| 28399 | | .register => { |
| 28400 | | while (try ptr.toLea(cg) or try val.toRegClass(true, .general_purpose, cg)) {} |
| 28401 | | const val_reg = val.tracking(cg).short.register; |
| 28402 | | switch (val_reg.class()) { |
| 28403 | | .general_purpose => try cg.asmMemoryRegister( |
| 28442 | try ptr.toOffset(opts.disp, cg); |
| 28443 | while (try ptr.toLea(cg)) {} |
| 28444 | val_to_gpr: while (true) : (while (try ptr.toLea(cg) or |
| 28445 | try val.toRegClass(false, .general_purpose, cg)) |
| 28446 | {}) { |
| 28447 | const val_mcv = val.tracking(cg).short; |
| 28448 | switch (val_mcv) { |
| 28449 | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28450 | .undef => if (opts.safe) { |
| 28451 | var pat = try cg.tempInit(.u8, .{ .immediate = 0xaa }); |
| 28452 | var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); |
| 28453 | try ptr.memset(&pat, &len, cg); |
| 28454 | try pat.die(cg); |
| 28455 | try len.die(cg); |
| 28456 | }, |
| 28457 | .immediate => |val_imm| { |
| 28458 | const val_op: Immediate = if (std.math.cast(u31, val_imm)) |val_uimm31| |
| 28459 | .u(val_uimm31) |
| 28460 | else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32| |
| 28461 | .s(val_simm32) |
| 28462 | else |
| 28463 | continue :val_to_gpr; |
| 28464 | // hack around linker relocation bugs |
| 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 | 28470 | .{ ._, .mov }, |
| 28405 | 28471 | try ptr.tracking(cg).short.deref().mem(cg, .{ |
| 28406 | 28472 | .size = cg.memSize(val_ty), |
| 28407 | | .disp = disp, |
| 28408 | 28473 | }), |
| 28409 | | registerAlias(val_reg, @intCast(val_ty.abiSize(cg.pt.zcu))), |
| 28410 | | ), |
| 28411 | | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28412 | | } |
| 28413 | | }, |
| 28414 | | } |
| 28415 | | } |
| 28416 | | |
| 28417 | | fn read(src: *Temp, disp: i32, val_ty: Type, cg: *CodeGen) !Temp { |
| 28418 | | var val = try cg.tempAlloc(val_ty); |
| 28419 | | while (try src.toBase(cg)) {} |
| 28420 | | val_to_gpr: while (true) : (while (try val.toRegClass(false, .general_purpose, cg)) {}) { |
| 28421 | | const val_mcv = val.tracking(cg).short; |
| 28422 | | switch (val_mcv) { |
| 28423 | | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28424 | | .register => |val_reg| try src.readReg(disp, val_ty, registerAlias( |
| 28474 | val_op, |
| 28475 | ); |
| 28476 | }, |
| 28477 | .eflags => |cc| { |
| 28478 | // hack around linker relocation bugs |
| 28479 | switch (ptr.tracking(cg).short) { |
| 28480 | else => {}, |
| 28481 | .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {}, |
| 28482 | } |
| 28483 | try cg.asmSetccMemory( |
| 28484 | cc, |
| 28485 | try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }), |
| 28486 | ); |
| 28487 | }, |
| 28488 | .register => |val_reg| try ptr.storeReg(val_ty, registerAlias( |
| 28425 | 28489 | val_reg, |
| 28426 | 28490 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28427 | 28491 | ), cg), |
| 28428 | | inline .register_pair, .register_triple, .register_quadruple => |val_regs| { |
| 28429 | | var part_disp = disp; |
| 28430 | | for (val_regs) |val_reg| { |
| 28431 | | try src.readReg(disp, val_ty, val_reg, cg); |
| 28432 | | part_disp += @divExact(val_reg.bitSize(), 8); |
| 28433 | | } |
| 28492 | inline .register_pair, |
| 28493 | .register_triple, |
| 28494 | .register_quadruple, |
| 28495 | => |val_regs| for (val_regs) |val_reg| { |
| 28496 | try ptr.storeReg(val_ty, val_reg, cg); |
| 28497 | try ptr.toOffset(@divExact(val_reg.bitSize(), 8), cg); |
| 28498 | while (try ptr.toLea(cg)) {} |
| 28434 | 28499 | }, |
| 28435 | 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 | 28502 | val_reg_off.reg, |
| 28438 | 28503 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28439 | 28504 | ), cg), |
| 28440 | 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 | 28529 | .lea_frame, .lea_symbol => continue :val_to_gpr, |
| 28443 | 28530 | .memory, .indirect, .load_frame, .load_symbol => { |
| 28444 | 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 | 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 | 28534 | try val_ptr.die(cg); |
| 28449 | | try src_ptr.die(cg); |
| 28450 | 28535 | try len.die(cg); |
| 28451 | 28536 | }, |
| 28452 | 28537 | } |
| 28453 | | return val; |
| 28538 | break; |
| 28454 | 28539 | } |
| 28455 | 28540 | } |
| 28456 | 28541 | |
| 28457 | | fn readReg(src: Temp, disp: i32, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void { |
| 28458 | | const strat = try cg.moveStrategy(dst_ty, dst_reg.class(), false); |
| 28459 | | try strat.read(cg, dst_reg, try src.tracking(cg).short.mem(cg, .{ |
| 28460 | | .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())), |
| 28461 | | .disp = disp, |
| 28462 | | })); |
| 28542 | fn read(src: *Temp, val_ty: Type, opts: AccessOptions, cg: *CodeGen) !Temp { |
| 28543 | var val = try cg.tempAlloc(val_ty); |
| 28544 | while (try src.toBase(cg)) {} |
| 28545 | const val_mcv = val.tracking(cg).short; |
| 28546 | switch (val_mcv) { |
| 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 | } |
| 28464 | 28579 | |
| 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 | 28581 | const val_ty = val.typeOf(cg); |
| 28467 | 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 | 28586 | const val_mcv = val.tracking(cg).short; |
| 28470 | 28587 | switch (val_mcv) { |
| 28471 | 28588 | else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }), |
| 28472 | 28589 | .immediate => |val_imm| { |
| 28473 | | const val_op: Immediate = if (std.math.cast(u32, val_imm)) |val_uimm32| |
| 28474 | | .u(val_uimm32) |
| 28590 | const val_op: Immediate = if (std.math.cast(u31, val_imm)) |val_uimm31| |
| 28591 | .u(val_uimm31) |
| 28475 | 28592 | else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32| |
| 28476 | 28593 | .s(val_simm32) |
| 28477 | 28594 | else |
| ... | ... | @@ -28480,24 +28597,24 @@ const Temp = struct { |
| 28480 | 28597 | .{ ._, .mov }, |
| 28481 | 28598 | try dst.tracking(cg).short.mem(cg, .{ |
| 28482 | 28599 | .size = cg.memSize(val_ty), |
| 28483 | | .disp = disp, |
| 28600 | .disp = opts.disp, |
| 28484 | 28601 | }), |
| 28485 | 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 | 28606 | val_reg, |
| 28490 | 28607 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28491 | 28608 | ), cg), |
| 28492 | 28609 | inline .register_pair, .register_triple, .register_quadruple => |val_regs| { |
| 28493 | | var part_disp = disp; |
| 28610 | var disp = opts.disp; |
| 28494 | 28611 | for (val_regs) |val_reg| { |
| 28495 | | try dst.writeReg(part_disp, val_ty, val_reg, cg); |
| 28496 | | part_disp += @divExact(val_reg.bitSize(), 8); |
| 28612 | try dst.writeReg(disp, val_ty, val_reg, cg); |
| 28613 | disp += @divExact(val_reg.bitSize(), 8); |
| 28497 | 28614 | } |
| 28498 | 28615 | }, |
| 28499 | 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 | 28618 | val_reg_off.reg, |
| 28502 | 28619 | @intCast(val_ty.abiSize(cg.pt.zcu)), |
| 28503 | 28620 | ), cg), |
| ... | ... | @@ -28505,7 +28622,8 @@ const Temp = struct { |
| 28505 | 28622 | }, |
| 28506 | 28623 | .lea_frame, .lea_symbol => continue :val_to_gpr, |
| 28507 | 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 | 28627 | var val_ptr = try cg.tempInit(.usize, val_mcv.address()); |
| 28510 | 28628 | var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); |
| 28511 | 28629 | try dst_ptr.memcpy(&val_ptr, &len, cg); |
| ... | ... | @@ -28514,10 +28632,62 @@ const Temp = struct { |
| 28514 | 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 | } |
| 28520 | 28682 | |
| 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 | 28691 | fn writeReg(dst: Temp, disp: i32, src_ty: Type, src_reg: Register, cg: *CodeGen) !void { |
| 28522 | 28692 | const src_rc = src_reg.class(); |
| 28523 | 28693 | const src_abi_size = src_ty.abiSize(cg.pt.zcu); |
| ... | ... | @@ -28552,6 +28722,13 @@ const Temp = struct { |
| 28552 | 28722 | try cg.asmOpOnly(.{ .@"rep _sb", .mov }); |
| 28553 | 28723 | } |
| 28554 | 28724 | |
| 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 | 28732 | fn moveTo(temp: Temp, inst: Air.Inst.Index, cg: *CodeGen) !void { |
| 28556 | 28733 | if (cg.liveness.isUnused(inst)) try temp.die(cg) else switch (temp.unwrap(cg)) { |
| 28557 | 28734 | .ref => { |