| ... | ... | @@ -582,10 +582,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 582 | 582 | |
| 583 | 583 | switch (air_tags[inst]) { |
| 584 | 584 | // zig fmt: off |
| 585 | | .add, .ptr_add => try self.airAdd(inst), |
| 585 | .add => try self.airAdd(inst), |
| 586 | 586 | .addwrap => try self.airAddWrap(inst), |
| 587 | 587 | .add_sat => try self.airAddSat(inst), |
| 588 | | .sub, .ptr_sub => try self.airSub(inst), |
| 588 | .sub => try self.airSub(inst), |
| 589 | 589 | .subwrap => try self.airSubWrap(inst), |
| 590 | 590 | .sub_sat => try self.airSubSat(inst), |
| 591 | 591 | .mul => try self.airMul(inst), |
| ... | ... | @@ -597,6 +597,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 597 | 597 | .shl_sat => try self.airShlSat(inst), |
| 598 | 598 | .min => try self.airMin(inst), |
| 599 | 599 | .max => try self.airMax(inst), |
| 600 | .ptr_add => try self.airPtrAdd(inst), |
| 601 | .ptr_sub => try self.airPtrSub(inst), |
| 600 | 602 | .slice => try self.airSlice(inst), |
| 601 | 603 | |
| 602 | 604 | .sqrt, |
| ... | ... | @@ -1068,6 +1070,70 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1068 | 1070 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1069 | 1071 | } |
| 1070 | 1072 | |
| 1073 | fn 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 | |
| 1105 | fn 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 | |
| 1071 | 1137 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1072 | 1138 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1073 | 1139 | 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 { |
| 2148 | 2214 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 2149 | 2215 | } |
| 2150 | 2216 | |
| 2151 | | /// Perform "binary" operators, excluding comparisons. |
| 2152 | | /// Currently, the following ops are supported: |
| 2153 | | /// ADD, SUB, XOR, OR, AND |
| 2154 | | fn 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 | | // |
| 2217 | const BinMathOpMCValuePair = struct { |
| 2218 | dst: MCValue, |
| 2219 | src: MCValue, |
| 2220 | }; |
| 2221 | |
| 2222 | fn mcvsForBinMathOp( |
| 2223 | self: *Self, |
| 2224 | inst: Air.Inst.Index, |
| 2225 | op_lhs: Air.Inst.Ref, |
| 2226 | op_rhs: Air.Inst.Ref, |
| 2227 | ) !BinMathOpMCValuePair { |
| 2163 | 2228 | // TODO: make this algorithm less bad |
| 2164 | 2229 | const lhs = try self.resolveInst(op_lhs); |
| 2165 | 2230 | 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: |
| 2218 | 2283 | dst_mcv.freezeIfRegister(&self.register_manager); |
| 2219 | 2284 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); |
| 2220 | 2285 | |
| 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); |
| 2223 | 2287 | } |
| 2224 | 2288 | }, |
| 2225 | 2289 | else => {}, |
| 2226 | 2290 | } |
| 2227 | 2291 | |
| 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 |
| 2298 | fn 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) { |
| 2250 | 2306 | .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv), |
| 2251 | 2307 | .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv), |
| 2252 | 2308 | .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: |
| 2255 | 2311 | .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv), |
| 2256 | 2312 | else => unreachable, |
| 2257 | 2313 | } |
| 2258 | | |
| 2259 | 2314 | return dst_mcv; |
| 2260 | 2315 | } |
| 2261 | 2316 | |