| ... | @@ -1164,7 +1164,20 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1164,7 +1164,20 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1164 | | 1164 | |
| 1165 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | 1165 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1166 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1166 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1167 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_len for {}", .{self.target.cpu.arch}); | 1167 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1168 | const mcv = try self.resolveInst(ty_op.operand); |
| | 1169 | switch (mcv) { |
| | 1170 | .dead, .unreach => unreachable, |
| | 1171 | .register => unreachable, // a slice doesn't fit in one register |
| | 1172 | .stack_offset => |off| { |
| | 1173 | break :result MCValue{ .stack_offset = off + 8 }; |
| | 1174 | }, |
| | 1175 | .memory => |addr| { |
| | 1176 | break :result MCValue{ .memory = addr + 8 }; |
| | 1177 | }, |
| | 1178 | else => return self.fail("TODO implement slice_len for {}", .{mcv}), |
| | 1179 | } |
| | 1180 | }; |
| 1168 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1181 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1169 | } | 1182 | } |
| 1170 | | 1183 | |
| ... | @@ -1183,10 +1196,114 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1183,10 +1196,114 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1183 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 1196 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1184 | const is_volatile = false; // TODO | 1197 | const is_volatile = false; // TODO |
| 1185 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1198 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1186 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch}); | 1199 | |
| | 1200 | if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 1201 | const result: MCValue = result: { |
| | 1202 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| | 1203 | |
| | 1204 | // TODO optimize for the case where the index is a constant, |
| | 1205 | // i.e. index_mcv == .immediate |
| | 1206 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| | 1207 | const index_is_register = index_mcv == .register; |
| | 1208 | |
| | 1209 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| | 1210 | const elem_ty = slice_ty.childType(); |
| | 1211 | const elem_size = elem_ty.abiSize(self.target.*); |
| | 1212 | |
| | 1213 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| | 1214 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| | 1215 | |
| | 1216 | if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register}); |
| | 1217 | defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register}); |
| | 1218 | |
| | 1219 | const base_mcv: MCValue = switch (slice_mcv) { |
| | 1220 | .stack_offset => |off| .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, .{ .stack_offset = off + 8 }) }, |
| | 1221 | else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}), |
| | 1222 | }; |
| | 1223 | self.register_manager.freezeRegs(&.{base_mcv.register}); |
| | 1224 | |
| | 1225 | // TODO implement optimized ldr for airSliceElemVal |
| | 1226 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| | 1227 | |
| | 1228 | const offset_mcv = try self.genMulConstant(bin_op.rhs, @intCast(u32, elem_size)); |
| | 1229 | assert(offset_mcv == .register); // result of multiplication should always be register |
| | 1230 | self.register_manager.freezeRegs(&.{offset_mcv.register}); |
| | 1231 | |
| | 1232 | const addr_reg = try self.register_manager.allocReg(null); |
| | 1233 | self.register_manager.freezeRegs(&.{addr_reg}); |
| | 1234 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| | 1235 | |
| | 1236 | _ = try self.addInst(.{ |
| | 1237 | .tag = .add_shifted_register, |
| | 1238 | .data = .{ .rrr_imm6_shift = .{ |
| | 1239 | .rd = addr_reg, |
| | 1240 | .rn = base_mcv.register, |
| | 1241 | .rm = offset_mcv.register, |
| | 1242 | .imm6 = 0, |
| | 1243 | .shift = .lsl, |
| | 1244 | } }, |
| | 1245 | }); |
| | 1246 | |
| | 1247 | // At this point in time, neither the base register |
| | 1248 | // nor the offset register contains any valuable data |
| | 1249 | // anymore. |
| | 1250 | self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register }); |
| | 1251 | |
| | 1252 | try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type); |
| | 1253 | |
| | 1254 | break :result dst_mcv; |
| | 1255 | }; |
| 1187 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1256 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1188 | } | 1257 | } |
| 1189 | | 1258 | |
| | 1259 | fn genMulConstant(self: *Self, op: Air.Inst.Ref, imm: u32) !MCValue { |
| | 1260 | const lhs = try self.resolveInst(op); |
| | 1261 | const rhs = MCValue{ .immediate = imm }; |
| | 1262 | |
| | 1263 | const lhs_is_register = lhs == .register; |
| | 1264 | |
| | 1265 | if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register}); |
| | 1266 | defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register}); |
| | 1267 | |
| | 1268 | // Destination must be a register |
| | 1269 | // LHS must be a register |
| | 1270 | // RHS must be a register |
| | 1271 | var dst_mcv: MCValue = undefined; |
| | 1272 | var lhs_mcv: MCValue = lhs; |
| | 1273 | var rhs_mcv: MCValue = rhs; |
| | 1274 | |
| | 1275 | // Allocate registers for operands and/or destination |
| | 1276 | // Allocate 1 or 2 registers |
| | 1277 | if (lhs_is_register) { |
| | 1278 | // Move RHS to register |
| | 1279 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) }; |
| | 1280 | rhs_mcv = dst_mcv; |
| | 1281 | } else { |
| | 1282 | // Move LHS and RHS to register |
| | 1283 | const regs = try self.register_manager.allocRegs(2, .{ null, null }); |
| | 1284 | lhs_mcv = MCValue{ .register = regs[0] }; |
| | 1285 | rhs_mcv = MCValue{ .register = regs[1] }; |
| | 1286 | dst_mcv = lhs_mcv; |
| | 1287 | } |
| | 1288 | |
| | 1289 | // Move the operands to the newly allocated registers |
| | 1290 | if (!lhs_is_register) { |
| | 1291 | try self.genSetReg(self.air.typeOf(op), lhs_mcv.register, lhs); |
| | 1292 | } |
| | 1293 | try self.genSetReg(Type.initTag(.usize), rhs_mcv.register, rhs); |
| | 1294 | |
| | 1295 | _ = try self.addInst(.{ |
| | 1296 | .tag = .mul, |
| | 1297 | .data = .{ .rrr = .{ |
| | 1298 | .rd = dst_mcv.register, |
| | 1299 | .rn = lhs_mcv.register, |
| | 1300 | .rm = rhs_mcv.register, |
| | 1301 | } }, |
| | 1302 | }); |
| | 1303 | |
| | 1304 | return dst_mcv; |
| | 1305 | } |
| | 1306 | |
| 1190 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { | 1307 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1191 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1308 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1192 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1309 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| ... | @@ -1310,6 +1427,16 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1310,6 +1427,16 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1310 | .undef => unreachable, | 1427 | .undef => unreachable, |
| 1311 | .compare_flags_signed, .compare_flags_unsigned => unreachable, | 1428 | .compare_flags_signed, .compare_flags_unsigned => unreachable, |
| 1312 | .embedded_in_code => unreachable, | 1429 | .embedded_in_code => unreachable, |
| | 1430 | .register => |dst_reg| { |
| | 1431 | _ = try self.addInst(.{ |
| | 1432 | .tag = .ldr_immediate, |
| | 1433 | .data = .{ .load_store_register_immediate = .{ |
| | 1434 | .rt = dst_reg, |
| | 1435 | .rn = addr_reg, |
| | 1436 | .offset = Instruction.LoadStoreOffset.none.immediate, |
| | 1437 | } }, |
| | 1438 | }); |
| | 1439 | }, |
| 1313 | .stack_offset => |off| { | 1440 | .stack_offset => |off| { |
| 1314 | if (elem_ty.abiSize(self.target.*) <= 8) { | 1441 | if (elem_ty.abiSize(self.target.*) <= 8) { |
| 1315 | const tmp_reg = try self.register_manager.allocReg(null); | 1442 | const tmp_reg = try self.register_manager.allocReg(null); |
| ... | @@ -2590,8 +2717,61 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -2590,8 +2717,61 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2590 | if (stack_offset == off) | 2717 | if (stack_offset == off) |
| 2591 | return; // Copy stack variable to itself; nothing to do. | 2718 | return; // Copy stack variable to itself; nothing to do. |
| 2592 | | 2719 | |
| 2593 | const reg = try self.copyToTmpRegister(ty, mcv); | 2720 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 2594 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 2721 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| | 2722 | if (ty.abiSize(self.target.*) <= ptr_bytes) { |
| | 2723 | const reg = try self.copyToTmpRegister(ty, mcv); |
| | 2724 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| | 2725 | } else { |
| | 2726 | // TODO optimize the register allocation |
| | 2727 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }); |
| | 2728 | self.register_manager.freezeRegs(&regs); |
| | 2729 | defer self.register_manager.unfreezeRegs(&regs); |
| | 2730 | |
| | 2731 | const src_reg = regs[0]; |
| | 2732 | const dst_reg = regs[1]; |
| | 2733 | const len_reg = regs[2]; |
| | 2734 | const count_reg = regs[3]; |
| | 2735 | const tmp_reg = regs[4]; |
| | 2736 | |
| | 2737 | // sub src_reg, fp, #off |
| | 2738 | const adj_src_offset = off + @intCast(u32, ty.abiSize(self.target.*)); |
| | 2739 | const src_offset = math.cast(u12, adj_src_offset) catch return self.fail("TODO load: larger stack offsets", .{}); |
| | 2740 | _ = try self.addInst(.{ |
| | 2741 | .tag = .sub_immediate, |
| | 2742 | .data = .{ .rr_imm12_sh = .{ |
| | 2743 | .rd = src_reg, |
| | 2744 | .rn = .x29, |
| | 2745 | .imm12 = src_offset, |
| | 2746 | } }, |
| | 2747 | }); |
| | 2748 | |
| | 2749 | // sub dst_reg, fp, #stack_offset |
| | 2750 | const adj_dst_off = stack_offset + @intCast(u32, ty.abiSize(self.target.*)); |
| | 2751 | const dst_offset = math.cast(u12, adj_dst_off) catch return self.fail("TODO load: larger stack offsets", .{}); |
| | 2752 | _ = try self.addInst(.{ |
| | 2753 | .tag = .sub_immediate, |
| | 2754 | .data = .{ .rr_imm12_sh = .{ |
| | 2755 | .rd = dst_reg, |
| | 2756 | .rn = .x29, |
| | 2757 | .imm12 = dst_offset, |
| | 2758 | } }, |
| | 2759 | }); |
| | 2760 | |
| | 2761 | // mov len, #elem_size |
| | 2762 | const elem_size = @intCast(u32, ty.abiSize(self.target.*)); |
| | 2763 | const len_imm = math.cast(u16, elem_size) catch return self.fail("TODO load: larger stack offsets", .{}); |
| | 2764 | _ = try self.addInst(.{ |
| | 2765 | .tag = .movk, |
| | 2766 | .data = .{ .r_imm16_sh = .{ |
| | 2767 | .rd = len_reg, |
| | 2768 | .imm16 = len_imm, |
| | 2769 | } }, |
| | 2770 | }); |
| | 2771 | |
| | 2772 | // memcpy(src, dst, len) |
| | 2773 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| | 2774 | } |
| 2595 | }, | 2775 | }, |
| 2596 | } | 2776 | } |
| 2597 | } | 2777 | } |
| ... | @@ -2711,7 +2891,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -2711,7 +2891,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2711 | } }, | 2891 | } }, |
| 2712 | }); | 2892 | }); |
| 2713 | }, | 2893 | }, |
| 2714 | else => return self.fail("TODO implement genSetReg other types abi_size={}", .{abi_size}), | 2894 | 3 => return self.fail("TODO implement genSetReg types size 3", .{}), |
| | 2895 | else => unreachable, |
| 2715 | } | 2896 | } |
| 2716 | }, | 2897 | }, |
| 2717 | else => return self.fail("TODO implement genSetReg for aarch64 {}", .{mcv}), | 2898 | else => return self.fail("TODO implement genSetReg for aarch64 {}", .{mcv}), |