Commit 666d76d85c
Changed files (2)
src
arch
x86_64
test
behavior
src/arch/x86_64/CodeGen.zig
@@ -257,6 +257,7 @@ pub const MCValue = union(enum) {
};
}
+ // hack around linker relocation bugs
fn isBase(mcv: MCValue) bool {
return switch (mcv) {
.memory, .indirect, .load_frame => true,
@@ -2398,8 +2399,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.add_wrap,
.sub,
.sub_wrap,
- .bool_and,
- .bool_or,
.min,
.max,
=> |air_tag| try cg.airBinOp(inst, air_tag),
@@ -2454,9 +2453,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.is_null => try cg.airIsNull(inst),
.is_non_err => try cg.airIsNonErr(inst),
.is_err => try cg.airIsErr(inst),
- .load => try cg.airLoad(inst),
- .store => try cg.airStore(inst, false),
- .store_safe => try cg.airStore(inst, true),
.float_from_int => try cg.airFloatFromInt(inst),
.int_from_float => try cg.airIntFromFloat(inst),
.cmpxchg_strong => try cg.airCmpxchg(inst),
@@ -2791,14 +2787,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
try slot.moveTo(inst, cg);
},
.assembly => try cg.airAsm(inst),
- .bit_and, .bit_or, .xor => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else {
+ .bit_and, .bit_or, .xor, .bool_and, .bool_or => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else {
const bin_op = air_datas[@intFromEnum(inst)].bin_op;
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
var res: [1]Temp = undefined;
cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) {
else => unreachable,
- .bit_and => .@"and",
- .bit_or => .@"or",
+ .bit_and, .bool_and => .@"and",
+ .bit_or, .bool_or => .@"or",
.xor => .xor,
})) {
else => unreachable,
@@ -9601,6 +9597,25 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
try ops[0].die(cg);
try is_non_err.moveTo(inst, cg);
},
+ .load => if (use_old) try cg.airLoad(inst) else fallback: {
+ const ty_op = air_datas[@intFromEnum(inst)].ty_op;
+ const val_ty = ty_op.ty.toType();
+ const ptr_ty = cg.typeOf(ty_op.operand);
+ const ptr_info = ptr_ty.ptrInfo(zcu);
+ if (ptr_info.packed_offset.host_size > 0 and
+ (ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type))
+ break :fallback try cg.airLoad(inst);
+ var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
+ var res = try ops[0].load(val_ty, .{
+ .disp = switch (ptr_info.flags.vector_index) {
+ .none => 0,
+ .runtime => unreachable,
+ else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)),
+ },
+ }, cg);
+ for (ops) |op| if (op.index != res.index) try op.die(cg);
+ try res.moveTo(inst, cg);
+ },
.int_from_ptr => if (use_old) try cg.airIntFromPtr(inst) else {
const un_op = air_datas[@intFromEnum(inst)].un_op;
var ops = try cg.tempsFromOperands(inst, .{un_op});
@@ -9615,6 +9630,37 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.ret => try cg.airRet(inst, false),
.ret_safe => try cg.airRet(inst, true),
.ret_load => try cg.airRetLoad(inst),
+ .store, .store_safe => |air_tag| if (use_old) try cg.airStore(inst, switch (air_tag) {
+ else => unreachable,
+ .store => false,
+ .store_safe => true,
+ }) else fallback: {
+ const bin_op = air_datas[@intFromEnum(inst)].bin_op;
+ const ptr_ty = cg.typeOf(bin_op.lhs);
+ const ptr_info = ptr_ty.ptrInfo(zcu);
+ const val_ty = cg.typeOf(bin_op.rhs);
+ if (ptr_info.packed_offset.host_size > 0 and
+ (ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type))
+ break :fallback try cg.airStore(inst, switch (air_tag) {
+ else => unreachable,
+ .store => false,
+ .store_safe => true,
+ });
+ var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
+ try ops[0].store(&ops[1], .{
+ .disp = switch (ptr_info.flags.vector_index) {
+ .none => 0,
+ .runtime => unreachable,
+ else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)),
+ },
+ .safe = switch (air_tag) {
+ else => unreachable,
+ .store => false,
+ .store_safe => true,
+ },
+ }, cg);
+ for (ops) |op| try op.die(cg);
+ },
.unreach => {},
.optional_payload_ptr => if (use_old) try cg.airOptionalPayloadPtr(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
@@ -9630,7 +9676,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu));
try ops[0].toOffset(opt_child_abi_size, cg);
var has_value = try cg.tempInit(.bool, .{ .immediate = 1 });
- try ops[0].store(0, &has_value, cg);
+ try ops[0].store(&has_value, .{}, cg);
try has_value.die(cg);
try ops[0].toOffset(-opt_child_abi_size, cg);
}
@@ -9652,7 +9698,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(eu_err_off, cg);
- var err = try ops[0].load(0, eu_ty.errorUnionSet(zcu), cg);
+ var err = try ops[0].load(eu_ty.errorUnionSet(zcu), .{}, cg);
try ops[0].die(cg);
try err.moveTo(inst, cg);
},
@@ -9666,7 +9712,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(eu_err_off, cg);
var no_err = try cg.tempInit(eu_err_ty, .{ .immediate = 0 });
- try ops[0].store(0, &no_err, cg);
+ try ops[0].store(&no_err, .{}, cg);
try no_err.die(cg);
try ops[0].toOffset(eu_pl_off - eu_err_off, cg);
try ops[0].moveTo(inst, cg);
@@ -9682,43 +9728,29 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
), cg);
try ops[0].moveTo(inst, cg);
},
- .struct_field_ptr_index_0 => if (use_old) try cg.airStructFieldPtrIndex(inst, 0) else {
- const ty_op = air_datas[@intFromEnum(inst)].ty_op;
- var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
- try ops[0].toOffset(cg.fieldOffset(
- cg.typeOf(ty_op.operand),
- ty_op.ty.toType(),
- 0,
- ), cg);
- try ops[0].moveTo(inst, cg);
- },
- .struct_field_ptr_index_1 => if (use_old) try cg.airStructFieldPtrIndex(inst, 1) else {
- const ty_op = air_datas[@intFromEnum(inst)].ty_op;
- var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
- try ops[0].toOffset(cg.fieldOffset(
- cg.typeOf(ty_op.operand),
- ty_op.ty.toType(),
- 1,
- ), cg);
- try ops[0].moveTo(inst, cg);
- },
- .struct_field_ptr_index_2 => if (use_old) try cg.airStructFieldPtrIndex(inst, 2) else {
- const ty_op = air_datas[@intFromEnum(inst)].ty_op;
- var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
- try ops[0].toOffset(cg.fieldOffset(
- cg.typeOf(ty_op.operand),
- ty_op.ty.toType(),
- 2,
- ), cg);
- try ops[0].moveTo(inst, cg);
- },
- .struct_field_ptr_index_3 => if (use_old) try cg.airStructFieldPtrIndex(inst, 3) else {
+ .struct_field_ptr_index_0,
+ .struct_field_ptr_index_1,
+ .struct_field_ptr_index_2,
+ .struct_field_ptr_index_3,
+ => |air_tag| if (use_old) try cg.airStructFieldPtrIndex(inst, switch (air_tag) {
+ else => unreachable,
+ .struct_field_ptr_index_0 => 0,
+ .struct_field_ptr_index_1 => 1,
+ .struct_field_ptr_index_2 => 2,
+ .struct_field_ptr_index_3 => 3,
+ }) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(cg.fieldOffset(
cg.typeOf(ty_op.operand),
ty_op.ty.toType(),
- 3,
+ switch (air_tag) {
+ else => unreachable,
+ .struct_field_ptr_index_0 => 0,
+ .struct_field_ptr_index_1 => 1,
+ .struct_field_ptr_index_2 => 2,
+ .struct_field_ptr_index_3 => 3,
+ },
), cg);
try ops[0].moveTo(inst, cg);
},
@@ -9733,7 +9765,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
};
if (field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand});
- var res = try ops[0].read(field_off, field_ty, cg);
+ var res = try ops[0].read(field_ty, .{ .disp = field_off }, cg);
for (ops) |op| if (op.index != res.index) try op.die(cg);
try res.moveTo(inst, cg);
} else {
@@ -9748,7 +9780,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
const union_layout = union_ty.unionGetLayout(zcu);
// hack around Sema OPV bugs
- if (union_layout.tag_size > 0) try ops[0].store(@intCast(union_layout.tagOffset()), &ops[1], cg);
+ if (union_layout.tag_size > 0) try ops[0].store(&ops[1], .{
+ .disp = @intCast(union_layout.tagOffset()),
+ }, cg);
for (ops) |op| try op.die(cg);
},
.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 {
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
const union_layout = union_ty.unionGetLayout(zcu);
assert(union_layout.tag_size > 0);
- var res = try ops[0].read(@intCast(union_layout.tagOffset()), ty_op.ty.toType(), cg);
+ var res = try ops[0].read(ty_op.ty.toType(), .{
+ .disp = @intCast(union_layout.tagOffset()),
+ }, cg);
for (ops) |op| if (op.index != res.index) try op.die(cg);
try res.moveTo(inst, cg);
},
@@ -9916,7 +9952,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.scale = .fromFactor(@intCast(elem_size)),
} },
});
- res[0] = try ops[0].load(0, res_ty, cg);
+ res[0] = try ops[0].load(res_ty, .{}, cg);
},
},
else => |e| return e,
@@ -10002,10 +10038,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
union_ty.unionTagTypeSafety(zcu).?,
extra.field_index,
));
- try res.write(@intCast(union_layout.tagOffset()), &tag_temp, cg);
+ try res.write(&tag_temp, .{
+ .disp = @intCast(union_layout.tagOffset()),
+ }, cg);
try tag_temp.die(cg);
}
- try res.write(@intCast(union_layout.payloadOffset()), &ops[0], cg);
+ try res.write(&ops[0], .{
+ .disp = @intCast(union_layout.payloadOffset()),
+ }, cg);
try ops[0].die(cg);
try res.moveTo(inst, cg);
},
@@ -28338,6 +28378,7 @@ const Temp = struct {
return true;
}
+ // hack around linker relocation bugs
fn toBase(temp: *Temp, cg: *CodeGen) !bool {
const temp_tracking = temp.tracking(cg);
if (temp_tracking.short.isBase()) return false;
@@ -28354,17 +28395,38 @@ const Temp = struct {
return true;
}
- fn load(ptr: *Temp, disp: i32, val_ty: Type, cg: *CodeGen) !Temp {
+ const AccessOptions = struct {
+ disp: i32 = 0,
+ safe: bool = false,
+ };
+
+ fn load(ptr: *Temp, val_ty: Type, opts: AccessOptions, cg: *CodeGen) !Temp {
const val = try cg.tempAlloc(val_ty);
+ try ptr.toOffset(opts.disp, cg);
+ while (try ptr.toLea(cg)) {}
const val_mcv = val.tracking(cg).short;
switch (val_mcv) {
else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
- .register => |val_reg| {
+ .register => |val_reg| try ptr.loadReg(val_ty, registerAlias(
+ val_reg,
+ @intCast(val_ty.abiSize(cg.pt.zcu)),
+ ), cg),
+ inline .register_pair,
+ .register_triple,
+ .register_quadruple,
+ => |val_regs| for (val_regs) |val_reg| {
+ try ptr.loadReg(val_ty, val_reg, cg);
+ try ptr.toOffset(@divExact(val_reg.bitSize(), 8), cg);
while (try ptr.toLea(cg)) {}
- try cg.genSetReg(val_reg, val_ty, ptr.tracking(cg).short.offset(disp).deref(), .{});
+ },
+ .register_offset => |val_reg_off| switch (val_reg_off.off) {
+ 0 => try ptr.loadReg(val_ty, registerAlias(
+ val_reg_off.reg,
+ @intCast(val_ty.abiSize(cg.pt.zcu)),
+ ), cg),
+ else => unreachable,
},
.memory, .indirect, .load_frame, .load_symbol => {
- try ptr.toOffset(disp, cg);
var val_ptr = try cg.tempInit(.usize, val_mcv.address());
var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
try val_ptr.memcpy(ptr, &len, cg);
@@ -28375,103 +28437,158 @@ const Temp = struct {
return val;
}
- fn store(ptr: *Temp, disp: i32, val: *Temp, cg: *CodeGen) !void {
+ fn store(ptr: *Temp, val: *Temp, opts: AccessOptions, cg: *CodeGen) !void {
const val_ty = val.typeOf(cg);
- val: switch (val.tracking(cg).short) {
- else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
- .immediate => |val_imm| {
- const val_op: Immediate = if (std.math.cast(u32, val_imm)) |val_uimm32|
- .u(val_uimm32)
- else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
- .s(val_simm32)
- else
- continue :val .{ .register = undefined };
- while (try ptr.toLea(cg)) {}
- try cg.asmMemoryImmediate(
- .{ ._, .mov },
- try ptr.tracking(cg).short.deref().mem(cg, .{
- .size = cg.memSize(val_ty),
- .disp = disp,
- }),
- val_op,
- );
- },
- .register => {
- while (try ptr.toLea(cg) or try val.toRegClass(true, .general_purpose, cg)) {}
- const val_reg = val.tracking(cg).short.register;
- switch (val_reg.class()) {
- .general_purpose => try cg.asmMemoryRegister(
+ try ptr.toOffset(opts.disp, cg);
+ while (try ptr.toLea(cg)) {}
+ val_to_gpr: while (true) : (while (try ptr.toLea(cg) or
+ try val.toRegClass(false, .general_purpose, cg))
+ {}) {
+ const val_mcv = val.tracking(cg).short;
+ switch (val_mcv) {
+ else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
+ .undef => if (opts.safe) {
+ var pat = try cg.tempInit(.u8, .{ .immediate = 0xaa });
+ var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
+ try ptr.memset(&pat, &len, cg);
+ try pat.die(cg);
+ try len.die(cg);
+ },
+ .immediate => |val_imm| {
+ const val_op: Immediate = if (std.math.cast(u31, val_imm)) |val_uimm31|
+ .u(val_uimm31)
+ else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
+ .s(val_simm32)
+ else
+ continue :val_to_gpr;
+ // hack around linker relocation bugs
+ switch (ptr.tracking(cg).short) {
+ else => {},
+ .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {},
+ }
+ try cg.asmMemoryImmediate(
.{ ._, .mov },
try ptr.tracking(cg).short.deref().mem(cg, .{
.size = cg.memSize(val_ty),
- .disp = disp,
}),
- registerAlias(val_reg, @intCast(val_ty.abiSize(cg.pt.zcu))),
- ),
- else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
- }
- },
- }
- }
-
- fn read(src: *Temp, disp: i32, val_ty: Type, cg: *CodeGen) !Temp {
- var val = try cg.tempAlloc(val_ty);
- while (try src.toBase(cg)) {}
- val_to_gpr: while (true) : (while (try val.toRegClass(false, .general_purpose, cg)) {}) {
- const val_mcv = val.tracking(cg).short;
- switch (val_mcv) {
- else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
- .register => |val_reg| try src.readReg(disp, val_ty, registerAlias(
+ val_op,
+ );
+ },
+ .eflags => |cc| {
+ // hack around linker relocation bugs
+ switch (ptr.tracking(cg).short) {
+ else => {},
+ .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {},
+ }
+ try cg.asmSetccMemory(
+ cc,
+ try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }),
+ );
+ },
+ .register => |val_reg| try ptr.storeReg(val_ty, registerAlias(
val_reg,
@intCast(val_ty.abiSize(cg.pt.zcu)),
), cg),
- inline .register_pair, .register_triple, .register_quadruple => |val_regs| {
- var part_disp = disp;
- for (val_regs) |val_reg| {
- try src.readReg(disp, val_ty, val_reg, cg);
- part_disp += @divExact(val_reg.bitSize(), 8);
- }
+ inline .register_pair,
+ .register_triple,
+ .register_quadruple,
+ => |val_regs| for (val_regs) |val_reg| {
+ try ptr.storeReg(val_ty, val_reg, cg);
+ try ptr.toOffset(@divExact(val_reg.bitSize(), 8), cg);
+ while (try ptr.toLea(cg)) {}
},
.register_offset => |val_reg_off| switch (val_reg_off.off) {
- 0 => try src.readReg(disp, val_ty, registerAlias(
+ 0 => try ptr.storeReg(val_ty, registerAlias(
val_reg_off.reg,
@intCast(val_ty.abiSize(cg.pt.zcu)),
), cg),
else => continue :val_to_gpr,
},
+ .register_overflow => |val_reg_ov| {
+ const ip = &cg.pt.zcu.intern_pool;
+ const first_ty: Type = .fromInterned(first_ty: switch (ip.indexToKey(val_ty.toIntern())) {
+ .tuple_type => |tuple_type| {
+ const tuple_field_types = tuple_type.types.get(ip);
+ assert(tuple_field_types.len == 2 and tuple_field_types[1] == .u1_type);
+ break :first_ty tuple_field_types[0];
+ },
+ .opt_type => |opt_child| {
+ assert(!val_ty.optionalReprIsPayload(cg.pt.zcu));
+ break :first_ty opt_child;
+ },
+ else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }),
+ });
+ const first_size: u31 = @intCast(first_ty.abiSize(cg.pt.zcu));
+ try ptr.storeReg(first_ty, registerAlias(val_reg_ov.reg, first_size), cg);
+ try ptr.toOffset(first_size, cg);
+ try cg.asmSetccMemory(
+ val_reg_ov.eflags,
+ try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }),
+ );
+ },
.lea_frame, .lea_symbol => continue :val_to_gpr,
.memory, .indirect, .load_frame, .load_symbol => {
var val_ptr = try cg.tempInit(.usize, val_mcv.address());
- var src_ptr = try cg.tempInit(.usize, src.tracking(cg).short.address().offset(disp));
var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
- try val_ptr.memcpy(&src_ptr, &len, cg);
+ try ptr.memcpy(&val_ptr, &len, cg);
try val_ptr.die(cg);
- try src_ptr.die(cg);
try len.die(cg);
},
}
- return val;
+ break;
}
}
- fn readReg(src: Temp, disp: i32, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void {
- const strat = try cg.moveStrategy(dst_ty, dst_reg.class(), false);
- try strat.read(cg, dst_reg, try src.tracking(cg).short.mem(cg, .{
- .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())),
- .disp = disp,
- }));
+ fn read(src: *Temp, val_ty: Type, opts: AccessOptions, cg: *CodeGen) !Temp {
+ var val = try cg.tempAlloc(val_ty);
+ while (try src.toBase(cg)) {}
+ const val_mcv = val.tracking(cg).short;
+ switch (val_mcv) {
+ else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
+ .register => |val_reg| try src.readReg(opts.disp, val_ty, registerAlias(
+ val_reg,
+ @intCast(val_ty.abiSize(cg.pt.zcu)),
+ ), cg),
+ inline .register_pair, .register_triple, .register_quadruple => |val_regs| {
+ var disp = opts.disp;
+ for (val_regs) |val_reg| {
+ try src.readReg(disp, val_ty, val_reg, cg);
+ disp += @divExact(val_reg.bitSize(), 8);
+ }
+ },
+ .register_offset => |val_reg_off| switch (val_reg_off.off) {
+ 0 => try src.readReg(opts.disp, val_ty, registerAlias(
+ val_reg_off.reg,
+ @intCast(val_ty.abiSize(cg.pt.zcu)),
+ ), cg),
+ else => unreachable,
+ },
+ .memory, .indirect, .load_frame, .load_symbol => {
+ var val_ptr = try cg.tempInit(.usize, val_mcv.address());
+ var src_ptr =
+ try cg.tempInit(.usize, src.tracking(cg).short.address().offset(opts.disp));
+ var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
+ try val_ptr.memcpy(&src_ptr, &len, cg);
+ try val_ptr.die(cg);
+ try src_ptr.die(cg);
+ try len.die(cg);
+ },
+ }
+ return val;
}
- fn write(dst: *Temp, disp: i32, val: *Temp, cg: *CodeGen) !void {
+ fn write(dst: *Temp, val: *Temp, opts: AccessOptions, cg: *CodeGen) !void {
const val_ty = val.typeOf(cg);
while (try dst.toBase(cg)) {}
- val_to_gpr: while (true) : (while (try val.toRegClass(false, .general_purpose, cg)) {}) {
+ val_to_gpr: while (true) : (while (try dst.toBase(cg) or
+ try val.toRegClass(false, .general_purpose, cg))
+ {}) {
const val_mcv = val.tracking(cg).short;
switch (val_mcv) {
else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
.immediate => |val_imm| {
- const val_op: Immediate = if (std.math.cast(u32, val_imm)) |val_uimm32|
- .u(val_uimm32)
+ const val_op: Immediate = if (std.math.cast(u31, val_imm)) |val_uimm31|
+ .u(val_uimm31)
else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
.s(val_simm32)
else
@@ -28480,24 +28597,24 @@ const Temp = struct {
.{ ._, .mov },
try dst.tracking(cg).short.mem(cg, .{
.size = cg.memSize(val_ty),
- .disp = disp,
+ .disp = opts.disp,
}),
val_op,
);
},
- .register => |val_reg| try dst.writeReg(disp, val_ty, registerAlias(
+ .register => |val_reg| try dst.writeReg(opts.disp, val_ty, registerAlias(
val_reg,
@intCast(val_ty.abiSize(cg.pt.zcu)),
), cg),
inline .register_pair, .register_triple, .register_quadruple => |val_regs| {
- var part_disp = disp;
+ var disp = opts.disp;
for (val_regs) |val_reg| {
- try dst.writeReg(part_disp, val_ty, val_reg, cg);
- part_disp += @divExact(val_reg.bitSize(), 8);
+ try dst.writeReg(disp, val_ty, val_reg, cg);
+ disp += @divExact(val_reg.bitSize(), 8);
}
},
.register_offset => |val_reg_off| switch (val_reg_off.off) {
- 0 => try dst.writeReg(disp, val_ty, registerAlias(
+ 0 => try dst.writeReg(opts.disp, val_ty, registerAlias(
val_reg_off.reg,
@intCast(val_ty.abiSize(cg.pt.zcu)),
), cg),
@@ -28505,7 +28622,8 @@ const Temp = struct {
},
.lea_frame, .lea_symbol => continue :val_to_gpr,
.memory, .indirect, .load_frame, .load_symbol => {
- var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(disp));
+ var dst_ptr =
+ try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(opts.disp));
var val_ptr = try cg.tempInit(.usize, val_mcv.address());
var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
try dst_ptr.memcpy(&val_ptr, &len, cg);
@@ -28514,10 +28632,62 @@ const Temp = struct {
try len.die(cg);
},
}
- return;
+ break;
+ }
+ }
+
+ fn loadReg(ptr: *Temp, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void {
+ const dst_rc = dst_reg.class();
+ const strat = try cg.moveStrategy(dst_ty, dst_rc, false);
+ // hack around linker relocation bugs
+ switch (ptr.tracking(cg).short) {
+ else => {},
+ .lea_symbol => |sym_off| if (dst_rc != .general_purpose or sym_off.off != 0)
+ while (try ptr.toRegClass(false, .general_purpose, cg)) {},
+ }
+ try strat.read(cg, dst_reg, try ptr.tracking(cg).short.deref().mem(cg, .{
+ .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())),
+ }));
+ }
+
+ fn storeReg(ptr: *Temp, src_ty: Type, src_reg: Register, cg: *CodeGen) !void {
+ const src_rc = src_reg.class();
+ const src_abi_size = src_ty.abiSize(cg.pt.zcu);
+ const strat = try cg.moveStrategy(src_ty, src_rc, false);
+ // hack around linker relocation bugs
+ switch (ptr.tracking(cg).short) {
+ else => {},
+ .lea_symbol => |sym_off| if (src_rc != .general_purpose or sym_off.off != 0)
+ while (try ptr.toRegClass(false, .general_purpose, cg)) {},
+ }
+ if (src_rc == .x87 or std.math.isPowerOfTwo(src_abi_size)) {
+ try strat.write(cg, try ptr.tracking(cg).short.deref().mem(cg, .{
+ .size = .fromBitSize(@min(8 * src_abi_size, src_reg.bitSize())),
+ }), src_reg);
+ } else {
+ const frame_alloc: FrameAlloc = .initSpill(src_ty, cg.pt.zcu);
+ const frame_index = try cg.allocFrameIndex(frame_alloc);
+ const frame_size: Memory.Size = .fromSize(frame_alloc.abi_size);
+ try strat.write(cg, .{
+ .base = .{ .frame = frame_index },
+ .mod = .{ .rm = .{ .size = frame_size } },
+ }, src_reg);
+ var src_ptr = try cg.tempInit(.usize, .{ .lea_frame = .{ .index = frame_index } });
+ var len = try cg.tempInit(.usize, .{ .immediate = src_abi_size });
+ try ptr.memcpy(&src_ptr, &len, cg);
+ try src_ptr.die(cg);
+ try len.die(cg);
}
}
+ fn readReg(src: Temp, disp: i32, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void {
+ const strat = try cg.moveStrategy(dst_ty, dst_reg.class(), false);
+ try strat.read(cg, dst_reg, try src.tracking(cg).short.mem(cg, .{
+ .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())),
+ .disp = disp,
+ }));
+ }
+
fn writeReg(dst: Temp, disp: i32, src_ty: Type, src_reg: Register, cg: *CodeGen) !void {
const src_rc = src_reg.class();
const src_abi_size = src_ty.abiSize(cg.pt.zcu);
@@ -28552,6 +28722,13 @@ const Temp = struct {
try cg.asmOpOnly(.{ .@"rep _sb", .mov });
}
+ fn memset(dst: *Temp, val: *Temp, len: *Temp, cg: *CodeGen) !void {
+ while (true) for ([_]*Temp{ dst, val, len }, [_]Register{ .rdi, .rax, .rcx }) |temp, reg| {
+ if (try temp.toReg(reg, cg)) break;
+ } else break;
+ try cg.asmOpOnly(.{ .@"rep _sb", .sto });
+ }
+
fn moveTo(temp: Temp, inst: Air.Inst.Index, cg: *CodeGen) !void {
if (cg.liveness.isUnused(inst)) try temp.die(cg) else switch (temp.unwrap(cg)) {
.ref => {
test/behavior/basic.zig
@@ -1169,10 +1169,10 @@ test "arrays and vectors with big integers" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
inline for (.{ u65528, u65529, u65535 }) |Int| {
var a: [1]Int = undefined;