authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-17 00:09:33+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-17 15:07:42+01:00
log3193cc1c1ea1796df2ae40d5a11396d8626a8070
tree785a1ca2745450b15f484a55ba15bfed77c60b28
parentc1fb14c51ef9b329c0e4dfedfe6ae591bd972a88

x64: fix ptr_add and ptr_sub

Add standalone implementation of operand reuse for ptr related arithmetic operations of add and sub.

3 files changed, 52 insertions(+), 79 deletions(-)

src/arch/x86_64/CodeGen.zig+50-74
......@@ -1071,68 +1071,61 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void {
10711071 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
10721072}
10731073
1074fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void {
1075 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1076 if (self.liveness.isUnused(inst)) {
1077 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1078 }
1079
1080 const mcvs = try self.mcvsForBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1081 var dst_mcv = mcvs.dst;
1082 const src_mcv = mcvs.src;
1083
1084 // TODO clean this up
1085 // TODO take into account alignment
1074fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
10861075 const dst_ty = self.air.typeOfIndex(inst);
10871076 const elem_size = dst_ty.elemType2().abiSize(self.target.*);
1088 const dst_reg = blk: {
1089 switch (dst_mcv) {
1090 .register => |reg| break :blk reg,
1091 else => {
1092 src_mcv.freezeIfRegister(&self.register_manager);
1093 defer src_mcv.freezeIfRegister(&self.register_manager);
1094 const reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
1095 break :blk reg;
1096 },
1077 const ptr = try self.resolveInst(op_lhs);
1078 const offset = try self.resolveInst(op_rhs);
1079 const offset_ty = self.air.typeOf(op_rhs);
1080
1081 ptr.freezeIfRegister(&self.register_manager);
1082 defer ptr.unfreezeIfRegister(&self.register_manager);
1083
1084 offset.freezeIfRegister(&self.register_manager);
1085 defer offset.unfreezeIfRegister(&self.register_manager);
1086
1087 const dst_mcv = blk: {
1088 if (self.reuseOperand(inst, op_lhs, 0, ptr)) {
1089 if (ptr.isMemory() or ptr.isRegister()) break :blk ptr;
10971090 }
1091 break :blk try self.copyToNewRegister(inst, dst_ty, ptr);
10981092 };
1099 try self.genIMulOpMir(dst_ty, .{ .register = dst_reg }, .{ .immediate = elem_size });
1100 dst_mcv = .{ .register = dst_reg };
1101 try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv);
11021093
1103 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
1104}
1094 const offset_mcv = blk: {
1095 if (self.reuseOperand(inst, op_rhs, 1, offset)) {
1096 if (offset.isRegister()) break :blk offset;
1097 }
1098 break :blk MCValue{ .register = try self.copyToTmpRegister(offset_ty, offset) };
1099 };
11051100
1106fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void {
1107 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1108 if (self.liveness.isUnused(inst)) {
1109 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1101 try self.genIMulOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size });
1102
1103 const tag = self.air.instructions.items(.tag)[inst];
1104 switch (tag) {
1105 .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, offset_mcv),
1106 .ptr_sub => try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, offset_mcv),
1107 else => unreachable,
11101108 }
11111109
1112 const mcvs = try self.mcvsForBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1113 var dst_mcv = mcvs.dst;
1114 const src_mcv = mcvs.src;
1110 return dst_mcv;
1111}
11151112
1116 // TODO clean this up
1117 // TODO take into account alignment
1118 const dst_ty = self.air.typeOfIndex(inst);
1119 const elem_size = dst_ty.elemType2().abiSize(self.target.*);
1120 const dst_reg = blk: {
1121 switch (dst_mcv) {
1122 .register => |reg| break :blk reg,
1123 else => {
1124 src_mcv.freezeIfRegister(&self.register_manager);
1125 defer src_mcv.freezeIfRegister(&self.register_manager);
1126 const reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
1127 break :blk reg;
1128 },
1129 }
1130 };
1131 try self.genIMulOpMir(dst_ty, .{ .register = dst_reg }, .{ .immediate = elem_size });
1132 dst_mcv = .{ .register = dst_reg };
1133 try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, src_mcv);
1113fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void {
1114 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1115 const result = if (self.liveness.isUnused(inst))
1116 .dead
1117 else
1118 try self.genPtrBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1119 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1120}
11341121
1135 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
1122fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void {
1123 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1124 const result = if (self.liveness.isUnused(inst))
1125 .dead
1126 else
1127 try self.genPtrBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1128 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
11361129}
11371130
11381131fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
......@@ -2178,17 +2171,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
21782171 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
21792172}
21802173
2181const BinMathOpMCValuePair = struct {
2182 dst: MCValue,
2183 src: MCValue,
2184};
2185
2186fn mcvsForBinMathOp(
2187 self: *Self,
2188 inst: Air.Inst.Index,
2189 op_lhs: Air.Inst.Ref,
2190 op_rhs: Air.Inst.Ref,
2191) !BinMathOpMCValuePair {
2174/// Perform "binary" operators, excluding comparisons.
2175/// Currently, the following ops are supported:
2176/// ADD, SUB, XOR, OR, AND
2177fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
21922178 // TODO: make this algorithm less bad
21932179 const lhs = try self.resolveInst(op_lhs);
21942180 const rhs = try self.resolveInst(op_rhs);
......@@ -2201,6 +2187,7 @@ fn mcvsForBinMathOp(
22012187 const dst_ty = self.air.typeOfIndex(inst);
22022188 var dst_mcv: MCValue = undefined;
22032189 var src_mcv: MCValue = undefined;
2190
22042191 if (self.reuseOperand(inst, op_lhs, 0, lhs)) {
22052192 // LHS dies; use it as the destination.
22062193 // Both operands cannot be memory.
......@@ -2253,17 +2240,6 @@ fn mcvsForBinMathOp(
22532240 else => {},
22542241 }
22552242
2256 return BinMathOpMCValuePair{ .dst = dst_mcv, .src = src_mcv };
2257}
2258
2259/// Perform "binary" operators, excluding comparisons.
2260/// Currently, the following ops are supported:
2261/// ADD, SUB, XOR, OR, AND
2262fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
2263 const dst_ty = self.air.typeOfIndex(inst);
2264 const mcvs = try self.mcvsForBinMathOp(inst, op_lhs, op_rhs);
2265 const dst_mcv = mcvs.dst;
2266 const src_mcv = mcvs.src;
22672243 const tag = self.air.instructions.items(.tag)[inst];
22682244 switch (tag) {
22692245 .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
test/behavior/align.zig-2
......@@ -106,7 +106,6 @@ fn fnWithAlignedStack() i32 {
106106test "implicitly decreasing slice alignment" {
107107 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
108108 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
110109
111110 const a: u32 align(4) = 3;
112111 const b: u32 align(8) = 4;
......@@ -274,7 +273,6 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
274273test "runtime known array index has best alignment possible" {
275274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
276275 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
277 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
278276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
279277
280278 // take full advantage of over-alignment
test/behavior/cast.zig+2-3
......@@ -199,7 +199,7 @@ fn MakeType(comptime T: type) type {
199199
200200test "implicit cast from *[N]T to [*c]T" {
201201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
202 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
203203
204204 var x: [4]u16 = [4]u16{ 0, 1, 2, 3 };
205205 var y: [*c]u16 = &x;
......@@ -274,7 +274,7 @@ test "*const ?[*]const T to [*c]const [*c]const T" {
274274
275275test "array coersion to undefined at runtime" {
276276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
277 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
278278
279279 @setRuntimeSafety(true);
280280
......@@ -339,7 +339,6 @@ test "peer type unsigned int to signed" {
339339test "expected [*c]const u8, found [*:0]const u8" {
340340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
341341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
342 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
343342
344343 var a: [*:0]const u8 = "hello";
345344 var b: [*c]const u8 = a;