authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-16 15:00:32+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-16 15:00:32+01:00
log1b7ec44924ede3816438f9de4b4b5bc3b7705711
treeadae1544584882c5e37b96d1ebd8054f852d93e5
parent3383064b27cc8ad7aa997f6504d627af1fa8c960

x64: separate ptr_add and ptr_sub from normal bin ops


1 files changed, 94 insertions(+), 39 deletions(-)

src/arch/x86_64/CodeGen.zig+94-39
......@@ -582,10 +582,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
582582
583583 switch (air_tags[inst]) {
584584 // zig fmt: off
585 .add, .ptr_add => try self.airAdd(inst),
585 .add => try self.airAdd(inst),
586586 .addwrap => try self.airAddWrap(inst),
587587 .add_sat => try self.airAddSat(inst),
588 .sub, .ptr_sub => try self.airSub(inst),
588 .sub => try self.airSub(inst),
589589 .subwrap => try self.airSubWrap(inst),
590590 .sub_sat => try self.airSubSat(inst),
591591 .mul => try self.airMul(inst),
......@@ -597,6 +597,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
597597 .shl_sat => try self.airShlSat(inst),
598598 .min => try self.airMin(inst),
599599 .max => try self.airMax(inst),
600 .ptr_add => try self.airPtrAdd(inst),
601 .ptr_sub => try self.airPtrSub(inst),
600602 .slice => try self.airSlice(inst),
601603
602604 .sqrt,
......@@ -1068,6 +1070,70 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void {
10681070 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
10691071}
10701072
1073fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void {
1074 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1075 if (self.liveness.isUnused(inst)) {
1076 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1077 }
1078
1079 const mcvs = try self.mcvsForBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1080 var dst_mcv = mcvs.dst;
1081 const src_mcv = mcvs.src;
1082
1083 // TODO clean this up
1084 // TODO take into account alignment
1085 const dst_ty = self.air.typeOfIndex(inst);
1086 const elem_size = dst_ty.elemType2().abiSize(self.target.*);
1087 const dst_reg = blk: {
1088 switch (dst_mcv) {
1089 .register => |reg| break :blk reg,
1090 else => {
1091 src_mcv.freezeIfRegister(&self.register_manager);
1092 defer src_mcv.freezeIfRegister(&self.register_manager);
1093 const reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
1094 break :blk reg;
1095 },
1096 }
1097 };
1098 try self.genIMulOpMir(dst_ty, .{ .register = dst_reg }, .{ .immediate = elem_size });
1099 dst_mcv = .{ .register = dst_reg };
1100 try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv);
1101
1102 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
1103}
1104
1105fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void {
1106 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1107 if (self.liveness.isUnused(inst)) {
1108 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1109 }
1110
1111 const mcvs = try self.mcvsForBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1112 var dst_mcv = mcvs.dst;
1113 const src_mcv = mcvs.src;
1114
1115 // TODO clean this up
1116 // TODO take into account alignment
1117 const dst_ty = self.air.typeOfIndex(inst);
1118 const elem_size = dst_ty.elemType2().abiSize(self.target.*);
1119 const dst_reg = blk: {
1120 switch (dst_mcv) {
1121 .register => |reg| break :blk reg,
1122 else => {
1123 src_mcv.freezeIfRegister(&self.register_manager);
1124 defer src_mcv.freezeIfRegister(&self.register_manager);
1125 const reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
1126 break :blk reg;
1127 },
1128 }
1129 };
1130 try self.genIMulOpMir(dst_ty, .{ .register = dst_reg }, .{ .immediate = elem_size });
1131 dst_mcv = .{ .register = dst_reg };
1132 try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, src_mcv);
1133
1134 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
1135}
1136
10711137fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
10721138 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
10731139 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
......@@ -2148,18 +2214,17 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
21482214 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
21492215}
21502216
2151/// Perform "binary" operators, excluding comparisons.
2152/// Currently, the following ops are supported:
2153/// ADD, SUB, XOR, OR, AND
2154fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
2155 // We'll handle these ops in two steps.
2156 // 1) Prepare an output location (register or memory)
2157 // This location will be the location of the operand that dies (if one exists)
2158 // or just a temporary register (if one doesn't exist)
2159 // 2) Perform the op with the other argument
2160 // 3) Sometimes, the output location is memory but the op doesn't support it.
2161 // In this case, copy that location to a register, then perform the op to that register instead.
2162 //
2217const BinMathOpMCValuePair = struct {
2218 dst: MCValue,
2219 src: MCValue,
2220};
2221
2222fn mcvsForBinMathOp(
2223 self: *Self,
2224 inst: Air.Inst.Index,
2225 op_lhs: Air.Inst.Ref,
2226 op_rhs: Air.Inst.Ref,
2227) !BinMathOpMCValuePair {
21632228 // TODO: make this algorithm less bad
21642229 const lhs = try self.resolveInst(op_lhs);
21652230 const rhs = try self.resolveInst(op_rhs);
......@@ -2218,35 +2283,26 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
22182283 dst_mcv.freezeIfRegister(&self.register_manager);
22192284 defer dst_mcv.unfreezeIfRegister(&self.register_manager);
22202285
2221 const tmp_reg = try self.copyToTmpRegister(Type.u64, src_mcv);
2222 src_mcv = MCValue{ .register = tmp_reg };
2286 src_mcv = try self.copyToNewRegister(inst, Type.u64, src_mcv);
22232287 }
22242288 },
22252289 else => {},
22262290 }
22272291
2228 // Now for step 2, we assing an MIR instruction
2229 const air_tags = self.air.instructions.items(.tag);
2230 switch (air_tags[inst]) {
2231 .ptr_add => {
2232 // TODO clean this up
2233 // TODO take into account alignment
2234 const elem_size = dst_ty.elemType2().abiSize(self.target.*);
2235 const dst_reg = blk: {
2236 switch (dst_mcv) {
2237 .register => |reg| break :blk reg,
2238 else => {
2239 src_mcv.freezeIfRegister(&self.register_manager);
2240 defer src_mcv.freezeIfRegister(&self.register_manager);
2241 const reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
2242 break :blk reg;
2243 },
2244 }
2245 };
2246 try self.genIMulOpMir(dst_ty, .{ .register = dst_reg }, .{ .immediate = elem_size });
2247 dst_mcv = MCValue{ .register = dst_reg };
2248 try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv);
2249 },
2292 return BinMathOpMCValuePair{ .dst = dst_mcv, .src = src_mcv };
2293}
2294
2295/// Perform "binary" operators, excluding comparisons.
2296/// Currently, the following ops are supported:
2297/// ADD, SUB, XOR, OR, AND
2298fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
2299 const dst_ty = self.air.typeOfIndex(inst);
2300 const mcvs = try self.mcvsForBinMathOp(inst, op_lhs, op_rhs);
2301 const dst_mcv = mcvs.dst;
2302 const src_mcv = mcvs.src;
2303 log.warn("dst_mcv = {}, src_mcv = {}", .{ dst_mcv, src_mcv });
2304 const tag = self.air.instructions.items(.tag)[inst];
2305 switch (tag) {
22502306 .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
22512307 .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv),
22522308 .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv),
......@@ -2255,7 +2311,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
22552311 .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv),
22562312 else => unreachable,
22572313 }
2258
22592314 return dst_mcv;
22602315}
22612316