diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 257c9e5a6c..aba98276c3 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -1071,68 +1071,61 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } -fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[inst].bin_op; - if (self.liveness.isUnused(inst)) { - return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); - } - - const mcvs = try self.mcvsForBinMathOp(inst, bin_op.lhs, bin_op.rhs); - var dst_mcv = mcvs.dst; - const src_mcv = mcvs.src; - - // TODO clean this up - // TODO take into account alignment +fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { const dst_ty = self.air.typeOfIndex(inst); const elem_size = dst_ty.elemType2().abiSize(self.target.*); - const dst_reg = blk: { - switch (dst_mcv) { - .register => |reg| break :blk reg, - else => { - src_mcv.freezeIfRegister(&self.register_manager); - defer src_mcv.freezeIfRegister(&self.register_manager); - const reg = try self.copyToTmpRegister(dst_ty, dst_mcv); - break :blk reg; - }, - } - }; - try self.genIMulOpMir(dst_ty, .{ .register = dst_reg }, .{ .immediate = elem_size }); - dst_mcv = .{ .register = dst_reg }; - try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv); + const ptr = try self.resolveInst(op_lhs); + const offset = try self.resolveInst(op_rhs); + const offset_ty = self.air.typeOf(op_rhs); - return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); + ptr.freezeIfRegister(&self.register_manager); + defer ptr.unfreezeIfRegister(&self.register_manager); + + offset.freezeIfRegister(&self.register_manager); + defer offset.unfreezeIfRegister(&self.register_manager); + + const dst_mcv = blk: { + if (self.reuseOperand(inst, op_lhs, 0, ptr)) { + if (ptr.isMemory() or ptr.isRegister()) break :blk ptr; + } + break :blk try self.copyToNewRegister(inst, dst_ty, ptr); + }; + + const offset_mcv = blk: { + if (self.reuseOperand(inst, op_rhs, 1, offset)) { + if (offset.isRegister()) break :blk offset; + } + break :blk MCValue{ .register = try self.copyToTmpRegister(offset_ty, offset) }; + }; + + try self.genIMulOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size }); + + const tag = self.air.instructions.items(.tag)[inst]; + switch (tag) { + .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, offset_mcv), + .ptr_sub => try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, offset_mcv), + else => unreachable, + } + + return dst_mcv; +} + +fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void { + const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const result = if (self.liveness.isUnused(inst)) + .dead + else + try self.genPtrBinMathOp(inst, bin_op.lhs, bin_op.rhs); + return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; - if (self.liveness.isUnused(inst)) { - return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); - } - - const mcvs = try self.mcvsForBinMathOp(inst, bin_op.lhs, bin_op.rhs); - var dst_mcv = mcvs.dst; - const src_mcv = mcvs.src; - - // TODO clean this up - // TODO take into account alignment - const dst_ty = self.air.typeOfIndex(inst); - const elem_size = dst_ty.elemType2().abiSize(self.target.*); - const dst_reg = blk: { - switch (dst_mcv) { - .register => |reg| break :blk reg, - else => { - src_mcv.freezeIfRegister(&self.register_manager); - defer src_mcv.freezeIfRegister(&self.register_manager); - const reg = try self.copyToTmpRegister(dst_ty, dst_mcv); - break :blk reg; - }, - } - }; - try self.genIMulOpMir(dst_ty, .{ .register = dst_reg }, .{ .immediate = elem_size }); - dst_mcv = .{ .register = dst_reg }; - try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, src_mcv); - - return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); + const result = if (self.liveness.isUnused(inst)) + .dead + else + try self.genPtrBinMathOp(inst, bin_op.lhs, bin_op.rhs); + return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airSlice(self: *Self, inst: Air.Inst.Index) !void { @@ -2178,17 +2171,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); } -const BinMathOpMCValuePair = struct { - dst: MCValue, - src: MCValue, -}; - -fn mcvsForBinMathOp( - self: *Self, - inst: Air.Inst.Index, - op_lhs: Air.Inst.Ref, - op_rhs: Air.Inst.Ref, -) !BinMathOpMCValuePair { +/// Perform "binary" operators, excluding comparisons. +/// Currently, the following ops are supported: +/// ADD, SUB, XOR, OR, AND +fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { // TODO: make this algorithm less bad const lhs = try self.resolveInst(op_lhs); const rhs = try self.resolveInst(op_rhs); @@ -2201,6 +2187,7 @@ fn mcvsForBinMathOp( const dst_ty = self.air.typeOfIndex(inst); var dst_mcv: MCValue = undefined; var src_mcv: MCValue = undefined; + if (self.reuseOperand(inst, op_lhs, 0, lhs)) { // LHS dies; use it as the destination. // Both operands cannot be memory. @@ -2253,17 +2240,6 @@ fn mcvsForBinMathOp( else => {}, } - return BinMathOpMCValuePair{ .dst = dst_mcv, .src = src_mcv }; -} - -/// Perform "binary" operators, excluding comparisons. -/// Currently, the following ops are supported: -/// ADD, SUB, XOR, OR, AND -fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { - const dst_ty = self.air.typeOfIndex(inst); - const mcvs = try self.mcvsForBinMathOp(inst, op_lhs, op_rhs); - const dst_mcv = mcvs.dst; - const src_mcv = mcvs.src; const tag = self.air.instructions.items(.tag)[inst]; switch (tag) { .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv), diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 8a315ecab0..22cbce8261 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -106,7 +106,6 @@ fn fnWithAlignedStack() i32 { test "implicitly decreasing slice alignment" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const a: u32 align(4) = 3; const b: u32 align(8) = 4; @@ -274,7 +273,6 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { test "runtime known array index has best alignment possible" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // take full advantage of over-alignment diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 70b17a55a1..75d470b21f 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -199,7 +199,7 @@ fn MakeType(comptime T: type) type { test "implicit cast from *[N]T to [*c]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; var x: [4]u16 = [4]u16{ 0, 1, 2, 3 }; var y: [*c]u16 = &x; @@ -274,7 +274,7 @@ test "*const ?[*]const T to [*c]const [*c]const T" { test "array coersion to undefined at runtime" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @setRuntimeSafety(true); @@ -339,7 +339,6 @@ test "peer type unsigned int to signed" { test "expected [*c]const u8, found [*:0]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; var a: [*:0]const u8 = "hello"; var b: [*c]const u8 = a;